17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
53b00f311Syq * Common Development and Distribution License (the "License").
63b00f311Syq * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
226f6c7d2bSVincent Wang * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate */
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate * EHCI Host Controller Driver (EHCI)
277c478bd9Sstevel@tonic-gate *
287c478bd9Sstevel@tonic-gate * The EHCI driver is a software driver which interfaces to the Universal
297c478bd9Sstevel@tonic-gate * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
307c478bd9Sstevel@tonic-gate * the Host Controller is defined by the EHCI Host Controller Interface.
317c478bd9Sstevel@tonic-gate *
327c478bd9Sstevel@tonic-gate * This module contains the code for root hub related functions.
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate * NOTE:
357c478bd9Sstevel@tonic-gate *
367c478bd9Sstevel@tonic-gate * ONE_XFER is not supported on root hub interrupt polling
377c478bd9Sstevel@tonic-gate */
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
407c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h>
417c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_types.h>
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate /* Static function prototypes */
447c478bd9Sstevel@tonic-gate static int ehci_handle_set_clear_port_feature(
457c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
467c478bd9Sstevel@tonic-gate uchar_t bRequest,
477c478bd9Sstevel@tonic-gate uint16_t wValue,
487c478bd9Sstevel@tonic-gate uint16_t port);
497c478bd9Sstevel@tonic-gate static void ehci_handle_port_power(
507c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
517c478bd9Sstevel@tonic-gate uint16_t port,
527c478bd9Sstevel@tonic-gate uint_t on);
537c478bd9Sstevel@tonic-gate static void ehci_handle_port_enable(
547c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
557c478bd9Sstevel@tonic-gate uint16_t port,
567c478bd9Sstevel@tonic-gate uint_t on);
577c478bd9Sstevel@tonic-gate static void ehci_handle_clrchng_port_enable(
587c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
597c478bd9Sstevel@tonic-gate uint16_t port);
607c478bd9Sstevel@tonic-gate static void ehci_handle_port_suspend(
617c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
627c478bd9Sstevel@tonic-gate uint16_t port,
637c478bd9Sstevel@tonic-gate uint_t on);
647c478bd9Sstevel@tonic-gate static void ehci_handle_clrchng_port_suspend(
657c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
667c478bd9Sstevel@tonic-gate uint16_t port);
677c478bd9Sstevel@tonic-gate static void ehci_handle_port_reset(
687c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
697c478bd9Sstevel@tonic-gate uint16_t port);
707c478bd9Sstevel@tonic-gate static void ehci_root_hub_reset_occured(
717c478bd9Sstevel@tonic-gate ehci_state_t *ehcip);
727c478bd9Sstevel@tonic-gate static void ehci_handle_complete_port_reset(
737c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
747c478bd9Sstevel@tonic-gate uint16_t port);
757c478bd9Sstevel@tonic-gate static void ehci_handle_clear_port_connection(
767c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
777c478bd9Sstevel@tonic-gate uint16_t port);
787c478bd9Sstevel@tonic-gate static void ehci_handle_clrchng_port_over_current(
797c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
807c478bd9Sstevel@tonic-gate uint16_t port);
817c478bd9Sstevel@tonic-gate static void ehci_handle_get_port_status(
827c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
837c478bd9Sstevel@tonic-gate uint16_t port);
847c478bd9Sstevel@tonic-gate static void ehci_handle_get_hub_descriptor(
857c478bd9Sstevel@tonic-gate ehci_state_t *ehcip);
867c478bd9Sstevel@tonic-gate static void ehci_handle_get_hub_status(
877c478bd9Sstevel@tonic-gate ehci_state_t *ehcip);
8835f36846Ssl static void ehci_handle_get_device_status(
8935f36846Ssl ehci_state_t *ehcip);
907c478bd9Sstevel@tonic-gate static uint_t ehci_get_root_hub_port_status(
917c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
927c478bd9Sstevel@tonic-gate uint16_t port);
937c478bd9Sstevel@tonic-gate static int ehci_is_port_owner(
947c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
957c478bd9Sstevel@tonic-gate uint16_t port);
967c478bd9Sstevel@tonic-gate static int ehci_root_hub_allocate_intr_pipe_resource(
977c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
987c478bd9Sstevel@tonic-gate usb_flags_t flags);
997c478bd9Sstevel@tonic-gate static void ehci_root_hub_intr_pipe_cleanup(
1007c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
1017c478bd9Sstevel@tonic-gate usb_cr_t completion_reason);
1027c478bd9Sstevel@tonic-gate static void ehci_handle_root_hub_status_change(void *arg);
1037c478bd9Sstevel@tonic-gate static void ehci_root_hub_hcdi_callback(
1047c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1057c478bd9Sstevel@tonic-gate usb_cr_t completion_reason);
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate /*
1097c478bd9Sstevel@tonic-gate * ehci_init_root_hub:
1107c478bd9Sstevel@tonic-gate *
1117c478bd9Sstevel@tonic-gate * Initialize the root hub
1127c478bd9Sstevel@tonic-gate */
1137c478bd9Sstevel@tonic-gate int
ehci_init_root_hub(ehci_state_t * ehcip)1147c478bd9Sstevel@tonic-gate ehci_init_root_hub(ehci_state_t *ehcip)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate usb_hub_descr_t *root_hub_descr =
117112116d8Sfb &ehcip->ehci_root_hub.rh_descr;
1187c478bd9Sstevel@tonic-gate uint_t i, length, port_state;
1197c478bd9Sstevel@tonic-gate uint32_t capability;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1227c478bd9Sstevel@tonic-gate "ehci_init_root_hub:");
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate /* Read the EHCI capability register */
1257c478bd9Sstevel@tonic-gate capability = Get_Cap(ehci_hcs_params);
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate * Build the Root hub descriptor by looking EHCI capability
1297c478bd9Sstevel@tonic-gate * and operational registers.
1307c478bd9Sstevel@tonic-gate */
1317c478bd9Sstevel@tonic-gate root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE;
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate if ((capability & EHCI_HCS_NUM_PORTS) > EHCI_MAX_RH_PORTS) {
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1367c478bd9Sstevel@tonic-gate "ehci_init_root_hub: Invalid no of root hub ports 0x%x",
1377c478bd9Sstevel@tonic-gate capability & EHCI_HCS_NUM_PORTS);
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate return (USB_FAILURE);
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate /* Obtain the number of downstream ports */
1437c478bd9Sstevel@tonic-gate root_hub_descr->bNbrPorts = capability & EHCI_HCS_NUM_PORTS;
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate length = root_hub_descr->bNbrPorts / 8;
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate if (length) {
1487c478bd9Sstevel@tonic-gate root_hub_descr->bDescLength = 7 + (2 * (length + 1));
1497c478bd9Sstevel@tonic-gate } else {
1507c478bd9Sstevel@tonic-gate root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH;
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate * Obtain the number of Classic or Companion USB 1.1 (OHCI/UHCI)
1557c478bd9Sstevel@tonic-gate * Host Controllers information.
1567c478bd9Sstevel@tonic-gate */
1577c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_companion_controllers = (capability &
1587c478bd9Sstevel@tonic-gate EHCI_HCS_NUM_COMP_CTRLS) >> EHCI_HCS_NUM_COMP_CTRL_SHIFT;
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate /*
1617c478bd9Sstevel@tonic-gate * Determine the Power Switching Mode
1627c478bd9Sstevel@tonic-gate *
1637c478bd9Sstevel@tonic-gate * EHCI Specification, root hub supports either no power switching
1647c478bd9Sstevel@tonic-gate * individual port power switching. Also determine the Over-current
1657c478bd9Sstevel@tonic-gate * Protection Mode.
1667c478bd9Sstevel@tonic-gate */
1677c478bd9Sstevel@tonic-gate if (capability & EHCI_HCS_PORT_POWER_CONTROL) {
1687c478bd9Sstevel@tonic-gate /* Each port is powered individually */
1697c478bd9Sstevel@tonic-gate root_hub_descr-> wHubCharacteristics =
1707c478bd9Sstevel@tonic-gate HUB_CHARS_INDIVIDUAL_PORT_POWER;
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate /* Assume individual overcurrent reporting */
1737c478bd9Sstevel@tonic-gate root_hub_descr->wHubCharacteristics |=
1747c478bd9Sstevel@tonic-gate HUB_CHARS_INDIV_OVER_CURRENT;
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate /* Each port will start off in the POWERED_OFF mode */
1777c478bd9Sstevel@tonic-gate port_state = POWERED_OFF;
1787c478bd9Sstevel@tonic-gate } else {
1797c478bd9Sstevel@tonic-gate /* The ports are powered when the ctlr is powered */
1807c478bd9Sstevel@tonic-gate root_hub_descr->
1817c478bd9Sstevel@tonic-gate wHubCharacteristics = HUB_CHARS_NO_POWER_SWITCHING;
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate /* Assume no overcurrent reporting */
1847c478bd9Sstevel@tonic-gate root_hub_descr->wHubCharacteristics |=
1857c478bd9Sstevel@tonic-gate HUB_CHARS_NO_OVER_CURRENT;
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate port_state = DISCONNECTED;
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate /* Look at the port indicator information */
1917c478bd9Sstevel@tonic-gate if (capability & EHCI_HCS_PORT_INDICATOR) {
1927c478bd9Sstevel@tonic-gate root_hub_descr->wHubCharacteristics |= HUB_CHARS_PORT_INDICATOR;
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate /*
1967c478bd9Sstevel@tonic-gate * Obtain the power on to power good time of the ports.
1977c478bd9Sstevel@tonic-gate *
1987c478bd9Sstevel@tonic-gate * Assume: Zero for this field.
1997c478bd9Sstevel@tonic-gate */
2007c478bd9Sstevel@tonic-gate root_hub_descr->bPwrOn2PwrGood = 2;
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
2037c478bd9Sstevel@tonic-gate "Power on to power good %d", root_hub_descr->bPwrOn2PwrGood);
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate /* Indicate if the device is removable */
2067c478bd9Sstevel@tonic-gate root_hub_descr->DeviceRemovable = 0;
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate /* Set PortPowerControlMask to zero */
2097c478bd9Sstevel@tonic-gate root_hub_descr->PortPwrCtrlMask = 0;
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate /* Set the state of each port and initialize the status */
2127c478bd9Sstevel@tonic-gate for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate /* Initilize state/status of each root hub port */
2157c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_port_state[i] = port_state;
2167c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_port_status[i] = 0;
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate
2197c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate /*
2247c478bd9Sstevel@tonic-gate * ehci_load_root_hub_driver:
2257c478bd9Sstevel@tonic-gate *
2267c478bd9Sstevel@tonic-gate * Attach the root hub
2277c478bd9Sstevel@tonic-gate */
2287c478bd9Sstevel@tonic-gate static usb_dev_descr_t ehci_root_hub_device_descriptor = {
2297c478bd9Sstevel@tonic-gate 0x12, /* bLength */
2307c478bd9Sstevel@tonic-gate 0x01, /* bDescriptorType, Device */
2317c478bd9Sstevel@tonic-gate 0x200, /* bcdUSB, v2.0 */
2327c478bd9Sstevel@tonic-gate 0x09, /* bDeviceClass */
2337c478bd9Sstevel@tonic-gate 0x00, /* bDeviceSubClass */
2347c478bd9Sstevel@tonic-gate 0x01, /* bDeviceProtocol */
2357c478bd9Sstevel@tonic-gate 0x40, /* bMaxPacketSize0 */
2367c478bd9Sstevel@tonic-gate 0x00, /* idVendor */
2377c478bd9Sstevel@tonic-gate 0x00, /* idProduct */
2387c478bd9Sstevel@tonic-gate 0x00, /* bcdDevice */
2397c478bd9Sstevel@tonic-gate 0x00, /* iManufacturer */
2407c478bd9Sstevel@tonic-gate 0x00, /* iProduct */
2417c478bd9Sstevel@tonic-gate 0x00, /* iSerialNumber */
2427c478bd9Sstevel@tonic-gate 0x01 /* bNumConfigurations */
2437c478bd9Sstevel@tonic-gate };
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate static uchar_t ehci_root_hub_config_descriptor[] = {
2467c478bd9Sstevel@tonic-gate /* One configuartion */
2477c478bd9Sstevel@tonic-gate 0x09, /* bLength */
2487c478bd9Sstevel@tonic-gate 0x02, /* bDescriptorType, Configuartion */
2497c478bd9Sstevel@tonic-gate 0x19, 0x00, /* wTotalLength */
2507c478bd9Sstevel@tonic-gate 0x01, /* bNumInterfaces */
2517c478bd9Sstevel@tonic-gate 0x01, /* bConfigurationValue */
2527c478bd9Sstevel@tonic-gate 0x00, /* iConfiguration */
2537c478bd9Sstevel@tonic-gate 0x40, /* bmAttributes */
2547c478bd9Sstevel@tonic-gate 0x00, /* MaxPower */
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate /* One Interface */
2577c478bd9Sstevel@tonic-gate 0x09, /* bLength */
2587c478bd9Sstevel@tonic-gate 0x04, /* bDescriptorType, Interface */
2597c478bd9Sstevel@tonic-gate 0x00, /* bInterfaceNumber */
2607c478bd9Sstevel@tonic-gate 0x00, /* bAlternateSetting */
2617c478bd9Sstevel@tonic-gate 0x01, /* bNumEndpoints */
2627c478bd9Sstevel@tonic-gate 0x09, /* bInterfaceClass */
2637c478bd9Sstevel@tonic-gate 0x01, /* bInterfaceSubClass */
2647c478bd9Sstevel@tonic-gate 0x00, /* bInterfaceProtocol */
2657c478bd9Sstevel@tonic-gate 0x00, /* iInterface */
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate /* One Endpoint (status change endpoint) */
2687c478bd9Sstevel@tonic-gate 0x07, /* bLength */
2697c478bd9Sstevel@tonic-gate 0x05, /* bDescriptorType, Endpoint */
2707c478bd9Sstevel@tonic-gate 0x81, /* bEndpointAddress */
2717c478bd9Sstevel@tonic-gate 0x03, /* bmAttributes */
272112116d8Sfb 0x01, 0x00, /* wMaxPacketSize, 1 + (EHCI_MAX_RH_PORTS / 8) */
2737c478bd9Sstevel@tonic-gate 0xff /* bInterval */
2747c478bd9Sstevel@tonic-gate };
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate int
ehci_load_root_hub_driver(ehci_state_t * ehcip)2777c478bd9Sstevel@tonic-gate ehci_load_root_hub_driver(ehci_state_t *ehcip)
2787c478bd9Sstevel@tonic-gate {
2797c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
2807c478bd9Sstevel@tonic-gate "ehci_load_root_hub_driver:");
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate return (usba_hubdi_bind_root_hub(ehcip->ehci_dip,
2837c478bd9Sstevel@tonic-gate ehci_root_hub_config_descriptor,
2847c478bd9Sstevel@tonic-gate sizeof (ehci_root_hub_config_descriptor),
2857c478bd9Sstevel@tonic-gate &ehci_root_hub_device_descriptor));
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate /*
2907c478bd9Sstevel@tonic-gate * ehci_unload_root_hub_driver:
2917c478bd9Sstevel@tonic-gate */
2927c478bd9Sstevel@tonic-gate int
ehci_unload_root_hub_driver(ehci_state_t * ehcip)2937c478bd9Sstevel@tonic-gate ehci_unload_root_hub_driver(ehci_state_t *ehcip)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
2967c478bd9Sstevel@tonic-gate "ehci_unload_root_hub_driver:");
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate return (usba_hubdi_unbind_root_hub(ehcip->ehci_dip));
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate /*
3037c478bd9Sstevel@tonic-gate * ehci_handle_root_hub_pipe_open:
3047c478bd9Sstevel@tonic-gate *
3057c478bd9Sstevel@tonic-gate * Handle opening of control and interrupt pipes on root hub.
3067c478bd9Sstevel@tonic-gate */
3077c478bd9Sstevel@tonic-gate /* ARGSUSED */
3087c478bd9Sstevel@tonic-gate int
ehci_handle_root_hub_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)3097c478bd9Sstevel@tonic-gate ehci_handle_root_hub_pipe_open(
3107c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
3117c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
314112116d8Sfb ph->p_usba_device->usb_root_hub_dip);
3157c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3187c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_open: Root hub pipe open");
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
3237c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
3247c478bd9Sstevel@tonic-gate /* Save control pipe handle */
3257c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_handle = ph;
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate /* Set state of the root hub control pipe as idle */
3287c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_IDLE;
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_ctrl_reqp = NULL;
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3337c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_open: Root hub control "
3347c478bd9Sstevel@tonic-gate "pipe open succeeded");
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate break;
3377c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
3387c478bd9Sstevel@tonic-gate /* Save interrupt pipe handle */
3397c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_handle = ph;
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate /* Set state of the root hub interrupt pipe as idle */
3427c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_state = EHCI_PIPE_STATE_IDLE;
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp = NULL;
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL;
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3497c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_open: Root hub interrupt "
3507c478bd9Sstevel@tonic-gate "pipe open succeeded");
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate break;
3537c478bd9Sstevel@tonic-gate default:
3547c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3557c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_open: Root hub pipe open"
3567c478bd9Sstevel@tonic-gate "failed");
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate return (USB_FAILURE);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate ehcip->ehci_open_pipe_count++;
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate /*
3687c478bd9Sstevel@tonic-gate * ehci_handle_root_hub_pipe_close:
3697c478bd9Sstevel@tonic-gate *
3707c478bd9Sstevel@tonic-gate * Handle closing of control and interrupt pipes on root hub.
3717c478bd9Sstevel@tonic-gate */
3727c478bd9Sstevel@tonic-gate /* ARGSUSED */
3737c478bd9Sstevel@tonic-gate int
ehci_handle_root_hub_pipe_close(usba_pipe_handle_data_t * ph)3747c478bd9Sstevel@tonic-gate ehci_handle_root_hub_pipe_close(usba_pipe_handle_data_t *ph)
3757c478bd9Sstevel@tonic-gate {
3767c478bd9Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
377112116d8Sfb ph->p_usba_device->usb_root_hub_dip);
3787c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3817c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_close: Root hub pipe close");
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
3867c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
3877c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.
3887c478bd9Sstevel@tonic-gate rh_ctrl_pipe_state != EHCI_PIPE_STATE_CLOSE);
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate /* Set state of the root hub control pipe as close */
3917c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_CLOSE;
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate /* Set root hub control pipe handle to null */
3947c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_handle = NULL;
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
3977c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_close: "
3987c478bd9Sstevel@tonic-gate "Root hub control pipe close succeeded");
3997c478bd9Sstevel@tonic-gate break;
4007c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
4017c478bd9Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.
4047c478bd9Sstevel@tonic-gate rh_intr_pipe_state != EHCI_PIPE_STATE_CLOSE);
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate /* Set state of the root hub interrupt pipe as close */
4077c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_state = EHCI_PIPE_STATE_CLOSE;
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate /* Do interrupt pipe cleanup */
4107c478bd9Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_PIPE_CLOSING);
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate /* Set root hub interrupt pipe handle to null */
4137c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_handle = NULL;
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4167c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_close: "
4177c478bd9Sstevel@tonic-gate "Root hub interrupt pipe close succeeded");
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate break;
4207c478bd9Sstevel@tonic-gate default:
4217c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4227c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_close: "
4237c478bd9Sstevel@tonic-gate "Root hub pipe close failed");
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate return (USB_FAILURE);
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate ehcip->ehci_open_pipe_count--;
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate * ehci_handle_root_hub_pipe_reset:
4367c478bd9Sstevel@tonic-gate *
4377c478bd9Sstevel@tonic-gate * Handle resetting of control and interrupt pipes on root hub.
4387c478bd9Sstevel@tonic-gate */
4397c478bd9Sstevel@tonic-gate /* ARGSUSED */
4407c478bd9Sstevel@tonic-gate int
ehci_handle_root_hub_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)4417c478bd9Sstevel@tonic-gate ehci_handle_root_hub_pipe_reset(
4427c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
4437c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
446112116d8Sfb ph->p_usba_device->usb_root_hub_dip);
4477c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
4487c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4517c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_reset: Root hub pipe reset");
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
4567c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
4577c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_IDLE;
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4607c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_reset: Pipe reset"
4617c478bd9Sstevel@tonic-gate "for the root hub control pipe successful");
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate break;
4647c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
4657c478bd9Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate if ((ehcip->ehci_root_hub.rh_client_intr_reqp) &&
4687c478bd9Sstevel@tonic-gate (ehcip->ehci_root_hub.rh_intr_pipe_state !=
4697c478bd9Sstevel@tonic-gate EHCI_PIPE_STATE_IDLE)) {
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.
4727c478bd9Sstevel@tonic-gate rh_intr_pipe_state = EHCI_PIPE_STATE_RESET;
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate /* Do interrupt pipe cleanup */
4757c478bd9Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(
4767c478bd9Sstevel@tonic-gate ehcip, USB_CR_PIPE_RESET);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.
4807c478bd9Sstevel@tonic-gate rh_intr_pipe_state == EHCI_PIPE_STATE_IDLE);
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4837c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_reset: "
4847c478bd9Sstevel@tonic-gate "Pipe reset for root hub interrupt pipe successful");
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate break;
4877c478bd9Sstevel@tonic-gate default:
4887c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
4897c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_reset: "
4907c478bd9Sstevel@tonic-gate "Root hub pipe reset failed");
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate error = USB_FAILURE;
4937c478bd9Sstevel@tonic-gate break;
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate return (error);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate /*
5037c478bd9Sstevel@tonic-gate * ehci_handle_root_hub_request:
5047c478bd9Sstevel@tonic-gate *
5057c478bd9Sstevel@tonic-gate * Intercept a root hub request. Handle the root hub request through the
5067c478bd9Sstevel@tonic-gate * registers
5077c478bd9Sstevel@tonic-gate */
5087c478bd9Sstevel@tonic-gate /* ARGSUSED */
5097c478bd9Sstevel@tonic-gate int
ehci_handle_root_hub_request(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp)5107c478bd9Sstevel@tonic-gate ehci_handle_root_hub_request(
5117c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
5127c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
5137c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp)
5147c478bd9Sstevel@tonic-gate {
5157c478bd9Sstevel@tonic-gate uchar_t bmRequestType = ctrl_reqp->ctrl_bmRequestType;
5167c478bd9Sstevel@tonic-gate uchar_t bRequest = ctrl_reqp->ctrl_bRequest;
5177c478bd9Sstevel@tonic-gate uint16_t wValue = ctrl_reqp->ctrl_wValue;
5187c478bd9Sstevel@tonic-gate uint16_t wIndex = ctrl_reqp->ctrl_wIndex;
5197c478bd9Sstevel@tonic-gate uint16_t wLength = ctrl_reqp->ctrl_wLength;
5207c478bd9Sstevel@tonic-gate mblk_t *data = ctrl_reqp->ctrl_data;
5217c478bd9Sstevel@tonic-gate uint16_t port = wIndex - 1;
5227c478bd9Sstevel@tonic-gate usb_cr_t completion_reason;
5237c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
5267c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p",
5277c478bd9Sstevel@tonic-gate bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data);
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate if (ehcip->ehci_root_hub.
5327c478bd9Sstevel@tonic-gate rh_ctrl_pipe_state != EHCI_PIPE_STATE_IDLE) {
5337c478bd9Sstevel@tonic-gate
5347c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
5357c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_request: Pipe is not idle");
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate return (USB_FAILURE);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate /* Save the current control request pointer */
5437c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_ctrl_reqp = ctrl_reqp;
5447c478bd9Sstevel@tonic-gate
5457c478bd9Sstevel@tonic-gate /* Set pipe state to active */
5467c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_ACTIVE;
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate switch (bmRequestType) {
55135f36846Ssl case HUB_GET_DEVICE_STATUS_TYPE:
55235f36846Ssl ehci_handle_get_device_status(ehcip);
55335f36846Ssl break;
55435f36846Ssl case HUB_HANDLE_PORT_FEATURE_TYPE:
5557c478bd9Sstevel@tonic-gate error = ehci_handle_set_clear_port_feature(ehcip,
5567c478bd9Sstevel@tonic-gate bRequest, wValue, port);
5577c478bd9Sstevel@tonic-gate break;
55835f36846Ssl case HUB_GET_PORT_STATUS_TYPE:
5597c478bd9Sstevel@tonic-gate ehci_handle_get_port_status(ehcip, port);
5607c478bd9Sstevel@tonic-gate break;
56135f36846Ssl case HUB_CLASS_REQ_TYPE:
5627c478bd9Sstevel@tonic-gate switch (bRequest) {
5637c478bd9Sstevel@tonic-gate case USB_REQ_GET_STATUS:
5647c478bd9Sstevel@tonic-gate ehci_handle_get_hub_status(ehcip);
5657c478bd9Sstevel@tonic-gate break;
5667c478bd9Sstevel@tonic-gate case USB_REQ_GET_DESCR:
5677c478bd9Sstevel@tonic-gate ehci_handle_get_hub_descriptor(ehcip);
5687c478bd9Sstevel@tonic-gate break;
5697c478bd9Sstevel@tonic-gate default:
5707c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
5717c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_request:"
5727c478bd9Sstevel@tonic-gate "Unsupported request 0x%x", bRequest);
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate error = USB_FAILURE;
5757c478bd9Sstevel@tonic-gate break;
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate break;
5787c478bd9Sstevel@tonic-gate default:
5797c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
5807c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_request: "
5817c478bd9Sstevel@tonic-gate "Unsupported request 0x%x", bmRequestType);
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate error = USB_FAILURE;
5847c478bd9Sstevel@tonic-gate break;
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate
5877c478bd9Sstevel@tonic-gate completion_reason = (error) ? USB_CR_NOT_SUPPORTED : USB_CR_OK;
5887c478bd9Sstevel@tonic-gate
5897c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
5907c478bd9Sstevel@tonic-gate ehci_root_hub_hcdi_callback(ph, completion_reason);
5917c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
5927c478bd9Sstevel@tonic-gate
5937c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
5947c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_request: error = %d", error);
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate
6007c478bd9Sstevel@tonic-gate /*
6017c478bd9Sstevel@tonic-gate * ehci_handle_set_clear_port_feature:
6027c478bd9Sstevel@tonic-gate */
6037c478bd9Sstevel@tonic-gate static int
ehci_handle_set_clear_port_feature(ehci_state_t * ehcip,uchar_t bRequest,uint16_t wValue,uint16_t port)6047c478bd9Sstevel@tonic-gate ehci_handle_set_clear_port_feature(
6057c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
6067c478bd9Sstevel@tonic-gate uchar_t bRequest,
6077c478bd9Sstevel@tonic-gate uint16_t wValue,
6087c478bd9Sstevel@tonic-gate uint16_t port)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
6137c478bd9Sstevel@tonic-gate "ehci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x",
6147c478bd9Sstevel@tonic-gate bRequest, wValue, port);
6157c478bd9Sstevel@tonic-gate
6167c478bd9Sstevel@tonic-gate switch (bRequest) {
6177c478bd9Sstevel@tonic-gate case USB_REQ_SET_FEATURE:
6187c478bd9Sstevel@tonic-gate switch (wValue) {
6197c478bd9Sstevel@tonic-gate case CFS_PORT_ENABLE:
6207c478bd9Sstevel@tonic-gate ehci_handle_port_enable(ehcip, port, 1);
6217c478bd9Sstevel@tonic-gate break;
6227c478bd9Sstevel@tonic-gate case CFS_PORT_SUSPEND:
6237c478bd9Sstevel@tonic-gate ehci_handle_port_suspend(ehcip, port, 1);
6247c478bd9Sstevel@tonic-gate break;
6257c478bd9Sstevel@tonic-gate case CFS_PORT_RESET:
6267c478bd9Sstevel@tonic-gate ehci_handle_port_reset(ehcip, port);
6277c478bd9Sstevel@tonic-gate break;
6287c478bd9Sstevel@tonic-gate case CFS_PORT_POWER:
6297c478bd9Sstevel@tonic-gate ehci_handle_port_power(ehcip, port, 1);
6307c478bd9Sstevel@tonic-gate break;
6317c478bd9Sstevel@tonic-gate default:
6327c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
6337c478bd9Sstevel@tonic-gate "ehci_handle_set_clear_port_feature: "
6347c478bd9Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate error = USB_FAILURE;
6377c478bd9Sstevel@tonic-gate break;
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate break;
6407c478bd9Sstevel@tonic-gate case USB_REQ_CLEAR_FEATURE:
6417c478bd9Sstevel@tonic-gate switch (wValue) {
6427c478bd9Sstevel@tonic-gate case CFS_PORT_ENABLE:
6437c478bd9Sstevel@tonic-gate ehci_handle_port_enable(ehcip, port, 0);
6447c478bd9Sstevel@tonic-gate break;
6457c478bd9Sstevel@tonic-gate case CFS_C_PORT_ENABLE:
6467c478bd9Sstevel@tonic-gate ehci_handle_clrchng_port_enable(ehcip, port);
6477c478bd9Sstevel@tonic-gate break;
6487c478bd9Sstevel@tonic-gate case CFS_PORT_SUSPEND:
6497c478bd9Sstevel@tonic-gate ehci_handle_port_suspend(ehcip, port, 0);
6507c478bd9Sstevel@tonic-gate break;
6517c478bd9Sstevel@tonic-gate case CFS_C_PORT_SUSPEND:
6527c478bd9Sstevel@tonic-gate ehci_handle_clrchng_port_suspend(ehcip, port);
6537c478bd9Sstevel@tonic-gate break;
6547c478bd9Sstevel@tonic-gate case CFS_C_PORT_RESET:
6557c478bd9Sstevel@tonic-gate ehci_handle_complete_port_reset(ehcip, port);
6567c478bd9Sstevel@tonic-gate break;
6577c478bd9Sstevel@tonic-gate case CFS_PORT_POWER:
6587c478bd9Sstevel@tonic-gate ehci_handle_port_power(ehcip, port, 0);
6597c478bd9Sstevel@tonic-gate break;
6607c478bd9Sstevel@tonic-gate case CFS_C_PORT_CONNECTION:
6617c478bd9Sstevel@tonic-gate ehci_handle_clear_port_connection(ehcip, port);
6627c478bd9Sstevel@tonic-gate break;
6637c478bd9Sstevel@tonic-gate case CFS_C_PORT_OVER_CURRENT:
6647c478bd9Sstevel@tonic-gate ehci_handle_clrchng_port_over_current(ehcip, port);
6657c478bd9Sstevel@tonic-gate break;
6667c478bd9Sstevel@tonic-gate default:
6677c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
6687c478bd9Sstevel@tonic-gate "ehci_handle_set_clear_port_feature: "
6697c478bd9Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate error = USB_FAILURE;
6727c478bd9Sstevel@tonic-gate break;
6737c478bd9Sstevel@tonic-gate }
674112116d8Sfb break;
6757c478bd9Sstevel@tonic-gate default:
6767c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
6777c478bd9Sstevel@tonic-gate "ehci_handle_set_clear_port_feature: "
6787c478bd9Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate error = USB_FAILURE;
6817c478bd9Sstevel@tonic-gate break;
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate return (error);
6857c478bd9Sstevel@tonic-gate }
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate /*
6897c478bd9Sstevel@tonic-gate * ehci_handle_port_power:
6907c478bd9Sstevel@tonic-gate *
6917c478bd9Sstevel@tonic-gate * Turn on a root hub port.
6927c478bd9Sstevel@tonic-gate */
6937c478bd9Sstevel@tonic-gate static void
ehci_handle_port_power(ehci_state_t * ehcip,uint16_t port,uint_t on)6947c478bd9Sstevel@tonic-gate ehci_handle_port_power(
6957c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
6967c478bd9Sstevel@tonic-gate uint16_t port,
6977c478bd9Sstevel@tonic-gate uint_t on)
6987c478bd9Sstevel@tonic-gate {
6997c478bd9Sstevel@tonic-gate uint_t port_status;
7007c478bd9Sstevel@tonic-gate ehci_root_hub_t *rh;
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
7057c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate rh = &ehcip->ehci_root_hub;
7087c478bd9Sstevel@tonic-gate
7097c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
7107c478bd9Sstevel@tonic-gate "ehci_handle_port_power: port = 0x%x status = 0x%x on = %d",
7117c478bd9Sstevel@tonic-gate port, port_status, on);
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate /* Check port is owned by ehci */
7147c478bd9Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
7157c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate return;
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate if (on) {
7217c478bd9Sstevel@tonic-gate /* See if the port power is already on */
7227c478bd9Sstevel@tonic-gate if (!(port_status & EHCI_RH_PORT_POWER)) {
7237c478bd9Sstevel@tonic-gate /* Turn the port on */
7247c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
7257c478bd9Sstevel@tonic-gate port_status | EHCI_RH_PORT_POWER);
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate rh->rh_port_status[port] = 0;
7297c478bd9Sstevel@tonic-gate rh->rh_port_state[port] = DISCONNECTED;
7307c478bd9Sstevel@tonic-gate } else {
7317c478bd9Sstevel@tonic-gate /* See if the port power is already OFF */
7327c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_POWER) {
7337c478bd9Sstevel@tonic-gate /* Turn-off the port */
7347c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
7357c478bd9Sstevel@tonic-gate port_status & ~EHCI_RH_PORT_POWER);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate rh->rh_port_status[port] = 0;
7397c478bd9Sstevel@tonic-gate rh->rh_port_state[port] = POWERED_OFF;
7407c478bd9Sstevel@tonic-gate }
7417c478bd9Sstevel@tonic-gate
7427c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
7437c478bd9Sstevel@tonic-gate "ehci_handle_port_power done: port = 0x%x status = 0x%x on = %d",
7447c478bd9Sstevel@tonic-gate port, Get_OpReg(ehci_rh_port_status[port]), on);
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate
7507c478bd9Sstevel@tonic-gate /*
7517c478bd9Sstevel@tonic-gate * ehci_handle_port_enable:
7527c478bd9Sstevel@tonic-gate *
7537c478bd9Sstevel@tonic-gate * Handle port enable request.
7547c478bd9Sstevel@tonic-gate */
7557c478bd9Sstevel@tonic-gate static void
ehci_handle_port_enable(ehci_state_t * ehcip,uint16_t port,uint_t on)7567c478bd9Sstevel@tonic-gate ehci_handle_port_enable(
7577c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
7587c478bd9Sstevel@tonic-gate uint16_t port,
7597c478bd9Sstevel@tonic-gate uint_t on)
7607c478bd9Sstevel@tonic-gate {
7617c478bd9Sstevel@tonic-gate uint_t port_status;
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
7667c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
7697c478bd9Sstevel@tonic-gate "ehci_handle_port_enable: port = 0x%x, status = 0x%x",
7707c478bd9Sstevel@tonic-gate port, port_status);
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate /* Check port is owned by ehci */
7737c478bd9Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
7747c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
7757c478bd9Sstevel@tonic-gate
7767c478bd9Sstevel@tonic-gate return;
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate if (on) {
7807c478bd9Sstevel@tonic-gate /* See if the port enable is already on */
7817c478bd9Sstevel@tonic-gate if (!(port_status & EHCI_RH_PORT_ENABLE)) {
7827c478bd9Sstevel@tonic-gate /* Enable the port */
7837c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
7847c478bd9Sstevel@tonic-gate port_status | EHCI_RH_PORT_ENABLE);
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate } else {
7877c478bd9Sstevel@tonic-gate /* See if the port enable is already off */
7887c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_ENABLE) {
7897c478bd9Sstevel@tonic-gate /* Disable the port */
7907c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
7917c478bd9Sstevel@tonic-gate port_status & ~EHCI_RH_PORT_ENABLE);
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate
7957c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate /*
8007c478bd9Sstevel@tonic-gate * ehci_handle_clrchng_port_enable:
8017c478bd9Sstevel@tonic-gate *
8027c478bd9Sstevel@tonic-gate * Handle clear port enable change bit.
8037c478bd9Sstevel@tonic-gate */
8047c478bd9Sstevel@tonic-gate static void
ehci_handle_clrchng_port_enable(ehci_state_t * ehcip,uint16_t port)8057c478bd9Sstevel@tonic-gate ehci_handle_clrchng_port_enable(
8067c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
8077c478bd9Sstevel@tonic-gate uint16_t port)
8087c478bd9Sstevel@tonic-gate {
8097c478bd9Sstevel@tonic-gate uint_t port_status;
8107c478bd9Sstevel@tonic-gate
8117c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
8127c478bd9Sstevel@tonic-gate
8137c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
8147c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
8157c478bd9Sstevel@tonic-gate
8167c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
8177c478bd9Sstevel@tonic-gate "ehci_handle_port_enable: port = 0x%x, status = 0x%x",
8187c478bd9Sstevel@tonic-gate port, port_status);
8197c478bd9Sstevel@tonic-gate
8207c478bd9Sstevel@tonic-gate /* Check port is owned by ehci */
8217c478bd9Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
8227c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
8237c478bd9Sstevel@tonic-gate
8247c478bd9Sstevel@tonic-gate return;
8257c478bd9Sstevel@tonic-gate }
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate /* Clear the PortEnableStatusChange Bit */
8287c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
8297c478bd9Sstevel@tonic-gate port_status | EHCI_RH_PORT_ENABLE_CHANGE);
8307c478bd9Sstevel@tonic-gate
8317c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate /*
8367c478bd9Sstevel@tonic-gate * ehci_handle_port_suspend:
8377c478bd9Sstevel@tonic-gate *
8387c478bd9Sstevel@tonic-gate * Handle port suspend/resume request.
8397c478bd9Sstevel@tonic-gate */
8407c478bd9Sstevel@tonic-gate static void
ehci_handle_port_suspend(ehci_state_t * ehcip,uint16_t port,uint_t on)8417c478bd9Sstevel@tonic-gate ehci_handle_port_suspend(
8427c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
8437c478bd9Sstevel@tonic-gate uint16_t port,
8447c478bd9Sstevel@tonic-gate uint_t on)
8457c478bd9Sstevel@tonic-gate {
8467c478bd9Sstevel@tonic-gate uint_t port_status;
8477c478bd9Sstevel@tonic-gate
8487c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
8517c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
8527c478bd9Sstevel@tonic-gate
8537c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
8547c478bd9Sstevel@tonic-gate "ehci_handle_port_suspend: port = 0x%x, status = 0x%x",
8557c478bd9Sstevel@tonic-gate port, port_status);
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate /* Check port is owned by ehci */
8587c478bd9Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
8597c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate return;
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate if (on) {
8657c478bd9Sstevel@tonic-gate /*
8667c478bd9Sstevel@tonic-gate * Suspend port only if port is enabled and
8677c478bd9Sstevel@tonic-gate * it is not already in suspend state.
8687c478bd9Sstevel@tonic-gate */
8697c478bd9Sstevel@tonic-gate if ((port_status & EHCI_RH_PORT_ENABLE) &&
8707c478bd9Sstevel@tonic-gate (!(port_status & EHCI_RH_PORT_SUSPEND))) {
8717c478bd9Sstevel@tonic-gate /* Suspend the port */
8727c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
8737c478bd9Sstevel@tonic-gate port_status | EHCI_RH_PORT_SUSPEND);
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate /* Wait 10ms for port move to suspend state */
8787c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_PORT_SUSPEND_TIMEWAIT));
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate return;
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate } else {
8837c478bd9Sstevel@tonic-gate /* Perform resume only if port is in suspend state */
8847c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_SUSPEND) {
8857c478bd9Sstevel@tonic-gate /* Resume the port */
8867c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
8877c478bd9Sstevel@tonic-gate port_status | EHCI_RH_PORT_RESUME);
8887c478bd9Sstevel@tonic-gate }
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
8927c478bd9Sstevel@tonic-gate }
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate
8957c478bd9Sstevel@tonic-gate /*
8967c478bd9Sstevel@tonic-gate * ehci_handle_clrchng_port_suspend:
8977c478bd9Sstevel@tonic-gate *
8987c478bd9Sstevel@tonic-gate * Handle port clear port suspend change bit.
8997c478bd9Sstevel@tonic-gate */
9007c478bd9Sstevel@tonic-gate static void
ehci_handle_clrchng_port_suspend(ehci_state_t * ehcip,uint16_t port)9017c478bd9Sstevel@tonic-gate ehci_handle_clrchng_port_suspend(
9027c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
9037c478bd9Sstevel@tonic-gate uint16_t port)
9047c478bd9Sstevel@tonic-gate {
9057c478bd9Sstevel@tonic-gate uint_t port_status;
9063d89ea2cSpengcheng chen - Sun Microsystems - Beijing China int i;
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
9097c478bd9Sstevel@tonic-gate
9107c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
9117c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
9127c478bd9Sstevel@tonic-gate
9137c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
9147c478bd9Sstevel@tonic-gate "ehci_handle_clrchng_port_suspend: port = 0x%x, "
9157c478bd9Sstevel@tonic-gate "status = 0x%x", port, port_status);
9167c478bd9Sstevel@tonic-gate
9177c478bd9Sstevel@tonic-gate /* Check port is owned by ehci */
9187c478bd9Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
9197c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate return;
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate /* Return if port is not in resume state */
9257c478bd9Sstevel@tonic-gate if (!(port_status & EHCI_RH_PORT_RESUME)) {
9267c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
9277c478bd9Sstevel@tonic-gate
9287c478bd9Sstevel@tonic-gate return;
9297c478bd9Sstevel@tonic-gate }
9307c478bd9Sstevel@tonic-gate
9317c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate /* Wait for 20ms to terminate resume */
9347c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_PORT_RESUME_TIMEWAIT));
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
9377c478bd9Sstevel@tonic-gate
9387c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
9397c478bd9Sstevel@tonic-gate port_status & ~EHCI_RH_PORT_RESUME);
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
9427c478bd9Sstevel@tonic-gate
9433d89ea2cSpengcheng chen - Sun Microsystems - Beijing China /*
9443d89ea2cSpengcheng chen - Sun Microsystems - Beijing China * Wait for port to return to high speed mode. It's necessary to poll
9453d89ea2cSpengcheng chen - Sun Microsystems - Beijing China * for resume completion for some high-speed devices to work correctly.
9463d89ea2cSpengcheng chen - Sun Microsystems - Beijing China */
9473d89ea2cSpengcheng chen - Sun Microsystems - Beijing China for (i = 0; i < EHCI_PORT_RESUME_RETRY_MAX; i++) {
9483d89ea2cSpengcheng chen - Sun Microsystems - Beijing China delay(drv_usectohz(EHCI_PORT_RESUME_COMP_TIMEWAIT));
9493d89ea2cSpengcheng chen - Sun Microsystems - Beijing China
9503d89ea2cSpengcheng chen - Sun Microsystems - Beijing China mutex_enter(&ehcip->ehci_int_mutex);
9513d89ea2cSpengcheng chen - Sun Microsystems - Beijing China port_status = Get_OpReg(ehci_rh_port_status[port]) &
9523d89ea2cSpengcheng chen - Sun Microsystems - Beijing China ~EHCI_RH_PORT_CLEAR_MASK;
9533d89ea2cSpengcheng chen - Sun Microsystems - Beijing China mutex_exit(&ehcip->ehci_int_mutex);
9543d89ea2cSpengcheng chen - Sun Microsystems - Beijing China
9553d89ea2cSpengcheng chen - Sun Microsystems - Beijing China if (!(port_status & EHCI_RH_PORT_RESUME)) {
9563d89ea2cSpengcheng chen - Sun Microsystems - Beijing China break;
9573d89ea2cSpengcheng chen - Sun Microsystems - Beijing China }
9583d89ea2cSpengcheng chen - Sun Microsystems - Beijing China }
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate
9617c478bd9Sstevel@tonic-gate
9627c478bd9Sstevel@tonic-gate /*
9637c478bd9Sstevel@tonic-gate * ehci_handle_port_reset:
9647c478bd9Sstevel@tonic-gate *
9657c478bd9Sstevel@tonic-gate * Perform a port reset.
9667c478bd9Sstevel@tonic-gate */
9677c478bd9Sstevel@tonic-gate static void
ehci_handle_port_reset(ehci_state_t * ehcip,uint16_t port)9687c478bd9Sstevel@tonic-gate ehci_handle_port_reset(
9697c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
9707c478bd9Sstevel@tonic-gate uint16_t port)
9717c478bd9Sstevel@tonic-gate {
9727c478bd9Sstevel@tonic-gate ehci_root_hub_t *rh;
9737c478bd9Sstevel@tonic-gate uint_t port_status;
9743d89ea2cSpengcheng chen - Sun Microsystems - Beijing China int i;
9757c478bd9Sstevel@tonic-gate
9767c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
9777c478bd9Sstevel@tonic-gate
9787c478bd9Sstevel@tonic-gate /* Get the root hub structure */
9797c478bd9Sstevel@tonic-gate rh = &ehcip->ehci_root_hub;
9807c478bd9Sstevel@tonic-gate
9817c478bd9Sstevel@tonic-gate /* Get the port status information */
9827c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
9837c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
9847c478bd9Sstevel@tonic-gate
9857c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
9867c478bd9Sstevel@tonic-gate "ehci_handle_port_reset: port = 0x%x status = 0x%x",
9877c478bd9Sstevel@tonic-gate port, port_status);
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate /* Check port is owned by ehci */
9907c478bd9Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
9917c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
9927c478bd9Sstevel@tonic-gate
9937c478bd9Sstevel@tonic-gate return;
9947c478bd9Sstevel@tonic-gate }
9957c478bd9Sstevel@tonic-gate
9967c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_LOW_SPEED) {
9977c478bd9Sstevel@tonic-gate /* Check for classic or companion host controllers */
9987c478bd9Sstevel@tonic-gate if (rh->rh_companion_controllers) {
9997c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
10007c478bd9Sstevel@tonic-gate "ehci_handle_port_reset: Low speed device "
10017c478bd9Sstevel@tonic-gate "and handover this port to Companion controller");
10027c478bd9Sstevel@tonic-gate
10037c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
10047c478bd9Sstevel@tonic-gate port_status | EHCI_RH_PORT_OWNER_CLASSIC);
10057c478bd9Sstevel@tonic-gate } else {
10067c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
10077c478bd9Sstevel@tonic-gate "Low speed device is not supported");
10087c478bd9Sstevel@tonic-gate }
10097c478bd9Sstevel@tonic-gate } else {
10107c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
10117c478bd9Sstevel@tonic-gate ((port_status | EHCI_RH_PORT_RESET) &
10127c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_ENABLE));
10137c478bd9Sstevel@tonic-gate
10147c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
10157c478bd9Sstevel@tonic-gate
10163d89ea2cSpengcheng chen - Sun Microsystems - Beijing China /* Wait 50ms for reset to complete */
10177c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_PORT_RESET_TIMEWAIT));
10187c478bd9Sstevel@tonic-gate
10197c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
10207c478bd9Sstevel@tonic-gate
10217c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
10227c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
10237c478bd9Sstevel@tonic-gate
10247c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
10257c478bd9Sstevel@tonic-gate (port_status & ~EHCI_RH_PORT_RESET));
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
10287c478bd9Sstevel@tonic-gate
10297c478bd9Sstevel@tonic-gate /*
10303d89ea2cSpengcheng chen - Sun Microsystems - Beijing China * Wait for hardware to enable this port, if the connected
10313d89ea2cSpengcheng chen - Sun Microsystems - Beijing China * usb device is high speed. It's necessary to poll for reset
10323d89ea2cSpengcheng chen - Sun Microsystems - Beijing China * completion for some high-speed devices to recognized
10333d89ea2cSpengcheng chen - Sun Microsystems - Beijing China * correctly.
10347c478bd9Sstevel@tonic-gate */
10353d89ea2cSpengcheng chen - Sun Microsystems - Beijing China for (i = 0; i < EHCI_PORT_RESET_RETRY_MAX; i++) {
10363d89ea2cSpengcheng chen - Sun Microsystems - Beijing China delay(drv_usectohz(EHCI_PORT_RESET_COMP_TIMEWAIT));
10373d89ea2cSpengcheng chen - Sun Microsystems - Beijing China
10383d89ea2cSpengcheng chen - Sun Microsystems - Beijing China mutex_enter(&ehcip->ehci_int_mutex);
10393d89ea2cSpengcheng chen - Sun Microsystems - Beijing China port_status = Get_OpReg(ehci_rh_port_status[port]) &
10403d89ea2cSpengcheng chen - Sun Microsystems - Beijing China ~EHCI_RH_PORT_CLEAR_MASK;
10413d89ea2cSpengcheng chen - Sun Microsystems - Beijing China mutex_exit(&ehcip->ehci_int_mutex);
10423d89ea2cSpengcheng chen - Sun Microsystems - Beijing China
10433d89ea2cSpengcheng chen - Sun Microsystems - Beijing China if (!(port_status & EHCI_RH_PORT_RESET)) {
10443d89ea2cSpengcheng chen - Sun Microsystems - Beijing China break;
10453d89ea2cSpengcheng chen - Sun Microsystems - Beijing China }
10463d89ea2cSpengcheng chen - Sun Microsystems - Beijing China }
10477c478bd9Sstevel@tonic-gate
10487c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
10517c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
10527c478bd9Sstevel@tonic-gate
10537c478bd9Sstevel@tonic-gate /*
10547c478bd9Sstevel@tonic-gate * If port is not enabled, connected device is a
10557c478bd9Sstevel@tonic-gate * Full-speed usb device.
10567c478bd9Sstevel@tonic-gate */
10577c478bd9Sstevel@tonic-gate if (!(port_status & EHCI_RH_PORT_ENABLE)) {
10587c478bd9Sstevel@tonic-gate /* Check for classic or companion host controllers */
10597c478bd9Sstevel@tonic-gate if (rh->rh_companion_controllers) {
10607c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
10617c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl,
10627c478bd9Sstevel@tonic-gate "ehci_handle_port_reset: Full speed device "
10637c478bd9Sstevel@tonic-gate "and handover this port to Companion host "
10647c478bd9Sstevel@tonic-gate "controller");
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
10677c478bd9Sstevel@tonic-gate port_status | EHCI_RH_PORT_OWNER_CLASSIC);
10687c478bd9Sstevel@tonic-gate } else {
10697c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ROOT_HUB,
10707c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl,
10717c478bd9Sstevel@tonic-gate "Full speed device is not supported");
10727c478bd9Sstevel@tonic-gate }
10737c478bd9Sstevel@tonic-gate } else {
10747c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
10757c478bd9Sstevel@tonic-gate "ehci_handle_port_reset: High speed device ");
10767c478bd9Sstevel@tonic-gate
10777c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
10787c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate /*
10816f6c7d2bSVincent Wang * Disable over-current, connect, and disconnect
10827c478bd9Sstevel@tonic-gate * wakeup bits.
10837c478bd9Sstevel@tonic-gate */
10846f6c7d2bSVincent Wang Set_OpReg(ehci_rh_port_status[port], port_status &
10856f6c7d2bSVincent Wang ~(EHCI_RH_PORT_OVER_CURENT_ENABLE |
10867c478bd9Sstevel@tonic-gate EHCI_RH_PORT_DISCONNECT_ENABLE |
10877c478bd9Sstevel@tonic-gate EHCI_RH_PORT_CONNECT_ENABLE));
10887c478bd9Sstevel@tonic-gate
10897c478bd9Sstevel@tonic-gate /*
10907c478bd9Sstevel@tonic-gate * The next function is only called if the interrupt
10917c478bd9Sstevel@tonic-gate * pipe is polling and the USBA is ready to receive
10927c478bd9Sstevel@tonic-gate * the data.
10937c478bd9Sstevel@tonic-gate */
10947c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.
10957c478bd9Sstevel@tonic-gate rh_intr_pending_status |= (1 << port);
10967c478bd9Sstevel@tonic-gate
10977c478bd9Sstevel@tonic-gate if (ehcip->ehci_root_hub.
10987c478bd9Sstevel@tonic-gate rh_intr_pipe_state == EHCI_PIPE_STATE_ACTIVE) {
10997c478bd9Sstevel@tonic-gate
11007c478bd9Sstevel@tonic-gate ehci_root_hub_reset_occured(ehcip);
11017c478bd9Sstevel@tonic-gate }
11027c478bd9Sstevel@tonic-gate }
11037c478bd9Sstevel@tonic-gate }
11047c478bd9Sstevel@tonic-gate
11057c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
11067c478bd9Sstevel@tonic-gate }
11077c478bd9Sstevel@tonic-gate
11087c478bd9Sstevel@tonic-gate
11097c478bd9Sstevel@tonic-gate /*
11107c478bd9Sstevel@tonic-gate * ehci_root_hub_reset_occured:
11117c478bd9Sstevel@tonic-gate *
11127c478bd9Sstevel@tonic-gate * Inform the upper layer that reset has occured on the port. This is
11137c478bd9Sstevel@tonic-gate * required because the upper layer is expecting a an evernt immidiately
11147c478bd9Sstevel@tonic-gate * after doing reset. In case of OHCI, the controller gets an interrupt
11157c478bd9Sstevel@tonic-gate * for the change in the root hub status but in case of EHCI, we dont.
11167c478bd9Sstevel@tonic-gate * So, send a event to the upper layer as soon as we complete the reset.
11177c478bd9Sstevel@tonic-gate */
11187c478bd9Sstevel@tonic-gate void
ehci_root_hub_reset_occured(ehci_state_t * ehcip)11197c478bd9Sstevel@tonic-gate ehci_root_hub_reset_occured(
11207c478bd9Sstevel@tonic-gate ehci_state_t *ehcip)
11217c478bd9Sstevel@tonic-gate {
11227c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp =
1123112116d8Sfb ehcip->ehci_root_hub.rh_curr_intr_reqp;
11247c478bd9Sstevel@tonic-gate usb_port_mask_t port_mask;
11257c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
11267c478bd9Sstevel@tonic-gate
11277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
11287c478bd9Sstevel@tonic-gate "ehci_root_hub_reset_occured: curr_intr_reqp = 0x%p data = 0x%p",
1129112116d8Sfb (void *)curr_intr_reqp, (void *)curr_intr_reqp->intr_data);
11307c478bd9Sstevel@tonic-gate
11317c478bd9Sstevel@tonic-gate /* Get the interrupt pipe handle */
11327c478bd9Sstevel@tonic-gate ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
11337c478bd9Sstevel@tonic-gate
11347c478bd9Sstevel@tonic-gate /* Get the pending status */
11357c478bd9Sstevel@tonic-gate port_mask = ehcip->ehci_root_hub.rh_intr_pending_status << 1;
11367c478bd9Sstevel@tonic-gate
11377c478bd9Sstevel@tonic-gate do {
11387c478bd9Sstevel@tonic-gate *curr_intr_reqp->intr_data->b_wptr++ = (uchar_t)port_mask;
11397c478bd9Sstevel@tonic-gate port_mask >>= 8;
11407c478bd9Sstevel@tonic-gate } while (port_mask != 0);
11417c478bd9Sstevel@tonic-gate
11427c478bd9Sstevel@tonic-gate ehci_root_hub_hcdi_callback(ph, USB_CR_OK);
11437c478bd9Sstevel@tonic-gate
11447c478bd9Sstevel@tonic-gate /* Reset pending status */
11457c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pending_status = 0;
11467c478bd9Sstevel@tonic-gate
11477c478bd9Sstevel@tonic-gate /* If needed, allocate new interrupt request */
11487c478bd9Sstevel@tonic-gate if ((ehci_root_hub_allocate_intr_pipe_resource(
11497c478bd9Sstevel@tonic-gate ehcip, 0)) != USB_SUCCESS) {
11507c478bd9Sstevel@tonic-gate
11517c478bd9Sstevel@tonic-gate /* Do interrupt pipe cleanup */
11527c478bd9Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_NO_RESOURCES);
11537c478bd9Sstevel@tonic-gate }
11547c478bd9Sstevel@tonic-gate }
11557c478bd9Sstevel@tonic-gate
11567c478bd9Sstevel@tonic-gate
11577c478bd9Sstevel@tonic-gate /*
11587c478bd9Sstevel@tonic-gate * ehci_handle_complete_port_reset:
11597c478bd9Sstevel@tonic-gate *
11607c478bd9Sstevel@tonic-gate * Perform a port reset change.
11617c478bd9Sstevel@tonic-gate */
11627c478bd9Sstevel@tonic-gate static void
ehci_handle_complete_port_reset(ehci_state_t * ehcip,uint16_t port)11637c478bd9Sstevel@tonic-gate ehci_handle_complete_port_reset(
11647c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
11657c478bd9Sstevel@tonic-gate uint16_t port)
11667c478bd9Sstevel@tonic-gate {
11677c478bd9Sstevel@tonic-gate uint_t port_status;
11687c478bd9Sstevel@tonic-gate
11697c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
11727c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
11737c478bd9Sstevel@tonic-gate
11747c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
11757c478bd9Sstevel@tonic-gate "ehci_handle_complete_port_reset: port = 0x%x status = 0x%x",
11767c478bd9Sstevel@tonic-gate port, port_status);
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gate /* Check port is owned by ehci */
11797c478bd9Sstevel@tonic-gate if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
11807c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate return;
11837c478bd9Sstevel@tonic-gate }
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_RESET) {
11867c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
11877c478bd9Sstevel@tonic-gate port_status & ~EHCI_RH_PORT_RESET);
11887c478bd9Sstevel@tonic-gate
11897c478bd9Sstevel@tonic-gate }
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
11927c478bd9Sstevel@tonic-gate }
11937c478bd9Sstevel@tonic-gate
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate /*
11967c478bd9Sstevel@tonic-gate * ehci_handle_clear_port_connection:
11977c478bd9Sstevel@tonic-gate *
11987c478bd9Sstevel@tonic-gate * Perform a clear port connection.
11997c478bd9Sstevel@tonic-gate */
12007c478bd9Sstevel@tonic-gate static void
ehci_handle_clear_port_connection(ehci_state_t * ehcip,uint16_t port)12017c478bd9Sstevel@tonic-gate ehci_handle_clear_port_connection(
12027c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
12037c478bd9Sstevel@tonic-gate uint16_t port)
12047c478bd9Sstevel@tonic-gate {
12057c478bd9Sstevel@tonic-gate uint_t port_status;
12067c478bd9Sstevel@tonic-gate
12077c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
12087c478bd9Sstevel@tonic-gate
12097c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
12107c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
12117c478bd9Sstevel@tonic-gate
12127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
12137c478bd9Sstevel@tonic-gate "ehci_handle_clear_port_connection: port = 0x%x"
12147c478bd9Sstevel@tonic-gate "status = 0x%x", port, port_status);
12157c478bd9Sstevel@tonic-gate
12167c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
12177c478bd9Sstevel@tonic-gate port_status | EHCI_RH_PORT_CONNECT_STS_CHANGE);
12187c478bd9Sstevel@tonic-gate
12197c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate /*
12247c478bd9Sstevel@tonic-gate * ehci_handle_clrchng_port_over_current:
12257c478bd9Sstevel@tonic-gate *
12267c478bd9Sstevel@tonic-gate * Perform a clear port connection.
12277c478bd9Sstevel@tonic-gate */
12287c478bd9Sstevel@tonic-gate static void
ehci_handle_clrchng_port_over_current(ehci_state_t * ehcip,uint16_t port)12297c478bd9Sstevel@tonic-gate ehci_handle_clrchng_port_over_current(
12307c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
12317c478bd9Sstevel@tonic-gate uint16_t port)
12327c478bd9Sstevel@tonic-gate {
12337c478bd9Sstevel@tonic-gate uint_t port_status;
12347c478bd9Sstevel@tonic-gate
12357c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
12367c478bd9Sstevel@tonic-gate
12377c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
12387c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
12397c478bd9Sstevel@tonic-gate
12407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
12417c478bd9Sstevel@tonic-gate "ehci_handle_clrchng_port_over_current: port = 0x%x"
12427c478bd9Sstevel@tonic-gate "status = 0x%x", port, port_status);
12437c478bd9Sstevel@tonic-gate
12447c478bd9Sstevel@tonic-gate Set_OpReg(ehci_rh_port_status[port],
12457c478bd9Sstevel@tonic-gate port_status | EHCI_RH_PORT_OVER_CURR_CHANGE);
12467c478bd9Sstevel@tonic-gate
12477c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
12487c478bd9Sstevel@tonic-gate }
12497c478bd9Sstevel@tonic-gate
12507c478bd9Sstevel@tonic-gate
12517c478bd9Sstevel@tonic-gate /*
12527c478bd9Sstevel@tonic-gate * ehci_handle_get_port_status:
12537c478bd9Sstevel@tonic-gate *
12547c478bd9Sstevel@tonic-gate * Handle a get port status request.
12557c478bd9Sstevel@tonic-gate */
12567c478bd9Sstevel@tonic-gate static void
ehci_handle_get_port_status(ehci_state_t * ehcip,uint16_t port)12577c478bd9Sstevel@tonic-gate ehci_handle_get_port_status(
12587c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
12597c478bd9Sstevel@tonic-gate uint16_t port)
12607c478bd9Sstevel@tonic-gate {
12617c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp;
12627c478bd9Sstevel@tonic-gate mblk_t *message;
12637c478bd9Sstevel@tonic-gate uint_t new_port_status = 0;
12647c478bd9Sstevel@tonic-gate uint_t change_status = 0;
12657c478bd9Sstevel@tonic-gate uint_t port_status;
12667c478bd9Sstevel@tonic-gate
12677c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate /* Get the root hub port status information */
12727c478bd9Sstevel@tonic-gate port_status = ehci_get_root_hub_port_status(ehcip, port);
12737c478bd9Sstevel@tonic-gate
12747c478bd9Sstevel@tonic-gate new_port_status = port_status & PORT_STATUS_MASK;
1275*993e3fafSRobert Mustacchi change_status = (port_status >> 16) & PORT_CHANGE_MASK_2X;
12767c478bd9Sstevel@tonic-gate
12777c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_port_status[port] = new_port_status;
12787c478bd9Sstevel@tonic-gate
12797c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
12807c478bd9Sstevel@tonic-gate "ehci_handle_get_port_status: port = %d new status = 0x%x"
12817c478bd9Sstevel@tonic-gate "change = 0x%x", port, new_port_status, change_status);
12827c478bd9Sstevel@tonic-gate
12837c478bd9Sstevel@tonic-gate message = ctrl_reqp->ctrl_data;
12847c478bd9Sstevel@tonic-gate
12857c478bd9Sstevel@tonic-gate ASSERT(message != NULL);
12867c478bd9Sstevel@tonic-gate
12877c478bd9Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)new_port_status;
12887c478bd9Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_port_status >> 8);
12897c478bd9Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)change_status;
12907c478bd9Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(change_status >> 8);
12917c478bd9Sstevel@tonic-gate
12927c478bd9Sstevel@tonic-gate /* Save the data in control request */
12937c478bd9Sstevel@tonic-gate ctrl_reqp->ctrl_data = message;
12947c478bd9Sstevel@tonic-gate
12957c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
12967c478bd9Sstevel@tonic-gate }
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate
12997c478bd9Sstevel@tonic-gate /*
13007c478bd9Sstevel@tonic-gate * ehci_handle_get_hub_descriptor:
13017c478bd9Sstevel@tonic-gate */
13027c478bd9Sstevel@tonic-gate static void
ehci_handle_get_hub_descriptor(ehci_state_t * ehcip)13037c478bd9Sstevel@tonic-gate ehci_handle_get_hub_descriptor(
13047c478bd9Sstevel@tonic-gate ehci_state_t *ehcip)
13057c478bd9Sstevel@tonic-gate {
13067c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp;
13077c478bd9Sstevel@tonic-gate mblk_t *message;
13087c478bd9Sstevel@tonic-gate usb_hub_descr_t *root_hub_descr;
13097c478bd9Sstevel@tonic-gate size_t length;
13107c478bd9Sstevel@tonic-gate uchar_t raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH];
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
13137c478bd9Sstevel@tonic-gate
13147c478bd9Sstevel@tonic-gate ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
13157c478bd9Sstevel@tonic-gate root_hub_descr = &ehcip->ehci_root_hub.rh_descr;
13167c478bd9Sstevel@tonic-gate length = ctrl_reqp->ctrl_wLength;
13177c478bd9Sstevel@tonic-gate
13187c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1319112116d8Sfb "ehci_handle_get_hub_descriptor: Ctrl Req = 0x%p",
1320112116d8Sfb (void *)ctrl_reqp);
13217c478bd9Sstevel@tonic-gate
13227c478bd9Sstevel@tonic-gate message = ctrl_reqp->ctrl_data;
13237c478bd9Sstevel@tonic-gate
13247c478bd9Sstevel@tonic-gate ASSERT(message != NULL);
13257c478bd9Sstevel@tonic-gate
13267c478bd9Sstevel@tonic-gate bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH);
13277c478bd9Sstevel@tonic-gate
13287c478bd9Sstevel@tonic-gate raw_descr[0] = root_hub_descr->bDescLength;
13297c478bd9Sstevel@tonic-gate raw_descr[1] = root_hub_descr->bDescriptorType;
13307c478bd9Sstevel@tonic-gate raw_descr[2] = root_hub_descr->bNbrPorts;
13317c478bd9Sstevel@tonic-gate raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00FF;
13327c478bd9Sstevel@tonic-gate raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xFF00) >> 8;
13337c478bd9Sstevel@tonic-gate raw_descr[5] = root_hub_descr->bPwrOn2PwrGood;
13347c478bd9Sstevel@tonic-gate raw_descr[6] = root_hub_descr->bHubContrCurrent;
13357c478bd9Sstevel@tonic-gate raw_descr[7] = root_hub_descr->DeviceRemovable;
13367c478bd9Sstevel@tonic-gate raw_descr[8] = root_hub_descr->PortPwrCtrlMask;
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate bcopy(raw_descr, message->b_wptr, length);
13397c478bd9Sstevel@tonic-gate message->b_wptr += length;
13407c478bd9Sstevel@tonic-gate
13417c478bd9Sstevel@tonic-gate /* Save the data in control request */
13427c478bd9Sstevel@tonic-gate ctrl_reqp->ctrl_data = message;
13437c478bd9Sstevel@tonic-gate
13447c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
13457c478bd9Sstevel@tonic-gate }
13467c478bd9Sstevel@tonic-gate
13477c478bd9Sstevel@tonic-gate
13487c478bd9Sstevel@tonic-gate /*
13497c478bd9Sstevel@tonic-gate * ehci_handle_get_hub_status:
13507c478bd9Sstevel@tonic-gate *
13517c478bd9Sstevel@tonic-gate * Handle a get hub status request.
13527c478bd9Sstevel@tonic-gate */
13537c478bd9Sstevel@tonic-gate static void
ehci_handle_get_hub_status(ehci_state_t * ehcip)13547c478bd9Sstevel@tonic-gate ehci_handle_get_hub_status(
13557c478bd9Sstevel@tonic-gate ehci_state_t *ehcip)
13567c478bd9Sstevel@tonic-gate {
13577c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp;
13587c478bd9Sstevel@tonic-gate mblk_t *message;
13597c478bd9Sstevel@tonic-gate uint_t new_root_hub_status;
13607c478bd9Sstevel@tonic-gate
13617c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
13627c478bd9Sstevel@tonic-gate
13637c478bd9Sstevel@tonic-gate ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
13647c478bd9Sstevel@tonic-gate
13657c478bd9Sstevel@tonic-gate /*
13667c478bd9Sstevel@tonic-gate * For EHCI, there is no overall hub status information.
13677c478bd9Sstevel@tonic-gate * Only individual root hub port status information is
13687c478bd9Sstevel@tonic-gate * available. So return zero for the root hub status
13697c478bd9Sstevel@tonic-gate * request.
13707c478bd9Sstevel@tonic-gate */
13717c478bd9Sstevel@tonic-gate new_root_hub_status = 0;
13727c478bd9Sstevel@tonic-gate
13737c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
13747c478bd9Sstevel@tonic-gate "ehci_handle_get_hub_status: new root hub status = 0x%x",
13757c478bd9Sstevel@tonic-gate new_root_hub_status);
13767c478bd9Sstevel@tonic-gate
13777c478bd9Sstevel@tonic-gate message = ctrl_reqp->ctrl_data;
13787c478bd9Sstevel@tonic-gate
13797c478bd9Sstevel@tonic-gate ASSERT(message != NULL);
13807c478bd9Sstevel@tonic-gate
13817c478bd9Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)new_root_hub_status;
13827c478bd9Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 8);
13837c478bd9Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 16);
13847c478bd9Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 24);
13857c478bd9Sstevel@tonic-gate
13867c478bd9Sstevel@tonic-gate /* Save the data in control request */
13877c478bd9Sstevel@tonic-gate ctrl_reqp->ctrl_data = message;
13887c478bd9Sstevel@tonic-gate
13897c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
13907c478bd9Sstevel@tonic-gate }
13917c478bd9Sstevel@tonic-gate
13927c478bd9Sstevel@tonic-gate
139335f36846Ssl /*
139435f36846Ssl * ehci_handle_get_device_status:
139535f36846Ssl *
139635f36846Ssl * Handle a get device status request.
139735f36846Ssl */
139835f36846Ssl static void
ehci_handle_get_device_status(ehci_state_t * ehcip)139935f36846Ssl ehci_handle_get_device_status(
140035f36846Ssl ehci_state_t *ehcip)
140135f36846Ssl {
140235f36846Ssl usb_ctrl_req_t *ctrl_reqp;
140335f36846Ssl mblk_t *message;
140435f36846Ssl uint16_t dev_status;
140535f36846Ssl
140635f36846Ssl mutex_enter(&ehcip->ehci_int_mutex);
140735f36846Ssl
140835f36846Ssl ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
140935f36846Ssl
141035f36846Ssl /*
141135f36846Ssl * For EHCI, there is no device status information.
141235f36846Ssl * Simply return what is desired for the request.
141335f36846Ssl */
141435f36846Ssl dev_status = USB_DEV_SLF_PWRD_STATUS;
141535f36846Ssl
141635f36846Ssl USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
141735f36846Ssl "ehci_handle_get_device_status: device status = 0x%x",
141835f36846Ssl dev_status);
141935f36846Ssl
142035f36846Ssl message = ctrl_reqp->ctrl_data;
142135f36846Ssl
142235f36846Ssl ASSERT(message != NULL);
142335f36846Ssl
142435f36846Ssl *message->b_wptr++ = (uchar_t)dev_status;
142535f36846Ssl *message->b_wptr++ = (uchar_t)(dev_status >> 8);
142635f36846Ssl
142735f36846Ssl /* Save the data in control request */
142835f36846Ssl ctrl_reqp->ctrl_data = message;
142935f36846Ssl
143035f36846Ssl mutex_exit(&ehcip->ehci_int_mutex);
143135f36846Ssl }
143235f36846Ssl
143335f36846Ssl
14347c478bd9Sstevel@tonic-gate /*
14357c478bd9Sstevel@tonic-gate * ehci_handle_root_hub_pipe_start_intr_polling:
14367c478bd9Sstevel@tonic-gate *
14377c478bd9Sstevel@tonic-gate * Handle start polling on root hub interrupt pipe.
14387c478bd9Sstevel@tonic-gate */
14397c478bd9Sstevel@tonic-gate /* ARGSUSED */
14407c478bd9Sstevel@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)14417c478bd9Sstevel@tonic-gate ehci_handle_root_hub_pipe_start_intr_polling(
14427c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
14437c478bd9Sstevel@tonic-gate usb_intr_req_t *client_intr_reqp,
14447c478bd9Sstevel@tonic-gate usb_flags_t flags)
14457c478bd9Sstevel@tonic-gate {
14467c478bd9Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
1447112116d8Sfb ph->p_usba_device->usb_root_hub_dip);
14487c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
14497c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
14507c478bd9Sstevel@tonic-gate uint_t pipe_state;
14517c478bd9Sstevel@tonic-gate
14527c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
14537c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_start_intr_polling: "
14547c478bd9Sstevel@tonic-gate "Root hub pipe start polling");
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
14577c478bd9Sstevel@tonic-gate
14587c478bd9Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
14597c478bd9Sstevel@tonic-gate
14607c478bd9Sstevel@tonic-gate ASSERT((client_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) == 0);
14617c478bd9Sstevel@tonic-gate
14627c478bd9Sstevel@tonic-gate pipe_state = ehcip->ehci_root_hub.rh_intr_pipe_state;
14637c478bd9Sstevel@tonic-gate
14647c478bd9Sstevel@tonic-gate switch (pipe_state) {
14657c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_IDLE:
14667c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.rh_intr_pipe_timer_id == 0);
14677c478bd9Sstevel@tonic-gate
14687c478bd9Sstevel@tonic-gate /*
14697c478bd9Sstevel@tonic-gate * Save the Original Client's Interrupt IN request
14707c478bd9Sstevel@tonic-gate * information. We use this for final callback
14717c478bd9Sstevel@tonic-gate */
14727c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.rh_client_intr_reqp == NULL);
14737c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp = client_intr_reqp;
14747c478bd9Sstevel@tonic-gate
14757c478bd9Sstevel@tonic-gate error = ehci_root_hub_allocate_intr_pipe_resource(ehcip, flags);
14767c478bd9Sstevel@tonic-gate
14777c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) {
14787c478bd9Sstevel@tonic-gate /* Reset client interrupt request pointer */
14797c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp = NULL;
14807c478bd9Sstevel@tonic-gate
14817c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
14827c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_start_intr_polling: "
14837c478bd9Sstevel@tonic-gate "No Resources");
14847c478bd9Sstevel@tonic-gate
14857c478bd9Sstevel@tonic-gate return (error);
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate
14887c478bd9Sstevel@tonic-gate /* Check whether we need to send the reset data up */
14897c478bd9Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_intr_pending_status) {
14907c478bd9Sstevel@tonic-gate ehci_root_hub_reset_occured(ehcip);
14917c478bd9Sstevel@tonic-gate }
14927c478bd9Sstevel@tonic-gate
14937c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
14947c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_start_intr_polling: "
14957c478bd9Sstevel@tonic-gate "Start polling for root hub successful");
14967c478bd9Sstevel@tonic-gate
14977c478bd9Sstevel@tonic-gate break;
14987c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_ACTIVE:
14997c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
15007c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_start_intr_polling: "
15017c478bd9Sstevel@tonic-gate "Polling for root hub is already in progress");
15027c478bd9Sstevel@tonic-gate
15037c478bd9Sstevel@tonic-gate break;
15047c478bd9Sstevel@tonic-gate default:
15057c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
15067c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_start_intr_polling: "
15077c478bd9Sstevel@tonic-gate "Pipe is in error state 0x%x", pipe_state);
15087c478bd9Sstevel@tonic-gate
15097c478bd9Sstevel@tonic-gate error = USB_FAILURE;
15107c478bd9Sstevel@tonic-gate
15117c478bd9Sstevel@tonic-gate break;
15127c478bd9Sstevel@tonic-gate }
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate return (error);
15157c478bd9Sstevel@tonic-gate }
15167c478bd9Sstevel@tonic-gate
15177c478bd9Sstevel@tonic-gate
15187c478bd9Sstevel@tonic-gate /*
15197c478bd9Sstevel@tonic-gate * ehci_handle_root_hub_pipe_stop_intr_polling:
15207c478bd9Sstevel@tonic-gate *
15217c478bd9Sstevel@tonic-gate * Handle stop polling on root hub intr pipe.
15227c478bd9Sstevel@tonic-gate */
15237c478bd9Sstevel@tonic-gate /* ARGSUSED */
15247c478bd9Sstevel@tonic-gate void
ehci_handle_root_hub_pipe_stop_intr_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)15257c478bd9Sstevel@tonic-gate ehci_handle_root_hub_pipe_stop_intr_polling(
15267c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
15277c478bd9Sstevel@tonic-gate usb_flags_t flags)
15287c478bd9Sstevel@tonic-gate {
15297c478bd9Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
1530112116d8Sfb ph->p_usba_device->usb_root_hub_dip);
15317c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
15327c478bd9Sstevel@tonic-gate
15337c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
15347c478bd9Sstevel@tonic-gate
15357c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
15367c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_pipe_stop_intr_polling: "
15377c478bd9Sstevel@tonic-gate "Root hub pipe stop polling");
15387c478bd9Sstevel@tonic-gate
15397c478bd9Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
15407c478bd9Sstevel@tonic-gate
15417c478bd9Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_intr_pipe_state ==
15427c478bd9Sstevel@tonic-gate EHCI_PIPE_STATE_ACTIVE) {
15437c478bd9Sstevel@tonic-gate
15447c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_state =
15457c478bd9Sstevel@tonic-gate EHCI_PIPE_STATE_STOP_POLLING;
15467c478bd9Sstevel@tonic-gate
15477c478bd9Sstevel@tonic-gate /* Do interrupt pipe cleanup */
15487c478bd9Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_STOPPED_POLLING);
15497c478bd9Sstevel@tonic-gate
15507c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.
15517c478bd9Sstevel@tonic-gate rh_intr_pipe_state == EHCI_PIPE_STATE_IDLE);
15527c478bd9Sstevel@tonic-gate
15537c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
15547c478bd9Sstevel@tonic-gate "ehci_hcdi_pipe_stop_intr_polling: Stop polling for root"
15557c478bd9Sstevel@tonic-gate "hub successful");
15567c478bd9Sstevel@tonic-gate } else {
15577c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
15587c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, "ehci_hcdi_pipe_stop_intr_polling: "
15597c478bd9Sstevel@tonic-gate "Polling for root hub is already stopped");
15607c478bd9Sstevel@tonic-gate }
15617c478bd9Sstevel@tonic-gate }
15627c478bd9Sstevel@tonic-gate
15637c478bd9Sstevel@tonic-gate
15647c478bd9Sstevel@tonic-gate /*
15657c478bd9Sstevel@tonic-gate * ehci_get_root_hub_port_status:
15667c478bd9Sstevel@tonic-gate *
15677c478bd9Sstevel@tonic-gate * Construct root hub port status and change information
15687c478bd9Sstevel@tonic-gate */
15697c478bd9Sstevel@tonic-gate static uint_t
ehci_get_root_hub_port_status(ehci_state_t * ehcip,uint16_t port)15707c478bd9Sstevel@tonic-gate ehci_get_root_hub_port_status(
15717c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
15727c478bd9Sstevel@tonic-gate uint16_t port)
15737c478bd9Sstevel@tonic-gate {
15747c478bd9Sstevel@tonic-gate uint_t new_port_status = 0;
15757c478bd9Sstevel@tonic-gate uint_t change_status = 0;
15767c478bd9Sstevel@tonic-gate uint_t port_status;
15777c478bd9Sstevel@tonic-gate
15787c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
15797c478bd9Sstevel@tonic-gate
15807c478bd9Sstevel@tonic-gate /* Read the current port status */
15817c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]);
15827c478bd9Sstevel@tonic-gate
15837c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
15847c478bd9Sstevel@tonic-gate "ehci_get_root_hub_port_status: port %d "
15857c478bd9Sstevel@tonic-gate "port status = 0x%x", port, port_status);
15867c478bd9Sstevel@tonic-gate
15877c478bd9Sstevel@tonic-gate /*
15887c478bd9Sstevel@tonic-gate * EHCI root hub port status and control register information
15897c478bd9Sstevel@tonic-gate * format is different what Hub driver wants. So EHCI driver
15907c478bd9Sstevel@tonic-gate * needs to contruct the proper root hub port status information.
15917c478bd9Sstevel@tonic-gate *
15927c478bd9Sstevel@tonic-gate * Send all port status information only if port is owned by EHCI
15937c478bd9Sstevel@tonic-gate * host controller.
15947c478bd9Sstevel@tonic-gate */
15957c478bd9Sstevel@tonic-gate if ((port_status & EHCI_RH_PORT_OWNER) == EHCI_RH_PORT_OWNER_EHCI) {
15967c478bd9Sstevel@tonic-gate
15977c478bd9Sstevel@tonic-gate /* First construct port change information */
15987c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_ENABLE_CHANGE) {
15997c478bd9Sstevel@tonic-gate change_status |= PORT_CHANGE_PESC;
16007c478bd9Sstevel@tonic-gate }
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_RESUME) {
16037c478bd9Sstevel@tonic-gate change_status |= PORT_CHANGE_PSSC;
16047c478bd9Sstevel@tonic-gate }
16057c478bd9Sstevel@tonic-gate
16067c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_OVER_CURR_CHANGE) {
16077c478bd9Sstevel@tonic-gate change_status |= PORT_CHANGE_OCIC;
16087c478bd9Sstevel@tonic-gate }
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate /* Now construct port status information */
16117c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_CONNECT_STATUS) {
16127c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_CCS;
16137c478bd9Sstevel@tonic-gate }
16147c478bd9Sstevel@tonic-gate
16157c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_ENABLE) {
16167c478bd9Sstevel@tonic-gate new_port_status |=
16177c478bd9Sstevel@tonic-gate (PORT_STATUS_PES | PORT_STATUS_HSDA);
16187c478bd9Sstevel@tonic-gate }
16197c478bd9Sstevel@tonic-gate
16207c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_SUSPEND) {
16217c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_PSS;
16227c478bd9Sstevel@tonic-gate }
16237c478bd9Sstevel@tonic-gate
16247c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_OVER_CURR_ACTIVE) {
16257c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_POCI;
16267c478bd9Sstevel@tonic-gate }
16277c478bd9Sstevel@tonic-gate
16287c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_RESET) {
16297c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_PRS;
16307c478bd9Sstevel@tonic-gate }
16317c478bd9Sstevel@tonic-gate
16327c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_INDICATOR) {
16337c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_PIC;
16347c478bd9Sstevel@tonic-gate }
16357c478bd9Sstevel@tonic-gate }
16367c478bd9Sstevel@tonic-gate
16377c478bd9Sstevel@tonic-gate /*
16387c478bd9Sstevel@tonic-gate * Send the following port status and change information
16397c478bd9Sstevel@tonic-gate * even if port is not owned by EHCI.
16407c478bd9Sstevel@tonic-gate *
16417c478bd9Sstevel@tonic-gate * Additional port change information.
16427c478bd9Sstevel@tonic-gate */
16437c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_CONNECT_STS_CHANGE) {
16447c478bd9Sstevel@tonic-gate change_status |= PORT_CHANGE_CSC;
16457c478bd9Sstevel@tonic-gate }
16467c478bd9Sstevel@tonic-gate
16477c478bd9Sstevel@tonic-gate /* Additional port status information */
16487c478bd9Sstevel@tonic-gate if (port_status & EHCI_RH_PORT_POWER) {
16497c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_PPS;
16507c478bd9Sstevel@tonic-gate }
16517c478bd9Sstevel@tonic-gate
16527c478bd9Sstevel@tonic-gate if ((!(port_status & EHCI_RH_PORT_ENABLE)) &&
16537c478bd9Sstevel@tonic-gate (port_status & EHCI_RH_PORT_LOW_SPEED)) {
16547c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_LSDA;
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate
16577c478bd9Sstevel@tonic-gate /*
16587c478bd9Sstevel@tonic-gate * Construct complete root hub port status and change information.
16597c478bd9Sstevel@tonic-gate */
16607c478bd9Sstevel@tonic-gate port_status = ((change_status << 16) | new_port_status);
16617c478bd9Sstevel@tonic-gate
16627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
16637c478bd9Sstevel@tonic-gate "ehci_get_root_hub_port_status: port = %d new status = 0x%x "
16647c478bd9Sstevel@tonic-gate "change status = 0x%x complete port status 0x%x", port,
16657c478bd9Sstevel@tonic-gate new_port_status, change_status, port_status);
16667c478bd9Sstevel@tonic-gate
16677c478bd9Sstevel@tonic-gate return (port_status);
16687c478bd9Sstevel@tonic-gate }
16697c478bd9Sstevel@tonic-gate
16707c478bd9Sstevel@tonic-gate
16717c478bd9Sstevel@tonic-gate /*
16727c478bd9Sstevel@tonic-gate * ehci_is_port_owner:
16737c478bd9Sstevel@tonic-gate *
16747c478bd9Sstevel@tonic-gate * Check whether given port is owned by ehci.
16757c478bd9Sstevel@tonic-gate */
16767c478bd9Sstevel@tonic-gate static int
ehci_is_port_owner(ehci_state_t * ehcip,uint16_t port)16777c478bd9Sstevel@tonic-gate ehci_is_port_owner(
16787c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
16797c478bd9Sstevel@tonic-gate uint16_t port)
16807c478bd9Sstevel@tonic-gate {
16817c478bd9Sstevel@tonic-gate uint_t port_status;
16827c478bd9Sstevel@tonic-gate
16837c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
16847c478bd9Sstevel@tonic-gate
16857c478bd9Sstevel@tonic-gate port_status = Get_OpReg(ehci_rh_port_status[port]) &
16867c478bd9Sstevel@tonic-gate ~EHCI_RH_PORT_CLEAR_MASK;
16877c478bd9Sstevel@tonic-gate
16887c478bd9Sstevel@tonic-gate /*
16897c478bd9Sstevel@tonic-gate * Don't perform anything if port is owned by classis host
16907c478bd9Sstevel@tonic-gate * controller and return success.
16917c478bd9Sstevel@tonic-gate */
16927c478bd9Sstevel@tonic-gate if ((port_status & EHCI_RH_PORT_OWNER) == EHCI_RH_PORT_OWNER_CLASSIC) {
16937c478bd9Sstevel@tonic-gate
16947c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
16957c478bd9Sstevel@tonic-gate "ehci_handle_set_clear_port_feature: "
16967c478bd9Sstevel@tonic-gate "Port %d is owned by classic host controller", port);
16977c478bd9Sstevel@tonic-gate
16987c478bd9Sstevel@tonic-gate return (USB_FAILURE);
16997c478bd9Sstevel@tonic-gate }
17007c478bd9Sstevel@tonic-gate
17017c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
17027c478bd9Sstevel@tonic-gate }
17037c478bd9Sstevel@tonic-gate
17047c478bd9Sstevel@tonic-gate
17057c478bd9Sstevel@tonic-gate /*
17067c478bd9Sstevel@tonic-gate * ehci_root_hub_allocate_intr_pipe_resource:
17077c478bd9Sstevel@tonic-gate *
17087c478bd9Sstevel@tonic-gate * Allocate interrupt requests and initialize them.
17097c478bd9Sstevel@tonic-gate */
17107c478bd9Sstevel@tonic-gate static int
ehci_root_hub_allocate_intr_pipe_resource(ehci_state_t * ehcip,usb_flags_t flags)17117c478bd9Sstevel@tonic-gate ehci_root_hub_allocate_intr_pipe_resource(
17127c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
17137c478bd9Sstevel@tonic-gate usb_flags_t flags)
17147c478bd9Sstevel@tonic-gate {
17157c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
17167c478bd9Sstevel@tonic-gate size_t length;
17177c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
17187c478bd9Sstevel@tonic-gate
17197c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
17207c478bd9Sstevel@tonic-gate "ehci_root_hub_allocate_intr_pipe_resource");
17217c478bd9Sstevel@tonic-gate
17227c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
17237c478bd9Sstevel@tonic-gate
17247c478bd9Sstevel@tonic-gate /* Get the interrupt pipe handle */
17257c478bd9Sstevel@tonic-gate ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
17267c478bd9Sstevel@tonic-gate
17277c478bd9Sstevel@tonic-gate /* Get the current interrupt request pointer */
17287c478bd9Sstevel@tonic-gate curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp;
17297c478bd9Sstevel@tonic-gate
17307c478bd9Sstevel@tonic-gate /*
17317c478bd9Sstevel@tonic-gate * If current interrupt request pointer is null,
17327c478bd9Sstevel@tonic-gate * allocate new interrupt request.
17337c478bd9Sstevel@tonic-gate */
17347c478bd9Sstevel@tonic-gate if (curr_intr_reqp == NULL) {
17357c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_root_hub.rh_client_intr_reqp);
17367c478bd9Sstevel@tonic-gate
17377c478bd9Sstevel@tonic-gate /* Get the length of interrupt transfer */
17387c478bd9Sstevel@tonic-gate length = ehcip->ehci_root_hub.
17397c478bd9Sstevel@tonic-gate rh_client_intr_reqp->intr_len;
17407c478bd9Sstevel@tonic-gate
17417c478bd9Sstevel@tonic-gate curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
17427c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp,
17437c478bd9Sstevel@tonic-gate length, flags);
17447c478bd9Sstevel@tonic-gate
17457c478bd9Sstevel@tonic-gate if (curr_intr_reqp == NULL) {
17467c478bd9Sstevel@tonic-gate
17477c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
17487c478bd9Sstevel@tonic-gate "ehci_root_hub_allocate_intr_pipe_resource:"
17497c478bd9Sstevel@tonic-gate "Interrupt request structure allocation failed");
17507c478bd9Sstevel@tonic-gate
17517c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES);
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate
17547c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_intr_reqp = curr_intr_reqp;
17557c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
17567c478bd9Sstevel@tonic-gate ph->p_req_count++;
17577c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
17587c478bd9Sstevel@tonic-gate }
17597c478bd9Sstevel@tonic-gate
17607c478bd9Sstevel@tonic-gate /* Start the timer for the root hub interrupt pipe polling */
17617c478bd9Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_intr_pipe_timer_id == 0) {
17627c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_timer_id =
17637c478bd9Sstevel@tonic-gate timeout(ehci_handle_root_hub_status_change,
17647c478bd9Sstevel@tonic-gate (void *)ehcip, drv_usectohz(EHCI_RH_POLL_TIME));
17657c478bd9Sstevel@tonic-gate
17667c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.
17677c478bd9Sstevel@tonic-gate rh_intr_pipe_state = EHCI_PIPE_STATE_ACTIVE;
17687c478bd9Sstevel@tonic-gate }
17697c478bd9Sstevel@tonic-gate
17707c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
17717c478bd9Sstevel@tonic-gate }
17727c478bd9Sstevel@tonic-gate
17737c478bd9Sstevel@tonic-gate
17747c478bd9Sstevel@tonic-gate /*
17757c478bd9Sstevel@tonic-gate * ehci_root_hub_intr_pipe_cleanup:
17767c478bd9Sstevel@tonic-gate *
17777c478bd9Sstevel@tonic-gate * Deallocate all interrupt requests and do callback
17787c478bd9Sstevel@tonic-gate * the original client interrupt request.
17797c478bd9Sstevel@tonic-gate */
17807c478bd9Sstevel@tonic-gate static void
ehci_root_hub_intr_pipe_cleanup(ehci_state_t * ehcip,usb_cr_t completion_reason)17817c478bd9Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(
17827c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
17837c478bd9Sstevel@tonic-gate usb_cr_t completion_reason)
17847c478bd9Sstevel@tonic-gate {
17857c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
17867c478bd9Sstevel@tonic-gate usb_opaque_t client_intr_reqp;
17877c478bd9Sstevel@tonic-gate timeout_id_t timer_id;
17887c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
17897c478bd9Sstevel@tonic-gate
17907c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
17917c478bd9Sstevel@tonic-gate "ehci_root_hub_intr_pipe_cleanup");
17927c478bd9Sstevel@tonic-gate
17937c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
17947c478bd9Sstevel@tonic-gate
17957c478bd9Sstevel@tonic-gate /* Get the interrupt pipe handle */
17967c478bd9Sstevel@tonic-gate ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
17977c478bd9Sstevel@tonic-gate
17987c478bd9Sstevel@tonic-gate /* Get the interrupt timerid */
17997c478bd9Sstevel@tonic-gate timer_id = ehcip->ehci_root_hub.rh_intr_pipe_timer_id;
18007c478bd9Sstevel@tonic-gate
18017c478bd9Sstevel@tonic-gate /* Stop the root hub interrupt timer */
18027c478bd9Sstevel@tonic-gate if (timer_id) {
18037c478bd9Sstevel@tonic-gate /* Reset the timer id to zero */
18047c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0;
18057c478bd9Sstevel@tonic-gate
18067c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
18077c478bd9Sstevel@tonic-gate (void) untimeout(timer_id);
18087c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
18097c478bd9Sstevel@tonic-gate }
18107c478bd9Sstevel@tonic-gate
18117c478bd9Sstevel@tonic-gate /* Reset the current interrupt request pointer */
18127c478bd9Sstevel@tonic-gate curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp;
18137c478bd9Sstevel@tonic-gate
18147c478bd9Sstevel@tonic-gate /* Deallocate uncompleted interrupt request */
18157c478bd9Sstevel@tonic-gate if (curr_intr_reqp) {
18167c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL;
18177c478bd9Sstevel@tonic-gate usb_free_intr_req(curr_intr_reqp);
18187c478bd9Sstevel@tonic-gate
18197c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
18207c478bd9Sstevel@tonic-gate ph->p_req_count--;
18217c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
18227c478bd9Sstevel@tonic-gate }
18237c478bd9Sstevel@tonic-gate
18247c478bd9Sstevel@tonic-gate client_intr_reqp = (usb_opaque_t)
18257c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp;
18267c478bd9Sstevel@tonic-gate
18277c478bd9Sstevel@tonic-gate /* Callback for original client interrupt request */
18287c478bd9Sstevel@tonic-gate if (client_intr_reqp) {
18297c478bd9Sstevel@tonic-gate ehci_root_hub_hcdi_callback(ph, completion_reason);
18307c478bd9Sstevel@tonic-gate }
18317c478bd9Sstevel@tonic-gate }
18327c478bd9Sstevel@tonic-gate
18337c478bd9Sstevel@tonic-gate
18347c478bd9Sstevel@tonic-gate /*
18357c478bd9Sstevel@tonic-gate * ehci_handle_root_hub_status_change:
18367c478bd9Sstevel@tonic-gate *
18377c478bd9Sstevel@tonic-gate * A root hub status change interrupt will occur any time there is a change
18387c478bd9Sstevel@tonic-gate * in the root hub status register or one of the port status registers.
18397c478bd9Sstevel@tonic-gate */
18407c478bd9Sstevel@tonic-gate static void
ehci_handle_root_hub_status_change(void * arg)18417c478bd9Sstevel@tonic-gate ehci_handle_root_hub_status_change(void *arg)
18427c478bd9Sstevel@tonic-gate {
18437c478bd9Sstevel@tonic-gate ehci_state_t *ehcip = (ehci_state_t *)arg;
18447c478bd9Sstevel@tonic-gate usb_hub_descr_t *root_hub_descr =
1845112116d8Sfb &ehcip->ehci_root_hub.rh_descr;
18467c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
18477c478bd9Sstevel@tonic-gate usb_port_mask_t port_mask = 0;
18487c478bd9Sstevel@tonic-gate uint_t new_port_status;
18497c478bd9Sstevel@tonic-gate uint_t change_status;
18507c478bd9Sstevel@tonic-gate uint_t port_status;
18517c478bd9Sstevel@tonic-gate mblk_t *message;
18527c478bd9Sstevel@tonic-gate size_t length;
18537c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd;
18547c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
18557c478bd9Sstevel@tonic-gate int i;
18567c478bd9Sstevel@tonic-gate
18577c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
18587c478bd9Sstevel@tonic-gate
18597c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
18607c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_status_change: state = %d",
18617c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_state);
18627c478bd9Sstevel@tonic-gate
18633b00f311Syq #if defined(__x86)
18643b00f311Syq /*
18653b00f311Syq * When ohci are attached in ferrari 4000, SMI will reset ehci
18663b00f311Syq * registers. If ehci registers have been reset, we must re-initialize
18673b00f311Syq * them. During booting, this function will be called 2~3 times. When
18683b00f311Syq * this function is called 16 times, ohci drivers have been attached
18693b00f311Syq * and stop checking the ehci registers.
18703b00f311Syq */
18713b00f311Syq if (ehcip->ehci_polled_root_hub_count < 16) {
18723b00f311Syq
18733b00f311Syq if (Get_OpReg(ehci_config_flag) == 0) {
18743b00f311Syq
18753b00f311Syq USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
18763b00f311Syq ehcip->ehci_log_hdl,
1877112116d8Sfb "ehci_handle_root_hub_status_change:"
18783b00f311Syq " EHCI have been reset");
18793b00f311Syq
18803b00f311Syq /* Reinitialize the controller */
18813b00f311Syq if (ehci_init_ctlr(ehcip, EHCI_REINITIALIZATION) !=
18823b00f311Syq DDI_SUCCESS) {
18833b00f311Syq mutex_exit(&ehcip->ehci_int_mutex);
18843b00f311Syq
18853b00f311Syq return;
18863b00f311Syq }
18873b00f311Syq }
18883b00f311Syq
18893b00f311Syq ehcip->ehci_polled_root_hub_count++;
18903b00f311Syq }
18913b00f311Syq #endif /* __x86 */
18923b00f311Syq
18937c478bd9Sstevel@tonic-gate /* Get the current interrupt request pointer */
18947c478bd9Sstevel@tonic-gate curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp;
18957c478bd9Sstevel@tonic-gate
18967c478bd9Sstevel@tonic-gate ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
18977c478bd9Sstevel@tonic-gate
18987c478bd9Sstevel@tonic-gate /* Check whether timeout handler is valid */
18997c478bd9Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_intr_pipe_timer_id) {
19007c478bd9Sstevel@tonic-gate /* Check host controller is in operational state */
19017c478bd9Sstevel@tonic-gate if ((ehci_state_is_operational(ehcip)) != USB_SUCCESS) {
19027c478bd9Sstevel@tonic-gate /* Reset the timer id */
19037c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0;
19047c478bd9Sstevel@tonic-gate
19057c478bd9Sstevel@tonic-gate /* Do interrupt pipe cleanup */
19067c478bd9Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(
19077c478bd9Sstevel@tonic-gate ehcip, USB_CR_HC_HARDWARE_ERR);
19087c478bd9Sstevel@tonic-gate
19097c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
19107c478bd9Sstevel@tonic-gate
19117c478bd9Sstevel@tonic-gate return;
19127c478bd9Sstevel@tonic-gate }
19137c478bd9Sstevel@tonic-gate } else {
19147c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
19157c478bd9Sstevel@tonic-gate
19167c478bd9Sstevel@tonic-gate return;
19177c478bd9Sstevel@tonic-gate }
19187c478bd9Sstevel@tonic-gate
19197c478bd9Sstevel@tonic-gate eptd = &ehcip->ehci_root_hub.rh_intr_pipe_handle->p_ep;
19207c478bd9Sstevel@tonic-gate
19217c478bd9Sstevel@tonic-gate /* Check each port */
19227c478bd9Sstevel@tonic-gate for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
19237c478bd9Sstevel@tonic-gate
19247c478bd9Sstevel@tonic-gate port_status = ehci_get_root_hub_port_status(ehcip, i);
19257c478bd9Sstevel@tonic-gate
19267c478bd9Sstevel@tonic-gate new_port_status = port_status & PORT_STATUS_MASK;
1927*993e3fafSRobert Mustacchi change_status = (port_status >> 16) & PORT_CHANGE_MASK_2X;
19287c478bd9Sstevel@tonic-gate
19297c478bd9Sstevel@tonic-gate /*
19307c478bd9Sstevel@tonic-gate * If there is change in the port status then set the bit in the
19317c478bd9Sstevel@tonic-gate * bitmap of changes and inform hub driver about these changes.
19327c478bd9Sstevel@tonic-gate * Hub driver will take care of these changes.
19337c478bd9Sstevel@tonic-gate */
19347c478bd9Sstevel@tonic-gate if (change_status) {
19357c478bd9Sstevel@tonic-gate
19367c478bd9Sstevel@tonic-gate /* See if a device was attached/detached */
19377c478bd9Sstevel@tonic-gate if (change_status & PORT_CHANGE_CSC) {
19387c478bd9Sstevel@tonic-gate /*
19397c478bd9Sstevel@tonic-gate * Update the state depending on whether
19407c478bd9Sstevel@tonic-gate * the port was attached or detached.
19417c478bd9Sstevel@tonic-gate */
19427c478bd9Sstevel@tonic-gate if (new_port_status & PORT_STATUS_CCS) {
19437c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.
19447c478bd9Sstevel@tonic-gate rh_port_state[i] = DISABLED;
19457c478bd9Sstevel@tonic-gate
19467c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
19477c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl,
19488f1c3597Shx "Port %d connected", i+1);
19497c478bd9Sstevel@tonic-gate } else {
19507c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.
19517c478bd9Sstevel@tonic-gate rh_port_state[i] = DISCONNECTED;
19527c478bd9Sstevel@tonic-gate
19537c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
19547c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl,
19558f1c3597Shx "Port %d disconnected", i+1);
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate }
19587c478bd9Sstevel@tonic-gate
19597c478bd9Sstevel@tonic-gate /* See if port enable status changed */
19607c478bd9Sstevel@tonic-gate if (change_status & PORT_CHANGE_PESC) {
19617c478bd9Sstevel@tonic-gate /*
19627c478bd9Sstevel@tonic-gate * Update the state depending on whether
19637c478bd9Sstevel@tonic-gate * the port was enabled or disabled.
19647c478bd9Sstevel@tonic-gate */
19657c478bd9Sstevel@tonic-gate if (new_port_status & PORT_STATUS_PES) {
19667c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.
19677c478bd9Sstevel@tonic-gate rh_port_state[i] = ENABLED;
19687c478bd9Sstevel@tonic-gate
19697c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
19707c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl,
19718f1c3597Shx "Port %d enabled", i+1);
19727c478bd9Sstevel@tonic-gate } else {
19737c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.
19747c478bd9Sstevel@tonic-gate rh_port_state[i] = DISABLED;
19757c478bd9Sstevel@tonic-gate
19767c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
19777c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl,
19788f1c3597Shx "Port %d disabled", i+1);
19797c478bd9Sstevel@tonic-gate }
19807c478bd9Sstevel@tonic-gate }
19817c478bd9Sstevel@tonic-gate
19827c478bd9Sstevel@tonic-gate port_mask |= 1 << (i + 1);
19837c478bd9Sstevel@tonic-gate
19847c478bd9Sstevel@tonic-gate /* Update the status */
19857c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.
19867c478bd9Sstevel@tonic-gate rh_port_status[i] = new_port_status;
19877c478bd9Sstevel@tonic-gate }
19887c478bd9Sstevel@tonic-gate }
19897c478bd9Sstevel@tonic-gate
19907c478bd9Sstevel@tonic-gate if (ph && port_mask && curr_intr_reqp) {
19917c478bd9Sstevel@tonic-gate length = eptd->wMaxPacketSize;
19927c478bd9Sstevel@tonic-gate
19937c478bd9Sstevel@tonic-gate ASSERT(length != 0);
19947c478bd9Sstevel@tonic-gate
19957c478bd9Sstevel@tonic-gate /* Get the message block */
19967c478bd9Sstevel@tonic-gate message = curr_intr_reqp->intr_data;
19977c478bd9Sstevel@tonic-gate
19987c478bd9Sstevel@tonic-gate ASSERT(message != NULL);
19997c478bd9Sstevel@tonic-gate
20007c478bd9Sstevel@tonic-gate do {
20018f1c3597Shx /*
20028f1c3597Shx * check that the mblk is big enough when we
20038f1c3597Shx * are writing bytes into it
20048f1c3597Shx */
20058f1c3597Shx if (message->b_wptr >= message->b_datap->db_lim) {
20068f1c3597Shx
20078f1c3597Shx USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
20088f1c3597Shx ehcip->ehci_log_hdl,
20098f1c3597Shx "ehci_handle_root_hub_status_change"
20108f1c3597Shx "mblk data overflow.");
20118f1c3597Shx
20128f1c3597Shx break;
20138f1c3597Shx }
20147c478bd9Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)port_mask;
20157c478bd9Sstevel@tonic-gate port_mask >>= 8;
20167c478bd9Sstevel@tonic-gate } while (port_mask != 0);
20177c478bd9Sstevel@tonic-gate
20187c478bd9Sstevel@tonic-gate ehci_root_hub_hcdi_callback(ph, USB_CR_OK);
20197c478bd9Sstevel@tonic-gate }
20207c478bd9Sstevel@tonic-gate
20217c478bd9Sstevel@tonic-gate /* Reset the timer id */
20227c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0;
20237c478bd9Sstevel@tonic-gate
20247c478bd9Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_intr_pipe_state ==
20257c478bd9Sstevel@tonic-gate EHCI_PIPE_STATE_ACTIVE) {
20267c478bd9Sstevel@tonic-gate /*
20277c478bd9Sstevel@tonic-gate * If needed, allocate new interrupt request. Also
20287c478bd9Sstevel@tonic-gate * start the timer for the root hub interrupt polling.
20297c478bd9Sstevel@tonic-gate */
20307c478bd9Sstevel@tonic-gate if ((ehci_root_hub_allocate_intr_pipe_resource(
20317c478bd9Sstevel@tonic-gate ehcip, 0)) != USB_SUCCESS) {
20327c478bd9Sstevel@tonic-gate
20337c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
20347c478bd9Sstevel@tonic-gate "ehci_handle_root_hub_status_change: No Resources");
20357c478bd9Sstevel@tonic-gate
20367c478bd9Sstevel@tonic-gate /* Do interrupt pipe cleanup */
20377c478bd9Sstevel@tonic-gate ehci_root_hub_intr_pipe_cleanup(
20387c478bd9Sstevel@tonic-gate ehcip, USB_CR_NO_RESOURCES);
20397c478bd9Sstevel@tonic-gate }
20407c478bd9Sstevel@tonic-gate }
20417c478bd9Sstevel@tonic-gate
20427c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
20437c478bd9Sstevel@tonic-gate }
20447c478bd9Sstevel@tonic-gate
20457c478bd9Sstevel@tonic-gate
20467c478bd9Sstevel@tonic-gate /*
20477c478bd9Sstevel@tonic-gate * ehci_root_hub_hcdi_callback()
20487c478bd9Sstevel@tonic-gate *
20497c478bd9Sstevel@tonic-gate * Convenience wrapper around usba_hcdi_cb() for the root hub.
20507c478bd9Sstevel@tonic-gate */
20517c478bd9Sstevel@tonic-gate static void
ehci_root_hub_hcdi_callback(usba_pipe_handle_data_t * ph,usb_cr_t completion_reason)20527c478bd9Sstevel@tonic-gate ehci_root_hub_hcdi_callback(
20537c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
20547c478bd9Sstevel@tonic-gate usb_cr_t completion_reason)
20557c478bd9Sstevel@tonic-gate {
20567c478bd9Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
2057112116d8Sfb ph->p_usba_device->usb_root_hub_dip);
20587c478bd9Sstevel@tonic-gate uchar_t attributes = ph->p_ep.bmAttributes &
2059112116d8Sfb USB_EP_ATTR_MASK;
20607c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp;
20617c478bd9Sstevel@tonic-gate uint_t pipe_state = 0;
20627c478bd9Sstevel@tonic-gate
20637c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
20647c478bd9Sstevel@tonic-gate "ehci_root_hub_hcdi_callback: ph = 0x%p, cr = 0x%x",
2065112116d8Sfb (void *)ph, completion_reason);
20667c478bd9Sstevel@tonic-gate
20677c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
20687c478bd9Sstevel@tonic-gate
20697c478bd9Sstevel@tonic-gate /* Set the pipe state as per completion reason */
20707c478bd9Sstevel@tonic-gate switch (completion_reason) {
20717c478bd9Sstevel@tonic-gate case USB_CR_OK:
20727c478bd9Sstevel@tonic-gate switch (attributes) {
20737c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
20747c478bd9Sstevel@tonic-gate pipe_state = EHCI_PIPE_STATE_IDLE;
20757c478bd9Sstevel@tonic-gate break;
20767c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
20777c478bd9Sstevel@tonic-gate pipe_state = ehcip->ehci_root_hub.
20787c478bd9Sstevel@tonic-gate rh_intr_pipe_state;
20797c478bd9Sstevel@tonic-gate break;
20807c478bd9Sstevel@tonic-gate }
20817c478bd9Sstevel@tonic-gate break;
20827c478bd9Sstevel@tonic-gate case USB_CR_NO_RESOURCES:
20837c478bd9Sstevel@tonic-gate case USB_CR_NOT_SUPPORTED:
20847c478bd9Sstevel@tonic-gate case USB_CR_STOPPED_POLLING:
20857c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET:
20867c478bd9Sstevel@tonic-gate case USB_CR_HC_HARDWARE_ERR:
20877c478bd9Sstevel@tonic-gate /* Set pipe state to idle */
20887c478bd9Sstevel@tonic-gate pipe_state = EHCI_PIPE_STATE_IDLE;
20897c478bd9Sstevel@tonic-gate break;
20907c478bd9Sstevel@tonic-gate case USB_CR_PIPE_CLOSING:
20917c478bd9Sstevel@tonic-gate break;
20927c478bd9Sstevel@tonic-gate default:
20937c478bd9Sstevel@tonic-gate /* Set pipe state to error */
20947c478bd9Sstevel@tonic-gate pipe_state = EHCI_PIPE_STATE_ERROR;
20957c478bd9Sstevel@tonic-gate break;
20967c478bd9Sstevel@tonic-gate }
20977c478bd9Sstevel@tonic-gate
20987c478bd9Sstevel@tonic-gate switch (attributes) {
20997c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
21007c478bd9Sstevel@tonic-gate curr_xfer_reqp = (usb_opaque_t)
21017c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
21027c478bd9Sstevel@tonic-gate
21037c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_ctrl_reqp = NULL;
21047c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_ctrl_pipe_state = pipe_state;
21057c478bd9Sstevel@tonic-gate break;
21067c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
21077c478bd9Sstevel@tonic-gate /* if curr_intr_reqp available then use this request */
21087c478bd9Sstevel@tonic-gate if (ehcip->ehci_root_hub.rh_curr_intr_reqp) {
21097c478bd9Sstevel@tonic-gate curr_xfer_reqp = (usb_opaque_t)ehcip->
21107c478bd9Sstevel@tonic-gate ehci_root_hub.rh_curr_intr_reqp;
21117c478bd9Sstevel@tonic-gate
21127c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL;
21137c478bd9Sstevel@tonic-gate } else {
21147c478bd9Sstevel@tonic-gate /* no current request, use client's request */
21157c478bd9Sstevel@tonic-gate curr_xfer_reqp = (usb_opaque_t)
21167c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp;
21177c478bd9Sstevel@tonic-gate
21187c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_client_intr_reqp = NULL;
21197c478bd9Sstevel@tonic-gate }
21207c478bd9Sstevel@tonic-gate ehcip->ehci_root_hub.rh_intr_pipe_state = pipe_state;
21217c478bd9Sstevel@tonic-gate break;
21227c478bd9Sstevel@tonic-gate }
21237c478bd9Sstevel@tonic-gate
21247c478bd9Sstevel@tonic-gate ASSERT(curr_xfer_reqp != NULL);
21257c478bd9Sstevel@tonic-gate
21267c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
21277c478bd9Sstevel@tonic-gate usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
21287c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
21297c478bd9Sstevel@tonic-gate }
2130