xref: /onnv-gate/usr/src/uts/common/io/usb/hcd/openhci/ohci_hub.c (revision 7425:e4dbffd35ebc)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52326Ssl147100  * Common Development and Distribution License (the "License").
62326Ssl147100  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*6898Sfb209375  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * Open Host Controller Driver (OHCI)
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * The USB Open Host Controller driver is a software driver which interfaces
310Sstevel@tonic-gate  * to the Universal Serial Bus layer (USBA) and the USB Open Host Controller.
32*6898Sfb209375  * The interface to USB Open Host Controller is defined by the OpenHCI	Host
330Sstevel@tonic-gate  * Controller Interface.
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * This module contains the code for root hub related functions.
360Sstevel@tonic-gate  *
370Sstevel@tonic-gate  * Note: ONE_XFER is not supported on root hub interrupt polling.
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate #include <sys/usb/hcd/openhci/ohcid.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /* static function prototypes */
420Sstevel@tonic-gate static int	ohci_handle_set_clear_port_feature(
430Sstevel@tonic-gate 				ohci_state_t		*ohcip,
440Sstevel@tonic-gate 				uchar_t 		bRequest,
450Sstevel@tonic-gate 				uint16_t		wValue,
460Sstevel@tonic-gate 				uint16_t		port);
470Sstevel@tonic-gate static void	ohci_handle_port_power(ohci_state_t	*ohcip,
480Sstevel@tonic-gate 				uint16_t		port,
490Sstevel@tonic-gate 				uint_t			on);
500Sstevel@tonic-gate static void	ohci_handle_port_enable(ohci_state_t	*ohcip,
510Sstevel@tonic-gate 				uint16_t		port,
520Sstevel@tonic-gate 				uint_t			on);
530Sstevel@tonic-gate static void	ohci_handle_clrchng_port_enable(
540Sstevel@tonic-gate 				ohci_state_t		*ohcip,
550Sstevel@tonic-gate 				uint16_t		port);
560Sstevel@tonic-gate static void	ohci_handle_port_suspend(ohci_state_t	*ohcip,
570Sstevel@tonic-gate 				uint16_t		port,
580Sstevel@tonic-gate 				uint_t			on);
590Sstevel@tonic-gate static void	ohci_handle_clrchng_port_suspend(
600Sstevel@tonic-gate 				ohci_state_t		*ohcip,
610Sstevel@tonic-gate 				uint16_t		port);
620Sstevel@tonic-gate static void	ohci_handle_port_reset(ohci_state_t	*ohcip,
630Sstevel@tonic-gate 				uint16_t		port);
640Sstevel@tonic-gate static void	ohci_handle_complete_port_reset(
650Sstevel@tonic-gate 				ohci_state_t		*ohcip,
660Sstevel@tonic-gate 				uint16_t		port);
670Sstevel@tonic-gate static void	ohci_handle_clear_port_connection(
680Sstevel@tonic-gate 				ohci_state_t		*ohcip,
690Sstevel@tonic-gate 				uint16_t		port);
700Sstevel@tonic-gate static void	ohci_handle_clrchng_port_over_current(
710Sstevel@tonic-gate 				ohci_state_t		*ohcip,
720Sstevel@tonic-gate 				uint16_t		port);
730Sstevel@tonic-gate static void	ohci_handle_get_port_status(
740Sstevel@tonic-gate 				ohci_state_t		*ohcip,
750Sstevel@tonic-gate 				uint16_t		port);
762326Ssl147100 static int	ohci_handle_set_clear_hub_feature(
772326Ssl147100 				ohci_state_t		*ohcip,
782326Ssl147100 				uchar_t 		bRequest,
792326Ssl147100 				uint16_t		wValue);
802326Ssl147100 static void	ohci_handle_clrchng_hub_over_current(
812326Ssl147100 				ohci_state_t		*ohcip);
820Sstevel@tonic-gate static void	ohci_handle_get_hub_descriptor(
830Sstevel@tonic-gate 				ohci_state_t		*ohcip);
840Sstevel@tonic-gate static void	ohci_handle_get_hub_status(
850Sstevel@tonic-gate 				ohci_state_t		*ohcip);
861001Ssl147100 static void	ohci_handle_get_device_status(
871001Ssl147100 				ohci_state_t		*ohcip);
880Sstevel@tonic-gate static int	ohci_root_hub_allocate_intr_pipe_resource(
890Sstevel@tonic-gate 				ohci_state_t		*ohcip,
900Sstevel@tonic-gate 				usb_flags_t		flags);
910Sstevel@tonic-gate static void	ohci_root_hub_intr_pipe_cleanup(
920Sstevel@tonic-gate 				ohci_state_t		*ohcip,
930Sstevel@tonic-gate 				usb_cr_t		completion_reason);
940Sstevel@tonic-gate static void	ohci_root_hub_hcdi_callback(
950Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
960Sstevel@tonic-gate 				usb_cr_t		completion_reason);
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * ohci_init_root_hub:
1010Sstevel@tonic-gate  *
1020Sstevel@tonic-gate  * Initialize the root hub
1030Sstevel@tonic-gate  */
1040Sstevel@tonic-gate int
ohci_init_root_hub(ohci_state_t * ohcip)1050Sstevel@tonic-gate ohci_init_root_hub(ohci_state_t	*ohcip)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate 	usb_hub_descr_t 	*root_hub_descr =
108*6898Sfb209375 	    &ohcip->ohci_root_hub.rh_descr;
1090Sstevel@tonic-gate 	uint_t			des_A, des_B, port_state;
1100Sstevel@tonic-gate 	int			i, length;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1130Sstevel@tonic-gate 	    "ohci_init_root_hub:");
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	/* Read the descriptor registers */
1160Sstevel@tonic-gate 	des_A = ohcip->ohci_root_hub.rh_des_A = Get_OpReg(hcr_rh_descriptorA);
1170Sstevel@tonic-gate 	des_B = ohcip->ohci_root_hub.rh_des_B = Get_OpReg(hcr_rh_descriptorB);
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1200Sstevel@tonic-gate 	    "root hub descriptor A 0x%x", ohcip->ohci_root_hub.rh_des_A);
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1230Sstevel@tonic-gate 	    "root hub descriptor B 0x%x", ohcip->ohci_root_hub.rh_des_B);
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	/* Obtain the root hub status */
1260Sstevel@tonic-gate 	ohcip->ohci_root_hub.rh_status = Get_OpReg(hcr_rh_status);
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	/*
1290Sstevel@tonic-gate 	 * Build the hub descriptor based on HcRhDescriptorA and
1300Sstevel@tonic-gate 	 * HcRhDescriptorB
1310Sstevel@tonic-gate 	 */
1320Sstevel@tonic-gate 	root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE;
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	if ((des_A & HCR_RHA_NDP) > OHCI_MAX_RH_PORTS) {
1350Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1360Sstevel@tonic-gate 		    "ohci_init_root_hub:" "Invalid no of root hub ports 0x%x",
1370Sstevel@tonic-gate 		    des_A & HCR_RHA_NDP);
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 		return (USB_FAILURE);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	/* Obtain the number of downstream ports */
1430Sstevel@tonic-gate 	root_hub_descr->bNbrPorts = des_A & HCR_RHA_NDP;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	length = root_hub_descr->bNbrPorts / 8;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	if (length) {
1480Sstevel@tonic-gate 		root_hub_descr->bDescLength = 7 + (2 * (length + 1));
1490Sstevel@tonic-gate 	} else {
1500Sstevel@tonic-gate 		root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH;
1510Sstevel@tonic-gate 	}
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	/* Determine the Power Switching Mode */
1540Sstevel@tonic-gate 	if (!(des_A & HCR_RHA_NPS)) {
1550Sstevel@tonic-gate 		/*
1560Sstevel@tonic-gate 		 * The ports are power switched. Check for either individual
1570Sstevel@tonic-gate 		 * or gang power switching.
1580Sstevel@tonic-gate 		 */
1590Sstevel@tonic-gate 		if ((des_A & HCR_RHA_PSM) && (des_B & HCR_RHB_PPCM)) {
1600Sstevel@tonic-gate 			/* each port is powered individually */
1610Sstevel@tonic-gate 			root_hub_descr->wHubCharacteristics =
1620Sstevel@tonic-gate 			    HUB_CHARS_INDIVIDUAL_PORT_POWER;
1630Sstevel@tonic-gate 		} else {
1640Sstevel@tonic-gate 			/* the ports are gang powered */
1650Sstevel@tonic-gate 			root_hub_descr->
1660Sstevel@tonic-gate 			    wHubCharacteristics = HUB_CHARS_GANGED_POWER;
1670Sstevel@tonic-gate 		}
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 		/* Each port will start off in the POWERED_OFF mode */
1700Sstevel@tonic-gate 		port_state = POWERED_OFF;
1710Sstevel@tonic-gate 	} else {
1720Sstevel@tonic-gate 		/* The ports are powered when the ctlr is powered */
1730Sstevel@tonic-gate 		root_hub_descr->
1740Sstevel@tonic-gate 		    wHubCharacteristics = HUB_CHARS_NO_POWER_SWITCHING;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 		port_state = DISCONNECTED;
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	/* The root hub should never be a compound device */
1800Sstevel@tonic-gate 	ASSERT((des_A & HCR_RHA_DT) == 0);
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/* Determine the Over-current Protection Mode */
1830Sstevel@tonic-gate 	if (des_A & HCR_RHA_NOCP) {
1840Sstevel@tonic-gate 		/* No over current protection */
1850Sstevel@tonic-gate 		root_hub_descr->
1860Sstevel@tonic-gate 		    wHubCharacteristics |= HUB_CHARS_NO_OVER_CURRENT;
1870Sstevel@tonic-gate 	} else {
1880Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
1890Sstevel@tonic-gate 		    ohcip->ohci_log_hdl, "OCPM =%d, PSM=%d",
1900Sstevel@tonic-gate 		    des_A & HCR_RHA_OCPM, des_A & HCR_RHA_PSM);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 		/* See if over current protection is provided */
1930Sstevel@tonic-gate 		if (des_A & HCR_RHA_OCPM) {
1940Sstevel@tonic-gate 			/* reported on a per port basis */
1950Sstevel@tonic-gate 			root_hub_descr->
1960Sstevel@tonic-gate 			    wHubCharacteristics |= HUB_CHARS_INDIV_OVER_CURRENT;
1970Sstevel@tonic-gate 		}
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/* Obtain the power on to power good time of the ports */
2010Sstevel@tonic-gate 	root_hub_descr->bPwrOn2PwrGood = (uint32_t)
2020Sstevel@tonic-gate 	    ((des_A & HCR_RHA_PTPGT) >> HCR_RHA_PTPGT_SHIFT);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2050Sstevel@tonic-gate 	    "Power on to power good %d", root_hub_descr->bPwrOn2PwrGood);
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	/* Indicate if the device is removable */
2080Sstevel@tonic-gate 	root_hub_descr->DeviceRemovable = (uchar_t)des_B & HCR_RHB_DR;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	/*
2110Sstevel@tonic-gate 	 * Fill in the port power control mask:
2120Sstevel@tonic-gate 	 * Each bit in the  PortPowerControlMask
2130Sstevel@tonic-gate 	 * should be set. Refer to USB 2.0, table 11-13
2140Sstevel@tonic-gate 	 */
2150Sstevel@tonic-gate 	root_hub_descr->PortPwrCtrlMask = (uchar_t)(des_B >> 16);
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	/* Set the state of each port and initialize the status */
2180Sstevel@tonic-gate 	for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
2190Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_port_state[i] = port_state;
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 		/* Turn off the power on each port for now */
2220Sstevel@tonic-gate 		Set_OpReg(hcr_rh_portstatus[i],  HCR_PORT_CPP);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 		/*
2250Sstevel@tonic-gate 		 * Initialize each of the root hub port	status
2260Sstevel@tonic-gate 		 * equal to zero. This initialization makes sure
2270Sstevel@tonic-gate 		 * that all devices connected to root hub will
2280Sstevel@tonic-gate 		 * enumerates when the first RHSC interrupt occurs
2290Sstevel@tonic-gate 		 * since definitely there will be changes  in
2300Sstevel@tonic-gate 		 * the root hub port status.
2310Sstevel@tonic-gate 		 */
2320Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_port_status[i] = 0;
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	return (USB_SUCCESS);
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate /*
2400Sstevel@tonic-gate  * ohci_load_root_hub_driver:
2410Sstevel@tonic-gate  *
2420Sstevel@tonic-gate  * Attach the root hub
2430Sstevel@tonic-gate  */
2440Sstevel@tonic-gate static usb_dev_descr_t ohci_root_hub_device_descriptor = {
2450Sstevel@tonic-gate 	0x12,		/* bLength */
2460Sstevel@tonic-gate 	0x01,		/* bDescriptorType, Device */
2470Sstevel@tonic-gate 	0x110,		/* bcdUSB, v1.1 */
2480Sstevel@tonic-gate 	0x09,		/* bDeviceClass */
2490Sstevel@tonic-gate 	0x00,		/* bDeviceSubClass */
2500Sstevel@tonic-gate 	0x00,		/* bDeviceProtocol */
2510Sstevel@tonic-gate 	0x08,		/* bMaxPacketSize0 */
2520Sstevel@tonic-gate 	0x00,		/* idVendor */
2530Sstevel@tonic-gate 	0x00,		/* idProduct */
2540Sstevel@tonic-gate 	0x00,		/* bcdDevice */
2550Sstevel@tonic-gate 	0x00,		/* iManufacturer */
2560Sstevel@tonic-gate 	0x00,		/* iProduct */
2570Sstevel@tonic-gate 	0x00,		/* iSerialNumber */
2580Sstevel@tonic-gate 	0x01		/* bNumConfigurations */
2590Sstevel@tonic-gate };
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate static uchar_t ohci_root_hub_config_descriptor[] = {
2620Sstevel@tonic-gate 	/* One configuartion */
2630Sstevel@tonic-gate 	0x09,		/* bLength */
2640Sstevel@tonic-gate 	0x02,		/* bDescriptorType, Configuartion */
2650Sstevel@tonic-gate 	0x19, 0x00,	/* wTotalLength */
2660Sstevel@tonic-gate 	0x01,		/* bNumInterfaces */
2670Sstevel@tonic-gate 	0x01,		/* bConfigurationValue */
2680Sstevel@tonic-gate 	0x00,		/* iConfiguration */
2690Sstevel@tonic-gate 	0x40,		/* bmAttributes */
2700Sstevel@tonic-gate 	0x00,		/* MaxPower */
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	/* One Interface */
2730Sstevel@tonic-gate 	0x09,		/* bLength */
2740Sstevel@tonic-gate 	0x04,		/* bDescriptorType, Interface */
2750Sstevel@tonic-gate 	0x00,		/* bInterfaceNumber */
2760Sstevel@tonic-gate 	0x00,		/* bAlternateSetting */
2770Sstevel@tonic-gate 	0x01,		/* bNumEndpoints */
2780Sstevel@tonic-gate 	0x09,		/* bInterfaceClass */
2790Sstevel@tonic-gate 	0x01,		/* bInterfaceSubClass */
2800Sstevel@tonic-gate 	0x00,		/* bInterfaceProtocol */
2810Sstevel@tonic-gate 	0x00,		/* iInterface */
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	/* One Endpoint (status change endpoint) */
2840Sstevel@tonic-gate 	0x07,		/* bLength */
2850Sstevel@tonic-gate 	0x05,		/* bDescriptorType, Endpoint */
2860Sstevel@tonic-gate 	0x81,		/* bEndpointAddress */
2870Sstevel@tonic-gate 	0x03,		/* bmAttributes */
288*6898Sfb209375 	0x01, 0x00,	/* wMaxPacketSize, 1 +	(OHCI_MAX_RH_PORTS / 8) */
2890Sstevel@tonic-gate 	0xff		/* bInterval */
2900Sstevel@tonic-gate };
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate int
ohci_load_root_hub_driver(ohci_state_t * ohcip)2930Sstevel@tonic-gate ohci_load_root_hub_driver(ohci_state_t	*ohcip)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2960Sstevel@tonic-gate 	    "ohci_load_root_hub_driver:");
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	return (usba_hubdi_bind_root_hub(ohcip->ohci_dip,
2990Sstevel@tonic-gate 	    ohci_root_hub_config_descriptor,
3000Sstevel@tonic-gate 	    sizeof (ohci_root_hub_config_descriptor),
3010Sstevel@tonic-gate 	    &ohci_root_hub_device_descriptor));
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate /*
3060Sstevel@tonic-gate  * ohci_unload_root_hub_driver:
3070Sstevel@tonic-gate  */
3080Sstevel@tonic-gate int
ohci_unload_root_hub_driver(ohci_state_t * ohcip)3090Sstevel@tonic-gate ohci_unload_root_hub_driver(ohci_state_t	*ohcip)
3100Sstevel@tonic-gate {
3110Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3120Sstevel@tonic-gate 	    "ohci_unload_root_hub_driver:");
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	return (usba_hubdi_unbind_root_hub(ohcip->ohci_dip));
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate /*
3190Sstevel@tonic-gate  * ohci_handle_root_hub_pipe_open:
3200Sstevel@tonic-gate  *
3210Sstevel@tonic-gate  * Handle opening of control and interrupt pipes on root hub.
3220Sstevel@tonic-gate  */
3230Sstevel@tonic-gate /* ARGSUSED */
3240Sstevel@tonic-gate int
ohci_handle_root_hub_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)3250Sstevel@tonic-gate ohci_handle_root_hub_pipe_open(
3260Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
3270Sstevel@tonic-gate 	usb_flags_t		usb_flags)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate 	ohci_state_t		*ohcip = ohci_obtain_state(
330*6898Sfb209375 	    ph->p_usba_device->usb_root_hub_dip);
3310Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3340Sstevel@tonic-gate 	    "ohci_handle_root_hub_pipe_open: Root hub pipe open");
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
3390Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
3400Sstevel@tonic-gate 		/* Save control pipe handle */
3410Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_ctrl_pipe_handle = ph;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 		/* Set state of the root hub control pipe as idle */
3440Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_IDLE;
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_curr_ctrl_reqp = NULL;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3490Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_open: Root hub control "
3500Sstevel@tonic-gate 		    "pipe open succeeded");
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		break;
3530Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
3540Sstevel@tonic-gate 		/* Save interrupt pipe handle */
3550Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_intr_pipe_handle = ph;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 		/* Set state of the root hub interrupt pipe as idle */
3580Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_intr_pipe_state = OHCI_PIPE_STATE_IDLE;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3650Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_open: Root hub interrupt "
3660Sstevel@tonic-gate 		    "pipe open succeeded");
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 		break;
3690Sstevel@tonic-gate 	default:
3700Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3710Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_open: Root hub pipe open"
3720Sstevel@tonic-gate 		    "failed");
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		return (USB_FAILURE);
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	ohcip->ohci_open_pipe_count++;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	return (USB_SUCCESS);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate /*
3840Sstevel@tonic-gate  * ohci_handle_root_hub_pipe_close:
3850Sstevel@tonic-gate  *
3860Sstevel@tonic-gate  * Handle closing of control and interrupt pipes on root hub.
3870Sstevel@tonic-gate  */
3880Sstevel@tonic-gate /* ARGSUSED */
3890Sstevel@tonic-gate int
ohci_handle_root_hub_pipe_close(usba_pipe_handle_data_t * ph)3900Sstevel@tonic-gate ohci_handle_root_hub_pipe_close(usba_pipe_handle_data_t	*ph)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate 	ohci_state_t		*ohcip = ohci_obtain_state(
393*6898Sfb209375 	    ph->p_usba_device->usb_root_hub_dip);
3940Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3970Sstevel@tonic-gate 	    "ohci_handle_root_hub_pipe_close: Root hub pipe close");
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
4020Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
4030Sstevel@tonic-gate 		ASSERT(ohcip->ohci_root_hub.
4040Sstevel@tonic-gate 		    rh_ctrl_pipe_state != OHCI_PIPE_STATE_CLOSE);
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 		/* Set state of the root hub control pipe as close */
4070Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_CLOSE;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 		/* Set root hub control pipe handle to null */
4100Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_ctrl_pipe_handle = NULL;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4130Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_close: "
4140Sstevel@tonic-gate 		    "Root hub control pipe close succeeded");
4150Sstevel@tonic-gate 		break;
4160Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
4170Sstevel@tonic-gate 		ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 		ASSERT(ohcip->ohci_root_hub.
4200Sstevel@tonic-gate 		    rh_intr_pipe_state != OHCI_PIPE_STATE_CLOSE);
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 		/* Set state of the root hub interrupt pipe as close */
4230Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_intr_pipe_state = OHCI_PIPE_STATE_CLOSE;
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 		/* Do interrupt pipe cleanup */
4260Sstevel@tonic-gate 		ohci_root_hub_intr_pipe_cleanup(ohcip, USB_CR_PIPE_CLOSING);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 		/* Set root hub interrupt pipe handle to null */
4290Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_intr_pipe_handle = NULL;
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4320Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_close: "
4330Sstevel@tonic-gate 		    "Root hub interrupt pipe close succeeded");
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 		break;
4360Sstevel@tonic-gate 	default:
4370Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4380Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_close: "
4390Sstevel@tonic-gate 		    "Root hub pipe close failed");
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 		return (USB_FAILURE);
4420Sstevel@tonic-gate 	}
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	ohcip->ohci_open_pipe_count--;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	return (USB_SUCCESS);
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate  * ohci_handle_root_hub_pipe_reset:
4520Sstevel@tonic-gate  *
4530Sstevel@tonic-gate  * Handle resetting of control and interrupt pipes on root hub.
4540Sstevel@tonic-gate  */
4550Sstevel@tonic-gate /* ARGSUSED */
4560Sstevel@tonic-gate int
ohci_handle_root_hub_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)4570Sstevel@tonic-gate ohci_handle_root_hub_pipe_reset(
4580Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
4590Sstevel@tonic-gate 	usb_flags_t		usb_flags)
4600Sstevel@tonic-gate {
4610Sstevel@tonic-gate 	ohci_state_t		*ohcip = ohci_obtain_state(
462*6898Sfb209375 	    ph->p_usba_device->usb_root_hub_dip);
4630Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
4640Sstevel@tonic-gate 	int			error = USB_SUCCESS;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4670Sstevel@tonic-gate 	    "ohci_handle_root_hub_pipe_reset: Root hub pipe reset");
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
4720Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
4730Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_IDLE;
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4760Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_reset: Pipe reset"
4770Sstevel@tonic-gate 		    "for the root hub control pipe successful");
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 		break;
4800Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
4810Sstevel@tonic-gate 		ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 		if ((ohcip->ohci_root_hub.rh_client_intr_reqp) &&
4840Sstevel@tonic-gate 		    (ohcip->ohci_root_hub.rh_intr_pipe_state !=
4850Sstevel@tonic-gate 		    OHCI_PIPE_STATE_IDLE)) {
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 			ohcip->ohci_root_hub.
4880Sstevel@tonic-gate 			    rh_intr_pipe_state = OHCI_PIPE_STATE_RESET;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 			/* Do interrupt pipe cleanup */
4910Sstevel@tonic-gate 			ohci_root_hub_intr_pipe_cleanup(
4920Sstevel@tonic-gate 			    ohcip, USB_CR_PIPE_RESET);
4930Sstevel@tonic-gate 		}
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 		ASSERT(ohcip->ohci_root_hub.
4960Sstevel@tonic-gate 		    rh_intr_pipe_state == OHCI_PIPE_STATE_IDLE);
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4990Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_reset: "
5000Sstevel@tonic-gate 		    "Pipe reset for root hub interrupt pipe successful");
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 		break;
5030Sstevel@tonic-gate 	default:
5040Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
5050Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_reset: "
5060Sstevel@tonic-gate 		    "Root hub pipe reset failed");
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 		error = USB_FAILURE;
5090Sstevel@tonic-gate 		break;
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	return (error);
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate /*
5190Sstevel@tonic-gate  * ohci_handle_root_hub_request:
5200Sstevel@tonic-gate  *
5210Sstevel@tonic-gate  * Intercept a root hub request.  Handle the  root hub request through the
5220Sstevel@tonic-gate  * registers
5230Sstevel@tonic-gate  */
5240Sstevel@tonic-gate /* ARGSUSED */
5250Sstevel@tonic-gate int
ohci_handle_root_hub_request(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp)5260Sstevel@tonic-gate ohci_handle_root_hub_request(
5270Sstevel@tonic-gate 	ohci_state_t		*ohcip,
5280Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
5290Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_reqp)
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate 	uchar_t			bmRequestType = ctrl_reqp->ctrl_bmRequestType;
5320Sstevel@tonic-gate 	uchar_t			bRequest = ctrl_reqp->ctrl_bRequest;
5330Sstevel@tonic-gate 	uint16_t		wValue = ctrl_reqp->ctrl_wValue;
5340Sstevel@tonic-gate 	uint16_t		wIndex = ctrl_reqp->ctrl_wIndex;
5350Sstevel@tonic-gate 	uint16_t		wLength = ctrl_reqp->ctrl_wLength;
5360Sstevel@tonic-gate 	mblk_t			*data = ctrl_reqp->ctrl_data;
5370Sstevel@tonic-gate 	uint16_t		port = wIndex - 1;  /* Adjust for controller */
5380Sstevel@tonic-gate 	usb_cr_t		completion_reason;
5390Sstevel@tonic-gate 	int			error = USB_SUCCESS;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
5420Sstevel@tonic-gate 	    "ohci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p",
5430Sstevel@tonic-gate 	    bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	if (ohcip->ohci_root_hub.rh_ctrl_pipe_state != OHCI_PIPE_STATE_IDLE) {
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
5500Sstevel@tonic-gate 		    "ohci_handle_root_hub_request: Pipe is not idle");
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 		mutex_exit(&ohcip->ohci_int_mutex);
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 		return (USB_FAILURE);
5550Sstevel@tonic-gate 	}
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	/* Save the current control request pointer */
5580Sstevel@tonic-gate 	ohcip->ohci_root_hub.rh_curr_ctrl_reqp = ctrl_reqp;
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	/* Set pipe state to active */
5610Sstevel@tonic-gate 	ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_ACTIVE;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	switch (bmRequestType) {
5661001Ssl147100 	case HUB_GET_DEVICE_STATUS_TYPE:
5671001Ssl147100 		ohci_handle_get_device_status(ohcip);
5681001Ssl147100 		break;
5691001Ssl147100 	case HUB_HANDLE_PORT_FEATURE_TYPE:
5700Sstevel@tonic-gate 		error = ohci_handle_set_clear_port_feature(ohcip,
5710Sstevel@tonic-gate 		    bRequest, wValue, port);
5720Sstevel@tonic-gate 		break;
5731001Ssl147100 	case HUB_GET_PORT_STATUS_TYPE:
5740Sstevel@tonic-gate 		ohci_handle_get_port_status(ohcip, port);
5750Sstevel@tonic-gate 		break;
5761001Ssl147100 	case HUB_CLASS_REQ_TYPE:
5770Sstevel@tonic-gate 		switch (bRequest) {
5780Sstevel@tonic-gate 		case USB_REQ_GET_STATUS:
5790Sstevel@tonic-gate 			ohci_handle_get_hub_status(ohcip);
5800Sstevel@tonic-gate 			break;
5810Sstevel@tonic-gate 		case USB_REQ_GET_DESCR:
5820Sstevel@tonic-gate 			ohci_handle_get_hub_descriptor(ohcip);
5830Sstevel@tonic-gate 			break;
5840Sstevel@tonic-gate 		default:
5850Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
5860Sstevel@tonic-gate 			    "ohci_handle_root_hub_request:"
5870Sstevel@tonic-gate 			    "Unsupported request 0x%x", bRequest);
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 			error = USB_FAILURE;
5900Sstevel@tonic-gate 			break;
5910Sstevel@tonic-gate 		}
5920Sstevel@tonic-gate 		break;
5932326Ssl147100 	case HUB_HANDLE_HUB_FEATURE_TYPE:
5942326Ssl147100 		error = ohci_handle_set_clear_hub_feature(ohcip,
5952326Ssl147100 		    bRequest, wValue);
5962326Ssl147100 		break;
5970Sstevel@tonic-gate 	default:
5980Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
5990Sstevel@tonic-gate 		    "ohci_handle_root_hub_request: "
6000Sstevel@tonic-gate 		    "Unsupported request 0x%x", bmRequestType);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 		error = USB_FAILURE;
6030Sstevel@tonic-gate 		break;
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	completion_reason = (error) ? USB_CR_NOT_SUPPORTED : USB_CR_OK;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
6090Sstevel@tonic-gate 	ohci_root_hub_hcdi_callback(ph, completion_reason);
6100Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
6130Sstevel@tonic-gate 	    "ohci_handle_root_hub_request: error = %d", error);
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	return (USB_SUCCESS);
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate /*
6200Sstevel@tonic-gate  * ohci_handle_set_clear_port_feature:
6210Sstevel@tonic-gate  */
6220Sstevel@tonic-gate static int
ohci_handle_set_clear_port_feature(ohci_state_t * ohcip,uchar_t bRequest,uint16_t wValue,uint16_t port)6230Sstevel@tonic-gate ohci_handle_set_clear_port_feature(
6240Sstevel@tonic-gate 	ohci_state_t		*ohcip,
6250Sstevel@tonic-gate 	uchar_t 		bRequest,
6260Sstevel@tonic-gate 	uint16_t		wValue,
6270Sstevel@tonic-gate 	uint16_t		port)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate 	int			error = USB_SUCCESS;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
6320Sstevel@tonic-gate 	    "ohci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x",
6330Sstevel@tonic-gate 	    bRequest, wValue, port);
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	switch (bRequest) {
6360Sstevel@tonic-gate 	case USB_REQ_SET_FEATURE:
6370Sstevel@tonic-gate 		switch (wValue) {
6380Sstevel@tonic-gate 		case CFS_PORT_ENABLE:
6390Sstevel@tonic-gate 			ohci_handle_port_enable(ohcip, port, 1);
6400Sstevel@tonic-gate 			break;
6410Sstevel@tonic-gate 		case CFS_PORT_SUSPEND:
6420Sstevel@tonic-gate 			ohci_handle_port_suspend(ohcip, port, 1);
6430Sstevel@tonic-gate 			break;
6440Sstevel@tonic-gate 		case CFS_PORT_RESET:
6450Sstevel@tonic-gate 			ohci_handle_port_reset(ohcip, port);
6460Sstevel@tonic-gate 			break;
6470Sstevel@tonic-gate 		case CFS_PORT_POWER:
6480Sstevel@tonic-gate 			ohci_handle_port_power(ohcip, port, 1);
6490Sstevel@tonic-gate 			break;
6500Sstevel@tonic-gate 		default:
6510Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
6520Sstevel@tonic-gate 			    "ohci_handle_set_clear_port_feature: "
6530Sstevel@tonic-gate 			    "Unsupported request 0x%x 0x%x", bRequest, wValue);
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 			error = USB_FAILURE;
6560Sstevel@tonic-gate 			break;
6570Sstevel@tonic-gate 		}
6580Sstevel@tonic-gate 		break;
6590Sstevel@tonic-gate 	case USB_REQ_CLEAR_FEATURE:
6600Sstevel@tonic-gate 		switch (wValue) {
6610Sstevel@tonic-gate 		case CFS_PORT_ENABLE:
6620Sstevel@tonic-gate 			ohci_handle_port_enable(ohcip, port, 0);
6630Sstevel@tonic-gate 			break;
6640Sstevel@tonic-gate 		case CFS_C_PORT_ENABLE:
6650Sstevel@tonic-gate 			ohci_handle_clrchng_port_enable(ohcip, port);
6660Sstevel@tonic-gate 			break;
6670Sstevel@tonic-gate 		case CFS_PORT_SUSPEND:
6680Sstevel@tonic-gate 			ohci_handle_port_suspend(ohcip, port, 0);
6690Sstevel@tonic-gate 			break;
6700Sstevel@tonic-gate 		case CFS_C_PORT_SUSPEND:
6710Sstevel@tonic-gate 			ohci_handle_clrchng_port_suspend(ohcip, port);
6720Sstevel@tonic-gate 			break;
6730Sstevel@tonic-gate 		case CFS_C_PORT_RESET:
6740Sstevel@tonic-gate 			ohci_handle_complete_port_reset(ohcip, port);
6750Sstevel@tonic-gate 			break;
6760Sstevel@tonic-gate 		case CFS_PORT_POWER:
6770Sstevel@tonic-gate 			ohci_handle_port_power(ohcip, port, 0);
6780Sstevel@tonic-gate 			break;
6790Sstevel@tonic-gate 		case CFS_C_PORT_CONNECTION:
6800Sstevel@tonic-gate 			ohci_handle_clear_port_connection(ohcip, port);
6810Sstevel@tonic-gate 			break;
6820Sstevel@tonic-gate 		case CFS_C_PORT_OVER_CURRENT:
6830Sstevel@tonic-gate 			ohci_handle_clrchng_port_over_current(ohcip, port);
6840Sstevel@tonic-gate 			break;
6850Sstevel@tonic-gate 		default:
6860Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
6870Sstevel@tonic-gate 			    "ohci_handle_set_clear_port_feature: "
6880Sstevel@tonic-gate 			    "Unsupported request 0x%x 0x%x", bRequest, wValue);
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 			error = USB_FAILURE;
6910Sstevel@tonic-gate 			break;
6920Sstevel@tonic-gate 		}
693*6898Sfb209375 		break;
6940Sstevel@tonic-gate 	default:
6950Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
6960Sstevel@tonic-gate 		    "ohci_handle_set_clear_port_feature: "
6970Sstevel@tonic-gate 		    "Unsupported request 0x%x 0x%x", bRequest, wValue);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 		error = USB_FAILURE;
7000Sstevel@tonic-gate 		break;
7010Sstevel@tonic-gate 	}
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	return (error);
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate /*
7080Sstevel@tonic-gate  * ohci_handle_port_power:
7090Sstevel@tonic-gate  *
7100Sstevel@tonic-gate  * Turn on a root hub port.
7110Sstevel@tonic-gate  */
7120Sstevel@tonic-gate static void
ohci_handle_port_power(ohci_state_t * ohcip,uint16_t port,uint_t on)7130Sstevel@tonic-gate ohci_handle_port_power(
7140Sstevel@tonic-gate 	ohci_state_t		*ohcip,
7150Sstevel@tonic-gate 	uint16_t		port,
7160Sstevel@tonic-gate 	uint_t			on)
7170Sstevel@tonic-gate {
7180Sstevel@tonic-gate 	usb_hub_descr_t		*hub_descr;
7190Sstevel@tonic-gate 	uint_t			port_status;
7200Sstevel@tonic-gate 	ohci_root_hub_t		*rh;
7210Sstevel@tonic-gate 	uint_t			p;
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
7260Sstevel@tonic-gate 	rh = &ohcip->ohci_root_hub;
7270Sstevel@tonic-gate 	hub_descr = &ohcip->ohci_root_hub.rh_descr;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
7300Sstevel@tonic-gate 	    "ohci_handle_port_power: port = 0x%x status = 0x%x on = %d",
7310Sstevel@tonic-gate 	    port, port_status, on);
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	if (on) {
7340Sstevel@tonic-gate 		/*
7350Sstevel@tonic-gate 		 * If the port power is ganged, enable the power through
7360Sstevel@tonic-gate 		 * the status registers, else enable the port power.
7370Sstevel@tonic-gate 		 */
7380Sstevel@tonic-gate 		if ((hub_descr->wHubCharacteristics &
7390Sstevel@tonic-gate 		    HUB_CHARS_POWER_SWITCHING_MODE) ==
7400Sstevel@tonic-gate 		    HUB_CHARS_GANGED_POWER) {
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 			Set_OpReg(hcr_rh_status, HCR_RH_STATUS_LPSC);
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 			for (p = 0; p < hub_descr->bNbrPorts; p++) {
7450Sstevel@tonic-gate 				rh->rh_port_status[p] = 0;
7460Sstevel@tonic-gate 				rh->rh_port_state[p] = DISCONNECTED;
7470Sstevel@tonic-gate 			}
7480Sstevel@tonic-gate 		} else {
7490Sstevel@tonic-gate 			/* See if the port power is already on */
7500Sstevel@tonic-gate 			if (!(port_status & HCR_PORT_PPS)) {
7510Sstevel@tonic-gate 				/* Turn the port on */
7520Sstevel@tonic-gate 				Set_OpReg(hcr_rh_portstatus[port],
7530Sstevel@tonic-gate 				    HCR_PORT_PPS);
7540Sstevel@tonic-gate 			}
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 			rh->rh_port_status[port] = 0;
7570Sstevel@tonic-gate 			rh->rh_port_state[port] = DISCONNECTED;
7580Sstevel@tonic-gate 		}
7590Sstevel@tonic-gate 	} else {
7600Sstevel@tonic-gate 		/*
7610Sstevel@tonic-gate 		 * If the port power is ganged, disable the power through
7620Sstevel@tonic-gate 		 * the status registers, else disable the port power.
7630Sstevel@tonic-gate 		 */
7640Sstevel@tonic-gate 		if ((hub_descr->wHubCharacteristics &
7650Sstevel@tonic-gate 		    HUB_CHARS_POWER_SWITCHING_MODE) ==
7660Sstevel@tonic-gate 		    HUB_CHARS_GANGED_POWER) {
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 			Set_OpReg(hcr_rh_status, HCR_RH_STATUS_LPS);
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 			for (p = 0; p < hub_descr->bNbrPorts; p++) {
7710Sstevel@tonic-gate 				rh->rh_port_status[p] = 0;
7720Sstevel@tonic-gate 				rh->rh_port_state[p] = POWERED_OFF;
7730Sstevel@tonic-gate 			}
7740Sstevel@tonic-gate 		} else {
7750Sstevel@tonic-gate 			/* See if the port power is already OFF */
7760Sstevel@tonic-gate 			if ((port_status & HCR_PORT_PPS)) {
7770Sstevel@tonic-gate 				/* Turn the port OFF by writing LSSA bit  */
7780Sstevel@tonic-gate 				Set_OpReg(hcr_rh_portstatus[port],
779*6898Sfb209375 				    HCR_PORT_LSDA);
7800Sstevel@tonic-gate 			}
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 			rh->rh_port_status[port] = 0;
7830Sstevel@tonic-gate 			rh->rh_port_state[port] = POWERED_OFF;
7840Sstevel@tonic-gate 		}
7850Sstevel@tonic-gate 	}
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
7880Sstevel@tonic-gate 	    "ohci_handle_port_power done: "
7890Sstevel@tonic-gate 	    "port = 0x%x status = 0x%x on = %d",
7900Sstevel@tonic-gate 	    port, Get_OpReg(hcr_rh_portstatus[port]), on);
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate /*
7970Sstevel@tonic-gate  * ohci_handle_port_enable:
7980Sstevel@tonic-gate  *
7990Sstevel@tonic-gate  * Handle port enable request.
8000Sstevel@tonic-gate  */
8010Sstevel@tonic-gate static void
ohci_handle_port_enable(ohci_state_t * ohcip,uint16_t port,uint_t on)8020Sstevel@tonic-gate ohci_handle_port_enable(
8030Sstevel@tonic-gate 	ohci_state_t		*ohcip,
8040Sstevel@tonic-gate 	uint16_t		port,
8050Sstevel@tonic-gate 	uint_t			on)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate 	uint_t			port_status;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
8140Sstevel@tonic-gate 	    "ohci_handle_port_enable: port = 0x%x, status = 0x%x",
8150Sstevel@tonic-gate 	    port, port_status);
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	if (on) {
8180Sstevel@tonic-gate 		/* See if the port enable is already on */
8190Sstevel@tonic-gate 		if (!(port_status & HCR_PORT_PES)) {
8200Sstevel@tonic-gate 			/* Enable the port */
8210Sstevel@tonic-gate 			Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PES);
8220Sstevel@tonic-gate 		}
8230Sstevel@tonic-gate 	} else {
8240Sstevel@tonic-gate 		/* See if the port enable is already off */
8253026Syq193411 		if (port_status & HCR_PORT_PES) {
8260Sstevel@tonic-gate 			/* disable the port by writing CCS bit */
8270Sstevel@tonic-gate 			Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_CCS);
8280Sstevel@tonic-gate 		}
8290Sstevel@tonic-gate 	}
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate /*
8360Sstevel@tonic-gate  * ohci_handle_clrchng_port_enable:
8370Sstevel@tonic-gate  *
8380Sstevel@tonic-gate  * Handle clear port enable change bit.
8390Sstevel@tonic-gate  */
8400Sstevel@tonic-gate static void
ohci_handle_clrchng_port_enable(ohci_state_t * ohcip,uint16_t port)8410Sstevel@tonic-gate ohci_handle_clrchng_port_enable(
8420Sstevel@tonic-gate 	ohci_state_t		*ohcip,
8430Sstevel@tonic-gate 	uint16_t		port)
8440Sstevel@tonic-gate {
8450Sstevel@tonic-gate 	uint_t			port_status;
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
8520Sstevel@tonic-gate 	    "ohci_handle_port_enable: port = 0x%x, status = 0x%x",
8530Sstevel@tonic-gate 	    port, port_status);
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	/* Clear the PortEnableStatusChange Bit */
8560Sstevel@tonic-gate 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PESC);
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate /*
8630Sstevel@tonic-gate  * ohci_handle_port_suspend:
8640Sstevel@tonic-gate  *
8650Sstevel@tonic-gate  * Handle port suspend/resume request.
8660Sstevel@tonic-gate  */
8670Sstevel@tonic-gate static void
ohci_handle_port_suspend(ohci_state_t * ohcip,uint16_t port,uint_t on)8680Sstevel@tonic-gate ohci_handle_port_suspend(
8690Sstevel@tonic-gate 	ohci_state_t		*ohcip,
8700Sstevel@tonic-gate 	uint16_t		port,
8710Sstevel@tonic-gate 	uint_t			on)
8720Sstevel@tonic-gate {
8730Sstevel@tonic-gate 	uint_t			port_status;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
8800Sstevel@tonic-gate 	    "ohci_handle_port_suspend: port = 0x%x, status = 0x%x",
8810Sstevel@tonic-gate 	    port, port_status);
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	if (on) {
8840Sstevel@tonic-gate 		/* Suspend the port */
8850Sstevel@tonic-gate 		Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PSS);
8860Sstevel@tonic-gate 	} else {
8870Sstevel@tonic-gate 		/* To Resume, we write the POCI bit */
8880Sstevel@tonic-gate 		Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_POCI);
8890Sstevel@tonic-gate 	}
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate /*
8960Sstevel@tonic-gate  * ohci_handle_clrchng_port_suspend:
8970Sstevel@tonic-gate  *
8980Sstevel@tonic-gate  * Handle port clear port suspend change bit.
8990Sstevel@tonic-gate  */
9000Sstevel@tonic-gate static void
ohci_handle_clrchng_port_suspend(ohci_state_t * ohcip,uint16_t port)9010Sstevel@tonic-gate ohci_handle_clrchng_port_suspend(
9020Sstevel@tonic-gate 	ohci_state_t		*ohcip,
9030Sstevel@tonic-gate 	uint16_t		port)
9040Sstevel@tonic-gate {
9050Sstevel@tonic-gate 	uint_t			port_status;
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
9120Sstevel@tonic-gate 	    "ohci_handle_clrchng_port_suspend: port = 0x%x, status = 0x%x",
9130Sstevel@tonic-gate 	    port, port_status);
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PSSC);
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
9180Sstevel@tonic-gate }
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate /*
9220Sstevel@tonic-gate  * ohci_handle_port_reset:
9230Sstevel@tonic-gate  *
9240Sstevel@tonic-gate  * Perform a port reset.
9250Sstevel@tonic-gate  */
9260Sstevel@tonic-gate static void
ohci_handle_port_reset(ohci_state_t * ohcip,uint16_t port)9270Sstevel@tonic-gate ohci_handle_port_reset(
9280Sstevel@tonic-gate 	ohci_state_t		*ohcip,
9290Sstevel@tonic-gate 	uint16_t		port)
9300Sstevel@tonic-gate {
9310Sstevel@tonic-gate 	uint_t			port_status;
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
9380Sstevel@tonic-gate 	    "ohci_handle_port_reset: port = 0x%x status = 0x%x",
9390Sstevel@tonic-gate 	    port, port_status);
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	if (!(port_status & HCR_PORT_CCS)) {
9420Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
9430Sstevel@tonic-gate 		    "port_status & HCR_PORT_CCS == 0: "
9440Sstevel@tonic-gate 		    "port = 0x%x status = 0x%x", port, port_status);
9450Sstevel@tonic-gate 	}
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PRS);
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
9500Sstevel@tonic-gate }
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate /*
9540Sstevel@tonic-gate  * ohci_handle_complete_port_reset:
9550Sstevel@tonic-gate  *
9560Sstevel@tonic-gate  * Perform a port reset change.
9570Sstevel@tonic-gate  */
9580Sstevel@tonic-gate static void
ohci_handle_complete_port_reset(ohci_state_t * ohcip,uint16_t port)9590Sstevel@tonic-gate ohci_handle_complete_port_reset(
9600Sstevel@tonic-gate 	ohci_state_t		*ohcip,
9610Sstevel@tonic-gate 	uint16_t		port)
9620Sstevel@tonic-gate {
9630Sstevel@tonic-gate 	uint_t			port_status;
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
9700Sstevel@tonic-gate 	    "ohci_handle_complete_port_reset: port = 0x%x status = 0x%x",
9710Sstevel@tonic-gate 	    port, port_status);
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	if (!(port_status & HCR_PORT_CCS)) {
9740Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
9750Sstevel@tonic-gate 		    "port_status & HCR_PORT_CCS == 0: "
9760Sstevel@tonic-gate 		    "port = 0x%x status = 0x%x", port, port_status);
9770Sstevel@tonic-gate 	}
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PRSC);
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate /*
9860Sstevel@tonic-gate  * ohci_handle_clear_port_connection:
9870Sstevel@tonic-gate  *
9880Sstevel@tonic-gate  * Perform a clear port connection.
9890Sstevel@tonic-gate  */
9900Sstevel@tonic-gate static void
ohci_handle_clear_port_connection(ohci_state_t * ohcip,uint16_t port)9910Sstevel@tonic-gate ohci_handle_clear_port_connection(
9920Sstevel@tonic-gate 	ohci_state_t		*ohcip,
9930Sstevel@tonic-gate 	uint16_t		port)
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate 	uint_t			port_status;
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
10020Sstevel@tonic-gate 	    "ohci_handle_clear_port_connection: port = 0x%x"
10030Sstevel@tonic-gate 	    "status = 0x%x", port, port_status);
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	/* Clear CSC bit */
10060Sstevel@tonic-gate 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_CSC);
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
10090Sstevel@tonic-gate }
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate /*
10130Sstevel@tonic-gate  * ohci_handle_clrchng_port_over_current:
10140Sstevel@tonic-gate  *
10150Sstevel@tonic-gate  * Perform a clear over current condition.
10160Sstevel@tonic-gate  */
10170Sstevel@tonic-gate static void
ohci_handle_clrchng_port_over_current(ohci_state_t * ohcip,uint16_t port)10180Sstevel@tonic-gate ohci_handle_clrchng_port_over_current(
10190Sstevel@tonic-gate 	ohci_state_t		*ohcip,
10200Sstevel@tonic-gate 	uint16_t		port)
10210Sstevel@tonic-gate {
10220Sstevel@tonic-gate 	uint_t			port_status;
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
10290Sstevel@tonic-gate 	    "ohci_handle_clrchng_port_over_current: port = 0x%x"
10300Sstevel@tonic-gate 	    "status = 0x%x", port, port_status);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_OCIC);
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate /*
10390Sstevel@tonic-gate  * ohci_handle_get_port_status:
10400Sstevel@tonic-gate  *
10410Sstevel@tonic-gate  * Handle a get port status request.
10420Sstevel@tonic-gate  */
10430Sstevel@tonic-gate static void
ohci_handle_get_port_status(ohci_state_t * ohcip,uint16_t port)10440Sstevel@tonic-gate ohci_handle_get_port_status(
10450Sstevel@tonic-gate 	ohci_state_t		*ohcip,
10460Sstevel@tonic-gate 	uint16_t		port)
10470Sstevel@tonic-gate {
10480Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_reqp;
10490Sstevel@tonic-gate 	mblk_t			*message;
10500Sstevel@tonic-gate 	uint_t			new_port_status;
10510Sstevel@tonic-gate 	uint_t			change_status;
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	/* Read the current port status and return it */
10580Sstevel@tonic-gate 	new_port_status = Get_OpReg(hcr_rh_portstatus[port]);
10590Sstevel@tonic-gate 	ohcip->ohci_root_hub.rh_port_status[port] = new_port_status;
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	change_status = (new_port_status & HCR_PORT_CHNG_MASK) >> 16;
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
10640Sstevel@tonic-gate 	    "ohci_handle_get_port_status: port = %d new status = 0x%x"
10650Sstevel@tonic-gate 	    "change = 0x%x", port, new_port_status, change_status);
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	message = ctrl_reqp->ctrl_data;
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	ASSERT(message != NULL);
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	*message->b_wptr++ = (uchar_t)new_port_status;
10720Sstevel@tonic-gate 	*message->b_wptr++ = (uchar_t)(new_port_status >> 8);
10730Sstevel@tonic-gate 	*message->b_wptr++ = (uchar_t)change_status;
10740Sstevel@tonic-gate 	*message->b_wptr++ = (uchar_t)(change_status >> 8);
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	/* Save the data in control request */
10770Sstevel@tonic-gate 	ctrl_reqp->ctrl_data = message;
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate /*
10842326Ssl147100  * ohci_handle_set_clear_hub_feature:
10852326Ssl147100  *
10862326Ssl147100  * OHCI only implements clearing C_HUB_OVER_CURRENT feature now.
10872326Ssl147100  * Other hub requests of this bmRequestType are either not
10882326Ssl147100  * supported by hardware or never used.
10892326Ssl147100  */
10902326Ssl147100 static int
ohci_handle_set_clear_hub_feature(ohci_state_t * ohcip,uchar_t bRequest,uint16_t wValue)10912326Ssl147100 ohci_handle_set_clear_hub_feature(
10922326Ssl147100 	ohci_state_t		*ohcip,
10932326Ssl147100 	uchar_t 		bRequest,
10942326Ssl147100 	uint16_t		wValue)
10952326Ssl147100 {
10962326Ssl147100 	int			error = USB_SUCCESS;
10972326Ssl147100 
10982326Ssl147100 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
10992326Ssl147100 	    "ohci_handle_set_clear_hub_feature: 0x%x 0x%x",
11002326Ssl147100 	    bRequest, wValue);
11012326Ssl147100 
11022326Ssl147100 	switch (bRequest) {
11032326Ssl147100 	case USB_REQ_CLEAR_FEATURE:
11042326Ssl147100 		if (wValue == CFS_C_HUB_OVER_CURRENT) {
11052326Ssl147100 			ohci_handle_clrchng_hub_over_current(ohcip);
11062326Ssl147100 		} else {
11072326Ssl147100 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
11082326Ssl147100 			    "ohci_handle_set_clear_hub_feature: "
11092326Ssl147100 			    "Unsupported request 0x%x 0x%x", bRequest, wValue);
11102326Ssl147100 
11112326Ssl147100 			error = USB_FAILURE;
11122326Ssl147100 		}
11132326Ssl147100 		break;
11142326Ssl147100 
11152326Ssl147100 	case USB_REQ_SET_FEATURE:
11162326Ssl147100 	default:
11172326Ssl147100 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
11182326Ssl147100 		    "ohci_handle_set_clear_hub_feature: "
11192326Ssl147100 		    "Unsupported request 0x%x 0x%x", bRequest, wValue);
11202326Ssl147100 
11212326Ssl147100 		error = USB_FAILURE;
11222326Ssl147100 		break;
11232326Ssl147100 	}
11242326Ssl147100 
11252326Ssl147100 	return (error);
11262326Ssl147100 }
11272326Ssl147100 
11282326Ssl147100 
11292326Ssl147100 /*
11302326Ssl147100  * ohci_handle_clrchng_hub_over_current:
11312326Ssl147100  *
11322326Ssl147100  * Clear over current indicator change bit on the root hub.
11332326Ssl147100  */
11342326Ssl147100 static void
ohci_handle_clrchng_hub_over_current(ohci_state_t * ohcip)11352326Ssl147100 ohci_handle_clrchng_hub_over_current(
11362326Ssl147100 	ohci_state_t		*ohcip)
11372326Ssl147100 {
11382326Ssl147100 	uint_t			hub_status;
11392326Ssl147100 
11402326Ssl147100 	mutex_enter(&ohcip->ohci_int_mutex);
11412326Ssl147100 
11422326Ssl147100 	hub_status = Get_OpReg(hcr_rh_status);
11432326Ssl147100 
11442326Ssl147100 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
11452326Ssl147100 	    "ohci_handle_clrchng_hub_over_current: "
11462326Ssl147100 	    "status = 0x%x", hub_status);
11472326Ssl147100 
11482326Ssl147100 	Set_OpReg(hcr_rh_status, HCR_RH_STATUS_OCIC);
11492326Ssl147100 
11502326Ssl147100 	mutex_exit(&ohcip->ohci_int_mutex);
11512326Ssl147100 }
11522326Ssl147100 
11532326Ssl147100 
11542326Ssl147100 /*
11550Sstevel@tonic-gate  * ohci_handle_get_hub_descriptor:
11560Sstevel@tonic-gate  */
11570Sstevel@tonic-gate static void
ohci_handle_get_hub_descriptor(ohci_state_t * ohcip)11580Sstevel@tonic-gate ohci_handle_get_hub_descriptor(
11590Sstevel@tonic-gate 	ohci_state_t		*ohcip)
11600Sstevel@tonic-gate {
11610Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_reqp;
11620Sstevel@tonic-gate 	mblk_t			*message;
11630Sstevel@tonic-gate 	usb_hub_descr_t		*root_hub_descr;
11640Sstevel@tonic-gate 	size_t			length;
11650Sstevel@tonic-gate 	uchar_t			raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH];
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
11700Sstevel@tonic-gate 	root_hub_descr = &ohcip->ohci_root_hub.rh_descr;
11710Sstevel@tonic-gate 	length = ctrl_reqp->ctrl_wLength;
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
11740Sstevel@tonic-gate 	    "ohci_handle_get_hub_descriptor: Ctrl Req  = 0x%p",
1175*6898Sfb209375 	    (void *)ctrl_reqp);
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate 	message = ctrl_reqp->ctrl_data;
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	ASSERT(message != NULL);
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH);
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	raw_descr[0] = root_hub_descr->bDescLength;
11840Sstevel@tonic-gate 	raw_descr[1] = root_hub_descr->bDescriptorType;
11850Sstevel@tonic-gate 	raw_descr[2] = root_hub_descr->bNbrPorts;
11860Sstevel@tonic-gate 	raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00FF;
11870Sstevel@tonic-gate 	raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xFF00) >> 8;
11880Sstevel@tonic-gate 	raw_descr[5] = root_hub_descr->bPwrOn2PwrGood;
11890Sstevel@tonic-gate 	raw_descr[6] = root_hub_descr->bHubContrCurrent;
11900Sstevel@tonic-gate 	raw_descr[7] = root_hub_descr->DeviceRemovable;
11910Sstevel@tonic-gate 	raw_descr[8] = root_hub_descr->PortPwrCtrlMask;
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	bcopy(raw_descr, message->b_wptr, length);
11940Sstevel@tonic-gate 	message->b_wptr += length;
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	/* Save the data in control request */
11970Sstevel@tonic-gate 	ctrl_reqp->ctrl_data = message;
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate /*
12040Sstevel@tonic-gate  * ohci_handle_get_hub_status:
12050Sstevel@tonic-gate  *
12060Sstevel@tonic-gate  * Handle a get hub status request.
12070Sstevel@tonic-gate  */
12080Sstevel@tonic-gate static void
ohci_handle_get_hub_status(ohci_state_t * ohcip)12090Sstevel@tonic-gate ohci_handle_get_hub_status(
12100Sstevel@tonic-gate 	ohci_state_t		*ohcip)
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_reqp;
12130Sstevel@tonic-gate 	mblk_t			*message;
12140Sstevel@tonic-gate 	uint_t			new_root_hub_status;
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
12190Sstevel@tonic-gate 	new_root_hub_status = Get_OpReg(hcr_rh_status);
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
12220Sstevel@tonic-gate 	    "ohci_handle_get_hub_status: new root hub status = 0x%x",
12230Sstevel@tonic-gate 	    new_root_hub_status);
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	message = ctrl_reqp->ctrl_data;
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	ASSERT(message != NULL);
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	*message->b_wptr++ = (uchar_t)new_root_hub_status;
12300Sstevel@tonic-gate 	*message->b_wptr++ = (uchar_t)(new_root_hub_status >> 8);
12310Sstevel@tonic-gate 	*message->b_wptr++ = (uchar_t)(new_root_hub_status >> 16);
12320Sstevel@tonic-gate 	*message->b_wptr++ = (uchar_t)(new_root_hub_status >> 24);
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	/* Save the data in control request */
12350Sstevel@tonic-gate 	ctrl_reqp->ctrl_data = message;
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
12380Sstevel@tonic-gate }
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate /*
12421001Ssl147100  * ohci_handle_get_device_status:
12431001Ssl147100  *
12441001Ssl147100  * Handle a get device status request.
12451001Ssl147100  */
12461001Ssl147100 static void
ohci_handle_get_device_status(ohci_state_t * ohcip)12471001Ssl147100 ohci_handle_get_device_status(
12481001Ssl147100 	ohci_state_t		*ohcip)
12491001Ssl147100 {
12501001Ssl147100 	usb_ctrl_req_t		*ctrl_reqp;
12511001Ssl147100 	mblk_t			*message;
12521001Ssl147100 	uint16_t		dev_status;
12531001Ssl147100 
12541001Ssl147100 	mutex_enter(&ohcip->ohci_int_mutex);
12551001Ssl147100 
12561001Ssl147100 	ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
12571001Ssl147100 
12581001Ssl147100 	/*
12591001Ssl147100 	 * OHCI doesn't have device status information.
12601001Ssl147100 	 * Simply return what is desired for the request.
12611001Ssl147100 	 */
12621001Ssl147100 	dev_status = USB_DEV_SLF_PWRD_STATUS;
12631001Ssl147100 
12641001Ssl147100 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
12651001Ssl147100 	    "ohci_handle_get_device_status: device status = 0x%x",
12661001Ssl147100 	    dev_status);
12671001Ssl147100 
12681001Ssl147100 	message = ctrl_reqp->ctrl_data;
12691001Ssl147100 
12701001Ssl147100 	ASSERT(message != NULL);
12711001Ssl147100 
12721001Ssl147100 	*message->b_wptr++ = (uchar_t)dev_status;
12731001Ssl147100 	*message->b_wptr++ = (uchar_t)(dev_status >> 8);
12741001Ssl147100 
12751001Ssl147100 	/* Save the data in control request */
12761001Ssl147100 	ctrl_reqp->ctrl_data = message;
12771001Ssl147100 
12781001Ssl147100 	mutex_exit(&ohcip->ohci_int_mutex);
12791001Ssl147100 }
12801001Ssl147100 
12811001Ssl147100 
12821001Ssl147100 /*
12830Sstevel@tonic-gate  * ohci_handle_root_hub_pipe_start_intr_polling:
12840Sstevel@tonic-gate  *
12850Sstevel@tonic-gate  * Handle start polling on root hub interrupt pipe.
12860Sstevel@tonic-gate  */
12870Sstevel@tonic-gate /* ARGSUSED */
12880Sstevel@tonic-gate int
ohci_handle_root_hub_pipe_start_intr_polling(usba_pipe_handle_data_t * ph,usb_intr_req_t * client_intr_reqp,usb_flags_t flags)12890Sstevel@tonic-gate ohci_handle_root_hub_pipe_start_intr_polling(
12900Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
12910Sstevel@tonic-gate 	usb_intr_req_t		*client_intr_reqp,
12920Sstevel@tonic-gate 	usb_flags_t		flags)
12930Sstevel@tonic-gate {
12940Sstevel@tonic-gate 	ohci_state_t		*ohcip = ohci_obtain_state(
1295*6898Sfb209375 	    ph->p_usba_device->usb_root_hub_dip);
12960Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
12970Sstevel@tonic-gate 	int			error = USB_SUCCESS;
12980Sstevel@tonic-gate 	uint_t			pipe_state;
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13010Sstevel@tonic-gate 	    "ohci_handle_root_hub_pipe_start_intr_polling: "
13020Sstevel@tonic-gate 	    "Root hub pipe start polling");
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate 	ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	/* ONE_XFER not supported for root hub interrupt pipe */
13090Sstevel@tonic-gate 	ASSERT((client_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) == 0);
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 	/* Get root hub intr pipe state */
13120Sstevel@tonic-gate 	pipe_state = ohcip->ohci_root_hub.rh_intr_pipe_state;
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	switch (pipe_state) {
13150Sstevel@tonic-gate 	case OHCI_PIPE_STATE_IDLE:
13160Sstevel@tonic-gate 		ASSERT(ohcip->ohci_root_hub.rh_intr_pipe_timer_id == 0);
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 		/*
13190Sstevel@tonic-gate 		 * Save the Original Client's Interrupt IN request
13200Sstevel@tonic-gate 		 * information. We use this for final callback
13210Sstevel@tonic-gate 		 */
13220Sstevel@tonic-gate 		ASSERT(ohcip->ohci_root_hub.rh_client_intr_reqp == NULL);
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_client_intr_reqp = client_intr_reqp;
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 		error = ohci_root_hub_allocate_intr_pipe_resource(ohcip, flags);
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 		if (error != USB_SUCCESS) {
13290Sstevel@tonic-gate 			/* Reset client interrupt request pointer */
13300Sstevel@tonic-gate 			ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13330Sstevel@tonic-gate 			    "ohci_handle_root_hub_pipe_start_intr_polling: "
13340Sstevel@tonic-gate 			    "No Resources");
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 			return (error);
13370Sstevel@tonic-gate 		}
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13400Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_start_intr_polling: "
13410Sstevel@tonic-gate 		    "Start polling for root hub successful");
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 		break;
13440Sstevel@tonic-gate 	case OHCI_PIPE_STATE_ACTIVE:
13450Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13460Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_start_intr_polling: "
13470Sstevel@tonic-gate 		    "Polling for root hub is already in progress");
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 		break;
13500Sstevel@tonic-gate 	default:
13510Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13520Sstevel@tonic-gate 		    "ohci_handle_root_hub_pipe_start_intr_polling: "
13530Sstevel@tonic-gate 		    "Pipe is in error state 0x%x", pipe_state);
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 		error = USB_FAILURE;
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 		break;
13580Sstevel@tonic-gate 	}
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	return (error);
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate /*
13650Sstevel@tonic-gate  * ohci_handle_root_hub_pipe_stop_intr_polling:
13660Sstevel@tonic-gate  *
13670Sstevel@tonic-gate  * Handle stop polling on root hub intr pipe.
13680Sstevel@tonic-gate  */
13690Sstevel@tonic-gate /* ARGSUSED */
13700Sstevel@tonic-gate void
ohci_handle_root_hub_pipe_stop_intr_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)13710Sstevel@tonic-gate ohci_handle_root_hub_pipe_stop_intr_polling(
13720Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
13730Sstevel@tonic-gate 	usb_flags_t		flags)
13740Sstevel@tonic-gate {
13750Sstevel@tonic-gate 	ohci_state_t		*ohcip = ohci_obtain_state(
1376*6898Sfb209375 	    ph->p_usba_device->usb_root_hub_dip);
13770Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13820Sstevel@tonic-gate 	    "ohci_handle_root_hub_pipe_stop_intr_polling: "
13830Sstevel@tonic-gate 	    "Root hub pipe stop polling");
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 	ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	if (ohcip->ohci_root_hub.rh_intr_pipe_state == OHCI_PIPE_STATE_ACTIVE) {
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_intr_pipe_state =
13900Sstevel@tonic-gate 		    OHCI_PIPE_STATE_STOP_POLLING;
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 		/* Do interrupt pipe cleanup */
13930Sstevel@tonic-gate 		ohci_root_hub_intr_pipe_cleanup(ohcip, USB_CR_STOPPED_POLLING);
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 		ASSERT(ohcip->ohci_root_hub.
13960Sstevel@tonic-gate 		    rh_intr_pipe_state == OHCI_PIPE_STATE_IDLE);
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13990Sstevel@tonic-gate 		    "ohci_hcdi_pipe_stop_intr_polling: Stop polling for root"
14000Sstevel@tonic-gate 		    "hub successful");
14010Sstevel@tonic-gate 	} else {
14020Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
14030Sstevel@tonic-gate 		    "ohci_hcdi_pipe_stop_intr_polling: "
14040Sstevel@tonic-gate 		    "Polling for root hub is already stopped");
14050Sstevel@tonic-gate 	}
14060Sstevel@tonic-gate }
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate /*
14100Sstevel@tonic-gate  * ohci_root_hub_allocate_intr_pipe_resource:
14110Sstevel@tonic-gate  *
14120Sstevel@tonic-gate  * Allocate interrupt requests and initialize them.
14130Sstevel@tonic-gate  */
14140Sstevel@tonic-gate static int
ohci_root_hub_allocate_intr_pipe_resource(ohci_state_t * ohcip,usb_flags_t flags)14150Sstevel@tonic-gate ohci_root_hub_allocate_intr_pipe_resource(
14160Sstevel@tonic-gate 	ohci_state_t		*ohcip,
14170Sstevel@tonic-gate 	usb_flags_t		flags)
14180Sstevel@tonic-gate {
14190Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph;
14200Sstevel@tonic-gate 	size_t			length;
14210Sstevel@tonic-gate 	usb_intr_req_t		*curr_intr_reqp;
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
14240Sstevel@tonic-gate 	    "ohci_root_hub_allocate_intr_pipe_resource");
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	/* Get the interrupt pipe handle */
14290Sstevel@tonic-gate 	ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	/* Get the current interrupt request pointer */
14320Sstevel@tonic-gate 	curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	/*
14350Sstevel@tonic-gate 	 * If current interrupt request pointer is null,
14360Sstevel@tonic-gate 	 * allocate new interrupt request.
14370Sstevel@tonic-gate 	 */
14380Sstevel@tonic-gate 	if (curr_intr_reqp == NULL) {
14390Sstevel@tonic-gate 		ASSERT(ohcip->ohci_root_hub.rh_client_intr_reqp);
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 		/* Get the length of interrupt transfer */
14420Sstevel@tonic-gate 		length = ohcip->ohci_root_hub.
14430Sstevel@tonic-gate 		    rh_client_intr_reqp->intr_len;
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 		curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
14460Sstevel@tonic-gate 		    ohcip->ohci_root_hub.rh_client_intr_reqp,
14470Sstevel@tonic-gate 		    length, flags);
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 		if (curr_intr_reqp == NULL) {
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
14520Sstevel@tonic-gate 			    "ohci_root_hub_allocate_intr_pipe_resource:"
14530Sstevel@tonic-gate 			    "Interrupt request structure allocation failed");
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate 			return (USB_NO_RESOURCES);
14560Sstevel@tonic-gate 		}
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_curr_intr_reqp = curr_intr_reqp;
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
14610Sstevel@tonic-gate 		ph->p_req_count++;
14620Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
14630Sstevel@tonic-gate 	}
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	/* Start the timer for the root hub interrupt pipe polling */
14660Sstevel@tonic-gate 	if (ohcip->ohci_root_hub.rh_intr_pipe_timer_id == 0) {
14670Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_intr_pipe_timer_id =
14680Sstevel@tonic-gate 		    timeout(ohci_handle_root_hub_status_change,
14690Sstevel@tonic-gate 		    (void *)ohcip, drv_usectohz(OHCI_RH_POLL_TIME));
14700Sstevel@tonic-gate 
14710Sstevel@tonic-gate 		ohcip->ohci_root_hub.
14720Sstevel@tonic-gate 		    rh_intr_pipe_state = OHCI_PIPE_STATE_ACTIVE;
14730Sstevel@tonic-gate 	}
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 	return (USB_SUCCESS);
14760Sstevel@tonic-gate }
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate  * ohci_root_hub_intr_pipe_cleanup:
14810Sstevel@tonic-gate  *
14820Sstevel@tonic-gate  * Deallocate all interrupt requests and do callback
14830Sstevel@tonic-gate  * the original client interrupt request.
14840Sstevel@tonic-gate  */
14850Sstevel@tonic-gate static void
ohci_root_hub_intr_pipe_cleanup(ohci_state_t * ohcip,usb_cr_t completion_reason)14860Sstevel@tonic-gate ohci_root_hub_intr_pipe_cleanup(
14870Sstevel@tonic-gate 	ohci_state_t		*ohcip,
14880Sstevel@tonic-gate 	usb_cr_t		completion_reason)
14890Sstevel@tonic-gate {
14900Sstevel@tonic-gate 	usb_intr_req_t		*curr_intr_reqp;
14910Sstevel@tonic-gate 	usb_opaque_t		client_intr_reqp;
14920Sstevel@tonic-gate 	timeout_id_t		timer_id;
14930Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph;
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
14960Sstevel@tonic-gate 	    "ohci_root_hub_intr_pipe_cleanup");
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate 	/* Get the interrupt pipe handle */
15010Sstevel@tonic-gate 	ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 	/* Get the interrupt timerid */
15040Sstevel@tonic-gate 	timer_id = ohcip->ohci_root_hub.rh_intr_pipe_timer_id;
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	/* Stop the root hub interrupt timer */
15070Sstevel@tonic-gate 	if (timer_id) {
15080Sstevel@tonic-gate 		/* Reset the timer id to zero */
15090Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 		mutex_exit(&ohcip->ohci_int_mutex);
15120Sstevel@tonic-gate 		(void) untimeout(timer_id);
15130Sstevel@tonic-gate 		mutex_enter(&ohcip->ohci_int_mutex);
15140Sstevel@tonic-gate 	}
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	/* Reset the current interrupt request pointer */
15170Sstevel@tonic-gate 	curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate 	/* Deallocate uncompleted interrupt request */
15200Sstevel@tonic-gate 	if (curr_intr_reqp) {
15210Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
15220Sstevel@tonic-gate 		usb_free_intr_req(curr_intr_reqp);
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
15250Sstevel@tonic-gate 		ph->p_req_count--;
15260Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
15270Sstevel@tonic-gate 	}
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	client_intr_reqp = (usb_opaque_t)
15300Sstevel@tonic-gate 	    ohcip->ohci_root_hub.rh_client_intr_reqp;
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 	/* Callback for original client interrupt request */
15330Sstevel@tonic-gate 	if (client_intr_reqp) {
15340Sstevel@tonic-gate 		ohci_root_hub_hcdi_callback(ph, completion_reason);
15350Sstevel@tonic-gate 	}
15360Sstevel@tonic-gate }
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate /*
15400Sstevel@tonic-gate  * ohci_handle_root_hub_status_change:
15410Sstevel@tonic-gate  *
15420Sstevel@tonic-gate  * A root hub status change interrupt will occur any time there is a change
15430Sstevel@tonic-gate  * in the root hub status register or one of the port status registers.
15440Sstevel@tonic-gate  */
15450Sstevel@tonic-gate void
ohci_handle_root_hub_status_change(void * arg)15460Sstevel@tonic-gate ohci_handle_root_hub_status_change(void *arg)
15470Sstevel@tonic-gate {
15480Sstevel@tonic-gate 	ohci_state_t		*ohcip = (ohci_state_t *)arg;
15490Sstevel@tonic-gate 	usb_intr_req_t		*curr_intr_reqp;
1550520Shx149380 	usb_port_mask_t		all_ports_status = 0;
15510Sstevel@tonic-gate 	uint_t			new_root_hub_status;
15520Sstevel@tonic-gate 	uint_t			new_port_status;
15530Sstevel@tonic-gate 	uint_t			change_status;
15540Sstevel@tonic-gate 	usb_hub_descr_t		*hub_descr;
15550Sstevel@tonic-gate 	mblk_t			*message;
15560Sstevel@tonic-gate 	size_t			length;
15570Sstevel@tonic-gate 	usb_ep_descr_t		*eptd;
15580Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph;
15590Sstevel@tonic-gate 	int			i;
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
15640Sstevel@tonic-gate 	    "ohci_handle_root_hub_status_change: state = %d",
15650Sstevel@tonic-gate 	    ohcip->ohci_root_hub.rh_intr_pipe_state);
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate 	/* Get the pointer to root hub descriptor */
15680Sstevel@tonic-gate 	hub_descr = &ohcip->ohci_root_hub.rh_descr;
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	/* Get the current interrupt request pointer */
15710Sstevel@tonic-gate 	curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate 	/* Check whether timeout handler is valid */
15760Sstevel@tonic-gate 	if (ohcip->ohci_root_hub.rh_intr_pipe_timer_id) {
15770Sstevel@tonic-gate 		/* Check host controller is in operational state */
15780Sstevel@tonic-gate 		if ((ohci_state_is_operational(ohcip)) != USB_SUCCESS) {
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 			/* Reset the timer id */
15810Sstevel@tonic-gate 			ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 			/* Do interrupt pipe cleanup */
15840Sstevel@tonic-gate 			ohci_root_hub_intr_pipe_cleanup(
15850Sstevel@tonic-gate 			    ohcip, USB_CR_HC_HARDWARE_ERR);
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 			mutex_exit(&ohcip->ohci_int_mutex);
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 			return;
15900Sstevel@tonic-gate 		}
15910Sstevel@tonic-gate 	} else {
15920Sstevel@tonic-gate 		mutex_exit(&ohcip->ohci_int_mutex);
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 		return;
15950Sstevel@tonic-gate 	}
15960Sstevel@tonic-gate 
15970Sstevel@tonic-gate 	eptd = &ohcip->ohci_root_hub.rh_intr_pipe_handle->p_ep;
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate 	new_root_hub_status = Get_OpReg(hcr_rh_status);
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	/* See if the root hub status has changed */
16022326Ssl147100 	if (new_root_hub_status & HCR_RH_CHNG_MASK) {
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
16050Sstevel@tonic-gate 		    "ohci_handle_root_hub_status_change: "
16060Sstevel@tonic-gate 		    "Root hub status has changed!");
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 		all_ports_status = 1;
16092326Ssl147100 
16102326Ssl147100 		/* Update root hub status */
16112326Ssl147100 		ohcip->ohci_root_hub.rh_status = new_root_hub_status;
16120Sstevel@tonic-gate 	}
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 	/* Check each port */
16150Sstevel@tonic-gate 	for (i = 0; i < hub_descr->bNbrPorts; i++) {
16160Sstevel@tonic-gate 		new_port_status = Get_OpReg(hcr_rh_portstatus[i]);
16170Sstevel@tonic-gate 		change_status = new_port_status & HCR_PORT_CHNG_MASK;
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate 		/*
16200Sstevel@tonic-gate 		 * If there is change in the port status then set
16210Sstevel@tonic-gate 		 * the bit in the bitmap of changes and inform hub
16220Sstevel@tonic-gate 		 * driver about these changes. Hub driver will take
16230Sstevel@tonic-gate 		 * care of these changes.
16240Sstevel@tonic-gate 		 */
16250Sstevel@tonic-gate 		if (change_status) {
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 			/* See if a device was attached/detached */
16280Sstevel@tonic-gate 			if (change_status & HCR_PORT_CSC) {
16290Sstevel@tonic-gate 				/*
16300Sstevel@tonic-gate 				 * Update the state depending on whether
16310Sstevel@tonic-gate 				 * the port was attached or detached.
16320Sstevel@tonic-gate 				 */
16330Sstevel@tonic-gate 				if (new_port_status & HCR_PORT_CCS) {
16340Sstevel@tonic-gate 					ohcip->ohci_root_hub.
16350Sstevel@tonic-gate 					    rh_port_state[i] = DISABLED;
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
16380Sstevel@tonic-gate 					    ohcip->ohci_log_hdl,
1639520Shx149380 					    "Port %d connected", i+1);
16400Sstevel@tonic-gate 				} else {
16410Sstevel@tonic-gate 					ohcip->ohci_root_hub.
16420Sstevel@tonic-gate 					    rh_port_state[i] = DISCONNECTED;
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
16450Sstevel@tonic-gate 					    ohcip->ohci_log_hdl,
1646520Shx149380 					    "Port %d disconnected", i+1);
16470Sstevel@tonic-gate 				}
16480Sstevel@tonic-gate 			}
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate 			/* See if port enable status changed */
16510Sstevel@tonic-gate 			if (change_status & HCR_PORT_PESC) {
16520Sstevel@tonic-gate 				/*
16530Sstevel@tonic-gate 				 * Update the state depending on whether
16540Sstevel@tonic-gate 				 * the port was enabled or disabled.
16550Sstevel@tonic-gate 				 */
16560Sstevel@tonic-gate 				if (new_port_status & HCR_PORT_PES) {
16570Sstevel@tonic-gate 					ohcip->ohci_root_hub.
16580Sstevel@tonic-gate 					    rh_port_state[i] = ENABLED;
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
16610Sstevel@tonic-gate 					    ohcip->ohci_log_hdl,
1662520Shx149380 					    "Port %d enabled", i+1);
16630Sstevel@tonic-gate 				} else {
16640Sstevel@tonic-gate 					ohcip->ohci_root_hub.
16650Sstevel@tonic-gate 					    rh_port_state[i] = DISABLED;
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
16680Sstevel@tonic-gate 					    ohcip->ohci_log_hdl,
1669520Shx149380 					    "Port %d disabled", i+1);
16700Sstevel@tonic-gate 				}
16710Sstevel@tonic-gate 			}
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 			all_ports_status |= 1 << (i + 1);
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 			/* Update the status */
16760Sstevel@tonic-gate 			ohcip->ohci_root_hub.
16770Sstevel@tonic-gate 			    rh_port_status[i] = new_port_status;
16780Sstevel@tonic-gate 		}
16790Sstevel@tonic-gate 	}
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate 	if (ph && all_ports_status && curr_intr_reqp) {
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate 		length = eptd->wMaxPacketSize;
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 		ASSERT(length != 0);
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 		/* Get the  message block */
16880Sstevel@tonic-gate 		message = curr_intr_reqp->intr_data;
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 		ASSERT(message != NULL);
16910Sstevel@tonic-gate 
1692520Shx149380 		do {
1693520Shx149380 			/*
1694520Shx149380 			 * check that mblk is big enough when we
1695520Shx149380 			 * are writing bytes into it
1696520Shx149380 			 */
1697520Shx149380 			if (message->b_wptr >= message->b_datap->db_lim) {
1698520Shx149380 
1699520Shx149380 				USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
1700520Shx149380 				    ohcip->ohci_log_hdl,
1701520Shx149380 				    "ohci_handle_root_hub_status_change: "
1702520Shx149380 				    "mblk data overflow.");
1703520Shx149380 
1704520Shx149380 				break;
1705520Shx149380 			}
1706520Shx149380 
1707520Shx149380 			*message->b_wptr++ = (uchar_t)all_ports_status;
1708520Shx149380 			all_ports_status >>= 8;
1709520Shx149380 		} while (all_ports_status != 0);
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate 		ohci_root_hub_hcdi_callback(ph, USB_CR_OK);
17120Sstevel@tonic-gate 	}
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 	/* Reset the timer id */
17150Sstevel@tonic-gate 	ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	if (ohcip->ohci_root_hub.rh_intr_pipe_state == OHCI_PIPE_STATE_ACTIVE) {
17180Sstevel@tonic-gate 		/*
17190Sstevel@tonic-gate 		 * If needed, allocate new interrupt request. Also
17200Sstevel@tonic-gate 		 * start the timer for the root hub interrupt polling.
17210Sstevel@tonic-gate 		 */
17220Sstevel@tonic-gate 		if ((ohci_root_hub_allocate_intr_pipe_resource(
17230Sstevel@tonic-gate 		    ohcip, 0)) != USB_SUCCESS) {
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
17260Sstevel@tonic-gate 			    "ohci_handle_root_hub_status_change: No Resources");
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 			/* Do interrupt pipe cleanup */
17290Sstevel@tonic-gate 			ohci_root_hub_intr_pipe_cleanup(
17300Sstevel@tonic-gate 			    ohcip, USB_CR_NO_RESOURCES);
17310Sstevel@tonic-gate 		}
17320Sstevel@tonic-gate 	}
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate /*
17390Sstevel@tonic-gate  * ohci_root_hub_hcdi_callback()
17400Sstevel@tonic-gate  *
17410Sstevel@tonic-gate  * Convenience wrapper around usba_hcdi_cb() for the root hub.
17420Sstevel@tonic-gate  */
17430Sstevel@tonic-gate static void
ohci_root_hub_hcdi_callback(usba_pipe_handle_data_t * ph,usb_cr_t completion_reason)17440Sstevel@tonic-gate ohci_root_hub_hcdi_callback(
17450Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
17460Sstevel@tonic-gate 	usb_cr_t		completion_reason)
17470Sstevel@tonic-gate {
17480Sstevel@tonic-gate 	ohci_state_t		*ohcip = ohci_obtain_state(
1749*6898Sfb209375 	    ph->p_usba_device->usb_root_hub_dip);
17500Sstevel@tonic-gate 	uchar_t			attributes = ph->p_ep.bmAttributes &
1751*6898Sfb209375 	    USB_EP_ATTR_MASK;
17520Sstevel@tonic-gate 	usb_opaque_t		curr_xfer_reqp;
17530Sstevel@tonic-gate 	uint_t			pipe_state = 0;
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
17560Sstevel@tonic-gate 	    "ohci_root_hub_hcdi_callback: ph = 0x%p, cr = 0x%x",
1757*6898Sfb209375 	    (void *)ph, completion_reason);
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 	/* Set the pipe state as per completion reason */
17620Sstevel@tonic-gate 	switch (completion_reason) {
17630Sstevel@tonic-gate 	case USB_CR_OK:
17640Sstevel@tonic-gate 		switch (attributes) {
17650Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
17660Sstevel@tonic-gate 			pipe_state = OHCI_PIPE_STATE_IDLE;
17670Sstevel@tonic-gate 			break;
17680Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
17690Sstevel@tonic-gate 			pipe_state = ohcip->ohci_root_hub.rh_intr_pipe_state;
17700Sstevel@tonic-gate 			break;
17710Sstevel@tonic-gate 		}
17720Sstevel@tonic-gate 		break;
17730Sstevel@tonic-gate 	case USB_CR_NO_RESOURCES:
17740Sstevel@tonic-gate 	case USB_CR_NOT_SUPPORTED:
17750Sstevel@tonic-gate 	case USB_CR_STOPPED_POLLING:
17760Sstevel@tonic-gate 	case USB_CR_PIPE_RESET:
17770Sstevel@tonic-gate 	case USB_CR_HC_HARDWARE_ERR:
17780Sstevel@tonic-gate 		/* Set pipe state to idle */
17790Sstevel@tonic-gate 		pipe_state = OHCI_PIPE_STATE_IDLE;
17800Sstevel@tonic-gate 		break;
17810Sstevel@tonic-gate 	case USB_CR_PIPE_CLOSING:
17820Sstevel@tonic-gate 		break;
17830Sstevel@tonic-gate 	default:
17840Sstevel@tonic-gate 		/* Set pipe state to error */
17850Sstevel@tonic-gate 		pipe_state = OHCI_PIPE_STATE_ERROR;
17860Sstevel@tonic-gate 		break;
17870Sstevel@tonic-gate 	}
17880Sstevel@tonic-gate 
17890Sstevel@tonic-gate 	switch (attributes) {
17900Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
17910Sstevel@tonic-gate 		curr_xfer_reqp = (usb_opaque_t)
17920Sstevel@tonic-gate 		    ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_curr_ctrl_reqp = NULL;
17950Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_ctrl_pipe_state = pipe_state;
17960Sstevel@tonic-gate 		break;
17970Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
17980Sstevel@tonic-gate 		/* if curr_intr_reqp available then use this request */
17990Sstevel@tonic-gate 		if (ohcip->ohci_root_hub.rh_curr_intr_reqp) {
18000Sstevel@tonic-gate 			curr_xfer_reqp = (usb_opaque_t)
18010Sstevel@tonic-gate 			    ohcip->ohci_root_hub.rh_curr_intr_reqp;
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate 			ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
18040Sstevel@tonic-gate 		} else {
18050Sstevel@tonic-gate 			/* no current request, use client's request */
18060Sstevel@tonic-gate 			curr_xfer_reqp = (usb_opaque_t)
18070Sstevel@tonic-gate 			    ohcip->ohci_root_hub.rh_client_intr_reqp;
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 			ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
18100Sstevel@tonic-gate 		}
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate 		ohcip->ohci_root_hub.rh_intr_pipe_state = pipe_state;
18130Sstevel@tonic-gate 		break;
18140Sstevel@tonic-gate 	}
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate 	ASSERT(curr_xfer_reqp != NULL);
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate 	mutex_exit(&ohcip->ohci_int_mutex);
18190Sstevel@tonic-gate 	usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
18200Sstevel@tonic-gate 	mutex_enter(&ohcip->ohci_int_mutex);
18210Sstevel@tonic-gate }
1822