root/dev/sdmmc/sbt.c

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

DEFINITIONS

This source file includes following definitions.
  1. sbt_match
  2. sbt_attach
  3. sbt_detach
  4. sbt_write_packet
  5. sbt_read_packet
  6. sbt_intr
  7. sbt_enable
  8. sbt_disable
  9. sbt_start
  10. sbt_start_cmd
  11. sbt_start_acl
  12. sbt_start_sco

    1 /*      $OpenBSD: sbt.c,v 1.9 2007/06/19 07:59:57 uwe Exp $     */
    2 
    3 /*
    4  * Copyright (c) 2007 Uwe Stuehler <uwe@openbsd.org>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 /* Driver for Type-A/B SDIO Bluetooth cards */
   20 
   21 #include <sys/param.h>
   22 #include <sys/device.h>
   23 #include <sys/malloc.h>
   24 #include <sys/mbuf.h>
   25 #include <sys/proc.h>
   26 #include <sys/queue.h>
   27 #include <sys/socket.h>
   28 #include <sys/systm.h>
   29 
   30 #include <netbt/hci.h>
   31 
   32 #include <dev/sdmmc/sdmmcdevs.h>
   33 #include <dev/sdmmc/sdmmcvar.h>
   34 
   35 #define CSR_READ_1(sc, reg)       sdmmc_io_read_1((sc)->sc_sf, (reg))
   36 #define CSR_WRITE_1(sc, reg, val) sdmmc_io_write_1((sc)->sc_sf, (reg), (val))
   37 
   38 #define SBT_REG_DAT     0x00            /* receiver/transmitter data */
   39 #define SBT_REG_RPC     0x10            /* read packet control */
   40 #define  RPC_PCRRT      (1<<0)          /* packet read retry */
   41 #define SBT_REG_WPC     0x11            /* write packet control */
   42 #define  WPC_PCWRT      (1<<0)          /* packet write retry */
   43 #define SBT_REG_RC      0x12            /* retry control status/set */
   44 #define SBT_REG_ISTAT   0x13            /* interrupt status */
   45 #define  ISTAT_INTRD    (1<<0)          /* packet available for read */
   46 #define SBT_REG_ICLR    0x13            /* interrupt clear */
   47 #define SBT_REG_IENA    0x14            /* interrupt enable */
   48 #define SBT_REG_BTMODE  0x20            /* SDIO Bluetooth card mode */
   49 #define  BTMODE_TYPEB   (1<<0)          /* 1=Type-B, 0=Type-A */
   50 
   51 #define SBT_PKT_BUFSIZ  65540
   52 #define SBT_RXTRY_MAX   5
   53 
   54 struct sbt_softc {
   55         struct device sc_dev;           /* base device */
   56         struct hci_unit sc_unit;        /* MI host controller */
   57         struct sdmmc_function *sc_sf;   /* SDIO function */
   58         struct proc *sc_thread;         /* inquiry thread */
   59         int sc_dying;                   /* shutdown in progress */
   60         void *sc_ih;
   61         u_char *sc_buf;
   62         int sc_rxtry;
   63 };
   64 
   65 int     sbt_match(struct device *, void *, void *);
   66 void    sbt_attach(struct device *, struct device *, void *);
   67 int     sbt_detach(struct device *, int);
   68 
   69 int     sbt_write_packet(struct sbt_softc *, u_char *, size_t);
   70 int     sbt_read_packet(struct sbt_softc *, u_char *, size_t *);
   71 
   72 int     sbt_intr(void *);
   73 
   74 int     sbt_enable(struct hci_unit *);
   75 void    sbt_disable(struct hci_unit *);
   76 void    sbt_start(struct hci_unit *, struct ifqueue *, int);
   77 void    sbt_start_cmd(struct hci_unit *);
   78 void    sbt_start_acl(struct hci_unit *);
   79 void    sbt_start_sco(struct hci_unit *);
   80 
   81 #undef DPRINTF
   82 #define SBT_DEBUG
   83 #ifdef SBT_DEBUG
   84 int sbt_debug = 1;
   85 #define DPRINTF(s)      printf s
   86 #define DNPRINTF(n, s)  do { if ((n) <= sbt_debug) printf s; } while (0)
   87 #else
   88 #define DPRINTF(s)      do {} while (0)
   89 #define DNPRINTF(n, s)  do {} while (0)
   90 #endif
   91 
   92 #define DEVNAME(sc)     ((sc)->sc_dev.dv_xname)
   93 
   94 struct cfattach sbt_ca = {
   95         sizeof(struct sbt_softc), sbt_match, sbt_attach, sbt_detach
   96 };
   97 
   98 struct cfdriver sbt_cd = {
   99         NULL, "sbt", DV_DULL
  100 };
  101 
  102 
  103 /*
  104  * Autoconf glue
  105  */
  106 
  107 static const struct sbt_product {
  108         u_int16_t       sp_vendor;
  109         u_int16_t       sp_product;
  110         const char      *sp_cisinfo[4];
  111 } sbt_products[] = {
  112         { SDMMC_VENDOR_SOCKETCOM,
  113           SDMMC_PRODUCT_SOCKETCOM_BTCARD,
  114           SDMMC_CIS_SOCKETCOM_BTCARD }
  115 };
  116 
  117 int
  118 sbt_match(struct device *parent, void *match, void *aux)
  119 {
  120         struct sdmmc_attach_args *sa = aux;
  121         const struct sbt_product *sp;
  122         struct sdmmc_function *sf;
  123         int i;
  124 
  125         if (sa->sf == NULL)
  126                 return 0;       /* not SDIO */
  127 
  128         sf = sa->sf->sc->sc_fn0;
  129         sp = &sbt_products[0];
  130 
  131         for (i = 0; i < sizeof(sbt_products) / sizeof(sbt_products[0]);
  132              i++, sp = &sbt_products[i])
  133                 if (sp->sp_vendor == sf->cis.manufacturer &&
  134                     sp->sp_product == sf->cis.product)
  135                         return 1;
  136         return 0;
  137 }
  138 
  139 void
  140 sbt_attach(struct device *parent, struct device *self, void *aux)
  141 {
  142         struct sbt_softc *sc = (struct sbt_softc *)self;
  143         struct sdmmc_attach_args *sa = aux;
  144 
  145         printf("\n");
  146 
  147         sc->sc_sf = sa->sf;
  148 
  149         (void)sdmmc_io_function_disable(sc->sc_sf);
  150         if (sdmmc_io_function_enable(sc->sc_sf)) {
  151                 printf("%s: function not ready\n", DEVNAME(sc));
  152                 return;
  153         }
  154 
  155         /* It may be Type-B, but we use it only in Type-A mode. */
  156         printf("%s: SDIO Bluetooth Type-A\n", DEVNAME(sc));
  157 
  158         sc->sc_buf = malloc(SBT_PKT_BUFSIZ, M_DEVBUF,
  159             M_NOWAIT | M_CANFAIL);
  160         if (sc->sc_buf == NULL) {
  161                 printf("%s: can't allocate cmd buffer\n", DEVNAME(sc));
  162                 return;
  163         }
  164 
  165         /* Enable the HCI packet transport read interrupt. */
  166         CSR_WRITE_1(sc, SBT_REG_IENA, ISTAT_INTRD);
  167 
  168         /* Enable the card interrupt for this function. */
  169         sc->sc_ih = sdmmc_intr_establish(parent, sbt_intr, sc, DEVNAME(sc));
  170         if (sc->sc_ih == NULL) {
  171                 printf("%s: can't establish interrupt\n", DEVNAME(sc));
  172                 return;
  173         }
  174         sdmmc_intr_enable(sc->sc_sf);
  175 
  176         /*
  177          * Attach Bluetooth unit (machine-independent HCI).
  178          */
  179         sc->sc_unit.hci_softc = self;
  180         sc->sc_unit.hci_devname = DEVNAME(sc);
  181         sc->sc_unit.hci_enable = sbt_enable;
  182         sc->sc_unit.hci_disable = sbt_disable;
  183         sc->sc_unit.hci_start_cmd = sbt_start_cmd;
  184         sc->sc_unit.hci_start_acl = sbt_start_acl;
  185         sc->sc_unit.hci_start_sco = sbt_start_sco;
  186         sc->sc_unit.hci_ipl = IPL_TTY; /* XXX */
  187         hci_attach(&sc->sc_unit);
  188 }
  189 
  190 int
  191 sbt_detach(struct device *self, int flags)
  192 {
  193         struct sbt_softc *sc = (struct sbt_softc *)self;
  194 
  195         sc->sc_dying = 1;
  196         while (sc->sc_thread != NULL)
  197                 tsleep(sc, PWAIT, "dying", 0);
  198 
  199         hci_detach(&sc->sc_unit);
  200 
  201         if (sc->sc_ih != NULL)
  202                 sdmmc_intr_disestablish(sc->sc_ih);
  203 
  204         return 0;
  205 }
  206 
  207 
  208 /*
  209  * Bluetooth HCI packet transport
  210  */
  211 
  212 int
  213 sbt_write_packet(struct sbt_softc *sc, u_char *buf, size_t len)
  214 {
  215         u_char hdr[3];
  216         size_t pktlen;
  217         int error = EIO;
  218         int retry = 3;
  219 
  220 again:
  221         if (retry-- == 0) {
  222                 DPRINTF(("%s: sbt_write_cmd: giving up\n", DEVNAME(sc)));
  223                 return error;
  224         }
  225 
  226         /* Restart the current packet. */
  227         sdmmc_io_write_1(sc->sc_sf, SBT_REG_WPC, WPC_PCWRT);
  228 
  229         /* Write the packet length. */
  230         pktlen = len + 3;
  231         hdr[0] = pktlen & 0xff;
  232         hdr[1] = (pktlen >> 8) & 0xff;
  233         hdr[2] = (pktlen >> 16) & 0xff;
  234         error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3);
  235         if (error) {
  236                 DPRINTF(("%s: sbt_write_packet: failed to send length\n",
  237                     DEVNAME(sc)));
  238                 goto again;
  239         }
  240 
  241         error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len);
  242         if (error) {
  243                 DPRINTF(("%s: sbt_write_packet: failed to send packet data\n",
  244                     DEVNAME(sc)));
  245                 goto again;
  246         }
  247         return 0;
  248 }
  249 
  250 int
  251 sbt_read_packet(struct sbt_softc *sc, u_char *buf, size_t *lenp)
  252 {
  253         u_char hdr[3];
  254         size_t len;
  255         int error;
  256 
  257         error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3);
  258         if (error) {
  259                 DPRINTF(("%s: sbt_read_packet: failed to read length\n",
  260                     DEVNAME(sc)));
  261                 goto out;
  262         }
  263         len = (hdr[0] | (hdr[1] << 8) | (hdr[2] << 16)) - 3;
  264         if (len > *lenp) {
  265                 DPRINTF(("%s: sbt_read_packet: len %u > %u\n",
  266                     DEVNAME(sc), len, *lenp));
  267                 error = ENOBUFS;
  268                 goto out;
  269         }
  270 
  271         DNPRINTF(2,("%s: sbt_read_packet: reading len %u bytes\n",
  272             DEVNAME(sc), len));
  273         error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len);
  274         if (error) {
  275                 DPRINTF(("%s: sbt_read_packet: failed to read packet data\n",
  276                     DEVNAME(sc)));
  277                 goto out;
  278         }
  279 
  280 out:
  281         if (error) {
  282                 if (sc->sc_rxtry >= SBT_RXTRY_MAX) {
  283                         /* Drop and request the next packet. */
  284                         sc->sc_rxtry = 0;
  285                         CSR_WRITE_1(sc, SBT_REG_RPC, 0);
  286                 } else {
  287                         /* Request the current packet again. */
  288                         sc->sc_rxtry++;
  289                         CSR_WRITE_1(sc, SBT_REG_RPC, RPC_PCRRT);
  290                 }
  291                 return error;
  292         }
  293 
  294         /* acknowledge read packet */
  295         CSR_WRITE_1(sc, SBT_REG_RPC, 0);
  296 
  297         *lenp = len;
  298         return 0;
  299 }
  300 
  301 /*
  302  * Interrupt handling
  303  */
  304 
  305 int
  306 sbt_intr(void *arg)
  307 {
  308         struct sbt_softc *sc = arg;
  309         struct mbuf *m = NULL;
  310         u_int8_t status;
  311         size_t len;
  312         int s;
  313 
  314         s = splsdmmc();
  315 
  316         status = CSR_READ_1(sc, SBT_REG_ISTAT);
  317         CSR_WRITE_1(sc, SBT_REG_ICLR, status);
  318 
  319         if ((status & ISTAT_INTRD) == 0)
  320                 return 0;       /* shared SDIO card interrupt? */
  321 
  322         len = SBT_PKT_BUFSIZ;
  323         if (sbt_read_packet(sc, sc->sc_buf, &len) != 0 || len == 0) {
  324                 DPRINTF(("%s: sbt_intr: read failed\n", DEVNAME(sc)));
  325                 goto eoi;
  326         }
  327 
  328         MGETHDR(m, M_DONTWAIT, MT_DATA);
  329         if (m == NULL) {
  330                 DPRINTF(("%s: sbt_intr: MGETHDR failed\n", DEVNAME(sc)));
  331                 goto eoi;
  332         }
  333 
  334         m->m_pkthdr.len = m->m_len = MHLEN;
  335         m_copyback(m, 0, len, sc->sc_buf);
  336         if (m->m_pkthdr.len == MAX(MHLEN, len)) {
  337                 m->m_pkthdr.len = len;
  338                 m->m_len = MIN(MHLEN, m->m_pkthdr.len);
  339         } else {
  340                 DPRINTF(("%s: sbt_intr: m_copyback failed\n", DEVNAME(sc)));
  341                 m_free(m);
  342                 m = NULL;
  343         }
  344 
  345 eoi:
  346         if (m != NULL) {
  347                 switch (sc->sc_buf[0]) {
  348                 case HCI_ACL_DATA_PKT:
  349                         DNPRINTF(1,("%s: recv ACL packet (%d bytes)\n",
  350                             DEVNAME(sc), m->m_pkthdr.len));
  351                         hci_input_acl(&sc->sc_unit, m);
  352                         break;
  353                 case HCI_SCO_DATA_PKT:
  354                         DNPRINTF(1,("%s: recv SCO packet (%d bytes)\n",
  355                             DEVNAME(sc), m->m_pkthdr.len));
  356                         hci_input_sco(&sc->sc_unit, m);
  357                         break;
  358                 case HCI_EVENT_PKT:
  359                         DNPRINTF(1,("%s: recv EVENT packet (%d bytes)\n",
  360                             DEVNAME(sc), m->m_pkthdr.len));
  361                         hci_input_event(&sc->sc_unit, m);
  362                         break;
  363                 default:
  364                         DPRINTF(("%s: recv 0x%x packet (%d bytes)\n",
  365                             DEVNAME(sc), sc->sc_buf[0], m->m_pkthdr.len));
  366                         sc->sc_unit.hci_stats.err_rx++;
  367                         m_free(m);
  368                         break;
  369                 }
  370         } else
  371                 sc->sc_unit.hci_stats.err_rx++;
  372 
  373         splx(s);
  374 
  375         /* Claim this interrupt. */
  376         return 1;
  377 }
  378 
  379 
  380 /*
  381  * Bluetooth HCI unit functions
  382  */
  383 
  384 int
  385 sbt_enable(struct hci_unit *unit)
  386 {
  387         if (unit->hci_flags & BTF_RUNNING)
  388                 return 0;
  389 
  390         unit->hci_flags |= BTF_RUNNING;
  391         unit->hci_flags &= ~BTF_XMIT;
  392         return 0;
  393 }
  394 
  395 void
  396 sbt_disable(struct hci_unit *unit)
  397 {
  398         if (!(unit->hci_flags & BTF_RUNNING))
  399                 return;
  400 
  401 #ifdef notyet                   /* XXX */
  402         if (sc->sc_rxp) {
  403                 m_freem(sc->sc_rxp);
  404                 sc->sc_rxp = NULL;
  405         }
  406 
  407         if (sc->sc_txp) {
  408                 m_freem(sc->sc_txp);
  409                 sc->sc_txp = NULL;
  410         }
  411 #endif
  412 
  413         unit->hci_flags &= ~BTF_RUNNING;
  414 }
  415 
  416 void
  417 sbt_start(struct hci_unit *unit, struct ifqueue *q, int xmit)
  418 {
  419         struct sbt_softc *sc = (struct sbt_softc *)unit->hci_softc;
  420         struct mbuf *m;
  421         int len;
  422 #ifdef SBT_DEBUG
  423         const char *what;
  424 #endif
  425 
  426         if (sc->sc_dying || IF_IS_EMPTY(q))
  427                 return;
  428 
  429         IF_DEQUEUE(q, m);
  430 
  431 #ifdef SBT_DEBUG
  432         switch (xmit) {
  433         case BTF_XMIT_CMD:
  434                 what = "CMD";
  435                 break;
  436         case BTF_XMIT_ACL:
  437                 what = "ACL";
  438                 break;
  439         case BTF_XMIT_SCO:
  440                 what = "SCO";
  441                 break;
  442         }
  443         DNPRINTF(1,("%s: xmit %s packet (%d bytes)\n", DEVNAME(sc),
  444             what, m->m_pkthdr.len));
  445 #endif
  446 
  447         unit->hci_flags |= xmit;
  448 
  449         len = m->m_pkthdr.len;
  450         m_copydata(m, 0, len, sc->sc_buf);
  451         m_freem(m);
  452 
  453         if (sbt_write_packet(sc, sc->sc_buf, len))
  454                 DPRINTF(("%s: sbt_write_packet failed\n", DEVNAME(sc)));
  455 
  456         unit->hci_flags &= ~xmit;
  457 }
  458 
  459 void
  460 sbt_start_cmd(struct hci_unit *unit)
  461 {
  462         sbt_start(unit, &unit->hci_cmdq, BTF_XMIT_CMD);
  463 }
  464 
  465 void
  466 sbt_start_acl(struct hci_unit *unit)
  467 {
  468         sbt_start(unit, &unit->hci_acltxq, BTF_XMIT_ACL);
  469 }
  470 
  471 void
  472 sbt_start_sco(struct hci_unit *unit)
  473 {
  474         sbt_start(unit, &unit->hci_scotxq, BTF_XMIT_SCO);
  475 }

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