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 * USBA: Solaris USB Architecture support 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * Utility functions 33*7c478bd9Sstevel@tonic-gate */ 34*7c478bd9Sstevel@tonic-gate #define USBA_FRAMEWORK 35*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h> 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate static mblk_t *usba_get_cfg_cloud(dev_info_t *, usb_pipe_handle_t, int); 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate /* local functions */ 41*7c478bd9Sstevel@tonic-gate static int usba_sync_set_cfg(dev_info_t *, usba_ph_impl_t *, 42*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t); 43*7c478bd9Sstevel@tonic-gate static int usba_sync_set_alt_if(dev_info_t *, usba_ph_impl_t *, 44*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t); 45*7c478bd9Sstevel@tonic-gate static int usba_sync_clear_feature(dev_info_t *, usba_ph_impl_t *, 46*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t); 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate /* 49*7c478bd9Sstevel@tonic-gate * Wrapper functions returning parsed standard descriptors without 50*7c478bd9Sstevel@tonic-gate * getting the config cloud first but by just providing the dip. 51*7c478bd9Sstevel@tonic-gate * 52*7c478bd9Sstevel@tonic-gate * The client can easily retrieve the device and config descriptor from 53*7c478bd9Sstevel@tonic-gate * the usb registration and no separate functions are provided 54*7c478bd9Sstevel@tonic-gate * 55*7c478bd9Sstevel@tonic-gate * These functions return failure if the full descriptor can not be 56*7c478bd9Sstevel@tonic-gate * retrieved. These functions will not access the device. 57*7c478bd9Sstevel@tonic-gate * The caller must allocate the buffer. 58*7c478bd9Sstevel@tonic-gate */ 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate /* 61*7c478bd9Sstevel@tonic-gate * usb_get_if_descr: 62*7c478bd9Sstevel@tonic-gate * Function to get the cooked interface descriptor 63*7c478bd9Sstevel@tonic-gate * This function will not access the device. 64*7c478bd9Sstevel@tonic-gate * 65*7c478bd9Sstevel@tonic-gate * Arguments: 66*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 67*7c478bd9Sstevel@tonic-gate * if_index - interface index 68*7c478bd9Sstevel@tonic-gate * alt_setting - alt interface setting 69*7c478bd9Sstevel@tonic-gate * descr - pointer to user allocated interface descr 70*7c478bd9Sstevel@tonic-gate * 71*7c478bd9Sstevel@tonic-gate * Return Values: 72*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - descriptor is valid 73*7c478bd9Sstevel@tonic-gate * USB_FAILURE - full descriptor could not be retrieved 74*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 75*7c478bd9Sstevel@tonic-gate */ 76*7c478bd9Sstevel@tonic-gate int 77*7c478bd9Sstevel@tonic-gate usb_get_if_descr(dev_info_t *dip, 78*7c478bd9Sstevel@tonic-gate uint_t if_index, 79*7c478bd9Sstevel@tonic-gate uint_t alt_setting, 80*7c478bd9Sstevel@tonic-gate usb_if_descr_t *descr) 81*7c478bd9Sstevel@tonic-gate { 82*7c478bd9Sstevel@tonic-gate uchar_t *usb_cfg; /* buf for config descriptor */ 83*7c478bd9Sstevel@tonic-gate size_t size, cfg_length; 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 86*7c478bd9Sstevel@tonic-gate "usb_get_if_descr: %s, index=0x%x, alt#=0x%x", 87*7c478bd9Sstevel@tonic-gate ddi_node_name(dip), if_index, alt_setting); 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (descr == NULL)) { 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 92*7c478bd9Sstevel@tonic-gate } 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length); 95*7c478bd9Sstevel@tonic-gate size = usb_parse_if_descr(usb_cfg, cfg_length, 96*7c478bd9Sstevel@tonic-gate if_index, /* interface index */ 97*7c478bd9Sstevel@tonic-gate alt_setting, /* alt interface index */ 98*7c478bd9Sstevel@tonic-gate descr, 99*7c478bd9Sstevel@tonic-gate USB_IF_DESCR_SIZE); 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate if (size != USB_IF_DESCR_SIZE) { 102*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 103*7c478bd9Sstevel@tonic-gate "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)", 104*7c478bd9Sstevel@tonic-gate size, USB_IF_DESCR_SIZE); 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 107*7c478bd9Sstevel@tonic-gate } 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 110*7c478bd9Sstevel@tonic-gate } 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate /* 114*7c478bd9Sstevel@tonic-gate * usb_get_ep_descr: 115*7c478bd9Sstevel@tonic-gate * Function to get the cooked endpoint descriptor 116*7c478bd9Sstevel@tonic-gate * This function will not access the device. 117*7c478bd9Sstevel@tonic-gate * 118*7c478bd9Sstevel@tonic-gate * Arguments: 119*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 120*7c478bd9Sstevel@tonic-gate * if_index - interface index 121*7c478bd9Sstevel@tonic-gate * alt_setting - alternate interface setting 122*7c478bd9Sstevel@tonic-gate * endpoint_index - endpoint index 123*7c478bd9Sstevel@tonic-gate * descr - pointer to user allocated interface descr 124*7c478bd9Sstevel@tonic-gate * 125*7c478bd9Sstevel@tonic-gate * Return Values: 126*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - descriptor is valid 127*7c478bd9Sstevel@tonic-gate * USB_FAILURE - full descriptor could not be retrieved 128*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 129*7c478bd9Sstevel@tonic-gate */ 130*7c478bd9Sstevel@tonic-gate int 131*7c478bd9Sstevel@tonic-gate usb_get_ep_descr(dev_info_t *dip, 132*7c478bd9Sstevel@tonic-gate uint_t if_index, 133*7c478bd9Sstevel@tonic-gate uint_t alt_setting, 134*7c478bd9Sstevel@tonic-gate uint_t endpoint_index, 135*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *descr) 136*7c478bd9Sstevel@tonic-gate { 137*7c478bd9Sstevel@tonic-gate uchar_t *usb_cfg; /* buf for config descriptor */ 138*7c478bd9Sstevel@tonic-gate size_t size, cfg_length; 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 141*7c478bd9Sstevel@tonic-gate "usb_get_ep_descr: %s, index=0x%x, alt#=0x%x", 142*7c478bd9Sstevel@tonic-gate ddi_node_name(dip), if_index, alt_setting); 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (descr == NULL)) { 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 147*7c478bd9Sstevel@tonic-gate } 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length); 150*7c478bd9Sstevel@tonic-gate size = usb_parse_ep_descr(usb_cfg, cfg_length, 151*7c478bd9Sstevel@tonic-gate if_index, /* interface index */ 152*7c478bd9Sstevel@tonic-gate alt_setting, /* alt interface index */ 153*7c478bd9Sstevel@tonic-gate endpoint_index, /* ep index */ 154*7c478bd9Sstevel@tonic-gate descr, USB_EP_DESCR_SIZE); 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate if (size != USB_EP_DESCR_SIZE) { 157*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 158*7c478bd9Sstevel@tonic-gate "parsing endpoint: size (%lu) != USB_EP_DESCR_SIZE (%d)", 159*7c478bd9Sstevel@tonic-gate size, USB_EP_DESCR_SIZE); 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 162*7c478bd9Sstevel@tonic-gate } 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 165*7c478bd9Sstevel@tonic-gate } 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate /* 169*7c478bd9Sstevel@tonic-gate * usb_lookup_ep_data: 170*7c478bd9Sstevel@tonic-gate * usb_get_ep_data (deprecated): 171*7c478bd9Sstevel@tonic-gate * Function to get specific endpoint descriptor data 172*7c478bd9Sstevel@tonic-gate * This function will not access the device. 173*7c478bd9Sstevel@tonic-gate * 174*7c478bd9Sstevel@tonic-gate * Arguments: 175*7c478bd9Sstevel@tonic-gate * dip - pointer to dev info 176*7c478bd9Sstevel@tonic-gate * usb_client_dev_data_t - pointer to registration data 177*7c478bd9Sstevel@tonic-gate * interface - requested interface 178*7c478bd9Sstevel@tonic-gate * alternate - requested alternate 179*7c478bd9Sstevel@tonic-gate * skip - how many to skip 180*7c478bd9Sstevel@tonic-gate * type - endpoint type 181*7c478bd9Sstevel@tonic-gate * direction - endpoint direction or USB_DIR_DONT_CARE 182*7c478bd9Sstevel@tonic-gate * 183*7c478bd9Sstevel@tonic-gate * Return Values: 184*7c478bd9Sstevel@tonic-gate * NULL or an endpoint descriptor pointer 185*7c478bd9Sstevel@tonic-gate */ 186*7c478bd9Sstevel@tonic-gate usb_ep_data_t * 187*7c478bd9Sstevel@tonic-gate usb_lookup_ep_data(dev_info_t *dip, 188*7c478bd9Sstevel@tonic-gate usb_client_dev_data_t *dev_datap, 189*7c478bd9Sstevel@tonic-gate uint_t interface, 190*7c478bd9Sstevel@tonic-gate uint_t alternate, 191*7c478bd9Sstevel@tonic-gate uint_t skip, 192*7c478bd9Sstevel@tonic-gate uint_t type, 193*7c478bd9Sstevel@tonic-gate uint_t dir) 194*7c478bd9Sstevel@tonic-gate { 195*7c478bd9Sstevel@tonic-gate usb_alt_if_data_t *altif_data; 196*7c478bd9Sstevel@tonic-gate int i; 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 199*7c478bd9Sstevel@tonic-gate "usb_lookup_ep_data: " 200*7c478bd9Sstevel@tonic-gate "if=%d alt=%d skip=%d type=%d dir=%d", 201*7c478bd9Sstevel@tonic-gate interface, alternate, skip, type, dir); 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (dev_datap == NULL)) { 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate return (NULL); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate altif_data = &dev_datap->dev_curr_cfg-> 209*7c478bd9Sstevel@tonic-gate cfg_if[interface].if_alt[alternate]; 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 212*7c478bd9Sstevel@tonic-gate "altif=0x%p n_ep=%d", altif_data, altif_data->altif_n_ep); 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate for (i = 0; i < altif_data->altif_n_ep; i++) { 215*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr; 216*7c478bd9Sstevel@tonic-gate uint8_t ept_type = ept->bmAttributes & USB_EP_ATTR_MASK; 217*7c478bd9Sstevel@tonic-gate uint8_t ept_dir = ept->bEndpointAddress & USB_EP_DIR_MASK; 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate if (ept->bLength == 0) { 220*7c478bd9Sstevel@tonic-gate continue; 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate if ((ept_type == type) && 223*7c478bd9Sstevel@tonic-gate ((type == USB_EP_ATTR_CONTROL) || (dir == ept_dir))) { 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate if (skip-- == 0) { 226*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, 227*7c478bd9Sstevel@tonic-gate usbai_log_handle, 228*7c478bd9Sstevel@tonic-gate "usb_get_ep_data: data=0x%p", 229*7c478bd9Sstevel@tonic-gate &altif_data->altif_ep[i]); 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate return (&altif_data->altif_ep[i]); 232*7c478bd9Sstevel@tonic-gate } 233*7c478bd9Sstevel@tonic-gate } 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 236*7c478bd9Sstevel@tonic-gate "usb_get_ep_data: returning NULL"); 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate return (NULL); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 243*7c478bd9Sstevel@tonic-gate usb_ep_data_t * 244*7c478bd9Sstevel@tonic-gate usb_get_ep_data(dev_info_t *dip, 245*7c478bd9Sstevel@tonic-gate usb_client_dev_data_t *dev_datap, 246*7c478bd9Sstevel@tonic-gate uint_t interface, 247*7c478bd9Sstevel@tonic-gate uint_t alternate, 248*7c478bd9Sstevel@tonic-gate uint_t type, 249*7c478bd9Sstevel@tonic-gate uint_t dir) 250*7c478bd9Sstevel@tonic-gate { 251*7c478bd9Sstevel@tonic-gate return (usb_lookup_ep_data(dip, dev_datap, interface, 252*7c478bd9Sstevel@tonic-gate alternate, 0, type, dir)); 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate /* 257*7c478bd9Sstevel@tonic-gate * usb_get_string_descr: 258*7c478bd9Sstevel@tonic-gate * Function to read the string descriptor 259*7c478bd9Sstevel@tonic-gate * This function will access the device and block. 260*7c478bd9Sstevel@tonic-gate * 261*7c478bd9Sstevel@tonic-gate * Arguments: 262*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 263*7c478bd9Sstevel@tonic-gate * langid - LANGID to read different LOCALEs 264*7c478bd9Sstevel@tonic-gate * index - index to the string 265*7c478bd9Sstevel@tonic-gate * buf - user provided buffer for string descriptor 266*7c478bd9Sstevel@tonic-gate * buflen - user provided length of the buffer 267*7c478bd9Sstevel@tonic-gate * 268*7c478bd9Sstevel@tonic-gate * Return Values: 269*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - descriptor is valid 270*7c478bd9Sstevel@tonic-gate * USB_FAILURE - full descriptor could not be retrieved 271*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 272*7c478bd9Sstevel@tonic-gate */ 273*7c478bd9Sstevel@tonic-gate int 274*7c478bd9Sstevel@tonic-gate usb_get_string_descr(dev_info_t *dip, 275*7c478bd9Sstevel@tonic-gate uint16_t langid, 276*7c478bd9Sstevel@tonic-gate uint8_t index, 277*7c478bd9Sstevel@tonic-gate char *buf, 278*7c478bd9Sstevel@tonic-gate size_t buflen) 279*7c478bd9Sstevel@tonic-gate { 280*7c478bd9Sstevel@tonic-gate mblk_t *data = NULL; 281*7c478bd9Sstevel@tonic-gate uint16_t length; 282*7c478bd9Sstevel@tonic-gate int rval; 283*7c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 284*7c478bd9Sstevel@tonic-gate size_t len; 285*7c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 288*7c478bd9Sstevel@tonic-gate "usb_get_string_descr: %s, langid=0x%x index=0x%x", 289*7c478bd9Sstevel@tonic-gate ddi_node_name(dip), langid, index); 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (buf == NULL) || (buflen == 0) || (index == 0)) { 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate /* 297*7c478bd9Sstevel@tonic-gate * determine the length of the descriptor 298*7c478bd9Sstevel@tonic-gate */ 299*7c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, 300*7c478bd9Sstevel@tonic-gate usba_get_dflt_pipe_handle(dip), 301*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST, 302*7c478bd9Sstevel@tonic-gate USB_REQ_GET_DESCR, 303*7c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_STRING << 8 | index & 0xff, 304*7c478bd9Sstevel@tonic-gate langid, 305*7c478bd9Sstevel@tonic-gate 4, 306*7c478bd9Sstevel@tonic-gate &data, USB_ATTRS_SHORT_XFER_OK, 307*7c478bd9Sstevel@tonic-gate &completion_reason, 308*7c478bd9Sstevel@tonic-gate &cb_flags, USB_FLAGS_SLEEP); 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 311*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 312*7c478bd9Sstevel@tonic-gate "rval=%d cr=%d", rval, completion_reason); 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate goto done; 315*7c478bd9Sstevel@tonic-gate } 316*7c478bd9Sstevel@tonic-gate if (data->b_wptr - data->b_rptr == 0) { 317*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 318*7c478bd9Sstevel@tonic-gate "0 bytes received"); 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate goto done; 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate ASSERT(data); 324*7c478bd9Sstevel@tonic-gate length = *(data->b_rptr); 325*7c478bd9Sstevel@tonic-gate freemsg(data); 326*7c478bd9Sstevel@tonic-gate data = NULL; 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 329*7c478bd9Sstevel@tonic-gate "rval=%d, cr=%d, length=%d", rval, completion_reason, length); 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* 332*7c478bd9Sstevel@tonic-gate * if length is zero the next control request may fail. 333*7c478bd9Sstevel@tonic-gate * the HCD may not support a zero length control request 334*7c478bd9Sstevel@tonic-gate * and return an mblk_t which is NULL along with rval 335*7c478bd9Sstevel@tonic-gate * being USB_SUCCESS and "cr" being USB_CR_OK 336*7c478bd9Sstevel@tonic-gate */ 337*7c478bd9Sstevel@tonic-gate if (length < 2) { 338*7c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate goto done; 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, 344*7c478bd9Sstevel@tonic-gate usba_get_dflt_pipe_handle(dip), 345*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST, 346*7c478bd9Sstevel@tonic-gate USB_REQ_GET_DESCR, 347*7c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_STRING << 8 | index & 0xff, 348*7c478bd9Sstevel@tonic-gate langid, 349*7c478bd9Sstevel@tonic-gate length, 350*7c478bd9Sstevel@tonic-gate &data, USB_ATTRS_SHORT_XFER_OK, 351*7c478bd9Sstevel@tonic-gate &completion_reason, 352*7c478bd9Sstevel@tonic-gate &cb_flags, USB_FLAGS_SLEEP); 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 355*7c478bd9Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason); 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate if ((data == NULL) || (rval != USB_SUCCESS)) { 358*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 359*7c478bd9Sstevel@tonic-gate "failed to get string descriptor (rval=%d cr=%d)", 360*7c478bd9Sstevel@tonic-gate rval, completion_reason); 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate goto done; 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate if ((length = data->b_wptr - data->b_rptr) != 0) { 366*7c478bd9Sstevel@tonic-gate len = usba_ascii_string_descr(data->b_rptr, length, buf, 367*7c478bd9Sstevel@tonic-gate buflen); 368*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, 369*7c478bd9Sstevel@tonic-gate usbai_log_handle, "buf=%s buflen=%lu", buf, len); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate ASSERT(len <= buflen); 372*7c478bd9Sstevel@tonic-gate } else { 373*7c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate done: 376*7c478bd9Sstevel@tonic-gate freemsg(data); 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate return (rval); 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate /* 383*7c478bd9Sstevel@tonic-gate * usb_get_dev_descr: 384*7c478bd9Sstevel@tonic-gate * utility function to get device descriptor from usba_device 385*7c478bd9Sstevel@tonic-gate * 386*7c478bd9Sstevel@tonic-gate * Arguments: 387*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 388*7c478bd9Sstevel@tonic-gate * 389*7c478bd9Sstevel@tonic-gate * Return Values: 390*7c478bd9Sstevel@tonic-gate * usb_dev_descr - device descriptor or NULL 391*7c478bd9Sstevel@tonic-gate */ 392*7c478bd9Sstevel@tonic-gate usb_dev_descr_t * 393*7c478bd9Sstevel@tonic-gate usb_get_dev_descr(dev_info_t *dip) 394*7c478bd9Sstevel@tonic-gate { 395*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 396*7c478bd9Sstevel@tonic-gate usb_dev_descr_t *usb_dev_descr = NULL; 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate if (dip) { 399*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 400*7c478bd9Sstevel@tonic-gate "usb_get_dev_descr: %s", ddi_node_name(dip)); 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 403*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 404*7c478bd9Sstevel@tonic-gate usb_dev_descr = usba_device->usb_dev_descr; 405*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate return (usb_dev_descr); 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate /* 413*7c478bd9Sstevel@tonic-gate * usb_get_raw_cfg_data: 414*7c478bd9Sstevel@tonic-gate * utility function to get raw config descriptor from usba_device 415*7c478bd9Sstevel@tonic-gate * 416*7c478bd9Sstevel@tonic-gate * Arguments: 417*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 418*7c478bd9Sstevel@tonic-gate * length - pointer to copy the cfg length 419*7c478bd9Sstevel@tonic-gate * 420*7c478bd9Sstevel@tonic-gate * Return Values: 421*7c478bd9Sstevel@tonic-gate * usb_cfg - raw config descriptor 422*7c478bd9Sstevel@tonic-gate */ 423*7c478bd9Sstevel@tonic-gate uchar_t * 424*7c478bd9Sstevel@tonic-gate usb_get_raw_cfg_data(dev_info_t *dip, size_t *length) 425*7c478bd9Sstevel@tonic-gate { 426*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 427*7c478bd9Sstevel@tonic-gate uchar_t *usb_cfg; 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 430*7c478bd9Sstevel@tonic-gate "usb_get_raw_cfg_data: %s", ddi_node_name(dip)); 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (length == NULL)) { 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate return (NULL); 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 440*7c478bd9Sstevel@tonic-gate usb_cfg = usba_device->usb_cfg; 441*7c478bd9Sstevel@tonic-gate *length = usba_device->usb_cfg_length; 442*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate return (usb_cfg); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate /* 449*7c478bd9Sstevel@tonic-gate * usb_get_addr: 450*7c478bd9Sstevel@tonic-gate * utility function to return current usb address, mostly 451*7c478bd9Sstevel@tonic-gate * for debugging purposes 452*7c478bd9Sstevel@tonic-gate * 453*7c478bd9Sstevel@tonic-gate * Arguments: 454*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 455*7c478bd9Sstevel@tonic-gate * 456*7c478bd9Sstevel@tonic-gate * Return Values: 457*7c478bd9Sstevel@tonic-gate * address - USB Device Address 458*7c478bd9Sstevel@tonic-gate */ 459*7c478bd9Sstevel@tonic-gate int 460*7c478bd9Sstevel@tonic-gate usb_get_addr(dev_info_t *dip) 461*7c478bd9Sstevel@tonic-gate { 462*7c478bd9Sstevel@tonic-gate int address = 0; 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 465*7c478bd9Sstevel@tonic-gate "usb_get_addr: %s", ddi_node_name(dip)); 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate if (dip) { 468*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 471*7c478bd9Sstevel@tonic-gate address = usba_device->usb_addr; 472*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 473*7c478bd9Sstevel@tonic-gate } 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate return (address); 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate /* 480*7c478bd9Sstevel@tonic-gate * usb_set_cfg(): 481*7c478bd9Sstevel@tonic-gate * set configuration, use with caution (issues USB_REQ_SET_CONFIG) 482*7c478bd9Sstevel@tonic-gate * Changing configuration will fail if pipes are still open or when 483*7c478bd9Sstevel@tonic-gate * invoked from a driver bound to an interface on a composite device. 484*7c478bd9Sstevel@tonic-gate * 485*7c478bd9Sstevel@tonic-gate * This function will access the device and block 486*7c478bd9Sstevel@tonic-gate * 487*7c478bd9Sstevel@tonic-gate * Arguments: 488*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 489*7c478bd9Sstevel@tonic-gate * cfg_index - config index 490*7c478bd9Sstevel@tonic-gate * cfg_value - config value to be set 491*7c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP: 492*7c478bd9Sstevel@tonic-gate * wait for completion 493*7c478bd9Sstevel@tonic-gate * cb - if USB_FLAGS_SLEEP has not been specified 494*7c478bd9Sstevel@tonic-gate * this callback function will be called on 495*7c478bd9Sstevel@tonic-gate * completion. This callback may be NULL 496*7c478bd9Sstevel@tonic-gate * and no notification of completion will then 497*7c478bd9Sstevel@tonic-gate * be provided. 498*7c478bd9Sstevel@tonic-gate * cb_arg - 2nd argument to callback function. 499*7c478bd9Sstevel@tonic-gate * 500*7c478bd9Sstevel@tonic-gate * Return Values: 501*7c478bd9Sstevel@tonic-gate * USB_SUCCESS: - new configuration was set 502*7c478bd9Sstevel@tonic-gate * USB_FAILURE: - new configuration could not be set 503*7c478bd9Sstevel@tonic-gate * USB_BUSY: - some pipes were open or there were children 504*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 505*7c478bd9Sstevel@tonic-gate */ 506*7c478bd9Sstevel@tonic-gate int 507*7c478bd9Sstevel@tonic-gate usb_set_cfg(dev_info_t *dip, 508*7c478bd9Sstevel@tonic-gate uint_t cfg_index, 509*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 510*7c478bd9Sstevel@tonic-gate void (*cb)( 511*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 512*7c478bd9Sstevel@tonic-gate usb_opaque_t arg, 513*7c478bd9Sstevel@tonic-gate int rval, 514*7c478bd9Sstevel@tonic-gate usb_cb_flags_t flags), 515*7c478bd9Sstevel@tonic-gate usb_opaque_t cb_arg) 516*7c478bd9Sstevel@tonic-gate { 517*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph; 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 520*7c478bd9Sstevel@tonic-gate "usb_set_cfg: %s%d, cfg_index = 0x%x, uf = 0x%x", 521*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), cfg_index, 522*7c478bd9Sstevel@tonic-gate usb_flags); 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate if (dip == NULL) { 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 527*7c478bd9Sstevel@tonic-gate } 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) { 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT); 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate if (!usb_owns_device(dip)) { 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PERM); 537*7c478bd9Sstevel@tonic-gate } 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip); 540*7c478bd9Sstevel@tonic-gate if (usba_hold_ph_data(ph) == NULL) { 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 543*7c478bd9Sstevel@tonic-gate } 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate return (usba_pipe_setup_func_call(dip, 546*7c478bd9Sstevel@tonic-gate usba_sync_set_cfg, (usba_ph_impl_t *)ph, 547*7c478bd9Sstevel@tonic-gate (usb_opaque_t)((uintptr_t)cfg_index), usb_flags, cb, cb_arg)); 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate static int 552*7c478bd9Sstevel@tonic-gate usba_sync_set_cfg(dev_info_t *dip, 553*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl, 554*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request, 555*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 556*7c478bd9Sstevel@tonic-gate { 557*7c478bd9Sstevel@tonic-gate int rval; 558*7c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 559*7c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 560*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 561*7c478bd9Sstevel@tonic-gate int i, ph_open_cnt; 562*7c478bd9Sstevel@tonic-gate uint_t cfg_index = (uint_t)((uintptr_t)(request->arg)); 563*7c478bd9Sstevel@tonic-gate size_t size; 564*7c478bd9Sstevel@tonic-gate usb_cfg_descr_t confdescr; 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate /* 569*7c478bd9Sstevel@tonic-gate * default pipe is still open 570*7c478bd9Sstevel@tonic-gate * all other pipes should be closed 571*7c478bd9Sstevel@tonic-gate */ 572*7c478bd9Sstevel@tonic-gate for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) { 573*7c478bd9Sstevel@tonic-gate if (usba_device->usb_ph_list[i].usba_ph_data) { 574*7c478bd9Sstevel@tonic-gate ph_open_cnt++; 575*7c478bd9Sstevel@tonic-gate break; 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate } 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate if (ph_open_cnt || ddi_get_child(dip)) { 580*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate return (USB_BUSY); 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate size = usb_parse_cfg_descr(usba_device->usb_cfg_array[cfg_index], 586*7c478bd9Sstevel@tonic-gate USB_CFG_DESCR_SIZE, &confdescr, USB_CFG_DESCR_SIZE); 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate /* hubdi should ensure that this descriptor is correct */ 589*7c478bd9Sstevel@tonic-gate ASSERT(size == USB_CFG_DESCR_SIZE); 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate /* set the configuration */ 592*7c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, (usb_pipe_handle_t)ph_impl, 593*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_HOST_TO_DEV, 594*7c478bd9Sstevel@tonic-gate USB_REQ_SET_CFG, 595*7c478bd9Sstevel@tonic-gate confdescr.bConfigurationValue, 596*7c478bd9Sstevel@tonic-gate 0, 597*7c478bd9Sstevel@tonic-gate 0, 598*7c478bd9Sstevel@tonic-gate NULL, 0, 599*7c478bd9Sstevel@tonic-gate &completion_reason, 600*7c478bd9Sstevel@tonic-gate &cb_flags, flags | USBA_FLAGS_PRIVILEGED | USB_FLAGS_SLEEP); 601*7c478bd9Sstevel@tonic-gate 602*7c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 603*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 604*7c478bd9Sstevel@tonic-gate usba_device->usb_cfg_value = confdescr.bConfigurationValue; 605*7c478bd9Sstevel@tonic-gate usba_device->usb_active_cfg_ndx = cfg_index; 606*7c478bd9Sstevel@tonic-gate usba_device->usb_cfg = usba_device->usb_cfg_array[cfg_index]; 607*7c478bd9Sstevel@tonic-gate usba_device->usb_cfg_length = confdescr.wTotalLength; 608*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate /* update the configuration property */ 611*7c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 612*7c478bd9Sstevel@tonic-gate "configuration#", usba_device->usb_cfg_value); 613*7c478bd9Sstevel@tonic-gate } 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 616*7c478bd9Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason); 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate return (rval); 621*7c478bd9Sstevel@tonic-gate } 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate /* 626*7c478bd9Sstevel@tonic-gate * usb_get_cfg(): 627*7c478bd9Sstevel@tonic-gate * get configuration value 628*7c478bd9Sstevel@tonic-gate * 629*7c478bd9Sstevel@tonic-gate * Arguments: 630*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 631*7c478bd9Sstevel@tonic-gate * cfg_value - current config value 632*7c478bd9Sstevel@tonic-gate * flags - none, always blocks 633*7c478bd9Sstevel@tonic-gate * 634*7c478bd9Sstevel@tonic-gate * Return Values: 635*7c478bd9Sstevel@tonic-gate * USB_SUCCESS: - config value was retrieved 636*7c478bd9Sstevel@tonic-gate * USB_FAILURE: - config value could not be retrieved 637*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 638*7c478bd9Sstevel@tonic-gate */ 639*7c478bd9Sstevel@tonic-gate int 640*7c478bd9Sstevel@tonic-gate usb_get_cfg(dev_info_t *dip, 641*7c478bd9Sstevel@tonic-gate uint_t *cfgval, 642*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 643*7c478bd9Sstevel@tonic-gate { 644*7c478bd9Sstevel@tonic-gate int rval; 645*7c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 646*7c478bd9Sstevel@tonic-gate mblk_t *data = NULL; 647*7c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 648*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph; 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 651*7c478bd9Sstevel@tonic-gate "usb_get_cfg: %s uf = 0x%x", ddi_node_name(dip), flags); 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate if ((cfgval == NULL) || (dip == NULL)) { 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 656*7c478bd9Sstevel@tonic-gate } 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip); 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate /* 661*7c478bd9Sstevel@tonic-gate * get the cfg value 662*7c478bd9Sstevel@tonic-gate */ 663*7c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph, 664*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_DEV, 665*7c478bd9Sstevel@tonic-gate USB_REQ_GET_CFG, 666*7c478bd9Sstevel@tonic-gate 0, 667*7c478bd9Sstevel@tonic-gate 0, 668*7c478bd9Sstevel@tonic-gate 1, /* returns one byte of data */ 669*7c478bd9Sstevel@tonic-gate &data, 0, 670*7c478bd9Sstevel@tonic-gate &completion_reason, 671*7c478bd9Sstevel@tonic-gate &cb_flags, flags); 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 674*7c478bd9Sstevel@tonic-gate "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason); 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate if ((rval == USB_SUCCESS) && data && 677*7c478bd9Sstevel@tonic-gate ((data->b_wptr - data->b_rptr) == 1)) { 678*7c478bd9Sstevel@tonic-gate *cfgval = *(data->b_rptr); 679*7c478bd9Sstevel@tonic-gate } else { 680*7c478bd9Sstevel@tonic-gate *cfgval = 1; 681*7c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 682*7c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 683*7c478bd9Sstevel@tonic-gate } 684*7c478bd9Sstevel@tonic-gate } 685*7c478bd9Sstevel@tonic-gate 686*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 687*7c478bd9Sstevel@tonic-gate "usb_get_cfg: %s cfgval=%d", ddi_node_name(dip), *cfgval); 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate freemsg(data); 690*7c478bd9Sstevel@tonic-gate 691*7c478bd9Sstevel@tonic-gate return (rval); 692*7c478bd9Sstevel@tonic-gate } 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate /* 696*7c478bd9Sstevel@tonic-gate * usb_get_current_cfgidx: 697*7c478bd9Sstevel@tonic-gate * get current current config index 698*7c478bd9Sstevel@tonic-gate */ 699*7c478bd9Sstevel@tonic-gate uint_t 700*7c478bd9Sstevel@tonic-gate usb_get_current_cfgidx(dev_info_t *dip) 701*7c478bd9Sstevel@tonic-gate { 702*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 703*7c478bd9Sstevel@tonic-gate uint_t ndx; 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 706*7c478bd9Sstevel@tonic-gate ndx = usba_device->usb_active_cfg_ndx; 707*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate return (ndx); 710*7c478bd9Sstevel@tonic-gate } 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate /* 714*7c478bd9Sstevel@tonic-gate * usb_get_if_number: 715*7c478bd9Sstevel@tonic-gate * get usb interface number of current OS device node. 716*7c478bd9Sstevel@tonic-gate * 717*7c478bd9Sstevel@tonic-gate * Arguments: 718*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 719*7c478bd9Sstevel@tonic-gate * 720*7c478bd9Sstevel@tonic-gate * Return Values: 721*7c478bd9Sstevel@tonic-gate * USB_COMBINED_NODE if the driver is responsible for the entire 722*7c478bd9Sstevel@tonic-gate * device and this dip doesn't correspond to a device node. 723*7c478bd9Sstevel@tonic-gate * USB_DEVICE_NODE if the driver is responsible for the entire device 724*7c478bd9Sstevel@tonic-gate * and this dip corresponds to a device node. 725*7c478bd9Sstevel@tonic-gate * interface number: otherwise. 726*7c478bd9Sstevel@tonic-gate */ 727*7c478bd9Sstevel@tonic-gate int 728*7c478bd9Sstevel@tonic-gate usb_get_if_number(dev_info_t *dip) 729*7c478bd9Sstevel@tonic-gate { 730*7c478bd9Sstevel@tonic-gate int interface_num; 731*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 732*7c478bd9Sstevel@tonic-gate usb_dev_descr_t *usb_dev_descr; 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 735*7c478bd9Sstevel@tonic-gate "usb_get_if_number: dip = 0x%p", dip); 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate /* not quite right but we can't return a negative return value */ 738*7c478bd9Sstevel@tonic-gate if (dip == NULL) { 739*7c478bd9Sstevel@tonic-gate 740*7c478bd9Sstevel@tonic-gate return (0); 741*7c478bd9Sstevel@tonic-gate } 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate if (usba_device) { 744*7c478bd9Sstevel@tonic-gate usb_dev_descr = usba_device->usb_dev_descr; 745*7c478bd9Sstevel@tonic-gate } else { 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate return (0); 748*7c478bd9Sstevel@tonic-gate } 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate interface_num = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 751*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "interface", USB_COMBINED_NODE); 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate if (interface_num == USB_COMBINED_NODE) { 754*7c478bd9Sstevel@tonic-gate if (!(((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) || 755*7c478bd9Sstevel@tonic-gate (usb_dev_descr->bDeviceClass == 0)) && 756*7c478bd9Sstevel@tonic-gate (usba_device->usb_n_cfgs == 1) && 757*7c478bd9Sstevel@tonic-gate (usba_device->usb_n_ifs == 1))) { 758*7c478bd9Sstevel@tonic-gate interface_num = USB_DEVICE_NODE; 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate } 761*7c478bd9Sstevel@tonic-gate 762*7c478bd9Sstevel@tonic-gate return (interface_num); 763*7c478bd9Sstevel@tonic-gate } 764*7c478bd9Sstevel@tonic-gate 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate boolean_t 767*7c478bd9Sstevel@tonic-gate usb_owns_device(dev_info_t *dip) 768*7c478bd9Sstevel@tonic-gate { 769*7c478bd9Sstevel@tonic-gate int interface_num = usb_get_if_number(dip); 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate return (interface_num < 0 ? B_TRUE : B_FALSE); 772*7c478bd9Sstevel@tonic-gate } 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate uint8_t 776*7c478bd9Sstevel@tonic-gate usba_get_ifno(dev_info_t *dip) 777*7c478bd9Sstevel@tonic-gate { 778*7c478bd9Sstevel@tonic-gate int interface_num = usb_get_if_number(dip); 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate return (interface_num < 0 ? 0 : interface_num); 781*7c478bd9Sstevel@tonic-gate } 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate /* 785*7c478bd9Sstevel@tonic-gate * usb_set_alt_if: 786*7c478bd9Sstevel@tonic-gate * set the alternate interface number. Issues USB_REQ_SET_IF 787*7c478bd9Sstevel@tonic-gate * This function will access the device 788*7c478bd9Sstevel@tonic-gate * 789*7c478bd9Sstevel@tonic-gate * Arguments: 790*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 791*7c478bd9Sstevel@tonic-gate * if_number - interface number 792*7c478bd9Sstevel@tonic-gate * alt_number - alternate interface number 793*7c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP: 794*7c478bd9Sstevel@tonic-gate * wait for completion 795*7c478bd9Sstevel@tonic-gate * cb - if USB_FLAGS_SLEEP has not been specified 796*7c478bd9Sstevel@tonic-gate * this callback function will be called on 797*7c478bd9Sstevel@tonic-gate * completion. This callback may be NULL 798*7c478bd9Sstevel@tonic-gate * and no notification of completion will then 799*7c478bd9Sstevel@tonic-gate * be provided. 800*7c478bd9Sstevel@tonic-gate * cb_arg - 2nd argument to callback function. 801*7c478bd9Sstevel@tonic-gate * 802*7c478bd9Sstevel@tonic-gate * 803*7c478bd9Sstevel@tonic-gate * return values: 804*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - alternate was set 805*7c478bd9Sstevel@tonic-gate * USB_FAILURE - alternate could not be set because pipes 806*7c478bd9Sstevel@tonic-gate * were still open or some access error occurred 807*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 808*7c478bd9Sstevel@tonic-gate * 809*7c478bd9Sstevel@tonic-gate * Note: 810*7c478bd9Sstevel@tonic-gate * we can't easily check if all pipes to endpoints for this interface 811*7c478bd9Sstevel@tonic-gate * are closed since we don't have a map of which endpoints belong 812*7c478bd9Sstevel@tonic-gate * to which interface. If we had this map, we would need to update 813*7c478bd9Sstevel@tonic-gate * this on each alternative or configuration switch 814*7c478bd9Sstevel@tonic-gate */ 815*7c478bd9Sstevel@tonic-gate int 816*7c478bd9Sstevel@tonic-gate usb_set_alt_if(dev_info_t *dip, 817*7c478bd9Sstevel@tonic-gate uint_t interface, 818*7c478bd9Sstevel@tonic-gate uint_t alt_number, 819*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 820*7c478bd9Sstevel@tonic-gate void (*cb)( 821*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 822*7c478bd9Sstevel@tonic-gate usb_opaque_t arg, 823*7c478bd9Sstevel@tonic-gate int rval, 824*7c478bd9Sstevel@tonic-gate usb_cb_flags_t flags), 825*7c478bd9Sstevel@tonic-gate usb_opaque_t cb_arg) 826*7c478bd9Sstevel@tonic-gate { 827*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph; 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 830*7c478bd9Sstevel@tonic-gate "usb_set_alt_if: %s%d, if = %d alt = %d, uf = 0x%x", 831*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 832*7c478bd9Sstevel@tonic-gate interface, alt_number, usb_flags); 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate if (dip == NULL) { 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 837*7c478bd9Sstevel@tonic-gate } 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) { 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT); 842*7c478bd9Sstevel@tonic-gate } 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip); 845*7c478bd9Sstevel@tonic-gate if (usba_hold_ph_data(ph) == NULL) { 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 848*7c478bd9Sstevel@tonic-gate } 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate return (usba_pipe_setup_func_call(dip, 851*7c478bd9Sstevel@tonic-gate usba_sync_set_alt_if, (usba_ph_impl_t *)ph, 852*7c478bd9Sstevel@tonic-gate (usb_opaque_t)((uintptr_t)((interface << 8) | alt_number)), 853*7c478bd9Sstevel@tonic-gate usb_flags, cb, cb_arg)); 854*7c478bd9Sstevel@tonic-gate } 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate static int 858*7c478bd9Sstevel@tonic-gate usba_sync_set_alt_if(dev_info_t *dip, 859*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl, 860*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request, 861*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 862*7c478bd9Sstevel@tonic-gate { 863*7c478bd9Sstevel@tonic-gate int rval; 864*7c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 865*7c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 866*7c478bd9Sstevel@tonic-gate usb_opaque_t arg = request->arg; 867*7c478bd9Sstevel@tonic-gate int interface = ((uintptr_t)arg >> 8) & 0xff; 868*7c478bd9Sstevel@tonic-gate int alt_number = (uintptr_t)arg & 0xff; 869*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data( 870*7c478bd9Sstevel@tonic-gate (usb_pipe_handle_t)ph_impl); 871*7c478bd9Sstevel@tonic-gate 872*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 873*7c478bd9Sstevel@tonic-gate "usb_set_alt_if: %s, interface#=0x%x, alt#=0x%x, " 874*7c478bd9Sstevel@tonic-gate "uf=0x%x", ddi_node_name(dip), interface, 875*7c478bd9Sstevel@tonic-gate alt_number, flags); 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate /* if we don't own the device, we must own the interface */ 878*7c478bd9Sstevel@tonic-gate if (!usb_owns_device(dip) && 879*7c478bd9Sstevel@tonic-gate (interface != usb_get_if_number(dip))) { 880*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PERM); 883*7c478bd9Sstevel@tonic-gate } 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate /* set the alternate setting */ 886*7c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, usba_get_dflt_pipe_handle(dip), 887*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF, 888*7c478bd9Sstevel@tonic-gate USB_REQ_SET_IF, 889*7c478bd9Sstevel@tonic-gate alt_number, 890*7c478bd9Sstevel@tonic-gate interface, 891*7c478bd9Sstevel@tonic-gate 0, 892*7c478bd9Sstevel@tonic-gate NULL, 0, 893*7c478bd9Sstevel@tonic-gate &completion_reason, 894*7c478bd9Sstevel@tonic-gate &cb_flags, flags | USB_FLAGS_SLEEP); 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 897*7c478bd9Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason); 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate return (rval); 902*7c478bd9Sstevel@tonic-gate } 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate /* 906*7c478bd9Sstevel@tonic-gate * usb_get_alt_if: 907*7c478bd9Sstevel@tonic-gate * get the alternate interface number. Issues USB_REQ_GET_IF 908*7c478bd9Sstevel@tonic-gate * This function will access the device and block 909*7c478bd9Sstevel@tonic-gate * 910*7c478bd9Sstevel@tonic-gate * Arguments: 911*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 912*7c478bd9Sstevel@tonic-gate * if_number - interface number 913*7c478bd9Sstevel@tonic-gate * alt_number - alternate interface number 914*7c478bd9Sstevel@tonic-gate * flags - none but USB_FLAGS_SLEEP may be passed 915*7c478bd9Sstevel@tonic-gate * 916*7c478bd9Sstevel@tonic-gate * return values: 917*7c478bd9Sstevel@tonic-gate * USB_SUCCESS: alternate was set 918*7c478bd9Sstevel@tonic-gate * USB_FAILURE: alternate could not be set because pipes 919*7c478bd9Sstevel@tonic-gate * were still open or some access error occurred 920*7c478bd9Sstevel@tonic-gate */ 921*7c478bd9Sstevel@tonic-gate int 922*7c478bd9Sstevel@tonic-gate usb_get_alt_if(dev_info_t *dip, 923*7c478bd9Sstevel@tonic-gate uint_t if_number, 924*7c478bd9Sstevel@tonic-gate uint_t *alt_number, 925*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 926*7c478bd9Sstevel@tonic-gate { 927*7c478bd9Sstevel@tonic-gate int rval; 928*7c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 929*7c478bd9Sstevel@tonic-gate mblk_t *data = NULL; 930*7c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 931*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph; 932*7c478bd9Sstevel@tonic-gate 933*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 934*7c478bd9Sstevel@tonic-gate "usb_get_alt_if: %s, interface# = 0x%x, altp = 0x%p, " 935*7c478bd9Sstevel@tonic-gate "uf = 0x%x", ddi_node_name(dip), if_number, 936*7c478bd9Sstevel@tonic-gate alt_number, flags); 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate if ((alt_number == NULL) || (dip == NULL)) { 939*7c478bd9Sstevel@tonic-gate 940*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 941*7c478bd9Sstevel@tonic-gate } 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip); 944*7c478bd9Sstevel@tonic-gate 945*7c478bd9Sstevel@tonic-gate /* 946*7c478bd9Sstevel@tonic-gate * get the alternate setting 947*7c478bd9Sstevel@tonic-gate */ 948*7c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph, 949*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_IF, 950*7c478bd9Sstevel@tonic-gate USB_REQ_GET_IF, 951*7c478bd9Sstevel@tonic-gate 0, 952*7c478bd9Sstevel@tonic-gate if_number, 953*7c478bd9Sstevel@tonic-gate 1, /* returns one byte of data */ 954*7c478bd9Sstevel@tonic-gate &data, 0, 955*7c478bd9Sstevel@tonic-gate &completion_reason, 956*7c478bd9Sstevel@tonic-gate &cb_flags, flags); 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 959*7c478bd9Sstevel@tonic-gate "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason); 960*7c478bd9Sstevel@tonic-gate 961*7c478bd9Sstevel@tonic-gate if ((rval == USB_SUCCESS) && data && 962*7c478bd9Sstevel@tonic-gate ((data->b_wptr - data->b_rptr) == 1)) { 963*7c478bd9Sstevel@tonic-gate *alt_number = *(data->b_rptr); 964*7c478bd9Sstevel@tonic-gate } else { 965*7c478bd9Sstevel@tonic-gate *alt_number = 0; 966*7c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 967*7c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate } 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate freemsg(data); 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate return (rval); 974*7c478bd9Sstevel@tonic-gate } 975*7c478bd9Sstevel@tonic-gate 976*7c478bd9Sstevel@tonic-gate 977*7c478bd9Sstevel@tonic-gate /* 978*7c478bd9Sstevel@tonic-gate * usba_get_cfg_cloud: 979*7c478bd9Sstevel@tonic-gate * Get descriptor cloud for a given configuration. 980*7c478bd9Sstevel@tonic-gate * 981*7c478bd9Sstevel@tonic-gate * Arguments: 982*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 983*7c478bd9Sstevel@tonic-gate * default_ph - default pipe handle 984*7c478bd9Sstevel@tonic-gate * cfg - which configuration to retrieve raw cloud of 985*7c478bd9Sstevel@tonic-gate * 986*7c478bd9Sstevel@tonic-gate * Returns: 987*7c478bd9Sstevel@tonic-gate * on success: mblock containing the raw data. Caller must free. 988*7c478bd9Sstevel@tonic-gate * on failure: NULL 989*7c478bd9Sstevel@tonic-gate */ 990*7c478bd9Sstevel@tonic-gate static mblk_t * 991*7c478bd9Sstevel@tonic-gate usba_get_cfg_cloud(dev_info_t *dip, usb_pipe_handle_t default_ph, int cfg) 992*7c478bd9Sstevel@tonic-gate { 993*7c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 994*7c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 995*7c478bd9Sstevel@tonic-gate usb_cfg_descr_t cfg_descr; 996*7c478bd9Sstevel@tonic-gate mblk_t *pdata = NULL; 997*7c478bd9Sstevel@tonic-gate 998*7c478bd9Sstevel@tonic-gate if (usb_pipe_sync_ctrl_xfer(dip, default_ph, 999*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 1000*7c478bd9Sstevel@tonic-gate USB_REQ_GET_DESCR, 1001*7c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_SETUP_CFG | cfg, 1002*7c478bd9Sstevel@tonic-gate 0, 1003*7c478bd9Sstevel@tonic-gate USB_CFG_DESCR_SIZE, 1004*7c478bd9Sstevel@tonic-gate &pdata, 1005*7c478bd9Sstevel@tonic-gate 0, 1006*7c478bd9Sstevel@tonic-gate &completion_reason, 1007*7c478bd9Sstevel@tonic-gate &cb_flags, 1008*7c478bd9Sstevel@tonic-gate 0) != USB_SUCCESS) { 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate freemsg(pdata); 1011*7c478bd9Sstevel@tonic-gate 1012*7c478bd9Sstevel@tonic-gate return (NULL); 1013*7c478bd9Sstevel@tonic-gate } 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate (void) usb_parse_cfg_descr(pdata->b_rptr, 1016*7c478bd9Sstevel@tonic-gate pdata->b_wptr - pdata->b_rptr, &cfg_descr, USB_CFG_DESCR_SIZE); 1017*7c478bd9Sstevel@tonic-gate freemsg(pdata); 1018*7c478bd9Sstevel@tonic-gate pdata = NULL; 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate if (usb_pipe_sync_ctrl_xfer(dip, default_ph, 1021*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 1022*7c478bd9Sstevel@tonic-gate USB_REQ_GET_DESCR, 1023*7c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_SETUP_CFG | cfg, 1024*7c478bd9Sstevel@tonic-gate 0, 1025*7c478bd9Sstevel@tonic-gate cfg_descr.wTotalLength, 1026*7c478bd9Sstevel@tonic-gate &pdata, 1027*7c478bd9Sstevel@tonic-gate 0, 1028*7c478bd9Sstevel@tonic-gate &completion_reason, 1029*7c478bd9Sstevel@tonic-gate &cb_flags, 1030*7c478bd9Sstevel@tonic-gate 0) != USB_SUCCESS) { 1031*7c478bd9Sstevel@tonic-gate 1032*7c478bd9Sstevel@tonic-gate freemsg(pdata); 1033*7c478bd9Sstevel@tonic-gate 1034*7c478bd9Sstevel@tonic-gate return (NULL); 1035*7c478bd9Sstevel@tonic-gate } 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate return (pdata); 1038*7c478bd9Sstevel@tonic-gate } 1039*7c478bd9Sstevel@tonic-gate 1040*7c478bd9Sstevel@tonic-gate /* 1041*7c478bd9Sstevel@tonic-gate * usb_check_same_device: 1042*7c478bd9Sstevel@tonic-gate * Check if the device connected to the port is the same as 1043*7c478bd9Sstevel@tonic-gate * the previous device that was in the port. The previous device is 1044*7c478bd9Sstevel@tonic-gate * represented by the dip on record for the port. Print a message 1045*7c478bd9Sstevel@tonic-gate * if the device is different. If device_string arg is not NULL, it is 1046*7c478bd9Sstevel@tonic-gate * included in the message. Can block. 1047*7c478bd9Sstevel@tonic-gate * 1048*7c478bd9Sstevel@tonic-gate * Arguments: 1049*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 1050*7c478bd9Sstevel@tonic-gate * log_handle - handle to which messages are logged 1051*7c478bd9Sstevel@tonic-gate * log_level - one of USB_LOG_* 1052*7c478bd9Sstevel@tonic-gate * log_mask - logging mask 1053*7c478bd9Sstevel@tonic-gate * check_mask - one mask containing things to check: 1054*7c478bd9Sstevel@tonic-gate * USB_CHK_BASIC: empty mask; 1055*7c478bd9Sstevel@tonic-gate * these checks are always done. 1056*7c478bd9Sstevel@tonic-gate * USB_CHK_VIDPID: 1057*7c478bd9Sstevel@tonic-gate * check vid, pid only. 1058*7c478bd9Sstevel@tonic-gate * USB_CHK_SERIAL: check match on device 1059*7c478bd9Sstevel@tonic-gate * serial number. 1060*7c478bd9Sstevel@tonic-gate * USB_CHK_CFG: check all raw config 1061*7c478bd9Sstevel@tonic-gate * clouds for a match. 1062*7c478bd9Sstevel@tonic-gate * NOTE: descr length and content always checked 1063*7c478bd9Sstevel@tonic-gate * device_string - Device string to appear in error message 1064*7c478bd9Sstevel@tonic-gate * 1065*7c478bd9Sstevel@tonic-gate * return values: 1066*7c478bd9Sstevel@tonic-gate * USB_SUCCESS: same device 1067*7c478bd9Sstevel@tonic-gate * USB_INVALID_VERSION not same device 1068*7c478bd9Sstevel@tonic-gate * USB_FAILURE: Failure processing request 1069*7c478bd9Sstevel@tonic-gate * USB_INVALID_ARG: dip is invalid 1070*7c478bd9Sstevel@tonic-gate */ 1071*7c478bd9Sstevel@tonic-gate int 1072*7c478bd9Sstevel@tonic-gate usb_check_same_device(dev_info_t *dip, usb_log_handle_t log_handle, 1073*7c478bd9Sstevel@tonic-gate int log_level, int log_mask, uint_t check_mask, char *device_string) 1074*7c478bd9Sstevel@tonic-gate { 1075*7c478bd9Sstevel@tonic-gate usb_dev_descr_t usb_dev_descr; 1076*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 1077*7c478bd9Sstevel@tonic-gate mblk_t *pdata = NULL; 1078*7c478bd9Sstevel@tonic-gate uint16_t length; 1079*7c478bd9Sstevel@tonic-gate int rval; 1080*7c478bd9Sstevel@tonic-gate char *buf; 1081*7c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 1082*7c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 1083*7c478bd9Sstevel@tonic-gate boolean_t match = B_TRUE; 1084*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t def_ph; 1085*7c478bd9Sstevel@tonic-gate 1086*7c478bd9Sstevel@tonic-gate if (dip == NULL) { 1087*7c478bd9Sstevel@tonic-gate 1088*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1089*7c478bd9Sstevel@tonic-gate } 1090*7c478bd9Sstevel@tonic-gate 1091*7c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 1092*7c478bd9Sstevel@tonic-gate length = usba_device->usb_dev_descr->bLength; 1093*7c478bd9Sstevel@tonic-gate def_ph = usba_get_dflt_pipe_handle(dip); 1094*7c478bd9Sstevel@tonic-gate ASSERT(def_ph); 1095*7c478bd9Sstevel@tonic-gate 1096*7c478bd9Sstevel@tonic-gate /* get the "new" device descriptor */ 1097*7c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, def_ph, 1098*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | 1099*7c478bd9Sstevel@tonic-gate USB_DEV_REQ_TYPE_STANDARD, 1100*7c478bd9Sstevel@tonic-gate USB_REQ_GET_DESCR, /* bRequest */ 1101*7c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 1102*7c478bd9Sstevel@tonic-gate 0, /* wIndex */ 1103*7c478bd9Sstevel@tonic-gate length, /* wLength */ 1104*7c478bd9Sstevel@tonic-gate &pdata, 0, 1105*7c478bd9Sstevel@tonic-gate &completion_reason, 1106*7c478bd9Sstevel@tonic-gate &cb_flags, USB_FLAGS_SLEEP); 1107*7c478bd9Sstevel@tonic-gate 1108*7c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 1109*7c478bd9Sstevel@tonic-gate if (!((completion_reason == USB_CR_DATA_OVERRUN) && (pdata))) { 1110*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usbai_log_handle, 1111*7c478bd9Sstevel@tonic-gate "getting device descriptor failed (%d)", rval); 1112*7c478bd9Sstevel@tonic-gate freemsg(pdata); 1113*7c478bd9Sstevel@tonic-gate 1114*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1115*7c478bd9Sstevel@tonic-gate } 1116*7c478bd9Sstevel@tonic-gate } 1117*7c478bd9Sstevel@tonic-gate 1118*7c478bd9Sstevel@tonic-gate ASSERT(pdata != NULL); 1119*7c478bd9Sstevel@tonic-gate 1120*7c478bd9Sstevel@tonic-gate (void) usb_parse_dev_descr(pdata->b_rptr, 1121*7c478bd9Sstevel@tonic-gate pdata->b_wptr - pdata->b_rptr, &usb_dev_descr, 1122*7c478bd9Sstevel@tonic-gate sizeof (usb_dev_descr_t)); 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate freemsg(pdata); 1125*7c478bd9Sstevel@tonic-gate pdata = NULL; 1126*7c478bd9Sstevel@tonic-gate 1127*7c478bd9Sstevel@tonic-gate /* Always check the device descriptor length. */ 1128*7c478bd9Sstevel@tonic-gate if (usb_dev_descr.bLength != length) { 1129*7c478bd9Sstevel@tonic-gate match = B_FALSE; 1130*7c478bd9Sstevel@tonic-gate } 1131*7c478bd9Sstevel@tonic-gate 1132*7c478bd9Sstevel@tonic-gate if ((match == B_TRUE) && (check_mask & USB_CHK_VIDPID)) { 1133*7c478bd9Sstevel@tonic-gate match = (usba_device->usb_dev_descr->idVendor == 1134*7c478bd9Sstevel@tonic-gate usb_dev_descr.idVendor) && 1135*7c478bd9Sstevel@tonic-gate (usba_device->usb_dev_descr->idProduct == 1136*7c478bd9Sstevel@tonic-gate usb_dev_descr.idProduct); 1137*7c478bd9Sstevel@tonic-gate } else if (bcmp((char *)usba_device->usb_dev_descr, 1138*7c478bd9Sstevel@tonic-gate (char *)&usb_dev_descr, length) != 0) { 1139*7c478bd9Sstevel@tonic-gate match = B_FALSE; 1140*7c478bd9Sstevel@tonic-gate } 1141*7c478bd9Sstevel@tonic-gate 1142*7c478bd9Sstevel@tonic-gate /* if requested & this device has a serial number check and compare */ 1143*7c478bd9Sstevel@tonic-gate if ((match == B_TRUE) && ((check_mask & USB_CHK_SERIAL) != 0) && 1144*7c478bd9Sstevel@tonic-gate (usba_device->usb_serialno_str != NULL)) { 1145*7c478bd9Sstevel@tonic-gate buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP); 1146*7c478bd9Sstevel@tonic-gate if (usb_get_string_descr(dip, USB_LANG_ID, 1147*7c478bd9Sstevel@tonic-gate usb_dev_descr.iSerialNumber, buf, 1148*7c478bd9Sstevel@tonic-gate USB_MAXSTRINGLEN) == USB_SUCCESS) { 1149*7c478bd9Sstevel@tonic-gate match = 1150*7c478bd9Sstevel@tonic-gate (strcmp(buf, usba_device->usb_serialno_str) == 0); 1151*7c478bd9Sstevel@tonic-gate } 1152*7c478bd9Sstevel@tonic-gate kmem_free(buf, USB_MAXSTRINGLEN); 1153*7c478bd9Sstevel@tonic-gate } 1154*7c478bd9Sstevel@tonic-gate 1155*7c478bd9Sstevel@tonic-gate if ((match == B_TRUE) && (check_mask & USB_CHK_CFG)) { 1156*7c478bd9Sstevel@tonic-gate 1157*7c478bd9Sstevel@tonic-gate uint8_t num_cfgs = usb_dev_descr.bNumConfigurations; 1158*7c478bd9Sstevel@tonic-gate uint8_t cfg; 1159*7c478bd9Sstevel@tonic-gate mblk_t *cloud; 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate for (cfg = 0; cfg < num_cfgs; cfg++) { 1162*7c478bd9Sstevel@tonic-gate cloud = usba_get_cfg_cloud(dip, def_ph, cfg); 1163*7c478bd9Sstevel@tonic-gate if (cloud == NULL) { 1164*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, 1165*7c478bd9Sstevel@tonic-gate usbai_log_handle, 1166*7c478bd9Sstevel@tonic-gate "Could not retrieve config cloud for " 1167*7c478bd9Sstevel@tonic-gate "comparison"); 1168*7c478bd9Sstevel@tonic-gate break; 1169*7c478bd9Sstevel@tonic-gate } 1170*7c478bd9Sstevel@tonic-gate 1171*7c478bd9Sstevel@tonic-gate if (bcmp((char *)cloud->b_rptr, 1172*7c478bd9Sstevel@tonic-gate usba_device->usb_cfg_array[cfg], 1173*7c478bd9Sstevel@tonic-gate cloud->b_wptr - cloud->b_rptr) != 0) { 1174*7c478bd9Sstevel@tonic-gate freemsg(cloud); 1175*7c478bd9Sstevel@tonic-gate break; 1176*7c478bd9Sstevel@tonic-gate } 1177*7c478bd9Sstevel@tonic-gate 1178*7c478bd9Sstevel@tonic-gate freemsg(cloud); 1179*7c478bd9Sstevel@tonic-gate } 1180*7c478bd9Sstevel@tonic-gate if (cfg != num_cfgs) { 1181*7c478bd9Sstevel@tonic-gate match = B_FALSE; 1182*7c478bd9Sstevel@tonic-gate } 1183*7c478bd9Sstevel@tonic-gate } 1184*7c478bd9Sstevel@tonic-gate 1185*7c478bd9Sstevel@tonic-gate if (match == B_FALSE) { 1186*7c478bd9Sstevel@tonic-gate boolean_t allocated_here = (device_string == NULL); 1187*7c478bd9Sstevel@tonic-gate if (allocated_here) { 1188*7c478bd9Sstevel@tonic-gate device_string = 1189*7c478bd9Sstevel@tonic-gate kmem_zalloc(USB_MAXSTRINGLEN, USB_FLAGS_SLEEP); 1190*7c478bd9Sstevel@tonic-gate (void) usba_get_mfg_prod_sn_str(dip, device_string, 1191*7c478bd9Sstevel@tonic-gate USB_MAXSTRINGLEN); 1192*7c478bd9Sstevel@tonic-gate } 1193*7c478bd9Sstevel@tonic-gate if (device_string[0] != '\0') { 1194*7c478bd9Sstevel@tonic-gate (void) usb_log(log_handle, log_level, log_mask, 1195*7c478bd9Sstevel@tonic-gate "Cannot access %s. Please reconnect.", 1196*7c478bd9Sstevel@tonic-gate device_string); 1197*7c478bd9Sstevel@tonic-gate } else { 1198*7c478bd9Sstevel@tonic-gate (void) usb_log(log_handle, log_level, log_mask, 1199*7c478bd9Sstevel@tonic-gate "Device is not identical to the " 1200*7c478bd9Sstevel@tonic-gate "previous one this port.\n" 1201*7c478bd9Sstevel@tonic-gate "Please disconnect and reconnect"); 1202*7c478bd9Sstevel@tonic-gate } 1203*7c478bd9Sstevel@tonic-gate if (allocated_here) { 1204*7c478bd9Sstevel@tonic-gate kmem_free(device_string, USB_MAXSTRINGLEN); 1205*7c478bd9Sstevel@tonic-gate } 1206*7c478bd9Sstevel@tonic-gate 1207*7c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION); 1208*7c478bd9Sstevel@tonic-gate } 1209*7c478bd9Sstevel@tonic-gate 1210*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1211*7c478bd9Sstevel@tonic-gate } 1212*7c478bd9Sstevel@tonic-gate 1213*7c478bd9Sstevel@tonic-gate 1214*7c478bd9Sstevel@tonic-gate /* 1215*7c478bd9Sstevel@tonic-gate * usb_pipe_get_state: 1216*7c478bd9Sstevel@tonic-gate * Return the state of the pipe 1217*7c478bd9Sstevel@tonic-gate * 1218*7c478bd9Sstevel@tonic-gate * Arguments: 1219*7c478bd9Sstevel@tonic-gate * pipe_handle - pipe_handle pointer 1220*7c478bd9Sstevel@tonic-gate * pipe_state - pointer to copy pipe state to 1221*7c478bd9Sstevel@tonic-gate * flags: 1222*7c478bd9Sstevel@tonic-gate * not used other than to check context 1223*7c478bd9Sstevel@tonic-gate * 1224*7c478bd9Sstevel@tonic-gate * Return Values: 1225*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - port state returned 1226*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 1227*7c478bd9Sstevel@tonic-gate */ 1228*7c478bd9Sstevel@tonic-gate int 1229*7c478bd9Sstevel@tonic-gate usb_pipe_get_state(usb_pipe_handle_t pipe_handle, 1230*7c478bd9Sstevel@tonic-gate usb_pipe_state_t *pipe_state, 1231*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 1232*7c478bd9Sstevel@tonic-gate { 1233*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1234*7c478bd9Sstevel@tonic-gate 1235*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1236*7c478bd9Sstevel@tonic-gate "usb_pipe_get_state: ph_data=0x%p uf=0x%x", ph_data, usb_flags); 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate if (pipe_state == NULL) { 1239*7c478bd9Sstevel@tonic-gate if (ph_data) { 1240*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 1241*7c478bd9Sstevel@tonic-gate } 1242*7c478bd9Sstevel@tonic-gate 1243*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1244*7c478bd9Sstevel@tonic-gate } 1245*7c478bd9Sstevel@tonic-gate 1246*7c478bd9Sstevel@tonic-gate if (ph_data == NULL) { 1247*7c478bd9Sstevel@tonic-gate *pipe_state = USB_PIPE_STATE_CLOSED; 1248*7c478bd9Sstevel@tonic-gate 1249*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1250*7c478bd9Sstevel@tonic-gate } 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1253*7c478bd9Sstevel@tonic-gate *pipe_state = usba_get_ph_state(ph_data); 1254*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 1257*7c478bd9Sstevel@tonic-gate 1258*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1259*7c478bd9Sstevel@tonic-gate } 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate 1262*7c478bd9Sstevel@tonic-gate /* 1263*7c478bd9Sstevel@tonic-gate * usba_pipe_get_policy: 1264*7c478bd9Sstevel@tonic-gate * Return a pipe's policy 1265*7c478bd9Sstevel@tonic-gate * 1266*7c478bd9Sstevel@tonic-gate * Arguments: 1267*7c478bd9Sstevel@tonic-gate * pipe_handle - pipe_handle pointer 1268*7c478bd9Sstevel@tonic-gate * 1269*7c478bd9Sstevel@tonic-gate * Return Values: 1270*7c478bd9Sstevel@tonic-gate * On success: the pipe's policy 1271*7c478bd9Sstevel@tonic-gate * On failure: NULL 1272*7c478bd9Sstevel@tonic-gate */ 1273*7c478bd9Sstevel@tonic-gate usb_pipe_policy_t 1274*7c478bd9Sstevel@tonic-gate *usba_pipe_get_policy(usb_pipe_handle_t pipe_handle) 1275*7c478bd9Sstevel@tonic-gate { 1276*7c478bd9Sstevel@tonic-gate usb_pipe_policy_t *pp = NULL; 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1279*7c478bd9Sstevel@tonic-gate 1280*7c478bd9Sstevel@tonic-gate if (ph_data) { 1281*7c478bd9Sstevel@tonic-gate pp = &ph_data->p_policy; 1282*7c478bd9Sstevel@tonic-gate 1283*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 1284*7c478bd9Sstevel@tonic-gate } 1285*7c478bd9Sstevel@tonic-gate 1286*7c478bd9Sstevel@tonic-gate return (pp); 1287*7c478bd9Sstevel@tonic-gate } 1288*7c478bd9Sstevel@tonic-gate 1289*7c478bd9Sstevel@tonic-gate 1290*7c478bd9Sstevel@tonic-gate /* 1291*7c478bd9Sstevel@tonic-gate * usb_ep_num: 1292*7c478bd9Sstevel@tonic-gate * Return the endpoint number for a given pipe handle 1293*7c478bd9Sstevel@tonic-gate * 1294*7c478bd9Sstevel@tonic-gate * Arguments: 1295*7c478bd9Sstevel@tonic-gate * pipe_handle - pipe_handle pointer 1296*7c478bd9Sstevel@tonic-gate * 1297*7c478bd9Sstevel@tonic-gate * Return Values: 1298*7c478bd9Sstevel@tonic-gate * endpoint number 1299*7c478bd9Sstevel@tonic-gate */ 1300*7c478bd9Sstevel@tonic-gate int 1301*7c478bd9Sstevel@tonic-gate usb_ep_num(usb_pipe_handle_t pipe_handle) 1302*7c478bd9Sstevel@tonic-gate { 1303*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1304*7c478bd9Sstevel@tonic-gate int ep_num; 1305*7c478bd9Sstevel@tonic-gate 1306*7c478bd9Sstevel@tonic-gate if (ph_data == NULL) { 1307*7c478bd9Sstevel@tonic-gate 1308*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 1309*7c478bd9Sstevel@tonic-gate } 1310*7c478bd9Sstevel@tonic-gate 1311*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1312*7c478bd9Sstevel@tonic-gate ep_num = ph_data->p_ep.bEndpointAddress & USB_EP_NUM_MASK; 1313*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1314*7c478bd9Sstevel@tonic-gate 1315*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 1316*7c478bd9Sstevel@tonic-gate 1317*7c478bd9Sstevel@tonic-gate return (ep_num); 1318*7c478bd9Sstevel@tonic-gate } 1319*7c478bd9Sstevel@tonic-gate 1320*7c478bd9Sstevel@tonic-gate 1321*7c478bd9Sstevel@tonic-gate /* 1322*7c478bd9Sstevel@tonic-gate * usb_get_status 1323*7c478bd9Sstevel@tonic-gate * Issues USB_REQ_GET_STATUS to device/endpoint/interface 1324*7c478bd9Sstevel@tonic-gate * and report in "status" arg. 1325*7c478bd9Sstevel@tonic-gate * 1326*7c478bd9Sstevel@tonic-gate * status reported for a "device" is 1327*7c478bd9Sstevel@tonic-gate * RemoteWakeup enabled 1328*7c478bd9Sstevel@tonic-gate * SelfPowered device? 1329*7c478bd9Sstevel@tonic-gate * 1330*7c478bd9Sstevel@tonic-gate * status reported for an "interface" is NONE. 1331*7c478bd9Sstevel@tonic-gate * status reported for an "endpoint" is 1332*7c478bd9Sstevel@tonic-gate * HALT set (device STALLED?) 1333*7c478bd9Sstevel@tonic-gate * 1334*7c478bd9Sstevel@tonic-gate * Arguments: 1335*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 1336*7c478bd9Sstevel@tonic-gate * ph - pipe handle 1337*7c478bd9Sstevel@tonic-gate * type - bmRequestType to be used 1338*7c478bd9Sstevel@tonic-gate * what - 0 for device, otherwise interface or ep number 1339*7c478bd9Sstevel@tonic-gate * status - user supplied pointer for storing the status 1340*7c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP (mandatory) 1341*7c478bd9Sstevel@tonic-gate * 1342*7c478bd9Sstevel@tonic-gate * Return Values: 1343*7c478bd9Sstevel@tonic-gate * valid usb_status_t or USB_FAILURE 1344*7c478bd9Sstevel@tonic-gate */ 1345*7c478bd9Sstevel@tonic-gate int 1346*7c478bd9Sstevel@tonic-gate usb_get_status(dev_info_t *dip, 1347*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 1348*7c478bd9Sstevel@tonic-gate uint_t type, /* bmRequestType */ 1349*7c478bd9Sstevel@tonic-gate uint_t what, /* 0, interface, ept number */ 1350*7c478bd9Sstevel@tonic-gate uint16_t *status, 1351*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 1352*7c478bd9Sstevel@tonic-gate { 1353*7c478bd9Sstevel@tonic-gate int rval; 1354*7c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 1355*7c478bd9Sstevel@tonic-gate mblk_t *data = NULL; 1356*7c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 1357*7c478bd9Sstevel@tonic-gate 1358*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 1359*7c478bd9Sstevel@tonic-gate "usb_get_status: type = 0x%x, what = 0x%x, uf = 0x%x", 1360*7c478bd9Sstevel@tonic-gate type, what, flags); 1361*7c478bd9Sstevel@tonic-gate 1362*7c478bd9Sstevel@tonic-gate if ((status == NULL) || (dip == NULL)) { 1363*7c478bd9Sstevel@tonic-gate 1364*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1365*7c478bd9Sstevel@tonic-gate } 1366*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 1367*7c478bd9Sstevel@tonic-gate 1368*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 1369*7c478bd9Sstevel@tonic-gate } 1370*7c478bd9Sstevel@tonic-gate 1371*7c478bd9Sstevel@tonic-gate type |= USB_DEV_REQ_DEV_TO_HOST; 1372*7c478bd9Sstevel@tonic-gate 1373*7c478bd9Sstevel@tonic-gate /* get the status */ 1374*7c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph, 1375*7c478bd9Sstevel@tonic-gate type, 1376*7c478bd9Sstevel@tonic-gate USB_REQ_GET_STATUS, 1377*7c478bd9Sstevel@tonic-gate 0, 1378*7c478bd9Sstevel@tonic-gate what, 1379*7c478bd9Sstevel@tonic-gate USB_GET_STATUS_LEN, /* status is fixed 2 bytes long */ 1380*7c478bd9Sstevel@tonic-gate &data, 0, 1381*7c478bd9Sstevel@tonic-gate &completion_reason, &cb_flags, flags); 1382*7c478bd9Sstevel@tonic-gate 1383*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 1384*7c478bd9Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason); 1385*7c478bd9Sstevel@tonic-gate 1386*7c478bd9Sstevel@tonic-gate if ((rval == USB_SUCCESS) && data && 1387*7c478bd9Sstevel@tonic-gate ((data->b_wptr - data->b_rptr) == USB_GET_STATUS_LEN)) { 1388*7c478bd9Sstevel@tonic-gate *status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 1389*7c478bd9Sstevel@tonic-gate } else { 1390*7c478bd9Sstevel@tonic-gate *status = 0; 1391*7c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 1392*7c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 1393*7c478bd9Sstevel@tonic-gate } 1394*7c478bd9Sstevel@tonic-gate } 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate freemsg(data); 1397*7c478bd9Sstevel@tonic-gate 1398*7c478bd9Sstevel@tonic-gate return (rval); 1399*7c478bd9Sstevel@tonic-gate } 1400*7c478bd9Sstevel@tonic-gate 1401*7c478bd9Sstevel@tonic-gate 1402*7c478bd9Sstevel@tonic-gate /* 1403*7c478bd9Sstevel@tonic-gate * usb_clear_feature: 1404*7c478bd9Sstevel@tonic-gate * Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface 1405*7c478bd9Sstevel@tonic-gate * 1406*7c478bd9Sstevel@tonic-gate * Arguments: 1407*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 1408*7c478bd9Sstevel@tonic-gate * ph - pipe handle pointer 1409*7c478bd9Sstevel@tonic-gate * type - bmRequestType to be used 1410*7c478bd9Sstevel@tonic-gate * feature - feature to be cleared 1411*7c478bd9Sstevel@tonic-gate * what - 0 for device, otherwise interface or ep number 1412*7c478bd9Sstevel@tonic-gate * flags - none (but will sleep) 1413*7c478bd9Sstevel@tonic-gate * 1414*7c478bd9Sstevel@tonic-gate * Return Values: 1415*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - on doing a successful clear feature 1416*7c478bd9Sstevel@tonic-gate * USB_FAILURE - on failure 1417*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 1418*7c478bd9Sstevel@tonic-gate */ 1419*7c478bd9Sstevel@tonic-gate int 1420*7c478bd9Sstevel@tonic-gate usb_clear_feature(dev_info_t *dip, 1421*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 1422*7c478bd9Sstevel@tonic-gate uint_t type, /* bmRequestType */ 1423*7c478bd9Sstevel@tonic-gate uint_t feature, 1424*7c478bd9Sstevel@tonic-gate uint_t what, /* 0, interface, ept number */ 1425*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 1426*7c478bd9Sstevel@tonic-gate { 1427*7c478bd9Sstevel@tonic-gate int rval; 1428*7c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 1429*7c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 1430*7c478bd9Sstevel@tonic-gate 1431*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 1432*7c478bd9Sstevel@tonic-gate "usb_clear_feature: type = 0x%x, feature = 0x%x, what = 0x%x " 1433*7c478bd9Sstevel@tonic-gate "uf = 0x%x", type, feature, what, flags); 1434*7c478bd9Sstevel@tonic-gate 1435*7c478bd9Sstevel@tonic-gate if (dip == NULL) { 1436*7c478bd9Sstevel@tonic-gate 1437*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1438*7c478bd9Sstevel@tonic-gate } 1439*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 1440*7c478bd9Sstevel@tonic-gate 1441*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 1442*7c478bd9Sstevel@tonic-gate } 1443*7c478bd9Sstevel@tonic-gate 1444*7c478bd9Sstevel@tonic-gate /* issue Clear feature */ 1445*7c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph, 1446*7c478bd9Sstevel@tonic-gate type, 1447*7c478bd9Sstevel@tonic-gate USB_REQ_CLEAR_FEATURE, 1448*7c478bd9Sstevel@tonic-gate feature, 1449*7c478bd9Sstevel@tonic-gate what, 1450*7c478bd9Sstevel@tonic-gate 0, 1451*7c478bd9Sstevel@tonic-gate NULL, 0, 1452*7c478bd9Sstevel@tonic-gate &completion_reason, 1453*7c478bd9Sstevel@tonic-gate &cb_flags, flags | USB_FLAGS_SLEEP); 1454*7c478bd9Sstevel@tonic-gate 1455*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 1456*7c478bd9Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason); 1457*7c478bd9Sstevel@tonic-gate 1458*7c478bd9Sstevel@tonic-gate return (rval); 1459*7c478bd9Sstevel@tonic-gate } 1460*7c478bd9Sstevel@tonic-gate 1461*7c478bd9Sstevel@tonic-gate 1462*7c478bd9Sstevel@tonic-gate /* 1463*7c478bd9Sstevel@tonic-gate * usb_clr_feature: 1464*7c478bd9Sstevel@tonic-gate * Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface 1465*7c478bd9Sstevel@tonic-gate * 1466*7c478bd9Sstevel@tonic-gate * Arguments: 1467*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 1468*7c478bd9Sstevel@tonic-gate * type - bmRequestType to be used 1469*7c478bd9Sstevel@tonic-gate * feature - feature to be cleared 1470*7c478bd9Sstevel@tonic-gate * what - 0 for device, otherwise interface or ep number 1471*7c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP: 1472*7c478bd9Sstevel@tonic-gate * wait for completion 1473*7c478bd9Sstevel@tonic-gate * cb - if USB_FLAGS_SLEEP has not been specified 1474*7c478bd9Sstevel@tonic-gate * this callback function will be called on 1475*7c478bd9Sstevel@tonic-gate * completion. This callback may be NULL 1476*7c478bd9Sstevel@tonic-gate * and no notification of completion will then 1477*7c478bd9Sstevel@tonic-gate * be provided. 1478*7c478bd9Sstevel@tonic-gate * cb_arg - 2nd argument to callback function. 1479*7c478bd9Sstevel@tonic-gate * 1480*7c478bd9Sstevel@tonic-gate * 1481*7c478bd9Sstevel@tonic-gate * Return Values: 1482*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - on doing a successful clear feature 1483*7c478bd9Sstevel@tonic-gate * USB_FAILURE - on failure 1484*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 1485*7c478bd9Sstevel@tonic-gate */ 1486*7c478bd9Sstevel@tonic-gate int 1487*7c478bd9Sstevel@tonic-gate usb_clr_feature( 1488*7c478bd9Sstevel@tonic-gate dev_info_t *dip, 1489*7c478bd9Sstevel@tonic-gate uint_t type, /* bmRequestType */ 1490*7c478bd9Sstevel@tonic-gate uint_t feature, 1491*7c478bd9Sstevel@tonic-gate uint_t what, /* 0, interface, ept number */ 1492*7c478bd9Sstevel@tonic-gate usb_flags_t flags, 1493*7c478bd9Sstevel@tonic-gate void (*cb)( 1494*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 1495*7c478bd9Sstevel@tonic-gate usb_opaque_t arg, 1496*7c478bd9Sstevel@tonic-gate int rval, 1497*7c478bd9Sstevel@tonic-gate usb_cb_flags_t flags), 1498*7c478bd9Sstevel@tonic-gate usb_opaque_t cb_arg) 1499*7c478bd9Sstevel@tonic-gate { 1500*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph; 1501*7c478bd9Sstevel@tonic-gate 1502*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 1503*7c478bd9Sstevel@tonic-gate "usb_clr_feature: type = 0x%x, feature = 0x%x, what = 0x%x " 1504*7c478bd9Sstevel@tonic-gate "uf = 0x%x", type, feature, what, flags); 1505*7c478bd9Sstevel@tonic-gate 1506*7c478bd9Sstevel@tonic-gate if (dip == NULL) { 1507*7c478bd9Sstevel@tonic-gate 1508*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1509*7c478bd9Sstevel@tonic-gate } 1510*7c478bd9Sstevel@tonic-gate 1511*7c478bd9Sstevel@tonic-gate if ((flags & USB_FLAGS_SLEEP) && servicing_interrupt()) { 1512*7c478bd9Sstevel@tonic-gate 1513*7c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT); 1514*7c478bd9Sstevel@tonic-gate } 1515*7c478bd9Sstevel@tonic-gate 1516*7c478bd9Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip); 1517*7c478bd9Sstevel@tonic-gate if (usba_hold_ph_data(ph) == NULL) { 1518*7c478bd9Sstevel@tonic-gate 1519*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 1520*7c478bd9Sstevel@tonic-gate } 1521*7c478bd9Sstevel@tonic-gate 1522*7c478bd9Sstevel@tonic-gate return (usba_pipe_setup_func_call(dip, 1523*7c478bd9Sstevel@tonic-gate usba_sync_clear_feature, (usba_ph_impl_t *)ph, 1524*7c478bd9Sstevel@tonic-gate (usb_opaque_t)((uintptr_t)((type << 16 | feature << 8 | what))), 1525*7c478bd9Sstevel@tonic-gate flags, cb, cb_arg)); 1526*7c478bd9Sstevel@tonic-gate } 1527*7c478bd9Sstevel@tonic-gate 1528*7c478bd9Sstevel@tonic-gate 1529*7c478bd9Sstevel@tonic-gate static int 1530*7c478bd9Sstevel@tonic-gate usba_sync_clear_feature(dev_info_t *dip, 1531*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl, 1532*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *req, 1533*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 1534*7c478bd9Sstevel@tonic-gate { 1535*7c478bd9Sstevel@tonic-gate uint_t n = (uint_t)((uintptr_t)(req->arg)); 1536*7c478bd9Sstevel@tonic-gate uint_t type = ((uint_t)n >> 16) & 0xff; 1537*7c478bd9Sstevel@tonic-gate uint_t feature = ((uint_t)n >> 8) & 0xff; 1538*7c478bd9Sstevel@tonic-gate uint_t what = (uint_t)n & 0xff; 1539*7c478bd9Sstevel@tonic-gate int rval; 1540*7c478bd9Sstevel@tonic-gate 1541*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 1542*7c478bd9Sstevel@tonic-gate "usb_sync_clear_feature: " 1543*7c478bd9Sstevel@tonic-gate "dip=0x%p ph=0x%p type=0x%x feature=0x%x what=0x%x fl=0x%x", 1544*7c478bd9Sstevel@tonic-gate dip, ph_impl, type, feature, what, usb_flags); 1545*7c478bd9Sstevel@tonic-gate 1546*7c478bd9Sstevel@tonic-gate rval = usb_clear_feature(dip, (usb_pipe_handle_t)ph_impl, type, 1547*7c478bd9Sstevel@tonic-gate feature, what, usb_flags); 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 1550*7c478bd9Sstevel@tonic-gate 1551*7c478bd9Sstevel@tonic-gate return (rval); 1552*7c478bd9Sstevel@tonic-gate } 1553*7c478bd9Sstevel@tonic-gate 1554*7c478bd9Sstevel@tonic-gate 1555*7c478bd9Sstevel@tonic-gate /* 1556*7c478bd9Sstevel@tonic-gate * usb_async_req: 1557*7c478bd9Sstevel@tonic-gate * function used to dispatch a request to the taskq 1558*7c478bd9Sstevel@tonic-gate * 1559*7c478bd9Sstevel@tonic-gate * Arguments: 1560*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node 1561*7c478bd9Sstevel@tonic-gate * func - pointer to function issued by taskq 1562*7c478bd9Sstevel@tonic-gate * flag - USB_FLAGS_SLEEP mostly 1563*7c478bd9Sstevel@tonic-gate * 1564*7c478bd9Sstevel@tonic-gate * Return Values: 1565*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - on doing a successful taskq invocation 1566*7c478bd9Sstevel@tonic-gate * USB_FAILURE - on failure 1567*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 1568*7c478bd9Sstevel@tonic-gate */ 1569*7c478bd9Sstevel@tonic-gate int 1570*7c478bd9Sstevel@tonic-gate usb_async_req(dev_info_t *dip, 1571*7c478bd9Sstevel@tonic-gate void (*func)(void *), 1572*7c478bd9Sstevel@tonic-gate void *arg, 1573*7c478bd9Sstevel@tonic-gate usb_flags_t flag) 1574*7c478bd9Sstevel@tonic-gate { 1575*7c478bd9Sstevel@tonic-gate int tq_flag; 1576*7c478bd9Sstevel@tonic-gate 1577*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 1578*7c478bd9Sstevel@tonic-gate "usb_async_req: dip=0x%p func=0x%p, arg=0x%p flag=0x%x", 1579*7c478bd9Sstevel@tonic-gate dip, func, arg, flag); 1580*7c478bd9Sstevel@tonic-gate 1581*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (func == NULL)) { 1582*7c478bd9Sstevel@tonic-gate 1583*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1584*7c478bd9Sstevel@tonic-gate } 1585*7c478bd9Sstevel@tonic-gate tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP; 1586*7c478bd9Sstevel@tonic-gate if (flag & USB_FLAGS_NOQUEUE) { 1587*7c478bd9Sstevel@tonic-gate tq_flag |= TQ_NOQUEUE; 1588*7c478bd9Sstevel@tonic-gate } 1589*7c478bd9Sstevel@tonic-gate 1590*7c478bd9Sstevel@tonic-gate if (!taskq_dispatch(system_taskq, func, (void *)arg, 1591*7c478bd9Sstevel@tonic-gate tq_flag)) { 1592*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 1593*7c478bd9Sstevel@tonic-gate "usb_async_req: failure"); 1594*7c478bd9Sstevel@tonic-gate 1595*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1596*7c478bd9Sstevel@tonic-gate } 1597*7c478bd9Sstevel@tonic-gate 1598*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1599*7c478bd9Sstevel@tonic-gate } 1600*7c478bd9Sstevel@tonic-gate 1601*7c478bd9Sstevel@tonic-gate /* 1602*7c478bd9Sstevel@tonic-gate * usba_async_ph_req: 1603*7c478bd9Sstevel@tonic-gate * function used to dispatch a request to the ph taskq 1604*7c478bd9Sstevel@tonic-gate * 1605*7c478bd9Sstevel@tonic-gate * Arguments: 1606*7c478bd9Sstevel@tonic-gate * ph_data - pointer to pipe handle data 1607*7c478bd9Sstevel@tonic-gate * func - pointer to function issued by taskq 1608*7c478bd9Sstevel@tonic-gate * flag - USB_FLAGS_SLEEP or USB_FLAGS_NOSLEEP 1609*7c478bd9Sstevel@tonic-gate * 1610*7c478bd9Sstevel@tonic-gate * Return Values: 1611*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - on doing a successful taskq invocation 1612*7c478bd9Sstevel@tonic-gate * USB_FAILURE - on failure 1613*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 1614*7c478bd9Sstevel@tonic-gate * 1615*7c478bd9Sstevel@tonic-gate * Note: 1616*7c478bd9Sstevel@tonic-gate * If the caller specified USB_FLAGS_NOSLEEP, it must be 1617*7c478bd9Sstevel@tonic-gate * capable of reliably recovering from a failure return 1618*7c478bd9Sstevel@tonic-gate */ 1619*7c478bd9Sstevel@tonic-gate int 1620*7c478bd9Sstevel@tonic-gate usba_async_ph_req(usba_pipe_handle_data_t *ph_data, 1621*7c478bd9Sstevel@tonic-gate void (*func)(void *), 1622*7c478bd9Sstevel@tonic-gate void *arg, 1623*7c478bd9Sstevel@tonic-gate usb_flags_t flag) 1624*7c478bd9Sstevel@tonic-gate { 1625*7c478bd9Sstevel@tonic-gate int tq_flag; 1626*7c478bd9Sstevel@tonic-gate taskq_t *taskq; 1627*7c478bd9Sstevel@tonic-gate 1628*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 1629*7c478bd9Sstevel@tonic-gate "usba_async_ph_req: ph_data=0x%p func=0x%p, arg=0x%p flag=0x%x", 1630*7c478bd9Sstevel@tonic-gate ph_data, func, arg, flag); 1631*7c478bd9Sstevel@tonic-gate 1632*7c478bd9Sstevel@tonic-gate if (func == NULL) { 1633*7c478bd9Sstevel@tonic-gate 1634*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1635*7c478bd9Sstevel@tonic-gate } 1636*7c478bd9Sstevel@tonic-gate 1637*7c478bd9Sstevel@tonic-gate tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP; 1638*7c478bd9Sstevel@tonic-gate 1639*7c478bd9Sstevel@tonic-gate if (ph_data && ph_data->p_taskq) { 1640*7c478bd9Sstevel@tonic-gate taskq = ph_data->p_taskq; 1641*7c478bd9Sstevel@tonic-gate } else { 1642*7c478bd9Sstevel@tonic-gate taskq = system_taskq; 1643*7c478bd9Sstevel@tonic-gate tq_flag |= TQ_NOQUEUE; 1644*7c478bd9Sstevel@tonic-gate } 1645*7c478bd9Sstevel@tonic-gate 1646*7c478bd9Sstevel@tonic-gate if (!taskq_dispatch(taskq, func, (void *)arg, tq_flag)) { 1647*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 1648*7c478bd9Sstevel@tonic-gate "usba_async_ph_req: failure"); 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1651*7c478bd9Sstevel@tonic-gate } 1652*7c478bd9Sstevel@tonic-gate 1653*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1654*7c478bd9Sstevel@tonic-gate } 1655*7c478bd9Sstevel@tonic-gate 1656*7c478bd9Sstevel@tonic-gate 1657*7c478bd9Sstevel@tonic-gate /* 1658*7c478bd9Sstevel@tonic-gate * utility functions to display CR, CB, return values 1659*7c478bd9Sstevel@tonic-gate */ 1660*7c478bd9Sstevel@tonic-gate typedef struct conv_table { 1661*7c478bd9Sstevel@tonic-gate int what; 1662*7c478bd9Sstevel@tonic-gate const char *name; 1663*7c478bd9Sstevel@tonic-gate } conv_table_t; 1664*7c478bd9Sstevel@tonic-gate 1665*7c478bd9Sstevel@tonic-gate static const char * 1666*7c478bd9Sstevel@tonic-gate usba_get_name(conv_table_t *conv_table, int value) 1667*7c478bd9Sstevel@tonic-gate { 1668*7c478bd9Sstevel@tonic-gate int i; 1669*7c478bd9Sstevel@tonic-gate for (i = 0; conv_table[i].name != NULL; i++) { 1670*7c478bd9Sstevel@tonic-gate if (conv_table[i].what == value) { 1671*7c478bd9Sstevel@tonic-gate 1672*7c478bd9Sstevel@tonic-gate return (conv_table[i].name); 1673*7c478bd9Sstevel@tonic-gate } 1674*7c478bd9Sstevel@tonic-gate } 1675*7c478bd9Sstevel@tonic-gate 1676*7c478bd9Sstevel@tonic-gate return ("unknown"); 1677*7c478bd9Sstevel@tonic-gate } 1678*7c478bd9Sstevel@tonic-gate 1679*7c478bd9Sstevel@tonic-gate 1680*7c478bd9Sstevel@tonic-gate static conv_table_t cr_table[] = { 1681*7c478bd9Sstevel@tonic-gate { USB_CR_OK, "<no errors detected>" }, 1682*7c478bd9Sstevel@tonic-gate { USB_CR_CRC, "<crc error detected>" }, 1683*7c478bd9Sstevel@tonic-gate { USB_CR_BITSTUFFING, "<Bit stuffing violation>" }, 1684*7c478bd9Sstevel@tonic-gate { USB_CR_DATA_TOGGLE_MM, "<Data toggle PID did not match>" }, 1685*7c478bd9Sstevel@tonic-gate { USB_CR_STALL, "<Endpoint returned stall PID>" }, 1686*7c478bd9Sstevel@tonic-gate { USB_CR_DEV_NOT_RESP, "<Device not responding>" }, 1687*7c478bd9Sstevel@tonic-gate { USB_CR_PID_CHECKFAILURE, "<Check bits on PID failed>" }, 1688*7c478bd9Sstevel@tonic-gate { USB_CR_UNEXP_PID, "<Receive PID was not valid>" }, 1689*7c478bd9Sstevel@tonic-gate { USB_CR_DATA_OVERRUN, "<Data size exceeded>" }, 1690*7c478bd9Sstevel@tonic-gate { USB_CR_DATA_UNDERRUN, "<Less data recieved than requested>" }, 1691*7c478bd9Sstevel@tonic-gate { USB_CR_BUFFER_OVERRUN, "<Memory write can't keep up>" }, 1692*7c478bd9Sstevel@tonic-gate { USB_CR_BUFFER_UNDERRUN, "<Buffer underrun>" }, 1693*7c478bd9Sstevel@tonic-gate { USB_CR_TIMEOUT, "<Command timed out>" }, 1694*7c478bd9Sstevel@tonic-gate { USB_CR_NOT_ACCESSED, "<Not accessed by hardware>" }, 1695*7c478bd9Sstevel@tonic-gate { USB_CR_NO_RESOURCES, "<No resources>" }, 1696*7c478bd9Sstevel@tonic-gate { USB_CR_UNSPECIFIED_ERR, "<Unspecified usba or hcd error>" }, 1697*7c478bd9Sstevel@tonic-gate { USB_CR_STOPPED_POLLING, "<Intr/ISOC IN polling stopped>" }, 1698*7c478bd9Sstevel@tonic-gate { USB_CR_PIPE_CLOSING, "<Intr/ISOC IN pipe being closed>" }, 1699*7c478bd9Sstevel@tonic-gate { USB_CR_PIPE_RESET, "<Intr/ISOC IN pipe reset>" }, 1700*7c478bd9Sstevel@tonic-gate { USB_CR_NOT_SUPPORTED, "<Command not supported>" }, 1701*7c478bd9Sstevel@tonic-gate { USB_CR_FLUSHED, "<Req was flushed>" }, 1702*7c478bd9Sstevel@tonic-gate { USB_CR_HC_HARDWARE_ERR, "<USB host controller error>" }, 1703*7c478bd9Sstevel@tonic-gate { 0, NULL } 1704*7c478bd9Sstevel@tonic-gate }; 1705*7c478bd9Sstevel@tonic-gate 1706*7c478bd9Sstevel@tonic-gate const char * 1707*7c478bd9Sstevel@tonic-gate usb_str_cr(usb_cr_t cr) 1708*7c478bd9Sstevel@tonic-gate { 1709*7c478bd9Sstevel@tonic-gate return (usba_get_name(cr_table, cr)); 1710*7c478bd9Sstevel@tonic-gate } 1711*7c478bd9Sstevel@tonic-gate 1712*7c478bd9Sstevel@tonic-gate 1713*7c478bd9Sstevel@tonic-gate static conv_table_t cb_flags_table[] = { 1714*7c478bd9Sstevel@tonic-gate { USB_CB_NO_INFO, "<callback processed>" }, 1715*7c478bd9Sstevel@tonic-gate { USB_CB_STALL_CLEARED, "<stall cleared>" }, 1716*7c478bd9Sstevel@tonic-gate { USB_CB_FUNCTIONAL_STALL, "<functional stall>" }, 1717*7c478bd9Sstevel@tonic-gate { USB_CB_PROTOCOL_STALL, "<protocol stall>" }, 1718*7c478bd9Sstevel@tonic-gate { USB_CB_RESET_PIPE, "<pipe reset>" }, 1719*7c478bd9Sstevel@tonic-gate { USB_CB_ASYNC_REQ_FAILED, "<thread could not be started>" }, 1720*7c478bd9Sstevel@tonic-gate { USB_CB_NO_RESOURCES, "<no resources>" }, 1721*7c478bd9Sstevel@tonic-gate { USB_CB_SUBMIT_FAILED, "<submit failed>" }, 1722*7c478bd9Sstevel@tonic-gate { USB_CB_INTR_CONTEXT, "<Callback executing in interrupt context>" }, 1723*7c478bd9Sstevel@tonic-gate { 0, NULL } 1724*7c478bd9Sstevel@tonic-gate }; 1725*7c478bd9Sstevel@tonic-gate 1726*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1727*7c478bd9Sstevel@tonic-gate char * 1728*7c478bd9Sstevel@tonic-gate usb_str_cb_flags(usb_cb_flags_t cb_flags, char *buffer, size_t length) 1729*7c478bd9Sstevel@tonic-gate { 1730*7c478bd9Sstevel@tonic-gate int i; 1731*7c478bd9Sstevel@tonic-gate buffer[0] = '\0'; 1732*7c478bd9Sstevel@tonic-gate if (cb_flags == USB_CB_NO_INFO) { 1733*7c478bd9Sstevel@tonic-gate (void) strncpy(buffer, cb_flags_table[0].name, length); 1734*7c478bd9Sstevel@tonic-gate } else { 1735*7c478bd9Sstevel@tonic-gate for (i = 0; cb_flags_table[i].name != NULL; i++) { 1736*7c478bd9Sstevel@tonic-gate if (cb_flags & cb_flags_table[i].what) { 1737*7c478bd9Sstevel@tonic-gate (void) strncpy(&buffer[strlen(buffer)], 1738*7c478bd9Sstevel@tonic-gate cb_flags_table[0].name, 1739*7c478bd9Sstevel@tonic-gate length - strlen(buffer) - 1); 1740*7c478bd9Sstevel@tonic-gate } 1741*7c478bd9Sstevel@tonic-gate } 1742*7c478bd9Sstevel@tonic-gate } 1743*7c478bd9Sstevel@tonic-gate 1744*7c478bd9Sstevel@tonic-gate return (buffer); 1745*7c478bd9Sstevel@tonic-gate } 1746*7c478bd9Sstevel@tonic-gate 1747*7c478bd9Sstevel@tonic-gate 1748*7c478bd9Sstevel@tonic-gate static conv_table_t pipe_state_table[] = { 1749*7c478bd9Sstevel@tonic-gate { USB_PIPE_STATE_CLOSED, "<closed>" }, 1750*7c478bd9Sstevel@tonic-gate { USB_PIPE_STATE_IDLE, "<idle>" }, 1751*7c478bd9Sstevel@tonic-gate { USB_PIPE_STATE_ACTIVE, "<active>" }, 1752*7c478bd9Sstevel@tonic-gate { USB_PIPE_STATE_ERROR, "<error>" }, 1753*7c478bd9Sstevel@tonic-gate { USB_PIPE_STATE_CLOSING, "<closing>" }, 1754*7c478bd9Sstevel@tonic-gate { 0, NULL } 1755*7c478bd9Sstevel@tonic-gate }; 1756*7c478bd9Sstevel@tonic-gate 1757*7c478bd9Sstevel@tonic-gate const char * 1758*7c478bd9Sstevel@tonic-gate usb_str_pipe_state(usb_pipe_state_t state) 1759*7c478bd9Sstevel@tonic-gate { 1760*7c478bd9Sstevel@tonic-gate return (usba_get_name(pipe_state_table, state)); 1761*7c478bd9Sstevel@tonic-gate } 1762*7c478bd9Sstevel@tonic-gate 1763*7c478bd9Sstevel@tonic-gate 1764*7c478bd9Sstevel@tonic-gate static conv_table_t dev_state[] = { 1765*7c478bd9Sstevel@tonic-gate { USB_DEV_ONLINE, "<online>" }, 1766*7c478bd9Sstevel@tonic-gate { USB_DEV_DISCONNECTED, "<disconnected>" }, 1767*7c478bd9Sstevel@tonic-gate { USB_DEV_SUSPENDED, "<suspended>" }, 1768*7c478bd9Sstevel@tonic-gate { USB_DEV_PWRED_DOWN, "<powered down>" }, 1769*7c478bd9Sstevel@tonic-gate { 0, NULL } 1770*7c478bd9Sstevel@tonic-gate }; 1771*7c478bd9Sstevel@tonic-gate 1772*7c478bd9Sstevel@tonic-gate const char * 1773*7c478bd9Sstevel@tonic-gate usb_str_dev_state(int state) 1774*7c478bd9Sstevel@tonic-gate { 1775*7c478bd9Sstevel@tonic-gate return (usba_get_name(dev_state, state)); 1776*7c478bd9Sstevel@tonic-gate } 1777*7c478bd9Sstevel@tonic-gate 1778*7c478bd9Sstevel@tonic-gate 1779*7c478bd9Sstevel@tonic-gate static conv_table_t rval_table[] = { 1780*7c478bd9Sstevel@tonic-gate { USB_SUCCESS, "<success>" }, 1781*7c478bd9Sstevel@tonic-gate { USB_FAILURE, "<failure>" }, 1782*7c478bd9Sstevel@tonic-gate { USB_NO_RESOURCES, "<no resources>" }, 1783*7c478bd9Sstevel@tonic-gate { USB_NO_BANDWIDTH, "<no bandwidth>" }, 1784*7c478bd9Sstevel@tonic-gate { USB_NOT_SUPPORTED, "<not supported>" }, 1785*7c478bd9Sstevel@tonic-gate { USB_PIPE_ERROR, "<pipe error>" }, 1786*7c478bd9Sstevel@tonic-gate { USB_INVALID_PIPE, "<invalid pipe>" }, 1787*7c478bd9Sstevel@tonic-gate { USB_NO_FRAME_NUMBER, "<no frame number>" }, 1788*7c478bd9Sstevel@tonic-gate { USB_INVALID_START_FRAME, "<invalid frame>" }, 1789*7c478bd9Sstevel@tonic-gate { USB_HC_HARDWARE_ERROR, "<hw error>" }, 1790*7c478bd9Sstevel@tonic-gate { USB_INVALID_REQUEST, "<invalid request>" }, 1791*7c478bd9Sstevel@tonic-gate { USB_INVALID_CONTEXT, "<invalid context>" }, 1792*7c478bd9Sstevel@tonic-gate { USB_INVALID_VERSION, "<invalid version>" }, 1793*7c478bd9Sstevel@tonic-gate { USB_INVALID_ARGS, "<invalid args>" }, 1794*7c478bd9Sstevel@tonic-gate { USB_INVALID_PERM, "<invalid perms>" }, 1795*7c478bd9Sstevel@tonic-gate { USB_BUSY, "<busy>" }, 1796*7c478bd9Sstevel@tonic-gate { 0, NULL } 1797*7c478bd9Sstevel@tonic-gate }; 1798*7c478bd9Sstevel@tonic-gate 1799*7c478bd9Sstevel@tonic-gate const char * 1800*7c478bd9Sstevel@tonic-gate usb_str_rval(int rval) 1801*7c478bd9Sstevel@tonic-gate { 1802*7c478bd9Sstevel@tonic-gate return (usba_get_name(rval_table, rval)); 1803*7c478bd9Sstevel@tonic-gate } 1804*7c478bd9Sstevel@tonic-gate 1805*7c478bd9Sstevel@tonic-gate 1806*7c478bd9Sstevel@tonic-gate /* 1807*7c478bd9Sstevel@tonic-gate * function to convert USB return values to close errno 1808*7c478bd9Sstevel@tonic-gate */ 1809*7c478bd9Sstevel@tonic-gate static struct usb_rval2errno_entry { 1810*7c478bd9Sstevel@tonic-gate int rval; 1811*7c478bd9Sstevel@tonic-gate int Errno; 1812*7c478bd9Sstevel@tonic-gate } usb_rval2errno_table[] = { 1813*7c478bd9Sstevel@tonic-gate { USB_SUCCESS, 0 }, 1814*7c478bd9Sstevel@tonic-gate { USB_FAILURE, EIO }, 1815*7c478bd9Sstevel@tonic-gate { USB_NO_RESOURCES, ENOMEM }, 1816*7c478bd9Sstevel@tonic-gate { USB_NO_BANDWIDTH, EAGAIN }, 1817*7c478bd9Sstevel@tonic-gate { USB_NOT_SUPPORTED, ENOTSUP }, 1818*7c478bd9Sstevel@tonic-gate { USB_PIPE_ERROR, EIO }, 1819*7c478bd9Sstevel@tonic-gate { USB_INVALID_PIPE, EINVAL }, 1820*7c478bd9Sstevel@tonic-gate { USB_NO_FRAME_NUMBER, EINVAL }, 1821*7c478bd9Sstevel@tonic-gate { USB_INVALID_START_FRAME, EINVAL }, 1822*7c478bd9Sstevel@tonic-gate { USB_HC_HARDWARE_ERROR, EIO }, 1823*7c478bd9Sstevel@tonic-gate { USB_INVALID_REQUEST, EINVAL }, 1824*7c478bd9Sstevel@tonic-gate { USB_INVALID_CONTEXT, EINVAL }, 1825*7c478bd9Sstevel@tonic-gate { USB_INVALID_VERSION, EINVAL }, 1826*7c478bd9Sstevel@tonic-gate { USB_INVALID_ARGS, EINVAL }, 1827*7c478bd9Sstevel@tonic-gate { USB_INVALID_PERM, EACCES }, 1828*7c478bd9Sstevel@tonic-gate { USB_BUSY, EBUSY }, 1829*7c478bd9Sstevel@tonic-gate }; 1830*7c478bd9Sstevel@tonic-gate 1831*7c478bd9Sstevel@tonic-gate #define USB_RVAL2ERRNO_TABLE_SIZE (sizeof (usb_rval2errno_table) / \ 1832*7c478bd9Sstevel@tonic-gate sizeof (struct usb_rval2errno_entry)) 1833*7c478bd9Sstevel@tonic-gate int 1834*7c478bd9Sstevel@tonic-gate usb_rval2errno(int rval) 1835*7c478bd9Sstevel@tonic-gate { 1836*7c478bd9Sstevel@tonic-gate int i; 1837*7c478bd9Sstevel@tonic-gate 1838*7c478bd9Sstevel@tonic-gate for (i = 0; i < USB_RVAL2ERRNO_TABLE_SIZE; i++) { 1839*7c478bd9Sstevel@tonic-gate if (usb_rval2errno_table[i].rval == rval) { 1840*7c478bd9Sstevel@tonic-gate 1841*7c478bd9Sstevel@tonic-gate return (usb_rval2errno_table[i].Errno); 1842*7c478bd9Sstevel@tonic-gate } 1843*7c478bd9Sstevel@tonic-gate } 1844*7c478bd9Sstevel@tonic-gate 1845*7c478bd9Sstevel@tonic-gate return (EIO); 1846*7c478bd9Sstevel@tonic-gate } 1847*7c478bd9Sstevel@tonic-gate 1848*7c478bd9Sstevel@tonic-gate 1849*7c478bd9Sstevel@tonic-gate /* 1850*7c478bd9Sstevel@tonic-gate * serialization 1851*7c478bd9Sstevel@tonic-gate */ 1852*7c478bd9Sstevel@tonic-gate usb_serialization_t 1853*7c478bd9Sstevel@tonic-gate usb_init_serialization( 1854*7c478bd9Sstevel@tonic-gate dev_info_t *dip, 1855*7c478bd9Sstevel@tonic-gate uint_t flag) 1856*7c478bd9Sstevel@tonic-gate { 1857*7c478bd9Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp = kmem_zalloc( 1858*7c478bd9Sstevel@tonic-gate sizeof (usba_serialization_impl_t), KM_SLEEP); 1859*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 1860*7c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t cookie = NULL; 1861*7c478bd9Sstevel@tonic-gate 1862*7c478bd9Sstevel@tonic-gate if (dip) { 1863*7c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 1864*7c478bd9Sstevel@tonic-gate cookie = usba_hcdi_get_hcdi( 1865*7c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip)->hcdi_iblock_cookie; 1866*7c478bd9Sstevel@tonic-gate } 1867*7c478bd9Sstevel@tonic-gate impl_tokenp->s_dip = dip; 1868*7c478bd9Sstevel@tonic-gate impl_tokenp->s_flag = flag; 1869*7c478bd9Sstevel@tonic-gate mutex_init(&impl_tokenp->s_mutex, NULL, MUTEX_DRIVER, cookie); 1870*7c478bd9Sstevel@tonic-gate cv_init(&impl_tokenp->s_cv, NULL, CV_DRIVER, NULL); 1871*7c478bd9Sstevel@tonic-gate 1872*7c478bd9Sstevel@tonic-gate return ((usb_serialization_t)impl_tokenp); 1873*7c478bd9Sstevel@tonic-gate } 1874*7c478bd9Sstevel@tonic-gate 1875*7c478bd9Sstevel@tonic-gate 1876*7c478bd9Sstevel@tonic-gate void 1877*7c478bd9Sstevel@tonic-gate usb_fini_serialization( 1878*7c478bd9Sstevel@tonic-gate usb_serialization_t tokenp) 1879*7c478bd9Sstevel@tonic-gate { 1880*7c478bd9Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp; 1881*7c478bd9Sstevel@tonic-gate 1882*7c478bd9Sstevel@tonic-gate if (tokenp) { 1883*7c478bd9Sstevel@tonic-gate impl_tokenp = (usba_serialization_impl_t *)tokenp; 1884*7c478bd9Sstevel@tonic-gate ASSERT(impl_tokenp->s_count == 0); 1885*7c478bd9Sstevel@tonic-gate cv_destroy(&impl_tokenp->s_cv); 1886*7c478bd9Sstevel@tonic-gate mutex_destroy(&impl_tokenp->s_mutex); 1887*7c478bd9Sstevel@tonic-gate kmem_free(impl_tokenp, sizeof (usba_serialization_impl_t)); 1888*7c478bd9Sstevel@tonic-gate } 1889*7c478bd9Sstevel@tonic-gate } 1890*7c478bd9Sstevel@tonic-gate 1891*7c478bd9Sstevel@tonic-gate 1892*7c478bd9Sstevel@tonic-gate /* 1893*7c478bd9Sstevel@tonic-gate * usb_serialize_access() permits single threaded access. 1894*7c478bd9Sstevel@tonic-gate * 1895*7c478bd9Sstevel@tonic-gate * If tokenp is initialized with USB_INIT_SER_CHECK_SAME_THREAD, 1896*7c478bd9Sstevel@tonic-gate * it is reentrant with respect to thread. The thread must 1897*7c478bd9Sstevel@tonic-gate * hold and release the same number of times. 1898*7c478bd9Sstevel@tonic-gate * 1899*7c478bd9Sstevel@tonic-gate * If tokenp is initialized without USB_INIT_SER_CHECK_SAME_THREAD, 1900*7c478bd9Sstevel@tonic-gate * it is not reentrant by the same thread. It is something like 1901*7c478bd9Sstevel@tonic-gate * a semaphore. 1902*7c478bd9Sstevel@tonic-gate */ 1903*7c478bd9Sstevel@tonic-gate int 1904*7c478bd9Sstevel@tonic-gate usb_serialize_access( 1905*7c478bd9Sstevel@tonic-gate usb_serialization_t tokenp, uint_t how_to_wait, uint_t delta_timeout) 1906*7c478bd9Sstevel@tonic-gate { 1907*7c478bd9Sstevel@tonic-gate int rval = 1; /* Must be initialized > 0 */ 1908*7c478bd9Sstevel@tonic-gate clock_t abs_timeout; 1909*7c478bd9Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp; 1910*7c478bd9Sstevel@tonic-gate 1911*7c478bd9Sstevel@tonic-gate impl_tokenp = (usba_serialization_impl_t *)tokenp; 1912*7c478bd9Sstevel@tonic-gate 1913*7c478bd9Sstevel@tonic-gate /* 1914*7c478bd9Sstevel@tonic-gate * Convert delta timeout in ms to absolute timeout in ticks, if used. 1915*7c478bd9Sstevel@tonic-gate */ 1916*7c478bd9Sstevel@tonic-gate if ((how_to_wait == USB_TIMEDWAIT) || 1917*7c478bd9Sstevel@tonic-gate (how_to_wait == USB_TIMEDWAIT_SIG)) { 1918*7c478bd9Sstevel@tonic-gate /* Convert timeout arg (in ms) to hz */ 1919*7c478bd9Sstevel@tonic-gate abs_timeout = ddi_get_lbolt() + 1920*7c478bd9Sstevel@tonic-gate drv_usectohz(delta_timeout * 1000); 1921*7c478bd9Sstevel@tonic-gate } 1922*7c478bd9Sstevel@tonic-gate 1923*7c478bd9Sstevel@tonic-gate /* Get mutex after calc abs time, to count time waiting for mutex. */ 1924*7c478bd9Sstevel@tonic-gate mutex_enter(&impl_tokenp->s_mutex); 1925*7c478bd9Sstevel@tonic-gate 1926*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 1927*7c478bd9Sstevel@tonic-gate "usb_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p, " 1928*7c478bd9Sstevel@tonic-gate "flg=0x%x, abs_tmo=0x%lx", 1929*7c478bd9Sstevel@tonic-gate impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count, 1930*7c478bd9Sstevel@tonic-gate impl_tokenp->s_thread, how_to_wait, abs_timeout); 1931*7c478bd9Sstevel@tonic-gate 1932*7c478bd9Sstevel@tonic-gate if ((impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0 || 1933*7c478bd9Sstevel@tonic-gate impl_tokenp->s_thread != curthread) { 1934*7c478bd9Sstevel@tonic-gate 1935*7c478bd9Sstevel@tonic-gate /* 1936*7c478bd9Sstevel@tonic-gate * There are three ways to break out of the loop: 1937*7c478bd9Sstevel@tonic-gate * 1) Condition met (s_count == 0) - higher prio test 1938*7c478bd9Sstevel@tonic-gate * 2) kill(2) signal received (rval == 0) 1939*7c478bd9Sstevel@tonic-gate * 3) timeout occurred (rval == -1) 1940*7c478bd9Sstevel@tonic-gate * If condition met, whether or not signal or timeout occurred 1941*7c478bd9Sstevel@tonic-gate * take access. If condition not met, check other exit means. 1942*7c478bd9Sstevel@tonic-gate */ 1943*7c478bd9Sstevel@tonic-gate while (impl_tokenp->s_count != 0) { 1944*7c478bd9Sstevel@tonic-gate 1945*7c478bd9Sstevel@tonic-gate /* cv_timedwait* returns -1 on timeout. */ 1946*7c478bd9Sstevel@tonic-gate /* cv_wait*_sig returns 0 on (kill(2)) signal. */ 1947*7c478bd9Sstevel@tonic-gate if (rval <= 0) { 1948*7c478bd9Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex); 1949*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, 1950*7c478bd9Sstevel@tonic-gate usbai_log_handle, 1951*7c478bd9Sstevel@tonic-gate "usb_serialize_access: " 1952*7c478bd9Sstevel@tonic-gate "tok=0x%p exit due to %s", impl_tokenp, 1953*7c478bd9Sstevel@tonic-gate ((rval == 0) ? "signal" : "timeout")); 1954*7c478bd9Sstevel@tonic-gate 1955*7c478bd9Sstevel@tonic-gate return (rval); 1956*7c478bd9Sstevel@tonic-gate } 1957*7c478bd9Sstevel@tonic-gate 1958*7c478bd9Sstevel@tonic-gate switch (how_to_wait) { 1959*7c478bd9Sstevel@tonic-gate default: 1960*7c478bd9Sstevel@tonic-gate how_to_wait = USB_WAIT; 1961*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1962*7c478bd9Sstevel@tonic-gate case USB_WAIT: 1963*7c478bd9Sstevel@tonic-gate cv_wait(&impl_tokenp->s_cv, 1964*7c478bd9Sstevel@tonic-gate &impl_tokenp->s_mutex); 1965*7c478bd9Sstevel@tonic-gate break; 1966*7c478bd9Sstevel@tonic-gate case USB_WAIT_SIG: 1967*7c478bd9Sstevel@tonic-gate rval = cv_wait_sig(&impl_tokenp->s_cv, 1968*7c478bd9Sstevel@tonic-gate &impl_tokenp->s_mutex); 1969*7c478bd9Sstevel@tonic-gate break; 1970*7c478bd9Sstevel@tonic-gate case USB_TIMEDWAIT: 1971*7c478bd9Sstevel@tonic-gate rval = cv_timedwait(&impl_tokenp->s_cv, 1972*7c478bd9Sstevel@tonic-gate &impl_tokenp->s_mutex, abs_timeout); 1973*7c478bd9Sstevel@tonic-gate break; 1974*7c478bd9Sstevel@tonic-gate case USB_TIMEDWAIT_SIG: 1975*7c478bd9Sstevel@tonic-gate rval = cv_timedwait_sig(&impl_tokenp->s_cv, 1976*7c478bd9Sstevel@tonic-gate &impl_tokenp->s_mutex, abs_timeout); 1977*7c478bd9Sstevel@tonic-gate break; 1978*7c478bd9Sstevel@tonic-gate } 1979*7c478bd9Sstevel@tonic-gate } 1980*7c478bd9Sstevel@tonic-gate 1981*7c478bd9Sstevel@tonic-gate impl_tokenp->s_thread = curthread; 1982*7c478bd9Sstevel@tonic-gate } 1983*7c478bd9Sstevel@tonic-gate impl_tokenp->s_count++; 1984*7c478bd9Sstevel@tonic-gate 1985*7c478bd9Sstevel@tonic-gate ASSERT(!(impl_tokenp->s_count > 1 && 1986*7c478bd9Sstevel@tonic-gate (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0)); 1987*7c478bd9Sstevel@tonic-gate 1988*7c478bd9Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex); 1989*7c478bd9Sstevel@tonic-gate 1990*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 1991*7c478bd9Sstevel@tonic-gate "usb_serialize_access exit: tok=0x%p thr=0x%p", impl_tokenp, 1992*7c478bd9Sstevel@tonic-gate curthread); 1993*7c478bd9Sstevel@tonic-gate 1994*7c478bd9Sstevel@tonic-gate return (1); 1995*7c478bd9Sstevel@tonic-gate } 1996*7c478bd9Sstevel@tonic-gate 1997*7c478bd9Sstevel@tonic-gate 1998*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1999*7c478bd9Sstevel@tonic-gate int 2000*7c478bd9Sstevel@tonic-gate usb_try_serialize_access( 2001*7c478bd9Sstevel@tonic-gate usb_serialization_t tokenp, uint_t flag) 2002*7c478bd9Sstevel@tonic-gate { 2003*7c478bd9Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp = 2004*7c478bd9Sstevel@tonic-gate (usba_serialization_impl_t *)tokenp; 2005*7c478bd9Sstevel@tonic-gate mutex_enter(&impl_tokenp->s_mutex); 2006*7c478bd9Sstevel@tonic-gate 2007*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 2008*7c478bd9Sstevel@tonic-gate "usb_try_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p", 2009*7c478bd9Sstevel@tonic-gate impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count, curthread); 2010*7c478bd9Sstevel@tonic-gate 2011*7c478bd9Sstevel@tonic-gate /* 2012*7c478bd9Sstevel@tonic-gate * If lock is not taken (s_count is 0), take it. 2013*7c478bd9Sstevel@tonic-gate * If lock is already taken, the thread is owner and lock 2014*7c478bd9Sstevel@tonic-gate * is reentrant, take it. 2015*7c478bd9Sstevel@tonic-gate * Otherwise, fail the access. 2016*7c478bd9Sstevel@tonic-gate */ 2017*7c478bd9Sstevel@tonic-gate if (!impl_tokenp->s_count || ((impl_tokenp->s_thread == curthread) && 2018*7c478bd9Sstevel@tonic-gate (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD))) { 2019*7c478bd9Sstevel@tonic-gate impl_tokenp->s_thread = curthread; 2020*7c478bd9Sstevel@tonic-gate impl_tokenp->s_count++; 2021*7c478bd9Sstevel@tonic-gate 2022*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 2023*7c478bd9Sstevel@tonic-gate "usb_try_serialize_access success: tok=0x%p", impl_tokenp); 2024*7c478bd9Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex); 2025*7c478bd9Sstevel@tonic-gate 2026*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 2027*7c478bd9Sstevel@tonic-gate } 2028*7c478bd9Sstevel@tonic-gate 2029*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 2030*7c478bd9Sstevel@tonic-gate "usb_try_serialize_access failed: " 2031*7c478bd9Sstevel@tonic-gate "tok=0x%p dip=0x%p cnt=%d thr=0x%p", 2032*7c478bd9Sstevel@tonic-gate impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count, 2033*7c478bd9Sstevel@tonic-gate impl_tokenp->s_thread); 2034*7c478bd9Sstevel@tonic-gate 2035*7c478bd9Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex); 2036*7c478bd9Sstevel@tonic-gate 2037*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 2038*7c478bd9Sstevel@tonic-gate } 2039*7c478bd9Sstevel@tonic-gate 2040*7c478bd9Sstevel@tonic-gate 2041*7c478bd9Sstevel@tonic-gate void 2042*7c478bd9Sstevel@tonic-gate usb_release_access( 2043*7c478bd9Sstevel@tonic-gate usb_serialization_t tokenp) 2044*7c478bd9Sstevel@tonic-gate { 2045*7c478bd9Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp = 2046*7c478bd9Sstevel@tonic-gate (usba_serialization_impl_t *)tokenp; 2047*7c478bd9Sstevel@tonic-gate mutex_enter(&impl_tokenp->s_mutex); 2048*7c478bd9Sstevel@tonic-gate 2049*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 2050*7c478bd9Sstevel@tonic-gate "usb_release_access: tok=0x%p dip=0x%p count=%d thr=0x%p", 2051*7c478bd9Sstevel@tonic-gate impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count, curthread); 2052*7c478bd9Sstevel@tonic-gate 2053*7c478bd9Sstevel@tonic-gate ASSERT(impl_tokenp->s_count > 0); 2054*7c478bd9Sstevel@tonic-gate 2055*7c478bd9Sstevel@tonic-gate if (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) { 2056*7c478bd9Sstevel@tonic-gate if (impl_tokenp->s_thread != curthread) { 2057*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBA, usbai_log_handle, 2058*7c478bd9Sstevel@tonic-gate "usb_release_access: release from wrong thread"); 2059*7c478bd9Sstevel@tonic-gate } 2060*7c478bd9Sstevel@tonic-gate ASSERT(impl_tokenp->s_thread == curthread); 2061*7c478bd9Sstevel@tonic-gate } 2062*7c478bd9Sstevel@tonic-gate 2063*7c478bd9Sstevel@tonic-gate if (--impl_tokenp->s_count == 0) { 2064*7c478bd9Sstevel@tonic-gate impl_tokenp->s_thread = NULL; 2065*7c478bd9Sstevel@tonic-gate cv_broadcast(&impl_tokenp->s_cv); 2066*7c478bd9Sstevel@tonic-gate } 2067*7c478bd9Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex); 2068*7c478bd9Sstevel@tonic-gate } 2069*7c478bd9Sstevel@tonic-gate 2070*7c478bd9Sstevel@tonic-gate 2071*7c478bd9Sstevel@tonic-gate /* 2072*7c478bd9Sstevel@tonic-gate * usb_fail_checkpoint: 2073*7c478bd9Sstevel@tonic-gate * fail checkpoint as driver/device could not be quiesced 2074*7c478bd9Sstevel@tonic-gate */ 2075*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2076*7c478bd9Sstevel@tonic-gate void 2077*7c478bd9Sstevel@tonic-gate usb_fail_checkpoint(dev_info_t *dip, usb_flags_t flags) 2078*7c478bd9Sstevel@tonic-gate { 2079*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 2080*7c478bd9Sstevel@tonic-gate 2081*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 2082*7c478bd9Sstevel@tonic-gate "usb_fail_checkpoint: %s%d", ddi_driver_name(dip), 2083*7c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 2084*7c478bd9Sstevel@tonic-gate 2085*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 2086*7c478bd9Sstevel@tonic-gate usba_device->usb_no_cpr++; 2087*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 2088*7c478bd9Sstevel@tonic-gate } 2089*7c478bd9Sstevel@tonic-gate 2090*7c478bd9Sstevel@tonic-gate 2091*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk)) 2092*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab)) 2093*7c478bd9Sstevel@tonic-gate /* 2094*7c478bd9Sstevel@tonic-gate * usba_mk_mctl: 2095*7c478bd9Sstevel@tonic-gate * create a USB style M_CTL message, given an iocblk and a buffer 2096*7c478bd9Sstevel@tonic-gate * returns mblk_t * on success, NULL on failure 2097*7c478bd9Sstevel@tonic-gate */ 2098*7c478bd9Sstevel@tonic-gate mblk_t * 2099*7c478bd9Sstevel@tonic-gate usba_mk_mctl(struct iocblk mctlmsg, void *buf, size_t len) 2100*7c478bd9Sstevel@tonic-gate { 2101*7c478bd9Sstevel@tonic-gate mblk_t *bp1, *bp2; 2102*7c478bd9Sstevel@tonic-gate 2103*7c478bd9Sstevel@tonic-gate if ((bp1 = allocb(sizeof (struct iocblk), BPRI_HI)) != NULL) { 2104*7c478bd9Sstevel@tonic-gate *((struct iocblk *)bp1->b_datap->db_base) = mctlmsg; 2105*7c478bd9Sstevel@tonic-gate bp1->b_datap->db_type = M_CTL; 2106*7c478bd9Sstevel@tonic-gate bp1->b_wptr += sizeof (struct iocblk); 2107*7c478bd9Sstevel@tonic-gate if (buf != NULL) { 2108*7c478bd9Sstevel@tonic-gate if ((bp2 = allocb(len, BPRI_HI)) != NULL) { 2109*7c478bd9Sstevel@tonic-gate bp1->b_cont = bp2; 2110*7c478bd9Sstevel@tonic-gate bcopy(buf, bp2->b_datap->db_base, len); 2111*7c478bd9Sstevel@tonic-gate bp2->b_wptr += len; 2112*7c478bd9Sstevel@tonic-gate } else { 2113*7c478bd9Sstevel@tonic-gate freemsg(bp1); 2114*7c478bd9Sstevel@tonic-gate bp1 = NULL; 2115*7c478bd9Sstevel@tonic-gate } 2116*7c478bd9Sstevel@tonic-gate } 2117*7c478bd9Sstevel@tonic-gate } 2118*7c478bd9Sstevel@tonic-gate 2119*7c478bd9Sstevel@tonic-gate return (bp1); 2120*7c478bd9Sstevel@tonic-gate } 2121*7c478bd9Sstevel@tonic-gate 2122*7c478bd9Sstevel@tonic-gate 2123*7c478bd9Sstevel@tonic-gate #ifdef ALLOCB_TEST 2124*7c478bd9Sstevel@tonic-gate #undef allocb 2125*7c478bd9Sstevel@tonic-gate mblk_t * 2126*7c478bd9Sstevel@tonic-gate usba_test_allocb(size_t size, uint_t pri) 2127*7c478bd9Sstevel@tonic-gate { 2128*7c478bd9Sstevel@tonic-gate if (ddi_get_lbolt() & 0x1) { 2129*7c478bd9Sstevel@tonic-gate 2130*7c478bd9Sstevel@tonic-gate return (NULL); 2131*7c478bd9Sstevel@tonic-gate } else { 2132*7c478bd9Sstevel@tonic-gate 2133*7c478bd9Sstevel@tonic-gate return (allocb(size, pri)); 2134*7c478bd9Sstevel@tonic-gate } 2135*7c478bd9Sstevel@tonic-gate } 2136*7c478bd9Sstevel@tonic-gate #endif 2137