17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54c8a46c1Syq  * Common Development and Distribution License (the "License").
64c8a46c1Syq  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2209af7b17SRaymond Chen  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Universal Host Controller Driver (UHCI)
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  * The UHCI driver is a driver which interfaces to the Universal
307c478bd9Sstevel@tonic-gate  * Serial Bus Driver (USBA) and the Host Controller (HC). The interface to
317c478bd9Sstevel@tonic-gate  * the Host Controller is defined by the Universal Host Controller Interface.
327c478bd9Sstevel@tonic-gate  * This file contains the code for HCDI entry points.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcid.h>
357c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcitgt.h>
367c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhciutil.h>
3722eb7cb5Sgd #include <sys/strsun.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /* function prototypes */
407c478bd9Sstevel@tonic-gate static int	uhci_pipe_send_isoc_data(uhci_state_t *uhcip,
417c478bd9Sstevel@tonic-gate 			usba_pipe_handle_data_t *ph, usb_isoc_req_t *isoc_req,
427c478bd9Sstevel@tonic-gate 			usb_flags_t usb_flags);
437c478bd9Sstevel@tonic-gate static int	uhci_send_intr_data(uhci_state_t *uhcip,
447c478bd9Sstevel@tonic-gate 			usba_pipe_handle_data_t	*pipe_handle,
457c478bd9Sstevel@tonic-gate 			usb_intr_req_t		*req,
467c478bd9Sstevel@tonic-gate 			usb_flags_t		flags);
477c478bd9Sstevel@tonic-gate static int	uhci_start_periodic_pipe_polling(uhci_state_t *uhcip,
487c478bd9Sstevel@tonic-gate 			usba_pipe_handle_data_t	*ph,
497c478bd9Sstevel@tonic-gate 			usb_opaque_t		reqp,
507c478bd9Sstevel@tonic-gate 			usb_flags_t		flags);
517c478bd9Sstevel@tonic-gate static int	uhci_stop_periodic_pipe_polling(uhci_state_t *uhcip,
527c478bd9Sstevel@tonic-gate 			usba_pipe_handle_data_t	*ph,
537c478bd9Sstevel@tonic-gate 			usb_flags_t		flags);
547c478bd9Sstevel@tonic-gate static void	uhci_update_intr_td_data_toggle(uhci_state_t *uhcip,
557c478bd9Sstevel@tonic-gate 			uhci_pipe_private_t *pp);
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* Maximum bulk transfer size */
594610e4a0Sfrits int uhci_bulk_transfer_size = UHCI_BULK_MAX_XFER_SIZE;
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * uhci_hcdi_pipe_open:
637c478bd9Sstevel@tonic-gate  *	Member of HCD Ops structure and called during client specific pipe open
647c478bd9Sstevel@tonic-gate  *	Add the pipe to the data structure representing the device and allocate
657c478bd9Sstevel@tonic-gate  *	bandwidth for the pipe if it is a interrupt or isochronous endpoint.
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate int
uhci_hcdi_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t flags)687c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_open(usba_pipe_handle_data_t *ph, usb_flags_t flags)
697c478bd9Sstevel@tonic-gate {
707c478bd9Sstevel@tonic-gate 	uint_t			node = 0;
717c478bd9Sstevel@tonic-gate 	usb_addr_t		usb_addr;
727c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip;
737c478bd9Sstevel@tonic-gate 	uhci_pipe_private_t	*pp;
74fffe0b30Sqz 	int			rval, error = USB_SUCCESS;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	ASSERT(ph);
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	usb_addr = ph->p_usba_device->usb_addr;
797c478bd9Sstevel@tonic-gate 	uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
827c478bd9Sstevel@tonic-gate 	    "uhci_hcdi_pipe_open: addr = 0x%x, ep%d", usb_addr,
837c478bd9Sstevel@tonic-gate 	    ph->p_ep.bEndpointAddress & USB_EP_NUM_MASK);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	sema_p(&uhcip->uhci_ocsem);
867c478bd9Sstevel@tonic-gate 
87fffe0b30Sqz 	mutex_enter(&uhcip->uhci_int_mutex);
88fffe0b30Sqz 	rval = uhci_state_is_operational(uhcip);
89fffe0b30Sqz 	mutex_exit(&uhcip->uhci_int_mutex);
90fffe0b30Sqz 
91fffe0b30Sqz 	if (rval != USB_SUCCESS) {
92fffe0b30Sqz 		sema_v(&uhcip->uhci_ocsem);
93fffe0b30Sqz 
94fffe0b30Sqz 		return (rval);
95fffe0b30Sqz 	}
96fffe0b30Sqz 
977c478bd9Sstevel@tonic-gate 	/*
987c478bd9Sstevel@tonic-gate 	 * Return failure immediately for any other pipe open on the root hub
997c478bd9Sstevel@tonic-gate 	 * except control or interrupt pipe.
1007c478bd9Sstevel@tonic-gate 	 */
1017c478bd9Sstevel@tonic-gate 	if (usb_addr == ROOT_HUB_ADDR) {
1027c478bd9Sstevel@tonic-gate 		switch (UHCI_XFER_TYPE(&ph->p_ep)) {
1037c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
1047c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1057c478bd9Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: Root hub control pipe");
1067c478bd9Sstevel@tonic-gate 			break;
1077c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
1087c478bd9Sstevel@tonic-gate 			ASSERT(UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 			mutex_enter(&uhcip->uhci_int_mutex);
1117c478bd9Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_intr_pipe_handle = ph;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 			/*
1147c478bd9Sstevel@tonic-gate 			 * Set the state of the root hub interrupt
1157c478bd9Sstevel@tonic-gate 			 * pipe as IDLE.
1167c478bd9Sstevel@tonic-gate 			 */
1177c478bd9Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_pipe_state =
118fffe0b30Sqz 			    UHCI_PIPE_STATE_IDLE;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 			ASSERT(uhcip->uhci_root_hub.rh_client_intr_req == NULL);
1217c478bd9Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_client_intr_req = NULL;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 			ASSERT(uhcip->uhci_root_hub.rh_curr_intr_reqp == NULL);
1247c478bd9Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_curr_intr_reqp = NULL;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1277c478bd9Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: Root hub interrupt "
1287c478bd9Sstevel@tonic-gate 			    "pipe open succeeded");
1297c478bd9Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
1307c478bd9Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 			return (USB_SUCCESS);
1337c478bd9Sstevel@tonic-gate 		default:
1347c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1357c478bd9Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: Root hub pipe open failed");
1367c478bd9Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
1397c478bd9Sstevel@tonic-gate 		}
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	/*
1437c478bd9Sstevel@tonic-gate 	 * A portion of the bandwidth is reserved for the non-periodic
1447c478bd9Sstevel@tonic-gate 	 * transfers  i.e control and bulk transfers in each  of one
1457c478bd9Sstevel@tonic-gate 	 * mill second frame period & usually it will be 10% of frame
1467c478bd9Sstevel@tonic-gate 	 * period. Hence there is no need to check for the available
1477c478bd9Sstevel@tonic-gate 	 * bandwidth before adding the control or bulk endpoints.
1487c478bd9Sstevel@tonic-gate 	 *
1497c478bd9Sstevel@tonic-gate 	 * There is a need to check for the available bandwidth before
1507c478bd9Sstevel@tonic-gate 	 * adding the periodic transfers i.e interrupt & isochronous, since
1517c478bd9Sstevel@tonic-gate 	 * all these periodic transfers are guaranteed transfers. Usually,
1527c478bd9Sstevel@tonic-gate 	 * 90% of the total frame time is reserved for periodic transfers.
1537c478bd9Sstevel@tonic-gate 	 */
1547c478bd9Sstevel@tonic-gate 	if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) {
1557c478bd9Sstevel@tonic-gate 		/* Zero Max Packet size endpoints are not supported */
1567c478bd9Sstevel@tonic-gate 		if (ph->p_ep.wMaxPacketSize == 0) {
1577c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1587c478bd9Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: Zero length packet");
1597c478bd9Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
1627c478bd9Sstevel@tonic-gate 		}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 		mutex_enter(&uhcip->uhci_int_mutex);
1657c478bd9Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 		error = uhci_allocate_bandwidth(uhcip, ph, &node);
1687c478bd9Sstevel@tonic-gate 		if (error != USB_SUCCESS) {
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1717c478bd9Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: Bandwidth allocation failed");
1727c478bd9Sstevel@tonic-gate 			mutex_exit(&ph->p_mutex);
1737c478bd9Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
1747c478bd9Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 			return (error);
1777c478bd9Sstevel@tonic-gate 		}
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
1807c478bd9Sstevel@tonic-gate 		mutex_exit(&uhcip->uhci_int_mutex);
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	/* Create the HCD pipe private structure */
1847c478bd9Sstevel@tonic-gate 	pp = kmem_zalloc(sizeof (uhci_pipe_private_t),
1857c478bd9Sstevel@tonic-gate 	    (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
1867c478bd9Sstevel@tonic-gate 	if (pp == NULL) {
1877c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
1887c478bd9Sstevel@tonic-gate 		    "uhci_hcdi_pipe_open: pp allocation failure");
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 		if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) {
1917c478bd9Sstevel@tonic-gate 			mutex_enter(&uhcip->uhci_int_mutex);
1927c478bd9Sstevel@tonic-gate 			uhci_deallocate_bandwidth(uhcip, ph);
1937c478bd9Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
1947c478bd9Sstevel@tonic-gate 		}
1957c478bd9Sstevel@tonic-gate 		sema_v(&uhcip->uhci_ocsem);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
201fffe0b30Sqz 	rval = uhci_state_is_operational(uhcip);
202fffe0b30Sqz 
203fffe0b30Sqz 	if (rval != USB_SUCCESS) {
204fffe0b30Sqz 		kmem_free(ph, sizeof (uhci_pipe_private_t));
205fffe0b30Sqz 		mutex_exit(&uhcip->uhci_int_mutex);
206fffe0b30Sqz 		sema_v(&uhcip->uhci_ocsem);
207fffe0b30Sqz 
208fffe0b30Sqz 		return (rval);
209fffe0b30Sqz 	}
2107c478bd9Sstevel@tonic-gate 	pp->pp_node = node;	/* Store the node in the interrupt lattice */
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	/* Initialize frame number */
2137c478bd9Sstevel@tonic-gate 	pp->pp_frame_num = INVALID_FRNUM;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	/* Set the state of pipe as IDLE */
2167c478bd9Sstevel@tonic-gate 	pp->pp_state = UHCI_PIPE_STATE_IDLE;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	/* Store a pointer to the pipe handle */
2197c478bd9Sstevel@tonic-gate 	pp->pp_pipe_handle = ph;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/* Store the pointer in the pipe handle */
2227c478bd9Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
2237c478bd9Sstevel@tonic-gate 	ph->p_hcd_private = (usb_opaque_t)pp;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	/* Store a copy of the pipe policy */
2267c478bd9Sstevel@tonic-gate 	bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t));
2277c478bd9Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	/* don't check for ROOT_HUB here anymore */
2307c478bd9Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(&ph->p_ep) != USB_EP_ATTR_ISOCH) {
2317c478bd9Sstevel@tonic-gate 		/* Allocate the host controller endpoint descriptor */
2327c478bd9Sstevel@tonic-gate 		pp->pp_qh = uhci_alloc_queue_head(uhcip);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 		if (pp->pp_qh == NULL) {
2357c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
2367c478bd9Sstevel@tonic-gate 			    "uhci_hcdi_pipe_open: QH allocation failed");
2377c478bd9Sstevel@tonic-gate 
2384c8a46c1Syq 			if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) {
2394c8a46c1Syq 				uhci_deallocate_bandwidth(uhcip, ph);
2404c8a46c1Syq 			}
2414c8a46c1Syq 
2427c478bd9Sstevel@tonic-gate 			mutex_enter(&ph->p_mutex);
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 			/*
2457c478bd9Sstevel@tonic-gate 			 * Deallocate the hcd private portion
2467c478bd9Sstevel@tonic-gate 			 * of the pipe handle.
2477c478bd9Sstevel@tonic-gate 			 */
2487c478bd9Sstevel@tonic-gate 			kmem_free(ph->p_hcd_private,
249fffe0b30Sqz 			    sizeof (uhci_pipe_private_t));
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 			/*
2527c478bd9Sstevel@tonic-gate 			 * Set the private structure in the
2537c478bd9Sstevel@tonic-gate 			 * pipe handle equal to NULL.
2547c478bd9Sstevel@tonic-gate 			 */
2557c478bd9Sstevel@tonic-gate 			ph->p_hcd_private = NULL;
2567c478bd9Sstevel@tonic-gate 			mutex_exit(&ph->p_mutex);
2577c478bd9Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 			return (USB_NO_RESOURCES);
2627c478bd9Sstevel@tonic-gate 		}
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		/*
2657c478bd9Sstevel@tonic-gate 		 * Insert the endpoint onto the host controller's
2667c478bd9Sstevel@tonic-gate 		 * appropriate endpoint list. The host controller
2677c478bd9Sstevel@tonic-gate 		 * will not schedule this endpoint until there are
2687c478bd9Sstevel@tonic-gate 		 * any TD's to process.
2697c478bd9Sstevel@tonic-gate 		 */
2707c478bd9Sstevel@tonic-gate 		uhci_insert_qh(uhcip, ph);
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	/*
2747c478bd9Sstevel@tonic-gate 	 * Restore the data toggle from usb device structure.
2757c478bd9Sstevel@tonic-gate 	 */
2764c8a46c1Syq 	if (((ph->p_ep.bmAttributes) & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR ||
2774c8a46c1Syq 	    ((ph->p_ep.bmAttributes) & USB_EP_ATTR_MASK) == USB_EP_ATTR_BULK) {
2787c478bd9Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 		pp->pp_data_toggle = usba_hcdi_get_data_toggle(
281fffe0b30Sqz 		    ph->p_usba_device, ph->p_ep.bEndpointAddress);
2827c478bd9Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
2867c478bd9Sstevel@tonic-gate 	sema_v(&uhcip->uhci_ocsem);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
289112116d8Sfb 	    "uhci_hcdi_pipe_open: ph = 0x%p", (void *)ph);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate /*
2967c478bd9Sstevel@tonic-gate  * uhci_hcdi_pipe_close:
2977c478bd9Sstevel@tonic-gate  *	Member of HCD Ops structure and called during the client specific pipe
2987c478bd9Sstevel@tonic-gate  *	close. Remove the pipe to the data structure representing the device
2997c478bd9Sstevel@tonic-gate  *	deallocate bandwidth for the pipe if it is an intr or isoch endpoint.
3007c478bd9Sstevel@tonic-gate  */
3017c478bd9Sstevel@tonic-gate int
uhci_hcdi_pipe_close(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)3027c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_close(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags)
3037c478bd9Sstevel@tonic-gate {
3047c478bd9Sstevel@tonic-gate 	usb_addr_t		usb_addr;
3057c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip;
3067c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
3077c478bd9Sstevel@tonic-gate 	uhci_pipe_private_t	*pp;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
3107c478bd9Sstevel@tonic-gate 	pp = (uhci_pipe_private_t *)ph->p_hcd_private;
3117c478bd9Sstevel@tonic-gate 	usb_addr = ph->p_usba_device->usb_addr;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
3147c478bd9Sstevel@tonic-gate 	    "uhci_hcdi_pipe_close: addr = 0x%x, ep%d, flags = 0x%x", usb_addr,
3157c478bd9Sstevel@tonic-gate 	    eptd->bEndpointAddress, usb_flags);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	sema_p(&uhcip->uhci_ocsem);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/*
3227c478bd9Sstevel@tonic-gate 	 * Check whether the pipe is a root hub
3237c478bd9Sstevel@tonic-gate 	 */
3247c478bd9Sstevel@tonic-gate 	if (usb_addr == ROOT_HUB_ADDR) {
3257c478bd9Sstevel@tonic-gate 		switch (UHCI_XFER_TYPE(eptd)) {
3267c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
3277c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
3287c478bd9Sstevel@tonic-gate 			    "uhci_hcdi_pipe_close: Root hub control pipe "
3297c478bd9Sstevel@tonic-gate 			    "close succeeded");
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 			break;
3327c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
3337c478bd9Sstevel@tonic-gate 			ASSERT((eptd->bEndpointAddress &
334fffe0b30Sqz 			    USB_EP_NUM_MASK) == 1);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 			/* Do interrupt pipe cleanup */
3377c478bd9Sstevel@tonic-gate 			uhci_root_hub_intr_pipe_cleanup(uhcip,
338fffe0b30Sqz 			    USB_CR_PIPE_CLOSING);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 			ASSERT(uhcip->uhci_root_hub.rh_pipe_state ==
341fffe0b30Sqz 			    UHCI_PIPE_STATE_IDLE);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_intr_pipe_handle = NULL;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
3467c478bd9Sstevel@tonic-gate 			    "uhci_hcdi_pipe_close: Root hub interrupt "
3477c478bd9Sstevel@tonic-gate 			    "pipe close succeeded");
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_pipe_state =
350fffe0b30Sqz 			    UHCI_PIPE_STATE_IDLE;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
3537c478bd9Sstevel@tonic-gate 			sema_v(&uhcip->uhci_ocsem);
3547c478bd9Sstevel@tonic-gate 			return (USB_SUCCESS);
3557c478bd9Sstevel@tonic-gate 		}
3567c478bd9Sstevel@tonic-gate 	} else {
3577c478bd9Sstevel@tonic-gate 		/*
3587c478bd9Sstevel@tonic-gate 		 * Stop all the transactions if it is not the root hub.
3597c478bd9Sstevel@tonic-gate 		 */
3607c478bd9Sstevel@tonic-gate 		if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_INTR) {
3617c478bd9Sstevel@tonic-gate 			/*
3627c478bd9Sstevel@tonic-gate 			 * Stop polling on the pipe to prevent any subsequently
3637c478bd9Sstevel@tonic-gate 			 * queued tds (while we're waiting for SOF, below)
3647c478bd9Sstevel@tonic-gate 			 * from being executed
3657c478bd9Sstevel@tonic-gate 			 */
3667c478bd9Sstevel@tonic-gate 			pp->pp_state = UHCI_PIPE_STATE_IDLE;
3677c478bd9Sstevel@tonic-gate 		}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 		/* Disable all outstanding tds */
3707c478bd9Sstevel@tonic-gate 		uhci_modify_td_active_bits(uhcip, pp);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 		/* Prevent this queue from being executed */
3737c478bd9Sstevel@tonic-gate 		if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) {
3747c478bd9Sstevel@tonic-gate 			UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr);
3757c478bd9Sstevel@tonic-gate 		}
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 		/* Wait for the next start of frame */
3787c478bd9Sstevel@tonic-gate 		(void) uhci_wait_for_sof(uhcip);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		ASSERT(eptd != NULL);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 		switch (UHCI_XFER_TYPE(eptd)) {
3837c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
3847c478bd9Sstevel@tonic-gate 			uhci_update_intr_td_data_toggle(uhcip, pp);
3857c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
3867c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
3877c478bd9Sstevel@tonic-gate 			uhci_remove_tds_tws(uhcip, ph);
3887c478bd9Sstevel@tonic-gate 			break;
3897c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_BULK:
3907c478bd9Sstevel@tonic-gate 			SetQH32(uhcip, pp->pp_qh->element_ptr,
3917c478bd9Sstevel@tonic-gate 			    TD_PADDR(pp->pp_qh->td_tailp));
3927c478bd9Sstevel@tonic-gate 			uhci_remove_bulk_tds_tws(uhcip, pp, UHCI_IN_CLOSE);
3937c478bd9Sstevel@tonic-gate 			uhci_save_data_toggle(pp);
3947c478bd9Sstevel@tonic-gate 			break;
3957c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
3967c478bd9Sstevel@tonic-gate 			uhci_remove_isoc_tds_tws(uhcip, pp);
3977c478bd9Sstevel@tonic-gate 			break;
3987c478bd9Sstevel@tonic-gate 		default:
3997c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
4007c478bd9Sstevel@tonic-gate 			    "uhci_hcdi_pipe_close: Unknown xfer type");
4017c478bd9Sstevel@tonic-gate 			break;
4027c478bd9Sstevel@tonic-gate 		}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 		/*
4057c478bd9Sstevel@tonic-gate 		 * Remove the endoint descriptor from Host Controller's
4067c478bd9Sstevel@tonic-gate 		 * appropriate endpoint list. Isochronous pipes dont have
4077c478bd9Sstevel@tonic-gate 		 * any queue heads attached to it.
4087c478bd9Sstevel@tonic-gate 		 */
4097c478bd9Sstevel@tonic-gate 		if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) {
4107c478bd9Sstevel@tonic-gate 			uhci_remove_qh(uhcip, pp);
4117c478bd9Sstevel@tonic-gate 		}
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 		/*
4147c478bd9Sstevel@tonic-gate 		 * Do the callback for the original client
4157c478bd9Sstevel@tonic-gate 		 * periodic IN request.
4167c478bd9Sstevel@tonic-gate 		 */
4177c478bd9Sstevel@tonic-gate 		if (pp->pp_client_periodic_in_reqp) {
4187c478bd9Sstevel@tonic-gate 			uhci_hcdi_callback(uhcip, pp, ph, NULL,
4197c478bd9Sstevel@tonic-gate 			    USB_CR_PIPE_CLOSING);
4207c478bd9Sstevel@tonic-gate 		}
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 		/* Deallocate bandwidth */
4237c478bd9Sstevel@tonic-gate 		if (UHCI_PERIODIC_ENDPOINT(eptd)) {
4247c478bd9Sstevel@tonic-gate 			mutex_enter(&ph->p_mutex);
4257c478bd9Sstevel@tonic-gate 			uhci_deallocate_bandwidth(uhcip, ph);
4267c478bd9Sstevel@tonic-gate 			mutex_exit(&ph->p_mutex);
4277c478bd9Sstevel@tonic-gate 		}
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	/* Deallocate the hcd private portion of the pipe handle.  */
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
4337c478bd9Sstevel@tonic-gate 	kmem_free(ph->p_hcd_private, sizeof (uhci_pipe_private_t));
4347c478bd9Sstevel@tonic-gate 	ph->p_hcd_private = NULL;
4357c478bd9Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
438112116d8Sfb 	    "uhci_hcdi_pipe_close: ph = 0x%p", (void *)ph);
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
4417c478bd9Sstevel@tonic-gate 	sema_v(&uhcip->uhci_ocsem);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate /*
4487c478bd9Sstevel@tonic-gate  * uhci_hcdi_pipe_reset:
4497c478bd9Sstevel@tonic-gate  */
4507c478bd9Sstevel@tonic-gate int
uhci_hcdi_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)4517c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_reset(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags)
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip = uhci_obtain_state(
454fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
4557c478bd9Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
4567c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
457*32c2ff25Sfei feng - Sun Microsystems - Beijing China 	usb_port_t		port;
458*32c2ff25Sfei feng - Sun Microsystems - Beijing China 	uint_t 			port_status = 0;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
4617c478bd9Sstevel@tonic-gate 	    "uhci_hcdi_pipe_reset: usb_flags = 0x%x", usb_flags);
4627c478bd9Sstevel@tonic-gate 
46309af7b17SRaymond Chen 	/*
46409af7b17SRaymond Chen 	 * Under some circumstances, uhci internal hub's port
46509af7b17SRaymond Chen 	 * may become disabled because of some errors(see UHCI HCD Spec)
46609af7b17SRaymond Chen 	 * to make the UHCI driver robust enough, we should try to
46709af7b17SRaymond Chen 	 * re-enable it again here because HCD has already know something
46809af7b17SRaymond Chen 	 * bad happened.
46909af7b17SRaymond Chen 	 */
47009af7b17SRaymond Chen 	USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
47109af7b17SRaymond Chen 	    "uhci_hcdi_pipe_reset: try "
47209af7b17SRaymond Chen 	    "to enable disabled ports if necessary.");
473*32c2ff25Sfei feng - Sun Microsystems - Beijing China 	for (port = 0; port < uhcip->uhci_root_hub.rh_num_ports; port++) {
474*32c2ff25Sfei feng - Sun Microsystems - Beijing China 		port_status = Get_OpReg16(PORTSC[port]);
475*32c2ff25Sfei feng - Sun Microsystems - Beijing China 		if ((!(port_status & HCR_PORT_ENABLE)) &&
476*32c2ff25Sfei feng - Sun Microsystems - Beijing China 		    (port_status & HCR_PORT_CCS) &&
477*32c2ff25Sfei feng - Sun Microsystems - Beijing China 		    (!(port_status & HCR_PORT_CSC))) {
478*32c2ff25Sfei feng - Sun Microsystems - Beijing China 			Set_OpReg16(PORTSC[port],
479*32c2ff25Sfei feng - Sun Microsystems - Beijing China 			    (port_status | HCR_PORT_ENABLE));
48009af7b17SRaymond Chen 			drv_usecwait(UHCI_ONE_MS * 2);
48109af7b17SRaymond Chen 		}
48209af7b17SRaymond Chen 	}
48309af7b17SRaymond Chen 
4847c478bd9Sstevel@tonic-gate 	/*
4857c478bd9Sstevel@tonic-gate 	 * Return failure immediately for any other pipe reset on the root
4867c478bd9Sstevel@tonic-gate 	 * hub except control or interrupt pipe.
4877c478bd9Sstevel@tonic-gate 	 */
4887c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
4897c478bd9Sstevel@tonic-gate 		switch (UHCI_XFER_TYPE(&ph->p_ep)) {
4907c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
4917c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
4927c478bd9Sstevel@tonic-gate 			    "uhci_hcdi_pipe_reset: Pipe reset for root"
4937c478bd9Sstevel@tonic-gate 			    "hub control pipe successful");
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 			break;
4967c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
4977c478bd9Sstevel@tonic-gate 			mutex_enter(&uhcip->uhci_int_mutex);
4987c478bd9Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_pipe_state =
499fffe0b30Sqz 			    UHCI_PIPE_STATE_IDLE;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 			/* Do interrupt pipe cleanup */
5027c478bd9Sstevel@tonic-gate 			uhci_root_hub_intr_pipe_cleanup(uhcip,
503fffe0b30Sqz 			    USB_CR_PIPE_RESET);
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
5067c478bd9Sstevel@tonic-gate 			    "uhci_hcdi_pipe_reset: Pipe reset for "
5077c478bd9Sstevel@tonic-gate 			    "root hub interrupt pipe successful");
5087c478bd9Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 			break;
5117c478bd9Sstevel@tonic-gate 		default:
5127c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
513fffe0b30Sqz 			    "uhci_hcdi_pipe_reset: Root hub pipe reset failed");
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
5167c478bd9Sstevel@tonic-gate 		}
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	/*
5247c478bd9Sstevel@tonic-gate 	 * Set the active bit in to INACTIVE for all the remaining TD's of
5257c478bd9Sstevel@tonic-gate 	 * this end point.  Set the active bit for the dummy td. This will
5267c478bd9Sstevel@tonic-gate 	 * generate an interrupt at the end of the frame.  After receiving
5277c478bd9Sstevel@tonic-gate 	 * the interrupt, it is safe to to manipulate the lattice.
5287c478bd9Sstevel@tonic-gate 	 */
5297c478bd9Sstevel@tonic-gate 	uhci_modify_td_active_bits(uhcip, pp);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	/* Initialize the element pointer */
5327c478bd9Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) {
5337c478bd9Sstevel@tonic-gate 		UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr);
5347c478bd9Sstevel@tonic-gate 		SetQH32(uhcip, pp->pp_qh->element_ptr,
5357c478bd9Sstevel@tonic-gate 		    TD_PADDR(pp->pp_qh->td_tailp));
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	(void) uhci_wait_for_sof(uhcip);
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	/*
5417c478bd9Sstevel@tonic-gate 	 * Save the data toggle and clear the pipe.
5427c478bd9Sstevel@tonic-gate 	 */
5437c478bd9Sstevel@tonic-gate 	switch (UHCI_XFER_TYPE(eptd)) {
5447c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
5457c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
5467c478bd9Sstevel@tonic-gate 		uhci_remove_tds_tws(uhcip, ph);
5477c478bd9Sstevel@tonic-gate 		break;
5487c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
5497c478bd9Sstevel@tonic-gate 		SetQH32(uhcip, pp->pp_qh->element_ptr,
5507c478bd9Sstevel@tonic-gate 		    TD_PADDR(pp->pp_qh->td_tailp));
5517c478bd9Sstevel@tonic-gate 		uhci_remove_bulk_tds_tws(uhcip, pp, UHCI_IN_RESET);
5527c478bd9Sstevel@tonic-gate 		break;
5537c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
5547c478bd9Sstevel@tonic-gate 		uhci_remove_isoc_tds_tws(uhcip, pp);
5557c478bd9Sstevel@tonic-gate 		break;
5567c478bd9Sstevel@tonic-gate 	default:
5577c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
5587c478bd9Sstevel@tonic-gate 		    "uhci_hcdi_pipe_reset: Unknown xfer type");
5597c478bd9Sstevel@tonic-gate 		break;
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	/*
5637c478bd9Sstevel@tonic-gate 	 * Do the callback for the original client
5647c478bd9Sstevel@tonic-gate 	 * periodic IN request.
5657c478bd9Sstevel@tonic-gate 	 */
5667c478bd9Sstevel@tonic-gate 	if (pp->pp_client_periodic_in_reqp) {
5677c478bd9Sstevel@tonic-gate 		uhci_hcdi_callback(uhcip, pp, ph, NULL, USB_CR_PIPE_RESET);
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	/*
5717c478bd9Sstevel@tonic-gate 	 * Since the endpoint is stripped of Transfer Descriptors (TD),
5727c478bd9Sstevel@tonic-gate 	 * reset the state of the periodic pipe to IDLE.
5737c478bd9Sstevel@tonic-gate 	 */
5747c478bd9Sstevel@tonic-gate 	pp->pp_state = UHCI_PIPE_STATE_IDLE;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
5797c478bd9Sstevel@tonic-gate }
5807c478bd9Sstevel@tonic-gate 
581269552cdSguoqing zhu - Sun Microsystems - Beijing China /*
582269552cdSguoqing zhu - Sun Microsystems - Beijing China  * uhci_hcdi_pipe_reset_data_toggle:
583269552cdSguoqing zhu - Sun Microsystems - Beijing China  */
584269552cdSguoqing zhu - Sun Microsystems - Beijing China void
uhci_hcdi_pipe_reset_data_toggle(usba_pipe_handle_data_t * ph)585269552cdSguoqing zhu - Sun Microsystems - Beijing China uhci_hcdi_pipe_reset_data_toggle(
586269552cdSguoqing zhu - Sun Microsystems - Beijing China 	usba_pipe_handle_data_t	*ph)
587269552cdSguoqing zhu - Sun Microsystems - Beijing China {
588269552cdSguoqing zhu - Sun Microsystems - Beijing China 	uhci_state_t		*uhcip = uhci_obtain_state(
589269552cdSguoqing zhu - Sun Microsystems - Beijing China 	    ph->p_usba_device->usb_root_hub_dip);
590269552cdSguoqing zhu - Sun Microsystems - Beijing China 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
591269552cdSguoqing zhu - Sun Microsystems - Beijing China 
592269552cdSguoqing zhu - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
593269552cdSguoqing zhu - Sun Microsystems - Beijing China 	    "uhci_hcdi_pipe_reset_data_toggle:");
594269552cdSguoqing zhu - Sun Microsystems - Beijing China 
595269552cdSguoqing zhu - Sun Microsystems - Beijing China 	mutex_enter(&uhcip->uhci_int_mutex);
596269552cdSguoqing zhu - Sun Microsystems - Beijing China 
597269552cdSguoqing zhu - Sun Microsystems - Beijing China 	mutex_enter(&ph->p_mutex);
598269552cdSguoqing zhu - Sun Microsystems - Beijing China 	pp->pp_data_toggle = 0;
599269552cdSguoqing zhu - Sun Microsystems - Beijing China 	usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress,
600269552cdSguoqing zhu - Sun Microsystems - Beijing China 	    pp->pp_data_toggle);
601269552cdSguoqing zhu - Sun Microsystems - Beijing China 	mutex_exit(&ph->p_mutex);
602269552cdSguoqing zhu - Sun Microsystems - Beijing China 
603269552cdSguoqing zhu - Sun Microsystems - Beijing China 	mutex_exit(&uhcip->uhci_int_mutex);
604269552cdSguoqing zhu - Sun Microsystems - Beijing China 
605269552cdSguoqing zhu - Sun Microsystems - Beijing China }
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate /*
6087c478bd9Sstevel@tonic-gate  * uhci_hcdi_pipe_ctrl_xfer:
6097c478bd9Sstevel@tonic-gate  */
6107c478bd9Sstevel@tonic-gate int
uhci_hcdi_pipe_ctrl_xfer(usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t flags)6117c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_ctrl_xfer(
6127c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
6137c478bd9Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_reqp,
6147c478bd9Sstevel@tonic-gate 	usb_flags_t		flags)
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate 	uhci_state_t *uhcip = uhci_obtain_state(
617fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
6187c478bd9Sstevel@tonic-gate 	uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private;
619fffe0b30Sqz 	int error;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
6227c478bd9Sstevel@tonic-gate 	    "uhci_hcdi_pipe_ctrl_xfer: req=0x%p, ph=0x%p, flags=0x%x",
623112116d8Sfb 	    (void *)ctrl_reqp, (void *)ph, flags);
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
626fffe0b30Sqz 	error = uhci_state_is_operational(uhcip);
627fffe0b30Sqz 
628fffe0b30Sqz 	if (error != USB_SUCCESS) {
629fffe0b30Sqz 		mutex_exit(&uhcip->uhci_int_mutex);
630fffe0b30Sqz 
631fffe0b30Sqz 		return (error);
632fffe0b30Sqz 	}
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	ASSERT(pp->pp_state == UHCI_PIPE_STATE_IDLE);
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	/*
6377c478bd9Sstevel@tonic-gate 	 * Check and handle root hub control request.
6387c478bd9Sstevel@tonic-gate 	 */
6397c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
6407c478bd9Sstevel@tonic-gate 		error = uhci_handle_root_hub_request(uhcip, ph, ctrl_reqp);
6417c478bd9Sstevel@tonic-gate 		mutex_exit(&uhcip->uhci_int_mutex);
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 		return (error);
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	/* Insert the td's on the endpoint */
6477c478bd9Sstevel@tonic-gate 	if ((error = uhci_insert_ctrl_td(uhcip, ph, ctrl_reqp, flags)) !=
6487c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
6497c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
6507c478bd9Sstevel@tonic-gate 		    "uhci_hcdi_pipe_ctrl_xfer: No resources");
6517c478bd9Sstevel@tonic-gate 	}
6527c478bd9Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	return (error);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate /*
6597c478bd9Sstevel@tonic-gate  * uhci_hcdi_pipe_bulk_xfer:
6607c478bd9Sstevel@tonic-gate  */
6617c478bd9Sstevel@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)6627c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_bulk_xfer(usba_pipe_handle_data_t *pipe_handle,
6637c478bd9Sstevel@tonic-gate     usb_bulk_req_t *bulk_reqp, usb_flags_t usb_flags)
6647c478bd9Sstevel@tonic-gate {
6657c478bd9Sstevel@tonic-gate 	int		error;
6667c478bd9Sstevel@tonic-gate 	uhci_state_t	*uhcip;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	uhcip = uhci_obtain_state(pipe_handle->p_usba_device->usb_root_hub_dip);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
6717c478bd9Sstevel@tonic-gate 	    "uhci_hcdi_pipe_bulk_xfer: Flags = 0x%x", usb_flags);
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	/* Check the size of bulk request */
6747c478bd9Sstevel@tonic-gate 	if (bulk_reqp->bulk_len > UHCI_BULK_MAX_XFER_SIZE) {
6757c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
6767c478bd9Sstevel@tonic-gate 		    "uhci_hcdi_pipe_bulk_xfer: req size 0x%x is more than 0x%x",
6777c478bd9Sstevel@tonic-gate 		    bulk_reqp->bulk_len, UHCI_BULK_MAX_XFER_SIZE);
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
6837c478bd9Sstevel@tonic-gate 
684fffe0b30Sqz 	error = uhci_state_is_operational(uhcip);
685fffe0b30Sqz 
686fffe0b30Sqz 	if (error != USB_SUCCESS) {
687fffe0b30Sqz 		mutex_exit(&uhcip->uhci_int_mutex);
688fffe0b30Sqz 
689fffe0b30Sqz 		return (error);
690fffe0b30Sqz 	}
6917c478bd9Sstevel@tonic-gate 	/* Add the TD into the Host Controller's bulk list */
6927c478bd9Sstevel@tonic-gate 	if ((error = uhci_insert_bulk_td(uhcip, pipe_handle, bulk_reqp,
6937c478bd9Sstevel@tonic-gate 	    usb_flags)) != USB_SUCCESS) {
6947c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
6957c478bd9Sstevel@tonic-gate 		    "uhci_hcdi_pipe_bulk_xfer: uhci_insert_bulk_td failed");
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	return (error);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate /*
7047c478bd9Sstevel@tonic-gate  * uhci_hcdi_bulk_transfer_size:
7057c478bd9Sstevel@tonic-gate  *	Return maximum bulk transfer size
7067c478bd9Sstevel@tonic-gate  */
7077c478bd9Sstevel@tonic-gate int
uhci_hcdi_bulk_transfer_size(usba_device_t * usba_device,size_t * size)7087c478bd9Sstevel@tonic-gate uhci_hcdi_bulk_transfer_size(
7097c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device,
7107c478bd9Sstevel@tonic-gate 	size_t		*size)
7117c478bd9Sstevel@tonic-gate {
712fffe0b30Sqz 	uhci_state_t	*uhcip = uhci_obtain_state(
713fffe0b30Sqz 	    usba_device->usb_root_hub_dip);
714fffe0b30Sqz 	int		rval;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
7177c478bd9Sstevel@tonic-gate 	    "uhci_hcdi_bulk_transfer_size:");
7187c478bd9Sstevel@tonic-gate 
719fffe0b30Sqz 	mutex_enter(&uhcip->uhci_int_mutex);
720fffe0b30Sqz 	rval = uhci_state_is_operational(uhcip);
721fffe0b30Sqz 
722fffe0b30Sqz 	if (rval != USB_SUCCESS) {
723fffe0b30Sqz 		mutex_exit(&uhcip->uhci_int_mutex);
724fffe0b30Sqz 
725fffe0b30Sqz 		return (rval);
726fffe0b30Sqz 	}
727fffe0b30Sqz 
7287c478bd9Sstevel@tonic-gate 	*size = uhci_bulk_transfer_size;
729fffe0b30Sqz 	mutex_exit(&uhcip->uhci_int_mutex);
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate /*
7367c478bd9Sstevel@tonic-gate  * uhci_hcdi_pipe_intr_xfer:
7377c478bd9Sstevel@tonic-gate  */
7387c478bd9Sstevel@tonic-gate int
uhci_hcdi_pipe_intr_xfer(usba_pipe_handle_data_t * ph,usb_intr_req_t * req,usb_flags_t flags)7397c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_intr_xfer(
7407c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
7417c478bd9Sstevel@tonic-gate 	usb_intr_req_t		*req,
7427c478bd9Sstevel@tonic-gate 	usb_flags_t		flags)
7437c478bd9Sstevel@tonic-gate {
7447c478bd9Sstevel@tonic-gate 	uhci_state_t	*uhcip = uhci_obtain_state(
745fffe0b30Sqz 	    ph->p_usba_device->usb_root_hub_dip);
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
748112116d8Sfb 	    "uhci_hcdi_pipe_intr_xfer: req=0x%p, uf=0x%x", (void *)req, flags);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN) {
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 		return (uhci_start_periodic_pipe_polling(uhcip, ph,
753fffe0b30Sqz 		    (usb_opaque_t)req, flags));
7547c478bd9Sstevel@tonic-gate 	} else {
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 		return (uhci_send_intr_data(uhcip, ph, req, flags));
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate /*
7627c478bd9Sstevel@tonic-gate  * uhci_send_intr_data():
7637c478bd9Sstevel@tonic-gate  *	send data to interrupt out pipe
7647c478bd9Sstevel@tonic-gate  */
7657c478bd9Sstevel@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)7667c478bd9Sstevel@tonic-gate uhci_send_intr_data(
7677c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip,
7687c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*pipe_handle,
7697c478bd9Sstevel@tonic-gate 	usb_intr_req_t		*req,
7707c478bd9Sstevel@tonic-gate 	usb_flags_t		flags)
7717c478bd9Sstevel@tonic-gate {
772fffe0b30Sqz 	int	rval;
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
7757c478bd9Sstevel@tonic-gate 	    "uhci_send_intr_data:");
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
7787c478bd9Sstevel@tonic-gate 
779fffe0b30Sqz 	rval = uhci_state_is_operational(uhcip);
780fffe0b30Sqz 
781fffe0b30Sqz 	if (rval != USB_SUCCESS) {
782fffe0b30Sqz 		mutex_exit(&uhcip->uhci_int_mutex);
783fffe0b30Sqz 
784fffe0b30Sqz 		return (rval);
785fffe0b30Sqz 	}
786fffe0b30Sqz 
7877c478bd9Sstevel@tonic-gate 	/* Add the TD into the Host Controller's interrupt list */
7887c478bd9Sstevel@tonic-gate 	if ((rval = uhci_insert_intr_td(uhcip, pipe_handle, req, flags)) !=
7897c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
7907c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
7917c478bd9Sstevel@tonic-gate 		    "uhci_send_intr_data: No resources");
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	return (rval);
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate /*
8007c478bd9Sstevel@tonic-gate  * uhci_hcdi_pipe_stop_intr_polling()
8017c478bd9Sstevel@tonic-gate  */
8027c478bd9Sstevel@tonic-gate int
uhci_hcdi_pipe_stop_intr_polling(usba_pipe_handle_data_t * pipe_handle,usb_flags_t flags)8037c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_stop_intr_polling(
8047c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *pipe_handle,
8057c478bd9Sstevel@tonic-gate 	usb_flags_t		flags)
8067c478bd9Sstevel@tonic-gate {
8077c478bd9Sstevel@tonic-gate 	uhci_state_t *uhcip =
808fffe0b30Sqz 	    uhci_obtain_state(pipe_handle->p_usba_device->usb_root_hub_dip);
809fffe0b30Sqz 	int		rval;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
8127c478bd9Sstevel@tonic-gate 	    "uhci_hcdi_pipe_stop_intr_polling: ph = 0x%p fl = 0x%x",
8137c478bd9Sstevel@tonic-gate 	    (void *)pipe_handle, flags);
814fffe0b30Sqz 	mutex_enter(&uhcip->uhci_int_mutex);
8157c478bd9Sstevel@tonic-gate 
816fffe0b30Sqz 	rval = uhci_stop_periodic_pipe_polling(uhcip, pipe_handle, flags);
817fffe0b30Sqz 
818fffe0b30Sqz 	mutex_exit(&uhcip->uhci_int_mutex);
819fffe0b30Sqz 
820fffe0b30Sqz 	return (rval);
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate /*
8257c478bd9Sstevel@tonic-gate  * uhci_hcdi_get_current_frame_number
826fffe0b30Sqz  *	Get the current frame number.
827fffe0b30Sqz  *	Return whether the request is handled successfully.
8287c478bd9Sstevel@tonic-gate  */
829fffe0b30Sqz int
uhci_hcdi_get_current_frame_number(usba_device_t * usba_device,usb_frame_number_t * frame_number)830fffe0b30Sqz uhci_hcdi_get_current_frame_number(
831fffe0b30Sqz 	usba_device_t		*usba_device,
832fffe0b30Sqz 	usb_frame_number_t	*frame_number)
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate 	uhci_state_t *uhcip = uhci_obtain_state(usba_device->usb_root_hub_dip);
835fffe0b30Sqz 	int		rval;
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
838fffe0b30Sqz 	rval = uhci_state_is_operational(uhcip);
839fffe0b30Sqz 
840fffe0b30Sqz 	if (rval != USB_SUCCESS) {
841fffe0b30Sqz 		mutex_exit(&uhcip->uhci_int_mutex);
842fffe0b30Sqz 
843fffe0b30Sqz 		return (rval);
844fffe0b30Sqz 	}
845fffe0b30Sqz 
846fffe0b30Sqz 	*frame_number = uhci_get_sw_frame_number(uhcip);
8477c478bd9Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
850112116d8Sfb 	    "uhci_hcdi_get_current_frame_number: %llx",
851112116d8Sfb 	    (unsigned long long)(*frame_number));
8527c478bd9Sstevel@tonic-gate 
853fffe0b30Sqz 	return (rval);
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate /*
8587c478bd9Sstevel@tonic-gate  * uhci_hcdi_get_max_isoc_pkts
859fffe0b30Sqz  *	Get the maximum number of isoc packets per USB Isoch request.
860fffe0b30Sqz  *	Return whether the request is handled successfully.
8617c478bd9Sstevel@tonic-gate  */
862fffe0b30Sqz int
uhci_hcdi_get_max_isoc_pkts(usba_device_t * usba_device,uint_t * max_isoc_pkts_per_request)863fffe0b30Sqz uhci_hcdi_get_max_isoc_pkts(
864fffe0b30Sqz 	usba_device_t	*usba_device,
865fffe0b30Sqz 	uint_t		*max_isoc_pkts_per_request)
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate 	uhci_state_t *uhcip = uhci_obtain_state(usba_device->usb_root_hub_dip);
868fffe0b30Sqz 	int		rval;
869fffe0b30Sqz 
870fffe0b30Sqz 	mutex_enter(&uhcip->uhci_int_mutex);
871fffe0b30Sqz 	rval = uhci_state_is_operational(uhcip);
872fffe0b30Sqz 
873fffe0b30Sqz 	if (rval != USB_SUCCESS) {
874fffe0b30Sqz 		mutex_exit(&uhcip->uhci_int_mutex);
875fffe0b30Sqz 
876fffe0b30Sqz 		return (rval);
877fffe0b30Sqz 	}
878fffe0b30Sqz 
879fffe0b30Sqz 	*max_isoc_pkts_per_request = UHCI_MAX_ISOC_PKTS;
880fffe0b30Sqz 	mutex_exit(&uhcip->uhci_int_mutex);
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
8837c478bd9Sstevel@tonic-gate 	    "uhci_hcdi_get_max_isoc_pkts: 0x%x", UHCI_MAX_ISOC_PKTS);
8847c478bd9Sstevel@tonic-gate 
885fffe0b30Sqz 	return (rval);
8867c478bd9Sstevel@tonic-gate }
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate /*
8907c478bd9Sstevel@tonic-gate  * uhci_hcdi_pipe_isoc_xfer:
8917c478bd9Sstevel@tonic-gate  */
8927c478bd9Sstevel@tonic-gate int
uhci_hcdi_pipe_isoc_xfer(usba_pipe_handle_data_t * ph,usb_isoc_req_t * isoc_reqp,usb_flags_t flags)8937c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_isoc_xfer(
8947c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
8957c478bd9Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_reqp,
8967c478bd9Sstevel@tonic-gate 	usb_flags_t		flags)
8977c478bd9Sstevel@tonic-gate {
8987c478bd9Sstevel@tonic-gate 	uhci_state_t	*uhcip;
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
9017c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
902112116d8Sfb 	    "uhci_hcdi_pipe_isoc_xfer: req=0x%p, uf=0x%x",
903112116d8Sfb 	    (void *)isoc_reqp, flags);
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN) {
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 		return (uhci_start_periodic_pipe_polling(uhcip, ph,
908fffe0b30Sqz 		    (usb_opaque_t)isoc_reqp, flags));
9097c478bd9Sstevel@tonic-gate 	} else {
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 		return (uhci_pipe_send_isoc_data(uhcip, ph, isoc_reqp, flags));
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate /*
9177c478bd9Sstevel@tonic-gate  * uhci_hcdi_pipe_stop_isoc_polling()
9187c478bd9Sstevel@tonic-gate  */
9197c478bd9Sstevel@tonic-gate int
uhci_hcdi_pipe_stop_isoc_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)9207c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_stop_isoc_polling(
9217c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
9227c478bd9Sstevel@tonic-gate 	usb_flags_t		flags)
9237c478bd9Sstevel@tonic-gate {
9247c478bd9Sstevel@tonic-gate 	uhci_state_t *uhcip =
925fffe0b30Sqz 	    uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
926fffe0b30Sqz 	int		rval;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
9297c478bd9Sstevel@tonic-gate 	    "uhci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x",
9307c478bd9Sstevel@tonic-gate 	    (void *)ph, flags);
9317c478bd9Sstevel@tonic-gate 
932fffe0b30Sqz 	mutex_enter(&uhcip->uhci_int_mutex);
933fffe0b30Sqz 	rval = uhci_state_is_operational(uhcip);
934fffe0b30Sqz 
935fffe0b30Sqz 	if (rval != USB_SUCCESS) {
936fffe0b30Sqz 		mutex_exit(&uhcip->uhci_int_mutex);
937fffe0b30Sqz 
938fffe0b30Sqz 		return (rval);
939fffe0b30Sqz 	}
940fffe0b30Sqz 
941fffe0b30Sqz 	rval = uhci_stop_periodic_pipe_polling(uhcip, ph, flags);
942fffe0b30Sqz 
943fffe0b30Sqz 	mutex_exit(&uhcip->uhci_int_mutex);
944fffe0b30Sqz 
945fffe0b30Sqz 	return (rval);
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate /*
9507c478bd9Sstevel@tonic-gate  * uhci_start_periodic_pipe_polling:
9517c478bd9Sstevel@tonic-gate  */
9527c478bd9Sstevel@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)9537c478bd9Sstevel@tonic-gate uhci_start_periodic_pipe_polling(
9547c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip,
9557c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
9567c478bd9Sstevel@tonic-gate 	usb_opaque_t		in_reqp,
9577c478bd9Sstevel@tonic-gate 	usb_flags_t		flags)
9587c478bd9Sstevel@tonic-gate {
9597c478bd9Sstevel@tonic-gate 	int			n, num_tds;
960fffe0b30Sqz 	int			error;
9617c478bd9Sstevel@tonic-gate 	usb_intr_req_t		*intr_reqp = (usb_intr_req_t *)in_reqp;
9627c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
9637c478bd9Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
9667c478bd9Sstevel@tonic-gate 	    "uhci_start_periodic_pipe_polling: flags: 0x%x, ep%d",
9677c478bd9Sstevel@tonic-gate 	    flags, eptd->bEndpointAddress);
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
9707c478bd9Sstevel@tonic-gate 
971fffe0b30Sqz 	error = uhci_state_is_operational(uhcip);
972fffe0b30Sqz 
973fffe0b30Sqz 	if (error != USB_SUCCESS) {
974fffe0b30Sqz 		mutex_exit(&uhcip->uhci_int_mutex);
975fffe0b30Sqz 
976fffe0b30Sqz 		return (error);
977fffe0b30Sqz 	}
978fffe0b30Sqz 
9797c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
9807c478bd9Sstevel@tonic-gate 		uint_t	pipe_state = uhcip->uhci_root_hub.rh_pipe_state;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 		ASSERT(pipe_state == UHCI_PIPE_STATE_IDLE);
9837c478bd9Sstevel@tonic-gate 		ASSERT(UHCI_XFER_DIR(eptd) == USB_EP_DIR_IN);
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 		/* ONE_XFER not supported */
9867c478bd9Sstevel@tonic-gate 		ASSERT((intr_reqp->intr_attributes &
9877c478bd9Sstevel@tonic-gate 		    USB_ATTRS_ONE_XFER) == 0);
9887c478bd9Sstevel@tonic-gate 		ASSERT(uhcip->uhci_root_hub.rh_client_intr_req == NULL);
9897c478bd9Sstevel@tonic-gate 		uhcip->uhci_root_hub.rh_client_intr_req = intr_reqp;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 		if ((error = uhci_root_hub_allocate_intr_pipe_resource(
9927c478bd9Sstevel@tonic-gate 		    uhcip, flags)) != USB_SUCCESS) {
9937c478bd9Sstevel@tonic-gate 			/* reset the client interrupt request pointer */
9947c478bd9Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_client_intr_req = NULL;
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 			mutex_exit(&uhcip->uhci_int_mutex);
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 			return (error);
9997c478bd9Sstevel@tonic-gate 		}
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 		uhcip->uhci_root_hub.rh_pipe_state = USB_PIPE_STATE_ACTIVE;
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
10047c478bd9Sstevel@tonic-gate 		    "uhci_start_periodic_pipe_polling: "
10057c478bd9Sstevel@tonic-gate 		    "Start intr polling for root hub successful");
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 		/* check if we need to send the reset data up? */
10087c478bd9Sstevel@tonic-gate 		if (uhcip->uhci_root_hub.rh_status) {
10097c478bd9Sstevel@tonic-gate 			uhci_root_hub_reset_occurred(uhcip,
10107c478bd9Sstevel@tonic-gate 			    uhcip->uhci_root_hub.rh_status - 1);
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_status = 0;
10137c478bd9Sstevel@tonic-gate 		}
10147c478bd9Sstevel@tonic-gate 		mutex_exit(&uhcip->uhci_int_mutex);
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 		return (error);
10177c478bd9Sstevel@tonic-gate 	}
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	/* save the original client's periodic IN request */
10207c478bd9Sstevel@tonic-gate 	pp->pp_client_periodic_in_reqp = in_reqp;
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	ASSERT(pp->pp_state != UHCI_PIPE_STATE_ACTIVE);
10237c478bd9Sstevel@tonic-gate 	/*
10247c478bd9Sstevel@tonic-gate 	 *
10257c478bd9Sstevel@tonic-gate 	 * This pipe is uninitialized. If it is an isoc
10267c478bd9Sstevel@tonic-gate 	 * receive request, insert four times the same
10277c478bd9Sstevel@tonic-gate 	 * request so that we do not lose any frames.
10287c478bd9Sstevel@tonic-gate 	 */
10297c478bd9Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_ISOCH) {
10307c478bd9Sstevel@tonic-gate 		for (n = 0; n < 5; n++) {
10317c478bd9Sstevel@tonic-gate 			if ((error = uhci_start_isoc_receive_polling(
10327c478bd9Sstevel@tonic-gate 			    uhcip, ph, NULL, flags)) != USB_SUCCESS) {
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L2(PRINT_MASK_INTR,
10357c478bd9Sstevel@tonic-gate 				    uhcip->uhci_log_hdl,
10367c478bd9Sstevel@tonic-gate 				    "uhci_start_periodic_pipe_polling: "
10377c478bd9Sstevel@tonic-gate 				    "Start isoc polling failed %d", n);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 				pp->pp_client_periodic_in_reqp = NULL;
10407c478bd9Sstevel@tonic-gate 				mutex_exit(&uhcip->uhci_int_mutex);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 				return (error);
10437c478bd9Sstevel@tonic-gate 			}
10447c478bd9Sstevel@tonic-gate 		}
10457c478bd9Sstevel@tonic-gate 	}
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_INTR) {
10487c478bd9Sstevel@tonic-gate 		if ((pp->pp_node < POLLING_FREQ_7MS) &&
10497c478bd9Sstevel@tonic-gate 		    (!(intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER))) {
10507c478bd9Sstevel@tonic-gate 			num_tds = 5;
10517c478bd9Sstevel@tonic-gate 		} else {
10527c478bd9Sstevel@tonic-gate 			num_tds = 1;
10537c478bd9Sstevel@tonic-gate 		}
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 		/*
10567c478bd9Sstevel@tonic-gate 		 * This pipe is uninitialized.
10577c478bd9Sstevel@tonic-gate 		 * Insert a TD on the interrupt ED.
10587c478bd9Sstevel@tonic-gate 		 */
10597c478bd9Sstevel@tonic-gate 		for (n = 0; n < num_tds; n++) {
10607c478bd9Sstevel@tonic-gate 			if ((error = uhci_insert_intr_td(uhcip, ph, NULL,
10617c478bd9Sstevel@tonic-gate 			    flags)) != USB_SUCCESS) {
10627c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L2(PRINT_MASK_INTR,
10637c478bd9Sstevel@tonic-gate 				    uhcip->uhci_log_hdl,
10647c478bd9Sstevel@tonic-gate 				    "uhci_start_periodic_pipe_polling: "
10657c478bd9Sstevel@tonic-gate 				    "Start polling failed");
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 				pp->pp_client_periodic_in_reqp = NULL;
10687c478bd9Sstevel@tonic-gate 				mutex_exit(&uhcip->uhci_int_mutex);
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 				return (error);
10717c478bd9Sstevel@tonic-gate 			}
10727c478bd9Sstevel@tonic-gate 		}
10737c478bd9Sstevel@tonic-gate 	}
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	pp->pp_state = UHCI_PIPE_STATE_ACTIVE;
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	return (error);
10807c478bd9Sstevel@tonic-gate }
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate /*
10847c478bd9Sstevel@tonic-gate  * uhci_hcdi_periodic_pipe_stop_polling:
10857c478bd9Sstevel@tonic-gate  */
10867c478bd9Sstevel@tonic-gate static int
uhci_stop_periodic_pipe_polling(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph,usb_flags_t flags)10877c478bd9Sstevel@tonic-gate uhci_stop_periodic_pipe_polling(uhci_state_t *uhcip,
10887c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t  *ph, usb_flags_t flags)
10897c478bd9Sstevel@tonic-gate {
10907c478bd9Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
10917c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
10947c478bd9Sstevel@tonic-gate 	    "uhci_stop_periodic_pipe_polling: flags = 0x%x", flags);
10957c478bd9Sstevel@tonic-gate 
1096fffe0b30Sqz 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
10977c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
10987c478bd9Sstevel@tonic-gate 		ASSERT(UHCI_XFER_DIR(eptd) == USB_EP_DIR_IN);
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 		if (uhcip->uhci_root_hub.rh_pipe_state ==
11017c478bd9Sstevel@tonic-gate 		    UHCI_PIPE_STATE_ACTIVE) {
11027c478bd9Sstevel@tonic-gate 			uhcip->uhci_root_hub.rh_pipe_state =
1103fffe0b30Sqz 			    UHCI_PIPE_STATE_IDLE;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 			/* Do interrupt pipe cleanup */
11067c478bd9Sstevel@tonic-gate 			uhci_root_hub_intr_pipe_cleanup(uhcip,
1107fffe0b30Sqz 			    USB_CR_STOPPED_POLLING);
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
11107c478bd9Sstevel@tonic-gate 			    "uhci_stop_periodic_pipe_polling: Stop intr "
11117c478bd9Sstevel@tonic-gate 			    "polling for root hub successful");
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 		} else {
11147c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
11157c478bd9Sstevel@tonic-gate 			    "uhci_stop_periodic_pipe_polling: "
11167c478bd9Sstevel@tonic-gate 			    "Intr polling for root hub is already stopped");
11177c478bd9Sstevel@tonic-gate 		}
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
11207c478bd9Sstevel@tonic-gate 	}
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 	if (pp->pp_state != UHCI_PIPE_STATE_ACTIVE) {
11237c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
11247c478bd9Sstevel@tonic-gate 		    "uhci_stop_periodic_pipe_polling: Polling already stopped");
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	/*
11307c478bd9Sstevel@tonic-gate 	 * Set the terminate bits in all the tds in the queue and
11317c478bd9Sstevel@tonic-gate 	 * in the element_ptr.
11327c478bd9Sstevel@tonic-gate 	 * Do not deallocate the bandwidth or tear down the DMA
11337c478bd9Sstevel@tonic-gate 	 */
11347c478bd9Sstevel@tonic-gate 	uhci_modify_td_active_bits(uhcip, pp);
11357c478bd9Sstevel@tonic-gate 	(void) uhci_wait_for_sof(uhcip);
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_ISOCH) {
11387c478bd9Sstevel@tonic-gate 		uhci_remove_isoc_tds_tws(uhcip, pp);
11397c478bd9Sstevel@tonic-gate 		pp->pp_state = UHCI_PIPE_STATE_IDLE;
11407c478bd9Sstevel@tonic-gate 	} else {
11417c478bd9Sstevel@tonic-gate 		UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr);
11427c478bd9Sstevel@tonic-gate 		uhci_update_intr_td_data_toggle(uhcip, pp);
11437c478bd9Sstevel@tonic-gate 		SetQH32(uhcip, pp->pp_qh->element_ptr,
11447c478bd9Sstevel@tonic-gate 		    TD_PADDR(pp->pp_qh->td_tailp));
11457c478bd9Sstevel@tonic-gate 		uhci_remove_tds_tws(uhcip, ph);
11467c478bd9Sstevel@tonic-gate 	}
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	pp->pp_state = UHCI_PIPE_STATE_IDLE;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	if (pp->pp_client_periodic_in_reqp) {
11517c478bd9Sstevel@tonic-gate 		uhci_hcdi_callback(uhcip, pp, ph, NULL, USB_CR_STOPPED_POLLING);
11527c478bd9Sstevel@tonic-gate 	}
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
11557c478bd9Sstevel@tonic-gate }
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate /*
11597c478bd9Sstevel@tonic-gate  * uhci_hcdi_pipe_send_isoc_data:
11607c478bd9Sstevel@tonic-gate  *	Handles the isoc write request.
11617c478bd9Sstevel@tonic-gate  */
11627c478bd9Sstevel@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)11637c478bd9Sstevel@tonic-gate uhci_pipe_send_isoc_data(
11647c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip,
11657c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
11667c478bd9Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_req,
11677c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags)
11687c478bd9Sstevel@tonic-gate {
11697c478bd9Sstevel@tonic-gate 	int			error;
11707c478bd9Sstevel@tonic-gate 	size_t			max_isoc_xfer_sz, length;
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
11737c478bd9Sstevel@tonic-gate 	    "uhci_pipe_send_isoc_data: isoc_req = %p flags = %x",
1174112116d8Sfb 	    (void *)isoc_req, usb_flags);
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	ASSERT(isoc_req->isoc_pkts_count < UHCI_MAX_ISOC_PKTS);
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	/* Calculate the maximum isochronous transfer size */
11797c478bd9Sstevel@tonic-gate 	max_isoc_xfer_sz = UHCI_MAX_ISOC_PKTS * ph->p_ep.wMaxPacketSize;
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	/* Check the size of isochronous request */
11827c478bd9Sstevel@tonic-gate 	ASSERT(isoc_req->isoc_data != NULL);
118322eb7cb5Sgd 	length = MBLKL(isoc_req->isoc_data);
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	if (length > max_isoc_xfer_sz) {
11867c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
11877c478bd9Sstevel@tonic-gate 		    "uhci_pipe_send_isoc_data: Maximum isoc request size %lx "
11887c478bd9Sstevel@tonic-gate 		    "Given isoc request size %lx", max_isoc_xfer_sz, length);
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 		return (USB_INVALID_REQUEST);
11917c478bd9Sstevel@tonic-gate 	}
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 	/*
11957c478bd9Sstevel@tonic-gate 	 * Check whether we can insert these tds?
11967c478bd9Sstevel@tonic-gate 	 * At any point of time, we can insert maximum of 1024 isoc td's,
11977c478bd9Sstevel@tonic-gate 	 * size of frame list table.
11987c478bd9Sstevel@tonic-gate 	 */
11997c478bd9Sstevel@tonic-gate 	if (isoc_req->isoc_pkts_count > UHCI_MAX_ISOC_PKTS) {
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
12027c478bd9Sstevel@tonic-gate 		    "uhci_pipe_send_isoc_data: request too big");
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 		return (USB_INVALID_REQUEST);
12057c478bd9Sstevel@tonic-gate 	}
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	/* Add the TD into the Host Controller's isoc list */
12087c478bd9Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
12097c478bd9Sstevel@tonic-gate 
1210fffe0b30Sqz 	error = uhci_state_is_operational(uhcip);
1211fffe0b30Sqz 
1212fffe0b30Sqz 	if (error != USB_SUCCESS) {
1213fffe0b30Sqz 		mutex_exit(&uhcip->uhci_int_mutex);
1214fffe0b30Sqz 
1215fffe0b30Sqz 		return (error);
1216fffe0b30Sqz 	}
1217fffe0b30Sqz 
12187c478bd9Sstevel@tonic-gate 	if ((error = uhci_insert_isoc_td(uhcip, ph, isoc_req,
12197c478bd9Sstevel@tonic-gate 	    length, usb_flags)) != USB_SUCCESS) {
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
12227c478bd9Sstevel@tonic-gate 		    "uhci_pipe_send_isoc_data: Unable to insert the isoc_req,"
12237c478bd9Sstevel@tonic-gate 		    "Error = %d", error);
12247c478bd9Sstevel@tonic-gate 	}
12257c478bd9Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	return (error);
12287c478bd9Sstevel@tonic-gate }
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate /*
12327c478bd9Sstevel@tonic-gate  * uhci_update_intr_td_data_toggle
12337c478bd9Sstevel@tonic-gate  *	Update the data toggle and save in the usba_device structure
12347c478bd9Sstevel@tonic-gate  */
12357c478bd9Sstevel@tonic-gate static void
uhci_update_intr_td_data_toggle(uhci_state_t * uhcip,uhci_pipe_private_t * pp)12367c478bd9Sstevel@tonic-gate uhci_update_intr_td_data_toggle(uhci_state_t *uhcip, uhci_pipe_private_t *pp)
12377c478bd9Sstevel@tonic-gate {
12387c478bd9Sstevel@tonic-gate 	uint32_t	paddr_tail, element_ptr;
12397c478bd9Sstevel@tonic-gate 	uhci_td_t	*next_td;
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	/* Find the next td that would have been executed */
12427c478bd9Sstevel@tonic-gate 	element_ptr = GetQH32(uhcip, pp->pp_qh->element_ptr) &
1243fffe0b30Sqz 	    QH_ELEMENT_PTR_MASK;
12447c478bd9Sstevel@tonic-gate 	next_td = TD_VADDR(element_ptr);
12457c478bd9Sstevel@tonic-gate 	paddr_tail = TD_PADDR(pp->pp_qh->td_tailp);
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	/*
12487c478bd9Sstevel@tonic-gate 	 * If element_ptr points to the dummy td, then the data toggle in
12497c478bd9Sstevel@tonic-gate 	 * pp_data_toggle is correct. Otherwise update the data toggle in
12507c478bd9Sstevel@tonic-gate 	 * the pipe private
12517c478bd9Sstevel@tonic-gate 	 */
12527c478bd9Sstevel@tonic-gate 	if (element_ptr != paddr_tail) {
12537c478bd9Sstevel@tonic-gate 		pp->pp_data_toggle = GetTD_dtogg(uhcip, next_td);
12547c478bd9Sstevel@tonic-gate 	}
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
12577c478bd9Sstevel@tonic-gate 	    "uhci_update_intr_td_data_toggle: "
12587c478bd9Sstevel@tonic-gate 	    "pp %p toggle %x element ptr %x ptail %x",
1259112116d8Sfb 	    (void *)pp, pp->pp_data_toggle, element_ptr, paddr_tail);
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	uhci_save_data_toggle(pp);
12627c478bd9Sstevel@tonic-gate }
1263