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