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
52125Ssl147100 * Common Development and Distribution License (the "License").
62125Ssl147100 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12819SVincent.Wang@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * Universal Host Controller Driver (UHCI)
280Sstevel@tonic-gate *
290Sstevel@tonic-gate * The UHCI driver is a driver which interfaces to the Universal
300Sstevel@tonic-gate * Serial Bus Architecture (USBA) and the Host Controller (HC). The interface to
310Sstevel@tonic-gate * the Host Controller is defined by the Universal Host Controller Interface.
320Sstevel@tonic-gate * This file contains code for auto-configuration entry points and interrupt
330Sstevel@tonic-gate * handling.
340Sstevel@tonic-gate */
350Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcid.h>
360Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcihub.h>
370Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhciutil.h>
380Sstevel@tonic-gate
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate * Prototype Declarations for cb_ops and dev_ops
410Sstevel@tonic-gate */
420Sstevel@tonic-gate static int uhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
435773Sqz150045 static int uhci_add_intrs(uhci_state_t *uhcip, int intr_type);
440Sstevel@tonic-gate static int uhci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
45965Sgovinda static void uhci_rem_intrs(uhci_state_t *uhcip);
460Sstevel@tonic-gate static int uhci_open(dev_t *devp, int flags, int otyp, cred_t *credp);
470Sstevel@tonic-gate static int uhci_close(dev_t dev, int flag, int otyp, cred_t *credp);
480Sstevel@tonic-gate static int uhci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
490Sstevel@tonic-gate cred_t *credp, int *rvalp);
500Sstevel@tonic-gate static int uhci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd);
517656SSherry.Moore@Sun.COM static int uhci_quiesce(dev_info_t *dip);
520Sstevel@tonic-gate static int uhci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
530Sstevel@tonic-gate void **result);
540Sstevel@tonic-gate
555773Sqz150045 /* extern */
565773Sqz150045 int usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level);
575773Sqz150045
580Sstevel@tonic-gate static struct cb_ops uhci_cb_ops = {
590Sstevel@tonic-gate uhci_open, /* Open */
600Sstevel@tonic-gate uhci_close, /* Close */
610Sstevel@tonic-gate nodev, /* Strategy */
620Sstevel@tonic-gate nodev, /* Print */
630Sstevel@tonic-gate nodev, /* Dump */
640Sstevel@tonic-gate nodev, /* Read */
650Sstevel@tonic-gate nodev, /* Write */
660Sstevel@tonic-gate uhci_ioctl, /* Ioctl */
670Sstevel@tonic-gate nodev, /* Devmap */
680Sstevel@tonic-gate nodev, /* Mmap */
690Sstevel@tonic-gate nodev, /* Segmap */
700Sstevel@tonic-gate nochpoll, /* Poll */
710Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */
720Sstevel@tonic-gate NULL, /* Streamtab */
730Sstevel@tonic-gate D_MP /* Driver compatibility flag */
740Sstevel@tonic-gate };
750Sstevel@tonic-gate
760Sstevel@tonic-gate static struct dev_ops uhci_ops = {
770Sstevel@tonic-gate DEVO_REV, /* Devo_rev */
780Sstevel@tonic-gate 0, /* Refcnt */
790Sstevel@tonic-gate uhci_info, /* Info */
800Sstevel@tonic-gate nulldev, /* Identify */
810Sstevel@tonic-gate nulldev, /* Probe */
820Sstevel@tonic-gate uhci_attach, /* Attach */
830Sstevel@tonic-gate uhci_detach, /* Detach */
840Sstevel@tonic-gate uhci_reset, /* Reset */
850Sstevel@tonic-gate &uhci_cb_ops, /* Driver operations */
860Sstevel@tonic-gate &usba_hubdi_busops, /* Bus operations */
877656SSherry.Moore@Sun.COM usba_hubdi_root_hub_power, /* Power */
887656SSherry.Moore@Sun.COM uhci_quiesce /* quiesce */
890Sstevel@tonic-gate };
900Sstevel@tonic-gate
910Sstevel@tonic-gate static struct modldrv modldrv = {
920Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */
937425SGongtian.Zhao@Sun.COM "USB UHCI Controller Driver", /* Name of the module. */
940Sstevel@tonic-gate &uhci_ops, /* Driver ops */
950Sstevel@tonic-gate };
960Sstevel@tonic-gate
970Sstevel@tonic-gate static struct modlinkage modlinkage = {
980Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL
990Sstevel@tonic-gate };
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate * Globals
1030Sstevel@tonic-gate */
1040Sstevel@tonic-gate void *uhci_statep;
105880Sfrits uint_t uhci_errlevel = USB_LOG_L2;
106880Sfrits uint_t uhci_errmask = PRINT_MASK_ALL;
107880Sfrits uint_t uhci_instance_debug = (uint_t)-1;
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate uint_t uhci_td_pool_size = 256; /* Num TDs */
1100Sstevel@tonic-gate uint_t uhci_qh_pool_size = 130; /* Num QHs */
1110Sstevel@tonic-gate ushort_t uhci_tree_bottom_nodes[NUM_FRAME_LST_ENTRIES];
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate /*
115965Sgovinda * UHCI MSI tunable:
116965Sgovinda *
117965Sgovinda * By default MSI is enabled on all supported platforms.
118965Sgovinda */
119965Sgovinda boolean_t uhci_enable_msi = B_TRUE;
120965Sgovinda
121965Sgovinda /*
1220Sstevel@tonic-gate * tunable, delay during attach in seconds
1230Sstevel@tonic-gate */
1245773Sqz150045 int uhci_attach_wait = 0;
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate /* function prototypes */
1270Sstevel@tonic-gate static void uhci_handle_intr_td_errors(uhci_state_t *uhcip, uhci_td_t *td,
1280Sstevel@tonic-gate uhci_trans_wrapper_t *tw, uhci_pipe_private_t *pp);
1290Sstevel@tonic-gate static void uhci_handle_one_xfer_completion(uhci_state_t *uhcip,
1300Sstevel@tonic-gate usb_cr_t usb_err, uhci_td_t *td);
131965Sgovinda static uint_t uhci_intr(caddr_t arg1, caddr_t arg2);
1320Sstevel@tonic-gate static int uhci_cleanup(uhci_state_t *uhcip);
1335773Sqz150045 static int uhci_cpr_suspend(uhci_state_t *uhcip);
1345773Sqz150045 static int uhci_cpr_resume(uhci_state_t *uhcip);
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate int
_init(void)1380Sstevel@tonic-gate _init(void)
1390Sstevel@tonic-gate {
1400Sstevel@tonic-gate int error;
1410Sstevel@tonic-gate ushort_t i, j, k, *temp, num_of_nodes;
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate /* Initialize the soft state structures */
1440Sstevel@tonic-gate if ((error = ddi_soft_state_init(&uhci_statep, sizeof (uhci_state_t),
1450Sstevel@tonic-gate UHCI_MAX_INSTS)) != 0) {
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate return (error);
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate /* Install the loadable module */
1510Sstevel@tonic-gate if ((error = mod_install(&modlinkage)) != 0) {
1520Sstevel@tonic-gate ddi_soft_state_fini(&uhci_statep);
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate return (error);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate /*
1580Sstevel@tonic-gate * Build the tree bottom shared by all instances
1590Sstevel@tonic-gate */
1600Sstevel@tonic-gate temp = kmem_zalloc(NUM_FRAME_LST_ENTRIES * 2, KM_SLEEP);
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate num_of_nodes = 1;
1630Sstevel@tonic-gate for (i = 0; i < log_2(NUM_FRAME_LST_ENTRIES); i++) {
1640Sstevel@tonic-gate for (j = 0, k = 0; k < num_of_nodes; k++, j++) {
1650Sstevel@tonic-gate uhci_tree_bottom_nodes[j++] = temp[k];
1660Sstevel@tonic-gate uhci_tree_bottom_nodes[j] = temp[k] + pow_2(i);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate num_of_nodes *= 2;
1700Sstevel@tonic-gate for (k = 0; k < num_of_nodes; k++)
1710Sstevel@tonic-gate temp[k] = uhci_tree_bottom_nodes[k];
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate kmem_free(temp, (NUM_FRAME_LST_ENTRIES*2));
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate return (error);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1820Sstevel@tonic-gate _info(struct modinfo *modinfop)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate int
_fini(void)1890Sstevel@tonic-gate _fini(void)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate int error;
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate error = mod_remove(&modlinkage);
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate if (error == 0) {
1960Sstevel@tonic-gate /* Release per module resources */
1970Sstevel@tonic-gate ddi_soft_state_fini(&uhci_statep);
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate return (error);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate
2032191Sszhou /*
2042191Sszhou * The following simulated polling is for debugging purposes only.
2052191Sszhou * It is activated on x86 by setting usb-polling=true in GRUB or uhci.conf.
2062191Sszhou */
2072191Sszhou static int
uhci_is_polled(dev_info_t * dip)2082191Sszhou uhci_is_polled(dev_info_t *dip)
2092191Sszhou {
2102191Sszhou int ret;
2112191Sszhou char *propval;
2122191Sszhou
2132191Sszhou if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
2142191Sszhou "usb-polling", &propval) != DDI_SUCCESS)
2152191Sszhou
2162191Sszhou return (0);
2172191Sszhou
2182191Sszhou ret = (strcmp(propval, "true") == 0);
2192191Sszhou ddi_prop_free(propval);
2202191Sszhou
2212191Sszhou return (ret);
2222191Sszhou }
2232191Sszhou
2242191Sszhou static void
uhci_poll_intr(void * arg)2252191Sszhou uhci_poll_intr(void *arg)
2262191Sszhou {
2272191Sszhou /* poll every msec */
2282191Sszhou for (;;) {
2292191Sszhou (void) uhci_intr(arg, NULL);
2302191Sszhou delay(drv_usectohz(1000));
2312191Sszhou }
2322191Sszhou }
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate * Host Controller Driver (HCD) Auto configuration entry points
2360Sstevel@tonic-gate */
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate * Function Name : uhci_attach:
2400Sstevel@tonic-gate * Description : Attach entry point - called by the Kernel.
2410Sstevel@tonic-gate * Allocates of per controller data structure.
2420Sstevel@tonic-gate * Initializes the controller.
2430Sstevel@tonic-gate * Output : DDI_SUCCESS / DDI_FAILURE
2440Sstevel@tonic-gate */
2450Sstevel@tonic-gate static int
uhci_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2460Sstevel@tonic-gate uhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2470Sstevel@tonic-gate {
2482191Sszhou int instance, polled;
249965Sgovinda int i, intr_types;
2500Sstevel@tonic-gate uhci_state_t *uhcip = NULL;
2510Sstevel@tonic-gate usba_hcdi_register_args_t hcdi_args;
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, NULL, "uhci_attach:");
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate switch (cmd) {
2560Sstevel@tonic-gate case DDI_ATTACH:
2570Sstevel@tonic-gate break;
2580Sstevel@tonic-gate case DDI_RESUME:
2595773Sqz150045 uhcip = uhci_obtain_state(dip);
2605773Sqz150045
2615773Sqz150045 return (uhci_cpr_resume(uhcip));
2620Sstevel@tonic-gate default:
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate return (DDI_FAILURE);
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate /* Get the instance and create soft state */
2680Sstevel@tonic-gate instance = ddi_get_instance(dip);
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate /* Allocate the soft state structure for this instance of the driver */
2710Sstevel@tonic-gate if (ddi_soft_state_zalloc(uhci_statep, instance) != 0) {
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate return (DDI_FAILURE);
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate if ((uhcip = ddi_get_soft_state(uhci_statep, instance)) == NULL) {
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate return (DDI_FAILURE);
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate uhcip->uhci_log_hdl = usb_alloc_log_hdl(dip, "uhci", &uhci_errlevel,
2820Sstevel@tonic-gate &uhci_errmask, &uhci_instance_debug, 0);
2830Sstevel@tonic-gate
2845773Sqz150045 /* Set host controller soft state to initialization */
2855773Sqz150045 uhcip->uhci_hc_soft_state = UHCI_CTLR_INIT_STATE;
2865773Sqz150045
2870Sstevel@tonic-gate /* Save the dip and instance */
2880Sstevel@tonic-gate uhcip->uhci_dip = dip;
2890Sstevel@tonic-gate uhcip->uhci_instance = instance;
2900Sstevel@tonic-gate
2912191Sszhou polled = uhci_is_polled(dip);
2922191Sszhou if (polled)
2932191Sszhou
2942191Sszhou goto skip_intr;
2952191Sszhou
296965Sgovinda /* Get supported interrupt types */
297965Sgovinda if (ddi_intr_get_supported_types(uhcip->uhci_dip,
298965Sgovinda &intr_types) != DDI_SUCCESS) {
299965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
300965Sgovinda "uhci_attach: ddi_intr_get_supported_types failed");
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate usb_free_log_hdl(uhcip->uhci_log_hdl);
3030Sstevel@tonic-gate ddi_soft_state_free(uhci_statep, instance);
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate return (DDI_FAILURE);
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate
308965Sgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
309965Sgovinda "uhci_attach: supported interrupt types 0x%x", intr_types);
3100Sstevel@tonic-gate
311965Sgovinda if ((intr_types & DDI_INTR_TYPE_MSI) && uhci_enable_msi) {
312965Sgovinda if (uhci_add_intrs(uhcip, DDI_INTR_TYPE_MSI)
313965Sgovinda != DDI_SUCCESS) {
314965Sgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
315965Sgovinda "uhci_attach: MSI registration failed, "
316965Sgovinda "trying FIXED interrupt \n");
317965Sgovinda } else {
318965Sgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
319965Sgovinda "uhci_attach: Using MSI interrupt type\n");
3200Sstevel@tonic-gate
321965Sgovinda uhcip->uhci_intr_type = DDI_INTR_TYPE_MSI;
322965Sgovinda }
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate
325965Sgovinda if (!(uhcip->uhci_htable) && (intr_types & DDI_INTR_TYPE_FIXED)) {
326965Sgovinda if (uhci_add_intrs(uhcip, DDI_INTR_TYPE_FIXED)
327965Sgovinda != DDI_SUCCESS) {
328965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
329965Sgovinda "uhci_attach: FIXED interrupt registration "
330965Sgovinda "failed\n");
3310Sstevel@tonic-gate
332965Sgovinda usb_free_log_hdl(uhcip->uhci_log_hdl);
333965Sgovinda ddi_soft_state_free(uhci_statep, instance);
334965Sgovinda
335965Sgovinda return (DDI_FAILURE);
336965Sgovinda }
337965Sgovinda
338965Sgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
339965Sgovinda "uhci_attach: Using FIXED interrupt type\n");
340965Sgovinda
341965Sgovinda uhcip->uhci_intr_type = DDI_INTR_TYPE_FIXED;
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3442191Sszhou skip_intr:
345965Sgovinda /* Semaphore to serialize opens and closes */
346965Sgovinda sema_init(&uhcip->uhci_ocsem, 1, NULL, SEMA_DRIVER, NULL);
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate /* Create prototype condition variable */
3490Sstevel@tonic-gate cv_init(&uhcip->uhci_cv_SOF, NULL, CV_DRIVER, NULL);
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate /* Initialize the DMA attributes */
3520Sstevel@tonic-gate uhci_set_dma_attributes(uhcip);
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /* Initialize the kstat structures */
3550Sstevel@tonic-gate uhci_create_stats(uhcip);
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate /* Create the td and ed pools */
3580Sstevel@tonic-gate if (uhci_allocate_pools(uhcip) != USB_SUCCESS) {
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate goto fail;
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate /* Map the registers */
3640Sstevel@tonic-gate if (uhci_map_regs(uhcip) != USB_SUCCESS) {
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate goto fail;
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate
369965Sgovinda /* Enable all interrupts */
3702191Sszhou if (polled) {
3712191Sszhou extern pri_t maxclsyspri;
3722191Sszhou
3733435Slg150142 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
3742191Sszhou "uhci_attach: running in simulated polled mode.");
3752191Sszhou
3762191Sszhou /* create thread to poll */
3772191Sszhou (void) thread_create(NULL, 0, uhci_poll_intr, uhcip, 0, &p0,
3782191Sszhou TS_RUN, maxclsyspri);
3792191Sszhou } else if (uhcip->uhci_intr_cap & DDI_INTR_FLAG_BLOCK) {
380965Sgovinda /* Call ddi_intr_block_enable() for MSI interrupts */
381965Sgovinda (void) ddi_intr_block_enable(uhcip->uhci_htable,
382965Sgovinda uhcip->uhci_intr_cnt);
383965Sgovinda } else {
384965Sgovinda /* Call ddi_intr_enable for MSI or FIXED interrupts */
385965Sgovinda for (i = 0; i < uhcip->uhci_intr_cnt; i++)
386965Sgovinda (void) ddi_intr_enable(uhcip->uhci_htable[i]);
387965Sgovinda }
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate /* Initialize the controller */
3910Sstevel@tonic-gate if (uhci_init_ctlr(uhcip) != USB_SUCCESS) {
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate goto fail;
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate /*
3970Sstevel@tonic-gate * At this point, the hardware will be okay.
3980Sstevel@tonic-gate * Initialize the usba_hcdi structure
3990Sstevel@tonic-gate */
4000Sstevel@tonic-gate uhcip->uhci_hcdi_ops = uhci_alloc_hcdi_ops(uhcip);
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate * Make this HCD instance known to USBA
4040Sstevel@tonic-gate * (dma_attr must be passed for USBA busctl's)
4050Sstevel@tonic-gate */
4060Sstevel@tonic-gate hcdi_args.usba_hcdi_register_version = HCDI_REGISTER_VERSION;
4070Sstevel@tonic-gate hcdi_args.usba_hcdi_register_dip = dip;
4080Sstevel@tonic-gate hcdi_args.usba_hcdi_register_ops = uhcip->uhci_hcdi_ops;
4090Sstevel@tonic-gate hcdi_args.usba_hcdi_register_dma_attr = &uhcip->uhci_dma_attr;
4100Sstevel@tonic-gate hcdi_args.usba_hcdi_register_iblock_cookie =
411965Sgovinda (ddi_iblock_cookie_t)(uintptr_t)uhcip->uhci_intr_pri;
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate if (usba_hcdi_register(&hcdi_args, 0) != USB_SUCCESS) {
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate goto fail;
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate
4180Sstevel@tonic-gate #ifndef __sparc
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate * On NCR system, the driver seen failure of some commands
4210Sstevel@tonic-gate * while booting. This delay mysteriously solved the problem.
4220Sstevel@tonic-gate */
4230Sstevel@tonic-gate delay(drv_usectohz(uhci_attach_wait*1000000));
4240Sstevel@tonic-gate #endif
4250Sstevel@tonic-gate
4260Sstevel@tonic-gate /*
4270Sstevel@tonic-gate * Create another timeout handler to check whether any
4280Sstevel@tonic-gate * control/bulk/interrupt commands failed.
4290Sstevel@tonic-gate * This gets called every second.
4300Sstevel@tonic-gate */
4310Sstevel@tonic-gate uhcip->uhci_cmd_timeout_id = timeout(uhci_cmd_timeout_hdlr,
4324384Sfb209375 (void *)uhcip, UHCI_ONE_SECOND);
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex);
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate /*
4370Sstevel@tonic-gate * Set HcInterruptEnable to enable all interrupts except Root
4380Sstevel@tonic-gate * Hub Status change and SOF interrupts.
4390Sstevel@tonic-gate */
4400Sstevel@tonic-gate Set_OpReg16(USBINTR, ENABLE_ALL_INTRS);
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate /* Test the SOF interrupt */
4430Sstevel@tonic-gate if (uhci_wait_for_sof(uhcip) != USB_SUCCESS) {
4440Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
4450Sstevel@tonic-gate "No SOF interrupts have been received, this USB UHCI host"
4460Sstevel@tonic-gate " controller is unusable");
4470Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate goto fail;
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate /* This should be the last step which might fail during attaching */
4550Sstevel@tonic-gate if (uhci_init_root_hub(uhcip) != USB_SUCCESS) {
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate goto fail;
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate /* Display information in the banner */
4610Sstevel@tonic-gate ddi_report_dev(dip);
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
4640Sstevel@tonic-gate "uhci_attach successful");
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate return (DDI_SUCCESS);
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate fail:
469978Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
4700Sstevel@tonic-gate "failed to attach");
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate (void) uhci_cleanup(uhcip);
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate return (DDI_FAILURE);
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate /*
479965Sgovinda * uhci_add_intrs:
480965Sgovinda *
481965Sgovinda * Register FIXED or MSI interrupts.
482965Sgovinda */
483965Sgovinda static int
uhci_add_intrs(uhci_state_t * uhcip,int intr_type)484965Sgovinda uhci_add_intrs(uhci_state_t *uhcip,
485965Sgovinda int intr_type)
486965Sgovinda {
487965Sgovinda int actual, avail, intr_size, count = 0;
4885773Sqz150045 int i, flag, ret;
489965Sgovinda
490965Sgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
491965Sgovinda "uhci_add_intrs: interrupt type 0x%x", intr_type);
492965Sgovinda
493965Sgovinda /* Get number of interrupts */
494965Sgovinda ret = ddi_intr_get_nintrs(uhcip->uhci_dip, intr_type, &count);
495965Sgovinda if ((ret != DDI_SUCCESS) || (count == 0)) {
496965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
497965Sgovinda "uhci_add_intrs: ddi_intr_get_nintrs() failure, "
498965Sgovinda "ret: %d, count: %d", ret, count);
499965Sgovinda
500965Sgovinda return (DDI_FAILURE);
501965Sgovinda }
502965Sgovinda
503965Sgovinda /* Get number of available interrupts */
504965Sgovinda ret = ddi_intr_get_navail(uhcip->uhci_dip, intr_type, &avail);
505965Sgovinda if ((ret != DDI_SUCCESS) || (avail == 0)) {
506965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
507965Sgovinda "uhci_add_intrs: ddi_intr_get_navail() failure, "
508965Sgovinda "ret: %d, count: %d", ret, count);
509965Sgovinda
510965Sgovinda return (DDI_FAILURE);
511965Sgovinda }
512965Sgovinda
513965Sgovinda if (avail < count) {
514965Sgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
515965Sgovinda "uhci_add_intrs: uhci_add_intrs: nintrs () "
516965Sgovinda "returned %d, navail returned %d\n", count, avail);
517965Sgovinda }
518965Sgovinda
519965Sgovinda /* Allocate an array of interrupt handles */
520965Sgovinda intr_size = count * sizeof (ddi_intr_handle_t);
521965Sgovinda uhcip->uhci_htable = kmem_zalloc(intr_size, KM_SLEEP);
522965Sgovinda
523965Sgovinda flag = (intr_type == DDI_INTR_TYPE_MSI) ?
524965Sgovinda DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL;
525965Sgovinda
526965Sgovinda /* call ddi_intr_alloc() */
527965Sgovinda ret = ddi_intr_alloc(uhcip->uhci_dip, uhcip->uhci_htable,
528965Sgovinda intr_type, 0, count, &actual, flag);
529965Sgovinda
530965Sgovinda if ((ret != DDI_SUCCESS) || (actual == 0)) {
531965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
532965Sgovinda "uhci_add_intrs: ddi_intr_alloc() failed %d", ret);
533965Sgovinda
534965Sgovinda kmem_free(uhcip->uhci_htable, intr_size);
535965Sgovinda
536965Sgovinda return (DDI_FAILURE);
537965Sgovinda }
538965Sgovinda
539965Sgovinda if (actual < count) {
540965Sgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
541965Sgovinda "uhci_add_intrs: Requested: %d, Received: %d\n",
542965Sgovinda count, actual);
543965Sgovinda
544965Sgovinda for (i = 0; i < actual; i++)
545965Sgovinda (void) ddi_intr_free(uhcip->uhci_htable[i]);
546965Sgovinda
547965Sgovinda kmem_free(uhcip->uhci_htable, intr_size);
548965Sgovinda
549965Sgovinda return (DDI_FAILURE);
550965Sgovinda }
551965Sgovinda
552965Sgovinda uhcip->uhci_intr_cnt = actual;
553965Sgovinda
554965Sgovinda if ((ret = ddi_intr_get_pri(uhcip->uhci_htable[0],
555965Sgovinda &uhcip->uhci_intr_pri)) != DDI_SUCCESS) {
556965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
557965Sgovinda "uhci_add_intrs: ddi_intr_get_pri() failed %d", ret);
558965Sgovinda
559965Sgovinda for (i = 0; i < actual; i++)
560965Sgovinda (void) ddi_intr_free(uhcip->uhci_htable[i]);
561965Sgovinda
562965Sgovinda kmem_free(uhcip->uhci_htable, intr_size);
563965Sgovinda
564965Sgovinda return (DDI_FAILURE);
565965Sgovinda }
566965Sgovinda
567965Sgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
568965Sgovinda "uhci_add_intrs: Supported Interrupt priority 0x%x",
569965Sgovinda uhcip->uhci_intr_pri);
570965Sgovinda
571965Sgovinda /* Test for high level mutex */
572965Sgovinda if (uhcip->uhci_intr_pri >= ddi_intr_get_hilevel_pri()) {
573965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
574965Sgovinda "uhci_add_intrs: Hi level interrupt not supported");
575965Sgovinda
576965Sgovinda for (i = 0; i < actual; i++)
577965Sgovinda (void) ddi_intr_free(uhcip->uhci_htable[i]);
578965Sgovinda
579965Sgovinda kmem_free(uhcip->uhci_htable, intr_size);
580965Sgovinda
581965Sgovinda return (DDI_FAILURE);
582965Sgovinda }
583965Sgovinda
584965Sgovinda /* Initialize the mutex */
585965Sgovinda mutex_init(&uhcip->uhci_int_mutex, NULL, MUTEX_DRIVER,
586965Sgovinda DDI_INTR_PRI(uhcip->uhci_intr_pri));
587965Sgovinda
588965Sgovinda /* Call ddi_intr_add_handler() */
589965Sgovinda for (i = 0; i < actual; i++) {
590965Sgovinda if ((ret = ddi_intr_add_handler(uhcip->uhci_htable[i],
591965Sgovinda uhci_intr, (caddr_t)uhcip,
592965Sgovinda (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
593965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
594965Sgovinda "uhci_add_intrs: ddi_intr_add_handler() "
595965Sgovinda "failed %d", ret);
596965Sgovinda
597965Sgovinda for (i = 0; i < actual; i++)
598965Sgovinda (void) ddi_intr_free(uhcip->uhci_htable[i]);
599965Sgovinda
600965Sgovinda mutex_destroy(&uhcip->uhci_int_mutex);
601965Sgovinda kmem_free(uhcip->uhci_htable, intr_size);
602965Sgovinda
603965Sgovinda return (DDI_FAILURE);
604965Sgovinda }
605965Sgovinda }
606965Sgovinda
607965Sgovinda if ((ret = ddi_intr_get_cap(uhcip->uhci_htable[0],
608965Sgovinda &uhcip->uhci_intr_cap)) != DDI_SUCCESS) {
609965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
610965Sgovinda "uhci_add_intrs: ddi_intr_get_cap() failed %d", ret);
611965Sgovinda
612965Sgovinda for (i = 0; i < actual; i++) {
613965Sgovinda (void) ddi_intr_remove_handler(uhcip->uhci_htable[i]);
614965Sgovinda (void) ddi_intr_free(uhcip->uhci_htable[i]);
615965Sgovinda }
616965Sgovinda
617965Sgovinda mutex_destroy(&uhcip->uhci_int_mutex);
618965Sgovinda kmem_free(uhcip->uhci_htable, intr_size);
619965Sgovinda
620965Sgovinda return (DDI_FAILURE);
621965Sgovinda }
622965Sgovinda
623965Sgovinda return (DDI_SUCCESS);
624965Sgovinda }
625965Sgovinda
626965Sgovinda
627965Sgovinda /*
6280Sstevel@tonic-gate * Function Name: uhci_detach
6290Sstevel@tonic-gate * Description: Detach entry point - called by the Kernel.
6300Sstevel@tonic-gate * Deallocates all the memory
6310Sstevel@tonic-gate * Unregisters the interrupt handle and other resources.
6320Sstevel@tonic-gate * Output: DDI_SUCCESS / DDI_FAILURE
6330Sstevel@tonic-gate */
6340Sstevel@tonic-gate static int
uhci_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)6350Sstevel@tonic-gate uhci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
6360Sstevel@tonic-gate {
6370Sstevel@tonic-gate uhci_state_t *uhcip = uhci_obtain_state(dip);
6380Sstevel@tonic-gate
6390Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
6400Sstevel@tonic-gate "uhci_detach:");
6410Sstevel@tonic-gate
6420Sstevel@tonic-gate switch (cmd) {
6430Sstevel@tonic-gate case DDI_DETACH:
6440Sstevel@tonic-gate
6450Sstevel@tonic-gate return (uhci_cleanup(uhcip) == USB_SUCCESS ?
6464384Sfb209375 DDI_SUCCESS : DDI_FAILURE);
6470Sstevel@tonic-gate case DDI_SUSPEND:
6480Sstevel@tonic-gate
6495773Sqz150045 return (uhci_cpr_suspend(uhcip));
6500Sstevel@tonic-gate default:
6510Sstevel@tonic-gate
6520Sstevel@tonic-gate return (DDI_FAILURE);
6530Sstevel@tonic-gate }
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate /*
658965Sgovinda * uhci_rem_intrs:
659965Sgovinda *
660965Sgovinda * Unregister FIXED or MSI interrupts
661965Sgovinda */
662965Sgovinda static void
uhci_rem_intrs(uhci_state_t * uhcip)663965Sgovinda uhci_rem_intrs(uhci_state_t *uhcip)
664965Sgovinda {
665965Sgovinda int i;
666965Sgovinda
667965Sgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
668965Sgovinda "uhci_rem_intrs: interrupt type 0x%x", uhcip->uhci_intr_type);
669965Sgovinda
670965Sgovinda /* Disable all interrupts */
671965Sgovinda if (uhcip->uhci_intr_cap & DDI_INTR_FLAG_BLOCK) {
672965Sgovinda (void) ddi_intr_block_disable(uhcip->uhci_htable,
673965Sgovinda uhcip->uhci_intr_cnt);
674965Sgovinda } else {
675965Sgovinda for (i = 0; i < uhcip->uhci_intr_cnt; i++) {
676965Sgovinda (void) ddi_intr_disable(uhcip->uhci_htable[i]);
677965Sgovinda }
678965Sgovinda }
679965Sgovinda
680965Sgovinda /* Call ddi_intr_remove_handler() */
681965Sgovinda for (i = 0; i < uhcip->uhci_intr_cnt; i++) {
682965Sgovinda (void) ddi_intr_remove_handler(uhcip->uhci_htable[i]);
683965Sgovinda (void) ddi_intr_free(uhcip->uhci_htable[i]);
684965Sgovinda }
685965Sgovinda
686965Sgovinda kmem_free(uhcip->uhci_htable,
687965Sgovinda uhcip->uhci_intr_cnt * sizeof (ddi_intr_handle_t));
688965Sgovinda }
689965Sgovinda
690965Sgovinda
691965Sgovinda /*
6920Sstevel@tonic-gate * Function Name: uhci_reset
6930Sstevel@tonic-gate * Description: Reset entry point - called by the Kernel
6940Sstevel@tonic-gate * on the way down.
6950Sstevel@tonic-gate * The Toshiba laptop has been observed to hang
6960Sstevel@tonic-gate * on reboot when BIOS is set to suspend/resume.
6970Sstevel@tonic-gate * The resetting uhci on the way down solves the
6980Sstevel@tonic-gate * problem.
6990Sstevel@tonic-gate * Output: DDI_SUCCESS / DDI_FAILURE
7000Sstevel@tonic-gate */
7010Sstevel@tonic-gate /* ARGSUSED */
7020Sstevel@tonic-gate static int
uhci_reset(dev_info_t * dip,ddi_reset_cmd_t cmd)7030Sstevel@tonic-gate uhci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate uhci_state_t *uhcip = uhci_obtain_state(dip);
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate /* Disable all HC ED list processing */
7080Sstevel@tonic-gate Set_OpReg16(USBINTR, DISABLE_ALL_INTRS);
7090Sstevel@tonic-gate Set_OpReg16(USBCMD, 0);
7100Sstevel@tonic-gate
7110Sstevel@tonic-gate return (DDI_SUCCESS);
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate
7147656SSherry.Moore@Sun.COM /*
7157656SSherry.Moore@Sun.COM * quiesce(9E) entry point.
7167656SSherry.Moore@Sun.COM *
7177656SSherry.Moore@Sun.COM * This function is called when the system is single-threaded at high
7187656SSherry.Moore@Sun.COM * PIL with preemption disabled. Therefore, this function must not be
7197656SSherry.Moore@Sun.COM * blocked.
7207656SSherry.Moore@Sun.COM *
7217656SSherry.Moore@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
7227656SSherry.Moore@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen.
7237656SSherry.Moore@Sun.COM */
7247656SSherry.Moore@Sun.COM static int
uhci_quiesce(dev_info_t * dip)7257656SSherry.Moore@Sun.COM uhci_quiesce(dev_info_t *dip)
7267656SSherry.Moore@Sun.COM {
7277656SSherry.Moore@Sun.COM uhci_state_t *uhcip = uhci_obtain_state(dip);
7287656SSherry.Moore@Sun.COM
7297656SSherry.Moore@Sun.COM if (uhcip == NULL)
7307656SSherry.Moore@Sun.COM return (DDI_FAILURE);
7317656SSherry.Moore@Sun.COM
7327656SSherry.Moore@Sun.COM /* Disable interrupts */
7337656SSherry.Moore@Sun.COM Set_OpReg16(USBINTR, DISABLE_ALL_INTRS);
7347656SSherry.Moore@Sun.COM
7357656SSherry.Moore@Sun.COM /* Stop the Host Controller */
7367656SSherry.Moore@Sun.COM Set_OpReg16(USBCMD, 0);
7377656SSherry.Moore@Sun.COM
7388115SSherry.Moore@Sun.COM /* Clear all status bits */
7398115SSherry.Moore@Sun.COM Set_OpReg16(USBSTS, Get_OpReg16(USBSTS) & UHCI_INTR_MASK);
7407656SSherry.Moore@Sun.COM
7417656SSherry.Moore@Sun.COM return (DDI_SUCCESS);
7427656SSherry.Moore@Sun.COM }
7437656SSherry.Moore@Sun.COM
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate /*
7460Sstevel@tonic-gate * uhci_info:
7470Sstevel@tonic-gate */
7480Sstevel@tonic-gate /* ARGSUSED */
7490Sstevel@tonic-gate static int
uhci_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)7500Sstevel@tonic-gate uhci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
7510Sstevel@tonic-gate {
7520Sstevel@tonic-gate dev_t dev;
7530Sstevel@tonic-gate int instance;
7540Sstevel@tonic-gate int error = DDI_FAILURE;
7550Sstevel@tonic-gate uhci_state_t *uhcip;
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate switch (infocmd) {
7580Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
7590Sstevel@tonic-gate dev = (dev_t)arg;
7600Sstevel@tonic-gate instance = UHCI_UNIT(dev);
7610Sstevel@tonic-gate uhcip = ddi_get_soft_state(uhci_statep, instance);
7620Sstevel@tonic-gate if (uhcip != NULL) {
7630Sstevel@tonic-gate *result = (void *)uhcip->uhci_dip;
7640Sstevel@tonic-gate if (*result != NULL) {
7650Sstevel@tonic-gate error = DDI_SUCCESS;
7660Sstevel@tonic-gate }
7670Sstevel@tonic-gate } else {
7680Sstevel@tonic-gate *result = NULL;
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate
7710Sstevel@tonic-gate break;
7720Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
7730Sstevel@tonic-gate dev = (dev_t)arg;
7740Sstevel@tonic-gate instance = UHCI_UNIT(dev);
7750Sstevel@tonic-gate *result = (void *)(uintptr_t)instance;
7760Sstevel@tonic-gate error = DDI_SUCCESS;
7770Sstevel@tonic-gate
7780Sstevel@tonic-gate break;
7790Sstevel@tonic-gate default:
7800Sstevel@tonic-gate break;
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate
7830Sstevel@tonic-gate return (error);
7840Sstevel@tonic-gate }
7850Sstevel@tonic-gate
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate /*
7880Sstevel@tonic-gate * uhci_cleanup:
7890Sstevel@tonic-gate * Cleanup on attach failure or detach
7900Sstevel@tonic-gate */
7910Sstevel@tonic-gate static int
uhci_cleanup(uhci_state_t * uhcip)7920Sstevel@tonic-gate uhci_cleanup(uhci_state_t *uhcip)
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, "uhci_cleanup:");
7950Sstevel@tonic-gate
7960Sstevel@tonic-gate if (usba_hubdi_unbind_root_hub(uhcip->uhci_dip) != USB_SUCCESS) {
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate return (USB_FAILURE);
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate
8010Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex);
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate if (uhcip->uhci_cmd_timeout_id) {
8040Sstevel@tonic-gate timeout_id_t timeout_id = uhcip->uhci_cmd_timeout_id;
8050Sstevel@tonic-gate uhcip->uhci_cmd_timeout_id = 0;
8060Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
8070Sstevel@tonic-gate (void) untimeout(timeout_id);
8080Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex);
8090Sstevel@tonic-gate }
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate uhci_uninit_ctlr(uhcip);
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
8140Sstevel@tonic-gate
8150Sstevel@tonic-gate /* do interrupt cleanup */
816965Sgovinda if (uhcip->uhci_htable) {
817965Sgovinda uhci_rem_intrs(uhcip);
8180Sstevel@tonic-gate }
8190Sstevel@tonic-gate
8200Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex);
8210Sstevel@tonic-gate
8220Sstevel@tonic-gate usba_hcdi_unregister(uhcip->uhci_dip);
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate uhci_unmap_regs(uhcip);
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate uhci_free_pools(uhcip);
8270Sstevel@tonic-gate
8280Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
8290Sstevel@tonic-gate
8300Sstevel@tonic-gate mutex_destroy(&uhcip->uhci_int_mutex);
8310Sstevel@tonic-gate cv_destroy(&uhcip->uhci_cv_SOF);
8320Sstevel@tonic-gate sema_destroy(&uhcip->uhci_ocsem);
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate /* cleanup kstat structures */
8350Sstevel@tonic-gate uhci_destroy_stats(uhcip);
8360Sstevel@tonic-gate
8370Sstevel@tonic-gate usba_free_hcdi_ops(uhcip->uhci_hcdi_ops);
8380Sstevel@tonic-gate usb_free_log_hdl(uhcip->uhci_log_hdl);
8390Sstevel@tonic-gate ddi_prop_remove_all(uhcip->uhci_dip);
8400Sstevel@tonic-gate ddi_soft_state_free(uhci_statep, uhcip->uhci_instance);
8410Sstevel@tonic-gate
8420Sstevel@tonic-gate return (USB_SUCCESS);
8430Sstevel@tonic-gate }
8440Sstevel@tonic-gate
8450Sstevel@tonic-gate
8460Sstevel@tonic-gate /*
8475773Sqz150045 * uhci_cpr_suspend
8485773Sqz150045 */
8495773Sqz150045 static int
uhci_cpr_suspend(uhci_state_t * uhcip)8505773Sqz150045 uhci_cpr_suspend(uhci_state_t *uhcip)
8515773Sqz150045 {
8528550SSeth.Goldberg@Sun.COM uint16_t cmd_reg;
8538550SSeth.Goldberg@Sun.COM int i;
8548550SSeth.Goldberg@Sun.COM
8555773Sqz150045 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
8565773Sqz150045 "uhci_cpr_suspend:");
8575773Sqz150045
8585773Sqz150045 /* Call into the root hub and suspend it */
8595773Sqz150045 if (usba_hubdi_detach(uhcip->uhci_dip, DDI_SUSPEND) != DDI_SUCCESS) {
8605773Sqz150045
8615773Sqz150045 return (DDI_FAILURE);
8625773Sqz150045 }
8635773Sqz150045
8645773Sqz150045 mutex_enter(&uhcip->uhci_int_mutex);
8655773Sqz150045
8668550SSeth.Goldberg@Sun.COM /* Stop the Host Controller */
8678550SSeth.Goldberg@Sun.COM cmd_reg = Get_OpReg16(USBCMD);
8688550SSeth.Goldberg@Sun.COM cmd_reg &= ~USBCMD_REG_HC_RUN;
8698550SSeth.Goldberg@Sun.COM Set_OpReg16(USBCMD, cmd_reg);
8708550SSeth.Goldberg@Sun.COM
8718550SSeth.Goldberg@Sun.COM /*
8728550SSeth.Goldberg@Sun.COM * Wait for the duration of an SOF period until the host controller
8738550SSeth.Goldberg@Sun.COM * reaches the stopped state, indicated by the HCHalted bit in the
8748550SSeth.Goldberg@Sun.COM * USB status register.
8758550SSeth.Goldberg@Sun.COM */
8768550SSeth.Goldberg@Sun.COM for (i = 0; i <= UHCI_TIMEWAIT / 1000; i++) {
8778550SSeth.Goldberg@Sun.COM if (Get_OpReg16(USBSTS) & USBSTS_REG_HC_HALTED)
8788550SSeth.Goldberg@Sun.COM break;
8798550SSeth.Goldberg@Sun.COM drv_usecwait(1000);
8808550SSeth.Goldberg@Sun.COM }
8818550SSeth.Goldberg@Sun.COM
8828550SSeth.Goldberg@Sun.COM USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
8838550SSeth.Goldberg@Sun.COM "uhci_cpr_suspend: waited %d milliseconds for hc to halt", i);
8848550SSeth.Goldberg@Sun.COM
8855773Sqz150045 /* Disable interrupts */
8865773Sqz150045 Set_OpReg16(USBINTR, DISABLE_ALL_INTRS);
8875773Sqz150045
8888550SSeth.Goldberg@Sun.COM /* Clear any scheduled pending interrupts */
8898550SSeth.Goldberg@Sun.COM Set_OpReg16(USBSTS, USBSTS_REG_HC_HALTED |
8908550SSeth.Goldberg@Sun.COM USBSTS_REG_HC_PROCESS_ERR | USBSTS_REG_HOST_SYS_ERR |
8918550SSeth.Goldberg@Sun.COM USBSTS_REG_RESUME_DETECT | USBSTS_REG_USB_ERR_INTR |
8928550SSeth.Goldberg@Sun.COM USBSTS_REG_USB_INTR);
8935773Sqz150045
8945773Sqz150045 /* Set Global Suspend bit */
8958550SSeth.Goldberg@Sun.COM Set_OpReg16(USBCMD, USBCMD_REG_ENTER_GBL_SUSPEND);
8965773Sqz150045
8975773Sqz150045 /* Set host controller soft state to suspend */
8985773Sqz150045 uhcip->uhci_hc_soft_state = UHCI_CTLR_SUSPEND_STATE;
8995773Sqz150045
9005773Sqz150045 mutex_exit(&uhcip->uhci_int_mutex);
9015773Sqz150045
9025773Sqz150045 return (USB_SUCCESS);
9035773Sqz150045 }
9045773Sqz150045
9055773Sqz150045
9065773Sqz150045 /*
9075773Sqz150045 * uhci_cpr_cleanup:
9085773Sqz150045 *
9095773Sqz150045 * Cleanup uhci specific information across resuming.
9105773Sqz150045 */
9115773Sqz150045 static void
uhci_cpr_cleanup(uhci_state_t * uhcip)9125773Sqz150045 uhci_cpr_cleanup(uhci_state_t *uhcip)
9135773Sqz150045 {
9145773Sqz150045 ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
9155773Sqz150045
9165773Sqz150045 /* Reset software part of usb frame number */
9175773Sqz150045 uhcip->uhci_sw_frnum = 0;
9185773Sqz150045 }
9195773Sqz150045
9205773Sqz150045
9215773Sqz150045 /*
9225773Sqz150045 * uhci_cpr_resume
9235773Sqz150045 */
9245773Sqz150045 static int
uhci_cpr_resume(uhci_state_t * uhcip)9255773Sqz150045 uhci_cpr_resume(uhci_state_t *uhcip)
9265773Sqz150045 {
9275773Sqz150045 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
9285773Sqz150045 "uhci_cpr_resume: Restart the controller");
9295773Sqz150045
9305773Sqz150045 mutex_enter(&uhcip->uhci_int_mutex);
9315773Sqz150045
9325773Sqz150045 /* Cleanup uhci specific information across cpr */
9335773Sqz150045 uhci_cpr_cleanup(uhcip);
9345773Sqz150045
9355773Sqz150045 mutex_exit(&uhcip->uhci_int_mutex);
9365773Sqz150045
9375773Sqz150045 /* Restart the controller */
9385773Sqz150045 if (uhci_init_ctlr(uhcip) != DDI_SUCCESS) {
9395773Sqz150045
9405773Sqz150045 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
9415773Sqz150045 "uhci_cpr_resume: uhci host controller resume failed ");
9425773Sqz150045
9435773Sqz150045 return (DDI_FAILURE);
9445773Sqz150045 }
9455773Sqz150045
9465773Sqz150045 mutex_enter(&uhcip->uhci_int_mutex);
9475773Sqz150045
9485773Sqz150045 /*
9495773Sqz150045 * Set HcInterruptEnable to enable all interrupts except Root
9505773Sqz150045 * Hub Status change and SOF interrupts.
9515773Sqz150045 */
9525773Sqz150045 Set_OpReg16(USBINTR, ENABLE_ALL_INTRS);
9535773Sqz150045
9545773Sqz150045 mutex_exit(&uhcip->uhci_int_mutex);
9555773Sqz150045
9565773Sqz150045 /* Now resume the root hub */
9575773Sqz150045 if (usba_hubdi_attach(uhcip->uhci_dip, DDI_RESUME) != DDI_SUCCESS) {
9585773Sqz150045
9595773Sqz150045 return (DDI_FAILURE);
9605773Sqz150045 }
9615773Sqz150045
9625773Sqz150045 return (DDI_SUCCESS);
9635773Sqz150045 }
9645773Sqz150045
9655773Sqz150045
9665773Sqz150045 /*
9670Sstevel@tonic-gate * uhci_intr:
9680Sstevel@tonic-gate * uhci interrupt handling routine.
9690Sstevel@tonic-gate */
9700Sstevel@tonic-gate static uint_t
uhci_intr(caddr_t arg1,caddr_t arg2)971965Sgovinda uhci_intr(caddr_t arg1, caddr_t arg2)
9720Sstevel@tonic-gate {
9736427Ssl147100 ushort_t intr_status, cmd_reg, intr_reg;
974965Sgovinda uhci_state_t *uhcip = (uhci_state_t *)arg1;
975965Sgovinda
9766427Ssl147100 USB_DPRINTF_L4(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
9776898Sfb209375 "uhci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p",
9786898Sfb209375 (void *)arg1, (void *)arg2);
9790Sstevel@tonic-gate
9800Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex);
9810Sstevel@tonic-gate
9825773Sqz150045 /* Any interrupt is not handled for the suspended device. */
9835773Sqz150045 if (uhcip->uhci_hc_soft_state == UHCI_CTLR_SUSPEND_STATE) {
9845773Sqz150045 mutex_exit(&uhcip->uhci_int_mutex);
9855773Sqz150045
9865773Sqz150045 return (DDI_INTR_UNCLAIMED);
9875773Sqz150045 }
9885773Sqz150045
9890Sstevel@tonic-gate /* Get the status of the interrupts */
9900Sstevel@tonic-gate intr_status = Get_OpReg16(USBSTS);
9916427Ssl147100 intr_reg = Get_OpReg16(USBINTR);
9920Sstevel@tonic-gate
9936427Ssl147100 USB_DPRINTF_L3(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
9946427Ssl147100 "uhci_intr: intr_status = %x, intr_reg = %x",
9956427Ssl147100 intr_status, intr_reg);
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate /*
9986427Ssl147100 * If uhci interrupts are all disabled, the driver should return
9996427Ssl147100 * unclaimed.
10006427Ssl147100 * HC Process Error and Host System Error interrupts cannot be
10016427Ssl147100 * disabled by intr register, and need to be judged separately.
10026427Ssl147100 */
10036427Ssl147100 if (((intr_reg & ENABLE_ALL_INTRS) == 0) &&
10046427Ssl147100 ((intr_status & USBSTS_REG_HC_PROCESS_ERR) == 0) &&
10056427Ssl147100 ((intr_status & USBSTS_REG_HOST_SYS_ERR) == 0)) {
10066427Ssl147100
10076427Ssl147100 USB_DPRINTF_L3(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
10086427Ssl147100 "uhci_intr: interrupts disabled, unclaim");
10096427Ssl147100 mutex_exit(&uhcip->uhci_int_mutex);
10106427Ssl147100
10116427Ssl147100 return (DDI_INTR_UNCLAIMED);
10126427Ssl147100 }
10136427Ssl147100
10146427Ssl147100 /*
10156427Ssl147100 * If the intr is not from our controller, just return unclaimed.
10166427Ssl147100 * HCHalted status bit cannot generate interrupts and should be
10176427Ssl147100 * ignored.
10180Sstevel@tonic-gate */
10190Sstevel@tonic-gate if (!(intr_status & UHCI_INTR_MASK)) {
10200Sstevel@tonic-gate
10210Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
10226427Ssl147100 "uhci_intr: no interrupt status set, unclaim");
10230Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
10240Sstevel@tonic-gate
10250Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED);
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate /* Update kstat values */
10290Sstevel@tonic-gate uhci_do_intrs_stats(uhcip, intr_status);
10300Sstevel@tonic-gate
10310Sstevel@tonic-gate /* Acknowledge the interrupt */
10320Sstevel@tonic-gate Set_OpReg16(USBSTS, intr_status);
10330Sstevel@tonic-gate
10340Sstevel@tonic-gate /*
10350Sstevel@tonic-gate * If uhci controller has not been initialized, just clear the
10360Sstevel@tonic-gate * interrupter status and return claimed.
10370Sstevel@tonic-gate */
10385773Sqz150045 if (uhcip->uhci_hc_soft_state != UHCI_CTLR_OPERATIONAL_STATE) {
10390Sstevel@tonic-gate
10400Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
10416427Ssl147100 "uhci_intr: uhci controller is not in the operational "
10425773Sqz150045 "state");
10430Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
10440Sstevel@tonic-gate
10450Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
10460Sstevel@tonic-gate }
10470Sstevel@tonic-gate
10480Sstevel@tonic-gate /*
10490Sstevel@tonic-gate * We configured the hw incorrectly, disable future interrupts.
10500Sstevel@tonic-gate */
10510Sstevel@tonic-gate if ((intr_status & USBSTS_REG_HOST_SYS_ERR)) {
1052978Sfrits USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
10530Sstevel@tonic-gate "uhci_intr: Sys Err Disabling Interrupt");
10540Sstevel@tonic-gate Set_OpReg16(USBINTR, DISABLE_ALL_INTRS);
10555773Sqz150045 uhcip->uhci_hc_soft_state = UHCI_CTLR_ERROR_STATE;
10565773Sqz150045
10570Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
10580Sstevel@tonic-gate
10590Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
10600Sstevel@tonic-gate }
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate /*
10630Sstevel@tonic-gate * Check whether a frame number overflow occurred.
10640Sstevel@tonic-gate * if so, update the sw frame number.
10650Sstevel@tonic-gate */
10660Sstevel@tonic-gate uhci_isoc_update_sw_frame_number(uhcip);
10670Sstevel@tonic-gate
10680Sstevel@tonic-gate /*
10690Sstevel@tonic-gate * Check whether any commands got completed. If so, process them.
10700Sstevel@tonic-gate */
10710Sstevel@tonic-gate uhci_process_submitted_td_queue(uhcip);
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate * This should not occur. It occurs only if a HC controller
10750Sstevel@tonic-gate * experiences internal problem.
10760Sstevel@tonic-gate */
10770Sstevel@tonic-gate if (intr_status & USBSTS_REG_HC_HALTED) {
10780Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
10790Sstevel@tonic-gate "uhci_intr: Controller halted");
10800Sstevel@tonic-gate cmd_reg = Get_OpReg16(USBCMD);
10810Sstevel@tonic-gate Set_OpReg16(USBCMD, (cmd_reg | USBCMD_REG_HC_RUN));
10820Sstevel@tonic-gate }
10830Sstevel@tonic-gate
10840Sstevel@tonic-gate /*
10850Sstevel@tonic-gate * Wake up all the threads which are waiting for the Start of Frame
10860Sstevel@tonic-gate */
10870Sstevel@tonic-gate if (uhcip->uhci_cv_signal == B_TRUE) {
10880Sstevel@tonic-gate cv_broadcast(&uhcip->uhci_cv_SOF);
10890Sstevel@tonic-gate uhcip->uhci_cv_signal = B_FALSE;
10900Sstevel@tonic-gate }
10910Sstevel@tonic-gate
10920Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
10950Sstevel@tonic-gate }
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate
10980Sstevel@tonic-gate /*
10990Sstevel@tonic-gate * uhci_process_submitted_td_queue:
11000Sstevel@tonic-gate * Traverse thru the submitted queue and process the completed ones.
11010Sstevel@tonic-gate */
11020Sstevel@tonic-gate void
uhci_process_submitted_td_queue(uhci_state_t * uhcip)11030Sstevel@tonic-gate uhci_process_submitted_td_queue(uhci_state_t *uhcip)
11040Sstevel@tonic-gate {
11050Sstevel@tonic-gate uhci_td_t *head = uhcip->uhci_outst_tds_head;
11060Sstevel@tonic-gate uhci_trans_wrapper_t *tw;
11070Sstevel@tonic-gate
11080Sstevel@tonic-gate while (head != NULL) {
11090Sstevel@tonic-gate if ((!(GetTD_status(uhcip, head) & UHCI_TD_ACTIVE)) &&
11100Sstevel@tonic-gate (head->tw->tw_claim == UHCI_NOT_CLAIMED)) {
11110Sstevel@tonic-gate tw = head->tw;
11120Sstevel@tonic-gate
11130Sstevel@tonic-gate /*
11140Sstevel@tonic-gate * Call the corresponding handle_td routine
11150Sstevel@tonic-gate */
11160Sstevel@tonic-gate (*tw->tw_handle_td)(uhcip, head);
11170Sstevel@tonic-gate
11180Sstevel@tonic-gate /* restart at the beginning again */
11190Sstevel@tonic-gate head = uhcip->uhci_outst_tds_head;
11200Sstevel@tonic-gate } else {
11210Sstevel@tonic-gate head = head->outst_td_next;
11220Sstevel@tonic-gate }
11230Sstevel@tonic-gate }
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate
11260Sstevel@tonic-gate
11270Sstevel@tonic-gate /*
11280Sstevel@tonic-gate * uhci_handle_intr_td:
11290Sstevel@tonic-gate * handles the completed interrupt transfer TD's.
11300Sstevel@tonic-gate */
11310Sstevel@tonic-gate void
uhci_handle_intr_td(uhci_state_t * uhcip,uhci_td_t * td)11320Sstevel@tonic-gate uhci_handle_intr_td(uhci_state_t *uhcip, uhci_td_t *td)
11330Sstevel@tonic-gate {
11340Sstevel@tonic-gate usb_req_attrs_t attrs;
11350Sstevel@tonic-gate uint_t bytes_xfered;
11360Sstevel@tonic-gate usb_cr_t usb_err;
11370Sstevel@tonic-gate uhci_trans_wrapper_t *tw = td->tw;
11380Sstevel@tonic-gate uhci_pipe_private_t *pp = tw->tw_pipe_private;
11390Sstevel@tonic-gate usb_intr_req_t *intr_reqp =
11404384Sfb209375 (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
11410Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
11440Sstevel@tonic-gate "uhci_handle_intr_td: intr_reqp = 0x%p", (void *)intr_reqp);
11450Sstevel@tonic-gate
11460Sstevel@tonic-gate ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
11470Sstevel@tonic-gate
11480Sstevel@tonic-gate /* set tw->tw_claim flag, so that nobody else works on this td. */
11490Sstevel@tonic-gate tw->tw_claim = UHCI_INTR_HDLR_CLAIMED;
11500Sstevel@tonic-gate
11510Sstevel@tonic-gate /* Interrupt OUT */
11520Sstevel@tonic-gate if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_OUT) {
11530Sstevel@tonic-gate
11540Sstevel@tonic-gate /* process errors first */
11550Sstevel@tonic-gate usb_err = uhci_parse_td_error(uhcip, pp, td);
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate /* get the actual xfered data size */
11580Sstevel@tonic-gate bytes_xfered = GetTD_alen(uhcip, td);
11590Sstevel@tonic-gate
11600Sstevel@tonic-gate /* check data underrun error */
11610Sstevel@tonic-gate if ((usb_err == USB_CR_OK) && (bytes_xfered !=
11620Sstevel@tonic-gate GetTD_mlen(uhcip, td))) {
11630Sstevel@tonic-gate
11640Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS,
11650Sstevel@tonic-gate uhcip->uhci_log_hdl, "uhci_handle_intr_td:"
11660Sstevel@tonic-gate " Intr out pipe, data underrun occurred");
11670Sstevel@tonic-gate
11680Sstevel@tonic-gate usb_err = USB_CR_DATA_UNDERRUN;
11690Sstevel@tonic-gate
11700Sstevel@tonic-gate }
11710Sstevel@tonic-gate
11720Sstevel@tonic-gate bytes_xfered = (bytes_xfered == ZERO_LENGTH) ?
11734384Sfb209375 0 : bytes_xfered+1;
11740Sstevel@tonic-gate tw->tw_bytes_xfered += bytes_xfered;
11750Sstevel@tonic-gate uhci_do_byte_stats(uhcip, tw->tw_bytes_xfered,
11760Sstevel@tonic-gate ph->p_ep.bmAttributes, ph->p_ep.bEndpointAddress);
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate
11790Sstevel@tonic-gate /*
11800Sstevel@tonic-gate * If error occurred or all data xfered, delete the current td,
11810Sstevel@tonic-gate * free tw, do the callback. Otherwise wait for the next td.
11820Sstevel@tonic-gate */
11830Sstevel@tonic-gate if (usb_err != USB_CR_OK) {
11840Sstevel@tonic-gate
11850Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
11860Sstevel@tonic-gate "uhci_handle_intr_td: Intr out pipe error");
11870Sstevel@tonic-gate
11880Sstevel@tonic-gate /* update the element pointer */
11890Sstevel@tonic-gate SetQH32(uhcip, pp->pp_qh->element_ptr, GetTD32(
11904384Sfb209375 uhcip, tw->tw_hctd_tail->link_ptr));
11910Sstevel@tonic-gate
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate } else if (tw->tw_bytes_xfered == tw->tw_length) {
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate /* all data xfered */
11960Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
11970Sstevel@tonic-gate "uhci_handle_intr_td: Intr out pipe,"
11980Sstevel@tonic-gate " all data xfered");
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate } else {
12010Sstevel@tonic-gate
12020Sstevel@tonic-gate /* remove the current td and wait for the next one. */
12030Sstevel@tonic-gate uhci_delete_td(uhcip, td);
12040Sstevel@tonic-gate tw->tw_claim = UHCI_NOT_CLAIMED;
12050Sstevel@tonic-gate
12060Sstevel@tonic-gate return;
12070Sstevel@tonic-gate }
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate uhci_delete_td(uhcip, td);
12100Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, ph, tw, usb_err);
12110Sstevel@tonic-gate uhci_deallocate_tw(uhcip, tw->tw_pipe_private, tw);
12120Sstevel@tonic-gate
12130Sstevel@tonic-gate return;
12140Sstevel@tonic-gate }
12150Sstevel@tonic-gate
12160Sstevel@tonic-gate /* Interrupt IN */
12170Sstevel@tonic-gate
12180Sstevel@tonic-gate /* Get the actual received data size */
12190Sstevel@tonic-gate tw->tw_bytes_xfered = GetTD_alen(uhcip, td);
12200Sstevel@tonic-gate if (tw->tw_bytes_xfered == ZERO_LENGTH) {
12210Sstevel@tonic-gate tw->tw_bytes_xfered = 0;
12220Sstevel@tonic-gate } else {
12230Sstevel@tonic-gate tw->tw_bytes_xfered++;
12240Sstevel@tonic-gate }
12250Sstevel@tonic-gate
12260Sstevel@tonic-gate /* process errors first */
12270Sstevel@tonic-gate if (GetTD_status(uhcip, td) & TD_STATUS_MASK) {
12280Sstevel@tonic-gate SetQH32(uhcip, pp->pp_qh->element_ptr,
12290Sstevel@tonic-gate GetTD32(uhcip, td->link_ptr));
12300Sstevel@tonic-gate
12310Sstevel@tonic-gate uhci_handle_intr_td_errors(uhcip, td, tw, pp);
12320Sstevel@tonic-gate
12330Sstevel@tonic-gate return;
12340Sstevel@tonic-gate }
12350Sstevel@tonic-gate
12360Sstevel@tonic-gate /*
12370Sstevel@tonic-gate * Check for data underruns.
12380Sstevel@tonic-gate * For data underrun case, the host controller does not update
12390Sstevel@tonic-gate * element pointer. So, we update here.
12400Sstevel@tonic-gate */
12410Sstevel@tonic-gate if (GetTD_alen(uhcip, td) != GetTD_mlen(uhcip, td)) {
12420Sstevel@tonic-gate SetQH32(uhcip, pp->pp_qh->element_ptr,
12430Sstevel@tonic-gate GetTD32(uhcip, td->link_ptr));
12440Sstevel@tonic-gate }
12450Sstevel@tonic-gate
12460Sstevel@tonic-gate /*
12470Sstevel@tonic-gate * Call uhci_sendup_td_message to send message upstream.
12480Sstevel@tonic-gate * The function uhci_sendup_td_message returns USB_NO_RESOURCES
12490Sstevel@tonic-gate * if allocb fails and also sends error message to upstream by
12500Sstevel@tonic-gate * calling USBA callback function. Under error conditions just
12510Sstevel@tonic-gate * drop the current message.
12520Sstevel@tonic-gate */
12530Sstevel@tonic-gate
12540Sstevel@tonic-gate /* Get the interrupt xfer attributes */
12550Sstevel@tonic-gate attrs = intr_reqp->intr_attributes;
12560Sstevel@tonic-gate
12570Sstevel@tonic-gate /*
12580Sstevel@tonic-gate * Check usb flag whether USB_FLAGS_ONE_XFER flag is set
12590Sstevel@tonic-gate * and if so, free duplicate request.
12600Sstevel@tonic-gate */
12610Sstevel@tonic-gate if (attrs & USB_ATTRS_ONE_XFER) {
12620Sstevel@tonic-gate uhci_handle_one_xfer_completion(uhcip, USB_CR_OK, td);
12630Sstevel@tonic-gate
12640Sstevel@tonic-gate return;
12650Sstevel@tonic-gate }
12660Sstevel@tonic-gate
12670Sstevel@tonic-gate /* save it temporarily */
12680Sstevel@tonic-gate if (tw->tw_bytes_xfered != 0) {
12690Sstevel@tonic-gate uhci_sendup_td_message(uhcip, USB_CR_OK, tw);
12700Sstevel@tonic-gate }
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate /* Clear the tw->tw_claim flag */
12730Sstevel@tonic-gate tw->tw_claim = UHCI_NOT_CLAIMED;
12740Sstevel@tonic-gate
12750Sstevel@tonic-gate uhci_delete_td(uhcip, td);
12760Sstevel@tonic-gate
12770Sstevel@tonic-gate /* allocate another interrupt periodic resource */
12780Sstevel@tonic-gate if (pp->pp_state == UHCI_PIPE_STATE_ACTIVE) {
12790Sstevel@tonic-gate if (uhci_allocate_periodic_in_resource(uhcip, pp, tw, 0) !=
12800Sstevel@tonic-gate USB_SUCCESS) {
12810Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
12820Sstevel@tonic-gate "uhci_insert_intr_req: Interrupt request structure"
12830Sstevel@tonic-gate "allocation failed");
12840Sstevel@tonic-gate
12850Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, ph,
12860Sstevel@tonic-gate tw, USB_CR_NO_RESOURCES);
12870Sstevel@tonic-gate
12880Sstevel@tonic-gate return;
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate /* Insert another interrupt TD */
12922125Ssl147100 if (uhci_insert_hc_td(uhcip, 0,
12930Sstevel@tonic-gate tw->tw_length, pp, tw, PID_IN, attrs) != USB_SUCCESS) {
12940Sstevel@tonic-gate
12950Sstevel@tonic-gate uhci_deallocate_periodic_in_resource(uhcip, pp, tw);
12960Sstevel@tonic-gate
12970Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
12980Sstevel@tonic-gate "uhci_handle_intr_td: TD exhausted");
12990Sstevel@tonic-gate
13000Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, ph,
13010Sstevel@tonic-gate tw, USB_CR_NO_RESOURCES);
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate }
13040Sstevel@tonic-gate }
13050Sstevel@tonic-gate
13060Sstevel@tonic-gate
13070Sstevel@tonic-gate /*
13080Sstevel@tonic-gate * uhci_sendup_td_message:
13090Sstevel@tonic-gate *
13100Sstevel@tonic-gate * Get a message block and send the received message upstream.
13110Sstevel@tonic-gate */
13120Sstevel@tonic-gate void
uhci_sendup_td_message(uhci_state_t * uhcip,usb_cr_t usb_err,uhci_trans_wrapper_t * tw)13130Sstevel@tonic-gate uhci_sendup_td_message(
13140Sstevel@tonic-gate uhci_state_t *uhcip,
13150Sstevel@tonic-gate usb_cr_t usb_err,
13160Sstevel@tonic-gate uhci_trans_wrapper_t *tw)
13170Sstevel@tonic-gate {
13180Sstevel@tonic-gate mblk_t *mp = NULL;
13190Sstevel@tonic-gate size_t length = 0;
13200Sstevel@tonic-gate size_t skip_len = 0;
13210Sstevel@tonic-gate uchar_t *buf;
13220Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp = tw->tw_curr_xfer_reqp;
13230Sstevel@tonic-gate uhci_pipe_private_t *pp = tw->tw_pipe_private;
13240Sstevel@tonic-gate usb_ep_descr_t *ept = &pp->pp_pipe_handle->p_ep;
13250Sstevel@tonic-gate
13260Sstevel@tonic-gate ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
13270Sstevel@tonic-gate
13280Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
13290Sstevel@tonic-gate "uhci_sendup_td_message: bytes transferred=0x%x, "
13300Sstevel@tonic-gate "bytes pending=0x%x",
13310Sstevel@tonic-gate tw->tw_bytes_xfered, tw->tw_bytes_pending);
13320Sstevel@tonic-gate
13330Sstevel@tonic-gate length = tw->tw_bytes_xfered;
13340Sstevel@tonic-gate
13350Sstevel@tonic-gate switch (UHCI_XFER_TYPE(ept)) {
13360Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
13372125Ssl147100 skip_len = UHCI_CTRL_EPT_MAX_SIZE; /* length to skip */
13380Sstevel@tonic-gate mp = ((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_data;
13390Sstevel@tonic-gate break;
13400Sstevel@tonic-gate case USB_EP_ATTR_INTR:
13410Sstevel@tonic-gate mp = ((usb_intr_req_t *)curr_xfer_reqp)->intr_data;
13420Sstevel@tonic-gate break;
13430Sstevel@tonic-gate case USB_EP_ATTR_BULK:
13440Sstevel@tonic-gate mp = ((usb_bulk_req_t *)curr_xfer_reqp)->bulk_data;
13450Sstevel@tonic-gate break;
13460Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
13470Sstevel@tonic-gate length = tw->tw_length;
13480Sstevel@tonic-gate mp = ((usb_isoc_req_t *)curr_xfer_reqp)->isoc_data;
13490Sstevel@tonic-gate break;
13500Sstevel@tonic-gate default:
13510Sstevel@tonic-gate break;
13520Sstevel@tonic-gate }
13530Sstevel@tonic-gate
13540Sstevel@tonic-gate /* Copy the data into the mblk_t */
13550Sstevel@tonic-gate buf = (uchar_t *)tw->tw_buf + skip_len;
13560Sstevel@tonic-gate
13570Sstevel@tonic-gate ASSERT(mp != NULL);
13580Sstevel@tonic-gate
13590Sstevel@tonic-gate /*
13600Sstevel@tonic-gate * Update kstat byte counts
13610Sstevel@tonic-gate * The control endpoints don't have direction bits so in
13620Sstevel@tonic-gate * order for control stats to be counted correctly an IN
13630Sstevel@tonic-gate * bit must be faked on a control read.
13640Sstevel@tonic-gate */
13650Sstevel@tonic-gate uhci_do_byte_stats(uhcip, length, ept->bmAttributes,
13660Sstevel@tonic-gate (UHCI_XFER_TYPE(ept) == USB_EP_ATTR_CONTROL) ?
13670Sstevel@tonic-gate USB_EP_DIR_IN : ept->bEndpointAddress);
13680Sstevel@tonic-gate
13690Sstevel@tonic-gate if (length) {
13702125Ssl147100 int rval, i;
13712125Ssl147100 uchar_t *p = mp->b_rptr;
13722125Ssl147100
13732125Ssl147100 if (UHCI_XFER_TYPE(ept) == USB_EP_ATTR_ISOCH) {
13742125Ssl147100 /* Deal with isoc data by packets */
13752125Ssl147100 for (i = 0; i < tw->tw_ncookies; i++) {
13762125Ssl147100 rval = ddi_dma_sync(
13772125Ssl147100 tw->tw_isoc_bufs[i].dma_handle, 0,
13782125Ssl147100 tw->tw_isoc_bufs[i].length,
13792125Ssl147100 DDI_DMA_SYNC_FORCPU);
13802125Ssl147100 ASSERT(rval == DDI_SUCCESS);
13810Sstevel@tonic-gate
13822125Ssl147100 ddi_rep_get8(tw->tw_isoc_bufs[i].mem_handle,
13832125Ssl147100 p, (uint8_t *)tw->tw_isoc_bufs[i].buf_addr,
13842125Ssl147100 tw->tw_isoc_bufs[i].length,
13852125Ssl147100 DDI_DEV_AUTOINCR);
13862125Ssl147100 p += tw->tw_isoc_bufs[i].length;
13872125Ssl147100 }
13882125Ssl147100 } else {
13892125Ssl147100 /* Sync the streaming buffer */
13902125Ssl147100 rval = ddi_dma_sync(tw->tw_dmahandle, 0,
13912125Ssl147100 (skip_len + length), DDI_DMA_SYNC_FORCPU);
13922125Ssl147100 ASSERT(rval == DDI_SUCCESS);
13930Sstevel@tonic-gate
13942125Ssl147100 /* Copy the data into the message */
13952125Ssl147100 ddi_rep_get8(tw->tw_accesshandle,
13962125Ssl147100 mp->b_rptr, buf, length, DDI_DEV_AUTOINCR);
13972125Ssl147100 }
13980Sstevel@tonic-gate
13990Sstevel@tonic-gate /* Increment the write pointer */
14000Sstevel@tonic-gate mp->b_wptr += length;
14010Sstevel@tonic-gate } else {
14020Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
14030Sstevel@tonic-gate "uhci_sendup_td_message: Zero length packet");
14040Sstevel@tonic-gate }
14050Sstevel@tonic-gate
14060Sstevel@tonic-gate /* Do the callback */
14070Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, pp->pp_pipe_handle, tw, usb_err);
14080Sstevel@tonic-gate }
14090Sstevel@tonic-gate
14100Sstevel@tonic-gate
14110Sstevel@tonic-gate /*
14120Sstevel@tonic-gate * uhci_handle_ctrl_td:
14130Sstevel@tonic-gate * Handle a control Transfer Descriptor (TD).
14140Sstevel@tonic-gate */
14150Sstevel@tonic-gate void
uhci_handle_ctrl_td(uhci_state_t * uhcip,uhci_td_t * td)14160Sstevel@tonic-gate uhci_handle_ctrl_td(uhci_state_t *uhcip, uhci_td_t *td)
14170Sstevel@tonic-gate {
14180Sstevel@tonic-gate ushort_t direction;
14190Sstevel@tonic-gate ushort_t bytes_for_xfer;
14200Sstevel@tonic-gate ushort_t bytes_xfered;
14210Sstevel@tonic-gate ushort_t MaxPacketSize;
14220Sstevel@tonic-gate usb_cr_t error;
14230Sstevel@tonic-gate uhci_trans_wrapper_t *tw = td->tw;
14240Sstevel@tonic-gate uhci_pipe_private_t *pp = tw->tw_pipe_private;
14250Sstevel@tonic-gate usba_pipe_handle_data_t *usb_pp = pp->pp_pipe_handle;
14260Sstevel@tonic-gate usb_ep_descr_t *eptd = &usb_pp->p_ep;
14270Sstevel@tonic-gate usb_ctrl_req_t *reqp = (usb_ctrl_req_t *)tw->tw_curr_xfer_reqp;
14280Sstevel@tonic-gate
14290Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
14300Sstevel@tonic-gate "uhci_handle_ctrl_td: pp = 0x%p tw = 0x%p td = 0x%p "
14310Sstevel@tonic-gate "state = 0x%x len = 0x%lx", (void *)pp, (void *)tw,
14320Sstevel@tonic-gate (void *)td, tw->tw_ctrl_state, tw->tw_length);
14330Sstevel@tonic-gate
14340Sstevel@tonic-gate ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
14350Sstevel@tonic-gate
14360Sstevel@tonic-gate error = uhci_parse_td_error(uhcip, pp, td);
14370Sstevel@tonic-gate
14380Sstevel@tonic-gate /*
14390Sstevel@tonic-gate * In case of control transfers, the device can send NAK when it
14400Sstevel@tonic-gate * is busy. If a NAK is received, then send the status TD again.
14410Sstevel@tonic-gate */
14420Sstevel@tonic-gate if (error != USB_CR_OK) {
14430Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
14440Sstevel@tonic-gate "uhci_handle_ctrl_td: Ctrl cmd failed, error = %x", error);
14450Sstevel@tonic-gate
14460Sstevel@tonic-gate SetQH32(uhcip, pp->pp_qh->element_ptr,
14470Sstevel@tonic-gate GetTD32(uhcip, td->link_ptr));
14480Sstevel@tonic-gate uhci_delete_td(uhcip, td);
14490Sstevel@tonic-gate
14500Sstevel@tonic-gate /* Return number of bytes xfered */
14510Sstevel@tonic-gate if (GetTD_alen(uhcip, td) != ZERO_LENGTH) {
14520Sstevel@tonic-gate tw->tw_bytes_xfered = GetTD_alen(uhcip, td) + 1;
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate
14550Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
14560Sstevel@tonic-gate "uhci_handle_ctrl_td: Bytes transferred = %x",
14570Sstevel@tonic-gate tw->tw_bytes_xfered);
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate if ((tw->tw_ctrl_state == DATA) &&
14600Sstevel@tonic-gate (tw->tw_direction == PID_IN)) {
14610Sstevel@tonic-gate uhci_sendup_td_message(uhcip, error, tw);
14620Sstevel@tonic-gate } else {
14630Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, usb_pp, tw, error);
14640Sstevel@tonic-gate
14650Sstevel@tonic-gate uhci_deallocate_tw(uhcip, pp, tw);
14660Sstevel@tonic-gate }
14670Sstevel@tonic-gate
14680Sstevel@tonic-gate return;
14690Sstevel@tonic-gate }
14700Sstevel@tonic-gate
14710Sstevel@tonic-gate /*
14720Sstevel@tonic-gate * A control transfer consists of three phases:
14730Sstevel@tonic-gate * - Setup
14740Sstevel@tonic-gate * - Data (optional)
14750Sstevel@tonic-gate * - Status
14760Sstevel@tonic-gate *
14770Sstevel@tonic-gate * There is a TD per phase. A TD for a given phase isn't
14780Sstevel@tonic-gate * enqueued until the previous phase is finished.
14790Sstevel@tonic-gate */
14800Sstevel@tonic-gate switch (tw->tw_ctrl_state) {
14810Sstevel@tonic-gate case SETUP:
14820Sstevel@tonic-gate /*
14830Sstevel@tonic-gate * Enqueue either the data or the status
14840Sstevel@tonic-gate * phase depending on the length.
14850Sstevel@tonic-gate */
14860Sstevel@tonic-gate pp->pp_data_toggle = 1;
14870Sstevel@tonic-gate uhci_delete_td(uhcip, td);
14880Sstevel@tonic-gate
14890Sstevel@tonic-gate /*
14900Sstevel@tonic-gate * If the length is 0, move to the status.
14910Sstevel@tonic-gate * If length is not 0, then we have some data
14920Sstevel@tonic-gate * to move on the bus to device either IN or OUT.
14930Sstevel@tonic-gate */
14940Sstevel@tonic-gate if ((tw->tw_length - SETUP_SIZE) == 0) {
14950Sstevel@tonic-gate /*
14960Sstevel@tonic-gate * There is no data stage, then
14970Sstevel@tonic-gate * initiate status phase from the host.
14980Sstevel@tonic-gate */
14992125Ssl147100 if ((uhci_insert_hc_td(uhcip, 0, 0, pp, tw, PID_IN,
15000Sstevel@tonic-gate reqp->ctrl_attributes)) != USB_SUCCESS) {
15010Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS,
15020Sstevel@tonic-gate uhcip->uhci_log_hdl,
15030Sstevel@tonic-gate "uhci_handle_ctrl_td: No resources");
15040Sstevel@tonic-gate
15050Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, usb_pp, tw,
15060Sstevel@tonic-gate USB_CR_NO_RESOURCES);
15070Sstevel@tonic-gate
15080Sstevel@tonic-gate return;
15090Sstevel@tonic-gate }
15100Sstevel@tonic-gate
15110Sstevel@tonic-gate tw->tw_ctrl_state = STATUS;
15120Sstevel@tonic-gate } else {
15130Sstevel@tonic-gate uint_t xx;
15140Sstevel@tonic-gate
15150Sstevel@tonic-gate /*
15160Sstevel@tonic-gate * Each USB device can send/receive 8/16/32/64
15170Sstevel@tonic-gate * depending on wMaxPacketSize's implementation.
15180Sstevel@tonic-gate * We need to insert 'N = Number of byte/
15190Sstevel@tonic-gate * MaxpktSize" TD's in the lattice to send/
15200Sstevel@tonic-gate * receive the data. Though the USB protocol
15210Sstevel@tonic-gate * allows to insert more than one TD in the same
15220Sstevel@tonic-gate * frame, we are inserting only one TD in one
15230Sstevel@tonic-gate * frame. This is bcos OHCI has seen some problem
15240Sstevel@tonic-gate * when multiple TD's are inserted at the same time.
15250Sstevel@tonic-gate */
15262125Ssl147100 tw->tw_length -= UHCI_CTRL_EPT_MAX_SIZE;
15270Sstevel@tonic-gate MaxPacketSize = eptd->wMaxPacketSize;
15280Sstevel@tonic-gate
15290Sstevel@tonic-gate /*
15300Sstevel@tonic-gate * We dont know the maximum packet size that
15310Sstevel@tonic-gate * the device can handle(MaxPAcketSize=0).
15320Sstevel@tonic-gate * In that case insert a data phase with
15330Sstevel@tonic-gate * eight bytes or less.
15340Sstevel@tonic-gate */
15350Sstevel@tonic-gate if (MaxPacketSize == 0) {
15360Sstevel@tonic-gate xx = (tw->tw_length > 8) ? 8 : tw->tw_length;
15370Sstevel@tonic-gate } else {
15380Sstevel@tonic-gate xx = (tw->tw_length > MaxPacketSize) ?
15394384Sfb209375 MaxPacketSize : tw->tw_length;
15400Sstevel@tonic-gate }
15410Sstevel@tonic-gate
15420Sstevel@tonic-gate tw->tw_tmp = xx;
15430Sstevel@tonic-gate
15440Sstevel@tonic-gate /*
15450Sstevel@tonic-gate * Create the TD. If this is an OUT
15460Sstevel@tonic-gate * transaction, the data is already
15470Sstevel@tonic-gate * in the buffer of the TW.
15480Sstevel@tonic-gate * Get first 8 bytes of the command only.
15490Sstevel@tonic-gate */
15500Sstevel@tonic-gate if ((uhci_insert_hc_td(uhcip,
15512125Ssl147100 UHCI_CTRL_EPT_MAX_SIZE, xx,
15520Sstevel@tonic-gate pp, tw, tw->tw_direction,
15530Sstevel@tonic-gate reqp->ctrl_attributes)) != USB_SUCCESS) {
15540Sstevel@tonic-gate
15550Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS,
15560Sstevel@tonic-gate uhcip->uhci_log_hdl,
15570Sstevel@tonic-gate "uhci_handle_ctrl_td: No resources");
15580Sstevel@tonic-gate
15590Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, usb_pp, tw,
15600Sstevel@tonic-gate USB_CR_NO_RESOURCES);
15610Sstevel@tonic-gate
15620Sstevel@tonic-gate return;
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate
15650Sstevel@tonic-gate tw->tw_ctrl_state = DATA;
15660Sstevel@tonic-gate }
15670Sstevel@tonic-gate
15680Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
15690Sstevel@tonic-gate "Setup complete: pp 0x%p td 0x%p", (void *)pp, (void *)td);
15700Sstevel@tonic-gate
15710Sstevel@tonic-gate break;
15720Sstevel@tonic-gate case DATA:
15730Sstevel@tonic-gate uhci_delete_td(uhcip, td);
15740Sstevel@tonic-gate
15750Sstevel@tonic-gate MaxPacketSize = eptd->wMaxPacketSize;
15760Sstevel@tonic-gate
15770Sstevel@tonic-gate /*
15780Sstevel@tonic-gate * Decrement pending bytes and increment the total
15790Sstevel@tonic-gate * number bytes transferred by the actual number of bytes
15800Sstevel@tonic-gate * transferred in this TD. If the number of bytes transferred
15810Sstevel@tonic-gate * is less than requested, that means an underrun has
15820Sstevel@tonic-gate * occurred. Set the tw_tmp varible to indicate UNDER run.
15830Sstevel@tonic-gate */
15840Sstevel@tonic-gate bytes_xfered = GetTD_alen(uhcip, td);
15850Sstevel@tonic-gate if (bytes_xfered == ZERO_LENGTH) {
15860Sstevel@tonic-gate bytes_xfered = 0;
15870Sstevel@tonic-gate } else {
15880Sstevel@tonic-gate bytes_xfered++;
15890Sstevel@tonic-gate }
15900Sstevel@tonic-gate
15910Sstevel@tonic-gate tw->tw_bytes_pending -= bytes_xfered;
15920Sstevel@tonic-gate tw->tw_bytes_xfered += bytes_xfered;
15930Sstevel@tonic-gate
15940Sstevel@tonic-gate if (bytes_xfered < tw->tw_tmp) {
15950Sstevel@tonic-gate tw->tw_bytes_pending = 0;
15960Sstevel@tonic-gate tw->tw_tmp = UHCI_UNDERRUN_OCCURRED;
15970Sstevel@tonic-gate
15980Sstevel@tonic-gate /*
15990Sstevel@tonic-gate * Controller does not update the queue head
16000Sstevel@tonic-gate * element pointer when a data underrun occurs.
16010Sstevel@tonic-gate */
16020Sstevel@tonic-gate SetQH32(uhcip, pp->pp_qh->element_ptr,
16030Sstevel@tonic-gate GetTD32(uhcip, td->link_ptr));
16040Sstevel@tonic-gate }
16050Sstevel@tonic-gate
16060Sstevel@tonic-gate if (bytes_xfered > tw->tw_tmp) {
16070Sstevel@tonic-gate tw->tw_bytes_pending = 0;
16080Sstevel@tonic-gate tw->tw_tmp = UHCI_OVERRUN_OCCURRED;
16090Sstevel@tonic-gate }
16100Sstevel@tonic-gate
16110Sstevel@tonic-gate /*
16120Sstevel@tonic-gate * If no more bytes are pending, insert status
16130Sstevel@tonic-gate * phase. Otherwise insert data phase.
16140Sstevel@tonic-gate */
16150Sstevel@tonic-gate if (tw->tw_bytes_pending) {
16160Sstevel@tonic-gate bytes_for_xfer = (tw->tw_bytes_pending >
16174384Sfb209375 MaxPacketSize) ? MaxPacketSize :
16184384Sfb209375 tw->tw_bytes_pending;
16190Sstevel@tonic-gate
16200Sstevel@tonic-gate tw->tw_tmp = bytes_for_xfer;
16210Sstevel@tonic-gate
16220Sstevel@tonic-gate if ((uhci_insert_hc_td(uhcip,
16232125Ssl147100 UHCI_CTRL_EPT_MAX_SIZE + tw->tw_bytes_xfered,
16242125Ssl147100 bytes_for_xfer, pp, tw,
16250Sstevel@tonic-gate tw->tw_direction,
16260Sstevel@tonic-gate reqp->ctrl_attributes)) != USB_SUCCESS) {
16270Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS,
16280Sstevel@tonic-gate uhcip->uhci_log_hdl,
16290Sstevel@tonic-gate "uhci_handle_ctrl_td: No TD");
16300Sstevel@tonic-gate
16310Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, usb_pp,
16320Sstevel@tonic-gate tw, USB_NO_RESOURCES);
16330Sstevel@tonic-gate
16340Sstevel@tonic-gate return;
16350Sstevel@tonic-gate }
16360Sstevel@tonic-gate
16370Sstevel@tonic-gate tw->tw_ctrl_state = DATA;
16380Sstevel@tonic-gate
16390Sstevel@tonic-gate break;
16400Sstevel@tonic-gate }
16410Sstevel@tonic-gate
16420Sstevel@tonic-gate pp->pp_data_toggle = 1;
16430Sstevel@tonic-gate direction = (tw->tw_direction == PID_IN) ? PID_OUT : PID_IN;
16440Sstevel@tonic-gate
16452125Ssl147100 if ((uhci_insert_hc_td(uhcip, 0, 0, pp, tw, direction,
16460Sstevel@tonic-gate reqp->ctrl_attributes)) != USB_SUCCESS) {
16470Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
16480Sstevel@tonic-gate "uhci_handle_ctrl_td: TD exhausted");
16490Sstevel@tonic-gate
16500Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, usb_pp, tw,
16510Sstevel@tonic-gate USB_NO_RESOURCES);
16520Sstevel@tonic-gate
16530Sstevel@tonic-gate return;
16540Sstevel@tonic-gate }
16550Sstevel@tonic-gate
16560Sstevel@tonic-gate tw->tw_ctrl_state = STATUS;
16570Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
16580Sstevel@tonic-gate "Data complete: pp 0x%p td 0x%p", (void *)pp, (void *)td);
16590Sstevel@tonic-gate
16600Sstevel@tonic-gate break;
16610Sstevel@tonic-gate case STATUS:
16620Sstevel@tonic-gate /*
16630Sstevel@tonic-gate * Send the data to the client if it is a DATA IN,
16640Sstevel@tonic-gate * else send just return status for DATA OUT commnads.
16650Sstevel@tonic-gate * And set the tw_claim flag.
16660Sstevel@tonic-gate */
16670Sstevel@tonic-gate tw->tw_claim = UHCI_INTR_HDLR_CLAIMED;
16680Sstevel@tonic-gate
16690Sstevel@tonic-gate if ((tw->tw_length != 0) && (tw->tw_direction == PID_IN)) {
16700Sstevel@tonic-gate usb_req_attrs_t attrs = ((usb_ctrl_req_t *)
16714384Sfb209375 tw->tw_curr_xfer_reqp)->ctrl_attributes;
16720Sstevel@tonic-gate /*
16730Sstevel@tonic-gate * Call uhci_sendup_td_message to send message
16740Sstevel@tonic-gate * upstream. The function uhci_sendup_td_message
16750Sstevel@tonic-gate * returns USB_NO_RESOURCES if allocb fails and
16760Sstevel@tonic-gate * also sends error message to upstream by calling
16770Sstevel@tonic-gate * USBA callback function.
16780Sstevel@tonic-gate *
16790Sstevel@tonic-gate * Under error conditions just drop the current msg.
16800Sstevel@tonic-gate */
16810Sstevel@tonic-gate if ((tw->tw_tmp == UHCI_UNDERRUN_OCCURRED) &&
16820Sstevel@tonic-gate (!(attrs & USB_ATTRS_SHORT_XFER_OK))) {
16830Sstevel@tonic-gate error = USB_CR_DATA_UNDERRUN;
16840Sstevel@tonic-gate } else if (tw->tw_tmp == UHCI_OVERRUN_OCCURRED) {
16850Sstevel@tonic-gate error = USB_CR_DATA_OVERRUN;
16860Sstevel@tonic-gate }
16870Sstevel@tonic-gate uhci_sendup_td_message(uhcip, error, tw);
16880Sstevel@tonic-gate
16890Sstevel@tonic-gate } else {
16900Sstevel@tonic-gate uhci_do_byte_stats(uhcip, tw->tw_length,
16910Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress);
16920Sstevel@tonic-gate
16930Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, usb_pp, tw, USB_CR_OK);
16940Sstevel@tonic-gate }
16950Sstevel@tonic-gate
16960Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
16976898Sfb209375 "Status complete: pp 0x%p td 0x%p", (void *)pp, (void *)td);
16980Sstevel@tonic-gate
16990Sstevel@tonic-gate uhci_delete_td(uhcip, td);
17000Sstevel@tonic-gate uhci_deallocate_tw(uhcip, pp, tw);
17010Sstevel@tonic-gate
17020Sstevel@tonic-gate break;
17030Sstevel@tonic-gate default:
17040Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
17050Sstevel@tonic-gate "uhci_handle_ctrl_td: Bad control state");
17060Sstevel@tonic-gate
17070Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, usb_pp, tw,
17080Sstevel@tonic-gate USB_CR_UNSPECIFIED_ERR);
17090Sstevel@tonic-gate }
17100Sstevel@tonic-gate }
17110Sstevel@tonic-gate
17120Sstevel@tonic-gate
17130Sstevel@tonic-gate /*
17140Sstevel@tonic-gate * uhci_handle_intr_td_errors:
17150Sstevel@tonic-gate * Handles the errors encountered for the interrupt transfers.
17160Sstevel@tonic-gate */
17170Sstevel@tonic-gate static void
uhci_handle_intr_td_errors(uhci_state_t * uhcip,uhci_td_t * td,uhci_trans_wrapper_t * tw,uhci_pipe_private_t * pp)17180Sstevel@tonic-gate uhci_handle_intr_td_errors(uhci_state_t *uhcip, uhci_td_t *td,
17190Sstevel@tonic-gate uhci_trans_wrapper_t *tw, uhci_pipe_private_t *pp)
17200Sstevel@tonic-gate {
17210Sstevel@tonic-gate usb_cr_t usb_err;
17220Sstevel@tonic-gate usb_intr_req_t *intr_reqp =
17234384Sfb209375 (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
17240Sstevel@tonic-gate
17250Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
17266898Sfb209375 "uhci_handle_intr_td_errors: td = 0x%p tw = 0x%p",
17276898Sfb209375 (void *)td, (void *)tw);
17280Sstevel@tonic-gate
17290Sstevel@tonic-gate usb_err = uhci_parse_td_error(uhcip, pp, td);
17300Sstevel@tonic-gate
17310Sstevel@tonic-gate if (intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) {
17320Sstevel@tonic-gate uhci_handle_one_xfer_completion(uhcip, usb_err, td);
17330Sstevel@tonic-gate
17340Sstevel@tonic-gate return;
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate
17370Sstevel@tonic-gate uhci_delete_td(uhcip, td);
17380Sstevel@tonic-gate uhci_sendup_td_message(uhcip, usb_err, tw);
17390Sstevel@tonic-gate uhci_deallocate_tw(uhcip, tw->tw_pipe_private, tw);
17400Sstevel@tonic-gate }
17410Sstevel@tonic-gate
17420Sstevel@tonic-gate
17430Sstevel@tonic-gate /*
17440Sstevel@tonic-gate * uhci_handle_one_xfer_completion:
17450Sstevel@tonic-gate */
17460Sstevel@tonic-gate static void
uhci_handle_one_xfer_completion(uhci_state_t * uhcip,usb_cr_t usb_err,uhci_td_t * td)17470Sstevel@tonic-gate uhci_handle_one_xfer_completion(
17480Sstevel@tonic-gate uhci_state_t *uhcip,
17490Sstevel@tonic-gate usb_cr_t usb_err,
17500Sstevel@tonic-gate uhci_td_t *td)
17510Sstevel@tonic-gate {
17520Sstevel@tonic-gate uhci_trans_wrapper_t *tw = td->tw;
17530Sstevel@tonic-gate uhci_pipe_private_t *pp = tw->tw_pipe_private;
17540Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
17550Sstevel@tonic-gate usb_intr_req_t *intr_reqp =
17564384Sfb209375 (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
17570Sstevel@tonic-gate
17580Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
17596898Sfb209375 "uhci_handle_one_xfer_completion: td = 0x%p", (void *)td);
17600Sstevel@tonic-gate
17610Sstevel@tonic-gate ASSERT(intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER);
17620Sstevel@tonic-gate
17630Sstevel@tonic-gate /* set state to idle */
17640Sstevel@tonic-gate pp->pp_state = UHCI_PIPE_STATE_IDLE;
17650Sstevel@tonic-gate
17660Sstevel@tonic-gate ((usb_intr_req_t *)(pp->pp_client_periodic_in_reqp))->
17670Sstevel@tonic-gate intr_data = ((usb_intr_req_t *)(tw->tw_curr_xfer_reqp))->intr_data;
17680Sstevel@tonic-gate
17690Sstevel@tonic-gate ((usb_intr_req_t *)tw->tw_curr_xfer_reqp)->intr_data = NULL;
17700Sstevel@tonic-gate
17710Sstevel@tonic-gate /* now free duplicate current request */
17720Sstevel@tonic-gate usb_free_intr_req((usb_intr_req_t *)tw->tw_curr_xfer_reqp);
17730Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
17740Sstevel@tonic-gate ph->p_req_count--;
17750Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
17760Sstevel@tonic-gate
17770Sstevel@tonic-gate /* make client's request the current request */
17780Sstevel@tonic-gate tw->tw_curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
17790Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL;
17800Sstevel@tonic-gate
17810Sstevel@tonic-gate uhci_sendup_td_message(uhcip, usb_err, tw);
17820Sstevel@tonic-gate /* Clear the tw->tw_claim flag */
17830Sstevel@tonic-gate tw->tw_claim = UHCI_NOT_CLAIMED;
17840Sstevel@tonic-gate
17850Sstevel@tonic-gate uhci_delete_td(uhcip, td);
17860Sstevel@tonic-gate uhci_deallocate_tw(uhcip, pp, tw);
17870Sstevel@tonic-gate }
17880Sstevel@tonic-gate
17890Sstevel@tonic-gate
17900Sstevel@tonic-gate /*
17910Sstevel@tonic-gate * uhci_parse_td_error
17920Sstevel@tonic-gate * Parses the Transfer Descriptors error
17930Sstevel@tonic-gate */
17940Sstevel@tonic-gate usb_cr_t
uhci_parse_td_error(uhci_state_t * uhcip,uhci_pipe_private_t * pp,uhci_td_t * td)17950Sstevel@tonic-gate uhci_parse_td_error(uhci_state_t *uhcip, uhci_pipe_private_t *pp, uhci_td_t *td)
17960Sstevel@tonic-gate {
17970Sstevel@tonic-gate uint_t status;
17980Sstevel@tonic-gate
17990Sstevel@tonic-gate status = GetTD_status(uhcip, td) & TD_STATUS_MASK;
18000Sstevel@tonic-gate
18010Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
18020Sstevel@tonic-gate "uhci_parse_td_error: status_bits=0x%x", status);
18030Sstevel@tonic-gate
18040Sstevel@tonic-gate if (UHCI_XFER_TYPE(&pp->pp_pipe_handle->p_ep) == USB_EP_ATTR_ISOCH) {
18050Sstevel@tonic-gate
18060Sstevel@tonic-gate return (USB_CR_OK);
18070Sstevel@tonic-gate }
18080Sstevel@tonic-gate
18090Sstevel@tonic-gate if (!status) {
18100Sstevel@tonic-gate
18110Sstevel@tonic-gate return (USB_CR_OK);
18120Sstevel@tonic-gate }
18130Sstevel@tonic-gate
18140Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
18150Sstevel@tonic-gate "uhci_parse_td_error: status_bits=0x%x", status);
18160Sstevel@tonic-gate
18170Sstevel@tonic-gate
18180Sstevel@tonic-gate if (status & UHCI_TD_BITSTUFF_ERR) {
18190Sstevel@tonic-gate
18200Sstevel@tonic-gate return (USB_CR_BITSTUFFING);
18210Sstevel@tonic-gate }
18220Sstevel@tonic-gate
18230Sstevel@tonic-gate if (status & UHCI_TD_CRC_TIMEOUT) {
18240Sstevel@tonic-gate pp->pp_data_toggle = GetTD_dtogg(uhcip, td);
18250Sstevel@tonic-gate
18260Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
18270Sstevel@tonic-gate "uhci_parse_td_error: timeout & data toggle reset; "
18280Sstevel@tonic-gate "data toggle: %x", pp->pp_data_toggle);
18290Sstevel@tonic-gate
18300Sstevel@tonic-gate return ((GetTD_PID(uhcip, td) == PID_IN) ? USB_CR_DEV_NOT_RESP :
18310Sstevel@tonic-gate USB_CR_TIMEOUT);
18320Sstevel@tonic-gate }
18330Sstevel@tonic-gate
18340Sstevel@tonic-gate if (status & UHCI_TD_BABBLE_ERR) {
18350Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
18360Sstevel@tonic-gate "babble error");
18370Sstevel@tonic-gate
18380Sstevel@tonic-gate return (USB_CR_UNSPECIFIED_ERR);
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate
18410Sstevel@tonic-gate if (status & UHCI_TD_DATA_BUFFER_ERR) {
18420Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
18430Sstevel@tonic-gate "buffer error");
18440Sstevel@tonic-gate
18450Sstevel@tonic-gate return ((GetTD_PID(uhcip, td) == PID_IN) ?
18460Sstevel@tonic-gate USB_CR_BUFFER_OVERRUN : USB_CR_BUFFER_UNDERRUN);
18470Sstevel@tonic-gate }
18480Sstevel@tonic-gate
18490Sstevel@tonic-gate if (status & UHCI_TD_STALLED) {
18500Sstevel@tonic-gate pp->pp_data_toggle = 0;
18510Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
18520Sstevel@tonic-gate "uhci_parse_td_error: stall; data toggle reset; "
18530Sstevel@tonic-gate "data toggle: %x", pp->pp_data_toggle);
18540Sstevel@tonic-gate
18550Sstevel@tonic-gate return (USB_CR_STALL);
18560Sstevel@tonic-gate }
18570Sstevel@tonic-gate
18580Sstevel@tonic-gate if (status) {
18590Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
18600Sstevel@tonic-gate "unspecified error=0x%x", status);
18610Sstevel@tonic-gate }
18620Sstevel@tonic-gate
18630Sstevel@tonic-gate return (USB_CR_OK);
18640Sstevel@tonic-gate }
18650Sstevel@tonic-gate
18660Sstevel@tonic-gate
18670Sstevel@tonic-gate static dev_info_t *
uhci_get_dip(dev_t dev)18680Sstevel@tonic-gate uhci_get_dip(dev_t dev)
18690Sstevel@tonic-gate {
18700Sstevel@tonic-gate int instance = UHCI_UNIT(dev);
18710Sstevel@tonic-gate uhci_state_t *uhcip = ddi_get_soft_state(uhci_statep, instance);
18720Sstevel@tonic-gate
18730Sstevel@tonic-gate return (uhcip ? uhcip->uhci_dip : NULL);
18740Sstevel@tonic-gate }
18750Sstevel@tonic-gate
18760Sstevel@tonic-gate
18770Sstevel@tonic-gate /*
18780Sstevel@tonic-gate * cb_ops entry points
18790Sstevel@tonic-gate */
18800Sstevel@tonic-gate static int
uhci_open(dev_t * devp,int flags,int otyp,cred_t * credp)18810Sstevel@tonic-gate uhci_open(dev_t *devp, int flags, int otyp, cred_t *credp)
18820Sstevel@tonic-gate {
18830Sstevel@tonic-gate dev_info_t *dip = uhci_get_dip(*devp);
18840Sstevel@tonic-gate
18850Sstevel@tonic-gate return (usba_hubdi_open(dip, devp, flags, otyp, credp));
18860Sstevel@tonic-gate }
18870Sstevel@tonic-gate
18880Sstevel@tonic-gate
18890Sstevel@tonic-gate static int
uhci_close(dev_t dev,int flag,int otyp,cred_t * credp)18900Sstevel@tonic-gate uhci_close(dev_t dev, int flag, int otyp, cred_t *credp)
18910Sstevel@tonic-gate {
18920Sstevel@tonic-gate dev_info_t *dip = uhci_get_dip(dev);
18930Sstevel@tonic-gate
18940Sstevel@tonic-gate return (usba_hubdi_close(dip, dev, flag, otyp, credp));
18950Sstevel@tonic-gate }
18960Sstevel@tonic-gate
18970Sstevel@tonic-gate
18980Sstevel@tonic-gate static int
uhci_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)18990Sstevel@tonic-gate uhci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
19000Sstevel@tonic-gate cred_t *credp, int *rvalp)
19010Sstevel@tonic-gate {
19020Sstevel@tonic-gate dev_info_t *dip = uhci_get_dip(dev);
19030Sstevel@tonic-gate
19040Sstevel@tonic-gate return (usba_hubdi_ioctl(dip, dev, cmd, arg, mode, credp, rvalp));
19050Sstevel@tonic-gate }
1906