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