Home | History | Annotate | Line # | Download | only in netbt
      1  1.16  thorpej /*	$NetBSD: hci_unit.c,v 1.16 2021/08/07 16:19:18 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.16  thorpej __KERNEL_RCSID(0, "$NetBSD: hci_unit.c,v 1.16 2021/08/07 16:19:18 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.16  thorpej 	    CFARGS(.iattr = "btbus"));
    198   1.3   plunky 
    199   1.1  gdamore 	return 0;
    200   1.1  gdamore 
    201   1.1  gdamore bad2:
    202   1.8   plunky 	(*unit->hci_if->disable)(unit->hci_dev);
    203   1.8   plunky 	unit->hci_flags &= ~BTF_RUNNING;
    204   1.1  gdamore bad1:
    205   1.5       ad 	softint_disestablish(unit->hci_rxint);
    206   1.1  gdamore 	unit->hci_rxint = NULL;
    207   1.1  gdamore 
    208   1.1  gdamore 	return err;
    209   1.1  gdamore }
    210   1.1  gdamore 
    211   1.1  gdamore void
    212   1.1  gdamore hci_disable(struct hci_unit *unit)
    213   1.1  gdamore {
    214   1.1  gdamore 	struct hci_link *link, *next;
    215   1.1  gdamore 	struct hci_memo *memo;
    216   1.8   plunky 	int acl;
    217   1.1  gdamore 
    218   1.3   plunky 	if (unit->hci_bthub) {
    219  1.12   plunky 		device_t hub;
    220  1.12   plunky 
    221  1.12   plunky 		hub = unit->hci_bthub;
    222   1.3   plunky 		unit->hci_bthub = NULL;
    223  1.12   plunky 
    224  1.12   plunky 		mutex_exit(bt_lock);
    225  1.12   plunky 		config_detach(hub, DETACH_FORCE);
    226  1.12   plunky 		mutex_enter(bt_lock);
    227   1.3   plunky 	}
    228   1.3   plunky 
    229   1.1  gdamore 	if (unit->hci_rxint) {
    230   1.5       ad 		softint_disestablish(unit->hci_rxint);
    231   1.1  gdamore 		unit->hci_rxint = NULL;
    232   1.1  gdamore 	}
    233   1.1  gdamore 
    234   1.8   plunky 	(*unit->hci_if->disable)(unit->hci_dev);
    235   1.8   plunky 	unit->hci_flags &= ~BTF_RUNNING;
    236   1.1  gdamore 
    237   1.1  gdamore 	/*
    238   1.1  gdamore 	 * close down any links, take care to close SCO first since
    239   1.1  gdamore 	 * they may depend on ACL links.
    240   1.1  gdamore 	 */
    241   1.1  gdamore 	for (acl = 0 ; acl < 2 ; acl++) {
    242   1.1  gdamore 		next = TAILQ_FIRST(&unit->hci_links);
    243   1.1  gdamore 		while ((link = next) != NULL) {
    244   1.1  gdamore 			next = TAILQ_NEXT(link, hl_next);
    245   1.1  gdamore 			if (acl || link->hl_type != HCI_LINK_ACL)
    246   1.1  gdamore 				hci_link_free(link, ECONNABORTED);
    247   1.1  gdamore 		}
    248   1.1  gdamore 	}
    249   1.1  gdamore 
    250   1.1  gdamore 	while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
    251   1.1  gdamore 		hci_memo_free(memo);
    252   1.1  gdamore 
    253   1.8   plunky 	/* (no need to hold hci_devlock, the driver is disabled) */
    254   1.8   plunky 
    255   1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_eventq);
    256   1.1  gdamore 	unit->hci_eventqlen = 0;
    257   1.1  gdamore 
    258   1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_aclrxq);
    259   1.1  gdamore 	unit->hci_aclrxqlen = 0;
    260   1.1  gdamore 
    261   1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_scorxq);
    262   1.1  gdamore 	unit->hci_scorxqlen = 0;
    263   1.1  gdamore 
    264   1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_cmdwait);
    265   1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_scodone);
    266   1.1  gdamore }
    267   1.1  gdamore 
    268   1.1  gdamore struct hci_unit *
    269  1.13   plunky hci_unit_lookup(const bdaddr_t *addr)
    270   1.1  gdamore {
    271   1.1  gdamore 	struct hci_unit *unit;
    272   1.1  gdamore 
    273   1.1  gdamore 	SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
    274   1.1  gdamore 		if ((unit->hci_flags & BTF_UP) == 0)
    275   1.1  gdamore 			continue;
    276   1.1  gdamore 
    277   1.1  gdamore 		if (bdaddr_same(&unit->hci_bdaddr, addr))
    278   1.1  gdamore 			break;
    279   1.1  gdamore 	}
    280   1.1  gdamore 
    281   1.1  gdamore 	return unit;
    282   1.1  gdamore }
    283   1.1  gdamore 
    284   1.1  gdamore /*
    285  1.10   plunky  * update num_cmd_pkts and push on pending commands queue
    286  1.10   plunky  */
    287  1.10   plunky void
    288  1.10   plunky hci_num_cmds(struct hci_unit *unit, uint8_t num)
    289  1.10   plunky {
    290  1.10   plunky 	struct mbuf *m;
    291  1.10   plunky 
    292  1.10   plunky 	unit->hci_num_cmd_pkts = num;
    293  1.10   plunky 
    294  1.10   plunky 	while (unit->hci_num_cmd_pkts > 0 && MBUFQ_FIRST(&unit->hci_cmdwait)) {
    295  1.10   plunky 		MBUFQ_DEQUEUE(&unit->hci_cmdwait, m);
    296  1.10   plunky 		hci_output_cmd(unit, m);
    297  1.10   plunky 	}
    298  1.10   plunky }
    299  1.10   plunky 
    300  1.10   plunky /*
    301   1.1  gdamore  * construct and queue a HCI command packet
    302   1.1  gdamore  */
    303   1.1  gdamore int
    304   1.1  gdamore hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
    305   1.1  gdamore {
    306   1.1  gdamore 	struct mbuf *m;
    307   1.1  gdamore 	hci_cmd_hdr_t *p;
    308   1.1  gdamore 
    309   1.4   plunky 	KASSERT(unit != NULL);
    310   1.1  gdamore 
    311   1.1  gdamore 	m = m_gethdr(M_DONTWAIT, MT_DATA);
    312   1.1  gdamore 	if (m == NULL)
    313   1.1  gdamore 		return ENOMEM;
    314   1.1  gdamore 
    315   1.1  gdamore 	p = mtod(m, hci_cmd_hdr_t *);
    316   1.1  gdamore 	p->type = HCI_CMD_PKT;
    317   1.1  gdamore 	p->opcode = htole16(opcode);
    318   1.1  gdamore 	p->length = len;
    319   1.1  gdamore 	m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
    320   1.1  gdamore 
    321   1.1  gdamore 	if (len) {
    322   1.4   plunky 		KASSERT(buf != NULL);
    323   1.1  gdamore 
    324   1.1  gdamore 		m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf);
    325   1.1  gdamore 		if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) {
    326   1.1  gdamore 			m_freem(m);
    327   1.1  gdamore 			return ENOMEM;
    328   1.1  gdamore 		}
    329   1.1  gdamore 	}
    330   1.1  gdamore 
    331   1.7   plunky 	DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", device_xname(unit->hci_dev),
    332   1.1  gdamore 		HCI_OGF(opcode), HCI_OCF(opcode));
    333   1.1  gdamore 
    334   1.1  gdamore 	/* and send it on */
    335   1.1  gdamore 	if (unit->hci_num_cmd_pkts == 0)
    336   1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_cmdwait, m);
    337   1.1  gdamore 	else
    338   1.1  gdamore 		hci_output_cmd(unit, m);
    339   1.1  gdamore 
    340   1.1  gdamore 	return 0;
    341   1.1  gdamore }
    342   1.1  gdamore 
    343   1.1  gdamore /*
    344   1.1  gdamore  * Incoming packet processing. Since the code is single threaded
    345   1.1  gdamore  * in any case (IPL_SOFTNET), we handle it all in one interrupt function
    346   1.1  gdamore  * picking our way through more important packets first so that hopefully
    347   1.1  gdamore  * we will never get clogged up with bulk data.
    348   1.1  gdamore  */
    349   1.1  gdamore static void
    350   1.1  gdamore hci_intr(void *arg)
    351   1.1  gdamore {
    352   1.1  gdamore 	struct hci_unit *unit = arg;
    353   1.1  gdamore 	struct mbuf *m;
    354   1.1  gdamore 
    355  1.11       ad 	mutex_enter(bt_lock);
    356   1.1  gdamore another:
    357   1.8   plunky 	mutex_enter(&unit->hci_devlock);
    358   1.1  gdamore 
    359   1.1  gdamore 	if (unit->hci_eventqlen > 0) {
    360   1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_eventq, m);
    361   1.1  gdamore 		unit->hci_eventqlen--;
    362   1.8   plunky 		mutex_exit(&unit->hci_devlock);
    363   1.8   plunky 
    364   1.1  gdamore 		KASSERT(m != NULL);
    365   1.1  gdamore 
    366   1.1  gdamore 		DPRINTFN(10, "(%s) recv event, len = %d\n",
    367   1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    368   1.1  gdamore 
    369   1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    370   1.1  gdamore 		hci_mtap(m, unit);
    371   1.1  gdamore 		hci_event(m, unit);
    372   1.1  gdamore 
    373   1.1  gdamore 		goto another;
    374   1.1  gdamore 	}
    375   1.1  gdamore 
    376   1.1  gdamore 	if (unit->hci_scorxqlen > 0) {
    377   1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_scorxq, m);
    378   1.1  gdamore 		unit->hci_scorxqlen--;
    379   1.8   plunky 		mutex_exit(&unit->hci_devlock);
    380   1.8   plunky 
    381   1.1  gdamore 		KASSERT(m != NULL);
    382   1.1  gdamore 
    383   1.1  gdamore 		DPRINTFN(10, "(%s) recv SCO, len = %d\n",
    384   1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    385   1.1  gdamore 
    386   1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    387   1.1  gdamore 		hci_mtap(m, unit);
    388   1.1  gdamore 		hci_sco_recv(m, unit);
    389   1.1  gdamore 
    390   1.1  gdamore 		goto another;
    391   1.1  gdamore 	}
    392   1.1  gdamore 
    393   1.1  gdamore 	if (unit->hci_aclrxqlen > 0) {
    394   1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_aclrxq, m);
    395   1.1  gdamore 		unit->hci_aclrxqlen--;
    396   1.8   plunky 		mutex_exit(&unit->hci_devlock);
    397   1.8   plunky 
    398   1.1  gdamore 		KASSERT(m != NULL);
    399   1.1  gdamore 
    400   1.1  gdamore 		DPRINTFN(10, "(%s) recv ACL, len = %d\n",
    401   1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    402   1.1  gdamore 
    403   1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    404   1.1  gdamore 		hci_mtap(m, unit);
    405   1.1  gdamore 		hci_acl_recv(m, unit);
    406   1.1  gdamore 
    407   1.1  gdamore 		goto another;
    408   1.1  gdamore 	}
    409   1.1  gdamore 
    410   1.1  gdamore 	MBUFQ_DEQUEUE(&unit->hci_scodone, m);
    411   1.1  gdamore 	if (m != NULL) {
    412   1.1  gdamore 		struct hci_link *link;
    413   1.8   plunky 
    414   1.8   plunky 		mutex_exit(&unit->hci_devlock);
    415   1.1  gdamore 
    416   1.1  gdamore 		DPRINTFN(11, "(%s) complete SCO\n",
    417   1.7   plunky 				device_xname(unit->hci_dev));
    418   1.1  gdamore 
    419   1.1  gdamore 		TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
    420   1.1  gdamore 			if (link == M_GETCTX(m, struct hci_link *)) {
    421   1.1  gdamore 				hci_sco_complete(link, 1);
    422   1.1  gdamore 				break;
    423   1.1  gdamore 			}
    424   1.1  gdamore 		}
    425   1.1  gdamore 
    426   1.1  gdamore 		unit->hci_num_sco_pkts++;
    427   1.1  gdamore 		m_freem(m);
    428   1.1  gdamore 
    429   1.1  gdamore 		goto another;
    430   1.1  gdamore 	}
    431   1.1  gdamore 
    432   1.8   plunky 	mutex_exit(&unit->hci_devlock);
    433  1.11       ad 	mutex_exit(bt_lock);
    434   1.1  gdamore 
    435   1.1  gdamore 	DPRINTFN(10, "done\n");
    436   1.1  gdamore }
    437   1.1  gdamore 
    438   1.1  gdamore /**********************************************************************
    439   1.1  gdamore  *
    440   1.1  gdamore  * IO routines
    441   1.1  gdamore  *
    442   1.8   plunky  * input & complete routines will be called from device drivers,
    443   1.8   plunky  * possibly in interrupt context. We return success or failure to
    444   1.8   plunky  * enable proper accounting but we own the mbuf.
    445   1.1  gdamore  */
    446   1.1  gdamore 
    447   1.8   plunky bool
    448   1.1  gdamore hci_input_event(struct hci_unit *unit, struct mbuf *m)
    449   1.1  gdamore {
    450   1.8   plunky 	bool rv;
    451   1.8   plunky 
    452   1.8   plunky 	mutex_enter(&unit->hci_devlock);
    453   1.1  gdamore 
    454   1.1  gdamore 	if (unit->hci_eventqlen > hci_eventq_max || unit->hci_rxint == NULL) {
    455   1.7   plunky 		DPRINTF("(%s) dropped event packet.\n", device_xname(unit->hci_dev));
    456   1.1  gdamore 		m_freem(m);
    457   1.8   plunky 		rv = false;
    458   1.1  gdamore 	} else {
    459   1.1  gdamore 		unit->hci_eventqlen++;
    460   1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_eventq, m);
    461   1.5       ad 		softint_schedule(unit->hci_rxint);
    462   1.8   plunky 		rv = true;
    463   1.1  gdamore 	}
    464   1.8   plunky 
    465   1.8   plunky 	mutex_exit(&unit->hci_devlock);
    466   1.8   plunky 	return rv;
    467   1.1  gdamore }
    468   1.1  gdamore 
    469   1.8   plunky bool
    470   1.1  gdamore hci_input_acl(struct hci_unit *unit, struct mbuf *m)
    471   1.1  gdamore {
    472   1.8   plunky 	bool rv;
    473   1.8   plunky 
    474   1.8   plunky 	mutex_enter(&unit->hci_devlock);
    475   1.1  gdamore 
    476   1.1  gdamore 	if (unit->hci_aclrxqlen > hci_aclrxq_max || unit->hci_rxint == NULL) {
    477   1.7   plunky 		DPRINTF("(%s) dropped ACL packet.\n", device_xname(unit->hci_dev));
    478   1.1  gdamore 		m_freem(m);
    479   1.8   plunky 		rv = false;
    480   1.1  gdamore 	} else {
    481   1.1  gdamore 		unit->hci_aclrxqlen++;
    482   1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_aclrxq, m);
    483   1.5       ad 		softint_schedule(unit->hci_rxint);
    484   1.8   plunky 		rv = true;
    485   1.1  gdamore 	}
    486   1.8   plunky 
    487   1.8   plunky 	mutex_exit(&unit->hci_devlock);
    488   1.8   plunky 	return rv;
    489   1.1  gdamore }
    490   1.1  gdamore 
    491   1.8   plunky bool
    492   1.1  gdamore hci_input_sco(struct hci_unit *unit, struct mbuf *m)
    493   1.1  gdamore {
    494   1.8   plunky 	bool rv;
    495   1.8   plunky 
    496   1.8   plunky 	mutex_enter(&unit->hci_devlock);
    497   1.1  gdamore 
    498   1.1  gdamore 	if (unit->hci_scorxqlen > hci_scorxq_max || unit->hci_rxint == NULL) {
    499   1.7   plunky 		DPRINTF("(%s) dropped SCO packet.\n", device_xname(unit->hci_dev));
    500   1.1  gdamore 		m_freem(m);
    501   1.8   plunky 		rv = false;
    502   1.1  gdamore 	} else {
    503   1.1  gdamore 		unit->hci_scorxqlen++;
    504   1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_scorxq, m);
    505   1.5       ad 		softint_schedule(unit->hci_rxint);
    506   1.8   plunky 		rv = true;
    507   1.1  gdamore 	}
    508   1.8   plunky 
    509   1.8   plunky 	mutex_exit(&unit->hci_devlock);
    510   1.8   plunky 	return rv;
    511   1.1  gdamore }
    512   1.1  gdamore 
    513   1.1  gdamore void
    514   1.1  gdamore hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
    515   1.1  gdamore {
    516   1.1  gdamore 	void *arg;
    517   1.1  gdamore 
    518   1.1  gdamore 	hci_mtap(m, unit);
    519   1.1  gdamore 
    520   1.7   plunky 	DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", device_xname(unit->hci_dev),
    521   1.1  gdamore 					       unit->hci_num_cmd_pkts);
    522   1.1  gdamore 
    523   1.1  gdamore 	unit->hci_num_cmd_pkts--;
    524   1.1  gdamore 
    525   1.1  gdamore 	/*
    526   1.1  gdamore 	 * If context is set, this was from a HCI raw socket
    527   1.1  gdamore 	 * and a record needs to be dropped from the sockbuf.
    528   1.1  gdamore 	 */
    529   1.1  gdamore 	arg = M_GETCTX(m, void *);
    530   1.1  gdamore 	if (arg != NULL)
    531   1.1  gdamore 		hci_drop(arg);
    532   1.1  gdamore 
    533   1.8   plunky 	(*unit->hci_if->output_cmd)(unit->hci_dev, m);
    534   1.1  gdamore }
    535   1.1  gdamore 
    536   1.1  gdamore void
    537   1.1  gdamore hci_output_acl(struct hci_unit *unit, struct mbuf *m)
    538   1.1  gdamore {
    539   1.1  gdamore 
    540   1.1  gdamore 	hci_mtap(m, unit);
    541   1.1  gdamore 
    542   1.7   plunky 	DPRINTFN(10, "(%s) num_acl_pkts=%d\n", device_xname(unit->hci_dev),
    543   1.1  gdamore 					       unit->hci_num_acl_pkts);
    544   1.1  gdamore 
    545   1.1  gdamore 	unit->hci_num_acl_pkts--;
    546   1.8   plunky 	(*unit->hci_if->output_acl)(unit->hci_dev, m);
    547   1.1  gdamore }
    548   1.1  gdamore 
    549   1.1  gdamore void
    550   1.1  gdamore hci_output_sco(struct hci_unit *unit, struct mbuf *m)
    551   1.1  gdamore {
    552   1.1  gdamore 
    553   1.1  gdamore 	hci_mtap(m, unit);
    554   1.1  gdamore 
    555   1.7   plunky 	DPRINTFN(10, "(%s) num_sco_pkts=%d\n", device_xname(unit->hci_dev),
    556   1.1  gdamore 					       unit->hci_num_sco_pkts);
    557   1.1  gdamore 
    558   1.1  gdamore 	unit->hci_num_sco_pkts--;
    559   1.8   plunky 	(*unit->hci_if->output_sco)(unit->hci_dev, m);
    560   1.1  gdamore }
    561   1.1  gdamore 
    562   1.8   plunky bool
    563   1.1  gdamore hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
    564   1.1  gdamore {
    565   1.1  gdamore 
    566   1.1  gdamore 	if (unit->hci_rxint == NULL) {
    567   1.7   plunky 		DPRINTFN(10, "(%s) complete SCO!\n", device_xname(unit->hci_dev));
    568   1.1  gdamore 		m_freem(m);
    569   1.8   plunky 		return false;
    570   1.1  gdamore 	}
    571   1.8   plunky 
    572   1.8   plunky 	mutex_enter(&unit->hci_devlock);
    573   1.8   plunky 
    574   1.8   plunky 	MBUFQ_ENQUEUE(&unit->hci_scodone, m);
    575   1.8   plunky 	softint_schedule(unit->hci_rxint);
    576   1.8   plunky 
    577   1.8   plunky 	mutex_exit(&unit->hci_devlock);
    578   1.8   plunky 	return true;
    579   1.1  gdamore }
    580