#include <sys/usb/hcd/uhci/uhcid.h>
#include <sys/usb/hcd/uhci/uhci.h>
#include <sys/usb/hcd/uhci/uhcihub.h>
static int uhci_handle_set_clear_port_feature(
uhci_state_t *uhcip,
uchar_t bRequest,
uint16_t wValue,
usb_port_t port);
static void uhci_handle_port_power(
uhci_state_t *uhcip,
usb_port_t port,
uint_t on);
static void uhci_handle_port_suspend(
uhci_state_t *uhcip,
usb_port_t port,
uint_t on);
static void uhci_handle_port_enable_disable(
uhci_state_t *uhcip,
usb_port_t port,
uint_t on);
static void uhci_handle_port_reset(
uhci_state_t *uhcip,
usb_port_t port);
static void uhci_handle_complete_port_reset(
uhci_state_t *uhcip,
usb_port_t port);
static void uhci_handle_clear_port_connection(
uhci_state_t *uhcip,
usb_port_t port);
static void uhci_handle_get_port_status(
uhci_state_t *uhcip,
usb_ctrl_req_t *req,
usb_port_t port);
static void uhci_handle_get_hub_descriptor(
uhci_state_t *uhcip,
usb_ctrl_req_t *req);
static void uhci_handle_get_hub_status(
uhci_state_t *uhcip,
usb_ctrl_req_t *req);
static void uhci_handle_get_device_status(
uhci_state_t *uhcip,
usb_ctrl_req_t *req);
static uint_t uhci_get_port_status(
uhci_state_t *uhcip,
usb_port_t port);
static void uhci_rh_hcdi_callback(
uhci_state_t *uhcip,
usba_pipe_handle_data_t *ph,
usb_opaque_t req,
usb_cr_t cr);
static usb_dev_descr_t uhci_rh_dev_descr = {
0x12,
1,
0x110,
9,
0,
0,
8,
0,
0,
0,
0,
0,
0,
1
};
static uchar_t uhci_rh_config_descr[] = {
0x09,
0x02,
0x19, 0x00,
0x01,
0x01,
0x00,
0x40,
0x00,
0x09,
0x04,
0x00,
0x00,
0x01,
0x09,
0x01,
0x00,
0x00,
0x07,
0x05,
0x81,
0x03,
0x01, 0x00,
0x20
};
int
uhci_init_root_hub(uhci_state_t *uhcip)
{
int i, length;
usb_hub_descr_t *root_hub_descr = &uhcip->uhci_root_hub.rh_descr;
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_init_root_hub:");
uhcip->uhci_root_hub.rh_num_ports = MAX_RH_PORTS;
root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE;
root_hub_descr->bNbrPorts = MAX_RH_PORTS;
length = root_hub_descr->bNbrPorts / 8;
if (length) {
root_hub_descr->bDescLength = 7 + (2 * (length + 1));
} else {
root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH;
}
root_hub_descr->bPwrOn2PwrGood = 10;
root_hub_descr->wHubCharacteristics =
HUB_CHARS_NO_POWER_SWITCHING|HUB_CHARS_NO_OVER_CURRENT;
root_hub_descr->DeviceRemovable = 0x0;
root_hub_descr->PortPwrCtrlMask = 0xff;
for (i = 0; i < uhcip->uhci_root_hub.rh_num_ports; i++) {
uhcip->uhci_root_hub.rh_port_state[i] = DISCONNECTED;
uhcip->uhci_root_hub.rh_port_status[i] = 0;
uhcip->uhci_root_hub.rh_port_changes[i] = 0;
}
return (usba_hubdi_bind_root_hub(uhcip->uhci_dip, uhci_rh_config_descr,
sizeof (uhci_rh_config_descr), &uhci_rh_dev_descr));
}
int
uhci_handle_root_hub_request(
uhci_state_t *uhcip,
usba_pipe_handle_data_t *pipe_handle,
usb_ctrl_req_t *req)
{
int error = USB_SUCCESS;
uint16_t port = req->ctrl_wIndex - 1;
usb_cr_t completion_reason;
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p",
req->ctrl_bmRequestType, req->ctrl_bRequest, req->ctrl_wValue,
req->ctrl_wIndex, req->ctrl_wLength, (void *)req->ctrl_data);
ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
switch (req->ctrl_bmRequestType) {
case HUB_GET_DEVICE_STATUS_TYPE:
uhci_handle_get_device_status(uhcip, req);
break;
case HUB_HANDLE_PORT_FEATURE_TYPE:
error = uhci_handle_set_clear_port_feature(uhcip,
req->ctrl_bRequest, req->ctrl_wValue, port);
break;
case HUB_GET_PORT_STATUS_TYPE:
uhci_handle_get_port_status(uhcip, req, port);
break;
case HUB_CLASS_REQ_TYPE:
switch (req->ctrl_bRequest) {
case USB_REQ_GET_DESCR:
uhci_handle_get_hub_descriptor(uhcip, req);
break;
case USB_REQ_GET_STATUS:
uhci_handle_get_hub_status(uhcip, req);
break;
default:
USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_root_hub_request: Unsupported "
"request 0x%x", req->ctrl_bmRequestType);
break;
}
break;
default:
USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_root_hub_request: Unsupported request 0x%x",
req->ctrl_bmRequestType);
break;
}
completion_reason = (error != USB_SUCCESS) ?
USB_CR_NOT_SUPPORTED : USB_CR_OK;
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_root_hub_request: error = %d", error);
uhci_rh_hcdi_callback(uhcip, pipe_handle, (usb_opaque_t)req,
completion_reason);
return (USB_SUCCESS);
}
static int
uhci_handle_set_clear_port_feature(
uhci_state_t *uhcip,
uchar_t bRequest,
uint16_t wValue,
usb_port_t port)
{
int error = USB_SUCCESS;
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x",
bRequest, wValue, port);
switch (bRequest) {
case USB_REQ_SET_FEATURE:
switch (wValue) {
case CFS_PORT_ENABLE:
uhci_handle_port_enable_disable(uhcip,
port, UHCI_ENABLE_PORT);
break;
case CFS_PORT_SUSPEND:
uhci_handle_port_suspend(uhcip, port, 1);
break;
case CFS_PORT_RESET:
uhci_handle_port_reset(uhcip, port);
break;
case CFS_PORT_POWER:
uhci_handle_port_power(uhcip, port,
UHCI_ENABLE_PORT_PWR);
break;
default:
USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_set_clear_port_feature: "
"Unsupported request 0x%x 0x%x", bRequest, wValue);
error = USB_FAILURE;
break;
}
break;
case USB_REQ_CLEAR_FEATURE:
switch (wValue) {
case CFS_PORT_ENABLE:
uhci_handle_port_enable_disable(uhcip,
port, UHCI_DISABLE_PORT);
break;
case CFS_C_PORT_ENABLE:
uhci_handle_port_enable_disable(uhcip,
port, UHCI_CLEAR_ENDIS_BIT);
break;
case CFS_PORT_SUSPEND:
uhci_handle_port_suspend(uhcip, port, 0);
break;
case CFS_C_PORT_RESET:
uhci_handle_complete_port_reset(uhcip, port);
break;
case CFS_PORT_POWER:
uhci_handle_port_power(uhcip, port,
UHCI_DISABLE_PORT_PWR);
break;
case CFS_C_PORT_CONNECTION:
uhci_handle_clear_port_connection(uhcip, port);
break;
default:
USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_set_clear_port_feature: "
"Unsupported request 0x%x 0x%x", bRequest, wValue);
error = USB_FAILURE;
break;
}
break;
default:
USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_set_clear_port_feature: "
"Unsupported request 0x%x 0x%x", bRequest, wValue);
error = USB_FAILURE;
}
return (error);
}
static void
uhci_handle_port_suspend(
uhci_state_t *uhcip,
usb_port_t port,
uint_t on)
{
uint_t port_status = Get_OpReg16(PORTSC[port]);
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_port_suspend: port=%d on=%d",
port, on);
if (on) {
if (!(port_status & HCR_PORT_SUSPEND)) {
Set_OpReg16(PORTSC[port],
(port_status | HCR_PORT_SUSPEND));
}
} else {
if ((port_status & HCR_PORT_SUSPEND)) {
Set_OpReg16(PORTSC[port],
(port_status & ~HCR_PORT_SUSPEND));
}
}
}
static void
uhci_handle_port_power(
uhci_state_t *uhcip,
usb_port_t port,
uint_t on)
{
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_port_power: nothing to do");
}
static void
uhci_handle_port_enable_disable(
uhci_state_t *uhcip,
usb_port_t port,
uint_t action)
{
uint_t port_status = Get_OpReg16(PORTSC[port]);
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_port_enable: port = 0x%x, status = 0x%x",
port, port_status);
if (action == UHCI_ENABLE_PORT) {
if (!(port_status & HCR_PORT_ENABLE)) {
Set_OpReg16(PORTSC[port],
(port_status | HCR_PORT_ENABLE));
}
} else if (action == UHCI_DISABLE_PORT) {
if ((port_status & HCR_PORT_ENABLE)) {
Set_OpReg16(PORTSC[port],
(port_status & ~HCR_PORT_ENABLE));
}
} else {
Set_OpReg16(PORTSC[port], (port_status | HCR_PORT_ENDIS_CHG));
uhcip->uhci_root_hub.rh_port_changes[port] &= ~PORT_CHANGE_PESC;
}
}
void
uhci_root_hub_reset_occurred(
uhci_state_t *uhcip,
uint16_t port)
{
usb_intr_req_t *intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp;
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_root_hub_reset_occurred: intr_reqp = 0x%p data = 0x%p",
(void *)intr_reqp, (void *)intr_reqp->intr_data);
*intr_reqp->intr_data->b_wptr++ = (1 << (port+1));
uhci_rh_hcdi_callback(uhcip, uhcip->uhci_root_hub.rh_intr_pipe_handle,
(usb_opaque_t)intr_reqp, USB_CR_OK);
}
static void
uhci_handle_port_reset(
uhci_state_t *uhcip,
usb_port_t port)
{
uint_t port_status = Get_OpReg16(PORTSC[port]);
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_port_reset: port = 0x%x, status = 0x%x",
port, port_status);
if (!(port_status & HCR_PORT_CCS)) {
USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"port_status & HCR_PORT_CCS == 0: "
"port = 0x%x, status = 0x%x", port, port_status);
}
Set_OpReg16(PORTSC[port], (port_status| HCR_PORT_RESET));
drv_usecwait(UHCI_RESET_DELAY);
Set_OpReg16(PORTSC[port], (port_status & ~HCR_PORT_RESET));
drv_usecwait(UHCI_RESET_DELAY/100);
Set_OpReg16(PORTSC[port], (port_status| HCR_PORT_ENABLE));
if (uhcip->uhci_root_hub.rh_pipe_state != UHCI_PIPE_STATE_ACTIVE) {
uhcip->uhci_root_hub.rh_status = port + 1;
} else {
uhci_root_hub_reset_occurred(uhcip, port);
}
}
static void
uhci_handle_complete_port_reset(
uhci_state_t *uhcip,
usb_port_t port)
{
uint_t port_status = Get_OpReg16(PORTSC[port]);
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_complete_port_reset: port = 0x%x status = 0x%x",
port, port_status);
if (!(port_status & HCR_PORT_CCS)) {
USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"port_status & HCR_PORT_CCS == 0: "
"port = 0x%x, status = 0x%x", port, port_status);
}
Set_OpReg16(PORTSC[port], (port_status & (~ HCR_PORT_RESET)));
uhcip->uhci_root_hub.rh_port_changes[port] &= ~PORT_CHANGE_PRSC;
}
static void
uhci_handle_clear_port_connection(
uhci_state_t *uhcip,
usb_port_t port)
{
uint_t port_status = Get_OpReg16(PORTSC[port]);
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_clear_port_connection: port = 0x%x status = 0x%x",
port, port_status);
Set_OpReg16(PORTSC[port], port_status | HCR_PORT_CSC);
uhcip->uhci_root_hub.rh_port_changes[port] &= ~PORT_CHANGE_CSC;
}
static void
uhci_handle_get_port_status(
uhci_state_t *uhcip,
usb_ctrl_req_t *req,
usb_port_t port)
{
uint_t new_port_status;
uint_t old_port_status =
uhcip->uhci_root_hub.rh_port_status[port];
uint_t old_port_changes =
uhcip->uhci_root_hub.rh_port_changes[port];
uint_t change_status;
usb_ctrl_req_t *ctrl_reqp = (usb_ctrl_req_t *)req;
uint16_t wLength = req->ctrl_wLength;
ASSERT(wLength == 4);
ASSERT(ctrl_reqp->ctrl_data != NULL);
new_port_status = uhci_get_port_status(uhcip, port);
change_status = (old_port_status ^ new_port_status) & 0xff;
change_status |= old_port_changes;
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_get_port_status:\n\t"
"port%d: old status = 0x%x new status = 0x%x change = 0x%x",
port, old_port_status, new_port_status, change_status);
*ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)new_port_status;
*ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)(new_port_status >> 8);
*ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)change_status;
*ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)(change_status >> 8);
uhcip->uhci_root_hub.rh_port_status[port] = new_port_status;
uhcip->uhci_root_hub.rh_port_changes[port] = change_status;
}
static void
uhci_handle_get_hub_descriptor(
uhci_state_t *uhcip,
usb_ctrl_req_t *req)
{
uchar_t raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH];
usb_hub_descr_t *root_hub_descr = &uhcip->uhci_root_hub.rh_descr;
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_get_hub_descriptor: wLength = 0x%x",
req->ctrl_wLength);
ASSERT(req->ctrl_wLength != 0);
ASSERT(req->ctrl_data != NULL);
bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH);
raw_descr[0] = root_hub_descr->bDescLength;
raw_descr[1] = root_hub_descr->bDescriptorType;
raw_descr[2] = root_hub_descr->bNbrPorts;
raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00ff;
raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xff00) >> 8;
raw_descr[5] = root_hub_descr->bPwrOn2PwrGood;
raw_descr[6] = root_hub_descr->bHubContrCurrent;
raw_descr[7] = root_hub_descr->DeviceRemovable;
raw_descr[8] = root_hub_descr->PortPwrCtrlMask;
bcopy(raw_descr, req->ctrl_data->b_wptr, req->ctrl_wLength);
req->ctrl_data->b_wptr += req->ctrl_wLength;
}
static void
uhci_handle_get_hub_status(
uhci_state_t *uhcip,
usb_ctrl_req_t *req)
{
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_get_hub_status: wLength = 0x%x",
req->ctrl_wLength);
ASSERT(req->ctrl_wLength != 0);
ASSERT(req->ctrl_data != NULL);
bzero(req->ctrl_data->b_wptr, req->ctrl_wLength);
req->ctrl_data->b_wptr += req->ctrl_wLength;
}
static void
uhci_handle_get_device_status(
uhci_state_t *uhcip,
usb_ctrl_req_t *req)
{
uint16_t dev_status;
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_handle_get_device_status: wLength = 0x%x",
req->ctrl_wLength);
ASSERT(req->ctrl_wLength != 0);
ASSERT(req->ctrl_data != NULL);
dev_status = USB_DEV_SLF_PWRD_STATUS;
*req->ctrl_data->b_wptr++ = (uchar_t)dev_status;
*req->ctrl_data->b_wptr++ = (uchar_t)(dev_status >> 8);
}
void
uhci_handle_root_hub_status_change(void *arg)
{
usb_port_t port;
uint_t old_port_status;
uint_t new_port_status;
ushort_t port_status;
uint_t change_status;
uchar_t all_ports_status = 0;
uhci_state_t *uhcip = (uhci_state_t *)arg;
usb_intr_req_t *curr_intr_reqp;
mutex_enter(&uhcip->uhci_int_mutex);
uhcip->uhci_timeout_id = 0;
curr_intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp;
for (port = 0; port < uhcip->uhci_root_hub.rh_num_ports; port++) {
new_port_status = uhci_get_port_status(uhcip, port);
old_port_status = uhcip->uhci_root_hub.rh_port_status[port];
change_status = (old_port_status ^ new_port_status) & 0xff;
change_status |= uhcip->uhci_root_hub.rh_port_changes[port];
if (change_status & PORT_STATUS_CCS) {
all_ports_status |= 1 << (port + 1);
}
port_status = Get_OpReg16(PORTSC[port]);
Set_OpReg16(PORTSC[port], port_status | HCR_PORT_ENDIS_CHG);
uhcip->uhci_root_hub.rh_port_status[port] = new_port_status;
uhcip->uhci_root_hub.rh_port_changes[port] = change_status;
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"port %d old status 0x%x new status 0x%x change 0x%x\n\t"
"all_ports_status = 0x%x", port, old_port_status,
new_port_status, change_status, all_ports_status);
}
if (uhcip->uhci_root_hub.rh_intr_pipe_handle &&
all_ports_status && curr_intr_reqp &&
(uhcip->uhci_root_hub.rh_pipe_state == UHCI_PIPE_STATE_ACTIVE)) {
ASSERT(curr_intr_reqp->intr_data != NULL);
*curr_intr_reqp->intr_data->b_wptr++ = all_ports_status;
uhci_rh_hcdi_callback(uhcip,
uhcip->uhci_root_hub.rh_intr_pipe_handle,
(usb_opaque_t)curr_intr_reqp, USB_CR_OK);
}
if (uhcip->uhci_root_hub.rh_pipe_state == UHCI_PIPE_STATE_ACTIVE) {
if (uhci_root_hub_allocate_intr_pipe_resource(uhcip, 0) !=
USB_SUCCESS) {
uhci_root_hub_intr_pipe_cleanup(uhcip,
USB_CR_NO_RESOURCES);
}
}
mutex_exit(&uhcip->uhci_int_mutex);
}
static uint_t
uhci_get_port_status(
uhci_state_t *uhcip,
usb_port_t port)
{
uint_t new_port_status = PORT_STATUS_PPS;
ushort_t port_status = Get_OpReg16(PORTSC[port]);
if (port_status & HCR_PORT_CCS) {
new_port_status |= PORT_STATUS_CCS;
}
if (port_status & HCR_PORT_LSDA) {
new_port_status |= PORT_STATUS_LSDA;
}
if (port_status & HCR_PORT_ENABLE) {
new_port_status |= PORT_STATUS_PES;
}
if (port_status & HCR_PORT_SUSPEND) {
new_port_status |= PORT_STATUS_PSS;
}
if (port_status & HCR_PORT_RESET) {
new_port_status |= PORT_STATUS_PRS;
}
return (new_port_status);
}
int
uhci_root_hub_allocate_intr_pipe_resource(
uhci_state_t *uhcip,
usb_flags_t flags)
{
usb_intr_req_t *curr_intr_reqp;
usba_pipe_handle_data_t *ph;
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_root_hub_allocate_intr_pipe_resource:");
ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
ph = uhcip->uhci_root_hub.rh_intr_pipe_handle;
curr_intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp;
if (curr_intr_reqp == NULL) {
ASSERT(uhcip->uhci_root_hub.rh_client_intr_req);
if ((curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
uhcip->uhci_root_hub.rh_client_intr_req,
uhcip->uhci_root_hub.rh_client_intr_req->intr_len,
flags)) == NULL) {
USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
"uhci_root_hub_allocate_intr_pipe_resource:"
"Interrupt request structure allocation failed");
return (USB_NO_RESOURCES);
}
uhcip->uhci_root_hub.rh_curr_intr_reqp = curr_intr_reqp;
mutex_enter(&ph->p_mutex);
ph->p_req_count++;
mutex_exit(&ph->p_mutex);
}
if (uhcip->uhci_timeout_id == 0) {
uhcip->uhci_timeout_id = timeout(
uhci_handle_root_hub_status_change,
(void *)uhcip, UHCI_256_MS);
uhcip->uhci_root_hub.rh_pipe_state =
UHCI_PIPE_STATE_ACTIVE;
}
return (USB_SUCCESS);
}
void
uhci_root_hub_intr_pipe_cleanup(uhci_state_t *uhcip, usb_cr_t cr)
{
usb_intr_req_t *curr_intr_reqp;
usb_opaque_t client_intr_reqp;
usba_pipe_handle_data_t *ph;
timeout_id_t timer_id;
USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
"uhci_root_hub_intr_pipe_cleanup:");
ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
ph = uhcip->uhci_root_hub.rh_intr_pipe_handle;
timer_id = uhcip->uhci_timeout_id;
if (timer_id) {
uhcip->uhci_timeout_id = 0;
uhcip->uhci_root_hub.rh_pipe_state =
UHCI_PIPE_STATE_IDLE;
mutex_exit(&uhcip->uhci_int_mutex);
(void) untimeout(timer_id);
mutex_enter(&uhcip->uhci_int_mutex);
}
curr_intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp;
if (curr_intr_reqp) {
uhcip->uhci_root_hub.rh_curr_intr_reqp = NULL;
usb_free_intr_req(curr_intr_reqp);
mutex_enter(&ph->p_mutex);
ph->p_req_count--;
mutex_exit(&ph->p_mutex);
}
client_intr_reqp = (usb_opaque_t)
uhcip->uhci_root_hub.rh_client_intr_req;
if (client_intr_reqp) {
uhcip->uhci_root_hub.rh_client_intr_req = NULL;
uhci_rh_hcdi_callback(uhcip, ph,
(usb_opaque_t)client_intr_reqp, cr);
}
}
static void
uhci_rh_hcdi_callback(
uhci_state_t *uhcip,
usba_pipe_handle_data_t *ph,
usb_opaque_t req,
usb_cr_t cr)
{
USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
"uhci_rh_hcdi_callback: ph=0x%p cr=0x%x req=0x%p",
(void *)ph, cr, (void *)req);
ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
switch (UHCI_XFER_TYPE(&ph->p_ep)) {
case USB_EP_ATTR_CONTROL:
break;
case USB_EP_ATTR_INTR:
if ((usb_intr_req_t *)req ==
uhcip->uhci_root_hub.rh_curr_intr_reqp) {
uhcip->uhci_root_hub.rh_curr_intr_reqp = NULL;
break;
} else if ((usb_intr_req_t *)req ==
uhcip->uhci_root_hub.rh_client_intr_req) {
uhcip->uhci_root_hub.rh_client_intr_req = NULL;
break;
}
default:
ASSERT(req);
break;
}
mutex_exit(&uhcip->uhci_int_mutex);
usba_hcdi_cb(ph, req, cr);
mutex_enter(&uhcip->uhci_int_mutex);
}