1 /* $NetBSD: cardslot.c,v 1.21 2002/10/02 16:33:40 thorpej 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.21 2002/10/02 16:33:40 thorpej 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 CFATTACH_DECL(cardslot, sizeof(struct cardslot_softc), 78 cardslotmatch, cardslotattach, NULL, NULL); 79 80 STATIC int 81 cardslotmatch(parent, cf, aux) 82 struct device *parent; 83 struct cfdata *cf; 84 void *aux; 85 { 86 struct cardslot_attach_args *caa = aux; 87 88 if (caa->caa_cb_attach == NULL && caa->caa_16_attach == NULL) { 89 /* Neither CardBus nor 16-bit PCMCIA are defined. */ 90 return 0; 91 } 92 93 return 1; 94 } 95 96 97 98 STATIC void 99 cardslotattach(parent, self, aux) 100 struct device *parent; 101 struct device *self; 102 void *aux; 103 { 104 struct cardslot_softc *sc = (struct cardslot_softc *)self; 105 struct cardslot_attach_args *caa = aux; 106 107 struct cbslot_attach_args *cba = caa->caa_cb_attach; 108 struct pcmciabus_attach_args *pa = caa->caa_16_attach; 109 110 struct cardbus_softc *csc; 111 struct pcmcia_softc *psc; 112 113 sc->sc_slot = sc->sc_dev.dv_unit; 114 sc->sc_cb_softc = NULL; 115 sc->sc_16_softc = NULL; 116 SIMPLEQ_INIT(&sc->sc_events); 117 sc->sc_th_enable = 0; 118 119 printf(" slot %d flags %x\n", sc->sc_slot, sc->sc_dev.dv_cfdata->cf_flags); 120 121 DPRINTF(("%s attaching CardBus bus...\n", sc->sc_dev.dv_xname)); 122 if (cba != NULL) { 123 if (NULL != (csc = (void *)config_found(self, cba, cardslot_cb_print))) { 124 /* cardbus found */ 125 DPRINTF(("cardslotattach: found cardbus on %s\n", sc->sc_dev.dv_xname)); 126 sc->sc_cb_softc = csc; 127 } 128 } 129 130 if (pa != NULL) { 131 if (NULL != (psc = (void *)config_found_sm(self, pa, 132 cardslot_16_print, cardslot_16_submatch))) { 133 /* pcmcia 16-bit bus found */ 134 DPRINTF(("cardslotattach: found 16-bit pcmcia bus\n")); 135 sc->sc_16_softc = psc; 136 /* 137 * XXX: 138 * dirty. This code should be removed to achieve MI. 139 */ 140 caa->caa_ph->pcmcia = (struct device *)psc; 141 } 142 } 143 144 if (csc != NULL || psc != NULL) { 145 config_pending_incr(); 146 kthread_create(create_slot_manager, (void *)sc); 147 } 148 149 if (csc && (csc->sc_cf->cardbus_ctrl)(csc->sc_cc, CARDBUS_CD)) { 150 DPRINTF(("cardslotattach: CardBus card found\n")); 151 /* attach deferred */ 152 cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_CB); 153 } 154 155 if (psc && (psc->pct->card_detect)(psc->pch)) { 156 DPRINTF(("cardbusattach: 16-bit card found\n")); 157 /* attach deferred */ 158 cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_16); 159 } 160 } 161 162 163 164 STATIC int 165 cardslot_cb_print(aux, pnp) 166 void *aux; 167 const char *pnp; 168 { 169 struct cbslot_attach_args *cba = aux; 170 171 if (pnp) { 172 printf("cardbus at %s subordinate bus %d", pnp, cba->cba_bus); 173 } 174 175 return UNCONF; 176 } 177 178 179 static int 180 cardslot_16_submatch(parent, cf, aux) 181 struct device *parent; 182 struct cfdata *cf; 183 void *aux; 184 { 185 186 if (cf->cf_loc[PCMCIABUSCF_CONTROLLER] != PCMCIABUSCF_CONTROLLER_DEFAULT 187 && cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 0) { 188 return 0; 189 } 190 191 if ((cf->cf_loc[PCMCIABUSCF_CONTROLLER] == PCMCIABUSCF_CONTROLLER_DEFAULT)) { 192 return (config_match(parent, cf, aux)); 193 } 194 195 return 0; 196 } 197 198 199 200 static int 201 cardslot_16_print(arg, pnp) 202 void *arg; 203 const char *pnp; 204 { 205 206 if (pnp) { 207 printf("pcmciabus at %s", pnp); 208 } 209 210 return UNCONF; 211 } 212 213 214 215 216 static void 217 create_slot_manager(arg) 218 void *arg; 219 { 220 struct cardslot_softc *sc = (struct cardslot_softc *)arg; 221 222 sc->sc_th_enable = 1; 223 224 if (kthread_create1(cardslot_event_thread, sc, &sc->sc_event_thread, 225 "%s", sc->sc_dev.dv_xname)) { 226 printf("%s: unable to create event thread for slot %d\n", 227 sc->sc_dev.dv_xname, sc->sc_slot); 228 panic("create_slot_manager"); 229 } 230 } 231 232 233 234 235 /* 236 * void cardslot_event_throw(struct cardslot_softc *sc, int ev) 237 * 238 * This function throws an event to the event handler. If the state 239 * of a slot is changed, it should be noticed using this function. 240 */ 241 void 242 cardslot_event_throw(sc, ev) 243 struct cardslot_softc *sc; 244 int ev; 245 { 246 struct cardslot_event *ce; 247 248 DPRINTF(("cardslot_event_throw: an event %s comes\n", 249 ev == CARDSLOT_EVENT_INSERTION_CB ? "CardBus Card inserted" : 250 ev == CARDSLOT_EVENT_INSERTION_16 ? "16-bit Card inserted" : 251 ev == CARDSLOT_EVENT_REMOVAL_CB ? "CardBus Card removed" : 252 ev == CARDSLOT_EVENT_REMOVAL_16 ? "16-bit Card removed" : "???")); 253 254 if (NULL == (ce = (struct cardslot_event *)malloc(sizeof (struct cardslot_event), M_TEMP, M_NOWAIT))) { 255 panic("cardslot_enevt"); 256 } 257 258 ce->ce_type = ev; 259 260 { 261 int s = spltty(); 262 SIMPLEQ_INSERT_TAIL(&sc->sc_events, ce, ce_q); 263 splx(s); 264 } 265 266 wakeup(&sc->sc_events); 267 268 return; 269 } 270 271 272 /* 273 * static void cardslot_event_thread(void *arg) 274 * 275 * This function is the main routine handing cardslot events such as 276 * insertions and removals. 277 * 278 */ 279 static void 280 cardslot_event_thread(arg) 281 void *arg; 282 { 283 struct cardslot_softc *sc = arg; 284 struct cardslot_event *ce; 285 int s, first = 1; 286 static int antonym_ev[4] = { 287 CARDSLOT_EVENT_REMOVAL_16, CARDSLOT_EVENT_INSERTION_16, 288 CARDSLOT_EVENT_REMOVAL_CB, CARDSLOT_EVENT_INSERTION_CB 289 }; 290 291 while (sc->sc_th_enable) { 292 s = spltty(); 293 if ((ce = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) { 294 splx(s); 295 if (first) { 296 first = 0; 297 config_pending_decr(); 298 } 299 (void) tsleep(&sc->sc_events, PWAIT, "cardslotev", 0); 300 continue; 301 } 302 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q); 303 splx(s); 304 305 if (IS_CARDSLOT_INSERT_REMOVE_EV(ce->ce_type)) { 306 /* Chattering supression */ 307 s = spltty(); 308 while (1) { 309 struct cardslot_event *ce1, *ce2; 310 311 if ((ce1 = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) { 312 break; 313 } 314 if (ce1->ce_type != antonym_ev[ce->ce_type]) { 315 break; 316 } 317 if ((ce2 = SIMPLEQ_NEXT(ce1, ce_q)) == NULL) { 318 break; 319 } 320 if (ce2->ce_type == ce->ce_type) { 321 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, 322 ce_q); 323 free(ce1, M_TEMP); 324 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, 325 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