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