1 /* $NetBSD: cardslot.c,v 1.40 2008/04/06 07:54:17 cegger 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.40 2008/04/06 07:54:17 cegger 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 <sys/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 #include "locators.h" 57 58 #if defined CARDSLOT_DEBUG 59 #define STATIC 60 #define DPRINTF(a) printf a 61 #else 62 #define STATIC static 63 #define DPRINTF(a) 64 #endif 65 66 67 68 STATIC void cardslotattach(struct device *, struct device *, void *); 69 STATIC int cardslotdetach(device_t, int); 70 71 STATIC int cardslotmatch(struct device *, struct cfdata *, void *); 72 static void cardslot_event_thread(void *arg); 73 74 STATIC int cardslot_cb_print(void *aux, const char *pcic); 75 static int cardslot_16_print(void *, const char *); 76 static int cardslot_16_submatch(struct device *, struct cfdata *, 77 const int *, void *); 78 79 CFATTACH_DECL(cardslot, sizeof(struct cardslot_softc), 80 cardslotmatch, cardslotattach, cardslotdetach, NULL); 81 82 STATIC int 83 cardslotmatch(struct device *parent, 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(struct device *parent, struct device *self, 100 void *aux) 101 { 102 struct cardslot_softc *sc = device_private(self); 103 struct cardslot_attach_args *caa = aux; 104 105 struct cbslot_attach_args *cba = caa->caa_cb_attach; 106 struct pcmciabus_attach_args *pa = caa->caa_16_attach; 107 108 struct cardbus_softc *csc = NULL; 109 struct pcmcia_softc *psc = NULL; 110 111 sc->sc_slot = device_unit(&sc->sc_dev); 112 sc->sc_cb_softc = NULL; 113 sc->sc_16_softc = NULL; 114 SIMPLEQ_INIT(&sc->sc_events); 115 sc->sc_th_enable = 0; 116 117 aprint_naive("\n"); 118 aprint_normal(" slot %d flags %x\n", sc->sc_slot, 119 device_cfdata(&sc->sc_dev)->cf_flags); 120 121 DPRINTF(("%s attaching CardBus bus...\n", device_xname(&sc->sc_dev))); 122 if (cba != NULL) { 123 csc = (void *)config_found_ia(self, "cbbus", cba, 124 cardslot_cb_print); 125 if (csc) { 126 /* cardbus found */ 127 DPRINTF(("%s: found cardbus on %s\n", __func__, 128 device_xname(&sc->sc_dev))); 129 sc->sc_cb_softc = csc; 130 } 131 } 132 133 if (pa != NULL) { 134 psc = (void *)config_found_sm_loc(self, "pcmciabus", NULL, pa, 135 cardslot_16_print, cardslot_16_submatch); 136 if (psc) { 137 /* pcmcia 16-bit bus found */ 138 DPRINTF(("%s: found 16-bit pcmcia bus\n", __func__)); 139 sc->sc_16_softc = psc; 140 /* 141 * XXX: 142 * dirty. This code should be removed to achieve MI. 143 */ 144 caa->caa_ph->pcmcia = (struct device *)psc; 145 } 146 } 147 148 if (csc != NULL || psc != NULL) { 149 config_pending_incr(); 150 if (kthread_create(PRI_NONE, 0, NULL, cardslot_event_thread, 151 sc, &sc->sc_event_thread, "%s", device_xname(&sc->sc_dev))) { 152 aprint_error_dev(&sc->sc_dev, "unable to create thread for slot %d\n", 153 sc->sc_slot); 154 panic("cardslotattach"); 155 } 156 sc->sc_th_enable = 1; 157 } 158 159 if (csc && (csc->sc_cf->cardbus_ctrl)(csc->sc_cc, CARDBUS_CD)) { 160 DPRINTF(("%s: CardBus card found\n", __func__)); 161 /* attach deferred */ 162 cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_CB); 163 } 164 165 if (psc && (psc->pct->card_detect)(psc->pch)) { 166 DPRINTF(("%s: 16-bit card found\n", __func__)); 167 /* attach deferred */ 168 cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_16); 169 } 170 171 if (!pmf_device_register(self, NULL, NULL)) 172 aprint_error_dev(self, "couldn't establish power handler\n"); 173 } 174 175 STATIC int 176 cardslotdetach(device_t self, int flags) 177 { 178 int rc; 179 struct cardslot_softc *sc = device_private(self); 180 181 if ((rc = config_detach_children(self, flags)) != 0) 182 return rc; 183 184 sc->sc_th_enable = 0; 185 wakeup(&sc->sc_events); 186 while (sc->sc_event_thread != NULL) 187 (void)tsleep(sc, PWAIT, "cardslotthd", 0); 188 189 if (!SIMPLEQ_EMPTY(&sc->sc_events)) 190 aprint_error_dev(self, "events outstanding"); 191 192 pmf_device_deregister(self); 193 return 0; 194 } 195 196 STATIC int 197 cardslot_cb_print(void *aux, const char *pnp) 198 { 199 struct cbslot_attach_args *cba = aux; 200 201 if (pnp != NULL) { 202 aprint_normal("cardbus at %s subordinate bus %d", 203 pnp, cba->cba_bus); 204 } 205 206 return UNCONF; 207 } 208 209 210 static int 211 cardslot_16_submatch(struct device *parent, struct cfdata *cf, 212 const int *ldesc, void *aux) 213 { 214 215 if (cf->cf_loc[PCMCIABUSCF_CONTROLLER] != PCMCIABUSCF_CONTROLLER_DEFAULT 216 && cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 0) { 217 return 0; 218 } 219 220 if ((cf->cf_loc[PCMCIABUSCF_CONTROLLER] == PCMCIABUSCF_CONTROLLER_DEFAULT)) { 221 return (config_match(parent, cf, aux)); 222 } 223 224 return 0; 225 } 226 227 228 229 static int 230 cardslot_16_print(void *arg, const char *pnp) 231 { 232 233 if (pnp != NULL) { 234 aprint_normal("pcmciabus at %s", pnp); 235 } 236 237 return UNCONF; 238 } 239 240 241 /* 242 * void cardslot_event_throw(struct cardslot_softc *sc, int ev) 243 * 244 * This function throws an event to the event handler. If the state 245 * of a slot is changed, it should be noticed using this function. 246 */ 247 void 248 cardslot_event_throw(struct cardslot_softc *sc, int ev) 249 { 250 struct cardslot_event *ce; 251 252 DPRINTF(("cardslot_event_throw: an event %s comes\n", 253 ev == CARDSLOT_EVENT_INSERTION_CB ? "CardBus Card inserted" : 254 ev == CARDSLOT_EVENT_INSERTION_16 ? "16-bit Card inserted" : 255 ev == CARDSLOT_EVENT_REMOVAL_CB ? "CardBus Card removed" : 256 ev == CARDSLOT_EVENT_REMOVAL_16 ? "16-bit Card removed" : "???")); 257 258 if (NULL == (ce = (struct cardslot_event *)malloc(sizeof (struct cardslot_event), M_TEMP, M_NOWAIT))) { 259 panic("cardslot_enevt"); 260 } 261 262 ce->ce_type = ev; 263 264 { 265 int s = spltty(); 266 SIMPLEQ_INSERT_TAIL(&sc->sc_events, ce, ce_q); 267 splx(s); 268 } 269 270 wakeup(&sc->sc_events); 271 272 return; 273 } 274 275 276 /* 277 * static void cardslot_event_thread(void *arg) 278 * 279 * This function is the main routine handing cardslot events such as 280 * insertions and removals. 281 * 282 */ 283 static void 284 cardslot_event_thread(arg) 285 void *arg; 286 { 287 struct cardslot_softc *sc = arg; 288 struct cardslot_event *ce; 289 int s, first = 1; 290 static int antonym_ev[4] = { 291 CARDSLOT_EVENT_REMOVAL_16, CARDSLOT_EVENT_INSERTION_16, 292 CARDSLOT_EVENT_REMOVAL_CB, CARDSLOT_EVENT_INSERTION_CB 293 }; 294 295 while (sc->sc_th_enable) { 296 s = spltty(); 297 if ((ce = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) { 298 splx(s); 299 if (first) { 300 first = 0; 301 config_pending_decr(); 302 } 303 (void) tsleep(&sc->sc_events, PWAIT, "cardslotev", 0); 304 continue; 305 } 306 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q); 307 splx(s); 308 309 if (IS_CARDSLOT_INSERT_REMOVE_EV(ce->ce_type)) { 310 /* Chattering suppression */ 311 s = spltty(); 312 while (1) { 313 struct cardslot_event *ce1, *ce2; 314 315 if ((ce1 = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) { 316 break; 317 } 318 if (ce1->ce_type != antonym_ev[ce->ce_type]) { 319 break; 320 } 321 if ((ce2 = SIMPLEQ_NEXT(ce1, ce_q)) == NULL) { 322 break; 323 } 324 if (ce2->ce_type == ce->ce_type) { 325 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, 326 ce_q); 327 free(ce1, M_TEMP); 328 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, 329 ce_q); 330 free(ce2, M_TEMP); 331 } 332 } 333 splx(s); 334 } 335 336 switch (ce->ce_type) { 337 case CARDSLOT_EVENT_INSERTION_CB: 338 if ((CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB) 339 || (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_16)) { 340 if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) { 341 /* 342 * A card has already been 343 * inserted and works. 344 */ 345 break; 346 } 347 } 348 349 if (sc->sc_cb_softc) { 350 CARDSLOT_SET_CARDTYPE(sc->sc_status, 351 CARDSLOT_STATUS_CARD_CB); 352 if (cardbus_attach_card(sc->sc_cb_softc) > 0) { 353 /* at least one function works */ 354 CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_WORKING); 355 } else { 356 /* 357 * no functions work or this 358 * card is not known 359 */ 360 CARDSLOT_SET_WORK(sc->sc_status, 361 CARDSLOT_STATUS_NOTWORK); 362 } 363 } else { 364 panic("no cardbus on %s", device_xname(&sc->sc_dev)); 365 } 366 367 break; 368 369 case CARDSLOT_EVENT_INSERTION_16: 370 if ((CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB) 371 || (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_16)) { 372 if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) { 373 /* 374 * A card has already been 375 * inserted and work. 376 */ 377 break; 378 } 379 } 380 if (sc->sc_16_softc) { 381 CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_16); 382 if (pcmcia_card_attach((struct device *)sc->sc_16_softc)) { 383 /* Do not attach */ 384 CARDSLOT_SET_WORK(sc->sc_status, 385 CARDSLOT_STATUS_NOTWORK); 386 } else { 387 /* working */ 388 CARDSLOT_SET_WORK(sc->sc_status, 389 CARDSLOT_STATUS_WORKING); 390 } 391 } else { 392 panic("no 16-bit pcmcia on %s", device_xname(&sc->sc_dev)); 393 } 394 395 break; 396 397 case CARDSLOT_EVENT_REMOVAL_CB: 398 if (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB) { 399 /* CardBus card has not been inserted. */ 400 if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) { 401 cardbus_detach_card(sc->sc_cb_softc); 402 CARDSLOT_SET_WORK(sc->sc_status, 403 CARDSLOT_STATUS_NOTWORK); 404 CARDSLOT_SET_WORK(sc->sc_status, 405 CARDSLOT_STATUS_CARD_NONE); 406 } 407 CARDSLOT_SET_CARDTYPE(sc->sc_status, 408 CARDSLOT_STATUS_CARD_NONE); 409 } else if (CARDSLOT_CARDTYPE(sc->sc_status) != CARDSLOT_STATUS_CARD_16) { 410 /* Unknown card... */ 411 CARDSLOT_SET_CARDTYPE(sc->sc_status, 412 CARDSLOT_STATUS_CARD_NONE); 413 } 414 CARDSLOT_SET_WORK(sc->sc_status, 415 CARDSLOT_STATUS_NOTWORK); 416 break; 417 418 case CARDSLOT_EVENT_REMOVAL_16: 419 DPRINTF(("%s: removal event\n", device_xname(&sc->sc_dev))); 420 if (CARDSLOT_CARDTYPE(sc->sc_status) != CARDSLOT_STATUS_CARD_16) { 421 /* 16-bit card has not been inserted. */ 422 break; 423 } 424 if ((sc->sc_16_softc != NULL) 425 && (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING)) { 426 struct pcmcia_softc *psc = sc->sc_16_softc; 427 428 pcmcia_card_deactivate((struct device *)psc); 429 pcmcia_chip_socket_disable(psc->pct, psc->pch); 430 pcmcia_card_detach((struct device *)psc, DETACH_FORCE); 431 } 432 CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_NONE); 433 CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_NOTWORK); 434 break; 435 436 default: 437 panic("cardslot_event_thread: unknown event %d", ce->ce_type); 438 } 439 free(ce, M_TEMP); 440 } 441 442 sc->sc_event_thread = NULL; 443 444 /* In case the parent device is waiting for us to exit. */ 445 wakeup(sc); 446 447 kthread_exit(0); 448 } 449