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, ¶ms);
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>