xref: /onnv-gate/usr/src/uts/common/io/usb/hcd/ehci/ehci.c (revision 9212:00cbbe3ae682)
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
51458Syq193411  * Common Development and Distribution License (the "License").
61458Syq193411  * 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 /*
228945SGuoqing.Zhu@Sun.COM  * Copyright 2009 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  * EHCI Host Controller Driver (EHCI)
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * The EHCI driver is a software driver which interfaces to the Universal
310Sstevel@tonic-gate  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
320Sstevel@tonic-gate  * the Host Controller is defined by the EHCI Host Controller Interface.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * This file contains code for Auto-configuration and HCDI entry points.
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  * NOTE:
370Sstevel@tonic-gate  *
380Sstevel@tonic-gate  * Currently EHCI driver does not support the following features
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  * - Alternate QTD for short xfer condition is only used in Bulk xfers.
410Sstevel@tonic-gate  * - Frame Span Traversal Nodes (FSTN).
420Sstevel@tonic-gate  * - Bandwidth allocation scheme needs to be updated for FSTN and USB2.0
430Sstevel@tonic-gate  *   or High speed hub with multiple TT implementation. Currently bandwidth
440Sstevel@tonic-gate  *   allocation scheme assumes one TT per USB2.0 or High speed hub.
450Sstevel@tonic-gate  * - 64 bit addressing capability.
460Sstevel@tonic-gate  * - Programmable periodic frame list size like 256, 512, 1024.
470Sstevel@tonic-gate  *   It supports only 1024 periodic frame list size.
480Sstevel@tonic-gate  */
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
510Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
520Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_intr.h>
530Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h>
540Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h>
550Sstevel@tonic-gate 
560Sstevel@tonic-gate /* Pointer to the state structure */
570Sstevel@tonic-gate void *ehci_statep;
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /* Number of instances */
600Sstevel@tonic-gate #define	EHCI_INSTS	1
610Sstevel@tonic-gate 
620Sstevel@tonic-gate /* Debugging information */
630Sstevel@tonic-gate uint_t ehci_errmask	= (uint_t)PRINT_MASK_ALL;
640Sstevel@tonic-gate uint_t ehci_errlevel	= USB_LOG_L2;
650Sstevel@tonic-gate uint_t ehci_instance_debug = (uint_t)-1;
660Sstevel@tonic-gate 
675295Srandyf /*
685295Srandyf  * Tunable to ensure host controller goes off even if a keyboard is attached.
695295Srandyf  */
705295Srandyf int force_ehci_off = 1;
715295Srandyf 
720Sstevel@tonic-gate /* Enable all workarounds for VIA VT62x2 */
730Sstevel@tonic-gate uint_t ehci_vt62x2_workaround = EHCI_VIA_WORKAROUNDS;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate  * EHCI Auto-configuration entry points.
770Sstevel@tonic-gate  *
780Sstevel@tonic-gate  * Device operations (dev_ops) entries function prototypes.
790Sstevel@tonic-gate  *
800Sstevel@tonic-gate  * We use the hub cbops since all nexus ioctl operations defined so far will
810Sstevel@tonic-gate  * be executed by the root hub. The following are the Host Controller Driver
820Sstevel@tonic-gate  * (HCD) entry points.
830Sstevel@tonic-gate  *
840Sstevel@tonic-gate  * the open/close/ioctl functions call the corresponding usba_hubdi_*
850Sstevel@tonic-gate  * calls after looking up the dip thru the dev_t.
860Sstevel@tonic-gate  */
870Sstevel@tonic-gate static int	ehci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
880Sstevel@tonic-gate static int	ehci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
890Sstevel@tonic-gate static int	ehci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd);
900Sstevel@tonic-gate static int	ehci_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
910Sstevel@tonic-gate 				void *arg, void **result);
920Sstevel@tonic-gate 
930Sstevel@tonic-gate static int	ehci_open(dev_t	*devp, int flags, int otyp, cred_t *credp);
940Sstevel@tonic-gate static int	ehci_close(dev_t dev, int flag, int otyp, cred_t *credp);
950Sstevel@tonic-gate static int	ehci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
960Sstevel@tonic-gate     cred_t *credp, int *rvalp);
970Sstevel@tonic-gate 
980Sstevel@tonic-gate int		usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level);
997656SSherry.Moore@Sun.COM static int	ehci_quiesce(dev_info_t *dip);
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate static struct cb_ops ehci_cb_ops = {
1020Sstevel@tonic-gate 	ehci_open,			/* EHCI */
1030Sstevel@tonic-gate 	ehci_close,			/* Close */
1040Sstevel@tonic-gate 	nodev,				/* Strategy */
1050Sstevel@tonic-gate 	nodev,				/* Print */
1060Sstevel@tonic-gate 	nodev,				/* Dump */
1070Sstevel@tonic-gate 	nodev,				/* Read */
1080Sstevel@tonic-gate 	nodev,				/* Write */
1090Sstevel@tonic-gate 	ehci_ioctl,			/* Ioctl */
1100Sstevel@tonic-gate 	nodev,				/* Devmap */
1110Sstevel@tonic-gate 	nodev,				/* Mmap */
1120Sstevel@tonic-gate 	nodev,				/* Segmap */
1130Sstevel@tonic-gate 	nochpoll,			/* Poll */
1140Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
1150Sstevel@tonic-gate 	NULL,				/* Streamtab */
1160Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG	/* Driver compatibility flag */
1170Sstevel@tonic-gate };
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate static struct dev_ops ehci_ops = {
1200Sstevel@tonic-gate 	DEVO_REV,			/* Devo_rev */
1210Sstevel@tonic-gate 	0,				/* Refcnt */
1220Sstevel@tonic-gate 	ehci_info,			/* Info */
1230Sstevel@tonic-gate 	nulldev,			/* Identify */
1240Sstevel@tonic-gate 	nulldev,			/* Probe */
1250Sstevel@tonic-gate 	ehci_attach,			/* Attach */
1260Sstevel@tonic-gate 	ehci_detach,			/* Detach */
1270Sstevel@tonic-gate 	ehci_reset,			/* Reset */
1280Sstevel@tonic-gate 	&ehci_cb_ops,			/* Driver operations */
1290Sstevel@tonic-gate 	&usba_hubdi_busops,		/* Bus operations */
1307656SSherry.Moore@Sun.COM 	usba_hubdi_root_hub_power,	/* Power */
1317656SSherry.Moore@Sun.COM 	ehci_quiesce			/* Quiesce */
1320Sstevel@tonic-gate };
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate  * The USBA library must be loaded for this driver.
1360Sstevel@tonic-gate  */
1370Sstevel@tonic-gate static struct modldrv modldrv = {
1380Sstevel@tonic-gate 	&mod_driverops, 	/* Type of module. This one is a driver */
1397293Sbc224572 	"USB EHCI Driver", /* Name of the module. */
1400Sstevel@tonic-gate 	&ehci_ops,		/* Driver ops */
1410Sstevel@tonic-gate };
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate static struct modlinkage modlinkage = {
1440Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
1450Sstevel@tonic-gate };
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate int
_init(void)1490Sstevel@tonic-gate _init(void)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate 	int error;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	/* Initialize the soft state structures */
1540Sstevel@tonic-gate 	if ((error = ddi_soft_state_init(&ehci_statep, sizeof (ehci_state_t),
1550Sstevel@tonic-gate 	    EHCI_INSTS)) != 0) {
1560Sstevel@tonic-gate 		return (error);
1570Sstevel@tonic-gate 	}
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	/* Install the loadable module */
1600Sstevel@tonic-gate 	if ((error = mod_install(&modlinkage)) != 0) {
1610Sstevel@tonic-gate 		ddi_soft_state_fini(&ehci_statep);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	return (error);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1690Sstevel@tonic-gate _info(struct modinfo *modinfop)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate int
_fini(void)1760Sstevel@tonic-gate _fini(void)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate 	int error;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	if ((error = mod_remove(&modlinkage)) == 0) {
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 		/* Release per module resources */
1830Sstevel@tonic-gate 		ddi_soft_state_fini(&ehci_statep);
1840Sstevel@tonic-gate 	}
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	return (error);
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate  * EHCI Auto configuration entry points.
1920Sstevel@tonic-gate  */
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate /*
1950Sstevel@tonic-gate  * ehci_attach:
1960Sstevel@tonic-gate  *
1970Sstevel@tonic-gate  * Description: Attach entry point is called by the Kernel.
1980Sstevel@tonic-gate  *		Allocates resources for each EHCI host controller instance.
1990Sstevel@tonic-gate  *		Initializes the EHCI Host Controller.
2000Sstevel@tonic-gate  *
2010Sstevel@tonic-gate  * Return     : DDI_SUCCESS / DDI_FAILURE.
2020Sstevel@tonic-gate  */
2030Sstevel@tonic-gate static int
ehci_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2040Sstevel@tonic-gate ehci_attach(dev_info_t		*dip,
2050Sstevel@tonic-gate 	ddi_attach_cmd_t	cmd)
2060Sstevel@tonic-gate {
2070Sstevel@tonic-gate 	int			instance;
2080Sstevel@tonic-gate 	ehci_state_t		*ehcip = NULL;
2090Sstevel@tonic-gate 	usba_hcdi_register_args_t hcdi_args;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	switch (cmd) {
2120Sstevel@tonic-gate 	case DDI_ATTACH:
2130Sstevel@tonic-gate 		break;
2140Sstevel@tonic-gate 	case DDI_RESUME:
2150Sstevel@tonic-gate 		ehcip = ehci_obtain_state(dip);
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 		return (ehci_cpr_resume(ehcip));
2180Sstevel@tonic-gate 	default:
2190Sstevel@tonic-gate 		return (DDI_FAILURE);
2200Sstevel@tonic-gate 	}
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	/* Get the instance and create soft state */
2230Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(ehci_statep, instance) != 0) {
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 		return (DDI_FAILURE);
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	ehcip = ddi_get_soft_state(ehci_statep, instance);
2310Sstevel@tonic-gate 	if (ehcip == NULL) {
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 		return (DDI_FAILURE);
2340Sstevel@tonic-gate 	}
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	ehcip->ehci_flags = EHCI_ATTACH;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	ehcip->ehci_log_hdl = usb_alloc_log_hdl(dip, "ehci", &ehci_errlevel,
2390Sstevel@tonic-gate 	    &ehci_errmask, &ehci_instance_debug, 0);
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	ehcip->ehci_flags |= EHCI_ZALLOC;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	/* Set host controller soft state to initialization */
2440Sstevel@tonic-gate 	ehcip->ehci_hc_soft_state = EHCI_CTLR_INIT_STATE;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
2470Sstevel@tonic-gate 	    "ehcip = 0x%p", (void *)ehcip);
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	/* Save the dip and instance */
2500Sstevel@tonic-gate 	ehcip->ehci_dip = dip;
2510Sstevel@tonic-gate 	ehcip->ehci_instance = instance;
2520Sstevel@tonic-gate 
2537293Sbc224572 	/* Map the registers */
2547293Sbc224572 	if (ehci_map_regs(ehcip) != DDI_SUCCESS) {
2557293Sbc224572 		(void) ehci_cleanup(ehcip);
2567293Sbc224572 
2577293Sbc224572 		return (DDI_FAILURE);
2587293Sbc224572 	}
2597293Sbc224572 
2607293Sbc224572 	/* Get the ehci chip vendor and device id */
2617293Sbc224572 	ehcip->ehci_vendor_id = pci_config_get16(
2627293Sbc224572 	    ehcip->ehci_config_handle, PCI_CONF_VENID);
2637293Sbc224572 	ehcip->ehci_device_id = pci_config_get16(
2647293Sbc224572 	    ehcip->ehci_config_handle, PCI_CONF_DEVID);
2657293Sbc224572 	ehcip->ehci_rev_id = pci_config_get8(
2667293Sbc224572 	    ehcip->ehci_config_handle, PCI_CONF_REVID);
2677293Sbc224572 
2680Sstevel@tonic-gate 	/* Initialize the DMA attributes */
2697293Sbc224572 	ehci_set_dma_attributes(ehcip);
2707293Sbc224572 
2717293Sbc224572 	/* Initialize kstat structures */
2720Sstevel@tonic-gate 	ehci_create_stats(ehcip);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/* Create the qtd and qh pools */
2750Sstevel@tonic-gate 	if (ehci_allocate_pools(ehcip) != DDI_SUCCESS) {
2760Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 		return (DDI_FAILURE);
2790Sstevel@tonic-gate 	}
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	/* Initialize the isochronous resources */
2820Sstevel@tonic-gate 	if (ehci_isoc_init(ehcip) != DDI_SUCCESS) {
2830Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 		return (DDI_FAILURE);
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	/* Register interrupts */
2890Sstevel@tonic-gate 	if (ehci_register_intrs_and_init_mutex(ehcip) != DDI_SUCCESS) {
2900Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 		return (DDI_FAILURE);
2930Sstevel@tonic-gate 	}
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	/* Initialize the controller */
2981458Syq193411 	if (ehci_init_ctlr(ehcip, EHCI_NORMAL_INITIALIZATION) != DDI_SUCCESS) {
2990Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
3000Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 		return (DDI_FAILURE);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	/*
3060Sstevel@tonic-gate 	 * At this point, the hardware will be okay.
3070Sstevel@tonic-gate 	 * Initialize the usba_hcdi structure
3080Sstevel@tonic-gate 	 */
3090Sstevel@tonic-gate 	ehcip->ehci_hcdi_ops = ehci_alloc_hcdi_ops(ehcip);
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	/*
3140Sstevel@tonic-gate 	 * Make this HCD instance known to USBA
3150Sstevel@tonic-gate 	 * (dma_attr must be passed for USBA busctl's)
3160Sstevel@tonic-gate 	 */
3170Sstevel@tonic-gate 	hcdi_args.usba_hcdi_register_version = HCDI_REGISTER_VERSION;
3180Sstevel@tonic-gate 	hcdi_args.usba_hcdi_register_dip = dip;
3190Sstevel@tonic-gate 	hcdi_args.usba_hcdi_register_ops = ehcip->ehci_hcdi_ops;
3200Sstevel@tonic-gate 	hcdi_args.usba_hcdi_register_dma_attr = &ehcip->ehci_dma_attr;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	/*
3230Sstevel@tonic-gate 	 * Priority and iblock_cookie are one and the same
3240Sstevel@tonic-gate 	 * (However, retaining hcdi_soft_iblock_cookie for now
3250Sstevel@tonic-gate 	 * assigning it w/ priority. In future all iblock_cookie
3260Sstevel@tonic-gate 	 * could just go)
3270Sstevel@tonic-gate 	 */
3280Sstevel@tonic-gate 	hcdi_args.usba_hcdi_register_iblock_cookie =
32942Sagiri 	    (ddi_iblock_cookie_t)(uintptr_t)ehcip->ehci_intr_pri;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	if (usba_hcdi_register(&hcdi_args, 0) != DDI_SUCCESS) {
3320Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 		return (DDI_FAILURE);
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	ehcip->ehci_flags |= EHCI_USBAREG;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	if ((ehci_init_root_hub(ehcip)) != USB_SUCCESS) {
3420Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
3430Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 		return (DDI_FAILURE);
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	/* Finally load the root hub driver */
3510Sstevel@tonic-gate 	if (ehci_load_root_hub_driver(ehcip) != USB_SUCCESS) {
3520Sstevel@tonic-gate 		(void) ehci_cleanup(ehcip);
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 		return (DDI_FAILURE);
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 	ehcip->ehci_flags |= EHCI_RHREG;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	/* Display information in the banner */
3590Sstevel@tonic-gate 	ddi_report_dev(dip);
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	/* Reset the ehci initialization flag */
3640Sstevel@tonic-gate 	ehcip->ehci_flags &= ~EHCI_ATTACH;
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	/* Print the Host Control's Operational registers */
3670Sstevel@tonic-gate 	ehci_print_caps(ehcip);
3680Sstevel@tonic-gate 	ehci_print_regs(ehcip);
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	(void) pci_report_pmcap(dip, PCI_PM_IDLESPEED, (void *)4000);
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3750Sstevel@tonic-gate 	    "ehci_attach: dip = 0x%p done", (void *)dip);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	return (DDI_SUCCESS);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate  * ehci_detach:
3830Sstevel@tonic-gate  *
3840Sstevel@tonic-gate  * Description: Detach entry point is called by the Kernel.
3850Sstevel@tonic-gate  *		Deallocates all resource allocated.
3860Sstevel@tonic-gate  *		Unregisters the interrupt handler.
3870Sstevel@tonic-gate  *
3880Sstevel@tonic-gate  * Return     : DDI_SUCCESS / DDI_FAILURE
3890Sstevel@tonic-gate  */
3900Sstevel@tonic-gate int
ehci_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3910Sstevel@tonic-gate ehci_detach(dev_info_t		*dip,
3920Sstevel@tonic-gate 	ddi_detach_cmd_t	cmd)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(dip);
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_detach:");
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	switch (cmd) {
3990Sstevel@tonic-gate 	case DDI_DETACH:
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 		return (ehci_cleanup(ehcip));
4020Sstevel@tonic-gate 	case DDI_SUSPEND:
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 		return (ehci_cpr_suspend(ehcip));
4050Sstevel@tonic-gate 	default:
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 		return (DDI_FAILURE);
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate  * ehci_reset:
4130Sstevel@tonic-gate  *
4140Sstevel@tonic-gate  * Description:	Reset entry point - called by the Kernel
4150Sstevel@tonic-gate  *		on the way down.
4160Sstevel@tonic-gate  *		Toshiba Tecra laptop has been observed to hang
4170Sstevel@tonic-gate  *		on soft reboot. The resetting ehci on the way
4180Sstevel@tonic-gate  *		down solves the problem.
4190Sstevel@tonic-gate  *
4200Sstevel@tonic-gate  * Return	: DDI_SUCCESS / DDI_FAILURE
4210Sstevel@tonic-gate  */
4220Sstevel@tonic-gate /* ARGSUSED */
4230Sstevel@tonic-gate static int
ehci_reset(dev_info_t * dip,ddi_reset_cmd_t cmd)4240Sstevel@tonic-gate ehci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
4250Sstevel@tonic-gate {
4262651Ssl147100 #if defined(__sparc)
4272651Ssl147100 	/*
4282651Ssl147100 	 * Don't reset the host controller on SPARC, for OBP needs Solaris
4292651Ssl147100 	 * to continue to provide keyboard support after shutdown of SPARC,
4302651Ssl147100 	 * or the keyboard connected to a USB 2.0 port will not work after
4312651Ssl147100 	 * that. The incomplete reset problem on Toshiba Tecra laptop is
4322651Ssl147100 	 * specific to Tecra laptop or BIOS, not present on SPARC. The SPARC
4332651Ssl147100 	 * OBP guarantees good reset behavior during startup.
4342651Ssl147100 	 */
4352651Ssl147100 	return (DDI_SUCCESS);
4362651Ssl147100 #else
4370Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(dip);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	/*
4420Sstevel@tonic-gate 	 * To reset the host controller, the HCRESET bit should be set to one.
4430Sstevel@tonic-gate 	 * Software should not set this bit to a one when the HCHalted bit in
4440Sstevel@tonic-gate 	 * the USBSTS register is a zero. Attempting to reset an actively
4450Sstevel@tonic-gate 	 * running host controller will result in undefined behavior.
4460Sstevel@tonic-gate 	 * see EHCI SPEC. for more information.
4470Sstevel@tonic-gate 	 */
4480Sstevel@tonic-gate 	if (!(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 		/* Stop the EHCI host controller */
4510Sstevel@tonic-gate 		Set_OpReg(ehci_command,
4520Sstevel@tonic-gate 		    Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
4530Sstevel@tonic-gate 		/*
4540Sstevel@tonic-gate 		 * When this bit is set to 0, the Host Controller completes the
4550Sstevel@tonic-gate 		 * current and any actively pipelined transactions on the USB
4560Sstevel@tonic-gate 		 * and then halts. The Host Controller must halt within 16
4570Sstevel@tonic-gate 		 * micro-frames after software clears the Run bit.
4580Sstevel@tonic-gate 		 * The HC Halted bit in the status register indicates when the
4590Sstevel@tonic-gate 		 * Host Controller has finished its pending pipelined
4600Sstevel@tonic-gate 		 * transactions and has entered the stopped state.
4610Sstevel@tonic-gate 		 */
4620Sstevel@tonic-gate 		drv_usecwait(EHCI_RESET_TIMEWAIT);
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	/* Reset the EHCI host controller */
4660Sstevel@tonic-gate 	Set_OpReg(ehci_command,
4670Sstevel@tonic-gate 	    Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	return (DDI_SUCCESS);
4722651Ssl147100 #endif
4730Sstevel@tonic-gate }
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate /*
4767656SSherry.Moore@Sun.COM  * quiesce(9E) entry point.
4777656SSherry.Moore@Sun.COM  *
4787656SSherry.Moore@Sun.COM  * This function is called when the system is single-threaded at high
4797656SSherry.Moore@Sun.COM  * PIL with preemption disabled. Therefore, this function must not be
4807656SSherry.Moore@Sun.COM  * blocked.
4817656SSherry.Moore@Sun.COM  *
4827656SSherry.Moore@Sun.COM  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4837656SSherry.Moore@Sun.COM  * DDI_FAILURE indicates an error condition and should almost never happen.
4847656SSherry.Moore@Sun.COM  */
4857656SSherry.Moore@Sun.COM static int
ehci_quiesce(dev_info_t * dip)4867656SSherry.Moore@Sun.COM ehci_quiesce(dev_info_t *dip)
4877656SSherry.Moore@Sun.COM {
4887656SSherry.Moore@Sun.COM 	ehci_state_t		*ehcip = ehci_obtain_state(dip);
4897656SSherry.Moore@Sun.COM 
4907656SSherry.Moore@Sun.COM 	if (ehcip == NULL)
4917656SSherry.Moore@Sun.COM 		return (DDI_FAILURE);
4927656SSherry.Moore@Sun.COM 
493*9212SZhigang.Lu@Sun.COM #ifndef lint
494*9212SZhigang.Lu@Sun.COM 	_NOTE(NO_COMPETING_THREADS_NOW);
495*9212SZhigang.Lu@Sun.COM #endif
4967656SSherry.Moore@Sun.COM 	/*
4977656SSherry.Moore@Sun.COM 	 * To reset the host controller, the HCRESET bit should be set to one.
4987656SSherry.Moore@Sun.COM 	 * Software should not set this bit to a one when the HCHalted bit in
4997656SSherry.Moore@Sun.COM 	 * the USBSTS register is a zero. Attempting to reset an actively
5007656SSherry.Moore@Sun.COM 	 * running host controller will result in undefined behavior.
5017656SSherry.Moore@Sun.COM 	 * see EHCI SPEC. for more information.
5027656SSherry.Moore@Sun.COM 	 */
5037656SSherry.Moore@Sun.COM 	if (!(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
5047656SSherry.Moore@Sun.COM 
5057656SSherry.Moore@Sun.COM 		/* Stop the EHCI host controller */
5067656SSherry.Moore@Sun.COM 		Set_OpReg(ehci_command,
5077656SSherry.Moore@Sun.COM 		    Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
5087656SSherry.Moore@Sun.COM 		/*
5097656SSherry.Moore@Sun.COM 		 * When this bit is set to 0, the Host Controller completes the
5107656SSherry.Moore@Sun.COM 		 * current and any actively pipelined transactions on the USB
5117656SSherry.Moore@Sun.COM 		 * and then halts. The Host Controller must halt within 16
5127656SSherry.Moore@Sun.COM 		 * micro-frames after software clears the Run bit.
5137656SSherry.Moore@Sun.COM 		 * The HC Halted bit in the status register indicates when the
5147656SSherry.Moore@Sun.COM 		 * Host Controller has finished its pending pipelined
5157656SSherry.Moore@Sun.COM 		 * transactions and has entered the stopped state.
5167656SSherry.Moore@Sun.COM 		 */
5177656SSherry.Moore@Sun.COM 		drv_usecwait(EHCI_RESET_TIMEWAIT);
5187656SSherry.Moore@Sun.COM 	}
5197656SSherry.Moore@Sun.COM 
5207656SSherry.Moore@Sun.COM 	/* Reset the EHCI host controller */
5217656SSherry.Moore@Sun.COM 	Set_OpReg(ehci_command,
5227656SSherry.Moore@Sun.COM 	    Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET);
5237656SSherry.Moore@Sun.COM 
524*9212SZhigang.Lu@Sun.COM #ifndef lint
525*9212SZhigang.Lu@Sun.COM 	_NOTE(COMPETING_THREADS_NOW);
526*9212SZhigang.Lu@Sun.COM #endif
5277656SSherry.Moore@Sun.COM 	return (DDI_SUCCESS);
5287656SSherry.Moore@Sun.COM }
5297656SSherry.Moore@Sun.COM 
5307656SSherry.Moore@Sun.COM 
5317656SSherry.Moore@Sun.COM /*
5320Sstevel@tonic-gate  * ehci_info:
5330Sstevel@tonic-gate  */
5340Sstevel@tonic-gate /* ARGSUSED */
5350Sstevel@tonic-gate static int
ehci_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)5360Sstevel@tonic-gate ehci_info(dev_info_t		*dip,
5370Sstevel@tonic-gate 	ddi_info_cmd_t		infocmd,
5380Sstevel@tonic-gate 	void			*arg,
5390Sstevel@tonic-gate 	void			**result)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 	dev_t			dev;
5420Sstevel@tonic-gate 	ehci_state_t		*ehcip;
5430Sstevel@tonic-gate 	int			instance;
5440Sstevel@tonic-gate 	int			error = DDI_FAILURE;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	switch (infocmd) {
5470Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
5480Sstevel@tonic-gate 		dev = (dev_t)arg;
5490Sstevel@tonic-gate 		instance = EHCI_UNIT(dev);
5500Sstevel@tonic-gate 		ehcip = ddi_get_soft_state(ehci_statep, instance);
5510Sstevel@tonic-gate 		if (ehcip != NULL) {
5520Sstevel@tonic-gate 			*result = (void *)ehcip->ehci_dip;
5530Sstevel@tonic-gate 			if (*result != NULL) {
5540Sstevel@tonic-gate 				error = DDI_SUCCESS;
5550Sstevel@tonic-gate 			}
5560Sstevel@tonic-gate 		} else {
5570Sstevel@tonic-gate 			*result = NULL;
5580Sstevel@tonic-gate 		}
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 		break;
5610Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
5620Sstevel@tonic-gate 		dev = (dev_t)arg;
5630Sstevel@tonic-gate 		instance = EHCI_UNIT(dev);
5640Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
5650Sstevel@tonic-gate 		error = DDI_SUCCESS;
5660Sstevel@tonic-gate 		break;
5670Sstevel@tonic-gate 	default:
5680Sstevel@tonic-gate 		break;
5690Sstevel@tonic-gate 	}
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	return (error);
5720Sstevel@tonic-gate }
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate /*
5760Sstevel@tonic-gate  * EHCI CB_OPS entry points.
5770Sstevel@tonic-gate  */
5780Sstevel@tonic-gate static dev_info_t *
ehci_get_dip(dev_t dev)5790Sstevel@tonic-gate ehci_get_dip(dev_t	dev)
5800Sstevel@tonic-gate {
5810Sstevel@tonic-gate 	int		instance = EHCI_UNIT(dev);
5820Sstevel@tonic-gate 	ehci_state_t	*ehcip = ddi_get_soft_state(ehci_statep, instance);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if (ehcip) {
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 		return (ehcip->ehci_dip);
5870Sstevel@tonic-gate 	} else {
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 		return (NULL);
5900Sstevel@tonic-gate 	}
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate static int
ehci_open(dev_t * devp,int flags,int otyp,cred_t * credp)5950Sstevel@tonic-gate ehci_open(dev_t		*devp,
5960Sstevel@tonic-gate 	int		flags,
5970Sstevel@tonic-gate 	int		otyp,
5980Sstevel@tonic-gate 	cred_t		*credp)
5990Sstevel@tonic-gate {
6000Sstevel@tonic-gate 	dev_info_t	*dip = ehci_get_dip(*devp);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	return (usba_hubdi_open(dip, devp, flags, otyp, credp));
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate static int
ehci_close(dev_t dev,int flag,int otyp,cred_t * credp)6070Sstevel@tonic-gate ehci_close(dev_t	dev,
6080Sstevel@tonic-gate 	int		flag,
6090Sstevel@tonic-gate 	int		otyp,
6100Sstevel@tonic-gate 	cred_t		*credp)
6110Sstevel@tonic-gate {
6120Sstevel@tonic-gate 	dev_info_t	*dip = ehci_get_dip(dev);
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	return (usba_hubdi_close(dip, dev, flag, otyp, credp));
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate static int
ehci_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)6190Sstevel@tonic-gate ehci_ioctl(dev_t	dev,
6200Sstevel@tonic-gate 	int		cmd,
6210Sstevel@tonic-gate 	intptr_t	arg,
6220Sstevel@tonic-gate 	int		mode,
6230Sstevel@tonic-gate 	cred_t		*credp,
6240Sstevel@tonic-gate 	int		*rvalp)
6250Sstevel@tonic-gate {
6260Sstevel@tonic-gate 	dev_info_t	*dip = ehci_get_dip(dev);
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	return (usba_hubdi_ioctl(dip,
6290Sstevel@tonic-gate 	    dev, cmd, arg, mode, credp, rvalp));
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate /*
6330Sstevel@tonic-gate  * EHCI Interrupt Handler entry point.
6340Sstevel@tonic-gate  */
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate /*
6370Sstevel@tonic-gate  * ehci_intr:
6380Sstevel@tonic-gate  *
6390Sstevel@tonic-gate  * EHCI (EHCI) interrupt handling routine.
6400Sstevel@tonic-gate  */
6410Sstevel@tonic-gate uint_t
ehci_intr(caddr_t arg1,caddr_t arg2)642965Sgovinda ehci_intr(caddr_t arg1, caddr_t arg2)
6430Sstevel@tonic-gate {
6440Sstevel@tonic-gate 	uint_t			intr;
6457492SZhigang.Lu@Sun.COM 	ehci_state_t		*ehcip = (void *)arg1;
6460Sstevel@tonic-gate 
6473255Slg150142 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
6486898Sfb209375 	    "ehci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p",
6496898Sfb209375 	    (void *)arg1, (void *)arg2);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	/* Get the ehci global mutex */
6520Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
6530Sstevel@tonic-gate 
6545773Sqz150045 	/* Any interrupt is not handled for the suspended device. */
6555773Sqz150045 	if (ehcip->ehci_hc_soft_state == EHCI_CTLR_SUSPEND_STATE) {
6565773Sqz150045 		mutex_exit(&ehcip->ehci_int_mutex);
6575773Sqz150045 
6585773Sqz150045 		return (DDI_INTR_UNCLAIMED);
6595773Sqz150045 	}
6605773Sqz150045 
6610Sstevel@tonic-gate 	/*
6620Sstevel@tonic-gate 	 * Now process the actual ehci interrupt events  that caused
6630Sstevel@tonic-gate 	 * invocation of this ehci interrupt handler.
6640Sstevel@tonic-gate 	 */
6650Sstevel@tonic-gate 	intr = (Get_OpReg(ehci_status) & Get_OpReg(ehci_interrupt));
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	/* Update kstat values */
6680Sstevel@tonic-gate 	ehci_do_intrs_stats(ehcip, intr);
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	/*
6710Sstevel@tonic-gate 	 * We could have gotten a spurious interrupts. If so, do not
6720Sstevel@tonic-gate 	 * claim it.  This is quite  possible on some  architectures
6730Sstevel@tonic-gate 	 * where more than one PCI slots share the IRQs.  If so, the
6740Sstevel@tonic-gate 	 * associated driver's interrupt routine may get called even
6750Sstevel@tonic-gate 	 * if the interrupt is not meant for them.
6760Sstevel@tonic-gate 	 *
6770Sstevel@tonic-gate 	 * By unclaiming the interrupt, the other driver gets chance
6780Sstevel@tonic-gate 	 * to service its interrupt.
6790Sstevel@tonic-gate 	 */
6800Sstevel@tonic-gate 	if (!intr) {
6810Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
6840Sstevel@tonic-gate 	}
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	/* Acknowledge the interrupt */
6870Sstevel@tonic-gate 	Set_OpReg(ehci_status, intr);
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (ehcip->ehci_hc_soft_state == EHCI_CTLR_ERROR_STATE) {
6900Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 		return (DDI_INTR_CLAIMED);
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
6960Sstevel@tonic-gate 	    "Interrupt status 0x%x", intr);
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	/*
6990Sstevel@tonic-gate 	 * If necessary broadcast that an interrupt has occured.  This
7000Sstevel@tonic-gate 	 * is only necessary during controller init.
7010Sstevel@tonic-gate 	 */
7020Sstevel@tonic-gate 	if (ehcip->ehci_flags & EHCI_CV_INTR) {
7030Sstevel@tonic-gate 		ehcip->ehci_flags &= ~EHCI_CV_INTR;
7040Sstevel@tonic-gate 		cv_broadcast(&ehcip->ehci_async_schedule_advance_cv);
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	/* Check for Frame List Rollover */
7080Sstevel@tonic-gate 	if (intr & EHCI_INTR_FRAME_LIST_ROLLOVER) {
7091458Syq193411 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
7100Sstevel@tonic-gate 		    "ehci_intr: Frame List Rollover");
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 		ehci_handle_frame_list_rollover(ehcip);
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 		/* VIA VT6202 looses EHCI_INTR_USB interrupts, workaround. */
7150Sstevel@tonic-gate 		if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) &&
7160Sstevel@tonic-gate 		    (ehci_vt62x2_workaround & EHCI_VIA_LOST_INTERRUPTS)) {
7170Sstevel@tonic-gate 			ehcip->ehci_missed_intr_sts |= EHCI_INTR_USB;
7180Sstevel@tonic-gate 		}
7190Sstevel@tonic-gate 	}
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	/* Check for Advance on Asynchronous Schedule */
7220Sstevel@tonic-gate 	if (intr & EHCI_INTR_ASYNC_ADVANCE) {
7230Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
7240Sstevel@tonic-gate 		    "ehci_intr: Asynchronous Schedule Advance Notification");
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 		/* Disable async list advance interrupt */
7270Sstevel@tonic-gate 		Set_OpReg(ehci_interrupt,
7280Sstevel@tonic-gate 		    (Get_OpReg(ehci_interrupt) & ~EHCI_INTR_ASYNC_ADVANCE));
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 		/*
7310Sstevel@tonic-gate 		 * Call cv_broadcast on every this interrupt to wakeup
7320Sstevel@tonic-gate 		 * all the threads that are waiting the async list advance
7330Sstevel@tonic-gate 		 * event.
7340Sstevel@tonic-gate 		 */
7350Sstevel@tonic-gate 		cv_broadcast(&ehcip->ehci_async_schedule_advance_cv);
7360Sstevel@tonic-gate 	}
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	/* Always process completed itds */
7390Sstevel@tonic-gate 	ehci_traverse_active_isoc_list(ehcip);
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	/*
7420Sstevel@tonic-gate 	 * Check for any USB transaction completion notification. Also
7430Sstevel@tonic-gate 	 * process any missed USB transaction completion interrupts.
7440Sstevel@tonic-gate 	 */
7450Sstevel@tonic-gate 	if ((intr & EHCI_INTR_USB) || (intr & EHCI_INTR_USB_ERROR) ||
7460Sstevel@tonic-gate 	    (ehcip->ehci_missed_intr_sts & EHCI_INTR_USB) ||
7470Sstevel@tonic-gate 	    (ehcip->ehci_missed_intr_sts & EHCI_INTR_USB_ERROR)) {
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
7500Sstevel@tonic-gate 		    "ehci_intr: USB Transaction Completion Notification");
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 		/* Clear missed interrupts */
7530Sstevel@tonic-gate 		if (ehcip->ehci_missed_intr_sts) {
7540Sstevel@tonic-gate 			ehcip->ehci_missed_intr_sts = 0;
7550Sstevel@tonic-gate 		}
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 		/* Process completed qtds */
7580Sstevel@tonic-gate 		ehci_traverse_active_qtd_list(ehcip);
7590Sstevel@tonic-gate 	}
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	/* Process endpoint reclamation list */
7620Sstevel@tonic-gate 	if (ehcip->ehci_reclaim_list) {
7630Sstevel@tonic-gate 		ehci_handle_endpoint_reclaimation(ehcip);
7640Sstevel@tonic-gate 	}
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	/* Check for Host System Error */
7670Sstevel@tonic-gate 	if (intr & EHCI_INTR_HOST_SYSTEM_ERROR) {
7680Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
7690Sstevel@tonic-gate 		    "ehci_intr: Unrecoverable error");
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 		ehci_handle_ue(ehcip);
7720Sstevel@tonic-gate 	}
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	/*
7750Sstevel@tonic-gate 	 * Read interrupt status register to make sure that any PIO
7760Sstevel@tonic-gate 	 * store to clear the ISR has made it on the PCI bus before
7770Sstevel@tonic-gate 	 * returning from its interrupt handler.
7780Sstevel@tonic-gate 	 */
7790Sstevel@tonic-gate 	(void) Get_OpReg(ehci_status);
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	/* Release the ehci global mutex */
7820Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
7830Sstevel@tonic-gate 
7843255Slg150142 	USB_DPRINTF_L4(PRINT_MASK_INTR,  ehcip->ehci_log_hdl,
7850Sstevel@tonic-gate 	    "Interrupt handling completed");
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);
7880Sstevel@tonic-gate }
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate /*
7920Sstevel@tonic-gate  * EHCI HCDI entry points
7930Sstevel@tonic-gate  *
7940Sstevel@tonic-gate  * The Host Controller Driver Interfaces (HCDI) are the software interfaces
7950Sstevel@tonic-gate  * between the Universal Serial Bus Layer (USBA) and the Host Controller
7960Sstevel@tonic-gate  * Driver (HCD). The HCDI interfaces or entry points are subject to change.
7970Sstevel@tonic-gate  */
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate /*
8000Sstevel@tonic-gate  * ehci_hcdi_pipe_open:
8010Sstevel@tonic-gate  *
8020Sstevel@tonic-gate  * Member of HCD Ops structure and called during client specific pipe open
8030Sstevel@tonic-gate  * Add the pipe to the data structure representing the device and allocate
8040Sstevel@tonic-gate  * bandwidth for the pipe if it is a interrupt or isochronous endpoint.
8050Sstevel@tonic-gate  */
8060Sstevel@tonic-gate int
ehci_hcdi_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t flags)8070Sstevel@tonic-gate ehci_hcdi_pipe_open(
8080Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
8090Sstevel@tonic-gate 	usb_flags_t		flags)
8100Sstevel@tonic-gate {
8110Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
8125773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
8130Sstevel@tonic-gate 	usb_ep_descr_t		*epdt = &ph->p_ep;
8140Sstevel@tonic-gate 	int			rval, error = USB_SUCCESS;
8150Sstevel@tonic-gate 	int			kmflag = (flags & USB_FLAGS_SLEEP) ?
8165773Sqz150045 	    KM_SLEEP : KM_NOSLEEP;
8170Sstevel@tonic-gate 	uchar_t			smask = 0;
8180Sstevel@tonic-gate 	uchar_t			cmask = 0;
8190Sstevel@tonic-gate 	uint_t			pnode = 0;
8200Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
8230Sstevel@tonic-gate 	    "ehci_hcdi_pipe_open: addr = 0x%x, ep%d",
8240Sstevel@tonic-gate 	    ph->p_usba_device->usb_addr,
8250Sstevel@tonic-gate 	    epdt->bEndpointAddress & USB_EP_NUM_MASK);
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
8280Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
8290Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 		return (rval);
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	/*
8370Sstevel@tonic-gate 	 * Check and handle root hub pipe open.
8380Sstevel@tonic-gate 	 */
8390Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 		mutex_enter(&ehcip->ehci_int_mutex);
8420Sstevel@tonic-gate 		error = ehci_handle_root_hub_pipe_open(ph, flags);
8430Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 		return (error);
8460Sstevel@tonic-gate 	}
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	/*
8490Sstevel@tonic-gate 	 * Opening of other pipes excluding root hub pipe are
8500Sstevel@tonic-gate 	 * handled below. Check whether pipe is already opened.
8510Sstevel@tonic-gate 	 */
8520Sstevel@tonic-gate 	if (ph->p_hcd_private) {
8530Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
8540Sstevel@tonic-gate 		    "ehci_hcdi_pipe_open: Pipe is already opened");
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 		return (USB_FAILURE);
8570Sstevel@tonic-gate 	}
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	/*
8600Sstevel@tonic-gate 	 * A portion of the bandwidth is reserved for the non-periodic
8610Sstevel@tonic-gate 	 * transfers, i.e control and bulk transfers in each of one
8620Sstevel@tonic-gate 	 * millisecond frame period & usually it will be 20% of frame
8630Sstevel@tonic-gate 	 * period. Hence there is no need to check for the available
8640Sstevel@tonic-gate 	 * bandwidth before adding the control or bulk endpoints.
8650Sstevel@tonic-gate 	 *
8660Sstevel@tonic-gate 	 * There is a need to check for the available bandwidth before
8670Sstevel@tonic-gate 	 * adding the periodic transfers, i.e interrupt & isochronous,
8680Sstevel@tonic-gate 	 * since all these periodic transfers are guaranteed transfers.
8690Sstevel@tonic-gate 	 * Usually 80% of the total frame time is reserved for periodic
8700Sstevel@tonic-gate 	 * transfers.
8710Sstevel@tonic-gate 	 */
8720Sstevel@tonic-gate 	if (EHCI_PERIODIC_ENDPOINT(epdt)) {
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 		mutex_enter(&ehcip->ehci_int_mutex);
8750Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 		error = ehci_allocate_bandwidth(ehcip,
8780Sstevel@tonic-gate 		    ph, &pnode, &smask, &cmask);
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 		if (error != USB_SUCCESS) {
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
8830Sstevel@tonic-gate 			    "ehci_hcdi_pipe_open: Bandwidth allocation failed");
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 			mutex_exit(&ph->p_mutex);
8860Sstevel@tonic-gate 			mutex_exit(&ehcip->ehci_int_mutex);
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 			return (error);
8890Sstevel@tonic-gate 		}
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
8920Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
8930Sstevel@tonic-gate 	}
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	/* Create the HCD pipe private structure */
8960Sstevel@tonic-gate 	pp = kmem_zalloc(sizeof (ehci_pipe_private_t), kmflag);
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	/*
8990Sstevel@tonic-gate 	 * Return failure if ehci pipe private
9000Sstevel@tonic-gate 	 * structure allocation fails.
9010Sstevel@tonic-gate 	 */
9020Sstevel@tonic-gate 	if (pp == NULL) {
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 		mutex_enter(&ehcip->ehci_int_mutex);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 		/* Deallocate bandwidth */
9070Sstevel@tonic-gate 		if (EHCI_PERIODIC_ENDPOINT(epdt)) {
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 			mutex_enter(&ph->p_mutex);
9100Sstevel@tonic-gate 			ehci_deallocate_bandwidth(ehcip,
9110Sstevel@tonic-gate 			    ph, pnode, smask, cmask);
9120Sstevel@tonic-gate 			mutex_exit(&ph->p_mutex);
9130Sstevel@tonic-gate 		}
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
9180Sstevel@tonic-gate 	}
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	/* Save periodic nodes */
9230Sstevel@tonic-gate 	pp->pp_pnode = pnode;
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	/* Save start and complete split mask values */
9260Sstevel@tonic-gate 	pp->pp_smask = smask;
9270Sstevel@tonic-gate 	pp->pp_cmask = cmask;
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	/* Create prototype for xfer completion condition variable */
9300Sstevel@tonic-gate 	cv_init(&pp->pp_xfer_cmpl_cv, NULL, CV_DRIVER, NULL);
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	/* Set the state of pipe as idle */
9330Sstevel@tonic-gate 	pp->pp_state = EHCI_PIPE_STATE_IDLE;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	/* Store a pointer to the pipe handle */
9360Sstevel@tonic-gate 	pp->pp_pipe_handle = ph;
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	/* Store the pointer in the pipe handle */
9410Sstevel@tonic-gate 	ph->p_hcd_private = (usb_opaque_t)pp;
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	/* Store a copy of the pipe policy */
9440Sstevel@tonic-gate 	bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t));
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	/* Allocate the host controller endpoint descriptor */
9490Sstevel@tonic-gate 	pp->pp_qh = ehci_alloc_qh(ehcip, ph, NULL);
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	/* Initialize the halting flag */
9520Sstevel@tonic-gate 	pp->pp_halt_state = EHCI_HALT_STATE_FREE;
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	/* Create prototype for halt completion condition variable */
9550Sstevel@tonic-gate 	cv_init(&pp->pp_halt_cmpl_cv, NULL, CV_DRIVER, NULL);
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	/* Isoch does not use QH, so ignore this */
9580Sstevel@tonic-gate 	if ((pp->pp_qh == NULL) && !(EHCI_ISOC_ENDPOINT(epdt))) {
9590Sstevel@tonic-gate 		ASSERT(pp->pp_qh == NULL);
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
9620Sstevel@tonic-gate 		    "ehci_hcdi_pipe_open: QH allocation failed");
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 		/* Deallocate bandwidth */
9670Sstevel@tonic-gate 		if (EHCI_PERIODIC_ENDPOINT(epdt)) {
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 			ehci_deallocate_bandwidth(ehcip,
9700Sstevel@tonic-gate 			    ph, pnode, smask, cmask);
9710Sstevel@tonic-gate 		}
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 		/* Destroy the xfer completion condition variable */
9740Sstevel@tonic-gate 		cv_destroy(&pp->pp_xfer_cmpl_cv);
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 		/*
9770Sstevel@tonic-gate 		 * Deallocate the hcd private portion
9780Sstevel@tonic-gate 		 * of the pipe handle.
9790Sstevel@tonic-gate 		 */
9800Sstevel@tonic-gate 		kmem_free(ph->p_hcd_private, sizeof (ehci_pipe_private_t));
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 		/*
9830Sstevel@tonic-gate 		 * Set the private structure in the
9840Sstevel@tonic-gate 		 * pipe handle equal to NULL.
9850Sstevel@tonic-gate 		 */
9860Sstevel@tonic-gate 		ph->p_hcd_private = NULL;
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
9890Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
9920Sstevel@tonic-gate 	}
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	/*
9950Sstevel@tonic-gate 	 * Isoch does not use QH so no need to
9960Sstevel@tonic-gate 	 * restore data toggle or insert QH
9970Sstevel@tonic-gate 	 */
9980Sstevel@tonic-gate 	if (!(EHCI_ISOC_ENDPOINT(epdt))) {
9990Sstevel@tonic-gate 		/* Restore the data toggle information */
10000Sstevel@tonic-gate 		ehci_restore_data_toggle(ehcip, ph);
10010Sstevel@tonic-gate 	}
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	/*
10040Sstevel@tonic-gate 	 * Insert the endpoint onto the host controller's
10050Sstevel@tonic-gate 	 * appropriate endpoint list. The host controller
10060Sstevel@tonic-gate 	 * will not schedule this endpoint and will not have
10070Sstevel@tonic-gate 	 * any QTD's to process.  It will also update the pipe count.
10080Sstevel@tonic-gate 	 */
10090Sstevel@tonic-gate 	ehci_insert_qh(ehcip, ph);
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
10120Sstevel@tonic-gate 	    "ehci_hcdi_pipe_open: ph = 0x%p", (void *)ph);
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	ehcip->ehci_open_pipe_count++;
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	return (USB_SUCCESS);
10190Sstevel@tonic-gate }
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate /*
10230Sstevel@tonic-gate  * ehci_hcdi_pipe_close:
10240Sstevel@tonic-gate  *
10250Sstevel@tonic-gate  * Member of HCD Ops structure and called during the client  specific pipe
10260Sstevel@tonic-gate  * close. Remove the pipe and the data structure representing the device.
10270Sstevel@tonic-gate  * Deallocate  bandwidth for the pipe if it is a interrupt or isochronous
10280Sstevel@tonic-gate  * endpoint.
10290Sstevel@tonic-gate  */
10300Sstevel@tonic-gate /* ARGSUSED */
10310Sstevel@tonic-gate int
ehci_hcdi_pipe_close(usba_pipe_handle_data_t * ph,usb_flags_t flags)10320Sstevel@tonic-gate ehci_hcdi_pipe_close(
10330Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
10340Sstevel@tonic-gate 	usb_flags_t		flags)
10350Sstevel@tonic-gate {
10360Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
10375773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
10380Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
10390Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
10400Sstevel@tonic-gate 	int			error = USB_SUCCESS;
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
10430Sstevel@tonic-gate 	    "ehci_hcdi_pipe_close: addr = 0x%x, ep%d",
10440Sstevel@tonic-gate 	    ph->p_usba_device->usb_addr,
10450Sstevel@tonic-gate 	    eptd->bEndpointAddress & USB_EP_NUM_MASK);
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	/* Check and handle root hub pipe close */
10480Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 		mutex_enter(&ehcip->ehci_int_mutex);
10510Sstevel@tonic-gate 		error = ehci_handle_root_hub_pipe_close(ph);
10520Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 		return (error);
10550Sstevel@tonic-gate 	}
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	ASSERT(ph->p_hcd_private != NULL);
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	/* Set pipe state to pipe close */
10620Sstevel@tonic-gate 	pp->pp_state = EHCI_PIPE_STATE_CLOSE;
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	ehci_pipe_cleanup(ehcip, ph);
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	/*
10670Sstevel@tonic-gate 	 * Remove the endpoint descriptor from Host
10680Sstevel@tonic-gate 	 * Controller's appropriate endpoint list.
10690Sstevel@tonic-gate 	 */
10700Sstevel@tonic-gate 	ehci_remove_qh(ehcip, pp, B_TRUE);
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	/* Deallocate bandwidth */
10730Sstevel@tonic-gate 	if (EHCI_PERIODIC_ENDPOINT(eptd)) {
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
10760Sstevel@tonic-gate 		ehci_deallocate_bandwidth(ehcip, ph, pp->pp_pnode,
10770Sstevel@tonic-gate 		    pp->pp_smask, pp->pp_cmask);
10780Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
10790Sstevel@tonic-gate 	}
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	/* Destroy the xfer completion condition variable */
10840Sstevel@tonic-gate 	cv_destroy(&pp->pp_xfer_cmpl_cv);
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	/* Destory halt completion condition variable */
10880Sstevel@tonic-gate 	cv_destroy(&pp->pp_halt_cmpl_cv);
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	/*
10910Sstevel@tonic-gate 	 * Deallocate the hcd private portion
10920Sstevel@tonic-gate 	 * of the pipe handle.
10930Sstevel@tonic-gate 	 */
10940Sstevel@tonic-gate 	kmem_free(ph->p_hcd_private, sizeof (ehci_pipe_private_t));
10950Sstevel@tonic-gate 	ph->p_hcd_private = NULL;
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
11000Sstevel@tonic-gate 	    "ehci_hcdi_pipe_close: ph = 0x%p", (void *)ph);
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	ehcip->ehci_open_pipe_count--;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 	return (error);
11070Sstevel@tonic-gate }
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate /*
11110Sstevel@tonic-gate  * ehci_hcdi_pipe_reset:
11120Sstevel@tonic-gate  */
11130Sstevel@tonic-gate /* ARGSUSED */
11140Sstevel@tonic-gate int
ehci_hcdi_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)11150Sstevel@tonic-gate ehci_hcdi_pipe_reset(
11160Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
11170Sstevel@tonic-gate 	usb_flags_t		usb_flags)
11180Sstevel@tonic-gate {
11190Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
11205773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
11210Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
11220Sstevel@tonic-gate 	int			error = USB_SUCCESS;
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
11250Sstevel@tonic-gate 	    "ehci_hcdi_pipe_reset:");
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 	/*
11280Sstevel@tonic-gate 	 * Check and handle root hub pipe reset.
11290Sstevel@tonic-gate 	 */
11300Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 		error = ehci_handle_root_hub_pipe_reset(ph, usb_flags);
11330Sstevel@tonic-gate 		return (error);
11340Sstevel@tonic-gate 	}
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	/* Set pipe state to pipe reset */
11390Sstevel@tonic-gate 	pp->pp_state = EHCI_PIPE_STATE_RESET;
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	ehci_pipe_cleanup(ehcip, ph);
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	return (error);
11460Sstevel@tonic-gate }
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate /*
11498945SGuoqing.Zhu@Sun.COM  * ehci_hcdi_pipe_reset_data_toggle:
11508945SGuoqing.Zhu@Sun.COM  */
11518945SGuoqing.Zhu@Sun.COM void
ehci_hcdi_pipe_reset_data_toggle(usba_pipe_handle_data_t * ph)11528945SGuoqing.Zhu@Sun.COM ehci_hcdi_pipe_reset_data_toggle(
11538945SGuoqing.Zhu@Sun.COM 	usba_pipe_handle_data_t	*ph)
11548945SGuoqing.Zhu@Sun.COM {
11558945SGuoqing.Zhu@Sun.COM 	ehci_state_t		*ehcip = ehci_obtain_state(
11568945SGuoqing.Zhu@Sun.COM 	    ph->p_usba_device->usb_root_hub_dip);
11578945SGuoqing.Zhu@Sun.COM 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
11588945SGuoqing.Zhu@Sun.COM 
11598945SGuoqing.Zhu@Sun.COM 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
11608945SGuoqing.Zhu@Sun.COM 	    "ehci_hcdi_pipe_reset_data_toggle:");
11618945SGuoqing.Zhu@Sun.COM 
11628945SGuoqing.Zhu@Sun.COM 	mutex_enter(&ehcip->ehci_int_mutex);
11638945SGuoqing.Zhu@Sun.COM 
11648945SGuoqing.Zhu@Sun.COM 	mutex_enter(&ph->p_mutex);
11658945SGuoqing.Zhu@Sun.COM 	usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress,
11668945SGuoqing.Zhu@Sun.COM 	    DATA0);
11678945SGuoqing.Zhu@Sun.COM 	mutex_exit(&ph->p_mutex);
11688945SGuoqing.Zhu@Sun.COM 
11698945SGuoqing.Zhu@Sun.COM 	Set_QH(pp->pp_qh->qh_status,
11708945SGuoqing.Zhu@Sun.COM 	    Get_QH(pp->pp_qh->qh_status) & (~EHCI_QH_STS_DATA_TOGGLE));
11718945SGuoqing.Zhu@Sun.COM 	mutex_exit(&ehcip->ehci_int_mutex);
11728945SGuoqing.Zhu@Sun.COM 
11738945SGuoqing.Zhu@Sun.COM }
11748945SGuoqing.Zhu@Sun.COM 
11758945SGuoqing.Zhu@Sun.COM /*
11760Sstevel@tonic-gate  * ehci_hcdi_pipe_ctrl_xfer:
11770Sstevel@tonic-gate  */
11780Sstevel@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)11790Sstevel@tonic-gate ehci_hcdi_pipe_ctrl_xfer(
11800Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
11810Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_reqp,
11820Sstevel@tonic-gate 	usb_flags_t		usb_flags)
11830Sstevel@tonic-gate {
11840Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
11855773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
11860Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
11870Sstevel@tonic-gate 	int			rval;
11880Sstevel@tonic-gate 	int			error = USB_SUCCESS;
11890Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
11920Sstevel@tonic-gate 	    "ehci_hcdi_pipe_ctrl_xfer: ph = 0x%p reqp = 0x%p flags = %x",
11936898Sfb209375 	    (void *)ph, (void *)ctrl_reqp, usb_flags);
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
11960Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
11970Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 		return (rval);
12020Sstevel@tonic-gate 	}
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	/*
12050Sstevel@tonic-gate 	 * Check and handle root hub control request.
12060Sstevel@tonic-gate 	 */
12070Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 		error = ehci_handle_root_hub_request(ehcip, ph, ctrl_reqp);
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 		return (error);
12120Sstevel@tonic-gate 	}
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	/*
12170Sstevel@tonic-gate 	 *  Check whether pipe is in halted state.
12180Sstevel@tonic-gate 	 */
12190Sstevel@tonic-gate 	if (pp->pp_state == EHCI_PIPE_STATE_ERROR) {
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
12220Sstevel@tonic-gate 		    "ehci_hcdi_pipe_ctrl_xfer: "
12230Sstevel@tonic-gate 		    "Pipe is in error state, need pipe reset to continue");
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 		return (USB_FAILURE);
12280Sstevel@tonic-gate 	}
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	/* Allocate a transfer wrapper */
12310Sstevel@tonic-gate 	if ((tw = ehci_allocate_ctrl_resources(ehcip, pp, ctrl_reqp,
12320Sstevel@tonic-gate 	    usb_flags)) == NULL) {
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 		error = USB_NO_RESOURCES;
12350Sstevel@tonic-gate 	} else {
12360Sstevel@tonic-gate 		/* Insert the qtd's on the endpoint */
12370Sstevel@tonic-gate 		ehci_insert_ctrl_req(ehcip, ph, ctrl_reqp, tw, usb_flags);
12380Sstevel@tonic-gate 	}
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 	return (error);
12430Sstevel@tonic-gate }
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate /*
12470Sstevel@tonic-gate  * ehci_hcdi_bulk_transfer_size:
12480Sstevel@tonic-gate  *
12490Sstevel@tonic-gate  * Return maximum bulk transfer size
12500Sstevel@tonic-gate  */
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate /* ARGSUSED */
12530Sstevel@tonic-gate int
ehci_hcdi_bulk_transfer_size(usba_device_t * usba_device,size_t * size)12540Sstevel@tonic-gate ehci_hcdi_bulk_transfer_size(
12550Sstevel@tonic-gate 	usba_device_t	*usba_device,
12560Sstevel@tonic-gate 	size_t		*size)
12570Sstevel@tonic-gate {
12580Sstevel@tonic-gate 	ehci_state_t	*ehcip = ehci_obtain_state(
12595773Sqz150045 	    usba_device->usb_root_hub_dip);
12600Sstevel@tonic-gate 	int		rval;
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
12630Sstevel@tonic-gate 	    "ehci_hcdi_bulk_transfer_size:");
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
12660Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
12670Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate 		return (rval);
12720Sstevel@tonic-gate 	}
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	/* VIA VT6202 may not handle bigger xfers well, workaround. */
12750Sstevel@tonic-gate 	if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) &&
12760Sstevel@tonic-gate 	    (ehci_vt62x2_workaround & EHCI_VIA_REDUCED_MAX_BULK_XFER_SIZE)) {
12770Sstevel@tonic-gate 		*size = EHCI_VIA_MAX_BULK_XFER_SIZE;
12780Sstevel@tonic-gate 	} else {
12790Sstevel@tonic-gate 		*size = EHCI_MAX_BULK_XFER_SIZE;
12800Sstevel@tonic-gate 	}
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 	return (USB_SUCCESS);
12830Sstevel@tonic-gate }
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate /*
12870Sstevel@tonic-gate  * ehci_hcdi_pipe_bulk_xfer:
12880Sstevel@tonic-gate  */
12890Sstevel@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)12900Sstevel@tonic-gate ehci_hcdi_pipe_bulk_xfer(
12910Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
12920Sstevel@tonic-gate 	usb_bulk_req_t		*bulk_reqp,
12930Sstevel@tonic-gate 	usb_flags_t		usb_flags)
12940Sstevel@tonic-gate {
12950Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
12965773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
12970Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
12980Sstevel@tonic-gate 	int			rval, error = USB_SUCCESS;
12990Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
13020Sstevel@tonic-gate 	    "ehci_hcdi_pipe_bulk_xfer: ph = 0x%p reqp = 0x%p flags = %x",
13036898Sfb209375 	    (void *)ph, (void *)bulk_reqp, usb_flags);
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
13060Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
13090Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 		return (rval);
13120Sstevel@tonic-gate 	}
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	/*
13150Sstevel@tonic-gate 	 *  Check whether pipe is in halted state.
13160Sstevel@tonic-gate 	 */
13170Sstevel@tonic-gate 	if (pp->pp_state == EHCI_PIPE_STATE_ERROR) {
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
13200Sstevel@tonic-gate 		    "ehci_hcdi_pipe_bulk_xfer:"
13210Sstevel@tonic-gate 		    "Pipe is in error state, need pipe reset to continue");
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 		return (USB_FAILURE);
13260Sstevel@tonic-gate 	}
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	/* Allocate a transfer wrapper */
13290Sstevel@tonic-gate 	if ((tw = ehci_allocate_bulk_resources(ehcip, pp, bulk_reqp,
13300Sstevel@tonic-gate 	    usb_flags)) == NULL) {
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 		error = USB_NO_RESOURCES;
13330Sstevel@tonic-gate 	} else {
13340Sstevel@tonic-gate 		/* Add the QTD into the Host Controller's bulk list */
13350Sstevel@tonic-gate 		ehci_insert_bulk_req(ehcip, ph, bulk_reqp, tw, usb_flags);
13360Sstevel@tonic-gate 	}
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	return (error);
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate /*
13450Sstevel@tonic-gate  * ehci_hcdi_pipe_intr_xfer:
13460Sstevel@tonic-gate  */
13470Sstevel@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)13480Sstevel@tonic-gate ehci_hcdi_pipe_intr_xfer(
13490Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
13500Sstevel@tonic-gate 	usb_intr_req_t		*intr_reqp,
13510Sstevel@tonic-gate 	usb_flags_t		usb_flags)
13520Sstevel@tonic-gate {
13530Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
13545773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
13550Sstevel@tonic-gate 	int			pipe_dir, rval, error = USB_SUCCESS;
13560Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
13590Sstevel@tonic-gate 	    "ehci_hcdi_pipe_intr_xfer: ph = 0x%p reqp = 0x%p flags = %x",
13606898Sfb209375 	    (void *)ph, (void *)intr_reqp, usb_flags);
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
13630Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
13660Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 		return (rval);
13690Sstevel@tonic-gate 	}
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	/* Get the pipe direction */
13720Sstevel@tonic-gate 	pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 	if (pipe_dir == USB_EP_DIR_IN) {
13750Sstevel@tonic-gate 		error = ehci_start_periodic_pipe_polling(ehcip, ph,
13760Sstevel@tonic-gate 		    (usb_opaque_t)intr_reqp, usb_flags);
13770Sstevel@tonic-gate 	} else {
13780Sstevel@tonic-gate 		/* Allocate transaction resources */
13790Sstevel@tonic-gate 		if ((tw = ehci_allocate_intr_resources(ehcip, ph,
13800Sstevel@tonic-gate 		    intr_reqp, usb_flags)) == NULL) {
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 			error = USB_NO_RESOURCES;
13830Sstevel@tonic-gate 		} else {
13840Sstevel@tonic-gate 			ehci_insert_intr_req(ehcip,
13850Sstevel@tonic-gate 			    (ehci_pipe_private_t *)ph->p_hcd_private,
13860Sstevel@tonic-gate 			    tw, usb_flags);
13870Sstevel@tonic-gate 		}
13880Sstevel@tonic-gate 	}
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 	return (error);
13930Sstevel@tonic-gate }
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate /*
13960Sstevel@tonic-gate  * ehci_hcdi_pipe_stop_intr_polling()
13970Sstevel@tonic-gate  */
13980Sstevel@tonic-gate int
ehci_hcdi_pipe_stop_intr_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)13990Sstevel@tonic-gate ehci_hcdi_pipe_stop_intr_polling(
14000Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
14010Sstevel@tonic-gate 	usb_flags_t		flags)
14020Sstevel@tonic-gate {
14030Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
14045773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
14050Sstevel@tonic-gate 	int			error = USB_SUCCESS;
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
14080Sstevel@tonic-gate 	    "ehci_hcdi_pipe_stop_intr_polling: ph = 0x%p fl = 0x%x",
14090Sstevel@tonic-gate 	    (void *)ph, flags);
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	error = ehci_stop_periodic_pipe_polling(ehcip, ph, flags);
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 	return (error);
14180Sstevel@tonic-gate }
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate /*
14220Sstevel@tonic-gate  * ehci_hcdi_get_current_frame_number:
14230Sstevel@tonic-gate  *
14245773Sqz150045  * Get the current usb frame number.
14255773Sqz150045  * Return whether the request is handled successfully.
14260Sstevel@tonic-gate  */
14275773Sqz150045 int
ehci_hcdi_get_current_frame_number(usba_device_t * usba_device,usb_frame_number_t * frame_number)14285773Sqz150045 ehci_hcdi_get_current_frame_number(
14295773Sqz150045 	usba_device_t		*usba_device,
14305773Sqz150045 	usb_frame_number_t	*frame_number)
14310Sstevel@tonic-gate {
14320Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
14335773Sqz150045 	    usba_device->usb_root_hub_dip);
14340Sstevel@tonic-gate 	int			rval;
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	ehcip = ehci_obtain_state(usba_device->usb_root_hub_dip);
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
14390Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
14420Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 		return (rval);
14450Sstevel@tonic-gate 	}
14460Sstevel@tonic-gate 
14475773Sqz150045 	*frame_number = ehci_get_current_frame_number(ehcip);
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
14520Sstevel@tonic-gate 	    "ehci_hcdi_get_current_frame_number: "
14536898Sfb209375 	    "Current frame number 0x%llx", (unsigned long long)(*frame_number));
14540Sstevel@tonic-gate 
14555773Sqz150045 	return (rval);
14560Sstevel@tonic-gate }
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate /*
14600Sstevel@tonic-gate  * ehci_hcdi_get_max_isoc_pkts:
14610Sstevel@tonic-gate  *
14625773Sqz150045  * Get maximum isochronous packets per usb isochronous request.
14635773Sqz150045  * Return whether the request is handled successfully.
14640Sstevel@tonic-gate  */
14655773Sqz150045 int
ehci_hcdi_get_max_isoc_pkts(usba_device_t * usba_device,uint_t * max_isoc_pkts_per_request)14665773Sqz150045 ehci_hcdi_get_max_isoc_pkts(
14675773Sqz150045 	usba_device_t	*usba_device,
14685773Sqz150045 	uint_t		*max_isoc_pkts_per_request)
14690Sstevel@tonic-gate {
14700Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
14715773Sqz150045 	    usba_device->usb_root_hub_dip);
14720Sstevel@tonic-gate 	int			rval;
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
14750Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
14760Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 		return (rval);
14810Sstevel@tonic-gate 	}
14820Sstevel@tonic-gate 
14835773Sqz150045 	*max_isoc_pkts_per_request = EHCI_MAX_ISOC_PKTS_PER_XFER;
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
14860Sstevel@tonic-gate 	    "ehci_hcdi_get_max_isoc_pkts: maximum isochronous"
14870Sstevel@tonic-gate 	    "packets per usb isochronous request = 0x%x",
14886898Sfb209375 	    *max_isoc_pkts_per_request);
14890Sstevel@tonic-gate 
14905773Sqz150045 	return (rval);
14910Sstevel@tonic-gate }
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate /*
14950Sstevel@tonic-gate  * ehci_hcdi_pipe_isoc_xfer:
14960Sstevel@tonic-gate  */
14970Sstevel@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)14980Sstevel@tonic-gate ehci_hcdi_pipe_isoc_xfer(
14990Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
15000Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_reqp,
15010Sstevel@tonic-gate 	usb_flags_t		usb_flags)
15020Sstevel@tonic-gate {
15030Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
15045773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	int			pipe_dir, rval;
15070Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw;
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
15100Sstevel@tonic-gate 	    "ehci_hcdi_pipe_isoc_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x",
15116898Sfb209375 	    (void *)ph, (void *)isoc_reqp, usb_flags);
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
15140Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
15170Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate 		return (rval);
15200Sstevel@tonic-gate 	}
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	/* Get the isochronous pipe direction */
15230Sstevel@tonic-gate 	pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 	if (pipe_dir == USB_EP_DIR_IN) {
15260Sstevel@tonic-gate 		rval = ehci_start_periodic_pipe_polling(ehcip, ph,
15270Sstevel@tonic-gate 		    (usb_opaque_t)isoc_reqp, usb_flags);
15280Sstevel@tonic-gate 	} else {
15290Sstevel@tonic-gate 		/* Allocate transaction resources */
15300Sstevel@tonic-gate 		if ((itw = ehci_allocate_isoc_resources(ehcip, ph,
15310Sstevel@tonic-gate 		    isoc_reqp, usb_flags)) == NULL) {
15320Sstevel@tonic-gate 			rval = USB_NO_RESOURCES;
15330Sstevel@tonic-gate 		} else {
15340Sstevel@tonic-gate 			rval = ehci_insert_isoc_req(ehcip,
15350Sstevel@tonic-gate 			    (ehci_pipe_private_t *)ph->p_hcd_private,
15360Sstevel@tonic-gate 			    itw, usb_flags);
15370Sstevel@tonic-gate 		}
15380Sstevel@tonic-gate 	}
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	return (rval);
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 
15460Sstevel@tonic-gate /*
15470Sstevel@tonic-gate  * ehci_hcdi_pipe_stop_isoc_polling()
15480Sstevel@tonic-gate  */
15490Sstevel@tonic-gate /*ARGSUSED*/
15500Sstevel@tonic-gate int
ehci_hcdi_pipe_stop_isoc_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)15510Sstevel@tonic-gate ehci_hcdi_pipe_stop_isoc_polling(
15520Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
15530Sstevel@tonic-gate 	usb_flags_t		flags)
15540Sstevel@tonic-gate {
15550Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
15565773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
15570Sstevel@tonic-gate 	int			rval;
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
15600Sstevel@tonic-gate 	    "ehci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x",
15610Sstevel@tonic-gate 	    (void *)ph, flags);
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
15640Sstevel@tonic-gate 	rval = ehci_state_is_operational(ehcip);
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
15670Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate 		return (rval);
15700Sstevel@tonic-gate 	}
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 	rval = ehci_stop_periodic_pipe_polling(ehcip, ph, flags);
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	return (rval);
15770Sstevel@tonic-gate }
1578