summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pccard/pccardd/cardd.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/pccard/pccardd/cardd.c')
-rw-r--r--usr.sbin/pccard/pccardd/cardd.c701
1 files changed, 701 insertions, 0 deletions
diff --git a/usr.sbin/pccard/pccardd/cardd.c b/usr.sbin/pccard/pccardd/cardd.c
new file mode 100644
index 0000000..ce97520
--- /dev/null
+++ b/usr.sbin/pccard/pccardd/cardd.c
@@ -0,0 +1,701 @@
+#define HERE() printf("<%d>\n",__LINE__)
+/*
+ * pcmciad
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <varargs.h>
+#include "cardd.h"
+
+
+char *config_file = "/etc/card.conf";
+
+struct card_config *assign_driver(struct card *);
+int setup_slot(struct slot *);
+void read_ether(struct slot *);
+void dump_config_file();
+void pr_cmd(struct cmd *);
+void readslots();
+void slot_change(struct slot *);
+void card_removed(struct slot *);
+void card_inserted(struct slot *);
+
+/*
+ * mainline code for cardd
+ */
+main(int argc, char *argv[])
+{
+struct slot *sp;
+int mask, count, debug = 0, err = 0;
+int verbose = 0;
+extern char *optarg;
+extern int optind, optopt;
+
+ while ((count = getopt(argc, argv, ":dvf:")) != -1) {
+ switch(count) {
+ case 'd':
+ setbuf(stdout,0);
+ setbuf(stderr,0);
+ debug = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'f':
+ config_file = optarg;
+ break;
+ case ':':
+ die("No config file argument");
+ break;
+ case '?':
+ die("Illegal option");
+ break;
+ }
+ }
+#ifdef DEBUG
+ debug = 1;
+#endif
+ io_avail = bit_alloc(IOPORTS); /* Only supports ISA ports */
+/*
+ * Mem allocation done in MEMUNIT units.
+ */
+ mem_avail = bit_alloc(MEMBLKS);
+ readfile(config_file);
+ if (verbose)
+ dump_config_file();
+ if (!debug)
+ {
+ if (daemon(0, 0))
+ die("fork failed");
+ openlog("cardd", LOG_PID, LOG_DAEMON);
+ do_log = 1;
+ }
+ printf("Before readslots\n");
+ readslots();
+ printf("After readslots\n");
+ if (slots == 0)
+ die("No PC-CARD slots");
+ for (;;)
+ {
+ mask = 0;
+ for (sp = slots; sp; sp = sp->next)
+ mask |= sp->mask;
+printf("Doing select\n");
+ count = select(32, 0, 0, &mask, 0);
+ if (count == -1)
+ {
+ perror("Select");
+ continue;
+ }
+ if (count)
+ for (sp = slots; sp; sp = sp->next)
+ if (mask & sp->mask)
+ slot_change(sp);
+ }
+}
+/*
+ * Dump configuration file data.
+ */
+void
+dump_config_file()
+{
+struct driver *drvp;
+struct device *devp;
+struct card *cp;
+struct card_config *confp;
+
+ for (cp = cards; cp; cp = cp->next)
+ {
+ printf("Card manuf %s, vers %s\n", cp->manuf, cp->version);
+ printf("Configuration entries:\n");
+ for (confp = cp->config; confp; confp = confp->next)
+ printf("\tIndex code = 0x%x, driver name = %s\n",
+ confp->index, confp->driver->name);
+ if (cp->insert)
+ {
+ printf("Insert commands are:\n");
+ pr_cmd(cp->insert);
+ }
+ if (cp->remove)
+ {
+ printf("Remove commands are:\n");
+ pr_cmd(cp->remove);
+ }
+ }
+#if 0
+ for (devp = devlist; devp; devp = devp->next)
+ {
+ if (devp->insert)
+ {
+ printf("Insert commands are:\n");
+ pr_cmd(devp->insert);
+ }
+ if (devp->remove)
+ {
+ printf("Remove commands are:\n");
+ pr_cmd(devp->remove);
+ }
+ }
+#endif
+}
+void
+pr_cmd(struct cmd *cp)
+{
+ while (cp)
+ {
+ printf("\t%s\n", cp->line);
+ cp = cp->next;
+ }
+}
+/*
+ * readslots - read all the PCMCIA slots, and build
+ * a list of the slots.
+ */
+void
+readslots()
+{
+char name[128];
+int i, fd;
+struct slot *sp;
+
+ for (i = 0; i < MAXSLOT; i++)
+ {
+ sprintf(name, CARD_DEVICE, i);
+ fd = open(name, 2);
+ if (fd < 0)
+ continue;
+printf("opened %s\n",name);
+ sp = xmalloc(sizeof(*sp));
+ sp->fd = fd;
+ sp->mask = 1 << fd;
+ sp->name = newstr(name);
+ sp->slot = i;
+ sp->state = empty;
+/*
+ * Check to see if the controller memory has been set up.
+ */
+ if (slots == 0)
+ {
+ unsigned long mem = 0;
+
+HERE();
+ if (ioctl(fd, PIOCRWMEM, &mem))
+ perror("ioctl (PIOCRWMEM)");
+ if (mem == 0)
+ {
+HERE();
+ mem = alloc_memory(4*1024);
+HERE();
+ if (mem == 0)
+ die("Can't allocate memory for controller access");
+ if (ioctl(fd, PIOCRWMEM, &mem))
+ perror("ioctl (PIOCRWMEM)");
+ }
+ }
+ sp->next = slots;
+ slots = sp;
+HERE();
+#if 0
+ slot_change(sp);
+#endif
+HERE();
+ }
+}
+/*
+ * slot_change - Card status has changed.
+ * read new state and process.
+ */
+void
+slot_change(struct slot *sp)
+{
+int state;
+
+ current_slot = sp;
+HERE();
+ if (ioctl(sp->fd, PIOCGSTATE, &state))
+ {
+ perror("ioctl (PIOCGSTATE)");
+ return;
+ }
+HERE();
+ if (state == sp->state)
+ return;
+HERE();
+ sp->state = state;
+HERE();
+ switch (sp->state)
+ {
+ case empty:
+ case noslot:
+HERE();
+ card_removed(sp);
+HERE();
+ break;
+ case filled:
+HERE();
+ card_inserted(sp);
+HERE();
+ break;
+ }
+}
+/*
+ * card_removed - card has been removed from slot.
+ * Execute the remove commands, and clear the slot's state.
+ * Execute the device commands, then the driver commands
+ * and then the card commands. This is the reverse
+ * order to the insertion commands
+ */
+void
+card_removed(struct slot *sp)
+{
+struct driver *drvp;
+struct card *cp;
+
+HERE();
+ if (sp->cis)
+ freecis(sp->cis);
+ if (sp->config)
+ {
+ sp->config->inuse = 0;
+ sp->config->driver->inuse = 0;
+ }
+HERE();
+ if (cp = sp->card)
+ execute(cp->remove);
+HERE();
+ sp->cis = 0;
+ sp->config = 0;
+HERE();
+}
+/*
+ * card_inserted - Card has been inserted;
+ * - Read the CIS
+ * - match the card type.
+ * - Match the driver and allocate a driver instance.
+ * - Allocate I/O ports, memory and IRQ.
+ * - Set up the slot.
+ * - assign the driver (if failed, then terminate).
+ * - Run the card commands.
+ * - Run the driver commands
+ * - Run the device commands
+ */
+void
+card_inserted(struct slot *sp)
+{
+struct card *cp;
+
+ sp->cis = readcis(sp->fd);
+ if (sp->cis == 0)
+ {
+ log_1s("Error reading CIS on %s\n", sp->name);
+ return;
+ }
+ for (cp = cards; cp; cp = cp->next)
+ if (strcmp(cp->manuf, sp->cis->manuf) == 0 &&
+ strcmp(cp->version, sp->cis->vers) == 0)
+ break;
+ sp->card = cp;
+/*
+ reset_slot(sp);
+ */
+ if (cp == 0)
+ {
+ log_1s("No card in database for %s", sp->cis->manuf);
+ return;
+ }
+ if (cp->ether)
+ read_ether(sp);
+ sp->config = assign_driver(cp);
+ if (sp->config == 0)
+ {
+ execute(cp->insert);
+ return;
+ }
+ if (assign_io(sp))
+ {
+ log_1s("Resource allocation failure for %s", sp->cis->manuf);
+ return;
+ }
+/*
+ * Once assigned, then set up the I/O & mem contexts, and
+ * set up the windows, and then attach the driver.
+ */
+ if (setup_slot(sp))
+ execute(cp->insert);
+#if 0
+ else
+ reset_slot(sp);
+#endif
+}
+/*
+ * read_ether - read ethernet address from card. Offset is
+ * the offset into the attribute memory of the card.
+ */
+void
+read_ether(struct slot *sp)
+{
+unsigned char net_addr[12], *p;
+
+ lseek(sp->fd, (off_t)sp->card->ether, SEEK_SET);
+ if (read(sp->fd, net_addr, sizeof(net_addr)) != sizeof(net_addr))
+ {
+ logerr("read err on net addr");
+ return;
+ }
+ sp->eaddr[0] = net_addr[0];
+ sp->eaddr[1] = net_addr[2];
+ sp->eaddr[2] = net_addr[4];
+ sp->eaddr[3] = net_addr[6];
+ sp->eaddr[4] = net_addr[8];
+ sp->eaddr[5] = net_addr[10];
+}
+/*
+ * assign_driver - Assign driver to card.
+ * First, see if an existing driver is already setup.
+ */
+struct card_config *
+assign_driver(struct card *cp)
+{
+struct driver *drvp;
+struct card_config *conf;
+
+ for (conf = cp->config; conf; conf = conf->next)
+ if (conf->inuse == 0 && conf->driver->card == cp &&
+ conf->driver->config == conf)
+ {
+#ifdef DEBUG
+ fprintf(stderr, "Found existing driver (%s) for %s\n",
+ conf->driver->name, cp->manuf);
+#endif /* DEBUG */
+ return(conf);
+ }
+/*
+ * New driver must be allocated. Find one that matches the
+ * any configurations not in use.
+ */
+ for (conf = cp->config; conf; conf = conf->next)
+ if (conf->inuse == 0 && conf->driver->card == 0)
+ break;
+ if (conf == 0)
+ {
+ log_1s("No free configuration for card %s", cp->manuf);
+ return(0);
+ }
+/*
+ * Now we have a free driver and a matching configuration.
+ * Before assigning and allocating everything, check to
+ * see if a device class can be allocated to this.
+ */
+ drvp = conf->driver;
+/*
+ * If none available, then we can't use this card.
+ */
+ if (drvp->inuse)
+ {
+ log_1s("Driver already being used for %s", cp->manuf);
+ return(0);
+ }
+#if 0
+/*
+ * Allocate I/O, memory and IRQ resources.
+ */
+ for (ap = drvp->io; ap; ap = ap->next)
+ {
+ if (ap->addr == 0 && ap->size)
+ {
+ int i = bit_fns(io_avail, IOPORTS, ap->size);
+
+ if (i < 0)
+ {
+ log_1s("Failed to allocate I/O ports for %s\n",
+ cp->manuf);
+ return(0);
+ }
+ ap->addr = i;
+ bit_nclear(io_avail, i, ap->size);
+ }
+ }
+ if (drvp->irq == 0)
+ {
+ int i;
+ for (i = 1; i < 16; i++)
+ if (pool_irq[i])
+ {
+ drvp->irq = i;
+ pool_irq[i] = 0;
+ break;
+ }
+ if (drvp->irq == 0)
+ {
+ log_1s("Failed to allocate IRQ for %s\n", cp->manuf);
+ return(0);
+ }
+ }
+ for (ap = drvp->mem; ap; ap = ap->next)
+ {
+ if (ap->addr == 0 && ap->size)
+ {
+ ap->addr = alloc_memory(ap->size);
+ if (ap->addr == 0)
+ {
+ log_1s("Failed to allocate memory for %s\n",
+ cp->manuf);
+ return(0);
+ }
+ }
+ }
+#endif /* 0 */
+ drvp->card = cp;
+ drvp->config = conf;
+ drvp->inuse = 1;
+ conf->inuse = 1;
+ return(conf);
+}
+/*
+ * assign_io - Allocate resources to slot matching the
+ * configuration index selected.
+ */
+int
+assign_io(struct slot *sp)
+{
+struct cis *cis;
+struct cis_config *cisconf, *defconf;
+
+ cis = sp->cis;
+ defconf = cis->def_config;
+ for (cisconf = cis->conf; cisconf; cisconf = cisconf->next)
+ if (cisconf->id == sp->config->index)
+ break;
+ if (cisconf == 0)
+ return(-1);
+ sp->card_config = cisconf;
+/*
+ * Found a matching configuration. Now look at the I/O, memory and IRQ
+ * to create the desired parameters. Look at memory first.
+ */
+ if (cisconf->memspace || (defconf && defconf->memspace))
+ {
+ struct cis_memblk *mp;
+
+ mp = cisconf->mem;
+ if (!cisconf->memspace)
+ mp = defconf->mem;
+ sp->mem.size = mp->length;
+ sp->mem.cardaddr = mp->address;
+/*
+ * For now, we allocate our own memory from the pool.
+ */
+ sp->mem.addr = sp->config->driver->mem;
+/*
+ * Host memory address is required. Allocate one
+ * from our pool.
+ */
+ if (sp->mem.size && sp->mem.addr == 0)
+ {
+ sp->mem.addr = alloc_memory(mp->length);
+ if (sp->mem.addr == 0)
+ return(-1);
+ sp->config->driver->mem = sp->mem.addr;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Using mem addr 0x%x, size %d, card addr 0x%x\n",
+ sp->mem.addr, sp->mem.cardaddr, sp->mem.size);
+#endif /* DEBUG */
+ }
+/*
+ * Now look at I/O.
+ */
+ bzero(&sp->io, sizeof(sp->io));
+ if (cisconf->iospace || (defconf && defconf->iospace))
+ {
+ struct cis_config *cp;
+
+ cp = cisconf;
+ if (!cisconf->iospace)
+ cp = defconf;
+/*
+ * If # of I/O lines decoded == 10, then card does its
+ * own decoding.
+ */
+/*
+ * If an I/O block exists, then use it.
+ * If no address (but a length) is available, allocate
+ * from the pool.
+ */
+ if (cp->io)
+ {
+ sp->io.addr = cp->io->addr;
+ sp->io.size = cp->io->size;
+ }
+/*
+ * No I/O block, assume the address lines decode gives the size.
+ */
+ else
+ sp->io.size = 1 << cp->io_addr;
+ if (sp->io.addr == 0)
+ {
+ int i = bit_fns(io_avail, IOPORTS, sp->io.size);
+
+ if (i < 0)
+ return(-1);
+ sp->io.addr = i;
+ }
+ bit_nclear(io_avail, sp->io.addr, sp->io.size);
+/*
+ * Set up the size to take into account the decode lines.
+ */
+ sp->io.cardaddr = cp->io_addr;
+ switch(cp->io_bus)
+ {
+ case 0:
+ break;
+ case 1:
+ sp->io.flags = IODF_WS;
+ break;
+ case 2:
+ sp->io.flags = IODF_WS|IODF_CS16;
+ break;
+ case 3:
+ sp->io.flags = IODF_WS|IODF_CS16|IODF_16BIT;
+ break;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Using I/O addr 0x%x, size %d\n",
+ sp->io.addr, sp->io.size);
+#endif /* DEBUG */
+ }
+ sp->irq = sp->config->irq;
+ return(0);
+}
+/*
+ * setup_slot - Allocate the I/O and memory contexts
+ * return true if completed OK.
+ */
+int
+setup_slot(struct slot *sp)
+{
+struct mem_desc mem;
+struct io_desc io;
+struct drv_desc drv;
+struct allocblk *ap;
+struct driver *drvp = sp->config->driver;
+char c;
+off_t offs;
+int rw_flags;
+
+ offs = sp->cis->reg_addr;
+ rw_flags = MDF_ATTR;
+ ioctl(sp->fd, PIOCRWFLAG, &rw_flags);
+ lseek(sp->fd, offs, SEEK_SET);
+ c = 0x80;
+ write(sp->fd, &c, sizeof(c));
+ usleep(sp->card->reset_time*1000);
+ lseek(sp->fd, offs, SEEK_SET);
+ c = 0x00;
+ write(sp->fd, &c, sizeof(c));
+ usleep(sp->card->reset_time*1000);
+ lseek(sp->fd, offs, SEEK_SET);
+ c = sp->config->index;
+ write(sp->fd, &c, sizeof(c));
+#ifdef DEBUG
+ printf("Setting config reg at offs 0x%x to 0x%x\n",
+ sp->cis->reg_addr, c);
+ printf("Reset time = %d ms\n", sp->card->reset_time);
+#endif
+ usleep(sp->card->reset_time*1000);
+/*
+ * If other config registers exist, set them up.
+ */
+ if (sp->cis->ccrs & 2) /* CCSR */
+ {
+ c = 0;
+ if (sp->cis->def_config && sp->cis->def_config->misc_valid &&
+ (sp->cis->def_config->misc & 0x8))
+ c |= 0x08;
+ if (sp->card_config->io_bus == 1)
+ c |= 0x20;
+ lseek(sp->fd, offs+2, SEEK_SET);
+ write(sp->fd, &c, sizeof(c));
+#ifdef DEBUG
+ printf("Setting CCSR reg to 0x%x\n", c);
+#endif
+ }
+ mem.window = 0;
+ if (sp->mem.size)
+ {
+ mem.window = 0;
+ mem.flags = sp->mem.flags;
+ mem.start = (caddr_t)sp->mem.addr;
+ mem.card = sp->mem.cardaddr;
+ mem.size = sp->mem.size;
+ if (ioctl(sp->fd, PIOCSMEM, &mem))
+ {
+ logerr("ioctl (PIOCSMEM)");
+ return(0);
+ }
+ }
+ io.window = 0;
+ if (sp->io.size)
+ {
+ io.flags = sp->io.flags;
+ io.start = sp->io.addr;
+ io.size = sp->io.size;
+/*
+ io.start = sp->io.addr & ~((1 << sp->io.cardaddr)-1);
+ io.size = 1 << sp->io.cardaddr;
+ if (io.start < 0x100)
+ {
+ io.start = 0x100;
+ io.size = 0x300;
+ }
+ */
+#ifdef DEBUG
+ printf("Assigning I/O window 0, start 0x%x, size 0x%x\n",
+ io.start, io.size);
+#endif
+ if (ioctl(sp->fd, PIOCSIO, &io))
+ {
+ logerr("ioctl (PIOCSIO)");
+ return(0);
+ }
+ }
+ strcpy(drv.name, drvp->kernel);
+ drv.unit = drvp->unit;
+ drv.irqmask = 1 << sp->irq;
+ if (sp->mem.size)
+ {
+ drv.mem = sp->mem.addr;
+ drv.memsize = sp->mem.size;
+ }
+ else
+ {
+ drv.mem = 0;
+ drv.memsize = 0;
+ }
+ if (sp->io.size)
+ drv.iobase = sp->io.addr;
+ else
+ drv.iobase = 0;
+#ifdef DEBUG
+ fprintf(stderr, "Assign %s%d, io 0x%x, mem 0x%x, %d bytes, irq %x\n",
+ drv.name, drv.unit, drv.iobase, drv.mem, drv.memsize, drv.irqmask);
+#endif /* DEBUG */
+/*
+ * If the driver fails to be connected to the device,
+ * then it may mean that the driver did not recognise it.
+ */
+ if (ioctl(sp->fd, PIOCSDRV, &drv))
+ {
+#ifdef DEBUG
+ perror(sp->card->manuf);
+#endif
+ log_1s("driver allocation failed for %s", sp->card->manuf);
+ return(0);
+ }
+ return(1);
+}
OpenPOWER on IntegriCloud