2013-10-12 20:49:00 +04:00
|
|
|
/* $NetBSD: cardslot.c,v 1.55 2013/10/12 16:49:00 christos Exp $ */
|
1999-11-15 09:08:02 +03:00
|
|
|
|
1999-10-15 10:07:17 +04:00
|
|
|
/*
|
2000-01-26 12:04:59 +03:00
|
|
|
* Copyright (c) 1999 and 2000
|
1999-10-15 10:07:17 +04:00
|
|
|
* HAYAKAWA Koichi. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2001-11-13 15:51:12 +03:00
|
|
|
#include <sys/cdefs.h>
|
2013-10-12 20:49:00 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: cardslot.c,v 1.55 2013/10/12 16:49:00 christos Exp $");
|
2001-11-13 15:51:12 +03:00
|
|
|
|
1999-10-27 13:29:18 +04:00
|
|
|
#include "opt_cardslot.h"
|
1999-10-15 10:07:17 +04:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/device.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/syslog.h>
|
|
|
|
#include <sys/kthread.h>
|
|
|
|
|
2007-10-19 15:59:34 +04:00
|
|
|
#include <sys/bus.h>
|
1999-10-15 10:07:17 +04:00
|
|
|
|
|
|
|
#include <dev/cardbus/cardslotvar.h>
|
|
|
|
#include <dev/cardbus/cardbusvar.h>
|
|
|
|
#include <dev/pcmcia/pcmciavar.h>
|
|
|
|
#include <dev/pcmcia/pcmciachip.h>
|
|
|
|
|
2004-09-13 16:55:47 +04:00
|
|
|
#include "locators.h"
|
1999-10-15 10:07:17 +04:00
|
|
|
|
|
|
|
#if defined CARDSLOT_DEBUG
|
|
|
|
#define STATIC
|
|
|
|
#define DPRINTF(a) printf a
|
|
|
|
#else
|
|
|
|
#define STATIC static
|
|
|
|
#define DPRINTF(a)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-05-21 21:32:32 +04:00
|
|
|
STATIC void cardslotchilddet(device_t, device_t);
|
2009-05-12 18:16:35 +04:00
|
|
|
STATIC void cardslotattach(device_t, device_t, void *);
|
2007-12-17 00:28:30 +03:00
|
|
|
STATIC int cardslotdetach(device_t, int);
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2009-05-12 18:16:35 +04:00
|
|
|
STATIC int cardslotmatch(device_t, cfdata_t, void *);
|
2005-02-04 05:10:35 +03:00
|
|
|
static void cardslot_event_thread(void *arg);
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2005-02-04 05:10:35 +03:00
|
|
|
STATIC int cardslot_cb_print(void *aux, const char *pcic);
|
|
|
|
static int cardslot_16_print(void *, const char *);
|
2012-10-27 21:17:22 +04:00
|
|
|
static int cardslot_16_submatch(device_t, cfdata_t, const int *, void *);
|
1999-10-15 10:07:17 +04:00
|
|
|
|
During shutdown, detach devices in an orderly fashion.
Call the detach routine for every device in the device tree, starting
with the leaves and moving toward the root, expecting that each
(pseudo-)device driver will use the opportunity to gracefully commit
outstandings transactions to the underlying (pseudo-)device and to
relinquish control of the hardware to the system BIOS.
Detaching devices is not suitable for every shutdown: in an emergency,
or if the system state is inconsistent, we should resort to a fast,
simple shutdown that uses only the pmf(9) shutdown hooks and the
(deprecated) shutdownhooks. For now, if the flag RB_NOSYNC is set in
boothowto, opt for the fast, simple shutdown.
Add a device flag, DVF_DETACH_SHUTDOWN, that indicates by its presence
that it is safe to detach a device during shutdown. Introduce macros
CFATTACH_DECL3() and CFATTACH_DECL3_NEW() for creating autoconf
attachments with default device flags. Add DVF_DETACH_SHUTDOWN
to configuration attachments for atabus(4), atw(4) at cardbus(4),
cardbus(4), cardslot(4), com(4) at isa(4), elanpar(4), elanpex(4),
elansc(4), gpio(4), npx(4) at isa(4), nsphyter(4), pci(4), pcib(4),
pcmcia(4), ppb(4), sip(4), wd(4), and wdc(4) at isa(4).
Add a device-detachment "reason" flag, DETACH_SHUTDOWN, that tells the
autoconf code and a device driver that the reason for detachment is
system shutdown.
Add a sysctl, kern.detachall, that tells the system to try to detach
every device at shutdown, regardless of any device's DVF_DETACH_SHUTDOWN
flag. The default for kern.detachall is 0. SET IT TO 1, PLEASE, TO
HELP TEST AND DEBUG DEVICE DETACHMENT AT SHUTDOWN.
This is a work in progress. In future work, I aim to treat
pseudo-devices more thoroughly, and to gracefully tear down a stack of
(pseudo-)disk drivers and filesystems, including cgd(4), vnd(4), and
raid(4) instances at shutdown.
Also commit some changes that are not easily untangled from the rest:
(1) begin to simplify device_t locking: rename struct pmf_private to
device_lock, and incorporate device_lock into struct device.
(2) #include <sys/device.h> in sys/pmf.h in order to get some
definitions that it needs. Stop unnecessarily #including <sys/device.h>
in sys/arch/x86/include/pic.h to keep the amd64, xen, and i386 releases
building.
2009-04-02 04:09:32 +04:00
|
|
|
CFATTACH_DECL3_NEW(cardslot, sizeof(struct cardslot_softc),
|
2009-05-21 21:32:32 +04:00
|
|
|
cardslotmatch, cardslotattach, cardslotdetach, NULL, NULL, cardslotchilddet,
|
During shutdown, detach devices in an orderly fashion.
Call the detach routine for every device in the device tree, starting
with the leaves and moving toward the root, expecting that each
(pseudo-)device driver will use the opportunity to gracefully commit
outstandings transactions to the underlying (pseudo-)device and to
relinquish control of the hardware to the system BIOS.
Detaching devices is not suitable for every shutdown: in an emergency,
or if the system state is inconsistent, we should resort to a fast,
simple shutdown that uses only the pmf(9) shutdown hooks and the
(deprecated) shutdownhooks. For now, if the flag RB_NOSYNC is set in
boothowto, opt for the fast, simple shutdown.
Add a device flag, DVF_DETACH_SHUTDOWN, that indicates by its presence
that it is safe to detach a device during shutdown. Introduce macros
CFATTACH_DECL3() and CFATTACH_DECL3_NEW() for creating autoconf
attachments with default device flags. Add DVF_DETACH_SHUTDOWN
to configuration attachments for atabus(4), atw(4) at cardbus(4),
cardbus(4), cardslot(4), com(4) at isa(4), elanpar(4), elanpex(4),
elansc(4), gpio(4), npx(4) at isa(4), nsphyter(4), pci(4), pcib(4),
pcmcia(4), ppb(4), sip(4), wd(4), and wdc(4) at isa(4).
Add a device-detachment "reason" flag, DETACH_SHUTDOWN, that tells the
autoconf code and a device driver that the reason for detachment is
system shutdown.
Add a sysctl, kern.detachall, that tells the system to try to detach
every device at shutdown, regardless of any device's DVF_DETACH_SHUTDOWN
flag. The default for kern.detachall is 0. SET IT TO 1, PLEASE, TO
HELP TEST AND DEBUG DEVICE DETACHMENT AT SHUTDOWN.
This is a work in progress. In future work, I aim to treat
pseudo-devices more thoroughly, and to gracefully tear down a stack of
(pseudo-)disk drivers and filesystems, including cgd(4), vnd(4), and
raid(4) instances at shutdown.
Also commit some changes that are not easily untangled from the rest:
(1) begin to simplify device_t locking: rename struct pmf_private to
device_lock, and incorporate device_lock into struct device.
(2) #include <sys/device.h> in sys/pmf.h in order to get some
definitions that it needs. Stop unnecessarily #including <sys/device.h>
in sys/arch/x86/include/pic.h to keep the amd64, xen, and i386 releases
building.
2009-04-02 04:09:32 +04:00
|
|
|
DVF_DETACH_SHUTDOWN);
|
1999-10-15 10:07:17 +04:00
|
|
|
|
|
|
|
STATIC int
|
2009-05-12 18:16:35 +04:00
|
|
|
cardslotmatch(device_t parent, cfdata_t cf,
|
2006-10-12 05:30:41 +04:00
|
|
|
void *aux)
|
1999-10-15 10:07:17 +04:00
|
|
|
{
|
2001-03-27 14:34:05 +04:00
|
|
|
struct cardslot_attach_args *caa = aux;
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
if (caa->caa_cb_attach == NULL && caa->caa_16_attach == NULL) {
|
|
|
|
/* Neither CardBus nor 16-bit PCMCIA are defined. */
|
|
|
|
return 0;
|
|
|
|
}
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
return 1;
|
1999-10-15 10:07:17 +04:00
|
|
|
}
|
|
|
|
|
2009-05-21 21:32:32 +04:00
|
|
|
STATIC void
|
|
|
|
cardslotchilddet(device_t self, device_t child)
|
|
|
|
{
|
|
|
|
struct cardslot_softc *sc = device_private(self);
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2009-05-21 21:32:32 +04:00
|
|
|
KASSERT(sc->sc_cb_softc == device_private(child) ||
|
|
|
|
sc->sc_16_softc == child);
|
|
|
|
|
|
|
|
if (sc->sc_cb_softc == device_private(child))
|
|
|
|
sc->sc_cb_softc = NULL;
|
|
|
|
else if (sc->sc_16_softc == child)
|
|
|
|
sc->sc_16_softc = NULL;
|
|
|
|
}
|
1999-10-15 10:07:17 +04:00
|
|
|
|
|
|
|
STATIC void
|
2012-10-27 21:17:22 +04:00
|
|
|
cardslotattach(device_t parent, device_t self, void *aux)
|
1999-10-15 10:07:17 +04:00
|
|
|
{
|
2006-03-29 10:22:38 +04:00
|
|
|
struct cardslot_softc *sc = device_private(self);
|
2001-03-27 14:34:05 +04:00
|
|
|
struct cardslot_attach_args *caa = aux;
|
|
|
|
|
|
|
|
struct cbslot_attach_args *cba = caa->caa_cb_attach;
|
|
|
|
struct pcmciabus_attach_args *pa = caa->caa_16_attach;
|
|
|
|
|
2003-10-25 22:34:14 +04:00
|
|
|
struct cardbus_softc *csc = NULL;
|
|
|
|
struct pcmcia_softc *psc = NULL;
|
2001-03-27 14:34:05 +04:00
|
|
|
|
2008-06-25 15:42:32 +04:00
|
|
|
sc->sc_dev = self;
|
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
sc->sc_cb_softc = NULL;
|
|
|
|
sc->sc_16_softc = NULL;
|
|
|
|
SIMPLEQ_INIT(&sc->sc_events);
|
|
|
|
sc->sc_th_enable = 0;
|
|
|
|
|
2007-12-01 07:50:50 +03:00
|
|
|
aprint_naive("\n");
|
2008-06-24 21:32:09 +04:00
|
|
|
aprint_normal("\n");
|
2001-03-27 14:34:05 +04:00
|
|
|
|
2008-06-25 15:42:32 +04:00
|
|
|
DPRINTF(("%s attaching CardBus bus...\n", device_xname(self)));
|
2001-03-27 14:34:05 +04:00
|
|
|
if (cba != NULL) {
|
2008-06-25 15:42:32 +04:00
|
|
|
csc = device_private(config_found_ia(self, "cbbus", cba,
|
|
|
|
cardslot_cb_print));
|
2004-09-13 16:55:47 +04:00
|
|
|
if (csc) {
|
2001-03-27 14:34:05 +04:00
|
|
|
/* cardbus found */
|
2007-02-05 02:39:02 +03:00
|
|
|
DPRINTF(("%s: found cardbus on %s\n", __func__,
|
2008-06-25 15:42:32 +04:00
|
|
|
device_xname(self)));
|
2001-03-27 14:34:05 +04:00
|
|
|
sc->sc_cb_softc = csc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pa != NULL) {
|
2008-07-03 22:57:52 +04:00
|
|
|
sc->sc_16_softc = config_found_sm_loc(self, "pcmciabus", NULL,
|
|
|
|
pa, cardslot_16_print,
|
|
|
|
cardslot_16_submatch);
|
|
|
|
if (sc->sc_16_softc) {
|
2001-03-27 14:34:05 +04:00
|
|
|
/* pcmcia 16-bit bus found */
|
2007-02-05 02:39:02 +03:00
|
|
|
DPRINTF(("%s: found 16-bit pcmcia bus\n", __func__));
|
2008-07-03 22:57:52 +04:00
|
|
|
psc = device_private(sc->sc_16_softc);
|
2001-03-27 14:34:05 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (csc != NULL || psc != NULL) {
|
2013-10-12 20:49:00 +04:00
|
|
|
config_pending_incr(self);
|
2007-07-10 00:51:58 +04:00
|
|
|
if (kthread_create(PRI_NONE, 0, NULL, cardslot_event_thread,
|
2008-06-24 21:32:09 +04:00
|
|
|
sc, &sc->sc_event_thread, "%s", device_xname(self))) {
|
2008-06-25 15:42:32 +04:00
|
|
|
aprint_error_dev(sc->sc_dev,
|
2008-06-24 21:32:09 +04:00
|
|
|
"unable to create thread\n");
|
2007-07-10 00:51:58 +04:00
|
|
|
panic("cardslotattach");
|
|
|
|
}
|
|
|
|
sc->sc_th_enable = 1;
|
2001-03-27 14:34:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (csc && (csc->sc_cf->cardbus_ctrl)(csc->sc_cc, CARDBUS_CD)) {
|
2007-02-05 02:39:02 +03:00
|
|
|
DPRINTF(("%s: CardBus card found\n", __func__));
|
2001-03-27 14:34:05 +04:00
|
|
|
/* attach deferred */
|
|
|
|
cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_CB);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (psc && (psc->pct->card_detect)(psc->pch)) {
|
2007-02-05 02:39:02 +03:00
|
|
|
DPRINTF(("%s: 16-bit card found\n", __func__));
|
2001-03-27 14:34:05 +04:00
|
|
|
/* attach deferred */
|
|
|
|
cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_16);
|
|
|
|
}
|
2007-12-09 23:27:42 +03:00
|
|
|
|
|
|
|
if (!pmf_device_register(self, NULL, NULL))
|
|
|
|
aprint_error_dev(self, "couldn't establish power handler\n");
|
1999-10-15 10:07:17 +04:00
|
|
|
}
|
|
|
|
|
2007-12-17 00:28:30 +03:00
|
|
|
STATIC int
|
|
|
|
cardslotdetach(device_t self, int flags)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct cardslot_softc *sc = device_private(self);
|
|
|
|
|
|
|
|
if ((rc = config_detach_children(self, flags)) != 0)
|
|
|
|
return rc;
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2007-12-17 00:28:30 +03:00
|
|
|
sc->sc_th_enable = 0;
|
|
|
|
wakeup(&sc->sc_events);
|
|
|
|
while (sc->sc_event_thread != NULL)
|
|
|
|
(void)tsleep(sc, PWAIT, "cardslotthd", 0);
|
|
|
|
|
|
|
|
if (!SIMPLEQ_EMPTY(&sc->sc_events))
|
|
|
|
aprint_error_dev(self, "events outstanding");
|
|
|
|
|
|
|
|
pmf_device_deregister(self);
|
|
|
|
return 0;
|
|
|
|
}
|
1999-10-15 10:07:17 +04:00
|
|
|
|
|
|
|
STATIC int
|
2007-02-05 02:39:02 +03:00
|
|
|
cardslot_cb_print(void *aux, const char *pnp)
|
1999-10-15 10:07:17 +04:00
|
|
|
{
|
2000-03-22 12:35:06 +03:00
|
|
|
struct cbslot_attach_args *cba = aux;
|
1999-10-29 11:27:43 +04:00
|
|
|
|
2007-02-05 02:39:02 +03:00
|
|
|
if (pnp != NULL) {
|
2003-01-01 03:10:15 +03:00
|
|
|
aprint_normal("cardbus at %s subordinate bus %d",
|
|
|
|
pnp, cba->cba_bus);
|
2000-03-22 12:35:06 +03:00
|
|
|
}
|
1999-10-29 11:27:43 +04:00
|
|
|
|
2000-03-22 12:35:06 +03:00
|
|
|
return UNCONF;
|
1999-10-15 10:07:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-05-12 18:16:35 +04:00
|
|
|
cardslot_16_submatch(device_t parent, cfdata_t cf,
|
2006-11-16 04:32:37 +03:00
|
|
|
const int *ldesc, void *aux)
|
1999-10-15 10:07:17 +04:00
|
|
|
{
|
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
if (cf->cf_loc[PCMCIABUSCF_CONTROLLER] != PCMCIABUSCF_CONTROLLER_DEFAULT
|
|
|
|
&& cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-24 20:37:04 +04:00
|
|
|
if (cf->cf_loc[PCMCIABUSCF_CONTROLLER] == PCMCIABUSCF_CONTROLLER_DEFAULT) {
|
2002-09-27 07:17:40 +04:00
|
|
|
return (config_match(parent, cf, aux));
|
2001-03-27 14:34:05 +04:00
|
|
|
}
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
return 0;
|
1999-10-15 10:07:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2006-11-16 04:32:37 +03:00
|
|
|
cardslot_16_print(void *arg, const char *pnp)
|
1999-10-15 10:07:17 +04:00
|
|
|
{
|
1999-10-29 11:27:43 +04:00
|
|
|
|
2007-02-05 02:39:02 +03:00
|
|
|
if (pnp != NULL) {
|
2003-01-01 03:10:15 +03:00
|
|
|
aprint_normal("pcmciabus at %s", pnp);
|
2001-03-27 14:34:05 +04:00
|
|
|
}
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
return UNCONF;
|
1999-10-15 10:07:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* void cardslot_event_throw(struct cardslot_softc *sc, int ev)
|
|
|
|
*
|
|
|
|
* This function throws an event to the event handler. If the state
|
|
|
|
* of a slot is changed, it should be noticed using this function.
|
|
|
|
*/
|
|
|
|
void
|
2007-02-05 02:39:02 +03:00
|
|
|
cardslot_event_throw(struct cardslot_softc *sc, int ev)
|
1999-10-15 10:07:17 +04:00
|
|
|
{
|
2001-03-27 14:34:05 +04:00
|
|
|
struct cardslot_event *ce;
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
DPRINTF(("cardslot_event_throw: an event %s comes\n",
|
|
|
|
ev == CARDSLOT_EVENT_INSERTION_CB ? "CardBus Card inserted" :
|
|
|
|
ev == CARDSLOT_EVENT_INSERTION_16 ? "16-bit Card inserted" :
|
|
|
|
ev == CARDSLOT_EVENT_REMOVAL_CB ? "CardBus Card removed" :
|
|
|
|
ev == CARDSLOT_EVENT_REMOVAL_16 ? "16-bit Card removed" : "???"));
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
if (NULL == (ce = (struct cardslot_event *)malloc(sizeof (struct cardslot_event), M_TEMP, M_NOWAIT))) {
|
|
|
|
panic("cardslot_enevt");
|
|
|
|
}
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
ce->ce_type = ev;
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
{
|
|
|
|
int s = spltty();
|
|
|
|
SIMPLEQ_INSERT_TAIL(&sc->sc_events, ce, ce_q);
|
|
|
|
splx(s);
|
|
|
|
}
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
wakeup(&sc->sc_events);
|
1999-10-15 10:07:17 +04:00
|
|
|
|
2001-03-27 14:34:05 +04:00
|
|
|
return;
|
1999-10-15 10:07:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* static void cardslot_event_thread(void *arg)
|
|
|
|
*
|
|
|
|
* This function is the main routine handing cardslot events such as
|
|
|
|
* insertions and removals.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
cardslot_event_thread(void *arg)
|
1999-10-15 10:07:17 +04:00
|
|
|
{
|
2001-03-27 14:34:05 +04:00
|
|
|
struct cardslot_softc *sc = arg;
|
|
|
|
struct cardslot_event *ce;
|
|
|
|
int s, first = 1;
|
|
|
|
static int antonym_ev[4] = {
|
|
|
|
CARDSLOT_EVENT_REMOVAL_16, CARDSLOT_EVENT_INSERTION_16,
|
|
|
|
CARDSLOT_EVENT_REMOVAL_CB, CARDSLOT_EVENT_INSERTION_CB
|
|
|
|
};
|
|
|
|
|
|
|
|
while (sc->sc_th_enable) {
|
|
|
|
s = spltty();
|
|
|
|
if ((ce = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) {
|
|
|
|
splx(s);
|
|
|
|
if (first) {
|
|
|
|
first = 0;
|
2013-10-12 20:49:00 +04:00
|
|
|
config_pending_decr(sc->sc_dev);
|
2001-03-27 14:34:05 +04:00
|
|
|
}
|
|
|
|
(void) tsleep(&sc->sc_events, PWAIT, "cardslotev", 0);
|
|
|
|
continue;
|
|
|
|
}
|
2002-06-02 03:50:52 +04:00
|
|
|
SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q);
|
2001-03-27 14:34:05 +04:00
|
|
|
splx(s);
|
|
|
|
|
|
|
|
if (IS_CARDSLOT_INSERT_REMOVE_EV(ce->ce_type)) {
|
2003-11-02 12:52:33 +03:00
|
|
|
/* Chattering suppression */
|
2001-03-27 14:34:05 +04:00
|
|
|
s = spltty();
|
|
|
|
while (1) {
|
|
|
|
struct cardslot_event *ce1, *ce2;
|
|
|
|
|
|
|
|
if ((ce1 = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ce1->ce_type != antonym_ev[ce->ce_type]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((ce2 = SIMPLEQ_NEXT(ce1, ce_q)) == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ce2->ce_type == ce->ce_type) {
|
2002-06-02 03:50:52 +04:00
|
|
|
SIMPLEQ_REMOVE_HEAD(&sc->sc_events,
|
|
|
|
ce_q);
|
2001-03-27 14:34:05 +04:00
|
|
|
free(ce1, M_TEMP);
|
2002-06-02 03:50:52 +04:00
|
|
|
SIMPLEQ_REMOVE_HEAD(&sc->sc_events,
|
|
|
|
ce_q);
|
2001-03-27 14:34:05 +04:00
|
|
|
free(ce2, M_TEMP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (ce->ce_type) {
|
|
|
|
case CARDSLOT_EVENT_INSERTION_CB:
|
|
|
|
if ((CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB)
|
|
|
|
|| (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_16)) {
|
|
|
|
if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) {
|
|
|
|
/*
|
|
|
|
* A card has already been
|
|
|
|
* inserted and works.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->sc_cb_softc) {
|
|
|
|
CARDSLOT_SET_CARDTYPE(sc->sc_status,
|
|
|
|
CARDSLOT_STATUS_CARD_CB);
|
|
|
|
if (cardbus_attach_card(sc->sc_cb_softc) > 0) {
|
|
|
|
/* at least one function works */
|
|
|
|
CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_WORKING);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* no functions work or this
|
|
|
|
* card is not known
|
|
|
|
*/
|
|
|
|
CARDSLOT_SET_WORK(sc->sc_status,
|
|
|
|
CARDSLOT_STATUS_NOTWORK);
|
|
|
|
}
|
|
|
|
} else {
|
2008-06-25 15:42:32 +04:00
|
|
|
panic("no cardbus on %s",
|
|
|
|
device_xname(sc->sc_dev));
|
2001-03-27 14:34:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CARDSLOT_EVENT_INSERTION_16:
|
|
|
|
if ((CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB)
|
|
|
|
|| (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_16)) {
|
|
|
|
if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) {
|
|
|
|
/*
|
|
|
|
* A card has already been
|
|
|
|
* inserted and work.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sc->sc_16_softc) {
|
|
|
|
CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_16);
|
2010-03-19 04:44:05 +03:00
|
|
|
if (pcmcia_card_attach(sc->sc_16_softc)) {
|
2001-03-27 14:34:05 +04:00
|
|
|
/* Do not attach */
|
|
|
|
CARDSLOT_SET_WORK(sc->sc_status,
|
|
|
|
CARDSLOT_STATUS_NOTWORK);
|
|
|
|
} else {
|
|
|
|
/* working */
|
|
|
|
CARDSLOT_SET_WORK(sc->sc_status,
|
|
|
|
CARDSLOT_STATUS_WORKING);
|
|
|
|
}
|
|
|
|
} else {
|
2008-06-25 15:42:32 +04:00
|
|
|
panic("no 16-bit pcmcia on %s",
|
|
|
|
device_xname(sc->sc_dev));
|
2001-03-27 14:34:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CARDSLOT_EVENT_REMOVAL_CB:
|
|
|
|
if (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB) {
|
|
|
|
/* CardBus card has not been inserted. */
|
|
|
|
if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) {
|
|
|
|
cardbus_detach_card(sc->sc_cb_softc);
|
|
|
|
CARDSLOT_SET_WORK(sc->sc_status,
|
|
|
|
CARDSLOT_STATUS_NOTWORK);
|
|
|
|
CARDSLOT_SET_WORK(sc->sc_status,
|
|
|
|
CARDSLOT_STATUS_CARD_NONE);
|
|
|
|
}
|
|
|
|
CARDSLOT_SET_CARDTYPE(sc->sc_status,
|
|
|
|
CARDSLOT_STATUS_CARD_NONE);
|
|
|
|
} else if (CARDSLOT_CARDTYPE(sc->sc_status) != CARDSLOT_STATUS_CARD_16) {
|
|
|
|
/* Unknown card... */
|
|
|
|
CARDSLOT_SET_CARDTYPE(sc->sc_status,
|
|
|
|
CARDSLOT_STATUS_CARD_NONE);
|
|
|
|
}
|
|
|
|
CARDSLOT_SET_WORK(sc->sc_status,
|
|
|
|
CARDSLOT_STATUS_NOTWORK);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CARDSLOT_EVENT_REMOVAL_16:
|
2008-06-29 13:09:09 +04:00
|
|
|
DPRINTF(("%s: removal event\n", device_xname(sc->sc_dev)));
|
2001-03-27 14:34:05 +04:00
|
|
|
if (CARDSLOT_CARDTYPE(sc->sc_status) != CARDSLOT_STATUS_CARD_16) {
|
|
|
|
/* 16-bit card has not been inserted. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((sc->sc_16_softc != NULL)
|
|
|
|
&& (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING)) {
|
2008-07-03 22:57:52 +04:00
|
|
|
struct pcmcia_softc *psc =
|
|
|
|
device_private(sc->sc_16_softc);
|
2001-03-27 14:34:05 +04:00
|
|
|
|
2008-07-03 22:57:52 +04:00
|
|
|
pcmcia_card_deactivate(sc->sc_16_softc);
|
2001-03-27 14:34:05 +04:00
|
|
|
pcmcia_chip_socket_disable(psc->pct, psc->pch);
|
2008-07-03 22:57:52 +04:00
|
|
|
pcmcia_card_detach(sc->sc_16_softc,
|
|
|
|
DETACH_FORCE);
|
2001-03-27 14:34:05 +04:00
|
|
|
}
|
|
|
|
CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_NONE);
|
|
|
|
CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_NOTWORK);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
panic("cardslot_event_thread: unknown event %d", ce->ce_type);
|
|
|
|
}
|
|
|
|
free(ce, M_TEMP);
|
1999-10-15 10:07:17 +04:00
|
|
|
}
|
2001-03-27 14:34:05 +04:00
|
|
|
|
|
|
|
sc->sc_event_thread = NULL;
|
|
|
|
|
|
|
|
/* In case the parent device is waiting for us to exit. */
|
|
|
|
wakeup(sc);
|
|
|
|
|
|
|
|
kthread_exit(0);
|
1999-10-15 10:07:17 +04:00
|
|
|
}
|