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 
52 /* Video controls that supported by usbvc driver */
53 static usbvc_v4l2_ctrl_map_t usbvc_v4l2_ctrls[] = {
54 	{
55 		"Brightness",
56 		PU_BRIGHTNESS_CONTROL,
57 		2,
58 		0,
59 		V4L2_CTRL_TYPE_INTEGER
60 	},
61 	{
62 		"Contrast",
63 		PU_CONTRAST_CONTROL,
64 		2,
65 		1,
66 		V4L2_CTRL_TYPE_INTEGER
67 	},
68 	{
69 		"Saturation",
70 		PU_SATURATION_CONTROL,
71 		2,
72 		3,
73 		V4L2_CTRL_TYPE_INTEGER
74 	},
75 	{
76 		"Hue",
77 		PU_HUE_CONTROL,
78 		2,
79 		2,
80 		V4L2_CTRL_TYPE_INTEGER
81 	},
82 	{
83 		"Gamma",
84 		PU_GAMMA_CONTROL,
85 		2,
86 		5,
87 		V4L2_CTRL_TYPE_INTEGER
88 	}
89 };
90 
91 
92 /*
93  * V4L2 colorspaces.
94  */
95 static const uint8_t color_primaries[] = {
96 		0,
97 		V4L2_COLORSPACE_SRGB,
98 		V4L2_COLORSPACE_470_SYSTEM_M,
99 		V4L2_COLORSPACE_470_SYSTEM_BG,
100 		V4L2_COLORSPACE_SMPTE170M,
101 		V4L2_COLORSPACE_SMPTE240M,
102 };
103 
104 /* V4L2 ioctls */
105 int
106 usbvc_v4l2_ioctl(usbvc_state_t *usbvcp, int cmd, intptr_t arg, int mode)
107 {
108 	int	rv = 0;
109 
110 	switch (cmd) {
111 	case VIDIOC_QUERYCAP:	/* Query capabilities */
112 	{
113 		struct v4l2_capability caps;
114 
115 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
116 		    "V4L2 ioctl: VIDIOC_QUERYCAP");
117 		bzero(&caps, sizeof (caps));
118 		(void) strncpy((char *)&caps.driver, "usbvc",
119 		    sizeof (caps.driver));
120 		if (usbvcp->usbvc_reg->dev_product) {
121 			(void) strncpy((char *)&caps.card,
122 			    usbvcp->usbvc_reg->dev_product, sizeof (caps.card));
123 		} else {
124 			(void) strncpy((char *)&caps.card, "Generic USB video"
125 			    "class device", sizeof (caps.card));
126 		}
127 		(void) strncpy((char *)&caps.bus_info, "usb",
128 		    sizeof (caps.bus_info));
129 		caps.version = 1;
130 		caps.capabilities = V4L2_CAP_VIDEO_CAPTURE
131 		    | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
132 		USBVC_COPYOUT(caps);
133 
134 		break;
135 	}
136 	case VIDIOC_ENUM_FMT:
137 	{
138 		struct v4l2_fmtdesc	fmtdesc;
139 		usbvc_format_group_t	*fmtgrp;
140 		usbvc_stream_if_t	*strm_if;
141 
142 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
143 		    "V4L2 ioctl: VIDIOC_ENUM_FMT");
144 		USBVC_COPYIN(fmtdesc);
145 		mutex_enter(&usbvcp->usbvc_mutex);
146 		strm_if = usbvcp->usbvc_curr_strm;
147 		if (fmtdesc.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
148 		    fmtdesc.index >= strm_if->fmtgrp_cnt) {
149 			rv = EINVAL;
150 			mutex_exit(&usbvcp->usbvc_mutex);
151 
152 			break;
153 		}
154 		fmtgrp = &strm_if->format_group[fmtdesc.index];
155 		fmtdesc.pixelformat = fmtgrp->v4l2_pixelformat;
156 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
157 		    "V4L2 ioctl: VIDIOC_ENUM_FMT, idx=%d, grpcnt=%d",
158 		    fmtdesc.index, strm_if->fmtgrp_cnt);
159 
160 		switch (fmtgrp->format->bDescriptorSubType) {
161 		case VS_FORMAT_MJPEG:
162 			fmtdesc.flags = V4L2_FMT_FLAG_COMPRESSED;
163 			(void) strncpy(fmtdesc.description, "MJPEG",
164 			    sizeof (fmtdesc.description));
165 
166 			break;
167 		case VS_FORMAT_UNCOMPRESSED:
168 			fmtdesc.flags = 0;
169 			if (fmtdesc.pixelformat == V4L2_PIX_FMT_YUYV) {
170 				(void) strncpy(fmtdesc.description, "YUYV",
171 				    sizeof (fmtdesc.description));
172 			} else if (fmtdesc.pixelformat == V4L2_PIX_FMT_NV12) {
173 				(void) strncpy(fmtdesc.description, "NV12",
174 				    sizeof (fmtdesc.description));
175 			} else {
176 				(void) strncpy(fmtdesc.description,
177 				    "Unknown format",
178 				    sizeof (fmtdesc.description));
179 			}
180 
181 			break;
182 		default:
183 			fmtdesc.flags = 0;
184 			(void) strncpy(fmtdesc.description, "Unknown format",
185 			    sizeof (fmtdesc.description));
186 		}
187 
188 		mutex_exit(&usbvcp->usbvc_mutex);
189 		USBVC_COPYOUT(fmtdesc);
190 
191 		break;
192 	}
193 	case VIDIOC_S_FMT:
194 	{
195 		struct v4l2_format	fmt;
196 		usbvc_stream_if_t	*strm_if;
197 
198 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
199 		    "V4L2 ioctl: VIDIOC_S_FMT");
200 		mutex_enter(&usbvcp->usbvc_mutex);
201 		strm_if = usbvcp->usbvc_curr_strm;
202 
203 		/* If data I/O is in progress */
204 		if (strm_if->start_polling == 1) {
205 			rv = EBUSY;
206 			mutex_exit(&usbvcp->usbvc_mutex);
207 
208 			break;
209 		}
210 		mutex_exit(&usbvcp->usbvc_mutex);
211 
212 		USBVC_COPYIN(fmt);
213 		if (usbvc_v4l2_set_format(usbvcp, &fmt) != USB_SUCCESS) {
214 			rv = EFAULT;
215 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
216 			    usbvcp->usbvc_log_handle,
217 			    "V4L2 ioctl VIDIOC_S_FMT fail");
218 		}
219 		USBVC_COPYOUT(fmt);
220 
221 		break;
222 	}
223 	case VIDIOC_G_FMT:
224 	{
225 		struct v4l2_format	fmt;
226 
227 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
228 		    "V4L2 ioctl: VIDIOC_G_FMT");
229 		USBVC_COPYIN(fmt);
230 
231 		if ((rv = usbvc_v4l2_get_format(usbvcp, &fmt)) != 0) {
232 
233 			break;
234 		}
235 
236 		USBVC_COPYOUT(fmt);
237 
238 		break;
239 	}
240 	case VIDIOC_REQBUFS: /* for memory mapping IO method */
241 	{
242 		struct v4l2_requestbuffers	reqbuf;
243 		uint_t				bufsize;
244 		usbvc_stream_if_t		*strm_if;
245 
246 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
247 		    "V4L2 ioctl: VIDIOC_REQBUFS");
248 		USBVC_COPYIN(reqbuf);
249 		if (reqbuf.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
250 		    reqbuf.memory != V4L2_MEMORY_MMAP) {
251 			rv = EINVAL;
252 
253 			break;
254 		}
255 		mutex_enter(&usbvcp->usbvc_mutex);
256 		strm_if = usbvcp->usbvc_curr_strm;
257 		if (!strm_if) {
258 			mutex_exit(&usbvcp->usbvc_mutex);
259 			rv = EINVAL;
260 
261 			break;
262 		}
263 		if (reqbuf.count > USBVC_MAX_MAP_BUF_NUM) {
264 			mutex_exit(&usbvcp->usbvc_mutex);
265 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
266 			    usbvcp->usbvc_log_handle,
267 			    "V4L2 ioctl: req too many buffers, fail");
268 			rv = EINVAL;
269 
270 			break;
271 		}
272 
273 		/* If some bufs were already allocated */
274 		if (strm_if->buf_map.buf_cnt) {
275 			/*
276 			 * According to v4l2 spec, application can change the
277 			 * buffer number and also free all buffers if set
278 			 * count to 0
279 			 */
280 			if (reqbuf.count == 0) {
281 				if (strm_if->start_polling == 1) {
282 					mutex_exit(&usbvcp->usbvc_mutex);
283 					usb_pipe_stop_isoc_polling(
284 					    strm_if->datain_ph,
285 					    USB_FLAGS_SLEEP);
286 					mutex_enter(&usbvcp->usbvc_mutex);
287 					strm_if->start_polling = 0;
288 				}
289 				usbvc_free_map_bufs(usbvcp, strm_if);
290 				mutex_exit(&usbvcp->usbvc_mutex);
291 
292 				break;
293 			}
294 			if (reqbuf.count == strm_if->buf_map.buf_cnt) {
295 				mutex_exit(&usbvcp->usbvc_mutex);
296 				USB_DPRINTF_L2(PRINT_MASK_IOCTL,
297 				    usbvcp->usbvc_log_handle,
298 				    "v4l2 ioctls: req the same buffers"
299 				    " as we already have, just return success");
300 
301 				break;
302 			} else {
303 				/*
304 				 * req different number of bufs, according to
305 				 * v4l2 spec, this is not allowed when there
306 				 * are some bufs still mapped.
307 				 */
308 				mutex_exit(&usbvcp->usbvc_mutex);
309 				USB_DPRINTF_L2(PRINT_MASK_IOCTL,
310 				    usbvcp->usbvc_log_handle,
311 				    "v4l2 ioctls: req different number bufs"
312 				    "than the exist ones, fail");
313 				rv = EINVAL;
314 
315 				break;
316 			}
317 		}
318 
319 		if (reqbuf.count == 0) {
320 			mutex_exit(&usbvcp->usbvc_mutex);
321 			rv = EINVAL;
322 
323 			break;
324 		}
325 		LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0, bufsize);
326 		if ((reqbuf.count =
327 		    (uint32_t)usbvc_alloc_map_bufs(usbvcp, strm_if,
328 		    reqbuf.count, bufsize)) == 0) {
329 			mutex_exit(&usbvcp->usbvc_mutex);
330 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
331 			    usbvcp->usbvc_log_handle,
332 			    "V4L2 ioctl: VIDIOC_REQBUFS: alloc fail");
333 			rv = EINVAL;
334 
335 			break;
336 		}
337 		mutex_exit(&usbvcp->usbvc_mutex);
338 
339 		/*
340 		 * return buf number that acctually allocated to application
341 		 */
342 		USBVC_COPYOUT(reqbuf);
343 
344 		break;
345 	}
346 	case VIDIOC_QUERYBUF: /* for memory mapping IO method */
347 	{
348 		struct v4l2_buffer	buf;
349 		usbvc_buf_grp_t		*usbvc_bufg;
350 
351 		USBVC_COPYIN(buf);
352 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
353 		    "V4L2 ioctl: VIDIOC_QUERYBUF: idx=%d", buf.index);
354 		mutex_enter(&usbvcp->usbvc_mutex);
355 		usbvc_bufg = &usbvcp->usbvc_curr_strm->buf_map;
356 		if ((buf.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
357 		    (buf.index >= usbvc_bufg->buf_cnt)) {
358 			mutex_exit(&usbvcp->usbvc_mutex);
359 			rv = EINVAL;
360 
361 			break;
362 		}
363 
364 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
365 		    "V4L2 ioctl: VIDIOC_QUERYBUF: len=%d",
366 		    usbvc_bufg->buf_head[buf.index].v4l2_buf.length);
367 
368 		usbvc_v4l2_query_buf(usbvcp, &usbvc_bufg->buf_head[buf.index],
369 		    &buf);
370 		mutex_exit(&usbvcp->usbvc_mutex);
371 		USBVC_COPYOUT(buf);
372 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
373 		    "V4L2 ioctl: VIDIOC_QUERYBUF,(index=%d)len=%d",
374 		    buf.index, buf.length);
375 
376 		break;
377 	}
378 	case VIDIOC_QBUF:
379 	{
380 		struct v4l2_buffer	buf;
381 		usbvc_buf_grp_t		*usbvc_bufg;
382 
383 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
384 		    "V4L2 ioctl: VIDIOC_QBUF");
385 		USBVC_COPYIN(buf);
386 		mutex_enter(&usbvcp->usbvc_mutex);
387 		usbvc_bufg = &usbvcp->usbvc_curr_strm->buf_map;
388 
389 		if ((buf.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
390 		    (buf.index >= usbvc_bufg->buf_cnt) ||
391 		    (buf.memory != V4L2_MEMORY_MMAP)) {
392 			mutex_exit(&usbvcp->usbvc_mutex);
393 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
394 			    usbvcp->usbvc_log_handle,  "V4L2 ioctl: "
395 			    "VIDIOC_QBUF error:index=%d,type=%d,memory=%d",
396 			    buf.index, buf.type, buf.memory);
397 			rv = EINVAL;
398 
399 			break;
400 		}
401 		rv = usbvc_v4l2_enqueue_buf(usbvcp,
402 		    &usbvc_bufg->buf_head[buf.index], &buf);
403 		if (rv < 0) {
404 			mutex_exit(&usbvcp->usbvc_mutex);
405 
406 			break;
407 		}
408 		mutex_exit(&usbvcp->usbvc_mutex);
409 		USBVC_COPYOUT(buf);
410 
411 		break;
412 	}
413 
414 	case VIDIOC_DQBUF:
415 	{
416 		struct v4l2_buffer	buf;
417 
418 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
419 		    "V4L2 ioctl: VIDIOC_DQBUF");
420 		USBVC_COPYIN(buf);
421 		mutex_enter(&usbvcp->usbvc_mutex);
422 		if ((rv = usbvc_v4l2_dequeue_buffer(usbvcp, &buf, mode)) != 0) {
423 			mutex_exit(&usbvcp->usbvc_mutex);
424 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
425 			    usbvcp->usbvc_log_handle, "V4L2 ioctl: "
426 			    "VIDIOC_DQBUF: fail, rv=%d", rv);
427 
428 			break;
429 		}
430 		mutex_exit(&usbvcp->usbvc_mutex);
431 		USBVC_COPYOUT(buf);
432 
433 		break;
434 	}
435 
436 	case VIDIOC_STREAMON:
437 	{
438 		int			type; /* v4l2_buf_type */
439 		usbvc_stream_if_t	*strm_if;
440 
441 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
442 		    "V4L2 ioctl: VIDIOC_STREAMON");
443 		USBVC_COPYIN(type);
444 		mutex_enter(&usbvcp->usbvc_mutex);
445 		strm_if = usbvcp->usbvc_curr_strm;
446 		if (!strm_if) {
447 			mutex_exit(&usbvcp->usbvc_mutex);
448 			rv = EINVAL;
449 
450 			break;
451 		}
452 		if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
453 			mutex_exit(&usbvcp->usbvc_mutex);
454 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
455 			    usbvcp->usbvc_log_handle, "V4L2 ioctl: "
456 			    "VIDIOC_STREAMON: fail. Only capture type is"
457 			    " supported by now.");
458 			rv = EINVAL;
459 
460 			break;
461 		}
462 		/* if the first read, open isoc pipe */
463 		if (!strm_if->datain_ph) {
464 			if (usbvc_open_isoc_pipe(usbvcp, strm_if) !=
465 			    USB_SUCCESS) {
466 				mutex_exit(&usbvcp->usbvc_mutex);
467 				USB_DPRINTF_L2(PRINT_MASK_IOCTL,
468 				    usbvcp->usbvc_log_handle, "V4L2 ioctl:"
469 				    " first read, open pipe fail");
470 				rv = EINVAL;
471 
472 				break;
473 			}
474 		}
475 		/* If it is already started */
476 		if (strm_if->start_polling == 1) {
477 			mutex_exit(&usbvcp->usbvc_mutex);
478 
479 			break;
480 		}
481 		/* At present, VIDIOC_STREAMON supports mmap io only. */
482 		if (usbvc_start_isoc_polling(usbvcp, strm_if,
483 		    V4L2_MEMORY_MMAP) != USB_SUCCESS) {
484 			rv = EFAULT;
485 			mutex_exit(&usbvcp->usbvc_mutex);
486 
487 			break;
488 		}
489 		strm_if->start_polling = 1;
490 
491 		mutex_exit(&usbvcp->usbvc_mutex);
492 
493 		break;
494 	}
495 
496 	case VIDIOC_STREAMOFF:
497 	{
498 		int			type;	/* v4l2_buf_type */
499 		usbvc_stream_if_t	*strm_if;
500 
501 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
502 		    "V4L2 ioctl: VIDIOC_STREAMOFF");
503 		USBVC_COPYIN(type);
504 		mutex_enter(&usbvcp->usbvc_mutex);
505 		strm_if = usbvcp->usbvc_curr_strm;
506 		if (!strm_if) {
507 			mutex_exit(&usbvcp->usbvc_mutex);
508 			rv = EINVAL;
509 
510 			break;
511 		}
512 		if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
513 			mutex_exit(&usbvcp->usbvc_mutex);
514 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
515 			    usbvcp->usbvc_log_handle, "V4L2 ioctl: "
516 			    "VIDIOC_STREAMON: fail. Only capture type is "
517 			    "supported by now.");
518 			rv = EINVAL;
519 
520 			break;
521 		}
522 
523 		/* Need close the isoc data pipe if any reads are performed. */
524 		strm_if = usbvcp->usbvc_curr_strm;
525 		if (strm_if->start_polling == 1) {
526 			mutex_exit(&usbvcp->usbvc_mutex);
527 			usb_pipe_stop_isoc_polling(strm_if->datain_ph,
528 			    USB_FLAGS_SLEEP);
529 			mutex_enter(&usbvcp->usbvc_mutex);
530 			strm_if->start_polling = 0;
531 		}
532 		mutex_exit(&usbvcp->usbvc_mutex);
533 
534 		break;
535 	}
536 
537 	case VIDIOC_ENUMINPUT:
538 	{
539 		struct v4l2_input input;
540 
541 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
542 		    "V4L2 ioctl: ENUMINPUT");
543 		USBVC_COPYIN(input);
544 
545 		if (input.index != 0) { /* Support only one INPUT now */
546 			rv = EINVAL;
547 
548 			break;
549 		}
550 		(void) strncpy((char *)input.name, "Camera Terminal",
551 		    sizeof (input.name));
552 		input.type = V4L2_INPUT_TYPE_CAMERA;
553 		USBVC_COPYOUT(input);
554 
555 		break;
556 	}
557 
558 	case VIDIOC_G_INPUT:
559 	{
560 		int input_idx = 0;	/* Support only one input now */
561 
562 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
563 		    "V4L2 ioctl: G_INPUT");
564 		USBVC_COPYOUT(input_idx);
565 
566 		break;
567 	}
568 
569 	case VIDIOC_S_INPUT:
570 	{
571 		int input_idx;
572 
573 		USBVC_COPYIN(input_idx);
574 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
575 		    "V4L2 ioctl: S_INPUT");
576 		if (input_idx != 0) {	/* Support only one input now */
577 			rv = EINVAL;
578 		}
579 
580 		break;
581 	}
582 
583 	/* Query the device that what kinds of video ctrls are supported */
584 	case VIDIOC_QUERYCTRL:
585 	{
586 		struct v4l2_queryctrl queryctrl;
587 
588 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
589 		    "V4L2 ioctl: QUERYCTRL");
590 		USBVC_COPYIN(queryctrl);
591 
592 		if (usbvc_v4l2_query_ctrl(usbvcp, &queryctrl) != USB_SUCCESS) {
593 			rv = EINVAL;
594 
595 			break;
596 		}
597 
598 		USBVC_COPYOUT(queryctrl);
599 
600 		break;
601 	}
602 	case VIDIOC_G_CTRL:
603 	{
604 		struct v4l2_control ctrl;
605 
606 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
607 		    "V4L2 ioctl: G_CTRL");
608 		USBVC_COPYIN(ctrl);
609 		if (usbvc_v4l2_get_ctrl(usbvcp, &ctrl) != USB_SUCCESS) {
610 			rv = EINVAL;
611 
612 			break;
613 		}
614 
615 		USBVC_COPYOUT(ctrl);
616 
617 		break;
618 	}
619 	case VIDIOC_S_CTRL:
620 	{
621 		struct v4l2_control ctrl;
622 
623 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
624 		    "V4L2 ioctl: S_CTRL");
625 		USBVC_COPYIN(ctrl);
626 		if (usbvc_v4l2_set_ctrl(usbvcp, &ctrl) != USB_SUCCESS) {
627 			rv = EINVAL;
628 
629 			break;
630 		}
631 
632 		USBVC_COPYOUT(ctrl);
633 
634 		break;
635 	}
636 	/* These ioctls are for analog video standards. */
637 	case VIDIOC_G_STD:
638 	case VIDIOC_S_STD:
639 	case VIDIOC_ENUMSTD:
640 	case VIDIOC_QUERYSTD:
641 		rv = EINVAL;
642 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
643 		    "usbvc_v4l2_ioctl: not a supported cmd, cmd=%x", cmd);
644 
645 		break;
646 	default:
647 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
648 		    "usbvc_v4l2_ioctl: not a valid cmd value, cmd=%x", cmd);
649 		rv = ENOTTY;
650 	}
651 
652 	USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
653 	    "usbvc_v4l2_ioctl: exit, rv=%d", rv);
654 
655 	return (rv);
656 
657 }
658 
659 
660 /*
661  * Convert GUID in uncompressed format descriptor to the pixelformat element
662  * in struct v4l2_pix_format
663  */
664 uint32_t
665 usbvc_v4l2_guid2fcc(uint8_t *guid)
666 {
667 	uint32_t ret;
668 
669 	uint8_t y[16] = USBVC_FORMAT_GUID_YUY2;
670 	uint8_t n[16] = USBVC_FORMAT_GUID_NV12;
671 	if (!memcmp((void *)guid, (void *) &y[0], 16)) {
672 		ret = V4L2_PIX_FMT_YUYV;
673 
674 		return (ret);
675 	}
676 	if (!memcmp((void *)guid, (void *) &n, 16)) {
677 		ret = V4L2_PIX_FMT_NV12;
678 
679 		return (ret);
680 	}
681 
682 	return (0);
683 }
684 
685 
686 /*
687  * Find a frame which has the closest image size as the input args
688  * (width, height)
689  */
690 static usbvc_frames_t *
691 usbvc_match_image_size(uint32_t width, uint32_t height,
692     usbvc_format_group_t *fmtgrp)
693 {
694 	uint32_t w, h, diff, sz, i;
695 	usbvc_frames_t *frame = NULL;
696 	usbvc_frame_descr_t *descr;
697 
698 	diff = 0xffffffff;
699 
700 	for (i = 0; i < fmtgrp->frame_cnt; i++) {
701 
702 		descr = fmtgrp->frames[i].descr;
703 		if (descr == NULL) {
704 
705 			continue;
706 		}
707 		LE_TO_UINT16(descr->wWidth, 0, w);
708 		LE_TO_UINT16(descr->wHeight, 0, h);
709 
710 		sz = min(w, width) * min(h, height);
711 		sz = (w * h + width * height - sz * 2);
712 		if (sz < diff) {
713 			frame = &fmtgrp->frames[i];
714 			diff = sz;
715 		}
716 
717 		if (diff == 0) {
718 
719 			return (frame);
720 		}
721 	}
722 
723 	return (frame);
724 }
725 
726 
727 /* Implement ioctl VIDIOC_S_FMT, set a video format */
728 static int
729 usbvc_v4l2_set_format(usbvc_state_t *usbvcp, struct v4l2_format *format)
730 {
731 	usbvc_vs_probe_commit_t	ctrl, ctrl_max, ctrl_min, ctrl_curr;
732 	usbvc_stream_if_t	*strm_if;
733 	usbvc_format_group_t	*fmtgrp;
734 	usbvc_frames_t		*frame;
735 	uint32_t		w, h, interval, bandwidth;
736 	uint8_t			type, i;
737 
738 	mutex_enter(&usbvcp->usbvc_mutex);
739 
740 	/*
741 	 * Get the first stream interface. Todo: deal with multi stream
742 	 * interfaces.
743 	 */
744 	strm_if = usbvcp->usbvc_curr_strm;
745 
746 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
747 	    "usbvc_v4l2_set_format: strm_if->fmtgrp_cnt=%d",
748 	    strm_if->fmtgrp_cnt);
749 
750 	/* Find the proper format group according to compress type and guid */
751 	for (i = 0; i < strm_if->fmtgrp_cnt; i++) {
752 		fmtgrp = &strm_if->format_group[i];
753 
754 		/*
755 		 * If v4l2_pixelformat is NULL, then that means there is not
756 		 * a parsed format in format_group[i].
757 		 */
758 		if (!fmtgrp->v4l2_pixelformat || fmtgrp->frame_cnt == 0) {
759 			USB_DPRINTF_L3(PRINT_MASK_DEVCTRL,
760 			    usbvcp->usbvc_log_handle,
761 			    "usbvc_set_default_stream_fmt: no frame, fail");
762 
763 			continue;
764 		}
765 		type = fmtgrp->format->bDescriptorSubType;
766 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
767 		    "usbvc_v4l2_set_format: type =%x, i =%d", type, i);
768 
769 		if ((type == VS_FORMAT_MJPEG) ||
770 		    (type == VS_FORMAT_UNCOMPRESSED)) {
771 			if (format->fmt.pix.pixelformat ==
772 			    fmtgrp->v4l2_pixelformat) {
773 
774 				break;
775 			}
776 		}
777 	}
778 
779 	if (i >= strm_if->fmtgrp_cnt) {
780 		mutex_exit(&usbvcp->usbvc_mutex);
781 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
782 		    "usbvc_v4l2_set_format: can't find a proper format, "
783 		    "pixelformat=%x", format->fmt.pix.pixelformat);
784 
785 		return (USB_FAILURE);
786 	}
787 
788 	fmtgrp = &strm_if->format_group[i];
789 
790 	frame = usbvc_match_image_size(format->fmt.pix.width,
791 	    format->fmt.pix.height, fmtgrp);
792 
793 	if (frame == NULL) {
794 		mutex_exit(&usbvcp->usbvc_mutex);
795 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
796 		    "usbvc_v4l2_set_format: can't find a proper frame, rw=%d, "
797 		    "rh=%d", format->fmt.pix.width, format->fmt.pix.height);
798 
799 		return (USB_FAILURE);
800 	}
801 
802 	/* frame interval */
803 	LE_TO_UINT32(frame->descr->dwDefaultFrameInterval, 0, interval);
804 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
805 	    "usbvc_v4l2_set_format: Default Frame Interval=%x", interval);
806 
807 	/*
808 	 * Begin negotiate formats.
809 	 */
810 	bzero((void *)&ctrl, sizeof (usbvc_vs_probe_commit_t));
811 
812 	/* dwFrameInterval is fixed */
813 	ctrl.bmHint[0] = 1;
814 
815 	ctrl.bFormatIndex = fmtgrp->format->bFormatIndex;
816 	ctrl.bFrameIndex = frame->descr->bFrameIndex;
817 	UINT32_TO_LE(interval, 0, ctrl.dwFrameInterval);
818 
819 	mutex_exit(&usbvcp->usbvc_mutex);
820 
821 	/* Probe, just a test before the real try */
822 	if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl, VS_PROBE_CONTROL)
823 	    != USB_SUCCESS) {
824 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
825 		    "usbvc_v4l2_set_format: set probe failed");
826 
827 		return (USB_FAILURE);
828 	}
829 
830 	/* Get max values */
831 	if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_max, GET_MAX) !=
832 	    USB_SUCCESS) {
833 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
834 		    "usbvc_v4l2_set_format: get probe MAX failed");
835 
836 		return (USB_FAILURE);
837 	}
838 
839 	/* Use the best quality first */
840 	bcopy(&ctrl_max.wCompQuality, &ctrl.wCompQuality, 2);
841 
842 	/*
843 	 * By now, we've get some parametres of ctrl req, next try to set ctrl.
844 	 */
845 	for (i = 0; i < 2; i++) {
846 
847 		/* Probe */
848 		if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl,
849 		    VS_PROBE_CONTROL) != USB_SUCCESS) {
850 
851 			return (USB_FAILURE);
852 		}
853 
854 		/* Get current value after probe */
855 		if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_curr, GET_CUR)
856 		    != USB_SUCCESS) {
857 
858 			return (USB_FAILURE);
859 		}
860 		LE_TO_UINT32(ctrl_curr.dwMaxPayloadTransferSize, 0, bandwidth);
861 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
862 		    "usbvc_v4l2_set_format: bandwidth=%x", bandwidth);
863 
864 		/*
865 		 * If the bandwidth does not exceed the max value of all the
866 		 * alternatives in this interface, we done.
867 		 */
868 		if (bandwidth <= strm_if->max_isoc_payload) {
869 
870 			break;
871 		}
872 		if (i >= 1) {
873 
874 			return (USB_FAILURE);
875 		}
876 
877 		/* Get minimum values since the bandwidth is not enough */
878 		if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_min, GET_MIN) !=
879 		    USB_SUCCESS) {
880 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
881 			    usbvcp->usbvc_log_handle,
882 			    "usbvc_v4l2_set_format: get probe MIN failed");
883 
884 			return (USB_FAILURE);
885 		}
886 
887 		/* To keep simple, just use some minimum values to try again */
888 		bcopy(&ctrl_min.wKeyFrameRate, &ctrl_curr.wKeyFrameRate, 2);
889 		bcopy(&ctrl_min.wPFrameRate, &ctrl_curr.wPFrameRate, 2);
890 		bcopy(&ctrl_min.wCompWindowSize, &ctrl_curr.wCompWindowSize, 2);
891 		bcopy(&ctrl_max.wCompQuality, &ctrl_curr.wCompQuality, 2);
892 
893 		bcopy(&ctrl_curr, &ctrl,
894 		    sizeof (usbvc_vs_probe_commit_t));
895 	}
896 
897 	bcopy(&ctrl_curr, &ctrl, sizeof (usbvc_vs_probe_commit_t));
898 
899 	/* commit the values we negotiated above */
900 	if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl,
901 	    VS_COMMIT_CONTROL) != USB_SUCCESS) {
902 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
903 		    "usbvc_v4l2_set_format: set probe failed, i=%d", i);
904 
905 		return (USB_FAILURE);
906 	}
907 	mutex_enter(&usbvcp->usbvc_mutex);
908 
909 	/*
910 	 * It's good to check index here before use it. bFormatIndex is based
911 	 * on 1, and format_group[i] is based on 0, so minus 1
912 	 */
913 	i = ctrl.bFormatIndex - 1;
914 	if (i < strm_if->fmtgrp_cnt) {
915 		strm_if->cur_format_group = &strm_if->format_group[i];
916 	} else {
917 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
918 		    "usbvc_v4l2_set_format: format index out of range");
919 		mutex_exit(&usbvcp->usbvc_mutex);
920 
921 		return (USB_FAILURE);
922 	}
923 
924 	/* bFrameIndex is based on 1, and frames[i] is based on 0, so minus 1 */
925 	i = ctrl.bFrameIndex -1;
926 	if (i < strm_if->cur_format_group->frame_cnt) {
927 		strm_if->cur_format_group->cur_frame =
928 		    &strm_if->cur_format_group->frames[i];
929 	} else {
930 		mutex_exit(&usbvcp->usbvc_mutex);
931 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
932 		    "usbvc_v4l2_set_format: frame index out of range");
933 
934 		return (USB_FAILURE);
935 	}
936 
937 	/*
938 	 * by now, the video format is set successfully. record the current
939 	 * setting to strm_if->ctrl_pc
940 	 */
941 	bcopy(&ctrl_curr, &strm_if->ctrl_pc, sizeof (usbvc_vs_probe_commit_t));
942 
943 	format->fmt.pix.colorspace = fmtgrp->v4l2_color;
944 	format->fmt.pix.field = V4L2_FIELD_NONE;
945 	format->fmt.pix.priv = 0;
946 
947 	LE_TO_UINT16(frame->descr->wWidth, 0, w);
948 	LE_TO_UINT16(frame->descr->wHeight, 0, h);
949 	format->fmt.pix.width = w;
950 	format->fmt.pix.height = h;
951 	format->fmt.pix.bytesperline = fmtgrp->v4l2_bpp * w;
952 	LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0,
953 	    format->fmt.pix.sizeimage);
954 
955 	mutex_exit(&usbvcp->usbvc_mutex);
956 
957 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
958 	    "usbvc_v4l2_set_format: dwMaxVideoFrameSize=%x, w=%x, h=%x",
959 	    format->fmt.pix.sizeimage, w, h);
960 
961 	return (USB_SUCCESS);
962 }
963 
964 
965 /* Implement ioctl VIDIOC_G_FMT, get the current video format */
966 static int
967 usbvc_v4l2_get_format(usbvc_state_t *usbvcp, struct v4l2_format *format)
968 {
969 	usbvc_stream_if_t	*strm_if;
970 	usbvc_format_group_t	*fmtgrp;
971 	uint16_t		w, h;
972 
973 	if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
974 
975 		return (EINVAL);
976 	}
977 	mutex_enter(&usbvcp->usbvc_mutex);
978 
979 	/* get the current interface. */
980 	strm_if = usbvcp->usbvc_curr_strm;
981 	fmtgrp = strm_if->cur_format_group;
982 
983 	if (!fmtgrp || !fmtgrp->cur_frame) {
984 		mutex_exit(&usbvcp->usbvc_mutex);
985 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
986 		    "usbvc_v4l2_get_format: fail, no current format or frame,"
987 		    "fmtgrp=%p", (void *)fmtgrp);
988 
989 		return (EINVAL);
990 	}
991 	format->fmt.pix.colorspace = fmtgrp->v4l2_color;
992 	format->fmt.pix.priv = 0;
993 	format->fmt.pix.pixelformat = fmtgrp->v4l2_pixelformat;
994 
995 	LE_TO_UINT16(fmtgrp->cur_frame->descr->wWidth, 0, w);
996 	LE_TO_UINT16(fmtgrp->cur_frame->descr->wHeight, 0, h);
997 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
998 	    "v4l2 ioctl get format ");
999 	format->fmt.pix.width = w;
1000 	format->fmt.pix.height = h;
1001 
1002 	format->fmt.pix.field = V4L2_FIELD_NONE;
1003 	format->fmt.pix.bytesperline = fmtgrp->v4l2_bpp * w;
1004 
1005 	LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0,
1006 	    format->fmt.pix.sizeimage);
1007 
1008 	mutex_exit(&usbvcp->usbvc_mutex);
1009 
1010 	return (0);
1011 }
1012 
1013 
1014 /*
1015  * Convert color space descriptor's bColorPrimaries to the colorspace element
1016  * in struct v4l2_pix_format
1017  */
1018 uint8_t
1019 usbvc_v4l2_colorspace(uint8_t color_prim)
1020 {
1021 
1022 	if (color_prim < NELEM(color_primaries)) {
1023 
1024 		return (color_primaries[color_prim]);
1025 	}
1026 
1027 	return (0);
1028 }
1029 
1030 
1031 /* Implement ioctl VIDIOC_QUERYBUF, get the buf status */
1032 static void
1033 usbvc_v4l2_query_buf(usbvc_state_t *usbvcp, usbvc_buf_t *usbvc_buf,
1034 	struct v4l2_buffer *v4l2_buf)
1035 {
1036 	ASSERT(mutex_owned(&usbvcp->usbvc_mutex));
1037 
1038 	bcopy(&(usbvc_buf->v4l2_buf), v4l2_buf, sizeof (struct v4l2_buffer));
1039 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1040 	    "usbvc_v4l2_query_buf: uv_buf_len=%d, len=%d",
1041 	    usbvc_buf->v4l2_buf.length, v4l2_buf->length);
1042 
1043 	if (usbvc_buf->status >= USBVC_BUF_MAPPED) {
1044 		v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
1045 	}
1046 
1047 	switch (usbvc_buf->status) {
1048 	case USBVC_BUF_DONE:
1049 	case USBVC_BUF_ERR:
1050 		v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
1051 
1052 		break;
1053 	case USBVC_BUF_EMPTY:
1054 		v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
1055 
1056 		break;
1057 	case USBVC_BUF_INIT:
1058 	default:
1059 
1060 		break;
1061 	}
1062 }
1063 
1064 
1065 /* Implement ioctl VIDIOC_QBUF, queue a empty buf to the free list */
1066 static int
1067 usbvc_v4l2_enqueue_buf(usbvc_state_t *usbvcp, usbvc_buf_t *usbvc_buf,
1068 	struct v4l2_buffer *buf)
1069 {
1070 	usbvc_buf_t	*donebuf;
1071 	boolean_t	queued = B_FALSE;
1072 	usbvc_buf_grp_t	*bufgrp;
1073 
1074 	ASSERT(mutex_owned(&usbvcp->usbvc_mutex));
1075 
1076 	bufgrp = &usbvcp->usbvc_curr_strm->buf_map;
1077 
1078 	if (usbvc_buf == bufgrp->buf_filling) {
1079 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1080 		    "enqueue_buffer(%d) , want to queue buf_filling, "
1081 		    "just return success", buf->index);
1082 
1083 		return (0);
1084 	}
1085 
1086 	if (!list_is_empty(&bufgrp->uv_buf_done)) {
1087 		donebuf = (usbvc_buf_t *)list_head(&bufgrp->uv_buf_done);
1088 		while (donebuf) {
1089 
1090 			if (donebuf == &(bufgrp->buf_head[buf->index])) {
1091 				queued = B_TRUE;
1092 
1093 				break;
1094 			}
1095 			donebuf = (usbvc_buf_t *)list_next(&bufgrp->uv_buf_done,
1096 			    donebuf);
1097 		}
1098 	}
1099 	if (queued) {
1100 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1101 		    "enqueue_buffer(%d), still in done list, don't insert to"
1102 		    " free list", buf->index);
1103 
1104 		return (0);
1105 	}
1106 
1107 	if (usbvc_buf->status == USBVC_BUF_EMPTY) {
1108 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1109 		    "enqueue buffer(%d), already queued.", buf->index);
1110 
1111 		return (0);
1112 
1113 	}
1114 	if (usbvc_buf->status < USBVC_BUF_MAPPED) {
1115 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1116 		    "enqueue buffer(%d), state error, not mapped.", buf->index);
1117 
1118 		return (EINVAL);
1119 	}
1120 
1121 	/*
1122 	 * The buf is put to the buf free list when allocated, so, if the buf
1123 	 * is the first time to enqueue, just change the state to empty is
1124 	 * enough.
1125 	 */
1126 	if (usbvc_buf->status == USBVC_BUF_MAPPED) {
1127 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1128 		    "queue_buffer(%d), 1st time queue this buf", buf->index);
1129 
1130 		usbvc_buf->status = USBVC_BUF_EMPTY;
1131 
1132 	} else {
1133 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1134 		    "enqueue_buffer(%d) , USBVC_BUF_EMPTY", buf->index);
1135 
1136 		usbvc_buf->status = USBVC_BUF_EMPTY;
1137 		usbvc_buf->v4l2_buf.bytesused = 0;
1138 		list_insert_tail(&bufgrp->uv_buf_free, usbvc_buf);
1139 	}
1140 	buf->flags &= ~V4L2_BUF_FLAG_DONE;
1141 	buf->flags |= V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
1142 
1143 	return (0);
1144 }
1145 
1146 
1147 /* Implement ioctl VIDIOC_DQBUF, pick a buf from done list */
1148 static int
1149 usbvc_v4l2_dequeue_buffer(usbvc_state_t *usbvcp, struct v4l2_buffer *buf,
1150 	int mode)
1151 {
1152 	usbvc_buf_t *buf_done;
1153 
1154 	ASSERT(mutex_owned(&usbvcp->usbvc_mutex));
1155 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1156 	    "usbvc_v4l2_dequeue_buffer: idx=%x", buf->index);
1157 
1158 	/* v4l2 spec: app just set type and memory field */
1159 	if ((buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
1160 	    (buf->memory != V4L2_MEMORY_MMAP)) {
1161 
1162 		return (EINVAL);
1163 	}
1164 	if ((mode & (O_NDELAY|O_NONBLOCK)) &&
1165 	    (list_is_empty(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done))) {
1166 
1167 		/* non-blocking */
1168 		return (EAGAIN);
1169 	}
1170 
1171 	/* no available buffers, block here */
1172 	while (list_is_empty(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done)) {
1173 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1174 		    "usbvc_v4l2_dequeue_buffer: wait for done buf");
1175 		if (cv_wait_sig(&usbvcp->usbvc_mapio_cv, &usbvcp->usbvc_mutex)
1176 		    <= 0) {
1177 
1178 			/* no done buf and is signaled */
1179 			return (EINTR);
1180 		}
1181 		if (usbvcp->usbvc_dev_state != USB_DEV_ONLINE) {
1182 
1183 			/* Device is disconnected. */
1184 			return (EINTR);
1185 		}
1186 	}
1187 
1188 	buf_done = list_head(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done);
1189 
1190 	list_remove(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done, buf_done);
1191 
1192 	/*
1193 	 * just copy the v4l2_buf structure because app need only the index
1194 	 * value to locate the mapped memory
1195 	 */
1196 	bcopy(&buf_done->v4l2_buf, buf, sizeof (struct v4l2_buffer));
1197 	buf->flags |= V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_MAPPED;
1198 	buf->bytesused = buf_done->filled;
1199 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1200 	    "usbvc_v4l2_dequeue_buffer: bytesused=%d, idx=%x, status=%d",
1201 	    buf->bytesused, buf->index, buf_done->status);
1202 
1203 	return (0);
1204 }
1205 
1206 
1207 /*
1208  * Check if a ctrl_id is supported by the device, if yes, find the
1209  * corresponding processing unit and fill usbvc_v4l2_ctrl_t
1210  */
1211 static int
1212 usbvc_v4l2_match_ctrl(usbvc_state_t *usbvcp, usbvc_v4l2_ctrl_t *ctrl,
1213     uint32_t ctrl_id)
1214 {
1215 	uint8_t		idx;
1216 	usbvc_units_t	*unit;
1217 	uchar_t		bit;
1218 
1219 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1220 	    "usbvc_v4l2_match_ctrl: ctrl_id=%x", ctrl_id);
1221 	if (ctrl_id >= V4L2_CID_PRIVATE_BASE) {
1222 
1223 		return (USB_FAILURE);
1224 	}
1225 	if (ctrl_id < V4L2_CID_BASE) {
1226 
1227 		return (USB_FAILURE);
1228 	}
1229 
1230 	/* get the idx of ctrl array usbvc_v4l2_ctrl */
1231 	idx = ctrl_id - V4L2_CID_BASE;
1232 	if (ctrl_id == V4L2_CID_GAMMA) {
1233 
1234 		/* The 4th one is for Gamma ctrl */
1235 		bit = usbvc_v4l2_ctrls[4].bit;
1236 	} else if ((ctrl_id >= V4L2_CID_BRIGHTNESS) &&
1237 	    (ctrl_id <= V4L2_CID_HUE)) {
1238 
1239 		/* The idxth one is for this ctrl */
1240 		bit = usbvc_v4l2_ctrls[idx].bit;
1241 	} else {
1242 
1243 		return (USB_FAILURE);
1244 	}
1245 	unit = (usbvc_units_t *)list_head(&usbvcp->usbvc_unit_list);
1246 
1247 	/*
1248 	 * Check if there is a processing unit supportting this ctrl.
1249 	 * Todo: check if the ctrl and the unit is really for the right
1250 	 * stream interface in case of multi stream interfaces.
1251 	 */
1252 	while (unit != NULL) {
1253 
1254 		if (unit->descr->bDescriptorSubType == VC_PROCESSING_UNIT) {
1255 
1256 			if (bit >=
1257 			    (unit->descr->unit.processing.bControlSize * 8)) {
1258 
1259 				/*
1260 				 * If this unit's bmControls size is smaller
1261 				 * than bit, then next
1262 				 */
1263 				unit = (usbvc_units_t *)
1264 				    list_next(&usbvcp->usbvc_unit_list, unit);
1265 
1266 				continue;
1267 			} else {
1268 
1269 				/*
1270 				 * The first two bytes of bmControls are
1271 				 * for ctrls
1272 				 */
1273 				if ((bit < 8) &&
1274 				    unit->bmControls[0] & (0x1 << bit)) {
1275 
1276 					break;
1277 				}
1278 				if ((bit >= 8 && bit < 16) &&
1279 				    unit->bmControls[1] & (0x1 << bit)) {
1280 
1281 					break;
1282 				}
1283 			}
1284 		}
1285 		unit = (usbvc_units_t *)list_next(&usbvcp->usbvc_unit_list,
1286 		    unit);
1287 	}
1288 	if (unit == NULL) {
1289 
1290 		return (USB_FAILURE);
1291 	}
1292 	ctrl->entity_id = unit->descr->bUnitID;
1293 	if (ctrl_id == V4L2_CID_GAMMA) {
1294 		ctrl->ctrl_map = &usbvc_v4l2_ctrls[4];
1295 	} else {
1296 		ctrl->ctrl_map = &usbvc_v4l2_ctrls[idx];
1297 	}
1298 
1299 	return (USB_SUCCESS);
1300 }
1301 
1302 
1303 /*
1304  * Implement ioctl VIDIOC_QUERYCTRL, query the ctrl types that the device
1305  * supports
1306  */
1307 static int
1308 usbvc_v4l2_query_ctrl(usbvc_state_t *usbvcp, struct v4l2_queryctrl *queryctrl)
1309 {
1310 	usbvc_v4l2_ctrl_t	ctrl;
1311 	mblk_t			*data;
1312 	char			req[16];
1313 
1314 	if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, queryctrl->id) !=
1315 	    USB_SUCCESS) {
1316 
1317 		return (USB_FAILURE);
1318 	}
1319 	if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) {
1320 
1321 		return (USB_FAILURE);
1322 	}
1323 
1324 	if (usbvc_vc_get_ctrl(usbvcp, GET_MIN, ctrl.entity_id,
1325 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) !=
1326 	    USB_SUCCESS) {
1327 		(void) strncpy(&req[0], "GET_MIN", sizeof (req));
1328 
1329 		goto fail;
1330 	}
1331 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->minimum);
1332 	if (usbvc_vc_get_ctrl(usbvcp, GET_MAX, ctrl.entity_id,
1333 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1334 		(void) strncpy(&req[0], "GET_MAX", sizeof (req));
1335 
1336 		goto fail;
1337 	}
1338 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->maximum);
1339 
1340 	if (usbvc_vc_get_ctrl(usbvcp, GET_RES, ctrl.entity_id,
1341 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1342 		(void) strncpy(&req[0], "GET_RES", sizeof (req));
1343 
1344 		goto fail;
1345 	}
1346 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->step);
1347 
1348 	if (usbvc_vc_get_ctrl(usbvcp, GET_DEF, ctrl.entity_id,
1349 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1350 		(void) strncpy(&req[0], "GET_DEF", sizeof (req));
1351 
1352 		goto fail;
1353 	}
1354 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->default_value);
1355 
1356 	(void) strncpy(queryctrl->name, ctrl.ctrl_map->name,
1357 	    sizeof (queryctrl->name));
1358 	queryctrl->type = ctrl.ctrl_map->type;
1359 	queryctrl->flags = 0;
1360 
1361 	if (data) {
1362 		freemsg(data);
1363 	}
1364 
1365 	return (USB_SUCCESS);
1366 
1367 fail:
1368 	if (data) {
1369 		freemsg(data);
1370 	}
1371 	USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1372 	    "usbvc_v4l2_query_ctrl: fail when %s", req);
1373 
1374 	return (USB_FAILURE);
1375 
1376 }
1377 
1378 
1379 /* Implement ioctl VIDIOC_G_CTRL, get current ctrl */
1380 static int
1381 usbvc_v4l2_get_ctrl(usbvc_state_t *usbvcp, struct v4l2_control *v4l2_ctrl)
1382 {
1383 	usbvc_v4l2_ctrl_t	ctrl;
1384 	mblk_t			*data;
1385 
1386 	if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, v4l2_ctrl->id) !=
1387 	    USB_SUCCESS) {
1388 
1389 		return (USB_FAILURE);
1390 	}
1391 	if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) {
1392 
1393 		return (USB_FAILURE);
1394 	}
1395 
1396 	if (usbvc_vc_get_ctrl(usbvcp, GET_CUR, ctrl.entity_id,
1397 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1398 		if (data) {
1399 			freemsg(data);
1400 		}
1401 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1402 		    "usbvc_v4l2_get_ctrl: fail");
1403 
1404 		return (USB_FAILURE);
1405 	}
1406 	LE_TO_UINT16(data->b_rptr, 0, v4l2_ctrl->value);
1407 
1408 	if (data) {
1409 		freemsg(data);
1410 	}
1411 
1412 	return (USB_SUCCESS);
1413 }
1414 
1415 
1416 /* Implement ioctl VIDIOC_S_CTRL */
1417 static int
1418 usbvc_v4l2_set_ctrl(usbvc_state_t *usbvcp, struct v4l2_control *v4l2_ctrl)
1419 {
1420 	usbvc_v4l2_ctrl_t	ctrl;
1421 	mblk_t			*data;
1422 
1423 	if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, v4l2_ctrl->id) !=
1424 	    USB_SUCCESS) {
1425 
1426 		return (USB_FAILURE);
1427 	}
1428 	if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) {
1429 
1430 		return (USB_FAILURE);
1431 	}
1432 
1433 	UINT16_TO_LE(v4l2_ctrl->value, 0, data->b_wptr);
1434 	data->b_wptr += 2;
1435 	if (usbvc_vc_set_ctrl(usbvcp, SET_CUR, ctrl.entity_id,
1436 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) !=
1437 	    USB_SUCCESS) {
1438 		if (data) {
1439 			freemsg(data);
1440 		}
1441 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1442 		    "usbvc_v4l2_set_ctrl: fail");
1443 
1444 		return (USB_FAILURE);
1445 	}
1446 	if (data) {
1447 		freemsg(data);
1448 	}
1449 
1450 	return (USB_SUCCESS);
1451 }
1452