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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * USB video class driver: V4L2 interface implementation. 30 */ 31 32 #include <sys/usb/usba.h> 33 #include <sys/fcntl.h> 34 #include <sys/cmn_err.h> 35 36 #include <sys/usb/clients/video/usbvc/usbvc_var.h> 37 #include <sys/usb/clients/video/usbvc/usbvc.h> 38 #include <sys/videodev2.h> 39 40 static int usbvc_v4l2_set_format(usbvc_state_t *, struct v4l2_format *); 41 static int usbvc_v4l2_get_format(usbvc_state_t *, struct v4l2_format *); 42 static void usbvc_v4l2_query_buf(usbvc_state_t *, usbvc_buf_t *, 43 struct v4l2_buffer *); 44 static int usbvc_v4l2_enqueue_buf(usbvc_state_t *, usbvc_buf_t *, 45 struct v4l2_buffer *); 46 static int usbvc_v4l2_dequeue_buffer(usbvc_state_t *, 47 struct v4l2_buffer *, int); 48 static int usbvc_v4l2_query_ctrl(usbvc_state_t *, struct v4l2_queryctrl *); 49 static int usbvc_v4l2_get_ctrl(usbvc_state_t *, struct v4l2_control *); 50 static int usbvc_v4l2_set_ctrl(usbvc_state_t *, struct v4l2_control *); 51 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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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 /* These ioctls are for analog video standards. */ 637 case VIDIOC_G_STD: 638 case VIDIOC_S_STD: 639 case VIDIOC_ENUMSTD: 640 case VIDIOC_QUERYSTD: 641 rv = EINVAL; 642 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 643 "usbvc_v4l2_ioctl: not a supported cmd, cmd=%x", cmd); 644 645 break; 646 default: 647 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 648 "usbvc_v4l2_ioctl: not a valid cmd value, cmd=%x", cmd); 649 rv = ENOTTY; 650 } 651 652 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 653 "usbvc_v4l2_ioctl: exit, rv=%d", rv); 654 655 return (rv); 656 657 } 658 659 660 /* 661 * Convert GUID in uncompressed format descriptor to the pixelformat element 662 * in struct v4l2_pix_format 663 */ 664 uint32_t 665 usbvc_v4l2_guid2fcc(uint8_t *guid) 666 { 667 uint32_t ret; 668 669 uint8_t y[16] = USBVC_FORMAT_GUID_YUY2; 670 uint8_t n[16] = USBVC_FORMAT_GUID_NV12; 671 if (!memcmp((void *)guid, (void *) &y[0], 16)) { 672 ret = V4L2_PIX_FMT_YUYV; 673 674 return (ret); 675 } 676 if (!memcmp((void *)guid, (void *) &n, 16)) { 677 ret = V4L2_PIX_FMT_NV12; 678 679 return (ret); 680 } 681 682 return (0); 683 } 684 685 686 /* 687 * Find a frame which has the closest image size as the input args 688 * (width, height) 689 */ 690 static usbvc_frames_t * 691 usbvc_match_image_size(uint32_t width, uint32_t height, 692 usbvc_format_group_t *fmtgrp) 693 { 694 uint32_t w, h, diff, sz, i; 695 usbvc_frames_t *frame = NULL; 696 usbvc_frame_descr_t *descr; 697 698 diff = 0xffffffff; 699 700 for (i = 0; i < fmtgrp->frame_cnt; i++) { 701 702 descr = fmtgrp->frames[i].descr; 703 if (descr == NULL) { 704 705 continue; 706 } 707 LE_TO_UINT16(descr->wWidth, 0, w); 708 LE_TO_UINT16(descr->wHeight, 0, h); 709 710 sz = min(w, width) * min(h, height); 711 sz = (w * h + width * height - sz * 2); 712 if (sz < diff) { 713 frame = &fmtgrp->frames[i]; 714 diff = sz; 715 } 716 717 if (diff == 0) { 718 719 return (frame); 720 } 721 } 722 723 return (frame); 724 } 725 726 727 /* Implement ioctl VIDIOC_S_FMT, set a video format */ 728 static int 729 usbvc_v4l2_set_format(usbvc_state_t *usbvcp, struct v4l2_format *format) 730 { 731 usbvc_vs_probe_commit_t ctrl, ctrl_max, ctrl_min, ctrl_curr; 732 usbvc_stream_if_t *strm_if; 733 usbvc_format_group_t *fmtgrp; 734 usbvc_frames_t *frame; 735 uint32_t w, h, interval, bandwidth; 736 uint8_t type, i; 737 738 mutex_enter(&usbvcp->usbvc_mutex); 739 740 /* 741 * Get the first stream interface. Todo: deal with multi stream 742 * interfaces. 743 */ 744 strm_if = usbvcp->usbvc_curr_strm; 745 746 USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 747 "usbvc_v4l2_set_format: strm_if->fmtgrp_cnt=%d", 748 strm_if->fmtgrp_cnt); 749 750 /* Find the proper format group according to compress type and guid */ 751 for (i = 0; i < strm_if->fmtgrp_cnt; i++) { 752 fmtgrp = &strm_if->format_group[i]; 753 754 /* 755 * If v4l2_pixelformat is NULL, then that means there is not 756 * a parsed format in format_group[i]. 757 */ 758 if (!fmtgrp->v4l2_pixelformat || fmtgrp->frame_cnt == 0) { 759 USB_DPRINTF_L3(PRINT_MASK_DEVCTRL, 760 usbvcp->usbvc_log_handle, 761 "usbvc_set_default_stream_fmt: no frame, fail"); 762 763 continue; 764 } 765 type = fmtgrp->format->bDescriptorSubType; 766 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 767 "usbvc_v4l2_set_format: type =%x, i =%d", type, i); 768 769 if ((type == VS_FORMAT_MJPEG) || 770 (type == VS_FORMAT_UNCOMPRESSED)) { 771 if (format->fmt.pix.pixelformat == 772 fmtgrp->v4l2_pixelformat) { 773 774 break; 775 } 776 } 777 } 778 779 if (i >= strm_if->fmtgrp_cnt) { 780 mutex_exit(&usbvcp->usbvc_mutex); 781 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 782 "usbvc_v4l2_set_format: can't find a proper format, " 783 "pixelformat=%x", format->fmt.pix.pixelformat); 784 785 return (USB_FAILURE); 786 } 787 788 fmtgrp = &strm_if->format_group[i]; 789 790 frame = usbvc_match_image_size(format->fmt.pix.width, 791 format->fmt.pix.height, fmtgrp); 792 793 if (frame == NULL) { 794 mutex_exit(&usbvcp->usbvc_mutex); 795 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 796 "usbvc_v4l2_set_format: can't find a proper frame, rw=%d, " 797 "rh=%d", format->fmt.pix.width, format->fmt.pix.height); 798 799 return (USB_FAILURE); 800 } 801 802 /* frame interval */ 803 LE_TO_UINT32(frame->descr->dwDefaultFrameInterval, 0, interval); 804 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 805 "usbvc_v4l2_set_format: Default Frame Interval=%x", interval); 806 807 /* 808 * Begin negotiate formats. 809 */ 810 bzero((void *)&ctrl, sizeof (usbvc_vs_probe_commit_t)); 811 812 /* dwFrameInterval is fixed */ 813 ctrl.bmHint[0] = 1; 814 815 ctrl.bFormatIndex = fmtgrp->format->bFormatIndex; 816 ctrl.bFrameIndex = frame->descr->bFrameIndex; 817 UINT32_TO_LE(interval, 0, ctrl.dwFrameInterval); 818 819 mutex_exit(&usbvcp->usbvc_mutex); 820 821 /* Probe, just a test before the real try */ 822 if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl, VS_PROBE_CONTROL) 823 != USB_SUCCESS) { 824 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 825 "usbvc_v4l2_set_format: set probe failed"); 826 827 return (USB_FAILURE); 828 } 829 830 /* Get max values */ 831 if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_max, GET_MAX) != 832 USB_SUCCESS) { 833 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 834 "usbvc_v4l2_set_format: get probe MAX failed"); 835 836 return (USB_FAILURE); 837 } 838 839 /* Use the best quality first */ 840 bcopy(&ctrl_max.wCompQuality, &ctrl.wCompQuality, 2); 841 842 /* 843 * By now, we've get some parametres of ctrl req, next try to set ctrl. 844 */ 845 for (i = 0; i < 2; i++) { 846 847 /* Probe */ 848 if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl, 849 VS_PROBE_CONTROL) != USB_SUCCESS) { 850 851 return (USB_FAILURE); 852 } 853 854 /* Get current value after probe */ 855 if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_curr, GET_CUR) 856 != USB_SUCCESS) { 857 858 return (USB_FAILURE); 859 } 860 LE_TO_UINT32(ctrl_curr.dwMaxPayloadTransferSize, 0, bandwidth); 861 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 862 "usbvc_v4l2_set_format: bandwidth=%x", bandwidth); 863 864 /* 865 * If the bandwidth does not exceed the max value of all the 866 * alternatives in this interface, we done. 867 */ 868 if (bandwidth <= strm_if->max_isoc_payload) { 869 870 break; 871 } 872 if (i >= 1) { 873 874 return (USB_FAILURE); 875 } 876 877 /* Get minimum values since the bandwidth is not enough */ 878 if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_min, GET_MIN) != 879 USB_SUCCESS) { 880 USB_DPRINTF_L2(PRINT_MASK_IOCTL, 881 usbvcp->usbvc_log_handle, 882 "usbvc_v4l2_set_format: get probe MIN failed"); 883 884 return (USB_FAILURE); 885 } 886 887 /* To keep simple, just use some minimum values to try again */ 888 bcopy(&ctrl_min.wKeyFrameRate, &ctrl_curr.wKeyFrameRate, 2); 889 bcopy(&ctrl_min.wPFrameRate, &ctrl_curr.wPFrameRate, 2); 890 bcopy(&ctrl_min.wCompWindowSize, &ctrl_curr.wCompWindowSize, 2); 891 bcopy(&ctrl_max.wCompQuality, &ctrl_curr.wCompQuality, 2); 892 893 bcopy(&ctrl_curr, &ctrl, 894 sizeof (usbvc_vs_probe_commit_t)); 895 } 896 897 bcopy(&ctrl_curr, &ctrl, sizeof (usbvc_vs_probe_commit_t)); 898 899 /* commit the values we negotiated above */ 900 if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl, 901 VS_COMMIT_CONTROL) != USB_SUCCESS) { 902 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 903 "usbvc_v4l2_set_format: set probe failed, i=%d", i); 904 905 return (USB_FAILURE); 906 } 907 mutex_enter(&usbvcp->usbvc_mutex); 908 909 /* 910 * It's good to check index here before use it. bFormatIndex is based 911 * on 1, and format_group[i] is based on 0, so minus 1 912 */ 913 i = ctrl.bFormatIndex - 1; 914 if (i < strm_if->fmtgrp_cnt) { 915 strm_if->cur_format_group = &strm_if->format_group[i]; 916 } else { 917 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 918 "usbvc_v4l2_set_format: format index out of range"); 919 mutex_exit(&usbvcp->usbvc_mutex); 920 921 return (USB_FAILURE); 922 } 923 924 /* bFrameIndex is based on 1, and frames[i] is based on 0, so minus 1 */ 925 i = ctrl.bFrameIndex -1; 926 if (i < strm_if->cur_format_group->frame_cnt) { 927 strm_if->cur_format_group->cur_frame = 928 &strm_if->cur_format_group->frames[i]; 929 } else { 930 mutex_exit(&usbvcp->usbvc_mutex); 931 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 932 "usbvc_v4l2_set_format: frame index out of range"); 933 934 return (USB_FAILURE); 935 } 936 937 /* 938 * by now, the video format is set successfully. record the current 939 * setting to strm_if->ctrl_pc 940 */ 941 bcopy(&ctrl_curr, &strm_if->ctrl_pc, sizeof (usbvc_vs_probe_commit_t)); 942 943 format->fmt.pix.colorspace = fmtgrp->v4l2_color; 944 format->fmt.pix.field = V4L2_FIELD_NONE; 945 format->fmt.pix.priv = 0; 946 947 LE_TO_UINT16(frame->descr->wWidth, 0, w); 948 LE_TO_UINT16(frame->descr->wHeight, 0, h); 949 format->fmt.pix.width = w; 950 format->fmt.pix.height = h; 951 format->fmt.pix.bytesperline = fmtgrp->v4l2_bpp * w; 952 LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0, 953 format->fmt.pix.sizeimage); 954 955 mutex_exit(&usbvcp->usbvc_mutex); 956 957 USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 958 "usbvc_v4l2_set_format: dwMaxVideoFrameSize=%x, w=%x, h=%x", 959 format->fmt.pix.sizeimage, w, h); 960 961 return (USB_SUCCESS); 962 } 963 964 965 /* Implement ioctl VIDIOC_G_FMT, get the current video format */ 966 static int 967 usbvc_v4l2_get_format(usbvc_state_t *usbvcp, struct v4l2_format *format) 968 { 969 usbvc_stream_if_t *strm_if; 970 usbvc_format_group_t *fmtgrp; 971 uint16_t w, h; 972 973 if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { 974 975 return (EINVAL); 976 } 977 mutex_enter(&usbvcp->usbvc_mutex); 978 979 /* get the current interface. */ 980 strm_if = usbvcp->usbvc_curr_strm; 981 fmtgrp = strm_if->cur_format_group; 982 983 if (!fmtgrp || !fmtgrp->cur_frame) { 984 mutex_exit(&usbvcp->usbvc_mutex); 985 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 986 "usbvc_v4l2_get_format: fail, no current format or frame," 987 "fmtgrp=%p", fmtgrp); 988 989 return (EINVAL); 990 } 991 format->fmt.pix.colorspace = fmtgrp->v4l2_color; 992 format->fmt.pix.priv = 0; 993 format->fmt.pix.pixelformat = fmtgrp->v4l2_pixelformat; 994 995 LE_TO_UINT16(fmtgrp->cur_frame->descr->wWidth, 0, w); 996 LE_TO_UINT16(fmtgrp->cur_frame->descr->wHeight, 0, h); 997 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 998 "v4l2 ioctl get format "); 999 format->fmt.pix.width = w; 1000 format->fmt.pix.height = h; 1001 1002 format->fmt.pix.field = V4L2_FIELD_NONE; 1003 format->fmt.pix.bytesperline = fmtgrp->v4l2_bpp * w; 1004 1005 LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0, 1006 format->fmt.pix.sizeimage); 1007 1008 mutex_exit(&usbvcp->usbvc_mutex); 1009 1010 return (0); 1011 } 1012 1013 1014 /* 1015 * Convert color space descriptor's bColorPrimaries to the colorspace element 1016 * in struct v4l2_pix_format 1017 */ 1018 uint8_t 1019 usbvc_v4l2_colorspace(uint8_t color_prim) 1020 { 1021 1022 if (color_prim < NELEM(color_primaries)) { 1023 1024 return (color_primaries[color_prim]); 1025 } 1026 1027 return (0); 1028 } 1029 1030 1031 /* Implement ioctl VIDIOC_QUERYBUF, get the buf status */ 1032 static void 1033 usbvc_v4l2_query_buf(usbvc_state_t *usbvcp, usbvc_buf_t *usbvc_buf, 1034 struct v4l2_buffer *v4l2_buf) 1035 { 1036 ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 1037 1038 bcopy(&(usbvc_buf->v4l2_buf), v4l2_buf, sizeof (struct v4l2_buffer)); 1039 USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1040 "usbvc_v4l2_query_buf: uv_buf_len=%d, len=%d", 1041 usbvc_buf->v4l2_buf.length, v4l2_buf->length); 1042 1043 if (usbvc_buf->status >= USBVC_BUF_MAPPED) { 1044 v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED; 1045 } 1046 1047 switch (usbvc_buf->status) { 1048 case USBVC_BUF_DONE: 1049 case USBVC_BUF_ERR: 1050 v4l2_buf->flags |= V4L2_BUF_FLAG_DONE; 1051 1052 break; 1053 case USBVC_BUF_EMPTY: 1054 v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; 1055 1056 break; 1057 case USBVC_BUF_INIT: 1058 default: 1059 1060 break; 1061 } 1062 } 1063 1064 1065 /* Implement ioctl VIDIOC_QBUF, queue a empty buf to the free list */ 1066 static int 1067 usbvc_v4l2_enqueue_buf(usbvc_state_t *usbvcp, usbvc_buf_t *usbvc_buf, 1068 struct v4l2_buffer *buf) 1069 { 1070 usbvc_buf_t *donebuf; 1071 boolean_t queued = B_FALSE; 1072 usbvc_buf_grp_t *bufgrp; 1073 1074 ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 1075 1076 bufgrp = &usbvcp->usbvc_curr_strm->buf_map; 1077 1078 if (usbvc_buf == bufgrp->buf_filling) { 1079 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1080 "enqueue_buffer(%d) , want to queue buf_filling, " 1081 "just return success", buf->index); 1082 1083 return (0); 1084 } 1085 1086 if (!list_is_empty(&bufgrp->uv_buf_done)) { 1087 donebuf = (usbvc_buf_t *)list_head(&bufgrp->uv_buf_done); 1088 while (donebuf) { 1089 1090 if (donebuf == &(bufgrp->buf_head[buf->index])) { 1091 queued = B_TRUE; 1092 1093 break; 1094 } 1095 donebuf = (usbvc_buf_t *)list_next(&bufgrp->uv_buf_done, 1096 donebuf); 1097 } 1098 } 1099 if (queued) { 1100 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1101 "enqueue_buffer(%d), still in done list, don't insert to" 1102 " free list", buf->index); 1103 1104 return (0); 1105 } 1106 1107 if (usbvc_buf->status == USBVC_BUF_EMPTY) { 1108 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1109 "enqueue buffer(%d), already queued.", buf->index); 1110 1111 return (0); 1112 1113 } 1114 if (usbvc_buf->status < USBVC_BUF_MAPPED) { 1115 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1116 "enqueue buffer(%d), state error, not mapped.", buf->index); 1117 1118 return (EINVAL); 1119 } 1120 1121 /* 1122 * The buf is put to the buf free list when allocated, so, if the buf 1123 * is the first time to enqueue, just change the state to empty is 1124 * enough. 1125 */ 1126 if (usbvc_buf->status == USBVC_BUF_MAPPED) { 1127 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1128 "queue_buffer(%d), 1st time queue this buf", buf->index); 1129 1130 usbvc_buf->status = USBVC_BUF_EMPTY; 1131 1132 } else { 1133 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1134 "enqueue_buffer(%d) , USBVC_BUF_EMPTY", buf->index); 1135 1136 usbvc_buf->status = USBVC_BUF_EMPTY; 1137 usbvc_buf->v4l2_buf.bytesused = 0; 1138 list_insert_tail(&bufgrp->uv_buf_free, usbvc_buf); 1139 } 1140 buf->flags &= ~V4L2_BUF_FLAG_DONE; 1141 buf->flags |= V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED; 1142 1143 return (0); 1144 } 1145 1146 1147 /* Implement ioctl VIDIOC_DQBUF, pick a buf from done list */ 1148 static int 1149 usbvc_v4l2_dequeue_buffer(usbvc_state_t *usbvcp, struct v4l2_buffer *buf, 1150 int mode) 1151 { 1152 usbvc_buf_t *buf_done; 1153 1154 ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 1155 USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1156 "usbvc_v4l2_dequeue_buffer: idx=%x", buf->index); 1157 1158 /* v4l2 spec: app just set type and memory field */ 1159 if ((buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || 1160 (buf->memory != V4L2_MEMORY_MMAP)) { 1161 1162 return (EINVAL); 1163 } 1164 if ((mode & (O_NDELAY|O_NONBLOCK)) && 1165 (list_is_empty(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done))) { 1166 1167 /* non-blocking */ 1168 return (EAGAIN); 1169 } 1170 1171 /* no available buffers, block here */ 1172 while (list_is_empty(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done)) { 1173 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1174 "usbvc_v4l2_dequeue_buffer: wait for done buf"); 1175 if (cv_wait_sig(&usbvcp->usbvc_mapio_cv, &usbvcp->usbvc_mutex) 1176 <= 0) { 1177 1178 /* no done buf and is signaled */ 1179 return (EINTR); 1180 } 1181 if (usbvcp->usbvc_dev_state != USB_DEV_ONLINE) { 1182 1183 /* Device is disconnected. */ 1184 return (EINTR); 1185 } 1186 } 1187 1188 buf_done = list_head(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done); 1189 1190 list_remove(&usbvcp->usbvc_curr_strm->buf_map.uv_buf_done, buf_done); 1191 1192 /* 1193 * just copy the v4l2_buf structure because app need only the index 1194 * value to locate the mapped memory 1195 */ 1196 bcopy(&buf_done->v4l2_buf, buf, sizeof (struct v4l2_buffer)); 1197 buf->flags |= V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_MAPPED; 1198 buf->bytesused = buf_done->filled; 1199 USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1200 "usbvc_v4l2_dequeue_buffer: bytesused=%d, idx=%x, status=%d", 1201 buf->bytesused, buf->index, buf_done->status); 1202 1203 return (0); 1204 } 1205 1206 1207 /* 1208 * Check if a ctrl_id is supported by the device, if yes, find the 1209 * corresponding processing unit and fill usbvc_v4l2_ctrl_t 1210 */ 1211 static int 1212 usbvc_v4l2_match_ctrl(usbvc_state_t *usbvcp, usbvc_v4l2_ctrl_t *ctrl, 1213 uint32_t ctrl_id) 1214 { 1215 uint8_t idx; 1216 usbvc_units_t *unit; 1217 uchar_t bit; 1218 1219 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1220 "usbvc_v4l2_match_ctrl: ctrl_id=%x", ctrl_id); 1221 if (ctrl_id >= V4L2_CID_PRIVATE_BASE) { 1222 1223 return (USB_FAILURE); 1224 } 1225 if (ctrl_id < V4L2_CID_BASE) { 1226 1227 return (USB_FAILURE); 1228 } 1229 1230 /* get the idx of ctrl array usbvc_v4l2_ctrl */ 1231 idx = ctrl_id - V4L2_CID_BASE; 1232 if (ctrl_id == V4L2_CID_GAMMA) { 1233 1234 /* The 4th one is for Gamma ctrl */ 1235 bit = usbvc_v4l2_ctrls[4].bit; 1236 } else if ((ctrl_id >= V4L2_CID_BRIGHTNESS) && 1237 (ctrl_id <= V4L2_CID_HUE)) { 1238 1239 /* The idxth one is for this ctrl */ 1240 bit = usbvc_v4l2_ctrls[idx].bit; 1241 } else { 1242 1243 return (USB_FAILURE); 1244 } 1245 unit = (usbvc_units_t *)list_head(&usbvcp->usbvc_unit_list); 1246 1247 /* 1248 * Check if there is a processing unit supportting this ctrl. 1249 * Todo: check if the ctrl and the unit is really for the right 1250 * stream interface in case of multi stream interfaces. 1251 */ 1252 while (unit != NULL) { 1253 1254 if (unit->descr->bDescriptorSubType == VC_PROCESSING_UNIT) { 1255 1256 if (bit >= 1257 (unit->descr->unit.processing.bControlSize * 8)) { 1258 1259 /* 1260 * If this unit's bmControls size is smaller 1261 * than bit, then next 1262 */ 1263 unit = (usbvc_units_t *) 1264 list_next(&usbvcp->usbvc_unit_list, unit); 1265 1266 continue; 1267 } else { 1268 1269 /* 1270 * The first two bytes of bmControls are 1271 * for ctrls 1272 */ 1273 if ((bit < 8) && 1274 unit->bmControls[0] & (0x1 << bit)) { 1275 1276 break; 1277 } 1278 if ((bit >= 8 && bit < 16) && 1279 unit->bmControls[1] & (0x1 << bit)) { 1280 1281 break; 1282 } 1283 } 1284 } 1285 unit = (usbvc_units_t *)list_next(&usbvcp->usbvc_unit_list, 1286 unit); 1287 } 1288 if (unit == NULL) { 1289 1290 return (USB_FAILURE); 1291 } 1292 ctrl->entity_id = unit->descr->bUnitID; 1293 if (ctrl_id == V4L2_CID_GAMMA) { 1294 ctrl->ctrl_map = &usbvc_v4l2_ctrls[4]; 1295 } else { 1296 ctrl->ctrl_map = &usbvc_v4l2_ctrls[idx]; 1297 } 1298 1299 return (USB_SUCCESS); 1300 } 1301 1302 1303 /* 1304 * Implement ioctl VIDIOC_QUERYCTRL, query the ctrl types that the device 1305 * supports 1306 */ 1307 static int 1308 usbvc_v4l2_query_ctrl(usbvc_state_t *usbvcp, struct v4l2_queryctrl *queryctrl) 1309 { 1310 usbvc_v4l2_ctrl_t ctrl; 1311 mblk_t *data; 1312 char req[16]; 1313 1314 if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, queryctrl->id) != 1315 USB_SUCCESS) { 1316 1317 return (USB_FAILURE); 1318 } 1319 if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) { 1320 1321 return (USB_FAILURE); 1322 } 1323 1324 if (usbvc_vc_get_ctrl(usbvcp, GET_MIN, ctrl.entity_id, 1325 ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != 1326 USB_SUCCESS) { 1327 (void) strncpy(&req[0], "GET_MIN", sizeof (req)); 1328 1329 goto fail; 1330 } 1331 LE_TO_UINT16(data->b_rptr, 0, queryctrl->minimum); 1332 if (usbvc_vc_get_ctrl(usbvcp, GET_MAX, ctrl.entity_id, 1333 ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) { 1334 (void) strncpy(&req[0], "GET_MAX", sizeof (req)); 1335 1336 goto fail; 1337 } 1338 LE_TO_UINT16(data->b_rptr, 0, queryctrl->maximum); 1339 1340 if (usbvc_vc_get_ctrl(usbvcp, GET_RES, ctrl.entity_id, 1341 ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) { 1342 (void) strncpy(&req[0], "GET_RES", sizeof (req)); 1343 1344 goto fail; 1345 } 1346 LE_TO_UINT16(data->b_rptr, 0, queryctrl->step); 1347 1348 if (usbvc_vc_get_ctrl(usbvcp, GET_DEF, ctrl.entity_id, 1349 ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) { 1350 (void) strncpy(&req[0], "GET_DEF", sizeof (req)); 1351 1352 goto fail; 1353 } 1354 LE_TO_UINT16(data->b_rptr, 0, queryctrl->default_value); 1355 1356 (void) strncpy(queryctrl->name, ctrl.ctrl_map->name, 1357 sizeof (queryctrl->name)); 1358 queryctrl->type = ctrl.ctrl_map->type; 1359 queryctrl->flags = 0; 1360 1361 if (data) { 1362 freemsg(data); 1363 } 1364 1365 return (USB_SUCCESS); 1366 1367 fail: 1368 if (data) { 1369 freemsg(data); 1370 } 1371 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1372 "usbvc_v4l2_query_ctrl: fail when %s", req); 1373 1374 return (USB_FAILURE); 1375 1376 } 1377 1378 1379 /* Implement ioctl VIDIOC_G_CTRL, get current ctrl */ 1380 static int 1381 usbvc_v4l2_get_ctrl(usbvc_state_t *usbvcp, struct v4l2_control *v4l2_ctrl) 1382 { 1383 usbvc_v4l2_ctrl_t ctrl; 1384 mblk_t *data; 1385 1386 if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, v4l2_ctrl->id) != 1387 USB_SUCCESS) { 1388 1389 return (USB_FAILURE); 1390 } 1391 if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) { 1392 1393 return (USB_FAILURE); 1394 } 1395 1396 if (usbvc_vc_get_ctrl(usbvcp, GET_CUR, ctrl.entity_id, 1397 ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != USB_SUCCESS) { 1398 if (data) { 1399 freemsg(data); 1400 } 1401 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1402 "usbvc_v4l2_get_ctrl: fail"); 1403 1404 return (USB_FAILURE); 1405 } 1406 LE_TO_UINT16(data->b_rptr, 0, v4l2_ctrl->value); 1407 1408 if (data) { 1409 freemsg(data); 1410 } 1411 1412 return (USB_SUCCESS); 1413 } 1414 1415 1416 /* Implement ioctl VIDIOC_S_CTRL */ 1417 static int 1418 usbvc_v4l2_set_ctrl(usbvc_state_t *usbvcp, struct v4l2_control *v4l2_ctrl) 1419 { 1420 usbvc_v4l2_ctrl_t ctrl; 1421 mblk_t *data; 1422 1423 if (usbvc_v4l2_match_ctrl(usbvcp, &ctrl, v4l2_ctrl->id) != 1424 USB_SUCCESS) { 1425 1426 return (USB_FAILURE); 1427 } 1428 if ((data = allocb(ctrl.ctrl_map->len, BPRI_LO)) == NULL) { 1429 1430 return (USB_FAILURE); 1431 } 1432 1433 UINT16_TO_LE(v4l2_ctrl->value, 0, data->b_wptr); 1434 data->b_wptr += 2; 1435 if (usbvc_vc_set_ctrl(usbvcp, SET_CUR, ctrl.entity_id, 1436 ctrl.ctrl_map->selector, ctrl.ctrl_map->len, data) != 1437 USB_SUCCESS) { 1438 if (data) { 1439 freemsg(data); 1440 } 1441 USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 1442 "usbvc_v4l2_set_ctrl: fail"); 1443 1444 return (USB_FAILURE); 1445 } 1446 if (data) { 1447 freemsg(data); 1448 } 1449 1450 return (USB_SUCCESS); 1451 } 1452