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