[BACK]Return to sbt.c CVS log [TXT][DIR] Up to [local] / sys / dev / sdmmc

Annotation of sys/dev/sdmmc/sbt.c, Revision 1.1.1.1

1.1       nbrk        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: }

CVSweb