[BACK]Return to hci_unit.c CVS log [TXT][DIR] Up to [local] / sys / netbt

Annotation of sys/netbt/hci_unit.c, Revision 1.1.1.1

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

CVSweb