summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1999-08-08 01:00:16 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1999-08-08 01:00:16 +0000
commita6833536653e21a3adece6249320e89dea0647f3 (patch)
treee72e3e5717aaad246a9e91df3f7cd8dea5f2a879 /sys
parente09cf6c78cf6abfe9238df036609a770d07895c7 (diff)
Support detaching. Support CIS-less cards. Style police.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pcmcia/pcmcia.c225
-rw-r--r--sys/dev/pcmcia/pcmciachip.h5
-rw-r--r--sys/dev/pcmcia/pcmciavar.h10
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)))