Home | History | Annotate | Line # | Download | only in netbt
hci_unit.c revision 1.15
      1  1.15  thorpej /*	$NetBSD: hci_unit.c,v 1.15 2021/04/24 23:37:01 thorpej Exp $	*/
      2   1.1  gdamore 
      3   1.1  gdamore /*-
      4   1.1  gdamore  * Copyright (c) 2005 Iain Hibbert.
      5   1.1  gdamore  * Copyright (c) 2006 Itronix Inc.
      6   1.1  gdamore  * All rights reserved.
      7   1.1  gdamore  *
      8   1.1  gdamore  * Redistribution and use in source and binary forms, with or without
      9   1.1  gdamore  * modification, are permitted provided that the following conditions
     10   1.1  gdamore  * are met:
     11   1.1  gdamore  * 1. Redistributions of source code must retain the above copyright
     12   1.1  gdamore  *    notice, this list of conditions and the following disclaimer.
     13   1.1  gdamore  * 2. Redistributions in binary form must reproduce the above copyright
     14   1.1  gdamore  *    notice, this list of conditions and the following disclaimer in the
     15   1.1  gdamore  *    documentation and/or other materials provided with the distribution.
     16   1.1  gdamore  * 3. The name of Itronix Inc. may not be used to endorse
     17   1.1  gdamore  *    or promote products derived from this software without specific
     18   1.1  gdamore  *    prior written permission.
     19   1.1  gdamore  *
     20   1.1  gdamore  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
     21   1.1  gdamore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22   1.1  gdamore  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23   1.1  gdamore  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
     24   1.1  gdamore  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     25   1.1  gdamore  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     26   1.1  gdamore  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     27   1.1  gdamore  * ON ANY THEORY OF LIABILITY, WHETHER IN
     28   1.1  gdamore  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29   1.1  gdamore  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30   1.1  gdamore  * POSSIBILITY OF SUCH DAMAGE.
     31   1.1  gdamore  */
     32   1.1  gdamore 
     33   1.1  gdamore #include <sys/cdefs.h>
     34  1.15  thorpej __KERNEL_RCSID(0, "$NetBSD: hci_unit.c,v 1.15 2021/04/24 23:37:01 thorpej Exp $");
     35   1.1  gdamore 
     36   1.1  gdamore #include <sys/param.h>
     37   1.1  gdamore #include <sys/conf.h>
     38   1.1  gdamore #include <sys/device.h>
     39   1.1  gdamore #include <sys/kernel.h>
     40   1.1  gdamore #include <sys/malloc.h>
     41   1.1  gdamore #include <sys/mbuf.h>
     42   1.1  gdamore #include <sys/proc.h>
     43   1.1  gdamore #include <sys/queue.h>
     44   1.1  gdamore #include <sys/systm.h>
     45   1.5       ad #include <sys/intr.h>
     46  1.11       ad #include <sys/socketvar.h>
     47   1.1  gdamore 
     48   1.1  gdamore #include <netbt/bluetooth.h>
     49   1.1  gdamore #include <netbt/hci.h>
     50   1.1  gdamore 
     51   1.1  gdamore struct hci_unit_list hci_unit_list = SIMPLEQ_HEAD_INITIALIZER(hci_unit_list);
     52   1.1  gdamore 
     53   1.1  gdamore MALLOC_DEFINE(M_BLUETOOTH, "Bluetooth", "Bluetooth System Memory");
     54   1.1  gdamore 
     55   1.1  gdamore /*
     56   1.1  gdamore  * HCI Input Queue max lengths.
     57   1.1  gdamore  */
     58   1.1  gdamore int hci_eventq_max = 20;
     59   1.1  gdamore int hci_aclrxq_max = 50;
     60   1.1  gdamore int hci_scorxq_max = 50;
     61   1.1  gdamore 
     62   1.1  gdamore /*
     63   1.9   plunky  * This is the default minimum command set supported by older
     64   1.9   plunky  * devices. Anything conforming to 1.2 spec or later will get
     65   1.9   plunky  * updated during init.
     66   1.9   plunky  */
     67   1.9   plunky static const uint8_t hci_cmds_v10[HCI_COMMANDS_SIZE] = {
     68   1.9   plunky 	0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff,
     69   1.9   plunky 	0xff, 0xff, 0xff, 0x7f, 0x32, 0x03, 0xb8, 0xfe,
     70   1.9   plunky 	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     71   1.9   plunky 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     72   1.9   plunky 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     73   1.9   plunky 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     74   1.9   plunky 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     75   1.9   plunky 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     76   1.9   plunky };
     77   1.9   plunky 
     78   1.9   plunky /*
     79   1.1  gdamore  * bluetooth unit functions
     80   1.1  gdamore  */
     81   1.1  gdamore static void hci_intr (void *);
     82   1.1  gdamore 
     83   1.8   plunky struct hci_unit *
     84  1.14    rmind hci_attach_pcb(const struct hci_if *hci_if, device_t dev, uint16_t flags)
     85   1.1  gdamore {
     86   1.8   plunky 	struct hci_unit *unit;
     87   1.8   plunky 
     88   1.8   plunky 	KASSERT(dev != NULL);
     89   1.8   plunky 	KASSERT(hci_if->enable != NULL);
     90   1.8   plunky 	KASSERT(hci_if->disable != NULL);
     91   1.8   plunky 	KASSERT(hci_if->output_cmd != NULL);
     92   1.8   plunky 	KASSERT(hci_if->output_acl != NULL);
     93   1.8   plunky 	KASSERT(hci_if->output_sco != NULL);
     94   1.8   plunky 	KASSERT(hci_if->get_stats != NULL);
     95   1.8   plunky 
     96   1.8   plunky 	unit = malloc(sizeof(struct hci_unit), M_BLUETOOTH, M_ZERO | M_WAITOK);
     97   1.8   plunky 	KASSERT(unit != NULL);
     98   1.1  gdamore 
     99   1.8   plunky 	unit->hci_dev = dev;
    100   1.8   plunky 	unit->hci_if = hci_if;
    101   1.8   plunky 	unit->hci_flags = flags;
    102   1.8   plunky 
    103   1.8   plunky 	mutex_init(&unit->hci_devlock, MUTEX_DRIVER, hci_if->ipl);
    104  1.11       ad 	cv_init(&unit->hci_init, "hci_init");
    105   1.1  gdamore 
    106   1.1  gdamore 	MBUFQ_INIT(&unit->hci_eventq);
    107   1.1  gdamore 	MBUFQ_INIT(&unit->hci_aclrxq);
    108   1.1  gdamore 	MBUFQ_INIT(&unit->hci_scorxq);
    109   1.1  gdamore 	MBUFQ_INIT(&unit->hci_cmdwait);
    110   1.1  gdamore 	MBUFQ_INIT(&unit->hci_scodone);
    111   1.1  gdamore 
    112   1.1  gdamore 	TAILQ_INIT(&unit->hci_links);
    113   1.1  gdamore 	LIST_INIT(&unit->hci_memos);
    114   1.1  gdamore 
    115  1.11       ad 	mutex_enter(bt_lock);
    116   1.1  gdamore 	SIMPLEQ_INSERT_TAIL(&hci_unit_list, unit, hci_next);
    117  1.11       ad 	mutex_exit(bt_lock);
    118   1.8   plunky 
    119   1.8   plunky 	return unit;
    120   1.1  gdamore }
    121   1.1  gdamore 
    122   1.1  gdamore void
    123  1.14    rmind hci_detach_pcb(struct hci_unit *unit)
    124   1.1  gdamore {
    125   1.1  gdamore 
    126  1.11       ad 	mutex_enter(bt_lock);
    127   1.1  gdamore 	hci_disable(unit);
    128   1.1  gdamore 
    129   1.1  gdamore 	SIMPLEQ_REMOVE(&hci_unit_list, unit, hci_unit, hci_next);
    130  1.11       ad 	mutex_exit(bt_lock);
    131   1.8   plunky 
    132  1.11       ad 	cv_destroy(&unit->hci_init);
    133   1.8   plunky 	mutex_destroy(&unit->hci_devlock);
    134   1.8   plunky 	free(unit, M_BLUETOOTH);
    135   1.1  gdamore }
    136   1.1  gdamore 
    137   1.1  gdamore int
    138   1.1  gdamore hci_enable(struct hci_unit *unit)
    139   1.1  gdamore {
    140   1.8   plunky 	int err;
    141   1.1  gdamore 
    142   1.1  gdamore 	/*
    143   1.1  gdamore 	 * Bluetooth spec says that a device can accept one
    144   1.1  gdamore 	 * command on power up until they send a Command Status
    145   1.1  gdamore 	 * or Command Complete event with more information, but
    146   1.1  gdamore 	 * it seems that some devices cant and prefer to send a
    147   1.8   plunky 	 * No-op Command Status packet when they are ready.
    148   1.1  gdamore 	 */
    149   1.8   plunky 	unit->hci_num_cmd_pkts = (unit->hci_flags & BTF_POWER_UP_NOOP) ? 0 : 1;
    150   1.1  gdamore 	unit->hci_num_acl_pkts = 0;
    151   1.1  gdamore 	unit->hci_num_sco_pkts = 0;
    152   1.1  gdamore 
    153   1.1  gdamore 	/*
    154   1.1  gdamore 	 * only allow the basic packet types until
    155   1.1  gdamore 	 * the features report is in
    156   1.1  gdamore 	 */
    157   1.1  gdamore 	unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
    158   1.1  gdamore 	unit->hci_packet_type = unit->hci_acl_mask;
    159   1.1  gdamore 
    160   1.9   plunky 	memcpy(unit->hci_cmds, hci_cmds_v10, HCI_COMMANDS_SIZE);
    161   1.9   plunky 
    162   1.5       ad 	unit->hci_rxint = softint_establish(SOFTINT_NET, &hci_intr, unit);
    163   1.1  gdamore 	if (unit->hci_rxint == NULL)
    164   1.1  gdamore 		return EIO;
    165   1.1  gdamore 
    166   1.8   plunky 	err = (*unit->hci_if->enable)(unit->hci_dev);
    167   1.1  gdamore 	if (err)
    168   1.1  gdamore 		goto bad1;
    169   1.1  gdamore 
    170   1.8   plunky 	unit->hci_flags |= BTF_RUNNING;
    171   1.8   plunky 
    172   1.1  gdamore 	/*
    173   1.1  gdamore 	 * Reset the device, this will trigger initialisation
    174   1.1  gdamore 	 * and wake us up.
    175   1.1  gdamore 	 */
    176   1.1  gdamore 	unit->hci_flags |= BTF_INIT;
    177   1.1  gdamore 
    178   1.1  gdamore 	err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0);
    179   1.1  gdamore 	if (err)
    180   1.1  gdamore 		goto bad2;
    181   1.1  gdamore 
    182   1.1  gdamore 	while (unit->hci_flags & BTF_INIT) {
    183  1.11       ad 		err = cv_timedwait_sig(&unit->hci_init, bt_lock, 5 * hz);
    184   1.1  gdamore 		if (err)
    185   1.1  gdamore 			goto bad2;
    186   1.1  gdamore 
    187   1.1  gdamore 		/* XXX
    188   1.1  gdamore 		 * "What If", while we were sleeping, the device
    189   1.1  gdamore 		 * was removed and detached? Ho Hum.
    190   1.1  gdamore 		 */
    191   1.1  gdamore 	}
    192   1.1  gdamore 
    193   1.3   plunky 	/*
    194   1.3   plunky 	 * Attach Bluetooth Device Hub
    195   1.3   plunky 	 */
    196  1.15  thorpej 	unit->hci_bthub = config_found(unit->hci_dev, &unit->hci_bdaddr, NULL,
    197  1.15  thorpej 	    CFARG_IATTR, "btbus",
    198  1.15  thorpej 	    CFARG_EOL);
    199   1.3   plunky 
    200   1.1  gdamore 	return 0;
    201   1.1  gdamore 
    202   1.1  gdamore bad2:
    203   1.8   plunky 	(*unit->hci_if->disable)(unit->hci_dev);
    204   1.8   plunky 	unit->hci_flags &= ~BTF_RUNNING;
    205   1.1  gdamore bad1:
    206   1.5       ad 	softint_disestablish(unit->hci_rxint);
    207   1.1  gdamore 	unit->hci_rxint = NULL;
    208   1.1  gdamore 
    209   1.1  gdamore 	return err;
    210   1.1  gdamore }
    211   1.1  gdamore 
    212   1.1  gdamore void
    213   1.1  gdamore hci_disable(struct hci_unit *unit)
    214   1.1  gdamore {
    215   1.1  gdamore 	struct hci_link *link, *next;
    216   1.1  gdamore 	struct hci_memo *memo;
    217   1.8   plunky 	int acl;
    218   1.1  gdamore 
    219   1.3   plunky 	if (unit->hci_bthub) {
    220  1.12   plunky 		device_t hub;
    221  1.12   plunky 
    222  1.12   plunky 		hub = unit->hci_bthub;
    223   1.3   plunky 		unit->hci_bthub = NULL;
    224  1.12   plunky 
    225  1.12   plunky 		mutex_exit(bt_lock);
    226  1.12   plunky 		config_detach(hub, DETACH_FORCE);
    227  1.12   plunky 		mutex_enter(bt_lock);
    228   1.3   plunky 	}
    229   1.3   plunky 
    230   1.1  gdamore 	if (unit->hci_rxint) {
    231   1.5       ad 		softint_disestablish(unit->hci_rxint);
    232   1.1  gdamore 		unit->hci_rxint = NULL;
    233   1.1  gdamore 	}
    234   1.1  gdamore 
    235   1.8   plunky 	(*unit->hci_if->disable)(unit->hci_dev);
    236   1.8   plunky 	unit->hci_flags &= ~BTF_RUNNING;
    237   1.1  gdamore 
    238   1.1  gdamore 	/*
    239   1.1  gdamore 	 * close down any links, take care to close SCO first since
    240   1.1  gdamore 	 * they may depend on ACL links.
    241   1.1  gdamore 	 */
    242   1.1  gdamore 	for (acl = 0 ; acl < 2 ; acl++) {
    243   1.1  gdamore 		next = TAILQ_FIRST(&unit->hci_links);
    244   1.1  gdamore 		while ((link = next) != NULL) {
    245   1.1  gdamore 			next = TAILQ_NEXT(link, hl_next);
    246   1.1  gdamore 			if (acl || link->hl_type != HCI_LINK_ACL)
    247   1.1  gdamore 				hci_link_free(link, ECONNABORTED);
    248   1.1  gdamore 		}
    249   1.1  gdamore 	}
    250   1.1  gdamore 
    251   1.1  gdamore 	while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
    252   1.1  gdamore 		hci_memo_free(memo);
    253   1.1  gdamore 
    254   1.8   plunky 	/* (no need to hold hci_devlock, the driver is disabled) */
    255   1.8   plunky 
    256   1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_eventq);
    257   1.1  gdamore 	unit->hci_eventqlen = 0;
    258   1.1  gdamore 
    259   1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_aclrxq);
    260   1.1  gdamore 	unit->hci_aclrxqlen = 0;
    261   1.1  gdamore 
    262   1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_scorxq);
    263   1.1  gdamore 	unit->hci_scorxqlen = 0;
    264   1.1  gdamore 
    265   1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_cmdwait);
    266   1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_scodone);
    267   1.1  gdamore }
    268   1.1  gdamore 
    269   1.1  gdamore struct hci_unit *
    270  1.13   plunky hci_unit_lookup(const bdaddr_t *addr)
    271   1.1  gdamore {
    272   1.1  gdamore 	struct hci_unit *unit;
    273   1.1  gdamore 
    274   1.1  gdamore 	SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
    275   1.1  gdamore 		if ((unit->hci_flags & BTF_UP) == 0)
    276   1.1  gdamore 			continue;
    277   1.1  gdamore 
    278   1.1  gdamore 		if (bdaddr_same(&unit->hci_bdaddr, addr))
    279   1.1  gdamore 			break;
    280   1.1  gdamore 	}
    281   1.1  gdamore 
    282   1.1  gdamore 	return unit;
    283   1.1  gdamore }
    284   1.1  gdamore 
    285   1.1  gdamore /*
    286  1.10   plunky  * update num_cmd_pkts and push on pending commands queue
    287  1.10   plunky  */
    288  1.10   plunky void
    289  1.10   plunky hci_num_cmds(struct hci_unit *unit, uint8_t num)
    290  1.10   plunky {
    291  1.10   plunky 	struct mbuf *m;
    292  1.10   plunky 
    293  1.10   plunky 	unit->hci_num_cmd_pkts = num;
    294  1.10   plunky 
    295  1.10   plunky 	while (unit->hci_num_cmd_pkts > 0 && MBUFQ_FIRST(&unit->hci_cmdwait)) {
    296  1.10   plunky 		MBUFQ_DEQUEUE(&unit->hci_cmdwait, m);
    297  1.10   plunky 		hci_output_cmd(unit, m);
    298  1.10   plunky 	}
    299  1.10   plunky }
    300  1.10   plunky 
    301  1.10   plunky /*
    302   1.1  gdamore  * construct and queue a HCI command packet
    303   1.1  gdamore  */
    304   1.1  gdamore int
    305   1.1  gdamore hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
    306   1.1  gdamore {
    307   1.1  gdamore 	struct mbuf *m;
    308   1.1  gdamore 	hci_cmd_hdr_t *p;
    309   1.1  gdamore 
    310   1.4   plunky 	KASSERT(unit != NULL);
    311   1.1  gdamore 
    312   1.1  gdamore 	m = m_gethdr(M_DONTWAIT, MT_DATA);
    313   1.1  gdamore 	if (m == NULL)
    314   1.1  gdamore 		return ENOMEM;
    315   1.1  gdamore 
    316   1.1  gdamore 	p = mtod(m, hci_cmd_hdr_t *);
    317   1.1  gdamore 	p->type = HCI_CMD_PKT;
    318   1.1  gdamore 	p->opcode = htole16(opcode);
    319   1.1  gdamore 	p->length = len;
    320   1.1  gdamore 	m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
    321   1.1  gdamore 
    322   1.1  gdamore 	if (len) {
    323   1.4   plunky 		KASSERT(buf != NULL);
    324   1.1  gdamore 
    325   1.1  gdamore 		m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf);
    326   1.1  gdamore 		if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) {
    327   1.1  gdamore 			m_freem(m);
    328   1.1  gdamore 			return ENOMEM;
    329   1.1  gdamore 		}
    330   1.1  gdamore 	}
    331   1.1  gdamore 
    332   1.7   plunky 	DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", device_xname(unit->hci_dev),
    333   1.1  gdamore 		HCI_OGF(opcode), HCI_OCF(opcode));
    334   1.1  gdamore 
    335   1.1  gdamore 	/* and send it on */
    336   1.1  gdamore 	if (unit->hci_num_cmd_pkts == 0)
    337   1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_cmdwait, m);
    338   1.1  gdamore 	else
    339   1.1  gdamore 		hci_output_cmd(unit, m);
    340   1.1  gdamore 
    341   1.1  gdamore 	return 0;
    342   1.1  gdamore }
    343   1.1  gdamore 
    344   1.1  gdamore /*
    345   1.1  gdamore  * Incoming packet processing. Since the code is single threaded
    346   1.1  gdamore  * in any case (IPL_SOFTNET), we handle it all in one interrupt function
    347   1.1  gdamore  * picking our way through more important packets first so that hopefully
    348   1.1  gdamore  * we will never get clogged up with bulk data.
    349   1.1  gdamore  */
    350   1.1  gdamore static void
    351   1.1  gdamore hci_intr(void *arg)
    352   1.1  gdamore {
    353   1.1  gdamore 	struct hci_unit *unit = arg;
    354   1.1  gdamore 	struct mbuf *m;
    355   1.1  gdamore 
    356  1.11       ad 	mutex_enter(bt_lock);
    357   1.1  gdamore another:
    358   1.8   plunky 	mutex_enter(&unit->hci_devlock);
    359   1.1  gdamore 
    360   1.1  gdamore 	if (unit->hci_eventqlen > 0) {
    361   1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_eventq, m);
    362   1.1  gdamore 		unit->hci_eventqlen--;
    363   1.8   plunky 		mutex_exit(&unit->hci_devlock);
    364   1.8   plunky 
    365   1.1  gdamore 		KASSERT(m != NULL);
    366   1.1  gdamore 
    367   1.1  gdamore 		DPRINTFN(10, "(%s) recv event, len = %d\n",
    368   1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    369   1.1  gdamore 
    370   1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    371   1.1  gdamore 		hci_mtap(m, unit);
    372   1.1  gdamore 		hci_event(m, unit);
    373   1.1  gdamore 
    374   1.1  gdamore 		goto another;
    375   1.1  gdamore 	}
    376   1.1  gdamore 
    377   1.1  gdamore 	if (unit->hci_scorxqlen > 0) {
    378   1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_scorxq, m);
    379   1.1  gdamore 		unit->hci_scorxqlen--;
    380   1.8   plunky 		mutex_exit(&unit->hci_devlock);
    381   1.8   plunky 
    382   1.1  gdamore 		KASSERT(m != NULL);
    383   1.1  gdamore 
    384   1.1  gdamore 		DPRINTFN(10, "(%s) recv SCO, len = %d\n",
    385   1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    386   1.1  gdamore 
    387   1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    388   1.1  gdamore 		hci_mtap(m, unit);
    389   1.1  gdamore 		hci_sco_recv(m, unit);
    390   1.1  gdamore 
    391   1.1  gdamore 		goto another;
    392   1.1  gdamore 	}
    393   1.1  gdamore 
    394   1.1  gdamore 	if (unit->hci_aclrxqlen > 0) {
    395   1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_aclrxq, m);
    396   1.1  gdamore 		unit->hci_aclrxqlen--;
    397   1.8   plunky 		mutex_exit(&unit->hci_devlock);
    398   1.8   plunky 
    399   1.1  gdamore 		KASSERT(m != NULL);
    400   1.1  gdamore 
    401   1.1  gdamore 		DPRINTFN(10, "(%s) recv ACL, len = %d\n",
    402   1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    403   1.1  gdamore 
    404   1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    405   1.1  gdamore 		hci_mtap(m, unit);
    406   1.1  gdamore 		hci_acl_recv(m, unit);
    407   1.1  gdamore 
    408   1.1  gdamore 		goto another;
    409   1.1  gdamore 	}
    410   1.1  gdamore 
    411   1.1  gdamore 	MBUFQ_DEQUEUE(&unit->hci_scodone, m);
    412   1.1  gdamore 	if (m != NULL) {
    413   1.1  gdamore 		struct hci_link *link;
    414   1.8   plunky 
    415   1.8   plunky 		mutex_exit(&unit->hci_devlock);
    416   1.1  gdamore 
    417   1.1  gdamore 		DPRINTFN(11, "(%s) complete SCO\n",
    418   1.7   plunky 				device_xname(unit->hci_dev));
    419   1.1  gdamore 
    420   1.1  gdamore 		TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
    421   1.1  gdamore 			if (link == M_GETCTX(m, struct hci_link *)) {
    422   1.1  gdamore 				hci_sco_complete(link, 1);
    423   1.1  gdamore 				break;
    424   1.1  gdamore 			}
    425   1.1  gdamore 		}
    426   1.1  gdamore 
    427   1.1  gdamore 		unit->hci_num_sco_pkts++;
    428   1.1  gdamore 		m_freem(m);
    429   1.1  gdamore 
    430   1.1  gdamore 		goto another;
    431   1.1  gdamore 	}
    432   1.1  gdamore 
    433   1.8   plunky 	mutex_exit(&unit->hci_devlock);
    434  1.11       ad 	mutex_exit(bt_lock);
    435   1.1  gdamore 
    436   1.1  gdamore 	DPRINTFN(10, "done\n");
    437   1.1  gdamore }
    438   1.1  gdamore 
    439   1.1  gdamore /**********************************************************************
    440   1.1  gdamore  *
    441   1.1  gdamore  * IO routines
    442   1.1  gdamore  *
    443   1.8   plunky  * input & complete routines will be called from device drivers,
    444   1.8   plunky  * possibly in interrupt context. We return success or failure to
    445   1.8   plunky  * enable proper accounting but we own the mbuf.
    446   1.1  gdamore  */
    447   1.1  gdamore 
    448   1.8   plunky bool
    449   1.1  gdamore hci_input_event(struct hci_unit *unit, struct mbuf *m)
    450   1.1  gdamore {
    451   1.8   plunky 	bool rv;
    452   1.8   plunky 
    453   1.8   plunky 	mutex_enter(&unit->hci_devlock);
    454   1.1  gdamore 
    455   1.1  gdamore 	if (unit->hci_eventqlen > hci_eventq_max || unit->hci_rxint == NULL) {
    456   1.7   plunky 		DPRINTF("(%s) dropped event packet.\n", device_xname(unit->hci_dev));
    457   1.1  gdamore 		m_freem(m);
    458   1.8   plunky 		rv = false;
    459   1.1  gdamore 	} else {
    460   1.1  gdamore 		unit->hci_eventqlen++;
    461   1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_eventq, m);
    462   1.5       ad 		softint_schedule(unit->hci_rxint);
    463   1.8   plunky 		rv = true;
    464   1.1  gdamore 	}
    465   1.8   plunky 
    466   1.8   plunky 	mutex_exit(&unit->hci_devlock);
    467   1.8   plunky 	return rv;
    468   1.1  gdamore }
    469   1.1  gdamore 
    470   1.8   plunky bool
    471   1.1  gdamore hci_input_acl(struct hci_unit *unit, struct mbuf *m)
    472   1.1  gdamore {
    473   1.8   plunky 	bool rv;
    474   1.8   plunky 
    475   1.8   plunky 	mutex_enter(&unit->hci_devlock);
    476   1.1  gdamore 
    477   1.1  gdamore 	if (unit->hci_aclrxqlen > hci_aclrxq_max || unit->hci_rxint == NULL) {
    478   1.7   plunky 		DPRINTF("(%s) dropped ACL packet.\n", device_xname(unit->hci_dev));
    479   1.1  gdamore 		m_freem(m);
    480   1.8   plunky 		rv = false;
    481   1.1  gdamore 	} else {
    482   1.1  gdamore 		unit->hci_aclrxqlen++;
    483   1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_aclrxq, m);
    484   1.5       ad 		softint_schedule(unit->hci_rxint);
    485   1.8   plunky 		rv = true;
    486   1.1  gdamore 	}
    487   1.8   plunky 
    488   1.8   plunky 	mutex_exit(&unit->hci_devlock);
    489   1.8   plunky 	return rv;
    490   1.1  gdamore }
    491   1.1  gdamore 
    492   1.8   plunky bool
    493   1.1  gdamore hci_input_sco(struct hci_unit *unit, struct mbuf *m)
    494   1.1  gdamore {
    495   1.8   plunky 	bool rv;
    496   1.8   plunky 
    497   1.8   plunky 	mutex_enter(&unit->hci_devlock);
    498   1.1  gdamore 
    499   1.1  gdamore 	if (unit->hci_scorxqlen > hci_scorxq_max || unit->hci_rxint == NULL) {
    500   1.7   plunky 		DPRINTF("(%s) dropped SCO packet.\n", device_xname(unit->hci_dev));
    501   1.1  gdamore 		m_freem(m);
    502   1.8   plunky 		rv = false;
    503   1.1  gdamore 	} else {
    504   1.1  gdamore 		unit->hci_scorxqlen++;
    505   1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_scorxq, m);
    506   1.5       ad 		softint_schedule(unit->hci_rxint);
    507   1.8   plunky 		rv = true;
    508   1.1  gdamore 	}
    509   1.8   plunky 
    510   1.8   plunky 	mutex_exit(&unit->hci_devlock);
    511   1.8   plunky 	return rv;
    512   1.1  gdamore }
    513   1.1  gdamore 
    514   1.1  gdamore void
    515   1.1  gdamore hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
    516   1.1  gdamore {
    517   1.1  gdamore 	void *arg;
    518   1.1  gdamore 
    519   1.1  gdamore 	hci_mtap(m, unit);
    520   1.1  gdamore 
    521   1.7   plunky 	DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", device_xname(unit->hci_dev),
    522   1.1  gdamore 					       unit->hci_num_cmd_pkts);
    523   1.1  gdamore 
    524   1.1  gdamore 	unit->hci_num_cmd_pkts--;
    525   1.1  gdamore 
    526   1.1  gdamore 	/*
    527   1.1  gdamore 	 * If context is set, this was from a HCI raw socket
    528   1.1  gdamore 	 * and a record needs to be dropped from the sockbuf.
    529   1.1  gdamore 	 */
    530   1.1  gdamore 	arg = M_GETCTX(m, void *);
    531   1.1  gdamore 	if (arg != NULL)
    532   1.1  gdamore 		hci_drop(arg);
    533   1.1  gdamore 
    534   1.8   plunky 	(*unit->hci_if->output_cmd)(unit->hci_dev, m);
    535   1.1  gdamore }
    536   1.1  gdamore 
    537   1.1  gdamore void
    538   1.1  gdamore hci_output_acl(struct hci_unit *unit, struct mbuf *m)
    539   1.1  gdamore {
    540   1.1  gdamore 
    541   1.1  gdamore 	hci_mtap(m, unit);
    542   1.1  gdamore 
    543   1.7   plunky 	DPRINTFN(10, "(%s) num_acl_pkts=%d\n", device_xname(unit->hci_dev),
    544   1.1  gdamore 					       unit->hci_num_acl_pkts);
    545   1.1  gdamore 
    546   1.1  gdamore 	unit->hci_num_acl_pkts--;
    547   1.8   plunky 	(*unit->hci_if->output_acl)(unit->hci_dev, m);
    548   1.1  gdamore }
    549   1.1  gdamore 
    550   1.1  gdamore void
    551   1.1  gdamore hci_output_sco(struct hci_unit *unit, struct mbuf *m)
    552   1.1  gdamore {
    553   1.1  gdamore 
    554   1.1  gdamore 	hci_mtap(m, unit);
    555   1.1  gdamore 
    556   1.7   plunky 	DPRINTFN(10, "(%s) num_sco_pkts=%d\n", device_xname(unit->hci_dev),
    557   1.1  gdamore 					       unit->hci_num_sco_pkts);
    558   1.1  gdamore 
    559   1.1  gdamore 	unit->hci_num_sco_pkts--;
    560   1.8   plunky 	(*unit->hci_if->output_sco)(unit->hci_dev, m);
    561   1.1  gdamore }
    562   1.1  gdamore 
    563   1.8   plunky bool
    564   1.1  gdamore hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
    565   1.1  gdamore {
    566   1.1  gdamore 
    567   1.1  gdamore 	if (unit->hci_rxint == NULL) {
    568   1.7   plunky 		DPRINTFN(10, "(%s) complete SCO!\n", device_xname(unit->hci_dev));
    569   1.1  gdamore 		m_freem(m);
    570   1.8   plunky 		return false;
    571   1.1  gdamore 	}
    572   1.8   plunky 
    573   1.8   plunky 	mutex_enter(&unit->hci_devlock);
    574   1.8   plunky 
    575   1.8   plunky 	MBUFQ_ENQUEUE(&unit->hci_scodone, m);
    576   1.8   plunky 	softint_schedule(unit->hci_rxint);
    577   1.8   plunky 
    578   1.8   plunky 	mutex_exit(&unit->hci_devlock);
    579   1.8   plunky 	return true;
    580   1.1  gdamore }
    581