xref: /illumos-gate/usr/src/uts/common/io/usb/hcd/ehci/ehci.c (revision 6aef9e11)
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 /*
22269552cdSguoqing zhu - Sun Microsystems - Beijing China  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * EHCI Host Controller Driver (EHCI)
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * The EHCI driver is a software driver which interfaces to the Universal
317c478bd9Sstevel@tonic-gate  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
327c478bd9Sstevel@tonic-gate  * the Host Controller is defined by the EHCI Host Controller Interface.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * This file contains code for Auto-configuration and HCDI entry points.
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * NOTE:
377c478bd9Sstevel@tonic-gate  *
387c478bd9Sstevel@tonic-gate  * Currently EHCI driver does not support the following features
397c478bd9Sstevel@tonic-gate  *
407c478bd9Sstevel@tonic-gate  * - Alternate QTD for short xfer condition is only used in Bulk xfers.
417c478bd9Sstevel@tonic-gate  * - Frame Span Traversal Nodes (FSTN).
427c478bd9Sstevel@tonic-gate  * - Bandwidth allocation scheme needs to be updated for FSTN and USB2.0
437c478bd9Sstevel@tonic-gate  *   or High speed hub with multiple TT implementation. Currently bandwidth
447c478bd9Sstevel@tonic-gate  *   allocation scheme assumes one TT per USB2.0 or High speed hub.
457c478bd9Sstevel@tonic-gate  * - 64 bit addressing capability.
467c478bd9Sstevel@tonic-gate  * - Programmable periodic frame list size like 256, 512, 1024.
477c478bd9Sstevel@tonic-gate  *   It supports only 1024 periodic frame list size.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
517c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
527c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_intr.h>
537c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h>
547c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /* Pointer to the state structure */
577c478bd9Sstevel@tonic-gate void *ehci_statep;
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /* Number of instances */
607c478bd9Sstevel@tonic-gate #define	EHCI_INSTS	1
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /* Debugging information */
637c478bd9Sstevel@tonic-gate uint_t ehci_errmask	= (uint_t)PRINT_MASK_ALL;
647c478bd9Sstevel@tonic-gate uint_t ehci_errlevel	= USB_LOG_L2;
657c478bd9Sstevel@tonic-gate uint_t ehci_instance_debug = (uint_t)-1;
667c478bd9Sstevel@tonic-gate 
672df1fe9cSrandyf /*
682df1fe9cSrandyf  * Tunable to ensure host controller goes off even if a keyboard is attached.
692df1fe9cSrandyf  */
702df1fe9cSrandyf int force_ehci_off = 1;
712df1fe9cSrandyf 
727c478bd9Sstevel@tonic-gate /* Enable all workarounds for VIA VT62x2 */
737c478bd9Sstevel@tonic-gate uint_t ehci_vt62x2_workaround = EHCI_VIA_WORKAROUNDS;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate  * EHCI Auto-configuration entry points.
777c478bd9Sstevel@tonic-gate  *
787c478bd9Sstevel@tonic-gate  * Device operations (dev_ops) entries function prototypes.
797c478bd9Sstevel@tonic-gate  *
807c478bd9Sstevel@tonic-gate  * We use the hub cbops since all nexus ioctl operations defined so far will
817c478bd9Sstevel@tonic-gate  * be executed by the root hub. The following are the Host Controller Driver
827c478bd9Sstevel@tonic-gate  * (HCD) entry points.
837c478bd9Sstevel@tonic-gate  *
847c478bd9Sstevel@tonic-gate  * the open/close/ioctl functions call the corresponding usba_hubdi_*
857c478bd9Sstevel@tonic-gate  * calls after looking up the dip thru the dev_t.
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate static int	ehci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
887c478bd9Sstevel@tonic-gate static int	ehci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
897c478bd9Sstevel@tonic-gate static int	ehci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd);
907c478bd9Sstevel@tonic-gate static int	ehci_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
91*6aef9e11SToomas Soome     void *arg, void **result);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate static int	ehci_open(dev_t	*devp, int flags, int otyp, cred_t *credp);
947c478bd9Sstevel@tonic-gate static int	ehci_close(dev_t dev, int flag, int otyp, cred_t *credp);
957c478bd9Sstevel@tonic-gate static int	ehci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
967c478bd9Sstevel@tonic-gate     cred_t *credp, int *rvalp);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate int		usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level);
9919397407SSherry Moore static int	ehci_quiesce(dev_info_t *dip);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static struct cb_ops ehci_cb_ops = {
1027c478bd9Sstevel@tonic-gate 	ehci_open,			/* EHCI */
1037c478bd9Sstevel@tonic-gate 	ehci_close,			/* Close */
1047c478bd9Sstevel@tonic-gate 	nodev,				/* Strategy */
1057c478bd9Sstevel@tonic-gate 	nodev,				/* Print */
1067c478bd9Sstevel@tonic-gate 	nodev,				/* Dump */
1077c478bd9Sstevel@tonic-gate 	nodev,				/* Read */
1087c478bd9Sstevel@tonic-gate 	nodev,				/* Write */
1097c478bd9Sstevel@tonic-gate 	ehci_ioctl,			/* Ioctl */
1107c478bd9Sstevel@tonic-gate 	nodev,				/* Devmap */
1117c478bd9Sstevel@tonic-gate 	nodev,				/* Mmap */
1127c478bd9Sstevel@tonic-gate 	nodev,				/* Segmap */
1137c478bd9Sstevel@tonic-gate 	nochpoll,			/* Poll */
1147c478bd9Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
1157c478bd9Sstevel@tonic-gate 	NULL,				/* Streamtab */
1167c478bd9Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG	/* Driver compatibility flag */
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static struct dev_ops ehci_ops = {
1207c478bd9Sstevel@tonic-gate 	DEVO_REV,			/* Devo_rev */
1217c478bd9Sstevel@tonic-gate 	0,				/* Refcnt */
1227c478bd9Sstevel@tonic-gate 	ehci_info,			/* Info */
1237c478bd9Sstevel@tonic-gate 	nulldev,			/* Identify */
1247c478bd9Sstevel@tonic-gate 	nulldev,			/* Probe */
1257c478bd9Sstevel@tonic-gate 	ehci_attach,			/* Attach */
1267c478bd9Sstevel@tonic-gate 	ehci_detach,			/* Detach */
1277c478bd9Sstevel@tonic-gate 	ehci_reset,			/* Reset */
1287c478bd9Sstevel@tonic-gate 	&ehci_cb_ops,			/* Driver operations */
1297c478bd9Sstevel@tonic-gate 	&usba_hubdi_busops,		/* Bus operations */
13019397407SSherry Moore 	usba_hubdi_root_hub_power,	/* Power */
13119397407SSherry Moore 	ehci_quiesce			/* Quiesce */
1327c478bd9Sstevel@tonic-gate };
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate  * The USBA library must be loaded for this driver.
1367c478bd9Sstevel@tonic-gate  */
1377c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
138*6aef9e11SToomas Soome 	&mod_driverops,		/* Type of module. This one is a driver */
139*6aef9e11SToomas Soome 	"USB EHCI Driver",	/* Name of the module. */
1407c478bd9Sstevel@tonic-gate 	&ehci_ops,		/* Driver ops */
1417c478bd9Sstevel@tonic-gate };
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1447c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
1457c478bd9Sstevel@tonic-gate };
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate int
_init(void)1497c478bd9Sstevel@tonic-gate _init(void)
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate 	int error;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	/* Initialize the soft state structures */
1547c478bd9Sstevel@tonic-gate 	if ((error = ddi_soft_state_init(&ehci_statep, sizeof (ehci_state_t),
1557c478bd9Sstevel@tonic-gate 	    EHCI_INSTS)) != 0) {
1567c478bd9Sstevel@tonic-gate 		return (error);
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	/* Install the loadable module */
1607c478bd9Sstevel@tonic-gate 	if ((error = mod_install(&modlinkage)) != 0) {
1617c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&ehci_statep);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	return (error);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1697c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate int
_fini(void)1767c478bd9Sstevel@tonic-gate _fini(void)
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate 	int error;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if ((error = mod_remove(&modlinkage)) == 0) {
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 		/* Release per module resources */
1837c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&ehci_statep);
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	return (error);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate /*
1917c478bd9Sstevel@tonic-gate  * EHCI Auto configuration entry points.
1927c478bd9Sstevel@tonic-gate  */
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate /*
1957c478bd9Sstevel@tonic-gate  * ehci_attach:
1967c478bd9Sstevel@tonic-gate  *
1977c478bd9Sstevel@tonic-gate  * Description: Attach entry point is called by the Kernel.
1987c478bd9Sstevel@tonic-gate  *		Allocates resources for each EHCI host controller instance.
1997c478bd9Sstevel@tonic-gate  *		Initializes the EHCI Host Controller.
2007c478bd9Sstevel@tonic-gate  *
2017c478bd9Sstevel@tonic-gate  * Return     : DDI_SUCCESS / DDI_FAILURE.
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate static int
ehci_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)204*6aef9e11SToomas Soome ehci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	int			instance;
2077c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = NULL;
2087c478bd9Sstevel@tonic-gate 	usba_hcdi_register_args_t hcdi_args;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	switch (cmd) {
2117c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
2127c478bd9Sstevel@tonic-gate 		break;
2137c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
2147c478bd9Sstevel@tonic-gate 		ehcip = ehci_obtain_state(dip);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 		return (ehci_cpr_resume(ehcip));
2177c478bd9Sstevel@tonic-gate 	default:
2187c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/* Get the instance and create soft state */
2227c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(ehci_statep, instance) != 0) {
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	ehcip = ddi_get_soft_state(ehci_statep, instance);
2307c478bd9Sstevel@tonic-gate 	if (ehcip == NULL) {
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	ehcip->ehci_flags = EHCI_ATTACH;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	ehcip->ehci_log_hdl = usb_alloc_log_hdl(dip, "ehci", &ehci_errlevel,
2387c478bd9Sstevel@tonic-gate 	    &ehci_errmask, &ehci_instance_debug, 0);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	ehcip->ehci_flags |= EHCI_ZALLOC;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	/* Set host controller soft state to initialization */
2437c478bd9Sstevel@tonic-gate 	ehcip->ehci_hc_soft_state = EHCI_CTLR_INIT_STATE;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
2467c478bd9Sstevel@tonic-gate 	    "ehcip = 0x%p", (void *)ehcip);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	/* Save the dip and instance */
2497c478bd9Sstevel@tonic-gate 	ehcip->ehci_dip = dip;
2507c478bd9Sstevel@tonic-gate 	ehcip->ehci_instance = instance;
2517c478bd9Sstevel@tonic-gate 
2523ceb94daSbc 	/* Map the registers */
2533ceb94daSbc 	if (ehci_map_regs(ehcip) != DDI_SUCCESS) {
2543ceb94daSbc 		(void) ehci_cleanup(ehcip);
2553ceb94daSbc 
2563ceb94daSbc 		return (DDI_FAILURE);
2573ceb94daSbc 	}
2583ceb94daSbc 
2593ceb94daSbc 	/* Get the ehci chip vendor and device id */
2603ceb94daSbc 	ehcip->ehci_vendor_id = pci_config_get16(
2613ceb94daSbc 	    ehcip->ehci_config_handle, PCI_CONF_VENID);
2623ceb94daSbc 	ehcip->ehci_device_id = pci_config_get16(
2633ceb94daSbc 	    ehcip->ehci_config_handle, PCI_CONF_DEVID);
2643ceb94daSbc 	ehcip->ehci_rev_id = pci_config_get8(
2653ceb94daSbc 	    ehcip->ehci_config_handle, PCI_CONF_REVID);
2663ceb94daSbc 
2677c478bd9Sstevel@tonic-gate 	/* Initialize the DMA attributes */
2683ceb94daSbc 	ehci_set_dma_attributes(ehcip);
2693ceb94daSbc 
2703ceb94daSbc 	/* Initialize kstat structures */
2717c478bd9Sstevel@tonic-gate 	ehci_create_stats(ehcip);
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	/* Create the qtd and qh pools */
2747c478bd9Sstevel@tonic-gate 	if (ehci_allocate_pools(ehcip) != DDI_SUCCESS) {
2757c478bd9Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	/* Initialize the isochronous resources */
2817c478bd9Sstevel@tonic-gate 	if (ehci_isoc_init(ehcip) != DDI_SUCCESS) {
2827c478bd9Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	/* Register interrupts */
2887c478bd9Sstevel@tonic-gate 	if (ehci_register_intrs_and_init_mutex(ehcip) != DDI_SUCCESS) {
2897c478bd9Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2927c478bd9Sstevel@tonic-gate 	}
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	/* Initialize the controller */
2973b00f311Syq 	if (ehci_init_ctlr(ehcip, EHCI_NORMAL_INITIALIZATION) != DDI_SUCCESS) {
2987c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
2997c478bd9Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	/*
3057c478bd9Sstevel@tonic-gate 	 * At this point, the hardware will be okay.
3067c478bd9Sstevel@tonic-gate 	 * Initialize the usba_hcdi structure
3077c478bd9Sstevel@tonic-gate 	 */
3087c478bd9Sstevel@tonic-gate 	ehcip->ehci_hcdi_ops = ehci_alloc_hcdi_ops(ehcip);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	/*
3137c478bd9Sstevel@tonic-gate 	 * Make this HCD instance known to USBA
3147c478bd9Sstevel@tonic-gate 	 * (dma_attr must be passed for USBA busctl's)
3157c478bd9Sstevel@tonic-gate 	 */
3167c478bd9Sstevel@tonic-gate 	hcdi_args.usba_hcdi_register_version = HCDI_REGISTER_VERSION;
3177c478bd9Sstevel@tonic-gate 	hcdi_args.usba_hcdi_register_dip = dip;
3187c478bd9Sstevel@tonic-gate 	hcdi_args.usba_hcdi_register_ops = ehcip->ehci_hcdi_ops;
3197c478bd9Sstevel@tonic-gate 	hcdi_args.usba_hcdi_register_dma_attr = &ehcip->ehci_dma_attr;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/*
3227c478bd9Sstevel@tonic-gate 	 * Priority and iblock_cookie are one and the same
3237c478bd9Sstevel@tonic-gate 	 * (However, retaining hcdi_soft_iblock_cookie for now
3247c478bd9Sstevel@tonic-gate 	 * assigning it w/ priority. In future all iblock_cookie
3257c478bd9Sstevel@tonic-gate 	 * could just go)
3267c478bd9Sstevel@tonic-gate 	 */
3277c478bd9Sstevel@tonic-gate 	hcdi_args.usba_hcdi_register_iblock_cookie =
328abdbd06dSagiri 	    (ddi_iblock_cookie_t)(uintptr_t)ehcip->ehci_intr_pri;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if (usba_hcdi_register(&hcdi_args, 0) != DDI_SUCCESS) {
3317c478bd9Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	ehcip->ehci_flags |= EHCI_USBAREG;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	if ((ehci_init_root_hub(ehcip)) != USB_SUCCESS) {
3417c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
3427c478bd9Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3457c478bd9Sstevel@tonic-gate 	}
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	/* Finally load the root hub driver */
3507c478bd9Sstevel@tonic-gate 	if (ehci_load_root_hub_driver(ehcip) != USB_SUCCESS) {
3517c478bd9Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 	ehcip->ehci_flags |= EHCI_RHREG;
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	/* Display information in the banner */
3587c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	/* Reset the ehci initialization flag */
3637c478bd9Sstevel@tonic-gate 	ehcip->ehci_flags &= ~EHCI_ATTACH;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	/* Print the Host Control's Operational registers */
3667c478bd9Sstevel@tonic-gate 	ehci_print_caps(ehcip);
3677c478bd9Sstevel@tonic-gate 	ehci_print_regs(ehcip);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	(void) pci_report_pmcap(dip, PCI_PM_IDLESPEED, (void *)4000);
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3747c478bd9Sstevel@tonic-gate 	    "ehci_attach: dip = 0x%p done", (void *)dip);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate /*
3817c478bd9Sstevel@tonic-gate  * ehci_detach:
3827c478bd9Sstevel@tonic-gate  *
3837c478bd9Sstevel@tonic-gate  * Description: Detach entry point is called by the Kernel.
3847c478bd9Sstevel@tonic-gate  *		Deallocates all resource allocated.
3857c478bd9Sstevel@tonic-gate  *		Unregisters the interrupt handler.
3867c478bd9Sstevel@tonic-gate  *
3877c478bd9Sstevel@tonic-gate  * Return     : DDI_SUCCESS / DDI_FAILURE
3887c478bd9Sstevel@tonic-gate  */
3897c478bd9Sstevel@tonic-gate int
ehci_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)390*6aef9e11SToomas Soome ehci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(dip);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_detach:");
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	switch (cmd) {
3977c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 		return (ehci_cleanup(ehcip));
4007c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 		return (ehci_cpr_suspend(ehcip));
4037c478bd9Sstevel@tonic-gate 	default:
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /*
4107c478bd9Sstevel@tonic-gate  * ehci_reset:
4117c478bd9Sstevel@tonic-gate  *
4127c478bd9Sstevel@tonic-gate  * Description:	Reset entry point - called by the Kernel
4137c478bd9Sstevel@tonic-gate  *		on the way down.
4147c478bd9Sstevel@tonic-gate  *		Toshiba Tecra laptop has been observed to hang
4157c478bd9Sstevel@tonic-gate  *		on soft reboot. The resetting ehci on the way
4167c478bd9Sstevel@tonic-gate  *		down solves the problem.
4177c478bd9Sstevel@tonic-gate  *
4187c478bd9Sstevel@tonic-gate  * Return	: DDI_SUCCESS / DDI_FAILURE
4197c478bd9Sstevel@tonic-gate  */
4207c478bd9Sstevel@tonic-gate /* ARGSUSED */
4217c478bd9Sstevel@tonic-gate static int
ehci_reset(dev_info_t * dip,ddi_reset_cmd_t cmd)4227c478bd9Sstevel@tonic-gate ehci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
4237c478bd9Sstevel@tonic-gate {
4246c7181fcSsl #if defined(__sparc)
4256c7181fcSsl 	/*
4266c7181fcSsl 	 * Don't reset the host controller on SPARC, for OBP needs Solaris
4276c7181fcSsl 	 * to continue to provide keyboard support after shutdown of SPARC,
4286c7181fcSsl 	 * or the keyboard connected to a USB 2.0 port will not work after
4296c7181fcSsl 	 * that. The incomplete reset problem on Toshiba Tecra laptop is
4306c7181fcSsl 	 * specific to Tecra laptop or BIOS, not present on SPARC. The SPARC
4316c7181fcSsl 	 * OBP guarantees good reset behavior during startup.
4326c7181fcSsl 	 */
4336c7181fcSsl 	return (DDI_SUCCESS);
4346c7181fcSsl #else
4357c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(dip);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	/*
4407c478bd9Sstevel@tonic-gate 	 * To reset the host controller, the HCRESET bit should be set to one.
4417c478bd9Sstevel@tonic-gate 	 * Software should not set this bit to a one when the HCHalted bit in
4427c478bd9Sstevel@tonic-gate 	 * the USBSTS register is a zero. Attempting to reset an actively
4437c478bd9Sstevel@tonic-gate 	 * running host controller will result in undefined behavior.
4447c478bd9Sstevel@tonic-gate 	 * see EHCI SPEC. for more information.
4457c478bd9Sstevel@tonic-gate 	 */
4467c478bd9Sstevel@tonic-gate 	if (!(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 		/* Stop the EHCI host controller */
4497c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command,
4507c478bd9Sstevel@tonic-gate 		    Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
4517c478bd9Sstevel@tonic-gate 		/*
4527c478bd9Sstevel@tonic-gate 		 * When this bit is set to 0, the Host Controller completes the
4537c478bd9Sstevel@tonic-gate 		 * current and any actively pipelined transactions on the USB
4547c478bd9Sstevel@tonic-gate 		 * and then halts. The Host Controller must halt within 16
4557c478bd9Sstevel@tonic-gate 		 * micro-frames after software clears the Run bit.
4567c478bd9Sstevel@tonic-gate 		 * The HC Halted bit in the status register indicates when the
4577c478bd9Sstevel@tonic-gate 		 * Host Controller has finished its pending pipelined
4587c478bd9Sstevel@tonic-gate 		 * transactions and has entered the stopped state.
4597c478bd9Sstevel@tonic-gate 		 */
4607c478bd9Sstevel@tonic-gate 		drv_usecwait(EHCI_RESET_TIMEWAIT);
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	/* Reset the EHCI host controller */
4647c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command,
4657c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET);
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4706c7181fcSsl #endif
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate 
47319397407SSherry Moore /*
47419397407SSherry Moore  * quiesce(9E) entry point.
47519397407SSherry Moore  *
47619397407SSherry Moore  * This function is called when the system is single-threaded at high
47719397407SSherry Moore  * PIL with preemption disabled. Therefore, this function must not be
47819397407SSherry Moore  * blocked.
47919397407SSherry Moore  *
48019397407SSherry Moore  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
48119397407SSherry Moore  * DDI_FAILURE indicates an error condition and should almost never happen.
48219397407SSherry Moore  */
48319397407SSherry Moore static int
ehci_quiesce(dev_info_t * dip)48419397407SSherry Moore ehci_quiesce(dev_info_t *dip)
48519397407SSherry Moore {
48619397407SSherry Moore 	ehci_state_t		*ehcip = ehci_obtain_state(dip);
48719397407SSherry Moore 
48819397407SSherry Moore 	if (ehcip == NULL)
48919397407SSherry Moore 		return (DDI_FAILURE);
49019397407SSherry Moore 
49134c852b0Szhigang lu - Sun Microsystems - Beijing China #ifndef lint
49234c852b0Szhigang lu - Sun Microsystems - Beijing China 	_NOTE(NO_COMPETING_THREADS_NOW);
49334c852b0Szhigang lu - Sun Microsystems - Beijing China #endif
49419397407SSherry Moore 	/*
49519397407SSherry Moore 	 * To reset the host controller, the HCRESET bit should be set to one.
49619397407SSherry Moore 	 * Software should not set this bit to a one when the HCHalted bit in
49719397407SSherry Moore 	 * the USBSTS register is a zero. Attempting to reset an actively
49819397407SSherry Moore 	 * running host controller will result in undefined behavior.
49919397407SSherry Moore 	 * see EHCI SPEC. for more information.
50019397407SSherry Moore 	 */
50119397407SSherry Moore 	if (!(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
50219397407SSherry Moore 
50319397407SSherry Moore 		/* Stop the EHCI host controller */
50419397407SSherry Moore 		Set_OpReg(ehci_command,
50519397407SSherry Moore 		    Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
50619397407SSherry Moore 		/*
50719397407SSherry Moore 		 * When this bit is set to 0, the Host Controller completes the
50819397407SSherry Moore 		 * current and any actively pipelined transactions on the USB
50919397407SSherry Moore 		 * and then halts. The Host Controller must halt within 16
51019397407SSherry Moore 		 * micro-frames after software clears the Run bit.
51119397407SSherry Moore 		 * The HC Halted bit in the status register indicates when the
51219397407SSherry Moore 		 * Host Controller has finished its pending pipelined
51319397407SSherry Moore 		 * transactions and has entered the stopped state.
51419397407SSherry Moore 		 */
51519397407SSherry Moore 		drv_usecwait(EHCI_RESET_TIMEWAIT);
51619397407SSherry Moore 	}
51719397407SSherry Moore 
51819397407SSherry Moore 	/* Reset the EHCI host controller */
51919397407SSherry Moore 	Set_OpReg(ehci_command,
52019397407SSherry Moore 	    Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET);
52119397407SSherry Moore 
52234c852b0Szhigang lu - Sun Microsystems - Beijing China #ifndef lint
52334c852b0Szhigang lu - Sun Microsystems - Beijing China 	_NOTE(COMPETING_THREADS_NOW);
52434c852b0Szhigang lu - Sun Microsystems - Beijing China #endif
52519397407SSherry Moore 	return (DDI_SUCCESS);
52619397407SSherry Moore }
52719397407SSherry Moore 
52819397407SSherry Moore 
5297c478bd9Sstevel@tonic-gate /*
5307c478bd9Sstevel@tonic-gate  * ehci_info:
5317c478bd9Sstevel@tonic-gate  */
5327c478bd9Sstevel@tonic-gate /* ARGSUSED */
5337c478bd9Sstevel@tonic-gate static int
ehci_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)534*6aef9e11SToomas Soome ehci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate 	dev_t			dev;
5377c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip;
5387c478bd9Sstevel@tonic-gate 	int			instance;
5397c478bd9Sstevel@tonic-gate 	int			error = DDI_FAILURE;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	switch (infocmd) {
5427c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
5437c478bd9Sstevel@tonic-gate 		dev = (dev_t)arg;
5447c478bd9Sstevel@tonic-gate 		instance = EHCI_UNIT(dev);
5457c478bd9Sstevel@tonic-gate 		ehcip = ddi_get_soft_state(ehci_statep, instance);
5467c478bd9Sstevel@tonic-gate 		if (ehcip != NULL) {
5477c478bd9Sstevel@tonic-gate 			*result = (void *)ehcip->ehci_dip;
5487c478bd9Sstevel@tonic-gate 			if (*result != NULL) {
5497c478bd9Sstevel@tonic-gate 				error = DDI_SUCCESS;
5507c478bd9Sstevel@tonic-gate 			}
5517c478bd9Sstevel@tonic-gate 		} else {
5527c478bd9Sstevel@tonic-gate 			*result = NULL;
5537c478bd9Sstevel@tonic-gate 		}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 		break;
5567c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
5577c478bd9Sstevel@tonic-gate 		dev = (dev_t)arg;
5587c478bd9Sstevel@tonic-gate 		instance = EHCI_UNIT(dev);
5597c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
5607c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
5617c478bd9Sstevel@tonic-gate 		break;
5627c478bd9Sstevel@tonic-gate 	default:
5637c478bd9Sstevel@tonic-gate 		break;
5647c478bd9Sstevel@tonic-gate 	}
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	return (error);
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate /*
5717c478bd9Sstevel@tonic-gate  * EHCI CB_OPS entry points.
5727c478bd9Sstevel@tonic-gate  */
5737c478bd9Sstevel@tonic-gate static dev_info_t *
ehci_get_dip(dev_t dev)574*6aef9e11SToomas Soome ehci_get_dip(dev_t dev)
5757c478bd9Sstevel@tonic-gate {
5767c478bd9Sstevel@tonic-gate 	int		instance = EHCI_UNIT(dev);
5777c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip = ddi_get_soft_state(ehci_statep, instance);
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	if (ehcip) {
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 		return (ehcip->ehci_dip);
5827c478bd9Sstevel@tonic-gate 	} else {
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 		return (NULL);
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate static int
ehci_open(dev_t * devp,int flags,int otyp,cred_t * credp)590*6aef9e11SToomas Soome ehci_open(dev_t *devp, int flags, int otyp, cred_t *credp)
5917c478bd9Sstevel@tonic-gate {
5927c478bd9Sstevel@tonic-gate 	dev_info_t	*dip = ehci_get_dip(*devp);
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	return (usba_hubdi_open(dip, devp, flags, otyp, credp));
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate static int
ehci_close(dev_t dev,int flag,int otyp,cred_t * credp)599*6aef9e11SToomas Soome ehci_close(dev_t dev, int flag, int otyp, cred_t *credp)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate 	dev_info_t	*dip = ehci_get_dip(dev);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	return (usba_hubdi_close(dip, dev, flag, otyp, credp));
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate static int
ehci_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)608*6aef9e11SToomas Soome ehci_ioctl(dev_t dev, int cmd, intptr_t	arg, int mode, cred_t *credp,
609*6aef9e11SToomas Soome     int *rvalp)
6107c478bd9Sstevel@tonic-gate {
6117c478bd9Sstevel@tonic-gate 	dev_info_t	*dip = ehci_get_dip(dev);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	return (usba_hubdi_ioctl(dip,
6147c478bd9Sstevel@tonic-gate 	    dev, cmd, arg, mode, credp, rvalp));
6157c478bd9Sstevel@tonic-gate }
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate /*
6187c478bd9Sstevel@tonic-gate  * EHCI Interrupt Handler entry point.
6197c478bd9Sstevel@tonic-gate  */
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate /*
6227c478bd9Sstevel@tonic-gate  * ehci_intr:
6237c478bd9Sstevel@tonic-gate  *
6247c478bd9Sstevel@tonic-gate  * EHCI (EHCI) interrupt handling routine.
6257c478bd9Sstevel@tonic-gate  */
6267c478bd9Sstevel@tonic-gate uint_t
ehci_intr(caddr_t arg1,caddr_t arg2)6279c75c6bfSgovinda ehci_intr(caddr_t arg1, caddr_t arg2)
6287c478bd9Sstevel@tonic-gate {
6297c478bd9Sstevel@tonic-gate 	uint_t			intr;
630d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	ehci_state_t		*ehcip = (void *)arg1;
6317c478bd9Sstevel@tonic-gate 
632b3001defSlg 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
633112116d8Sfb 	    "ehci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p",
634112116d8Sfb 	    (void *)arg1, (void *)arg2);
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	/* Get the ehci global mutex */
6377c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
6387c478bd9Sstevel@tonic-gate 
639fffe0b30Sqz 	/* Any interrupt is not handled for the suspended device. */
640fffe0b30Sqz 	if (ehcip->ehci_hc_soft_state == EHCI_CTLR_SUSPEND_STATE) {
641fffe0b30Sqz 		mutex_exit(&ehcip->ehci_int_mutex);
642fffe0b30Sqz 
643fffe0b30Sqz 		return (DDI_INTR_UNCLAIMED);
644fffe0b30Sqz 	}
645fffe0b30Sqz 
6467c478bd9Sstevel@tonic-gate 	/*
6477c478bd9Sstevel@tonic-gate 	 * Now process the actual ehci interrupt events  that caused
6487c478bd9Sstevel@tonic-gate 	 * invocation of this ehci interrupt handler.
6497c478bd9Sstevel@tonic-gate 	 */
6507c478bd9Sstevel@tonic-gate 	intr = (Get_OpReg(ehci_status) & Get_OpReg(ehci_interrupt));
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/* Update kstat values */
6537c478bd9Sstevel@tonic-gate 	ehci_do_intrs_stats(ehcip, intr);
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	/*
6567c478bd9Sstevel@tonic-gate 	 * We could have gotten a spurious interrupts. If so, do not
6577c478bd9Sstevel@tonic-gate 	 * claim it.  This is quite  possible on some  architectures
6587c478bd9Sstevel@tonic-gate 	 * where more than one PCI slots share the IRQs.  If so, the
6597c478bd9Sstevel@tonic-gate 	 * associated driver's interrupt routine may get called even
6607c478bd9Sstevel@tonic-gate 	 * if the interrupt is not meant for them.
6617c478bd9Sstevel@tonic-gate 	 *
6627c478bd9Sstevel@tonic-gate 	 * By unclaiming the interrupt, the other driver gets chance
6637c478bd9Sstevel@tonic-gate 	 * to service its interrupt.
6647c478bd9Sstevel@tonic-gate 	 */
6657c478bd9Sstevel@tonic-gate 	if (!intr) {
6667c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	/* Acknowledge the interrupt */
6727c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_status, intr);
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_hc_soft_state == EHCI_CTLR_ERROR_STATE) {
6757c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 		return (DDI_INTR_CLAIMED);
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
6817c478bd9Sstevel@tonic-gate 	    "Interrupt status 0x%x", intr);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	/*
6847c478bd9Sstevel@tonic-gate 	 * If necessary broadcast that an interrupt has occured.  This
6857c478bd9Sstevel@tonic-gate 	 * is only necessary during controller init.
6867c478bd9Sstevel@tonic-gate 	 */
6877c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_flags & EHCI_CV_INTR) {
6887c478bd9Sstevel@tonic-gate 		ehcip->ehci_flags &= ~EHCI_CV_INTR;
6897c478bd9Sstevel@tonic-gate 		cv_broadcast(&ehcip->ehci_async_schedule_advance_cv);
6907c478bd9Sstevel@tonic-gate 	}
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	/* Check for Frame List Rollover */
6937c478bd9Sstevel@tonic-gate 	if (intr & EHCI_INTR_FRAME_LIST_ROLLOVER) {
6943b00f311Syq 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
6957c478bd9Sstevel@tonic-gate 		    "ehci_intr: Frame List Rollover");
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 		ehci_handle_frame_list_rollover(ehcip);
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 		/* VIA VT6202 looses EHCI_INTR_USB interrupts, workaround. */
7007c478bd9Sstevel@tonic-gate 		if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) &&
7017c478bd9Sstevel@tonic-gate 		    (ehci_vt62x2_workaround & EHCI_VIA_LOST_INTERRUPTS)) {
7027c478bd9Sstevel@tonic-gate 			ehcip->ehci_missed_intr_sts |= EHCI_INTR_USB;
7037c478bd9Sstevel@tonic-gate 		}
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	/* Check for Advance on Asynchronous Schedule */
7077c478bd9Sstevel@tonic-gate 	if (intr & EHCI_INTR_ASYNC_ADVANCE) {
7087c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
7097c478bd9Sstevel@tonic-gate 		    "ehci_intr: Asynchronous Schedule Advance Notification");
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 		/* Disable async list advance interrupt */
7127c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_interrupt,
7137c478bd9Sstevel@tonic-gate 		    (Get_OpReg(ehci_interrupt) & ~EHCI_INTR_ASYNC_ADVANCE));
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 		/*
7167c478bd9Sstevel@tonic-gate 		 * Call cv_broadcast on every this interrupt to wakeup
7177c478bd9Sstevel@tonic-gate 		 * all the threads that are waiting the async list advance
7187c478bd9Sstevel@tonic-gate 		 * event.
7197c478bd9Sstevel@tonic-gate 		 */
7207c478bd9Sstevel@tonic-gate 		cv_broadcast(&ehcip->ehci_async_schedule_advance_cv);
7217c478bd9Sstevel@tonic-gate 	}
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	/* Always process completed itds */
7247c478bd9Sstevel@tonic-gate 	ehci_traverse_active_isoc_list(ehcip);
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	/*
7277c478bd9Sstevel@tonic-gate 	 * Check for any USB transaction completion notification. Also
7287c478bd9Sstevel@tonic-gate 	 * process any missed USB transaction completion interrupts.
7297c478bd9Sstevel@tonic-gate 	 */
7307c478bd9Sstevel@tonic-gate 	if ((intr & EHCI_INTR_USB) || (intr & EHCI_INTR_USB_ERROR) ||
7317c478bd9Sstevel@tonic-gate 	    (ehcip->ehci_missed_intr_sts & EHCI_INTR_USB) ||
7327c478bd9Sstevel@tonic-gate 	    (ehcip->ehci_missed_intr_sts & EHCI_INTR_USB_ERROR)) {
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
7357c478bd9Sstevel@tonic-gate 		    "ehci_intr: USB Transaction Completion Notification");
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 		/* Clear missed interrupts */
7387c478bd9Sstevel@tonic-gate 		if (ehcip->ehci_missed_intr_sts) {
7397c478bd9Sstevel@tonic-gate 			ehcip->ehci_missed_intr_sts = 0;
7407c478bd9Sstevel@tonic-gate 		}
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 		/* Process completed qtds */
7437c478bd9Sstevel@tonic-gate 		ehci_traverse_active_qtd_list(ehcip);
7447c478bd9Sstevel@tonic-gate 	}
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	/* Process endpoint reclamation list */
7477c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_reclaim_list) {
7487c478bd9Sstevel@tonic-gate 		ehci_handle_endpoint_reclaimation(ehcip);
7497c478bd9Sstevel@tonic-gate 	}
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	/* Check for Host System Error */
7527c478bd9Sstevel@tonic-gate 	if (intr & EHCI_INTR_HOST_SYSTEM_ERROR) {
7537c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
7547c478bd9Sstevel@tonic-gate 		    "ehci_intr: Unrecoverable error");
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 		ehci_handle_ue(ehcip);
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	/*
7607c478bd9Sstevel@tonic-gate 	 * Read interrupt status register to make sure that any PIO
7617c478bd9Sstevel@tonic-gate 	 * store to clear the ISR has made it on the PCI bus before
7627c478bd9Sstevel@tonic-gate 	 * returning from its interrupt handler.
7637c478bd9Sstevel@tonic-gate 	 */
7647c478bd9Sstevel@tonic-gate 	(void) Get_OpReg(ehci_status);
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	/* Release the ehci global mutex */
7677c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
7687c478bd9Sstevel@tonic-gate 
769b3001defSlg 	USB_DPRINTF_L4(PRINT_MASK_INTR,  ehcip->ehci_log_hdl,
7707c478bd9Sstevel@tonic-gate 	    "Interrupt handling completed");
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate /*
7777c478bd9Sstevel@tonic-gate  * EHCI HCDI entry points
7787c478bd9Sstevel@tonic-gate  *
7797c478bd9Sstevel@tonic-gate  * The Host Controller Driver Interfaces (HCDI) are the software interfaces
7807c478bd9Sstevel@tonic-gate  * between the Universal Serial Bus Layer (USBA) and the Host Controller
7817c478bd9Sstevel@tonic-gate  * Driver (HCD). The HCDI interfaces or entry points are subject to change.
7827c478bd9Sstevel@tonic-gate  */
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate /*
7857c478bd9Sstevel@tonic-gate  * ehci_hcdi_pipe_open:
7867c478bd9Sstevel@tonic-gate  *
7877c478bd9Sstevel@tonic-gate  * Member of HCD Ops structure and called during client specific pipe open
7887c478bd9Sstevel@tonic-gate  * Add the pipe to the data structure representing the device and allocate
7897c478bd9Sstevel@tonic-gate  * bandwidth for the pipe if it is a interrupt or isochronous endpoint.
7907c478bd9Sstevel@tonic-gate  */
7917c478bd9Sstevel@tonic-gate int
ehci_hcdi_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t flags)7927c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_open(
7937c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
7947c478bd9Sstevel@tonic-gate 	usb_flags_t		flags)
7957c478bd9Sstevel@tonic-gate {
7967c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
797fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
7987c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*epdt = &ph->p_ep;
7997c478bd9Sstevel@tonic-gate 	int			rval, error = USB_SUCCESS;
8007c478bd9Sstevel@tonic-gate 	int			kmflag = (flags & USB_FLAGS_SLEEP) ?
801fffe0b30Sqz 	    KM_SLEEP : KM_NOSLEEP;
8027c478bd9Sstevel@tonic-gate 	uchar_t			smask = 0;
8037c478bd9Sstevel@tonic-gate 	uchar_t			cmask = 0;
8047c478bd9Sstevel@tonic-gate 	uint_t			pnode = 0;
8057c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
8087c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_pipe_open: addr = 0x%x, ep%d",
8097c478bd9Sstevel@tonic-gate 	    ph->p_usba_device->usb_addr,
8107c478bd9Sstevel@tonic-gate 	    epdt->bEndpointAddress & USB_EP_NUM_MASK);
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
8137c478bd9Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
8147c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 		return (rval);
8197c478bd9Sstevel@tonic-gate 	}
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	/*
8227c478bd9Sstevel@tonic-gate 	 * Check and handle root hub pipe open.
8237c478bd9Sstevel@tonic-gate 	 */
8247c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 		mutex_enter(&ehcip->ehci_int_mutex);
8277c478bd9Sstevel@tonic-gate 		error = ehci_handle_root_hub_pipe_open(ph, flags);
8287c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 		return (error);
8317c478bd9Sstevel@tonic-gate 	}
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	/*
8347c478bd9Sstevel@tonic-gate 	 * Opening of other pipes excluding root hub pipe are
8357c478bd9Sstevel@tonic-gate 	 * handled below. Check whether pipe is already opened.
8367c478bd9Sstevel@tonic-gate 	 */
8377c478bd9Sstevel@tonic-gate 	if (ph->p_hcd_private) {
8387c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
8397c478bd9Sstevel@tonic-gate 		    "ehci_hcdi_pipe_open: Pipe is already opened");
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
8427c478bd9Sstevel@tonic-gate 	}
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	/*
8457c478bd9Sstevel@tonic-gate 	 * A portion of the bandwidth is reserved for the non-periodic
8467c478bd9Sstevel@tonic-gate 	 * transfers, i.e control and bulk transfers in each of one
8477c478bd9Sstevel@tonic-gate 	 * millisecond frame period & usually it will be 20% of frame
8487c478bd9Sstevel@tonic-gate 	 * period. Hence there is no need to check for the available
8497c478bd9Sstevel@tonic-gate 	 * bandwidth before adding the control or bulk endpoints.
8507c478bd9Sstevel@tonic-gate 	 *
8517c478bd9Sstevel@tonic-gate 	 * There is a need to check for the available bandwidth before
8527c478bd9Sstevel@tonic-gate 	 * adding the periodic transfers, i.e interrupt & isochronous,
8537c478bd9Sstevel@tonic-gate 	 * since all these periodic transfers are guaranteed transfers.
8547c478bd9Sstevel@tonic-gate 	 * Usually 80% of the total frame time is reserved for periodic
8557c478bd9Sstevel@tonic-gate 	 * transfers.
8567c478bd9Sstevel@tonic-gate 	 */
8577c478bd9Sstevel@tonic-gate 	if (EHCI_PERIODIC_ENDPOINT(epdt)) {
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 		mutex_enter(&ehcip->ehci_int_mutex);
8607c478bd9Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 		error = ehci_allocate_bandwidth(ehcip,
8637c478bd9Sstevel@tonic-gate 		    ph, &pnode, &smask, &cmask);
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 		if (error != USB_SUCCESS) {
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
8687c478bd9Sstevel@tonic-gate 			    "ehci_hcdi_pipe_open: Bandwidth allocation failed");
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 			mutex_exit(&ph->p_mutex);
8717c478bd9Sstevel@tonic-gate 			mutex_exit(&ehcip->ehci_int_mutex);
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 			return (error);
8747c478bd9Sstevel@tonic-gate 		}
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
8777c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
8787c478bd9Sstevel@tonic-gate 	}
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	/* Create the HCD pipe private structure */
8817c478bd9Sstevel@tonic-gate 	pp = kmem_zalloc(sizeof (ehci_pipe_private_t), kmflag);
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	/*
8847c478bd9Sstevel@tonic-gate 	 * Return failure if ehci pipe private
8857c478bd9Sstevel@tonic-gate 	 * structure allocation fails.
8867c478bd9Sstevel@tonic-gate 	 */
8877c478bd9Sstevel@tonic-gate 	if (pp == NULL) {
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 		mutex_enter(&ehcip->ehci_int_mutex);
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 		/* Deallocate bandwidth */
8927c478bd9Sstevel@tonic-gate 		if (EHCI_PERIODIC_ENDPOINT(epdt)) {
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 			mutex_enter(&ph->p_mutex);
8957c478bd9Sstevel@tonic-gate 			ehci_deallocate_bandwidth(ehcip,
8967c478bd9Sstevel@tonic-gate 			    ph, pnode, smask, cmask);
8977c478bd9Sstevel@tonic-gate 			mutex_exit(&ph->p_mutex);
8987c478bd9Sstevel@tonic-gate 		}
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
9037c478bd9Sstevel@tonic-gate 	}
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	/* Save periodic nodes */
9087c478bd9Sstevel@tonic-gate 	pp->pp_pnode = pnode;
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	/* Save start and complete split mask values */
9117c478bd9Sstevel@tonic-gate 	pp->pp_smask = smask;
9127c478bd9Sstevel@tonic-gate 	pp->pp_cmask = cmask;
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	/* Create prototype for xfer completion condition variable */
9157c478bd9Sstevel@tonic-gate 	cv_init(&pp->pp_xfer_cmpl_cv, NULL, CV_DRIVER, NULL);
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	/* Set the state of pipe as idle */
9187c478bd9Sstevel@tonic-gate 	pp->pp_state = EHCI_PIPE_STATE_IDLE;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	/* Store a pointer to the pipe handle */
9217c478bd9Sstevel@tonic-gate 	pp->pp_pipe_handle = ph;
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	/* Store the pointer in the pipe handle */
9267c478bd9Sstevel@tonic-gate 	ph->p_hcd_private = (usb_opaque_t)pp;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	/* Store a copy of the pipe policy */
9297c478bd9Sstevel@tonic-gate 	bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t));
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	/* Allocate the host controller endpoint descriptor */
934*6aef9e11SToomas Soome 	pp->pp_qh = ehci_alloc_qh(ehcip, ph, EHCI_INTERRUPT_MODE_FLAG);
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 	/* Initialize the halting flag */
9377c478bd9Sstevel@tonic-gate 	pp->pp_halt_state = EHCI_HALT_STATE_FREE;
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	/* Create prototype for halt completion condition variable */
9407c478bd9Sstevel@tonic-gate 	cv_init(&pp->pp_halt_cmpl_cv, NULL, CV_DRIVER, NULL);
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	/* Isoch does not use QH, so ignore this */
9437c478bd9Sstevel@tonic-gate 	if ((pp->pp_qh == NULL) && !(EHCI_ISOC_ENDPOINT(epdt))) {
9447c478bd9Sstevel@tonic-gate 		ASSERT(pp->pp_qh == NULL);
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
9477c478bd9Sstevel@tonic-gate 		    "ehci_hcdi_pipe_open: QH allocation failed");
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 		/* Deallocate bandwidth */
9527c478bd9Sstevel@tonic-gate 		if (EHCI_PERIODIC_ENDPOINT(epdt)) {
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 			ehci_deallocate_bandwidth(ehcip,
9557c478bd9Sstevel@tonic-gate 			    ph, pnode, smask, cmask);
9567c478bd9Sstevel@tonic-gate 		}
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 		/* Destroy the xfer completion condition variable */
9597c478bd9Sstevel@tonic-gate 		cv_destroy(&pp->pp_xfer_cmpl_cv);
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 		/*
9627c478bd9Sstevel@tonic-gate 		 * Deallocate the hcd private portion
9637c478bd9Sstevel@tonic-gate 		 * of the pipe handle.
9647c478bd9Sstevel@tonic-gate 		 */
9657c478bd9Sstevel@tonic-gate 		kmem_free(ph->p_hcd_private, sizeof (ehci_pipe_private_t));
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 		/*
9687c478bd9Sstevel@tonic-gate 		 * Set the private structure in the
9697c478bd9Sstevel@tonic-gate 		 * pipe handle equal to NULL.
9707c478bd9Sstevel@tonic-gate 		 */
9717c478bd9Sstevel@tonic-gate 		ph->p_hcd_private = NULL;
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
9747c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
9777c478bd9Sstevel@tonic-gate 	}
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	/*
9807c478bd9Sstevel@tonic-gate 	 * Isoch does not use QH so no need to
9817c478bd9Sstevel@tonic-gate 	 * restore data toggle or insert QH
9827c478bd9Sstevel@tonic-gate 	 */
9837c478bd9Sstevel@tonic-gate 	if (!(EHCI_ISOC_ENDPOINT(epdt))) {
9847c478bd9Sstevel@tonic-gate 		/* Restore the data toggle information */
9857c478bd9Sstevel@tonic-gate 		ehci_restore_data_toggle(ehcip, ph);
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	/*
9897c478bd9Sstevel@tonic-gate 	 * Insert the endpoint onto the host controller's
9907c478bd9Sstevel@tonic-gate 	 * appropriate endpoint list. The host controller
9917c478bd9Sstevel@tonic-gate 	 * will not schedule this endpoint and will not have
9927c478bd9Sstevel@tonic-gate 	 * any QTD's to process.  It will also update the pipe count.
9937c478bd9Sstevel@tonic-gate 	 */
9947c478bd9Sstevel@tonic-gate 	ehci_insert_qh(ehcip, ph);
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
9977c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_pipe_open: ph = 0x%p", (void *)ph);
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	ehcip->ehci_open_pipe_count++;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate /*
10087c478bd9Sstevel@tonic-gate  * ehci_hcdi_pipe_close:
10097c478bd9Sstevel@tonic-gate  *
10107c478bd9Sstevel@tonic-gate  * Member of HCD Ops structure and called during the client  specific pipe
10117c478bd9Sstevel@tonic-gate  * close. Remove the pipe and the data structure representing the device.
10127c478bd9Sstevel@tonic-gate  * Deallocate  bandwidth for the pipe if it is a interrupt or isochronous
10137c478bd9Sstevel@tonic-gate  * endpoint.
10147c478bd9Sstevel@tonic-gate  */
10157c478bd9Sstevel@tonic-gate /* ARGSUSED */
10167c478bd9Sstevel@tonic-gate int
ehci_hcdi_pipe_close(usba_pipe_handle_data_t * ph,usb_flags_t flags)10177c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_close(
10187c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
10197c478bd9Sstevel@tonic-gate 	usb_flags_t		flags)
10207c478bd9Sstevel@tonic-gate {
10217c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
1022fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
10237c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
10247c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
10257c478bd9Sstevel@tonic-gate 	int			error = USB_SUCCESS;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
10287c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_pipe_close: addr = 0x%x, ep%d",
10297c478bd9Sstevel@tonic-gate 	    ph->p_usba_device->usb_addr,
10307c478bd9Sstevel@tonic-gate 	    eptd->bEndpointAddress & USB_EP_NUM_MASK);
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	/* Check and handle root hub pipe close */
10337c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 		mutex_enter(&ehcip->ehci_int_mutex);
10367c478bd9Sstevel@tonic-gate 		error = ehci_handle_root_hub_pipe_close(ph);
10377c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 		return (error);
10407c478bd9Sstevel@tonic-gate 	}
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	ASSERT(ph->p_hcd_private != NULL);
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	/* Set pipe state to pipe close */
10477c478bd9Sstevel@tonic-gate 	pp->pp_state = EHCI_PIPE_STATE_CLOSE;
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	ehci_pipe_cleanup(ehcip, ph);
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	/*
10527c478bd9Sstevel@tonic-gate 	 * Remove the endpoint descriptor from Host
10537c478bd9Sstevel@tonic-gate 	 * Controller's appropriate endpoint list.
10547c478bd9Sstevel@tonic-gate 	 */
10557c478bd9Sstevel@tonic-gate 	ehci_remove_qh(ehcip, pp, B_TRUE);
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	/* Deallocate bandwidth */
10587c478bd9Sstevel@tonic-gate 	if (EHCI_PERIODIC_ENDPOINT(eptd)) {
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
10617c478bd9Sstevel@tonic-gate 		ehci_deallocate_bandwidth(ehcip, ph, pp->pp_pnode,
10627c478bd9Sstevel@tonic-gate 		    pp->pp_smask, pp->pp_cmask);
10637c478bd9Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
10647c478bd9Sstevel@tonic-gate 	}
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	/* Destroy the xfer completion condition variable */
10697c478bd9Sstevel@tonic-gate 	cv_destroy(&pp->pp_xfer_cmpl_cv);
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	/* Destory halt completion condition variable */
10737c478bd9Sstevel@tonic-gate 	cv_destroy(&pp->pp_halt_cmpl_cv);
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	/*
10767c478bd9Sstevel@tonic-gate 	 * Deallocate the hcd private portion
10777c478bd9Sstevel@tonic-gate 	 * of the pipe handle.
10787c478bd9Sstevel@tonic-gate 	 */
10797c478bd9Sstevel@tonic-gate 	kmem_free(ph->p_hcd_private, sizeof (ehci_pipe_private_t));
10807c478bd9Sstevel@tonic-gate 	ph->p_hcd_private = NULL;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
10857c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_pipe_close: ph = 0x%p", (void *)ph);
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	ehcip->ehci_open_pipe_count--;
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	return (error);
10927c478bd9Sstevel@tonic-gate }
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate /*
10967c478bd9Sstevel@tonic-gate  * ehci_hcdi_pipe_reset:
10977c478bd9Sstevel@tonic-gate  */
10987c478bd9Sstevel@tonic-gate /* ARGSUSED */
10997c478bd9Sstevel@tonic-gate int
ehci_hcdi_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)11007c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_reset(
11017c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
11027c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags)
11037c478bd9Sstevel@tonic-gate {
11047c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
1105fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
11067c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
11077c478bd9Sstevel@tonic-gate 	int			error = USB_SUCCESS;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
11107c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_pipe_reset:");
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	/*
11137c478bd9Sstevel@tonic-gate 	 * Check and handle root hub pipe reset.
11147c478bd9Sstevel@tonic-gate 	 */
11157c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 		error = ehci_handle_root_hub_pipe_reset(ph, usb_flags);
11187c478bd9Sstevel@tonic-gate 		return (error);
11197c478bd9Sstevel@tonic-gate 	}
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	/* Set pipe state to pipe reset */
11247c478bd9Sstevel@tonic-gate 	pp->pp_state = EHCI_PIPE_STATE_RESET;
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	ehci_pipe_cleanup(ehcip, ph);
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	return (error);
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate 
1133269552cdSguoqing zhu - Sun Microsystems - Beijing China /*
1134269552cdSguoqing zhu - Sun Microsystems - Beijing China  * ehci_hcdi_pipe_reset_data_toggle:
1135269552cdSguoqing zhu - Sun Microsystems - Beijing China  */
1136269552cdSguoqing zhu - Sun Microsystems - Beijing China void
ehci_hcdi_pipe_reset_data_toggle(usba_pipe_handle_data_t * ph)1137269552cdSguoqing zhu - Sun Microsystems - Beijing China ehci_hcdi_pipe_reset_data_toggle(
1138269552cdSguoqing zhu - Sun Microsystems - Beijing China 	usba_pipe_handle_data_t	*ph)
1139269552cdSguoqing zhu - Sun Microsystems - Beijing China {
1140269552cdSguoqing zhu - Sun Microsystems - Beijing China 	ehci_state_t		*ehcip = ehci_obtain_state(
1141269552cdSguoqing zhu - Sun Microsystems - Beijing China 	    ph->p_usba_device->usb_root_hub_dip);
1142269552cdSguoqing zhu - Sun Microsystems - Beijing China 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
1143269552cdSguoqing zhu - Sun Microsystems - Beijing China 
1144269552cdSguoqing zhu - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
1145269552cdSguoqing zhu - Sun Microsystems - Beijing China 	    "ehci_hcdi_pipe_reset_data_toggle:");
1146269552cdSguoqing zhu - Sun Microsystems - Beijing China 
1147269552cdSguoqing zhu - Sun Microsystems - Beijing China 	mutex_enter(&ehcip->ehci_int_mutex);
1148269552cdSguoqing zhu - Sun Microsystems - Beijing China 
1149269552cdSguoqing zhu - Sun Microsystems - Beijing China 	mutex_enter(&ph->p_mutex);
1150269552cdSguoqing zhu - Sun Microsystems - Beijing China 	usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress,
1151269552cdSguoqing zhu - Sun Microsystems - Beijing China 	    DATA0);
1152269552cdSguoqing zhu - Sun Microsystems - Beijing China 	mutex_exit(&ph->p_mutex);
1153269552cdSguoqing zhu - Sun Microsystems - Beijing China 
1154269552cdSguoqing zhu - Sun Microsystems - Beijing China 	Set_QH(pp->pp_qh->qh_status,
1155269552cdSguoqing zhu - Sun Microsystems - Beijing China 	    Get_QH(pp->pp_qh->qh_status) & (~EHCI_QH_STS_DATA_TOGGLE));
1156269552cdSguoqing zhu - Sun Microsystems - Beijing China 	mutex_exit(&ehcip->ehci_int_mutex);
1157269552cdSguoqing zhu - Sun Microsystems - Beijing China 
1158269552cdSguoqing zhu - Sun Microsystems - Beijing China }
1159269552cdSguoqing zhu - Sun Microsystems - Beijing China 
11607c478bd9Sstevel@tonic-gate /*
11617c478bd9Sstevel@tonic-gate  * ehci_hcdi_pipe_ctrl_xfer:
11627c478bd9Sstevel@tonic-gate  */
11637c478bd9Sstevel@tonic-gate int
ehci_hcdi_pipe_ctrl_xfer(usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)11647c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_ctrl_xfer(
11657c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
11667c478bd9Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_reqp,
11677c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags)
11687c478bd9Sstevel@tonic-gate {
11697c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
1170fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
11717c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
11727c478bd9Sstevel@tonic-gate 	int			rval;
11737c478bd9Sstevel@tonic-gate 	int			error = USB_SUCCESS;
11747c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
11777c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_pipe_ctrl_xfer: ph = 0x%p reqp = 0x%p flags = %x",
1178112116d8Sfb 	    (void *)ph, (void *)ctrl_reqp, usb_flags);
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
11817c478bd9Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
11827c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 		return (rval);
11877c478bd9Sstevel@tonic-gate 	}
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	/*
11907c478bd9Sstevel@tonic-gate 	 * Check and handle root hub control request.
11917c478bd9Sstevel@tonic-gate 	 */
11927c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 		error = ehci_handle_root_hub_request(ehcip, ph, ctrl_reqp);
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 		return (error);
11977c478bd9Sstevel@tonic-gate 	}
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	/*
12027c478bd9Sstevel@tonic-gate 	 *  Check whether pipe is in halted state.
12037c478bd9Sstevel@tonic-gate 	 */
12047c478bd9Sstevel@tonic-gate 	if (pp->pp_state == EHCI_PIPE_STATE_ERROR) {
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
12077c478bd9Sstevel@tonic-gate 		    "ehci_hcdi_pipe_ctrl_xfer: "
12087c478bd9Sstevel@tonic-gate 		    "Pipe is in error state, need pipe reset to continue");
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
12137c478bd9Sstevel@tonic-gate 	}
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	/* Allocate a transfer wrapper */
12167c478bd9Sstevel@tonic-gate 	if ((tw = ehci_allocate_ctrl_resources(ehcip, pp, ctrl_reqp,
12177c478bd9Sstevel@tonic-gate 	    usb_flags)) == NULL) {
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 		error = USB_NO_RESOURCES;
12207c478bd9Sstevel@tonic-gate 	} else {
12217c478bd9Sstevel@tonic-gate 		/* Insert the qtd's on the endpoint */
12227c478bd9Sstevel@tonic-gate 		ehci_insert_ctrl_req(ehcip, ph, ctrl_reqp, tw, usb_flags);
12237c478bd9Sstevel@tonic-gate 	}
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	return (error);
12287c478bd9Sstevel@tonic-gate }
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate /*
12327c478bd9Sstevel@tonic-gate  * ehci_hcdi_bulk_transfer_size:
12337c478bd9Sstevel@tonic-gate  *
12347c478bd9Sstevel@tonic-gate  * Return maximum bulk transfer size
12357c478bd9Sstevel@tonic-gate  */
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate /* ARGSUSED */
12387c478bd9Sstevel@tonic-gate int
ehci_hcdi_bulk_transfer_size(usba_device_t * usba_device,size_t * size)12397c478bd9Sstevel@tonic-gate ehci_hcdi_bulk_transfer_size(
12407c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device,
12417c478bd9Sstevel@tonic-gate 	size_t		*size)
12427c478bd9Sstevel@tonic-gate {
12437c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip = ehci_obtain_state(
1244fffe0b30Sqz 	    usba_device->usb_root_hub_dip);
12457c478bd9Sstevel@tonic-gate 	int		rval;
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
12487c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_bulk_transfer_size:");
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
12517c478bd9Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
12527c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 		return (rval);
12577c478bd9Sstevel@tonic-gate 	}
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	/* VIA VT6202 may not handle bigger xfers well, workaround. */
12607c478bd9Sstevel@tonic-gate 	if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) &&
12617c478bd9Sstevel@tonic-gate 	    (ehci_vt62x2_workaround & EHCI_VIA_REDUCED_MAX_BULK_XFER_SIZE)) {
12627c478bd9Sstevel@tonic-gate 		*size = EHCI_VIA_MAX_BULK_XFER_SIZE;
12637c478bd9Sstevel@tonic-gate 	} else {
12647c478bd9Sstevel@tonic-gate 		*size = EHCI_MAX_BULK_XFER_SIZE;
12657c478bd9Sstevel@tonic-gate 	}
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
12687c478bd9Sstevel@tonic-gate }
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate /*
12727c478bd9Sstevel@tonic-gate  * ehci_hcdi_pipe_bulk_xfer:
12737c478bd9Sstevel@tonic-gate  */
12747c478bd9Sstevel@tonic-gate int
ehci_hcdi_pipe_bulk_xfer(usba_pipe_handle_data_t * ph,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)12757c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_bulk_xfer(
12767c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
12777c478bd9Sstevel@tonic-gate 	usb_bulk_req_t		*bulk_reqp,
12787c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags)
12797c478bd9Sstevel@tonic-gate {
12807c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
1281fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
12827c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
12837c478bd9Sstevel@tonic-gate 	int			rval, error = USB_SUCCESS;
12847c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
12877c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_pipe_bulk_xfer: ph = 0x%p reqp = 0x%p flags = %x",
1288112116d8Sfb 	    (void *)ph, (void *)bulk_reqp, usb_flags);
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
12917c478bd9Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
12947c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 		return (rval);
12977c478bd9Sstevel@tonic-gate 	}
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	/*
13007c478bd9Sstevel@tonic-gate 	 *  Check whether pipe is in halted state.
13017c478bd9Sstevel@tonic-gate 	 */
13027c478bd9Sstevel@tonic-gate 	if (pp->pp_state == EHCI_PIPE_STATE_ERROR) {
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
13057c478bd9Sstevel@tonic-gate 		    "ehci_hcdi_pipe_bulk_xfer:"
13067c478bd9Sstevel@tonic-gate 		    "Pipe is in error state, need pipe reset to continue");
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
13117c478bd9Sstevel@tonic-gate 	}
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 	/* Allocate a transfer wrapper */
13147c478bd9Sstevel@tonic-gate 	if ((tw = ehci_allocate_bulk_resources(ehcip, pp, bulk_reqp,
13157c478bd9Sstevel@tonic-gate 	    usb_flags)) == NULL) {
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 		error = USB_NO_RESOURCES;
13187c478bd9Sstevel@tonic-gate 	} else {
13197c478bd9Sstevel@tonic-gate 		/* Add the QTD into the Host Controller's bulk list */
13207c478bd9Sstevel@tonic-gate 		ehci_insert_bulk_req(ehcip, ph, bulk_reqp, tw, usb_flags);
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	return (error);
13267c478bd9Sstevel@tonic-gate }
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate /*
13307c478bd9Sstevel@tonic-gate  * ehci_hcdi_pipe_intr_xfer:
13317c478bd9Sstevel@tonic-gate  */
13327c478bd9Sstevel@tonic-gate int
ehci_hcdi_pipe_intr_xfer(usba_pipe_handle_data_t * ph,usb_intr_req_t * intr_reqp,usb_flags_t usb_flags)13337c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_intr_xfer(
13347c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
13357c478bd9Sstevel@tonic-gate 	usb_intr_req_t		*intr_reqp,
13367c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags)
13377c478bd9Sstevel@tonic-gate {
13387c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
1339fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
13407c478bd9Sstevel@tonic-gate 	int			pipe_dir, rval, error = USB_SUCCESS;
13417c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
13447c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_pipe_intr_xfer: ph = 0x%p reqp = 0x%p flags = %x",
1345112116d8Sfb 	    (void *)ph, (void *)intr_reqp, usb_flags);
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
13487c478bd9Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
13517c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 		return (rval);
13547c478bd9Sstevel@tonic-gate 	}
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 	/* Get the pipe direction */
13577c478bd9Sstevel@tonic-gate 	pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 	if (pipe_dir == USB_EP_DIR_IN) {
13607c478bd9Sstevel@tonic-gate 		error = ehci_start_periodic_pipe_polling(ehcip, ph,
13617c478bd9Sstevel@tonic-gate 		    (usb_opaque_t)intr_reqp, usb_flags);
13627c478bd9Sstevel@tonic-gate 	} else {
13637c478bd9Sstevel@tonic-gate 		/* Allocate transaction resources */
13647c478bd9Sstevel@tonic-gate 		if ((tw = ehci_allocate_intr_resources(ehcip, ph,
13657c478bd9Sstevel@tonic-gate 		    intr_reqp, usb_flags)) == NULL) {
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 			error = USB_NO_RESOURCES;
13687c478bd9Sstevel@tonic-gate 		} else {
13697c478bd9Sstevel@tonic-gate 			ehci_insert_intr_req(ehcip,
13707c478bd9Sstevel@tonic-gate 			    (ehci_pipe_private_t *)ph->p_hcd_private,
13717c478bd9Sstevel@tonic-gate 			    tw, usb_flags);
13727c478bd9Sstevel@tonic-gate 		}
13737c478bd9Sstevel@tonic-gate 	}
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	return (error);
13787c478bd9Sstevel@tonic-gate }
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate /*
13817c478bd9Sstevel@tonic-gate  * ehci_hcdi_pipe_stop_intr_polling()
13827c478bd9Sstevel@tonic-gate  */
13837c478bd9Sstevel@tonic-gate int
ehci_hcdi_pipe_stop_intr_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)13847c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_stop_intr_polling(
13857c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
13867c478bd9Sstevel@tonic-gate 	usb_flags_t		flags)
13877c478bd9Sstevel@tonic-gate {
13887c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
1389fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
13907c478bd9Sstevel@tonic-gate 	int			error = USB_SUCCESS;
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
13937c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_pipe_stop_intr_polling: ph = 0x%p fl = 0x%x",
13947c478bd9Sstevel@tonic-gate 	    (void *)ph, flags);
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	error = ehci_stop_periodic_pipe_polling(ehcip, ph, flags);
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 	return (error);
14037c478bd9Sstevel@tonic-gate }
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate /*
14077c478bd9Sstevel@tonic-gate  * ehci_hcdi_get_current_frame_number:
14087c478bd9Sstevel@tonic-gate  *
1409fffe0b30Sqz  * Get the current usb frame number.
1410fffe0b30Sqz  * Return whether the request is handled successfully.
14117c478bd9Sstevel@tonic-gate  */
1412fffe0b30Sqz int
ehci_hcdi_get_current_frame_number(usba_device_t * usba_device,usb_frame_number_t * frame_number)1413fffe0b30Sqz ehci_hcdi_get_current_frame_number(
1414fffe0b30Sqz 	usba_device_t		*usba_device,
1415fffe0b30Sqz 	usb_frame_number_t	*frame_number)
14167c478bd9Sstevel@tonic-gate {
14177c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
1418fffe0b30Sqz 	    usba_device->usb_root_hub_dip);
14197c478bd9Sstevel@tonic-gate 	int			rval;
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 	ehcip = ehci_obtain_state(usba_device->usb_root_hub_dip);
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
14247c478bd9Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
14277c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 		return (rval);
14307c478bd9Sstevel@tonic-gate 	}
14317c478bd9Sstevel@tonic-gate 
1432fffe0b30Sqz 	*frame_number = ehci_get_current_frame_number(ehcip);
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
14377c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_get_current_frame_number: "
1438112116d8Sfb 	    "Current frame number 0x%llx", (unsigned long long)(*frame_number));
14397c478bd9Sstevel@tonic-gate 
1440fffe0b30Sqz 	return (rval);
14417c478bd9Sstevel@tonic-gate }
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate /*
14457c478bd9Sstevel@tonic-gate  * ehci_hcdi_get_max_isoc_pkts:
14467c478bd9Sstevel@tonic-gate  *
1447fffe0b30Sqz  * Get maximum isochronous packets per usb isochronous request.
1448fffe0b30Sqz  * Return whether the request is handled successfully.
14497c478bd9Sstevel@tonic-gate  */
1450fffe0b30Sqz int
ehci_hcdi_get_max_isoc_pkts(usba_device_t * usba_device,uint_t * max_isoc_pkts_per_request)1451fffe0b30Sqz ehci_hcdi_get_max_isoc_pkts(
1452fffe0b30Sqz 	usba_device_t	*usba_device,
1453fffe0b30Sqz 	uint_t		*max_isoc_pkts_per_request)
14547c478bd9Sstevel@tonic-gate {
14557c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
1456fffe0b30Sqz 	    usba_device->usb_root_hub_dip);
14577c478bd9Sstevel@tonic-gate 	int			rval;
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
14607c478bd9Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
14617c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 		return (rval);
14667c478bd9Sstevel@tonic-gate 	}
14677c478bd9Sstevel@tonic-gate 
1468fffe0b30Sqz 	*max_isoc_pkts_per_request = EHCI_MAX_ISOC_PKTS_PER_XFER;
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
14717c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_get_max_isoc_pkts: maximum isochronous"
14727c478bd9Sstevel@tonic-gate 	    "packets per usb isochronous request = 0x%x",
1473112116d8Sfb 	    *max_isoc_pkts_per_request);
14747c478bd9Sstevel@tonic-gate 
1475fffe0b30Sqz 	return (rval);
14767c478bd9Sstevel@tonic-gate }
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate /*
14807c478bd9Sstevel@tonic-gate  * ehci_hcdi_pipe_isoc_xfer:
14817c478bd9Sstevel@tonic-gate  */
14827c478bd9Sstevel@tonic-gate int
ehci_hcdi_pipe_isoc_xfer(usba_pipe_handle_data_t * ph,usb_isoc_req_t * isoc_reqp,usb_flags_t usb_flags)14837c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_isoc_xfer(
14847c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
14857c478bd9Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_reqp,
14867c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags)
14877c478bd9Sstevel@tonic-gate {
14887c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
1489fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	int			pipe_dir, rval;
14927c478bd9Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw;
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
14957c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_pipe_isoc_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x",
1496112116d8Sfb 	    (void *)ph, (void *)isoc_reqp, usb_flags);
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
14997c478bd9Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
15027c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 		return (rval);
15057c478bd9Sstevel@tonic-gate 	}
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	/* Get the isochronous pipe direction */
15087c478bd9Sstevel@tonic-gate 	pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	if (pipe_dir == USB_EP_DIR_IN) {
15117c478bd9Sstevel@tonic-gate 		rval = ehci_start_periodic_pipe_polling(ehcip, ph,
15127c478bd9Sstevel@tonic-gate 		    (usb_opaque_t)isoc_reqp, usb_flags);
15137c478bd9Sstevel@tonic-gate 	} else {
15147c478bd9Sstevel@tonic-gate 		/* Allocate transaction resources */
15157c478bd9Sstevel@tonic-gate 		if ((itw = ehci_allocate_isoc_resources(ehcip, ph,
15167c478bd9Sstevel@tonic-gate 		    isoc_reqp, usb_flags)) == NULL) {
15177c478bd9Sstevel@tonic-gate 			rval = USB_NO_RESOURCES;
15187c478bd9Sstevel@tonic-gate 		} else {
15197c478bd9Sstevel@tonic-gate 			rval = ehci_insert_isoc_req(ehcip,
15207c478bd9Sstevel@tonic-gate 			    (ehci_pipe_private_t *)ph->p_hcd_private,
15217c478bd9Sstevel@tonic-gate 			    itw, usb_flags);
15227c478bd9Sstevel@tonic-gate 		}
15237c478bd9Sstevel@tonic-gate 	}
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	return (rval);
15287c478bd9Sstevel@tonic-gate }
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate /*
15327c478bd9Sstevel@tonic-gate  * ehci_hcdi_pipe_stop_isoc_polling()
15337c478bd9Sstevel@tonic-gate  */
15347c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15357c478bd9Sstevel@tonic-gate int
ehci_hcdi_pipe_stop_isoc_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)15367c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_stop_isoc_polling(
15377c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
15387c478bd9Sstevel@tonic-gate 	usb_flags_t		flags)
15397c478bd9Sstevel@tonic-gate {
15407c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
1541fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
15427c478bd9Sstevel@tonic-gate 	int			rval;
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
15457c478bd9Sstevel@tonic-gate 	    "ehci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x",
15467c478bd9Sstevel@tonic-gate 	    (void *)ph, flags);
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
15497c478bd9Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
15527c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 		return (rval);
15557c478bd9Sstevel@tonic-gate 	}
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 	rval = ehci_stop_periodic_pipe_polling(ehcip, ph, flags);
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 	return (rval);
15627c478bd9Sstevel@tonic-gate }
1563