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