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
528cdc3d7Sszhou  * Common Development and Distribution License (the "License").
628cdc3d7Sszhou  * 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 /*
2222eb7cb5Sgd  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * This module contains the specific uhci code used in POLLED mode.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcid.h>
317c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcipolled.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #ifndef __sparc
347c478bd9Sstevel@tonic-gate extern void invalidate_cache();
357c478bd9Sstevel@tonic-gate #endif
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate  * Internal Function Prototypes
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate /* Polled initialization routine */
407c478bd9Sstevel@tonic-gate static int	uhci_polled_init(usba_pipe_handle_data_t *, uhci_state_t *,
417c478bd9Sstevel@tonic-gate 		    usb_console_info_impl_t *);
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /* Polled fini routine */
447c478bd9Sstevel@tonic-gate static int	uhci_polled_fini(uhci_polled_t *, uhci_state_t *);
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /* Polled save state routine */
477c478bd9Sstevel@tonic-gate static void	uhci_polled_save_state(uhci_polled_t *);
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /* Polled restore state routine */
507c478bd9Sstevel@tonic-gate static void	uhci_polled_restore_state(uhci_polled_t *);
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /* Polled read routines */
537c478bd9Sstevel@tonic-gate static int	uhci_polled_insert_td_on_qh(uhci_polled_t *,
547c478bd9Sstevel@tonic-gate 		    usba_pipe_handle_data_t *);
557c478bd9Sstevel@tonic-gate static uhci_trans_wrapper_t
567c478bd9Sstevel@tonic-gate 		*uhci_polled_create_tw(uhci_state_t *);
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * POLLED entry points
617c478bd9Sstevel@tonic-gate  *
627c478bd9Sstevel@tonic-gate  * These functions are entry points into the POLLED code.
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /*
667c478bd9Sstevel@tonic-gate  * uhci_hcdi_polled_input_init:
677c478bd9Sstevel@tonic-gate  *	This is the initialization routine for handling the USB keyboard
687c478bd9Sstevel@tonic-gate  *	in POLLED mode.  This routine is not called from POLLED mode, so
697c478bd9Sstevel@tonic-gate  *	it is OK to acquire mutexes.
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate int
uhci_hcdi_polled_input_init(usba_pipe_handle_data_t * ph,uchar_t ** polled_buf,usb_console_info_impl_t * console_input_info)727c478bd9Sstevel@tonic-gate uhci_hcdi_polled_input_init(usba_pipe_handle_data_t *ph,
737c478bd9Sstevel@tonic-gate 	uchar_t			**polled_buf,
747c478bd9Sstevel@tonic-gate 	usb_console_info_impl_t *console_input_info)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	int		ret;
777c478bd9Sstevel@tonic-gate 	uhci_polled_t	*uhci_polledp;
787c478bd9Sstevel@tonic-gate 	uhci_state_t	*uhcip;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	/*
837c478bd9Sstevel@tonic-gate 	 * Grab the uhci_int_mutex so that things don't change on us
847c478bd9Sstevel@tonic-gate 	 * if an interrupt comes in.
857c478bd9Sstevel@tonic-gate 	 */
867c478bd9Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
877c478bd9Sstevel@tonic-gate 	ret = uhci_polled_init(ph, uhcip, console_input_info);
887c478bd9Sstevel@tonic-gate 	if (ret != USB_SUCCESS) {
897c478bd9Sstevel@tonic-gate 		mutex_exit(&uhcip->uhci_int_mutex);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 		return (ret);
927c478bd9Sstevel@tonic-gate 	}
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	uhci_polledp = (uhci_polled_t *)console_input_info->uci_private;
957c478bd9Sstevel@tonic-gate 	/*
967c478bd9Sstevel@tonic-gate 	 * Mark the structure so that if we are using it, we don't free
977c478bd9Sstevel@tonic-gate 	 * the structures if one of them is unplugged.
987c478bd9Sstevel@tonic-gate 	 */
997c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_flags |= POLLED_INPUT_MODE;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	/*
1027c478bd9Sstevel@tonic-gate 	 * This is the buffer we will copy characters into. It will be
1037c478bd9Sstevel@tonic-gate 	 * copied into at this layer, so we need to keep track of it.
1047c478bd9Sstevel@tonic-gate 	 */
1057c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_buf =
10622eb7cb5Sgd 	    (uchar_t *)kmem_zalloc(POLLED_RAW_BUF_SIZE, KM_SLEEP);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	*polled_buf = uhci_polledp->uhci_polled_buf;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
1117c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate  * uhci_hcdi_polled_input_fini:
1177c478bd9Sstevel@tonic-gate  */
1187c478bd9Sstevel@tonic-gate int
uhci_hcdi_polled_input_fini(usb_console_info_impl_t * info)1197c478bd9Sstevel@tonic-gate uhci_hcdi_polled_input_fini(usb_console_info_impl_t *info)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate 	int			ret;
1227c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip;
1237c478bd9Sstevel@tonic-gate 	uhci_polled_t		*uhci_polledp;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	uhci_polledp = (uhci_polled_t *)info->uci_private;
1267c478bd9Sstevel@tonic-gate 	uhcip = uhci_polledp->uhci_polled_uhcip;
1277c478bd9Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	/* Free the buffer that we copied data into */
1307c478bd9Sstevel@tonic-gate 	kmem_free(uhci_polledp->uhci_polled_buf, POLLED_RAW_BUF_SIZE);
1317c478bd9Sstevel@tonic-gate 	ret = uhci_polled_fini(uhci_polledp, uhcip);
1327c478bd9Sstevel@tonic-gate 	info->uci_private = NULL;
1337c478bd9Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	return (ret);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate  * uhci_hcdi_polled_input_enter:
1417c478bd9Sstevel@tonic-gate  *	This is where we enter into POLLED mode.  This routine sets up
1427c478bd9Sstevel@tonic-gate  *	everything so that calls to  uhci_hcdi_polled_read will return
1437c478bd9Sstevel@tonic-gate  *	characters.
1447c478bd9Sstevel@tonic-gate  */
1457c478bd9Sstevel@tonic-gate int
uhci_hcdi_polled_input_enter(usb_console_info_impl_t * info)1467c478bd9Sstevel@tonic-gate uhci_hcdi_polled_input_enter(usb_console_info_impl_t *info)
1477c478bd9Sstevel@tonic-gate {
1487c478bd9Sstevel@tonic-gate 	uhci_polled_t	*uhci_polledp;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	uhci_polledp = (uhci_polled_t *)info->uci_private;
1517c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_entry++;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	/*
1547c478bd9Sstevel@tonic-gate 	 * If the controller is already switched over, just return
1557c478bd9Sstevel@tonic-gate 	 */
1567c478bd9Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_entry > 1) {
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	uhci_polled_save_state(uhci_polledp);
1627c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_flags |= POLLED_INPUT_MODE_INUSE;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate  * uhci_hcdi_polled_input_exit:
1707c478bd9Sstevel@tonic-gate  *	This is where we exit POLLED mode. This routine restores
1717c478bd9Sstevel@tonic-gate  *	everything that is needed to continue operation.
1727c478bd9Sstevel@tonic-gate  */
1737c478bd9Sstevel@tonic-gate int
uhci_hcdi_polled_input_exit(usb_console_info_impl_t * info)1747c478bd9Sstevel@tonic-gate uhci_hcdi_polled_input_exit(usb_console_info_impl_t *info)
1757c478bd9Sstevel@tonic-gate {
1767c478bd9Sstevel@tonic-gate 	uhci_polled_t	*uhci_polledp;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	uhci_polledp = (uhci_polled_t *)info->uci_private;
1797c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_entry--;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	/*
1827c478bd9Sstevel@tonic-gate 	 * If there are still outstanding "enters", just return
1837c478bd9Sstevel@tonic-gate 	 */
1847c478bd9Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_entry > 0) {
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_flags &= ~POLLED_INPUT_MODE_INUSE;
1907c478bd9Sstevel@tonic-gate 	uhci_polled_restore_state(uhci_polledp);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate  * uhci_hcdi_polled_read:
1987c478bd9Sstevel@tonic-gate  *	Get a key character
1997c478bd9Sstevel@tonic-gate  */
2007c478bd9Sstevel@tonic-gate int
uhci_hcdi_polled_read(usb_console_info_impl_t * info,uint_t * num_characters)2017c478bd9Sstevel@tonic-gate uhci_hcdi_polled_read(usb_console_info_impl_t *info, uint_t *num_characters)
2027c478bd9Sstevel@tonic-gate {
2037c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip;
2047c478bd9Sstevel@tonic-gate 	uhci_polled_t		*uhci_polledp;
2057c478bd9Sstevel@tonic-gate 	uhci_td_t		*td;
2067c478bd9Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw;
2077c478bd9Sstevel@tonic-gate 	ushort_t		intr_status;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	uhci_polledp = (uhci_polled_t *)info->uci_private;
2107c478bd9Sstevel@tonic-gate 	uhcip = uhci_polledp->uhci_polled_uhcip;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	/*
2137c478bd9Sstevel@tonic-gate 	 * This is a temporary work around for halt problem. The upper
2147c478bd9Sstevel@tonic-gate 	 * layer code does not call the right sequence of entry points
2157c478bd9Sstevel@tonic-gate 	 * points for reading a character in a polled mode. Once the
2167c478bd9Sstevel@tonic-gate 	 * upper layer code is fixed, the following code (two lines)
2177c478bd9Sstevel@tonic-gate 	 * must be removed.
2187c478bd9Sstevel@tonic-gate 	 */
2197c478bd9Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_entry == 0) {
2207c478bd9Sstevel@tonic-gate 		if (uhci_hcdi_polled_input_enter(info) != USB_SUCCESS) {
2217c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "Entering Polled Mode failed");
2227c478bd9Sstevel@tonic-gate 		}
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate #ifndef lint
2267c478bd9Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
2277c478bd9Sstevel@tonic-gate #endif
2287c478bd9Sstevel@tonic-gate #ifndef __sparc
2297c478bd9Sstevel@tonic-gate 	invalidate_cache();
2307c478bd9Sstevel@tonic-gate #endif
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	td = uhci_polledp->uhci_polled_td;
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	/*
2357c478bd9Sstevel@tonic-gate 	 * Check to see if there are any TD's on the done head.
2367c478bd9Sstevel@tonic-gate 	 */
2377c478bd9Sstevel@tonic-gate 	if (GetTD_status(uhcip, td) & UHCI_TD_ACTIVE) {
2387c478bd9Sstevel@tonic-gate 		*num_characters = 0;
2397c478bd9Sstevel@tonic-gate 	} else {
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 		/*
2427c478bd9Sstevel@tonic-gate 		 * If the TD does not complete, retry.
2437c478bd9Sstevel@tonic-gate 		 */
2447c478bd9Sstevel@tonic-gate 		if ((GetTD_status(uhcip, td) & TD_STATUS_MASK) ||
2457c478bd9Sstevel@tonic-gate 		    (GetTD_alen(uhcip, td) == ZERO_LENGTH)) {
2467c478bd9Sstevel@tonic-gate 			*num_characters = 0;
2477c478bd9Sstevel@tonic-gate 			SetTD_alen(uhcip, td, 0);
2487c478bd9Sstevel@tonic-gate 		} else {
2497c478bd9Sstevel@tonic-gate 			*num_characters = GetTD_alen(uhcip, td) + 1;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 			tw = td->tw;
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 			/* Copy the data into the message */
2547c478bd9Sstevel@tonic-gate 			ddi_rep_get8(tw->tw_accesshandle,
25522eb7cb5Sgd 			    (uint8_t *)uhci_polledp->uhci_polled_buf,
25622eb7cb5Sgd 			    (uint8_t *)td->tw->tw_buf,
25722eb7cb5Sgd 			    *num_characters, DDI_DEV_AUTOINCR);
2587c478bd9Sstevel@tonic-gate 		}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 		/*
2617c478bd9Sstevel@tonic-gate 		 * Insert the td again into the lattice.
2627c478bd9Sstevel@tonic-gate 		 */
2637c478bd9Sstevel@tonic-gate 		SetTD_dtogg(uhcip, td, GetTD_dtogg(uhcip, td) == 0 ? 1 : 0);
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 		SetTD_status(uhcip, td, UHCI_TD_ACTIVE);
2667c478bd9Sstevel@tonic-gate 		SetQH32(uhcip, uhci_polledp->uhci_polled_qh->element_ptr,
2677c478bd9Sstevel@tonic-gate 		    TD_PADDR(td));
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 		/* Clear the interrupt status register */
2707c478bd9Sstevel@tonic-gate 		intr_status = Get_OpReg16(USBSTS);
2717c478bd9Sstevel@tonic-gate 		Set_OpReg16(USBSTS, intr_status);
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate #ifndef lint
2757c478bd9Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
2767c478bd9Sstevel@tonic-gate #endif
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
28128cdc3d7Sszhou /*
28228cdc3d7Sszhou  * uhci_hcdi_polled_output_init:
28328cdc3d7Sszhou  *	This is the initialization routine for handling the USB serial
28428cdc3d7Sszhou  *	output in POLLED mode.  This routine is called after input_init
28528cdc3d7Sszhou  *	succeeded.
28628cdc3d7Sszhou  */
28728cdc3d7Sszhou int
uhci_hcdi_polled_output_init(usba_pipe_handle_data_t * ph,usb_console_info_impl_t * console_output_info)28828cdc3d7Sszhou uhci_hcdi_polled_output_init(usba_pipe_handle_data_t *ph,
28928cdc3d7Sszhou 	usb_console_info_impl_t *console_output_info)
29028cdc3d7Sszhou {
29128cdc3d7Sszhou 	int		ret;
29228cdc3d7Sszhou 	uhci_polled_t	*uhci_polledp;
29328cdc3d7Sszhou 	uhci_state_t	*uhcip;
29428cdc3d7Sszhou 
29528cdc3d7Sszhou 	uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
29628cdc3d7Sszhou 
29728cdc3d7Sszhou 	/*
29828cdc3d7Sszhou 	 * Grab the uhci_int_mutex so that things don't change on us
29928cdc3d7Sszhou 	 * if an interrupt comes in.
30028cdc3d7Sszhou 	 */
30128cdc3d7Sszhou 	mutex_enter(&uhcip->uhci_int_mutex);
30228cdc3d7Sszhou 	ret = uhci_polled_init(ph, uhcip, console_output_info);
30328cdc3d7Sszhou 	if (ret != USB_SUCCESS) {
30428cdc3d7Sszhou 		mutex_exit(&uhcip->uhci_int_mutex);
30528cdc3d7Sszhou 
30628cdc3d7Sszhou 		return (ret);
30728cdc3d7Sszhou 	}
30828cdc3d7Sszhou 
30928cdc3d7Sszhou 	uhci_polledp = (uhci_polled_t *)console_output_info->uci_private;
31028cdc3d7Sszhou 	/*
31128cdc3d7Sszhou 	 * Mark the structure so that if we are using it, we don't free
31228cdc3d7Sszhou 	 * the structures if one of them is unplugged.
31328cdc3d7Sszhou 	 */
31428cdc3d7Sszhou 	uhci_polledp->uhci_polled_flags |= POLLED_OUTPUT_MODE;
31528cdc3d7Sszhou 
31628cdc3d7Sszhou 	mutex_exit(&uhcip->uhci_int_mutex);
31728cdc3d7Sszhou 
31828cdc3d7Sszhou 	return (USB_SUCCESS);
31928cdc3d7Sszhou }
32028cdc3d7Sszhou 
32128cdc3d7Sszhou 
32228cdc3d7Sszhou /*
32328cdc3d7Sszhou  * uhci_hcdi_polled_output_fini:
32428cdc3d7Sszhou  */
32528cdc3d7Sszhou int
uhci_hcdi_polled_output_fini(usb_console_info_impl_t * info)32628cdc3d7Sszhou uhci_hcdi_polled_output_fini(usb_console_info_impl_t *info)
32728cdc3d7Sszhou {
32828cdc3d7Sszhou 	int			ret;
32928cdc3d7Sszhou 	uhci_state_t		*uhcip;
33028cdc3d7Sszhou 	uhci_polled_t		*uhci_polledp;
33128cdc3d7Sszhou 
33228cdc3d7Sszhou 	uhci_polledp = (uhci_polled_t *)info->uci_private;
33328cdc3d7Sszhou 	uhcip = uhci_polledp->uhci_polled_uhcip;
33428cdc3d7Sszhou 	mutex_enter(&uhcip->uhci_int_mutex);
33528cdc3d7Sszhou 
33628cdc3d7Sszhou 	ret = uhci_polled_fini(uhci_polledp, uhcip);
33728cdc3d7Sszhou 	info->uci_private = NULL;
33828cdc3d7Sszhou 	mutex_exit(&uhcip->uhci_int_mutex);
33928cdc3d7Sszhou 
34028cdc3d7Sszhou 	return (ret);
34128cdc3d7Sszhou }
34228cdc3d7Sszhou 
34328cdc3d7Sszhou 
34428cdc3d7Sszhou /*
34528cdc3d7Sszhou  * uhci_hcdi_polled_output_enter:
34628cdc3d7Sszhou  *	everything is done in input enter
34728cdc3d7Sszhou  */
34828cdc3d7Sszhou int
uhci_hcdi_polled_output_enter(usb_console_info_impl_t * info)34928cdc3d7Sszhou uhci_hcdi_polled_output_enter(usb_console_info_impl_t *info)
35028cdc3d7Sszhou {
35128cdc3d7Sszhou 	uhci_state_t		*uhcip;
35228cdc3d7Sszhou 	uhci_polled_t		*uhci_polledp;
35328cdc3d7Sszhou 
35428cdc3d7Sszhou 	uhci_polledp = (uhci_polled_t *)info->uci_private;
35528cdc3d7Sszhou 	uhcip = uhci_polledp->uhci_polled_uhcip;
35628cdc3d7Sszhou 
35728cdc3d7Sszhou 	/*
35828cdc3d7Sszhou 	 * Check if the number of devices reaches the max number
35928cdc3d7Sszhou 	 * we can support in polled mode
36028cdc3d7Sszhou 	 */
36128cdc3d7Sszhou 	if (uhcip->uhci_polled_count + 1 > MAX_NUM_FOR_KEYBORAD) {
36228cdc3d7Sszhou 
36328cdc3d7Sszhou 		return (USB_FAILURE);
36428cdc3d7Sszhou 	}
36528cdc3d7Sszhou 
36628cdc3d7Sszhou 	return (USB_SUCCESS);
36728cdc3d7Sszhou }
36828cdc3d7Sszhou 
36928cdc3d7Sszhou 
37028cdc3d7Sszhou /*
37128cdc3d7Sszhou  * uhci_hcdi_polled_output_exit:
37228cdc3d7Sszhou  *	everything is done in input exit
37328cdc3d7Sszhou  */
37428cdc3d7Sszhou /*ARGSUSED*/
37528cdc3d7Sszhou int
uhci_hcdi_polled_output_exit(usb_console_info_impl_t * info)37628cdc3d7Sszhou uhci_hcdi_polled_output_exit(usb_console_info_impl_t *info)
37728cdc3d7Sszhou {
37828cdc3d7Sszhou 	return (USB_SUCCESS);
37928cdc3d7Sszhou }
38028cdc3d7Sszhou 
38128cdc3d7Sszhou /*
38228cdc3d7Sszhou  * uhci_hcdi_polled_write:
38328cdc3d7Sszhou  *	Put a key character -- rewrite this!
38428cdc3d7Sszhou  */
38528cdc3d7Sszhou int
uhci_hcdi_polled_write(usb_console_info_impl_t * info,uchar_t * buf,uint_t num_characters,uint_t * num_characters_written)38628cdc3d7Sszhou uhci_hcdi_polled_write(usb_console_info_impl_t *info, uchar_t *buf,
38728cdc3d7Sszhou     uint_t num_characters, uint_t *num_characters_written)
38828cdc3d7Sszhou {
38928cdc3d7Sszhou 	int			i;
39028cdc3d7Sszhou 	uhci_state_t		*uhcip;
39128cdc3d7Sszhou 	uhci_polled_t		*uhci_polledp;
39228cdc3d7Sszhou 	uhci_td_t		*td;
39328cdc3d7Sszhou 	uhci_trans_wrapper_t	*tw;
39428cdc3d7Sszhou 	uhci_pipe_private_t	*pp;
39528cdc3d7Sszhou 	usba_pipe_handle_data_t	*ph;
39628cdc3d7Sszhou 
397fef1e07eSsl #ifndef lint
398fef1e07eSsl 	_NOTE(NO_COMPETING_THREADS_NOW);
399fef1e07eSsl #endif
400fef1e07eSsl 
40128cdc3d7Sszhou 	uhci_polledp = (uhci_polled_t *)info->uci_private;
40228cdc3d7Sszhou 	uhcip = uhci_polledp->uhci_polled_uhcip;
40328cdc3d7Sszhou 	ph = uhci_polledp->uhci_polled_ph;
40428cdc3d7Sszhou 	pp = (uhci_pipe_private_t *)ph->p_hcd_private;
40528cdc3d7Sszhou 
40628cdc3d7Sszhou 	td = uhci_polledp->uhci_polled_td;
40728cdc3d7Sszhou 	tw = td->tw;
40828cdc3d7Sszhou 
40928cdc3d7Sszhou 	/* copy transmit buffer */
41028cdc3d7Sszhou 	if (num_characters > POLLED_RAW_BUF_SIZE) {
41128cdc3d7Sszhou 		cmn_err(CE_NOTE, "polled write size %d bigger than %d",
41228cdc3d7Sszhou 		    num_characters, POLLED_RAW_BUF_SIZE);
41328cdc3d7Sszhou 		num_characters = POLLED_RAW_BUF_SIZE;
41428cdc3d7Sszhou 	}
41528cdc3d7Sszhou 	tw->tw_length = num_characters;
41628cdc3d7Sszhou 	ddi_put8(tw->tw_accesshandle, (uint8_t *)tw->tw_buf, *buf);
41728cdc3d7Sszhou 	ddi_rep_put8(tw->tw_accesshandle, buf, (uint8_t *)tw->tw_buf,
41828cdc3d7Sszhou 	    num_characters, DDI_DEV_AUTOINCR);
41928cdc3d7Sszhou 
42028cdc3d7Sszhou 	bzero((char *)td, sizeof (uhci_td_t));
42128cdc3d7Sszhou 
42228cdc3d7Sszhou 	td->tw = tw;
42328cdc3d7Sszhou 	SetTD_c_err(uhcip, td, UHCI_MAX_ERR_COUNT);
42428cdc3d7Sszhou 	SetTD_status(uhcip, td, UHCI_TD_ACTIVE);
42528cdc3d7Sszhou 	SetTD_ioc(uhcip, td, INTERRUPT_ON_COMPLETION);
42628cdc3d7Sszhou 	SetTD_mlen(uhcip, td, num_characters - 1);
42728cdc3d7Sszhou 	SetTD_dtogg(uhcip, td, pp->pp_data_toggle);
42828cdc3d7Sszhou 	ADJ_DATA_TOGGLE(pp);
42928cdc3d7Sszhou 	SetTD_devaddr(uhcip, td, ph->p_usba_device->usb_addr);
43028cdc3d7Sszhou 	SetTD_endpt(uhcip, td, ph->p_ep.bEndpointAddress &
43122eb7cb5Sgd 	    END_POINT_ADDRESS_MASK);
43228cdc3d7Sszhou 	SetTD_PID(uhcip, td, PID_OUT);
43328cdc3d7Sszhou 	SetTD32(uhcip, td->buffer_address, tw->tw_cookie.dmac_address);
43428cdc3d7Sszhou 
43528cdc3d7Sszhou 	SetQH32(uhcip, uhci_polledp->uhci_polled_qh->element_ptr,
43628cdc3d7Sszhou 	    TD_PADDR(td));
43728cdc3d7Sszhou 
43828cdc3d7Sszhou 	/*
43928cdc3d7Sszhou 	 * Now, add the endpoint to the lattice that we will hang  our
44028cdc3d7Sszhou 	 * TD's off of.
44128cdc3d7Sszhou 	 */
44228cdc3d7Sszhou 	for (i = uhcip->uhci_polled_count; i < NUM_FRAME_LST_ENTRIES;
44328cdc3d7Sszhou 	    i += MIN_LOW_SPEED_POLL_INTERVAL) {
44428cdc3d7Sszhou 		SetFL32(uhcip, uhcip->uhci_frame_lst_tablep[i],
44528cdc3d7Sszhou 		    QH_PADDR(uhci_polledp->uhci_polled_qh) | HC_QUEUE_HEAD);
44628cdc3d7Sszhou 	}
44728cdc3d7Sszhou 
44828cdc3d7Sszhou 	/* wait for xfer to finish */
44928cdc3d7Sszhou 	while (GetTD_status(uhcip, td) & UHCI_TD_ACTIVE)
45028cdc3d7Sszhou #ifndef __sparc
45128cdc3d7Sszhou 		invalidate_cache();
45228cdc3d7Sszhou #else
45328cdc3d7Sszhou 		;
45428cdc3d7Sszhou #endif
45528cdc3d7Sszhou 	*num_characters_written = GetTD_alen(uhcip, td) + 1;
45628cdc3d7Sszhou 
45728cdc3d7Sszhou 	/* Now, remove the endpoint from the lattice */
45828cdc3d7Sszhou 	for (i = uhcip->uhci_polled_count; i < NUM_FRAME_LST_ENTRIES;
45928cdc3d7Sszhou 	    i += MIN_LOW_SPEED_POLL_INTERVAL) {
46028cdc3d7Sszhou 		SetFL32(uhcip, uhcip->uhci_frame_lst_tablep[i],
46128cdc3d7Sszhou 		    HC_END_OF_LIST);
46228cdc3d7Sszhou 	}
46328cdc3d7Sszhou 
464fef1e07eSsl #ifndef lint
465fef1e07eSsl 	_NOTE(COMPETING_THREADS_NOW);
466fef1e07eSsl #endif
467fef1e07eSsl 
46828cdc3d7Sszhou 	return (USB_SUCCESS);
46928cdc3d7Sszhou }
47028cdc3d7Sszhou 
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate /*
4737c478bd9Sstevel@tonic-gate  * uhci_polled_init:
4747c478bd9Sstevel@tonic-gate  *	Initialize generic information that is needed to provide USB/POLLED
4757c478bd9Sstevel@tonic-gate  *	support.
4767c478bd9Sstevel@tonic-gate  */
4777c478bd9Sstevel@tonic-gate static int
uhci_polled_init(usba_pipe_handle_data_t * ph,uhci_state_t * uhcip,usb_console_info_impl_t * console_info)4787c478bd9Sstevel@tonic-gate uhci_polled_init(usba_pipe_handle_data_t	*ph,
4797c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip,
4807c478bd9Sstevel@tonic-gate 	usb_console_info_impl_t	*console_info)
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate 	uhci_polled_t	*uhci_polledp;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	/*
4877c478bd9Sstevel@tonic-gate 	 * If the structure has already been initialized, then we don't
4887c478bd9Sstevel@tonic-gate 	 * need to redo it.
4897c478bd9Sstevel@tonic-gate 	 */
4907c478bd9Sstevel@tonic-gate 	if (console_info->uci_private != NULL) {
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	/* Allocate and intitialize a polled mode state structure */
496*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	uhci_polledp = (uhci_polled_t *)kmem_zalloc(sizeof (uhci_polled_t),
497*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    KM_SLEEP);
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	/*
5007c478bd9Sstevel@tonic-gate 	 * Keep a copy of normal mode state structure and pipe handle.
5017c478bd9Sstevel@tonic-gate 	 */
5027c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_uhcip	= uhcip;
5037c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_ph	= ph;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	/*
5067c478bd9Sstevel@tonic-gate 	 * Allocate a queue head for the device. This queue head wiil be
5077c478bd9Sstevel@tonic-gate 	 * put in action when we switch to polled mode in _enter point.
5087c478bd9Sstevel@tonic-gate 	 */
5097c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_qh = uhci_alloc_queue_head(uhcip);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_qh == NULL) {
5127c478bd9Sstevel@tonic-gate 		kmem_free(uhci_polledp, sizeof (uhci_polled_t));
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	/*
5187c478bd9Sstevel@tonic-gate 	 * Insert a TD onto the queue head.
5197c478bd9Sstevel@tonic-gate 	 */
5207c478bd9Sstevel@tonic-gate 	if ((uhci_polled_insert_td_on_qh(uhci_polledp,
5217c478bd9Sstevel@tonic-gate 	    uhci_polledp->uhci_polled_ph)) != USB_SUCCESS) {
5227c478bd9Sstevel@tonic-gate 		uhci_polledp->uhci_polled_qh->qh_flag = QUEUE_HEAD_FLAG_FREE;
5237c478bd9Sstevel@tonic-gate 		kmem_free(uhci_polledp, sizeof (uhci_polled_t));
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	console_info->uci_private = (usb_console_info_private_t)uhci_polledp;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate /*
5357c478bd9Sstevel@tonic-gate  * uhci_polled_fini:
5367c478bd9Sstevel@tonic-gate  */
5377c478bd9Sstevel@tonic-gate static int
uhci_polled_fini(uhci_polled_t * uhci_polledp,uhci_state_t * uhcip)5387c478bd9Sstevel@tonic-gate uhci_polled_fini(uhci_polled_t *uhci_polledp, uhci_state_t *uhcip)
5397c478bd9Sstevel@tonic-gate {
5407c478bd9Sstevel@tonic-gate 	uhci_td_t	*td = uhci_polledp->uhci_polled_td;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	/*
5457c478bd9Sstevel@tonic-gate 	 * Free the transfer wrapper
5467c478bd9Sstevel@tonic-gate 	 */
5477c478bd9Sstevel@tonic-gate 	uhci_free_tw(uhcip, td->tw);
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	/*
5507c478bd9Sstevel@tonic-gate 	 * Free the queue head and transfer descriptor allocated.
5517c478bd9Sstevel@tonic-gate 	 */
5527c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_qh->qh_flag = QUEUE_HEAD_FLAG_FREE;
5537c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_td->flag = TD_FLAG_FREE;
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	/*
5567c478bd9Sstevel@tonic-gate 	 * Deallocate the memory for the polled mode state structure.
5577c478bd9Sstevel@tonic-gate 	 */
5587c478bd9Sstevel@tonic-gate 	kmem_free(uhci_polledp, sizeof (uhci_polled_t));
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate /*
5657c478bd9Sstevel@tonic-gate  * uhci_polled_save_state:
5667c478bd9Sstevel@tonic-gate  */
5677c478bd9Sstevel@tonic-gate static void
uhci_polled_save_state(uhci_polled_t * uhci_polledp)5687c478bd9Sstevel@tonic-gate uhci_polled_save_state(uhci_polled_t	*uhci_polledp)
5697c478bd9Sstevel@tonic-gate {
5707c478bd9Sstevel@tonic-gate 	int			i;
5717c478bd9Sstevel@tonic-gate 	uhci_td_t		*td, *polled_td;
5727c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip;
5737c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph;
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate #ifndef lint
5767c478bd9Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
5777c478bd9Sstevel@tonic-gate #endif
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	/*
5807c478bd9Sstevel@tonic-gate 	 * If either of these two flags are set, then we have already
5817c478bd9Sstevel@tonic-gate 	 * saved off the state information and setup the controller.
5827c478bd9Sstevel@tonic-gate 	 */
5837c478bd9Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_flags & POLLED_INPUT_MODE_INUSE) {
5847c478bd9Sstevel@tonic-gate #ifndef lint
5857c478bd9Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
5867c478bd9Sstevel@tonic-gate #endif
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 		return;
5897c478bd9Sstevel@tonic-gate 	}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	uhcip = uhci_polledp->uhci_polled_uhcip;
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	/*
5947c478bd9Sstevel@tonic-gate 	 * Check if the number of keyboard reaches the max number we can
5957c478bd9Sstevel@tonic-gate 	 * support in polled mode
5967c478bd9Sstevel@tonic-gate 	 */
5977c478bd9Sstevel@tonic-gate 	if (++ uhcip->uhci_polled_count > MAX_NUM_FOR_KEYBORAD) {
5987c478bd9Sstevel@tonic-gate #ifndef lint
5997c478bd9Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
6007c478bd9Sstevel@tonic-gate #endif
6017c478bd9Sstevel@tonic-gate 		return;
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	/*
6057c478bd9Sstevel@tonic-gate 	 * Get the normal mode usb pipe handle.
6067c478bd9Sstevel@tonic-gate 	 */
6077c478bd9Sstevel@tonic-gate 	ph = (usba_pipe_handle_data_t *)uhci_polledp->uhci_polled_ph;
6087c478bd9Sstevel@tonic-gate 	/*
6097c478bd9Sstevel@tonic-gate 	 * Only the first keyboard enter disable the interrutps, stop the
6107c478bd9Sstevel@tonic-gate 	 * host controller processing and initialize the interrupt table.
6117c478bd9Sstevel@tonic-gate 	 */
6127c478bd9Sstevel@tonic-gate 	if (uhcip->uhci_polled_count == 1) {
6137c478bd9Sstevel@tonic-gate 		/*
6147c478bd9Sstevel@tonic-gate 		 * Disable interrupts to prevent the interrupt handler getting
6157c478bd9Sstevel@tonic-gate 		 * called while we are switing to POLLed mode.
6167c478bd9Sstevel@tonic-gate 		 */
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 		Set_OpReg16(USBINTR, DISABLE_ALL_INTRS);
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 		/*
6217c478bd9Sstevel@tonic-gate 		 * Stop the HC controller from processing TD's
6227c478bd9Sstevel@tonic-gate 		 */
6237c478bd9Sstevel@tonic-gate 		Set_OpReg16(USBCMD, 0);
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 		/*
6267c478bd9Sstevel@tonic-gate 		 * Save the current interrupt lattice and  replace this lattice
6277c478bd9Sstevel@tonic-gate 		 * with an lattice used in POLLED mode. We will restore lattice
6287c478bd9Sstevel@tonic-gate 		 * back when we exit from the POLLED mode.
6297c478bd9Sstevel@tonic-gate 		 */
6307c478bd9Sstevel@tonic-gate 		for (i = 0; i < NUM_FRAME_LST_ENTRIES; i++) {
6317c478bd9Sstevel@tonic-gate 			uhcip->uhci_polled_save_IntTble[i] =
6327c478bd9Sstevel@tonic-gate 			    uhcip->uhci_frame_lst_tablep[i];
6337c478bd9Sstevel@tonic-gate 		}
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 		/*
6367c478bd9Sstevel@tonic-gate 		 * Zero out the entire interrupt lattice tree.
6377c478bd9Sstevel@tonic-gate 		 */
6387c478bd9Sstevel@tonic-gate 		for (i = 0; i < NUM_FRAME_LST_ENTRIES; i++) {
6397c478bd9Sstevel@tonic-gate 			SetFL32(uhcip, uhcip->uhci_frame_lst_tablep[i],
6407c478bd9Sstevel@tonic-gate 			    HC_END_OF_LIST);
6417c478bd9Sstevel@tonic-gate 		}
6427c478bd9Sstevel@tonic-gate 	}
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	/*
64528cdc3d7Sszhou 	 * Now, add the endpoint to the lattice that we will hang  our
6467c478bd9Sstevel@tonic-gate 	 * TD's off of.  We (assume always) need to poll this device at
6477c478bd9Sstevel@tonic-gate 	 * every 8 ms.
6487c478bd9Sstevel@tonic-gate 	 */
6497c478bd9Sstevel@tonic-gate 	for (i = uhcip->uhci_polled_count - 1; i < NUM_FRAME_LST_ENTRIES;
6507c478bd9Sstevel@tonic-gate 	    i += MIN_LOW_SPEED_POLL_INTERVAL) {
6517c478bd9Sstevel@tonic-gate 		SetFL32(uhcip, uhcip->uhci_frame_lst_tablep[i],
6527c478bd9Sstevel@tonic-gate 		    QH_PADDR(uhci_polledp->uhci_polled_qh) | HC_QUEUE_HEAD);
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	/*
6567c478bd9Sstevel@tonic-gate 	 * Adjust the data toggle
6577c478bd9Sstevel@tonic-gate 	 */
6587c478bd9Sstevel@tonic-gate 	td = uhcip->uhci_outst_tds_head;
6597c478bd9Sstevel@tonic-gate 	while (td != NULL) {
6607c478bd9Sstevel@tonic-gate 		if (td->tw->tw_pipe_private->pp_pipe_handle == ph) {
6617c478bd9Sstevel@tonic-gate 			polled_td = uhci_polledp->uhci_polled_td;
6627c478bd9Sstevel@tonic-gate 			if (GetTD_status(uhcip, td) & UHCI_TD_ACTIVE) {
6637c478bd9Sstevel@tonic-gate 				SetTD_dtogg(uhcip, polled_td,
6647c478bd9Sstevel@tonic-gate 				    GetTD_dtogg(uhcip, td));
6657c478bd9Sstevel@tonic-gate 			} else {
6667c478bd9Sstevel@tonic-gate 				SetTD_dtogg(uhcip, polled_td,
6677c478bd9Sstevel@tonic-gate 				    (GetTD_dtogg(uhcip, td) ^ 1));
6687c478bd9Sstevel@tonic-gate 				uhcip->uhci_polled_flag =
6697c478bd9Sstevel@tonic-gate 				    UHCI_POLLED_FLAG_TD_COMPL;
6707c478bd9Sstevel@tonic-gate 			}
6717c478bd9Sstevel@tonic-gate 			break;
6727c478bd9Sstevel@tonic-gate 		}
6737c478bd9Sstevel@tonic-gate 		td = td->outst_td_next;
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 	/*
6767c478bd9Sstevel@tonic-gate 	 * Only the first keyboard enter reset the frame number and start
6777c478bd9Sstevel@tonic-gate 	 * the host controler processing.
6787c478bd9Sstevel@tonic-gate 	 */
6797c478bd9Sstevel@tonic-gate 	if (uhcip->uhci_polled_count == 1) {
6807c478bd9Sstevel@tonic-gate 		/* Set the frame number to zero */
6817c478bd9Sstevel@tonic-gate 		Set_OpReg16(FRNUM, 0);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 		/*
6847c478bd9Sstevel@tonic-gate 		 * Start the Host controller processing
6857c478bd9Sstevel@tonic-gate 		 */
6867c478bd9Sstevel@tonic-gate 		Set_OpReg16(USBCMD, (USBCMD_REG_HC_RUN | USBCMD_REG_MAXPKT_64 |
6877c478bd9Sstevel@tonic-gate 		    USBCMD_REG_CONFIG_FLAG));
6887c478bd9Sstevel@tonic-gate 	}
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate #ifndef lint
6917c478bd9Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
6927c478bd9Sstevel@tonic-gate #endif
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate /*
6977c478bd9Sstevel@tonic-gate  * uhci_polled_restore_state:
6987c478bd9Sstevel@tonic-gate  */
6997c478bd9Sstevel@tonic-gate static void
uhci_polled_restore_state(uhci_polled_t * uhci_polledp)7007c478bd9Sstevel@tonic-gate uhci_polled_restore_state(uhci_polled_t	*uhci_polledp)
7017c478bd9Sstevel@tonic-gate {
7027c478bd9Sstevel@tonic-gate 	int			i;
7037c478bd9Sstevel@tonic-gate 	ushort_t		real_data_toggle;
7047c478bd9Sstevel@tonic-gate 	uhci_td_t		*td, *polled_td;
7057c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip;
7067c478bd9Sstevel@tonic-gate 	uhci_pipe_private_t	*pp;
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate #ifndef lint
7097c478bd9Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
7107c478bd9Sstevel@tonic-gate #endif
7117c478bd9Sstevel@tonic-gate 	/*
7127c478bd9Sstevel@tonic-gate 	 * If this flags is set, then we are still using this structure,
7137c478bd9Sstevel@tonic-gate 	 * so don't restore any controller state information yet.
7147c478bd9Sstevel@tonic-gate 	 */
7157c478bd9Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_flags & POLLED_INPUT_MODE_INUSE) {
7167c478bd9Sstevel@tonic-gate #ifndef lint
7177c478bd9Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
7187c478bd9Sstevel@tonic-gate #endif
7197c478bd9Sstevel@tonic-gate 		return;
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	uhcip = uhci_polledp->uhci_polled_uhcip;
7237c478bd9Sstevel@tonic-gate 	uhcip->uhci_polled_count --;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	/* Just first leave keyboard entry turn off the controller */
7267c478bd9Sstevel@tonic-gate 	if (Get_OpReg16(USBCMD)) {
7277c478bd9Sstevel@tonic-gate 		Set_OpReg16(USBCMD, 0x0);
7287c478bd9Sstevel@tonic-gate 	}
7297c478bd9Sstevel@tonic-gate 	/* Only the last leave keyboard entry restore the interrupt table */
7307c478bd9Sstevel@tonic-gate 	if (uhcip->uhci_polled_count == 0) {
7317c478bd9Sstevel@tonic-gate 		/*
7327c478bd9Sstevel@tonic-gate 		 * Replace the lattice
7337c478bd9Sstevel@tonic-gate 		 */
7347c478bd9Sstevel@tonic-gate 		for (i = 0; i < NUM_FRAME_LST_ENTRIES; i++) {
7357c478bd9Sstevel@tonic-gate 			uhcip->uhci_frame_lst_tablep[i] =
7367c478bd9Sstevel@tonic-gate 			    uhcip->uhci_polled_save_IntTble[i];
7377c478bd9Sstevel@tonic-gate 		}
7387c478bd9Sstevel@tonic-gate 	}
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	/*
7417c478bd9Sstevel@tonic-gate 	 * Adjust data toggle
7427c478bd9Sstevel@tonic-gate 	 */
7437c478bd9Sstevel@tonic-gate 	pp = (uhci_pipe_private_t *)
74422eb7cb5Sgd 	    uhci_polledp->uhci_polled_ph->p_hcd_private;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	polled_td = uhci_polledp->uhci_polled_td;
7477c478bd9Sstevel@tonic-gate 	real_data_toggle = (GetTD_status(uhcip, polled_td) & UHCI_TD_ACTIVE) ?
74822eb7cb5Sgd 	    GetTD_dtogg(uhcip, polled_td) :
74922eb7cb5Sgd 	    !GetTD_dtogg(uhcip, polled_td);
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	td = uhcip->uhci_outst_tds_head;
7527c478bd9Sstevel@tonic-gate 	while (td != NULL) {
7537c478bd9Sstevel@tonic-gate 		if (td->tw->tw_pipe_private->pp_pipe_handle ==
7547c478bd9Sstevel@tonic-gate 		    uhci_polledp->uhci_polled_ph) {
7557c478bd9Sstevel@tonic-gate 			if (GetTD_status(uhcip, td) & UHCI_TD_ACTIVE) {
7567c478bd9Sstevel@tonic-gate 				SetTD_dtogg(uhcip, td, real_data_toggle);
7577c478bd9Sstevel@tonic-gate 				pp->pp_data_toggle =
7587c478bd9Sstevel@tonic-gate 				    (real_data_toggle == 0) ? 1 : 0;
7597c478bd9Sstevel@tonic-gate 			} else {
760*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				pp->pp_data_toggle = (uchar_t)real_data_toggle;
7617c478bd9Sstevel@tonic-gate 			}
7627c478bd9Sstevel@tonic-gate 		}
7637c478bd9Sstevel@tonic-gate 		td = td->outst_td_next;
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	/*
7677c478bd9Sstevel@tonic-gate 	 * Only the last leave keyboard entry enable the interrupts,
7687c478bd9Sstevel@tonic-gate 	 * start Host controller processing.
7697c478bd9Sstevel@tonic-gate 	 */
7707c478bd9Sstevel@tonic-gate 	if (uhcip->uhci_polled_count == 0) {
7717c478bd9Sstevel@tonic-gate 		Set_OpReg16(USBINTR, ENABLE_ALL_INTRS);
7727c478bd9Sstevel@tonic-gate 		Set_OpReg16(USBCMD, (USBCMD_REG_HC_RUN | USBCMD_REG_MAXPKT_64 |
7737c478bd9Sstevel@tonic-gate 		    USBCMD_REG_CONFIG_FLAG));
7747c478bd9Sstevel@tonic-gate 		if (uhcip->uhci_polled_flag == UHCI_POLLED_FLAG_TD_COMPL) {
7757c478bd9Sstevel@tonic-gate 			uhcip->uhci_polled_flag = UHCI_POLLED_FLAG_TRUE;
7767c478bd9Sstevel@tonic-gate 		}
7777c478bd9Sstevel@tonic-gate 	}
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate #ifndef lint
7807c478bd9Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
7817c478bd9Sstevel@tonic-gate #endif
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate /*
7867c478bd9Sstevel@tonic-gate  * uhci_polled_insert_td:
7877c478bd9Sstevel@tonic-gate  *	Initializes the transfer descriptor for polling and inserts on the
7887c478bd9Sstevel@tonic-gate  *	polled queue head. This will be put in action when entered in to
7897c478bd9Sstevel@tonic-gate  *	polled mode.
7907c478bd9Sstevel@tonic-gate  */
7917c478bd9Sstevel@tonic-gate static int
uhci_polled_insert_td_on_qh(uhci_polled_t * uhci_polledp,usba_pipe_handle_data_t * ph)7927c478bd9Sstevel@tonic-gate uhci_polled_insert_td_on_qh(uhci_polled_t *uhci_polledp,
7937c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph)
7947c478bd9Sstevel@tonic-gate {
7957c478bd9Sstevel@tonic-gate 	uhci_td_t		*td;
7967c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip = uhci_polledp->uhci_polled_uhcip;
7977c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd;
7987c478bd9Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw;
79928cdc3d7Sszhou 	uint_t			direction;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	/* Create the transfer wrapper */
8027c478bd9Sstevel@tonic-gate 	if ((tw = uhci_polled_create_tw(uhci_polledp->uhci_polled_uhcip)) ==
8037c478bd9Sstevel@tonic-gate 	    NULL) {
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	/* Use the dummy TD allocated for the queue head */
8097c478bd9Sstevel@tonic-gate 	td = uhci_polledp->uhci_polled_qh->td_tailp;
8107c478bd9Sstevel@tonic-gate 	bzero((char *)td, sizeof (uhci_td_t));
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	uhci_polledp->uhci_polled_td = td;
8137c478bd9Sstevel@tonic-gate 	td->tw = tw;
8147c478bd9Sstevel@tonic-gate 	td->flag = TD_FLAG_BUSY;
8157c478bd9Sstevel@tonic-gate 	SetTD32(uhcip, td->link_ptr, HC_END_OF_LIST);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	mutex_enter(&ph->p_usba_device->usb_mutex);
8187c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
8197c478bd9Sstevel@tonic-gate 		SetTD_ls(uhcip, td, LOW_SPEED_DEVICE);
8207c478bd9Sstevel@tonic-gate 	}
8217c478bd9Sstevel@tonic-gate 
82228cdc3d7Sszhou 	eptd = &ph->p_ep;
82328cdc3d7Sszhou 	direction = (UHCI_XFER_DIR(eptd) == USB_EP_DIR_OUT) ? PID_OUT : PID_IN;
8247c478bd9Sstevel@tonic-gate 	SetTD_c_err(uhcip, td, UHCI_MAX_ERR_COUNT);
82528cdc3d7Sszhou 	SetTD_mlen(uhcip, td, POLLED_RAW_BUF_SIZE - 1);
8267c478bd9Sstevel@tonic-gate 	SetTD_devaddr(uhcip, td, ph->p_usba_device->usb_addr);
8277c478bd9Sstevel@tonic-gate 	SetTD_endpt(uhcip, td, eptd->bEndpointAddress & END_POINT_ADDRESS_MASK);
82828cdc3d7Sszhou 	SetTD_PID(uhcip, td, direction);
8297c478bd9Sstevel@tonic-gate 	SetTD32(uhcip, td->buffer_address, tw->tw_cookie.dmac_address);
8307c478bd9Sstevel@tonic-gate 	SetTD_ioc(uhcip, td, INTERRUPT_ON_COMPLETION);
8317c478bd9Sstevel@tonic-gate 	SetTD_status(uhcip, td, UHCI_TD_ACTIVE);
8327c478bd9Sstevel@tonic-gate 	mutex_exit(&ph->p_usba_device->usb_mutex);
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	SetQH32(uhcip, uhci_polledp->uhci_polled_qh->element_ptr, TD_PADDR(td));
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
8377c478bd9Sstevel@tonic-gate }
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate /*
8417c478bd9Sstevel@tonic-gate  * uhci_polled_create_wrapper_t:
8427c478bd9Sstevel@tonic-gate  *	Creates the transfer wrapper used in polled mode.
8437c478bd9Sstevel@tonic-gate  */
8447c478bd9Sstevel@tonic-gate static uhci_trans_wrapper_t *
uhci_polled_create_tw(uhci_state_t * uhcip)8457c478bd9Sstevel@tonic-gate uhci_polled_create_tw(uhci_state_t *uhcip)
8467c478bd9Sstevel@tonic-gate {
8477c478bd9Sstevel@tonic-gate 	uint_t			result, ccount;
8487c478bd9Sstevel@tonic-gate 	size_t			real_length;
8497c478bd9Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw;
8507c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t	dev_attr;
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	/* Allocate space for the transfer wrapper */
8537c478bd9Sstevel@tonic-gate 	if ((tw = kmem_zalloc(sizeof (uhci_trans_wrapper_t), KM_NOSLEEP)) ==
8547c478bd9Sstevel@tonic-gate 	    NULL) {
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 		return (NULL);
8577c478bd9Sstevel@tonic-gate 	}
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	tw->tw_length = POLLED_RAW_BUF_SIZE;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	/* Allocate the DMA handle */
8627c478bd9Sstevel@tonic-gate 	if ((result = ddi_dma_alloc_handle(uhcip->uhci_dip,
8637c478bd9Sstevel@tonic-gate 	    &uhcip->uhci_dma_attr, DDI_DMA_DONTWAIT, 0, &tw->tw_dmahandle)) !=
8647c478bd9Sstevel@tonic-gate 	    DDI_SUCCESS) {
8657c478bd9Sstevel@tonic-gate 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 		return (NULL);
8687c478bd9Sstevel@tonic-gate 	}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_version		= DDI_DEVICE_ATTR_V0;
8717c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags	= DDI_STRUCTURE_LE_ACC;
8727c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder		= DDI_STRICTORDER_ACC;
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	/* Allocate the memory */
8757c478bd9Sstevel@tonic-gate 	if ((result = ddi_dma_mem_alloc(tw->tw_dmahandle, POLLED_RAW_BUF_SIZE,
8767c478bd9Sstevel@tonic-gate 	    &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
8777c478bd9Sstevel@tonic-gate 	    &tw->tw_buf, &real_length, &tw->tw_accesshandle)) !=
8787c478bd9Sstevel@tonic-gate 	    DDI_SUCCESS) {
8797c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&tw->tw_dmahandle);
8807c478bd9Sstevel@tonic-gate 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 		return (NULL);
8837c478bd9Sstevel@tonic-gate 	}
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	/* Bind the handle */
8867c478bd9Sstevel@tonic-gate 	if ((result = ddi_dma_addr_bind_handle(tw->tw_dmahandle, NULL,
8877c478bd9Sstevel@tonic-gate 	    tw->tw_buf, real_length, DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
8887c478bd9Sstevel@tonic-gate 	    DDI_DMA_DONTWAIT, NULL, &tw->tw_cookie, &ccount)) !=
8897c478bd9Sstevel@tonic-gate 	    DDI_DMA_MAPPED) {
8907c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&tw->tw_accesshandle);
8917c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&tw->tw_dmahandle);
8927c478bd9Sstevel@tonic-gate 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 		return (NULL);
8957c478bd9Sstevel@tonic-gate 	}
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	/* The cookie count should be 1 */
8987c478bd9Sstevel@tonic-gate 	if (ccount != 1) {
8997c478bd9Sstevel@tonic-gate 		result = ddi_dma_unbind_handle(tw->tw_dmahandle);
9007c478bd9Sstevel@tonic-gate 		ASSERT(result == DDI_SUCCESS);
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&tw->tw_accesshandle);
9037c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&tw->tw_dmahandle);
9047c478bd9Sstevel@tonic-gate 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 		return (NULL);
9077c478bd9Sstevel@tonic-gate 	}
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	return (tw);
9107c478bd9Sstevel@tonic-gate }
911