10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51458Syq193411 * Common Development and Distribution License (the "License").
61458Syq193411 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12819SVincent.Wang@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate * EHCI Host Controller Driver (EHCI)
270Sstevel@tonic-gate *
280Sstevel@tonic-gate * The EHCI driver is a software driver which interfaces to the Universal
290Sstevel@tonic-gate * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
300Sstevel@tonic-gate * the Host Controller is defined by the EHCI Host Controller Interface.
310Sstevel@tonic-gate *
320Sstevel@tonic-gate * This module contains the code for root hub related functions.
330Sstevel@tonic-gate *
340Sstevel@tonic-gate * NOTE:
350Sstevel@tonic-gate *
360Sstevel@tonic-gate * ONE_XFER is not supported on root hub interrupt polling
370Sstevel@tonic-gate */
380Sstevel@tonic-gate
390Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
400Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h>
410Sstevel@tonic-gate #include <sys/usb/usba/usba_types.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate /* Static function prototypes */
440Sstevel@tonic-gate static int ehci_handle_set_clear_port_feature(
450Sstevel@tonic-gate ehci_state_t *ehcip,
460Sstevel@tonic-gate uchar_t bRequest,
470Sstevel@tonic-gate uint16_t wValue,
480Sstevel@tonic-gate uint16_t port);
490Sstevel@tonic-gate static void ehci_handle_port_power(
500Sstevel@tonic-gate ehci_state_t *ehcip,
510Sstevel@tonic-gate uint16_t port,
520Sstevel@tonic-gate uint_t on);
530Sstevel@tonic-gate static void ehci_handle_port_enable(
540Sstevel@tonic-gate ehci_state_t *ehcip,
550Sstevel@tonic-gate uint16_t port,
560Sstevel@tonic-gate uint_t on);
570Sstevel@tonic-gate static void ehci_handle_clrchng_port_enable(
580Sstevel@tonic-gate ehci_state_t *ehcip,
590Sstevel@tonic-gate uint16_t port);
600Sstevel@tonic-gate static void ehci_handle_port_suspend(
610Sstevel@tonic-gate ehci_state_t *ehcip,
620Sstevel@tonic-gate uint16_t port,
630Sstevel@tonic-gate uint_t on);
640Sstevel@tonic-gate static void ehci_handle_clrchng_port_suspend(
650Sstevel@tonic-gate ehci_state_t *ehcip,
660Sstevel@tonic-gate uint16_t port);
670Sstevel@tonic-gate static void ehci_handle_port_reset(
680Sstevel@tonic-gate ehci_state_t *ehcip,
690Sstevel@tonic-gate uint16_t port);
700Sstevel@tonic-gate static void ehci_root_hub_reset_occured(
710Sstevel@tonic-gate ehci_state_t *ehcip);
720Sstevel@tonic-gate static void ehci_handle_complete_port_reset(
730Sstevel@tonic-gate ehci_state_t *ehcip,
740Sstevel@tonic-gate uint16_t port);
750Sstevel@tonic-gate static void ehci_handle_clear_port_connection(
760Sstevel@tonic-gate ehci_state_t *ehcip,
770Sstevel@tonic-gate uint16_t port);
780Sstevel@tonic-gate static void ehci_handle_clrchng_port_over_current(
790Sstevel@tonic-gate ehci_state_t *ehcip,
800Sstevel@tonic-gate uint16_t port);
810Sstevel@tonic-gate static void ehci_handle_get_port_status(
820Sstevel@tonic-gate ehci_state_t *ehcip,
830Sstevel@tonic-gate uint16_t port);
840Sstevel@tonic-gate static void ehci_handle_get_hub_descriptor(
850Sstevel@tonic-gate ehci_state_t *ehcip);
860Sstevel@tonic-gate static void ehci_handle_get_hub_status(
870Sstevel@tonic-gate ehci_state_t *ehcip);
881001Ssl147100 static void ehci_handle_get_device_status(
891001Ssl147100 ehci_state_t *ehcip);
900Sstevel@tonic-gate static uint_t ehci_get_root_hub_port_status(
910Sstevel@tonic-gate ehci_state_t *ehcip,
920Sstevel@tonic-gate uint16_t port);
930Sstevel@tonic-gate static int ehci_is_port_owner(
940Sstevel@tonic-gate ehci_state_t *ehcip,
950Sstevel@tonic-gate uint16_t port);
960Sstevel@tonic-gate static int ehci_root_hub_allocate_intr_pipe_resource(
970Sstevel@tonic-gate ehci_state_t *ehcip,
980Sstevel@tonic-gate usb_flags_t flags);
990Sstevel@tonic-gate static void ehci_root_hub_intr_pipe_cleanup(
1000Sstevel@tonic-gate ehci_state_t *ehcip,
1010Sstevel@tonic-gate usb_cr_t completion_reason);
1020Sstevel@tonic-gate static void ehci_handle_root_hub_status_change(void *arg);
1030Sstevel@tonic-gate static void ehci_root_hub_hcdi_callback(
1040Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1050Sstevel@tonic-gate usb_cr_t completion_reason);
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate * ehci_init_root_hub:
1100Sstevel@tonic-gate *
1110Sstevel@tonic-gate * Initialize the root hub
1120Sstevel@tonic-gate */
1130Sstevel@tonic-gate int
ehci_init_root_hub(ehci_state_t * ehcip)1140Sstevel@tonic-gate ehci_init_root_hub(ehci_state_t *ehcip)
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate usb_hub_descr_t *root_hub_descr =
1176898Sfb209375 &ehcip->ehci_root_hub.rh_descr;
1180Sstevel@tonic-gate uint_t i, length, port_state;
1190Sstevel@tonic-gate uint32_t capability;
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1220Sstevel@tonic-gate "ehci_init_root_hub:");
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate /* Read the EHCI capability register */
1250Sstevel@tonic-gate capability = Get_Cap(ehci_hcs_params);
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate /*
1280Sstevel@tonic-gate * Build the Root hub descriptor by looking EHCI capability
1290Sstevel@tonic-gate * and operational registers.
1300Sstevel@tonic-gate */
1310Sstevel@tonic-gate root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE;
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate if ((capability & EHCI_HCS_NUM_PORTS) > EHCI_MAX_RH_PORTS) {
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1360Sstevel@tonic-gate "ehci_init_root_hub: Invalid no of root hub ports 0x%x",
1370Sstevel@tonic-gate capability & EHCI_HCS_NUM_PORTS);
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate return (USB_FAILURE);
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate /* Obtain the number of downstream ports */
1430Sstevel@tonic-gate root_hub_descr->bNbrPorts = capability & EHCI_HCS_NUM_PORTS;
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate length = root_hub_descr->bNbrPorts / 8;
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate if (length) {
1480Sstevel@tonic-gate root_hub_descr->bDescLength = 7 + (2 * (length + 1));
1490Sstevel@tonic-gate } else {
1500Sstevel@tonic-gate root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH;
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate * Obtain the number of Classic or Companion USB 1.1 (OHCI/UHCI)
1550Sstevel@tonic-gate * Host Controllers information.
1560Sstevel@tonic-gate */
1570Sstevel@tonic-gate ehcip->ehci_root_hub.rh_companion_controllers = (capability &
1580Sstevel@tonic-gate EHCI_HCS_NUM_COMP_CTRLS) >> EHCI_HCS_NUM_COMP_CTRL_SHIFT;
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate /*
1610Sstevel@tonic-gate * Determine the Power Switching Mode
1620Sstevel@tonic-gate *
1630Sstevel@tonic-gate * EHCI Specification, root hub supports either no power switching
1640Sstevel@tonic-gate * individual port power switching. Also determine the Over-current
1650Sstevel@tonic-gate * Protection Mode.
1660Sstevel@tonic-gate */
1670Sstevel@tonic-gate if (capability & EHCI_HCS_PORT_POWER_CONTROL) {
1680Sstevel@tonic-gate /* Each port is powered individually */
1690Sstevel@tonic-gate root_hub_descr-> wHubCharacteristics =
1700Sstevel@tonic-gate HUB_CHARS_INDIVIDUAL_PORT_POWER;
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate /* Assume individual overcurrent reporting */
1730Sstevel@tonic-gate root_hub_descr->wHubCharacteristics |=
1740Sstevel@tonic-gate HUB_CHARS_INDIV_OVER_CURRENT;
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate /* Each port will start off in the POWERED_OFF mode */
1770Sstevel@tonic-gate port_state = POWERED_OFF;
1780Sstevel@tonic-gate } else {
1790Sstevel@tonic-gate /* The ports are powered when the ctlr is powered */
1800Sstevel@tonic-gate root_hub_descr->
1810Sstevel@tonic-gate wHubCharacteristics = HUB_CHARS_NO_POWER_SWITCHING;
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate /* Assume no overcurrent reporting */
1840Sstevel@tonic-gate root_hub_descr->wHubCharacteristics |=
1850Sstevel@tonic-gate HUB_CHARS_NO_OVER_CURRENT;
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate port_state = DISCONNECTED;
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate /* Look at the port indicator information */
1910Sstevel@tonic-gate if (capability & EHCI_HCS_PORT_INDICATOR) {
1920Sstevel@tonic-gate root_hub_descr->wHubCharacteristics |= HUB_CHARS_PORT_INDICATOR;
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate /*
1960Sstevel@tonic-gate * Obtain the power on to power good time of the ports.
1970Sstevel@tonic-gate *
1980Sstevel@tonic-gate * Assume: Zero for this field.
1990Sstevel@tonic-gate */
2000Sstevel@tonic-gate root_hub_descr->bPwrOn2PwrGood = 2;
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
2030Sstevel@tonic-gate "Power on to power good %d", root_hub_descr->bPwrOn2PwrGood);
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate /* Indicate if the device is removable */
2060Sstevel@tonic-gate root_hub_descr->DeviceRemovable = 0;
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate /* Set PortPowerControlMask to zero */
2090Sstevel@tonic-gate root_hub_descr->PortPwrCtrlMask = 0;
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate /* Set the state of each port and initialize the status */
2120Sstevel@tonic-gate for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate /* Initilize state/status of each root hub port */
2150Sstevel@tonic-gate ehcip->ehci_root_hub.rh_port_state[i] = port_state;
2160Sstevel@tonic-gate ehcip->ehci_root_hub.rh_port_status[i] = 0;
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate return (USB_SUCCESS);
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate /*
2240Sstevel@tonic-gate * ehci_load_root_hub_driver:
2250Sstevel@tonic-gate *
2260Sstevel@tonic-gate * Attach the root hub
2270Sstevel@tonic-gate */
2280Sstevel@tonic-gate static usb_dev_descr_t ehci_root_hub_device_descriptor = {
2290Sstevel@tonic-gate 0x12, /* bLength */
2300Sstevel@tonic-gate 0x01, /* bDescriptorType, Device */
2310Sstevel@tonic-gate 0x200, /* bcdUSB, v2.0 */
2320Sstevel@tonic-gate 0x09, /* bDeviceClass */
2330Sstevel@tonic-gate 0x00, /* bDeviceSubClass */
2340Sstevel@tonic-gate 0x01, /* bDeviceProtocol */
2350Sstevel@tonic-gate 0x40, /* bMaxPacketSize0 */
2360Sstevel@tonic-gate 0x00, /* idVendor */
2370Sstevel@tonic-gate 0x00, /* idProduct */
2380Sstevel@tonic-gate 0x00, /* bcdDevice */
2390Sstevel@tonic-gate 0x00, /* iManufacturer */
2400Sstevel@tonic-gate 0x00, /* iProduct */
2410Sstevel@tonic-gate 0x00, /* iSerialNumber */
2420Sstevel@tonic-gate 0x01 /* bNumConfigurations */
2430Sstevel@tonic-gate };
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate static uchar_t ehci_root_hub_config_descriptor[] = {
2460Sstevel@tonic-gate /* One configuartion */
2470Sstevel@tonic-gate 0x09, /* bLength */
2480Sstevel@tonic-gate 0x02, /* bDescriptorType, Configuartion */
2490Sstevel@tonic-gate 0x19, 0x00, /* wTotalLength */
2500Sstevel@tonic-gate 0x01, /* bNumInterfaces */
2510Sstevel@tonic-gate 0x01, /* bConfigurationValue */
2520Sstevel@tonic-gate 0x00, /* iConfiguration */
2530Sstevel@tonic-gate 0x40, /* bmAttributes */
2540Sstevel@tonic-gate 0x00, /* MaxPower */
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate /* One Interface */
2570Sstevel@tonic-gate 0x09, /* bLength */
2580Sstevel@tonic-gate 0x04, /* bDescriptorType, Interface */
2590Sstevel@tonic-gate 0x00, /* bInterfaceNumber */
2600Sstevel@tonic-gate 0x00, /* bAlternateSetting */
2610Sstevel@tonic-gate 0x01, /* bNumEndpoints */
2620Sstevel@tonic-gate 0x09, /* bInterfaceClass */
2630Sstevel@tonic-gate 0x01, /* bInterfaceSubClass */
2640Sstevel@tonic-gate 0x00, /* bInterfaceProtocol */
2650Sstevel@tonic-gate 0x00, /* iInterface */
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate /* One Endpoint (status change endpoint) */
2680Sstevel@tonic-gate 0x07, /* bLength */
2690Sstevel@tonic-gate 0x05, /* bDescriptorType, Endpoint */
2700Sstevel@tonic-gate 0x81, /* bEndpointAddress */
2710Sstevel@tonic-gate 0x03, /* bmAttributes */
2726898Sfb209375 0x01, 0x00, /* wMaxPacketSize, 1 + (EHCI_MAX_RH_PORTS / 8) */
2730Sstevel@tonic-gate 0xff /* bInterval */
2740Sstevel@tonic-gate };
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate int
ehci_load_root_hub_driver(ehci_state_t * ehcip)2770Sstevel@tonic-gate ehci_load_root_hub_driver(ehci_state_t *ehcip)
2780Sstevel@tonic-gate {
2790Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
2800Sstevel@tonic-gate "ehci_load_root_hub_driver:");
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate return (usba_hubdi_bind_root_hub(ehcip->ehci_dip,
2830Sstevel@tonic-gate ehci_root_hub_config_descriptor,
2840Sstevel@tonic-gate sizeof (ehci_root_hub_config_descriptor),
2850Sstevel@tonic-gate &ehci_root_hub_device_descriptor));
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate * ehci_unload_root_hub_driver:
2910Sstevel@tonic-gate */
2920Sstevel@tonic-gate int
ehci_unload_root_hub_driver(ehci_state_t * ehcip)2930Sstevel@tonic-gate ehci_unload_root_hub_driver(ehci_state_t *ehcip)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
2960Sstevel@tonic-gate "ehci_unload_root_hub_driver:");
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate return (usba_hubdi_unbind_root_hub(ehcip->ehci_dip));
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate /*
3030Sstevel@tonic-gate * ehci_handle_root_hub_pipe_open:
3040Sstevel@tonic-gate *
3050Sstevel@tonic-gate * Handle opening of control and interrupt pipes on root hub.
3060Sstevel@tonic-gate */
3070Sstevel@tonic-gate /* ARGSUSED */
3080Sstevel@tonic-gate int
ehci_handle_root_hub_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)3090Sstevel@tonic-gate ehci_handle_root_hub_pipe_open(
3100Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
3110Sstevel@tonic-gate usb_flags_t usb_flags)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
3146898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
3150Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3180Sstevel@tonic-gate "ehci_handle_root_hub_pipe_open: Root hub pipe open");
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
3230Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
3240Sstevel@tonic-gate /* Save control pipe handle */
3250Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_handle = ph;
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate /* Set state of the root hub control pipe as idle */
3280Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_IDLE;
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_ctrl_reqp = NULL;
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3330Sstevel@tonic-gate "ehci_handle_root_hub_pipe_open: Root hub control "
3340Sstevel@tonic-gate "pipe open succeeded");
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate break;
3370Sstevel@tonic-gate case USB_EP_ATTR_INTR:
3380Sstevel@tonic-gate /* Save interrupt pipe handle */
3390Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_handle = ph;
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate /* Set state of the root hub interrupt pipe as idle */
3420Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_state = EHCI_PIPE_STATE_IDLE;
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp = NULL;
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL;
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3490Sstevel@tonic-gate "ehci_handle_root_hub_pipe_open: Root hub interrupt "
3500Sstevel@tonic-gate "pipe open succeeded");
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate break;
3530Sstevel@tonic-gate default:
3540Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3550Sstevel@tonic-gate "ehci_handle_root_hub_pipe_open: Root hub pipe open"
3560Sstevel@tonic-gate "failed");
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate return (USB_FAILURE);
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate ehcip->ehci_open_pipe_count++;
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate return (USB_SUCCESS);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate /*
3680Sstevel@tonic-gate * ehci_handle_root_hub_pipe_close:
3690Sstevel@tonic-gate *
3700Sstevel@tonic-gate * Handle closing of control and interrupt pipes on root hub.
3710Sstevel@tonic-gate */
3720Sstevel@tonic-gate /* ARGSUSED */
3730Sstevel@tonic-gate int
ehci_handle_root_hub_pipe_close(usba_pipe_handle_data_t * ph)3740Sstevel@tonic-gate ehci_handle_root_hub_pipe_close(usba_pipe_handle_data_t *ph)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
3776898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
3780Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3810Sstevel@tonic-gate "ehci_handle_root_hub_pipe_close: Root hub pipe close");
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
3860Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
3870Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.
3880Sstevel@tonic-gate rh_ctrl_pipe_state != EHCI_PIPE_STATE_CLOSE);
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate /* Set state of the root hub control pipe as close */
3910Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_CLOSE;
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate /* Set root hub control pipe handle to null */
3940Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_handle = NULL;
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3970Sstevel@tonic-gate "ehci_handle_root_hub_pipe_close: "
3980Sstevel@tonic-gate "Root hub control pipe close succeeded");
3990Sstevel@tonic-gate break;
4000Sstevel@tonic-gate case USB_EP_ATTR_INTR:
4010Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.
4040Sstevel@tonic-gate rh_intr_pipe_state != EHCI_PIPE_STATE_CLOSE);
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate /* Set state of the root hub interrupt pipe as close */
4070Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_state = EHCI_PIPE_STATE_CLOSE;
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate /* Do interrupt pipe cleanup */
4100Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_PIPE_CLOSING);
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate /* Set root hub interrupt pipe handle to null */
4130Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_handle = NULL;
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4160Sstevel@tonic-gate "ehci_handle_root_hub_pipe_close: "
4170Sstevel@tonic-gate "Root hub interrupt pipe close succeeded");
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate break;
4200Sstevel@tonic-gate default:
4210Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4220Sstevel@tonic-gate "ehci_handle_root_hub_pipe_close: "
4230Sstevel@tonic-gate "Root hub pipe close failed");
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate return (USB_FAILURE);
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate ehcip->ehci_open_pipe_count--;
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate return (USB_SUCCESS);
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate /*
4350Sstevel@tonic-gate * ehci_handle_root_hub_pipe_reset:
4360Sstevel@tonic-gate *
4370Sstevel@tonic-gate * Handle resetting of control and interrupt pipes on root hub.
4380Sstevel@tonic-gate */
4390Sstevel@tonic-gate /* ARGSUSED */
4400Sstevel@tonic-gate int
ehci_handle_root_hub_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)4410Sstevel@tonic-gate ehci_handle_root_hub_pipe_reset(
4420Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
4430Sstevel@tonic-gate usb_flags_t usb_flags)
4440Sstevel@tonic-gate {
4450Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
4466898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
4470Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
4480Sstevel@tonic-gate int error = USB_SUCCESS;
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4510Sstevel@tonic-gate "ehci_handle_root_hub_pipe_reset: Root hub pipe reset");
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
4560Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
4570Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_IDLE;
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4600Sstevel@tonic-gate "ehci_handle_root_hub_pipe_reset: Pipe reset"
4610Sstevel@tonic-gate "for the root hub control pipe successful");
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate break;
4640Sstevel@tonic-gate case USB_EP_ATTR_INTR:
4650Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate if ((ehcip->ehci_root_hub.rh_client_intr_reqp) &&
4680Sstevel@tonic-gate (ehcip->ehci_root_hub.rh_intr_pipe_state !=
4690Sstevel@tonic-gate EHCI_PIPE_STATE_IDLE)) {
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate ehcip->ehci_root_hub.
4720Sstevel@tonic-gate rh_intr_pipe_state = EHCI_PIPE_STATE_RESET;
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate /* Do interrupt pipe cleanup */
4750Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(
4760Sstevel@tonic-gate ehcip, USB_CR_PIPE_RESET);
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate
4790Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.
4800Sstevel@tonic-gate rh_intr_pipe_state == EHCI_PIPE_STATE_IDLE);
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4830Sstevel@tonic-gate "ehci_handle_root_hub_pipe_reset: "
4840Sstevel@tonic-gate "Pipe reset for root hub interrupt pipe successful");
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate break;
4870Sstevel@tonic-gate default:
4880Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4890Sstevel@tonic-gate "ehci_handle_root_hub_pipe_reset: "
4900Sstevel@tonic-gate "Root hub pipe reset failed");
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate error = USB_FAILURE;
4930Sstevel@tonic-gate break;
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate return (error);
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate /*
5030Sstevel@tonic-gate * ehci_handle_root_hub_request:
5040Sstevel@tonic-gate *
5050Sstevel@tonic-gate * Intercept a root hub request. Handle the root hub request through the
5060Sstevel@tonic-gate * registers
5070Sstevel@tonic-gate */
5080Sstevel@tonic-gate /* ARGSUSED */
5090Sstevel@tonic-gate int
ehci_handle_root_hub_request(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp)5100Sstevel@tonic-gate ehci_handle_root_hub_request(
5110Sstevel@tonic-gate ehci_state_t *ehcip,
5120Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
5130Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp)
5140Sstevel@tonic-gate {
5150Sstevel@tonic-gate uchar_t bmRequestType = ctrl_reqp->ctrl_bmRequestType;
5160Sstevel@tonic-gate uchar_t bRequest = ctrl_reqp->ctrl_bRequest;
5170Sstevel@tonic-gate uint16_t wValue = ctrl_reqp->ctrl_wValue;
5180Sstevel@tonic-gate uint16_t wIndex = ctrl_reqp->ctrl_wIndex;
5190Sstevel@tonic-gate uint16_t wLength = ctrl_reqp->ctrl_wLength;
5200Sstevel@tonic-gate mblk_t *data = ctrl_reqp->ctrl_data;
5210Sstevel@tonic-gate uint16_t port = wIndex - 1;
5220Sstevel@tonic-gate usb_cr_t completion_reason;
5230Sstevel@tonic-gate int error = USB_SUCCESS;
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
5260Sstevel@tonic-gate "ehci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p",
5270Sstevel@tonic-gate bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data);
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate if (ehcip->ehci_root_hub.
5320Sstevel@tonic-gate rh_ctrl_pipe_state != EHCI_PIPE_STATE_IDLE) {
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
5350Sstevel@tonic-gate "ehci_handle_root_hub_request: Pipe is not idle");
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate return (USB_FAILURE);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate /* Save the current control request pointer */
5430Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_ctrl_reqp = ctrl_reqp;
5440Sstevel@tonic-gate
5450Sstevel@tonic-gate /* Set pipe state to active */
5460Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_ACTIVE;
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
5490Sstevel@tonic-gate
5500Sstevel@tonic-gate switch (bmRequestType) {
5511001Ssl147100 case HUB_GET_DEVICE_STATUS_TYPE:
5521001Ssl147100 ehci_handle_get_device_status(ehcip);
5531001Ssl147100 break;
5541001Ssl147100 case HUB_HANDLE_PORT_FEATURE_TYPE:
5550Sstevel@tonic-gate error = ehci_handle_set_clear_port_feature(ehcip,
5560Sstevel@tonic-gate bRequest, wValue, port);
5570Sstevel@tonic-gate break;
5581001Ssl147100 case HUB_GET_PORT_STATUS_TYPE:
5590Sstevel@tonic-gate ehci_handle_get_port_status(ehcip, port);
5600Sstevel@tonic-gate break;
5611001Ssl147100 case HUB_CLASS_REQ_TYPE:
5620Sstevel@tonic-gate switch (bRequest) {
5630Sstevel@tonic-gate case USB_REQ_GET_STATUS:
5640Sstevel@tonic-gate ehci_handle_get_hub_status(ehcip);
5650Sstevel@tonic-gate break;
5660Sstevel@tonic-gate case USB_REQ_GET_DESCR:
5670Sstevel@tonic-gate ehci_handle_get_hub_descriptor(ehcip);
5680Sstevel@tonic-gate break;
5690Sstevel@tonic-gate default:
5700Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
5710Sstevel@tonic-gate "ehci_handle_root_hub_request:"
5720Sstevel@tonic-gate "Unsupported request 0x%x", bRequest);
5730Sstevel@tonic-gate
5740Sstevel@tonic-gate error = USB_FAILURE;
5750Sstevel@tonic-gate break;
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate break;
5780Sstevel@tonic-gate default:
5790Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
5800Sstevel@tonic-gate "ehci_handle_root_hub_request: "
5810Sstevel@tonic-gate "Unsupported request 0x%x", bmRequestType);
5820Sstevel@tonic-gate
5830Sstevel@tonic-gate error = USB_FAILURE;
5840Sstevel@tonic-gate break;
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate completion_reason = (error) ? USB_CR_NOT_SUPPORTED : USB_CR_OK;
5880Sstevel@tonic-gate
5890Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
5900Sstevel@tonic-gate ehci_root_hub_hcdi_callback(ph, completion_reason);
5910Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
5940Sstevel@tonic-gate "ehci_handle_root_hub_request: error = %d", error);
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate return (USB_SUCCESS);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate
6000Sstevel@tonic-gate /*
6010Sstevel@tonic-gate * ehci_handle_set_clear_port_feature:
6020Sstevel@tonic-gate */
6030Sstevel@tonic-gate static int
ehci_handle_set_clear_port_feature(ehci_state_t * ehcip,uchar_t bRequest,uint16_t wValue,uint16_t port)6040Sstevel@tonic-gate ehci_handle_set_clear_port_feature(
6050Sstevel@tonic-gate ehci_state_t *ehcip,
6060Sstevel@tonic-gate uchar_t bRequest,
6070Sstevel@tonic-gate uint16_t wValue,
6080Sstevel@tonic-gate uint16_t port)
6090Sstevel@tonic-gate {
6100Sstevel@tonic-gate int error = USB_SUCCESS;
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
6130Sstevel@tonic-gate "ehci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x",
6140Sstevel@tonic-gate bRequest, wValue, port);
6150Sstevel@tonic-gate
6160Sstevel@tonic-gate switch (bRequest) {
6170Sstevel@tonic-gate case USB_REQ_SET_FEATURE:
6180Sstevel@tonic-gate switch (wValue) {
6190Sstevel@tonic-gate case CFS_PORT_ENABLE:
6200Sstevel@tonic-gate ehci_handle_port_enable(ehcip, port, 1);
6210Sstevel@tonic-gate break;
6220Sstevel@tonic-gate case CFS_PORT_SUSPEND:
6230Sstevel@tonic-gate ehci_handle_port_suspend(ehcip, port, 1);
6240Sstevel@tonic-gate break;
6250Sstevel@tonic-gate case CFS_PORT_RESET:
6260Sstevel@tonic-gate ehci_handle_port_reset(ehcip, port);
6270Sstevel@tonic-gate break;
6280Sstevel@tonic-gate case CFS_PORT_POWER:
6290Sstevel@tonic-gate ehci_handle_port_power(ehcip, port, 1);
6300Sstevel@tonic-gate break;
6310Sstevel@tonic-gate default:
6320Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
6330Sstevel@tonic-gate "ehci_handle_set_clear_port_feature: "
6340Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate error = USB_FAILURE;
6370Sstevel@tonic-gate break;
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate break;
6400Sstevel@tonic-gate case USB_REQ_CLEAR_FEATURE:
6410Sstevel@tonic-gate switch (wValue) {
6420Sstevel@tonic-gate case CFS_PORT_ENABLE:
6430Sstevel@tonic-gate ehci_handle_port_enable(ehcip, port, 0);
6440Sstevel@tonic-gate break;
6450Sstevel@tonic-gate case CFS_C_PORT_ENABLE:
6460Sstevel@tonic-gate ehci_handle_clrchng_port_enable(ehcip, port);
6470Sstevel@tonic-gate break;
6480Sstevel@tonic-gate case CFS_PORT_SUSPEND:
6490Sstevel@tonic-gate ehci_handle_port_suspend(ehcip, port, 0);
6500Sstevel@tonic-gate break;
6510Sstevel@tonic-gate case CFS_C_PORT_SUSPEND:
6520Sstevel@tonic-gate ehci_handle_clrchng_port_suspend(ehcip, port);
6530Sstevel@tonic-gate break;
6540Sstevel@tonic-gate case CFS_C_PORT_RESET:
6550Sstevel@tonic-gate ehci_handle_complete_port_reset(ehcip, port);
6560Sstevel@tonic-gate break;
6570Sstevel@tonic-gate case CFS_PORT_POWER:
6580Sstevel@tonic-gate ehci_handle_port_power(ehcip, port, 0);
6590Sstevel@tonic-gate break;
6600Sstevel@tonic-gate case CFS_C_PORT_CONNECTION:
6610Sstevel@tonic-gate ehci_handle_clear_port_connection(ehcip, port);
6620Sstevel@tonic-gate break;
6630Sstevel@tonic-gate case CFS_C_PORT_OVER_CURRENT:
6640Sstevel@tonic-gate ehci_handle_clrchng_port_over_current(ehcip, port);
6650Sstevel@tonic-gate break;
6660Sstevel@tonic-gate default:
6670Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
6680Sstevel@tonic-gate "ehci_handle_set_clear_port_feature: "
6690Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
6700Sstevel@tonic-gate
6710Sstevel@tonic-gate error = USB_FAILURE;
6720Sstevel@tonic-gate break;
6730Sstevel@tonic-gate }
6746898Sfb209375 break;
6750Sstevel@tonic-gate default:
6760Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
6770Sstevel@tonic-gate "ehci_handle_set_clear_port_feature: "
6780Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate error = USB_FAILURE;
6810Sstevel@tonic-gate break;
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate return (error);
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate /*
6890Sstevel@tonic-gate * ehci_handle_port_power:
6900Sstevel@tonic-gate *
6910Sstevel@tonic-gate * Turn on a root hub port.
6920Sstevel@tonic-gate */
6930Sstevel@tonic-gate static void
ehci_handle_port_power(ehci_state_t * ehcip,uint16_t port,uint_t on)6940Sstevel@tonic-gate ehci_handle_port_power(
6950Sstevel@tonic-gate ehci_state_t *ehcip,
6960Sstevel@tonic-gate uint16_t port,
6970Sstevel@tonic-gate uint_t on)
6980Sstevel@tonic-gate {
6990Sstevel@tonic-gate uint_t port_status;
7000Sstevel@tonic-gate ehci_root_hub_t *rh;
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
7050Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate rh = &ehcip->ehci_root_hub;
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
7100Sstevel@tonic-gate "ehci_handle_port_power: port = 0x%x status = 0x%x on = %d",
7110Sstevel@tonic-gate port, port_status, on);
7120Sstevel@tonic-gate
7130Sstevel@tonic-gate /* Check port is owned by ehci */
7140Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
7150Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
7160Sstevel@tonic-gate
7170Sstevel@tonic-gate return;
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate if (on) {
7210Sstevel@tonic-gate /* See if the port power is already on */
7220Sstevel@tonic-gate if (!(port_status & EHCI_RH_PORT_POWER)) {
7230Sstevel@tonic-gate /* Turn the port on */
7240Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
7250Sstevel@tonic-gate port_status | EHCI_RH_PORT_POWER);
7260Sstevel@tonic-gate }
7270Sstevel@tonic-gate
7280Sstevel@tonic-gate rh->rh_port_status[port] = 0;
7290Sstevel@tonic-gate rh->rh_port_state[port] = DISCONNECTED;
7300Sstevel@tonic-gate } else {
7310Sstevel@tonic-gate /* See if the port power is already OFF */
7320Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_POWER) {
7330Sstevel@tonic-gate /* Turn-off the port */
7340Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
7350Sstevel@tonic-gate port_status & ~EHCI_RH_PORT_POWER);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate rh->rh_port_status[port] = 0;
7390Sstevel@tonic-gate rh->rh_port_state[port] = POWERED_OFF;
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate
7420Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
7430Sstevel@tonic-gate "ehci_handle_port_power done: port = 0x%x status = 0x%x on = %d",
7440Sstevel@tonic-gate port, Get_OpReg(ehci_rh_port_status[port]), on);
7450Sstevel@tonic-gate
7460Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
7470Sstevel@tonic-gate }
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate
7500Sstevel@tonic-gate /*
7510Sstevel@tonic-gate * ehci_handle_port_enable:
7520Sstevel@tonic-gate *
7530Sstevel@tonic-gate * Handle port enable request.
7540Sstevel@tonic-gate */
7550Sstevel@tonic-gate static void
ehci_handle_port_enable(ehci_state_t * ehcip,uint16_t port,uint_t on)7560Sstevel@tonic-gate ehci_handle_port_enable(
7570Sstevel@tonic-gate ehci_state_t *ehcip,
7580Sstevel@tonic-gate uint16_t port,
7590Sstevel@tonic-gate uint_t on)
7600Sstevel@tonic-gate {
7610Sstevel@tonic-gate uint_t port_status;
7620Sstevel@tonic-gate
7630Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
7660Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
7670Sstevel@tonic-gate
7680Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
7690Sstevel@tonic-gate "ehci_handle_port_enable: port = 0x%x, status = 0x%x",
7700Sstevel@tonic-gate port, port_status);
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate /* Check port is owned by ehci */
7730Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
7740Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
7750Sstevel@tonic-gate
7760Sstevel@tonic-gate return;
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate if (on) {
7800Sstevel@tonic-gate /* See if the port enable is already on */
7810Sstevel@tonic-gate if (!(port_status & EHCI_RH_PORT_ENABLE)) {
7820Sstevel@tonic-gate /* Enable the port */
7830Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
7840Sstevel@tonic-gate port_status | EHCI_RH_PORT_ENABLE);
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate } else {
7870Sstevel@tonic-gate /* See if the port enable is already off */
7880Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_ENABLE) {
7890Sstevel@tonic-gate /* Disable the port */
7900Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
7910Sstevel@tonic-gate port_status & ~EHCI_RH_PORT_ENABLE);
7920Sstevel@tonic-gate }
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate
7950Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate
7990Sstevel@tonic-gate /*
8000Sstevel@tonic-gate * ehci_handle_clrchng_port_enable:
8010Sstevel@tonic-gate *
8020Sstevel@tonic-gate * Handle clear port enable change bit.
8030Sstevel@tonic-gate */
8040Sstevel@tonic-gate static void
ehci_handle_clrchng_port_enable(ehci_state_t * ehcip,uint16_t port)8050Sstevel@tonic-gate ehci_handle_clrchng_port_enable(
8060Sstevel@tonic-gate ehci_state_t *ehcip,
8070Sstevel@tonic-gate uint16_t port)
8080Sstevel@tonic-gate {
8090Sstevel@tonic-gate uint_t port_status;
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
8140Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
8150Sstevel@tonic-gate
8160Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
8170Sstevel@tonic-gate "ehci_handle_port_enable: port = 0x%x, status = 0x%x",
8180Sstevel@tonic-gate port, port_status);
8190Sstevel@tonic-gate
8200Sstevel@tonic-gate /* Check port is owned by ehci */
8210Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
8220Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate return;
8250Sstevel@tonic-gate }
8260Sstevel@tonic-gate
8270Sstevel@tonic-gate /* Clear the PortEnableStatusChange Bit */
8280Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
8290Sstevel@tonic-gate port_status | EHCI_RH_PORT_ENABLE_CHANGE);
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate
8350Sstevel@tonic-gate /*
8360Sstevel@tonic-gate * ehci_handle_port_suspend:
8370Sstevel@tonic-gate *
8380Sstevel@tonic-gate * Handle port suspend/resume request.
8390Sstevel@tonic-gate */
8400Sstevel@tonic-gate static void
ehci_handle_port_suspend(ehci_state_t * ehcip,uint16_t port,uint_t on)8410Sstevel@tonic-gate ehci_handle_port_suspend(
8420Sstevel@tonic-gate ehci_state_t *ehcip,
8430Sstevel@tonic-gate uint16_t port,
8440Sstevel@tonic-gate uint_t on)
8450Sstevel@tonic-gate {
8460Sstevel@tonic-gate uint_t port_status;
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
8490Sstevel@tonic-gate
8500Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
8510Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
8520Sstevel@tonic-gate
8530Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
8540Sstevel@tonic-gate "ehci_handle_port_suspend: port = 0x%x, status = 0x%x",
8550Sstevel@tonic-gate port, port_status);
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate /* Check port is owned by ehci */
8580Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
8590Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate return;
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate
8640Sstevel@tonic-gate if (on) {
8650Sstevel@tonic-gate /*
8660Sstevel@tonic-gate * Suspend port only if port is enabled and
8670Sstevel@tonic-gate * it is not already in suspend state.
8680Sstevel@tonic-gate */
8690Sstevel@tonic-gate if ((port_status & EHCI_RH_PORT_ENABLE) &&
8700Sstevel@tonic-gate (!(port_status & EHCI_RH_PORT_SUSPEND))) {
8710Sstevel@tonic-gate /* Suspend the port */
8720Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
8730Sstevel@tonic-gate port_status | EHCI_RH_PORT_SUSPEND);
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate /* Wait 10ms for port move to suspend state */
8780Sstevel@tonic-gate delay(drv_usectohz(EHCI_PORT_SUSPEND_TIMEWAIT));
8790Sstevel@tonic-gate
8800Sstevel@tonic-gate return;
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate } else {
8830Sstevel@tonic-gate /* Perform resume only if port is in suspend state */
8840Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_SUSPEND) {
8850Sstevel@tonic-gate /* Resume the port */
8860Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
8870Sstevel@tonic-gate port_status | EHCI_RH_PORT_RESUME);
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate }
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate /*
8960Sstevel@tonic-gate * ehci_handle_clrchng_port_suspend:
8970Sstevel@tonic-gate *
8980Sstevel@tonic-gate * Handle port clear port suspend change bit.
8990Sstevel@tonic-gate */
9000Sstevel@tonic-gate static void
ehci_handle_clrchng_port_suspend(ehci_state_t * ehcip,uint16_t port)9010Sstevel@tonic-gate ehci_handle_clrchng_port_suspend(
9020Sstevel@tonic-gate ehci_state_t *ehcip,
9030Sstevel@tonic-gate uint16_t port)
9040Sstevel@tonic-gate {
9050Sstevel@tonic-gate uint_t port_status;
90610039SPengcheng.Chen@Sun.COM int i;
9070Sstevel@tonic-gate
9080Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
9090Sstevel@tonic-gate
9100Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
9110Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
9140Sstevel@tonic-gate "ehci_handle_clrchng_port_suspend: port = 0x%x, "
9150Sstevel@tonic-gate "status = 0x%x", port, port_status);
9160Sstevel@tonic-gate
9170Sstevel@tonic-gate /* Check port is owned by ehci */
9180Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
9190Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate return;
9220Sstevel@tonic-gate }
9230Sstevel@tonic-gate
9240Sstevel@tonic-gate /* Return if port is not in resume state */
9250Sstevel@tonic-gate if (!(port_status & EHCI_RH_PORT_RESUME)) {
9260Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate return;
9290Sstevel@tonic-gate }
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
9320Sstevel@tonic-gate
9330Sstevel@tonic-gate /* Wait for 20ms to terminate resume */
9340Sstevel@tonic-gate delay(drv_usectohz(EHCI_PORT_RESUME_TIMEWAIT));
9350Sstevel@tonic-gate
9360Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
9370Sstevel@tonic-gate
9380Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
9390Sstevel@tonic-gate port_status & ~EHCI_RH_PORT_RESUME);
9400Sstevel@tonic-gate
9410Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
9420Sstevel@tonic-gate
94310039SPengcheng.Chen@Sun.COM /*
94410039SPengcheng.Chen@Sun.COM * Wait for port to return to high speed mode. It's necessary to poll
94510039SPengcheng.Chen@Sun.COM * for resume completion for some high-speed devices to work correctly.
94610039SPengcheng.Chen@Sun.COM */
94710039SPengcheng.Chen@Sun.COM for (i = 0; i < EHCI_PORT_RESUME_RETRY_MAX; i++) {
94810039SPengcheng.Chen@Sun.COM delay(drv_usectohz(EHCI_PORT_RESUME_COMP_TIMEWAIT));
94910039SPengcheng.Chen@Sun.COM
95010039SPengcheng.Chen@Sun.COM mutex_enter(&ehcip->ehci_int_mutex);
95110039SPengcheng.Chen@Sun.COM port_status = Get_OpReg(ehci_rh_port_status[port]) &
95210039SPengcheng.Chen@Sun.COM ~EHCI_RH_PORT_CLEAR_MASK;
95310039SPengcheng.Chen@Sun.COM mutex_exit(&ehcip->ehci_int_mutex);
95410039SPengcheng.Chen@Sun.COM
95510039SPengcheng.Chen@Sun.COM if (!(port_status & EHCI_RH_PORT_RESUME)) {
95610039SPengcheng.Chen@Sun.COM break;
95710039SPengcheng.Chen@Sun.COM }
95810039SPengcheng.Chen@Sun.COM }
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate
9610Sstevel@tonic-gate
9620Sstevel@tonic-gate /*
9630Sstevel@tonic-gate * ehci_handle_port_reset:
9640Sstevel@tonic-gate *
9650Sstevel@tonic-gate * Perform a port reset.
9660Sstevel@tonic-gate */
9670Sstevel@tonic-gate static void
ehci_handle_port_reset(ehci_state_t * ehcip,uint16_t port)9680Sstevel@tonic-gate ehci_handle_port_reset(
9690Sstevel@tonic-gate ehci_state_t *ehcip,
9700Sstevel@tonic-gate uint16_t port)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate ehci_root_hub_t *rh;
9730Sstevel@tonic-gate uint_t port_status;
97410039SPengcheng.Chen@Sun.COM int i;
9750Sstevel@tonic-gate
9760Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate /* Get the root hub structure */
9790Sstevel@tonic-gate rh = &ehcip->ehci_root_hub;
9800Sstevel@tonic-gate
9810Sstevel@tonic-gate /* Get the port status information */
9820Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
9830Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
9840Sstevel@tonic-gate
9850Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
9860Sstevel@tonic-gate "ehci_handle_port_reset: port = 0x%x status = 0x%x",
9870Sstevel@tonic-gate port, port_status);
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate /* Check port is owned by ehci */
9900Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
9910Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
9920Sstevel@tonic-gate
9930Sstevel@tonic-gate return;
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate
9960Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_LOW_SPEED) {
9970Sstevel@tonic-gate /* Check for classic or companion host controllers */
9980Sstevel@tonic-gate if (rh->rh_companion_controllers) {
9990Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
10000Sstevel@tonic-gate "ehci_handle_port_reset: Low speed device "
10010Sstevel@tonic-gate "and handover this port to Companion controller");
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
10040Sstevel@tonic-gate port_status | EHCI_RH_PORT_OWNER_CLASSIC);
10050Sstevel@tonic-gate } else {
10060Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
10070Sstevel@tonic-gate "Low speed device is not supported");
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate } else {
10100Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
10110Sstevel@tonic-gate ((port_status | EHCI_RH_PORT_RESET) &
10120Sstevel@tonic-gate ~EHCI_RH_PORT_ENABLE));
10130Sstevel@tonic-gate
10140Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
10150Sstevel@tonic-gate
101610039SPengcheng.Chen@Sun.COM /* Wait 50ms for reset to complete */
10170Sstevel@tonic-gate delay(drv_usectohz(EHCI_PORT_RESET_TIMEWAIT));
10180Sstevel@tonic-gate
10190Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
10200Sstevel@tonic-gate
10210Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
10220Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
10250Sstevel@tonic-gate (port_status & ~EHCI_RH_PORT_RESET));
10260Sstevel@tonic-gate
10270Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
10280Sstevel@tonic-gate
10290Sstevel@tonic-gate /*
103010039SPengcheng.Chen@Sun.COM * Wait for hardware to enable this port, if the connected
103110039SPengcheng.Chen@Sun.COM * usb device is high speed. It's necessary to poll for reset
103210039SPengcheng.Chen@Sun.COM * completion for some high-speed devices to recognized
103310039SPengcheng.Chen@Sun.COM * correctly.
10340Sstevel@tonic-gate */
103510039SPengcheng.Chen@Sun.COM for (i = 0; i < EHCI_PORT_RESET_RETRY_MAX; i++) {
103610039SPengcheng.Chen@Sun.COM delay(drv_usectohz(EHCI_PORT_RESET_COMP_TIMEWAIT));
103710039SPengcheng.Chen@Sun.COM
103810039SPengcheng.Chen@Sun.COM mutex_enter(&ehcip->ehci_int_mutex);
103910039SPengcheng.Chen@Sun.COM port_status = Get_OpReg(ehci_rh_port_status[port]) &
104010039SPengcheng.Chen@Sun.COM ~EHCI_RH_PORT_CLEAR_MASK;
104110039SPengcheng.Chen@Sun.COM mutex_exit(&ehcip->ehci_int_mutex);
104210039SPengcheng.Chen@Sun.COM
104310039SPengcheng.Chen@Sun.COM if (!(port_status & EHCI_RH_PORT_RESET)) {
104410039SPengcheng.Chen@Sun.COM break;
104510039SPengcheng.Chen@Sun.COM }
104610039SPengcheng.Chen@Sun.COM }
10470Sstevel@tonic-gate
10480Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
10510Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate /*
10540Sstevel@tonic-gate * If port is not enabled, connected device is a
10550Sstevel@tonic-gate * Full-speed usb device.
10560Sstevel@tonic-gate */
10570Sstevel@tonic-gate if (!(port_status & EHCI_RH_PORT_ENABLE)) {
10580Sstevel@tonic-gate /* Check for classic or companion host controllers */
10590Sstevel@tonic-gate if (rh->rh_companion_controllers) {
10600Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
10610Sstevel@tonic-gate ehcip->ehci_log_hdl,
10620Sstevel@tonic-gate "ehci_handle_port_reset: Full speed device "
10630Sstevel@tonic-gate "and handover this port to Companion host "
10640Sstevel@tonic-gate "controller");
10650Sstevel@tonic-gate
10660Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
10670Sstevel@tonic-gate port_status | EHCI_RH_PORT_OWNER_CLASSIC);
10680Sstevel@tonic-gate } else {
10690Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ROOT_HUB,
10700Sstevel@tonic-gate ehcip->ehci_log_hdl,
10710Sstevel@tonic-gate "Full speed device is not supported");
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate } else {
10740Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
10750Sstevel@tonic-gate "ehci_handle_port_reset: High speed device ");
10760Sstevel@tonic-gate
10770Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
10780Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
10790Sstevel@tonic-gate
10800Sstevel@tonic-gate /*
1081*12819SVincent.Wang@Sun.COM * Disable over-current, connect, and disconnect
10820Sstevel@tonic-gate * wakeup bits.
10830Sstevel@tonic-gate */
1084*12819SVincent.Wang@Sun.COM Set_OpReg(ehci_rh_port_status[port], port_status &
1085*12819SVincent.Wang@Sun.COM ~(EHCI_RH_PORT_OVER_CURENT_ENABLE |
10860Sstevel@tonic-gate EHCI_RH_PORT_DISCONNECT_ENABLE |
10870Sstevel@tonic-gate EHCI_RH_PORT_CONNECT_ENABLE));
10880Sstevel@tonic-gate
10890Sstevel@tonic-gate /*
10900Sstevel@tonic-gate * The next function is only called if the interrupt
10910Sstevel@tonic-gate * pipe is polling and the USBA is ready to receive
10920Sstevel@tonic-gate * the data.
10930Sstevel@tonic-gate */
10940Sstevel@tonic-gate ehcip->ehci_root_hub.
10950Sstevel@tonic-gate rh_intr_pending_status |= (1 << port);
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate if (ehcip->ehci_root_hub.
10980Sstevel@tonic-gate rh_intr_pipe_state == EHCI_PIPE_STATE_ACTIVE) {
10990Sstevel@tonic-gate
11000Sstevel@tonic-gate ehci_root_hub_reset_occured(ehcip);
11010Sstevel@tonic-gate }
11020Sstevel@tonic-gate }
11030Sstevel@tonic-gate }
11040Sstevel@tonic-gate
11050Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
11060Sstevel@tonic-gate }
11070Sstevel@tonic-gate
11080Sstevel@tonic-gate
11090Sstevel@tonic-gate /*
11100Sstevel@tonic-gate * ehci_root_hub_reset_occured:
11110Sstevel@tonic-gate *
11120Sstevel@tonic-gate * Inform the upper layer that reset has occured on the port. This is
11130Sstevel@tonic-gate * required because the upper layer is expecting a an evernt immidiately
11140Sstevel@tonic-gate * after doing reset. In case of OHCI, the controller gets an interrupt
11150Sstevel@tonic-gate * for the change in the root hub status but in case of EHCI, we dont.
11160Sstevel@tonic-gate * So, send a event to the upper layer as soon as we complete the reset.
11170Sstevel@tonic-gate */
11180Sstevel@tonic-gate void
ehci_root_hub_reset_occured(ehci_state_t * ehcip)11190Sstevel@tonic-gate ehci_root_hub_reset_occured(
11200Sstevel@tonic-gate ehci_state_t *ehcip)
11210Sstevel@tonic-gate {
11220Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp =
11236898Sfb209375 ehcip->ehci_root_hub.rh_curr_intr_reqp;
11240Sstevel@tonic-gate usb_port_mask_t port_mask;
11250Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
11260Sstevel@tonic-gate
11270Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
11280Sstevel@tonic-gate "ehci_root_hub_reset_occured: curr_intr_reqp = 0x%p data = 0x%p",
11296898Sfb209375 (void *)curr_intr_reqp, (void *)curr_intr_reqp->intr_data);
11300Sstevel@tonic-gate
11310Sstevel@tonic-gate /* Get the interrupt pipe handle */
11320Sstevel@tonic-gate ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
11330Sstevel@tonic-gate
11340Sstevel@tonic-gate /* Get the pending status */
11350Sstevel@tonic-gate port_mask = ehcip->ehci_root_hub.rh_intr_pending_status << 1;
11360Sstevel@tonic-gate
11370Sstevel@tonic-gate do {
11380Sstevel@tonic-gate *curr_intr_reqp->intr_data->b_wptr++ = (uchar_t)port_mask;
11390Sstevel@tonic-gate port_mask >>= 8;
11400Sstevel@tonic-gate } while (port_mask != 0);
11410Sstevel@tonic-gate
11420Sstevel@tonic-gate ehci_root_hub_hcdi_callback(ph, USB_CR_OK);
11430Sstevel@tonic-gate
11440Sstevel@tonic-gate /* Reset pending status */
11450Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pending_status = 0;
11460Sstevel@tonic-gate
11470Sstevel@tonic-gate /* If needed, allocate new interrupt request */
11480Sstevel@tonic-gate if ((ehci_root_hub_allocate_intr_pipe_resource(
11490Sstevel@tonic-gate ehcip, 0)) != USB_SUCCESS) {
11500Sstevel@tonic-gate
11510Sstevel@tonic-gate /* Do interrupt pipe cleanup */
11520Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_NO_RESOURCES);
11530Sstevel@tonic-gate }
11540Sstevel@tonic-gate }
11550Sstevel@tonic-gate
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate /*
11580Sstevel@tonic-gate * ehci_handle_complete_port_reset:
11590Sstevel@tonic-gate *
11600Sstevel@tonic-gate * Perform a port reset change.
11610Sstevel@tonic-gate */
11620Sstevel@tonic-gate static void
ehci_handle_complete_port_reset(ehci_state_t * ehcip,uint16_t port)11630Sstevel@tonic-gate ehci_handle_complete_port_reset(
11640Sstevel@tonic-gate ehci_state_t *ehcip,
11650Sstevel@tonic-gate uint16_t port)
11660Sstevel@tonic-gate {
11670Sstevel@tonic-gate uint_t port_status;
11680Sstevel@tonic-gate
11690Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
11700Sstevel@tonic-gate
11710Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
11720Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
11730Sstevel@tonic-gate
11740Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
11750Sstevel@tonic-gate "ehci_handle_complete_port_reset: port = 0x%x status = 0x%x",
11760Sstevel@tonic-gate port, port_status);
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate /* Check port is owned by ehci */
11790Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
11800Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
11810Sstevel@tonic-gate
11820Sstevel@tonic-gate return;
11830Sstevel@tonic-gate }
11840Sstevel@tonic-gate
11850Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_RESET) {
11860Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
11870Sstevel@tonic-gate port_status & ~EHCI_RH_PORT_RESET);
11880Sstevel@tonic-gate
11890Sstevel@tonic-gate }
11900Sstevel@tonic-gate
11910Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
11920Sstevel@tonic-gate }
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate /*
11960Sstevel@tonic-gate * ehci_handle_clear_port_connection:
11970Sstevel@tonic-gate *
11980Sstevel@tonic-gate * Perform a clear port connection.
11990Sstevel@tonic-gate */
12000Sstevel@tonic-gate static void
ehci_handle_clear_port_connection(ehci_state_t * ehcip,uint16_t port)12010Sstevel@tonic-gate ehci_handle_clear_port_connection(
12020Sstevel@tonic-gate ehci_state_t *ehcip,
12030Sstevel@tonic-gate uint16_t port)
12040Sstevel@tonic-gate {
12050Sstevel@tonic-gate uint_t port_status;
12060Sstevel@tonic-gate
12070Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
12100Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
12110Sstevel@tonic-gate
12120Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
12130Sstevel@tonic-gate "ehci_handle_clear_port_connection: port = 0x%x"
12140Sstevel@tonic-gate "status = 0x%x", port, port_status);
12150Sstevel@tonic-gate
12160Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
12170Sstevel@tonic-gate port_status | EHCI_RH_PORT_CONNECT_STS_CHANGE);
12180Sstevel@tonic-gate
12190Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate
12230Sstevel@tonic-gate /*
12240Sstevel@tonic-gate * ehci_handle_clrchng_port_over_current:
12250Sstevel@tonic-gate *
12260Sstevel@tonic-gate * Perform a clear port connection.
12270Sstevel@tonic-gate */
12280Sstevel@tonic-gate static void
ehci_handle_clrchng_port_over_current(ehci_state_t * ehcip,uint16_t port)12290Sstevel@tonic-gate ehci_handle_clrchng_port_over_current(
12300Sstevel@tonic-gate ehci_state_t *ehcip,
12310Sstevel@tonic-gate uint16_t port)
12320Sstevel@tonic-gate {
12330Sstevel@tonic-gate uint_t port_status;
12340Sstevel@tonic-gate
12350Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
12360Sstevel@tonic-gate
12370Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
12380Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
12390Sstevel@tonic-gate
12400Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
12410Sstevel@tonic-gate "ehci_handle_clrchng_port_over_current: port = 0x%x"
12420Sstevel@tonic-gate "status = 0x%x", port, port_status);
12430Sstevel@tonic-gate
12440Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
12450Sstevel@tonic-gate port_status | EHCI_RH_PORT_OVER_CURR_CHANGE);
12460Sstevel@tonic-gate
12470Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
12480Sstevel@tonic-gate }
12490Sstevel@tonic-gate
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate /*
12520Sstevel@tonic-gate * ehci_handle_get_port_status:
12530Sstevel@tonic-gate *
12540Sstevel@tonic-gate * Handle a get port status request.
12550Sstevel@tonic-gate */
12560Sstevel@tonic-gate static void
ehci_handle_get_port_status(ehci_state_t * ehcip,uint16_t port)12570Sstevel@tonic-gate ehci_handle_get_port_status(
12580Sstevel@tonic-gate ehci_state_t *ehcip,
12590Sstevel@tonic-gate uint16_t port)
12600Sstevel@tonic-gate {
12610Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp;
12620Sstevel@tonic-gate mblk_t *message;
12630Sstevel@tonic-gate uint_t new_port_status = 0;
12640Sstevel@tonic-gate uint_t change_status = 0;
12650Sstevel@tonic-gate uint_t port_status;
12660Sstevel@tonic-gate
12670Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
12680Sstevel@tonic-gate
12690Sstevel@tonic-gate ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
12700Sstevel@tonic-gate
12710Sstevel@tonic-gate /* Get the root hub port status information */
12720Sstevel@tonic-gate port_status = ehci_get_root_hub_port_status(ehcip, port);
12730Sstevel@tonic-gate
12740Sstevel@tonic-gate new_port_status = port_status & PORT_STATUS_MASK;
12750Sstevel@tonic-gate change_status = (port_status >> 16) & PORT_CHANGE_MASK;
12760Sstevel@tonic-gate
12770Sstevel@tonic-gate ehcip->ehci_root_hub.rh_port_status[port] = new_port_status;
12780Sstevel@tonic-gate
12790Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
12800Sstevel@tonic-gate "ehci_handle_get_port_status: port = %d new status = 0x%x"
12810Sstevel@tonic-gate "change = 0x%x", port, new_port_status, change_status);
12820Sstevel@tonic-gate
12830Sstevel@tonic-gate message = ctrl_reqp->ctrl_data;
12840Sstevel@tonic-gate
12850Sstevel@tonic-gate ASSERT(message != NULL);
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)new_port_status;
12880Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_port_status >> 8);
12890Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)change_status;
12900Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(change_status >> 8);
12910Sstevel@tonic-gate
12920Sstevel@tonic-gate /* Save the data in control request */
12930Sstevel@tonic-gate ctrl_reqp->ctrl_data = message;
12940Sstevel@tonic-gate
12950Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
12960Sstevel@tonic-gate }
12970Sstevel@tonic-gate
12980Sstevel@tonic-gate
12990Sstevel@tonic-gate /*
13000Sstevel@tonic-gate * ehci_handle_get_hub_descriptor:
13010Sstevel@tonic-gate */
13020Sstevel@tonic-gate static void
ehci_handle_get_hub_descriptor(ehci_state_t * ehcip)13030Sstevel@tonic-gate ehci_handle_get_hub_descriptor(
13040Sstevel@tonic-gate ehci_state_t *ehcip)
13050Sstevel@tonic-gate {
13060Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp;
13070Sstevel@tonic-gate mblk_t *message;
13080Sstevel@tonic-gate usb_hub_descr_t *root_hub_descr;
13090Sstevel@tonic-gate size_t length;
13100Sstevel@tonic-gate uchar_t raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH];
13110Sstevel@tonic-gate
13120Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
13150Sstevel@tonic-gate root_hub_descr = &ehcip->ehci_root_hub.rh_descr;
13160Sstevel@tonic-gate length = ctrl_reqp->ctrl_wLength;
13170Sstevel@tonic-gate
13180Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
13196898Sfb209375 "ehci_handle_get_hub_descriptor: Ctrl Req = 0x%p",
13206898Sfb209375 (void *)ctrl_reqp);
13210Sstevel@tonic-gate
13220Sstevel@tonic-gate message = ctrl_reqp->ctrl_data;
13230Sstevel@tonic-gate
13240Sstevel@tonic-gate ASSERT(message != NULL);
13250Sstevel@tonic-gate
13260Sstevel@tonic-gate bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH);
13270Sstevel@tonic-gate
13280Sstevel@tonic-gate raw_descr[0] = root_hub_descr->bDescLength;
13290Sstevel@tonic-gate raw_descr[1] = root_hub_descr->bDescriptorType;
13300Sstevel@tonic-gate raw_descr[2] = root_hub_descr->bNbrPorts;
13310Sstevel@tonic-gate raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00FF;
13320Sstevel@tonic-gate raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xFF00) >> 8;
13330Sstevel@tonic-gate raw_descr[5] = root_hub_descr->bPwrOn2PwrGood;
13340Sstevel@tonic-gate raw_descr[6] = root_hub_descr->bHubContrCurrent;
13350Sstevel@tonic-gate raw_descr[7] = root_hub_descr->DeviceRemovable;
13360Sstevel@tonic-gate raw_descr[8] = root_hub_descr->PortPwrCtrlMask;
13370Sstevel@tonic-gate
13380Sstevel@tonic-gate bcopy(raw_descr, message->b_wptr, length);
13390Sstevel@tonic-gate message->b_wptr += length;
13400Sstevel@tonic-gate
13410Sstevel@tonic-gate /* Save the data in control request */
13420Sstevel@tonic-gate ctrl_reqp->ctrl_data = message;
13430Sstevel@tonic-gate
13440Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
13450Sstevel@tonic-gate }
13460Sstevel@tonic-gate
13470Sstevel@tonic-gate
13480Sstevel@tonic-gate /*
13490Sstevel@tonic-gate * ehci_handle_get_hub_status:
13500Sstevel@tonic-gate *
13510Sstevel@tonic-gate * Handle a get hub status request.
13520Sstevel@tonic-gate */
13530Sstevel@tonic-gate static void
ehci_handle_get_hub_status(ehci_state_t * ehcip)13540Sstevel@tonic-gate ehci_handle_get_hub_status(
13550Sstevel@tonic-gate ehci_state_t *ehcip)
13560Sstevel@tonic-gate {
13570Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp;
13580Sstevel@tonic-gate mblk_t *message;
13590Sstevel@tonic-gate uint_t new_root_hub_status;
13600Sstevel@tonic-gate
13610Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
13620Sstevel@tonic-gate
13630Sstevel@tonic-gate ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
13640Sstevel@tonic-gate
13650Sstevel@tonic-gate /*
13660Sstevel@tonic-gate * For EHCI, there is no overall hub status information.
13670Sstevel@tonic-gate * Only individual root hub port status information is
13680Sstevel@tonic-gate * available. So return zero for the root hub status
13690Sstevel@tonic-gate * request.
13700Sstevel@tonic-gate */
13710Sstevel@tonic-gate new_root_hub_status = 0;
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
13740Sstevel@tonic-gate "ehci_handle_get_hub_status: new root hub status = 0x%x",
13750Sstevel@tonic-gate new_root_hub_status);
13760Sstevel@tonic-gate
13770Sstevel@tonic-gate message = ctrl_reqp->ctrl_data;
13780Sstevel@tonic-gate
13790Sstevel@tonic-gate ASSERT(message != NULL);
13800Sstevel@tonic-gate
13810Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)new_root_hub_status;
13820Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 8);
13830Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 16);
13840Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 24);
13850Sstevel@tonic-gate
13860Sstevel@tonic-gate /* Save the data in control request */
13870Sstevel@tonic-gate ctrl_reqp->ctrl_data = message;
13880Sstevel@tonic-gate
13890Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
13900Sstevel@tonic-gate }
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate
13930Sstevel@tonic-gate /*
13941001Ssl147100 * ehci_handle_get_device_status:
13951001Ssl147100 *
13961001Ssl147100 * Handle a get device status request.
13971001Ssl147100 */
13981001Ssl147100 static void
ehci_handle_get_device_status(ehci_state_t * ehcip)13991001Ssl147100 ehci_handle_get_device_status(
14001001Ssl147100 ehci_state_t *ehcip)
14011001Ssl147100 {
14021001Ssl147100 usb_ctrl_req_t *ctrl_reqp;
14031001Ssl147100 mblk_t *message;
14041001Ssl147100 uint16_t dev_status;
14051001Ssl147100
14061001Ssl147100 mutex_enter(&ehcip->ehci_int_mutex);
14071001Ssl147100
14081001Ssl147100 ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
14091001Ssl147100
14101001Ssl147100 /*
14111001Ssl147100 * For EHCI, there is no device status information.
14121001Ssl147100 * Simply return what is desired for the request.
14131001Ssl147100 */
14141001Ssl147100 dev_status = USB_DEV_SLF_PWRD_STATUS;
14151001Ssl147100
14161001Ssl147100 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
14171001Ssl147100 "ehci_handle_get_device_status: device status = 0x%x",
14181001Ssl147100 dev_status);
14191001Ssl147100
14201001Ssl147100 message = ctrl_reqp->ctrl_data;
14211001Ssl147100
14221001Ssl147100 ASSERT(message != NULL);
14231001Ssl147100
14241001Ssl147100 *message->b_wptr++ = (uchar_t)dev_status;
14251001Ssl147100 *message->b_wptr++ = (uchar_t)(dev_status >> 8);
14261001Ssl147100
14271001Ssl147100 /* Save the data in control request */
14281001Ssl147100 ctrl_reqp->ctrl_data = message;
14291001Ssl147100
14301001Ssl147100 mutex_exit(&ehcip->ehci_int_mutex);
14311001Ssl147100 }
14321001Ssl147100
14331001Ssl147100
14341001Ssl147100 /*
14350Sstevel@tonic-gate * ehci_handle_root_hub_pipe_start_intr_polling:
14360Sstevel@tonic-gate *
14370Sstevel@tonic-gate * Handle start polling on root hub interrupt pipe.
14380Sstevel@tonic-gate */
14390Sstevel@tonic-gate /* ARGSUSED */
14400Sstevel@tonic-gate int
ehci_handle_root_hub_pipe_start_intr_polling(usba_pipe_handle_data_t * ph,usb_intr_req_t * client_intr_reqp,usb_flags_t flags)14410Sstevel@tonic-gate ehci_handle_root_hub_pipe_start_intr_polling(
14420Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
14430Sstevel@tonic-gate usb_intr_req_t *client_intr_reqp,
14440Sstevel@tonic-gate usb_flags_t flags)
14450Sstevel@tonic-gate {
14460Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
14476898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
14480Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
14490Sstevel@tonic-gate int error = USB_SUCCESS;
14500Sstevel@tonic-gate uint_t pipe_state;
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
14530Sstevel@tonic-gate "ehci_handle_root_hub_pipe_start_intr_polling: "
14540Sstevel@tonic-gate "Root hub pipe start polling");
14550Sstevel@tonic-gate
14560Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
14570Sstevel@tonic-gate
14580Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
14590Sstevel@tonic-gate
14600Sstevel@tonic-gate ASSERT((client_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) == 0);
14610Sstevel@tonic-gate
14620Sstevel@tonic-gate pipe_state = ehcip->ehci_root_hub.rh_intr_pipe_state;
14630Sstevel@tonic-gate
14640Sstevel@tonic-gate switch (pipe_state) {
14650Sstevel@tonic-gate case EHCI_PIPE_STATE_IDLE:
14660Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.rh_intr_pipe_timer_id == 0);
14670Sstevel@tonic-gate
14680Sstevel@tonic-gate /*
14690Sstevel@tonic-gate * Save the Original Client's Interrupt IN request
14700Sstevel@tonic-gate * information. We use this for final callback
14710Sstevel@tonic-gate */
14720Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.rh_client_intr_reqp == NULL);
14730Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp = client_intr_reqp;
14740Sstevel@tonic-gate
14750Sstevel@tonic-gate error = ehci_root_hub_allocate_intr_pipe_resource(ehcip, flags);
14760Sstevel@tonic-gate
14770Sstevel@tonic-gate if (error != USB_SUCCESS) {
14780Sstevel@tonic-gate /* Reset client interrupt request pointer */
14790Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp = NULL;
14800Sstevel@tonic-gate
14810Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
14820Sstevel@tonic-gate "ehci_handle_root_hub_pipe_start_intr_polling: "
14830Sstevel@tonic-gate "No Resources");
14840Sstevel@tonic-gate
14850Sstevel@tonic-gate return (error);
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate
14880Sstevel@tonic-gate /* Check whether we need to send the reset data up */
14890Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_intr_pending_status) {
14900Sstevel@tonic-gate ehci_root_hub_reset_occured(ehcip);
14910Sstevel@tonic-gate }
14920Sstevel@tonic-gate
14930Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
14940Sstevel@tonic-gate "ehci_handle_root_hub_pipe_start_intr_polling: "
14950Sstevel@tonic-gate "Start polling for root hub successful");
14960Sstevel@tonic-gate
14970Sstevel@tonic-gate break;
14980Sstevel@tonic-gate case EHCI_PIPE_STATE_ACTIVE:
14990Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
15000Sstevel@tonic-gate "ehci_handle_root_hub_pipe_start_intr_polling: "
15010Sstevel@tonic-gate "Polling for root hub is already in progress");
15020Sstevel@tonic-gate
15030Sstevel@tonic-gate break;
15040Sstevel@tonic-gate default:
15050Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
15060Sstevel@tonic-gate "ehci_handle_root_hub_pipe_start_intr_polling: "
15070Sstevel@tonic-gate "Pipe is in error state 0x%x", pipe_state);
15080Sstevel@tonic-gate
15090Sstevel@tonic-gate error = USB_FAILURE;
15100Sstevel@tonic-gate
15110Sstevel@tonic-gate break;
15120Sstevel@tonic-gate }
15130Sstevel@tonic-gate
15140Sstevel@tonic-gate return (error);
15150Sstevel@tonic-gate }
15160Sstevel@tonic-gate
15170Sstevel@tonic-gate
15180Sstevel@tonic-gate /*
15190Sstevel@tonic-gate * ehci_handle_root_hub_pipe_stop_intr_polling:
15200Sstevel@tonic-gate *
15210Sstevel@tonic-gate * Handle stop polling on root hub intr pipe.
15220Sstevel@tonic-gate */
15230Sstevel@tonic-gate /* ARGSUSED */
15240Sstevel@tonic-gate void
ehci_handle_root_hub_pipe_stop_intr_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)15250Sstevel@tonic-gate ehci_handle_root_hub_pipe_stop_intr_polling(
15260Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
15270Sstevel@tonic-gate usb_flags_t flags)
15280Sstevel@tonic-gate {
15290Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
15306898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
15310Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
15320Sstevel@tonic-gate
15330Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
15340Sstevel@tonic-gate
15350Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
15360Sstevel@tonic-gate "ehci_handle_root_hub_pipe_stop_intr_polling: "
15370Sstevel@tonic-gate "Root hub pipe stop polling");
15380Sstevel@tonic-gate
15390Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
15400Sstevel@tonic-gate
15410Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_intr_pipe_state ==
15420Sstevel@tonic-gate EHCI_PIPE_STATE_ACTIVE) {
15430Sstevel@tonic-gate
15440Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_state =
15450Sstevel@tonic-gate EHCI_PIPE_STATE_STOP_POLLING;
15460Sstevel@tonic-gate
15470Sstevel@tonic-gate /* Do interrupt pipe cleanup */
15480Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_STOPPED_POLLING);
15490Sstevel@tonic-gate
15500Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.
15510Sstevel@tonic-gate rh_intr_pipe_state == EHCI_PIPE_STATE_IDLE);
15520Sstevel@tonic-gate
15530Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
15540Sstevel@tonic-gate "ehci_hcdi_pipe_stop_intr_polling: Stop polling for root"
15550Sstevel@tonic-gate "hub successful");
15560Sstevel@tonic-gate } else {
15570Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
15580Sstevel@tonic-gate ehcip->ehci_log_hdl, "ehci_hcdi_pipe_stop_intr_polling: "
15590Sstevel@tonic-gate "Polling for root hub is already stopped");
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate }
15620Sstevel@tonic-gate
15630Sstevel@tonic-gate
15640Sstevel@tonic-gate /*
15650Sstevel@tonic-gate * ehci_get_root_hub_port_status:
15660Sstevel@tonic-gate *
15670Sstevel@tonic-gate * Construct root hub port status and change information
15680Sstevel@tonic-gate */
15690Sstevel@tonic-gate static uint_t
ehci_get_root_hub_port_status(ehci_state_t * ehcip,uint16_t port)15700Sstevel@tonic-gate ehci_get_root_hub_port_status(
15710Sstevel@tonic-gate ehci_state_t *ehcip,
15720Sstevel@tonic-gate uint16_t port)
15730Sstevel@tonic-gate {
15740Sstevel@tonic-gate uint_t new_port_status = 0;
15750Sstevel@tonic-gate uint_t change_status = 0;
15760Sstevel@tonic-gate uint_t port_status;
15770Sstevel@tonic-gate
15780Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
15790Sstevel@tonic-gate
15800Sstevel@tonic-gate /* Read the current port status */
15810Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]);
15820Sstevel@tonic-gate
15830Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
15840Sstevel@tonic-gate "ehci_get_root_hub_port_status: port %d "
15850Sstevel@tonic-gate "port status = 0x%x", port, port_status);
15860Sstevel@tonic-gate
15870Sstevel@tonic-gate /*
15880Sstevel@tonic-gate * EHCI root hub port status and control register information
15890Sstevel@tonic-gate * format is different what Hub driver wants. So EHCI driver
15900Sstevel@tonic-gate * needs to contruct the proper root hub port status information.
15910Sstevel@tonic-gate *
15920Sstevel@tonic-gate * Send all port status information only if port is owned by EHCI
15930Sstevel@tonic-gate * host controller.
15940Sstevel@tonic-gate */
15950Sstevel@tonic-gate if ((port_status & EHCI_RH_PORT_OWNER) == EHCI_RH_PORT_OWNER_EHCI) {
15960Sstevel@tonic-gate
15970Sstevel@tonic-gate /* First construct port change information */
15980Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_ENABLE_CHANGE) {
15990Sstevel@tonic-gate change_status |= PORT_CHANGE_PESC;
16000Sstevel@tonic-gate }
16010Sstevel@tonic-gate
16020Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_RESUME) {
16030Sstevel@tonic-gate change_status |= PORT_CHANGE_PSSC;
16040Sstevel@tonic-gate }
16050Sstevel@tonic-gate
16060Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_OVER_CURR_CHANGE) {
16070Sstevel@tonic-gate change_status |= PORT_CHANGE_OCIC;
16080Sstevel@tonic-gate }
16090Sstevel@tonic-gate
16100Sstevel@tonic-gate /* Now construct port status information */
16110Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_CONNECT_STATUS) {
16120Sstevel@tonic-gate new_port_status |= PORT_STATUS_CCS;
16130Sstevel@tonic-gate }
16140Sstevel@tonic-gate
16150Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_ENABLE) {
16160Sstevel@tonic-gate new_port_status |=
16170Sstevel@tonic-gate (PORT_STATUS_PES | PORT_STATUS_HSDA);
16180Sstevel@tonic-gate }
16190Sstevel@tonic-gate
16200Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_SUSPEND) {
16210Sstevel@tonic-gate new_port_status |= PORT_STATUS_PSS;
16220Sstevel@tonic-gate }
16230Sstevel@tonic-gate
16240Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_OVER_CURR_ACTIVE) {
16250Sstevel@tonic-gate new_port_status |= PORT_STATUS_POCI;
16260Sstevel@tonic-gate }
16270Sstevel@tonic-gate
16280Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_RESET) {
16290Sstevel@tonic-gate new_port_status |= PORT_STATUS_PRS;
16300Sstevel@tonic-gate }
16310Sstevel@tonic-gate
16320Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_INDICATOR) {
16330Sstevel@tonic-gate new_port_status |= PORT_STATUS_PIC;
16340Sstevel@tonic-gate }
16350Sstevel@tonic-gate }
16360Sstevel@tonic-gate
16370Sstevel@tonic-gate /*
16380Sstevel@tonic-gate * Send the following port status and change information
16390Sstevel@tonic-gate * even if port is not owned by EHCI.
16400Sstevel@tonic-gate *
16410Sstevel@tonic-gate * Additional port change information.
16420Sstevel@tonic-gate */
16430Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_CONNECT_STS_CHANGE) {
16440Sstevel@tonic-gate change_status |= PORT_CHANGE_CSC;
16450Sstevel@tonic-gate }
16460Sstevel@tonic-gate
16470Sstevel@tonic-gate /* Additional port status information */
16480Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_POWER) {
16490Sstevel@tonic-gate new_port_status |= PORT_STATUS_PPS;
16500Sstevel@tonic-gate }
16510Sstevel@tonic-gate
16520Sstevel@tonic-gate if ((!(port_status & EHCI_RH_PORT_ENABLE)) &&
16530Sstevel@tonic-gate (port_status & EHCI_RH_PORT_LOW_SPEED)) {
16540Sstevel@tonic-gate new_port_status |= PORT_STATUS_LSDA;
16550Sstevel@tonic-gate }
16560Sstevel@tonic-gate
16570Sstevel@tonic-gate /*
16580Sstevel@tonic-gate * Construct complete root hub port status and change information.
16590Sstevel@tonic-gate */
16600Sstevel@tonic-gate port_status = ((change_status << 16) | new_port_status);
16610Sstevel@tonic-gate
16620Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
16630Sstevel@tonic-gate "ehci_get_root_hub_port_status: port = %d new status = 0x%x "
16640Sstevel@tonic-gate "change status = 0x%x complete port status 0x%x", port,
16650Sstevel@tonic-gate new_port_status, change_status, port_status);
16660Sstevel@tonic-gate
16670Sstevel@tonic-gate return (port_status);
16680Sstevel@tonic-gate }
16690Sstevel@tonic-gate
16700Sstevel@tonic-gate
16710Sstevel@tonic-gate /*
16720Sstevel@tonic-gate * ehci_is_port_owner:
16730Sstevel@tonic-gate *
16740Sstevel@tonic-gate * Check whether given port is owned by ehci.
16750Sstevel@tonic-gate */
16760Sstevel@tonic-gate static int
ehci_is_port_owner(ehci_state_t * ehcip,uint16_t port)16770Sstevel@tonic-gate ehci_is_port_owner(
16780Sstevel@tonic-gate ehci_state_t *ehcip,
16790Sstevel@tonic-gate uint16_t port)
16800Sstevel@tonic-gate {
16810Sstevel@tonic-gate uint_t port_status;
16820Sstevel@tonic-gate
16830Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
16840Sstevel@tonic-gate
16850Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
16860Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
16870Sstevel@tonic-gate
16880Sstevel@tonic-gate /*
16890Sstevel@tonic-gate * Don't perform anything if port is owned by classis host
16900Sstevel@tonic-gate * controller and return success.
16910Sstevel@tonic-gate */
16920Sstevel@tonic-gate if ((port_status & EHCI_RH_PORT_OWNER) == EHCI_RH_PORT_OWNER_CLASSIC) {
16930Sstevel@tonic-gate
16940Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
16950Sstevel@tonic-gate "ehci_handle_set_clear_port_feature: "
16960Sstevel@tonic-gate "Port %d is owned by classic host controller", port);
16970Sstevel@tonic-gate
16980Sstevel@tonic-gate return (USB_FAILURE);
16990Sstevel@tonic-gate }
17000Sstevel@tonic-gate
17010Sstevel@tonic-gate return (USB_SUCCESS);
17020Sstevel@tonic-gate }
17030Sstevel@tonic-gate
17040Sstevel@tonic-gate
17050Sstevel@tonic-gate /*
17060Sstevel@tonic-gate * ehci_root_hub_allocate_intr_pipe_resource:
17070Sstevel@tonic-gate *
17080Sstevel@tonic-gate * Allocate interrupt requests and initialize them.
17090Sstevel@tonic-gate */
17100Sstevel@tonic-gate static int
ehci_root_hub_allocate_intr_pipe_resource(ehci_state_t * ehcip,usb_flags_t flags)17110Sstevel@tonic-gate ehci_root_hub_allocate_intr_pipe_resource(
17120Sstevel@tonic-gate ehci_state_t *ehcip,
17130Sstevel@tonic-gate usb_flags_t flags)
17140Sstevel@tonic-gate {
17150Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
17160Sstevel@tonic-gate size_t length;
17170Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
17180Sstevel@tonic-gate
17190Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
17200Sstevel@tonic-gate "ehci_root_hub_allocate_intr_pipe_resource");
17210Sstevel@tonic-gate
17220Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
17230Sstevel@tonic-gate
17240Sstevel@tonic-gate /* Get the interrupt pipe handle */
17250Sstevel@tonic-gate ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
17260Sstevel@tonic-gate
17270Sstevel@tonic-gate /* Get the current interrupt request pointer */
17280Sstevel@tonic-gate curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp;
17290Sstevel@tonic-gate
17300Sstevel@tonic-gate /*
17310Sstevel@tonic-gate * If current interrupt request pointer is null,
17320Sstevel@tonic-gate * allocate new interrupt request.
17330Sstevel@tonic-gate */
17340Sstevel@tonic-gate if (curr_intr_reqp == NULL) {
17350Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.rh_client_intr_reqp);
17360Sstevel@tonic-gate
17370Sstevel@tonic-gate /* Get the length of interrupt transfer */
17380Sstevel@tonic-gate length = ehcip->ehci_root_hub.
17390Sstevel@tonic-gate rh_client_intr_reqp->intr_len;
17400Sstevel@tonic-gate
17410Sstevel@tonic-gate curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
17420Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp,
17430Sstevel@tonic-gate length, flags);
17440Sstevel@tonic-gate
17450Sstevel@tonic-gate if (curr_intr_reqp == NULL) {
17460Sstevel@tonic-gate
17470Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
17480Sstevel@tonic-gate "ehci_root_hub_allocate_intr_pipe_resource:"
17490Sstevel@tonic-gate "Interrupt request structure allocation failed");
17500Sstevel@tonic-gate
17510Sstevel@tonic-gate return (USB_NO_RESOURCES);
17520Sstevel@tonic-gate }
17530Sstevel@tonic-gate
17540Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_intr_reqp = curr_intr_reqp;
17550Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
17560Sstevel@tonic-gate ph->p_req_count++;
17570Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
17580Sstevel@tonic-gate }
17590Sstevel@tonic-gate
17600Sstevel@tonic-gate /* Start the timer for the root hub interrupt pipe polling */
17610Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_intr_pipe_timer_id == 0) {
17620Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_timer_id =
17630Sstevel@tonic-gate timeout(ehci_handle_root_hub_status_change,
17640Sstevel@tonic-gate (void *)ehcip, drv_usectohz(EHCI_RH_POLL_TIME));
17650Sstevel@tonic-gate
17660Sstevel@tonic-gate ehcip->ehci_root_hub.
17670Sstevel@tonic-gate rh_intr_pipe_state = EHCI_PIPE_STATE_ACTIVE;
17680Sstevel@tonic-gate }
17690Sstevel@tonic-gate
17700Sstevel@tonic-gate return (USB_SUCCESS);
17710Sstevel@tonic-gate }
17720Sstevel@tonic-gate
17730Sstevel@tonic-gate
17740Sstevel@tonic-gate /*
17750Sstevel@tonic-gate * ehci_root_hub_intr_pipe_cleanup:
17760Sstevel@tonic-gate *
17770Sstevel@tonic-gate * Deallocate all interrupt requests and do callback
17780Sstevel@tonic-gate * the original client interrupt request.
17790Sstevel@tonic-gate */
17800Sstevel@tonic-gate static void
ehci_root_hub_intr_pipe_cleanup(ehci_state_t * ehcip,usb_cr_t completion_reason)17810Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(
17820Sstevel@tonic-gate ehci_state_t *ehcip,
17830Sstevel@tonic-gate usb_cr_t completion_reason)
17840Sstevel@tonic-gate {
17850Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
17860Sstevel@tonic-gate usb_opaque_t client_intr_reqp;
17870Sstevel@tonic-gate timeout_id_t timer_id;
17880Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
17890Sstevel@tonic-gate
17900Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
17910Sstevel@tonic-gate "ehci_root_hub_intr_pipe_cleanup");
17920Sstevel@tonic-gate
17930Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
17940Sstevel@tonic-gate
17950Sstevel@tonic-gate /* Get the interrupt pipe handle */
17960Sstevel@tonic-gate ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
17970Sstevel@tonic-gate
17980Sstevel@tonic-gate /* Get the interrupt timerid */
17990Sstevel@tonic-gate timer_id = ehcip->ehci_root_hub.rh_intr_pipe_timer_id;
18000Sstevel@tonic-gate
18010Sstevel@tonic-gate /* Stop the root hub interrupt timer */
18020Sstevel@tonic-gate if (timer_id) {
18030Sstevel@tonic-gate /* Reset the timer id to zero */
18040Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0;
18050Sstevel@tonic-gate
18060Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
18070Sstevel@tonic-gate (void) untimeout(timer_id);
18080Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
18090Sstevel@tonic-gate }
18100Sstevel@tonic-gate
18110Sstevel@tonic-gate /* Reset the current interrupt request pointer */
18120Sstevel@tonic-gate curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp;
18130Sstevel@tonic-gate
18140Sstevel@tonic-gate /* Deallocate uncompleted interrupt request */
18150Sstevel@tonic-gate if (curr_intr_reqp) {
18160Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL;
18170Sstevel@tonic-gate usb_free_intr_req(curr_intr_reqp);
18180Sstevel@tonic-gate
18190Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
18200Sstevel@tonic-gate ph->p_req_count--;
18210Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
18220Sstevel@tonic-gate }
18230Sstevel@tonic-gate
18240Sstevel@tonic-gate client_intr_reqp = (usb_opaque_t)
18250Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp;
18260Sstevel@tonic-gate
18270Sstevel@tonic-gate /* Callback for original client interrupt request */
18280Sstevel@tonic-gate if (client_intr_reqp) {
18290Sstevel@tonic-gate ehci_root_hub_hcdi_callback(ph, completion_reason);
18300Sstevel@tonic-gate }
18310Sstevel@tonic-gate }
18320Sstevel@tonic-gate
18330Sstevel@tonic-gate
18340Sstevel@tonic-gate /*
18350Sstevel@tonic-gate * ehci_handle_root_hub_status_change:
18360Sstevel@tonic-gate *
18370Sstevel@tonic-gate * A root hub status change interrupt will occur any time there is a change
18380Sstevel@tonic-gate * in the root hub status register or one of the port status registers.
18390Sstevel@tonic-gate */
18400Sstevel@tonic-gate static void
ehci_handle_root_hub_status_change(void * arg)18410Sstevel@tonic-gate ehci_handle_root_hub_status_change(void *arg)
18420Sstevel@tonic-gate {
18430Sstevel@tonic-gate ehci_state_t *ehcip = (ehci_state_t *)arg;
18440Sstevel@tonic-gate usb_hub_descr_t *root_hub_descr =
18456898Sfb209375 &ehcip->ehci_root_hub.rh_descr;
18460Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
18470Sstevel@tonic-gate usb_port_mask_t port_mask = 0;
18480Sstevel@tonic-gate uint_t new_port_status;
18490Sstevel@tonic-gate uint_t change_status;
18500Sstevel@tonic-gate uint_t port_status;
18510Sstevel@tonic-gate mblk_t *message;
18520Sstevel@tonic-gate size_t length;
18530Sstevel@tonic-gate usb_ep_descr_t *eptd;
18540Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
18550Sstevel@tonic-gate int i;
18560Sstevel@tonic-gate
18570Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
18580Sstevel@tonic-gate
18590Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
18600Sstevel@tonic-gate "ehci_handle_root_hub_status_change: state = %d",
18610Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_state);
18620Sstevel@tonic-gate
18631458Syq193411 #if defined(__x86)
18641458Syq193411 /*
18651458Syq193411 * When ohci are attached in ferrari 4000, SMI will reset ehci
18661458Syq193411 * registers. If ehci registers have been reset, we must re-initialize
18671458Syq193411 * them. During booting, this function will be called 2~3 times. When
18681458Syq193411 * this function is called 16 times, ohci drivers have been attached
18691458Syq193411 * and stop checking the ehci registers.
18701458Syq193411 */
18711458Syq193411 if (ehcip->ehci_polled_root_hub_count < 16) {
18721458Syq193411
18731458Syq193411 if (Get_OpReg(ehci_config_flag) == 0) {
18741458Syq193411
18751458Syq193411 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
18761458Syq193411 ehcip->ehci_log_hdl,
18776898Sfb209375 "ehci_handle_root_hub_status_change:"
18781458Syq193411 " EHCI have been reset");
18791458Syq193411
18801458Syq193411 /* Reinitialize the controller */
18811458Syq193411 if (ehci_init_ctlr(ehcip, EHCI_REINITIALIZATION) !=
18821458Syq193411 DDI_SUCCESS) {
18831458Syq193411 mutex_exit(&ehcip->ehci_int_mutex);
18841458Syq193411
18851458Syq193411 return;
18861458Syq193411 }
18871458Syq193411 }
18881458Syq193411
18891458Syq193411 ehcip->ehci_polled_root_hub_count++;
18901458Syq193411 }
18911458Syq193411 #endif /* __x86 */
18921458Syq193411
18930Sstevel@tonic-gate /* Get the current interrupt request pointer */
18940Sstevel@tonic-gate curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp;
18950Sstevel@tonic-gate
18960Sstevel@tonic-gate ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
18970Sstevel@tonic-gate
18980Sstevel@tonic-gate /* Check whether timeout handler is valid */
18990Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_intr_pipe_timer_id) {
19000Sstevel@tonic-gate /* Check host controller is in operational state */
19010Sstevel@tonic-gate if ((ehci_state_is_operational(ehcip)) != USB_SUCCESS) {
19020Sstevel@tonic-gate /* Reset the timer id */
19030Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0;
19040Sstevel@tonic-gate
19050Sstevel@tonic-gate /* Do interrupt pipe cleanup */
19060Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(
19070Sstevel@tonic-gate ehcip, USB_CR_HC_HARDWARE_ERR);
19080Sstevel@tonic-gate
19090Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
19100Sstevel@tonic-gate
19110Sstevel@tonic-gate return;
19120Sstevel@tonic-gate }
19130Sstevel@tonic-gate } else {
19140Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
19150Sstevel@tonic-gate
19160Sstevel@tonic-gate return;
19170Sstevel@tonic-gate }
19180Sstevel@tonic-gate
19190Sstevel@tonic-gate eptd = &ehcip->ehci_root_hub.rh_intr_pipe_handle->p_ep;
19200Sstevel@tonic-gate
19210Sstevel@tonic-gate /* Check each port */
19220Sstevel@tonic-gate for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
19230Sstevel@tonic-gate
19240Sstevel@tonic-gate port_status = ehci_get_root_hub_port_status(ehcip, i);
19250Sstevel@tonic-gate
19260Sstevel@tonic-gate new_port_status = port_status & PORT_STATUS_MASK;
19270Sstevel@tonic-gate change_status = (port_status >> 16) & PORT_CHANGE_MASK;
19280Sstevel@tonic-gate
19290Sstevel@tonic-gate /*
19300Sstevel@tonic-gate * If there is change in the port status then set the bit in the
19310Sstevel@tonic-gate * bitmap of changes and inform hub driver about these changes.
19320Sstevel@tonic-gate * Hub driver will take care of these changes.
19330Sstevel@tonic-gate */
19340Sstevel@tonic-gate if (change_status) {
19350Sstevel@tonic-gate
19360Sstevel@tonic-gate /* See if a device was attached/detached */
19370Sstevel@tonic-gate if (change_status & PORT_CHANGE_CSC) {
19380Sstevel@tonic-gate /*
19390Sstevel@tonic-gate * Update the state depending on whether
19400Sstevel@tonic-gate * the port was attached or detached.
19410Sstevel@tonic-gate */
19420Sstevel@tonic-gate if (new_port_status & PORT_STATUS_CCS) {
19430Sstevel@tonic-gate ehcip->ehci_root_hub.
19440Sstevel@tonic-gate rh_port_state[i] = DISABLED;
19450Sstevel@tonic-gate
19460Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
19470Sstevel@tonic-gate ehcip->ehci_log_hdl,
1948520Shx149380 "Port %d connected", i+1);
19490Sstevel@tonic-gate } else {
19500Sstevel@tonic-gate ehcip->ehci_root_hub.
19510Sstevel@tonic-gate rh_port_state[i] = DISCONNECTED;
19520Sstevel@tonic-gate
19530Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
19540Sstevel@tonic-gate ehcip->ehci_log_hdl,
1955520Shx149380 "Port %d disconnected", i+1);
19560Sstevel@tonic-gate }
19570Sstevel@tonic-gate }
19580Sstevel@tonic-gate
19590Sstevel@tonic-gate /* See if port enable status changed */
19600Sstevel@tonic-gate if (change_status & PORT_CHANGE_PESC) {
19610Sstevel@tonic-gate /*
19620Sstevel@tonic-gate * Update the state depending on whether
19630Sstevel@tonic-gate * the port was enabled or disabled.
19640Sstevel@tonic-gate */
19650Sstevel@tonic-gate if (new_port_status & PORT_STATUS_PES) {
19660Sstevel@tonic-gate ehcip->ehci_root_hub.
19670Sstevel@tonic-gate rh_port_state[i] = ENABLED;
19680Sstevel@tonic-gate
19690Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
19700Sstevel@tonic-gate ehcip->ehci_log_hdl,
1971520Shx149380 "Port %d enabled", i+1);
19720Sstevel@tonic-gate } else {
19730Sstevel@tonic-gate ehcip->ehci_root_hub.
19740Sstevel@tonic-gate rh_port_state[i] = DISABLED;
19750Sstevel@tonic-gate
19760Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
19770Sstevel@tonic-gate ehcip->ehci_log_hdl,
1978520Shx149380 "Port %d disabled", i+1);
19790Sstevel@tonic-gate }
19800Sstevel@tonic-gate }
19810Sstevel@tonic-gate
19820Sstevel@tonic-gate port_mask |= 1 << (i + 1);
19830Sstevel@tonic-gate
19840Sstevel@tonic-gate /* Update the status */
19850Sstevel@tonic-gate ehcip->ehci_root_hub.
19860Sstevel@tonic-gate rh_port_status[i] = new_port_status;
19870Sstevel@tonic-gate }
19880Sstevel@tonic-gate }
19890Sstevel@tonic-gate
19900Sstevel@tonic-gate if (ph && port_mask && curr_intr_reqp) {
19910Sstevel@tonic-gate length = eptd->wMaxPacketSize;
19920Sstevel@tonic-gate
19930Sstevel@tonic-gate ASSERT(length != 0);
19940Sstevel@tonic-gate
19950Sstevel@tonic-gate /* Get the message block */
19960Sstevel@tonic-gate message = curr_intr_reqp->intr_data;
19970Sstevel@tonic-gate
19980Sstevel@tonic-gate ASSERT(message != NULL);
19990Sstevel@tonic-gate
20000Sstevel@tonic-gate do {
2001520Shx149380 /*
2002520Shx149380 * check that the mblk is big enough when we
2003520Shx149380 * are writing bytes into it
2004520Shx149380 */
2005520Shx149380 if (message->b_wptr >= message->b_datap->db_lim) {
2006520Shx149380
2007520Shx149380 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
2008520Shx149380 ehcip->ehci_log_hdl,
2009520Shx149380 "ehci_handle_root_hub_status_change"
2010520Shx149380 "mblk data overflow.");
2011520Shx149380
2012520Shx149380 break;
2013520Shx149380 }
20140Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)port_mask;
20150Sstevel@tonic-gate port_mask >>= 8;
20160Sstevel@tonic-gate } while (port_mask != 0);
20170Sstevel@tonic-gate
20180Sstevel@tonic-gate ehci_root_hub_hcdi_callback(ph, USB_CR_OK);
20190Sstevel@tonic-gate }
20200Sstevel@tonic-gate
20210Sstevel@tonic-gate /* Reset the timer id */
20220Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0;
20230Sstevel@tonic-gate
20240Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_intr_pipe_state ==
20250Sstevel@tonic-gate EHCI_PIPE_STATE_ACTIVE) {
20260Sstevel@tonic-gate /*
20270Sstevel@tonic-gate * If needed, allocate new interrupt request. Also
20280Sstevel@tonic-gate * start the timer for the root hub interrupt polling.
20290Sstevel@tonic-gate */
20300Sstevel@tonic-gate if ((ehci_root_hub_allocate_intr_pipe_resource(
20310Sstevel@tonic-gate ehcip, 0)) != USB_SUCCESS) {
20320Sstevel@tonic-gate
20330Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
20340Sstevel@tonic-gate "ehci_handle_root_hub_status_change: No Resources");
20350Sstevel@tonic-gate
20360Sstevel@tonic-gate /* Do interrupt pipe cleanup */
20370Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(
20380Sstevel@tonic-gate ehcip, USB_CR_NO_RESOURCES);
20390Sstevel@tonic-gate }
20400Sstevel@tonic-gate }
20410Sstevel@tonic-gate
20420Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
20430Sstevel@tonic-gate }
20440Sstevel@tonic-gate
20450Sstevel@tonic-gate
20460Sstevel@tonic-gate /*
20470Sstevel@tonic-gate * ehci_root_hub_hcdi_callback()
20480Sstevel@tonic-gate *
20490Sstevel@tonic-gate * Convenience wrapper around usba_hcdi_cb() for the root hub.
20500Sstevel@tonic-gate */
20510Sstevel@tonic-gate static void
ehci_root_hub_hcdi_callback(usba_pipe_handle_data_t * ph,usb_cr_t completion_reason)20520Sstevel@tonic-gate ehci_root_hub_hcdi_callback(
20530Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
20540Sstevel@tonic-gate usb_cr_t completion_reason)
20550Sstevel@tonic-gate {
20560Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
20576898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
20580Sstevel@tonic-gate uchar_t attributes = ph->p_ep.bmAttributes &
20596898Sfb209375 USB_EP_ATTR_MASK;
20600Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp;
20610Sstevel@tonic-gate uint_t pipe_state = 0;
20620Sstevel@tonic-gate
20630Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
20640Sstevel@tonic-gate "ehci_root_hub_hcdi_callback: ph = 0x%p, cr = 0x%x",
20656898Sfb209375 (void *)ph, completion_reason);
20660Sstevel@tonic-gate
20670Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
20680Sstevel@tonic-gate
20690Sstevel@tonic-gate /* Set the pipe state as per completion reason */
20700Sstevel@tonic-gate switch (completion_reason) {
20710Sstevel@tonic-gate case USB_CR_OK:
20720Sstevel@tonic-gate switch (attributes) {
20730Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
20740Sstevel@tonic-gate pipe_state = EHCI_PIPE_STATE_IDLE;
20750Sstevel@tonic-gate break;
20760Sstevel@tonic-gate case USB_EP_ATTR_INTR:
20770Sstevel@tonic-gate pipe_state = ehcip->ehci_root_hub.
20780Sstevel@tonic-gate rh_intr_pipe_state;
20790Sstevel@tonic-gate break;
20800Sstevel@tonic-gate }
20810Sstevel@tonic-gate break;
20820Sstevel@tonic-gate case USB_CR_NO_RESOURCES:
20830Sstevel@tonic-gate case USB_CR_NOT_SUPPORTED:
20840Sstevel@tonic-gate case USB_CR_STOPPED_POLLING:
20850Sstevel@tonic-gate case USB_CR_PIPE_RESET:
20860Sstevel@tonic-gate case USB_CR_HC_HARDWARE_ERR:
20870Sstevel@tonic-gate /* Set pipe state to idle */
20880Sstevel@tonic-gate pipe_state = EHCI_PIPE_STATE_IDLE;
20890Sstevel@tonic-gate break;
20900Sstevel@tonic-gate case USB_CR_PIPE_CLOSING:
20910Sstevel@tonic-gate break;
20920Sstevel@tonic-gate default:
20930Sstevel@tonic-gate /* Set pipe state to error */
20940Sstevel@tonic-gate pipe_state = EHCI_PIPE_STATE_ERROR;
20950Sstevel@tonic-gate break;
20960Sstevel@tonic-gate }
20970Sstevel@tonic-gate
20980Sstevel@tonic-gate switch (attributes) {
20990Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
21000Sstevel@tonic-gate curr_xfer_reqp = (usb_opaque_t)
21010Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
21020Sstevel@tonic-gate
21030Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_ctrl_reqp = NULL;
21040Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_state = pipe_state;
21050Sstevel@tonic-gate break;
21060Sstevel@tonic-gate case USB_EP_ATTR_INTR:
21070Sstevel@tonic-gate /* if curr_intr_reqp available then use this request */
21080Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_curr_intr_reqp) {
21090Sstevel@tonic-gate curr_xfer_reqp = (usb_opaque_t)ehcip->
21100Sstevel@tonic-gate ehci_root_hub.rh_curr_intr_reqp;
21110Sstevel@tonic-gate
21120Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL;
21130Sstevel@tonic-gate } else {
21140Sstevel@tonic-gate /* no current request, use client's request */
21150Sstevel@tonic-gate curr_xfer_reqp = (usb_opaque_t)
21160Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp;
21170Sstevel@tonic-gate
21180Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp = NULL;
21190Sstevel@tonic-gate }
21200Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_state = pipe_state;
21210Sstevel@tonic-gate break;
21220Sstevel@tonic-gate }
21230Sstevel@tonic-gate
21240Sstevel@tonic-gate ASSERT(curr_xfer_reqp != NULL);
21250Sstevel@tonic-gate
21260Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
21270Sstevel@tonic-gate usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
21280Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
21290Sstevel@tonic-gate }
2130