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

Annotation of src/sys/dev/usb/auvitek_video.c, Revision 1.7.18.1

1.7.18.1! christos    1: /* $NetBSD: auvitek_video.c,v 1.9 2019/01/22 06:47:20 skrll Exp $ */
1.1       jmcneill    2:
                      3: /*-
                      4:  * Copyright (c) 2010 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
                     31:  */
                     32:
                     33: #include <sys/cdefs.h>
1.7.18.1! christos   34: __KERNEL_RCSID(0, "$NetBSD: auvitek_video.c,v 1.9 2019/01/22 06:47:20 skrll Exp $");
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/video_if.h>
                     50:
                     51: #include <dev/usb/auvitekreg.h>
                     52: #include <dev/usb/auvitekvar.h>
                     53:
                     54: #define        AUVITEK_FORMAT_DEFAULT          0
                     55: #define        AUVITEK_STANDARD_NTSC_M         0
                     56: #define        AUVITEK_TUNER_DEFAULT           0
                     57: #define        AUVITEK_AUDIO_TELEVISION        0
                     58: #define        AUVITEK_AUDIO_LINEIN            1
                     59: #define        AUVITEK_INPUT_COMPOSITE         0
                     60: #define        AUVITEK_INPUT_SVIDEO            1
                     61: #define        AUVITEK_INPUT_TELEVISION        2
                     62: #define        AUVITEK_INPUT_CABLE             3
                     63:
                     64: static int             auvitek_open(void *, int);
                     65: static void            auvitek_close(void *);
                     66: static const char *    auvitek_get_devname(void *);
                     67: static const char *    auvitek_get_businfo(void *);
                     68: static int             auvitek_enum_format(void *, uint32_t,
                     69:                                          struct video_format *);
                     70: static int             auvitek_get_format(void *, struct video_format *);
                     71: static int             auvitek_set_format(void *, struct video_format *);
                     72: static int             auvitek_try_format(void *, struct video_format *);
                     73: static int             auvitek_enum_standard(void *, uint32_t,
                     74:                                              enum video_standard *);
                     75: static int             auvitek_get_standard(void *, enum video_standard *);
                     76: static int             auvitek_set_standard(void *, enum video_standard);
                     77: static int             auvitek_start_transfer(void *);
                     78: static int             auvitek_stop_transfer(void *);
                     79: static int             auvitek_get_tuner(void *, struct video_tuner *);
                     80: static int             auvitek_set_tuner(void *, struct video_tuner *);
                     81: static int             auvitek_enum_audio(void *, uint32_t,
                     82:                                           struct video_audio *);
                     83: static int             auvitek_get_audio(void *, struct video_audio *);
                     84: static int             auvitek_set_audio(void *, struct video_audio *);
                     85: static int             auvitek_enum_input(void *, uint32_t,
                     86:                                           struct video_input *);
                     87: static int             auvitek_get_input(void *, struct video_input *);
                     88: static int             auvitek_set_input(void *, struct video_input *);
                     89: static int             auvitek_get_frequency(void *, struct video_frequency *);
                     90: static int             auvitek_set_frequency(void *, struct video_frequency *);
                     91:
                     92: static int             auvitek_start_xfer(struct auvitek_softc *);
                     93: static int             auvitek_stop_xfer(struct auvitek_softc *);
                     94: static int             auvitek_isoc_start(struct auvitek_softc *);
                     95: static int             auvitek_isoc_start1(struct auvitek_isoc *);
1.7       skrll      96: static void            auvitek_isoc_intr(struct usbd_xfer *, void *,
1.1       jmcneill   97:                                          usbd_status);
                     98: static int             auvitek_isoc_process(struct auvitek_softc *,
                     99:                                             uint8_t *, uint32_t);
                    100: static void            auvitek_videobuf_weave(struct auvitek_softc *,
                    101:                                               uint8_t *, uint32_t);
                    102:
1.4       jmcneill  103: static const struct video_hw_if auvitek_video_if = {
1.1       jmcneill  104:        .open = auvitek_open,
                    105:        .close = auvitek_close,
                    106:        .get_devname = auvitek_get_devname,
                    107:        .get_businfo = auvitek_get_businfo,
                    108:        .enum_format = auvitek_enum_format,
                    109:        .get_format = auvitek_get_format,
                    110:        .set_format = auvitek_set_format,
                    111:        .try_format = auvitek_try_format,
                    112:        .enum_standard = auvitek_enum_standard,
                    113:        .get_standard = auvitek_get_standard,
                    114:        .set_standard = auvitek_set_standard,
                    115:        .start_transfer = auvitek_start_transfer,
                    116:        .stop_transfer = auvitek_stop_transfer,
                    117:        .get_tuner = auvitek_get_tuner,
                    118:        .set_tuner = auvitek_set_tuner,
                    119:        .enum_audio = auvitek_enum_audio,
                    120:        .get_audio = auvitek_get_audio,
                    121:        .set_audio = auvitek_set_audio,
                    122:        .enum_input = auvitek_enum_input,
                    123:        .get_input = auvitek_get_input,
                    124:        .set_input = auvitek_set_input,
                    125:        .get_frequency = auvitek_get_frequency,
                    126:        .set_frequency = auvitek_set_frequency,
                    127: };
                    128:
                    129: int
                    130: auvitek_video_attach(struct auvitek_softc *sc)
                    131: {
                    132:        snprintf(sc->sc_businfo, sizeof(sc->sc_businfo), "usb:%08x",
1.7       skrll     133:            sc->sc_udev->ud_cookie.cookie);
1.5       jmcneill  134:
                    135:        auvitek_video_rescan(sc, NULL, NULL);
1.1       jmcneill  136:
1.7.18.1! christos  137:        return sc->sc_videodev != NULL;
1.1       jmcneill  138: }
                    139:
                    140: int
                    141: auvitek_video_detach(struct auvitek_softc *sc, int flags)
                    142: {
                    143:        if (sc->sc_videodev != NULL) {
                    144:                config_detach(sc->sc_videodev, flags);
                    145:                sc->sc_videodev = NULL;
                    146:        }
                    147:
                    148:        return 0;
                    149: }
                    150:
                    151: void
1.5       jmcneill  152: auvitek_video_rescan(struct auvitek_softc *sc, const char *ifattr,
                    153:     const int *locs)
                    154: {
                    155:        if (ifattr_match(ifattr, "videobus") && sc->sc_videodev == NULL)
                    156:                sc->sc_videodev = video_attach_mi(&auvitek_video_if,
                    157:                    sc->sc_dev);
                    158: }
                    159:
                    160: void
1.1       jmcneill  161: auvitek_video_childdet(struct auvitek_softc *sc, device_t child)
                    162: {
                    163:        if (sc->sc_videodev == child)
                    164:                sc->sc_videodev = NULL;
                    165: }
                    166:
                    167: static int
                    168: auvitek_open(void *opaque, int flags)
                    169: {
                    170:        struct auvitek_softc *sc = opaque;
                    171:
                    172:        if (sc->sc_dying)
                    173:                return EIO;
                    174:
1.6       jmcneill  175:        auvitek_attach_tuner(sc->sc_dev);
1.1       jmcneill  176:
                    177:        if (sc->sc_xc5k == NULL)
                    178:                return ENXIO;
                    179:
                    180:        return 0;
                    181: }
                    182:
                    183: static void
                    184: auvitek_close(void *opaque)
                    185: {
                    186: }
                    187:
                    188: static const char *
                    189: auvitek_get_devname(void *opaque)
                    190: {
                    191:        struct auvitek_softc *sc = opaque;
                    192:
                    193:        return sc->sc_descr;
                    194: }
                    195:
                    196: static const char *
                    197: auvitek_get_businfo(void *opaque)
                    198: {
                    199:        struct auvitek_softc *sc = opaque;
                    200:
                    201:        return sc->sc_businfo;
                    202: }
                    203:
                    204: static int
                    205: auvitek_enum_format(void *opaque, uint32_t index, struct video_format *format)
                    206: {
                    207:        if (index != AUVITEK_FORMAT_DEFAULT)
                    208:                return EINVAL;
                    209:
                    210:        format->pixel_format = VIDEO_FORMAT_UYVY;
                    211:
                    212:        return 0;
                    213: }
                    214:
                    215: static int
                    216: auvitek_get_format(void *opaque, struct video_format *format)
                    217: {
                    218:
                    219:        format->pixel_format = VIDEO_FORMAT_UYVY;
                    220:        format->width = 720;
                    221:        format->height = 480;
                    222:        format->stride = format->width * 2;
                    223:        format->sample_size = format->stride * format->height;
                    224:        format->aspect_x = 4;
                    225:        format->aspect_y = 3;
                    226:        format->color.primaries = VIDEO_COLOR_PRIMARIES_SMPTE_170M;
                    227:        format->color.gamma_function = VIDEO_GAMMA_FUNCTION_UNSPECIFIED;
                    228:        format->color.matrix_coeff = VIDEO_MATRIX_COEFF_UNSPECIFIED;
                    229:        format->interlace_flags = VIDEO_INTERLACE_ON;
                    230:        format->priv = 0;
                    231:
                    232:        return 0;
                    233: }
                    234:
                    235: static int
                    236: auvitek_set_format(void *opaque, struct video_format *format)
                    237: {
                    238:        if (format->pixel_format != VIDEO_FORMAT_UYVY)
                    239:                return EINVAL;
                    240:
                    241:        return auvitek_get_format(opaque, format);
                    242: }
                    243:
                    244: static int
                    245: auvitek_try_format(void *opaque, struct video_format *format)
                    246: {
                    247:        return auvitek_get_format(opaque, format);
                    248: }
                    249:
                    250: static int
                    251: auvitek_enum_standard(void *opaque, uint32_t index, enum video_standard *vstd)
                    252: {
                    253:        switch (index) {
                    254:        case AUVITEK_STANDARD_NTSC_M:
                    255:                *vstd = VIDEO_STANDARD_NTSC_M;
                    256:                return 0;
                    257:        default:
                    258:                return EINVAL;
                    259:        }
                    260: }
                    261:
                    262: static int
                    263: auvitek_get_standard(void *opaque, enum video_standard *vstd)
                    264: {
                    265:        *vstd = VIDEO_STANDARD_NTSC_M;
                    266:        return 0;
                    267: }
                    268:
                    269: static int
                    270: auvitek_set_standard(void *opaque, enum video_standard vstd)
                    271: {
                    272:        switch (vstd) {
                    273:        case VIDEO_STANDARD_NTSC_M:
                    274:                return 0;
                    275:        default:
                    276:                return EINVAL;
                    277:        }
                    278: }
                    279:
                    280: static int
                    281: auvitek_start_transfer(void *opaque)
                    282: {
                    283:        struct auvitek_softc *sc = opaque;
                    284:        int error, s;
                    285:        uint16_t vpos = 0, hpos = 0;
                    286:        uint16_t hres = 720 * 2;
                    287:        uint16_t vres = 484 / 2;
                    288:
                    289:        auvitek_write_1(sc, AU0828_REG_SENSORVBI_CTL, 0x00);
                    290:
                    291:        /* program video position and size */
                    292:        auvitek_write_1(sc, AU0828_REG_HPOS_LO, hpos & 0xff);
                    293:        auvitek_write_1(sc, AU0828_REG_HPOS_HI, hpos >> 8);
                    294:        auvitek_write_1(sc, AU0828_REG_VPOS_LO, vpos & 0xff);
                    295:        auvitek_write_1(sc, AU0828_REG_VPOS_HI, vpos >> 8);
                    296:        auvitek_write_1(sc, AU0828_REG_HRES_LO, hres & 0xff);
                    297:        auvitek_write_1(sc, AU0828_REG_HRES_HI, hres >> 8);
                    298:        auvitek_write_1(sc, AU0828_REG_VRES_LO, vres & 0xff);
                    299:        auvitek_write_1(sc, AU0828_REG_VRES_HI, vres >> 8);
                    300:
                    301:        auvitek_write_1(sc, AU0828_REG_SENSOR_CTL, 0xb3);
                    302:
                    303:        auvitek_write_1(sc, AU0828_REG_AUDIOCTL, 0x01);
                    304:
                    305:        s = splusb();
                    306:        error = auvitek_start_xfer(sc);
                    307:        splx(s);
                    308:
                    309:        if (error)
                    310:                auvitek_stop_transfer(sc);
                    311:
                    312:        return error;
                    313: }
                    314:
                    315: static int
                    316: auvitek_stop_transfer(void *opaque)
                    317: {
                    318:        struct auvitek_softc *sc = opaque;
                    319:        int error, s;
                    320:
                    321:        auvitek_write_1(sc, AU0828_REG_SENSOR_CTL, 0x00);
                    322:
                    323:        s = splusb();
                    324:        error = auvitek_stop_xfer(sc);
                    325:        splx(s);
                    326:
                    327:        return error;
                    328: }
                    329:
                    330: static int
                    331: auvitek_get_tuner(void *opaque, struct video_tuner *vt)
                    332: {
                    333:        struct auvitek_softc *sc = opaque;
                    334:
                    335:        switch (vt->index) {
                    336:        case AUVITEK_TUNER_DEFAULT:
                    337:                strlcpy(vt->name, "XC5000", sizeof(vt->name));
                    338:                vt->freq_lo =  44000000 / 62500;
                    339:                vt->freq_hi = 958000000 / 62500;
                    340:                vt->caps = VIDEO_TUNER_F_STEREO;
                    341:                vt->mode = VIDEO_TUNER_F_STEREO;
                    342:                if (sc->sc_au8522)
                    343:                        vt->signal = au8522_get_signal(sc->sc_au8522);
                    344:                else
                    345:                        vt->signal = 0;
                    346:                break;
                    347:        default:
                    348:                return EINVAL;
                    349:        }
                    350:
                    351:        return 0;
                    352: }
                    353:
                    354: static int
                    355: auvitek_set_tuner(void *opaque, struct video_tuner *vt)
                    356: {
                    357:        if (vt->index != AUVITEK_TUNER_DEFAULT)
                    358:                return EINVAL;
                    359:        return 0;
                    360: }
                    361:
                    362: static int
                    363: auvitek_enum_audio(void *opaque, uint32_t index, struct video_audio *va)
                    364: {
                    365:        switch (index) {
                    366:        case AUVITEK_AUDIO_TELEVISION:
                    367:                strlcpy(va->name, "Television", sizeof(va->name));
                    368:                va->caps = VIDEO_AUDIO_F_STEREO;
                    369:                break;
                    370:        case AUVITEK_AUDIO_LINEIN:
                    371:                strlcpy(va->name, "Line In", sizeof(va->name));
                    372:                va->caps = VIDEO_AUDIO_F_STEREO;
                    373:                break;
                    374:        default:
                    375:                return EINVAL;
                    376:        }
                    377:
                    378:        return 0;
                    379: }
                    380:
                    381: static int
                    382: auvitek_get_audio(void *opaque, struct video_audio *va)
                    383: {
                    384:        struct auvitek_softc *sc = opaque;
                    385:
                    386:        return auvitek_enum_audio(opaque, sc->sc_ainput, va);
                    387: }
                    388:
                    389: static int
                    390: auvitek_set_audio(void *opaque, struct video_audio *va)
                    391: {
                    392:        struct auvitek_softc *sc = opaque;
                    393:
                    394:        if (va->index == sc->sc_ainput)
                    395:                return 0;
                    396:
                    397:        return EINVAL;
                    398: }
                    399:
                    400: static int
                    401: auvitek_enum_input(void *opaque, uint32_t index, struct video_input *vi)
                    402: {
                    403:        switch (index) {
                    404:        case AUVITEK_INPUT_COMPOSITE:
                    405:                strlcpy(vi->name, "Composite", sizeof(vi->name));
                    406:                vi->type = VIDEO_INPUT_TYPE_BASEBAND;
                    407:                vi->standards = VIDEO_STANDARD_NTSC_M;
                    408:                break;
                    409:        case AUVITEK_INPUT_SVIDEO:
                    410:                strlcpy(vi->name, "S-Video", sizeof(vi->name));
                    411:                vi->type = VIDEO_INPUT_TYPE_BASEBAND;
                    412:                vi->standards = VIDEO_STANDARD_NTSC_M;
                    413:                break;
                    414:        case AUVITEK_INPUT_TELEVISION:
                    415:                strlcpy(vi->name, "Television", sizeof(vi->name));
                    416:                vi->type = VIDEO_INPUT_TYPE_TUNER;
                    417:                vi->standards = VIDEO_STANDARD_NTSC_M;
                    418:                break;
                    419:        case AUVITEK_INPUT_CABLE:
                    420:                strlcpy(vi->name, "Cable TV", sizeof(vi->name));
                    421:                vi->type = VIDEO_INPUT_TYPE_TUNER;
                    422:                vi->standards = VIDEO_STANDARD_NTSC_M;
                    423:                break;
                    424:        default:
                    425:                return EINVAL;
                    426:        }
                    427:
                    428:        vi->index = index;
                    429:        vi->tuner_index = AUVITEK_TUNER_DEFAULT;
                    430:
                    431:        return 0;
                    432: }
                    433:
                    434: static int
                    435: auvitek_get_input(void *opaque, struct video_input *vi)
                    436: {
                    437:        struct auvitek_softc *sc = opaque;
                    438:
                    439:        return auvitek_enum_input(opaque, sc->sc_vinput, vi);
                    440: }
                    441:
                    442: static int
                    443: auvitek_set_input(void *opaque, struct video_input *vi)
                    444: {
                    445:        struct auvitek_softc *sc = opaque;
                    446:        struct video_frequency vf;
                    447:        au8522_vinput_t vinput = AU8522_VINPUT_UNCONF;
                    448:        au8522_ainput_t ainput = AU8522_AINPUT_UNCONF;
                    449:        uint8_t r;
                    450:
                    451:        switch (vi->index) {
                    452:        case AUVITEK_INPUT_COMPOSITE:
                    453:                vinput = AU8522_VINPUT_CVBS;
                    454:                ainput = AU8522_AINPUT_NONE;
                    455:                sc->sc_ainput = AUVITEK_AUDIO_LINEIN;
                    456:                break;
                    457:        case AUVITEK_INPUT_SVIDEO:
                    458:                vinput = AU8522_VINPUT_SVIDEO;
                    459:                ainput = AU8522_AINPUT_NONE;
                    460:                sc->sc_ainput = AUVITEK_AUDIO_LINEIN;
                    461:                break;
                    462:        case AUVITEK_INPUT_TELEVISION:
                    463:        case AUVITEK_INPUT_CABLE:
                    464:                vinput = AU8522_VINPUT_CVBS_TUNER;
                    465:                ainput = AU8522_AINPUT_SIF;
                    466:                sc->sc_ainput = AUVITEK_AUDIO_TELEVISION;
                    467:                break;
                    468:        default:
                    469:                return EINVAL;
                    470:        }
                    471:
                    472:        sc->sc_vinput = vi->index;
                    473:
                    474:        au8522_set_input(sc->sc_au8522, vinput, ainput);
                    475:
1.2       jmcneill  476:        /* XXX HVR-850/950Q specific */
1.1       jmcneill  477:        r = auvitek_read_1(sc, AU0828_REG_GPIO1_OUTEN);
                    478:        if (ainput == AU8522_AINPUT_NONE)
                    479:                r |= 0x10;
                    480:        else
                    481:                r &= ~0x10;
                    482:        auvitek_write_1(sc, AU0828_REG_GPIO1_OUTEN, r);
                    483:
                    484:        if (vinput == AU8522_VINPUT_CVBS_TUNER && sc->sc_curfreq > 0) {
                    485:                vf.tuner_index = AUVITEK_TUNER_DEFAULT;
                    486:                vf.frequency = sc->sc_curfreq;
                    487:                auvitek_set_frequency(sc, &vf);
                    488:        }
                    489:
                    490:        return 0;
                    491: }
                    492:
                    493: static int
                    494: auvitek_get_frequency(void *opaque, struct video_frequency *vf)
                    495: {
                    496:        struct auvitek_softc *sc = opaque;
                    497:
                    498:        if (sc->sc_vinput != AUVITEK_INPUT_TELEVISION &&
                    499:            sc->sc_vinput != AUVITEK_INPUT_CABLE)
                    500:                return EINVAL;
                    501:
                    502:        vf->tuner_index = AUVITEK_TUNER_DEFAULT;
                    503:        vf->frequency = sc->sc_curfreq;
                    504:
                    505:        return 0;
                    506: }
                    507:
                    508: static int
                    509: auvitek_set_frequency(void *opaque, struct video_frequency *vf)
                    510: {
                    511:        struct auvitek_softc *sc = opaque;
                    512:        struct xc5k_params params;
                    513:        int error;
                    514:
                    515:        if (sc->sc_vinput != AUVITEK_INPUT_TELEVISION &&
                    516:            sc->sc_vinput != AUVITEK_INPUT_CABLE)
                    517:                return EINVAL;
                    518:        if (vf->tuner_index != AUVITEK_TUNER_DEFAULT)
                    519:                return EINVAL;
                    520:        if (sc->sc_xc5k == NULL)
                    521:                return ENODEV;
                    522:
                    523:        params.standard = VIDEO_STANDARD_NTSC_M;
                    524:        if (sc->sc_vinput == AUVITEK_INPUT_TELEVISION)
                    525:                params.signal_source = XC5K_SIGNAL_SOURCE_AIR;
                    526:        else
                    527:                params.signal_source = XC5K_SIGNAL_SOURCE_CABLE;
                    528:        params.frequency = vf->frequency;
1.3       jmcneill  529:        if (sc->sc_au8522)
                    530:                au8522_set_audio(sc->sc_au8522, false);
1.4       jmcneill  531:        error = xc5k_tune_video(sc->sc_xc5k, &params);
1.3       jmcneill  532:        if (sc->sc_au8522)
                    533:                au8522_set_audio(sc->sc_au8522, true);
1.1       jmcneill  534:        if (error)
                    535:                return error;
                    536:
                    537:        sc->sc_curfreq = vf->frequency;
                    538:
                    539:        auvitek_write_1(sc, AU0828_REG_SENSOR_CTL, 0x00);
                    540:        delay(30000);
                    541:        auvitek_write_1(sc, AU0828_REG_SENSOR_CTL, 0xb3);
                    542:
                    543:        return 0;
                    544: }
                    545:
                    546: static int
                    547: auvitek_start_xfer(struct auvitek_softc *sc)
                    548: {
                    549:        struct auvitek_xfer *ax = &sc->sc_ax;
                    550:        uint32_t vframe_len, uframe_len, nframes;
                    551:        usbd_status err;
                    552:        int i;
                    553:
1.4       jmcneill  554:        err = usbd_set_interface(sc->sc_isoc_iface, AUVITEK_XFER_ALTNO);
1.1       jmcneill  555:        if (err != USBD_NORMAL_COMPLETION) {
                    556:                aprint_error_dev(sc->sc_dev, "couldn't set altno %d: %s\n",
                    557:                    AUVITEK_XFER_ALTNO, usbd_errstr(err));
                    558:                return EIO;
                    559:        }
                    560:
                    561:        vframe_len = 720 * 480 * 2;
                    562:        uframe_len = ax->ax_maxpktlen;
                    563:        nframes = (vframe_len + uframe_len - 1) / uframe_len;
                    564:        nframes = (nframes + 7) & ~7;
                    565:
                    566:        ax->ax_nframes = nframes;
                    567:        ax->ax_uframe_len = uframe_len;
1.4       jmcneill  568:        for (i = 0; i < AUVITEK_NISOC_XFERS; i++) {
1.1       jmcneill  569:                struct auvitek_isoc *isoc = &ax->ax_i[i];
                    570:                isoc->i_ax = ax;
                    571:                isoc->i_frlengths =
                    572:                    kmem_alloc(sizeof(isoc->i_frlengths[0]) * nframes,
                    573:                        KM_SLEEP);
                    574:        }
                    575:
1.4       jmcneill  576:        err = usbd_open_pipe(sc->sc_isoc_iface, ax->ax_endpt,
1.1       jmcneill  577:            USBD_EXCLUSIVE_USE, &ax->ax_pipe);
                    578:        if (err != USBD_NORMAL_COMPLETION) {
                    579:                aprint_error_dev(sc->sc_dev, "couldn't open pipe: %s\n",
                    580:                    usbd_errstr(err));
                    581:                return EIO;
                    582:        }
                    583:
1.4       jmcneill  584:        for (i = 0; i < AUVITEK_NISOC_XFERS; i++) {
1.1       jmcneill  585:                struct auvitek_isoc *isoc = &ax->ax_i[i];
                    586:
1.7       skrll     587:                int error = usbd_create_xfer(ax->ax_pipe,
                    588:                    nframes * uframe_len, 0, ax->ax_nframes, &isoc->i_xfer);
                    589:                if (error) {
1.1       jmcneill  590:                        aprint_error_dev(sc->sc_dev,
1.7       skrll     591:                            "couldn't create usb xfer\n");
                    592:                        return error;
1.1       jmcneill  593:                }
                    594:
1.7       skrll     595:                isoc->i_buf = usbd_get_buffer(isoc->i_xfer);
1.1       jmcneill  596:        }
                    597:
                    598:        return auvitek_isoc_start(sc);
                    599: }
                    600:
                    601: static int
                    602: auvitek_stop_xfer(struct auvitek_softc *sc)
                    603: {
                    604:        struct auvitek_xfer *ax = &sc->sc_ax;
                    605:        usbd_status err;
                    606:        int i;
                    607:
                    608:        if (ax->ax_pipe != NULL) {
                    609:                usbd_abort_pipe(ax->ax_pipe);
                    610:        }
1.4       jmcneill  611:        for (i = 0; i < AUVITEK_NISOC_XFERS; i++) {
1.1       jmcneill  612:                struct auvitek_isoc *isoc = &ax->ax_i[i];
                    613:                if (isoc->i_xfer != NULL) {
1.7       skrll     614:                        usbd_destroy_xfer(isoc->i_xfer);
1.1       jmcneill  615:                        isoc->i_xfer = NULL;
                    616:                }
                    617:                if (isoc->i_frlengths != NULL) {
                    618:                        kmem_free(isoc->i_frlengths,
                    619:                            sizeof(isoc->i_frlengths[0]) * ax->ax_nframes);
                    620:                        isoc->i_frlengths = NULL;
                    621:                }
                    622:        }
1.7       skrll     623:        if (ax->ax_pipe != NULL) {
                    624:                usbd_close_pipe(ax->ax_pipe);
                    625:                ax->ax_pipe = NULL;
                    626:        }
1.1       jmcneill  627:
                    628:        usbd_delay_ms(sc->sc_udev, 1000);
1.4       jmcneill  629:        err = usbd_set_interface(sc->sc_isoc_iface, 0);
1.1       jmcneill  630:        if (err != USBD_NORMAL_COMPLETION) {
                    631:                aprint_error_dev(sc->sc_dev,
                    632:                    "couldn't set zero bw interface: %s\n",
                    633:                    usbd_errstr(err));
                    634:                return EIO;
                    635:        }
                    636:
                    637:        return 0;
                    638: }
                    639:
                    640: static int
                    641: auvitek_isoc_start(struct auvitek_softc *sc)
                    642: {
                    643:        struct auvitek_xfer *ax = &sc->sc_ax;
                    644:        int i, error;
                    645:
                    646:        ax->ax_av.av_el = ax->ax_av.av_ol = 0;
                    647:        ax->ax_av.av_eb = ax->ax_av.av_ob = 0;
                    648:        ax->ax_av.av_stride = 720 * 2;
                    649:
1.4       jmcneill  650:        for (i = 0; i < AUVITEK_NISOC_XFERS; i++) {
1.1       jmcneill  651:                error = auvitek_isoc_start1(&ax->ax_i[i]);
                    652:                if (error)
                    653:                        return error;
                    654:        }
                    655:
                    656:        return 0;
                    657: }
                    658:
                    659: static int
                    660: auvitek_isoc_start1(struct auvitek_isoc *isoc)
                    661: {
                    662:        struct auvitek_xfer *ax = isoc->i_ax;
                    663:        struct auvitek_softc *sc = ax->ax_sc;
                    664:        usbd_status err;
                    665:        unsigned int i;
                    666:
                    667:        ax = isoc->i_ax;
                    668:
                    669:        for (i = 0; i < ax->ax_nframes; i++)
                    670:                isoc->i_frlengths[i] = ax->ax_uframe_len;
                    671:
                    672:        usbd_setup_isoc_xfer(isoc->i_xfer,
                    673:                             isoc,
                    674:                             isoc->i_frlengths,
                    675:                             ax->ax_nframes,
1.7       skrll     676:                             USBD_SHORT_XFER_OK,
1.1       jmcneill  677:                             auvitek_isoc_intr);
                    678:
                    679:        err = usbd_transfer(isoc->i_xfer);
                    680:        if (err != USBD_IN_PROGRESS) {
                    681:                aprint_error_dev(sc->sc_dev, "couldn't start isoc xfer: %s\n",
                    682:                                 usbd_errstr(err));
                    683:                return ENODEV;
                    684:        }
                    685:
                    686:        return 0;
                    687: }
                    688:
                    689: static void
1.7       skrll     690: auvitek_isoc_intr(struct usbd_xfer *xfer, void * priv,
1.1       jmcneill  691:     usbd_status status)
                    692: {
                    693:        struct auvitek_isoc *isoc = priv;
                    694:        struct auvitek_xfer *ax = isoc->i_ax;
                    695:        struct auvitek_softc *sc = ax->ax_sc;
                    696:        uint32_t count;
                    697:        uint8_t *buf;
                    698:        unsigned int i;
                    699:
                    700:        if (sc->sc_dying)
                    701:                return;
                    702:
                    703:        if (status != USBD_NORMAL_COMPLETION) {
                    704:                if (status == USBD_STALLED) {
                    705:                        usbd_clear_endpoint_stall_async(ax->ax_pipe);
                    706:                        goto next;
                    707:                }
                    708:                return;
                    709:        }
                    710:
                    711:        usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
                    712:
                    713:        if (count == 0)
                    714:                goto next;
                    715:
                    716:        for (i = 0, buf = isoc->i_buf;
                    717:             i < ax->ax_nframes;
                    718:             ++i, buf += ax->ax_uframe_len) {
                    719:                status = auvitek_isoc_process(sc, buf, isoc->i_frlengths[i]);
                    720:                if (status == USBD_IOERROR)
                    721:                        break;
                    722:        }
                    723:
                    724: next:
                    725:        auvitek_isoc_start1(isoc);
                    726: }
                    727:
                    728: static int
                    729: auvitek_isoc_process(struct auvitek_softc *sc, uint8_t *buf, uint32_t len)
                    730: {
                    731:        struct video_payload payload;
                    732:        bool submit = false;
                    733:
                    734:        if (buf[0] & 0x80) {
                    735:                sc->sc_ax.ax_frinfo = buf[0];
                    736:                if (sc->sc_ax.ax_frinfo & 0x40) {
                    737:                        sc->sc_ax.ax_frno = !sc->sc_ax.ax_frno;
                    738:                        submit = true;
                    739:                }
                    740:                buf += 4;
                    741:                len -= 4;
                    742:        }
                    743:        buf += 4;
                    744:        len -= 4;
                    745:
                    746:        auvitek_videobuf_weave(sc, buf, len);
                    747:
                    748:        if (submit) {
                    749:                payload.end_of_frame = 1;
                    750:                payload.data = sc->sc_ax.ax_av.av_buf;
                    751:                payload.size = sizeof(sc->sc_ax.ax_av.av_buf);
                    752:                payload.frameno = -1;
                    753:
                    754:                video_submit_payload(sc->sc_videodev, &payload);
                    755:
                    756:                sc->sc_ax.ax_av.av_el = sc->sc_ax.ax_av.av_ol = 0;
                    757:                sc->sc_ax.ax_av.av_eb = sc->sc_ax.ax_av.av_ob = 0;
                    758:        }
                    759:
                    760:        return USBD_NORMAL_COMPLETION;
                    761: }
                    762:
                    763: static void
                    764: auvitek_videobuf_weave(struct auvitek_softc *sc, uint8_t *buf, uint32_t len)
                    765: {
                    766:        struct auvitek_videobuf *av = &sc->sc_ax.ax_av;
                    767:        uint32_t resid, wlen;
                    768:        uint32_t *l, *b;
                    769:        uint8_t *vp;
                    770:
                    771:        if (sc->sc_ax.ax_frinfo & 0x40) {
                    772:                l = &av->av_ol;
                    773:                b = &av->av_ob;
                    774:                vp = av->av_buf;
                    775:        } else {
                    776:                l = &av->av_el;
                    777:                b = &av->av_eb;
                    778:                vp = av->av_buf + av->av_stride;
                    779:        }
                    780:
                    781:        resid = len;
                    782:        while (resid > 0) {
                    783:                if (*b == av->av_stride) {
                    784:                        *l = *l + 1;
                    785:                        *b = 0;
                    786:                }
                    787:                if (*l >= 240) {
                    788:                        break;
                    789:                }
1.7.18.1! christos  790:                wlen = uimin(resid, av->av_stride - *b);
1.1       jmcneill  791:                memcpy(vp + (av->av_stride * 2 * *l) + *b, buf, wlen);
                    792:                *b += wlen;
                    793:                buf += wlen;
                    794:                resid -= wlen;
                    795:        }
                    796: }

CVSweb <webmaster@jp.NetBSD.org>