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