The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netbt/hci_unit.c

Version: -  FREEBSD  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: hci_unit.c,v 1.10 2008/11/22 16:56:39 uwe Exp $       */
    2 /*      $NetBSD: hci_unit.c,v 1.12 2008/06/26 14:17:27 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/param.h>
   35 #include <sys/conf.h>
   36 #include <sys/device.h>
   37 #include <sys/kernel.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/proc.h>
   41 #include <sys/queue.h>
   42 #include <sys/systm.h>
   43 
   44 #include <net/netisr.h>
   45 
   46 #include <netbt/bluetooth.h>
   47 #include <netbt/hci.h>
   48 
   49 struct hci_unit_list hci_unit_list = TAILQ_HEAD_INITIALIZER(hci_unit_list);
   50 
   51 /*
   52  * HCI Input Queue max lengths.
   53  */
   54 int hci_eventq_max = 20;
   55 int hci_aclrxq_max = 50;
   56 int hci_scorxq_max = 50;
   57 int hci_cmdwait_max = 50;
   58 int hci_scodone_max = 50;
   59 
   60 /*
   61  * This is the default minimum command set supported by older
   62  * devices. Anything conforming to 1.2 spec or later will get
   63  * updated during init.
   64  */
   65 static const uint8_t hci_cmds_v10[HCI_COMMANDS_SIZE] = {
   66         0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff,
   67         0xff, 0xff, 0xff, 0x7f, 0x32, 0x03, 0xb8, 0xfe,
   68         0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   69         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   70         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   71         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   72         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   73         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
   74 };
   75 
   76 /*
   77  * bluetooth unit functions
   78  */
   79 
   80 struct hci_unit *
   81 hci_attach(const struct hci_if *hci_if, struct device *dev, uint16_t flags)
   82 {
   83         struct hci_unit *unit;
   84 
   85         KASSERT(dev != NULL);
   86         KASSERT(hci_if->enable != NULL);
   87         KASSERT(hci_if->disable != NULL);
   88         KASSERT(hci_if->output_cmd != NULL);
   89         KASSERT(hci_if->output_acl != NULL);
   90         KASSERT(hci_if->output_sco != NULL);
   91         KASSERT(hci_if->get_stats != NULL);
   92 
   93         unit = malloc(sizeof(struct hci_unit), M_BLUETOOTH, M_ZERO | M_WAITOK);
   94         KASSERT(unit != NULL);
   95 
   96         unit->hci_dev = dev;
   97         unit->hci_if = hci_if;
   98         unit->hci_flags = flags;
   99 
  100         mtx_init(&unit->hci_devlock, hci_if->ipl);
  101         unit->hci_init = 0;     /* kcondvar_t in NetBSD */
  102 
  103         unit->hci_eventq.ifq_maxlen = hci_eventq_max;
  104         unit->hci_aclrxq.ifq_maxlen = hci_aclrxq_max;
  105         unit->hci_scorxq.ifq_maxlen = hci_scorxq_max;
  106         unit->hci_cmdwait.ifq_maxlen = hci_cmdwait_max;
  107         unit->hci_scodone.ifq_maxlen = hci_scodone_max;
  108 
  109         TAILQ_INIT(&unit->hci_links);
  110         LIST_INIT(&unit->hci_memos);
  111 
  112         mutex_enter(&bt_lock);
  113         TAILQ_INSERT_TAIL(&hci_unit_list, unit, hci_next);
  114         mutex_exit(&bt_lock);
  115 
  116         return unit;
  117 }
  118 
  119 void
  120 hci_detach(struct hci_unit *unit)
  121 {
  122 
  123         mutex_enter(&bt_lock);
  124         hci_disable(unit);
  125 
  126         TAILQ_REMOVE(&hci_unit_list, unit, hci_next);
  127         mutex_exit(&bt_lock);
  128 
  129         /* mutex_destroy(&unit->hci_devlock) in NetBSD */
  130         free(unit, M_BLUETOOTH);
  131 }
  132 
  133 int
  134 hci_enable(struct hci_unit *unit)
  135 {
  136         int err;
  137 
  138         /*
  139          * Block further attempts to enable the interface until the
  140          * previous attempt has completed.
  141          */
  142         if (unit->hci_flags & BTF_INIT)
  143                 return EBUSY;
  144 
  145         /*
  146          * Bluetooth spec says that a device can accept one
  147          * command on power up until they send a Command Status
  148          * or Command Complete event with more information, but
  149          * it seems that some devices cant and prefer to send a
  150          * No-op Command Status packet when they are ready.
  151          */
  152         unit->hci_num_cmd_pkts = (unit->hci_flags & BTF_POWER_UP_NOOP) ? 0 : 1;
  153         unit->hci_num_acl_pkts = 0;
  154         unit->hci_num_sco_pkts = 0;
  155 
  156         /*
  157          * only allow the basic packet types until
  158          * the features report is in
  159          */
  160         unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
  161         unit->hci_packet_type = unit->hci_acl_mask;
  162 
  163         memcpy(unit->hci_cmds, hci_cmds_v10, HCI_COMMANDS_SIZE);
  164 
  165 #ifndef __OpenBSD__
  166         unit->hci_rxint = softint_establish(SOFTINT_NET, &hci_intr, unit);
  167         if (unit->hci_rxint == NULL)
  168                 return EIO;
  169 #endif
  170 
  171         err = (*unit->hci_if->enable)(unit->hci_dev);
  172         if (err)
  173                 goto bad1;
  174 
  175         unit->hci_flags |= BTF_RUNNING;
  176 
  177         /*
  178          * Reset the device, this will trigger initialisation
  179          * and wake us up.
  180          */
  181         unit->hci_flags |= BTF_INIT;
  182 
  183         err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0);
  184         if (err)
  185                 goto bad2;
  186 
  187         while (unit->hci_flags & BTF_INIT) {
  188                 err = msleep(&unit->hci_init, &bt_lock, PWAIT | PCATCH,
  189                     __func__, 5 * hz);
  190                 if (err)
  191                         goto bad2;
  192 
  193                 /* XXX
  194                  * "What If", while we were sleeping, the device
  195                  * was removed and detached? Ho Hum.
  196                  */
  197         }
  198 
  199         /*
  200          * Attach Bluetooth Device Hub
  201          */
  202         unit->hci_bthub = config_found(unit->hci_dev,
  203             &unit->hci_bdaddr, NULL);
  204 
  205         return 0;
  206 
  207 bad2:
  208         (*unit->hci_if->disable)(unit->hci_dev);
  209         unit->hci_flags &= ~BTF_RUNNING;
  210 bad1:
  211 #ifndef __OpenBSD__
  212         softint_disestablish(unit->hci_rxint);
  213         unit->hci_rxint = NULL;
  214 #endif
  215 
  216         return err;
  217 }
  218 
  219 void
  220 hci_disable(struct hci_unit *unit)
  221 {
  222         struct hci_link *link, *next;
  223         struct hci_memo *memo;
  224         int acl;
  225 
  226         if (unit->hci_bthub) {
  227                 struct device *hub;
  228 
  229                 hub = unit->hci_bthub;
  230                 unit->hci_bthub = NULL;
  231 
  232                 mutex_exit(&bt_lock);
  233                 config_detach(hub, DETACH_FORCE);
  234                 mutex_enter(&bt_lock);
  235         }
  236 
  237 #ifndef __OpenBSD__
  238         if (unit->hci_rxint) {
  239                 softint_disestablish(unit->hci_rxint);
  240                 unit->hci_rxint = NULL;
  241         }
  242 #endif
  243 
  244         (*unit->hci_if->disable)(unit->hci_dev);
  245         unit->hci_flags &= ~BTF_RUNNING;
  246 
  247         /*
  248          * close down any links, take care to close SCO first since
  249          * they may depend on ACL links.
  250          */
  251         for (acl = 0 ; acl < 2 ; acl++) {
  252                 next = TAILQ_FIRST(&unit->hci_links);
  253                 while ((link = next) != NULL) {
  254                         next = TAILQ_NEXT(link, hl_next);
  255                         if (acl || link->hl_type != HCI_LINK_ACL)
  256                                 hci_link_free(link, ECONNABORTED);
  257                 }
  258         }
  259 
  260         while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
  261                 hci_memo_free(memo);
  262 
  263         /* (no need to hold hci_devlock, the driver is disabled) */
  264 
  265         IF_PURGE(&unit->hci_eventq);
  266         unit->hci_eventqlen = 0;
  267 
  268         IF_PURGE(&unit->hci_aclrxq);
  269         unit->hci_aclrxqlen = 0;
  270 
  271         IF_PURGE(&unit->hci_scorxq);
  272         unit->hci_scorxqlen = 0;
  273 
  274         IF_PURGE(&unit->hci_cmdwait);
  275         IF_PURGE(&unit->hci_scodone);
  276 }
  277 
  278 struct hci_unit *
  279 hci_unit_lookup(bdaddr_t *addr)
  280 {
  281         struct hci_unit *unit;
  282 
  283         TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
  284                 if ((unit->hci_flags & BTF_UP) == 0)
  285                         continue;
  286 
  287                 if (bdaddr_same(&unit->hci_bdaddr, addr))
  288                         break;
  289         }
  290 
  291         return unit;
  292 }
  293 
  294 /*
  295  * construct and queue a HCI command packet
  296  */
  297 int
  298 hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
  299 {
  300         struct mbuf *m;
  301         hci_cmd_hdr_t *p;
  302 
  303         KASSERT(unit != NULL);
  304 
  305         m = m_gethdr(M_DONTWAIT, MT_DATA);
  306         if (m == NULL)
  307                 return ENOMEM;
  308 
  309         p = mtod(m, hci_cmd_hdr_t *);
  310         p->type = HCI_CMD_PKT;
  311         p->opcode = htole16(opcode);
  312         p->length = len;
  313         m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
  314         M_SETCTX(m, NULL);      /* XXX is this needed? */
  315 
  316         if (len) {
  317                 KASSERT(buf != NULL);
  318 
  319                 m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf);
  320                 if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) {
  321                         m_freem(m);
  322                         return ENOMEM;
  323                 }
  324         }
  325 
  326         DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", device_xname(unit->hci_dev),
  327                 HCI_OGF(opcode), HCI_OCF(opcode));
  328 
  329         /* and send it on */
  330         if (unit->hci_num_cmd_pkts == 0)
  331                 IF_ENQUEUE(&unit->hci_cmdwait, m);
  332         else
  333                 hci_output_cmd(unit, m);
  334 
  335         return 0;
  336 }
  337 
  338 /*
  339  * Incoming packet processing. Since the code is single threaded
  340  * in any case (IPL_SOFTNET), we handle it all in one interrupt function
  341  * picking our way through more important packets first so that hopefully
  342  * we will never get clogged up with bulk data.
  343  */
  344 void
  345 hci_intr(void *arg)
  346 {
  347         struct hci_unit *unit = arg;
  348         struct mbuf *m;
  349 
  350         mutex_enter(&bt_lock);
  351 another:
  352         mutex_enter(&unit->hci_devlock);
  353 
  354         if (unit->hci_eventqlen > 0) {
  355                 IF_DEQUEUE(&unit->hci_eventq, m);
  356                 unit->hci_eventqlen--;
  357                 mutex_exit(&unit->hci_devlock);
  358 
  359                 KASSERT(m != NULL);
  360 
  361                 DPRINTFN(10, "(%s) recv event, len = %d\n",
  362                     device_xname(unit->hci_dev), m->m_pkthdr.len);
  363 
  364                 m->m_flags |= M_LINK0;  /* mark incoming packet */
  365                 hci_mtap(m, unit);
  366                 hci_event(m, unit);
  367 
  368                 goto another;
  369         }
  370 
  371         if (unit->hci_scorxqlen > 0) {
  372                 IF_DEQUEUE(&unit->hci_scorxq, m);
  373                 unit->hci_scorxqlen--;
  374                 mutex_exit(&unit->hci_devlock);
  375 
  376                 KASSERT(m != NULL);
  377 
  378                 DPRINTFN(10, "(%s) recv SCO, len = %d\n",
  379                     device_xname(unit->hci_dev), m->m_pkthdr.len);
  380 
  381                 m->m_flags |= M_LINK0;  /* mark incoming packet */
  382                 hci_mtap(m, unit);
  383                 hci_sco_recv(m, unit);
  384 
  385                 goto another;
  386         }
  387 
  388         if (unit->hci_aclrxqlen > 0) {
  389                 IF_DEQUEUE(&unit->hci_aclrxq, m);
  390                 unit->hci_aclrxqlen--;
  391                 mutex_exit(&unit->hci_devlock);
  392 
  393                 KASSERT(m != NULL);
  394 
  395                 DPRINTFN(10, "(%s) recv ACL, len = %d\n",
  396                     device_xname(unit->hci_dev), m->m_pkthdr.len);
  397 
  398                 m->m_flags |= M_LINK0;  /* mark incoming packet */
  399                 hci_mtap(m, unit);
  400                 hci_acl_recv(m, unit);
  401 
  402                 goto another;
  403         }
  404 
  405         IF_DEQUEUE(&unit->hci_scodone, m);
  406         if (m != NULL) {
  407                 struct hci_link *link;
  408 
  409                 mutex_exit(&unit->hci_devlock);
  410 
  411                 DPRINTFN(11, "(%s) complete SCO\n",
  412                     device_xname(unit->hci_dev));
  413 
  414                 TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
  415                         if (link == M_GETCTX(m, struct hci_link *)) {
  416                                 hci_sco_complete(link, 1);
  417                                 break;
  418                         }
  419                 }
  420 
  421                 unit->hci_num_sco_pkts++;
  422                 m_freem(m);
  423 
  424                 goto another;
  425         }
  426 
  427         mutex_exit(&unit->hci_devlock);
  428         mutex_exit(&bt_lock);
  429 
  430         DPRINTFN(10, "done\n");
  431 }
  432 
  433 /**********************************************************************
  434  *
  435  * IO routines
  436  *
  437  * input & complete routines will be called from device drivers,
  438  * possibly in interrupt context. We return success or failure to
  439  * enable proper accounting but we own the mbuf.
  440  */
  441 
  442 int
  443 hci_input_event(struct hci_unit *unit, struct mbuf *m)
  444 {
  445         int rv;
  446 
  447         mutex_enter(&unit->hci_devlock);
  448 
  449         if (unit->hci_eventqlen > hci_eventq_max) {
  450                 DPRINTF("(%s) dropped event packet.\n", device_xname(unit->hci_dev));
  451                 m_freem(m);
  452                 rv = 0;
  453         } else {
  454                 unit->hci_eventqlen++;
  455                 IF_ENQUEUE(&unit->hci_eventq, m);
  456                 schednetisr(NETISR_BT);
  457                 rv = 1;
  458         }
  459 
  460         mutex_exit(&unit->hci_devlock);
  461         return rv;
  462 }
  463 
  464 int
  465 hci_input_acl(struct hci_unit *unit, struct mbuf *m)
  466 {
  467         int rv;
  468 
  469         mutex_enter(&unit->hci_devlock);
  470 
  471         if (unit->hci_aclrxqlen > hci_aclrxq_max) {
  472                 DPRINTF("(%s) dropped ACL packet.\n", device_xname(unit->hci_dev));
  473                 m_freem(m);
  474                 rv = 0;
  475         } else {
  476                 unit->hci_aclrxqlen++;
  477                 IF_ENQUEUE(&unit->hci_aclrxq, m);
  478                 schednetisr(NETISR_BT);
  479                 rv = 1;
  480         }
  481 
  482         mutex_exit(&unit->hci_devlock);
  483         return rv;
  484 }
  485 
  486 int
  487 hci_input_sco(struct hci_unit *unit, struct mbuf *m)
  488 {
  489         int rv;
  490 
  491         mutex_enter(&unit->hci_devlock);
  492 
  493         if (unit->hci_scorxqlen > hci_scorxq_max) {
  494                 DPRINTF("(%s) dropped SCO packet.\n", device_xname(unit->hci_dev));
  495                 m_freem(m);
  496                 rv = 0;
  497         } else {
  498                 unit->hci_scorxqlen++;
  499                 IF_ENQUEUE(&unit->hci_scorxq, m);
  500                 schednetisr(NETISR_BT);
  501                 rv = 1;
  502         }
  503 
  504         mutex_exit(&unit->hci_devlock);
  505         return rv;
  506 }
  507 
  508 void
  509 hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
  510 {
  511         void *arg;
  512 
  513         hci_mtap(m, unit);
  514 
  515         DPRINTFN(10, "(%s) num_cmd_pkts=%d\n",
  516             device_xname(unit->hci_dev), unit->hci_num_cmd_pkts);
  517 
  518         unit->hci_num_cmd_pkts--;
  519 
  520         /*
  521          * If context is set, this was from a HCI raw socket
  522          * and a record needs to be dropped from the sockbuf.
  523          */
  524         arg = M_GETCTX(m, void *);
  525         if (arg != NULL)
  526                 hci_drop(arg);
  527 
  528         (*unit->hci_if->output_cmd)(unit->hci_dev, m);
  529 }
  530 
  531 void
  532 hci_output_acl(struct hci_unit *unit, struct mbuf *m)
  533 {
  534 
  535         hci_mtap(m, unit);
  536 
  537         DPRINTFN(10, "(%s) num_acl_pkts=%d\n",
  538             device_xname(unit->hci_dev), unit->hci_num_acl_pkts);
  539 
  540         unit->hci_num_acl_pkts--;
  541         (*unit->hci_if->output_acl)(unit->hci_dev, m);
  542 }
  543 
  544 void
  545 hci_output_sco(struct hci_unit *unit, struct mbuf *m)
  546 {
  547 
  548         hci_mtap(m, unit);
  549 
  550         DPRINTFN(10, "(%s) num_sco_pkts=%d\n",
  551             device_xname(unit->hci_dev), unit->hci_num_sco_pkts);
  552 
  553         unit->hci_num_sco_pkts--;
  554         (*unit->hci_if->output_sco)(unit->hci_dev, m);
  555 }
  556 
  557 int
  558 hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
  559 {
  560 
  561 #ifndef __OpenBSD__
  562         if (unit->hci_rxint == NULL) {
  563                 DPRINTFN(10, "(%s) complete SCO!\n", device_xname(unit->hci_dev));
  564                 m_freem(m);
  565                 return 0;
  566         }
  567 #endif
  568 
  569         mutex_enter(&unit->hci_devlock);
  570 
  571         IF_ENQUEUE(&unit->hci_scodone, m);
  572         schednetisr(NETISR_BT);
  573 
  574         mutex_exit(&unit->hci_devlock);
  575         return 1;
  576 }
  577 
  578 /*
  579  * update num_cmd_pkts and push on pending commands queue
  580  */
  581 void
  582 hci_num_cmds(struct hci_unit *unit, uint8_t num)
  583 {
  584         struct mbuf *m;
  585 
  586         unit->hci_num_cmd_pkts = num;
  587 
  588         while (unit->hci_num_cmd_pkts > 0 && !IF_IS_EMPTY(&unit->hci_cmdwait)) {
  589                 IF_DEQUEUE(&unit->hci_cmdwait, m);
  590                 hci_output_cmd(unit, m);
  591         }
  592 }

Cache object: 0b64f600c860675e03e5e578515ce62f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.