1 /* $NetBSD: bthidev.c,v 1.17 2009/05/12 12:10:46 cegger Exp $ */
4 * Copyright (c) 2006 Itronix Inc.
7 * Written by Iain Hibbert for Itronix Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: bthidev.c,v 1.17 2009/05/12 12:10:46 cegger Exp $");
37 #include <sys/param.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>
46 #include <sys/socketvar.h>
47 #include <sys/systm.h>
49 #include <prop/proplib.h>
51 #include <netbt/bluetooth.h>
52 #include <netbt/l2cap.h>
54 #include <dev/usb/hid.h>
55 #include <dev/bluetooth/btdev.h>
56 #include <dev/bluetooth/bthid.h>
57 #include <dev/bluetooth/bthidev.h>
61 /*****************************************************************************
63 * Bluetooth HID device
66 #define MAX_DESCRIPTOR_LEN 1024 /* sanity check */
69 struct bthidev_softc
{
74 bdaddr_t sc_laddr
; /* local address */
75 bdaddr_t sc_raddr
; /* remote address */
76 struct sockopt sc_mode
; /* link mode sockopt */
78 uint16_t sc_ctlpsm
; /* control PSM */
79 struct l2cap_channel
*sc_ctl
; /* control channel */
80 struct l2cap_channel
*sc_ctl_l
; /* control listen */
82 uint16_t sc_intpsm
; /* interrupt PSM */
83 struct l2cap_channel
*sc_int
; /* interrupt channel */
84 struct l2cap_channel
*sc_int_l
; /* interrupt listen */
86 LIST_HEAD(,bthidev
) sc_list
; /* child list */
88 callout_t sc_reconnect
;
89 int sc_attempts
; /* connection attempts */
93 #define BTHID_RECONNECT (1 << 0) /* reconnect on link loss */
94 #define BTHID_CONNECTING (1 << 1) /* we are connecting */
97 #define BTHID_CLOSED 0
98 #define BTHID_WAIT_CTL 1
99 #define BTHID_WAIT_INT 2
102 #define BTHID_RETRY_INTERVAL 5 /* seconds between connection attempts */
104 /* bthidev internals */
105 static void bthidev_timeout(void *);
106 static int bthidev_listen(struct bthidev_softc
*);
107 static int bthidev_connect(struct bthidev_softc
*);
108 static int bthidev_output(struct bthidev
*, uint8_t *, int);
109 static void bthidev_null(struct bthidev
*, uint8_t *, int);
111 /* autoconf(9) glue */
112 static int bthidev_match(device_t
, cfdata_t
, void *);
113 static void bthidev_attach(device_t
, device_t
, void *);
114 static int bthidev_detach(device_t
, int);
115 static int bthidev_print(void *, const char *);
117 CFATTACH_DECL_NEW(bthidev
, sizeof(struct bthidev_softc
),
118 bthidev_match
, bthidev_attach
, bthidev_detach
, NULL
);
120 /* bluetooth(9) protocol methods for L2CAP */
121 static void bthidev_connecting(void *);
122 static void bthidev_ctl_connected(void *);
123 static void bthidev_int_connected(void *);
124 static void bthidev_ctl_disconnected(void *, int);
125 static void bthidev_int_disconnected(void *, int);
126 static void *bthidev_ctl_newconn(void *, struct sockaddr_bt
*, struct sockaddr_bt
*);
127 static void *bthidev_int_newconn(void *, struct sockaddr_bt
*, struct sockaddr_bt
*);
128 static void bthidev_complete(void *, int);
129 static void bthidev_linkmode(void *, int);
130 static void bthidev_input(void *, struct mbuf
*);
132 static const struct btproto bthidev_ctl_proto
= {
134 bthidev_ctl_connected
,
135 bthidev_ctl_disconnected
,
142 static const struct btproto bthidev_int_proto
= {
144 bthidev_int_connected
,
145 bthidev_int_disconnected
,
152 /*****************************************************************************
154 * bthidev autoconf(9) routines
158 bthidev_match(device_t self
, cfdata_t cfdata
, void *aux
)
160 prop_dictionary_t dict
= aux
;
163 obj
= prop_dictionary_get(dict
, BTDEVservice
);
164 if (prop_string_equals_cstring(obj
, "HID"))
171 bthidev_attach(device_t parent
, device_t self
, void *aux
)
173 struct bthidev_softc
*sc
= device_private(self
);
174 prop_dictionary_t dict
= aux
;
177 struct bthidev_attach_args bha
;
178 struct bthidev
*hidev
;
182 int locs
[BTHIDBUSCF_NLOCS
];
183 int maxid
, rep
, dlen
;
189 LIST_INIT(&sc
->sc_list
);
190 callout_init(&sc
->sc_reconnect
, 0);
191 callout_setfunc(&sc
->sc_reconnect
, bthidev_timeout
, sc
);
192 sc
->sc_state
= BTHID_CLOSED
;
193 sc
->sc_flags
= BTHID_CONNECTING
;
194 sc
->sc_ctlpsm
= L2CAP_PSM_HID_CNTL
;
195 sc
->sc_intpsm
= L2CAP_PSM_HID_INTR
;
197 sockopt_init(&sc
->sc_mode
, BTPROTO_L2CAP
, SO_L2CAP_LM
, 0);
200 * extract config from proplist
202 obj
= prop_dictionary_get(dict
, BTDEVladdr
);
203 bdaddr_copy(&sc
->sc_laddr
, prop_data_data_nocopy(obj
));
205 obj
= prop_dictionary_get(dict
, BTDEVraddr
);
206 bdaddr_copy(&sc
->sc_raddr
, prop_data_data_nocopy(obj
));
208 obj
= prop_dictionary_get(dict
, BTDEVmode
);
209 if (prop_object_type(obj
) == PROP_TYPE_STRING
) {
210 if (prop_string_equals_cstring(obj
, BTDEVauth
))
211 sockopt_setint(&sc
->sc_mode
, L2CAP_LM_AUTH
);
212 else if (prop_string_equals_cstring(obj
, BTDEVencrypt
))
213 sockopt_setint(&sc
->sc_mode
, L2CAP_LM_ENCRYPT
);
214 else if (prop_string_equals_cstring(obj
, BTDEVsecure
))
215 sockopt_setint(&sc
->sc_mode
, L2CAP_LM_SECURE
);
217 aprint_error(" unknown %s\n", BTDEVmode
);
221 aprint_verbose(" %s %s", BTDEVmode
,
222 prop_string_cstring_nocopy(obj
));
225 obj
= prop_dictionary_get(dict
, BTHIDEVcontrolpsm
);
226 if (prop_object_type(obj
) == PROP_TYPE_NUMBER
) {
227 sc
->sc_ctlpsm
= prop_number_integer_value(obj
);
228 if (L2CAP_PSM_INVALID(sc
->sc_ctlpsm
)) {
229 aprint_error(" invalid %s\n", BTHIDEVcontrolpsm
);
234 obj
= prop_dictionary_get(dict
, BTHIDEVinterruptpsm
);
235 if (prop_object_type(obj
) == PROP_TYPE_NUMBER
) {
236 sc
->sc_intpsm
= prop_number_integer_value(obj
);
237 if (L2CAP_PSM_INVALID(sc
->sc_intpsm
)) {
238 aprint_error(" invalid %s\n", BTHIDEVinterruptpsm
);
243 obj
= prop_dictionary_get(dict
, BTHIDEVdescriptor
);
244 if (prop_object_type(obj
) == PROP_TYPE_DATA
) {
245 dlen
= prop_data_size(obj
);
246 desc
= prop_data_data_nocopy(obj
);
248 aprint_error(" no %s\n", BTHIDEVdescriptor
);
252 obj
= prop_dictionary_get(dict
, BTHIDEVreconnect
);
253 if (prop_object_type(obj
) == PROP_TYPE_BOOL
254 && !prop_bool_true(obj
))
255 sc
->sc_flags
|= BTHID_RECONNECT
;
258 * Parse the descriptor and attach child devices, one per report.
262 d
= hid_start_parse(desc
, dlen
, hid_none
);
263 while (hid_get_item(d
, &h
)) {
264 if (h
.report_ID
> maxid
)
270 aprint_error(" no reports found\n");
276 for (rep
= 0 ; rep
<= maxid
; rep
++) {
277 if (hid_report_size(desc
, dlen
, hid_feature
, rep
) == 0
278 && hid_report_size(desc
, dlen
, hid_input
, rep
) == 0
279 && hid_report_size(desc
, dlen
, hid_output
, rep
) == 0)
284 bha
.ba_input
= bthidev_null
;
285 bha
.ba_feature
= bthidev_null
;
286 bha
.ba_output
= bthidev_output
;
289 locs
[BTHIDBUSCF_REPORTID
] = rep
;
291 dev
= config_found_sm_loc(self
, "bthidbus",
292 locs
, &bha
, bthidev_print
, config_stdsubmatch
);
294 hidev
= device_private(dev
);
296 hidev
->sc_parent
= self
;
298 hidev
->sc_input
= bha
.ba_input
;
299 hidev
->sc_feature
= bha
.ba_feature
;
300 LIST_INSERT_HEAD(&sc
->sc_list
, hidev
, sc_next
);
305 * start bluetooth connections
307 mutex_enter(bt_lock
);
308 if ((sc
->sc_flags
& BTHID_RECONNECT
) == 0)
311 if (sc
->sc_flags
& BTHID_CONNECTING
)
317 bthidev_detach(device_t self
, int flags
)
319 struct bthidev_softc
*sc
= device_private(self
);
320 struct bthidev
*hidev
;
322 mutex_enter(bt_lock
);
323 sc
->sc_flags
= 0; /* disable reconnecting */
325 /* release interrupt listen */
326 if (sc
->sc_int_l
!= NULL
) {
327 l2cap_detach(&sc
->sc_int_l
);
331 /* release control listen */
332 if (sc
->sc_ctl_l
!= NULL
) {
333 l2cap_detach(&sc
->sc_ctl_l
);
337 /* close interrupt channel */
338 if (sc
->sc_int
!= NULL
) {
339 l2cap_disconnect(sc
->sc_int
, 0);
340 l2cap_detach(&sc
->sc_int
);
344 /* close control channel */
345 if (sc
->sc_ctl
!= NULL
) {
346 l2cap_disconnect(sc
->sc_ctl
, 0);
347 l2cap_detach(&sc
->sc_ctl
);
351 callout_halt(&sc
->sc_reconnect
, bt_lock
);
352 callout_destroy(&sc
->sc_reconnect
);
356 /* detach children */
357 while ((hidev
= LIST_FIRST(&sc
->sc_list
)) != NULL
) {
358 LIST_REMOVE(hidev
, sc_next
);
359 config_detach(hidev
->sc_dev
, flags
);
362 sockopt_destroy(&sc
->sc_mode
);
368 * bthidev config print
371 bthidev_print(void *aux
, const char *pnp
)
373 struct bthidev_attach_args
*ba
= aux
;
376 aprint_normal("%s:", pnp
);
379 aprint_normal(" reportid %d", ba
->ba_id
);
384 /*****************************************************************************
386 * bluetooth(4) HID attach/detach routines
390 * callouts are scheduled after connections have been lost, in order
391 * to clean up and reconnect.
394 bthidev_timeout(void *arg
)
396 struct bthidev_softc
*sc
= arg
;
398 mutex_enter(bt_lock
);
399 callout_ack(&sc
->sc_reconnect
);
401 switch (sc
->sc_state
) {
403 if (sc
->sc_int
!= NULL
) {
404 l2cap_disconnect(sc
->sc_int
, 0);
408 if (sc
->sc_ctl
!= NULL
) {
409 l2cap_disconnect(sc
->sc_ctl
, 0);
413 if (sc
->sc_flags
& BTHID_RECONNECT
) {
414 sc
->sc_flags
|= BTHID_CONNECTING
;
437 * listen for our device
440 bthidev_listen(struct bthidev_softc
*sc
)
442 struct sockaddr_bt sa
;
445 memset(&sa
, 0, sizeof(sa
));
446 sa
.bt_len
= sizeof(sa
);
447 sa
.bt_family
= AF_BLUETOOTH
;
448 bdaddr_copy(&sa
.bt_bdaddr
, &sc
->sc_laddr
);
451 * Listen on control PSM
453 err
= l2cap_attach(&sc
->sc_ctl_l
, &bthidev_ctl_proto
, sc
);
457 err
= l2cap_setopt(sc
->sc_ctl_l
, &sc
->sc_mode
);
461 sa
.bt_psm
= sc
->sc_ctlpsm
;
462 err
= l2cap_bind(sc
->sc_ctl_l
, &sa
);
466 err
= l2cap_listen(sc
->sc_ctl_l
);
471 * Listen on interrupt PSM
473 err
= l2cap_attach(&sc
->sc_int_l
, &bthidev_int_proto
, sc
);
477 err
= l2cap_setopt(sc
->sc_int_l
, &sc
->sc_mode
);
481 sa
.bt_psm
= sc
->sc_intpsm
;
482 err
= l2cap_bind(sc
->sc_int_l
, &sa
);
486 err
= l2cap_listen(sc
->sc_int_l
);
490 sc
->sc_state
= BTHID_WAIT_CTL
;
495 * start connecting to our device
498 bthidev_connect(struct bthidev_softc
*sc
)
500 struct sockaddr_bt sa
;
503 if (sc
->sc_attempts
++ > 0)
504 aprint_verbose_dev(sc
->sc_dev
, "connect (#%d)\n", sc
->sc_attempts
);
506 memset(&sa
, 0, sizeof(sa
));
507 sa
.bt_len
= sizeof(sa
);
508 sa
.bt_family
= AF_BLUETOOTH
;
510 err
= l2cap_attach(&sc
->sc_ctl
, &bthidev_ctl_proto
, sc
);
512 aprint_error_dev(sc
->sc_dev
, "l2cap_attach failed (%d)\n", err
);
516 err
= l2cap_setopt(sc
->sc_ctl
, &sc
->sc_mode
);
520 bdaddr_copy(&sa
.bt_bdaddr
, &sc
->sc_laddr
);
521 err
= l2cap_bind(sc
->sc_ctl
, &sa
);
523 aprint_error_dev(sc
->sc_dev
, "l2cap_bind failed (%d)\n", err
);
527 sa
.bt_psm
= sc
->sc_ctlpsm
;
528 bdaddr_copy(&sa
.bt_bdaddr
, &sc
->sc_raddr
);
529 err
= l2cap_connect(sc
->sc_ctl
, &sa
);
531 aprint_error_dev(sc
->sc_dev
, "l2cap_connect failed (%d)\n", err
);
535 sc
->sc_state
= BTHID_WAIT_CTL
;
539 /*****************************************************************************
541 * bluetooth(9) callback methods for L2CAP
543 * All these are called from Bluetooth Protocol code, in a soft
544 * interrupt context at IPL_SOFTNET.
548 bthidev_connecting(void *arg
)
555 bthidev_ctl_connected(void *arg
)
557 struct sockaddr_bt sa
;
558 struct bthidev_softc
*sc
= arg
;
561 if (sc
->sc_state
!= BTHID_WAIT_CTL
)
564 KASSERT(sc
->sc_ctl
!= NULL
);
565 KASSERT(sc
->sc_int
== NULL
);
567 if (sc
->sc_flags
& BTHID_CONNECTING
) {
568 /* initiate connect on interrupt PSM */
569 err
= l2cap_attach(&sc
->sc_int
, &bthidev_int_proto
, sc
);
573 err
= l2cap_setopt(sc
->sc_int
, &sc
->sc_mode
);
577 memset(&sa
, 0, sizeof(sa
));
578 sa
.bt_len
= sizeof(sa
);
579 sa
.bt_family
= AF_BLUETOOTH
;
580 bdaddr_copy(&sa
.bt_bdaddr
, &sc
->sc_laddr
);
582 err
= l2cap_bind(sc
->sc_int
, &sa
);
586 sa
.bt_psm
= sc
->sc_intpsm
;
587 bdaddr_copy(&sa
.bt_bdaddr
, &sc
->sc_raddr
);
588 err
= l2cap_connect(sc
->sc_int
, &sa
);
593 sc
->sc_state
= BTHID_WAIT_INT
;
597 l2cap_detach(&sc
->sc_ctl
);
600 aprint_error_dev(sc
->sc_dev
, "connect failed (%d)\n", err
);
604 bthidev_int_connected(void *arg
)
606 struct bthidev_softc
*sc
= arg
;
608 if (sc
->sc_state
!= BTHID_WAIT_INT
)
611 KASSERT(sc
->sc_ctl
!= NULL
);
612 KASSERT(sc
->sc_int
!= NULL
);
615 sc
->sc_flags
&= ~BTHID_CONNECTING
;
616 sc
->sc_state
= BTHID_OPEN
;
618 aprint_normal_dev(sc
->sc_dev
, "connected\n");
624 * Depending on our state, this could mean several things, but essentially
625 * we are lost. If both channels are closed, and we are marked to reconnect,
626 * schedule another try otherwise just give up. They will contact us.
629 bthidev_ctl_disconnected(void *arg
, int err
)
631 struct bthidev_softc
*sc
= arg
;
633 if (sc
->sc_ctl
!= NULL
) {
634 l2cap_detach(&sc
->sc_ctl
);
638 sc
->sc_state
= BTHID_CLOSED
;
640 if (sc
->sc_int
== NULL
) {
641 aprint_normal_dev(sc
->sc_dev
, "disconnected\n");
642 sc
->sc_flags
&= ~BTHID_CONNECTING
;
644 if (sc
->sc_flags
& BTHID_RECONNECT
)
645 callout_schedule(&sc
->sc_reconnect
,
646 BTHID_RETRY_INTERVAL
* hz
);
648 sc
->sc_state
= BTHID_WAIT_CTL
;
651 * The interrupt channel should have been closed first,
652 * but its potentially unsafe to detach that from here.
653 * Give them a second to do the right thing or let the
656 callout_schedule(&sc
->sc_reconnect
, hz
);
661 bthidev_int_disconnected(void *arg
, int err
)
663 struct bthidev_softc
*sc
= arg
;
665 if (sc
->sc_int
!= NULL
) {
666 l2cap_detach(&sc
->sc_int
);
670 sc
->sc_state
= BTHID_CLOSED
;
672 if (sc
->sc_ctl
== NULL
) {
673 aprint_normal_dev(sc
->sc_dev
, "disconnected\n");
674 sc
->sc_flags
&= ~BTHID_CONNECTING
;
676 if (sc
->sc_flags
& BTHID_RECONNECT
)
677 callout_schedule(&sc
->sc_reconnect
,
678 BTHID_RETRY_INTERVAL
* hz
);
680 sc
->sc_state
= BTHID_WAIT_CTL
;
683 * The control channel should be closing also, allow
684 * them a chance to do that before we force it.
686 callout_schedule(&sc
->sc_reconnect
, hz
);
693 * We give a new L2CAP handle back if this matches the BDADDR we are
694 * listening for and we are in the right state. bthidev_connected will
695 * be called when the connection is open, so nothing else to do here
698 bthidev_ctl_newconn(void *arg
, struct sockaddr_bt
*laddr
,
699 struct sockaddr_bt
*raddr
)
701 struct bthidev_softc
*sc
= arg
;
703 if (bdaddr_same(&raddr
->bt_bdaddr
, &sc
->sc_raddr
) == 0)
706 if ((sc
->sc_flags
& BTHID_CONNECTING
)
707 || sc
->sc_state
!= BTHID_WAIT_CTL
708 || sc
->sc_ctl
!= NULL
709 || sc
->sc_int
!= NULL
) {
710 aprint_verbose_dev(sc
->sc_dev
, "reject ctl newconn %s%s%s%s\n",
711 (sc
->sc_flags
& BTHID_CONNECTING
) ? " (CONNECTING)" : "",
712 (sc
->sc_state
== BTHID_WAIT_CTL
) ? " (WAITING)": "",
713 (sc
->sc_ctl
!= NULL
) ? " (GOT CONTROL)" : "",
714 (sc
->sc_int
!= NULL
) ? " (GOT INTERRUPT)" : "");
719 l2cap_attach(&sc
->sc_ctl
, &bthidev_ctl_proto
, sc
);
724 bthidev_int_newconn(void *arg
, struct sockaddr_bt
*laddr
,
725 struct sockaddr_bt
*raddr
)
727 struct bthidev_softc
*sc
= arg
;
729 if (bdaddr_same(&raddr
->bt_bdaddr
, &sc
->sc_raddr
) == 0)
732 if ((sc
->sc_flags
& BTHID_CONNECTING
)
733 || sc
->sc_state
!= BTHID_WAIT_INT
734 || sc
->sc_ctl
== NULL
735 || sc
->sc_int
!= NULL
) {
736 aprint_verbose_dev(sc
->sc_dev
, "reject int newconn %s%s%s%s\n",
737 (sc
->sc_flags
& BTHID_CONNECTING
) ? " (CONNECTING)" : "",
738 (sc
->sc_state
== BTHID_WAIT_INT
) ? " (WAITING)": "",
739 (sc
->sc_ctl
== NULL
) ? " (NO CONTROL)" : "",
740 (sc
->sc_int
!= NULL
) ? " (GOT INTERRUPT)" : "");
745 l2cap_attach(&sc
->sc_int
, &bthidev_int_proto
, sc
);
750 bthidev_complete(void *arg
, int count
)
757 bthidev_linkmode(void *arg
, int new)
759 struct bthidev_softc
*sc
= arg
;
762 (void)sockopt_getint(&sc
->sc_mode
, &mode
);
764 if ((mode
& L2CAP_LM_AUTH
) && !(new & L2CAP_LM_AUTH
))
765 aprint_error_dev(sc
->sc_dev
, "auth failed\n");
766 else if ((mode
& L2CAP_LM_ENCRYPT
) && !(new & L2CAP_LM_ENCRYPT
))
767 aprint_error_dev(sc
->sc_dev
, "encrypt off\n");
768 else if ((mode
& L2CAP_LM_SECURE
) && !(new & L2CAP_LM_SECURE
))
769 aprint_error_dev(sc
->sc_dev
, "insecure\n");
773 if (sc
->sc_int
!= NULL
)
774 l2cap_disconnect(sc
->sc_int
, 0);
776 if (sc
->sc_ctl
!= NULL
)
777 l2cap_disconnect(sc
->sc_ctl
, 0);
781 * Receive reports from the protocol stack.
784 bthidev_input(void *arg
, struct mbuf
*m
)
786 struct bthidev_softc
*sc
= arg
;
787 struct bthidev
*hidev
;
791 if (sc
->sc_state
!= BTHID_OPEN
)
794 if (m
->m_pkthdr
.len
> m
->m_len
)
795 aprint_error_dev(sc
->sc_dev
, "truncating HID report\n");
798 data
= mtod(m
, uint8_t *);
800 if (BTHID_TYPE(data
[0]) == BTHID_DATA
) {
802 * data[0] == type / parameter
804 * data[2..len] == report
809 LIST_FOREACH(hidev
, &sc
->sc_list
, sc_next
) {
810 if (data
[1] == hidev
->sc_id
) {
811 switch (BTHID_DATA_PARAM(data
[0])) {
812 case BTHID_DATA_INPUT
:
813 (*hidev
->sc_input
)(hidev
, data
+ 2, len
- 2);
816 case BTHID_DATA_FEATURE
:
817 (*hidev
->sc_feature
)(hidev
, data
+ 2, len
- 2);
827 aprint_error_dev(sc
->sc_dev
, "report id %d, len = %d ignored\n",
833 if (BTHID_TYPE(data
[0]) == BTHID_CONTROL
) {
837 if (BTHID_DATA_PARAM(data
[0]) == BTHID_CONTROL_UNPLUG
) {
838 aprint_normal_dev(sc
->sc_dev
, "unplugged\n");
840 /* close interrupt channel */
841 if (sc
->sc_int
!= NULL
) {
842 l2cap_disconnect(sc
->sc_int
, 0);
843 l2cap_detach(&sc
->sc_int
);
847 /* close control channel */
848 if (sc
->sc_ctl
!= NULL
) {
849 l2cap_disconnect(sc
->sc_ctl
, 0);
850 l2cap_detach(&sc
->sc_ctl
);
862 /*****************************************************************************
868 bthidev_null(struct bthidev
*hidev
, uint8_t *report
, int len
)
872 * empty routine just in case the device
873 * provided no method to handle this report
878 bthidev_output(struct bthidev
*hidev
, uint8_t *report
, int rlen
)
880 struct bthidev_softc
*sc
= device_private(hidev
->sc_parent
);
884 if (sc
== NULL
|| sc
->sc_state
!= BTHID_OPEN
)
887 KASSERT(sc
->sc_ctl
!= NULL
);
888 KASSERT(sc
->sc_int
!= NULL
);
890 if (rlen
== 0 || report
== NULL
)
893 if (rlen
> MHLEN
- 2) {
894 aprint_error_dev(sc
->sc_dev
,
895 "output report too long (%d)!\n", rlen
);
899 m
= m_gethdr(M_DONTWAIT
, MT_DATA
);
904 * data[0] = type / parameter
906 * data[2..N] = report
908 mtod(m
, uint8_t *)[0] = (uint8_t)((BTHID_DATA
<< 4) | BTHID_DATA_OUTPUT
);
909 mtod(m
, uint8_t *)[1] = hidev
->sc_id
;
910 memcpy(mtod(m
, uint8_t *) + 2, report
, rlen
);
911 m
->m_pkthdr
.len
= m
->m_len
= rlen
+ 2;
913 mutex_enter(bt_lock
);
914 err
= l2cap_send(sc
->sc_int
, m
);