xref: /onnv-gate/usr/src/uts/common/io/usb/hcd/uhci/uhcipolled.c (revision 7492:2387323b838f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52191Sszhou  * Common Development and Distribution License (the "License").
62191Sszhou  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
226990Sgd78059  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * This module contains the specific uhci code used in POLLED mode.
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcid.h>
310Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcipolled.h>
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #ifndef __sparc
340Sstevel@tonic-gate extern void invalidate_cache();
350Sstevel@tonic-gate #endif
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate  * Internal Function Prototypes
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate /* Polled initialization routine */
400Sstevel@tonic-gate static int	uhci_polled_init(usba_pipe_handle_data_t *, uhci_state_t *,
410Sstevel@tonic-gate 		    usb_console_info_impl_t *);
420Sstevel@tonic-gate 
430Sstevel@tonic-gate /* Polled fini routine */
440Sstevel@tonic-gate static int	uhci_polled_fini(uhci_polled_t *, uhci_state_t *);
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /* Polled save state routine */
470Sstevel@tonic-gate static void	uhci_polled_save_state(uhci_polled_t *);
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /* Polled restore state routine */
500Sstevel@tonic-gate static void	uhci_polled_restore_state(uhci_polled_t *);
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /* Polled read routines */
530Sstevel@tonic-gate static int	uhci_polled_insert_td_on_qh(uhci_polled_t *,
540Sstevel@tonic-gate 		    usba_pipe_handle_data_t *);
550Sstevel@tonic-gate static uhci_trans_wrapper_t
560Sstevel@tonic-gate 		*uhci_polled_create_tw(uhci_state_t *);
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate  * POLLED entry points
610Sstevel@tonic-gate  *
620Sstevel@tonic-gate  * These functions are entry points into the POLLED code.
630Sstevel@tonic-gate  */
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate  * uhci_hcdi_polled_input_init:
670Sstevel@tonic-gate  *	This is the initialization routine for handling the USB keyboard
680Sstevel@tonic-gate  *	in POLLED mode.  This routine is not called from POLLED mode, so
690Sstevel@tonic-gate  *	it is OK to acquire mutexes.
700Sstevel@tonic-gate  */
710Sstevel@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)720Sstevel@tonic-gate uhci_hcdi_polled_input_init(usba_pipe_handle_data_t *ph,
730Sstevel@tonic-gate 	uchar_t			**polled_buf,
740Sstevel@tonic-gate 	usb_console_info_impl_t *console_input_info)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	int		ret;
770Sstevel@tonic-gate 	uhci_polled_t	*uhci_polledp;
780Sstevel@tonic-gate 	uhci_state_t	*uhcip;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	/*
830Sstevel@tonic-gate 	 * Grab the uhci_int_mutex so that things don't change on us
840Sstevel@tonic-gate 	 * if an interrupt comes in.
850Sstevel@tonic-gate 	 */
860Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
870Sstevel@tonic-gate 	ret = uhci_polled_init(ph, uhcip, console_input_info);
880Sstevel@tonic-gate 	if (ret != USB_SUCCESS) {
890Sstevel@tonic-gate 		mutex_exit(&uhcip->uhci_int_mutex);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 		return (ret);
920Sstevel@tonic-gate 	}
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	uhci_polledp = (uhci_polled_t *)console_input_info->uci_private;
950Sstevel@tonic-gate 	/*
960Sstevel@tonic-gate 	 * Mark the structure so that if we are using it, we don't free
970Sstevel@tonic-gate 	 * the structures if one of them is unplugged.
980Sstevel@tonic-gate 	 */
990Sstevel@tonic-gate 	uhci_polledp->uhci_polled_flags |= POLLED_INPUT_MODE;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	/*
1020Sstevel@tonic-gate 	 * This is the buffer we will copy characters into. It will be
1030Sstevel@tonic-gate 	 * copied into at this layer, so we need to keep track of it.
1040Sstevel@tonic-gate 	 */
1050Sstevel@tonic-gate 	uhci_polledp->uhci_polled_buf =
1066990Sgd78059 	    (uchar_t *)kmem_zalloc(POLLED_RAW_BUF_SIZE, KM_SLEEP);
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	*polled_buf = uhci_polledp->uhci_polled_buf;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
1110Sstevel@tonic-gate 	return (USB_SUCCESS);
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate  * uhci_hcdi_polled_input_fini:
1170Sstevel@tonic-gate  */
1180Sstevel@tonic-gate int
uhci_hcdi_polled_input_fini(usb_console_info_impl_t * info)1190Sstevel@tonic-gate uhci_hcdi_polled_input_fini(usb_console_info_impl_t *info)
1200Sstevel@tonic-gate {
1210Sstevel@tonic-gate 	int			ret;
1220Sstevel@tonic-gate 	uhci_state_t		*uhcip;
1230Sstevel@tonic-gate 	uhci_polled_t		*uhci_polledp;
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	uhci_polledp = (uhci_polled_t *)info->uci_private;
1260Sstevel@tonic-gate 	uhcip = uhci_polledp->uhci_polled_uhcip;
1270Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	/* Free the buffer that we copied data into */
1300Sstevel@tonic-gate 	kmem_free(uhci_polledp->uhci_polled_buf, POLLED_RAW_BUF_SIZE);
1310Sstevel@tonic-gate 	ret = uhci_polled_fini(uhci_polledp, uhcip);
1320Sstevel@tonic-gate 	info->uci_private = NULL;
1330Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	return (ret);
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate  * uhci_hcdi_polled_input_enter:
1410Sstevel@tonic-gate  *	This is where we enter into POLLED mode.  This routine sets up
1420Sstevel@tonic-gate  *	everything so that calls to  uhci_hcdi_polled_read will return
1430Sstevel@tonic-gate  *	characters.
1440Sstevel@tonic-gate  */
1450Sstevel@tonic-gate int
uhci_hcdi_polled_input_enter(usb_console_info_impl_t * info)1460Sstevel@tonic-gate uhci_hcdi_polled_input_enter(usb_console_info_impl_t *info)
1470Sstevel@tonic-gate {
1480Sstevel@tonic-gate 	uhci_polled_t	*uhci_polledp;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	uhci_polledp = (uhci_polled_t *)info->uci_private;
1510Sstevel@tonic-gate 	uhci_polledp->uhci_polled_entry++;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	/*
1540Sstevel@tonic-gate 	 * If the controller is already switched over, just return
1550Sstevel@tonic-gate 	 */
1560Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_entry > 1) {
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 		return (USB_SUCCESS);
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	uhci_polled_save_state(uhci_polledp);
1620Sstevel@tonic-gate 	uhci_polledp->uhci_polled_flags |= POLLED_INPUT_MODE_INUSE;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	return (USB_SUCCESS);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate /*
1690Sstevel@tonic-gate  * uhci_hcdi_polled_input_exit:
1700Sstevel@tonic-gate  *	This is where we exit POLLED mode. This routine restores
1710Sstevel@tonic-gate  *	everything that is needed to continue operation.
1720Sstevel@tonic-gate  */
1730Sstevel@tonic-gate int
uhci_hcdi_polled_input_exit(usb_console_info_impl_t * info)1740Sstevel@tonic-gate uhci_hcdi_polled_input_exit(usb_console_info_impl_t *info)
1750Sstevel@tonic-gate {
1760Sstevel@tonic-gate 	uhci_polled_t	*uhci_polledp;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	uhci_polledp = (uhci_polled_t *)info->uci_private;
1790Sstevel@tonic-gate 	uhci_polledp->uhci_polled_entry--;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	/*
1820Sstevel@tonic-gate 	 * If there are still outstanding "enters", just return
1830Sstevel@tonic-gate 	 */
1840Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_entry > 0) {
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 		return (USB_SUCCESS);
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	uhci_polledp->uhci_polled_flags &= ~POLLED_INPUT_MODE_INUSE;
1900Sstevel@tonic-gate 	uhci_polled_restore_state(uhci_polledp);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	return (USB_SUCCESS);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate /*
1970Sstevel@tonic-gate  * uhci_hcdi_polled_read:
1980Sstevel@tonic-gate  *	Get a key character
1990Sstevel@tonic-gate  */
2000Sstevel@tonic-gate int
uhci_hcdi_polled_read(usb_console_info_impl_t * info,uint_t * num_characters)2010Sstevel@tonic-gate uhci_hcdi_polled_read(usb_console_info_impl_t *info, uint_t *num_characters)
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate 	uhci_state_t		*uhcip;
2040Sstevel@tonic-gate 	uhci_polled_t		*uhci_polledp;
2050Sstevel@tonic-gate 	uhci_td_t		*td;
2060Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw;
2070Sstevel@tonic-gate 	ushort_t		intr_status;
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	uhci_polledp = (uhci_polled_t *)info->uci_private;
2100Sstevel@tonic-gate 	uhcip = uhci_polledp->uhci_polled_uhcip;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	/*
2130Sstevel@tonic-gate 	 * This is a temporary work around for halt problem. The upper
2140Sstevel@tonic-gate 	 * layer code does not call the right sequence of entry points
2150Sstevel@tonic-gate 	 * points for reading a character in a polled mode. Once the
2160Sstevel@tonic-gate 	 * upper layer code is fixed, the following code (two lines)
2170Sstevel@tonic-gate 	 * must be removed.
2180Sstevel@tonic-gate 	 */
2190Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_entry == 0) {
2200Sstevel@tonic-gate 		if (uhci_hcdi_polled_input_enter(info) != USB_SUCCESS) {
2210Sstevel@tonic-gate 			cmn_err(CE_WARN, "Entering Polled Mode failed");
2220Sstevel@tonic-gate 		}
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate #ifndef lint
2260Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
2270Sstevel@tonic-gate #endif
2280Sstevel@tonic-gate #ifndef __sparc
2290Sstevel@tonic-gate 	invalidate_cache();
2300Sstevel@tonic-gate #endif
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	td = uhci_polledp->uhci_polled_td;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	/*
2350Sstevel@tonic-gate 	 * Check to see if there are any TD's on the done head.
2360Sstevel@tonic-gate 	 */
2370Sstevel@tonic-gate 	if (GetTD_status(uhcip, td) & UHCI_TD_ACTIVE) {
2380Sstevel@tonic-gate 		*num_characters = 0;
2390Sstevel@tonic-gate 	} else {
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 		/*
2420Sstevel@tonic-gate 		 * If the TD does not complete, retry.
2430Sstevel@tonic-gate 		 */
2440Sstevel@tonic-gate 		if ((GetTD_status(uhcip, td) & TD_STATUS_MASK) ||
2450Sstevel@tonic-gate 		    (GetTD_alen(uhcip, td) == ZERO_LENGTH)) {
2460Sstevel@tonic-gate 			*num_characters = 0;
2470Sstevel@tonic-gate 			SetTD_alen(uhcip, td, 0);
2480Sstevel@tonic-gate 		} else {
2490Sstevel@tonic-gate 			*num_characters = GetTD_alen(uhcip, td) + 1;
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 			tw = td->tw;
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 			/* Copy the data into the message */
2540Sstevel@tonic-gate 			ddi_rep_get8(tw->tw_accesshandle,
2556990Sgd78059 			    (uint8_t *)uhci_polledp->uhci_polled_buf,
2566990Sgd78059 			    (uint8_t *)td->tw->tw_buf,
2576990Sgd78059 			    *num_characters, DDI_DEV_AUTOINCR);
2580Sstevel@tonic-gate 		}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 		/*
2610Sstevel@tonic-gate 		 * Insert the td again into the lattice.
2620Sstevel@tonic-gate 		 */
2630Sstevel@tonic-gate 		SetTD_dtogg(uhcip, td, GetTD_dtogg(uhcip, td) == 0 ? 1 : 0);
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 		SetTD_status(uhcip, td, UHCI_TD_ACTIVE);
2660Sstevel@tonic-gate 		SetQH32(uhcip, uhci_polledp->uhci_polled_qh->element_ptr,
2670Sstevel@tonic-gate 		    TD_PADDR(td));
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 		/* Clear the interrupt status register */
2700Sstevel@tonic-gate 		intr_status = Get_OpReg16(USBSTS);
2710Sstevel@tonic-gate 		Set_OpReg16(USBSTS, intr_status);
2720Sstevel@tonic-gate 	}
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate #ifndef lint
2750Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
2760Sstevel@tonic-gate #endif
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	return (USB_SUCCESS);
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate 
2812191Sszhou /*
2822191Sszhou  * uhci_hcdi_polled_output_init:
2832191Sszhou  *	This is the initialization routine for handling the USB serial
2842191Sszhou  *	output in POLLED mode.  This routine is called after input_init
2852191Sszhou  *	succeeded.
2862191Sszhou  */
2872191Sszhou int
uhci_hcdi_polled_output_init(usba_pipe_handle_data_t * ph,usb_console_info_impl_t * console_output_info)2882191Sszhou uhci_hcdi_polled_output_init(usba_pipe_handle_data_t *ph,
2892191Sszhou 	usb_console_info_impl_t *console_output_info)
2902191Sszhou {
2912191Sszhou 	int		ret;
2922191Sszhou 	uhci_polled_t	*uhci_polledp;
2932191Sszhou 	uhci_state_t	*uhcip;
2942191Sszhou 
2952191Sszhou 	uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
2962191Sszhou 
2972191Sszhou 	/*
2982191Sszhou 	 * Grab the uhci_int_mutex so that things don't change on us
2992191Sszhou 	 * if an interrupt comes in.
3002191Sszhou 	 */
3012191Sszhou 	mutex_enter(&uhcip->uhci_int_mutex);
3022191Sszhou 	ret = uhci_polled_init(ph, uhcip, console_output_info);
3032191Sszhou 	if (ret != USB_SUCCESS) {
3042191Sszhou 		mutex_exit(&uhcip->uhci_int_mutex);
3052191Sszhou 
3062191Sszhou 		return (ret);
3072191Sszhou 	}
3082191Sszhou 
3092191Sszhou 	uhci_polledp = (uhci_polled_t *)console_output_info->uci_private;
3102191Sszhou 	/*
3112191Sszhou 	 * Mark the structure so that if we are using it, we don't free
3122191Sszhou 	 * the structures if one of them is unplugged.
3132191Sszhou 	 */
3142191Sszhou 	uhci_polledp->uhci_polled_flags |= POLLED_OUTPUT_MODE;
3152191Sszhou 
3162191Sszhou 	mutex_exit(&uhcip->uhci_int_mutex);
3172191Sszhou 
3182191Sszhou 	return (USB_SUCCESS);
3192191Sszhou }
3202191Sszhou 
3212191Sszhou 
3222191Sszhou /*
3232191Sszhou  * uhci_hcdi_polled_output_fini:
3242191Sszhou  */
3252191Sszhou int
uhci_hcdi_polled_output_fini(usb_console_info_impl_t * info)3262191Sszhou uhci_hcdi_polled_output_fini(usb_console_info_impl_t *info)
3272191Sszhou {
3282191Sszhou 	int			ret;
3292191Sszhou 	uhci_state_t		*uhcip;
3302191Sszhou 	uhci_polled_t		*uhci_polledp;
3312191Sszhou 
3322191Sszhou 	uhci_polledp = (uhci_polled_t *)info->uci_private;
3332191Sszhou 	uhcip = uhci_polledp->uhci_polled_uhcip;
3342191Sszhou 	mutex_enter(&uhcip->uhci_int_mutex);
3352191Sszhou 
3362191Sszhou 	ret = uhci_polled_fini(uhci_polledp, uhcip);
3372191Sszhou 	info->uci_private = NULL;
3382191Sszhou 	mutex_exit(&uhcip->uhci_int_mutex);
3392191Sszhou 
3402191Sszhou 	return (ret);
3412191Sszhou }
3422191Sszhou 
3432191Sszhou 
3442191Sszhou /*
3452191Sszhou  * uhci_hcdi_polled_output_enter:
3462191Sszhou  *	everything is done in input enter
3472191Sszhou  */
3482191Sszhou int
uhci_hcdi_polled_output_enter(usb_console_info_impl_t * info)3492191Sszhou uhci_hcdi_polled_output_enter(usb_console_info_impl_t *info)
3502191Sszhou {
3512191Sszhou 	uhci_state_t		*uhcip;
3522191Sszhou 	uhci_polled_t		*uhci_polledp;
3532191Sszhou 
3542191Sszhou 	uhci_polledp = (uhci_polled_t *)info->uci_private;
3552191Sszhou 	uhcip = uhci_polledp->uhci_polled_uhcip;
3562191Sszhou 
3572191Sszhou 	/*
3582191Sszhou 	 * Check if the number of devices reaches the max number
3592191Sszhou 	 * we can support in polled mode
3602191Sszhou 	 */
3612191Sszhou 	if (uhcip->uhci_polled_count + 1 > MAX_NUM_FOR_KEYBORAD) {
3622191Sszhou 
3632191Sszhou 		return (USB_FAILURE);
3642191Sszhou 	}
3652191Sszhou 
3662191Sszhou 	return (USB_SUCCESS);
3672191Sszhou }
3682191Sszhou 
3692191Sszhou 
3702191Sszhou /*
3712191Sszhou  * uhci_hcdi_polled_output_exit:
3722191Sszhou  *	everything is done in input exit
3732191Sszhou  */
3742191Sszhou /*ARGSUSED*/
3752191Sszhou int
uhci_hcdi_polled_output_exit(usb_console_info_impl_t * info)3762191Sszhou uhci_hcdi_polled_output_exit(usb_console_info_impl_t *info)
3772191Sszhou {
3782191Sszhou 	return (USB_SUCCESS);
3792191Sszhou }
3802191Sszhou 
3812191Sszhou /*
3822191Sszhou  * uhci_hcdi_polled_write:
3832191Sszhou  *	Put a key character -- rewrite this!
3842191Sszhou  */
3852191Sszhou int
uhci_hcdi_polled_write(usb_console_info_impl_t * info,uchar_t * buf,uint_t num_characters,uint_t * num_characters_written)3862191Sszhou uhci_hcdi_polled_write(usb_console_info_impl_t *info, uchar_t *buf,
3872191Sszhou     uint_t num_characters, uint_t *num_characters_written)
3882191Sszhou {
3892191Sszhou 	int			i;
3902191Sszhou 	uhci_state_t		*uhcip;
3912191Sszhou 	uhci_polled_t		*uhci_polledp;
3922191Sszhou 	uhci_td_t		*td;
3932191Sszhou 	uhci_trans_wrapper_t	*tw;
3942191Sszhou 	uhci_pipe_private_t	*pp;
3952191Sszhou 	usba_pipe_handle_data_t	*ph;
3962191Sszhou 
3972326Ssl147100 #ifndef lint
3982326Ssl147100 	_NOTE(NO_COMPETING_THREADS_NOW);
3992326Ssl147100 #endif
4002326Ssl147100 
4012191Sszhou 	uhci_polledp = (uhci_polled_t *)info->uci_private;
4022191Sszhou 	uhcip = uhci_polledp->uhci_polled_uhcip;
4032191Sszhou 	ph = uhci_polledp->uhci_polled_ph;
4042191Sszhou 	pp = (uhci_pipe_private_t *)ph->p_hcd_private;
4052191Sszhou 
4062191Sszhou 	td = uhci_polledp->uhci_polled_td;
4072191Sszhou 	tw = td->tw;
4082191Sszhou 
4092191Sszhou 	/* copy transmit buffer */
4102191Sszhou 	if (num_characters > POLLED_RAW_BUF_SIZE) {
4112191Sszhou 		cmn_err(CE_NOTE, "polled write size %d bigger than %d",
4122191Sszhou 		    num_characters, POLLED_RAW_BUF_SIZE);
4132191Sszhou 		num_characters = POLLED_RAW_BUF_SIZE;
4142191Sszhou 	}
4152191Sszhou 	tw->tw_length = num_characters;
4162191Sszhou 	ddi_put8(tw->tw_accesshandle, (uint8_t *)tw->tw_buf, *buf);
4172191Sszhou 	ddi_rep_put8(tw->tw_accesshandle, buf, (uint8_t *)tw->tw_buf,
4182191Sszhou 	    num_characters, DDI_DEV_AUTOINCR);
4192191Sszhou 
4202191Sszhou 	bzero((char *)td, sizeof (uhci_td_t));
4212191Sszhou 
4222191Sszhou 	td->tw = tw;
4232191Sszhou 	SetTD_c_err(uhcip, td, UHCI_MAX_ERR_COUNT);
4242191Sszhou 	SetTD_status(uhcip, td, UHCI_TD_ACTIVE);
4252191Sszhou 	SetTD_ioc(uhcip, td, INTERRUPT_ON_COMPLETION);
4262191Sszhou 	SetTD_mlen(uhcip, td, num_characters - 1);
4272191Sszhou 	SetTD_dtogg(uhcip, td, pp->pp_data_toggle);
4282191Sszhou 	ADJ_DATA_TOGGLE(pp);
4292191Sszhou 	SetTD_devaddr(uhcip, td, ph->p_usba_device->usb_addr);
4302191Sszhou 	SetTD_endpt(uhcip, td, ph->p_ep.bEndpointAddress &
4316990Sgd78059 	    END_POINT_ADDRESS_MASK);
4322191Sszhou 	SetTD_PID(uhcip, td, PID_OUT);
4332191Sszhou 	SetTD32(uhcip, td->buffer_address, tw->tw_cookie.dmac_address);
4342191Sszhou 
4352191Sszhou 	SetQH32(uhcip, uhci_polledp->uhci_polled_qh->element_ptr,
4362191Sszhou 	    TD_PADDR(td));
4372191Sszhou 
4382191Sszhou 	/*
4392191Sszhou 	 * Now, add the endpoint to the lattice that we will hang  our
4402191Sszhou 	 * TD's off of.
4412191Sszhou 	 */
4422191Sszhou 	for (i = uhcip->uhci_polled_count; i < NUM_FRAME_LST_ENTRIES;
4432191Sszhou 	    i += MIN_LOW_SPEED_POLL_INTERVAL) {
4442191Sszhou 		SetFL32(uhcip, uhcip->uhci_frame_lst_tablep[i],
4452191Sszhou 		    QH_PADDR(uhci_polledp->uhci_polled_qh) | HC_QUEUE_HEAD);
4462191Sszhou 	}
4472191Sszhou 
4482191Sszhou 	/* wait for xfer to finish */
4492191Sszhou 	while (GetTD_status(uhcip, td) & UHCI_TD_ACTIVE)
4502191Sszhou #ifndef __sparc
4512191Sszhou 		invalidate_cache();
4522191Sszhou #else
4532191Sszhou 		;
4542191Sszhou #endif
4552191Sszhou 	*num_characters_written = GetTD_alen(uhcip, td) + 1;
4562191Sszhou 
4572191Sszhou 	/* Now, remove the endpoint from the lattice */
4582191Sszhou 	for (i = uhcip->uhci_polled_count; i < NUM_FRAME_LST_ENTRIES;
4592191Sszhou 	    i += MIN_LOW_SPEED_POLL_INTERVAL) {
4602191Sszhou 		SetFL32(uhcip, uhcip->uhci_frame_lst_tablep[i],
4612191Sszhou 		    HC_END_OF_LIST);
4622191Sszhou 	}
4632191Sszhou 
4642326Ssl147100 #ifndef lint
4652326Ssl147100 	_NOTE(COMPETING_THREADS_NOW);
4662326Ssl147100 #endif
4672326Ssl147100 
4682191Sszhou 	return (USB_SUCCESS);
4692191Sszhou }
4702191Sszhou 
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate /*
4730Sstevel@tonic-gate  * uhci_polled_init:
4740Sstevel@tonic-gate  *	Initialize generic information that is needed to provide USB/POLLED
4750Sstevel@tonic-gate  *	support.
4760Sstevel@tonic-gate  */
4770Sstevel@tonic-gate static int
uhci_polled_init(usba_pipe_handle_data_t * ph,uhci_state_t * uhcip,usb_console_info_impl_t * console_info)4780Sstevel@tonic-gate uhci_polled_init(usba_pipe_handle_data_t	*ph,
4790Sstevel@tonic-gate 	uhci_state_t		*uhcip,
4800Sstevel@tonic-gate 	usb_console_info_impl_t	*console_info)
4810Sstevel@tonic-gate {
4820Sstevel@tonic-gate 	uhci_polled_t	*uhci_polledp;
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	/*
4870Sstevel@tonic-gate 	 * If the structure has already been initialized, then we don't
4880Sstevel@tonic-gate 	 * need to redo it.
4890Sstevel@tonic-gate 	 */
4900Sstevel@tonic-gate 	if (console_info->uci_private != NULL) {
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 		return (USB_SUCCESS);
4930Sstevel@tonic-gate 	}
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	/* Allocate and intitialize a polled mode state structure */
496*7492SZhigang.Lu@Sun.COM 	uhci_polledp = (uhci_polled_t *)kmem_zalloc(sizeof (uhci_polled_t),
497*7492SZhigang.Lu@Sun.COM 	    KM_SLEEP);
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	/*
5000Sstevel@tonic-gate 	 * Keep a copy of normal mode state structure and pipe handle.
5010Sstevel@tonic-gate 	 */
5020Sstevel@tonic-gate 	uhci_polledp->uhci_polled_uhcip	= uhcip;
5030Sstevel@tonic-gate 	uhci_polledp->uhci_polled_ph	= ph;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	/*
5060Sstevel@tonic-gate 	 * Allocate a queue head for the device. This queue head wiil be
5070Sstevel@tonic-gate 	 * put in action when we switch to polled mode in _enter point.
5080Sstevel@tonic-gate 	 */
5090Sstevel@tonic-gate 	uhci_polledp->uhci_polled_qh = uhci_alloc_queue_head(uhcip);
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_qh == NULL) {
5120Sstevel@tonic-gate 		kmem_free(uhci_polledp, sizeof (uhci_polled_t));
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
5150Sstevel@tonic-gate 	}
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	/*
5180Sstevel@tonic-gate 	 * Insert a TD onto the queue head.
5190Sstevel@tonic-gate 	 */
5200Sstevel@tonic-gate 	if ((uhci_polled_insert_td_on_qh(uhci_polledp,
5210Sstevel@tonic-gate 	    uhci_polledp->uhci_polled_ph)) != USB_SUCCESS) {
5220Sstevel@tonic-gate 		uhci_polledp->uhci_polled_qh->qh_flag = QUEUE_HEAD_FLAG_FREE;
5230Sstevel@tonic-gate 		kmem_free(uhci_polledp, sizeof (uhci_polled_t));
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
5260Sstevel@tonic-gate 	}
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	console_info->uci_private = (usb_console_info_private_t)uhci_polledp;
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	return (USB_SUCCESS);
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate /*
5350Sstevel@tonic-gate  * uhci_polled_fini:
5360Sstevel@tonic-gate  */
5370Sstevel@tonic-gate static int
uhci_polled_fini(uhci_polled_t * uhci_polledp,uhci_state_t * uhcip)5380Sstevel@tonic-gate uhci_polled_fini(uhci_polled_t *uhci_polledp, uhci_state_t *uhcip)
5390Sstevel@tonic-gate {
5400Sstevel@tonic-gate 	uhci_td_t	*td = uhci_polledp->uhci_polled_td;
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	/*
5450Sstevel@tonic-gate 	 * Free the transfer wrapper
5460Sstevel@tonic-gate 	 */
5470Sstevel@tonic-gate 	uhci_free_tw(uhcip, td->tw);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	/*
5500Sstevel@tonic-gate 	 * Free the queue head and transfer descriptor allocated.
5510Sstevel@tonic-gate 	 */
5520Sstevel@tonic-gate 	uhci_polledp->uhci_polled_qh->qh_flag = QUEUE_HEAD_FLAG_FREE;
5530Sstevel@tonic-gate 	uhci_polledp->uhci_polled_td->flag = TD_FLAG_FREE;
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	/*
5560Sstevel@tonic-gate 	 * Deallocate the memory for the polled mode state structure.
5570Sstevel@tonic-gate 	 */
5580Sstevel@tonic-gate 	kmem_free(uhci_polledp, sizeof (uhci_polled_t));
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	return (USB_SUCCESS);
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate /*
5650Sstevel@tonic-gate  * uhci_polled_save_state:
5660Sstevel@tonic-gate  */
5670Sstevel@tonic-gate static void
uhci_polled_save_state(uhci_polled_t * uhci_polledp)5680Sstevel@tonic-gate uhci_polled_save_state(uhci_polled_t	*uhci_polledp)
5690Sstevel@tonic-gate {
5700Sstevel@tonic-gate 	int			i;
5710Sstevel@tonic-gate 	uhci_td_t		*td, *polled_td;
5720Sstevel@tonic-gate 	uhci_state_t		*uhcip;
5730Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph;
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate #ifndef lint
5760Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
5770Sstevel@tonic-gate #endif
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	/*
5800Sstevel@tonic-gate 	 * If either of these two flags are set, then we have already
5810Sstevel@tonic-gate 	 * saved off the state information and setup the controller.
5820Sstevel@tonic-gate 	 */
5830Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_flags & POLLED_INPUT_MODE_INUSE) {
5840Sstevel@tonic-gate #ifndef lint
5850Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
5860Sstevel@tonic-gate #endif
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 		return;
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	uhcip = uhci_polledp->uhci_polled_uhcip;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	/*
5940Sstevel@tonic-gate 	 * Check if the number of keyboard reaches the max number we can
5950Sstevel@tonic-gate 	 * support in polled mode
5960Sstevel@tonic-gate 	 */
5970Sstevel@tonic-gate 	if (++ uhcip->uhci_polled_count > MAX_NUM_FOR_KEYBORAD) {
5980Sstevel@tonic-gate #ifndef lint
5990Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
6000Sstevel@tonic-gate #endif
6010Sstevel@tonic-gate 		return;
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	/*
6050Sstevel@tonic-gate 	 * Get the normal mode usb pipe handle.
6060Sstevel@tonic-gate 	 */
6070Sstevel@tonic-gate 	ph = (usba_pipe_handle_data_t *)uhci_polledp->uhci_polled_ph;
6080Sstevel@tonic-gate 	/*
6090Sstevel@tonic-gate 	 * Only the first keyboard enter disable the interrutps, stop the
6100Sstevel@tonic-gate 	 * host controller processing and initialize the interrupt table.
6110Sstevel@tonic-gate 	 */
6120Sstevel@tonic-gate 	if (uhcip->uhci_polled_count == 1) {
6130Sstevel@tonic-gate 		/*
6140Sstevel@tonic-gate 		 * Disable interrupts to prevent the interrupt handler getting
6150Sstevel@tonic-gate 		 * called while we are switing to POLLed mode.
6160Sstevel@tonic-gate 		 */
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 		Set_OpReg16(USBINTR, DISABLE_ALL_INTRS);
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 		/*
6210Sstevel@tonic-gate 		 * Stop the HC controller from processing TD's
6220Sstevel@tonic-gate 		 */
6230Sstevel@tonic-gate 		Set_OpReg16(USBCMD, 0);
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 		/*
6260Sstevel@tonic-gate 		 * Save the current interrupt lattice and  replace this lattice
6270Sstevel@tonic-gate 		 * with an lattice used in POLLED mode. We will restore lattice
6280Sstevel@tonic-gate 		 * back when we exit from the POLLED mode.
6290Sstevel@tonic-gate 		 */
6300Sstevel@tonic-gate 		for (i = 0; i < NUM_FRAME_LST_ENTRIES; i++) {
6310Sstevel@tonic-gate 			uhcip->uhci_polled_save_IntTble[i] =
6320Sstevel@tonic-gate 			    uhcip->uhci_frame_lst_tablep[i];
6330Sstevel@tonic-gate 		}
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 		/*
6360Sstevel@tonic-gate 		 * Zero out the entire interrupt lattice tree.
6370Sstevel@tonic-gate 		 */
6380Sstevel@tonic-gate 		for (i = 0; i < NUM_FRAME_LST_ENTRIES; i++) {
6390Sstevel@tonic-gate 			SetFL32(uhcip, uhcip->uhci_frame_lst_tablep[i],
6400Sstevel@tonic-gate 			    HC_END_OF_LIST);
6410Sstevel@tonic-gate 		}
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	/*
6452191Sszhou 	 * Now, add the endpoint to the lattice that we will hang  our
6460Sstevel@tonic-gate 	 * TD's off of.  We (assume always) need to poll this device at
6470Sstevel@tonic-gate 	 * every 8 ms.
6480Sstevel@tonic-gate 	 */
6490Sstevel@tonic-gate 	for (i = uhcip->uhci_polled_count - 1; i < NUM_FRAME_LST_ENTRIES;
6500Sstevel@tonic-gate 	    i += MIN_LOW_SPEED_POLL_INTERVAL) {
6510Sstevel@tonic-gate 		SetFL32(uhcip, uhcip->uhci_frame_lst_tablep[i],
6520Sstevel@tonic-gate 		    QH_PADDR(uhci_polledp->uhci_polled_qh) | HC_QUEUE_HEAD);
6530Sstevel@tonic-gate 	}
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	/*
6560Sstevel@tonic-gate 	 * Adjust the data toggle
6570Sstevel@tonic-gate 	 */
6580Sstevel@tonic-gate 	td = uhcip->uhci_outst_tds_head;
6590Sstevel@tonic-gate 	while (td != NULL) {
6600Sstevel@tonic-gate 		if (td->tw->tw_pipe_private->pp_pipe_handle == ph) {
6610Sstevel@tonic-gate 			polled_td = uhci_polledp->uhci_polled_td;
6620Sstevel@tonic-gate 			if (GetTD_status(uhcip, td) & UHCI_TD_ACTIVE) {
6630Sstevel@tonic-gate 				SetTD_dtogg(uhcip, polled_td,
6640Sstevel@tonic-gate 				    GetTD_dtogg(uhcip, td));
6650Sstevel@tonic-gate 			} else {
6660Sstevel@tonic-gate 				SetTD_dtogg(uhcip, polled_td,
6670Sstevel@tonic-gate 				    (GetTD_dtogg(uhcip, td) ^ 1));
6680Sstevel@tonic-gate 				uhcip->uhci_polled_flag =
6690Sstevel@tonic-gate 				    UHCI_POLLED_FLAG_TD_COMPL;
6700Sstevel@tonic-gate 			}
6710Sstevel@tonic-gate 			break;
6720Sstevel@tonic-gate 		}
6730Sstevel@tonic-gate 		td = td->outst_td_next;
6740Sstevel@tonic-gate 	}
6750Sstevel@tonic-gate 	/*
6760Sstevel@tonic-gate 	 * Only the first keyboard enter reset the frame number and start
6770Sstevel@tonic-gate 	 * the host controler processing.
6780Sstevel@tonic-gate 	 */
6790Sstevel@tonic-gate 	if (uhcip->uhci_polled_count == 1) {
6800Sstevel@tonic-gate 		/* Set the frame number to zero */
6810Sstevel@tonic-gate 		Set_OpReg16(FRNUM, 0);
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 		/*
6840Sstevel@tonic-gate 		 * Start the Host controller processing
6850Sstevel@tonic-gate 		 */
6860Sstevel@tonic-gate 		Set_OpReg16(USBCMD, (USBCMD_REG_HC_RUN | USBCMD_REG_MAXPKT_64 |
6870Sstevel@tonic-gate 		    USBCMD_REG_CONFIG_FLAG));
6880Sstevel@tonic-gate 	}
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate #ifndef lint
6910Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
6920Sstevel@tonic-gate #endif
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate /*
6970Sstevel@tonic-gate  * uhci_polled_restore_state:
6980Sstevel@tonic-gate  */
6990Sstevel@tonic-gate static void
uhci_polled_restore_state(uhci_polled_t * uhci_polledp)7000Sstevel@tonic-gate uhci_polled_restore_state(uhci_polled_t	*uhci_polledp)
7010Sstevel@tonic-gate {
7020Sstevel@tonic-gate 	int			i;
7030Sstevel@tonic-gate 	ushort_t		real_data_toggle;
7040Sstevel@tonic-gate 	uhci_td_t		*td, *polled_td;
7050Sstevel@tonic-gate 	uhci_state_t		*uhcip;
7060Sstevel@tonic-gate 	uhci_pipe_private_t	*pp;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate #ifndef lint
7090Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
7100Sstevel@tonic-gate #endif
7110Sstevel@tonic-gate 	/*
7120Sstevel@tonic-gate 	 * If this flags is set, then we are still using this structure,
7130Sstevel@tonic-gate 	 * so don't restore any controller state information yet.
7140Sstevel@tonic-gate 	 */
7150Sstevel@tonic-gate 	if (uhci_polledp->uhci_polled_flags & POLLED_INPUT_MODE_INUSE) {
7160Sstevel@tonic-gate #ifndef lint
7170Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
7180Sstevel@tonic-gate #endif
7190Sstevel@tonic-gate 		return;
7200Sstevel@tonic-gate 	}
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	uhcip = uhci_polledp->uhci_polled_uhcip;
7230Sstevel@tonic-gate 	uhcip->uhci_polled_count --;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	/* Just first leave keyboard entry turn off the controller */
7260Sstevel@tonic-gate 	if (Get_OpReg16(USBCMD)) {
7270Sstevel@tonic-gate 		Set_OpReg16(USBCMD, 0x0);
7280Sstevel@tonic-gate 	}
7290Sstevel@tonic-gate 	/* Only the last leave keyboard entry restore the interrupt table */
7300Sstevel@tonic-gate 	if (uhcip->uhci_polled_count == 0) {
7310Sstevel@tonic-gate 		/*
7320Sstevel@tonic-gate 		 * Replace the lattice
7330Sstevel@tonic-gate 		 */
7340Sstevel@tonic-gate 		for (i = 0; i < NUM_FRAME_LST_ENTRIES; i++) {
7350Sstevel@tonic-gate 			uhcip->uhci_frame_lst_tablep[i] =
7360Sstevel@tonic-gate 			    uhcip->uhci_polled_save_IntTble[i];
7370Sstevel@tonic-gate 		}
7380Sstevel@tonic-gate 	}
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	/*
7410Sstevel@tonic-gate 	 * Adjust data toggle
7420Sstevel@tonic-gate 	 */
7430Sstevel@tonic-gate 	pp = (uhci_pipe_private_t *)
7446990Sgd78059 	    uhci_polledp->uhci_polled_ph->p_hcd_private;
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	polled_td = uhci_polledp->uhci_polled_td;
7470Sstevel@tonic-gate 	real_data_toggle = (GetTD_status(uhcip, polled_td) & UHCI_TD_ACTIVE) ?
7486990Sgd78059 	    GetTD_dtogg(uhcip, polled_td) :
7496990Sgd78059 	    !GetTD_dtogg(uhcip, polled_td);
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	td = uhcip->uhci_outst_tds_head;
7520Sstevel@tonic-gate 	while (td != NULL) {
7530Sstevel@tonic-gate 		if (td->tw->tw_pipe_private->pp_pipe_handle ==
7540Sstevel@tonic-gate 		    uhci_polledp->uhci_polled_ph) {
7550Sstevel@tonic-gate 			if (GetTD_status(uhcip, td) & UHCI_TD_ACTIVE) {
7560Sstevel@tonic-gate 				SetTD_dtogg(uhcip, td, real_data_toggle);
7570Sstevel@tonic-gate 				pp->pp_data_toggle =
7580Sstevel@tonic-gate 				    (real_data_toggle == 0) ? 1 : 0;
7590Sstevel@tonic-gate 			} else {
760*7492SZhigang.Lu@Sun.COM 				pp->pp_data_toggle = (uchar_t)real_data_toggle;
7610Sstevel@tonic-gate 			}
7620Sstevel@tonic-gate 		}
7630Sstevel@tonic-gate 		td = td->outst_td_next;
7640Sstevel@tonic-gate 	}
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	/*
7670Sstevel@tonic-gate 	 * Only the last leave keyboard entry enable the interrupts,
7680Sstevel@tonic-gate 	 * start Host controller processing.
7690Sstevel@tonic-gate 	 */
7700Sstevel@tonic-gate 	if (uhcip->uhci_polled_count == 0) {
7710Sstevel@tonic-gate 		Set_OpReg16(USBINTR, ENABLE_ALL_INTRS);
7720Sstevel@tonic-gate 		Set_OpReg16(USBCMD, (USBCMD_REG_HC_RUN | USBCMD_REG_MAXPKT_64 |
7730Sstevel@tonic-gate 		    USBCMD_REG_CONFIG_FLAG));
7740Sstevel@tonic-gate 		if (uhcip->uhci_polled_flag == UHCI_POLLED_FLAG_TD_COMPL) {
7750Sstevel@tonic-gate 			uhcip->uhci_polled_flag = UHCI_POLLED_FLAG_TRUE;
7760Sstevel@tonic-gate 		}
7770Sstevel@tonic-gate 	}
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate #ifndef lint
7800Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
7810Sstevel@tonic-gate #endif
7820Sstevel@tonic-gate }
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate /*
7860Sstevel@tonic-gate  * uhci_polled_insert_td:
7870Sstevel@tonic-gate  *	Initializes the transfer descriptor for polling and inserts on the
7880Sstevel@tonic-gate  *	polled queue head. This will be put in action when entered in to
7890Sstevel@tonic-gate  *	polled mode.
7900Sstevel@tonic-gate  */
7910Sstevel@tonic-gate static int
uhci_polled_insert_td_on_qh(uhci_polled_t * uhci_polledp,usba_pipe_handle_data_t * ph)7920Sstevel@tonic-gate uhci_polled_insert_td_on_qh(uhci_polled_t *uhci_polledp,
7930Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph)
7940Sstevel@tonic-gate {
7950Sstevel@tonic-gate 	uhci_td_t		*td;
7960Sstevel@tonic-gate 	uhci_state_t		*uhcip = uhci_polledp->uhci_polled_uhcip;
7970Sstevel@tonic-gate 	usb_ep_descr_t		*eptd;
7980Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw;
7992191Sszhou 	uint_t			direction;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	/* Create the transfer wrapper */
8020Sstevel@tonic-gate 	if ((tw = uhci_polled_create_tw(uhci_polledp->uhci_polled_uhcip)) ==
8030Sstevel@tonic-gate 	    NULL) {
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 		return (USB_FAILURE);
8060Sstevel@tonic-gate 	}
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	/* Use the dummy TD allocated for the queue head */
8090Sstevel@tonic-gate 	td = uhci_polledp->uhci_polled_qh->td_tailp;
8100Sstevel@tonic-gate 	bzero((char *)td, sizeof (uhci_td_t));
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	uhci_polledp->uhci_polled_td = td;
8130Sstevel@tonic-gate 	td->tw = tw;
8140Sstevel@tonic-gate 	td->flag = TD_FLAG_BUSY;
8150Sstevel@tonic-gate 	SetTD32(uhcip, td->link_ptr, HC_END_OF_LIST);
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	mutex_enter(&ph->p_usba_device->usb_mutex);
8180Sstevel@tonic-gate 	if (ph->p_usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
8190Sstevel@tonic-gate 		SetTD_ls(uhcip, td, LOW_SPEED_DEVICE);
8200Sstevel@tonic-gate 	}
8210Sstevel@tonic-gate 
8222191Sszhou 	eptd = &ph->p_ep;
8232191Sszhou 	direction = (UHCI_XFER_DIR(eptd) == USB_EP_DIR_OUT) ? PID_OUT : PID_IN;
8240Sstevel@tonic-gate 	SetTD_c_err(uhcip, td, UHCI_MAX_ERR_COUNT);
8252191Sszhou 	SetTD_mlen(uhcip, td, POLLED_RAW_BUF_SIZE - 1);
8260Sstevel@tonic-gate 	SetTD_devaddr(uhcip, td, ph->p_usba_device->usb_addr);
8270Sstevel@tonic-gate 	SetTD_endpt(uhcip, td, eptd->bEndpointAddress & END_POINT_ADDRESS_MASK);
8282191Sszhou 	SetTD_PID(uhcip, td, direction);
8290Sstevel@tonic-gate 	SetTD32(uhcip, td->buffer_address, tw->tw_cookie.dmac_address);
8300Sstevel@tonic-gate 	SetTD_ioc(uhcip, td, INTERRUPT_ON_COMPLETION);
8310Sstevel@tonic-gate 	SetTD_status(uhcip, td, UHCI_TD_ACTIVE);
8320Sstevel@tonic-gate 	mutex_exit(&ph->p_usba_device->usb_mutex);
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	SetQH32(uhcip, uhci_polledp->uhci_polled_qh->element_ptr, TD_PADDR(td));
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	return (USB_SUCCESS);
8370Sstevel@tonic-gate }
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate /*
8410Sstevel@tonic-gate  * uhci_polled_create_wrapper_t:
8420Sstevel@tonic-gate  *	Creates the transfer wrapper used in polled mode.
8430Sstevel@tonic-gate  */
8440Sstevel@tonic-gate static uhci_trans_wrapper_t *
uhci_polled_create_tw(uhci_state_t * uhcip)8450Sstevel@tonic-gate uhci_polled_create_tw(uhci_state_t *uhcip)
8460Sstevel@tonic-gate {
8470Sstevel@tonic-gate 	uint_t			result, ccount;
8480Sstevel@tonic-gate 	size_t			real_length;
8490Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw;
8500Sstevel@tonic-gate 	ddi_device_acc_attr_t	dev_attr;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	/* Allocate space for the transfer wrapper */
8530Sstevel@tonic-gate 	if ((tw = kmem_zalloc(sizeof (uhci_trans_wrapper_t), KM_NOSLEEP)) ==
8540Sstevel@tonic-gate 	    NULL) {
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 		return (NULL);
8570Sstevel@tonic-gate 	}
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	tw->tw_length = POLLED_RAW_BUF_SIZE;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	/* Allocate the DMA handle */
8620Sstevel@tonic-gate 	if ((result = ddi_dma_alloc_handle(uhcip->uhci_dip,
8630Sstevel@tonic-gate 	    &uhcip->uhci_dma_attr, DDI_DMA_DONTWAIT, 0, &tw->tw_dmahandle)) !=
8640Sstevel@tonic-gate 	    DDI_SUCCESS) {
8650Sstevel@tonic-gate 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 		return (NULL);
8680Sstevel@tonic-gate 	}
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	dev_attr.devacc_attr_version		= DDI_DEVICE_ATTR_V0;
8710Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags	= DDI_STRUCTURE_LE_ACC;
8720Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder		= DDI_STRICTORDER_ACC;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	/* Allocate the memory */
8750Sstevel@tonic-gate 	if ((result = ddi_dma_mem_alloc(tw->tw_dmahandle, POLLED_RAW_BUF_SIZE,
8760Sstevel@tonic-gate 	    &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
8770Sstevel@tonic-gate 	    &tw->tw_buf, &real_length, &tw->tw_accesshandle)) !=
8780Sstevel@tonic-gate 	    DDI_SUCCESS) {
8790Sstevel@tonic-gate 		ddi_dma_free_handle(&tw->tw_dmahandle);
8800Sstevel@tonic-gate 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 		return (NULL);
8830Sstevel@tonic-gate 	}
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	/* Bind the handle */
8860Sstevel@tonic-gate 	if ((result = ddi_dma_addr_bind_handle(tw->tw_dmahandle, NULL,
8870Sstevel@tonic-gate 	    tw->tw_buf, real_length, DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
8880Sstevel@tonic-gate 	    DDI_DMA_DONTWAIT, NULL, &tw->tw_cookie, &ccount)) !=
8890Sstevel@tonic-gate 	    DDI_DMA_MAPPED) {
8900Sstevel@tonic-gate 		ddi_dma_mem_free(&tw->tw_accesshandle);
8910Sstevel@tonic-gate 		ddi_dma_free_handle(&tw->tw_dmahandle);
8920Sstevel@tonic-gate 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 		return (NULL);
8950Sstevel@tonic-gate 	}
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	/* The cookie count should be 1 */
8980Sstevel@tonic-gate 	if (ccount != 1) {
8990Sstevel@tonic-gate 		result = ddi_dma_unbind_handle(tw->tw_dmahandle);
9000Sstevel@tonic-gate 		ASSERT(result == DDI_SUCCESS);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 		ddi_dma_mem_free(&tw->tw_accesshandle);
9030Sstevel@tonic-gate 		ddi_dma_free_handle(&tw->tw_dmahandle);
9040Sstevel@tonic-gate 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 		return (NULL);
9070Sstevel@tonic-gate 	}
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	return (tw);
9100Sstevel@tonic-gate }
911