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