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