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