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