xref: /dflybsd-src/sys/netbt/hci_unit.c (revision b272101acc636ac635f83d03265ef6a44a3ba51a)
183aacedeSHasso Tepper /* $OpenBSD: src/sys/netbt/hci_unit.c,v 1.8 2008/02/24 21:34:48 uwe Exp $ */
283aacedeSHasso Tepper /* $NetBSD: hci_unit.c,v 1.9 2007/12/30 18:26:42 plunky Exp $ */
30a9108ebSHasso Tepper 
40a9108ebSHasso Tepper /*-
50a9108ebSHasso Tepper  * Copyright (c) 2005 Iain Hibbert.
60a9108ebSHasso Tepper  * Copyright (c) 2006 Itronix Inc.
70a9108ebSHasso Tepper  * All rights reserved.
80a9108ebSHasso Tepper  *
90a9108ebSHasso Tepper  * Redistribution and use in source and binary forms, with or without
100a9108ebSHasso Tepper  * modification, are permitted provided that the following conditions
110a9108ebSHasso Tepper  * are met:
120a9108ebSHasso Tepper  * 1. Redistributions of source code must retain the above copyright
130a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer.
140a9108ebSHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
150a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
160a9108ebSHasso Tepper  *    documentation and/or other materials provided with the distribution.
170a9108ebSHasso Tepper  * 3. The name of Itronix Inc. may not be used to endorse
180a9108ebSHasso Tepper  *    or promote products derived from this software without specific
190a9108ebSHasso Tepper  *    prior written permission.
200a9108ebSHasso Tepper  *
210a9108ebSHasso Tepper  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
220a9108ebSHasso Tepper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
230a9108ebSHasso Tepper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
240a9108ebSHasso Tepper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
250a9108ebSHasso Tepper  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
260a9108ebSHasso Tepper  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
270a9108ebSHasso Tepper  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
280a9108ebSHasso Tepper  * ON ANY THEORY OF LIABILITY, WHETHER IN
290a9108ebSHasso Tepper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
300a9108ebSHasso Tepper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
310a9108ebSHasso Tepper  * POSSIBILITY OF SUCH DAMAGE.
320a9108ebSHasso Tepper  */
330a9108ebSHasso Tepper 
340a9108ebSHasso Tepper #include <sys/param.h>
350a9108ebSHasso Tepper #include <sys/conf.h>
360a9108ebSHasso Tepper #include <sys/device.h>
370a9108ebSHasso Tepper #include <sys/kernel.h>
380a9108ebSHasso Tepper #include <sys/malloc.h>
390a9108ebSHasso Tepper #include <sys/mbuf.h>
400a9108ebSHasso Tepper #include <sys/proc.h>
410a9108ebSHasso Tepper #include <sys/queue.h>
420a9108ebSHasso Tepper #include <sys/systm.h>
430a9108ebSHasso Tepper #include <sys/endian.h>
440a9108ebSHasso Tepper #include <sys/bus.h>
450a9108ebSHasso Tepper 
460a9108ebSHasso Tepper #include <net/netisr.h>
470a9108ebSHasso Tepper 
480a9108ebSHasso Tepper #include <netbt/bluetooth.h>
490a9108ebSHasso Tepper #include <netbt/hci.h>
500a9108ebSHasso Tepper 
510a9108ebSHasso Tepper struct hci_unit_list hci_unit_list = TAILQ_HEAD_INITIALIZER(hci_unit_list);
520a9108ebSHasso Tepper 
530a9108ebSHasso Tepper /*
540a9108ebSHasso Tepper  * HCI Input Queue max lengths.
550a9108ebSHasso Tepper  */
560a9108ebSHasso Tepper int hci_eventq_max = 20;
570a9108ebSHasso Tepper int hci_aclrxq_max = 50;
580a9108ebSHasso Tepper int hci_scorxq_max = 50;
5983aacedeSHasso Tepper int hci_cmdwait_max = 50;
6083aacedeSHasso Tepper int hci_scodone_max = 50;
6183aacedeSHasso Tepper 
6283aacedeSHasso Tepper /*
6383aacedeSHasso Tepper  * This is the default minimum command set supported by older
6483aacedeSHasso Tepper  * devices. Anything conforming to 1.2 spec or later will get
6583aacedeSHasso Tepper  * updated during init.
6683aacedeSHasso Tepper  */
6783aacedeSHasso Tepper static const uint8_t hci_cmds_v10[HCI_COMMANDS_SIZE] = {
6883aacedeSHasso Tepper 	0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff,
6983aacedeSHasso Tepper 	0xff, 0xff, 0xff, 0x7f, 0x32, 0x03, 0xb8, 0xfe,
7083aacedeSHasso Tepper 	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7183aacedeSHasso Tepper 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7283aacedeSHasso Tepper 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7383aacedeSHasso Tepper 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7483aacedeSHasso Tepper 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7583aacedeSHasso Tepper 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7683aacedeSHasso Tepper };
770a9108ebSHasso Tepper 
780a9108ebSHasso Tepper /*
790a9108ebSHasso Tepper  * bluetooth unit functions
800a9108ebSHasso Tepper  */
810a9108ebSHasso Tepper 
8283aacedeSHasso Tepper struct hci_unit *
hci_attach(const struct hci_if * hci_if,device_t dev,uint16_t flags)835d302545SFrançois Tigeot hci_attach(const struct hci_if *hci_if, device_t dev, uint16_t flags)
840a9108ebSHasso Tepper {
8583aacedeSHasso Tepper 	struct hci_unit *unit;
8683aacedeSHasso Tepper 
8783aacedeSHasso Tepper 	KKASSERT(dev != NULL);
8883aacedeSHasso Tepper 	KKASSERT(hci_if->enable != NULL);
8983aacedeSHasso Tepper 	KKASSERT(hci_if->disable != NULL);
9083aacedeSHasso Tepper 	KKASSERT(hci_if->output_cmd != NULL);
9183aacedeSHasso Tepper 	KKASSERT(hci_if->output_acl != NULL);
9283aacedeSHasso Tepper 	KKASSERT(hci_if->output_sco != NULL);
9383aacedeSHasso Tepper 	KKASSERT(hci_if->get_stats != NULL);
9483aacedeSHasso Tepper 
9583aacedeSHasso Tepper 	unit = kmalloc(sizeof(struct hci_unit), M_BLUETOOTH, M_ZERO | M_WAITOK);
9683aacedeSHasso Tepper 	KKASSERT(unit != NULL);
9783aacedeSHasso Tepper 
9883aacedeSHasso Tepper 	unit->hci_dev = dev;
9983aacedeSHasso Tepper 	unit->hci_if = hci_if;
10083aacedeSHasso Tepper 	unit->hci_flags = flags;
10183aacedeSHasso Tepper 
10283aacedeSHasso Tepper 	lockinit(&unit->hci_devlock, "HCI device lock", 0, 0);
1030a9108ebSHasso Tepper 
1040a9108ebSHasso Tepper 	unit->hci_eventq.ifq_maxlen = hci_eventq_max;
1050a9108ebSHasso Tepper 	unit->hci_aclrxq.ifq_maxlen = hci_aclrxq_max;
1060a9108ebSHasso Tepper 	unit->hci_scorxq.ifq_maxlen = hci_scorxq_max;
10783aacedeSHasso Tepper 	unit->hci_cmdwait.ifq_maxlen = hci_cmdwait_max;
10883aacedeSHasso Tepper 	unit->hci_scodone.ifq_maxlen = hci_scodone_max;
1090a9108ebSHasso Tepper 
1100a9108ebSHasso Tepper 	TAILQ_INIT(&unit->hci_links);
1110a9108ebSHasso Tepper 	LIST_INIT(&unit->hci_memos);
1120a9108ebSHasso Tepper 
11383aacedeSHasso Tepper 	crit_enter();
1140a9108ebSHasso Tepper 	TAILQ_INSERT_TAIL(&hci_unit_list, unit, hci_next);
11583aacedeSHasso Tepper 	crit_exit();
11683aacedeSHasso Tepper 
11783aacedeSHasso Tepper 	return unit;
1180a9108ebSHasso Tepper }
1190a9108ebSHasso Tepper 
1200a9108ebSHasso Tepper void
hci_detach(struct hci_unit * unit)1210a9108ebSHasso Tepper hci_detach(struct hci_unit *unit)
1220a9108ebSHasso Tepper {
12383aacedeSHasso Tepper 	crit_enter();
1240a9108ebSHasso Tepper 	hci_disable(unit);
1250a9108ebSHasso Tepper 
1260a9108ebSHasso Tepper 	TAILQ_REMOVE(&hci_unit_list, unit, hci_next);
12783aacedeSHasso Tepper 	crit_exit();
12883aacedeSHasso Tepper 
12983aacedeSHasso Tepper 	kfree(unit, M_BLUETOOTH);
1300a9108ebSHasso Tepper }
1310a9108ebSHasso Tepper 
1320a9108ebSHasso Tepper int
hci_enable(struct hci_unit * unit)1330a9108ebSHasso Tepper hci_enable(struct hci_unit *unit)
1340a9108ebSHasso Tepper {
1350a9108ebSHasso Tepper 	int err;
1360a9108ebSHasso Tepper 
1370a9108ebSHasso Tepper 	/*
1380a9108ebSHasso Tepper 	 * Bluetooth spec says that a device can accept one
1390a9108ebSHasso Tepper 	 * command on power up until they send a Command Status
1400a9108ebSHasso Tepper 	 * or Command Complete event with more information, but
1410a9108ebSHasso Tepper 	 * it seems that some devices cant and prefer to send a
14283aacedeSHasso Tepper 	 * No-op Command Status packet when they are ready.
1430a9108ebSHasso Tepper 	 */
14483aacedeSHasso Tepper 	unit->hci_num_cmd_pkts = (unit->hci_flags & BTF_POWER_UP_NOOP) ? 0 : 1;
1450a9108ebSHasso Tepper 	unit->hci_num_acl_pkts = 0;
1460a9108ebSHasso Tepper 	unit->hci_num_sco_pkts = 0;
1470a9108ebSHasso Tepper 
1480a9108ebSHasso Tepper 	/*
1490a9108ebSHasso Tepper 	 * only allow the basic packet types until
1500a9108ebSHasso Tepper 	 * the features report is in
1510a9108ebSHasso Tepper 	 */
1520a9108ebSHasso Tepper 	unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
1530a9108ebSHasso Tepper 	unit->hci_packet_type = unit->hci_acl_mask;
1540a9108ebSHasso Tepper 
15583aacedeSHasso Tepper 	memcpy(unit->hci_cmds, hci_cmds_v10, HCI_COMMANDS_SIZE);
15683aacedeSHasso Tepper 	err = (*unit->hci_if->enable)(unit->hci_dev);
1570a9108ebSHasso Tepper 	if (err)
1580a9108ebSHasso Tepper 		goto bad1;
1590a9108ebSHasso Tepper 
16083aacedeSHasso Tepper 	unit->hci_flags |= BTF_RUNNING;
16183aacedeSHasso Tepper 
1620a9108ebSHasso Tepper 	/*
1630a9108ebSHasso Tepper 	 * Reset the device, this will trigger initialisation
1640a9108ebSHasso Tepper 	 * and wake us up.
1650a9108ebSHasso Tepper 	 */
1660a9108ebSHasso Tepper 	crit_enter();
1670a9108ebSHasso Tepper  	unit->hci_flags |= BTF_INIT;
1680a9108ebSHasso Tepper 	crit_exit();
1690a9108ebSHasso Tepper 
1700a9108ebSHasso Tepper 	err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0);
1710a9108ebSHasso Tepper 	if (err)
1720a9108ebSHasso Tepper 		goto bad2;
1730a9108ebSHasso Tepper 
1740a9108ebSHasso Tepper 	while (unit->hci_flags & BTF_INIT) {
1750a9108ebSHasso Tepper 		err = tsleep(unit, PCATCH, "hciena", 5 * hz);
1760a9108ebSHasso Tepper 		if (err)
1770a9108ebSHasso Tepper 			goto bad2;
1780a9108ebSHasso Tepper 
1790a9108ebSHasso Tepper 		/* XXX
1800a9108ebSHasso Tepper 		 * "What If", while we were sleeping, the device
1810a9108ebSHasso Tepper 		 * was removed and detached? Ho Hum.
1820a9108ebSHasso Tepper 		 */
1830a9108ebSHasso Tepper 	}
1840a9108ebSHasso Tepper 
1850a9108ebSHasso Tepper #if 0 /* not yet */
1860a9108ebSHasso Tepper 	/*
1870a9108ebSHasso Tepper 	 * Attach Bluetooth Device Hub
1880a9108ebSHasso Tepper 	 */
1890a9108ebSHasso Tepper 	unit->hci_bthub = NULL;
1900a9108ebSHasso Tepper 
1910a9108ebSHasso Tepper 	unit->hci_bthub = device_add_child(unit->hci_softc, "bthub", -1);
1920a9108ebSHasso Tepper 	if (!unit->hci_bthub) {
1930a9108ebSHasso Tepper 		device_printf(unit->hci_softc, "Device creation failed\n");
1940a9108ebSHasso Tepper 		goto bad2;
1950a9108ebSHasso Tepper 	}
1960a9108ebSHasso Tepper 
1970a9108ebSHasso Tepper 	DPRINTFN(10, "%s is added as child to %s\n",
1980a9108ebSHasso Tepper 	    device_get_nameunit(unit->hci_bthub),
1990a9108ebSHasso Tepper 	    device_get_nameunit(unit->hci_softc));
2000a9108ebSHasso Tepper 
2010a9108ebSHasso Tepper 	device_set_desc(unit->hci_bthub,"Bluetooth Device Hub");
2020a9108ebSHasso Tepper 
2030a9108ebSHasso Tepper 	device_set_ivars(unit->hci_bthub, &unit->hci_bdaddr);
2040a9108ebSHasso Tepper 
2050a9108ebSHasso Tepper 	device_probe_and_attach(unit->hci_bthub);
2060a9108ebSHasso Tepper #endif
2070a9108ebSHasso Tepper 	return 0;
2080a9108ebSHasso Tepper 
2090a9108ebSHasso Tepper bad2:
21083aacedeSHasso Tepper 	(*unit->hci_if->disable)(unit->hci_dev);
21183aacedeSHasso Tepper 	unit->hci_flags &= ~BTF_RUNNING;
2120a9108ebSHasso Tepper 
2130a9108ebSHasso Tepper bad1:
2140a9108ebSHasso Tepper 	return err;
2150a9108ebSHasso Tepper }
2160a9108ebSHasso Tepper 
2170a9108ebSHasso Tepper void
hci_disable(struct hci_unit * unit)2180a9108ebSHasso Tepper hci_disable(struct hci_unit *unit)
2190a9108ebSHasso Tepper {
2200a9108ebSHasso Tepper 	struct hci_link *link, *next;
2210a9108ebSHasso Tepper 	struct hci_memo *memo;
2220a9108ebSHasso Tepper 	int acl;
2230a9108ebSHasso Tepper 
2240a9108ebSHasso Tepper #if 0 /* not yet */
2250a9108ebSHasso Tepper 	if (unit->hci_bthub) {
2260a9108ebSHasso Tepper 		device_delete_child(unit->hci_softc, unit->hci_bthub);
2270a9108ebSHasso Tepper 		unit->hci_bthub = NULL;
2280a9108ebSHasso Tepper 	}
2290a9108ebSHasso Tepper #endif
2300a9108ebSHasso Tepper 
23183aacedeSHasso Tepper 	(*unit->hci_if->disable)(unit->hci_dev);
23283aacedeSHasso Tepper 	unit->hci_flags &= ~BTF_RUNNING;
2330a9108ebSHasso Tepper 
2340a9108ebSHasso Tepper 	/*
2350a9108ebSHasso Tepper 	 * close down any links, take care to close SCO first since
2360a9108ebSHasso Tepper 	 * they may depend on ACL links.
2370a9108ebSHasso Tepper 	 */
2380a9108ebSHasso Tepper 	for (acl = 0 ; acl < 2 ; acl++) {
2390a9108ebSHasso Tepper 		next = TAILQ_FIRST(&unit->hci_links);
2400a9108ebSHasso Tepper 		while ((link = next) != NULL) {
2410a9108ebSHasso Tepper 			next = TAILQ_NEXT(link, hl_next);
2420a9108ebSHasso Tepper 			if (acl || link->hl_type != HCI_LINK_ACL)
2430a9108ebSHasso Tepper 				hci_link_free(link, ECONNABORTED);
2440a9108ebSHasso Tepper 		}
2450a9108ebSHasso Tepper 	}
2460a9108ebSHasso Tepper 
2470a9108ebSHasso Tepper 	while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
2480a9108ebSHasso Tepper 		hci_memo_free(memo);
2490a9108ebSHasso Tepper 
25083aacedeSHasso Tepper 	/* (no need to hold hci_devlock, the driver is disabled) */
25183aacedeSHasso Tepper 
2520a9108ebSHasso Tepper 	IF_DRAIN(&unit->hci_eventq);
2530a9108ebSHasso Tepper 	unit->hci_eventqlen = 0;
2540a9108ebSHasso Tepper 
2550a9108ebSHasso Tepper 	IF_DRAIN(&unit->hci_aclrxq);
2560a9108ebSHasso Tepper 	unit->hci_aclrxqlen = 0;
2570a9108ebSHasso Tepper 
2580a9108ebSHasso Tepper 	IF_DRAIN(&unit->hci_scorxq);
2590a9108ebSHasso Tepper 	unit->hci_scorxqlen = 0;
2600a9108ebSHasso Tepper 
2610a9108ebSHasso Tepper 	IF_DRAIN(&unit->hci_cmdwait);
2620a9108ebSHasso Tepper 	IF_DRAIN(&unit->hci_scodone);
2630a9108ebSHasso Tepper }
2640a9108ebSHasso Tepper 
2650a9108ebSHasso Tepper struct hci_unit *
hci_unit_lookup(bdaddr_t * addr)2660a9108ebSHasso Tepper hci_unit_lookup(bdaddr_t *addr)
2670a9108ebSHasso Tepper {
2680a9108ebSHasso Tepper 	struct hci_unit *unit;
2690a9108ebSHasso Tepper 
2700a9108ebSHasso Tepper 	TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
2710a9108ebSHasso Tepper 		if ((unit->hci_flags & BTF_UP) == 0)
2720a9108ebSHasso Tepper 			continue;
2730a9108ebSHasso Tepper 
2740a9108ebSHasso Tepper 		if (bdaddr_same(&unit->hci_bdaddr, addr))
2750a9108ebSHasso Tepper 			break;
2760a9108ebSHasso Tepper 	}
2770a9108ebSHasso Tepper 
2780a9108ebSHasso Tepper 	return unit;
2790a9108ebSHasso Tepper }
2800a9108ebSHasso Tepper 
2810a9108ebSHasso Tepper /*
2820a9108ebSHasso Tepper  * construct and queue a HCI command packet
2830a9108ebSHasso Tepper  */
2840a9108ebSHasso Tepper int
hci_send_cmd(struct hci_unit * unit,uint16_t opcode,void * buf,uint8_t len)2850a9108ebSHasso Tepper hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
2860a9108ebSHasso Tepper {
2870a9108ebSHasso Tepper 	struct mbuf *m;
2880a9108ebSHasso Tepper 	hci_cmd_hdr_t *p;
2890a9108ebSHasso Tepper 
2900a9108ebSHasso Tepper 	KKASSERT(unit != NULL);
2910a9108ebSHasso Tepper 
292b5523eacSSascha Wildner 	m = m_gethdr(M_NOWAIT, MT_DATA);
2930a9108ebSHasso Tepper 	if (m == NULL)
2940a9108ebSHasso Tepper 		return ENOMEM;
2950a9108ebSHasso Tepper 
2960a9108ebSHasso Tepper 	p = mtod(m, hci_cmd_hdr_t *);
2970a9108ebSHasso Tepper 	p->type = HCI_CMD_PKT;
2980a9108ebSHasso Tepper 	p->opcode = htole16(opcode);
2990a9108ebSHasso Tepper 	p->length = len;
3000a9108ebSHasso Tepper 	m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
30183aacedeSHasso Tepper 	M_SETCTX(m, NULL);	/* XXX is this needed? */
3020a9108ebSHasso Tepper 
303*44647b48SAaron LI 	if (len > 0 &&
304*44647b48SAaron LI 	    m_copyback2(m, sizeof(hci_cmd_hdr_t), len, buf, M_NOWAIT) != 0) {
3050a9108ebSHasso Tepper 		m_freem(m);
3060a9108ebSHasso Tepper 		return ENOMEM;
3070a9108ebSHasso Tepper 	}
3080a9108ebSHasso Tepper 
30983aacedeSHasso Tepper 	DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n",
31083aacedeSHasso Tepper 		device_get_nameunit(unit->hci_dev),
3110a9108ebSHasso Tepper 		HCI_OGF(opcode), HCI_OCF(opcode));
3120a9108ebSHasso Tepper 
3130a9108ebSHasso Tepper 	/* and send it on */
31483aacedeSHasso Tepper 	if (unit->hci_num_cmd_pkts == 0)
3150a9108ebSHasso Tepper 		IF_ENQUEUE(&unit->hci_cmdwait, m);
31683aacedeSHasso Tepper 	else
3170a9108ebSHasso Tepper 		hci_output_cmd(unit, m);
3180a9108ebSHasso Tepper 
3190a9108ebSHasso Tepper 	return 0;
3200a9108ebSHasso Tepper }
3210a9108ebSHasso Tepper 
3220a9108ebSHasso Tepper /*
3230a9108ebSHasso Tepper  * Incoming packet processing. Since the code is single threaded
3240a9108ebSHasso Tepper  * in any case (IPL_SOFTNET), we handle it all in one interrupt function
3250a9108ebSHasso Tepper  * picking our way through more important packets first so that hopefully
3260a9108ebSHasso Tepper  * we will never get clogged up with bulk data.
3270a9108ebSHasso Tepper  */
3280a9108ebSHasso Tepper void
hci_intr(void * arg)3290a9108ebSHasso Tepper hci_intr(void *arg)
3300a9108ebSHasso Tepper {
3310a9108ebSHasso Tepper 	struct hci_unit *unit = arg;
3320a9108ebSHasso Tepper 	struct mbuf *m;
3330a9108ebSHasso Tepper 
3340a9108ebSHasso Tepper another:
33583aacedeSHasso Tepper 	lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
3360a9108ebSHasso Tepper 
3370a9108ebSHasso Tepper 	if (unit->hci_eventqlen > 0) {
3380a9108ebSHasso Tepper 		IF_DEQUEUE(&unit->hci_eventq, m);
3390a9108ebSHasso Tepper 		unit->hci_eventqlen--;
34083aacedeSHasso Tepper 		lockmgr(&unit->hci_devlock, LK_RELEASE);
34183aacedeSHasso Tepper 
3420a9108ebSHasso Tepper 		KKASSERT(m != NULL);
3430a9108ebSHasso Tepper 
3440a9108ebSHasso Tepper 		DPRINTFN(10, "(%s) recv event, len = %d\n",
34583aacedeSHasso Tepper 		    device_get_nameunit(unit->hci_dev), m->m_pkthdr.len);
3460a9108ebSHasso Tepper 
3470a9108ebSHasso Tepper 		m->m_flags |= IFF_LINK0;	/* mark incoming packet */
3480a9108ebSHasso Tepper 		hci_mtap(m, unit);
3490a9108ebSHasso Tepper 		hci_event(m, unit);
3500a9108ebSHasso Tepper 
3510a9108ebSHasso Tepper 		goto another;
3520a9108ebSHasso Tepper 	}
3530a9108ebSHasso Tepper 
3540a9108ebSHasso Tepper 	if (unit->hci_scorxqlen > 0) {
3550a9108ebSHasso Tepper 		IF_DEQUEUE(&unit->hci_scorxq, m);
3560a9108ebSHasso Tepper 		unit->hci_scorxqlen--;
35783aacedeSHasso Tepper 		lockmgr(&unit->hci_devlock, LK_RELEASE);
3580a9108ebSHasso Tepper 		KKASSERT(m != NULL);
3590a9108ebSHasso Tepper 
3600a9108ebSHasso Tepper 		DPRINTFN(10, "(%s) recv SCO, len = %d\n",
36183aacedeSHasso Tepper 		    device_get_nameunit(unit->hci_dev), m->m_pkthdr.len);
3620a9108ebSHasso Tepper 
3630a9108ebSHasso Tepper 		m->m_flags |= IFF_LINK0;	/* mark incoming packet */
3640a9108ebSHasso Tepper 		hci_mtap(m, unit);
3650a9108ebSHasso Tepper 		hci_sco_recv(m, unit);
3660a9108ebSHasso Tepper 
3670a9108ebSHasso Tepper 		goto another;
3680a9108ebSHasso Tepper 	}
3690a9108ebSHasso Tepper 
3700a9108ebSHasso Tepper 	if (unit->hci_aclrxqlen > 0) {
3710a9108ebSHasso Tepper 		IF_DEQUEUE(&unit->hci_aclrxq, m);
3720a9108ebSHasso Tepper 		unit->hci_aclrxqlen--;
37383aacedeSHasso Tepper 		lockmgr(&unit->hci_devlock, LK_RELEASE);
37483aacedeSHasso Tepper 
3750a9108ebSHasso Tepper 		KKASSERT(m != NULL);
3760a9108ebSHasso Tepper 
3770a9108ebSHasso Tepper 		DPRINTFN(10, "(%s) recv ACL, len = %d\n",
37883aacedeSHasso Tepper 		    device_get_nameunit(unit->hci_dev), m->m_pkthdr.len);
3790a9108ebSHasso Tepper 
3800a9108ebSHasso Tepper 		m->m_flags |= IFF_LINK0;	/* mark incoming packet */
3810a9108ebSHasso Tepper 		hci_mtap(m, unit);
3820a9108ebSHasso Tepper 		hci_acl_recv(m, unit);
3830a9108ebSHasso Tepper 
3840a9108ebSHasso Tepper 		goto another;
3850a9108ebSHasso Tepper 	}
3860a9108ebSHasso Tepper 
3870a9108ebSHasso Tepper 	IF_DEQUEUE(&unit->hci_scodone, m);
3880a9108ebSHasso Tepper 	if (m != NULL) {
3890a9108ebSHasso Tepper 		struct hci_link *link;
39083aacedeSHasso Tepper 		lockmgr(&unit->hci_devlock, LK_RELEASE);
3910a9108ebSHasso Tepper 
3920a9108ebSHasso Tepper 		DPRINTFN(11, "(%s) complete SCO\n",
39383aacedeSHasso Tepper 		    device_get_nameunit(unit->hci_dev));
3940a9108ebSHasso Tepper 
3950a9108ebSHasso Tepper 		TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
3960a9108ebSHasso Tepper 			if (link == M_GETCTX(m, struct hci_link *)) {
3970a9108ebSHasso Tepper 				hci_sco_complete(link, 1);
3980a9108ebSHasso Tepper 				break;
3990a9108ebSHasso Tepper 			}
4000a9108ebSHasso Tepper 		}
4010a9108ebSHasso Tepper 
4020a9108ebSHasso Tepper 		unit->hci_num_sco_pkts++;
4030a9108ebSHasso Tepper 		m_freem(m);
4040a9108ebSHasso Tepper 
4050a9108ebSHasso Tepper 		goto another;
4060a9108ebSHasso Tepper 	}
4070a9108ebSHasso Tepper 
40883aacedeSHasso Tepper 	lockmgr(&unit->hci_devlock, LK_RELEASE);
4090a9108ebSHasso Tepper 
4100a9108ebSHasso Tepper 	DPRINTFN(10, "done\n");
4110a9108ebSHasso Tepper }
4120a9108ebSHasso Tepper 
4130a9108ebSHasso Tepper /**********************************************************************
4140a9108ebSHasso Tepper  *
4150a9108ebSHasso Tepper  * IO routines
4160a9108ebSHasso Tepper  *
41783aacedeSHasso Tepper  * input & complete routines will be called from device drivers,
41883aacedeSHasso Tepper  * possibly in interrupt context. We return success or failure to
41983aacedeSHasso Tepper  * enable proper accounting but we own the mbuf.
4200a9108ebSHasso Tepper  */
4210a9108ebSHasso Tepper 
42283aacedeSHasso Tepper int
hci_input_event(struct hci_unit * unit,struct mbuf * m)4230a9108ebSHasso Tepper hci_input_event(struct hci_unit *unit, struct mbuf *m)
4240a9108ebSHasso Tepper {
42583aacedeSHasso Tepper 	int rv;
42683aacedeSHasso Tepper 
42783aacedeSHasso Tepper 	lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
42883aacedeSHasso Tepper 
4290a9108ebSHasso Tepper 	if (unit->hci_eventqlen > hci_eventq_max) {
43083aacedeSHasso Tepper 		DPRINTF("(%s) dropped event packet.\n",
43183aacedeSHasso Tepper 		    device_get_nameunit(unit->hci_dev));
4320a9108ebSHasso Tepper 		m_freem(m);
43383aacedeSHasso Tepper 		rv = 0;
4340a9108ebSHasso Tepper 	} else {
4350a9108ebSHasso Tepper 		unit->hci_eventqlen++;
4360a9108ebSHasso Tepper 		IF_ENQUEUE(&unit->hci_eventq, m);
4370a9108ebSHasso Tepper 		netisr_queue(NETISR_BLUETOOTH, m);
43883aacedeSHasso Tepper 		rv = 1;
4390a9108ebSHasso Tepper 	}
44083aacedeSHasso Tepper 	lockmgr(&unit->hci_devlock, LK_RELEASE);
44183aacedeSHasso Tepper 
44283aacedeSHasso Tepper 	return rv;
4430a9108ebSHasso Tepper }
4440a9108ebSHasso Tepper 
44583aacedeSHasso Tepper int
hci_input_acl(struct hci_unit * unit,struct mbuf * m)4460a9108ebSHasso Tepper hci_input_acl(struct hci_unit *unit, struct mbuf *m)
4470a9108ebSHasso Tepper {
44883aacedeSHasso Tepper 	int rv;
44983aacedeSHasso Tepper 
45083aacedeSHasso Tepper 	lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
4510a9108ebSHasso Tepper 	if (unit->hci_aclrxqlen > hci_aclrxq_max) {
45283aacedeSHasso Tepper 		DPRINTF("(%s) dropped ACL packet.\n",
45383aacedeSHasso Tepper 		    device_get_nameunit(unit->hci_dev));
4540a9108ebSHasso Tepper 		m_freem(m);
45583aacedeSHasso Tepper 		rv = 0;
4560a9108ebSHasso Tepper 	} else {
4570a9108ebSHasso Tepper 		unit->hci_aclrxqlen++;
4580a9108ebSHasso Tepper 		IF_ENQUEUE(&unit->hci_aclrxq, m);
4590a9108ebSHasso Tepper 		netisr_queue(NETISR_BLUETOOTH, m);
46083aacedeSHasso Tepper 		rv = 1;
4610a9108ebSHasso Tepper 	}
46283aacedeSHasso Tepper 	lockmgr(&unit->hci_devlock, LK_RELEASE);
46383aacedeSHasso Tepper 
46483aacedeSHasso Tepper 	return rv;
4650a9108ebSHasso Tepper }
4660a9108ebSHasso Tepper 
46783aacedeSHasso Tepper int
hci_input_sco(struct hci_unit * unit,struct mbuf * m)4680a9108ebSHasso Tepper hci_input_sco(struct hci_unit *unit, struct mbuf *m)
4690a9108ebSHasso Tepper {
47083aacedeSHasso Tepper 	int rv;
47183aacedeSHasso Tepper 
47283aacedeSHasso Tepper 	lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
4730a9108ebSHasso Tepper 	if (unit->hci_scorxqlen > hci_scorxq_max) {
47483aacedeSHasso Tepper 		DPRINTF("(%s) dropped SCO packet.\n",
47583aacedeSHasso Tepper 		    device_get_nameunit(unit->hci_dev));
4760a9108ebSHasso Tepper 		m_freem(m);
47783aacedeSHasso Tepper 		rv = 0;
4780a9108ebSHasso Tepper 	} else {
4790a9108ebSHasso Tepper 		unit->hci_scorxqlen++;
4800a9108ebSHasso Tepper 		IF_ENQUEUE(&unit->hci_scorxq, m);
4810a9108ebSHasso Tepper 		netisr_queue(NETISR_BLUETOOTH, m);
48283aacedeSHasso Tepper 		rv = 1;
4830a9108ebSHasso Tepper 	}
48483aacedeSHasso Tepper 	lockmgr(&unit->hci_devlock, LK_RELEASE);
48583aacedeSHasso Tepper 
48683aacedeSHasso Tepper 	return rv;
4870a9108ebSHasso Tepper }
4880a9108ebSHasso Tepper 
4890a9108ebSHasso Tepper void
hci_output_cmd(struct hci_unit * unit,struct mbuf * m)4900a9108ebSHasso Tepper hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
4910a9108ebSHasso Tepper {
4920a9108ebSHasso Tepper 	void *arg;
4930a9108ebSHasso Tepper 
4940a9108ebSHasso Tepper 	hci_mtap(m, unit);
4950a9108ebSHasso Tepper 
49683aacedeSHasso Tepper 	DPRINTFN(10, "(%s) num_cmd_pkts=%d\n",
49783aacedeSHasso Tepper 	    device_get_nameunit(unit->hci_dev), unit->hci_num_cmd_pkts);
4980a9108ebSHasso Tepper 
4990a9108ebSHasso Tepper 	unit->hci_num_cmd_pkts--;
5000a9108ebSHasso Tepper 
5010a9108ebSHasso Tepper 	/*
5020a9108ebSHasso Tepper 	 * If context is set, this was from a HCI raw socket
5030a9108ebSHasso Tepper 	 * and a record needs to be dropped from the sockbuf.
5040a9108ebSHasso Tepper 	 */
5050a9108ebSHasso Tepper 	arg = M_GETCTX(m, void *);
5060a9108ebSHasso Tepper 	if (arg != NULL)
5070a9108ebSHasso Tepper 		hci_drop(arg);
5080a9108ebSHasso Tepper 
50983aacedeSHasso Tepper 	(*unit->hci_if->output_cmd)(unit->hci_dev, m);
5100a9108ebSHasso Tepper }
5110a9108ebSHasso Tepper 
5120a9108ebSHasso Tepper void
hci_output_acl(struct hci_unit * unit,struct mbuf * m)5130a9108ebSHasso Tepper hci_output_acl(struct hci_unit *unit, struct mbuf *m)
5140a9108ebSHasso Tepper {
5150a9108ebSHasso Tepper 	hci_mtap(m, unit);
5160a9108ebSHasso Tepper 
51783aacedeSHasso Tepper 	DPRINTFN(10, "(%s) num_acl_pkts=%d\n",
51883aacedeSHasso Tepper 	    device_get_nameunit(unit->hci_dev), unit->hci_num_acl_pkts);
5190a9108ebSHasso Tepper 
5200a9108ebSHasso Tepper 	unit->hci_num_acl_pkts--;
5210a9108ebSHasso Tepper 
52283aacedeSHasso Tepper 	(*unit->hci_if->output_acl)(unit->hci_dev, m);
5230a9108ebSHasso Tepper }
5240a9108ebSHasso Tepper 
5250a9108ebSHasso Tepper void
hci_output_sco(struct hci_unit * unit,struct mbuf * m)5260a9108ebSHasso Tepper hci_output_sco(struct hci_unit *unit, struct mbuf *m)
5270a9108ebSHasso Tepper {
5280a9108ebSHasso Tepper 	hci_mtap(m, unit);
5290a9108ebSHasso Tepper 
53083aacedeSHasso Tepper 	DPRINTFN(10, "(%s) num_sco_pkts=%d\n",
53183aacedeSHasso Tepper 	    device_get_nameunit(unit->hci_dev), unit->hci_num_sco_pkts);
5320a9108ebSHasso Tepper 
5330a9108ebSHasso Tepper 	unit->hci_num_sco_pkts--;
5340a9108ebSHasso Tepper 
53583aacedeSHasso Tepper 	(*unit->hci_if->output_sco)(unit->hci_dev, m);
5360a9108ebSHasso Tepper }
5370a9108ebSHasso Tepper 
53883aacedeSHasso Tepper int
hci_complete_sco(struct hci_unit * unit,struct mbuf * m)5390a9108ebSHasso Tepper hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
5400a9108ebSHasso Tepper {
54183aacedeSHasso Tepper 	lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
5420a9108ebSHasso Tepper 	IF_ENQUEUE(&unit->hci_scodone, m);
5430a9108ebSHasso Tepper 	netisr_queue(NETISR_BLUETOOTH,m);
54483aacedeSHasso Tepper 	lockmgr(&unit->hci_devlock, LK_RELEASE);
54583aacedeSHasso Tepper 
54683aacedeSHasso Tepper 	return 1;
5470a9108ebSHasso Tepper }
548