xref: /onnv-gate/usr/src/uts/common/io/usb/hcd/uhci/uhcitgt.c (revision 12559:e3b3e6fd0267)
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
53026Syq193411  * Common Development and Distribution License (the "License").
63026Syq193411  * 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 /*
2212377SRaymond.Chen@Sun.COM  * Copyright (c) 1999, 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 Driver (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 the code for HCDI entry points.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcid.h>
350Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcitgt.h>
360Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhciutil.h>
376990Sgd78059 #include <sys/strsun.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate /* function prototypes */
400Sstevel@tonic-gate static int	uhci_pipe_send_isoc_data(uhci_state_t *uhcip,
410Sstevel@tonic-gate 			usba_pipe_handle_data_t *ph, usb_isoc_req_t *isoc_req,
420Sstevel@tonic-gate 			usb_flags_t usb_flags);
430Sstevel@tonic-gate static int	uhci_send_intr_data(uhci_state_t *uhcip,
440Sstevel@tonic-gate 			usba_pipe_handle_data_t	*pipe_handle,
450Sstevel@tonic-gate 			usb_intr_req_t		*req,
460Sstevel@tonic-gate 			usb_flags_t		flags);
470Sstevel@tonic-gate static int	uhci_start_periodic_pipe_polling(uhci_state_t *uhcip,
480Sstevel@tonic-gate 			usba_pipe_handle_data_t	*ph,
490Sstevel@tonic-gate 			usb_opaque_t		reqp,
500Sstevel@tonic-gate 			usb_flags_t		flags);
510Sstevel@tonic-gate static int	uhci_stop_periodic_pipe_polling(uhci_state_t *uhcip,
520Sstevel@tonic-gate 			usba_pipe_handle_data_t	*ph,
530Sstevel@tonic-gate 			usb_flags_t		flags);
540Sstevel@tonic-gate static void	uhci_update_intr_td_data_toggle(uhci_state_t *uhcip,
550Sstevel@tonic-gate 			uhci_pipe_private_t *pp);
560Sstevel@tonic-gate 
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /* Maximum bulk transfer size */
59880Sfrits int uhci_bulk_transfer_size = UHCI_BULK_MAX_XFER_SIZE;
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate  * uhci_hcdi_pipe_open:
630Sstevel@tonic-gate  *	Member of HCD Ops structure and called during client specific pipe open
640Sstevel@tonic-gate  *	Add the pipe to the data structure representing the device and allocate
650Sstevel@tonic-gate  *	bandwidth for the pipe if it is a interrupt or isochronous endpoint.
660Sstevel@tonic-gate  */
670Sstevel@tonic-gate int
uhci_hcdi_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t flags)680Sstevel@tonic-gate uhci_hcdi_pipe_open(usba_pipe_handle_data_t *ph, usb_flags_t flags)
690Sstevel@tonic-gate {
700Sstevel@tonic-gate 	uint_t			node = 0;
710Sstevel@tonic-gate 	usb_addr_t		usb_addr;
720Sstevel@tonic-gate 	uhci_state_t		*uhcip;
730Sstevel@tonic-gate 	uhci_pipe_private_t	*pp;
745773Sqz150045 	int			rval, error = USB_SUCCESS;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	ASSERT(ph);
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	usb_addr = ph->p_usba_device->usb_addr;
790Sstevel@tonic-gate 	uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
820Sstevel@tonic-gate 	    "uhci_hcdi_pipe_open: addr = 0x%x, ep%d", usb_addr,
830Sstevel@tonic-gate 	    ph->p_ep.bEndpointAddress & USB_EP_NUM_MASK);
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	sema_p(&uhcip->uhci_ocsem);
860Sstevel@tonic-gate 
875773Sqz150045 	mutex_enter(&uhcip->uhci_int_mutex);
885773Sqz150045 	rval = uhci_state_is_operational(uhcip);
895773Sqz150045 	mutex_exit(&uhcip->uhci_int_mutex);
905773Sqz150045 
915773Sqz150045 	if (rval != USB_SUCCESS) {
925773Sqz150045 		sema_v(&uhcip->uhci_ocsem);
935773Sqz150045 
945773Sqz150045 		return (rval);
955773Sqz150045 	}
965773Sqz150045 
970Sstevel@tonic-gate 	/*
980Sstevel@tonic-gate 	 * Return failure immediately for any other pipe open on the root hub
990Sstevel@tonic-gate 	 * except control or interrupt pipe.
1000Sstevel@tonic-gate 	 */
1010Sstevel@tonic-gate 	if (usb_addr == ROOT_HUB_ADDR) {
1020Sstevel@tonic-gate 		switch (UHCI_XFER_TYPE(&ph->p_ep)) {
1030Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
1040Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1050Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: Root hub control pipe");
1060Sstevel@tonic-gate 			break;
1070Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
1080Sstevel@tonic-gate 			ASSERT(UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 			mutex_enter(&uhcip->uhci_int_mutex);
1110Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_intr_pipe_handle = ph;
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 			/*
1140Sstevel@tonic-gate 			 * Set the state of the root hub interrupt
1150Sstevel@tonic-gate 			 * pipe as IDLE.
1160Sstevel@tonic-gate 			 */
1170Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_pipe_state =
1185773Sqz150045 			    UHCI_PIPE_STATE_IDLE;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 			ASSERT(uhcip->uhci_root_hub.rh_client_intr_req == NULL);
1210Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_client_intr_req = NULL;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 			ASSERT(uhcip->uhci_root_hub.rh_curr_intr_reqp == NULL);
1240Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_curr_intr_reqp = NULL;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1270Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: Root hub interrupt "
1280Sstevel@tonic-gate 			    "pipe open succeeded");
1290Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
1300Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 			return (USB_SUCCESS);
1330Sstevel@tonic-gate 		default:
1340Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1350Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: Root hub pipe open failed");
1360Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 			return (USB_FAILURE);
1390Sstevel@tonic-gate 		}
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	/*
1430Sstevel@tonic-gate 	 * A portion of the bandwidth is reserved for the non-periodic
1440Sstevel@tonic-gate 	 * transfers  i.e control and bulk transfers in each  of one
1450Sstevel@tonic-gate 	 * mill second frame period & usually it will be 10% of frame
1460Sstevel@tonic-gate 	 * period. Hence there is no need to check for the available
1470Sstevel@tonic-gate 	 * bandwidth before adding the control or bulk endpoints.
1480Sstevel@tonic-gate 	 *
1490Sstevel@tonic-gate 	 * There is a need to check for the available bandwidth before
1500Sstevel@tonic-gate 	 * adding the periodic transfers i.e interrupt & isochronous, since
1510Sstevel@tonic-gate 	 * all these periodic transfers are guaranteed transfers. Usually,
1520Sstevel@tonic-gate 	 * 90% of the total frame time is reserved for periodic transfers.
1530Sstevel@tonic-gate 	 */
1540Sstevel@tonic-gate 	if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) {
1550Sstevel@tonic-gate 		/* Zero Max Packet size endpoints are not supported */
1560Sstevel@tonic-gate 		if (ph->p_ep.wMaxPacketSize == 0) {
1570Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1580Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: Zero length packet");
1590Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 			return (USB_FAILURE);
1620Sstevel@tonic-gate 		}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 		mutex_enter(&uhcip->uhci_int_mutex);
1650Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 		error = uhci_allocate_bandwidth(uhcip, ph, &node);
1680Sstevel@tonic-gate 		if (error != USB_SUCCESS) {
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1710Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: Bandwidth allocation failed");
1720Sstevel@tonic-gate 			mutex_exit(&ph->p_mutex);
1730Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
1740Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 			return (error);
1770Sstevel@tonic-gate 		}
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
1800Sstevel@tonic-gate 		mutex_exit(&uhcip->uhci_int_mutex);
1810Sstevel@tonic-gate 	}
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	/* Create the HCD pipe private structure */
1840Sstevel@tonic-gate 	pp = kmem_zalloc(sizeof (uhci_pipe_private_t),
1850Sstevel@tonic-gate 	    (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
1860Sstevel@tonic-gate 	if (pp == NULL) {
1870Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1880Sstevel@tonic-gate 		    "uhci_hcdi_pipe_open: pp allocation failure");
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 		if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) {
1910Sstevel@tonic-gate 			mutex_enter(&uhcip->uhci_int_mutex);
1920Sstevel@tonic-gate 			uhci_deallocate_bandwidth(uhcip, ph);
1930Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
1940Sstevel@tonic-gate 		}
1950Sstevel@tonic-gate 		sema_v(&uhcip->uhci_ocsem);
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
2015773Sqz150045 	rval = uhci_state_is_operational(uhcip);
2025773Sqz150045 
2035773Sqz150045 	if (rval != USB_SUCCESS) {
2045773Sqz150045 		kmem_free(ph, sizeof (uhci_pipe_private_t));
2055773Sqz150045 		mutex_exit(&uhcip->uhci_int_mutex);
2065773Sqz150045 		sema_v(&uhcip->uhci_ocsem);
2075773Sqz150045 
2085773Sqz150045 		return (rval);
2095773Sqz150045 	}
2100Sstevel@tonic-gate 	pp->pp_node = node;	/* Store the node in the interrupt lattice */
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	/* Initialize frame number */
2130Sstevel@tonic-gate 	pp->pp_frame_num = INVALID_FRNUM;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	/* Set the state of pipe as IDLE */
2160Sstevel@tonic-gate 	pp->pp_state = UHCI_PIPE_STATE_IDLE;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	/* Store a pointer to the pipe handle */
2190Sstevel@tonic-gate 	pp->pp_pipe_handle = ph;
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	/* Store the pointer in the pipe handle */
2220Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
2230Sstevel@tonic-gate 	ph->p_hcd_private = (usb_opaque_t)pp;
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	/* Store a copy of the pipe policy */
2260Sstevel@tonic-gate 	bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t));
2270Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	/* don't check for ROOT_HUB here anymore */
2300Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(&ph->p_ep) != USB_EP_ATTR_ISOCH) {
2310Sstevel@tonic-gate 		/* Allocate the host controller endpoint descriptor */
2320Sstevel@tonic-gate 		pp->pp_qh = uhci_alloc_queue_head(uhcip);
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 		if (pp->pp_qh == NULL) {
2350Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
2360Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: QH allocation failed");
2370Sstevel@tonic-gate 
2383026Syq193411 			if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) {
2393026Syq193411 				uhci_deallocate_bandwidth(uhcip, ph);
2403026Syq193411 			}
2413026Syq193411 
2420Sstevel@tonic-gate 			mutex_enter(&ph->p_mutex);
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 			/*
2450Sstevel@tonic-gate 			 * Deallocate the hcd private portion
2460Sstevel@tonic-gate 			 * of the pipe handle.
2470Sstevel@tonic-gate 			 */
2480Sstevel@tonic-gate 			kmem_free(ph->p_hcd_private,
2495773Sqz150045 			    sizeof (uhci_pipe_private_t));
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 			/*
2520Sstevel@tonic-gate 			 * Set the private structure in the
2530Sstevel@tonic-gate 			 * pipe handle equal to NULL.
2540Sstevel@tonic-gate 			 */
2550Sstevel@tonic-gate 			ph->p_hcd_private = NULL;
2560Sstevel@tonic-gate 			mutex_exit(&ph->p_mutex);
2570Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 			return (USB_NO_RESOURCES);
2620Sstevel@tonic-gate 		}
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 		/*
2650Sstevel@tonic-gate 		 * Insert the endpoint onto the host controller's
2660Sstevel@tonic-gate 		 * appropriate endpoint list. The host controller
2670Sstevel@tonic-gate 		 * will not schedule this endpoint until there are
2680Sstevel@tonic-gate 		 * any TD's to process.
2690Sstevel@tonic-gate 		 */
2700Sstevel@tonic-gate 		uhci_insert_qh(uhcip, ph);
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	/*
2740Sstevel@tonic-gate 	 * Restore the data toggle from usb device structure.
2750Sstevel@tonic-gate 	 */
2763026Syq193411 	if (((ph->p_ep.bmAttributes) & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR ||
2773026Syq193411 	    ((ph->p_ep.bmAttributes) & USB_EP_ATTR_MASK) == USB_EP_ATTR_BULK) {
2780Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 		pp->pp_data_toggle = usba_hcdi_get_data_toggle(
2815773Sqz150045 		    ph->p_usba_device, ph->p_ep.bEndpointAddress);
2820Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
2860Sstevel@tonic-gate 	sema_v(&uhcip->uhci_ocsem);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
2896898Sfb209375 	    "uhci_hcdi_pipe_open: ph = 0x%p", (void *)ph);
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	return (USB_SUCCESS);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate /*
2960Sstevel@tonic-gate  * uhci_hcdi_pipe_close:
2970Sstevel@tonic-gate  *	Member of HCD Ops structure and called during the client specific pipe
2980Sstevel@tonic-gate  *	close. Remove the pipe to the data structure representing the device
2990Sstevel@tonic-gate  *	deallocate bandwidth for the pipe if it is an intr or isoch endpoint.
3000Sstevel@tonic-gate  */
3010Sstevel@tonic-gate int
uhci_hcdi_pipe_close(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)3020Sstevel@tonic-gate uhci_hcdi_pipe_close(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags)
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate 	usb_addr_t		usb_addr;
3050Sstevel@tonic-gate 	uhci_state_t		*uhcip;
3060Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
3070Sstevel@tonic-gate 	uhci_pipe_private_t	*pp;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
3100Sstevel@tonic-gate 	pp = (uhci_pipe_private_t *)ph->p_hcd_private;
3110Sstevel@tonic-gate 	usb_addr = ph->p_usba_device->usb_addr;
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
3140Sstevel@tonic-gate 	    "uhci_hcdi_pipe_close: addr = 0x%x, ep%d, flags = 0x%x", usb_addr,
3150Sstevel@tonic-gate 	    eptd->bEndpointAddress, usb_flags);
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	sema_p(&uhcip->uhci_ocsem);
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	/*
3220Sstevel@tonic-gate 	 * Check whether the pipe is a root hub
3230Sstevel@tonic-gate 	 */
3240Sstevel@tonic-gate 	if (usb_addr == ROOT_HUB_ADDR) {
3250Sstevel@tonic-gate 		switch (UHCI_XFER_TYPE(eptd)) {
3260Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
3270Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
3280Sstevel@tonic-gate 			    "uhci_hcdi_pipe_close: Root hub control pipe "
3290Sstevel@tonic-gate 			    "close succeeded");
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 			break;
3320Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
3330Sstevel@tonic-gate 			ASSERT((eptd->bEndpointAddress &
3345773Sqz150045 			    USB_EP_NUM_MASK) == 1);
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 			/* Do interrupt pipe cleanup */
3370Sstevel@tonic-gate 			uhci_root_hub_intr_pipe_cleanup(uhcip,
3385773Sqz150045 			    USB_CR_PIPE_CLOSING);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 			ASSERT(uhcip->uhci_root_hub.rh_pipe_state ==
3415773Sqz150045 			    UHCI_PIPE_STATE_IDLE);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_intr_pipe_handle = NULL;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
3460Sstevel@tonic-gate 			    "uhci_hcdi_pipe_close: Root hub interrupt "
3470Sstevel@tonic-gate 			    "pipe close succeeded");
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_pipe_state =
3505773Sqz150045 			    UHCI_PIPE_STATE_IDLE;
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
3530Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
3540Sstevel@tonic-gate 			return (USB_SUCCESS);
3550Sstevel@tonic-gate 		}
3560Sstevel@tonic-gate 	} else {
3570Sstevel@tonic-gate 		/*
3580Sstevel@tonic-gate 		 * Stop all the transactions if it is not the root hub.
3590Sstevel@tonic-gate 		 */
3600Sstevel@tonic-gate 		if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_INTR) {
3610Sstevel@tonic-gate 			/*
3620Sstevel@tonic-gate 			 * Stop polling on the pipe to prevent any subsequently
3630Sstevel@tonic-gate 			 * queued tds (while we're waiting for SOF, below)
3640Sstevel@tonic-gate 			 * from being executed
3650Sstevel@tonic-gate 			 */
3660Sstevel@tonic-gate 			pp->pp_state = UHCI_PIPE_STATE_IDLE;
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 		/* Disable all outstanding tds */
3700Sstevel@tonic-gate 		uhci_modify_td_active_bits(uhcip, pp);
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		/* Prevent this queue from being executed */
3730Sstevel@tonic-gate 		if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) {
3740Sstevel@tonic-gate 			UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr);
3750Sstevel@tonic-gate 		}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 		/* Wait for the next start of frame */
3780Sstevel@tonic-gate 		(void) uhci_wait_for_sof(uhcip);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 		ASSERT(eptd != NULL);
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 		switch (UHCI_XFER_TYPE(eptd)) {
3830Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
3840Sstevel@tonic-gate 			uhci_update_intr_td_data_toggle(uhcip, pp);
3850Sstevel@tonic-gate 			/* FALLTHROUGH */
3860Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
3870Sstevel@tonic-gate 			uhci_remove_tds_tws(uhcip, ph);
3880Sstevel@tonic-gate 			break;
3890Sstevel@tonic-gate 		case USB_EP_ATTR_BULK:
3900Sstevel@tonic-gate 			SetQH32(uhcip, pp->pp_qh->element_ptr,
3910Sstevel@tonic-gate 			    TD_PADDR(pp->pp_qh->td_tailp));
3920Sstevel@tonic-gate 			uhci_remove_bulk_tds_tws(uhcip, pp, UHCI_IN_CLOSE);
3930Sstevel@tonic-gate 			uhci_save_data_toggle(pp);
3940Sstevel@tonic-gate 			break;
3950Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
3960Sstevel@tonic-gate 			uhci_remove_isoc_tds_tws(uhcip, pp);
3970Sstevel@tonic-gate 			break;
3980Sstevel@tonic-gate 		default:
3990Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
4000Sstevel@tonic-gate 			    "uhci_hcdi_pipe_close: Unknown xfer type");
4010Sstevel@tonic-gate 			break;
4020Sstevel@tonic-gate 		}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 		/*
4050Sstevel@tonic-gate 		 * Remove the endoint descriptor from Host Controller's
4060Sstevel@tonic-gate 		 * appropriate endpoint list. Isochronous pipes dont have
4070Sstevel@tonic-gate 		 * any queue heads attached to it.
4080Sstevel@tonic-gate 		 */
4090Sstevel@tonic-gate 		if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) {
4100Sstevel@tonic-gate 			uhci_remove_qh(uhcip, pp);
4110Sstevel@tonic-gate 		}
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 		/*
4140Sstevel@tonic-gate 		 * Do the callback for the original client
4150Sstevel@tonic-gate 		 * periodic IN request.
4160Sstevel@tonic-gate 		 */
4170Sstevel@tonic-gate 		if (pp->pp_client_periodic_in_reqp) {
4180Sstevel@tonic-gate 			uhci_hcdi_callback(uhcip, pp, ph, NULL,
4190Sstevel@tonic-gate 			    USB_CR_PIPE_CLOSING);
4200Sstevel@tonic-gate 		}
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 		/* Deallocate bandwidth */
4230Sstevel@tonic-gate 		if (UHCI_PERIODIC_ENDPOINT(eptd)) {
4240Sstevel@tonic-gate 			mutex_enter(&ph->p_mutex);
4250Sstevel@tonic-gate 			uhci_deallocate_bandwidth(uhcip, ph);
4260Sstevel@tonic-gate 			mutex_exit(&ph->p_mutex);
4270Sstevel@tonic-gate 		}
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	/* Deallocate the hcd private portion of the pipe handle.  */
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
4330Sstevel@tonic-gate 	kmem_free(ph->p_hcd_private, sizeof (uhci_pipe_private_t));
4340Sstevel@tonic-gate 	ph->p_hcd_private = NULL;
4350Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
4386898Sfb209375 	    "uhci_hcdi_pipe_close: ph = 0x%p", (void *)ph);
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
4410Sstevel@tonic-gate 	sema_v(&uhcip->uhci_ocsem);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	return (USB_SUCCESS);
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate /*
4480Sstevel@tonic-gate  * uhci_hcdi_pipe_reset:
4490Sstevel@tonic-gate  */
4500Sstevel@tonic-gate int
uhci_hcdi_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)4510Sstevel@tonic-gate uhci_hcdi_pipe_reset(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags)
4520Sstevel@tonic-gate {
4530Sstevel@tonic-gate 	uhci_state_t		*uhcip = uhci_obtain_state(
4545773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
4550Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
4560Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
457*12559SFei.Feng@Sun.COM 	usb_port_t		port;
458*12559SFei.Feng@Sun.COM 	uint_t 			port_status = 0;
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
4610Sstevel@tonic-gate 	    "uhci_hcdi_pipe_reset: usb_flags = 0x%x", usb_flags);
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	/*
46412377SRaymond.Chen@Sun.COM 	 * Under some circumstances, uhci internal hub's port
46512377SRaymond.Chen@Sun.COM 	 * may become disabled because of some errors(see UHCI HCD Spec)
46612377SRaymond.Chen@Sun.COM 	 * to make the UHCI driver robust enough, we should try to
46712377SRaymond.Chen@Sun.COM 	 * re-enable it again here because HCD has already know something
46812377SRaymond.Chen@Sun.COM 	 * bad happened.
46912377SRaymond.Chen@Sun.COM 	 */
47012377SRaymond.Chen@Sun.COM 	USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
47112377SRaymond.Chen@Sun.COM 	    "uhci_hcdi_pipe_reset: try "
47212377SRaymond.Chen@Sun.COM 	    "to enable disabled ports if necessary.");
473*12559SFei.Feng@Sun.COM 	for (port = 0; port < uhcip->uhci_root_hub.rh_num_ports; port++) {
474*12559SFei.Feng@Sun.COM 		port_status = Get_OpReg16(PORTSC[port]);
475*12559SFei.Feng@Sun.COM 		if ((!(port_status & HCR_PORT_ENABLE)) &&
476*12559SFei.Feng@Sun.COM 		    (port_status & HCR_PORT_CCS) &&
477*12559SFei.Feng@Sun.COM 		    (!(port_status & HCR_PORT_CSC))) {
478*12559SFei.Feng@Sun.COM 			Set_OpReg16(PORTSC[port],
479*12559SFei.Feng@Sun.COM 			    (port_status | HCR_PORT_ENABLE));
48012377SRaymond.Chen@Sun.COM 			drv_usecwait(UHCI_ONE_MS * 2);
48112377SRaymond.Chen@Sun.COM 		}
48212377SRaymond.Chen@Sun.COM 	}
48312377SRaymond.Chen@Sun.COM 
48412377SRaymond.Chen@Sun.COM 	/*
4850Sstevel@tonic-gate 	 * Return failure immediately for any other pipe reset on the root
4860Sstevel@tonic-gate 	 * hub except control or interrupt pipe.
4870Sstevel@tonic-gate 	 */
4880Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
4890Sstevel@tonic-gate 		switch (UHCI_XFER_TYPE(&ph->p_ep)) {
4900Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
4910Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
4920Sstevel@tonic-gate 			    "uhci_hcdi_pipe_reset: Pipe reset for root"
4930Sstevel@tonic-gate 			    "hub control pipe successful");
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 			break;
4960Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
4970Sstevel@tonic-gate 			mutex_enter(&uhcip->uhci_int_mutex);
4980Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_pipe_state =
4995773Sqz150045 			    UHCI_PIPE_STATE_IDLE;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 			/* Do interrupt pipe cleanup */
5020Sstevel@tonic-gate 			uhci_root_hub_intr_pipe_cleanup(uhcip,
5035773Sqz150045 			    USB_CR_PIPE_RESET);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
5060Sstevel@tonic-gate 			    "uhci_hcdi_pipe_reset: Pipe reset for "
5070Sstevel@tonic-gate 			    "root hub interrupt pipe successful");
5080Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 			break;
5110Sstevel@tonic-gate 		default:
5120Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
5135773Sqz150045 			    "uhci_hcdi_pipe_reset: Root hub pipe reset failed");
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 			return (USB_FAILURE);
5160Sstevel@tonic-gate 		}
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 		return (USB_SUCCESS);
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	/*
5240Sstevel@tonic-gate 	 * Set the active bit in to INACTIVE for all the remaining TD's of
5250Sstevel@tonic-gate 	 * this end point.  Set the active bit for the dummy td. This will
5260Sstevel@tonic-gate 	 * generate an interrupt at the end of the frame.  After receiving
5270Sstevel@tonic-gate 	 * the interrupt, it is safe to to manipulate the lattice.
5280Sstevel@tonic-gate 	 */
5290Sstevel@tonic-gate 	uhci_modify_td_active_bits(uhcip, pp);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	/* Initialize the element pointer */
5320Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) {
5330Sstevel@tonic-gate 		UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr);
5340Sstevel@tonic-gate 		SetQH32(uhcip, pp->pp_qh->element_ptr,
5350Sstevel@tonic-gate 		    TD_PADDR(pp->pp_qh->td_tailp));
5360Sstevel@tonic-gate 	}
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	(void) uhci_wait_for_sof(uhcip);
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/*
5410Sstevel@tonic-gate 	 * Save the data toggle and clear the pipe.
5420Sstevel@tonic-gate 	 */
5430Sstevel@tonic-gate 	switch (UHCI_XFER_TYPE(eptd)) {
5440Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
5450Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
5460Sstevel@tonic-gate 		uhci_remove_tds_tws(uhcip, ph);
5470Sstevel@tonic-gate 		break;
5480Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
5490Sstevel@tonic-gate 		SetQH32(uhcip, pp->pp_qh->element_ptr,
5500Sstevel@tonic-gate 		    TD_PADDR(pp->pp_qh->td_tailp));
5510Sstevel@tonic-gate 		uhci_remove_bulk_tds_tws(uhcip, pp, UHCI_IN_RESET);
5520Sstevel@tonic-gate 		break;
5530Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
5540Sstevel@tonic-gate 		uhci_remove_isoc_tds_tws(uhcip, pp);
5550Sstevel@tonic-gate 		break;
5560Sstevel@tonic-gate 	default:
5570Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
5580Sstevel@tonic-gate 		    "uhci_hcdi_pipe_reset: Unknown xfer type");
5590Sstevel@tonic-gate 		break;
5600Sstevel@tonic-gate 	}
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	/*
5630Sstevel@tonic-gate 	 * Do the callback for the original client
5640Sstevel@tonic-gate 	 * periodic IN request.
5650Sstevel@tonic-gate 	 */
5660Sstevel@tonic-gate 	if (pp->pp_client_periodic_in_reqp) {
5670Sstevel@tonic-gate 		uhci_hcdi_callback(uhcip, pp, ph, NULL, USB_CR_PIPE_RESET);
5680Sstevel@tonic-gate 	}
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	/*
5710Sstevel@tonic-gate 	 * Since the endpoint is stripped of Transfer Descriptors (TD),
5720Sstevel@tonic-gate 	 * reset the state of the periodic pipe to IDLE.
5730Sstevel@tonic-gate 	 */
5740Sstevel@tonic-gate 	pp->pp_state = UHCI_PIPE_STATE_IDLE;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	return (USB_SUCCESS);
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate 
5818945SGuoqing.Zhu@Sun.COM /*
5828945SGuoqing.Zhu@Sun.COM  * uhci_hcdi_pipe_reset_data_toggle:
5838945SGuoqing.Zhu@Sun.COM  */
5848945SGuoqing.Zhu@Sun.COM void
uhci_hcdi_pipe_reset_data_toggle(usba_pipe_handle_data_t * ph)5858945SGuoqing.Zhu@Sun.COM uhci_hcdi_pipe_reset_data_toggle(
5868945SGuoqing.Zhu@Sun.COM 	usba_pipe_handle_data_t	*ph)
5878945SGuoqing.Zhu@Sun.COM {
5888945SGuoqing.Zhu@Sun.COM 	uhci_state_t		*uhcip = uhci_obtain_state(
5898945SGuoqing.Zhu@Sun.COM 	    ph->p_usba_device->usb_root_hub_dip);
5908945SGuoqing.Zhu@Sun.COM 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
5918945SGuoqing.Zhu@Sun.COM 
5928945SGuoqing.Zhu@Sun.COM 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
5938945SGuoqing.Zhu@Sun.COM 	    "uhci_hcdi_pipe_reset_data_toggle:");
5948945SGuoqing.Zhu@Sun.COM 
5958945SGuoqing.Zhu@Sun.COM 	mutex_enter(&uhcip->uhci_int_mutex);
5968945SGuoqing.Zhu@Sun.COM 
5978945SGuoqing.Zhu@Sun.COM 	mutex_enter(&ph->p_mutex);
5988945SGuoqing.Zhu@Sun.COM 	pp->pp_data_toggle = 0;
5998945SGuoqing.Zhu@Sun.COM 	usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress,
6008945SGuoqing.Zhu@Sun.COM 	    pp->pp_data_toggle);
6018945SGuoqing.Zhu@Sun.COM 	mutex_exit(&ph->p_mutex);
6028945SGuoqing.Zhu@Sun.COM 
6038945SGuoqing.Zhu@Sun.COM 	mutex_exit(&uhcip->uhci_int_mutex);
6048945SGuoqing.Zhu@Sun.COM 
6058945SGuoqing.Zhu@Sun.COM }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate /*
6080Sstevel@tonic-gate  * uhci_hcdi_pipe_ctrl_xfer:
6090Sstevel@tonic-gate  */
6100Sstevel@tonic-gate int
uhci_hcdi_pipe_ctrl_xfer(usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t flags)6110Sstevel@tonic-gate uhci_hcdi_pipe_ctrl_xfer(
6120Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
6130Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_reqp,
6140Sstevel@tonic-gate 	usb_flags_t		flags)
6150Sstevel@tonic-gate {
6160Sstevel@tonic-gate 	uhci_state_t *uhcip = uhci_obtain_state(
6175773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
6180Sstevel@tonic-gate 	uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private;
6195773Sqz150045 	int error;
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
6220Sstevel@tonic-gate 	    "uhci_hcdi_pipe_ctrl_xfer: req=0x%p, ph=0x%p, flags=0x%x",
6236898Sfb209375 	    (void *)ctrl_reqp, (void *)ph, flags);
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
6265773Sqz150045 	error = uhci_state_is_operational(uhcip);
6275773Sqz150045 
6285773Sqz150045 	if (error != USB_SUCCESS) {
6295773Sqz150045 		mutex_exit(&uhcip->uhci_int_mutex);
6305773Sqz150045 
6315773Sqz150045 		return (error);
6325773Sqz150045 	}
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	ASSERT(pp->pp_state == UHCI_PIPE_STATE_IDLE);
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	/*
6370Sstevel@tonic-gate 	 * Check and handle root hub control request.
6380Sstevel@tonic-gate 	 */
6390Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
6400Sstevel@tonic-gate 		error = uhci_handle_root_hub_request(uhcip, ph, ctrl_reqp);
6410Sstevel@tonic-gate 		mutex_exit(&uhcip->uhci_int_mutex);
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 		return (error);
6440Sstevel@tonic-gate 	}
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	/* Insert the td's on the endpoint */
6470Sstevel@tonic-gate 	if ((error = uhci_insert_ctrl_td(uhcip, ph, ctrl_reqp, flags)) !=
6480Sstevel@tonic-gate 	    USB_SUCCESS) {
6490Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
6500Sstevel@tonic-gate 		    "uhci_hcdi_pipe_ctrl_xfer: No resources");
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	return (error);
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate /*
6590Sstevel@tonic-gate  * uhci_hcdi_pipe_bulk_xfer:
6600Sstevel@tonic-gate  */
6610Sstevel@tonic-gate int
uhci_hcdi_pipe_bulk_xfer(usba_pipe_handle_data_t * pipe_handle,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)6620Sstevel@tonic-gate uhci_hcdi_pipe_bulk_xfer(usba_pipe_handle_data_t *pipe_handle,
6630Sstevel@tonic-gate     usb_bulk_req_t *bulk_reqp, usb_flags_t usb_flags)
6640Sstevel@tonic-gate {
6650Sstevel@tonic-gate 	int		error;
6660Sstevel@tonic-gate 	uhci_state_t	*uhcip;
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	uhcip = uhci_obtain_state(pipe_handle->p_usba_device->usb_root_hub_dip);
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
6710Sstevel@tonic-gate 	    "uhci_hcdi_pipe_bulk_xfer: Flags = 0x%x", usb_flags);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	/* Check the size of bulk request */
6740Sstevel@tonic-gate 	if (bulk_reqp->bulk_len > UHCI_BULK_MAX_XFER_SIZE) {
6750Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
6760Sstevel@tonic-gate 		    "uhci_hcdi_pipe_bulk_xfer: req size 0x%x is more than 0x%x",
6770Sstevel@tonic-gate 		    bulk_reqp->bulk_len, UHCI_BULK_MAX_XFER_SIZE);
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 		return (USB_FAILURE);
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
6830Sstevel@tonic-gate 
6845773Sqz150045 	error = uhci_state_is_operational(uhcip);
6855773Sqz150045 
6865773Sqz150045 	if (error != USB_SUCCESS) {
6875773Sqz150045 		mutex_exit(&uhcip->uhci_int_mutex);
6885773Sqz150045 
6895773Sqz150045 		return (error);
6905773Sqz150045 	}
6910Sstevel@tonic-gate 	/* Add the TD into the Host Controller's bulk list */
6920Sstevel@tonic-gate 	if ((error = uhci_insert_bulk_td(uhcip, pipe_handle, bulk_reqp,
6930Sstevel@tonic-gate 	    usb_flags)) != USB_SUCCESS) {
6940Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
6950Sstevel@tonic-gate 		    "uhci_hcdi_pipe_bulk_xfer: uhci_insert_bulk_td failed");
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	return (error);
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate /*
7040Sstevel@tonic-gate  * uhci_hcdi_bulk_transfer_size:
7050Sstevel@tonic-gate  *	Return maximum bulk transfer size
7060Sstevel@tonic-gate  */
7070Sstevel@tonic-gate int
uhci_hcdi_bulk_transfer_size(usba_device_t * usba_device,size_t * size)7080Sstevel@tonic-gate uhci_hcdi_bulk_transfer_size(
7090Sstevel@tonic-gate 	usba_device_t	*usba_device,
7100Sstevel@tonic-gate 	size_t		*size)
7110Sstevel@tonic-gate {
7125773Sqz150045 	uhci_state_t	*uhcip = uhci_obtain_state(
7135773Sqz150045 	    usba_device->usb_root_hub_dip);
7145773Sqz150045 	int		rval;
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
7170Sstevel@tonic-gate 	    "uhci_hcdi_bulk_transfer_size:");
7180Sstevel@tonic-gate 
7195773Sqz150045 	mutex_enter(&uhcip->uhci_int_mutex);
7205773Sqz150045 	rval = uhci_state_is_operational(uhcip);
7215773Sqz150045 
7225773Sqz150045 	if (rval != USB_SUCCESS) {
7235773Sqz150045 		mutex_exit(&uhcip->uhci_int_mutex);
7245773Sqz150045 
7255773Sqz150045 		return (rval);
7265773Sqz150045 	}
7275773Sqz150045 
7280Sstevel@tonic-gate 	*size = uhci_bulk_transfer_size;
7295773Sqz150045 	mutex_exit(&uhcip->uhci_int_mutex);
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	return (USB_SUCCESS);
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate /*
7360Sstevel@tonic-gate  * uhci_hcdi_pipe_intr_xfer:
7370Sstevel@tonic-gate  */
7380Sstevel@tonic-gate int
uhci_hcdi_pipe_intr_xfer(usba_pipe_handle_data_t * ph,usb_intr_req_t * req,usb_flags_t flags)7390Sstevel@tonic-gate uhci_hcdi_pipe_intr_xfer(
7400Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
7410Sstevel@tonic-gate 	usb_intr_req_t		*req,
7420Sstevel@tonic-gate 	usb_flags_t		flags)
7430Sstevel@tonic-gate {
7440Sstevel@tonic-gate 	uhci_state_t	*uhcip = uhci_obtain_state(
7455773Sqz150045 	    ph->p_usba_device->usb_root_hub_dip);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
7486898Sfb209375 	    "uhci_hcdi_pipe_intr_xfer: req=0x%p, uf=0x%x", (void *)req, flags);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN) {
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 		return (uhci_start_periodic_pipe_polling(uhcip, ph,
7535773Sqz150045 		    (usb_opaque_t)req, flags));
7540Sstevel@tonic-gate 	} else {
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 		return (uhci_send_intr_data(uhcip, ph, req, flags));
7570Sstevel@tonic-gate 	}
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate /*
7620Sstevel@tonic-gate  * uhci_send_intr_data():
7630Sstevel@tonic-gate  *	send data to interrupt out pipe
7640Sstevel@tonic-gate  */
7650Sstevel@tonic-gate static int
uhci_send_intr_data(uhci_state_t * uhcip,usba_pipe_handle_data_t * pipe_handle,usb_intr_req_t * req,usb_flags_t flags)7660Sstevel@tonic-gate uhci_send_intr_data(
7670Sstevel@tonic-gate 	uhci_state_t		*uhcip,
7680Sstevel@tonic-gate 	usba_pipe_handle_data_t	*pipe_handle,
7690Sstevel@tonic-gate 	usb_intr_req_t		*req,
7700Sstevel@tonic-gate 	usb_flags_t		flags)
7710Sstevel@tonic-gate {
7725773Sqz150045 	int	rval;
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
7750Sstevel@tonic-gate 	    "uhci_send_intr_data:");
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
7780Sstevel@tonic-gate 
7795773Sqz150045 	rval = uhci_state_is_operational(uhcip);
7805773Sqz150045 
7815773Sqz150045 	if (rval != USB_SUCCESS) {
7825773Sqz150045 		mutex_exit(&uhcip->uhci_int_mutex);
7835773Sqz150045 
7845773Sqz150045 		return (rval);
7855773Sqz150045 	}
7865773Sqz150045 
7870Sstevel@tonic-gate 	/* Add the TD into the Host Controller's interrupt list */
7880Sstevel@tonic-gate 	if ((rval = uhci_insert_intr_td(uhcip, pipe_handle, req, flags)) !=
7890Sstevel@tonic-gate 	    USB_SUCCESS) {
7900Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
7910Sstevel@tonic-gate 		    "uhci_send_intr_data: No resources");
7920Sstevel@tonic-gate 	}
7930Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	return (rval);
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate /*
8000Sstevel@tonic-gate  * uhci_hcdi_pipe_stop_intr_polling()
8010Sstevel@tonic-gate  */
8020Sstevel@tonic-gate int
uhci_hcdi_pipe_stop_intr_polling(usba_pipe_handle_data_t * pipe_handle,usb_flags_t flags)8030Sstevel@tonic-gate uhci_hcdi_pipe_stop_intr_polling(
8040Sstevel@tonic-gate 	usba_pipe_handle_data_t *pipe_handle,
8050Sstevel@tonic-gate 	usb_flags_t		flags)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate 	uhci_state_t *uhcip =
8085773Sqz150045 	    uhci_obtain_state(pipe_handle->p_usba_device->usb_root_hub_dip);
8095773Sqz150045 	int		rval;
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
8120Sstevel@tonic-gate 	    "uhci_hcdi_pipe_stop_intr_polling: ph = 0x%p fl = 0x%x",
8130Sstevel@tonic-gate 	    (void *)pipe_handle, flags);
8145773Sqz150045 	mutex_enter(&uhcip->uhci_int_mutex);
8150Sstevel@tonic-gate 
8165773Sqz150045 	rval = uhci_stop_periodic_pipe_polling(uhcip, pipe_handle, flags);
8175773Sqz150045 
8185773Sqz150045 	mutex_exit(&uhcip->uhci_int_mutex);
8195773Sqz150045 
8205773Sqz150045 	return (rval);
8210Sstevel@tonic-gate }
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate /*
8250Sstevel@tonic-gate  * uhci_hcdi_get_current_frame_number
8265773Sqz150045  *	Get the current frame number.
8275773Sqz150045  *	Return whether the request is handled successfully.
8280Sstevel@tonic-gate  */
8295773Sqz150045 int
uhci_hcdi_get_current_frame_number(usba_device_t * usba_device,usb_frame_number_t * frame_number)8305773Sqz150045 uhci_hcdi_get_current_frame_number(
8315773Sqz150045 	usba_device_t		*usba_device,
8325773Sqz150045 	usb_frame_number_t	*frame_number)
8330Sstevel@tonic-gate {
8340Sstevel@tonic-gate 	uhci_state_t *uhcip = uhci_obtain_state(usba_device->usb_root_hub_dip);
8355773Sqz150045 	int		rval;
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
8385773Sqz150045 	rval = uhci_state_is_operational(uhcip);
8395773Sqz150045 
8405773Sqz150045 	if (rval != USB_SUCCESS) {
8415773Sqz150045 		mutex_exit(&uhcip->uhci_int_mutex);
8425773Sqz150045 
8435773Sqz150045 		return (rval);
8445773Sqz150045 	}
8455773Sqz150045 
8465773Sqz150045 	*frame_number = uhci_get_sw_frame_number(uhcip);
8470Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
8506898Sfb209375 	    "uhci_hcdi_get_current_frame_number: %llx",
8516898Sfb209375 	    (unsigned long long)(*frame_number));
8520Sstevel@tonic-gate 
8535773Sqz150045 	return (rval);
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate /*
8580Sstevel@tonic-gate  * uhci_hcdi_get_max_isoc_pkts
8595773Sqz150045  *	Get the maximum number of isoc packets per USB Isoch request.
8605773Sqz150045  *	Return whether the request is handled successfully.
8610Sstevel@tonic-gate  */
8625773Sqz150045 int
uhci_hcdi_get_max_isoc_pkts(usba_device_t * usba_device,uint_t * max_isoc_pkts_per_request)8635773Sqz150045 uhci_hcdi_get_max_isoc_pkts(
8645773Sqz150045 	usba_device_t	*usba_device,
8655773Sqz150045 	uint_t		*max_isoc_pkts_per_request)
8660Sstevel@tonic-gate {
8670Sstevel@tonic-gate 	uhci_state_t *uhcip = uhci_obtain_state(usba_device->usb_root_hub_dip);
8685773Sqz150045 	int		rval;
8695773Sqz150045 
8705773Sqz150045 	mutex_enter(&uhcip->uhci_int_mutex);
8715773Sqz150045 	rval = uhci_state_is_operational(uhcip);
8725773Sqz150045 
8735773Sqz150045 	if (rval != USB_SUCCESS) {
8745773Sqz150045 		mutex_exit(&uhcip->uhci_int_mutex);
8755773Sqz150045 
8765773Sqz150045 		return (rval);
8775773Sqz150045 	}
8785773Sqz150045 
8795773Sqz150045 	*max_isoc_pkts_per_request = UHCI_MAX_ISOC_PKTS;
8805773Sqz150045 	mutex_exit(&uhcip->uhci_int_mutex);
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
8830Sstevel@tonic-gate 	    "uhci_hcdi_get_max_isoc_pkts: 0x%x", UHCI_MAX_ISOC_PKTS);
8840Sstevel@tonic-gate 
8855773Sqz150045 	return (rval);
8860Sstevel@tonic-gate }
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate /*
8900Sstevel@tonic-gate  * uhci_hcdi_pipe_isoc_xfer:
8910Sstevel@tonic-gate  */
8920Sstevel@tonic-gate int
uhci_hcdi_pipe_isoc_xfer(usba_pipe_handle_data_t * ph,usb_isoc_req_t * isoc_reqp,usb_flags_t flags)8930Sstevel@tonic-gate uhci_hcdi_pipe_isoc_xfer(
8940Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
8950Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_reqp,
8960Sstevel@tonic-gate 	usb_flags_t		flags)
8970Sstevel@tonic-gate {
8980Sstevel@tonic-gate 	uhci_state_t	*uhcip;
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
9010Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
9026898Sfb209375 	    "uhci_hcdi_pipe_isoc_xfer: req=0x%p, uf=0x%x",
9036898Sfb209375 	    (void *)isoc_reqp, flags);
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN) {
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 		return (uhci_start_periodic_pipe_polling(uhcip, ph,
9085773Sqz150045 		    (usb_opaque_t)isoc_reqp, flags));
9090Sstevel@tonic-gate 	} else {
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 		return (uhci_pipe_send_isoc_data(uhcip, ph, isoc_reqp, flags));
9120Sstevel@tonic-gate 	}
9130Sstevel@tonic-gate }
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate /*
9170Sstevel@tonic-gate  * uhci_hcdi_pipe_stop_isoc_polling()
9180Sstevel@tonic-gate  */
9190Sstevel@tonic-gate int
uhci_hcdi_pipe_stop_isoc_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)9200Sstevel@tonic-gate uhci_hcdi_pipe_stop_isoc_polling(
9210Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
9220Sstevel@tonic-gate 	usb_flags_t		flags)
9230Sstevel@tonic-gate {
9240Sstevel@tonic-gate 	uhci_state_t *uhcip =
9255773Sqz150045 	    uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
9265773Sqz150045 	int		rval;
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
9290Sstevel@tonic-gate 	    "uhci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x",
9300Sstevel@tonic-gate 	    (void *)ph, flags);
9310Sstevel@tonic-gate 
9325773Sqz150045 	mutex_enter(&uhcip->uhci_int_mutex);
9335773Sqz150045 	rval = uhci_state_is_operational(uhcip);
9345773Sqz150045 
9355773Sqz150045 	if (rval != USB_SUCCESS) {
9365773Sqz150045 		mutex_exit(&uhcip->uhci_int_mutex);
9375773Sqz150045 
9385773Sqz150045 		return (rval);
9395773Sqz150045 	}
9405773Sqz150045 
9415773Sqz150045 	rval = uhci_stop_periodic_pipe_polling(uhcip, ph, flags);
9425773Sqz150045 
9435773Sqz150045 	mutex_exit(&uhcip->uhci_int_mutex);
9445773Sqz150045 
9455773Sqz150045 	return (rval);
9460Sstevel@tonic-gate }
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate /*
9500Sstevel@tonic-gate  * uhci_start_periodic_pipe_polling:
9510Sstevel@tonic-gate  */
9520Sstevel@tonic-gate static int
uhci_start_periodic_pipe_polling(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph,usb_opaque_t in_reqp,usb_flags_t flags)9530Sstevel@tonic-gate uhci_start_periodic_pipe_polling(
9540Sstevel@tonic-gate 	uhci_state_t		*uhcip,
9550Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
9560Sstevel@tonic-gate 	usb_opaque_t		in_reqp,
9570Sstevel@tonic-gate 	usb_flags_t		flags)
9580Sstevel@tonic-gate {
9590Sstevel@tonic-gate 	int			n, num_tds;
9605773Sqz150045 	int			error;
9610Sstevel@tonic-gate 	usb_intr_req_t		*intr_reqp = (usb_intr_req_t *)in_reqp;
9620Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
9630Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
9660Sstevel@tonic-gate 	    "uhci_start_periodic_pipe_polling: flags: 0x%x, ep%d",
9670Sstevel@tonic-gate 	    flags, eptd->bEndpointAddress);
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
9700Sstevel@tonic-gate 
9715773Sqz150045 	error = uhci_state_is_operational(uhcip);
9725773Sqz150045 
9735773Sqz150045 	if (error != USB_SUCCESS) {
9745773Sqz150045 		mutex_exit(&uhcip->uhci_int_mutex);
9755773Sqz150045 
9765773Sqz150045 		return (error);
9775773Sqz150045 	}
9785773Sqz150045 
9790Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
9800Sstevel@tonic-gate 		uint_t	pipe_state = uhcip->uhci_root_hub.rh_pipe_state;
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 		ASSERT(pipe_state == UHCI_PIPE_STATE_IDLE);
9830Sstevel@tonic-gate 		ASSERT(UHCI_XFER_DIR(eptd) == USB_EP_DIR_IN);
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 		/* ONE_XFER not supported */
9860Sstevel@tonic-gate 		ASSERT((intr_reqp->intr_attributes &
9870Sstevel@tonic-gate 		    USB_ATTRS_ONE_XFER) == 0);
9880Sstevel@tonic-gate 		ASSERT(uhcip->uhci_root_hub.rh_client_intr_req == NULL);
9890Sstevel@tonic-gate 		uhcip->uhci_root_hub.rh_client_intr_req = intr_reqp;
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 		if ((error = uhci_root_hub_allocate_intr_pipe_resource(
9920Sstevel@tonic-gate 		    uhcip, flags)) != USB_SUCCESS) {
9930Sstevel@tonic-gate 			/* reset the client interrupt request pointer */
9940Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_client_intr_req = NULL;
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 			return (error);
9990Sstevel@tonic-gate 		}
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 		uhcip->uhci_root_hub.rh_pipe_state = USB_PIPE_STATE_ACTIVE;
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
10040Sstevel@tonic-gate 		    "uhci_start_periodic_pipe_polling: "
10050Sstevel@tonic-gate 		    "Start intr polling for root hub successful");
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 		/* check if we need to send the reset data up? */
10080Sstevel@tonic-gate 		if (uhcip->uhci_root_hub.rh_status) {
10090Sstevel@tonic-gate 			uhci_root_hub_reset_occurred(uhcip,
10100Sstevel@tonic-gate 			    uhcip->uhci_root_hub.rh_status - 1);
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_status = 0;
10130Sstevel@tonic-gate 		}
10140Sstevel@tonic-gate 		mutex_exit(&uhcip->uhci_int_mutex);
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 		return (error);
10170Sstevel@tonic-gate 	}
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	/* save the original client's periodic IN request */
10200Sstevel@tonic-gate 	pp->pp_client_periodic_in_reqp = in_reqp;
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	ASSERT(pp->pp_state != UHCI_PIPE_STATE_ACTIVE);
10230Sstevel@tonic-gate 	/*
10240Sstevel@tonic-gate 	 *
10250Sstevel@tonic-gate 	 * This pipe is uninitialized. If it is an isoc
10260Sstevel@tonic-gate 	 * receive request, insert four times the same
10270Sstevel@tonic-gate 	 * request so that we do not lose any frames.
10280Sstevel@tonic-gate 	 */
10290Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_ISOCH) {
10300Sstevel@tonic-gate 		for (n = 0; n < 5; n++) {
10310Sstevel@tonic-gate 			if ((error = uhci_start_isoc_receive_polling(
10320Sstevel@tonic-gate 			    uhcip, ph, NULL, flags)) != USB_SUCCESS) {
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 				USB_DPRINTF_L2(PRINT_MASK_INTR,
10350Sstevel@tonic-gate 				    uhcip->uhci_log_hdl,
10360Sstevel@tonic-gate 				    "uhci_start_periodic_pipe_polling: "
10370Sstevel@tonic-gate 				    "Start isoc polling failed %d", n);
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 				pp->pp_client_periodic_in_reqp = NULL;
10400Sstevel@tonic-gate 				mutex_exit(&uhcip->uhci_int_mutex);
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 				return (error);
10430Sstevel@tonic-gate 			}
10440Sstevel@tonic-gate 		}
10450Sstevel@tonic-gate 	}
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_INTR) {
10480Sstevel@tonic-gate 		if ((pp->pp_node < POLLING_FREQ_7MS) &&
10490Sstevel@tonic-gate 		    (!(intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER))) {
10500Sstevel@tonic-gate 			num_tds = 5;
10510Sstevel@tonic-gate 		} else {
10520Sstevel@tonic-gate 			num_tds = 1;
10530Sstevel@tonic-gate 		}
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 		/*
10560Sstevel@tonic-gate 		 * This pipe is uninitialized.
10570Sstevel@tonic-gate 		 * Insert a TD on the interrupt ED.
10580Sstevel@tonic-gate 		 */
10590Sstevel@tonic-gate 		for (n = 0; n < num_tds; n++) {
10600Sstevel@tonic-gate 			if ((error = uhci_insert_intr_td(uhcip, ph, NULL,
10610Sstevel@tonic-gate 			    flags)) != USB_SUCCESS) {
10620Sstevel@tonic-gate 				USB_DPRINTF_L2(PRINT_MASK_INTR,
10630Sstevel@tonic-gate 				    uhcip->uhci_log_hdl,
10640Sstevel@tonic-gate 				    "uhci_start_periodic_pipe_polling: "
10650Sstevel@tonic-gate 				    "Start polling failed");
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 				pp->pp_client_periodic_in_reqp = NULL;
10680Sstevel@tonic-gate 				mutex_exit(&uhcip->uhci_int_mutex);
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 				return (error);
10710Sstevel@tonic-gate 			}
10720Sstevel@tonic-gate 		}
10730Sstevel@tonic-gate 	}
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	pp->pp_state = UHCI_PIPE_STATE_ACTIVE;
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	return (error);
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate /*
10840Sstevel@tonic-gate  * uhci_hcdi_periodic_pipe_stop_polling:
10850Sstevel@tonic-gate  */
10860Sstevel@tonic-gate static int
uhci_stop_periodic_pipe_polling(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph,usb_flags_t flags)10870Sstevel@tonic-gate uhci_stop_periodic_pipe_polling(uhci_state_t *uhcip,
10880Sstevel@tonic-gate 	usba_pipe_handle_data_t  *ph, usb_flags_t flags)
10890Sstevel@tonic-gate {
10900Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
10910Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
10940Sstevel@tonic-gate 	    "uhci_stop_periodic_pipe_polling: flags = 0x%x", flags);
10950Sstevel@tonic-gate 
10965773Sqz150045 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
10970Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
10980Sstevel@tonic-gate 		ASSERT(UHCI_XFER_DIR(eptd) == USB_EP_DIR_IN);
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 		if (uhcip->uhci_root_hub.rh_pipe_state ==
11010Sstevel@tonic-gate 		    UHCI_PIPE_STATE_ACTIVE) {
11020Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_pipe_state =
11035773Sqz150045 			    UHCI_PIPE_STATE_IDLE;
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 			/* Do interrupt pipe cleanup */
11060Sstevel@tonic-gate 			uhci_root_hub_intr_pipe_cleanup(uhcip,
11075773Sqz150045 			    USB_CR_STOPPED_POLLING);
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
11100Sstevel@tonic-gate 			    "uhci_stop_periodic_pipe_polling: Stop intr "
11110Sstevel@tonic-gate 			    "polling for root hub successful");
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 		} else {
11140Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
11150Sstevel@tonic-gate 			    "uhci_stop_periodic_pipe_polling: "
11160Sstevel@tonic-gate 			    "Intr polling for root hub is already stopped");
11170Sstevel@tonic-gate 		}
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 		return (USB_SUCCESS);
11200Sstevel@tonic-gate 	}
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	if (pp->pp_state != UHCI_PIPE_STATE_ACTIVE) {
11230Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
11240Sstevel@tonic-gate 		    "uhci_stop_periodic_pipe_polling: Polling already stopped");
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 		return (USB_SUCCESS);
11270Sstevel@tonic-gate 	}
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	/*
11300Sstevel@tonic-gate 	 * Set the terminate bits in all the tds in the queue and
11310Sstevel@tonic-gate 	 * in the element_ptr.
11320Sstevel@tonic-gate 	 * Do not deallocate the bandwidth or tear down the DMA
11330Sstevel@tonic-gate 	 */
11340Sstevel@tonic-gate 	uhci_modify_td_active_bits(uhcip, pp);
11350Sstevel@tonic-gate 	(void) uhci_wait_for_sof(uhcip);
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_ISOCH) {
11380Sstevel@tonic-gate 		uhci_remove_isoc_tds_tws(uhcip, pp);
11390Sstevel@tonic-gate 		pp->pp_state = UHCI_PIPE_STATE_IDLE;
11400Sstevel@tonic-gate 	} else {
11410Sstevel@tonic-gate 		UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr);
11420Sstevel@tonic-gate 		uhci_update_intr_td_data_toggle(uhcip, pp);
11430Sstevel@tonic-gate 		SetQH32(uhcip, pp->pp_qh->element_ptr,
11440Sstevel@tonic-gate 		    TD_PADDR(pp->pp_qh->td_tailp));
11450Sstevel@tonic-gate 		uhci_remove_tds_tws(uhcip, ph);
11460Sstevel@tonic-gate 	}
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 	pp->pp_state = UHCI_PIPE_STATE_IDLE;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	if (pp->pp_client_periodic_in_reqp) {
11510Sstevel@tonic-gate 		uhci_hcdi_callback(uhcip, pp, ph, NULL, USB_CR_STOPPED_POLLING);
11520Sstevel@tonic-gate 	}
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 	return (USB_SUCCESS);
11550Sstevel@tonic-gate }
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate /*
11590Sstevel@tonic-gate  * uhci_hcdi_pipe_send_isoc_data:
11600Sstevel@tonic-gate  *	Handles the isoc write request.
11610Sstevel@tonic-gate  */
11620Sstevel@tonic-gate static int
uhci_pipe_send_isoc_data(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph,usb_isoc_req_t * isoc_req,usb_flags_t usb_flags)11630Sstevel@tonic-gate uhci_pipe_send_isoc_data(
11640Sstevel@tonic-gate 	uhci_state_t		*uhcip,
11650Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
11660Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_req,
11670Sstevel@tonic-gate 	usb_flags_t		usb_flags)
11680Sstevel@tonic-gate {
11690Sstevel@tonic-gate 	int			error;
11700Sstevel@tonic-gate 	size_t			max_isoc_xfer_sz, length;
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
11730Sstevel@tonic-gate 	    "uhci_pipe_send_isoc_data: isoc_req = %p flags = %x",
11746898Sfb209375 	    (void *)isoc_req, usb_flags);
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	ASSERT(isoc_req->isoc_pkts_count < UHCI_MAX_ISOC_PKTS);
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	/* Calculate the maximum isochronous transfer size */
11790Sstevel@tonic-gate 	max_isoc_xfer_sz = UHCI_MAX_ISOC_PKTS * ph->p_ep.wMaxPacketSize;
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	/* Check the size of isochronous request */
11820Sstevel@tonic-gate 	ASSERT(isoc_req->isoc_data != NULL);
11836990Sgd78059 	length = MBLKL(isoc_req->isoc_data);
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	if (length > max_isoc_xfer_sz) {
11860Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
11870Sstevel@tonic-gate 		    "uhci_pipe_send_isoc_data: Maximum isoc request size %lx "
11880Sstevel@tonic-gate 		    "Given isoc request size %lx", max_isoc_xfer_sz, length);
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 		return (USB_INVALID_REQUEST);
11910Sstevel@tonic-gate 	}
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	/*
11950Sstevel@tonic-gate 	 * Check whether we can insert these tds?
11960Sstevel@tonic-gate 	 * At any point of time, we can insert maximum of 1024 isoc td's,
11970Sstevel@tonic-gate 	 * size of frame list table.
11980Sstevel@tonic-gate 	 */
11990Sstevel@tonic-gate 	if (isoc_req->isoc_pkts_count > UHCI_MAX_ISOC_PKTS) {
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
12020Sstevel@tonic-gate 		    "uhci_pipe_send_isoc_data: request too big");
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 		return (USB_INVALID_REQUEST);
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	/* Add the TD into the Host Controller's isoc list */
12080Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
12090Sstevel@tonic-gate 
12105773Sqz150045 	error = uhci_state_is_operational(uhcip);
12115773Sqz150045 
12125773Sqz150045 	if (error != USB_SUCCESS) {
12135773Sqz150045 		mutex_exit(&uhcip->uhci_int_mutex);
12145773Sqz150045 
12155773Sqz150045 		return (error);
12165773Sqz150045 	}
12175773Sqz150045 
12180Sstevel@tonic-gate 	if ((error = uhci_insert_isoc_td(uhcip, ph, isoc_req,
12190Sstevel@tonic-gate 	    length, usb_flags)) != USB_SUCCESS) {
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
12220Sstevel@tonic-gate 		    "uhci_pipe_send_isoc_data: Unable to insert the isoc_req,"
12230Sstevel@tonic-gate 		    "Error = %d", error);
12240Sstevel@tonic-gate 	}
12250Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	return (error);
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate /*
12320Sstevel@tonic-gate  * uhci_update_intr_td_data_toggle
12330Sstevel@tonic-gate  *	Update the data toggle and save in the usba_device structure
12340Sstevel@tonic-gate  */
12350Sstevel@tonic-gate static void
uhci_update_intr_td_data_toggle(uhci_state_t * uhcip,uhci_pipe_private_t * pp)12360Sstevel@tonic-gate uhci_update_intr_td_data_toggle(uhci_state_t *uhcip, uhci_pipe_private_t *pp)
12370Sstevel@tonic-gate {
12380Sstevel@tonic-gate 	uint32_t	paddr_tail, element_ptr;
12390Sstevel@tonic-gate 	uhci_td_t	*next_td;
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	/* Find the next td that would have been executed */
12420Sstevel@tonic-gate 	element_ptr = GetQH32(uhcip, pp->pp_qh->element_ptr) &
12435773Sqz150045 	    QH_ELEMENT_PTR_MASK;
12440Sstevel@tonic-gate 	next_td = TD_VADDR(element_ptr);
12450Sstevel@tonic-gate 	paddr_tail = TD_PADDR(pp->pp_qh->td_tailp);
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	/*
12480Sstevel@tonic-gate 	 * If element_ptr points to the dummy td, then the data toggle in
12490Sstevel@tonic-gate 	 * pp_data_toggle is correct. Otherwise update the data toggle in
12500Sstevel@tonic-gate 	 * the pipe private
12510Sstevel@tonic-gate 	 */
12520Sstevel@tonic-gate 	if (element_ptr != paddr_tail) {
12530Sstevel@tonic-gate 		pp->pp_data_toggle = GetTD_dtogg(uhcip, next_td);
12540Sstevel@tonic-gate 	}
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
12570Sstevel@tonic-gate 	    "uhci_update_intr_td_data_toggle: "
12580Sstevel@tonic-gate 	    "pp %p toggle %x element ptr %x ptail %x",
12596898Sfb209375 	    (void *)pp, pp->pp_data_toggle, element_ptr, paddr_tail);
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 	uhci_save_data_toggle(pp);
12620Sstevel@tonic-gate }
1263