1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate * 22*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 23*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 24*7c478bd9Sstevel@tonic-gate */ 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate /* 29*7c478bd9Sstevel@tonic-gate * UGEN: USB Generic Driver support code 30*7c478bd9Sstevel@tonic-gate * 31*7c478bd9Sstevel@tonic-gate * This code provides entry points called by the ugen driver or other 32*7c478bd9Sstevel@tonic-gate * drivers that want to export a ugen interface 33*7c478bd9Sstevel@tonic-gate * 34*7c478bd9Sstevel@tonic-gate * The "Universal Generic Driver" (UGEN) for USB devices provides interfaces 35*7c478bd9Sstevel@tonic-gate * to talk to USB devices. This is very useful for Point of Sale sale 36*7c478bd9Sstevel@tonic-gate * devices and other simple devices like USB scanner, USB palm pilot. 37*7c478bd9Sstevel@tonic-gate * The UGEN provides a system call interface to USB devices enabling 38*7c478bd9Sstevel@tonic-gate * a USB device vendor to write an application for his 39*7c478bd9Sstevel@tonic-gate * device instead of writing a driver. This facilitates the vendor to write 40*7c478bd9Sstevel@tonic-gate * device management s/w quickly in userland. 41*7c478bd9Sstevel@tonic-gate * 42*7c478bd9Sstevel@tonic-gate * UGEN supports read/write/poll entry points. An application can be written 43*7c478bd9Sstevel@tonic-gate * using read/write/aioread/aiowrite/poll system calls to communicate 44*7c478bd9Sstevel@tonic-gate * with the device. 45*7c478bd9Sstevel@tonic-gate * 46*7c478bd9Sstevel@tonic-gate * XXX Theory of Operations 47*7c478bd9Sstevel@tonic-gate */ 48*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate #include "sys/usb/clients/ugen/usb_ugen.h" 53*7c478bd9Sstevel@tonic-gate #include "sys/usb/usba/usba_ugen.h" 54*7c478bd9Sstevel@tonic-gate #include "sys/usb/usba/usba_ugend.h" 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate /* Debugging information */ 57*7c478bd9Sstevel@tonic-gate static uint_t ugen_errmask = (uint_t)UGEN_PRINT_ALL; 58*7c478bd9Sstevel@tonic-gate static uint_t ugen_errlevel = USB_LOG_L4; 59*7c478bd9Sstevel@tonic-gate static uint_t ugen_instance_debug = (uint_t)-1; 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate /* default endpoint descriptor */ 62*7c478bd9Sstevel@tonic-gate static usb_ep_descr_t ugen_default_ep_descr = 63*7c478bd9Sstevel@tonic-gate {7, 5, 0, USB_EP_ATTR_CONTROL, 8, 0}; 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate /* tunables */ 66*7c478bd9Sstevel@tonic-gate static int ugen_busy_loop = 60; /* secs */ 67*7c478bd9Sstevel@tonic-gate static int ugen_ctrl_timeout = 10; 68*7c478bd9Sstevel@tonic-gate static int ugen_bulk_timeout = 10; 69*7c478bd9Sstevel@tonic-gate static int ugen_intr_timeout = 10; 70*7c478bd9Sstevel@tonic-gate static int ugen_enable_pm = 0; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate /* local function prototypes */ 74*7c478bd9Sstevel@tonic-gate static int ugen_cleanup(ugen_state_t *); 75*7c478bd9Sstevel@tonic-gate static int ugen_cpr_suspend(ugen_state_t *); 76*7c478bd9Sstevel@tonic-gate static void ugen_cpr_resume(ugen_state_t *); 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate static void ugen_restore_state(ugen_state_t *); 79*7c478bd9Sstevel@tonic-gate static int ugen_check_open_flags(ugen_state_t *, dev_t, int); 80*7c478bd9Sstevel@tonic-gate static int ugen_strategy(struct buf *); 81*7c478bd9Sstevel@tonic-gate static void ugen_minphys(struct buf *); 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate static void ugen_pm_init(ugen_state_t *); 84*7c478bd9Sstevel@tonic-gate static void ugen_pm_destroy(ugen_state_t *); 85*7c478bd9Sstevel@tonic-gate static void ugen_pm_busy_component(ugen_state_t *); 86*7c478bd9Sstevel@tonic-gate static void ugen_pm_idle_component(ugen_state_t *); 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate /* endpoint xfer and status management */ 89*7c478bd9Sstevel@tonic-gate static int ugen_epxs_init(ugen_state_t *); 90*7c478bd9Sstevel@tonic-gate static void ugen_epxs_destroy(ugen_state_t *); 91*7c478bd9Sstevel@tonic-gate static int ugen_epxs_data_init(ugen_state_t *, usb_ep_data_t *, 92*7c478bd9Sstevel@tonic-gate uchar_t, uchar_t, uchar_t, uchar_t); 93*7c478bd9Sstevel@tonic-gate static void ugen_epxs_data_destroy(ugen_state_t *, ugen_ep_t *); 94*7c478bd9Sstevel@tonic-gate static int ugen_epxs_minor_nodes_create(ugen_state_t *, 95*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *, uchar_t, 96*7c478bd9Sstevel@tonic-gate uchar_t, uchar_t, uchar_t); 97*7c478bd9Sstevel@tonic-gate static int ugen_epxs_check_open_nodes(ugen_state_t *); 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate static int ugen_epx_open(ugen_state_t *, dev_t, int); 100*7c478bd9Sstevel@tonic-gate static void ugen_epx_close(ugen_state_t *, dev_t, int); 101*7c478bd9Sstevel@tonic-gate static void ugen_epx_shutdown(ugen_state_t *); 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate static int ugen_epx_open_pipe(ugen_state_t *, ugen_ep_t *, int); 104*7c478bd9Sstevel@tonic-gate static void ugen_epx_close_pipe(ugen_state_t *, ugen_ep_t *); 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate static int ugen_epx_req(ugen_state_t *, struct buf *); 107*7c478bd9Sstevel@tonic-gate static int ugen_epx_ctrl_req(ugen_state_t *, ugen_ep_t *, 108*7c478bd9Sstevel@tonic-gate struct buf *, boolean_t *); 109*7c478bd9Sstevel@tonic-gate static void ugen_epx_ctrl_req_cb(usb_pipe_handle_t, usb_ctrl_req_t *); 110*7c478bd9Sstevel@tonic-gate static int ugen_epx_bulk_req(ugen_state_t *, ugen_ep_t *, 111*7c478bd9Sstevel@tonic-gate struct buf *, boolean_t *); 112*7c478bd9Sstevel@tonic-gate static void ugen_epx_bulk_req_cb(usb_pipe_handle_t, usb_bulk_req_t *); 113*7c478bd9Sstevel@tonic-gate static int ugen_epx_intr_IN_req(ugen_state_t *, ugen_ep_t *, 114*7c478bd9Sstevel@tonic-gate struct buf *, boolean_t *); 115*7c478bd9Sstevel@tonic-gate static int ugen_epx_intr_IN_start_polling(ugen_state_t *, ugen_ep_t *); 116*7c478bd9Sstevel@tonic-gate static void ugen_epx_intr_IN_stop_polling(ugen_state_t *, ugen_ep_t *); 117*7c478bd9Sstevel@tonic-gate static void ugen_epx_intr_IN_req_cb(usb_pipe_handle_t, usb_intr_req_t *); 118*7c478bd9Sstevel@tonic-gate static int ugen_epx_intr_OUT_req(ugen_state_t *, ugen_ep_t *, 119*7c478bd9Sstevel@tonic-gate struct buf *, boolean_t *); 120*7c478bd9Sstevel@tonic-gate static void ugen_epx_intr_OUT_req_cb(usb_pipe_handle_t, usb_intr_req_t *); 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate static int ugen_eps_open(ugen_state_t *, dev_t, int); 123*7c478bd9Sstevel@tonic-gate static void ugen_eps_close(ugen_state_t *, dev_t, int); 124*7c478bd9Sstevel@tonic-gate static int ugen_eps_req(ugen_state_t *, struct buf *); 125*7c478bd9Sstevel@tonic-gate static void ugen_update_ep_descr(ugen_state_t *, ugen_ep_t *); 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate /* device status management */ 128*7c478bd9Sstevel@tonic-gate static int ugen_ds_init(ugen_state_t *); 129*7c478bd9Sstevel@tonic-gate static void ugen_ds_destroy(ugen_state_t *); 130*7c478bd9Sstevel@tonic-gate static int ugen_ds_open(ugen_state_t *, dev_t, int); 131*7c478bd9Sstevel@tonic-gate static void ugen_ds_close(ugen_state_t *, dev_t, int); 132*7c478bd9Sstevel@tonic-gate static int ugen_ds_req(ugen_state_t *, struct buf *); 133*7c478bd9Sstevel@tonic-gate static void ugen_ds_change(ugen_state_t *); 134*7c478bd9Sstevel@tonic-gate static int ugen_ds_minor_nodes_create(ugen_state_t *); 135*7c478bd9Sstevel@tonic-gate static void ugen_ds_poll_wakeup(ugen_state_t *); 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate /* utility functions */ 138*7c478bd9Sstevel@tonic-gate static int ugen_minor_index_create(ugen_state_t *, ugen_minor_t); 139*7c478bd9Sstevel@tonic-gate static ugen_minor_t ugen_devt2minor(ugen_state_t *, dev_t); 140*7c478bd9Sstevel@tonic-gate static void ugen_minor_node_table_create(ugen_state_t *); 141*7c478bd9Sstevel@tonic-gate static void ugen_minor_node_table_destroy(ugen_state_t *); 142*7c478bd9Sstevel@tonic-gate static void ugen_minor_node_table_shrink(ugen_state_t *); 143*7c478bd9Sstevel@tonic-gate static int ugen_cr2lcstat(int); 144*7c478bd9Sstevel@tonic-gate static void ugen_check_mask(uint_t, uint_t *, uint_t *); 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate static kmutex_t ugen_devt_list_mutex; 147*7c478bd9Sstevel@tonic-gate static ugen_devt_list_entry_t ugen_devt_list; 148*7c478bd9Sstevel@tonic-gate static ugen_devt_cache_entry_t ugen_devt_cache[UGEN_DEVT_CACHE_SIZE]; 149*7c478bd9Sstevel@tonic-gate static uint_t ugen_devt_cache_index; 150*7c478bd9Sstevel@tonic-gate static void ugen_store_devt(ugen_state_t *, minor_t); 151*7c478bd9Sstevel@tonic-gate static ugen_state_t *ugen_devt2state(dev_t); 152*7c478bd9Sstevel@tonic-gate static void ugen_free_devt(ugen_state_t *); 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* 155*7c478bd9Sstevel@tonic-gate * usb_ugen entry points 156*7c478bd9Sstevel@tonic-gate * 157*7c478bd9Sstevel@tonic-gate * usb_ugen_get_hdl: 158*7c478bd9Sstevel@tonic-gate * allocate and initialize handle 159*7c478bd9Sstevel@tonic-gate */ 160*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_t 161*7c478bd9Sstevel@tonic-gate usb_ugen_get_hdl(dev_info_t *dip, usb_ugen_info_t *usb_ugen_info) 162*7c478bd9Sstevel@tonic-gate { 163*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_impl_t *hdl = kmem_zalloc(sizeof (*hdl), KM_SLEEP); 164*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp = kmem_zalloc(sizeof (ugen_state_t), 165*7c478bd9Sstevel@tonic-gate KM_SLEEP); 166*7c478bd9Sstevel@tonic-gate uint_t len, shift, limit; 167*7c478bd9Sstevel@tonic-gate int rval; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate hdl->hdl_ugenp = ugenp; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate /* masks may not overlap */ 172*7c478bd9Sstevel@tonic-gate if (usb_ugen_info->usb_ugen_minor_node_ugen_bits_mask & 173*7c478bd9Sstevel@tonic-gate usb_ugen_info->usb_ugen_minor_node_instance_mask) { 174*7c478bd9Sstevel@tonic-gate usb_ugen_release_hdl((usb_ugen_hdl_t)hdl); 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate return (NULL); 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate if ((rval = usb_get_dev_data(dip, &ugenp->ug_dev_data, 180*7c478bd9Sstevel@tonic-gate usb_owns_device(dip) ? USB_PARSE_LVL_ALL : USB_PARSE_LVL_IF, 181*7c478bd9Sstevel@tonic-gate 0)) != USB_SUCCESS) { 182*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 183*7c478bd9Sstevel@tonic-gate "usb_ugen_attach: usb_get_dev_data failed, rval=%d", rval); 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate return (NULL); 186*7c478bd9Sstevel@tonic-gate } 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate /* Initialize state structure for this instance */ 189*7c478bd9Sstevel@tonic-gate mutex_init(&ugenp->ug_mutex, NULL, MUTEX_DRIVER, 190*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_data->dev_iblock_cookie); 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 193*7c478bd9Sstevel@tonic-gate ugenp->ug_dip = dip; 194*7c478bd9Sstevel@tonic-gate ugenp->ug_instance = ddi_get_instance(dip); 195*7c478bd9Sstevel@tonic-gate ugenp->ug_hdl = hdl; 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate /* Allocate a log handle for debug/error messages */ 198*7c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(dip), "ugen") != 0) { 199*7c478bd9Sstevel@tonic-gate char *name; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate len = strlen(ddi_driver_name(dip)) + sizeof ("_ugen") + 1; 202*7c478bd9Sstevel@tonic-gate name = kmem_alloc(len, KM_SLEEP); 203*7c478bd9Sstevel@tonic-gate (void) snprintf(name, len, "%s_ugen", ddi_driver_name(dip)); 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate ugenp->ug_log_hdl = usb_alloc_log_hdl(dip, name, &ugen_errlevel, 206*7c478bd9Sstevel@tonic-gate &ugen_errmask, &ugen_instance_debug, 0); 207*7c478bd9Sstevel@tonic-gate hdl->hdl_log_name = name; 208*7c478bd9Sstevel@tonic-gate hdl->hdl_log_name_length = len; 209*7c478bd9Sstevel@tonic-gate } else { 210*7c478bd9Sstevel@tonic-gate ugenp->ug_log_hdl = usb_alloc_log_hdl(dip, "ugen", 211*7c478bd9Sstevel@tonic-gate &ugen_errlevel, 212*7c478bd9Sstevel@tonic-gate &ugen_errmask, &ugen_instance_debug, 0); 213*7c478bd9Sstevel@tonic-gate } 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate hdl->hdl_dip = dip; 216*7c478bd9Sstevel@tonic-gate hdl->hdl_flags = usb_ugen_info->usb_ugen_flags; 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate ugen_check_mask(usb_ugen_info->usb_ugen_minor_node_ugen_bits_mask, 219*7c478bd9Sstevel@tonic-gate &shift, &limit); 220*7c478bd9Sstevel@tonic-gate if (limit == 0) { 221*7c478bd9Sstevel@tonic-gate usb_ugen_release_hdl((usb_ugen_hdl_t)hdl); 222*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate return (NULL); 225*7c478bd9Sstevel@tonic-gate } 226*7c478bd9Sstevel@tonic-gate hdl->hdl_minor_node_ugen_bits_mask = usb_ugen_info-> 227*7c478bd9Sstevel@tonic-gate usb_ugen_minor_node_ugen_bits_mask; 228*7c478bd9Sstevel@tonic-gate hdl->hdl_minor_node_ugen_bits_shift = shift; 229*7c478bd9Sstevel@tonic-gate hdl->hdl_minor_node_ugen_bits_limit = limit; 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate ugen_check_mask(usb_ugen_info->usb_ugen_minor_node_instance_mask, 232*7c478bd9Sstevel@tonic-gate &shift, &limit); 233*7c478bd9Sstevel@tonic-gate if (limit == 0) { 234*7c478bd9Sstevel@tonic-gate usb_ugen_release_hdl((usb_ugen_hdl_t)hdl); 235*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate return (NULL); 238*7c478bd9Sstevel@tonic-gate } 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate hdl->hdl_minor_node_instance_mask = usb_ugen_info-> 241*7c478bd9Sstevel@tonic-gate usb_ugen_minor_node_instance_mask; 242*7c478bd9Sstevel@tonic-gate hdl->hdl_minor_node_instance_shift = shift; 243*7c478bd9Sstevel@tonic-gate hdl->hdl_minor_node_instance_limit = limit; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 246*7c478bd9Sstevel@tonic-gate "usb_ugen_get_hdl: instance shift=%d instance limit=%d", 247*7c478bd9Sstevel@tonic-gate hdl->hdl_minor_node_instance_shift, 248*7c478bd9Sstevel@tonic-gate hdl->hdl_minor_node_instance_limit); 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 251*7c478bd9Sstevel@tonic-gate "usb_ugen_get_hdl: bits shift=%d bits limit=%d", 252*7c478bd9Sstevel@tonic-gate hdl->hdl_minor_node_ugen_bits_shift, 253*7c478bd9Sstevel@tonic-gate hdl->hdl_minor_node_ugen_bits_limit); 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate return ((usb_ugen_hdl_t)hdl); 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate /* 262*7c478bd9Sstevel@tonic-gate * usb_ugen_release_hdl: 263*7c478bd9Sstevel@tonic-gate * deallocate a handle 264*7c478bd9Sstevel@tonic-gate */ 265*7c478bd9Sstevel@tonic-gate void 266*7c478bd9Sstevel@tonic-gate usb_ugen_release_hdl(usb_ugen_hdl_t usb_ugen_hdl) 267*7c478bd9Sstevel@tonic-gate { 268*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 269*7c478bd9Sstevel@tonic-gate (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate if (usb_ugen_hdl_impl) { 272*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp = usb_ugen_hdl_impl->hdl_ugenp; 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate if (ugenp) { 275*7c478bd9Sstevel@tonic-gate mutex_destroy(&ugenp->ug_mutex); 276*7c478bd9Sstevel@tonic-gate usb_free_log_hdl(ugenp->ug_log_hdl); 277*7c478bd9Sstevel@tonic-gate usb_free_dev_data(usb_ugen_hdl_impl->hdl_dip, 278*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_data); 279*7c478bd9Sstevel@tonic-gate kmem_free(ugenp, sizeof (*ugenp)); 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate if (usb_ugen_hdl_impl->hdl_log_name) { 282*7c478bd9Sstevel@tonic-gate kmem_free(usb_ugen_hdl_impl->hdl_log_name, 283*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_impl->hdl_log_name_length); 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate kmem_free(usb_ugen_hdl_impl, sizeof (*usb_ugen_hdl_impl)); 286*7c478bd9Sstevel@tonic-gate } 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate /* 291*7c478bd9Sstevel@tonic-gate * usb_ugen_attach() 292*7c478bd9Sstevel@tonic-gate */ 293*7c478bd9Sstevel@tonic-gate int 294*7c478bd9Sstevel@tonic-gate usb_ugen_attach(usb_ugen_hdl_t usb_ugen_hdl, ddi_attach_cmd_t cmd) 295*7c478bd9Sstevel@tonic-gate { 296*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 297*7c478bd9Sstevel@tonic-gate (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 298*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp; 299*7c478bd9Sstevel@tonic-gate dev_info_t *dip; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate if (usb_ugen_hdl == NULL) { 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 304*7c478bd9Sstevel@tonic-gate } 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate ugenp = usb_ugen_hdl_impl->hdl_ugenp; 307*7c478bd9Sstevel@tonic-gate dip = usb_ugen_hdl_impl->hdl_dip; 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 311*7c478bd9Sstevel@tonic-gate "usb_ugen_attach: cmd=%d", cmd); 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate switch (cmd) { 314*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate break; 317*7c478bd9Sstevel@tonic-gate case DDI_RESUME: 318*7c478bd9Sstevel@tonic-gate ugen_cpr_resume(ugenp); 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 321*7c478bd9Sstevel@tonic-gate default: 322*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_ATTA, NULL, 323*7c478bd9Sstevel@tonic-gate "usb_ugen_attach: unknown command"); 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 326*7c478bd9Sstevel@tonic-gate } 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 329*7c478bd9Sstevel@tonic-gate ugenp->ug_ser_cookie = 330*7c478bd9Sstevel@tonic-gate usb_init_serialization(dip, USB_INIT_SER_CHECK_SAME_THREAD); 331*7c478bd9Sstevel@tonic-gate ugenp->ug_cleanup_flags |= UGEN_INIT_LOCKS; 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate /* Get maximum bulk transfer size supported by the HCD */ 334*7c478bd9Sstevel@tonic-gate if (usb_pipe_get_max_bulk_transfer_size(dip, 335*7c478bd9Sstevel@tonic-gate &ugenp->ug_max_bulk_xfer_sz) != USB_SUCCESS) { 336*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 337*7c478bd9Sstevel@tonic-gate "usb_ugen_attach: Getting max bulk xfer sz failed"); 338*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate goto fail; 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate /* table for mapping 48 bit minor codes to 9 bit index (for ugen) */ 344*7c478bd9Sstevel@tonic-gate ugen_minor_node_table_create(ugenp); 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate /* prepare device status node handling */ 347*7c478bd9Sstevel@tonic-gate if (ugen_ds_init(ugenp) != USB_SUCCESS) { 348*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 349*7c478bd9Sstevel@tonic-gate "usb_ugen_attach: preparing dev status failed"); 350*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate goto fail; 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate /* prepare all available xfer and status endpoints nodes */ 356*7c478bd9Sstevel@tonic-gate if (ugen_epxs_init(ugenp) != USB_SUCCESS) { 357*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 358*7c478bd9Sstevel@tonic-gate "usb_ugen_attach: preparing endpoints failed"); 359*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate goto fail; 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate /* reduce table size if not all entries are used */ 365*7c478bd9Sstevel@tonic-gate ugen_minor_node_table_shrink(ugenp); 366*7c478bd9Sstevel@tonic-gate 367*7c478bd9Sstevel@tonic-gate /* we are ready to go */ 368*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_state = USB_DEV_ONLINE; 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate /* prepare PM */ 373*7c478bd9Sstevel@tonic-gate if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 374*7c478bd9Sstevel@tonic-gate ugen_pm_init(ugenp); 375*7c478bd9Sstevel@tonic-gate } 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate /* 378*7c478bd9Sstevel@tonic-gate * if ugen driver, kill all child nodes otherwise set cfg fails 379*7c478bd9Sstevel@tonic-gate * if requested 380*7c478bd9Sstevel@tonic-gate */ 381*7c478bd9Sstevel@tonic-gate if (usb_owns_device(dip) && 382*7c478bd9Sstevel@tonic-gate (usb_ugen_hdl_impl->hdl_flags & USB_UGEN_REMOVE_CHILDREN)) { 383*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate /* save cfgidx so we can restore on detach */ 386*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 387*7c478bd9Sstevel@tonic-gate ugenp->ug_initial_cfgidx = usb_get_current_cfgidx(dip); 388*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate for (cdip = ddi_get_child(dip); cdip; ) { 391*7c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 392*7c478bd9Sstevel@tonic-gate (void) ddi_remove_child(cdip, 0); 393*7c478bd9Sstevel@tonic-gate cdip = next; 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 398*7c478bd9Sstevel@tonic-gate fail: 399*7c478bd9Sstevel@tonic-gate if (ugenp) { 400*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 401*7c478bd9Sstevel@tonic-gate "attach fail"); 402*7c478bd9Sstevel@tonic-gate (void) ugen_cleanup(ugenp); 403*7c478bd9Sstevel@tonic-gate } 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate /* 410*7c478bd9Sstevel@tonic-gate * usb_ugen_detach() 411*7c478bd9Sstevel@tonic-gate */ 412*7c478bd9Sstevel@tonic-gate int 413*7c478bd9Sstevel@tonic-gate usb_ugen_detach(usb_ugen_hdl_t usb_ugen_hdl, ddi_detach_cmd_t cmd) 414*7c478bd9Sstevel@tonic-gate { 415*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 416*7c478bd9Sstevel@tonic-gate (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 417*7c478bd9Sstevel@tonic-gate int rval = USB_FAILURE; 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate if (usb_ugen_hdl) { 420*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp = usb_ugen_hdl_impl->hdl_ugenp; 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 423*7c478bd9Sstevel@tonic-gate "usb_ugen_detach cmd %d", cmd); 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate switch (cmd) { 426*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 427*7c478bd9Sstevel@tonic-gate rval = ugen_cleanup(ugenp); 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate break; 430*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 431*7c478bd9Sstevel@tonic-gate rval = ugen_cpr_suspend(ugenp); 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate break; 434*7c478bd9Sstevel@tonic-gate default: 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate break; 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate return (rval); 441*7c478bd9Sstevel@tonic-gate } 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate /* 445*7c478bd9Sstevel@tonic-gate * ugen_cleanup() 446*7c478bd9Sstevel@tonic-gate */ 447*7c478bd9Sstevel@tonic-gate static int 448*7c478bd9Sstevel@tonic-gate ugen_cleanup(ugen_state_t *ugenp) 449*7c478bd9Sstevel@tonic-gate { 450*7c478bd9Sstevel@tonic-gate dev_info_t *dip = ugenp->ug_dip; 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, "ugen_cleanup"); 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate if (ugenp->ug_cleanup_flags & UGEN_INIT_LOCKS) { 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate /* shutdown all endpoints */ 457*7c478bd9Sstevel@tonic-gate ugen_epx_shutdown(ugenp); 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate /* 460*7c478bd9Sstevel@tonic-gate * At this point, no new activity can be initiated. 461*7c478bd9Sstevel@tonic-gate * The driver has disabled hotplug callbacks. 462*7c478bd9Sstevel@tonic-gate * The Solaris framework has disabled 463*7c478bd9Sstevel@tonic-gate * new opens on a device being detached, and does not 464*7c478bd9Sstevel@tonic-gate * allow detaching an open device. PM should power 465*7c478bd9Sstevel@tonic-gate * down while we are detaching 466*7c478bd9Sstevel@tonic-gate * 467*7c478bd9Sstevel@tonic-gate * The following ensures that any other driver 468*7c478bd9Sstevel@tonic-gate * activity must have drained (paranoia) 469*7c478bd9Sstevel@tonic-gate */ 470*7c478bd9Sstevel@tonic-gate (void) usb_serialize_access(ugenp->ug_ser_cookie, 471*7c478bd9Sstevel@tonic-gate USB_WAIT, 0); 472*7c478bd9Sstevel@tonic-gate usb_release_access(ugenp->ug_ser_cookie); 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 475*7c478bd9Sstevel@tonic-gate ASSERT(ugenp->ug_open_count == 0); 476*7c478bd9Sstevel@tonic-gate ASSERT(ugenp->ug_pending_cmds == 0); 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate /* dismantle in reverse order */ 479*7c478bd9Sstevel@tonic-gate ugen_pm_destroy(ugenp); 480*7c478bd9Sstevel@tonic-gate ugen_epxs_destroy(ugenp); 481*7c478bd9Sstevel@tonic-gate ugen_ds_destroy(ugenp); 482*7c478bd9Sstevel@tonic-gate ugen_minor_node_table_destroy(ugenp); 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate /* restore to initial configuration */ 486*7c478bd9Sstevel@tonic-gate if (usb_owns_device(dip) && 487*7c478bd9Sstevel@tonic-gate (ugenp->ug_dev_state != USB_DEV_DISCONNECTED)) { 488*7c478bd9Sstevel@tonic-gate int idx = ugenp->ug_initial_cfgidx; 489*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 490*7c478bd9Sstevel@tonic-gate (void) usb_set_cfg(dip, idx, 491*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, NULL); 492*7c478bd9Sstevel@tonic-gate } else { 493*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate usb_fini_serialization(ugenp->ug_ser_cookie); 497*7c478bd9Sstevel@tonic-gate } 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate ddi_prop_remove_all(dip); 500*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate ugen_free_devt(ugenp); 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate /* 509*7c478bd9Sstevel@tonic-gate * ugen_cpr_suspend 510*7c478bd9Sstevel@tonic-gate */ 511*7c478bd9Sstevel@tonic-gate static int 512*7c478bd9Sstevel@tonic-gate ugen_cpr_suspend(ugen_state_t *ugenp) 513*7c478bd9Sstevel@tonic-gate { 514*7c478bd9Sstevel@tonic-gate int rval = USB_FAILURE; 515*7c478bd9Sstevel@tonic-gate int i; 516*7c478bd9Sstevel@tonic-gate int prev_state; 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CPR, ugenp->ug_log_hdl, 519*7c478bd9Sstevel@tonic-gate "ugen_cpr_suspend:"); 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 522*7c478bd9Sstevel@tonic-gate switch (ugenp->ug_dev_state) { 523*7c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE: 524*7c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED: 525*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CPR, ugenp->ug_log_hdl, 526*7c478bd9Sstevel@tonic-gate "ugen_cpr_suspend:"); 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate prev_state = ugenp->ug_dev_state; 529*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_state = USB_DEV_SUSPENDED; 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate if (ugenp->ug_open_count) { 532*7c478bd9Sstevel@tonic-gate /* drain outstanding cmds */ 533*7c478bd9Sstevel@tonic-gate for (i = 0; i < ugen_busy_loop; i++) { 534*7c478bd9Sstevel@tonic-gate if (ugenp->ug_pending_cmds == 0) { 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate break; 537*7c478bd9Sstevel@tonic-gate } 538*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 539*7c478bd9Sstevel@tonic-gate delay(drv_usectohz(100000)); 540*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 541*7c478bd9Sstevel@tonic-gate } 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate /* if still outstanding cmds, fail suspend */ 544*7c478bd9Sstevel@tonic-gate if (ugenp->ug_pending_cmds) { 545*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_state = prev_state; 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_CPR, 548*7c478bd9Sstevel@tonic-gate ugenp->ug_log_hdl, 549*7c478bd9Sstevel@tonic-gate "ugen_cpr_suspend: pending %d", 550*7c478bd9Sstevel@tonic-gate ugenp->ug_pending_cmds); 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 553*7c478bd9Sstevel@tonic-gate break; 554*7c478bd9Sstevel@tonic-gate } 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 557*7c478bd9Sstevel@tonic-gate (void) usb_serialize_access(ugenp->ug_ser_cookie, 558*7c478bd9Sstevel@tonic-gate USB_WAIT, 0); 559*7c478bd9Sstevel@tonic-gate /* close all pipes */ 560*7c478bd9Sstevel@tonic-gate ugen_epx_shutdown(ugenp); 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate usb_release_access(ugenp->ug_ser_cookie); 563*7c478bd9Sstevel@tonic-gate 564*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 565*7c478bd9Sstevel@tonic-gate } 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate /* wakeup devstat reads and polls */ 568*7c478bd9Sstevel@tonic-gate ugen_ds_change(ugenp); 569*7c478bd9Sstevel@tonic-gate ugen_ds_poll_wakeup(ugenp); 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate rval = USB_SUCCESS; 572*7c478bd9Sstevel@tonic-gate break; 573*7c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED: 574*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RESUME: 575*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 576*7c478bd9Sstevel@tonic-gate default: 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate break; 579*7c478bd9Sstevel@tonic-gate } 580*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate return (rval); 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate /* 586*7c478bd9Sstevel@tonic-gate * ugen_cpr_resume 587*7c478bd9Sstevel@tonic-gate */ 588*7c478bd9Sstevel@tonic-gate static void 589*7c478bd9Sstevel@tonic-gate ugen_cpr_resume(ugen_state_t *ugenp) 590*7c478bd9Sstevel@tonic-gate { 591*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CPR, ugenp->ug_log_hdl, 592*7c478bd9Sstevel@tonic-gate "ugen_cpr_resume:"); 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate ugen_restore_state(ugenp); 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate /* 598*7c478bd9Sstevel@tonic-gate * usb_ugen_disconnect_ev_cb: 599*7c478bd9Sstevel@tonic-gate */ 600*7c478bd9Sstevel@tonic-gate int 601*7c478bd9Sstevel@tonic-gate usb_ugen_disconnect_ev_cb(usb_ugen_hdl_t usb_ugen_hdl) 602*7c478bd9Sstevel@tonic-gate { 603*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 604*7c478bd9Sstevel@tonic-gate (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 605*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp; 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate if (usb_ugen_hdl_impl == NULL) { 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 610*7c478bd9Sstevel@tonic-gate } 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate ugenp = usb_ugen_hdl_impl->hdl_ugenp; 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG, ugenp->ug_log_hdl, 615*7c478bd9Sstevel@tonic-gate "usb_ugen_disconnect_ev_cb:"); 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate /* get exclusive access */ 618*7c478bd9Sstevel@tonic-gate (void) usb_serialize_access(ugenp->ug_ser_cookie, USB_WAIT, 0); 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 621*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_state = USB_DEV_DISCONNECTED; 622*7c478bd9Sstevel@tonic-gate if (ugenp->ug_open_count) { 623*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate /* close all pipes */ 626*7c478bd9Sstevel@tonic-gate (void) ugen_epx_shutdown(ugenp); 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 629*7c478bd9Sstevel@tonic-gate } 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate /* wakeup devstat reads and polls */ 633*7c478bd9Sstevel@tonic-gate ugen_ds_change(ugenp); 634*7c478bd9Sstevel@tonic-gate ugen_ds_poll_wakeup(ugenp); 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 637*7c478bd9Sstevel@tonic-gate usb_release_access(ugenp->ug_ser_cookie); 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate /* 644*7c478bd9Sstevel@tonic-gate * usb_ugen_reconnect_ev_cb: 645*7c478bd9Sstevel@tonic-gate */ 646*7c478bd9Sstevel@tonic-gate int 647*7c478bd9Sstevel@tonic-gate usb_ugen_reconnect_ev_cb(usb_ugen_hdl_t usb_ugen_hdl) 648*7c478bd9Sstevel@tonic-gate { 649*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 650*7c478bd9Sstevel@tonic-gate (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 651*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp = usb_ugen_hdl_impl->hdl_ugenp; 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG, ugenp->ug_log_hdl, 654*7c478bd9Sstevel@tonic-gate "usb_ugen_reconnect_ev_cb:"); 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate ugen_restore_state(ugenp); 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 659*7c478bd9Sstevel@tonic-gate } 660*7c478bd9Sstevel@tonic-gate 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate /* 663*7c478bd9Sstevel@tonic-gate * ugen_restore_state: 664*7c478bd9Sstevel@tonic-gate * Check for same device; if a different device is attached, set 665*7c478bd9Sstevel@tonic-gate * the device status to disconnected. 666*7c478bd9Sstevel@tonic-gate * If we were open, then set to UNAVAILABLE until all endpoints have 667*7c478bd9Sstevel@tonic-gate * be closed. 668*7c478bd9Sstevel@tonic-gate */ 669*7c478bd9Sstevel@tonic-gate static void 670*7c478bd9Sstevel@tonic-gate ugen_restore_state(ugen_state_t *ugenp) 671*7c478bd9Sstevel@tonic-gate { 672*7c478bd9Sstevel@tonic-gate dev_info_t *dip = ugenp->ug_dip; 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG, ugenp->ug_log_hdl, 675*7c478bd9Sstevel@tonic-gate "ugen_restore_state"); 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate /* first raise power */ 678*7c478bd9Sstevel@tonic-gate if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 679*7c478bd9Sstevel@tonic-gate ugen_pm_busy_component(ugenp); 680*7c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 681*7c478bd9Sstevel@tonic-gate } 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate /* Check if we are talking to the same device */ 684*7c478bd9Sstevel@tonic-gate if (usb_check_same_device(dip, ugenp->ug_log_hdl, 685*7c478bd9Sstevel@tonic-gate USB_LOG_L0, UGEN_PRINT_HOTPLUG, USB_CHK_ALL, NULL) == 686*7c478bd9Sstevel@tonic-gate USB_FAILURE) { 687*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 688*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_state = USB_DEV_DISCONNECTED; 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate /* wakeup devstat reads and polls */ 691*7c478bd9Sstevel@tonic-gate ugen_ds_change(ugenp); 692*7c478bd9Sstevel@tonic-gate ugen_ds_poll_wakeup(ugenp); 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 695*7c478bd9Sstevel@tonic-gate 696*7c478bd9Sstevel@tonic-gate if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 697*7c478bd9Sstevel@tonic-gate ugen_pm_idle_component(ugenp); 698*7c478bd9Sstevel@tonic-gate } 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate return; 701*7c478bd9Sstevel@tonic-gate } 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate /* 704*7c478bd9Sstevel@tonic-gate * get exclusive access, we don't want to change state in the 705*7c478bd9Sstevel@tonic-gate * middle of some other actions 706*7c478bd9Sstevel@tonic-gate */ 707*7c478bd9Sstevel@tonic-gate (void) usb_serialize_access(ugenp->ug_ser_cookie, USB_WAIT, 0); 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 710*7c478bd9Sstevel@tonic-gate switch (ugenp->ug_dev_state) { 711*7c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED: 712*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_state = (ugenp->ug_open_count == 0) ? 713*7c478bd9Sstevel@tonic-gate USB_DEV_ONLINE : USB_UGEN_DEV_UNAVAILABLE_RECONNECT; 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate break; 716*7c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED: 717*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_state = (ugenp->ug_open_count == 0) ? 718*7c478bd9Sstevel@tonic-gate USB_DEV_ONLINE : USB_UGEN_DEV_UNAVAILABLE_RESUME; 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate break; 721*7c478bd9Sstevel@tonic-gate } 722*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG, ugenp->ug_log_hdl, 723*7c478bd9Sstevel@tonic-gate "ugen_restore_state: state=%d, opencount=%d", 724*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_state, ugenp->ug_open_count); 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate /* wakeup devstat reads and polls */ 727*7c478bd9Sstevel@tonic-gate ugen_ds_change(ugenp); 728*7c478bd9Sstevel@tonic-gate ugen_ds_poll_wakeup(ugenp); 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 731*7c478bd9Sstevel@tonic-gate usb_release_access(ugenp->ug_ser_cookie); 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 734*7c478bd9Sstevel@tonic-gate ugen_pm_idle_component(ugenp); 735*7c478bd9Sstevel@tonic-gate } 736*7c478bd9Sstevel@tonic-gate } 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate /* 740*7c478bd9Sstevel@tonic-gate * usb_ugen_open: 741*7c478bd9Sstevel@tonic-gate */ 742*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 743*7c478bd9Sstevel@tonic-gate int 744*7c478bd9Sstevel@tonic-gate usb_ugen_open(usb_ugen_hdl_t usb_ugen_hdl, dev_t *devp, int flag, int sflag, 745*7c478bd9Sstevel@tonic-gate cred_t *cr) 746*7c478bd9Sstevel@tonic-gate { 747*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 748*7c478bd9Sstevel@tonic-gate (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 749*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp; 750*7c478bd9Sstevel@tonic-gate int rval; 751*7c478bd9Sstevel@tonic-gate int minor_node_type; 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate if (usb_ugen_hdl == NULL) { 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate return (EINVAL); 756*7c478bd9Sstevel@tonic-gate } 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate ugenp = usb_ugen_hdl_impl->hdl_ugenp; 759*7c478bd9Sstevel@tonic-gate minor_node_type = UGEN_MINOR_TYPE(ugenp, *devp); 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 762*7c478bd9Sstevel@tonic-gate "usb_ugen_open: minor=%u", getminor(*devp)); 763*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 764*7c478bd9Sstevel@tonic-gate "cfgval=%" PRIu64 " cfgidx=%" PRIu64 " if=%" PRIu64 765*7c478bd9Sstevel@tonic-gate " alt=%" PRIu64 " epidx=%" PRIu64 " type=0x%" PRIx64, 766*7c478bd9Sstevel@tonic-gate UGEN_MINOR_CFGVAL(ugenp, *devp), UGEN_MINOR_CFGIDX(ugenp, *devp), 767*7c478bd9Sstevel@tonic-gate UGEN_MINOR_IF(ugenp, *devp), UGEN_MINOR_ALT(ugenp, *devp), 768*7c478bd9Sstevel@tonic-gate UGEN_MINOR_EPIDX(ugenp, *devp), UGEN_MINOR_TYPE(ugenp, *devp)); 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate /* first check for legal open flags */ 771*7c478bd9Sstevel@tonic-gate if ((rval = ugen_check_open_flags(ugenp, *devp, flag)) != 0) { 772*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 773*7c478bd9Sstevel@tonic-gate "usb_ugen_open: check failed, rval=%d", rval); 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate return (rval); 776*7c478bd9Sstevel@tonic-gate } 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate /* exclude other threads including other opens */ 779*7c478bd9Sstevel@tonic-gate if (usb_serialize_access(ugenp->ug_ser_cookie, 780*7c478bd9Sstevel@tonic-gate USB_WAIT_SIG, 0) <= 0) { 781*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 782*7c478bd9Sstevel@tonic-gate "usb_ugen_open: interrupted"); 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate return (EINTR); 785*7c478bd9Sstevel@tonic-gate } 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate /* always allow open of dev stat node */ 790*7c478bd9Sstevel@tonic-gate if (minor_node_type != UGEN_MINOR_DEV_STAT_NODE) { 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate /* if we are not online or powered down, fail open */ 793*7c478bd9Sstevel@tonic-gate switch (ugenp->ug_dev_state) { 794*7c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE: 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate break; 797*7c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED: 798*7c478bd9Sstevel@tonic-gate rval = ENODEV; 799*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate goto done; 802*7c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED: 803*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RESUME: 804*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 805*7c478bd9Sstevel@tonic-gate default: 806*7c478bd9Sstevel@tonic-gate rval = EBADF; 807*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate goto done; 810*7c478bd9Sstevel@tonic-gate } 811*7c478bd9Sstevel@tonic-gate } 812*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate /* open node depending on type */ 815*7c478bd9Sstevel@tonic-gate switch (minor_node_type) { 816*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_XFER_NODE: 817*7c478bd9Sstevel@tonic-gate if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 818*7c478bd9Sstevel@tonic-gate ugen_pm_busy_component(ugenp); 819*7c478bd9Sstevel@tonic-gate (void) pm_raise_power(ugenp->ug_dip, 0, 820*7c478bd9Sstevel@tonic-gate USB_DEV_OS_FULL_PWR); 821*7c478bd9Sstevel@tonic-gate } 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate rval = ugen_epx_open(ugenp, *devp, flag); 824*7c478bd9Sstevel@tonic-gate if (rval == 0) { 825*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 826*7c478bd9Sstevel@tonic-gate ugenp->ug_open_count++; 827*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 828*7c478bd9Sstevel@tonic-gate } else { 829*7c478bd9Sstevel@tonic-gate if (ugenp->ug_hdl->hdl_flags & 830*7c478bd9Sstevel@tonic-gate USB_UGEN_ENABLE_PM) { 831*7c478bd9Sstevel@tonic-gate ugen_pm_idle_component(ugenp); 832*7c478bd9Sstevel@tonic-gate } 833*7c478bd9Sstevel@tonic-gate } 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate break; 836*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_STAT_NODE: 837*7c478bd9Sstevel@tonic-gate rval = ugen_eps_open(ugenp, *devp, flag); 838*7c478bd9Sstevel@tonic-gate if (rval == 0) { 839*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 840*7c478bd9Sstevel@tonic-gate ugenp->ug_open_count++; 841*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 842*7c478bd9Sstevel@tonic-gate } 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate break; 845*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_DEV_STAT_NODE: 846*7c478bd9Sstevel@tonic-gate rval = ugen_ds_open(ugenp, *devp, flag); 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate break; 849*7c478bd9Sstevel@tonic-gate default: 850*7c478bd9Sstevel@tonic-gate rval = EINVAL; 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate break; 853*7c478bd9Sstevel@tonic-gate } 854*7c478bd9Sstevel@tonic-gate done: 855*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 858*7c478bd9Sstevel@tonic-gate "usb_ugen_open: minor=0x%x rval=%d state=%d cnt=%d", 859*7c478bd9Sstevel@tonic-gate getminor(*devp), rval, ugenp->ug_dev_state, 860*7c478bd9Sstevel@tonic-gate ugenp->ug_open_count); 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate usb_release_access(ugenp->ug_ser_cookie); 865*7c478bd9Sstevel@tonic-gate 866*7c478bd9Sstevel@tonic-gate return (rval); 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate /* 871*7c478bd9Sstevel@tonic-gate * usb_ugen_close() 872*7c478bd9Sstevel@tonic-gate */ 873*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 874*7c478bd9Sstevel@tonic-gate int 875*7c478bd9Sstevel@tonic-gate usb_ugen_close(usb_ugen_hdl_t usb_ugen_hdl, dev_t dev, int flag, int otype, 876*7c478bd9Sstevel@tonic-gate cred_t *cr) 877*7c478bd9Sstevel@tonic-gate { 878*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 879*7c478bd9Sstevel@tonic-gate (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 880*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp; 881*7c478bd9Sstevel@tonic-gate int minor_node_type; 882*7c478bd9Sstevel@tonic-gate 883*7c478bd9Sstevel@tonic-gate if (usb_ugen_hdl == NULL) { 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate return (EINVAL); 886*7c478bd9Sstevel@tonic-gate } 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate ugenp = usb_ugen_hdl_impl->hdl_ugenp; 889*7c478bd9Sstevel@tonic-gate minor_node_type = UGEN_MINOR_TYPE(ugenp, dev); 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 892*7c478bd9Sstevel@tonic-gate "usb_ugen_close: minor=0x%x", getminor(dev)); 893*7c478bd9Sstevel@tonic-gate 894*7c478bd9Sstevel@tonic-gate /* exclude other threads, including other opens */ 895*7c478bd9Sstevel@tonic-gate if (usb_serialize_access(ugenp->ug_ser_cookie, 896*7c478bd9Sstevel@tonic-gate USB_WAIT_SIG, 0) <= 0) { 897*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 898*7c478bd9Sstevel@tonic-gate "usb_ugen_close: interrupted"); 899*7c478bd9Sstevel@tonic-gate 900*7c478bd9Sstevel@tonic-gate return (EINTR); 901*7c478bd9Sstevel@tonic-gate } 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate /* close node depending on type */ 904*7c478bd9Sstevel@tonic-gate switch (minor_node_type) { 905*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_XFER_NODE: 906*7c478bd9Sstevel@tonic-gate ugen_epx_close(ugenp, dev, flag); 907*7c478bd9Sstevel@tonic-gate if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 908*7c478bd9Sstevel@tonic-gate ugen_pm_idle_component(ugenp); 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate break; 912*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_STAT_NODE: 913*7c478bd9Sstevel@tonic-gate ugen_eps_close(ugenp, dev, flag); 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate break; 916*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_DEV_STAT_NODE: 917*7c478bd9Sstevel@tonic-gate ugen_ds_close(ugenp, dev, flag); 918*7c478bd9Sstevel@tonic-gate 919*7c478bd9Sstevel@tonic-gate break; 920*7c478bd9Sstevel@tonic-gate default: 921*7c478bd9Sstevel@tonic-gate usb_release_access(ugenp->ug_ser_cookie); 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate return (EINVAL); 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 927*7c478bd9Sstevel@tonic-gate if (minor_node_type != UGEN_MINOR_DEV_STAT_NODE) { 928*7c478bd9Sstevel@tonic-gate ASSERT(ugenp->ug_open_count > 0); 929*7c478bd9Sstevel@tonic-gate if ((--ugenp->ug_open_count == 0) && 930*7c478bd9Sstevel@tonic-gate ((ugenp->ug_dev_state == USB_UGEN_DEV_UNAVAILABLE_RESUME) || 931*7c478bd9Sstevel@tonic-gate (ugenp->ug_dev_state == 932*7c478bd9Sstevel@tonic-gate USB_UGEN_DEV_UNAVAILABLE_RECONNECT))) { 933*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_state = USB_DEV_ONLINE; 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate /* wakeup devstat reads and polls */ 936*7c478bd9Sstevel@tonic-gate ugen_ds_change(ugenp); 937*7c478bd9Sstevel@tonic-gate ugen_ds_poll_wakeup(ugenp); 938*7c478bd9Sstevel@tonic-gate } 939*7c478bd9Sstevel@tonic-gate } 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 942*7c478bd9Sstevel@tonic-gate "usb_ugen_close: minor=0x%x state=%d cnt=%d", 943*7c478bd9Sstevel@tonic-gate getminor(dev), ugenp->ug_dev_state, ugenp->ug_open_count); 944*7c478bd9Sstevel@tonic-gate 945*7c478bd9Sstevel@tonic-gate if (ugenp->ug_open_count == 0) { 946*7c478bd9Sstevel@tonic-gate ASSERT(ugen_epxs_check_open_nodes(ugenp) == USB_FAILURE); 947*7c478bd9Sstevel@tonic-gate } 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate usb_release_access(ugenp->ug_ser_cookie); 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate return (0); 954*7c478bd9Sstevel@tonic-gate } 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate 957*7c478bd9Sstevel@tonic-gate /* 958*7c478bd9Sstevel@tonic-gate * usb_ugen_read/write() 959*7c478bd9Sstevel@tonic-gate */ 960*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 961*7c478bd9Sstevel@tonic-gate int 962*7c478bd9Sstevel@tonic-gate usb_ugen_read(usb_ugen_hdl_t usb_ugen_hdl, dev_t dev, struct uio *uiop, 963*7c478bd9Sstevel@tonic-gate cred_t *credp) 964*7c478bd9Sstevel@tonic-gate { 965*7c478bd9Sstevel@tonic-gate return (physio(ugen_strategy, 966*7c478bd9Sstevel@tonic-gate (struct buf *)0, dev, B_READ, ugen_minphys, uiop)); 967*7c478bd9Sstevel@tonic-gate } 968*7c478bd9Sstevel@tonic-gate 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 971*7c478bd9Sstevel@tonic-gate int 972*7c478bd9Sstevel@tonic-gate usb_ugen_write(usb_ugen_hdl_t usb_ugen_hdl, dev_t dev, struct uio *uiop, 973*7c478bd9Sstevel@tonic-gate cred_t *credp) 974*7c478bd9Sstevel@tonic-gate { 975*7c478bd9Sstevel@tonic-gate return (physio(ugen_strategy, 976*7c478bd9Sstevel@tonic-gate (struct buf *)0, dev, B_WRITE, ugen_minphys, uiop)); 977*7c478bd9Sstevel@tonic-gate } 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate /* 981*7c478bd9Sstevel@tonic-gate * usb_ugen_poll 982*7c478bd9Sstevel@tonic-gate */ 983*7c478bd9Sstevel@tonic-gate int 984*7c478bd9Sstevel@tonic-gate usb_ugen_poll(usb_ugen_hdl_t usb_ugen_hdl, dev_t dev, short events, 985*7c478bd9Sstevel@tonic-gate int anyyet, short *reventsp, struct pollhead **phpp) 986*7c478bd9Sstevel@tonic-gate { 987*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 988*7c478bd9Sstevel@tonic-gate (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 989*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp; 990*7c478bd9Sstevel@tonic-gate int minor_node_type; 991*7c478bd9Sstevel@tonic-gate uint_t ep_index; 992*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp; 993*7c478bd9Sstevel@tonic-gate 994*7c478bd9Sstevel@tonic-gate if (usb_ugen_hdl == NULL) { 995*7c478bd9Sstevel@tonic-gate 996*7c478bd9Sstevel@tonic-gate return (EINVAL); 997*7c478bd9Sstevel@tonic-gate } 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate ugenp = usb_ugen_hdl_impl->hdl_ugenp; 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate minor_node_type = UGEN_MINOR_TYPE(ugenp, dev); 1002*7c478bd9Sstevel@tonic-gate ep_index = UGEN_MINOR_EPIDX(ugenp, dev); 1003*7c478bd9Sstevel@tonic-gate epp = &ugenp->ug_ep[ep_index]; 1004*7c478bd9Sstevel@tonic-gate 1005*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_POLL, ugenp->ug_log_hdl, 1008*7c478bd9Sstevel@tonic-gate "usb_ugen_poll: " 1009*7c478bd9Sstevel@tonic-gate "dev=0x%lx events=0x%x anyyet=0x%x rev=0x%p type=%d " 1010*7c478bd9Sstevel@tonic-gate "devstat=0x%x devstate=0x%x", 1011*7c478bd9Sstevel@tonic-gate dev, events, anyyet, (void *)reventsp, minor_node_type, 1012*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_stat, ugenp->ug_ds.dev_state); 1013*7c478bd9Sstevel@tonic-gate 1014*7c478bd9Sstevel@tonic-gate *reventsp = 0; 1015*7c478bd9Sstevel@tonic-gate 1016*7c478bd9Sstevel@tonic-gate if (ugenp->ug_dev_state == USB_DEV_ONLINE) { 1017*7c478bd9Sstevel@tonic-gate switch (minor_node_type) { 1018*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_XFER_NODE: 1019*7c478bd9Sstevel@tonic-gate /* if interrupt IN ep and there is data, set POLLIN */ 1020*7c478bd9Sstevel@tonic-gate if ((UGEN_XFER_TYPE(epp) == USB_EP_ATTR_INTR) && 1021*7c478bd9Sstevel@tonic-gate (UGEN_XFER_DIR(epp) & USB_EP_DIR_IN)) { 1022*7c478bd9Sstevel@tonic-gate 1023*7c478bd9Sstevel@tonic-gate /* 1024*7c478bd9Sstevel@tonic-gate * if we are not polling, force another 1025*7c478bd9Sstevel@tonic-gate * read to kick off polling 1026*7c478bd9Sstevel@tonic-gate */ 1027*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1028*7c478bd9Sstevel@tonic-gate if ((epp->ep_data) || 1029*7c478bd9Sstevel@tonic-gate ((epp->ep_state & 1030*7c478bd9Sstevel@tonic-gate UGEN_EP_STATE_INTR_IN_POLLING_ON) == 0)) { 1031*7c478bd9Sstevel@tonic-gate *reventsp |= POLLIN; 1032*7c478bd9Sstevel@tonic-gate } else if (!anyyet) { 1033*7c478bd9Sstevel@tonic-gate *phpp = &epp->ep_pollhead; 1034*7c478bd9Sstevel@tonic-gate epp->ep_state |= 1035*7c478bd9Sstevel@tonic-gate UGEN_EP_STATE_INTR_IN_POLL_PENDING; 1036*7c478bd9Sstevel@tonic-gate } 1037*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1038*7c478bd9Sstevel@tonic-gate } else { 1039*7c478bd9Sstevel@tonic-gate /* no poll on other ep nodes */ 1040*7c478bd9Sstevel@tonic-gate *reventsp |= POLLERR; 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate 1043*7c478bd9Sstevel@tonic-gate break; 1044*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_DEV_STAT_NODE: 1045*7c478bd9Sstevel@tonic-gate if (ugenp->ug_ds.dev_stat & UGEN_DEV_STATUS_CHANGED) { 1046*7c478bd9Sstevel@tonic-gate *reventsp |= POLLIN; 1047*7c478bd9Sstevel@tonic-gate } else if (!anyyet) { 1048*7c478bd9Sstevel@tonic-gate *phpp = &ugenp->ug_ds.dev_pollhead; 1049*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_stat |= 1050*7c478bd9Sstevel@tonic-gate UGEN_DEV_STATUS_POLL_PENDING; 1051*7c478bd9Sstevel@tonic-gate } 1052*7c478bd9Sstevel@tonic-gate 1053*7c478bd9Sstevel@tonic-gate break; 1054*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_STAT_NODE: 1055*7c478bd9Sstevel@tonic-gate default: 1056*7c478bd9Sstevel@tonic-gate *reventsp |= POLLERR; 1057*7c478bd9Sstevel@tonic-gate 1058*7c478bd9Sstevel@tonic-gate break; 1059*7c478bd9Sstevel@tonic-gate } 1060*7c478bd9Sstevel@tonic-gate } else { 1061*7c478bd9Sstevel@tonic-gate if (ugenp->ug_ds.dev_stat & UGEN_DEV_STATUS_CHANGED) { 1062*7c478bd9Sstevel@tonic-gate *reventsp |= POLLHUP|POLLIN; 1063*7c478bd9Sstevel@tonic-gate } else if (!anyyet) { 1064*7c478bd9Sstevel@tonic-gate *phpp = &ugenp->ug_ds.dev_pollhead; 1065*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_stat |= 1066*7c478bd9Sstevel@tonic-gate UGEN_DEV_STATUS_POLL_PENDING; 1067*7c478bd9Sstevel@tonic-gate } 1068*7c478bd9Sstevel@tonic-gate } 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 1071*7c478bd9Sstevel@tonic-gate 1072*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_POLL, ugenp->ug_log_hdl, 1073*7c478bd9Sstevel@tonic-gate "usb_ugen_poll end: reventsp=0x%x", *reventsp); 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate return (0); 1076*7c478bd9Sstevel@tonic-gate } 1077*7c478bd9Sstevel@tonic-gate 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate /* 1080*7c478bd9Sstevel@tonic-gate * ugen_strategy 1081*7c478bd9Sstevel@tonic-gate */ 1082*7c478bd9Sstevel@tonic-gate static int 1083*7c478bd9Sstevel@tonic-gate ugen_strategy(struct buf *bp) 1084*7c478bd9Sstevel@tonic-gate { 1085*7c478bd9Sstevel@tonic-gate dev_t dev = bp->b_edev; 1086*7c478bd9Sstevel@tonic-gate int rval = 0; 1087*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp = ugen_devt2state(dev); 1088*7c478bd9Sstevel@tonic-gate int minor_node_type = UGEN_MINOR_TYPE(ugenp, dev); 1089*7c478bd9Sstevel@tonic-gate 1090*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1091*7c478bd9Sstevel@tonic-gate "ugen_strategy: bp=0x%p minor=0x%x", bp, getminor(dev)); 1092*7c478bd9Sstevel@tonic-gate 1093*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 1094*7c478bd9Sstevel@tonic-gate ugenp->ug_pending_cmds++; 1095*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 1096*7c478bd9Sstevel@tonic-gate 1097*7c478bd9Sstevel@tonic-gate bp_mapin(bp); 1098*7c478bd9Sstevel@tonic-gate 1099*7c478bd9Sstevel@tonic-gate switch (minor_node_type) { 1100*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_XFER_NODE: 1101*7c478bd9Sstevel@tonic-gate rval = ugen_epx_req(ugenp, bp); 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate break; 1104*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_STAT_NODE: 1105*7c478bd9Sstevel@tonic-gate rval = ugen_eps_req(ugenp, bp); 1106*7c478bd9Sstevel@tonic-gate 1107*7c478bd9Sstevel@tonic-gate break; 1108*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_DEV_STAT_NODE: 1109*7c478bd9Sstevel@tonic-gate rval = ugen_ds_req(ugenp, bp); 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate break; 1112*7c478bd9Sstevel@tonic-gate default: 1113*7c478bd9Sstevel@tonic-gate rval = EINVAL; 1114*7c478bd9Sstevel@tonic-gate 1115*7c478bd9Sstevel@tonic-gate break; 1116*7c478bd9Sstevel@tonic-gate } 1117*7c478bd9Sstevel@tonic-gate 1118*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 1119*7c478bd9Sstevel@tonic-gate ugenp->ug_pending_cmds--; 1120*7c478bd9Sstevel@tonic-gate 1121*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1122*7c478bd9Sstevel@tonic-gate "ugen_strategy: " 1123*7c478bd9Sstevel@tonic-gate "bp=0x%p cnt=%lu resid=%lu err=%d minor=0x%x rval=%d #cmds=%d", 1124*7c478bd9Sstevel@tonic-gate (void *)bp, bp->b_bcount, bp->b_resid, geterror(bp), 1125*7c478bd9Sstevel@tonic-gate getminor(dev), rval, ugenp->ug_pending_cmds); 1126*7c478bd9Sstevel@tonic-gate 1127*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate if (rval) { 1130*7c478bd9Sstevel@tonic-gate if (geterror(bp) == 0) { 1131*7c478bd9Sstevel@tonic-gate bioerror(bp, rval); 1132*7c478bd9Sstevel@tonic-gate } 1133*7c478bd9Sstevel@tonic-gate } 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate biodone(bp); 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate return (0); 1138*7c478bd9Sstevel@tonic-gate } 1139*7c478bd9Sstevel@tonic-gate 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate /* 1142*7c478bd9Sstevel@tonic-gate * ugen_minphys: 1143*7c478bd9Sstevel@tonic-gate */ 1144*7c478bd9Sstevel@tonic-gate static void 1145*7c478bd9Sstevel@tonic-gate ugen_minphys(struct buf *bp) 1146*7c478bd9Sstevel@tonic-gate { 1147*7c478bd9Sstevel@tonic-gate dev_t dev = bp->b_edev; 1148*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp = ugen_devt2state(dev); 1149*7c478bd9Sstevel@tonic-gate int minor_node_type = UGEN_MINOR_TYPE(ugenp, dev); 1150*7c478bd9Sstevel@tonic-gate uint_t ep_index = UGEN_MINOR_EPIDX(ugenp, dev); 1151*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = &ugenp->ug_ep[ep_index]; 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1154*7c478bd9Sstevel@tonic-gate "ugen_phys: bp=0x%p dev=0x%lx index=%d type=0x%x", 1155*7c478bd9Sstevel@tonic-gate (void *)bp, dev, ep_index, minor_node_type); 1156*7c478bd9Sstevel@tonic-gate 1157*7c478bd9Sstevel@tonic-gate switch (minor_node_type) { 1158*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_XFER_NODE: 1159*7c478bd9Sstevel@tonic-gate switch (UGEN_XFER_TYPE(epp)) { 1160*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 1161*7c478bd9Sstevel@tonic-gate if (bp->b_bcount > ugenp->ug_max_bulk_xfer_sz) { 1162*7c478bd9Sstevel@tonic-gate bp->b_bcount = ugenp->ug_max_bulk_xfer_sz; 1163*7c478bd9Sstevel@tonic-gate } 1164*7c478bd9Sstevel@tonic-gate 1165*7c478bd9Sstevel@tonic-gate break; 1166*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 1167*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 1168*7c478bd9Sstevel@tonic-gate default: 1169*7c478bd9Sstevel@tonic-gate 1170*7c478bd9Sstevel@tonic-gate break; 1171*7c478bd9Sstevel@tonic-gate } 1172*7c478bd9Sstevel@tonic-gate break; 1173*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_STAT_NODE: 1174*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_DEV_STAT_NODE: 1175*7c478bd9Sstevel@tonic-gate default: 1176*7c478bd9Sstevel@tonic-gate 1177*7c478bd9Sstevel@tonic-gate break; 1178*7c478bd9Sstevel@tonic-gate } 1179*7c478bd9Sstevel@tonic-gate } 1180*7c478bd9Sstevel@tonic-gate 1181*7c478bd9Sstevel@tonic-gate 1182*7c478bd9Sstevel@tonic-gate /* 1183*7c478bd9Sstevel@tonic-gate * check whether flag is appropriate for node type 1184*7c478bd9Sstevel@tonic-gate */ 1185*7c478bd9Sstevel@tonic-gate static int 1186*7c478bd9Sstevel@tonic-gate ugen_check_open_flags(ugen_state_t *ugenp, dev_t dev, int flag) 1187*7c478bd9Sstevel@tonic-gate { 1188*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp; 1189*7c478bd9Sstevel@tonic-gate int minor_node_type = UGEN_MINOR_TYPE(ugenp, dev); 1190*7c478bd9Sstevel@tonic-gate int rval = 0; 1191*7c478bd9Sstevel@tonic-gate 1192*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1193*7c478bd9Sstevel@tonic-gate "ugen_check_open_flags: " 1194*7c478bd9Sstevel@tonic-gate "dev=0x%lx, type=0x%x flag=0x%x idx=%" PRIu64, 1195*7c478bd9Sstevel@tonic-gate dev, minor_node_type, flag, UGEN_MINOR_EPIDX(ugenp, dev)); 1196*7c478bd9Sstevel@tonic-gate 1197*7c478bd9Sstevel@tonic-gate switch (minor_node_type) { 1198*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_XFER_NODE: 1199*7c478bd9Sstevel@tonic-gate epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 1200*7c478bd9Sstevel@tonic-gate switch (UGEN_XFER_TYPE(epp)) { 1201*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 1202*7c478bd9Sstevel@tonic-gate /* read and write must be set, ndelay not allowed */ 1203*7c478bd9Sstevel@tonic-gate if (((flag & (FREAD | FWRITE)) != (FREAD | FWRITE)) || 1204*7c478bd9Sstevel@tonic-gate (flag & (FNDELAY | FNONBLOCK))) { 1205*7c478bd9Sstevel@tonic-gate rval = EACCES; 1206*7c478bd9Sstevel@tonic-gate } 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate break; 1209*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 1210*7c478bd9Sstevel@tonic-gate /* ndelay not allowed */ 1211*7c478bd9Sstevel@tonic-gate if (flag & (FNDELAY | FNONBLOCK)) { 1212*7c478bd9Sstevel@tonic-gate rval = EACCES; 1213*7c478bd9Sstevel@tonic-gate 1214*7c478bd9Sstevel@tonic-gate break; 1215*7c478bd9Sstevel@tonic-gate } 1216*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 1217*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 1218*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 1219*7c478bd9Sstevel@tonic-gate /* check flag versus direction */ 1220*7c478bd9Sstevel@tonic-gate if ((flag & FWRITE) && 1221*7c478bd9Sstevel@tonic-gate (UGEN_XFER_DIR(epp) & USB_EP_DIR_IN)) { 1222*7c478bd9Sstevel@tonic-gate rval = EACCES; 1223*7c478bd9Sstevel@tonic-gate } 1224*7c478bd9Sstevel@tonic-gate if ((flag & FREAD) && 1225*7c478bd9Sstevel@tonic-gate ((UGEN_XFER_DIR(epp) & USB_EP_DIR_IN) == 0)) { 1226*7c478bd9Sstevel@tonic-gate rval = EACCES; 1227*7c478bd9Sstevel@tonic-gate } 1228*7c478bd9Sstevel@tonic-gate 1229*7c478bd9Sstevel@tonic-gate break; 1230*7c478bd9Sstevel@tonic-gate default: 1231*7c478bd9Sstevel@tonic-gate rval = EINVAL; 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate break; 1234*7c478bd9Sstevel@tonic-gate } 1235*7c478bd9Sstevel@tonic-gate break; 1236*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_DEV_STAT_NODE: 1237*7c478bd9Sstevel@tonic-gate /* only reads are supported */ 1238*7c478bd9Sstevel@tonic-gate if (flag & FWRITE) { 1239*7c478bd9Sstevel@tonic-gate rval = EACCES; 1240*7c478bd9Sstevel@tonic-gate } 1241*7c478bd9Sstevel@tonic-gate 1242*7c478bd9Sstevel@tonic-gate break; 1243*7c478bd9Sstevel@tonic-gate case UGEN_MINOR_EP_STAT_NODE: 1244*7c478bd9Sstevel@tonic-gate 1245*7c478bd9Sstevel@tonic-gate break; 1246*7c478bd9Sstevel@tonic-gate default: 1247*7c478bd9Sstevel@tonic-gate rval = EINVAL; 1248*7c478bd9Sstevel@tonic-gate 1249*7c478bd9Sstevel@tonic-gate break; 1250*7c478bd9Sstevel@tonic-gate } 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate return (rval); 1253*7c478bd9Sstevel@tonic-gate } 1254*7c478bd9Sstevel@tonic-gate 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate /* 1257*7c478bd9Sstevel@tonic-gate * endpoint management 1258*7c478bd9Sstevel@tonic-gate * 1259*7c478bd9Sstevel@tonic-gate * create/initialize all endpoint xfer/stat structures 1260*7c478bd9Sstevel@tonic-gate */ 1261*7c478bd9Sstevel@tonic-gate static int 1262*7c478bd9Sstevel@tonic-gate ugen_epxs_init(ugen_state_t *ugenp) 1263*7c478bd9Sstevel@tonic-gate { 1264*7c478bd9Sstevel@tonic-gate usb_cfg_data_t *dev_cfg = ugenp->ug_dev_data->dev_cfg; 1265*7c478bd9Sstevel@tonic-gate uchar_t cfgidx, cfgval, iface, alt, ep; 1266*7c478bd9Sstevel@tonic-gate usb_if_data_t *if_data; 1267*7c478bd9Sstevel@tonic-gate usb_alt_if_data_t *alt_if_data; 1268*7c478bd9Sstevel@tonic-gate usb_ep_data_t *ep_data; 1269*7c478bd9Sstevel@tonic-gate 1270*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1271*7c478bd9Sstevel@tonic-gate "ugen_epxs_init:"); 1272*7c478bd9Sstevel@tonic-gate 1273*7c478bd9Sstevel@tonic-gate /* initialize each ep's mutex first */ 1274*7c478bd9Sstevel@tonic-gate for (ep = 0; ep < UGEN_N_ENDPOINTS; ep++) { 1275*7c478bd9Sstevel@tonic-gate mutex_init(&ugenp->ug_ep[ep].ep_mutex, NULL, MUTEX_DRIVER, 1276*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_data->dev_iblock_cookie); 1277*7c478bd9Sstevel@tonic-gate } 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate /* init default ep as it does not have a descriptor */ 1280*7c478bd9Sstevel@tonic-gate if (ugen_epxs_data_init(ugenp, NULL, 0, 0, 1281*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_data->dev_curr_if, 0) != USB_SUCCESS) { 1282*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 1283*7c478bd9Sstevel@tonic-gate "creating default endpoint failed"); 1284*7c478bd9Sstevel@tonic-gate 1285*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1286*7c478bd9Sstevel@tonic-gate } 1287*7c478bd9Sstevel@tonic-gate 1288*7c478bd9Sstevel@tonic-gate /* 1289*7c478bd9Sstevel@tonic-gate * walk all endpoints of all alternates of all interfaces of 1290*7c478bd9Sstevel@tonic-gate * all cfs 1291*7c478bd9Sstevel@tonic-gate */ 1292*7c478bd9Sstevel@tonic-gate for (cfgidx = 0; cfgidx < ugenp->ug_dev_data->dev_n_cfg; cfgidx++) { 1293*7c478bd9Sstevel@tonic-gate dev_cfg = &ugenp->ug_dev_data->dev_cfg[cfgidx]; 1294*7c478bd9Sstevel@tonic-gate cfgval = dev_cfg->cfg_descr.bConfigurationValue; 1295*7c478bd9Sstevel@tonic-gate for (iface = 0; iface < dev_cfg->cfg_n_if; iface++) { 1296*7c478bd9Sstevel@tonic-gate if_data = &dev_cfg->cfg_if[iface]; 1297*7c478bd9Sstevel@tonic-gate for (alt = 0; alt < if_data->if_n_alt; alt++) { 1298*7c478bd9Sstevel@tonic-gate alt_if_data = &if_data->if_alt[alt]; 1299*7c478bd9Sstevel@tonic-gate for (ep = 0; ep < alt_if_data->altif_n_ep; 1300*7c478bd9Sstevel@tonic-gate ep++) { 1301*7c478bd9Sstevel@tonic-gate ep_data = &alt_if_data->altif_ep[ep]; 1302*7c478bd9Sstevel@tonic-gate if (ugen_epxs_data_init(ugenp, ep_data, 1303*7c478bd9Sstevel@tonic-gate cfgval, cfgidx, iface, alt) != 1304*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1305*7c478bd9Sstevel@tonic-gate 1306*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1307*7c478bd9Sstevel@tonic-gate } 1308*7c478bd9Sstevel@tonic-gate } 1309*7c478bd9Sstevel@tonic-gate } 1310*7c478bd9Sstevel@tonic-gate } 1311*7c478bd9Sstevel@tonic-gate } 1312*7c478bd9Sstevel@tonic-gate 1313*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1314*7c478bd9Sstevel@tonic-gate } 1315*7c478bd9Sstevel@tonic-gate 1316*7c478bd9Sstevel@tonic-gate 1317*7c478bd9Sstevel@tonic-gate /* 1318*7c478bd9Sstevel@tonic-gate * initialize one endpoint structure 1319*7c478bd9Sstevel@tonic-gate */ 1320*7c478bd9Sstevel@tonic-gate static int 1321*7c478bd9Sstevel@tonic-gate ugen_epxs_data_init(ugen_state_t *ugenp, usb_ep_data_t *ep_data, 1322*7c478bd9Sstevel@tonic-gate uchar_t cfgval, uchar_t cfgidx, uchar_t iface, uchar_t alt) 1323*7c478bd9Sstevel@tonic-gate { 1324*7c478bd9Sstevel@tonic-gate int ep_index; 1325*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp; 1326*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *ep_descr; 1327*7c478bd9Sstevel@tonic-gate 1328*7c478bd9Sstevel@tonic-gate /* is this the default endpoint */ 1329*7c478bd9Sstevel@tonic-gate ep_index = (ep_data == NULL) ? 0 : 1330*7c478bd9Sstevel@tonic-gate usb_get_ep_index(ep_data->ep_descr.bEndpointAddress); 1331*7c478bd9Sstevel@tonic-gate epp = &ugenp->ug_ep[ep_index]; 1332*7c478bd9Sstevel@tonic-gate 1333*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1334*7c478bd9Sstevel@tonic-gate "ugen_epxs_data_init: " 1335*7c478bd9Sstevel@tonic-gate "cfgval=%d cfgidx=%d iface=%d alt=%d ep_index=%d", 1336*7c478bd9Sstevel@tonic-gate cfgval, cfgidx, iface, alt, ep_index); 1337*7c478bd9Sstevel@tonic-gate 1338*7c478bd9Sstevel@tonic-gate ep_descr = (ep_data == NULL) ? &ugen_default_ep_descr : 1339*7c478bd9Sstevel@tonic-gate &ep_data->ep_descr; 1340*7c478bd9Sstevel@tonic-gate 1341*7c478bd9Sstevel@tonic-gate mutex_init(&epp->ep_mutex, NULL, MUTEX_DRIVER, 1342*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_data->dev_iblock_cookie); 1343*7c478bd9Sstevel@tonic-gate 1344*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate /* initialize if not yet init'ed */ 1347*7c478bd9Sstevel@tonic-gate if (epp->ep_state == UGEN_EP_STATE_NONE) { 1348*7c478bd9Sstevel@tonic-gate epp->ep_descr = *ep_descr; 1349*7c478bd9Sstevel@tonic-gate epp->ep_cfgidx = cfgidx; 1350*7c478bd9Sstevel@tonic-gate epp->ep_if = iface; 1351*7c478bd9Sstevel@tonic-gate epp->ep_alt = alt; 1352*7c478bd9Sstevel@tonic-gate epp->ep_state = UGEN_EP_STATE_ACTIVE; 1353*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 1354*7c478bd9Sstevel@tonic-gate epp->ep_pipe_policy.pp_max_async_reqs = 1; 1355*7c478bd9Sstevel@tonic-gate 1356*7c478bd9Sstevel@tonic-gate cv_init(&epp->ep_wait_cv, NULL, CV_DRIVER, NULL); 1357*7c478bd9Sstevel@tonic-gate epp->ep_ser_cookie = usb_init_serialization( 1358*7c478bd9Sstevel@tonic-gate ugenp->ug_dip, 0); 1359*7c478bd9Sstevel@tonic-gate } 1360*7c478bd9Sstevel@tonic-gate 1361*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1362*7c478bd9Sstevel@tonic-gate 1363*7c478bd9Sstevel@tonic-gate /* create minor nodes for all alts */ 1364*7c478bd9Sstevel@tonic-gate 1365*7c478bd9Sstevel@tonic-gate return (ugen_epxs_minor_nodes_create(ugenp, ep_descr, 1366*7c478bd9Sstevel@tonic-gate cfgval, cfgidx, iface, alt)); 1367*7c478bd9Sstevel@tonic-gate } 1368*7c478bd9Sstevel@tonic-gate 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate /* 1371*7c478bd9Sstevel@tonic-gate * undo all endpoint initializations 1372*7c478bd9Sstevel@tonic-gate */ 1373*7c478bd9Sstevel@tonic-gate static void 1374*7c478bd9Sstevel@tonic-gate ugen_epxs_destroy(ugen_state_t *ugenp) 1375*7c478bd9Sstevel@tonic-gate { 1376*7c478bd9Sstevel@tonic-gate int i; 1377*7c478bd9Sstevel@tonic-gate 1378*7c478bd9Sstevel@tonic-gate for (i = 0; i < UGEN_N_ENDPOINTS; i++) { 1379*7c478bd9Sstevel@tonic-gate ugen_epxs_data_destroy(ugenp, &ugenp->ug_ep[i]); 1380*7c478bd9Sstevel@tonic-gate } 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate 1383*7c478bd9Sstevel@tonic-gate 1384*7c478bd9Sstevel@tonic-gate static void 1385*7c478bd9Sstevel@tonic-gate ugen_epxs_data_destroy(ugen_state_t *ugenp, ugen_ep_t *epp) 1386*7c478bd9Sstevel@tonic-gate { 1387*7c478bd9Sstevel@tonic-gate if (epp) { 1388*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_ph == NULL); 1389*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1390*7c478bd9Sstevel@tonic-gate if (epp->ep_state != UGEN_EP_STATE_NONE) { 1391*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1392*7c478bd9Sstevel@tonic-gate "ugen_epxs_destroy: addr=0x%x", 1393*7c478bd9Sstevel@tonic-gate UGEN_XFER_ADDR(epp)); 1394*7c478bd9Sstevel@tonic-gate cv_destroy(&epp->ep_wait_cv); 1395*7c478bd9Sstevel@tonic-gate } 1396*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1397*7c478bd9Sstevel@tonic-gate 1398*7c478bd9Sstevel@tonic-gate mutex_destroy(&epp->ep_mutex); 1399*7c478bd9Sstevel@tonic-gate usb_fini_serialization(epp->ep_ser_cookie); 1400*7c478bd9Sstevel@tonic-gate } 1401*7c478bd9Sstevel@tonic-gate } 1402*7c478bd9Sstevel@tonic-gate 1403*7c478bd9Sstevel@tonic-gate 1404*7c478bd9Sstevel@tonic-gate /* 1405*7c478bd9Sstevel@tonic-gate * create endpoint status and xfer minor nodes 1406*7c478bd9Sstevel@tonic-gate * 1407*7c478bd9Sstevel@tonic-gate * The actual minor node needs more than 18 bits. We create a table 1408*7c478bd9Sstevel@tonic-gate * and store the full minor node in this table and use the 1409*7c478bd9Sstevel@tonic-gate * index in the table as minor node. This allows 256 minor nodes 1410*7c478bd9Sstevel@tonic-gate * and 1024 instances 1411*7c478bd9Sstevel@tonic-gate */ 1412*7c478bd9Sstevel@tonic-gate static int 1413*7c478bd9Sstevel@tonic-gate ugen_epxs_minor_nodes_create(ugen_state_t *ugenp, usb_ep_descr_t *ep_descr, 1414*7c478bd9Sstevel@tonic-gate uchar_t cfgval, uchar_t cfgidx, uchar_t iface, uchar_t alt) 1415*7c478bd9Sstevel@tonic-gate { 1416*7c478bd9Sstevel@tonic-gate char node_name[32], *type; 1417*7c478bd9Sstevel@tonic-gate int vid = ugenp->ug_dev_data->dev_descr->idVendor; 1418*7c478bd9Sstevel@tonic-gate int pid = ugenp->ug_dev_data->dev_descr->idProduct; 1419*7c478bd9Sstevel@tonic-gate minor_t minor; 1420*7c478bd9Sstevel@tonic-gate int minor_index; 1421*7c478bd9Sstevel@tonic-gate ugen_minor_t minor_code, minor_code_base; 1422*7c478bd9Sstevel@tonic-gate int owns_device = (usb_owns_device(ugenp->ug_dip) ? 1423*7c478bd9Sstevel@tonic-gate UGEN_OWNS_DEVICE : 0); 1424*7c478bd9Sstevel@tonic-gate int ep_index = 1425*7c478bd9Sstevel@tonic-gate usb_get_ep_index(ep_descr->bEndpointAddress); 1426*7c478bd9Sstevel@tonic-gate int ep_addr = 1427*7c478bd9Sstevel@tonic-gate ep_descr->bEndpointAddress & USB_EP_NUM_MASK; 1428*7c478bd9Sstevel@tonic-gate int ep_type = 1429*7c478bd9Sstevel@tonic-gate ep_descr->bmAttributes & USB_EP_ATTR_MASK; 1430*7c478bd9Sstevel@tonic-gate int ep_dir = 1431*7c478bd9Sstevel@tonic-gate ep_descr->bEndpointAddress & USB_EP_DIR_IN; 1432*7c478bd9Sstevel@tonic-gate 1433*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1434*7c478bd9Sstevel@tonic-gate "ugen_epxs_minor_nodes_create: " 1435*7c478bd9Sstevel@tonic-gate "cfgval=%d cfgidx=%d if=%d alt=%d ep=0x%x", 1436*7c478bd9Sstevel@tonic-gate cfgval, cfgidx, iface, alt, ep_addr); 1437*7c478bd9Sstevel@tonic-gate 1438*7c478bd9Sstevel@tonic-gate if (ugenp->ug_instance >= UGEN_MINOR_INSTANCE_LIMIT(ugenp)) { 1439*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1440*7c478bd9Sstevel@tonic-gate "instance number too high (%d)", ugenp->ug_instance); 1441*7c478bd9Sstevel@tonic-gate 1442*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1443*7c478bd9Sstevel@tonic-gate } 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate /* create stat and xfer minor node */ 1446*7c478bd9Sstevel@tonic-gate minor_code_base = 1447*7c478bd9Sstevel@tonic-gate ((ugen_minor_t)cfgval) << UGEN_MINOR_CFGVAL_SHIFT | 1448*7c478bd9Sstevel@tonic-gate ((ugen_minor_t)cfgidx) << UGEN_MINOR_CFGIDX_SHIFT | 1449*7c478bd9Sstevel@tonic-gate iface << UGEN_MINOR_IF_SHIFT | 1450*7c478bd9Sstevel@tonic-gate alt << UGEN_MINOR_ALT_SHIFT | 1451*7c478bd9Sstevel@tonic-gate ep_index << UGEN_MINOR_EPIDX_SHIFT | owns_device; 1452*7c478bd9Sstevel@tonic-gate minor_code = minor_code_base | UGEN_MINOR_EP_XFER_NODE; 1453*7c478bd9Sstevel@tonic-gate 1454*7c478bd9Sstevel@tonic-gate minor_index = ugen_minor_index_create(ugenp, minor_code); 1455*7c478bd9Sstevel@tonic-gate if (minor_index < 0) { 1456*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1457*7c478bd9Sstevel@tonic-gate "too many minor nodes, " 1458*7c478bd9Sstevel@tonic-gate "cannot create %d.%d.%d.%x", 1459*7c478bd9Sstevel@tonic-gate cfgval, iface, alt, ep_addr); 1460*7c478bd9Sstevel@tonic-gate /* carry on regardless */ 1461*7c478bd9Sstevel@tonic-gate 1462*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1463*7c478bd9Sstevel@tonic-gate } 1464*7c478bd9Sstevel@tonic-gate minor = (minor_index << UGEN_MINOR_IDX_SHIFT(ugenp)) | 1465*7c478bd9Sstevel@tonic-gate ugenp->ug_instance << UGEN_MINOR_INSTANCE_SHIFT(ugenp); 1466*7c478bd9Sstevel@tonic-gate 1467*7c478bd9Sstevel@tonic-gate if (ep_type == USB_EP_ATTR_CONTROL) { 1468*7c478bd9Sstevel@tonic-gate type = "cntrl"; 1469*7c478bd9Sstevel@tonic-gate } else { 1470*7c478bd9Sstevel@tonic-gate type = (ep_dir & USB_EP_DIR_IN) ? "in" : "out"; 1471*7c478bd9Sstevel@tonic-gate } 1472*7c478bd9Sstevel@tonic-gate 1473*7c478bd9Sstevel@tonic-gate /* 1474*7c478bd9Sstevel@tonic-gate * xfer ep node name: 1475*7c478bd9Sstevel@tonic-gate * vid.pid.[in|out|cntrl].[<cfg>.][if<iface>.][<alt>.]<ep addr> 1476*7c478bd9Sstevel@tonic-gate */ 1477*7c478bd9Sstevel@tonic-gate if ((ep_addr == 0) && owns_device) { 1478*7c478bd9Sstevel@tonic-gate (void) sprintf(node_name, "%x.%x.%s%d", 1479*7c478bd9Sstevel@tonic-gate vid, pid, type, ep_addr); 1480*7c478bd9Sstevel@tonic-gate } else if (cfgidx == 0 && alt == 0) { 1481*7c478bd9Sstevel@tonic-gate (void) sprintf(node_name, "%x.%x.if%d%s%d", 1482*7c478bd9Sstevel@tonic-gate vid, pid, iface, type, ep_addr); 1483*7c478bd9Sstevel@tonic-gate } else if (cfgidx == 0 && alt != 0) { 1484*7c478bd9Sstevel@tonic-gate (void) sprintf(node_name, "%x.%x.if%d.%d%s%d", 1485*7c478bd9Sstevel@tonic-gate vid, pid, iface, alt, type, ep_addr); 1486*7c478bd9Sstevel@tonic-gate } else if (cfgidx != 0 && alt == 0) { 1487*7c478bd9Sstevel@tonic-gate (void) sprintf(node_name, "%x.%x.cfg%dif%d%s%d", 1488*7c478bd9Sstevel@tonic-gate vid, pid, cfgval, iface, type, ep_addr); 1489*7c478bd9Sstevel@tonic-gate } else if (cfgidx != 0 && alt != 0) { 1490*7c478bd9Sstevel@tonic-gate (void) sprintf(node_name, "%x.%x.cfg%dif%d.%d%s%d", 1491*7c478bd9Sstevel@tonic-gate vid, pid, cfgval, iface, alt, 1492*7c478bd9Sstevel@tonic-gate type, ep_addr); 1493*7c478bd9Sstevel@tonic-gate } 1494*7c478bd9Sstevel@tonic-gate 1495*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1496*7c478bd9Sstevel@tonic-gate "minor=0x%x index=%d code=0x%" PRIx64 " name=%s", 1497*7c478bd9Sstevel@tonic-gate minor, minor_index, minor_code, node_name); 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate ASSERT(minor < L_MAXMIN); 1500*7c478bd9Sstevel@tonic-gate 1501*7c478bd9Sstevel@tonic-gate if ((ddi_create_minor_node(ugenp->ug_dip, node_name, 1502*7c478bd9Sstevel@tonic-gate S_IFCHR, minor, DDI_NT_UGEN, 0)) != DDI_SUCCESS) { 1503*7c478bd9Sstevel@tonic-gate 1504*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1505*7c478bd9Sstevel@tonic-gate } 1506*7c478bd9Sstevel@tonic-gate 1507*7c478bd9Sstevel@tonic-gate ugen_store_devt(ugenp, minor); 1508*7c478bd9Sstevel@tonic-gate 1509*7c478bd9Sstevel@tonic-gate minor_code = minor_code_base | UGEN_MINOR_EP_STAT_NODE; 1510*7c478bd9Sstevel@tonic-gate minor_index = ugen_minor_index_create(ugenp, minor_code); 1511*7c478bd9Sstevel@tonic-gate if (minor_index < 0) { 1512*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1513*7c478bd9Sstevel@tonic-gate "too many minor nodes, " 1514*7c478bd9Sstevel@tonic-gate "cannot create %d.%d.%d.%x stat", 1515*7c478bd9Sstevel@tonic-gate cfgval, iface, alt, 1516*7c478bd9Sstevel@tonic-gate ep_descr->bEndpointAddress); 1517*7c478bd9Sstevel@tonic-gate /* carry on regardless */ 1518*7c478bd9Sstevel@tonic-gate 1519*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1520*7c478bd9Sstevel@tonic-gate } 1521*7c478bd9Sstevel@tonic-gate minor = (minor_index << UGEN_MINOR_IDX_SHIFT(ugenp)) | 1522*7c478bd9Sstevel@tonic-gate ugenp->ug_instance << UGEN_MINOR_INSTANCE_SHIFT(ugenp); 1523*7c478bd9Sstevel@tonic-gate 1524*7c478bd9Sstevel@tonic-gate (void) strcat(node_name, "stat"); 1525*7c478bd9Sstevel@tonic-gate 1526*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1527*7c478bd9Sstevel@tonic-gate "minor=0x%x index=%d code=0x%" PRIx64 " name=%s", 1528*7c478bd9Sstevel@tonic-gate minor, minor_index, minor_code, node_name); 1529*7c478bd9Sstevel@tonic-gate 1530*7c478bd9Sstevel@tonic-gate ASSERT(minor < L_MAXMIN); 1531*7c478bd9Sstevel@tonic-gate 1532*7c478bd9Sstevel@tonic-gate if ((ddi_create_minor_node(ugenp->ug_dip, node_name, 1533*7c478bd9Sstevel@tonic-gate S_IFCHR, minor, DDI_NT_UGEN, 0)) != DDI_SUCCESS) { 1534*7c478bd9Sstevel@tonic-gate 1535*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1536*7c478bd9Sstevel@tonic-gate } 1537*7c478bd9Sstevel@tonic-gate 1538*7c478bd9Sstevel@tonic-gate ugen_store_devt(ugenp, minor); 1539*7c478bd9Sstevel@tonic-gate 1540*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1541*7c478bd9Sstevel@tonic-gate } 1542*7c478bd9Sstevel@tonic-gate 1543*7c478bd9Sstevel@tonic-gate 1544*7c478bd9Sstevel@tonic-gate /* 1545*7c478bd9Sstevel@tonic-gate * close all non-default pipes and drain default pipe 1546*7c478bd9Sstevel@tonic-gate */ 1547*7c478bd9Sstevel@tonic-gate static void 1548*7c478bd9Sstevel@tonic-gate ugen_epx_shutdown(ugen_state_t *ugenp) 1549*7c478bd9Sstevel@tonic-gate { 1550*7c478bd9Sstevel@tonic-gate int i; 1551*7c478bd9Sstevel@tonic-gate 1552*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1553*7c478bd9Sstevel@tonic-gate "ugen_epx_shutdown:"); 1554*7c478bd9Sstevel@tonic-gate 1555*7c478bd9Sstevel@tonic-gate for (i = 0; i < UGEN_N_ENDPOINTS; i++) { 1556*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = &ugenp->ug_ep[i]; 1557*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1558*7c478bd9Sstevel@tonic-gate if (epp->ep_state != UGEN_EP_STATE_NONE) { 1559*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1560*7c478bd9Sstevel@tonic-gate (void) usb_serialize_access(epp->ep_ser_cookie, 1561*7c478bd9Sstevel@tonic-gate USB_WAIT, 0); 1562*7c478bd9Sstevel@tonic-gate (void) ugen_epx_close_pipe(ugenp, epp); 1563*7c478bd9Sstevel@tonic-gate usb_release_access(epp->ep_ser_cookie); 1564*7c478bd9Sstevel@tonic-gate } else { 1565*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1566*7c478bd9Sstevel@tonic-gate } 1567*7c478bd9Sstevel@tonic-gate } 1568*7c478bd9Sstevel@tonic-gate } 1569*7c478bd9Sstevel@tonic-gate 1570*7c478bd9Sstevel@tonic-gate 1571*7c478bd9Sstevel@tonic-gate /* 1572*7c478bd9Sstevel@tonic-gate * find cfg index corresponding to cfg value 1573*7c478bd9Sstevel@tonic-gate */ 1574*7c478bd9Sstevel@tonic-gate static int 1575*7c478bd9Sstevel@tonic-gate ugen_cfgval2idx(ugen_state_t *ugenp, uint_t cfgval) 1576*7c478bd9Sstevel@tonic-gate { 1577*7c478bd9Sstevel@tonic-gate usb_cfg_data_t *dev_cfg = ugenp->ug_dev_data->dev_cfg; 1578*7c478bd9Sstevel@tonic-gate int cfgidx; 1579*7c478bd9Sstevel@tonic-gate 1580*7c478bd9Sstevel@tonic-gate for (cfgidx = 0; cfgidx < ugenp->ug_dev_data->dev_n_cfg; cfgidx++) { 1581*7c478bd9Sstevel@tonic-gate dev_cfg = &ugenp->ug_dev_data->dev_cfg[cfgidx]; 1582*7c478bd9Sstevel@tonic-gate if (cfgval == dev_cfg->cfg_descr.bConfigurationValue) { 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate return (cfgidx); 1585*7c478bd9Sstevel@tonic-gate } 1586*7c478bd9Sstevel@tonic-gate } 1587*7c478bd9Sstevel@tonic-gate 1588*7c478bd9Sstevel@tonic-gate ASSERT(cfgidx < ugenp->ug_dev_data->dev_n_cfg); 1589*7c478bd9Sstevel@tonic-gate 1590*7c478bd9Sstevel@tonic-gate return (0); 1591*7c478bd9Sstevel@tonic-gate } 1592*7c478bd9Sstevel@tonic-gate 1593*7c478bd9Sstevel@tonic-gate 1594*7c478bd9Sstevel@tonic-gate /* 1595*7c478bd9Sstevel@tonic-gate * check if any node is open 1596*7c478bd9Sstevel@tonic-gate */ 1597*7c478bd9Sstevel@tonic-gate static int 1598*7c478bd9Sstevel@tonic-gate ugen_epxs_check_open_nodes(ugen_state_t *ugenp) 1599*7c478bd9Sstevel@tonic-gate { 1600*7c478bd9Sstevel@tonic-gate int i; 1601*7c478bd9Sstevel@tonic-gate 1602*7c478bd9Sstevel@tonic-gate for (i = 1; i < UGEN_N_ENDPOINTS; i++) { 1603*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = &ugenp->ug_ep[i]; 1604*7c478bd9Sstevel@tonic-gate 1605*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1606*7c478bd9Sstevel@tonic-gate 1607*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1608*7c478bd9Sstevel@tonic-gate "ugen_epxs_check_open_nodes: epp=%d, ep_state=0x%x", 1609*7c478bd9Sstevel@tonic-gate i, epp->ep_state); 1610*7c478bd9Sstevel@tonic-gate 1611*7c478bd9Sstevel@tonic-gate if (epp->ep_state & UGEN_EP_STATE_XS_OPEN) { 1612*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1613*7c478bd9Sstevel@tonic-gate 1614*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1615*7c478bd9Sstevel@tonic-gate } 1616*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1617*7c478bd9Sstevel@tonic-gate } 1618*7c478bd9Sstevel@tonic-gate 1619*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1620*7c478bd9Sstevel@tonic-gate } 1621*7c478bd9Sstevel@tonic-gate 1622*7c478bd9Sstevel@tonic-gate 1623*7c478bd9Sstevel@tonic-gate /* 1624*7c478bd9Sstevel@tonic-gate * check if we can switch alternate 1625*7c478bd9Sstevel@tonic-gate */ 1626*7c478bd9Sstevel@tonic-gate static int 1627*7c478bd9Sstevel@tonic-gate ugen_epxs_check_alt_switch(ugen_state_t *ugenp, uchar_t iface, uchar_t cfgidx) 1628*7c478bd9Sstevel@tonic-gate { 1629*7c478bd9Sstevel@tonic-gate int i; 1630*7c478bd9Sstevel@tonic-gate 1631*7c478bd9Sstevel@tonic-gate for (i = 1; i < UGEN_N_ENDPOINTS; i++) { 1632*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = &ugenp->ug_ep[i]; 1633*7c478bd9Sstevel@tonic-gate 1634*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1635*7c478bd9Sstevel@tonic-gate 1636*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1637*7c478bd9Sstevel@tonic-gate "ugen_epxs_check_alt_switch: epp=%d, ep_state=0x%x", 1638*7c478bd9Sstevel@tonic-gate i, epp->ep_state); 1639*7c478bd9Sstevel@tonic-gate 1640*7c478bd9Sstevel@tonic-gate /* 1641*7c478bd9Sstevel@tonic-gate * if the endpoint is open and part of this cfg and interface 1642*7c478bd9Sstevel@tonic-gate * then we cannot switch alternates 1643*7c478bd9Sstevel@tonic-gate */ 1644*7c478bd9Sstevel@tonic-gate if ((epp->ep_state & UGEN_EP_STATE_XS_OPEN) && 1645*7c478bd9Sstevel@tonic-gate (epp->ep_cfgidx == cfgidx) && 1646*7c478bd9Sstevel@tonic-gate (epp->ep_if == iface)) { 1647*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1648*7c478bd9Sstevel@tonic-gate 1649*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1650*7c478bd9Sstevel@tonic-gate } 1651*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1652*7c478bd9Sstevel@tonic-gate } 1653*7c478bd9Sstevel@tonic-gate 1654*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1655*7c478bd9Sstevel@tonic-gate } 1656*7c478bd9Sstevel@tonic-gate 1657*7c478bd9Sstevel@tonic-gate 1658*7c478bd9Sstevel@tonic-gate /* 1659*7c478bd9Sstevel@tonic-gate * implicit switch to new cfg and alt 1660*7c478bd9Sstevel@tonic-gate * If a crummy device fails usb_get_cfg or usb_get_alt_if, we carry on 1661*7c478bd9Sstevel@tonic-gate * regardless so at least the device can be opened. 1662*7c478bd9Sstevel@tonic-gate */ 1663*7c478bd9Sstevel@tonic-gate static int 1664*7c478bd9Sstevel@tonic-gate ugen_epxs_switch_cfg_alt(ugen_state_t *ugenp, ugen_ep_t *epp, dev_t dev) 1665*7c478bd9Sstevel@tonic-gate { 1666*7c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 1667*7c478bd9Sstevel@tonic-gate uint_t alt; 1668*7c478bd9Sstevel@tonic-gate uint_t new_alt = UGEN_MINOR_ALT(ugenp, dev); 1669*7c478bd9Sstevel@tonic-gate uint_t new_if = UGEN_MINOR_IF(ugenp, dev); 1670*7c478bd9Sstevel@tonic-gate uint_t cur_if = epp->ep_if; 1671*7c478bd9Sstevel@tonic-gate uint_t new_cfgidx = UGEN_MINOR_CFGIDX(ugenp, dev); 1672*7c478bd9Sstevel@tonic-gate uint_t cur_cfgidx; 1673*7c478bd9Sstevel@tonic-gate uint_t cfgval; 1674*7c478bd9Sstevel@tonic-gate int switched = 0; 1675*7c478bd9Sstevel@tonic-gate 1676*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1677*7c478bd9Sstevel@tonic-gate "ugen_epxs_switch_cfg_alt: old cfgidx=%d, if=%d alt=%d", 1678*7c478bd9Sstevel@tonic-gate epp->ep_cfgidx, epp->ep_if, epp->ep_alt); 1679*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1680*7c478bd9Sstevel@tonic-gate "new cfgidx=%d, if=%d alt=%d ep_state=0x%x", 1681*7c478bd9Sstevel@tonic-gate new_cfgidx, new_if, new_alt, epp->ep_state); 1682*7c478bd9Sstevel@tonic-gate 1683*7c478bd9Sstevel@tonic-gate /* no need to switch if there is only 1 cfg, 1 iface and no alts */ 1684*7c478bd9Sstevel@tonic-gate if ((new_if == 0) && (new_alt == 0) && 1685*7c478bd9Sstevel@tonic-gate (ugenp->ug_dev_data->dev_n_cfg == 1) && 1686*7c478bd9Sstevel@tonic-gate (ugenp->ug_dev_data->dev_cfg[0].cfg_n_if == 1) && 1687*7c478bd9Sstevel@tonic-gate (ugenp->ug_dev_data-> 1688*7c478bd9Sstevel@tonic-gate dev_cfg[0].cfg_if[new_if].if_n_alt == 1)) { 1689*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1690*7c478bd9Sstevel@tonic-gate "no need for switching: n_cfg=%d n_alt=%d", 1691*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_data->dev_n_cfg, 1692*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_data-> 1693*7c478bd9Sstevel@tonic-gate dev_cfg[0].cfg_if[new_if].if_n_alt); 1694*7c478bd9Sstevel@tonic-gate 1695*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_alt == new_alt); 1696*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_cfgidx == new_cfgidx); 1697*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_if == new_if); 1698*7c478bd9Sstevel@tonic-gate 1699*7c478bd9Sstevel@tonic-gate return (rval); 1700*7c478bd9Sstevel@tonic-gate } 1701*7c478bd9Sstevel@tonic-gate 1702*7c478bd9Sstevel@tonic-gate /* no switch for default endpoint */ 1703*7c478bd9Sstevel@tonic-gate if (epp->ep_descr.bEndpointAddress == 0) { 1704*7c478bd9Sstevel@tonic-gate 1705*7c478bd9Sstevel@tonic-gate return (rval); 1706*7c478bd9Sstevel@tonic-gate } 1707*7c478bd9Sstevel@tonic-gate 1708*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1709*7c478bd9Sstevel@tonic-gate if ((ugenp->ug_dev_data->dev_n_cfg > 1) && 1710*7c478bd9Sstevel@tonic-gate usb_get_cfg(ugenp->ug_dip, &cfgval, 1711*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP) == USB_SUCCESS) { 1712*7c478bd9Sstevel@tonic-gate 1713*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1714*7c478bd9Sstevel@tonic-gate 1715*7c478bd9Sstevel@tonic-gate cur_cfgidx = ugen_cfgval2idx(ugenp, cfgval); 1716*7c478bd9Sstevel@tonic-gate 1717*7c478bd9Sstevel@tonic-gate if (new_cfgidx != cur_cfgidx) { 1718*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1719*7c478bd9Sstevel@tonic-gate 1720*7c478bd9Sstevel@tonic-gate /* 1721*7c478bd9Sstevel@tonic-gate * we can't change config if any node 1722*7c478bd9Sstevel@tonic-gate * is open 1723*7c478bd9Sstevel@tonic-gate */ 1724*7c478bd9Sstevel@tonic-gate if (ugen_epxs_check_open_nodes(ugenp) == 1725*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1726*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1727*7c478bd9Sstevel@tonic-gate 1728*7c478bd9Sstevel@tonic-gate return (USB_BUSY); 1729*7c478bd9Sstevel@tonic-gate } 1730*7c478bd9Sstevel@tonic-gate 1731*7c478bd9Sstevel@tonic-gate /* 1732*7c478bd9Sstevel@tonic-gate * we are going to do this synchronously to 1733*7c478bd9Sstevel@tonic-gate * keep it simple. 1734*7c478bd9Sstevel@tonic-gate * This should never hang forever. 1735*7c478bd9Sstevel@tonic-gate */ 1736*7c478bd9Sstevel@tonic-gate if ((rval = usb_set_cfg(ugenp->ug_dip, 1737*7c478bd9Sstevel@tonic-gate new_cfgidx, USB_FLAGS_SLEEP, NULL, 1738*7c478bd9Sstevel@tonic-gate NULL)) != USB_SUCCESS) { 1739*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_XFER, 1740*7c478bd9Sstevel@tonic-gate ugenp->ug_log_hdl, 1741*7c478bd9Sstevel@tonic-gate "implicit set cfg (%" PRId64 1742*7c478bd9Sstevel@tonic-gate ") failed (%d)", 1743*7c478bd9Sstevel@tonic-gate UGEN_MINOR_CFGIDX(ugenp, dev), rval); 1744*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1745*7c478bd9Sstevel@tonic-gate 1746*7c478bd9Sstevel@tonic-gate return (rval); 1747*7c478bd9Sstevel@tonic-gate } 1748*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1749*7c478bd9Sstevel@tonic-gate epp->ep_if = new_if; 1750*7c478bd9Sstevel@tonic-gate switched++; 1751*7c478bd9Sstevel@tonic-gate } 1752*7c478bd9Sstevel@tonic-gate epp->ep_cfgidx = new_cfgidx; 1753*7c478bd9Sstevel@tonic-gate 1754*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1755*7c478bd9Sstevel@tonic-gate } 1756*7c478bd9Sstevel@tonic-gate 1757*7c478bd9Sstevel@tonic-gate /* 1758*7c478bd9Sstevel@tonic-gate * implicitly switch to new alternate if 1759*7c478bd9Sstevel@tonic-gate * - we have not switched configuration (if we 1760*7c478bd9Sstevel@tonic-gate * we switched config, the alternate must be 0) 1761*7c478bd9Sstevel@tonic-gate * - n_alts is > 1 1762*7c478bd9Sstevel@tonic-gate * - if the device supports get_alternate iface 1763*7c478bd9Sstevel@tonic-gate */ 1764*7c478bd9Sstevel@tonic-gate if ((switched && (new_alt > 0)) || 1765*7c478bd9Sstevel@tonic-gate ((ugenp->ug_dev_data->dev_cfg[new_cfgidx]. 1766*7c478bd9Sstevel@tonic-gate cfg_if[new_if].if_n_alt > 1) && 1767*7c478bd9Sstevel@tonic-gate (usb_get_alt_if(ugenp->ug_dip, new_if, &alt, 1768*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP) == USB_SUCCESS))) { 1769*7c478bd9Sstevel@tonic-gate if (switched || (alt != new_alt)) { 1770*7c478bd9Sstevel@tonic-gate if (ugen_epxs_check_alt_switch(ugenp, cur_if, 1771*7c478bd9Sstevel@tonic-gate new_cfgidx) != USB_SUCCESS) { 1772*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1773*7c478bd9Sstevel@tonic-gate 1774*7c478bd9Sstevel@tonic-gate return (USB_BUSY); 1775*7c478bd9Sstevel@tonic-gate } 1776*7c478bd9Sstevel@tonic-gate if ((rval = usb_set_alt_if(ugenp->ug_dip, new_if, 1777*7c478bd9Sstevel@tonic-gate new_alt, USB_FLAGS_SLEEP, NULL, NULL)) != 1778*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1779*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_XFER, 1780*7c478bd9Sstevel@tonic-gate ugenp->ug_log_hdl, 1781*7c478bd9Sstevel@tonic-gate "implicit set new alternate " 1782*7c478bd9Sstevel@tonic-gate "(%d) failed (%d)", new_alt, rval); 1783*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1784*7c478bd9Sstevel@tonic-gate 1785*7c478bd9Sstevel@tonic-gate return (rval); 1786*7c478bd9Sstevel@tonic-gate } 1787*7c478bd9Sstevel@tonic-gate } 1788*7c478bd9Sstevel@tonic-gate } 1789*7c478bd9Sstevel@tonic-gate 1790*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1791*7c478bd9Sstevel@tonic-gate epp->ep_alt = new_alt; 1792*7c478bd9Sstevel@tonic-gate ugen_update_ep_descr(ugenp, epp); 1793*7c478bd9Sstevel@tonic-gate 1794*7c478bd9Sstevel@tonic-gate return (rval); 1795*7c478bd9Sstevel@tonic-gate } 1796*7c478bd9Sstevel@tonic-gate 1797*7c478bd9Sstevel@tonic-gate 1798*7c478bd9Sstevel@tonic-gate /* 1799*7c478bd9Sstevel@tonic-gate * update endpoint descriptor in ugen_ep structure after 1800*7c478bd9Sstevel@tonic-gate * switching configuration or alternate 1801*7c478bd9Sstevel@tonic-gate */ 1802*7c478bd9Sstevel@tonic-gate static void 1803*7c478bd9Sstevel@tonic-gate ugen_update_ep_descr(ugen_state_t *ugenp, ugen_ep_t *epp) 1804*7c478bd9Sstevel@tonic-gate { 1805*7c478bd9Sstevel@tonic-gate usb_cfg_data_t *dev_cfg = ugenp->ug_dev_data->dev_cfg; 1806*7c478bd9Sstevel@tonic-gate usb_if_data_t *if_data; 1807*7c478bd9Sstevel@tonic-gate usb_alt_if_data_t *alt_if_data; 1808*7c478bd9Sstevel@tonic-gate usb_ep_data_t *ep_data; 1809*7c478bd9Sstevel@tonic-gate int ep; 1810*7c478bd9Sstevel@tonic-gate 1811*7c478bd9Sstevel@tonic-gate dev_cfg = &ugenp->ug_dev_data->dev_cfg[epp->ep_cfgidx]; 1812*7c478bd9Sstevel@tonic-gate if_data = &dev_cfg->cfg_if[epp->ep_if]; 1813*7c478bd9Sstevel@tonic-gate alt_if_data = &if_data->if_alt[epp->ep_alt]; 1814*7c478bd9Sstevel@tonic-gate for (ep = 0; ep < alt_if_data->altif_n_ep; ep++) { 1815*7c478bd9Sstevel@tonic-gate ep_data = &alt_if_data->altif_ep[ep]; 1816*7c478bd9Sstevel@tonic-gate if (usb_get_ep_index(ep_data->ep_descr. 1817*7c478bd9Sstevel@tonic-gate bEndpointAddress) == 1818*7c478bd9Sstevel@tonic-gate usb_get_ep_index(epp->ep_descr. 1819*7c478bd9Sstevel@tonic-gate bEndpointAddress)) { 1820*7c478bd9Sstevel@tonic-gate epp->ep_descr = ep_data->ep_descr; 1821*7c478bd9Sstevel@tonic-gate 1822*7c478bd9Sstevel@tonic-gate break; 1823*7c478bd9Sstevel@tonic-gate } 1824*7c478bd9Sstevel@tonic-gate } 1825*7c478bd9Sstevel@tonic-gate } 1826*7c478bd9Sstevel@tonic-gate 1827*7c478bd9Sstevel@tonic-gate 1828*7c478bd9Sstevel@tonic-gate /* 1829*7c478bd9Sstevel@tonic-gate * Xfer endpoint management 1830*7c478bd9Sstevel@tonic-gate * 1831*7c478bd9Sstevel@tonic-gate * open an endpoint for xfers 1832*7c478bd9Sstevel@tonic-gate * 1833*7c478bd9Sstevel@tonic-gate * Return values: errno 1834*7c478bd9Sstevel@tonic-gate */ 1835*7c478bd9Sstevel@tonic-gate static int 1836*7c478bd9Sstevel@tonic-gate ugen_epx_open(ugen_state_t *ugenp, dev_t dev, int flag) 1837*7c478bd9Sstevel@tonic-gate { 1838*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 1839*7c478bd9Sstevel@tonic-gate int rval; 1840*7c478bd9Sstevel@tonic-gate 1841*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1842*7c478bd9Sstevel@tonic-gate 1843*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1844*7c478bd9Sstevel@tonic-gate "ugen_epx_open: minor=0x%x flag=0x%x ep_state=0x%x", 1845*7c478bd9Sstevel@tonic-gate getminor(dev), flag, epp->ep_state); 1846*7c478bd9Sstevel@tonic-gate 1847*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_state & UGEN_EP_STATE_ACTIVE); 1848*7c478bd9Sstevel@tonic-gate 1849*7c478bd9Sstevel@tonic-gate /* implicit switch to new cfg & alt */ 1850*7c478bd9Sstevel@tonic-gate if ((epp->ep_state & UGEN_EP_STATE_XFER_OPEN) != 0) { 1851*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1852*7c478bd9Sstevel@tonic-gate 1853*7c478bd9Sstevel@tonic-gate return (EBUSY); 1854*7c478bd9Sstevel@tonic-gate } 1855*7c478bd9Sstevel@tonic-gate if ((rval = ugen_epxs_switch_cfg_alt(ugenp, epp, dev)) == 1856*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1857*7c478bd9Sstevel@tonic-gate rval = ugen_epx_open_pipe(ugenp, epp, flag); 1858*7c478bd9Sstevel@tonic-gate } 1859*7c478bd9Sstevel@tonic-gate 1860*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1861*7c478bd9Sstevel@tonic-gate "ugen_epx_open: state=0x%x", epp->ep_state); 1862*7c478bd9Sstevel@tonic-gate 1863*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_state & UGEN_EP_STATE_ACTIVE); 1864*7c478bd9Sstevel@tonic-gate epp->ep_done = epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 1865*7c478bd9Sstevel@tonic-gate 1866*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1867*7c478bd9Sstevel@tonic-gate 1868*7c478bd9Sstevel@tonic-gate return (usb_rval2errno(rval)); 1869*7c478bd9Sstevel@tonic-gate } 1870*7c478bd9Sstevel@tonic-gate 1871*7c478bd9Sstevel@tonic-gate 1872*7c478bd9Sstevel@tonic-gate /* 1873*7c478bd9Sstevel@tonic-gate * close an endpoint for xfers 1874*7c478bd9Sstevel@tonic-gate */ 1875*7c478bd9Sstevel@tonic-gate static void 1876*7c478bd9Sstevel@tonic-gate ugen_epx_close(ugen_state_t *ugenp, dev_t dev, int flag) 1877*7c478bd9Sstevel@tonic-gate { 1878*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 1879*7c478bd9Sstevel@tonic-gate 1880*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1881*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1882*7c478bd9Sstevel@tonic-gate "ugen_epx_close: dev=0x%lx flag=0x%x state=0x%x", dev, flag, 1883*7c478bd9Sstevel@tonic-gate epp->ep_state); 1884*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1885*7c478bd9Sstevel@tonic-gate 1886*7c478bd9Sstevel@tonic-gate ugen_epx_close_pipe(ugenp, epp); 1887*7c478bd9Sstevel@tonic-gate 1888*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1889*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1890*7c478bd9Sstevel@tonic-gate "ugen_epx_close: state=0x%x", epp->ep_state); 1891*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_state & UGEN_EP_STATE_ACTIVE); 1892*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_bp == NULL); 1893*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_done == 0); 1894*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_data == NULL); 1895*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1896*7c478bd9Sstevel@tonic-gate } 1897*7c478bd9Sstevel@tonic-gate 1898*7c478bd9Sstevel@tonic-gate 1899*7c478bd9Sstevel@tonic-gate /* 1900*7c478bd9Sstevel@tonic-gate * open pipe for this endpoint 1901*7c478bd9Sstevel@tonic-gate * If the pipe is an interrupt IN pipe, start polling immediately 1902*7c478bd9Sstevel@tonic-gate */ 1903*7c478bd9Sstevel@tonic-gate static int 1904*7c478bd9Sstevel@tonic-gate ugen_epx_open_pipe(ugen_state_t *ugenp, ugen_ep_t *epp, int flag) 1905*7c478bd9Sstevel@tonic-gate { 1906*7c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 1907*7c478bd9Sstevel@tonic-gate 1908*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1909*7c478bd9Sstevel@tonic-gate "ugen_epx_open_pipe: epp=0x%p flag=%d state=0x%x", 1910*7c478bd9Sstevel@tonic-gate epp, flag, epp->ep_state); 1911*7c478bd9Sstevel@tonic-gate 1912*7c478bd9Sstevel@tonic-gate epp->ep_state |= UGEN_EP_STATE_XFER_OPEN; 1913*7c478bd9Sstevel@tonic-gate epp->ep_xfer_oflag = flag; 1914*7c478bd9Sstevel@tonic-gate 1915*7c478bd9Sstevel@tonic-gate /* if default pipe, just copy the handle */ 1916*7c478bd9Sstevel@tonic-gate if ((epp->ep_descr.bEndpointAddress & USB_EP_NUM_MASK) == 0) { 1917*7c478bd9Sstevel@tonic-gate epp->ep_ph = ugenp->ug_dev_data->dev_default_ph; 1918*7c478bd9Sstevel@tonic-gate } else { 1919*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1920*7c478bd9Sstevel@tonic-gate 1921*7c478bd9Sstevel@tonic-gate /* open pipe */ 1922*7c478bd9Sstevel@tonic-gate rval = usb_pipe_open(ugenp->ug_dip, 1923*7c478bd9Sstevel@tonic-gate &epp->ep_descr, &epp->ep_pipe_policy, 1924*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, &epp->ep_ph); 1925*7c478bd9Sstevel@tonic-gate 1926*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1927*7c478bd9Sstevel@tonic-gate 1928*7c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 1929*7c478bd9Sstevel@tonic-gate (void) usb_pipe_set_private(epp->ep_ph, 1930*7c478bd9Sstevel@tonic-gate (usb_opaque_t)epp); 1931*7c478bd9Sstevel@tonic-gate 1932*7c478bd9Sstevel@tonic-gate /* 1933*7c478bd9Sstevel@tonic-gate * if interrupt IN pipe, and one xfer mode 1934*7c478bd9Sstevel@tonic-gate * has not been set, start polling immediately 1935*7c478bd9Sstevel@tonic-gate */ 1936*7c478bd9Sstevel@tonic-gate if ((UGEN_XFER_TYPE(epp) == USB_EP_ATTR_INTR) && 1937*7c478bd9Sstevel@tonic-gate (!(epp->ep_one_xfer)) && 1938*7c478bd9Sstevel@tonic-gate (UGEN_XFER_DIR(epp) == USB_EP_DIR_IN)) { 1939*7c478bd9Sstevel@tonic-gate if ((rval = ugen_epx_intr_IN_start_polling( 1940*7c478bd9Sstevel@tonic-gate ugenp, epp)) != USB_SUCCESS) { 1941*7c478bd9Sstevel@tonic-gate 1942*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1943*7c478bd9Sstevel@tonic-gate usb_pipe_close(ugenp->ug_dip, 1944*7c478bd9Sstevel@tonic-gate epp->ep_ph, USB_FLAGS_SLEEP, 1945*7c478bd9Sstevel@tonic-gate NULL, NULL); 1946*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1947*7c478bd9Sstevel@tonic-gate 1948*7c478bd9Sstevel@tonic-gate epp->ep_ph = NULL; 1949*7c478bd9Sstevel@tonic-gate } else { 1950*7c478bd9Sstevel@tonic-gate epp->ep_state |= 1951*7c478bd9Sstevel@tonic-gate UGEN_EP_STATE_INTR_IN_POLLING_ON; 1952*7c478bd9Sstevel@tonic-gate 1953*7c478bd9Sstevel@tonic-gate /* allow for about 1 sec of data */ 1954*7c478bd9Sstevel@tonic-gate epp->ep_buf_limit = 1955*7c478bd9Sstevel@tonic-gate (1000/epp->ep_descr.bInterval) * 1956*7c478bd9Sstevel@tonic-gate epp->ep_descr.wMaxPacketSize; 1957*7c478bd9Sstevel@tonic-gate } 1958*7c478bd9Sstevel@tonic-gate } 1959*7c478bd9Sstevel@tonic-gate } 1960*7c478bd9Sstevel@tonic-gate } 1961*7c478bd9Sstevel@tonic-gate 1962*7c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 1963*7c478bd9Sstevel@tonic-gate epp->ep_state &= ~(UGEN_EP_STATE_XFER_OPEN | 1964*7c478bd9Sstevel@tonic-gate UGEN_EP_STATE_INTR_IN_POLLING_ON); 1965*7c478bd9Sstevel@tonic-gate } 1966*7c478bd9Sstevel@tonic-gate 1967*7c478bd9Sstevel@tonic-gate return (rval); 1968*7c478bd9Sstevel@tonic-gate } 1969*7c478bd9Sstevel@tonic-gate 1970*7c478bd9Sstevel@tonic-gate 1971*7c478bd9Sstevel@tonic-gate /* 1972*7c478bd9Sstevel@tonic-gate * close an endpoint pipe 1973*7c478bd9Sstevel@tonic-gate */ 1974*7c478bd9Sstevel@tonic-gate static void 1975*7c478bd9Sstevel@tonic-gate ugen_epx_close_pipe(ugen_state_t *ugenp, ugen_ep_t *epp) 1976*7c478bd9Sstevel@tonic-gate { 1977*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1978*7c478bd9Sstevel@tonic-gate "ugen_epx_close_pipe: epp=0x%p", epp); 1979*7c478bd9Sstevel@tonic-gate 1980*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1981*7c478bd9Sstevel@tonic-gate if (epp->ep_state & UGEN_EP_STATE_XFER_OPEN) { 1982*7c478bd9Sstevel@tonic-gate epp->ep_state &= ~(UGEN_EP_STATE_XFER_OPEN | 1983*7c478bd9Sstevel@tonic-gate UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED | 1984*7c478bd9Sstevel@tonic-gate UGEN_EP_STATE_INTR_IN_POLLING_ON); 1985*7c478bd9Sstevel@tonic-gate 1986*7c478bd9Sstevel@tonic-gate if (epp->ep_ph == ugenp->ug_dev_data->dev_default_ph) { 1987*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1988*7c478bd9Sstevel@tonic-gate 1989*7c478bd9Sstevel@tonic-gate (void) usb_pipe_drain_reqs(ugenp->ug_dip, 1990*7c478bd9Sstevel@tonic-gate epp->ep_ph, 0, USB_FLAGS_SLEEP, 1991*7c478bd9Sstevel@tonic-gate NULL, NULL); 1992*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1993*7c478bd9Sstevel@tonic-gate } else { 1994*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 1995*7c478bd9Sstevel@tonic-gate usb_pipe_close(ugenp->ug_dip, 1996*7c478bd9Sstevel@tonic-gate epp->ep_ph, USB_FLAGS_SLEEP, NULL, NULL); 1997*7c478bd9Sstevel@tonic-gate 1998*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 1999*7c478bd9Sstevel@tonic-gate epp->ep_ph = NULL; 2000*7c478bd9Sstevel@tonic-gate } 2001*7c478bd9Sstevel@tonic-gate 2002*7c478bd9Sstevel@tonic-gate freemsg(epp->ep_data); 2003*7c478bd9Sstevel@tonic-gate epp->ep_ph = NULL; 2004*7c478bd9Sstevel@tonic-gate epp->ep_data = NULL; 2005*7c478bd9Sstevel@tonic-gate } 2006*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_ph == NULL); 2007*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_data == NULL); 2008*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2009*7c478bd9Sstevel@tonic-gate } 2010*7c478bd9Sstevel@tonic-gate 2011*7c478bd9Sstevel@tonic-gate 2012*7c478bd9Sstevel@tonic-gate /* 2013*7c478bd9Sstevel@tonic-gate * start endpoint xfer 2014*7c478bd9Sstevel@tonic-gate * 2015*7c478bd9Sstevel@tonic-gate * We first serialize at endpoint level for only one request at the time 2016*7c478bd9Sstevel@tonic-gate * 2017*7c478bd9Sstevel@tonic-gate * Return values: errno 2018*7c478bd9Sstevel@tonic-gate */ 2019*7c478bd9Sstevel@tonic-gate static int 2020*7c478bd9Sstevel@tonic-gate ugen_epx_req(ugen_state_t *ugenp, struct buf *bp) 2021*7c478bd9Sstevel@tonic-gate { 2022*7c478bd9Sstevel@tonic-gate dev_t dev = bp->b_edev; 2023*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 2024*7c478bd9Sstevel@tonic-gate boolean_t wait = B_FALSE; 2025*7c478bd9Sstevel@tonic-gate int rval = 0; 2026*7c478bd9Sstevel@tonic-gate 2027*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2028*7c478bd9Sstevel@tonic-gate "ugen_epx_req: bp=0x%p dev=0x%lx", (void *)bp, dev); 2029*7c478bd9Sstevel@tonic-gate 2030*7c478bd9Sstevel@tonic-gate /* single thread per endpoint, one request at the time */ 2031*7c478bd9Sstevel@tonic-gate if (usb_serialize_access(epp->ep_ser_cookie, USB_WAIT_SIG, 0) <= 2032*7c478bd9Sstevel@tonic-gate 0) { 2033*7c478bd9Sstevel@tonic-gate 2034*7c478bd9Sstevel@tonic-gate return (EINTR); 2035*7c478bd9Sstevel@tonic-gate } 2036*7c478bd9Sstevel@tonic-gate 2037*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 2038*7c478bd9Sstevel@tonic-gate switch (ugenp->ug_dev_state) { 2039*7c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE: 2040*7c478bd9Sstevel@tonic-gate 2041*7c478bd9Sstevel@tonic-gate break; 2042*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 2043*7c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED: 2044*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2045*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_DISCONNECTED; 2046*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2047*7c478bd9Sstevel@tonic-gate rval = ENODEV; 2048*7c478bd9Sstevel@tonic-gate 2049*7c478bd9Sstevel@tonic-gate break; 2050*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RESUME: 2051*7c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED: 2052*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2053*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_SUSPENDED; 2054*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2055*7c478bd9Sstevel@tonic-gate rval = EBADF; 2056*7c478bd9Sstevel@tonic-gate 2057*7c478bd9Sstevel@tonic-gate break; 2058*7c478bd9Sstevel@tonic-gate default: 2059*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2060*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_HW_ERR; 2061*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2062*7c478bd9Sstevel@tonic-gate rval = EIO; 2063*7c478bd9Sstevel@tonic-gate 2064*7c478bd9Sstevel@tonic-gate break; 2065*7c478bd9Sstevel@tonic-gate } 2066*7c478bd9Sstevel@tonic-gate 2067*7c478bd9Sstevel@tonic-gate #ifndef __lock_lint 2068*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2069*7c478bd9Sstevel@tonic-gate "ugen_epx_req: lcmd_status=0x%x", epp->ep_lcmd_status); 2070*7c478bd9Sstevel@tonic-gate #endif 2071*7c478bd9Sstevel@tonic-gate 2072*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 2073*7c478bd9Sstevel@tonic-gate 2074*7c478bd9Sstevel@tonic-gate if (rval) { 2075*7c478bd9Sstevel@tonic-gate usb_release_access(epp->ep_ser_cookie); 2076*7c478bd9Sstevel@tonic-gate 2077*7c478bd9Sstevel@tonic-gate return (rval); 2078*7c478bd9Sstevel@tonic-gate } 2079*7c478bd9Sstevel@tonic-gate 2080*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2081*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_state & UGEN_EP_STATE_XS_OPEN); 2082*7c478bd9Sstevel@tonic-gate epp->ep_done = 0; 2083*7c478bd9Sstevel@tonic-gate epp->ep_bp = bp; 2084*7c478bd9Sstevel@tonic-gate 2085*7c478bd9Sstevel@tonic-gate switch (epp->ep_descr.bmAttributes & USB_EP_ATTR_MASK) { 2086*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 2087*7c478bd9Sstevel@tonic-gate rval = ugen_epx_ctrl_req(ugenp, epp, bp, &wait); 2088*7c478bd9Sstevel@tonic-gate 2089*7c478bd9Sstevel@tonic-gate break; 2090*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 2091*7c478bd9Sstevel@tonic-gate rval = ugen_epx_bulk_req(ugenp, epp, bp, &wait); 2092*7c478bd9Sstevel@tonic-gate 2093*7c478bd9Sstevel@tonic-gate break; 2094*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 2095*7c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 2096*7c478bd9Sstevel@tonic-gate rval = ugen_epx_intr_IN_req(ugenp, epp, bp, &wait); 2097*7c478bd9Sstevel@tonic-gate } else { 2098*7c478bd9Sstevel@tonic-gate rval = ugen_epx_intr_OUT_req(ugenp, epp, bp, &wait); 2099*7c478bd9Sstevel@tonic-gate } 2100*7c478bd9Sstevel@tonic-gate 2101*7c478bd9Sstevel@tonic-gate break; 2102*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 2103*7c478bd9Sstevel@tonic-gate default: 2104*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_INVALID_REQ; 2105*7c478bd9Sstevel@tonic-gate rval = USB_INVALID_REQUEST; 2106*7c478bd9Sstevel@tonic-gate } 2107*7c478bd9Sstevel@tonic-gate 2108*7c478bd9Sstevel@tonic-gate /* if the xfer could not immediately be completed, block here */ 2109*7c478bd9Sstevel@tonic-gate if ((rval == USB_SUCCESS) && wait) { 2110*7c478bd9Sstevel@tonic-gate while (!epp->ep_done) { 2111*7c478bd9Sstevel@tonic-gate if ((cv_wait_sig(&epp->ep_wait_cv, 2112*7c478bd9Sstevel@tonic-gate &epp->ep_mutex) <= 0) && !epp->ep_done) { 2113*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_XFER, 2114*7c478bd9Sstevel@tonic-gate ugenp->ug_log_hdl, 2115*7c478bd9Sstevel@tonic-gate "ugen_epx_req: interrupted ep=0x%" PRIx64, 2116*7c478bd9Sstevel@tonic-gate UGEN_MINOR_EPIDX(ugenp, dev)); 2117*7c478bd9Sstevel@tonic-gate 2118*7c478bd9Sstevel@tonic-gate /* 2119*7c478bd9Sstevel@tonic-gate * blow away the request except for dflt pipe 2120*7c478bd9Sstevel@tonic-gate * (this is prevented in USBA) 2121*7c478bd9Sstevel@tonic-gate */ 2122*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2123*7c478bd9Sstevel@tonic-gate usb_pipe_reset(ugenp->ug_dip, epp->ep_ph, 2124*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, NULL); 2125*7c478bd9Sstevel@tonic-gate (void) usb_pipe_drain_reqs(ugenp->ug_dip, 2126*7c478bd9Sstevel@tonic-gate epp->ep_ph, 0, 2127*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, NULL); 2128*7c478bd9Sstevel@tonic-gate 2129*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2130*7c478bd9Sstevel@tonic-gate 2131*7c478bd9Sstevel@tonic-gate if (geterror(bp) == 0) { 2132*7c478bd9Sstevel@tonic-gate bioerror(bp, EINTR); 2133*7c478bd9Sstevel@tonic-gate } 2134*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = 2135*7c478bd9Sstevel@tonic-gate USB_LC_STAT_INTERRUPTED; 2136*7c478bd9Sstevel@tonic-gate 2137*7c478bd9Sstevel@tonic-gate break; 2138*7c478bd9Sstevel@tonic-gate } 2139*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2140*7c478bd9Sstevel@tonic-gate "ugen_epx_req: wakeup"); 2141*7c478bd9Sstevel@tonic-gate } 2142*7c478bd9Sstevel@tonic-gate } 2143*7c478bd9Sstevel@tonic-gate 2144*7c478bd9Sstevel@tonic-gate /* always set lcmd_status if there was a failure */ 2145*7c478bd9Sstevel@tonic-gate if ((rval != USB_SUCCESS) && 2146*7c478bd9Sstevel@tonic-gate (epp->ep_lcmd_status == USB_LC_STAT_NOERROR)) { 2147*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_UNSPECIFIED_ERR; 2148*7c478bd9Sstevel@tonic-gate } 2149*7c478bd9Sstevel@tonic-gate 2150*7c478bd9Sstevel@tonic-gate epp->ep_done = 0; 2151*7c478bd9Sstevel@tonic-gate epp->ep_bp = NULL; 2152*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2153*7c478bd9Sstevel@tonic-gate 2154*7c478bd9Sstevel@tonic-gate usb_release_access(epp->ep_ser_cookie); 2155*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2156*7c478bd9Sstevel@tonic-gate "ugen_epx_req: done"); 2157*7c478bd9Sstevel@tonic-gate 2158*7c478bd9Sstevel@tonic-gate return (usb_rval2errno(rval)); 2159*7c478bd9Sstevel@tonic-gate } 2160*7c478bd9Sstevel@tonic-gate 2161*7c478bd9Sstevel@tonic-gate 2162*7c478bd9Sstevel@tonic-gate /* 2163*7c478bd9Sstevel@tonic-gate * handle control xfers 2164*7c478bd9Sstevel@tonic-gate */ 2165*7c478bd9Sstevel@tonic-gate static int 2166*7c478bd9Sstevel@tonic-gate ugen_epx_ctrl_req(ugen_state_t *ugenp, ugen_ep_t *epp, 2167*7c478bd9Sstevel@tonic-gate struct buf *bp, boolean_t *wait) 2168*7c478bd9Sstevel@tonic-gate { 2169*7c478bd9Sstevel@tonic-gate usb_ctrl_req_t *reqp = NULL; 2170*7c478bd9Sstevel@tonic-gate uchar_t *setup = ((uchar_t *)(bp->b_un.b_addr)); 2171*7c478bd9Sstevel@tonic-gate int rval; 2172*7c478bd9Sstevel@tonic-gate ushort_t wLength; 2173*7c478bd9Sstevel@tonic-gate 2174*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2175*7c478bd9Sstevel@tonic-gate "ugen_epx_ctrl_req: epp=0x%p state=0x%x bp=0x%p", 2176*7c478bd9Sstevel@tonic-gate epp, epp->ep_state, bp); 2177*7c478bd9Sstevel@tonic-gate 2178*7c478bd9Sstevel@tonic-gate /* is this a read following a write with setup data? */ 2179*7c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 2180*7c478bd9Sstevel@tonic-gate if (epp->ep_data) { 2181*7c478bd9Sstevel@tonic-gate int ep_len = epp->ep_data->b_wptr - 2182*7c478bd9Sstevel@tonic-gate epp->ep_data->b_rptr; 2183*7c478bd9Sstevel@tonic-gate int len = min(bp->b_bcount, ep_len); 2184*7c478bd9Sstevel@tonic-gate 2185*7c478bd9Sstevel@tonic-gate bcopy(epp->ep_data->b_rptr, bp->b_un.b_addr, len); 2186*7c478bd9Sstevel@tonic-gate epp->ep_data->b_rptr += len; 2187*7c478bd9Sstevel@tonic-gate if ((epp->ep_data->b_wptr - epp->ep_data->b_rptr) == 2188*7c478bd9Sstevel@tonic-gate 0) { 2189*7c478bd9Sstevel@tonic-gate freemsg(epp->ep_data); 2190*7c478bd9Sstevel@tonic-gate epp->ep_data = NULL; 2191*7c478bd9Sstevel@tonic-gate } 2192*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount - len; 2193*7c478bd9Sstevel@tonic-gate } else { 2194*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 2195*7c478bd9Sstevel@tonic-gate } 2196*7c478bd9Sstevel@tonic-gate 2197*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 2198*7c478bd9Sstevel@tonic-gate } 2199*7c478bd9Sstevel@tonic-gate 2200*7c478bd9Sstevel@tonic-gate /* discard old data if any */ 2201*7c478bd9Sstevel@tonic-gate if (epp->ep_data) { 2202*7c478bd9Sstevel@tonic-gate freemsg(epp->ep_data); 2203*7c478bd9Sstevel@tonic-gate epp->ep_data = NULL; 2204*7c478bd9Sstevel@tonic-gate } 2205*7c478bd9Sstevel@tonic-gate 2206*7c478bd9Sstevel@tonic-gate /* allocate and initialize request */ 2207*7c478bd9Sstevel@tonic-gate wLength = (setup[7] << 8) | setup[6]; 2208*7c478bd9Sstevel@tonic-gate reqp = usb_alloc_ctrl_req(ugenp->ug_dip, wLength, USB_FLAGS_NOSLEEP); 2209*7c478bd9Sstevel@tonic-gate if (reqp == NULL) { 2210*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_NO_RESOURCES; 2211*7c478bd9Sstevel@tonic-gate 2212*7c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 2213*7c478bd9Sstevel@tonic-gate } 2214*7c478bd9Sstevel@tonic-gate 2215*7c478bd9Sstevel@tonic-gate /* assume an LE data stream */ 2216*7c478bd9Sstevel@tonic-gate reqp->ctrl_bmRequestType = setup[0]; 2217*7c478bd9Sstevel@tonic-gate reqp->ctrl_bRequest = setup[1]; 2218*7c478bd9Sstevel@tonic-gate reqp->ctrl_wValue = (setup[3] << 8) | setup[2]; 2219*7c478bd9Sstevel@tonic-gate reqp->ctrl_wIndex = (setup[5] << 8) | setup[4]; 2220*7c478bd9Sstevel@tonic-gate reqp->ctrl_wLength = wLength; 2221*7c478bd9Sstevel@tonic-gate reqp->ctrl_timeout = ugen_ctrl_timeout; 2222*7c478bd9Sstevel@tonic-gate reqp->ctrl_attributes = USB_ATTRS_AUTOCLEARING | 2223*7c478bd9Sstevel@tonic-gate USB_ATTRS_SHORT_XFER_OK; 2224*7c478bd9Sstevel@tonic-gate reqp->ctrl_cb = ugen_epx_ctrl_req_cb; 2225*7c478bd9Sstevel@tonic-gate reqp->ctrl_exc_cb = ugen_epx_ctrl_req_cb; 2226*7c478bd9Sstevel@tonic-gate reqp->ctrl_client_private = (usb_opaque_t)ugenp; 2227*7c478bd9Sstevel@tonic-gate 2228*7c478bd9Sstevel@tonic-gate /* 2229*7c478bd9Sstevel@tonic-gate * is this a legal request? No accesses to device are 2230*7c478bd9Sstevel@tonic-gate * allowed if we don't own the device 2231*7c478bd9Sstevel@tonic-gate */ 2232*7c478bd9Sstevel@tonic-gate if (((reqp->ctrl_bmRequestType & USB_DEV_REQ_RCPT_MASK) == 2233*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_RCPT_DEV) && 2234*7c478bd9Sstevel@tonic-gate (((reqp->ctrl_bmRequestType & USB_DEV_REQ_DIR_MASK) == 2235*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_HOST_TO_DEV) && 2236*7c478bd9Sstevel@tonic-gate (usb_owns_device(ugenp->ug_dip) == B_FALSE))) { 2237*7c478bd9Sstevel@tonic-gate rval = USB_INVALID_PERM; 2238*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_INVALID_REQ; 2239*7c478bd9Sstevel@tonic-gate 2240*7c478bd9Sstevel@tonic-gate goto fail; 2241*7c478bd9Sstevel@tonic-gate } 2242*7c478bd9Sstevel@tonic-gate 2243*7c478bd9Sstevel@tonic-gate /* filter out set_cfg and set_if standard requests */ 2244*7c478bd9Sstevel@tonic-gate if ((reqp->ctrl_bmRequestType & USB_DEV_REQ_TYPE_MASK) == 2245*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_TYPE_STANDARD) { 2246*7c478bd9Sstevel@tonic-gate switch (reqp->ctrl_bRequest) { 2247*7c478bd9Sstevel@tonic-gate case USB_REQ_SET_CFG: 2248*7c478bd9Sstevel@tonic-gate case USB_REQ_SET_IF: 2249*7c478bd9Sstevel@tonic-gate rval = USB_INVALID_REQUEST; 2250*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_INVALID_REQ; 2251*7c478bd9Sstevel@tonic-gate 2252*7c478bd9Sstevel@tonic-gate goto fail; 2253*7c478bd9Sstevel@tonic-gate default: 2254*7c478bd9Sstevel@tonic-gate 2255*7c478bd9Sstevel@tonic-gate break; 2256*7c478bd9Sstevel@tonic-gate } 2257*7c478bd9Sstevel@tonic-gate } 2258*7c478bd9Sstevel@tonic-gate 2259*7c478bd9Sstevel@tonic-gate /* is this from host to device? */ 2260*7c478bd9Sstevel@tonic-gate if (((reqp->ctrl_bmRequestType & USB_DEV_REQ_DIR_MASK) == 2261*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_HOST_TO_DEV) && reqp->ctrl_wLength) { 2262*7c478bd9Sstevel@tonic-gate if (((bp->b_bcount - UGEN_SETUP_PKT_SIZE) - wLength) != 0) { 2263*7c478bd9Sstevel@tonic-gate rval = USB_INVALID_REQUEST; 2264*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_INVALID_REQ; 2265*7c478bd9Sstevel@tonic-gate 2266*7c478bd9Sstevel@tonic-gate goto fail; 2267*7c478bd9Sstevel@tonic-gate } 2268*7c478bd9Sstevel@tonic-gate bcopy(bp->b_un.b_addr + UGEN_SETUP_PKT_SIZE, 2269*7c478bd9Sstevel@tonic-gate reqp->ctrl_data->b_wptr, wLength); 2270*7c478bd9Sstevel@tonic-gate reqp->ctrl_data->b_wptr += wLength; 2271*7c478bd9Sstevel@tonic-gate } else if ((reqp->ctrl_bmRequestType & USB_DEV_REQ_DIR_MASK) == 2272*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST) { 2273*7c478bd9Sstevel@tonic-gate if (bp->b_bcount != UGEN_SETUP_PKT_SIZE) { 2274*7c478bd9Sstevel@tonic-gate rval = USB_INVALID_REQUEST; 2275*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_INVALID_REQ; 2276*7c478bd9Sstevel@tonic-gate 2277*7c478bd9Sstevel@tonic-gate goto fail; 2278*7c478bd9Sstevel@tonic-gate } 2279*7c478bd9Sstevel@tonic-gate } 2280*7c478bd9Sstevel@tonic-gate 2281*7c478bd9Sstevel@tonic-gate /* submit the request */ 2282*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2283*7c478bd9Sstevel@tonic-gate rval = usb_pipe_ctrl_xfer(epp->ep_ph, reqp, USB_FLAGS_NOSLEEP); 2284*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2285*7c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 2286*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = 2287*7c478bd9Sstevel@tonic-gate ugen_cr2lcstat(reqp->ctrl_completion_reason); 2288*7c478bd9Sstevel@tonic-gate 2289*7c478bd9Sstevel@tonic-gate goto fail; 2290*7c478bd9Sstevel@tonic-gate } 2291*7c478bd9Sstevel@tonic-gate done: 2292*7c478bd9Sstevel@tonic-gate *wait = B_TRUE; 2293*7c478bd9Sstevel@tonic-gate 2294*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 2295*7c478bd9Sstevel@tonic-gate fail: 2296*7c478bd9Sstevel@tonic-gate *wait = B_FALSE; 2297*7c478bd9Sstevel@tonic-gate 2298*7c478bd9Sstevel@tonic-gate usb_free_ctrl_req(reqp); 2299*7c478bd9Sstevel@tonic-gate 2300*7c478bd9Sstevel@tonic-gate return (rval); 2301*7c478bd9Sstevel@tonic-gate } 2302*7c478bd9Sstevel@tonic-gate 2303*7c478bd9Sstevel@tonic-gate 2304*7c478bd9Sstevel@tonic-gate /* 2305*7c478bd9Sstevel@tonic-gate * callback for control requests, normal and exception completion 2306*7c478bd9Sstevel@tonic-gate */ 2307*7c478bd9Sstevel@tonic-gate static void 2308*7c478bd9Sstevel@tonic-gate ugen_epx_ctrl_req_cb(usb_pipe_handle_t ph, usb_ctrl_req_t *reqp) 2309*7c478bd9Sstevel@tonic-gate { 2310*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp = (ugen_state_t *)reqp->ctrl_client_private; 2311*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = (ugen_ep_t *)usb_pipe_get_private(ph); 2312*7c478bd9Sstevel@tonic-gate 2313*7c478bd9Sstevel@tonic-gate if (epp == NULL) { 2314*7c478bd9Sstevel@tonic-gate epp = &ugenp->ug_ep[0]; 2315*7c478bd9Sstevel@tonic-gate } 2316*7c478bd9Sstevel@tonic-gate 2317*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2318*7c478bd9Sstevel@tonic-gate 2319*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2320*7c478bd9Sstevel@tonic-gate "ugen_epx_ctrl_req_cb:\n\t" 2321*7c478bd9Sstevel@tonic-gate "epp=0x%p state=0x%x ph=0x%p reqp=0x%p cr=%d cb=0x%x", 2322*7c478bd9Sstevel@tonic-gate epp, epp->ep_state, ph, reqp, reqp->ctrl_completion_reason, 2323*7c478bd9Sstevel@tonic-gate reqp->ctrl_cb_flags); 2324*7c478bd9Sstevel@tonic-gate 2325*7c478bd9Sstevel@tonic-gate ASSERT((reqp->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0); 2326*7c478bd9Sstevel@tonic-gate 2327*7c478bd9Sstevel@tonic-gate /* save any data for the next read */ 2328*7c478bd9Sstevel@tonic-gate switch (reqp->ctrl_completion_reason) { 2329*7c478bd9Sstevel@tonic-gate case USB_CR_OK: 2330*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 2331*7c478bd9Sstevel@tonic-gate 2332*7c478bd9Sstevel@tonic-gate break; 2333*7c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET: 2334*7c478bd9Sstevel@tonic-gate 2335*7c478bd9Sstevel@tonic-gate break; 2336*7c478bd9Sstevel@tonic-gate default: 2337*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = 2338*7c478bd9Sstevel@tonic-gate ugen_cr2lcstat(reqp->ctrl_completion_reason); 2339*7c478bd9Sstevel@tonic-gate if (epp->ep_bp) { 2340*7c478bd9Sstevel@tonic-gate bioerror(epp->ep_bp, EIO); 2341*7c478bd9Sstevel@tonic-gate } 2342*7c478bd9Sstevel@tonic-gate 2343*7c478bd9Sstevel@tonic-gate break; 2344*7c478bd9Sstevel@tonic-gate } 2345*7c478bd9Sstevel@tonic-gate 2346*7c478bd9Sstevel@tonic-gate if (reqp->ctrl_data) { 2347*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_data == NULL); 2348*7c478bd9Sstevel@tonic-gate epp->ep_data = reqp->ctrl_data; 2349*7c478bd9Sstevel@tonic-gate reqp->ctrl_data = NULL; 2350*7c478bd9Sstevel@tonic-gate } 2351*7c478bd9Sstevel@tonic-gate epp->ep_done++; 2352*7c478bd9Sstevel@tonic-gate cv_signal(&epp->ep_wait_cv); 2353*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2354*7c478bd9Sstevel@tonic-gate 2355*7c478bd9Sstevel@tonic-gate usb_free_ctrl_req(reqp); 2356*7c478bd9Sstevel@tonic-gate 2357*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2358*7c478bd9Sstevel@tonic-gate "ugen_epx_ctrl_req_cb: done"); 2359*7c478bd9Sstevel@tonic-gate } 2360*7c478bd9Sstevel@tonic-gate 2361*7c478bd9Sstevel@tonic-gate 2362*7c478bd9Sstevel@tonic-gate /* 2363*7c478bd9Sstevel@tonic-gate * handle bulk xfers 2364*7c478bd9Sstevel@tonic-gate */ 2365*7c478bd9Sstevel@tonic-gate static int 2366*7c478bd9Sstevel@tonic-gate ugen_epx_bulk_req(ugen_state_t *ugenp, ugen_ep_t *epp, 2367*7c478bd9Sstevel@tonic-gate struct buf *bp, boolean_t *wait) 2368*7c478bd9Sstevel@tonic-gate { 2369*7c478bd9Sstevel@tonic-gate int rval; 2370*7c478bd9Sstevel@tonic-gate usb_bulk_req_t *reqp = usb_alloc_bulk_req(ugenp->ug_dip, 2371*7c478bd9Sstevel@tonic-gate bp->b_bcount, USB_FLAGS_NOSLEEP); 2372*7c478bd9Sstevel@tonic-gate 2373*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2374*7c478bd9Sstevel@tonic-gate "ugen_epx_bulk_req: epp=0x%p state=0x%x bp=0x%p", 2375*7c478bd9Sstevel@tonic-gate epp, epp->ep_state, bp); 2376*7c478bd9Sstevel@tonic-gate 2377*7c478bd9Sstevel@tonic-gate if (reqp == NULL) { 2378*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_NO_RESOURCES; 2379*7c478bd9Sstevel@tonic-gate 2380*7c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 2381*7c478bd9Sstevel@tonic-gate } 2382*7c478bd9Sstevel@tonic-gate 2383*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_state & UGEN_EP_STATE_XS_OPEN); 2384*7c478bd9Sstevel@tonic-gate 2385*7c478bd9Sstevel@tonic-gate /* 2386*7c478bd9Sstevel@tonic-gate * the transfer count is limited in minphys with what the HCD can 2387*7c478bd9Sstevel@tonic-gate * do 2388*7c478bd9Sstevel@tonic-gate */ 2389*7c478bd9Sstevel@tonic-gate reqp->bulk_len = bp->b_bcount; 2390*7c478bd9Sstevel@tonic-gate reqp->bulk_timeout = ugen_bulk_timeout; 2391*7c478bd9Sstevel@tonic-gate reqp->bulk_client_private = (usb_opaque_t)ugenp; 2392*7c478bd9Sstevel@tonic-gate reqp->bulk_attributes = USB_ATTRS_AUTOCLEARING; 2393*7c478bd9Sstevel@tonic-gate reqp->bulk_cb = ugen_epx_bulk_req_cb; 2394*7c478bd9Sstevel@tonic-gate reqp->bulk_exc_cb = ugen_epx_bulk_req_cb; 2395*7c478bd9Sstevel@tonic-gate 2396*7c478bd9Sstevel@tonic-gate /* copy data into bp for OUT pipes */ 2397*7c478bd9Sstevel@tonic-gate if ((UGEN_XFER_DIR(epp) & USB_EP_DIR_IN) == 0) { 2398*7c478bd9Sstevel@tonic-gate bcopy(epp->ep_bp->b_un.b_addr, reqp->bulk_data->b_rptr, 2399*7c478bd9Sstevel@tonic-gate bp->b_bcount); 2400*7c478bd9Sstevel@tonic-gate reqp->bulk_data->b_wptr += bp->b_bcount; 2401*7c478bd9Sstevel@tonic-gate } else { 2402*7c478bd9Sstevel@tonic-gate reqp->bulk_attributes |= USB_ATTRS_SHORT_XFER_OK; 2403*7c478bd9Sstevel@tonic-gate } 2404*7c478bd9Sstevel@tonic-gate 2405*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2406*7c478bd9Sstevel@tonic-gate if ((rval = usb_pipe_bulk_xfer(epp->ep_ph, reqp, 2407*7c478bd9Sstevel@tonic-gate USB_FLAGS_NOSLEEP)) != USB_SUCCESS) { 2408*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2409*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = 2410*7c478bd9Sstevel@tonic-gate ugen_cr2lcstat(reqp->bulk_completion_reason); 2411*7c478bd9Sstevel@tonic-gate usb_free_bulk_req(reqp); 2412*7c478bd9Sstevel@tonic-gate bioerror(bp, EIO); 2413*7c478bd9Sstevel@tonic-gate } else { 2414*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2415*7c478bd9Sstevel@tonic-gate } 2416*7c478bd9Sstevel@tonic-gate *wait = (rval == USB_SUCCESS) ? B_TRUE : B_FALSE; 2417*7c478bd9Sstevel@tonic-gate 2418*7c478bd9Sstevel@tonic-gate return (rval); 2419*7c478bd9Sstevel@tonic-gate } 2420*7c478bd9Sstevel@tonic-gate 2421*7c478bd9Sstevel@tonic-gate 2422*7c478bd9Sstevel@tonic-gate /* 2423*7c478bd9Sstevel@tonic-gate * normal and exception bulk request callback 2424*7c478bd9Sstevel@tonic-gate */ 2425*7c478bd9Sstevel@tonic-gate static void 2426*7c478bd9Sstevel@tonic-gate ugen_epx_bulk_req_cb(usb_pipe_handle_t ph, usb_bulk_req_t *reqp) 2427*7c478bd9Sstevel@tonic-gate { 2428*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp = (ugen_state_t *)reqp->bulk_client_private; 2429*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = (ugen_ep_t *)usb_pipe_get_private(ph); 2430*7c478bd9Sstevel@tonic-gate 2431*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2432*7c478bd9Sstevel@tonic-gate "ugen_epx_bulk_req_cb: ph=0x%p reqp=0x%p cr=%d cb=0x%x", 2433*7c478bd9Sstevel@tonic-gate ph, reqp, reqp->bulk_completion_reason, reqp->bulk_cb_flags); 2434*7c478bd9Sstevel@tonic-gate 2435*7c478bd9Sstevel@tonic-gate ASSERT((reqp->bulk_cb_flags & USB_CB_INTR_CONTEXT) == 0); 2436*7c478bd9Sstevel@tonic-gate 2437*7c478bd9Sstevel@tonic-gate /* epp might be NULL if we are closing the pipe */ 2438*7c478bd9Sstevel@tonic-gate if (epp) { 2439*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2440*7c478bd9Sstevel@tonic-gate if (epp->ep_bp && reqp->bulk_data) { 2441*7c478bd9Sstevel@tonic-gate int len = min(reqp->bulk_data->b_wptr - 2442*7c478bd9Sstevel@tonic-gate reqp->bulk_data->b_rptr, 2443*7c478bd9Sstevel@tonic-gate epp->ep_bp->b_bcount); 2444*7c478bd9Sstevel@tonic-gate if (UGEN_XFER_DIR(epp) & USB_EP_DIR_IN) { 2445*7c478bd9Sstevel@tonic-gate if (len) { 2446*7c478bd9Sstevel@tonic-gate bcopy(reqp->bulk_data->b_rptr, 2447*7c478bd9Sstevel@tonic-gate epp->ep_bp->b_un.b_addr, len); 2448*7c478bd9Sstevel@tonic-gate epp->ep_bp->b_resid = 2449*7c478bd9Sstevel@tonic-gate epp->ep_bp->b_bcount - len; 2450*7c478bd9Sstevel@tonic-gate } 2451*7c478bd9Sstevel@tonic-gate } else { 2452*7c478bd9Sstevel@tonic-gate epp->ep_bp->b_resid = 2453*7c478bd9Sstevel@tonic-gate epp->ep_bp->b_bcount - len; 2454*7c478bd9Sstevel@tonic-gate } 2455*7c478bd9Sstevel@tonic-gate } 2456*7c478bd9Sstevel@tonic-gate switch (reqp->bulk_completion_reason) { 2457*7c478bd9Sstevel@tonic-gate case USB_CR_OK: 2458*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 2459*7c478bd9Sstevel@tonic-gate 2460*7c478bd9Sstevel@tonic-gate break; 2461*7c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET: 2462*7c478bd9Sstevel@tonic-gate 2463*7c478bd9Sstevel@tonic-gate break; 2464*7c478bd9Sstevel@tonic-gate default: 2465*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = 2466*7c478bd9Sstevel@tonic-gate ugen_cr2lcstat(reqp->bulk_completion_reason); 2467*7c478bd9Sstevel@tonic-gate if (epp->ep_bp) { 2468*7c478bd9Sstevel@tonic-gate bioerror(epp->ep_bp, EIO); 2469*7c478bd9Sstevel@tonic-gate } 2470*7c478bd9Sstevel@tonic-gate } 2471*7c478bd9Sstevel@tonic-gate epp->ep_done++; 2472*7c478bd9Sstevel@tonic-gate cv_signal(&epp->ep_wait_cv); 2473*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2474*7c478bd9Sstevel@tonic-gate } 2475*7c478bd9Sstevel@tonic-gate 2476*7c478bd9Sstevel@tonic-gate usb_free_bulk_req(reqp); 2477*7c478bd9Sstevel@tonic-gate } 2478*7c478bd9Sstevel@tonic-gate 2479*7c478bd9Sstevel@tonic-gate 2480*7c478bd9Sstevel@tonic-gate /* 2481*7c478bd9Sstevel@tonic-gate * handle intr IN xfers 2482*7c478bd9Sstevel@tonic-gate */ 2483*7c478bd9Sstevel@tonic-gate static int 2484*7c478bd9Sstevel@tonic-gate ugen_epx_intr_IN_req(ugen_state_t *ugenp, ugen_ep_t *epp, 2485*7c478bd9Sstevel@tonic-gate struct buf *bp, boolean_t *wait) 2486*7c478bd9Sstevel@tonic-gate { 2487*7c478bd9Sstevel@tonic-gate int len = 0; 2488*7c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 2489*7c478bd9Sstevel@tonic-gate 2490*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2491*7c478bd9Sstevel@tonic-gate "ugen_epx_intr_IN_req: epp=0x%p state=0x%x bp=0x%p", 2492*7c478bd9Sstevel@tonic-gate epp, epp->ep_state, bp); 2493*7c478bd9Sstevel@tonic-gate 2494*7c478bd9Sstevel@tonic-gate *wait = B_FALSE; 2495*7c478bd9Sstevel@tonic-gate 2496*7c478bd9Sstevel@tonic-gate /* can we satisfy this read? */ 2497*7c478bd9Sstevel@tonic-gate if (epp->ep_data) { 2498*7c478bd9Sstevel@tonic-gate len = min(epp->ep_data->b_wptr - epp->ep_data->b_rptr, 2499*7c478bd9Sstevel@tonic-gate bp->b_bcount); 2500*7c478bd9Sstevel@tonic-gate } 2501*7c478bd9Sstevel@tonic-gate 2502*7c478bd9Sstevel@tonic-gate /* 2503*7c478bd9Sstevel@tonic-gate * if polling not active, restart, and return failure 2504*7c478bd9Sstevel@tonic-gate * immediately unless one xfer mode has been requested 2505*7c478bd9Sstevel@tonic-gate * if there is some data, return a short read 2506*7c478bd9Sstevel@tonic-gate */ 2507*7c478bd9Sstevel@tonic-gate if ((epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_ON) == 0) { 2508*7c478bd9Sstevel@tonic-gate if (len == 0) { 2509*7c478bd9Sstevel@tonic-gate if (!epp->ep_one_xfer) { 2510*7c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 2511*7c478bd9Sstevel@tonic-gate if (epp->ep_lcmd_status == 2512*7c478bd9Sstevel@tonic-gate USB_LC_STAT_NOERROR) { 2513*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = 2514*7c478bd9Sstevel@tonic-gate USB_LC_STAT_INTR_BUF_FULL; 2515*7c478bd9Sstevel@tonic-gate } 2516*7c478bd9Sstevel@tonic-gate } 2517*7c478bd9Sstevel@tonic-gate if (ugen_epx_intr_IN_start_polling(ugenp, 2518*7c478bd9Sstevel@tonic-gate epp) != USB_SUCCESS) { 2519*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = 2520*7c478bd9Sstevel@tonic-gate USB_LC_STAT_INTR_POLLING_FAILED; 2521*7c478bd9Sstevel@tonic-gate } 2522*7c478bd9Sstevel@tonic-gate if (epp->ep_one_xfer) { 2523*7c478bd9Sstevel@tonic-gate *wait = B_TRUE; 2524*7c478bd9Sstevel@tonic-gate } 2525*7c478bd9Sstevel@tonic-gate goto done; 2526*7c478bd9Sstevel@tonic-gate } else if (epp->ep_data && (len < bp->b_bcount)) { 2527*7c478bd9Sstevel@tonic-gate bcopy(epp->ep_data->b_rptr, bp->b_un.b_addr, len); 2528*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount - len; 2529*7c478bd9Sstevel@tonic-gate epp->ep_data->b_rptr += len; 2530*7c478bd9Sstevel@tonic-gate 2531*7c478bd9Sstevel@tonic-gate goto done; 2532*7c478bd9Sstevel@tonic-gate } 2533*7c478bd9Sstevel@tonic-gate } 2534*7c478bd9Sstevel@tonic-gate 2535*7c478bd9Sstevel@tonic-gate /* 2536*7c478bd9Sstevel@tonic-gate * if there is data or FNDELAY, return available data 2537*7c478bd9Sstevel@tonic-gate */ 2538*7c478bd9Sstevel@tonic-gate if ((len >= bp->b_bcount) || 2539*7c478bd9Sstevel@tonic-gate (epp->ep_xfer_oflag & (FNDELAY | FNONBLOCK))) { 2540*7c478bd9Sstevel@tonic-gate if (epp->ep_data) { 2541*7c478bd9Sstevel@tonic-gate bcopy(epp->ep_data->b_rptr, bp->b_un.b_addr, len); 2542*7c478bd9Sstevel@tonic-gate epp->ep_data->b_rptr += len; 2543*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount - len; 2544*7c478bd9Sstevel@tonic-gate } else { 2545*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 2546*7c478bd9Sstevel@tonic-gate } 2547*7c478bd9Sstevel@tonic-gate } else { 2548*7c478bd9Sstevel@tonic-gate /* otherwise just wait for data */ 2549*7c478bd9Sstevel@tonic-gate *wait = B_TRUE; 2550*7c478bd9Sstevel@tonic-gate } 2551*7c478bd9Sstevel@tonic-gate 2552*7c478bd9Sstevel@tonic-gate done: 2553*7c478bd9Sstevel@tonic-gate if (epp->ep_data && (epp->ep_data->b_rptr == epp->ep_data->b_wptr)) { 2554*7c478bd9Sstevel@tonic-gate freemsg(epp->ep_data); 2555*7c478bd9Sstevel@tonic-gate epp->ep_data = NULL; 2556*7c478bd9Sstevel@tonic-gate } 2557*7c478bd9Sstevel@tonic-gate 2558*7c478bd9Sstevel@tonic-gate if (*wait) { 2559*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_ON); 2560*7c478bd9Sstevel@tonic-gate } 2561*7c478bd9Sstevel@tonic-gate 2562*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2563*7c478bd9Sstevel@tonic-gate "ugen_epx_intr_IN_req end: rval=%d bcount=%lu len=%d data=0x%p", 2564*7c478bd9Sstevel@tonic-gate rval, bp->b_bcount, len, epp->ep_data); 2565*7c478bd9Sstevel@tonic-gate 2566*7c478bd9Sstevel@tonic-gate return (rval); 2567*7c478bd9Sstevel@tonic-gate } 2568*7c478bd9Sstevel@tonic-gate 2569*7c478bd9Sstevel@tonic-gate 2570*7c478bd9Sstevel@tonic-gate /* 2571*7c478bd9Sstevel@tonic-gate * Start polling on interrupt endpoint, synchronously 2572*7c478bd9Sstevel@tonic-gate */ 2573*7c478bd9Sstevel@tonic-gate static int 2574*7c478bd9Sstevel@tonic-gate ugen_epx_intr_IN_start_polling(ugen_state_t *ugenp, ugen_ep_t *epp) 2575*7c478bd9Sstevel@tonic-gate { 2576*7c478bd9Sstevel@tonic-gate int rval = USB_FAILURE; 2577*7c478bd9Sstevel@tonic-gate usb_intr_req_t *reqp; 2578*7c478bd9Sstevel@tonic-gate usb_flags_t uflag; 2579*7c478bd9Sstevel@tonic-gate 2580*7c478bd9Sstevel@tonic-gate /* 2581*7c478bd9Sstevel@tonic-gate * if polling is being stopped, we restart polling in the 2582*7c478bd9Sstevel@tonic-gate * interrrupt callback again 2583*7c478bd9Sstevel@tonic-gate */ 2584*7c478bd9Sstevel@tonic-gate if (epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED) { 2585*7c478bd9Sstevel@tonic-gate 2586*7c478bd9Sstevel@tonic-gate return (rval); 2587*7c478bd9Sstevel@tonic-gate } 2588*7c478bd9Sstevel@tonic-gate if ((epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_ON) == 0) { 2589*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2590*7c478bd9Sstevel@tonic-gate "ugen_epx_intr_IN_start_polling: epp=0x%p state=0x%x", 2591*7c478bd9Sstevel@tonic-gate epp, epp->ep_state); 2592*7c478bd9Sstevel@tonic-gate 2593*7c478bd9Sstevel@tonic-gate epp->ep_state |= UGEN_EP_STATE_INTR_IN_POLLING_ON; 2594*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2595*7c478bd9Sstevel@tonic-gate 2596*7c478bd9Sstevel@tonic-gate reqp = usb_alloc_intr_req(ugenp->ug_dip, 0, 2597*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP); 2598*7c478bd9Sstevel@tonic-gate reqp->intr_client_private = (usb_opaque_t)ugenp; 2599*7c478bd9Sstevel@tonic-gate 2600*7c478bd9Sstevel@tonic-gate reqp->intr_attributes = USB_ATTRS_AUTOCLEARING | 2601*7c478bd9Sstevel@tonic-gate USB_ATTRS_SHORT_XFER_OK; 2602*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2603*7c478bd9Sstevel@tonic-gate if (epp->ep_one_xfer) { 2604*7c478bd9Sstevel@tonic-gate reqp->intr_attributes |= USB_ATTRS_ONE_XFER; 2605*7c478bd9Sstevel@tonic-gate uflag = USB_FLAGS_NOSLEEP; 2606*7c478bd9Sstevel@tonic-gate } else { 2607*7c478bd9Sstevel@tonic-gate uflag = USB_FLAGS_SLEEP; 2608*7c478bd9Sstevel@tonic-gate } 2609*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2610*7c478bd9Sstevel@tonic-gate 2611*7c478bd9Sstevel@tonic-gate reqp->intr_len = epp->ep_descr.wMaxPacketSize; 2612*7c478bd9Sstevel@tonic-gate reqp->intr_cb = ugen_epx_intr_IN_req_cb; 2613*7c478bd9Sstevel@tonic-gate reqp->intr_exc_cb = ugen_epx_intr_IN_req_cb; 2614*7c478bd9Sstevel@tonic-gate 2615*7c478bd9Sstevel@tonic-gate 2616*7c478bd9Sstevel@tonic-gate if ((rval = usb_pipe_intr_xfer(epp->ep_ph, reqp, 2617*7c478bd9Sstevel@tonic-gate uflag)) != USB_SUCCESS) { 2618*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2619*7c478bd9Sstevel@tonic-gate "ugen_epx_intr_IN_start_polling: failed %d", rval); 2620*7c478bd9Sstevel@tonic-gate usb_free_intr_req(reqp); 2621*7c478bd9Sstevel@tonic-gate } 2622*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2623*7c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 2624*7c478bd9Sstevel@tonic-gate epp->ep_state &= ~UGEN_EP_STATE_INTR_IN_POLLING_ON; 2625*7c478bd9Sstevel@tonic-gate } 2626*7c478bd9Sstevel@tonic-gate } else { 2627*7c478bd9Sstevel@tonic-gate rval = USB_SUCCESS; 2628*7c478bd9Sstevel@tonic-gate } 2629*7c478bd9Sstevel@tonic-gate 2630*7c478bd9Sstevel@tonic-gate return (rval); 2631*7c478bd9Sstevel@tonic-gate } 2632*7c478bd9Sstevel@tonic-gate 2633*7c478bd9Sstevel@tonic-gate 2634*7c478bd9Sstevel@tonic-gate /* 2635*7c478bd9Sstevel@tonic-gate * stop polling on an interrupt endpoint, asynchronously 2636*7c478bd9Sstevel@tonic-gate */ 2637*7c478bd9Sstevel@tonic-gate static void 2638*7c478bd9Sstevel@tonic-gate ugen_epx_intr_IN_stop_polling(ugen_state_t *ugenp, ugen_ep_t *epp) 2639*7c478bd9Sstevel@tonic-gate { 2640*7c478bd9Sstevel@tonic-gate if ((epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_ON) && 2641*7c478bd9Sstevel@tonic-gate ((epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED) == 0)) { 2642*7c478bd9Sstevel@tonic-gate 2643*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2644*7c478bd9Sstevel@tonic-gate "ugen_epx_intr_IN_stop_polling: epp=0x%p state=0x%x", 2645*7c478bd9Sstevel@tonic-gate epp, epp->ep_state); 2646*7c478bd9Sstevel@tonic-gate 2647*7c478bd9Sstevel@tonic-gate epp->ep_state |= UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED; 2648*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2649*7c478bd9Sstevel@tonic-gate usb_pipe_stop_intr_polling(epp->ep_ph, USB_FLAGS_NOSLEEP); 2650*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2651*7c478bd9Sstevel@tonic-gate } 2652*7c478bd9Sstevel@tonic-gate } 2653*7c478bd9Sstevel@tonic-gate 2654*7c478bd9Sstevel@tonic-gate 2655*7c478bd9Sstevel@tonic-gate /* 2656*7c478bd9Sstevel@tonic-gate * poll management 2657*7c478bd9Sstevel@tonic-gate */ 2658*7c478bd9Sstevel@tonic-gate static void 2659*7c478bd9Sstevel@tonic-gate ugen_epx_intr_IN_poll_wakeup(ugen_state_t *ugenp, ugen_ep_t *epp) 2660*7c478bd9Sstevel@tonic-gate { 2661*7c478bd9Sstevel@tonic-gate if (epp->ep_state & UGEN_EP_STATE_INTR_IN_POLL_PENDING) { 2662*7c478bd9Sstevel@tonic-gate struct pollhead *phpp = &epp->ep_pollhead; 2663*7c478bd9Sstevel@tonic-gate 2664*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2665*7c478bd9Sstevel@tonic-gate "ugen_epx_intr_IN_poll_wakeup: state=0x%x", epp->ep_state); 2666*7c478bd9Sstevel@tonic-gate 2667*7c478bd9Sstevel@tonic-gate epp->ep_state &= ~UGEN_EP_STATE_INTR_IN_POLL_PENDING; 2668*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2669*7c478bd9Sstevel@tonic-gate pollwakeup(phpp, POLLIN); 2670*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2671*7c478bd9Sstevel@tonic-gate } 2672*7c478bd9Sstevel@tonic-gate } 2673*7c478bd9Sstevel@tonic-gate 2674*7c478bd9Sstevel@tonic-gate 2675*7c478bd9Sstevel@tonic-gate /* 2676*7c478bd9Sstevel@tonic-gate * callback functions for interrupt IN pipe 2677*7c478bd9Sstevel@tonic-gate */ 2678*7c478bd9Sstevel@tonic-gate static void 2679*7c478bd9Sstevel@tonic-gate ugen_epx_intr_IN_req_cb(usb_pipe_handle_t ph, usb_intr_req_t *reqp) 2680*7c478bd9Sstevel@tonic-gate { 2681*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp = (ugen_state_t *)reqp->intr_client_private; 2682*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = (ugen_ep_t *)usb_pipe_get_private(ph); 2683*7c478bd9Sstevel@tonic-gate 2684*7c478bd9Sstevel@tonic-gate if (epp == NULL) { 2685*7c478bd9Sstevel@tonic-gate /* pipe is closing */ 2686*7c478bd9Sstevel@tonic-gate 2687*7c478bd9Sstevel@tonic-gate goto done; 2688*7c478bd9Sstevel@tonic-gate } 2689*7c478bd9Sstevel@tonic-gate 2690*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2691*7c478bd9Sstevel@tonic-gate 2692*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2693*7c478bd9Sstevel@tonic-gate "ugen_epx_intr_IN_req_cb:\n\t" 2694*7c478bd9Sstevel@tonic-gate "epp=0x%p state=0x%x ph=0x%p reqp=0x%p cr=%d cb=0x%x len=%d", 2695*7c478bd9Sstevel@tonic-gate epp, epp->ep_state, ph, reqp, reqp->intr_completion_reason, 2696*7c478bd9Sstevel@tonic-gate reqp->intr_cb_flags, 2697*7c478bd9Sstevel@tonic-gate (reqp->intr_data == NULL) ? 0 : 2698*7c478bd9Sstevel@tonic-gate reqp->intr_data->b_wptr - reqp->intr_data->b_rptr); 2699*7c478bd9Sstevel@tonic-gate 2700*7c478bd9Sstevel@tonic-gate ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 2701*7c478bd9Sstevel@tonic-gate 2702*7c478bd9Sstevel@tonic-gate if (epp->ep_data && reqp->intr_data) { 2703*7c478bd9Sstevel@tonic-gate mblk_t *mp; 2704*7c478bd9Sstevel@tonic-gate 2705*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2706*7c478bd9Sstevel@tonic-gate "ep%x coalesce data", epp->ep_descr.bEndpointAddress); 2707*7c478bd9Sstevel@tonic-gate 2708*7c478bd9Sstevel@tonic-gate /* coalesce the data into one mblk */ 2709*7c478bd9Sstevel@tonic-gate epp->ep_data->b_cont = reqp->intr_data; 2710*7c478bd9Sstevel@tonic-gate if ((mp = msgpullup(epp->ep_data, -1)) != NULL) { 2711*7c478bd9Sstevel@tonic-gate reqp->intr_data = NULL; 2712*7c478bd9Sstevel@tonic-gate freemsg(epp->ep_data); 2713*7c478bd9Sstevel@tonic-gate epp->ep_data = mp; 2714*7c478bd9Sstevel@tonic-gate } else { 2715*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2716*7c478bd9Sstevel@tonic-gate "msgpullup failed, discard data"); 2717*7c478bd9Sstevel@tonic-gate epp->ep_data->b_cont = NULL; 2718*7c478bd9Sstevel@tonic-gate } 2719*7c478bd9Sstevel@tonic-gate } else if (reqp->intr_data) { 2720*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2721*7c478bd9Sstevel@tonic-gate "setting ep_data"); 2722*7c478bd9Sstevel@tonic-gate 2723*7c478bd9Sstevel@tonic-gate epp->ep_data = reqp->intr_data; 2724*7c478bd9Sstevel@tonic-gate reqp->intr_data = NULL; 2725*7c478bd9Sstevel@tonic-gate } 2726*7c478bd9Sstevel@tonic-gate 2727*7c478bd9Sstevel@tonic-gate switch (reqp->intr_completion_reason) { 2728*7c478bd9Sstevel@tonic-gate case USB_CR_OK: 2729*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 2730*7c478bd9Sstevel@tonic-gate 2731*7c478bd9Sstevel@tonic-gate break; 2732*7c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET: 2733*7c478bd9Sstevel@tonic-gate case USB_CR_STOPPED_POLLING: 2734*7c478bd9Sstevel@tonic-gate 2735*7c478bd9Sstevel@tonic-gate break; 2736*7c478bd9Sstevel@tonic-gate default: 2737*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = 2738*7c478bd9Sstevel@tonic-gate ugen_cr2lcstat(reqp->intr_completion_reason); 2739*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2740*7c478bd9Sstevel@tonic-gate "ugen_exp_intr_cb_req: lcmd_status=0x%x", 2741*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status); 2742*7c478bd9Sstevel@tonic-gate 2743*7c478bd9Sstevel@tonic-gate break; 2744*7c478bd9Sstevel@tonic-gate } 2745*7c478bd9Sstevel@tonic-gate 2746*7c478bd9Sstevel@tonic-gate /* any non-zero completion reason stops polling */ 2747*7c478bd9Sstevel@tonic-gate if ((reqp->intr_completion_reason) || 2748*7c478bd9Sstevel@tonic-gate (epp->ep_one_xfer)) { 2749*7c478bd9Sstevel@tonic-gate epp->ep_state &= ~(UGEN_EP_STATE_INTR_IN_POLLING_ON | 2750*7c478bd9Sstevel@tonic-gate UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED); 2751*7c478bd9Sstevel@tonic-gate } 2752*7c478bd9Sstevel@tonic-gate 2753*7c478bd9Sstevel@tonic-gate /* is there a poll pending? should we stop polling? */ 2754*7c478bd9Sstevel@tonic-gate if (epp->ep_data) { 2755*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2756*7c478bd9Sstevel@tonic-gate "ugen_epx_intr_IN_req_cb: data len=0x%x", 2757*7c478bd9Sstevel@tonic-gate epp->ep_data->b_wptr - epp->ep_data->b_rptr); 2758*7c478bd9Sstevel@tonic-gate 2759*7c478bd9Sstevel@tonic-gate ugen_epx_intr_IN_poll_wakeup(ugenp, epp); 2760*7c478bd9Sstevel@tonic-gate 2761*7c478bd9Sstevel@tonic-gate /* if there is no space left, stop polling */ 2762*7c478bd9Sstevel@tonic-gate if (epp->ep_data && 2763*7c478bd9Sstevel@tonic-gate ((epp->ep_data->b_wptr - epp->ep_data->b_rptr) >= 2764*7c478bd9Sstevel@tonic-gate epp->ep_buf_limit)) { 2765*7c478bd9Sstevel@tonic-gate ugen_epx_intr_IN_stop_polling(ugenp, epp); 2766*7c478bd9Sstevel@tonic-gate } 2767*7c478bd9Sstevel@tonic-gate } 2768*7c478bd9Sstevel@tonic-gate 2769*7c478bd9Sstevel@tonic-gate if (reqp->intr_completion_reason && epp->ep_bp) { 2770*7c478bd9Sstevel@tonic-gate bioerror(epp->ep_bp, EIO); 2771*7c478bd9Sstevel@tonic-gate epp->ep_done++; 2772*7c478bd9Sstevel@tonic-gate cv_signal(&epp->ep_wait_cv); 2773*7c478bd9Sstevel@tonic-gate 2774*7c478bd9Sstevel@tonic-gate /* can we satisfy the read now */ 2775*7c478bd9Sstevel@tonic-gate } else if (epp->ep_data && epp->ep_bp && 2776*7c478bd9Sstevel@tonic-gate (!epp->ep_done || epp->ep_one_xfer)) { 2777*7c478bd9Sstevel@tonic-gate boolean_t wait; 2778*7c478bd9Sstevel@tonic-gate 2779*7c478bd9Sstevel@tonic-gate if ((ugen_epx_intr_IN_req(ugenp, epp, epp->ep_bp, &wait) == 2780*7c478bd9Sstevel@tonic-gate USB_SUCCESS) && (wait == B_FALSE)) { 2781*7c478bd9Sstevel@tonic-gate epp->ep_done++; 2782*7c478bd9Sstevel@tonic-gate cv_signal(&epp->ep_wait_cv); 2783*7c478bd9Sstevel@tonic-gate } 2784*7c478bd9Sstevel@tonic-gate } 2785*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2786*7c478bd9Sstevel@tonic-gate 2787*7c478bd9Sstevel@tonic-gate done: 2788*7c478bd9Sstevel@tonic-gate usb_free_intr_req(reqp); 2789*7c478bd9Sstevel@tonic-gate } 2790*7c478bd9Sstevel@tonic-gate 2791*7c478bd9Sstevel@tonic-gate 2792*7c478bd9Sstevel@tonic-gate /* 2793*7c478bd9Sstevel@tonic-gate * handle intr OUT xfers 2794*7c478bd9Sstevel@tonic-gate */ 2795*7c478bd9Sstevel@tonic-gate static int 2796*7c478bd9Sstevel@tonic-gate ugen_epx_intr_OUT_req(ugen_state_t *ugenp, ugen_ep_t *epp, 2797*7c478bd9Sstevel@tonic-gate struct buf *bp, boolean_t *wait) 2798*7c478bd9Sstevel@tonic-gate { 2799*7c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 2800*7c478bd9Sstevel@tonic-gate usb_intr_req_t *reqp; 2801*7c478bd9Sstevel@tonic-gate 2802*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2803*7c478bd9Sstevel@tonic-gate "ugen_epx_intr_OUT_req: epp=0x%p state=0x%x bp=0x%p", 2804*7c478bd9Sstevel@tonic-gate epp, epp->ep_state, bp); 2805*7c478bd9Sstevel@tonic-gate 2806*7c478bd9Sstevel@tonic-gate reqp = usb_alloc_intr_req(ugenp->ug_dip, bp->b_bcount, 2807*7c478bd9Sstevel@tonic-gate USB_FLAGS_NOSLEEP); 2808*7c478bd9Sstevel@tonic-gate if (reqp == NULL) { 2809*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_NO_RESOURCES; 2810*7c478bd9Sstevel@tonic-gate 2811*7c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 2812*7c478bd9Sstevel@tonic-gate } 2813*7c478bd9Sstevel@tonic-gate 2814*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_state & UGEN_EP_STATE_XS_OPEN); 2815*7c478bd9Sstevel@tonic-gate 2816*7c478bd9Sstevel@tonic-gate reqp->intr_timeout = ugen_intr_timeout; 2817*7c478bd9Sstevel@tonic-gate reqp->intr_client_private = (usb_opaque_t)ugenp; 2818*7c478bd9Sstevel@tonic-gate reqp->intr_len = bp->b_bcount; 2819*7c478bd9Sstevel@tonic-gate reqp->intr_attributes = USB_ATTRS_AUTOCLEARING; 2820*7c478bd9Sstevel@tonic-gate reqp->intr_cb = ugen_epx_intr_OUT_req_cb; 2821*7c478bd9Sstevel@tonic-gate reqp->intr_exc_cb = ugen_epx_intr_OUT_req_cb; 2822*7c478bd9Sstevel@tonic-gate 2823*7c478bd9Sstevel@tonic-gate /* copy data from bp */ 2824*7c478bd9Sstevel@tonic-gate bcopy(epp->ep_bp->b_un.b_addr, reqp->intr_data->b_rptr, 2825*7c478bd9Sstevel@tonic-gate bp->b_bcount); 2826*7c478bd9Sstevel@tonic-gate reqp->intr_data->b_wptr += bp->b_bcount; 2827*7c478bd9Sstevel@tonic-gate 2828*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2829*7c478bd9Sstevel@tonic-gate if ((rval = usb_pipe_intr_xfer(epp->ep_ph, reqp, 2830*7c478bd9Sstevel@tonic-gate USB_FLAGS_NOSLEEP)) != USB_SUCCESS) { 2831*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2832*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = 2833*7c478bd9Sstevel@tonic-gate ugen_cr2lcstat(reqp->intr_completion_reason); 2834*7c478bd9Sstevel@tonic-gate usb_free_intr_req(reqp); 2835*7c478bd9Sstevel@tonic-gate bioerror(bp, EIO); 2836*7c478bd9Sstevel@tonic-gate } else { 2837*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2838*7c478bd9Sstevel@tonic-gate } 2839*7c478bd9Sstevel@tonic-gate *wait = (rval == USB_SUCCESS) ? B_TRUE : B_FALSE; 2840*7c478bd9Sstevel@tonic-gate 2841*7c478bd9Sstevel@tonic-gate return (rval); 2842*7c478bd9Sstevel@tonic-gate } 2843*7c478bd9Sstevel@tonic-gate 2844*7c478bd9Sstevel@tonic-gate 2845*7c478bd9Sstevel@tonic-gate /* 2846*7c478bd9Sstevel@tonic-gate * callback functions for interrupt OUT pipe 2847*7c478bd9Sstevel@tonic-gate */ 2848*7c478bd9Sstevel@tonic-gate static void 2849*7c478bd9Sstevel@tonic-gate ugen_epx_intr_OUT_req_cb(usb_pipe_handle_t ph, usb_intr_req_t *reqp) 2850*7c478bd9Sstevel@tonic-gate { 2851*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp = (ugen_state_t *)reqp->intr_client_private; 2852*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = (ugen_ep_t *)usb_pipe_get_private(ph); 2853*7c478bd9Sstevel@tonic-gate 2854*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2855*7c478bd9Sstevel@tonic-gate "ugen_epx_intr_OUT_req_cb: ph=0x%p reqp=0x%p cr=%d cb=0x%x", 2856*7c478bd9Sstevel@tonic-gate ph, reqp, reqp->intr_completion_reason, reqp->intr_cb_flags); 2857*7c478bd9Sstevel@tonic-gate 2858*7c478bd9Sstevel@tonic-gate ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 2859*7c478bd9Sstevel@tonic-gate 2860*7c478bd9Sstevel@tonic-gate /* epp might be NULL if we are closing the pipe */ 2861*7c478bd9Sstevel@tonic-gate if (epp) { 2862*7c478bd9Sstevel@tonic-gate int len; 2863*7c478bd9Sstevel@tonic-gate 2864*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2865*7c478bd9Sstevel@tonic-gate if (epp->ep_bp) { 2866*7c478bd9Sstevel@tonic-gate len = min(reqp->intr_data->b_wptr - 2867*7c478bd9Sstevel@tonic-gate reqp->intr_data->b_rptr, epp->ep_bp->b_bcount); 2868*7c478bd9Sstevel@tonic-gate 2869*7c478bd9Sstevel@tonic-gate epp->ep_bp->b_resid = epp->ep_bp->b_bcount - len; 2870*7c478bd9Sstevel@tonic-gate 2871*7c478bd9Sstevel@tonic-gate switch (reqp->intr_completion_reason) { 2872*7c478bd9Sstevel@tonic-gate case USB_CR_OK: 2873*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 2874*7c478bd9Sstevel@tonic-gate 2875*7c478bd9Sstevel@tonic-gate break; 2876*7c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET: 2877*7c478bd9Sstevel@tonic-gate 2878*7c478bd9Sstevel@tonic-gate break; 2879*7c478bd9Sstevel@tonic-gate default: 2880*7c478bd9Sstevel@tonic-gate epp->ep_lcmd_status = 2881*7c478bd9Sstevel@tonic-gate ugen_cr2lcstat( 2882*7c478bd9Sstevel@tonic-gate reqp->intr_completion_reason); 2883*7c478bd9Sstevel@tonic-gate bioerror(epp->ep_bp, EIO); 2884*7c478bd9Sstevel@tonic-gate } 2885*7c478bd9Sstevel@tonic-gate } 2886*7c478bd9Sstevel@tonic-gate epp->ep_done++; 2887*7c478bd9Sstevel@tonic-gate cv_signal(&epp->ep_wait_cv); 2888*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2889*7c478bd9Sstevel@tonic-gate } 2890*7c478bd9Sstevel@tonic-gate 2891*7c478bd9Sstevel@tonic-gate usb_free_intr_req(reqp); 2892*7c478bd9Sstevel@tonic-gate } 2893*7c478bd9Sstevel@tonic-gate 2894*7c478bd9Sstevel@tonic-gate 2895*7c478bd9Sstevel@tonic-gate /* 2896*7c478bd9Sstevel@tonic-gate * Endpoint status node management 2897*7c478bd9Sstevel@tonic-gate * 2898*7c478bd9Sstevel@tonic-gate * open/close an endpoint status node. 2899*7c478bd9Sstevel@tonic-gate * 2900*7c478bd9Sstevel@tonic-gate * Return values: errno 2901*7c478bd9Sstevel@tonic-gate */ 2902*7c478bd9Sstevel@tonic-gate static int 2903*7c478bd9Sstevel@tonic-gate ugen_eps_open(ugen_state_t *ugenp, dev_t dev, int flag) 2904*7c478bd9Sstevel@tonic-gate { 2905*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 2906*7c478bd9Sstevel@tonic-gate int rval = EBUSY; 2907*7c478bd9Sstevel@tonic-gate 2908*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2909*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_STAT, ugenp->ug_log_hdl, 2910*7c478bd9Sstevel@tonic-gate "ugen_eps_open: dev=0x%lx flag=0x%x state=0x%x", 2911*7c478bd9Sstevel@tonic-gate dev, flag, epp->ep_state); 2912*7c478bd9Sstevel@tonic-gate 2913*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_state & UGEN_EP_STATE_ACTIVE); 2914*7c478bd9Sstevel@tonic-gate 2915*7c478bd9Sstevel@tonic-gate /* only one open at the time */ 2916*7c478bd9Sstevel@tonic-gate if ((epp->ep_state & UGEN_EP_STATE_STAT_OPEN) == 0) { 2917*7c478bd9Sstevel@tonic-gate epp->ep_state |= UGEN_EP_STATE_STAT_OPEN; 2918*7c478bd9Sstevel@tonic-gate epp->ep_stat_oflag = flag; 2919*7c478bd9Sstevel@tonic-gate rval = 0; 2920*7c478bd9Sstevel@tonic-gate } 2921*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2922*7c478bd9Sstevel@tonic-gate 2923*7c478bd9Sstevel@tonic-gate return (rval); 2924*7c478bd9Sstevel@tonic-gate } 2925*7c478bd9Sstevel@tonic-gate 2926*7c478bd9Sstevel@tonic-gate 2927*7c478bd9Sstevel@tonic-gate /* 2928*7c478bd9Sstevel@tonic-gate * close endpoint status 2929*7c478bd9Sstevel@tonic-gate */ 2930*7c478bd9Sstevel@tonic-gate static void 2931*7c478bd9Sstevel@tonic-gate ugen_eps_close(ugen_state_t *ugenp, dev_t dev, int flag) 2932*7c478bd9Sstevel@tonic-gate { 2933*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 2934*7c478bd9Sstevel@tonic-gate 2935*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2936*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_STAT, ugenp->ug_log_hdl, 2937*7c478bd9Sstevel@tonic-gate "ugen_eps_close: dev=0x%lx flag=0x%x state=0x%x", 2938*7c478bd9Sstevel@tonic-gate dev, flag, epp->ep_state); 2939*7c478bd9Sstevel@tonic-gate 2940*7c478bd9Sstevel@tonic-gate epp->ep_state &= ~(UGEN_EP_STATE_STAT_OPEN | 2941*7c478bd9Sstevel@tonic-gate UGEN_EP_STATE_INTR_IN_POLL_PENDING); 2942*7c478bd9Sstevel@tonic-gate epp->ep_one_xfer = B_FALSE; 2943*7c478bd9Sstevel@tonic-gate 2944*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_STAT, ugenp->ug_log_hdl, 2945*7c478bd9Sstevel@tonic-gate "ugen_eps_close: state=0x%x", epp->ep_state); 2946*7c478bd9Sstevel@tonic-gate 2947*7c478bd9Sstevel@tonic-gate ASSERT(epp->ep_state & UGEN_EP_STATE_ACTIVE); 2948*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2949*7c478bd9Sstevel@tonic-gate } 2950*7c478bd9Sstevel@tonic-gate 2951*7c478bd9Sstevel@tonic-gate 2952*7c478bd9Sstevel@tonic-gate /* 2953*7c478bd9Sstevel@tonic-gate * return status info 2954*7c478bd9Sstevel@tonic-gate * 2955*7c478bd9Sstevel@tonic-gate * Return values: errno 2956*7c478bd9Sstevel@tonic-gate */ 2957*7c478bd9Sstevel@tonic-gate static int 2958*7c478bd9Sstevel@tonic-gate ugen_eps_req(ugen_state_t *ugenp, struct buf *bp) 2959*7c478bd9Sstevel@tonic-gate { 2960*7c478bd9Sstevel@tonic-gate ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, bp->b_edev)]; 2961*7c478bd9Sstevel@tonic-gate 2962*7c478bd9Sstevel@tonic-gate mutex_enter(&epp->ep_mutex); 2963*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2964*7c478bd9Sstevel@tonic-gate "ugen_eps_req: bp=0x%p lcmd_status=0x%x bcount=%lu", 2965*7c478bd9Sstevel@tonic-gate bp, epp->ep_lcmd_status, bp->b_bcount); 2966*7c478bd9Sstevel@tonic-gate 2967*7c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 2968*7c478bd9Sstevel@tonic-gate int len = min(sizeof (epp->ep_lcmd_status), bp->b_bcount); 2969*7c478bd9Sstevel@tonic-gate if (len) { 2970*7c478bd9Sstevel@tonic-gate bcopy(&epp->ep_lcmd_status, bp->b_un.b_addr, len); 2971*7c478bd9Sstevel@tonic-gate } 2972*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount - len; 2973*7c478bd9Sstevel@tonic-gate } else { 2974*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2975*7c478bd9Sstevel@tonic-gate "ugen_eps_req: control=0x%x", 2976*7c478bd9Sstevel@tonic-gate *((char *)(bp->b_un.b_addr))); 2977*7c478bd9Sstevel@tonic-gate 2978*7c478bd9Sstevel@tonic-gate if (epp->ep_state & UGEN_EP_STATE_XFER_OPEN) { 2979*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2980*7c478bd9Sstevel@tonic-gate "ugen_eps_req: cannot change one xfer mode if " 2981*7c478bd9Sstevel@tonic-gate "endpoint is open"); 2982*7c478bd9Sstevel@tonic-gate 2983*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2984*7c478bd9Sstevel@tonic-gate 2985*7c478bd9Sstevel@tonic-gate return (EINVAL); 2986*7c478bd9Sstevel@tonic-gate } 2987*7c478bd9Sstevel@tonic-gate 2988*7c478bd9Sstevel@tonic-gate if ((epp->ep_descr.bmAttributes & USB_EP_ATTR_INTR) && 2989*7c478bd9Sstevel@tonic-gate (epp->ep_descr.bEndpointAddress & USB_EP_DIR_IN)) { 2990*7c478bd9Sstevel@tonic-gate epp->ep_one_xfer = (*((char *)(bp->b_un.b_addr)) & 2991*7c478bd9Sstevel@tonic-gate USB_EP_INTR_ONE_XFER) ? B_TRUE : B_FALSE; 2992*7c478bd9Sstevel@tonic-gate } else { 2993*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2994*7c478bd9Sstevel@tonic-gate "ugen_eps_req: not an interrupt endpoint"); 2995*7c478bd9Sstevel@tonic-gate 2996*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 2997*7c478bd9Sstevel@tonic-gate 2998*7c478bd9Sstevel@tonic-gate return (EINVAL); 2999*7c478bd9Sstevel@tonic-gate } 3000*7c478bd9Sstevel@tonic-gate 3001*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount - 1; 3002*7c478bd9Sstevel@tonic-gate } 3003*7c478bd9Sstevel@tonic-gate mutex_exit(&epp->ep_mutex); 3004*7c478bd9Sstevel@tonic-gate 3005*7c478bd9Sstevel@tonic-gate return (0); 3006*7c478bd9Sstevel@tonic-gate } 3007*7c478bd9Sstevel@tonic-gate 3008*7c478bd9Sstevel@tonic-gate 3009*7c478bd9Sstevel@tonic-gate /* 3010*7c478bd9Sstevel@tonic-gate * device status node management 3011*7c478bd9Sstevel@tonic-gate */ 3012*7c478bd9Sstevel@tonic-gate static int 3013*7c478bd9Sstevel@tonic-gate ugen_ds_init(ugen_state_t *ugenp) 3014*7c478bd9Sstevel@tonic-gate { 3015*7c478bd9Sstevel@tonic-gate cv_init(&ugenp->ug_ds.dev_wait_cv, NULL, CV_DRIVER, NULL); 3016*7c478bd9Sstevel@tonic-gate 3017*7c478bd9Sstevel@tonic-gate /* Create devstat minor node for this instance */ 3018*7c478bd9Sstevel@tonic-gate if (ugen_ds_minor_nodes_create(ugenp) != USB_SUCCESS) { 3019*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 3020*7c478bd9Sstevel@tonic-gate "ugen_create_dev_stat_minor_nodes failed"); 3021*7c478bd9Sstevel@tonic-gate 3022*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 3023*7c478bd9Sstevel@tonic-gate } 3024*7c478bd9Sstevel@tonic-gate 3025*7c478bd9Sstevel@tonic-gate 3026*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 3027*7c478bd9Sstevel@tonic-gate } 3028*7c478bd9Sstevel@tonic-gate 3029*7c478bd9Sstevel@tonic-gate 3030*7c478bd9Sstevel@tonic-gate static void 3031*7c478bd9Sstevel@tonic-gate ugen_ds_destroy(ugen_state_t *ugenp) 3032*7c478bd9Sstevel@tonic-gate { 3033*7c478bd9Sstevel@tonic-gate cv_destroy(&ugenp->ug_ds.dev_wait_cv); 3034*7c478bd9Sstevel@tonic-gate } 3035*7c478bd9Sstevel@tonic-gate 3036*7c478bd9Sstevel@tonic-gate 3037*7c478bd9Sstevel@tonic-gate /* 3038*7c478bd9Sstevel@tonic-gate * open devstat minor node 3039*7c478bd9Sstevel@tonic-gate * 3040*7c478bd9Sstevel@tonic-gate * Return values: errno 3041*7c478bd9Sstevel@tonic-gate */ 3042*7c478bd9Sstevel@tonic-gate static int 3043*7c478bd9Sstevel@tonic-gate ugen_ds_open(ugen_state_t *ugenp, dev_t dev, int flag) 3044*7c478bd9Sstevel@tonic-gate { 3045*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3046*7c478bd9Sstevel@tonic-gate "ugen_ds_open: dev=0x%lx flag=0x%x", dev, flag); 3047*7c478bd9Sstevel@tonic-gate 3048*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 3049*7c478bd9Sstevel@tonic-gate if ((ugenp->ug_ds.dev_stat & UGEN_DEV_STATUS_ACTIVE) == 0) { 3050*7c478bd9Sstevel@tonic-gate /* 3051*7c478bd9Sstevel@tonic-gate * first read on device node should return status 3052*7c478bd9Sstevel@tonic-gate */ 3053*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_stat |= UGEN_DEV_STATUS_CHANGED | 3054*7c478bd9Sstevel@tonic-gate UGEN_DEV_STATUS_ACTIVE; 3055*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_oflag = flag; 3056*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3057*7c478bd9Sstevel@tonic-gate 3058*7c478bd9Sstevel@tonic-gate return (0); 3059*7c478bd9Sstevel@tonic-gate } else { 3060*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3061*7c478bd9Sstevel@tonic-gate 3062*7c478bd9Sstevel@tonic-gate return (EBUSY); 3063*7c478bd9Sstevel@tonic-gate } 3064*7c478bd9Sstevel@tonic-gate } 3065*7c478bd9Sstevel@tonic-gate 3066*7c478bd9Sstevel@tonic-gate 3067*7c478bd9Sstevel@tonic-gate static void 3068*7c478bd9Sstevel@tonic-gate ugen_ds_close(ugen_state_t *ugenp, dev_t dev, int flag) 3069*7c478bd9Sstevel@tonic-gate { 3070*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3071*7c478bd9Sstevel@tonic-gate "ugen_ds_close: dev=0x%lx flag=0x%x", dev, flag); 3072*7c478bd9Sstevel@tonic-gate 3073*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 3074*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_stat = UGEN_DEV_STATUS_INACTIVE; 3075*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3076*7c478bd9Sstevel@tonic-gate } 3077*7c478bd9Sstevel@tonic-gate 3078*7c478bd9Sstevel@tonic-gate 3079*7c478bd9Sstevel@tonic-gate /* 3080*7c478bd9Sstevel@tonic-gate * request for devstat 3081*7c478bd9Sstevel@tonic-gate * 3082*7c478bd9Sstevel@tonic-gate * Return values: errno 3083*7c478bd9Sstevel@tonic-gate */ 3084*7c478bd9Sstevel@tonic-gate static int 3085*7c478bd9Sstevel@tonic-gate ugen_ds_req(ugen_state_t *ugenp, struct buf *bp) 3086*7c478bd9Sstevel@tonic-gate { 3087*7c478bd9Sstevel@tonic-gate int len = min(sizeof (ugenp->ug_ds.dev_state), bp->b_bcount); 3088*7c478bd9Sstevel@tonic-gate 3089*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3090*7c478bd9Sstevel@tonic-gate "ugen_ds_req: bp=0x%p", bp); 3091*7c478bd9Sstevel@tonic-gate 3092*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 3093*7c478bd9Sstevel@tonic-gate if ((ugenp->ug_ds.dev_oflag & (FNDELAY | FNONBLOCK)) == 0) { 3094*7c478bd9Sstevel@tonic-gate while ((ugenp->ug_ds.dev_stat & 3095*7c478bd9Sstevel@tonic-gate UGEN_DEV_STATUS_CHANGED) == 0) { 3096*7c478bd9Sstevel@tonic-gate if (cv_wait_sig(&ugenp->ug_ds.dev_wait_cv, 3097*7c478bd9Sstevel@tonic-gate &ugenp->ug_mutex) <= 0) { 3098*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3099*7c478bd9Sstevel@tonic-gate 3100*7c478bd9Sstevel@tonic-gate return (EINTR); 3101*7c478bd9Sstevel@tonic-gate } 3102*7c478bd9Sstevel@tonic-gate } 3103*7c478bd9Sstevel@tonic-gate } else if ((ugenp->ug_ds.dev_stat & UGEN_DEV_STATUS_CHANGED) == 3104*7c478bd9Sstevel@tonic-gate 0) { 3105*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 3106*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3107*7c478bd9Sstevel@tonic-gate 3108*7c478bd9Sstevel@tonic-gate return (0); 3109*7c478bd9Sstevel@tonic-gate } 3110*7c478bd9Sstevel@tonic-gate 3111*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_stat &= ~UGEN_DEV_STATUS_CHANGED; 3112*7c478bd9Sstevel@tonic-gate switch (ugenp->ug_dev_state) { 3113*7c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE: 3114*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_state = USB_DEV_STAT_ONLINE; 3115*7c478bd9Sstevel@tonic-gate 3116*7c478bd9Sstevel@tonic-gate break; 3117*7c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED: 3118*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_state = USB_DEV_STAT_DISCONNECTED; 3119*7c478bd9Sstevel@tonic-gate 3120*7c478bd9Sstevel@tonic-gate break; 3121*7c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED: 3122*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RESUME: 3123*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_state = USB_DEV_STAT_RESUMED; 3124*7c478bd9Sstevel@tonic-gate 3125*7c478bd9Sstevel@tonic-gate break; 3126*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 3127*7c478bd9Sstevel@tonic-gate default: 3128*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_state = USB_DEV_STAT_UNAVAILABLE; 3129*7c478bd9Sstevel@tonic-gate 3130*7c478bd9Sstevel@tonic-gate break; 3131*7c478bd9Sstevel@tonic-gate } 3132*7c478bd9Sstevel@tonic-gate 3133*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3134*7c478bd9Sstevel@tonic-gate "ugen_ds_req: dev_state=0x%x dev_stat=0x%x", 3135*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_state, ugenp->ug_ds.dev_stat); 3136*7c478bd9Sstevel@tonic-gate 3137*7c478bd9Sstevel@tonic-gate bcopy(&ugenp->ug_ds.dev_state, bp->b_un.b_addr, len); 3138*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount - len; 3139*7c478bd9Sstevel@tonic-gate 3140*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3141*7c478bd9Sstevel@tonic-gate 3142*7c478bd9Sstevel@tonic-gate return (0); 3143*7c478bd9Sstevel@tonic-gate } 3144*7c478bd9Sstevel@tonic-gate 3145*7c478bd9Sstevel@tonic-gate 3146*7c478bd9Sstevel@tonic-gate static void 3147*7c478bd9Sstevel@tonic-gate ugen_ds_change(ugen_state_t *ugenp) 3148*7c478bd9Sstevel@tonic-gate { 3149*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3150*7c478bd9Sstevel@tonic-gate "ugen_ds_change:"); 3151*7c478bd9Sstevel@tonic-gate 3152*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_stat |= UGEN_DEV_STATUS_CHANGED; 3153*7c478bd9Sstevel@tonic-gate cv_signal(&ugenp->ug_ds.dev_wait_cv); 3154*7c478bd9Sstevel@tonic-gate } 3155*7c478bd9Sstevel@tonic-gate 3156*7c478bd9Sstevel@tonic-gate 3157*7c478bd9Sstevel@tonic-gate /* 3158*7c478bd9Sstevel@tonic-gate * poll management 3159*7c478bd9Sstevel@tonic-gate */ 3160*7c478bd9Sstevel@tonic-gate static void 3161*7c478bd9Sstevel@tonic-gate ugen_ds_poll_wakeup(ugen_state_t *ugenp) 3162*7c478bd9Sstevel@tonic-gate { 3163*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3164*7c478bd9Sstevel@tonic-gate "ugen_ds_poll_wakeup:"); 3165*7c478bd9Sstevel@tonic-gate 3166*7c478bd9Sstevel@tonic-gate if (ugenp->ug_ds.dev_stat & UGEN_DEV_STATUS_POLL_PENDING) { 3167*7c478bd9Sstevel@tonic-gate struct pollhead *phpp = &ugenp->ug_ds.dev_pollhead; 3168*7c478bd9Sstevel@tonic-gate ugenp->ug_ds.dev_stat &= ~UGEN_DEV_STATUS_POLL_PENDING; 3169*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3170*7c478bd9Sstevel@tonic-gate pollwakeup(phpp, POLLIN); 3171*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 3172*7c478bd9Sstevel@tonic-gate } 3173*7c478bd9Sstevel@tonic-gate } 3174*7c478bd9Sstevel@tonic-gate 3175*7c478bd9Sstevel@tonic-gate 3176*7c478bd9Sstevel@tonic-gate /* 3177*7c478bd9Sstevel@tonic-gate * minor node management: 3178*7c478bd9Sstevel@tonic-gate */ 3179*7c478bd9Sstevel@tonic-gate static int 3180*7c478bd9Sstevel@tonic-gate ugen_ds_minor_nodes_create(ugen_state_t *ugenp) 3181*7c478bd9Sstevel@tonic-gate { 3182*7c478bd9Sstevel@tonic-gate char node_name[32]; 3183*7c478bd9Sstevel@tonic-gate int vid = ugenp->ug_dev_data->dev_descr->idVendor; 3184*7c478bd9Sstevel@tonic-gate int pid = ugenp->ug_dev_data->dev_descr->idProduct; 3185*7c478bd9Sstevel@tonic-gate minor_t minor; 3186*7c478bd9Sstevel@tonic-gate int minor_index; 3187*7c478bd9Sstevel@tonic-gate int owns_device = (usb_owns_device(ugenp->ug_dip) ? 3188*7c478bd9Sstevel@tonic-gate UGEN_OWNS_DEVICE : 0); 3189*7c478bd9Sstevel@tonic-gate 3190*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 3191*7c478bd9Sstevel@tonic-gate "ugen_ds_minor_nodes_create: idx shift=%d inst shift=%d", 3192*7c478bd9Sstevel@tonic-gate UGEN_MINOR_IDX_SHIFT(ugenp), 3193*7c478bd9Sstevel@tonic-gate UGEN_MINOR_INSTANCE_SHIFT(ugenp)); 3194*7c478bd9Sstevel@tonic-gate 3195*7c478bd9Sstevel@tonic-gate if (ugenp->ug_instance >= UGEN_MINOR_INSTANCE_LIMIT(ugenp)) { 3196*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 3197*7c478bd9Sstevel@tonic-gate "instance number too high (%d)", ugenp->ug_instance); 3198*7c478bd9Sstevel@tonic-gate 3199*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 3200*7c478bd9Sstevel@tonic-gate } 3201*7c478bd9Sstevel@tonic-gate 3202*7c478bd9Sstevel@tonic-gate /* create devstat minor node */ 3203*7c478bd9Sstevel@tonic-gate if (owns_device) { 3204*7c478bd9Sstevel@tonic-gate (void) sprintf(node_name, "%x.%x.devstat", vid, pid); 3205*7c478bd9Sstevel@tonic-gate } else { 3206*7c478bd9Sstevel@tonic-gate (void) sprintf(node_name, "%x.%x.if%ddevstat", vid, pid, 3207*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_data->dev_curr_if); 3208*7c478bd9Sstevel@tonic-gate } 3209*7c478bd9Sstevel@tonic-gate 3210*7c478bd9Sstevel@tonic-gate minor_index = ugen_minor_index_create(ugenp, 3211*7c478bd9Sstevel@tonic-gate (UGEN_MINOR_DEV_STAT_NODE | owns_device) << 3212*7c478bd9Sstevel@tonic-gate UGEN_MINOR_IDX_SHIFT(ugenp)); 3213*7c478bd9Sstevel@tonic-gate 3214*7c478bd9Sstevel@tonic-gate if (minor_index < 0) { 3215*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 3216*7c478bd9Sstevel@tonic-gate "too many minor nodes"); 3217*7c478bd9Sstevel@tonic-gate 3218*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 3219*7c478bd9Sstevel@tonic-gate } 3220*7c478bd9Sstevel@tonic-gate minor = (minor_index << UGEN_MINOR_IDX_SHIFT(ugenp)) | 3221*7c478bd9Sstevel@tonic-gate ugenp->ug_instance << UGEN_MINOR_INSTANCE_SHIFT(ugenp); 3222*7c478bd9Sstevel@tonic-gate 3223*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 3224*7c478bd9Sstevel@tonic-gate "minor=0x%x minor_index=%d name=%s", 3225*7c478bd9Sstevel@tonic-gate minor, minor_index, node_name); 3226*7c478bd9Sstevel@tonic-gate 3227*7c478bd9Sstevel@tonic-gate ASSERT(minor < L_MAXMIN); 3228*7c478bd9Sstevel@tonic-gate 3229*7c478bd9Sstevel@tonic-gate if ((ddi_create_minor_node(ugenp->ug_dip, node_name, 3230*7c478bd9Sstevel@tonic-gate S_IFCHR, minor, DDI_NT_UGEN, 0)) != DDI_SUCCESS) { 3231*7c478bd9Sstevel@tonic-gate 3232*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 3233*7c478bd9Sstevel@tonic-gate } 3234*7c478bd9Sstevel@tonic-gate 3235*7c478bd9Sstevel@tonic-gate ugen_store_devt(ugenp, minor); 3236*7c478bd9Sstevel@tonic-gate 3237*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 3238*7c478bd9Sstevel@tonic-gate } 3239*7c478bd9Sstevel@tonic-gate 3240*7c478bd9Sstevel@tonic-gate 3241*7c478bd9Sstevel@tonic-gate /* 3242*7c478bd9Sstevel@tonic-gate * utility functions: 3243*7c478bd9Sstevel@tonic-gate * 3244*7c478bd9Sstevel@tonic-gate * conversion from completion reason to USB_LC_STAT_* 3245*7c478bd9Sstevel@tonic-gate */ 3246*7c478bd9Sstevel@tonic-gate static struct ugen_cr2lcstat_entry { 3247*7c478bd9Sstevel@tonic-gate int cr; 3248*7c478bd9Sstevel@tonic-gate int lcstat; 3249*7c478bd9Sstevel@tonic-gate } ugen_cr2lcstat_table[] = { 3250*7c478bd9Sstevel@tonic-gate { USB_CR_OK, USB_LC_STAT_NOERROR }, 3251*7c478bd9Sstevel@tonic-gate { USB_CR_CRC, USB_LC_STAT_CRC }, 3252*7c478bd9Sstevel@tonic-gate { USB_CR_BITSTUFFING, USB_LC_STAT_BITSTUFFING }, 3253*7c478bd9Sstevel@tonic-gate { USB_CR_DATA_TOGGLE_MM, USB_LC_STAT_DATA_TOGGLE_MM }, 3254*7c478bd9Sstevel@tonic-gate { USB_CR_STALL, USB_LC_STAT_STALL }, 3255*7c478bd9Sstevel@tonic-gate { USB_CR_DEV_NOT_RESP, USB_LC_STAT_DEV_NOT_RESP }, 3256*7c478bd9Sstevel@tonic-gate { USB_CR_PID_CHECKFAILURE, USB_LC_STAT_PID_CHECKFAILURE }, 3257*7c478bd9Sstevel@tonic-gate { USB_CR_UNEXP_PID, USB_LC_STAT_UNEXP_PID }, 3258*7c478bd9Sstevel@tonic-gate { USB_CR_DATA_OVERRUN, USB_LC_STAT_DATA_OVERRUN }, 3259*7c478bd9Sstevel@tonic-gate { USB_CR_DATA_UNDERRUN, USB_LC_STAT_DATA_UNDERRUN }, 3260*7c478bd9Sstevel@tonic-gate { USB_CR_BUFFER_OVERRUN, USB_LC_STAT_BUFFER_OVERRUN }, 3261*7c478bd9Sstevel@tonic-gate { USB_CR_BUFFER_UNDERRUN, USB_LC_STAT_BUFFER_UNDERRUN }, 3262*7c478bd9Sstevel@tonic-gate { USB_CR_TIMEOUT, USB_LC_STAT_TIMEOUT }, 3263*7c478bd9Sstevel@tonic-gate { USB_CR_NOT_ACCESSED, USB_LC_STAT_NOT_ACCESSED }, 3264*7c478bd9Sstevel@tonic-gate { USB_CR_NO_RESOURCES, USB_LC_STAT_NO_BANDWIDTH }, 3265*7c478bd9Sstevel@tonic-gate { USB_CR_UNSPECIFIED_ERR, USB_LC_STAT_UNSPECIFIED_ERR }, 3266*7c478bd9Sstevel@tonic-gate { USB_CR_STOPPED_POLLING, USB_LC_STAT_HW_ERR }, 3267*7c478bd9Sstevel@tonic-gate { USB_CR_PIPE_CLOSING, USB_LC_STAT_UNSPECIFIED_ERR }, 3268*7c478bd9Sstevel@tonic-gate { USB_CR_PIPE_RESET, USB_LC_STAT_UNSPECIFIED_ERR }, 3269*7c478bd9Sstevel@tonic-gate { USB_CR_NOT_SUPPORTED, USB_LC_STAT_UNSPECIFIED_ERR }, 3270*7c478bd9Sstevel@tonic-gate { USB_CR_FLUSHED, USB_LC_STAT_UNSPECIFIED_ERR } 3271*7c478bd9Sstevel@tonic-gate }; 3272*7c478bd9Sstevel@tonic-gate 3273*7c478bd9Sstevel@tonic-gate #define UGEN_CR2LCSTAT_TABLE_SIZE (sizeof (ugen_cr2lcstat_table) / \ 3274*7c478bd9Sstevel@tonic-gate sizeof (struct ugen_cr2lcstat_entry)) 3275*7c478bd9Sstevel@tonic-gate static int 3276*7c478bd9Sstevel@tonic-gate ugen_cr2lcstat(int cr) 3277*7c478bd9Sstevel@tonic-gate { 3278*7c478bd9Sstevel@tonic-gate int i; 3279*7c478bd9Sstevel@tonic-gate 3280*7c478bd9Sstevel@tonic-gate for (i = 0; i < UGEN_CR2LCSTAT_TABLE_SIZE; i++) { 3281*7c478bd9Sstevel@tonic-gate if (ugen_cr2lcstat_table[i].cr == cr) { 3282*7c478bd9Sstevel@tonic-gate 3283*7c478bd9Sstevel@tonic-gate return (ugen_cr2lcstat_table[i].lcstat); 3284*7c478bd9Sstevel@tonic-gate } 3285*7c478bd9Sstevel@tonic-gate } 3286*7c478bd9Sstevel@tonic-gate 3287*7c478bd9Sstevel@tonic-gate return (USB_LC_STAT_UNSPECIFIED_ERR); 3288*7c478bd9Sstevel@tonic-gate } 3289*7c478bd9Sstevel@tonic-gate 3290*7c478bd9Sstevel@tonic-gate 3291*7c478bd9Sstevel@tonic-gate /* 3292*7c478bd9Sstevel@tonic-gate * create and lookup minor index 3293*7c478bd9Sstevel@tonic-gate */ 3294*7c478bd9Sstevel@tonic-gate static int 3295*7c478bd9Sstevel@tonic-gate ugen_minor_index_create(ugen_state_t *ugenp, ugen_minor_t minor) 3296*7c478bd9Sstevel@tonic-gate { 3297*7c478bd9Sstevel@tonic-gate int i; 3298*7c478bd9Sstevel@tonic-gate 3299*7c478bd9Sstevel@tonic-gate /* check if already in the table */ 3300*7c478bd9Sstevel@tonic-gate for (i = 1; i < ugenp->ug_minor_node_table_index; i++) { 3301*7c478bd9Sstevel@tonic-gate if (ugenp->ug_minor_node_table[i] == minor) { 3302*7c478bd9Sstevel@tonic-gate 3303*7c478bd9Sstevel@tonic-gate return (-1); 3304*7c478bd9Sstevel@tonic-gate } 3305*7c478bd9Sstevel@tonic-gate } 3306*7c478bd9Sstevel@tonic-gate if (ugenp->ug_minor_node_table_index < 3307*7c478bd9Sstevel@tonic-gate (ugenp->ug_minor_node_table_size/sizeof (ugen_minor_t))) { 3308*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table[ugenp-> 3309*7c478bd9Sstevel@tonic-gate ug_minor_node_table_index] = minor; 3310*7c478bd9Sstevel@tonic-gate 3311*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 3312*7c478bd9Sstevel@tonic-gate "ugen_minor_index_create: %d: 0x%lx", 3313*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table_index, 3314*7c478bd9Sstevel@tonic-gate minor); 3315*7c478bd9Sstevel@tonic-gate 3316*7c478bd9Sstevel@tonic-gate return (ugenp->ug_minor_node_table_index++); 3317*7c478bd9Sstevel@tonic-gate } else { 3318*7c478bd9Sstevel@tonic-gate 3319*7c478bd9Sstevel@tonic-gate return (-1); 3320*7c478bd9Sstevel@tonic-gate } 3321*7c478bd9Sstevel@tonic-gate } 3322*7c478bd9Sstevel@tonic-gate 3323*7c478bd9Sstevel@tonic-gate 3324*7c478bd9Sstevel@tonic-gate static ugen_minor_t 3325*7c478bd9Sstevel@tonic-gate ugen_devt2minor(ugen_state_t *ugenp, dev_t dev) 3326*7c478bd9Sstevel@tonic-gate { 3327*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 3328*7c478bd9Sstevel@tonic-gate "ugen_devt2minor: minorcode=%d, minor=0x%" PRIx64, 3329*7c478bd9Sstevel@tonic-gate UGEN_MINOR_GET_IDX(ugenp, dev), 3330*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table[UGEN_MINOR_GET_IDX(ugenp, dev)]); 3331*7c478bd9Sstevel@tonic-gate 3332*7c478bd9Sstevel@tonic-gate ASSERT(UGEN_MINOR_GET_IDX(ugenp, dev) < 3333*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table_index); 3334*7c478bd9Sstevel@tonic-gate 3335*7c478bd9Sstevel@tonic-gate return (ugenp->ug_minor_node_table[UGEN_MINOR_GET_IDX(ugenp, dev)]); 3336*7c478bd9Sstevel@tonic-gate } 3337*7c478bd9Sstevel@tonic-gate 3338*7c478bd9Sstevel@tonic-gate 3339*7c478bd9Sstevel@tonic-gate static void 3340*7c478bd9Sstevel@tonic-gate ugen_minor_node_table_create(ugen_state_t *ugenp) 3341*7c478bd9Sstevel@tonic-gate { 3342*7c478bd9Sstevel@tonic-gate size_t size = sizeof (ugen_minor_t) * UGEN_MINOR_IDX_LIMIT(ugenp); 3343*7c478bd9Sstevel@tonic-gate 3344*7c478bd9Sstevel@tonic-gate /* allocate the max table size needed, we reduce later */ 3345*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table = kmem_zalloc(size, KM_SLEEP); 3346*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table_size = size; 3347*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table_index = 1; 3348*7c478bd9Sstevel@tonic-gate } 3349*7c478bd9Sstevel@tonic-gate 3350*7c478bd9Sstevel@tonic-gate 3351*7c478bd9Sstevel@tonic-gate static void 3352*7c478bd9Sstevel@tonic-gate ugen_minor_node_table_shrink(ugen_state_t *ugenp) 3353*7c478bd9Sstevel@tonic-gate { 3354*7c478bd9Sstevel@tonic-gate /* reduce the table size to save some memory */ 3355*7c478bd9Sstevel@tonic-gate if (ugenp->ug_minor_node_table_index < UGEN_MINOR_IDX_LIMIT(ugenp)) { 3356*7c478bd9Sstevel@tonic-gate size_t newsize = sizeof (ugen_minor_t) * 3357*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table_index; 3358*7c478bd9Sstevel@tonic-gate ugen_minor_t *buf = kmem_zalloc(newsize, KM_SLEEP); 3359*7c478bd9Sstevel@tonic-gate 3360*7c478bd9Sstevel@tonic-gate bcopy(ugenp->ug_minor_node_table, buf, newsize); 3361*7c478bd9Sstevel@tonic-gate kmem_free(ugenp->ug_minor_node_table, 3362*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table_size); 3363*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table = buf; 3364*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table_size = newsize; 3365*7c478bd9Sstevel@tonic-gate } 3366*7c478bd9Sstevel@tonic-gate } 3367*7c478bd9Sstevel@tonic-gate 3368*7c478bd9Sstevel@tonic-gate 3369*7c478bd9Sstevel@tonic-gate static void 3370*7c478bd9Sstevel@tonic-gate ugen_minor_node_table_destroy(ugen_state_t *ugenp) 3371*7c478bd9Sstevel@tonic-gate { 3372*7c478bd9Sstevel@tonic-gate if (ugenp->ug_minor_node_table) { 3373*7c478bd9Sstevel@tonic-gate kmem_free(ugenp->ug_minor_node_table, 3374*7c478bd9Sstevel@tonic-gate ugenp->ug_minor_node_table_size); 3375*7c478bd9Sstevel@tonic-gate } 3376*7c478bd9Sstevel@tonic-gate } 3377*7c478bd9Sstevel@tonic-gate 3378*7c478bd9Sstevel@tonic-gate 3379*7c478bd9Sstevel@tonic-gate static void 3380*7c478bd9Sstevel@tonic-gate ugen_check_mask(uint_t mask, uint_t *shift, uint_t *limit) 3381*7c478bd9Sstevel@tonic-gate { 3382*7c478bd9Sstevel@tonic-gate uint_t i, j; 3383*7c478bd9Sstevel@tonic-gate 3384*7c478bd9Sstevel@tonic-gate for (i = 0; i < UGEN_MINOR_NODE_SIZE; i++) { 3385*7c478bd9Sstevel@tonic-gate if ((1 << i) & mask) { 3386*7c478bd9Sstevel@tonic-gate 3387*7c478bd9Sstevel@tonic-gate break; 3388*7c478bd9Sstevel@tonic-gate } 3389*7c478bd9Sstevel@tonic-gate } 3390*7c478bd9Sstevel@tonic-gate 3391*7c478bd9Sstevel@tonic-gate for (j = i; j < UGEN_MINOR_NODE_SIZE; j++) { 3392*7c478bd9Sstevel@tonic-gate if (((1 << j) & mask) == 0) { 3393*7c478bd9Sstevel@tonic-gate 3394*7c478bd9Sstevel@tonic-gate break; 3395*7c478bd9Sstevel@tonic-gate } 3396*7c478bd9Sstevel@tonic-gate } 3397*7c478bd9Sstevel@tonic-gate 3398*7c478bd9Sstevel@tonic-gate *limit = (i == j) ? 0 : 1 << (j - i); 3399*7c478bd9Sstevel@tonic-gate *shift = i; 3400*7c478bd9Sstevel@tonic-gate } 3401*7c478bd9Sstevel@tonic-gate 3402*7c478bd9Sstevel@tonic-gate 3403*7c478bd9Sstevel@tonic-gate 3404*7c478bd9Sstevel@tonic-gate /* 3405*7c478bd9Sstevel@tonic-gate * power management: 3406*7c478bd9Sstevel@tonic-gate * 3407*7c478bd9Sstevel@tonic-gate * ugen_pm_init: 3408*7c478bd9Sstevel@tonic-gate * Initialize power management and remote wakeup functionality. 3409*7c478bd9Sstevel@tonic-gate * No mutex is necessary in this function as it's called only by attach. 3410*7c478bd9Sstevel@tonic-gate */ 3411*7c478bd9Sstevel@tonic-gate static void 3412*7c478bd9Sstevel@tonic-gate ugen_pm_init(ugen_state_t *ugenp) 3413*7c478bd9Sstevel@tonic-gate { 3414*7c478bd9Sstevel@tonic-gate dev_info_t *dip = ugenp->ug_dip; 3415*7c478bd9Sstevel@tonic-gate ugen_power_t *ugenpm; 3416*7c478bd9Sstevel@tonic-gate 3417*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3418*7c478bd9Sstevel@tonic-gate "ugen_pm_init:"); 3419*7c478bd9Sstevel@tonic-gate 3420*7c478bd9Sstevel@tonic-gate /* Allocate the state structure */ 3421*7c478bd9Sstevel@tonic-gate ugenpm = kmem_zalloc(sizeof (ugen_power_t), KM_SLEEP); 3422*7c478bd9Sstevel@tonic-gate 3423*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 3424*7c478bd9Sstevel@tonic-gate ugenp->ug_pm = ugenpm; 3425*7c478bd9Sstevel@tonic-gate ugenpm->pwr_wakeup_enabled = B_FALSE; 3426*7c478bd9Sstevel@tonic-gate ugenpm->pwr_current = USB_DEV_OS_FULL_PWR; 3427*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3428*7c478bd9Sstevel@tonic-gate 3429*7c478bd9Sstevel@tonic-gate /* 3430*7c478bd9Sstevel@tonic-gate * If remote wakeup is not available you may not want to do 3431*7c478bd9Sstevel@tonic-gate * power management. 3432*7c478bd9Sstevel@tonic-gate */ 3433*7c478bd9Sstevel@tonic-gate if (ugen_enable_pm || usb_handle_remote_wakeup(dip, 3434*7c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 3435*7c478bd9Sstevel@tonic-gate if (usb_create_pm_components(dip, 3436*7c478bd9Sstevel@tonic-gate &ugenpm->pwr_states) == USB_SUCCESS) { 3437*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_PM, 3438*7c478bd9Sstevel@tonic-gate ugenp->ug_log_hdl, 3439*7c478bd9Sstevel@tonic-gate "ugen_pm_init: " 3440*7c478bd9Sstevel@tonic-gate "created PM components"); 3441*7c478bd9Sstevel@tonic-gate 3442*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 3443*7c478bd9Sstevel@tonic-gate ugenpm->pwr_wakeup_enabled = B_TRUE; 3444*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3445*7c478bd9Sstevel@tonic-gate 3446*7c478bd9Sstevel@tonic-gate if (pm_raise_power(dip, 0, 3447*7c478bd9Sstevel@tonic-gate USB_DEV_OS_FULL_PWR) != DDI_SUCCESS) { 3448*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_PM, 3449*7c478bd9Sstevel@tonic-gate ugenp->ug_log_hdl, 3450*7c478bd9Sstevel@tonic-gate "ugen_pm_init: " 3451*7c478bd9Sstevel@tonic-gate "raising power failed"); 3452*7c478bd9Sstevel@tonic-gate } 3453*7c478bd9Sstevel@tonic-gate } else { 3454*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_PM, 3455*7c478bd9Sstevel@tonic-gate ugenp->ug_log_hdl, 3456*7c478bd9Sstevel@tonic-gate "ugen_pm_init: " 3457*7c478bd9Sstevel@tonic-gate "create_pm_comps failed"); 3458*7c478bd9Sstevel@tonic-gate } 3459*7c478bd9Sstevel@tonic-gate } else { 3460*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_PM, 3461*7c478bd9Sstevel@tonic-gate ugenp->ug_log_hdl, "ugen_pm_init: " 3462*7c478bd9Sstevel@tonic-gate "failure enabling remote wakeup"); 3463*7c478bd9Sstevel@tonic-gate } 3464*7c478bd9Sstevel@tonic-gate 3465*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3466*7c478bd9Sstevel@tonic-gate "ugen_pm_init: end"); 3467*7c478bd9Sstevel@tonic-gate } 3468*7c478bd9Sstevel@tonic-gate 3469*7c478bd9Sstevel@tonic-gate 3470*7c478bd9Sstevel@tonic-gate /* 3471*7c478bd9Sstevel@tonic-gate * ugen_pm_destroy: 3472*7c478bd9Sstevel@tonic-gate * Shut down and destroy power management and remote wakeup functionality. 3473*7c478bd9Sstevel@tonic-gate */ 3474*7c478bd9Sstevel@tonic-gate static void 3475*7c478bd9Sstevel@tonic-gate ugen_pm_destroy(ugen_state_t *ugenp) 3476*7c478bd9Sstevel@tonic-gate { 3477*7c478bd9Sstevel@tonic-gate dev_info_t *dip = ugenp->ug_dip; 3478*7c478bd9Sstevel@tonic-gate 3479*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3480*7c478bd9Sstevel@tonic-gate "ugen_pm_destroy:"); 3481*7c478bd9Sstevel@tonic-gate 3482*7c478bd9Sstevel@tonic-gate if (ugenp->ug_pm) { 3483*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3484*7c478bd9Sstevel@tonic-gate ugen_pm_busy_component(ugenp); 3485*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 3486*7c478bd9Sstevel@tonic-gate 3487*7c478bd9Sstevel@tonic-gate if ((ugenp->ug_pm->pwr_wakeup_enabled) && 3488*7c478bd9Sstevel@tonic-gate (ugenp->ug_dev_state != USB_DEV_DISCONNECTED)) { 3489*7c478bd9Sstevel@tonic-gate int rval; 3490*7c478bd9Sstevel@tonic-gate 3491*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3492*7c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 3493*7c478bd9Sstevel@tonic-gate 3494*7c478bd9Sstevel@tonic-gate if ((rval = usb_handle_remote_wakeup(dip, 3495*7c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_DISABLE)) != USB_SUCCESS) { 3496*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_PM, 3497*7c478bd9Sstevel@tonic-gate ugenp->ug_log_hdl, "ugen_pm_destroy: " 3498*7c478bd9Sstevel@tonic-gate "disabling rmt wakeup: rval=%d", rval); 3499*7c478bd9Sstevel@tonic-gate } 3500*7c478bd9Sstevel@tonic-gate /* 3501*7c478bd9Sstevel@tonic-gate * Since remote wakeup is disabled now, 3502*7c478bd9Sstevel@tonic-gate * no one can raise power 3503*7c478bd9Sstevel@tonic-gate * and get to device once power is lowered here. 3504*7c478bd9Sstevel@tonic-gate */ 3505*7c478bd9Sstevel@tonic-gate } else { 3506*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3507*7c478bd9Sstevel@tonic-gate } 3508*7c478bd9Sstevel@tonic-gate (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF); 3509*7c478bd9Sstevel@tonic-gate ugen_pm_idle_component(ugenp); 3510*7c478bd9Sstevel@tonic-gate 3511*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 3512*7c478bd9Sstevel@tonic-gate kmem_free(ugenp->ug_pm, sizeof (ugen_power_t)); 3513*7c478bd9Sstevel@tonic-gate ugenp->ug_pm = NULL; 3514*7c478bd9Sstevel@tonic-gate } 3515*7c478bd9Sstevel@tonic-gate } 3516*7c478bd9Sstevel@tonic-gate 3517*7c478bd9Sstevel@tonic-gate 3518*7c478bd9Sstevel@tonic-gate /* 3519*7c478bd9Sstevel@tonic-gate * ugen_power : 3520*7c478bd9Sstevel@tonic-gate * Power entry point, the workhorse behind pm_raise_power, pm_lower_power, 3521*7c478bd9Sstevel@tonic-gate * usb_req_raise_power and usb_req_lower_power. 3522*7c478bd9Sstevel@tonic-gate */ 3523*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3524*7c478bd9Sstevel@tonic-gate int 3525*7c478bd9Sstevel@tonic-gate usb_ugen_power(usb_ugen_hdl_t usb_ugen_hdl, int comp, int level) 3526*7c478bd9Sstevel@tonic-gate { 3527*7c478bd9Sstevel@tonic-gate ugen_power_t *pm; 3528*7c478bd9Sstevel@tonic-gate int rval = USB_FAILURE; 3529*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 3530*7c478bd9Sstevel@tonic-gate (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 3531*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp; 3532*7c478bd9Sstevel@tonic-gate dev_info_t *dip; 3533*7c478bd9Sstevel@tonic-gate 3534*7c478bd9Sstevel@tonic-gate if (usb_ugen_hdl == NULL) { 3535*7c478bd9Sstevel@tonic-gate 3536*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 3537*7c478bd9Sstevel@tonic-gate } 3538*7c478bd9Sstevel@tonic-gate 3539*7c478bd9Sstevel@tonic-gate ugenp = usb_ugen_hdl_impl->hdl_ugenp; 3540*7c478bd9Sstevel@tonic-gate dip = ugenp->ug_dip; 3541*7c478bd9Sstevel@tonic-gate 3542*7c478bd9Sstevel@tonic-gate if (ugenp->ug_pm == NULL) { 3543*7c478bd9Sstevel@tonic-gate 3544*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 3545*7c478bd9Sstevel@tonic-gate } 3546*7c478bd9Sstevel@tonic-gate 3547*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3548*7c478bd9Sstevel@tonic-gate "usb_ugen_power: level=%d", level); 3549*7c478bd9Sstevel@tonic-gate 3550*7c478bd9Sstevel@tonic-gate (void) usb_serialize_access(ugenp->ug_ser_cookie, 3551*7c478bd9Sstevel@tonic-gate USB_WAIT, 0); 3552*7c478bd9Sstevel@tonic-gate /* 3553*7c478bd9Sstevel@tonic-gate * If we are disconnected/suspended, return success. Note that if we 3554*7c478bd9Sstevel@tonic-gate * return failure, bringing down the system will hang when 3555*7c478bd9Sstevel@tonic-gate * PM tries to power up all devices 3556*7c478bd9Sstevel@tonic-gate */ 3557*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 3558*7c478bd9Sstevel@tonic-gate switch (ugenp->ug_dev_state) { 3559*7c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE: 3560*7c478bd9Sstevel@tonic-gate 3561*7c478bd9Sstevel@tonic-gate break; 3562*7c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED: 3563*7c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED: 3564*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RESUME: 3565*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 3566*7c478bd9Sstevel@tonic-gate default: 3567*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3568*7c478bd9Sstevel@tonic-gate "ugen_power: disconnected/suspended " 3569*7c478bd9Sstevel@tonic-gate "dev_state=%d", ugenp->ug_dev_state); 3570*7c478bd9Sstevel@tonic-gate rval = USB_SUCCESS; 3571*7c478bd9Sstevel@tonic-gate 3572*7c478bd9Sstevel@tonic-gate goto done; 3573*7c478bd9Sstevel@tonic-gate } 3574*7c478bd9Sstevel@tonic-gate 3575*7c478bd9Sstevel@tonic-gate pm = ugenp->ug_pm; 3576*7c478bd9Sstevel@tonic-gate 3577*7c478bd9Sstevel@tonic-gate /* Check if we are transitioning to a legal power level */ 3578*7c478bd9Sstevel@tonic-gate if (USB_DEV_PWRSTATE_OK(pm->pwr_states, level)) { 3579*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3580*7c478bd9Sstevel@tonic-gate "ugen_power: illegal power level=%d " 3581*7c478bd9Sstevel@tonic-gate "pwr_states: 0x%x", level, pm->pwr_states); 3582*7c478bd9Sstevel@tonic-gate 3583*7c478bd9Sstevel@tonic-gate goto done; 3584*7c478bd9Sstevel@tonic-gate } 3585*7c478bd9Sstevel@tonic-gate 3586*7c478bd9Sstevel@tonic-gate switch (level) { 3587*7c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_OFF : 3588*7c478bd9Sstevel@tonic-gate switch (ugenp->ug_dev_state) { 3589*7c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE: 3590*7c478bd9Sstevel@tonic-gate /* Deny the powerdown request if the device is busy */ 3591*7c478bd9Sstevel@tonic-gate if (ugenp->ug_pm->pwr_busy != 0) { 3592*7c478bd9Sstevel@tonic-gate 3593*7c478bd9Sstevel@tonic-gate break; 3594*7c478bd9Sstevel@tonic-gate } 3595*7c478bd9Sstevel@tonic-gate ASSERT(ugenp->ug_open_count == 0); 3596*7c478bd9Sstevel@tonic-gate ASSERT(ugenp->ug_pending_cmds == 0); 3597*7c478bd9Sstevel@tonic-gate ugenp->ug_pm->pwr_current = USB_DEV_OS_PWR_OFF; 3598*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3599*7c478bd9Sstevel@tonic-gate 3600*7c478bd9Sstevel@tonic-gate /* Issue USB D3 command to the device here */ 3601*7c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl3(dip); 3602*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 3603*7c478bd9Sstevel@tonic-gate 3604*7c478bd9Sstevel@tonic-gate break; 3605*7c478bd9Sstevel@tonic-gate default: 3606*7c478bd9Sstevel@tonic-gate rval = USB_SUCCESS; 3607*7c478bd9Sstevel@tonic-gate 3608*7c478bd9Sstevel@tonic-gate break; 3609*7c478bd9Sstevel@tonic-gate } 3610*7c478bd9Sstevel@tonic-gate break; 3611*7c478bd9Sstevel@tonic-gate case USB_DEV_OS_FULL_PWR : 3612*7c478bd9Sstevel@tonic-gate /* 3613*7c478bd9Sstevel@tonic-gate * PM framework tries to put us in full power during system 3614*7c478bd9Sstevel@tonic-gate * shutdown. 3615*7c478bd9Sstevel@tonic-gate */ 3616*7c478bd9Sstevel@tonic-gate switch (ugenp->ug_dev_state) { 3617*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RESUME: 3618*7c478bd9Sstevel@tonic-gate case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 3619*7c478bd9Sstevel@tonic-gate 3620*7c478bd9Sstevel@tonic-gate break; 3621*7c478bd9Sstevel@tonic-gate default: 3622*7c478bd9Sstevel@tonic-gate ugenp->ug_dev_state = USB_DEV_ONLINE; 3623*7c478bd9Sstevel@tonic-gate 3624*7c478bd9Sstevel@tonic-gate /* wakeup devstat reads and polls */ 3625*7c478bd9Sstevel@tonic-gate ugen_ds_change(ugenp); 3626*7c478bd9Sstevel@tonic-gate ugen_ds_poll_wakeup(ugenp); 3627*7c478bd9Sstevel@tonic-gate 3628*7c478bd9Sstevel@tonic-gate break; 3629*7c478bd9Sstevel@tonic-gate } 3630*7c478bd9Sstevel@tonic-gate ugenp->ug_pm->pwr_current = USB_DEV_OS_FULL_PWR; 3631*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3632*7c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl0(dip); 3633*7c478bd9Sstevel@tonic-gate mutex_enter(&ugenp->ug_mutex); 3634*7c478bd9Sstevel@tonic-gate 3635*7c478bd9Sstevel@tonic-gate break; 3636*7c478bd9Sstevel@tonic-gate default: 3637*7c478bd9Sstevel@tonic-gate /* Levels 1 and 2 are not supported to keep it simple. */ 3638*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3639*7c478bd9Sstevel@tonic-gate "ugen_power: power level %d not supported", level); 3640*7c478bd9Sstevel@tonic-gate 3641*7c478bd9Sstevel@tonic-gate break; 3642*7c478bd9Sstevel@tonic-gate } 3643*7c478bd9Sstevel@tonic-gate done: 3644*7c478bd9Sstevel@tonic-gate mutex_exit(&ugenp->ug_mutex); 3645*7c478bd9Sstevel@tonic-gate usb_release_access(ugenp->ug_ser_cookie); 3646*7c478bd9Sstevel@tonic-gate 3647*7c478bd9Sstevel@tonic-gate return (rval); 3648*7c478bd9Sstevel@tonic-gate } 3649*7c478bd9Sstevel@tonic-gate 3650*7c478bd9Sstevel@tonic-gate 3651*7c478bd9Sstevel@tonic-gate static void 3652*7c478bd9Sstevel@tonic-gate ugen_pm_busy_component(ugen_state_t *ugen_statep) 3653*7c478bd9Sstevel@tonic-gate { 3654*7c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&ugen_statep->ug_mutex)); 3655*7c478bd9Sstevel@tonic-gate 3656*7c478bd9Sstevel@tonic-gate if (ugen_statep->ug_pm != NULL) { 3657*7c478bd9Sstevel@tonic-gate mutex_enter(&ugen_statep->ug_mutex); 3658*7c478bd9Sstevel@tonic-gate ugen_statep->ug_pm->pwr_busy++; 3659*7c478bd9Sstevel@tonic-gate 3660*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_PM, ugen_statep->ug_log_hdl, 3661*7c478bd9Sstevel@tonic-gate "ugen_pm_busy_component: %d", ugen_statep->ug_pm->pwr_busy); 3662*7c478bd9Sstevel@tonic-gate 3663*7c478bd9Sstevel@tonic-gate mutex_exit(&ugen_statep->ug_mutex); 3664*7c478bd9Sstevel@tonic-gate if (pm_busy_component(ugen_statep->ug_dip, 0) != DDI_SUCCESS) { 3665*7c478bd9Sstevel@tonic-gate mutex_enter(&ugen_statep->ug_mutex); 3666*7c478bd9Sstevel@tonic-gate ugen_statep->ug_pm->pwr_busy--; 3667*7c478bd9Sstevel@tonic-gate 3668*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(UGEN_PRINT_PM, ugen_statep->ug_log_hdl, 3669*7c478bd9Sstevel@tonic-gate "ugen_pm_busy_component failed: %d", 3670*7c478bd9Sstevel@tonic-gate ugen_statep->ug_pm->pwr_busy); 3671*7c478bd9Sstevel@tonic-gate 3672*7c478bd9Sstevel@tonic-gate mutex_exit(&ugen_statep->ug_mutex); 3673*7c478bd9Sstevel@tonic-gate } 3674*7c478bd9Sstevel@tonic-gate } 3675*7c478bd9Sstevel@tonic-gate } 3676*7c478bd9Sstevel@tonic-gate 3677*7c478bd9Sstevel@tonic-gate 3678*7c478bd9Sstevel@tonic-gate static void 3679*7c478bd9Sstevel@tonic-gate ugen_pm_idle_component(ugen_state_t *ugen_statep) 3680*7c478bd9Sstevel@tonic-gate { 3681*7c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&ugen_statep->ug_mutex)); 3682*7c478bd9Sstevel@tonic-gate 3683*7c478bd9Sstevel@tonic-gate if (ugen_statep->ug_pm != NULL) { 3684*7c478bd9Sstevel@tonic-gate if (pm_idle_component(ugen_statep->ug_dip, 0) == DDI_SUCCESS) { 3685*7c478bd9Sstevel@tonic-gate mutex_enter(&ugen_statep->ug_mutex); 3686*7c478bd9Sstevel@tonic-gate ASSERT(ugen_statep->ug_pm->pwr_busy > 0); 3687*7c478bd9Sstevel@tonic-gate ugen_statep->ug_pm->pwr_busy--; 3688*7c478bd9Sstevel@tonic-gate 3689*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(UGEN_PRINT_PM, ugen_statep->ug_log_hdl, 3690*7c478bd9Sstevel@tonic-gate "ugen_pm_idle_component: %d", 3691*7c478bd9Sstevel@tonic-gate ugen_statep->ug_pm->pwr_busy); 3692*7c478bd9Sstevel@tonic-gate 3693*7c478bd9Sstevel@tonic-gate mutex_exit(&ugen_statep->ug_mutex); 3694*7c478bd9Sstevel@tonic-gate } 3695*7c478bd9Sstevel@tonic-gate } 3696*7c478bd9Sstevel@tonic-gate } 3697*7c478bd9Sstevel@tonic-gate 3698*7c478bd9Sstevel@tonic-gate 3699*7c478bd9Sstevel@tonic-gate /* 3700*7c478bd9Sstevel@tonic-gate * devt lookup support 3701*7c478bd9Sstevel@tonic-gate * In ugen_strategy and ugen_minphys, we only have the devt and need 3702*7c478bd9Sstevel@tonic-gate * the ugen_state pointer. Since we don't know instance mask, we can't 3703*7c478bd9Sstevel@tonic-gate * easily derive a softstate pointer. Therefore, we use a list 3704*7c478bd9Sstevel@tonic-gate */ 3705*7c478bd9Sstevel@tonic-gate static void 3706*7c478bd9Sstevel@tonic-gate ugen_store_devt(ugen_state_t *ugenp, minor_t minor) 3707*7c478bd9Sstevel@tonic-gate { 3708*7c478bd9Sstevel@tonic-gate ugen_devt_list_entry_t *e = kmem_zalloc( 3709*7c478bd9Sstevel@tonic-gate sizeof (ugen_devt_list_entry_t), KM_SLEEP); 3710*7c478bd9Sstevel@tonic-gate ugen_devt_list_entry_t *t; 3711*7c478bd9Sstevel@tonic-gate 3712*7c478bd9Sstevel@tonic-gate mutex_enter(&ugen_devt_list_mutex); 3713*7c478bd9Sstevel@tonic-gate e->list_dev = makedevice(ddi_driver_major(ugenp->ug_dip), minor); 3714*7c478bd9Sstevel@tonic-gate e->list_state = ugenp; 3715*7c478bd9Sstevel@tonic-gate 3716*7c478bd9Sstevel@tonic-gate t = ugen_devt_list.list_next; 3717*7c478bd9Sstevel@tonic-gate 3718*7c478bd9Sstevel@tonic-gate /* check if the entry is already in the list */ 3719*7c478bd9Sstevel@tonic-gate while (t) { 3720*7c478bd9Sstevel@tonic-gate ASSERT(t->list_dev != e->list_dev); 3721*7c478bd9Sstevel@tonic-gate t = t->list_next; 3722*7c478bd9Sstevel@tonic-gate } 3723*7c478bd9Sstevel@tonic-gate 3724*7c478bd9Sstevel@tonic-gate /* add to the head of the list */ 3725*7c478bd9Sstevel@tonic-gate e->list_next = ugen_devt_list.list_next; 3726*7c478bd9Sstevel@tonic-gate if (ugen_devt_list.list_next) { 3727*7c478bd9Sstevel@tonic-gate ugen_devt_list.list_next->list_prev = e; 3728*7c478bd9Sstevel@tonic-gate } 3729*7c478bd9Sstevel@tonic-gate ugen_devt_list.list_next = e; 3730*7c478bd9Sstevel@tonic-gate mutex_exit(&ugen_devt_list_mutex); 3731*7c478bd9Sstevel@tonic-gate } 3732*7c478bd9Sstevel@tonic-gate 3733*7c478bd9Sstevel@tonic-gate 3734*7c478bd9Sstevel@tonic-gate static ugen_state_t * 3735*7c478bd9Sstevel@tonic-gate ugen_devt2state(dev_t dev) 3736*7c478bd9Sstevel@tonic-gate { 3737*7c478bd9Sstevel@tonic-gate ugen_devt_list_entry_t *t; 3738*7c478bd9Sstevel@tonic-gate ugen_state_t *ugenp = NULL; 3739*7c478bd9Sstevel@tonic-gate int index, count; 3740*7c478bd9Sstevel@tonic-gate 3741*7c478bd9Sstevel@tonic-gate mutex_enter(&ugen_devt_list_mutex); 3742*7c478bd9Sstevel@tonic-gate 3743*7c478bd9Sstevel@tonic-gate for (index = ugen_devt_cache_index, count = 0; 3744*7c478bd9Sstevel@tonic-gate count < UGEN_DEVT_CACHE_SIZE; count++) { 3745*7c478bd9Sstevel@tonic-gate if (ugen_devt_cache[index].cache_dev == dev) { 3746*7c478bd9Sstevel@tonic-gate ugen_devt_cache[index].cache_hit++; 3747*7c478bd9Sstevel@tonic-gate ugenp = ugen_devt_cache[index].cache_state; 3748*7c478bd9Sstevel@tonic-gate 3749*7c478bd9Sstevel@tonic-gate mutex_exit(&ugen_devt_list_mutex); 3750*7c478bd9Sstevel@tonic-gate 3751*7c478bd9Sstevel@tonic-gate return (ugenp); 3752*7c478bd9Sstevel@tonic-gate } 3753*7c478bd9Sstevel@tonic-gate index++; 3754*7c478bd9Sstevel@tonic-gate index %= UGEN_DEVT_CACHE_SIZE; 3755*7c478bd9Sstevel@tonic-gate } 3756*7c478bd9Sstevel@tonic-gate 3757*7c478bd9Sstevel@tonic-gate t = ugen_devt_list.list_next; 3758*7c478bd9Sstevel@tonic-gate 3759*7c478bd9Sstevel@tonic-gate while (t) { 3760*7c478bd9Sstevel@tonic-gate if (t->list_dev == dev) { 3761*7c478bd9Sstevel@tonic-gate ugenp = t->list_state; 3762*7c478bd9Sstevel@tonic-gate ugen_devt_cache_index++; 3763*7c478bd9Sstevel@tonic-gate ugen_devt_cache_index %= UGEN_DEVT_CACHE_SIZE; 3764*7c478bd9Sstevel@tonic-gate ugen_devt_cache[ugen_devt_cache_index].cache_dev = dev; 3765*7c478bd9Sstevel@tonic-gate ugen_devt_cache[ugen_devt_cache_index].cache_state = 3766*7c478bd9Sstevel@tonic-gate ugenp; 3767*7c478bd9Sstevel@tonic-gate mutex_exit(&ugen_devt_list_mutex); 3768*7c478bd9Sstevel@tonic-gate 3769*7c478bd9Sstevel@tonic-gate return (ugenp); 3770*7c478bd9Sstevel@tonic-gate } 3771*7c478bd9Sstevel@tonic-gate t = t->list_next; 3772*7c478bd9Sstevel@tonic-gate } 3773*7c478bd9Sstevel@tonic-gate mutex_exit(&ugen_devt_list_mutex); 3774*7c478bd9Sstevel@tonic-gate 3775*7c478bd9Sstevel@tonic-gate return (ugenp); 3776*7c478bd9Sstevel@tonic-gate } 3777*7c478bd9Sstevel@tonic-gate 3778*7c478bd9Sstevel@tonic-gate 3779*7c478bd9Sstevel@tonic-gate static void 3780*7c478bd9Sstevel@tonic-gate ugen_free_devt(ugen_state_t *ugenp) 3781*7c478bd9Sstevel@tonic-gate { 3782*7c478bd9Sstevel@tonic-gate ugen_devt_list_entry_t *e, *next, *prev; 3783*7c478bd9Sstevel@tonic-gate major_t major = ddi_driver_major(ugenp->ug_dip); 3784*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(ugenp->ug_dip); 3785*7c478bd9Sstevel@tonic-gate 3786*7c478bd9Sstevel@tonic-gate mutex_enter(&ugen_devt_list_mutex); 3787*7c478bd9Sstevel@tonic-gate prev = &ugen_devt_list; 3788*7c478bd9Sstevel@tonic-gate for (e = prev->list_next; e != 0; e = next) { 3789*7c478bd9Sstevel@tonic-gate int i = (getminor(e->list_dev) & 3790*7c478bd9Sstevel@tonic-gate ugenp->ug_hdl->hdl_minor_node_instance_mask) >> 3791*7c478bd9Sstevel@tonic-gate ugenp->ug_hdl->hdl_minor_node_instance_shift; 3792*7c478bd9Sstevel@tonic-gate int m = getmajor(e->list_dev); 3793*7c478bd9Sstevel@tonic-gate 3794*7c478bd9Sstevel@tonic-gate next = e->list_next; 3795*7c478bd9Sstevel@tonic-gate 3796*7c478bd9Sstevel@tonic-gate if ((i == instance) && (m == major)) { 3797*7c478bd9Sstevel@tonic-gate prev->list_next = e->list_next; 3798*7c478bd9Sstevel@tonic-gate if (e->list_next) { 3799*7c478bd9Sstevel@tonic-gate e->list_next->list_prev = prev; 3800*7c478bd9Sstevel@tonic-gate } 3801*7c478bd9Sstevel@tonic-gate kmem_free(e, sizeof (ugen_devt_list_entry_t)); 3802*7c478bd9Sstevel@tonic-gate } else { 3803*7c478bd9Sstevel@tonic-gate prev = e; 3804*7c478bd9Sstevel@tonic-gate } 3805*7c478bd9Sstevel@tonic-gate } 3806*7c478bd9Sstevel@tonic-gate 3807*7c478bd9Sstevel@tonic-gate bzero(ugen_devt_cache, sizeof (ugen_devt_cache)); 3808*7c478bd9Sstevel@tonic-gate ugen_devt_cache_index = 0; 3809*7c478bd9Sstevel@tonic-gate mutex_exit(&ugen_devt_list_mutex); 3810*7c478bd9Sstevel@tonic-gate } 3811