[BACK]Return to auvitek_dtv.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / usb

Annotation of src/sys/dev/usb/auvitek_dtv.c, Revision 1.5

1.5     ! jmcneill    1: /* $NetBSD$ */
1.1       jmcneill    2:
                      3: /*-
                      4:  * Copyright (c) 2011 Jared D. McNeill <jmcneill@invisible.ca>
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     17:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     18:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     19:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     20:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     21:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     22:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     23:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     24:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     25:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     26:  * POSSIBILITY OF SUCH DAMAGE.
                     27:  */
                     28:
                     29: /*
                     30:  * Auvitek AU0828 USB controller (Digital TV function)
                     31:  */
                     32:
                     33: #include <sys/cdefs.h>
1.5     ! jmcneill   34: __KERNEL_RCSID(0, "$NetBSD$");
1.1       jmcneill   35:
                     36: #include <sys/param.h>
                     37: #include <sys/systm.h>
                     38: #include <sys/device.h>
                     39: #include <sys/conf.h>
                     40: #include <sys/kmem.h>
                     41: #include <sys/bus.h>
                     42:
                     43: #include <dev/usb/usb.h>
                     44: #include <dev/usb/usbdi.h>
                     45: #include <dev/usb/usbdivar.h>
                     46: #include <dev/usb/usbdi_util.h>
                     47: #include <dev/usb/usbdevs.h>
                     48:
                     49: #include <dev/dtv/dtvif.h>
                     50:
                     51: #include <dev/usb/auvitekreg.h>
                     52: #include <dev/usb/auvitekvar.h>
                     53:
                     54: static void            auvitek_dtv_get_devinfo(void *,
                     55:                            struct dvb_frontend_info *);
                     56: static int             auvitek_dtv_open(void *, int);
                     57: static void            auvitek_dtv_close(void *);
                     58: static int             auvitek_dtv_set_tuner(void *,
                     59:                            const struct dvb_frontend_parameters *);
                     60: static fe_status_t     auvitek_dtv_get_status(void *);
                     61: static uint16_t                auvitek_dtv_get_signal_strength(void *);
                     62: static uint16_t                auvitek_dtv_get_snr(void *);
1.3       jmcneill   63: static int             auvitek_dtv_start_transfer(void *,
                     64:                            void (*)(void *, const struct dtv_payload *),
                     65:                            void *);
1.1       jmcneill   66: static int             auvitek_dtv_stop_transfer(void *);
                     67:
                     68: static int             auvitek_dtv_init_pipes(struct auvitek_softc *);
                     69: static int             auvitek_dtv_close_pipes(struct auvitek_softc *);
                     70:
                     71: static int             auvitek_dtv_bulk_start(struct auvitek_softc *);
                     72: static int             auvitek_dtv_bulk_start1(struct auvitek_bulk_xfer *);
                     73: static void            auvitek_dtv_bulk_cb(usbd_xfer_handle,
                     74:                                            usbd_private_handle,
                     75:                                            usbd_status);
                     76:
                     77: static const struct dtv_hw_if auvitek_dtv_if = {
                     78:        .get_devinfo = auvitek_dtv_get_devinfo,
                     79:        .open = auvitek_dtv_open,
                     80:        .close = auvitek_dtv_close,
                     81:        .set_tuner = auvitek_dtv_set_tuner,
                     82:        .get_status = auvitek_dtv_get_status,
                     83:        .get_signal_strength = auvitek_dtv_get_signal_strength,
                     84:        .get_snr = auvitek_dtv_get_snr,
                     85:        .start_transfer = auvitek_dtv_start_transfer,
                     86:        .stop_transfer = auvitek_dtv_stop_transfer,
                     87: };
                     88:
                     89: int
                     90: auvitek_dtv_attach(struct auvitek_softc *sc)
                     91: {
                     92:
1.3       jmcneill   93:        auvitek_dtv_rescan(sc, NULL, NULL);
1.1       jmcneill   94:
                     95:        return (sc->sc_dtvdev != NULL);
                     96: }
                     97:
                     98: int
                     99: auvitek_dtv_detach(struct auvitek_softc *sc, int flags)
                    100: {
                    101:        if (sc->sc_dtvdev != NULL) {
                    102:                config_detach(sc->sc_dtvdev, flags);
                    103:                sc->sc_dtvdev = NULL;
                    104:        }
                    105:
                    106:        return 0;
                    107: }
                    108:
                    109: void
1.3       jmcneill  110: auvitek_dtv_rescan(struct auvitek_softc *sc, const char *ifattr,
                    111:     const int *locs)
                    112: {
                    113:        struct dtv_attach_args daa;
                    114:
                    115:        daa.hw = &auvitek_dtv_if;
                    116:        daa.priv = sc;
                    117:
                    118:        if (ifattr_match(ifattr, "dtvbus") && sc->sc_dtvdev == NULL)
                    119:                sc->sc_dtvdev = config_found_ia(sc->sc_dev, "dtvbus",
                    120:                    &daa, dtv_print);
                    121: }
                    122:
                    123: void
1.1       jmcneill  124: auvitek_dtv_childdet(struct auvitek_softc *sc, device_t child)
                    125: {
                    126:        if (sc->sc_dtvdev == child)
                    127:                sc->sc_dtvdev = NULL;
                    128: }
                    129:
                    130: static void
                    131: auvitek_dtv_get_devinfo(void *priv, struct dvb_frontend_info *info)
                    132: {
                    133:        struct auvitek_softc *sc = priv;
                    134:
                    135:        memset(info, 0, sizeof(*info));
                    136:        strlcpy(info->name, sc->sc_descr, sizeof(info->name));
                    137:        info->type = FE_ATSC;
                    138:        info->frequency_min = 54000000;
                    139:        info->frequency_max = 858000000;
                    140:        info->frequency_stepsize = 62500;
                    141:        info->caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB;
                    142: }
                    143:
                    144: static int
                    145: auvitek_dtv_open(void *priv, int flags)
                    146: {
                    147:        struct auvitek_softc *sc = priv;
                    148:
                    149:        if (sc->sc_dying)
                    150:                return EIO;
                    151:
1.4       jmcneill  152:        auvitek_attach_tuner(sc->sc_dev);
1.1       jmcneill  153:        if (sc->sc_xc5k == NULL)
                    154:                return ENXIO;
                    155:
                    156:        return auvitek_dtv_init_pipes(sc);
                    157: }
                    158:
                    159: static void
                    160: auvitek_dtv_close(void *priv)
                    161: {
                    162:        struct auvitek_softc *sc = priv;
                    163:
                    164:        auvitek_dtv_stop_transfer(sc);
                    165:        auvitek_dtv_close_pipes(sc);
1.3       jmcneill  166:
                    167:        sc->sc_dtvsubmitcb = NULL;
                    168:        sc->sc_dtvsubmitarg = NULL;
1.1       jmcneill  169: }
                    170:
                    171: static int
                    172: auvitek_dtv_set_tuner(void *priv, const struct dvb_frontend_parameters *params)
                    173: {
                    174:        struct auvitek_softc *sc = priv;
                    175:        int error;
                    176:
                    177:        error = au8522_set_modulation(sc->sc_au8522, params->u.vsb.modulation);
                    178:        if (error)
                    179:                return error;
                    180:
                    181:        delay(100000);
                    182:
                    183:        au8522_set_gate(sc->sc_au8522, true);
                    184:        error = xc5k_tune_dtv(sc->sc_xc5k, params);
                    185:        au8522_set_gate(sc->sc_au8522, false);
                    186:
                    187:        return error;
                    188: }
                    189:
                    190: fe_status_t
                    191: auvitek_dtv_get_status(void *priv)
                    192: {
                    193:        struct auvitek_softc *sc = priv;
                    194:
                    195:        return au8522_get_dtv_status(sc->sc_au8522);
                    196: }
                    197:
                    198: uint16_t
                    199: auvitek_dtv_get_signal_strength(void *priv)
                    200: {
1.2       jmcneill  201:        return auvitek_dtv_get_snr(priv);
1.1       jmcneill  202: }
                    203:
                    204: uint16_t
                    205: auvitek_dtv_get_snr(void *priv)
                    206: {
1.2       jmcneill  207:        struct auvitek_softc *sc = priv;
                    208:
                    209:        return au8522_get_snr(sc->sc_au8522);
1.1       jmcneill  210: }
                    211:
                    212: static int
1.3       jmcneill  213: auvitek_dtv_start_transfer(void *priv,
                    214:     void (*cb)(void *, const struct dtv_payload *), void *arg)
1.1       jmcneill  215: {
                    216:        struct auvitek_softc *sc = priv;
                    217:        int s;
                    218:
                    219:        if (sc->sc_ab.ab_running) {
                    220:                return 0;
                    221:        }
                    222:
1.3       jmcneill  223:        sc->sc_dtvsubmitcb = cb;
                    224:        sc->sc_dtvsubmitarg = arg;
                    225:
1.1       jmcneill  226:        auvitek_write_1(sc, 0x608, 0x90);
                    227:        auvitek_write_1(sc, 0x609, 0x72);
                    228:        auvitek_write_1(sc, 0x60a, 0x71);
                    229:        auvitek_write_1(sc, 0x60b, 0x01);
                    230:
                    231:        sc->sc_ab.ab_running = true;
                    232:
                    233:        s = splusb();
                    234:        auvitek_dtv_bulk_start(sc);
                    235:        splx(s);
                    236:
                    237:        return 0;
                    238: }
                    239:
                    240: static int
                    241: auvitek_dtv_stop_transfer(void *priv)
                    242: {
                    243:        struct auvitek_softc *sc = priv;
                    244:
                    245:        sc->sc_ab.ab_running = false;
                    246:
                    247:        auvitek_write_1(sc, 0x608, 0x00);
                    248:        auvitek_write_1(sc, 0x609, 0x00);
                    249:        auvitek_write_1(sc, 0x60a, 0x00);
                    250:        auvitek_write_1(sc, 0x60b, 0x00);
                    251:
                    252:        return 0;
                    253: }
                    254:
                    255: static int
                    256: auvitek_dtv_init_pipes(struct auvitek_softc *sc)
                    257: {
                    258:        usbd_status err;
                    259:
1.5     ! jmcneill  260:        KERNEL_LOCK(1, curlwp);
1.1       jmcneill  261:        err = usbd_open_pipe(sc->sc_bulk_iface, sc->sc_ab.ab_endpt,
                    262:            USBD_EXCLUSIVE_USE, &sc->sc_ab.ab_pipe);
1.5     ! jmcneill  263:        KERNEL_UNLOCK_ONE(curlwp);
        !           264:
1.1       jmcneill  265:        if (err) {
                    266:                aprint_error_dev(sc->sc_dev, "couldn't open bulk-in pipe: %s\n",
                    267:                    usbd_errstr(err));
                    268:                return ENOMEM;
                    269:        }
                    270:
                    271:        return 0;
                    272: }
                    273:
                    274: static int
                    275: auvitek_dtv_close_pipes(struct auvitek_softc *sc)
                    276: {
                    277:        if (sc->sc_ab.ab_pipe != NULL) {
1.5     ! jmcneill  278:                KERNEL_LOCK(1, curlwp);
1.1       jmcneill  279:                usbd_abort_pipe(sc->sc_ab.ab_pipe);
                    280:                usbd_close_pipe(sc->sc_ab.ab_pipe);
1.5     ! jmcneill  281:                KERNEL_UNLOCK_ONE(curlwp);
1.1       jmcneill  282:                sc->sc_ab.ab_pipe = NULL;
                    283:        }
                    284:
                    285:        return 0;
                    286: }
                    287:
                    288: static void
                    289: auvitek_dtv_bulk_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
                    290:     usbd_status status)
                    291: {
                    292:        struct auvitek_bulk_xfer *bx = priv;
                    293:        struct auvitek_softc *sc = bx->bx_sc;
                    294:        struct auvitek_bulk *ab = &sc->sc_ab;
                    295:        struct dtv_payload payload;
                    296:        uint32_t xferlen;
                    297:
1.3       jmcneill  298:        if (ab->ab_running == false || sc->sc_dtvsubmitcb == NULL)
1.1       jmcneill  299:                return;
                    300:
                    301:        usbd_get_xfer_status(xfer, NULL, NULL, &xferlen, NULL);
                    302:
                    303:        //printf("%s: status=%d xferlen=%u\n", __func__, status, xferlen);
                    304:
                    305:        if (status != USBD_NORMAL_COMPLETION) {
                    306:                printf("%s: USB error (%s)\n", __func__, usbd_errstr(status));
                    307:                if (status == USBD_STALLED) {
                    308:                        usbd_clear_endpoint_stall_async(ab->ab_pipe);
                    309:                        goto next;
                    310:                }
                    311:                if (status == USBD_SHORT_XFER) {
                    312:                        goto next;
                    313:                }
                    314:                return;
                    315:        }
                    316:
                    317:        if (xferlen == 0) {
                    318:                printf("%s: 0-length xfer\n", __func__);
                    319:                goto next;
                    320:        }
                    321:
                    322:        payload.data = bx->bx_buffer;
                    323:        payload.size = xferlen;
1.3       jmcneill  324:        sc->sc_dtvsubmitcb(sc->sc_dtvsubmitarg, &payload);
1.1       jmcneill  325:
                    326: next:
                    327:        auvitek_dtv_bulk_start1(bx);
                    328: }
                    329:
                    330: static int
                    331: auvitek_dtv_bulk_start(struct auvitek_softc *sc)
                    332: {
                    333:        int i, error;
                    334:
                    335:        for (i = 0; i < AUVITEK_NBULK_XFERS; i++) {
                    336:                error = auvitek_dtv_bulk_start1(&sc->sc_ab.ab_bx[i]);
                    337:                if (error)
                    338:                        return error;
                    339:        }
                    340:
                    341:        return 0;
                    342: }
                    343:
                    344: static int
                    345: auvitek_dtv_bulk_start1(struct auvitek_bulk_xfer *bx)
                    346: {
                    347:        struct auvitek_softc *sc = bx->bx_sc;
                    348:        struct auvitek_bulk *ab = &sc->sc_ab;
                    349:        int err;
                    350:
                    351:        usbd_setup_xfer(bx->bx_xfer, ab->ab_pipe, bx,
                    352:            bx->bx_buffer, AUVITEK_BULK_BUFLEN,
                    353:            //USBD_SHORT_XFER_OK|USBD_NO_COPY, USBD_NO_TIMEOUT,
                    354:            USBD_NO_COPY, 100,
                    355:            auvitek_dtv_bulk_cb);
1.5     ! jmcneill  356:
        !           357:        KERNEL_LOCK(1, curlwp);
1.1       jmcneill  358:        err = usbd_transfer(bx->bx_xfer);
1.5     ! jmcneill  359:        KERNEL_UNLOCK_ONE(curlwp);
        !           360:
1.1       jmcneill  361:        if (err != USBD_IN_PROGRESS) {
                    362:                aprint_error_dev(sc->sc_dev, "USB error: %s\n",
                    363:                    usbd_errstr(err));
                    364:                return ENODEV;
                    365:        }
                    366:
                    367:        return 0;
                    368: }

CVSweb <webmaster@jp.NetBSD.org>