root/netbt/hci_unit.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hci_attach
  2. hci_detach
  3. hci_enable
  4. hci_disable
  5. hci_unit_lookup
  6. hci_send_cmd
  7. hci_intr
  8. hci_input_event
  9. hci_input_acl
  10. hci_input_sco
  11. hci_output_cmd
  12. hci_output_acl
  13. hci_output_sco
  14. hci_complete_sco

    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 }

/* [<][>][^][v][top][bottom][index][help] */