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