1 /* 2 * ng_bt3c_pccard.c 3 */ 4 5 /*- 6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $Id: ng_bt3c_pccard.c,v 1.5 2003/04/01 18:15:21 max Exp $ 31 * $FreeBSD: src/sys/netgraph/bluetooth/drivers/bt3c/ng_bt3c_pccard.c,v 1.20 2007/02/23 12:19:02 piso Exp $ 32 * $DragonFly: src/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_pccard.c,v 1.2 2008/06/26 23:05:40 dillon Exp $ 33 * $DragonFly: src/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_pccard.c,v 1.2 2008/06/26 23:05:40 dillon Exp $ 34 * 35 * XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX 36 * 37 * Based on information obrained from: Jose Orlando Pereira <jop@di.uminho.pt> 38 * and disassembled w2k driver. 39 * 40 * XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX 41 * 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 47 #include <sys/bus.h> 48 #include <machine/bus.h> 49 50 #include <sys/conf.h> 51 #include <sys/endian.h> 52 #include <sys/interrupt.h> 53 #include <sys/kernel.h> 54 #include <sys/mbuf.h> 55 #include <sys/module.h> 56 57 #include <machine/resource.h> 58 #include <sys/rman.h> 59 60 #include <sys/socket.h> 61 #include <net/if.h> 62 #include <net/if_var.h> 63 64 #include <dev/pccard/pccardreg.h> 65 #include <dev/pccard/pccardvar.h> 66 #include "pccarddevs.h" 67 68 #include "ng_message.h" 69 #include "netgraph.h" 70 #include "ng_parse.h" 71 #include "bluetooth/include/ng_bluetooth.h" 72 #include "bluetooth/include/ng_hci.h" 73 #include "bluetooth/include/ng_bt3c.h" 74 #include "bluetooth/drivers/bt3c/ng_bt3c_var.h" 75 76 /* Netgraph methods */ 77 static ng_constructor_t ng_bt3c_constructor; 78 static ng_shutdown_t ng_bt3c_shutdown; 79 static ng_newhook_t ng_bt3c_newhook; 80 static ng_connect_t ng_bt3c_connect; 81 static ng_disconnect_t ng_bt3c_disconnect; 82 static ng_rcvmsg_t ng_bt3c_rcvmsg; 83 static ng_rcvdata_t ng_bt3c_rcvdata; 84 85 /* PCMCIA driver methods */ 86 static int bt3c_pccard_probe (device_t); 87 static int bt3c_pccard_attach (device_t); 88 static int bt3c_pccard_detach (device_t); 89 90 static void bt3c_intr (void *); 91 static void bt3c_receive (bt3c_softc_p); 92 93 static void bt3c_swi_intr (void *); 94 static void bt3c_forward (node_p, hook_p, void *, int); 95 static void bt3c_send (node_p, hook_p, void *, int); 96 97 static void bt3c_download_firmware (bt3c_softc_p, char const *, int); 98 99 #define bt3c_set_address(sc, address) \ 100 do { \ 101 bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_ADDR_L, ((address) & 0xff)); \ 102 bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_ADDR_H, (((address) >> 8) & 0xff)); \ 103 } while (0) 104 105 #define bt3c_read_data(sc, data) \ 106 do { \ 107 (data) = bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_DATA_L); \ 108 (data) |= ((bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_DATA_H) & 0xff) << 8); \ 109 } while (0) 110 111 #define bt3c_write_data(sc, data) \ 112 do { \ 113 bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_DATA_L, ((data) & 0xff)); \ 114 bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_DATA_H, (((data) >> 8) & 0xff)); \ 115 } while (0) 116 117 #define bt3c_read_control(sc, data) \ 118 do { \ 119 (data) = bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_CONTROL); \ 120 } while (0) 121 122 #define bt3c_write_control(sc, data) \ 123 do { \ 124 bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_CONTROL, (data)); \ 125 } while (0) 126 127 #define bt3c_read(sc, address, data) \ 128 do { \ 129 bt3c_set_address((sc), (address)); \ 130 bt3c_read_data((sc), (data)); \ 131 } while(0) 132 133 #define bt3c_write(sc, address, data) \ 134 do { \ 135 bt3c_set_address((sc), (address)); \ 136 bt3c_write_data((sc), (data)); \ 137 } while(0) 138 139 static MALLOC_DEFINE(M_BT3C, "bt3c", "bt3c data structures"); 140 141 /**************************************************************************** 142 **************************************************************************** 143 ** Netgraph specific 144 **************************************************************************** 145 ****************************************************************************/ 146 147 /* 148 * Netgraph node type 149 */ 150 151 /* Queue length */ 152 static const struct ng_parse_struct_field ng_bt3c_node_qlen_type_fields[] = 153 { 154 { "queue", &ng_parse_int32_type, }, 155 { "qlen", &ng_parse_int32_type, }, 156 { NULL, } 157 }; 158 static const struct ng_parse_type ng_bt3c_node_qlen_type = { 159 &ng_parse_struct_type, 160 &ng_bt3c_node_qlen_type_fields 161 }; 162 163 /* Stat info */ 164 static const struct ng_parse_struct_field ng_bt3c_node_stat_type_fields[] = 165 { 166 { "pckts_recv", &ng_parse_uint32_type, }, 167 { "bytes_recv", &ng_parse_uint32_type, }, 168 { "pckts_sent", &ng_parse_uint32_type, }, 169 { "bytes_sent", &ng_parse_uint32_type, }, 170 { "oerrors", &ng_parse_uint32_type, }, 171 { "ierrors", &ng_parse_uint32_type, }, 172 { NULL, } 173 }; 174 static const struct ng_parse_type ng_bt3c_node_stat_type = { 175 &ng_parse_struct_type, 176 &ng_bt3c_node_stat_type_fields 177 }; 178 179 static const struct ng_cmdlist ng_bt3c_cmdlist[] = { 180 { 181 NGM_BT3C_COOKIE, 182 NGM_BT3C_NODE_GET_STATE, 183 "get_state", 184 NULL, 185 &ng_parse_uint16_type 186 }, 187 { 188 NGM_BT3C_COOKIE, 189 NGM_BT3C_NODE_SET_DEBUG, 190 "set_debug", 191 &ng_parse_uint16_type, 192 NULL 193 }, 194 { 195 NGM_BT3C_COOKIE, 196 NGM_BT3C_NODE_GET_DEBUG, 197 "get_debug", 198 NULL, 199 &ng_parse_uint16_type 200 }, 201 { 202 NGM_BT3C_COOKIE, 203 NGM_BT3C_NODE_GET_QLEN, 204 "get_qlen", 205 NULL, 206 &ng_bt3c_node_qlen_type 207 }, 208 { 209 NGM_BT3C_COOKIE, 210 NGM_BT3C_NODE_SET_QLEN, 211 "set_qlen", 212 &ng_bt3c_node_qlen_type, 213 NULL 214 }, 215 { 216 NGM_BT3C_COOKIE, 217 NGM_BT3C_NODE_GET_STAT, 218 "get_stat", 219 NULL, 220 &ng_bt3c_node_stat_type 221 }, 222 { 223 NGM_BT3C_COOKIE, 224 NGM_BT3C_NODE_RESET_STAT, 225 "reset_stat", 226 NULL, 227 NULL 228 }, 229 { 0, } 230 }; 231 232 static struct ng_type typestruct = { 233 .version = NG_ABI_VERSION, 234 .name = NG_BT3C_NODE_TYPE, 235 .constructor = ng_bt3c_constructor, 236 .rcvmsg = ng_bt3c_rcvmsg, 237 .shutdown = ng_bt3c_shutdown, 238 .newhook = ng_bt3c_newhook, 239 .connect = ng_bt3c_connect, 240 .rcvdata = ng_bt3c_rcvdata, 241 .disconnect = ng_bt3c_disconnect, 242 .cmdlist = ng_bt3c_cmdlist 243 }; 244 245 /* 246 * Netgraph node constructor. Do not allow to create node of this type. 247 */ 248 249 static int 250 ng_bt3c_constructor(node_p node) 251 { 252 return (EINVAL); 253 } /* ng_bt3c_constructor */ 254 255 /* 256 * Netgraph node destructor. Destroy node only when device has been detached 257 */ 258 259 static int 260 ng_bt3c_shutdown(node_p node) 261 { 262 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); 263 264 /* Let old node go */ 265 NG_NODE_SET_PRIVATE(node, NULL); 266 NG_NODE_UNREF(node); 267 268 /* Create new fresh one if we are not going down */ 269 if (sc == NULL) 270 goto out; 271 272 /* Create new Netgraph node */ 273 if (ng_make_node_common(&typestruct, &sc->node) != 0) { 274 device_printf(sc->dev, "Could not create Netgraph node\n"); 275 sc->node = NULL; 276 goto out; 277 } 278 279 /* Name new Netgraph node */ 280 if (ng_name_node(sc->node, device_get_nameunit(sc->dev)) != 0) { 281 device_printf(sc->dev, "Could not name Netgraph node\n"); 282 NG_NODE_UNREF(sc->node); 283 sc->node = NULL; 284 goto out; 285 } 286 287 NG_NODE_SET_PRIVATE(sc->node, sc); 288 out: 289 return (0); 290 } /* ng_bt3c_shutdown */ 291 292 /* 293 * Create new hook. There can only be one. 294 */ 295 296 static int 297 ng_bt3c_newhook(node_p node, hook_p hook, char const *name) 298 { 299 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); 300 301 if (strcmp(name, NG_BT3C_HOOK) != 0) 302 return (EINVAL); 303 304 if (sc->hook != NULL) 305 return (EISCONN); 306 307 sc->hook = hook; 308 309 return (0); 310 } /* ng_bt3c_newhook */ 311 312 /* 313 * Connect hook. Say YEP, that's OK with me. 314 */ 315 316 static int 317 ng_bt3c_connect(hook_p hook) 318 { 319 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 320 321 if (hook != sc->hook) { 322 sc->hook = NULL; 323 return (EINVAL); 324 } 325 326 /* set the hook into queueing mode (for incoming (from wire) packets) */ 327 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 328 329 return (0); 330 } /* ng_bt3c_connect */ 331 332 /* 333 * Disconnect hook 334 */ 335 336 static int 337 ng_bt3c_disconnect(hook_p hook) 338 { 339 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 340 341 /* 342 * We need to check for sc != NULL because we can be called from 343 * bt3c_pccard_detach() via ng_rmnode_self() 344 */ 345 346 if (sc != NULL) { 347 if (hook != sc->hook) 348 return (EINVAL); 349 350 IF_DRAIN(&sc->inq); 351 IF_DRAIN(&sc->outq); 352 353 sc->hook = NULL; 354 } 355 356 return (0); 357 } /* ng_bt3c_disconnect */ 358 359 /* 360 * Process control message 361 */ 362 363 static int 364 ng_bt3c_rcvmsg(node_p node, item_p item, hook_p lasthook) 365 { 366 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); 367 struct ng_mesg *msg = NULL, *rsp = NULL; 368 int error = 0; 369 370 if (sc == NULL) { 371 NG_FREE_ITEM(item); 372 return (EHOSTDOWN); 373 } 374 375 NGI_GET_MSG(item, msg); 376 377 switch (msg->header.typecookie) { 378 case NGM_GENERIC_COOKIE: 379 switch (msg->header.cmd) { 380 case NGM_TEXT_STATUS: 381 NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_WAITOK | M_NULLOK); 382 if (rsp == NULL) 383 error = ENOMEM; 384 else 385 snprintf(rsp->data, NG_TEXTRESPONSE, 386 "Hook: %s\n" \ 387 "Flags: %#x\n" \ 388 "Debug: %d\n" \ 389 "State: %d\n" \ 390 "IncmQ: [len:%d,max:%d]\n" \ 391 "OutgQ: [len:%d,max:%d]\n", 392 (sc->hook != NULL)? NG_BT3C_HOOK : "", 393 sc->flags, 394 sc->debug, 395 sc->state, 396 _IF_QLEN(&sc->inq), /* XXX */ 397 sc->inq.ifq_maxlen, /* XXX */ 398 _IF_QLEN(&sc->outq), /* XXX */ 399 sc->outq.ifq_maxlen /* XXX */ 400 ); 401 break; 402 403 default: 404 error = EINVAL; 405 break; 406 } 407 break; 408 409 case NGM_BT3C_COOKIE: 410 switch (msg->header.cmd) { 411 case NGM_BT3C_NODE_GET_STATE: 412 NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_state_ep), 413 M_WAITOK | M_NULLOK); 414 if (rsp == NULL) 415 error = ENOMEM; 416 else 417 *((ng_bt3c_node_state_ep *)(rsp->data)) = 418 sc->state; 419 break; 420 421 case NGM_BT3C_NODE_SET_DEBUG: 422 if (msg->header.arglen != sizeof(ng_bt3c_node_debug_ep)) 423 error = EMSGSIZE; 424 else 425 sc->debug = 426 *((ng_bt3c_node_debug_ep *)(msg->data)); 427 break; 428 429 case NGM_BT3C_NODE_GET_DEBUG: 430 NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_debug_ep), 431 M_WAITOK | M_NULLOK); 432 if (rsp == NULL) 433 error = ENOMEM; 434 else 435 *((ng_bt3c_node_debug_ep *)(rsp->data)) = 436 sc->debug; 437 break; 438 439 case NGM_BT3C_NODE_GET_QLEN: 440 NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_qlen_ep), 441 M_WAITOK | M_NULLOK); 442 if (rsp == NULL) { 443 error = ENOMEM; 444 break; 445 } 446 447 switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) { 448 case NGM_BT3C_NODE_IN_QUEUE: 449 ((ng_bt3c_node_qlen_ep *)(rsp->data))->queue = 450 NGM_BT3C_NODE_IN_QUEUE; 451 ((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen = 452 sc->inq.ifq_maxlen; 453 break; 454 455 case NGM_BT3C_NODE_OUT_QUEUE: 456 ((ng_bt3c_node_qlen_ep *)(rsp->data))->queue = 457 NGM_BT3C_NODE_OUT_QUEUE; 458 ((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen = 459 sc->outq.ifq_maxlen; 460 break; 461 462 default: 463 NG_FREE_MSG(rsp); 464 error = EINVAL; 465 break; 466 } 467 break; 468 469 case NGM_BT3C_NODE_SET_QLEN: 470 if (msg->header.arglen != sizeof(ng_bt3c_node_qlen_ep)){ 471 error = EMSGSIZE; 472 break; 473 } 474 475 if (((ng_bt3c_node_qlen_ep *)(msg->data))->qlen <= 0) { 476 error = EINVAL; 477 break; 478 } 479 480 switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) { 481 case NGM_BT3C_NODE_IN_QUEUE: 482 sc->inq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *) 483 (msg->data))->qlen; /* XXX */ 484 break; 485 486 case NGM_BT3C_NODE_OUT_QUEUE: 487 sc->outq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *) 488 (msg->data))->qlen; /* XXX */ 489 break; 490 491 default: 492 error = EINVAL; 493 break; 494 } 495 break; 496 497 case NGM_BT3C_NODE_GET_STAT: 498 NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_stat_ep), 499 M_WAITOK | M_NULLOK); 500 if (rsp == NULL) 501 error = ENOMEM; 502 else 503 bcopy(&sc->stat, rsp->data, 504 sizeof(ng_bt3c_node_stat_ep)); 505 break; 506 507 case NGM_BT3C_NODE_RESET_STAT: 508 NG_BT3C_STAT_RESET(sc->stat); 509 break; 510 511 case NGM_BT3C_NODE_DOWNLOAD_FIRMWARE: 512 if (msg->header.arglen < 513 sizeof(ng_bt3c_firmware_block_ep)) 514 error = EMSGSIZE; 515 else 516 bt3c_download_firmware(sc, msg->data, 517 msg->header.arglen); 518 break; 519 520 default: 521 error = EINVAL; 522 break; 523 } 524 break; 525 526 default: 527 error = EINVAL; 528 break; 529 } 530 531 NG_RESPOND_MSG(error, node, item, rsp); 532 NG_FREE_MSG(msg); 533 534 return (error); 535 } /* ng_bt3c_rcvmsg */ 536 537 /* 538 * Process data 539 */ 540 541 static int 542 ng_bt3c_rcvdata(hook_p hook, item_p item) 543 { 544 bt3c_softc_p sc = (bt3c_softc_p)NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 545 struct mbuf *m = NULL; 546 int error = 0; 547 548 if (sc == NULL) { 549 error = EHOSTDOWN; 550 goto out; 551 } 552 553 if (hook != sc->hook) { 554 error = EINVAL; 555 goto out; 556 } 557 558 NGI_GET_M(item, m); 559 560 IF_LOCK(&sc->outq); 561 if (_IF_QFULL(&sc->outq)) { 562 NG_BT3C_ERR(sc->dev, 563 "Outgoing queue is full. Dropping mbuf, len=%d\n", m->m_pkthdr.len); 564 565 _IF_DROP(&sc->outq); 566 NG_BT3C_STAT_OERROR(sc->stat); 567 568 NG_FREE_M(m); 569 } else 570 _IF_ENQUEUE(&sc->outq, m); 571 IF_UNLOCK(&sc->outq); 572 573 error = ng_send_fn(sc->node, NULL, bt3c_send, NULL, 0 /* new send */); 574 out: 575 NG_FREE_ITEM(item); 576 577 return (error); 578 } /* ng_bt3c_rcvdata */ 579 580 /**************************************************************************** 581 **************************************************************************** 582 ** PCMCIA driver specific 583 **************************************************************************** 584 ****************************************************************************/ 585 586 /* 587 * PC Card (PCMCIA) probe routine 588 */ 589 590 static int 591 bt3c_pccard_probe(device_t dev) 592 { 593 static struct pccard_product const bt3c_pccard_products[] = { 594 PCMCIA_CARD(3COM, 3CRWB609), 595 { NULL, } 596 }; 597 598 struct pccard_product const *pp = NULL; 599 600 pp = pccard_product_lookup(dev, bt3c_pccard_products, 601 sizeof(bt3c_pccard_products[0]), NULL); 602 if (pp == NULL) 603 return (ENXIO); 604 605 device_set_desc(dev, pp->pp_name); 606 607 return (0); 608 } /* bt3c_pccard_probe */ 609 610 /* 611 * PC Card (PCMCIA) attach routine 612 */ 613 614 static int 615 bt3c_pccard_attach(device_t dev) 616 { 617 bt3c_softc_p sc = (bt3c_softc_p) device_get_softc(dev); 618 619 /* Allocate I/O ports */ 620 sc->iobase_rid = 0; 621 sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iobase_rid, 622 0, ~0, 8, RF_ACTIVE); 623 if (sc->iobase == NULL) { 624 device_printf(dev, "Could not allocate I/O ports\n"); 625 goto bad; 626 } 627 sc->iot = rman_get_bustag(sc->iobase); 628 sc->ioh = rman_get_bushandle(sc->iobase); 629 630 /* Allocate IRQ */ 631 sc->irq_rid = 0; 632 sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 633 RF_ACTIVE); 634 if (sc->irq == NULL) { 635 device_printf(dev, "Could not allocate IRQ\n"); 636 goto bad; 637 } 638 639 sc->irq_cookie = NULL; 640 if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, NULL, bt3c_intr, sc, 641 &sc->irq_cookie) != 0) { 642 device_printf(dev, "Could not setup ISR\n"); 643 goto bad; 644 } 645 646 /* Attach handler to TTY SWI thread */ 647 sc->ith = NULL; 648 if (swi_add(&tty_intr_event, device_get_nameunit(dev), 649 bt3c_swi_intr, sc, SWI_TTY, 0, &sc->ith) < 0) { 650 device_printf(dev, "Could not setup SWI ISR\n"); 651 goto bad; 652 } 653 654 /* Create Netgraph node */ 655 if (ng_make_node_common(&typestruct, &sc->node) != 0) { 656 device_printf(dev, "Could not create Netgraph node\n"); 657 sc->node = NULL; 658 goto bad; 659 } 660 661 /* Name Netgraph node */ 662 if (ng_name_node(sc->node, device_get_nameunit(dev)) != 0) { 663 device_printf(dev, "Could not name Netgraph node\n"); 664 NG_NODE_UNREF(sc->node); 665 sc->node = NULL; 666 goto bad; 667 } 668 669 sc->dev = dev; 670 sc->debug = NG_BT3C_WARN_LEVEL; 671 672 sc->inq.ifq_maxlen = sc->outq.ifq_maxlen = BT3C_DEFAULTQLEN; 673 mtx_init(&sc->inq.ifq_mtx, "BT3C inq", NULL, MTX_DEF); 674 mtx_init(&sc->outq.ifq_mtx, "BT3C outq", NULL, MTX_DEF); 675 676 sc->state = NG_BT3C_W4_PKT_IND; 677 sc->want = 1; 678 679 NG_NODE_SET_PRIVATE(sc->node, sc); 680 681 return (0); 682 bad: 683 if (sc->ith != NULL) { 684 swi_remove(sc->ith); 685 sc->ith = NULL; 686 } 687 688 if (sc->irq != NULL) { 689 if (sc->irq_cookie != NULL) 690 bus_teardown_intr(dev, sc->irq, sc->irq_cookie); 691 692 bus_release_resource(dev, SYS_RES_IRQ, 693 sc->irq_rid, sc->irq); 694 695 sc->irq = NULL; 696 sc->irq_rid = 0; 697 } 698 699 if (sc->iobase != NULL) { 700 bus_release_resource(dev, SYS_RES_IOPORT, 701 sc->iobase_rid, sc->iobase); 702 703 sc->iobase = NULL; 704 sc->iobase_rid = 0; 705 } 706 707 return (ENXIO); 708 } /* bt3c_pccacd_attach */ 709 710 /* 711 * PC Card (PCMCIA) detach routine 712 */ 713 714 static int 715 bt3c_pccard_detach(device_t dev) 716 { 717 bt3c_softc_p sc = (bt3c_softc_p) device_get_softc(dev); 718 719 if (sc == NULL) 720 return (0); 721 722 swi_remove(sc->ith); 723 sc->ith = NULL; 724 725 bus_teardown_intr(dev, sc->irq, sc->irq_cookie); 726 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); 727 sc->irq_cookie = NULL; 728 sc->irq = NULL; 729 sc->irq_rid = 0; 730 731 bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase); 732 sc->iobase = NULL; 733 sc->iobase_rid = 0; 734 735 if (sc->node != NULL) { 736 NG_NODE_SET_PRIVATE(sc->node, NULL); 737 ng_rmnode_self(sc->node); 738 sc->node = NULL; 739 } 740 741 NG_FREE_M(sc->m); 742 IF_DRAIN(&sc->inq); 743 IF_DRAIN(&sc->outq); 744 745 mtx_destroy(&sc->inq.ifq_mtx); 746 mtx_destroy(&sc->outq.ifq_mtx); 747 748 return (0); 749 } /* bt3c_pccacd_detach */ 750 751 /* 752 * Interrupt service routine's 753 */ 754 755 static void 756 bt3c_intr(void *context) 757 { 758 bt3c_softc_p sc = (bt3c_softc_p) context; 759 u_int16_t control, status; 760 761 if (sc == NULL || sc->ith == NULL) { 762 printf("%s: bogus interrupt\n", NG_BT3C_NODE_TYPE); 763 return; 764 } 765 766 bt3c_read_control(sc, control); 767 if ((control & 0x80) == 0) 768 return; 769 770 bt3c_read(sc, 0x7001, status); 771 NG_BT3C_INFO(sc->dev, "control=%#x, status=%#x\n", control, status); 772 773 if ((status & 0xff) == 0x7f || (status & 0xff) == 0xff) { 774 NG_BT3C_WARN(sc->dev, "Strange status=%#x\n", status); 775 return; 776 } 777 778 /* Receive complete */ 779 if (status & 0x0001) 780 bt3c_receive(sc); 781 782 /* Record status and schedule SWI */ 783 sc->status |= status; 784 swi_sched(sc->ith, 0); 785 786 /* Complete interrupt */ 787 bt3c_write(sc, 0x7001, 0x0000); 788 bt3c_write_control(sc, control); 789 } /* bt3c_intr */ 790 791 /* 792 * Receive data 793 */ 794 795 static void 796 bt3c_receive(bt3c_softc_p sc) 797 { 798 u_int16_t i, count, c; 799 800 /* Receive data from the card */ 801 bt3c_read(sc, 0x7006, count); 802 NG_BT3C_INFO(sc->dev, "The card has %d characters\n", count); 803 804 bt3c_set_address(sc, 0x7480); 805 806 for (i = 0; i < count; i++) { 807 /* Allocate new mbuf if needed */ 808 if (sc->m == NULL) { 809 sc->state = NG_BT3C_W4_PKT_IND; 810 sc->want = 1; 811 812 MGETHDR(sc->m, MB_DONTWAIT, MT_DATA); 813 if (sc->m == NULL) { 814 NG_BT3C_ERR(sc->dev, "Could not get mbuf\n"); 815 NG_BT3C_STAT_IERROR(sc->stat); 816 817 break; /* XXX lost of sync */ 818 } 819 820 MCLGET(sc->m, MB_DONTWAIT); 821 if (!(sc->m->m_flags & M_EXT)) { 822 NG_FREE_M(sc->m); 823 824 NG_BT3C_ERR(sc->dev, "Could not get cluster\n"); 825 NG_BT3C_STAT_IERROR(sc->stat); 826 827 break; /* XXX lost of sync */ 828 } 829 830 sc->m->m_len = sc->m->m_pkthdr.len = 0; 831 } 832 833 /* Read and append character to mbuf */ 834 bt3c_read_data(sc, c); 835 if (sc->m->m_pkthdr.len >= MCLBYTES) { 836 NG_BT3C_ERR(sc->dev, "Oversized frame\n"); 837 838 NG_FREE_M(sc->m); 839 sc->state = NG_BT3C_W4_PKT_IND; 840 sc->want = 1; 841 842 break; /* XXX lost of sync */ 843 } 844 845 mtod(sc->m, u_int8_t *)[sc->m->m_len ++] = (u_int8_t) c; 846 sc->m->m_pkthdr.len ++; 847 848 NG_BT3C_INFO(sc->dev, 849 "Got char %#x, want=%d, got=%d\n", c, sc->want, sc->m->m_pkthdr.len); 850 851 if (sc->m->m_pkthdr.len < sc->want) 852 continue; /* wait for more */ 853 854 switch (sc->state) { 855 /* Got packet indicator */ 856 case NG_BT3C_W4_PKT_IND: 857 NG_BT3C_INFO(sc->dev, 858 "Got packet indicator %#x\n", *mtod(sc->m, u_int8_t *)); 859 860 sc->state = NG_BT3C_W4_PKT_HDR; 861 862 /* 863 * Since packet indicator included in the packet 864 * header just set sc->want to sizeof(packet header). 865 */ 866 867 switch (*mtod(sc->m, u_int8_t *)) { 868 case NG_HCI_ACL_DATA_PKT: 869 sc->want = sizeof(ng_hci_acldata_pkt_t); 870 break; 871 872 case NG_HCI_SCO_DATA_PKT: 873 sc->want = sizeof(ng_hci_scodata_pkt_t); 874 break; 875 876 case NG_HCI_EVENT_PKT: 877 sc->want = sizeof(ng_hci_event_pkt_t); 878 break; 879 880 default: 881 NG_BT3C_ERR(sc->dev, 882 "Ignoring unknown packet type=%#x\n", *mtod(sc->m, u_int8_t *)); 883 884 NG_BT3C_STAT_IERROR(sc->stat); 885 886 NG_FREE_M(sc->m); 887 sc->state = NG_BT3C_W4_PKT_IND; 888 sc->want = 1; 889 break; 890 } 891 break; 892 893 /* Got packet header */ 894 case NG_BT3C_W4_PKT_HDR: 895 sc->state = NG_BT3C_W4_PKT_DATA; 896 897 switch (*mtod(sc->m, u_int8_t *)) { 898 case NG_HCI_ACL_DATA_PKT: 899 c = le16toh(mtod(sc->m, 900 ng_hci_acldata_pkt_t *)->length); 901 break; 902 903 case NG_HCI_SCO_DATA_PKT: 904 c = mtod(sc->m, ng_hci_scodata_pkt_t*)->length; 905 break; 906 907 case NG_HCI_EVENT_PKT: 908 c = mtod(sc->m, ng_hci_event_pkt_t *)->length; 909 break; 910 911 default: 912 KASSERT(0, 913 ("Invalid packet type=%#x\n", *mtod(sc->m, u_int8_t *))); 914 break; 915 } 916 917 NG_BT3C_INFO(sc->dev, 918 "Got packet header, packet type=%#x, got so far %d, payload size=%d\n", 919 *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len, 920 c); 921 922 if (c > 0) { 923 sc->want += c; 924 break; 925 } 926 927 /* else FALLTHROUGH and deliver frame */ 928 /* XXX is this true? should we deliver empty frame? */ 929 930 /* Got packet data */ 931 case NG_BT3C_W4_PKT_DATA: 932 NG_BT3C_INFO(sc->dev, 933 "Got full packet, packet type=%#x, packet size=%d\n", 934 *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len); 935 936 NG_BT3C_STAT_BYTES_RECV(sc->stat, sc->m->m_pkthdr.len); 937 NG_BT3C_STAT_PCKTS_RECV(sc->stat); 938 939 IF_LOCK(&sc->inq); 940 if (_IF_QFULL(&sc->inq)) { 941 NG_BT3C_ERR(sc->dev, 942 "Incoming queue is full. Dropping mbuf, len=%d\n", sc->m->m_pkthdr.len); 943 944 _IF_DROP(&sc->inq); 945 NG_BT3C_STAT_IERROR(sc->stat); 946 947 NG_FREE_M(sc->m); 948 } else { 949 _IF_ENQUEUE(&sc->inq, sc->m); 950 sc->m = NULL; 951 } 952 IF_UNLOCK(&sc->inq); 953 954 sc->state = NG_BT3C_W4_PKT_IND; 955 sc->want = 1; 956 break; 957 958 default: 959 KASSERT(0, 960 ("Invalid node state=%d", sc->state)); 961 break; 962 } 963 } 964 965 bt3c_write(sc, 0x7006, 0x0000); 966 } /* bt3c_receive */ 967 968 /* 969 * SWI interrupt handler 970 * Netgraph part is handled via ng_send_fn() to avoid race with hook 971 * connection/disconnection 972 */ 973 974 static void 975 bt3c_swi_intr(void *context) 976 { 977 bt3c_softc_p sc = (bt3c_softc_p) context; 978 u_int16_t data; 979 980 /* Receive complete */ 981 if (sc->status & 0x0001) { 982 sc->status &= ~0x0001; /* XXX is it safe? */ 983 984 if (ng_send_fn(sc->node, NULL, &bt3c_forward, NULL, 0) != 0) 985 NG_BT3C_ALERT(sc->dev, "Could not forward frames!\n"); 986 } 987 988 /* Send complete */ 989 if (sc->status & 0x0002) { 990 sc->status &= ~0x0002; /* XXX is it safe */ 991 992 if (ng_send_fn(sc->node, NULL, &bt3c_send, NULL, 1) != 0) 993 NG_BT3C_ALERT(sc->dev, "Could not send frames!\n"); 994 } 995 996 /* Antenna position */ 997 if (sc->status & 0x0020) { 998 sc->status &= ~0x0020; /* XXX is it safe */ 999 1000 bt3c_read(sc, 0x7002, data); 1001 data &= 0x10; 1002 1003 if (data) 1004 sc->flags |= BT3C_ANTENNA_OUT; 1005 else 1006 sc->flags &= ~BT3C_ANTENNA_OUT; 1007 1008 NG_BT3C_INFO(sc->dev, "Antenna %s\n", data? "OUT" : "IN"); 1009 } 1010 } /* bt3c_swi_intr */ 1011 1012 /* 1013 * Send all incoming frames to the upper layer 1014 */ 1015 1016 static void 1017 bt3c_forward(node_p node, hook_p hook, void *arg1, int arg2) 1018 { 1019 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); 1020 struct mbuf *m = NULL; 1021 int error; 1022 1023 if (sc == NULL) 1024 return; 1025 1026 if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) { 1027 for (;;) { 1028 IF_DEQUEUE(&sc->inq, m); 1029 if (m == NULL) 1030 break; 1031 1032 NG_SEND_DATA_ONLY(error, sc->hook, m); 1033 if (error != 0) 1034 NG_BT3C_STAT_IERROR(sc->stat); 1035 } 1036 } else { 1037 IF_LOCK(&sc->inq); 1038 for (;;) { 1039 _IF_DEQUEUE(&sc->inq, m); 1040 if (m == NULL) 1041 break; 1042 1043 NG_BT3C_STAT_IERROR(sc->stat); 1044 NG_FREE_M(m); 1045 } 1046 IF_UNLOCK(&sc->inq); 1047 } 1048 } /* bt3c_forward */ 1049 1050 /* 1051 * Send more data to the device. Must be called when node is locked 1052 */ 1053 1054 static void 1055 bt3c_send(node_p node, hook_p hook, void *arg, int completed) 1056 { 1057 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); 1058 struct mbuf *m = NULL; 1059 int i, wrote, len; 1060 1061 if (sc == NULL) 1062 return; 1063 1064 if (completed) 1065 sc->flags &= ~BT3C_XMIT; 1066 1067 if (sc->flags & BT3C_XMIT) 1068 return; 1069 1070 bt3c_set_address(sc, 0x7080); 1071 1072 for (wrote = 0; wrote < BT3C_FIFO_SIZE; ) { 1073 IF_DEQUEUE(&sc->outq, m); 1074 if (m == NULL) 1075 break; 1076 1077 while (m != NULL) { 1078 len = min((BT3C_FIFO_SIZE - wrote), m->m_len); 1079 1080 for (i = 0; i < len; i++) 1081 bt3c_write_data(sc, m->m_data[i]); 1082 1083 wrote += len; 1084 m->m_data += len; 1085 m->m_len -= len; 1086 1087 if (m->m_len > 0) 1088 break; 1089 1090 m = m_free(m); 1091 } 1092 1093 if (m != NULL) { 1094 IF_PREPEND(&sc->outq, m); 1095 break; 1096 } 1097 1098 NG_BT3C_STAT_PCKTS_SENT(sc->stat); 1099 } 1100 1101 if (wrote > 0) { 1102 NG_BT3C_INFO(sc->dev, "Wrote %d bytes\n", wrote); 1103 NG_BT3C_STAT_BYTES_SENT(sc->stat, wrote); 1104 1105 bt3c_write(sc, 0x7005, wrote); 1106 sc->flags |= BT3C_XMIT; 1107 } 1108 } /* bt3c_send */ 1109 1110 /* 1111 * Download chip firmware 1112 */ 1113 1114 static void 1115 bt3c_download_firmware(bt3c_softc_p sc, char const *firmware, int firmware_size) 1116 { 1117 ng_bt3c_firmware_block_ep const *block = NULL; 1118 u_int16_t const *data = NULL; 1119 int i, size; 1120 u_int8_t c; 1121 1122 /* Reset */ 1123 device_printf(sc->dev, "Reseting the card...\n"); 1124 bt3c_write(sc, 0x8040, 0x0404); 1125 bt3c_write(sc, 0x8040, 0x0400); 1126 DELAY(1); 1127 1128 bt3c_write(sc, 0x8040, 0x0404); 1129 DELAY(17); 1130 1131 /* Download firmware */ 1132 device_printf(sc->dev, "Starting firmware download process...\n"); 1133 1134 for (size = 0; size < firmware_size; ) { 1135 block = (ng_bt3c_firmware_block_ep const *)(firmware + size); 1136 data = (u_int16_t const *)(block + 1); 1137 1138 if (bootverbose) 1139 device_printf(sc->dev, "Download firmware block, " \ 1140 "address=%#08x, size=%d words, aligment=%d\n", 1141 block->block_address, block->block_size, 1142 block->block_alignment); 1143 1144 bt3c_set_address(sc, block->block_address); 1145 for (i = 0; i < block->block_size; i++) 1146 bt3c_write_data(sc, data[i]); 1147 1148 size += (sizeof(*block) + (block->block_size * 2) + 1149 block->block_alignment); 1150 } 1151 1152 DELAY(17); 1153 device_printf(sc->dev, "Firmware download process complete\n"); 1154 1155 /* Boot */ 1156 device_printf(sc->dev, "Starting the card...\n"); 1157 bt3c_set_address(sc, 0x3000); 1158 bt3c_read_control(sc, c); 1159 bt3c_write_control(sc, (c | 0x40)); 1160 DELAY(17); 1161 1162 /* Clear registers */ 1163 device_printf(sc->dev, "Clearing card registers...\n"); 1164 bt3c_write(sc, 0x7006, 0x0000); 1165 bt3c_write(sc, 0x7005, 0x0000); 1166 bt3c_write(sc, 0x7001, 0x0000); 1167 DELAY(1000); 1168 } /* bt3c_download_firmware */ 1169 1170 /**************************************************************************** 1171 **************************************************************************** 1172 ** Driver module 1173 **************************************************************************** 1174 ****************************************************************************/ 1175 1176 /* 1177 * PC Card (PCMCIA) driver 1178 */ 1179 1180 static device_method_t bt3c_pccard_methods[] = { 1181 /* Device interface */ 1182 DEVMETHOD(device_probe, bt3c_pccard_probe), 1183 DEVMETHOD(device_attach, bt3c_pccard_attach), 1184 DEVMETHOD(device_detach, bt3c_pccard_detach), 1185 1186 { 0, 0 } 1187 }; 1188 1189 static driver_t bt3c_pccard_driver = { 1190 NG_BT3C_NODE_TYPE, 1191 bt3c_pccard_methods, 1192 sizeof(bt3c_softc_t) 1193 }; 1194 1195 static devclass_t bt3c_devclass; 1196 1197 1198 /* 1199 * Load/Unload the driver module 1200 */ 1201 1202 static int 1203 bt3c_modevent(module_t mod, int event, void *data) 1204 { 1205 int error; 1206 1207 switch (event) { 1208 case MOD_LOAD: 1209 error = ng_newtype(&typestruct); 1210 if (error != 0) 1211 printf("%s: Could not register Netgraph node type, " \ 1212 "error=%d\n", NG_BT3C_NODE_TYPE, error); 1213 break; 1214 1215 case MOD_UNLOAD: 1216 error = ng_rmtype(&typestruct); 1217 break; 1218 1219 default: 1220 error = EOPNOTSUPP; 1221 break; 1222 } 1223 1224 return (error); 1225 } /* bt3c_modevent */ 1226 1227 DRIVER_MODULE(bt3c, pccard, bt3c_pccard_driver, bt3c_devclass, bt3c_modevent,0); 1228 MODULE_VERSION(ng_bt3c, NG_BLUETOOTH_VERSION); 1229 MODULE_DEPEND(ng_bt3c, netgraph, NG_ABI_VERSION, NG_ABI_VERSION,NG_ABI_VERSION); 1230 1231