diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-08-08 01:00:16 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-08-08 01:00:16 +0000 |
commit | a6833536653e21a3adece6249320e89dea0647f3 (patch) | |
tree | e72e3e5717aaad246a9e91df3f7cd8dea5f2a879 /sys | |
parent | e09cf6c78cf6abfe9238df036609a770d07895c7 (diff) |
Support detaching. Support CIS-less cards. Style police.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pcmcia/pcmcia.c | 225 | ||||
-rw-r--r-- | sys/dev/pcmcia/pcmciachip.h | 5 | ||||
-rw-r--r-- | sys/dev/pcmcia/pcmciavar.h | 10 |
3 files changed, 150 insertions, 90 deletions
diff --git a/sys/dev/pcmcia/pcmcia.c b/sys/dev/pcmcia/pcmcia.c index b621fa07b0d..9f704d554c0 100644 --- a/sys/dev/pcmcia/pcmcia.c +++ b/sys/dev/pcmcia/pcmcia.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pcmcia.c,v 1.18 1999/07/30 17:13:51 deraadt Exp $ */ +/* $OpenBSD: pcmcia.c,v 1.19 1999/08/08 01:00:14 niklas Exp $ */ /* $NetBSD: pcmcia.c,v 1.9 1998/08/13 02:10:55 eeh Exp $ */ /* @@ -34,6 +34,7 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> +#include <sys/malloc.h> #include <dev/pcmcia/pcmciareg.h> #include <dev/pcmcia/pcmciachip.h> @@ -55,6 +56,7 @@ int pcmcia_match __P((struct device *, void *, void *)); int pcmcia_submatch __P((struct device *, void *, void *)); void pcmcia_attach __P((struct device *, struct device *, void *)); int pcmcia_print __P((void *, const char *)); +void pcmcia_card_detach_notify __P((struct device *, void *)); static inline void pcmcia_socket_enable __P((pcmcia_chipset_tag_t, pcmcia_chipset_handle_t *)); @@ -99,7 +101,7 @@ pcmcia_match(parent, match, aux) struct device *parent; void *match, *aux; { - /* if the autoconfiguration got this far, there's a socket here */ + /* If the autoconfiguration got this far, there's a socket here. */ return (1); } @@ -143,41 +145,59 @@ pcmcia_card_attach(dev) pcmcia_check_cis_quirks(sc); +#if 0 /* - * bail now if the card has no functions, or if there was an error in - * the cis. + * Bail now if the card has no functions, or if there was an error in + * the CIS. */ if (sc->card.error) return (1); if (sc->card.pf_head.sqh_first == NULL) return (1); +#endif if (pcmcia_verbose) pcmcia_print_cis(sc); + /* + * If there was no function, this might be CIS-less card we still + * want to probe. Fixup a function element for it. + */ + if (SIMPLEQ_FIRST(&sc->card.pf_head) == NULL) { + pf = malloc(sizeof *pf, M_DEVBUF, M_NOWAIT); + bzero(pf, sizeof *pf); + pf->number = 0; + pf->pf_flags = PFF_FAKE; + pf->last_config_index = -1; + SIMPLEQ_INIT(&pf->cfe_head); + SIMPLEQ_INSERT_TAIL(&sc->card.pf_head, pf, pf_list); + } + attached = 0; - for (pf = sc->card.pf_head.sqh_first; pf != NULL; - pf = pf->pf_list.sqe_next) { + for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL; + pf = SIMPLEQ_NEXT(pf, pf_list)) { pf->sc = sc; + pf->child = NULL; pf->cfe = NULL; pf->ih_fct = NULL; pf->ih_arg = NULL; } - for (pf = sc->card.pf_head.sqh_first; pf != NULL; - pf = pf->pf_list.sqe_next) { + for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL; + pf = SIMPLEQ_NEXT(pf, pf_list)) { paa.manufacturer = sc->card.manufacturer; paa.product = sc->card.product; paa.card = &sc->card; paa.pf = pf; - if (config_found_sm(&sc->dev, &paa, pcmcia_print, - pcmcia_submatch)) { + pf->child = config_found_sm(&sc->dev, &paa, pcmcia_print, + pcmcia_submatch); + if (pf->child) { attached++; - if (SIMPLEQ_FIRST(&pf->cfe_head)) { + if ((pf->pf_flags & PFF_FAKE) == 0) DPRINTF(("%s: function %d CCR at %d offset %lx" ": %x %x %x %x, %x %x %x %x, %x\n", sc->dev.dv_xname, pf->number, @@ -191,18 +211,63 @@ pcmcia_card_attach(dev) pcmcia_ccr_read(pf, 0x0E), pcmcia_ccr_read(pf, 0x10), pcmcia_ccr_read(pf, 0x12))); - } } } return (attached ? 0 : 1); } void -pcmcia_card_detach(dev) +pcmcia_card_detach(dev, flags) + struct device *dev; + int flags; /* DETACH_* flags */ +{ + struct pcmcia_softc *sc = (struct pcmcia_softc *) dev; + struct pcmcia_function *pf; + int error; + + /* + * We are running on either the PCMCIA socket's event thread + * or in user context detaching a device by user request. + */ + for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL; + pf = SIMPLEQ_NEXT(pf, pf_list)) { + if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL) + continue; + if (pf->child == NULL) + continue; + DPRINTF(("%s: detaching %s (function %d)\n", + sc->dev.dv_xname, pf->child->dv_xname, pf->number)); + if ((error = config_detach(pf->child, flags)) != 0) { + printf("%s: error %d detaching %s (function %d)\n", + sc->dev.dv_xname, error, pf->child->dv_xname, + pf->number); + } else + pf->child = NULL; + } +} + +void +pcmcia_card_deactivate(dev) struct device *dev; { - /* struct pcmcia_softc *sc = (struct pcmcia_softc *) dev; */ - /* don't do anything yet */ + struct pcmcia_softc *sc = (struct pcmcia_softc *) dev; + struct pcmcia_function *pf; + + /* + * We're in the chip's card removal interrupt handler. + * Deactivate the child driver. The PCMCIA socket's + * event thread will run later to finish the detach. + */ + for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL; + pf = SIMPLEQ_NEXT(pf, pf_list)) { + if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL) + continue; + if (pf->child == NULL) + continue; + DPRINTF(("%s: deactivating %s (function %d)\n", + sc->dev.dv_xname, pf->child->dv_xname, pf->number)); + config_deactivate(pf->child); + } } int @@ -273,14 +338,14 @@ pcmcia_card_gettype(dev) struct pcmcia_function *pf; /* - * set the iftype to memory if this card has no functions (not yet + * Set the iftype to memory if this card has no functions (not yet * probed), or only one function, and that is not initialized yet or * that is memory. */ pf = SIMPLEQ_FIRST(&sc->card.pf_head); - if (pf == NULL || - (SIMPLEQ_NEXT(pf, pf_list) == NULL && - (pf->cfe == NULL || pf->cfe->iftype == PCMCIA_IFTYPE_MEMORY))) + if (pf == NULL || (SIMPLEQ_NEXT(pf, pf_list) == NULL && + ((pf->pf_flags & PFF_FAKE) || + pf->cfe == NULL || pf->cfe->iftype == PCMCIA_IFTYPE_MEMORY))) return (PCMCIA_IFTYPE_MEMORY); else return (PCMCIA_IFTYPE_IO); @@ -344,8 +409,12 @@ pcmcia_function_enable(pf) return (0); } + /* If there was no CIS don't mess with CCR */ + if (pf->pf_flags & PFF_FAKE) + goto done; + /* - * it's possible for different functions' CCRs to be in the same + * It's possible for different functions' CCRs to be in the same * underlying page. Check for that. */ for (tmp = pf->sc->card.pf_head.sqh_first; tmp != NULL; @@ -445,6 +514,7 @@ pcmcia_function_enable(pf) } #endif + done: pf->pf_flags |= PFF_ENABLED; return (0); @@ -478,12 +548,17 @@ pcmcia_function_disable(pf) return; } + /* If there was no CIS don't mess with CCR */ + if (pf->pf_flags & PFF_FAKE) { + pf->pf_flags &= ~PFF_ENABLED; + goto done; + } + /* * it's possible for different functions' CCRs to be in the same * underlying page. Check for that. Note we mark us as disabled * first to avoid matching ourself. */ - pf->pf_flags &= ~PFF_ENABLED; for (tmp = pf->sc->card.pf_head.sqh_first; tmp != NULL; tmp = tmp->pf_list.sqe_next) { @@ -500,6 +575,7 @@ pcmcia_function_disable(pf) pcmcia_mem_free(pf, &pf->pf_pcmh); } + done: /* * Decrement the reference count, and power down the socket, if * necessary. @@ -526,9 +602,9 @@ pcmcia_io_map(pf, width, offset, size, pcihp, windowp) return (1); /* - * XXX in the multifunction multi-iospace-per-function case, this + * XXX In the multifunction multi-iospace-per-function case, this * needs to cooperate with io_alloc to make sure that the spaces - * don't overlap, and that the ccr's are set correctly + * don't overlap, and that the ccr's are set correctly. */ if (pcmcia_mfc(pf->sc)) { @@ -538,7 +614,7 @@ pcmcia_io_map(pf, width, offset, size, pcihp, windowp) pf->pf_mfc_iobase = pcihp->addr + offset; pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; } else { - /* this makes the assumption that nothing overlaps */ + /* This makes the assumption that nothing overlaps. */ if (pf->pf_mfc_iobase > pcihp->addr + offset) pf->pf_mfc_iobase = pcihp->addr + offset; if (pf->pf_mfc_iomax < pcihp->addr + offset + size) @@ -575,56 +651,44 @@ pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg) void *ih_arg; { void *ret; + int s, ihcnt, hiipl, reg; + struct pcmcia_function *pf2; - /* behave differently if this is a multifunction card */ - + /* Behave differently if this is a multifunction card. */ if (pcmcia_mfc(pf->sc)) { - int s, ihcnt, hiipl, reg; - struct pcmcia_function *pf2; - /* - * mask all the ipl's which are already used by this card, - * and find the highest ipl number (lowest priority) + * Mask all the ipl's which are already used by this card, + * and find the highest ipl number (lowest priority). */ - ihcnt = 0; - s = 0; /* this is only here to keep the compiler - happy */ - hiipl = 0; /* this is only here to keep the compiler - happy */ - for (pf2 = pf->sc->card.pf_head.sqh_first; pf2 != NULL; - pf2 = pf2->pf_list.sqe_next) { + pf2 = pf2->pf_list.sqe_next) if (pf2->ih_fct) { DPRINTF(("%s: function %d has ih_fct %p\n", - pf->sc->dev.dv_xname, pf2->number, - pf2->ih_fct)); + pf->sc->dev.dv_xname, pf2->number, + pf2->ih_fct)); - if (ihcnt == 0) { + if (ihcnt == 0) + hiipl = pf2->ih_ipl; + else if (pf2->ih_ipl > hiipl) hiipl = pf2->ih_ipl; - } else { - if (pf2->ih_ipl > hiipl) - hiipl = pf2->ih_ipl; - } ihcnt++; } - } /* - * establish the real interrupt, changing the ipl if - * necessary + * Establish the real interrupt, changing the ipl if + * necessary. */ - if (ihcnt == 0) { #ifdef DIAGNOSTIC if (pf->sc->ih != NULL) - panic("card has intr handler, but no function does"); + panic("card has intr handler, " + "but no function does"); #endif s = spltty(); - /* set up the handler for the new function */ - + /* Set up the handler for the new function. */ pf->ih_fct = ih_fct; pf->ih_arg = ih_arg; pf->ih_ipl = ipl; @@ -635,13 +699,14 @@ pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg) } else if (ipl > hiipl) { #ifdef DIAGNOSTIC if (pf->sc->ih == NULL) - panic("functions have ih, but the card does not"); + panic("functions have ih, " + "but the card does not"); #endif s = spltty(); pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, - pf->sc->ih); + pf->sc->ih); /* set up the handler for the new function */ pf->ih_fct = ih_fct; @@ -655,8 +720,7 @@ pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg) } else { s = spltty(); - /* set up the handler for the new function */ - + /* Set up the handler for the new function. */ pf->ih_fct = ih_fct; pf->ih_arg = ih_arg; pf->ih_ipl = ipl; @@ -675,10 +739,9 @@ pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg) reg |= PCMCIA_CCR_STATUS_INTRACK; pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg); } - } else { + } else ret = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch, pf, ipl, ih_fct, ih_arg); - } return (ret); } @@ -688,51 +751,41 @@ pcmcia_intr_disestablish(pf, ih) struct pcmcia_function *pf; void *ih; { - /* behave differently if this is a multifunction card */ + int s, reg, ihcnt, hiipl; + struct pcmcia_function *pf2; + /* Behave differently if this is a multifunction card. */ if (pcmcia_mfc(pf->sc)) { - int s, ihcnt, hiipl; - struct pcmcia_function *pf2; - /* - * mask all the ipl's which are already used by this card, + * Mask all the ipl's which are already used by this card, * and find the highest ipl number (lowest priority). Skip * the current function. */ - ihcnt = 0; - s = 0; /* this is only here to keep the compipler - happy */ - hiipl = 0; /* this is only here to keep the compipler - happy */ - for (pf2 = pf->sc->card.pf_head.sqh_first; pf2 != NULL; - pf2 = pf2->pf_list.sqe_next) { + pf2 = pf2->pf_list.sqe_next) { if (pf2 == pf) continue; if (pf2->ih_fct) { - if (ihcnt == 0) { + if (ihcnt == 0) + hiipl = pf2->ih_ipl; + else if (pf2->ih_ipl > hiipl) hiipl = pf2->ih_ipl; - } else { - if (pf2->ih_ipl > hiipl) - hiipl = pf2->ih_ipl; - } ihcnt++; } } /* - * if the ih being removed is lower priority than the lowest + * If the ih being removed is lower priority than the lowest * priority remaining interrupt, up the priority. */ - /* ihcnt is the number of interrupt handlers *not* including - the one about to be removed. */ - + /* + * ihcnt is the number of interrupt handlers *not* including + * the one about to be removed. + */ if (ihcnt == 0) { - int reg; - #ifdef DIAGNOSTIC if (pf->sc->ih == NULL) panic("disestablishing last function, but card has no ih"); @@ -760,8 +813,7 @@ pcmcia_intr_disestablish(pf, ih) pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch, pf, hiipl, pcmcia_card_intr, pf->sc); - /* null out the handler for this function */ - + /* Null out the handler for this function. */ pf->ih_fct = NULL; pf->ih_arg = NULL; @@ -774,9 +826,8 @@ pcmcia_intr_disestablish(pf, ih) splx(s); } - } else { + } else pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih); - } } int @@ -789,8 +840,8 @@ pcmcia_card_intr(arg) ret = 0; - for (pf = sc->card.pf_head.sqh_first; pf != NULL; - pf = pf->pf_list.sqe_next) { + for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL; + pf = SIMPLEQ_NEXT(pf, pf_list)) { #ifdef PCMCIADEBUG printf("%s: intr flags=%x fct=%d cor=%02x csr=%02x pin=%02x", sc->dev.dv_xname, pf->pf_flags, pf->number, diff --git a/sys/dev/pcmcia/pcmciachip.h b/sys/dev/pcmcia/pcmciachip.h index 6950c6775e9..bbe25659f85 100644 --- a/sys/dev/pcmcia/pcmciachip.h +++ b/sys/dev/pcmcia/pcmciachip.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pcmciachip.h,v 1.1 1998/09/11 10:47:15 fgsch Exp $ */ +/* $OpenBSD: pcmciachip.h,v 1.2 1999/08/08 01:00:14 niklas Exp $ */ /* $NetBSD: pcmciachip.h,v 1.2 1997/10/16 23:27:36 thorpej Exp $ */ /* @@ -139,7 +139,8 @@ struct pcmciabus_attach_args { /* interfaces for the chipset to call pcmcia */ int pcmcia_card_attach __P((struct device *)); -void pcmcia_card_detach __P((struct device *)); +void pcmcia_card_detach __P((struct device *, int)); +void pcmcia_card_deactivate __P((struct device *)); int pcmcia_card_gettype __P((struct device *)); #endif /* _PCMCIA_PCMCIACHIP_H_ */ diff --git a/sys/dev/pcmcia/pcmciavar.h b/sys/dev/pcmcia/pcmciavar.h index 8432ac08fa6..18748da441e 100644 --- a/sys/dev/pcmcia/pcmciavar.h +++ b/sys/dev/pcmcia/pcmciavar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pcmciavar.h,v 1.10 1999/07/20 21:51:21 fgsch Exp $ */ +/* $OpenBSD: pcmciavar.h,v 1.11 1999/08/08 01:00:15 niklas Exp $ */ /* $NetBSD: pcmciavar.h,v 1.5 1998/07/19 17:28:17 christos Exp $ */ /* @@ -117,6 +117,7 @@ struct pcmcia_function { SIMPLEQ_ENTRY(pcmcia_function) pf_list; /* run-time state */ struct pcmcia_softc *sc; + struct device *child; struct pcmcia_config_entry *cfe; struct pcmcia_mem_handle pf_pcmh; #define pf_ccrt pf_pcmh.memt @@ -135,6 +136,7 @@ struct pcmcia_function { /* pf_flags */ #define PFF_ENABLED 0x0001 /* function is enabled */ +#define PFF_FAKE 0x0002 /* function is made up (no CIS) */ struct pcmcia_card { int cis1_major; @@ -259,6 +261,12 @@ void pcmcia_function_disable __P((struct pcmcia_function *)); int pcmcia_io_map __P((struct pcmcia_function *, int, bus_addr_t, bus_size_t, struct pcmcia_io_handle *, int *)); +#define pcmcia_io_unmap(pf, window) \ + (pcmcia_chip_io_unmap((pf)->sc->pct, (pf)->sc->pch, (window))) + +#define pcmcia_io_free(pf, pciop) \ + (pcmcia_chip_io_free((pf)->sc->pct, (pf)->sc->pch, (pciop))) + #define pcmcia_mem_alloc(pf, size, pcmhp) \ (pcmcia_chip_mem_alloc((pf)->sc->pct, (pf)->sc->pch, (size), (pcmhp))) |