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