10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52125Ssl147100 * Common Development and Distribution License (the "License").
62125Ssl147100 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*9095SZhigang.Lu@Sun.COM * Copyright 2009 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 * Open Host Controller Driver (OHCI)
280Sstevel@tonic-gate *
290Sstevel@tonic-gate * The USB Open Host Controller driver is a software driver which interfaces
300Sstevel@tonic-gate * to the Universal Serial Bus layer (USBA) and the USB Open Host Controller.
310Sstevel@tonic-gate * The interface to USB Open Host Controller is defined by the OpenHCI Host
320Sstevel@tonic-gate * Controller Interface.
330Sstevel@tonic-gate *
340Sstevel@tonic-gate * This module contains the specific ohci code used in POLLED mode and this
350Sstevel@tonic-gate * code is in a separate file since it will never become part of ohci driver.
360Sstevel@tonic-gate */
370Sstevel@tonic-gate #include <sys/usb/hcd/openhci/ohcid.h>
380Sstevel@tonic-gate #include <sys/usb/hcd/openhci/ohci_polled.h>
390Sstevel@tonic-gate
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate * Internal Function Prototypes
420Sstevel@tonic-gate */
430Sstevel@tonic-gate
440Sstevel@tonic-gate /* Polled initialization routines */
450Sstevel@tonic-gate static int ohci_polled_init(
460Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
470Sstevel@tonic-gate ohci_state_t *ohcip,
480Sstevel@tonic-gate usb_console_info_impl_t *console_input_info);
490Sstevel@tonic-gate
500Sstevel@tonic-gate /* Polled deinitialization routines */
510Sstevel@tonic-gate static int ohci_polled_fini(ohci_polled_t *ohci_polledp);
520Sstevel@tonic-gate
530Sstevel@tonic-gate /* Polled save state routines */
540Sstevel@tonic-gate static void ohci_polled_save_state(ohci_polled_t *ohci_polledp);
550Sstevel@tonic-gate static void ohci_polled_stop_processing(
560Sstevel@tonic-gate ohci_polled_t *ohci_polledp);
570Sstevel@tonic-gate
580Sstevel@tonic-gate /* Polled restore state routines */
590Sstevel@tonic-gate static void ohci_polled_restore_state(ohci_polled_t *ohci_polledp);
600Sstevel@tonic-gate static void ohci_polled_start_processing(
610Sstevel@tonic-gate ohci_polled_t *ohci_polledp);
620Sstevel@tonic-gate
630Sstevel@tonic-gate /* Polled read routines */
640Sstevel@tonic-gate static ohci_td_t *ohci_polled_pickup_done_list(
650Sstevel@tonic-gate ohci_polled_t *ohci_polledp,
660Sstevel@tonic-gate ohci_td_t *done_head);
670Sstevel@tonic-gate static int ohci_polled_check_done_list(
680Sstevel@tonic-gate ohci_polled_t *ohci_polledp);
690Sstevel@tonic-gate static void ohci_polled_create_input_list(
700Sstevel@tonic-gate ohci_polled_t *ohci_polledp,
710Sstevel@tonic-gate ohci_td_t *head_done_list);
720Sstevel@tonic-gate static int ohci_polled_process_input_list(
730Sstevel@tonic-gate ohci_polled_t *ohci_polledp);
740Sstevel@tonic-gate static int ohci_polled_handle_normal_td(
750Sstevel@tonic-gate ohci_polled_t *ohci_polledp,
760Sstevel@tonic-gate ohci_td_t *td);
770Sstevel@tonic-gate static void ohci_polled_insert_td(ohci_state_t *ohcip,
780Sstevel@tonic-gate ohci_td_t *td);
790Sstevel@tonic-gate static void ohci_polled_fill_in_td(ohci_state_t *ohcip,
800Sstevel@tonic-gate ohci_td_t *td,
810Sstevel@tonic-gate ohci_td_t *new_dummy,
820Sstevel@tonic-gate uint_t hctd_ctrl,
830Sstevel@tonic-gate uint32_t hctd_iommu_cbp,
840Sstevel@tonic-gate size_t hctd_length,
850Sstevel@tonic-gate ohci_trans_wrapper_t *tw);
860Sstevel@tonic-gate static void ohci_polled_insert_td_on_tw(
870Sstevel@tonic-gate ohci_state_t *ohcip,
880Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
890Sstevel@tonic-gate ohci_td_t *td);
900Sstevel@tonic-gate static void ohci_polled_handle_frame_number_overflow(
910Sstevel@tonic-gate ohci_state_t *ohcip);
920Sstevel@tonic-gate static void ohci_polled_finish_interrupt(
930Sstevel@tonic-gate ohci_state_t *ohcip,
940Sstevel@tonic-gate uint_t intr);
95*9095SZhigang.Lu@Sun.COM static void ohci_polled_insert_bulk_td(
96*9095SZhigang.Lu@Sun.COM ohci_polled_t *ohci_polledp);
97*9095SZhigang.Lu@Sun.COM static int ohci_polled_create_tw(
98*9095SZhigang.Lu@Sun.COM ohci_state_t *ohcip,
99*9095SZhigang.Lu@Sun.COM usba_pipe_handle_data_t *ph,
100*9095SZhigang.Lu@Sun.COM usb_flags_t usb_flags);
101*9095SZhigang.Lu@Sun.COM static int ohci_polled_insert_hc_td(
102*9095SZhigang.Lu@Sun.COM ohci_state_t *ohcip,
103*9095SZhigang.Lu@Sun.COM uint_t hctd_ctrl,
104*9095SZhigang.Lu@Sun.COM uint32_t hctd_dma_offs,
105*9095SZhigang.Lu@Sun.COM size_t hctd_length,
106*9095SZhigang.Lu@Sun.COM ohci_pipe_private_t *pp,
107*9095SZhigang.Lu@Sun.COM ohci_trans_wrapper_t *tw);
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate * POLLED entry points
1100Sstevel@tonic-gate *
1110Sstevel@tonic-gate * These functions are entry points into the POLLED code.
1120Sstevel@tonic-gate */
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate /*
1150Sstevel@tonic-gate * ohci_hcdi_polled_input_init:
1160Sstevel@tonic-gate *
117*9095SZhigang.Lu@Sun.COM * This is the initialization routine for handling the USB input device
1180Sstevel@tonic-gate * in POLLED mode. This routine is not called from POLLED mode, so
1190Sstevel@tonic-gate * it is OK to acquire mutexes.
1200Sstevel@tonic-gate */
1210Sstevel@tonic-gate int
ohci_hcdi_polled_input_init(usba_pipe_handle_data_t * ph,uchar_t ** polled_buf,usb_console_info_impl_t * console_input_info)1220Sstevel@tonic-gate ohci_hcdi_polled_input_init(
1230Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1240Sstevel@tonic-gate uchar_t **polled_buf,
1250Sstevel@tonic-gate usb_console_info_impl_t *console_input_info)
1260Sstevel@tonic-gate {
1270Sstevel@tonic-gate ohci_polled_t *ohci_polledp;
1280Sstevel@tonic-gate ohci_state_t *ohcip;
129*9095SZhigang.Lu@Sun.COM int pipe_attr, ret;
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate ohcip = ohci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate /*
1340Sstevel@tonic-gate * Grab the ohci_int_mutex so that things don't change on us
1350Sstevel@tonic-gate * if an interrupt comes in.
1360Sstevel@tonic-gate */
1370Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate ret = ohci_polled_init(ph, ohcip, console_input_info);
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate if (ret != USB_SUCCESS) {
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate /* Allow interrupts to continue */
1440Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate return (ret);
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate ohci_polledp = (ohci_polled_t *)console_input_info->uci_private;
1500Sstevel@tonic-gate /*
1510Sstevel@tonic-gate * Mark the structure so that if we are using it, we don't free
1520Sstevel@tonic-gate * the structures if one of them is unplugged.
1530Sstevel@tonic-gate */
1540Sstevel@tonic-gate ohci_polledp->ohci_polled_flags |= POLLED_INPUT_MODE;
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate /* increase the polled kbd counter for keyboard connected */
1570Sstevel@tonic-gate ohcip->ohci_polled_kbd_count ++;
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate * This is the buffer we will copy characters into. It will be
1610Sstevel@tonic-gate * copied into at this layer, so we need to keep track of it.
1620Sstevel@tonic-gate */
1630Sstevel@tonic-gate ohci_polledp->ohci_polled_buf =
1647425SGongtian.Zhao@Sun.COM (uchar_t *)kmem_zalloc(POLLED_RAW_BUF_SIZE, KM_SLEEP);
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate *polled_buf = ohci_polledp->ohci_polled_buf;
1670Sstevel@tonic-gate
168*9095SZhigang.Lu@Sun.COM /* Insert bulkin td into endpoint's tds list */
169*9095SZhigang.Lu@Sun.COM pipe_attr = ohci_polledp->ohci_polled_input_pipe_handle->
170*9095SZhigang.Lu@Sun.COM p_ep.bmAttributes & USB_EP_ATTR_MASK;
171*9095SZhigang.Lu@Sun.COM
172*9095SZhigang.Lu@Sun.COM if (pipe_attr == USB_EP_ATTR_BULK) {
173*9095SZhigang.Lu@Sun.COM ohci_polled_insert_bulk_td(ohci_polledp);
174*9095SZhigang.Lu@Sun.COM }
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate * This is a software workaround to fix schizo hardware bug.
1770Sstevel@tonic-gate * Existence of "no-prom-cdma-sync" property means consistent
1780Sstevel@tonic-gate * dma sync should not be done while in prom or polled mode.
1790Sstevel@tonic-gate */
1800Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, ohcip->ohci_dip,
1810Sstevel@tonic-gate DDI_PROP_NOTPROM, "no-prom-cdma-sync")) {
1820Sstevel@tonic-gate ohci_polledp->ohci_polled_no_sync_flag = B_TRUE;
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate /* Allow interrupts to continue */
1860Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate return (USB_SUCCESS);
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate /*
1930Sstevel@tonic-gate * ohci_hcdi_polled_input_fini:
1940Sstevel@tonic-gate */
1950Sstevel@tonic-gate int
ohci_hcdi_polled_input_fini(usb_console_info_impl_t * info)1960Sstevel@tonic-gate ohci_hcdi_polled_input_fini(usb_console_info_impl_t *info)
1970Sstevel@tonic-gate {
1980Sstevel@tonic-gate ohci_polled_t *ohci_polledp;
1990Sstevel@tonic-gate ohci_state_t *ohcip;
2000Sstevel@tonic-gate int ret;
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate ohci_polledp = (ohci_polled_t *)info->uci_private;
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate ohcip = ohci_polledp->ohci_polled_ohcip;
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate /*
2090Sstevel@tonic-gate * Reset the POLLED_INPUT_MODE flag so that we can tell if
2100Sstevel@tonic-gate * this structure is in use in the ohci_polled_fini routine.
2110Sstevel@tonic-gate */
2120Sstevel@tonic-gate ohci_polledp->ohci_polled_flags &= ~POLLED_INPUT_MODE;
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate /* Decrease the polled kbd counter for keyboard disconnected */
2150Sstevel@tonic-gate ohcip->ohci_polled_kbd_count --;
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate /* Free the buffer that we copied data into */
2180Sstevel@tonic-gate kmem_free(ohci_polledp->ohci_polled_buf, POLLED_RAW_BUF_SIZE);
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate ret = ohci_polled_fini(ohci_polledp);
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate return (ret);
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate * ohci_hcdi_polled_input_enter:
2300Sstevel@tonic-gate *
2310Sstevel@tonic-gate * This is where we enter into POLLED mode. This routine sets up
2320Sstevel@tonic-gate * everything so that calls to ohci_hcdi_polled_read will return
2330Sstevel@tonic-gate * characters.
2340Sstevel@tonic-gate */
2350Sstevel@tonic-gate int
ohci_hcdi_polled_input_enter(usb_console_info_impl_t * info)2360Sstevel@tonic-gate ohci_hcdi_polled_input_enter(usb_console_info_impl_t *info)
2370Sstevel@tonic-gate {
2380Sstevel@tonic-gate ohci_polled_t *ohci_polledp;
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate ohci_polledp = (ohci_polled_t *)info->uci_private;
2410Sstevel@tonic-gate ohci_polledp->ohci_polled_entry++;
2420Sstevel@tonic-gate /*
2430Sstevel@tonic-gate * If the controller is already switched over, just return
2440Sstevel@tonic-gate */
2450Sstevel@tonic-gate if (ohci_polledp->ohci_polled_entry > 1) {
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate return (USB_SUCCESS);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate ohci_polled_save_state(ohci_polledp);
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate ohci_polledp->ohci_polled_flags |= POLLED_INPUT_MODE_INUSE;
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate return (USB_SUCCESS);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate /*
2580Sstevel@tonic-gate * ohci_hcdi_polled_input_exit:
2590Sstevel@tonic-gate *
2600Sstevel@tonic-gate * This is where we exit POLLED mode. This routine restores
2610Sstevel@tonic-gate * everything that is needed to continue operation.
2620Sstevel@tonic-gate */
2630Sstevel@tonic-gate int
ohci_hcdi_polled_input_exit(usb_console_info_impl_t * info)2640Sstevel@tonic-gate ohci_hcdi_polled_input_exit(usb_console_info_impl_t *info)
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate ohci_polled_t *ohci_polledp;
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate ohci_polledp = (ohci_polled_t *)info->uci_private;
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate ohci_polledp->ohci_polled_entry--;
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * If there are still outstanding "enters", just return
2740Sstevel@tonic-gate */
2750Sstevel@tonic-gate if (ohci_polledp->ohci_polled_entry > 0)
2760Sstevel@tonic-gate return (USB_SUCCESS);
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate ohci_polledp->ohci_polled_flags &= ~POLLED_INPUT_MODE_INUSE;
2790Sstevel@tonic-gate ohci_polled_restore_state(ohci_polledp);
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate return (USB_SUCCESS);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate * ohci_hcdi_polled_read:
2870Sstevel@tonic-gate *
2880Sstevel@tonic-gate * Get a key character
2890Sstevel@tonic-gate */
2900Sstevel@tonic-gate int
ohci_hcdi_polled_read(usb_console_info_impl_t * info,uint_t * num_characters)2910Sstevel@tonic-gate ohci_hcdi_polled_read(
2920Sstevel@tonic-gate usb_console_info_impl_t *info,
2930Sstevel@tonic-gate uint_t *num_characters)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate ohci_state_t *ohcip;
2960Sstevel@tonic-gate ohci_polled_t *ohci_polledp;
2970Sstevel@tonic-gate uint_t intr;
2980Sstevel@tonic-gate ohci_polledp = (ohci_polled_t *)info->uci_private;
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate ohcip = ohci_polledp->ohci_polled_ohcip;
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate #ifndef lint
3030Sstevel@tonic-gate _NOTE(NO_COMPETING_THREADS_NOW);
3040Sstevel@tonic-gate #endif
3050Sstevel@tonic-gate *num_characters = 0;
3060Sstevel@tonic-gate intr = (Get_OpReg(hcr_intr_status) & Get_OpReg(hcr_intr_enable));
3070Sstevel@tonic-gate
3080Sstevel@tonic-gate /*
3090Sstevel@tonic-gate * Check whether any Frame Number Overflow interrupt is pending
3100Sstevel@tonic-gate * and if it is pending, process this interrupt.
3110Sstevel@tonic-gate */
3120Sstevel@tonic-gate if (intr & HCR_INTR_FNO) {
3130Sstevel@tonic-gate ohci_handle_frame_number_overflow(ohcip);
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate /* Acknowledge the FNO interrupt */
3160Sstevel@tonic-gate ohci_polled_finish_interrupt(ohcip, HCR_INTR_FNO);
3170Sstevel@tonic-gate }
318*9095SZhigang.Lu@Sun.COM
319*9095SZhigang.Lu@Sun.COM /* Check to see if there are any TD's for this input device */
320*9095SZhigang.Lu@Sun.COM if (ohci_polled_check_done_list(ohci_polledp) == USB_SUCCESS) {
321*9095SZhigang.Lu@Sun.COM
322*9095SZhigang.Lu@Sun.COM /* Process any TD's on the input done list */
323*9095SZhigang.Lu@Sun.COM *num_characters =
324*9095SZhigang.Lu@Sun.COM ohci_polled_process_input_list(ohci_polledp);
325*9095SZhigang.Lu@Sun.COM }
326*9095SZhigang.Lu@Sun.COM
327*9095SZhigang.Lu@Sun.COM /*
328*9095SZhigang.Lu@Sun.COM * To make sure after we get the done list from DoneHead,
329*9095SZhigang.Lu@Sun.COM * every input device get his own TD's in the
330*9095SZhigang.Lu@Sun.COM * ohci_polled_done_list and then clear the interrupt status.
331*9095SZhigang.Lu@Sun.COM */
3320Sstevel@tonic-gate if (intr & HCR_INTR_WDH) {
3330Sstevel@tonic-gate
334*9095SZhigang.Lu@Sun.COM /* Acknowledge the WDH interrupt */
335*9095SZhigang.Lu@Sun.COM ohci_polled_finish_interrupt(ohcip, HCR_INTR_WDH);
3360Sstevel@tonic-gate }
3370Sstevel@tonic-gate #ifndef lint
3380Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW);
3390Sstevel@tonic-gate #endif
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate return (USB_SUCCESS);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate /*
346*9095SZhigang.Lu@Sun.COM * ohci_hcdi_polled_output_init:
347*9095SZhigang.Lu@Sun.COM *
348*9095SZhigang.Lu@Sun.COM * This is the initialization routine for handling the USB serial output
349*9095SZhigang.Lu@Sun.COM * in POLLED mode. This routine is not called from POLLED mode, so
350*9095SZhigang.Lu@Sun.COM * it is OK to acquire mutexes.
351*9095SZhigang.Lu@Sun.COM */
352*9095SZhigang.Lu@Sun.COM int
ohci_hcdi_polled_output_init(usba_pipe_handle_data_t * ph,usb_console_info_impl_t * console_output_info)353*9095SZhigang.Lu@Sun.COM ohci_hcdi_polled_output_init(
354*9095SZhigang.Lu@Sun.COM usba_pipe_handle_data_t *ph,
355*9095SZhigang.Lu@Sun.COM usb_console_info_impl_t *console_output_info)
356*9095SZhigang.Lu@Sun.COM {
357*9095SZhigang.Lu@Sun.COM ohci_polled_t *ohci_polledp;
358*9095SZhigang.Lu@Sun.COM ohci_state_t *ohcip;
359*9095SZhigang.Lu@Sun.COM int ret;
360*9095SZhigang.Lu@Sun.COM
361*9095SZhigang.Lu@Sun.COM ohcip = ohci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
362*9095SZhigang.Lu@Sun.COM
363*9095SZhigang.Lu@Sun.COM /*
364*9095SZhigang.Lu@Sun.COM * Grab the ohci_int_mutex so that things don't change on us
365*9095SZhigang.Lu@Sun.COM * if an interrupt comes in.
366*9095SZhigang.Lu@Sun.COM */
367*9095SZhigang.Lu@Sun.COM mutex_enter(&ohcip->ohci_int_mutex);
368*9095SZhigang.Lu@Sun.COM
369*9095SZhigang.Lu@Sun.COM ret = ohci_polled_init(ph, ohcip, console_output_info);
370*9095SZhigang.Lu@Sun.COM
371*9095SZhigang.Lu@Sun.COM if (ret != USB_SUCCESS) {
372*9095SZhigang.Lu@Sun.COM
373*9095SZhigang.Lu@Sun.COM /* Allow interrupts to continue */
374*9095SZhigang.Lu@Sun.COM mutex_exit(&ohcip->ohci_int_mutex);
375*9095SZhigang.Lu@Sun.COM
376*9095SZhigang.Lu@Sun.COM return (ret);
377*9095SZhigang.Lu@Sun.COM }
378*9095SZhigang.Lu@Sun.COM
379*9095SZhigang.Lu@Sun.COM ohci_polledp = (ohci_polled_t *)console_output_info->uci_private;
380*9095SZhigang.Lu@Sun.COM /*
381*9095SZhigang.Lu@Sun.COM * Mark the structure so that if we are using it, we don't free
382*9095SZhigang.Lu@Sun.COM * the structures if one of them is unplugged.
383*9095SZhigang.Lu@Sun.COM */
384*9095SZhigang.Lu@Sun.COM ohci_polledp->ohci_polled_flags |= POLLED_OUTPUT_MODE;
385*9095SZhigang.Lu@Sun.COM
386*9095SZhigang.Lu@Sun.COM /*
387*9095SZhigang.Lu@Sun.COM * This is a software workaround to fix schizo hardware bug.
388*9095SZhigang.Lu@Sun.COM * Existence of "no-prom-cdma-sync" property means consistent
389*9095SZhigang.Lu@Sun.COM * dma sync should not be done while in prom or polled mode.
390*9095SZhigang.Lu@Sun.COM */
391*9095SZhigang.Lu@Sun.COM if (ddi_prop_exists(DDI_DEV_T_ANY, ohcip->ohci_dip,
392*9095SZhigang.Lu@Sun.COM DDI_PROP_NOTPROM, "no-prom-cdma-sync")) {
393*9095SZhigang.Lu@Sun.COM ohci_polledp->ohci_polled_no_sync_flag = B_TRUE;
394*9095SZhigang.Lu@Sun.COM }
395*9095SZhigang.Lu@Sun.COM
396*9095SZhigang.Lu@Sun.COM /* Allow interrupts to continue */
397*9095SZhigang.Lu@Sun.COM mutex_exit(&ohcip->ohci_int_mutex);
398*9095SZhigang.Lu@Sun.COM
399*9095SZhigang.Lu@Sun.COM return (USB_SUCCESS);
400*9095SZhigang.Lu@Sun.COM }
401*9095SZhigang.Lu@Sun.COM
402*9095SZhigang.Lu@Sun.COM /*
403*9095SZhigang.Lu@Sun.COM * ohci_hcdi_polled_output_fini:
404*9095SZhigang.Lu@Sun.COM */
405*9095SZhigang.Lu@Sun.COM int
ohci_hcdi_polled_output_fini(usb_console_info_impl_t * info)406*9095SZhigang.Lu@Sun.COM ohci_hcdi_polled_output_fini(usb_console_info_impl_t *info)
407*9095SZhigang.Lu@Sun.COM {
408*9095SZhigang.Lu@Sun.COM ohci_polled_t *ohci_polledp;
409*9095SZhigang.Lu@Sun.COM ohci_state_t *ohcip;
410*9095SZhigang.Lu@Sun.COM int ret;
411*9095SZhigang.Lu@Sun.COM
412*9095SZhigang.Lu@Sun.COM ohci_polledp = (ohci_polled_t *)info->uci_private;
413*9095SZhigang.Lu@Sun.COM
414*9095SZhigang.Lu@Sun.COM ohcip = ohci_polledp->ohci_polled_ohcip;
415*9095SZhigang.Lu@Sun.COM
416*9095SZhigang.Lu@Sun.COM mutex_enter(&ohcip->ohci_int_mutex);
417*9095SZhigang.Lu@Sun.COM
418*9095SZhigang.Lu@Sun.COM /*
419*9095SZhigang.Lu@Sun.COM * Reset the POLLED_INPUT_MODE flag so that we can tell if
420*9095SZhigang.Lu@Sun.COM * this structure is in use in the ohci_polled_fini routine.
421*9095SZhigang.Lu@Sun.COM */
422*9095SZhigang.Lu@Sun.COM ohci_polledp->ohci_polled_flags &= ~POLLED_OUTPUT_MODE;
423*9095SZhigang.Lu@Sun.COM
424*9095SZhigang.Lu@Sun.COM ret = ohci_polled_fini(ohci_polledp);
425*9095SZhigang.Lu@Sun.COM
426*9095SZhigang.Lu@Sun.COM info->uci_private = NULL;
427*9095SZhigang.Lu@Sun.COM
428*9095SZhigang.Lu@Sun.COM mutex_exit(&ohcip->ohci_int_mutex);
429*9095SZhigang.Lu@Sun.COM
430*9095SZhigang.Lu@Sun.COM return (ret);
431*9095SZhigang.Lu@Sun.COM }
432*9095SZhigang.Lu@Sun.COM
433*9095SZhigang.Lu@Sun.COM
434*9095SZhigang.Lu@Sun.COM /*
435*9095SZhigang.Lu@Sun.COM * ohci_hcdi_polled_output_enter:
436*9095SZhigang.Lu@Sun.COM *
437*9095SZhigang.Lu@Sun.COM * everything is done in input enter
438*9095SZhigang.Lu@Sun.COM */
439*9095SZhigang.Lu@Sun.COM /*ARGSUSED*/
440*9095SZhigang.Lu@Sun.COM int
ohci_hcdi_polled_output_enter(usb_console_info_impl_t * info)441*9095SZhigang.Lu@Sun.COM ohci_hcdi_polled_output_enter(usb_console_info_impl_t *info)
442*9095SZhigang.Lu@Sun.COM {
443*9095SZhigang.Lu@Sun.COM return (USB_SUCCESS);
444*9095SZhigang.Lu@Sun.COM }
445*9095SZhigang.Lu@Sun.COM
446*9095SZhigang.Lu@Sun.COM
447*9095SZhigang.Lu@Sun.COM /*
448*9095SZhigang.Lu@Sun.COM * ohci_hcdi_polled_output_exit:
449*9095SZhigang.Lu@Sun.COM *
450*9095SZhigang.Lu@Sun.COM * everything is done in input exit
451*9095SZhigang.Lu@Sun.COM */
452*9095SZhigang.Lu@Sun.COM /*ARGSUSED*/
453*9095SZhigang.Lu@Sun.COM int
ohci_hcdi_polled_output_exit(usb_console_info_impl_t * info)454*9095SZhigang.Lu@Sun.COM ohci_hcdi_polled_output_exit(usb_console_info_impl_t *info)
455*9095SZhigang.Lu@Sun.COM {
456*9095SZhigang.Lu@Sun.COM return (USB_SUCCESS);
457*9095SZhigang.Lu@Sun.COM }
458*9095SZhigang.Lu@Sun.COM
459*9095SZhigang.Lu@Sun.COM
460*9095SZhigang.Lu@Sun.COM /*
461*9095SZhigang.Lu@Sun.COM * ohci_hcdi_polled_write:
462*9095SZhigang.Lu@Sun.COM * Put a key character -- rewrite this!
463*9095SZhigang.Lu@Sun.COM */
464*9095SZhigang.Lu@Sun.COM int
ohci_hcdi_polled_write(usb_console_info_impl_t * info,uchar_t * buf,uint_t num_characters,uint_t * num_characters_written)465*9095SZhigang.Lu@Sun.COM ohci_hcdi_polled_write(usb_console_info_impl_t *info, uchar_t *buf,
466*9095SZhigang.Lu@Sun.COM uint_t num_characters, uint_t *num_characters_written)
467*9095SZhigang.Lu@Sun.COM {
468*9095SZhigang.Lu@Sun.COM ohci_state_t *ohcip;
469*9095SZhigang.Lu@Sun.COM ohci_polled_t *ohci_polledp;
470*9095SZhigang.Lu@Sun.COM ohci_trans_wrapper_t *tw;
471*9095SZhigang.Lu@Sun.COM ohci_pipe_private_t *pp;
472*9095SZhigang.Lu@Sun.COM usba_pipe_handle_data_t *ph;
473*9095SZhigang.Lu@Sun.COM uint32_t ctrl;
474*9095SZhigang.Lu@Sun.COM uint_t intr, bulk_pkg_size;
475*9095SZhigang.Lu@Sun.COM int i;
476*9095SZhigang.Lu@Sun.COM
477*9095SZhigang.Lu@Sun.COM #ifndef lint
478*9095SZhigang.Lu@Sun.COM _NOTE(NO_COMPETING_THREADS_NOW);
479*9095SZhigang.Lu@Sun.COM #endif
480*9095SZhigang.Lu@Sun.COM
481*9095SZhigang.Lu@Sun.COM ohci_polledp = (ohci_polled_t *)info->uci_private;
482*9095SZhigang.Lu@Sun.COM ohcip = ohci_polledp->ohci_polled_ohcip;
483*9095SZhigang.Lu@Sun.COM
484*9095SZhigang.Lu@Sun.COM /* Disable periodic list processing */
485*9095SZhigang.Lu@Sun.COM Set_OpReg(hcr_control,
486*9095SZhigang.Lu@Sun.COM (Get_OpReg(hcr_control) & (~HCR_CONTROL_PLE)));
487*9095SZhigang.Lu@Sun.COM
488*9095SZhigang.Lu@Sun.COM /* Add the endpoint to the lattice */
489*9095SZhigang.Lu@Sun.COM for (i = ohcip->ohci_polled_enter_count; i < NUM_INTR_ED_LISTS;
490*9095SZhigang.Lu@Sun.COM i = i + MIN_LOW_SPEED_POLL_INTERVAL) {
491*9095SZhigang.Lu@Sun.COM Set_HCCA(ohcip->ohci_hccap->HccaIntTble[i],
492*9095SZhigang.Lu@Sun.COM ohci_ed_cpu_to_iommu(ohcip,
493*9095SZhigang.Lu@Sun.COM ohci_polledp->ohci_polled_ed));
494*9095SZhigang.Lu@Sun.COM }
495*9095SZhigang.Lu@Sun.COM
496*9095SZhigang.Lu@Sun.COM ph = ohci_polledp->ohci_polled_input_pipe_handle;
497*9095SZhigang.Lu@Sun.COM pp = (ohci_pipe_private_t *)ph->p_hcd_private;
498*9095SZhigang.Lu@Sun.COM tw = pp->pp_tw_head;
499*9095SZhigang.Lu@Sun.COM
500*9095SZhigang.Lu@Sun.COM ASSERT(tw != NULL);
501*9095SZhigang.Lu@Sun.COM if (tw->tw_hctd_free_list == NULL) {
502*9095SZhigang.Lu@Sun.COM #ifndef lint
503*9095SZhigang.Lu@Sun.COM _NOTE(COMPETING_THREADS_NOW);
504*9095SZhigang.Lu@Sun.COM #endif
505*9095SZhigang.Lu@Sun.COM return (USB_SUCCESS);
506*9095SZhigang.Lu@Sun.COM }
507*9095SZhigang.Lu@Sun.COM
508*9095SZhigang.Lu@Sun.COM /* Copy transmit buffer */
509*9095SZhigang.Lu@Sun.COM if (num_characters > POLLED_RAW_BUF_SIZE) {
510*9095SZhigang.Lu@Sun.COM cmn_err(CE_NOTE, "polled write size %d bigger than %d",
511*9095SZhigang.Lu@Sun.COM num_characters, POLLED_RAW_BUF_SIZE);
512*9095SZhigang.Lu@Sun.COM num_characters = POLLED_RAW_BUF_SIZE;
513*9095SZhigang.Lu@Sun.COM }
514*9095SZhigang.Lu@Sun.COM tw->tw_length = num_characters;
515*9095SZhigang.Lu@Sun.COM
516*9095SZhigang.Lu@Sun.COM ddi_rep_put8(tw->tw_accesshandle,
517*9095SZhigang.Lu@Sun.COM buf, (uint8_t *)tw->tw_buf,
518*9095SZhigang.Lu@Sun.COM tw->tw_length, DDI_DEV_AUTOINCR);
519*9095SZhigang.Lu@Sun.COM Sync_IO_Buffer_for_device(tw->tw_dmahandle, tw->tw_length);
520*9095SZhigang.Lu@Sun.COM
521*9095SZhigang.Lu@Sun.COM /* Insert td into endpoint's tds list */
522*9095SZhigang.Lu@Sun.COM ctrl = tw->tw_direction | HC_TD_DT_0|HC_TD_1I | HC_TD_R;
523*9095SZhigang.Lu@Sun.COM bulk_pkg_size = min(tw->tw_length, OHCI_MAX_TD_XFER_SIZE);
524*9095SZhigang.Lu@Sun.COM
525*9095SZhigang.Lu@Sun.COM (void) ohci_polled_insert_hc_td(ohcip, ctrl, 0, bulk_pkg_size, pp, tw);
526*9095SZhigang.Lu@Sun.COM
527*9095SZhigang.Lu@Sun.COM /* Enable periodic list processing */
528*9095SZhigang.Lu@Sun.COM Set_OpReg(hcr_control,
529*9095SZhigang.Lu@Sun.COM (Get_OpReg(hcr_control) | HCR_CONTROL_PLE));
530*9095SZhigang.Lu@Sun.COM
531*9095SZhigang.Lu@Sun.COM /* Wait for bulk out tds transfer completion */
532*9095SZhigang.Lu@Sun.COM for (;;) {
533*9095SZhigang.Lu@Sun.COM intr = Get_OpReg(hcr_intr_status);
534*9095SZhigang.Lu@Sun.COM
535*9095SZhigang.Lu@Sun.COM if (intr & HCR_INTR_FNO) {
536*9095SZhigang.Lu@Sun.COM ohci_handle_frame_number_overflow(ohcip);
537*9095SZhigang.Lu@Sun.COM ohci_polled_finish_interrupt(ohcip, HCR_INTR_FNO);
538*9095SZhigang.Lu@Sun.COM }
539*9095SZhigang.Lu@Sun.COM
540*9095SZhigang.Lu@Sun.COM if (intr & HCR_INTR_WDH) {
541*9095SZhigang.Lu@Sun.COM if (ohci_polled_check_done_list(ohci_polledp) ==
542*9095SZhigang.Lu@Sun.COM USB_SUCCESS) {
543*9095SZhigang.Lu@Sun.COM *num_characters_written =
544*9095SZhigang.Lu@Sun.COM ohci_polled_process_input_list(
545*9095SZhigang.Lu@Sun.COM ohci_polledp);
546*9095SZhigang.Lu@Sun.COM break;
547*9095SZhigang.Lu@Sun.COM }
548*9095SZhigang.Lu@Sun.COM }
549*9095SZhigang.Lu@Sun.COM
550*9095SZhigang.Lu@Sun.COM Set_OpReg(hcr_intr_status, intr);
551*9095SZhigang.Lu@Sun.COM (void) Get_OpReg(hcr_intr_status);
552*9095SZhigang.Lu@Sun.COM }
553*9095SZhigang.Lu@Sun.COM
554*9095SZhigang.Lu@Sun.COM /* Remove the endpoint from the lattice */
555*9095SZhigang.Lu@Sun.COM for (i = ohcip->ohci_polled_enter_count; i < NUM_INTR_ED_LISTS;
556*9095SZhigang.Lu@Sun.COM i = i + MIN_LOW_SPEED_POLL_INTERVAL) {
557*9095SZhigang.Lu@Sun.COM Set_HCCA(ohcip->ohci_hccap->HccaIntTble[i],
558*9095SZhigang.Lu@Sun.COM ohci_ed_cpu_to_iommu(ohcip,
559*9095SZhigang.Lu@Sun.COM ohci_polledp->ohci_polled_dummy_ed));
560*9095SZhigang.Lu@Sun.COM }
561*9095SZhigang.Lu@Sun.COM
562*9095SZhigang.Lu@Sun.COM Set_OpReg(hcr_intr_status, intr);
563*9095SZhigang.Lu@Sun.COM (void) Get_OpReg(hcr_intr_status);
564*9095SZhigang.Lu@Sun.COM #ifndef lint
565*9095SZhigang.Lu@Sun.COM _NOTE(COMPETING_THREADS_NOW);
566*9095SZhigang.Lu@Sun.COM #endif
567*9095SZhigang.Lu@Sun.COM return (USB_SUCCESS);
568*9095SZhigang.Lu@Sun.COM }
569*9095SZhigang.Lu@Sun.COM
570*9095SZhigang.Lu@Sun.COM
571*9095SZhigang.Lu@Sun.COM /*
5720Sstevel@tonic-gate * Internal Functions
5730Sstevel@tonic-gate */
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate /*
5760Sstevel@tonic-gate * Polled initialization routines
5770Sstevel@tonic-gate */
5780Sstevel@tonic-gate
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate /*
5810Sstevel@tonic-gate * ohci_polled_init:
5820Sstevel@tonic-gate *
5830Sstevel@tonic-gate * Initialize generic information Uthat is needed to provide USB/POLLED
5840Sstevel@tonic-gate * support.
5850Sstevel@tonic-gate */
5860Sstevel@tonic-gate static int
ohci_polled_init(usba_pipe_handle_data_t * ph,ohci_state_t * ohcip,usb_console_info_impl_t * console_info)5870Sstevel@tonic-gate ohci_polled_init(
5880Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
5890Sstevel@tonic-gate ohci_state_t *ohcip,
5900Sstevel@tonic-gate usb_console_info_impl_t *console_info)
5910Sstevel@tonic-gate {
5920Sstevel@tonic-gate ohci_polled_t *ohci_polledp;
5930Sstevel@tonic-gate ohci_pipe_private_t *pp;
594*9095SZhigang.Lu@Sun.COM int pipe_attr;
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate /*
5990Sstevel@tonic-gate * We have already initialized this structure. If the structure
6000Sstevel@tonic-gate * has already been initialized, then we don't need to redo it.
6010Sstevel@tonic-gate */
6020Sstevel@tonic-gate if (console_info->uci_private) {
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate return (USB_SUCCESS);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate
6070Sstevel@tonic-gate /* Allocate and intitialize a state structure */
6080Sstevel@tonic-gate ohci_polledp = (ohci_polled_t *)
6090Sstevel@tonic-gate kmem_zalloc(sizeof (ohci_polled_t), KM_SLEEP);
6100Sstevel@tonic-gate
6110Sstevel@tonic-gate console_info->uci_private = (usb_console_info_private_t)ohci_polledp;
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate /*
6140Sstevel@tonic-gate * Store away the ohcip so that we can get to it when we are in
6150Sstevel@tonic-gate * POLLED mode. We don't want to have to call ohci_obtain_state
6160Sstevel@tonic-gate * every time we want to access this structure. Also save ohci
6170Sstevel@tonic-gate * polled state information in ohcip.
6180Sstevel@tonic-gate */
6190Sstevel@tonic-gate ohci_polledp->ohci_polled_ohcip = ohcip;
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate /*
6220Sstevel@tonic-gate * Save usb device and endpoint number information from the usb
6230Sstevel@tonic-gate * pipe handle.
6240Sstevel@tonic-gate */
6250Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
6260Sstevel@tonic-gate ohci_polledp->ohci_polled_usb_dev = ph->p_usba_device;
6270Sstevel@tonic-gate ohci_polledp->ohci_polled_ep_addr = ph->p_ep.bEndpointAddress;
6280Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate /*
6310Sstevel@tonic-gate * Allocate memory to make duplicate of original usb pipe handle.
6320Sstevel@tonic-gate */
6330Sstevel@tonic-gate ohci_polledp->ohci_polled_input_pipe_handle =
6340Sstevel@tonic-gate kmem_zalloc(sizeof (usba_pipe_handle_data_t), KM_SLEEP);
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate /*
6370Sstevel@tonic-gate * Copy the USB handle into the new pipe handle. Also
6380Sstevel@tonic-gate * create new lock for the new pipe handle.
6390Sstevel@tonic-gate */
6400Sstevel@tonic-gate bcopy((void *)ph,
6410Sstevel@tonic-gate (void *)ohci_polledp->ohci_polled_input_pipe_handle,
6420Sstevel@tonic-gate sizeof (usba_pipe_handle_data_t));
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate /*
6450Sstevel@tonic-gate * uint64_t typecast to make sure amd64 can compile
6460Sstevel@tonic-gate */
6470Sstevel@tonic-gate mutex_init(&ohci_polledp->ohci_polled_input_pipe_handle->p_mutex,
648693Sgovinda NULL, MUTEX_DRIVER, DDI_INTR_PRI(ohcip->ohci_intr_pri));
6490Sstevel@tonic-gate
6500Sstevel@tonic-gate /* Create a new ohci pipe private structure */
6510Sstevel@tonic-gate pp = (ohci_pipe_private_t *)
6520Sstevel@tonic-gate kmem_zalloc(sizeof (ohci_pipe_private_t), KM_SLEEP);
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate /*
6550Sstevel@tonic-gate * Store the pointer in the pipe handle. This structure was also
6560Sstevel@tonic-gate * just allocated.
6570Sstevel@tonic-gate */
6580Sstevel@tonic-gate mutex_enter(&ohci_polledp->ohci_polled_input_pipe_handle->p_mutex);
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate ohci_polledp->ohci_polled_input_pipe_handle->
6610Sstevel@tonic-gate p_hcd_private = (usb_opaque_t)pp;
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate mutex_exit(&ohci_polledp->ohci_polled_input_pipe_handle->p_mutex);
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate /*
6660Sstevel@tonic-gate * Store a pointer to the pipe handle. This structure was just
6670Sstevel@tonic-gate * allocated and it is not in use yet. The locking is there to
6680Sstevel@tonic-gate * satisfy warlock.
6690Sstevel@tonic-gate */
6700Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t));
6730Sstevel@tonic-gate
6740Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
6750Sstevel@tonic-gate
6760Sstevel@tonic-gate pp->pp_pipe_handle = ohci_polledp->ohci_polled_input_pipe_handle;
6770Sstevel@tonic-gate
6780Sstevel@tonic-gate /*
6790Sstevel@tonic-gate * Allocate a dummy for the interrupt table. This dummy will be
6800Sstevel@tonic-gate * put into the action when we switch interrupt tables during
6810Sstevel@tonic-gate * ohci_hcdi_polled_enter. Dummy is placed on the unused lattice
6820Sstevel@tonic-gate * entries. When the ED is allocated we will replace dummy ED by
6830Sstevel@tonic-gate * valid interrupt ED in one or more locations in the interrupt
6840Sstevel@tonic-gate * lattice depending on the requested polling interval. Also we
6850Sstevel@tonic-gate * will hang a dummy TD to the ED & dummy TD is used to indicate
6860Sstevel@tonic-gate * the end of the TD chain.
6870Sstevel@tonic-gate */
6880Sstevel@tonic-gate ohci_polledp->ohci_polled_dummy_ed = ohci_alloc_hc_ed(ohcip, NULL);
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate if (ohci_polledp->ohci_polled_dummy_ed == NULL) {
6910Sstevel@tonic-gate
6920Sstevel@tonic-gate return (USB_NO_RESOURCES);
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate
6950Sstevel@tonic-gate /*
696*9095SZhigang.Lu@Sun.COM * Allocate the endpoint. This ED will be inserted in
697*9095SZhigang.Lu@Sun.COM * to the lattice chain for the device. This endpoint
6980Sstevel@tonic-gate * will have the TDs hanging off of it for the processing.
6990Sstevel@tonic-gate */
7000Sstevel@tonic-gate ohci_polledp->ohci_polled_ed = ohci_alloc_hc_ed(ohcip,
7010Sstevel@tonic-gate ohci_polledp->ohci_polled_input_pipe_handle);
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate if (ohci_polledp->ohci_polled_ed == NULL) {
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate return (USB_NO_RESOURCES);
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate /* Set the state of pipe as idle */
7090Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE;
7100Sstevel@tonic-gate
7110Sstevel@tonic-gate /* Insert the endpoint onto the pipe handle */
7120Sstevel@tonic-gate pp->pp_ept = ohci_polledp->ohci_polled_ed;
7130Sstevel@tonic-gate
714*9095SZhigang.Lu@Sun.COM pipe_attr = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
715*9095SZhigang.Lu@Sun.COM
716*9095SZhigang.Lu@Sun.COM switch (pipe_attr) {
717*9095SZhigang.Lu@Sun.COM case USB_EP_ATTR_INTR:
718*9095SZhigang.Lu@Sun.COM /*
719*9095SZhigang.Lu@Sun.COM * Set soft interrupt handler flag in the normal mode usb
720*9095SZhigang.Lu@Sun.COM * pipe handle.
721*9095SZhigang.Lu@Sun.COM */
722*9095SZhigang.Lu@Sun.COM mutex_enter(&ph->p_mutex);
723*9095SZhigang.Lu@Sun.COM ph->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
724*9095SZhigang.Lu@Sun.COM mutex_exit(&ph->p_mutex);
7250Sstevel@tonic-gate
726*9095SZhigang.Lu@Sun.COM /*
727*9095SZhigang.Lu@Sun.COM * Insert a Interrupt polling request onto the endpoint.
728*9095SZhigang.Lu@Sun.COM *
729*9095SZhigang.Lu@Sun.COM * There will now be two TDs on the ED, one is the dummy TD
730*9095SZhigang.Lu@Sun.COM * that was allocated above in the ohci_alloc_hc_ed and
731*9095SZhigang.Lu@Sun.COM * this new one.
732*9095SZhigang.Lu@Sun.COM */
733*9095SZhigang.Lu@Sun.COM if ((ohci_start_periodic_pipe_polling(ohcip,
734*9095SZhigang.Lu@Sun.COM ohci_polledp->ohci_polled_input_pipe_handle,
735*9095SZhigang.Lu@Sun.COM NULL, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
736*9095SZhigang.Lu@Sun.COM return (USB_NO_RESOURCES);
737*9095SZhigang.Lu@Sun.COM }
738*9095SZhigang.Lu@Sun.COM break;
739*9095SZhigang.Lu@Sun.COM case USB_EP_ATTR_BULK:
740*9095SZhigang.Lu@Sun.COM if ((ohci_polled_create_tw(ohcip,
741*9095SZhigang.Lu@Sun.COM ohci_polledp->ohci_polled_input_pipe_handle,
742*9095SZhigang.Lu@Sun.COM USB_FLAGS_SLEEP)) != USB_SUCCESS) {
743*9095SZhigang.Lu@Sun.COM return (USB_NO_RESOURCES);
744*9095SZhigang.Lu@Sun.COM }
745*9095SZhigang.Lu@Sun.COM break;
746*9095SZhigang.Lu@Sun.COM default:
747*9095SZhigang.Lu@Sun.COM return (USB_FAILURE);
7480Sstevel@tonic-gate }
7490Sstevel@tonic-gate return (USB_SUCCESS);
7500Sstevel@tonic-gate }
7510Sstevel@tonic-gate
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate /*
7540Sstevel@tonic-gate * Polled deinitialization routines
7550Sstevel@tonic-gate */
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate
7580Sstevel@tonic-gate /*
7590Sstevel@tonic-gate * ohci_polled_fini:
7600Sstevel@tonic-gate */
7610Sstevel@tonic-gate static int
ohci_polled_fini(ohci_polled_t * ohci_polledp)7620Sstevel@tonic-gate ohci_polled_fini(ohci_polled_t *ohci_polledp)
7630Sstevel@tonic-gate {
7640Sstevel@tonic-gate ohci_state_t *ohcip = ohci_polledp->ohci_polled_ohcip;
7650Sstevel@tonic-gate ohci_pipe_private_t *pp;
7660Sstevel@tonic-gate ohci_td_t *curr_td, *next_td;
7670Sstevel@tonic-gate ohci_trans_wrapper_t *curr_tw, *next_tw;
7680Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
7690Sstevel@tonic-gate
7700Sstevel@tonic-gate /*
7710Sstevel@tonic-gate * If the structure is already in use, then don't free it.
7720Sstevel@tonic-gate */
7730Sstevel@tonic-gate if (ohci_polledp->ohci_polled_flags & POLLED_INPUT_MODE) {
7740Sstevel@tonic-gate
7750Sstevel@tonic-gate return (USB_SUCCESS);
7760Sstevel@tonic-gate }
7770Sstevel@tonic-gate
7780Sstevel@tonic-gate pp = (ohci_pipe_private_t *)
7790Sstevel@tonic-gate ohci_polledp->ohci_polled_input_pipe_handle->p_hcd_private;
7800Sstevel@tonic-gate
7810Sstevel@tonic-gate /*
7820Sstevel@tonic-gate * Deallocate all the pre-allocated interrupt requests
7830Sstevel@tonic-gate */
7840Sstevel@tonic-gate ohci_handle_outstanding_requests(ohcip, pp);
7850Sstevel@tonic-gate
7860Sstevel@tonic-gate /*
7870Sstevel@tonic-gate * Traverse the list of TD's on this endpoint and these TD's
7880Sstevel@tonic-gate * have outstanding transfer requests. Since list processing
7890Sstevel@tonic-gate * is stopped, these TDs can be deallocated.
7900Sstevel@tonic-gate */
7910Sstevel@tonic-gate ohci_traverse_tds(ohcip, pp->pp_pipe_handle);
7920Sstevel@tonic-gate
7930Sstevel@tonic-gate /*
7940Sstevel@tonic-gate * For each transfer wrapper on this pipe, free the TD and
7950Sstevel@tonic-gate * free the TW. We don't free the last TD in the chain
7960Sstevel@tonic-gate * because it will be freed by ohci_deallocate_ed. All TD's
7970Sstevel@tonic-gate * on this TW are also on the end point associated with this
7980Sstevel@tonic-gate * pipe.
7990Sstevel@tonic-gate */
8000Sstevel@tonic-gate next_tw = pp->pp_tw_head;
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate while (next_tw) {
8030Sstevel@tonic-gate next_td = (ohci_td_t *)next_tw->tw_hctd_head;
8040Sstevel@tonic-gate
8050Sstevel@tonic-gate /*
8060Sstevel@tonic-gate * Walk through each TD for this transfer
8070Sstevel@tonic-gate * wrapper and free that TD.
8080Sstevel@tonic-gate */
8090Sstevel@tonic-gate while (next_td) {
8100Sstevel@tonic-gate curr_td = next_td;
8110Sstevel@tonic-gate
8120Sstevel@tonic-gate next_td = ohci_td_iommu_to_cpu(ohcip,
8130Sstevel@tonic-gate Get_TD(next_td->hctd_tw_next_td));
8140Sstevel@tonic-gate
8150Sstevel@tonic-gate ohci_deallocate_td(ohcip, curr_td);
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate
8180Sstevel@tonic-gate curr_tw = next_tw;
8190Sstevel@tonic-gate next_tw = curr_tw->tw_next;
8200Sstevel@tonic-gate
8210Sstevel@tonic-gate /* Free the transfer wrapper */
8220Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, curr_tw);
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate
8250Sstevel@tonic-gate /*
8260Sstevel@tonic-gate * Deallocate the endpoint descriptors that we allocated
8270Sstevel@tonic-gate * with ohci_alloc_hc_ed.
8280Sstevel@tonic-gate */
8290Sstevel@tonic-gate if (ohci_polledp->ohci_polled_dummy_ed) {
8300Sstevel@tonic-gate ohci_deallocate_ed(ohcip, ohci_polledp->ohci_polled_dummy_ed);
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate
8330Sstevel@tonic-gate if (ohci_polledp->ohci_polled_ed) {
8340Sstevel@tonic-gate ohci_deallocate_ed(ohcip, ohci_polledp->ohci_polled_ed);
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate
8370Sstevel@tonic-gate mutex_destroy(&ohci_polledp->ohci_polled_input_pipe_handle->p_mutex);
8380Sstevel@tonic-gate
8390Sstevel@tonic-gate /*
8400Sstevel@tonic-gate * Destroy everything about the pipe that we allocated in
8410Sstevel@tonic-gate * ohci_polled_duplicate_pipe_handle
8420Sstevel@tonic-gate */
8430Sstevel@tonic-gate kmem_free(pp, sizeof (ohci_pipe_private_t));
8440Sstevel@tonic-gate
8450Sstevel@tonic-gate kmem_free(ohci_polledp->ohci_polled_input_pipe_handle,
8460Sstevel@tonic-gate sizeof (usba_pipe_handle_data_t));
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate /*
8490Sstevel@tonic-gate * We use this field to determine if a TD is for input or not,
8500Sstevel@tonic-gate * so NULL the pointer so we don't check deallocated data.
8510Sstevel@tonic-gate */
8520Sstevel@tonic-gate ohci_polledp->ohci_polled_input_pipe_handle = NULL;
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate /*
8550Sstevel@tonic-gate * Finally, free off the structure that we use to keep track
8560Sstevel@tonic-gate * of all this.
8570Sstevel@tonic-gate */
8580Sstevel@tonic-gate kmem_free(ohci_polledp, sizeof (ohci_polled_t));
8590Sstevel@tonic-gate
8600Sstevel@tonic-gate return (USB_SUCCESS);
8610Sstevel@tonic-gate }
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate
8640Sstevel@tonic-gate /*
8650Sstevel@tonic-gate * Polled save state routines
8660Sstevel@tonic-gate */
8670Sstevel@tonic-gate
8680Sstevel@tonic-gate
8690Sstevel@tonic-gate /*
8700Sstevel@tonic-gate * ohci_polled_save_state:
8710Sstevel@tonic-gate */
8720Sstevel@tonic-gate static void
ohci_polled_save_state(ohci_polled_t * ohci_polledp)8730Sstevel@tonic-gate ohci_polled_save_state(ohci_polled_t *ohci_polledp)
8740Sstevel@tonic-gate {
8750Sstevel@tonic-gate ohci_state_t *ohcip;
8760Sstevel@tonic-gate int i;
8770Sstevel@tonic-gate uint_t polled_toggle;
8780Sstevel@tonic-gate uint_t real_toggle;
8790Sstevel@tonic-gate ohci_pipe_private_t *pp = NULL; /* Normal mode Pipe */
8800Sstevel@tonic-gate ohci_pipe_private_t *polled_pp; /* Polled mode Pipe */
8810Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
8820Sstevel@tonic-gate uint8_t ep_addr;
8830Sstevel@tonic-gate ohci_save_intr_sts_t *ohci_intr_sts;
8840Sstevel@tonic-gate ohci_regs_t *ohci_polled_regsp;
8850Sstevel@tonic-gate ohci_td_t *td, *prev_td;
8860Sstevel@tonic-gate ohci_td_t *done_head, **done_list;
8870Sstevel@tonic-gate
8880Sstevel@tonic-gate #ifndef lint
8890Sstevel@tonic-gate _NOTE(NO_COMPETING_THREADS_NOW);
8900Sstevel@tonic-gate #endif
8910Sstevel@tonic-gate
8920Sstevel@tonic-gate /*
8930Sstevel@tonic-gate * If either of these two flags are set, then we have already
8940Sstevel@tonic-gate * saved off the state information and setup the controller.
8950Sstevel@tonic-gate */
8960Sstevel@tonic-gate if (ohci_polledp->ohci_polled_flags & POLLED_INPUT_MODE_INUSE) {
8970Sstevel@tonic-gate #ifndef lint
8980Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW);
8990Sstevel@tonic-gate #endif
9000Sstevel@tonic-gate return;
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate
9030Sstevel@tonic-gate ohcip = ohci_polledp->ohci_polled_ohcip;
9040Sstevel@tonic-gate
9050Sstevel@tonic-gate /*
9060Sstevel@tonic-gate * Check if the number of keyboard reach the max number we can
9070Sstevel@tonic-gate * support in polled mode
9080Sstevel@tonic-gate */
9090Sstevel@tonic-gate if (++ ohcip->ohci_polled_enter_count > MAX_NUM_FOR_KEYBOARD) {
9100Sstevel@tonic-gate #ifndef lint
9110Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW);
9120Sstevel@tonic-gate #endif
9130Sstevel@tonic-gate return;
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate /* Get the endpoint addr. */
9160Sstevel@tonic-gate ep_addr = ohci_polledp->ohci_polled_ep_addr;
9170Sstevel@tonic-gate
9180Sstevel@tonic-gate /* Get the normal mode usb pipe handle */
9190Sstevel@tonic-gate ph = usba_hcdi_get_ph_data(ohci_polledp->ohci_polled_usb_dev, ep_addr);
9200Sstevel@tonic-gate ohci_intr_sts = &ohcip->ohci_save_intr_sts;
9210Sstevel@tonic-gate ohci_polled_regsp = &ohcip->ohci_polled_save_regs;
9220Sstevel@tonic-gate
9230Sstevel@tonic-gate /*
9240Sstevel@tonic-gate * Only the first enter keyboard entry disable the interrupt, save the
9250Sstevel@tonic-gate * information of normal mode, stop the processing, initialize the
9260Sstevel@tonic-gate * frame list table.
9270Sstevel@tonic-gate */
9280Sstevel@tonic-gate if (ohcip->ohci_polled_enter_count == 1) {
9290Sstevel@tonic-gate /*
9300Sstevel@tonic-gate * Prevent the ohci interrupt handler from handling interrupt.
9310Sstevel@tonic-gate * We will turn off interrupts. This keeps us from generating
9320Sstevel@tonic-gate * a hardware interrupt.This is the useful for testing because
9330Sstevel@tonic-gate * in POLLED mode we can't get interrupts anyway. We can test
9340Sstevel@tonic-gate * this code by shutting off hardware interrupt generation and
9350Sstevel@tonic-gate * polling for the interrupts.
9360Sstevel@tonic-gate */
9370Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_MIE);
9380Sstevel@tonic-gate /*
9390Sstevel@tonic-gate * Save the current normal mode ohci registers and later this
9400Sstevel@tonic-gate * saved register copy is used to replace some of required ohci
9410Sstevel@tonic-gate * registers before switching from polled mode to normal mode.
9420Sstevel@tonic-gate */
9430Sstevel@tonic-gate bzero((void *)ohci_polled_regsp, sizeof (ohci_regs_t));
9440Sstevel@tonic-gate
9450Sstevel@tonic-gate ohci_polled_regsp->hcr_control = Get_OpReg(hcr_control);
9460Sstevel@tonic-gate ohci_polled_regsp->hcr_cmd_status = Get_OpReg(hcr_cmd_status);
9470Sstevel@tonic-gate ohci_polled_regsp->hcr_intr_enable = Get_OpReg(hcr_intr_enable);
9480Sstevel@tonic-gate ohci_polled_regsp->hcr_HCCA = Get_OpReg(hcr_HCCA);
9490Sstevel@tonic-gate ohci_polled_regsp->hcr_done_head = Get_OpReg(hcr_done_head);
9500Sstevel@tonic-gate ohci_polled_regsp->hcr_bulk_head = Get_OpReg(hcr_bulk_head);
9510Sstevel@tonic-gate ohci_polled_regsp->hcr_ctrl_head = Get_OpReg(hcr_ctrl_head);
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate /*
9540Sstevel@tonic-gate * The functionality & importance of critical code section in
9550Sstevel@tonic-gate * the normal mode ohci interrupt handler and its usage in the
9560Sstevel@tonic-gate * polled mode is explained below.
9570Sstevel@tonic-gate *
9580Sstevel@tonic-gate * (a) Normal mode:
9590Sstevel@tonic-gate *
9600Sstevel@tonic-gate * - Set the flag indicating that processing critical code
9610Sstevel@tonic-gate * in ohci interrupt handler.
9620Sstevel@tonic-gate *
9630Sstevel@tonic-gate * - Process the missed ohci interrupts by copying missed
9640Sstevel@tonic-gate * interrupt events & done head list fields information
9650Sstevel@tonic-gate * to the critical interrupt events & done list fields.
9660Sstevel@tonic-gate *
9670Sstevel@tonic-gate * - Reset the missed ohci interrupt events and done head
9680Sstevel@tonic-gate * list fields so that the new missed interrupt events
9690Sstevel@tonic-gate * and done head list information can be saved.
9700Sstevel@tonic-gate *
9710Sstevel@tonic-gate * - All above steps will be executed within the critical
9720Sstevel@tonic-gate * section of the interrupt handler. Then ohci missed
9730Sstevel@tonic-gate * interrupt handler will be called to service the ohci
9740Sstevel@tonic-gate * missed interrupts.
9750Sstevel@tonic-gate *
9760Sstevel@tonic-gate * (b) Polled mode:
9770Sstevel@tonic-gate *
9780Sstevel@tonic-gate * - On entering the polled code, checks for the critical
9790Sstevel@tonic-gate * section code execution within normal mode interrupt
9800Sstevel@tonic-gate * handler.
9810Sstevel@tonic-gate *
9820Sstevel@tonic-gate * - If critical section code is executing in the normal
9830Sstevel@tonic-gate * mode ohci interrupt handler & if copying of the ohci
9840Sstevel@tonic-gate * missed interrupt events and done head list fields to
9850Sstevel@tonic-gate * the critical fields is finished then, save the "any
9860Sstevel@tonic-gate * missed interrupt events and done head list" because
9870Sstevel@tonic-gate * of current polled mode switch into "critical missed
9880Sstevel@tonic-gate * interrupt events & done list fields" instead actual
9890Sstevel@tonic-gate * missed events and done list fields.
9900Sstevel@tonic-gate *
9910Sstevel@tonic-gate * - Otherwise save "any missed interrupt events and done
9920Sstevel@tonic-gate * list" because of this current polled mode switch in
9930Sstevel@tonic-gate * the actual missed interrupt events & done head list
9940Sstevel@tonic-gate * fields.
9950Sstevel@tonic-gate */
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate /*
9980Sstevel@tonic-gate * Check and save the pending SOF interrupt condition for the
9990Sstevel@tonic-gate * ohci normal mode. This information will be saved either in
10000Sstevel@tonic-gate * the critical missed event fields or in actual missed event
10010Sstevel@tonic-gate * fields depending on the whether the critical code section's
10020Sstevel@tonic-gate * execution flag was set or not when switched to polled mode
10030Sstevel@tonic-gate * from normal mode.
10040Sstevel@tonic-gate */
10050Sstevel@tonic-gate if ((ohci_intr_sts->ohci_intr_flag & OHCI_INTR_CRITICAL) &&
10060Sstevel@tonic-gate (ohci_intr_sts->ohci_critical_intr_sts != 0)) {
10070Sstevel@tonic-gate
10080Sstevel@tonic-gate ohci_intr_sts->ohci_critical_intr_sts |=
10090Sstevel@tonic-gate ((Get_OpReg(hcr_intr_status) &
10100Sstevel@tonic-gate Get_OpReg(hcr_intr_enable)) & HCR_INTR_SOF);
10110Sstevel@tonic-gate } else {
10120Sstevel@tonic-gate ohci_intr_sts->ohci_missed_intr_sts |=
10130Sstevel@tonic-gate ((Get_OpReg(hcr_intr_status) &
10140Sstevel@tonic-gate Get_OpReg(hcr_intr_enable)) & HCR_INTR_SOF);
10150Sstevel@tonic-gate }
10160Sstevel@tonic-gate ohci_polled_stop_processing(ohci_polledp);
10170Sstevel@tonic-gate
10180Sstevel@tonic-gate /* Process any missed Frame Number Overflow (FNO) interrupt */
10190Sstevel@tonic-gate ohci_polled_handle_frame_number_overflow(ohcip);
10200Sstevel@tonic-gate
10210Sstevel@tonic-gate /*
10220Sstevel@tonic-gate * By this time all list processing has been stopped.Now check
10230Sstevel@tonic-gate * and save the information about the pending HCCA done list,
10240Sstevel@tonic-gate * done head ohci register and WDH bit in the interrupt status
10250Sstevel@tonic-gate * register. This information will be saved either in critical
10260Sstevel@tonic-gate * missed event fields or in actual missed event fields depend
10270Sstevel@tonic-gate * on the whether the critical code section's execution flag
10280Sstevel@tonic-gate * was set or not when switched to polled mode from the normal
10290Sstevel@tonic-gate * mode.
10300Sstevel@tonic-gate */
10310Sstevel@tonic-gate
10320Sstevel@tonic-gate /* Read and Save the HCCA DoneHead value */
10330Sstevel@tonic-gate done_head = (ohci_td_t *)(uintptr_t)(Get_HCCA(
10340Sstevel@tonic-gate ohcip->ohci_hccap->HccaDoneHead) & HCCA_DONE_HEAD_MASK);
10350Sstevel@tonic-gate
10360Sstevel@tonic-gate if ((done_head) &&
10370Sstevel@tonic-gate (done_head != ohci_intr_sts->ohci_curr_done_lst)) {
10380Sstevel@tonic-gate
10390Sstevel@tonic-gate if ((ohci_intr_sts->ohci_intr_flag &
10400Sstevel@tonic-gate OHCI_INTR_CRITICAL) &&
10410Sstevel@tonic-gate ((ohci_intr_sts->ohci_critical_done_lst) ||
10420Sstevel@tonic-gate (ohci_intr_sts->ohci_missed_done_lst == NULL))) {
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate done_list =
10450Sstevel@tonic-gate &ohci_intr_sts->ohci_critical_done_lst;
10460Sstevel@tonic-gate ohci_intr_sts->ohci_critical_intr_sts |=
10470Sstevel@tonic-gate HCR_INTR_WDH;
10480Sstevel@tonic-gate } else {
10490Sstevel@tonic-gate done_list =
10500Sstevel@tonic-gate &ohci_intr_sts->ohci_missed_done_lst;
10510Sstevel@tonic-gate ohci_intr_sts->ohci_missed_intr_sts |=
10520Sstevel@tonic-gate HCR_INTR_WDH;
10530Sstevel@tonic-gate }
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate if (*done_list) {
10560Sstevel@tonic-gate td = (ohci_td_t *)
10570Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip,
10580Sstevel@tonic-gate (uintptr_t)done_head);
10590Sstevel@tonic-gate
10600Sstevel@tonic-gate while (td) {
10610Sstevel@tonic-gate prev_td = td;
10620Sstevel@tonic-gate td = ohci_td_iommu_to_cpu(ohcip,
10630Sstevel@tonic-gate Get_TD(td->hctd_next_td));
10640Sstevel@tonic-gate }
10650Sstevel@tonic-gate
10660Sstevel@tonic-gate Set_TD(prev_td->hctd_next_td, *done_list);
10670Sstevel@tonic-gate
10680Sstevel@tonic-gate *done_list = done_head;
10690Sstevel@tonic-gate } else {
10700Sstevel@tonic-gate *done_list = (ohci_td_t *)done_head;
10710Sstevel@tonic-gate }
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate
10740Sstevel@tonic-gate /*
10750Sstevel@tonic-gate * Save the latest hcr_done_head ohci register value, so that
10760Sstevel@tonic-gate * this value can be replaced when exit from the POLLED mode.
10770Sstevel@tonic-gate */
10780Sstevel@tonic-gate ohci_polled_regsp->hcr_done_head = Get_OpReg(hcr_done_head);
10790Sstevel@tonic-gate /*
10800Sstevel@tonic-gate * Reset the HCCA done head and ohci done head register.
10810Sstevel@tonic-gate */
10820Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaDoneHead, NULL);
10830Sstevel@tonic-gate Set_OpReg(hcr_done_head, (uint32_t)0x0);
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate /*
10860Sstevel@tonic-gate * Clear the WriteDoneHead interrupt bit in the ohci interrupt
10870Sstevel@tonic-gate * status register.
10880Sstevel@tonic-gate */
10890Sstevel@tonic-gate Set_OpReg(hcr_intr_status, HCR_INTR_WDH);
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate /*
10920Sstevel@tonic-gate * Save the current interrupt lattice and replace this lattice
10930Sstevel@tonic-gate * with an lattice used in POLLED mode. We will restore lattice
10940Sstevel@tonic-gate * back when we exit from the POLLED mode.
10950Sstevel@tonic-gate */
10960Sstevel@tonic-gate for (i = 0; i < NUM_INTR_ED_LISTS; i++) {
10970Sstevel@tonic-gate ohcip->ohci_polled_save_IntTble[i] =
10980Sstevel@tonic-gate (ohci_ed_t *)(uintptr_t)Get_HCCA(
10990Sstevel@tonic-gate ohcip->ohci_hccap->HccaIntTble[i]);
11000Sstevel@tonic-gate }
11010Sstevel@tonic-gate /*
11020Sstevel@tonic-gate * Fill in the lattice with dummy EDs. These EDs are used so the
11030Sstevel@tonic-gate * controller can tell that it is at the end of the ED list.
11040Sstevel@tonic-gate */
11050Sstevel@tonic-gate for (i = 0; i < NUM_INTR_ED_LISTS; i++) {
11060Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaIntTble[i],
11070Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip,
11080Sstevel@tonic-gate ohci_polledp->ohci_polled_dummy_ed));
11090Sstevel@tonic-gate }
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate /* Get the polled mode ohci pipe private structure */
11120Sstevel@tonic-gate polled_pp = (ohci_pipe_private_t *)
11130Sstevel@tonic-gate ohci_polledp->ohci_polled_input_pipe_handle->p_hcd_private;
11140Sstevel@tonic-gate
11150Sstevel@tonic-gate /*
11160Sstevel@tonic-gate * Before replacing the lattice, adjust the data togggle on the
11170Sstevel@tonic-gate * on the ohci's interrupt ed
11180Sstevel@tonic-gate */
11190Sstevel@tonic-gate polled_toggle = (Get_ED(polled_pp->pp_ept->hced_headp) &
11207425SGongtian.Zhao@Sun.COM HC_EPT_Carry) ? DATA1:DATA0;
11210Sstevel@tonic-gate
11220Sstevel@tonic-gate /*
11230Sstevel@tonic-gate * If normal mode interrupt pipe endpoint is active, get the data
11240Sstevel@tonic-gate * toggle from the this interrupt endpoint through the corresponding
11250Sstevel@tonic-gate * interrupt pipe handle. Else get the data toggle information from
11260Sstevel@tonic-gate * the usb device structure and this information is saved during the
11270Sstevel@tonic-gate * normal mode interrupt pipe close. Use this data toggle information
11280Sstevel@tonic-gate * to fix the data toggle of polled mode interrupt endpoint.
11290Sstevel@tonic-gate */
11300Sstevel@tonic-gate if (ph) {
11310Sstevel@tonic-gate /* Get the normal mode ohci pipe private structure */
11320Sstevel@tonic-gate pp = (ohci_pipe_private_t *)ph->p_hcd_private;
11330Sstevel@tonic-gate
11340Sstevel@tonic-gate real_toggle = (Get_ED(pp->pp_ept->hced_headp) &
11350Sstevel@tonic-gate HC_EPT_Carry) ? DATA1:DATA0;
11360Sstevel@tonic-gate } else {
11370Sstevel@tonic-gate real_toggle = usba_hcdi_get_data_toggle(
11380Sstevel@tonic-gate ohci_polledp->ohci_polled_usb_dev, ep_addr);
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate
11410Sstevel@tonic-gate if (polled_toggle != real_toggle) {
11420Sstevel@tonic-gate if (real_toggle == DATA0) {
11430Sstevel@tonic-gate Set_ED(polled_pp->pp_ept->hced_headp,
11440Sstevel@tonic-gate Get_ED(polled_pp->pp_ept->hced_headp) &
11450Sstevel@tonic-gate ~HC_EPT_Carry);
11460Sstevel@tonic-gate } else {
11470Sstevel@tonic-gate Set_ED(polled_pp->pp_ept->hced_headp,
11480Sstevel@tonic-gate Get_ED(polled_pp->pp_ept->hced_headp) |
11490Sstevel@tonic-gate HC_EPT_Carry);
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate }
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate /*
11540Sstevel@tonic-gate * Check whether Halt bit is set in the ED and if so clear the
11550Sstevel@tonic-gate * halt bit.
11560Sstevel@tonic-gate */
11570Sstevel@tonic-gate if (polled_pp->pp_ept->hced_headp & HC_EPT_Halt) {
11580Sstevel@tonic-gate
11590Sstevel@tonic-gate /* Clear the halt bit */
11600Sstevel@tonic-gate Set_ED(polled_pp->pp_ept->hced_headp,
11610Sstevel@tonic-gate (Get_ED(polled_pp->pp_ept->hced_headp) & ~HC_EPT_Halt));
11620Sstevel@tonic-gate }
11630Sstevel@tonic-gate
11640Sstevel@tonic-gate /*
11650Sstevel@tonic-gate * Now, add the endpoint to the lattice that we will hang our
11660Sstevel@tonic-gate * TD's off of. We need to poll this device at every 8 ms and
11670Sstevel@tonic-gate * hence add this ED needs 4 entries in interrupt lattice.
11680Sstevel@tonic-gate */
11690Sstevel@tonic-gate for (i = (ohcip->ohci_polled_enter_count -1); i < NUM_INTR_ED_LISTS;
11707425SGongtian.Zhao@Sun.COM i = i + MIN_LOW_SPEED_POLL_INTERVAL) {
11710Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaIntTble[i],
11720Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip,
11730Sstevel@tonic-gate ohci_polledp->ohci_polled_ed));
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate /*
11760Sstevel@tonic-gate * Only the first enter keyboard entry clear the contents of
11770Sstevel@tonic-gate * periodic ED register and enable the WDH interrupt and
11780Sstevel@tonic-gate * start process the periodic list.
11790Sstevel@tonic-gate */
11800Sstevel@tonic-gate if (ohcip->ohci_polled_enter_count == 1) {
11810Sstevel@tonic-gate /*
11820Sstevel@tonic-gate * Clear the contents of current ohci periodic ED register that
11830Sstevel@tonic-gate * is physical address of current Isochronous or Interrupt ED.
11840Sstevel@tonic-gate */
11850Sstevel@tonic-gate
11860Sstevel@tonic-gate Set_OpReg(hcr_periodic_curr, (uint32_t)0x0);
11870Sstevel@tonic-gate
11880Sstevel@tonic-gate /* Make sure WriteDoneHead interrupt is enabled */
11890Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_WDH);
11900Sstevel@tonic-gate
11910Sstevel@tonic-gate /*
11920Sstevel@tonic-gate * Enable the periodic list. We will now start processing EDs &
11930Sstevel@tonic-gate * TDs again.
11940Sstevel@tonic-gate */
11950Sstevel@tonic-gate Set_OpReg(hcr_control,
11960Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_PLE));
11970Sstevel@tonic-gate }
11980Sstevel@tonic-gate #ifndef lint
11990Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW);
12000Sstevel@tonic-gate #endif
12010Sstevel@tonic-gate }
12020Sstevel@tonic-gate
12030Sstevel@tonic-gate
12040Sstevel@tonic-gate /*
12050Sstevel@tonic-gate * ohci_polled_stop_processing:
12060Sstevel@tonic-gate */
12070Sstevel@tonic-gate static void
ohci_polled_stop_processing(ohci_polled_t * ohci_polledp)12080Sstevel@tonic-gate ohci_polled_stop_processing(ohci_polled_t *ohci_polledp)
12090Sstevel@tonic-gate {
12100Sstevel@tonic-gate ohci_state_t *ohcip;
12110Sstevel@tonic-gate uint_t count;
12120Sstevel@tonic-gate ohci_regs_t *ohci_polled_regsp;
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate ohcip = ohci_polledp->ohci_polled_ohcip;
12150Sstevel@tonic-gate ohci_polled_regsp = &ohcip->ohci_polled_save_regs;
12160Sstevel@tonic-gate
12170Sstevel@tonic-gate /*
12180Sstevel@tonic-gate * Turn off all list processing. This will take place starting
12190Sstevel@tonic-gate * at the next frame.
12200Sstevel@tonic-gate */
12210Sstevel@tonic-gate Set_OpReg(hcr_control,
12220Sstevel@tonic-gate (ohci_polled_regsp->hcr_control) & ~(HCR_CONTROL_CLE|
12230Sstevel@tonic-gate HCR_CONTROL_PLE| HCR_CONTROL_BLE|HCR_CONTROL_IE));
12240Sstevel@tonic-gate
12250Sstevel@tonic-gate /*
12260Sstevel@tonic-gate * Make sure that the SOF interrupt bit is cleared in the ohci
12270Sstevel@tonic-gate * interrupt status register.
12280Sstevel@tonic-gate */
12290Sstevel@tonic-gate Set_OpReg(hcr_intr_status, HCR_INTR_SOF);
12300Sstevel@tonic-gate
12310Sstevel@tonic-gate /* Enable SOF interrupt */
12320Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SOF);
12330Sstevel@tonic-gate
12340Sstevel@tonic-gate /*
12350Sstevel@tonic-gate * According to OHCI Specification, we have to wait for eight
12360Sstevel@tonic-gate * start of frames to make sure that the Host Controller writes
12370Sstevel@tonic-gate * contents of done head register to done head filed of HCCA.
12380Sstevel@tonic-gate */
12390Sstevel@tonic-gate for (count = 0; count <= DONE_QUEUE_INTR_COUNTER; count++) {
12400Sstevel@tonic-gate while (!((Get_OpReg(hcr_intr_status)) & HCR_INTR_SOF)) {
12410Sstevel@tonic-gate continue;
12420Sstevel@tonic-gate }
12430Sstevel@tonic-gate
12440Sstevel@tonic-gate /* Acknowledge the SOF interrupt */
12450Sstevel@tonic-gate ohci_polled_finish_interrupt(ohcip, HCR_INTR_SOF);
12460Sstevel@tonic-gate }
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_SOF);
12490Sstevel@tonic-gate }
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate
12520Sstevel@tonic-gate /*
12530Sstevel@tonic-gate * Polled restore state routines
12540Sstevel@tonic-gate */
12550Sstevel@tonic-gate
12560Sstevel@tonic-gate /*
12570Sstevel@tonic-gate * ohci_polled_restore_state:
12580Sstevel@tonic-gate */
12590Sstevel@tonic-gate static void
ohci_polled_restore_state(ohci_polled_t * ohci_polledp)12600Sstevel@tonic-gate ohci_polled_restore_state(ohci_polled_t *ohci_polledp)
12610Sstevel@tonic-gate {
12620Sstevel@tonic-gate ohci_state_t *ohcip;
12630Sstevel@tonic-gate int i;
12640Sstevel@tonic-gate uint_t polled_toggle;
12650Sstevel@tonic-gate uint_t real_toggle;
12660Sstevel@tonic-gate ohci_pipe_private_t *pp = NULL; /* Normal mode Pipe */
12670Sstevel@tonic-gate ohci_pipe_private_t *polled_pp; /* Polled mode Pipe */
12680Sstevel@tonic-gate ohci_td_t *td;
12690Sstevel@tonic-gate ohci_td_t *next_td; /* TD pointers */
12700Sstevel@tonic-gate uint_t count;
12710Sstevel@tonic-gate ohci_save_intr_sts_t *ohci_intr_sts;
12720Sstevel@tonic-gate ohci_regs_t *ohci_polled_regsp;
12730Sstevel@tonic-gate uint32_t mask;
12740Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
12750Sstevel@tonic-gate uint8_t ep_addr;
12760Sstevel@tonic-gate
12770Sstevel@tonic-gate #ifndef lint
12780Sstevel@tonic-gate _NOTE(NO_COMPETING_THREADS_NOW);
12790Sstevel@tonic-gate #endif
12800Sstevel@tonic-gate
12810Sstevel@tonic-gate /*
12820Sstevel@tonic-gate * If this flag is set, then we are still using this structure,
12830Sstevel@tonic-gate * so don't restore any controller state information yet.
12840Sstevel@tonic-gate */
12850Sstevel@tonic-gate if (ohci_polledp->ohci_polled_flags & POLLED_INPUT_MODE_INUSE) {
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate #ifndef lint
12880Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW);
12890Sstevel@tonic-gate #endif
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate return;
12920Sstevel@tonic-gate }
12930Sstevel@tonic-gate
12940Sstevel@tonic-gate ohcip = ohci_polledp->ohci_polled_ohcip;
12950Sstevel@tonic-gate ohci_intr_sts = &ohcip->ohci_save_intr_sts;
12960Sstevel@tonic-gate ohci_polled_regsp = &ohcip->ohci_polled_save_regs;
12970Sstevel@tonic-gate ohcip->ohci_polled_enter_count --;
12980Sstevel@tonic-gate
12990Sstevel@tonic-gate /* Get the endpoint addr. */
13000Sstevel@tonic-gate ep_addr = ohci_polledp->ohci_polled_ep_addr;
13010Sstevel@tonic-gate /* Get the normal mode usb pipe handle */
13020Sstevel@tonic-gate ph = usba_hcdi_get_ph_data(ohci_polledp->ohci_polled_usb_dev, ep_addr);
13030Sstevel@tonic-gate
13040Sstevel@tonic-gate /*
13050Sstevel@tonic-gate * Only the first leave keyboard entry turn off all list processing.
13060Sstevel@tonic-gate * This will take place starting at the next frame.
13070Sstevel@tonic-gate */
13080Sstevel@tonic-gate if (Get_OpReg(hcr_control) & HCR_CONTROL_PLE) {
13090Sstevel@tonic-gate Set_OpReg(hcr_control,
13100Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~HCR_CONTROL_PLE));
13110Sstevel@tonic-gate }
13120Sstevel@tonic-gate
13130Sstevel@tonic-gate /*
13140Sstevel@tonic-gate * Only the last leave keyboard entry restore the info for
13150Sstevel@tonic-gate * normal mode.
13160Sstevel@tonic-gate */
13170Sstevel@tonic-gate if (ohcip->ohci_polled_enter_count == 0) {
13180Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SOF);
13190Sstevel@tonic-gate
13200Sstevel@tonic-gate /*
13210Sstevel@tonic-gate * According to OHCI Specification, we have to wait for eight
13220Sstevel@tonic-gate * start of frames to make sure that the Host Controller writes
13230Sstevel@tonic-gate * contents of done head register to done head filed of HCCA.
13240Sstevel@tonic-gate */
13250Sstevel@tonic-gate for (count = 0; count <= DONE_QUEUE_INTR_COUNTER; count++) {
13260Sstevel@tonic-gate while (!((Get_OpReg(hcr_intr_status)) & HCR_INTR_SOF)) {
13270Sstevel@tonic-gate continue;
13280Sstevel@tonic-gate }
13290Sstevel@tonic-gate /* Acknowledge the SOF interrupt */
13300Sstevel@tonic-gate ohci_polled_finish_interrupt(ohcip, HCR_INTR_SOF);
13310Sstevel@tonic-gate }
13320Sstevel@tonic-gate
13330Sstevel@tonic-gate /*
13340Sstevel@tonic-gate * Check any Frame Number Overflow interrupt (FNO) is pending.
13350Sstevel@tonic-gate */
13360Sstevel@tonic-gate ohci_polled_handle_frame_number_overflow(ohcip);
13370Sstevel@tonic-gate
13380Sstevel@tonic-gate /*
13390Sstevel@tonic-gate * Before switching back, we have to process last TD in the
13400Sstevel@tonic-gate * POLLED mode. It may be in the hcr_done_head register or
13410Sstevel@tonic-gate * in done list or in the lattice. If it is either on the
13420Sstevel@tonic-gate * hcr_done_head register or in the done list, just re-inserted
13430Sstevel@tonic-gate * into the ED's TD list.
13440Sstevel@tonic-gate *
13450Sstevel@tonic-gate * First look up at the TD's that are in the hcr_done_head
13460Sstevel@tonic-gate * register and re-insert them back into the ED's TD list.
13470Sstevel@tonic-gate */
13480Sstevel@tonic-gate td = ohci_td_iommu_to_cpu(ohcip,
13490Sstevel@tonic-gate (uintptr_t)Get_OpReg(hcr_done_head));
13500Sstevel@tonic-gate
13510Sstevel@tonic-gate while (td) {
13520Sstevel@tonic-gate
13530Sstevel@tonic-gate next_td = ohci_td_iommu_to_cpu(ohcip, Get_TD(td->hctd_next_td));
13540Sstevel@tonic-gate
13550Sstevel@tonic-gate /*
13560Sstevel@tonic-gate * Insert valid interrupt TD back into ED's
13570Sstevel@tonic-gate * TD list. No periodic TD's will be processed
13580Sstevel@tonic-gate * since all processing has been stopped.
13590Sstevel@tonic-gate */
13600Sstevel@tonic-gate ohci_polled_insert_td(ohcip, td);
13610Sstevel@tonic-gate
13620Sstevel@tonic-gate td = next_td;
13630Sstevel@tonic-gate }
13640Sstevel@tonic-gate
13650Sstevel@tonic-gate /*
13660Sstevel@tonic-gate * Now look up at the TD's that are in the HCCA done head list &
13670Sstevel@tonic-gate * re-insert them back into the ED's TD list.
13680Sstevel@tonic-gate */
13690Sstevel@tonic-gate td = ohci_td_iommu_to_cpu(ohcip, (Get_HCCA(
13700Sstevel@tonic-gate ohcip->ohci_hccap->HccaDoneHead) & HCCA_DONE_HEAD_MASK));
13710Sstevel@tonic-gate
13720Sstevel@tonic-gate while (td) {
13730Sstevel@tonic-gate
13740Sstevel@tonic-gate next_td = ohci_td_iommu_to_cpu(ohcip,
13750Sstevel@tonic-gate Get_TD(td->hctd_next_td));
13760Sstevel@tonic-gate
13770Sstevel@tonic-gate /*
13780Sstevel@tonic-gate * Insert valid interrupt TD back into ED's
13790Sstevel@tonic-gate * TD list. No periodic TD's will be processed
13800Sstevel@tonic-gate * since all processing has been stopped.
13810Sstevel@tonic-gate */
13820Sstevel@tonic-gate ohci_polled_insert_td(ohcip, td);
13830Sstevel@tonic-gate
13840Sstevel@tonic-gate td = next_td;
13850Sstevel@tonic-gate }
13860Sstevel@tonic-gate /* Reset the HCCA done head list to NULL */
13870Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaDoneHead, NULL);
13880Sstevel@tonic-gate
13890Sstevel@tonic-gate /*
13900Sstevel@tonic-gate * Replace the hcr_done_head register field with the saved copy
13910Sstevel@tonic-gate * of current normal mode hcr_done_head register contents.
13920Sstevel@tonic-gate */
13930Sstevel@tonic-gate Set_OpReg(hcr_done_head,
13940Sstevel@tonic-gate (uint32_t)ohci_polled_regsp->hcr_done_head);
13950Sstevel@tonic-gate
13960Sstevel@tonic-gate /*
13970Sstevel@tonic-gate * Clear the WriteDoneHead and SOF interrupt bits in the ohci
13980Sstevel@tonic-gate * interrupt status register.
13990Sstevel@tonic-gate */
14000Sstevel@tonic-gate Set_OpReg(hcr_intr_status, (HCR_INTR_WDH | HCR_INTR_SOF));
14010Sstevel@tonic-gate }
14020Sstevel@tonic-gate
14030Sstevel@tonic-gate /* Get the polled mode ohci pipe private structure */
14040Sstevel@tonic-gate polled_pp = (ohci_pipe_private_t *)
14050Sstevel@tonic-gate ohci_polledp->ohci_polled_input_pipe_handle->p_hcd_private;
14060Sstevel@tonic-gate
14070Sstevel@tonic-gate /*
14080Sstevel@tonic-gate * Before replacing the lattice, adjust the data togggle
14090Sstevel@tonic-gate * on the on the ohci's interrupt ed
14100Sstevel@tonic-gate */
14110Sstevel@tonic-gate polled_toggle = (Get_ED(polled_pp->pp_ept->hced_headp) &
14127425SGongtian.Zhao@Sun.COM HC_EPT_Carry) ? DATA1:DATA0;
14130Sstevel@tonic-gate
14140Sstevel@tonic-gate /*
14150Sstevel@tonic-gate * If normal mode interrupt pipe endpoint is active, fix the
14160Sstevel@tonic-gate * data toggle for this interrupt endpoint by getting the data
14170Sstevel@tonic-gate * toggle information from the polled interrupt endpoint. Else
14180Sstevel@tonic-gate * save the data toggle information in usb device structure.
14190Sstevel@tonic-gate */
14200Sstevel@tonic-gate if (ph) {
14210Sstevel@tonic-gate /* Get the normal mode ohci pipe private structure */
14220Sstevel@tonic-gate pp = (ohci_pipe_private_t *)ph->p_hcd_private;
14230Sstevel@tonic-gate
14240Sstevel@tonic-gate real_toggle = (Get_ED(pp->pp_ept->hced_headp) &
14250Sstevel@tonic-gate HC_EPT_Carry) ? DATA1:DATA0;
14260Sstevel@tonic-gate
14270Sstevel@tonic-gate if (polled_toggle != real_toggle) {
14280Sstevel@tonic-gate if (polled_toggle == DATA0) {
14290Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp,
14300Sstevel@tonic-gate Get_ED(pp->pp_ept->hced_headp) &
14310Sstevel@tonic-gate ~HC_EPT_Carry);
14320Sstevel@tonic-gate } else {
14330Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp,
14340Sstevel@tonic-gate Get_ED(pp->pp_ept->hced_headp) |
14350Sstevel@tonic-gate HC_EPT_Carry);
14360Sstevel@tonic-gate }
14370Sstevel@tonic-gate }
14380Sstevel@tonic-gate } else {
14390Sstevel@tonic-gate usba_hcdi_set_data_toggle(ohci_polledp->ohci_polled_usb_dev,
14400Sstevel@tonic-gate ep_addr, polled_toggle);
14410Sstevel@tonic-gate }
14420Sstevel@tonic-gate /*
14430Sstevel@tonic-gate * Only the last leave keyboard entry restore the Interrupt table,
14440Sstevel@tonic-gate * start processing and enable the interrupt.
14450Sstevel@tonic-gate */
14460Sstevel@tonic-gate if (ohcip->ohci_polled_enter_count == 0) {
14470Sstevel@tonic-gate /* Replace the lattice */
14480Sstevel@tonic-gate for (i = 0; i < NUM_INTR_ED_LISTS; i++) {
14490Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaIntTble[i],
14500Sstevel@tonic-gate (uintptr_t)ohcip->ohci_polled_save_IntTble[i]);
14510Sstevel@tonic-gate }
14520Sstevel@tonic-gate
14530Sstevel@tonic-gate /*
14540Sstevel@tonic-gate * Clear the contents of current ohci periodic ED register that
14550Sstevel@tonic-gate * is physical address of current Isochronous or Interrupt ED.
14560Sstevel@tonic-gate */
14570Sstevel@tonic-gate Set_OpReg(hcr_periodic_curr, (uint32_t)0x0);
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate ohci_polled_start_processing(ohci_polledp);
14600Sstevel@tonic-gate
14610Sstevel@tonic-gate /*
14620Sstevel@tonic-gate * Check and enable required ohci interrupts before switching
14630Sstevel@tonic-gate * back to normal mode from the POLLED mode.
14640Sstevel@tonic-gate */
14650Sstevel@tonic-gate mask = (uint32_t)ohci_polled_regsp->hcr_intr_enable &
14660Sstevel@tonic-gate (HCR_INTR_SOF | HCR_INTR_WDH);
14670Sstevel@tonic-gate
14680Sstevel@tonic-gate if (ohci_intr_sts->ohci_intr_flag & OHCI_INTR_HANDLING) {
14690Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, mask);
14700Sstevel@tonic-gate } else {
14710Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, mask | HCR_INTR_MIE);
14720Sstevel@tonic-gate }
14730Sstevel@tonic-gate }
14740Sstevel@tonic-gate #ifndef lint
14750Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW);
14760Sstevel@tonic-gate #endif
14770Sstevel@tonic-gate }
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate * ohci_polled_start_processing:
14810Sstevel@tonic-gate */
14820Sstevel@tonic-gate static void
ohci_polled_start_processing(ohci_polled_t * ohci_polledp)14830Sstevel@tonic-gate ohci_polled_start_processing(ohci_polled_t *ohci_polledp)
14840Sstevel@tonic-gate {
14850Sstevel@tonic-gate ohci_state_t *ohcip;
14860Sstevel@tonic-gate uint32_t control;
14870Sstevel@tonic-gate uint32_t mask;
14880Sstevel@tonic-gate ohci_regs_t *ohci_polled_regsp;
14890Sstevel@tonic-gate
14900Sstevel@tonic-gate ohcip = ohci_polledp->ohci_polled_ohcip;
14910Sstevel@tonic-gate ohci_polled_regsp = &ohcip->ohci_polled_save_regs;
14920Sstevel@tonic-gate
14930Sstevel@tonic-gate mask = ((uint32_t)ohci_polled_regsp->hcr_control) & (HCR_CONTROL_CLE |
14940Sstevel@tonic-gate HCR_CONTROL_PLE | HCR_CONTROL_BLE | HCR_CONTROL_IE);
14950Sstevel@tonic-gate
14960Sstevel@tonic-gate control = Get_OpReg(hcr_control) & ~(HCR_CONTROL_CLE |
14970Sstevel@tonic-gate HCR_CONTROL_PLE | HCR_CONTROL_BLE | HCR_CONTROL_IE);
14980Sstevel@tonic-gate
14990Sstevel@tonic-gate Set_OpReg(hcr_control, (control | mask));
15000Sstevel@tonic-gate }
15010Sstevel@tonic-gate
15020Sstevel@tonic-gate
15030Sstevel@tonic-gate /*
15040Sstevel@tonic-gate * Polled read routines
15050Sstevel@tonic-gate */
15060Sstevel@tonic-gate /*
15070Sstevel@tonic-gate * ohci_polled_check_done_list:
15080Sstevel@tonic-gate *
15090Sstevel@tonic-gate * Check to see it there are any TD's on the done head. If there are
15100Sstevel@tonic-gate * then reverse the done list and put the TD's on the appropriated list.
15110Sstevel@tonic-gate */
15120Sstevel@tonic-gate static int
ohci_polled_check_done_list(ohci_polled_t * ohci_polledp)15130Sstevel@tonic-gate ohci_polled_check_done_list(ohci_polled_t *ohci_polledp)
15140Sstevel@tonic-gate {
15150Sstevel@tonic-gate ohci_state_t *ohcip = ohci_polledp->ohci_polled_ohcip;
15160Sstevel@tonic-gate ohci_td_t *done_head, *done_list;
15170Sstevel@tonic-gate
15180Sstevel@tonic-gate /* Sync HCCA area */
15190Sstevel@tonic-gate if (ohci_polledp->ohci_polled_no_sync_flag == B_FALSE) {
15200Sstevel@tonic-gate Sync_HCCA(ohcip);
15210Sstevel@tonic-gate }
15220Sstevel@tonic-gate
15230Sstevel@tonic-gate /* Read and Save the HCCA DoneHead value */
15240Sstevel@tonic-gate done_head = (ohci_td_t *)(uintptr_t)
15250Sstevel@tonic-gate (Get_HCCA(ohcip->ohci_hccap->HccaDoneHead) & HCCA_DONE_HEAD_MASK);
15260Sstevel@tonic-gate
15270Sstevel@tonic-gate /*
15280Sstevel@tonic-gate * Look at the Done Head and if it is NULL and ohci done list is NULL,
15290Sstevel@tonic-gate * just return; else if ohci done list is not NULL, should check it.
15300Sstevel@tonic-gate */
15310Sstevel@tonic-gate if (done_head == NULL) {
15320Sstevel@tonic-gate if (ohcip->ohci_polled_done_list) {
15330Sstevel@tonic-gate done_head = ohcip->ohci_polled_done_list;
1534*9095SZhigang.Lu@Sun.COM ohcip->ohci_polled_done_list = NULL;
15350Sstevel@tonic-gate } else {
15360Sstevel@tonic-gate
15370Sstevel@tonic-gate return (USB_FAILURE);
15380Sstevel@tonic-gate }
15390Sstevel@tonic-gate } else {
15400Sstevel@tonic-gate /* Reset the done head to NULL */
15410Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaDoneHead, NULL);
15420Sstevel@tonic-gate }
15430Sstevel@tonic-gate
15440Sstevel@tonic-gate /* Sync ED and TD pool */
15450Sstevel@tonic-gate if (ohci_polledp->ohci_polled_no_sync_flag == B_FALSE) {
15460Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip);
15470Sstevel@tonic-gate }
15480Sstevel@tonic-gate
15490Sstevel@tonic-gate /* Pickup own tds in the done head */
15500Sstevel@tonic-gate done_list = ohci_polled_pickup_done_list(ohci_polledp, done_head);
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate /*
15530Sstevel@tonic-gate * Look at the own done list which is pickup'ed
15540Sstevel@tonic-gate * and if it is NULL, just return.
15550Sstevel@tonic-gate */
15560Sstevel@tonic-gate if (done_list == NULL) {
15570Sstevel@tonic-gate
15580Sstevel@tonic-gate return (USB_FAILURE);
15590Sstevel@tonic-gate }
15600Sstevel@tonic-gate /* Create the input done list */
15610Sstevel@tonic-gate ohci_polled_create_input_list(ohci_polledp, done_list);
15620Sstevel@tonic-gate
15630Sstevel@tonic-gate return (USB_SUCCESS);
15640Sstevel@tonic-gate }
15650Sstevel@tonic-gate
1566*9095SZhigang.Lu@Sun.COM
15670Sstevel@tonic-gate /*
15680Sstevel@tonic-gate * ohci_polled_pickup_done_list:
15690Sstevel@tonic-gate *
15700Sstevel@tonic-gate * Pickup the TDs of own in the Done Head List
15710Sstevel@tonic-gate */
15720Sstevel@tonic-gate static ohci_td_t *
ohci_polled_pickup_done_list(ohci_polled_t * ohci_polledp,ohci_td_t * done_head)15730Sstevel@tonic-gate ohci_polled_pickup_done_list(
15740Sstevel@tonic-gate ohci_polled_t *ohci_polledp,
15750Sstevel@tonic-gate ohci_td_t *done_head)
15760Sstevel@tonic-gate {
15770Sstevel@tonic-gate ohci_state_t *ohcip = ohci_polledp->ohci_polled_ohcip;
15780Sstevel@tonic-gate ohci_td_t *create_head = NULL, *current_td, *td;
15790Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
15800Sstevel@tonic-gate ohci_pipe_private_t *pp;
15810Sstevel@tonic-gate
15820Sstevel@tonic-gate /*
15830Sstevel@tonic-gate * Current_td pointers point to the done head.
15840Sstevel@tonic-gate */
15850Sstevel@tonic-gate current_td = (ohci_td_t *)
15860Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, (uintptr_t)done_head);
15870Sstevel@tonic-gate while (current_td) {
15880Sstevel@tonic-gate td = (ohci_td_t *)ohci_td_iommu_to_cpu(ohcip,
15890Sstevel@tonic-gate Get_TD(current_td->hctd_next_td));
15900Sstevel@tonic-gate
15910Sstevel@tonic-gate Set_TD(current_td->hctd_next_td, NULL);
15920Sstevel@tonic-gate
15930Sstevel@tonic-gate /* Obtain the transfer wrapper from the TD */
15940Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID(
15950Sstevel@tonic-gate (uint32_t)Get_TD(current_td->hctd_trans_wrapper));
15960Sstevel@tonic-gate
15970Sstevel@tonic-gate /* Get the pipe handle for this transfer wrapper. */
15980Sstevel@tonic-gate pp = tw->tw_pipe_private;
15990Sstevel@tonic-gate
16000Sstevel@tonic-gate /*
1601*9095SZhigang.Lu@Sun.COM * Figure out which done list to put this TD on and put it
1602*9095SZhigang.Lu@Sun.COM * there. If the pipe handle of the TD matches the pipe
16030Sstevel@tonic-gate * handle we are using for the input device, then this must
16040Sstevel@tonic-gate * be an input TD, reverse the order and link to the list for
16050Sstevel@tonic-gate * this input device. Else put the TD to the reserve done list
16060Sstevel@tonic-gate * for other input devices.
16070Sstevel@tonic-gate */
16080Sstevel@tonic-gate
16090Sstevel@tonic-gate if (pp->pp_pipe_handle ==
16100Sstevel@tonic-gate ohci_polledp->ohci_polled_input_pipe_handle) {
16110Sstevel@tonic-gate if (create_head == NULL) {
16120Sstevel@tonic-gate create_head = current_td;
16130Sstevel@tonic-gate } else {
16140Sstevel@tonic-gate Set_TD(current_td->hctd_next_td,
16150Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, create_head));
16160Sstevel@tonic-gate create_head = current_td;
16170Sstevel@tonic-gate }
16180Sstevel@tonic-gate } else {
1619*9095SZhigang.Lu@Sun.COM if (ohcip->ohci_polled_done_list == NULL) {
1620*9095SZhigang.Lu@Sun.COM ohcip->ohci_polled_done_list = (ohci_td_t *)
1621*9095SZhigang.Lu@Sun.COM (uintptr_t)ohci_td_cpu_to_iommu(ohcip,
1622*9095SZhigang.Lu@Sun.COM current_td);
16230Sstevel@tonic-gate } else {
1624*9095SZhigang.Lu@Sun.COM Set_TD(current_td->hctd_next_td,
1625*9095SZhigang.Lu@Sun.COM ohcip->ohci_polled_done_list);
1626*9095SZhigang.Lu@Sun.COM ohcip->ohci_polled_done_list = (ohci_td_t *)
1627*9095SZhigang.Lu@Sun.COM (uintptr_t)ohci_td_cpu_to_iommu(ohcip,
1628*9095SZhigang.Lu@Sun.COM current_td);
16290Sstevel@tonic-gate }
16300Sstevel@tonic-gate }
16310Sstevel@tonic-gate current_td = td;
16320Sstevel@tonic-gate }
16330Sstevel@tonic-gate
16340Sstevel@tonic-gate return (create_head);
16350Sstevel@tonic-gate }
16360Sstevel@tonic-gate
1637*9095SZhigang.Lu@Sun.COM
16380Sstevel@tonic-gate /*
16390Sstevel@tonic-gate * ohci_polled_create_input_list:
16400Sstevel@tonic-gate *
16410Sstevel@tonic-gate * Create the input done list from the actual done head list.
16420Sstevel@tonic-gate */
16430Sstevel@tonic-gate static void
ohci_polled_create_input_list(ohci_polled_t * ohci_polledp,ohci_td_t * head_done_list)16440Sstevel@tonic-gate ohci_polled_create_input_list(
16450Sstevel@tonic-gate ohci_polled_t *ohci_polledp,
16460Sstevel@tonic-gate ohci_td_t *head_done_list)
16470Sstevel@tonic-gate {
16480Sstevel@tonic-gate ohci_state_t *ohcip = ohci_polledp->ohci_polled_ohcip;
16490Sstevel@tonic-gate ohci_td_t *cpu_save, *td;
16500Sstevel@tonic-gate
16510Sstevel@tonic-gate ASSERT(head_done_list != NULL);
16520Sstevel@tonic-gate
16530Sstevel@tonic-gate /* Get the done head list */
16540Sstevel@tonic-gate td = (ohci_td_t *)head_done_list;
16550Sstevel@tonic-gate
16560Sstevel@tonic-gate /*
16570Sstevel@tonic-gate * Traverse the done list and create the input done list.
16580Sstevel@tonic-gate */
16590Sstevel@tonic-gate while (td) {
16600Sstevel@tonic-gate
16610Sstevel@tonic-gate /*
16620Sstevel@tonic-gate * Convert the iommu pointer to a cpu pointer. No point
16630Sstevel@tonic-gate * in doing this over and over, might as well do it once.
16640Sstevel@tonic-gate */
16650Sstevel@tonic-gate cpu_save = ohci_td_iommu_to_cpu(ohcip,
16660Sstevel@tonic-gate Get_TD(td->hctd_next_td));
16670Sstevel@tonic-gate
16680Sstevel@tonic-gate /*
16690Sstevel@tonic-gate * Terminate this TD by setting its next pointer to NULL.
16700Sstevel@tonic-gate */
16710Sstevel@tonic-gate Set_TD(td->hctd_next_td, NULL);
16720Sstevel@tonic-gate
16730Sstevel@tonic-gate /* This is an input TD, so put it on the input done list */
16740Sstevel@tonic-gate if (ohci_polledp->ohci_polled_input_done_head == NULL) {
16750Sstevel@tonic-gate
16760Sstevel@tonic-gate /*
16770Sstevel@tonic-gate * There is nothing on the input done list,
16780Sstevel@tonic-gate * so put this TD on the head.
16790Sstevel@tonic-gate */
16800Sstevel@tonic-gate ohci_polledp->ohci_polled_input_done_head = td;
16810Sstevel@tonic-gate } else {
16820Sstevel@tonic-gate Set_TD(ohci_polledp->
16830Sstevel@tonic-gate ohci_polled_input_done_tail->hctd_next_td,
16840Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, td));
16850Sstevel@tonic-gate }
16860Sstevel@tonic-gate
16870Sstevel@tonic-gate /* The tail points to the new TD */
16880Sstevel@tonic-gate ohci_polledp->ohci_polled_input_done_tail = td;
16890Sstevel@tonic-gate td = cpu_save;
16900Sstevel@tonic-gate }
16910Sstevel@tonic-gate }
16920Sstevel@tonic-gate
16930Sstevel@tonic-gate
16940Sstevel@tonic-gate /*
16950Sstevel@tonic-gate * ohci_polled_process_input_list:
16960Sstevel@tonic-gate *
16970Sstevel@tonic-gate * This routine takes the TD's off of the input done head and processes
16980Sstevel@tonic-gate * them. It returns the number of characters that have been copied for
16990Sstevel@tonic-gate * input.
17000Sstevel@tonic-gate */
17010Sstevel@tonic-gate static int
ohci_polled_process_input_list(ohci_polled_t * ohci_polledp)17020Sstevel@tonic-gate ohci_polled_process_input_list(ohci_polled_t *ohci_polledp)
17030Sstevel@tonic-gate {
17040Sstevel@tonic-gate ohci_state_t *ohcip = ohci_polledp->ohci_polled_ohcip;
17050Sstevel@tonic-gate ohci_td_t *td, *next_td;
17060Sstevel@tonic-gate uint_t ctrl;
17070Sstevel@tonic-gate uint_t num_characters;
17080Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
17090Sstevel@tonic-gate ohci_pipe_private_t *pp;
1710*9095SZhigang.Lu@Sun.COM int pipe_dir;
17110Sstevel@tonic-gate
17120Sstevel@tonic-gate /*
17130Sstevel@tonic-gate * Get the first TD on the input done head.
17140Sstevel@tonic-gate */
17150Sstevel@tonic-gate td = ohci_polledp->ohci_polled_input_done_head;
17160Sstevel@tonic-gate
17170Sstevel@tonic-gate ohci_polledp->ohci_polled_input_done_head = NULL;
17180Sstevel@tonic-gate
17190Sstevel@tonic-gate num_characters = 0;
17200Sstevel@tonic-gate
17210Sstevel@tonic-gate /*
17220Sstevel@tonic-gate * Traverse the list of transfer descriptors. We can't destroy
17230Sstevel@tonic-gate * hctd_next_td pointers of these TDs because we are using it
17240Sstevel@tonic-gate * to traverse the done list. Therefore, we can not put these
17250Sstevel@tonic-gate * TDs back on the ED until we are done processing all of them.
17260Sstevel@tonic-gate */
17270Sstevel@tonic-gate while (td) {
17280Sstevel@tonic-gate
17290Sstevel@tonic-gate /* Get the next TD from the input done list */
17300Sstevel@tonic-gate next_td = (ohci_td_t *)
17310Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, Get_TD(td->hctd_next_td));
17320Sstevel@tonic-gate
17330Sstevel@tonic-gate /* Look at the status */
17340Sstevel@tonic-gate ctrl = (uint_t)Get_TD(td->hctd_ctrl) & (uint32_t)HC_TD_CC;
17350Sstevel@tonic-gate
17360Sstevel@tonic-gate /*
17370Sstevel@tonic-gate * Check to see if there is an error. If there is error
17380Sstevel@tonic-gate * clear the halt condition in the Endpoint Descriptor
17390Sstevel@tonic-gate * (ED) associated with this Transfer Descriptor (TD).
17400Sstevel@tonic-gate */
17410Sstevel@tonic-gate if (ctrl != HC_TD_CC_NO_E) {
17420Sstevel@tonic-gate /* Obtain the transfer wrapper from the TD */
17430Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID(
17440Sstevel@tonic-gate (uint32_t)Get_TD(td->hctd_trans_wrapper));
17450Sstevel@tonic-gate
17460Sstevel@tonic-gate /* Get the pipe handle for this transfer wrapper */
17470Sstevel@tonic-gate pp = tw->tw_pipe_private;
17480Sstevel@tonic-gate
17490Sstevel@tonic-gate /* Clear the halt bit */
17500Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp,
17510Sstevel@tonic-gate (Get_ED(pp->pp_ept->hced_headp) & ~HC_EPT_Halt));
17520Sstevel@tonic-gate }
17530Sstevel@tonic-gate
1754*9095SZhigang.Lu@Sun.COM /* Obtain the transfer wrapper from the TD */
1755*9095SZhigang.Lu@Sun.COM tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID(
1756*9095SZhigang.Lu@Sun.COM (uint32_t)Get_TD(td->hctd_trans_wrapper));
1757*9095SZhigang.Lu@Sun.COM
1758*9095SZhigang.Lu@Sun.COM /* Get the pipe direction for this transfer wrapper */
1759*9095SZhigang.Lu@Sun.COM pipe_dir = tw->tw_pipe_private->pp_pipe_handle->
1760*9095SZhigang.Lu@Sun.COM p_ep.bEndpointAddress & USB_EP_DIR_MASK;
1761*9095SZhigang.Lu@Sun.COM
1762*9095SZhigang.Lu@Sun.COM switch (pipe_dir) {
1763*9095SZhigang.Lu@Sun.COM case USB_EP_DIR_IN:
1764*9095SZhigang.Lu@Sun.COM num_characters +=
1765*9095SZhigang.Lu@Sun.COM ohci_polled_handle_normal_td(ohci_polledp,
1766*9095SZhigang.Lu@Sun.COM td);
1767*9095SZhigang.Lu@Sun.COM
1768*9095SZhigang.Lu@Sun.COM /*
1769*9095SZhigang.Lu@Sun.COM * Insert this TD back
1770*9095SZhigang.Lu@Sun.COM * onto the ED's TD list
1771*9095SZhigang.Lu@Sun.COM */
1772*9095SZhigang.Lu@Sun.COM ohci_polled_insert_td(ohcip, td);
1773*9095SZhigang.Lu@Sun.COM break;
1774*9095SZhigang.Lu@Sun.COM case USB_EP_DIR_OUT:
1775*9095SZhigang.Lu@Sun.COM ASSERT((ohci_td_t *)tw->tw_hctd_head == td);
1776*9095SZhigang.Lu@Sun.COM
1777*9095SZhigang.Lu@Sun.COM tw->tw_hctd_head = (ohci_td_t *)
1778*9095SZhigang.Lu@Sun.COM ohci_td_iommu_to_cpu(ohcip,
1779*9095SZhigang.Lu@Sun.COM Get_TD(td->hctd_tw_next_td));
1780*9095SZhigang.Lu@Sun.COM Set_TD(td->hctd_state, HC_TD_DUMMY);
1781*9095SZhigang.Lu@Sun.COM
1782*9095SZhigang.Lu@Sun.COM if (tw->tw_hctd_head == NULL) {
1783*9095SZhigang.Lu@Sun.COM tw->tw_hctd_tail = NULL;
1784*9095SZhigang.Lu@Sun.COM }
1785*9095SZhigang.Lu@Sun.COM
1786*9095SZhigang.Lu@Sun.COM if (tw->tw_hctd_free_list != NULL) {
1787*9095SZhigang.Lu@Sun.COM uint32_t td_addr;
1788*9095SZhigang.Lu@Sun.COM td_addr = ohci_td_cpu_to_iommu(ohcip,
1789*9095SZhigang.Lu@Sun.COM tw->tw_hctd_free_list);
1790*9095SZhigang.Lu@Sun.COM Set_TD(td->hctd_tw_next_td, td_addr);
1791*9095SZhigang.Lu@Sun.COM tw->tw_hctd_free_list = td;
1792*9095SZhigang.Lu@Sun.COM } else {
1793*9095SZhigang.Lu@Sun.COM tw->tw_hctd_free_list = td;
1794*9095SZhigang.Lu@Sun.COM Set_TD(td->hctd_tw_next_td, NULL);
1795*9095SZhigang.Lu@Sun.COM }
1796*9095SZhigang.Lu@Sun.COM break;
1797*9095SZhigang.Lu@Sun.COM }
17980Sstevel@tonic-gate
17990Sstevel@tonic-gate td = next_td;
18000Sstevel@tonic-gate }
18010Sstevel@tonic-gate
18020Sstevel@tonic-gate return (num_characters);
18030Sstevel@tonic-gate }
18040Sstevel@tonic-gate
18050Sstevel@tonic-gate
18060Sstevel@tonic-gate /*
18070Sstevel@tonic-gate * ohci_polled_handle_normal_td:
18080Sstevel@tonic-gate */
18090Sstevel@tonic-gate static int
ohci_polled_handle_normal_td(ohci_polled_t * ohci_polledp,ohci_td_t * td)18100Sstevel@tonic-gate ohci_polled_handle_normal_td(
18110Sstevel@tonic-gate ohci_polled_t *ohci_polledp,
18120Sstevel@tonic-gate ohci_td_t *td)
18130Sstevel@tonic-gate {
18140Sstevel@tonic-gate ohci_state_t *ohcip = ohci_polledp->ohci_polled_ohcip;
18150Sstevel@tonic-gate uchar_t *buf;
18160Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
18172125Ssl147100 size_t length, residue;
18180Sstevel@tonic-gate
18190Sstevel@tonic-gate /* Obtain the transfer wrapper from the TD */
18200Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID((uint32_t)
18210Sstevel@tonic-gate Get_TD(td->hctd_trans_wrapper));
18220Sstevel@tonic-gate
18230Sstevel@tonic-gate ASSERT(tw != NULL);
18240Sstevel@tonic-gate
18250Sstevel@tonic-gate buf = (uchar_t *)tw->tw_buf;
18260Sstevel@tonic-gate
18270Sstevel@tonic-gate length = tw->tw_length;
18280Sstevel@tonic-gate /*
18290Sstevel@tonic-gate * If "CurrentBufferPointer" of Transfer Descriptor (TD) is
18300Sstevel@tonic-gate * not equal to zero, then we received less data from the
18310Sstevel@tonic-gate * device than requested by us. In that case, get the actual
18320Sstevel@tonic-gate * received data size.
18330Sstevel@tonic-gate */
18340Sstevel@tonic-gate if (Get_TD(td->hctd_cbp)) {
18350Sstevel@tonic-gate
18362125Ssl147100 residue = ohci_get_td_residue(ohcip, td);
18372125Ssl147100 length = Get_TD(td->hctd_xfer_offs) +
18382125Ssl147100 Get_TD(td->hctd_xfer_len) - residue;
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate
18410Sstevel@tonic-gate /* Sync IO buffer */
18420Sstevel@tonic-gate if (ohci_polledp->ohci_polled_no_sync_flag == B_FALSE) {
18430Sstevel@tonic-gate Sync_IO_Buffer(tw->tw_dmahandle, length);
18440Sstevel@tonic-gate }
18450Sstevel@tonic-gate
1846*9095SZhigang.Lu@Sun.COM /* Copy the data into the message */
18470Sstevel@tonic-gate ddi_rep_get8(tw->tw_accesshandle,
18480Sstevel@tonic-gate (uint8_t *)ohci_polledp->ohci_polled_buf,
18490Sstevel@tonic-gate (uint8_t *)buf, length, DDI_DEV_AUTOINCR);
18500Sstevel@tonic-gate
18517492SZhigang.Lu@Sun.COM return ((int)length);
18520Sstevel@tonic-gate }
18530Sstevel@tonic-gate
18540Sstevel@tonic-gate
18550Sstevel@tonic-gate /*
18560Sstevel@tonic-gate * ohci_polled_insert_td:
18570Sstevel@tonic-gate *
18580Sstevel@tonic-gate * Insert a Transfer Descriptor (TD) on an Endpoint Descriptor (ED).
18590Sstevel@tonic-gate */
18600Sstevel@tonic-gate static void
ohci_polled_insert_td(ohci_state_t * ohcip,ohci_td_t * td)18610Sstevel@tonic-gate ohci_polled_insert_td(
18620Sstevel@tonic-gate ohci_state_t *ohcip,
18630Sstevel@tonic-gate ohci_td_t *td)
18640Sstevel@tonic-gate {
18650Sstevel@tonic-gate ohci_pipe_private_t *pp;
18660Sstevel@tonic-gate ohci_ed_t *ept;
18670Sstevel@tonic-gate uint_t td_control;
18680Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
18690Sstevel@tonic-gate ohci_td_t *cpu_current_dummy;
18700Sstevel@tonic-gate usb_intr_req_t *intr_req;
1871*9095SZhigang.Lu@Sun.COM usba_pipe_handle_data_t *ph;
1872*9095SZhigang.Lu@Sun.COM int pipe_attr;
18730Sstevel@tonic-gate
18740Sstevel@tonic-gate /* Obtain the transfer wrapper from the TD */
18750Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID(
18760Sstevel@tonic-gate (uint32_t)Get_TD(td->hctd_trans_wrapper));
18770Sstevel@tonic-gate
18782125Ssl147100 /* Ensure the DMA cookie is valid for reuse */
18792125Ssl147100 ASSERT((tw->tw_cookie_idx == 0) && (tw->tw_dma_offs == 0));
18802125Ssl147100
18810Sstevel@tonic-gate /*
18820Sstevel@tonic-gate * Take this TD off the transfer wrapper's list since
18830Sstevel@tonic-gate * the pipe is FIFO, this must be the first TD on the
18840Sstevel@tonic-gate * list.
18850Sstevel@tonic-gate */
18860Sstevel@tonic-gate ASSERT((ohci_td_t *)tw->tw_hctd_head == td);
18870Sstevel@tonic-gate
18880Sstevel@tonic-gate tw->tw_hctd_head = (ohci_td_t *)
18890Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, Get_TD(td->hctd_tw_next_td));
18900Sstevel@tonic-gate
18910Sstevel@tonic-gate /*
18920Sstevel@tonic-gate * If the head becomes NULL, then there are no more
18930Sstevel@tonic-gate * active TD's for this transfer wrapper. Also set
18940Sstevel@tonic-gate * the tail to NULL.
18950Sstevel@tonic-gate */
18960Sstevel@tonic-gate if (tw->tw_hctd_head == NULL) {
18970Sstevel@tonic-gate tw->tw_hctd_tail = NULL;
18980Sstevel@tonic-gate }
18990Sstevel@tonic-gate
19000Sstevel@tonic-gate /* Convert current valid TD as new dummy TD */
19010Sstevel@tonic-gate bzero((char *)td, sizeof (ohci_td_t));
19020Sstevel@tonic-gate Set_TD(td->hctd_state, HC_TD_DUMMY);
19030Sstevel@tonic-gate
19040Sstevel@tonic-gate pp = tw->tw_pipe_private;
1905*9095SZhigang.Lu@Sun.COM ph = pp->pp_pipe_handle;
19060Sstevel@tonic-gate
1907*9095SZhigang.Lu@Sun.COM /* Obtain the endpoint and the request */
19080Sstevel@tonic-gate ept = pp->pp_ept;
19090Sstevel@tonic-gate
1910*9095SZhigang.Lu@Sun.COM /* Get the pipe attribute */
1911*9095SZhigang.Lu@Sun.COM pipe_attr = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
1912*9095SZhigang.Lu@Sun.COM
1913*9095SZhigang.Lu@Sun.COM switch (pipe_attr) {
1914*9095SZhigang.Lu@Sun.COM case USB_EP_ATTR_INTR:
1915*9095SZhigang.Lu@Sun.COM intr_req = (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
19160Sstevel@tonic-gate
1917*9095SZhigang.Lu@Sun.COM if (intr_req->intr_attributes & USB_ATTRS_SHORT_XFER_OK) {
1918*9095SZhigang.Lu@Sun.COM td_control = HC_TD_IN|HC_TD_1I|HC_TD_R;
1919*9095SZhigang.Lu@Sun.COM } else {
1920*9095SZhigang.Lu@Sun.COM td_control = HC_TD_IN|HC_TD_1I;
1921*9095SZhigang.Lu@Sun.COM }
1922*9095SZhigang.Lu@Sun.COM break;
1923*9095SZhigang.Lu@Sun.COM case USB_EP_ATTR_BULK:
1924*9095SZhigang.Lu@Sun.COM td_control = tw->tw_direction|HC_TD_DT_0|HC_TD_1I|HC_TD_R;
1925*9095SZhigang.Lu@Sun.COM break;
19260Sstevel@tonic-gate }
19270Sstevel@tonic-gate
19280Sstevel@tonic-gate /* Get the current dummy */
19290Sstevel@tonic-gate cpu_current_dummy = (ohci_td_t *)
19300Sstevel@tonic-gate (ohci_td_iommu_to_cpu(ohcip, Get_ED(ept->hced_tailp)));
19310Sstevel@tonic-gate
19320Sstevel@tonic-gate /*
19330Sstevel@tonic-gate * Fill in the current dummy td and
19340Sstevel@tonic-gate * add the new dummy to the end.
19350Sstevel@tonic-gate */
19360Sstevel@tonic-gate ohci_polled_fill_in_td(ohcip, cpu_current_dummy, td,
19372125Ssl147100 td_control, 0, tw->tw_length, tw);
19380Sstevel@tonic-gate
19390Sstevel@tonic-gate /* Insert this td onto the tw */
19400Sstevel@tonic-gate ohci_polled_insert_td_on_tw(ohcip, tw, cpu_current_dummy);
19410Sstevel@tonic-gate
19420Sstevel@tonic-gate /*
19430Sstevel@tonic-gate * Add the new dummy to the ED's list. When this occurs,
19440Sstevel@tonic-gate * the Host Controller will see the newly filled in dummy
19450Sstevel@tonic-gate * TD.
19460Sstevel@tonic-gate */
19470Sstevel@tonic-gate Set_ED(ept->hced_tailp, (ohci_td_cpu_to_iommu(ohcip, td)));
19480Sstevel@tonic-gate }
19490Sstevel@tonic-gate
19500Sstevel@tonic-gate
19510Sstevel@tonic-gate /*
19520Sstevel@tonic-gate * ohci_polled_fill_in_td:
19530Sstevel@tonic-gate *
19540Sstevel@tonic-gate * Fill in the fields of a Transfer Descriptor (TD).
19550Sstevel@tonic-gate */
19560Sstevel@tonic-gate static void
ohci_polled_fill_in_td(ohci_state_t * ohcip,ohci_td_t * td,ohci_td_t * new_dummy,uint_t hctd_ctrl,uint32_t hctd_dma_offs,size_t hctd_length,ohci_trans_wrapper_t * tw)19570Sstevel@tonic-gate ohci_polled_fill_in_td(
19580Sstevel@tonic-gate ohci_state_t *ohcip,
19590Sstevel@tonic-gate ohci_td_t *td,
19600Sstevel@tonic-gate ohci_td_t *new_dummy,
19610Sstevel@tonic-gate uint_t hctd_ctrl,
19622125Ssl147100 uint32_t hctd_dma_offs,
19630Sstevel@tonic-gate size_t hctd_length,
19640Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
19650Sstevel@tonic-gate {
19660Sstevel@tonic-gate /* Assert that the td to be filled in is a dummy */
19670Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_state) == HC_TD_DUMMY);
19680Sstevel@tonic-gate
19690Sstevel@tonic-gate /* Clear the TD */
19700Sstevel@tonic-gate bzero((char *)td, sizeof (ohci_td_t));
19710Sstevel@tonic-gate
19720Sstevel@tonic-gate /* Update the dummy with control information */
19730Sstevel@tonic-gate Set_TD(td->hctd_ctrl, (hctd_ctrl | HC_TD_CC_NA));
19740Sstevel@tonic-gate
19752125Ssl147100 /* Update the beginning and end of the buffer */
19762125Ssl147100 ohci_init_td(ohcip, tw, hctd_dma_offs, hctd_length, td);
19770Sstevel@tonic-gate
19780Sstevel@tonic-gate /* The current dummy now points to the new dummy */
19790Sstevel@tonic-gate Set_TD(td->hctd_next_td, (ohci_td_cpu_to_iommu(ohcip, new_dummy)));
19800Sstevel@tonic-gate
19810Sstevel@tonic-gate /* Fill in the wrapper portion of the TD */
19820Sstevel@tonic-gate Set_TD(td->hctd_trans_wrapper, (uint32_t)tw->tw_id);
19830Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, NULL);
19840Sstevel@tonic-gate }
19850Sstevel@tonic-gate
19860Sstevel@tonic-gate
19870Sstevel@tonic-gate /*
19880Sstevel@tonic-gate * ohci_polled_insert_td_on_tw:
19890Sstevel@tonic-gate *
19900Sstevel@tonic-gate * The transfer wrapper keeps a list of all Transfer Descriptors (TD) that
19910Sstevel@tonic-gate * are allocated for this transfer. Insert a TD onto this list. The list
19920Sstevel@tonic-gate * of TD's does not include the dummy TD that is at the end of the list of
19930Sstevel@tonic-gate * TD's for the endpoint.
19940Sstevel@tonic-gate */
19950Sstevel@tonic-gate static void
ohci_polled_insert_td_on_tw(ohci_state_t * ohcip,ohci_trans_wrapper_t * tw,ohci_td_t * td)19960Sstevel@tonic-gate ohci_polled_insert_td_on_tw(
19970Sstevel@tonic-gate ohci_state_t *ohcip,
19980Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
19990Sstevel@tonic-gate ohci_td_t *td)
20000Sstevel@tonic-gate {
20010Sstevel@tonic-gate
20020Sstevel@tonic-gate /*
20030Sstevel@tonic-gate * Set the next pointer to NULL because
20040Sstevel@tonic-gate * this is the last TD on list.
20050Sstevel@tonic-gate */
20060Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, NULL);
20070Sstevel@tonic-gate
20080Sstevel@tonic-gate if (tw->tw_hctd_head == NULL) {
20090Sstevel@tonic-gate ASSERT(tw->tw_hctd_tail == NULL);
20100Sstevel@tonic-gate tw->tw_hctd_head = td;
20110Sstevel@tonic-gate tw->tw_hctd_tail = td;
20120Sstevel@tonic-gate } else {
20130Sstevel@tonic-gate ohci_td_t *dummy = (ohci_td_t *)tw->tw_hctd_tail;
20140Sstevel@tonic-gate
20150Sstevel@tonic-gate ASSERT(dummy != NULL);
20160Sstevel@tonic-gate ASSERT(dummy != td);
20170Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_state) == HC_TD_DUMMY);
20180Sstevel@tonic-gate
20190Sstevel@tonic-gate /* Add the td to the end of the list */
20200Sstevel@tonic-gate Set_TD(dummy->hctd_tw_next_td, ohci_td_cpu_to_iommu(ohcip, td));
20210Sstevel@tonic-gate tw->tw_hctd_tail = td;
20220Sstevel@tonic-gate
20230Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_tw_next_td) == NULL);
20240Sstevel@tonic-gate }
20250Sstevel@tonic-gate }
20260Sstevel@tonic-gate
20270Sstevel@tonic-gate
20280Sstevel@tonic-gate /*
20290Sstevel@tonic-gate * ohci_polled_handle_frame_number_overflow:
20300Sstevel@tonic-gate *
20310Sstevel@tonic-gate * Process Frame Number Overflow (FNO) interrupt in polled mode.
20320Sstevel@tonic-gate */
20330Sstevel@tonic-gate static void
ohci_polled_handle_frame_number_overflow(ohci_state_t * ohcip)20340Sstevel@tonic-gate ohci_polled_handle_frame_number_overflow(ohci_state_t *ohcip)
20350Sstevel@tonic-gate {
20360Sstevel@tonic-gate uint_t intr;
20370Sstevel@tonic-gate
20380Sstevel@tonic-gate /* Read the Interrupt Status & Interrupt enable register */
20390Sstevel@tonic-gate intr = (Get_OpReg(hcr_intr_status) & Get_OpReg(hcr_intr_enable));
20400Sstevel@tonic-gate
20410Sstevel@tonic-gate /*
20420Sstevel@tonic-gate * Check whether any Frame Number Overflow interrupt is pending
20430Sstevel@tonic-gate * and if it is pending, process this interrupt.
20440Sstevel@tonic-gate */
20450Sstevel@tonic-gate if (intr & HCR_INTR_FNO) {
20460Sstevel@tonic-gate ohci_handle_frame_number_overflow(ohcip);
20470Sstevel@tonic-gate
20480Sstevel@tonic-gate /* Acknowledge the FNO interrupt */
20490Sstevel@tonic-gate ohci_polled_finish_interrupt(ohcip, HCR_INTR_FNO);
20500Sstevel@tonic-gate }
20510Sstevel@tonic-gate }
20520Sstevel@tonic-gate
20530Sstevel@tonic-gate
20540Sstevel@tonic-gate /*
20550Sstevel@tonic-gate * ohci_polled_finish_interrupt:
20560Sstevel@tonic-gate */
20570Sstevel@tonic-gate static void
ohci_polled_finish_interrupt(ohci_state_t * ohcip,uint_t intr)20580Sstevel@tonic-gate ohci_polled_finish_interrupt(
20590Sstevel@tonic-gate ohci_state_t *ohcip,
20600Sstevel@tonic-gate uint_t intr)
20610Sstevel@tonic-gate {
20620Sstevel@tonic-gate /* Acknowledge the interrupt */
20630Sstevel@tonic-gate Set_OpReg(hcr_intr_status, intr);
20640Sstevel@tonic-gate
20650Sstevel@tonic-gate /*
20660Sstevel@tonic-gate * Read interrupt status register to make sure that any PIO
20670Sstevel@tonic-gate * store to clear the ISR has made it on the PCI bus before
20680Sstevel@tonic-gate * returning from its interrupt handler.
20690Sstevel@tonic-gate */
20700Sstevel@tonic-gate (void) Get_OpReg(hcr_intr_status);
20710Sstevel@tonic-gate }
2072*9095SZhigang.Lu@Sun.COM
2073*9095SZhigang.Lu@Sun.COM
2074*9095SZhigang.Lu@Sun.COM /*
2075*9095SZhigang.Lu@Sun.COM * ohci_polled_buikin_start:
2076*9095SZhigang.Lu@Sun.COM * Insert bulkin td into endpoint's td list.
2077*9095SZhigang.Lu@Sun.COM */
2078*9095SZhigang.Lu@Sun.COM static void
ohci_polled_insert_bulk_td(ohci_polled_t * ohci_polledp)2079*9095SZhigang.Lu@Sun.COM ohci_polled_insert_bulk_td(
2080*9095SZhigang.Lu@Sun.COM ohci_polled_t *ohci_polledp)
2081*9095SZhigang.Lu@Sun.COM {
2082*9095SZhigang.Lu@Sun.COM ohci_state_t *ohcip;
2083*9095SZhigang.Lu@Sun.COM ohci_trans_wrapper_t *tw;
2084*9095SZhigang.Lu@Sun.COM ohci_pipe_private_t *pp;
2085*9095SZhigang.Lu@Sun.COM usba_pipe_handle_data_t *ph;
2086*9095SZhigang.Lu@Sun.COM uint32_t ctrl;
2087*9095SZhigang.Lu@Sun.COM uint_t bulk_pkg_size;
2088*9095SZhigang.Lu@Sun.COM
2089*9095SZhigang.Lu@Sun.COM ohcip = ohci_polledp->ohci_polled_ohcip;
2090*9095SZhigang.Lu@Sun.COM ph = ohci_polledp->ohci_polled_input_pipe_handle;
2091*9095SZhigang.Lu@Sun.COM pp = (ohci_pipe_private_t *)ph->p_hcd_private;
2092*9095SZhigang.Lu@Sun.COM
2093*9095SZhigang.Lu@Sun.COM tw = pp->pp_tw_head;
2094*9095SZhigang.Lu@Sun.COM ASSERT(tw != NULL);
2095*9095SZhigang.Lu@Sun.COM
2096*9095SZhigang.Lu@Sun.COM ctrl = tw->tw_direction | HC_TD_DT_0 | HC_TD_1I | HC_TD_R;
2097*9095SZhigang.Lu@Sun.COM bulk_pkg_size = min(POLLED_RAW_BUF_SIZE, OHCI_MAX_TD_XFER_SIZE);
2098*9095SZhigang.Lu@Sun.COM
2099*9095SZhigang.Lu@Sun.COM (void) ohci_polled_insert_hc_td(ohcip, ctrl, 0, bulk_pkg_size, pp, tw);
2100*9095SZhigang.Lu@Sun.COM }
2101*9095SZhigang.Lu@Sun.COM
2102*9095SZhigang.Lu@Sun.COM
2103*9095SZhigang.Lu@Sun.COM /*
2104*9095SZhigang.Lu@Sun.COM * ohci_polled_create_tw:
2105*9095SZhigang.Lu@Sun.COM * Create the transfer wrapper used in polled mode.
2106*9095SZhigang.Lu@Sun.COM */
2107*9095SZhigang.Lu@Sun.COM static int
ohci_polled_create_tw(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)2108*9095SZhigang.Lu@Sun.COM ohci_polled_create_tw(
2109*9095SZhigang.Lu@Sun.COM ohci_state_t *ohcip,
2110*9095SZhigang.Lu@Sun.COM usba_pipe_handle_data_t *ph,
2111*9095SZhigang.Lu@Sun.COM usb_flags_t usb_flags)
2112*9095SZhigang.Lu@Sun.COM {
2113*9095SZhigang.Lu@Sun.COM uint_t ccount;
2114*9095SZhigang.Lu@Sun.COM ohci_trans_wrapper_t *tw;
2115*9095SZhigang.Lu@Sun.COM ddi_device_acc_attr_t dev_attr;
2116*9095SZhigang.Lu@Sun.COM ddi_dma_attr_t dma_attr;
2117*9095SZhigang.Lu@Sun.COM ohci_pipe_private_t *pp;
2118*9095SZhigang.Lu@Sun.COM int result, pipe_dir, td_count;
2119*9095SZhigang.Lu@Sun.COM size_t real_length;
2120*9095SZhigang.Lu@Sun.COM
2121*9095SZhigang.Lu@Sun.COM pp = (ohci_pipe_private_t *)ph->p_hcd_private;
2122*9095SZhigang.Lu@Sun.COM td_count = (POLLED_RAW_BUF_SIZE - 1) / OHCI_MAX_TD_XFER_SIZE + 1;
2123*9095SZhigang.Lu@Sun.COM
2124*9095SZhigang.Lu@Sun.COM if ((tw = kmem_zalloc(sizeof (ohci_trans_wrapper_t),
2125*9095SZhigang.Lu@Sun.COM KM_NOSLEEP)) == NULL) {
2126*9095SZhigang.Lu@Sun.COM return (USB_FAILURE);
2127*9095SZhigang.Lu@Sun.COM }
2128*9095SZhigang.Lu@Sun.COM
2129*9095SZhigang.Lu@Sun.COM /* allow sg lists for transfer wrapper dma memory */
2130*9095SZhigang.Lu@Sun.COM bcopy(&ohcip->ohci_dma_attr, &dma_attr, sizeof (ddi_dma_attr_t));
2131*9095SZhigang.Lu@Sun.COM dma_attr.dma_attr_sgllen = OHCI_DMA_ATTR_TW_SGLLEN;
2132*9095SZhigang.Lu@Sun.COM dma_attr.dma_attr_align = OHCI_DMA_ATTR_ALIGNMENT;
2133*9095SZhigang.Lu@Sun.COM
2134*9095SZhigang.Lu@Sun.COM /* Allocate the DMA handle */
2135*9095SZhigang.Lu@Sun.COM if ((result = ddi_dma_alloc_handle(ohcip->ohci_dip,
2136*9095SZhigang.Lu@Sun.COM &dma_attr, DDI_DMA_DONTWAIT, 0, &tw->tw_dmahandle)) !=
2137*9095SZhigang.Lu@Sun.COM DDI_SUCCESS) {
2138*9095SZhigang.Lu@Sun.COM kmem_free(tw, sizeof (ohci_trans_wrapper_t));
2139*9095SZhigang.Lu@Sun.COM
2140*9095SZhigang.Lu@Sun.COM return (USB_FAILURE);
2141*9095SZhigang.Lu@Sun.COM }
2142*9095SZhigang.Lu@Sun.COM
2143*9095SZhigang.Lu@Sun.COM dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2144*9095SZhigang.Lu@Sun.COM dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
2145*9095SZhigang.Lu@Sun.COM dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2146*9095SZhigang.Lu@Sun.COM
2147*9095SZhigang.Lu@Sun.COM /* Allocate the memory */
2148*9095SZhigang.Lu@Sun.COM if ((result = ddi_dma_mem_alloc(tw->tw_dmahandle, POLLED_RAW_BUF_SIZE,
2149*9095SZhigang.Lu@Sun.COM &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
2150*9095SZhigang.Lu@Sun.COM &tw->tw_buf, &real_length, &tw->tw_accesshandle)) !=
2151*9095SZhigang.Lu@Sun.COM DDI_SUCCESS) {
2152*9095SZhigang.Lu@Sun.COM ddi_dma_free_handle(&tw->tw_dmahandle);
2153*9095SZhigang.Lu@Sun.COM kmem_free(tw, sizeof (ohci_trans_wrapper_t));
2154*9095SZhigang.Lu@Sun.COM
2155*9095SZhigang.Lu@Sun.COM return (USB_FAILURE);
2156*9095SZhigang.Lu@Sun.COM }
2157*9095SZhigang.Lu@Sun.COM
2158*9095SZhigang.Lu@Sun.COM /* Bind the handle */
2159*9095SZhigang.Lu@Sun.COM if ((result = ddi_dma_addr_bind_handle(tw->tw_dmahandle, NULL,
2160*9095SZhigang.Lu@Sun.COM tw->tw_buf, real_length, DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
2161*9095SZhigang.Lu@Sun.COM DDI_DMA_DONTWAIT, NULL, &tw->tw_cookie, &ccount)) !=
2162*9095SZhigang.Lu@Sun.COM DDI_DMA_MAPPED) {
2163*9095SZhigang.Lu@Sun.COM ddi_dma_mem_free(&tw->tw_accesshandle);
2164*9095SZhigang.Lu@Sun.COM ddi_dma_free_handle(&tw->tw_dmahandle);
2165*9095SZhigang.Lu@Sun.COM kmem_free(tw, sizeof (ohci_trans_wrapper_t));
2166*9095SZhigang.Lu@Sun.COM
2167*9095SZhigang.Lu@Sun.COM return (USB_FAILURE);
2168*9095SZhigang.Lu@Sun.COM }
2169*9095SZhigang.Lu@Sun.COM
2170*9095SZhigang.Lu@Sun.COM /* The cookie count should be 1 */
2171*9095SZhigang.Lu@Sun.COM if (ccount != 1) {
2172*9095SZhigang.Lu@Sun.COM result = ddi_dma_unbind_handle(tw->tw_dmahandle);
2173*9095SZhigang.Lu@Sun.COM ASSERT(result == DDI_SUCCESS);
2174*9095SZhigang.Lu@Sun.COM
2175*9095SZhigang.Lu@Sun.COM ddi_dma_mem_free(&tw->tw_accesshandle);
2176*9095SZhigang.Lu@Sun.COM ddi_dma_free_handle(&tw->tw_dmahandle);
2177*9095SZhigang.Lu@Sun.COM kmem_free(tw, sizeof (ohci_trans_wrapper_t));
2178*9095SZhigang.Lu@Sun.COM
2179*9095SZhigang.Lu@Sun.COM return (USB_FAILURE);
2180*9095SZhigang.Lu@Sun.COM }
2181*9095SZhigang.Lu@Sun.COM
2182*9095SZhigang.Lu@Sun.COM if (ohci_allocate_tds_for_tw(ohcip, tw, td_count) == USB_SUCCESS) {
2183*9095SZhigang.Lu@Sun.COM tw->tw_num_tds = td_count;
2184*9095SZhigang.Lu@Sun.COM } else {
2185*9095SZhigang.Lu@Sun.COM ohci_deallocate_tw_resources(ohcip, pp, tw);
2186*9095SZhigang.Lu@Sun.COM return (USB_FAILURE);
2187*9095SZhigang.Lu@Sun.COM }
2188*9095SZhigang.Lu@Sun.COM tw->tw_cookie_idx = 0;
2189*9095SZhigang.Lu@Sun.COM tw->tw_dma_offs = 0;
2190*9095SZhigang.Lu@Sun.COM
2191*9095SZhigang.Lu@Sun.COM /*
2192*9095SZhigang.Lu@Sun.COM * Only allow one wrapper to be added at a time. Insert the
2193*9095SZhigang.Lu@Sun.COM * new transaction wrapper into the list for this pipe.
2194*9095SZhigang.Lu@Sun.COM */
2195*9095SZhigang.Lu@Sun.COM if (pp->pp_tw_head == NULL) {
2196*9095SZhigang.Lu@Sun.COM pp->pp_tw_head = tw;
2197*9095SZhigang.Lu@Sun.COM pp->pp_tw_tail = tw;
2198*9095SZhigang.Lu@Sun.COM } else {
2199*9095SZhigang.Lu@Sun.COM pp->pp_tw_tail->tw_next = tw;
2200*9095SZhigang.Lu@Sun.COM pp->pp_tw_tail = tw;
2201*9095SZhigang.Lu@Sun.COM }
2202*9095SZhigang.Lu@Sun.COM
2203*9095SZhigang.Lu@Sun.COM /* Store the transfer length */
2204*9095SZhigang.Lu@Sun.COM tw->tw_length = POLLED_RAW_BUF_SIZE;
2205*9095SZhigang.Lu@Sun.COM
2206*9095SZhigang.Lu@Sun.COM /* Store a back pointer to the pipe private structure */
2207*9095SZhigang.Lu@Sun.COM tw->tw_pipe_private = pp;
2208*9095SZhigang.Lu@Sun.COM
2209*9095SZhigang.Lu@Sun.COM /* Store the transfer type - synchronous or asynchronous */
2210*9095SZhigang.Lu@Sun.COM tw->tw_flags = usb_flags;
2211*9095SZhigang.Lu@Sun.COM
2212*9095SZhigang.Lu@Sun.COM /* Get and Store 32bit ID */
2213*9095SZhigang.Lu@Sun.COM tw->tw_id = OHCI_GET_ID((void *)tw);
2214*9095SZhigang.Lu@Sun.COM
2215*9095SZhigang.Lu@Sun.COM ASSERT(tw->tw_id != NULL);
2216*9095SZhigang.Lu@Sun.COM
2217*9095SZhigang.Lu@Sun.COM pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
2218*9095SZhigang.Lu@Sun.COM tw->tw_direction = (pipe_dir == USB_EP_DIR_IN) ? HC_TD_IN : HC_TD_OUT;
2219*9095SZhigang.Lu@Sun.COM
2220*9095SZhigang.Lu@Sun.COM USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
2221*9095SZhigang.Lu@Sun.COM "ohci_create_transfer_wrapper: tw = 0x%p, ncookies = %u",
2222*9095SZhigang.Lu@Sun.COM (void *)tw, tw->tw_ncookies);
2223*9095SZhigang.Lu@Sun.COM
2224*9095SZhigang.Lu@Sun.COM return (USB_SUCCESS);
2225*9095SZhigang.Lu@Sun.COM }
2226*9095SZhigang.Lu@Sun.COM
2227*9095SZhigang.Lu@Sun.COM
2228*9095SZhigang.Lu@Sun.COM /*
2229*9095SZhigang.Lu@Sun.COM * ohci_polled_insert_hc_td:
2230*9095SZhigang.Lu@Sun.COM *
2231*9095SZhigang.Lu@Sun.COM * Insert a Transfer Descriptor (TD) on an Endpoint Descriptor (ED).
2232*9095SZhigang.Lu@Sun.COM */
2233*9095SZhigang.Lu@Sun.COM int
ohci_polled_insert_hc_td(ohci_state_t * ohcip,uint_t hctd_ctrl,uint32_t hctd_dma_offs,size_t hctd_length,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw)2234*9095SZhigang.Lu@Sun.COM ohci_polled_insert_hc_td(
2235*9095SZhigang.Lu@Sun.COM ohci_state_t *ohcip,
2236*9095SZhigang.Lu@Sun.COM uint_t hctd_ctrl,
2237*9095SZhigang.Lu@Sun.COM uint32_t hctd_dma_offs,
2238*9095SZhigang.Lu@Sun.COM size_t hctd_length,
2239*9095SZhigang.Lu@Sun.COM ohci_pipe_private_t *pp,
2240*9095SZhigang.Lu@Sun.COM ohci_trans_wrapper_t *tw)
2241*9095SZhigang.Lu@Sun.COM {
2242*9095SZhigang.Lu@Sun.COM ohci_td_t *new_dummy;
2243*9095SZhigang.Lu@Sun.COM ohci_td_t *cpu_current_dummy;
2244*9095SZhigang.Lu@Sun.COM ohci_ed_t *ept = pp->pp_ept;
2245*9095SZhigang.Lu@Sun.COM
2246*9095SZhigang.Lu@Sun.COM /* Retrieve preallocated td from the TW */
2247*9095SZhigang.Lu@Sun.COM new_dummy = tw->tw_hctd_free_list;
2248*9095SZhigang.Lu@Sun.COM
2249*9095SZhigang.Lu@Sun.COM ASSERT(new_dummy != NULL);
2250*9095SZhigang.Lu@Sun.COM
2251*9095SZhigang.Lu@Sun.COM tw->tw_hctd_free_list = ohci_td_iommu_to_cpu(ohcip,
2252*9095SZhigang.Lu@Sun.COM Get_TD(new_dummy->hctd_tw_next_td));
2253*9095SZhigang.Lu@Sun.COM Set_TD(new_dummy->hctd_tw_next_td, NULL);
2254*9095SZhigang.Lu@Sun.COM
2255*9095SZhigang.Lu@Sun.COM /* Fill in the current dummy */
2256*9095SZhigang.Lu@Sun.COM cpu_current_dummy = (ohci_td_t *)
2257*9095SZhigang.Lu@Sun.COM (ohci_td_iommu_to_cpu(ohcip, Get_ED(ept->hced_tailp)));
2258*9095SZhigang.Lu@Sun.COM
2259*9095SZhigang.Lu@Sun.COM /*
2260*9095SZhigang.Lu@Sun.COM * Fill in the current dummy td and
2261*9095SZhigang.Lu@Sun.COM * add the new dummy to the end.
2262*9095SZhigang.Lu@Sun.COM */
2263*9095SZhigang.Lu@Sun.COM ohci_polled_fill_in_td(ohcip, cpu_current_dummy, new_dummy,
2264*9095SZhigang.Lu@Sun.COM hctd_ctrl, hctd_dma_offs, hctd_length, tw);
2265*9095SZhigang.Lu@Sun.COM
2266*9095SZhigang.Lu@Sun.COM /*
2267*9095SZhigang.Lu@Sun.COM * add the new dummy to the ED's list. When
2268*9095SZhigang.Lu@Sun.COM * this occurs, the Host Controller will see
2269*9095SZhigang.Lu@Sun.COM * the newly filled in dummy TD.
2270*9095SZhigang.Lu@Sun.COM */
2271*9095SZhigang.Lu@Sun.COM Set_ED(ept->hced_tailp,
2272*9095SZhigang.Lu@Sun.COM (ohci_td_cpu_to_iommu(ohcip, new_dummy)));
2273*9095SZhigang.Lu@Sun.COM
2274*9095SZhigang.Lu@Sun.COM /* Insert this td onto the tw */
2275*9095SZhigang.Lu@Sun.COM ohci_polled_insert_td_on_tw(ohcip, tw, cpu_current_dummy);
2276*9095SZhigang.Lu@Sun.COM
2277*9095SZhigang.Lu@Sun.COM return (USB_SUCCESS);
2278*9095SZhigang.Lu@Sun.COM }
2279