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  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 1830087a424aea7f72897a3a0e22a1cf


[ 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.