ohci_hub.c revision 35f36846429327ed1512f8098c6a6b337055d875
2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A/*
2N/A * Open Host Controller Driver (OHCI)
2N/A *
2N/A * The USB Open Host Controller driver is a software driver which interfaces
2N/A * to the Universal Serial Bus layer (USBA) and the USB Open Host Controller.
2N/A * The interface to USB Open Host Controller is defined by the OpenHCI Host
2N/A * Controller Interface.
2N/A *
2N/A * This module contains the code for root hub related functions.
2N/A *
2N/A * Note: ONE_XFER is not supported on root hub interrupt polling.
2N/A */
2N/A#include <sys/usb/hcd/openhci/ohcid.h>
2N/A
2N/A/* static function prototypes */
2N/Astatic int ohci_handle_set_clear_port_feature(
2N/A ohci_state_t *ohcip,
2N/A uchar_t bRequest,
2N/A uint16_t wValue,
2N/A uint16_t port);
2N/Astatic void ohci_handle_port_power(ohci_state_t *ohcip,
2N/A uint16_t port,
2N/A uint_t on);
2N/Astatic void ohci_handle_port_enable(ohci_state_t *ohcip,
2N/A uint16_t port,
2N/A uint_t on);
2N/Astatic void ohci_handle_clrchng_port_enable(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port);
2N/Astatic void ohci_handle_port_suspend(ohci_state_t *ohcip,
2N/A uint16_t port,
2N/A uint_t on);
2N/Astatic void ohci_handle_clrchng_port_suspend(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port);
2N/Astatic void ohci_handle_port_reset(ohci_state_t *ohcip,
2N/A uint16_t port);
2N/Astatic void ohci_handle_complete_port_reset(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port);
2N/Astatic void ohci_handle_clear_port_connection(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port);
2N/Astatic void ohci_handle_clrchng_port_over_current(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port);
2N/Astatic void ohci_handle_get_port_status(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port);
2N/Astatic void ohci_handle_get_hub_descriptor(
2N/A ohci_state_t *ohcip);
2N/Astatic void ohci_handle_get_hub_status(
2N/A ohci_state_t *ohcip);
2N/Astatic void ohci_handle_get_device_status(
2N/A ohci_state_t *ohcip);
2N/Astatic int ohci_root_hub_allocate_intr_pipe_resource(
2N/A ohci_state_t *ohcip,
2N/A usb_flags_t flags);
2N/Astatic void ohci_root_hub_intr_pipe_cleanup(
2N/A ohci_state_t *ohcip,
2N/A usb_cr_t completion_reason);
2N/Astatic void ohci_root_hub_hcdi_callback(
2N/A usba_pipe_handle_data_t *ph,
2N/A usb_cr_t completion_reason);
2N/A
2N/A
2N/A/*
2N/A * ohci_init_root_hub:
2N/A *
2N/A * Initialize the root hub
2N/A */
2N/Aint
2N/Aohci_init_root_hub(ohci_state_t *ohcip)
2N/A{
2N/A usb_hub_descr_t *root_hub_descr =
2N/A &ohcip->ohci_root_hub.rh_descr;
2N/A uint_t des_A, des_B, port_state;
2N/A int i, length;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_init_root_hub:");
2N/A
2N/A /* Read the descriptor registers */
2N/A des_A = ohcip->ohci_root_hub.rh_des_A = Get_OpReg(hcr_rh_descriptorA);
2N/A des_B = ohcip->ohci_root_hub.rh_des_B = Get_OpReg(hcr_rh_descriptorB);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "root hub descriptor A 0x%x", ohcip->ohci_root_hub.rh_des_A);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "root hub descriptor B 0x%x", ohcip->ohci_root_hub.rh_des_B);
2N/A
2N/A /* Obtain the root hub status */
2N/A ohcip->ohci_root_hub.rh_status = Get_OpReg(hcr_rh_status);
2N/A
2N/A /*
2N/A * Build the hub descriptor based on HcRhDescriptorA and
2N/A * HcRhDescriptorB
2N/A */
2N/A root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE;
2N/A
2N/A if ((des_A & HCR_RHA_NDP) > OHCI_MAX_RH_PORTS) {
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_init_root_hub:" "Invalid no of root hub ports 0x%x",
2N/A des_A & HCR_RHA_NDP);
2N/A
2N/A return (USB_FAILURE);
2N/A }
2N/A
2N/A /* Obtain the number of downstream ports */
2N/A root_hub_descr->bNbrPorts = des_A & HCR_RHA_NDP;
2N/A
2N/A length = root_hub_descr->bNbrPorts / 8;
2N/A
2N/A if (length) {
2N/A root_hub_descr->bDescLength = 7 + (2 * (length + 1));
2N/A } else {
2N/A root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH;
2N/A }
2N/A
2N/A /* Determine the Power Switching Mode */
2N/A if (!(des_A & HCR_RHA_NPS)) {
2N/A /*
2N/A * The ports are power switched. Check for either individual
2N/A * or gang power switching.
2N/A */
2N/A if ((des_A & HCR_RHA_PSM) && (des_B & HCR_RHB_PPCM)) {
2N/A /* each port is powered individually */
2N/A root_hub_descr->wHubCharacteristics =
2N/A HUB_CHARS_INDIVIDUAL_PORT_POWER;
2N/A } else {
2N/A /* the ports are gang powered */
2N/A root_hub_descr->
2N/A wHubCharacteristics = HUB_CHARS_GANGED_POWER;
2N/A }
2N/A
2N/A /* Each port will start off in the POWERED_OFF mode */
2N/A port_state = POWERED_OFF;
2N/A } else {
2N/A /* The ports are powered when the ctlr is powered */
2N/A root_hub_descr->
2N/A wHubCharacteristics = HUB_CHARS_NO_POWER_SWITCHING;
2N/A
2N/A port_state = DISCONNECTED;
2N/A }
2N/A
2N/A /* The root hub should never be a compound device */
2N/A ASSERT((des_A & HCR_RHA_DT) == 0);
2N/A
2N/A /* Determine the Over-current Protection Mode */
2N/A if (des_A & HCR_RHA_NOCP) {
2N/A /* No over current protection */
2N/A root_hub_descr->
2N/A wHubCharacteristics |= HUB_CHARS_NO_OVER_CURRENT;
2N/A } else {
2N/A USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
2N/A ohcip->ohci_log_hdl, "OCPM =%d, PSM=%d",
2N/A des_A & HCR_RHA_OCPM, des_A & HCR_RHA_PSM);
2N/A
2N/A /* See if over current protection is provided */
2N/A if (des_A & HCR_RHA_OCPM) {
2N/A /* reported on a per port basis */
2N/A root_hub_descr->
2N/A wHubCharacteristics |= HUB_CHARS_INDIV_OVER_CURRENT;
2N/A }
2N/A }
2N/A
2N/A /* Obtain the power on to power good time of the ports */
2N/A root_hub_descr->bPwrOn2PwrGood = (uint32_t)
2N/A ((des_A & HCR_RHA_PTPGT) >> HCR_RHA_PTPGT_SHIFT);
2N/A
2N/A USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "Power on to power good %d", root_hub_descr->bPwrOn2PwrGood);
2N/A
2N/A /* Indicate if the device is removable */
2N/A root_hub_descr->DeviceRemovable = (uchar_t)des_B & HCR_RHB_DR;
2N/A
2N/A /*
2N/A * Fill in the port power control mask:
2N/A * Each bit in the PortPowerControlMask
2N/A * should be set. Refer to USB 2.0, table 11-13
2N/A */
2N/A root_hub_descr->PortPwrCtrlMask = (uchar_t)(des_B >> 16);
2N/A
2N/A /* Set the state of each port and initialize the status */
2N/A for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
2N/A ohcip->ohci_root_hub.rh_port_state[i] = port_state;
2N/A
2N/A /* Turn off the power on each port for now */
2N/A Set_OpReg(hcr_rh_portstatus[i], HCR_PORT_CPP);
2N/A
2N/A /*
2N/A * Initialize each of the root hub port status
2N/A * equal to zero. This initialization makes sure
2N/A * that all devices connected to root hub will
2N/A * enumerates when the first RHSC interrupt occurs
2N/A * since definitely there will be changes in
2N/A * the root hub port status.
2N/A */
2N/A ohcip->ohci_root_hub.rh_port_status[i] = 0;
2N/A }
2N/A
2N/A return (USB_SUCCESS);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_load_root_hub_driver:
2N/A *
2N/A * Attach the root hub
2N/A */
2N/Astatic usb_dev_descr_t ohci_root_hub_device_descriptor = {
2N/A 0x12, /* bLength */
2N/A 0x01, /* bDescriptorType, Device */
2N/A 0x110, /* bcdUSB, v1.1 */
2N/A 0x09, /* bDeviceClass */
2N/A 0x00, /* bDeviceSubClass */
2N/A 0x00, /* bDeviceProtocol */
2N/A 0x08, /* bMaxPacketSize0 */
2N/A 0x00, /* idVendor */
2N/A 0x00, /* idProduct */
2N/A 0x00, /* bcdDevice */
2N/A 0x00, /* iManufacturer */
2N/A 0x00, /* iProduct */
2N/A 0x00, /* iSerialNumber */
2N/A 0x01 /* bNumConfigurations */
2N/A};
2N/A
2N/Astatic uchar_t ohci_root_hub_config_descriptor[] = {
2N/A /* One configuartion */
2N/A 0x09, /* bLength */
2N/A 0x02, /* bDescriptorType, Configuartion */
2N/A 0x19, 0x00, /* wTotalLength */
2N/A 0x01, /* bNumInterfaces */
2N/A 0x01, /* bConfigurationValue */
2N/A 0x00, /* iConfiguration */
2N/A 0x40, /* bmAttributes */
2N/A 0x00, /* MaxPower */
2N/A
2N/A /* One Interface */
2N/A 0x09, /* bLength */
2N/A 0x04, /* bDescriptorType, Interface */
2N/A 0x00, /* bInterfaceNumber */
2N/A 0x00, /* bAlternateSetting */
2N/A 0x01, /* bNumEndpoints */
2N/A 0x09, /* bInterfaceClass */
2N/A 0x01, /* bInterfaceSubClass */
2N/A 0x00, /* bInterfaceProtocol */
2N/A 0x00, /* iInterface */
2N/A
2N/A /* One Endpoint (status change endpoint) */
2N/A 0x07, /* bLength */
2N/A 0x05, /* bDescriptorType, Endpoint */
2N/A 0x81, /* bEndpointAddress */
2N/A 0x03, /* bmAttributes */
2N/A 0x01, 0x00, /* wMaxPacketSize, 1 + (OHCI_MAX_RH_PORTS / 8) */
2N/A 0xff /* bInterval */
2N/A};
2N/A
2N/Aint
2N/Aohci_load_root_hub_driver(ohci_state_t *ohcip)
2N/A{
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_load_root_hub_driver:");
2N/A
2N/A return (usba_hubdi_bind_root_hub(ohcip->ohci_dip,
2N/A ohci_root_hub_config_descriptor,
2N/A sizeof (ohci_root_hub_config_descriptor),
2N/A &ohci_root_hub_device_descriptor));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_unload_root_hub_driver:
2N/A */
2N/Aint
2N/Aohci_unload_root_hub_driver(ohci_state_t *ohcip)
2N/A{
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_unload_root_hub_driver:");
2N/A
2N/A return (usba_hubdi_unbind_root_hub(ohcip->ohci_dip));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_root_hub_pipe_open:
2N/A *
2N/A * Handle opening of control and interrupt pipes on root hub.
2N/A */
2N/A/* ARGSUSED */
2N/Aint
2N/Aohci_handle_root_hub_pipe_open(
2N/A usba_pipe_handle_data_t *ph,
2N/A usb_flags_t usb_flags)
2N/A{
2N/A ohci_state_t *ohcip = ohci_obtain_state(
2N/A ph->p_usba_device->usb_root_hub_dip);
2N/A usb_ep_descr_t *eptd = &ph->p_ep;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_open: Root hub pipe open");
2N/A
2N/A ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
2N/A
2N/A switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
2N/A case USB_EP_ATTR_CONTROL:
2N/A /* Save control pipe handle */
2N/A ohcip->ohci_root_hub.rh_ctrl_pipe_handle = ph;
2N/A
2N/A /* Set state of the root hub control pipe as idle */
2N/A ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_IDLE;
2N/A
2N/A ohcip->ohci_root_hub.rh_curr_ctrl_reqp = NULL;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_open: Root hub control "
2N/A "pipe open succeeded");
2N/A
2N/A break;
2N/A case USB_EP_ATTR_INTR:
2N/A /* Save interrupt pipe handle */
2N/A ohcip->ohci_root_hub.rh_intr_pipe_handle = ph;
2N/A
2N/A /* Set state of the root hub interrupt pipe as idle */
2N/A ohcip->ohci_root_hub.rh_intr_pipe_state = OHCI_PIPE_STATE_IDLE;
2N/A
2N/A ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
2N/A
2N/A ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_open: Root hub interrupt "
2N/A "pipe open succeeded");
2N/A
2N/A break;
2N/A default:
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_open: Root hub pipe open"
2N/A "failed");
2N/A
2N/A return (USB_FAILURE);
2N/A }
2N/A
2N/A ohcip->ohci_open_pipe_count++;
2N/A
2N/A return (USB_SUCCESS);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_root_hub_pipe_close:
2N/A *
2N/A * Handle closing of control and interrupt pipes on root hub.
2N/A */
2N/A/* ARGSUSED */
2N/Aint
2N/Aohci_handle_root_hub_pipe_close(usba_pipe_handle_data_t *ph)
2N/A{
2N/A ohci_state_t *ohcip = ohci_obtain_state(
2N/A ph->p_usba_device->usb_root_hub_dip);
2N/A usb_ep_descr_t *eptd = &ph->p_ep;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_close: Root hub pipe close");
2N/A
2N/A ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
2N/A
2N/A switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
2N/A case USB_EP_ATTR_CONTROL:
2N/A ASSERT(ohcip->ohci_root_hub.
2N/A rh_ctrl_pipe_state != OHCI_PIPE_STATE_CLOSE);
2N/A
2N/A /* Set state of the root hub control pipe as close */
2N/A ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_CLOSE;
2N/A
2N/A /* Set root hub control pipe handle to null */
2N/A ohcip->ohci_root_hub.rh_ctrl_pipe_handle = NULL;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_close: "
2N/A "Root hub control pipe close succeeded");
2N/A break;
2N/A case USB_EP_ATTR_INTR:
2N/A ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
2N/A
2N/A ASSERT(ohcip->ohci_root_hub.
2N/A rh_intr_pipe_state != OHCI_PIPE_STATE_CLOSE);
2N/A
2N/A /* Set state of the root hub interrupt pipe as close */
2N/A ohcip->ohci_root_hub.rh_intr_pipe_state = OHCI_PIPE_STATE_CLOSE;
2N/A
2N/A /* Do interrupt pipe cleanup */
2N/A ohci_root_hub_intr_pipe_cleanup(ohcip, USB_CR_PIPE_CLOSING);
2N/A
2N/A /* Set root hub interrupt pipe handle to null */
2N/A ohcip->ohci_root_hub.rh_intr_pipe_handle = NULL;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_close: "
2N/A "Root hub interrupt pipe close succeeded");
2N/A
2N/A break;
2N/A default:
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_close: "
2N/A "Root hub pipe close failed");
2N/A
2N/A return (USB_FAILURE);
2N/A }
2N/A
2N/A ohcip->ohci_open_pipe_count--;
2N/A
2N/A return (USB_SUCCESS);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_root_hub_pipe_reset:
2N/A *
2N/A * Handle resetting of control and interrupt pipes on root hub.
2N/A */
2N/A/* ARGSUSED */
2N/Aint
2N/Aohci_handle_root_hub_pipe_reset(
2N/A usba_pipe_handle_data_t *ph,
2N/A usb_flags_t usb_flags)
2N/A{
2N/A ohci_state_t *ohcip = ohci_obtain_state(
2N/A ph->p_usba_device->usb_root_hub_dip);
2N/A usb_ep_descr_t *eptd = &ph->p_ep;
2N/A int error = USB_SUCCESS;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_reset: Root hub pipe reset");
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
2N/A case USB_EP_ATTR_CONTROL:
2N/A ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_IDLE;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_reset: Pipe reset"
2N/A "for the root hub control pipe successful");
2N/A
2N/A break;
2N/A case USB_EP_ATTR_INTR:
2N/A ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
2N/A
2N/A if ((ohcip->ohci_root_hub.rh_client_intr_reqp) &&
2N/A (ohcip->ohci_root_hub.rh_intr_pipe_state !=
2N/A OHCI_PIPE_STATE_IDLE)) {
2N/A
2N/A ohcip->ohci_root_hub.
2N/A rh_intr_pipe_state = OHCI_PIPE_STATE_RESET;
2N/A
2N/A /* Do interrupt pipe cleanup */
2N/A ohci_root_hub_intr_pipe_cleanup(
2N/A ohcip, USB_CR_PIPE_RESET);
2N/A }
2N/A
2N/A ASSERT(ohcip->ohci_root_hub.
2N/A rh_intr_pipe_state == OHCI_PIPE_STATE_IDLE);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_reset: "
2N/A "Pipe reset for root hub interrupt pipe successful");
2N/A
2N/A break;
2N/A default:
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_reset: "
2N/A "Root hub pipe reset failed");
2N/A
2N/A error = USB_FAILURE;
2N/A break;
2N/A }
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A
2N/A return (error);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_root_hub_request:
2N/A *
2N/A * Intercept a root hub request. Handle the root hub request through the
2N/A * registers
2N/A */
2N/A/* ARGSUSED */
2N/Aint
2N/Aohci_handle_root_hub_request(
2N/A ohci_state_t *ohcip,
2N/A usba_pipe_handle_data_t *ph,
2N/A usb_ctrl_req_t *ctrl_reqp)
2N/A{
2N/A uchar_t bmRequestType = ctrl_reqp->ctrl_bmRequestType;
2N/A uchar_t bRequest = ctrl_reqp->ctrl_bRequest;
2N/A uint16_t wValue = ctrl_reqp->ctrl_wValue;
2N/A uint16_t wIndex = ctrl_reqp->ctrl_wIndex;
2N/A uint16_t wLength = ctrl_reqp->ctrl_wLength;
2N/A mblk_t *data = ctrl_reqp->ctrl_data;
2N/A uint16_t port = wIndex - 1; /* Adjust for controller */
2N/A usb_cr_t completion_reason;
2N/A int error = USB_SUCCESS;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p",
2N/A bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data);
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A if (ohcip->ohci_root_hub.rh_ctrl_pipe_state != OHCI_PIPE_STATE_IDLE) {
2N/A
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_request: Pipe is not idle");
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A
2N/A return (USB_FAILURE);
2N/A }
2N/A
2N/A /* Save the current control request pointer */
2N/A ohcip->ohci_root_hub.rh_curr_ctrl_reqp = ctrl_reqp;
2N/A
2N/A /* Set pipe state to active */
2N/A ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_ACTIVE;
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A
2N/A switch (bmRequestType) {
2N/A case HUB_GET_DEVICE_STATUS_TYPE:
2N/A ohci_handle_get_device_status(ohcip);
2N/A break;
2N/A case HUB_HANDLE_PORT_FEATURE_TYPE:
2N/A error = ohci_handle_set_clear_port_feature(ohcip,
2N/A bRequest, wValue, port);
2N/A break;
2N/A case HUB_GET_PORT_STATUS_TYPE:
2N/A ohci_handle_get_port_status(ohcip, port);
2N/A break;
2N/A case HUB_CLASS_REQ_TYPE:
2N/A switch (bRequest) {
2N/A case USB_REQ_GET_STATUS:
2N/A ohci_handle_get_hub_status(ohcip);
2N/A break;
2N/A case USB_REQ_GET_DESCR:
2N/A ohci_handle_get_hub_descriptor(ohcip);
2N/A break;
2N/A default:
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_request:"
2N/A "Unsupported request 0x%x", bRequest);
2N/A
2N/A error = USB_FAILURE;
2N/A break;
2N/A }
2N/A break;
2N/A default:
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_request: "
2N/A "Unsupported request 0x%x", bmRequestType);
2N/A
2N/A error = USB_FAILURE;
2N/A break;
2N/A }
2N/A
2N/A completion_reason = (error) ? USB_CR_NOT_SUPPORTED : USB_CR_OK;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A ohci_root_hub_hcdi_callback(ph, completion_reason);
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_request: error = %d", error);
2N/A
2N/A return (USB_SUCCESS);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_set_clear_port_feature:
2N/A */
2N/Astatic int
2N/Aohci_handle_set_clear_port_feature(
2N/A ohci_state_t *ohcip,
2N/A uchar_t bRequest,
2N/A uint16_t wValue,
2N/A uint16_t port)
2N/A{
2N/A int error = USB_SUCCESS;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x",
2N/A bRequest, wValue, port);
2N/A
2N/A switch (bRequest) {
2N/A case USB_REQ_SET_FEATURE:
2N/A switch (wValue) {
2N/A case CFS_PORT_ENABLE:
2N/A ohci_handle_port_enable(ohcip, port, 1);
2N/A break;
2N/A case CFS_PORT_SUSPEND:
2N/A ohci_handle_port_suspend(ohcip, port, 1);
2N/A break;
2N/A case CFS_PORT_RESET:
2N/A ohci_handle_port_reset(ohcip, port);
2N/A break;
2N/A case CFS_PORT_POWER:
2N/A ohci_handle_port_power(ohcip, port, 1);
2N/A break;
2N/A default:
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_set_clear_port_feature: "
2N/A "Unsupported request 0x%x 0x%x", bRequest, wValue);
2N/A
2N/A error = USB_FAILURE;
2N/A break;
2N/A }
2N/A break;
2N/A case USB_REQ_CLEAR_FEATURE:
2N/A switch (wValue) {
2N/A case CFS_PORT_ENABLE:
2N/A ohci_handle_port_enable(ohcip, port, 0);
2N/A break;
2N/A case CFS_C_PORT_ENABLE:
2N/A ohci_handle_clrchng_port_enable(ohcip, port);
2N/A break;
2N/A case CFS_PORT_SUSPEND:
2N/A ohci_handle_port_suspend(ohcip, port, 0);
2N/A break;
2N/A case CFS_C_PORT_SUSPEND:
2N/A ohci_handle_clrchng_port_suspend(ohcip, port);
2N/A break;
2N/A case CFS_C_PORT_RESET:
2N/A ohci_handle_complete_port_reset(ohcip, port);
2N/A break;
2N/A case CFS_PORT_POWER:
2N/A ohci_handle_port_power(ohcip, port, 0);
2N/A break;
2N/A case CFS_C_PORT_CONNECTION:
2N/A ohci_handle_clear_port_connection(ohcip, port);
2N/A break;
2N/A case CFS_C_PORT_OVER_CURRENT:
2N/A ohci_handle_clrchng_port_over_current(ohcip, port);
2N/A break;
2N/A default:
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_set_clear_port_feature: "
2N/A "Unsupported request 0x%x 0x%x", bRequest, wValue);
2N/A
2N/A error = USB_FAILURE;
2N/A break;
2N/A }
2N/A break;
2N/A default:
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_set_clear_port_feature: "
2N/A "Unsupported request 0x%x 0x%x", bRequest, wValue);
2N/A
2N/A error = USB_FAILURE;
2N/A break;
2N/A }
2N/A
2N/A return (error);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_port_power:
2N/A *
2N/A * Turn on a root hub port.
2N/A */
2N/Astatic void
2N/Aohci_handle_port_power(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port,
2N/A uint_t on)
2N/A{
2N/A usb_hub_descr_t *hub_descr;
2N/A uint_t port_status;
2N/A ohci_root_hub_t *rh;
2N/A uint_t p;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A port_status = Get_OpReg(hcr_rh_portstatus[port]);
2N/A rh = &ohcip->ohci_root_hub;
2N/A hub_descr = &ohcip->ohci_root_hub.rh_descr;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_port_power: port = 0x%x status = 0x%x on = %d",
2N/A port, port_status, on);
2N/A
2N/A if (on) {
2N/A /*
2N/A * If the port power is ganged, enable the power through
2N/A * the status registers, else enable the port power.
2N/A */
2N/A if ((hub_descr->wHubCharacteristics &
2N/A HUB_CHARS_POWER_SWITCHING_MODE) ==
2N/A HUB_CHARS_GANGED_POWER) {
2N/A
2N/A Set_OpReg(hcr_rh_status, HCR_RH_STATUS_LPSC);
2N/A
2N/A for (p = 0; p < hub_descr->bNbrPorts; p++) {
2N/A rh->rh_port_status[p] = 0;
2N/A rh->rh_port_state[p] = DISCONNECTED;
2N/A }
2N/A } else {
2N/A /* See if the port power is already on */
2N/A if (!(port_status & HCR_PORT_PPS)) {
2N/A /* Turn the port on */
2N/A Set_OpReg(hcr_rh_portstatus[port],
2N/A HCR_PORT_PPS);
2N/A }
2N/A
2N/A rh->rh_port_status[port] = 0;
2N/A rh->rh_port_state[port] = DISCONNECTED;
2N/A }
2N/A } else {
2N/A /*
2N/A * If the port power is ganged, disable the power through
2N/A * the status registers, else disable the port power.
2N/A */
2N/A if ((hub_descr->wHubCharacteristics &
2N/A HUB_CHARS_POWER_SWITCHING_MODE) ==
2N/A HUB_CHARS_GANGED_POWER) {
2N/A
2N/A Set_OpReg(hcr_rh_status, HCR_RH_STATUS_LPS);
2N/A
2N/A for (p = 0; p < hub_descr->bNbrPorts; p++) {
2N/A rh->rh_port_status[p] = 0;
2N/A rh->rh_port_state[p] = POWERED_OFF;
2N/A }
2N/A } else {
2N/A /* See if the port power is already OFF */
2N/A if ((port_status & HCR_PORT_PPS)) {
2N/A /* Turn the port OFF by writing LSSA bit */
2N/A Set_OpReg(hcr_rh_portstatus[port],
2N/A HCR_PORT_LSDA);
2N/A }
2N/A
2N/A rh->rh_port_status[port] = 0;
2N/A rh->rh_port_state[port] = POWERED_OFF;
2N/A }
2N/A }
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_port_power done: "
2N/A "port = 0x%x status = 0x%x on = %d",
2N/A port, Get_OpReg(hcr_rh_portstatus[port]), on);
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_port_enable:
2N/A *
2N/A * Handle port enable request.
2N/A */
2N/Astatic void
2N/Aohci_handle_port_enable(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port,
2N/A uint_t on)
2N/A{
2N/A uint_t port_status;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A port_status = Get_OpReg(hcr_rh_portstatus[port]);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_port_enable: port = 0x%x, status = 0x%x",
2N/A port, port_status);
2N/A
2N/A if (on) {
2N/A /* See if the port enable is already on */
2N/A if (!(port_status & HCR_PORT_PES)) {
2N/A /* Enable the port */
2N/A Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PES);
2N/A }
2N/A } else {
2N/A /* See if the port enable is already off */
2N/A if (!(port_status & HCR_PORT_PES)) {
2N/A /* disable the port by writing CCS bit */
2N/A Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_CCS);
2N/A }
2N/A }
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_clrchng_port_enable:
2N/A *
2N/A * Handle clear port enable change bit.
2N/A */
2N/Astatic void
2N/Aohci_handle_clrchng_port_enable(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port)
2N/A{
2N/A uint_t port_status;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A port_status = Get_OpReg(hcr_rh_portstatus[port]);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_port_enable: port = 0x%x, status = 0x%x",
2N/A port, port_status);
2N/A
2N/A /* Clear the PortEnableStatusChange Bit */
2N/A Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PESC);
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_port_suspend:
2N/A *
2N/A * Handle port suspend/resume request.
2N/A */
2N/Astatic void
2N/Aohci_handle_port_suspend(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port,
2N/A uint_t on)
2N/A{
2N/A uint_t port_status;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A port_status = Get_OpReg(hcr_rh_portstatus[port]);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_port_suspend: port = 0x%x, status = 0x%x",
2N/A port, port_status);
2N/A
2N/A if (on) {
2N/A /* Suspend the port */
2N/A Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PSS);
2N/A } else {
2N/A /* To Resume, we write the POCI bit */
2N/A Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_POCI);
2N/A }
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_clrchng_port_suspend:
2N/A *
2N/A * Handle port clear port suspend change bit.
2N/A */
2N/Astatic void
2N/Aohci_handle_clrchng_port_suspend(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port)
2N/A{
2N/A uint_t port_status;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A port_status = Get_OpReg(hcr_rh_portstatus[port]);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_clrchng_port_suspend: port = 0x%x, status = 0x%x",
2N/A port, port_status);
2N/A
2N/A Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PSSC);
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_port_reset:
2N/A *
2N/A * Perform a port reset.
2N/A */
2N/Astatic void
2N/Aohci_handle_port_reset(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port)
2N/A{
2N/A uint_t port_status;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A port_status = Get_OpReg(hcr_rh_portstatus[port]);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_port_reset: port = 0x%x status = 0x%x",
2N/A port, port_status);
2N/A
2N/A if (!(port_status & HCR_PORT_CCS)) {
2N/A USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "port_status & HCR_PORT_CCS == 0: "
2N/A "port = 0x%x status = 0x%x", port, port_status);
2N/A }
2N/A
2N/A Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PRS);
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_complete_port_reset:
2N/A *
2N/A * Perform a port reset change.
2N/A */
2N/Astatic void
2N/Aohci_handle_complete_port_reset(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port)
2N/A{
2N/A uint_t port_status;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A port_status = Get_OpReg(hcr_rh_portstatus[port]);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_complete_port_reset: port = 0x%x status = 0x%x",
2N/A port, port_status);
2N/A
2N/A if (!(port_status & HCR_PORT_CCS)) {
2N/A USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "port_status & HCR_PORT_CCS == 0: "
2N/A "port = 0x%x status = 0x%x", port, port_status);
2N/A }
2N/A
2N/A Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PRSC);
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_clear_port_connection:
2N/A *
2N/A * Perform a clear port connection.
2N/A */
2N/Astatic void
2N/Aohci_handle_clear_port_connection(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port)
2N/A{
2N/A uint_t port_status;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A port_status = Get_OpReg(hcr_rh_portstatus[port]);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_clear_port_connection: port = 0x%x"
2N/A "status = 0x%x", port, port_status);
2N/A
2N/A /* Clear CSC bit */
2N/A Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_CSC);
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_clrchng_port_over_current:
2N/A *
2N/A * Perform a clear over current condition.
2N/A */
2N/Astatic void
2N/Aohci_handle_clrchng_port_over_current(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port)
2N/A{
2N/A uint_t port_status;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A port_status = Get_OpReg(hcr_rh_portstatus[port]);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_clrchng_port_over_current: port = 0x%x"
2N/A "status = 0x%x", port, port_status);
2N/A
2N/A Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_OCIC);
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_get_port_status:
2N/A *
2N/A * Handle a get port status request.
2N/A */
2N/Astatic void
2N/Aohci_handle_get_port_status(
2N/A ohci_state_t *ohcip,
2N/A uint16_t port)
2N/A{
2N/A usb_ctrl_req_t *ctrl_reqp;
2N/A mblk_t *message;
2N/A uint_t new_port_status;
2N/A uint_t change_status;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
2N/A
2N/A /* Read the current port status and return it */
2N/A new_port_status = Get_OpReg(hcr_rh_portstatus[port]);
2N/A ohcip->ohci_root_hub.rh_port_status[port] = new_port_status;
2N/A
2N/A change_status = (new_port_status & HCR_PORT_CHNG_MASK) >> 16;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_get_port_status: port = %d new status = 0x%x"
2N/A "change = 0x%x", port, new_port_status, change_status);
2N/A
2N/A message = ctrl_reqp->ctrl_data;
2N/A
2N/A ASSERT(message != NULL);
2N/A
2N/A *message->b_wptr++ = (uchar_t)new_port_status;
2N/A *message->b_wptr++ = (uchar_t)(new_port_status >> 8);
2N/A *message->b_wptr++ = (uchar_t)change_status;
2N/A *message->b_wptr++ = (uchar_t)(change_status >> 8);
2N/A
2N/A /* Save the data in control request */
2N/A ctrl_reqp->ctrl_data = message;
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_get_hub_descriptor:
2N/A */
2N/Astatic void
2N/Aohci_handle_get_hub_descriptor(
2N/A ohci_state_t *ohcip)
2N/A{
2N/A usb_ctrl_req_t *ctrl_reqp;
2N/A mblk_t *message;
2N/A usb_hub_descr_t *root_hub_descr;
2N/A size_t length;
2N/A uchar_t raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH];
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
2N/A root_hub_descr = &ohcip->ohci_root_hub.rh_descr;
2N/A length = ctrl_reqp->ctrl_wLength;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_get_hub_descriptor: Ctrl Req = 0x%p",
2N/A ctrl_reqp);
2N/A
2N/A message = ctrl_reqp->ctrl_data;
2N/A
2N/A ASSERT(message != NULL);
2N/A
2N/A bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH);
2N/A
2N/A raw_descr[0] = root_hub_descr->bDescLength;
2N/A raw_descr[1] = root_hub_descr->bDescriptorType;
2N/A raw_descr[2] = root_hub_descr->bNbrPorts;
2N/A raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00FF;
2N/A raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xFF00) >> 8;
2N/A raw_descr[5] = root_hub_descr->bPwrOn2PwrGood;
2N/A raw_descr[6] = root_hub_descr->bHubContrCurrent;
2N/A raw_descr[7] = root_hub_descr->DeviceRemovable;
2N/A raw_descr[8] = root_hub_descr->PortPwrCtrlMask;
2N/A
2N/A bcopy(raw_descr, message->b_wptr, length);
2N/A message->b_wptr += length;
2N/A
2N/A /* Save the data in control request */
2N/A ctrl_reqp->ctrl_data = message;
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_get_hub_status:
2N/A *
2N/A * Handle a get hub status request.
2N/A */
2N/Astatic void
2N/Aohci_handle_get_hub_status(
2N/A ohci_state_t *ohcip)
2N/A{
2N/A usb_ctrl_req_t *ctrl_reqp;
2N/A mblk_t *message;
2N/A uint_t new_root_hub_status;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
2N/A new_root_hub_status = Get_OpReg(hcr_rh_status);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_get_hub_status: new root hub status = 0x%x",
2N/A new_root_hub_status);
2N/A
2N/A message = ctrl_reqp->ctrl_data;
2N/A
2N/A ASSERT(message != NULL);
2N/A
2N/A *message->b_wptr++ = (uchar_t)new_root_hub_status;
2N/A *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 8);
2N/A *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 16);
2N/A *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 24);
2N/A
2N/A /* Save the data in control request */
2N/A ctrl_reqp->ctrl_data = message;
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_get_device_status:
2N/A *
2N/A * Handle a get device status request.
2N/A */
2N/Astatic void
2N/Aohci_handle_get_device_status(
2N/A ohci_state_t *ohcip)
2N/A{
2N/A usb_ctrl_req_t *ctrl_reqp;
2N/A mblk_t *message;
2N/A uint16_t dev_status;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
2N/A
2N/A /*
2N/A * OHCI doesn't have device status information.
2N/A * Simply return what is desired for the request.
2N/A */
2N/A dev_status = USB_DEV_SLF_PWRD_STATUS;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_get_device_status: device status = 0x%x",
2N/A dev_status);
2N/A
2N/A message = ctrl_reqp->ctrl_data;
2N/A
2N/A ASSERT(message != NULL);
2N/A
2N/A *message->b_wptr++ = (uchar_t)dev_status;
2N/A *message->b_wptr++ = (uchar_t)(dev_status >> 8);
2N/A
2N/A /* Save the data in control request */
2N/A ctrl_reqp->ctrl_data = message;
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_root_hub_pipe_start_intr_polling:
2N/A *
2N/A * Handle start polling on root hub interrupt pipe.
2N/A */
2N/A/* ARGSUSED */
2N/Aint
2N/Aohci_handle_root_hub_pipe_start_intr_polling(
2N/A usba_pipe_handle_data_t *ph,
2N/A usb_intr_req_t *client_intr_reqp,
2N/A usb_flags_t flags)
2N/A{
2N/A ohci_state_t *ohcip = ohci_obtain_state(
2N/A ph->p_usba_device->usb_root_hub_dip);
2N/A usb_ep_descr_t *eptd = &ph->p_ep;
2N/A int error = USB_SUCCESS;
2N/A uint_t pipe_state;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_start_intr_polling: "
2N/A "Root hub pipe start polling");
2N/A
2N/A ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
2N/A
2N/A ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
2N/A
2N/A /* ONE_XFER not supported for root hub interrupt pipe */
2N/A ASSERT((client_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) == 0);
2N/A
2N/A /* Get root hub intr pipe state */
2N/A pipe_state = ohcip->ohci_root_hub.rh_intr_pipe_state;
2N/A
2N/A switch (pipe_state) {
2N/A case OHCI_PIPE_STATE_IDLE:
2N/A ASSERT(ohcip->ohci_root_hub.rh_intr_pipe_timer_id == 0);
2N/A
2N/A /*
2N/A * Save the Original Client's Interrupt IN request
2N/A * information. We use this for final callback
2N/A */
2N/A ASSERT(ohcip->ohci_root_hub.rh_client_intr_reqp == NULL);
2N/A
2N/A ohcip->ohci_root_hub.rh_client_intr_reqp = client_intr_reqp;
2N/A
2N/A error = ohci_root_hub_allocate_intr_pipe_resource(ohcip, flags);
2N/A
2N/A if (error != USB_SUCCESS) {
2N/A /* Reset client interrupt request pointer */
2N/A ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
2N/A
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_start_intr_polling: "
2N/A "No Resources");
2N/A
2N/A return (error);
2N/A }
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_start_intr_polling: "
2N/A "Start polling for root hub successful");
2N/A
2N/A break;
2N/A case OHCI_PIPE_STATE_ACTIVE:
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_start_intr_polling: "
2N/A "Polling for root hub is already in progress");
2N/A
2N/A break;
2N/A default:
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_start_intr_polling: "
2N/A "Pipe is in error state 0x%x", pipe_state);
2N/A
2N/A error = USB_FAILURE;
2N/A
2N/A break;
2N/A }
2N/A
2N/A return (error);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_root_hub_pipe_stop_intr_polling:
2N/A *
2N/A * Handle stop polling on root hub intr pipe.
2N/A */
2N/A/* ARGSUSED */
2N/Avoid
2N/Aohci_handle_root_hub_pipe_stop_intr_polling(
2N/A usba_pipe_handle_data_t *ph,
2N/A usb_flags_t flags)
2N/A{
2N/A ohci_state_t *ohcip = ohci_obtain_state(
2N/A ph->p_usba_device->usb_root_hub_dip);
2N/A usb_ep_descr_t *eptd = &ph->p_ep;
2N/A
2N/A ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_pipe_stop_intr_polling: "
2N/A "Root hub pipe stop polling");
2N/A
2N/A ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
2N/A
2N/A if (ohcip->ohci_root_hub.rh_intr_pipe_state == OHCI_PIPE_STATE_ACTIVE) {
2N/A
2N/A ohcip->ohci_root_hub.rh_intr_pipe_state =
2N/A OHCI_PIPE_STATE_STOP_POLLING;
2N/A
2N/A /* Do interrupt pipe cleanup */
2N/A ohci_root_hub_intr_pipe_cleanup(ohcip, USB_CR_STOPPED_POLLING);
2N/A
2N/A ASSERT(ohcip->ohci_root_hub.
2N/A rh_intr_pipe_state == OHCI_PIPE_STATE_IDLE);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_hcdi_pipe_stop_intr_polling: Stop polling for root"
2N/A "hub successful");
2N/A } else {
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_hcdi_pipe_stop_intr_polling: "
2N/A "Polling for root hub is already stopped");
2N/A }
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_root_hub_allocate_intr_pipe_resource:
2N/A *
2N/A * Allocate interrupt requests and initialize them.
2N/A */
2N/Astatic int
2N/Aohci_root_hub_allocate_intr_pipe_resource(
2N/A ohci_state_t *ohcip,
2N/A usb_flags_t flags)
2N/A{
2N/A usba_pipe_handle_data_t *ph;
2N/A size_t length;
2N/A usb_intr_req_t *curr_intr_reqp;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_root_hub_allocate_intr_pipe_resource");
2N/A
2N/A ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
2N/A
2N/A /* Get the interrupt pipe handle */
2N/A ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
2N/A
2N/A /* Get the current interrupt request pointer */
2N/A curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
2N/A
2N/A /*
2N/A * If current interrupt request pointer is null,
2N/A * allocate new interrupt request.
2N/A */
2N/A if (curr_intr_reqp == NULL) {
2N/A ASSERT(ohcip->ohci_root_hub.rh_client_intr_reqp);
2N/A
2N/A /* Get the length of interrupt transfer */
2N/A length = ohcip->ohci_root_hub.
2N/A rh_client_intr_reqp->intr_len;
2N/A
2N/A curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
2N/A ohcip->ohci_root_hub.rh_client_intr_reqp,
2N/A length, flags);
2N/A
2N/A if (curr_intr_reqp == NULL) {
2N/A
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_root_hub_allocate_intr_pipe_resource:"
2N/A "Interrupt request structure allocation failed");
2N/A
2N/A return (USB_NO_RESOURCES);
2N/A }
2N/A
2N/A ohcip->ohci_root_hub.rh_curr_intr_reqp = curr_intr_reqp;
2N/A
2N/A mutex_enter(&ph->p_mutex);
2N/A ph->p_req_count++;
2N/A mutex_exit(&ph->p_mutex);
2N/A }
2N/A
2N/A /* Start the timer for the root hub interrupt pipe polling */
2N/A if (ohcip->ohci_root_hub.rh_intr_pipe_timer_id == 0) {
2N/A ohcip->ohci_root_hub.rh_intr_pipe_timer_id =
2N/A timeout(ohci_handle_root_hub_status_change,
2N/A (void *)ohcip, drv_usectohz(OHCI_RH_POLL_TIME));
2N/A
2N/A ohcip->ohci_root_hub.
2N/A rh_intr_pipe_state = OHCI_PIPE_STATE_ACTIVE;
2N/A }
2N/A
2N/A return (USB_SUCCESS);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_root_hub_intr_pipe_cleanup:
2N/A *
2N/A * Deallocate all interrupt requests and do callback
2N/A * the original client interrupt request.
2N/A */
2N/Astatic void
2N/Aohci_root_hub_intr_pipe_cleanup(
2N/A ohci_state_t *ohcip,
2N/A usb_cr_t completion_reason)
2N/A{
2N/A usb_intr_req_t *curr_intr_reqp;
2N/A usb_opaque_t client_intr_reqp;
2N/A timeout_id_t timer_id;
2N/A usba_pipe_handle_data_t *ph;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_root_hub_intr_pipe_cleanup");
2N/A
2N/A ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
2N/A
2N/A /* Get the interrupt pipe handle */
2N/A ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
2N/A
2N/A /* Get the interrupt timerid */
2N/A timer_id = ohcip->ohci_root_hub.rh_intr_pipe_timer_id;
2N/A
2N/A /* Stop the root hub interrupt timer */
2N/A if (timer_id) {
2N/A /* Reset the timer id to zero */
2N/A ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A (void) untimeout(timer_id);
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A }
2N/A
2N/A /* Reset the current interrupt request pointer */
2N/A curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
2N/A
2N/A /* Deallocate uncompleted interrupt request */
2N/A if (curr_intr_reqp) {
2N/A ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
2N/A usb_free_intr_req(curr_intr_reqp);
2N/A
2N/A mutex_enter(&ph->p_mutex);
2N/A ph->p_req_count--;
2N/A mutex_exit(&ph->p_mutex);
2N/A }
2N/A
2N/A client_intr_reqp = (usb_opaque_t)
2N/A ohcip->ohci_root_hub.rh_client_intr_reqp;
2N/A
2N/A /* Callback for original client interrupt request */
2N/A if (client_intr_reqp) {
2N/A ohci_root_hub_hcdi_callback(ph, completion_reason);
2N/A }
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_handle_root_hub_status_change:
2N/A *
2N/A * A root hub status change interrupt will occur any time there is a change
2N/A * in the root hub status register or one of the port status registers.
2N/A */
2N/Avoid
2N/Aohci_handle_root_hub_status_change(void *arg)
2N/A{
2N/A ohci_state_t *ohcip = (ohci_state_t *)arg;
2N/A usb_intr_req_t *curr_intr_reqp;
2N/A usb_port_mask_t all_ports_status = 0;
2N/A uint_t new_root_hub_status;
2N/A uint_t new_port_status;
2N/A uint_t change_status;
2N/A usb_hub_descr_t *hub_descr;
2N/A mblk_t *message;
2N/A size_t length;
2N/A usb_ep_descr_t *eptd;
2N/A usba_pipe_handle_data_t *ph;
2N/A int i;
2N/A
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_status_change: state = %d",
2N/A ohcip->ohci_root_hub.rh_intr_pipe_state);
2N/A
2N/A /* Get the pointer to root hub descriptor */
2N/A hub_descr = &ohcip->ohci_root_hub.rh_descr;
2N/A
2N/A /* Get the current interrupt request pointer */
2N/A curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
2N/A
2N/A ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
2N/A
2N/A /* Check whether timeout handler is valid */
2N/A if (ohcip->ohci_root_hub.rh_intr_pipe_timer_id) {
2N/A /* Check host controller is in operational state */
2N/A if ((ohci_state_is_operational(ohcip)) != USB_SUCCESS) {
2N/A
2N/A /* Reset the timer id */
2N/A ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
2N/A
2N/A /* Do interrupt pipe cleanup */
2N/A ohci_root_hub_intr_pipe_cleanup(
2N/A ohcip, USB_CR_HC_HARDWARE_ERR);
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A
2N/A return;
2N/A }
2N/A } else {
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A
2N/A return;
2N/A }
2N/A
2N/A eptd = &ohcip->ohci_root_hub.rh_intr_pipe_handle->p_ep;
2N/A
2N/A new_root_hub_status = Get_OpReg(hcr_rh_status);
2N/A
2N/A /* See if the root hub status has changed */
2N/A if ((new_root_hub_status & HCR_RH_STATUS_MASK) !=
2N/A ohcip->ohci_root_hub.rh_status) {
2N/A
2N/A USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_status_change: "
2N/A "Root hub status has changed!");
2N/A
2N/A all_ports_status = 1;
2N/A }
2N/A
2N/A /* Check each port */
2N/A for (i = 0; i < hub_descr->bNbrPorts; i++) {
2N/A new_port_status = Get_OpReg(hcr_rh_portstatus[i]);
2N/A change_status = new_port_status & HCR_PORT_CHNG_MASK;
2N/A
2N/A /*
2N/A * If there is change in the port status then set
2N/A * the bit in the bitmap of changes and inform hub
2N/A * driver about these changes. Hub driver will take
2N/A * care of these changes.
2N/A */
2N/A if (change_status) {
2N/A
2N/A /* See if a device was attached/detached */
2N/A if (change_status & HCR_PORT_CSC) {
2N/A /*
2N/A * Update the state depending on whether
2N/A * the port was attached or detached.
2N/A */
2N/A if (new_port_status & HCR_PORT_CCS) {
2N/A ohcip->ohci_root_hub.
2N/A rh_port_state[i] = DISABLED;
2N/A
2N/A USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
2N/A ohcip->ohci_log_hdl,
2N/A "Port %d connected", i+1);
2N/A } else {
2N/A ohcip->ohci_root_hub.
2N/A rh_port_state[i] = DISCONNECTED;
2N/A
2N/A USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
2N/A ohcip->ohci_log_hdl,
2N/A "Port %d disconnected", i+1);
2N/A }
2N/A }
2N/A
2N/A /* See if port enable status changed */
2N/A if (change_status & HCR_PORT_PESC) {
2N/A /*
2N/A * Update the state depending on whether
2N/A * the port was enabled or disabled.
2N/A */
2N/A if (new_port_status & HCR_PORT_PES) {
2N/A ohcip->ohci_root_hub.
2N/A rh_port_state[i] = ENABLED;
2N/A
2N/A USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
2N/A ohcip->ohci_log_hdl,
2N/A "Port %d enabled", i+1);
2N/A } else {
2N/A ohcip->ohci_root_hub.
2N/A rh_port_state[i] = DISABLED;
2N/A
2N/A USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
2N/A ohcip->ohci_log_hdl,
2N/A "Port %d disabled", i+1);
2N/A }
2N/A }
2N/A
2N/A all_ports_status |= 1 << (i + 1);
2N/A
2N/A /* Update the status */
2N/A ohcip->ohci_root_hub.
2N/A rh_port_status[i] = new_port_status;
2N/A }
2N/A }
2N/A
2N/A if (ph && all_ports_status && curr_intr_reqp) {
2N/A
2N/A length = eptd->wMaxPacketSize;
2N/A
2N/A ASSERT(length != 0);
2N/A
2N/A /* Get the message block */
2N/A message = curr_intr_reqp->intr_data;
2N/A
2N/A ASSERT(message != NULL);
2N/A
2N/A do {
2N/A /*
2N/A * check that mblk is big enough when we
2N/A * are writing bytes into it
2N/A */
2N/A if (message->b_wptr >= message->b_datap->db_lim) {
2N/A
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
2N/A ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_status_change: "
2N/A "mblk data overflow.");
2N/A
2N/A break;
2N/A }
2N/A
2N/A *message->b_wptr++ = (uchar_t)all_ports_status;
2N/A all_ports_status >>= 8;
2N/A } while (all_ports_status != 0);
2N/A
2N/A ohci_root_hub_hcdi_callback(ph, USB_CR_OK);
2N/A }
2N/A
2N/A /* Reset the timer id */
2N/A ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
2N/A
2N/A if (ohcip->ohci_root_hub.rh_intr_pipe_state == OHCI_PIPE_STATE_ACTIVE) {
2N/A /*
2N/A * If needed, allocate new interrupt request. Also
2N/A * start the timer for the root hub interrupt polling.
2N/A */
2N/A if ((ohci_root_hub_allocate_intr_pipe_resource(
2N/A ohcip, 0)) != USB_SUCCESS) {
2N/A
2N/A USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_handle_root_hub_status_change: No Resources");
2N/A
2N/A /* Do interrupt pipe cleanup */
2N/A ohci_root_hub_intr_pipe_cleanup(
2N/A ohcip, USB_CR_NO_RESOURCES);
2N/A }
2N/A }
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * ohci_root_hub_hcdi_callback()
2N/A *
2N/A * Convenience wrapper around usba_hcdi_cb() for the root hub.
2N/A */
2N/Astatic void
2N/Aohci_root_hub_hcdi_callback(
2N/A usba_pipe_handle_data_t *ph,
2N/A usb_cr_t completion_reason)
2N/A{
2N/A ohci_state_t *ohcip = ohci_obtain_state(
2N/A ph->p_usba_device->usb_root_hub_dip);
2N/A uchar_t attributes = ph->p_ep.bmAttributes &
2N/A USB_EP_ATTR_MASK;
2N/A usb_opaque_t curr_xfer_reqp;
2N/A uint_t pipe_state = 0;
2N/A
2N/A USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2N/A "ohci_root_hub_hcdi_callback: ph = 0x%p, cr = 0x%x",
2N/A ph, completion_reason);
2N/A
2N/A ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
2N/A
2N/A /* Set the pipe state as per completion reason */
2N/A switch (completion_reason) {
2N/A case USB_CR_OK:
2N/A switch (attributes) {
2N/A case USB_EP_ATTR_CONTROL:
2N/A pipe_state = OHCI_PIPE_STATE_IDLE;
2N/A break;
2N/A case USB_EP_ATTR_INTR:
2N/A pipe_state = ohcip->ohci_root_hub.rh_intr_pipe_state;
2N/A break;
2N/A }
2N/A break;
2N/A case USB_CR_NO_RESOURCES:
2N/A case USB_CR_NOT_SUPPORTED:
2N/A case USB_CR_STOPPED_POLLING:
2N/A case USB_CR_PIPE_RESET:
2N/A case USB_CR_HC_HARDWARE_ERR:
2N/A /* Set pipe state to idle */
2N/A pipe_state = OHCI_PIPE_STATE_IDLE;
2N/A break;
2N/A case USB_CR_PIPE_CLOSING:
2N/A break;
2N/A default:
2N/A /* Set pipe state to error */
2N/A pipe_state = OHCI_PIPE_STATE_ERROR;
2N/A break;
2N/A }
2N/A
2N/A switch (attributes) {
2N/A case USB_EP_ATTR_CONTROL:
2N/A curr_xfer_reqp = (usb_opaque_t)
2N/A ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
2N/A
2N/A ohcip->ohci_root_hub.rh_curr_ctrl_reqp = NULL;
2N/A ohcip->ohci_root_hub.rh_ctrl_pipe_state = pipe_state;
2N/A break;
2N/A case USB_EP_ATTR_INTR:
2N/A /* if curr_intr_reqp available then use this request */
2N/A if (ohcip->ohci_root_hub.rh_curr_intr_reqp) {
2N/A curr_xfer_reqp = (usb_opaque_t)
2N/A ohcip->ohci_root_hub.rh_curr_intr_reqp;
2N/A
2N/A ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
2N/A } else {
2N/A /* no current request, use client's request */
2N/A curr_xfer_reqp = (usb_opaque_t)
2N/A ohcip->ohci_root_hub.rh_client_intr_reqp;
2N/A
2N/A ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
2N/A }
2N/A
2N/A ohcip->ohci_root_hub.rh_intr_pipe_state = pipe_state;
2N/A break;
2N/A }
2N/A
2N/A ASSERT(curr_xfer_reqp != NULL);
2N/A
2N/A mutex_exit(&ohcip->ohci_int_mutex);
2N/A usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
2N/A mutex_enter(&ohcip->ohci_int_mutex);
2N/A}
2N/A