diff options
Diffstat (limited to 'sys/dev/ic/i82365.c')
-rw-r--r-- | sys/dev/ic/i82365.c | 179 |
1 files changed, 107 insertions, 72 deletions
diff --git a/sys/dev/ic/i82365.c b/sys/dev/ic/i82365.c index 92546233e4d..3e5cb36f5c5 100644 --- a/sys/dev/ic/i82365.c +++ b/sys/dev/ic/i82365.c @@ -1,4 +1,4 @@ -/* $OpenBSD: i82365.c,v 1.14 2000/06/23 16:53:07 aaron Exp $ */ +/* $OpenBSD: i82365.c,v 1.15 2000/06/28 17:48:10 aaron Exp $ */ /* $NetBSD: i82365.c,v 1.10 1998/06/09 07:36:55 thorpej Exp $ */ /* @@ -99,7 +99,7 @@ void pcic_chip_do_io_map __P((struct pcic_handle *, int)); void pcic_create_event_thread __P((void *)); void pcic_event_thread __P((void *)); - +void pcic_event_process __P((struct pcic_handle *, struct pcic_event *)); void pcic_queue_event __P((struct pcic_handle *, int)); void pcic_wait_ready __P((struct pcic_handle *)); @@ -434,78 +434,81 @@ pcic_event_thread(arg) (void) tsleep((caddr_t)pcic_event_thread, PWAIT, "pcicss", hz/4); } + pcic_event_process(h, pe); + } + + h->event_thread = NULL; + + /* In case parent is waiting for us to exit. */ + wakeup(sc); + + kthread_exit(0); +} + +void +pcic_event_process(h, pe) + struct pcic_handle *h; + struct pcic_event *pe; +{ + int s; + + s = splhigh(); + SIMPLEQ_REMOVE_HEAD(&h->events, pe, pe_q); + splx(s); + + switch (pe->pe_type) { + case PCIC_EVENT_INSERTION: s = splhigh(); - SIMPLEQ_REMOVE_HEAD(&h->events, pe, pe_q); - splx(s); + while (1) { + struct pcic_event *pe1, *pe2; - switch (pe->pe_type) { - case PCIC_EVENT_INSERTION: - s = splhigh(); - while (1) { - struct pcic_event *pe1, *pe2; - - if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL) - break; - if (pe1->pe_type != PCIC_EVENT_REMOVAL) - break; - if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL) - break; - if (pe2->pe_type == PCIC_EVENT_INSERTION) { - SIMPLEQ_REMOVE_HEAD(&h->events, pe1, - pe_q); - free(pe1, M_TEMP); - SIMPLEQ_REMOVE_HEAD(&h->events, pe2, - pe_q); - free(pe2, M_TEMP); - } + if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL) + break; + if (pe1->pe_type != PCIC_EVENT_REMOVAL) + break; + if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL) + break; + if (pe2->pe_type == PCIC_EVENT_INSERTION) { + SIMPLEQ_REMOVE_HEAD(&h->events, pe1, pe_q); + free(pe1, M_TEMP); + SIMPLEQ_REMOVE_HEAD(&h->events, pe2, pe_q); + free(pe2, M_TEMP); } - splx(s); + } + splx(s); - DPRINTF(("%s: insertion event\n", - h->ph_parent->dv_xname)); - pcic_attach_card(h); - break; - - case PCIC_EVENT_REMOVAL: - s = splhigh(); - while (1) { - struct pcic_event *pe1, *pe2; - - if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL) - break; - if (pe1->pe_type != PCIC_EVENT_INSERTION) - break; - if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL) - break; - if (pe2->pe_type == PCIC_EVENT_REMOVAL) { - SIMPLEQ_REMOVE_HEAD(&h->events, pe1, - pe_q); - free(pe1, M_TEMP); - SIMPLEQ_REMOVE_HEAD(&h->events, pe2, - pe_q); - free(pe2, M_TEMP); - } - } - splx(s); + DPRINTF(("%s: insertion event\n", h->ph_parent->dv_xname)); + pcic_attach_card(h); + break; - DPRINTF(("%s: removal event\n", - h->ph_parent->dv_xname)); - pcic_detach_card(h, DETACH_FORCE); - break; + case PCIC_EVENT_REMOVAL: + s = splhigh(); + while (1) { + struct pcic_event *pe1, *pe2; - default: - panic("pcic_event_thread: unknown event %d", - pe->pe_type); + if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL) + break; + if (pe1->pe_type != PCIC_EVENT_INSERTION) + break; + if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL) + break; + if (pe2->pe_type == PCIC_EVENT_REMOVAL) { + SIMPLEQ_REMOVE_HEAD(&h->events, pe1, pe_q); + free(pe1, M_TEMP); + SIMPLEQ_REMOVE_HEAD(&h->events, pe2, pe_q); + free(pe2, M_TEMP); + } } - free(pe, M_TEMP); - } - - h->event_thread = NULL; + splx(s); - /* In case parent is waiting for us to exit. */ - wakeup(sc); + DPRINTF(("%s: removal event\n", h->ph_parent->dv_xname)); + pcic_detach_card(h, DETACH_FORCE); + break; - kthread_exit(0); + default: + panic("pcic_event_thread: unknown event %d", pe->pe_type); + } + free(pe, M_TEMP); } void @@ -669,16 +672,13 @@ pcic_poll_intr(arg) void *arg; { struct pcic_softc *sc = arg; - int i, s; - - s = spltty(); + int i; for (i = 0; i < PCIC_NSLOTS; i++) if (sc->handle[i].flags & PCIC_FLAG_SOCKETP) pcic_intr_socket(&sc->handle[i]); - timeout_add(&sc->poll_timeout, hz / 2 ); - splx(s); + timeout_add(&sc->poll_timeout, hz / 2); } int @@ -797,9 +797,15 @@ void pcic_deactivate_card(h) struct pcic_handle *h; { + struct device *dev = (struct device *)h->pcmcia; - /* call the MI deactivate function */ - pcmcia_card_deactivate(h->pcmcia); + /* + * At suspend, apm deactivates any connected cards. If we've woken up + * to find a previously-connected device missing, and we're detaching + * it, we don't want to deactivate it again. + */ + if (dev->dv_flags & DVF_ACTIVE) + pcmcia_card_deactivate(h->pcmcia); /* power down the socket */ pcic_write(h, PCIC_PWRCTL, 0); @@ -808,6 +814,35 @@ pcic_deactivate_card(h) pcic_write(h, PCIC_INTR, 0); } +/* + * The pcic_power() function must execute BEFORE the pcmcia_power() hooks. + * During suspend, a card may have been ejected. If so, we must detach it + * completely before pcmcia_power() tries to activate it. Attempting to + * activate a card that isn't there is bad news. + */ +void +pcic_power(why, arg) + int why; + void *arg; +{ + struct pcic_handle *h = (struct pcic_handle *)arg; + struct pcic_softc *sc = (struct pcic_softc *)h->ph_parent; + struct pcic_event *pe; + + if (why != PWR_RESUME) { + if (timeout_pending(&sc->poll_timeout)) + timeout_del(&sc->poll_timeout); + } + else { + pcic_intr_socket(h); + + while ((pe = SIMPLEQ_FIRST(&h->events))) + pcic_event_process(h, pe); + + timeout_add(&sc->poll_timeout, hz / 2); + } +} + int pcic_chip_mem_alloc(pch, size, pcmhp) pcmcia_chipset_handle_t pch; |