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