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 (usbvc(7D)) 30*c77a61a7Syz * 31*c77a61a7Syz * 1. Overview 32*c77a61a7Syz * ------------ 33*c77a61a7Syz * 34*c77a61a7Syz * This driver supports USB video class devices that used to capture video, 35*c77a61a7Syz * e.g., some webcams. It is developed according to "USB Device Class 36*c77a61a7Syz * Definition for Video Devices" spec. This spec defines detail info needed by 37*c77a61a7Syz * designing a USB video device. It is available at: 38*c77a61a7Syz * http://www.usb.org/developers/devclass_docs 39*c77a61a7Syz * 40*c77a61a7Syz * This driver implements: 41*c77a61a7Syz * 42*c77a61a7Syz * - V4L2 interfaces for applications to communicate with video devices. 43*c77a61a7Syz * V4L2 is an API that is widely used by video applications, like Ekiga, 44*c77a61a7Syz * luvcview, etc. The API spec is at: 45*c77a61a7Syz * http://www.thedirks.org/v4l2/ 46*c77a61a7Syz * This driver is according to V4L2 spec version 0.20 47*c77a61a7Syz * 48*c77a61a7Syz * - Video capture function. (Video output is not supported by now.) 49*c77a61a7Syz * 50*c77a61a7Syz * - Isochronous transfer for video data. (Bulk transfer is not supported.) 51*c77a61a7Syz * 52*c77a61a7Syz * - read & mmap I/O methods for userland video applications to get video 53*c77a61a7Syz * data. Userland video applications can use read() system call directly, 54*c77a61a7Syz * it is the simplest way but not the most efficient way. Applications can 55*c77a61a7Syz * also use mmap() system call to map several bufs (they are linked as a 56*c77a61a7Syz * buf list), and then use some specific ioctls to start/stop isoc polling, 57*c77a61a7Syz * to queue/dequeue bufs. 58*c77a61a7Syz * 59*c77a61a7Syz * 2. Source and header files 60*c77a61a7Syz * --------------------------- 61*c77a61a7Syz * 62*c77a61a7Syz * There are two source files and three header files for this driver: 63*c77a61a7Syz * 64*c77a61a7Syz * - usbvc.c Main source file, implements usb video class spec. 65*c77a61a7Syz * 66*c77a61a7Syz * - usbvc_v4l2.c V4L2 interface specific code. 67*c77a61a7Syz * 68*c77a61a7Syz * - usbvc_var.h Main header file, includes soft state structure. 69*c77a61a7Syz * 70*c77a61a7Syz * - usbvc.h The descriptors in usb video class spec. 71*c77a61a7Syz * 72*c77a61a7Syz * - videodev2.h This header file is included in V4L2 spec. It defines 73*c77a61a7Syz * ioctls and data structures that used as an interface between video 74*c77a61a7Syz * applications and video drivers. This is the only header file that 75*c77a61a7Syz * usbvc driver should export to userland application. 76*c77a61a7Syz * 77*c77a61a7Syz * 3. USB video class devices overview 78*c77a61a7Syz * ----------------------------------- 79*c77a61a7Syz * According to UVC spec, there must be one control interface in a UVC device. 80*c77a61a7Syz * Control interface is used to receive control commands from user, all the 81*c77a61a7Syz * commands are sent through default ctrl pipe. usbvc driver implements V4L2 82*c77a61a7Syz * API, so ioctls are implemented to relay user commands to UVC device. 83*c77a61a7Syz * 84*c77a61a7Syz * There can be no or multiple stream interfaces in a UVC device. Stream 85*c77a61a7Syz * interfaces are used to do video data I/O. In practice, if no stream 86*c77a61a7Syz * interface, the video device can do nothing since it has no data I/O. 87*c77a61a7Syz * 88*c77a61a7Syz * usbvc driver parses descriptors of control interface and stream interfaces. 89*c77a61a7Syz * The descriptors tell the function layout and the capability of the device. 90*c77a61a7Syz * During attach, usbvc driver set up some key data structures according to 91*c77a61a7Syz * the descriptors. 92*c77a61a7Syz * 93*c77a61a7Syz * 4. I/O methods 94*c77a61a7Syz * --------------- 95*c77a61a7Syz * 96*c77a61a7Syz * Userland applications use ioctls to set/get video formats of the device, 97*c77a61a7Syz * and control brightness, contrast, image size, etc. 98*c77a61a7Syz * 99*c77a61a7Syz * Besides implementing standard read I/O method to get video data from 100*c77a61a7Syz * the device, usbvc driver also implements some specific ioctls to implement 101*c77a61a7Syz * mmap I/O method. 102*c77a61a7Syz * 103*c77a61a7Syz * A view from userland application: ioctl and mmap flow chart: 104*c77a61a7Syz * 105*c77a61a7Syz * REQBUFS -> QUERYBUF -> mmap() -> 106*c77a61a7Syz * 107*c77a61a7Syz * -> QBUF -> STREAMON -> DQBUF -> process image -> QBUF 108*c77a61a7Syz * ^ | 109*c77a61a7Syz * | | 110*c77a61a7Syz * | v 111*c77a61a7Syz * |---<-------------------- 112*c77a61a7Syz * 113*c77a61a7Syz * The above queue and dequeue buf operations can be stopped by issuing a 114*c77a61a7Syz * STREAMOFF ioctl. 115*c77a61a7Syz * 116*c77a61a7Syz * 5. Device states 117*c77a61a7Syz * ---------------- 118*c77a61a7Syz * 119*c77a61a7Syz * The device has four states (refer to usbai.h): 120*c77a61a7Syz * 121*c77a61a7Syz * - USB_DEV_ONLINE: In action or ready for action. 122*c77a61a7Syz * 123*c77a61a7Syz * - USB_DEV_DISCONNECTED: Hotplug removed, or device not present/correct 124*c77a61a7Syz * on resume (CPR). 125*c77a61a7Syz * 126*c77a61a7Syz * - USB_DEV_SUSPENDED: Device has been suspended along with the system. 127*c77a61a7Syz * 128*c77a61a7Syz * - USB_DEV_PWRED_DOWN: Device has been powered down. (Note that this 129*c77a61a7Syz * driver supports only two power states, powered down and 130*c77a61a7Syz * full power.) 131*c77a61a7Syz * 132*c77a61a7Syz * 6. Serialize 133*c77a61a7Syz * ------------- 134*c77a61a7Syz * In order to avoid race conditions between driver entry points, access to 135*c77a61a7Syz * the device is serialized. All the ioctls, and read, open/close are 136*c77a61a7Syz * serialized. The functions usbvc_serialize/release_access are implemented 137*c77a61a7Syz * for this purpose. 138*c77a61a7Syz * 139*c77a61a7Syz * 7. PM & CPR 140*c77a61a7Syz * ------------ 141*c77a61a7Syz * PM & CPR are supported. pm_busy_component and pm_idle_component mark 142*c77a61a7Syz * the device as busy or idle to the system. 143*c77a61a7Syz */ 144*c77a61a7Syz 145*c77a61a7Syz #if defined(lint) && !defined(DEBUG) 146*c77a61a7Syz #define DEBUG 147*c77a61a7Syz #endif 148*c77a61a7Syz 149*c77a61a7Syz #define USBDRV_MAJOR_VER 2 150*c77a61a7Syz #define USBDRV_MINOR_VER 0 151*c77a61a7Syz 152*c77a61a7Syz #include <sys/usb/usba.h> 153*c77a61a7Syz #include <sys/fcntl.h> 154*c77a61a7Syz #include <sys/cmn_err.h> 155*c77a61a7Syz #include <sys/usb/clients/video/usbvc/usbvc_var.h> 156*c77a61a7Syz #include <sys/videodev2.h> /* V4L2 API header file */ 157*c77a61a7Syz 158*c77a61a7Syz /* Descriptors according to USB video class spec */ 159*c77a61a7Syz #include <sys/usb/clients/video/usbvc/usbvc.h> 160*c77a61a7Syz 161*c77a61a7Syz static uint_t usbvc_errmask = (uint_t)PRINT_MASK_ALL; 162*c77a61a7Syz static uint_t usbvc_errlevel = 4; 163*c77a61a7Syz static uint_t usbvc_instance_debug = (uint_t)-1; 164*c77a61a7Syz 165*c77a61a7Syz static char *name = "usbvc"; /* Driver name, used all over. */ 166*c77a61a7Syz 167*c77a61a7Syz /* 168*c77a61a7Syz * Function Prototypes 169*c77a61a7Syz */ 170*c77a61a7Syz 171*c77a61a7Syz /* Entries */ 172*c77a61a7Syz static int usbvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 173*c77a61a7Syz static int usbvc_attach(dev_info_t *, ddi_attach_cmd_t); 174*c77a61a7Syz static int usbvc_detach(dev_info_t *, ddi_detach_cmd_t); 175*c77a61a7Syz static void usbvc_cleanup(dev_info_t *, usbvc_state_t *); 176*c77a61a7Syz static int usbvc_open(dev_t *, int, int, cred_t *); 177*c77a61a7Syz static int usbvc_close(dev_t, int, int, cred_t *); 178*c77a61a7Syz static int usbvc_read(dev_t, struct uio *uip_p, cred_t *); 179*c77a61a7Syz static int usbvc_strategy(struct buf *); 180*c77a61a7Syz static void usbvc_minphys(struct buf *); 181*c77a61a7Syz static int usbvc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 182*c77a61a7Syz static int usbvc_devmap(dev_t, devmap_cookie_t, offset_t, 183*c77a61a7Syz size_t, size_t *, uint_t); 184*c77a61a7Syz 185*c77a61a7Syz /* pm and cpr */ 186*c77a61a7Syz static int usbvc_power(dev_info_t *, int, int); 187*c77a61a7Syz static void usbvc_init_power_mgmt(usbvc_state_t *); 188*c77a61a7Syz static void usbvc_destroy_power_mgmt(usbvc_state_t *); 189*c77a61a7Syz static void usbvc_pm_busy_component(usbvc_state_t *); 190*c77a61a7Syz static void usbvc_pm_idle_component(usbvc_state_t *); 191*c77a61a7Syz static int usbvc_pwrlvl0(usbvc_state_t *); 192*c77a61a7Syz static int usbvc_pwrlvl1(usbvc_state_t *); 193*c77a61a7Syz static int usbvc_pwrlvl2(usbvc_state_t *); 194*c77a61a7Syz static int usbvc_pwrlvl3(usbvc_state_t *); 195*c77a61a7Syz static void usbvc_cpr_suspend(dev_info_t *); 196*c77a61a7Syz static void usbvc_cpr_resume(dev_info_t *); 197*c77a61a7Syz static void usbvc_restore_device_state(dev_info_t *, usbvc_state_t *); 198*c77a61a7Syz 199*c77a61a7Syz /* Events */ 200*c77a61a7Syz static int usbvc_disconnect_event_cb(dev_info_t *); 201*c77a61a7Syz static int usbvc_reconnect_event_cb(dev_info_t *); 202*c77a61a7Syz 203*c77a61a7Syz /* Sync objs and lists */ 204*c77a61a7Syz static void usbvc_init_sync_objs(usbvc_state_t *); 205*c77a61a7Syz static void usbvc_fini_sync_objs(usbvc_state_t *); 206*c77a61a7Syz static void usbvc_init_lists(usbvc_state_t *); 207*c77a61a7Syz static void usbvc_fini_lists(usbvc_state_t *); 208*c77a61a7Syz static void usbvc_free_ctrl_descr(usbvc_state_t *); 209*c77a61a7Syz static void usbvc_free_stream_descr(usbvc_state_t *); 210*c77a61a7Syz 211*c77a61a7Syz /* Parse descriptors */ 212*c77a61a7Syz static int usbvc_chk_descr_len(uint8_t, uint8_t, uint8_t, 213*c77a61a7Syz usb_cvs_data_t *); 214*c77a61a7Syz static usbvc_stream_if_t *usbvc_parse_stream_if(usbvc_state_t *, int); 215*c77a61a7Syz static int usbvc_parse_ctrl_if(usbvc_state_t *); 216*c77a61a7Syz static int usbvc_parse_stream_ifs(usbvc_state_t *); 217*c77a61a7Syz static void usbvc_parse_color_still(usbvc_state_t *, 218*c77a61a7Syz usbvc_format_group_t *, usb_cvs_data_t *, uint_t, uint_t); 219*c77a61a7Syz static void usbvc_parse_frames(usbvc_state_t *, usbvc_format_group_t *, 220*c77a61a7Syz usb_cvs_data_t *, uint_t, uint_t); 221*c77a61a7Syz static int usbvc_parse_format_group(usbvc_state_t *, 222*c77a61a7Syz usbvc_format_group_t *, usb_cvs_data_t *, uint_t, uint_t); 223*c77a61a7Syz static int usbvc_parse_format_groups(usbvc_state_t *, usbvc_stream_if_t *); 224*c77a61a7Syz static int usbvc_parse_stream_header(usbvc_state_t *, usbvc_stream_if_t *); 225*c77a61a7Syz 226*c77a61a7Syz /* read I/O functions */ 227*c77a61a7Syz static int usbvc_alloc_read_bufs(usbvc_state_t *, usbvc_stream_if_t *); 228*c77a61a7Syz static int usbvc_read_buf(usbvc_state_t *, struct buf *); 229*c77a61a7Syz static void usbvc_free_read_buf(usbvc_buf_t *); 230*c77a61a7Syz static void usbvc_free_read_bufs(usbvc_state_t *, usbvc_stream_if_t *); 231*c77a61a7Syz static void usbvc_close_isoc_pipe(usbvc_state_t *, usbvc_stream_if_t *); 232*c77a61a7Syz 233*c77a61a7Syz /* callbacks */ 234*c77a61a7Syz static void usbvc_isoc_cb(usb_pipe_handle_t, usb_isoc_req_t *); 235*c77a61a7Syz static void usbvc_isoc_exc_cb(usb_pipe_handle_t, usb_isoc_req_t *); 236*c77a61a7Syz 237*c77a61a7Syz /* Others */ 238*c77a61a7Syz static int usbvc_set_alt(usbvc_state_t *, usbvc_stream_if_t *); 239*c77a61a7Syz static int usbvc_decode_stream_header(usbvc_state_t *, usbvc_buf_grp_t *, 240*c77a61a7Syz mblk_t *, int); 241*c77a61a7Syz static int usbvc_serialize_access(usbvc_state_t *, boolean_t); 242*c77a61a7Syz static void usbvc_release_access(usbvc_state_t *); 243*c77a61a7Syz static int usbvc_set_default_stream_fmt(usbvc_state_t *); 244*c77a61a7Syz 245*c77a61a7Syz static usb_event_t usbvc_events = { 246*c77a61a7Syz usbvc_disconnect_event_cb, 247*c77a61a7Syz usbvc_reconnect_event_cb, 248*c77a61a7Syz NULL, NULL 249*c77a61a7Syz }; 250*c77a61a7Syz 251*c77a61a7Syz /* module loading stuff */ 252*c77a61a7Syz struct cb_ops usbvc_cb_ops = { 253*c77a61a7Syz usbvc_open, /* open */ 254*c77a61a7Syz usbvc_close, /* close */ 255*c77a61a7Syz usbvc_strategy, /* strategy */ 256*c77a61a7Syz nulldev, /* print */ 257*c77a61a7Syz nulldev, /* dump */ 258*c77a61a7Syz usbvc_read, /* read */ 259*c77a61a7Syz nodev, /* write */ 260*c77a61a7Syz usbvc_ioctl, /* ioctl */ 261*c77a61a7Syz usbvc_devmap, /* devmap */ 262*c77a61a7Syz nodev, /* mmap */ 263*c77a61a7Syz ddi_devmap_segmap, /* segmap */ 264*c77a61a7Syz nochpoll, /* poll */ 265*c77a61a7Syz ddi_prop_op, /* cb_prop_op */ 266*c77a61a7Syz NULL, /* streamtab */ 267*c77a61a7Syz D_MP | D_DEVMAP 268*c77a61a7Syz }; 269*c77a61a7Syz 270*c77a61a7Syz static struct dev_ops usbvc_ops = { 271*c77a61a7Syz DEVO_REV, /* devo_rev, */ 272*c77a61a7Syz 0, /* refcnt */ 273*c77a61a7Syz usbvc_info, /* info */ 274*c77a61a7Syz nulldev, /* identify */ 275*c77a61a7Syz nulldev, /* probe */ 276*c77a61a7Syz usbvc_attach, /* attach */ 277*c77a61a7Syz usbvc_detach, /* detach */ 278*c77a61a7Syz nodev, /* reset */ 279*c77a61a7Syz &usbvc_cb_ops, /* driver operations */ 280*c77a61a7Syz NULL, /* bus operations */ 281*c77a61a7Syz usbvc_power /* power */ 282*c77a61a7Syz }; 283*c77a61a7Syz 284*c77a61a7Syz static struct modldrv usbvc_modldrv = { 285*c77a61a7Syz &mod_driverops, 286*c77a61a7Syz "USB video class driver %I%", 287*c77a61a7Syz &usbvc_ops 288*c77a61a7Syz }; 289*c77a61a7Syz 290*c77a61a7Syz static struct modlinkage modlinkage = { 291*c77a61a7Syz MODREV_1, 292*c77a61a7Syz &usbvc_modldrv, 293*c77a61a7Syz NULL 294*c77a61a7Syz }; 295*c77a61a7Syz 296*c77a61a7Syz /* Soft state structures */ 297*c77a61a7Syz #define USBVC_INITIAL_SOFT_SPACE 1 298*c77a61a7Syz static void *usbvc_statep; 299*c77a61a7Syz 300*c77a61a7Syz 301*c77a61a7Syz /* 302*c77a61a7Syz * Module-wide initialization routine. 303*c77a61a7Syz */ 304*c77a61a7Syz int 305*c77a61a7Syz _init(void) 306*c77a61a7Syz { 307*c77a61a7Syz int rval; 308*c77a61a7Syz 309*c77a61a7Syz if ((rval = ddi_soft_state_init(&usbvc_statep, 310*c77a61a7Syz sizeof (usbvc_state_t), USBVC_INITIAL_SOFT_SPACE)) != 0) { 311*c77a61a7Syz 312*c77a61a7Syz return (rval); 313*c77a61a7Syz } 314*c77a61a7Syz 315*c77a61a7Syz if ((rval = mod_install(&modlinkage)) != 0) { 316*c77a61a7Syz ddi_soft_state_fini(&usbvc_statep); 317*c77a61a7Syz } 318*c77a61a7Syz 319*c77a61a7Syz return (rval); 320*c77a61a7Syz } 321*c77a61a7Syz 322*c77a61a7Syz 323*c77a61a7Syz /* 324*c77a61a7Syz * Module-wide tear-down routine. 325*c77a61a7Syz */ 326*c77a61a7Syz int 327*c77a61a7Syz _fini(void) 328*c77a61a7Syz { 329*c77a61a7Syz int rval; 330*c77a61a7Syz 331*c77a61a7Syz if ((rval = mod_remove(&modlinkage)) != 0) { 332*c77a61a7Syz 333*c77a61a7Syz return (rval); 334*c77a61a7Syz } 335*c77a61a7Syz 336*c77a61a7Syz ddi_soft_state_fini(&usbvc_statep); 337*c77a61a7Syz 338*c77a61a7Syz return (rval); 339*c77a61a7Syz } 340*c77a61a7Syz 341*c77a61a7Syz 342*c77a61a7Syz int 343*c77a61a7Syz _info(struct modinfo *modinfop) 344*c77a61a7Syz { 345*c77a61a7Syz return (mod_info(&modlinkage, modinfop)); 346*c77a61a7Syz } 347*c77a61a7Syz 348*c77a61a7Syz 349*c77a61a7Syz /* 350*c77a61a7Syz * usbvc_info: 351*c77a61a7Syz * Get minor number, soft state structure, etc. 352*c77a61a7Syz */ 353*c77a61a7Syz /*ARGSUSED*/ 354*c77a61a7Syz static int 355*c77a61a7Syz usbvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 356*c77a61a7Syz void *arg, void **result) 357*c77a61a7Syz { 358*c77a61a7Syz usbvc_state_t *usbvcp; 359*c77a61a7Syz int error = DDI_FAILURE; 360*c77a61a7Syz 361*c77a61a7Syz switch (infocmd) { 362*c77a61a7Syz case DDI_INFO_DEVT2DEVINFO: 363*c77a61a7Syz if ((usbvcp = ddi_get_soft_state(usbvc_statep, 364*c77a61a7Syz getminor((dev_t)arg))) != NULL) { 365*c77a61a7Syz *result = usbvcp->usbvc_dip; 366*c77a61a7Syz if (*result != NULL) { 367*c77a61a7Syz error = DDI_SUCCESS; 368*c77a61a7Syz } 369*c77a61a7Syz } else { 370*c77a61a7Syz *result = NULL; 371*c77a61a7Syz } 372*c77a61a7Syz break; 373*c77a61a7Syz case DDI_INFO_DEVT2INSTANCE: 374*c77a61a7Syz *result = (void *)(uintptr_t)getminor((dev_t)arg); 375*c77a61a7Syz error = DDI_SUCCESS; 376*c77a61a7Syz break; 377*c77a61a7Syz default: 378*c77a61a7Syz break; 379*c77a61a7Syz } 380*c77a61a7Syz 381*c77a61a7Syz return (error); 382*c77a61a7Syz } 383*c77a61a7Syz 384*c77a61a7Syz 385*c77a61a7Syz /* 386*c77a61a7Syz * Entry functions. 387*c77a61a7Syz */ 388*c77a61a7Syz 389*c77a61a7Syz /* 390*c77a61a7Syz * usbvc_attach: 391*c77a61a7Syz * Attach or resume. 392*c77a61a7Syz * 393*c77a61a7Syz * For attach, initialize state and device, including: 394*c77a61a7Syz * state variables, locks, device node 395*c77a61a7Syz * device registration with system 396*c77a61a7Syz * power management, hotplugging 397*c77a61a7Syz * For resume, restore device and state 398*c77a61a7Syz */ 399*c77a61a7Syz static int 400*c77a61a7Syz usbvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 401*c77a61a7Syz { 402*c77a61a7Syz int instance = ddi_get_instance(dip); 403*c77a61a7Syz usbvc_state_t *usbvcp = NULL; 404*c77a61a7Syz int status; 405*c77a61a7Syz 406*c77a61a7Syz switch (cmd) { 407*c77a61a7Syz case DDI_ATTACH: 408*c77a61a7Syz 409*c77a61a7Syz break; 410*c77a61a7Syz case DDI_RESUME: 411*c77a61a7Syz usbvc_cpr_resume(dip); 412*c77a61a7Syz 413*c77a61a7Syz return (DDI_SUCCESS); 414*c77a61a7Syz default: 415*c77a61a7Syz 416*c77a61a7Syz return (DDI_FAILURE); 417*c77a61a7Syz } 418*c77a61a7Syz 419*c77a61a7Syz if (ddi_soft_state_zalloc(usbvc_statep, instance) == DDI_SUCCESS) { 420*c77a61a7Syz usbvcp = ddi_get_soft_state(usbvc_statep, instance); 421*c77a61a7Syz } 422*c77a61a7Syz if (usbvcp == NULL) { 423*c77a61a7Syz 424*c77a61a7Syz return (DDI_FAILURE); 425*c77a61a7Syz } 426*c77a61a7Syz 427*c77a61a7Syz usbvcp->usbvc_dip = dip; 428*c77a61a7Syz 429*c77a61a7Syz usbvcp->usbvc_log_handle = usb_alloc_log_hdl(dip, 430*c77a61a7Syz "usbvc", &usbvc_errlevel, 431*c77a61a7Syz &usbvc_errmask, &usbvc_instance_debug, 0); 432*c77a61a7Syz 433*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 434*c77a61a7Syz "usbvc_attach: enter"); 435*c77a61a7Syz 436*c77a61a7Syz if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) != 437*c77a61a7Syz USB_SUCCESS) { 438*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 439*c77a61a7Syz "usbvc_attach: usb_client_attach failed, error code:%d", 440*c77a61a7Syz status); 441*c77a61a7Syz 442*c77a61a7Syz goto fail; 443*c77a61a7Syz } 444*c77a61a7Syz 445*c77a61a7Syz if ((status = usb_get_dev_data(dip, &usbvcp->usbvc_reg, 446*c77a61a7Syz USB_PARSE_LVL_ALL, 0)) != USB_SUCCESS) { 447*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 448*c77a61a7Syz "usbvc_attach: usb_get_dev_data failed, error code:%d", 449*c77a61a7Syz status); 450*c77a61a7Syz 451*c77a61a7Syz goto fail; 452*c77a61a7Syz } 453*c77a61a7Syz usbvc_init_sync_objs(usbvcp); 454*c77a61a7Syz 455*c77a61a7Syz /* create minor node */ 456*c77a61a7Syz if ((status = ddi_create_minor_node(dip, name, S_IFCHR, instance, 457*c77a61a7Syz "usb_video", 0)) != DDI_SUCCESS) { 458*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 459*c77a61a7Syz "usbvc_attach: Error creating minor node, error code:%d", 460*c77a61a7Syz status); 461*c77a61a7Syz 462*c77a61a7Syz goto fail; 463*c77a61a7Syz } 464*c77a61a7Syz 465*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 466*c77a61a7Syz usbvc_init_lists(usbvcp); 467*c77a61a7Syz 468*c77a61a7Syz usbvcp->usbvc_default_ph = usbvcp->usbvc_reg->dev_default_ph; 469*c77a61a7Syz 470*c77a61a7Syz /* Put online before PM init as can get power managed afterward. */ 471*c77a61a7Syz usbvcp->usbvc_dev_state = USB_DEV_ONLINE; 472*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 473*c77a61a7Syz 474*c77a61a7Syz /* initialize power management */ 475*c77a61a7Syz usbvc_init_power_mgmt(usbvcp); 476*c77a61a7Syz 477*c77a61a7Syz if ((status = usbvc_parse_ctrl_if(usbvcp)) != USB_SUCCESS) { 478*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 479*c77a61a7Syz "usbvc_attach: parse ctrl interface fail, error code:%d", 480*c77a61a7Syz status); 481*c77a61a7Syz 482*c77a61a7Syz goto fail; 483*c77a61a7Syz } 484*c77a61a7Syz if ((status = usbvc_parse_stream_ifs(usbvcp)) != USB_SUCCESS) { 485*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 486*c77a61a7Syz "usbvc_attach: parse stream interfaces fail, error code:%d", 487*c77a61a7Syz status); 488*c77a61a7Syz 489*c77a61a7Syz goto fail; 490*c77a61a7Syz } 491*c77a61a7Syz (void) usbvc_set_default_stream_fmt(usbvcp); 492*c77a61a7Syz 493*c77a61a7Syz /* Register for events */ 494*c77a61a7Syz if ((status = usb_register_event_cbs(dip, &usbvc_events, 0)) != 495*c77a61a7Syz USB_SUCCESS) { 496*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 497*c77a61a7Syz "usbvc_attach: register_event_cbs failed, error code:%d", 498*c77a61a7Syz status); 499*c77a61a7Syz 500*c77a61a7Syz goto fail; 501*c77a61a7Syz } 502*c77a61a7Syz 503*c77a61a7Syz /* Report device */ 504*c77a61a7Syz ddi_report_dev(dip); 505*c77a61a7Syz 506*c77a61a7Syz return (DDI_SUCCESS); 507*c77a61a7Syz 508*c77a61a7Syz fail: 509*c77a61a7Syz if (usbvcp) { 510*c77a61a7Syz usbvc_cleanup(dip, usbvcp); 511*c77a61a7Syz } 512*c77a61a7Syz 513*c77a61a7Syz return (DDI_FAILURE); 514*c77a61a7Syz } 515*c77a61a7Syz 516*c77a61a7Syz 517*c77a61a7Syz /* 518*c77a61a7Syz * usbvc_detach: 519*c77a61a7Syz * detach or suspend driver instance 520*c77a61a7Syz * 521*c77a61a7Syz * Note: in detach, only contention threads is from pm and disconnnect. 522*c77a61a7Syz */ 523*c77a61a7Syz static int 524*c77a61a7Syz usbvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 525*c77a61a7Syz { 526*c77a61a7Syz int instance = ddi_get_instance(dip); 527*c77a61a7Syz usbvc_state_t *usbvcp = ddi_get_soft_state(usbvc_statep, instance); 528*c77a61a7Syz int rval = USB_FAILURE; 529*c77a61a7Syz 530*c77a61a7Syz switch (cmd) { 531*c77a61a7Syz case DDI_DETACH: 532*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 533*c77a61a7Syz ASSERT((usbvcp->usbvc_drv_state & USBVC_OPEN) == 0); 534*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 535*c77a61a7Syz 536*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 537*c77a61a7Syz "usbvc_detach: enter for detach"); 538*c77a61a7Syz 539*c77a61a7Syz usbvc_cleanup(dip, usbvcp); 540*c77a61a7Syz rval = USB_SUCCESS; 541*c77a61a7Syz 542*c77a61a7Syz break; 543*c77a61a7Syz case DDI_SUSPEND: 544*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 545*c77a61a7Syz "usbvc_detach: enter for suspend"); 546*c77a61a7Syz 547*c77a61a7Syz usbvc_cpr_suspend(dip); 548*c77a61a7Syz rval = USB_SUCCESS; 549*c77a61a7Syz 550*c77a61a7Syz break; 551*c77a61a7Syz default: 552*c77a61a7Syz 553*c77a61a7Syz break; 554*c77a61a7Syz } 555*c77a61a7Syz 556*c77a61a7Syz return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 557*c77a61a7Syz } 558*c77a61a7Syz 559*c77a61a7Syz 560*c77a61a7Syz /* 561*c77a61a7Syz * usbvc_cleanup: 562*c77a61a7Syz * clean up the driver state for detach 563*c77a61a7Syz */ 564*c77a61a7Syz static void 565*c77a61a7Syz usbvc_cleanup(dev_info_t *dip, usbvc_state_t *usbvcp) 566*c77a61a7Syz { 567*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 568*c77a61a7Syz "Cleanup: enter"); 569*c77a61a7Syz 570*c77a61a7Syz if (usbvcp->usbvc_locks_initialized) { 571*c77a61a7Syz 572*c77a61a7Syz /* This must be done 1st to prevent more events from coming. */ 573*c77a61a7Syz usb_unregister_event_cbs(dip, &usbvc_events); 574*c77a61a7Syz 575*c77a61a7Syz /* 576*c77a61a7Syz * At this point, no new activity can be initiated. The driver 577*c77a61a7Syz * has disabled hotplug callbacks. The Solaris framework has 578*c77a61a7Syz * disabled new opens on a device being detached, and does not 579*c77a61a7Syz * allow detaching an open device. 580*c77a61a7Syz * 581*c77a61a7Syz * The following ensures that all driver activity has drained. 582*c77a61a7Syz */ 583*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 584*c77a61a7Syz (void) usbvc_serialize_access(usbvcp, USBVC_SER_NOSIG); 585*c77a61a7Syz usbvc_release_access(usbvcp); 586*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 587*c77a61a7Syz 588*c77a61a7Syz /* All device activity has died down. */ 589*c77a61a7Syz usbvc_destroy_power_mgmt(usbvcp); 590*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 591*c77a61a7Syz usbvc_fini_lists(usbvcp); 592*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 593*c77a61a7Syz 594*c77a61a7Syz ddi_remove_minor_node(dip, NULL); 595*c77a61a7Syz usbvc_fini_sync_objs(usbvcp); 596*c77a61a7Syz } 597*c77a61a7Syz 598*c77a61a7Syz usb_client_detach(dip, usbvcp->usbvc_reg); 599*c77a61a7Syz usb_free_log_hdl(usbvcp->usbvc_log_handle); 600*c77a61a7Syz ddi_soft_state_free(usbvc_statep, ddi_get_instance(dip)); 601*c77a61a7Syz ddi_prop_remove_all(dip); 602*c77a61a7Syz } 603*c77a61a7Syz 604*c77a61a7Syz 605*c77a61a7Syz /*ARGSUSED*/ 606*c77a61a7Syz static int 607*c77a61a7Syz usbvc_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 608*c77a61a7Syz { 609*c77a61a7Syz usbvc_state_t *usbvcp = 610*c77a61a7Syz ddi_get_soft_state(usbvc_statep, getminor(*devp)); 611*c77a61a7Syz 612*c77a61a7Syz if (usbvcp == NULL) { 613*c77a61a7Syz 614*c77a61a7Syz return (ENXIO); 615*c77a61a7Syz } 616*c77a61a7Syz 617*c77a61a7Syz /* 618*c77a61a7Syz * Keep it simple: one client at a time. 619*c77a61a7Syz * Exclusive open only 620*c77a61a7Syz */ 621*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 622*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 623*c77a61a7Syz "usbvc_open: enter, dev_stat=%d", usbvcp->usbvc_dev_state); 624*c77a61a7Syz 625*c77a61a7Syz if (usbvcp->usbvc_dev_state == USB_DEV_DISCONNECTED) { 626*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 627*c77a61a7Syz 628*c77a61a7Syz return (ENODEV); 629*c77a61a7Syz } 630*c77a61a7Syz if (usbvcp->usbvc_dev_state == USB_DEV_SUSPENDED) { 631*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 632*c77a61a7Syz 633*c77a61a7Syz return (EIO); 634*c77a61a7Syz } 635*c77a61a7Syz if ((usbvcp->usbvc_drv_state & USBVC_OPEN) != 0) { 636*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 637*c77a61a7Syz 638*c77a61a7Syz return (EBUSY); 639*c77a61a7Syz } 640*c77a61a7Syz usbvcp->usbvc_drv_state |= USBVC_OPEN; 641*c77a61a7Syz 642*c77a61a7Syz if (usbvc_serialize_access(usbvcp, USBVC_SER_SIG) == 0) { 643*c77a61a7Syz usbvcp->usbvc_drv_state &= ~USBVC_OPEN; 644*c77a61a7Syz usbvcp->usbvc_serial_inuse = B_FALSE; 645*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 646*c77a61a7Syz 647*c77a61a7Syz return (EINTR); 648*c77a61a7Syz } 649*c77a61a7Syz 650*c77a61a7Syz /* raise power */ 651*c77a61a7Syz usbvc_pm_busy_component(usbvcp); 652*c77a61a7Syz if (usbvcp->usbvc_pm->usbvc_current_power != USB_DEV_OS_FULL_PWR) { 653*c77a61a7Syz usbvcp->usbvc_pm->usbvc_raise_power = B_TRUE; 654*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 655*c77a61a7Syz (void) pm_raise_power(usbvcp->usbvc_dip, 656*c77a61a7Syz 0, USB_DEV_OS_FULL_PWR); 657*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 658*c77a61a7Syz usbvcp->usbvc_pm->usbvc_raise_power = B_FALSE; 659*c77a61a7Syz } 660*c77a61a7Syz 661*c77a61a7Syz /* Device is idle until it is used. */ 662*c77a61a7Syz usbvc_release_access(usbvcp); 663*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 664*c77a61a7Syz 665*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 666*c77a61a7Syz "usbvc_open: end."); 667*c77a61a7Syz 668*c77a61a7Syz return (0); 669*c77a61a7Syz } 670*c77a61a7Syz 671*c77a61a7Syz 672*c77a61a7Syz /*ARGSUSED*/ 673*c77a61a7Syz static int 674*c77a61a7Syz usbvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 675*c77a61a7Syz { 676*c77a61a7Syz usbvc_stream_if_t *strm_if; 677*c77a61a7Syz int if_num; 678*c77a61a7Syz usbvc_state_t *usbvcp = 679*c77a61a7Syz ddi_get_soft_state(usbvc_statep, getminor(dev)); 680*c77a61a7Syz 681*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_CLOSE, usbvcp->usbvc_log_handle, 682*c77a61a7Syz "close: enter"); 683*c77a61a7Syz 684*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 685*c77a61a7Syz (void) usbvc_serialize_access(usbvcp, USBVC_SER_NOSIG); 686*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 687*c77a61a7Syz 688*c77a61a7Syz /* Perform device session cleanup here. */ 689*c77a61a7Syz 690*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbvcp->usbvc_log_handle, 691*c77a61a7Syz "close: cleaning up..."); 692*c77a61a7Syz 693*c77a61a7Syz /* 694*c77a61a7Syz * USBA automatically flushes/resets active non-default pipes 695*c77a61a7Syz * when they are closed. We can't reset default pipe, but we 696*c77a61a7Syz * can wait for all requests on it from this dip to drain. 697*c77a61a7Syz */ 698*c77a61a7Syz (void) usb_pipe_drain_reqs(usbvcp->usbvc_dip, 699*c77a61a7Syz usbvcp->usbvc_reg->dev_default_ph, 0, 700*c77a61a7Syz USB_FLAGS_SLEEP, NULL, 0); 701*c77a61a7Syz 702*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 703*c77a61a7Syz strm_if = usbvcp->usbvc_curr_strm; 704*c77a61a7Syz if (strm_if->start_polling == 1) { 705*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 706*c77a61a7Syz usb_pipe_stop_isoc_polling(strm_if->datain_ph, USB_FLAGS_SLEEP); 707*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 708*c77a61a7Syz strm_if->start_polling = 0; 709*c77a61a7Syz } 710*c77a61a7Syz usbvc_close_isoc_pipe(usbvcp, strm_if); 711*c77a61a7Syz if_num = strm_if->if_descr->if_alt->altif_descr.bInterfaceNumber; 712*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 713*c77a61a7Syz 714*c77a61a7Syz /* reset alternate to the default one. */ 715*c77a61a7Syz (void) usb_set_alt_if(usbvcp->usbvc_dip, if_num, 0, 716*c77a61a7Syz USB_FLAGS_SLEEP, NULL, NULL); 717*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 718*c77a61a7Syz 719*c77a61a7Syz usbvc_free_read_bufs(usbvcp, strm_if); 720*c77a61a7Syz usbvc_free_map_bufs(usbvcp, strm_if); 721*c77a61a7Syz usbvcp->usbvc_drv_state &= ~USBVC_OPEN; 722*c77a61a7Syz 723*c77a61a7Syz usbvc_release_access(usbvcp); 724*c77a61a7Syz usbvc_pm_idle_component(usbvcp); 725*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 726*c77a61a7Syz 727*c77a61a7Syz return (0); 728*c77a61a7Syz } 729*c77a61a7Syz 730*c77a61a7Syz 731*c77a61a7Syz /*ARGSUSED*/ 732*c77a61a7Syz /* Read isoc data from usb video devices */ 733*c77a61a7Syz static int 734*c77a61a7Syz usbvc_read(dev_t dev, struct uio *uio_p, cred_t *cred_p) 735*c77a61a7Syz { 736*c77a61a7Syz int rval; 737*c77a61a7Syz usbvc_stream_if_t *strm_if; 738*c77a61a7Syz usbvc_state_t *usbvcp = 739*c77a61a7Syz ddi_get_soft_state(usbvc_statep, getminor(dev)); 740*c77a61a7Syz 741*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 742*c77a61a7Syz "usbvc_read: enter"); 743*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 744*c77a61a7Syz if (usbvcp->usbvc_dev_state != USB_DEV_ONLINE) { 745*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 746*c77a61a7Syz "usbvc_read: Device is not available," 747*c77a61a7Syz " dev_stat=%d", usbvcp->usbvc_dev_state); 748*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 749*c77a61a7Syz 750*c77a61a7Syz return (EFAULT); 751*c77a61a7Syz } 752*c77a61a7Syz if ((uio_p->uio_fmode & (FNDELAY|FNONBLOCK)) && 753*c77a61a7Syz (usbvcp->usbvc_serial_inuse != B_FALSE)) { 754*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 755*c77a61a7Syz "usbvc_read: non-blocking read, return fail."); 756*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 757*c77a61a7Syz 758*c77a61a7Syz return (EAGAIN); 759*c77a61a7Syz } 760*c77a61a7Syz if (usbvc_serialize_access(usbvcp, USBVC_SER_SIG) <= 0) { 761*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 762*c77a61a7Syz "usbvc_read: serialize_access failed."); 763*c77a61a7Syz rval = EFAULT; 764*c77a61a7Syz 765*c77a61a7Syz goto fail; 766*c77a61a7Syz } 767*c77a61a7Syz 768*c77a61a7Syz /* Get the first stream interface */ 769*c77a61a7Syz strm_if = usbvcp->usbvc_curr_strm; 770*c77a61a7Syz if (!strm_if) { 771*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 772*c77a61a7Syz "usbvc_read: no stream interfaces"); 773*c77a61a7Syz rval = EFAULT; 774*c77a61a7Syz 775*c77a61a7Syz goto fail; 776*c77a61a7Syz } 777*c77a61a7Syz 778*c77a61a7Syz /* 779*c77a61a7Syz * If it is the first read, open isoc pipe and allocate bufs for 780*c77a61a7Syz * read I/O method. 781*c77a61a7Syz */ 782*c77a61a7Syz if (strm_if->datain_ph == NULL) { 783*c77a61a7Syz if (usbvc_open_isoc_pipe(usbvcp, strm_if) != USB_SUCCESS) { 784*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_READ, 785*c77a61a7Syz usbvcp->usbvc_log_handle, 786*c77a61a7Syz "usbvc_read: first read, open pipe fail"); 787*c77a61a7Syz rval = EFAULT; 788*c77a61a7Syz 789*c77a61a7Syz goto fail; 790*c77a61a7Syz } 791*c77a61a7Syz if (usbvc_alloc_read_bufs(usbvcp, strm_if) != USB_SUCCESS) { 792*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_READ, 793*c77a61a7Syz usbvcp->usbvc_log_handle, 794*c77a61a7Syz "usbvc_read: allocate rw bufs fail"); 795*c77a61a7Syz rval = EFAULT; 796*c77a61a7Syz 797*c77a61a7Syz goto fail; 798*c77a61a7Syz } 799*c77a61a7Syz } 800*c77a61a7Syz 801*c77a61a7Syz /* start polling if it is not started yet */ 802*c77a61a7Syz if (strm_if->start_polling != 1) { 803*c77a61a7Syz if (usbvc_start_isoc_polling(usbvcp, strm_if, NULL) != 804*c77a61a7Syz USB_SUCCESS) { 805*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_READ, 806*c77a61a7Syz usbvcp->usbvc_log_handle, 807*c77a61a7Syz "usbvc_read: usbvc_start_isoc_polling fail"); 808*c77a61a7Syz rval = EFAULT; 809*c77a61a7Syz 810*c77a61a7Syz goto fail; 811*c77a61a7Syz } 812*c77a61a7Syz strm_if->start_polling = 1; 813*c77a61a7Syz } 814*c77a61a7Syz 815*c77a61a7Syz if (list_is_empty(&strm_if->buf_read.uv_buf_done)) { 816*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 817*c77a61a7Syz "usbvc_read: full buf list is empty."); 818*c77a61a7Syz 819*c77a61a7Syz if (uio_p->uio_fmode & (FNDELAY | FNONBLOCK)) { 820*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_READ, 821*c77a61a7Syz usbvcp->usbvc_log_handle, "usbvc_read: fail, " 822*c77a61a7Syz "non-blocking read, done buf is empty."); 823*c77a61a7Syz rval = EAGAIN; 824*c77a61a7Syz 825*c77a61a7Syz goto fail; 826*c77a61a7Syz } 827*c77a61a7Syz 828*c77a61a7Syz /* no available buffers, block here */ 829*c77a61a7Syz while (list_is_empty(&strm_if->buf_read.uv_buf_done)) { 830*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_READ, 831*c77a61a7Syz usbvcp->usbvc_log_handle, 832*c77a61a7Syz "usbvc_read: wait for done buf"); 833*c77a61a7Syz if (cv_wait_sig(&usbvcp->usbvc_read_cv, 834*c77a61a7Syz &usbvcp->usbvc_mutex) <= 0) { 835*c77a61a7Syz /* no done buf and cv is signaled */ 836*c77a61a7Syz rval = EINTR; 837*c77a61a7Syz 838*c77a61a7Syz goto fail; 839*c77a61a7Syz } 840*c77a61a7Syz if (usbvcp->usbvc_dev_state != USB_DEV_ONLINE) { 841*c77a61a7Syz 842*c77a61a7Syz /* Device is disconnected. */ 843*c77a61a7Syz rval = EINTR; 844*c77a61a7Syz 845*c77a61a7Syz goto fail; 846*c77a61a7Syz } 847*c77a61a7Syz } 848*c77a61a7Syz 849*c77a61a7Syz } 850*c77a61a7Syz 851*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 852*c77a61a7Syz rval = physio(usbvc_strategy, NULL, dev, B_READ, 853*c77a61a7Syz usbvc_minphys, uio_p); 854*c77a61a7Syz 855*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 856*c77a61a7Syz usbvc_release_access(usbvcp); 857*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 858*c77a61a7Syz 859*c77a61a7Syz return (rval); 860*c77a61a7Syz 861*c77a61a7Syz fail: 862*c77a61a7Syz usbvc_release_access(usbvcp); 863*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 864*c77a61a7Syz 865*c77a61a7Syz return (rval); 866*c77a61a7Syz } 867*c77a61a7Syz 868*c77a61a7Syz 869*c77a61a7Syz /* 870*c77a61a7Syz * strategy: 871*c77a61a7Syz * Called through physio to setup and start the transfer. 872*c77a61a7Syz */ 873*c77a61a7Syz static int 874*c77a61a7Syz usbvc_strategy(struct buf *bp) 875*c77a61a7Syz { 876*c77a61a7Syz usbvc_state_t *usbvcp = ddi_get_soft_state(usbvc_statep, 877*c77a61a7Syz getminor(bp->b_edev)); 878*c77a61a7Syz 879*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 880*c77a61a7Syz "usbvc_strategy: enter"); 881*c77a61a7Syz 882*c77a61a7Syz /* 883*c77a61a7Syz * Initialize residual count here in case transfer doesn't even get 884*c77a61a7Syz * started. 885*c77a61a7Syz */ 886*c77a61a7Syz bp->b_resid = bp->b_bcount; 887*c77a61a7Syz 888*c77a61a7Syz /* Needed as this is a character driver. */ 889*c77a61a7Syz if (bp->b_flags & (B_PHYS | B_PAGEIO)) { 890*c77a61a7Syz bp_mapin(bp); 891*c77a61a7Syz } 892*c77a61a7Syz 893*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 894*c77a61a7Syz 895*c77a61a7Syz /* Make sure device has not been disconnected. */ 896*c77a61a7Syz if (usbvcp->usbvc_dev_state != USB_DEV_ONLINE) { 897*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 898*c77a61a7Syz "usbvc_strategy: device can't be accessed"); 899*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 900*c77a61a7Syz 901*c77a61a7Syz goto fail; 902*c77a61a7Syz } 903*c77a61a7Syz 904*c77a61a7Syz /* read data from uv_buf_done list */ 905*c77a61a7Syz if (usbvc_read_buf(usbvcp, bp) != USB_SUCCESS) { 906*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 907*c77a61a7Syz "usbvc_strategy: read full buf list fail"); 908*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 909*c77a61a7Syz 910*c77a61a7Syz goto fail; 911*c77a61a7Syz } 912*c77a61a7Syz 913*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 914*c77a61a7Syz 915*c77a61a7Syz biodone(bp); 916*c77a61a7Syz 917*c77a61a7Syz return (0); 918*c77a61a7Syz 919*c77a61a7Syz fail: 920*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 921*c77a61a7Syz "usbvc_strategy: strategy fail"); 922*c77a61a7Syz bp->b_private = NULL; 923*c77a61a7Syz 924*c77a61a7Syz bioerror(bp, EIO); 925*c77a61a7Syz biodone(bp); 926*c77a61a7Syz 927*c77a61a7Syz return (0); 928*c77a61a7Syz } 929*c77a61a7Syz 930*c77a61a7Syz 931*c77a61a7Syz static void 932*c77a61a7Syz usbvc_minphys(struct buf *bp) 933*c77a61a7Syz { 934*c77a61a7Syz dev_t dev = bp->b_edev; 935*c77a61a7Syz usbvc_stream_if_t *strm_if; 936*c77a61a7Syz uint32_t maxsize; 937*c77a61a7Syz usbvc_state_t *usbvcp = 938*c77a61a7Syz ddi_get_soft_state(usbvc_statep, getminor(dev)); 939*c77a61a7Syz 940*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 941*c77a61a7Syz strm_if = usbvcp->usbvc_curr_strm; 942*c77a61a7Syz LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0, maxsize); 943*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 944*c77a61a7Syz "usbvc_minphys: max read size=%d", maxsize); 945*c77a61a7Syz 946*c77a61a7Syz if (bp->b_bcount > maxsize) { 947*c77a61a7Syz bp->b_bcount = maxsize; 948*c77a61a7Syz } 949*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 950*c77a61a7Syz } 951*c77a61a7Syz 952*c77a61a7Syz 953*c77a61a7Syz /* 954*c77a61a7Syz * ioctl entry. 955*c77a61a7Syz */ 956*c77a61a7Syz /*ARGSUSED*/ 957*c77a61a7Syz static int 958*c77a61a7Syz usbvc_ioctl(dev_t dev, int cmd, intptr_t arg, 959*c77a61a7Syz int mode, cred_t *cred_p, int *rval_p) 960*c77a61a7Syz { 961*c77a61a7Syz int rv = 0; 962*c77a61a7Syz usbvc_state_t *usbvcp = 963*c77a61a7Syz ddi_get_soft_state(usbvc_statep, getminor(dev)); 964*c77a61a7Syz 965*c77a61a7Syz if (usbvcp == NULL) { 966*c77a61a7Syz 967*c77a61a7Syz return (ENXIO); 968*c77a61a7Syz } 969*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 970*c77a61a7Syz "ioctl enter, cmd=%x", cmd); 971*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 972*c77a61a7Syz if (usbvcp->usbvc_dev_state != USB_DEV_ONLINE) { 973*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 974*c77a61a7Syz "ioctl: Device is not online," 975*c77a61a7Syz " dev_stat=%d", usbvcp->usbvc_dev_state); 976*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 977*c77a61a7Syz 978*c77a61a7Syz return (EFAULT); 979*c77a61a7Syz } 980*c77a61a7Syz if (usbvc_serialize_access(usbvcp, USBVC_SER_SIG) <= 0) { 981*c77a61a7Syz usbvcp->usbvc_serial_inuse = B_FALSE; 982*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 983*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 984*c77a61a7Syz "serialize_access failed."); 985*c77a61a7Syz 986*c77a61a7Syz return (EFAULT); 987*c77a61a7Syz } 988*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 989*c77a61a7Syz 990*c77a61a7Syz rv = usbvc_v4l2_ioctl(usbvcp, cmd, arg, mode); 991*c77a61a7Syz 992*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 993*c77a61a7Syz usbvc_release_access(usbvcp); 994*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 995*c77a61a7Syz 996*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 997*c77a61a7Syz "usbvc_ioctl exit"); 998*c77a61a7Syz 999*c77a61a7Syz return (rv); 1000*c77a61a7Syz } 1001*c77a61a7Syz 1002*c77a61a7Syz 1003*c77a61a7Syz /* Entry for mmap system call */ 1004*c77a61a7Syz static int 1005*c77a61a7Syz usbvc_devmap(dev_t dev, devmap_cookie_t handle, offset_t off, 1006*c77a61a7Syz size_t len, size_t *maplen, uint_t model) 1007*c77a61a7Syz { 1008*c77a61a7Syz usbvc_state_t *usbvcp; 1009*c77a61a7Syz int error, i; 1010*c77a61a7Syz usbvc_buf_t *buf = NULL; 1011*c77a61a7Syz usbvc_stream_if_t *strm_if; 1012*c77a61a7Syz usbvc_buf_grp_t *bufgrp; 1013*c77a61a7Syz 1014*c77a61a7Syz usbvcp = ddi_get_soft_state(usbvc_statep, getminor(dev)); 1015*c77a61a7Syz if (usbvcp == NULL) { 1016*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVMAP, usbvcp->usbvc_log_handle, 1017*c77a61a7Syz "usbvc_devmap: usbvcp == NULL"); 1018*c77a61a7Syz 1019*c77a61a7Syz return (ENXIO); 1020*c77a61a7Syz } 1021*c77a61a7Syz 1022*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_DEVMAP, usbvcp->usbvc_log_handle, 1023*c77a61a7Syz "devmap: memory map for instance(%d), off=%llx, len=%d, maplen=%d," 1024*c77a61a7Syz " model=%d", getminor(dev), off, len, maplen, model); 1025*c77a61a7Syz 1026*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1027*c77a61a7Syz (void) usbvc_serialize_access(usbvcp, USBVC_SER_NOSIG); 1028*c77a61a7Syz strm_if = usbvcp->usbvc_curr_strm; 1029*c77a61a7Syz if (!strm_if) { 1030*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVMAP, usbvcp->usbvc_log_handle, 1031*c77a61a7Syz "usbvc_devmap: No current strm if"); 1032*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1033*c77a61a7Syz 1034*c77a61a7Syz return (ENXIO); 1035*c77a61a7Syz } 1036*c77a61a7Syz bufgrp = &strm_if->buf_map; 1037*c77a61a7Syz for (i = 0; i < bufgrp->buf_cnt; i++) { 1038*c77a61a7Syz if (bufgrp->buf_head[i].v4l2_buf.m.offset == off) { 1039*c77a61a7Syz buf = &bufgrp->buf_head[i]; 1040*c77a61a7Syz 1041*c77a61a7Syz break; 1042*c77a61a7Syz } 1043*c77a61a7Syz } 1044*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_DEVMAP, usbvcp->usbvc_log_handle, 1045*c77a61a7Syz "usbvc_devmap: idx=%d", i); 1046*c77a61a7Syz if (buf == NULL) { 1047*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1048*c77a61a7Syz 1049*c77a61a7Syz return (ENXIO); 1050*c77a61a7Syz } 1051*c77a61a7Syz /* 1052*c77a61a7Syz * round up len to a multiple of a page size, according to chapter 1053*c77a61a7Syz * 10 of "writing device drivers" 1054*c77a61a7Syz */ 1055*c77a61a7Syz len = ptob(btopr(len)); 1056*c77a61a7Syz if (len > ptob(btopr(buf->len))) { 1057*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVMAP, usbvcp->usbvc_log_handle, 1058*c77a61a7Syz "usbvc_devmap: len=%x", len); 1059*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1060*c77a61a7Syz 1061*c77a61a7Syz return (ENXIO); 1062*c77a61a7Syz } 1063*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1064*c77a61a7Syz 1065*c77a61a7Syz error = devmap_umem_setup(handle, usbvcp->usbvc_dip, NULL, 1066*c77a61a7Syz buf->umem_cookie, off, len, PROT_ALL, DEVMAP_DEFAULTS, NULL); 1067*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1068*c77a61a7Syz *maplen = len; 1069*c77a61a7Syz if (error == 0 && buf->status == USBVC_BUF_INIT) { 1070*c77a61a7Syz buf->status = USBVC_BUF_MAPPED; 1071*c77a61a7Syz } else { 1072*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_DEVMAP, usbvcp->usbvc_log_handle, 1073*c77a61a7Syz "usbvc_devmap: devmap_umem_setup, err=%d", error); 1074*c77a61a7Syz } 1075*c77a61a7Syz 1076*c77a61a7Syz (void) usbvc_release_access(usbvcp); 1077*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1078*c77a61a7Syz 1079*c77a61a7Syz return (error); 1080*c77a61a7Syz } 1081*c77a61a7Syz 1082*c77a61a7Syz /* 1083*c77a61a7Syz * pm and cpr 1084*c77a61a7Syz */ 1085*c77a61a7Syz 1086*c77a61a7Syz /* 1087*c77a61a7Syz * usbvc_power : 1088*c77a61a7Syz * Power entry point, the workhorse behind pm_raise_power, pm_lower_power, 1089*c77a61a7Syz * usb_req_raise_power and usb_req_lower_power. 1090*c77a61a7Syz */ 1091*c77a61a7Syz /* ARGSUSED */ 1092*c77a61a7Syz static int 1093*c77a61a7Syz usbvc_power(dev_info_t *dip, int comp, int level) 1094*c77a61a7Syz { 1095*c77a61a7Syz usbvc_state_t *usbvcp; 1096*c77a61a7Syz usbvc_power_t *pm; 1097*c77a61a7Syz int rval = USB_FAILURE; 1098*c77a61a7Syz 1099*c77a61a7Syz usbvcp = ddi_get_soft_state(usbvc_statep, ddi_get_instance(dip)); 1100*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1101*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1102*c77a61a7Syz "usbvc_power: enter: level = %d, dev_state: %x", 1103*c77a61a7Syz level, usbvcp->usbvc_dev_state); 1104*c77a61a7Syz 1105*c77a61a7Syz if (usbvcp->usbvc_pm == NULL) { 1106*c77a61a7Syz 1107*c77a61a7Syz goto done; 1108*c77a61a7Syz } 1109*c77a61a7Syz 1110*c77a61a7Syz pm = usbvcp->usbvc_pm; 1111*c77a61a7Syz 1112*c77a61a7Syz /* Check if we are transitioning to a legal power level */ 1113*c77a61a7Syz if (USB_DEV_PWRSTATE_OK(pm->usbvc_pwr_states, level)) { 1114*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 1115*c77a61a7Syz "usbvc_power: illegal power level = %d " 1116*c77a61a7Syz "pwr_states: %x", level, pm->usbvc_pwr_states); 1117*c77a61a7Syz 1118*c77a61a7Syz goto done; 1119*c77a61a7Syz } 1120*c77a61a7Syz /* 1121*c77a61a7Syz * if we are about to raise power and asked to lower power, fail 1122*c77a61a7Syz */ 1123*c77a61a7Syz if (pm->usbvc_raise_power && (level < (int)pm->usbvc_current_power)) { 1124*c77a61a7Syz 1125*c77a61a7Syz goto done; 1126*c77a61a7Syz } 1127*c77a61a7Syz switch (level) { 1128*c77a61a7Syz case USB_DEV_OS_PWR_OFF : 1129*c77a61a7Syz rval = usbvc_pwrlvl0(usbvcp); 1130*c77a61a7Syz 1131*c77a61a7Syz break; 1132*c77a61a7Syz case USB_DEV_OS_PWR_1 : 1133*c77a61a7Syz rval = usbvc_pwrlvl1(usbvcp); 1134*c77a61a7Syz 1135*c77a61a7Syz break; 1136*c77a61a7Syz case USB_DEV_OS_PWR_2 : 1137*c77a61a7Syz rval = usbvc_pwrlvl2(usbvcp); 1138*c77a61a7Syz 1139*c77a61a7Syz break; 1140*c77a61a7Syz case USB_DEV_OS_FULL_PWR : 1141*c77a61a7Syz rval = usbvc_pwrlvl3(usbvcp); 1142*c77a61a7Syz 1143*c77a61a7Syz break; 1144*c77a61a7Syz } 1145*c77a61a7Syz 1146*c77a61a7Syz done: 1147*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1148*c77a61a7Syz 1149*c77a61a7Syz return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 1150*c77a61a7Syz } 1151*c77a61a7Syz 1152*c77a61a7Syz 1153*c77a61a7Syz /* 1154*c77a61a7Syz * usbvc_init_power_mgmt: 1155*c77a61a7Syz * Initialize power management and remote wakeup functionality. 1156*c77a61a7Syz * No mutex is necessary in this function as it's called only by attach. 1157*c77a61a7Syz */ 1158*c77a61a7Syz static void 1159*c77a61a7Syz usbvc_init_power_mgmt(usbvc_state_t *usbvcp) 1160*c77a61a7Syz { 1161*c77a61a7Syz usbvc_power_t *usbvcpm; 1162*c77a61a7Syz uint_t pwr_states; 1163*c77a61a7Syz 1164*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1165*c77a61a7Syz "init_power_mgmt enter"); 1166*c77a61a7Syz 1167*c77a61a7Syz /* Allocate the state structure */ 1168*c77a61a7Syz usbvcpm = kmem_zalloc(sizeof (usbvc_power_t), KM_SLEEP); 1169*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1170*c77a61a7Syz usbvcp->usbvc_pm = usbvcpm; 1171*c77a61a7Syz usbvcpm->usbvc_state = usbvcp; 1172*c77a61a7Syz usbvcpm->usbvc_pm_capabilities = 0; 1173*c77a61a7Syz usbvcpm->usbvc_current_power = USB_DEV_OS_FULL_PWR; 1174*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1175*c77a61a7Syz 1176*c77a61a7Syz if (usb_create_pm_components(usbvcp->usbvc_dip, &pwr_states) == 1177*c77a61a7Syz USB_SUCCESS) { 1178*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1179*c77a61a7Syz "usbvc_init_power_mgmt: created PM components"); 1180*c77a61a7Syz 1181*c77a61a7Syz if (usb_handle_remote_wakeup(usbvcp->usbvc_dip, 1182*c77a61a7Syz USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 1183*c77a61a7Syz usbvcpm->usbvc_wakeup_enabled = 1; 1184*c77a61a7Syz } else { 1185*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, 1186*c77a61a7Syz usbvcp->usbvc_log_handle, "usbvc_init_power_mgmt:" 1187*c77a61a7Syz " remote wakeup not supported"); 1188*c77a61a7Syz } 1189*c77a61a7Syz 1190*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1191*c77a61a7Syz usbvcpm->usbvc_pwr_states = (uint8_t)pwr_states; 1192*c77a61a7Syz usbvc_pm_busy_component(usbvcp); 1193*c77a61a7Syz usbvcpm->usbvc_raise_power = B_TRUE; 1194*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1195*c77a61a7Syz 1196*c77a61a7Syz (void) pm_raise_power( 1197*c77a61a7Syz usbvcp->usbvc_dip, 0, USB_DEV_OS_FULL_PWR); 1198*c77a61a7Syz 1199*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1200*c77a61a7Syz usbvcpm->usbvc_raise_power = B_FALSE; 1201*c77a61a7Syz usbvc_pm_idle_component(usbvcp); 1202*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1203*c77a61a7Syz 1204*c77a61a7Syz } 1205*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1206*c77a61a7Syz "usbvc_init_power_mgmt: end"); 1207*c77a61a7Syz } 1208*c77a61a7Syz 1209*c77a61a7Syz 1210*c77a61a7Syz /* 1211*c77a61a7Syz * usbvc_destroy_power_mgmt: 1212*c77a61a7Syz * Shut down and destroy power management and remote wakeup functionality. 1213*c77a61a7Syz */ 1214*c77a61a7Syz static void 1215*c77a61a7Syz usbvc_destroy_power_mgmt(usbvc_state_t *usbvcp) 1216*c77a61a7Syz { 1217*c77a61a7Syz usbvc_power_t *pm; 1218*c77a61a7Syz int rval; 1219*c77a61a7Syz 1220*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1221*c77a61a7Syz "destroy_power_mgmt enter"); 1222*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1223*c77a61a7Syz pm = usbvcp->usbvc_pm; 1224*c77a61a7Syz if (pm && (usbvcp->usbvc_dev_state != USB_DEV_DISCONNECTED)) { 1225*c77a61a7Syz 1226*c77a61a7Syz usbvc_pm_busy_component(usbvcp); 1227*c77a61a7Syz if (pm->usbvc_wakeup_enabled) { 1228*c77a61a7Syz pm->usbvc_raise_power = B_TRUE; 1229*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1230*c77a61a7Syz 1231*c77a61a7Syz /* First bring the device to full power */ 1232*c77a61a7Syz (void) pm_raise_power(usbvcp->usbvc_dip, 0, 1233*c77a61a7Syz USB_DEV_OS_FULL_PWR); 1234*c77a61a7Syz if ((rval = usb_handle_remote_wakeup( 1235*c77a61a7Syz usbvcp->usbvc_dip, 1236*c77a61a7Syz USB_REMOTE_WAKEUP_DISABLE)) != 1237*c77a61a7Syz USB_SUCCESS) { 1238*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, 1239*c77a61a7Syz usbvcp->usbvc_log_handle, 1240*c77a61a7Syz "usbvc_destroy_power_mgmt: " 1241*c77a61a7Syz "Error disabling rmt wakeup: rval = %d", 1242*c77a61a7Syz rval); 1243*c77a61a7Syz } 1244*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1245*c77a61a7Syz pm->usbvc_raise_power = B_FALSE; 1246*c77a61a7Syz 1247*c77a61a7Syz } 1248*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1249*c77a61a7Syz 1250*c77a61a7Syz /* 1251*c77a61a7Syz * Since remote wakeup is disabled now, 1252*c77a61a7Syz * no one can raise power 1253*c77a61a7Syz * and get to device once power is lowered here. 1254*c77a61a7Syz */ 1255*c77a61a7Syz (void) pm_lower_power(usbvcp->usbvc_dip, 0, USB_DEV_OS_PWR_OFF); 1256*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1257*c77a61a7Syz usbvc_pm_idle_component(usbvcp); 1258*c77a61a7Syz } 1259*c77a61a7Syz 1260*c77a61a7Syz if (pm) { 1261*c77a61a7Syz kmem_free(pm, sizeof (usbvc_power_t)); 1262*c77a61a7Syz usbvcp->usbvc_pm = NULL; 1263*c77a61a7Syz } 1264*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1265*c77a61a7Syz } 1266*c77a61a7Syz 1267*c77a61a7Syz 1268*c77a61a7Syz static void 1269*c77a61a7Syz usbvc_pm_busy_component(usbvc_state_t *usbvcp) 1270*c77a61a7Syz { 1271*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 1272*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1273*c77a61a7Syz "usbvc_pm_busy_component: enter"); 1274*c77a61a7Syz 1275*c77a61a7Syz usbvcp->usbvc_pm->usbvc_pm_busy++; 1276*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1277*c77a61a7Syz 1278*c77a61a7Syz if (pm_busy_component(usbvcp->usbvc_dip, 0) != 1279*c77a61a7Syz DDI_SUCCESS) { 1280*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1281*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1282*c77a61a7Syz "usbvc_pm_busy_component: pm busy fail, usbvc_pm_busy=%d", 1283*c77a61a7Syz usbvcp->usbvc_pm->usbvc_pm_busy); 1284*c77a61a7Syz 1285*c77a61a7Syz usbvcp->usbvc_pm->usbvc_pm_busy--; 1286*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1287*c77a61a7Syz } 1288*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1289*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1290*c77a61a7Syz "usbvc_pm_busy_component: exit"); 1291*c77a61a7Syz } 1292*c77a61a7Syz 1293*c77a61a7Syz 1294*c77a61a7Syz static void 1295*c77a61a7Syz usbvc_pm_idle_component(usbvc_state_t *usbvcp) 1296*c77a61a7Syz { 1297*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 1298*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1299*c77a61a7Syz "usbvc_pm_idle_component: enter"); 1300*c77a61a7Syz 1301*c77a61a7Syz if (usbvcp->usbvc_pm != NULL) { 1302*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1303*c77a61a7Syz if (pm_idle_component(usbvcp->usbvc_dip, 0) == 1304*c77a61a7Syz DDI_SUCCESS) { 1305*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1306*c77a61a7Syz ASSERT(usbvcp->usbvc_pm->usbvc_pm_busy > 0); 1307*c77a61a7Syz usbvcp->usbvc_pm->usbvc_pm_busy--; 1308*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1309*c77a61a7Syz } 1310*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1311*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1312*c77a61a7Syz "usbvc_pm_idle_component: %d", 1313*c77a61a7Syz usbvcp->usbvc_pm->usbvc_pm_busy); 1314*c77a61a7Syz } 1315*c77a61a7Syz } 1316*c77a61a7Syz 1317*c77a61a7Syz 1318*c77a61a7Syz /* 1319*c77a61a7Syz * usbvc_pwrlvl0: 1320*c77a61a7Syz * Functions to handle power transition for OS levels 0 -> 3 1321*c77a61a7Syz */ 1322*c77a61a7Syz static int 1323*c77a61a7Syz usbvc_pwrlvl0(usbvc_state_t *usbvcp) 1324*c77a61a7Syz { 1325*c77a61a7Syz int rval; 1326*c77a61a7Syz 1327*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1328*c77a61a7Syz "usbvc_pwrlvl0, dev_state: %x", usbvcp->usbvc_dev_state); 1329*c77a61a7Syz 1330*c77a61a7Syz switch (usbvcp->usbvc_dev_state) { 1331*c77a61a7Syz case USB_DEV_ONLINE: 1332*c77a61a7Syz /* Deny the powerdown request if the device is busy */ 1333*c77a61a7Syz if (usbvcp->usbvc_pm->usbvc_pm_busy != 0) { 1334*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1335*c77a61a7Syz "usbvc_pwrlvl0: usbvc_pm_busy"); 1336*c77a61a7Syz 1337*c77a61a7Syz return (USB_FAILURE); 1338*c77a61a7Syz } 1339*c77a61a7Syz 1340*c77a61a7Syz /* Issue USB D3 command to the device here */ 1341*c77a61a7Syz rval = usb_set_device_pwrlvl3(usbvcp->usbvc_dip); 1342*c77a61a7Syz ASSERT(rval == USB_SUCCESS); 1343*c77a61a7Syz 1344*c77a61a7Syz usbvcp->usbvc_dev_state = USB_DEV_PWRED_DOWN; 1345*c77a61a7Syz usbvcp->usbvc_pm->usbvc_current_power = 1346*c77a61a7Syz USB_DEV_OS_PWR_OFF; 1347*c77a61a7Syz /* FALLTHRU */ 1348*c77a61a7Syz case USB_DEV_DISCONNECTED: 1349*c77a61a7Syz case USB_DEV_SUSPENDED: 1350*c77a61a7Syz /* allow a disconnect/cpr'ed device to go to lower power */ 1351*c77a61a7Syz 1352*c77a61a7Syz return (USB_SUCCESS); 1353*c77a61a7Syz case USB_DEV_PWRED_DOWN: 1354*c77a61a7Syz default: 1355*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1356*c77a61a7Syz "usbvc_pwrlvl0: illegal dev state"); 1357*c77a61a7Syz 1358*c77a61a7Syz return (USB_FAILURE); 1359*c77a61a7Syz } 1360*c77a61a7Syz } 1361*c77a61a7Syz 1362*c77a61a7Syz 1363*c77a61a7Syz /* 1364*c77a61a7Syz * usbvc_pwrlvl1: 1365*c77a61a7Syz * Functions to handle power transition to OS levels -> 2 1366*c77a61a7Syz */ 1367*c77a61a7Syz static int 1368*c77a61a7Syz usbvc_pwrlvl1(usbvc_state_t *usbvcp) 1369*c77a61a7Syz { 1370*c77a61a7Syz int rval; 1371*c77a61a7Syz 1372*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1373*c77a61a7Syz "usbvc_pwrlvl1"); 1374*c77a61a7Syz 1375*c77a61a7Syz /* Issue USB D2 command to the device here */ 1376*c77a61a7Syz rval = usb_set_device_pwrlvl2(usbvcp->usbvc_dip); 1377*c77a61a7Syz ASSERT(rval == USB_SUCCESS); 1378*c77a61a7Syz 1379*c77a61a7Syz return (USB_FAILURE); 1380*c77a61a7Syz } 1381*c77a61a7Syz 1382*c77a61a7Syz 1383*c77a61a7Syz /* 1384*c77a61a7Syz * usbvc_pwrlvl2: 1385*c77a61a7Syz * Functions to handle power transition to OS levels -> 1 1386*c77a61a7Syz */ 1387*c77a61a7Syz static int 1388*c77a61a7Syz usbvc_pwrlvl2(usbvc_state_t *usbvcp) 1389*c77a61a7Syz { 1390*c77a61a7Syz int rval; 1391*c77a61a7Syz 1392*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1393*c77a61a7Syz "usbvc_pwrlvl2"); 1394*c77a61a7Syz 1395*c77a61a7Syz /* Issue USB D1 command to the device here */ 1396*c77a61a7Syz rval = usb_set_device_pwrlvl1(usbvcp->usbvc_dip); 1397*c77a61a7Syz ASSERT(rval == USB_SUCCESS); 1398*c77a61a7Syz 1399*c77a61a7Syz return (USB_FAILURE); 1400*c77a61a7Syz } 1401*c77a61a7Syz 1402*c77a61a7Syz 1403*c77a61a7Syz /* 1404*c77a61a7Syz * usbvc_pwrlvl3: 1405*c77a61a7Syz * Functions to handle power transition to OS level -> 0 1406*c77a61a7Syz */ 1407*c77a61a7Syz static int 1408*c77a61a7Syz usbvc_pwrlvl3(usbvc_state_t *usbvcp) 1409*c77a61a7Syz { 1410*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1411*c77a61a7Syz "usbvc_pwrlvl3, dev_stat=%d", usbvcp->usbvc_dev_state); 1412*c77a61a7Syz 1413*c77a61a7Syz switch (usbvcp->usbvc_dev_state) { 1414*c77a61a7Syz case USB_DEV_PWRED_DOWN: 1415*c77a61a7Syz /* Issue USB D0 command to the device here */ 1416*c77a61a7Syz (void) usb_set_device_pwrlvl0(usbvcp->usbvc_dip); 1417*c77a61a7Syz 1418*c77a61a7Syz usbvcp->usbvc_dev_state = USB_DEV_ONLINE; 1419*c77a61a7Syz usbvcp->usbvc_pm->usbvc_current_power = 1420*c77a61a7Syz USB_DEV_OS_FULL_PWR; 1421*c77a61a7Syz 1422*c77a61a7Syz /* FALLTHRU */ 1423*c77a61a7Syz case USB_DEV_ONLINE: 1424*c77a61a7Syz /* we are already in full power */ 1425*c77a61a7Syz /* FALLTHRU */ 1426*c77a61a7Syz case USB_DEV_DISCONNECTED: 1427*c77a61a7Syz case USB_DEV_SUSPENDED: 1428*c77a61a7Syz /* 1429*c77a61a7Syz * PM framework tries to put us in full power 1430*c77a61a7Syz * during system shutdown. If we are disconnected/cpr'ed 1431*c77a61a7Syz * return success anyways 1432*c77a61a7Syz */ 1433*c77a61a7Syz 1434*c77a61a7Syz return (USB_SUCCESS); 1435*c77a61a7Syz default: 1436*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1437*c77a61a7Syz "usbvc_pwrlvl3: illegal dev state"); 1438*c77a61a7Syz 1439*c77a61a7Syz return (USB_FAILURE); 1440*c77a61a7Syz } 1441*c77a61a7Syz } 1442*c77a61a7Syz 1443*c77a61a7Syz 1444*c77a61a7Syz /* 1445*c77a61a7Syz * usbvc_cpr_suspend: 1446*c77a61a7Syz * Clean up device. 1447*c77a61a7Syz * Wait for any IO to finish, then close pipes. 1448*c77a61a7Syz * Quiesce device. 1449*c77a61a7Syz */ 1450*c77a61a7Syz static void 1451*c77a61a7Syz usbvc_cpr_suspend(dev_info_t *dip) 1452*c77a61a7Syz { 1453*c77a61a7Syz int instance = ddi_get_instance(dip); 1454*c77a61a7Syz usbvc_state_t *usbvcp = ddi_get_soft_state(usbvc_statep, 1455*c77a61a7Syz instance); 1456*c77a61a7Syz 1457*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1458*c77a61a7Syz "usbvc_cpr_suspend enter"); 1459*c77a61a7Syz 1460*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1461*c77a61a7Syz 1462*c77a61a7Syz /* 1463*c77a61a7Syz * Set dev_state to suspended so other driver threads don't start any 1464*c77a61a7Syz * new I/O. 1465*c77a61a7Syz */ 1466*c77a61a7Syz usbvcp->usbvc_dev_state = USB_DEV_SUSPENDED; 1467*c77a61a7Syz 1468*c77a61a7Syz /* 1469*c77a61a7Syz * Wake up the read threads in case there are any threads are blocking. 1470*c77a61a7Syz * After being waked up, those threads will quit immediately since the 1471*c77a61a7Syz * dev_state is not ONLINE 1472*c77a61a7Syz */ 1473*c77a61a7Syz if (usbvcp->usbvc_io_type == V4L2_MEMORY_MMAP) { 1474*c77a61a7Syz cv_broadcast(&usbvcp->usbvc_mapio_cv); 1475*c77a61a7Syz } else { 1476*c77a61a7Syz cv_broadcast(&usbvcp->usbvc_read_cv); 1477*c77a61a7Syz } 1478*c77a61a7Syz /* Wait for the other threads to quit */ 1479*c77a61a7Syz (void) usbvc_serialize_access(usbvcp, USBVC_SER_NOSIG); 1480*c77a61a7Syz usbvc_release_access(usbvcp); 1481*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1482*c77a61a7Syz 1483*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 1484*c77a61a7Syz "usbvc_cpr_suspend: return"); 1485*c77a61a7Syz } 1486*c77a61a7Syz 1487*c77a61a7Syz 1488*c77a61a7Syz /* 1489*c77a61a7Syz * usbvc_cpr_resume: 1490*c77a61a7Syz * 1491*c77a61a7Syz * usbvc_restore_device_state marks success by putting device back online 1492*c77a61a7Syz */ 1493*c77a61a7Syz static void 1494*c77a61a7Syz usbvc_cpr_resume(dev_info_t *dip) 1495*c77a61a7Syz { 1496*c77a61a7Syz int instance = ddi_get_instance(dip); 1497*c77a61a7Syz usbvc_state_t *usbvcp = ddi_get_soft_state(usbvc_statep, 1498*c77a61a7Syz instance); 1499*c77a61a7Syz 1500*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 1501*c77a61a7Syz "resume: enter"); 1502*c77a61a7Syz 1503*c77a61a7Syz /* 1504*c77a61a7Syz * NOTE: A pm_raise_power in usbvc_restore_device_state will bring 1505*c77a61a7Syz * the power-up state of device into synch with the system. 1506*c77a61a7Syz */ 1507*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1508*c77a61a7Syz usbvc_restore_device_state(dip, usbvcp); 1509*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1510*c77a61a7Syz } 1511*c77a61a7Syz 1512*c77a61a7Syz 1513*c77a61a7Syz /* 1514*c77a61a7Syz * usbvc_restore_device_state: 1515*c77a61a7Syz * Called during hotplug-reconnect and resume. 1516*c77a61a7Syz * reenable power management 1517*c77a61a7Syz * Verify the device is the same as before the disconnect/suspend. 1518*c77a61a7Syz * Restore device state 1519*c77a61a7Syz * Thaw any IO which was frozen. 1520*c77a61a7Syz * Quiesce device. (Other routines will activate if thawed IO.) 1521*c77a61a7Syz * Set device online. 1522*c77a61a7Syz * Leave device disconnected if there are problems. 1523*c77a61a7Syz */ 1524*c77a61a7Syz static void 1525*c77a61a7Syz usbvc_restore_device_state(dev_info_t *dip, usbvc_state_t *usbvcp) 1526*c77a61a7Syz { 1527*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1528*c77a61a7Syz "usbvc_restore_device_state: enter"); 1529*c77a61a7Syz 1530*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 1531*c77a61a7Syz 1532*c77a61a7Syz ASSERT((usbvcp->usbvc_dev_state == USB_DEV_DISCONNECTED) || 1533*c77a61a7Syz (usbvcp->usbvc_dev_state == USB_DEV_SUSPENDED)); 1534*c77a61a7Syz 1535*c77a61a7Syz usbvc_pm_busy_component(usbvcp); 1536*c77a61a7Syz usbvcp->usbvc_pm->usbvc_raise_power = B_TRUE; 1537*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1538*c77a61a7Syz (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1539*c77a61a7Syz 1540*c77a61a7Syz /* Check if we are talking to the same device */ 1541*c77a61a7Syz if (usb_check_same_device(dip, usbvcp->usbvc_log_handle, 1542*c77a61a7Syz USB_LOG_L0, PRINT_MASK_ALL, 1543*c77a61a7Syz USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) { 1544*c77a61a7Syz 1545*c77a61a7Syz goto fail; 1546*c77a61a7Syz } 1547*c77a61a7Syz 1548*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1549*c77a61a7Syz usbvcp->usbvc_pm->usbvc_raise_power = B_FALSE; 1550*c77a61a7Syz usbvcp->usbvc_dev_state = USB_DEV_ONLINE; 1551*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1552*c77a61a7Syz 1553*c77a61a7Syz if (usbvcp->usbvc_pm->usbvc_wakeup_enabled) { 1554*c77a61a7Syz 1555*c77a61a7Syz /* Failure here means device disappeared again. */ 1556*c77a61a7Syz if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) != 1557*c77a61a7Syz USB_SUCCESS) { 1558*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, 1559*c77a61a7Syz usbvcp->usbvc_log_handle, 1560*c77a61a7Syz "device may or may not be accessible. " 1561*c77a61a7Syz "Please verify reconnection"); 1562*c77a61a7Syz } 1563*c77a61a7Syz } 1564*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1565*c77a61a7Syz 1566*c77a61a7Syz usbvc_pm_idle_component(usbvcp); 1567*c77a61a7Syz 1568*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_PM, usbvcp->usbvc_log_handle, 1569*c77a61a7Syz "usbvc_restore_device_state: end"); 1570*c77a61a7Syz 1571*c77a61a7Syz return; 1572*c77a61a7Syz 1573*c77a61a7Syz fail: 1574*c77a61a7Syz /* change the device state from suspended to disconnected */ 1575*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1576*c77a61a7Syz usbvcp->usbvc_dev_state = USB_DEV_DISCONNECTED; 1577*c77a61a7Syz usbvc_pm_idle_component(usbvcp); 1578*c77a61a7Syz } 1579*c77a61a7Syz 1580*c77a61a7Syz 1581*c77a61a7Syz /* Events */ 1582*c77a61a7Syz 1583*c77a61a7Syz /* 1584*c77a61a7Syz * usbvc_disconnect_event_cb: 1585*c77a61a7Syz * Called when device hotplug-removed. 1586*c77a61a7Syz * Close pipes. (This does not attempt to contact device.) 1587*c77a61a7Syz * Set state to DISCONNECTED 1588*c77a61a7Syz */ 1589*c77a61a7Syz static int 1590*c77a61a7Syz usbvc_disconnect_event_cb(dev_info_t *dip) 1591*c77a61a7Syz { 1592*c77a61a7Syz int instance = ddi_get_instance(dip); 1593*c77a61a7Syz usbvc_state_t *usbvcp = 1594*c77a61a7Syz ddi_get_soft_state(usbvc_statep, instance); 1595*c77a61a7Syz 1596*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_HOTPLUG, usbvcp->usbvc_log_handle, 1597*c77a61a7Syz "disconnect: enter"); 1598*c77a61a7Syz 1599*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1600*c77a61a7Syz /* 1601*c77a61a7Syz * Save any state of device or IO in progress required by 1602*c77a61a7Syz * usbvc_restore_device_state for proper device "thawing" later. 1603*c77a61a7Syz */ 1604*c77a61a7Syz usbvcp->usbvc_dev_state = USB_DEV_DISCONNECTED; 1605*c77a61a7Syz 1606*c77a61a7Syz /* 1607*c77a61a7Syz * wake up the read threads in case there are any threads are blocking, 1608*c77a61a7Syz * after being waked up, those threads will quit fail immediately since 1609*c77a61a7Syz * we have changed the dev_stat. 1610*c77a61a7Syz */ 1611*c77a61a7Syz if (usbvcp->usbvc_io_type == V4L2_MEMORY_MMAP) { 1612*c77a61a7Syz cv_broadcast(&usbvcp->usbvc_mapio_cv); 1613*c77a61a7Syz } else { 1614*c77a61a7Syz cv_broadcast(&usbvcp->usbvc_read_cv); 1615*c77a61a7Syz } 1616*c77a61a7Syz /* Wait for the other threads to quit */ 1617*c77a61a7Syz (void) usbvc_serialize_access(usbvcp, USBVC_SER_SIG); 1618*c77a61a7Syz usbvc_release_access(usbvcp); 1619*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1620*c77a61a7Syz 1621*c77a61a7Syz return (USB_SUCCESS); 1622*c77a61a7Syz } 1623*c77a61a7Syz 1624*c77a61a7Syz 1625*c77a61a7Syz /* 1626*c77a61a7Syz * usbvc_reconnect_event_cb: 1627*c77a61a7Syz * Called with device hotplug-inserted 1628*c77a61a7Syz * Restore state 1629*c77a61a7Syz */ 1630*c77a61a7Syz static int 1631*c77a61a7Syz usbvc_reconnect_event_cb(dev_info_t *dip) 1632*c77a61a7Syz { 1633*c77a61a7Syz int instance = ddi_get_instance(dip); 1634*c77a61a7Syz usbvc_state_t *usbvcp = ddi_get_soft_state(usbvc_statep, instance); 1635*c77a61a7Syz 1636*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_HOTPLUG, usbvcp->usbvc_log_handle, 1637*c77a61a7Syz "reconnect: enter"); 1638*c77a61a7Syz 1639*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 1640*c77a61a7Syz (void) usbvc_serialize_access(usbvcp, USBVC_SER_SIG); 1641*c77a61a7Syz usbvc_restore_device_state(dip, usbvcp); 1642*c77a61a7Syz usbvc_release_access(usbvcp); 1643*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 1644*c77a61a7Syz 1645*c77a61a7Syz return (USB_SUCCESS); 1646*c77a61a7Syz } 1647*c77a61a7Syz 1648*c77a61a7Syz /* Sync objs and lists */ 1649*c77a61a7Syz 1650*c77a61a7Syz /* 1651*c77a61a7Syz * init/fini sync objects during attach 1652*c77a61a7Syz */ 1653*c77a61a7Syz static void 1654*c77a61a7Syz usbvc_init_sync_objs(usbvc_state_t *usbvcp) 1655*c77a61a7Syz { 1656*c77a61a7Syz mutex_init(&usbvcp->usbvc_mutex, NULL, MUTEX_DRIVER, 1657*c77a61a7Syz usbvcp->usbvc_reg->dev_iblock_cookie); 1658*c77a61a7Syz 1659*c77a61a7Syz cv_init(&usbvcp->usbvc_serial_cv, NULL, CV_DRIVER, NULL); 1660*c77a61a7Syz cv_init(&usbvcp->usbvc_read_cv, NULL, CV_DRIVER, NULL); 1661*c77a61a7Syz cv_init(&usbvcp->usbvc_mapio_cv, NULL, CV_DRIVER, NULL); 1662*c77a61a7Syz 1663*c77a61a7Syz usbvcp->usbvc_serial_inuse = B_FALSE; 1664*c77a61a7Syz 1665*c77a61a7Syz usbvcp->usbvc_locks_initialized = B_TRUE; 1666*c77a61a7Syz } 1667*c77a61a7Syz 1668*c77a61a7Syz 1669*c77a61a7Syz static void 1670*c77a61a7Syz usbvc_fini_sync_objs(usbvc_state_t *usbvcp) 1671*c77a61a7Syz { 1672*c77a61a7Syz cv_destroy(&usbvcp->usbvc_serial_cv); 1673*c77a61a7Syz cv_destroy(&usbvcp->usbvc_read_cv); 1674*c77a61a7Syz cv_destroy(&usbvcp->usbvc_mapio_cv); 1675*c77a61a7Syz 1676*c77a61a7Syz mutex_destroy(&usbvcp->usbvc_mutex); 1677*c77a61a7Syz } 1678*c77a61a7Syz 1679*c77a61a7Syz 1680*c77a61a7Syz static void 1681*c77a61a7Syz usbvc_init_lists(usbvc_state_t *usbvcp) 1682*c77a61a7Syz { 1683*c77a61a7Syz /* video terminals */ 1684*c77a61a7Syz list_create(&(usbvcp->usbvc_term_list), sizeof (usbvc_terms_t), 1685*c77a61a7Syz offsetof(usbvc_terms_t, term_node)); 1686*c77a61a7Syz 1687*c77a61a7Syz /* video units */ 1688*c77a61a7Syz list_create(&(usbvcp->usbvc_unit_list), sizeof (usbvc_units_t), 1689*c77a61a7Syz offsetof(usbvc_units_t, unit_node)); 1690*c77a61a7Syz 1691*c77a61a7Syz /* stream interfaces */ 1692*c77a61a7Syz list_create(&(usbvcp->usbvc_stream_list), sizeof (usbvc_stream_if_t), 1693*c77a61a7Syz offsetof(usbvc_stream_if_t, stream_if_node)); 1694*c77a61a7Syz } 1695*c77a61a7Syz 1696*c77a61a7Syz 1697*c77a61a7Syz /* 1698*c77a61a7Syz * Free all the data structures allocated when parsing descriptors of ctrl 1699*c77a61a7Syz * and stream interfaces. It is safe to call this function because it always 1700*c77a61a7Syz * checks the pointer before free mem. 1701*c77a61a7Syz */ 1702*c77a61a7Syz static void 1703*c77a61a7Syz usbvc_fini_lists(usbvc_state_t *usbvcp) 1704*c77a61a7Syz { 1705*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_CLOSE, usbvcp->usbvc_log_handle, 1706*c77a61a7Syz "usbvc_fini_lists: enter"); 1707*c77a61a7Syz 1708*c77a61a7Syz usbvc_free_ctrl_descr(usbvcp); 1709*c77a61a7Syz 1710*c77a61a7Syz /* Free all video stream structure and the sub-structures */ 1711*c77a61a7Syz usbvc_free_stream_descr(usbvcp); 1712*c77a61a7Syz 1713*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_CLOSE, usbvcp->usbvc_log_handle, 1714*c77a61a7Syz "usbvc_fini_lists: end"); 1715*c77a61a7Syz } 1716*c77a61a7Syz 1717*c77a61a7Syz 1718*c77a61a7Syz /* 1719*c77a61a7Syz * Free all the data structures allocated when parsing descriptors of ctrl 1720*c77a61a7Syz * interface. 1721*c77a61a7Syz */ 1722*c77a61a7Syz static void 1723*c77a61a7Syz usbvc_free_ctrl_descr(usbvc_state_t *usbvcp) 1724*c77a61a7Syz { 1725*c77a61a7Syz usbvc_terms_t *term; 1726*c77a61a7Syz usbvc_units_t *unit; 1727*c77a61a7Syz 1728*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_CLOSE, usbvcp->usbvc_log_handle, 1729*c77a61a7Syz "usbvc_free_ctrl_descr: enter"); 1730*c77a61a7Syz 1731*c77a61a7Syz if (usbvcp->usbvc_vc_header) { 1732*c77a61a7Syz kmem_free(usbvcp->usbvc_vc_header, sizeof (usbvc_vc_header_t)); 1733*c77a61a7Syz } 1734*c77a61a7Syz 1735*c77a61a7Syz /* Free all video terminal structure */ 1736*c77a61a7Syz while (!list_is_empty(&usbvcp->usbvc_term_list)) { 1737*c77a61a7Syz term = list_head(&usbvcp->usbvc_term_list); 1738*c77a61a7Syz if (term != NULL) { 1739*c77a61a7Syz list_remove(&(usbvcp->usbvc_term_list), term); 1740*c77a61a7Syz kmem_free(term, sizeof (usbvc_terms_t)); 1741*c77a61a7Syz } 1742*c77a61a7Syz } 1743*c77a61a7Syz 1744*c77a61a7Syz /* Free all video unit structure */ 1745*c77a61a7Syz while (!list_is_empty(&usbvcp->usbvc_unit_list)) { 1746*c77a61a7Syz unit = list_head(&usbvcp->usbvc_unit_list); 1747*c77a61a7Syz if (unit != NULL) { 1748*c77a61a7Syz list_remove(&(usbvcp->usbvc_unit_list), unit); 1749*c77a61a7Syz kmem_free(unit, sizeof (usbvc_units_t)); 1750*c77a61a7Syz } 1751*c77a61a7Syz } 1752*c77a61a7Syz } 1753*c77a61a7Syz 1754*c77a61a7Syz 1755*c77a61a7Syz /* 1756*c77a61a7Syz * Free all the data structures allocated when parsing descriptors of stream 1757*c77a61a7Syz * interfaces. 1758*c77a61a7Syz */ 1759*c77a61a7Syz static void 1760*c77a61a7Syz usbvc_free_stream_descr(usbvc_state_t *usbvcp) 1761*c77a61a7Syz { 1762*c77a61a7Syz usbvc_stream_if_t *strm; 1763*c77a61a7Syz usbvc_input_header_t *in_hdr; 1764*c77a61a7Syz usbvc_output_header_t *out_hdr; 1765*c77a61a7Syz uint8_t fmt_cnt, frm_cnt; 1766*c77a61a7Syz 1767*c77a61a7Syz while (!list_is_empty(&usbvcp->usbvc_stream_list)) { 1768*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbvcp->usbvc_log_handle, 1769*c77a61a7Syz "usbvc_fini_lists: stream list not empty."); 1770*c77a61a7Syz 1771*c77a61a7Syz strm = list_head(&usbvcp->usbvc_stream_list); 1772*c77a61a7Syz if (strm != NULL) { 1773*c77a61a7Syz 1774*c77a61a7Syz /* unlink this stream's data structure from the list */ 1775*c77a61a7Syz list_remove(&(usbvcp->usbvc_stream_list), strm); 1776*c77a61a7Syz } else { 1777*c77a61a7Syz 1778*c77a61a7Syz /* No real stream data structure in the list */ 1779*c77a61a7Syz return; 1780*c77a61a7Syz } 1781*c77a61a7Syz 1782*c77a61a7Syz in_hdr = strm->input_header; 1783*c77a61a7Syz out_hdr = strm->output_header; 1784*c77a61a7Syz 1785*c77a61a7Syz if (in_hdr) { 1786*c77a61a7Syz fmt_cnt = in_hdr->descr->bNumFormats; 1787*c77a61a7Syz } else if (out_hdr) { 1788*c77a61a7Syz fmt_cnt = out_hdr->descr->bNumFormats; 1789*c77a61a7Syz } 1790*c77a61a7Syz 1791*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CLOSE, 1792*c77a61a7Syz usbvcp->usbvc_log_handle, "usbvc_fini_lists:" 1793*c77a61a7Syz " fmtgrp cnt=%d", fmt_cnt); 1794*c77a61a7Syz 1795*c77a61a7Syz /* Free headers */ 1796*c77a61a7Syz if (in_hdr) { 1797*c77a61a7Syz kmem_free(in_hdr, sizeof (usbvc_input_header_t)); 1798*c77a61a7Syz } 1799*c77a61a7Syz if (out_hdr) { 1800*c77a61a7Syz kmem_free(out_hdr, sizeof (usbvc_output_header_t)); 1801*c77a61a7Syz } 1802*c77a61a7Syz 1803*c77a61a7Syz /* Free format descriptors */ 1804*c77a61a7Syz if (strm->format_group) { 1805*c77a61a7Syz int i; 1806*c77a61a7Syz usbvc_format_group_t *fmtgrp; 1807*c77a61a7Syz 1808*c77a61a7Syz for (i = 0; i < fmt_cnt; i++) { 1809*c77a61a7Syz fmtgrp = &strm->format_group[i]; 1810*c77a61a7Syz if (fmtgrp->format == NULL) { 1811*c77a61a7Syz 1812*c77a61a7Syz break; 1813*c77a61a7Syz } 1814*c77a61a7Syz if (fmtgrp->still) { 1815*c77a61a7Syz kmem_free(fmtgrp->still, 1816*c77a61a7Syz sizeof (usbvc_still_image_frame_t)); 1817*c77a61a7Syz } 1818*c77a61a7Syz frm_cnt = fmtgrp->format->bNumFrameDescriptors; 1819*c77a61a7Syz 1820*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CLOSE, 1821*c77a61a7Syz usbvcp->usbvc_log_handle, 1822*c77a61a7Syz "usbvc_fini_lists:" 1823*c77a61a7Syz " frame cnt=%d", frm_cnt); 1824*c77a61a7Syz 1825*c77a61a7Syz if (fmtgrp->frames) { 1826*c77a61a7Syz kmem_free(fmtgrp->frames, 1827*c77a61a7Syz sizeof (usbvc_frames_t) * frm_cnt); 1828*c77a61a7Syz } 1829*c77a61a7Syz } 1830*c77a61a7Syz kmem_free(strm->format_group, 1831*c77a61a7Syz sizeof (usbvc_format_group_t) * fmt_cnt); 1832*c77a61a7Syz } 1833*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CLOSE, 1834*c77a61a7Syz usbvcp->usbvc_log_handle, "usbvc_fini_lists:" 1835*c77a61a7Syz " free stream_if_t"); 1836*c77a61a7Syz 1837*c77a61a7Syz kmem_free(strm, sizeof (usbvc_stream_if_t)); 1838*c77a61a7Syz } 1839*c77a61a7Syz } 1840*c77a61a7Syz 1841*c77a61a7Syz /* 1842*c77a61a7Syz * Parse class specific descriptors of the video device 1843*c77a61a7Syz */ 1844*c77a61a7Syz 1845*c77a61a7Syz /* 1846*c77a61a7Syz * Check the length of a class specific descriptor. Make sure cvs_buf_len is 1847*c77a61a7Syz * not less than the length expected according to uvc spec. 1848*c77a61a7Syz * 1849*c77a61a7Syz * Args: 1850*c77a61a7Syz * - off_num: the cvs_buf offset of the descriptor element that 1851*c77a61a7Syz * indicates the number of variable descriptor elements; 1852*c77a61a7Syz * - size: the size of each variable descriptor element, if zero, then the 1853*c77a61a7Syz * size value is offered by off_size; 1854*c77a61a7Syz * - off_size: the cvs_buf offset of the descriptor element that indicates 1855*c77a61a7Syz * the size of each variable descriptor element; 1856*c77a61a7Syz */ 1857*c77a61a7Syz static int 1858*c77a61a7Syz usbvc_chk_descr_len(uint8_t off_num, uint8_t size, uint8_t off_size, 1859*c77a61a7Syz usb_cvs_data_t *cvs_data) 1860*c77a61a7Syz { 1861*c77a61a7Syz uchar_t *cvs_buf; 1862*c77a61a7Syz uint_t cvs_buf_len; 1863*c77a61a7Syz 1864*c77a61a7Syz cvs_buf = cvs_data->cvs_buf; 1865*c77a61a7Syz cvs_buf_len = cvs_data->cvs_buf_len; 1866*c77a61a7Syz 1867*c77a61a7Syz if (size == 0) { 1868*c77a61a7Syz if (cvs_buf_len > off_size) { 1869*c77a61a7Syz size = cvs_buf[off_size]; 1870*c77a61a7Syz } else { 1871*c77a61a7Syz 1872*c77a61a7Syz return (USB_FAILURE); 1873*c77a61a7Syz } 1874*c77a61a7Syz } 1875*c77a61a7Syz if (cvs_buf_len < (off_num + 1)) { 1876*c77a61a7Syz 1877*c77a61a7Syz return (USB_FAILURE); 1878*c77a61a7Syz } 1879*c77a61a7Syz 1880*c77a61a7Syz if (cvs_buf_len < (cvs_buf[off_num] * size + off_num +1)) { 1881*c77a61a7Syz 1882*c77a61a7Syz return (USB_FAILURE); 1883*c77a61a7Syz } 1884*c77a61a7Syz 1885*c77a61a7Syz return (USB_SUCCESS); 1886*c77a61a7Syz } 1887*c77a61a7Syz 1888*c77a61a7Syz 1889*c77a61a7Syz /* Parse the descriptors of control interface */ 1890*c77a61a7Syz static int 1891*c77a61a7Syz usbvc_parse_ctrl_if(usbvc_state_t *usbvcp) 1892*c77a61a7Syz { 1893*c77a61a7Syz int if_num; 1894*c77a61a7Syz int cvs_num; 1895*c77a61a7Syz usb_alt_if_data_t *if_alt_data; 1896*c77a61a7Syz usb_cvs_data_t *cvs_data; 1897*c77a61a7Syz uchar_t *cvs_buf; 1898*c77a61a7Syz uint_t cvs_buf_len; 1899*c77a61a7Syz uint16_t version; 1900*c77a61a7Syz 1901*c77a61a7Syz if_num = usbvcp->usbvc_reg->dev_curr_if; 1902*c77a61a7Syz if_alt_data = usbvcp->usbvc_reg->dev_curr_cfg->cfg_if[if_num].if_alt; 1903*c77a61a7Syz cvs_data = if_alt_data->altif_cvs; 1904*c77a61a7Syz 1905*c77a61a7Syz for (cvs_num = 0; cvs_num < if_alt_data->altif_n_cvs; cvs_num++) { 1906*c77a61a7Syz cvs_buf = cvs_data[cvs_num].cvs_buf; 1907*c77a61a7Syz cvs_buf_len = cvs_data[cvs_num].cvs_buf_len; 1908*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 1909*c77a61a7Syz "usbvc_parse_ctrl_if: cvs_num= %d, cvs_buf_len=%d", 1910*c77a61a7Syz cvs_num, cvs_buf_len); 1911*c77a61a7Syz 1912*c77a61a7Syz /* 1913*c77a61a7Syz * parse interface cvs descriptors here; by checking 1914*c77a61a7Syz * bDescriptorType (cvs_buf[1]) 1915*c77a61a7Syz */ 1916*c77a61a7Syz if (cvs_buf[1] != CS_INTERFACE) { 1917*c77a61a7Syz 1918*c77a61a7Syz continue; 1919*c77a61a7Syz } 1920*c77a61a7Syz 1921*c77a61a7Syz /* 1922*c77a61a7Syz * Different descriptors in VC interface; according to 1923*c77a61a7Syz * bDescriptorSubType (cvs_buf[2]) 1924*c77a61a7Syz */ 1925*c77a61a7Syz switch (cvs_buf[2]) { 1926*c77a61a7Syz case VC_HEADER: 1927*c77a61a7Syz 1928*c77a61a7Syz /* 1929*c77a61a7Syz * According to uvc spec, there must be one and only 1930*c77a61a7Syz * be one header. If more than one, return failure. 1931*c77a61a7Syz */ 1932*c77a61a7Syz if (usbvcp->usbvc_vc_header) { 1933*c77a61a7Syz 1934*c77a61a7Syz return (USB_FAILURE); 1935*c77a61a7Syz } 1936*c77a61a7Syz /* 1937*c77a61a7Syz * Check if it is a valid HEADER descriptor in case of 1938*c77a61a7Syz * a device not compliant to uvc spec. This descriptor 1939*c77a61a7Syz * is critical, return failure if not a valid one. 1940*c77a61a7Syz */ 1941*c77a61a7Syz if (usbvc_chk_descr_len(11, 1, 0, cvs_data) != 1942*c77a61a7Syz USB_SUCCESS) { 1943*c77a61a7Syz 1944*c77a61a7Syz return (USB_FAILURE); 1945*c77a61a7Syz } 1946*c77a61a7Syz usbvcp->usbvc_vc_header = 1947*c77a61a7Syz (usbvc_vc_header_t *)kmem_zalloc( 1948*c77a61a7Syz sizeof (usbvc_vc_header_t), KM_SLEEP); 1949*c77a61a7Syz usbvcp->usbvc_vc_header->descr = 1950*c77a61a7Syz (usbvc_vc_header_descr_t *)&cvs_buf[0]; 1951*c77a61a7Syz 1952*c77a61a7Syz LE_TO_UINT16(usbvcp->usbvc_vc_header->descr->bcdUVC, 1953*c77a61a7Syz 0, version); 1954*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, 1955*c77a61a7Syz usbvcp->usbvc_log_handle, "usbvc_parse_ctrl_if:" 1956*c77a61a7Syz " VC header, bcdUVC=%x", version); 1957*c77a61a7Syz if (usbvcp->usbvc_vc_header->descr->bInCollection == 1958*c77a61a7Syz 0) { 1959*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, 1960*c77a61a7Syz usbvcp->usbvc_log_handle, 1961*c77a61a7Syz "usbvc_parse_ctrl_if: no strm interfaces"); 1962*c77a61a7Syz 1963*c77a61a7Syz break; 1964*c77a61a7Syz } 1965*c77a61a7Syz 1966*c77a61a7Syz /* stream interface numbers */ 1967*c77a61a7Syz usbvcp->usbvc_vc_header->baInterfaceNr = &cvs_buf[12]; 1968*c77a61a7Syz 1969*c77a61a7Syz break; 1970*c77a61a7Syz case VC_INPUT_TERMINAL: 1971*c77a61a7Syz { 1972*c77a61a7Syz usbvc_terms_t *term; 1973*c77a61a7Syz 1974*c77a61a7Syz /* 1975*c77a61a7Syz * Check if it is a valid descriptor in case of a 1976*c77a61a7Syz * device not compliant to uvc spec 1977*c77a61a7Syz */ 1978*c77a61a7Syz if (cvs_buf_len < USBVC_I_TERM_LEN_MIN) { 1979*c77a61a7Syz 1980*c77a61a7Syz break; 1981*c77a61a7Syz } 1982*c77a61a7Syz term = (usbvc_terms_t *) 1983*c77a61a7Syz kmem_zalloc(sizeof (usbvc_terms_t), KM_SLEEP); 1984*c77a61a7Syz term->descr = (usbvc_term_descr_t *)cvs_buf; 1985*c77a61a7Syz 1986*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, 1987*c77a61a7Syz usbvcp->usbvc_log_handle, "usbvc_parse_ctrl_if: " 1988*c77a61a7Syz "input term type=%x", term->descr->wTerminalType); 1989*c77a61a7Syz if (term->descr->wTerminalType == ITT_CAMERA) { 1990*c77a61a7Syz if (usbvc_chk_descr_len(14, 1, 0, cvs_data) != 1991*c77a61a7Syz USB_SUCCESS) { 1992*c77a61a7Syz kmem_free(term, sizeof (usbvc_terms_t)); 1993*c77a61a7Syz 1994*c77a61a7Syz break; 1995*c77a61a7Syz } 1996*c77a61a7Syz term->bmControls = &cvs_buf[15]; 1997*c77a61a7Syz } else if (cvs_buf_len > 8) { /* other input terms */ 1998*c77a61a7Syz term->bSpecific = &cvs_buf[8]; 1999*c77a61a7Syz } 2000*c77a61a7Syz list_insert_tail(&(usbvcp->usbvc_term_list), term); 2001*c77a61a7Syz 2002*c77a61a7Syz break; 2003*c77a61a7Syz } 2004*c77a61a7Syz case VC_OUTPUT_TERMINAL: 2005*c77a61a7Syz { 2006*c77a61a7Syz usbvc_terms_t *term; 2007*c77a61a7Syz 2008*c77a61a7Syz if (cvs_buf_len < USBVC_O_TERM_LEN_MIN) { 2009*c77a61a7Syz 2010*c77a61a7Syz break; 2011*c77a61a7Syz } 2012*c77a61a7Syz term = (usbvc_terms_t *) 2013*c77a61a7Syz kmem_zalloc(sizeof (usbvc_terms_t), KM_SLEEP); 2014*c77a61a7Syz term->descr = (usbvc_term_descr_t *)cvs_buf; 2015*c77a61a7Syz 2016*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, 2017*c77a61a7Syz usbvcp->usbvc_log_handle, "usbvc_parse_ctrl_if:" 2018*c77a61a7Syz " output term id= %x", term->descr->bTerminalID); 2019*c77a61a7Syz if (cvs_buf_len > 9) { 2020*c77a61a7Syz term->bSpecific = &cvs_buf[9]; 2021*c77a61a7Syz } 2022*c77a61a7Syz list_insert_tail(&(usbvcp->usbvc_term_list), term); 2023*c77a61a7Syz 2024*c77a61a7Syz break; 2025*c77a61a7Syz } 2026*c77a61a7Syz case VC_PROCESSING_UNIT: 2027*c77a61a7Syz { 2028*c77a61a7Syz uint8_t sz; 2029*c77a61a7Syz usbvc_units_t *unit; 2030*c77a61a7Syz 2031*c77a61a7Syz if (usbvc_chk_descr_len(7, 1, 0, cvs_data) != 2032*c77a61a7Syz USB_SUCCESS) { 2033*c77a61a7Syz 2034*c77a61a7Syz break; 2035*c77a61a7Syz } 2036*c77a61a7Syz 2037*c77a61a7Syz /* bControlSize */ 2038*c77a61a7Syz sz = cvs_buf[7]; 2039*c77a61a7Syz 2040*c77a61a7Syz if ((sz + 8) >= cvs_buf_len) { 2041*c77a61a7Syz 2042*c77a61a7Syz break; 2043*c77a61a7Syz } 2044*c77a61a7Syz unit = (usbvc_units_t *) 2045*c77a61a7Syz kmem_zalloc(sizeof (usbvc_units_t), KM_SLEEP); 2046*c77a61a7Syz 2047*c77a61a7Syz unit->descr = (usbvc_unit_descr_t *)cvs_buf; 2048*c77a61a7Syz 2049*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, 2050*c77a61a7Syz usbvcp->usbvc_log_handle, "usbvc_parse_ctrl_if: " 2051*c77a61a7Syz "unit type=%x", unit->descr->bDescriptorSubType); 2052*c77a61a7Syz 2053*c77a61a7Syz if (sz != 0) { 2054*c77a61a7Syz unit->bmControls = &cvs_buf[8]; 2055*c77a61a7Syz } 2056*c77a61a7Syz unit->iProcessing = cvs_buf[8 + sz]; 2057*c77a61a7Syz 2058*c77a61a7Syz /* 2059*c77a61a7Syz * video class 1.1 version add one element 2060*c77a61a7Syz * (bmVideoStandards) to processing unit descriptor 2061*c77a61a7Syz */ 2062*c77a61a7Syz if (cvs_buf_len > (9 + sz)) { 2063*c77a61a7Syz unit->bmVideoStandards = cvs_buf[9 + sz]; 2064*c77a61a7Syz } 2065*c77a61a7Syz list_insert_tail(&(usbvcp->usbvc_unit_list), unit); 2066*c77a61a7Syz 2067*c77a61a7Syz break; 2068*c77a61a7Syz } 2069*c77a61a7Syz case VC_SELECTOR_UNIT: 2070*c77a61a7Syz { 2071*c77a61a7Syz uint8_t pins; 2072*c77a61a7Syz usbvc_units_t *unit; 2073*c77a61a7Syz 2074*c77a61a7Syz if (usbvc_chk_descr_len(4, 1, 0, cvs_data) != 2075*c77a61a7Syz USB_SUCCESS) { 2076*c77a61a7Syz 2077*c77a61a7Syz break; 2078*c77a61a7Syz } 2079*c77a61a7Syz pins = cvs_buf[4]; 2080*c77a61a7Syz if ((pins + 5) >= cvs_buf_len) { 2081*c77a61a7Syz 2082*c77a61a7Syz break; 2083*c77a61a7Syz } 2084*c77a61a7Syz unit = (usbvc_units_t *) 2085*c77a61a7Syz kmem_zalloc(sizeof (usbvc_units_t), KM_SLEEP); 2086*c77a61a7Syz 2087*c77a61a7Syz unit->descr = (usbvc_unit_descr_t *)cvs_buf; 2088*c77a61a7Syz 2089*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, 2090*c77a61a7Syz usbvcp->usbvc_log_handle, "usbvc_parse_ctrl_if: " 2091*c77a61a7Syz "unit type=%x", unit->descr->bDescriptorSubType); 2092*c77a61a7Syz if (pins > 0) { 2093*c77a61a7Syz unit->baSourceID = &cvs_buf[5]; 2094*c77a61a7Syz } 2095*c77a61a7Syz unit->iSelector = cvs_buf[5 + pins]; 2096*c77a61a7Syz 2097*c77a61a7Syz list_insert_tail(&(usbvcp->usbvc_unit_list), unit); 2098*c77a61a7Syz 2099*c77a61a7Syz break; 2100*c77a61a7Syz } 2101*c77a61a7Syz case VC_EXTENSION_UNIT: 2102*c77a61a7Syz { 2103*c77a61a7Syz uint8_t pins, n; 2104*c77a61a7Syz usbvc_units_t *unit; 2105*c77a61a7Syz 2106*c77a61a7Syz if (usbvc_chk_descr_len(21, 1, 0, cvs_data) != 2107*c77a61a7Syz USB_SUCCESS) { 2108*c77a61a7Syz 2109*c77a61a7Syz break; 2110*c77a61a7Syz } 2111*c77a61a7Syz pins = cvs_buf[21]; 2112*c77a61a7Syz if ((pins + 22) >= cvs_buf_len) { 2113*c77a61a7Syz 2114*c77a61a7Syz break; 2115*c77a61a7Syz } 2116*c77a61a7Syz 2117*c77a61a7Syz /* Size of bmControls */ 2118*c77a61a7Syz n = cvs_buf[pins + 22]; 2119*c77a61a7Syz 2120*c77a61a7Syz if (usbvc_chk_descr_len(pins + 22, 1, 0, cvs_data) != 2121*c77a61a7Syz USB_SUCCESS) { 2122*c77a61a7Syz 2123*c77a61a7Syz break; 2124*c77a61a7Syz } 2125*c77a61a7Syz if ((23 + pins + n) >= cvs_buf_len) { 2126*c77a61a7Syz 2127*c77a61a7Syz break; 2128*c77a61a7Syz } 2129*c77a61a7Syz unit = (usbvc_units_t *) 2130*c77a61a7Syz kmem_zalloc(sizeof (usbvc_units_t), KM_SLEEP); 2131*c77a61a7Syz 2132*c77a61a7Syz unit->descr = (usbvc_unit_descr_t *)cvs_buf; 2133*c77a61a7Syz 2134*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, 2135*c77a61a7Syz usbvcp->usbvc_log_handle, "usbvc_parse_ctrl_if: " 2136*c77a61a7Syz "unit type=%x", unit->descr->bDescriptorSubType); 2137*c77a61a7Syz if (pins != 0) { 2138*c77a61a7Syz unit->baSourceID = &cvs_buf[22]; 2139*c77a61a7Syz } 2140*c77a61a7Syz unit->bControlSize = cvs_buf[22 + pins]; 2141*c77a61a7Syz 2142*c77a61a7Syz if (unit->bControlSize != 0) { 2143*c77a61a7Syz unit->bmControls = &cvs_buf[23 + pins]; 2144*c77a61a7Syz } 2145*c77a61a7Syz unit->iExtension = cvs_buf[23 + pins + n]; 2146*c77a61a7Syz 2147*c77a61a7Syz list_insert_tail(&(usbvcp->usbvc_unit_list), unit); 2148*c77a61a7Syz 2149*c77a61a7Syz break; 2150*c77a61a7Syz } 2151*c77a61a7Syz default: 2152*c77a61a7Syz 2153*c77a61a7Syz break; 2154*c77a61a7Syz } 2155*c77a61a7Syz } 2156*c77a61a7Syz 2157*c77a61a7Syz return (USB_SUCCESS); 2158*c77a61a7Syz } 2159*c77a61a7Syz 2160*c77a61a7Syz 2161*c77a61a7Syz /* Parse all the cvs descriptors in one stream interface. */ 2162*c77a61a7Syz usbvc_stream_if_t * 2163*c77a61a7Syz usbvc_parse_stream_if(usbvc_state_t *usbvcp, int if_num) 2164*c77a61a7Syz { 2165*c77a61a7Syz usb_alt_if_data_t *if_alt_data; 2166*c77a61a7Syz uint_t i, j; 2167*c77a61a7Syz usbvc_stream_if_t *strm_if; 2168*c77a61a7Syz uint16_t pktsize; 2169*c77a61a7Syz uint8_t ep_adr; 2170*c77a61a7Syz 2171*c77a61a7Syz strm_if = (usbvc_stream_if_t *)kmem_zalloc(sizeof (usbvc_stream_if_t), 2172*c77a61a7Syz KM_SLEEP); 2173*c77a61a7Syz strm_if->if_descr = &usbvcp->usbvc_reg->dev_curr_cfg->cfg_if[if_num]; 2174*c77a61a7Syz if_alt_data = strm_if->if_descr->if_alt; 2175*c77a61a7Syz if (usbvc_parse_stream_header(usbvcp, strm_if) != USB_SUCCESS) { 2176*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2177*c77a61a7Syz "usbvc_parse_stream_if: parse header fail"); 2178*c77a61a7Syz kmem_free(strm_if, sizeof (usbvc_stream_if_t)); 2179*c77a61a7Syz 2180*c77a61a7Syz return (NULL); 2181*c77a61a7Syz } 2182*c77a61a7Syz if (usbvc_parse_format_groups(usbvcp, strm_if) != USB_SUCCESS) { 2183*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2184*c77a61a7Syz "usbvc_parse_stream_if: parse groups fail"); 2185*c77a61a7Syz kmem_free(strm_if, sizeof (usbvc_stream_if_t)); 2186*c77a61a7Syz 2187*c77a61a7Syz return (NULL); 2188*c77a61a7Syz } 2189*c77a61a7Syz 2190*c77a61a7Syz /* Parse the alternate settings to find the maximum bandwidth. */ 2191*c77a61a7Syz for (i = 0; i < strm_if->if_descr->if_n_alt; i++) { 2192*c77a61a7Syz if_alt_data = &strm_if->if_descr->if_alt[i]; 2193*c77a61a7Syz for (j = 0; j < if_alt_data->altif_n_ep; j++) { 2194*c77a61a7Syz ep_adr = 2195*c77a61a7Syz if_alt_data->altif_ep[j].ep_descr.bEndpointAddress; 2196*c77a61a7Syz if (strm_if->input_header != NULL && 2197*c77a61a7Syz ep_adr != 2198*c77a61a7Syz strm_if->input_header->descr->bEndpointAddress) { 2199*c77a61a7Syz 2200*c77a61a7Syz continue; 2201*c77a61a7Syz } 2202*c77a61a7Syz if (strm_if->output_header != NULL && 2203*c77a61a7Syz ep_adr != 2204*c77a61a7Syz strm_if->output_header->descr->bEndpointAddress) { 2205*c77a61a7Syz 2206*c77a61a7Syz continue; 2207*c77a61a7Syz } 2208*c77a61a7Syz pktsize = 2209*c77a61a7Syz if_alt_data->altif_ep[j].ep_descr.wMaxPacketSize; 2210*c77a61a7Syz pktsize = HS_PKT_SIZE(pktsize); 2211*c77a61a7Syz if (pktsize > strm_if->max_isoc_payload) { 2212*c77a61a7Syz strm_if->max_isoc_payload = pktsize; 2213*c77a61a7Syz } 2214*c77a61a7Syz } 2215*c77a61a7Syz } 2216*c77a61a7Syz 2217*c77a61a7Syz /* initialize MJPEC FID toggle */ 2218*c77a61a7Syz strm_if->fid = 0xff; 2219*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2220*c77a61a7Syz "usbvc_parse_stream_if: return. max_isoc_payload=%x", 2221*c77a61a7Syz strm_if->max_isoc_payload); 2222*c77a61a7Syz 2223*c77a61a7Syz return (strm_if); 2224*c77a61a7Syz } 2225*c77a61a7Syz 2226*c77a61a7Syz 2227*c77a61a7Syz /* 2228*c77a61a7Syz * Parse all the stream interfaces asociated with the video control interface. 2229*c77a61a7Syz * This driver will attach to a video control interface on the device, 2230*c77a61a7Syz * there might be multiple video stream interfaces associated with one video 2231*c77a61a7Syz * control interface. 2232*c77a61a7Syz */ 2233*c77a61a7Syz static int 2234*c77a61a7Syz usbvc_parse_stream_ifs(usbvc_state_t *usbvcp) 2235*c77a61a7Syz { 2236*c77a61a7Syz int i, if_cnt, if_num; 2237*c77a61a7Syz usbvc_stream_if_t *strm_if; 2238*c77a61a7Syz 2239*c77a61a7Syz if_cnt = usbvcp->usbvc_vc_header->descr->bInCollection; 2240*c77a61a7Syz if (if_cnt == 0) { 2241*c77a61a7Syz ASSERT(list_is_empty(&usbvcp->usbvc_stream_list)); 2242*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2243*c77a61a7Syz "usbvc_parse_stream_ifs: no stream interfaces"); 2244*c77a61a7Syz 2245*c77a61a7Syz return (USB_SUCCESS); 2246*c77a61a7Syz } 2247*c77a61a7Syz for (i = 0; i < if_cnt; i++) { 2248*c77a61a7Syz if_num = usbvcp->usbvc_vc_header->baInterfaceNr[i]; 2249*c77a61a7Syz strm_if = usbvc_parse_stream_if(usbvcp, if_num); 2250*c77a61a7Syz if (strm_if == NULL) { 2251*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, 2252*c77a61a7Syz usbvcp->usbvc_log_handle, "usbvc_parse_stream_ifs:" 2253*c77a61a7Syz " parse stream interface %d failed.", if_num); 2254*c77a61a7Syz 2255*c77a61a7Syz return (USB_FAILURE); 2256*c77a61a7Syz } 2257*c77a61a7Syz /* video data buffers */ 2258*c77a61a7Syz list_create(&(strm_if->buf_map.uv_buf_free), 2259*c77a61a7Syz sizeof (usbvc_buf_t), offsetof(usbvc_buf_t, buf_node)); 2260*c77a61a7Syz list_create(&(strm_if->buf_map.uv_buf_done), 2261*c77a61a7Syz sizeof (usbvc_buf_t), offsetof(usbvc_buf_t, buf_node)); 2262*c77a61a7Syz list_create(&(strm_if->buf_read.uv_buf_free), 2263*c77a61a7Syz sizeof (usbvc_buf_t), offsetof(usbvc_buf_t, buf_node)); 2264*c77a61a7Syz list_create(&(strm_if->buf_read.uv_buf_done), 2265*c77a61a7Syz sizeof (usbvc_buf_t), offsetof(usbvc_buf_t, buf_node)); 2266*c77a61a7Syz 2267*c77a61a7Syz list_insert_tail(&(usbvcp->usbvc_stream_list), strm_if); 2268*c77a61a7Syz } 2269*c77a61a7Syz 2270*c77a61a7Syz /* Make the first stream interface as the default one. */ 2271*c77a61a7Syz usbvcp->usbvc_curr_strm = 2272*c77a61a7Syz (usbvc_stream_if_t *)list_head(&usbvcp->usbvc_stream_list); 2273*c77a61a7Syz 2274*c77a61a7Syz return (USB_SUCCESS); 2275*c77a61a7Syz } 2276*c77a61a7Syz 2277*c77a61a7Syz 2278*c77a61a7Syz /* 2279*c77a61a7Syz * Parse colorspace descriptor and still image descriptor of a format group. 2280*c77a61a7Syz * There is only one colorspace or still image descriptor in one format group. 2281*c77a61a7Syz */ 2282*c77a61a7Syz static void 2283*c77a61a7Syz usbvc_parse_color_still(usbvc_state_t *usbvcp, usbvc_format_group_t *fmtgrp, 2284*c77a61a7Syz usb_cvs_data_t *cvs_data, uint_t cvs_num, uint_t altif_n_cvs) 2285*c77a61a7Syz { 2286*c77a61a7Syz uint8_t frame_cnt; 2287*c77a61a7Syz uint_t last_frame, i; 2288*c77a61a7Syz uchar_t *cvs_buf; 2289*c77a61a7Syz uint_t cvs_buf_len; 2290*c77a61a7Syz 2291*c77a61a7Syz frame_cnt = fmtgrp->format->bNumFrameDescriptors; 2292*c77a61a7Syz last_frame = frame_cnt + cvs_num; 2293*c77a61a7Syz 2294*c77a61a7Syz /* 2295*c77a61a7Syz * Find the still image descr and color format descr if there are any. 2296*c77a61a7Syz * UVC Spec: only one still image and one color descr is allowed in 2297*c77a61a7Syz * one format group. 2298*c77a61a7Syz */ 2299*c77a61a7Syz for (i = 1; i <= 2; i++) { 2300*c77a61a7Syz if ((last_frame + i) >= altif_n_cvs) { 2301*c77a61a7Syz 2302*c77a61a7Syz break; 2303*c77a61a7Syz } 2304*c77a61a7Syz cvs_buf = cvs_data[last_frame + i].cvs_buf; 2305*c77a61a7Syz cvs_buf_len = cvs_data[last_frame + i].cvs_buf_len; 2306*c77a61a7Syz 2307*c77a61a7Syz if (cvs_buf[2] == VS_STILL_IMAGE_FRAME) { 2308*c77a61a7Syz uint8_t m, n, off; 2309*c77a61a7Syz usbvc_still_image_frame_t *st; 2310*c77a61a7Syz 2311*c77a61a7Syz if (usbvc_chk_descr_len(4, 4, 0, cvs_data) != 2312*c77a61a7Syz USB_SUCCESS) { 2313*c77a61a7Syz 2314*c77a61a7Syz continue; 2315*c77a61a7Syz } 2316*c77a61a7Syz 2317*c77a61a7Syz /* Number of Image Size patterns of this format */ 2318*c77a61a7Syz n = cvs_buf[4]; 2319*c77a61a7Syz 2320*c77a61a7Syz /* offset of bNumCompressionPattern */ 2321*c77a61a7Syz off = 9 + 4 * n -4; 2322*c77a61a7Syz 2323*c77a61a7Syz if (off >= cvs_buf_len) { 2324*c77a61a7Syz 2325*c77a61a7Syz continue; 2326*c77a61a7Syz } 2327*c77a61a7Syz 2328*c77a61a7Syz /* Number of compression pattern of this format */ 2329*c77a61a7Syz m = cvs_buf[off]; 2330*c77a61a7Syz 2331*c77a61a7Syz if (usbvc_chk_descr_len(m, 1, 0, cvs_data) != 2332*c77a61a7Syz USB_SUCCESS) { 2333*c77a61a7Syz 2334*c77a61a7Syz continue; 2335*c77a61a7Syz } 2336*c77a61a7Syz fmtgrp->still = (usbvc_still_image_frame_t *) 2337*c77a61a7Syz kmem_zalloc(sizeof (usbvc_still_image_frame_t), 2338*c77a61a7Syz KM_SLEEP); 2339*c77a61a7Syz st = fmtgrp->still; 2340*c77a61a7Syz st->descr = (usbvc_still_image_frame_descr_t *)cvs_buf; 2341*c77a61a7Syz n = st->descr->bNumImageSizePatterns; 2342*c77a61a7Syz if (n > 0) { 2343*c77a61a7Syz st->width_height = 2344*c77a61a7Syz (width_height_t *)&cvs_buf[5]; 2345*c77a61a7Syz } 2346*c77a61a7Syz st->bNumCompressionPattern = cvs_buf[off]; 2347*c77a61a7Syz if (cvs_buf[off] > 0) { 2348*c77a61a7Syz st->bCompression = &cvs_buf[off + 1]; 2349*c77a61a7Syz } 2350*c77a61a7Syz } 2351*c77a61a7Syz if (cvs_buf[2] == VS_COLORFORMAT) { 2352*c77a61a7Syz fmtgrp->color = (usbvc_color_matching_descr_t *)cvs_buf; 2353*c77a61a7Syz fmtgrp->v4l2_color = usbvc_v4l2_colorspace( 2354*c77a61a7Syz fmtgrp->color->bColorPrimaries); 2355*c77a61a7Syz } 2356*c77a61a7Syz } 2357*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2358*c77a61a7Syz "usbvc_parse_color_still: still=%p, color=%p", 2359*c77a61a7Syz fmtgrp->still, fmtgrp->color); 2360*c77a61a7Syz } 2361*c77a61a7Syz 2362*c77a61a7Syz 2363*c77a61a7Syz /* 2364*c77a61a7Syz * Parse frame descriptors of a format group. There might be multi frame 2365*c77a61a7Syz * descriptors in one format group. 2366*c77a61a7Syz */ 2367*c77a61a7Syz static void 2368*c77a61a7Syz usbvc_parse_frames(usbvc_state_t *usbvcp, usbvc_format_group_t *fmtgrp, 2369*c77a61a7Syz usb_cvs_data_t *cvs_data, uint_t cvs_num, uint_t altif_n_cvs) 2370*c77a61a7Syz { 2371*c77a61a7Syz uint_t last_frame; 2372*c77a61a7Syz usbvc_frames_t *frm; 2373*c77a61a7Syz usb_cvs_data_t *cvs; 2374*c77a61a7Syz uchar_t *cvs_buf; 2375*c77a61a7Syz uint_t cvs_buf_len; 2376*c77a61a7Syz uint8_t i; 2377*c77a61a7Syz uint8_t frame_cnt = fmtgrp->format->bNumFrameDescriptors; 2378*c77a61a7Syz 2379*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2380*c77a61a7Syz "usbvc_parse_format_group: frame_cnt=%d", frame_cnt); 2381*c77a61a7Syz 2382*c77a61a7Syz if (frame_cnt == 0) { 2383*c77a61a7Syz fmtgrp->frames = NULL; 2384*c77a61a7Syz 2385*c77a61a7Syz return; 2386*c77a61a7Syz } 2387*c77a61a7Syz 2388*c77a61a7Syz /* All these mem allocated will be freed in cleanup() */ 2389*c77a61a7Syz fmtgrp->frames = (usbvc_frames_t *) 2390*c77a61a7Syz kmem_zalloc(sizeof (usbvc_frames_t) * frame_cnt, KM_SLEEP); 2391*c77a61a7Syz 2392*c77a61a7Syz last_frame = frame_cnt + cvs_num; 2393*c77a61a7Syz cvs_num++; 2394*c77a61a7Syz i = 0; 2395*c77a61a7Syz 2396*c77a61a7Syz /* 2397*c77a61a7Syz * Traverse from the format decr's first frame decr to the the last 2398*c77a61a7Syz * frame descr. 2399*c77a61a7Syz */ 2400*c77a61a7Syz for (; cvs_num <= last_frame; cvs_num++) { 2401*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2402*c77a61a7Syz "usbvc_parse_frames: cvs_num=%d, i=%d", cvs_num, i); 2403*c77a61a7Syz if (cvs_num >= altif_n_cvs) { 2404*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, 2405*c77a61a7Syz usbvcp->usbvc_log_handle, 2406*c77a61a7Syz "usbvc_parse_frames: less frames than " 2407*c77a61a7Syz "expected, cvs_num=%d, i=%d", cvs_num, i); 2408*c77a61a7Syz 2409*c77a61a7Syz break; 2410*c77a61a7Syz } 2411*c77a61a7Syz cvs = &cvs_data[cvs_num]; 2412*c77a61a7Syz cvs_buf = cvs->cvs_buf; 2413*c77a61a7Syz cvs_buf_len = cvs->cvs_buf_len; 2414*c77a61a7Syz if (cvs_buf_len < USBVC_FRAME_LEN_MIN) { 2415*c77a61a7Syz i++; 2416*c77a61a7Syz 2417*c77a61a7Syz continue; 2418*c77a61a7Syz } 2419*c77a61a7Syz frm = &fmtgrp->frames[i]; 2420*c77a61a7Syz frm->descr = (usbvc_frame_descr_t *)cvs->cvs_buf; 2421*c77a61a7Syz 2422*c77a61a7Syz /* Descriptor for discrete frame interval */ 2423*c77a61a7Syz if (frm->descr->bFrameIntervalType > 0) { 2424*c77a61a7Syz if (usbvc_chk_descr_len(25, 4, 0, cvs) != USB_SUCCESS) { 2425*c77a61a7Syz frm->descr = NULL; 2426*c77a61a7Syz i++; 2427*c77a61a7Syz 2428*c77a61a7Syz continue; 2429*c77a61a7Syz } 2430*c77a61a7Syz 2431*c77a61a7Syz frm->dwFrameInterval = (uint32_t *)&cvs_buf[26]; 2432*c77a61a7Syz } else { /* Continuous interval */ 2433*c77a61a7Syz if (cvs_buf_len < USBVC_FRAME_LEN_CON) { 2434*c77a61a7Syz frm->descr = NULL; 2435*c77a61a7Syz i++; 2436*c77a61a7Syz 2437*c77a61a7Syz continue; 2438*c77a61a7Syz } 2439*c77a61a7Syz 2440*c77a61a7Syz /* Continuous frame intervals */ 2441*c77a61a7Syz LE_TO_UINT32(cvs_buf, 26, frm->dwMinFrameInterval); 2442*c77a61a7Syz LE_TO_UINT32(cvs_buf, 30, frm->dwMaxFrameInterval); 2443*c77a61a7Syz LE_TO_UINT32(cvs_buf, 34, frm->dwFrameIntervalStep); 2444*c77a61a7Syz } 2445*c77a61a7Syz 2446*c77a61a7Syz i++; 2447*c77a61a7Syz } 2448*c77a61a7Syz fmtgrp->frame_cnt = i; 2449*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2450*c77a61a7Syz "usbvc_parse_frames: %d frames are actually parsed", 2451*c77a61a7Syz fmtgrp->frame_cnt); 2452*c77a61a7Syz } 2453*c77a61a7Syz 2454*c77a61a7Syz 2455*c77a61a7Syz /* Parse one of the format groups in a stream interface */ 2456*c77a61a7Syz static int 2457*c77a61a7Syz usbvc_parse_format_group(usbvc_state_t *usbvcp, usbvc_format_group_t *fmtgrp, 2458*c77a61a7Syz usb_cvs_data_t *cvs_data, uint_t cvs_num, uint_t altif_n_cvs) 2459*c77a61a7Syz { 2460*c77a61a7Syz usbvc_format_descr_t *fmt; 2461*c77a61a7Syz 2462*c77a61a7Syz fmt = fmtgrp->format; 2463*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2464*c77a61a7Syz "usbvc_parse_format_group: frame_cnt=%d, cvs_num=%d", 2465*c77a61a7Syz fmt->bNumFrameDescriptors, cvs_num); 2466*c77a61a7Syz 2467*c77a61a7Syz switch (fmt->bDescriptorSubType) { 2468*c77a61a7Syz case VS_FORMAT_UNCOMPRESSED: 2469*c77a61a7Syz usbvc_parse_color_still(usbvcp, fmtgrp, cvs_data, cvs_num, 2470*c77a61a7Syz altif_n_cvs); 2471*c77a61a7Syz usbvc_parse_frames(usbvcp, fmtgrp, cvs_data, cvs_num, 2472*c77a61a7Syz altif_n_cvs); 2473*c77a61a7Syz fmtgrp->v4l2_bpp = 16; 2474*c77a61a7Syz fmtgrp->v4l2_pixelformat = usbvc_v4l2_guid2fcc( 2475*c77a61a7Syz (uint8_t *)&fmt->fmt.uncompressed.guidFormat); 2476*c77a61a7Syz 2477*c77a61a7Syz break; 2478*c77a61a7Syz case VS_FORMAT_MJPEG: 2479*c77a61a7Syz usbvc_parse_color_still(usbvcp, fmtgrp, cvs_data, cvs_num, 2480*c77a61a7Syz altif_n_cvs); 2481*c77a61a7Syz usbvc_parse_frames(usbvcp, fmtgrp, cvs_data, cvs_num, 2482*c77a61a7Syz altif_n_cvs); 2483*c77a61a7Syz fmtgrp->v4l2_bpp = 0; 2484*c77a61a7Syz fmtgrp->v4l2_pixelformat = V4L2_PIX_FMT_MJPEG; 2485*c77a61a7Syz 2486*c77a61a7Syz break; 2487*c77a61a7Syz case VS_FORMAT_MPEG2TS: 2488*c77a61a7Syz case VS_FORMAT_DV: 2489*c77a61a7Syz case VS_FORMAT_FRAME_BASED: 2490*c77a61a7Syz case VS_FORMAT_STREAM_BASED: 2491*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2492*c77a61a7Syz "usbvc_parse_format_group: format not supported yet."); 2493*c77a61a7Syz 2494*c77a61a7Syz return (USB_FAILURE); 2495*c77a61a7Syz default: 2496*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2497*c77a61a7Syz "usbvc_parse_format_group: unknown format."); 2498*c77a61a7Syz 2499*c77a61a7Syz return (USB_FAILURE); 2500*c77a61a7Syz } 2501*c77a61a7Syz 2502*c77a61a7Syz return (USB_SUCCESS); 2503*c77a61a7Syz } 2504*c77a61a7Syz 2505*c77a61a7Syz 2506*c77a61a7Syz /* Parse the descriptors belong to one format */ 2507*c77a61a7Syz static int 2508*c77a61a7Syz usbvc_parse_format_groups(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if) 2509*c77a61a7Syz { 2510*c77a61a7Syz usb_alt_if_data_t *if_alt_data; 2511*c77a61a7Syz usb_cvs_data_t *cvs_data; 2512*c77a61a7Syz uint8_t fmtgrp_num, fmtgrp_cnt; 2513*c77a61a7Syz uchar_t *cvs_buf; 2514*c77a61a7Syz uint_t cvs_num = 0; 2515*c77a61a7Syz usbvc_format_group_t *fmtgrp; 2516*c77a61a7Syz 2517*c77a61a7Syz fmtgrp_cnt = 0; 2518*c77a61a7Syz /* 2519*c77a61a7Syz * bNumFormats indicates the number of formats in this stream 2520*c77a61a7Syz * interface. On some devices, we see this number is larger than 2521*c77a61a7Syz * the truth. 2522*c77a61a7Syz */ 2523*c77a61a7Syz if (strm_if->input_header) { 2524*c77a61a7Syz fmtgrp_cnt = strm_if->input_header->descr->bNumFormats; 2525*c77a61a7Syz } else if (strm_if->output_header) { 2526*c77a61a7Syz fmtgrp_cnt = strm_if->output_header->descr->bNumFormats; 2527*c77a61a7Syz } 2528*c77a61a7Syz if (!fmtgrp_cnt) { 2529*c77a61a7Syz 2530*c77a61a7Syz return (USB_FAILURE); 2531*c77a61a7Syz } 2532*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2533*c77a61a7Syz "usbvc_parse_format_groups: fmtgrp_cnt=%d", fmtgrp_cnt); 2534*c77a61a7Syz 2535*c77a61a7Syz fmtgrp = (usbvc_format_group_t *) 2536*c77a61a7Syz kmem_zalloc(sizeof (usbvc_format_group_t) * fmtgrp_cnt, KM_SLEEP); 2537*c77a61a7Syz 2538*c77a61a7Syz if_alt_data = strm_if->if_descr->if_alt; 2539*c77a61a7Syz cvs_data = if_alt_data->altif_cvs; 2540*c77a61a7Syz for (fmtgrp_num = 0; fmtgrp_num < fmtgrp_cnt; fmtgrp_num++) { 2541*c77a61a7Syz 2542*c77a61a7Syz /* find the next format descriptor */ 2543*c77a61a7Syz for (; cvs_num < if_alt_data->altif_n_cvs; cvs_num++) { 2544*c77a61a7Syz cvs_buf = cvs_data[cvs_num].cvs_buf; 2545*c77a61a7Syz switch (cvs_buf[2]) { 2546*c77a61a7Syz case VS_FORMAT_UNCOMPRESSED: 2547*c77a61a7Syz case VS_FORMAT_MJPEG: 2548*c77a61a7Syz case VS_FORMAT_MPEG2TS: 2549*c77a61a7Syz case VS_FORMAT_DV: 2550*c77a61a7Syz case VS_FORMAT_FRAME_BASED: 2551*c77a61a7Syz case VS_FORMAT_STREAM_BASED: 2552*c77a61a7Syz fmtgrp[fmtgrp_num].format = 2553*c77a61a7Syz (usbvc_format_descr_t *)cvs_buf; 2554*c77a61a7Syz 2555*c77a61a7Syz break; 2556*c77a61a7Syz default: 2557*c77a61a7Syz 2558*c77a61a7Syz break; 2559*c77a61a7Syz } 2560*c77a61a7Syz if (fmtgrp[fmtgrp_num].format) { 2561*c77a61a7Syz 2562*c77a61a7Syz break; 2563*c77a61a7Syz } 2564*c77a61a7Syz } 2565*c77a61a7Syz 2566*c77a61a7Syz /* If can't find the next format, then break. */ 2567*c77a61a7Syz if (!(fmtgrp[fmtgrp_num].format)) { 2568*c77a61a7Syz strm_if->fmtgrp_cnt = fmtgrp_num; 2569*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, 2570*c77a61a7Syz usbvcp->usbvc_log_handle, 2571*c77a61a7Syz "usbvc_parse_format_groups: acctually %d formats" 2572*c77a61a7Syz " parsed", fmtgrp_num); 2573*c77a61a7Syz 2574*c77a61a7Syz break; 2575*c77a61a7Syz } 2576*c77a61a7Syz 2577*c77a61a7Syz /* 2578*c77a61a7Syz * Now cvs_data[cvs_num].cvs_buf is format descriptor, 2579*c77a61a7Syz * usbvc_parse_format_group will then parse the frame 2580*c77a61a7Syz * descriptors following this format descriptor. 2581*c77a61a7Syz */ 2582*c77a61a7Syz (void) usbvc_parse_format_group(usbvcp, &fmtgrp[fmtgrp_num], 2583*c77a61a7Syz cvs_data, cvs_num, if_alt_data->altif_n_cvs); 2584*c77a61a7Syz 2585*c77a61a7Syz /* 2586*c77a61a7Syz * cvs_data[cvs_num].cvs_buf is the one was parsed, so plus 2587*c77a61a7Syz * 1 to move to the next format group 2588*c77a61a7Syz */ 2589*c77a61a7Syz cvs_num++; 2590*c77a61a7Syz } 2591*c77a61a7Syz 2592*c77a61a7Syz /* 2593*c77a61a7Syz * If can't find any formats, then free all allocated 2594*c77a61a7Syz * usbvc_format_group_t, return failure. 2595*c77a61a7Syz */ 2596*c77a61a7Syz if (!(fmtgrp[0].format)) { 2597*c77a61a7Syz kmem_free(fmtgrp, sizeof (usbvc_format_group_t) * fmtgrp_cnt); 2598*c77a61a7Syz strm_if->format_group = NULL; 2599*c77a61a7Syz 2600*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2601*c77a61a7Syz "usbvc_parse_format_groups: can't find any formats"); 2602*c77a61a7Syz 2603*c77a61a7Syz return (USB_FAILURE); 2604*c77a61a7Syz } 2605*c77a61a7Syz strm_if->format_group = fmtgrp; 2606*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2607*c77a61a7Syz "usbvc_parse_format_groups: %d format groups parsed", fmtgrp_num); 2608*c77a61a7Syz 2609*c77a61a7Syz return (USB_SUCCESS); 2610*c77a61a7Syz } 2611*c77a61a7Syz 2612*c77a61a7Syz 2613*c77a61a7Syz /* 2614*c77a61a7Syz * Parse the input/output header in one stream interface. 2615*c77a61a7Syz * UVC Spec: there must be one and only one header in one stream interface. 2616*c77a61a7Syz */ 2617*c77a61a7Syz int 2618*c77a61a7Syz usbvc_parse_stream_header(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if) 2619*c77a61a7Syz { 2620*c77a61a7Syz usb_alt_if_data_t *if_alt_data; 2621*c77a61a7Syz usb_cvs_data_t *cvs_data; 2622*c77a61a7Syz int cvs_num; 2623*c77a61a7Syz uchar_t *cvs_buf; 2624*c77a61a7Syz usbvc_input_header_t *in_hdr; 2625*c77a61a7Syz usbvc_output_header_t *out_hdr; 2626*c77a61a7Syz 2627*c77a61a7Syz if_alt_data = strm_if->if_descr->if_alt; 2628*c77a61a7Syz cvs_data = if_alt_data->altif_cvs; 2629*c77a61a7Syz for (cvs_num = 0; cvs_num < if_alt_data->altif_n_cvs; cvs_num++) { 2630*c77a61a7Syz cvs_buf = cvs_data[cvs_num].cvs_buf; 2631*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2632*c77a61a7Syz "usbvc_parse_stream_header: cvs_num= %d", cvs_num); 2633*c77a61a7Syz 2634*c77a61a7Syz /* 2635*c77a61a7Syz * parse interface cvs descriptors here; by checking 2636*c77a61a7Syz * bDescriptorType (cvs_buf[1]) 2637*c77a61a7Syz */ 2638*c77a61a7Syz if (cvs_buf[1] != CS_INTERFACE) { 2639*c77a61a7Syz 2640*c77a61a7Syz continue; 2641*c77a61a7Syz } 2642*c77a61a7Syz 2643*c77a61a7Syz if (cvs_buf[2] == VS_INPUT_HEADER) { 2644*c77a61a7Syz if (usbvc_chk_descr_len(3, 0, 12, cvs_data) != 2645*c77a61a7Syz USB_SUCCESS) { 2646*c77a61a7Syz 2647*c77a61a7Syz continue; 2648*c77a61a7Syz } 2649*c77a61a7Syz 2650*c77a61a7Syz strm_if->input_header = 2651*c77a61a7Syz (usbvc_input_header_t *) 2652*c77a61a7Syz kmem_zalloc(sizeof (usbvc_input_header_t), 2653*c77a61a7Syz KM_SLEEP); 2654*c77a61a7Syz in_hdr = strm_if->input_header; 2655*c77a61a7Syz in_hdr->descr = (usbvc_input_header_descr_t *)cvs_buf; 2656*c77a61a7Syz if (in_hdr->descr->bNumFormats > 0) { 2657*c77a61a7Syz in_hdr->bmaControls = &cvs_buf[13]; 2658*c77a61a7Syz } 2659*c77a61a7Syz 2660*c77a61a7Syz return (USB_SUCCESS); 2661*c77a61a7Syz } else if (cvs_buf[2] == VS_OUTPUT_HEADER) { 2662*c77a61a7Syz if (usbvc_chk_descr_len(3, 0, 8, cvs_data) != 2663*c77a61a7Syz USB_SUCCESS) { 2664*c77a61a7Syz 2665*c77a61a7Syz continue; 2666*c77a61a7Syz } 2667*c77a61a7Syz strm_if->output_header = 2668*c77a61a7Syz (usbvc_output_header_t *) 2669*c77a61a7Syz kmem_zalloc(sizeof (usbvc_output_header_t), 2670*c77a61a7Syz KM_SLEEP); 2671*c77a61a7Syz out_hdr = strm_if->output_header; 2672*c77a61a7Syz out_hdr->descr = 2673*c77a61a7Syz (usbvc_output_header_descr_t *)cvs_buf; 2674*c77a61a7Syz if (out_hdr->descr->bNumFormats > 0) { 2675*c77a61a7Syz out_hdr->bmaControls = &cvs_buf[13]; 2676*c77a61a7Syz } 2677*c77a61a7Syz 2678*c77a61a7Syz return (USB_SUCCESS); 2679*c77a61a7Syz } else { 2680*c77a61a7Syz 2681*c77a61a7Syz continue; 2682*c77a61a7Syz } 2683*c77a61a7Syz } 2684*c77a61a7Syz /* Didn't find one header descriptor. */ 2685*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_ATTA, usbvcp->usbvc_log_handle, 2686*c77a61a7Syz "usbvc_parse_stream_header: FAIL"); 2687*c77a61a7Syz 2688*c77a61a7Syz return (USB_FAILURE); 2689*c77a61a7Syz } 2690*c77a61a7Syz 2691*c77a61a7Syz /* read I/O functions */ 2692*c77a61a7Syz 2693*c77a61a7Syz /* Allocate bufs for read I/O method */ 2694*c77a61a7Syz static int 2695*c77a61a7Syz usbvc_alloc_read_bufs(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if) 2696*c77a61a7Syz { 2697*c77a61a7Syz usbvc_buf_t *buf; 2698*c77a61a7Syz uchar_t *data; 2699*c77a61a7Syz int i; 2700*c77a61a7Syz uint32_t len; 2701*c77a61a7Syz 2702*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 2703*c77a61a7Syz 2704*c77a61a7Syz LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0, len); 2705*c77a61a7Syz if (!len) { 2706*c77a61a7Syz 2707*c77a61a7Syz return (USB_FAILURE); 2708*c77a61a7Syz } 2709*c77a61a7Syz for (i = 0; i < USBVC_READ_BUF_NUM; i++) { 2710*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 2711*c77a61a7Syz buf = (usbvc_buf_t *)kmem_zalloc(sizeof (usbvc_buf_t), 2712*c77a61a7Syz KM_SLEEP); 2713*c77a61a7Syz data = (uchar_t *)kmem_zalloc(len, KM_SLEEP); 2714*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 2715*c77a61a7Syz buf->data = data; 2716*c77a61a7Syz buf->len = len; 2717*c77a61a7Syz list_insert_tail(&(strm_if->buf_read.uv_buf_free), buf); 2718*c77a61a7Syz } 2719*c77a61a7Syz strm_if->buf_read.buf_cnt = USBVC_READ_BUF_NUM; 2720*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_READ, usbvcp->usbvc_log_handle, 2721*c77a61a7Syz "read_bufs: %d bufs allocated", strm_if->buf_read.buf_cnt); 2722*c77a61a7Syz 2723*c77a61a7Syz return (USB_SUCCESS); 2724*c77a61a7Syz } 2725*c77a61a7Syz 2726*c77a61a7Syz 2727*c77a61a7Syz /* Read a done buf, copy data to bp. This function is for read I/O method */ 2728*c77a61a7Syz static int 2729*c77a61a7Syz usbvc_read_buf(usbvc_state_t *usbvcp, struct buf *bp) 2730*c77a61a7Syz { 2731*c77a61a7Syz usbvc_buf_t *buf; 2732*c77a61a7Syz 2733*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 2734*c77a61a7Syz 2735*c77a61a7Syz /* read a buf from full list and then put it to free list */ 2736*c77a61a7Syz buf = list_head(&usbvcp->usbvc_curr_strm->buf_read.uv_buf_done); 2737*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 2738*c77a61a7Syz "usbvc_read_buf: buf=%p, buf->filled=%d, bfu->len=%d," 2739*c77a61a7Syz " bp->b_bcount=%d, bp->b_resid=%d", 2740*c77a61a7Syz buf, buf->filled, buf->len, bp->b_bcount, bp->b_resid); 2741*c77a61a7Syz 2742*c77a61a7Syz list_remove(&usbvcp->usbvc_curr_strm->buf_read.uv_buf_done, buf); 2743*c77a61a7Syz bcopy(buf->data, bp->b_un.b_addr, buf->filled); 2744*c77a61a7Syz bp->b_private = NULL; 2745*c77a61a7Syz bp->b_resid = bp->b_bcount - buf->filled; 2746*c77a61a7Syz list_insert_tail(&usbvcp->usbvc_curr_strm->buf_read.uv_buf_free, buf); 2747*c77a61a7Syz 2748*c77a61a7Syz return (USB_SUCCESS); 2749*c77a61a7Syz } 2750*c77a61a7Syz 2751*c77a61a7Syz 2752*c77a61a7Syz /* Free one buf which is for read/write IO style */ 2753*c77a61a7Syz static void 2754*c77a61a7Syz usbvc_free_read_buf(usbvc_buf_t *buf) 2755*c77a61a7Syz { 2756*c77a61a7Syz if (buf != NULL) { 2757*c77a61a7Syz if (buf->data) { 2758*c77a61a7Syz kmem_free(buf->data, buf->len); 2759*c77a61a7Syz } 2760*c77a61a7Syz kmem_free(buf, sizeof (usbvc_buf_t)); 2761*c77a61a7Syz } 2762*c77a61a7Syz } 2763*c77a61a7Syz 2764*c77a61a7Syz 2765*c77a61a7Syz /* Free all bufs which are for read/write IO style */ 2766*c77a61a7Syz static void 2767*c77a61a7Syz usbvc_free_read_bufs(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if) 2768*c77a61a7Syz { 2769*c77a61a7Syz usbvc_buf_t *buf; 2770*c77a61a7Syz 2771*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 2772*c77a61a7Syz 2773*c77a61a7Syz if (!strm_if) { 2774*c77a61a7Syz 2775*c77a61a7Syz return; 2776*c77a61a7Syz } 2777*c77a61a7Syz buf = strm_if->buf_read.buf_filling; 2778*c77a61a7Syz usbvc_free_read_buf(buf); 2779*c77a61a7Syz strm_if->buf_read.buf_filling = NULL; 2780*c77a61a7Syz 2781*c77a61a7Syz while (!list_is_empty(&strm_if->buf_read.uv_buf_free)) { 2782*c77a61a7Syz buf = list_head(&strm_if->buf_read.uv_buf_free); 2783*c77a61a7Syz if (buf != NULL) { 2784*c77a61a7Syz list_remove(&(strm_if->buf_read.uv_buf_free), buf); 2785*c77a61a7Syz usbvc_free_read_buf(buf); 2786*c77a61a7Syz } 2787*c77a61a7Syz } 2788*c77a61a7Syz while (!list_is_empty(&strm_if->buf_read.uv_buf_done)) { 2789*c77a61a7Syz buf = list_head(&strm_if->buf_read.uv_buf_done); 2790*c77a61a7Syz if (buf != NULL) { 2791*c77a61a7Syz list_remove(&(strm_if->buf_read.uv_buf_done), buf); 2792*c77a61a7Syz usbvc_free_read_buf(buf); 2793*c77a61a7Syz } 2794*c77a61a7Syz } 2795*c77a61a7Syz strm_if->buf_read.buf_cnt = 0; 2796*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_CLOSE, usbvcp->usbvc_log_handle, 2797*c77a61a7Syz "usbvc_free_read_bufs: return"); 2798*c77a61a7Syz } 2799*c77a61a7Syz 2800*c77a61a7Syz 2801*c77a61a7Syz /* 2802*c77a61a7Syz * Allocate bufs for mapped I/O , return the number of allocated bufs 2803*c77a61a7Syz * if success, return 0 if fail. 2804*c77a61a7Syz */ 2805*c77a61a7Syz int 2806*c77a61a7Syz usbvc_alloc_map_bufs(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if, 2807*c77a61a7Syz int buf_cnt, int buf_len) 2808*c77a61a7Syz { 2809*c77a61a7Syz int i = 0; 2810*c77a61a7Syz usbvc_buf_t *bufs; 2811*c77a61a7Syz 2812*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 2813*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 2814*c77a61a7Syz "usbvc_alloc_map_bufs: bufcnt=%d, buflen=%d", buf_cnt, buf_len); 2815*c77a61a7Syz if (buf_len <= 0 || buf_cnt <= 0) { 2816*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 2817*c77a61a7Syz "usbvc_alloc_map_bufs: len<=0, cnt<=0"); 2818*c77a61a7Syz 2819*c77a61a7Syz return (0); 2820*c77a61a7Syz } 2821*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 2822*c77a61a7Syz 2823*c77a61a7Syz bufs = (usbvc_buf_t *) kmem_zalloc(sizeof (usbvc_buf_t) * buf_cnt, 2824*c77a61a7Syz KM_SLEEP); 2825*c77a61a7Syz 2826*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 2827*c77a61a7Syz strm_if->buf_map.buf_head = bufs; 2828*c77a61a7Syz buf_len = ptob(btopr(buf_len)); 2829*c77a61a7Syz 2830*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 2831*c77a61a7Syz bufs[0].data = ddi_umem_alloc(buf_len * buf_cnt, DDI_UMEM_SLEEP, 2832*c77a61a7Syz &bufs[0].umem_cookie); 2833*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 2834*c77a61a7Syz 2835*c77a61a7Syz for (i = 0; i < buf_cnt; i++) { 2836*c77a61a7Syz bufs[i].len = buf_len; 2837*c77a61a7Syz bufs[i].data = bufs[0].data + (buf_len * i); 2838*c77a61a7Syz bufs[i].umem_cookie = bufs[0].umem_cookie; 2839*c77a61a7Syz bufs[i].status = USBVC_BUF_INIT; 2840*c77a61a7Syz 2841*c77a61a7Syz bufs[i].v4l2_buf.index = i; 2842*c77a61a7Syz bufs[i].v4l2_buf.m.offset = i * bufs[i].len; 2843*c77a61a7Syz bufs[i].v4l2_buf.length = bufs[i].len; 2844*c77a61a7Syz bufs[i].v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2845*c77a61a7Syz bufs[i].v4l2_buf.sequence = 0; 2846*c77a61a7Syz bufs[i].v4l2_buf.field = V4L2_FIELD_NONE; 2847*c77a61a7Syz bufs[i].v4l2_buf.memory = V4L2_MEMORY_MMAP; 2848*c77a61a7Syz bufs[i].v4l2_buf.flags = V4L2_MEMORY_MMAP; 2849*c77a61a7Syz 2850*c77a61a7Syz list_insert_tail(&strm_if->buf_map.uv_buf_free, &bufs[i]); 2851*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 2852*c77a61a7Syz "usbvc_alloc_map_bufs: prepare %d buffers of %d bytes", 2853*c77a61a7Syz buf_cnt, bufs[i].len); 2854*c77a61a7Syz } 2855*c77a61a7Syz strm_if->buf_map.buf_cnt = buf_cnt; 2856*c77a61a7Syz strm_if->buf_map.buf_filling = NULL; 2857*c77a61a7Syz 2858*c77a61a7Syz return (buf_cnt); 2859*c77a61a7Syz } 2860*c77a61a7Syz 2861*c77a61a7Syz 2862*c77a61a7Syz /* Free all bufs which are for memory map IO style */ 2863*c77a61a7Syz void 2864*c77a61a7Syz usbvc_free_map_bufs(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if) 2865*c77a61a7Syz { 2866*c77a61a7Syz usbvc_buf_t *buf; 2867*c77a61a7Syz 2868*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 2869*c77a61a7Syz if (!strm_if) { 2870*c77a61a7Syz 2871*c77a61a7Syz return; 2872*c77a61a7Syz } 2873*c77a61a7Syz strm_if->buf_map.buf_filling = NULL; 2874*c77a61a7Syz while (!list_is_empty(&strm_if->buf_map.uv_buf_free)) { 2875*c77a61a7Syz buf = (usbvc_buf_t *)list_head(&strm_if->buf_map.uv_buf_free); 2876*c77a61a7Syz list_remove(&(strm_if->buf_map.uv_buf_free), buf); 2877*c77a61a7Syz } 2878*c77a61a7Syz while (!list_is_empty(&strm_if->buf_map.uv_buf_done)) { 2879*c77a61a7Syz buf = (usbvc_buf_t *)list_head(&strm_if->buf_map.uv_buf_done); 2880*c77a61a7Syz list_remove(&(strm_if->buf_map.uv_buf_done), buf); 2881*c77a61a7Syz } 2882*c77a61a7Syz buf = strm_if->buf_map.buf_head; 2883*c77a61a7Syz if (!buf) { 2884*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CLOSE, usbvcp->usbvc_log_handle, 2885*c77a61a7Syz "usbvc_free_map_bufs: no data buf need be freed, return"); 2886*c77a61a7Syz 2887*c77a61a7Syz return; 2888*c77a61a7Syz } 2889*c77a61a7Syz if (buf->umem_cookie) { 2890*c77a61a7Syz ddi_umem_free(buf->umem_cookie); 2891*c77a61a7Syz } 2892*c77a61a7Syz kmem_free(buf, sizeof (usbvc_buf_t) * strm_if->buf_map.buf_cnt); 2893*c77a61a7Syz strm_if->buf_map.buf_cnt = 0; 2894*c77a61a7Syz strm_if->buf_map.buf_head = NULL; 2895*c77a61a7Syz 2896*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CLOSE, usbvcp->usbvc_log_handle, 2897*c77a61a7Syz "usbvc_free_map_bufs: return"); 2898*c77a61a7Syz } 2899*c77a61a7Syz 2900*c77a61a7Syz 2901*c77a61a7Syz /* 2902*c77a61a7Syz * Open the isoc pipe, this pipe is for video data transfer 2903*c77a61a7Syz */ 2904*c77a61a7Syz int 2905*c77a61a7Syz usbvc_open_isoc_pipe(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if) 2906*c77a61a7Syz { 2907*c77a61a7Syz usb_pipe_policy_t policy; 2908*c77a61a7Syz int rval = USB_SUCCESS; 2909*c77a61a7Syz 2910*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 2911*c77a61a7Syz 2912*c77a61a7Syz if ((rval = usbvc_set_alt(usbvcp, strm_if)) != USB_SUCCESS) { 2913*c77a61a7Syz 2914*c77a61a7Syz return (rval); 2915*c77a61a7Syz } 2916*c77a61a7Syz bzero(&policy, sizeof (usb_pipe_policy_t)); 2917*c77a61a7Syz policy.pp_max_async_reqs = 2; 2918*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 2919*c77a61a7Syz if ((rval = usb_pipe_open(usbvcp->usbvc_dip, strm_if->curr_ep, &policy, 2920*c77a61a7Syz USB_FLAGS_SLEEP, &strm_if->datain_ph)) != USB_SUCCESS) { 2921*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 2922*c77a61a7Syz "usbvc_open_isoc_pipe: open pipe fail"); 2923*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 2924*c77a61a7Syz 2925*c77a61a7Syz return (rval); 2926*c77a61a7Syz } 2927*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 2928*c77a61a7Syz strm_if->start_polling = 0; 2929*c77a61a7Syz 2930*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 2931*c77a61a7Syz "usbvc_open_isoc_pipe: success, datain_ph=%p", strm_if->datain_ph); 2932*c77a61a7Syz 2933*c77a61a7Syz return (rval); 2934*c77a61a7Syz } 2935*c77a61a7Syz 2936*c77a61a7Syz 2937*c77a61a7Syz /* 2938*c77a61a7Syz * Open the isoc pipe 2939*c77a61a7Syz */ 2940*c77a61a7Syz static void 2941*c77a61a7Syz usbvc_close_isoc_pipe(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if) 2942*c77a61a7Syz { 2943*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 2944*c77a61a7Syz if (!strm_if) { 2945*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CLOSE, usbvcp->usbvc_log_handle, 2946*c77a61a7Syz "usbvc_close_isoc_pipe: stream interface is NULL"); 2947*c77a61a7Syz 2948*c77a61a7Syz return; 2949*c77a61a7Syz } 2950*c77a61a7Syz if (strm_if->datain_ph) { 2951*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 2952*c77a61a7Syz usb_pipe_close(usbvcp->usbvc_dip, strm_if->datain_ph, 2953*c77a61a7Syz USB_FLAGS_SLEEP, NULL, NULL); 2954*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 2955*c77a61a7Syz } 2956*c77a61a7Syz strm_if->datain_ph = NULL; 2957*c77a61a7Syz } 2958*c77a61a7Syz 2959*c77a61a7Syz 2960*c77a61a7Syz /* 2961*c77a61a7Syz * Start to get video data from isoc pipe in the stream interface, 2962*c77a61a7Syz * issue isoc req. 2963*c77a61a7Syz */ 2964*c77a61a7Syz int 2965*c77a61a7Syz usbvc_start_isoc_polling(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if, 2966*c77a61a7Syz uchar_t io_type) 2967*c77a61a7Syz { 2968*c77a61a7Syz int rval = USB_SUCCESS; 2969*c77a61a7Syz uint_t if_num; 2970*c77a61a7Syz usb_isoc_req_t *req; 2971*c77a61a7Syz ushort_t pkt_size; 2972*c77a61a7Syz ushort_t n_pkt, pkt; 2973*c77a61a7Syz uint32_t frame_size; 2974*c77a61a7Syz 2975*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 2976*c77a61a7Syz pkt_size = strm_if->curr_ep->wMaxPacketSize; 2977*c77a61a7Syz if_num = strm_if->if_descr->if_alt->altif_descr.bInterfaceNumber; 2978*c77a61a7Syz LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0, frame_size); 2979*c77a61a7Syz n_pkt = (frame_size + HS_PKT_SIZE(pkt_size) -1) 2980*c77a61a7Syz / HS_PKT_SIZE(pkt_size); 2981*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 2982*c77a61a7Syz "usbvc_start_isoc_polling: if_num=%d, alt=%d, n_pkt=%d," 2983*c77a61a7Syz " pkt_size=0x%x, frame_size=0x%x", 2984*c77a61a7Syz if_num, strm_if->curr_alt, n_pkt, pkt_size, frame_size); 2985*c77a61a7Syz 2986*c77a61a7Syz if (n_pkt > USBVC_MAX_PKTS) { 2987*c77a61a7Syz n_pkt = USBVC_MAX_PKTS; 2988*c77a61a7Syz } 2989*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 2990*c77a61a7Syz "usbvc_start_isoc_polling: n_pkt=%d", n_pkt); 2991*c77a61a7Syz 2992*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 2993*c77a61a7Syz if ((req = usb_alloc_isoc_req(usbvcp->usbvc_dip, n_pkt, 2994*c77a61a7Syz n_pkt * pkt_size, USB_FLAGS_SLEEP)) != NULL) { 2995*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 2996*c77a61a7Syz 2997*c77a61a7Syz /* Initialize the packet descriptor */ 2998*c77a61a7Syz for (pkt = 0; pkt < n_pkt; pkt++) { 2999*c77a61a7Syz req->isoc_pkt_descr[pkt].isoc_pkt_length = pkt_size; 3000*c77a61a7Syz } 3001*c77a61a7Syz 3002*c77a61a7Syz req->isoc_pkts_count = n_pkt; 3003*c77a61a7Syz 3004*c77a61a7Syz /* 3005*c77a61a7Syz * zero here indicates that HCDs will use 3006*c77a61a7Syz * isoc_pkt_descr->isoc_pkt_length to calculate 3007*c77a61a7Syz * isoc_pkts_length. 3008*c77a61a7Syz */ 3009*c77a61a7Syz req->isoc_pkts_length = 0; 3010*c77a61a7Syz req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP | 3011*c77a61a7Syz USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 3012*c77a61a7Syz req->isoc_cb = usbvc_isoc_cb; 3013*c77a61a7Syz req->isoc_exc_cb = usbvc_isoc_exc_cb; 3014*c77a61a7Syz usbvcp->usbvc_io_type = io_type; 3015*c77a61a7Syz req->isoc_client_private = (usb_opaque_t)usbvcp; 3016*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3017*c77a61a7Syz rval = usb_pipe_isoc_xfer(strm_if->datain_ph, req, 0); 3018*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 3019*c77a61a7Syz } else { 3020*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 3021*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 3022*c77a61a7Syz "usbvc_start_isoc_polling: alloc_isoc_req fail"); 3023*c77a61a7Syz 3024*c77a61a7Syz return (USB_FAILURE); 3025*c77a61a7Syz } 3026*c77a61a7Syz 3027*c77a61a7Syz if (rval != USB_SUCCESS) { 3028*c77a61a7Syz if (req) { 3029*c77a61a7Syz usb_free_isoc_req(req); 3030*c77a61a7Syz req = NULL; 3031*c77a61a7Syz } 3032*c77a61a7Syz } 3033*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle, 3034*c77a61a7Syz "usbvc_start_isoc_polling: return, rval=%d", rval); 3035*c77a61a7Syz 3036*c77a61a7Syz return (rval); 3037*c77a61a7Syz } 3038*c77a61a7Syz 3039*c77a61a7Syz /* callbacks for receiving video data (isco in transfer) */ 3040*c77a61a7Syz 3041*c77a61a7Syz /*ARGSUSED*/ 3042*c77a61a7Syz /* Isoc transfer callback, get video data */ 3043*c77a61a7Syz static void 3044*c77a61a7Syz usbvc_isoc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) 3045*c77a61a7Syz { 3046*c77a61a7Syz usbvc_state_t *usbvcp = 3047*c77a61a7Syz (usbvc_state_t *)isoc_req->isoc_client_private; 3048*c77a61a7Syz int i; 3049*c77a61a7Syz mblk_t *data = isoc_req->isoc_data; 3050*c77a61a7Syz usbvc_buf_grp_t *bufgrp; 3051*c77a61a7Syz 3052*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 3053*c77a61a7Syz 3054*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3055*c77a61a7Syz "usbvc_isoc_cb: rq=0x%p, fno=%" PRId64 ", n_pkts=%u, flag=0x%x," 3056*c77a61a7Syz " data=0x%p, cnt=%d", 3057*c77a61a7Syz isoc_req, isoc_req->isoc_frame_no, isoc_req->isoc_pkts_count, 3058*c77a61a7Syz isoc_req->isoc_attributes, isoc_req->isoc_data, 3059*c77a61a7Syz isoc_req->isoc_error_count); 3060*c77a61a7Syz 3061*c77a61a7Syz ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) != 0); 3062*c77a61a7Syz for (i = 0; i < isoc_req->isoc_pkts_count; i++) { 3063*c77a61a7Syz 3064*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3065*c77a61a7Syz "\tpkt%d: " 3066*c77a61a7Syz "pktsize=%d status=%d resid=%d", 3067*c77a61a7Syz i, 3068*c77a61a7Syz isoc_req->isoc_pkt_descr[i].isoc_pkt_length, 3069*c77a61a7Syz isoc_req->isoc_pkt_descr[i].isoc_pkt_status, 3070*c77a61a7Syz isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length); 3071*c77a61a7Syz 3072*c77a61a7Syz if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status != 3073*c77a61a7Syz USB_CR_OK) { 3074*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CB, 3075*c77a61a7Syz usbvcp->usbvc_log_handle, 3076*c77a61a7Syz "record: pkt=%d status=%s", i, usb_str_cr( 3077*c77a61a7Syz isoc_req->isoc_pkt_descr[i].isoc_pkt_status)); 3078*c77a61a7Syz } 3079*c77a61a7Syz 3080*c77a61a7Syz if (usbvcp->usbvc_io_type == V4L2_MEMORY_MMAP) { 3081*c77a61a7Syz bufgrp = &usbvcp->usbvc_curr_strm->buf_map; 3082*c77a61a7Syz } else { 3083*c77a61a7Syz bufgrp = &usbvcp->usbvc_curr_strm->buf_read; 3084*c77a61a7Syz } 3085*c77a61a7Syz 3086*c77a61a7Syz if (isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length) { 3087*c77a61a7Syz if (usbvc_decode_stream_header(usbvcp, bufgrp, data, 3088*c77a61a7Syz isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length) 3089*c77a61a7Syz != USB_SUCCESS) { 3090*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CB, 3091*c77a61a7Syz usbvcp->usbvc_log_handle, "decode error"); 3092*c77a61a7Syz } 3093*c77a61a7Syz if (bufgrp->buf_filling && 3094*c77a61a7Syz (bufgrp->buf_filling->status == USBVC_BUF_ERR || 3095*c77a61a7Syz bufgrp->buf_filling->status == USBVC_BUF_DONE)) { 3096*c77a61a7Syz 3097*c77a61a7Syz /* Move the buf to the full list */ 3098*c77a61a7Syz list_insert_tail(&bufgrp->uv_buf_done, 3099*c77a61a7Syz bufgrp->buf_filling); 3100*c77a61a7Syz 3101*c77a61a7Syz bufgrp->buf_filling = NULL; 3102*c77a61a7Syz 3103*c77a61a7Syz if (usbvcp->usbvc_io_type == V4L2_MEMORY_MMAP) { 3104*c77a61a7Syz cv_broadcast(&usbvcp->usbvc_mapio_cv); 3105*c77a61a7Syz } else { 3106*c77a61a7Syz cv_broadcast(&usbvcp->usbvc_read_cv); 3107*c77a61a7Syz } 3108*c77a61a7Syz } 3109*c77a61a7Syz } 3110*c77a61a7Syz data->b_rptr += 3111*c77a61a7Syz HS_PKT_SIZE(isoc_req->isoc_pkt_descr[i].isoc_pkt_length); 3112*c77a61a7Syz } 3113*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3114*c77a61a7Syz usb_free_isoc_req(isoc_req); 3115*c77a61a7Syz } 3116*c77a61a7Syz 3117*c77a61a7Syz 3118*c77a61a7Syz /*ARGSUSED*/ 3119*c77a61a7Syz static void 3120*c77a61a7Syz usbvc_isoc_exc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) 3121*c77a61a7Syz { 3122*c77a61a7Syz usbvc_state_t *usbvcp = 3123*c77a61a7Syz (usbvc_state_t *)isoc_req->isoc_client_private; 3124*c77a61a7Syz usb_cr_t completion_reason; 3125*c77a61a7Syz int rval; 3126*c77a61a7Syz usbvc_stream_if_t *strm_if; 3127*c77a61a7Syz 3128*c77a61a7Syz ASSERT(!list_is_empty(&usbvcp->usbvc_stream_list)); 3129*c77a61a7Syz 3130*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 3131*c77a61a7Syz 3132*c77a61a7Syz /* get the first stream interface */ 3133*c77a61a7Syz strm_if = usbvcp->usbvc_curr_strm; 3134*c77a61a7Syz 3135*c77a61a7Syz completion_reason = isoc_req->isoc_completion_reason; 3136*c77a61a7Syz 3137*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3138*c77a61a7Syz "usbvc_isoc_exc_cb: ph=0x%p, isoc_req=0x%p, cr=%d", 3139*c77a61a7Syz (void *)ph, (void *)isoc_req, completion_reason); 3140*c77a61a7Syz 3141*c77a61a7Syz ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) == 0); 3142*c77a61a7Syz 3143*c77a61a7Syz switch (completion_reason) { 3144*c77a61a7Syz case USB_CR_STOPPED_POLLING: 3145*c77a61a7Syz case USB_CR_PIPE_CLOSING: 3146*c77a61a7Syz case USB_CR_PIPE_RESET: 3147*c77a61a7Syz 3148*c77a61a7Syz break; 3149*c77a61a7Syz case USB_CR_NO_RESOURCES: 3150*c77a61a7Syz /* 3151*c77a61a7Syz * keep the show going: Since we have the original 3152*c77a61a7Syz * request, we just resubmit it 3153*c77a61a7Syz */ 3154*c77a61a7Syz rval = usb_pipe_isoc_xfer(strm_if->datain_ph, isoc_req, 3155*c77a61a7Syz USB_FLAGS_NOSLEEP); 3156*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3157*c77a61a7Syz "usbvc_isoc_exc_cb: restart capture rval=%d", rval); 3158*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3159*c77a61a7Syz 3160*c77a61a7Syz return; 3161*c77a61a7Syz default: 3162*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3163*c77a61a7Syz usb_pipe_stop_isoc_polling(ph, USB_FLAGS_NOSLEEP); 3164*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3165*c77a61a7Syz "usbvc_isoc_exc_cb: stop polling"); 3166*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 3167*c77a61a7Syz } 3168*c77a61a7Syz usb_free_isoc_req(isoc_req); 3169*c77a61a7Syz strm_if->start_polling = 0; 3170*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3171*c77a61a7Syz "usbvc_isoc_exc_cb: start_polling=%d cr=%d", 3172*c77a61a7Syz strm_if->start_polling, completion_reason); 3173*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3174*c77a61a7Syz } 3175*c77a61a7Syz 3176*c77a61a7Syz /* 3177*c77a61a7Syz * Other utility functions 3178*c77a61a7Syz */ 3179*c77a61a7Syz 3180*c77a61a7Syz /* 3181*c77a61a7Syz * Find a proper alternate according to the bandwidth that the current video 3182*c77a61a7Syz * format need; 3183*c77a61a7Syz * Set alternate by calling usb_set_alt_if; 3184*c77a61a7Syz * Called before open pipes in stream interface. 3185*c77a61a7Syz */ 3186*c77a61a7Syz static int 3187*c77a61a7Syz usbvc_set_alt(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if) 3188*c77a61a7Syz { 3189*c77a61a7Syz usb_alt_if_data_t *alt; 3190*c77a61a7Syz uint_t i, j, if_num; 3191*c77a61a7Syz uint16_t pktsize, curr_pktsize; 3192*c77a61a7Syz uint32_t bandwidth; 3193*c77a61a7Syz int rval = USB_SUCCESS; 3194*c77a61a7Syz usbvc_input_header_t *ihd; 3195*c77a61a7Syz usbvc_output_header_t *ohd; 3196*c77a61a7Syz 3197*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 3198*c77a61a7Syz 3199*c77a61a7Syz LE_TO_UINT32(strm_if->ctrl_pc.dwMaxPayloadTransferSize, 0, bandwidth); 3200*c77a61a7Syz if (!bandwidth) { 3201*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 3202*c77a61a7Syz "usbvc_set_alt: bandwidth is not set yet"); 3203*c77a61a7Syz 3204*c77a61a7Syz return (USB_FAILURE); 3205*c77a61a7Syz } 3206*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 3207*c77a61a7Syz "usbvc_set_alt: bandwidth=%x", bandwidth); 3208*c77a61a7Syz 3209*c77a61a7Syz strm_if->curr_ep = NULL; 3210*c77a61a7Syz curr_pktsize = 0xffff; 3211*c77a61a7Syz ohd = strm_if->output_header; 3212*c77a61a7Syz ihd = strm_if->input_header; 3213*c77a61a7Syz /* 3214*c77a61a7Syz * Find one alternate setting whose isoc ep's max pktsize is just 3215*c77a61a7Syz * enough for the bandwidth. 3216*c77a61a7Syz */ 3217*c77a61a7Syz for (i = 0; i < strm_if->if_descr->if_n_alt; i++) { 3218*c77a61a7Syz alt = &strm_if->if_descr->if_alt[i]; 3219*c77a61a7Syz 3220*c77a61a7Syz for (j = 0; j < alt->altif_n_ep; j++) { 3221*c77a61a7Syz 3222*c77a61a7Syz /* if this stream interface is for input */ 3223*c77a61a7Syz if (ihd != NULL && 3224*c77a61a7Syz alt->altif_ep[j].ep_descr.bEndpointAddress != 3225*c77a61a7Syz ihd->descr->bEndpointAddress) { 3226*c77a61a7Syz 3227*c77a61a7Syz continue; 3228*c77a61a7Syz } 3229*c77a61a7Syz /* if this stream interface is for output */ 3230*c77a61a7Syz if (ohd != NULL && 3231*c77a61a7Syz alt->altif_ep[j].ep_descr.bEndpointAddress != 3232*c77a61a7Syz ohd->descr->bEndpointAddress) { 3233*c77a61a7Syz 3234*c77a61a7Syz continue; 3235*c77a61a7Syz } 3236*c77a61a7Syz pktsize = 3237*c77a61a7Syz alt->altif_ep[j].ep_descr.wMaxPacketSize; 3238*c77a61a7Syz pktsize = HS_PKT_SIZE(pktsize); 3239*c77a61a7Syz if (pktsize >= bandwidth && pktsize < curr_pktsize) { 3240*c77a61a7Syz curr_pktsize = pktsize; 3241*c77a61a7Syz strm_if->curr_alt = i; 3242*c77a61a7Syz strm_if->curr_ep = &alt->altif_ep[j].ep_descr; 3243*c77a61a7Syz } 3244*c77a61a7Syz } 3245*c77a61a7Syz } 3246*c77a61a7Syz if (!strm_if->curr_ep) { 3247*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 3248*c77a61a7Syz "usbvc_set_alt: can't find a proper ep to satisfy" 3249*c77a61a7Syz " the given bandwidth"); 3250*c77a61a7Syz 3251*c77a61a7Syz return (USB_FAILURE); 3252*c77a61a7Syz } 3253*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 3254*c77a61a7Syz "usbvc_set_alt: strm_if->curr_alt=%d", strm_if->curr_alt); 3255*c77a61a7Syz if_num = strm_if->if_descr->if_alt->altif_descr.bInterfaceNumber; 3256*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3257*c77a61a7Syz if ((rval = usb_set_alt_if(usbvcp->usbvc_dip, if_num, strm_if->curr_alt, 3258*c77a61a7Syz USB_FLAGS_SLEEP, NULL, NULL)) != USB_SUCCESS) { 3259*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 3260*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 3261*c77a61a7Syz "usbvc_set_alt: usb_set_alt_if fail, if.alt=%d.%d, rval=%d", 3262*c77a61a7Syz if_num, strm_if->curr_alt, rval); 3263*c77a61a7Syz 3264*c77a61a7Syz return (rval); 3265*c77a61a7Syz } 3266*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 3267*c77a61a7Syz 3268*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle, 3269*c77a61a7Syz "usbvc_set_alt: return, if_num=%d, alt=%d", 3270*c77a61a7Syz if_num, strm_if->curr_alt); 3271*c77a61a7Syz 3272*c77a61a7Syz return (rval); 3273*c77a61a7Syz } 3274*c77a61a7Syz 3275*c77a61a7Syz 3276*c77a61a7Syz /* 3277*c77a61a7Syz * Decode stream header for mjpeg and uncompressed format video data. 3278*c77a61a7Syz * mjpeg and uncompressed format have the same stream header. See their 3279*c77a61a7Syz * payload spec, 2.2 and 2.4 3280*c77a61a7Syz */ 3281*c77a61a7Syz static int 3282*c77a61a7Syz usbvc_decode_stream_header(usbvc_state_t *usbvcp, usbvc_buf_grp_t *bufgrp, 3283*c77a61a7Syz mblk_t *data, int actual_len) 3284*c77a61a7Syz { 3285*c77a61a7Syz uint32_t len, buf_left, data_len; 3286*c77a61a7Syz usbvc_stream_if_t *strm_if; 3287*c77a61a7Syz uchar_t head_flag, head_len; 3288*c77a61a7Syz usbvc_buf_t *buf_filling; 3289*c77a61a7Syz 3290*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 3291*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3292*c77a61a7Syz "usbvc_decode_stream_header: enter. actual_len=%x", actual_len); 3293*c77a61a7Syz 3294*c77a61a7Syz /* header length check. */ 3295*c77a61a7Syz if (actual_len < 2) { 3296*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3297*c77a61a7Syz "usbvc_decode_stream_header: header is not completed"); 3298*c77a61a7Syz 3299*c77a61a7Syz return (USB_FAILURE); 3300*c77a61a7Syz } 3301*c77a61a7Syz head_len = data->b_rptr[0]; 3302*c77a61a7Syz head_flag = data->b_rptr[1]; 3303*c77a61a7Syz 3304*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3305*c77a61a7Syz "usbvc_decode_stream_header: headlen=%x", head_len); 3306*c77a61a7Syz 3307*c77a61a7Syz /* header length check. */ 3308*c77a61a7Syz if (actual_len < head_len) { 3309*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3310*c77a61a7Syz "usbvc_decode_stream_header: actual_len < head_len"); 3311*c77a61a7Syz 3312*c77a61a7Syz return (USB_FAILURE); 3313*c77a61a7Syz } 3314*c77a61a7Syz 3315*c77a61a7Syz /* 3316*c77a61a7Syz * If there is no stream data in this packet and this packet is not 3317*c77a61a7Syz * used to indicate the end of a frame, then just skip it. 3318*c77a61a7Syz */ 3319*c77a61a7Syz if ((actual_len == head_len) && !(head_flag & USBVC_STREAM_EOF)) { 3320*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3321*c77a61a7Syz "usbvc_decode_stream_header: only header, no data"); 3322*c77a61a7Syz 3323*c77a61a7Syz return (USB_FAILURE); 3324*c77a61a7Syz } 3325*c77a61a7Syz 3326*c77a61a7Syz /* Get the first stream interface */ 3327*c77a61a7Syz strm_if = usbvcp->usbvc_curr_strm; 3328*c77a61a7Syz 3329*c77a61a7Syz LE_TO_UINT32(strm_if->ctrl_pc.dwMaxVideoFrameSize, 0, len); 3330*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3331*c77a61a7Syz "usbvc_decode_stream_header: dwMaxVideoFrameSize=%x, head_flag=%x", 3332*c77a61a7Syz len, head_flag); 3333*c77a61a7Syz 3334*c77a61a7Syz /* 3335*c77a61a7Syz * if no buf is filling, pick one buf from free list and alloc data 3336*c77a61a7Syz * mem for the buf. 3337*c77a61a7Syz */ 3338*c77a61a7Syz if (!bufgrp->buf_filling) { 3339*c77a61a7Syz if (list_is_empty(&bufgrp->uv_buf_free)) { 3340*c77a61a7Syz strm_if->fid = head_flag & USBVC_STREAM_FID; 3341*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3342*c77a61a7Syz "usbvc_decode_stream_header: free list are empty"); 3343*c77a61a7Syz 3344*c77a61a7Syz return (USB_FAILURE); 3345*c77a61a7Syz 3346*c77a61a7Syz } else { 3347*c77a61a7Syz bufgrp->buf_filling = 3348*c77a61a7Syz (usbvc_buf_t *)list_head(&bufgrp->uv_buf_free); 3349*c77a61a7Syz 3350*c77a61a7Syz /* unlink from buf free list */ 3351*c77a61a7Syz list_remove(&bufgrp->uv_buf_free, bufgrp->buf_filling); 3352*c77a61a7Syz } 3353*c77a61a7Syz bufgrp->buf_filling->filled = 0; 3354*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3355*c77a61a7Syz "usbvc_decode_stream_header: status=%d", 3356*c77a61a7Syz bufgrp->buf_filling->status); 3357*c77a61a7Syz bufgrp->buf_filling->status = USBVC_BUF_EMPTY; 3358*c77a61a7Syz } 3359*c77a61a7Syz buf_filling = bufgrp->buf_filling; 3360*c77a61a7Syz ASSERT(buf_filling->len >= buf_filling->filled); 3361*c77a61a7Syz buf_left = buf_filling->len - buf_filling->filled; 3362*c77a61a7Syz 3363*c77a61a7Syz /* if no buf room left, then return with a err status */ 3364*c77a61a7Syz if (buf_left == 0) { 3365*c77a61a7Syz buf_filling->status = USBVC_BUF_ERR; 3366*c77a61a7Syz 3367*c77a61a7Syz return (USB_FAILURE); 3368*c77a61a7Syz } 3369*c77a61a7Syz 3370*c77a61a7Syz /* get this sample's data length except header */ 3371*c77a61a7Syz data_len = actual_len - head_len; 3372*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3373*c77a61a7Syz "usbvc_decode_stream_header: fid=%x, len=%x, filled=%x", 3374*c77a61a7Syz strm_if->fid, buf_filling->len, buf_filling->filled); 3375*c77a61a7Syz 3376*c77a61a7Syz /* if the first sample for a frame */ 3377*c77a61a7Syz if (buf_filling->filled == 0) { 3378*c77a61a7Syz /* 3379*c77a61a7Syz * Only if it is the frist packet of a frame, 3380*c77a61a7Syz * we will begin filling a frame. 3381*c77a61a7Syz */ 3382*c77a61a7Syz if (strm_if->fid != 0xff && strm_if->fid == 3383*c77a61a7Syz (head_flag & USBVC_STREAM_FID)) { 3384*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3385*c77a61a7Syz "usbvc_decode_stream_header: 1st sample of a frame," 3386*c77a61a7Syz " fid is incorrect."); 3387*c77a61a7Syz 3388*c77a61a7Syz return (USB_FAILURE); 3389*c77a61a7Syz } 3390*c77a61a7Syz strm_if->fid = head_flag & USBVC_STREAM_FID; 3391*c77a61a7Syz 3392*c77a61a7Syz /* If in the middle of a frame, fid should be consistent. */ 3393*c77a61a7Syz } else if (strm_if->fid != (head_flag & USBVC_STREAM_FID)) { 3394*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3395*c77a61a7Syz "usbvc_decode_stream_header: fid is incorrect."); 3396*c77a61a7Syz strm_if->fid = head_flag & USBVC_STREAM_FID; 3397*c77a61a7Syz buf_filling->status = USBVC_BUF_ERR; 3398*c77a61a7Syz 3399*c77a61a7Syz return (USB_FAILURE); 3400*c77a61a7Syz } 3401*c77a61a7Syz if (data_len) { 3402*c77a61a7Syz bcopy((void *)(data->b_rptr + head_len), 3403*c77a61a7Syz (void *)(buf_filling->data + buf_filling->filled), 3404*c77a61a7Syz min(data_len, buf_left)); 3405*c77a61a7Syz 3406*c77a61a7Syz buf_filling->filled += min(data_len, buf_left); 3407*c77a61a7Syz } 3408*c77a61a7Syz 3409*c77a61a7Syz /* If the last packet for this frame */ 3410*c77a61a7Syz if (head_flag & USBVC_STREAM_EOF) { 3411*c77a61a7Syz buf_filling->status = USBVC_BUF_DONE; 3412*c77a61a7Syz } 3413*c77a61a7Syz if (data_len > buf_left) { 3414*c77a61a7Syz buf_filling->status = USBVC_BUF_ERR; 3415*c77a61a7Syz } 3416*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_CB, usbvcp->usbvc_log_handle, 3417*c77a61a7Syz "usbvc_decode_stream_header: buf_status=%d", buf_filling->status); 3418*c77a61a7Syz 3419*c77a61a7Syz return (USB_SUCCESS); 3420*c77a61a7Syz } 3421*c77a61a7Syz 3422*c77a61a7Syz 3423*c77a61a7Syz /* 3424*c77a61a7Syz * usbvc_serialize_access: 3425*c77a61a7Syz * Get the serial synchronization object before returning. 3426*c77a61a7Syz * 3427*c77a61a7Syz * Arguments: 3428*c77a61a7Syz * usbvcp - Pointer to usbvc state structure 3429*c77a61a7Syz * waitsig - Set to: 3430*c77a61a7Syz * USBVC_SER_SIG - to wait such that a signal can interrupt 3431*c77a61a7Syz * USBVC_SER_NOSIG - to wait such that a signal cannot interrupt 3432*c77a61a7Syz */ 3433*c77a61a7Syz static int 3434*c77a61a7Syz usbvc_serialize_access(usbvc_state_t *usbvcp, boolean_t waitsig) 3435*c77a61a7Syz { 3436*c77a61a7Syz int rval = 1; 3437*c77a61a7Syz 3438*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 3439*c77a61a7Syz 3440*c77a61a7Syz while (usbvcp->usbvc_serial_inuse) { 3441*c77a61a7Syz if (waitsig == USBVC_SER_SIG) { 3442*c77a61a7Syz rval = cv_wait_sig(&usbvcp->usbvc_serial_cv, 3443*c77a61a7Syz &usbvcp->usbvc_mutex); 3444*c77a61a7Syz } else { 3445*c77a61a7Syz cv_wait(&usbvcp->usbvc_serial_cv, 3446*c77a61a7Syz &usbvcp->usbvc_mutex); 3447*c77a61a7Syz } 3448*c77a61a7Syz } 3449*c77a61a7Syz usbvcp->usbvc_serial_inuse = B_TRUE; 3450*c77a61a7Syz 3451*c77a61a7Syz return (rval); 3452*c77a61a7Syz } 3453*c77a61a7Syz 3454*c77a61a7Syz 3455*c77a61a7Syz /* 3456*c77a61a7Syz * usbvc_release_access: 3457*c77a61a7Syz * Release the serial synchronization object. 3458*c77a61a7Syz */ 3459*c77a61a7Syz static void 3460*c77a61a7Syz usbvc_release_access(usbvc_state_t *usbvcp) 3461*c77a61a7Syz { 3462*c77a61a7Syz ASSERT(mutex_owned(&usbvcp->usbvc_mutex)); 3463*c77a61a7Syz usbvcp->usbvc_serial_inuse = B_FALSE; 3464*c77a61a7Syz cv_broadcast(&usbvcp->usbvc_serial_cv); 3465*c77a61a7Syz } 3466*c77a61a7Syz 3467*c77a61a7Syz 3468*c77a61a7Syz /* Send req to video control interface to get ctrl */ 3469*c77a61a7Syz int 3470*c77a61a7Syz usbvc_vc_get_ctrl(usbvc_state_t *usbvcp, uint8_t req_code, uint8_t entity_id, 3471*c77a61a7Syz uint16_t cs, uint16_t wlength, mblk_t *data) 3472*c77a61a7Syz { 3473*c77a61a7Syz usb_cb_flags_t cb_flags; 3474*c77a61a7Syz usb_cr_t cr; 3475*c77a61a7Syz usb_ctrl_setup_t setup; 3476*c77a61a7Syz 3477*c77a61a7Syz setup.bmRequestType = USBVC_GET_IF; /* bmRequestType */ 3478*c77a61a7Syz setup.bRequest = req_code; /* bRequest */ 3479*c77a61a7Syz setup.wValue = cs<<8; 3480*c77a61a7Syz setup.wIndex = entity_id<<8; 3481*c77a61a7Syz setup.wLength = wlength; 3482*c77a61a7Syz setup.attrs = 0; 3483*c77a61a7Syz 3484*c77a61a7Syz if (usb_pipe_ctrl_xfer_wait(usbvcp->usbvc_default_ph, &setup, &data, 3485*c77a61a7Syz &cr, &cb_flags, 0) != USB_SUCCESS) { 3486*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3487*c77a61a7Syz "usbvc_vc_get_ctrl: cmd failed, cr=%d, cb_flags=%x", 3488*c77a61a7Syz cr, cb_flags); 3489*c77a61a7Syz 3490*c77a61a7Syz return (USB_FAILURE); 3491*c77a61a7Syz } 3492*c77a61a7Syz 3493*c77a61a7Syz return (USB_SUCCESS); 3494*c77a61a7Syz } 3495*c77a61a7Syz 3496*c77a61a7Syz 3497*c77a61a7Syz /* Send req to video control interface to get ctrl */ 3498*c77a61a7Syz int 3499*c77a61a7Syz usbvc_vc_set_ctrl(usbvc_state_t *usbvcp, uint8_t req_code, uint8_t entity_id, 3500*c77a61a7Syz uint16_t cs, uint16_t wlength, mblk_t *data) 3501*c77a61a7Syz { 3502*c77a61a7Syz usb_cb_flags_t cb_flags; 3503*c77a61a7Syz usb_cr_t cr; 3504*c77a61a7Syz usb_ctrl_setup_t setup; 3505*c77a61a7Syz 3506*c77a61a7Syz setup.bmRequestType = USBVC_SET_IF; /* bmRequestType */ 3507*c77a61a7Syz setup.bRequest = req_code; /* bRequest */ 3508*c77a61a7Syz setup.wValue = cs<<8; 3509*c77a61a7Syz setup.wIndex = entity_id<<8; 3510*c77a61a7Syz setup.wLength = wlength; 3511*c77a61a7Syz setup.attrs = 0; 3512*c77a61a7Syz 3513*c77a61a7Syz if (usb_pipe_ctrl_xfer_wait(usbvcp->usbvc_default_ph, &setup, &data, 3514*c77a61a7Syz &cr, &cb_flags, 0) != USB_SUCCESS) { 3515*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3516*c77a61a7Syz "usbvc_vc_set_ctrl: cmd failed, cr=%d, cb_flags=%x", 3517*c77a61a7Syz cr, cb_flags); 3518*c77a61a7Syz 3519*c77a61a7Syz return (USB_FAILURE); 3520*c77a61a7Syz } 3521*c77a61a7Syz 3522*c77a61a7Syz return (USB_SUCCESS); 3523*c77a61a7Syz } 3524*c77a61a7Syz 3525*c77a61a7Syz 3526*c77a61a7Syz /* Set probe or commit ctrl for video stream interface */ 3527*c77a61a7Syz int 3528*c77a61a7Syz usbvc_vs_set_probe_commit(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if, 3529*c77a61a7Syz usbvc_vs_probe_commit_t *ctrl_pc, uchar_t cs) 3530*c77a61a7Syz { 3531*c77a61a7Syz mblk_t *data; 3532*c77a61a7Syz usb_cb_flags_t cb_flags; 3533*c77a61a7Syz usb_cr_t cr; 3534*c77a61a7Syz usb_ctrl_setup_t setup; 3535*c77a61a7Syz int rval; 3536*c77a61a7Syz 3537*c77a61a7Syz setup.bmRequestType = USBVC_SET_IF; /* bmRequestType */ 3538*c77a61a7Syz setup.bRequest = SET_CUR; /* bRequest */ 3539*c77a61a7Syz 3540*c77a61a7Syz /* wValue, VS_PROBE_CONTROL or VS_COMMIT_CONTROL */ 3541*c77a61a7Syz setup.wValue = cs; 3542*c77a61a7Syz 3543*c77a61a7Syz /* UVC Spec: this value must be put to the high byte */ 3544*c77a61a7Syz setup.wValue = setup.wValue << 8; 3545*c77a61a7Syz 3546*c77a61a7Syz setup.wIndex = strm_if->if_descr->if_alt->altif_descr.bInterfaceNumber; 3547*c77a61a7Syz setup.wLength = usbvcp->usbvc_vc_header->descr->bcdUVC[0] ? 34 : 26; 3548*c77a61a7Syz setup.attrs = 0; 3549*c77a61a7Syz 3550*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3551*c77a61a7Syz "usbvc_vs_set_probe_commit: wLength=%d", setup.wLength); 3552*c77a61a7Syz 3553*c77a61a7Syz /* Data block */ 3554*c77a61a7Syz if ((data = allocb(setup.wLength, BPRI_HI)) == NULL) { 3555*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3556*c77a61a7Syz "usbvc_vs_set_probe_commit: allocb failed"); 3557*c77a61a7Syz 3558*c77a61a7Syz return (USB_FAILURE); 3559*c77a61a7Syz } 3560*c77a61a7Syz 3561*c77a61a7Syz bcopy(ctrl_pc, data->b_rptr, setup.wLength); 3562*c77a61a7Syz data->b_wptr += setup.wLength; 3563*c77a61a7Syz 3564*c77a61a7Syz if ((rval = usb_pipe_ctrl_xfer_wait(usbvcp->usbvc_default_ph, &setup, 3565*c77a61a7Syz &data, &cr, &cb_flags, 0)) != USB_SUCCESS) { 3566*c77a61a7Syz if (data) { 3567*c77a61a7Syz freemsg(data); 3568*c77a61a7Syz } 3569*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3570*c77a61a7Syz "usbvc_vs_set_probe_commit: fail, rval=%d, cr=%d, " 3571*c77a61a7Syz "cb_flags=%x", rval, cr, cb_flags); 3572*c77a61a7Syz 3573*c77a61a7Syz return (rval); 3574*c77a61a7Syz } 3575*c77a61a7Syz if (data) { 3576*c77a61a7Syz freemsg(data); 3577*c77a61a7Syz } 3578*c77a61a7Syz 3579*c77a61a7Syz return (USB_SUCCESS); 3580*c77a61a7Syz } 3581*c77a61a7Syz 3582*c77a61a7Syz 3583*c77a61a7Syz /* Get probe ctrl for vodeo stream interface */ 3584*c77a61a7Syz int 3585*c77a61a7Syz usbvc_vs_get_probe(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if, 3586*c77a61a7Syz usbvc_vs_probe_commit_t *ctrl_pc, uchar_t bRequest) 3587*c77a61a7Syz { 3588*c77a61a7Syz mblk_t *data = NULL; 3589*c77a61a7Syz usb_cb_flags_t cb_flags; 3590*c77a61a7Syz usb_cr_t cr; 3591*c77a61a7Syz usb_ctrl_setup_t setup; 3592*c77a61a7Syz 3593*c77a61a7Syz setup.bmRequestType = USBVC_GET_IF; /* bmRequestType */ 3594*c77a61a7Syz setup.bRequest = bRequest; /* bRequest */ 3595*c77a61a7Syz setup.wValue = VS_PROBE_CONTROL; /* wValue, PROBE or COMMIT */ 3596*c77a61a7Syz setup.wValue = setup.wValue << 8; 3597*c77a61a7Syz setup.wIndex = 3598*c77a61a7Syz (uint16_t)strm_if->if_descr->if_alt->altif_descr.bInterfaceNumber; 3599*c77a61a7Syz setup.wLength = usbvcp->usbvc_vc_header->descr->bcdUVC[0] ? 34 : 26; 3600*c77a61a7Syz 3601*c77a61a7Syz setup.attrs = 0; 3602*c77a61a7Syz 3603*c77a61a7Syz if (usb_pipe_ctrl_xfer_wait(usbvcp->usbvc_default_ph, &setup, &data, 3604*c77a61a7Syz &cr, &cb_flags, 0) != USB_SUCCESS) { 3605*c77a61a7Syz if (data) { 3606*c77a61a7Syz freemsg(data); 3607*c77a61a7Syz } 3608*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3609*c77a61a7Syz "usbvc_vs_get_probe: cmd failed, cr=%d, cb_flags=%x", 3610*c77a61a7Syz cr, cb_flags); 3611*c77a61a7Syz 3612*c77a61a7Syz return (USB_FAILURE); 3613*c77a61a7Syz } 3614*c77a61a7Syz bcopy(data->b_rptr, ctrl_pc, setup.wLength); 3615*c77a61a7Syz if (data) { 3616*c77a61a7Syz freemsg(data); 3617*c77a61a7Syz } 3618*c77a61a7Syz 3619*c77a61a7Syz return (USB_SUCCESS); 3620*c77a61a7Syz } 3621*c77a61a7Syz 3622*c77a61a7Syz 3623*c77a61a7Syz /* Set a default format when open the device */ 3624*c77a61a7Syz static int 3625*c77a61a7Syz usbvc_set_default_stream_fmt(usbvc_state_t *usbvcp) 3626*c77a61a7Syz { 3627*c77a61a7Syz usbvc_vs_probe_commit_t ctrl, ctrl_get; 3628*c77a61a7Syz usbvc_stream_if_t *strm_if; 3629*c77a61a7Syz usbvc_format_group_t *curr_fmtgrp; 3630*c77a61a7Syz uint32_t bandwidth; 3631*c77a61a7Syz uint8_t index, i; 3632*c77a61a7Syz 3633*c77a61a7Syz USB_DPRINTF_L4(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3634*c77a61a7Syz "usbvc_set_default_stream_fmt: enter"); 3635*c77a61a7Syz 3636*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 3637*c77a61a7Syz if (list_is_empty(&usbvcp->usbvc_stream_list)) { 3638*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3639*c77a61a7Syz "usbvc_set_default_stream_fmt: no stream interface, fail"); 3640*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3641*c77a61a7Syz 3642*c77a61a7Syz return (USB_FAILURE); 3643*c77a61a7Syz } 3644*c77a61a7Syz bzero((void *)&ctrl, sizeof (usbvc_vs_probe_commit_t)); 3645*c77a61a7Syz 3646*c77a61a7Syz /* Get the current stream interface */ 3647*c77a61a7Syz strm_if = usbvcp->usbvc_curr_strm; 3648*c77a61a7Syz 3649*c77a61a7Syz /* Fill the probe commit req data */ 3650*c77a61a7Syz ctrl.bmHint[0] = 0; 3651*c77a61a7Syz 3652*c77a61a7Syz for (i = 0; i < strm_if->fmtgrp_cnt; i++) { 3653*c77a61a7Syz curr_fmtgrp = &strm_if->format_group[i]; 3654*c77a61a7Syz 3655*c77a61a7Syz /* 3656*c77a61a7Syz * If v4l2_pixelformat is NULL, then that means there is not 3657*c77a61a7Syz * a parsed format in format_group[i]. 3658*c77a61a7Syz */ 3659*c77a61a7Syz if (!curr_fmtgrp || !curr_fmtgrp->v4l2_pixelformat || 3660*c77a61a7Syz curr_fmtgrp->frame_cnt == 0) { 3661*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, 3662*c77a61a7Syz usbvcp->usbvc_log_handle, 3663*c77a61a7Syz "usbvc_set_default_stream_fmt: no frame, fail"); 3664*c77a61a7Syz 3665*c77a61a7Syz continue; 3666*c77a61a7Syz } else { 3667*c77a61a7Syz 3668*c77a61a7Syz break; 3669*c77a61a7Syz } 3670*c77a61a7Syz } 3671*c77a61a7Syz if (!curr_fmtgrp || curr_fmtgrp->frame_cnt == 0) { 3672*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3673*c77a61a7Syz "usbvc_set_default_stream_fmt: can't find a fmtgrp" 3674*c77a61a7Syz "which has a frame, fail"); 3675*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3676*c77a61a7Syz 3677*c77a61a7Syz return (USB_FAILURE); 3678*c77a61a7Syz } 3679*c77a61a7Syz 3680*c77a61a7Syz ctrl.bFormatIndex = curr_fmtgrp->format->bFormatIndex; 3681*c77a61a7Syz 3682*c77a61a7Syz /* use the first frame descr as default */ 3683*c77a61a7Syz ctrl.bFrameIndex = curr_fmtgrp->frames[0].descr->bFrameIndex; 3684*c77a61a7Syz 3685*c77a61a7Syz /* use bcopy to keep the byte sequence as 32 bit little endian */ 3686*c77a61a7Syz bcopy(&(curr_fmtgrp->frames[0].descr->dwDefaultFrameInterval[0]), 3687*c77a61a7Syz &(ctrl.dwFrameInterval[0]), 4); 3688*c77a61a7Syz 3689*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3690*c77a61a7Syz if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl, VS_PROBE_CONTROL) 3691*c77a61a7Syz != USB_SUCCESS) { 3692*c77a61a7Syz 3693*c77a61a7Syz return (USB_FAILURE); 3694*c77a61a7Syz } 3695*c77a61a7Syz if (usbvc_vs_get_probe(usbvcp, strm_if, &ctrl_get, GET_CUR) 3696*c77a61a7Syz != USB_SUCCESS) { 3697*c77a61a7Syz 3698*c77a61a7Syz return (USB_FAILURE); 3699*c77a61a7Syz } 3700*c77a61a7Syz 3701*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 3702*c77a61a7Syz LE_TO_UINT32(strm_if->ctrl_pc.dwMaxPayloadTransferSize, 0, bandwidth); 3703*c77a61a7Syz USB_DPRINTF_L3(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3704*c77a61a7Syz "usbvc_set_default_stream_fmt: get bandwidth=%x", bandwidth); 3705*c77a61a7Syz 3706*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3707*c77a61a7Syz if (usbvc_vs_set_probe_commit(usbvcp, strm_if, &ctrl_get, 3708*c77a61a7Syz VS_COMMIT_CONTROL) != USB_SUCCESS) { 3709*c77a61a7Syz 3710*c77a61a7Syz return (USB_FAILURE); 3711*c77a61a7Syz } 3712*c77a61a7Syz 3713*c77a61a7Syz mutex_enter(&usbvcp->usbvc_mutex); 3714*c77a61a7Syz 3715*c77a61a7Syz /* it's good to check index here before use it */ 3716*c77a61a7Syz index = ctrl_get.bFormatIndex - curr_fmtgrp->format->bFormatIndex; 3717*c77a61a7Syz if (index < strm_if->fmtgrp_cnt) { 3718*c77a61a7Syz strm_if->cur_format_group = &strm_if->format_group[index]; 3719*c77a61a7Syz } else { 3720*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3721*c77a61a7Syz "usbvc_set_default_stream_fmt: format index out of range"); 3722*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3723*c77a61a7Syz 3724*c77a61a7Syz return (USB_FAILURE); 3725*c77a61a7Syz } 3726*c77a61a7Syz 3727*c77a61a7Syz index = ctrl_get.bFrameIndex - 3728*c77a61a7Syz strm_if->cur_format_group->frames[0].descr->bFrameIndex; 3729*c77a61a7Syz if (index < strm_if->cur_format_group->frame_cnt) { 3730*c77a61a7Syz strm_if->cur_format_group->cur_frame = 3731*c77a61a7Syz &strm_if->cur_format_group->frames[index]; 3732*c77a61a7Syz } else { 3733*c77a61a7Syz USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, usbvcp->usbvc_log_handle, 3734*c77a61a7Syz "usbvc_set_default_stream: frame index out of range"); 3735*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3736*c77a61a7Syz 3737*c77a61a7Syz return (USB_FAILURE); 3738*c77a61a7Syz } 3739*c77a61a7Syz 3740*c77a61a7Syz /* 3741*c77a61a7Syz * by now, the video format is set successfully. record the current 3742*c77a61a7Syz * setting to strm_if->ctrl_pc 3743*c77a61a7Syz */ 3744*c77a61a7Syz bcopy(&ctrl_get, &strm_if->ctrl_pc, sizeof (usbvc_vs_probe_commit_t)); 3745*c77a61a7Syz 3746*c77a61a7Syz mutex_exit(&usbvcp->usbvc_mutex); 3747*c77a61a7Syz 3748*c77a61a7Syz return (USB_SUCCESS); 3749*c77a61a7Syz } 3750