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