1 /* $OpenBSD: cardslot.c,v 1.16 2013/10/30 08:47:20 mpi 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/malloc.h> 35 #include <sys/kernel.h> 36 #include <sys/syslog.h> 37 #include <sys/kthread.h> 38 #include <sys/pool.h> 39 #include <sys/task.h> 40 41 #include <machine/bus.h> 42 43 #include <dev/cardbus/cardslotvar.h> 44 #include <dev/cardbus/cardbusvar.h> 45 #include <dev/pcmcia/pcmciavar.h> 46 #include <dev/pcmcia/pcmciachip.h> 47 #include <dev/ic/i82365var.h> 48 49 #if defined CARDSLOT_DEBUG 50 #define STATIC 51 #define DPRINTF(a) printf a 52 #else 53 #ifdef DDB 54 #define STATIC 55 #else 56 #define STATIC static 57 #endif 58 #define DPRINTF(a) 59 #endif 60 61 STATIC void cardslotattach(struct device *, struct device *, void *); 62 63 STATIC int cardslotmatch(struct device *, void *, void *); 64 STATIC void cardslot_event(void *arg1, void *arg2); 65 STATIC void cardslot_process_event(struct cardslot_softc *); 66 67 STATIC int cardslot_cb_print(void *aux, const char *pcic); 68 STATIC int cardslot_16_print(void *, const char *); 69 STATIC int cardslot_16_submatch(struct device *, void *,void *); 70 71 struct cfattach cardslot_ca = { 72 sizeof(struct cardslot_softc), cardslotmatch, cardslotattach 73 }; 74 75 struct cfdriver cardslot_cd = { 76 NULL, "cardslot", DV_DULL 77 }; 78 79 struct pool cardsloteventpool; 80 81 STATIC int 82 cardslotmatch(struct device *parent, void *match, void *aux) 83 { 84 struct cardslot_attach_args *caa = aux; 85 86 if (caa->caa_cb_attach == NULL && caa->caa_16_attach == NULL) { 87 /* Neither CardBus nor 16-bit PCMCIA are defined. */ 88 return (0); 89 } 90 91 return (1); 92 } 93 94 STATIC void 95 cardslotattach(struct device *parent, struct device *self, void *aux) 96 { 97 struct cardslot_softc *sc = (struct cardslot_softc *)self; 98 struct cardslot_attach_args *caa = aux; 99 100 struct cbslot_attach_args *cba = caa->caa_cb_attach; 101 struct pcmciabus_attach_args *pa = caa->caa_16_attach; 102 103 struct cardbus_softc *csc = NULL; 104 struct pcmcia_softc *psc = NULL; 105 106 if (cardsloteventpool.pr_align == 0) 107 pool_init(&cardsloteventpool, sizeof(struct cardslot_event), 108 0, 0, 0, "cardslot", NULL); 109 110 sc->sc_slot = sc->sc_dev.dv_unit; 111 sc->sc_cb_softc = NULL; 112 sc->sc_16_softc = NULL; 113 SIMPLEQ_INIT(&sc->sc_events); 114 task_set(&sc->sc_event_task, cardslot_event, sc, NULL); 115 116 printf(" slot %d flags %x\n", sc->sc_slot, 117 sc->sc_dev.dv_cfdata->cf_flags); 118 119 DPRINTF(("%s attaching CardBus bus...\n", sc->sc_dev.dv_xname)); 120 if (cba != NULL) { 121 if ((csc = (void *)config_found(self, cba, 122 cardslot_cb_print)) != NULL) { 123 /* cardbus found */ 124 DPRINTF(("cardslotattach: found cardbus on %s\n", 125 sc->sc_dev.dv_xname)); 126 sc->sc_cb_softc = csc; 127 } 128 } 129 130 if (pa != NULL) { 131 if ((psc = (void *)config_found_sm(self, pa, cardslot_16_print, 132 cardslot_16_submatch)) != NULL) { 133 /* pcmcia 16-bit bus found */ 134 DPRINTF(("cardslotattach: found 16-bit pcmcia bus\n")); 135 sc->sc_16_softc = psc; 136 /* XXX: dirty. This code should be removed 137 * to achieve MI 138 */ 139 caa->caa_ph->pcmcia = (struct device *)psc; 140 } 141 } 142 143 if (csc && (csc->sc_cf->cardbus_ctrl)(csc->sc_cc, CARDBUS_CD)) { 144 DPRINTF(("cardslotattach: CardBus card found\n")); 145 /* attach deferred */ 146 cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_CB); 147 } 148 149 if (psc && (psc->pct->card_detect)(psc->pch)) { 150 DPRINTF(("cardbusattach: 16-bit card found\n")); 151 /* attach deferred */ 152 cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_16); 153 } 154 } 155 156 STATIC int 157 cardslot_cb_print(void *aux, const char *pnp) 158 { 159 struct cbslot_attach_args *cba = aux; 160 161 if (pnp) 162 printf("cardbus at %s subordinate bus %d", pnp, cba->cba_bus); 163 164 return (UNCONF); 165 } 166 167 STATIC int 168 cardslot_16_submatch(struct device *parent, void *match, void *aux) 169 { 170 struct cfdata *cf = match; 171 172 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != 0) 173 return (0); 174 175 if (cf->cf_loc[0] == -1) 176 return ((*cf->cf_attach->ca_match)(parent, cf, aux)); 177 178 return (0); 179 } 180 181 STATIC int 182 cardslot_16_print(void *arg, const char *pnp) 183 { 184 if (pnp) 185 printf("pcmciabus at %s", pnp); 186 187 return (UNCONF); 188 } 189 190 /* 191 * void cardslot_event_throw(struct cardslot_softc *sc, int ev) 192 * 193 * This function throws an event to the event handler. If the state 194 * of a slot is changed, it should be noticed using this function. 195 */ 196 void 197 cardslot_event_throw(struct cardslot_softc *sc, int ev) 198 { 199 struct cardslot_event *ce; 200 int s; 201 202 DPRINTF(("cardslot_event_throw: an event %s comes\n", 203 ev == CARDSLOT_EVENT_INSERTION_CB ? "CardBus Card inserted" : 204 ev == CARDSLOT_EVENT_INSERTION_16 ? "16-bit Card inserted" : 205 ev == CARDSLOT_EVENT_REMOVAL_CB ? "CardBus Card removed" : 206 ev == CARDSLOT_EVENT_REMOVAL_16 ? "16-bit Card removed" : "???")); 207 208 ce = pool_get(&cardsloteventpool, PR_NOWAIT); 209 if (ce == NULL) 210 return; 211 ce->ce_type = ev; 212 213 s = spltty(); 214 SIMPLEQ_INSERT_TAIL(&sc->sc_events, ce, ce_q); 215 splx(s); 216 217 task_add(systq, &sc->sc_event_task); 218 } 219 220 /* 221 * STATIC void cardslot_event(void *arg) 222 * 223 * This function is the main routine handing cardslot events such as 224 * insertions and removals. 225 * 226 */ 227 STATIC void 228 cardslot_event(void *arg1, void *arg2) 229 { 230 struct cardslot_softc *sc = arg1; 231 232 while (!SIMPLEQ_EMPTY(&sc->sc_events)) 233 cardslot_process_event(sc); 234 } 235 236 237 STATIC void 238 cardslot_process_event(struct cardslot_softc *sc) 239 { 240 struct cardslot_event *ce; 241 int s, ev; 242 243 s = spltty(); 244 if ((ce = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) { 245 splx(s); 246 return; 247 } 248 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q); 249 250 if (IS_CARDSLOT_INSERT_REMOVE_EV(ce->ce_type)) { 251 /* Chattering suppression */ 252 static int antonym_ev[4] = { 253 CARDSLOT_EVENT_REMOVAL_16, 254 CARDSLOT_EVENT_INSERTION_16, 255 CARDSLOT_EVENT_REMOVAL_CB, 256 CARDSLOT_EVENT_INSERTION_CB 257 }; 258 259 while (1) { 260 struct cardslot_event *ce1, *ce2; 261 262 if ((ce1 = SIMPLEQ_FIRST(&sc->sc_events)) == 263 NULL) 264 break; 265 if (ce1->ce_type != antonym_ev[ce->ce_type]) 266 break; 267 if ((ce2 = SIMPLEQ_NEXT(ce1, ce_q)) == NULL) 268 break; 269 if (ce2->ce_type == ce->ce_type) { 270 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q); 271 pool_put(&cardsloteventpool, ce1); 272 SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q); 273 pool_put(&cardsloteventpool, ce2); 274 } 275 } 276 } 277 splx(s); 278 279 ev = ce->ce_type; 280 pool_put(&cardsloteventpool, ce); 281 282 switch (ev) { 283 case CARDSLOT_EVENT_INSERTION_CB: 284 if ((CARDSLOT_CARDTYPE(sc->sc_status) == 285 CARDSLOT_STATUS_CARD_CB) || 286 (CARDSLOT_CARDTYPE(sc->sc_status) == 287 CARDSLOT_STATUS_CARD_16)) { 288 if (CARDSLOT_WORK(sc->sc_status) == 289 CARDSLOT_STATUS_WORKING) { 290 /* A card has already been inserted 291 * and works. 292 */ 293 break; 294 } 295 } 296 297 if (sc->sc_cb_softc) { 298 CARDSLOT_SET_CARDTYPE(sc->sc_status, 299 CARDSLOT_STATUS_CARD_CB); 300 if (cardbus_attach_card(sc->sc_cb_softc) > 0) { 301 /* At least one function works */ 302 CARDSLOT_SET_WORK(sc->sc_status, 303 CARDSLOT_STATUS_WORKING); 304 } else { 305 /* No functions work or this card is 306 * not known 307 */ 308 CARDSLOT_SET_WORK(sc->sc_status, 309 CARDSLOT_STATUS_NOTWORK); 310 } 311 } else { 312 printf("%s: CardBus support disabled\n", 313 sc->sc_dev.dv_xname); 314 } 315 break; 316 317 case CARDSLOT_EVENT_INSERTION_16: 318 if ((CARDSLOT_CARDTYPE(sc->sc_status) == 319 CARDSLOT_STATUS_CARD_CB) || 320 (CARDSLOT_CARDTYPE(sc->sc_status) == 321 CARDSLOT_STATUS_CARD_16)) { 322 if (CARDSLOT_WORK(sc->sc_status) == 323 CARDSLOT_STATUS_WORKING) { 324 /* A card has already been inserted 325 * and works. 326 */ 327 break; 328 } 329 } 330 if (sc->sc_16_softc) { 331 CARDSLOT_SET_CARDTYPE(sc->sc_status, 332 CARDSLOT_STATUS_CARD_16); 333 if (pcmcia_card_attach( 334 (struct device *)sc->sc_16_softc)) { 335 /* Do not attach */ 336 CARDSLOT_SET_WORK(sc->sc_status, 337 CARDSLOT_STATUS_NOTWORK); 338 } else { 339 /* working */ 340 CARDSLOT_SET_WORK(sc->sc_status, 341 CARDSLOT_STATUS_WORKING); 342 } 343 } else { 344 panic("no 16-bit pcmcia on %s", 345 sc->sc_dev.dv_xname); 346 } 347 break; 348 349 case CARDSLOT_EVENT_REMOVAL_CB: 350 if (CARDSLOT_CARDTYPE(sc->sc_status) == 351 CARDSLOT_STATUS_CARD_CB) { 352 /* CardBus card has not been inserted. */ 353 if (CARDSLOT_WORK(sc->sc_status) == 354 CARDSLOT_STATUS_WORKING) { 355 cardbus_detach_card(sc->sc_cb_softc); 356 CARDSLOT_SET_WORK(sc->sc_status, 357 CARDSLOT_STATUS_NOTWORK); 358 CARDSLOT_SET_WORK(sc->sc_status, 359 CARDSLOT_STATUS_CARD_NONE); 360 } 361 CARDSLOT_SET_CARDTYPE(sc->sc_status, 362 CARDSLOT_STATUS_CARD_NONE); 363 } else if (CARDSLOT_CARDTYPE(sc->sc_status) != 364 CARDSLOT_STATUS_CARD_16) { 365 /* Unknown card... */ 366 CARDSLOT_SET_CARDTYPE(sc->sc_status, 367 CARDSLOT_STATUS_CARD_NONE); 368 } 369 CARDSLOT_SET_WORK(sc->sc_status, 370 CARDSLOT_STATUS_NOTWORK); 371 break; 372 373 case CARDSLOT_EVENT_REMOVAL_16: 374 DPRINTF(("%s: removal event\n", sc->sc_dev.dv_xname)); 375 if (CARDSLOT_CARDTYPE(sc->sc_status) != 376 CARDSLOT_STATUS_CARD_16) { 377 /* 16-bit card has not been inserted. */ 378 break; 379 } 380 if ((sc->sc_16_softc != NULL) && 381 (CARDSLOT_WORK(sc->sc_status) == 382 CARDSLOT_STATUS_WORKING)) { 383 struct pcmcia_softc *psc = sc->sc_16_softc; 384 385 pcmcia_card_deactivate((struct device *)psc); 386 pcmcia_chip_socket_disable(psc->pct, psc->pch); 387 pcmcia_card_detach((struct device *)psc, 388 DETACH_FORCE); 389 } 390 CARDSLOT_SET_CARDTYPE(sc->sc_status, 391 CARDSLOT_STATUS_CARD_NONE); 392 CARDSLOT_SET_WORK(sc->sc_status, 393 CARDSLOT_STATUS_NOTWORK); 394 break; 395 396 default: 397 panic("cardslot_event_thread: unknown event %d", ev); 398 } 399 } 400