1 /* $NetBSD: cardslot.c,v 1.50 2009/05/21 17:32:32 dyoung Exp $ */
4 * Copyright (c) 1999 and 2000
5 * HAYAKAWA Koichi. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: cardslot.c,v 1.50 2009/05/21 17:32:32 dyoung Exp $");
32 #include "opt_cardslot.h"
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37 #include <sys/malloc.h>
38 #include <sys/kernel.h>
39 #include <sys/syslog.h>
40 #include <sys/kthread.h>
44 #include <dev/cardbus/cardslotvar.h>
45 #include <dev/cardbus/cardbusvar.h>
46 #include <dev/pcmcia/pcmciavar.h>
47 #include <dev/pcmcia/pcmciachip.h>
51 #if defined CARDSLOT_DEBUG
53 #define DPRINTF(a) printf a
61 STATIC
void cardslotchilddet(device_t
, device_t
);
62 STATIC
void cardslotattach(device_t
, device_t
, void *);
63 STATIC
int cardslotdetach(device_t
, int);
65 STATIC
int cardslotmatch(device_t
, cfdata_t
, void *);
66 static void cardslot_event_thread(void *arg
);
68 STATIC
int cardslot_cb_print(void *aux
, const char *pcic
);
69 static int cardslot_16_print(void *, const char *);
70 static int cardslot_16_submatch(device_t
, cfdata_t
,
73 CFATTACH_DECL3_NEW(cardslot
, sizeof(struct cardslot_softc
),
74 cardslotmatch
, cardslotattach
, cardslotdetach
, NULL
, NULL
, cardslotchilddet
,
78 cardslotmatch(device_t parent
, cfdata_t cf
,
81 struct cardslot_attach_args
*caa
= aux
;
83 if (caa
->caa_cb_attach
== NULL
&& caa
->caa_16_attach
== NULL
) {
84 /* Neither CardBus nor 16-bit PCMCIA are defined. */
92 cardslotchilddet(device_t self
, device_t child
)
94 struct cardslot_softc
*sc
= device_private(self
);
96 KASSERT(sc
->sc_cb_softc
== device_private(child
) ||
97 sc
->sc_16_softc
== child
);
99 if (sc
->sc_cb_softc
== device_private(child
))
100 sc
->sc_cb_softc
= NULL
;
101 else if (sc
->sc_16_softc
== child
)
102 sc
->sc_16_softc
= NULL
;
106 cardslotattach(device_t parent
, device_t self
,
109 struct cardslot_softc
*sc
= device_private(self
);
110 struct cardslot_attach_args
*caa
= aux
;
112 struct cbslot_attach_args
*cba
= caa
->caa_cb_attach
;
113 struct pcmciabus_attach_args
*pa
= caa
->caa_16_attach
;
115 struct cardbus_softc
*csc
= NULL
;
116 struct pcmcia_softc
*psc
= NULL
;
120 sc
->sc_cb_softc
= NULL
;
121 sc
->sc_16_softc
= NULL
;
122 SIMPLEQ_INIT(&sc
->sc_events
);
123 sc
->sc_th_enable
= 0;
128 DPRINTF(("%s attaching CardBus bus...\n", device_xname(self
)));
130 csc
= device_private(config_found_ia(self
, "cbbus", cba
,
134 DPRINTF(("%s: found cardbus on %s\n", __func__
,
135 device_xname(self
)));
136 sc
->sc_cb_softc
= csc
;
141 sc
->sc_16_softc
= config_found_sm_loc(self
, "pcmciabus", NULL
,
142 pa
, cardslot_16_print
,
143 cardslot_16_submatch
);
144 if (sc
->sc_16_softc
) {
145 /* pcmcia 16-bit bus found */
146 DPRINTF(("%s: found 16-bit pcmcia bus\n", __func__
));
147 psc
= device_private(sc
->sc_16_softc
);
151 if (csc
!= NULL
|| psc
!= NULL
) {
152 config_pending_incr();
153 if (kthread_create(PRI_NONE
, 0, NULL
, cardslot_event_thread
,
154 sc
, &sc
->sc_event_thread
, "%s", device_xname(self
))) {
155 aprint_error_dev(sc
->sc_dev
,
156 "unable to create thread\n");
157 panic("cardslotattach");
159 sc
->sc_th_enable
= 1;
162 if (csc
&& (csc
->sc_cf
->cardbus_ctrl
)(csc
->sc_cc
, CARDBUS_CD
)) {
163 DPRINTF(("%s: CardBus card found\n", __func__
));
164 /* attach deferred */
165 cardslot_event_throw(sc
, CARDSLOT_EVENT_INSERTION_CB
);
168 if (psc
&& (psc
->pct
->card_detect
)(psc
->pch
)) {
169 DPRINTF(("%s: 16-bit card found\n", __func__
));
170 /* attach deferred */
171 cardslot_event_throw(sc
, CARDSLOT_EVENT_INSERTION_16
);
174 if (!pmf_device_register(self
, NULL
, NULL
))
175 aprint_error_dev(self
, "couldn't establish power handler\n");
179 cardslotdetach(device_t self
, int flags
)
182 struct cardslot_softc
*sc
= device_private(self
);
184 if ((rc
= config_detach_children(self
, flags
)) != 0)
187 sc
->sc_th_enable
= 0;
188 wakeup(&sc
->sc_events
);
189 while (sc
->sc_event_thread
!= NULL
)
190 (void)tsleep(sc
, PWAIT
, "cardslotthd", 0);
192 if (!SIMPLEQ_EMPTY(&sc
->sc_events
))
193 aprint_error_dev(self
, "events outstanding");
195 pmf_device_deregister(self
);
200 cardslot_cb_print(void *aux
, const char *pnp
)
202 struct cbslot_attach_args
*cba
= aux
;
205 aprint_normal("cardbus at %s subordinate bus %d",
214 cardslot_16_submatch(device_t parent
, cfdata_t cf
,
215 const int *ldesc
, void *aux
)
218 if (cf
->cf_loc
[PCMCIABUSCF_CONTROLLER
] != PCMCIABUSCF_CONTROLLER_DEFAULT
219 && cf
->cf_loc
[PCMCIABUSCF_CONTROLLER
] != 0) {
223 if ((cf
->cf_loc
[PCMCIABUSCF_CONTROLLER
] == PCMCIABUSCF_CONTROLLER_DEFAULT
)) {
224 return (config_match(parent
, cf
, aux
));
233 cardslot_16_print(void *arg
, const char *pnp
)
237 aprint_normal("pcmciabus at %s", pnp
);
245 * void cardslot_event_throw(struct cardslot_softc *sc, int ev)
247 * This function throws an event to the event handler. If the state
248 * of a slot is changed, it should be noticed using this function.
251 cardslot_event_throw(struct cardslot_softc
*sc
, int ev
)
253 struct cardslot_event
*ce
;
255 DPRINTF(("cardslot_event_throw: an event %s comes\n",
256 ev
== CARDSLOT_EVENT_INSERTION_CB
? "CardBus Card inserted" :
257 ev
== CARDSLOT_EVENT_INSERTION_16
? "16-bit Card inserted" :
258 ev
== CARDSLOT_EVENT_REMOVAL_CB
? "CardBus Card removed" :
259 ev
== CARDSLOT_EVENT_REMOVAL_16
? "16-bit Card removed" : "???"));
261 if (NULL
== (ce
= (struct cardslot_event
*)malloc(sizeof (struct cardslot_event
), M_TEMP
, M_NOWAIT
))) {
262 panic("cardslot_enevt");
269 SIMPLEQ_INSERT_TAIL(&sc
->sc_events
, ce
, ce_q
);
273 wakeup(&sc
->sc_events
);
280 * static void cardslot_event_thread(void *arg)
282 * This function is the main routine handing cardslot events such as
283 * insertions and removals.
287 cardslot_event_thread(void *arg
)
289 struct cardslot_softc
*sc
= arg
;
290 struct cardslot_event
*ce
;
292 static int antonym_ev
[4] = {
293 CARDSLOT_EVENT_REMOVAL_16
, CARDSLOT_EVENT_INSERTION_16
,
294 CARDSLOT_EVENT_REMOVAL_CB
, CARDSLOT_EVENT_INSERTION_CB
297 while (sc
->sc_th_enable
) {
299 if ((ce
= SIMPLEQ_FIRST(&sc
->sc_events
)) == NULL
) {
303 config_pending_decr();
305 (void) tsleep(&sc
->sc_events
, PWAIT
, "cardslotev", 0);
308 SIMPLEQ_REMOVE_HEAD(&sc
->sc_events
, ce_q
);
311 if (IS_CARDSLOT_INSERT_REMOVE_EV(ce
->ce_type
)) {
312 /* Chattering suppression */
315 struct cardslot_event
*ce1
, *ce2
;
317 if ((ce1
= SIMPLEQ_FIRST(&sc
->sc_events
)) == NULL
) {
320 if (ce1
->ce_type
!= antonym_ev
[ce
->ce_type
]) {
323 if ((ce2
= SIMPLEQ_NEXT(ce1
, ce_q
)) == NULL
) {
326 if (ce2
->ce_type
== ce
->ce_type
) {
327 SIMPLEQ_REMOVE_HEAD(&sc
->sc_events
,
330 SIMPLEQ_REMOVE_HEAD(&sc
->sc_events
,
338 switch (ce
->ce_type
) {
339 case CARDSLOT_EVENT_INSERTION_CB
:
340 if ((CARDSLOT_CARDTYPE(sc
->sc_status
) == CARDSLOT_STATUS_CARD_CB
)
341 || (CARDSLOT_CARDTYPE(sc
->sc_status
) == CARDSLOT_STATUS_CARD_16
)) {
342 if (CARDSLOT_WORK(sc
->sc_status
) == CARDSLOT_STATUS_WORKING
) {
344 * A card has already been
345 * inserted and works.
351 if (sc
->sc_cb_softc
) {
352 CARDSLOT_SET_CARDTYPE(sc
->sc_status
,
353 CARDSLOT_STATUS_CARD_CB
);
354 if (cardbus_attach_card(sc
->sc_cb_softc
) > 0) {
355 /* at least one function works */
356 CARDSLOT_SET_WORK(sc
->sc_status
, CARDSLOT_STATUS_WORKING
);
359 * no functions work or this
362 CARDSLOT_SET_WORK(sc
->sc_status
,
363 CARDSLOT_STATUS_NOTWORK
);
366 panic("no cardbus on %s",
367 device_xname(sc
->sc_dev
));
372 case CARDSLOT_EVENT_INSERTION_16
:
373 if ((CARDSLOT_CARDTYPE(sc
->sc_status
) == CARDSLOT_STATUS_CARD_CB
)
374 || (CARDSLOT_CARDTYPE(sc
->sc_status
) == CARDSLOT_STATUS_CARD_16
)) {
375 if (CARDSLOT_WORK(sc
->sc_status
) == CARDSLOT_STATUS_WORKING
) {
377 * A card has already been
383 if (sc
->sc_16_softc
) {
384 CARDSLOT_SET_CARDTYPE(sc
->sc_status
, CARDSLOT_STATUS_CARD_16
);
385 if (pcmcia_card_attach((device_t
)sc
->sc_16_softc
)) {
387 CARDSLOT_SET_WORK(sc
->sc_status
,
388 CARDSLOT_STATUS_NOTWORK
);
391 CARDSLOT_SET_WORK(sc
->sc_status
,
392 CARDSLOT_STATUS_WORKING
);
395 panic("no 16-bit pcmcia on %s",
396 device_xname(sc
->sc_dev
));
401 case CARDSLOT_EVENT_REMOVAL_CB
:
402 if (CARDSLOT_CARDTYPE(sc
->sc_status
) == CARDSLOT_STATUS_CARD_CB
) {
403 /* CardBus card has not been inserted. */
404 if (CARDSLOT_WORK(sc
->sc_status
) == CARDSLOT_STATUS_WORKING
) {
405 cardbus_detach_card(sc
->sc_cb_softc
);
406 CARDSLOT_SET_WORK(sc
->sc_status
,
407 CARDSLOT_STATUS_NOTWORK
);
408 CARDSLOT_SET_WORK(sc
->sc_status
,
409 CARDSLOT_STATUS_CARD_NONE
);
411 CARDSLOT_SET_CARDTYPE(sc
->sc_status
,
412 CARDSLOT_STATUS_CARD_NONE
);
413 } else if (CARDSLOT_CARDTYPE(sc
->sc_status
) != CARDSLOT_STATUS_CARD_16
) {
414 /* Unknown card... */
415 CARDSLOT_SET_CARDTYPE(sc
->sc_status
,
416 CARDSLOT_STATUS_CARD_NONE
);
418 CARDSLOT_SET_WORK(sc
->sc_status
,
419 CARDSLOT_STATUS_NOTWORK
);
422 case CARDSLOT_EVENT_REMOVAL_16
:
423 DPRINTF(("%s: removal event\n", device_xname(sc
->sc_dev
)));
424 if (CARDSLOT_CARDTYPE(sc
->sc_status
) != CARDSLOT_STATUS_CARD_16
) {
425 /* 16-bit card has not been inserted. */
428 if ((sc
->sc_16_softc
!= NULL
)
429 && (CARDSLOT_WORK(sc
->sc_status
) == CARDSLOT_STATUS_WORKING
)) {
430 struct pcmcia_softc
*psc
=
431 device_private(sc
->sc_16_softc
);
433 pcmcia_card_deactivate(sc
->sc_16_softc
);
434 pcmcia_chip_socket_disable(psc
->pct
, psc
->pch
);
435 pcmcia_card_detach(sc
->sc_16_softc
,
438 CARDSLOT_SET_CARDTYPE(sc
->sc_status
, CARDSLOT_STATUS_CARD_NONE
);
439 CARDSLOT_SET_WORK(sc
->sc_status
, CARDSLOT_STATUS_NOTWORK
);
443 panic("cardslot_event_thread: unknown event %d", ce
->ce_type
);
448 sc
->sc_event_thread
= NULL
;
450 /* In case the parent device is waiting for us to exit. */