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