Line data Source code
1 : /* $OpenBSD: cardslot.c,v 1.21 2016/09/15 02:00:17 dlg Exp $ */
2 : /* $NetBSD: cardslot.c,v 1.9 2000/03/22 09:35:06 haya Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1999 and 2000
6 : * HAYAKAWA Koichi. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : *
18 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 : * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 : * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 : * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 : * POSSIBILITY OF SUCH DAMAGE.
29 : */
30 :
31 : #include <sys/param.h>
32 : #include <sys/systm.h>
33 : #include <sys/device.h>
34 : #include <sys/malloc.h>
35 : #include <sys/kernel.h>
36 : #include <sys/syslog.h>
37 : #include <sys/kthread.h>
38 : #include <sys/pool.h>
39 : #include <sys/task.h>
40 :
41 : #include <dev/cardbus/cardslotvar.h>
42 : #include <dev/cardbus/cardbusvar.h>
43 : #include <dev/pcmcia/pcmciavar.h>
44 : #include <dev/pcmcia/pcmciachip.h>
45 : #include <dev/ic/i82365var.h>
46 :
47 : #if defined CARDSLOT_DEBUG
48 : #define STATIC
49 : #define DPRINTF(a) printf a
50 : #else
51 : #ifdef DDB
52 : #define STATIC
53 : #else
54 : #define STATIC static
55 : #endif
56 : #define DPRINTF(a)
57 : #endif
58 :
59 : STATIC void cardslotattach(struct device *, struct device *, void *);
60 :
61 : STATIC int cardslotmatch(struct device *, void *, void *);
62 : STATIC void cardslot_event(void *arg);
63 : STATIC void cardslot_process_event(struct cardslot_softc *);
64 :
65 : STATIC int cardslot_cb_print(void *aux, const char *pcic);
66 : STATIC int cardslot_16_print(void *, const char *);
67 : STATIC int cardslot_16_submatch(struct device *, void *,void *);
68 :
69 : struct cfattach cardslot_ca = {
70 : sizeof(struct cardslot_softc), cardslotmatch, cardslotattach
71 : };
72 :
73 : struct cfdriver cardslot_cd = {
74 : NULL, "cardslot", DV_DULL
75 : };
76 :
77 : struct pool cardsloteventpool;
78 :
79 : STATIC int
80 0 : cardslotmatch(struct device *parent, void *match, void *aux)
81 : {
82 0 : struct cardslot_attach_args *caa = aux;
83 :
84 0 : if (caa->caa_cb_attach == NULL && caa->caa_16_attach == NULL) {
85 : /* Neither CardBus nor 16-bit PCMCIA are defined. */
86 0 : return (0);
87 : }
88 :
89 0 : return (1);
90 0 : }
91 :
92 : STATIC void
93 0 : cardslotattach(struct device *parent, struct device *self, void *aux)
94 : {
95 0 : struct cardslot_softc *sc = (struct cardslot_softc *)self;
96 0 : struct cardslot_attach_args *caa = aux;
97 :
98 0 : struct cbslot_attach_args *cba = caa->caa_cb_attach;
99 0 : struct pcmciabus_attach_args *pa = caa->caa_16_attach;
100 :
101 : struct cardbus_softc *csc = NULL;
102 : struct pcmcia_softc *psc = NULL;
103 :
104 0 : if (cardsloteventpool.pr_size == 0) {
105 0 : pool_init(&cardsloteventpool, sizeof(struct cardslot_event),
106 : 0, IPL_BIO, 0, "cardslot", NULL);
107 0 : }
108 :
109 0 : sc->sc_slot = sc->sc_dev.dv_unit;
110 0 : sc->sc_cb_softc = NULL;
111 0 : sc->sc_16_softc = NULL;
112 0 : SIMPLEQ_INIT(&sc->sc_events);
113 0 : task_set(&sc->sc_event_task, cardslot_event, sc);
114 :
115 0 : printf(" slot %d flags %x\n", sc->sc_slot,
116 0 : sc->sc_dev.dv_cfdata->cf_flags);
117 :
118 : DPRINTF(("%s attaching CardBus bus...\n", sc->sc_dev.dv_xname));
119 0 : if (cba != NULL) {
120 0 : if ((csc = (void *)config_found(self, cba,
121 0 : cardslot_cb_print)) != NULL) {
122 : /* cardbus found */
123 : DPRINTF(("cardslotattach: found cardbus on %s\n",
124 : sc->sc_dev.dv_xname));
125 0 : sc->sc_cb_softc = csc;
126 0 : }
127 : }
128 :
129 0 : if (pa != NULL) {
130 0 : if ((psc = (void *)config_found_sm(self, pa, cardslot_16_print,
131 0 : cardslot_16_submatch)) != NULL) {
132 : /* pcmcia 16-bit bus found */
133 : DPRINTF(("cardslotattach: found 16-bit pcmcia bus\n"));
134 0 : sc->sc_16_softc = psc;
135 : /* XXX: dirty. This code should be removed
136 : * to achieve MI
137 : */
138 0 : caa->caa_ph->pcmcia = (struct device *)psc;
139 0 : }
140 : }
141 :
142 0 : if (csc && (csc->sc_cf->cardbus_ctrl)(csc->sc_cc, CARDBUS_CD)) {
143 : DPRINTF(("cardslotattach: CardBus card found\n"));
144 : /* attach deferred */
145 0 : cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_CB);
146 0 : }
147 :
148 0 : if (psc && (psc->pct->card_detect)(psc->pch)) {
149 : DPRINTF(("cardbusattach: 16-bit card found\n"));
150 : /* attach deferred */
151 0 : cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_16);
152 0 : }
153 0 : }
154 :
155 : STATIC int
156 0 : cardslot_cb_print(void *aux, const char *pnp)
157 : {
158 0 : struct cbslot_attach_args *cba = aux;
159 :
160 0 : if (pnp)
161 0 : printf("cardbus at %s subordinate bus %d", pnp, cba->cba_bus);
162 :
163 0 : return (UNCONF);
164 : }
165 :
166 : STATIC int
167 0 : cardslot_16_submatch(struct device *parent, void *match, void *aux)
168 : {
169 0 : struct cfdata *cf = match;
170 :
171 0 : if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != 0)
172 0 : return (0);
173 :
174 0 : if (cf->cf_loc[0] == -1)
175 0 : return ((*cf->cf_attach->ca_match)(parent, cf, aux));
176 :
177 0 : return (0);
178 0 : }
179 :
180 : STATIC int
181 0 : cardslot_16_print(void *arg, const char *pnp)
182 : {
183 0 : if (pnp)
184 0 : printf("pcmciabus at %s", pnp);
185 :
186 0 : return (UNCONF);
187 : }
188 :
189 : /*
190 : * void cardslot_event_throw(struct cardslot_softc *sc, int ev)
191 : *
192 : * This function throws an event to the event handler. If the state
193 : * of a slot is changed, it should be noticed using this function.
194 : */
195 : void
196 0 : cardslot_event_throw(struct cardslot_softc *sc, int ev)
197 : {
198 : struct cardslot_event *ce;
199 : int s;
200 :
201 : DPRINTF(("cardslot_event_throw: an event %s comes\n",
202 : ev == CARDSLOT_EVENT_INSERTION_CB ? "CardBus Card inserted" :
203 : ev == CARDSLOT_EVENT_INSERTION_16 ? "16-bit Card inserted" :
204 : ev == CARDSLOT_EVENT_REMOVAL_CB ? "CardBus Card removed" :
205 : ev == CARDSLOT_EVENT_REMOVAL_16 ? "16-bit Card removed" : "???"));
206 :
207 0 : ce = pool_get(&cardsloteventpool, PR_NOWAIT);
208 0 : if (ce == NULL)
209 0 : return;
210 0 : ce->ce_type = ev;
211 :
212 0 : s = spltty();
213 0 : SIMPLEQ_INSERT_TAIL(&sc->sc_events, ce, ce_q);
214 0 : splx(s);
215 :
216 0 : task_add(systq, &sc->sc_event_task);
217 0 : }
218 :
219 : /*
220 : * STATIC void cardslot_event(void *arg)
221 : *
222 : * This function is the main routine handing cardslot events such as
223 : * insertions and removals.
224 : *
225 : */
226 : STATIC void
227 0 : cardslot_event(void *arg1)
228 : {
229 0 : struct cardslot_softc *sc = arg1;
230 :
231 0 : while (!SIMPLEQ_EMPTY(&sc->sc_events))
232 0 : cardslot_process_event(sc);
233 0 : }
234 :
235 :
236 : STATIC void
237 0 : cardslot_process_event(struct cardslot_softc *sc)
238 : {
239 : struct cardslot_event *ce;
240 : int s, ev;
241 :
242 0 : s = spltty();
243 0 : if ((ce = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) {
244 0 : splx(s);
245 0 : return;
246 : }
247 0 : SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q);
248 :
249 0 : if (IS_CARDSLOT_INSERT_REMOVE_EV(ce->ce_type)) {
250 : /* Chattering suppression */
251 : static int antonym_ev[4] = {
252 : CARDSLOT_EVENT_REMOVAL_16,
253 : CARDSLOT_EVENT_INSERTION_16,
254 : CARDSLOT_EVENT_REMOVAL_CB,
255 : CARDSLOT_EVENT_INSERTION_CB
256 : };
257 :
258 0 : while (1) {
259 : struct cardslot_event *ce1, *ce2;
260 :
261 0 : if ((ce1 = SIMPLEQ_FIRST(&sc->sc_events)) ==
262 : NULL)
263 0 : break;
264 0 : if (ce1->ce_type != antonym_ev[ce->ce_type])
265 0 : break;
266 0 : if ((ce2 = SIMPLEQ_NEXT(ce1, ce_q)) == NULL)
267 0 : break;
268 0 : if (ce2->ce_type == ce->ce_type) {
269 0 : SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q);
270 0 : pool_put(&cardsloteventpool, ce1);
271 0 : SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q);
272 0 : pool_put(&cardsloteventpool, ce2);
273 0 : }
274 0 : }
275 : }
276 0 : splx(s);
277 :
278 0 : ev = ce->ce_type;
279 0 : pool_put(&cardsloteventpool, ce);
280 :
281 0 : switch (ev) {
282 : case CARDSLOT_EVENT_INSERTION_CB:
283 0 : if ((CARDSLOT_CARDTYPE(sc->sc_status) ==
284 0 : CARDSLOT_STATUS_CARD_CB) ||
285 0 : (CARDSLOT_CARDTYPE(sc->sc_status) ==
286 : CARDSLOT_STATUS_CARD_16)) {
287 0 : if (CARDSLOT_WORK(sc->sc_status) ==
288 : CARDSLOT_STATUS_WORKING) {
289 : /* A card has already been inserted
290 : * and works.
291 : */
292 : break;
293 : }
294 : }
295 :
296 0 : if (sc->sc_cb_softc) {
297 0 : CARDSLOT_SET_CARDTYPE(sc->sc_status,
298 : CARDSLOT_STATUS_CARD_CB);
299 0 : if (cardbus_attach_card(sc->sc_cb_softc) > 0) {
300 : /* At least one function works */
301 0 : CARDSLOT_SET_WORK(sc->sc_status,
302 : CARDSLOT_STATUS_WORKING);
303 0 : } else {
304 : /* No functions work or this card is
305 : * not known
306 : */
307 0 : CARDSLOT_SET_WORK(sc->sc_status,
308 : CARDSLOT_STATUS_NOTWORK);
309 : }
310 : } else {
311 0 : printf("%s: CardBus support disabled\n",
312 0 : sc->sc_dev.dv_xname);
313 : }
314 : break;
315 :
316 : case CARDSLOT_EVENT_INSERTION_16:
317 0 : if ((CARDSLOT_CARDTYPE(sc->sc_status) ==
318 0 : CARDSLOT_STATUS_CARD_CB) ||
319 0 : (CARDSLOT_CARDTYPE(sc->sc_status) ==
320 : CARDSLOT_STATUS_CARD_16)) {
321 0 : if (CARDSLOT_WORK(sc->sc_status) ==
322 : CARDSLOT_STATUS_WORKING) {
323 : /* A card has already been inserted
324 : * and works.
325 : */
326 : break;
327 : }
328 : }
329 0 : if (sc->sc_16_softc) {
330 0 : CARDSLOT_SET_CARDTYPE(sc->sc_status,
331 : CARDSLOT_STATUS_CARD_16);
332 0 : if (pcmcia_card_attach(
333 0 : (struct device *)sc->sc_16_softc)) {
334 : /* Do not attach */
335 0 : CARDSLOT_SET_WORK(sc->sc_status,
336 : CARDSLOT_STATUS_NOTWORK);
337 0 : } else {
338 : /* working */
339 0 : CARDSLOT_SET_WORK(sc->sc_status,
340 : CARDSLOT_STATUS_WORKING);
341 : }
342 : } else {
343 0 : panic("no 16-bit pcmcia on %s",
344 0 : sc->sc_dev.dv_xname);
345 : }
346 : break;
347 :
348 : case CARDSLOT_EVENT_REMOVAL_CB:
349 0 : if (CARDSLOT_CARDTYPE(sc->sc_status) ==
350 : CARDSLOT_STATUS_CARD_CB) {
351 : /* CardBus card has not been inserted. */
352 0 : if (CARDSLOT_WORK(sc->sc_status) ==
353 : CARDSLOT_STATUS_WORKING) {
354 0 : cardbus_detach_card(sc->sc_cb_softc);
355 0 : CARDSLOT_SET_WORK(sc->sc_status,
356 : CARDSLOT_STATUS_NOTWORK);
357 0 : CARDSLOT_SET_WORK(sc->sc_status,
358 : CARDSLOT_STATUS_CARD_NONE);
359 0 : }
360 0 : CARDSLOT_SET_CARDTYPE(sc->sc_status,
361 : CARDSLOT_STATUS_CARD_NONE);
362 0 : } else if (CARDSLOT_CARDTYPE(sc->sc_status) !=
363 : CARDSLOT_STATUS_CARD_16) {
364 : /* Unknown card... */
365 0 : CARDSLOT_SET_CARDTYPE(sc->sc_status,
366 : CARDSLOT_STATUS_CARD_NONE);
367 0 : }
368 0 : CARDSLOT_SET_WORK(sc->sc_status,
369 : CARDSLOT_STATUS_NOTWORK);
370 0 : break;
371 :
372 : case CARDSLOT_EVENT_REMOVAL_16:
373 : DPRINTF(("%s: removal event\n", sc->sc_dev.dv_xname));
374 0 : if (CARDSLOT_CARDTYPE(sc->sc_status) !=
375 : CARDSLOT_STATUS_CARD_16) {
376 : /* 16-bit card has not been inserted. */
377 : break;
378 : }
379 0 : if ((sc->sc_16_softc != NULL) &&
380 0 : (CARDSLOT_WORK(sc->sc_status) ==
381 : CARDSLOT_STATUS_WORKING)) {
382 : struct pcmcia_softc *psc = sc->sc_16_softc;
383 :
384 0 : pcmcia_card_deactivate((struct device *)psc);
385 0 : pcmcia_chip_socket_disable(psc->pct, psc->pch);
386 0 : pcmcia_card_detach((struct device *)psc,
387 : DETACH_FORCE);
388 0 : }
389 0 : CARDSLOT_SET_CARDTYPE(sc->sc_status,
390 : CARDSLOT_STATUS_CARD_NONE);
391 0 : CARDSLOT_SET_WORK(sc->sc_status,
392 : CARDSLOT_STATUS_NOTWORK);
393 0 : break;
394 :
395 : default:
396 0 : panic("cardslot_event_thread: unknown event %d", ev);
397 : }
398 0 : }
|