1 /* $NetBSD: sbt.c,v 1.2 2009/05/06 08:20:49 cegger Exp $ */ 2 /* $OpenBSD: sbt.c,v 1.9 2007/06/19 07:59:57 uwe Exp $ */ 3 4 /* 5 * Copyright (c) 2007 Uwe Stuehler <uwe@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Driver for Type-A/B SDIO Bluetooth cards */ 21 22 #include <sys/cdefs.h> 23 __KERNEL_RCSID(0, "$NetBSD: sbt.c,v 1.2 2009/05/06 08:20:49 cegger Exp $"); 24 25 #include <sys/param.h> 26 #include <sys/device.h> 27 #include <sys/malloc.h> 28 #include <sys/mbuf.h> 29 #include <sys/proc.h> 30 #include <sys/queue.h> 31 #include <sys/socket.h> 32 #include <sys/systm.h> 33 34 #include <netbt/hci.h> 35 36 #include <dev/sdmmc/sdmmcdevs.h> 37 #include <dev/sdmmc/sdmmcvar.h> 38 39 #define CSR_READ_1(sc, reg) sdmmc_io_read_1((sc)->sc_sf, (reg)) 40 #define CSR_WRITE_1(sc, reg, val) sdmmc_io_write_1((sc)->sc_sf, (reg), (val)) 41 42 #define SBT_REG_DAT 0x00 /* receiver/transmitter data */ 43 #define SBT_REG_RPC 0x10 /* read packet control */ 44 #define RPC_PCRRT (1<<0) /* packet read retry */ 45 #define SBT_REG_WPC 0x11 /* write packet control */ 46 #define WPC_PCWRT (1<<0) /* packet write retry */ 47 #define SBT_REG_RC 0x12 /* retry control status/set */ 48 #define SBT_REG_ISTAT 0x13 /* interrupt status */ 49 #define ISTAT_INTRD (1<<0) /* packet available for read */ 50 #define SBT_REG_ICLR 0x13 /* interrupt clear */ 51 #define SBT_REG_IENA 0x14 /* interrupt enable */ 52 #define SBT_REG_BTMODE 0x20 /* SDIO Bluetooth card mode */ 53 #define BTMODE_TYPEB (1<<0) /* 1=Type-B, 0=Type-A */ 54 55 #define SBT_PKT_BUFSIZ 65540 56 #define SBT_RXTRY_MAX 5 57 58 struct sbt_softc { 59 device_t sc_dev; /* base device */ 60 int sc_flags; 61 struct hci_unit *sc_unit; /* Bluetooth HCI Unit */ 62 struct bt_stats sc_stats; 63 struct sdmmc_function *sc_sf; /* SDIO function */ 64 int sc_dying; /* shutdown in progress */ 65 void *sc_ih; 66 u_char *sc_buf; 67 int sc_rxtry; 68 69 /* transmit queues */ 70 MBUFQ_HEAD() sc_cmdq; 71 MBUFQ_HEAD() sc_aclq; 72 MBUFQ_HEAD() sc_scoq; 73 }; 74 75 /* sc_flags */ 76 #define SBT_XMIT (1 << 0) /* transmit is active */ 77 #define SBT_ENABLED (1 << 1) /* device is enabled */ 78 79 static int sbt_match(device_t, cfdata_t, void *); 80 static void sbt_attach(device_t, device_t, void *); 81 static int sbt_detach(device_t, int); 82 83 CFATTACH_DECL_NEW(sbt, sizeof(struct sbt_softc), 84 sbt_match, sbt_attach, sbt_detach, NULL); 85 86 static int sbt_write_packet(struct sbt_softc *, u_char *, size_t); 87 static int sbt_read_packet(struct sbt_softc *, u_char *, size_t *); 88 static void sbt_start(struct sbt_softc *); 89 90 static int sbt_intr(void *); 91 92 static int sbt_enable(device_t); 93 static void sbt_disable(device_t); 94 static void sbt_start_cmd(device_t, struct mbuf *); 95 static void sbt_start_acl(device_t, struct mbuf *); 96 static void sbt_start_sco(device_t, struct mbuf *); 97 static void sbt_stats(device_t, struct bt_stats *, int); 98 99 #undef DPRINTF /* avoid redefine by bluetooth.h */ 100 #ifdef SBT_DEBUG 101 int sbt_debug = 1; 102 #define DPRINTF(s) printf s 103 #define DNPRINTF(n, s) do { if ((n) <= sbt_debug) printf s; } while (0) 104 #else 105 #define DPRINTF(s) do {} while (0) 106 #define DNPRINTF(n, s) do {} while (0) 107 #endif 108 109 #define DEVNAME(sc) device_xname((sc)->sc_dev) 110 111 112 /* 113 * Autoconf glue 114 */ 115 116 static const struct sbt_product { 117 uint16_t sp_vendor; 118 uint16_t sp_product; 119 const char *sp_cisinfo[4]; 120 } sbt_products[] = { 121 { 122 SDMMC_VENDOR_SOCKETCOM, 123 SDMMC_PRODUCT_SOCKETCOM_BTCARD, 124 SDMMC_CIS_SOCKETCOM_BTCARD 125 }, 126 }; 127 128 static const struct hci_if sbt_hci = { 129 .enable = sbt_enable, 130 .disable = sbt_disable, 131 .output_cmd = sbt_start_cmd, 132 .output_acl = sbt_start_acl, 133 .output_sco = sbt_start_sco, 134 .get_stats = sbt_stats, 135 .ipl = IPL_TTY, /* XXX */ 136 }; 137 138 139 static int 140 sbt_match(device_t parent, cfdata_t match, void *aux) 141 { 142 struct sdmmc_attach_args *sa = aux; 143 const struct sbt_product *sp; 144 struct sdmmc_function *sf; 145 int i; 146 147 if (sa->sf == NULL) 148 return 0; /* not SDIO */ 149 150 sf = sa->sf->sc->sc_fn0; 151 sp = &sbt_products[0]; 152 153 for (i = 0; i < sizeof(sbt_products) / sizeof(sbt_products[0]); 154 i++, sp = &sbt_products[i]) 155 if (sp->sp_vendor == sf->cis.manufacturer && 156 sp->sp_product == sf->cis.product) 157 return 1; 158 return 0; 159 } 160 161 static void 162 sbt_attach(device_t parent, device_t self, void *aux) 163 { 164 struct sbt_softc *sc = device_private(self); 165 struct sdmmc_attach_args *sa = aux; 166 167 aprint_normal("\n"); 168 aprint_naive("\n"); 169 170 sc->sc_dev = self; 171 sc->sc_sf = sa->sf; 172 MBUFQ_INIT(&sc->sc_cmdq); 173 MBUFQ_INIT(&sc->sc_aclq); 174 MBUFQ_INIT(&sc->sc_scoq); 175 176 (void)sdmmc_io_function_disable(sc->sc_sf); 177 if (sdmmc_io_function_enable(sc->sc_sf)) { 178 printf("%s: function not ready\n", DEVNAME(sc)); 179 return; 180 } 181 182 /* It may be Type-B, but we use it only in Type-A mode. */ 183 printf("%s: SDIO Bluetooth Type-A\n", DEVNAME(sc)); 184 185 sc->sc_buf = malloc(SBT_PKT_BUFSIZ, M_DEVBUF, M_NOWAIT | M_CANFAIL); 186 if (sc->sc_buf == NULL) { 187 printf("%s: can't allocate cmd buffer\n", DEVNAME(sc)); 188 return; 189 } 190 191 /* Enable the HCI packet transport read interrupt. */ 192 CSR_WRITE_1(sc, SBT_REG_IENA, ISTAT_INTRD); 193 194 /* Enable the card interrupt for this function. */ 195 sc->sc_ih = sdmmc_intr_establish(parent, sbt_intr, sc, DEVNAME(sc)); 196 if (sc->sc_ih == NULL) { 197 printf("%s: can't establish interrupt\n", DEVNAME(sc)); 198 return; 199 } 200 sdmmc_intr_enable(sc->sc_sf); 201 202 /* 203 * Attach Bluetooth unit (machine-independent HCI). 204 */ 205 sc->sc_unit = hci_attach(&sbt_hci, self, 0); 206 } 207 208 static int 209 sbt_detach(device_t self, int flags) 210 { 211 struct sbt_softc *sc = (struct sbt_softc *)self; 212 213 sc->sc_dying = 1; 214 215 if (sc->sc_unit) { 216 hci_detach(sc->sc_unit); 217 sc->sc_unit = NULL; 218 } 219 220 if (sc->sc_ih != NULL) 221 sdmmc_intr_disestablish(sc->sc_ih); 222 223 return 0; 224 } 225 226 227 /* 228 * Bluetooth HCI packet transport 229 */ 230 231 static int 232 sbt_write_packet(struct sbt_softc *sc, u_char *buf, size_t len) 233 { 234 u_char hdr[3]; 235 size_t pktlen; 236 int error = EIO; 237 int retry = 3; 238 239 again: 240 if (retry-- == 0) { 241 DPRINTF(("%s: sbt_write_cmd: giving up\n", DEVNAME(sc))); 242 return error; 243 } 244 245 /* Restart the current packet. */ 246 sdmmc_io_write_1(sc->sc_sf, SBT_REG_WPC, WPC_PCWRT); 247 248 /* Write the packet length. */ 249 pktlen = len + 3; 250 hdr[0] = pktlen & 0xff; 251 hdr[1] = (pktlen >> 8) & 0xff; 252 hdr[2] = (pktlen >> 16) & 0xff; 253 error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3); 254 if (error) { 255 DPRINTF(("%s: sbt_write_packet: failed to send length\n", 256 DEVNAME(sc))); 257 goto again; 258 } 259 260 error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len); 261 if (error) { 262 DPRINTF(("%s: sbt_write_packet: failed to send packet data\n", 263 DEVNAME(sc))); 264 goto again; 265 } 266 return 0; 267 } 268 269 static int 270 sbt_read_packet(struct sbt_softc *sc, u_char *buf, size_t *lenp) 271 { 272 u_char hdr[3]; 273 size_t len; 274 int error; 275 276 error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3); 277 if (error) { 278 DPRINTF(("%s: sbt_read_packet: failed to read length\n", 279 DEVNAME(sc))); 280 goto out; 281 } 282 len = (hdr[0] | (hdr[1] << 8) | (hdr[2] << 16)) - 3; 283 if (len > *lenp) { 284 DPRINTF(("%s: sbt_read_packet: len %u > %u\n", 285 DEVNAME(sc), len, *lenp)); 286 error = ENOBUFS; 287 goto out; 288 } 289 290 DNPRINTF(2,("%s: sbt_read_packet: reading len %u bytes\n", 291 DEVNAME(sc), len)); 292 error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len); 293 if (error) { 294 DPRINTF(("%s: sbt_read_packet: failed to read packet data\n", 295 DEVNAME(sc))); 296 goto out; 297 } 298 299 out: 300 if (error) { 301 if (sc->sc_rxtry >= SBT_RXTRY_MAX) { 302 /* Drop and request the next packet. */ 303 sc->sc_rxtry = 0; 304 CSR_WRITE_1(sc, SBT_REG_RPC, 0); 305 } else { 306 /* Request the current packet again. */ 307 sc->sc_rxtry++; 308 CSR_WRITE_1(sc, SBT_REG_RPC, RPC_PCRRT); 309 } 310 return error; 311 } 312 313 /* acknowledge read packet */ 314 CSR_WRITE_1(sc, SBT_REG_RPC, 0); 315 316 *lenp = len; 317 return 0; 318 } 319 320 /* 321 * Interrupt handling 322 */ 323 324 static int 325 sbt_intr(void *arg) 326 { 327 struct sbt_softc *sc = arg; 328 struct mbuf *m = NULL; 329 u_int8_t status; 330 size_t len; 331 int s; 332 333 s = splsdmmc(); 334 335 status = CSR_READ_1(sc, SBT_REG_ISTAT); 336 CSR_WRITE_1(sc, SBT_REG_ICLR, status); 337 338 if ((status & ISTAT_INTRD) == 0) 339 return 0; /* shared SDIO card interrupt? */ 340 341 len = SBT_PKT_BUFSIZ; 342 if (sbt_read_packet(sc, sc->sc_buf, &len) != 0 || len == 0) { 343 DPRINTF(("%s: sbt_intr: read failed\n", DEVNAME(sc))); 344 goto eoi; 345 } 346 347 MGETHDR(m, M_DONTWAIT, MT_DATA); 348 if (m == NULL) { 349 DPRINTF(("%s: sbt_intr: MGETHDR failed\n", DEVNAME(sc))); 350 goto eoi; 351 } 352 353 m->m_pkthdr.len = m->m_len = MHLEN; 354 m_copyback(m, 0, len, sc->sc_buf); 355 if (m->m_pkthdr.len == MAX(MHLEN, len)) { 356 m->m_pkthdr.len = len; 357 m->m_len = MIN(MHLEN, m->m_pkthdr.len); 358 } else { 359 DPRINTF(("%s: sbt_intr: m_copyback failed\n", DEVNAME(sc))); 360 m_free(m); 361 m = NULL; 362 } 363 364 eoi: 365 if (m != NULL) { 366 switch (sc->sc_buf[0]) { 367 case HCI_ACL_DATA_PKT: 368 DNPRINTF(1,("%s: recv ACL packet (%d bytes)\n", 369 DEVNAME(sc), m->m_pkthdr.len)); 370 hci_input_acl(sc->sc_unit, m); 371 break; 372 case HCI_SCO_DATA_PKT: 373 DNPRINTF(1,("%s: recv SCO packet (%d bytes)\n", 374 DEVNAME(sc), m->m_pkthdr.len)); 375 hci_input_sco(sc->sc_unit, m); 376 break; 377 case HCI_EVENT_PKT: 378 DNPRINTF(1,("%s: recv EVENT packet (%d bytes)\n", 379 DEVNAME(sc), m->m_pkthdr.len)); 380 hci_input_event(sc->sc_unit, m); 381 break; 382 default: 383 DPRINTF(("%s: recv 0x%x packet (%d bytes)\n", 384 DEVNAME(sc), sc->sc_buf[0], m->m_pkthdr.len)); 385 sc->sc_stats.err_rx++; 386 m_free(m); 387 break; 388 } 389 } else 390 sc->sc_stats.err_rx++; 391 392 splx(s); 393 394 /* Claim this interrupt. */ 395 return 1; 396 } 397 398 399 /* 400 * Bluetooth HCI unit functions 401 */ 402 403 static int 404 sbt_enable(device_t self) 405 { 406 struct sbt_softc *sc = device_private(self); 407 int s; 408 409 if (sc->sc_flags & SBT_ENABLED) 410 return 0; 411 412 s = spltty(); 413 414 sc->sc_flags |= SBT_ENABLED; 415 sc->sc_flags &= ~SBT_XMIT; 416 417 splx(s); 418 419 return 0; 420 } 421 422 static void 423 sbt_disable(device_t self) 424 { 425 struct sbt_softc *sc = device_private(self); 426 int s; 427 428 if (!(sc->sc_flags & SBT_ENABLED)) 429 return; 430 431 s = spltty(); 432 433 #ifdef notyet /* XXX */ 434 if (sc->sc_rxp) { 435 m_freem(sc->sc_rxp); 436 sc->sc_rxp = NULL; 437 } 438 439 if (sc->sc_txp) { 440 m_freem(sc->sc_txp); 441 sc->sc_txp = NULL; 442 } 443 #endif 444 445 MBUFQ_DRAIN(&sc->sc_cmdq); 446 MBUFQ_DRAIN(&sc->sc_aclq); 447 MBUFQ_DRAIN(&sc->sc_scoq); 448 449 sc->sc_flags &= ~SBT_ENABLED; 450 451 splx(s); 452 } 453 454 static void 455 sbt_start(struct sbt_softc *sc) 456 { 457 struct mbuf *m; 458 int len; 459 #ifdef SBT_DEBUG 460 const char *what; 461 #endif 462 463 KASSERT((sc->sc_flags & SBT_XMIT) == 0); 464 465 if (sc->sc_dying) 466 return; 467 468 if (MBUFQ_FIRST(&sc->sc_cmdq)) { 469 MBUFQ_DEQUEUE(&sc->sc_cmdq, m); 470 sc->sc_stats.cmd_tx++; 471 #ifdef SBT_DEBUG 472 what = "CMD"; 473 #endif 474 goto start; 475 } 476 477 if (MBUFQ_FIRST(&sc->sc_scoq)) { 478 MBUFQ_DEQUEUE(&sc->sc_scoq, m); 479 sc->sc_stats.sco_tx++; 480 #ifdef SBT_DEBUG 481 what = "SCO"; 482 #endif 483 goto start; 484 } 485 486 if (MBUFQ_FIRST(&sc->sc_aclq)) { 487 MBUFQ_DEQUEUE(&sc->sc_aclq, m); 488 sc->sc_stats.acl_tx++; 489 #ifdef SBT_DEBUG 490 what = "ACL"; 491 #endif 492 goto start; 493 } 494 495 /* Nothing to send */ 496 return; 497 498 start: 499 DNPRINTF(1,("%s: xmit %s packet (%d bytes)\n", DEVNAME(sc), 500 what, m->m_pkthdr.len)); 501 502 sc->sc_flags |= SBT_XMIT; 503 504 len = m->m_pkthdr.len; 505 m_copydata(m, 0, len, sc->sc_buf); 506 m_freem(m); 507 508 if (sbt_write_packet(sc, sc->sc_buf, len)) 509 DPRINTF(("%s: sbt_write_packet failed\n", DEVNAME(sc))); 510 511 sc->sc_flags &= ~SBT_XMIT; 512 } 513 514 static void 515 sbt_start_cmd(device_t self, struct mbuf *m) 516 { 517 struct sbt_softc *sc = device_private(self); 518 int s; 519 520 KASSERT(sc->sc_flags & SBT_ENABLED); 521 522 M_SETCTX(m, NULL); 523 524 s = spltty(); 525 526 MBUFQ_ENQUEUE(&sc->sc_cmdq, m); 527 if ((sc->sc_flags & SBT_XMIT) == 0) 528 sbt_start(sc); 529 530 splx(s); 531 } 532 533 static void 534 sbt_start_acl(device_t self, struct mbuf *m) 535 { 536 struct sbt_softc *sc = device_private(self); 537 int s; 538 539 KASSERT(sc->sc_flags & SBT_ENABLED); 540 541 M_SETCTX(m, NULL); 542 543 s = spltty(); 544 545 MBUFQ_ENQUEUE(&sc->sc_aclq, m); 546 if ((sc->sc_flags & SBT_XMIT) == 0) 547 sbt_start(sc); 548 549 splx(s); 550 } 551 552 static void 553 sbt_start_sco(device_t self, struct mbuf *m) 554 { 555 struct sbt_softc *sc = device_private(self); 556 int s; 557 558 KASSERT(sc->sc_flags & SBT_ENABLED); 559 560 s = spltty(); 561 562 MBUFQ_ENQUEUE(&sc->sc_scoq, m); 563 if ((sc->sc_flags & SBT_XMIT) == 0) 564 sbt_start(sc); 565 566 splx(s); 567 } 568 569 static void 570 sbt_stats(device_t self, struct bt_stats *dest, int flush) 571 { 572 struct sbt_softc *sc = device_private(self); 573 int s; 574 575 s = spltty(); 576 577 memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats)); 578 579 if (flush) 580 memset(&sc->sc_stats, 0, sizeof(struct bt_stats)); 581 582 splx(s); 583 } 584