Home | History | Annotate | Line # | Download | only in netbt
hci_unit.c revision 1.9.6.1
      1  1.9.6.1      mjf /*	$NetBSD: hci_unit.c,v 1.9.6.1 2008/04/03 12:43:08 mjf 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.9.6.1      mjf __KERNEL_RCSID(0, "$NetBSD: hci_unit.c,v 1.9.6.1 2008/04/03 12:43:08 mjf 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.1  gdamore 
     47      1.1  gdamore #include <netbt/bluetooth.h>
     48      1.1  gdamore #include <netbt/hci.h>
     49      1.1  gdamore 
     50      1.1  gdamore struct hci_unit_list hci_unit_list = SIMPLEQ_HEAD_INITIALIZER(hci_unit_list);
     51      1.1  gdamore 
     52      1.1  gdamore MALLOC_DEFINE(M_BLUETOOTH, "Bluetooth", "Bluetooth System Memory");
     53      1.1  gdamore 
     54      1.1  gdamore /*
     55      1.1  gdamore  * HCI Input Queue max lengths.
     56      1.1  gdamore  */
     57      1.1  gdamore int hci_eventq_max = 20;
     58      1.1  gdamore int hci_aclrxq_max = 50;
     59      1.1  gdamore int hci_scorxq_max = 50;
     60      1.1  gdamore 
     61      1.1  gdamore /*
     62      1.9   plunky  * This is the default minimum command set supported by older
     63      1.9   plunky  * devices. Anything conforming to 1.2 spec or later will get
     64      1.9   plunky  * updated during init.
     65      1.9   plunky  */
     66      1.9   plunky static const uint8_t hci_cmds_v10[HCI_COMMANDS_SIZE] = {
     67      1.9   plunky 	0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff,
     68      1.9   plunky 	0xff, 0xff, 0xff, 0x7f, 0x32, 0x03, 0xb8, 0xfe,
     69      1.9   plunky 	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     70      1.9   plunky 	0x00, 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 };
     76      1.9   plunky 
     77      1.9   plunky /*
     78      1.1  gdamore  * bluetooth unit functions
     79      1.1  gdamore  */
     80      1.1  gdamore static void hci_intr (void *);
     81      1.1  gdamore 
     82      1.8   plunky struct hci_unit *
     83      1.8   plunky hci_attach(const struct hci_if *hci_if, device_t dev, uint16_t flags)
     84      1.1  gdamore {
     85      1.8   plunky 	struct hci_unit *unit;
     86      1.8   plunky 	int s;
     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.1  gdamore 
    105      1.1  gdamore 	MBUFQ_INIT(&unit->hci_eventq);
    106      1.1  gdamore 	MBUFQ_INIT(&unit->hci_aclrxq);
    107      1.1  gdamore 	MBUFQ_INIT(&unit->hci_scorxq);
    108      1.1  gdamore 	MBUFQ_INIT(&unit->hci_cmdwait);
    109      1.1  gdamore 	MBUFQ_INIT(&unit->hci_scodone);
    110      1.1  gdamore 
    111      1.1  gdamore 	TAILQ_INIT(&unit->hci_links);
    112      1.1  gdamore 	LIST_INIT(&unit->hci_memos);
    113      1.1  gdamore 
    114      1.8   plunky 	s = splsoftnet();
    115      1.1  gdamore 	SIMPLEQ_INSERT_TAIL(&hci_unit_list, unit, hci_next);
    116      1.8   plunky 	splx(s);
    117      1.8   plunky 
    118      1.8   plunky 	return unit;
    119      1.1  gdamore }
    120      1.1  gdamore 
    121      1.1  gdamore void
    122      1.1  gdamore hci_detach(struct hci_unit *unit)
    123      1.1  gdamore {
    124      1.8   plunky 	int s;
    125      1.1  gdamore 
    126      1.8   plunky 	s = splsoftnet();
    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.8   plunky 	splx(s);
    131      1.8   plunky 
    132      1.8   plunky 	mutex_destroy(&unit->hci_devlock);
    133      1.8   plunky 	free(unit, M_BLUETOOTH);
    134      1.1  gdamore }
    135      1.1  gdamore 
    136      1.1  gdamore int
    137      1.1  gdamore hci_enable(struct hci_unit *unit)
    138      1.1  gdamore {
    139      1.8   plunky 	int err;
    140      1.1  gdamore 
    141      1.1  gdamore 	/*
    142      1.1  gdamore 	 * Bluetooth spec says that a device can accept one
    143      1.1  gdamore 	 * command on power up until they send a Command Status
    144      1.1  gdamore 	 * or Command Complete event with more information, but
    145      1.1  gdamore 	 * it seems that some devices cant and prefer to send a
    146      1.8   plunky 	 * No-op Command Status packet when they are ready.
    147      1.1  gdamore 	 */
    148      1.8   plunky 	unit->hci_num_cmd_pkts = (unit->hci_flags & BTF_POWER_UP_NOOP) ? 0 : 1;
    149      1.1  gdamore 	unit->hci_num_acl_pkts = 0;
    150      1.1  gdamore 	unit->hci_num_sco_pkts = 0;
    151      1.1  gdamore 
    152      1.1  gdamore 	/*
    153      1.1  gdamore 	 * only allow the basic packet types until
    154      1.1  gdamore 	 * the features report is in
    155      1.1  gdamore 	 */
    156      1.1  gdamore 	unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
    157      1.1  gdamore 	unit->hci_packet_type = unit->hci_acl_mask;
    158      1.1  gdamore 
    159      1.9   plunky 	memcpy(unit->hci_cmds, hci_cmds_v10, HCI_COMMANDS_SIZE);
    160      1.9   plunky 
    161      1.5       ad 	unit->hci_rxint = softint_establish(SOFTINT_NET, &hci_intr, unit);
    162      1.1  gdamore 	if (unit->hci_rxint == NULL)
    163      1.1  gdamore 		return EIO;
    164      1.1  gdamore 
    165      1.8   plunky 	err = (*unit->hci_if->enable)(unit->hci_dev);
    166      1.1  gdamore 	if (err)
    167      1.1  gdamore 		goto bad1;
    168      1.1  gdamore 
    169      1.8   plunky 	unit->hci_flags |= BTF_RUNNING;
    170      1.8   plunky 
    171      1.1  gdamore 	/*
    172      1.1  gdamore 	 * Reset the device, this will trigger initialisation
    173      1.1  gdamore 	 * and wake us up.
    174      1.1  gdamore 	 */
    175      1.1  gdamore 	unit->hci_flags |= BTF_INIT;
    176      1.1  gdamore 
    177      1.1  gdamore 	err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0);
    178      1.1  gdamore 	if (err)
    179      1.1  gdamore 		goto bad2;
    180      1.1  gdamore 
    181      1.1  gdamore 	while (unit->hci_flags & BTF_INIT) {
    182      1.2  gdamore 		err = tsleep(unit, PWAIT | PCATCH, __func__, 5 * hz);
    183      1.1  gdamore 		if (err)
    184      1.1  gdamore 			goto bad2;
    185      1.1  gdamore 
    186      1.1  gdamore 		/* XXX
    187      1.1  gdamore 		 * "What If", while we were sleeping, the device
    188      1.1  gdamore 		 * was removed and detached? Ho Hum.
    189      1.1  gdamore 		 */
    190      1.1  gdamore 	}
    191      1.1  gdamore 
    192      1.3   plunky 	/*
    193      1.3   plunky 	 * Attach Bluetooth Device Hub
    194      1.3   plunky 	 */
    195      1.7   plunky 	unit->hci_bthub = config_found_ia(unit->hci_dev,
    196      1.3   plunky 					  "btbus", &unit->hci_bdaddr, NULL);
    197      1.3   plunky 
    198      1.1  gdamore 	return 0;
    199      1.1  gdamore 
    200      1.1  gdamore bad2:
    201      1.8   plunky 	(*unit->hci_if->disable)(unit->hci_dev);
    202      1.8   plunky 	unit->hci_flags &= ~BTF_RUNNING;
    203      1.1  gdamore bad1:
    204      1.5       ad 	softint_disestablish(unit->hci_rxint);
    205      1.1  gdamore 	unit->hci_rxint = NULL;
    206      1.1  gdamore 
    207      1.1  gdamore 	return err;
    208      1.1  gdamore }
    209      1.1  gdamore 
    210      1.1  gdamore void
    211      1.1  gdamore hci_disable(struct hci_unit *unit)
    212      1.1  gdamore {
    213      1.1  gdamore 	struct hci_link *link, *next;
    214      1.1  gdamore 	struct hci_memo *memo;
    215      1.8   plunky 	int acl;
    216      1.1  gdamore 
    217      1.3   plunky 	if (unit->hci_bthub) {
    218      1.3   plunky 		config_detach(unit->hci_bthub, DETACH_FORCE);
    219      1.3   plunky 		unit->hci_bthub = NULL;
    220      1.3   plunky 	}
    221      1.3   plunky 
    222      1.1  gdamore 	if (unit->hci_rxint) {
    223      1.5       ad 		softint_disestablish(unit->hci_rxint);
    224      1.1  gdamore 		unit->hci_rxint = NULL;
    225      1.1  gdamore 	}
    226      1.1  gdamore 
    227      1.8   plunky 	(*unit->hci_if->disable)(unit->hci_dev);
    228      1.8   plunky 	unit->hci_flags &= ~BTF_RUNNING;
    229      1.1  gdamore 
    230      1.1  gdamore 	/*
    231      1.1  gdamore 	 * close down any links, take care to close SCO first since
    232      1.1  gdamore 	 * they may depend on ACL links.
    233      1.1  gdamore 	 */
    234      1.1  gdamore 	for (acl = 0 ; acl < 2 ; acl++) {
    235      1.1  gdamore 		next = TAILQ_FIRST(&unit->hci_links);
    236      1.1  gdamore 		while ((link = next) != NULL) {
    237      1.1  gdamore 			next = TAILQ_NEXT(link, hl_next);
    238      1.1  gdamore 			if (acl || link->hl_type != HCI_LINK_ACL)
    239      1.1  gdamore 				hci_link_free(link, ECONNABORTED);
    240      1.1  gdamore 		}
    241      1.1  gdamore 	}
    242      1.1  gdamore 
    243      1.1  gdamore 	while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
    244      1.1  gdamore 		hci_memo_free(memo);
    245      1.1  gdamore 
    246      1.8   plunky 	/* (no need to hold hci_devlock, the driver is disabled) */
    247      1.8   plunky 
    248      1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_eventq);
    249      1.1  gdamore 	unit->hci_eventqlen = 0;
    250      1.1  gdamore 
    251      1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_aclrxq);
    252      1.1  gdamore 	unit->hci_aclrxqlen = 0;
    253      1.1  gdamore 
    254      1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_scorxq);
    255      1.1  gdamore 	unit->hci_scorxqlen = 0;
    256      1.1  gdamore 
    257      1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_cmdwait);
    258      1.1  gdamore 	MBUFQ_DRAIN(&unit->hci_scodone);
    259      1.1  gdamore }
    260      1.1  gdamore 
    261      1.1  gdamore struct hci_unit *
    262      1.1  gdamore hci_unit_lookup(bdaddr_t *addr)
    263      1.1  gdamore {
    264      1.1  gdamore 	struct hci_unit *unit;
    265      1.1  gdamore 
    266      1.1  gdamore 	SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
    267      1.1  gdamore 		if ((unit->hci_flags & BTF_UP) == 0)
    268      1.1  gdamore 			continue;
    269      1.1  gdamore 
    270      1.1  gdamore 		if (bdaddr_same(&unit->hci_bdaddr, addr))
    271      1.1  gdamore 			break;
    272      1.1  gdamore 	}
    273      1.1  gdamore 
    274      1.1  gdamore 	return unit;
    275      1.1  gdamore }
    276      1.1  gdamore 
    277      1.1  gdamore /*
    278  1.9.6.1      mjf  * update num_cmd_pkts and push on pending commands queue
    279  1.9.6.1      mjf  */
    280  1.9.6.1      mjf void
    281  1.9.6.1      mjf hci_num_cmds(struct hci_unit *unit, uint8_t num)
    282  1.9.6.1      mjf {
    283  1.9.6.1      mjf 	struct mbuf *m;
    284  1.9.6.1      mjf 
    285  1.9.6.1      mjf 	unit->hci_num_cmd_pkts = num;
    286  1.9.6.1      mjf 
    287  1.9.6.1      mjf 	while (unit->hci_num_cmd_pkts > 0 && MBUFQ_FIRST(&unit->hci_cmdwait)) {
    288  1.9.6.1      mjf 		MBUFQ_DEQUEUE(&unit->hci_cmdwait, m);
    289  1.9.6.1      mjf 		hci_output_cmd(unit, m);
    290  1.9.6.1      mjf 	}
    291  1.9.6.1      mjf }
    292  1.9.6.1      mjf 
    293  1.9.6.1      mjf /*
    294      1.1  gdamore  * construct and queue a HCI command packet
    295      1.1  gdamore  */
    296      1.1  gdamore int
    297      1.1  gdamore hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
    298      1.1  gdamore {
    299      1.1  gdamore 	struct mbuf *m;
    300      1.1  gdamore 	hci_cmd_hdr_t *p;
    301      1.1  gdamore 
    302      1.4   plunky 	KASSERT(unit != NULL);
    303      1.1  gdamore 
    304      1.1  gdamore 	m = m_gethdr(M_DONTWAIT, MT_DATA);
    305      1.1  gdamore 	if (m == NULL)
    306      1.1  gdamore 		return ENOMEM;
    307      1.1  gdamore 
    308      1.1  gdamore 	p = mtod(m, hci_cmd_hdr_t *);
    309      1.1  gdamore 	p->type = HCI_CMD_PKT;
    310      1.1  gdamore 	p->opcode = htole16(opcode);
    311      1.1  gdamore 	p->length = len;
    312      1.1  gdamore 	m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
    313      1.1  gdamore 
    314      1.1  gdamore 	if (len) {
    315      1.4   plunky 		KASSERT(buf != NULL);
    316      1.1  gdamore 
    317      1.1  gdamore 		m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf);
    318      1.1  gdamore 		if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) {
    319      1.1  gdamore 			m_freem(m);
    320      1.1  gdamore 			return ENOMEM;
    321      1.1  gdamore 		}
    322      1.1  gdamore 	}
    323      1.1  gdamore 
    324      1.7   plunky 	DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", device_xname(unit->hci_dev),
    325      1.1  gdamore 		HCI_OGF(opcode), HCI_OCF(opcode));
    326      1.1  gdamore 
    327      1.1  gdamore 	/* and send it on */
    328      1.1  gdamore 	if (unit->hci_num_cmd_pkts == 0)
    329      1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_cmdwait, m);
    330      1.1  gdamore 	else
    331      1.1  gdamore 		hci_output_cmd(unit, m);
    332      1.1  gdamore 
    333      1.1  gdamore 	return 0;
    334      1.1  gdamore }
    335      1.1  gdamore 
    336      1.1  gdamore /*
    337      1.1  gdamore  * Incoming packet processing. Since the code is single threaded
    338      1.1  gdamore  * in any case (IPL_SOFTNET), we handle it all in one interrupt function
    339      1.1  gdamore  * picking our way through more important packets first so that hopefully
    340      1.1  gdamore  * we will never get clogged up with bulk data.
    341      1.1  gdamore  */
    342      1.1  gdamore static void
    343      1.1  gdamore hci_intr(void *arg)
    344      1.1  gdamore {
    345      1.1  gdamore 	struct hci_unit *unit = arg;
    346      1.1  gdamore 	struct mbuf *m;
    347      1.1  gdamore 
    348      1.1  gdamore another:
    349      1.8   plunky 	mutex_enter(&unit->hci_devlock);
    350      1.1  gdamore 
    351      1.1  gdamore 	if (unit->hci_eventqlen > 0) {
    352      1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_eventq, m);
    353      1.1  gdamore 		unit->hci_eventqlen--;
    354      1.8   plunky 		mutex_exit(&unit->hci_devlock);
    355      1.8   plunky 
    356      1.1  gdamore 		KASSERT(m != NULL);
    357      1.1  gdamore 
    358      1.1  gdamore 		DPRINTFN(10, "(%s) recv event, len = %d\n",
    359      1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    360      1.1  gdamore 
    361      1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    362      1.1  gdamore 		hci_mtap(m, unit);
    363      1.1  gdamore 		hci_event(m, unit);
    364      1.1  gdamore 
    365      1.1  gdamore 		goto another;
    366      1.1  gdamore 	}
    367      1.1  gdamore 
    368      1.1  gdamore 	if (unit->hci_scorxqlen > 0) {
    369      1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_scorxq, m);
    370      1.1  gdamore 		unit->hci_scorxqlen--;
    371      1.8   plunky 		mutex_exit(&unit->hci_devlock);
    372      1.8   plunky 
    373      1.1  gdamore 		KASSERT(m != NULL);
    374      1.1  gdamore 
    375      1.1  gdamore 		DPRINTFN(10, "(%s) recv SCO, len = %d\n",
    376      1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    377      1.1  gdamore 
    378      1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    379      1.1  gdamore 		hci_mtap(m, unit);
    380      1.1  gdamore 		hci_sco_recv(m, unit);
    381      1.1  gdamore 
    382      1.1  gdamore 		goto another;
    383      1.1  gdamore 	}
    384      1.1  gdamore 
    385      1.1  gdamore 	if (unit->hci_aclrxqlen > 0) {
    386      1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_aclrxq, m);
    387      1.1  gdamore 		unit->hci_aclrxqlen--;
    388      1.8   plunky 		mutex_exit(&unit->hci_devlock);
    389      1.8   plunky 
    390      1.1  gdamore 		KASSERT(m != NULL);
    391      1.1  gdamore 
    392      1.1  gdamore 		DPRINTFN(10, "(%s) recv ACL, len = %d\n",
    393      1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    394      1.1  gdamore 
    395      1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    396      1.1  gdamore 		hci_mtap(m, unit);
    397      1.1  gdamore 		hci_acl_recv(m, unit);
    398      1.1  gdamore 
    399      1.1  gdamore 		goto another;
    400      1.1  gdamore 	}
    401      1.1  gdamore 
    402      1.1  gdamore 	MBUFQ_DEQUEUE(&unit->hci_scodone, m);
    403      1.1  gdamore 	if (m != NULL) {
    404      1.1  gdamore 		struct hci_link *link;
    405      1.8   plunky 
    406      1.8   plunky 		mutex_exit(&unit->hci_devlock);
    407      1.1  gdamore 
    408      1.1  gdamore 		DPRINTFN(11, "(%s) complete SCO\n",
    409      1.7   plunky 				device_xname(unit->hci_dev));
    410      1.1  gdamore 
    411      1.1  gdamore 		TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
    412      1.1  gdamore 			if (link == M_GETCTX(m, struct hci_link *)) {
    413      1.1  gdamore 				hci_sco_complete(link, 1);
    414      1.1  gdamore 				break;
    415      1.1  gdamore 			}
    416      1.1  gdamore 		}
    417      1.1  gdamore 
    418      1.1  gdamore 		unit->hci_num_sco_pkts++;
    419      1.1  gdamore 		m_freem(m);
    420      1.1  gdamore 
    421      1.1  gdamore 		goto another;
    422      1.1  gdamore 	}
    423      1.1  gdamore 
    424      1.8   plunky 	mutex_exit(&unit->hci_devlock);
    425      1.1  gdamore 
    426      1.1  gdamore 	DPRINTFN(10, "done\n");
    427      1.1  gdamore }
    428      1.1  gdamore 
    429      1.1  gdamore /**********************************************************************
    430      1.1  gdamore  *
    431      1.1  gdamore  * IO routines
    432      1.1  gdamore  *
    433      1.8   plunky  * input & complete routines will be called from device drivers,
    434      1.8   plunky  * possibly in interrupt context. We return success or failure to
    435      1.8   plunky  * enable proper accounting but we own the mbuf.
    436      1.1  gdamore  */
    437      1.1  gdamore 
    438      1.8   plunky bool
    439      1.1  gdamore hci_input_event(struct hci_unit *unit, struct mbuf *m)
    440      1.1  gdamore {
    441      1.8   plunky 	bool rv;
    442      1.8   plunky 
    443      1.8   plunky 	mutex_enter(&unit->hci_devlock);
    444      1.1  gdamore 
    445      1.1  gdamore 	if (unit->hci_eventqlen > hci_eventq_max || unit->hci_rxint == NULL) {
    446      1.7   plunky 		DPRINTF("(%s) dropped event packet.\n", device_xname(unit->hci_dev));
    447      1.1  gdamore 		m_freem(m);
    448      1.8   plunky 		rv = false;
    449      1.1  gdamore 	} else {
    450      1.1  gdamore 		unit->hci_eventqlen++;
    451      1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_eventq, m);
    452      1.5       ad 		softint_schedule(unit->hci_rxint);
    453      1.8   plunky 		rv = true;
    454      1.1  gdamore 	}
    455      1.8   plunky 
    456      1.8   plunky 	mutex_exit(&unit->hci_devlock);
    457      1.8   plunky 	return rv;
    458      1.1  gdamore }
    459      1.1  gdamore 
    460      1.8   plunky bool
    461      1.1  gdamore hci_input_acl(struct hci_unit *unit, struct mbuf *m)
    462      1.1  gdamore {
    463      1.8   plunky 	bool rv;
    464      1.8   plunky 
    465      1.8   plunky 	mutex_enter(&unit->hci_devlock);
    466      1.1  gdamore 
    467      1.1  gdamore 	if (unit->hci_aclrxqlen > hci_aclrxq_max || unit->hci_rxint == NULL) {
    468      1.7   plunky 		DPRINTF("(%s) dropped ACL packet.\n", device_xname(unit->hci_dev));
    469      1.1  gdamore 		m_freem(m);
    470      1.8   plunky 		rv = false;
    471      1.1  gdamore 	} else {
    472      1.1  gdamore 		unit->hci_aclrxqlen++;
    473      1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_aclrxq, m);
    474      1.5       ad 		softint_schedule(unit->hci_rxint);
    475      1.8   plunky 		rv = true;
    476      1.1  gdamore 	}
    477      1.8   plunky 
    478      1.8   plunky 	mutex_exit(&unit->hci_devlock);
    479      1.8   plunky 	return rv;
    480      1.1  gdamore }
    481      1.1  gdamore 
    482      1.8   plunky bool
    483      1.1  gdamore hci_input_sco(struct hci_unit *unit, struct mbuf *m)
    484      1.1  gdamore {
    485      1.8   plunky 	bool rv;
    486      1.8   plunky 
    487      1.8   plunky 	mutex_enter(&unit->hci_devlock);
    488      1.1  gdamore 
    489      1.1  gdamore 	if (unit->hci_scorxqlen > hci_scorxq_max || unit->hci_rxint == NULL) {
    490      1.7   plunky 		DPRINTF("(%s) dropped SCO packet.\n", device_xname(unit->hci_dev));
    491      1.1  gdamore 		m_freem(m);
    492      1.8   plunky 		rv = false;
    493      1.1  gdamore 	} else {
    494      1.1  gdamore 		unit->hci_scorxqlen++;
    495      1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_scorxq, m);
    496      1.5       ad 		softint_schedule(unit->hci_rxint);
    497      1.8   plunky 		rv = true;
    498      1.1  gdamore 	}
    499      1.8   plunky 
    500      1.8   plunky 	mutex_exit(&unit->hci_devlock);
    501      1.8   plunky 	return rv;
    502      1.1  gdamore }
    503      1.1  gdamore 
    504      1.1  gdamore void
    505      1.1  gdamore hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
    506      1.1  gdamore {
    507      1.1  gdamore 	void *arg;
    508      1.1  gdamore 
    509      1.1  gdamore 	hci_mtap(m, unit);
    510      1.1  gdamore 
    511      1.7   plunky 	DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", device_xname(unit->hci_dev),
    512      1.1  gdamore 					       unit->hci_num_cmd_pkts);
    513      1.1  gdamore 
    514      1.1  gdamore 	unit->hci_num_cmd_pkts--;
    515      1.1  gdamore 
    516      1.1  gdamore 	/*
    517      1.1  gdamore 	 * If context is set, this was from a HCI raw socket
    518      1.1  gdamore 	 * and a record needs to be dropped from the sockbuf.
    519      1.1  gdamore 	 */
    520      1.1  gdamore 	arg = M_GETCTX(m, void *);
    521      1.1  gdamore 	if (arg != NULL)
    522      1.1  gdamore 		hci_drop(arg);
    523      1.1  gdamore 
    524      1.8   plunky 	(*unit->hci_if->output_cmd)(unit->hci_dev, m);
    525      1.1  gdamore }
    526      1.1  gdamore 
    527      1.1  gdamore void
    528      1.1  gdamore hci_output_acl(struct hci_unit *unit, struct mbuf *m)
    529      1.1  gdamore {
    530      1.1  gdamore 
    531      1.1  gdamore 	hci_mtap(m, unit);
    532      1.1  gdamore 
    533      1.7   plunky 	DPRINTFN(10, "(%s) num_acl_pkts=%d\n", device_xname(unit->hci_dev),
    534      1.1  gdamore 					       unit->hci_num_acl_pkts);
    535      1.1  gdamore 
    536      1.1  gdamore 	unit->hci_num_acl_pkts--;
    537      1.8   plunky 	(*unit->hci_if->output_acl)(unit->hci_dev, m);
    538      1.1  gdamore }
    539      1.1  gdamore 
    540      1.1  gdamore void
    541      1.1  gdamore hci_output_sco(struct hci_unit *unit, struct mbuf *m)
    542      1.1  gdamore {
    543      1.1  gdamore 
    544      1.1  gdamore 	hci_mtap(m, unit);
    545      1.1  gdamore 
    546      1.7   plunky 	DPRINTFN(10, "(%s) num_sco_pkts=%d\n", device_xname(unit->hci_dev),
    547      1.1  gdamore 					       unit->hci_num_sco_pkts);
    548      1.1  gdamore 
    549      1.1  gdamore 	unit->hci_num_sco_pkts--;
    550      1.8   plunky 	(*unit->hci_if->output_sco)(unit->hci_dev, m);
    551      1.1  gdamore }
    552      1.1  gdamore 
    553      1.8   plunky bool
    554      1.1  gdamore hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
    555      1.1  gdamore {
    556      1.1  gdamore 
    557      1.1  gdamore 	if (unit->hci_rxint == NULL) {
    558      1.7   plunky 		DPRINTFN(10, "(%s) complete SCO!\n", device_xname(unit->hci_dev));
    559      1.1  gdamore 		m_freem(m);
    560      1.8   plunky 		return false;
    561      1.1  gdamore 	}
    562      1.8   plunky 
    563      1.8   plunky 	mutex_enter(&unit->hci_devlock);
    564      1.8   plunky 
    565      1.8   plunky 	MBUFQ_ENQUEUE(&unit->hci_scodone, m);
    566      1.8   plunky 	softint_schedule(unit->hci_rxint);
    567      1.8   plunky 
    568      1.8   plunky 	mutex_exit(&unit->hci_devlock);
    569      1.8   plunky 	return true;
    570      1.1  gdamore }
    571