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 /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Sample skeleton USB driver. 31*7c478bd9Sstevel@tonic-gate * This driver provides a framework for developing USB client drivers. 32*7c478bd9Sstevel@tonic-gate * 33*7c478bd9Sstevel@tonic-gate * As a simplistic example, usbskel implements a data transfer by reading 34*7c478bd9Sstevel@tonic-gate * raw configuration data, which every USB device has. It is expected that 35*7c478bd9Sstevel@tonic-gate * the caller will issue an initial 4-byte read to get the total length of the 36*7c478bd9Sstevel@tonic-gate * first configuration, and follow up with a second read, passing the total 37*7c478bd9Sstevel@tonic-gate * length to read the entire configuration cloud. 38*7c478bd9Sstevel@tonic-gate * 39*7c478bd9Sstevel@tonic-gate * The device has four states (refer to usbai.h): 40*7c478bd9Sstevel@tonic-gate * USB_DEV_ONLINE: In action or ready for action. 41*7c478bd9Sstevel@tonic-gate * USB_DEV_DISCONNECTED: Hotplug removed, or device not present/correct on 42*7c478bd9Sstevel@tonic-gate * resume (CPR). 43*7c478bd9Sstevel@tonic-gate * USB_DEV_SUSPENDED: Device has been suspended along with the system. 44*7c478bd9Sstevel@tonic-gate * USB_DEV_PWRED_DOWN: Device has been powered down. (Note that this 45*7c478bd9Sstevel@tonic-gate * driver supports only two power states, powered down and 46*7c478bd9Sstevel@tonic-gate * full power.) 47*7c478bd9Sstevel@tonic-gate * 48*7c478bd9Sstevel@tonic-gate * In order to avoid race conditions between driver entry points, 49*7c478bd9Sstevel@tonic-gate * access to the device is serialized. Race conditions are an issue in 50*7c478bd9Sstevel@tonic-gate * particular between disconnect event callbacks, detach, power, open 51*7c478bd9Sstevel@tonic-gate * and data transfer callbacks. The functions usbskel_serialize/release_access 52*7c478bd9Sstevel@tonic-gate * are implemented for this purpose. 53*7c478bd9Sstevel@tonic-gate * 54*7c478bd9Sstevel@tonic-gate * Mutexes should never be held when making calls into USBA or when 55*7c478bd9Sstevel@tonic-gate * sleeping. 56*7c478bd9Sstevel@tonic-gate * 57*7c478bd9Sstevel@tonic-gate * pm_busy_component and pm_idle_component mark the device as busy or idle to 58*7c478bd9Sstevel@tonic-gate * the system. These functions are paired, and are called only from code 59*7c478bd9Sstevel@tonic-gate * bracketed by usbskel_serialize_access and usbskel_release_access. 60*7c478bd9Sstevel@tonic-gate * 61*7c478bd9Sstevel@tonic-gate * NOTE: PM and CPR will be enabled at a later release of S10. 62*7c478bd9Sstevel@tonic-gate */ 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG) 65*7c478bd9Sstevel@tonic-gate #define DEBUG 66*7c478bd9Sstevel@tonic-gate #endif 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate #define USBDRV_MAJOR_VER 2 69*7c478bd9Sstevel@tonic-gate #define USBDRV_MINOR_VER 0 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate /* Uncomment to enable Power Management, when the OS PM framework is ready. */ 72*7c478bd9Sstevel@tonic-gate /* 73*7c478bd9Sstevel@tonic-gate * #ifndef USBSKEL_PM 74*7c478bd9Sstevel@tonic-gate * #define USBSKEL_PM 75*7c478bd9Sstevel@tonic-gate * #endif 76*7c478bd9Sstevel@tonic-gate */ 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate /* 79*7c478bd9Sstevel@tonic-gate * Uncomment to enable Check Point Resume (system suspend and resume) when the 80*7c478bd9Sstevel@tonic-gate * OS CPR framework is ready. 81*7c478bd9Sstevel@tonic-gate */ 82*7c478bd9Sstevel@tonic-gate /* 83*7c478bd9Sstevel@tonic-gate * #ifndef USBSKEL_CPR 84*7c478bd9Sstevel@tonic-gate * #define USBSKEL_CPR 85*7c478bd9Sstevel@tonic-gate * #endif 86*7c478bd9Sstevel@tonic-gate */ 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h> 89*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_private.h> 90*7c478bd9Sstevel@tonic-gate #include <sys/usb/clients/usbskel/usbskel.h> 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate static int usbskel_errlevel = USBSKEL_LOG_LOG; 93*7c478bd9Sstevel@tonic-gate static char *name = "usbskl"; /* Driver name, used all over. */ 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate /* 96*7c478bd9Sstevel@tonic-gate * Boolean set to whether or not to dump the device's descriptor tree. 97*7c478bd9Sstevel@tonic-gate * Can be changed with the usblog_dumptree property in a usbskel.conf file. 98*7c478bd9Sstevel@tonic-gate */ 99*7c478bd9Sstevel@tonic-gate static boolean_t usbskel_dumptree; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate /* 102*7c478bd9Sstevel@tonic-gate * Function Prototypes 103*7c478bd9Sstevel@tonic-gate */ 104*7c478bd9Sstevel@tonic-gate static int usbskel_attach(dev_info_t *, ddi_attach_cmd_t); 105*7c478bd9Sstevel@tonic-gate static int usbskel_detach(dev_info_t *, ddi_detach_cmd_t); 106*7c478bd9Sstevel@tonic-gate static int usbskel_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 107*7c478bd9Sstevel@tonic-gate static int usbskel_cleanup(dev_info_t *, usbskel_state_t *); 108*7c478bd9Sstevel@tonic-gate static int usbskel_open(dev_t *, int, int, cred_t *); 109*7c478bd9Sstevel@tonic-gate static int usbskel_close(dev_t, int, int, cred_t *); 110*7c478bd9Sstevel@tonic-gate static int usbskel_read(dev_t, struct uio *uip_p, cred_t *); 111*7c478bd9Sstevel@tonic-gate static int usbskel_strategy(struct buf *); 112*7c478bd9Sstevel@tonic-gate static void usbskel_minphys(struct buf *); 113*7c478bd9Sstevel@tonic-gate static void usbskel_normal_callback(usb_pipe_handle_t, usb_ctrl_req_t *); 114*7c478bd9Sstevel@tonic-gate static void usbskel_exception_callback(usb_pipe_handle_t, usb_ctrl_req_t *); 115*7c478bd9Sstevel@tonic-gate static int usbskel_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 116*7c478bd9Sstevel@tonic-gate static int usbskel_disconnect_callback(dev_info_t *); 117*7c478bd9Sstevel@tonic-gate static int usbskel_reconnect_callback(dev_info_t *); 118*7c478bd9Sstevel@tonic-gate static void usbskel_restore_device_state(dev_info_t *, usbskel_state_t *); 119*7c478bd9Sstevel@tonic-gate static int usbskel_cpr_suspend(dev_info_t *); 120*7c478bd9Sstevel@tonic-gate static void usbskel_cpr_resume(dev_info_t *); 121*7c478bd9Sstevel@tonic-gate static int usbskel_test_and_adjust_device_state(usbskel_state_t *); 122*7c478bd9Sstevel@tonic-gate static int usbskel_open_pipes(usbskel_state_t *); 123*7c478bd9Sstevel@tonic-gate static void usbskel_close_pipes(usbskel_state_t *); 124*7c478bd9Sstevel@tonic-gate static int usbskel_pm_busy_component(usbskel_state_t *); 125*7c478bd9Sstevel@tonic-gate static void usbskel_pm_idle_component(usbskel_state_t *); 126*7c478bd9Sstevel@tonic-gate static int usbskel_power(dev_info_t *, int, int); 127*7c478bd9Sstevel@tonic-gate #ifdef USBSKEL_PM 128*7c478bd9Sstevel@tonic-gate static int usbskel_init_power_mgmt(usbskel_state_t *); 129*7c478bd9Sstevel@tonic-gate static void usbskel_destroy_power_mgmt(usbskel_state_t *); 130*7c478bd9Sstevel@tonic-gate #endif 131*7c478bd9Sstevel@tonic-gate static int usbskel_serialize_access(usbskel_state_t *, boolean_t); 132*7c478bd9Sstevel@tonic-gate static void usbskel_release_access(usbskel_state_t *); 133*7c478bd9Sstevel@tonic-gate static int usbskel_check_same_device(usbskel_state_t *); 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/ 136*7c478bd9Sstevel@tonic-gate static void usbskel_log(usbskel_state_t *, int, char *, ...); 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate /* _NOTE is an advice for locklint. Locklint checks lock use for deadlocks. */ 139*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req)) 140*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", buf)) 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* module loading stuff */ 143*7c478bd9Sstevel@tonic-gate struct cb_ops usbskel_cb_ops = { 144*7c478bd9Sstevel@tonic-gate usbskel_open, /* open */ 145*7c478bd9Sstevel@tonic-gate usbskel_close, /* close */ 146*7c478bd9Sstevel@tonic-gate usbskel_strategy, /* strategy */ 147*7c478bd9Sstevel@tonic-gate nulldev, /* print */ 148*7c478bd9Sstevel@tonic-gate nulldev, /* dump */ 149*7c478bd9Sstevel@tonic-gate usbskel_read, /* read */ 150*7c478bd9Sstevel@tonic-gate nodev, /* write */ 151*7c478bd9Sstevel@tonic-gate usbskel_ioctl, /* ioctl */ 152*7c478bd9Sstevel@tonic-gate nulldev, /* devmap */ 153*7c478bd9Sstevel@tonic-gate nodev, /* mmap */ 154*7c478bd9Sstevel@tonic-gate nodev, /* segmap */ 155*7c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 156*7c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 157*7c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 158*7c478bd9Sstevel@tonic-gate D_MP 159*7c478bd9Sstevel@tonic-gate }; 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate static struct dev_ops usbskel_ops = { 162*7c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 163*7c478bd9Sstevel@tonic-gate 0, /* refcnt */ 164*7c478bd9Sstevel@tonic-gate usbskel_info, /* info */ 165*7c478bd9Sstevel@tonic-gate nulldev, /* identify */ 166*7c478bd9Sstevel@tonic-gate nulldev, /* probe */ 167*7c478bd9Sstevel@tonic-gate usbskel_attach, /* attach */ 168*7c478bd9Sstevel@tonic-gate usbskel_detach, /* detach */ 169*7c478bd9Sstevel@tonic-gate nodev, /* reset */ 170*7c478bd9Sstevel@tonic-gate &usbskel_cb_ops, /* driver operations */ 171*7c478bd9Sstevel@tonic-gate NULL, /* bus operations */ 172*7c478bd9Sstevel@tonic-gate usbskel_power /* power */ 173*7c478bd9Sstevel@tonic-gate }; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate static struct modldrv usbskel_modldrv = { 176*7c478bd9Sstevel@tonic-gate &mod_driverops, 177*7c478bd9Sstevel@tonic-gate "USB skeleton driver %I%", 178*7c478bd9Sstevel@tonic-gate &usbskel_ops 179*7c478bd9Sstevel@tonic-gate }; 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 182*7c478bd9Sstevel@tonic-gate MODREV_1, 183*7c478bd9Sstevel@tonic-gate &usbskel_modldrv, 184*7c478bd9Sstevel@tonic-gate NULL 185*7c478bd9Sstevel@tonic-gate }; 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate /* event support */ 188*7c478bd9Sstevel@tonic-gate static usb_event_t usbskel_events = { 189*7c478bd9Sstevel@tonic-gate usbskel_disconnect_callback, 190*7c478bd9Sstevel@tonic-gate usbskel_reconnect_callback, 191*7c478bd9Sstevel@tonic-gate NULL, NULL 192*7c478bd9Sstevel@tonic-gate }; 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate /* local variables */ 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate /* Soft state structures */ 197*7c478bd9Sstevel@tonic-gate #define USBSKEL_INITIAL_SOFT_SPACE 1 198*7c478bd9Sstevel@tonic-gate static void *usbskel_statep; 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* 202*7c478bd9Sstevel@tonic-gate * Module-wide initialization routine. 203*7c478bd9Sstevel@tonic-gate */ 204*7c478bd9Sstevel@tonic-gate int 205*7c478bd9Sstevel@tonic-gate _init(void) 206*7c478bd9Sstevel@tonic-gate { 207*7c478bd9Sstevel@tonic-gate int rval; 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _init"); 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate if ((rval = ddi_soft_state_init(&usbskel_statep, 212*7c478bd9Sstevel@tonic-gate sizeof (usbskel_state_t), USBSKEL_INITIAL_SOFT_SPACE)) != 0) { 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate return (rval); 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate if ((rval = mod_install(&modlinkage)) != 0) { 218*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&usbskel_statep); 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _init done"); 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate return (rval); 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate /* 228*7c478bd9Sstevel@tonic-gate * Module-wide tear-down routine. 229*7c478bd9Sstevel@tonic-gate */ 230*7c478bd9Sstevel@tonic-gate int 231*7c478bd9Sstevel@tonic-gate _fini(void) 232*7c478bd9Sstevel@tonic-gate { 233*7c478bd9Sstevel@tonic-gate int rval; 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _fini"); 236*7c478bd9Sstevel@tonic-gate if ((rval = mod_remove(&modlinkage)) != 0) { 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate return (rval); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&usbskel_statep); 242*7c478bd9Sstevel@tonic-gate usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _fini done"); 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate return (rval); 245*7c478bd9Sstevel@tonic-gate } 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate int 249*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 250*7c478bd9Sstevel@tonic-gate { 251*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate /* 256*7c478bd9Sstevel@tonic-gate * usbskel_info: 257*7c478bd9Sstevel@tonic-gate * Get minor number, soft state structure, etc. 258*7c478bd9Sstevel@tonic-gate */ 259*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 260*7c478bd9Sstevel@tonic-gate static int 261*7c478bd9Sstevel@tonic-gate usbskel_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 262*7c478bd9Sstevel@tonic-gate void *arg, void **result) 263*7c478bd9Sstevel@tonic-gate { 264*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp; 265*7c478bd9Sstevel@tonic-gate int error = DDI_FAILURE; 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate switch (infocmd) { 268*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 269*7c478bd9Sstevel@tonic-gate if ((usbskelp = ddi_get_soft_state(usbskel_statep, 270*7c478bd9Sstevel@tonic-gate getminor((dev_t)arg))) != NULL) { 271*7c478bd9Sstevel@tonic-gate *result = usbskelp->usbskel_dip; 272*7c478bd9Sstevel@tonic-gate if (*result != NULL) { 273*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate } else { 276*7c478bd9Sstevel@tonic-gate *result = NULL; 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate break; 279*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 280*7c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)getminor((dev_t)arg); 281*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 282*7c478bd9Sstevel@tonic-gate break; 283*7c478bd9Sstevel@tonic-gate default: 284*7c478bd9Sstevel@tonic-gate break; 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate return (error); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate /* 292*7c478bd9Sstevel@tonic-gate * usbskel_attach: 293*7c478bd9Sstevel@tonic-gate * Attach or resume. 294*7c478bd9Sstevel@tonic-gate * 295*7c478bd9Sstevel@tonic-gate * For attach, initialize state and device, including: 296*7c478bd9Sstevel@tonic-gate * state variables, locks, device node 297*7c478bd9Sstevel@tonic-gate * device registration with system 298*7c478bd9Sstevel@tonic-gate * power management, hotplugging 299*7c478bd9Sstevel@tonic-gate * For resume, restore device and state 300*7c478bd9Sstevel@tonic-gate */ 301*7c478bd9Sstevel@tonic-gate static int 302*7c478bd9Sstevel@tonic-gate usbskel_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 303*7c478bd9Sstevel@tonic-gate { 304*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 305*7c478bd9Sstevel@tonic-gate char *devinst; 306*7c478bd9Sstevel@tonic-gate int devinstlen; 307*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = NULL; 308*7c478bd9Sstevel@tonic-gate usb_reg_parse_lvl_t parse_level; 309*7c478bd9Sstevel@tonic-gate usb_ep_data_t *ep_datap; 310*7c478bd9Sstevel@tonic-gate int status; 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate switch (cmd) { 313*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 314*7c478bd9Sstevel@tonic-gate break; 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate case DDI_RESUME: 317*7c478bd9Sstevel@tonic-gate usbskel_cpr_resume(dip); 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate /* 320*7c478bd9Sstevel@tonic-gate * Always return success to work around enumeration failures. 321*7c478bd9Sstevel@tonic-gate * This works around an issue where devices which are present 322*7c478bd9Sstevel@tonic-gate * before a suspend and absent upon resume could cause a system 323*7c478bd9Sstevel@tonic-gate * panic on resume. 324*7c478bd9Sstevel@tonic-gate */ 325*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 326*7c478bd9Sstevel@tonic-gate default: 327*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(usbskel_statep, instance) == DDI_SUCCESS) { 331*7c478bd9Sstevel@tonic-gate usbskelp = ddi_get_soft_state(usbskel_statep, instance); 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate if (usbskelp == NULL) { 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip = dip; 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate devinst = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 341*7c478bd9Sstevel@tonic-gate devinstlen = snprintf(devinst, USB_MAXSTRINGLEN, "%s%d: ", 342*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), instance); 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP); 345*7c478bd9Sstevel@tonic-gate (void) strncpy(usbskelp->usbskel_devinst, devinst, devinstlen); 346*7c478bd9Sstevel@tonic-gate kmem_free(devinst, USB_MAXSTRINGLEN); 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "Attach: enter for attach"); 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate usbskel_dumptree = (ddi_prop_exists(DDI_DEV_T_ANY, dip, 351*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "usbskel_dumptree") == 1); 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "Tree will %sbe dumped", 354*7c478bd9Sstevel@tonic-gate ((usbskel_dumptree) ? "" : "not ")); 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate parse_level = (usb_reg_parse_lvl_t)ddi_prop_get_int( 357*7c478bd9Sstevel@tonic-gate DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 358*7c478bd9Sstevel@tonic-gate "usbskel_parse_level", USB_PARSE_LVL_ALL); 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate switch (parse_level) { 361*7c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_NONE: 362*7c478bd9Sstevel@tonic-gate /* This driver needs a tree. */ 363*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 364*7c478bd9Sstevel@tonic-gate "parse_level requested to NOT DUMP"); 365*7c478bd9Sstevel@tonic-gate parse_level = USB_PARSE_LVL_IF; 366*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 367*7c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_IF: 368*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 369*7c478bd9Sstevel@tonic-gate "parse_level set to dump specific interface"); 370*7c478bd9Sstevel@tonic-gate break; 371*7c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_CFG: 372*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 373*7c478bd9Sstevel@tonic-gate "parse_level set to dump specific config"); 374*7c478bd9Sstevel@tonic-gate break; 375*7c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_ALL: 376*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 377*7c478bd9Sstevel@tonic-gate "parse_level set to dump everything"); 378*7c478bd9Sstevel@tonic-gate break; 379*7c478bd9Sstevel@tonic-gate default: 380*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 381*7c478bd9Sstevel@tonic-gate "attach: parse_level will default to dump everything"); 382*7c478bd9Sstevel@tonic-gate parse_level = USB_PARSE_LVL_ALL; 383*7c478bd9Sstevel@tonic-gate } 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) != 386*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 387*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 388*7c478bd9Sstevel@tonic-gate "attach: usb_client_attach failed, error code:%d", status); 389*7c478bd9Sstevel@tonic-gate goto fail; 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate if ((status = usb_get_dev_data(dip, &usbskelp->usbskel_reg, parse_level, 393*7c478bd9Sstevel@tonic-gate 0)) != USB_SUCCESS) { 394*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 395*7c478bd9Sstevel@tonic-gate "attach: usb_get_dev_data failed, error code:%d", status); 396*7c478bd9Sstevel@tonic-gate goto fail; 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate if (usbskel_dumptree) { 400*7c478bd9Sstevel@tonic-gate (void) usb_print_descr_tree( 401*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, usbskelp->usbskel_reg); 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate /* 405*7c478bd9Sstevel@tonic-gate * Get the descriptor for an intr pipe at alt 0 of current interface. 406*7c478bd9Sstevel@tonic-gate * This will be used later to open the pipe. 407*7c478bd9Sstevel@tonic-gate */ 408*7c478bd9Sstevel@tonic-gate if ((ep_datap = usb_lookup_ep_data(dip, usbskelp->usbskel_reg, 409*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_reg->dev_curr_if, 0, 0, 410*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR, USB_EP_DIR_IN)) == NULL) { 411*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 412*7c478bd9Sstevel@tonic-gate "attach: Error getting intr endpoint descriptor"); 413*7c478bd9Sstevel@tonic-gate goto fail; 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_intr_ep_descr = ep_datap->ep_descr; 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate usb_free_descr_tree(dip, usbskelp->usbskel_reg); 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate mutex_init(&usbskelp->usbskel_mutex, NULL, MUTEX_DRIVER, 420*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_reg->dev_iblock_cookie); 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate cv_init(&usbskelp->usbskel_serial_cv, NULL, CV_DRIVER, NULL); 423*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_serial_inuse = B_FALSE; 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_locks_initialized = B_TRUE; 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate /* create minor node */ 428*7c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, name, S_IFCHR, instance, 429*7c478bd9Sstevel@tonic-gate "usb_skeleton", 0) != DDI_SUCCESS) { 430*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 431*7c478bd9Sstevel@tonic-gate "attach: Error creating minor node"); 432*7c478bd9Sstevel@tonic-gate goto fail; 433*7c478bd9Sstevel@tonic-gate } 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate /* Put online before PM init as can get power managed afterward. */ 436*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_ONLINE; 437*7c478bd9Sstevel@tonic-gate 438*7c478bd9Sstevel@tonic-gate #ifdef USBSKEL_PM 439*7c478bd9Sstevel@tonic-gate /* initialize power management */ 440*7c478bd9Sstevel@tonic-gate if (usbskel_init_power_mgmt(usbskelp) != USB_SUCCESS) { 441*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 442*7c478bd9Sstevel@tonic-gate "attach: Could not initialize power mgmt"); 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate #endif 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate if (usb_register_hotplug_cbs(dip, usbskel_disconnect_callback, 447*7c478bd9Sstevel@tonic-gate usbskel_reconnect_callback) != USB_SUCCESS) { 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate goto fail; 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate /* Report device */ 453*7c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate fail: 458*7c478bd9Sstevel@tonic-gate if (usbskelp) { 459*7c478bd9Sstevel@tonic-gate (void) usbskel_cleanup(dip, usbskelp); 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate /* 467*7c478bd9Sstevel@tonic-gate * usbskel_detach: 468*7c478bd9Sstevel@tonic-gate * detach or suspend driver instance 469*7c478bd9Sstevel@tonic-gate * 470*7c478bd9Sstevel@tonic-gate * Note: in detach, only contention threads is from pm and disconnnect. 471*7c478bd9Sstevel@tonic-gate */ 472*7c478bd9Sstevel@tonic-gate static int 473*7c478bd9Sstevel@tonic-gate usbskel_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 474*7c478bd9Sstevel@tonic-gate { 475*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 476*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 477*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(usbskel_statep, instance); 478*7c478bd9Sstevel@tonic-gate int rval = DDI_FAILURE; 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate switch (cmd) { 481*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 482*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 483*7c478bd9Sstevel@tonic-gate ASSERT((usbskelp->usbskel_drv_state & USBSKEL_OPEN) == 0); 484*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 487*7c478bd9Sstevel@tonic-gate "Detach: enter for detach"); 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate rval = usbskel_cleanup(dip, usbskelp); 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate break; 492*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 493*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 494*7c478bd9Sstevel@tonic-gate "Detach: enter for suspend"); 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate rval = usbskel_cpr_suspend(dip); 497*7c478bd9Sstevel@tonic-gate default: 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate break; 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 503*7c478bd9Sstevel@tonic-gate } 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate /* 507*7c478bd9Sstevel@tonic-gate * usbskel_cleanup: 508*7c478bd9Sstevel@tonic-gate * clean up the driver state for detach 509*7c478bd9Sstevel@tonic-gate */ 510*7c478bd9Sstevel@tonic-gate static int 511*7c478bd9Sstevel@tonic-gate usbskel_cleanup(dev_info_t *dip, usbskel_state_t *usbskelp) 512*7c478bd9Sstevel@tonic-gate { 513*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "Cleanup: enter"); 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_locks_initialized) { 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate /* This must be done 1st to prevent more events from coming. */ 518*7c478bd9Sstevel@tonic-gate usb_unregister_hotplug_cbs(dip); 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate /* 521*7c478bd9Sstevel@tonic-gate * At this point, no new activity can be initiated. The driver 522*7c478bd9Sstevel@tonic-gate * has disabled hotplug callbacks. The Solaris framework has 523*7c478bd9Sstevel@tonic-gate * disabled new opens on a device being detached, and does not 524*7c478bd9Sstevel@tonic-gate * allow detaching an open device. 525*7c478bd9Sstevel@tonic-gate * 526*7c478bd9Sstevel@tonic-gate * The following ensures that all driver activity has drained. 527*7c478bd9Sstevel@tonic-gate */ 528*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 529*7c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 530*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 531*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate #ifdef USBSKEL_PM 534*7c478bd9Sstevel@tonic-gate /* All device activity has died down. */ 535*7c478bd9Sstevel@tonic-gate usbskel_destroy_power_mgmt(usbskelp); 536*7c478bd9Sstevel@tonic-gate #endif 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate /* start dismantling */ 539*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate cv_destroy(&usbskelp->usbskel_serial_cv); 542*7c478bd9Sstevel@tonic-gate mutex_destroy(&usbskelp->usbskel_mutex); 543*7c478bd9Sstevel@tonic-gate } 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate usb_client_detach(dip, usbskelp->usbskel_reg); 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_devinst != NULL) { 548*7c478bd9Sstevel@tonic-gate kmem_free(usbskelp->usbskel_devinst, 549*7c478bd9Sstevel@tonic-gate strlen(usbskelp->usbskel_devinst) + 1); 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(usbskel_statep, ddi_get_instance(dip)); 553*7c478bd9Sstevel@tonic-gate ddi_prop_remove_all(dip); 554*7c478bd9Sstevel@tonic-gate 555*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 560*7c478bd9Sstevel@tonic-gate static int 561*7c478bd9Sstevel@tonic-gate usbskel_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 562*7c478bd9Sstevel@tonic-gate { 563*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 564*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(usbskel_statep, getminor(*devp)); 565*7c478bd9Sstevel@tonic-gate int rval = 0; 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate if (usbskelp == NULL) { 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate return (ENXIO); 570*7c478bd9Sstevel@tonic-gate } 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "open: enter"); 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate /* 575*7c478bd9Sstevel@tonic-gate * Keep it simple: one client at a time. 576*7c478bd9Sstevel@tonic-gate * Exclusive open only 577*7c478bd9Sstevel@tonic-gate */ 578*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 579*7c478bd9Sstevel@tonic-gate if ((usbskelp->usbskel_drv_state & USBSKEL_OPEN) != 0) { 580*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate return (EBUSY); 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_drv_state |= USBSKEL_OPEN; 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate /* 587*7c478bd9Sstevel@tonic-gate * This is in place so that a disconnect or CPR doesn't interfere with 588*7c478bd9Sstevel@tonic-gate * pipe opens. 589*7c478bd9Sstevel@tonic-gate */ 590*7c478bd9Sstevel@tonic-gate if (usbskel_serialize_access(usbskelp, USBSKEL_SER_SIG) == 0) { 591*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_drv_state &= ~USBSKEL_OPEN; 592*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate return (EINTR); 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 598*7c478bd9Sstevel@tonic-gate if (usbskel_pm_busy_component(usbskelp) != DDI_SUCCESS) { 599*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 600*7c478bd9Sstevel@tonic-gate "open: Error raising power"); 601*7c478bd9Sstevel@tonic-gate rval = EIO; 602*7c478bd9Sstevel@tonic-gate goto done; 603*7c478bd9Sstevel@tonic-gate } 604*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate /* Fail if device is no longer ready. */ 607*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_dev_state != USB_DEV_ONLINE) { 608*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 609*7c478bd9Sstevel@tonic-gate rval = EIO; 610*7c478bd9Sstevel@tonic-gate goto done; 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 614*7c478bd9Sstevel@tonic-gate if (usbskel_open_pipes(usbskelp) != USB_SUCCESS) { 615*7c478bd9Sstevel@tonic-gate rval = EIO; 616*7c478bd9Sstevel@tonic-gate goto done; 617*7c478bd9Sstevel@tonic-gate } 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate /* Device specific initialization goes here. */ 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate done: 622*7c478bd9Sstevel@tonic-gate if (rval != 0) { 623*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 624*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_drv_state &= ~USBSKEL_OPEN; 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 627*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 628*7c478bd9Sstevel@tonic-gate 629*7c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 630*7c478bd9Sstevel@tonic-gate } else { 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate /* Device is idle until it is used. */ 633*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 634*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 635*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 636*7c478bd9Sstevel@tonic-gate } 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate return (rval); 639*7c478bd9Sstevel@tonic-gate } 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 643*7c478bd9Sstevel@tonic-gate static int 644*7c478bd9Sstevel@tonic-gate usbskel_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 645*7c478bd9Sstevel@tonic-gate { 646*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 647*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(usbskel_statep, getminor(dev)); 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "close: enter"); 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 652*7c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 653*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate /* Perform device session cleanup here. */ 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "close: cleaning up..."); 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate /* 660*7c478bd9Sstevel@tonic-gate * USBA automatically flushes/resets active non-default pipes 661*7c478bd9Sstevel@tonic-gate * when they are closed. We can't reset default pipe, but we 662*7c478bd9Sstevel@tonic-gate * can wait for all requests on it from this dip to drain. 663*7c478bd9Sstevel@tonic-gate */ 664*7c478bd9Sstevel@tonic-gate (void) usb_pipe_drain_reqs(usbskelp->usbskel_dip, 665*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_reg->dev_default_ph, 0, 666*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, 0); 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 669*7c478bd9Sstevel@tonic-gate usbskel_close_pipes(usbskelp); 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_drv_state &= ~USBSKEL_OPEN; 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 674*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate return (0); 679*7c478bd9Sstevel@tonic-gate } 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 683*7c478bd9Sstevel@tonic-gate static int 684*7c478bd9Sstevel@tonic-gate usbskel_read(dev_t dev, struct uio *uio_p, cred_t *cred_p) 685*7c478bd9Sstevel@tonic-gate { 686*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 687*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(usbskel_statep, getminor(dev)); 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "read enter"); 690*7c478bd9Sstevel@tonic-gate 691*7c478bd9Sstevel@tonic-gate return (physio(usbskel_strategy, NULL, dev, B_READ, 692*7c478bd9Sstevel@tonic-gate usbskel_minphys, uio_p)); 693*7c478bd9Sstevel@tonic-gate } 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate 696*7c478bd9Sstevel@tonic-gate /* 697*7c478bd9Sstevel@tonic-gate * strategy: 698*7c478bd9Sstevel@tonic-gate * Called through physio to setup and start the transfer. 699*7c478bd9Sstevel@tonic-gate */ 700*7c478bd9Sstevel@tonic-gate static int 701*7c478bd9Sstevel@tonic-gate usbskel_strategy(struct buf *bp) 702*7c478bd9Sstevel@tonic-gate { 703*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 704*7c478bd9Sstevel@tonic-gate getminor(bp->b_edev)); 705*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe = usbskelp->usbskel_reg->dev_default_ph; 706*7c478bd9Sstevel@tonic-gate usb_ctrl_req_t *request; 707*7c478bd9Sstevel@tonic-gate int status; 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "strategy enter"); 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate /* 712*7c478bd9Sstevel@tonic-gate * Initialize residual count here in case transfer doesn't even get 713*7c478bd9Sstevel@tonic-gate * started. 714*7c478bd9Sstevel@tonic-gate */ 715*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate /* Needed as this is a character driver. */ 718*7c478bd9Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) { 719*7c478bd9Sstevel@tonic-gate bp_mapin(bp); 720*7c478bd9Sstevel@tonic-gate } 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 723*7c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate /* Make sure device has not been disconnected. */ 726*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_dev_state != USB_DEV_ONLINE) { 727*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 728*7c478bd9Sstevel@tonic-gate "usbskel_strategy: device can't be accessed"); 729*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 730*7c478bd9Sstevel@tonic-gate goto fail; 731*7c478bd9Sstevel@tonic-gate } 732*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate /* 735*7c478bd9Sstevel@tonic-gate * Since every device has raw configuration data, set up a control 736*7c478bd9Sstevel@tonic-gate * transfer to read the raw configuration data. In a production driver 737*7c478bd9Sstevel@tonic-gate * a read would probably be done on a pipe other than the default pipe, 738*7c478bd9Sstevel@tonic-gate * and would be reading data streamed by the device. 739*7c478bd9Sstevel@tonic-gate */ 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate /* Allocate and initialize the request. */ 742*7c478bd9Sstevel@tonic-gate if ((bp->b_private = request = usb_alloc_ctrl_req( 743*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, bp->b_bcount, USB_FLAGS_SLEEP)) == 744*7c478bd9Sstevel@tonic-gate NULL) { 745*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 746*7c478bd9Sstevel@tonic-gate "usbskel_read: Error allocating request"); 747*7c478bd9Sstevel@tonic-gate goto fail; 748*7c478bd9Sstevel@tonic-gate } 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate request->ctrl_bmRequestType = 751*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD | 752*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_RCPT_DEV; 753*7c478bd9Sstevel@tonic-gate request->ctrl_bRequest = USB_REQ_GET_DESCR; 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate /* For now, return only the first configuration. */ 756*7c478bd9Sstevel@tonic-gate request->ctrl_wValue = USB_DESCR_TYPE_SETUP_CFG | 0; 757*7c478bd9Sstevel@tonic-gate request->ctrl_wIndex = 0; 758*7c478bd9Sstevel@tonic-gate request->ctrl_wLength = bp->b_bcount; 759*7c478bd9Sstevel@tonic-gate request->ctrl_timeout = 3; 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate /* Autoclearing automatically set on default pipe. */ 762*7c478bd9Sstevel@tonic-gate request->ctrl_attributes = USB_ATTRS_SHORT_XFER_OK; 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate request->ctrl_cb = usbskel_normal_callback; 765*7c478bd9Sstevel@tonic-gate request->ctrl_exc_cb = usbskel_exception_callback; 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate /* Hook the req to the bp, so callback knows where to put the data. */ 768*7c478bd9Sstevel@tonic-gate /* Now both bp and request know about each other. */ 769*7c478bd9Sstevel@tonic-gate request->ctrl_client_private = (usb_opaque_t)bp; 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate /* 772*7c478bd9Sstevel@tonic-gate * Issue the request asynchronously. Physio will block waiting for an 773*7c478bd9Sstevel@tonic-gate * "interrupt" which comes as a callback. The callback calls biodone 774*7c478bd9Sstevel@tonic-gate * to release physio from its wait. 775*7c478bd9Sstevel@tonic-gate */ 776*7c478bd9Sstevel@tonic-gate if ((status = usb_pipe_ctrl_xfer(pipe, request, USB_FLAGS_NOSLEEP)) != 777*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 778*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 779*7c478bd9Sstevel@tonic-gate "usbskel_strategy: can't start transfer: status: %d", 780*7c478bd9Sstevel@tonic-gate status); 781*7c478bd9Sstevel@tonic-gate goto fail; 782*7c478bd9Sstevel@tonic-gate } 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate /* 785*7c478bd9Sstevel@tonic-gate * Normally, usbskel_release_access() and usbskel_pm_idle_component 786*7c478bd9Sstevel@tonic-gate * is called in callback handler. 787*7c478bd9Sstevel@tonic-gate */ 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate return (0); 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate fail: 792*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 793*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 794*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate bioerror(bp, EIO); 797*7c478bd9Sstevel@tonic-gate biodone(bp); 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate return (0); 800*7c478bd9Sstevel@tonic-gate } 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate static void 804*7c478bd9Sstevel@tonic-gate usbskel_minphys(struct buf *bp) 805*7c478bd9Sstevel@tonic-gate { 806*7c478bd9Sstevel@tonic-gate /* the config cloud is limited to 64k */ 807*7c478bd9Sstevel@tonic-gate if (bp->b_bcount > USBSKEL_REQUEST_SIZE) { 808*7c478bd9Sstevel@tonic-gate bp->b_bcount = USBSKEL_REQUEST_SIZE; 809*7c478bd9Sstevel@tonic-gate } 810*7c478bd9Sstevel@tonic-gate minphys(bp); 811*7c478bd9Sstevel@tonic-gate } 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate /* 815*7c478bd9Sstevel@tonic-gate * usbskel_normal_callback: 816*7c478bd9Sstevel@tonic-gate * Completion handler for successful transfer. 817*7c478bd9Sstevel@tonic-gate * Copy data from mblk returned by USBA, into 818*7c478bd9Sstevel@tonic-gate * buffer passed by physio, to get it back to user. 819*7c478bd9Sstevel@tonic-gate * Idle device 820*7c478bd9Sstevel@tonic-gate * update counts, etc. 821*7c478bd9Sstevel@tonic-gate * release request. 822*7c478bd9Sstevel@tonic-gate * signal completion via biodone 823*7c478bd9Sstevel@tonic-gate */ 824*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 825*7c478bd9Sstevel@tonic-gate static void 826*7c478bd9Sstevel@tonic-gate usbskel_normal_callback(usb_pipe_handle_t pipe, usb_ctrl_req_t *request) 827*7c478bd9Sstevel@tonic-gate { 828*7c478bd9Sstevel@tonic-gate struct buf *bp = (struct buf *)request->ctrl_client_private; 829*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 830*7c478bd9Sstevel@tonic-gate getminor(bp->b_edev)); 831*7c478bd9Sstevel@tonic-gate mblk_t *data = request->ctrl_data; 832*7c478bd9Sstevel@tonic-gate int amt_transferred = data->b_wptr - data->b_rptr; 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "normal callback enter"); 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate ASSERT((request->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0); 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 839*7c478bd9Sstevel@tonic-gate "at entry, b_bcount = %lu, b_resid = %lu, trans = %d", bp->b_bcount, 840*7c478bd9Sstevel@tonic-gate bp->b_resid, amt_transferred); 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 843*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 844*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate /* Copy data out of mblk, into buffer. */ 847*7c478bd9Sstevel@tonic-gate if (amt_transferred) { 848*7c478bd9Sstevel@tonic-gate bcopy(data->b_rptr, bp->b_un.b_addr, amt_transferred); 849*7c478bd9Sstevel@tonic-gate } 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 852*7c478bd9Sstevel@tonic-gate "normal callback: transferring %d bytes from 0x%p to 0x%p", 853*7c478bd9Sstevel@tonic-gate amt_transferred, (void *)data, (void *)(bp->b_un.b_addr)); 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate /* Unhook. */ 856*7c478bd9Sstevel@tonic-gate bp->b_private = NULL; 857*7c478bd9Sstevel@tonic-gate request->ctrl_client_private = NULL; 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate /* Free request. */ 860*7c478bd9Sstevel@tonic-gate usb_free_ctrl_req(request); 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate /* Finish up. */ 863*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount - amt_transferred; 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 866*7c478bd9Sstevel@tonic-gate "at exit, b_bcount = %lu, b_resid = %lu, trans = %d", bp->b_bcount, 867*7c478bd9Sstevel@tonic-gate bp->b_resid, amt_transferred); 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate biodone(bp); 870*7c478bd9Sstevel@tonic-gate } 871*7c478bd9Sstevel@tonic-gate 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate /* 874*7c478bd9Sstevel@tonic-gate * usbskel_exception_callback: 875*7c478bd9Sstevel@tonic-gate * Completion handler for an erred transfer. 876*7c478bd9Sstevel@tonic-gate * Copy data from mblk returned by USBA, if any, into 877*7c478bd9Sstevel@tonic-gate * buffer passed by physio, to get it back to user. 878*7c478bd9Sstevel@tonic-gate * Idle device 879*7c478bd9Sstevel@tonic-gate * update counts, etc. 880*7c478bd9Sstevel@tonic-gate * release request. 881*7c478bd9Sstevel@tonic-gate * signal completion via biodone 882*7c478bd9Sstevel@tonic-gate */ 883*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 884*7c478bd9Sstevel@tonic-gate static void 885*7c478bd9Sstevel@tonic-gate usbskel_exception_callback(usb_pipe_handle_t pipe, usb_ctrl_req_t *request) 886*7c478bd9Sstevel@tonic-gate { 887*7c478bd9Sstevel@tonic-gate struct buf *bp = (struct buf *)request->ctrl_client_private; 888*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 889*7c478bd9Sstevel@tonic-gate getminor(bp->b_edev)); 890*7c478bd9Sstevel@tonic-gate mblk_t *data = request->ctrl_data; 891*7c478bd9Sstevel@tonic-gate int amt_transferred = (data ? data->b_wptr - data->b_rptr : 0); 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 894*7c478bd9Sstevel@tonic-gate "at except cb entry, b_bcount = %lu, b_resid = %lu, trans = %d", 895*7c478bd9Sstevel@tonic-gate bp->b_bcount, bp->b_resid, amt_transferred); 896*7c478bd9Sstevel@tonic-gate 897*7c478bd9Sstevel@tonic-gate ASSERT((request->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0); 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 900*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 901*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate /* Copy data, if any, out of mblk, into buffer. */ 904*7c478bd9Sstevel@tonic-gate if (amt_transferred) { 905*7c478bd9Sstevel@tonic-gate bcopy(data, bp->b_un.b_addr, amt_transferred); 906*7c478bd9Sstevel@tonic-gate } 907*7c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount - amt_transferred; 908*7c478bd9Sstevel@tonic-gate 909*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 910*7c478bd9Sstevel@tonic-gate "exception cb: req = 0x%p, cr = %d\n\t cb_flags = 0x%x " 911*7c478bd9Sstevel@tonic-gate "data = 0x%p, amt xfered = %d", (void *)request, 912*7c478bd9Sstevel@tonic-gate request->ctrl_completion_reason, request->ctrl_cb_flags, 913*7c478bd9Sstevel@tonic-gate (void *)(request->ctrl_data), amt_transferred); 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate /* Unhook */ 916*7c478bd9Sstevel@tonic-gate bp->b_private = NULL; 917*7c478bd9Sstevel@tonic-gate request->ctrl_client_private = NULL; 918*7c478bd9Sstevel@tonic-gate 919*7c478bd9Sstevel@tonic-gate /* Free request. */ 920*7c478bd9Sstevel@tonic-gate usb_free_ctrl_req(request); 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 923*7c478bd9Sstevel@tonic-gate "at except cb exit, b_bcount = %lu, b_resid = %lu, trans = %d", 924*7c478bd9Sstevel@tonic-gate bp->b_bcount, bp->b_resid, amt_transferred); 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate bioerror(bp, EIO); 927*7c478bd9Sstevel@tonic-gate biodone(bp); 928*7c478bd9Sstevel@tonic-gate } 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate /* 932*7c478bd9Sstevel@tonic-gate * XXX Empty ioctl for now. 933*7c478bd9Sstevel@tonic-gate */ 934*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 935*7c478bd9Sstevel@tonic-gate static int 936*7c478bd9Sstevel@tonic-gate usbskel_ioctl(dev_t dev, int cmd, intptr_t arg, 937*7c478bd9Sstevel@tonic-gate int mode, cred_t *cred_p, int *rval_p) 938*7c478bd9Sstevel@tonic-gate { 939*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 940*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(usbskel_statep, getminor(dev)); 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "ioctl enter"); 943*7c478bd9Sstevel@tonic-gate 944*7c478bd9Sstevel@tonic-gate return (ENOTTY); 945*7c478bd9Sstevel@tonic-gate } 946*7c478bd9Sstevel@tonic-gate 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate /* 949*7c478bd9Sstevel@tonic-gate * usbskel_disconnect_callback: 950*7c478bd9Sstevel@tonic-gate * Called when device hotplug-removed. 951*7c478bd9Sstevel@tonic-gate * Close pipes. (This does not attempt to contact device.) 952*7c478bd9Sstevel@tonic-gate * Set state to DISCONNECTED 953*7c478bd9Sstevel@tonic-gate */ 954*7c478bd9Sstevel@tonic-gate static int 955*7c478bd9Sstevel@tonic-gate usbskel_disconnect_callback(dev_info_t *dip) 956*7c478bd9Sstevel@tonic-gate { 957*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 958*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 959*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(usbskel_statep, instance); 960*7c478bd9Sstevel@tonic-gate 961*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "disconnect: enter"); 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 964*7c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate /* 967*7c478bd9Sstevel@tonic-gate * Save any state of device or IO in progress required by 968*7c478bd9Sstevel@tonic-gate * usbskel_restore_device_state for proper device "thawing" later. 969*7c478bd9Sstevel@tonic-gate */ 970*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_DISCONNECTED; 971*7c478bd9Sstevel@tonic-gate 972*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 973*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 974*7c478bd9Sstevel@tonic-gate 975*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 976*7c478bd9Sstevel@tonic-gate } 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate /* 980*7c478bd9Sstevel@tonic-gate * usbskel_reconnect_callback: 981*7c478bd9Sstevel@tonic-gate * Called with device hotplug-inserted 982*7c478bd9Sstevel@tonic-gate * Restore state 983*7c478bd9Sstevel@tonic-gate */ 984*7c478bd9Sstevel@tonic-gate static int 985*7c478bd9Sstevel@tonic-gate usbskel_reconnect_callback(dev_info_t *dip) 986*7c478bd9Sstevel@tonic-gate { 987*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 988*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 989*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(usbskel_statep, instance); 990*7c478bd9Sstevel@tonic-gate 991*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "reconnect: enter"); 992*7c478bd9Sstevel@tonic-gate 993*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 994*7c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 995*7c478bd9Sstevel@tonic-gate usbskel_restore_device_state(dip, usbskelp); 996*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 997*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1000*7c478bd9Sstevel@tonic-gate } 1001*7c478bd9Sstevel@tonic-gate 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate /* 1004*7c478bd9Sstevel@tonic-gate * usbskel_restore_device_state: 1005*7c478bd9Sstevel@tonic-gate * Called during hotplug-reconnect and resume. 1006*7c478bd9Sstevel@tonic-gate * reenable power management 1007*7c478bd9Sstevel@tonic-gate * Verify the device is the same as before the disconnect/suspend. 1008*7c478bd9Sstevel@tonic-gate * Restore device state 1009*7c478bd9Sstevel@tonic-gate * Thaw any IO which was frozen. 1010*7c478bd9Sstevel@tonic-gate * Quiesce device. (Other routines will activate if thawed IO.) 1011*7c478bd9Sstevel@tonic-gate * Set device online. 1012*7c478bd9Sstevel@tonic-gate * Leave device disconnected if there are problems. 1013*7c478bd9Sstevel@tonic-gate */ 1014*7c478bd9Sstevel@tonic-gate static void 1015*7c478bd9Sstevel@tonic-gate usbskel_restore_device_state(dev_info_t *dip, usbskel_state_t *usbskelp) 1016*7c478bd9Sstevel@tonic-gate { 1017*7c478bd9Sstevel@tonic-gate int rval; 1018*7c478bd9Sstevel@tonic-gate 1019*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1020*7c478bd9Sstevel@tonic-gate "usbskel_restore_device_state: enter"); 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&usbskelp->usbskel_mutex)); 1023*7c478bd9Sstevel@tonic-gate 1024*7c478bd9Sstevel@tonic-gate ASSERT((usbskelp->usbskel_dev_state == USB_DEV_DISCONNECTED) || 1025*7c478bd9Sstevel@tonic-gate (usbskelp->usbskel_dev_state == USB_DEV_SUSPENDED)); 1026*7c478bd9Sstevel@tonic-gate 1027*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1028*7c478bd9Sstevel@tonic-gate 1029*7c478bd9Sstevel@tonic-gate if (usbskel_pm_busy_component(usbskelp) != DDI_SUCCESS) { 1030*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1031*7c478bd9Sstevel@tonic-gate "usbskel_restore_device_state: Error raising power"); 1032*7c478bd9Sstevel@tonic-gate 1033*7c478bd9Sstevel@tonic-gate goto fail; 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate 1036*7c478bd9Sstevel@tonic-gate /* Check if we are talking to the same device */ 1037*7c478bd9Sstevel@tonic-gate if (usbskel_check_same_device(usbskelp) != USB_SUCCESS) { 1038*7c478bd9Sstevel@tonic-gate 1039*7c478bd9Sstevel@tonic-gate goto fail; 1040*7c478bd9Sstevel@tonic-gate } 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1043*7c478bd9Sstevel@tonic-gate if ((rval = usbskel_test_and_adjust_device_state(usbskelp)) != 1044*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1045*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1046*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1047*7c478bd9Sstevel@tonic-gate "usbskel_restore_device_state: " 1048*7c478bd9Sstevel@tonic-gate "Error adjusting device: rval = %d", rval); 1049*7c478bd9Sstevel@tonic-gate 1050*7c478bd9Sstevel@tonic-gate goto fail; 1051*7c478bd9Sstevel@tonic-gate } 1052*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_ONLINE; 1053*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_pm) { 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate /* Failure here means device disappeared again. */ 1058*7c478bd9Sstevel@tonic-gate if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) != 1059*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1060*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1061*7c478bd9Sstevel@tonic-gate "device may or may not be accessible. " 1062*7c478bd9Sstevel@tonic-gate "Please verify reconnection"); 1063*7c478bd9Sstevel@tonic-gate } 1064*7c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 1065*7c478bd9Sstevel@tonic-gate } 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1071*7c478bd9Sstevel@tonic-gate "usbskel_restore_device_state: end"); 1072*7c478bd9Sstevel@tonic-gate 1073*7c478bd9Sstevel@tonic-gate return; 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate fail: 1076*7c478bd9Sstevel@tonic-gate /* change the device state from suspended to disconnected */ 1077*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1078*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_DISCONNECTED; 1079*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 1082*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1083*7c478bd9Sstevel@tonic-gate } 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate 1086*7c478bd9Sstevel@tonic-gate /* 1087*7c478bd9Sstevel@tonic-gate * usbskel_cpr_suspend: 1088*7c478bd9Sstevel@tonic-gate * Clean up device. 1089*7c478bd9Sstevel@tonic-gate * Wait for any IO to finish, then close pipes. 1090*7c478bd9Sstevel@tonic-gate * Quiesce device. 1091*7c478bd9Sstevel@tonic-gate */ 1092*7c478bd9Sstevel@tonic-gate static int 1093*7c478bd9Sstevel@tonic-gate usbskel_cpr_suspend(dev_info_t *dip) 1094*7c478bd9Sstevel@tonic-gate { 1095*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 1096*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 1097*7c478bd9Sstevel@tonic-gate instance); 1098*7c478bd9Sstevel@tonic-gate 1099*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "suspend enter"); 1100*7c478bd9Sstevel@tonic-gate 1101*7c478bd9Sstevel@tonic-gate /* Serialize to prevent races with detach, open, device access. */ 1102*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1103*7c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 1104*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1105*7c478bd9Sstevel@tonic-gate 1106*7c478bd9Sstevel@tonic-gate if (usbskel_pm_busy_component(usbskelp) != DDI_SUCCESS) { 1107*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1108*7c478bd9Sstevel@tonic-gate "suspend: Error raising power"); 1109*7c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1112*7c478bd9Sstevel@tonic-gate } 1113*7c478bd9Sstevel@tonic-gate 1114*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1115*7c478bd9Sstevel@tonic-gate 1116*7c478bd9Sstevel@tonic-gate /* 1117*7c478bd9Sstevel@tonic-gate * Set dev_state to suspended so other driver threads don't start any 1118*7c478bd9Sstevel@tonic-gate * new I/O. In a real driver, there may be draining of requests done 1119*7c478bd9Sstevel@tonic-gate * afterwards, and we don't want the draining to compete with new 1120*7c478bd9Sstevel@tonic-gate * requests being queued. 1121*7c478bd9Sstevel@tonic-gate */ 1122*7c478bd9Sstevel@tonic-gate 1123*7c478bd9Sstevel@tonic-gate /* Don't suspend if the device is open. */ 1124*7c478bd9Sstevel@tonic-gate if ((usbskelp->usbskel_drv_state & USBSKEL_OPEN) != 0) { 1125*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1126*7c478bd9Sstevel@tonic-gate "suspend: Device is open. Can't suspend"); 1127*7c478bd9Sstevel@tonic-gate 1128*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 1129*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1130*7c478bd9Sstevel@tonic-gate 1131*7c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 1132*7c478bd9Sstevel@tonic-gate 1133*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1134*7c478bd9Sstevel@tonic-gate } 1135*7c478bd9Sstevel@tonic-gate 1136*7c478bd9Sstevel@tonic-gate /* Access device here to clean it up. */ 1137*7c478bd9Sstevel@tonic-gate 1138*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_SUSPENDED; 1139*7c478bd9Sstevel@tonic-gate 1140*7c478bd9Sstevel@tonic-gate /* 1141*7c478bd9Sstevel@tonic-gate * Save any state of device required by usbskel_restore_device_state 1142*7c478bd9Sstevel@tonic-gate * for proper device "thawing" later. 1143*7c478bd9Sstevel@tonic-gate */ 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 1146*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "suspend: success"); 1151*7c478bd9Sstevel@tonic-gate 1152*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1153*7c478bd9Sstevel@tonic-gate } 1154*7c478bd9Sstevel@tonic-gate 1155*7c478bd9Sstevel@tonic-gate 1156*7c478bd9Sstevel@tonic-gate /* 1157*7c478bd9Sstevel@tonic-gate * usbskel_cpr_resume: 1158*7c478bd9Sstevel@tonic-gate * 1159*7c478bd9Sstevel@tonic-gate * usbskel_restore_device_state marks success by putting device back online 1160*7c478bd9Sstevel@tonic-gate */ 1161*7c478bd9Sstevel@tonic-gate static void 1162*7c478bd9Sstevel@tonic-gate usbskel_cpr_resume(dev_info_t *dip) 1163*7c478bd9Sstevel@tonic-gate { 1164*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 1165*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 1166*7c478bd9Sstevel@tonic-gate instance); 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "resume: enter"); 1169*7c478bd9Sstevel@tonic-gate 1170*7c478bd9Sstevel@tonic-gate /* 1171*7c478bd9Sstevel@tonic-gate * NOTE: A pm_raise_power in usbskel_restore_device_state will bring 1172*7c478bd9Sstevel@tonic-gate * the power-up state of device into synch with the system. 1173*7c478bd9Sstevel@tonic-gate */ 1174*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1175*7c478bd9Sstevel@tonic-gate usbskel_restore_device_state(dip, usbskelp); 1176*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1177*7c478bd9Sstevel@tonic-gate } 1178*7c478bd9Sstevel@tonic-gate 1179*7c478bd9Sstevel@tonic-gate 1180*7c478bd9Sstevel@tonic-gate /* 1181*7c478bd9Sstevel@tonic-gate * usbskel_test_and_adjust_device_state: 1182*7c478bd9Sstevel@tonic-gate * Place any device-specific initialization or sanity verification here. 1183*7c478bd9Sstevel@tonic-gate */ 1184*7c478bd9Sstevel@tonic-gate static int 1185*7c478bd9Sstevel@tonic-gate usbskel_test_and_adjust_device_state(usbskel_state_t *usbskelp) 1186*7c478bd9Sstevel@tonic-gate { 1187*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "test and adjust enter"); 1188*7c478bd9Sstevel@tonic-gate 1189*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1190*7c478bd9Sstevel@tonic-gate } 1191*7c478bd9Sstevel@tonic-gate 1192*7c478bd9Sstevel@tonic-gate 1193*7c478bd9Sstevel@tonic-gate /* 1194*7c478bd9Sstevel@tonic-gate * usbskel_open_pipes: 1195*7c478bd9Sstevel@tonic-gate * Open any pipes other than default pipe. 1196*7c478bd9Sstevel@tonic-gate * Mutex is assumed to be held. 1197*7c478bd9Sstevel@tonic-gate */ 1198*7c478bd9Sstevel@tonic-gate static int 1199*7c478bd9Sstevel@tonic-gate usbskel_open_pipes(usbskel_state_t *usbskelp) 1200*7c478bd9Sstevel@tonic-gate { 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 1203*7c478bd9Sstevel@tonic-gate usb_pipe_policy_t pipe_policy; 1204*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle; 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "open_pipes enter"); 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate bzero(&pipe_policy, sizeof (pipe_policy)); 1209*7c478bd9Sstevel@tonic-gate 1210*7c478bd9Sstevel@tonic-gate /* 1211*7c478bd9Sstevel@tonic-gate * Allow that pipes can support at least two asynchronous operations 1212*7c478bd9Sstevel@tonic-gate * going on simultaneously. Operations include asynchronous callbacks, 1213*7c478bd9Sstevel@tonic-gate * resets, closures. 1214*7c478bd9Sstevel@tonic-gate */ 1215*7c478bd9Sstevel@tonic-gate pipe_policy.pp_max_async_reqs = 2; 1216*7c478bd9Sstevel@tonic-gate 1217*7c478bd9Sstevel@tonic-gate if ((rval = usb_pipe_open(usbskelp->usbskel_dip, 1218*7c478bd9Sstevel@tonic-gate &usbskelp->usbskel_intr_ep_descr, &pipe_policy, 1219*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, &pipe_handle)) != USB_SUCCESS) { 1220*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1221*7c478bd9Sstevel@tonic-gate "usbskel_open_pipes: Error opening intr pipe: status = %d", 1222*7c478bd9Sstevel@tonic-gate rval); 1223*7c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 1224*7c478bd9Sstevel@tonic-gate } 1225*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1226*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_intr_ph = pipe_handle; 1227*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1228*7c478bd9Sstevel@tonic-gate 1229*7c478bd9Sstevel@tonic-gate /* 1230*7c478bd9Sstevel@tonic-gate * At this point, polling could be started on the pipe by making an 1231*7c478bd9Sstevel@tonic-gate * asynchronous input request on the pipe. Allocate a request by 1232*7c478bd9Sstevel@tonic-gate * calling usb_alloc_intr_req(9F) with a zero length, initialize 1233*7c478bd9Sstevel@tonic-gate * attributes with USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING, 1234*7c478bd9Sstevel@tonic-gate * initialize length to be packetsize of the endpoint, specify the 1235*7c478bd9Sstevel@tonic-gate * callbacks. Pass this request to usb_pipe_intr_xfer to start polling. 1236*7c478bd9Sstevel@tonic-gate * Call usb_pipe_stop_intr_poling(9F) to stop polling. 1237*7c478bd9Sstevel@tonic-gate */ 1238*7c478bd9Sstevel@tonic-gate 1239*7c478bd9Sstevel@tonic-gate return (rval); 1240*7c478bd9Sstevel@tonic-gate } 1241*7c478bd9Sstevel@tonic-gate 1242*7c478bd9Sstevel@tonic-gate 1243*7c478bd9Sstevel@tonic-gate /* 1244*7c478bd9Sstevel@tonic-gate * usbskel_close_pipes: 1245*7c478bd9Sstevel@tonic-gate * Close pipes. Mutex is assumed to be held. 1246*7c478bd9Sstevel@tonic-gate */ 1247*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1248*7c478bd9Sstevel@tonic-gate static void 1249*7c478bd9Sstevel@tonic-gate usbskel_close_pipes(usbskel_state_t *usbskelp) 1250*7c478bd9Sstevel@tonic-gate { 1251*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "close_pipes enter"); 1252*7c478bd9Sstevel@tonic-gate 1253*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_intr_ph) { 1254*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle = usbskelp->usbskel_intr_ph; 1255*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_intr_ph = NULL; 1256*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1257*7c478bd9Sstevel@tonic-gate 1258*7c478bd9Sstevel@tonic-gate usb_pipe_close(usbskelp->usbskel_dip, pipe_handle, 1259*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, 0); 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1262*7c478bd9Sstevel@tonic-gate } 1263*7c478bd9Sstevel@tonic-gate } 1264*7c478bd9Sstevel@tonic-gate 1265*7c478bd9Sstevel@tonic-gate static int 1266*7c478bd9Sstevel@tonic-gate usbskel_pm_busy_component(usbskel_state_t *usbskelp) 1267*7c478bd9Sstevel@tonic-gate { 1268*7c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 1269*7c478bd9Sstevel@tonic-gate 1270*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1271*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_pm != NULL) { 1272*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_pm_busy++; 1273*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1274*7c478bd9Sstevel@tonic-gate if (pm_busy_component(usbskelp->usbskel_dip, 0) == 1275*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 1276*7c478bd9Sstevel@tonic-gate (void) pm_raise_power( 1277*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, 0, USB_DEV_OS_FULL_PWR); 1278*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1279*7c478bd9Sstevel@tonic-gate } else { 1280*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1281*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_pm_busy--; 1282*7c478bd9Sstevel@tonic-gate rval = DDI_FAILURE; 1283*7c478bd9Sstevel@tonic-gate } 1284*7c478bd9Sstevel@tonic-gate } 1285*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1286*7c478bd9Sstevel@tonic-gate 1287*7c478bd9Sstevel@tonic-gate return (rval); 1288*7c478bd9Sstevel@tonic-gate } 1289*7c478bd9Sstevel@tonic-gate 1290*7c478bd9Sstevel@tonic-gate static void 1291*7c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskel_state_t *usbskelp) 1292*7c478bd9Sstevel@tonic-gate { 1293*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1294*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_pm != NULL) { 1295*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1296*7c478bd9Sstevel@tonic-gate if (pm_idle_component(usbskelp->usbskel_dip, 0) == 1297*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 1298*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1299*7c478bd9Sstevel@tonic-gate ASSERT(usbskelp->usbskel_pm->usbskel_pm_busy > 0); 1300*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_pm_busy--; 1301*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1302*7c478bd9Sstevel@tonic-gate } 1303*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1304*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1305*7c478bd9Sstevel@tonic-gate "usbskel_pm_idle_component: %d", 1306*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_pm_busy); 1307*7c478bd9Sstevel@tonic-gate } 1308*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1309*7c478bd9Sstevel@tonic-gate } 1310*7c478bd9Sstevel@tonic-gate 1311*7c478bd9Sstevel@tonic-gate /* 1312*7c478bd9Sstevel@tonic-gate * usbskel_power : 1313*7c478bd9Sstevel@tonic-gate * Power entry point, the workhorse behind pm_raise_power, pm_lower_power, 1314*7c478bd9Sstevel@tonic-gate * usb_req_raise_power and usb_req_lower_power. 1315*7c478bd9Sstevel@tonic-gate */ 1316*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1317*7c478bd9Sstevel@tonic-gate static int 1318*7c478bd9Sstevel@tonic-gate usbskel_power(dev_info_t *dip, int comp, int level) 1319*7c478bd9Sstevel@tonic-gate { 1320*7c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp; 1321*7c478bd9Sstevel@tonic-gate usbskel_power_t *pm; 1322*7c478bd9Sstevel@tonic-gate int rval = USB_FAILURE; 1323*7c478bd9Sstevel@tonic-gate 1324*7c478bd9Sstevel@tonic-gate usbskelp = ddi_get_soft_state(usbskel_statep, ddi_get_instance(dip)); 1325*7c478bd9Sstevel@tonic-gate 1326*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1327*7c478bd9Sstevel@tonic-gate "usbskel_power: enter: level = %d", level); 1328*7c478bd9Sstevel@tonic-gate 1329*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1330*7c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 1331*7c478bd9Sstevel@tonic-gate 1332*7c478bd9Sstevel@tonic-gate 1333*7c478bd9Sstevel@tonic-gate /* 1334*7c478bd9Sstevel@tonic-gate * If we are disconnected/suspended, return success. Note that if we 1335*7c478bd9Sstevel@tonic-gate * return failure, bringing down the system will hang when 1336*7c478bd9Sstevel@tonic-gate * PM tries to power up all devices 1337*7c478bd9Sstevel@tonic-gate */ 1338*7c478bd9Sstevel@tonic-gate if ((usbskelp->usbskel_dev_state == USB_DEV_DISCONNECTED) || 1339*7c478bd9Sstevel@tonic-gate (usbskelp->usbskel_dev_state == USB_DEV_SUSPENDED)) { 1340*7c478bd9Sstevel@tonic-gate 1341*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1342*7c478bd9Sstevel@tonic-gate "usbskel_power: disconnected/suspended " 1343*7c478bd9Sstevel@tonic-gate "dev_state=%d", usbskelp->usbskel_dev_state); 1344*7c478bd9Sstevel@tonic-gate rval = USB_SUCCESS; 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate goto done; 1347*7c478bd9Sstevel@tonic-gate } 1348*7c478bd9Sstevel@tonic-gate 1349*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_pm == NULL) { 1350*7c478bd9Sstevel@tonic-gate 1351*7c478bd9Sstevel@tonic-gate goto done; 1352*7c478bd9Sstevel@tonic-gate } 1353*7c478bd9Sstevel@tonic-gate 1354*7c478bd9Sstevel@tonic-gate pm = usbskelp->usbskel_pm; 1355*7c478bd9Sstevel@tonic-gate 1356*7c478bd9Sstevel@tonic-gate /* Check if we are transitioning to a legal power level */ 1357*7c478bd9Sstevel@tonic-gate if (USB_DEV_PWRSTATE_OK(pm->usbskel_pwr_states, level)) { 1358*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1359*7c478bd9Sstevel@tonic-gate "usbskel_power: illegal power level = %d " 1360*7c478bd9Sstevel@tonic-gate "pwr_states: %x", level, pm->usbskel_pwr_states); 1361*7c478bd9Sstevel@tonic-gate 1362*7c478bd9Sstevel@tonic-gate goto done; 1363*7c478bd9Sstevel@tonic-gate } 1364*7c478bd9Sstevel@tonic-gate 1365*7c478bd9Sstevel@tonic-gate switch (level) { 1366*7c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_OFF : 1367*7c478bd9Sstevel@tonic-gate /* fail attempt to go to low power if busy */ 1368*7c478bd9Sstevel@tonic-gate if (pm->usbskel_pm_busy) { 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate goto done; 1371*7c478bd9Sstevel@tonic-gate } 1372*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_dev_state == USB_DEV_ONLINE) { 1373*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_PWRED_DOWN; 1374*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_current_power = 1375*7c478bd9Sstevel@tonic-gate USB_DEV_OS_PWR_OFF; 1376*7c478bd9Sstevel@tonic-gate } else { 1377*7c478bd9Sstevel@tonic-gate rval = USB_SUCCESS; 1378*7c478bd9Sstevel@tonic-gate } 1379*7c478bd9Sstevel@tonic-gate break; 1380*7c478bd9Sstevel@tonic-gate 1381*7c478bd9Sstevel@tonic-gate case USB_DEV_OS_FULL_PWR : 1382*7c478bd9Sstevel@tonic-gate /* 1383*7c478bd9Sstevel@tonic-gate * PM framework tries to put us in full power during system 1384*7c478bd9Sstevel@tonic-gate * shutdown. 1385*7c478bd9Sstevel@tonic-gate */ 1386*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_ONLINE; 1387*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_current_power = 1388*7c478bd9Sstevel@tonic-gate USB_DEV_OS_FULL_PWR; 1389*7c478bd9Sstevel@tonic-gate break; 1390*7c478bd9Sstevel@tonic-gate 1391*7c478bd9Sstevel@tonic-gate /* Levels 1 and 2 are not supported by this driver to keep it simple. */ 1392*7c478bd9Sstevel@tonic-gate default: 1393*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1394*7c478bd9Sstevel@tonic-gate "usbskel_power: power level %d not supported", level); 1395*7c478bd9Sstevel@tonic-gate break; 1396*7c478bd9Sstevel@tonic-gate } 1397*7c478bd9Sstevel@tonic-gate done: 1398*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 1399*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1400*7c478bd9Sstevel@tonic-gate 1401*7c478bd9Sstevel@tonic-gate return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 1402*7c478bd9Sstevel@tonic-gate } 1403*7c478bd9Sstevel@tonic-gate 1404*7c478bd9Sstevel@tonic-gate 1405*7c478bd9Sstevel@tonic-gate #ifdef USBSKEL_PM 1406*7c478bd9Sstevel@tonic-gate /* 1407*7c478bd9Sstevel@tonic-gate * usbskel_init_power_mgmt: 1408*7c478bd9Sstevel@tonic-gate * Initialize power management and remote wakeup functionality. 1409*7c478bd9Sstevel@tonic-gate * No mutex is necessary in this function as it's called only by attach. 1410*7c478bd9Sstevel@tonic-gate */ 1411*7c478bd9Sstevel@tonic-gate static int 1412*7c478bd9Sstevel@tonic-gate usbskel_init_power_mgmt(usbskel_state_t *usbskelp) 1413*7c478bd9Sstevel@tonic-gate { 1414*7c478bd9Sstevel@tonic-gate int rval = USB_FAILURE; 1415*7c478bd9Sstevel@tonic-gate 1416*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "init_power_mgmt enter"); 1417*7c478bd9Sstevel@tonic-gate 1418*7c478bd9Sstevel@tonic-gate /* 1419*7c478bd9Sstevel@tonic-gate * If remote wakeup is not available you may not want to do 1420*7c478bd9Sstevel@tonic-gate * power management. 1421*7c478bd9Sstevel@tonic-gate */ 1422*7c478bd9Sstevel@tonic-gate if (usb_handle_remote_wakeup(usbskelp->usbskel_dip, 1423*7c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 1424*7c478bd9Sstevel@tonic-gate usbskel_power_t *usbskelpm; 1425*7c478bd9Sstevel@tonic-gate uint_t pwr_states; 1426*7c478bd9Sstevel@tonic-gate 1427*7c478bd9Sstevel@tonic-gate /* Allocate the state structure */ 1428*7c478bd9Sstevel@tonic-gate usbskelpm = kmem_zalloc(sizeof (usbskel_power_t), KM_SLEEP); 1429*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm = usbskelpm; 1430*7c478bd9Sstevel@tonic-gate usbskelpm->usbskel_state = usbskelp; 1431*7c478bd9Sstevel@tonic-gate usbskelpm->usbskel_pm_capabilities = 0; 1432*7c478bd9Sstevel@tonic-gate usbskelpm->usbskel_current_power = USB_DEV_OS_FULL_PWR; 1433*7c478bd9Sstevel@tonic-gate 1434*7c478bd9Sstevel@tonic-gate if ((rval = usb_create_pm_components( 1435*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, &pwr_states)) == USB_SUCCESS) { 1436*7c478bd9Sstevel@tonic-gate 1437*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1438*7c478bd9Sstevel@tonic-gate "usbskel_init_power_mgmt: created PM components"); 1439*7c478bd9Sstevel@tonic-gate 1440*7c478bd9Sstevel@tonic-gate usbskelpm->usbskel_pwr_states = 1441*7c478bd9Sstevel@tonic-gate (uint8_t)pwr_states; 1442*7c478bd9Sstevel@tonic-gate (void) pm_raise_power( 1443*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, 0, USB_DEV_OS_FULL_PWR); 1444*7c478bd9Sstevel@tonic-gate } else { 1445*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1446*7c478bd9Sstevel@tonic-gate "usbskel_init_power_mgmt: create_pm_compts failed"); 1447*7c478bd9Sstevel@tonic-gate } 1448*7c478bd9Sstevel@tonic-gate } else { 1449*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1450*7c478bd9Sstevel@tonic-gate "usbskel_init_power_mgmt: failure enabling remote wakeup"); 1451*7c478bd9Sstevel@tonic-gate } 1452*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "usbskel_init_power_mgmt: end"); 1453*7c478bd9Sstevel@tonic-gate 1454*7c478bd9Sstevel@tonic-gate return (rval); 1455*7c478bd9Sstevel@tonic-gate } 1456*7c478bd9Sstevel@tonic-gate 1457*7c478bd9Sstevel@tonic-gate 1458*7c478bd9Sstevel@tonic-gate /* 1459*7c478bd9Sstevel@tonic-gate * usbskel_destroy_power_mgmt: 1460*7c478bd9Sstevel@tonic-gate * Shut down and destroy power management and remote wakeup functionality. 1461*7c478bd9Sstevel@tonic-gate */ 1462*7c478bd9Sstevel@tonic-gate static void 1463*7c478bd9Sstevel@tonic-gate usbskel_destroy_power_mgmt(usbskel_state_t *usbskelp) 1464*7c478bd9Sstevel@tonic-gate { 1465*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "destroy_power_mgmt enter"); 1466*7c478bd9Sstevel@tonic-gate 1467*7c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&usbskelp->usbskel_mutex)); 1468*7c478bd9Sstevel@tonic-gate 1469*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_pm) { 1470*7c478bd9Sstevel@tonic-gate (void) usbskel_pm_busy_component(usbskelp); 1471*7c478bd9Sstevel@tonic-gate 1472*7c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 1473*7c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_dev_state != USB_DEV_DISCONNECTED) { 1474*7c478bd9Sstevel@tonic-gate int rval; 1475*7c478bd9Sstevel@tonic-gate 1476*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1477*7c478bd9Sstevel@tonic-gate 1478*7c478bd9Sstevel@tonic-gate if ((rval = usb_handle_remote_wakeup( 1479*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, 1480*7c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_DISABLE)) != 1481*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1482*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1483*7c478bd9Sstevel@tonic-gate "usbskel_destroy_power_mgmt: " 1484*7c478bd9Sstevel@tonic-gate "Error disabling rmt wakeup: rval = %d", 1485*7c478bd9Sstevel@tonic-gate rval); 1486*7c478bd9Sstevel@tonic-gate } 1487*7c478bd9Sstevel@tonic-gate } else { 1488*7c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 1489*7c478bd9Sstevel@tonic-gate } 1490*7c478bd9Sstevel@tonic-gate 1491*7c478bd9Sstevel@tonic-gate /* 1492*7c478bd9Sstevel@tonic-gate * Since remote wakeup is disabled now, 1493*7c478bd9Sstevel@tonic-gate * no one can raise power 1494*7c478bd9Sstevel@tonic-gate * and get to device once power is lowered here. 1495*7c478bd9Sstevel@tonic-gate */ 1496*7c478bd9Sstevel@tonic-gate pm_lower_power(usbskelp->usbskel_dip, 0, USB_DEV_OS_PWR_OFF); 1497*7c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 1498*7c478bd9Sstevel@tonic-gate kmem_free(usbskelp->usbskel_pm, sizeof (usbskel_power_t)); 1499*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm = NULL; 1500*7c478bd9Sstevel@tonic-gate } 1501*7c478bd9Sstevel@tonic-gate } 1502*7c478bd9Sstevel@tonic-gate #endif 1503*7c478bd9Sstevel@tonic-gate 1504*7c478bd9Sstevel@tonic-gate 1505*7c478bd9Sstevel@tonic-gate /* 1506*7c478bd9Sstevel@tonic-gate * usbskel_serialize_access: 1507*7c478bd9Sstevel@tonic-gate * Get the serial synchronization object before returning. 1508*7c478bd9Sstevel@tonic-gate * 1509*7c478bd9Sstevel@tonic-gate * Arguments: 1510*7c478bd9Sstevel@tonic-gate * usbskelp - Pointer to usbskel state structure 1511*7c478bd9Sstevel@tonic-gate * waitsig - Set to: 1512*7c478bd9Sstevel@tonic-gate * USBSKEL_SER_SIG - to wait such that a signal can interrupt 1513*7c478bd9Sstevel@tonic-gate * USBSKEL_SER_NOSIG - to wait such that a signal cannot interrupt 1514*7c478bd9Sstevel@tonic-gate */ 1515*7c478bd9Sstevel@tonic-gate static int 1516*7c478bd9Sstevel@tonic-gate usbskel_serialize_access(usbskel_state_t *usbskelp, boolean_t waitsig) 1517*7c478bd9Sstevel@tonic-gate { 1518*7c478bd9Sstevel@tonic-gate int rval = 1; 1519*7c478bd9Sstevel@tonic-gate 1520*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&usbskelp->usbskel_mutex)); 1521*7c478bd9Sstevel@tonic-gate 1522*7c478bd9Sstevel@tonic-gate while (usbskelp->usbskel_serial_inuse) { 1523*7c478bd9Sstevel@tonic-gate if (waitsig == USBSKEL_SER_SIG) { 1524*7c478bd9Sstevel@tonic-gate rval = cv_wait_sig(&usbskelp->usbskel_serial_cv, 1525*7c478bd9Sstevel@tonic-gate &usbskelp->usbskel_mutex); 1526*7c478bd9Sstevel@tonic-gate } else { 1527*7c478bd9Sstevel@tonic-gate cv_wait(&usbskelp->usbskel_serial_cv, 1528*7c478bd9Sstevel@tonic-gate &usbskelp->usbskel_mutex); 1529*7c478bd9Sstevel@tonic-gate } 1530*7c478bd9Sstevel@tonic-gate } 1531*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_serial_inuse = B_TRUE; 1532*7c478bd9Sstevel@tonic-gate 1533*7c478bd9Sstevel@tonic-gate return (rval); 1534*7c478bd9Sstevel@tonic-gate } 1535*7c478bd9Sstevel@tonic-gate 1536*7c478bd9Sstevel@tonic-gate 1537*7c478bd9Sstevel@tonic-gate /* 1538*7c478bd9Sstevel@tonic-gate * usbskel_release_access: 1539*7c478bd9Sstevel@tonic-gate * Release the serial synchronization object. 1540*7c478bd9Sstevel@tonic-gate */ 1541*7c478bd9Sstevel@tonic-gate static void 1542*7c478bd9Sstevel@tonic-gate usbskel_release_access(usbskel_state_t *usbskelp) 1543*7c478bd9Sstevel@tonic-gate { 1544*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&usbskelp->usbskel_mutex)); 1545*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_serial_inuse = B_FALSE; 1546*7c478bd9Sstevel@tonic-gate cv_broadcast(&usbskelp->usbskel_serial_cv); 1547*7c478bd9Sstevel@tonic-gate } 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate 1550*7c478bd9Sstevel@tonic-gate /* 1551*7c478bd9Sstevel@tonic-gate * usbskel_check_same_device: 1552*7c478bd9Sstevel@tonic-gate * Check if the device connected to the port is the same as 1553*7c478bd9Sstevel@tonic-gate * the previous device that was in the port. The previous device is 1554*7c478bd9Sstevel@tonic-gate * represented by the dip on record for the port. Print a message 1555*7c478bd9Sstevel@tonic-gate * if the device is different. Can block. 1556*7c478bd9Sstevel@tonic-gate * 1557*7c478bd9Sstevel@tonic-gate * return values: 1558*7c478bd9Sstevel@tonic-gate * USB_SUCCESS: same device 1559*7c478bd9Sstevel@tonic-gate * USB_INVALID_VERSION not same device 1560*7c478bd9Sstevel@tonic-gate * USB_FAILURE: Failure processing request 1561*7c478bd9Sstevel@tonic-gate */ 1562*7c478bd9Sstevel@tonic-gate static int 1563*7c478bd9Sstevel@tonic-gate usbskel_check_same_device(usbskel_state_t *usbskelp) 1564*7c478bd9Sstevel@tonic-gate { 1565*7c478bd9Sstevel@tonic-gate usb_dev_descr_t *orig_usb_dev_descr; 1566*7c478bd9Sstevel@tonic-gate usb_dev_descr_t usb_dev_descr; 1567*7c478bd9Sstevel@tonic-gate mblk_t *pdata = NULL; 1568*7c478bd9Sstevel@tonic-gate int rval; 1569*7c478bd9Sstevel@tonic-gate char *buf; 1570*7c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 1571*7c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 1572*7c478bd9Sstevel@tonic-gate boolean_t match = B_TRUE; 1573*7c478bd9Sstevel@tonic-gate 1574*7c478bd9Sstevel@tonic-gate usb_ctrl_setup_t setup = { 1575*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD | 1576*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_RCPT_DEV, 1577*7c478bd9Sstevel@tonic-gate USB_REQ_GET_DESCR, /* bRequest */ 1578*7c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 1579*7c478bd9Sstevel@tonic-gate 0, /* wIndex */ 1580*7c478bd9Sstevel@tonic-gate USB_DEV_DESCR_SIZE, /* wLength */ 1581*7c478bd9Sstevel@tonic-gate 0 /* request attributes */ 1582*7c478bd9Sstevel@tonic-gate }; 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&usbskelp->usbskel_mutex)); 1585*7c478bd9Sstevel@tonic-gate 1586*7c478bd9Sstevel@tonic-gate orig_usb_dev_descr = usbskelp->usbskel_reg->dev_descr; 1587*7c478bd9Sstevel@tonic-gate 1588*7c478bd9Sstevel@tonic-gate /* get the "new" device descriptor */ 1589*7c478bd9Sstevel@tonic-gate rval = usb_pipe_ctrl_xfer_wait(usbskelp->usbskel_reg->dev_default_ph, 1590*7c478bd9Sstevel@tonic-gate &setup, &pdata, &completion_reason, &cb_flags, USB_FLAGS_SLEEP); 1591*7c478bd9Sstevel@tonic-gate 1592*7c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 1593*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1594*7c478bd9Sstevel@tonic-gate "usbskel_check_same_device: " 1595*7c478bd9Sstevel@tonic-gate "getting device descriptor failed " 1596*7c478bd9Sstevel@tonic-gate "rval=%d, cr=%d, cb=0x%x\n", 1597*7c478bd9Sstevel@tonic-gate rval, completion_reason, cb_flags); 1598*7c478bd9Sstevel@tonic-gate freemsg(pdata); 1599*7c478bd9Sstevel@tonic-gate 1600*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1601*7c478bd9Sstevel@tonic-gate } 1602*7c478bd9Sstevel@tonic-gate 1603*7c478bd9Sstevel@tonic-gate ASSERT(pdata != NULL); 1604*7c478bd9Sstevel@tonic-gate 1605*7c478bd9Sstevel@tonic-gate (void) usb_parse_data("2cs4c3s4c", pdata->b_rptr, 1606*7c478bd9Sstevel@tonic-gate pdata->b_wptr - pdata->b_rptr, &usb_dev_descr, 1607*7c478bd9Sstevel@tonic-gate sizeof (usb_dev_descr_t)); 1608*7c478bd9Sstevel@tonic-gate 1609*7c478bd9Sstevel@tonic-gate freemsg(pdata); 1610*7c478bd9Sstevel@tonic-gate pdata = NULL; 1611*7c478bd9Sstevel@tonic-gate 1612*7c478bd9Sstevel@tonic-gate /* Always check the device descriptor length. */ 1613*7c478bd9Sstevel@tonic-gate if (usb_dev_descr.bLength != USB_DEV_DESCR_SIZE) { 1614*7c478bd9Sstevel@tonic-gate match = B_FALSE; 1615*7c478bd9Sstevel@tonic-gate 1616*7c478bd9Sstevel@tonic-gate /* Always check the device descriptor. */ 1617*7c478bd9Sstevel@tonic-gate } else if (bcmp(orig_usb_dev_descr, 1618*7c478bd9Sstevel@tonic-gate (char *)&usb_dev_descr, USB_DEV_DESCR_SIZE) != 0) { 1619*7c478bd9Sstevel@tonic-gate match = B_FALSE; 1620*7c478bd9Sstevel@tonic-gate } 1621*7c478bd9Sstevel@tonic-gate 1622*7c478bd9Sstevel@tonic-gate /* if requested & this device has a serial number check and compare */ 1623*7c478bd9Sstevel@tonic-gate if ((match == B_TRUE) && 1624*7c478bd9Sstevel@tonic-gate (usbskelp->usbskel_reg->dev_serial != NULL)) { 1625*7c478bd9Sstevel@tonic-gate buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP); 1626*7c478bd9Sstevel@tonic-gate if (usb_get_string_descr(usbskelp->usbskel_dip, USB_LANG_ID, 1627*7c478bd9Sstevel@tonic-gate usb_dev_descr.iSerialNumber, buf, 1628*7c478bd9Sstevel@tonic-gate USB_MAXSTRINGLEN) == USB_SUCCESS) { 1629*7c478bd9Sstevel@tonic-gate match = 1630*7c478bd9Sstevel@tonic-gate (strcmp(buf, 1631*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_reg->dev_serial) == 0); 1632*7c478bd9Sstevel@tonic-gate } 1633*7c478bd9Sstevel@tonic-gate kmem_free(buf, USB_MAXSTRINGLEN); 1634*7c478bd9Sstevel@tonic-gate } 1635*7c478bd9Sstevel@tonic-gate 1636*7c478bd9Sstevel@tonic-gate if (match == B_FALSE) { 1637*7c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1638*7c478bd9Sstevel@tonic-gate "Device is not identical to the " 1639*7c478bd9Sstevel@tonic-gate "previous one this port.\n" 1640*7c478bd9Sstevel@tonic-gate "Please disconnect and reconnect"); 1641*7c478bd9Sstevel@tonic-gate 1642*7c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION); 1643*7c478bd9Sstevel@tonic-gate } 1644*7c478bd9Sstevel@tonic-gate 1645*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1646*7c478bd9Sstevel@tonic-gate } 1647*7c478bd9Sstevel@tonic-gate 1648*7c478bd9Sstevel@tonic-gate /* 1649*7c478bd9Sstevel@tonic-gate * usbskel_log: 1650*7c478bd9Sstevel@tonic-gate * Switchable logging to logfile and screen. 1651*7c478bd9Sstevel@tonic-gate * 1652*7c478bd9Sstevel@tonic-gate * Arguments: 1653*7c478bd9Sstevel@tonic-gate * usbskelp: usbskel state pointer. 1654*7c478bd9Sstevel@tonic-gate * if NULL, driver name and instance won't print with the message 1655*7c478bd9Sstevel@tonic-gate * msglevel: 1656*7c478bd9Sstevel@tonic-gate * if USBSKEL_LOG_LOG, goes only to logfile. 1657*7c478bd9Sstevel@tonic-gate * (usbskel_errlevel must be set to USBSKEL_LOG_LOG too.) 1658*7c478bd9Sstevel@tonic-gate * if USBSKEL_LOG_CONSOLE, goes to both logfile and screen 1659*7c478bd9Sstevel@tonic-gate * (usbskel_errlevel can be either value for this to work.) 1660*7c478bd9Sstevel@tonic-gate * cmn_err_level: error level passed to cmn_err(9F) 1661*7c478bd9Sstevel@tonic-gate * format and args: as you would call cmn_err, except without special 1662*7c478bd9Sstevel@tonic-gate * first routing character. 1663*7c478bd9Sstevel@tonic-gate * 1664*7c478bd9Sstevel@tonic-gate * Do not call this in an interrupt context, since kmem_alloc can sleep. 1665*7c478bd9Sstevel@tonic-gate */ 1666*7c478bd9Sstevel@tonic-gate static void 1667*7c478bd9Sstevel@tonic-gate usbskel_log(usbskel_state_t *usbskelp, int msglevel, char *formatarg, ...) 1668*7c478bd9Sstevel@tonic-gate { 1669*7c478bd9Sstevel@tonic-gate va_list ap; 1670*7c478bd9Sstevel@tonic-gate 1671*7c478bd9Sstevel@tonic-gate if (msglevel <= usbskel_errlevel) { 1672*7c478bd9Sstevel@tonic-gate char *format; 1673*7c478bd9Sstevel@tonic-gate int formatlen = strlen(formatarg) + 2; /* '!' and NULL char */ 1674*7c478bd9Sstevel@tonic-gate int devinst_start = 0; 1675*7c478bd9Sstevel@tonic-gate 1676*7c478bd9Sstevel@tonic-gate /* Allocate extra room if driver name and instance is present */ 1677*7c478bd9Sstevel@tonic-gate if (usbskelp != NULL) { 1678*7c478bd9Sstevel@tonic-gate formatlen += strlen(usbskelp->usbskel_devinst); 1679*7c478bd9Sstevel@tonic-gate } 1680*7c478bd9Sstevel@tonic-gate 1681*7c478bd9Sstevel@tonic-gate format = kmem_zalloc(formatlen, KM_SLEEP); 1682*7c478bd9Sstevel@tonic-gate 1683*7c478bd9Sstevel@tonic-gate if (msglevel == USBSKEL_LOG_LOG) { 1684*7c478bd9Sstevel@tonic-gate format[0] = '!'; 1685*7c478bd9Sstevel@tonic-gate devinst_start = 1; 1686*7c478bd9Sstevel@tonic-gate } 1687*7c478bd9Sstevel@tonic-gate 1688*7c478bd9Sstevel@tonic-gate if (usbskelp != NULL) { 1689*7c478bd9Sstevel@tonic-gate (void) strcpy(&format[devinst_start], 1690*7c478bd9Sstevel@tonic-gate usbskelp->usbskel_devinst); 1691*7c478bd9Sstevel@tonic-gate } 1692*7c478bd9Sstevel@tonic-gate 1693*7c478bd9Sstevel@tonic-gate va_start(ap, formatarg); 1694*7c478bd9Sstevel@tonic-gate (void) strcat(format, formatarg); 1695*7c478bd9Sstevel@tonic-gate vcmn_err(CE_CONT, format, ap); 1696*7c478bd9Sstevel@tonic-gate va_end(ap); 1697*7c478bd9Sstevel@tonic-gate 1698*7c478bd9Sstevel@tonic-gate kmem_free(format, formatlen); 1699*7c478bd9Sstevel@tonic-gate } 1700*7c478bd9Sstevel@tonic-gate } 1701