Home | History | Annotate | Line # | Download | only in netbt
hci_unit.c revision 1.5
      1 /*	$NetBSD: hci_unit.c,v 1.5 2007/10/08 16:18:05 ad Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2005 Iain Hibbert.
      5  * Copyright (c) 2006 Itronix Inc.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. The name of Itronix Inc. may not be used to endorse
     17  *    or promote products derived from this software without specific
     18  *    prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
     24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     27  * ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: hci_unit.c,v 1.5 2007/10/08 16:18:05 ad Exp $");
     35 
     36 #include <sys/param.h>
     37 #include <sys/conf.h>
     38 #include <sys/device.h>
     39 #include <sys/kernel.h>
     40 #include <sys/malloc.h>
     41 #include <sys/mbuf.h>
     42 #include <sys/proc.h>
     43 #include <sys/queue.h>
     44 #include <sys/systm.h>
     45 #include <sys/intr.h>
     46 
     47 #include <netbt/bluetooth.h>
     48 #include <netbt/hci.h>
     49 
     50 struct hci_unit_list hci_unit_list = SIMPLEQ_HEAD_INITIALIZER(hci_unit_list);
     51 
     52 MALLOC_DEFINE(M_BLUETOOTH, "Bluetooth", "Bluetooth System Memory");
     53 
     54 /*
     55  * HCI Input Queue max lengths.
     56  */
     57 int hci_eventq_max = 20;
     58 int hci_aclrxq_max = 50;
     59 int hci_scorxq_max = 50;
     60 
     61 /*
     62  * bluetooth unit functions
     63  */
     64 static void hci_intr (void *);
     65 
     66 void
     67 hci_attach(struct hci_unit *unit)
     68 {
     69 
     70 	KASSERT(unit->hci_softc != NULL);
     71 	KASSERT(unit->hci_devname != NULL);
     72 	KASSERT(unit->hci_enable != NULL);
     73 	KASSERT(unit->hci_disable != NULL);
     74 	KASSERT(unit->hci_start_cmd != NULL);
     75 	KASSERT(unit->hci_start_acl != NULL);
     76 	KASSERT(unit->hci_start_sco != NULL);
     77 
     78 	MBUFQ_INIT(&unit->hci_eventq);
     79 	MBUFQ_INIT(&unit->hci_aclrxq);
     80 	MBUFQ_INIT(&unit->hci_scorxq);
     81 	MBUFQ_INIT(&unit->hci_cmdq);
     82 	MBUFQ_INIT(&unit->hci_cmdwait);
     83 	MBUFQ_INIT(&unit->hci_acltxq);
     84 	MBUFQ_INIT(&unit->hci_scotxq);
     85 	MBUFQ_INIT(&unit->hci_scodone);
     86 
     87 	TAILQ_INIT(&unit->hci_links);
     88 	LIST_INIT(&unit->hci_memos);
     89 
     90 	SIMPLEQ_INSERT_TAIL(&hci_unit_list, unit, hci_next);
     91 }
     92 
     93 void
     94 hci_detach(struct hci_unit *unit)
     95 {
     96 
     97 	hci_disable(unit);
     98 
     99 	SIMPLEQ_REMOVE(&hci_unit_list, unit, hci_unit, hci_next);
    100 }
    101 
    102 int
    103 hci_enable(struct hci_unit *unit)
    104 {
    105 	int s, err;
    106 
    107 	/*
    108 	 * Bluetooth spec says that a device can accept one
    109 	 * command on power up until they send a Command Status
    110 	 * or Command Complete event with more information, but
    111 	 * it seems that some devices cant and prefer to send a
    112 	 * No-op Command Status packet when they are ready, so
    113 	 * we set this here and allow the driver (bt3c) to zero
    114 	 * it.
    115 	 */
    116 	unit->hci_num_cmd_pkts = 1;
    117 	unit->hci_num_acl_pkts = 0;
    118 	unit->hci_num_sco_pkts = 0;
    119 
    120 	/*
    121 	 * only allow the basic packet types until
    122 	 * the features report is in
    123 	 */
    124 	unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
    125 	unit->hci_packet_type = unit->hci_acl_mask;
    126 
    127 	unit->hci_rxint = softint_establish(SOFTINT_NET, &hci_intr, unit);
    128 	if (unit->hci_rxint == NULL)
    129 		return EIO;
    130 
    131 	s = splraiseipl(unit->hci_ipl);
    132 	err = (*unit->hci_enable)(unit);
    133 	splx(s);
    134 	if (err)
    135 		goto bad1;
    136 
    137 	/*
    138 	 * Reset the device, this will trigger initialisation
    139 	 * and wake us up.
    140 	 */
    141 	unit->hci_flags |= BTF_INIT;
    142 
    143 	err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0);
    144 	if (err)
    145 		goto bad2;
    146 
    147 	while (unit->hci_flags & BTF_INIT) {
    148 		err = tsleep(unit, PWAIT | PCATCH, __func__, 5 * hz);
    149 		if (err)
    150 			goto bad2;
    151 
    152 		/* XXX
    153 		 * "What If", while we were sleeping, the device
    154 		 * was removed and detached? Ho Hum.
    155 		 */
    156 	}
    157 
    158 	/*
    159 	 * Attach Bluetooth Device Hub
    160 	 */
    161 	unit->hci_bthub = config_found_ia((struct device *)unit->hci_softc,
    162 					  "btbus", &unit->hci_bdaddr, NULL);
    163 
    164 	return 0;
    165 
    166 bad2:
    167 	s = splraiseipl(unit->hci_ipl);
    168 	(*unit->hci_disable)(unit);
    169 	splx(s);
    170 
    171 bad1:
    172 	softint_disestablish(unit->hci_rxint);
    173 	unit->hci_rxint = NULL;
    174 
    175 	return err;
    176 }
    177 
    178 void
    179 hci_disable(struct hci_unit *unit)
    180 {
    181 	struct hci_link *link, *next;
    182 	struct hci_memo *memo;
    183 	int s, acl;
    184 
    185 	if (unit->hci_bthub) {
    186 		config_detach(unit->hci_bthub, DETACH_FORCE);
    187 		unit->hci_bthub = NULL;
    188 	}
    189 
    190 	if (unit->hci_rxint) {
    191 		softint_disestablish(unit->hci_rxint);
    192 		unit->hci_rxint = NULL;
    193 	}
    194 
    195 	s = splraiseipl(unit->hci_ipl);
    196 	(*unit->hci_disable)(unit);
    197 	splx(s);
    198 
    199 	/*
    200 	 * close down any links, take care to close SCO first since
    201 	 * they may depend on ACL links.
    202 	 */
    203 	for (acl = 0 ; acl < 2 ; acl++) {
    204 		next = TAILQ_FIRST(&unit->hci_links);
    205 		while ((link = next) != NULL) {
    206 			next = TAILQ_NEXT(link, hl_next);
    207 			if (acl || link->hl_type != HCI_LINK_ACL)
    208 				hci_link_free(link, ECONNABORTED);
    209 		}
    210 	}
    211 
    212 	while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
    213 		hci_memo_free(memo);
    214 
    215 	MBUFQ_DRAIN(&unit->hci_eventq);
    216 	unit->hci_eventqlen = 0;
    217 
    218 	MBUFQ_DRAIN(&unit->hci_aclrxq);
    219 	unit->hci_aclrxqlen = 0;
    220 
    221 	MBUFQ_DRAIN(&unit->hci_scorxq);
    222 	unit->hci_scorxqlen = 0;
    223 
    224 	MBUFQ_DRAIN(&unit->hci_cmdq);
    225 	MBUFQ_DRAIN(&unit->hci_cmdwait);
    226 	MBUFQ_DRAIN(&unit->hci_acltxq);
    227 	MBUFQ_DRAIN(&unit->hci_scotxq);
    228 	MBUFQ_DRAIN(&unit->hci_scodone);
    229 }
    230 
    231 struct hci_unit *
    232 hci_unit_lookup(bdaddr_t *addr)
    233 {
    234 	struct hci_unit *unit;
    235 
    236 	SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
    237 		if ((unit->hci_flags & BTF_UP) == 0)
    238 			continue;
    239 
    240 		if (bdaddr_same(&unit->hci_bdaddr, addr))
    241 			break;
    242 	}
    243 
    244 	return unit;
    245 }
    246 
    247 /*
    248  * construct and queue a HCI command packet
    249  */
    250 int
    251 hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
    252 {
    253 	struct mbuf *m;
    254 	hci_cmd_hdr_t *p;
    255 
    256 	KASSERT(unit != NULL);
    257 
    258 	m = m_gethdr(M_DONTWAIT, MT_DATA);
    259 	if (m == NULL)
    260 		return ENOMEM;
    261 
    262 	p = mtod(m, hci_cmd_hdr_t *);
    263 	p->type = HCI_CMD_PKT;
    264 	p->opcode = htole16(opcode);
    265 	p->length = len;
    266 	m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
    267 
    268 	if (len) {
    269 		KASSERT(buf != NULL);
    270 
    271 		m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf);
    272 		if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) {
    273 			m_freem(m);
    274 			return ENOMEM;
    275 		}
    276 	}
    277 
    278 	DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", unit->hci_devname,
    279 		HCI_OGF(opcode), HCI_OCF(opcode));
    280 
    281 	/* and send it on */
    282 	if (unit->hci_num_cmd_pkts == 0)
    283 		MBUFQ_ENQUEUE(&unit->hci_cmdwait, m);
    284 	else
    285 		hci_output_cmd(unit, m);
    286 
    287 	return 0;
    288 }
    289 
    290 /*
    291  * Incoming packet processing. Since the code is single threaded
    292  * in any case (IPL_SOFTNET), we handle it all in one interrupt function
    293  * picking our way through more important packets first so that hopefully
    294  * we will never get clogged up with bulk data.
    295  */
    296 static void
    297 hci_intr(void *arg)
    298 {
    299 	struct hci_unit *unit = arg;
    300 	struct mbuf *m;
    301 	int s;
    302 
    303 another:
    304 	s = splraiseipl(unit->hci_ipl);
    305 
    306 	if (unit->hci_eventqlen > 0) {
    307 		MBUFQ_DEQUEUE(&unit->hci_eventq, m);
    308 		unit->hci_eventqlen--;
    309 		KASSERT(m != NULL);
    310 		splx(s);
    311 
    312 		DPRINTFN(10, "(%s) recv event, len = %d\n",
    313 				unit->hci_devname, m->m_pkthdr.len);
    314 
    315 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    316 		hci_mtap(m, unit);
    317 		hci_event(m, unit);
    318 
    319 		goto another;
    320 	}
    321 
    322 	if (unit->hci_scorxqlen > 0) {
    323 		MBUFQ_DEQUEUE(&unit->hci_scorxq, m);
    324 		unit->hci_scorxqlen--;
    325 		KASSERT(m != NULL);
    326 		splx(s);
    327 
    328 		DPRINTFN(10, "(%s) recv SCO, len = %d\n",
    329 				unit->hci_devname, m->m_pkthdr.len);
    330 
    331 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    332 		hci_mtap(m, unit);
    333 		hci_sco_recv(m, unit);
    334 
    335 		goto another;
    336 	}
    337 
    338 	if (unit->hci_aclrxqlen > 0) {
    339 		MBUFQ_DEQUEUE(&unit->hci_aclrxq, m);
    340 		unit->hci_aclrxqlen--;
    341 		KASSERT(m != NULL);
    342 		splx(s);
    343 
    344 		DPRINTFN(10, "(%s) recv ACL, len = %d\n",
    345 				unit->hci_devname, m->m_pkthdr.len);
    346 
    347 		m->m_flags |= M_LINK0;	/* mark incoming packet */
    348 		hci_mtap(m, unit);
    349 		hci_acl_recv(m, unit);
    350 
    351 		goto another;
    352 	}
    353 
    354 	MBUFQ_DEQUEUE(&unit->hci_scodone, m);
    355 	if (m != NULL) {
    356 		struct hci_link *link;
    357 		splx(s);
    358 
    359 		DPRINTFN(11, "(%s) complete SCO\n",
    360 				unit->hci_devname);
    361 
    362 		TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
    363 			if (link == M_GETCTX(m, struct hci_link *)) {
    364 				hci_sco_complete(link, 1);
    365 				break;
    366 			}
    367 		}
    368 
    369 		unit->hci_num_sco_pkts++;
    370 		m_freem(m);
    371 
    372 		goto another;
    373 	}
    374 
    375 	splx(s);
    376 
    377 	DPRINTFN(10, "done\n");
    378 }
    379 
    380 /**********************************************************************
    381  *
    382  * IO routines
    383  *
    384  * input & complete routines will be called from device driver
    385  * (at unit->hci_ipl)
    386  */
    387 
    388 void
    389 hci_input_event(struct hci_unit *unit, struct mbuf *m)
    390 {
    391 
    392 	if (unit->hci_eventqlen > hci_eventq_max || unit->hci_rxint == NULL) {
    393 		DPRINTF("(%s) dropped event packet.\n", unit->hci_devname);
    394 		unit->hci_stats.err_rx++;
    395 		m_freem(m);
    396 	} else {
    397 		unit->hci_eventqlen++;
    398 		MBUFQ_ENQUEUE(&unit->hci_eventq, m);
    399 		softint_schedule(unit->hci_rxint);
    400 	}
    401 }
    402 
    403 void
    404 hci_input_acl(struct hci_unit *unit, struct mbuf *m)
    405 {
    406 
    407 	if (unit->hci_aclrxqlen > hci_aclrxq_max || unit->hci_rxint == NULL) {
    408 		DPRINTF("(%s) dropped ACL packet.\n", unit->hci_devname);
    409 		unit->hci_stats.err_rx++;
    410 		m_freem(m);
    411 	} else {
    412 		unit->hci_aclrxqlen++;
    413 		MBUFQ_ENQUEUE(&unit->hci_aclrxq, m);
    414 		softint_schedule(unit->hci_rxint);
    415 	}
    416 }
    417 
    418 void
    419 hci_input_sco(struct hci_unit *unit, struct mbuf *m)
    420 {
    421 
    422 	if (unit->hci_scorxqlen > hci_scorxq_max || unit->hci_rxint == NULL) {
    423 		DPRINTF("(%s) dropped SCO packet.\n", unit->hci_devname);
    424 		unit->hci_stats.err_rx++;
    425 		m_freem(m);
    426 	} else {
    427 		unit->hci_scorxqlen++;
    428 		MBUFQ_ENQUEUE(&unit->hci_scorxq, m);
    429 		softint_schedule(unit->hci_rxint);
    430 	}
    431 }
    432 
    433 void
    434 hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
    435 {
    436 	void *arg;
    437 	int s;
    438 
    439 	hci_mtap(m, unit);
    440 
    441 	DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", unit->hci_devname,
    442 					       unit->hci_num_cmd_pkts);
    443 
    444 	unit->hci_num_cmd_pkts--;
    445 
    446 	/*
    447 	 * If context is set, this was from a HCI raw socket
    448 	 * and a record needs to be dropped from the sockbuf.
    449 	 */
    450 	arg = M_GETCTX(m, void *);
    451 	if (arg != NULL)
    452 		hci_drop(arg);
    453 
    454 	s = splraiseipl(unit->hci_ipl);
    455 	MBUFQ_ENQUEUE(&unit->hci_cmdq, m);
    456 	if ((unit->hci_flags & BTF_XMIT_CMD) == 0)
    457 		(*unit->hci_start_cmd)(unit);
    458 
    459 	splx(s);
    460 }
    461 
    462 void
    463 hci_output_acl(struct hci_unit *unit, struct mbuf *m)
    464 {
    465 	int s;
    466 
    467 	hci_mtap(m, unit);
    468 
    469 	DPRINTFN(10, "(%s) num_acl_pkts=%d\n", unit->hci_devname,
    470 					       unit->hci_num_acl_pkts);
    471 
    472 	unit->hci_num_acl_pkts--;
    473 
    474 	s = splraiseipl(unit->hci_ipl);
    475 	MBUFQ_ENQUEUE(&unit->hci_acltxq, m);
    476 	if ((unit->hci_flags & BTF_XMIT_ACL) == 0)
    477 		(*unit->hci_start_acl)(unit);
    478 
    479 	splx(s);
    480 }
    481 
    482 void
    483 hci_output_sco(struct hci_unit *unit, struct mbuf *m)
    484 {
    485 	int s;
    486 
    487 	hci_mtap(m, unit);
    488 
    489 	DPRINTFN(10, "(%s) num_sco_pkts=%d\n", unit->hci_devname,
    490 					       unit->hci_num_sco_pkts);
    491 
    492 	unit->hci_num_sco_pkts--;
    493 
    494 	s = splraiseipl(unit->hci_ipl);
    495 	MBUFQ_ENQUEUE(&unit->hci_scotxq, m);
    496 	if ((unit->hci_flags & BTF_XMIT_SCO) == 0)
    497 		(*unit->hci_start_sco)(unit);
    498 
    499 	splx(s);
    500 }
    501 
    502 void
    503 hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
    504 {
    505 
    506 	if (unit->hci_rxint == NULL) {
    507 		DPRINTFN(10, "(%s) complete SCO!\n", unit->hci_devname);
    508 		unit->hci_stats.err_rx++;
    509 		m_freem(m);
    510 	} else {
    511 		MBUFQ_ENQUEUE(&unit->hci_scodone, m);
    512 		softint_schedule(unit->hci_rxint);
    513 	}
    514 }
    515