Home | History | Annotate | Line # | Download | only in netbt
hci_unit.c revision 1.8.6.1
      1  1.8.6.1   bouyer /*	$NetBSD: hci_unit.c,v 1.8.6.1 2008/01/02 21:57:17 bouyer 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.8.6.1   bouyer __KERNEL_RCSID(0, "$NetBSD: hci_unit.c,v 1.8.6.1 2008/01/02 21:57:17 bouyer 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.8.6.1   bouyer  * This is the default minimum command set supported by older
     63  1.8.6.1   bouyer  * devices. Anything conforming to 1.2 spec or later will get
     64  1.8.6.1   bouyer  * updated during init.
     65  1.8.6.1   bouyer  */
     66  1.8.6.1   bouyer static const uint8_t hci_cmds_v10[HCI_COMMANDS_SIZE] = {
     67  1.8.6.1   bouyer 	0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff,
     68  1.8.6.1   bouyer 	0xff, 0xff, 0xff, 0x7f, 0x32, 0x03, 0xb8, 0xfe,
     69  1.8.6.1   bouyer 	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     70  1.8.6.1   bouyer 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     71  1.8.6.1   bouyer 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     72  1.8.6.1   bouyer 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     73  1.8.6.1   bouyer 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     74  1.8.6.1   bouyer 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     75  1.8.6.1   bouyer };
     76  1.8.6.1   bouyer 
     77  1.8.6.1   bouyer /*
     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.8.6.1   bouyer 	memcpy(unit->hci_cmds, hci_cmds_v10, HCI_COMMANDS_SIZE);
    160  1.8.6.1   bouyer 
    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.1  gdamore  * construct and queue a HCI command packet
    279      1.1  gdamore  */
    280      1.1  gdamore int
    281      1.1  gdamore hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
    282      1.1  gdamore {
    283      1.1  gdamore 	struct mbuf *m;
    284      1.1  gdamore 	hci_cmd_hdr_t *p;
    285      1.1  gdamore 
    286      1.4   plunky 	KASSERT(unit != NULL);
    287      1.1  gdamore 
    288      1.1  gdamore 	m = m_gethdr(M_DONTWAIT, MT_DATA);
    289      1.1  gdamore 	if (m == NULL)
    290      1.1  gdamore 		return ENOMEM;
    291      1.1  gdamore 
    292      1.1  gdamore 	p = mtod(m, hci_cmd_hdr_t *);
    293      1.1  gdamore 	p->type = HCI_CMD_PKT;
    294      1.1  gdamore 	p->opcode = htole16(opcode);
    295      1.1  gdamore 	p->length = len;
    296      1.1  gdamore 	m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
    297      1.1  gdamore 
    298      1.1  gdamore 	if (len) {
    299      1.4   plunky 		KASSERT(buf != NULL);
    300      1.1  gdamore 
    301      1.1  gdamore 		m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf);
    302      1.1  gdamore 		if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) {
    303      1.1  gdamore 			m_freem(m);
    304      1.1  gdamore 			return ENOMEM;
    305      1.1  gdamore 		}
    306      1.1  gdamore 	}
    307      1.1  gdamore 
    308      1.7   plunky 	DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", device_xname(unit->hci_dev),
    309      1.1  gdamore 		HCI_OGF(opcode), HCI_OCF(opcode));
    310      1.1  gdamore 
    311      1.1  gdamore 	/* and send it on */
    312      1.1  gdamore 	if (unit->hci_num_cmd_pkts == 0)
    313      1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_cmdwait, m);
    314      1.1  gdamore 	else
    315      1.1  gdamore 		hci_output_cmd(unit, m);
    316      1.1  gdamore 
    317      1.1  gdamore 	return 0;
    318      1.1  gdamore }
    319      1.1  gdamore 
    320      1.1  gdamore /*
    321      1.1  gdamore  * Incoming packet processing. Since the code is single threaded
    322      1.1  gdamore  * in any case (IPL_SOFTNET), we handle it all in one interrupt function
    323      1.1  gdamore  * picking our way through more important packets first so that hopefully
    324      1.1  gdamore  * we will never get clogged up with bulk data.
    325      1.1  gdamore  */
    326      1.1  gdamore static void
    327      1.1  gdamore hci_intr(void *arg)
    328      1.1  gdamore {
    329      1.1  gdamore 	struct hci_unit *unit = arg;
    330      1.1  gdamore 	struct mbuf *m;
    331      1.1  gdamore 
    332      1.1  gdamore another:
    333      1.8   plunky 	mutex_enter(&unit->hci_devlock);
    334      1.1  gdamore 
    335      1.1  gdamore 	if (unit->hci_eventqlen > 0) {
    336      1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_eventq, m);
    337      1.1  gdamore 		unit->hci_eventqlen--;
    338      1.8   plunky 		mutex_exit(&unit->hci_devlock);
    339      1.8   plunky 
    340      1.1  gdamore 		KASSERT(m != NULL);
    341      1.1  gdamore 
    342      1.1  gdamore 		DPRINTFN(10, "(%s) recv event, len = %d\n",
    343      1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    344      1.1  gdamore 
    345      1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    346      1.1  gdamore 		hci_mtap(m, unit);
    347      1.1  gdamore 		hci_event(m, unit);
    348      1.1  gdamore 
    349      1.1  gdamore 		goto another;
    350      1.1  gdamore 	}
    351      1.1  gdamore 
    352      1.1  gdamore 	if (unit->hci_scorxqlen > 0) {
    353      1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_scorxq, m);
    354      1.1  gdamore 		unit->hci_scorxqlen--;
    355      1.8   plunky 		mutex_exit(&unit->hci_devlock);
    356      1.8   plunky 
    357      1.1  gdamore 		KASSERT(m != NULL);
    358      1.1  gdamore 
    359      1.1  gdamore 		DPRINTFN(10, "(%s) recv SCO, len = %d\n",
    360      1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    361      1.1  gdamore 
    362      1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    363      1.1  gdamore 		hci_mtap(m, unit);
    364      1.1  gdamore 		hci_sco_recv(m, unit);
    365      1.1  gdamore 
    366      1.1  gdamore 		goto another;
    367      1.1  gdamore 	}
    368      1.1  gdamore 
    369      1.1  gdamore 	if (unit->hci_aclrxqlen > 0) {
    370      1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_aclrxq, m);
    371      1.1  gdamore 		unit->hci_aclrxqlen--;
    372      1.8   plunky 		mutex_exit(&unit->hci_devlock);
    373      1.8   plunky 
    374      1.1  gdamore 		KASSERT(m != NULL);
    375      1.1  gdamore 
    376      1.1  gdamore 		DPRINTFN(10, "(%s) recv ACL, len = %d\n",
    377      1.7   plunky 				device_xname(unit->hci_dev), m->m_pkthdr.len);
    378      1.1  gdamore 
    379      1.1  gdamore 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    380      1.1  gdamore 		hci_mtap(m, unit);
    381      1.1  gdamore 		hci_acl_recv(m, unit);
    382      1.1  gdamore 
    383      1.1  gdamore 		goto another;
    384      1.1  gdamore 	}
    385      1.1  gdamore 
    386      1.1  gdamore 	MBUFQ_DEQUEUE(&unit->hci_scodone, m);
    387      1.1  gdamore 	if (m != NULL) {
    388      1.1  gdamore 		struct hci_link *link;
    389      1.8   plunky 
    390      1.8   plunky 		mutex_exit(&unit->hci_devlock);
    391      1.1  gdamore 
    392      1.1  gdamore 		DPRINTFN(11, "(%s) complete SCO\n",
    393      1.7   plunky 				device_xname(unit->hci_dev));
    394      1.1  gdamore 
    395      1.1  gdamore 		TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
    396      1.1  gdamore 			if (link == M_GETCTX(m, struct hci_link *)) {
    397      1.1  gdamore 				hci_sco_complete(link, 1);
    398      1.1  gdamore 				break;
    399      1.1  gdamore 			}
    400      1.1  gdamore 		}
    401      1.1  gdamore 
    402      1.1  gdamore 		unit->hci_num_sco_pkts++;
    403      1.1  gdamore 		m_freem(m);
    404      1.1  gdamore 
    405      1.1  gdamore 		goto another;
    406      1.1  gdamore 	}
    407      1.1  gdamore 
    408      1.8   plunky 	mutex_exit(&unit->hci_devlock);
    409      1.1  gdamore 
    410      1.1  gdamore 	DPRINTFN(10, "done\n");
    411      1.1  gdamore }
    412      1.1  gdamore 
    413      1.1  gdamore /**********************************************************************
    414      1.1  gdamore  *
    415      1.1  gdamore  * IO routines
    416      1.1  gdamore  *
    417      1.8   plunky  * input & complete routines will be called from device drivers,
    418      1.8   plunky  * possibly in interrupt context. We return success or failure to
    419      1.8   plunky  * enable proper accounting but we own the mbuf.
    420      1.1  gdamore  */
    421      1.1  gdamore 
    422      1.8   plunky bool
    423      1.1  gdamore hci_input_event(struct hci_unit *unit, struct mbuf *m)
    424      1.1  gdamore {
    425      1.8   plunky 	bool rv;
    426      1.8   plunky 
    427      1.8   plunky 	mutex_enter(&unit->hci_devlock);
    428      1.1  gdamore 
    429      1.1  gdamore 	if (unit->hci_eventqlen > hci_eventq_max || unit->hci_rxint == NULL) {
    430      1.7   plunky 		DPRINTF("(%s) dropped event packet.\n", device_xname(unit->hci_dev));
    431      1.1  gdamore 		m_freem(m);
    432      1.8   plunky 		rv = false;
    433      1.1  gdamore 	} else {
    434      1.1  gdamore 		unit->hci_eventqlen++;
    435      1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_eventq, m);
    436      1.5       ad 		softint_schedule(unit->hci_rxint);
    437      1.8   plunky 		rv = true;
    438      1.1  gdamore 	}
    439      1.8   plunky 
    440      1.8   plunky 	mutex_exit(&unit->hci_devlock);
    441      1.8   plunky 	return rv;
    442      1.1  gdamore }
    443      1.1  gdamore 
    444      1.8   plunky bool
    445      1.1  gdamore hci_input_acl(struct hci_unit *unit, struct mbuf *m)
    446      1.1  gdamore {
    447      1.8   plunky 	bool rv;
    448      1.8   plunky 
    449      1.8   plunky 	mutex_enter(&unit->hci_devlock);
    450      1.1  gdamore 
    451      1.1  gdamore 	if (unit->hci_aclrxqlen > hci_aclrxq_max || unit->hci_rxint == NULL) {
    452      1.7   plunky 		DPRINTF("(%s) dropped ACL packet.\n", device_xname(unit->hci_dev));
    453      1.1  gdamore 		m_freem(m);
    454      1.8   plunky 		rv = false;
    455      1.1  gdamore 	} else {
    456      1.1  gdamore 		unit->hci_aclrxqlen++;
    457      1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_aclrxq, m);
    458      1.5       ad 		softint_schedule(unit->hci_rxint);
    459      1.8   plunky 		rv = true;
    460      1.1  gdamore 	}
    461      1.8   plunky 
    462      1.8   plunky 	mutex_exit(&unit->hci_devlock);
    463      1.8   plunky 	return rv;
    464      1.1  gdamore }
    465      1.1  gdamore 
    466      1.8   plunky bool
    467      1.1  gdamore hci_input_sco(struct hci_unit *unit, struct mbuf *m)
    468      1.1  gdamore {
    469      1.8   plunky 	bool rv;
    470      1.8   plunky 
    471      1.8   plunky 	mutex_enter(&unit->hci_devlock);
    472      1.1  gdamore 
    473      1.1  gdamore 	if (unit->hci_scorxqlen > hci_scorxq_max || unit->hci_rxint == NULL) {
    474      1.7   plunky 		DPRINTF("(%s) dropped SCO packet.\n", device_xname(unit->hci_dev));
    475      1.1  gdamore 		m_freem(m);
    476      1.8   plunky 		rv = false;
    477      1.1  gdamore 	} else {
    478      1.1  gdamore 		unit->hci_scorxqlen++;
    479      1.1  gdamore 		MBUFQ_ENQUEUE(&unit->hci_scorxq, m);
    480      1.5       ad 		softint_schedule(unit->hci_rxint);
    481      1.8   plunky 		rv = true;
    482      1.1  gdamore 	}
    483      1.8   plunky 
    484      1.8   plunky 	mutex_exit(&unit->hci_devlock);
    485      1.8   plunky 	return rv;
    486      1.1  gdamore }
    487      1.1  gdamore 
    488      1.1  gdamore void
    489      1.1  gdamore hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
    490      1.1  gdamore {
    491      1.1  gdamore 	void *arg;
    492      1.1  gdamore 
    493      1.1  gdamore 	hci_mtap(m, unit);
    494      1.1  gdamore 
    495      1.7   plunky 	DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", device_xname(unit->hci_dev),
    496      1.1  gdamore 					       unit->hci_num_cmd_pkts);
    497      1.1  gdamore 
    498      1.1  gdamore 	unit->hci_num_cmd_pkts--;
    499      1.1  gdamore 
    500      1.1  gdamore 	/*
    501      1.1  gdamore 	 * If context is set, this was from a HCI raw socket
    502      1.1  gdamore 	 * and a record needs to be dropped from the sockbuf.
    503      1.1  gdamore 	 */
    504      1.1  gdamore 	arg = M_GETCTX(m, void *);
    505      1.1  gdamore 	if (arg != NULL)
    506      1.1  gdamore 		hci_drop(arg);
    507      1.1  gdamore 
    508      1.8   plunky 	(*unit->hci_if->output_cmd)(unit->hci_dev, m);
    509      1.1  gdamore }
    510      1.1  gdamore 
    511      1.1  gdamore void
    512      1.1  gdamore hci_output_acl(struct hci_unit *unit, struct mbuf *m)
    513      1.1  gdamore {
    514      1.1  gdamore 
    515      1.1  gdamore 	hci_mtap(m, unit);
    516      1.1  gdamore 
    517      1.7   plunky 	DPRINTFN(10, "(%s) num_acl_pkts=%d\n", device_xname(unit->hci_dev),
    518      1.1  gdamore 					       unit->hci_num_acl_pkts);
    519      1.1  gdamore 
    520      1.1  gdamore 	unit->hci_num_acl_pkts--;
    521      1.8   plunky 	(*unit->hci_if->output_acl)(unit->hci_dev, m);
    522      1.1  gdamore }
    523      1.1  gdamore 
    524      1.1  gdamore void
    525      1.1  gdamore hci_output_sco(struct hci_unit *unit, struct mbuf *m)
    526      1.1  gdamore {
    527      1.1  gdamore 
    528      1.1  gdamore 	hci_mtap(m, unit);
    529      1.1  gdamore 
    530      1.7   plunky 	DPRINTFN(10, "(%s) num_sco_pkts=%d\n", device_xname(unit->hci_dev),
    531      1.1  gdamore 					       unit->hci_num_sco_pkts);
    532      1.1  gdamore 
    533      1.1  gdamore 	unit->hci_num_sco_pkts--;
    534      1.8   plunky 	(*unit->hci_if->output_sco)(unit->hci_dev, m);
    535      1.1  gdamore }
    536      1.1  gdamore 
    537      1.8   plunky bool
    538      1.1  gdamore hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
    539      1.1  gdamore {
    540      1.1  gdamore 
    541      1.1  gdamore 	if (unit->hci_rxint == NULL) {
    542      1.7   plunky 		DPRINTFN(10, "(%s) complete SCO!\n", device_xname(unit->hci_dev));
    543      1.1  gdamore 		m_freem(m);
    544      1.8   plunky 		return false;
    545      1.1  gdamore 	}
    546      1.8   plunky 
    547      1.8   plunky 	mutex_enter(&unit->hci_devlock);
    548      1.8   plunky 
    549      1.8   plunky 	MBUFQ_ENQUEUE(&unit->hci_scodone, m);
    550      1.8   plunky 	softint_schedule(unit->hci_rxint);
    551      1.8   plunky 
    552      1.8   plunky 	mutex_exit(&unit->hci_devlock);
    553      1.8   plunky 	return true;
    554      1.1  gdamore }
    555