xref: /openbsd-src/sys/dev/cardbus/cardslot.c (revision c7101648ccc694093c4a805ebde0f53056d1a24c)
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