Line data Source code
1 : /* $OpenBSD: utvfu.c,v 1.9 2016/09/19 06:46:44 ratchov Exp $ */
2 : /*
3 : * Copyright (c) 2013 Lubomir Rintel
4 : * Copyright (c) 2013 Federico Simoncelli
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 : * without modification.
13 : * 2. The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 : *
16 : * Alternatively, this software may be distributed under the terms of the
17 : * GNU General Public License ("GPL").
18 : *
19 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 : */
31 : /*
32 : * Fushicai USBTV007 Audio-Video Grabber Driver
33 : *
34 : * Product web site:
35 : * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
36 : *
37 : * Following LWN articles were very useful in construction of this driver:
38 : * Video4Linux2 API series: http://lwn.net/Articles/203924/
39 : * videobuf2 API explanation: http://lwn.net/Articles/447435/
40 : * Thanks go to Jonathan Corbet for providing this quality documentation.
41 : * He is awesome.
42 : *
43 : * No physical hardware was harmed running Windows during the
44 : * reverse-engineering activity
45 : */
46 :
47 : #include <sys/param.h>
48 : #include <sys/systm.h>
49 : #include <sys/fcntl.h>
50 : #include <sys/kernel.h>
51 : #include <sys/kthread.h>
52 : #include <sys/malloc.h>
53 : #include <sys/device.h>
54 : #include <sys/audioio.h>
55 : #include <sys/videoio.h>
56 :
57 : #include <uvm/uvm_extern.h>
58 :
59 : #include <machine/bus.h>
60 :
61 : #include <dev/audio_if.h>
62 : #include <dev/usb/usb.h>
63 : #include <dev/usb/usbdi.h>
64 : #include <dev/usb/usbdivar.h>
65 : #include <dev/usb/usb_mem.h>
66 : #include <dev/usb/usbdi_util.h>
67 : #include <dev/usb/usbdevs.h>
68 : #include <dev/video_if.h>
69 :
70 : #include "utvfu.h"
71 :
72 : #ifdef UTVFU_DEBUG
73 : int utvfu_debug = 1;
74 : #define DPRINTF(l, x...) do { if ((l) <= utvfu_debug) printf(x); } while (0)
75 : #else
76 : #define DPRINTF(l, x...)
77 : #endif
78 :
79 : #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
80 :
81 : struct utvfu_norm_params utvfu_norm_params[] = {
82 : {
83 : .norm = V4L2_STD_525_60,
84 : .cap_width = 720,
85 : .cap_height = 480,
86 : /* 4 bytes/2 pixel YUYV/YUV 4:2:2 */
87 : .frame_len = (720 * 480 * 2),
88 : },
89 : {
90 : .norm = V4L2_STD_PAL,
91 : .cap_width = 720,
92 : .cap_height = 576,
93 : /* 4 bytes/2 pixel YUYV/YUV 4:2:2 */
94 : .frame_len = (720 * 576 * 2),
95 : }
96 : };
97 :
98 : int
99 0 : utvfu_set_regs(struct utvfu_softc *sc, const uint16_t regs[][2], int size)
100 : {
101 : int i;
102 : usbd_status error;
103 0 : usb_device_request_t req;
104 :
105 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
106 0 : req.bRequest = UTVFU_REQUEST_REG;
107 0 : USETW(req.wLength, 0);
108 :
109 0 : for (i = 0; i < size; i++) {
110 0 : USETW(req.wIndex, regs[i][0]);
111 0 : USETW(req.wValue, regs[i][1]);
112 :
113 0 : error = usbd_do_request(sc->sc_udev, &req, NULL);
114 0 : if (error != USBD_NORMAL_COMPLETION) {
115 : DPRINTF(1, "%s: %s: exit EINVAL\n",
116 : DEVNAME(sc), __func__);
117 0 : return (EINVAL);
118 : }
119 : }
120 :
121 0 : return (0);
122 0 : }
123 :
124 : int
125 0 : utvfu_max_frame_size(void)
126 : {
127 : int i, sz = 0;
128 0 : for (i = 0; i < nitems(utvfu_norm_params); i++) {
129 0 : if (sz < utvfu_norm_params[i].frame_len)
130 0 : sz = utvfu_norm_params[i].frame_len;
131 : }
132 0 : return (sz);
133 : }
134 :
135 : int
136 0 : utvfu_configure_for_norm(struct utvfu_softc *sc, v4l2_std_id norm)
137 : {
138 : int i, ret = EINVAL;
139 : struct utvfu_norm_params *params = NULL;
140 :
141 0 : for (i = 0; i < nitems(utvfu_norm_params); i++) {
142 0 : if (utvfu_norm_params[i].norm & norm) {
143 : params = &utvfu_norm_params[i];
144 0 : break;
145 : }
146 : }
147 :
148 0 : if (params != NULL) {
149 0 : sc->sc_normi = i;
150 0 : sc->sc_nchunks = params->cap_width * params->cap_height
151 0 : / 4 / UTVFU_CHUNK;
152 : ret = 0;
153 0 : }
154 :
155 0 : return (ret);
156 : }
157 :
158 : int
159 0 : utvfu_select_input(struct utvfu_softc *sc, int input)
160 : {
161 : int ret;
162 :
163 : static const uint16_t composite[][2] = {
164 : { UTVFU_BASE + 0x0105, 0x0060 },
165 : { UTVFU_BASE + 0x011f, 0x00f2 },
166 : { UTVFU_BASE + 0x0127, 0x0060 },
167 : { UTVFU_BASE + 0x00ae, 0x0010 },
168 : { UTVFU_BASE + 0x0239, 0x0060 },
169 : };
170 :
171 : static const uint16_t svideo[][2] = {
172 : { UTVFU_BASE + 0x0105, 0x0010 },
173 : { UTVFU_BASE + 0x011f, 0x00ff },
174 : { UTVFU_BASE + 0x0127, 0x0060 },
175 : { UTVFU_BASE + 0x00ae, 0x0030 },
176 : { UTVFU_BASE + 0x0239, 0x0060 },
177 : };
178 :
179 0 : switch (input) {
180 : case UTVFU_COMPOSITE_INPUT:
181 0 : ret = utvfu_set_regs(sc, composite, nitems(composite));
182 0 : break;
183 : case UTVFU_SVIDEO_INPUT:
184 0 : ret = utvfu_set_regs(sc, svideo, nitems(svideo));
185 0 : break;
186 : default:
187 : ret = EINVAL;
188 0 : }
189 :
190 0 : if (ret == 0)
191 0 : sc->sc_input = input;
192 :
193 0 : return (ret);
194 : }
195 :
196 : int
197 0 : utvfu_select_norm(struct utvfu_softc *sc, v4l2_std_id norm)
198 : {
199 : int ret;
200 : static const uint16_t pal[][2] = {
201 : { UTVFU_BASE + 0x001a, 0x0068 },
202 : { UTVFU_BASE + 0x010e, 0x0072 },
203 : { UTVFU_BASE + 0x010f, 0x00a2 },
204 : { UTVFU_BASE + 0x0112, 0x00b0 },
205 : { UTVFU_BASE + 0x0117, 0x0001 },
206 : { UTVFU_BASE + 0x0118, 0x002c },
207 : { UTVFU_BASE + 0x012d, 0x0010 },
208 : { UTVFU_BASE + 0x012f, 0x0020 },
209 : { UTVFU_BASE + 0x024f, 0x0002 },
210 : { UTVFU_BASE + 0x0254, 0x0059 },
211 : { UTVFU_BASE + 0x025a, 0x0016 },
212 : { UTVFU_BASE + 0x025b, 0x0035 },
213 : { UTVFU_BASE + 0x0263, 0x0017 },
214 : { UTVFU_BASE + 0x0266, 0x0016 },
215 : { UTVFU_BASE + 0x0267, 0x0036 }
216 : };
217 :
218 : static const uint16_t ntsc[][2] = {
219 : { UTVFU_BASE + 0x001a, 0x0079 },
220 : { UTVFU_BASE + 0x010e, 0x0068 },
221 : { UTVFU_BASE + 0x010f, 0x009c },
222 : { UTVFU_BASE + 0x0112, 0x00f0 },
223 : { UTVFU_BASE + 0x0117, 0x0000 },
224 : { UTVFU_BASE + 0x0118, 0x00fc },
225 : { UTVFU_BASE + 0x012d, 0x0004 },
226 : { UTVFU_BASE + 0x012f, 0x0008 },
227 : { UTVFU_BASE + 0x024f, 0x0001 },
228 : { UTVFU_BASE + 0x0254, 0x005f },
229 : { UTVFU_BASE + 0x025a, 0x0012 },
230 : { UTVFU_BASE + 0x025b, 0x0001 },
231 : { UTVFU_BASE + 0x0263, 0x001c },
232 : { UTVFU_BASE + 0x0266, 0x0011 },
233 : { UTVFU_BASE + 0x0267, 0x0005 }
234 : };
235 :
236 0 : ret = utvfu_configure_for_norm(sc, norm);
237 :
238 0 : if (ret == 0) {
239 0 : if (norm & V4L2_STD_525_60)
240 0 : ret = utvfu_set_regs(sc, ntsc, nitems(ntsc));
241 0 : else if (norm & V4L2_STD_PAL)
242 0 : ret = utvfu_set_regs(sc, pal, nitems(pal));
243 : }
244 :
245 0 : return (ret);
246 : }
247 :
248 : int
249 0 : utvfu_setup_capture(struct utvfu_softc *sc)
250 : {
251 : int ret;
252 : static const uint16_t setup[][2] = {
253 : /* These seem to enable the device. */
254 : { UTVFU_BASE + 0x0008, 0x0001 },
255 : { UTVFU_BASE + 0x01d0, 0x00ff },
256 : { UTVFU_BASE + 0x01d9, 0x0002 },
257 :
258 : /*
259 : * These seem to influence color parameters, such as
260 : * brightness, etc.
261 : */
262 : { UTVFU_BASE + 0x0239, 0x0040 },
263 : { UTVFU_BASE + 0x0240, 0x0000 },
264 : { UTVFU_BASE + 0x0241, 0x0000 },
265 : { UTVFU_BASE + 0x0242, 0x0002 },
266 : { UTVFU_BASE + 0x0243, 0x0080 },
267 : { UTVFU_BASE + 0x0244, 0x0012 },
268 : { UTVFU_BASE + 0x0245, 0x0090 },
269 : { UTVFU_BASE + 0x0246, 0x0000 },
270 :
271 : { UTVFU_BASE + 0x0278, 0x002d },
272 : { UTVFU_BASE + 0x0279, 0x000a },
273 : { UTVFU_BASE + 0x027a, 0x0032 },
274 : { 0xf890, 0x000c },
275 : { 0xf894, 0x0086 },
276 :
277 : { UTVFU_BASE + 0x00ac, 0x00c0 },
278 : { UTVFU_BASE + 0x00ad, 0x0000 },
279 : { UTVFU_BASE + 0x00a2, 0x0012 },
280 : { UTVFU_BASE + 0x00a3, 0x00e0 },
281 : { UTVFU_BASE + 0x00a4, 0x0028 },
282 : { UTVFU_BASE + 0x00a5, 0x0082 },
283 : { UTVFU_BASE + 0x00a7, 0x0080 },
284 : { UTVFU_BASE + 0x0000, 0x0014 },
285 : { UTVFU_BASE + 0x0006, 0x0003 },
286 : { UTVFU_BASE + 0x0090, 0x0099 },
287 : { UTVFU_BASE + 0x0091, 0x0090 },
288 : { UTVFU_BASE + 0x0094, 0x0068 },
289 : { UTVFU_BASE + 0x0095, 0x0070 },
290 : { UTVFU_BASE + 0x009c, 0x0030 },
291 : { UTVFU_BASE + 0x009d, 0x00c0 },
292 : { UTVFU_BASE + 0x009e, 0x00e0 },
293 : { UTVFU_BASE + 0x0019, 0x0006 },
294 : { UTVFU_BASE + 0x008c, 0x00ba },
295 : { UTVFU_BASE + 0x0101, 0x00ff },
296 : { UTVFU_BASE + 0x010c, 0x00b3 },
297 : { UTVFU_BASE + 0x01b2, 0x0080 },
298 : { UTVFU_BASE + 0x01b4, 0x00a0 },
299 : { UTVFU_BASE + 0x014c, 0x00ff },
300 : { UTVFU_BASE + 0x014d, 0x00ca },
301 : { UTVFU_BASE + 0x0113, 0x0053 },
302 : { UTVFU_BASE + 0x0119, 0x008a },
303 : { UTVFU_BASE + 0x013c, 0x0003 },
304 : { UTVFU_BASE + 0x0150, 0x009c },
305 : { UTVFU_BASE + 0x0151, 0x0071 },
306 : { UTVFU_BASE + 0x0152, 0x00c6 },
307 : { UTVFU_BASE + 0x0153, 0x0084 },
308 : { UTVFU_BASE + 0x0154, 0x00bc },
309 : { UTVFU_BASE + 0x0155, 0x00a0 },
310 : { UTVFU_BASE + 0x0156, 0x00a0 },
311 : { UTVFU_BASE + 0x0157, 0x009c },
312 : { UTVFU_BASE + 0x0158, 0x001f },
313 : { UTVFU_BASE + 0x0159, 0x0006 },
314 : { UTVFU_BASE + 0x015d, 0x0000 },
315 :
316 : { UTVFU_BASE + 0x0003, 0x0004 },
317 : { UTVFU_BASE + 0x0100, 0x00d3 },
318 : { UTVFU_BASE + 0x0115, 0x0015 },
319 : { UTVFU_BASE + 0x0220, 0x002e },
320 : { UTVFU_BASE + 0x0225, 0x0008 },
321 : { UTVFU_BASE + 0x024e, 0x0002 },
322 : { UTVFU_BASE + 0x024e, 0x0002 },
323 : { UTVFU_BASE + 0x024f, 0x0002 },
324 : };
325 :
326 0 : ret = utvfu_set_regs(sc, setup, nitems(setup));
327 0 : if (ret)
328 0 : return (ret);
329 :
330 0 : ret = utvfu_select_norm(sc, utvfu_norm_params[sc->sc_normi].norm);
331 0 : if (ret)
332 0 : return (ret);
333 :
334 0 : ret = utvfu_select_input(sc, sc->sc_input);
335 0 : if (ret)
336 0 : return (ret);
337 :
338 0 : return (0);
339 0 : }
340 :
341 : /*
342 : * Copy data from chunk into a frame buffer, deinterlacing the data
343 : * into every second line. Unfortunately, they don't align nicely into
344 : * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels.
345 : * Therefore, we break down the chunk into two halves before copying,
346 : * so that we can interleave a line if needed.
347 : *
348 : * Each "chunk" is 240 words; a word in this context equals 4 bytes.
349 : * Image format is YUYV/YUV 4:2:2, consisting of Y Cr Y Cb, defining two
350 : * pixels, the Cr and Cb shared between the two pixels, but each having
351 : * separate Y values. Thus, the 240 words equal 480 pixels. It therefore,
352 : * takes 1.5 chunks to make a 720 pixel-wide line for the frame.
353 : * The image is interlaced, so there is a "scan" of odd lines, followed
354 : * by "scan" of even numbered lines.
355 : *
356 : * Following code is writing the chunks in correct sequence, skipping
357 : * the rows based on "odd" value.
358 : * line 1: chunk[0][ 0..479] chunk[0][480..959] chunk[1][ 0..479]
359 : * line 3: chunk[1][480..959] chunk[2][ 0..479] chunk[2][480..959]
360 : * ...etc
361 : */
362 : void
363 0 : utvfu_chunk_to_vbuf(uint8_t *frame, uint8_t *src, int chunk_no, int odd)
364 : {
365 : uint8_t *dst;
366 : int half, line, part_no, part_index;
367 : #define UTVFU_STRIDE (UTVFU_CHUNK/2 * 4)
368 :
369 0 : for (half = 0; half < 2; half++) {
370 0 : part_no = chunk_no * 2 + half;
371 0 : line = part_no / 3;
372 0 : part_index = (line * 2 + !odd) * 3 + (part_no % 3);
373 :
374 0 : dst = &frame[part_index * UTVFU_STRIDE];
375 :
376 0 : memcpy(dst, src, UTVFU_STRIDE);
377 0 : src += UTVFU_STRIDE;
378 : }
379 : #undef UTVFU_STRIDE
380 0 : }
381 :
382 : /*
383 : * Called for each 256-byte image chunk.
384 : * First word identifies the chunk, followed by 240 words of image
385 : * data and padding.
386 : */
387 : void
388 0 : utvfu_image_chunk(struct utvfu_softc *sc, u_char *chunk)
389 : {
390 : int frame_id, odd, chunk_no, frame_len;
391 : uint32_t hdr;
392 :
393 0 : memcpy(&hdr, chunk, sizeof(hdr));
394 0 : chunk += sizeof(hdr);
395 0 : hdr = be32toh(hdr);
396 :
397 : /* Ignore corrupted lines. */
398 0 : if (!UTVFU_MAGIC_OK(hdr)) {
399 : DPRINTF(2, "%s: bad magic=0x%08x\n",
400 : DEVNAME(sc), UTVFU_MAGIC(hdr));
401 0 : return;
402 : }
403 :
404 0 : frame_id = UTVFU_FRAME_ID(hdr);
405 0 : odd = UTVFU_ODD(hdr);
406 0 : chunk_no = UTVFU_CHUNK_NO(hdr);
407 0 : if (chunk_no >= sc->sc_nchunks) {
408 : DPRINTF(2, "%s: chunk_no=%d >= sc_nchunks=%d\n",
409 : DEVNAME(sc), chunk_no, sc->sc_nchunks);
410 0 : return;
411 : }
412 :
413 : /* Beginning of a frame. */
414 0 : if (chunk_no == 0) {
415 0 : sc->sc_fb.fid = frame_id;
416 0 : sc->sc_fb.chunks_done = 0;
417 0 : }
418 0 : else if (sc->sc_fb.fid != frame_id) {
419 : DPRINTF(2, "%s: frame id mismatch expecting=%d got=%d\n",
420 : DEVNAME(sc), sc->sc_fb.fid, frame_id);
421 0 : return;
422 : }
423 :
424 0 : frame_len = utvfu_norm_params[sc->sc_normi].frame_len;
425 :
426 : /* Copy the chunk data. */
427 0 : utvfu_chunk_to_vbuf(sc->sc_fb.buf, chunk, chunk_no, odd);
428 0 : sc->sc_fb.chunks_done++;
429 :
430 : /* Last chunk in a field */
431 0 : if (chunk_no == sc->sc_nchunks-1) {
432 : /* Last chunk in a frame, signalling an end */
433 0 : if (odd && !sc->sc_fb.last_odd) {
434 0 : if (sc->sc_fb.chunks_done != sc->sc_nchunks) {
435 : DPRINTF(1, "%s: chunks_done=%d != nchunks=%d\n",
436 : DEVNAME(sc),
437 : sc->sc_fb.chunks_done, sc->sc_nchunks);
438 : }
439 :
440 0 : if (sc->sc_flags & UTVFU_FLAG_MMAP) {
441 0 : utvfu_mmap_queue(sc, sc->sc_fb.buf, frame_len);
442 0 : }
443 : else {
444 0 : utvfu_read(sc, sc->sc_fb.buf, frame_len);
445 : }
446 : }
447 0 : sc->sc_fb.last_odd = odd;
448 0 : }
449 0 : }
450 :
451 : int
452 0 : utvfu_start_capture(struct utvfu_softc *sc)
453 : {
454 : usbd_status error;
455 : int restart_au;
456 :
457 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
458 :
459 0 : restart_au = ISSET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING);
460 0 : utvfu_audio_stop(sc);
461 :
462 : /* default video stream interface */
463 0 : error = usbd_set_interface(sc->sc_uifaceh, UTVFU_DFLT_IFACE_IDX);
464 0 : if (error != USBD_NORMAL_COMPLETION)
465 0 : return (EINVAL);
466 :
467 0 : if (utvfu_setup_capture(sc) != 0)
468 0 : return (EINVAL);
469 :
470 : /* alt setting */
471 0 : error = usbd_set_interface(sc->sc_uifaceh, UTVFU_ALT_IFACE_IDX);
472 0 : if (error != USBD_NORMAL_COMPLETION)
473 0 : return (EINVAL);
474 :
475 0 : if (restart_au)
476 0 : utvfu_audio_start(sc);
477 :
478 0 : return (0);
479 0 : }
480 :
481 : int
482 0 : utvfu_querycap(void *v, struct v4l2_capability *cap)
483 : {
484 0 : struct utvfu_softc *sc = v;
485 :
486 0 : memset(cap, 0, sizeof(*cap));
487 0 : strlcpy(cap->driver, DEVNAME(sc), sizeof(cap->driver));
488 0 : strlcpy(cap->card, "utvfu", sizeof(cap->card));
489 0 : strlcpy(cap->bus_info, "usb", sizeof(cap->bus_info));
490 0 : cap->device_caps = V4L2_CAP_VIDEO_CAPTURE;
491 0 : cap->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
492 0 : cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
493 0 : return (0);
494 : }
495 :
496 : int
497 0 : utvfu_enum_input(void *v, struct v4l2_input *i)
498 : {
499 0 : struct utvfu_softc *sc = v;
500 :
501 0 : switch (i->index) {
502 : case UTVFU_COMPOSITE_INPUT:
503 0 : strlcpy(i->name, "Composite", sizeof(i->name));
504 0 : break;
505 : case UTVFU_SVIDEO_INPUT:
506 0 : strlcpy(i->name, "S-Video", sizeof(i->name));
507 0 : break;
508 : default:
509 0 : return (EINVAL);
510 : }
511 :
512 0 : i->type = V4L2_INPUT_TYPE_CAMERA;
513 0 : i->std = utvfu_norm_params[sc->sc_normi].norm;
514 0 : return (0);
515 0 : }
516 :
517 : int
518 0 : utvfu_enum_fmt_vid_cap(void *v, struct v4l2_fmtdesc *f)
519 : {
520 0 : if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || f->index != 0)
521 0 : return (EINVAL);
522 :
523 0 : strlcpy(f->description, "16 bpp YUY2, 4:2:2, packed",
524 : sizeof(f->description));
525 0 : f->pixelformat = V4L2_PIX_FMT_YUYV;
526 0 : return (0);
527 0 : }
528 :
529 : int
530 0 : utvfu_enum_fsizes(void *v, struct v4l2_frmsizeenum *fsizes)
531 : {
532 0 : struct utvfu_softc *sc = v;
533 :
534 0 : if (fsizes->pixel_format != V4L2_PIX_FMT_YUYV)
535 0 : return (EINVAL);
536 :
537 0 : fsizes->type = V4L2_FRMSIZE_TYPE_DISCRETE;
538 0 : fsizes->discrete.width = utvfu_norm_params[sc->sc_normi].cap_width;
539 0 : fsizes->discrete.height = utvfu_norm_params[sc->sc_normi].cap_height;
540 0 : return (0);
541 0 : }
542 :
543 : int
544 0 : utvfu_g_fmt(void *v, struct v4l2_format *f)
545 : {
546 0 : struct utvfu_softc *sc = v;
547 :
548 0 : f->fmt.pix.width = utvfu_norm_params[sc->sc_normi].cap_width;
549 0 : f->fmt.pix.height = utvfu_norm_params[sc->sc_normi].cap_height;
550 0 : f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
551 0 : f->fmt.pix.field = V4L2_FIELD_INTERLACED;
552 0 : f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
553 0 : f->fmt.pix.sizeimage = (f->fmt.pix.bytesperline * f->fmt.pix.height);
554 0 : f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
555 0 : return (0);
556 : }
557 :
558 : int
559 0 : utvfu_s_fmt(void *v, struct v4l2_format *f)
560 : {
561 0 : if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV)
562 0 : return (EINVAL);
563 0 : return (0);
564 0 : }
565 :
566 : int
567 0 : utvfu_g_std(void *v, v4l2_std_id *norm)
568 : {
569 0 : struct utvfu_softc *sc = v;
570 0 : *norm = utvfu_norm_params[sc->sc_normi].norm;
571 0 : return (0);
572 : }
573 :
574 : int
575 0 : utvfu_s_std(void *v, v4l2_std_id norm)
576 : {
577 : int ret = EINVAL;
578 0 : struct utvfu_softc *sc = v;
579 :
580 0 : if ((norm & V4L2_STD_525_60) || (norm & V4L2_STD_PAL))
581 0 : ret = utvfu_select_norm(sc, norm);
582 :
583 0 : return (ret);
584 : }
585 :
586 : int
587 0 : utvfu_g_input(void *v, int *i)
588 : {
589 0 : struct utvfu_softc *sc = v;
590 0 : *i = sc->sc_input;
591 0 : return (0);
592 : }
593 :
594 : int
595 0 : utvfu_s_input(void *v, int i)
596 : {
597 0 : return utvfu_select_input(v, i);
598 : }
599 :
600 : /* A U D I O */
601 :
602 : void
603 0 : utvfu_audio_decode(struct utvfu_softc *sc, int len)
604 : {
605 : uint8_t *dst, *src;
606 : int n, chunk, ncopied;
607 :
608 0 : if (sc->sc_audio.blksize == 0)
609 0 : return;
610 :
611 0 : src = KERNADDR(&sc->sc_audio.iface.xfer->dmabuf, 0);
612 0 : dst = sc->sc_audio.cur;
613 0 : ncopied = sc->sc_audio.cur - sc->sc_audio.start;
614 : /* b/c region start->end is a multiple blksize chunks */
615 0 : ncopied %= sc->sc_audio.blksize;
616 :
617 0 : while (len >= UTVFU_CHUNK_SIZE) {
618 : /*
619 : * The header, skipped here, ranges from 0xdd000000 to
620 : * 0xdd0003ff. The 0xdd seems to be the "magic" and
621 : * 0x3ff masks the chunk number.
622 : */
623 0 : src += UTVFU_AUDIO_HDRSIZE;
624 : chunk = UTVFU_CHUNK;
625 0 : while (chunk > 0) {
626 0 : n = min(chunk, sc->sc_audio.blksize - ncopied);
627 0 : memcpy(dst, src, n);
628 0 : dst += n;
629 0 : src += n;
630 0 : chunk -= n;
631 0 : ncopied += n;
632 0 : if (ncopied >= sc->sc_audio.blksize) {
633 0 : mtx_enter(&audio_lock);
634 0 : (*sc->sc_audio.intr)(sc->sc_audio.intr_arg);
635 0 : mtx_leave(&audio_lock);
636 0 : ncopied -= sc->sc_audio.blksize;
637 0 : }
638 0 : if (dst > sc->sc_audio.end)
639 0 : dst = sc->sc_audio.start;
640 : }
641 0 : len -= UTVFU_CHUNK_SIZE; /* _CHUNK + _AUDIO_HDRSIZE */
642 : }
643 0 : sc->sc_audio.cur = dst;
644 0 : }
645 :
646 : int
647 0 : utvfu_audio_start_chip(struct utvfu_softc *sc)
648 : {
649 : static const uint16_t setup[][2] = {
650 : /* These seem to enable the device. */
651 : { UTVFU_BASE + 0x0008, 0x0001 },
652 : { UTVFU_BASE + 0x01d0, 0x00ff },
653 : { UTVFU_BASE + 0x01d9, 0x0002 },
654 :
655 : { UTVFU_BASE + 0x01da, 0x0013 },
656 : { UTVFU_BASE + 0x01db, 0x0012 },
657 : { UTVFU_BASE + 0x01e9, 0x0002 },
658 : { UTVFU_BASE + 0x01ec, 0x006c },
659 : { UTVFU_BASE + 0x0294, 0x0020 },
660 : { UTVFU_BASE + 0x0255, 0x00cf },
661 : { UTVFU_BASE + 0x0256, 0x0020 },
662 : { UTVFU_BASE + 0x01eb, 0x0030 },
663 : { UTVFU_BASE + 0x027d, 0x00a6 },
664 : { UTVFU_BASE + 0x0280, 0x0011 },
665 : { UTVFU_BASE + 0x0281, 0x0040 },
666 : { UTVFU_BASE + 0x0282, 0x0011 },
667 : { UTVFU_BASE + 0x0283, 0x0040 },
668 : { 0xf891, 0x0010 },
669 :
670 : /* this sets the input from composite */
671 : { UTVFU_BASE + 0x0284, 0x00aa },
672 : };
673 :
674 : /* starting the stream */
675 0 : utvfu_set_regs(sc, setup, nitems(setup));
676 :
677 0 : return (0);
678 : }
679 :
680 : int
681 0 : utvfu_audio_stop_chip(struct utvfu_softc *sc)
682 : {
683 : static const uint16_t setup[][2] = {
684 : /*
685 : * The original windows driver sometimes sends also:
686 : * { UTVFU_BASE + 0x00a2, 0x0013 }
687 : * but it seems useless and its real effects are untested at
688 : * the moment.
689 : */
690 : { UTVFU_BASE + 0x027d, 0x0000 },
691 : { UTVFU_BASE + 0x0280, 0x0010 },
692 : { UTVFU_BASE + 0x0282, 0x0010 },
693 : };
694 :
695 0 : utvfu_set_regs(sc, setup, nitems(setup));
696 :
697 0 : return (0);
698 : }
699 :
700 : /*
701 : * Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
702 : * Copyright (c) 2008 Marcus Glocker <mglocker@openbsd.org>
703 : * Copyright (c) 2016 Patrick Keshishian <patrick@boxsoft.com>
704 : *
705 : * Permission to use, copy, modify, and distribute this software for any
706 : * purpose with or without fee is hereby granted, provided that the above
707 : * copyright notice and this permission notice appear in all copies.
708 : *
709 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
710 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
711 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
712 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
713 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
714 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
715 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
716 : */
717 : /*
718 : * Heavily based on uvideo.c source.
719 : */
720 :
721 : int utvfu_match(struct device *, void *, void *);
722 : void utvfu_attach(struct device *, struct device *, void *);
723 : int utvfu_detach(struct device *, int);
724 :
725 : usbd_status utvfu_parse_desc(struct utvfu_softc *);
726 :
727 : void utvfu_vs_close(struct utvfu_softc *);
728 : void utvfu_vs_free_frame(struct utvfu_softc *);
729 : void utvfu_vs_free_isoc(struct utvfu_softc *);
730 : void utvfu_vs_start_isoc_ixfer(struct utvfu_softc *,
731 : struct utvfu_isoc_xfer *);
732 : void utvfu_vs_cb(struct usbd_xfer *, void *, usbd_status);
733 :
734 : void utvfu_vs_free(struct utvfu_softc *);
735 : int utvfu_vs_init(struct utvfu_softc *);
736 : int utvfu_vs_alloc_frame(struct utvfu_softc *);
737 : usbd_status utvfu_vs_alloc_isoc(struct utvfu_softc *);
738 :
739 : int utvfu_open(void *, int, int *, uint8_t *,
740 : void (*)(void *), void *);
741 : int utvfu_close(void *);
742 : int utvfu_querycap(void *, struct v4l2_capability *);
743 : int utvfu_enum_fmt_vid_cap(void *, struct v4l2_fmtdesc *);
744 : int utvfu_enum_fsizes(void *, struct v4l2_frmsizeenum *);
745 : int utvfu_g_fmt(void *, struct v4l2_format *);
746 : int utvfu_s_fmt(void *, struct v4l2_format *);
747 : int utvfu_g_parm(void *, struct v4l2_streamparm *);
748 : int utvfu_s_parm(void *, struct v4l2_streamparm *);
749 : int utvfu_enum_input(void *, struct v4l2_input *);
750 : int utvfu_s_input(void *, int);
751 : int utvfu_g_input(void *, int *);
752 :
753 : int utvfu_reqbufs(void *, struct v4l2_requestbuffers *);
754 : int utvfu_querybuf(void *, struct v4l2_buffer *);
755 : int utvfu_qbuf(void *, struct v4l2_buffer *);
756 : int utvfu_dqbuf(void *, struct v4l2_buffer *);
757 : int utvfu_streamon(void *, int);
758 : int utvfu_streamoff(void *, int);
759 : int utvfu_queryctrl(void *, struct v4l2_queryctrl *);
760 : caddr_t utvfu_mappage(void *, off_t, int);
761 : int utvfu_get_bufsize(void *);
762 : int utvfu_start_read(void *);
763 :
764 : int utvfu_as_init(struct utvfu_softc *);
765 : void utvfu_as_free(struct utvfu_softc *);
766 :
767 : usbd_status utvfu_as_open(struct utvfu_softc *);
768 : int utvfu_as_alloc_bulk(struct utvfu_softc *);
769 : void utvfu_as_free_bulk(struct utvfu_softc *);
770 : int utvfu_as_start_bulk(struct utvfu_softc *);
771 : void utvfu_as_bulk_thread(void *);
772 :
773 : int utvfu_audio_open(void *, int);
774 : void utvfu_audio_close(void *);
775 : int utvfu_audio_set_params(void *, int, int,
776 : struct audio_params *, struct audio_params *);
777 : int utvfu_audio_halt_out(void *);
778 : int utvfu_audio_halt_in(void *);
779 : int utvfu_audio_mixer_set_port(void *, struct mixer_ctrl *);
780 : int utvfu_audio_mixer_get_port(void *, struct mixer_ctrl *);
781 : int utvfu_audio_query_devinfo(void *, struct mixer_devinfo *);
782 : int utvfu_audio_get_props(void *);
783 : int utvfu_audio_trigger_output(void *, void *, void *, int,
784 : void (*)(void *), void *, struct audio_params *);
785 : int utvfu_audio_trigger_input(void *, void *, void *, int,
786 : void (*)(void *), void *, struct audio_params *);
787 :
788 : struct cfdriver utvfu_cd = {
789 : NULL, "utvfu", DV_DULL
790 : };
791 :
792 : const struct cfattach utvfu_ca = {
793 : sizeof(struct utvfu_softc),
794 : utvfu_match,
795 : utvfu_attach,
796 : utvfu_detach,
797 : NULL
798 : };
799 :
800 : struct video_hw_if utvfu_vid_hw_if = {
801 : utvfu_open, /* open */
802 : utvfu_close, /* close */
803 : utvfu_querycap, /* VIDIOC_QUERYCAP */
804 : utvfu_enum_fmt_vid_cap, /* VIDIOC_ENUM_FMT */
805 : utvfu_enum_fsizes, /* VIDIOC_ENUM_FRAMESIZES */
806 : NULL, /* VIDIOC_ENUM_FRAMEINTERVALS */
807 : utvfu_s_fmt, /* VIDIOC_S_FMT */
808 : utvfu_g_fmt, /* VIDIOC_G_FMT */
809 : utvfu_s_parm, /* VIDIOC_S_PARM */
810 : utvfu_g_parm, /* VIDIOC_G_PARM */
811 : utvfu_enum_input, /* VIDIOC_ENUMINPUT */
812 : utvfu_s_input, /* VIDIOC_S_INPUT */
813 : utvfu_g_input, /* VIDIOC_G_INPUT */
814 : utvfu_reqbufs, /* VIDIOC_REQBUFS */
815 : utvfu_querybuf, /* VIDIOC_QUERYBUF */
816 : utvfu_qbuf, /* VIDIOC_QBUF */
817 : utvfu_dqbuf, /* VIDIOC_DQBUF */
818 : utvfu_streamon, /* VIDIOC_STREAMON */
819 : utvfu_streamoff, /* VIDIOC_STREAMOFF */
820 : NULL, /* VIDIOC_TRY_FMT */
821 : utvfu_queryctrl, /* VIDIOC_QUERYCTRL */
822 : NULL, /* VIDIOC_G_CTRL */
823 : NULL, /* VIDIOC_S_CTRL */
824 : utvfu_mappage, /* mmap */
825 : utvfu_get_bufsize, /* read */
826 : utvfu_start_read /* start stream for read */
827 : };
828 :
829 : struct audio_hw_if utvfu_au_hw_if = {
830 : utvfu_audio_open, /* open hardware */
831 : utvfu_audio_close, /* close hardware */
832 : utvfu_audio_set_params,
833 : NULL,
834 : NULL,
835 : NULL,
836 : NULL,
837 : NULL,
838 : NULL,
839 : utvfu_audio_halt_out,
840 : utvfu_audio_halt_in,
841 : NULL,
842 : NULL,
843 : utvfu_audio_mixer_set_port,
844 : utvfu_audio_mixer_get_port,
845 : utvfu_audio_query_devinfo,
846 : NULL,
847 : NULL,
848 : NULL,
849 : utvfu_audio_get_props,
850 : utvfu_audio_trigger_output,
851 : utvfu_audio_trigger_input
852 : };
853 :
854 : int
855 0 : utvfu_match(struct device *parent, void *match, void *aux)
856 : {
857 0 : struct usb_attach_arg *uaa = aux;
858 : const struct usb_descriptor *ud;
859 0 : struct usbd_desc_iter iter;
860 : struct usb_interface_descriptor *uid = NULL;
861 : const struct usb_endpoint_descriptor *ued = NULL;
862 : usb_device_descriptor_t *dd;
863 : int ret = UMATCH_NONE;
864 : int nep, nalt;
865 : uint16_t psize = 0;
866 :
867 0 : if (uaa->iface == NULL)
868 0 : return ret;
869 :
870 0 : dd = usbd_get_device_descriptor(uaa->device);
871 :
872 0 : if (UGETW(dd->idVendor) == USB_VENDOR_FUSHICAI &&
873 0 : UGETW(dd->idProduct) == USB_PRODUCT_FUSHICAI_USBTV007)
874 0 : ret = UMATCH_VENDOR_PRODUCT;
875 : /*
876 : * This seems like a fragile check, but the original driver ensures
877 : * there are two alternate settings for the interface, and alternate
878 : * setting 1 has four endpoints.
879 : *
880 : * Comment says "Checks that the device is what we think it is."
881 : *
882 : * Adding check that wMaxPacketSize for the video endpoint is > 0.
883 : */
884 : nep = nalt = 0;
885 0 : usbd_desc_iter_init(uaa->device, &iter);
886 0 : while ((ud = usbd_desc_iter_next(&iter)) != NULL) {
887 0 : switch (ud->bDescriptorType) {
888 : default:
889 : break;
890 : case UDESC_INTERFACE:
891 0 : uid = (void *)ud;
892 0 : if (uid->bInterfaceNumber == 0)
893 0 : nalt++;
894 : break;
895 : case UDESC_ENDPOINT:
896 0 : if (uid->bAlternateSetting == 1) {
897 0 : ued = (void *)ud;
898 0 : if (ued->bEndpointAddress == UTVFU_VIDEO_ENDP)
899 0 : psize = UGETW(ued->wMaxPacketSize);
900 0 : nep++;
901 0 : }
902 : break;
903 : }
904 0 : if (uid != NULL && uid->bInterfaceNumber > 0)
905 : break;
906 : }
907 :
908 0 : if (nalt != 2 || nep != 4 || psize == 0)
909 0 : ret = UMATCH_NONE;
910 :
911 0 : return (ret);
912 0 : }
913 :
914 : void
915 0 : utvfu_attach(struct device *parent, struct device *self, void *aux)
916 : {
917 : int i;
918 0 : struct utvfu_softc *sc = (struct utvfu_softc *)self;
919 0 : struct usb_attach_arg *uaa = aux;
920 :
921 0 : sc->sc_udev = uaa->device;
922 0 : for (i = 0; i < uaa->nifaces; i++) {
923 0 : if (usbd_iface_claimed(sc->sc_udev, i))
924 : continue;
925 0 : usbd_claim_iface(sc->sc_udev, i);
926 0 : }
927 :
928 0 : utvfu_parse_desc(sc);
929 :
930 : /* init mmap queue */
931 0 : SIMPLEQ_INIT(&sc->sc_mmap_q);
932 0 : sc->sc_mmap_count = 0;
933 :
934 0 : sc->sc_max_frame_sz = utvfu_max_frame_size();
935 :
936 : /* calculate optimal isoc xfer size */
937 0 : sc->sc_nframes = (sc->sc_max_frame_sz + sc->sc_iface.psize - 1)
938 0 : / sc->sc_iface.psize;
939 0 : if (sc->sc_nframes > UTVFU_NFRAMES_MAX)
940 0 : sc->sc_nframes = UTVFU_NFRAMES_MAX;
941 : DPRINTF(1, "%s: nframes=%d\n", DEVNAME(sc), sc->sc_nframes);
942 :
943 0 : rw_init(&sc->sc_audio.rwlock, "audiorwl");
944 :
945 0 : sc->sc_audiodev = audio_attach_mi(&utvfu_au_hw_if, sc, &sc->sc_dev);
946 0 : sc->sc_videodev = video_attach_mi(&utvfu_vid_hw_if, sc, &sc->sc_dev);
947 0 : }
948 :
949 : int
950 0 : utvfu_detach(struct device *self, int flags)
951 : {
952 0 : struct utvfu_softc *sc = (struct utvfu_softc *)self;
953 : int rv = 0;
954 :
955 : /* Wait for outstanding requests to complete */
956 0 : usbd_delay_ms(sc->sc_udev, UTVFU_NFRAMES_MAX); /* XXX meh? */
957 :
958 0 : if (sc->sc_videodev != NULL)
959 0 : rv = config_detach(sc->sc_videodev, flags);
960 :
961 0 : if (sc->sc_audiodev != NULL)
962 0 : rv += config_detach(sc->sc_audiodev, flags);
963 :
964 0 : utvfu_as_free(sc);
965 0 : utvfu_vs_free(sc);
966 :
967 0 : sc->sc_flags = 0;
968 :
969 0 : return (rv);
970 : }
971 :
972 : usbd_status
973 0 : utvfu_parse_desc(struct utvfu_softc *sc)
974 : {
975 : int nif, nep;
976 : uint32_t psize;
977 0 : struct usbd_desc_iter iter;
978 : const struct usb_descriptor *ud;
979 : struct usb_endpoint_descriptor *ued;
980 : struct usb_interface_descriptor *uid = NULL;
981 :
982 : nif = nep = 0;
983 0 : usbd_desc_iter_init(sc->sc_udev, &iter);
984 0 : while ((ud = usbd_desc_iter_next(&iter)) != NULL) {
985 0 : if (ud->bDescriptorType != UDESC_INTERFACE)
986 0 : continue;
987 : /* looking for interface 0, alt-setting 1 */
988 0 : uid = (void *)ud;
989 0 : if (uid->bInterfaceNumber > 0)
990 : break;
991 0 : if (uid->bAlternateSetting == 1)
992 : break;
993 : }
994 :
995 : /* this should not fail as it was ensured during match */
996 0 : if (uid == NULL || uid->bInterfaceNumber != 0 ||
997 0 : uid->bAlternateSetting != 1) {
998 0 : printf("%s: no valid alternate interface found!\n",
999 0 : DEVNAME(sc));
1000 0 : return (USBD_INVAL);
1001 : }
1002 :
1003 : /* bInterfaceNumber = 0 */
1004 0 : sc->sc_uifaceh = &sc->sc_udev->ifaces[0];
1005 :
1006 : /* looking for video endpoint to on alternate setting 1 */
1007 0 : while ((ud = usbd_desc_iter_next(&iter)) != NULL) {
1008 0 : if (ud->bDescriptorType != UDESC_ENDPOINT)
1009 : break;
1010 :
1011 0 : ued = (void *)ud;
1012 0 : if (ued->bEndpointAddress != UTVFU_VIDEO_ENDP)
1013 0 : continue;
1014 :
1015 0 : psize = UGETW(ued->wMaxPacketSize);
1016 0 : psize = UE_GET_SIZE(psize) * (1 + UE_GET_TRANS(psize));
1017 0 : sc->sc_iface.psize = psize;
1018 0 : break;
1019 : }
1020 :
1021 0 : return (USBD_NORMAL_COMPLETION);
1022 0 : }
1023 :
1024 : int
1025 0 : utvfu_open(void *addr, int flags, int *size, uint8_t *buffer,
1026 : void (*intr)(void *), void *arg)
1027 : {
1028 0 : struct utvfu_softc *sc = addr;
1029 : int rv;
1030 :
1031 : DPRINTF(1, "%s: utvfu_open: sc=%p\n", DEVNAME(sc), sc);
1032 :
1033 0 : if (usbd_is_dying(sc->sc_udev))
1034 0 : return (EIO);
1035 :
1036 0 : if ((rv = utvfu_vs_init(sc)) != 0)
1037 0 : return (rv);
1038 :
1039 : /* pointers to upper video layer */
1040 0 : sc->sc_uplayer_arg = arg;
1041 0 : sc->sc_uplayer_fsize = size;
1042 0 : sc->sc_uplayer_fbuffer = buffer;
1043 0 : sc->sc_uplayer_intr = intr;
1044 :
1045 0 : sc->sc_flags &= ~UTVFU_FLAG_MMAP;
1046 :
1047 0 : return (0);
1048 0 : }
1049 :
1050 : int
1051 0 : utvfu_close(void *addr)
1052 : {
1053 0 : struct utvfu_softc *sc = addr;
1054 :
1055 : DPRINTF(1, "%s: utvfu_close: sc=%p\n", DEVNAME(sc), sc);
1056 :
1057 : /* free & clean up video stream */
1058 0 : utvfu_vs_free(sc);
1059 :
1060 0 : return (0);
1061 : }
1062 :
1063 : usbd_status
1064 0 : utvfu_as_open(struct utvfu_softc *sc)
1065 : {
1066 : usb_endpoint_descriptor_t *ed;
1067 : usbd_status error;
1068 :
1069 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1070 :
1071 0 : if (sc->sc_audio.iface.pipeh != NULL) {
1072 0 : printf("%s: %s called while sc_audio.iface.pipeh not NULL\n",
1073 0 : DEVNAME(sc), __func__);
1074 0 : return (USBD_INVAL);
1075 : }
1076 :
1077 0 : ed = usbd_get_endpoint_descriptor(sc->sc_uifaceh, UTVFU_AUDIO_ENDP);
1078 0 : if (ed == NULL) {
1079 0 : printf("%s: no endpoint descriptor for AS iface\n",
1080 0 : DEVNAME(sc));
1081 0 : return (USBD_INVAL);
1082 : }
1083 : DPRINTF(1, "%s: open pipe for ", DEVNAME(sc));
1084 : DPRINTF(1, "bEndpointAddress=0x%02x (0x%02x), wMaxPacketSize="
1085 : "0x%04x (%d)\n",
1086 : UE_GET_ADDR(ed->bEndpointAddress),
1087 : UTVFU_AUDIO_ENDP,
1088 : UGETW(ed->wMaxPacketSize),
1089 : UE_GET_SIZE(UGETW(ed->wMaxPacketSize))
1090 : * (1 + UE_GET_TRANS(UGETW(ed->wMaxPacketSize))));
1091 :
1092 0 : error = usbd_open_pipe(
1093 0 : sc->sc_uifaceh,
1094 : UTVFU_AUDIO_ENDP,
1095 : USBD_EXCLUSIVE_USE,
1096 : &sc->sc_audio.iface.pipeh);
1097 0 : if (error != USBD_NORMAL_COMPLETION) {
1098 0 : printf("%s: could not open AS pipe: %s\n",
1099 0 : DEVNAME(sc), usbd_errstr(error));
1100 0 : }
1101 :
1102 0 : return (error);
1103 0 : }
1104 :
1105 : usbd_status
1106 0 : utvfu_vs_open(struct utvfu_softc *sc)
1107 : {
1108 : usb_endpoint_descriptor_t *ed;
1109 : usbd_status error;
1110 :
1111 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1112 :
1113 0 : if (sc->sc_iface.pipeh != NULL) {
1114 0 : printf("%s: %s called while sc_iface.pipeh not NULL\n",
1115 0 : DEVNAME(sc), __func__);
1116 0 : return (USBD_INVAL);
1117 : }
1118 :
1119 0 : ed = usbd_get_endpoint_descriptor(sc->sc_uifaceh, UTVFU_VIDEO_ENDP);
1120 0 : if (ed == NULL) {
1121 0 : printf("%s: no endpoint descriptor for VS iface\n",
1122 0 : DEVNAME(sc));
1123 0 : return (USBD_INVAL);
1124 : }
1125 : DPRINTF(1, "%s: open pipe for ", DEVNAME(sc));
1126 : DPRINTF(1, "bEndpointAddress=0x%02x (0x%02x), wMaxPacketSize="
1127 : "0x%04x (%d)\n",
1128 : UE_GET_ADDR(ed->bEndpointAddress),
1129 : UTVFU_VIDEO_ENDP,
1130 : UGETW(ed->wMaxPacketSize),
1131 : sc->sc_iface.psize);
1132 :
1133 0 : error = usbd_open_pipe(
1134 0 : sc->sc_uifaceh,
1135 : UTVFU_VIDEO_ENDP,
1136 : USBD_EXCLUSIVE_USE,
1137 : &sc->sc_iface.pipeh);
1138 0 : if (error != USBD_NORMAL_COMPLETION) {
1139 0 : printf("%s: could not open VS pipe: %s\n",
1140 0 : DEVNAME(sc), usbd_errstr(error));
1141 0 : }
1142 :
1143 0 : return (error);
1144 0 : }
1145 :
1146 : void
1147 0 : utvfu_as_close(struct utvfu_softc *sc)
1148 : {
1149 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1150 :
1151 0 : CLR(sc->sc_flags, UTVFU_FLAG_AS_RUNNING);
1152 :
1153 0 : if (sc->sc_audio.iface.pipeh != NULL) {
1154 0 : usbd_abort_pipe(sc->sc_audio.iface.pipeh);
1155 :
1156 0 : usbd_ref_wait(sc->sc_udev);
1157 :
1158 0 : usbd_close_pipe(sc->sc_audio.iface.pipeh);
1159 0 : sc->sc_audio.iface.pipeh = NULL;
1160 0 : }
1161 0 : }
1162 :
1163 : void
1164 0 : utvfu_vs_close(struct utvfu_softc *sc)
1165 : {
1166 0 : if (sc->sc_iface.pipeh != NULL) {
1167 0 : usbd_abort_pipe(sc->sc_iface.pipeh);
1168 0 : usbd_close_pipe(sc->sc_iface.pipeh);
1169 0 : sc->sc_iface.pipeh = NULL;
1170 0 : }
1171 :
1172 : /*
1173 : * Some devices need time to shutdown before we switch back to
1174 : * the default interface (0). Not doing so can leave the device
1175 : * back in a undefined condition.
1176 : */
1177 0 : usbd_delay_ms(sc->sc_udev, 100);
1178 :
1179 : /* switch back to default interface (turns off cam LED) */
1180 0 : (void)usbd_set_interface(sc->sc_uifaceh, UTVFU_DFLT_IFACE_IDX);
1181 0 : }
1182 :
1183 : void
1184 0 : utvfu_read(struct utvfu_softc *sc, uint8_t *buf, int len)
1185 : {
1186 : /*
1187 : * Copy video frame to upper layer buffer and call
1188 : * upper layer interrupt.
1189 : */
1190 0 : *sc->sc_uplayer_fsize = len;
1191 0 : memcpy(sc->sc_uplayer_fbuffer, buf, len);
1192 0 : (*sc->sc_uplayer_intr)(sc->sc_uplayer_arg);
1193 0 : }
1194 :
1195 : int
1196 0 : utvfu_as_start_bulk(struct utvfu_softc *sc)
1197 : {
1198 : int error;
1199 :
1200 0 : if (ISSET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING))
1201 0 : return (0);
1202 0 : if (sc->sc_audio.iface.pipeh == NULL)
1203 0 : return (ENXIO);
1204 :
1205 0 : SET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING);
1206 0 : error = kthread_create(utvfu_as_bulk_thread, sc, NULL, DEVNAME(sc));
1207 0 : if (error) {
1208 0 : CLR(sc->sc_flags, UTVFU_FLAG_AS_RUNNING);
1209 0 : printf("%s: can't create kernel thread!", DEVNAME(sc));
1210 0 : }
1211 :
1212 0 : return (error);
1213 0 : }
1214 :
1215 : void
1216 0 : utvfu_as_bulk_thread(void *arg)
1217 : {
1218 0 : struct utvfu_softc *sc = arg;
1219 : struct utvfu_as_iface *iface;
1220 : usbd_status error;
1221 0 : uint32_t actlen;
1222 :
1223 : DPRINTF(1, "%s %s\n", DEVNAME(sc), __func__);
1224 :
1225 0 : iface = &sc->sc_audio.iface;
1226 0 : usbd_ref_incr(sc->sc_udev);
1227 0 : while (ISSET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING)) {
1228 0 : usbd_setup_xfer(
1229 0 : iface->xfer,
1230 0 : iface->pipeh,
1231 : 0,
1232 : NULL,
1233 : UTVFU_AUDIO_URBSIZE,
1234 : USBD_NO_COPY | USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS,
1235 : 0,
1236 : NULL);
1237 0 : error = usbd_transfer(iface->xfer);
1238 :
1239 0 : if (error != USBD_NORMAL_COMPLETION) {
1240 : DPRINTF(1, "%s: error in bulk xfer: %s!\n",
1241 : DEVNAME(sc), usbd_errstr(error));
1242 : break;
1243 : }
1244 :
1245 0 : usbd_get_xfer_status(iface->xfer, NULL, NULL, &actlen,
1246 : NULL);
1247 : DPRINTF(2, "%s: *** buffer len = %d\n", DEVNAME(sc), actlen);
1248 :
1249 0 : rw_enter_read(&sc->sc_audio.rwlock);
1250 0 : utvfu_audio_decode(sc, actlen);
1251 0 : rw_exit_read(&sc->sc_audio.rwlock);
1252 : }
1253 :
1254 0 : CLR(sc->sc_flags, UTVFU_FLAG_AS_RUNNING);
1255 0 : usbd_ref_decr(sc->sc_udev);
1256 :
1257 : DPRINTF(1, "%s %s: exiting\n", DEVNAME(sc), __func__);
1258 :
1259 0 : kthread_exit(0);
1260 : }
1261 :
1262 : void
1263 0 : utvfu_vs_start_isoc(struct utvfu_softc *sc)
1264 : {
1265 : int i;
1266 0 : for (i = 0; i < UTVFU_ISOC_TRANSFERS; i++)
1267 0 : utvfu_vs_start_isoc_ixfer(sc, &sc->sc_iface.ixfer[i]);
1268 0 : }
1269 :
1270 : void
1271 0 : utvfu_vs_start_isoc_ixfer(struct utvfu_softc *sc,
1272 : struct utvfu_isoc_xfer *ixfer)
1273 : {
1274 : int i;
1275 : usbd_status error;
1276 :
1277 : DPRINTF(2, "%s: %s\n", DEVNAME(sc), __func__);
1278 :
1279 0 : if (usbd_is_dying(sc->sc_udev))
1280 0 : return;
1281 :
1282 0 : for (i = 0; i < sc->sc_nframes; i++)
1283 0 : ixfer->size[i] = sc->sc_iface.psize;
1284 :
1285 0 : usbd_setup_isoc_xfer(
1286 0 : ixfer->xfer,
1287 0 : sc->sc_iface.pipeh,
1288 0 : ixfer,
1289 0 : ixfer->size,
1290 : sc->sc_nframes,
1291 : USBD_NO_COPY | USBD_SHORT_XFER_OK,
1292 : utvfu_vs_cb);
1293 :
1294 0 : error = usbd_transfer(ixfer->xfer);
1295 0 : if (error && error != USBD_IN_PROGRESS) {
1296 : DPRINTF(1, "%s: usbd_transfer error=%s!\n",
1297 : DEVNAME(sc), usbd_errstr(error));
1298 : }
1299 0 : }
1300 :
1301 : /*
1302 : * Each packet contains a number of 256-byte chunks composing the image frame.
1303 : */
1304 : void
1305 0 : utvfu_vs_cb(struct usbd_xfer *xfer, void *priv, usbd_status status)
1306 : {
1307 0 : struct utvfu_isoc_xfer *ixfer = priv;
1308 0 : struct utvfu_softc *sc = ixfer->sc;
1309 : int i, off, frame_size;
1310 0 : uint32_t actlen;
1311 : uint8_t *frame;
1312 :
1313 : DPRINTF(2, "%s: %s\n", DEVNAME(sc), __func__);
1314 :
1315 0 : if (status != USBD_NORMAL_COMPLETION) {
1316 : DPRINTF(1, "%s: %s: %s\n", DEVNAME(sc), __func__,
1317 : usbd_errstr(status));
1318 0 : return;
1319 : }
1320 0 : usbd_get_xfer_status(xfer, NULL, NULL, &actlen, NULL);
1321 :
1322 : DPRINTF(2, "%s: *** buffer len = %d\n", DEVNAME(sc), actlen);
1323 0 : if (actlen == 0)
1324 : goto skip;
1325 :
1326 0 : frame = KERNADDR(&xfer->dmabuf, 0);
1327 0 : for (i = 0; i < sc->sc_nframes; i++, frame += sc->sc_iface.psize) {
1328 0 : frame_size = ixfer->size[i];
1329 :
1330 0 : if (frame_size == 0)
1331 : /* frame is empty */
1332 : continue;
1333 :
1334 : #define CHUNK_STRIDE (UTVFU_CHUNK_SIZE*4)
1335 0 : for (off = 0; off + CHUNK_STRIDE <= frame_size;
1336 : off += CHUNK_STRIDE) {
1337 0 : utvfu_image_chunk(sc, frame + off);
1338 : }
1339 : #undef CHUNK_STRIDE
1340 : }
1341 :
1342 : skip: /* setup new transfer */
1343 0 : utvfu_vs_start_isoc_ixfer(sc, ixfer);
1344 0 : }
1345 :
1346 : int
1347 0 : utvfu_find_queued(struct utvfu_softc *sc)
1348 : {
1349 : int i;
1350 :
1351 : /* find a buffer which is ready for queueing */
1352 0 : for (i = 0; i < sc->sc_mmap_count; i++) {
1353 0 : if (sc->sc_mmap[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
1354 : continue;
1355 0 : if (sc->sc_mmap[i].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)
1356 0 : return (i);
1357 : }
1358 0 : return (-1);
1359 0 : }
1360 :
1361 : int
1362 0 : utvfu_mmap_queue(struct utvfu_softc *sc, uint8_t *buf, int len)
1363 : {
1364 : int i;
1365 :
1366 0 : if (sc->sc_mmap_count == 0 || sc->sc_mmap_buffer == NULL)
1367 0 : panic("%s: mmap buffers not allocated", __func__);
1368 :
1369 : /* find a buffer which is ready for queueing */
1370 0 : if ((i = utvfu_find_queued(sc)) == -1) {
1371 : DPRINTF(2, "%s: mmap queue is full!\n", DEVNAME(sc));
1372 0 : return (ENOMEM);
1373 : }
1374 :
1375 : /* copy frame to mmap buffer and report length */
1376 0 : memcpy(sc->sc_mmap[i].buf, buf, len);
1377 0 : sc->sc_mmap[i].v4l2_buf.bytesused = len;
1378 :
1379 : /* timestamp it */
1380 0 : getmicrotime(&sc->sc_mmap[i].v4l2_buf.timestamp);
1381 :
1382 : /* appropriately set/clear flags */
1383 0 : sc->sc_mmap[i].v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
1384 0 : sc->sc_mmap[i].v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
1385 :
1386 : /* queue it */
1387 0 : SIMPLEQ_INSERT_TAIL(&sc->sc_mmap_q, &sc->sc_mmap[i], q_frames);
1388 : DPRINTF(2, "%s: %s: frame queued on index %d\n",
1389 : DEVNAME(sc), __func__, i);
1390 :
1391 0 : wakeup(sc);
1392 :
1393 : /*
1394 : * In case userland uses poll(2), signal that we have a frame
1395 : * ready to dequeue.
1396 : */
1397 0 : (*sc->sc_uplayer_intr)(sc->sc_uplayer_arg);
1398 :
1399 0 : return (0);
1400 0 : }
1401 :
1402 : caddr_t
1403 0 : utvfu_mappage(void *v, off_t off, int prot)
1404 : {
1405 0 : struct utvfu_softc *sc = v;
1406 : caddr_t p = NULL;
1407 :
1408 0 : if (off < sc->sc_mmap_bufsz) {
1409 0 : if ((sc->sc_flags & UTVFU_FLAG_MMAP) == 0)
1410 0 : sc->sc_flags |= UTVFU_FLAG_MMAP;
1411 :
1412 0 : p = sc->sc_mmap_buffer + off;
1413 0 : }
1414 :
1415 0 : return (p);
1416 : }
1417 :
1418 : int
1419 0 : utvfu_get_bufsize(void *v)
1420 : {
1421 0 : struct utvfu_softc *sc = v;
1422 : /* YUYV/YUV-422: 4 bytes/2 pixel */
1423 0 : return (utvfu_norm_params[sc->sc_normi].cap_width *
1424 0 : utvfu_norm_params[sc->sc_normi].cap_height * 2);
1425 : }
1426 :
1427 : int
1428 0 : utvfu_start_read(void *v)
1429 : {
1430 0 : struct utvfu_softc *sc = v;
1431 : usbd_status error;
1432 :
1433 0 : if (sc->sc_flags & UTVFU_FLAG_MMAP)
1434 0 : sc->sc_flags &= ~UTVFU_FLAG_MMAP;
1435 :
1436 : /* open video stream pipe */
1437 0 : error = utvfu_vs_open(sc);
1438 0 : if (error != USBD_NORMAL_COMPLETION)
1439 0 : return (EINVAL);
1440 :
1441 0 : utvfu_vs_start_isoc(sc);
1442 :
1443 0 : return (0);
1444 0 : }
1445 :
1446 : void
1447 0 : utvfu_audio_clear_client(struct utvfu_softc *sc)
1448 : {
1449 0 : rw_enter_write(&sc->sc_audio.rwlock);
1450 :
1451 0 : sc->sc_audio.intr = NULL;
1452 0 : sc->sc_audio.intr_arg = NULL;
1453 0 : sc->sc_audio.start = NULL;
1454 0 : sc->sc_audio.end = NULL;
1455 0 : sc->sc_audio.cur = NULL;
1456 0 : sc->sc_audio.blksize = 0;
1457 :
1458 0 : rw_exit_write(&sc->sc_audio.rwlock);
1459 0 : }
1460 :
1461 : void
1462 0 : utvfu_as_free(struct utvfu_softc *sc)
1463 : {
1464 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1465 :
1466 0 : utvfu_as_close(sc);
1467 0 : utvfu_as_free_bulk(sc);
1468 0 : }
1469 :
1470 : void
1471 0 : utvfu_vs_free(struct utvfu_softc *sc)
1472 : {
1473 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1474 0 : utvfu_vs_close(sc);
1475 0 : utvfu_vs_free_isoc(sc);
1476 0 : utvfu_vs_free_frame(sc);
1477 0 : }
1478 :
1479 : int
1480 0 : utvfu_as_init(struct utvfu_softc *sc)
1481 : {
1482 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1483 :
1484 0 : if (sc->sc_audio.iface.xfer != NULL)
1485 0 : return (0);
1486 :
1487 : /* allocate audio and video stream xfer buffer */
1488 0 : return utvfu_as_alloc_bulk(sc);
1489 0 : }
1490 :
1491 : int
1492 0 : utvfu_vs_init(struct utvfu_softc *sc)
1493 : {
1494 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1495 :
1496 0 : if (utvfu_start_capture(sc) != 0)
1497 0 : return (EINVAL);
1498 :
1499 0 : if (utvfu_vs_alloc_isoc(sc) != 0 || utvfu_vs_alloc_frame(sc) != 0)
1500 0 : return (ENOMEM);
1501 :
1502 0 : return (0);
1503 0 : }
1504 :
1505 : int
1506 0 : utvfu_vs_alloc_frame(struct utvfu_softc *sc)
1507 : {
1508 0 : struct utvfu_frame_buf *fb = &sc->sc_fb;
1509 :
1510 0 : fb->size = sc->sc_max_frame_sz;
1511 0 : fb->buf = malloc(fb->size, M_DEVBUF, M_NOWAIT);
1512 0 : if (fb->buf == NULL) {
1513 0 : printf("%s: can't allocate frame buffer!\n", DEVNAME(sc));
1514 0 : return (ENOMEM);
1515 : }
1516 :
1517 : DPRINTF(1, "%s: %s: allocated %d bytes frame buffer\n",
1518 : DEVNAME(sc), __func__, fb->size);
1519 :
1520 0 : fb->chunks_done = 0;
1521 0 : fb->fid = 0;
1522 0 : fb->last_odd = 1;
1523 :
1524 0 : return (0);
1525 0 : }
1526 :
1527 : void
1528 0 : utvfu_vs_free_frame(struct utvfu_softc *sc)
1529 : {
1530 0 : struct utvfu_frame_buf *fb = &sc->sc_fb;
1531 :
1532 0 : if (fb->buf != NULL) {
1533 0 : free(fb->buf, M_DEVBUF, fb->size);
1534 0 : fb->buf = NULL;
1535 0 : }
1536 :
1537 0 : if (sc->sc_mmap_buffer != NULL) {
1538 0 : free(sc->sc_mmap_buffer, M_DEVBUF, sc->sc_mmap_bufsz);
1539 0 : sc->sc_mmap_buffer = NULL;
1540 0 : memset(sc->sc_mmap, 0, sizeof(sc->sc_mmap));
1541 0 : }
1542 :
1543 0 : while (!SIMPLEQ_EMPTY(&sc->sc_mmap_q))
1544 0 : SIMPLEQ_REMOVE_HEAD(&sc->sc_mmap_q, q_frames);
1545 :
1546 0 : sc->sc_mmap_count = 0;
1547 0 : }
1548 :
1549 : usbd_status
1550 0 : utvfu_vs_alloc_isoc(struct utvfu_softc *sc)
1551 : {
1552 : int size, i;
1553 : void *buf;
1554 :
1555 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1556 :
1557 0 : for (i = 0; i < UTVFU_ISOC_TRANSFERS; i++) {
1558 0 : sc->sc_iface.ixfer[i].sc = sc;
1559 0 : sc->sc_iface.ixfer[i].xfer = usbd_alloc_xfer(sc->sc_udev);
1560 0 : if (sc->sc_iface.ixfer[i].xfer == NULL) {
1561 0 : printf("%s: could not allocate isoc VS xfer!\n",
1562 0 : DEVNAME(sc));
1563 0 : return (USBD_NOMEM);
1564 : }
1565 :
1566 0 : size = sc->sc_iface.psize * sc->sc_nframes;
1567 :
1568 0 : buf = usbd_alloc_buffer(sc->sc_iface.ixfer[i].xfer, size);
1569 0 : if (buf == NULL) {
1570 0 : printf("%s: could not allocate isoc VS buffer!\n",
1571 0 : DEVNAME(sc));
1572 0 : return (USBD_NOMEM);
1573 : }
1574 : DPRINTF(1, "%s: allocated %d bytes isoc VS xfer buffer\n",
1575 : DEVNAME(sc), size);
1576 : }
1577 :
1578 0 : return (USBD_NORMAL_COMPLETION);
1579 0 : }
1580 :
1581 : int
1582 0 : utvfu_as_alloc_bulk(struct utvfu_softc *sc)
1583 : {
1584 : struct usbd_xfer *xfer;
1585 :
1586 0 : xfer = usbd_alloc_xfer(sc->sc_udev);
1587 0 : if (xfer == NULL) {
1588 0 : printf("%s: could not allocate bulk AUDIO xfer!\n",
1589 0 : DEVNAME(sc));
1590 0 : return (ENOMEM);
1591 : }
1592 :
1593 0 : if (usbd_alloc_buffer(xfer, UTVFU_AUDIO_URBSIZE) == NULL) {
1594 0 : usbd_free_xfer(xfer);
1595 0 : printf("%s: could not allocate bulk AUDIO buffer!\n",
1596 0 : DEVNAME(sc));
1597 0 : return (ENOMEM);
1598 : }
1599 : DPRINTF(1, "%s: allocated %d bytes bulk AUDIO xfer buffer\n",
1600 : DEVNAME(sc), UTVFU_AUDIO_URBSIZE);
1601 :
1602 0 : sc->sc_audio.iface.xfer = xfer;
1603 :
1604 0 : return (0);
1605 0 : }
1606 :
1607 : void
1608 0 : utvfu_vs_free_isoc(struct utvfu_softc *sc)
1609 : {
1610 : int i;
1611 :
1612 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1613 :
1614 0 : for (i = 0; i < UTVFU_ISOC_TRANSFERS; i++) {
1615 0 : if (sc->sc_iface.ixfer[i].xfer != NULL) {
1616 0 : usbd_free_xfer(sc->sc_iface.ixfer[i].xfer);
1617 0 : sc->sc_iface.ixfer[i].xfer = NULL;
1618 0 : }
1619 : }
1620 0 : }
1621 :
1622 : void
1623 0 : utvfu_as_free_bulk(struct utvfu_softc *sc)
1624 : {
1625 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1626 :
1627 0 : if (sc->sc_audio.iface.xfer != NULL) {
1628 0 : usbd_free_xfer(sc->sc_audio.iface.xfer);
1629 0 : sc->sc_audio.iface.xfer = NULL;
1630 0 : }
1631 0 : }
1632 :
1633 : int
1634 0 : utvfu_reqbufs(void *v, struct v4l2_requestbuffers *rb)
1635 : {
1636 0 : struct utvfu_softc *sc = v;
1637 : int i;
1638 :
1639 : DPRINTF(1, "%s: %s: count=%d\n", DEVNAME(sc), __func__, rb->count);
1640 :
1641 : /* We do not support freeing buffers via reqbufs(0) */
1642 0 : if (rb->count == 0)
1643 0 : return (EINVAL);
1644 :
1645 0 : if (sc->sc_mmap_count > 0 || sc->sc_mmap_buffer != NULL) {
1646 : DPRINTF(1, "%s: %s: mmap buffers already allocated\n",
1647 : DEVNAME(sc), __func__);
1648 0 : return (EINVAL);
1649 : }
1650 :
1651 : /* limit the buffers */
1652 0 : if (rb->count > UTVFU_MAX_BUFFERS)
1653 0 : sc->sc_mmap_count = UTVFU_MAX_BUFFERS;
1654 : else
1655 0 : sc->sc_mmap_count = rb->count;
1656 :
1657 : /* allocate the total mmap buffer */
1658 0 : sc->sc_mmap_bufsz = sc->sc_max_frame_sz;
1659 0 : if (INT_MAX / sc->sc_mmap_count < sc->sc_max_frame_sz) /* overflow */
1660 0 : return (ENOMEM);
1661 0 : sc->sc_mmap_bufsz *= sc->sc_mmap_count;
1662 0 : sc->sc_mmap_bufsz = round_page(sc->sc_mmap_bufsz); /* page align */
1663 0 : sc->sc_mmap_buffer = malloc(sc->sc_mmap_bufsz, M_DEVBUF, M_NOWAIT);
1664 0 : if (sc->sc_mmap_buffer == NULL) {
1665 0 : printf("%s: can't allocate mmap buffer!\n", DEVNAME(sc));
1666 0 : return (ENOMEM);
1667 : }
1668 : DPRINTF(1, "%s: allocated %d bytes mmap buffer\n",
1669 : DEVNAME(sc), sc->sc_mmap_bufsz);
1670 :
1671 : /* fill the v4l2_buffer structure */
1672 0 : for (i = 0; i < sc->sc_mmap_count; i++) {
1673 0 : sc->sc_mmap[i].buf = sc->sc_mmap_buffer
1674 0 : + (i * sc->sc_max_frame_sz);
1675 0 : sc->sc_mmap[i].v4l2_buf.index = i;
1676 0 : sc->sc_mmap[i].v4l2_buf.m.offset = i * sc->sc_max_frame_sz;
1677 0 : sc->sc_mmap[i].v4l2_buf.length = sc->sc_max_frame_sz;
1678 0 : sc->sc_mmap[i].v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1679 0 : sc->sc_mmap[i].v4l2_buf.sequence = 0;
1680 0 : sc->sc_mmap[i].v4l2_buf.field = V4L2_FIELD_NONE;
1681 0 : sc->sc_mmap[i].v4l2_buf.memory = V4L2_MEMORY_MMAP;
1682 0 : sc->sc_mmap[i].v4l2_buf.flags = V4L2_BUF_FLAG_MAPPED;
1683 :
1684 : DPRINTF(1, "%s: %s: index=%d, offset=%d, length=%d\n",
1685 : DEVNAME(sc), __func__,
1686 : sc->sc_mmap[i].v4l2_buf.index,
1687 : sc->sc_mmap[i].v4l2_buf.m.offset,
1688 : sc->sc_mmap[i].v4l2_buf.length);
1689 : }
1690 :
1691 : /* tell how many buffers we have really allocated */
1692 0 : rb->count = sc->sc_mmap_count;
1693 :
1694 0 : return (0);
1695 0 : }
1696 :
1697 : int
1698 0 : utvfu_querybuf(void *v, struct v4l2_buffer *qb)
1699 : {
1700 0 : struct utvfu_softc *sc = v;
1701 :
1702 0 : if (qb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
1703 0 : qb->memory != V4L2_MEMORY_MMAP ||
1704 0 : qb->index >= sc->sc_mmap_count)
1705 0 : return (EINVAL);
1706 :
1707 0 : memcpy(qb, &sc->sc_mmap[qb->index].v4l2_buf,
1708 : sizeof(struct v4l2_buffer));
1709 :
1710 : DPRINTF(1, "%s: %s: index=%d, offset=%d, length=%d\n",
1711 : DEVNAME(sc), __func__, qb->index, qb->m.offset, qb->length);
1712 :
1713 0 : return (0);
1714 0 : }
1715 :
1716 : int
1717 0 : utvfu_qbuf(void *v, struct v4l2_buffer *qb)
1718 : {
1719 0 : struct utvfu_softc *sc = v;
1720 :
1721 0 : if (qb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
1722 0 : qb->memory != V4L2_MEMORY_MMAP ||
1723 0 : qb->index >= sc->sc_mmap_count)
1724 0 : return (EINVAL);
1725 :
1726 0 : sc->sc_mmap[qb->index].v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
1727 0 : sc->sc_mmap[qb->index].v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED;
1728 0 : sc->sc_mmap[qb->index].v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED;
1729 :
1730 : DPRINTF(2, "%s: %s: buffer on index %d ready for queueing\n",
1731 : DEVNAME(sc), __func__, qb->index);
1732 :
1733 0 : return (0);
1734 0 : }
1735 :
1736 : int
1737 0 : utvfu_dqbuf(void *v, struct v4l2_buffer *dqb)
1738 : {
1739 0 : struct utvfu_softc *sc = v;
1740 : struct utvfu_mmap *mmap;
1741 : int error;
1742 :
1743 0 : if (dqb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
1744 0 : dqb->memory != V4L2_MEMORY_MMAP)
1745 0 : return (EINVAL);
1746 :
1747 0 : if (SIMPLEQ_EMPTY(&sc->sc_mmap_q)) {
1748 : /* mmap queue is empty, block until first frame is queued */
1749 0 : error = tsleep(sc, 0, "vid_mmap", 10 * hz);
1750 0 : if (error)
1751 0 : return (EINVAL);
1752 : }
1753 :
1754 0 : mmap = SIMPLEQ_FIRST(&sc->sc_mmap_q);
1755 0 : if (mmap == NULL)
1756 0 : panic("utvfu_dqbuf: NULL pointer!");
1757 :
1758 0 : memcpy(dqb, &mmap->v4l2_buf, sizeof(struct v4l2_buffer));
1759 :
1760 0 : mmap->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_DONE|V4L2_BUF_FLAG_QUEUED);
1761 0 : mmap->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED;
1762 :
1763 : DPRINTF(2, "%s: %s: frame dequeued from index %d\n",
1764 : DEVNAME(sc), __func__, mmap->v4l2_buf.index);
1765 0 : SIMPLEQ_REMOVE_HEAD(&sc->sc_mmap_q, q_frames);
1766 :
1767 0 : return (0);
1768 0 : }
1769 :
1770 : int
1771 0 : utvfu_streamon(void *v, int type)
1772 : {
1773 0 : struct utvfu_softc *sc = v;
1774 : usbd_status error;
1775 :
1776 : /* open video stream pipe */
1777 0 : error = utvfu_vs_open(sc);
1778 0 : if (error != USBD_NORMAL_COMPLETION)
1779 0 : return (EINVAL);
1780 :
1781 0 : utvfu_vs_start_isoc(sc);
1782 :
1783 0 : return (0);
1784 0 : }
1785 :
1786 : int
1787 0 : utvfu_streamoff(void *v, int type)
1788 : {
1789 0 : utvfu_vs_close(v);
1790 0 : return (0);
1791 : }
1792 :
1793 : int
1794 0 : utvfu_queryctrl(void *v, struct v4l2_queryctrl *qctrl)
1795 : {
1796 0 : qctrl->flags = V4L2_CTRL_FLAG_DISABLED;
1797 0 : return (0);
1798 : }
1799 :
1800 : int
1801 0 : utvfu_g_parm(void *v, struct v4l2_streamparm *parm)
1802 : {
1803 0 : struct utvfu_softc *sc = v;
1804 :
1805 0 : if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1806 0 : return (EINVAL);
1807 : /*
1808 : * XXX Unsure whether there is a way to negotiate this with the
1809 : * device, but returning 0 will allow xenocara's video to run
1810 : */
1811 0 : switch (utvfu_norm_params[sc->sc_normi].norm) {
1812 : default:
1813 0 : return (EINVAL);
1814 : case V4L2_STD_525_60:
1815 0 : parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
1816 0 : parm->parm.capture.capturemode = 0;
1817 0 : parm->parm.capture.timeperframe.numerator = 30;
1818 0 : parm->parm.capture.timeperframe.denominator = 1;
1819 0 : break;
1820 : case V4L2_STD_PAL:
1821 0 : parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
1822 0 : parm->parm.capture.capturemode = 0;
1823 0 : parm->parm.capture.timeperframe.numerator = 25;
1824 0 : parm->parm.capture.timeperframe.denominator = 1;
1825 0 : break;
1826 : }
1827 0 : return (0);
1828 0 : }
1829 :
1830 : int
1831 0 : utvfu_s_parm(void *v, struct v4l2_streamparm *parm)
1832 : {
1833 0 : if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1834 0 : return (EINVAL);
1835 0 : return (0);
1836 0 : }
1837 :
1838 : /*
1839 : * A U D I O O P S
1840 : */
1841 :
1842 : int
1843 0 : utvfu_audio_open(void *v, int flags)
1844 : {
1845 0 : struct utvfu_softc *sc = v;
1846 :
1847 0 : if (usbd_is_dying(sc->sc_udev))
1848 0 : return (EIO);
1849 :
1850 0 : if ((flags & FWRITE))
1851 0 : return (ENXIO);
1852 :
1853 0 : if (ISSET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING))
1854 0 : return (EBUSY);
1855 :
1856 0 : return utvfu_as_init(sc);
1857 0 : }
1858 :
1859 : void
1860 0 : utvfu_audio_close(void *v)
1861 : {
1862 0 : struct utvfu_softc *sc = v;
1863 :
1864 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1865 :
1866 0 : utvfu_audio_stop(sc);
1867 0 : utvfu_audio_clear_client(sc);
1868 0 : }
1869 :
1870 : int
1871 0 : utvfu_audio_set_params(void *v, int setmode, int usemode,
1872 : struct audio_params *play, struct audio_params *rec)
1873 : {
1874 0 : struct utvfu_softc *sc = v;
1875 :
1876 0 : if (usbd_is_dying(sc->sc_udev))
1877 0 : return (EIO);
1878 :
1879 : DPRINTF(1, "%s %s\n", DEVNAME(sc), __func__);
1880 :
1881 : /* XXX ? */
1882 0 : play->sample_rate = 0;
1883 0 : play->encoding = AUDIO_ENCODING_NONE;
1884 :
1885 0 : rec->sample_rate = 48000;
1886 0 : rec->encoding = AUDIO_ENCODING_SLINEAR_LE;
1887 0 : rec->precision = 16;
1888 0 : rec->bps = 2;
1889 0 : rec->msb = 1;
1890 0 : rec->channels = 2;
1891 :
1892 0 : return (0);
1893 0 : }
1894 :
1895 : int
1896 0 : utvfu_audio_halt_out(void *v)
1897 : {
1898 0 : return (EIO);
1899 : }
1900 :
1901 : int
1902 0 : utvfu_audio_halt_in(void *v)
1903 : {
1904 0 : struct utvfu_softc *sc = v;
1905 :
1906 0 : if (usbd_is_dying(sc->sc_udev))
1907 0 : return (EIO);
1908 :
1909 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
1910 :
1911 0 : utvfu_audio_stop(sc);
1912 0 : utvfu_audio_clear_client(sc);
1913 :
1914 0 : return (0);
1915 0 : }
1916 :
1917 : int
1918 0 : utvfu_audio_mixer_set_port(void *v, struct mixer_ctrl *cp)
1919 : {
1920 0 : struct utvfu_softc *sc = v;
1921 :
1922 0 : if (usbd_is_dying(sc->sc_udev))
1923 0 : return (EIO);
1924 :
1925 : DPRINTF(1, "%s %s\n", DEVNAME(sc), __func__);
1926 :
1927 0 : if (cp->type != AUDIO_MIXER_ENUM ||
1928 0 : cp->un.ord < 0 || cp->un.ord > 1)
1929 0 : return (EINVAL);
1930 : /* XXX TODO */
1931 : DPRINTF(1, "%s %s: cp->un.ord=%d\n", DEVNAME(sc), __func__, cp->un.ord);
1932 0 : return (0);
1933 0 : }
1934 :
1935 : int
1936 0 : utvfu_audio_mixer_get_port(void *v, struct mixer_ctrl *cp)
1937 : {
1938 0 : struct utvfu_softc *sc = v;
1939 :
1940 0 : if (usbd_is_dying(sc->sc_udev))
1941 0 : return (EIO);
1942 :
1943 : DPRINTF(1, "%s %s\n", DEVNAME(sc), __func__);
1944 :
1945 0 : if (cp->type != AUDIO_MIXER_ENUM ||
1946 0 : cp->un.ord < 0 || cp->un.ord > 1)
1947 0 : return (EINVAL);
1948 : /* XXX TODO */
1949 : DPRINTF(1, "%s %s: cp->un.ord=%d\n", DEVNAME(sc), __func__, cp->un.ord);
1950 0 : return (0);
1951 0 : }
1952 :
1953 : int
1954 0 : utvfu_audio_query_devinfo(void *v, struct mixer_devinfo *mi)
1955 : {
1956 0 : struct utvfu_softc *sc = v;
1957 :
1958 0 : if (usbd_is_dying(sc->sc_udev))
1959 0 : return (EIO);
1960 :
1961 : DPRINTF(1, "%s %s\n", DEVNAME(sc), __func__);
1962 :
1963 0 : if (mi->index != 0)
1964 0 : return (EINVAL);
1965 :
1966 : /* XXX SOMEONE WITH AUDIO EXPERTIZE NEEDS TO HELP HERE */
1967 0 : strlcpy(mi->label.name, "mix0-i0", sizeof(mi->label.name));
1968 0 : mi->type = AUDIO_MIXER_ENUM;
1969 0 : mi->un.e.num_mem = 2;
1970 0 : mi->un.e.member[0].ord = 0;
1971 0 : strlcpy(mi->un.e.member[0].label.name, AudioNoff,
1972 : sizeof(mi->un.e.member[0].label.name));
1973 0 : mi->un.e.member[1].ord = 1;
1974 0 : strlcpy(mi->un.e.member[1].label.name, AudioNon,
1975 : sizeof(mi->un.e.member[1].label.name));
1976 :
1977 0 : return (0);
1978 0 : }
1979 :
1980 : int
1981 0 : utvfu_audio_get_props(void *v)
1982 : {
1983 0 : return (0);
1984 : }
1985 :
1986 : int
1987 0 : utvfu_audio_trigger_output(void *v, void *start, void *end, int blksize,
1988 : void (*intr)(void *), void *arg, struct audio_params *param)
1989 : {
1990 0 : return (EIO);
1991 : }
1992 :
1993 : int
1994 0 : utvfu_audio_trigger_input(void *v, void *start, void *end, int blksize,
1995 : void (*intr)(void *), void *arg, struct audio_params *param)
1996 : {
1997 0 : struct utvfu_softc *sc = v;
1998 :
1999 0 : if (usbd_is_dying(sc->sc_udev))
2000 0 : return (EIO);
2001 :
2002 0 : rw_enter_write(&sc->sc_audio.rwlock);
2003 :
2004 0 : sc->sc_audio.intr_arg = arg;
2005 0 : sc->sc_audio.intr = intr;
2006 0 : sc->sc_audio.start = start;
2007 0 : sc->sc_audio.end = end;
2008 0 : sc->sc_audio.cur = start;
2009 0 : sc->sc_audio.blksize = blksize;
2010 :
2011 0 : rw_exit_write(&sc->sc_audio.rwlock);
2012 :
2013 : DPRINTF(1, "%s %s: start=%p end=%p diff=%lu blksize=%d\n",
2014 : DEVNAME(sc), __func__, start, end,
2015 : ((u_char *)end - (u_char *)start), blksize);
2016 :
2017 0 : return utvfu_audio_start(sc);
2018 0 : }
2019 :
2020 : int
2021 0 : utvfu_audio_start(struct utvfu_softc *sc)
2022 : {
2023 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
2024 :
2025 0 : if (ISSET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING))
2026 0 : return (0);
2027 :
2028 0 : utvfu_audio_start_chip(sc);
2029 :
2030 0 : if (utvfu_as_init(sc) != 0)
2031 0 : return (ENOMEM);
2032 0 : if (sc->sc_audio.iface.pipeh == NULL) {
2033 0 : if (utvfu_as_open(sc) != USBD_NORMAL_COMPLETION)
2034 0 : return (ENOMEM);
2035 : }
2036 :
2037 0 : return utvfu_as_start_bulk(sc);
2038 0 : }
2039 :
2040 : int
2041 0 : utvfu_audio_stop(struct utvfu_softc *sc)
2042 : {
2043 : DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
2044 :
2045 0 : utvfu_audio_stop_chip(sc);
2046 0 : utvfu_as_free(sc);
2047 :
2048 0 : return (0);
2049 : }
|