Finish implementing interrupt-driven card insertion and removal support.

- Deactivate the card on removal and queue a REMOVAL event for the socket's
event thread to finish the detach.
- Queue an INSERTION event for the socket's event thread on insertion.

Implement a few missing infrastructure pieces to support this.

Hot swapping of PCMCIA cards now "works".  (Not quite; things like network
devices need changes for their respestive subsystems.  These changes are
coming soon...)
This commit is contained in:
thorpej 1998-11-17 08:49:11 +00:00
parent ab1b371163
commit 0c3ca7b31e
4 changed files with 101 additions and 30 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: i82365.c,v 1.14 1998/11/16 22:41:01 thorpej Exp $ */
/* $NetBSD: i82365.c,v 1.15 1998/11/17 08:49:11 thorpej Exp $ */
#define PCICDEBUG
@ -80,7 +80,8 @@ int pcic_print __P((void *arg, const char *pnp));
int pcic_intr_socket __P((struct pcic_handle *));
void pcic_attach_card __P((struct pcic_handle *));
void pcic_detach_card __P((struct pcic_handle *));
void pcic_detach_card __P((struct pcic_handle *, int));
void pcic_deactivate_card __P((struct pcic_handle *));
void pcic_chip_do_mem_map __P((struct pcic_handle *, int));
void pcic_chip_do_io_map __P((struct pcic_handle *, int));
@ -388,7 +389,7 @@ pcic_event_thread(arg)
case PCIC_EVENT_REMOVAL:
DPRINTF(("%s: removal event\n", h->sc->dev.dv_xname));
pcic_detach_card(h);
pcic_detach_card(h, DETACH_FORCE);
break;
default:
@ -589,7 +590,11 @@ pcic_intr_socket(h)
}
} else {
if (h->flags & PCIC_FLAG_CARDP) {
/* XXX Should deactivate children NOW. */
/* Deactivate the card now. */
DPRINTF(("%s: deactivating card\n",
h->sc->dev.dv_xname));
pcic_deactivate_card(h);
DPRINTF(("%s: enqueing REMOVAL event\n",
h->sc->dev.dv_xname));
pcic_queue_event(h, PCIC_EVENT_REMOVAL);
@ -632,37 +637,46 @@ void
pcic_attach_card(h)
struct pcic_handle *h;
{
if (h->flags & PCIC_FLAG_CARDP)
panic("pcic_attach_card: already attached");
/* call the MI attach function */
pcmcia_card_attach(h->pcmcia);
h->flags |= PCIC_FLAG_CARDP;
}
void
pcic_detach_card(h)
pcic_detach_card(h, flags)
struct pcic_handle *h;
int flags; /* DETACH_* */
{
if (!(h->flags & PCIC_FLAG_CARDP))
panic("pcic_attach_card: already detached");
h->flags &= ~PCIC_FLAG_CARDP;
/* call the MI attach function */
/* call the MI detach function */
pcmcia_card_detach(h->pcmcia, flags);
}
pcmcia_card_detach(h->pcmcia);
void
pcic_deactivate_card(h)
struct pcic_handle *h;
{
/* disable card detect resume and configuration reset */
if (!(h->flags & PCIC_FLAG_CARDP))
panic("pcic_deactivate_card: already detached");
/* call the MI deactivate function */
pcmcia_card_deactivate(h->pcmcia);
/* power down the socket */
pcic_write(h, PCIC_PWRCTL, 0);
/* reset the card */
/* reset the socket */
pcic_write(h, PCIC_INTR, 0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcmcia.c,v 1.10 1998/11/14 01:54:25 thorpej Exp $ */
/* $NetBSD: pcmcia.c,v 1.11 1998/11/17 08:49:12 thorpej Exp $ */
#define PCMCIADEBUG
@ -167,7 +167,16 @@ pcmcia_card_attach(dev)
if (pf->cfe_head.sqh_first == NULL)
continue;
#ifdef DIAGNOSTIC
if (pf->child != NULL) {
printf("%s: %s still attached to function %d!\n",
sc->dev.dv_xname, pf->child->dv_xname,
pf->number);
panic("pcmcia_card_attach");
}
#endif
pf->sc = sc;
pf->child = NULL;
pf->cfe = NULL;
pf->ih_fct = NULL;
pf->ih_arg = NULL;
@ -183,8 +192,8 @@ pcmcia_card_attach(dev)
paa.card = &sc->card;
paa.pf = pf;
if (config_found_sm(&sc->dev, &paa, pcmcia_print,
pcmcia_submatch)) {
if ((pf->child = config_found_sm(&sc->dev, &paa, pcmcia_print,
pcmcia_submatch)) != NULL) {
attached++;
DPRINTF(("%s: function %d CCR at %d "
@ -203,23 +212,57 @@ pcmcia_card_attach(dev)
}
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;
struct pcmcia_function *pf;
/* XXX Implement me!
*
* Should:
*
* - ensure child is deactivated
*
* - config_detach child
*
* We assume we have context (and can block).
/*
* 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.
*/
printf("%s: pcmcia_card_detach called!\n", sc->dev.dv_xname);
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
@ -557,6 +600,17 @@ pcmcia_io_map(pf, width, offset, size, pcihp, windowp)
return (0);
}
void
pcmcia_io_unmap(pf, window)
struct pcmcia_function *pf;
int window;
{
pcmcia_chip_io_unmap(pf->sc->pct, pf->sc->pch, window);
/* XXX Anything for multi-function cards? */
}
void *
pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg)
struct pcmcia_function *pf;

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcmciachip.h,v 1.2 1997/10/16 23:27:36 thorpej Exp $ */
/* $NetBSD: pcmciachip.h,v 1.3 1998/11/17 08:49:12 thorpej Exp $ */
/*
* Copyright (c) 1997 Marc Horowitz. All rights reserved.
@ -138,7 +138,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_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcmciavar.h,v 1.6 1998/10/10 21:59:40 thorpej Exp $ */
/* $NetBSD: pcmciavar.h,v 1.7 1998/11/17 08:49:13 thorpej Exp $ */
/*
* Copyright (c) 1997 Marc Horowitz. All rights reserved.
@ -114,6 +114,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
@ -246,6 +247,7 @@ 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 *));
void pcmcia_io_unmap __P((struct pcmcia_function *, int));
#define pcmcia_mem_alloc(pf, size, pcmhp) \
(pcmcia_chip_mem_alloc((pf)->sc->pct, (pf)->sc->pch, (size), (pcmhp)))