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