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