bthidev.c revision 1.1.8.2 1 /* $NetBSD: bthidev.c,v 1.1.8.2 2006/07/13 17:49:22 gdamore 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.1.8.2 2006/07/13 17:49:22 gdamore 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 <netbt/bluetooth.h>
49 #include <netbt/l2cap.h>
50
51 #include <dev/usb/hid.h>
52 #include <dev/bluetooth/btdev.h>
53 #include <dev/bluetooth/bthid.h>
54 #include <dev/bluetooth/bthidev.h>
55
56 #include "locators.h"
57
58 /*****************************************************************************
59 *
60 * Bluetooth HID device
61 */
62
63 MALLOC_DEFINE(M_BTHIDEV, "bthidev", "Bluetooth HID Memory");
64
65 #define MAX_DESCRIPTOR_LEN 1024 /* sanity check */
66
67 /* bthidev softc */
68 struct bthidev_softc {
69 struct btdev sc_btdev; /* device+ */
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 void *sc_desc; /* HID descriptor */
77 int sc_dlen; /* descriptor length */
78
79 uint16_t sc_ctlpsm; /* control PSM */
80 struct l2cap_channel *sc_ctl; /* control channel */
81 struct l2cap_channel *sc_ctl_l; /* control listen */
82
83 uint16_t sc_intpsm; /* interrupt PSM */
84 struct l2cap_channel *sc_int; /* interrupt channel */
85 struct l2cap_channel *sc_int_l; /* interrupt listen */
86
87 LIST_HEAD(,bthidev) sc_list; /* child list */
88
89 struct callout sc_reconnect;
90 int sc_attempts; /* connection attempts */
91 };
92
93 /* device state */
94 #define BTHID_CLOSED 0
95 #define BTHID_WAIT_CTL 1
96 #define BTHID_WAIT_INT 2
97 #define BTHID_OPEN 3
98 #define BTHID_DETACHING 4
99
100 #define BTHID_RETRY_INTERVAL 5 /* seconds between connection attempts */
101
102 /* bthidev internals */
103 static void bthidev_timeout(void *);
104 static int bthidev_listen(struct bthidev_softc *);
105 static int bthidev_connect(struct bthidev_softc *);
106 static int bthidev_output(struct bthidev *, uint8_t *, int);
107 static void bthidev_null(struct bthidev *, uint8_t *, int);
108
109 /* autoconf(9) glue */
110 static int bthidev_match(struct device *, struct cfdata *, void *);
111 static void bthidev_attach(struct device *, struct device *, void *);
112 static int bthidev_detach(struct device *, int);
113 static int bthidev_print(void *, const char *);
114
115 CFATTACH_DECL(bthidev, sizeof(struct bthidev_softc),
116 bthidev_match, bthidev_attach, bthidev_detach, NULL);
117
118 /* bluetooth(9) protocol methods for L2CAP */
119 static void bthidev_connecting(void *);
120 static void bthidev_ctl_connected(void *);
121 static void bthidev_int_connected(void *);
122 static void bthidev_ctl_disconnected(void *, int);
123 static void bthidev_int_disconnected(void *, int);
124 static void *bthidev_ctl_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
125 static void *bthidev_int_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
126 static void bthidev_complete(void *, int);
127 static void bthidev_input(void *, struct mbuf *);
128
129 static const struct btproto bthidev_ctl_proto = {
130 bthidev_connecting,
131 bthidev_ctl_connected,
132 bthidev_ctl_disconnected,
133 bthidev_ctl_newconn,
134 bthidev_complete,
135 bthidev_input,
136 };
137
138 static const struct btproto bthidev_int_proto = {
139 bthidev_connecting,
140 bthidev_int_connected,
141 bthidev_int_disconnected,
142 bthidev_int_newconn,
143 bthidev_complete,
144 bthidev_input,
145 };
146
147 /*****************************************************************************
148 *
149 * bthidev autoconf(9) routines
150 */
151
152 static int
153 bthidev_match(struct device *self, struct cfdata *cfdata, void *aux)
154 {
155 struct btdev_attach_args *bda = (struct btdev_attach_args *)aux;
156
157 if (bda->bd_type != BTDEV_HID
158 || L2CAP_PSM_INVALID(bda->bd_hid.hid_ctl)
159 || L2CAP_PSM_INVALID(bda->bd_hid.hid_int)
160 || bda->bd_hid.hid_desc == NULL
161 || bda->bd_hid.hid_dlen == 0
162 || bda->bd_hid.hid_dlen > MAX_DESCRIPTOR_LEN)
163 return 0;
164
165 return 1;
166 }
167
168 static void
169 bthidev_attach(struct device *parent, struct device *self, void *aux)
170 {
171 struct bthidev_softc *sc = (struct bthidev_softc *)self;
172 struct btdev_attach_args *bda = (struct btdev_attach_args *)aux;
173 struct bthidev_attach_args bha;
174 struct bthidev *dev;
175 struct hid_data *d;
176 struct hid_item h;
177 int locs[BTHIDBUSCF_NLOCS];
178 int maxid, rep, s;
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
188 /*
189 * copy in our configuration info
190 */
191 bdaddr_copy(&sc->sc_laddr, &bda->bd_laddr);
192 bdaddr_copy(&sc->sc_raddr, &bda->bd_raddr);
193
194 sc->sc_ctlpsm = bda->bd_hid.hid_ctl;
195 sc->sc_intpsm = bda->bd_hid.hid_int;
196
197 sc->sc_flags = bda->bd_hid.hid_flags;
198 if (sc->sc_flags & BTHID_INITIATE)
199 sc->sc_flags |= BTHID_CONNECT;
200
201 sc->sc_dlen = bda->bd_hid.hid_dlen;
202 sc->sc_desc = malloc(bda->bd_hid.hid_dlen, M_BTHIDEV, M_WAITOK);
203 if (sc->sc_desc == NULL) {
204 aprint_error(" no memory\n");
205 return;
206 }
207 copyin(bda->bd_hid.hid_desc, sc->sc_desc, bda->bd_hid.hid_dlen);
208
209 /*
210 * Parse the descriptor and attach child devices, one per report.
211 */
212 maxid = -1;
213 h.report_ID = 0;
214 d = hid_start_parse(sc->sc_desc, sc->sc_dlen, hid_none);
215 while (hid_get_item(d, &h)) {
216 if (h.report_ID > maxid)
217 maxid = h.report_ID;
218 }
219 hid_end_parse(d);
220
221 if (maxid < 0) {
222 aprint_error(" no reports found\n");
223 return;
224 }
225
226 aprint_normal("\n");
227
228 for (rep = 0 ; rep <= maxid ; rep++) {
229 if (hid_report_size(sc->sc_desc, sc->sc_dlen, hid_feature, rep) == 0
230 && hid_report_size(sc->sc_desc, sc->sc_dlen, hid_input, rep) == 0
231 && hid_report_size(sc->sc_desc, sc->sc_dlen, hid_output, rep) == 0)
232 continue;
233
234 bha.ba_desc = sc->sc_desc;
235 bha.ba_dlen = sc->sc_dlen;
236 bha.ba_input = bthidev_null;
237 bha.ba_feature = bthidev_null;
238 bha.ba_output = bthidev_output;
239 bha.ba_id = rep;
240
241 locs[BTHIDBUSCF_REPORTID] = rep;
242
243 dev = (struct bthidev *)config_found_sm_loc((struct device *)sc, "bthidbus",
244 locs, &bha, bthidev_print, config_stdsubmatch);
245 if (dev != NULL) {
246 dev->sc_parent = &sc->sc_btdev;
247 dev->sc_id = rep;
248 dev->sc_input = bha.ba_input;
249 dev->sc_feature = bha.ba_feature;
250 LIST_INSERT_HEAD(&sc->sc_list, dev, sc_next);
251 }
252 }
253
254 /*
255 * start bluetooth connections
256 */
257 s = splsoftnet();
258 if ((sc->sc_flags & BTHID_INITIATE) == 0)
259 bthidev_listen(sc);
260
261 if (sc->sc_flags & BTHID_CONNECT)
262 bthidev_connect(sc);
263 splx(s);
264 }
265
266 static int
267 bthidev_detach(struct device *self, int flags)
268 {
269 struct bthidev_softc *sc = (struct bthidev_softc *)self;
270 struct bthidev *dev;
271 int s;
272
273 s = splsoftnet();
274 sc->sc_flags = 0; /* disable reconnecting */
275
276 /* release interrupt listen */
277 if (sc->sc_int_l != NULL) {
278 l2cap_detach(&sc->sc_int_l);
279 sc->sc_int_l = NULL;
280 }
281
282 /* release control listen */
283 if (sc->sc_ctl_l != NULL) {
284 l2cap_detach(&sc->sc_ctl_l);
285 sc->sc_ctl_l = NULL;
286 }
287
288 /* close interrupt channel */
289 if (sc->sc_int != NULL) {
290 l2cap_disconnect(sc->sc_int, 0);
291 l2cap_detach(&sc->sc_int);
292 sc->sc_int = NULL;
293 }
294
295 /* close control channel */
296 if (sc->sc_ctl != NULL) {
297 l2cap_disconnect(sc->sc_ctl, 0);
298 l2cap_detach(&sc->sc_ctl);
299 sc->sc_ctl = NULL;
300 }
301
302 /* remove callout */
303 sc->sc_state = BTHID_DETACHING;
304 callout_stop(&sc->sc_reconnect);
305 if (callout_invoking(&sc->sc_reconnect))
306 tsleep(sc, PWAIT, "bthidetach", 0);
307
308 splx(s);
309
310 /* detach children */
311 while ((dev = LIST_FIRST(&sc->sc_list)) != NULL) {
312 LIST_REMOVE(dev, sc_next);
313 config_detach(&dev->sc_dev, flags);
314 }
315
316 /* release descriptor */
317 if (sc->sc_desc != NULL) {
318 free(sc->sc_desc, M_BTHIDEV);
319 sc->sc_desc = NULL;
320 }
321 return 0;
322 }
323
324 /*
325 * bthidev config print
326 */
327 static int
328 bthidev_print(void *aux, const char *pnp)
329 {
330 struct bthidev_attach_args *ba = aux;
331
332 if (pnp != NULL)
333 aprint_normal("%s:", pnp);
334
335 if (ba->ba_id > 0)
336 aprint_normal(" reportid %d", ba->ba_id);
337
338 return UNCONF;
339 }
340
341
342 /*****************************************************************************
343 *
344 * bluetooth(4) HID attach/detach routines
345 */
346
347 /*
348 * callouts are scheduled to initiate outgoing connections
349 * after the connection has been lost.
350 */
351 static void
352 bthidev_timeout(void *arg)
353 {
354 struct bthidev_softc *sc = arg;
355 int s, err;
356
357 s = splsoftnet();
358 callout_ack(&sc->sc_reconnect);
359
360 switch (sc->sc_state) {
361 case BTHID_CLOSED:
362 sc->sc_flags |= BTHID_CONNECT;
363 err = bthidev_connect(sc);
364 if (err)
365 printf("%s: connect failed (%d)\n",
366 btdev_name(sc), err);
367 break;
368
369 case BTHID_WAIT_CTL:
370 break;
371
372 case BTHID_WAIT_INT:
373 break;
374
375 case BTHID_OPEN:
376 break;
377
378 case BTHID_DETACHING:
379 wakeup(sc);
380 break;
381
382 default:
383 break;
384 }
385 splx(s);
386 }
387
388 /*
389 * listen for our device
390 */
391 static int
392 bthidev_listen(struct bthidev_softc *sc)
393 {
394 struct sockaddr_bt sa;
395 int err;
396
397 memset(&sa, 0, sizeof(sa));
398 sa.bt_len = sizeof(sa);
399 sa.bt_family = AF_BLUETOOTH;
400 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr);
401
402 /*
403 * Listen on control PSM
404 */
405 err = l2cap_attach(&sc->sc_ctl_l, &bthidev_ctl_proto, sc);
406 if (err)
407 return err;
408
409 sa.bt_psm = sc->sc_ctlpsm;
410 err = l2cap_bind(sc->sc_ctl_l, &sa);
411 if (err)
412 return err;
413
414 err = l2cap_listen(sc->sc_ctl_l);
415 if (err)
416 return err;
417
418 /*
419 * Listen on interrupt PSM
420 */
421 err = l2cap_attach(&sc->sc_int_l, &bthidev_int_proto, sc);
422 if (err)
423 return err;
424
425 sa.bt_psm = sc->sc_intpsm;
426 err = l2cap_bind(sc->sc_int_l, &sa);
427 if (err)
428 return err;
429
430 err = l2cap_listen(sc->sc_int_l);
431 if (err)
432 return err;
433
434 sc->sc_state = BTHID_WAIT_CTL;
435 return 0;
436 }
437
438 /*
439 * start connecting to our device
440 */
441 static int
442 bthidev_connect(struct bthidev_softc *sc)
443 {
444 struct sockaddr_bt sa;
445 int err;
446
447 if (sc->sc_attempts++ > 0)
448 printf("%s: connect (#%d)\n", btdev_name(sc), sc->sc_attempts);
449
450 memset(&sa, 0, sizeof(sa));
451 sa.bt_len = sizeof(sa);
452 sa.bt_family = AF_BLUETOOTH;
453
454 err = l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc);
455 if (err) {
456 printf("%s: l2cap_attach failed (%d)\n", btdev_name(sc), err);
457 return err;
458 }
459
460 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr);
461 err = l2cap_bind(sc->sc_ctl, &sa);
462 if (err) {
463 printf("%s: l2cap_bind failed (%d)\n", btdev_name(sc), err);
464 return err;
465 }
466
467 sa.bt_psm = sc->sc_ctlpsm;
468 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr);
469 err = l2cap_connect(sc->sc_ctl, &sa);
470 if (err) {
471 printf("%s: l2cap_connect failed (%d)\n", btdev_name(sc), err);
472 return err;
473 }
474
475 sc->sc_state = BTHID_WAIT_CTL;
476 return 0;
477 }
478
479 /*****************************************************************************
480 *
481 * bluetooth(9) callback methods for L2CAP
482 *
483 * All these are called from Bluetooth Protocol code, in a soft
484 * interrupt context at IPL_SOFTNET.
485 */
486
487 static void
488 bthidev_connecting(void *arg)
489 {
490
491 /* dont care */
492 }
493
494 static void
495 bthidev_ctl_connected(void *arg)
496 {
497 struct sockaddr_bt sa;
498 struct bthidev_softc *sc = arg;
499 int err;
500
501 if (sc->sc_state != BTHID_WAIT_CTL)
502 return;
503
504 KASSERT(sc->sc_ctl != NULL);
505 KASSERT(sc->sc_int == NULL);
506
507 if (sc->sc_flags & BTHID_CONNECT) {
508 /* initiate connect on interrupt PSM */
509 err = l2cap_attach(&sc->sc_int, &bthidev_int_proto, sc);
510 if (err)
511 goto fail;
512
513 memset(&sa, 0, sizeof(sa));
514 sa.bt_len = sizeof(sa);
515 sa.bt_family = AF_BLUETOOTH;
516 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr);
517
518 err = l2cap_bind(sc->sc_int, &sa);
519 if (err)
520 goto fail;
521
522 sa.bt_psm = sc->sc_intpsm;
523 bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr);
524 err = l2cap_connect(sc->sc_int, &sa);
525 if (err)
526 goto fail;
527 }
528
529 sc->sc_state = BTHID_WAIT_INT;
530 return;
531
532 fail:
533 l2cap_detach(&sc->sc_ctl);
534 sc->sc_ctl = NULL;
535 printf("%s: connect failed (%d)\n", btdev_name(sc), err);
536 }
537
538 static void
539 bthidev_int_connected(void *arg)
540 {
541 struct bthidev_softc *sc = arg;
542
543 if (sc->sc_state != BTHID_WAIT_INT)
544 return;
545
546 KASSERT(sc->sc_ctl != NULL);
547 KASSERT(sc->sc_int != NULL);
548
549 sc->sc_attempts = 0;
550 sc->sc_flags &= ~BTHID_CONNECT;
551 sc->sc_state = BTHID_OPEN;
552
553 printf("%s: connected\n", btdev_name(sc));
554 }
555
556 /*
557 * Disconnected
558 *
559 * Depending on our state, this could mean several things, but essentially
560 * we are lost.
561 */
562 static void
563 bthidev_ctl_disconnected(void *arg, int err)
564 {
565 struct bthidev_softc *sc = arg;
566
567 if (sc->sc_ctl != NULL) {
568 l2cap_detach(&sc->sc_ctl);
569 sc->sc_ctl = NULL;
570 }
571
572 sc->sc_state = BTHID_CLOSED;
573
574 if (sc->sc_int == NULL) {
575 printf("%s: disconnected\n", btdev_name(sc));
576
577 if (sc->sc_flags & BTHID_INITIATE)
578 callout_schedule(&sc->sc_reconnect,
579 BTHID_RETRY_INTERVAL * hz);
580 else
581 sc->sc_state = BTHID_WAIT_CTL;
582 }
583 }
584
585 static void
586 bthidev_int_disconnected(void *arg, int err)
587 {
588 struct bthidev_softc *sc = arg;
589
590 if (sc->sc_int != NULL) {
591 l2cap_detach(&sc->sc_int);
592 sc->sc_int = NULL;
593 }
594
595 sc->sc_state = BTHID_CLOSED;
596
597 if (sc->sc_ctl == NULL) {
598 printf("%s: disconnected\n", btdev_name(sc));
599
600 if (sc->sc_flags & BTHID_INITIATE)
601 callout_schedule(&sc->sc_reconnect,
602 BTHID_RETRY_INTERVAL * hz);
603 else
604 sc->sc_state = BTHID_WAIT_CTL;
605 }
606 }
607
608 /*
609 * New Connections
610 *
611 * We give a new L2CAP handle back if this matches the BDADDR we are
612 * listening for and we are in the right state. bthidev_connected will
613 * be called when the connection is open, so nothing else to do here
614 */
615 static void *
616 bthidev_ctl_newconn(void *arg, struct sockaddr_bt *laddr, struct sockaddr_bt *raddr)
617 {
618 struct bthidev_softc *sc = arg;
619
620 if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0
621 || (sc->sc_flags & BTHID_INITIATE)
622 || sc->sc_state != BTHID_WAIT_CTL
623 || sc->sc_ctl != NULL
624 || sc->sc_int != NULL)
625 return NULL;
626
627 l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc);
628 return sc->sc_ctl;
629 }
630
631 static void *
632 bthidev_int_newconn(void *arg, struct sockaddr_bt *laddr, struct sockaddr_bt *raddr)
633 {
634 struct bthidev_softc *sc = arg;
635
636 if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0
637 || (sc->sc_flags & BTHID_INITIATE)
638 || sc->sc_state != BTHID_WAIT_INT
639 || sc->sc_ctl == NULL
640 || sc->sc_int != NULL)
641 return NULL;
642
643 l2cap_attach(&sc->sc_int, &bthidev_int_proto, sc);
644 return sc->sc_int;
645 }
646
647 static void
648 bthidev_complete(void *arg, int count)
649 {
650
651 /* dont care */
652 }
653
654 /*
655 * Receive reports from the protocol stack.
656 */
657 static void
658 bthidev_input(void *arg, struct mbuf *m)
659 {
660 struct bthidev_softc *sc = arg;
661 struct bthidev *dev;
662 uint8_t *data;
663 int len;
664
665 if (sc->sc_state != BTHID_OPEN)
666 goto release;
667
668 if (m->m_pkthdr.len > m->m_len)
669 printf("%s: truncating HID report\n", btdev_name(sc));
670
671 len = m->m_len;
672 data = mtod(m, uint8_t *);
673
674 if (BTHID_TYPE(data[0]) == BTHID_DATA) {
675 /*
676 * data[0] == type / parameter
677 * data[1] == id
678 * data[2..len] == report
679 */
680 if (len < 3)
681 goto release;
682
683 LIST_FOREACH(dev, &sc->sc_list, sc_next) {
684 if (data[1] == dev->sc_id) {
685 switch (BTHID_DATA_PARAM(data[0])) {
686 case BTHID_DATA_INPUT:
687 (*dev->sc_input)(dev, data + 2, len - 2);
688 break;
689
690 case BTHID_DATA_FEATURE:
691 (*dev->sc_feature)(dev, data + 2, len - 2);
692 break;
693
694 default:
695 break;
696 }
697
698 goto release;
699 }
700 }
701 printf("%s: report id %d, len = %d ignored\n",
702 btdev_name(sc), data[1], len - 2);
703
704 goto release;
705 }
706
707 if (BTHID_TYPE(data[0]) == BTHID_CONTROL) {
708 if (len < 1)
709 goto release;
710
711 if (BTHID_DATA_PARAM(data[0]) == BTHID_CONTROL_UNPLUG) {
712 printf("%s: unplugged\n", btdev_name(sc));
713
714 /* close interrupt channel */
715 if (sc->sc_int != NULL) {
716 l2cap_disconnect(sc->sc_int, 0);
717 l2cap_detach(&sc->sc_int);
718 sc->sc_int = NULL;
719 }
720
721 /* close control channel */
722 if (sc->sc_ctl != NULL) {
723 l2cap_disconnect(sc->sc_ctl, 0);
724 l2cap_detach(&sc->sc_ctl);
725 sc->sc_ctl = NULL;
726 }
727 }
728
729 goto release;
730 }
731
732 release:
733 m_freem(m);
734 }
735
736 /*****************************************************************************
737 *
738 * IO routines
739 */
740
741 static void
742 bthidev_null(struct bthidev *dev, uint8_t *report, int len)
743 {
744
745 /*
746 * empty routine just in case the device
747 * provided no method to handle this report
748 */
749 }
750
751 static int
752 bthidev_output(struct bthidev *dev, uint8_t *report, int rlen)
753 {
754 struct bthidev_softc *sc = (struct bthidev_softc *)dev->sc_parent;
755 struct mbuf *m;
756 int s, err;
757
758 if (sc == NULL || sc->sc_state != BTHID_OPEN)
759 return ENOTCONN;
760
761 KASSERT(sc->sc_ctl != NULL);
762 KASSERT(sc->sc_int != NULL);
763
764 if (rlen == 0 || report == NULL)
765 return 0;
766
767 if (rlen > MHLEN - 2) {
768 printf("%s: output report too long (%d)!\n",
769 btdev_name(sc), rlen);
770
771 return EMSGSIZE;
772 }
773
774 m = m_gethdr(M_DONTWAIT, MT_DATA);
775 if (m == NULL)
776 return ENOMEM;
777
778 /*
779 * data[0] = type / parameter
780 * data[1] = id
781 * data[2..N] = report
782 */
783 mtod(m, uint8_t *)[0] = (uint8_t)((BTHID_DATA << 4) | BTHID_DATA_OUTPUT);
784 mtod(m, uint8_t *)[1] = dev->sc_id;
785 memcpy(mtod(m, uint8_t *) + 2, report, rlen);
786 m->m_pkthdr.len = m->m_len = rlen + 2;
787
788 s = splsoftnet();
789 err = l2cap_send(sc->sc_int, m);
790 splx(s);
791
792 return err;
793 }
794