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: releng/11.0/sys/netgraph/bluetooth/drivers/bt3c/ng_bt3c_pccard.c 296137 2016-02-27 03:38:01Z jhibbits $ 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 <netgraph/ng_message.h> 67#include <netgraph/netgraph.h> 68#include <netgraph/ng_parse.h> 69#include <netgraph/bluetooth/include/ng_bluetooth.h> 70#include <netgraph/bluetooth/include/ng_hci.h> 71#include <netgraph/bluetooth/include/ng_bt3c.h> 72#include <netgraph/bluetooth/drivers/bt3c/ng_bt3c_var.h> 73 74/* Netgraph methods */ 75static ng_constructor_t ng_bt3c_constructor; 76static ng_shutdown_t ng_bt3c_shutdown; 77static ng_newhook_t ng_bt3c_newhook; 78static ng_connect_t ng_bt3c_connect; 79static ng_disconnect_t ng_bt3c_disconnect; 80static ng_rcvmsg_t ng_bt3c_rcvmsg; 81static ng_rcvdata_t ng_bt3c_rcvdata; 82 83/* PCMCIA driver methods */ 84static int bt3c_pccard_probe (device_t); 85static int bt3c_pccard_attach (device_t); 86static int bt3c_pccard_detach (device_t); 87 88static void bt3c_intr (void *); 89static void bt3c_receive (bt3c_softc_p); 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 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) \ 104do { \ 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) \ 110do { \ 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) \ 116do { \ 117 (data) = bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_CONTROL); \ 118} while (0) 119 120#define bt3c_write_control(sc, data) \ 121do { \ 122 bus_space_write_1((sc)->iot, (sc)->ioh, 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 .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 247static int 248ng_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 257static int 258ng_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); 286out: 287 return (0); 288} /* ng_bt3c_shutdown */ 289 290/* 291 * Create new hook. There can only be one. 292 */ 293 294static int 295ng_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 314static int 315ng_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 334static int 335ng_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 361static int 362ng_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_NOWAIT); 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_NOWAIT); 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_NOWAIT); 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_NOWAIT); 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_NOWAIT); 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 539static int 540ng_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 NG_BT3C_STAT_OERROR(sc->stat); 564 565 NG_FREE_M(m); 566 } else 567 _IF_ENQUEUE(&sc->outq, m); 568 IF_UNLOCK(&sc->outq); 569 570 error = ng_send_fn(sc->node, NULL, bt3c_send, NULL, 0 /* new send */); 571out: 572 NG_FREE_ITEM(item); 573 574 return (error); 575} /* ng_bt3c_rcvdata */ 576 577/**************************************************************************** 578 **************************************************************************** 579 ** PCMCIA driver specific 580 **************************************************************************** 581 ****************************************************************************/ 582 583/* 584 * PC Card (PCMCIA) probe routine 585 */ 586 587static struct pccard_product const bt3c_pccard_products[] = { 588 PCMCIA_CARD(3COM, 3CRWB609), 589 { NULL, } 590}; 591 592static int 593bt3c_pccard_probe(device_t dev) 594{ 595 struct pccard_product const *pp = NULL; 596 597 pp = pccard_product_lookup(dev, bt3c_pccard_products, 598 sizeof(bt3c_pccard_products[0]), NULL); 599 if (pp == NULL) 600 return (ENXIO); 601 602 device_set_desc(dev, pp->pp_name); 603 604 return (0); 605} /* bt3c_pccard_probe */ 606 607/* 608 * PC Card (PCMCIA) attach routine 609 */ 610 611static int 612bt3c_pccard_attach(device_t dev) 613{ 614 bt3c_softc_p sc = (bt3c_softc_p) device_get_softc(dev); 615 616 /* Allocate I/O ports */ 617 sc->iobase_rid = 0; 618 sc->iobase = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, 619 &sc->iobase_rid, 8, RF_ACTIVE); 620 if (sc->iobase == NULL) { 621 device_printf(dev, "Could not allocate I/O ports\n"); 622 goto bad; 623 } 624 sc->iot = rman_get_bustag(sc->iobase); 625 sc->ioh = rman_get_bushandle(sc->iobase); 626 627 /* Allocate IRQ */ 628 sc->irq_rid = 0; 629 sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 630 RF_ACTIVE); 631 if (sc->irq == NULL) { 632 device_printf(dev, "Could not allocate IRQ\n"); 633 goto bad; 634 } 635 636 sc->irq_cookie = NULL; 637 if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, NULL, bt3c_intr, sc, 638 &sc->irq_cookie) != 0) { 639 device_printf(dev, "Could not setup ISR\n"); 640 goto bad; 641 } 642 643 /* Attach handler to TTY SWI thread */ 644 sc->ith = NULL; 645 if (swi_add(&tty_intr_event, device_get_nameunit(dev), 646 bt3c_swi_intr, sc, SWI_TTY, 0, &sc->ith) < 0) { 647 device_printf(dev, "Could not setup SWI ISR\n"); 648 goto bad; 649 } 650 651 /* Create Netgraph node */ 652 if (ng_make_node_common(&typestruct, &sc->node) != 0) { 653 device_printf(dev, "Could not create Netgraph node\n"); 654 sc->node = NULL; 655 goto bad; 656 } 657 658 /* Name Netgraph node */ 659 if (ng_name_node(sc->node, device_get_nameunit(dev)) != 0) { 660 device_printf(dev, "Could not name Netgraph node\n"); 661 NG_NODE_UNREF(sc->node); 662 sc->node = NULL; 663 goto bad; 664 } 665 666 sc->dev = dev; 667 sc->debug = NG_BT3C_WARN_LEVEL; 668 669 sc->inq.ifq_maxlen = sc->outq.ifq_maxlen = BT3C_DEFAULTQLEN; 670 mtx_init(&sc->inq.ifq_mtx, "BT3C inq", NULL, MTX_DEF); 671 mtx_init(&sc->outq.ifq_mtx, "BT3C outq", NULL, MTX_DEF); 672 673 sc->state = NG_BT3C_W4_PKT_IND; 674 sc->want = 1; 675 676 NG_NODE_SET_PRIVATE(sc->node, sc); 677 678 return (0); 679bad: 680 if (sc->ith != NULL) { 681 swi_remove(sc->ith); 682 sc->ith = NULL; 683 } 684 685 if (sc->irq != NULL) { 686 if (sc->irq_cookie != NULL) 687 bus_teardown_intr(dev, sc->irq, sc->irq_cookie); 688 689 bus_release_resource(dev, SYS_RES_IRQ, 690 sc->irq_rid, sc->irq); 691 692 sc->irq = NULL; 693 sc->irq_rid = 0; 694 } 695 696 if (sc->iobase != NULL) { 697 bus_release_resource(dev, SYS_RES_IOPORT, 698 sc->iobase_rid, sc->iobase); 699 700 sc->iobase = NULL; 701 sc->iobase_rid = 0; 702 } 703 704 return (ENXIO); 705} /* bt3c_pccacd_attach */ 706 707/* 708 * PC Card (PCMCIA) detach routine 709 */ 710 711static int 712bt3c_pccard_detach(device_t dev) 713{ 714 bt3c_softc_p sc = (bt3c_softc_p) device_get_softc(dev); 715 716 if (sc == NULL) 717 return (0); 718 719 swi_remove(sc->ith); 720 sc->ith = NULL; 721 722 bus_teardown_intr(dev, sc->irq, sc->irq_cookie); 723 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); 724 sc->irq_cookie = NULL; 725 sc->irq = NULL; 726 sc->irq_rid = 0; 727 728 bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase); 729 sc->iobase = NULL; 730 sc->iobase_rid = 0; 731 732 if (sc->node != NULL) { 733 NG_NODE_SET_PRIVATE(sc->node, NULL); 734 ng_rmnode_self(sc->node); 735 sc->node = NULL; 736 } 737 738 NG_FREE_M(sc->m); 739 IF_DRAIN(&sc->inq); 740 IF_DRAIN(&sc->outq); 741 742 mtx_destroy(&sc->inq.ifq_mtx); 743 mtx_destroy(&sc->outq.ifq_mtx); 744 745 return (0); 746} /* bt3c_pccacd_detach */ 747 748/* 749 * Interrupt service routine's 750 */ 751 752static void 753bt3c_intr(void *context) 754{ 755 bt3c_softc_p sc = (bt3c_softc_p) context; 756 u_int16_t control, status; 757 758 if (sc == NULL || sc->ith == NULL) { 759 printf("%s: bogus interrupt\n", NG_BT3C_NODE_TYPE); 760 return; 761 } 762 763 bt3c_read_control(sc, control); 764 if ((control & 0x80) == 0) 765 return; 766 767 bt3c_read(sc, 0x7001, status); 768 NG_BT3C_INFO(sc->dev, "control=%#x, status=%#x\n", control, status); 769 770 if ((status & 0xff) == 0x7f || (status & 0xff) == 0xff) { 771 NG_BT3C_WARN(sc->dev, "Strange status=%#x\n", status); 772 return; 773 } 774 775 /* Receive complete */ 776 if (status & 0x0001) 777 bt3c_receive(sc); 778 779 /* Record status and schedule SWI */ 780 sc->status |= status; 781 swi_sched(sc->ith, 0); 782 783 /* Complete interrupt */ 784 bt3c_write(sc, 0x7001, 0x0000); 785 bt3c_write_control(sc, control); 786} /* bt3c_intr */ 787 788/* 789 * Receive data 790 */ 791 792static void 793bt3c_receive(bt3c_softc_p sc) 794{ 795 u_int16_t i, count, c; 796 797 /* Receive data from the card */ 798 bt3c_read(sc, 0x7006, count); 799 NG_BT3C_INFO(sc->dev, "The card has %d characters\n", count); 800 801 bt3c_set_address(sc, 0x7480); 802 803 for (i = 0; i < count; i++) { 804 /* Allocate new mbuf if needed */ 805 if (sc->m == NULL) { 806 sc->state = NG_BT3C_W4_PKT_IND; 807 sc->want = 1; 808 809 MGETHDR(sc->m, M_NOWAIT, MT_DATA); 810 if (sc->m == NULL) { 811 NG_BT3C_ERR(sc->dev, "Could not get mbuf\n"); 812 NG_BT3C_STAT_IERROR(sc->stat); 813 814 break; /* XXX lost of sync */ 815 } 816 817 if (!(MCLGET(sc->m, M_NOWAIT))) { 818 NG_FREE_M(sc->m); 819 820 NG_BT3C_ERR(sc->dev, "Could not get cluster\n"); 821 NG_BT3C_STAT_IERROR(sc->stat); 822 823 break; /* XXX lost of sync */ 824 } 825 826 sc->m->m_len = sc->m->m_pkthdr.len = 0; 827 } 828 829 /* Read and append character to mbuf */ 830 bt3c_read_data(sc, c); 831 if (sc->m->m_pkthdr.len >= MCLBYTES) { 832 NG_BT3C_ERR(sc->dev, "Oversized frame\n"); 833 834 NG_FREE_M(sc->m); 835 sc->state = NG_BT3C_W4_PKT_IND; 836 sc->want = 1; 837 838 break; /* XXX lost of sync */ 839 } 840 841 mtod(sc->m, u_int8_t *)[sc->m->m_len ++] = (u_int8_t) c; 842 sc->m->m_pkthdr.len ++; 843 844 NG_BT3C_INFO(sc->dev, 845"Got char %#x, want=%d, got=%d\n", c, sc->want, sc->m->m_pkthdr.len); 846 847 if (sc->m->m_pkthdr.len < sc->want) 848 continue; /* wait for more */ 849 850 switch (sc->state) { 851 /* Got packet indicator */ 852 case NG_BT3C_W4_PKT_IND: 853 NG_BT3C_INFO(sc->dev, 854"Got packet indicator %#x\n", *mtod(sc->m, u_int8_t *)); 855 856 sc->state = NG_BT3C_W4_PKT_HDR; 857 858 /* 859 * Since packet indicator included in the packet 860 * header just set sc->want to sizeof(packet header). 861 */ 862 863 switch (*mtod(sc->m, u_int8_t *)) { 864 case NG_HCI_ACL_DATA_PKT: 865 sc->want = sizeof(ng_hci_acldata_pkt_t); 866 break; 867 868 case NG_HCI_SCO_DATA_PKT: 869 sc->want = sizeof(ng_hci_scodata_pkt_t); 870 break; 871 872 case NG_HCI_EVENT_PKT: 873 sc->want = sizeof(ng_hci_event_pkt_t); 874 break; 875 876 default: 877 NG_BT3C_ERR(sc->dev, 878"Ignoring unknown packet type=%#x\n", *mtod(sc->m, u_int8_t *)); 879 880 NG_BT3C_STAT_IERROR(sc->stat); 881 882 NG_FREE_M(sc->m); 883 sc->state = NG_BT3C_W4_PKT_IND; 884 sc->want = 1; 885 break; 886 } 887 break; 888 889 /* Got packet header */ 890 case NG_BT3C_W4_PKT_HDR: 891 sc->state = NG_BT3C_W4_PKT_DATA; 892 893 switch (*mtod(sc->m, u_int8_t *)) { 894 case NG_HCI_ACL_DATA_PKT: 895 c = le16toh(mtod(sc->m, 896 ng_hci_acldata_pkt_t *)->length); 897 break; 898 899 case NG_HCI_SCO_DATA_PKT: 900 c = mtod(sc->m, ng_hci_scodata_pkt_t*)->length; 901 break; 902 903 case NG_HCI_EVENT_PKT: 904 c = mtod(sc->m, ng_hci_event_pkt_t *)->length; 905 break; 906 907 default: 908 KASSERT(0, 909("Invalid packet type=%#x\n", *mtod(sc->m, u_int8_t *))); 910 break; 911 } 912 913 NG_BT3C_INFO(sc->dev, 914"Got packet header, packet type=%#x, got so far %d, payload size=%d\n", 915 *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len, 916 c); 917 918 if (c > 0) { 919 sc->want += c; 920 break; 921 } 922 923 /* else FALLTHROUGH and deliver frame */ 924 /* XXX is this true? should we deliver empty frame? */ 925 926 /* Got packet data */ 927 case NG_BT3C_W4_PKT_DATA: 928 NG_BT3C_INFO(sc->dev, 929"Got full packet, packet type=%#x, packet size=%d\n", 930 *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len); 931 932 NG_BT3C_STAT_BYTES_RECV(sc->stat, sc->m->m_pkthdr.len); 933 NG_BT3C_STAT_PCKTS_RECV(sc->stat); 934 935 IF_LOCK(&sc->inq); 936 if (_IF_QFULL(&sc->inq)) { 937 NG_BT3C_ERR(sc->dev, 938"Incoming queue is full. Dropping mbuf, len=%d\n", sc->m->m_pkthdr.len); 939 940 NG_BT3C_STAT_IERROR(sc->stat); 941 942 NG_FREE_M(sc->m); 943 } else { 944 _IF_ENQUEUE(&sc->inq, sc->m); 945 sc->m = NULL; 946 } 947 IF_UNLOCK(&sc->inq); 948 949 sc->state = NG_BT3C_W4_PKT_IND; 950 sc->want = 1; 951 break; 952 953 default: 954 KASSERT(0, 955("Invalid node state=%d", sc->state)); 956 break; 957 } 958 } 959 960 bt3c_write(sc, 0x7006, 0x0000); 961} /* bt3c_receive */ 962 963/* 964 * SWI interrupt handler 965 * Netgraph part is handled via ng_send_fn() to avoid race with hook 966 * connection/disconnection 967 */ 968 969static void 970bt3c_swi_intr(void *context) 971{ 972 bt3c_softc_p sc = (bt3c_softc_p) context; 973 u_int16_t data; 974 975 /* Receive complete */ 976 if (sc->status & 0x0001) { 977 sc->status &= ~0x0001; /* XXX is it safe? */ 978 979 if (ng_send_fn(sc->node, NULL, &bt3c_forward, NULL, 0) != 0) 980 NG_BT3C_ALERT(sc->dev, "Could not forward frames!\n"); 981 } 982 983 /* Send complete */ 984 if (sc->status & 0x0002) { 985 sc->status &= ~0x0002; /* XXX is it safe */ 986 987 if (ng_send_fn(sc->node, NULL, &bt3c_send, NULL, 1) != 0) 988 NG_BT3C_ALERT(sc->dev, "Could not send frames!\n"); 989 } 990 991 /* Antenna position */ 992 if (sc->status & 0x0020) { 993 sc->status &= ~0x0020; /* XXX is it safe */ 994 995 bt3c_read(sc, 0x7002, data); 996 data &= 0x10; 997 998 if (data) 999 sc->flags |= BT3C_ANTENNA_OUT; 1000 else 1001 sc->flags &= ~BT3C_ANTENNA_OUT; 1002 1003 NG_BT3C_INFO(sc->dev, "Antenna %s\n", data? "OUT" : "IN"); 1004 } 1005} /* bt3c_swi_intr */ 1006 1007/* 1008 * Send all incoming frames to the upper layer 1009 */ 1010 1011static void 1012bt3c_forward(node_p node, hook_p hook, void *arg1, int arg2) 1013{ 1014 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); 1015 struct mbuf *m = NULL; 1016 int error; 1017 1018 if (sc == NULL) 1019 return; 1020 1021 if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) { 1022 for (;;) { 1023 IF_DEQUEUE(&sc->inq, m); 1024 if (m == NULL) 1025 break; 1026 1027 NG_SEND_DATA_ONLY(error, sc->hook, m); 1028 if (error != 0) 1029 NG_BT3C_STAT_IERROR(sc->stat); 1030 } 1031 } else { 1032 IF_LOCK(&sc->inq); 1033 for (;;) { 1034 _IF_DEQUEUE(&sc->inq, m); 1035 if (m == NULL) 1036 break; 1037 1038 NG_BT3C_STAT_IERROR(sc->stat); 1039 NG_FREE_M(m); 1040 } 1041 IF_UNLOCK(&sc->inq); 1042 } 1043} /* bt3c_forward */ 1044 1045/* 1046 * Send more data to the device. Must be called when node is locked 1047 */ 1048 1049static void 1050bt3c_send(node_p node, hook_p hook, void *arg, int completed) 1051{ 1052 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); 1053 struct mbuf *m = NULL; 1054 int i, wrote, len; 1055 1056 if (sc == NULL) 1057 return; 1058 1059 if (completed) 1060 sc->flags &= ~BT3C_XMIT; 1061 1062 if (sc->flags & BT3C_XMIT) 1063 return; 1064 1065 bt3c_set_address(sc, 0x7080); 1066 1067 for (wrote = 0; wrote < BT3C_FIFO_SIZE; ) { 1068 IF_DEQUEUE(&sc->outq, m); 1069 if (m == NULL) 1070 break; 1071 1072 while (m != NULL) { 1073 len = min((BT3C_FIFO_SIZE - wrote), m->m_len); 1074 1075 for (i = 0; i < len; i++) 1076 bt3c_write_data(sc, m->m_data[i]); 1077 1078 wrote += len; 1079 m->m_data += len; 1080 m->m_len -= len; 1081 1082 if (m->m_len > 0) 1083 break; 1084 1085 m = m_free(m); 1086 } 1087 1088 if (m != NULL) { 1089 IF_PREPEND(&sc->outq, m); 1090 break; 1091 } 1092 1093 NG_BT3C_STAT_PCKTS_SENT(sc->stat); 1094 } 1095 1096 if (wrote > 0) { 1097 NG_BT3C_INFO(sc->dev, "Wrote %d bytes\n", wrote); 1098 NG_BT3C_STAT_BYTES_SENT(sc->stat, wrote); 1099 1100 bt3c_write(sc, 0x7005, wrote); 1101 sc->flags |= BT3C_XMIT; 1102 } 1103} /* bt3c_send */ 1104 1105/* 1106 * Download chip firmware 1107 */ 1108 1109static void 1110bt3c_download_firmware(bt3c_softc_p sc, char const *firmware, int firmware_size) 1111{ 1112 ng_bt3c_firmware_block_ep const *block = NULL; 1113 u_int16_t const *data = NULL; 1114 int i, size; 1115 u_int8_t c; 1116 1117 /* Reset */ 1118 device_printf(sc->dev, "Reseting the card...\n"); 1119 bt3c_write(sc, 0x8040, 0x0404); 1120 bt3c_write(sc, 0x8040, 0x0400); 1121 DELAY(1); 1122 1123 bt3c_write(sc, 0x8040, 0x0404); 1124 DELAY(17); 1125 1126 /* Download firmware */ 1127 device_printf(sc->dev, "Starting firmware download process...\n"); 1128 1129 for (size = 0; size < firmware_size; ) { 1130 block = (ng_bt3c_firmware_block_ep const *)(firmware + size); 1131 data = (u_int16_t const *)(block + 1); 1132 1133 if (bootverbose) 1134 device_printf(sc->dev, "Download firmware block, " \ 1135 "address=%#08x, size=%d words, aligment=%d\n", 1136 block->block_address, block->block_size, 1137 block->block_alignment); 1138 1139 bt3c_set_address(sc, block->block_address); 1140 for (i = 0; i < block->block_size; i++) 1141 bt3c_write_data(sc, data[i]); 1142 1143 size += (sizeof(*block) + (block->block_size * 2) + 1144 block->block_alignment); 1145 } 1146 1147 DELAY(17); 1148 device_printf(sc->dev, "Firmware download process complete\n"); 1149 1150 /* Boot */ 1151 device_printf(sc->dev, "Starting the card...\n"); 1152 bt3c_set_address(sc, 0x3000); 1153 bt3c_read_control(sc, c); 1154 bt3c_write_control(sc, (c | 0x40)); 1155 DELAY(17); 1156 1157 /* Clear registers */ 1158 device_printf(sc->dev, "Clearing card registers...\n"); 1159 bt3c_write(sc, 0x7006, 0x0000); 1160 bt3c_write(sc, 0x7005, 0x0000); 1161 bt3c_write(sc, 0x7001, 0x0000); 1162 DELAY(1000); 1163} /* bt3c_download_firmware */ 1164 1165/**************************************************************************** 1166 **************************************************************************** 1167 ** Driver module 1168 **************************************************************************** 1169 ****************************************************************************/ 1170 1171/* 1172 * PC Card (PCMCIA) driver 1173 */ 1174 1175static device_method_t bt3c_pccard_methods[] = { 1176 /* Device interface */ 1177 DEVMETHOD(device_probe, bt3c_pccard_probe), 1178 DEVMETHOD(device_attach, bt3c_pccard_attach), 1179 DEVMETHOD(device_detach, bt3c_pccard_detach), 1180 1181 { 0, 0 } 1182}; 1183 1184static driver_t bt3c_pccard_driver = { 1185 NG_BT3C_NODE_TYPE, 1186 bt3c_pccard_methods, 1187 sizeof(bt3c_softc_t) 1188}; 1189 1190static devclass_t bt3c_devclass; 1191 1192 1193/* 1194 * Load/Unload the driver module 1195 */ 1196 1197static int 1198bt3c_modevent(module_t mod, int event, void *data) 1199{ 1200 int error; 1201 1202 switch (event) { 1203 case MOD_LOAD: 1204 error = ng_newtype(&typestruct); 1205 if (error != 0) 1206 printf("%s: Could not register Netgraph node type, " \ 1207 "error=%d\n", NG_BT3C_NODE_TYPE, error); 1208 break; 1209 1210 case MOD_UNLOAD: 1211 error = ng_rmtype(&typestruct); 1212 break; 1213 1214 default: 1215 error = EOPNOTSUPP; 1216 break; 1217 } 1218 1219 return (error); 1220} /* bt3c_modevent */ 1221 1222DRIVER_MODULE(bt3c, pccard, bt3c_pccard_driver, bt3c_devclass, bt3c_modevent,0); 1223MODULE_VERSION(ng_bt3c, NG_BLUETOOTH_VERSION); 1224MODULE_DEPEND(ng_bt3c, netgraph, NG_ABI_VERSION, NG_ABI_VERSION,NG_ABI_VERSION); 1225PCCARD_PNP_INFO(bt3c_pccard_products); 1226