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