xref: /netbsd-src/sys/dev/bluetooth/bthidev.c (revision c0179c282a5968435315a82f4128c61372c68fc3)
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