/* * Copyright (c) 1995 Andrew McRae. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$Id: pccardd.c,v 1.2 1998/03/09 05:18:58 hosokawa Exp $"; #endif /* not lint */ /* * Code cleanup, bug-fix and extension * by Tatsumi Hosokawa */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define EXTERN #include "cardd.h" static char *config_file = "/etc/pccard.conf"; static char *stand_config_file = "/stand/etc/pccard.conf"; static char *conf = 0; static char *pid_file = "/var/run/pccardd.pid"; static u_int irqmask = 0u; #ifdef SERVER /* * pathname of UNIX-domain socket */ static char *socket_name = "/var/tmp/.pccardd"; static char *sock = 0; static int server_sock; #endif extern void dump_config_file(void); extern void dump_resource(void); extern void readslots(void); extern void slot_change(struct slot *); static u_int irq_init(void); static void resource_init(void); /* receive hungup signal */ static void restart(void) { int slen; struct sockaddr_un sun; bit_nclear(io_avail, 0, IOPORTS - 1); bit_nclear(mem_avail, 0, MEMBLKS - 1); readfile(conf, irqmask); if (2 <= verbose) dump_config_file(); if (verbose) dump_resource(); #if not_yet log_setup(); readslots(); if (slots == 0) die("No PC-CARD slots"); #endif logmsg("pccardd restarted", NULL); #ifdef SERVER close(server_sock); if ((server_sock = socket(PF_LOCAL, SOCK_DGRAM, 0)) < 0) die("socket failed"); bzero(&sun, sizeof(sun)); sun.sun_family = AF_UNIX; if (sock) { socket_name = sock; } strcpy(sun.sun_path, socket_name); slen = SUN_LEN(&sun); (void)unlink(socket_name); if (bind(server_sock, (struct sockaddr *) & sun, slen) < 0) die("bind failed"); chown(socket_name, 0, 5); /* XXX - root.operator */ chmod(socket_name, 0660); set_socket(server_sock); #endif /* SERVER */ } /* receive a SIGTERM or SIGINT */ static void term(int sig) { logmsg("pccardd terminated: signal %d received", sig); (void)unlink(socket_name); (void)unlink(pid_file); exit(0); } /* * automatically grab irq's that are available to us. */ static u_int irq_init() { int mib[2]; int siz; u_int irqmask; mib[0] = CTL_MACHDEP; mib[1] = CPU_INTRINUSE; siz = sizeof(irqmask); if (sysctl(mib, 2, &irqmask, &siz, NULL, 0) < 0) { fprintf(stderr, "pccardd: kernel version older than " "expected; we don't take kernel's advice\n"); irqflag = 1; return 0; } irqmask = ~irqmask; irqmask &= PCCARD_INT_MASK_ALLOWED; return irqmask; } /* * automatically grab ioport/iomem that are available to us. */ static void resource_init() { int mib[4]; int siz; int status; int i; /* check for io port. */ #define IOPORTCHKSIZ 8 mib[0] = CTL_MACHDEP; mib[1] = CPU_CHECKIO; mib[3] = IOPORTCHKSIZ; siz = sizeof(status); for (i = 0; i < IOPORTS; i += IOPORTCHKSIZ) { mib[2] = i; if (sysctl(mib, 4, &status, &siz, NULL, 0) < 0) { perror("syscall(machdep.checkio)"); exit(1); } if (status < 0) { bit_nclear(io_kern, i, i + IOPORTCHKSIZ - 1) ; } else { bit_nset(io_kern, i, i + IOPORTCHKSIZ - 1) ; } } #undef IOPORTCHKSIZ /* check for iomem */ mib[0] = CTL_MACHDEP; mib[1] = CPU_CHECKMEM; mib[3] = MEMUNIT; siz = sizeof(status); for (i = MEMSTART; i < MEMEND; i += MEMUNIT) { mib[2] = i; if (sysctl(mib, 4, &status, &siz, NULL, 0) < 0) { perror("syscall(machdep.checkmem)"); exit(1); } if (status < 0) { bit_nclear(mem_kern, MEM2BIT(i), MEM2BIT(i)) ; } else { bit_nset(mem_kern, MEM2BIT(i), MEM2BIT(i)) ; } } } /* * mainline code for pccardd */ int main(int argc, char *argv[]) { struct slot *sp; int i; int count, debug = 0; int delay = 0; FILE *fp; int slen; struct sockaddr_un sun; extern char *optarg; extern int optind, optopt; #ifdef SERVER #define COM_OPTS ":dvf:s:i:nIz" #else #define COM_OPTS ":dvf:i:nIz" #endif cards = last_card = 0; nosyslog = 0; verbose = 0; irqflag = 0; irqmask = irq_init(); while ((count = getopt(argc, argv, COM_OPTS)) != -1) { switch (count) { case 'd': setbuf(stdout, 0); setbuf(stderr, 0); debug = 1; break; case 'v': verbose++; break; case 'f': conf = optarg; break; case 'n': nosyslog = 1; break; case 'i': /* supress specified irq */ if (sscanf(optarg, "%d", &i) != 1) { fprintf(stderr, "%s: -i number\n", argv[0]); exit(1); } irqmask &= ~(1u << i); break; #ifdef SERVER case 's': sock = optarg; break; #endif /* SERVER */ case 'z': delay = 1; break; case ':': die("No config file argument"); break; case 'I': /* do not take kernel's advice */ irqflag = 1; irqmask = 0; break; case '?': die("Illegal option"); break; } } #ifdef DEBUG debug = 1; #endif /* Mem allocation done in MEMUNIT units. */ io_avail = bit_alloc(IOPORTS); /* Only supports ISA ports */ mem_avail = bit_alloc(MEMBLKS); io_kern = bit_alloc(IOPORTS); /* Only supports ISA ports */ mem_kern = bit_alloc(MEMBLKS); resource_init(); if (!conf) { if ((fp = fopen(config_file, "r"))) { conf = config_file; fclose(fp); } else if ((fp = fopen(stand_config_file, "r"))) { conf = stand_config_file; fclose(fp); } } if (!conf) die("can't open default config file"); readfile(conf, irqmask); log_setup(); if (2 <= verbose) dump_config_file(); if (verbose) dump_resource(); if (!debug && !delay) if (daemon(0, 0)) die("fork failed"); readslots(); if (slots == 0) die("No PC-CARD slots"); if (delay) if (daemon(0, 0)) die("fork failed"); fp = fopen(pid_file, "w"); if (fp) { fprintf(fp, "%d\n", getpid()); (void)fclose(fp); } logmsg("pccardd started", NULL); #ifdef SERVER if ((server_sock = socket(PF_LOCAL, SOCK_DGRAM, 0)) < 0) die("socket failed"); bzero(&sun, sizeof(sun)); sun.sun_family = AF_UNIX; if (sock) { socket_name = sock; } strcpy(sun.sun_path, socket_name); slen = SUN_LEN(&sun); (void)unlink(socket_name); if (bind(server_sock, (struct sockaddr *) & sun, slen) < 0) die("bind failed"); chown(socket_name, 0, 5); /* XXX - root.operator */ chmod(socket_name, 0660); set_socket(server_sock); #endif /* SERVER */ (void)signal(SIGINT, debug ? term : SIG_IGN); (void)signal(SIGTERM, term); (void)signal(SIGHUP, (void (*)(int))restart); for (;;) { fd_set rmask, emask; FD_ZERO(&emask); #ifdef SERVER FD_ZERO(&rmask); #endif /* SERVER */ for (sp = slots; sp; sp = sp->next) FD_SET(sp->fd, &emask); #ifdef SERVER FD_SET(server_sock, &rmask); count = select(32, &rmask, 0, &emask, 0); #else /* SERVER */ count = select(32, 0, 0, &emask, 0); #endif /* SERVER */ if (count == -1) { perror("Select"); continue; } if (count) { for (sp = slots; sp; sp = sp->next) if (FD_ISSET(sp->fd, &emask)) slot_change(sp); #ifdef SERVER if (FD_ISSET(server_sock, &rmask)) process_client(); #endif /* SERVER */ } } }