183aacedeSHasso Tepper /* $OpenBSD: src/sys/netbt/hci_unit.c,v 1.8 2008/02/24 21:34:48 uwe Exp $ */
283aacedeSHasso Tepper /* $NetBSD: hci_unit.c,v 1.9 2007/12/30 18:26:42 plunky Exp $ */
30a9108ebSHasso Tepper
40a9108ebSHasso Tepper /*-
50a9108ebSHasso Tepper * Copyright (c) 2005 Iain Hibbert.
60a9108ebSHasso Tepper * Copyright (c) 2006 Itronix Inc.
70a9108ebSHasso Tepper * All rights reserved.
80a9108ebSHasso Tepper *
90a9108ebSHasso Tepper * Redistribution and use in source and binary forms, with or without
100a9108ebSHasso Tepper * modification, are permitted provided that the following conditions
110a9108ebSHasso Tepper * are met:
120a9108ebSHasso Tepper * 1. Redistributions of source code must retain the above copyright
130a9108ebSHasso Tepper * notice, this list of conditions and the following disclaimer.
140a9108ebSHasso Tepper * 2. Redistributions in binary form must reproduce the above copyright
150a9108ebSHasso Tepper * notice, this list of conditions and the following disclaimer in the
160a9108ebSHasso Tepper * documentation and/or other materials provided with the distribution.
170a9108ebSHasso Tepper * 3. The name of Itronix Inc. may not be used to endorse
180a9108ebSHasso Tepper * or promote products derived from this software without specific
190a9108ebSHasso Tepper * prior written permission.
200a9108ebSHasso Tepper *
210a9108ebSHasso Tepper * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
220a9108ebSHasso Tepper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
230a9108ebSHasso Tepper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
240a9108ebSHasso Tepper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
250a9108ebSHasso Tepper * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
260a9108ebSHasso Tepper * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
270a9108ebSHasso Tepper * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
280a9108ebSHasso Tepper * ON ANY THEORY OF LIABILITY, WHETHER IN
290a9108ebSHasso Tepper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
300a9108ebSHasso Tepper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
310a9108ebSHasso Tepper * POSSIBILITY OF SUCH DAMAGE.
320a9108ebSHasso Tepper */
330a9108ebSHasso Tepper
340a9108ebSHasso Tepper #include <sys/param.h>
350a9108ebSHasso Tepper #include <sys/conf.h>
360a9108ebSHasso Tepper #include <sys/device.h>
370a9108ebSHasso Tepper #include <sys/kernel.h>
380a9108ebSHasso Tepper #include <sys/malloc.h>
390a9108ebSHasso Tepper #include <sys/mbuf.h>
400a9108ebSHasso Tepper #include <sys/proc.h>
410a9108ebSHasso Tepper #include <sys/queue.h>
420a9108ebSHasso Tepper #include <sys/systm.h>
430a9108ebSHasso Tepper #include <sys/endian.h>
440a9108ebSHasso Tepper #include <sys/bus.h>
450a9108ebSHasso Tepper
460a9108ebSHasso Tepper #include <net/netisr.h>
470a9108ebSHasso Tepper
480a9108ebSHasso Tepper #include <netbt/bluetooth.h>
490a9108ebSHasso Tepper #include <netbt/hci.h>
500a9108ebSHasso Tepper
510a9108ebSHasso Tepper struct hci_unit_list hci_unit_list = TAILQ_HEAD_INITIALIZER(hci_unit_list);
520a9108ebSHasso Tepper
530a9108ebSHasso Tepper /*
540a9108ebSHasso Tepper * HCI Input Queue max lengths.
550a9108ebSHasso Tepper */
560a9108ebSHasso Tepper int hci_eventq_max = 20;
570a9108ebSHasso Tepper int hci_aclrxq_max = 50;
580a9108ebSHasso Tepper int hci_scorxq_max = 50;
5983aacedeSHasso Tepper int hci_cmdwait_max = 50;
6083aacedeSHasso Tepper int hci_scodone_max = 50;
6183aacedeSHasso Tepper
6283aacedeSHasso Tepper /*
6383aacedeSHasso Tepper * This is the default minimum command set supported by older
6483aacedeSHasso Tepper * devices. Anything conforming to 1.2 spec or later will get
6583aacedeSHasso Tepper * updated during init.
6683aacedeSHasso Tepper */
6783aacedeSHasso Tepper static const uint8_t hci_cmds_v10[HCI_COMMANDS_SIZE] = {
6883aacedeSHasso Tepper 0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff,
6983aacedeSHasso Tepper 0xff, 0xff, 0xff, 0x7f, 0x32, 0x03, 0xb8, 0xfe,
7083aacedeSHasso Tepper 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7183aacedeSHasso Tepper 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7283aacedeSHasso Tepper 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7383aacedeSHasso Tepper 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7483aacedeSHasso Tepper 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7583aacedeSHasso Tepper 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7683aacedeSHasso Tepper };
770a9108ebSHasso Tepper
780a9108ebSHasso Tepper /*
790a9108ebSHasso Tepper * bluetooth unit functions
800a9108ebSHasso Tepper */
810a9108ebSHasso Tepper
8283aacedeSHasso Tepper struct hci_unit *
hci_attach(const struct hci_if * hci_if,device_t dev,uint16_t flags)835d302545SFrançois Tigeot hci_attach(const struct hci_if *hci_if, device_t dev, uint16_t flags)
840a9108ebSHasso Tepper {
8583aacedeSHasso Tepper struct hci_unit *unit;
8683aacedeSHasso Tepper
8783aacedeSHasso Tepper KKASSERT(dev != NULL);
8883aacedeSHasso Tepper KKASSERT(hci_if->enable != NULL);
8983aacedeSHasso Tepper KKASSERT(hci_if->disable != NULL);
9083aacedeSHasso Tepper KKASSERT(hci_if->output_cmd != NULL);
9183aacedeSHasso Tepper KKASSERT(hci_if->output_acl != NULL);
9283aacedeSHasso Tepper KKASSERT(hci_if->output_sco != NULL);
9383aacedeSHasso Tepper KKASSERT(hci_if->get_stats != NULL);
9483aacedeSHasso Tepper
9583aacedeSHasso Tepper unit = kmalloc(sizeof(struct hci_unit), M_BLUETOOTH, M_ZERO | M_WAITOK);
9683aacedeSHasso Tepper KKASSERT(unit != NULL);
9783aacedeSHasso Tepper
9883aacedeSHasso Tepper unit->hci_dev = dev;
9983aacedeSHasso Tepper unit->hci_if = hci_if;
10083aacedeSHasso Tepper unit->hci_flags = flags;
10183aacedeSHasso Tepper
10283aacedeSHasso Tepper lockinit(&unit->hci_devlock, "HCI device lock", 0, 0);
1030a9108ebSHasso Tepper
1040a9108ebSHasso Tepper unit->hci_eventq.ifq_maxlen = hci_eventq_max;
1050a9108ebSHasso Tepper unit->hci_aclrxq.ifq_maxlen = hci_aclrxq_max;
1060a9108ebSHasso Tepper unit->hci_scorxq.ifq_maxlen = hci_scorxq_max;
10783aacedeSHasso Tepper unit->hci_cmdwait.ifq_maxlen = hci_cmdwait_max;
10883aacedeSHasso Tepper unit->hci_scodone.ifq_maxlen = hci_scodone_max;
1090a9108ebSHasso Tepper
1100a9108ebSHasso Tepper TAILQ_INIT(&unit->hci_links);
1110a9108ebSHasso Tepper LIST_INIT(&unit->hci_memos);
1120a9108ebSHasso Tepper
11383aacedeSHasso Tepper crit_enter();
1140a9108ebSHasso Tepper TAILQ_INSERT_TAIL(&hci_unit_list, unit, hci_next);
11583aacedeSHasso Tepper crit_exit();
11683aacedeSHasso Tepper
11783aacedeSHasso Tepper return unit;
1180a9108ebSHasso Tepper }
1190a9108ebSHasso Tepper
1200a9108ebSHasso Tepper void
hci_detach(struct hci_unit * unit)1210a9108ebSHasso Tepper hci_detach(struct hci_unit *unit)
1220a9108ebSHasso Tepper {
12383aacedeSHasso Tepper crit_enter();
1240a9108ebSHasso Tepper hci_disable(unit);
1250a9108ebSHasso Tepper
1260a9108ebSHasso Tepper TAILQ_REMOVE(&hci_unit_list, unit, hci_next);
12783aacedeSHasso Tepper crit_exit();
12883aacedeSHasso Tepper
12983aacedeSHasso Tepper kfree(unit, M_BLUETOOTH);
1300a9108ebSHasso Tepper }
1310a9108ebSHasso Tepper
1320a9108ebSHasso Tepper int
hci_enable(struct hci_unit * unit)1330a9108ebSHasso Tepper hci_enable(struct hci_unit *unit)
1340a9108ebSHasso Tepper {
1350a9108ebSHasso Tepper int err;
1360a9108ebSHasso Tepper
1370a9108ebSHasso Tepper /*
1380a9108ebSHasso Tepper * Bluetooth spec says that a device can accept one
1390a9108ebSHasso Tepper * command on power up until they send a Command Status
1400a9108ebSHasso Tepper * or Command Complete event with more information, but
1410a9108ebSHasso Tepper * it seems that some devices cant and prefer to send a
14283aacedeSHasso Tepper * No-op Command Status packet when they are ready.
1430a9108ebSHasso Tepper */
14483aacedeSHasso Tepper unit->hci_num_cmd_pkts = (unit->hci_flags & BTF_POWER_UP_NOOP) ? 0 : 1;
1450a9108ebSHasso Tepper unit->hci_num_acl_pkts = 0;
1460a9108ebSHasso Tepper unit->hci_num_sco_pkts = 0;
1470a9108ebSHasso Tepper
1480a9108ebSHasso Tepper /*
1490a9108ebSHasso Tepper * only allow the basic packet types until
1500a9108ebSHasso Tepper * the features report is in
1510a9108ebSHasso Tepper */
1520a9108ebSHasso Tepper unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
1530a9108ebSHasso Tepper unit->hci_packet_type = unit->hci_acl_mask;
1540a9108ebSHasso Tepper
15583aacedeSHasso Tepper memcpy(unit->hci_cmds, hci_cmds_v10, HCI_COMMANDS_SIZE);
15683aacedeSHasso Tepper err = (*unit->hci_if->enable)(unit->hci_dev);
1570a9108ebSHasso Tepper if (err)
1580a9108ebSHasso Tepper goto bad1;
1590a9108ebSHasso Tepper
16083aacedeSHasso Tepper unit->hci_flags |= BTF_RUNNING;
16183aacedeSHasso Tepper
1620a9108ebSHasso Tepper /*
1630a9108ebSHasso Tepper * Reset the device, this will trigger initialisation
1640a9108ebSHasso Tepper * and wake us up.
1650a9108ebSHasso Tepper */
1660a9108ebSHasso Tepper crit_enter();
1670a9108ebSHasso Tepper unit->hci_flags |= BTF_INIT;
1680a9108ebSHasso Tepper crit_exit();
1690a9108ebSHasso Tepper
1700a9108ebSHasso Tepper err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0);
1710a9108ebSHasso Tepper if (err)
1720a9108ebSHasso Tepper goto bad2;
1730a9108ebSHasso Tepper
1740a9108ebSHasso Tepper while (unit->hci_flags & BTF_INIT) {
1750a9108ebSHasso Tepper err = tsleep(unit, PCATCH, "hciena", 5 * hz);
1760a9108ebSHasso Tepper if (err)
1770a9108ebSHasso Tepper goto bad2;
1780a9108ebSHasso Tepper
1790a9108ebSHasso Tepper /* XXX
1800a9108ebSHasso Tepper * "What If", while we were sleeping, the device
1810a9108ebSHasso Tepper * was removed and detached? Ho Hum.
1820a9108ebSHasso Tepper */
1830a9108ebSHasso Tepper }
1840a9108ebSHasso Tepper
1850a9108ebSHasso Tepper #if 0 /* not yet */
1860a9108ebSHasso Tepper /*
1870a9108ebSHasso Tepper * Attach Bluetooth Device Hub
1880a9108ebSHasso Tepper */
1890a9108ebSHasso Tepper unit->hci_bthub = NULL;
1900a9108ebSHasso Tepper
1910a9108ebSHasso Tepper unit->hci_bthub = device_add_child(unit->hci_softc, "bthub", -1);
1920a9108ebSHasso Tepper if (!unit->hci_bthub) {
1930a9108ebSHasso Tepper device_printf(unit->hci_softc, "Device creation failed\n");
1940a9108ebSHasso Tepper goto bad2;
1950a9108ebSHasso Tepper }
1960a9108ebSHasso Tepper
1970a9108ebSHasso Tepper DPRINTFN(10, "%s is added as child to %s\n",
1980a9108ebSHasso Tepper device_get_nameunit(unit->hci_bthub),
1990a9108ebSHasso Tepper device_get_nameunit(unit->hci_softc));
2000a9108ebSHasso Tepper
2010a9108ebSHasso Tepper device_set_desc(unit->hci_bthub,"Bluetooth Device Hub");
2020a9108ebSHasso Tepper
2030a9108ebSHasso Tepper device_set_ivars(unit->hci_bthub, &unit->hci_bdaddr);
2040a9108ebSHasso Tepper
2050a9108ebSHasso Tepper device_probe_and_attach(unit->hci_bthub);
2060a9108ebSHasso Tepper #endif
2070a9108ebSHasso Tepper return 0;
2080a9108ebSHasso Tepper
2090a9108ebSHasso Tepper bad2:
21083aacedeSHasso Tepper (*unit->hci_if->disable)(unit->hci_dev);
21183aacedeSHasso Tepper unit->hci_flags &= ~BTF_RUNNING;
2120a9108ebSHasso Tepper
2130a9108ebSHasso Tepper bad1:
2140a9108ebSHasso Tepper return err;
2150a9108ebSHasso Tepper }
2160a9108ebSHasso Tepper
2170a9108ebSHasso Tepper void
hci_disable(struct hci_unit * unit)2180a9108ebSHasso Tepper hci_disable(struct hci_unit *unit)
2190a9108ebSHasso Tepper {
2200a9108ebSHasso Tepper struct hci_link *link, *next;
2210a9108ebSHasso Tepper struct hci_memo *memo;
2220a9108ebSHasso Tepper int acl;
2230a9108ebSHasso Tepper
2240a9108ebSHasso Tepper #if 0 /* not yet */
2250a9108ebSHasso Tepper if (unit->hci_bthub) {
2260a9108ebSHasso Tepper device_delete_child(unit->hci_softc, unit->hci_bthub);
2270a9108ebSHasso Tepper unit->hci_bthub = NULL;
2280a9108ebSHasso Tepper }
2290a9108ebSHasso Tepper #endif
2300a9108ebSHasso Tepper
23183aacedeSHasso Tepper (*unit->hci_if->disable)(unit->hci_dev);
23283aacedeSHasso Tepper unit->hci_flags &= ~BTF_RUNNING;
2330a9108ebSHasso Tepper
2340a9108ebSHasso Tepper /*
2350a9108ebSHasso Tepper * close down any links, take care to close SCO first since
2360a9108ebSHasso Tepper * they may depend on ACL links.
2370a9108ebSHasso Tepper */
2380a9108ebSHasso Tepper for (acl = 0 ; acl < 2 ; acl++) {
2390a9108ebSHasso Tepper next = TAILQ_FIRST(&unit->hci_links);
2400a9108ebSHasso Tepper while ((link = next) != NULL) {
2410a9108ebSHasso Tepper next = TAILQ_NEXT(link, hl_next);
2420a9108ebSHasso Tepper if (acl || link->hl_type != HCI_LINK_ACL)
2430a9108ebSHasso Tepper hci_link_free(link, ECONNABORTED);
2440a9108ebSHasso Tepper }
2450a9108ebSHasso Tepper }
2460a9108ebSHasso Tepper
2470a9108ebSHasso Tepper while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
2480a9108ebSHasso Tepper hci_memo_free(memo);
2490a9108ebSHasso Tepper
25083aacedeSHasso Tepper /* (no need to hold hci_devlock, the driver is disabled) */
25183aacedeSHasso Tepper
2520a9108ebSHasso Tepper IF_DRAIN(&unit->hci_eventq);
2530a9108ebSHasso Tepper unit->hci_eventqlen = 0;
2540a9108ebSHasso Tepper
2550a9108ebSHasso Tepper IF_DRAIN(&unit->hci_aclrxq);
2560a9108ebSHasso Tepper unit->hci_aclrxqlen = 0;
2570a9108ebSHasso Tepper
2580a9108ebSHasso Tepper IF_DRAIN(&unit->hci_scorxq);
2590a9108ebSHasso Tepper unit->hci_scorxqlen = 0;
2600a9108ebSHasso Tepper
2610a9108ebSHasso Tepper IF_DRAIN(&unit->hci_cmdwait);
2620a9108ebSHasso Tepper IF_DRAIN(&unit->hci_scodone);
2630a9108ebSHasso Tepper }
2640a9108ebSHasso Tepper
2650a9108ebSHasso Tepper struct hci_unit *
hci_unit_lookup(bdaddr_t * addr)2660a9108ebSHasso Tepper hci_unit_lookup(bdaddr_t *addr)
2670a9108ebSHasso Tepper {
2680a9108ebSHasso Tepper struct hci_unit *unit;
2690a9108ebSHasso Tepper
2700a9108ebSHasso Tepper TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
2710a9108ebSHasso Tepper if ((unit->hci_flags & BTF_UP) == 0)
2720a9108ebSHasso Tepper continue;
2730a9108ebSHasso Tepper
2740a9108ebSHasso Tepper if (bdaddr_same(&unit->hci_bdaddr, addr))
2750a9108ebSHasso Tepper break;
2760a9108ebSHasso Tepper }
2770a9108ebSHasso Tepper
2780a9108ebSHasso Tepper return unit;
2790a9108ebSHasso Tepper }
2800a9108ebSHasso Tepper
2810a9108ebSHasso Tepper /*
2820a9108ebSHasso Tepper * construct and queue a HCI command packet
2830a9108ebSHasso Tepper */
2840a9108ebSHasso Tepper int
hci_send_cmd(struct hci_unit * unit,uint16_t opcode,void * buf,uint8_t len)2850a9108ebSHasso Tepper hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
2860a9108ebSHasso Tepper {
2870a9108ebSHasso Tepper struct mbuf *m;
2880a9108ebSHasso Tepper hci_cmd_hdr_t *p;
2890a9108ebSHasso Tepper
2900a9108ebSHasso Tepper KKASSERT(unit != NULL);
2910a9108ebSHasso Tepper
292b5523eacSSascha Wildner m = m_gethdr(M_NOWAIT, MT_DATA);
2930a9108ebSHasso Tepper if (m == NULL)
2940a9108ebSHasso Tepper return ENOMEM;
2950a9108ebSHasso Tepper
2960a9108ebSHasso Tepper p = mtod(m, hci_cmd_hdr_t *);
2970a9108ebSHasso Tepper p->type = HCI_CMD_PKT;
2980a9108ebSHasso Tepper p->opcode = htole16(opcode);
2990a9108ebSHasso Tepper p->length = len;
3000a9108ebSHasso Tepper m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
30183aacedeSHasso Tepper M_SETCTX(m, NULL); /* XXX is this needed? */
3020a9108ebSHasso Tepper
303*44647b48SAaron LI if (len > 0 &&
304*44647b48SAaron LI m_copyback2(m, sizeof(hci_cmd_hdr_t), len, buf, M_NOWAIT) != 0) {
3050a9108ebSHasso Tepper m_freem(m);
3060a9108ebSHasso Tepper return ENOMEM;
3070a9108ebSHasso Tepper }
3080a9108ebSHasso Tepper
30983aacedeSHasso Tepper DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n",
31083aacedeSHasso Tepper device_get_nameunit(unit->hci_dev),
3110a9108ebSHasso Tepper HCI_OGF(opcode), HCI_OCF(opcode));
3120a9108ebSHasso Tepper
3130a9108ebSHasso Tepper /* and send it on */
31483aacedeSHasso Tepper if (unit->hci_num_cmd_pkts == 0)
3150a9108ebSHasso Tepper IF_ENQUEUE(&unit->hci_cmdwait, m);
31683aacedeSHasso Tepper else
3170a9108ebSHasso Tepper hci_output_cmd(unit, m);
3180a9108ebSHasso Tepper
3190a9108ebSHasso Tepper return 0;
3200a9108ebSHasso Tepper }
3210a9108ebSHasso Tepper
3220a9108ebSHasso Tepper /*
3230a9108ebSHasso Tepper * Incoming packet processing. Since the code is single threaded
3240a9108ebSHasso Tepper * in any case (IPL_SOFTNET), we handle it all in one interrupt function
3250a9108ebSHasso Tepper * picking our way through more important packets first so that hopefully
3260a9108ebSHasso Tepper * we will never get clogged up with bulk data.
3270a9108ebSHasso Tepper */
3280a9108ebSHasso Tepper void
hci_intr(void * arg)3290a9108ebSHasso Tepper hci_intr(void *arg)
3300a9108ebSHasso Tepper {
3310a9108ebSHasso Tepper struct hci_unit *unit = arg;
3320a9108ebSHasso Tepper struct mbuf *m;
3330a9108ebSHasso Tepper
3340a9108ebSHasso Tepper another:
33583aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
3360a9108ebSHasso Tepper
3370a9108ebSHasso Tepper if (unit->hci_eventqlen > 0) {
3380a9108ebSHasso Tepper IF_DEQUEUE(&unit->hci_eventq, m);
3390a9108ebSHasso Tepper unit->hci_eventqlen--;
34083aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_RELEASE);
34183aacedeSHasso Tepper
3420a9108ebSHasso Tepper KKASSERT(m != NULL);
3430a9108ebSHasso Tepper
3440a9108ebSHasso Tepper DPRINTFN(10, "(%s) recv event, len = %d\n",
34583aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), m->m_pkthdr.len);
3460a9108ebSHasso Tepper
3470a9108ebSHasso Tepper m->m_flags |= IFF_LINK0; /* mark incoming packet */
3480a9108ebSHasso Tepper hci_mtap(m, unit);
3490a9108ebSHasso Tepper hci_event(m, unit);
3500a9108ebSHasso Tepper
3510a9108ebSHasso Tepper goto another;
3520a9108ebSHasso Tepper }
3530a9108ebSHasso Tepper
3540a9108ebSHasso Tepper if (unit->hci_scorxqlen > 0) {
3550a9108ebSHasso Tepper IF_DEQUEUE(&unit->hci_scorxq, m);
3560a9108ebSHasso Tepper unit->hci_scorxqlen--;
35783aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_RELEASE);
3580a9108ebSHasso Tepper KKASSERT(m != NULL);
3590a9108ebSHasso Tepper
3600a9108ebSHasso Tepper DPRINTFN(10, "(%s) recv SCO, len = %d\n",
36183aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), m->m_pkthdr.len);
3620a9108ebSHasso Tepper
3630a9108ebSHasso Tepper m->m_flags |= IFF_LINK0; /* mark incoming packet */
3640a9108ebSHasso Tepper hci_mtap(m, unit);
3650a9108ebSHasso Tepper hci_sco_recv(m, unit);
3660a9108ebSHasso Tepper
3670a9108ebSHasso Tepper goto another;
3680a9108ebSHasso Tepper }
3690a9108ebSHasso Tepper
3700a9108ebSHasso Tepper if (unit->hci_aclrxqlen > 0) {
3710a9108ebSHasso Tepper IF_DEQUEUE(&unit->hci_aclrxq, m);
3720a9108ebSHasso Tepper unit->hci_aclrxqlen--;
37383aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_RELEASE);
37483aacedeSHasso Tepper
3750a9108ebSHasso Tepper KKASSERT(m != NULL);
3760a9108ebSHasso Tepper
3770a9108ebSHasso Tepper DPRINTFN(10, "(%s) recv ACL, len = %d\n",
37883aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), m->m_pkthdr.len);
3790a9108ebSHasso Tepper
3800a9108ebSHasso Tepper m->m_flags |= IFF_LINK0; /* mark incoming packet */
3810a9108ebSHasso Tepper hci_mtap(m, unit);
3820a9108ebSHasso Tepper hci_acl_recv(m, unit);
3830a9108ebSHasso Tepper
3840a9108ebSHasso Tepper goto another;
3850a9108ebSHasso Tepper }
3860a9108ebSHasso Tepper
3870a9108ebSHasso Tepper IF_DEQUEUE(&unit->hci_scodone, m);
3880a9108ebSHasso Tepper if (m != NULL) {
3890a9108ebSHasso Tepper struct hci_link *link;
39083aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_RELEASE);
3910a9108ebSHasso Tepper
3920a9108ebSHasso Tepper DPRINTFN(11, "(%s) complete SCO\n",
39383aacedeSHasso Tepper device_get_nameunit(unit->hci_dev));
3940a9108ebSHasso Tepper
3950a9108ebSHasso Tepper TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
3960a9108ebSHasso Tepper if (link == M_GETCTX(m, struct hci_link *)) {
3970a9108ebSHasso Tepper hci_sco_complete(link, 1);
3980a9108ebSHasso Tepper break;
3990a9108ebSHasso Tepper }
4000a9108ebSHasso Tepper }
4010a9108ebSHasso Tepper
4020a9108ebSHasso Tepper unit->hci_num_sco_pkts++;
4030a9108ebSHasso Tepper m_freem(m);
4040a9108ebSHasso Tepper
4050a9108ebSHasso Tepper goto another;
4060a9108ebSHasso Tepper }
4070a9108ebSHasso Tepper
40883aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_RELEASE);
4090a9108ebSHasso Tepper
4100a9108ebSHasso Tepper DPRINTFN(10, "done\n");
4110a9108ebSHasso Tepper }
4120a9108ebSHasso Tepper
4130a9108ebSHasso Tepper /**********************************************************************
4140a9108ebSHasso Tepper *
4150a9108ebSHasso Tepper * IO routines
4160a9108ebSHasso Tepper *
41783aacedeSHasso Tepper * input & complete routines will be called from device drivers,
41883aacedeSHasso Tepper * possibly in interrupt context. We return success or failure to
41983aacedeSHasso Tepper * enable proper accounting but we own the mbuf.
4200a9108ebSHasso Tepper */
4210a9108ebSHasso Tepper
42283aacedeSHasso Tepper int
hci_input_event(struct hci_unit * unit,struct mbuf * m)4230a9108ebSHasso Tepper hci_input_event(struct hci_unit *unit, struct mbuf *m)
4240a9108ebSHasso Tepper {
42583aacedeSHasso Tepper int rv;
42683aacedeSHasso Tepper
42783aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
42883aacedeSHasso Tepper
4290a9108ebSHasso Tepper if (unit->hci_eventqlen > hci_eventq_max) {
43083aacedeSHasso Tepper DPRINTF("(%s) dropped event packet.\n",
43183aacedeSHasso Tepper device_get_nameunit(unit->hci_dev));
4320a9108ebSHasso Tepper m_freem(m);
43383aacedeSHasso Tepper rv = 0;
4340a9108ebSHasso Tepper } else {
4350a9108ebSHasso Tepper unit->hci_eventqlen++;
4360a9108ebSHasso Tepper IF_ENQUEUE(&unit->hci_eventq, m);
4370a9108ebSHasso Tepper netisr_queue(NETISR_BLUETOOTH, m);
43883aacedeSHasso Tepper rv = 1;
4390a9108ebSHasso Tepper }
44083aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_RELEASE);
44183aacedeSHasso Tepper
44283aacedeSHasso Tepper return rv;
4430a9108ebSHasso Tepper }
4440a9108ebSHasso Tepper
44583aacedeSHasso Tepper int
hci_input_acl(struct hci_unit * unit,struct mbuf * m)4460a9108ebSHasso Tepper hci_input_acl(struct hci_unit *unit, struct mbuf *m)
4470a9108ebSHasso Tepper {
44883aacedeSHasso Tepper int rv;
44983aacedeSHasso Tepper
45083aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
4510a9108ebSHasso Tepper if (unit->hci_aclrxqlen > hci_aclrxq_max) {
45283aacedeSHasso Tepper DPRINTF("(%s) dropped ACL packet.\n",
45383aacedeSHasso Tepper device_get_nameunit(unit->hci_dev));
4540a9108ebSHasso Tepper m_freem(m);
45583aacedeSHasso Tepper rv = 0;
4560a9108ebSHasso Tepper } else {
4570a9108ebSHasso Tepper unit->hci_aclrxqlen++;
4580a9108ebSHasso Tepper IF_ENQUEUE(&unit->hci_aclrxq, m);
4590a9108ebSHasso Tepper netisr_queue(NETISR_BLUETOOTH, m);
46083aacedeSHasso Tepper rv = 1;
4610a9108ebSHasso Tepper }
46283aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_RELEASE);
46383aacedeSHasso Tepper
46483aacedeSHasso Tepper return rv;
4650a9108ebSHasso Tepper }
4660a9108ebSHasso Tepper
46783aacedeSHasso Tepper int
hci_input_sco(struct hci_unit * unit,struct mbuf * m)4680a9108ebSHasso Tepper hci_input_sco(struct hci_unit *unit, struct mbuf *m)
4690a9108ebSHasso Tepper {
47083aacedeSHasso Tepper int rv;
47183aacedeSHasso Tepper
47283aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
4730a9108ebSHasso Tepper if (unit->hci_scorxqlen > hci_scorxq_max) {
47483aacedeSHasso Tepper DPRINTF("(%s) dropped SCO packet.\n",
47583aacedeSHasso Tepper device_get_nameunit(unit->hci_dev));
4760a9108ebSHasso Tepper m_freem(m);
47783aacedeSHasso Tepper rv = 0;
4780a9108ebSHasso Tepper } else {
4790a9108ebSHasso Tepper unit->hci_scorxqlen++;
4800a9108ebSHasso Tepper IF_ENQUEUE(&unit->hci_scorxq, m);
4810a9108ebSHasso Tepper netisr_queue(NETISR_BLUETOOTH, m);
48283aacedeSHasso Tepper rv = 1;
4830a9108ebSHasso Tepper }
48483aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_RELEASE);
48583aacedeSHasso Tepper
48683aacedeSHasso Tepper return rv;
4870a9108ebSHasso Tepper }
4880a9108ebSHasso Tepper
4890a9108ebSHasso Tepper void
hci_output_cmd(struct hci_unit * unit,struct mbuf * m)4900a9108ebSHasso Tepper hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
4910a9108ebSHasso Tepper {
4920a9108ebSHasso Tepper void *arg;
4930a9108ebSHasso Tepper
4940a9108ebSHasso Tepper hci_mtap(m, unit);
4950a9108ebSHasso Tepper
49683aacedeSHasso Tepper DPRINTFN(10, "(%s) num_cmd_pkts=%d\n",
49783aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), unit->hci_num_cmd_pkts);
4980a9108ebSHasso Tepper
4990a9108ebSHasso Tepper unit->hci_num_cmd_pkts--;
5000a9108ebSHasso Tepper
5010a9108ebSHasso Tepper /*
5020a9108ebSHasso Tepper * If context is set, this was from a HCI raw socket
5030a9108ebSHasso Tepper * and a record needs to be dropped from the sockbuf.
5040a9108ebSHasso Tepper */
5050a9108ebSHasso Tepper arg = M_GETCTX(m, void *);
5060a9108ebSHasso Tepper if (arg != NULL)
5070a9108ebSHasso Tepper hci_drop(arg);
5080a9108ebSHasso Tepper
50983aacedeSHasso Tepper (*unit->hci_if->output_cmd)(unit->hci_dev, m);
5100a9108ebSHasso Tepper }
5110a9108ebSHasso Tepper
5120a9108ebSHasso Tepper void
hci_output_acl(struct hci_unit * unit,struct mbuf * m)5130a9108ebSHasso Tepper hci_output_acl(struct hci_unit *unit, struct mbuf *m)
5140a9108ebSHasso Tepper {
5150a9108ebSHasso Tepper hci_mtap(m, unit);
5160a9108ebSHasso Tepper
51783aacedeSHasso Tepper DPRINTFN(10, "(%s) num_acl_pkts=%d\n",
51883aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), unit->hci_num_acl_pkts);
5190a9108ebSHasso Tepper
5200a9108ebSHasso Tepper unit->hci_num_acl_pkts--;
5210a9108ebSHasso Tepper
52283aacedeSHasso Tepper (*unit->hci_if->output_acl)(unit->hci_dev, m);
5230a9108ebSHasso Tepper }
5240a9108ebSHasso Tepper
5250a9108ebSHasso Tepper void
hci_output_sco(struct hci_unit * unit,struct mbuf * m)5260a9108ebSHasso Tepper hci_output_sco(struct hci_unit *unit, struct mbuf *m)
5270a9108ebSHasso Tepper {
5280a9108ebSHasso Tepper hci_mtap(m, unit);
5290a9108ebSHasso Tepper
53083aacedeSHasso Tepper DPRINTFN(10, "(%s) num_sco_pkts=%d\n",
53183aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), unit->hci_num_sco_pkts);
5320a9108ebSHasso Tepper
5330a9108ebSHasso Tepper unit->hci_num_sco_pkts--;
5340a9108ebSHasso Tepper
53583aacedeSHasso Tepper (*unit->hci_if->output_sco)(unit->hci_dev, m);
5360a9108ebSHasso Tepper }
5370a9108ebSHasso Tepper
53883aacedeSHasso Tepper int
hci_complete_sco(struct hci_unit * unit,struct mbuf * m)5390a9108ebSHasso Tepper hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
5400a9108ebSHasso Tepper {
54183aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
5420a9108ebSHasso Tepper IF_ENQUEUE(&unit->hci_scodone, m);
5430a9108ebSHasso Tepper netisr_queue(NETISR_BLUETOOTH,m);
54483aacedeSHasso Tepper lockmgr(&unit->hci_devlock, LK_RELEASE);
54583aacedeSHasso Tepper
54683aacedeSHasso Tepper return 1;
5470a9108ebSHasso Tepper }
548