/*
* 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
*/
/*
*/
/*
* EHCI Host Controller Driver (EHCI)
*
* The EHCI driver is a software driver which interfaces to the Universal
* Serial Bus layer (USBA) and the Host Controller (HC). The interface to
* the Host Controller is defined by the EHCI Host Controller Interface.
*
* This module contains the code for root hub related functions.
*
* NOTE:
*
* ONE_XFER is not supported on root hub interrupt polling
*/
/* Static function prototypes */
static int ehci_handle_set_clear_port_feature(
static void ehci_handle_port_power(
static void ehci_handle_port_enable(
static void ehci_handle_clrchng_port_enable(
static void ehci_handle_port_suspend(
static void ehci_handle_clrchng_port_suspend(
static void ehci_handle_port_reset(
static void ehci_root_hub_reset_occured(
static void ehci_handle_complete_port_reset(
static void ehci_handle_clear_port_connection(
static void ehci_handle_clrchng_port_over_current(
static void ehci_handle_get_port_status(
static void ehci_handle_get_hub_descriptor(
static void ehci_handle_get_hub_status(
static void ehci_handle_get_device_status(
static uint_t ehci_get_root_hub_port_status(
static int ehci_is_port_owner(
static int ehci_root_hub_allocate_intr_pipe_resource(
static void ehci_root_hub_intr_pipe_cleanup(
static void ehci_handle_root_hub_status_change(void *arg);
static void ehci_root_hub_hcdi_callback(
/*
* ehci_init_root_hub:
*
* Initialize the root hub
*/
int
{
"ehci_init_root_hub:");
/* Read the EHCI capability register */
/*
* Build the Root hub descriptor by looking EHCI capability
* and operational registers.
*/
"ehci_init_root_hub: Invalid no of root hub ports 0x%x",
return (USB_FAILURE);
}
/* Obtain the number of downstream ports */
if (length) {
} else {
}
/*
* Host Controllers information.
*/
/*
* Determine the Power Switching Mode
*
* EHCI Specification, root hub supports either no power switching
* individual port power switching. Also determine the Over-current
* Protection Mode.
*/
if (capability & EHCI_HCS_PORT_POWER_CONTROL) {
/* Each port is powered individually */
/* Assume individual overcurrent reporting */
/* Each port will start off in the POWERED_OFF mode */
} else {
/* The ports are powered when the ctlr is powered */
/* Assume no overcurrent reporting */
}
/* Look at the port indicator information */
if (capability & EHCI_HCS_PORT_INDICATOR) {
}
/*
* Obtain the power on to power good time of the ports.
*
* Assume: Zero for this field.
*/
/* Indicate if the device is removable */
/* Set PortPowerControlMask to zero */
/* Set the state of each port and initialize the status */
for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
}
return (USB_SUCCESS);
}
/*
* ehci_load_root_hub_driver:
*
* Attach the root hub
*/
0x12, /* bLength */
0x01, /* bDescriptorType, Device */
0x200, /* bcdUSB, v2.0 */
0x09, /* bDeviceClass */
0x00, /* bDeviceSubClass */
0x01, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0 */
0x00, /* idVendor */
0x00, /* idProduct */
0x00, /* bcdDevice */
0x00, /* iManufacturer */
0x00, /* iProduct */
0x00, /* iSerialNumber */
0x01 /* bNumConfigurations */
};
/* One configuartion */
0x09, /* bLength */
0x02, /* bDescriptorType, Configuartion */
0x19, 0x00, /* wTotalLength */
0x01, /* bNumInterfaces */
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
0x40, /* bmAttributes */
0x00, /* MaxPower */
/* One Interface */
0x09, /* bLength */
0x04, /* bDescriptorType, Interface */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x01, /* bNumEndpoints */
0x09, /* bInterfaceClass */
0x01, /* bInterfaceSubClass */
0x00, /* bInterfaceProtocol */
0x00, /* iInterface */
/* One Endpoint (status change endpoint) */
0x07, /* bLength */
0x05, /* bDescriptorType, Endpoint */
0x81, /* bEndpointAddress */
0x03, /* bmAttributes */
0x01, 0x00, /* wMaxPacketSize, 1 + (EHCI_MAX_RH_PORTS / 8) */
0xff /* bInterval */
};
int
{
"ehci_load_root_hub_driver:");
sizeof (ehci_root_hub_config_descriptor),
}
/*
* ehci_unload_root_hub_driver:
*/
int
{
"ehci_unload_root_hub_driver:");
}
/*
* ehci_handle_root_hub_pipe_open:
*
* Handle opening of control and interrupt pipes on root hub.
*/
/* ARGSUSED */
int
{
"ehci_handle_root_hub_pipe_open: Root hub pipe open");
case USB_EP_ATTR_CONTROL:
/* Save control pipe handle */
/* Set state of the root hub control pipe as idle */
"ehci_handle_root_hub_pipe_open: Root hub control "
"pipe open succeeded");
break;
case USB_EP_ATTR_INTR:
/* Save interrupt pipe handle */
/* Set state of the root hub interrupt pipe as idle */
"ehci_handle_root_hub_pipe_open: Root hub interrupt "
"pipe open succeeded");
break;
default:
"ehci_handle_root_hub_pipe_open: Root hub pipe open"
"failed");
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
/*
* ehci_handle_root_hub_pipe_close:
*
* Handle closing of control and interrupt pipes on root hub.
*/
/* ARGSUSED */
int
{
"ehci_handle_root_hub_pipe_close: Root hub pipe close");
case USB_EP_ATTR_CONTROL:
/* Set state of the root hub control pipe as close */
/* Set root hub control pipe handle to null */
"ehci_handle_root_hub_pipe_close: "
"Root hub control pipe close succeeded");
break;
case USB_EP_ATTR_INTR:
/* Set state of the root hub interrupt pipe as close */
/* Do interrupt pipe cleanup */
/* Set root hub interrupt pipe handle to null */
"ehci_handle_root_hub_pipe_close: "
"Root hub interrupt pipe close succeeded");
break;
default:
"ehci_handle_root_hub_pipe_close: "
"Root hub pipe close failed");
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
/*
* ehci_handle_root_hub_pipe_reset:
*
* Handle resetting of control and interrupt pipes on root hub.
*/
/* ARGSUSED */
int
{
"ehci_handle_root_hub_pipe_reset: Root hub pipe reset");
case USB_EP_ATTR_CONTROL:
"ehci_handle_root_hub_pipe_reset: Pipe reset"
"for the root hub control pipe successful");
break;
case USB_EP_ATTR_INTR:
/* Do interrupt pipe cleanup */
}
"ehci_handle_root_hub_pipe_reset: "
"Pipe reset for root hub interrupt pipe successful");
break;
default:
"ehci_handle_root_hub_pipe_reset: "
"Root hub pipe reset failed");
error = USB_FAILURE;
break;
}
return (error);
}
/*
* ehci_handle_root_hub_request:
*
* Intercept a root hub request. Handle the root hub request through the
* registers
*/
/* ARGSUSED */
int
{
"ehci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p",
if (ehcip->ehci_root_hub.
"ehci_handle_root_hub_request: Pipe is not idle");
return (USB_FAILURE);
}
/* Save the current control request pointer */
/* Set pipe state to active */
switch (bmRequestType) {
break;
break;
case HUB_GET_PORT_STATUS_TYPE:
break;
case HUB_CLASS_REQ_TYPE:
switch (bRequest) {
case USB_REQ_GET_STATUS:
break;
case USB_REQ_GET_DESCR:
break;
default:
"ehci_handle_root_hub_request:"
"Unsupported request 0x%x", bRequest);
error = USB_FAILURE;
break;
}
break;
default:
"ehci_handle_root_hub_request: "
"Unsupported request 0x%x", bmRequestType);
error = USB_FAILURE;
break;
}
"ehci_handle_root_hub_request: error = %d", error);
return (USB_SUCCESS);
}
/*
* ehci_handle_set_clear_port_feature:
*/
static int
{
"ehci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x",
switch (bRequest) {
case USB_REQ_SET_FEATURE:
switch (wValue) {
case CFS_PORT_ENABLE:
break;
case CFS_PORT_SUSPEND:
break;
case CFS_PORT_RESET:
break;
case CFS_PORT_POWER:
break;
default:
"ehci_handle_set_clear_port_feature: "
error = USB_FAILURE;
break;
}
break;
case USB_REQ_CLEAR_FEATURE:
switch (wValue) {
case CFS_PORT_ENABLE:
break;
case CFS_C_PORT_ENABLE:
break;
case CFS_PORT_SUSPEND:
break;
case CFS_C_PORT_SUSPEND:
break;
case CFS_C_PORT_RESET:
break;
case CFS_PORT_POWER:
break;
case CFS_C_PORT_CONNECTION:
break;
case CFS_C_PORT_OVER_CURRENT:
break;
default:
"ehci_handle_set_clear_port_feature: "
error = USB_FAILURE;
break;
}
break;
default:
"ehci_handle_set_clear_port_feature: "
error = USB_FAILURE;
break;
}
return (error);
}
/*
* ehci_handle_port_power:
*
* Turn on a root hub port.
*/
static void
{
"ehci_handle_port_power: port = 0x%x status = 0x%x on = %d",
/* Check port is owned by ehci */
return;
}
if (on) {
/* See if the port power is already on */
if (!(port_status & EHCI_RH_PORT_POWER)) {
/* Turn the port on */
}
} else {
/* See if the port power is already OFF */
if (port_status & EHCI_RH_PORT_POWER) {
/* Turn-off the port */
}
}
"ehci_handle_port_power done: port = 0x%x status = 0x%x on = %d",
}
/*
* ehci_handle_port_enable:
*
* Handle port enable request.
*/
static void
{
"ehci_handle_port_enable: port = 0x%x, status = 0x%x",
port, port_status);
/* Check port is owned by ehci */
return;
}
if (on) {
/* See if the port enable is already on */
if (!(port_status & EHCI_RH_PORT_ENABLE)) {
/* Enable the port */
}
} else {
/* See if the port enable is already off */
if (port_status & EHCI_RH_PORT_ENABLE) {
/* Disable the port */
}
}
}
/*
* ehci_handle_clrchng_port_enable:
*
* Handle clear port enable change bit.
*/
static void
{
"ehci_handle_port_enable: port = 0x%x, status = 0x%x",
port, port_status);
/* Check port is owned by ehci */
return;
}
/* Clear the PortEnableStatusChange Bit */
}
/*
* ehci_handle_port_suspend:
*
*/
static void
{
"ehci_handle_port_suspend: port = 0x%x, status = 0x%x",
port, port_status);
/* Check port is owned by ehci */
return;
}
if (on) {
/*
* Suspend port only if port is enabled and
* it is not already in suspend state.
*/
if ((port_status & EHCI_RH_PORT_ENABLE) &&
(!(port_status & EHCI_RH_PORT_SUSPEND))) {
/* Suspend the port */
/* Wait 10ms for port move to suspend state */
return;
}
} else {
/* Perform resume only if port is in suspend state */
if (port_status & EHCI_RH_PORT_SUSPEND) {
/* Resume the port */
}
}
}
/*
* ehci_handle_clrchng_port_suspend:
*
* Handle port clear port suspend change bit.
*/
static void
{
int i;
"ehci_handle_clrchng_port_suspend: port = 0x%x, "
/* Check port is owned by ehci */
return;
}
/* Return if port is not in resume state */
if (!(port_status & EHCI_RH_PORT_RESUME)) {
return;
}
/* Wait for 20ms to terminate resume */
/*
* Wait for port to return to high speed mode. It's necessary to poll
* for resume completion for some high-speed devices to work correctly.
*/
for (i = 0; i < EHCI_PORT_RESUME_RETRY_MAX; i++) {
if (!(port_status & EHCI_RH_PORT_RESUME)) {
break;
}
}
}
/*
* ehci_handle_port_reset:
*
* Perform a port reset.
*/
static void
{
int i;
/* Get the root hub structure */
/* Get the port status information */
"ehci_handle_port_reset: port = 0x%x status = 0x%x",
port, port_status);
/* Check port is owned by ehci */
return;
}
if (port_status & EHCI_RH_PORT_LOW_SPEED) {
/* Check for classic or companion host controllers */
if (rh->rh_companion_controllers) {
"ehci_handle_port_reset: Low speed device "
"and handover this port to Companion controller");
} else {
"Low speed device is not supported");
}
} else {
((port_status | EHCI_RH_PORT_RESET) &
/* Wait 50ms for reset to complete */
(port_status & ~EHCI_RH_PORT_RESET));
/*
* Wait for hardware to enable this port, if the connected
* usb device is high speed. It's necessary to poll for reset
* completion for some high-speed devices to recognized
* correctly.
*/
for (i = 0; i < EHCI_PORT_RESET_RETRY_MAX; i++) {
if (!(port_status & EHCI_RH_PORT_RESET)) {
break;
}
}
/*
* If port is not enabled, connected device is a
* Full-speed usb device.
*/
if (!(port_status & EHCI_RH_PORT_ENABLE)) {
/* Check for classic or companion host controllers */
if (rh->rh_companion_controllers) {
"ehci_handle_port_reset: Full speed device "
"and handover this port to Companion host "
"controller");
} else {
"Full speed device is not supported");
}
} else {
"ehci_handle_port_reset: High speed device ");
/*
* Disable over-current, connect, and disconnect
* wakeup bits.
*/
/*
* The next function is only called if the interrupt
* pipe is polling and the USBA is ready to receive
* the data.
*/
if (ehcip->ehci_root_hub.
}
}
}
}
/*
* ehci_root_hub_reset_occured:
*
* Inform the upper layer that reset has occured on the port. This is
* required because the upper layer is expecting a an evernt immidiately
* after doing reset. In case of OHCI, the controller gets an interrupt
* for the change in the root hub status but in case of EHCI, we dont.
* So, send a event to the upper layer as soon as we complete the reset.
*/
void
{
"ehci_root_hub_reset_occured: curr_intr_reqp = 0x%p data = 0x%p",
/* Get the interrupt pipe handle */
/* Get the pending status */
do {
port_mask >>= 8;
} while (port_mask != 0);
/* Reset pending status */
/* If needed, allocate new interrupt request */
ehcip, 0)) != USB_SUCCESS) {
/* Do interrupt pipe cleanup */
}
}
/*
* ehci_handle_complete_port_reset:
*
* Perform a port reset change.
*/
static void
{
"ehci_handle_complete_port_reset: port = 0x%x status = 0x%x",
port, port_status);
/* Check port is owned by ehci */
return;
}
if (port_status & EHCI_RH_PORT_RESET) {
}
}
/*
* ehci_handle_clear_port_connection:
*
* Perform a clear port connection.
*/
static void
{
"ehci_handle_clear_port_connection: port = 0x%x"
}
/*
* ehci_handle_clrchng_port_over_current:
*
* Perform a clear port connection.
*/
static void
{
"ehci_handle_clrchng_port_over_current: port = 0x%x"
}
/*
* ehci_handle_get_port_status:
*
* Handle a get port status request.
*/
static void
{
/* Get the root hub port status information */
"ehci_handle_get_port_status: port = %d new status = 0x%x"
/* Save the data in control request */
}
/*
* ehci_handle_get_hub_descriptor:
*/
static void
{
"ehci_handle_get_hub_descriptor: Ctrl Req = 0x%p",
(void *)ctrl_reqp);
/* Save the data in control request */
}
/*
* ehci_handle_get_hub_status:
*
* Handle a get hub status request.
*/
static void
{
/*
* For EHCI, there is no overall hub status information.
* Only individual root hub port status information is
* available. So return zero for the root hub status
* request.
*/
new_root_hub_status = 0;
"ehci_handle_get_hub_status: new root hub status = 0x%x",
/* Save the data in control request */
}
/*
* ehci_handle_get_device_status:
*
* Handle a get device status request.
*/
static void
{
/*
* For EHCI, there is no device status information.
* Simply return what is desired for the request.
*/
"ehci_handle_get_device_status: device status = 0x%x",
/* Save the data in control request */
}
/*
* ehci_handle_root_hub_pipe_start_intr_polling:
*
* Handle start polling on root hub interrupt pipe.
*/
/* ARGSUSED */
int
{
"ehci_handle_root_hub_pipe_start_intr_polling: "
"Root hub pipe start polling");
switch (pipe_state) {
case EHCI_PIPE_STATE_IDLE:
/*
* Save the Original Client's Interrupt IN request
* information. We use this for final callback
*/
if (error != USB_SUCCESS) {
/* Reset client interrupt request pointer */
"ehci_handle_root_hub_pipe_start_intr_polling: "
"No Resources");
return (error);
}
/* Check whether we need to send the reset data up */
}
"ehci_handle_root_hub_pipe_start_intr_polling: "
"Start polling for root hub successful");
break;
case EHCI_PIPE_STATE_ACTIVE:
"ehci_handle_root_hub_pipe_start_intr_polling: "
"Polling for root hub is already in progress");
break;
default:
"ehci_handle_root_hub_pipe_start_intr_polling: "
"Pipe is in error state 0x%x", pipe_state);
error = USB_FAILURE;
break;
}
return (error);
}
/*
* ehci_handle_root_hub_pipe_stop_intr_polling:
*
* Handle stop polling on root hub intr pipe.
*/
/* ARGSUSED */
void
{
"ehci_handle_root_hub_pipe_stop_intr_polling: "
"Root hub pipe stop polling");
/* Do interrupt pipe cleanup */
"ehci_hcdi_pipe_stop_intr_polling: Stop polling for root"
"hub successful");
} else {
"Polling for root hub is already stopped");
}
}
/*
* ehci_get_root_hub_port_status:
*
* Construct root hub port status and change information
*/
static uint_t
{
/* Read the current port status */
"ehci_get_root_hub_port_status: port %d "
/*
* EHCI root hub port status and control register information
* format is different what Hub driver wants. So EHCI driver
* needs to contruct the proper root hub port status information.
*
* Send all port status information only if port is owned by EHCI
* host controller.
*/
/* First construct port change information */
if (port_status & EHCI_RH_PORT_ENABLE_CHANGE) {
}
if (port_status & EHCI_RH_PORT_RESUME) {
}
if (port_status & EHCI_RH_PORT_OVER_CURR_CHANGE) {
}
/* Now construct port status information */
if (port_status & EHCI_RH_PORT_CONNECT_STATUS) {
}
if (port_status & EHCI_RH_PORT_ENABLE) {
}
if (port_status & EHCI_RH_PORT_SUSPEND) {
}
if (port_status & EHCI_RH_PORT_OVER_CURR_ACTIVE) {
}
if (port_status & EHCI_RH_PORT_RESET) {
}
if (port_status & EHCI_RH_PORT_INDICATOR) {
}
}
/*
* Send the following port status and change information
* even if port is not owned by EHCI.
*
* Additional port change information.
*/
}
/* Additional port status information */
if (port_status & EHCI_RH_PORT_POWER) {
}
if ((!(port_status & EHCI_RH_PORT_ENABLE)) &&
}
/*
* Construct complete root hub port status and change information.
*/
"ehci_get_root_hub_port_status: port = %d new status = 0x%x "
"change status = 0x%x complete port status 0x%x", port,
return (port_status);
}
/*
* ehci_is_port_owner:
*
* Check whether given port is owned by ehci.
*/
static int
{
/*
* Don't perform anything if port is owned by classis host
* controller and return success.
*/
"ehci_handle_set_clear_port_feature: "
"Port %d is owned by classic host controller", port);
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
/*
* ehci_root_hub_allocate_intr_pipe_resource:
*
* Allocate interrupt requests and initialize them.
*/
static int
{
"ehci_root_hub_allocate_intr_pipe_resource");
/* Get the interrupt pipe handle */
/* Get the current interrupt request pointer */
/*
* If current interrupt request pointer is null,
* allocate new interrupt request.
*/
if (curr_intr_reqp == NULL) {
/* Get the length of interrupt transfer */
if (curr_intr_reqp == NULL) {
"ehci_root_hub_allocate_intr_pipe_resource:"
"Interrupt request structure allocation failed");
return (USB_NO_RESOURCES);
}
ph->p_req_count++;
}
/* Start the timer for the root hub interrupt pipe polling */
}
return (USB_SUCCESS);
}
/*
* ehci_root_hub_intr_pipe_cleanup:
*
* Deallocate all interrupt requests and do callback
* the original client interrupt request.
*/
static void
{
"ehci_root_hub_intr_pipe_cleanup");
/* Get the interrupt pipe handle */
/* Get the interrupt timerid */
/* Stop the root hub interrupt timer */
if (timer_id) {
/* Reset the timer id to zero */
}
/* Reset the current interrupt request pointer */
/* Deallocate uncompleted interrupt request */
if (curr_intr_reqp) {
ph->p_req_count--;
}
/* Callback for original client interrupt request */
if (client_intr_reqp) {
}
}
/*
* ehci_handle_root_hub_status_change:
*
* A root hub status change interrupt will occur any time there is a change
* in the root hub status register or one of the port status registers.
*/
static void
{
int i;
"ehci_handle_root_hub_status_change: state = %d",
#if defined(__x86)
/*
* When ohci are attached in ferrari 4000, SMI will reset ehci
* registers. If ehci registers have been reset, we must re-initialize
* them. During booting, this function will be called 2~3 times. When
* this function is called 16 times, ohci drivers have been attached
* and stop checking the ehci registers.
*/
if (Get_OpReg(ehci_config_flag) == 0) {
"ehci_handle_root_hub_status_change:"
" EHCI have been reset");
/* Reinitialize the controller */
DDI_SUCCESS) {
return;
}
}
}
#endif /* __x86 */
/* Get the current interrupt request pointer */
/* Check whether timeout handler is valid */
/* Check host controller is in operational state */
/* Reset the timer id */
/* Do interrupt pipe cleanup */
return;
}
} else {
return;
}
/* Check each port */
for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
/*
* If there is change in the port status then set the bit in the
* bitmap of changes and inform hub driver about these changes.
* Hub driver will take care of these changes.
*/
if (change_status) {
if (change_status & PORT_CHANGE_CSC) {
/*
* Update the state depending on whether
* the port was attached or detached.
*/
if (new_port_status & PORT_STATUS_CCS) {
rh_port_state[i] = DISABLED;
"Port %d connected", i+1);
} else {
rh_port_state[i] = DISCONNECTED;
"Port %d disconnected", i+1);
}
}
/* See if port enable status changed */
if (change_status & PORT_CHANGE_PESC) {
/*
* Update the state depending on whether
* the port was enabled or disabled.
*/
if (new_port_status & PORT_STATUS_PES) {
rh_port_state[i] = ENABLED;
"Port %d enabled", i+1);
} else {
rh_port_state[i] = DISABLED;
"Port %d disabled", i+1);
}
}
/* Update the status */
}
}
/* Get the message block */
do {
/*
* check that the mblk is big enough when we
* are writing bytes into it
*/
"ehci_handle_root_hub_status_change"
"mblk data overflow.");
break;
}
port_mask >>= 8;
} while (port_mask != 0);
}
/* Reset the timer id */
/*
* If needed, allocate new interrupt request. Also
* start the timer for the root hub interrupt polling.
*/
ehcip, 0)) != USB_SUCCESS) {
"ehci_handle_root_hub_status_change: No Resources");
/* Do interrupt pipe cleanup */
}
}
}
/*
* ehci_root_hub_hcdi_callback()
*
* Convenience wrapper around usba_hcdi_cb() for the root hub.
*/
static void
{
"ehci_root_hub_hcdi_callback: ph = 0x%p, cr = 0x%x",
(void *)ph, completion_reason);
/* Set the pipe state as per completion reason */
switch (completion_reason) {
case USB_CR_OK:
switch (attributes) {
case USB_EP_ATTR_CONTROL:
break;
case USB_EP_ATTR_INTR:
break;
}
break;
case USB_CR_NO_RESOURCES:
case USB_CR_NOT_SUPPORTED:
case USB_CR_STOPPED_POLLING:
case USB_CR_PIPE_RESET:
case USB_CR_HC_HARDWARE_ERR:
/* Set pipe state to idle */
break;
case USB_CR_PIPE_CLOSING:
break;
default:
/* Set pipe state to error */
break;
}
switch (attributes) {
case USB_EP_ATTR_CONTROL:
break;
case USB_EP_ATTR_INTR:
/* if curr_intr_reqp available then use this request */
} else {
/* no current request, use client's request */
}
break;
}
}