1 /* $NetBSD: auvitek_video.c,v 1.7 2016/04/23 10:15:31 skrll 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.7 2016/04/23 10:15:31 skrll 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(struct usbd_xfer *, void *, 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 103 static const struct video_hw_if auvitek_video_if = { 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", 133 sc->sc_udev->ud_cookie.cookie); 134 135 auvitek_video_rescan(sc, NULL, NULL); 136 137 return (sc->sc_videodev != NULL); 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 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 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 175 auvitek_attach_tuner(sc->sc_dev); 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 476 /* XXX HVR-850/950Q specific */ 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; 529 if (sc->sc_au8522) 530 au8522_set_audio(sc->sc_au8522, false); 531 error = xc5k_tune_video(sc->sc_xc5k, ¶ms); 532 if (sc->sc_au8522) 533 au8522_set_audio(sc->sc_au8522, true); 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 554 err = usbd_set_interface(sc->sc_isoc_iface, AUVITEK_XFER_ALTNO); 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; 568 for (i = 0; i < AUVITEK_NISOC_XFERS; i++) { 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 576 err = usbd_open_pipe(sc->sc_isoc_iface, ax->ax_endpt, 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 584 for (i = 0; i < AUVITEK_NISOC_XFERS; i++) { 585 struct auvitek_isoc *isoc = &ax->ax_i[i]; 586 587 int error = usbd_create_xfer(ax->ax_pipe, 588 nframes * uframe_len, 0, ax->ax_nframes, &isoc->i_xfer); 589 if (error) { 590 aprint_error_dev(sc->sc_dev, 591 "couldn't create usb xfer\n"); 592 return error; 593 } 594 595 isoc->i_buf = usbd_get_buffer(isoc->i_xfer); 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 } 611 for (i = 0; i < AUVITEK_NISOC_XFERS; i++) { 612 struct auvitek_isoc *isoc = &ax->ax_i[i]; 613 if (isoc->i_xfer != NULL) { 614 usbd_destroy_xfer(isoc->i_xfer); 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 } 623 if (ax->ax_pipe != NULL) { 624 usbd_close_pipe(ax->ax_pipe); 625 ax->ax_pipe = NULL; 626 } 627 628 usbd_delay_ms(sc->sc_udev, 1000); 629 err = usbd_set_interface(sc->sc_isoc_iface, 0); 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 650 for (i = 0; i < AUVITEK_NISOC_XFERS; i++) { 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, 676 USBD_SHORT_XFER_OK, 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 690 auvitek_isoc_intr(struct usbd_xfer *xfer, void * priv, 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 } 790 wlen = min(resid, av->av_stride - *b); 791 memcpy(vp + (av->av_stride * 2 * *l) + *b, buf, wlen); 792 *b += wlen; 793 buf += wlen; 794 resid -= wlen; 795 } 796 } 797