10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
53341Sgc161489 * Common Development and Distribution License (the "License").
63341Sgc161489 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*8945SGuoqing.Zhu@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * USBA: Solaris USB Architecture support
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * Utility functions
310Sstevel@tonic-gate */
320Sstevel@tonic-gate #define USBA_FRAMEWORK
330Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
340Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
357492SZhigang.Lu@Sun.COM #include <sys/strsun.h>
360Sstevel@tonic-gate
373341Sgc161489 extern void usba_free_evdata(usba_evdata_t *);
383341Sgc161489
390Sstevel@tonic-gate static mblk_t *usba_get_cfg_cloud(dev_info_t *, usb_pipe_handle_t, int);
400Sstevel@tonic-gate
410Sstevel@tonic-gate /* local functions */
420Sstevel@tonic-gate static int usba_sync_set_cfg(dev_info_t *, usba_ph_impl_t *,
430Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t);
440Sstevel@tonic-gate static int usba_sync_set_alt_if(dev_info_t *, usba_ph_impl_t *,
450Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t);
460Sstevel@tonic-gate static int usba_sync_clear_feature(dev_info_t *, usba_ph_impl_t *,
470Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t);
480Sstevel@tonic-gate
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate * Wrapper functions returning parsed standard descriptors without
510Sstevel@tonic-gate * getting the config cloud first but by just providing the dip.
520Sstevel@tonic-gate *
530Sstevel@tonic-gate * The client can easily retrieve the device and config descriptor from
540Sstevel@tonic-gate * the usb registration and no separate functions are provided
550Sstevel@tonic-gate *
560Sstevel@tonic-gate * These functions return failure if the full descriptor can not be
570Sstevel@tonic-gate * retrieved. These functions will not access the device.
580Sstevel@tonic-gate * The caller must allocate the buffer.
590Sstevel@tonic-gate */
600Sstevel@tonic-gate
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate * usb_get_if_descr:
630Sstevel@tonic-gate * Function to get the cooked interface descriptor
640Sstevel@tonic-gate * This function will not access the device.
650Sstevel@tonic-gate *
660Sstevel@tonic-gate * Arguments:
670Sstevel@tonic-gate * dip - pointer to devinfo of the client
680Sstevel@tonic-gate * if_index - interface index
690Sstevel@tonic-gate * alt_setting - alt interface setting
700Sstevel@tonic-gate * descr - pointer to user allocated interface descr
710Sstevel@tonic-gate *
720Sstevel@tonic-gate * Return Values:
730Sstevel@tonic-gate * USB_SUCCESS - descriptor is valid
740Sstevel@tonic-gate * USB_FAILURE - full descriptor could not be retrieved
750Sstevel@tonic-gate * USB_* - refer to usbai.h
760Sstevel@tonic-gate */
770Sstevel@tonic-gate int
usb_get_if_descr(dev_info_t * dip,uint_t if_index,uint_t alt_setting,usb_if_descr_t * descr)780Sstevel@tonic-gate usb_get_if_descr(dev_info_t *dip,
790Sstevel@tonic-gate uint_t if_index,
800Sstevel@tonic-gate uint_t alt_setting,
810Sstevel@tonic-gate usb_if_descr_t *descr)
820Sstevel@tonic-gate {
830Sstevel@tonic-gate uchar_t *usb_cfg; /* buf for config descriptor */
840Sstevel@tonic-gate size_t size, cfg_length;
850Sstevel@tonic-gate
860Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
870Sstevel@tonic-gate "usb_get_if_descr: %s, index=0x%x, alt#=0x%x",
880Sstevel@tonic-gate ddi_node_name(dip), if_index, alt_setting);
890Sstevel@tonic-gate
900Sstevel@tonic-gate if ((dip == NULL) || (descr == NULL)) {
910Sstevel@tonic-gate
920Sstevel@tonic-gate return (USB_INVALID_ARGS);
930Sstevel@tonic-gate }
940Sstevel@tonic-gate
950Sstevel@tonic-gate usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
960Sstevel@tonic-gate size = usb_parse_if_descr(usb_cfg, cfg_length,
970Sstevel@tonic-gate if_index, /* interface index */
980Sstevel@tonic-gate alt_setting, /* alt interface index */
990Sstevel@tonic-gate descr,
1000Sstevel@tonic-gate USB_IF_DESCR_SIZE);
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate if (size != USB_IF_DESCR_SIZE) {
1030Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1040Sstevel@tonic-gate "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
1050Sstevel@tonic-gate size, USB_IF_DESCR_SIZE);
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate return (USB_FAILURE);
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate return (USB_SUCCESS);
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate /*
1150Sstevel@tonic-gate * usb_get_ep_descr:
1160Sstevel@tonic-gate * Function to get the cooked endpoint descriptor
1170Sstevel@tonic-gate * This function will not access the device.
1180Sstevel@tonic-gate *
1190Sstevel@tonic-gate * Arguments:
1200Sstevel@tonic-gate * dip - pointer to devinfo of the client
1210Sstevel@tonic-gate * if_index - interface index
1220Sstevel@tonic-gate * alt_setting - alternate interface setting
1230Sstevel@tonic-gate * endpoint_index - endpoint index
1240Sstevel@tonic-gate * descr - pointer to user allocated interface descr
1250Sstevel@tonic-gate *
1260Sstevel@tonic-gate * Return Values:
1270Sstevel@tonic-gate * USB_SUCCESS - descriptor is valid
1280Sstevel@tonic-gate * USB_FAILURE - full descriptor could not be retrieved
1290Sstevel@tonic-gate * USB_* - refer to usbai.h
1300Sstevel@tonic-gate */
1310Sstevel@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)1320Sstevel@tonic-gate usb_get_ep_descr(dev_info_t *dip,
1330Sstevel@tonic-gate uint_t if_index,
1340Sstevel@tonic-gate uint_t alt_setting,
1350Sstevel@tonic-gate uint_t endpoint_index,
1360Sstevel@tonic-gate usb_ep_descr_t *descr)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate uchar_t *usb_cfg; /* buf for config descriptor */
1390Sstevel@tonic-gate size_t size, cfg_length;
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1420Sstevel@tonic-gate "usb_get_ep_descr: %s, index=0x%x, alt#=0x%x",
1430Sstevel@tonic-gate ddi_node_name(dip), if_index, alt_setting);
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate if ((dip == NULL) || (descr == NULL)) {
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate return (USB_INVALID_ARGS);
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
1510Sstevel@tonic-gate size = usb_parse_ep_descr(usb_cfg, cfg_length,
1526898Sfb209375 if_index, /* interface index */
1536898Sfb209375 alt_setting, /* alt interface index */
1546898Sfb209375 endpoint_index, /* ep index */
1556898Sfb209375 descr, USB_EP_DESCR_SIZE);
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate if (size != USB_EP_DESCR_SIZE) {
1580Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1590Sstevel@tonic-gate "parsing endpoint: size (%lu) != USB_EP_DESCR_SIZE (%d)",
1600Sstevel@tonic-gate size, USB_EP_DESCR_SIZE);
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate return (USB_FAILURE);
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate return (USB_SUCCESS);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate /*
1700Sstevel@tonic-gate * usb_lookup_ep_data:
1710Sstevel@tonic-gate * usb_get_ep_data (deprecated):
1720Sstevel@tonic-gate * Function to get specific endpoint descriptor data
1730Sstevel@tonic-gate * This function will not access the device.
1740Sstevel@tonic-gate *
1750Sstevel@tonic-gate * Arguments:
1760Sstevel@tonic-gate * dip - pointer to dev info
1770Sstevel@tonic-gate * usb_client_dev_data_t - pointer to registration data
1780Sstevel@tonic-gate * interface - requested interface
1790Sstevel@tonic-gate * alternate - requested alternate
1800Sstevel@tonic-gate * skip - how many to skip
1810Sstevel@tonic-gate * type - endpoint type
1820Sstevel@tonic-gate * direction - endpoint direction or USB_DIR_DONT_CARE
1830Sstevel@tonic-gate *
1840Sstevel@tonic-gate * Return Values:
1850Sstevel@tonic-gate * NULL or an endpoint descriptor pointer
1860Sstevel@tonic-gate */
1870Sstevel@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)1880Sstevel@tonic-gate usb_lookup_ep_data(dev_info_t *dip,
1890Sstevel@tonic-gate usb_client_dev_data_t *dev_datap,
1900Sstevel@tonic-gate uint_t interface,
1910Sstevel@tonic-gate uint_t alternate,
1920Sstevel@tonic-gate uint_t skip,
1930Sstevel@tonic-gate uint_t type,
1940Sstevel@tonic-gate uint_t dir)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate usb_alt_if_data_t *altif_data;
1970Sstevel@tonic-gate int i;
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2000Sstevel@tonic-gate "usb_lookup_ep_data: "
2010Sstevel@tonic-gate "if=%d alt=%d skip=%d type=%d dir=%d",
2020Sstevel@tonic-gate interface, alternate, skip, type, dir);
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate if ((dip == NULL) || (dev_datap == NULL)) {
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate return (NULL);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate altif_data = &dev_datap->dev_curr_cfg->
2106898Sfb209375 cfg_if[interface].if_alt[alternate];
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2136898Sfb209375 "altif=0x%p n_ep=%d", (void *)altif_data, altif_data->altif_n_ep);
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate for (i = 0; i < altif_data->altif_n_ep; i++) {
2160Sstevel@tonic-gate usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr;
2170Sstevel@tonic-gate uint8_t ept_type = ept->bmAttributes & USB_EP_ATTR_MASK;
2180Sstevel@tonic-gate uint8_t ept_dir = ept->bEndpointAddress & USB_EP_DIR_MASK;
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate if (ept->bLength == 0) {
2210Sstevel@tonic-gate continue;
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate if ((ept_type == type) &&
2240Sstevel@tonic-gate ((type == USB_EP_ATTR_CONTROL) || (dir == ept_dir))) {
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate if (skip-- == 0) {
2270Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA,
2280Sstevel@tonic-gate usbai_log_handle,
2290Sstevel@tonic-gate "usb_get_ep_data: data=0x%p",
2306898Sfb209375 (void *)&altif_data->altif_ep[i]);
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate return (&altif_data->altif_ep[i]);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2370Sstevel@tonic-gate "usb_get_ep_data: returning NULL");
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate return (NULL);
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate /*ARGSUSED*/
2440Sstevel@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)2450Sstevel@tonic-gate usb_get_ep_data(dev_info_t *dip,
2460Sstevel@tonic-gate usb_client_dev_data_t *dev_datap,
2470Sstevel@tonic-gate uint_t interface,
2480Sstevel@tonic-gate uint_t alternate,
2490Sstevel@tonic-gate uint_t type,
2500Sstevel@tonic-gate uint_t dir)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate return (usb_lookup_ep_data(dip, dev_datap, interface,
2530Sstevel@tonic-gate alternate, 0, type, dir));
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate /*
2580Sstevel@tonic-gate * usb_get_string_descr:
2590Sstevel@tonic-gate * Function to read the string descriptor
2600Sstevel@tonic-gate * This function will access the device and block.
2610Sstevel@tonic-gate *
2620Sstevel@tonic-gate * Arguments:
2630Sstevel@tonic-gate * dip - pointer to devinfo of the client
2640Sstevel@tonic-gate * langid - LANGID to read different LOCALEs
2650Sstevel@tonic-gate * index - index to the string
2660Sstevel@tonic-gate * buf - user provided buffer for string descriptor
2670Sstevel@tonic-gate * buflen - user provided length of the buffer
2680Sstevel@tonic-gate *
2690Sstevel@tonic-gate * Return Values:
2700Sstevel@tonic-gate * USB_SUCCESS - descriptor is valid
2710Sstevel@tonic-gate * USB_FAILURE - full descriptor could not be retrieved
2720Sstevel@tonic-gate * USB_* - refer to usbai.h
2730Sstevel@tonic-gate */
2740Sstevel@tonic-gate int
usb_get_string_descr(dev_info_t * dip,uint16_t langid,uint8_t index,char * buf,size_t buflen)2750Sstevel@tonic-gate usb_get_string_descr(dev_info_t *dip,
2760Sstevel@tonic-gate uint16_t langid,
2770Sstevel@tonic-gate uint8_t index,
2780Sstevel@tonic-gate char *buf,
2790Sstevel@tonic-gate size_t buflen)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate mblk_t *data = NULL;
2820Sstevel@tonic-gate uint16_t length;
2830Sstevel@tonic-gate int rval;
2840Sstevel@tonic-gate usb_cr_t completion_reason;
2850Sstevel@tonic-gate size_t len;
2860Sstevel@tonic-gate usb_cb_flags_t cb_flags;
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2890Sstevel@tonic-gate "usb_get_string_descr: %s, langid=0x%x index=0x%x",
2900Sstevel@tonic-gate ddi_node_name(dip), langid, index);
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate if ((dip == NULL) || (buf == NULL) || (buflen == 0) || (index == 0)) {
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate return (USB_INVALID_ARGS);
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate /*
2980Sstevel@tonic-gate * determine the length of the descriptor
2990Sstevel@tonic-gate */
3000Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip,
3016898Sfb209375 usba_get_dflt_pipe_handle(dip),
3026898Sfb209375 USB_DEV_REQ_DEV_TO_HOST,
3036898Sfb209375 USB_REQ_GET_DESCR,
3046898Sfb209375 USB_DESCR_TYPE_STRING << 8 | index & 0xff,
3056898Sfb209375 langid,
3066898Sfb209375 4,
3076898Sfb209375 &data, USB_ATTRS_SHORT_XFER_OK,
3086898Sfb209375 &completion_reason,
3096898Sfb209375 &cb_flags, USB_FLAGS_SLEEP);
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate if (rval != USB_SUCCESS) {
3120Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
3130Sstevel@tonic-gate "rval=%d cr=%d", rval, completion_reason);
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate goto done;
3160Sstevel@tonic-gate }
3177492SZhigang.Lu@Sun.COM if (MBLKL(data) == 0) {
3180Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
3190Sstevel@tonic-gate "0 bytes received");
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate goto done;
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate ASSERT(data);
3250Sstevel@tonic-gate length = *(data->b_rptr);
3260Sstevel@tonic-gate freemsg(data);
3270Sstevel@tonic-gate data = NULL;
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
3300Sstevel@tonic-gate "rval=%d, cr=%d, length=%d", rval, completion_reason, length);
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate /*
3330Sstevel@tonic-gate * if length is zero the next control request may fail.
3340Sstevel@tonic-gate * the HCD may not support a zero length control request
3350Sstevel@tonic-gate * and return an mblk_t which is NULL along with rval
3360Sstevel@tonic-gate * being USB_SUCCESS and "cr" being USB_CR_OK
3370Sstevel@tonic-gate */
3380Sstevel@tonic-gate if (length < 2) {
3390Sstevel@tonic-gate rval = USB_FAILURE;
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate goto done;
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip,
3456898Sfb209375 usba_get_dflt_pipe_handle(dip),
3466898Sfb209375 USB_DEV_REQ_DEV_TO_HOST,
3476898Sfb209375 USB_REQ_GET_DESCR,
3486898Sfb209375 USB_DESCR_TYPE_STRING << 8 | index & 0xff,
3496898Sfb209375 langid,
3506898Sfb209375 length,
3516898Sfb209375 &data, USB_ATTRS_SHORT_XFER_OK,
3526898Sfb209375 &completion_reason,
3536898Sfb209375 &cb_flags, USB_FLAGS_SLEEP);
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
3560Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate if ((data == NULL) || (rval != USB_SUCCESS)) {
3590Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
3600Sstevel@tonic-gate "failed to get string descriptor (rval=%d cr=%d)",
3610Sstevel@tonic-gate rval, completion_reason);
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate goto done;
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate
3667492SZhigang.Lu@Sun.COM if ((length = MBLKL(data)) != 0) {
3670Sstevel@tonic-gate len = usba_ascii_string_descr(data->b_rptr, length, buf,
3686898Sfb209375 buflen);
3690Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA,
3700Sstevel@tonic-gate usbai_log_handle, "buf=%s buflen=%lu", buf, len);
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate ASSERT(len <= buflen);
3730Sstevel@tonic-gate } else {
3740Sstevel@tonic-gate rval = USB_FAILURE;
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate done:
3770Sstevel@tonic-gate freemsg(data);
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate return (rval);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate /*
3840Sstevel@tonic-gate * usb_get_dev_descr:
3850Sstevel@tonic-gate * utility function to get device descriptor from usba_device
3860Sstevel@tonic-gate *
3870Sstevel@tonic-gate * Arguments:
3880Sstevel@tonic-gate * dip - pointer to devinfo of the client
3890Sstevel@tonic-gate *
3900Sstevel@tonic-gate * Return Values:
3910Sstevel@tonic-gate * usb_dev_descr - device descriptor or NULL
3920Sstevel@tonic-gate */
3930Sstevel@tonic-gate usb_dev_descr_t *
usb_get_dev_descr(dev_info_t * dip)3940Sstevel@tonic-gate usb_get_dev_descr(dev_info_t *dip)
3950Sstevel@tonic-gate {
3960Sstevel@tonic-gate usba_device_t *usba_device;
3970Sstevel@tonic-gate usb_dev_descr_t *usb_dev_descr = NULL;
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate if (dip) {
4000Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
4010Sstevel@tonic-gate "usb_get_dev_descr: %s", ddi_node_name(dip));
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate usba_device = usba_get_usba_device(dip);
4040Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
4050Sstevel@tonic-gate usb_dev_descr = usba_device->usb_dev_descr;
4060Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate return (usb_dev_descr);
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate /*
4140Sstevel@tonic-gate * usb_get_raw_cfg_data:
4150Sstevel@tonic-gate * utility function to get raw config descriptor from usba_device
4160Sstevel@tonic-gate *
4170Sstevel@tonic-gate * Arguments:
4180Sstevel@tonic-gate * dip - pointer to devinfo of the client
4190Sstevel@tonic-gate * length - pointer to copy the cfg length
4200Sstevel@tonic-gate *
4210Sstevel@tonic-gate * Return Values:
4220Sstevel@tonic-gate * usb_cfg - raw config descriptor
4230Sstevel@tonic-gate */
4240Sstevel@tonic-gate uchar_t *
usb_get_raw_cfg_data(dev_info_t * dip,size_t * length)4250Sstevel@tonic-gate usb_get_raw_cfg_data(dev_info_t *dip, size_t *length)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate usba_device_t *usba_device;
4280Sstevel@tonic-gate uchar_t *usb_cfg;
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
4310Sstevel@tonic-gate "usb_get_raw_cfg_data: %s", ddi_node_name(dip));
4320Sstevel@tonic-gate
4330Sstevel@tonic-gate if ((dip == NULL) || (length == NULL)) {
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate return (NULL);
4360Sstevel@tonic-gate }
4370Sstevel@tonic-gate
4380Sstevel@tonic-gate usba_device = usba_get_usba_device(dip);
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
4410Sstevel@tonic-gate usb_cfg = usba_device->usb_cfg;
4420Sstevel@tonic-gate *length = usba_device->usb_cfg_length;
4430Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate return (usb_cfg);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate /*
4500Sstevel@tonic-gate * usb_get_addr:
4510Sstevel@tonic-gate * utility function to return current usb address, mostly
4520Sstevel@tonic-gate * for debugging purposes
4530Sstevel@tonic-gate *
4540Sstevel@tonic-gate * Arguments:
4550Sstevel@tonic-gate * dip - pointer to devinfo of the client
4560Sstevel@tonic-gate *
4570Sstevel@tonic-gate * Return Values:
4580Sstevel@tonic-gate * address - USB Device Address
4590Sstevel@tonic-gate */
4600Sstevel@tonic-gate int
usb_get_addr(dev_info_t * dip)4610Sstevel@tonic-gate usb_get_addr(dev_info_t *dip)
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate int address = 0;
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
4660Sstevel@tonic-gate "usb_get_addr: %s", ddi_node_name(dip));
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate if (dip) {
4690Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
4720Sstevel@tonic-gate address = usba_device->usb_addr;
4730Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate return (address);
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate /*
4810Sstevel@tonic-gate * usb_set_cfg():
4820Sstevel@tonic-gate * set configuration, use with caution (issues USB_REQ_SET_CONFIG)
4830Sstevel@tonic-gate * Changing configuration will fail if pipes are still open or when
4840Sstevel@tonic-gate * invoked from a driver bound to an interface on a composite device.
4850Sstevel@tonic-gate *
4860Sstevel@tonic-gate * This function will access the device and block
4870Sstevel@tonic-gate *
4880Sstevel@tonic-gate * Arguments:
4890Sstevel@tonic-gate * dip - pointer to devinfo of the client
4900Sstevel@tonic-gate * cfg_index - config index
4910Sstevel@tonic-gate * cfg_value - config value to be set
4920Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP:
4930Sstevel@tonic-gate * wait for completion
4940Sstevel@tonic-gate * cb - if USB_FLAGS_SLEEP has not been specified
4950Sstevel@tonic-gate * this callback function will be called on
4960Sstevel@tonic-gate * completion. This callback may be NULL
4970Sstevel@tonic-gate * and no notification of completion will then
4980Sstevel@tonic-gate * be provided.
4990Sstevel@tonic-gate * cb_arg - 2nd argument to callback function.
5000Sstevel@tonic-gate *
5010Sstevel@tonic-gate * Return Values:
5020Sstevel@tonic-gate * USB_SUCCESS: - new configuration was set
5030Sstevel@tonic-gate * USB_FAILURE: - new configuration could not be set
5040Sstevel@tonic-gate * USB_BUSY: - some pipes were open or there were children
5050Sstevel@tonic-gate * USB_* - refer to usbai.h
5060Sstevel@tonic-gate */
5070Sstevel@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)5080Sstevel@tonic-gate usb_set_cfg(dev_info_t *dip,
5090Sstevel@tonic-gate uint_t cfg_index,
5100Sstevel@tonic-gate usb_flags_t usb_flags,
5110Sstevel@tonic-gate void (*cb)(
5120Sstevel@tonic-gate usb_pipe_handle_t ph,
5130Sstevel@tonic-gate usb_opaque_t arg,
5140Sstevel@tonic-gate int rval,
5150Sstevel@tonic-gate usb_cb_flags_t flags),
5160Sstevel@tonic-gate usb_opaque_t cb_arg)
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate usb_pipe_handle_t ph;
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
5210Sstevel@tonic-gate "usb_set_cfg: %s%d, cfg_index = 0x%x, uf = 0x%x",
5220Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), cfg_index,
5230Sstevel@tonic-gate usb_flags);
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate if (dip == NULL) {
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate return (USB_INVALID_ARGS);
5280Sstevel@tonic-gate }
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate return (USB_INVALID_CONTEXT);
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate if (!usb_owns_device(dip)) {
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate return (USB_INVALID_PERM);
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip);
5410Sstevel@tonic-gate if (usba_hold_ph_data(ph) == NULL) {
5420Sstevel@tonic-gate
5430Sstevel@tonic-gate return (USB_INVALID_PIPE);
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate
5460Sstevel@tonic-gate return (usba_pipe_setup_func_call(dip,
5470Sstevel@tonic-gate usba_sync_set_cfg, (usba_ph_impl_t *)ph,
5480Sstevel@tonic-gate (usb_opaque_t)((uintptr_t)cfg_index), usb_flags, cb, cb_arg));
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate
5520Sstevel@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)5530Sstevel@tonic-gate usba_sync_set_cfg(dev_info_t *dip,
5540Sstevel@tonic-gate usba_ph_impl_t *ph_impl,
5550Sstevel@tonic-gate usba_pipe_async_req_t *request,
5560Sstevel@tonic-gate usb_flags_t flags)
5570Sstevel@tonic-gate {
5580Sstevel@tonic-gate int rval;
5590Sstevel@tonic-gate usb_cr_t completion_reason;
5600Sstevel@tonic-gate usb_cb_flags_t cb_flags;
5610Sstevel@tonic-gate usba_device_t *usba_device;
5620Sstevel@tonic-gate int i, ph_open_cnt;
5630Sstevel@tonic-gate uint_t cfg_index = (uint_t)((uintptr_t)(request->arg));
5640Sstevel@tonic-gate size_t size;
5650Sstevel@tonic-gate usb_cfg_descr_t confdescr;
5661001Ssl147100 dev_info_t *pdip;
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate usba_device = usba_get_usba_device(dip);
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate /*
5710Sstevel@tonic-gate * default pipe is still open
5720Sstevel@tonic-gate * all other pipes should be closed
5730Sstevel@tonic-gate */
5740Sstevel@tonic-gate for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
5750Sstevel@tonic-gate if (usba_device->usb_ph_list[i].usba_ph_data) {
5760Sstevel@tonic-gate ph_open_cnt++;
5770Sstevel@tonic-gate break;
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate if (ph_open_cnt || ddi_get_child(dip)) {
5820Sstevel@tonic-gate usba_release_ph_data(ph_impl);
5830Sstevel@tonic-gate
5840Sstevel@tonic-gate return (USB_BUSY);
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate
5871001Ssl147100 /*
5881001Ssl147100 * check if the configuration meets the
5891001Ssl147100 * power budget requirement
5901001Ssl147100 */
5911001Ssl147100 if (usba_is_root_hub(dip)) {
5921001Ssl147100 /*
5931001Ssl147100 * root hub should never be multi-configured.
5941001Ssl147100 * the code is here just to ensure
5951001Ssl147100 */
5961001Ssl147100 usba_release_ph_data(ph_impl);
5971001Ssl147100
5981001Ssl147100 return (USB_FAILURE);
5991001Ssl147100 }
6001001Ssl147100 pdip = ddi_get_parent(dip);
6011001Ssl147100
6021001Ssl147100 /*
6031001Ssl147100 * increase the power budget value back to the unconfigured
6041001Ssl147100 * state to eliminate the influence of the old configuration
6051001Ssl147100 * before checking the new configuration; but remember to
6061001Ssl147100 * make a decrement before leaving this routine to restore
6071001Ssl147100 * the power consumption state of the device no matter it
6081001Ssl147100 * is in the new or old configuration
6091001Ssl147100 */
6101001Ssl147100 usba_hubdi_incr_power_budget(pdip, usba_device);
6111001Ssl147100
6121001Ssl147100 if ((usba_hubdi_check_power_budget(pdip, usba_device,
6131001Ssl147100 cfg_index)) != USB_SUCCESS) {
6141001Ssl147100 usba_hubdi_decr_power_budget(pdip, usba_device);
6151001Ssl147100
6161001Ssl147100 usba_release_ph_data(ph_impl);
6171001Ssl147100
6181001Ssl147100 return (USB_FAILURE);
6191001Ssl147100 }
6201001Ssl147100
6210Sstevel@tonic-gate size = usb_parse_cfg_descr(usba_device->usb_cfg_array[cfg_index],
6226898Sfb209375 USB_CFG_DESCR_SIZE, &confdescr, USB_CFG_DESCR_SIZE);
6230Sstevel@tonic-gate
6240Sstevel@tonic-gate /* hubdi should ensure that this descriptor is correct */
6250Sstevel@tonic-gate ASSERT(size == USB_CFG_DESCR_SIZE);
6260Sstevel@tonic-gate
6270Sstevel@tonic-gate /* set the configuration */
6280Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, (usb_pipe_handle_t)ph_impl,
6296898Sfb209375 USB_DEV_REQ_HOST_TO_DEV,
6306898Sfb209375 USB_REQ_SET_CFG,
6316898Sfb209375 confdescr.bConfigurationValue,
6326898Sfb209375 0,
6336898Sfb209375 0,
6346898Sfb209375 NULL, 0,
6356898Sfb209375 &completion_reason,
6366898Sfb209375 &cb_flags, flags | USBA_FLAGS_PRIVILEGED | USB_FLAGS_SLEEP);
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate if (rval == USB_SUCCESS) {
6390Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
6400Sstevel@tonic-gate usba_device->usb_cfg_value = confdescr.bConfigurationValue;
6410Sstevel@tonic-gate usba_device->usb_active_cfg_ndx = cfg_index;
6420Sstevel@tonic-gate usba_device->usb_cfg = usba_device->usb_cfg_array[cfg_index];
6430Sstevel@tonic-gate usba_device->usb_cfg_length = confdescr.wTotalLength;
6440Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
6450Sstevel@tonic-gate
6460Sstevel@tonic-gate /* update the configuration property */
6470Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
6486898Sfb209375 "configuration#", usba_device->usb_cfg_value);
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate
6511001Ssl147100 /*
6521001Ssl147100 * usba_device->usb_cfg always stores current configuration
6531001Ssl147100 * descriptor no matter SET_CFG request succeeded or not,
6541001Ssl147100 * so usba_hubdi_decr_power_budget can be done regardless
6551001Ssl147100 * of rval above
6561001Ssl147100 */
6571001Ssl147100 usba_hubdi_decr_power_budget(pdip, usba_device);
6581001Ssl147100
6590Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
6600Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate usba_release_ph_data(ph_impl);
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate return (rval);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate /*
6700Sstevel@tonic-gate * usb_get_cfg():
6710Sstevel@tonic-gate * get configuration value
6720Sstevel@tonic-gate *
6730Sstevel@tonic-gate * Arguments:
6740Sstevel@tonic-gate * dip - pointer to devinfo of the client
6750Sstevel@tonic-gate * cfg_value - current config value
6760Sstevel@tonic-gate * flags - none, always blocks
6770Sstevel@tonic-gate *
6780Sstevel@tonic-gate * Return Values:
6790Sstevel@tonic-gate * USB_SUCCESS: - config value was retrieved
6800Sstevel@tonic-gate * USB_FAILURE: - config value could not be retrieved
6810Sstevel@tonic-gate * USB_* - refer to usbai.h
6820Sstevel@tonic-gate */
6830Sstevel@tonic-gate int
usb_get_cfg(dev_info_t * dip,uint_t * cfgval,usb_flags_t flags)6840Sstevel@tonic-gate usb_get_cfg(dev_info_t *dip,
6850Sstevel@tonic-gate uint_t *cfgval,
6860Sstevel@tonic-gate usb_flags_t flags)
6870Sstevel@tonic-gate {
6880Sstevel@tonic-gate int rval;
6890Sstevel@tonic-gate usb_cr_t completion_reason;
6900Sstevel@tonic-gate mblk_t *data = NULL;
6910Sstevel@tonic-gate usb_cb_flags_t cb_flags;
6920Sstevel@tonic-gate usb_pipe_handle_t ph;
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
6950Sstevel@tonic-gate "usb_get_cfg: %s uf = 0x%x", ddi_node_name(dip), flags);
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate if ((cfgval == NULL) || (dip == NULL)) {
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate return (USB_INVALID_ARGS);
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip);
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate /*
7050Sstevel@tonic-gate * get the cfg value
7060Sstevel@tonic-gate */
7070Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph,
7086898Sfb209375 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_DEV,
7096898Sfb209375 USB_REQ_GET_CFG,
7106898Sfb209375 0,
7116898Sfb209375 0,
7126898Sfb209375 1, /* returns one byte of data */
7136898Sfb209375 &data, 0,
7146898Sfb209375 &completion_reason,
7156898Sfb209375 &cb_flags, flags);
7160Sstevel@tonic-gate
7170Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
7180Sstevel@tonic-gate "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate if ((rval == USB_SUCCESS) && data &&
7217492SZhigang.Lu@Sun.COM (MBLKL(data) == 1)) {
7220Sstevel@tonic-gate *cfgval = *(data->b_rptr);
7230Sstevel@tonic-gate } else {
7240Sstevel@tonic-gate *cfgval = 1;
7250Sstevel@tonic-gate if (rval == USB_SUCCESS) {
7260Sstevel@tonic-gate rval = USB_FAILURE;
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate
7300Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
7310Sstevel@tonic-gate "usb_get_cfg: %s cfgval=%d", ddi_node_name(dip), *cfgval);
7320Sstevel@tonic-gate
7330Sstevel@tonic-gate freemsg(data);
7340Sstevel@tonic-gate
7350Sstevel@tonic-gate return (rval);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate
7390Sstevel@tonic-gate /*
7400Sstevel@tonic-gate * usb_get_current_cfgidx:
7410Sstevel@tonic-gate * get current current config index
7420Sstevel@tonic-gate */
7430Sstevel@tonic-gate uint_t
usb_get_current_cfgidx(dev_info_t * dip)7440Sstevel@tonic-gate usb_get_current_cfgidx(dev_info_t *dip)
7450Sstevel@tonic-gate {
7460Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
7470Sstevel@tonic-gate uint_t ndx;
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
7500Sstevel@tonic-gate ndx = usba_device->usb_active_cfg_ndx;
7510Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate return (ndx);
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate /*
7580Sstevel@tonic-gate * usb_get_if_number:
7590Sstevel@tonic-gate * get usb interface number of current OS device node.
7600Sstevel@tonic-gate *
7610Sstevel@tonic-gate * Arguments:
7620Sstevel@tonic-gate * dip - pointer to devinfo of the client
7630Sstevel@tonic-gate *
7640Sstevel@tonic-gate * Return Values:
7650Sstevel@tonic-gate * USB_COMBINED_NODE if the driver is responsible for the entire
7660Sstevel@tonic-gate * device and this dip doesn't correspond to a device node.
7670Sstevel@tonic-gate * USB_DEVICE_NODE if the driver is responsible for the entire device
7680Sstevel@tonic-gate * and this dip corresponds to a device node.
7690Sstevel@tonic-gate * interface number: otherwise.
7700Sstevel@tonic-gate */
7710Sstevel@tonic-gate int
usb_get_if_number(dev_info_t * dip)7720Sstevel@tonic-gate usb_get_if_number(dev_info_t *dip)
7730Sstevel@tonic-gate {
7740Sstevel@tonic-gate int interface_num;
7750Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
7760Sstevel@tonic-gate usb_dev_descr_t *usb_dev_descr;
7770Sstevel@tonic-gate
7780Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
7796898Sfb209375 "usb_get_if_number: dip = 0x%p", (void *)dip);
7800Sstevel@tonic-gate
7810Sstevel@tonic-gate /* not quite right but we can't return a negative return value */
7820Sstevel@tonic-gate if (dip == NULL) {
7830Sstevel@tonic-gate
7840Sstevel@tonic-gate return (0);
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate if (usba_device) {
7880Sstevel@tonic-gate usb_dev_descr = usba_device->usb_dev_descr;
7890Sstevel@tonic-gate } else {
7900Sstevel@tonic-gate
7910Sstevel@tonic-gate return (0);
7920Sstevel@tonic-gate }
7930Sstevel@tonic-gate
7940Sstevel@tonic-gate interface_num = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
7950Sstevel@tonic-gate DDI_PROP_DONTPASS, "interface", USB_COMBINED_NODE);
7960Sstevel@tonic-gate
7970Sstevel@tonic-gate if (interface_num == USB_COMBINED_NODE) {
7980Sstevel@tonic-gate if (!(((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
7990Sstevel@tonic-gate (usb_dev_descr->bDeviceClass == 0)) &&
8000Sstevel@tonic-gate (usba_device->usb_n_cfgs == 1) &&
8010Sstevel@tonic-gate (usba_device->usb_n_ifs == 1))) {
8020Sstevel@tonic-gate interface_num = USB_DEVICE_NODE;
8030Sstevel@tonic-gate }
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate
8060Sstevel@tonic-gate return (interface_num);
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate
8100Sstevel@tonic-gate boolean_t
usb_owns_device(dev_info_t * dip)8110Sstevel@tonic-gate usb_owns_device(dev_info_t *dip)
8120Sstevel@tonic-gate {
8130Sstevel@tonic-gate int interface_num = usb_get_if_number(dip);
8140Sstevel@tonic-gate
8150Sstevel@tonic-gate return (interface_num < 0 ? B_TRUE : B_FALSE);
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate
8180Sstevel@tonic-gate
8193341Sgc161489 /* check whether the interface is in this interface association */
8203341Sgc161489 boolean_t
usba_check_if_in_ia(dev_info_t * dip,int n_if)8213341Sgc161489 usba_check_if_in_ia(dev_info_t *dip, int n_if)
8223341Sgc161489 {
8233341Sgc161489 int first_if, if_count;
8243341Sgc161489
8253341Sgc161489 first_if = usb_get_if_number(dip);
8263341Sgc161489 if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
8276898Sfb209375 DDI_PROP_DONTPASS, "interface-count", -1);
8283341Sgc161489 if_count += first_if;
8293341Sgc161489
8303341Sgc161489 return ((n_if >= first_if && n_if < if_count) ? B_TRUE : B_FALSE);
8313341Sgc161489 }
8323341Sgc161489
8333341Sgc161489
8340Sstevel@tonic-gate uint8_t
usba_get_ifno(dev_info_t * dip)8350Sstevel@tonic-gate usba_get_ifno(dev_info_t *dip)
8360Sstevel@tonic-gate {
8370Sstevel@tonic-gate int interface_num = usb_get_if_number(dip);
8380Sstevel@tonic-gate
8397492SZhigang.Lu@Sun.COM return (uint8_t)(interface_num < 0 ? 0 : interface_num);
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate /*
8440Sstevel@tonic-gate * usb_set_alt_if:
8450Sstevel@tonic-gate * set the alternate interface number. Issues USB_REQ_SET_IF
8460Sstevel@tonic-gate * This function will access the device
8470Sstevel@tonic-gate *
8480Sstevel@tonic-gate * Arguments:
8490Sstevel@tonic-gate * dip - pointer to devinfo of the client
8500Sstevel@tonic-gate * if_number - interface number
8510Sstevel@tonic-gate * alt_number - alternate interface number
8520Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP:
8530Sstevel@tonic-gate * wait for completion
8540Sstevel@tonic-gate * cb - if USB_FLAGS_SLEEP has not been specified
8550Sstevel@tonic-gate * this callback function will be called on
8560Sstevel@tonic-gate * completion. This callback may be NULL
8570Sstevel@tonic-gate * and no notification of completion will then
8580Sstevel@tonic-gate * be provided.
8590Sstevel@tonic-gate * cb_arg - 2nd argument to callback function.
8600Sstevel@tonic-gate *
8610Sstevel@tonic-gate *
8620Sstevel@tonic-gate * return values:
8630Sstevel@tonic-gate * USB_SUCCESS - alternate was set
8640Sstevel@tonic-gate * USB_FAILURE - alternate could not be set because pipes
8650Sstevel@tonic-gate * were still open or some access error occurred
8660Sstevel@tonic-gate * USB_* - refer to usbai.h
8670Sstevel@tonic-gate *
8680Sstevel@tonic-gate * Note:
8690Sstevel@tonic-gate * we can't easily check if all pipes to endpoints for this interface
8700Sstevel@tonic-gate * are closed since we don't have a map of which endpoints belong
8710Sstevel@tonic-gate * to which interface. If we had this map, we would need to update
8720Sstevel@tonic-gate * this on each alternative or configuration switch
8730Sstevel@tonic-gate */
8740Sstevel@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)8750Sstevel@tonic-gate usb_set_alt_if(dev_info_t *dip,
8760Sstevel@tonic-gate uint_t interface,
8770Sstevel@tonic-gate uint_t alt_number,
8780Sstevel@tonic-gate usb_flags_t usb_flags,
8790Sstevel@tonic-gate void (*cb)(
8800Sstevel@tonic-gate usb_pipe_handle_t ph,
8810Sstevel@tonic-gate usb_opaque_t arg,
8820Sstevel@tonic-gate int rval,
8830Sstevel@tonic-gate usb_cb_flags_t flags),
8840Sstevel@tonic-gate usb_opaque_t cb_arg)
8850Sstevel@tonic-gate {
8860Sstevel@tonic-gate usb_pipe_handle_t ph;
8870Sstevel@tonic-gate
8880Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
8890Sstevel@tonic-gate "usb_set_alt_if: %s%d, if = %d alt = %d, uf = 0x%x",
8900Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip),
8910Sstevel@tonic-gate interface, alt_number, usb_flags);
8920Sstevel@tonic-gate
8930Sstevel@tonic-gate if (dip == NULL) {
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate return (USB_INVALID_ARGS);
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate return (USB_INVALID_CONTEXT);
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate
9030Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip);
9040Sstevel@tonic-gate if (usba_hold_ph_data(ph) == NULL) {
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate return (USB_INVALID_PIPE);
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate return (usba_pipe_setup_func_call(dip,
9100Sstevel@tonic-gate usba_sync_set_alt_if, (usba_ph_impl_t *)ph,
9110Sstevel@tonic-gate (usb_opaque_t)((uintptr_t)((interface << 8) | alt_number)),
9120Sstevel@tonic-gate usb_flags, cb, cb_arg));
9130Sstevel@tonic-gate }
9140Sstevel@tonic-gate
9150Sstevel@tonic-gate
9160Sstevel@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)9170Sstevel@tonic-gate usba_sync_set_alt_if(dev_info_t *dip,
9180Sstevel@tonic-gate usba_ph_impl_t *ph_impl,
9190Sstevel@tonic-gate usba_pipe_async_req_t *request,
9200Sstevel@tonic-gate usb_flags_t flags)
9210Sstevel@tonic-gate {
9220Sstevel@tonic-gate int rval;
9230Sstevel@tonic-gate usb_cr_t completion_reason;
9240Sstevel@tonic-gate usb_cb_flags_t cb_flags;
9250Sstevel@tonic-gate usb_opaque_t arg = request->arg;
9260Sstevel@tonic-gate int interface = ((uintptr_t)arg >> 8) & 0xff;
9270Sstevel@tonic-gate int alt_number = (uintptr_t)arg & 0xff;
9280Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
9296898Sfb209375 (usb_pipe_handle_t)ph_impl);
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
9320Sstevel@tonic-gate "usb_set_alt_if: %s, interface#=0x%x, alt#=0x%x, "
9330Sstevel@tonic-gate "uf=0x%x", ddi_node_name(dip), interface,
9340Sstevel@tonic-gate alt_number, flags);
9350Sstevel@tonic-gate
9363341Sgc161489 /* if we don't own the device, we must own the interface or ia */
9373341Sgc161489 if (!usb_owns_device(dip) && !usba_check_if_in_ia(dip, interface) &&
9380Sstevel@tonic-gate (interface != usb_get_if_number(dip))) {
9390Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
9400Sstevel@tonic-gate
9410Sstevel@tonic-gate return (USB_INVALID_PERM);
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate /* set the alternate setting */
9450Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, usba_get_dflt_pipe_handle(dip),
9466898Sfb209375 USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF,
9476898Sfb209375 USB_REQ_SET_IF,
9486898Sfb209375 alt_number,
9496898Sfb209375 interface,
9506898Sfb209375 0,
9516898Sfb209375 NULL, 0,
9526898Sfb209375 &completion_reason,
9536898Sfb209375 &cb_flags, flags | USB_FLAGS_SLEEP);
9540Sstevel@tonic-gate
9550Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
9560Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
9570Sstevel@tonic-gate
9580Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
9590Sstevel@tonic-gate
9600Sstevel@tonic-gate return (rval);
9610Sstevel@tonic-gate }
9620Sstevel@tonic-gate
9630Sstevel@tonic-gate
9640Sstevel@tonic-gate /*
9650Sstevel@tonic-gate * usb_get_alt_if:
9660Sstevel@tonic-gate * get the alternate interface number. Issues USB_REQ_GET_IF
9670Sstevel@tonic-gate * This function will access the device and block
9680Sstevel@tonic-gate *
9690Sstevel@tonic-gate * Arguments:
9700Sstevel@tonic-gate * dip - pointer to devinfo of the client
9710Sstevel@tonic-gate * if_number - interface number
9720Sstevel@tonic-gate * alt_number - alternate interface number
9730Sstevel@tonic-gate * flags - none but USB_FLAGS_SLEEP may be passed
9740Sstevel@tonic-gate *
9750Sstevel@tonic-gate * return values:
9760Sstevel@tonic-gate * USB_SUCCESS: alternate was set
9770Sstevel@tonic-gate * USB_FAILURE: alternate could not be set because pipes
9780Sstevel@tonic-gate * were still open or some access error occurred
9790Sstevel@tonic-gate */
9800Sstevel@tonic-gate int
usb_get_alt_if(dev_info_t * dip,uint_t if_number,uint_t * alt_number,usb_flags_t flags)9810Sstevel@tonic-gate usb_get_alt_if(dev_info_t *dip,
9820Sstevel@tonic-gate uint_t if_number,
9830Sstevel@tonic-gate uint_t *alt_number,
9840Sstevel@tonic-gate usb_flags_t flags)
9850Sstevel@tonic-gate {
9860Sstevel@tonic-gate int rval;
9870Sstevel@tonic-gate usb_cr_t completion_reason;
9880Sstevel@tonic-gate mblk_t *data = NULL;
9890Sstevel@tonic-gate usb_cb_flags_t cb_flags;
9900Sstevel@tonic-gate usb_pipe_handle_t ph;
9910Sstevel@tonic-gate
9920Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
9930Sstevel@tonic-gate "usb_get_alt_if: %s, interface# = 0x%x, altp = 0x%p, "
9940Sstevel@tonic-gate "uf = 0x%x", ddi_node_name(dip), if_number,
9956898Sfb209375 (void *)alt_number, flags);
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate if ((alt_number == NULL) || (dip == NULL)) {
9980Sstevel@tonic-gate
9990Sstevel@tonic-gate return (USB_INVALID_ARGS);
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate
10020Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip);
10030Sstevel@tonic-gate
10040Sstevel@tonic-gate /*
10050Sstevel@tonic-gate * get the alternate setting
10060Sstevel@tonic-gate */
10070Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph,
10086898Sfb209375 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_IF,
10096898Sfb209375 USB_REQ_GET_IF,
10106898Sfb209375 0,
10116898Sfb209375 if_number,
10126898Sfb209375 1, /* returns one byte of data */
10136898Sfb209375 &data, 0,
10146898Sfb209375 &completion_reason,
10156898Sfb209375 &cb_flags, flags);
10160Sstevel@tonic-gate
10170Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
10180Sstevel@tonic-gate "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
10190Sstevel@tonic-gate
10200Sstevel@tonic-gate if ((rval == USB_SUCCESS) && data &&
10217492SZhigang.Lu@Sun.COM (MBLKL(data) == 1)) {
10220Sstevel@tonic-gate *alt_number = *(data->b_rptr);
10230Sstevel@tonic-gate } else {
10240Sstevel@tonic-gate *alt_number = 0;
10250Sstevel@tonic-gate if (rval == USB_SUCCESS) {
10260Sstevel@tonic-gate rval = USB_FAILURE;
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate }
10290Sstevel@tonic-gate
10300Sstevel@tonic-gate freemsg(data);
10310Sstevel@tonic-gate
10320Sstevel@tonic-gate return (rval);
10330Sstevel@tonic-gate }
10340Sstevel@tonic-gate
10350Sstevel@tonic-gate
10360Sstevel@tonic-gate /*
10370Sstevel@tonic-gate * usba_get_cfg_cloud:
10380Sstevel@tonic-gate * Get descriptor cloud for a given configuration.
10390Sstevel@tonic-gate *
10400Sstevel@tonic-gate * Arguments:
10410Sstevel@tonic-gate * dip - pointer to devinfo of the client
10420Sstevel@tonic-gate * default_ph - default pipe handle
10430Sstevel@tonic-gate * cfg - which configuration to retrieve raw cloud of
10440Sstevel@tonic-gate *
10450Sstevel@tonic-gate * Returns:
10460Sstevel@tonic-gate * on success: mblock containing the raw data. Caller must free.
10470Sstevel@tonic-gate * on failure: NULL
10480Sstevel@tonic-gate */
10490Sstevel@tonic-gate static mblk_t *
usba_get_cfg_cloud(dev_info_t * dip,usb_pipe_handle_t default_ph,int cfg)10500Sstevel@tonic-gate usba_get_cfg_cloud(dev_info_t *dip, usb_pipe_handle_t default_ph, int cfg)
10510Sstevel@tonic-gate {
10520Sstevel@tonic-gate usb_cr_t completion_reason;
10530Sstevel@tonic-gate usb_cb_flags_t cb_flags;
10540Sstevel@tonic-gate usb_cfg_descr_t cfg_descr;
10550Sstevel@tonic-gate mblk_t *pdata = NULL;
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
10580Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
10590Sstevel@tonic-gate USB_REQ_GET_DESCR,
10600Sstevel@tonic-gate USB_DESCR_TYPE_SETUP_CFG | cfg,
10610Sstevel@tonic-gate 0,
10620Sstevel@tonic-gate USB_CFG_DESCR_SIZE,
10630Sstevel@tonic-gate &pdata,
10640Sstevel@tonic-gate 0,
10650Sstevel@tonic-gate &completion_reason,
10660Sstevel@tonic-gate &cb_flags,
10670Sstevel@tonic-gate 0) != USB_SUCCESS) {
10680Sstevel@tonic-gate
10690Sstevel@tonic-gate freemsg(pdata);
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate return (NULL);
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate
10740Sstevel@tonic-gate (void) usb_parse_cfg_descr(pdata->b_rptr,
10757492SZhigang.Lu@Sun.COM MBLKL(pdata), &cfg_descr, USB_CFG_DESCR_SIZE);
10760Sstevel@tonic-gate freemsg(pdata);
10770Sstevel@tonic-gate pdata = NULL;
10780Sstevel@tonic-gate
10790Sstevel@tonic-gate if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
10800Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
10810Sstevel@tonic-gate USB_REQ_GET_DESCR,
10820Sstevel@tonic-gate USB_DESCR_TYPE_SETUP_CFG | cfg,
10830Sstevel@tonic-gate 0,
10840Sstevel@tonic-gate cfg_descr.wTotalLength,
10850Sstevel@tonic-gate &pdata,
10860Sstevel@tonic-gate 0,
10870Sstevel@tonic-gate &completion_reason,
10880Sstevel@tonic-gate &cb_flags,
10890Sstevel@tonic-gate 0) != USB_SUCCESS) {
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate freemsg(pdata);
10920Sstevel@tonic-gate
10930Sstevel@tonic-gate return (NULL);
10940Sstevel@tonic-gate }
10950Sstevel@tonic-gate
10960Sstevel@tonic-gate return (pdata);
10970Sstevel@tonic-gate }
10980Sstevel@tonic-gate
10990Sstevel@tonic-gate /*
11000Sstevel@tonic-gate * usb_check_same_device:
11010Sstevel@tonic-gate * Check if the device connected to the port is the same as
11020Sstevel@tonic-gate * the previous device that was in the port. The previous device is
11030Sstevel@tonic-gate * represented by the dip on record for the port. Print a message
11040Sstevel@tonic-gate * if the device is different. If device_string arg is not NULL, it is
11050Sstevel@tonic-gate * included in the message. Can block.
11060Sstevel@tonic-gate *
11070Sstevel@tonic-gate * Arguments:
11080Sstevel@tonic-gate * dip - pointer to devinfo of the client
11090Sstevel@tonic-gate * log_handle - handle to which messages are logged
11100Sstevel@tonic-gate * log_level - one of USB_LOG_*
11110Sstevel@tonic-gate * log_mask - logging mask
11120Sstevel@tonic-gate * check_mask - one mask containing things to check:
11130Sstevel@tonic-gate * USB_CHK_BASIC: empty mask;
11140Sstevel@tonic-gate * these checks are always done.
11150Sstevel@tonic-gate * USB_CHK_VIDPID:
11160Sstevel@tonic-gate * check vid, pid only.
11170Sstevel@tonic-gate * USB_CHK_SERIAL: check match on device
11180Sstevel@tonic-gate * serial number.
11190Sstevel@tonic-gate * USB_CHK_CFG: check all raw config
11200Sstevel@tonic-gate * clouds for a match.
11210Sstevel@tonic-gate * NOTE: descr length and content always checked
11220Sstevel@tonic-gate * device_string - Device string to appear in error message
11230Sstevel@tonic-gate *
11240Sstevel@tonic-gate * return values:
11250Sstevel@tonic-gate * USB_SUCCESS: same device
11260Sstevel@tonic-gate * USB_INVALID_VERSION not same device
11270Sstevel@tonic-gate * USB_FAILURE: Failure processing request
11280Sstevel@tonic-gate * USB_INVALID_ARG: dip is invalid
11290Sstevel@tonic-gate */
11300Sstevel@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)11310Sstevel@tonic-gate usb_check_same_device(dev_info_t *dip, usb_log_handle_t log_handle,
11320Sstevel@tonic-gate int log_level, int log_mask, uint_t check_mask, char *device_string)
11330Sstevel@tonic-gate {
11340Sstevel@tonic-gate usb_dev_descr_t usb_dev_descr;
11350Sstevel@tonic-gate usba_device_t *usba_device;
11360Sstevel@tonic-gate mblk_t *pdata = NULL;
11370Sstevel@tonic-gate uint16_t length;
11380Sstevel@tonic-gate int rval;
11390Sstevel@tonic-gate char *buf;
11400Sstevel@tonic-gate usb_cr_t completion_reason;
11410Sstevel@tonic-gate usb_cb_flags_t cb_flags;
11420Sstevel@tonic-gate boolean_t match = B_TRUE;
11430Sstevel@tonic-gate usb_pipe_handle_t def_ph;
11440Sstevel@tonic-gate
11450Sstevel@tonic-gate if (dip == NULL) {
11460Sstevel@tonic-gate
11470Sstevel@tonic-gate return (USB_INVALID_ARGS);
11480Sstevel@tonic-gate }
11490Sstevel@tonic-gate
11500Sstevel@tonic-gate usba_device = usba_get_usba_device(dip);
11510Sstevel@tonic-gate length = usba_device->usb_dev_descr->bLength;
11520Sstevel@tonic-gate def_ph = usba_get_dflt_pipe_handle(dip);
11530Sstevel@tonic-gate ASSERT(def_ph);
11540Sstevel@tonic-gate
11550Sstevel@tonic-gate /* get the "new" device descriptor */
11560Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
11576898Sfb209375 USB_DEV_REQ_DEV_TO_HOST |
11586898Sfb209375 USB_DEV_REQ_TYPE_STANDARD,
11596898Sfb209375 USB_REQ_GET_DESCR, /* bRequest */
11606898Sfb209375 USB_DESCR_TYPE_SETUP_DEV, /* wValue */
11616898Sfb209375 0, /* wIndex */
11626898Sfb209375 length, /* wLength */
11636898Sfb209375 &pdata, 0,
11646898Sfb209375 &completion_reason,
11656898Sfb209375 &cb_flags, USB_FLAGS_SLEEP);
11660Sstevel@tonic-gate
11670Sstevel@tonic-gate if (rval != USB_SUCCESS) {
11680Sstevel@tonic-gate if (!((completion_reason == USB_CR_DATA_OVERRUN) && (pdata))) {
11690Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usbai_log_handle,
11700Sstevel@tonic-gate "getting device descriptor failed (%d)", rval);
11710Sstevel@tonic-gate freemsg(pdata);
11720Sstevel@tonic-gate
11730Sstevel@tonic-gate return (USB_FAILURE);
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate }
11760Sstevel@tonic-gate
11770Sstevel@tonic-gate ASSERT(pdata != NULL);
11780Sstevel@tonic-gate
11790Sstevel@tonic-gate (void) usb_parse_dev_descr(pdata->b_rptr,
11807492SZhigang.Lu@Sun.COM MBLKL(pdata), &usb_dev_descr,
11810Sstevel@tonic-gate sizeof (usb_dev_descr_t));
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate freemsg(pdata);
11840Sstevel@tonic-gate pdata = NULL;
11850Sstevel@tonic-gate
11860Sstevel@tonic-gate /* Always check the device descriptor length. */
11870Sstevel@tonic-gate if (usb_dev_descr.bLength != length) {
11880Sstevel@tonic-gate match = B_FALSE;
11890Sstevel@tonic-gate }
11900Sstevel@tonic-gate
11910Sstevel@tonic-gate if ((match == B_TRUE) && (check_mask & USB_CHK_VIDPID)) {
11920Sstevel@tonic-gate match = (usba_device->usb_dev_descr->idVendor ==
11930Sstevel@tonic-gate usb_dev_descr.idVendor) &&
11940Sstevel@tonic-gate (usba_device->usb_dev_descr->idProduct ==
11950Sstevel@tonic-gate usb_dev_descr.idProduct);
11960Sstevel@tonic-gate } else if (bcmp((char *)usba_device->usb_dev_descr,
11970Sstevel@tonic-gate (char *)&usb_dev_descr, length) != 0) {
11980Sstevel@tonic-gate match = B_FALSE;
11990Sstevel@tonic-gate }
12000Sstevel@tonic-gate
12010Sstevel@tonic-gate /* if requested & this device has a serial number check and compare */
12020Sstevel@tonic-gate if ((match == B_TRUE) && ((check_mask & USB_CHK_SERIAL) != 0) &&
12030Sstevel@tonic-gate (usba_device->usb_serialno_str != NULL)) {
12040Sstevel@tonic-gate buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP);
12050Sstevel@tonic-gate if (usb_get_string_descr(dip, USB_LANG_ID,
12060Sstevel@tonic-gate usb_dev_descr.iSerialNumber, buf,
12070Sstevel@tonic-gate USB_MAXSTRINGLEN) == USB_SUCCESS) {
12080Sstevel@tonic-gate match =
12090Sstevel@tonic-gate (strcmp(buf, usba_device->usb_serialno_str) == 0);
12100Sstevel@tonic-gate }
12110Sstevel@tonic-gate kmem_free(buf, USB_MAXSTRINGLEN);
12120Sstevel@tonic-gate }
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate if ((match == B_TRUE) && (check_mask & USB_CHK_CFG)) {
12150Sstevel@tonic-gate
12160Sstevel@tonic-gate uint8_t num_cfgs = usb_dev_descr.bNumConfigurations;
12170Sstevel@tonic-gate uint8_t cfg;
12180Sstevel@tonic-gate mblk_t *cloud;
12190Sstevel@tonic-gate
12200Sstevel@tonic-gate for (cfg = 0; cfg < num_cfgs; cfg++) {
12210Sstevel@tonic-gate cloud = usba_get_cfg_cloud(dip, def_ph, cfg);
12220Sstevel@tonic-gate if (cloud == NULL) {
12230Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA,
12240Sstevel@tonic-gate usbai_log_handle,
12250Sstevel@tonic-gate "Could not retrieve config cloud for "
12260Sstevel@tonic-gate "comparison");
12270Sstevel@tonic-gate break;
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate
12300Sstevel@tonic-gate if (bcmp((char *)cloud->b_rptr,
12310Sstevel@tonic-gate usba_device->usb_cfg_array[cfg],
12327492SZhigang.Lu@Sun.COM MBLKL(cloud)) != 0) {
12330Sstevel@tonic-gate freemsg(cloud);
12340Sstevel@tonic-gate break;
12350Sstevel@tonic-gate }
12360Sstevel@tonic-gate
12370Sstevel@tonic-gate freemsg(cloud);
12380Sstevel@tonic-gate }
12390Sstevel@tonic-gate if (cfg != num_cfgs) {
12400Sstevel@tonic-gate match = B_FALSE;
12410Sstevel@tonic-gate }
12420Sstevel@tonic-gate }
12430Sstevel@tonic-gate
12440Sstevel@tonic-gate if (match == B_FALSE) {
12450Sstevel@tonic-gate boolean_t allocated_here = (device_string == NULL);
12460Sstevel@tonic-gate if (allocated_here) {
12470Sstevel@tonic-gate device_string =
12480Sstevel@tonic-gate kmem_zalloc(USB_MAXSTRINGLEN, USB_FLAGS_SLEEP);
12490Sstevel@tonic-gate (void) usba_get_mfg_prod_sn_str(dip, device_string,
12506898Sfb209375 USB_MAXSTRINGLEN);
12510Sstevel@tonic-gate }
12520Sstevel@tonic-gate if (device_string[0] != '\0') {
12530Sstevel@tonic-gate (void) usb_log(log_handle, log_level, log_mask,
12540Sstevel@tonic-gate "Cannot access %s. Please reconnect.",
12550Sstevel@tonic-gate device_string);
12560Sstevel@tonic-gate } else {
12570Sstevel@tonic-gate (void) usb_log(log_handle, log_level, log_mask,
12580Sstevel@tonic-gate "Device is not identical to the "
12590Sstevel@tonic-gate "previous one this port.\n"
12600Sstevel@tonic-gate "Please disconnect and reconnect");
12610Sstevel@tonic-gate }
12620Sstevel@tonic-gate if (allocated_here) {
12630Sstevel@tonic-gate kmem_free(device_string, USB_MAXSTRINGLEN);
12640Sstevel@tonic-gate }
12650Sstevel@tonic-gate
12660Sstevel@tonic-gate return (USB_INVALID_VERSION);
12670Sstevel@tonic-gate }
12680Sstevel@tonic-gate
12690Sstevel@tonic-gate return (USB_SUCCESS);
12700Sstevel@tonic-gate }
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate
12730Sstevel@tonic-gate /*
12740Sstevel@tonic-gate * usb_pipe_get_state:
12750Sstevel@tonic-gate * Return the state of the pipe
12760Sstevel@tonic-gate *
12770Sstevel@tonic-gate * Arguments:
12780Sstevel@tonic-gate * pipe_handle - pipe_handle pointer
12790Sstevel@tonic-gate * pipe_state - pointer to copy pipe state to
12800Sstevel@tonic-gate * flags:
12810Sstevel@tonic-gate * not used other than to check context
12820Sstevel@tonic-gate *
12830Sstevel@tonic-gate * Return Values:
12840Sstevel@tonic-gate * USB_SUCCESS - port state returned
12850Sstevel@tonic-gate * USB_* - refer to usbai.h
12860Sstevel@tonic-gate */
12870Sstevel@tonic-gate int
usb_pipe_get_state(usb_pipe_handle_t pipe_handle,usb_pipe_state_t * pipe_state,usb_flags_t usb_flags)12880Sstevel@tonic-gate usb_pipe_get_state(usb_pipe_handle_t pipe_handle,
12890Sstevel@tonic-gate usb_pipe_state_t *pipe_state,
12900Sstevel@tonic-gate usb_flags_t usb_flags)
12910Sstevel@tonic-gate {
12920Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
12930Sstevel@tonic-gate
12940Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12956898Sfb209375 "usb_pipe_get_state: ph_data=0x%p uf=0x%x", (void *)ph_data,
12966898Sfb209375 usb_flags);
12970Sstevel@tonic-gate
12980Sstevel@tonic-gate if (pipe_state == NULL) {
12990Sstevel@tonic-gate if (ph_data) {
13000Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
13010Sstevel@tonic-gate }
13020Sstevel@tonic-gate
13030Sstevel@tonic-gate return (USB_INVALID_ARGS);
13040Sstevel@tonic-gate }
13050Sstevel@tonic-gate
13060Sstevel@tonic-gate if (ph_data == NULL) {
13070Sstevel@tonic-gate *pipe_state = USB_PIPE_STATE_CLOSED;
13080Sstevel@tonic-gate
13090Sstevel@tonic-gate return (USB_SUCCESS);
13100Sstevel@tonic-gate }
13110Sstevel@tonic-gate
13120Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
13130Sstevel@tonic-gate *pipe_state = usba_get_ph_state(ph_data);
13140Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
13150Sstevel@tonic-gate
13160Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
13170Sstevel@tonic-gate
13180Sstevel@tonic-gate return (USB_SUCCESS);
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate
13210Sstevel@tonic-gate
13220Sstevel@tonic-gate /*
13230Sstevel@tonic-gate * usba_pipe_get_policy:
13240Sstevel@tonic-gate * Return a pipe's policy
13250Sstevel@tonic-gate *
13260Sstevel@tonic-gate * Arguments:
13270Sstevel@tonic-gate * pipe_handle - pipe_handle pointer
13280Sstevel@tonic-gate *
13290Sstevel@tonic-gate * Return Values:
13300Sstevel@tonic-gate * On success: the pipe's policy
13310Sstevel@tonic-gate * On failure: NULL
13320Sstevel@tonic-gate */
13330Sstevel@tonic-gate usb_pipe_policy_t
usba_pipe_get_policy(usb_pipe_handle_t pipe_handle)13340Sstevel@tonic-gate *usba_pipe_get_policy(usb_pipe_handle_t pipe_handle)
13350Sstevel@tonic-gate {
13360Sstevel@tonic-gate usb_pipe_policy_t *pp = NULL;
13370Sstevel@tonic-gate
13380Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
13390Sstevel@tonic-gate
13400Sstevel@tonic-gate if (ph_data) {
13410Sstevel@tonic-gate pp = &ph_data->p_policy;
13420Sstevel@tonic-gate
13430Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
13440Sstevel@tonic-gate }
13450Sstevel@tonic-gate
13460Sstevel@tonic-gate return (pp);
13470Sstevel@tonic-gate }
13480Sstevel@tonic-gate
13490Sstevel@tonic-gate
13500Sstevel@tonic-gate /*
13510Sstevel@tonic-gate * usb_ep_num:
13520Sstevel@tonic-gate * Return the endpoint number for a given pipe handle
13530Sstevel@tonic-gate *
13540Sstevel@tonic-gate * Arguments:
13550Sstevel@tonic-gate * pipe_handle - pipe_handle pointer
13560Sstevel@tonic-gate *
13570Sstevel@tonic-gate * Return Values:
13580Sstevel@tonic-gate * endpoint number
13590Sstevel@tonic-gate */
13600Sstevel@tonic-gate int
usb_ep_num(usb_pipe_handle_t pipe_handle)13610Sstevel@tonic-gate usb_ep_num(usb_pipe_handle_t pipe_handle)
13620Sstevel@tonic-gate {
13630Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
13640Sstevel@tonic-gate int ep_num;
13650Sstevel@tonic-gate
13660Sstevel@tonic-gate if (ph_data == NULL) {
13670Sstevel@tonic-gate
13680Sstevel@tonic-gate return (USB_INVALID_PIPE);
13690Sstevel@tonic-gate }
13700Sstevel@tonic-gate
13710Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
13720Sstevel@tonic-gate ep_num = ph_data->p_ep.bEndpointAddress & USB_EP_NUM_MASK;
13730Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
13740Sstevel@tonic-gate
13750Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
13760Sstevel@tonic-gate
13770Sstevel@tonic-gate return (ep_num);
13780Sstevel@tonic-gate }
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate
13810Sstevel@tonic-gate /*
13820Sstevel@tonic-gate * usb_get_status
13830Sstevel@tonic-gate * Issues USB_REQ_GET_STATUS to device/endpoint/interface
13840Sstevel@tonic-gate * and report in "status" arg.
13850Sstevel@tonic-gate *
13860Sstevel@tonic-gate * status reported for a "device" is
13870Sstevel@tonic-gate * RemoteWakeup enabled
13880Sstevel@tonic-gate * SelfPowered device?
13890Sstevel@tonic-gate *
13900Sstevel@tonic-gate * status reported for an "interface" is NONE.
13910Sstevel@tonic-gate * status reported for an "endpoint" is
13920Sstevel@tonic-gate * HALT set (device STALLED?)
13930Sstevel@tonic-gate *
13940Sstevel@tonic-gate * Arguments:
13950Sstevel@tonic-gate * dip - pointer to devinfo of the client
13960Sstevel@tonic-gate * ph - pipe handle
13970Sstevel@tonic-gate * type - bmRequestType to be used
13980Sstevel@tonic-gate * what - 0 for device, otherwise interface or ep number
13990Sstevel@tonic-gate * status - user supplied pointer for storing the status
14000Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP (mandatory)
14010Sstevel@tonic-gate *
14020Sstevel@tonic-gate * Return Values:
14030Sstevel@tonic-gate * valid usb_status_t or USB_FAILURE
14040Sstevel@tonic-gate */
14050Sstevel@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)14060Sstevel@tonic-gate usb_get_status(dev_info_t *dip,
14070Sstevel@tonic-gate usb_pipe_handle_t ph,
14080Sstevel@tonic-gate uint_t type, /* bmRequestType */
14090Sstevel@tonic-gate uint_t what, /* 0, interface, ept number */
14100Sstevel@tonic-gate uint16_t *status,
14110Sstevel@tonic-gate usb_flags_t flags)
14120Sstevel@tonic-gate {
14130Sstevel@tonic-gate int rval;
14140Sstevel@tonic-gate usb_cr_t completion_reason;
14150Sstevel@tonic-gate mblk_t *data = NULL;
14160Sstevel@tonic-gate usb_cb_flags_t cb_flags;
14170Sstevel@tonic-gate
14180Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
14190Sstevel@tonic-gate "usb_get_status: type = 0x%x, what = 0x%x, uf = 0x%x",
14200Sstevel@tonic-gate type, what, flags);
14210Sstevel@tonic-gate
14220Sstevel@tonic-gate if ((status == NULL) || (dip == NULL)) {
14230Sstevel@tonic-gate
14240Sstevel@tonic-gate return (USB_INVALID_ARGS);
14250Sstevel@tonic-gate }
14260Sstevel@tonic-gate if (ph == NULL) {
14270Sstevel@tonic-gate
14280Sstevel@tonic-gate return (USB_INVALID_PIPE);
14290Sstevel@tonic-gate }
14300Sstevel@tonic-gate
14310Sstevel@tonic-gate type |= USB_DEV_REQ_DEV_TO_HOST;
14320Sstevel@tonic-gate
14330Sstevel@tonic-gate /* get the status */
14340Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph,
14356898Sfb209375 type,
14366898Sfb209375 USB_REQ_GET_STATUS,
14376898Sfb209375 0,
14386898Sfb209375 what,
14396898Sfb209375 USB_GET_STATUS_LEN, /* status is fixed 2 bytes long */
14406898Sfb209375 &data, 0,
14416898Sfb209375 &completion_reason, &cb_flags, flags);
14420Sstevel@tonic-gate
14430Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
14440Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
14450Sstevel@tonic-gate
14460Sstevel@tonic-gate if ((rval == USB_SUCCESS) && data &&
14477492SZhigang.Lu@Sun.COM (MBLKL(data) == USB_GET_STATUS_LEN)) {
14480Sstevel@tonic-gate *status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
14490Sstevel@tonic-gate } else {
14500Sstevel@tonic-gate *status = 0;
14510Sstevel@tonic-gate if (rval == USB_SUCCESS) {
14520Sstevel@tonic-gate rval = USB_FAILURE;
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate }
14550Sstevel@tonic-gate
14560Sstevel@tonic-gate freemsg(data);
14570Sstevel@tonic-gate
14580Sstevel@tonic-gate return (rval);
14590Sstevel@tonic-gate }
14600Sstevel@tonic-gate
14610Sstevel@tonic-gate
14620Sstevel@tonic-gate /*
14630Sstevel@tonic-gate * usb_clear_feature:
14640Sstevel@tonic-gate * Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
14650Sstevel@tonic-gate *
14660Sstevel@tonic-gate * Arguments:
14670Sstevel@tonic-gate * dip - pointer to devinfo of the client
14680Sstevel@tonic-gate * ph - pipe handle pointer
14690Sstevel@tonic-gate * type - bmRequestType to be used
14700Sstevel@tonic-gate * feature - feature to be cleared
14710Sstevel@tonic-gate * what - 0 for device, otherwise interface or ep number
14720Sstevel@tonic-gate * flags - none (but will sleep)
14730Sstevel@tonic-gate *
14740Sstevel@tonic-gate * Return Values:
14750Sstevel@tonic-gate * USB_SUCCESS - on doing a successful clear feature
14760Sstevel@tonic-gate * USB_FAILURE - on failure
14770Sstevel@tonic-gate * USB_* - refer to usbai.h
14780Sstevel@tonic-gate */
14790Sstevel@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)14800Sstevel@tonic-gate usb_clear_feature(dev_info_t *dip,
14810Sstevel@tonic-gate usb_pipe_handle_t ph,
14820Sstevel@tonic-gate uint_t type, /* bmRequestType */
14830Sstevel@tonic-gate uint_t feature,
14840Sstevel@tonic-gate uint_t what, /* 0, interface, ept number */
14850Sstevel@tonic-gate usb_flags_t flags)
14860Sstevel@tonic-gate {
14870Sstevel@tonic-gate int rval;
14880Sstevel@tonic-gate usb_cr_t completion_reason;
14890Sstevel@tonic-gate usb_cb_flags_t cb_flags;
14900Sstevel@tonic-gate
14910Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
14920Sstevel@tonic-gate "usb_clear_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
14930Sstevel@tonic-gate "uf = 0x%x", type, feature, what, flags);
14940Sstevel@tonic-gate
14950Sstevel@tonic-gate if (dip == NULL) {
14960Sstevel@tonic-gate
14970Sstevel@tonic-gate return (USB_INVALID_ARGS);
14980Sstevel@tonic-gate }
14990Sstevel@tonic-gate if (ph == NULL) {
15000Sstevel@tonic-gate
15010Sstevel@tonic-gate return (USB_INVALID_PIPE);
15020Sstevel@tonic-gate }
15030Sstevel@tonic-gate
15040Sstevel@tonic-gate /* issue Clear feature */
15050Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(dip, ph,
15066898Sfb209375 type,
15076898Sfb209375 USB_REQ_CLEAR_FEATURE,
15086898Sfb209375 feature,
15096898Sfb209375 what,
15106898Sfb209375 0,
15116898Sfb209375 NULL, 0,
15126898Sfb209375 &completion_reason,
15136898Sfb209375 &cb_flags, flags | USB_FLAGS_SLEEP);
15140Sstevel@tonic-gate
15150Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
15160Sstevel@tonic-gate "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
15170Sstevel@tonic-gate
15180Sstevel@tonic-gate return (rval);
15190Sstevel@tonic-gate }
15200Sstevel@tonic-gate
15210Sstevel@tonic-gate
15220Sstevel@tonic-gate /*
15230Sstevel@tonic-gate * usb_clr_feature:
15240Sstevel@tonic-gate * Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
15250Sstevel@tonic-gate *
15260Sstevel@tonic-gate * Arguments:
15270Sstevel@tonic-gate * dip - pointer to devinfo of the client
15280Sstevel@tonic-gate * type - bmRequestType to be used
15290Sstevel@tonic-gate * feature - feature to be cleared
15300Sstevel@tonic-gate * what - 0 for device, otherwise interface or ep number
15310Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP:
15320Sstevel@tonic-gate * wait for completion
15330Sstevel@tonic-gate * cb - if USB_FLAGS_SLEEP has not been specified
15340Sstevel@tonic-gate * this callback function will be called on
15350Sstevel@tonic-gate * completion. This callback may be NULL
15360Sstevel@tonic-gate * and no notification of completion will then
15370Sstevel@tonic-gate * be provided.
15380Sstevel@tonic-gate * cb_arg - 2nd argument to callback function.
15390Sstevel@tonic-gate *
15400Sstevel@tonic-gate *
15410Sstevel@tonic-gate * Return Values:
15420Sstevel@tonic-gate * USB_SUCCESS - on doing a successful clear feature
15430Sstevel@tonic-gate * USB_FAILURE - on failure
15440Sstevel@tonic-gate * USB_* - refer to usbai.h
15450Sstevel@tonic-gate */
15460Sstevel@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)15470Sstevel@tonic-gate usb_clr_feature(
15480Sstevel@tonic-gate dev_info_t *dip,
15490Sstevel@tonic-gate uint_t type, /* bmRequestType */
15500Sstevel@tonic-gate uint_t feature,
15510Sstevel@tonic-gate uint_t what, /* 0, interface, ept number */
15520Sstevel@tonic-gate usb_flags_t flags,
15530Sstevel@tonic-gate void (*cb)(
15540Sstevel@tonic-gate usb_pipe_handle_t ph,
15550Sstevel@tonic-gate usb_opaque_t arg,
15560Sstevel@tonic-gate int rval,
15570Sstevel@tonic-gate usb_cb_flags_t flags),
15580Sstevel@tonic-gate usb_opaque_t cb_arg)
15590Sstevel@tonic-gate {
15600Sstevel@tonic-gate usb_pipe_handle_t ph;
15610Sstevel@tonic-gate
15620Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
15630Sstevel@tonic-gate "usb_clr_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
15640Sstevel@tonic-gate "uf = 0x%x", type, feature, what, flags);
15650Sstevel@tonic-gate
15660Sstevel@tonic-gate if (dip == NULL) {
15670Sstevel@tonic-gate
15680Sstevel@tonic-gate return (USB_INVALID_ARGS);
15690Sstevel@tonic-gate }
15700Sstevel@tonic-gate
15710Sstevel@tonic-gate if ((flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
15720Sstevel@tonic-gate
15730Sstevel@tonic-gate return (USB_INVALID_CONTEXT);
15740Sstevel@tonic-gate }
15750Sstevel@tonic-gate
15760Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip);
15770Sstevel@tonic-gate if (usba_hold_ph_data(ph) == NULL) {
15780Sstevel@tonic-gate
15790Sstevel@tonic-gate return (USB_INVALID_PIPE);
15800Sstevel@tonic-gate }
15810Sstevel@tonic-gate
15820Sstevel@tonic-gate return (usba_pipe_setup_func_call(dip,
15830Sstevel@tonic-gate usba_sync_clear_feature, (usba_ph_impl_t *)ph,
15840Sstevel@tonic-gate (usb_opaque_t)((uintptr_t)((type << 16 | feature << 8 | what))),
15850Sstevel@tonic-gate flags, cb, cb_arg));
15860Sstevel@tonic-gate }
15870Sstevel@tonic-gate
15880Sstevel@tonic-gate
15890Sstevel@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)15900Sstevel@tonic-gate usba_sync_clear_feature(dev_info_t *dip,
15910Sstevel@tonic-gate usba_ph_impl_t *ph_impl,
15920Sstevel@tonic-gate usba_pipe_async_req_t *req,
15936898Sfb209375 usb_flags_t usb_flags)
15940Sstevel@tonic-gate {
15950Sstevel@tonic-gate uint_t n = (uint_t)((uintptr_t)(req->arg));
15960Sstevel@tonic-gate uint_t type = ((uint_t)n >> 16) & 0xff;
15970Sstevel@tonic-gate uint_t feature = ((uint_t)n >> 8) & 0xff;
15980Sstevel@tonic-gate uint_t what = (uint_t)n & 0xff;
15996898Sfb209375 int rval;
1600*8945SGuoqing.Zhu@Sun.COM usba_device_t *usba_device;
1601*8945SGuoqing.Zhu@Sun.COM usba_pipe_handle_data_t *ph_data;
1602*8945SGuoqing.Zhu@Sun.COM usba_ph_impl_t *ph_im;
1603*8945SGuoqing.Zhu@Sun.COM uchar_t ep_index;
1604*8945SGuoqing.Zhu@Sun.COM usb_ep_descr_t *eptd;
1605*8945SGuoqing.Zhu@Sun.COM
16060Sstevel@tonic-gate
16070Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
16080Sstevel@tonic-gate "usb_sync_clear_feature: "
16090Sstevel@tonic-gate "dip=0x%p ph=0x%p type=0x%x feature=0x%x what=0x%x fl=0x%x",
16106898Sfb209375 (void *)dip, (void *)ph_impl, type, feature, what, usb_flags);
16110Sstevel@tonic-gate
16120Sstevel@tonic-gate rval = usb_clear_feature(dip, (usb_pipe_handle_t)ph_impl, type,
16136898Sfb209375 feature, what, usb_flags);
16140Sstevel@tonic-gate
1615*8945SGuoqing.Zhu@Sun.COM /*
1616*8945SGuoqing.Zhu@Sun.COM * Reset data toggle to DATA0 for bulk and interrupt endpoint.
1617*8945SGuoqing.Zhu@Sun.COM * Data toggle synchronization is not supported for isochronous
1618*8945SGuoqing.Zhu@Sun.COM * transfer.Halt feature is not supported by control endpoint.
1619*8945SGuoqing.Zhu@Sun.COM *
1620*8945SGuoqing.Zhu@Sun.COM * From USB2.0 specification:
1621*8945SGuoqing.Zhu@Sun.COM * 1.Section 5.8.5 Bulk Transfer Data Sequences
1622*8945SGuoqing.Zhu@Sun.COM * Removal of the halt condition is achieved via software intervention
1623*8945SGuoqing.Zhu@Sun.COM * through a separate control pipe. This recovery will reset the data
1624*8945SGuoqing.Zhu@Sun.COM * toggle bit to DATA0 for the endpoint on both the host and the device.
1625*8945SGuoqing.Zhu@Sun.COM *
1626*8945SGuoqing.Zhu@Sun.COM * 2.Section 5.7.5 Interrupt Transfer Data Sequences
1627*8945SGuoqing.Zhu@Sun.COM * Removal of the halt condition is achieved via software intervention
1628*8945SGuoqing.Zhu@Sun.COM * through a separate control pipe. This recovery will reset the data
1629*8945SGuoqing.Zhu@Sun.COM * toggle bit to DATA0 for the endpoint on both the host and the device.
1630*8945SGuoqing.Zhu@Sun.COM *
1631*8945SGuoqing.Zhu@Sun.COM * 3.Section 9.4.5
1632*8945SGuoqing.Zhu@Sun.COM * If the condition causing a halt has been removed, clearing the Halt
1633*8945SGuoqing.Zhu@Sun.COM * feature via a ClearFeature(ENDPOINT_HALT) request results in the
1634*8945SGuoqing.Zhu@Sun.COM * endpoint no longer returning a STALL. For endpoints using data
1635*8945SGuoqing.Zhu@Sun.COM * toggle, regardless of whether an endpoint has the Halt feature set, a
1636*8945SGuoqing.Zhu@Sun.COM * ClearFeature(ENDPOINT_HALT) request always results in the data toggle
1637*8945SGuoqing.Zhu@Sun.COM * being reinitialized to DATA0.
1638*8945SGuoqing.Zhu@Sun.COM *
1639*8945SGuoqing.Zhu@Sun.COM */
1640*8945SGuoqing.Zhu@Sun.COM if (rval == USB_SUCCESS && feature == 0) {
1641*8945SGuoqing.Zhu@Sun.COM usba_device = usba_get_usba_device(dip);
1642*8945SGuoqing.Zhu@Sun.COM ep_index = usb_get_ep_index((uint8_t)what);
1643*8945SGuoqing.Zhu@Sun.COM ph_im = &usba_device->usb_ph_list[ep_index];
1644*8945SGuoqing.Zhu@Sun.COM ph_data = usba_get_ph_data((usb_pipe_handle_t)ph_im);
1645*8945SGuoqing.Zhu@Sun.COM eptd = &ph_data->p_ep;
1646*8945SGuoqing.Zhu@Sun.COM if ((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
1647*8945SGuoqing.Zhu@Sun.COM USB_EP_ATTR_BULK || (eptd->bmAttributes &
1648*8945SGuoqing.Zhu@Sun.COM USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR)
1649*8945SGuoqing.Zhu@Sun.COM usba_device->usb_hcdi_ops->
1650*8945SGuoqing.Zhu@Sun.COM usba_hcdi_pipe_reset_data_toggle(ph_data);
1651*8945SGuoqing.Zhu@Sun.COM }
1652*8945SGuoqing.Zhu@Sun.COM
16530Sstevel@tonic-gate usba_release_ph_data(ph_impl);
16540Sstevel@tonic-gate
16550Sstevel@tonic-gate return (rval);
16560Sstevel@tonic-gate }
16570Sstevel@tonic-gate
16580Sstevel@tonic-gate
16590Sstevel@tonic-gate /*
16600Sstevel@tonic-gate * usb_async_req:
16610Sstevel@tonic-gate * function used to dispatch a request to the taskq
16620Sstevel@tonic-gate *
16630Sstevel@tonic-gate * Arguments:
16640Sstevel@tonic-gate * dip - pointer to devinfo node
16650Sstevel@tonic-gate * func - pointer to function issued by taskq
16660Sstevel@tonic-gate * flag - USB_FLAGS_SLEEP mostly
16670Sstevel@tonic-gate *
16680Sstevel@tonic-gate * Return Values:
16690Sstevel@tonic-gate * USB_SUCCESS - on doing a successful taskq invocation
16700Sstevel@tonic-gate * USB_FAILURE - on failure
16710Sstevel@tonic-gate * USB_* - refer to usbai.h
16720Sstevel@tonic-gate */
16730Sstevel@tonic-gate int
usb_async_req(dev_info_t * dip,void (* func)(void *),void * arg,usb_flags_t flag)16740Sstevel@tonic-gate usb_async_req(dev_info_t *dip,
16750Sstevel@tonic-gate void (*func)(void *),
16760Sstevel@tonic-gate void *arg,
16770Sstevel@tonic-gate usb_flags_t flag)
16780Sstevel@tonic-gate {
16790Sstevel@tonic-gate int tq_flag;
16800Sstevel@tonic-gate
16810Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
16820Sstevel@tonic-gate "usb_async_req: dip=0x%p func=0x%p, arg=0x%p flag=0x%x",
16836898Sfb209375 (void *)dip, (void *)func, arg, flag);
16840Sstevel@tonic-gate
16850Sstevel@tonic-gate if ((dip == NULL) || (func == NULL)) {
16860Sstevel@tonic-gate
16870Sstevel@tonic-gate return (USB_INVALID_ARGS);
16880Sstevel@tonic-gate }
16890Sstevel@tonic-gate tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
16900Sstevel@tonic-gate if (flag & USB_FLAGS_NOQUEUE) {
16910Sstevel@tonic-gate tq_flag |= TQ_NOQUEUE;
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate
16940Sstevel@tonic-gate if (!taskq_dispatch(system_taskq, func, (void *)arg,
16950Sstevel@tonic-gate tq_flag)) {
16960Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
16970Sstevel@tonic-gate "usb_async_req: failure");
16980Sstevel@tonic-gate
16990Sstevel@tonic-gate return (USB_FAILURE);
17000Sstevel@tonic-gate }
17010Sstevel@tonic-gate
17020Sstevel@tonic-gate return (USB_SUCCESS);
17030Sstevel@tonic-gate }
17040Sstevel@tonic-gate
17050Sstevel@tonic-gate /*
17060Sstevel@tonic-gate * usba_async_ph_req:
17070Sstevel@tonic-gate * function used to dispatch a request to the ph taskq
17080Sstevel@tonic-gate *
17090Sstevel@tonic-gate * Arguments:
17100Sstevel@tonic-gate * ph_data - pointer to pipe handle data
17110Sstevel@tonic-gate * func - pointer to function issued by taskq
17120Sstevel@tonic-gate * flag - USB_FLAGS_SLEEP or USB_FLAGS_NOSLEEP
17130Sstevel@tonic-gate *
17140Sstevel@tonic-gate * Return Values:
17150Sstevel@tonic-gate * USB_SUCCESS - on doing a successful taskq invocation
17160Sstevel@tonic-gate * USB_FAILURE - on failure
17170Sstevel@tonic-gate * USB_* - refer to usbai.h
17180Sstevel@tonic-gate *
17190Sstevel@tonic-gate * Note:
17200Sstevel@tonic-gate * If the caller specified USB_FLAGS_NOSLEEP, it must be
17210Sstevel@tonic-gate * capable of reliably recovering from a failure return
17220Sstevel@tonic-gate */
17230Sstevel@tonic-gate int
usba_async_ph_req(usba_pipe_handle_data_t * ph_data,void (* func)(void *),void * arg,usb_flags_t flag)17240Sstevel@tonic-gate usba_async_ph_req(usba_pipe_handle_data_t *ph_data,
17250Sstevel@tonic-gate void (*func)(void *),
17260Sstevel@tonic-gate void *arg,
17270Sstevel@tonic-gate usb_flags_t flag)
17280Sstevel@tonic-gate {
17290Sstevel@tonic-gate int tq_flag;
17300Sstevel@tonic-gate taskq_t *taskq;
17310Sstevel@tonic-gate
17320Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
17330Sstevel@tonic-gate "usba_async_ph_req: ph_data=0x%p func=0x%p, arg=0x%p flag=0x%x",
17346898Sfb209375 (void *)ph_data, (void *)func, arg, flag);
17350Sstevel@tonic-gate
17360Sstevel@tonic-gate if (func == NULL) {
17370Sstevel@tonic-gate
17380Sstevel@tonic-gate return (USB_INVALID_ARGS);
17390Sstevel@tonic-gate }
17400Sstevel@tonic-gate
17410Sstevel@tonic-gate tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
17420Sstevel@tonic-gate
17430Sstevel@tonic-gate if (ph_data && ph_data->p_taskq) {
17440Sstevel@tonic-gate taskq = ph_data->p_taskq;
17450Sstevel@tonic-gate } else {
17460Sstevel@tonic-gate taskq = system_taskq;
17470Sstevel@tonic-gate tq_flag |= TQ_NOQUEUE;
17480Sstevel@tonic-gate }
17490Sstevel@tonic-gate
17500Sstevel@tonic-gate if (!taskq_dispatch(taskq, func, (void *)arg, tq_flag)) {
17510Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
17520Sstevel@tonic-gate "usba_async_ph_req: failure");
17530Sstevel@tonic-gate
17540Sstevel@tonic-gate return (USB_FAILURE);
17550Sstevel@tonic-gate }
17560Sstevel@tonic-gate
17570Sstevel@tonic-gate return (USB_SUCCESS);
17580Sstevel@tonic-gate }
17590Sstevel@tonic-gate
17600Sstevel@tonic-gate
17610Sstevel@tonic-gate /*
17620Sstevel@tonic-gate * utility functions to display CR, CB, return values
17630Sstevel@tonic-gate */
17640Sstevel@tonic-gate typedef struct conv_table {
17650Sstevel@tonic-gate int what;
17660Sstevel@tonic-gate const char *name;
17670Sstevel@tonic-gate } conv_table_t;
17680Sstevel@tonic-gate
17690Sstevel@tonic-gate static const char *
usba_get_name(conv_table_t * conv_table,int value)17700Sstevel@tonic-gate usba_get_name(conv_table_t *conv_table, int value)
17710Sstevel@tonic-gate {
17720Sstevel@tonic-gate int i;
17730Sstevel@tonic-gate for (i = 0; conv_table[i].name != NULL; i++) {
17740Sstevel@tonic-gate if (conv_table[i].what == value) {
17750Sstevel@tonic-gate
17760Sstevel@tonic-gate return (conv_table[i].name);
17770Sstevel@tonic-gate }
17780Sstevel@tonic-gate }
17790Sstevel@tonic-gate
17800Sstevel@tonic-gate return ("unknown");
17810Sstevel@tonic-gate }
17820Sstevel@tonic-gate
17830Sstevel@tonic-gate
17840Sstevel@tonic-gate static conv_table_t cr_table[] = {
17850Sstevel@tonic-gate { USB_CR_OK, "<no errors detected>" },
17860Sstevel@tonic-gate { USB_CR_CRC, "<crc error detected>" },
17870Sstevel@tonic-gate { USB_CR_BITSTUFFING, "<Bit stuffing violation>" },
17880Sstevel@tonic-gate { USB_CR_DATA_TOGGLE_MM, "<Data toggle PID did not match>" },
17890Sstevel@tonic-gate { USB_CR_STALL, "<Endpoint returned stall PID>" },
17900Sstevel@tonic-gate { USB_CR_DEV_NOT_RESP, "<Device not responding>" },
17910Sstevel@tonic-gate { USB_CR_PID_CHECKFAILURE, "<Check bits on PID failed>" },
17920Sstevel@tonic-gate { USB_CR_UNEXP_PID, "<Receive PID was not valid>" },
17930Sstevel@tonic-gate { USB_CR_DATA_OVERRUN, "<Data size exceeded>" },
17940Sstevel@tonic-gate { USB_CR_DATA_UNDERRUN, "<Less data recieved than requested>" },
17950Sstevel@tonic-gate { USB_CR_BUFFER_OVERRUN, "<Memory write can't keep up>" },
17960Sstevel@tonic-gate { USB_CR_BUFFER_UNDERRUN, "<Buffer underrun>" },
17970Sstevel@tonic-gate { USB_CR_TIMEOUT, "<Command timed out>" },
17980Sstevel@tonic-gate { USB_CR_NOT_ACCESSED, "<Not accessed by hardware>" },
17990Sstevel@tonic-gate { USB_CR_NO_RESOURCES, "<No resources>" },
18000Sstevel@tonic-gate { USB_CR_UNSPECIFIED_ERR, "<Unspecified usba or hcd error>" },
18010Sstevel@tonic-gate { USB_CR_STOPPED_POLLING, "<Intr/ISOC IN polling stopped>" },
18020Sstevel@tonic-gate { USB_CR_PIPE_CLOSING, "<Intr/ISOC IN pipe being closed>" },
18030Sstevel@tonic-gate { USB_CR_PIPE_RESET, "<Intr/ISOC IN pipe reset>" },
18040Sstevel@tonic-gate { USB_CR_NOT_SUPPORTED, "<Command not supported>" },
18050Sstevel@tonic-gate { USB_CR_FLUSHED, "<Req was flushed>" },
18060Sstevel@tonic-gate { USB_CR_HC_HARDWARE_ERR, "<USB host controller error>" },
18070Sstevel@tonic-gate { 0, NULL }
18080Sstevel@tonic-gate };
18090Sstevel@tonic-gate
18100Sstevel@tonic-gate const char *
usb_str_cr(usb_cr_t cr)18110Sstevel@tonic-gate usb_str_cr(usb_cr_t cr)
18120Sstevel@tonic-gate {
18130Sstevel@tonic-gate return (usba_get_name(cr_table, cr));
18140Sstevel@tonic-gate }
18150Sstevel@tonic-gate
18160Sstevel@tonic-gate
18170Sstevel@tonic-gate static conv_table_t cb_flags_table[] = {
18180Sstevel@tonic-gate { USB_CB_NO_INFO, "<callback processed>" },
18190Sstevel@tonic-gate { USB_CB_STALL_CLEARED, "<stall cleared>" },
18200Sstevel@tonic-gate { USB_CB_FUNCTIONAL_STALL, "<functional stall>" },
18210Sstevel@tonic-gate { USB_CB_PROTOCOL_STALL, "<protocol stall>" },
18220Sstevel@tonic-gate { USB_CB_RESET_PIPE, "<pipe reset>" },
18230Sstevel@tonic-gate { USB_CB_ASYNC_REQ_FAILED, "<thread could not be started>" },
18240Sstevel@tonic-gate { USB_CB_NO_RESOURCES, "<no resources>" },
18250Sstevel@tonic-gate { USB_CB_SUBMIT_FAILED, "<submit failed>" },
18260Sstevel@tonic-gate { USB_CB_INTR_CONTEXT, "<Callback executing in interrupt context>" },
18270Sstevel@tonic-gate { 0, NULL }
18280Sstevel@tonic-gate };
18290Sstevel@tonic-gate
18300Sstevel@tonic-gate /*ARGSUSED*/
18310Sstevel@tonic-gate char *
usb_str_cb_flags(usb_cb_flags_t cb_flags,char * buffer,size_t length)18320Sstevel@tonic-gate usb_str_cb_flags(usb_cb_flags_t cb_flags, char *buffer, size_t length)
18330Sstevel@tonic-gate {
18340Sstevel@tonic-gate int i;
18350Sstevel@tonic-gate buffer[0] = '\0';
18360Sstevel@tonic-gate if (cb_flags == USB_CB_NO_INFO) {
18370Sstevel@tonic-gate (void) strncpy(buffer, cb_flags_table[0].name, length);
18380Sstevel@tonic-gate } else {
18390Sstevel@tonic-gate for (i = 0; cb_flags_table[i].name != NULL; i++) {
18400Sstevel@tonic-gate if (cb_flags & cb_flags_table[i].what) {
18410Sstevel@tonic-gate (void) strncpy(&buffer[strlen(buffer)],
18420Sstevel@tonic-gate cb_flags_table[0].name,
18430Sstevel@tonic-gate length - strlen(buffer) - 1);
18440Sstevel@tonic-gate }
18450Sstevel@tonic-gate }
18460Sstevel@tonic-gate }
18470Sstevel@tonic-gate
18480Sstevel@tonic-gate return (buffer);
18490Sstevel@tonic-gate }
18500Sstevel@tonic-gate
18510Sstevel@tonic-gate
18520Sstevel@tonic-gate static conv_table_t pipe_state_table[] = {
18530Sstevel@tonic-gate { USB_PIPE_STATE_CLOSED, "<closed>" },
18540Sstevel@tonic-gate { USB_PIPE_STATE_IDLE, "<idle>" },
18550Sstevel@tonic-gate { USB_PIPE_STATE_ACTIVE, "<active>" },
18560Sstevel@tonic-gate { USB_PIPE_STATE_ERROR, "<error>" },
18570Sstevel@tonic-gate { USB_PIPE_STATE_CLOSING, "<closing>" },
18580Sstevel@tonic-gate { 0, NULL }
18590Sstevel@tonic-gate };
18600Sstevel@tonic-gate
18610Sstevel@tonic-gate const char *
usb_str_pipe_state(usb_pipe_state_t state)18620Sstevel@tonic-gate usb_str_pipe_state(usb_pipe_state_t state)
18630Sstevel@tonic-gate {
18640Sstevel@tonic-gate return (usba_get_name(pipe_state_table, state));
18650Sstevel@tonic-gate }
18660Sstevel@tonic-gate
18670Sstevel@tonic-gate
18680Sstevel@tonic-gate static conv_table_t dev_state[] = {
18690Sstevel@tonic-gate { USB_DEV_ONLINE, "<online>" },
18700Sstevel@tonic-gate { USB_DEV_DISCONNECTED, "<disconnected>" },
18710Sstevel@tonic-gate { USB_DEV_SUSPENDED, "<suspended>" },
18720Sstevel@tonic-gate { USB_DEV_PWRED_DOWN, "<powered down>" },
18730Sstevel@tonic-gate { 0, NULL }
18740Sstevel@tonic-gate };
18750Sstevel@tonic-gate
18760Sstevel@tonic-gate const char *
usb_str_dev_state(int state)18770Sstevel@tonic-gate usb_str_dev_state(int state)
18780Sstevel@tonic-gate {
18790Sstevel@tonic-gate return (usba_get_name(dev_state, state));
18800Sstevel@tonic-gate }
18810Sstevel@tonic-gate
18820Sstevel@tonic-gate
18830Sstevel@tonic-gate static conv_table_t rval_table[] = {
18840Sstevel@tonic-gate { USB_SUCCESS, "<success>" },
18850Sstevel@tonic-gate { USB_FAILURE, "<failure>" },
18860Sstevel@tonic-gate { USB_NO_RESOURCES, "<no resources>" },
18870Sstevel@tonic-gate { USB_NO_BANDWIDTH, "<no bandwidth>" },
18880Sstevel@tonic-gate { USB_NOT_SUPPORTED, "<not supported>" },
18890Sstevel@tonic-gate { USB_PIPE_ERROR, "<pipe error>" },
18900Sstevel@tonic-gate { USB_INVALID_PIPE, "<invalid pipe>" },
18910Sstevel@tonic-gate { USB_NO_FRAME_NUMBER, "<no frame number>" },
18920Sstevel@tonic-gate { USB_INVALID_START_FRAME, "<invalid frame>" },
18930Sstevel@tonic-gate { USB_HC_HARDWARE_ERROR, "<hw error>" },
18940Sstevel@tonic-gate { USB_INVALID_REQUEST, "<invalid request>" },
18950Sstevel@tonic-gate { USB_INVALID_CONTEXT, "<invalid context>" },
18960Sstevel@tonic-gate { USB_INVALID_VERSION, "<invalid version>" },
18970Sstevel@tonic-gate { USB_INVALID_ARGS, "<invalid args>" },
18980Sstevel@tonic-gate { USB_INVALID_PERM, "<invalid perms>" },
18990Sstevel@tonic-gate { USB_BUSY, "<busy>" },
19000Sstevel@tonic-gate { 0, NULL }
19010Sstevel@tonic-gate };
19020Sstevel@tonic-gate
19030Sstevel@tonic-gate const char *
usb_str_rval(int rval)19040Sstevel@tonic-gate usb_str_rval(int rval)
19050Sstevel@tonic-gate {
19060Sstevel@tonic-gate return (usba_get_name(rval_table, rval));
19070Sstevel@tonic-gate }
19080Sstevel@tonic-gate
19090Sstevel@tonic-gate
19100Sstevel@tonic-gate /*
19110Sstevel@tonic-gate * function to convert USB return values to close errno
19120Sstevel@tonic-gate */
19130Sstevel@tonic-gate static struct usb_rval2errno_entry {
19140Sstevel@tonic-gate int rval;
19150Sstevel@tonic-gate int Errno;
19160Sstevel@tonic-gate } usb_rval2errno_table[] = {
19170Sstevel@tonic-gate { USB_SUCCESS, 0 },
19180Sstevel@tonic-gate { USB_FAILURE, EIO },
19190Sstevel@tonic-gate { USB_NO_RESOURCES, ENOMEM },
19200Sstevel@tonic-gate { USB_NO_BANDWIDTH, EAGAIN },
19210Sstevel@tonic-gate { USB_NOT_SUPPORTED, ENOTSUP },
19220Sstevel@tonic-gate { USB_PIPE_ERROR, EIO },
19230Sstevel@tonic-gate { USB_INVALID_PIPE, EINVAL },
19240Sstevel@tonic-gate { USB_NO_FRAME_NUMBER, EINVAL },
19250Sstevel@tonic-gate { USB_INVALID_START_FRAME, EINVAL },
19260Sstevel@tonic-gate { USB_HC_HARDWARE_ERROR, EIO },
19270Sstevel@tonic-gate { USB_INVALID_REQUEST, EINVAL },
19280Sstevel@tonic-gate { USB_INVALID_CONTEXT, EINVAL },
19290Sstevel@tonic-gate { USB_INVALID_VERSION, EINVAL },
19300Sstevel@tonic-gate { USB_INVALID_ARGS, EINVAL },
19310Sstevel@tonic-gate { USB_INVALID_PERM, EACCES },
19320Sstevel@tonic-gate { USB_BUSY, EBUSY },
19330Sstevel@tonic-gate };
19340Sstevel@tonic-gate
19350Sstevel@tonic-gate #define USB_RVAL2ERRNO_TABLE_SIZE (sizeof (usb_rval2errno_table) / \
19360Sstevel@tonic-gate sizeof (struct usb_rval2errno_entry))
19370Sstevel@tonic-gate int
usb_rval2errno(int rval)19380Sstevel@tonic-gate usb_rval2errno(int rval)
19390Sstevel@tonic-gate {
19400Sstevel@tonic-gate int i;
19410Sstevel@tonic-gate
19420Sstevel@tonic-gate for (i = 0; i < USB_RVAL2ERRNO_TABLE_SIZE; i++) {
19430Sstevel@tonic-gate if (usb_rval2errno_table[i].rval == rval) {
19440Sstevel@tonic-gate
19450Sstevel@tonic-gate return (usb_rval2errno_table[i].Errno);
19460Sstevel@tonic-gate }
19470Sstevel@tonic-gate }
19480Sstevel@tonic-gate
19490Sstevel@tonic-gate return (EIO);
19500Sstevel@tonic-gate }
19510Sstevel@tonic-gate
19520Sstevel@tonic-gate
19530Sstevel@tonic-gate /*
19540Sstevel@tonic-gate * serialization
19550Sstevel@tonic-gate */
19560Sstevel@tonic-gate usb_serialization_t
usb_init_serialization(dev_info_t * dip,uint_t flag)19570Sstevel@tonic-gate usb_init_serialization(
19580Sstevel@tonic-gate dev_info_t *dip,
19590Sstevel@tonic-gate uint_t flag)
19600Sstevel@tonic-gate {
19610Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp = kmem_zalloc(
19626898Sfb209375 sizeof (usba_serialization_impl_t), KM_SLEEP);
19630Sstevel@tonic-gate usba_device_t *usba_device;
19640Sstevel@tonic-gate ddi_iblock_cookie_t cookie = NULL;
19650Sstevel@tonic-gate
19660Sstevel@tonic-gate if (dip) {
19670Sstevel@tonic-gate usba_device = usba_get_usba_device(dip);
19680Sstevel@tonic-gate cookie = usba_hcdi_get_hcdi(
19690Sstevel@tonic-gate usba_device->usb_root_hub_dip)->hcdi_iblock_cookie;
19700Sstevel@tonic-gate }
19710Sstevel@tonic-gate impl_tokenp->s_dip = dip;
19720Sstevel@tonic-gate impl_tokenp->s_flag = flag;
19730Sstevel@tonic-gate mutex_init(&impl_tokenp->s_mutex, NULL, MUTEX_DRIVER, cookie);
19740Sstevel@tonic-gate cv_init(&impl_tokenp->s_cv, NULL, CV_DRIVER, NULL);
19750Sstevel@tonic-gate
19760Sstevel@tonic-gate return ((usb_serialization_t)impl_tokenp);
19770Sstevel@tonic-gate }
19780Sstevel@tonic-gate
19790Sstevel@tonic-gate
19800Sstevel@tonic-gate void
usb_fini_serialization(usb_serialization_t tokenp)19810Sstevel@tonic-gate usb_fini_serialization(
19820Sstevel@tonic-gate usb_serialization_t tokenp)
19830Sstevel@tonic-gate {
19840Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp;
19850Sstevel@tonic-gate
19860Sstevel@tonic-gate if (tokenp) {
19870Sstevel@tonic-gate impl_tokenp = (usba_serialization_impl_t *)tokenp;
19880Sstevel@tonic-gate ASSERT(impl_tokenp->s_count == 0);
19890Sstevel@tonic-gate cv_destroy(&impl_tokenp->s_cv);
19900Sstevel@tonic-gate mutex_destroy(&impl_tokenp->s_mutex);
19910Sstevel@tonic-gate kmem_free(impl_tokenp, sizeof (usba_serialization_impl_t));
19920Sstevel@tonic-gate }
19930Sstevel@tonic-gate }
19940Sstevel@tonic-gate
19950Sstevel@tonic-gate
19960Sstevel@tonic-gate /*
19970Sstevel@tonic-gate * usb_serialize_access() permits single threaded access.
19980Sstevel@tonic-gate *
19990Sstevel@tonic-gate * If tokenp is initialized with USB_INIT_SER_CHECK_SAME_THREAD,
20000Sstevel@tonic-gate * it is reentrant with respect to thread. The thread must
20010Sstevel@tonic-gate * hold and release the same number of times.
20020Sstevel@tonic-gate *
20030Sstevel@tonic-gate * If tokenp is initialized without USB_INIT_SER_CHECK_SAME_THREAD,
20040Sstevel@tonic-gate * it is not reentrant by the same thread. It is something like
20050Sstevel@tonic-gate * a semaphore.
20060Sstevel@tonic-gate */
20070Sstevel@tonic-gate int
usb_serialize_access(usb_serialization_t tokenp,uint_t how_to_wait,uint_t delta_timeout)20080Sstevel@tonic-gate usb_serialize_access(
20090Sstevel@tonic-gate usb_serialization_t tokenp, uint_t how_to_wait, uint_t delta_timeout)
20100Sstevel@tonic-gate {
20110Sstevel@tonic-gate int rval = 1; /* Must be initialized > 0 */
20120Sstevel@tonic-gate clock_t abs_timeout;
20130Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp;
20140Sstevel@tonic-gate
20150Sstevel@tonic-gate impl_tokenp = (usba_serialization_impl_t *)tokenp;
20160Sstevel@tonic-gate
20170Sstevel@tonic-gate /*
20180Sstevel@tonic-gate * Convert delta timeout in ms to absolute timeout in ticks, if used.
20190Sstevel@tonic-gate */
20200Sstevel@tonic-gate if ((how_to_wait == USB_TIMEDWAIT) ||
20210Sstevel@tonic-gate (how_to_wait == USB_TIMEDWAIT_SIG)) {
20220Sstevel@tonic-gate /* Convert timeout arg (in ms) to hz */
20230Sstevel@tonic-gate abs_timeout = ddi_get_lbolt() +
20240Sstevel@tonic-gate drv_usectohz(delta_timeout * 1000);
20250Sstevel@tonic-gate }
20260Sstevel@tonic-gate
20270Sstevel@tonic-gate /* Get mutex after calc abs time, to count time waiting for mutex. */
20280Sstevel@tonic-gate mutex_enter(&impl_tokenp->s_mutex);
20290Sstevel@tonic-gate
20300Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
20310Sstevel@tonic-gate "usb_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p, "
20320Sstevel@tonic-gate "flg=0x%x, abs_tmo=0x%lx",
20336898Sfb209375 (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
20346898Sfb209375 impl_tokenp->s_count, (void *)impl_tokenp->s_thread,
20356898Sfb209375 how_to_wait, abs_timeout);
20360Sstevel@tonic-gate
20370Sstevel@tonic-gate if ((impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0 ||
20380Sstevel@tonic-gate impl_tokenp->s_thread != curthread) {
20390Sstevel@tonic-gate
20400Sstevel@tonic-gate /*
20410Sstevel@tonic-gate * There are three ways to break out of the loop:
20420Sstevel@tonic-gate * 1) Condition met (s_count == 0) - higher prio test
20430Sstevel@tonic-gate * 2) kill(2) signal received (rval == 0)
20440Sstevel@tonic-gate * 3) timeout occurred (rval == -1)
20450Sstevel@tonic-gate * If condition met, whether or not signal or timeout occurred
20460Sstevel@tonic-gate * take access. If condition not met, check other exit means.
20470Sstevel@tonic-gate */
20480Sstevel@tonic-gate while (impl_tokenp->s_count != 0) {
20490Sstevel@tonic-gate
20500Sstevel@tonic-gate /* cv_timedwait* returns -1 on timeout. */
20510Sstevel@tonic-gate /* cv_wait*_sig returns 0 on (kill(2)) signal. */
20520Sstevel@tonic-gate if (rval <= 0) {
20530Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex);
20540Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA,
20550Sstevel@tonic-gate usbai_log_handle,
20560Sstevel@tonic-gate "usb_serialize_access: "
20576898Sfb209375 "tok=0x%p exit due to %s",
20586898Sfb209375 (void *)impl_tokenp,
20590Sstevel@tonic-gate ((rval == 0) ? "signal" : "timeout"));
20600Sstevel@tonic-gate
20610Sstevel@tonic-gate return (rval);
20620Sstevel@tonic-gate }
20630Sstevel@tonic-gate
20640Sstevel@tonic-gate switch (how_to_wait) {
20650Sstevel@tonic-gate default:
20660Sstevel@tonic-gate how_to_wait = USB_WAIT;
20670Sstevel@tonic-gate /* FALLTHROUGH */
20680Sstevel@tonic-gate case USB_WAIT:
20690Sstevel@tonic-gate cv_wait(&impl_tokenp->s_cv,
20706898Sfb209375 &impl_tokenp->s_mutex);
20710Sstevel@tonic-gate break;
20720Sstevel@tonic-gate case USB_WAIT_SIG:
20730Sstevel@tonic-gate rval = cv_wait_sig(&impl_tokenp->s_cv,
20746898Sfb209375 &impl_tokenp->s_mutex);
20750Sstevel@tonic-gate break;
20760Sstevel@tonic-gate case USB_TIMEDWAIT:
20770Sstevel@tonic-gate rval = cv_timedwait(&impl_tokenp->s_cv,
20786898Sfb209375 &impl_tokenp->s_mutex, abs_timeout);
20790Sstevel@tonic-gate break;
20800Sstevel@tonic-gate case USB_TIMEDWAIT_SIG:
20810Sstevel@tonic-gate rval = cv_timedwait_sig(&impl_tokenp->s_cv,
20826898Sfb209375 &impl_tokenp->s_mutex, abs_timeout);
20830Sstevel@tonic-gate break;
20840Sstevel@tonic-gate }
20850Sstevel@tonic-gate }
20860Sstevel@tonic-gate
20870Sstevel@tonic-gate impl_tokenp->s_thread = curthread;
20880Sstevel@tonic-gate }
20890Sstevel@tonic-gate impl_tokenp->s_count++;
20900Sstevel@tonic-gate
20910Sstevel@tonic-gate ASSERT(!(impl_tokenp->s_count > 1 &&
20920Sstevel@tonic-gate (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0));
20930Sstevel@tonic-gate
20940Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex);
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
20976898Sfb209375 "usb_serialize_access exit: tok=0x%p thr=0x%p", (void *)impl_tokenp,
20986898Sfb209375 (void *)curthread);
20990Sstevel@tonic-gate
21000Sstevel@tonic-gate return (1);
21010Sstevel@tonic-gate }
21020Sstevel@tonic-gate
21030Sstevel@tonic-gate
21040Sstevel@tonic-gate /*ARGSUSED*/
21050Sstevel@tonic-gate int
usb_try_serialize_access(usb_serialization_t tokenp,uint_t flag)21060Sstevel@tonic-gate usb_try_serialize_access(
21070Sstevel@tonic-gate usb_serialization_t tokenp, uint_t flag)
21080Sstevel@tonic-gate {
21090Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp =
21106898Sfb209375 (usba_serialization_impl_t *)tokenp;
21110Sstevel@tonic-gate mutex_enter(&impl_tokenp->s_mutex);
21120Sstevel@tonic-gate
21130Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
21140Sstevel@tonic-gate "usb_try_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p",
21156898Sfb209375 (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
21166898Sfb209375 impl_tokenp->s_count, (void *)curthread);
21170Sstevel@tonic-gate
21180Sstevel@tonic-gate /*
21190Sstevel@tonic-gate * If lock is not taken (s_count is 0), take it.
21200Sstevel@tonic-gate * If lock is already taken, the thread is owner and lock
21210Sstevel@tonic-gate * is reentrant, take it.
21220Sstevel@tonic-gate * Otherwise, fail the access.
21230Sstevel@tonic-gate */
21240Sstevel@tonic-gate if (!impl_tokenp->s_count || ((impl_tokenp->s_thread == curthread) &&
21250Sstevel@tonic-gate (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD))) {
21260Sstevel@tonic-gate impl_tokenp->s_thread = curthread;
21270Sstevel@tonic-gate impl_tokenp->s_count++;
21280Sstevel@tonic-gate
21290Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
21306898Sfb209375 "usb_try_serialize_access success: tok=0x%p",
21316898Sfb209375 (void *)impl_tokenp);
21320Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex);
21330Sstevel@tonic-gate
21340Sstevel@tonic-gate return (USB_SUCCESS);
21350Sstevel@tonic-gate }
21360Sstevel@tonic-gate
21370Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
21380Sstevel@tonic-gate "usb_try_serialize_access failed: "
21390Sstevel@tonic-gate "tok=0x%p dip=0x%p cnt=%d thr=0x%p",
21406898Sfb209375 (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
21416898Sfb209375 impl_tokenp->s_count, (void *)impl_tokenp->s_thread);
21420Sstevel@tonic-gate
21430Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex);
21440Sstevel@tonic-gate
21450Sstevel@tonic-gate return (USB_FAILURE);
21460Sstevel@tonic-gate }
21470Sstevel@tonic-gate
21480Sstevel@tonic-gate
21490Sstevel@tonic-gate void
usb_release_access(usb_serialization_t tokenp)21500Sstevel@tonic-gate usb_release_access(
21510Sstevel@tonic-gate usb_serialization_t tokenp)
21520Sstevel@tonic-gate {
21530Sstevel@tonic-gate usba_serialization_impl_t *impl_tokenp =
21546898Sfb209375 (usba_serialization_impl_t *)tokenp;
21550Sstevel@tonic-gate mutex_enter(&impl_tokenp->s_mutex);
21560Sstevel@tonic-gate
21570Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
21580Sstevel@tonic-gate "usb_release_access: tok=0x%p dip=0x%p count=%d thr=0x%p",
21596898Sfb209375 (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
21606898Sfb209375 impl_tokenp->s_count, (void *)curthread);
21610Sstevel@tonic-gate
21620Sstevel@tonic-gate ASSERT(impl_tokenp->s_count > 0);
21630Sstevel@tonic-gate
21640Sstevel@tonic-gate if (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) {
21650Sstevel@tonic-gate if (impl_tokenp->s_thread != curthread) {
2166978Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
21670Sstevel@tonic-gate "usb_release_access: release from wrong thread");
21680Sstevel@tonic-gate }
21690Sstevel@tonic-gate ASSERT(impl_tokenp->s_thread == curthread);
21700Sstevel@tonic-gate }
21710Sstevel@tonic-gate
21720Sstevel@tonic-gate if (--impl_tokenp->s_count == 0) {
21730Sstevel@tonic-gate impl_tokenp->s_thread = NULL;
21740Sstevel@tonic-gate cv_broadcast(&impl_tokenp->s_cv);
21750Sstevel@tonic-gate }
21760Sstevel@tonic-gate mutex_exit(&impl_tokenp->s_mutex);
21770Sstevel@tonic-gate }
21780Sstevel@tonic-gate
21790Sstevel@tonic-gate
21800Sstevel@tonic-gate /*
21810Sstevel@tonic-gate * usb_fail_checkpoint:
21820Sstevel@tonic-gate * fail checkpoint as driver/device could not be quiesced
21830Sstevel@tonic-gate */
21840Sstevel@tonic-gate /*ARGSUSED*/
21850Sstevel@tonic-gate void
usb_fail_checkpoint(dev_info_t * dip,usb_flags_t flags)21860Sstevel@tonic-gate usb_fail_checkpoint(dev_info_t *dip, usb_flags_t flags)
21870Sstevel@tonic-gate {
21880Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
21890Sstevel@tonic-gate
21900Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
21910Sstevel@tonic-gate "usb_fail_checkpoint: %s%d", ddi_driver_name(dip),
21920Sstevel@tonic-gate ddi_get_instance(dip));
21930Sstevel@tonic-gate
21940Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
21950Sstevel@tonic-gate usba_device->usb_no_cpr++;
21960Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
21970Sstevel@tonic-gate }
21980Sstevel@tonic-gate
21990Sstevel@tonic-gate
22000Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
22010Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
22020Sstevel@tonic-gate /*
22030Sstevel@tonic-gate * usba_mk_mctl:
22040Sstevel@tonic-gate * create a USB style M_CTL message, given an iocblk and a buffer
22050Sstevel@tonic-gate * returns mblk_t * on success, NULL on failure
22060Sstevel@tonic-gate */
22070Sstevel@tonic-gate mblk_t *
usba_mk_mctl(struct iocblk mctlmsg,void * buf,size_t len)22080Sstevel@tonic-gate usba_mk_mctl(struct iocblk mctlmsg, void *buf, size_t len)
22090Sstevel@tonic-gate {
22100Sstevel@tonic-gate mblk_t *bp1, *bp2;
22110Sstevel@tonic-gate
22120Sstevel@tonic-gate if ((bp1 = allocb(sizeof (struct iocblk), BPRI_HI)) != NULL) {
22137492SZhigang.Lu@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */
22140Sstevel@tonic-gate *((struct iocblk *)bp1->b_datap->db_base) = mctlmsg;
22150Sstevel@tonic-gate bp1->b_datap->db_type = M_CTL;
22160Sstevel@tonic-gate bp1->b_wptr += sizeof (struct iocblk);
22170Sstevel@tonic-gate if (buf != NULL) {
22180Sstevel@tonic-gate if ((bp2 = allocb(len, BPRI_HI)) != NULL) {
22190Sstevel@tonic-gate bp1->b_cont = bp2;
22200Sstevel@tonic-gate bcopy(buf, bp2->b_datap->db_base, len);
22210Sstevel@tonic-gate bp2->b_wptr += len;
22220Sstevel@tonic-gate } else {
22230Sstevel@tonic-gate freemsg(bp1);
22240Sstevel@tonic-gate bp1 = NULL;
22250Sstevel@tonic-gate }
22260Sstevel@tonic-gate }
22270Sstevel@tonic-gate }
22280Sstevel@tonic-gate
22290Sstevel@tonic-gate return (bp1);
22300Sstevel@tonic-gate }
22310Sstevel@tonic-gate
22320Sstevel@tonic-gate
22330Sstevel@tonic-gate #ifdef ALLOCB_TEST
22340Sstevel@tonic-gate #undef allocb
22350Sstevel@tonic-gate mblk_t *
usba_test_allocb(size_t size,uint_t pri)22360Sstevel@tonic-gate usba_test_allocb(size_t size, uint_t pri)
22370Sstevel@tonic-gate {
22380Sstevel@tonic-gate if (ddi_get_lbolt() & 0x1) {
22390Sstevel@tonic-gate
22400Sstevel@tonic-gate return (NULL);
22410Sstevel@tonic-gate } else {
22420Sstevel@tonic-gate
22430Sstevel@tonic-gate return (allocb(size, pri));
22440Sstevel@tonic-gate }
22450Sstevel@tonic-gate }
22460Sstevel@tonic-gate #endif
22473341Sgc161489
22483341Sgc161489
22493341Sgc161489 /*
22503341Sgc161489 * usb common power management for usb_mid, usb_ia and maybe other simple
22513341Sgc161489 * drivers.
22523341Sgc161489 */
22533341Sgc161489
22543341Sgc161489 /*
22553341Sgc161489 * functions to handle power transition for OS levels 0 -> 3
22563341Sgc161489 */
22573341Sgc161489 static int
usb_common_pwrlvl0(dev_info_t * dip,uint8_t * pm,int * dev_state)22583528Sgc161489 usb_common_pwrlvl0(dev_info_t *dip, uint8_t *pm, int *dev_state)
22593341Sgc161489 {
22603341Sgc161489 int rval;
22613341Sgc161489
22623341Sgc161489 switch (*dev_state) {
22633341Sgc161489 case USB_DEV_ONLINE:
22643341Sgc161489 /* Issue USB D3 command to the device here */
22653341Sgc161489 rval = usb_set_device_pwrlvl3(dip);
22663341Sgc161489 ASSERT(rval == USB_SUCCESS);
22673341Sgc161489
22683341Sgc161489 *dev_state = USB_DEV_PWRED_DOWN;
22693528Sgc161489 *pm = USB_DEV_OS_PWR_OFF;
22703341Sgc161489 /* FALLTHRU */
22713341Sgc161489 case USB_DEV_DISCONNECTED:
22723341Sgc161489 case USB_DEV_SUSPENDED:
22733341Sgc161489 /* allow a disconnected/cpr'ed device to go to low pwr */
22743341Sgc161489
22753341Sgc161489 return (USB_SUCCESS);
22763341Sgc161489 case USB_DEV_PWRED_DOWN:
22773341Sgc161489 default:
22783341Sgc161489 return (USB_FAILURE);
22793341Sgc161489 }
22803341Sgc161489 }
22813341Sgc161489
22823341Sgc161489
22833341Sgc161489 /* ARGSUSED */
22843341Sgc161489 static int
usb_common_pwrlvl1(dev_info_t * dip,uint8_t * pm,int * dev_state)22853528Sgc161489 usb_common_pwrlvl1(dev_info_t *dip, uint8_t *pm, int *dev_state)
22863341Sgc161489 {
22873341Sgc161489 int rval;
22883341Sgc161489
22893341Sgc161489 /* Issue USB D2 command to the device here */
22903341Sgc161489 rval = usb_set_device_pwrlvl2(dip);
22913341Sgc161489 ASSERT(rval == USB_SUCCESS);
22923341Sgc161489
22933341Sgc161489 return (USB_FAILURE);
22943341Sgc161489 }
22953341Sgc161489
22963341Sgc161489
22973341Sgc161489 /* ARGSUSED */
22983341Sgc161489 static int
usb_common_pwrlvl2(dev_info_t * dip,uint8_t * pm,int * dev_state)22993528Sgc161489 usb_common_pwrlvl2(dev_info_t *dip, uint8_t *pm, int *dev_state)
23003341Sgc161489 {
23013341Sgc161489 int rval;
23023341Sgc161489
23033341Sgc161489 /* Issue USB D1 command to the device here */
23043341Sgc161489 rval = usb_set_device_pwrlvl1(dip);
23053341Sgc161489 ASSERT(rval == USB_SUCCESS);
23063341Sgc161489
23073341Sgc161489 return (USB_FAILURE);
23083341Sgc161489 }
23093341Sgc161489
23103341Sgc161489
23113341Sgc161489 static int
usb_common_pwrlvl3(dev_info_t * dip,uint8_t * pm,int * dev_state)23123528Sgc161489 usb_common_pwrlvl3(dev_info_t *dip, uint8_t *pm, int *dev_state)
23133341Sgc161489 {
23143341Sgc161489 int rval;
23153341Sgc161489
23163341Sgc161489 switch (*dev_state) {
23173341Sgc161489 case USB_DEV_PWRED_DOWN:
23183341Sgc161489 /* Issue USB D0 command to the device here */
23193341Sgc161489 rval = usb_set_device_pwrlvl0(dip);
23203341Sgc161489 ASSERT(rval == USB_SUCCESS);
23213341Sgc161489
23223341Sgc161489 *dev_state = USB_DEV_ONLINE;
23233528Sgc161489 *pm = USB_DEV_OS_FULL_PWR;
23243341Sgc161489
23253341Sgc161489 /* FALLTHRU */
23263341Sgc161489 case USB_DEV_ONLINE:
23273341Sgc161489 /* we are already in full power */
23283341Sgc161489
23293341Sgc161489 /* FALLTHRU */
23303341Sgc161489 case USB_DEV_DISCONNECTED:
23313341Sgc161489 case USB_DEV_SUSPENDED:
23323341Sgc161489 /* allow a disconnected/cpr'ed device to go to low power */
23333341Sgc161489
23343341Sgc161489 return (USB_SUCCESS);
23353341Sgc161489 default:
23363341Sgc161489 USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
23373341Sgc161489 "usb_common_pwrlvl3: Illegal state (%s)",
23383341Sgc161489 usb_str_dev_state(*dev_state));
23393341Sgc161489
23403341Sgc161489 return (USB_FAILURE);
23413341Sgc161489 }
23423341Sgc161489 }
23433341Sgc161489
23443341Sgc161489 /* power management */
23453341Sgc161489 int
usba_common_power(dev_info_t * dip,uint8_t * pm,int * dev_state,int level)23463528Sgc161489 usba_common_power(dev_info_t *dip, uint8_t *pm, int *dev_state, int level)
23473341Sgc161489 {
23483341Sgc161489 int rval = DDI_FAILURE;
23493341Sgc161489
23503341Sgc161489 switch (level) {
23513341Sgc161489 case USB_DEV_OS_PWR_OFF:
23523341Sgc161489 rval = usb_common_pwrlvl0(dip, pm, dev_state);
23533341Sgc161489 break;
23543341Sgc161489 case USB_DEV_OS_PWR_1:
23553341Sgc161489 rval = usb_common_pwrlvl1(dip, pm, dev_state);
23563341Sgc161489 break;
23573341Sgc161489 case USB_DEV_OS_PWR_2:
23583341Sgc161489 rval = usb_common_pwrlvl2(dip, pm, dev_state);
23593341Sgc161489 break;
23603341Sgc161489 case USB_DEV_OS_FULL_PWR:
23613341Sgc161489 rval = usb_common_pwrlvl3(dip, pm, dev_state);
23623341Sgc161489 break;
23633341Sgc161489 }
23643341Sgc161489
23653341Sgc161489 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
23663341Sgc161489 }
23673341Sgc161489
23683341Sgc161489 /*
23693341Sgc161489 * register and unregister for events from our parent for usb_mid and usb_ia
23703341Sgc161489 * and maybe other nexus driver.
23713341Sgc161489 *
23723341Sgc161489 * Note: The cookie fields in usba_device structure is not used. They are
23733341Sgc161489 * used/shared by children.
23743341Sgc161489 */
23753341Sgc161489 void
usba_common_register_events(dev_info_t * dip,uint_t if_num,void (* event_cb)(dev_info_t *,ddi_eventcookie_t,void *,void *))23763341Sgc161489 usba_common_register_events(dev_info_t *dip, uint_t if_num,
23773341Sgc161489 void (*event_cb)(dev_info_t *, ddi_eventcookie_t, void *, void *))
23783341Sgc161489 {
23793341Sgc161489 int rval;
23803341Sgc161489 usba_evdata_t *evdata;
23813341Sgc161489 ddi_eventcookie_t cookie;
23823341Sgc161489
23833341Sgc161489 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
23843341Sgc161489 "usb_common_register_events:");
23853341Sgc161489
23863341Sgc161489 evdata = usba_get_evdata(dip);
23873341Sgc161489
23883341Sgc161489 /* get event cookie, discard level and icookie for now */
23893341Sgc161489 rval = ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT,
23906898Sfb209375 &cookie);
23913341Sgc161489
23923341Sgc161489 if (rval == DDI_SUCCESS) {
23933341Sgc161489 rval = ddi_add_event_handler(dip,
23943341Sgc161489 cookie, event_cb, NULL, &evdata->ev_rm_cb_id);
23953341Sgc161489
23963341Sgc161489 if (rval != DDI_SUCCESS) {
23973341Sgc161489
23983341Sgc161489 goto fail;
23993341Sgc161489 }
24003341Sgc161489 }
24013341Sgc161489 rval = ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT,
24026898Sfb209375 &cookie);
24033341Sgc161489 if (rval == DDI_SUCCESS) {
24043341Sgc161489 rval = ddi_add_event_handler(dip, cookie, event_cb,
24053341Sgc161489 NULL, &evdata->ev_ins_cb_id);
24063341Sgc161489
24073341Sgc161489 if (rval != DDI_SUCCESS) {
24083341Sgc161489
24093341Sgc161489 goto fail;
24103341Sgc161489 }
24113341Sgc161489 }
24123341Sgc161489 rval = ddi_get_eventcookie(dip, USBA_PRE_SUSPEND_EVENT, &cookie);
24133341Sgc161489 if (rval == DDI_SUCCESS) {
24143341Sgc161489 rval = ddi_add_event_handler(dip,
24153341Sgc161489 cookie, event_cb, NULL, &evdata->ev_suspend_cb_id);
24163341Sgc161489
24173341Sgc161489 if (rval != DDI_SUCCESS) {
24183341Sgc161489
24193341Sgc161489 goto fail;
24203341Sgc161489 }
24213341Sgc161489 }
24223341Sgc161489 rval = ddi_get_eventcookie(dip, USBA_POST_RESUME_EVENT, &cookie);
24233341Sgc161489 if (rval == DDI_SUCCESS) {
24243341Sgc161489 rval = ddi_add_event_handler(dip, cookie, event_cb, NULL,
24253341Sgc161489 &evdata->ev_resume_cb_id);
24263341Sgc161489
24273341Sgc161489 if (rval != DDI_SUCCESS) {
24283341Sgc161489
24293341Sgc161489 goto fail;
24303341Sgc161489 }
24313341Sgc161489 }
24323341Sgc161489
24333341Sgc161489 return;
24343341Sgc161489
24353341Sgc161489
24363341Sgc161489 fail:
24373341Sgc161489 usba_common_unregister_events(dip, if_num);
24383341Sgc161489
24393341Sgc161489 }
24403341Sgc161489
24413341Sgc161489 void
usba_common_unregister_events(dev_info_t * dip,uint_t if_num)24423341Sgc161489 usba_common_unregister_events(dev_info_t *dip, uint_t if_num)
24433341Sgc161489 {
24443341Sgc161489 usba_evdata_t *evdata;
24453341Sgc161489 usba_device_t *usba_device = usba_get_usba_device(dip);
24463341Sgc161489 int i;
24473341Sgc161489
24483341Sgc161489 evdata = usba_get_evdata(dip);
24493341Sgc161489
24503341Sgc161489 if (evdata->ev_rm_cb_id != NULL) {
24513341Sgc161489 (void) ddi_remove_event_handler(evdata->ev_rm_cb_id);
24523341Sgc161489 evdata->ev_rm_cb_id = NULL;
24533341Sgc161489 }
24543341Sgc161489
24553341Sgc161489 if (evdata->ev_ins_cb_id != NULL) {
24563341Sgc161489 (void) ddi_remove_event_handler(evdata->ev_ins_cb_id);
24573341Sgc161489 evdata->ev_ins_cb_id = NULL;
24583341Sgc161489 }
24593341Sgc161489
24603341Sgc161489 if (evdata->ev_suspend_cb_id != NULL) {
24613341Sgc161489 (void) ddi_remove_event_handler(evdata->ev_suspend_cb_id);
24623341Sgc161489 evdata->ev_suspend_cb_id = NULL;
24633341Sgc161489 }
24643341Sgc161489
24653341Sgc161489 if (evdata->ev_resume_cb_id != NULL) {
24663341Sgc161489 (void) ddi_remove_event_handler(evdata->ev_resume_cb_id);
24673341Sgc161489 evdata->ev_resume_cb_id = NULL;
24683341Sgc161489 }
24693341Sgc161489
24703341Sgc161489 /* clear event data for children, required for cfgmadm unconfigure */
24713528Sgc161489 mutex_enter(&usba_device->usb_mutex);
24723341Sgc161489 if (usb_owns_device(dip)) {
24733341Sgc161489 usba_free_evdata(usba_device->usb_evdata);
24743341Sgc161489 usba_device->usb_evdata = NULL;
24753341Sgc161489 usba_device->rm_cookie = NULL;
24763341Sgc161489 usba_device->ins_cookie = NULL;
24773341Sgc161489 usba_device->suspend_cookie = NULL;
24783341Sgc161489 usba_device->resume_cookie = NULL;
24793341Sgc161489 } else {
24803341Sgc161489 for (i = 0; i < if_num; i++) {
24813341Sgc161489 usba_device->usb_client_flags[usba_get_ifno(dip) + i]
24826898Sfb209375 &= ~USBA_CLIENT_FLAG_EV_CBS;
24833341Sgc161489 }
24843341Sgc161489 }
24853528Sgc161489 mutex_exit(&usba_device->usb_mutex);
24863341Sgc161489 }
2487