1 /* $OpenBSD: cardslot.c,v 1.24 2024/05/24 06:26:47 jsg 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/pool.h>
35 #include <sys/task.h>
36
37 #include <dev/cardbus/cardslotvar.h>
38 #include <dev/cardbus/cardbusvar.h>
39 #include <dev/pcmcia/pcmciavar.h>
40 #include <dev/pcmcia/pcmciachip.h>
41 #include <dev/ic/i82365var.h>
42
43 #if defined CARDSLOT_DEBUG
44 #define STATIC
45 #define DPRINTF(a) printf a
46 #else
47 #ifdef DDB
48 #define STATIC
49 #else
50 #define STATIC static
51 #endif
52 #define DPRINTF(a)
53 #endif
54
55 STATIC void cardslotattach(struct device *, struct device *, void *);
56
57 STATIC int cardslotmatch(struct device *, void *, void *);
58 STATIC void cardslot_event(void *arg);
59 STATIC void cardslot_process_event(struct cardslot_softc *);
60
61 STATIC int cardslot_cb_print(void *aux, const char *pcic);
62 STATIC int cardslot_16_print(void *, const char *);
63 STATIC int cardslot_16_submatch(struct device *, void *,void *);
64
65 const struct cfattach cardslot_ca = {
66 sizeof(struct cardslot_softc), cardslotmatch, cardslotattach
67 };
68
69 struct cfdriver cardslot_cd = {
70 NULL, "cardslot", DV_DULL
71 };
72
73 struct pool cardsloteventpool;
74
75 STATIC int
cardslotmatch(struct device * parent,void * match,void * aux)76 cardslotmatch(struct device *parent, void *match, void *aux)
77 {
78 struct cardslot_attach_args *caa = aux;
79
80 if (caa->caa_cb_attach == NULL && caa->caa_16_attach == NULL) {
81 /* Neither CardBus nor 16-bit PCMCIA are defined. */
82 return (0);
83 }
84
85 return (1);
86 }
87
88 STATIC void
cardslotattach(struct device * parent,struct device * self,void * aux)89 cardslotattach(struct device *parent, struct device *self, void *aux)
90 {
91 struct cardslot_softc *sc = (struct cardslot_softc *)self;
92 struct cardslot_attach_args *caa = aux;
93
94 struct cbslot_attach_args *cba = caa->caa_cb_attach;
95 struct pcmciabus_attach_args *pa = caa->caa_16_attach;
96
97 struct cardbus_softc *csc = NULL;
98 struct pcmcia_softc *psc = NULL;
99
100 if (cardsloteventpool.pr_size == 0) {
101 pool_init(&cardsloteventpool, sizeof(struct cardslot_event),
102 0, IPL_BIO, 0, "cardslot", NULL);
103 }
104
105 sc->sc_slot = sc->sc_dev.dv_unit;
106 sc->sc_cb_softc = NULL;
107 sc->sc_16_softc = NULL;
108 SIMPLEQ_INIT(&sc->sc_events);
109 task_set(&sc->sc_event_task, cardslot_event, sc);
110
111 printf(" slot %d flags %x\n", sc->sc_slot,
112 sc->sc_dev.dv_cfdata->cf_flags);
113
114 DPRINTF(("%s attaching CardBus bus...\n", sc->sc_dev.dv_xname));
115 if (cba != NULL) {
116 if ((csc = (void *)config_found(self, cba,
117 cardslot_cb_print)) != NULL) {
118 /* cardbus found */
119 DPRINTF(("cardslotattach: found cardbus on %s\n",
120 sc->sc_dev.dv_xname));
121 sc->sc_cb_softc = csc;
122 }
123 }
124
125 if (pa != NULL) {
126 if ((psc = (void *)config_found_sm(self, pa, cardslot_16_print,
127 cardslot_16_submatch)) != NULL) {
128 /* pcmcia 16-bit bus found */
129 DPRINTF(("cardslotattach: found 16-bit pcmcia bus\n"));
130 sc->sc_16_softc = psc;
131 /* XXX: dirty. This code should be removed
132 * to achieve MI
133 */
134 caa->caa_ph->pcmcia = (struct device *)psc;
135 }
136 }
137
138 if (csc && (csc->sc_cf->cardbus_ctrl)(csc->sc_cc, CARDBUS_CD)) {
139 DPRINTF(("cardslotattach: CardBus card found\n"));
140 /* attach deferred */
141 cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_CB);
142 }
143
144 if (psc && (psc->pct->card_detect)(psc->pch)) {
145 DPRINTF(("cardbusattach: 16-bit card found\n"));
146 /* attach deferred */
147 cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_16);
148 }
149 }
150
151 STATIC int
cardslot_cb_print(void * aux,const char * pnp)152 cardslot_cb_print(void *aux, const char *pnp)
153 {
154 struct cbslot_attach_args *cba = aux;
155
156 if (pnp)
157 printf("cardbus at %s subordinate bus %d", pnp, cba->cba_bus);
158
159 return (UNCONF);
160 }
161
162 STATIC int
cardslot_16_submatch(struct device * parent,void * match,void * aux)163 cardslot_16_submatch(struct device *parent, void *match, void *aux)
164 {
165 struct cfdata *cf = match;
166
167 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != 0)
168 return (0);
169
170 if (cf->cf_loc[0] == -1)
171 return ((*cf->cf_attach->ca_match)(parent, cf, aux));
172
173 return (0);
174 }
175
176 STATIC int
cardslot_16_print(void * arg,const char * pnp)177 cardslot_16_print(void *arg, const char *pnp)
178 {
179 if (pnp)
180 printf("pcmciabus at %s", pnp);
181
182 return (UNCONF);
183 }
184
185 /*
186 * void cardslot_event_throw(struct cardslot_softc *sc, int ev)
187 *
188 * This function throws an event to the event handler. If the state
189 * of a slot is changed, it should be noticed using this function.
190 */
191 void
cardslot_event_throw(struct cardslot_softc * sc,int ev)192 cardslot_event_throw(struct cardslot_softc *sc, int ev)
193 {
194 struct cardslot_event *ce;
195 int s;
196
197 DPRINTF(("cardslot_event_throw: an event %s comes\n",
198 ev == CARDSLOT_EVENT_INSERTION_CB ? "CardBus Card inserted" :
199 ev == CARDSLOT_EVENT_INSERTION_16 ? "16-bit Card inserted" :
200 ev == CARDSLOT_EVENT_REMOVAL_CB ? "CardBus Card removed" :
201 ev == CARDSLOT_EVENT_REMOVAL_16 ? "16-bit Card removed" : "???"));
202
203 ce = pool_get(&cardsloteventpool, PR_NOWAIT);
204 if (ce == NULL)
205 return;
206 ce->ce_type = ev;
207
208 s = spltty();
209 SIMPLEQ_INSERT_TAIL(&sc->sc_events, ce, ce_q);
210 splx(s);
211
212 task_add(systq, &sc->sc_event_task);
213 }
214
215 /*
216 * STATIC void cardslot_event(void *arg)
217 *
218 * This function is the main routine handing cardslot events such as
219 * insertions and removals.
220 *
221 */
222 STATIC void
cardslot_event(void * arg1)223 cardslot_event(void *arg1)
224 {
225 struct cardslot_softc *sc = arg1;
226
227 while (!SIMPLEQ_EMPTY(&sc->sc_events))
228 cardslot_process_event(sc);
229 }
230
231
232 STATIC void
cardslot_process_event(struct cardslot_softc * sc)233 cardslot_process_event(struct cardslot_softc *sc)
234 {
235 struct cardslot_event *ce;
236 int s, ev;
237
238 s = spltty();
239 if ((ce = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) {
240 splx(s);
241 return;
242 }
243 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q);
244
245 if (IS_CARDSLOT_INSERT_REMOVE_EV(ce->ce_type)) {
246 /* Chattering suppression */
247 static int antonym_ev[4] = {
248 CARDSLOT_EVENT_REMOVAL_16,
249 CARDSLOT_EVENT_INSERTION_16,
250 CARDSLOT_EVENT_REMOVAL_CB,
251 CARDSLOT_EVENT_INSERTION_CB
252 };
253
254 while (1) {
255 struct cardslot_event *ce1, *ce2;
256
257 if ((ce1 = SIMPLEQ_FIRST(&sc->sc_events)) ==
258 NULL)
259 break;
260 if (ce1->ce_type != antonym_ev[ce->ce_type])
261 break;
262 if ((ce2 = SIMPLEQ_NEXT(ce1, ce_q)) == NULL)
263 break;
264 if (ce2->ce_type == ce->ce_type) {
265 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q);
266 pool_put(&cardsloteventpool, ce1);
267 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q);
268 pool_put(&cardsloteventpool, ce2);
269 }
270 }
271 }
272 splx(s);
273
274 ev = ce->ce_type;
275 pool_put(&cardsloteventpool, ce);
276
277 switch (ev) {
278 case CARDSLOT_EVENT_INSERTION_CB:
279 if ((CARDSLOT_CARDTYPE(sc->sc_status) ==
280 CARDSLOT_STATUS_CARD_CB) ||
281 (CARDSLOT_CARDTYPE(sc->sc_status) ==
282 CARDSLOT_STATUS_CARD_16)) {
283 if (CARDSLOT_WORK(sc->sc_status) ==
284 CARDSLOT_STATUS_WORKING) {
285 /* A card has already been inserted
286 * and works.
287 */
288 break;
289 }
290 }
291
292 if (sc->sc_cb_softc) {
293 CARDSLOT_SET_CARDTYPE(sc->sc_status,
294 CARDSLOT_STATUS_CARD_CB);
295 if (cardbus_attach_card(sc->sc_cb_softc) > 0) {
296 /* At least one function works */
297 CARDSLOT_SET_WORK(sc->sc_status,
298 CARDSLOT_STATUS_WORKING);
299 } else {
300 /* No functions work or this card is
301 * not known
302 */
303 CARDSLOT_SET_WORK(sc->sc_status,
304 CARDSLOT_STATUS_NOTWORK);
305 }
306 } else {
307 printf("%s: CardBus support disabled\n",
308 sc->sc_dev.dv_xname);
309 }
310 break;
311
312 case CARDSLOT_EVENT_INSERTION_16:
313 if ((CARDSLOT_CARDTYPE(sc->sc_status) ==
314 CARDSLOT_STATUS_CARD_CB) ||
315 (CARDSLOT_CARDTYPE(sc->sc_status) ==
316 CARDSLOT_STATUS_CARD_16)) {
317 if (CARDSLOT_WORK(sc->sc_status) ==
318 CARDSLOT_STATUS_WORKING) {
319 /* A card has already been inserted
320 * and works.
321 */
322 break;
323 }
324 }
325 if (sc->sc_16_softc) {
326 CARDSLOT_SET_CARDTYPE(sc->sc_status,
327 CARDSLOT_STATUS_CARD_16);
328 if (pcmcia_card_attach(
329 (struct device *)sc->sc_16_softc)) {
330 /* Do not attach */
331 CARDSLOT_SET_WORK(sc->sc_status,
332 CARDSLOT_STATUS_NOTWORK);
333 } else {
334 /* working */
335 CARDSLOT_SET_WORK(sc->sc_status,
336 CARDSLOT_STATUS_WORKING);
337 }
338 } else {
339 panic("no 16-bit pcmcia on %s",
340 sc->sc_dev.dv_xname);
341 }
342 break;
343
344 case CARDSLOT_EVENT_REMOVAL_CB:
345 if (CARDSLOT_CARDTYPE(sc->sc_status) ==
346 CARDSLOT_STATUS_CARD_CB) {
347 /* CardBus card has not been inserted. */
348 if (CARDSLOT_WORK(sc->sc_status) ==
349 CARDSLOT_STATUS_WORKING) {
350 cardbus_detach_card(sc->sc_cb_softc);
351 CARDSLOT_SET_WORK(sc->sc_status,
352 CARDSLOT_STATUS_NOTWORK);
353 CARDSLOT_SET_WORK(sc->sc_status,
354 CARDSLOT_STATUS_CARD_NONE);
355 }
356 CARDSLOT_SET_CARDTYPE(sc->sc_status,
357 CARDSLOT_STATUS_CARD_NONE);
358 } else if (CARDSLOT_CARDTYPE(sc->sc_status) !=
359 CARDSLOT_STATUS_CARD_16) {
360 /* Unknown card... */
361 CARDSLOT_SET_CARDTYPE(sc->sc_status,
362 CARDSLOT_STATUS_CARD_NONE);
363 }
364 CARDSLOT_SET_WORK(sc->sc_status,
365 CARDSLOT_STATUS_NOTWORK);
366 break;
367
368 case CARDSLOT_EVENT_REMOVAL_16:
369 DPRINTF(("%s: removal event\n", sc->sc_dev.dv_xname));
370 if (CARDSLOT_CARDTYPE(sc->sc_status) !=
371 CARDSLOT_STATUS_CARD_16) {
372 /* 16-bit card has not been inserted. */
373 break;
374 }
375 if ((sc->sc_16_softc != NULL) &&
376 (CARDSLOT_WORK(sc->sc_status) ==
377 CARDSLOT_STATUS_WORKING)) {
378 struct pcmcia_softc *psc = sc->sc_16_softc;
379
380 pcmcia_card_deactivate((struct device *)psc);
381 pcmcia_chip_socket_disable(psc->pct, psc->pch);
382 pcmcia_card_detach((struct device *)psc,
383 DETACH_FORCE);
384 }
385 CARDSLOT_SET_CARDTYPE(sc->sc_status,
386 CARDSLOT_STATUS_CARD_NONE);
387 CARDSLOT_SET_WORK(sc->sc_status,
388 CARDSLOT_STATUS_NOTWORK);
389 break;
390
391 default:
392 panic("cardslot_event_thread: unknown event %d", ev);
393 }
394 }
395