17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5d73ae94eSgc * Common Development and Distribution License (the "License"). 6d73ae94eSgc * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22112116d8Sfb * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * USBA: Solaris USB Architecture support 297c478bd9Sstevel@tonic-gate * 307c478bd9Sstevel@tonic-gate * Utility functions 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate #define USBA_FRAMEWORK 337c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h> 347c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h> 35*d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h> 367c478bd9Sstevel@tonic-gate 37d73ae94eSgc extern void usba_free_evdata(usba_evdata_t *); 38d73ae94eSgc 397c478bd9Sstevel@tonic-gate static mblk_t *usba_get_cfg_cloud(dev_info_t *, usb_pipe_handle_t, int); 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate /* local functions */ 427c478bd9Sstevel@tonic-gate static int usba_sync_set_cfg(dev_info_t *, usba_ph_impl_t *, 437c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t); 447c478bd9Sstevel@tonic-gate static int usba_sync_set_alt_if(dev_info_t *, usba_ph_impl_t *, 457c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t); 467c478bd9Sstevel@tonic-gate static int usba_sync_clear_feature(dev_info_t *, usba_ph_impl_t *, 477c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t); 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate /* 507c478bd9Sstevel@tonic-gate * Wrapper functions returning parsed standard descriptors without 517c478bd9Sstevel@tonic-gate * getting the config cloud first but by just providing the dip. 527c478bd9Sstevel@tonic-gate * 537c478bd9Sstevel@tonic-gate * The client can easily retrieve the device and config descriptor from 547c478bd9Sstevel@tonic-gate * the usb registration and no separate functions are provided 557c478bd9Sstevel@tonic-gate * 567c478bd9Sstevel@tonic-gate * These functions return failure if the full descriptor can not be 577c478bd9Sstevel@tonic-gate * retrieved. These functions will not access the device. 587c478bd9Sstevel@tonic-gate * The caller must allocate the buffer. 597c478bd9Sstevel@tonic-gate */ 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* 627c478bd9Sstevel@tonic-gate * usb_get_if_descr: 637c478bd9Sstevel@tonic-gate * Function to get the cooked interface descriptor 647c478bd9Sstevel@tonic-gate * This function will not access the device. 657c478bd9Sstevel@tonic-gate * 667c478bd9Sstevel@tonic-gate * Arguments: 677c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 687c478bd9Sstevel@tonic-gate * if_index - interface index 697c478bd9Sstevel@tonic-gate * alt_setting - alt interface setting 707c478bd9Sstevel@tonic-gate * descr - pointer to user allocated interface descr 717c478bd9Sstevel@tonic-gate * 727c478bd9Sstevel@tonic-gate * Return Values: 737c478bd9Sstevel@tonic-gate * USB_SUCCESS - descriptor is valid 747c478bd9Sstevel@tonic-gate * USB_FAILURE - full descriptor could not be retrieved 757c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate int 787c478bd9Sstevel@tonic-gate usb_get_if_descr(dev_info_t *dip, 797c478bd9Sstevel@tonic-gate uint_t if_index, 807c478bd9Sstevel@tonic-gate uint_t alt_setting, 817c478bd9Sstevel@tonic-gate usb_if_descr_t *descr) 827c478bd9Sstevel@tonic-gate { 837c478bd9Sstevel@tonic-gate uchar_t *usb_cfg; /* buf for config descriptor */ 847c478bd9Sstevel@tonic-gate size_t size, cfg_length; 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 877c478bd9Sstevel@tonic-gate "usb_get_if_descr: %s, index=0x%x, alt#=0x%x", 887c478bd9Sstevel@tonic-gate ddi_node_name(dip), if_index, alt_setting); 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate if ((dip == NULL) || (descr == NULL)) { 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length); 967c478bd9Sstevel@tonic-gate size = usb_parse_if_descr(usb_cfg, cfg_length, 977c478bd9Sstevel@tonic-gate if_index, /* interface index */ 987c478bd9Sstevel@tonic-gate alt_setting, /* alt interface index */ 997c478bd9Sstevel@tonic-gate descr, 1007c478bd9Sstevel@tonic-gate USB_IF_DESCR_SIZE); 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate if (size != USB_IF_DESCR_SIZE) { 1037c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1047c478bd9Sstevel@tonic-gate "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)", 1057c478bd9Sstevel@tonic-gate size, USB_IF_DESCR_SIZE); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1087c478bd9Sstevel@tonic-gate } 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* 1157c478bd9Sstevel@tonic-gate * usb_get_ep_descr: 1167c478bd9Sstevel@tonic-gate * Function to get the cooked endpoint descriptor 1177c478bd9Sstevel@tonic-gate * This function will not access the device. 1187c478bd9Sstevel@tonic-gate * 1197c478bd9Sstevel@tonic-gate * Arguments: 1207c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 1217c478bd9Sstevel@tonic-gate * if_index - interface index 1227c478bd9Sstevel@tonic-gate * alt_setting - alternate interface setting 1237c478bd9Sstevel@tonic-gate * endpoint_index - endpoint index 1247c478bd9Sstevel@tonic-gate * descr - pointer to user allocated interface descr 1257c478bd9Sstevel@tonic-gate * 1267c478bd9Sstevel@tonic-gate * Return Values: 1277c478bd9Sstevel@tonic-gate * USB_SUCCESS - descriptor is valid 1287c478bd9Sstevel@tonic-gate * USB_FAILURE - full descriptor could not be retrieved 1297c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 1307c478bd9Sstevel@tonic-gate */ 1317c478bd9Sstevel@tonic-gate int 1327c478bd9Sstevel@tonic-gate usb_get_ep_descr(dev_info_t *dip, 1337c478bd9Sstevel@tonic-gate uint_t if_index, 1347c478bd9Sstevel@tonic-gate uint_t alt_setting, 1357c478bd9Sstevel@tonic-gate uint_t endpoint_index, 1367c478bd9Sstevel@tonic-gate usb_ep_descr_t *descr) 1377c478bd9Sstevel@tonic-gate { 1387c478bd9Sstevel@tonic-gate uchar_t *usb_cfg; /* buf for config descriptor */ 1397c478bd9Sstevel@tonic-gate size_t size, cfg_length; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 1427c478bd9Sstevel@tonic-gate "usb_get_ep_descr: %s, index=0x%x, alt#=0x%x", 1437c478bd9Sstevel@tonic-gate ddi_node_name(dip), if_index, alt_setting); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate if ((dip == NULL) || (descr == NULL)) { 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length); 1517c478bd9Sstevel@tonic-gate size = usb_parse_ep_descr(usb_cfg, cfg_length, 152112116d8Sfb if_index, /* interface index */ 153112116d8Sfb alt_setting, /* alt interface index */ 154112116d8Sfb endpoint_index, /* ep index */ 155112116d8Sfb descr, USB_EP_DESCR_SIZE); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate if (size != USB_EP_DESCR_SIZE) { 1587c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1597c478bd9Sstevel@tonic-gate "parsing endpoint: size (%lu) != USB_EP_DESCR_SIZE (%d)", 1607c478bd9Sstevel@tonic-gate size, USB_EP_DESCR_SIZE); 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * usb_lookup_ep_data: 1717c478bd9Sstevel@tonic-gate * usb_get_ep_data (deprecated): 1727c478bd9Sstevel@tonic-gate * Function to get specific endpoint descriptor data 1737c478bd9Sstevel@tonic-gate * This function will not access the device. 1747c478bd9Sstevel@tonic-gate * 1757c478bd9Sstevel@tonic-gate * Arguments: 1767c478bd9Sstevel@tonic-gate * dip - pointer to dev info 1777c478bd9Sstevel@tonic-gate * usb_client_dev_data_t - pointer to registration data 1787c478bd9Sstevel@tonic-gate * interface - requested interface 1797c478bd9Sstevel@tonic-gate * alternate - requested alternate 1807c478bd9Sstevel@tonic-gate * skip - how many to skip 1817c478bd9Sstevel@tonic-gate * type - endpoint type 1827c478bd9Sstevel@tonic-gate * direction - endpoint direction or USB_DIR_DONT_CARE 1837c478bd9Sstevel@tonic-gate * 1847c478bd9Sstevel@tonic-gate * Return Values: 1857c478bd9Sstevel@tonic-gate * NULL or an endpoint descriptor pointer 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate usb_ep_data_t * 1887c478bd9Sstevel@tonic-gate usb_lookup_ep_data(dev_info_t *dip, 1897c478bd9Sstevel@tonic-gate usb_client_dev_data_t *dev_datap, 1907c478bd9Sstevel@tonic-gate uint_t interface, 1917c478bd9Sstevel@tonic-gate uint_t alternate, 1927c478bd9Sstevel@tonic-gate uint_t skip, 1937c478bd9Sstevel@tonic-gate uint_t type, 1947c478bd9Sstevel@tonic-gate uint_t dir) 1957c478bd9Sstevel@tonic-gate { 1967c478bd9Sstevel@tonic-gate usb_alt_if_data_t *altif_data; 1977c478bd9Sstevel@tonic-gate int i; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 2007c478bd9Sstevel@tonic-gate "usb_lookup_ep_data: " 2017c478bd9Sstevel@tonic-gate "if=%d alt=%d skip=%d type=%d dir=%d", 2027c478bd9Sstevel@tonic-gate interface, alternate, skip, type, dir); 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate if ((dip == NULL) || (dev_datap == NULL)) { 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate return (NULL); 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate altif_data = &dev_datap->dev_curr_cfg-> 210112116d8Sfb cfg_if[interface].if_alt[alternate]; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 213112116d8Sfb "altif=0x%p n_ep=%d", (void *)altif_data, altif_data->altif_n_ep); 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate for (i = 0; i < altif_data->altif_n_ep; i++) { 2167c478bd9Sstevel@tonic-gate usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr; 2177c478bd9Sstevel@tonic-gate uint8_t ept_type = ept->bmAttributes & USB_EP_ATTR_MASK; 2187c478bd9Sstevel@tonic-gate uint8_t ept_dir = ept->bEndpointAddress & USB_EP_DIR_MASK; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate if (ept->bLength == 0) { 2217c478bd9Sstevel@tonic-gate continue; 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate if ((ept_type == type) && 2247c478bd9Sstevel@tonic-gate ((type == USB_EP_ATTR_CONTROL) || (dir == ept_dir))) { 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate if (skip-- == 0) { 2277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, 2287c478bd9Sstevel@tonic-gate usbai_log_handle, 2297c478bd9Sstevel@tonic-gate "usb_get_ep_data: data=0x%p", 230112116d8Sfb (void *)&altif_data->altif_ep[i]); 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate return (&altif_data->altif_ep[i]); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 2377c478bd9Sstevel@tonic-gate "usb_get_ep_data: returning NULL"); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate return (NULL); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2447c478bd9Sstevel@tonic-gate usb_ep_data_t * 2457c478bd9Sstevel@tonic-gate usb_get_ep_data(dev_info_t *dip, 2467c478bd9Sstevel@tonic-gate usb_client_dev_data_t *dev_datap, 2477c478bd9Sstevel@tonic-gate uint_t interface, 2487c478bd9Sstevel@tonic-gate uint_t alternate, 2497c478bd9Sstevel@tonic-gate uint_t type, 2507c478bd9Sstevel@tonic-gate uint_t dir) 2517c478bd9Sstevel@tonic-gate { 2527c478bd9Sstevel@tonic-gate return (usb_lookup_ep_data(dip, dev_datap, interface, 2537c478bd9Sstevel@tonic-gate alternate, 0, type, dir)); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * usb_get_string_descr: 2597c478bd9Sstevel@tonic-gate * Function to read the string descriptor 2607c478bd9Sstevel@tonic-gate * This function will access the device and block. 2617c478bd9Sstevel@tonic-gate * 2627c478bd9Sstevel@tonic-gate * Arguments: 2637c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 2647c478bd9Sstevel@tonic-gate * langid - LANGID to read different LOCALEs 2657c478bd9Sstevel@tonic-gate * index - index to the string 2667c478bd9Sstevel@tonic-gate * buf - user provided buffer for string descriptor 2677c478bd9Sstevel@tonic-gate * buflen - user provided length of the buffer 2687c478bd9Sstevel@tonic-gate * 2697c478bd9Sstevel@tonic-gate * Return Values: 2707c478bd9Sstevel@tonic-gate * USB_SUCCESS - descriptor is valid 2717c478bd9Sstevel@tonic-gate * USB_FAILURE - full descriptor could not be retrieved 2727c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 2737c478bd9Sstevel@tonic-gate */ 2747c478bd9Sstevel@tonic-gate int 2757c478bd9Sstevel@tonic-gate usb_get_string_descr(dev_info_t *dip, 2767c478bd9Sstevel@tonic-gate uint16_t langid, 2777c478bd9Sstevel@tonic-gate uint8_t index, 2787c478bd9Sstevel@tonic-gate char *buf, 2797c478bd9Sstevel@tonic-gate size_t buflen) 2807c478bd9Sstevel@tonic-gate { 2817c478bd9Sstevel@tonic-gate mblk_t *data = NULL; 2827c478bd9Sstevel@tonic-gate uint16_t length; 2837c478bd9Sstevel@tonic-gate int rval; 2847c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 2857c478bd9Sstevel@tonic-gate size_t len; 2867c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 2897c478bd9Sstevel@tonic-gate "usb_get_string_descr: %s, langid=0x%x index=0x%x", 2907c478bd9Sstevel@tonic-gate ddi_node_name(dip), langid, index); 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate if ((dip == NULL) || (buf == NULL) || (buflen == 0) || (index == 0)) { 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate * determine the length of the descriptor 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, 301112116d8Sfb usba_get_dflt_pipe_handle(dip), 302112116d8Sfb USB_DEV_REQ_DEV_TO_HOST, 303112116d8Sfb USB_REQ_GET_DESCR, 304112116d8Sfb USB_DESCR_TYPE_STRING << 8 | index & 0xff, 305112116d8Sfb langid, 306112116d8Sfb 4, 307112116d8Sfb &data, USB_ATTRS_SHORT_XFER_OK, 308112116d8Sfb &completion_reason, 309112116d8Sfb &cb_flags, USB_FLAGS_SLEEP); 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 3127c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 3137c478bd9Sstevel@tonic-gate "rval=%d cr=%d", rval, completion_reason); 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate goto done; 3167c478bd9Sstevel@tonic-gate } 317*d29f5a71Szhigang lu - Sun Microsystems - Beijing China if (MBLKL(data) == 0) { 3187c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 3197c478bd9Sstevel@tonic-gate "0 bytes received"); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate goto done; 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate ASSERT(data); 3257c478bd9Sstevel@tonic-gate length = *(data->b_rptr); 3267c478bd9Sstevel@tonic-gate freemsg(data); 3277c478bd9Sstevel@tonic-gate data = NULL; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 3307c478bd9Sstevel@tonic-gate "rval=%d, cr=%d, length=%d", rval, completion_reason, length); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * if length is zero the next control request may fail. 3347c478bd9Sstevel@tonic-gate * the HCD may not support a zero length control request 3357c478bd9Sstevel@tonic-gate * and return an mblk_t which is NULL along with rval 3367c478bd9Sstevel@tonic-gate * being USB_SUCCESS and "cr" being USB_CR_OK 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate if (length < 2) { 3397c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate goto done; 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, 345112116d8Sfb usba_get_dflt_pipe_handle(dip), 346112116d8Sfb USB_DEV_REQ_DEV_TO_HOST, 347112116d8Sfb USB_REQ_GET_DESCR, 348112116d8Sfb USB_DESCR_TYPE_STRING << 8 | index & 0xff, 349112116d8Sfb langid, 350112116d8Sfb length, 351112116d8Sfb &data, USB_ATTRS_SHORT_XFER_OK, 352112116d8Sfb &completion_reason, 353112116d8Sfb &cb_flags, USB_FLAGS_SLEEP); 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 3567c478bd9Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate if ((data == NULL) || (rval != USB_SUCCESS)) { 3597c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 3607c478bd9Sstevel@tonic-gate "failed to get string descriptor (rval=%d cr=%d)", 3617c478bd9Sstevel@tonic-gate rval, completion_reason); 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate goto done; 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 366*d29f5a71Szhigang lu - Sun Microsystems - Beijing China if ((length = MBLKL(data)) != 0) { 3677c478bd9Sstevel@tonic-gate len = usba_ascii_string_descr(data->b_rptr, length, buf, 368112116d8Sfb buflen); 3697c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, 3707c478bd9Sstevel@tonic-gate usbai_log_handle, "buf=%s buflen=%lu", buf, len); 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate ASSERT(len <= buflen); 3737c478bd9Sstevel@tonic-gate } else { 3747c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate done: 3777c478bd9Sstevel@tonic-gate freemsg(data); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate return (rval); 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * usb_get_dev_descr: 3857c478bd9Sstevel@tonic-gate * utility function to get device descriptor from usba_device 3867c478bd9Sstevel@tonic-gate * 3877c478bd9Sstevel@tonic-gate * Arguments: 3887c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 3897c478bd9Sstevel@tonic-gate * 3907c478bd9Sstevel@tonic-gate * Return Values: 3917c478bd9Sstevel@tonic-gate * usb_dev_descr - device descriptor or NULL 3927c478bd9Sstevel@tonic-gate */ 3937c478bd9Sstevel@tonic-gate usb_dev_descr_t * 3947c478bd9Sstevel@tonic-gate usb_get_dev_descr(dev_info_t *dip) 3957c478bd9Sstevel@tonic-gate { 3967c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 3977c478bd9Sstevel@tonic-gate usb_dev_descr_t *usb_dev_descr = NULL; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate if (dip) { 4007c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 4017c478bd9Sstevel@tonic-gate "usb_get_dev_descr: %s", ddi_node_name(dip)); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 4047c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 4057c478bd9Sstevel@tonic-gate usb_dev_descr = usba_device->usb_dev_descr; 4067c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate return (usb_dev_descr); 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * usb_get_raw_cfg_data: 4157c478bd9Sstevel@tonic-gate * utility function to get raw config descriptor from usba_device 4167c478bd9Sstevel@tonic-gate * 4177c478bd9Sstevel@tonic-gate * Arguments: 4187c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 4197c478bd9Sstevel@tonic-gate * length - pointer to copy the cfg length 4207c478bd9Sstevel@tonic-gate * 4217c478bd9Sstevel@tonic-gate * Return Values: 4227c478bd9Sstevel@tonic-gate * usb_cfg - raw config descriptor 4237c478bd9Sstevel@tonic-gate */ 4247c478bd9Sstevel@tonic-gate uchar_t * 4257c478bd9Sstevel@tonic-gate usb_get_raw_cfg_data(dev_info_t *dip, size_t *length) 4267c478bd9Sstevel@tonic-gate { 4277c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 4287c478bd9Sstevel@tonic-gate uchar_t *usb_cfg; 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 4317c478bd9Sstevel@tonic-gate "usb_get_raw_cfg_data: %s", ddi_node_name(dip)); 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate if ((dip == NULL) || (length == NULL)) { 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate return (NULL); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 4417c478bd9Sstevel@tonic-gate usb_cfg = usba_device->usb_cfg; 4427c478bd9Sstevel@tonic-gate *length = usba_device->usb_cfg_length; 4437c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate return (usb_cfg); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate /* 4507c478bd9Sstevel@tonic-gate * usb_get_addr: 4517c478bd9Sstevel@tonic-gate * utility function to return current usb address, mostly 4527c478bd9Sstevel@tonic-gate * for debugging purposes 4537c478bd9Sstevel@tonic-gate * 4547c478bd9Sstevel@tonic-gate * Arguments: 4557c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 4567c478bd9Sstevel@tonic-gate * 4577c478bd9Sstevel@tonic-gate * Return Values: 4587c478bd9Sstevel@tonic-gate * address - USB Device Address 4597c478bd9Sstevel@tonic-gate */ 4607c478bd9Sstevel@tonic-gate int 4617c478bd9Sstevel@tonic-gate usb_get_addr(dev_info_t *dip) 4627c478bd9Sstevel@tonic-gate { 4637c478bd9Sstevel@tonic-gate int address = 0; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 4667c478bd9Sstevel@tonic-gate "usb_get_addr: %s", ddi_node_name(dip)); 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate if (dip) { 4697c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 4727c478bd9Sstevel@tonic-gate address = usba_device->usb_addr; 4737c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate return (address); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* 4817c478bd9Sstevel@tonic-gate * usb_set_cfg(): 4827c478bd9Sstevel@tonic-gate * set configuration, use with caution (issues USB_REQ_SET_CONFIG) 4837c478bd9Sstevel@tonic-gate * Changing configuration will fail if pipes are still open or when 4847c478bd9Sstevel@tonic-gate * invoked from a driver bound to an interface on a composite device. 4857c478bd9Sstevel@tonic-gate * 4867c478bd9Sstevel@tonic-gate * This function will access the device and block 4877c478bd9Sstevel@tonic-gate * 4887c478bd9Sstevel@tonic-gate * Arguments: 4897c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 4907c478bd9Sstevel@tonic-gate * cfg_index - config index 4917c478bd9Sstevel@tonic-gate * cfg_value - config value to be set 4927c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP: 4937c478bd9Sstevel@tonic-gate * wait for completion 4947c478bd9Sstevel@tonic-gate * cb - if USB_FLAGS_SLEEP has not been specified 4957c478bd9Sstevel@tonic-gate * this callback function will be called on 4967c478bd9Sstevel@tonic-gate * completion. This callback may be NULL 4977c478bd9Sstevel@tonic-gate * and no notification of completion will then 4987c478bd9Sstevel@tonic-gate * be provided. 4997c478bd9Sstevel@tonic-gate * cb_arg - 2nd argument to callback function. 5007c478bd9Sstevel@tonic-gate * 5017c478bd9Sstevel@tonic-gate * Return Values: 5027c478bd9Sstevel@tonic-gate * USB_SUCCESS: - new configuration was set 5037c478bd9Sstevel@tonic-gate * USB_FAILURE: - new configuration could not be set 5047c478bd9Sstevel@tonic-gate * USB_BUSY: - some pipes were open or there were children 5057c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 5067c478bd9Sstevel@tonic-gate */ 5077c478bd9Sstevel@tonic-gate int 5087c478bd9Sstevel@tonic-gate usb_set_cfg(dev_info_t *dip, 5097c478bd9Sstevel@tonic-gate uint_t cfg_index, 5107c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 5117c478bd9Sstevel@tonic-gate void (*cb)( 5127c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 5137c478bd9Sstevel@tonic-gate usb_opaque_t arg, 5147c478bd9Sstevel@tonic-gate int rval, 5157c478bd9Sstevel@tonic-gate usb_cb_flags_t flags), 5167c478bd9Sstevel@tonic-gate usb_opaque_t cb_arg) 5177c478bd9Sstevel@tonic-gate { 5187c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph; 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 5217c478bd9Sstevel@tonic-gate "usb_set_cfg: %s%d, cfg_index = 0x%x, uf = 0x%x", 5227c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), cfg_index, 5237c478bd9Sstevel@tonic-gate usb_flags); 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate if (dip == NULL) { 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) { 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate if (!usb_owns_device(dip)) { 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate return (USB_INVALID_PERM); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip); 5417c478bd9Sstevel@tonic-gate if (usba_hold_ph_data(ph) == NULL) { 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate return (usba_pipe_setup_func_call(dip, 5477c478bd9Sstevel@tonic-gate usba_sync_set_cfg, (usba_ph_impl_t *)ph, 5487c478bd9Sstevel@tonic-gate (usb_opaque_t)((uintptr_t)cfg_index), usb_flags, cb, cb_arg)); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate static int 5537c478bd9Sstevel@tonic-gate usba_sync_set_cfg(dev_info_t *dip, 5547c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl, 5557c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request, 5567c478bd9Sstevel@tonic-gate usb_flags_t flags) 5577c478bd9Sstevel@tonic-gate { 5587c478bd9Sstevel@tonic-gate int rval; 5597c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 5607c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 5617c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 5627c478bd9Sstevel@tonic-gate int i, ph_open_cnt; 5637c478bd9Sstevel@tonic-gate uint_t cfg_index = (uint_t)((uintptr_t)(request->arg)); 5647c478bd9Sstevel@tonic-gate size_t size; 5657c478bd9Sstevel@tonic-gate usb_cfg_descr_t confdescr; 56635f36846Ssl dev_info_t *pdip; 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate /* 5717c478bd9Sstevel@tonic-gate * default pipe is still open 5727c478bd9Sstevel@tonic-gate * all other pipes should be closed 5737c478bd9Sstevel@tonic-gate */ 5747c478bd9Sstevel@tonic-gate for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) { 5757c478bd9Sstevel@tonic-gate if (usba_device->usb_ph_list[i].usba_ph_data) { 5767c478bd9Sstevel@tonic-gate ph_open_cnt++; 5777c478bd9Sstevel@tonic-gate break; 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate if (ph_open_cnt || ddi_get_child(dip)) { 5827c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate return (USB_BUSY); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 58735f36846Ssl /* 58835f36846Ssl * check if the configuration meets the 58935f36846Ssl * power budget requirement 59035f36846Ssl */ 59135f36846Ssl if (usba_is_root_hub(dip)) { 59235f36846Ssl /* 59335f36846Ssl * root hub should never be multi-configured. 59435f36846Ssl * the code is here just to ensure 59535f36846Ssl */ 59635f36846Ssl usba_release_ph_data(ph_impl); 59735f36846Ssl 59835f36846Ssl return (USB_FAILURE); 59935f36846Ssl } 60035f36846Ssl pdip = ddi_get_parent(dip); 60135f36846Ssl 60235f36846Ssl /* 60335f36846Ssl * increase the power budget value back to the unconfigured 60435f36846Ssl * state to eliminate the influence of the old configuration 60535f36846Ssl * before checking the new configuration; but remember to 60635f36846Ssl * make a decrement before leaving this routine to restore 60735f36846Ssl * the power consumption state of the device no matter it 60835f36846Ssl * is in the new or old configuration 60935f36846Ssl */ 61035f36846Ssl usba_hubdi_incr_power_budget(pdip, usba_device); 61135f36846Ssl 61235f36846Ssl if ((usba_hubdi_check_power_budget(pdip, usba_device, 61335f36846Ssl cfg_index)) != USB_SUCCESS) { 61435f36846Ssl usba_hubdi_decr_power_budget(pdip, usba_device); 61535f36846Ssl 61635f36846Ssl usba_release_ph_data(ph_impl); 61735f36846Ssl 61835f36846Ssl return (USB_FAILURE); 61935f36846Ssl } 62035f36846Ssl 6217c478bd9Sstevel@tonic-gate size = usb_parse_cfg_descr(usba_device->usb_cfg_array[cfg_index], 622112116d8Sfb USB_CFG_DESCR_SIZE, &confdescr, USB_CFG_DESCR_SIZE); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* hubdi should ensure that this descriptor is correct */ 6257c478bd9Sstevel@tonic-gate ASSERT(size == USB_CFG_DESCR_SIZE); 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate /* set the configuration */ 6287c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, (usb_pipe_handle_t)ph_impl, 629112116d8Sfb USB_DEV_REQ_HOST_TO_DEV, 630112116d8Sfb USB_REQ_SET_CFG, 631112116d8Sfb confdescr.bConfigurationValue, 632112116d8Sfb 0, 633112116d8Sfb 0, 634112116d8Sfb NULL, 0, 635112116d8Sfb &completion_reason, 636112116d8Sfb &cb_flags, flags | USBA_FLAGS_PRIVILEGED | USB_FLAGS_SLEEP); 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 6397c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 6407c478bd9Sstevel@tonic-gate usba_device->usb_cfg_value = confdescr.bConfigurationValue; 6417c478bd9Sstevel@tonic-gate usba_device->usb_active_cfg_ndx = cfg_index; 6427c478bd9Sstevel@tonic-gate usba_device->usb_cfg = usba_device->usb_cfg_array[cfg_index]; 6437c478bd9Sstevel@tonic-gate usba_device->usb_cfg_length = confdescr.wTotalLength; 6447c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* update the configuration property */ 6477c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 648112116d8Sfb "configuration#", usba_device->usb_cfg_value); 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 65135f36846Ssl /* 65235f36846Ssl * usba_device->usb_cfg always stores current configuration 65335f36846Ssl * descriptor no matter SET_CFG request succeeded or not, 65435f36846Ssl * so usba_hubdi_decr_power_budget can be done regardless 65535f36846Ssl * of rval above 65635f36846Ssl */ 65735f36846Ssl usba_hubdi_decr_power_budget(pdip, usba_device); 65835f36846Ssl 6597c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 6607c478bd9Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason); 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate return (rval); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /* 6707c478bd9Sstevel@tonic-gate * usb_get_cfg(): 6717c478bd9Sstevel@tonic-gate * get configuration value 6727c478bd9Sstevel@tonic-gate * 6737c478bd9Sstevel@tonic-gate * Arguments: 6747c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 6757c478bd9Sstevel@tonic-gate * cfg_value - current config value 6767c478bd9Sstevel@tonic-gate * flags - none, always blocks 6777c478bd9Sstevel@tonic-gate * 6787c478bd9Sstevel@tonic-gate * Return Values: 6797c478bd9Sstevel@tonic-gate * USB_SUCCESS: - config value was retrieved 6807c478bd9Sstevel@tonic-gate * USB_FAILURE: - config value could not be retrieved 6817c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 6827c478bd9Sstevel@tonic-gate */ 6837c478bd9Sstevel@tonic-gate int 6847c478bd9Sstevel@tonic-gate usb_get_cfg(dev_info_t *dip, 6857c478bd9Sstevel@tonic-gate uint_t *cfgval, 6867c478bd9Sstevel@tonic-gate usb_flags_t flags) 6877c478bd9Sstevel@tonic-gate { 6887c478bd9Sstevel@tonic-gate int rval; 6897c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 6907c478bd9Sstevel@tonic-gate mblk_t *data = NULL; 6917c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 6927c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 6957c478bd9Sstevel@tonic-gate "usb_get_cfg: %s uf = 0x%x", ddi_node_name(dip), flags); 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate if ((cfgval == NULL) || (dip == NULL)) { 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip); 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate /* 7057c478bd9Sstevel@tonic-gate * get the cfg value 7067c478bd9Sstevel@tonic-gate */ 7077c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph, 708112116d8Sfb USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_DEV, 709112116d8Sfb USB_REQ_GET_CFG, 710112116d8Sfb 0, 711112116d8Sfb 0, 712112116d8Sfb 1, /* returns one byte of data */ 713112116d8Sfb &data, 0, 714112116d8Sfb &completion_reason, 715112116d8Sfb &cb_flags, flags); 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 7187c478bd9Sstevel@tonic-gate "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason); 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate if ((rval == USB_SUCCESS) && data && 721*d29f5a71Szhigang lu - Sun Microsystems - Beijing China (MBLKL(data) == 1)) { 7227c478bd9Sstevel@tonic-gate *cfgval = *(data->b_rptr); 7237c478bd9Sstevel@tonic-gate } else { 7247c478bd9Sstevel@tonic-gate *cfgval = 1; 7257c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 7267c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 7317c478bd9Sstevel@tonic-gate "usb_get_cfg: %s cfgval=%d", ddi_node_name(dip), *cfgval); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate freemsg(data); 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate return (rval); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate /* 7407c478bd9Sstevel@tonic-gate * usb_get_current_cfgidx: 7417c478bd9Sstevel@tonic-gate * get current current config index 7427c478bd9Sstevel@tonic-gate */ 7437c478bd9Sstevel@tonic-gate uint_t 7447c478bd9Sstevel@tonic-gate usb_get_current_cfgidx(dev_info_t *dip) 7457c478bd9Sstevel@tonic-gate { 7467c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 7477c478bd9Sstevel@tonic-gate uint_t ndx; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 7507c478bd9Sstevel@tonic-gate ndx = usba_device->usb_active_cfg_ndx; 7517c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate return (ndx); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate /* 7587c478bd9Sstevel@tonic-gate * usb_get_if_number: 7597c478bd9Sstevel@tonic-gate * get usb interface number of current OS device node. 7607c478bd9Sstevel@tonic-gate * 7617c478bd9Sstevel@tonic-gate * Arguments: 7627c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 7637c478bd9Sstevel@tonic-gate * 7647c478bd9Sstevel@tonic-gate * Return Values: 7657c478bd9Sstevel@tonic-gate * USB_COMBINED_NODE if the driver is responsible for the entire 7667c478bd9Sstevel@tonic-gate * device and this dip doesn't correspond to a device node. 7677c478bd9Sstevel@tonic-gate * USB_DEVICE_NODE if the driver is responsible for the entire device 7687c478bd9Sstevel@tonic-gate * and this dip corresponds to a device node. 7697c478bd9Sstevel@tonic-gate * interface number: otherwise. 7707c478bd9Sstevel@tonic-gate */ 7717c478bd9Sstevel@tonic-gate int 7727c478bd9Sstevel@tonic-gate usb_get_if_number(dev_info_t *dip) 7737c478bd9Sstevel@tonic-gate { 7747c478bd9Sstevel@tonic-gate int interface_num; 7757c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 7767c478bd9Sstevel@tonic-gate usb_dev_descr_t *usb_dev_descr; 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 779112116d8Sfb "usb_get_if_number: dip = 0x%p", (void *)dip); 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate /* not quite right but we can't return a negative return value */ 7827c478bd9Sstevel@tonic-gate if (dip == NULL) { 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate return (0); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate if (usba_device) { 7887c478bd9Sstevel@tonic-gate usb_dev_descr = usba_device->usb_dev_descr; 7897c478bd9Sstevel@tonic-gate } else { 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate return (0); 7927c478bd9Sstevel@tonic-gate } 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate interface_num = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 7957c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "interface", USB_COMBINED_NODE); 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate if (interface_num == USB_COMBINED_NODE) { 7987c478bd9Sstevel@tonic-gate if (!(((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) || 7997c478bd9Sstevel@tonic-gate (usb_dev_descr->bDeviceClass == 0)) && 8007c478bd9Sstevel@tonic-gate (usba_device->usb_n_cfgs == 1) && 8017c478bd9Sstevel@tonic-gate (usba_device->usb_n_ifs == 1))) { 8027c478bd9Sstevel@tonic-gate interface_num = USB_DEVICE_NODE; 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate return (interface_num); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate boolean_t 8117c478bd9Sstevel@tonic-gate usb_owns_device(dev_info_t *dip) 8127c478bd9Sstevel@tonic-gate { 8137c478bd9Sstevel@tonic-gate int interface_num = usb_get_if_number(dip); 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate return (interface_num < 0 ? B_TRUE : B_FALSE); 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate 819d73ae94eSgc /* check whether the interface is in this interface association */ 820d73ae94eSgc boolean_t 821d73ae94eSgc usba_check_if_in_ia(dev_info_t *dip, int n_if) 822d73ae94eSgc { 823d73ae94eSgc int first_if, if_count; 824d73ae94eSgc 825d73ae94eSgc first_if = usb_get_if_number(dip); 826d73ae94eSgc if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 827112116d8Sfb DDI_PROP_DONTPASS, "interface-count", -1); 828d73ae94eSgc if_count += first_if; 829d73ae94eSgc 830d73ae94eSgc return ((n_if >= first_if && n_if < if_count) ? B_TRUE : B_FALSE); 831d73ae94eSgc } 832d73ae94eSgc 833d73ae94eSgc 8347c478bd9Sstevel@tonic-gate uint8_t 8357c478bd9Sstevel@tonic-gate usba_get_ifno(dev_info_t *dip) 8367c478bd9Sstevel@tonic-gate { 8377c478bd9Sstevel@tonic-gate int interface_num = usb_get_if_number(dip); 8387c478bd9Sstevel@tonic-gate 839*d29f5a71Szhigang lu - Sun Microsystems - Beijing China return (uint8_t)(interface_num < 0 ? 0 : interface_num); 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate /* 8447c478bd9Sstevel@tonic-gate * usb_set_alt_if: 8457c478bd9Sstevel@tonic-gate * set the alternate interface number. Issues USB_REQ_SET_IF 8467c478bd9Sstevel@tonic-gate * This function will access the device 8477c478bd9Sstevel@tonic-gate * 8487c478bd9Sstevel@tonic-gate * Arguments: 8497c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 8507c478bd9Sstevel@tonic-gate * if_number - interface number 8517c478bd9Sstevel@tonic-gate * alt_number - alternate interface number 8527c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP: 8537c478bd9Sstevel@tonic-gate * wait for completion 8547c478bd9Sstevel@tonic-gate * cb - if USB_FLAGS_SLEEP has not been specified 8557c478bd9Sstevel@tonic-gate * this callback function will be called on 8567c478bd9Sstevel@tonic-gate * completion. This callback may be NULL 8577c478bd9Sstevel@tonic-gate * and no notification of completion will then 8587c478bd9Sstevel@tonic-gate * be provided. 8597c478bd9Sstevel@tonic-gate * cb_arg - 2nd argument to callback function. 8607c478bd9Sstevel@tonic-gate * 8617c478bd9Sstevel@tonic-gate * 8627c478bd9Sstevel@tonic-gate * return values: 8637c478bd9Sstevel@tonic-gate * USB_SUCCESS - alternate was set 8647c478bd9Sstevel@tonic-gate * USB_FAILURE - alternate could not be set because pipes 8657c478bd9Sstevel@tonic-gate * were still open or some access error occurred 8667c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 8677c478bd9Sstevel@tonic-gate * 8687c478bd9Sstevel@tonic-gate * Note: 8697c478bd9Sstevel@tonic-gate * we can't easily check if all pipes to endpoints for this interface 8707c478bd9Sstevel@tonic-gate * are closed since we don't have a map of which endpoints belong 8717c478bd9Sstevel@tonic-gate * to which interface. If we had this map, we would need to update 8727c478bd9Sstevel@tonic-gate * this on each alternative or configuration switch 8737c478bd9Sstevel@tonic-gate */ 8747c478bd9Sstevel@tonic-gate int 8757c478bd9Sstevel@tonic-gate usb_set_alt_if(dev_info_t *dip, 8767c478bd9Sstevel@tonic-gate uint_t interface, 8777c478bd9Sstevel@tonic-gate uint_t alt_number, 8787c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 8797c478bd9Sstevel@tonic-gate void (*cb)( 8807c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 8817c478bd9Sstevel@tonic-gate usb_opaque_t arg, 8827c478bd9Sstevel@tonic-gate int rval, 8837c478bd9Sstevel@tonic-gate usb_cb_flags_t flags), 8847c478bd9Sstevel@tonic-gate usb_opaque_t cb_arg) 8857c478bd9Sstevel@tonic-gate { 8867c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph; 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 8897c478bd9Sstevel@tonic-gate "usb_set_alt_if: %s%d, if = %d alt = %d, uf = 0x%x", 8907c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 8917c478bd9Sstevel@tonic-gate interface, alt_number, usb_flags); 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate if (dip == NULL) { 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) { 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT); 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip); 9047c478bd9Sstevel@tonic-gate if (usba_hold_ph_data(ph) == NULL) { 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate return (usba_pipe_setup_func_call(dip, 9107c478bd9Sstevel@tonic-gate usba_sync_set_alt_if, (usba_ph_impl_t *)ph, 9117c478bd9Sstevel@tonic-gate (usb_opaque_t)((uintptr_t)((interface << 8) | alt_number)), 9127c478bd9Sstevel@tonic-gate usb_flags, cb, cb_arg)); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate static int 9177c478bd9Sstevel@tonic-gate usba_sync_set_alt_if(dev_info_t *dip, 9187c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl, 9197c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request, 9207c478bd9Sstevel@tonic-gate usb_flags_t flags) 9217c478bd9Sstevel@tonic-gate { 9227c478bd9Sstevel@tonic-gate int rval; 9237c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 9247c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 9257c478bd9Sstevel@tonic-gate usb_opaque_t arg = request->arg; 9267c478bd9Sstevel@tonic-gate int interface = ((uintptr_t)arg >> 8) & 0xff; 9277c478bd9Sstevel@tonic-gate int alt_number = (uintptr_t)arg & 0xff; 9287c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data( 929112116d8Sfb (usb_pipe_handle_t)ph_impl); 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 9327c478bd9Sstevel@tonic-gate "usb_set_alt_if: %s, interface#=0x%x, alt#=0x%x, " 9337c478bd9Sstevel@tonic-gate "uf=0x%x", ddi_node_name(dip), interface, 9347c478bd9Sstevel@tonic-gate alt_number, flags); 9357c478bd9Sstevel@tonic-gate 936d73ae94eSgc /* if we don't own the device, we must own the interface or ia */ 937d73ae94eSgc if (!usb_owns_device(dip) && !usba_check_if_in_ia(dip, interface) && 9387c478bd9Sstevel@tonic-gate (interface != usb_get_if_number(dip))) { 9397c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate return (USB_INVALID_PERM); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate /* set the alternate setting */ 9457c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, usba_get_dflt_pipe_handle(dip), 946112116d8Sfb USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF, 947112116d8Sfb USB_REQ_SET_IF, 948112116d8Sfb alt_number, 949112116d8Sfb interface, 950112116d8Sfb 0, 951112116d8Sfb NULL, 0, 952112116d8Sfb &completion_reason, 953112116d8Sfb &cb_flags, flags | USB_FLAGS_SLEEP); 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 9567c478bd9Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason); 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate return (rval); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate /* 9657c478bd9Sstevel@tonic-gate * usb_get_alt_if: 9667c478bd9Sstevel@tonic-gate * get the alternate interface number. Issues USB_REQ_GET_IF 9677c478bd9Sstevel@tonic-gate * This function will access the device and block 9687c478bd9Sstevel@tonic-gate * 9697c478bd9Sstevel@tonic-gate * Arguments: 9707c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 9717c478bd9Sstevel@tonic-gate * if_number - interface number 9727c478bd9Sstevel@tonic-gate * alt_number - alternate interface number 9737c478bd9Sstevel@tonic-gate * flags - none but USB_FLAGS_SLEEP may be passed 9747c478bd9Sstevel@tonic-gate * 9757c478bd9Sstevel@tonic-gate * return values: 9767c478bd9Sstevel@tonic-gate * USB_SUCCESS: alternate was set 9777c478bd9Sstevel@tonic-gate * USB_FAILURE: alternate could not be set because pipes 9787c478bd9Sstevel@tonic-gate * were still open or some access error occurred 9797c478bd9Sstevel@tonic-gate */ 9807c478bd9Sstevel@tonic-gate int 9817c478bd9Sstevel@tonic-gate usb_get_alt_if(dev_info_t *dip, 9827c478bd9Sstevel@tonic-gate uint_t if_number, 9837c478bd9Sstevel@tonic-gate uint_t *alt_number, 9847c478bd9Sstevel@tonic-gate usb_flags_t flags) 9857c478bd9Sstevel@tonic-gate { 9867c478bd9Sstevel@tonic-gate int rval; 9877c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 9887c478bd9Sstevel@tonic-gate mblk_t *data = NULL; 9897c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 9907c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph; 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 9937c478bd9Sstevel@tonic-gate "usb_get_alt_if: %s, interface# = 0x%x, altp = 0x%p, " 9947c478bd9Sstevel@tonic-gate "uf = 0x%x", ddi_node_name(dip), if_number, 995112116d8Sfb (void *)alt_number, flags); 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate if ((alt_number == NULL) || (dip == NULL)) { 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip); 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* 10057c478bd9Sstevel@tonic-gate * get the alternate setting 10067c478bd9Sstevel@tonic-gate */ 10077c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph, 1008112116d8Sfb USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_IF, 1009112116d8Sfb USB_REQ_GET_IF, 1010112116d8Sfb 0, 1011112116d8Sfb if_number, 1012112116d8Sfb 1, /* returns one byte of data */ 1013112116d8Sfb &data, 0, 1014112116d8Sfb &completion_reason, 1015112116d8Sfb &cb_flags, flags); 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 10187c478bd9Sstevel@tonic-gate "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason); 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate if ((rval == USB_SUCCESS) && data && 1021*d29f5a71Szhigang lu - Sun Microsystems - Beijing China (MBLKL(data) == 1)) { 10227c478bd9Sstevel@tonic-gate *alt_number = *(data->b_rptr); 10237c478bd9Sstevel@tonic-gate } else { 10247c478bd9Sstevel@tonic-gate *alt_number = 0; 10257c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 10267c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 10277c478bd9Sstevel@tonic-gate } 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate freemsg(data); 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate return (rval); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate /* 10377c478bd9Sstevel@tonic-gate * usba_get_cfg_cloud: 10387c478bd9Sstevel@tonic-gate * Get descriptor cloud for a given configuration. 10397c478bd9Sstevel@tonic-gate * 10407c478bd9Sstevel@tonic-gate * Arguments: 10417c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 10427c478bd9Sstevel@tonic-gate * default_ph - default pipe handle 10437c478bd9Sstevel@tonic-gate * cfg - which configuration to retrieve raw cloud of 10447c478bd9Sstevel@tonic-gate * 10457c478bd9Sstevel@tonic-gate * Returns: 10467c478bd9Sstevel@tonic-gate * on success: mblock containing the raw data. Caller must free. 10477c478bd9Sstevel@tonic-gate * on failure: NULL 10487c478bd9Sstevel@tonic-gate */ 10497c478bd9Sstevel@tonic-gate static mblk_t * 10507c478bd9Sstevel@tonic-gate usba_get_cfg_cloud(dev_info_t *dip, usb_pipe_handle_t default_ph, int cfg) 10517c478bd9Sstevel@tonic-gate { 10527c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 10537c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 10547c478bd9Sstevel@tonic-gate usb_cfg_descr_t cfg_descr; 10557c478bd9Sstevel@tonic-gate mblk_t *pdata = NULL; 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate if (usb_pipe_sync_ctrl_xfer(dip, default_ph, 10587c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 10597c478bd9Sstevel@tonic-gate USB_REQ_GET_DESCR, 10607c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_SETUP_CFG | cfg, 10617c478bd9Sstevel@tonic-gate 0, 10627c478bd9Sstevel@tonic-gate USB_CFG_DESCR_SIZE, 10637c478bd9Sstevel@tonic-gate &pdata, 10647c478bd9Sstevel@tonic-gate 0, 10657c478bd9Sstevel@tonic-gate &completion_reason, 10667c478bd9Sstevel@tonic-gate &cb_flags, 10677c478bd9Sstevel@tonic-gate 0) != USB_SUCCESS) { 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate freemsg(pdata); 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate return (NULL); 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate (void) usb_parse_cfg_descr(pdata->b_rptr, 1075*d29f5a71Szhigang lu - Sun Microsystems - Beijing China MBLKL(pdata), &cfg_descr, USB_CFG_DESCR_SIZE); 10767c478bd9Sstevel@tonic-gate freemsg(pdata); 10777c478bd9Sstevel@tonic-gate pdata = NULL; 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate if (usb_pipe_sync_ctrl_xfer(dip, default_ph, 10807c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 10817c478bd9Sstevel@tonic-gate USB_REQ_GET_DESCR, 10827c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_SETUP_CFG | cfg, 10837c478bd9Sstevel@tonic-gate 0, 10847c478bd9Sstevel@tonic-gate cfg_descr.wTotalLength, 10857c478bd9Sstevel@tonic-gate &pdata, 10867c478bd9Sstevel@tonic-gate 0, 10877c478bd9Sstevel@tonic-gate &completion_reason, 10887c478bd9Sstevel@tonic-gate &cb_flags, 10897c478bd9Sstevel@tonic-gate 0) != USB_SUCCESS) { 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate freemsg(pdata); 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate return (NULL); 10947c478bd9Sstevel@tonic-gate } 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate return (pdata); 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate /* 11007c478bd9Sstevel@tonic-gate * usb_check_same_device: 11017c478bd9Sstevel@tonic-gate * Check if the device connected to the port is the same as 11027c478bd9Sstevel@tonic-gate * the previous device that was in the port. The previous device is 11037c478bd9Sstevel@tonic-gate * represented by the dip on record for the port. Print a message 11047c478bd9Sstevel@tonic-gate * if the device is different. If device_string arg is not NULL, it is 11057c478bd9Sstevel@tonic-gate * included in the message. Can block. 11067c478bd9Sstevel@tonic-gate * 11077c478bd9Sstevel@tonic-gate * Arguments: 11087c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 11097c478bd9Sstevel@tonic-gate * log_handle - handle to which messages are logged 11107c478bd9Sstevel@tonic-gate * log_level - one of USB_LOG_* 11117c478bd9Sstevel@tonic-gate * log_mask - logging mask 11127c478bd9Sstevel@tonic-gate * check_mask - one mask containing things to check: 11137c478bd9Sstevel@tonic-gate * USB_CHK_BASIC: empty mask; 11147c478bd9Sstevel@tonic-gate * these checks are always done. 11157c478bd9Sstevel@tonic-gate * USB_CHK_VIDPID: 11167c478bd9Sstevel@tonic-gate * check vid, pid only. 11177c478bd9Sstevel@tonic-gate * USB_CHK_SERIAL: check match on device 11187c478bd9Sstevel@tonic-gate * serial number. 11197c478bd9Sstevel@tonic-gate * USB_CHK_CFG: check all raw config 11207c478bd9Sstevel@tonic-gate * clouds for a match. 11217c478bd9Sstevel@tonic-gate * NOTE: descr length and content always checked 11227c478bd9Sstevel@tonic-gate * device_string - Device string to appear in error message 11237c478bd9Sstevel@tonic-gate * 11247c478bd9Sstevel@tonic-gate * return values: 11257c478bd9Sstevel@tonic-gate * USB_SUCCESS: same device 11267c478bd9Sstevel@tonic-gate * USB_INVALID_VERSION not same device 11277c478bd9Sstevel@tonic-gate * USB_FAILURE: Failure processing request 11287c478bd9Sstevel@tonic-gate * USB_INVALID_ARG: dip is invalid 11297c478bd9Sstevel@tonic-gate */ 11307c478bd9Sstevel@tonic-gate int 11317c478bd9Sstevel@tonic-gate usb_check_same_device(dev_info_t *dip, usb_log_handle_t log_handle, 11327c478bd9Sstevel@tonic-gate int log_level, int log_mask, uint_t check_mask, char *device_string) 11337c478bd9Sstevel@tonic-gate { 11347c478bd9Sstevel@tonic-gate usb_dev_descr_t usb_dev_descr; 11357c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 11367c478bd9Sstevel@tonic-gate mblk_t *pdata = NULL; 11377c478bd9Sstevel@tonic-gate uint16_t length; 11387c478bd9Sstevel@tonic-gate int rval; 11397c478bd9Sstevel@tonic-gate char *buf; 11407c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 11417c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 11427c478bd9Sstevel@tonic-gate boolean_t match = B_TRUE; 11437c478bd9Sstevel@tonic-gate usb_pipe_handle_t def_ph; 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate if (dip == NULL) { 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 11517c478bd9Sstevel@tonic-gate length = usba_device->usb_dev_descr->bLength; 11527c478bd9Sstevel@tonic-gate def_ph = usba_get_dflt_pipe_handle(dip); 11537c478bd9Sstevel@tonic-gate ASSERT(def_ph); 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate /* get the "new" device descriptor */ 11567c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, def_ph, 1157112116d8Sfb USB_DEV_REQ_DEV_TO_HOST | 1158112116d8Sfb USB_DEV_REQ_TYPE_STANDARD, 1159112116d8Sfb USB_REQ_GET_DESCR, /* bRequest */ 1160112116d8Sfb USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 1161112116d8Sfb 0, /* wIndex */ 1162112116d8Sfb length, /* wLength */ 1163112116d8Sfb &pdata, 0, 1164112116d8Sfb &completion_reason, 1165112116d8Sfb &cb_flags, USB_FLAGS_SLEEP); 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 11687c478bd9Sstevel@tonic-gate if (!((completion_reason == USB_CR_DATA_OVERRUN) && (pdata))) { 11697c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usbai_log_handle, 11707c478bd9Sstevel@tonic-gate "getting device descriptor failed (%d)", rval); 11717c478bd9Sstevel@tonic-gate freemsg(pdata); 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate return (USB_FAILURE); 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate ASSERT(pdata != NULL); 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate (void) usb_parse_dev_descr(pdata->b_rptr, 1180*d29f5a71Szhigang lu - Sun Microsystems - Beijing China MBLKL(pdata), &usb_dev_descr, 11817c478bd9Sstevel@tonic-gate sizeof (usb_dev_descr_t)); 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate freemsg(pdata); 11847c478bd9Sstevel@tonic-gate pdata = NULL; 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate /* Always check the device descriptor length. */ 11877c478bd9Sstevel@tonic-gate if (usb_dev_descr.bLength != length) { 11887c478bd9Sstevel@tonic-gate match = B_FALSE; 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate if ((match == B_TRUE) && (check_mask & USB_CHK_VIDPID)) { 11927c478bd9Sstevel@tonic-gate match = (usba_device->usb_dev_descr->idVendor == 11937c478bd9Sstevel@tonic-gate usb_dev_descr.idVendor) && 11947c478bd9Sstevel@tonic-gate (usba_device->usb_dev_descr->idProduct == 11957c478bd9Sstevel@tonic-gate usb_dev_descr.idProduct); 11967c478bd9Sstevel@tonic-gate } else if (bcmp((char *)usba_device->usb_dev_descr, 11977c478bd9Sstevel@tonic-gate (char *)&usb_dev_descr, length) != 0) { 11987c478bd9Sstevel@tonic-gate match = B_FALSE; 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate /* if requested & this device has a serial number check and compare */ 12027c478bd9Sstevel@tonic-gate if ((match == B_TRUE) && ((check_mask & USB_CHK_SERIAL) != 0) && 12037c478bd9Sstevel@tonic-gate (usba_device->usb_serialno_str != NULL)) { 12047c478bd9Sstevel@tonic-gate buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP); 12057c478bd9Sstevel@tonic-gate if (usb_get_string_descr(dip, USB_LANG_ID, 12067c478bd9Sstevel@tonic-gate usb_dev_descr.iSerialNumber, buf, 12077c478bd9Sstevel@tonic-gate USB_MAXSTRINGLEN) == USB_SUCCESS) { 12087c478bd9Sstevel@tonic-gate match = 12097c478bd9Sstevel@tonic-gate (strcmp(buf, usba_device->usb_serialno_str) == 0); 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate kmem_free(buf, USB_MAXSTRINGLEN); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate if ((match == B_TRUE) && (check_mask & USB_CHK_CFG)) { 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate uint8_t num_cfgs = usb_dev_descr.bNumConfigurations; 12177c478bd9Sstevel@tonic-gate uint8_t cfg; 12187c478bd9Sstevel@tonic-gate mblk_t *cloud; 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate for (cfg = 0; cfg < num_cfgs; cfg++) { 12217c478bd9Sstevel@tonic-gate cloud = usba_get_cfg_cloud(dip, def_ph, cfg); 12227c478bd9Sstevel@tonic-gate if (cloud == NULL) { 12237c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, 12247c478bd9Sstevel@tonic-gate usbai_log_handle, 12257c478bd9Sstevel@tonic-gate "Could not retrieve config cloud for " 12267c478bd9Sstevel@tonic-gate "comparison"); 12277c478bd9Sstevel@tonic-gate break; 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate if (bcmp((char *)cloud->b_rptr, 12317c478bd9Sstevel@tonic-gate usba_device->usb_cfg_array[cfg], 1232*d29f5a71Szhigang lu - Sun Microsystems - Beijing China MBLKL(cloud)) != 0) { 12337c478bd9Sstevel@tonic-gate freemsg(cloud); 12347c478bd9Sstevel@tonic-gate break; 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate freemsg(cloud); 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate if (cfg != num_cfgs) { 12407c478bd9Sstevel@tonic-gate match = B_FALSE; 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate if (match == B_FALSE) { 12457c478bd9Sstevel@tonic-gate boolean_t allocated_here = (device_string == NULL); 12467c478bd9Sstevel@tonic-gate if (allocated_here) { 12477c478bd9Sstevel@tonic-gate device_string = 12487c478bd9Sstevel@tonic-gate kmem_zalloc(USB_MAXSTRINGLEN, USB_FLAGS_SLEEP); 12497c478bd9Sstevel@tonic-gate (void) usba_get_mfg_prod_sn_str(dip, device_string, 1250112116d8Sfb USB_MAXSTRINGLEN); 12517c478bd9Sstevel@tonic-gate } 12527c478bd9Sstevel@tonic-gate if (device_string[0] != '\0') { 12537c478bd9Sstevel@tonic-gate (void) usb_log(log_handle, log_level, log_mask, 12547c478bd9Sstevel@tonic-gate "Cannot access %s. Please reconnect.", 12557c478bd9Sstevel@tonic-gate device_string); 12567c478bd9Sstevel@tonic-gate } else { 12577c478bd9Sstevel@tonic-gate (void) usb_log(log_handle, log_level, log_mask, 12587c478bd9Sstevel@tonic-gate "Device is not identical to the " 12597c478bd9Sstevel@tonic-gate "previous one this port.\n" 12607c478bd9Sstevel@tonic-gate "Please disconnect and reconnect"); 12617c478bd9Sstevel@tonic-gate } 12627c478bd9Sstevel@tonic-gate if (allocated_here) { 12637c478bd9Sstevel@tonic-gate kmem_free(device_string, USB_MAXSTRINGLEN); 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate /* 12747c478bd9Sstevel@tonic-gate * usb_pipe_get_state: 12757c478bd9Sstevel@tonic-gate * Return the state of the pipe 12767c478bd9Sstevel@tonic-gate * 12777c478bd9Sstevel@tonic-gate * Arguments: 12787c478bd9Sstevel@tonic-gate * pipe_handle - pipe_handle pointer 12797c478bd9Sstevel@tonic-gate * pipe_state - pointer to copy pipe state to 12807c478bd9Sstevel@tonic-gate * flags: 12817c478bd9Sstevel@tonic-gate * not used other than to check context 12827c478bd9Sstevel@tonic-gate * 12837c478bd9Sstevel@tonic-gate * Return Values: 12847c478bd9Sstevel@tonic-gate * USB_SUCCESS - port state returned 12857c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 12867c478bd9Sstevel@tonic-gate */ 12877c478bd9Sstevel@tonic-gate int 12887c478bd9Sstevel@tonic-gate usb_pipe_get_state(usb_pipe_handle_t pipe_handle, 12897c478bd9Sstevel@tonic-gate usb_pipe_state_t *pipe_state, 12907c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 12917c478bd9Sstevel@tonic-gate { 12927c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1295112116d8Sfb "usb_pipe_get_state: ph_data=0x%p uf=0x%x", (void *)ph_data, 1296112116d8Sfb usb_flags); 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate if (pipe_state == NULL) { 12997c478bd9Sstevel@tonic-gate if (ph_data) { 13007c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate if (ph_data == NULL) { 13077c478bd9Sstevel@tonic-gate *pipe_state = USB_PIPE_STATE_CLOSED; 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 13137c478bd9Sstevel@tonic-gate *pipe_state = usba_get_ph_state(ph_data); 13147c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate /* 13237c478bd9Sstevel@tonic-gate * usba_pipe_get_policy: 13247c478bd9Sstevel@tonic-gate * Return a pipe's policy 13257c478bd9Sstevel@tonic-gate * 13267c478bd9Sstevel@tonic-gate * Arguments: 13277c478bd9Sstevel@tonic-gate * pipe_handle - pipe_handle pointer 13287c478bd9Sstevel@tonic-gate * 13297c478bd9Sstevel@tonic-gate * Return Values: 13307c478bd9Sstevel@tonic-gate * On success: the pipe's policy 13317c478bd9Sstevel@tonic-gate * On failure: NULL 13327c478bd9Sstevel@tonic-gate */ 13337c478bd9Sstevel@tonic-gate usb_pipe_policy_t 13347c478bd9Sstevel@tonic-gate *usba_pipe_get_policy(usb_pipe_handle_t pipe_handle) 13357c478bd9Sstevel@tonic-gate { 13367c478bd9Sstevel@tonic-gate usb_pipe_policy_t *pp = NULL; 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate if (ph_data) { 13417c478bd9Sstevel@tonic-gate pp = &ph_data->p_policy; 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 13447c478bd9Sstevel@tonic-gate } 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate return (pp); 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate /* 13517c478bd9Sstevel@tonic-gate * usb_ep_num: 13527c478bd9Sstevel@tonic-gate * Return the endpoint number for a given pipe handle 13537c478bd9Sstevel@tonic-gate * 13547c478bd9Sstevel@tonic-gate * Arguments: 13557c478bd9Sstevel@tonic-gate * pipe_handle - pipe_handle pointer 13567c478bd9Sstevel@tonic-gate * 13577c478bd9Sstevel@tonic-gate * Return Values: 13587c478bd9Sstevel@tonic-gate * endpoint number 13597c478bd9Sstevel@tonic-gate */ 13607c478bd9Sstevel@tonic-gate int 13617c478bd9Sstevel@tonic-gate usb_ep_num(usb_pipe_handle_t pipe_handle) 13627c478bd9Sstevel@tonic-gate { 13637c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 13647c478bd9Sstevel@tonic-gate int ep_num; 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate if (ph_data == NULL) { 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 13727c478bd9Sstevel@tonic-gate ep_num = ph_data->p_ep.bEndpointAddress & USB_EP_NUM_MASK; 13737c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate return (ep_num); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* 13827c478bd9Sstevel@tonic-gate * usb_get_status 13837c478bd9Sstevel@tonic-gate * Issues USB_REQ_GET_STATUS to device/endpoint/interface 13847c478bd9Sstevel@tonic-gate * and report in "status" arg. 13857c478bd9Sstevel@tonic-gate * 13867c478bd9Sstevel@tonic-gate * status reported for a "device" is 13877c478bd9Sstevel@tonic-gate * RemoteWakeup enabled 13887c478bd9Sstevel@tonic-gate * SelfPowered device? 13897c478bd9Sstevel@tonic-gate * 13907c478bd9Sstevel@tonic-gate * status reported for an "interface" is NONE. 13917c478bd9Sstevel@tonic-gate * status reported for an "endpoint" is 13927c478bd9Sstevel@tonic-gate * HALT set (device STALLED?) 13937c478bd9Sstevel@tonic-gate * 13947c478bd9Sstevel@tonic-gate * Arguments: 13957c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 13967c478bd9Sstevel@tonic-gate * ph - pipe handle 13977c478bd9Sstevel@tonic-gate * type - bmRequestType to be used 13987c478bd9Sstevel@tonic-gate * what - 0 for device, otherwise interface or ep number 13997c478bd9Sstevel@tonic-gate * status - user supplied pointer for storing the status 14007c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP (mandatory) 14017c478bd9Sstevel@tonic-gate * 14027c478bd9Sstevel@tonic-gate * Return Values: 14037c478bd9Sstevel@tonic-gate * valid usb_status_t or USB_FAILURE 14047c478bd9Sstevel@tonic-gate */ 14057c478bd9Sstevel@tonic-gate int 14067c478bd9Sstevel@tonic-gate usb_get_status(dev_info_t *dip, 14077c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 14087c478bd9Sstevel@tonic-gate uint_t type, /* bmRequestType */ 14097c478bd9Sstevel@tonic-gate uint_t what, /* 0, interface, ept number */ 14107c478bd9Sstevel@tonic-gate uint16_t *status, 14117c478bd9Sstevel@tonic-gate usb_flags_t flags) 14127c478bd9Sstevel@tonic-gate { 14137c478bd9Sstevel@tonic-gate int rval; 14147c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 14157c478bd9Sstevel@tonic-gate mblk_t *data = NULL; 14167c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 14197c478bd9Sstevel@tonic-gate "usb_get_status: type = 0x%x, what = 0x%x, uf = 0x%x", 14207c478bd9Sstevel@tonic-gate type, what, flags); 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate if ((status == NULL) || (dip == NULL)) { 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate if (ph == NULL) { 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 14297c478bd9Sstevel@tonic-gate } 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate type |= USB_DEV_REQ_DEV_TO_HOST; 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate /* get the status */ 14347c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph, 1435112116d8Sfb type, 1436112116d8Sfb USB_REQ_GET_STATUS, 1437112116d8Sfb 0, 1438112116d8Sfb what, 1439112116d8Sfb USB_GET_STATUS_LEN, /* status is fixed 2 bytes long */ 1440112116d8Sfb &data, 0, 1441112116d8Sfb &completion_reason, &cb_flags, flags); 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 14447c478bd9Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason); 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate if ((rval == USB_SUCCESS) && data && 1447*d29f5a71Szhigang lu - Sun Microsystems - Beijing China (MBLKL(data) == USB_GET_STATUS_LEN)) { 14487c478bd9Sstevel@tonic-gate *status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 14497c478bd9Sstevel@tonic-gate } else { 14507c478bd9Sstevel@tonic-gate *status = 0; 14517c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 14527c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate freemsg(data); 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate return (rval); 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate /* 14637c478bd9Sstevel@tonic-gate * usb_clear_feature: 14647c478bd9Sstevel@tonic-gate * Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface 14657c478bd9Sstevel@tonic-gate * 14667c478bd9Sstevel@tonic-gate * Arguments: 14677c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 14687c478bd9Sstevel@tonic-gate * ph - pipe handle pointer 14697c478bd9Sstevel@tonic-gate * type - bmRequestType to be used 14707c478bd9Sstevel@tonic-gate * feature - feature to be cleared 14717c478bd9Sstevel@tonic-gate * what - 0 for device, otherwise interface or ep number 14727c478bd9Sstevel@tonic-gate * flags - none (but will sleep) 14737c478bd9Sstevel@tonic-gate * 14747c478bd9Sstevel@tonic-gate * Return Values: 14757c478bd9Sstevel@tonic-gate * USB_SUCCESS - on doing a successful clear feature 14767c478bd9Sstevel@tonic-gate * USB_FAILURE - on failure 14777c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 14787c478bd9Sstevel@tonic-gate */ 14797c478bd9Sstevel@tonic-gate int 14807c478bd9Sstevel@tonic-gate usb_clear_feature(dev_info_t *dip, 14817c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 14827c478bd9Sstevel@tonic-gate uint_t type, /* bmRequestType */ 14837c478bd9Sstevel@tonic-gate uint_t feature, 14847c478bd9Sstevel@tonic-gate uint_t what, /* 0, interface, ept number */ 14857c478bd9Sstevel@tonic-gate usb_flags_t flags) 14867c478bd9Sstevel@tonic-gate { 14877c478bd9Sstevel@tonic-gate int rval; 14887c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 14897c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 14927c478bd9Sstevel@tonic-gate "usb_clear_feature: type = 0x%x, feature = 0x%x, what = 0x%x " 14937c478bd9Sstevel@tonic-gate "uf = 0x%x", type, feature, what, flags); 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate if (dip == NULL) { 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 14987c478bd9Sstevel@tonic-gate } 14997c478bd9Sstevel@tonic-gate if (ph == NULL) { 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate /* issue Clear feature */ 15057c478bd9Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph, 1506112116d8Sfb type, 1507112116d8Sfb USB_REQ_CLEAR_FEATURE, 1508112116d8Sfb feature, 1509112116d8Sfb what, 1510112116d8Sfb 0, 1511112116d8Sfb NULL, 0, 1512112116d8Sfb &completion_reason, 1513112116d8Sfb &cb_flags, flags | USB_FLAGS_SLEEP); 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 15167c478bd9Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason); 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate return (rval); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate /* 15237c478bd9Sstevel@tonic-gate * usb_clr_feature: 15247c478bd9Sstevel@tonic-gate * Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface 15257c478bd9Sstevel@tonic-gate * 15267c478bd9Sstevel@tonic-gate * Arguments: 15277c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 15287c478bd9Sstevel@tonic-gate * type - bmRequestType to be used 15297c478bd9Sstevel@tonic-gate * feature - feature to be cleared 15307c478bd9Sstevel@tonic-gate * what - 0 for device, otherwise interface or ep number 15317c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP: 15327c478bd9Sstevel@tonic-gate * wait for completion 15337c478bd9Sstevel@tonic-gate * cb - if USB_FLAGS_SLEEP has not been specified 15347c478bd9Sstevel@tonic-gate * this callback function will be called on 15357c478bd9Sstevel@tonic-gate * completion. This callback may be NULL 15367c478bd9Sstevel@tonic-gate * and no notification of completion will then 15377c478bd9Sstevel@tonic-gate * be provided. 15387c478bd9Sstevel@tonic-gate * cb_arg - 2nd argument to callback function. 15397c478bd9Sstevel@tonic-gate * 15407c478bd9Sstevel@tonic-gate * 15417c478bd9Sstevel@tonic-gate * Return Values: 15427c478bd9Sstevel@tonic-gate * USB_SUCCESS - on doing a successful clear feature 15437c478bd9Sstevel@tonic-gate * USB_FAILURE - on failure 15447c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 15457c478bd9Sstevel@tonic-gate */ 15467c478bd9Sstevel@tonic-gate int 15477c478bd9Sstevel@tonic-gate usb_clr_feature( 15487c478bd9Sstevel@tonic-gate dev_info_t *dip, 15497c478bd9Sstevel@tonic-gate uint_t type, /* bmRequestType */ 15507c478bd9Sstevel@tonic-gate uint_t feature, 15517c478bd9Sstevel@tonic-gate uint_t what, /* 0, interface, ept number */ 15527c478bd9Sstevel@tonic-gate usb_flags_t flags, 15537c478bd9Sstevel@tonic-gate void (*cb)( 15547c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 15557c478bd9Sstevel@tonic-gate usb_opaque_t arg, 15567c478bd9Sstevel@tonic-gate int rval, 15577c478bd9Sstevel@tonic-gate usb_cb_flags_t flags), 15587c478bd9Sstevel@tonic-gate usb_opaque_t cb_arg) 15597c478bd9Sstevel@tonic-gate { 15607c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph; 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 15637c478bd9Sstevel@tonic-gate "usb_clr_feature: type = 0x%x, feature = 0x%x, what = 0x%x " 15647c478bd9Sstevel@tonic-gate "uf = 0x%x", type, feature, what, flags); 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate if (dip == NULL) { 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate if ((flags & USB_FLAGS_SLEEP) && servicing_interrupt()) { 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT); 15747c478bd9Sstevel@tonic-gate } 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip); 15777c478bd9Sstevel@tonic-gate if (usba_hold_ph_data(ph) == NULL) { 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 15807c478bd9Sstevel@tonic-gate } 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate return (usba_pipe_setup_func_call(dip, 15837c478bd9Sstevel@tonic-gate usba_sync_clear_feature, (usba_ph_impl_t *)ph, 15847c478bd9Sstevel@tonic-gate (usb_opaque_t)((uintptr_t)((type << 16 | feature << 8 | what))), 15857c478bd9Sstevel@tonic-gate flags, cb, cb_arg)); 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate static int 15907c478bd9Sstevel@tonic-gate usba_sync_clear_feature(dev_info_t *dip, 15917c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl, 15927c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *req, 1593112116d8Sfb usb_flags_t usb_flags) 15947c478bd9Sstevel@tonic-gate { 15957c478bd9Sstevel@tonic-gate uint_t n = (uint_t)((uintptr_t)(req->arg)); 15967c478bd9Sstevel@tonic-gate uint_t type = ((uint_t)n >> 16) & 0xff; 15977c478bd9Sstevel@tonic-gate uint_t feature = ((uint_t)n >> 8) & 0xff; 15987c478bd9Sstevel@tonic-gate uint_t what = (uint_t)n & 0xff; 1599112116d8Sfb int rval; 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 16027c478bd9Sstevel@tonic-gate "usb_sync_clear_feature: " 16037c478bd9Sstevel@tonic-gate "dip=0x%p ph=0x%p type=0x%x feature=0x%x what=0x%x fl=0x%x", 1604112116d8Sfb (void *)dip, (void *)ph_impl, type, feature, what, usb_flags); 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate rval = usb_clear_feature(dip, (usb_pipe_handle_t)ph_impl, type, 1607112116d8Sfb feature, what, usb_flags); 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate return (rval); 16127c478bd9Sstevel@tonic-gate } 16137c478bd9Sstevel@tonic-gate 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate /* 16167c478bd9Sstevel@tonic-gate * usb_async_req: 16177c478bd9Sstevel@tonic-gate * function used to dispatch a request to the taskq 16187c478bd9Sstevel@tonic-gate * 16197c478bd9Sstevel@tonic-gate * Arguments: 16207c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node 16217c478bd9Sstevel@tonic-gate * func - pointer to function issued by taskq 16227c478bd9Sstevel@tonic-gate * flag - USB_FLAGS_SLEEP mostly 16237c478bd9Sstevel@tonic-gate * 16247c478bd9Sstevel@tonic-gate * Return Values: 16257c478bd9Sstevel@tonic-gate * USB_SUCCESS - on doing a successful taskq invocation 16267c478bd9Sstevel@tonic-gate * USB_FAILURE - on failure 16277c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 16287c478bd9Sstevel@tonic-gate */ 16297c478bd9Sstevel@tonic-gate int 16307c478bd9Sstevel@tonic-gate usb_async_req(dev_info_t *dip, 16317c478bd9Sstevel@tonic-gate void (*func)(void *), 16327c478bd9Sstevel@tonic-gate void *arg, 16337c478bd9Sstevel@tonic-gate usb_flags_t flag) 16347c478bd9Sstevel@tonic-gate { 16357c478bd9Sstevel@tonic-gate int tq_flag; 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 16387c478bd9Sstevel@tonic-gate "usb_async_req: dip=0x%p func=0x%p, arg=0x%p flag=0x%x", 1639112116d8Sfb (void *)dip, (void *)func, arg, flag); 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate if ((dip == NULL) || (func == NULL)) { 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP; 16467c478bd9Sstevel@tonic-gate if (flag & USB_FLAGS_NOQUEUE) { 16477c478bd9Sstevel@tonic-gate tq_flag |= TQ_NOQUEUE; 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate if (!taskq_dispatch(system_taskq, func, (void *)arg, 16517c478bd9Sstevel@tonic-gate tq_flag)) { 16527c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 16537c478bd9Sstevel@tonic-gate "usb_async_req: failure"); 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate return (USB_FAILURE); 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 16597c478bd9Sstevel@tonic-gate } 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate /* 16627c478bd9Sstevel@tonic-gate * usba_async_ph_req: 16637c478bd9Sstevel@tonic-gate * function used to dispatch a request to the ph taskq 16647c478bd9Sstevel@tonic-gate * 16657c478bd9Sstevel@tonic-gate * Arguments: 16667c478bd9Sstevel@tonic-gate * ph_data - pointer to pipe handle data 16677c478bd9Sstevel@tonic-gate * func - pointer to function issued by taskq 16687c478bd9Sstevel@tonic-gate * flag - USB_FLAGS_SLEEP or USB_FLAGS_NOSLEEP 16697c478bd9Sstevel@tonic-gate * 16707c478bd9Sstevel@tonic-gate * Return Values: 16717c478bd9Sstevel@tonic-gate * USB_SUCCESS - on doing a successful taskq invocation 16727c478bd9Sstevel@tonic-gate * USB_FAILURE - on failure 16737c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 16747c478bd9Sstevel@tonic-gate * 16757c478bd9Sstevel@tonic-gate * Note: 16767c478bd9Sstevel@tonic-gate * If the caller specified USB_FLAGS_NOSLEEP, it must be 16777c478bd9Sstevel@tonic-gate * capable of reliably recovering from a failure return 16787c478bd9Sstevel@tonic-gate */ 16797c478bd9Sstevel@tonic-gate int 16807c478bd9Sstevel@tonic-gate usba_async_ph_req(usba_pipe_handle_data_t *ph_data, 16817c478bd9Sstevel@tonic-gate void (*func)(void *), 16827c478bd9Sstevel@tonic-gate void *arg, 16837c478bd9Sstevel@tonic-gate usb_flags_t flag) 16847c478bd9Sstevel@tonic-gate { 16857c478bd9Sstevel@tonic-gate int tq_flag; 16867c478bd9Sstevel@tonic-gate taskq_t *taskq; 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 16897c478bd9Sstevel@tonic-gate "usba_async_ph_req: ph_data=0x%p func=0x%p, arg=0x%p flag=0x%x", 1690112116d8Sfb (void *)ph_data, (void *)func, arg, flag); 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate if (func == NULL) { 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 16957c478bd9Sstevel@tonic-gate } 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP; 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate if (ph_data && ph_data->p_taskq) { 17007c478bd9Sstevel@tonic-gate taskq = ph_data->p_taskq; 17017c478bd9Sstevel@tonic-gate } else { 17027c478bd9Sstevel@tonic-gate taskq = system_taskq; 17037c478bd9Sstevel@tonic-gate tq_flag |= TQ_NOQUEUE; 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate if (!taskq_dispatch(taskq, func, (void *)arg, tq_flag)) { 17077c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 17087c478bd9Sstevel@tonic-gate "usba_async_ph_req: failure"); 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate return (USB_FAILURE); 17117c478bd9Sstevel@tonic-gate } 17127c478bd9Sstevel@tonic-gate 17137c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate /* 17187c478bd9Sstevel@tonic-gate * utility functions to display CR, CB, return values 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate typedef struct conv_table { 17217c478bd9Sstevel@tonic-gate int what; 17227c478bd9Sstevel@tonic-gate const char *name; 17237c478bd9Sstevel@tonic-gate } conv_table_t; 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate static const char * 17267c478bd9Sstevel@tonic-gate usba_get_name(conv_table_t *conv_table, int value) 17277c478bd9Sstevel@tonic-gate { 17287c478bd9Sstevel@tonic-gate int i; 17297c478bd9Sstevel@tonic-gate for (i = 0; conv_table[i].name != NULL; i++) { 17307c478bd9Sstevel@tonic-gate if (conv_table[i].what == value) { 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate return (conv_table[i].name); 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate } 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate return ("unknown"); 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate static conv_table_t cr_table[] = { 17417c478bd9Sstevel@tonic-gate { USB_CR_OK, "<no errors detected>" }, 17427c478bd9Sstevel@tonic-gate { USB_CR_CRC, "<crc error detected>" }, 17437c478bd9Sstevel@tonic-gate { USB_CR_BITSTUFFING, "<Bit stuffing violation>" }, 17447c478bd9Sstevel@tonic-gate { USB_CR_DATA_TOGGLE_MM, "<Data toggle PID did not match>" }, 17457c478bd9Sstevel@tonic-gate { USB_CR_STALL, "<Endpoint returned stall PID>" }, 17467c478bd9Sstevel@tonic-gate { USB_CR_DEV_NOT_RESP, "<Device not responding>" }, 17477c478bd9Sstevel@tonic-gate { USB_CR_PID_CHECKFAILURE, "<Check bits on PID failed>" }, 17487c478bd9Sstevel@tonic-gate { USB_CR_UNEXP_PID, "<Receive PID was not valid>" }, 17497c478bd9Sstevel@tonic-gate { USB_CR_DATA_OVERRUN, "<Data size exceeded>" }, 17507c478bd9Sstevel@tonic-gate { USB_CR_DATA_UNDERRUN, "<Less data recieved than requested>" }, 17517c478bd9Sstevel@tonic-gate { USB_CR_BUFFER_OVERRUN, "<Memory write can't keep up>" }, 17527c478bd9Sstevel@tonic-gate { USB_CR_BUFFER_UNDERRUN, "<Buffer underrun>" }, 17537c478bd9Sstevel@tonic-gate { USB_CR_TIMEOUT, "<Command timed out>" }, 17547c478bd9Sstevel@tonic-gate { USB_CR_NOT_ACCESSED, "<Not accessed by hardware>" }, 17557c478bd9Sstevel@tonic-gate { USB_CR_NO_RESOURCES, "<No resources>" }, 17567c478bd9Sstevel@tonic-gate { USB_CR_UNSPECIFIED_ERR, "<Unspecified usba or hcd error>" }, 17577c478bd9Sstevel@tonic-gate { USB_CR_STOPPED_POLLING, "<Intr/ISOC IN polling stopped>" }, 17587c478bd9Sstevel@tonic-gate { USB_CR_PIPE_CLOSING, "<Intr/ISOC IN pipe being closed>" }, 17597c478bd9Sstevel@tonic-gate { USB_CR_PIPE_RESET, "<Intr/ISOC IN pipe reset>" }, 17607c478bd9Sstevel@tonic-gate { USB_CR_NOT_SUPPORTED, "<Command not supported>" }, 17617c478bd9Sstevel@tonic-gate { USB_CR_FLUSHED, "<Req was flushed>" }, 17627c478bd9Sstevel@tonic-gate { USB_CR_HC_HARDWARE_ERR, "<USB host controller error>" }, 17637c478bd9Sstevel@tonic-gate { 0, NULL } 17647c478bd9Sstevel@tonic-gate }; 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate const char * 17677c478bd9Sstevel@tonic-gate usb_str_cr(usb_cr_t cr) 17687c478bd9Sstevel@tonic-gate { 17697c478bd9Sstevel@tonic-gate return (usba_get_name(cr_table, cr)); 17707c478bd9Sstevel@tonic-gate } 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate static conv_table_t cb_flags_table[] = { 17747c478bd9Sstevel@tonic-gate { USB_CB_NO_INFO, "<callback processed>" }, 17757c478bd9Sstevel@tonic-gate { USB_CB_STALL_CLEARED, "<stall cleared>" }, 17767c478bd9Sstevel@tonic-gate { USB_CB_FUNCTIONAL_STALL, "<functional stall>" }, 17777c478bd9Sstevel@tonic-gate { USB_CB_PROTOCOL_STALL, "<protocol stall>" }, 17787c478bd9Sstevel@tonic-gate { USB_CB_RESET_PIPE, "<pipe reset>" }, 17797c478bd9Sstevel@tonic-gate { USB_CB_ASYNC_REQ_FAILED, "<thread could not be started>" }, 17807c478bd9Sstevel@tonic-gate { USB_CB_NO_RESOURCES, "<no resources>" }, 17817c478bd9Sstevel@tonic-gate { USB_CB_SUBMIT_FAILED, "<submit failed>" }, 17827c478bd9Sstevel@tonic-gate { USB_CB_INTR_CONTEXT, "<Callback executing in interrupt context>" }, 17837c478bd9Sstevel@tonic-gate { 0, NULL } 17847c478bd9Sstevel@tonic-gate }; 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17877c478bd9Sstevel@tonic-gate char * 17887c478bd9Sstevel@tonic-gate usb_str_cb_flags(usb_cb_flags_t cb_flags, char *buffer, size_t length) 17897c478bd9Sstevel@tonic-gate { 17907c478bd9Sstevel@tonic-gate int i; 17917c478bd9Sstevel@tonic-gate buffer[0] = '\0'; 17927c478bd9Sstevel@tonic-gate if (cb_flags == USB_CB_NO_INFO) { 17937c478bd9Sstevel@tonic-gate (void) strncpy(buffer, cb_flags_table[0].name, length); 17947c478bd9Sstevel@tonic-gate } else { 17957c478bd9Sstevel@tonic-gate for (i = 0; cb_flags_table[i].name != NULL; i++) { 17967c478bd9Sstevel@tonic-gate if (cb_flags & cb_flags_table[i].what) { 17977c478bd9Sstevel@tonic-gate (void) strncpy(&buffer[strlen(buffer)], 17987c478bd9Sstevel@tonic-gate cb_flags_table[0].name, 17997c478bd9Sstevel@tonic-gate length - strlen(buffer) - 1); 18007c478bd9Sstevel@tonic-gate } 18017c478bd9Sstevel@tonic-gate } 18027c478bd9Sstevel@tonic-gate } 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate return (buffer); 18057c478bd9Sstevel@tonic-gate } 18067c478bd9Sstevel@tonic-gate 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate static conv_table_t pipe_state_table[] = { 18097c478bd9Sstevel@tonic-gate { USB_PIPE_STATE_CLOSED, "<closed>" }, 18107c478bd9Sstevel@tonic-gate { USB_PIPE_STATE_IDLE, "<idle>" }, 18117c478bd9Sstevel@tonic-gate { USB_PIPE_STATE_ACTIVE, "<active>" }, 18127c478bd9Sstevel@tonic-gate { USB_PIPE_STATE_ERROR, "<error>" }, 18137c478bd9Sstevel@tonic-gate { USB_PIPE_STATE_CLOSING, "<closing>" }, 18147c478bd9Sstevel@tonic-gate { 0, NULL } 18157c478bd9Sstevel@tonic-gate }; 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate const char * 18187c478bd9Sstevel@tonic-gate usb_str_pipe_state(usb_pipe_state_t state) 18197c478bd9Sstevel@tonic-gate { 18207c478bd9Sstevel@tonic-gate return (usba_get_name(pipe_state_table, state)); 18217c478bd9Sstevel@tonic-gate } 18227c478bd9Sstevel@tonic-gate 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate static conv_table_t dev_state[] = { 18257c478bd9Sstevel@tonic-gate { USB_DEV_ONLINE, "<online>" }, 18267c478bd9Sstevel@tonic-gate { USB_DEV_DISCONNECTED, "<disconnected>" }, 18277c478bd9Sstevel@tonic-gate { USB_DEV_SUSPENDED, "<suspended>" }, 18287c478bd9Sstevel@tonic-gate { USB_DEV_PWRED_DOWN, "<powered down>" }, 18297c478bd9Sstevel@tonic-gate { 0, NULL } 18307c478bd9Sstevel@tonic-gate }; 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate const char * 18337c478bd9Sstevel@tonic-gate usb_str_dev_state(int state) 18347c478bd9Sstevel@tonic-gate { 18357c478bd9Sstevel@tonic-gate return (usba_get_name(dev_state, state)); 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate static conv_table_t rval_table[] = { 18407c478bd9Sstevel@tonic-gate { USB_SUCCESS, "<success>" }, 18417c478bd9Sstevel@tonic-gate { USB_FAILURE, "<failure>" }, 18427c478bd9Sstevel@tonic-gate { USB_NO_RESOURCES, "<no resources>" }, 18437c478bd9Sstevel@tonic-gate { USB_NO_BANDWIDTH, "<no bandwidth>" }, 18447c478bd9Sstevel@tonic-gate { USB_NOT_SUPPORTED, "<not supported>" }, 18457c478bd9Sstevel@tonic-gate { USB_PIPE_ERROR, "<pipe error>" }, 18467c478bd9Sstevel@tonic-gate { USB_INVALID_PIPE, "<invalid pipe>" }, 18477c478bd9Sstevel@tonic-gate { USB_NO_FRAME_NUMBER, "<no frame number>" }, 18487c478bd9Sstevel@tonic-gate { USB_INVALID_START_FRAME, "<invalid frame>" }, 18497c478bd9Sstevel@tonic-gate { USB_HC_HARDWARE_ERROR, "<hw error>" }, 18507c478bd9Sstevel@tonic-gate { USB_INVALID_REQUEST, "<invalid request>" }, 18517c478bd9Sstevel@tonic-gate { USB_INVALID_CONTEXT, "<invalid context>" }, 18527c478bd9Sstevel@tonic-gate { USB_INVALID_VERSION, "<invalid version>" }, 18537c478bd9Sstevel@tonic-gate { USB_INVALID_ARGS, "<invalid args>" }, 18547c478bd9Sstevel@tonic-gate { USB_INVALID_PERM, "<invalid perms>" }, 18557c478bd9Sstevel@tonic-gate { USB_BUSY, "<busy>" }, 18567c478bd9Sstevel@tonic-gate { 0, NULL } 18577c478bd9Sstevel@tonic-gate }; 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate const char * 18607c478bd9Sstevel@tonic-gate usb_str_rval(int rval) 18617c478bd9Sstevel@tonic-gate { 18627c478bd9Sstevel@tonic-gate return (usba_get_name(rval_table, rval)); 18637c478bd9Sstevel@tonic-gate } 18647c478bd9Sstevel@tonic-gate 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate /* 18677c478bd9Sstevel@tonic-gate * function to convert USB return values to close errno 18687c478bd9Sstevel@tonic-gate */ 18697c478bd9Sstevel@tonic-gate static struct usb_rval2errno_entry { 18707c478bd9Sstevel@tonic-gate int rval; 18717c478bd9Sstevel@tonic-gate int Errno; 18727c478bd9Sstevel@tonic-gate } usb_rval2errno_table[] = { 18737c478bd9Sstevel@tonic-gate { USB_SUCCESS, 0 }, 18747c478bd9Sstevel@tonic-gate { USB_FAILURE, EIO }, 18757c478bd9Sstevel@tonic-gate { USB_NO_RESOURCES, ENOMEM }, 18767c478bd9Sstevel@tonic-gate { USB_NO_BANDWIDTH, EAGAIN }, 18777c478bd9Sstevel@tonic-gate { USB_NOT_SUPPORTED, ENOTSUP }, 18787c478bd9Sstevel@tonic-gate { USB_PIPE_ERROR, EIO }, 18797c478bd9Sstevel@tonic-gate { USB_INVALID_PIPE, EINVAL }, 18807c478bd9Sstevel@tonic-gate { USB_NO_FRAME_NUMBER, EINVAL }, 18817c478bd9Sstevel@tonic-gate { USB_INVALID_START_FRAME, EINVAL }, 18827c478bd9Sstevel@tonic-gate { USB_HC_HARDWARE_ERROR, EIO }, 18837c478bd9Sstevel@tonic-gate { USB_INVALID_REQUEST, EINVAL }, 18847c478bd9Sstevel@tonic-gate { USB_INVALID_CONTEXT, EINVAL }, 18857c478bd9Sstevel@tonic-gate { USB_INVALID_VERSION, EINVAL }, 18867c478bd9Sstevel@tonic-gate { USB_INVALID_ARGS, EINVAL }, 18877c478bd9Sstevel@tonic-gate { USB_INVALID_PERM, EACCES }, 18887c478bd9Sstevel@tonic-gate { USB_BUSY, EBUSY }, 18897c478bd9Sstevel@tonic-gate }; 18907c478bd9Sstevel@tonic-gate 18917c478bd9Sstevel@tonic-gate #define USB_RVAL2ERRNO_TABLE_SIZE (sizeof (usb_rval2errno_table) / \ 18927c478bd9Sstevel@tonic-gate sizeof (struct usb_rval2errno_entry)) 18937c478bd9Sstevel@tonic-gate int 18947c478bd9Sstevel@tonic-gate usb_rval2errno(int rval) 18957c478bd9Sstevel@tonic-gate { 18967c478bd9Sstevel@tonic-gate int i; 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate for (i = 0; i < USB_RVAL2ERRNO_TABLE_SIZE; i++) { 18997c478bd9Sstevel@tonic-gate if (usb_rval2errno_table[i].rval == rval) { 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate return (usb_rval2errno_table[i].Errno); 19027c478bd9Sstevel@tonic-gate } 19037c478bd9Sstevel@tonic-gate } 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate return (EIO); 19067c478bd9Sstevel@tonic-gate } 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate /* 19107c478bd9Sstevel@tonic-gate * serialization 19117c478bd9Sstevel@tonic-gate */ 19127c478bd9Sstevel@tonic-gate usb_serialization_t 19137c478bd9Sstevel@tonic-gate usb_init_serialization( 19147c478bd9Sstevel@tonic-gate dev_info_t *dip, 19157c478bd9Sstevel@tonic-gate uint_t flag) 19167c478bd9Sstevel@tonic-gate { 19177c478bd9Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp = kmem_zalloc( 1918112116d8Sfb sizeof (usba_serialization_impl_t), KM_SLEEP); 19197c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 19207c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t cookie = NULL; 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate if (dip) { 19237c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 19247c478bd9Sstevel@tonic-gate cookie = usba_hcdi_get_hcdi( 19257c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip)->hcdi_iblock_cookie; 19267c478bd9Sstevel@tonic-gate } 19277c478bd9Sstevel@tonic-gate impl_tokenp->s_dip = dip; 19287c478bd9Sstevel@tonic-gate impl_tokenp->s_flag = flag; 19297c478bd9Sstevel@tonic-gate mutex_init(&impl_tokenp->s_mutex, NULL, MUTEX_DRIVER, cookie); 19307c478bd9Sstevel@tonic-gate cv_init(&impl_tokenp->s_cv, NULL, CV_DRIVER, NULL); 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate return ((usb_serialization_t)impl_tokenp); 19337c478bd9Sstevel@tonic-gate } 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate void 19377c478bd9Sstevel@tonic-gate usb_fini_serialization( 19387c478bd9Sstevel@tonic-gate usb_serialization_t tokenp) 19397c478bd9Sstevel@tonic-gate { 19407c478bd9Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp; 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate if (tokenp) { 19437c478bd9Sstevel@tonic-gate impl_tokenp = (usba_serialization_impl_t *)tokenp; 19447c478bd9Sstevel@tonic-gate ASSERT(impl_tokenp->s_count == 0); 19457c478bd9Sstevel@tonic-gate cv_destroy(&impl_tokenp->s_cv); 19467c478bd9Sstevel@tonic-gate mutex_destroy(&impl_tokenp->s_mutex); 19477c478bd9Sstevel@tonic-gate kmem_free(impl_tokenp, sizeof (usba_serialization_impl_t)); 19487c478bd9Sstevel@tonic-gate } 19497c478bd9Sstevel@tonic-gate } 19507c478bd9Sstevel@tonic-gate 19517c478bd9Sstevel@tonic-gate 19527c478bd9Sstevel@tonic-gate /* 19537c478bd9Sstevel@tonic-gate * usb_serialize_access() permits single threaded access. 19547c478bd9Sstevel@tonic-gate * 19557c478bd9Sstevel@tonic-gate * If tokenp is initialized with USB_INIT_SER_CHECK_SAME_THREAD, 19567c478bd9Sstevel@tonic-gate * it is reentrant with respect to thread. The thread must 19577c478bd9Sstevel@tonic-gate * hold and release the same number of times. 19587c478bd9Sstevel@tonic-gate * 19597c478bd9Sstevel@tonic-gate * If tokenp is initialized without USB_INIT_SER_CHECK_SAME_THREAD, 19607c478bd9Sstevel@tonic-gate * it is not reentrant by the same thread. It is something like 19617c478bd9Sstevel@tonic-gate * a semaphore. 19627c478bd9Sstevel@tonic-gate */ 19637c478bd9Sstevel@tonic-gate int 19647c478bd9Sstevel@tonic-gate usb_serialize_access( 19657c478bd9Sstevel@tonic-gate usb_serialization_t tokenp, uint_t how_to_wait, uint_t delta_timeout) 19667c478bd9Sstevel@tonic-gate { 19677c478bd9Sstevel@tonic-gate int rval = 1; /* Must be initialized > 0 */ 19687c478bd9Sstevel@tonic-gate clock_t abs_timeout; 19697c478bd9Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp; 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate impl_tokenp = (usba_serialization_impl_t *)tokenp; 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate /* 19747c478bd9Sstevel@tonic-gate * Convert delta timeout in ms to absolute timeout in ticks, if used. 19757c478bd9Sstevel@tonic-gate */ 19767c478bd9Sstevel@tonic-gate if ((how_to_wait == USB_TIMEDWAIT) || 19777c478bd9Sstevel@tonic-gate (how_to_wait == USB_TIMEDWAIT_SIG)) { 19787c478bd9Sstevel@tonic-gate /* Convert timeout arg (in ms) to hz */ 19797c478bd9Sstevel@tonic-gate abs_timeout = ddi_get_lbolt() + 19807c478bd9Sstevel@tonic-gate drv_usectohz(delta_timeout * 1000); 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate /* Get mutex after calc abs time, to count time waiting for mutex. */ 19847c478bd9Sstevel@tonic-gate mutex_enter(&impl_tokenp->s_mutex); 19857c478bd9Sstevel@tonic-gate 19867c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 19877c478bd9Sstevel@tonic-gate "usb_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p, " 19887c478bd9Sstevel@tonic-gate "flg=0x%x, abs_tmo=0x%lx", 1989112116d8Sfb (void *)impl_tokenp, (void *)impl_tokenp->s_dip, 1990112116d8Sfb impl_tokenp->s_count, (void *)impl_tokenp->s_thread, 1991112116d8Sfb how_to_wait, abs_timeout); 19927c478bd9Sstevel@tonic-gate 19937c478bd9Sstevel@tonic-gate if ((impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0 || 19947c478bd9Sstevel@tonic-gate impl_tokenp->s_thread != curthread) { 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate /* 19977c478bd9Sstevel@tonic-gate * There are three ways to break out of the loop: 19987c478bd9Sstevel@tonic-gate * 1) Condition met (s_count == 0) - higher prio test 19997c478bd9Sstevel@tonic-gate * 2) kill(2) signal received (rval == 0) 20007c478bd9Sstevel@tonic-gate * 3) timeout occurred (rval == -1) 20017c478bd9Sstevel@tonic-gate * If condition met, whether or not signal or timeout occurred 20027c478bd9Sstevel@tonic-gate * take access. If condition not met, check other exit means. 20037c478bd9Sstevel@tonic-gate */ 20047c478bd9Sstevel@tonic-gate while (impl_tokenp->s_count != 0) { 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate /* cv_timedwait* returns -1 on timeout. */ 20077c478bd9Sstevel@tonic-gate /* cv_wait*_sig returns 0 on (kill(2)) signal. */ 20087c478bd9Sstevel@tonic-gate if (rval <= 0) { 20097c478bd9Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex); 20107c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, 20117c478bd9Sstevel@tonic-gate usbai_log_handle, 20127c478bd9Sstevel@tonic-gate "usb_serialize_access: " 2013112116d8Sfb "tok=0x%p exit due to %s", 2014112116d8Sfb (void *)impl_tokenp, 20157c478bd9Sstevel@tonic-gate ((rval == 0) ? "signal" : "timeout")); 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate return (rval); 20187c478bd9Sstevel@tonic-gate } 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate switch (how_to_wait) { 20217c478bd9Sstevel@tonic-gate default: 20227c478bd9Sstevel@tonic-gate how_to_wait = USB_WAIT; 20237c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 20247c478bd9Sstevel@tonic-gate case USB_WAIT: 20257c478bd9Sstevel@tonic-gate cv_wait(&impl_tokenp->s_cv, 2026112116d8Sfb &impl_tokenp->s_mutex); 20277c478bd9Sstevel@tonic-gate break; 20287c478bd9Sstevel@tonic-gate case USB_WAIT_SIG: 20297c478bd9Sstevel@tonic-gate rval = cv_wait_sig(&impl_tokenp->s_cv, 2030112116d8Sfb &impl_tokenp->s_mutex); 20317c478bd9Sstevel@tonic-gate break; 20327c478bd9Sstevel@tonic-gate case USB_TIMEDWAIT: 20337c478bd9Sstevel@tonic-gate rval = cv_timedwait(&impl_tokenp->s_cv, 2034112116d8Sfb &impl_tokenp->s_mutex, abs_timeout); 20357c478bd9Sstevel@tonic-gate break; 20367c478bd9Sstevel@tonic-gate case USB_TIMEDWAIT_SIG: 20377c478bd9Sstevel@tonic-gate rval = cv_timedwait_sig(&impl_tokenp->s_cv, 2038112116d8Sfb &impl_tokenp->s_mutex, abs_timeout); 20397c478bd9Sstevel@tonic-gate break; 20407c478bd9Sstevel@tonic-gate } 20417c478bd9Sstevel@tonic-gate } 20427c478bd9Sstevel@tonic-gate 20437c478bd9Sstevel@tonic-gate impl_tokenp->s_thread = curthread; 20447c478bd9Sstevel@tonic-gate } 20457c478bd9Sstevel@tonic-gate impl_tokenp->s_count++; 20467c478bd9Sstevel@tonic-gate 20477c478bd9Sstevel@tonic-gate ASSERT(!(impl_tokenp->s_count > 1 && 20487c478bd9Sstevel@tonic-gate (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0)); 20497c478bd9Sstevel@tonic-gate 20507c478bd9Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex); 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 2053112116d8Sfb "usb_serialize_access exit: tok=0x%p thr=0x%p", (void *)impl_tokenp, 2054112116d8Sfb (void *)curthread); 20557c478bd9Sstevel@tonic-gate 20567c478bd9Sstevel@tonic-gate return (1); 20577c478bd9Sstevel@tonic-gate } 20587c478bd9Sstevel@tonic-gate 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20617c478bd9Sstevel@tonic-gate int 20627c478bd9Sstevel@tonic-gate usb_try_serialize_access( 20637c478bd9Sstevel@tonic-gate usb_serialization_t tokenp, uint_t flag) 20647c478bd9Sstevel@tonic-gate { 20657c478bd9Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp = 2066112116d8Sfb (usba_serialization_impl_t *)tokenp; 20677c478bd9Sstevel@tonic-gate mutex_enter(&impl_tokenp->s_mutex); 20687c478bd9Sstevel@tonic-gate 20697c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 20707c478bd9Sstevel@tonic-gate "usb_try_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p", 2071112116d8Sfb (void *)impl_tokenp, (void *)impl_tokenp->s_dip, 2072112116d8Sfb impl_tokenp->s_count, (void *)curthread); 20737c478bd9Sstevel@tonic-gate 20747c478bd9Sstevel@tonic-gate /* 20757c478bd9Sstevel@tonic-gate * If lock is not taken (s_count is 0), take it. 20767c478bd9Sstevel@tonic-gate * If lock is already taken, the thread is owner and lock 20777c478bd9Sstevel@tonic-gate * is reentrant, take it. 20787c478bd9Sstevel@tonic-gate * Otherwise, fail the access. 20797c478bd9Sstevel@tonic-gate */ 20807c478bd9Sstevel@tonic-gate if (!impl_tokenp->s_count || ((impl_tokenp->s_thread == curthread) && 20817c478bd9Sstevel@tonic-gate (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD))) { 20827c478bd9Sstevel@tonic-gate impl_tokenp->s_thread = curthread; 20837c478bd9Sstevel@tonic-gate impl_tokenp->s_count++; 20847c478bd9Sstevel@tonic-gate 20857c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 2086112116d8Sfb "usb_try_serialize_access success: tok=0x%p", 2087112116d8Sfb (void *)impl_tokenp); 20887c478bd9Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex); 20897c478bd9Sstevel@tonic-gate 20907c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 20917c478bd9Sstevel@tonic-gate } 20927c478bd9Sstevel@tonic-gate 20937c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 20947c478bd9Sstevel@tonic-gate "usb_try_serialize_access failed: " 20957c478bd9Sstevel@tonic-gate "tok=0x%p dip=0x%p cnt=%d thr=0x%p", 2096112116d8Sfb (void *)impl_tokenp, (void *)impl_tokenp->s_dip, 2097112116d8Sfb impl_tokenp->s_count, (void *)impl_tokenp->s_thread); 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex); 21007c478bd9Sstevel@tonic-gate 21017c478bd9Sstevel@tonic-gate return (USB_FAILURE); 21027c478bd9Sstevel@tonic-gate } 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate 21057c478bd9Sstevel@tonic-gate void 21067c478bd9Sstevel@tonic-gate usb_release_access( 21077c478bd9Sstevel@tonic-gate usb_serialization_t tokenp) 21087c478bd9Sstevel@tonic-gate { 21097c478bd9Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp = 2110112116d8Sfb (usba_serialization_impl_t *)tokenp; 21117c478bd9Sstevel@tonic-gate mutex_enter(&impl_tokenp->s_mutex); 21127c478bd9Sstevel@tonic-gate 21137c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 21147c478bd9Sstevel@tonic-gate "usb_release_access: tok=0x%p dip=0x%p count=%d thr=0x%p", 2115112116d8Sfb (void *)impl_tokenp, (void *)impl_tokenp->s_dip, 2116112116d8Sfb impl_tokenp->s_count, (void *)curthread); 21177c478bd9Sstevel@tonic-gate 21187c478bd9Sstevel@tonic-gate ASSERT(impl_tokenp->s_count > 0); 21197c478bd9Sstevel@tonic-gate 21207c478bd9Sstevel@tonic-gate if (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) { 21217c478bd9Sstevel@tonic-gate if (impl_tokenp->s_thread != curthread) { 2122d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 21237c478bd9Sstevel@tonic-gate "usb_release_access: release from wrong thread"); 21247c478bd9Sstevel@tonic-gate } 21257c478bd9Sstevel@tonic-gate ASSERT(impl_tokenp->s_thread == curthread); 21267c478bd9Sstevel@tonic-gate } 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate if (--impl_tokenp->s_count == 0) { 21297c478bd9Sstevel@tonic-gate impl_tokenp->s_thread = NULL; 21307c478bd9Sstevel@tonic-gate cv_broadcast(&impl_tokenp->s_cv); 21317c478bd9Sstevel@tonic-gate } 21327c478bd9Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex); 21337c478bd9Sstevel@tonic-gate } 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate 21367c478bd9Sstevel@tonic-gate /* 21377c478bd9Sstevel@tonic-gate * usb_fail_checkpoint: 21387c478bd9Sstevel@tonic-gate * fail checkpoint as driver/device could not be quiesced 21397c478bd9Sstevel@tonic-gate */ 21407c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 21417c478bd9Sstevel@tonic-gate void 21427c478bd9Sstevel@tonic-gate usb_fail_checkpoint(dev_info_t *dip, usb_flags_t flags) 21437c478bd9Sstevel@tonic-gate { 21447c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 21457c478bd9Sstevel@tonic-gate 21467c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 21477c478bd9Sstevel@tonic-gate "usb_fail_checkpoint: %s%d", ddi_driver_name(dip), 21487c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 21497c478bd9Sstevel@tonic-gate 21507c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 21517c478bd9Sstevel@tonic-gate usba_device->usb_no_cpr++; 21527c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 21537c478bd9Sstevel@tonic-gate } 21547c478bd9Sstevel@tonic-gate 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk)) 21577c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab)) 21587c478bd9Sstevel@tonic-gate /* 21597c478bd9Sstevel@tonic-gate * usba_mk_mctl: 21607c478bd9Sstevel@tonic-gate * create a USB style M_CTL message, given an iocblk and a buffer 21617c478bd9Sstevel@tonic-gate * returns mblk_t * on success, NULL on failure 21627c478bd9Sstevel@tonic-gate */ 21637c478bd9Sstevel@tonic-gate mblk_t * 21647c478bd9Sstevel@tonic-gate usba_mk_mctl(struct iocblk mctlmsg, void *buf, size_t len) 21657c478bd9Sstevel@tonic-gate { 21667c478bd9Sstevel@tonic-gate mblk_t *bp1, *bp2; 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate if ((bp1 = allocb(sizeof (struct iocblk), BPRI_HI)) != NULL) { 2169*d29f5a71Szhigang lu - Sun Microsystems - Beijing China /* LINTED E_BAD_PTR_CAST_ALIGN */ 21707c478bd9Sstevel@tonic-gate *((struct iocblk *)bp1->b_datap->db_base) = mctlmsg; 21717c478bd9Sstevel@tonic-gate bp1->b_datap->db_type = M_CTL; 21727c478bd9Sstevel@tonic-gate bp1->b_wptr += sizeof (struct iocblk); 21737c478bd9Sstevel@tonic-gate if (buf != NULL) { 21747c478bd9Sstevel@tonic-gate if ((bp2 = allocb(len, BPRI_HI)) != NULL) { 21757c478bd9Sstevel@tonic-gate bp1->b_cont = bp2; 21767c478bd9Sstevel@tonic-gate bcopy(buf, bp2->b_datap->db_base, len); 21777c478bd9Sstevel@tonic-gate bp2->b_wptr += len; 21787c478bd9Sstevel@tonic-gate } else { 21797c478bd9Sstevel@tonic-gate freemsg(bp1); 21807c478bd9Sstevel@tonic-gate bp1 = NULL; 21817c478bd9Sstevel@tonic-gate } 21827c478bd9Sstevel@tonic-gate } 21837c478bd9Sstevel@tonic-gate } 21847c478bd9Sstevel@tonic-gate 21857c478bd9Sstevel@tonic-gate return (bp1); 21867c478bd9Sstevel@tonic-gate } 21877c478bd9Sstevel@tonic-gate 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate #ifdef ALLOCB_TEST 21907c478bd9Sstevel@tonic-gate #undef allocb 21917c478bd9Sstevel@tonic-gate mblk_t * 21927c478bd9Sstevel@tonic-gate usba_test_allocb(size_t size, uint_t pri) 21937c478bd9Sstevel@tonic-gate { 21947c478bd9Sstevel@tonic-gate if (ddi_get_lbolt() & 0x1) { 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate return (NULL); 21977c478bd9Sstevel@tonic-gate } else { 21987c478bd9Sstevel@tonic-gate 21997c478bd9Sstevel@tonic-gate return (allocb(size, pri)); 22007c478bd9Sstevel@tonic-gate } 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate #endif 2203d73ae94eSgc 2204d73ae94eSgc 2205d73ae94eSgc /* 2206d73ae94eSgc * usb common power management for usb_mid, usb_ia and maybe other simple 2207d73ae94eSgc * drivers. 2208d73ae94eSgc */ 2209d73ae94eSgc 2210d73ae94eSgc /* 2211d73ae94eSgc * functions to handle power transition for OS levels 0 -> 3 2212d73ae94eSgc */ 2213d73ae94eSgc static int 2214036aa261Sgc usb_common_pwrlvl0(dev_info_t *dip, uint8_t *pm, int *dev_state) 2215d73ae94eSgc { 2216d73ae94eSgc int rval; 2217d73ae94eSgc 2218d73ae94eSgc switch (*dev_state) { 2219d73ae94eSgc case USB_DEV_ONLINE: 2220d73ae94eSgc /* Issue USB D3 command to the device here */ 2221d73ae94eSgc rval = usb_set_device_pwrlvl3(dip); 2222d73ae94eSgc ASSERT(rval == USB_SUCCESS); 2223d73ae94eSgc 2224d73ae94eSgc *dev_state = USB_DEV_PWRED_DOWN; 2225036aa261Sgc *pm = USB_DEV_OS_PWR_OFF; 2226d73ae94eSgc /* FALLTHRU */ 2227d73ae94eSgc case USB_DEV_DISCONNECTED: 2228d73ae94eSgc case USB_DEV_SUSPENDED: 2229d73ae94eSgc /* allow a disconnected/cpr'ed device to go to low pwr */ 2230d73ae94eSgc 2231d73ae94eSgc return (USB_SUCCESS); 2232d73ae94eSgc case USB_DEV_PWRED_DOWN: 2233d73ae94eSgc default: 2234d73ae94eSgc return (USB_FAILURE); 2235d73ae94eSgc } 2236d73ae94eSgc } 2237d73ae94eSgc 2238d73ae94eSgc 2239d73ae94eSgc /* ARGSUSED */ 2240d73ae94eSgc static int 2241036aa261Sgc usb_common_pwrlvl1(dev_info_t *dip, uint8_t *pm, int *dev_state) 2242d73ae94eSgc { 2243d73ae94eSgc int rval; 2244d73ae94eSgc 2245d73ae94eSgc /* Issue USB D2 command to the device here */ 2246d73ae94eSgc rval = usb_set_device_pwrlvl2(dip); 2247d73ae94eSgc ASSERT(rval == USB_SUCCESS); 2248d73ae94eSgc 2249d73ae94eSgc return (USB_FAILURE); 2250d73ae94eSgc } 2251d73ae94eSgc 2252d73ae94eSgc 2253d73ae94eSgc /* ARGSUSED */ 2254d73ae94eSgc static int 2255036aa261Sgc usb_common_pwrlvl2(dev_info_t *dip, uint8_t *pm, int *dev_state) 2256d73ae94eSgc { 2257d73ae94eSgc int rval; 2258d73ae94eSgc 2259d73ae94eSgc /* Issue USB D1 command to the device here */ 2260d73ae94eSgc rval = usb_set_device_pwrlvl1(dip); 2261d73ae94eSgc ASSERT(rval == USB_SUCCESS); 2262d73ae94eSgc 2263d73ae94eSgc return (USB_FAILURE); 2264d73ae94eSgc } 2265d73ae94eSgc 2266d73ae94eSgc 2267d73ae94eSgc static int 2268036aa261Sgc usb_common_pwrlvl3(dev_info_t *dip, uint8_t *pm, int *dev_state) 2269d73ae94eSgc { 2270d73ae94eSgc int rval; 2271d73ae94eSgc 2272d73ae94eSgc switch (*dev_state) { 2273d73ae94eSgc case USB_DEV_PWRED_DOWN: 2274d73ae94eSgc /* Issue USB D0 command to the device here */ 2275d73ae94eSgc rval = usb_set_device_pwrlvl0(dip); 2276d73ae94eSgc ASSERT(rval == USB_SUCCESS); 2277d73ae94eSgc 2278d73ae94eSgc *dev_state = USB_DEV_ONLINE; 2279036aa261Sgc *pm = USB_DEV_OS_FULL_PWR; 2280d73ae94eSgc 2281d73ae94eSgc /* FALLTHRU */ 2282d73ae94eSgc case USB_DEV_ONLINE: 2283d73ae94eSgc /* we are already in full power */ 2284d73ae94eSgc 2285d73ae94eSgc /* FALLTHRU */ 2286d73ae94eSgc case USB_DEV_DISCONNECTED: 2287d73ae94eSgc case USB_DEV_SUSPENDED: 2288d73ae94eSgc /* allow a disconnected/cpr'ed device to go to low power */ 2289d73ae94eSgc 2290d73ae94eSgc return (USB_SUCCESS); 2291d73ae94eSgc default: 2292d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle, 2293d73ae94eSgc "usb_common_pwrlvl3: Illegal state (%s)", 2294d73ae94eSgc usb_str_dev_state(*dev_state)); 2295d73ae94eSgc 2296d73ae94eSgc return (USB_FAILURE); 2297d73ae94eSgc } 2298d73ae94eSgc } 2299d73ae94eSgc 2300d73ae94eSgc /* power management */ 2301d73ae94eSgc int 2302036aa261Sgc usba_common_power(dev_info_t *dip, uint8_t *pm, int *dev_state, int level) 2303d73ae94eSgc { 2304d73ae94eSgc int rval = DDI_FAILURE; 2305d73ae94eSgc 2306d73ae94eSgc switch (level) { 2307d73ae94eSgc case USB_DEV_OS_PWR_OFF: 2308d73ae94eSgc rval = usb_common_pwrlvl0(dip, pm, dev_state); 2309d73ae94eSgc break; 2310d73ae94eSgc case USB_DEV_OS_PWR_1: 2311d73ae94eSgc rval = usb_common_pwrlvl1(dip, pm, dev_state); 2312d73ae94eSgc break; 2313d73ae94eSgc case USB_DEV_OS_PWR_2: 2314d73ae94eSgc rval = usb_common_pwrlvl2(dip, pm, dev_state); 2315d73ae94eSgc break; 2316d73ae94eSgc case USB_DEV_OS_FULL_PWR: 2317d73ae94eSgc rval = usb_common_pwrlvl3(dip, pm, dev_state); 2318d73ae94eSgc break; 2319d73ae94eSgc } 2320d73ae94eSgc 2321d73ae94eSgc return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 2322d73ae94eSgc } 2323d73ae94eSgc 2324d73ae94eSgc /* 2325d73ae94eSgc * register and unregister for events from our parent for usb_mid and usb_ia 2326d73ae94eSgc * and maybe other nexus driver. 2327d73ae94eSgc * 2328d73ae94eSgc * Note: The cookie fields in usba_device structure is not used. They are 2329d73ae94eSgc * used/shared by children. 2330d73ae94eSgc */ 2331d73ae94eSgc void 2332d73ae94eSgc usba_common_register_events(dev_info_t *dip, uint_t if_num, 2333d73ae94eSgc void (*event_cb)(dev_info_t *, ddi_eventcookie_t, void *, void *)) 2334d73ae94eSgc { 2335d73ae94eSgc int rval; 2336d73ae94eSgc usba_evdata_t *evdata; 2337d73ae94eSgc ddi_eventcookie_t cookie; 2338d73ae94eSgc 2339d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 2340d73ae94eSgc "usb_common_register_events:"); 2341d73ae94eSgc 2342d73ae94eSgc evdata = usba_get_evdata(dip); 2343d73ae94eSgc 2344d73ae94eSgc /* get event cookie, discard level and icookie for now */ 2345d73ae94eSgc rval = ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT, 2346112116d8Sfb &cookie); 2347d73ae94eSgc 2348d73ae94eSgc if (rval == DDI_SUCCESS) { 2349d73ae94eSgc rval = ddi_add_event_handler(dip, 2350d73ae94eSgc cookie, event_cb, NULL, &evdata->ev_rm_cb_id); 2351d73ae94eSgc 2352d73ae94eSgc if (rval != DDI_SUCCESS) { 2353d73ae94eSgc 2354d73ae94eSgc goto fail; 2355d73ae94eSgc } 2356d73ae94eSgc } 2357d73ae94eSgc rval = ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT, 2358112116d8Sfb &cookie); 2359d73ae94eSgc if (rval == DDI_SUCCESS) { 2360d73ae94eSgc rval = ddi_add_event_handler(dip, cookie, event_cb, 2361d73ae94eSgc NULL, &evdata->ev_ins_cb_id); 2362d73ae94eSgc 2363d73ae94eSgc if (rval != DDI_SUCCESS) { 2364d73ae94eSgc 2365d73ae94eSgc goto fail; 2366d73ae94eSgc } 2367d73ae94eSgc } 2368d73ae94eSgc rval = ddi_get_eventcookie(dip, USBA_PRE_SUSPEND_EVENT, &cookie); 2369d73ae94eSgc if (rval == DDI_SUCCESS) { 2370d73ae94eSgc rval = ddi_add_event_handler(dip, 2371d73ae94eSgc cookie, event_cb, NULL, &evdata->ev_suspend_cb_id); 2372d73ae94eSgc 2373d73ae94eSgc if (rval != DDI_SUCCESS) { 2374d73ae94eSgc 2375d73ae94eSgc goto fail; 2376d73ae94eSgc } 2377d73ae94eSgc } 2378d73ae94eSgc rval = ddi_get_eventcookie(dip, USBA_POST_RESUME_EVENT, &cookie); 2379d73ae94eSgc if (rval == DDI_SUCCESS) { 2380d73ae94eSgc rval = ddi_add_event_handler(dip, cookie, event_cb, NULL, 2381d73ae94eSgc &evdata->ev_resume_cb_id); 2382d73ae94eSgc 2383d73ae94eSgc if (rval != DDI_SUCCESS) { 2384d73ae94eSgc 2385d73ae94eSgc goto fail; 2386d73ae94eSgc } 2387d73ae94eSgc } 2388d73ae94eSgc 2389d73ae94eSgc return; 2390d73ae94eSgc 2391d73ae94eSgc 2392d73ae94eSgc fail: 2393d73ae94eSgc usba_common_unregister_events(dip, if_num); 2394d73ae94eSgc 2395d73ae94eSgc } 2396d73ae94eSgc 2397d73ae94eSgc void 2398d73ae94eSgc usba_common_unregister_events(dev_info_t *dip, uint_t if_num) 2399d73ae94eSgc { 2400d73ae94eSgc usba_evdata_t *evdata; 2401d73ae94eSgc usba_device_t *usba_device = usba_get_usba_device(dip); 2402d73ae94eSgc int i; 2403d73ae94eSgc 2404d73ae94eSgc evdata = usba_get_evdata(dip); 2405d73ae94eSgc 2406d73ae94eSgc if (evdata->ev_rm_cb_id != NULL) { 2407d73ae94eSgc (void) ddi_remove_event_handler(evdata->ev_rm_cb_id); 2408d73ae94eSgc evdata->ev_rm_cb_id = NULL; 2409d73ae94eSgc } 2410d73ae94eSgc 2411d73ae94eSgc if (evdata->ev_ins_cb_id != NULL) { 2412d73ae94eSgc (void) ddi_remove_event_handler(evdata->ev_ins_cb_id); 2413d73ae94eSgc evdata->ev_ins_cb_id = NULL; 2414d73ae94eSgc } 2415d73ae94eSgc 2416d73ae94eSgc if (evdata->ev_suspend_cb_id != NULL) { 2417d73ae94eSgc (void) ddi_remove_event_handler(evdata->ev_suspend_cb_id); 2418d73ae94eSgc evdata->ev_suspend_cb_id = NULL; 2419d73ae94eSgc } 2420d73ae94eSgc 2421d73ae94eSgc if (evdata->ev_resume_cb_id != NULL) { 2422d73ae94eSgc (void) ddi_remove_event_handler(evdata->ev_resume_cb_id); 2423d73ae94eSgc evdata->ev_resume_cb_id = NULL; 2424d73ae94eSgc } 2425d73ae94eSgc 2426d73ae94eSgc /* clear event data for children, required for cfgmadm unconfigure */ 2427036aa261Sgc mutex_enter(&usba_device->usb_mutex); 2428d73ae94eSgc if (usb_owns_device(dip)) { 2429d73ae94eSgc usba_free_evdata(usba_device->usb_evdata); 2430d73ae94eSgc usba_device->usb_evdata = NULL; 2431d73ae94eSgc usba_device->rm_cookie = NULL; 2432d73ae94eSgc usba_device->ins_cookie = NULL; 2433d73ae94eSgc usba_device->suspend_cookie = NULL; 2434d73ae94eSgc usba_device->resume_cookie = NULL; 2435d73ae94eSgc } else { 2436d73ae94eSgc for (i = 0; i < if_num; i++) { 2437d73ae94eSgc usba_device->usb_client_flags[usba_get_ifno(dip) + i] 2438112116d8Sfb &= ~USBA_CLIENT_FLAG_EV_CBS; 2439d73ae94eSgc } 2440d73ae94eSgc } 2441036aa261Sgc mutex_exit(&usba_device->usb_mutex); 2442d73ae94eSgc } 2443