xref: /illumos-gate/usr/src/uts/common/io/usb/clients/video/usbvc/usbvc_v4l2.c (revision 09dd0d6c99966261df3f1fee78347f66cae3235a)
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 
27 /*
28  * USB video class driver: V4L2 interface implementation.
29  */
30 
31 #include <sys/usb/usba.h>
32 #include <sys/fcntl.h>
33 #include <sys/cmn_err.h>
34 
35 #include <sys/usb/clients/video/usbvc/usbvc_var.h>
36 #include <sys/usb/clients/video/usbvc/usbvc.h>
37 #include <sys/videodev2.h>
38 
39 static int usbvc_v4l2_set_format(usbvc_state_t *, struct v4l2_format *);
40 static int usbvc_v4l2_get_format(usbvc_state_t *, struct v4l2_format *);
41 static void usbvc_v4l2_query_buf(usbvc_state_t *, usbvc_buf_t *,
42 				struct v4l2_buffer *);
43 static int usbvc_v4l2_enqueue_buf(usbvc_state_t *, usbvc_buf_t *,
44 				struct v4l2_buffer *);
45 static int usbvc_v4l2_dequeue_buffer(usbvc_state_t *,
46 				struct v4l2_buffer *, int);
47 static int usbvc_v4l2_query_ctrl(usbvc_state_t *, struct v4l2_queryctrl *);
48 static int usbvc_v4l2_get_ctrl(usbvc_state_t *, struct v4l2_control *);
49 static int usbvc_v4l2_set_ctrl(usbvc_state_t *, struct v4l2_control *);
50 static int usbvc_v4l2_set_parm(usbvc_state_t *, struct v4l2_streamparm *);
51 static int usbvc_v4l2_get_parm(usbvc_state_t *, struct v4l2_streamparm *);
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
usbvc_v4l2_ioctl(usbvc_state_t * usbvcp,int cmd,intptr_t arg,int mode)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_L4(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_L4(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_L3(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_L4(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_L4(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_L4(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_L4(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_L4(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 		strm_if->stream_on = 1; /* the only place to set this value */
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 		strm_if->stream_on = 0;
534 		mutex_exit(&usbvcp->usbvc_mutex);
535 
536 		break;
537 	}
538 
539 	case VIDIOC_ENUMINPUT:
540 	{
541 		struct v4l2_input input;
542 
543 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
544 		    "V4L2 ioctl: ENUMINPUT");
545 		USBVC_COPYIN(input);
546 
547 		if (input.index != 0) { /* Support only one INPUT now */
548 			rv = EINVAL;
549 
550 			break;
551 		}
552 		(void) strncpy((char *)input.name, "Camera Terminal",
553 		    sizeof (input.name));
554 		input.type = V4L2_INPUT_TYPE_CAMERA;
555 		USBVC_COPYOUT(input);
556 
557 		break;
558 	}
559 
560 	case VIDIOC_G_INPUT:
561 	{
562 		int input_idx = 0;	/* Support only one input now */
563 
564 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
565 		    "V4L2 ioctl: G_INPUT");
566 		USBVC_COPYOUT(input_idx);
567 
568 		break;
569 	}
570 
571 	case VIDIOC_S_INPUT:
572 	{
573 		int input_idx;
574 
575 		USBVC_COPYIN(input_idx);
576 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
577 		    "V4L2 ioctl: S_INPUT");
578 		if (input_idx != 0) {	/* Support only one input now */
579 			rv = EINVAL;
580 		}
581 
582 		break;
583 	}
584 
585 	/* Query the device that what kinds of video ctrls are supported */
586 	case VIDIOC_QUERYCTRL:
587 	{
588 		struct v4l2_queryctrl queryctrl;
589 
590 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
591 		    "V4L2 ioctl: QUERYCTRL");
592 		USBVC_COPYIN(queryctrl);
593 
594 		if (usbvc_v4l2_query_ctrl(usbvcp, &queryctrl) != USB_SUCCESS) {
595 			rv = EINVAL;
596 
597 			break;
598 		}
599 
600 		USBVC_COPYOUT(queryctrl);
601 
602 		break;
603 	}
604 	case VIDIOC_G_CTRL:
605 	{
606 		struct v4l2_control ctrl;
607 
608 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
609 		    "V4L2 ioctl: G_CTRL");
610 		USBVC_COPYIN(ctrl);
611 		if (usbvc_v4l2_get_ctrl(usbvcp, &ctrl) != USB_SUCCESS) {
612 			rv = EINVAL;
613 
614 			break;
615 		}
616 
617 		USBVC_COPYOUT(ctrl);
618 
619 		break;
620 	}
621 	case VIDIOC_S_CTRL:
622 	{
623 		struct v4l2_control ctrl;
624 
625 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
626 		    "V4L2 ioctl: S_CTRL");
627 		USBVC_COPYIN(ctrl);
628 		if (usbvc_v4l2_set_ctrl(usbvcp, &ctrl) != USB_SUCCESS) {
629 			rv = EINVAL;
630 
631 			break;
632 		}
633 
634 		USBVC_COPYOUT(ctrl);
635 
636 		break;
637 	}
638 	case VIDIOC_S_PARM:
639 	{
640 		struct v4l2_streamparm	parm;
641 		usbvc_stream_if_t	*strm_if;
642 
643 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
644 		    "V4L2 ioctl: VIDIOC_S_PARM");
645 		mutex_enter(&usbvcp->usbvc_mutex);
646 		strm_if = usbvcp->usbvc_curr_strm;
647 
648 		/* If data I/O is in progress */
649 		if (strm_if->start_polling == 1) {
650 			rv = EBUSY;
651 			mutex_exit(&usbvcp->usbvc_mutex);
652 
653 			break;
654 		}
655 		mutex_exit(&usbvcp->usbvc_mutex);
656 
657 		USBVC_COPYIN(parm);
658 
659 		/* Support capture only, so far. */
660 		if (parm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
661 			rv = EINVAL;
662 
663 			break;
664 		}
665 
666 		if (usbvc_v4l2_set_parm(usbvcp, &parm) != USB_SUCCESS) {
667 			rv = EINVAL;
668 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
669 			    usbvcp->usbvc_log_handle,
670 			    "V4L2 ioctl VIDIOC_S_PARM fail");
671 		}
672 		USBVC_COPYOUT(parm);
673 
674 		break;
675 	}
676 	case VIDIOC_G_PARM:
677 	{
678 		struct v4l2_streamparm	parm;
679 
680 		USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
681 		    "V4L2 ioctl: VIDIOC_G_PARM");
682 		USBVC_COPYIN(parm);
683 
684 		/* Support capture only, so far. */
685 		if (parm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
686 			rv = EINVAL;
687 
688 			break;
689 		}
690 
691 		if ((rv = usbvc_v4l2_get_parm(usbvcp, &parm)) != USB_SUCCESS) {
692 
693 			break;
694 		}
695 
696 		USBVC_COPYOUT(parm);
697 
698 		break;
699 	}
700 	/* These ioctls are for analog video standards. */
701 	case VIDIOC_G_STD:
702 	case VIDIOC_S_STD:
703 	case VIDIOC_ENUMSTD:
704 	case VIDIOC_QUERYSTD:
705 		rv = EINVAL;
706 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
707 		    "usbvc_v4l2_ioctl: not a supported cmd, cmd=%x", cmd);
708 
709 		break;
710 	default:
711 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
712 		    "usbvc_v4l2_ioctl: not a valid cmd value, cmd=%x", cmd);
713 		rv = ENOTTY;
714 	}
715 
716 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
717 	    "usbvc_v4l2_ioctl: exit, rv=%d", rv);
718 
719 	return (rv);
720 
721 }
722 
723 
724 /*
725  * Convert GUID in uncompressed format descriptor to the pixelformat element
726  * in struct v4l2_pix_format
727  */
728 uint32_t
usbvc_v4l2_guid2fcc(uint8_t * guid)729 usbvc_v4l2_guid2fcc(uint8_t *guid)
730 {
731 	uint32_t ret;
732 
733 	uint8_t y[16] = USBVC_FORMAT_GUID_YUY2;
734 	uint8_t n[16] = USBVC_FORMAT_GUID_NV12;
735 	if (!memcmp((void *)guid, (void *) &y[0], 16)) {
736 		ret = V4L2_PIX_FMT_YUYV;
737 
738 		return (ret);
739 	}
740 	if (!memcmp((void *)guid, (void *) &n, 16)) {
741 		ret = V4L2_PIX_FMT_NV12;
742 
743 		return (ret);
744 	}
745 
746 	return (0);
747 }
748 
749 
750 /*
751  * Find a frame which has the closest image size as the input args
752  * (width, height)
753  */
754 static usbvc_frames_t *
usbvc_match_image_size(uint32_t width,uint32_t height,usbvc_format_group_t * fmtgrp)755 usbvc_match_image_size(uint32_t width, uint32_t height,
756     usbvc_format_group_t *fmtgrp)
757 {
758 	uint32_t w, h, diff, sz, i;
759 	usbvc_frames_t *frame = NULL;
760 	usbvc_frame_descr_t *descr;
761 
762 	diff = 0xffffffff;
763 
764 	for (i = 0; i < fmtgrp->frame_cnt; i++) {
765 
766 		descr = fmtgrp->frames[i].descr;
767 		if (descr == NULL) {
768 
769 			continue;
770 		}
771 		LE_TO_UINT16(descr->wWidth, 0, w);
772 		LE_TO_UINT16(descr->wHeight, 0, h);
773 
774 		sz = min(w, width) * min(h, height);
775 		sz = (w * h + width * height - sz * 2);
776 		if (sz < diff) {
777 			frame = &fmtgrp->frames[i];
778 			diff = sz;
779 		}
780 
781 		if (diff == 0) {
782 
783 			return (frame);
784 		}
785 	}
786 
787 	return (frame);
788 }
789 
790 
791 /* Implement ioctl VIDIOC_S_FMT, set a video format */
792 static int
usbvc_v4l2_set_format(usbvc_state_t * usbvcp,struct v4l2_format * format)793 usbvc_v4l2_set_format(usbvc_state_t *usbvcp, struct v4l2_format *format)
794 {
795 	usbvc_vs_probe_commit_t	ctrl, ctrl_max, ctrl_min, ctrl_curr;
796 	usbvc_stream_if_t	*strm_if;
797 	usbvc_format_group_t	*fmtgrp;
798 	usbvc_frames_t		*frame;
799 	uint32_t		w, h, interval, bandwidth;
800 	uint8_t			type, i;
801 
802 	mutex_enter(&usbvcp->usbvc_mutex);
803 
804 	/*
805 	 * Get the first stream interface. Todo: deal with multi stream
806 	 * interfaces.
807 	 */
808 	strm_if = usbvcp->usbvc_curr_strm;
809 
810 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
811 	    "usbvc_v4l2_set_format: strm_if->fmtgrp_cnt=%d",
812 	    strm_if->fmtgrp_cnt);
813 
814 	/* Find the proper format group according to compress type and guid */
815 	for (i = 0; i < strm_if->fmtgrp_cnt; i++) {
816 		fmtgrp = &strm_if->format_group[i];
817 
818 		/*
819 		 * If v4l2_pixelformat is NULL, then that means there is not
820 		 * a parsed format in format_group[i].
821 		 */
822 		if (!fmtgrp->v4l2_pixelformat || fmtgrp->frame_cnt == 0) {
823 			USB_DPRINTF_L3(PRINT_MASK_DEVCTRL,
824 			    usbvcp->usbvc_log_handle,
825 			    "usbvc_set_default_stream_fmt: no frame, fail");
826 
827 			continue;
828 		}
829 		type = fmtgrp->format->bDescriptorSubType;
830 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
831 		    "usbvc_v4l2_set_format: type =%x, i =%d", type, i);
832 
833 		if ((type == VS_FORMAT_MJPEG) ||
834 		    (type == VS_FORMAT_UNCOMPRESSED)) {
835 			if (format->fmt.pix.pixelformat ==
836 			    fmtgrp->v4l2_pixelformat) {
837 
838 				break;
839 			}
840 		}
841 	}
842 
843 	if (i >= strm_if->fmtgrp_cnt) {
844 		mutex_exit(&usbvcp->usbvc_mutex);
845 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
846 		    "usbvc_v4l2_set_format: can't find a proper format, "
847 		    "pixelformat=%x", format->fmt.pix.pixelformat);
848 
849 		return (USB_FAILURE);
850 	}
851 
852 	fmtgrp = &strm_if->format_group[i];
853 
854 	frame = usbvc_match_image_size(format->fmt.pix.width,
855 	    format->fmt.pix.height, fmtgrp);
856 
857 	if (frame == NULL) {
858 		mutex_exit(&usbvcp->usbvc_mutex);
859 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
860 		    "usbvc_v4l2_set_format: can't find a proper frame, rw=%d, "
861 		    "rh=%d", format->fmt.pix.width, format->fmt.pix.height);
862 
863 		return (USB_FAILURE);
864 	}
865 
866 	/* frame interval */
867 	LE_TO_UINT32(frame->descr->dwDefaultFrameInterval, 0, interval);
868 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
869 	    "usbvc_v4l2_set_format: Default Frame Interval=%x", interval);
870 
871 	/*
872 	 * Begin negotiate formats.
873 	 */
874 	bzero((void *)&ctrl, sizeof (usbvc_vs_probe_commit_t));
875 
876 	/* dwFrameInterval is fixed */
877 	ctrl.bmHint[0] = 1;
878 
879 	ctrl.bFormatIndex = fmtgrp->format->bFormatIndex;
880 	ctrl.bFrameIndex = frame->descr->bFrameIndex;
881 	UINT32_TO_LE(interval, 0, ctrl.dwFrameInterval);
882 
883 	mutex_exit(&usbvcp->usbvc_mutex);
884 
885 	/* Probe, just a test before the real try */
886 	if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl, VS_PROBE_CONTROL)
887 	    != USB_SUCCESS) {
888 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
889 		    "usbvc_v4l2_set_format: set probe failed");
890 
891 		return (USB_FAILURE);
892 	}
893 
894 	/* Get max values */
895 	if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_max, GET_MAX) !=
896 	    USB_SUCCESS) {
897 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
898 		    "usbvc_v4l2_set_format: get probe MAX failed");
899 
900 		return (USB_FAILURE);
901 	}
902 
903 	/* Use the best quality first */
904 	bcopy(&ctrl_max.wCompQuality, &ctrl.wCompQuality, 2);
905 
906 	/*
907 	 * By now, we've get some parametres of ctrl req, next try to set ctrl.
908 	 */
909 	for (i = 0; i < 2; i++) {
910 
911 		/* Probe */
912 		if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl,
913 		    VS_PROBE_CONTROL) != USB_SUCCESS) {
914 
915 			return (USB_FAILURE);
916 		}
917 
918 		/* Get current value after probe */
919 		if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_curr, GET_CUR)
920 		    != USB_SUCCESS) {
921 
922 			return (USB_FAILURE);
923 		}
924 		LE_TO_UINT32(ctrl_curr.dwMaxPayloadTransferSize, 0, bandwidth);
925 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
926 		    "usbvc_v4l2_set_format: bandwidth=%x", bandwidth);
927 
928 		/*
929 		 * If the bandwidth does not exceed the max value of all the
930 		 * alternatives in this interface, we done.
931 		 */
932 		if (bandwidth <= strm_if->max_isoc_payload) {
933 
934 			break;
935 		}
936 		if (i >= 1) {
937 
938 			return (USB_FAILURE);
939 		}
940 
941 		/* Get minimum values since the bandwidth is not enough */
942 		if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_min, GET_MIN) !=
943 		    USB_SUCCESS) {
944 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
945 			    usbvcp->usbvc_log_handle,
946 			    "usbvc_v4l2_set_format: get probe MIN failed");
947 
948 			return (USB_FAILURE);
949 		}
950 
951 		/* To keep simple, just use some minimum values to try again */
952 		bcopy(&ctrl_min.wKeyFrameRate, &ctrl_curr.wKeyFrameRate, 2);
953 		bcopy(&ctrl_min.wPFrameRate, &ctrl_curr.wPFrameRate, 2);
954 		bcopy(&ctrl_min.wCompWindowSize, &ctrl_curr.wCompWindowSize, 2);
955 		bcopy(&ctrl_max.wCompQuality, &ctrl_curr.wCompQuality, 2);
956 
957 		bcopy(&ctrl_curr, &ctrl,
958 		    sizeof (usbvc_vs_probe_commit_t));
959 	}
960 
961 	bcopy(&ctrl_curr, &ctrl, sizeof (usbvc_vs_probe_commit_t));
962 
963 	/* commit the values we negotiated above */
964 	if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl,
965 	    VS_COMMIT_CONTROL) != USB_SUCCESS) {
966 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
967 		    "usbvc_v4l2_set_format: set probe failed, i=%d", i);
968 
969 		return (USB_FAILURE);
970 	}
971 	mutex_enter(&usbvcp->usbvc_mutex);
972 
973 	/*
974 	 * It's good to check index here before use it. bFormatIndex is based
975 	 * on 1, and format_group[i] is based on 0, so minus 1
976 	 */
977 	i = ctrl.bFormatIndex - 1;
978 	if (i < strm_if->fmtgrp_cnt) {
979 		strm_if->cur_format_group = &strm_if->format_group[i];
980 	} else {
981 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
982 		    "usbvc_v4l2_set_format: format index out of range");
983 		mutex_exit(&usbvcp->usbvc_mutex);
984 
985 		return (USB_FAILURE);
986 	}
987 
988 	/* bFrameIndex is based on 1, and frames[i] is based on 0, so minus 1 */
989 	i = ctrl.bFrameIndex -1;
990 	if (i < strm_if->cur_format_group->frame_cnt) {
991 		strm_if->cur_format_group->cur_frame =
992 		    &strm_if->cur_format_group->frames[i];
993 	} else {
994 		mutex_exit(&usbvcp->usbvc_mutex);
995 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
996 		    "usbvc_v4l2_set_format: frame index out of range");
997 
998 		return (USB_FAILURE);
999 	}
1000 
1001 	/*
1002 	 * by now, the video format is set successfully. record the current
1003 	 * setting to strm_if->ctrl_pc
1004 	 */
1005 	bcopy(&ctrl_curr, &strm_if->ctrl_pc, sizeof (usbvc_vs_probe_commit_t));
1006 
1007 	format->fmt.pix.colorspace = fmtgrp->v4l2_color;
1008 	format->fmt.pix.field = V4L2_FIELD_NONE;
1009 	format->fmt.pix.priv = 0;
1010 
1011 	LE_TO_UINT16(frame->descr->wWidth, 0, w);
1012 	LE_TO_UINT16(frame->descr->wHeight, 0, h);
1013 	format->fmt.pix.width = w;
1014 	format->fmt.pix.height = h;
1015 	format->fmt.pix.bytesperline = fmtgrp->v4l2_bpp * w;
1016 	LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0,
1017 	    format->fmt.pix.sizeimage);
1018 
1019 	mutex_exit(&usbvcp->usbvc_mutex);
1020 
1021 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1022 	    "usbvc_v4l2_set_format: dwMaxVideoFrameSize=%x, w=%x, h=%x",
1023 	    format->fmt.pix.sizeimage, w, h);
1024 
1025 	return (USB_SUCCESS);
1026 }
1027 
1028 
1029 /* Implement ioctl VIDIOC_G_FMT, get the current video format */
1030 static int
usbvc_v4l2_get_format(usbvc_state_t * usbvcp,struct v4l2_format * format)1031 usbvc_v4l2_get_format(usbvc_state_t *usbvcp, struct v4l2_format *format)
1032 {
1033 	usbvc_stream_if_t	*strm_if;
1034 	usbvc_format_group_t	*fmtgrp;
1035 	uint16_t		w, h;
1036 
1037 	if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1038 
1039 		return (EINVAL);
1040 	}
1041 	mutex_enter(&usbvcp->usbvc_mutex);
1042 
1043 	/* get the current interface. */
1044 	strm_if = usbvcp->usbvc_curr_strm;
1045 	fmtgrp = strm_if->cur_format_group;
1046 
1047 	if (!fmtgrp || !fmtgrp->cur_frame) {
1048 		mutex_exit(&usbvcp->usbvc_mutex);
1049 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1050 		    "usbvc_v4l2_get_format: fail, no current format or frame,"
1051 		    "fmtgrp=%p", (void *)fmtgrp);
1052 
1053 		return (EINVAL);
1054 	}
1055 	format->fmt.pix.colorspace = fmtgrp->v4l2_color;
1056 	format->fmt.pix.priv = 0;
1057 	format->fmt.pix.pixelformat = fmtgrp->v4l2_pixelformat;
1058 
1059 	LE_TO_UINT16(fmtgrp->cur_frame->descr->wWidth, 0, w);
1060 	LE_TO_UINT16(fmtgrp->cur_frame->descr->wHeight, 0, h);
1061 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1062 	    "v4l2 ioctl get format ");
1063 	format->fmt.pix.width = w;
1064 	format->fmt.pix.height = h;
1065 
1066 	format->fmt.pix.field = V4L2_FIELD_NONE;
1067 	format->fmt.pix.bytesperline = fmtgrp->v4l2_bpp * w;
1068 
1069 	LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0,
1070 	    format->fmt.pix.sizeimage);
1071 
1072 	mutex_exit(&usbvcp->usbvc_mutex);
1073 
1074 	return (0);
1075 }
1076 
1077 
1078 /*
1079  * Convert color space descriptor's bColorPrimaries to the colorspace element
1080  * in struct v4l2_pix_format
1081  */
1082 uint8_t
usbvc_v4l2_colorspace(uint8_t color_prim)1083 usbvc_v4l2_colorspace(uint8_t color_prim)
1084 {
1085 
1086 	if (color_prim < NELEM(color_primaries)) {
1087 
1088 		return (color_primaries[color_prim]);
1089 	}
1090 
1091 	return (0);
1092 }
1093 
1094 
1095 /* Implement ioctl VIDIOC_QUERYBUF, get the buf status */
1096 static void
usbvc_v4l2_query_buf(usbvc_state_t * usbvcp,usbvc_buf_t * usbvc_buf,struct v4l2_buffer * v4l2_buf)1097 usbvc_v4l2_query_buf(usbvc_state_t *usbvcp, usbvc_buf_t *usbvc_buf,
1098 	struct v4l2_buffer *v4l2_buf)
1099 {
1100 	ASSERT(mutex_owned(&usbvcp->usbvc_mutex));
1101 
1102 	bcopy(&(usbvc_buf->v4l2_buf), v4l2_buf, sizeof (struct v4l2_buffer));
1103 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1104 	    "usbvc_v4l2_query_buf: uv_buf_len=%d, len=%d",
1105 	    usbvc_buf->v4l2_buf.length, v4l2_buf->length);
1106 
1107 	if (usbvc_buf->status >= USBVC_BUF_MAPPED) {
1108 		v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
1109 	}
1110 
1111 	switch (usbvc_buf->status) {
1112 	case USBVC_BUF_DONE:
1113 	case USBVC_BUF_ERR:
1114 		v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
1115 
1116 		break;
1117 	case USBVC_BUF_EMPTY:
1118 		v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
1119 
1120 		break;
1121 	case USBVC_BUF_INIT:
1122 	default:
1123 
1124 		break;
1125 	}
1126 }
1127 
1128 
1129 /* Implement ioctl VIDIOC_QBUF, queue a empty buf to the free list */
1130 static int
usbvc_v4l2_enqueue_buf(usbvc_state_t * usbvcp,usbvc_buf_t * usbvc_buf,struct v4l2_buffer * buf)1131 usbvc_v4l2_enqueue_buf(usbvc_state_t *usbvcp, usbvc_buf_t *usbvc_buf,
1132 	struct v4l2_buffer *buf)
1133 {
1134 	usbvc_buf_t	*donebuf;
1135 	boolean_t	queued = B_FALSE;
1136 	usbvc_buf_grp_t	*bufgrp;
1137 
1138 	ASSERT(mutex_owned(&usbvcp->usbvc_mutex));
1139 
1140 	bufgrp = &usbvcp->usbvc_curr_strm->buf_map;
1141 
1142 	if (usbvc_buf == bufgrp->buf_filling) {
1143 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1144 		    "enqueue_buffer(%d) , want to queue buf_filling, "
1145 		    "just return success", buf->index);
1146 
1147 		return (0);
1148 	}
1149 
1150 	if (!list_is_empty(&bufgrp->uv_buf_done)) {
1151 		donebuf = (usbvc_buf_t *)list_head(&bufgrp->uv_buf_done);
1152 		while (donebuf) {
1153 
1154 			if (donebuf == &(bufgrp->buf_head[buf->index])) {
1155 				queued = B_TRUE;
1156 
1157 				break;
1158 			}
1159 			donebuf = (usbvc_buf_t *)list_next(&bufgrp->uv_buf_done,
1160 			    donebuf);
1161 		}
1162 	}
1163 	if (queued) {
1164 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1165 		    "enqueue_buffer(%d), still in done list, don't insert to"
1166 		    " free list", buf->index);
1167 
1168 		return (0);
1169 	}
1170 
1171 	if (usbvc_buf->status == USBVC_BUF_EMPTY) {
1172 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1173 		    "enqueue buffer(%d), already queued.", buf->index);
1174 
1175 		return (0);
1176 
1177 	}
1178 	if (usbvc_buf->status < USBVC_BUF_MAPPED) {
1179 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1180 		    "enqueue buffer(%d), state error, not mapped.", buf->index);
1181 
1182 		return (EINVAL);
1183 	}
1184 
1185 	/*
1186 	 * The buf is put to the buf free list when allocated, so, if the buf
1187 	 * is the first time to enqueue, just change the state to empty is
1188 	 * enough.
1189 	 */
1190 	if (usbvc_buf->status == USBVC_BUF_MAPPED) {
1191 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1192 		    "queue_buffer(%d), 1st time queue this buf", buf->index);
1193 
1194 		usbvc_buf->status = USBVC_BUF_EMPTY;
1195 
1196 	} else {
1197 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1198 		    "enqueue_buffer(%d) , USBVC_BUF_EMPTY", buf->index);
1199 
1200 		usbvc_buf->status = USBVC_BUF_EMPTY;
1201 		usbvc_buf->v4l2_buf.bytesused = 0;
1202 		list_insert_tail(&bufgrp->uv_buf_free, usbvc_buf);
1203 	}
1204 	buf->flags &= ~V4L2_BUF_FLAG_DONE;
1205 	buf->flags |= V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
1206 
1207 	return (0);
1208 }
1209 
1210 
1211 /* Implement ioctl VIDIOC_DQBUF, pick a buf from done list */
1212 static int
usbvc_v4l2_dequeue_buffer(usbvc_state_t * usbvcp,struct v4l2_buffer * buf,int mode)1213 usbvc_v4l2_dequeue_buffer(usbvc_state_t *usbvcp, struct v4l2_buffer *buf,
1214 	int mode)
1215 {
1216 	usbvc_buf_t *buf_done;
1217 
1218 	ASSERT(mutex_owned(&usbvcp->usbvc_mutex));
1219 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1220 	    "usbvc_v4l2_dequeue_buffer: idx=%x", buf->index);
1221 
1222 	/* v4l2 spec: app just set type and memory field */
1223 	if ((buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
1224 	    (buf->memory != V4L2_MEMORY_MMAP)) {
1225 
1226 		return (EINVAL);
1227 	}
1228 	if ((mode & (O_NDELAY|O_NONBLOCK)) &&
1229 	    (list_is_empty(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done))) {
1230 
1231 		/* non-blocking */
1232 		return (EAGAIN);
1233 	}
1234 
1235 	/* no available buffers, block here */
1236 	while (list_is_empty(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done)) {
1237 		USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1238 		    "usbvc_v4l2_dequeue_buffer: wait for done buf");
1239 		if (cv_wait_sig(&usbvcp->usbvc_mapio_cv, &usbvcp->usbvc_mutex)
1240 		    <= 0) {
1241 
1242 			/* no done buf and is signaled */
1243 			return (EINTR);
1244 		}
1245 		if (usbvcp->usbvc_dev_state != USB_DEV_ONLINE) {
1246 
1247 			/* Device is disconnected. */
1248 			return (EINTR);
1249 		}
1250 	}
1251 
1252 	buf_done = list_head(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done);
1253 
1254 	list_remove(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done, buf_done);
1255 
1256 	/*
1257 	 * just copy the v4l2_buf structure because app need only the index
1258 	 * value to locate the mapped memory
1259 	 */
1260 	bcopy(&buf_done->v4l2_buf, buf, sizeof (struct v4l2_buffer));
1261 	buf->flags |= V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_MAPPED;
1262 	buf->bytesused = buf_done->filled;
1263 	USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1264 	    "usbvc_v4l2_dequeue_buffer: bytesused=%d, idx=%x, status=%d",
1265 	    buf->bytesused, buf->index, buf_done->status);
1266 
1267 	return (0);
1268 }
1269 
1270 
1271 /*
1272  * Check if a ctrl_id is supported by the device, if yes, find the
1273  * corresponding processing unit and fill usbvc_v4l2_ctrl_t
1274  */
1275 static int
usbvc_v4l2_match_ctrl(usbvc_state_t * usbvcp,usbvc_v4l2_ctrl_t * ctrl,uint32_t ctrl_id)1276 usbvc_v4l2_match_ctrl(usbvc_state_t *usbvcp, usbvc_v4l2_ctrl_t *ctrl,
1277     uint32_t ctrl_id)
1278 {
1279 	uint8_t		idx;
1280 	usbvc_units_t	*unit;
1281 	uchar_t		bit;
1282 
1283 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1284 	    "usbvc_v4l2_match_ctrl: ctrl_id=%x", ctrl_id);
1285 	if (ctrl_id >= V4L2_CID_PRIVATE_BASE) {
1286 
1287 		return (USB_FAILURE);
1288 	}
1289 	if (ctrl_id < V4L2_CID_BASE) {
1290 
1291 		return (USB_FAILURE);
1292 	}
1293 
1294 	/* get the idx of ctrl array usbvc_v4l2_ctrl */
1295 	idx = ctrl_id - V4L2_CID_BASE;
1296 	if (ctrl_id == V4L2_CID_GAMMA) {
1297 
1298 		/* The 4th one is for Gamma ctrl */
1299 		bit = usbvc_v4l2_ctrls[4].bit;
1300 	} else if ((ctrl_id >= V4L2_CID_BRIGHTNESS) &&
1301 	    (ctrl_id <= V4L2_CID_HUE)) {
1302 
1303 		/* The idxth one is for this ctrl */
1304 		bit = usbvc_v4l2_ctrls[idx].bit;
1305 	} else {
1306 
1307 		return (USB_FAILURE);
1308 	}
1309 	unit = (usbvc_units_t *)list_head(&usbvcp->usbvc_unit_list);
1310 
1311 	/*
1312 	 * Check if there is a processing unit supportting this ctrl.
1313 	 * Todo: check if the ctrl and the unit is really for the right
1314 	 * stream interface in case of multi stream interfaces.
1315 	 */
1316 	while (unit != NULL) {
1317 
1318 		if (unit->descr->bDescriptorSubType == VC_PROCESSING_UNIT) {
1319 
1320 			if (bit >=
1321 			    (unit->descr->unit.processing.bControlSize * 8)) {
1322 
1323 				/*
1324 				 * If this unit's bmControls size is smaller
1325 				 * than bit, then next
1326 				 */
1327 				unit = (usbvc_units_t *)
1328 				    list_next(&usbvcp->usbvc_unit_list, unit);
1329 
1330 				continue;
1331 			} else {
1332 
1333 				/*
1334 				 * The first two bytes of bmControls are
1335 				 * for ctrls
1336 				 */
1337 				if ((bit < 8) &&
1338 				    unit->bmControls[0] & (0x1 << bit)) {
1339 
1340 					break;
1341 				}
1342 				if ((bit >= 8 && bit < 16) &&
1343 				    unit->bmControls[1] & (0x1 << bit)) {
1344 
1345 					break;
1346 				}
1347 			}
1348 		}
1349 		unit = (usbvc_units_t *)list_next(&usbvcp->usbvc_unit_list,
1350 		    unit);
1351 	}
1352 	if (unit == NULL) {
1353 
1354 		return (USB_FAILURE);
1355 	}
1356 	ctrl->entity_id = unit->descr->bUnitID;
1357 	if (ctrl_id == V4L2_CID_GAMMA) {
1358 		ctrl->ctrl_map = &usbvc_v4l2_ctrls[4];
1359 	} else {
1360 		ctrl->ctrl_map = &usbvc_v4l2_ctrls[idx];
1361 	}
1362 
1363 	return (USB_SUCCESS);
1364 }
1365 
1366 
1367 /*
1368  * Implement ioctl VIDIOC_QUERYCTRL, query the ctrl types that the device
1369  * supports
1370  */
1371 static int
usbvc_v4l2_query_ctrl(usbvc_state_t * usbvcp,struct v4l2_queryctrl * queryctrl)1372 usbvc_v4l2_query_ctrl(usbvc_state_t *usbvcp, struct v4l2_queryctrl *queryctrl)
1373 {
1374 	usbvc_v4l2_ctrl_t	ctrl;
1375 	mblk_t			*data;
1376 	char			req[16];
1377 
1378 	if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, queryctrl->id) !=
1379 	    USB_SUCCESS) {
1380 
1381 		return (USB_FAILURE);
1382 	}
1383 	if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) {
1384 
1385 		return (USB_FAILURE);
1386 	}
1387 
1388 	if (usbvc_vc_get_ctrl(usbvcp, GET_MIN, ctrl.entity_id,
1389 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) !=
1390 	    USB_SUCCESS) {
1391 		(void) strncpy(&req[0], "GET_MIN", sizeof (req));
1392 
1393 		goto fail;
1394 	}
1395 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->minimum);
1396 	if (usbvc_vc_get_ctrl(usbvcp, GET_MAX, ctrl.entity_id,
1397 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1398 		(void) strncpy(&req[0], "GET_MAX", sizeof (req));
1399 
1400 		goto fail;
1401 	}
1402 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->maximum);
1403 
1404 	if (usbvc_vc_get_ctrl(usbvcp, GET_RES, ctrl.entity_id,
1405 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1406 		(void) strncpy(&req[0], "GET_RES", sizeof (req));
1407 
1408 		goto fail;
1409 	}
1410 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->step);
1411 
1412 	if (usbvc_vc_get_ctrl(usbvcp, GET_DEF, ctrl.entity_id,
1413 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1414 		(void) strncpy(&req[0], "GET_DEF", sizeof (req));
1415 
1416 		goto fail;
1417 	}
1418 	LE_TO_UINT16(data->b_rptr, 0, queryctrl->default_value);
1419 
1420 	(void) strncpy(queryctrl->name, ctrl.ctrl_map->name,
1421 	    sizeof (queryctrl->name));
1422 	queryctrl->type = ctrl.ctrl_map->type;
1423 	queryctrl->flags = 0;
1424 
1425 	if (data) {
1426 		freemsg(data);
1427 	}
1428 
1429 	return (USB_SUCCESS);
1430 
1431 fail:
1432 	if (data) {
1433 		freemsg(data);
1434 	}
1435 	USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1436 	    "usbvc_v4l2_query_ctrl: fail when %s", req);
1437 
1438 	return (USB_FAILURE);
1439 
1440 }
1441 
1442 
1443 /* Implement ioctl VIDIOC_G_CTRL, get current ctrl */
1444 static int
usbvc_v4l2_get_ctrl(usbvc_state_t * usbvcp,struct v4l2_control * v4l2_ctrl)1445 usbvc_v4l2_get_ctrl(usbvc_state_t *usbvcp, struct v4l2_control *v4l2_ctrl)
1446 {
1447 	usbvc_v4l2_ctrl_t	ctrl;
1448 	mblk_t			*data;
1449 
1450 	if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, v4l2_ctrl->id) !=
1451 	    USB_SUCCESS) {
1452 
1453 		return (USB_FAILURE);
1454 	}
1455 	if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) {
1456 
1457 		return (USB_FAILURE);
1458 	}
1459 
1460 	if (usbvc_vc_get_ctrl(usbvcp, GET_CUR, ctrl.entity_id,
1461 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) {
1462 		if (data) {
1463 			freemsg(data);
1464 		}
1465 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1466 		    "usbvc_v4l2_get_ctrl: fail");
1467 
1468 		return (USB_FAILURE);
1469 	}
1470 	LE_TO_UINT16(data->b_rptr, 0, v4l2_ctrl->value);
1471 
1472 	if (data) {
1473 		freemsg(data);
1474 	}
1475 
1476 	return (USB_SUCCESS);
1477 }
1478 
1479 
1480 /* Implement ioctl VIDIOC_S_CTRL */
1481 static int
usbvc_v4l2_set_ctrl(usbvc_state_t * usbvcp,struct v4l2_control * v4l2_ctrl)1482 usbvc_v4l2_set_ctrl(usbvc_state_t *usbvcp, struct v4l2_control *v4l2_ctrl)
1483 {
1484 	usbvc_v4l2_ctrl_t	ctrl;
1485 	mblk_t			*data;
1486 
1487 	if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, v4l2_ctrl->id) !=
1488 	    USB_SUCCESS) {
1489 
1490 		return (USB_FAILURE);
1491 	}
1492 	if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) {
1493 
1494 		return (USB_FAILURE);
1495 	}
1496 
1497 	UINT16_TO_LE(v4l2_ctrl->value, 0, data->b_wptr);
1498 	data->b_wptr += 2;
1499 	if (usbvc_vc_set_ctrl(usbvcp, SET_CUR, ctrl.entity_id,
1500 	    ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) !=
1501 	    USB_SUCCESS) {
1502 		if (data) {
1503 			freemsg(data);
1504 		}
1505 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1506 		    "usbvc_v4l2_set_ctrl: fail");
1507 
1508 		return (USB_FAILURE);
1509 	}
1510 	if (data) {
1511 		freemsg(data);
1512 	}
1513 
1514 	return (USB_SUCCESS);
1515 }
1516 
1517 /* For the given interval, find the closest frame interval to it. */
1518 static uint32_t
usbvc_find_interval(usbvc_frames_t * frame,uint32_t interval)1519 usbvc_find_interval(usbvc_frames_t *frame, uint32_t interval)
1520 {
1521 	uint32_t step, i, closest, index, approx1, approx2;
1522 
1523 
1524 	/*
1525 	 * for continuous case, there is a min and a max, and also a step
1526 	 * value. The available intervals are those between min and max
1527 	 * values.
1528 	 */
1529 	if (!frame->descr->bFrameIntervalType) {
1530 		step = frame->dwFrameIntervalStep;
1531 
1532 		if (step == 0) {
1533 		/* a malfunction device */
1534 
1535 			return (0);
1536 		} else if (interval <= frame->dwMinFrameInterval) {
1537 		/* return the most possible interval we can handle */
1538 
1539 			return (frame->dwMinFrameInterval);
1540 		} else if (interval >= frame->dwMaxFrameInterval) {
1541 		/* return the most possible interval we can handle */
1542 
1543 			return (frame->dwMaxFrameInterval);
1544 		}
1545 
1546 		approx1 = (interval / step) * step;
1547 		approx2 = approx1 + step;
1548 		closest = ((interval - approx1) < (approx2 - interval)) ?
1549 		    approx1 : approx2;
1550 
1551 		return (closest);
1552 	}
1553 
1554 	/*
1555 	 * for discrete case, search all the available intervals, find the
1556 	 * closest one.
1557 	 */
1558 	closest = 0;
1559 	approx2 = (uint32_t)-1;
1560 	for (index = 0; index < frame->descr->bFrameIntervalType; index++) {
1561 		LE_TO_UINT32(frame->dwFrameInterval, index * 4, i);
1562 		approx1 = (i > interval) ? (i - interval) : (interval - i);
1563 
1564 		if (approx1 == 0) {
1565 		/* find the matched one, return it immediately */
1566 			return (i);
1567 		}
1568 
1569 		if (approx1 < approx2) {
1570 			approx2 = approx1;
1571 			closest = i;
1572 		}
1573 	}
1574 
1575 	return (closest);
1576 }
1577 
1578 /* Implement ioctl VIDIOC_S_PARM. Support capture only, so far. */
1579 static int
usbvc_v4l2_set_parm(usbvc_state_t * usbvcp,struct v4l2_streamparm * parm)1580 usbvc_v4l2_set_parm(usbvc_state_t *usbvcp, struct v4l2_streamparm *parm)
1581 {
1582 	usbvc_stream_if_t	*strm_if;
1583 	usbvc_format_group_t	*cur_fmt;
1584 	usbvc_frames_t			*cur_frame;
1585 	uint32_t n, d, c, i;
1586 	usbvc_vs_probe_commit_t	ctrl;
1587 
1588 	mutex_enter(&usbvcp->usbvc_mutex);
1589 	strm_if = usbvcp->usbvc_curr_strm;
1590 
1591 	if (!strm_if->cur_format_group ||
1592 	    !strm_if->cur_format_group->cur_frame) {
1593 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1594 		    "usbvc_v4l2_set_parm: current format or"
1595 		    " frame is not set. cur_fmt=%p",
1596 		    (void *)strm_if->cur_format_group);
1597 
1598 		mutex_exit(&usbvcp->usbvc_mutex);
1599 
1600 		return (USB_FAILURE);
1601 	}
1602 
1603 	cur_fmt = strm_if->cur_format_group;
1604 	cur_frame = cur_fmt->cur_frame;
1605 
1606 	mutex_exit(&usbvcp->usbvc_mutex);
1607 	if (parm->parm.capture.readbuffers > USBVC_MAX_READ_BUF_NUM) {
1608 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1609 		    "usbvc_v4l2_set_parm: ask too many read buffers,"
1610 		    " readbuffers=%d",
1611 		    parm->parm.capture.readbuffers);
1612 
1613 		return (USB_FAILURE);
1614 	}
1615 
1616 	n = parm->parm.capture.timeperframe.numerator;
1617 	d = parm->parm.capture.timeperframe.denominator;
1618 
1619 	/* check the values passed in, in case of zero devide */
1620 	if (d == 0) {
1621 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1622 		    "usbvc_v4l2_set_parm: invalid denominator=%d", d);
1623 
1624 		return (USB_FAILURE);
1625 	}
1626 
1627 	/*
1628 	 * UVC frame intervals are in 100ns units, need convert from
1629 	 * 1s unit to 100ns unit
1630 	 */
1631 	c = USBVC_FRAME_INTERVAL_DENOMINATOR;
1632 
1633 	/* check the values passed in, in case of overflow */
1634 	if (n / d >= ((uint32_t)-1) / c) {
1635 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1636 		    "usbvc_v4l2_set_parm: overflow, numerator=%d,"
1637 		    " denominator=%d", n, d);
1638 
1639 		return (USB_FAILURE);
1640 	}
1641 
1642 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1643 	    "usbvc_v4l2_set_parm: numerator=%d, denominator=%d", n, d);
1644 
1645 	/* compute the interval in 100ns unit */
1646 	if (n <= ((uint32_t)-1) / c) {
1647 		i = (n * c) / d;
1648 	} else {
1649 		do {
1650 			n >>= 1;
1651 			d >>= 1;
1652 		/* decrease both n and d, in case overflow */
1653 		} while (n && d && n > ((uint32_t)-1) / c);
1654 
1655 		if (!d) {
1656 			USB_DPRINTF_L2(PRINT_MASK_IOCTL,
1657 			    usbvcp->usbvc_log_handle,
1658 			    "usbvc_v4l2_set_parm: can't compute interval,"
1659 			    " denominator=%d", d);
1660 
1661 			return (USB_FAILURE);
1662 		}
1663 		i = (n * c) / d;
1664 	}
1665 
1666 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1667 	    "usbvc_v4l2_set_parm: want interval=%d, n=%d, d=%d, c=%d",
1668 	    i, n, d, c);
1669 
1670 	/*
1671 	 * Begin negotiate frame intervals.
1672 	 */
1673 	bcopy(&strm_if->ctrl_pc, &ctrl, sizeof (usbvc_vs_probe_commit_t));
1674 	i = usbvc_find_interval(cur_frame, i);
1675 
1676 	if (i == 0) {
1677 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1678 		    "usbvc_v4l2_set_parm: can not find an proper interval."
1679 		    " i=%d, n=%d, d=%d", i, n, d);
1680 
1681 		return (USB_FAILURE);
1682 	}
1683 
1684 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1685 	    "usbvc_v4l2_set_parm: get interval=%d", i);
1686 
1687 	UINT32_TO_LE(i, 0, ctrl.dwFrameInterval);
1688 
1689 	/* Probe, just a test before the real try */
1690 	if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl, VS_PROBE_CONTROL)
1691 	    != USB_SUCCESS) {
1692 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1693 		    "usbvc_v4l2_set_parm: set probe failed");
1694 
1695 		return (USB_FAILURE);
1696 	}
1697 
1698 	/* Commit the frame interval. */
1699 	if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl, VS_COMMIT_CONTROL)
1700 	    != USB_SUCCESS) {
1701 		USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
1702 		    "usbvc_v4l2_set_parm: set commit failed");
1703 
1704 		return (USB_FAILURE);
1705 	}
1706 
1707 	bcopy(&ctrl, &strm_if->ctrl_pc, sizeof (usbvc_vs_probe_commit_t));
1708 
1709 	LE_TO_UINT32(ctrl.dwFrameInterval, 0, i);
1710 	parm->parm.capture.timeperframe.numerator = i;
1711 	parm->parm.capture.timeperframe.denominator = c;
1712 
1713 	mutex_enter(&usbvcp->usbvc_mutex);
1714 	/*
1715 	 * According to ioctl VIDIOC_S_PARM, zero value of readbuffers will not
1716 	 * be set. And the current value is expected to return to application.
1717 	 */
1718 	if (parm->parm.capture.readbuffers != 0) {
1719 		strm_if->buf_read_num = parm->parm.capture.readbuffers;
1720 	} else {
1721 		parm->parm.capture.readbuffers = strm_if->buf_read_num;
1722 	}
1723 	mutex_exit(&usbvcp->usbvc_mutex);
1724 
1725 	return (USB_SUCCESS);
1726 }
1727 
1728 /* Implement ioctl VIDIOC_G_PARM. */
1729 static int
usbvc_v4l2_get_parm(usbvc_state_t * usbvcp,struct v4l2_streamparm * parm)1730 usbvc_v4l2_get_parm(usbvc_state_t *usbvcp, struct v4l2_streamparm *parm)
1731 {
1732 	usbvc_stream_if_t	*strm_if;
1733 	uint32_t n, d;
1734 
1735 	bzero(parm, sizeof (*parm));
1736 
1737 	mutex_enter(&usbvcp->usbvc_mutex);
1738 	strm_if = usbvcp->usbvc_curr_strm;
1739 
1740 	/* return the actual number of buffers allocated for read() I/O */
1741 	parm->parm.capture.readbuffers = strm_if->buf_read.buf_cnt;
1742 
1743 	/* in 100ns units */
1744 	LE_TO_UINT32(strm_if->ctrl_pc.dwFrameInterval, 0, n);
1745 	mutex_exit(&usbvcp->usbvc_mutex);
1746 
1747 	/*
1748 	 * According to UVC payload specs, the dwFrameInterval in frame
1749 	 * descriptors is in 100ns unit.
1750 	 */
1751 	d = USBVC_FRAME_INTERVAL_DENOMINATOR;
1752 	parm->parm.capture.timeperframe.numerator = n;
1753 	parm->parm.capture.timeperframe.denominator = d;
1754 
1755 	/* Support capture only, so far. */
1756 	parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1757 	parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
1758 	parm->parm.capture.capturemode = 0; /* no high quality imaging mode */
1759 	parm->parm.capture.extendedmode = 0; /* no driver specific parameters */
1760 
1761 	/* Always success for current support of this command */
1762 	return (USB_SUCCESS);
1763 }
1764