xref: /onnv-gate/usr/src/uts/common/io/usb/hcd/uhci/uhci.c (revision 12819:b9f8177eb4e2)
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