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