1 /* $NetBSD: cardslot.c,v 1.24 2003/11/02 09:56:38 wiz 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.24 2003/11/02 09:56:38 wiz 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 = NULL; 111 struct pcmcia_softc *psc = NULL; 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 aprint_normal("cardbus at %s subordinate bus %d", 173 pnp, cba->cba_bus); 174 } 175 176 return UNCONF; 177 } 178 179 180 static int 181 cardslot_16_submatch(parent, cf, aux) 182 struct device *parent; 183 struct cfdata *cf; 184 void *aux; 185 { 186 187 if (cf->cf_loc[PCMCIABUSCF_CONTROLLER] != PCMCIABUSCF_CONTROLLER_DEFAULT 188 && cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 0) { 189 return 0; 190 } 191 192 if ((cf->cf_loc[PCMCIABUSCF_CONTROLLER] == PCMCIABUSCF_CONTROLLER_DEFAULT)) { 193 return (config_match(parent, cf, aux)); 194 } 195 196 return 0; 197 } 198 199 200 201 static int 202 cardslot_16_print(arg, pnp) 203 void *arg; 204 const char *pnp; 205 { 206 207 if (pnp) { 208 aprint_normal("pcmciabus at %s", pnp); 209 } 210 211 return UNCONF; 212 } 213 214 215 216 217 static void 218 create_slot_manager(arg) 219 void *arg; 220 { 221 struct cardslot_softc *sc = (struct cardslot_softc *)arg; 222 223 sc->sc_th_enable = 1; 224 225 if (kthread_create1(cardslot_event_thread, sc, &sc->sc_event_thread, 226 "%s", sc->sc_dev.dv_xname)) { 227 printf("%s: unable to create event thread for slot %d\n", 228 sc->sc_dev.dv_xname, sc->sc_slot); 229 panic("create_slot_manager"); 230 } 231 } 232 233 234 235 236 /* 237 * void cardslot_event_throw(struct cardslot_softc *sc, int ev) 238 * 239 * This function throws an event to the event handler. If the state 240 * of a slot is changed, it should be noticed using this function. 241 */ 242 void 243 cardslot_event_throw(sc, ev) 244 struct cardslot_softc *sc; 245 int ev; 246 { 247 struct cardslot_event *ce; 248 249 DPRINTF(("cardslot_event_throw: an event %s comes\n", 250 ev == CARDSLOT_EVENT_INSERTION_CB ? "CardBus Card inserted" : 251 ev == CARDSLOT_EVENT_INSERTION_16 ? "16-bit Card inserted" : 252 ev == CARDSLOT_EVENT_REMOVAL_CB ? "CardBus Card removed" : 253 ev == CARDSLOT_EVENT_REMOVAL_16 ? "16-bit Card removed" : "???")); 254 255 if (NULL == (ce = (struct cardslot_event *)malloc(sizeof (struct cardslot_event), M_TEMP, M_NOWAIT))) { 256 panic("cardslot_enevt"); 257 } 258 259 ce->ce_type = ev; 260 261 { 262 int s = spltty(); 263 SIMPLEQ_INSERT_TAIL(&sc->sc_events, ce, ce_q); 264 splx(s); 265 } 266 267 wakeup(&sc->sc_events); 268 269 return; 270 } 271 272 273 /* 274 * static void cardslot_event_thread(void *arg) 275 * 276 * This function is the main routine handing cardslot events such as 277 * insertions and removals. 278 * 279 */ 280 static void 281 cardslot_event_thread(arg) 282 void *arg; 283 { 284 struct cardslot_softc *sc = arg; 285 struct cardslot_event *ce; 286 int s, first = 1; 287 static int antonym_ev[4] = { 288 CARDSLOT_EVENT_REMOVAL_16, CARDSLOT_EVENT_INSERTION_16, 289 CARDSLOT_EVENT_REMOVAL_CB, CARDSLOT_EVENT_INSERTION_CB 290 }; 291 292 while (sc->sc_th_enable) { 293 s = spltty(); 294 if ((ce = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) { 295 splx(s); 296 if (first) { 297 first = 0; 298 config_pending_decr(); 299 } 300 (void) tsleep(&sc->sc_events, PWAIT, "cardslotev", 0); 301 continue; 302 } 303 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q); 304 splx(s); 305 306 if (IS_CARDSLOT_INSERT_REMOVE_EV(ce->ce_type)) { 307 /* Chattering suppression */ 308 s = spltty(); 309 while (1) { 310 struct cardslot_event *ce1, *ce2; 311 312 if ((ce1 = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) { 313 break; 314 } 315 if (ce1->ce_type != antonym_ev[ce->ce_type]) { 316 break; 317 } 318 if ((ce2 = SIMPLEQ_NEXT(ce1, ce_q)) == NULL) { 319 break; 320 } 321 if (ce2->ce_type == ce->ce_type) { 322 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, 323 ce_q); 324 free(ce1, M_TEMP); 325 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, 326 ce_q); 327 free(ce2, M_TEMP); 328 } 329 } 330 splx(s); 331 } 332 333 switch (ce->ce_type) { 334 case CARDSLOT_EVENT_INSERTION_CB: 335 if ((CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB) 336 || (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_16)) { 337 if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) { 338 /* 339 * A card has already been 340 * inserted and works. 341 */ 342 break; 343 } 344 } 345 346 if (sc->sc_cb_softc) { 347 CARDSLOT_SET_CARDTYPE(sc->sc_status, 348 CARDSLOT_STATUS_CARD_CB); 349 if (cardbus_attach_card(sc->sc_cb_softc) > 0) { 350 /* at least one function works */ 351 CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_WORKING); 352 } else { 353 /* 354 * no functions work or this 355 * card is not known 356 */ 357 CARDSLOT_SET_WORK(sc->sc_status, 358 CARDSLOT_STATUS_NOTWORK); 359 } 360 } else { 361 panic("no cardbus on %s", sc->sc_dev.dv_xname); 362 } 363 364 break; 365 366 case CARDSLOT_EVENT_INSERTION_16: 367 if ((CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB) 368 || (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_16)) { 369 if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) { 370 /* 371 * A card has already been 372 * inserted and work. 373 */ 374 break; 375 } 376 } 377 if (sc->sc_16_softc) { 378 CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_16); 379 if (pcmcia_card_attach((struct device *)sc->sc_16_softc)) { 380 /* Do not attach */ 381 CARDSLOT_SET_WORK(sc->sc_status, 382 CARDSLOT_STATUS_NOTWORK); 383 } else { 384 /* working */ 385 CARDSLOT_SET_WORK(sc->sc_status, 386 CARDSLOT_STATUS_WORKING); 387 } 388 } else { 389 panic("no 16-bit pcmcia on %s", sc->sc_dev.dv_xname); 390 } 391 392 break; 393 394 case CARDSLOT_EVENT_REMOVAL_CB: 395 if (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB) { 396 /* CardBus card has not been inserted. */ 397 if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) { 398 cardbus_detach_card(sc->sc_cb_softc); 399 CARDSLOT_SET_WORK(sc->sc_status, 400 CARDSLOT_STATUS_NOTWORK); 401 CARDSLOT_SET_WORK(sc->sc_status, 402 CARDSLOT_STATUS_CARD_NONE); 403 } 404 CARDSLOT_SET_CARDTYPE(sc->sc_status, 405 CARDSLOT_STATUS_CARD_NONE); 406 } else if (CARDSLOT_CARDTYPE(sc->sc_status) != CARDSLOT_STATUS_CARD_16) { 407 /* Unknown card... */ 408 CARDSLOT_SET_CARDTYPE(sc->sc_status, 409 CARDSLOT_STATUS_CARD_NONE); 410 } 411 CARDSLOT_SET_WORK(sc->sc_status, 412 CARDSLOT_STATUS_NOTWORK); 413 break; 414 415 case CARDSLOT_EVENT_REMOVAL_16: 416 DPRINTF(("%s: removal event\n", sc->sc_dev.dv_xname)); 417 if (CARDSLOT_CARDTYPE(sc->sc_status) != CARDSLOT_STATUS_CARD_16) { 418 /* 16-bit card has not been inserted. */ 419 break; 420 } 421 if ((sc->sc_16_softc != NULL) 422 && (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING)) { 423 struct pcmcia_softc *psc = sc->sc_16_softc; 424 425 pcmcia_card_deactivate((struct device *)psc); 426 pcmcia_chip_socket_disable(psc->pct, psc->pch); 427 pcmcia_card_detach((struct device *)psc, DETACH_FORCE); 428 } 429 CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_NONE); 430 CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_NOTWORK); 431 break; 432 433 default: 434 panic("cardslot_event_thread: unknown event %d", ce->ce_type); 435 } 436 free(ce, M_TEMP); 437 } 438 439 sc->sc_event_thread = NULL; 440 441 /* In case the parent device is waiting for us to exit. */ 442 wakeup(sc); 443 444 kthread_exit(0); 445 } 446