1 /* $NetBSD: bthidev.c,v 1.4 2006/09/12 18:18:01 plunky 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.4 2006/09/12 18:18:01 plunky 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 /* btdev identity matcher */ 120 static int bthidev_identify(struct btdev *, prop_dictionary_t); 121 122 /* bluetooth(9) protocol methods for L2CAP */ 123 static void bthidev_connecting(void *); 124 static void bthidev_ctl_connected(void *); 125 static void bthidev_int_connected(void *); 126 static void bthidev_ctl_disconnected(void *, int); 127 static void bthidev_int_disconnected(void *, int); 128 static void *bthidev_ctl_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 129 static void *bthidev_int_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 130 static void bthidev_complete(void *, int); 131 static void bthidev_input(void *, struct mbuf *); 132 133 static const struct btproto bthidev_ctl_proto = { 134 bthidev_connecting, 135 bthidev_ctl_connected, 136 bthidev_ctl_disconnected, 137 bthidev_ctl_newconn, 138 bthidev_complete, 139 bthidev_input, 140 }; 141 142 static const struct btproto bthidev_int_proto = { 143 bthidev_connecting, 144 bthidev_int_connected, 145 bthidev_int_disconnected, 146 bthidev_int_newconn, 147 bthidev_complete, 148 bthidev_input, 149 }; 150 151 /***************************************************************************** 152 * 153 * bthidev autoconf(9) routines 154 */ 155 156 static int 157 bthidev_match(struct device *self, struct cfdata *cfdata, void *aux) 158 { 159 prop_dictionary_t dict = aux; 160 prop_object_t obj; 161 162 obj = prop_dictionary_get(dict, BTDEVtype); 163 return prop_string_equals_cstring(obj, "bthidev"); 164 } 165 166 static void 167 bthidev_attach(struct device *parent, struct device *self, void *aux) 168 { 169 struct bthidev_softc *sc = (struct bthidev_softc *)self; 170 prop_dictionary_t dict = aux; 171 prop_object_t obj; 172 struct bthidev_attach_args bha; 173 struct bthidev *dev; 174 struct hid_data *d; 175 struct hid_item h; 176 const void *desc; 177 int locs[BTHIDBUSCF_NLOCS]; 178 int maxid, rep, s, dlen; 179 180 /* 181 * Init softc 182 */ 183 LIST_INIT(&sc->sc_list); 184 callout_init(&sc->sc_reconnect); 185 callout_setfunc(&sc->sc_reconnect, bthidev_timeout, sc); 186 sc->sc_state = BTHID_CLOSED; 187 sc->sc_flags = BTHID_CONNECTING; 188 sc->sc_ctlpsm = L2CAP_PSM_HID_CNTL; 189 sc->sc_intpsm = L2CAP_PSM_HID_INTR; 190 191 sc->sc_btdev.sc_identify = bthidev_identify; 192 193 /* 194 * extract config from proplist 195 */ 196 obj = prop_dictionary_get(dict, BTDEVladdr); 197 bdaddr_copy(&sc->sc_laddr, prop_data_data_nocopy(obj)); 198 199 obj = prop_dictionary_get(dict, BTDEVraddr); 200 bdaddr_copy(&sc->sc_raddr, prop_data_data_nocopy(obj)); 201 202 obj = prop_dictionary_get(dict, BTHIDEVcontrolpsm); 203 if (prop_object_type(obj) == PROP_TYPE_NUMBER) { 204 sc->sc_ctlpsm = prop_number_integer_value(obj); 205 if (L2CAP_PSM_INVALID(sc->sc_ctlpsm)) { 206 aprint_error(" invalid %s\n", BTHIDEVcontrolpsm); 207 return; 208 } 209 } 210 211 obj = prop_dictionary_get(dict, BTHIDEVinterruptpsm); 212 if (prop_object_type(obj) == PROP_TYPE_NUMBER) { 213 sc->sc_intpsm = prop_number_integer_value(obj); 214 if (L2CAP_PSM_INVALID(sc->sc_intpsm)) { 215 aprint_error(" invalid %s\n", BTHIDEVinterruptpsm); 216 return; 217 } 218 } 219 220 obj = prop_dictionary_get(dict, BTHIDEVdescriptor); 221 if (prop_object_type(obj) == PROP_TYPE_DATA) { 222 dlen = prop_data_size(obj); 223 desc = prop_data_data_nocopy(obj); 224 } else { 225 aprint_error(" no %s\n", BTHIDEVdescriptor); 226 return; 227 } 228 229 obj = prop_dictionary_get(dict, BTHIDEVreconnect); 230 if (prop_object_type(obj) == PROP_TYPE_BOOL 231 && !prop_bool_true(obj)) 232 sc->sc_flags |= BTHID_RECONNECT; 233 234 /* 235 * Parse the descriptor and attach child devices, one per report. 236 */ 237 maxid = -1; 238 h.report_ID = 0; 239 d = hid_start_parse(desc, dlen, hid_none); 240 while (hid_get_item(d, &h)) { 241 if (h.report_ID > maxid) 242 maxid = h.report_ID; 243 } 244 hid_end_parse(d); 245 246 if (maxid < 0) { 247 aprint_error(" no reports found\n"); 248 return; 249 } 250 251 aprint_normal("\n"); 252 253 for (rep = 0 ; rep <= maxid ; rep++) { 254 if (hid_report_size(desc, dlen, hid_feature, rep) == 0 255 && hid_report_size(desc, dlen, hid_input, rep) == 0 256 && hid_report_size(desc, dlen, hid_output, rep) == 0) 257 continue; 258 259 bha.ba_desc = desc; 260 bha.ba_dlen = dlen; 261 bha.ba_input = bthidev_null; 262 bha.ba_feature = bthidev_null; 263 bha.ba_output = bthidev_output; 264 bha.ba_id = rep; 265 266 locs[BTHIDBUSCF_REPORTID] = rep; 267 268 dev = (struct bthidev *)config_found_sm_loc((struct device *)sc, "bthidbus", 269 locs, &bha, bthidev_print, config_stdsubmatch); 270 if (dev != NULL) { 271 dev->sc_parent = (struct device *)sc; 272 dev->sc_id = rep; 273 dev->sc_input = bha.ba_input; 274 dev->sc_feature = bha.ba_feature; 275 LIST_INSERT_HEAD(&sc->sc_list, dev, sc_next); 276 } 277 } 278 279 /* 280 * start bluetooth connections 281 */ 282 s = splsoftnet(); 283 if ((sc->sc_flags & BTHID_RECONNECT) == 0) 284 bthidev_listen(sc); 285 286 if (sc->sc_flags & BTHID_CONNECTING) 287 bthidev_connect(sc); 288 splx(s); 289 } 290 291 static int 292 bthidev_detach(struct device *self, int flags) 293 { 294 struct bthidev_softc *sc = (struct bthidev_softc *)self; 295 struct bthidev *dev; 296 int s; 297 298 s = splsoftnet(); 299 sc->sc_flags = 0; /* disable reconnecting */ 300 301 /* release interrupt listen */ 302 if (sc->sc_int_l != NULL) { 303 l2cap_detach(&sc->sc_int_l); 304 sc->sc_int_l = NULL; 305 } 306 307 /* release control listen */ 308 if (sc->sc_ctl_l != NULL) { 309 l2cap_detach(&sc->sc_ctl_l); 310 sc->sc_ctl_l = NULL; 311 } 312 313 /* close interrupt channel */ 314 if (sc->sc_int != NULL) { 315 l2cap_disconnect(sc->sc_int, 0); 316 l2cap_detach(&sc->sc_int); 317 sc->sc_int = NULL; 318 } 319 320 /* close control channel */ 321 if (sc->sc_ctl != NULL) { 322 l2cap_disconnect(sc->sc_ctl, 0); 323 l2cap_detach(&sc->sc_ctl); 324 sc->sc_ctl = NULL; 325 } 326 327 /* remove callout */ 328 sc->sc_state = BTHID_DETACHING; 329 callout_stop(&sc->sc_reconnect); 330 if (callout_invoking(&sc->sc_reconnect)) 331 tsleep(sc, PWAIT, "bthidetach", 0); 332 333 splx(s); 334 335 /* detach children */ 336 while ((dev = LIST_FIRST(&sc->sc_list)) != NULL) { 337 LIST_REMOVE(dev, sc_next); 338 config_detach((struct device *)dev, flags); 339 } 340 341 return 0; 342 } 343 344 /* 345 * bthidev config print 346 */ 347 static int 348 bthidev_print(void *aux, const char *pnp) 349 { 350 struct bthidev_attach_args *ba = aux; 351 352 if (pnp != NULL) 353 aprint_normal("%s:", pnp); 354 355 if (ba->ba_id > 0) 356 aprint_normal(" reportid %d", ba->ba_id); 357 358 return UNCONF; 359 } 360 361 /* 362 * btdev identity matcher 363 */ 364 static int 365 bthidev_identify(struct btdev *dev, prop_dictionary_t dict) 366 { 367 struct bthidev_softc *sc = (struct bthidev_softc *)dev; 368 prop_object_t obj; 369 370 obj = prop_dictionary_get(dict, BTDEVtype); 371 if (!prop_string_equals_cstring(obj, "bthidev")) 372 return 0; 373 374 obj = prop_dictionary_get(dict, BTDEVladdr); 375 if (!prop_data_equals_data(obj, &sc->sc_laddr, sizeof(bdaddr_t))) 376 return 0; 377 378 obj = prop_dictionary_get(dict, BTDEVraddr); 379 if (!prop_data_equals_data(obj, &sc->sc_raddr, sizeof(bdaddr_t))) 380 return 0; 381 382 obj = prop_dictionary_get(dict, BTHIDEVcontrolpsm); 383 if (!prop_number_equals_integer(obj, sc->sc_ctlpsm)) 384 return 0; 385 386 obj = prop_dictionary_get(dict, BTHIDEVinterruptpsm); 387 if (!prop_number_equals_integer(obj, sc->sc_intpsm)) 388 return 0; 389 390 return 1; 391 } 392 393 /***************************************************************************** 394 * 395 * bluetooth(4) HID attach/detach routines 396 */ 397 398 /* 399 * callouts are scheduled after connections have been lost, in order 400 * to clean up and reconnect. 401 */ 402 static void 403 bthidev_timeout(void *arg) 404 { 405 struct bthidev_softc *sc = arg; 406 int s; 407 408 s = splsoftnet(); 409 callout_ack(&sc->sc_reconnect); 410 411 switch (sc->sc_state) { 412 case BTHID_CLOSED: 413 if (sc->sc_int != NULL) { 414 l2cap_disconnect(sc->sc_int, 0); 415 break; 416 } 417 418 if (sc->sc_ctl != NULL) { 419 l2cap_disconnect(sc->sc_ctl, 0); 420 break; 421 } 422 423 if (sc->sc_flags & BTHID_RECONNECT) { 424 sc->sc_flags |= BTHID_CONNECTING; 425 bthidev_connect(sc); 426 break; 427 } 428 429 break; 430 431 case BTHID_WAIT_CTL: 432 break; 433 434 case BTHID_WAIT_INT: 435 break; 436 437 case BTHID_OPEN: 438 break; 439 440 case BTHID_DETACHING: 441 wakeup(sc); 442 break; 443 444 default: 445 break; 446 } 447 splx(s); 448 } 449 450 /* 451 * listen for our device 452 */ 453 static int 454 bthidev_listen(struct bthidev_softc *sc) 455 { 456 struct sockaddr_bt sa; 457 int err; 458 459 memset(&sa, 0, sizeof(sa)); 460 sa.bt_len = sizeof(sa); 461 sa.bt_family = AF_BLUETOOTH; 462 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); 463 464 /* 465 * Listen on control PSM 466 */ 467 err = l2cap_attach(&sc->sc_ctl_l, &bthidev_ctl_proto, sc); 468 if (err) 469 return err; 470 471 sa.bt_psm = sc->sc_ctlpsm; 472 err = l2cap_bind(sc->sc_ctl_l, &sa); 473 if (err) 474 return err; 475 476 err = l2cap_listen(sc->sc_ctl_l); 477 if (err) 478 return err; 479 480 /* 481 * Listen on interrupt PSM 482 */ 483 err = l2cap_attach(&sc->sc_int_l, &bthidev_int_proto, sc); 484 if (err) 485 return err; 486 487 sa.bt_psm = sc->sc_intpsm; 488 err = l2cap_bind(sc->sc_int_l, &sa); 489 if (err) 490 return err; 491 492 err = l2cap_listen(sc->sc_int_l); 493 if (err) 494 return err; 495 496 sc->sc_state = BTHID_WAIT_CTL; 497 return 0; 498 } 499 500 /* 501 * start connecting to our device 502 */ 503 static int 504 bthidev_connect(struct bthidev_softc *sc) 505 { 506 struct sockaddr_bt sa; 507 int err; 508 509 if (sc->sc_attempts++ > 0) 510 printf("%s: connect (#%d)\n", 511 device_xname((struct device *)sc), sc->sc_attempts); 512 513 memset(&sa, 0, sizeof(sa)); 514 sa.bt_len = sizeof(sa); 515 sa.bt_family = AF_BLUETOOTH; 516 517 err = l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc); 518 if (err) { 519 printf("%s: l2cap_attach failed (%d)\n", 520 device_xname((struct device *)sc), err); 521 return err; 522 } 523 524 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); 525 err = l2cap_bind(sc->sc_ctl, &sa); 526 if (err) { 527 printf("%s: l2cap_bind failed (%d)\n", 528 device_xname((struct device *)sc), err); 529 return err; 530 } 531 532 sa.bt_psm = sc->sc_ctlpsm; 533 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); 534 err = l2cap_connect(sc->sc_ctl, &sa); 535 if (err) { 536 printf("%s: l2cap_connect failed (%d)\n", 537 device_xname((struct device *)sc), err); 538 return err; 539 } 540 541 sc->sc_state = BTHID_WAIT_CTL; 542 return 0; 543 } 544 545 /***************************************************************************** 546 * 547 * bluetooth(9) callback methods for L2CAP 548 * 549 * All these are called from Bluetooth Protocol code, in a soft 550 * interrupt context at IPL_SOFTNET. 551 */ 552 553 static void 554 bthidev_connecting(void *arg) 555 { 556 557 /* dont care */ 558 } 559 560 static void 561 bthidev_ctl_connected(void *arg) 562 { 563 struct sockaddr_bt sa; 564 struct bthidev_softc *sc = arg; 565 int err; 566 567 if (sc->sc_state != BTHID_WAIT_CTL) 568 return; 569 570 KASSERT(sc->sc_ctl != NULL); 571 KASSERT(sc->sc_int == NULL); 572 573 if (sc->sc_flags & BTHID_CONNECTING) { 574 /* initiate connect on interrupt PSM */ 575 err = l2cap_attach(&sc->sc_int, &bthidev_int_proto, sc); 576 if (err) 577 goto fail; 578 579 memset(&sa, 0, sizeof(sa)); 580 sa.bt_len = sizeof(sa); 581 sa.bt_family = AF_BLUETOOTH; 582 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); 583 584 err = l2cap_bind(sc->sc_int, &sa); 585 if (err) 586 goto fail; 587 588 sa.bt_psm = sc->sc_intpsm; 589 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); 590 err = l2cap_connect(sc->sc_int, &sa); 591 if (err) 592 goto fail; 593 } 594 595 sc->sc_state = BTHID_WAIT_INT; 596 return; 597 598 fail: 599 l2cap_detach(&sc->sc_ctl); 600 sc->sc_ctl = NULL; 601 602 printf("%s: connect failed (%d)\n", 603 device_xname((struct device *)sc), err); 604 } 605 606 static void 607 bthidev_int_connected(void *arg) 608 { 609 struct bthidev_softc *sc = arg; 610 611 if (sc->sc_state != BTHID_WAIT_INT) 612 return; 613 614 KASSERT(sc->sc_ctl != NULL); 615 KASSERT(sc->sc_int != NULL); 616 617 sc->sc_attempts = 0; 618 sc->sc_flags &= ~BTHID_CONNECTING; 619 sc->sc_state = BTHID_OPEN; 620 621 printf("%s: connected\n", device_xname((struct device *)sc)); 622 } 623 624 /* 625 * Disconnected 626 * 627 * Depending on our state, this could mean several things, but essentially 628 * we are lost. If both channels are closed, and we are marked to reconnect, 629 * schedule another try otherwise just give up. They will contact us. 630 */ 631 static void 632 bthidev_ctl_disconnected(void *arg, int err) 633 { 634 struct bthidev_softc *sc = arg; 635 636 if (sc->sc_ctl != NULL) { 637 l2cap_detach(&sc->sc_ctl); 638 sc->sc_ctl = NULL; 639 } 640 641 sc->sc_state = BTHID_CLOSED; 642 643 if (sc->sc_int == 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 interrupt channel should have been closed first, 656 * but its potentially unsafe to detach that from here. 657 * Give them a second to do the right thing or let the 658 * callout handle it. 659 */ 660 callout_schedule(&sc->sc_reconnect, hz); 661 } 662 } 663 664 static void 665 bthidev_int_disconnected(void *arg, int err) 666 { 667 struct bthidev_softc *sc = arg; 668 669 if (sc->sc_int != NULL) { 670 l2cap_detach(&sc->sc_int); 671 sc->sc_int = NULL; 672 } 673 674 sc->sc_state = BTHID_CLOSED; 675 676 if (sc->sc_ctl == NULL) { 677 printf("%s: disconnected\n", 678 device_xname((struct device *)sc)); 679 sc->sc_flags &= ~BTHID_CONNECTING; 680 681 if (sc->sc_flags & BTHID_RECONNECT) 682 callout_schedule(&sc->sc_reconnect, 683 BTHID_RETRY_INTERVAL * hz); 684 else 685 sc->sc_state = BTHID_WAIT_CTL; 686 } else { 687 /* 688 * The control channel should be closing also, allow 689 * them a chance to do that before we force it. 690 */ 691 callout_schedule(&sc->sc_reconnect, hz); 692 } 693 } 694 695 /* 696 * New Connections 697 * 698 * We give a new L2CAP handle back if this matches the BDADDR we are 699 * listening for and we are in the right state. bthidev_connected will 700 * be called when the connection is open, so nothing else to do here 701 */ 702 static void * 703 bthidev_ctl_newconn(void *arg, struct sockaddr_bt *laddr, struct sockaddr_bt *raddr) 704 { 705 struct bthidev_softc *sc = arg; 706 707 if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0 708 || (sc->sc_flags & BTHID_CONNECTING) 709 || sc->sc_state != BTHID_WAIT_CTL 710 || sc->sc_ctl != NULL 711 || sc->sc_int != NULL) 712 return NULL; 713 714 l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc); 715 return sc->sc_ctl; 716 } 717 718 static void * 719 bthidev_int_newconn(void *arg, struct sockaddr_bt *laddr, struct sockaddr_bt *raddr) 720 { 721 struct bthidev_softc *sc = arg; 722 723 if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0 724 || (sc->sc_flags & BTHID_CONNECTING) 725 || sc->sc_state != BTHID_WAIT_INT 726 || sc->sc_ctl == NULL 727 || sc->sc_int != NULL) 728 return NULL; 729 730 l2cap_attach(&sc->sc_int, &bthidev_int_proto, sc); 731 return sc->sc_int; 732 } 733 734 static void 735 bthidev_complete(void *arg, int count) 736 { 737 738 /* dont care */ 739 } 740 741 /* 742 * Receive reports from the protocol stack. 743 */ 744 static void 745 bthidev_input(void *arg, struct mbuf *m) 746 { 747 struct bthidev_softc *sc = arg; 748 struct bthidev *dev; 749 uint8_t *data; 750 int len; 751 752 if (sc->sc_state != BTHID_OPEN) 753 goto release; 754 755 if (m->m_pkthdr.len > m->m_len) 756 printf("%s: truncating HID report\n", 757 device_xname((struct device *)sc)); 758 759 len = m->m_len; 760 data = mtod(m, uint8_t *); 761 762 if (BTHID_TYPE(data[0]) == BTHID_DATA) { 763 /* 764 * data[0] == type / parameter 765 * data[1] == id 766 * data[2..len] == report 767 */ 768 if (len < 3) 769 goto release; 770 771 LIST_FOREACH(dev, &sc->sc_list, sc_next) { 772 if (data[1] == dev->sc_id) { 773 switch (BTHID_DATA_PARAM(data[0])) { 774 case BTHID_DATA_INPUT: 775 (*dev->sc_input)(dev, data + 2, len - 2); 776 break; 777 778 case BTHID_DATA_FEATURE: 779 (*dev->sc_feature)(dev, data + 2, len - 2); 780 break; 781 782 default: 783 break; 784 } 785 786 goto release; 787 } 788 } 789 printf("%s: report id %d, len = %d ignored\n", 790 device_xname((struct device *)sc), data[1], len - 2); 791 792 goto release; 793 } 794 795 if (BTHID_TYPE(data[0]) == BTHID_CONTROL) { 796 if (len < 1) 797 goto release; 798 799 if (BTHID_DATA_PARAM(data[0]) == BTHID_CONTROL_UNPLUG) { 800 printf("%s: unplugged\n", 801 device_xname((struct device *)sc)); 802 803 /* close interrupt channel */ 804 if (sc->sc_int != NULL) { 805 l2cap_disconnect(sc->sc_int, 0); 806 l2cap_detach(&sc->sc_int); 807 sc->sc_int = NULL; 808 } 809 810 /* close control channel */ 811 if (sc->sc_ctl != NULL) { 812 l2cap_disconnect(sc->sc_ctl, 0); 813 l2cap_detach(&sc->sc_ctl); 814 sc->sc_ctl = NULL; 815 } 816 } 817 818 goto release; 819 } 820 821 release: 822 m_freem(m); 823 } 824 825 /***************************************************************************** 826 * 827 * IO routines 828 */ 829 830 static void 831 bthidev_null(struct bthidev *dev, uint8_t *report, int len) 832 { 833 834 /* 835 * empty routine just in case the device 836 * provided no method to handle this report 837 */ 838 } 839 840 static int 841 bthidev_output(struct bthidev *dev, uint8_t *report, int rlen) 842 { 843 struct bthidev_softc *sc = (struct bthidev_softc *)dev->sc_parent; 844 struct mbuf *m; 845 int s, err; 846 847 if (sc == NULL || sc->sc_state != BTHID_OPEN) 848 return ENOTCONN; 849 850 KASSERT(sc->sc_ctl != NULL); 851 KASSERT(sc->sc_int != NULL); 852 853 if (rlen == 0 || report == NULL) 854 return 0; 855 856 if (rlen > MHLEN - 2) { 857 printf("%s: output report too long (%d)!\n", 858 device_xname((struct device *)sc), rlen); 859 860 return EMSGSIZE; 861 } 862 863 m = m_gethdr(M_DONTWAIT, MT_DATA); 864 if (m == NULL) 865 return ENOMEM; 866 867 /* 868 * data[0] = type / parameter 869 * data[1] = id 870 * data[2..N] = report 871 */ 872 mtod(m, uint8_t *)[0] = (uint8_t)((BTHID_DATA << 4) | BTHID_DATA_OUTPUT); 873 mtod(m, uint8_t *)[1] = dev->sc_id; 874 memcpy(mtod(m, uint8_t *) + 2, report, rlen); 875 m->m_pkthdr.len = m->m_len = rlen + 2; 876 877 s = splsoftnet(); 878 err = l2cap_send(sc->sc_int, m); 879 splx(s); 880 881 return err; 882 } 883