diff options
-rw-r--r-- | sys/pccard/pccard.c | 123 |
1 files changed, 66 insertions, 57 deletions
diff --git a/sys/pccard/pccard.c b/sys/pccard/pccard.c index 949dff7..969d97d 100644 --- a/sys/pccard/pccard.c +++ b/sys/pccard/pccard.c @@ -48,7 +48,7 @@ #include <i386/isa/icu.h> #include "apm.h" -#if NAPM > 0 +#if NAPM > 0 #include <machine/apm_bios.h> #endif /* NAPM > 0 */ @@ -59,6 +59,12 @@ #include <machine/clock.h> #include <machine/md_var.h> +/* + * XXX ISA_HOLE_START is defined in <machine/pmap.h>, but it + * carries too much baggage + */ +#define ISA_HOLE_START 0xA0000 + SYSCTL_NODE(_machdep, OID_AUTO, pccard, CTLFLAG_RW, 0, "pccard"); static int pcic_resume_reset = @@ -87,6 +93,7 @@ SYSCTL_INT(_machdep_pccard, OID_AUTO, apm_pccard_resume, CTLFLAG_RW, static int allocate_driver(struct slot *, struct drv_desc *); static void inserted(void *); +static void unregister_device_interrupt(struct pccard_dev *devp); static void disable_slot(struct slot *); static int invalid_io_memory(unsigned long, int); static struct pccard_drv *find_driver(char *); @@ -289,6 +296,36 @@ power_off_slot(void *arg) } /* + * unregister_device_interrupt - Disable the interrupt generation to + * the device driver which is handling it, so we can remove it. + */ +static void +unregister_device_interrupt(struct pccard_dev *devp) +{ + struct slot *sp = devp->sp; + int s; + + s = splhigh(); + if (devp->running) { + devp->drv->unload(devp); + devp->running = 0; + if (devp->isahd.id_irq && --sp->irqref <= 0) { + printf("Return IRQ=%d\n",sp->irq); + sp->ctrl->mapirq(sp, 0); + INTRDIS(1<<sp->irq); + unregister_intr(sp->irq, slot_irq_handler); + if (devp->drv->imask) + INTRUNMASK(*devp->drv->imask,(1<<sp->irq)); + /* Remove from the PCIC controller imask */ + if (sp->ctrl->imask) + INTRUNMASK(*(sp->ctrl->imask), (1<<sp->irq)); + sp->irq = 0; + } + } + splx(s); +} + +/* * disable_slot - Disables the slot by removing * the power and unmapping the I/O */ @@ -299,40 +336,23 @@ disable_slot(struct slot *sp) struct pccard_dev *devp; /* * Unload all the drivers on this slot. Note we can't - * call remove_device from here, because this may be called - * from the event routine, which is called from the slot - * controller's ISR, and this could remove the device - * structure out in the middle of some driver activity. + * remove the device structures themselves, because this + * may be called from the event routine, which is called + * from the slot controller's ISR, and removing the structures + * shouldn't happen during the middle of some driver activity. * * Note that a race condition is possible here; if a * driver is accessing the device and it is removed, then * all bets are off... */ - for (devp = sp->devices; devp; devp = devp->next) { - if (devp->running) { - int s = splhigh(); - devp->drv->unload(devp); - devp->running = 0; - if (devp->isahd.id_irq && --sp->irqref == 0) { - printf("Return IRQ=%d\n",sp->irq); - sp->ctrl->mapirq(sp, 0); - INTRDIS(1<<sp->irq); - unregister_intr(sp->irq, slot_irq_handler); - if (devp->drv->imask) - INTRUNMASK(*devp->drv->imask,(1<<sp->irq)); - /* Remove from the PCIC controller imask */ - if (sp->ctrl->imask) - INTRUNMASK(*(sp->ctrl->imask), (1<<sp->irq)); - sp->irq = 0; - } - splx(s); - } - } - /* Power off the slot 1/2 second after remove of the card */ + for (devp = sp->devices; devp; devp = devp->next) + unregister_device_interrupt(devp); + + /* Power off the slot 1/2 second after removal of the card */ sp->poff_ch = timeout(power_off_slot, (caddr_t)sp, hz / 2); sp->pwr_off_pending = 1; - /* De-activate all contexts. */ + /* De-activate all contexts. */ for (i = 0; i < sp->ctrl->maxmem; i++) if (sp->mem[i].flags & MDF_ACTIVE) { sp->mem[i].flags = 0; @@ -346,7 +366,7 @@ disable_slot(struct slot *sp) } /* - * APM hooks for suspending and resuming. + * APM hooks for suspending and resuming. */ #if NAPM > 0 static int @@ -463,7 +483,7 @@ pccard_alloc_slot(struct slot_ctrl *cp) ap->ah_order = APM_MID_ORDER; apm_hook_establish(APM_HOOK_RESUME, ap); } -#endif /* NAPM > 0 */ +#endif /* NAPM > 0 */ return(sp); } @@ -572,7 +592,7 @@ allocate_driver(struct slot *sp, struct drv_desc *drvp) */ if (drvp->mem) devp->isahd.id_maddr = - (caddr_t)(drvp->mem + atdevbase - 0xA0000); + (caddr_t)(drvp->mem + atdevbase - ISA_HOLE_START); else devp->isahd.id_maddr = 0; devp->next = sp->devices; @@ -604,24 +624,7 @@ remove_device(struct pccard_dev *devp) * If an interrupt is enabled on this slot, * then unregister it if no-one else is using it. */ - s = splhigh(); - if (devp->running) { - devp->drv->unload(devp); - devp->running = 0; - } - if (devp->isahd.id_irq && --sp->irqref == 0) { - printf("Return IRQ=%d\n",sp->irq); - sp->ctrl->mapirq(sp, 0); - INTRDIS(1<<sp->irq); - unregister_intr(sp->irq, slot_irq_handler); - if (devp->drv->imask) - INTRUNMASK(*devp->drv->imask,(1<<sp->irq)); - /* Remove from PCIC controller imask */ - if (sp->ctrl->imask) - INTRUNMASK(*(sp->ctrl->imask),(1<<sp->irq)); - sp->irq = 0; - } - splx(s); + unregister_device_interrupt(devp); /* * Remove from device list on this slot. */ @@ -654,11 +657,15 @@ inserted(void *arg) */ sp->pwr.vcc = 50; sp->pwr.vpp = 0; + /* + * Disable any pending timeouts for this slot, and explicitly + * power it off right now. Then, re-enable the power using + * the (possibly new) power settings. + */ untimeout(power_off_slot, (caddr_t)sp, sp->poff_ch); - if (sp->pwr_off_pending) - sp->ctrl->disable(sp); - sp->pwr_off_pending = 0; + power_off_slot(sp); sp->ctrl->power(sp); + printf("Card inserted, slot %d\n", sp->slot); /* * Now start resetting the card. @@ -684,8 +691,6 @@ static void enable_beep(void *dummy) void pccard_event(struct slot *sp, enum card_event event) { - int s; - if (sp->insert_seq) { sp->insert_seq = 0; untimeout(inserted, (void *)sp, sp->insert_ch); @@ -697,7 +702,7 @@ pccard_event(struct slot *sp, enum card_event event) * data structures are not unlinked. */ if (sp->state == filled) { - s = splhigh(); + int s = splhigh(); disable_slot(sp); sp->state = empty; splx(s); @@ -736,6 +741,10 @@ slot_irq_handler(int sp) for (dp = ((struct slot *)sp)->devices; dp; dp = dp->next) if (dp->isahd.id_irq && dp->running && dp->drv->handler(dp)) return; + /* + * XXX - Should 'debounce' these for drivers that have recently + * been removed. + */ printf("Slot %d, unfielded interrupt (%d)\n", ((struct slot *)sp)->slot, ((struct slot *)sp)->irq); } @@ -986,7 +995,7 @@ crdioctl(dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p) */ pccard_mem = *(unsigned long *)data; pccard_kmem = (unsigned char *)(pccard_mem - + atdevbase - 0xA0000); + + atdevbase - ISA_HOLE_START); break; /* * Set power values @@ -1006,7 +1015,7 @@ crdioctl(dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p) else sysbeep(PCCARD_BEEP_PITCH2, PCCARD_BEEP_DURATION2); return err; - } + } return(0); } @@ -1079,7 +1088,7 @@ crd_drvinit(void *unused) dev = makedev(CDEV_MAJOR, 0); cdevsw_add(&dev,&crd_cdevsw, NULL); crd_devsw_installed = 1; - } + } } SYSINIT(crddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,crd_drvinit,NULL) |