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