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