usbai_util.c revision 036aa26189b72905886e39d76d63352185cfd9d2
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* USBA: Solaris USB Architecture support
*
* Utility functions
*/
#define USBA_FRAMEWORK
extern void usba_free_evdata(usba_evdata_t *);
/* local functions */
/*
* Wrapper functions returning parsed standard descriptors without
* getting the config cloud first but by just providing the dip.
*
* The client can easily retrieve the device and config descriptor from
* the usb registration and no separate functions are provided
*
* These functions return failure if the full descriptor can not be
* retrieved. These functions will not access the device.
* The caller must allocate the buffer.
*/
/*
* usb_get_if_descr:
* Function to get the cooked interface descriptor
* This function will not access the device.
*
* Arguments:
* dip - pointer to devinfo of the client
* if_index - interface index
* alt_setting - alt interface setting
* descr - pointer to user allocated interface descr
*
* Return Values:
* USB_SUCCESS - descriptor is valid
* USB_FAILURE - full descriptor could not be retrieved
* USB_* - refer to usbai.h
*/
int
{
"usb_get_if_descr: %s, index=0x%x, alt#=0x%x",
return (USB_INVALID_ARGS);
}
if_index, /* interface index */
alt_setting, /* alt interface index */
if (size != USB_IF_DESCR_SIZE) {
"parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
/*
* usb_get_ep_descr:
* Function to get the cooked endpoint descriptor
* This function will not access the device.
*
* Arguments:
* dip - pointer to devinfo of the client
* if_index - interface index
* alt_setting - alternate interface setting
* endpoint_index - endpoint index
* descr - pointer to user allocated interface descr
*
* Return Values:
* USB_SUCCESS - descriptor is valid
* USB_FAILURE - full descriptor could not be retrieved
* USB_* - refer to usbai.h
*/
int
{
"usb_get_ep_descr: %s, index=0x%x, alt#=0x%x",
return (USB_INVALID_ARGS);
}
if_index, /* interface index */
alt_setting, /* alt interface index */
endpoint_index, /* ep index */
if (size != USB_EP_DESCR_SIZE) {
"parsing endpoint: size (%lu) != USB_EP_DESCR_SIZE (%d)",
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
/*
* usb_lookup_ep_data:
* usb_get_ep_data (deprecated):
* Function to get specific endpoint descriptor data
* This function will not access the device.
*
* Arguments:
* dip - pointer to dev info
* usb_client_dev_data_t - pointer to registration data
* interface - requested interface
* alternate - requested alternate
* skip - how many to skip
* type - endpoint type
* direction - endpoint direction or USB_DIR_DONT_CARE
*
* Return Values:
* NULL or an endpoint descriptor pointer
*/
{
int i;
"usb_lookup_ep_data: "
"if=%d alt=%d skip=%d type=%d dir=%d",
return (NULL);
}
for (i = 0; i < altif_data->altif_n_ep; i++) {
continue;
}
if (skip-- == 0) {
"usb_get_ep_data: data=0x%p",
&altif_data->altif_ep[i]);
return (&altif_data->altif_ep[i]);
}
}
}
"usb_get_ep_data: returning NULL");
return (NULL);
}
/*ARGSUSED*/
{
}
/*
* usb_get_string_descr:
* Function to read the string descriptor
* This function will access the device and block.
*
* Arguments:
* dip - pointer to devinfo of the client
* langid - LANGID to read different LOCALEs
* index - index to the string
* buf - user provided buffer for string descriptor
* buflen - user provided length of the buffer
*
* Return Values:
* USB_SUCCESS - descriptor is valid
* USB_FAILURE - full descriptor could not be retrieved
* USB_* - refer to usbai.h
*/
int
char *buf,
{
int rval;
"usb_get_string_descr: %s, langid=0x%x index=0x%x",
return (USB_INVALID_ARGS);
}
/*
* determine the length of the descriptor
*/
4,
if (rval != USB_SUCCESS) {
goto done;
}
"0 bytes received");
goto done;
}
/*
* if length is zero the next control request may fail.
* the HCD may not support a zero length control request
* and return an mblk_t which is NULL along with rval
* being USB_SUCCESS and "cr" being USB_CR_OK
*/
if (length < 2) {
rval = USB_FAILURE;
goto done;
}
"failed to get string descriptor (rval=%d cr=%d)",
goto done;
}
buflen);
} else {
rval = USB_FAILURE;
}
done:
return (rval);
}
/*
* usb_get_dev_descr:
* utility function to get device descriptor from usba_device
*
* Arguments:
* dip - pointer to devinfo of the client
*
* Return Values:
* usb_dev_descr - device descriptor or NULL
*/
{
if (dip) {
}
return (usb_dev_descr);
}
/*
* usb_get_raw_cfg_data:
* utility function to get raw config descriptor from usba_device
*
* Arguments:
* dip - pointer to devinfo of the client
* length - pointer to copy the cfg length
*
* Return Values:
* usb_cfg - raw config descriptor
*/
uchar_t *
{
return (NULL);
}
return (usb_cfg);
}
/*
* usb_get_addr:
* utility function to return current usb address, mostly
* for debugging purposes
*
* Arguments:
* dip - pointer to devinfo of the client
*
* Return Values:
* address - USB Device Address
*/
int
{
int address = 0;
if (dip) {
}
return (address);
}
/*
* usb_set_cfg():
* set configuration, use with caution (issues USB_REQ_SET_CONFIG)
* Changing configuration will fail if pipes are still open or when
* invoked from a driver bound to an interface on a composite device.
*
* This function will access the device and block
*
* Arguments:
* dip - pointer to devinfo of the client
* cfg_index - config index
* cfg_value - config value to be set
* flags - USB_FLAGS_SLEEP:
* wait for completion
* cb - if USB_FLAGS_SLEEP has not been specified
* this callback function will be called on
* completion. This callback may be NULL
* and no notification of completion will then
* be provided.
* cb_arg - 2nd argument to callback function.
*
* Return Values:
* USB_SUCCESS: - new configuration was set
* USB_FAILURE: - new configuration could not be set
* USB_BUSY: - some pipes were open or there were children
* USB_* - refer to usbai.h
*/
int
void (*cb)(
int rval,
{
"usb_set_cfg: %s%d, cfg_index = 0x%x, uf = 0x%x",
return (USB_INVALID_ARGS);
}
return (USB_INVALID_CONTEXT);
}
if (!usb_owns_device(dip)) {
return (USB_INVALID_PERM);
}
return (USB_INVALID_PIPE);
}
return (usba_pipe_setup_func_call(dip,
}
static int
{
int rval;
int i, ph_open_cnt;
/*
* default pipe is still open
* all other pipes should be closed
*/
ph_open_cnt++;
break;
}
}
return (USB_BUSY);
}
/*
* check if the configuration meets the
* power budget requirement
*/
if (usba_is_root_hub(dip)) {
/*
* root hub should never be multi-configured.
* the code is here just to ensure
*/
return (USB_FAILURE);
}
/*
* increase the power budget value back to the unconfigured
* state to eliminate the influence of the old configuration
* before checking the new configuration; but remember to
* make a decrement before leaving this routine to restore
* the power consumption state of the device no matter it
* is in the new or old configuration
*/
cfg_index)) != USB_SUCCESS) {
return (USB_FAILURE);
}
/* hubdi should ensure that this descriptor is correct */
/* set the configuration */
0,
0,
NULL, 0,
if (rval == USB_SUCCESS) {
/* update the configuration property */
}
/*
* usba_device->usb_cfg always stores current configuration
* descriptor no matter SET_CFG request succeeded or not,
* so usba_hubdi_decr_power_budget can be done regardless
* of rval above
*/
return (rval);
}
/*
* usb_get_cfg():
* get configuration value
*
* Arguments:
* dip - pointer to devinfo of the client
* cfg_value - current config value
* flags - none, always blocks
*
* Return Values:
* USB_SUCCESS: - config value was retrieved
* USB_FAILURE: - config value could not be retrieved
* USB_* - refer to usbai.h
*/
int
{
int rval;
return (USB_INVALID_ARGS);
}
/*
* get the cfg value
*/
0,
0,
1, /* returns one byte of data */
&data, 0,
} else {
*cfgval = 1;
if (rval == USB_SUCCESS) {
rval = USB_FAILURE;
}
}
return (rval);
}
/*
* usb_get_current_cfgidx:
* get current current config index
*/
{
return (ndx);
}
/*
* usb_get_if_number:
* get usb interface number of current OS device node.
*
* Arguments:
* dip - pointer to devinfo of the client
*
* Return Values:
* USB_COMBINED_NODE if the driver is responsible for the entire
* device and this dip doesn't correspond to a device node.
* USB_DEVICE_NODE if the driver is responsible for the entire device
* and this dip corresponds to a device node.
* interface number: otherwise.
*/
int
{
int interface_num;
"usb_get_if_number: dip = 0x%p", dip);
/* not quite right but we can't return a negative return value */
return (0);
}
if (usba_device) {
} else {
return (0);
}
if (interface_num == USB_COMBINED_NODE) {
(usb_dev_descr->bDeviceClass == 0)) &&
}
}
return (interface_num);
}
{
}
/* check whether the interface is in this interface association */
{
}
{
return (interface_num < 0 ? 0 : interface_num);
}
/*
* usb_set_alt_if:
* set the alternate interface number. Issues USB_REQ_SET_IF
* This function will access the device
*
* Arguments:
* dip - pointer to devinfo of the client
* if_number - interface number
* alt_number - alternate interface number
* flags - USB_FLAGS_SLEEP:
* wait for completion
* cb - if USB_FLAGS_SLEEP has not been specified
* this callback function will be called on
* completion. This callback may be NULL
* and no notification of completion will then
* be provided.
* cb_arg - 2nd argument to callback function.
*
*
* return values:
* USB_SUCCESS - alternate was set
* USB_FAILURE - alternate could not be set because pipes
* were still open or some access error occurred
* USB_* - refer to usbai.h
*
* Note:
* we can't easily check if all pipes to endpoints for this interface
* are closed since we don't have a map of which endpoints belong
* to which interface. If we had this map, we would need to update
* this on each alternative or configuration switch
*/
int
void (*cb)(
int rval,
{
"usb_set_alt_if: %s%d, if = %d alt = %d, uf = 0x%x",
return (USB_INVALID_ARGS);
}
return (USB_INVALID_CONTEXT);
}
return (USB_INVALID_PIPE);
}
return (usba_pipe_setup_func_call(dip,
}
static int
{
int rval;
"usb_set_alt_if: %s, interface#=0x%x, alt#=0x%x, "
alt_number, flags);
/* if we don't own the device, we must own the interface or ia */
return (USB_INVALID_PERM);
}
/* set the alternate setting */
0,
NULL, 0,
return (rval);
}
/*
* usb_get_alt_if:
* get the alternate interface number. Issues USB_REQ_GET_IF
* This function will access the device and block
*
* Arguments:
* dip - pointer to devinfo of the client
* if_number - interface number
* alt_number - alternate interface number
* flags - none but USB_FLAGS_SLEEP may be passed
*
* return values:
* USB_SUCCESS: alternate was set
* USB_FAILURE: alternate could not be set because pipes
* were still open or some access error occurred
*/
int
{
int rval;
"usb_get_alt_if: %s, interface# = 0x%x, altp = 0x%p, "
alt_number, flags);
return (USB_INVALID_ARGS);
}
/*
* get the alternate setting
*/
0,
1, /* returns one byte of data */
&data, 0,
} else {
*alt_number = 0;
if (rval == USB_SUCCESS) {
rval = USB_FAILURE;
}
}
return (rval);
}
/*
* usba_get_cfg_cloud:
* Get descriptor cloud for a given configuration.
*
* Arguments:
* dip - pointer to devinfo of the client
* default_ph - default pipe handle
* cfg - which configuration to retrieve raw cloud of
*
* Returns:
* on success: mblock containing the raw data. Caller must free.
* on failure: NULL
*/
static mblk_t *
{
0,
&pdata,
0,
&cb_flags,
0) != USB_SUCCESS) {
return (NULL);
}
0,
&pdata,
0,
&cb_flags,
0) != USB_SUCCESS) {
return (NULL);
}
return (pdata);
}
/*
* usb_check_same_device:
* Check if the device connected to the port is the same as
* the previous device that was in the port. The previous device is
* represented by the dip on record for the port. Print a message
* if the device is different. If device_string arg is not NULL, it is
* included in the message. Can block.
*
* Arguments:
* dip - pointer to devinfo of the client
* log_handle - handle to which messages are logged
* log_level - one of USB_LOG_*
* log_mask - logging mask
* check_mask - one mask containing things to check:
* USB_CHK_BASIC: empty mask;
* these checks are always done.
* USB_CHK_VIDPID:
* check vid, pid only.
* USB_CHK_SERIAL: check match on device
* serial number.
* USB_CHK_CFG: check all raw config
* clouds for a match.
* NOTE: descr length and content always checked
* device_string - Device string to appear in error message
*
* return values:
* USB_SUCCESS: same device
* USB_INVALID_VERSION not same device
* USB_FAILURE: Failure processing request
* USB_INVALID_ARG: dip is invalid
*/
int
{
int rval;
char *buf;
return (USB_INVALID_ARGS);
}
/* get the "new" device descriptor */
USB_REQ_GET_DESCR, /* bRequest */
USB_DESCR_TYPE_SETUP_DEV, /* wValue */
0, /* wIndex */
length, /* wLength */
&pdata, 0,
if (rval != USB_SUCCESS) {
"getting device descriptor failed (%d)", rval);
return (USB_FAILURE);
}
}
sizeof (usb_dev_descr_t));
/* Always check the device descriptor length. */
}
(char *)&usb_dev_descr, length) != 0) {
}
/* if requested & this device has a serial number check and compare */
USB_MAXSTRINGLEN) == USB_SUCCESS) {
match =
}
}
"Could not retrieve config cloud for "
"comparison");
break;
}
break;
}
}
}
}
if (allocated_here) {
}
if (device_string[0] != '\0') {
"Cannot access %s. Please reconnect.",
} else {
"Device is not identical to the "
"previous one this port.\n"
"Please disconnect and reconnect");
}
if (allocated_here) {
}
return (USB_INVALID_VERSION);
}
return (USB_SUCCESS);
}
/*
* usb_pipe_get_state:
* Return the state of the pipe
*
* Arguments:
* pipe_handle - pipe_handle pointer
* pipe_state - pointer to copy pipe state to
* flags:
* not used other than to check context
*
* Return Values:
* USB_SUCCESS - port state returned
* USB_* - refer to usbai.h
*/
int
{
if (pipe_state == NULL) {
if (ph_data) {
}
return (USB_INVALID_ARGS);
}
return (USB_SUCCESS);
}
return (USB_SUCCESS);
}
/*
* usba_pipe_get_policy:
* Return a pipe's policy
*
* Arguments:
* pipe_handle - pipe_handle pointer
*
* Return Values:
* On success: the pipe's policy
* On failure: NULL
*/
{
if (ph_data) {
}
return (pp);
}
/*
* usb_ep_num:
* Return the endpoint number for a given pipe handle
*
* Arguments:
* pipe_handle - pipe_handle pointer
*
* Return Values:
* endpoint number
*/
int
{
int ep_num;
return (USB_INVALID_PIPE);
}
return (ep_num);
}
/*
* usb_get_status
* and report in "status" arg.
*
* status reported for a "device" is
* RemoteWakeup enabled
* SelfPowered device?
*
* status reported for an "interface" is NONE.
* status reported for an "endpoint" is
* HALT set (device STALLED?)
*
* Arguments:
* dip - pointer to devinfo of the client
* ph - pipe handle
* type - bmRequestType to be used
* what - 0 for device, otherwise interface or ep number
* status - user supplied pointer for storing the status
* flags - USB_FLAGS_SLEEP (mandatory)
*
* Return Values:
* valid usb_status_t or USB_FAILURE
*/
int
{
int rval;
"usb_get_status: type = 0x%x, what = 0x%x, uf = 0x%x",
return (USB_INVALID_ARGS);
}
return (USB_INVALID_PIPE);
}
/* get the status */
type,
0,
what,
USB_GET_STATUS_LEN, /* status is fixed 2 bytes long */
&data, 0,
} else {
*status = 0;
if (rval == USB_SUCCESS) {
rval = USB_FAILURE;
}
}
return (rval);
}
/*
* usb_clear_feature:
*
* Arguments:
* dip - pointer to devinfo of the client
* ph - pipe handle pointer
* type - bmRequestType to be used
* feature - feature to be cleared
* what - 0 for device, otherwise interface or ep number
* flags - none (but will sleep)
*
* Return Values:
* USB_SUCCESS - on doing a successful clear feature
* USB_FAILURE - on failure
* USB_* - refer to usbai.h
*/
int
{
int rval;
"usb_clear_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
return (USB_INVALID_ARGS);
}
return (USB_INVALID_PIPE);
}
/* issue Clear feature */
type,
what,
0,
NULL, 0,
return (rval);
}
/*
* usb_clr_feature:
*
* Arguments:
* dip - pointer to devinfo of the client
* type - bmRequestType to be used
* feature - feature to be cleared
* what - 0 for device, otherwise interface or ep number
* flags - USB_FLAGS_SLEEP:
* wait for completion
* cb - if USB_FLAGS_SLEEP has not been specified
* this callback function will be called on
* completion. This callback may be NULL
* and no notification of completion will then
* be provided.
* cb_arg - 2nd argument to callback function.
*
*
* Return Values:
* USB_SUCCESS - on doing a successful clear feature
* USB_FAILURE - on failure
* USB_* - refer to usbai.h
*/
int
void (*cb)(
int rval,
{
"usb_clr_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
return (USB_INVALID_ARGS);
}
return (USB_INVALID_CONTEXT);
}
return (USB_INVALID_PIPE);
}
return (usba_pipe_setup_func_call(dip,
}
static int
{
int rval;
"usb_sync_clear_feature: "
"dip=0x%p ph=0x%p type=0x%x feature=0x%x what=0x%x fl=0x%x",
return (rval);
}
/*
* usb_async_req:
* function used to dispatch a request to the taskq
*
* Arguments:
* dip - pointer to devinfo node
* func - pointer to function issued by taskq
* flag - USB_FLAGS_SLEEP mostly
*
* Return Values:
* USB_SUCCESS - on doing a successful taskq invocation
* USB_FAILURE - on failure
* USB_* - refer to usbai.h
*/
int
void (*func)(void *),
void *arg,
{
int tq_flag;
"usb_async_req: dip=0x%p func=0x%p, arg=0x%p flag=0x%x",
return (USB_INVALID_ARGS);
}
if (flag & USB_FLAGS_NOQUEUE) {
tq_flag |= TQ_NOQUEUE;
}
tq_flag)) {
"usb_async_req: failure");
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
/*
* usba_async_ph_req:
* function used to dispatch a request to the ph taskq
*
* Arguments:
* ph_data - pointer to pipe handle data
* func - pointer to function issued by taskq
* flag - USB_FLAGS_SLEEP or USB_FLAGS_NOSLEEP
*
* Return Values:
* USB_SUCCESS - on doing a successful taskq invocation
* USB_FAILURE - on failure
* USB_* - refer to usbai.h
*
* Note:
* If the caller specified USB_FLAGS_NOSLEEP, it must be
* capable of reliably recovering from a failure return
*/
int
void (*func)(void *),
void *arg,
{
int tq_flag;
"usba_async_ph_req: ph_data=0x%p func=0x%p, arg=0x%p flag=0x%x",
return (USB_INVALID_ARGS);
}
} else {
tq_flag |= TQ_NOQUEUE;
}
"usba_async_ph_req: failure");
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
/*
* utility functions to display CR, CB, return values
*/
typedef struct conv_table {
int what;
const char *name;
} conv_table_t;
static const char *
{
int i;
return (conv_table[i].name);
}
}
return ("unknown");
}
static conv_table_t cr_table[] = {
{ USB_CR_OK, "<no errors detected>" },
{ USB_CR_CRC, "<crc error detected>" },
{ USB_CR_BITSTUFFING, "<Bit stuffing violation>" },
{ USB_CR_DATA_TOGGLE_MM, "<Data toggle PID did not match>" },
{ USB_CR_STALL, "<Endpoint returned stall PID>" },
{ USB_CR_DEV_NOT_RESP, "<Device not responding>" },
{ USB_CR_PID_CHECKFAILURE, "<Check bits on PID failed>" },
{ USB_CR_UNEXP_PID, "<Receive PID was not valid>" },
{ USB_CR_DATA_OVERRUN, "<Data size exceeded>" },
{ USB_CR_DATA_UNDERRUN, "<Less data recieved than requested>" },
{ USB_CR_BUFFER_OVERRUN, "<Memory write can't keep up>" },
{ USB_CR_BUFFER_UNDERRUN, "<Buffer underrun>" },
{ USB_CR_TIMEOUT, "<Command timed out>" },
{ USB_CR_NOT_ACCESSED, "<Not accessed by hardware>" },
{ USB_CR_NO_RESOURCES, "<No resources>" },
{ USB_CR_UNSPECIFIED_ERR, "<Unspecified usba or hcd error>" },
{ USB_CR_STOPPED_POLLING, "<Intr/ISOC IN polling stopped>" },
{ USB_CR_PIPE_CLOSING, "<Intr/ISOC IN pipe being closed>" },
{ USB_CR_PIPE_RESET, "<Intr/ISOC IN pipe reset>" },
{ USB_CR_NOT_SUPPORTED, "<Command not supported>" },
{ USB_CR_FLUSHED, "<Req was flushed>" },
{ USB_CR_HC_HARDWARE_ERR, "<USB host controller error>" },
{ 0, NULL }
};
const char *
{
}
static conv_table_t cb_flags_table[] = {
{ USB_CB_NO_INFO, "<callback processed>" },
{ USB_CB_STALL_CLEARED, "<stall cleared>" },
{ USB_CB_FUNCTIONAL_STALL, "<functional stall>" },
{ USB_CB_PROTOCOL_STALL, "<protocol stall>" },
{ USB_CB_RESET_PIPE, "<pipe reset>" },
{ USB_CB_ASYNC_REQ_FAILED, "<thread could not be started>" },
{ USB_CB_NO_RESOURCES, "<no resources>" },
{ USB_CB_SUBMIT_FAILED, "<submit failed>" },
{ USB_CB_INTR_CONTEXT, "<Callback executing in interrupt context>" },
{ 0, NULL }
};
/*ARGSUSED*/
char *
{
int i;
buffer[0] = '\0';
if (cb_flags == USB_CB_NO_INFO) {
} else {
cb_flags_table[0].name,
}
}
}
return (buffer);
}
static conv_table_t pipe_state_table[] = {
{ USB_PIPE_STATE_CLOSED, "<closed>" },
{ USB_PIPE_STATE_IDLE, "<idle>" },
{ USB_PIPE_STATE_ACTIVE, "<active>" },
{ USB_PIPE_STATE_ERROR, "<error>" },
{ USB_PIPE_STATE_CLOSING, "<closing>" },
{ 0, NULL }
};
const char *
{
}
static conv_table_t dev_state[] = {
{ USB_DEV_ONLINE, "<online>" },
{ USB_DEV_DISCONNECTED, "<disconnected>" },
{ USB_DEV_SUSPENDED, "<suspended>" },
{ USB_DEV_PWRED_DOWN, "<powered down>" },
{ 0, NULL }
};
const char *
usb_str_dev_state(int state)
{
}
static conv_table_t rval_table[] = {
{ USB_SUCCESS, "<success>" },
{ USB_FAILURE, "<failure>" },
{ USB_NO_RESOURCES, "<no resources>" },
{ USB_NO_BANDWIDTH, "<no bandwidth>" },
{ USB_NOT_SUPPORTED, "<not supported>" },
{ USB_PIPE_ERROR, "<pipe error>" },
{ USB_INVALID_PIPE, "<invalid pipe>" },
{ USB_NO_FRAME_NUMBER, "<no frame number>" },
{ USB_INVALID_START_FRAME, "<invalid frame>" },
{ USB_HC_HARDWARE_ERROR, "<hw error>" },
{ USB_INVALID_REQUEST, "<invalid request>" },
{ USB_INVALID_CONTEXT, "<invalid context>" },
{ USB_INVALID_VERSION, "<invalid version>" },
{ USB_INVALID_ARGS, "<invalid args>" },
{ USB_INVALID_PERM, "<invalid perms>" },
{ USB_BUSY, "<busy>" },
{ 0, NULL }
};
const char *
usb_str_rval(int rval)
{
}
/*
* function to convert USB return values to close errno
*/
static struct usb_rval2errno_entry {
int rval;
int Errno;
} usb_rval2errno_table[] = {
{ USB_SUCCESS, 0 },
{ USB_FAILURE, EIO },
{ USB_NO_RESOURCES, ENOMEM },
{ USB_NO_BANDWIDTH, EAGAIN },
{ USB_NOT_SUPPORTED, ENOTSUP },
{ USB_PIPE_ERROR, EIO },
{ USB_INVALID_PIPE, EINVAL },
{ USB_NO_FRAME_NUMBER, EINVAL },
{ USB_HC_HARDWARE_ERROR, EIO },
{ USB_INVALID_REQUEST, EINVAL },
{ USB_INVALID_CONTEXT, EINVAL },
{ USB_INVALID_VERSION, EINVAL },
{ USB_INVALID_ARGS, EINVAL },
{ USB_INVALID_PERM, EACCES },
};
#define USB_RVAL2ERRNO_TABLE_SIZE (sizeof (usb_rval2errno_table) / \
sizeof (struct usb_rval2errno_entry))
int
usb_rval2errno(int rval)
{
int i;
for (i = 0; i < USB_RVAL2ERRNO_TABLE_SIZE; i++) {
return (usb_rval2errno_table[i].Errno);
}
}
return (EIO);
}
/*
* serialization
*/
{
sizeof (usba_serialization_impl_t), KM_SLEEP);
if (dip) {
}
return ((usb_serialization_t)impl_tokenp);
}
void
{
if (tokenp) {
}
}
/*
* usb_serialize_access() permits single threaded access.
*
* If tokenp is initialized with USB_INIT_SER_CHECK_SAME_THREAD,
* it is reentrant with respect to thread. The thread must
* hold and release the same number of times.
*
* If tokenp is initialized without USB_INIT_SER_CHECK_SAME_THREAD,
* it is not reentrant by the same thread. It is something like
* a semaphore.
*/
int
{
/*
* Convert delta timeout in ms to absolute timeout in ticks, if used.
*/
if ((how_to_wait == USB_TIMEDWAIT) ||
(how_to_wait == USB_TIMEDWAIT_SIG)) {
/* Convert timeout arg (in ms) to hz */
abs_timeout = ddi_get_lbolt() +
}
/* Get mutex after calc abs time, to count time waiting for mutex. */
"usb_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p, "
"flg=0x%x, abs_tmo=0x%lx",
/*
* There are three ways to break out of the loop:
* 1) Condition met (s_count == 0) - higher prio test
* 2) kill(2) signal received (rval == 0)
* 3) timeout occurred (rval == -1)
* If condition met, whether or not signal or timeout occurred
* take access. If condition not met, check other exit means.
*/
while (impl_tokenp->s_count != 0) {
/* cv_timedwait* returns -1 on timeout. */
/* cv_wait*_sig returns 0 on (kill(2)) signal. */
if (rval <= 0) {
"usb_serialize_access: "
"tok=0x%p exit due to %s", impl_tokenp,
return (rval);
}
switch (how_to_wait) {
default:
/* FALLTHROUGH */
case USB_WAIT:
&impl_tokenp->s_mutex);
break;
case USB_WAIT_SIG:
&impl_tokenp->s_mutex);
break;
case USB_TIMEDWAIT:
break;
case USB_TIMEDWAIT_SIG:
break;
}
}
}
impl_tokenp->s_count++;
"usb_serialize_access exit: tok=0x%p thr=0x%p", impl_tokenp,
return (1);
}
/*ARGSUSED*/
int
{
"usb_try_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p",
/*
* If lock is not taken (s_count is 0), take it.
* If lock is already taken, the thread is owner and lock
* is reentrant, take it.
* Otherwise, fail the access.
*/
impl_tokenp->s_count++;
"usb_try_serialize_access success: tok=0x%p", impl_tokenp);
return (USB_SUCCESS);
}
"usb_try_serialize_access failed: "
"tok=0x%p dip=0x%p cnt=%d thr=0x%p",
return (USB_FAILURE);
}
void
{
"usb_release_access: tok=0x%p dip=0x%p count=%d thr=0x%p",
"usb_release_access: release from wrong thread");
}
}
if (--impl_tokenp->s_count == 0) {
}
}
/*
* usb_fail_checkpoint:
*/
/*ARGSUSED*/
void
{
}
/*
* usba_mk_mctl:
* create a USB style M_CTL message, given an iocblk and a buffer
* returns mblk_t * on success, NULL on failure
*/
mblk_t *
{
} else {
}
}
}
return (bp1);
}
#ifdef ALLOCB_TEST
mblk_t *
{
if (ddi_get_lbolt() & 0x1) {
return (NULL);
} else {
}
}
#endif
/*
* usb common power management for usb_mid, usb_ia and maybe other simple
* drivers.
*/
/*
* functions to handle power transition for OS levels 0 -> 3
*/
static int
{
int rval;
switch (*dev_state) {
case USB_DEV_ONLINE:
/* Issue USB D3 command to the device here */
*pm = USB_DEV_OS_PWR_OFF;
/* FALLTHRU */
case USB_DEV_DISCONNECTED:
case USB_DEV_SUSPENDED:
/* allow a disconnected/cpr'ed device to go to low pwr */
return (USB_SUCCESS);
case USB_DEV_PWRED_DOWN:
default:
return (USB_FAILURE);
}
}
/* ARGSUSED */
static int
{
int rval;
/* Issue USB D2 command to the device here */
return (USB_FAILURE);
}
/* ARGSUSED */
static int
{
int rval;
/* Issue USB D1 command to the device here */
return (USB_FAILURE);
}
static int
{
int rval;
switch (*dev_state) {
case USB_DEV_PWRED_DOWN:
/* Issue USB D0 command to the device here */
/* FALLTHRU */
case USB_DEV_ONLINE:
/* we are already in full power */
/* FALLTHRU */
case USB_DEV_DISCONNECTED:
case USB_DEV_SUSPENDED:
/* allow a disconnected/cpr'ed device to go to low power */
return (USB_SUCCESS);
default:
"usb_common_pwrlvl3: Illegal state (%s)",
return (USB_FAILURE);
}
}
/* power management */
int
{
int rval = DDI_FAILURE;
switch (level) {
case USB_DEV_OS_PWR_OFF:
break;
case USB_DEV_OS_PWR_1:
break;
case USB_DEV_OS_PWR_2:
break;
case USB_DEV_OS_FULL_PWR:
break;
}
}
/*
* register and unregister for events from our parent for usb_mid and usb_ia
* and maybe other nexus driver.
*
* Note: The cookie fields in usba_device structure is not used. They are
*/
void
{
int rval;
"usb_common_register_events:");
/* get event cookie, discard level and icookie for now */
&cookie);
if (rval == DDI_SUCCESS) {
if (rval != DDI_SUCCESS) {
goto fail;
}
}
&cookie);
if (rval == DDI_SUCCESS) {
if (rval != DDI_SUCCESS) {
goto fail;
}
}
if (rval == DDI_SUCCESS) {
if (rval != DDI_SUCCESS) {
goto fail;
}
}
if (rval == DDI_SUCCESS) {
if (rval != DDI_SUCCESS) {
goto fail;
}
}
return;
fail:
}
void
{
int i;
}
}
}
}
/* clear event data for children, required for cfgmadm unconfigure */
if (usb_owns_device(dip)) {
} else {
for (i = 0; i < if_num; i++) {
}
}
}