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