1 /* $NetBSD: bthidev.c,v 1.7 2006/11/16 01:32:48 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Itronix Inc. 5 * All rights reserved. 6 * 7 * Written by Iain Hibbert for Itronix Inc. 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 * 3. The name of Itronix Inc. may not be used to endorse 18 * or promote products derived from this software without specific 19 * prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28 * ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: bthidev.c,v 1.7 2006/11/16 01:32:48 christos Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/conf.h> 39 #include <sys/device.h> 40 #include <sys/fcntl.h> 41 #include <sys/kernel.h> 42 #include <sys/queue.h> 43 #include <sys/malloc.h> 44 #include <sys/mbuf.h> 45 #include <sys/proc.h> 46 #include <sys/systm.h> 47 48 #include <prop/proplib.h> 49 50 #include <netbt/bluetooth.h> 51 #include <netbt/l2cap.h> 52 53 #include <dev/usb/hid.h> 54 #include <dev/bluetooth/btdev.h> 55 #include <dev/bluetooth/bthid.h> 56 #include <dev/bluetooth/bthidev.h> 57 58 #include "locators.h" 59 60 /***************************************************************************** 61 * 62 * Bluetooth HID device 63 */ 64 65 #define MAX_DESCRIPTOR_LEN 1024 /* sanity check */ 66 67 /* bthidev softc */ 68 struct bthidev_softc { 69 struct btdev sc_btdev; 70 uint16_t sc_state; 71 uint16_t sc_flags; 72 73 bdaddr_t sc_laddr; /* local address */ 74 bdaddr_t sc_raddr; /* remote address */ 75 76 uint16_t sc_ctlpsm; /* control PSM */ 77 struct l2cap_channel *sc_ctl; /* control channel */ 78 struct l2cap_channel *sc_ctl_l; /* control listen */ 79 80 uint16_t sc_intpsm; /* interrupt PSM */ 81 struct l2cap_channel *sc_int; /* interrupt channel */ 82 struct l2cap_channel *sc_int_l; /* interrupt listen */ 83 84 LIST_HEAD(,bthidev) sc_list; /* child list */ 85 86 struct callout sc_reconnect; 87 int sc_attempts; /* connection attempts */ 88 }; 89 90 /* sc_flags */ 91 #define BTHID_RECONNECT (1 << 0) /* reconnect on link loss */ 92 #define BTHID_CONNECTING (1 << 1) /* we are connecting */ 93 94 /* device state */ 95 #define BTHID_CLOSED 0 96 #define BTHID_WAIT_CTL 1 97 #define BTHID_WAIT_INT 2 98 #define BTHID_OPEN 3 99 #define BTHID_DETACHING 4 100 101 #define BTHID_RETRY_INTERVAL 5 /* seconds between connection attempts */ 102 103 /* bthidev internals */ 104 static void bthidev_timeout(void *); 105 static int bthidev_listen(struct bthidev_softc *); 106 static int bthidev_connect(struct bthidev_softc *); 107 static int bthidev_output(struct bthidev *, uint8_t *, int); 108 static void bthidev_null(struct bthidev *, uint8_t *, int); 109 110 /* autoconf(9) glue */ 111 static int bthidev_match(struct device *, struct cfdata *, void *); 112 static void bthidev_attach(struct device *, struct device *, void *); 113 static int bthidev_detach(struct device *, int); 114 static int bthidev_print(void *, const char *); 115 116 CFATTACH_DECL(bthidev, sizeof(struct bthidev_softc), 117 bthidev_match, bthidev_attach, bthidev_detach, NULL); 118 119 /* bluetooth(9) protocol methods for L2CAP */ 120 static void bthidev_connecting(void *); 121 static void bthidev_ctl_connected(void *); 122 static void bthidev_int_connected(void *); 123 static void bthidev_ctl_disconnected(void *, int); 124 static void bthidev_int_disconnected(void *, int); 125 static void *bthidev_ctl_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 126 static void *bthidev_int_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 127 static void bthidev_complete(void *, int); 128 static void bthidev_input(void *, struct mbuf *); 129 130 static const struct btproto bthidev_ctl_proto = { 131 bthidev_connecting, 132 bthidev_ctl_connected, 133 bthidev_ctl_disconnected, 134 bthidev_ctl_newconn, 135 bthidev_complete, 136 bthidev_input, 137 }; 138 139 static const struct btproto bthidev_int_proto = { 140 bthidev_connecting, 141 bthidev_int_connected, 142 bthidev_int_disconnected, 143 bthidev_int_newconn, 144 bthidev_complete, 145 bthidev_input, 146 }; 147 148 /***************************************************************************** 149 * 150 * bthidev autoconf(9) routines 151 */ 152 153 static int 154 bthidev_match(struct device *self, struct cfdata *cfdata, 155 void *aux) 156 { 157 prop_dictionary_t dict = aux; 158 prop_object_t obj; 159 160 obj = prop_dictionary_get(dict, BTDEVservice); 161 if (prop_string_equals_cstring(obj, "HID")) 162 return 1; 163 164 return 0; 165 } 166 167 static void 168 bthidev_attach(struct device *parent, struct device *self, void *aux) 169 { 170 struct bthidev_softc *sc = (struct bthidev_softc *)self; 171 prop_dictionary_t dict = aux; 172 prop_object_t obj; 173 struct bthidev_attach_args bha; 174 struct bthidev *dev; 175 struct hid_data *d; 176 struct hid_item h; 177 const void *desc; 178 int locs[BTHIDBUSCF_NLOCS]; 179 int maxid, rep, s, dlen; 180 181 /* 182 * Init softc 183 */ 184 LIST_INIT(&sc->sc_list); 185 callout_init(&sc->sc_reconnect); 186 callout_setfunc(&sc->sc_reconnect, bthidev_timeout, sc); 187 sc->sc_state = BTHID_CLOSED; 188 sc->sc_flags = BTHID_CONNECTING; 189 sc->sc_ctlpsm = L2CAP_PSM_HID_CNTL; 190 sc->sc_intpsm = L2CAP_PSM_HID_INTR; 191 192 /* 193 * extract config from proplist 194 */ 195 obj = prop_dictionary_get(dict, BTDEVladdr); 196 bdaddr_copy(&sc->sc_laddr, prop_data_data_nocopy(obj)); 197 198 obj = prop_dictionary_get(dict, BTDEVraddr); 199 bdaddr_copy(&sc->sc_raddr, prop_data_data_nocopy(obj)); 200 201 obj = prop_dictionary_get(dict, BTHIDEVcontrolpsm); 202 if (prop_object_type(obj) == PROP_TYPE_NUMBER) { 203 sc->sc_ctlpsm = prop_number_integer_value(obj); 204 if (L2CAP_PSM_INVALID(sc->sc_ctlpsm)) { 205 aprint_error(" invalid %s\n", BTHIDEVcontrolpsm); 206 return; 207 } 208 } 209 210 obj = prop_dictionary_get(dict, BTHIDEVinterruptpsm); 211 if (prop_object_type(obj) == PROP_TYPE_NUMBER) { 212 sc->sc_intpsm = prop_number_integer_value(obj); 213 if (L2CAP_PSM_INVALID(sc->sc_intpsm)) { 214 aprint_error(" invalid %s\n", BTHIDEVinterruptpsm); 215 return; 216 } 217 } 218 219 obj = prop_dictionary_get(dict, BTHIDEVdescriptor); 220 if (prop_object_type(obj) == PROP_TYPE_DATA) { 221 dlen = prop_data_size(obj); 222 desc = prop_data_data_nocopy(obj); 223 } else { 224 aprint_error(" no %s\n", BTHIDEVdescriptor); 225 return; 226 } 227 228 obj = prop_dictionary_get(dict, BTHIDEVreconnect); 229 if (prop_object_type(obj) == PROP_TYPE_BOOL 230 && !prop_bool_true(obj)) 231 sc->sc_flags |= BTHID_RECONNECT; 232 233 /* 234 * Parse the descriptor and attach child devices, one per report. 235 */ 236 maxid = -1; 237 h.report_ID = 0; 238 d = hid_start_parse(desc, dlen, hid_none); 239 while (hid_get_item(d, &h)) { 240 if (h.report_ID > maxid) 241 maxid = h.report_ID; 242 } 243 hid_end_parse(d); 244 245 if (maxid < 0) { 246 aprint_error(" no reports found\n"); 247 return; 248 } 249 250 aprint_normal("\n"); 251 252 for (rep = 0 ; rep <= maxid ; rep++) { 253 if (hid_report_size(desc, dlen, hid_feature, rep) == 0 254 && hid_report_size(desc, dlen, hid_input, rep) == 0 255 && hid_report_size(desc, dlen, hid_output, rep) == 0) 256 continue; 257 258 bha.ba_desc = desc; 259 bha.ba_dlen = dlen; 260 bha.ba_input = bthidev_null; 261 bha.ba_feature = bthidev_null; 262 bha.ba_output = bthidev_output; 263 bha.ba_id = rep; 264 265 locs[BTHIDBUSCF_REPORTID] = rep; 266 267 dev = (struct bthidev *)config_found_sm_loc((struct device *)sc, "bthidbus", 268 locs, &bha, bthidev_print, config_stdsubmatch); 269 if (dev != NULL) { 270 dev->sc_parent = (struct device *)sc; 271 dev->sc_id = rep; 272 dev->sc_input = bha.ba_input; 273 dev->sc_feature = bha.ba_feature; 274 LIST_INSERT_HEAD(&sc->sc_list, dev, sc_next); 275 } 276 } 277 278 /* 279 * start bluetooth connections 280 */ 281 s = splsoftnet(); 282 if ((sc->sc_flags & BTHID_RECONNECT) == 0) 283 bthidev_listen(sc); 284 285 if (sc->sc_flags & BTHID_CONNECTING) 286 bthidev_connect(sc); 287 splx(s); 288 } 289 290 static int 291 bthidev_detach(struct device *self, int flags) 292 { 293 struct bthidev_softc *sc = (struct bthidev_softc *)self; 294 struct bthidev *dev; 295 int s; 296 297 s = splsoftnet(); 298 sc->sc_flags = 0; /* disable reconnecting */ 299 300 /* release interrupt listen */ 301 if (sc->sc_int_l != NULL) { 302 l2cap_detach(&sc->sc_int_l); 303 sc->sc_int_l = NULL; 304 } 305 306 /* release control listen */ 307 if (sc->sc_ctl_l != NULL) { 308 l2cap_detach(&sc->sc_ctl_l); 309 sc->sc_ctl_l = NULL; 310 } 311 312 /* close interrupt channel */ 313 if (sc->sc_int != NULL) { 314 l2cap_disconnect(sc->sc_int, 0); 315 l2cap_detach(&sc->sc_int); 316 sc->sc_int = NULL; 317 } 318 319 /* close control channel */ 320 if (sc->sc_ctl != NULL) { 321 l2cap_disconnect(sc->sc_ctl, 0); 322 l2cap_detach(&sc->sc_ctl); 323 sc->sc_ctl = NULL; 324 } 325 326 /* remove callout */ 327 sc->sc_state = BTHID_DETACHING; 328 callout_stop(&sc->sc_reconnect); 329 if (callout_invoking(&sc->sc_reconnect)) 330 tsleep(sc, PWAIT, "bthidetach", 0); 331 332 splx(s); 333 334 /* detach children */ 335 while ((dev = LIST_FIRST(&sc->sc_list)) != NULL) { 336 LIST_REMOVE(dev, sc_next); 337 config_detach((struct device *)dev, flags); 338 } 339 340 return 0; 341 } 342 343 /* 344 * bthidev config print 345 */ 346 static int 347 bthidev_print(void *aux, const char *pnp) 348 { 349 struct bthidev_attach_args *ba = aux; 350 351 if (pnp != NULL) 352 aprint_normal("%s:", pnp); 353 354 if (ba->ba_id > 0) 355 aprint_normal(" reportid %d", ba->ba_id); 356 357 return UNCONF; 358 } 359 360 /***************************************************************************** 361 * 362 * bluetooth(4) HID attach/detach routines 363 */ 364 365 /* 366 * callouts are scheduled after connections have been lost, in order 367 * to clean up and reconnect. 368 */ 369 static void 370 bthidev_timeout(void *arg) 371 { 372 struct bthidev_softc *sc = arg; 373 int s; 374 375 s = splsoftnet(); 376 callout_ack(&sc->sc_reconnect); 377 378 switch (sc->sc_state) { 379 case BTHID_CLOSED: 380 if (sc->sc_int != NULL) { 381 l2cap_disconnect(sc->sc_int, 0); 382 break; 383 } 384 385 if (sc->sc_ctl != NULL) { 386 l2cap_disconnect(sc->sc_ctl, 0); 387 break; 388 } 389 390 if (sc->sc_flags & BTHID_RECONNECT) { 391 sc->sc_flags |= BTHID_CONNECTING; 392 bthidev_connect(sc); 393 break; 394 } 395 396 break; 397 398 case BTHID_WAIT_CTL: 399 break; 400 401 case BTHID_WAIT_INT: 402 break; 403 404 case BTHID_OPEN: 405 break; 406 407 case BTHID_DETACHING: 408 wakeup(sc); 409 break; 410 411 default: 412 break; 413 } 414 splx(s); 415 } 416 417 /* 418 * listen for our device 419 */ 420 static int 421 bthidev_listen(struct bthidev_softc *sc) 422 { 423 struct sockaddr_bt sa; 424 int err; 425 426 memset(&sa, 0, sizeof(sa)); 427 sa.bt_len = sizeof(sa); 428 sa.bt_family = AF_BLUETOOTH; 429 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); 430 431 /* 432 * Listen on control PSM 433 */ 434 err = l2cap_attach(&sc->sc_ctl_l, &bthidev_ctl_proto, sc); 435 if (err) 436 return err; 437 438 sa.bt_psm = sc->sc_ctlpsm; 439 err = l2cap_bind(sc->sc_ctl_l, &sa); 440 if (err) 441 return err; 442 443 err = l2cap_listen(sc->sc_ctl_l); 444 if (err) 445 return err; 446 447 /* 448 * Listen on interrupt PSM 449 */ 450 err = l2cap_attach(&sc->sc_int_l, &bthidev_int_proto, sc); 451 if (err) 452 return err; 453 454 sa.bt_psm = sc->sc_intpsm; 455 err = l2cap_bind(sc->sc_int_l, &sa); 456 if (err) 457 return err; 458 459 err = l2cap_listen(sc->sc_int_l); 460 if (err) 461 return err; 462 463 sc->sc_state = BTHID_WAIT_CTL; 464 return 0; 465 } 466 467 /* 468 * start connecting to our device 469 */ 470 static int 471 bthidev_connect(struct bthidev_softc *sc) 472 { 473 struct sockaddr_bt sa; 474 int err; 475 476 if (sc->sc_attempts++ > 0) 477 printf("%s: connect (#%d)\n", 478 device_xname((struct device *)sc), sc->sc_attempts); 479 480 memset(&sa, 0, sizeof(sa)); 481 sa.bt_len = sizeof(sa); 482 sa.bt_family = AF_BLUETOOTH; 483 484 err = l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc); 485 if (err) { 486 printf("%s: l2cap_attach failed (%d)\n", 487 device_xname((struct device *)sc), err); 488 return err; 489 } 490 491 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); 492 err = l2cap_bind(sc->sc_ctl, &sa); 493 if (err) { 494 printf("%s: l2cap_bind failed (%d)\n", 495 device_xname((struct device *)sc), err); 496 return err; 497 } 498 499 sa.bt_psm = sc->sc_ctlpsm; 500 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); 501 err = l2cap_connect(sc->sc_ctl, &sa); 502 if (err) { 503 printf("%s: l2cap_connect failed (%d)\n", 504 device_xname((struct device *)sc), err); 505 return err; 506 } 507 508 sc->sc_state = BTHID_WAIT_CTL; 509 return 0; 510 } 511 512 /***************************************************************************** 513 * 514 * bluetooth(9) callback methods for L2CAP 515 * 516 * All these are called from Bluetooth Protocol code, in a soft 517 * interrupt context at IPL_SOFTNET. 518 */ 519 520 static void 521 bthidev_connecting(void *arg) 522 { 523 524 /* dont care */ 525 } 526 527 static void 528 bthidev_ctl_connected(void *arg) 529 { 530 struct sockaddr_bt sa; 531 struct bthidev_softc *sc = arg; 532 int err; 533 534 if (sc->sc_state != BTHID_WAIT_CTL) 535 return; 536 537 KASSERT(sc->sc_ctl != NULL); 538 KASSERT(sc->sc_int == NULL); 539 540 if (sc->sc_flags & BTHID_CONNECTING) { 541 /* initiate connect on interrupt PSM */ 542 err = l2cap_attach(&sc->sc_int, &bthidev_int_proto, sc); 543 if (err) 544 goto fail; 545 546 memset(&sa, 0, sizeof(sa)); 547 sa.bt_len = sizeof(sa); 548 sa.bt_family = AF_BLUETOOTH; 549 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); 550 551 err = l2cap_bind(sc->sc_int, &sa); 552 if (err) 553 goto fail; 554 555 sa.bt_psm = sc->sc_intpsm; 556 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); 557 err = l2cap_connect(sc->sc_int, &sa); 558 if (err) 559 goto fail; 560 } 561 562 sc->sc_state = BTHID_WAIT_INT; 563 return; 564 565 fail: 566 l2cap_detach(&sc->sc_ctl); 567 sc->sc_ctl = NULL; 568 569 printf("%s: connect failed (%d)\n", 570 device_xname((struct device *)sc), err); 571 } 572 573 static void 574 bthidev_int_connected(void *arg) 575 { 576 struct bthidev_softc *sc = arg; 577 578 if (sc->sc_state != BTHID_WAIT_INT) 579 return; 580 581 KASSERT(sc->sc_ctl != NULL); 582 KASSERT(sc->sc_int != NULL); 583 584 sc->sc_attempts = 0; 585 sc->sc_flags &= ~BTHID_CONNECTING; 586 sc->sc_state = BTHID_OPEN; 587 588 printf("%s: connected\n", device_xname((struct device *)sc)); 589 } 590 591 /* 592 * Disconnected 593 * 594 * Depending on our state, this could mean several things, but essentially 595 * we are lost. If both channels are closed, and we are marked to reconnect, 596 * schedule another try otherwise just give up. They will contact us. 597 */ 598 static void 599 bthidev_ctl_disconnected(void *arg, int err) 600 { 601 struct bthidev_softc *sc = arg; 602 603 if (sc->sc_ctl != NULL) { 604 l2cap_detach(&sc->sc_ctl); 605 sc->sc_ctl = NULL; 606 } 607 608 sc->sc_state = BTHID_CLOSED; 609 610 if (sc->sc_int == NULL) { 611 printf("%s: disconnected\n", 612 device_xname((struct device *)sc)); 613 sc->sc_flags &= ~BTHID_CONNECTING; 614 615 if (sc->sc_flags & BTHID_RECONNECT) 616 callout_schedule(&sc->sc_reconnect, 617 BTHID_RETRY_INTERVAL * hz); 618 else 619 sc->sc_state = BTHID_WAIT_CTL; 620 } else { 621 /* 622 * The interrupt channel should have been closed first, 623 * but its potentially unsafe to detach that from here. 624 * Give them a second to do the right thing or let the 625 * callout handle it. 626 */ 627 callout_schedule(&sc->sc_reconnect, hz); 628 } 629 } 630 631 static void 632 bthidev_int_disconnected(void *arg, int err) 633 { 634 struct bthidev_softc *sc = arg; 635 636 if (sc->sc_int != NULL) { 637 l2cap_detach(&sc->sc_int); 638 sc->sc_int = NULL; 639 } 640 641 sc->sc_state = BTHID_CLOSED; 642 643 if (sc->sc_ctl == NULL) { 644 printf("%s: disconnected\n", 645 device_xname((struct device *)sc)); 646 sc->sc_flags &= ~BTHID_CONNECTING; 647 648 if (sc->sc_flags & BTHID_RECONNECT) 649 callout_schedule(&sc->sc_reconnect, 650 BTHID_RETRY_INTERVAL * hz); 651 else 652 sc->sc_state = BTHID_WAIT_CTL; 653 } else { 654 /* 655 * The control channel should be closing also, allow 656 * them a chance to do that before we force it. 657 */ 658 callout_schedule(&sc->sc_reconnect, hz); 659 } 660 } 661 662 /* 663 * New Connections 664 * 665 * We give a new L2CAP handle back if this matches the BDADDR we are 666 * listening for and we are in the right state. bthidev_connected will 667 * be called when the connection is open, so nothing else to do here 668 */ 669 static void * 670 bthidev_ctl_newconn(void *arg, struct sockaddr_bt *laddr, 671 struct sockaddr_bt *raddr) 672 { 673 struct bthidev_softc *sc = arg; 674 675 if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0 676 || (sc->sc_flags & BTHID_CONNECTING) 677 || sc->sc_state != BTHID_WAIT_CTL 678 || sc->sc_ctl != NULL 679 || sc->sc_int != NULL) 680 return NULL; 681 682 l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc); 683 return sc->sc_ctl; 684 } 685 686 static void * 687 bthidev_int_newconn(void *arg, struct sockaddr_bt *laddr, 688 struct sockaddr_bt *raddr) 689 { 690 struct bthidev_softc *sc = arg; 691 692 if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0 693 || (sc->sc_flags & BTHID_CONNECTING) 694 || sc->sc_state != BTHID_WAIT_INT 695 || sc->sc_ctl == NULL 696 || sc->sc_int != NULL) 697 return NULL; 698 699 l2cap_attach(&sc->sc_int, &bthidev_int_proto, sc); 700 return sc->sc_int; 701 } 702 703 static void 704 bthidev_complete(void *arg, int count) 705 { 706 707 /* dont care */ 708 } 709 710 /* 711 * Receive reports from the protocol stack. 712 */ 713 static void 714 bthidev_input(void *arg, struct mbuf *m) 715 { 716 struct bthidev_softc *sc = arg; 717 struct bthidev *dev; 718 uint8_t *data; 719 int len; 720 721 if (sc->sc_state != BTHID_OPEN) 722 goto release; 723 724 if (m->m_pkthdr.len > m->m_len) 725 printf("%s: truncating HID report\n", 726 device_xname((struct device *)sc)); 727 728 len = m->m_len; 729 data = mtod(m, uint8_t *); 730 731 if (BTHID_TYPE(data[0]) == BTHID_DATA) { 732 /* 733 * data[0] == type / parameter 734 * data[1] == id 735 * data[2..len] == report 736 */ 737 if (len < 3) 738 goto release; 739 740 LIST_FOREACH(dev, &sc->sc_list, sc_next) { 741 if (data[1] == dev->sc_id) { 742 switch (BTHID_DATA_PARAM(data[0])) { 743 case BTHID_DATA_INPUT: 744 (*dev->sc_input)(dev, data + 2, len - 2); 745 break; 746 747 case BTHID_DATA_FEATURE: 748 (*dev->sc_feature)(dev, data + 2, len - 2); 749 break; 750 751 default: 752 break; 753 } 754 755 goto release; 756 } 757 } 758 printf("%s: report id %d, len = %d ignored\n", 759 device_xname((struct device *)sc), data[1], len - 2); 760 761 goto release; 762 } 763 764 if (BTHID_TYPE(data[0]) == BTHID_CONTROL) { 765 if (len < 1) 766 goto release; 767 768 if (BTHID_DATA_PARAM(data[0]) == BTHID_CONTROL_UNPLUG) { 769 printf("%s: unplugged\n", 770 device_xname((struct device *)sc)); 771 772 /* close interrupt channel */ 773 if (sc->sc_int != NULL) { 774 l2cap_disconnect(sc->sc_int, 0); 775 l2cap_detach(&sc->sc_int); 776 sc->sc_int = NULL; 777 } 778 779 /* close control channel */ 780 if (sc->sc_ctl != NULL) { 781 l2cap_disconnect(sc->sc_ctl, 0); 782 l2cap_detach(&sc->sc_ctl); 783 sc->sc_ctl = NULL; 784 } 785 } 786 787 goto release; 788 } 789 790 release: 791 m_freem(m); 792 } 793 794 /***************************************************************************** 795 * 796 * IO routines 797 */ 798 799 static void 800 bthidev_null(struct bthidev *dev, uint8_t *report, 801 int len) 802 { 803 804 /* 805 * empty routine just in case the device 806 * provided no method to handle this report 807 */ 808 } 809 810 static int 811 bthidev_output(struct bthidev *dev, uint8_t *report, int rlen) 812 { 813 struct bthidev_softc *sc = (struct bthidev_softc *)dev->sc_parent; 814 struct mbuf *m; 815 int s, err; 816 817 if (sc == NULL || sc->sc_state != BTHID_OPEN) 818 return ENOTCONN; 819 820 KASSERT(sc->sc_ctl != NULL); 821 KASSERT(sc->sc_int != NULL); 822 823 if (rlen == 0 || report == NULL) 824 return 0; 825 826 if (rlen > MHLEN - 2) { 827 printf("%s: output report too long (%d)!\n", 828 device_xname((struct device *)sc), rlen); 829 830 return EMSGSIZE; 831 } 832 833 m = m_gethdr(M_DONTWAIT, MT_DATA); 834 if (m == NULL) 835 return ENOMEM; 836 837 /* 838 * data[0] = type / parameter 839 * data[1] = id 840 * data[2..N] = report 841 */ 842 mtod(m, uint8_t *)[0] = (uint8_t)((BTHID_DATA << 4) | BTHID_DATA_OUTPUT); 843 mtod(m, uint8_t *)[1] = dev->sc_id; 844 memcpy(mtod(m, uint8_t *) + 2, report, rlen); 845 m->m_pkthdr.len = m->m_len = rlen + 2; 846 847 s = splsoftnet(); 848 err = l2cap_send(sc->sc_int, m); 849 splx(s); 850 851 return err; 852 } 853