xref: /illumos-gate/usr/src/uts/common/io/usb/clients/video/usbvc/usbvc_v4l2.c (revision bb0ade0978a02d3fe0b0165cd4725fdcb593fbfb)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * USB video class driver: V4L2 interface implementation.
30  */
31 
32 #include <sys/usb/usba.h>
33 #include <sys/fcntl.h>
34 #include <sys/cmn_err.h>
35 
36 #include <sys/usb/clients/video/usbvc/usbvc_var.h>
37 #include <sys/usb/clients/video/usbvc/usbvc.h>
38 #include <sys/videodev2.h>
39 
40 static int usbvc_v4l2_set_format(usbvc_state_t *, struct v4l2_format *);
41 static int usbvc_v4l2_get_format(usbvc_state_t *, struct v4l2_format *);
42 static void usbvc_v4l2_query_buf(usbvc_state_t *, usbvc_buf_t *,
43 				struct v4l2_buffer *);
44 static int usbvc_v4l2_enqueue_buf(usbvc_state_t *, usbvc_buf_t *,
45 				struct v4l2_buffer *);
46 static int usbvc_v4l2_dequeue_buffer(usbvc_state_t *,
47 				struct v4l2_buffer *, int);
48 static int usbvc_v4l2_query_ctrl(usbvc_state_t *, struct v4l2_queryctrl *);
49 static int usbvc_v4l2_get_ctrl(usbvc_state_t *, struct v4l2_control *);
50 static int usbvc_v4l2_set_ctrl(usbvc_state_t *, struct v4l2_control *);
51 static int usbvc_v4l2_set_parm(usbvc_state_t *, struct v4l2_streamparm *);
52 static int usbvc_v4l2_get_parm(usbvc_state_t *, struct v4l2_streamparm *);
53 /* Video controls that supported by usbvc driver */
54 static usbvc_v4l2_ctrl_map_t usbvc_v4l2_ctrls[] = {
55 	{
56 		"Brightness",
57 		PU_BRIGHTNESS_CONTROL,
58 		2,
59 		0,
60 		V4L2_CTRL_TYPE_INTEGER
61 	},
62 	{
63 		"Contrast",
64 		PU_CONTRAST_CONTROL,
65 		2,
66 		1,
67 		V4L2_CTRL_TYPE_INTEGER
68 	},
69 	{
70 		"Saturation",
71 		PU_SATURATION_CONTROL,
72 		2,
73 		3,
74 		V4L2_CTRL_TYPE_INTEGER
75 	},
76 	{
77 		"Hue",
78 		PU_HUE_CONTROL,
79 		2,
80 		2,
81 		V4L2_CTRL_TYPE_INTEGER
82 	},
83 	{
84 		"Gamma",
85 		PU_GAMMA_CONTROL,
86 		2,
87 		5,
88 		V4L2_CTRL_TYPE_INTEGER
89 	}
90 };
91 
92 
93 /*
94  * V4L2 colorspaces.
95  */
96 static const uint8_t color_primaries[] = {
97 		0,
98 		V4L2_COLORSPACE_SRGB,
99 		V4L2_COLORSPACE_470_SYSTEM_M,
100 		V4L2_COLORSPACE_470_SYSTEM_BG,
101 		V4L2_COLORSPACE_SMPTE170M,
102 		V4L2_COLORSPACE_SMPTE240M,
103 };
104 
105 /* V4L2 ioctls */
106 int
107 usbvc_v4l2_ioctl(usbvc_state_t *usbvcp, int cmd, intptr_t arg, int mode)
108 {
109 	int	rv = 0;
110 
111 	switch (cmd) {
112 	case VIDIOC_QUERYCAP:	/* Query capabilities */
113 	{
114 		struct v4l2_capability caps;
115 
116 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
117 		    "V4L2 ioctl: VIDIOC_QUERYCAP");
118 		bzero(&caps, sizeof (caps));
119 		(void) strncpy((char *)&caps.driver, "usbvc",
120 		    sizeof (caps.driver));
121 		if (usbvcp->usbvc_reg->dev_product) {
122 			(void) strncpy((char *)&caps.card,
123 			    usbvcp->usbvc_reg->dev_product, sizeof (caps.card));
124 		} else {
125 			(void) strncpy((char *)&caps.card, "Generic USB video"
126 			    "class device", sizeof (caps.card));
127 		}
128 		(void) strncpy((char *)&caps.bus_info, "usb",
129 		    sizeof (caps.bus_info));
130 		caps.version = 1;
131 		caps.capabilities = V4L2_CAP_VIDEO_CAPTURE
132 		    | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
133 		USBVC_COPYOUT(caps);
134 
135 		break;
136 	}
137 	case VIDIOC_ENUM_FMT:
138 	{
139 		struct v4l2_fmtdesc	fmtdesc;
140 		usbvc_format_group_t	*fmtgrp;
141 		usbvc_stream_if_t	*strm_if;
142 
143 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
144 		    "V4L2 ioctl: VIDIOC_ENUM_FMT");
145 		USBVC_COPYIN(fmtdesc);
146 		mutex_enter(&usbvcp->usbvc_mutex);
147 		strm_if = usbvcp->usbvc_curr_strm;
148 		if (fmtdesc.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
149 		    fmtdesc.index >= strm_if->fmtgrp_cnt) {
150 			rv = EINVAL;
151 			mutex_exit(&usbvcp->usbvc_mutex);
152 
153 			break;
154 		}
155 		fmtgrp = &strm_if->format_group[fmtdesc.index];
156 		fmtdesc.pixelformat = fmtgrp->v4l2_pixelformat;
157 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
158 		    "V4L2 ioctl: VIDIOC_ENUM_FMT, idx=%d, grpcnt=%d",
159 		    fmtdesc.index, strm_if->fmtgrp_cnt);
160 
161 		switch (fmtgrp->format->bDescriptorSubType) {
162 		case VS_FORMAT_MJPEG:
163 			fmtdesc.flags = V4L2_FMT_FLAG_COMPRESSED;
164 			(void) strncpy(fmtdesc.description, "MJPEG",
165 			    sizeof (fmtdesc.description));
166 
167 			break;
168 		case VS_FORMAT_UNCOMPRESSED:
169 			fmtdesc.flags = 0;
170 			if (fmtdesc.pixelformat == V4L2_PIX_FMT_YUYV) {
171 				(void) strncpy(fmtdesc.description, "YUYV",
172 				    sizeof (fmtdesc.description));
173 			} else if (fmtdesc.pixelformat == V4L2_PIX_FMT_NV12) {
174 				(void) strncpy(fmtdesc.description, "NV12",
175 				    sizeof (fmtdesc.description));
176 			} else {
177 				(void) strncpy(fmtdesc.description,
178 				    "Unknown format",
179 				    sizeof (fmtdesc.description));
180 			}
181 
182 			break;
183 		default:
184 			fmtdesc.flags = 0;
185 			(void) strncpy(fmtdesc.description, "Unknown format",
186 			    sizeof (fmtdesc.description));
187 		}
188 
189 		mutex_exit(&usbvcp->usbvc_mutex);
190 		USBVC_COPYOUT(fmtdesc);
191 
192 		break;
193 	}
194 	case VIDIOC_S_FMT:
195 	{
196 		struct v4l2_format	fmt;
197 		usbvc_stream_if_t	*strm_if;
198 
199 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
200 		    "V4L2 ioctl: VIDIOC_S_FMT");
201 		mutex_enter(&usbvcp->usbvc_mutex);
202 		strm_if = usbvcp->usbvc_curr_strm;
203 
204 		/* If data I/O is in progress */
205 		if (strm_if->start_polling == 1) {
206 			rv = EBUSY;
207 			mutex_exit(&usbvcp->usbvc_mutex);
208 
209 			break;
210 		}
211 		mutex_exit(&usbvcp->usbvc_mutex);
212 
213 		USBVC_COPYIN(fmt);
214 		if (usbvc_v4l2_set_format(usbvcp, &fmt) != USB_SUCCESS) {
215 			rv = EFAULT;
216 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
217 			    usbvcp->usbvc_log_handle,
218 			    "V4L2 ioctl VIDIOC_S_FMT fail");
219 		}
220 		USBVC_COPYOUT(fmt);
221 
222 		break;
223 	}
224 	case VIDIOC_G_FMT:
225 	{
226 		struct v4l2_format	fmt;
227 
228 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
229 		    "V4L2 ioctl: VIDIOC_G_FMT");
230 		USBVC_COPYIN(fmt);
231 
232 		if ((rv = usbvc_v4l2_get_format(usbvcp, &fmt)) != 0) {
233 
234 			break;
235 		}
236 
237 		USBVC_COPYOUT(fmt);
238 
239 		break;
240 	}
241 	case VIDIOC_REQBUFS: /* for memory mapping IO method */
242 	{
243 		struct v4l2_requestbuffers	reqbuf;
244 		uint_t				bufsize;
245 		usbvc_stream_if_t		*strm_if;
246 
247 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
248 		    "V4L2 ioctl: VIDIOC_REQBUFS");
249 		USBVC_COPYIN(reqbuf);
250 		if (reqbuf.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
251 		    reqbuf.memory != V4L2_MEMORY_MMAP) {
252 			rv = EINVAL;
253 
254 			break;
255 		}
256 		mutex_enter(&usbvcp->usbvc_mutex);
257 		strm_if = usbvcp->usbvc_curr_strm;
258 		if (!strm_if) {
259 			mutex_exit(&usbvcp->usbvc_mutex);
260 			rv = EINVAL;
261 
262 			break;
263 		}
264 		if (reqbuf.count > USBVC_MAX_MAP_BUF_NUM) {
265 			mutex_exit(&usbvcp->usbvc_mutex);
266 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
267 			    usbvcp->usbvc_log_handle,
268 			    "V4L2 ioctl: req too many buffers, fail");
269 			rv = EINVAL;
270 
271 			break;
272 		}
273 
274 		/* If some bufs were already allocated */
275 		if (strm_if->buf_map.buf_cnt) {
276 			/*
277 			 * According to v4l2 spec, application can change the
278 			 * buffer number and also free all buffers if set
279 			 * count to 0
280 			 */
281 			if (reqbuf.count == 0) {
282 				if (strm_if->start_polling == 1) {
283 					mutex_exit(&usbvcp->usbvc_mutex);
284 					usb_pipe_stop_isoc_polling(
285 					    strm_if->datain_ph,
286 					    USB_FLAGS_SLEEP);
287 					mutex_enter(&usbvcp->usbvc_mutex);
288 					strm_if->start_polling = 0;
289 				}
290 				usbvc_free_map_bufs(usbvcp, strm_if);
291 				mutex_exit(&usbvcp->usbvc_mutex);
292 
293 				break;
294 			}
295 			if (reqbuf.count == strm_if->buf_map.buf_cnt) {
296 				mutex_exit(&usbvcp->usbvc_mutex);
297 				USB_DPRINTF_L2(PRINT_MASK_IOCTL,
298 				    usbvcp->usbvc_log_handle,
299 				    "v4l2 ioctls: req the same buffers"
300 				    " as we already have, just return success");
301 
302 				break;
303 			} else {
304 				/*
305 				 * req different number of bufs, according to
306 				 * v4l2 spec, this is not allowed when there
307 				 * are some bufs still mapped.
308 				 */
309 				mutex_exit(&usbvcp->usbvc_mutex);
310 				USB_DPRINTF_L2(PRINT_MASK_IOCTL,
311 				    usbvcp->usbvc_log_handle,
312 				    "v4l2 ioctls: req different number bufs"
313 				    "than the exist ones, fail");
314 				rv = EINVAL;
315 
316 				break;
317 			}
318 		}
319 
320 		if (reqbuf.count == 0) {
321 			mutex_exit(&usbvcp->usbvc_mutex);
322 			rv = EINVAL;
323 
324 			break;
325 		}
326 		LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0, bufsize);
327 		if ((reqbuf.count =
328 		    (uint32_t)usbvc_alloc_map_bufs(usbvcp, strm_if,
329 		    reqbuf.count, bufsize)) == 0) {
330 			mutex_exit(&usbvcp->usbvc_mutex);
331 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
332 			    usbvcp->usbvc_log_handle,
333 			    "V4L2 ioctl: VIDIOC_REQBUFS: alloc fail");
334 			rv = EINVAL;
335 
336 			break;
337 		}
338 		mutex_exit(&usbvcp->usbvc_mutex);
339 
340 		/*
341 		 * return buf number that acctually allocated to application
342 		 */
343 		USBVC_COPYOUT(reqbuf);
344 
345 		break;
346 	}
347 	case VIDIOC_QUERYBUF: /* for memory mapping IO method */
348 	{
349 		struct v4l2_buffer	buf;
350 		usbvc_buf_grp_t		*usbvc_bufg;
351 
352 		USBVC_COPYIN(buf);
353 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
354 		    "V4L2 ioctl: VIDIOC_QUERYBUF: idx=%d", buf.index);
355 		mutex_enter(&usbvcp->usbvc_mutex);
356 		usbvc_bufg = &usbvcp->usbvc_curr_strm->buf_map;
357 		if ((buf.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
358 		    (buf.index >= usbvc_bufg->buf_cnt)) {
359 			mutex_exit(&usbvcp->usbvc_mutex);
360 			rv = EINVAL;
361 
362 			break;
363 		}
364 
365 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
366 		    "V4L2 ioctl: VIDIOC_QUERYBUF: len=%d",
367 		    usbvc_bufg->buf_head[buf.index].v4l2_buf.length);
368 
369 		usbvc_v4l2_query_buf(usbvcp, &usbvc_bufg->buf_head[buf.index],
370 		    &buf);
371 		mutex_exit(&usbvcp->usbvc_mutex);
372 		USBVC_COPYOUT(buf);
373 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
374 		    "V4L2 ioctl: VIDIOC_QUERYBUF,(index=%d)len=%d",
375 		    buf.index, buf.length);
376 
377 		break;
378 	}
379 	case VIDIOC_QBUF:
380 	{
381 		struct v4l2_buffer	buf;
382 		usbvc_buf_grp_t		*usbvc_bufg;
383 
384 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
385 		    "V4L2 ioctl: VIDIOC_QBUF");
386 		USBVC_COPYIN(buf);
387 		mutex_enter(&usbvcp->usbvc_mutex);
388 		usbvc_bufg = &usbvcp->usbvc_curr_strm->buf_map;
389 
390 		if ((buf.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
391 		    (buf.index >= usbvc_bufg->buf_cnt) ||
392 		    (buf.memory != V4L2_MEMORY_MMAP)) {
393 			mutex_exit(&usbvcp->usbvc_mutex);
394 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
395 			    usbvcp->usbvc_log_handle,  "V4L2 ioctl: "
396 			    "VIDIOC_QBUF error:index=%d,type=%d,memory=%d",
397 			    buf.index, buf.type, buf.memory);
398 			rv = EINVAL;
399 
400 			break;
401 		}
402 		rv = usbvc_v4l2_enqueue_buf(usbvcp,
403 		    &usbvc_bufg->buf_head[buf.index], &buf);
404 		if (rv < 0) {
405 			mutex_exit(&usbvcp->usbvc_mutex);
406 
407 			break;
408 		}
409 		mutex_exit(&usbvcp->usbvc_mutex);
410 		USBVC_COPYOUT(buf);
411 
412 		break;
413 	}
414 
415 	case VIDIOC_DQBUF:
416 	{
417 		struct v4l2_buffer	buf;
418 
419 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
420 		    "V4L2 ioctl: VIDIOC_DQBUF");
421 		USBVC_COPYIN(buf);
422 		mutex_enter(&usbvcp->usbvc_mutex);
423 		if ((rv = usbvc_v4l2_dequeue_buffer(usbvcp, &buf, mode)) != 0) {
424 			mutex_exit(&usbvcp->usbvc_mutex);
425 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
426 			    usbvcp->usbvc_log_handle, "V4L2 ioctl: "
427 			    "VIDIOC_DQBUF: fail, rv=%d", rv);
428 
429 			break;
430 		}
431 		mutex_exit(&usbvcp->usbvc_mutex);
432 		USBVC_COPYOUT(buf);
433 
434 		break;
435 	}
436 
437 	case VIDIOC_STREAMON:
438 	{
439 		int			type; /* v4l2_buf_type */
440 		usbvc_stream_if_t	*strm_if;
441 
442 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
443 		    "V4L2 ioctl: VIDIOC_STREAMON");
444 		USBVC_COPYIN(type);
445 		mutex_enter(&usbvcp->usbvc_mutex);
446 		strm_if = usbvcp->usbvc_curr_strm;
447 		if (!strm_if) {
448 			mutex_exit(&usbvcp->usbvc_mutex);
449 			rv = EINVAL;
450 
451 			break;
452 		}
453 		if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
454 			mutex_exit(&usbvcp->usbvc_mutex);
455 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
456 			    usbvcp->usbvc_log_handle, "V4L2 ioctl: "
457 			    "VIDIOC_STREAMON: fail. Only capture type is"
458 			    " supported by now.");
459 			rv = EINVAL;
460 
461 			break;
462 		}
463 		/* if the first read, open isoc pipe */
464 		if (!strm_if->datain_ph) {
465 			if (usbvc_open_isoc_pipe(usbvcp, strm_if) !=
466 			    USB_SUCCESS) {
467 				mutex_exit(&usbvcp->usbvc_mutex);
468 				USB_DPRINTF_L2(PRINT_MASK_IOCTL,
469 				    usbvcp->usbvc_log_handle, "V4L2 ioctl:"
470 				    " first read, open pipe fail");
471 				rv = EINVAL;
472 
473 				break;
474 			}
475 		}
476 		/* If it is already started */
477 		if (strm_if->start_polling == 1) {
478 			mutex_exit(&usbvcp->usbvc_mutex);
479 
480 			break;
481 		}
482 		/* At present, VIDIOC_STREAMON supports mmap io only. */
483 		if (usbvc_start_isoc_polling(usbvcp, strm_if,
484 		    V4L2_MEMORY_MMAP) != USB_SUCCESS) {
485 			rv = EFAULT;
486 			mutex_exit(&usbvcp->usbvc_mutex);
487 
488 			break;
489 		}
490 		strm_if->start_polling = 1;
491 
492 		mutex_exit(&usbvcp->usbvc_mutex);
493 
494 		break;
495 	}
496 
497 	case VIDIOC_STREAMOFF:
498 	{
499 		int			type;	/* v4l2_buf_type */
500 		usbvc_stream_if_t	*strm_if;
501 
502 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
503 		    "V4L2 ioctl: VIDIOC_STREAMOFF");
504 		USBVC_COPYIN(type);
505 		mutex_enter(&usbvcp->usbvc_mutex);
506 		strm_if = usbvcp->usbvc_curr_strm;
507 		if (!strm_if) {
508 			mutex_exit(&usbvcp->usbvc_mutex);
509 			rv = EINVAL;
510 
511 			break;
512 		}
513 		if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
514 			mutex_exit(&usbvcp->usbvc_mutex);
515 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
516 			    usbvcp->usbvc_log_handle, "V4L2 ioctl: "
517 			    "VIDIOC_STREAMON: fail. Only capture type is "
518 			    "supported by now.");
519 			rv = EINVAL;
520 
521 			break;
522 		}
523 
524 		/* Need close the isoc data pipe if any reads are performed. */
525 		strm_if = usbvcp->usbvc_curr_strm;
526 		if (strm_if->start_polling == 1) {
527 			mutex_exit(&usbvcp->usbvc_mutex);
528 			usb_pipe_stop_isoc_polling(strm_if->datain_ph,
529 			    USB_FLAGS_SLEEP);
530 			mutex_enter(&usbvcp->usbvc_mutex);
531 			strm_if->start_polling = 0;
532 		}
533 		mutex_exit(&usbvcp->usbvc_mutex);
534 
535 		break;
536 	}
537 
538 	case VIDIOC_ENUMINPUT:
539 	{
540 		struct v4l2_input input;
541 
542 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
543 		    "V4L2 ioctl: ENUMINPUT");
544 		USBVC_COPYIN(input);
545 
546 		if (input.index != 0) { /* Support only one INPUT now */
547 			rv = EINVAL;
548 
549 			break;
550 		}
551 		(void) strncpy((char *)input.name, "Camera Terminal",
552 		    sizeof (input.name));
553 		input.type = V4L2_INPUT_TYPE_CAMERA;
554 		USBVC_COPYOUT(input);
555 
556 		break;
557 	}
558 
559 	case VIDIOC_G_INPUT:
560 	{
561 		int input_idx = 0;	/* Support only one input now */
562 
563 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
564 		    "V4L2 ioctl: G_INPUT");
565 		USBVC_COPYOUT(input_idx);
566 
567 		break;
568 	}
569 
570 	case VIDIOC_S_INPUT:
571 	{
572 		int input_idx;
573 
574 		USBVC_COPYIN(input_idx);
575 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
576 		    "V4L2 ioctl: S_INPUT");
577 		if (input_idx != 0) {	/* Support only one input now */
578 			rv = EINVAL;
579 		}
580 
581 		break;
582 	}
583 
584 	/* Query the device that what kinds of video ctrls are supported */
585 	case VIDIOC_QUERYCTRL:
586 	{
587 		struct v4l2_queryctrl queryctrl;
588 
589 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
590 		    "V4L2 ioctl: QUERYCTRL");
591 		USBVC_COPYIN(queryctrl);
592 
593 		if (usbvc_v4l2_query_ctrl(usbvcp, &queryctrl) != USB_SUCCESS) {
594 			rv = EINVAL;
595 
596 			break;
597 		}
598 
599 		USBVC_COPYOUT(queryctrl);
600 
601 		break;
602 	}
603 	case VIDIOC_G_CTRL:
604 	{
605 		struct v4l2_control ctrl;
606 
607 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
608 		    "V4L2 ioctl: G_CTRL");
609 		USBVC_COPYIN(ctrl);
610 		if (usbvc_v4l2_get_ctrl(usbvcp, &ctrl) != USB_SUCCESS) {
611 			rv = EINVAL;
612 
613 			break;
614 		}
615 
616 		USBVC_COPYOUT(ctrl);
617 
618 		break;
619 	}
620 	case VIDIOC_S_CTRL:
621 	{
622 		struct v4l2_control ctrl;
623 
624 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
625 		    "V4L2 ioctl: S_CTRL");
626 		USBVC_COPYIN(ctrl);
627 		if (usbvc_v4l2_set_ctrl(usbvcp, &ctrl) != USB_SUCCESS) {
628 			rv = EINVAL;
629 
630 			break;
631 		}
632 
633 		USBVC_COPYOUT(ctrl);
634 
635 		break;
636 	}
637 	case VIDIOC_S_PARM:
638 	{
639 		struct v4l2_streamparm	parm;
640 		usbvc_stream_if_t	*strm_if;
641 
642 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
643 		    "V4L2 ioctl: VIDIOC_S_PARM");
644 		mutex_enter(&usbvcp->usbvc_mutex);
645 		strm_if = usbvcp->usbvc_curr_strm;
646 
647 		/* If data I/O is in progress */
648 		if (strm_if->start_polling == 1) {
649 			rv = EBUSY;
650 			mutex_exit(&usbvcp->usbvc_mutex);
651 
652 			break;
653 		}
654 		mutex_exit(&usbvcp->usbvc_mutex);
655 
656 		USBVC_COPYIN(parm);
657 
658 		/* Support capture only, so far. */
659 		if (parm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
660 			rv = EINVAL;
661 
662 			break;
663 		}
664 
665 		if (usbvc_v4l2_set_parm(usbvcp, &parm) != USB_SUCCESS) {
666 			rv = EINVAL;
667 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
668 			    usbvcp->usbvc_log_handle,
669 			    "V4L2 ioctl VIDIOC_S_PARM fail");
670 		}
671 		USBVC_COPYOUT(parm);
672 
673 		break;
674 	}
675 	case VIDIOC_G_PARM:
676 	{
677 		struct v4l2_streamparm	parm;
678 
679 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
680 		    "V4L2 ioctl: VIDIOC_G_PARM");
681 		USBVC_COPYIN(parm);
682 
683 		/* Support capture only, so far. */
684 		if (parm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
685 			rv = EINVAL;
686 
687 			break;
688 		}
689 
690 		if ((rv = usbvc_v4l2_get_parm(usbvcp, &parm)) != USB_SUCCESS) {
691 
692 			break;
693 		}
694 
695 		USBVC_COPYOUT(parm);
696 
697 		break;
698 	}
699 	/* These ioctls are for analog video standards. */
700 	case VIDIOC_G_STD:
701 	case VIDIOC_S_STD:
702 	case VIDIOC_ENUMSTD:
703 	case VIDIOC_QUERYSTD:
704 		rv = EINVAL;
705 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
706 		    "usbvc_v4l2_ioctl: not a supported cmd, cmd=%x", cmd);
707 
708 		break;
709 	default:
710 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
711 		    "usbvc_v4l2_ioctl: not a valid cmd value, cmd=%x", cmd);
712 		rv = ENOTTY;
713 	}
714 
715 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
716 	    "usbvc_v4l2_ioctl: exit, rv=%d", rv);
717 
718 	return (rv);
719 
720 }
721 
722 
723 /*
724  * Convert GUID in uncompressed format descriptor to the pixelformat element
725  * in struct v4l2_pix_format
726  */
727 uint32_t
728 usbvc_v4l2_guid2fcc(uint8_t *guid)
729 {
730 	uint32_t ret;
731 
732 	uint8_t y[16] = USBVC_FORMAT_GUID_YUY2;
733 	uint8_t n[16] = USBVC_FORMAT_GUID_NV12;
734 	if (!memcmp((void *)guid, (void *) &y[0], 16)) {
735 		ret = V4L2_PIX_FMT_YUYV;
736 
737 		return (ret);
738 	}
739 	if (!memcmp((void *)guid, (void *) &n, 16)) {
740 		ret = V4L2_PIX_FMT_NV12;
741 
742 		return (ret);
743 	}
744 
745 	return (0);
746 }
747 
748 
749 /*
750  * Find a frame which has the closest image size as the input args
751  * (width, height)
752  */
753 static usbvc_frames_t *
754 usbvc_match_image_size(uint32_t width, uint32_t height,
755     usbvc_format_group_t *fmtgrp)
756 {
757 	uint32_t w, h, diff, sz, i;
758 	usbvc_frames_t *frame = NULL;
759 	usbvc_frame_descr_t *descr;
760 
761 	diff = 0xffffffff;
762 
763 	for (i = 0; i < fmtgrp->frame_cnt; i++) {
764 
765 		descr = fmtgrp->frames[i].descr;
766 		if (descr == NULL) {
767 
768 			continue;
769 		}
770 		LE_TO_UINT16(descr->wWidth, 0, w);
771 		LE_TO_UINT16(descr->wHeight, 0, h);
772 
773 		sz = min(w, width) * min(h, height);
774 		sz = (w * h + width * height - sz * 2);
775 		if (sz < diff) {
776 			frame = &fmtgrp->frames[i];
777 			diff = sz;
778 		}
779 
780 		if (diff == 0) {
781 
782 			return (frame);
783 		}
784 	}
785 
786 	return (frame);
787 }
788 
789 
790 /* Implement ioctl VIDIOC_S_FMT, set a video format */
791 static int
792 usbvc_v4l2_set_format(usbvc_state_t *usbvcp, struct v4l2_format *format)
793 {
794 	usbvc_vs_probe_commit_t	ctrl, ctrl_max, ctrl_min, ctrl_curr;
795 	usbvc_stream_if_t	*strm_if;
796 	usbvc_format_group_t	*fmtgrp;
797 	usbvc_frames_t		*frame;
798 	uint32_t		w, h, interval, bandwidth;
799 	uint8_t			type, i;
800 
801 	mutex_enter(&usbvcp->usbvc_mutex);
802 
803 	/*
804 	 * Get the first stream interface. Todo: deal with multi stream
805 	 * interfaces.
806 	 */
807 	strm_if = usbvcp->usbvc_curr_strm;
808 
809 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
810 	    "usbvc_v4l2_set_format: strm_if->fmtgrp_cnt=%d",
811 	    strm_if->fmtgrp_cnt);
812 
813 	/* Find the proper format group according to compress type and guid */
814 	for (i = 0; i < strm_if->fmtgrp_cnt; i++) {
815 		fmtgrp = &strm_if->format_group[i];
816 
817 		/*
818 		 * If v4l2_pixelformat is NULL, then that means there is not
819 		 * a parsed format in format_group[i].
820 		 */
821 		if (!fmtgrp->v4l2_pixelformat || fmtgrp->frame_cnt == 0) {
822 			USB_DPRINTF_L3(PRINT_MASK_DEVCTRL,
823 			    usbvcp->usbvc_log_handle,
824 			    "usbvc_set_default_stream_fmt: no frame, fail");
825 
826 			continue;
827 		}
828 		type = fmtgrp->format->bDescriptorSubType;
829 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
830 		    "usbvc_v4l2_set_format: type =%x, i =%d", type, i);
831 
832 		if ((type == VS_FORMAT_MJPEG) ||
833 		    (type == VS_FORMAT_UNCOMPRESSED)) {
834 			if (format->fmt.pix.pixelformat ==
835 			    fmtgrp->v4l2_pixelformat) {
836 
837 				break;
838 			}
839 		}
840 	}
841 
842 	if (i >= strm_if->fmtgrp_cnt) {
843 		mutex_exit(&usbvcp->usbvc_mutex);
844 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
845 		    "usbvc_v4l2_set_format: can't find a proper format, "
846 		    "pixelformat=%x", format->fmt.pix.pixelformat);
847 
848 		return (USB_FAILURE);
849 	}
850 
851 	fmtgrp = &strm_if->format_group[i];
852 
853 	frame = usbvc_match_image_size(format->fmt.pix.width,
854 	    format->fmt.pix.height, fmtgrp);
855 
856 	if (frame == NULL) {
857 		mutex_exit(&usbvcp->usbvc_mutex);
858 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
859 		    "usbvc_v4l2_set_format: can't find a proper frame, rw=%d, "
860 		    "rh=%d", format->fmt.pix.width, format->fmt.pix.height);
861 
862 		return (USB_FAILURE);
863 	}
864 
865 	/* frame interval */
866 	LE_TO_UINT32(frame->descr->dwDefaultFrameInterval, 0, interval);
867 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
868 	    "usbvc_v4l2_set_format: Default Frame Interval=%x", interval);
869 
870 	/*
871 	 * Begin negotiate formats.
872 	 */
873 	bzero((void *)&ctrl, sizeof (usbvc_vs_probe_commit_t));
874 
875 	/* dwFrameInterval is fixed */
876 	ctrl.bmHint[0] = 1;
877 
878 	ctrl.bFormatIndex = fmtgrp->format->bFormatIndex;
879 	ctrl.bFrameIndex = frame->descr->bFrameIndex;
880 	UINT32_TO_LE(interval, 0, ctrl.dwFrameInterval);
881 
882 	mutex_exit(&usbvcp->usbvc_mutex);
883 
884 	/* Probe, just a test before the real try */
885 	if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl, VS_PROBE_CONTROL)
886 	    != USB_SUCCESS) {
887 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
888 		    "usbvc_v4l2_set_format: set probe failed");
889 
890 		return (USB_FAILURE);
891 	}
892 
893 	/* Get max values */
894 	if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_max, GET_MAX) !=
895 	    USB_SUCCESS) {
896 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
897 		    "usbvc_v4l2_set_format: get probe MAX failed");
898 
899 		return (USB_FAILURE);
900 	}
901 
902 	/* Use the best quality first */
903 	bcopy(&ctrl_max.wCompQuality, &ctrl.wCompQuality, 2);
904 
905 	/*
906 	 * By now, we've get some parametres of ctrl req, next try to set ctrl.
907 	 */
908 	for (i = 0; i < 2; i++) {
909 
910 		/* Probe */
911 		if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl,
912 		    VS_PROBE_CONTROL) != USB_SUCCESS) {
913 
914 			return (USB_FAILURE);
915 		}
916 
917 		/* Get current value after probe */
918 		if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_curr, GET_CUR)
919 		    != USB_SUCCESS) {
920 
921 			return (USB_FAILURE);
922 		}
923 		LE_TO_UINT32(ctrl_curr.dwMaxPayloadTransferSize, 0, bandwidth);
924 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
925 		    "usbvc_v4l2_set_format: bandwidth=%x", bandwidth);
926 
927 		/*
928 		 * If the bandwidth does not exceed the max value of all the
929 		 * alternatives in this interface, we done.
930 		 */
931 		if (bandwidth <= strm_if->max_isoc_payload) {
932 
933 			break;
934 		}
935 		if (i >= 1) {
936 
937 			return (USB_FAILURE);
938 		}
939 
940 		/* Get minimum values since the bandwidth is not enough */
941 		if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_min, GET_MIN) !=
942 		    USB_SUCCESS) {
943 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
944 			    usbvcp->usbvc_log_handle,
945 			    "usbvc_v4l2_set_format: get probe MIN failed");
946 
947 			return (USB_FAILURE);
948 		}
949 
950 		/* To keep simple, just use some minimum values to try again */
951 		bcopy(&ctrl_min.wKeyFrameRate, &ctrl_curr.wKeyFrameRate, 2);
952 		bcopy(&ctrl_min.wPFrameRate, &ctrl_curr.wPFrameRate, 2);
953 		bcopy(&ctrl_min.wCompWindowSize, &ctrl_curr.wCompWindowSize, 2);
954 		bcopy(&ctrl_max.wCompQuality, &ctrl_curr.wCompQuality, 2);
955 
956 		bcopy(&ctrl_curr, &ctrl,
957 		    sizeof (usbvc_vs_probe_commit_t));
958 	}
959 
960 	bcopy(&ctrl_curr, &ctrl, sizeof (usbvc_vs_probe_commit_t));
961 
962 	/* commit the values we negotiated above */
963 	if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl,
964 	    VS_COMMIT_CONTROL) != USB_SUCCESS) {
965 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
966 		    "usbvc_v4l2_set_format: set probe failed, i=%d", i);
967 
968 		return (USB_FAILURE);
969 	}
970 	mutex_enter(&usbvcp->usbvc_mutex);
971 
972 	/*
973 	 * It's good to check index here before use it. bFormatIndex is based
974 	 * on 1, and format_group[i] is based on 0, so minus 1
975 	 */
976 	i = ctrl.bFormatIndex - 1;
977 	if (i < strm_if->fmtgrp_cnt) {
978 		strm_if->cur_format_group = &strm_if->format_group[i];
979 	} else {
980 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
981 		    "usbvc_v4l2_set_format: format index out of range");
982 		mutex_exit(&usbvcp->usbvc_mutex);
983 
984 		return (USB_FAILURE);
985 	}
986 
987 	/* bFrameIndex is based on 1, and frames[i] is based on 0, so minus 1 */
988 	i = ctrl.bFrameIndex -1;
989 	if (i < strm_if->cur_format_group->frame_cnt) {
990 		strm_if->cur_format_group->cur_frame =
991 		    &strm_if->cur_format_group->frames[i];
992 	} else {
993 		mutex_exit(&usbvcp->usbvc_mutex);
994 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
995 		    "usbvc_v4l2_set_format: frame index out of range");
996 
997 		return (USB_FAILURE);
998 	}
999 
1000 	/*
1001 	 * by now, the video format is set successfully. record the current
1002 	 * setting to strm_if->ctrl_pc
1003 	 */
1004 	bcopy(&ctrl_curr, &strm_if->ctrl_pc, sizeof (usbvc_vs_probe_commit_t));
1005 
1006 	format->fmt.pix.colorspace = fmtgrp->v4l2_color;
1007 	format->fmt.pix.field = V4L2_FIELD_NONE;
1008 	format->fmt.pix.priv = 0;
1009 
1010 	LE_TO_UINT16(frame->descr->wWidth, 0, w);
1011 	LE_TO_UINT16(frame->descr->wHeight, 0, h);
1012 	format->fmt.pix.width = w;
1013 	format->fmt.pix.height = h;
1014 	format->fmt.pix.bytesperline = fmtgrp->v4l2_bpp * w;
1015 	LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0,
1016 	    format->fmt.pix.sizeimage);
1017 
1018 	mutex_exit(&usbvcp->usbvc_mutex);
1019 
1020 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1021 	    "usbvc_v4l2_set_format: dwMaxVideoFrameSize=%x, w=%x, h=%x",
1022 	    format->fmt.pix.sizeimage, w, h);
1023 
1024 	return (USB_SUCCESS);
1025 }
1026 
1027 
1028 /* Implement ioctl VIDIOC_G_FMT, get the current video format */
1029 static int
1030 usbvc_v4l2_get_format(usbvc_state_t *usbvcp, struct v4l2_format *format)
1031 {
1032 	usbvc_stream_if_t	*strm_if;
1033 	usbvc_format_group_t	*fmtgrp;
1034 	uint16_t		w, h;
1035 
1036 	if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1037 
1038 		return (EINVAL);
1039 	}
1040 	mutex_enter(&usbvcp->usbvc_mutex);
1041 
1042 	/* get the current interface. */
1043 	strm_if = usbvcp->usbvc_curr_strm;
1044 	fmtgrp = strm_if->cur_format_group;
1045 
1046 	if (!fmtgrp || !fmtgrp->cur_frame) {
1047 		mutex_exit(&usbvcp->usbvc_mutex);
1048 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1049 		    "usbvc_v4l2_get_format: fail, no current format or frame,"
1050 		    "fmtgrp=%p", (void *)fmtgrp);
1051 
1052 		return (EINVAL);
1053 	}
1054 	format->fmt.pix.colorspace = fmtgrp->v4l2_color;
1055 	format->fmt.pix.priv = 0;
1056 	format->fmt.pix.pixelformat = fmtgrp->v4l2_pixelformat;
1057 
1058 	LE_TO_UINT16(fmtgrp->cur_frame->descr->wWidth, 0, w);
1059 	LE_TO_UINT16(fmtgrp->cur_frame->descr->wHeight, 0, h);
1060 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1061 	    "v4l2 ioctl get format ");
1062 	format->fmt.pix.width = w;
1063 	format->fmt.pix.height = h;
1064 
1065 	format->fmt.pix.field = V4L2_FIELD_NONE;
1066 	format->fmt.pix.bytesperline = fmtgrp->v4l2_bpp * w;
1067 
1068 	LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0,
1069 	    format->fmt.pix.sizeimage);
1070 
1071 	mutex_exit(&usbvcp->usbvc_mutex);
1072 
1073 	return (0);
1074 }
1075 
1076 
1077 /*
1078  * Convert color space descriptor's bColorPrimaries to the colorspace element
1079  * in struct v4l2_pix_format
1080  */
1081 uint8_t
1082 usbvc_v4l2_colorspace(uint8_t color_prim)
1083 {
1084 
1085 	if (color_prim < NELEM(color_primaries)) {
1086 
1087 		return (color_primaries[color_prim]);
1088 	}
1089 
1090 	return (0);
1091 }
1092 
1093 
1094 /* Implement ioctl VIDIOC_QUERYBUF, get the buf status */
1095 static void
1096 usbvc_v4l2_query_buf(usbvc_state_t *usbvcp, usbvc_buf_t *usbvc_buf,
1097 	struct v4l2_buffer *v4l2_buf)
1098 {
1099 	ASSERT(mutex_owned(&usbvcp->usbvc_mutex));
1100 
1101 	bcopy(&(usbvc_buf->v4l2_buf), v4l2_buf, sizeof (struct v4l2_buffer));
1102 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1103 	    "usbvc_v4l2_query_buf: uv_buf_len=%d, len=%d",
1104 	    usbvc_buf->v4l2_buf.length, v4l2_buf->length);
1105 
1106 	if (usbvc_buf->status >= USBVC_BUF_MAPPED) {
1107 		v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
1108 	}
1109 
1110 	switch (usbvc_buf->status) {
1111 	case USBVC_BUF_DONE:
1112 	case USBVC_BUF_ERR:
1113 		v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
1114 
1115 		break;
1116 	case USBVC_BUF_EMPTY:
1117 		v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
1118 
1119 		break;
1120 	case USBVC_BUF_INIT:
1121 	default:
1122 
1123 		break;
1124 	}
1125 }
1126 
1127 
1128 /* Implement ioctl VIDIOC_QBUF, queue a empty buf to the free list */
1129 static int
1130 usbvc_v4l2_enqueue_buf(usbvc_state_t *usbvcp, usbvc_buf_t *usbvc_buf,
1131 	struct v4l2_buffer *buf)
1132 {
1133 	usbvc_buf_t	*donebuf;
1134 	boolean_t	queued = B_FALSE;
1135 	usbvc_buf_grp_t	*bufgrp;
1136 
1137 	ASSERT(mutex_owned(&usbvcp->usbvc_mutex));
1138 
1139 	bufgrp = &usbvcp->usbvc_curr_strm->buf_map;
1140 
1141 	if (usbvc_buf == bufgrp->buf_filling) {
1142 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1143 		    "enqueue_buffer(%d) , want to queue buf_filling, "
1144 		    "just return success", buf->index);
1145 
1146 		return (0);
1147 	}
1148 
1149 	if (!list_is_empty(&bufgrp->uv_buf_done)) {
1150 		donebuf = (usbvc_buf_t *)list_head(&bufgrp->uv_buf_done);
1151 		while (donebuf) {
1152 
1153 			if (donebuf == &(bufgrp->buf_head[buf->index])) {
1154 				queued = B_TRUE;
1155 
1156 				break;
1157 			}
1158 			donebuf = (usbvc_buf_t *)list_next(&bufgrp->uv_buf_done,
1159 			    donebuf);
1160 		}
1161 	}
1162 	if (queued) {
1163 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1164 		    "enqueue_buffer(%d), still in done list, don't insert to"
1165 		    " free list", buf->index);
1166 
1167 		return (0);
1168 	}
1169 
1170 	if (usbvc_buf->status == USBVC_BUF_EMPTY) {
1171 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1172 		    "enqueue buffer(%d), already queued.", buf->index);
1173 
1174 		return (0);
1175 
1176 	}
1177 	if (usbvc_buf->status < USBVC_BUF_MAPPED) {
1178 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1179 		    "enqueue buffer(%d), state error, not mapped.", buf->index);
1180 
1181 		return (EINVAL);
1182 	}
1183 
1184 	/*
1185 	 * The buf is put to the buf free list when allocated, so, if the buf
1186 	 * is the first time to enqueue, just change the state to empty is
1187 	 * enough.
1188 	 */
1189 	if (usbvc_buf->status == USBVC_BUF_MAPPED) {
1190 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1191 		    "queue_buffer(%d), 1st time queue this buf", buf->index);
1192 
1193 		usbvc_buf->status = USBVC_BUF_EMPTY;
1194 
1195 	} else {
1196 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1197 		    "enqueue_buffer(%d) , USBVC_BUF_EMPTY", buf->index);
1198 
1199 		usbvc_buf->status = USBVC_BUF_EMPTY;
1200 		usbvc_buf->v4l2_buf.bytesused = 0;
1201 		list_insert_tail(&bufgrp->uv_buf_free, usbvc_buf);
1202 	}
1203 	buf->flags &= ~V4L2_BUF_FLAG_DONE;
1204 	buf->flags |= V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
1205 
1206 	return (0);
1207 }
1208 
1209 
1210 /* Implement ioctl VIDIOC_DQBUF, pick a buf from done list */
1211 static int
1212 usbvc_v4l2_dequeue_buffer(usbvc_state_t *usbvcp, struct v4l2_buffer *buf,
1213 	int mode)
1214 {
1215 	usbvc_buf_t *buf_done;
1216 
1217 	ASSERT(mutex_owned(&usbvcp->usbvc_mutex));
1218 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1219 	    "usbvc_v4l2_dequeue_buffer: idx=%x", buf->index);
1220 
1221 	/* v4l2 spec: app just set type and memory field */
1222 	if ((buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
1223 	    (buf->memory != V4L2_MEMORY_MMAP)) {
1224 
1225 		return (EINVAL);
1226 	}
1227 	if ((mode & (O_NDELAY|O_NONBLOCK)) &&
1228 	    (list_is_empty(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done))) {
1229 
1230 		/* non-blocking */
1231 		return (EAGAIN);
1232 	}
1233 
1234 	/* no available buffers, block here */
1235 	while (list_is_empty(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done)) {
1236 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1237 		    "usbvc_v4l2_dequeue_buffer: wait for done buf");
1238 		if (cv_wait_sig(&usbvcp->usbvc_mapio_cv, &usbvcp->usbvc_mutex)
1239 		    <= 0) {
1240 
1241 			/* no done buf and is signaled */
1242 			return (EINTR);
1243 		}
1244 		if (usbvcp->usbvc_dev_state != USB_DEV_ONLINE) {
1245 
1246 			/* Device is disconnected. */
1247 			return (EINTR);
1248 		}
1249 	}
1250 
1251 	buf_done = list_head(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done);
1252 
1253 	list_remove(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done, buf_done);
1254 
1255 	/*
1256 	 * just copy the v4l2_buf structure because app need only the index
1257 	 * value to locate the mapped memory
1258 	 */
1259 	bcopy(&buf_done->v4l2_buf, buf, sizeof (struct v4l2_buffer));
1260 	buf->flags |= V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_MAPPED;
1261 	buf->bytesused = buf_done->filled;
1262 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1263 	    "usbvc_v4l2_dequeue_buffer: bytesused=%d, idx=%x, status=%d",
1264 	    buf->bytesused, buf->index, buf_done->status);
1265 
1266 	return (0);
1267 }
1268 
1269 
1270 /*
1271  * Check if a ctrl_id is supported by the device, if yes, find the
1272  * corresponding processing unit and fill usbvc_v4l2_ctrl_t
1273  */
1274 static int
1275 usbvc_v4l2_match_ctrl(usbvc_state_t *usbvcp, usbvc_v4l2_ctrl_t *ctrl,
1276     uint32_t ctrl_id)
1277 {
1278 	uint8_t		idx;
1279 	usbvc_units_t	*unit;
1280 	uchar_t		bit;
1281 
1282 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1283 	    "usbvc_v4l2_match_ctrl: ctrl_id=%x", ctrl_id);
1284 	if (ctrl_id >= V4L2_CID_PRIVATE_BASE) {
1285 
1286 		return (USB_FAILURE);
1287 	}
1288 	if (ctrl_id < V4L2_CID_BASE) {
1289 
1290 		return (USB_FAILURE);
1291 	}
1292 
1293 	/* get the idx of ctrl array usbvc_v4l2_ctrl */
1294 	idx = ctrl_id - V4L2_CID_BASE;
1295 	if (ctrl_id == V4L2_CID_GAMMA) {
1296 
1297 		/* The 4th one is for Gamma ctrl */
1298 		bit = usbvc_v4l2_ctrls[4].bit;
1299 	} else if ((ctrl_id >= V4L2_CID_BRIGHTNESS) &&
1300 	    (ctrl_id <= V4L2_CID_HUE)) {
1301 
1302 		/* The idxth one is for this ctrl */
1303 		bit = usbvc_v4l2_ctrls[idx].bit;
1304 	} else {
1305 
1306 		return (USB_FAILURE);
1307 	}
1308 	unit = (usbvc_units_t *)list_head(&usbvcp->usbvc_unit_list);
1309 
1310 	/*
1311 	 * Check if there is a processing unit supportting this ctrl.
1312 	 * Todo: check if the ctrl and the unit is really for the right
1313 	 * stream interface in case of multi stream interfaces.
1314 	 */
1315 	while (unit != NULL) {
1316 
1317 		if (unit->descr->bDescriptorSubType == VC_PROCESSING_UNIT) {
1318 
1319 			if (bit >=
1320 			    (unit->descr->unit.processing.bControlSize * 8)) {
1321 
1322 				/*
1323 				 * If this unit's bmControls size is smaller
1324 				 * than bit, then next
1325 				 */
1326 				unit = (usbvc_units_t *)
1327 				    list_next(&usbvcp->usbvc_unit_list, unit);
1328 
1329 				continue;
1330 			} else {
1331 
1332 				/*
1333 				 * The first two bytes of bmControls are
1334 				 * for ctrls
1335 				 */
1336 				if ((bit < 8) &&
1337 				    unit->bmControls[0] & (0x1 << bit)) {
1338 
1339 					break;
1340 				}
1341 				if ((bit >= 8 && bit < 16) &&
1342 				    unit->bmControls[1] & (0x1 << bit)) {
1343 
1344 					break;
1345 				}
1346 			}
1347 		}
1348 		unit = (usbvc_units_t *)list_next(&usbvcp->usbvc_unit_list,
1349 		    unit);
1350 	}
1351 	if (unit == NULL) {
1352 
1353 		return (USB_FAILURE);
1354 	}
1355 	ctrl->entity_id = unit->descr->bUnitID;
1356 	if (ctrl_id == V4L2_CID_GAMMA) {
1357 		ctrl->ctrl_map = &usbvc_v4l2_ctrls[4];
1358 	} else {
1359 		ctrl->ctrl_map = &usbvc_v4l2_ctrls[idx];
1360 	}
1361 
1362 	return (USB_SUCCESS);
1363 }
1364 
1365 
1366 /*
1367  * Implement ioctl VIDIOC_QUERYCTRL, query the ctrl types that the device
1368  * supports
1369  */
1370 static int
1371 usbvc_v4l2_query_ctrl(usbvc_state_t *usbvcp, struct v4l2_queryctrl *queryctrl)
1372 {
1373 	usbvc_v4l2_ctrl_t	ctrl;
1374 	mblk_t			*data;
1375 	char			req[16];
1376 
1377 	if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, queryctrl->id) !=
1378 	    USB_SUCCESS) {
1379 
1380 		return (USB_FAILURE);
1381 	}
1382 	if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) {
1383 
1384 		return (USB_FAILURE);
1385 	}
1386 
1387 	if (usbvc_vc_get_ctrl(usbvcp, GET_MIN, ctrl.entity_id,
1388 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) !=
1389 	    USB_SUCCESS) {
1390 		(void) strncpy(&req[0], "GET_MIN", sizeof (req));
1391 
1392 		goto fail;
1393 	}
1394 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->minimum);
1395 	if (usbvc_vc_get_ctrl(usbvcp, GET_MAX, ctrl.entity_id,
1396 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1397 		(void) strncpy(&req[0], "GET_MAX", sizeof (req));
1398 
1399 		goto fail;
1400 	}
1401 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->maximum);
1402 
1403 	if (usbvc_vc_get_ctrl(usbvcp, GET_RES, ctrl.entity_id,
1404 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1405 		(void) strncpy(&req[0], "GET_RES", sizeof (req));
1406 
1407 		goto fail;
1408 	}
1409 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->step);
1410 
1411 	if (usbvc_vc_get_ctrl(usbvcp, GET_DEF, ctrl.entity_id,
1412 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1413 		(void) strncpy(&req[0], "GET_DEF", sizeof (req));
1414 
1415 		goto fail;
1416 	}
1417 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->default_value);
1418 
1419 	(void) strncpy(queryctrl->name, ctrl.ctrl_map->name,
1420 	    sizeof (queryctrl->name));
1421 	queryctrl->type = ctrl.ctrl_map->type;
1422 	queryctrl->flags = 0;
1423 
1424 	if (data) {
1425 		freemsg(data);
1426 	}
1427 
1428 	return (USB_SUCCESS);
1429 
1430 fail:
1431 	if (data) {
1432 		freemsg(data);
1433 	}
1434 	USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1435 	    "usbvc_v4l2_query_ctrl: fail when %s", req);
1436 
1437 	return (USB_FAILURE);
1438 
1439 }
1440 
1441 
1442 /* Implement ioctl VIDIOC_G_CTRL, get current ctrl */
1443 static int
1444 usbvc_v4l2_get_ctrl(usbvc_state_t *usbvcp, struct v4l2_control *v4l2_ctrl)
1445 {
1446 	usbvc_v4l2_ctrl_t	ctrl;
1447 	mblk_t			*data;
1448 
1449 	if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, v4l2_ctrl->id) !=
1450 	    USB_SUCCESS) {
1451 
1452 		return (USB_FAILURE);
1453 	}
1454 	if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) {
1455 
1456 		return (USB_FAILURE);
1457 	}
1458 
1459 	if (usbvc_vc_get_ctrl(usbvcp, GET_CUR, ctrl.entity_id,
1460 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1461 		if (data) {
1462 			freemsg(data);
1463 		}
1464 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1465 		    "usbvc_v4l2_get_ctrl: fail");
1466 
1467 		return (USB_FAILURE);
1468 	}
1469 	LE_TO_UINT16(data->b_rptr, 0, v4l2_ctrl->value);
1470 
1471 	if (data) {
1472 		freemsg(data);
1473 	}
1474 
1475 	return (USB_SUCCESS);
1476 }
1477 
1478 
1479 /* Implement ioctl VIDIOC_S_CTRL */
1480 static int
1481 usbvc_v4l2_set_ctrl(usbvc_state_t *usbvcp, struct v4l2_control *v4l2_ctrl)
1482 {
1483 	usbvc_v4l2_ctrl_t	ctrl;
1484 	mblk_t			*data;
1485 
1486 	if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, v4l2_ctrl->id) !=
1487 	    USB_SUCCESS) {
1488 
1489 		return (USB_FAILURE);
1490 	}
1491 	if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) {
1492 
1493 		return (USB_FAILURE);
1494 	}
1495 
1496 	UINT16_TO_LE(v4l2_ctrl->value, 0, data->b_wptr);
1497 	data->b_wptr += 2;
1498 	if (usbvc_vc_set_ctrl(usbvcp, SET_CUR, ctrl.entity_id,
1499 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) !=
1500 	    USB_SUCCESS) {
1501 		if (data) {
1502 			freemsg(data);
1503 		}
1504 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1505 		    "usbvc_v4l2_set_ctrl: fail");
1506 
1507 		return (USB_FAILURE);
1508 	}
1509 	if (data) {
1510 		freemsg(data);
1511 	}
1512 
1513 	return (USB_SUCCESS);
1514 }
1515 
1516 /* For the given interval, find the closest frame interval to it. */
1517 static uint32_t
1518 usbvc_find_interval(usbvc_frames_t *frame, uint32_t interval)
1519 {
1520 	uint32_t step, i, closest, index, approx1, approx2;
1521 
1522 
1523 	/*
1524 	 * for continuous case, there is a min and a max, and also a step
1525 	 * value. The available intervals are those between min and max
1526 	 * values.
1527 	 */
1528 	if (!frame->descr->bFrameIntervalType) {
1529 		step = frame->dwFrameIntervalStep;
1530 
1531 		if (step == 0) {
1532 		/* a malfunction device */
1533 
1534 			return (0);
1535 		} else if (interval <= frame->dwMinFrameInterval) {
1536 		/* return the most possible interval we can handle */
1537 
1538 			return (frame->dwMinFrameInterval);
1539 		} else if (interval >= frame->dwMaxFrameInterval) {
1540 		/* return the most possible interval we can handle */
1541 
1542 			return (frame->dwMaxFrameInterval);
1543 		}
1544 
1545 		approx1 = (interval / step) * step;
1546 		approx2 = approx1 + step;
1547 		closest = ((interval - approx1) < (approx2 - interval)) ?
1548 		    approx1 : approx2;
1549 
1550 		return (closest);
1551 	}
1552 
1553 	/*
1554 	 * for discrete case, search all the available intervals, find the
1555 	 * closest one.
1556 	 */
1557 	closest = 0;
1558 	approx2 = (uint32_t)-1;
1559 	for (index = 0; index < frame->descr->bFrameIntervalType; index++) {
1560 		LE_TO_UINT32(frame->dwFrameInterval, index * 4, i);
1561 		approx1 = (i > interval) ? (i - interval) : (interval - i);
1562 
1563 		if (approx1 == 0) {
1564 		/* find the matched one, return it immediately */
1565 			return (i);
1566 		}
1567 
1568 		if (approx1 < approx2) {
1569 			approx2 = approx1;
1570 			closest = i;
1571 		}
1572 	}
1573 
1574 	return (closest);
1575 }
1576 
1577 /* Implement ioctl VIDIOC_S_PARM. Support capture only, so far. */
1578 static int
1579 usbvc_v4l2_set_parm(usbvc_state_t *usbvcp, struct v4l2_streamparm *parm)
1580 {
1581 	usbvc_stream_if_t	*strm_if;
1582 	usbvc_format_group_t	*cur_fmt;
1583 	usbvc_frames_t			*cur_frame;
1584 	uint32_t n, d, c, i;
1585 	usbvc_vs_probe_commit_t	ctrl;
1586 
1587 	mutex_enter(&usbvcp->usbvc_mutex);
1588 	strm_if = usbvcp->usbvc_curr_strm;
1589 
1590 	if (!strm_if->cur_format_group ||
1591 	    !strm_if->cur_format_group->cur_frame) {
1592 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1593 		    "usbvc_v4l2_set_parm: current format or"
1594 		    " frame is not set. cur_fmt=%p",
1595 		    (void *)strm_if->cur_format_group);
1596 
1597 		mutex_exit(&usbvcp->usbvc_mutex);
1598 
1599 		return (USB_FAILURE);
1600 	}
1601 
1602 	cur_fmt = strm_if->cur_format_group;
1603 	cur_frame = cur_fmt->cur_frame;
1604 
1605 	mutex_exit(&usbvcp->usbvc_mutex);
1606 	if (parm->parm.capture.readbuffers > USBVC_MAX_READ_BUF_NUM) {
1607 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1608 		    "usbvc_v4l2_set_parm: ask too many read buffers,"
1609 		    " readbuffers=%d",
1610 		    parm->parm.capture.readbuffers);
1611 
1612 		return (USB_FAILURE);
1613 	}
1614 
1615 	n = parm->parm.capture.timeperframe.numerator;
1616 	d = parm->parm.capture.timeperframe.denominator;
1617 
1618 	/* check the values passed in, in case of zero devide */
1619 	if (d == 0) {
1620 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1621 		    "usbvc_v4l2_set_parm: invalid denominator=%d", d);
1622 
1623 		return (USB_FAILURE);
1624 	}
1625 
1626 	/*
1627 	 * UVC frame intervals are in 100ns units, need convert from
1628 	 * 1s unit to 100ns unit
1629 	 */
1630 	c = USBVC_FRAME_INTERVAL_DENOMINATOR;
1631 
1632 	/* check the values passed in, in case of overflow */
1633 	if (n / d >= ((uint32_t)-1) / c) {
1634 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1635 		    "usbvc_v4l2_set_parm: overflow, numerator=%d,"
1636 		    " denominator=%d", n, d);
1637 
1638 		return (USB_FAILURE);
1639 	}
1640 
1641 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1642 	    "usbvc_v4l2_set_parm: numerator=%d, denominator=%d", n, d);
1643 
1644 	/* compute the interval in 100ns unit */
1645 	if (n <= ((uint32_t)-1) / c) {
1646 		i = (n * c) / d;
1647 	} else {
1648 		do {
1649 			n >>= 1;
1650 			d >>= 1;
1651 		/* decrease both n and d, in case overflow */
1652 		} while (n && d && n > ((uint32_t)-1) / c);
1653 
1654 		if (!d) {
1655 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
1656 			    usbvcp->usbvc_log_handle,
1657 			    "usbvc_v4l2_set_parm: can't compute interval,"
1658 			    " denominator=%d", d);
1659 
1660 			return (USB_FAILURE);
1661 		}
1662 		i = (n * c) / d;
1663 	}
1664 
1665 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1666 	    "usbvc_v4l2_set_parm: want interval=%d, n=%d, d=%d, c=%d",
1667 	    i, n, d, c);
1668 
1669 	/*
1670 	 * Begin negotiate frame intervals.
1671 	 */
1672 	bcopy(&strm_if->ctrl_pc, &ctrl, sizeof (usbvc_vs_probe_commit_t));
1673 	i = usbvc_find_interval(cur_frame, i);
1674 
1675 	if (i == 0) {
1676 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1677 		    "usbvc_v4l2_set_parm: can not find an proper interval."
1678 		    " i=%d, n=%d, d=%d", i, n, d);
1679 
1680 		return (USB_FAILURE);
1681 	}
1682 
1683 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1684 	    "usbvc_v4l2_set_parm: get interval=%d", i);
1685 
1686 	UINT32_TO_LE(i, 0, ctrl.dwFrameInterval);
1687 
1688 	/* Probe, just a test before the real try */
1689 	if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl, VS_PROBE_CONTROL)
1690 	    != USB_SUCCESS) {
1691 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1692 		    "usbvc_v4l2_set_parm: set probe failed");
1693 
1694 		return (USB_FAILURE);
1695 	}
1696 
1697 	/* Commit the frame interval. */
1698 	if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl, VS_COMMIT_CONTROL)
1699 	    != USB_SUCCESS) {
1700 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1701 		    "usbvc_v4l2_set_parm: set commit failed");
1702 
1703 		return (USB_FAILURE);
1704 	}
1705 
1706 	bcopy(&ctrl, &strm_if->ctrl_pc, sizeof (usbvc_vs_probe_commit_t));
1707 
1708 	LE_TO_UINT32(ctrl.dwFrameInterval, 0, i);
1709 	parm->parm.capture.timeperframe.numerator = i;
1710 	parm->parm.capture.timeperframe.denominator = c;
1711 
1712 	mutex_enter(&usbvcp->usbvc_mutex);
1713 	/*
1714 	 * According to ioctl VIDIOC_S_PARM, zero value of readbuffers will not
1715 	 * be set. And the current value is expected to return to application.
1716 	 */
1717 	if (parm->parm.capture.readbuffers != 0) {
1718 		strm_if->buf_read_num = parm->parm.capture.readbuffers;
1719 	} else {
1720 		parm->parm.capture.readbuffers = strm_if->buf_read_num;
1721 	}
1722 	mutex_exit(&usbvcp->usbvc_mutex);
1723 
1724 	return (USB_SUCCESS);
1725 }
1726 
1727 /* Implement ioctl VIDIOC_G_PARM. */
1728 static int
1729 usbvc_v4l2_get_parm(usbvc_state_t *usbvcp, struct v4l2_streamparm *parm)
1730 {
1731 	usbvc_stream_if_t	*strm_if;
1732 	uint32_t n, d;
1733 
1734 	bzero(parm, sizeof (*parm));
1735 
1736 	mutex_enter(&usbvcp->usbvc_mutex);
1737 	strm_if = usbvcp->usbvc_curr_strm;
1738 
1739 	/* return the actual number of buffers allocated for read() I/O */
1740 	parm->parm.capture.readbuffers = strm_if->buf_read.buf_cnt;
1741 
1742 	/* in 100ns units */
1743 	LE_TO_UINT32(strm_if->ctrl_pc.dwFrameInterval, 0, n);
1744 	mutex_exit(&usbvcp->usbvc_mutex);
1745 
1746 	/*
1747 	 * According to UVC payload specs, the dwFrameInterval in frame
1748 	 * descriptors is in 100ns unit.
1749 	 */
1750 	d = USBVC_FRAME_INTERVAL_DENOMINATOR;
1751 	parm->parm.capture.timeperframe.numerator = n;
1752 	parm->parm.capture.timeperframe.denominator = d;
1753 
1754 	/* Support capture only, so far. */
1755 	parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1756 	parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
1757 	parm->parm.capture.capturemode = 0; /* no high quality imaging mode */
1758 	parm->parm.capture.extendedmode = 0; /* no driver specific parameters */
1759 
1760 	/* Always success for current support of this command */
1761 	return (USB_SUCCESS);
1762 }
1763