--- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_polled.c Thu Mar 19 10:21:31 2009 +0800
+++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_polled.c Thu Mar 19 14:02:20 2009 +0800
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -42,6 +42,10 @@
#include <sys/usb/hcd/ehci/ehci_util.h>
#include <sys/usb/hcd/ehci/ehci_polled.h>
+#ifndef __sparc
+extern void invalidate_cache();
+#endif
+
/*
* Internal Function Prototypes
*/
@@ -71,9 +75,11 @@
static int ehci_polled_handle_normal_qtd(
ehci_polled_t *ehci_polledp,
ehci_qtd_t *qtd);
-static void ehci_polled_insert_qtd(
+static void ehci_polled_insert_intr_qtd(
ehci_polled_t *ehci_polledp,
ehci_qtd_t *qtd);
+static void ehci_polled_insert_bulk_qtd(
+ ehci_polled_t *ehci_polledp);
static void ehci_polled_fill_in_qtd(
ehci_state_t *ehcip,
ehci_qtd_t *qtd,
@@ -99,6 +105,16 @@
static void ehci_polled_finish_interrupt(
ehci_state_t *ehcip,
uint_t intr);
+static int ehci_polled_create_tw(
+ ehci_polled_t *ehci_polledp,
+ usba_pipe_handle_data_t *ph,
+ usb_flags_t usb_flags);
+static void ehci_polled_insert_async_qh(
+ ehci_state_t *ehcip,
+ ehci_pipe_private_t *pp);
+static void ehci_polled_remove_async_qh(
+ ehci_state_t *ehcip,
+ ehci_pipe_private_t *pp);
/*
* POLLED entry points
@@ -109,7 +125,7 @@
/*
* ehci_hcdi_polled_input_init:
*
- * This is the initialization routine for handling the USB keyboard
+ * This is the initialization routine for handling the USB input device
* in POLLED mode. This routine is not called from POLLED mode, so
* it is OK to acquire mutexes.
*/
@@ -224,11 +240,25 @@
ehci_hcdi_polled_input_enter(usb_console_info_impl_t *info)
{
ehci_polled_t *ehci_polledp;
+ ehci_state_t *ehcip;
+ usba_pipe_handle_data_t *ph;
+ ehci_pipe_private_t *pp;
+ int pipe_attr;
+#ifndef lint
+ _NOTE(NO_COMPETING_THREADS_NOW);
+#endif
ehci_polledp = (ehci_polled_t *)info->uci_private;
+ ehcip = ehci_polledp->ehci_polled_ehcip;
+ ph = ehci_polledp->ehci_polled_input_pipe_handle;
+ pp = (ehci_pipe_private_t *)ph->p_hcd_private;
+
+ pipe_attr = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
+#ifndef lint
+ _NOTE(COMPETING_THREADS_NOW);
+#endif
ehci_polledp->ehci_polled_entry++;
-
/*
* If the controller is already switched over, just return
*/
@@ -237,7 +267,33 @@
return (USB_SUCCESS);
}
- ehci_polled_save_state(ehci_polledp);
+ switch (pipe_attr) {
+ case USB_EP_ATTR_INTR:
+ ehci_polled_save_state(ehci_polledp);
+ break;
+ case USB_EP_ATTR_BULK:
+#ifndef lint
+ _NOTE(NO_COMPETING_THREADS_NOW);
+#endif
+ Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
+ ~(EHCI_CMD_PERIODIC_SCHED_ENABLE |
+ EHCI_CMD_ASYNC_SCHED_ENABLE)));
+ /* Wait for few milliseconds */
+ drv_usecwait(EHCI_POLLED_TIMEWAIT);
+
+ ehci_polled_insert_async_qh(ehcip, pp);
+
+ Set_OpReg(ehci_command,
+ (Get_OpReg(ehci_command) | EHCI_CMD_ASYNC_SCHED_ENABLE));
+#ifndef lint
+ _NOTE(COMPETING_THREADS_NOW);
+#endif
+ /* Wait for few milliseconds */
+ drv_usecwait(EHCI_POLLED_TIMEWAIT);
+ break;
+ default:
+ return (USB_FAILURE);
+ }
ehci_polledp->ehci_polled_flags |= POLLED_INPUT_MODE_INUSE;
@@ -255,8 +311,23 @@
ehci_hcdi_polled_input_exit(usb_console_info_impl_t *info)
{
ehci_polled_t *ehci_polledp;
+ ehci_state_t *ehcip;
+ ehci_pipe_private_t *pp;
+ int pipe_attr;
+#ifndef lint
+ _NOTE(NO_COMPETING_THREADS_NOW);
+#endif
ehci_polledp = (ehci_polled_t *)info->uci_private;
+ ehcip = ehci_polledp->ehci_polled_ehcip;
+ pp = (ehci_pipe_private_t *)ehci_polledp->
+ ehci_polled_input_pipe_handle->p_hcd_private;
+
+ pipe_attr = ehci_polledp->ehci_polled_input_pipe_handle->
+ p_ep.bmAttributes & USB_EP_ATTR_MASK;
+#ifndef lint
+ _NOTE(COMPETING_THREADS_NOW);
+#endif
ehci_polledp->ehci_polled_entry--;
@@ -270,7 +341,35 @@
ehci_polledp->ehci_polled_flags &= ~POLLED_INPUT_MODE_INUSE;
- ehci_polled_restore_state(ehci_polledp);
+ switch (pipe_attr & USB_EP_ATTR_MASK) {
+ case USB_EP_ATTR_INTR:
+ ehci_polled_restore_state(ehci_polledp);
+ break;
+ case USB_EP_ATTR_BULK:
+#ifndef lint
+ _NOTE(NO_COMPETING_THREADS_NOW);
+#endif
+ Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
+ ~(EHCI_CMD_PERIODIC_SCHED_ENABLE |
+ EHCI_CMD_ASYNC_SCHED_ENABLE)));
+ /* Wait for few milliseconds */
+ drv_usecwait(EHCI_POLLED_TIMEWAIT);
+
+ ehci_polled_remove_async_qh(ehcip, pp);
+
+ Set_OpReg(ehci_command,
+ (Get_OpReg(ehci_command) | EHCI_CMD_ASYNC_SCHED_ENABLE |
+ EHCI_CMD_ASYNC_SCHED_ENABLE));
+#ifndef lint
+ _NOTE(COMPETING_THREADS_NOW);
+#endif
+ /* Wait for few milliseconds */
+ drv_usecwait(EHCI_POLLED_TIMEWAIT);
+ break;
+ default:
+ return (USB_FAILURE);
+
+ }
return (USB_SUCCESS);
}
@@ -289,6 +388,7 @@
ehci_state_t *ehcip;
ehci_polled_t *ehci_polledp;
uint_t intr;
+ int pipe_attr;
ehci_polledp = (ehci_polled_t *)info->uci_private;
@@ -300,6 +400,13 @@
*num_characters = 0;
+ pipe_attr = ehci_polledp->ehci_polled_input_pipe_handle->
+ p_ep.bmAttributes & USB_EP_ATTR_MASK;
+
+ if (pipe_attr == USB_EP_ATTR_BULK) {
+ ehci_polled_insert_bulk_qtd(ehci_polledp);
+ }
+
intr = ((Get_OpReg(ehci_status) & Get_OpReg(ehci_interrupt)) &
(EHCI_INTR_FRAME_LIST_ROLLOVER |
EHCI_INTR_USB | EHCI_INTR_USB_ERROR));
@@ -315,22 +422,240 @@
EHCI_INTR_FRAME_LIST_ROLLOVER);
}
+ /* Process any QTD's on the active interrupt qtd list */
+ *num_characters =
+ ehci_polled_process_active_intr_qtd_list(ehci_polledp);
+
+#ifndef lint
+ _NOTE(COMPETING_THREADS_NOW);
+#endif
+
+ return (USB_SUCCESS);
+}
+
+
+/*
+ * ehci_hcdi_polled_output_init:
+ *
+ * This is the initialization routine for handling the USB serial output
+ * in POLLED mode. This routine is not called from POLLED mode, so
+ * it is OK to acquire mutexes.
+ */
+int
+ehci_hcdi_polled_output_init(
+ usba_pipe_handle_data_t *ph,
+ usb_console_info_impl_t *console_output_info)
+{
+ ehci_polled_t *ehci_polledp;
+ ehci_state_t *ehcip;
+ ehci_pipe_private_t *pp;
+ int ret;
+
+ ehcip = ehci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
+
+ /*
+ * Grab the ehci_int_mutex so that things don't change on us
+ * if an interrupt comes in.
+ */
+ mutex_enter(&ehcip->ehci_int_mutex);
+
+ ret = ehci_polled_init(ph, ehcip, console_output_info);
+
+ if (ret != USB_SUCCESS) {
+
+ /* Allow interrupts to continue */
+ mutex_exit(&ehcip->ehci_int_mutex);
+
+ return (ret);
+ }
+
+ ehci_polledp = (ehci_polled_t *)console_output_info->uci_private;
+ /*
+ * Mark the structure so that if we are using it, we don't free
+ * the structures if one of them is unplugged.
+ */
+ ehci_polledp->ehci_polled_flags |= POLLED_OUTPUT_MODE;
+
+ /*
+ * Insert the Endpoint Descriptor to appropriate endpoint list.
+ */
+ pp = (ehci_pipe_private_t *)ehci_polledp->
+ ehci_polled_input_pipe_handle->p_hcd_private;
+ ehci_polled_insert_async_qh(ehcip, pp);
+
+ /*
+ * This is a software workaround to fix schizo hardware bug.
+ * Existence of "no-prom-cdma-sync" property means consistent
+ * dma sync should not be done while in prom or polled mode.
+ */
+ if (ddi_prop_exists(DDI_DEV_T_ANY, ehcip->ehci_dip,
+ DDI_PROP_NOTPROM, "no-prom-cdma-sync")) {
+ ehci_polledp->ehci_polled_no_sync_flag = B_TRUE;
+ }
+
+ /* Allow interrupts to continue */
+ mutex_exit(&ehcip->ehci_int_mutex);
+
+ return (USB_SUCCESS);
+}
+
+
+/*
+ * ehci_hcdi_polled_output_fini:
+ */
+int
+ehci_hcdi_polled_output_fini(usb_console_info_impl_t *info)
+{
+ ehci_polled_t *ehci_polledp;
+ ehci_state_t *ehcip;
+ ehci_pipe_private_t *pp;
+ int ret;
+
+ ehci_polledp = (ehci_polled_t *)info->uci_private;
+
+ ehcip = ehci_polledp->ehci_polled_ehcip;
+
+ mutex_enter(&ehcip->ehci_int_mutex);
+
+ /* Remove the Endpoint Descriptor. */
+ pp = (ehci_pipe_private_t *)ehci_polledp->
+ ehci_polled_input_pipe_handle->p_hcd_private;
+ ehci_polled_remove_async_qh(ehcip, pp);
+
+ /*
+ * Reset the POLLED_INPUT_MODE flag so that we can tell if
+ * this structure is in use in the ehci_polled_fini routine.
+ */
+ ehci_polledp->ehci_polled_flags &= ~POLLED_OUTPUT_MODE;
+
+ ret = ehci_polled_fini(ehci_polledp);
+
+ info->uci_private = NULL;
+
+ mutex_exit(&ehcip->ehci_int_mutex);
+
+ return (ret);
+}
+
+
+/*
+ * ehci_hcdi_polled_output_enter:
+ *
+ * everything is done in input enter
+ */
+/*ARGSUSED*/
+int
+ehci_hcdi_polled_output_enter(usb_console_info_impl_t *info)
+{
+ return (USB_SUCCESS);
+}
+
+
+/*
+ * ehci_hcdi_polled_output_exit:
+ *
+ * everything is done in input exit
+ */
+/*ARGSUSED*/
+int
+ehci_hcdi_polled_output_exit(usb_console_info_impl_t *info)
+{
+ return (USB_SUCCESS);
+}
+
+
+/*
+ * ehci_hcdi_polled_write:
+ * Put a key character.
+ */
+int
+ehci_hcdi_polled_write(usb_console_info_impl_t *info, uchar_t *buf,
+ uint_t num_characters, uint_t *num_characters_written)
+{
+ ehci_state_t *ehcip;
+ ehci_polled_t *ehci_polledp;
+ ehci_trans_wrapper_t *tw;
+ ehci_pipe_private_t *pp;
+ usba_pipe_handle_data_t *ph;
+ int intr;
+
+#ifndef lint
+ _NOTE(NO_COMPETING_THREADS_NOW);
+#endif
+ ehci_polledp = (ehci_polled_t *)info->uci_private;
+ ehcip = ehci_polledp->ehci_polled_ehcip;
+ ph = ehci_polledp->ehci_polled_input_pipe_handle;
+ pp = (ehci_pipe_private_t *)ph->p_hcd_private;
+
+ /* Disable all list processing */
+ Set_OpReg(ehci_command, Get_OpReg(ehci_command) &
+ ~(EHCI_CMD_ASYNC_SCHED_ENABLE |
+ EHCI_CMD_PERIODIC_SCHED_ENABLE));
+
+ /* Wait for few milliseconds */
+ drv_usecwait(EHCI_POLLED_TIMEWAIT);
+
+ tw = pp->pp_tw_head;
+ ASSERT(tw != NULL);
+
+ /* copy transmit buffer */
+ if (num_characters > POLLED_RAW_BUF_SIZE) {
+ cmn_err(CE_NOTE, "polled write size %d bigger than %d",
+ num_characters, POLLED_RAW_BUF_SIZE);
+ num_characters = POLLED_RAW_BUF_SIZE;
+ }
+ tw->tw_length = num_characters;
+ ddi_rep_put8(tw->tw_accesshandle,
+ buf, (uint8_t *)tw->tw_buf,
+ tw->tw_length, DDI_DEV_AUTOINCR);
+ Sync_IO_Buffer_for_device(tw->tw_dmahandle, tw->tw_length);
+
+ ehci_polled_insert_bulk_qtd(ehci_polledp);
+
+ /* Enable async list processing */
+ Set_OpReg(ehci_command, (Get_OpReg(ehci_command) |
+ EHCI_CMD_ASYNC_SCHED_ENABLE));
+
+ /* Wait for few milliseconds */
+ drv_usecwait(EHCI_POLLED_TIMEWAIT);
+
+ while (!((Get_OpReg(ehci_status)) & (EHCI_INTR_USB
+ |EHCI_INTR_FRAME_LIST_ROLLOVER | EHCI_INTR_USB_ERROR))) {
+#ifndef __sparc
+ invalidate_cache();
+#else
+ ;
+#endif
+ }
+
+ intr = (Get_OpReg(ehci_status)) &
+ (EHCI_INTR_FRAME_LIST_ROLLOVER |
+ EHCI_INTR_USB | EHCI_INTR_USB_ERROR);
+
+ /*
+ * Check whether any frame list rollover interrupt is pending
+ * and if it is pending, process this interrupt.
+ */
+ if (intr & EHCI_INTR_FRAME_LIST_ROLLOVER) {
+
+ ehci_handle_frame_list_rollover(ehcip);
+ ehci_polled_finish_interrupt(ehcip,
+ EHCI_INTR_FRAME_LIST_ROLLOVER);
+ }
+
/* Check for any USB transaction completion notification */
if (intr & (EHCI_INTR_USB | EHCI_INTR_USB_ERROR)) {
- ehcip->ehci_polled_read_count ++;
- /* Process any QTD's on the active interrupt qtd list */
- *num_characters =
- ehci_polled_process_active_intr_qtd_list(ehci_polledp);
+
+ (void) ehci_polled_process_active_intr_qtd_list(ehci_polledp);
- if (ehcip->ehci_polled_read_count ==
- ehcip->ehci_polled_enter_count) {
- /* Acknowledge the frame list rollover interrupt */
- ehci_polled_finish_interrupt(ehcip,
- intr & (EHCI_INTR_USB | EHCI_INTR_USB_ERROR));
- ehcip->ehci_polled_read_count = 0;
- }
+ /* Acknowledge the USB and USB error interrupt */
+ ehci_polled_finish_interrupt(ehcip,
+ intr & (EHCI_INTR_USB | EHCI_INTR_USB_ERROR));
+
}
+ *num_characters_written = num_characters;
+
#ifndef lint
_NOTE(COMPETING_THREADS_NOW);
#endif
@@ -363,6 +688,7 @@
ehci_polled_t *ehci_polledp;
ehci_pipe_private_t *pp;
ehci_qtd_t *qtd;
+ int pipe_attr;
ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
@@ -465,8 +791,8 @@
}
/*
- * Allocate the interrupt endpoint. This QH will be inserted in
- * to the lattice chain for the keyboard device. This endpoint
+ * Allocate the endpoint. This QH will be inserted in
+ * to the lattice chain for the device. This endpoint
* will have the QTDs hanging off of it for the processing.
*/
ehci_polledp->ehci_polled_qh = ehci_alloc_qh(
@@ -486,33 +812,50 @@
/* Insert the endpoint onto the pipe handle */
pp->pp_qh = ehci_polledp->ehci_polled_qh;
- /*
- * Set soft interrupt handler flag in the normal mode usb
- * pipe handle.
- */
- mutex_enter(&ph->p_mutex);
- ph->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
- mutex_exit(&ph->p_mutex);
+ pipe_attr = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
+
+ switch (pipe_attr) {
+ case USB_EP_ATTR_INTR:
+ /*
+ * Set soft interrupt handler flag in the normal mode usb
+ * pipe handle.
+ */
+ mutex_enter(&ph->p_mutex);
+ ph->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
+ mutex_exit(&ph->p_mutex);
- /*
- * Insert a Interrupt polling request onto the endpoint.
- *
- * There will now be two QTDs on the QH, one is the dummy QTD that
- * was allocated above in the ehci_alloc_qh and this new one.
- */
- if ((ehci_start_periodic_pipe_polling(ehcip,
- ehci_polledp->ehci_polled_input_pipe_handle,
- NULL, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
+ /*
+ * Insert a Interrupt polling request onto the endpoint.
+ *
+ * There will now be two QTDs on the QH, one is the dummy QTD
+ * that was allocated above in the ehci_alloc_qh and this
+ * new one.
+ */
+ if ((ehci_start_periodic_pipe_polling(ehcip,
+ ehci_polledp->ehci_polled_input_pipe_handle,
+ NULL, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
- return (USB_NO_RESOURCES);
- }
+ return (USB_NO_RESOURCES);
+ }
+ /* Get the given new interrupt qtd */
+ qtd = (ehci_qtd_t *)(ehci_qtd_iommu_to_cpu(ehcip,
+ (Get_QH(pp->pp_qh->qh_next_qtd) & EHCI_QH_NEXT_QTD_PTR)));
- /* Get the given new interrupt qtd */
- qtd = (ehci_qtd_t *)(ehci_qtd_iommu_to_cpu(ehcip,
- (Get_QH(pp->pp_qh->qh_next_qtd) & EHCI_QH_NEXT_QTD_PTR)));
+ /* Insert this qtd into active interrupt QTD list */
+ ehci_polled_insert_qtd_into_active_intr_qtd_list(ehci_polledp,
+ qtd);
+ break;
+ case USB_EP_ATTR_BULK:
+ if ((ehci_polled_create_tw(ehci_polledp,
+ ehci_polledp->ehci_polled_input_pipe_handle,
+ USB_FLAGS_SLEEP)) != USB_SUCCESS) {
- /* Insert this qtd into active interrupt QTD list */
- ehci_polled_insert_qtd_into_active_intr_qtd_list(ehci_polledp, qtd);
+ return (USB_NO_RESOURCES);
+ }
+ break;
+ default:
+ return (USB_FAILURE);
+ }
return (USB_SUCCESS);
}
@@ -1017,6 +1360,7 @@
ehci_trans_wrapper_t *tw;
ehci_pipe_private_t *pp;
usb_cr_t error;
+ int pipe_attr, pipe_dir;
/* Sync QH and QTD pool */
if (ehci_polledp->ehci_polled_no_sync_flag == B_FALSE) {
@@ -1026,6 +1370,10 @@
/* Create done qtd list */
qtd = ehci_polled_create_done_qtd_list(ehci_polledp);
+ pipe_attr = ehci_polledp->ehci_polled_input_pipe_handle->
+ p_ep.bmAttributes & USB_EP_ATTR_MASK;
+ pipe_dir = ehci_polledp->ehci_polled_input_pipe_handle->
+ p_ep.bEndpointAddress & USB_EP_DIR_MASK;
/*
* Traverse the list of transfer descriptors. We can't destroy
* the qtd_next pointers of these QTDs because we are using it
@@ -1041,7 +1389,7 @@
tw = (ehci_trans_wrapper_t *)EHCI_LOOKUP_ID(
(uint32_t)Get_QTD(qtd->qtd_trans_wrapper));
- /* Get ohci pipe from transfer wrapper */
+ /* Get ehci pipe from transfer wrapper */
pp = tw->tw_pipe_private;
/* Look at the status */
@@ -1055,19 +1403,38 @@
* clear the halt condition in the Endpoint Descriptor
* (QH) associated with this Transfer Descriptor (QTD).
*/
- if (error == USB_CR_OK) {
- num_characters +=
- ehci_polled_handle_normal_qtd(ehci_polledp, qtd);
- } else {
+ if (error != USB_CR_OK) {
/* Clear the halt bit */
Set_QH(pp->pp_qh->qh_status,
Get_QH(pp->pp_qh->qh_status) &
~(EHCI_QH_STS_XACT_STATUS));
+ } else if (pipe_dir == USB_EP_DIR_IN) {
+
+ num_characters +=
+ ehci_polled_handle_normal_qtd(ehci_polledp,
+ qtd);
}
/* Insert this qtd back into QH's qtd list */
- ehci_polled_insert_qtd(ehci_polledp, qtd);
-
+ switch (pipe_attr) {
+ case USB_EP_ATTR_INTR:
+ ehci_polled_insert_intr_qtd(ehci_polledp, qtd);
+ break;
+ case USB_EP_ATTR_BULK:
+ if (tw->tw_qtd_free_list != NULL) {
+ uint32_t td_addr;
+ td_addr = ehci_qtd_cpu_to_iommu(ehcip,
+ tw->tw_qtd_free_list);
+ Set_QTD(qtd->qtd_tw_next_qtd, td_addr);
+ Set_QTD(qtd->qtd_state, EHCI_QTD_DUMMY);
+ tw->tw_qtd_free_list = qtd;
+ } else {
+ tw->tw_qtd_free_list = qtd;
+ Set_QTD(qtd->qtd_tw_next_qtd, NULL);
+ Set_QTD(qtd->qtd_state, EHCI_QTD_DUMMY);
+ }
+ break;
+ }
qtd = next_qtd;
}
@@ -1126,12 +1493,12 @@
/*
- * ehci_polled_insert_qtd:
+ * ehci_polled_insert_intr_qtd:
*
* Insert a Transfer Descriptor (QTD) on an Endpoint Descriptor (QH).
*/
static void
-ehci_polled_insert_qtd(
+ehci_polled_insert_intr_qtd(
ehci_polled_t *ehci_polledp,
ehci_qtd_t *qtd)
{
@@ -1209,6 +1576,61 @@
}
+static void
+ehci_polled_insert_bulk_qtd(
+ ehci_polled_t *ehci_polledp)
+{
+ ehci_state_t *ehcip;
+ ehci_pipe_private_t *pp;
+ ehci_trans_wrapper_t *tw;
+ ehci_qh_t *qh;
+ ehci_qtd_t *new_dummy_qtd;
+ ehci_qtd_t *curr_dummy_qtd, *next_dummy_qtd;
+ uint_t qtd_control;
+
+ ehcip = ehci_polledp->ehci_polled_ehcip;
+ pp = (ehci_pipe_private_t *)ehci_polledp->
+ ehci_polled_input_pipe_handle->p_hcd_private;
+ tw = pp->pp_tw_head;
+ qh = ehci_polledp->ehci_polled_qh;
+ new_dummy_qtd = tw->tw_qtd_free_list;
+
+ if (new_dummy_qtd == NULL) {
+ return;
+ }
+
+ tw->tw_qtd_free_list = ehci_qtd_iommu_to_cpu(ehcip,
+ Get_QTD(new_dummy_qtd->qtd_tw_next_qtd));
+ Set_QTD(new_dummy_qtd->qtd_tw_next_qtd, NULL);
+
+ /* Get the current and next dummy QTDs */
+ curr_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip,
+ Get_QH(qh->qh_dummy_qtd));
+ next_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip,
+ Get_QTD(curr_dummy_qtd->qtd_next_qtd));
+
+ /* Update QH's dummy qtd field */
+ Set_QH(qh->qh_dummy_qtd, ehci_qtd_cpu_to_iommu(ehcip, next_dummy_qtd));
+
+ /* Update next dummy's next qtd pointer */
+ Set_QTD(next_dummy_qtd->qtd_next_qtd,
+ ehci_qtd_cpu_to_iommu(ehcip, new_dummy_qtd));
+
+ qtd_control = (tw->tw_direction | EHCI_QTD_CTRL_INTR_ON_COMPLETE);
+
+ /*
+ * Fill in the current dummy qtd and
+ * add the new dummy to the end.
+ */
+ ehci_polled_fill_in_qtd(ehcip, curr_dummy_qtd, qtd_control,
+ 0, tw->tw_length, tw);
+
+ /* Insert this qtd into active interrupt QTD list */
+ ehci_polled_insert_qtd_into_active_intr_qtd_list(
+ ehci_polledp, curr_dummy_qtd);
+}
+
+
/*
* ehci_polled_fill_in_qtd:
*
@@ -1570,3 +1992,274 @@
*/
(void) Get_OpReg(ehci_status);
}
+
+
+static int
+ehci_polled_create_tw(
+ ehci_polled_t *ehci_polledp,
+ usba_pipe_handle_data_t *ph,
+ usb_flags_t usb_flags)
+{
+ uint_t ccount;
+ size_t real_length;
+ ehci_trans_wrapper_t *tw;
+ ddi_device_acc_attr_t dev_attr;
+ int result, pipe_dir, qtd_count;
+ ehci_state_t *ehcip;
+ ehci_pipe_private_t *pp;
+ ddi_dma_attr_t dma_attr;
+
+ ehcip = ehci_polledp->ehci_polled_ehcip;
+ pp = (ehci_pipe_private_t *)ph->p_hcd_private;
+
+ /* Get the required qtd counts */
+ qtd_count = (POLLED_RAW_BUF_SIZE - 1) / EHCI_MAX_QTD_XFER_SIZE + 1;
+
+ if ((tw = kmem_zalloc(sizeof (ehci_trans_wrapper_t),
+ KM_NOSLEEP)) == NULL) {
+ return (USB_FAILURE);
+ }
+
+ /* allow sg lists for transfer wrapper dma memory */
+ bcopy(&ehcip->ehci_dma_attr, &dma_attr, sizeof (ddi_dma_attr_t));
+ dma_attr.dma_attr_sgllen = EHCI_DMA_ATTR_TW_SGLLEN;
+ dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
+
+ /* Allocate the DMA handle */
+ if ((result = ddi_dma_alloc_handle(ehcip->ehci_dip,
+ &dma_attr, DDI_DMA_DONTWAIT, 0, &tw->tw_dmahandle)) !=
+ DDI_SUCCESS) {
+ kmem_free(tw, sizeof (ehci_trans_wrapper_t));
+
+ return (USB_FAILURE);
+ }
+
+ dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+ dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+ dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+ /* Allocate the memory */
+ if ((result = ddi_dma_mem_alloc(tw->tw_dmahandle, POLLED_RAW_BUF_SIZE,
+ &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
+ &tw->tw_buf, &real_length, &tw->tw_accesshandle)) !=
+ DDI_SUCCESS) {
+ ddi_dma_free_handle(&tw->tw_dmahandle);
+ kmem_free(tw, sizeof (ehci_trans_wrapper_t));
+
+ return (USB_FAILURE);
+ }
+
+ /* Bind the handle */
+ if ((result = ddi_dma_addr_bind_handle(tw->tw_dmahandle, NULL,
+ tw->tw_buf, real_length, DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
+ DDI_DMA_DONTWAIT, NULL, &tw->tw_cookie, &ccount)) !=
+ DDI_DMA_MAPPED) {
+ ddi_dma_mem_free(&tw->tw_accesshandle);
+ ddi_dma_free_handle(&tw->tw_dmahandle);
+ kmem_free(tw, sizeof (ehci_trans_wrapper_t));
+
+ return (USB_FAILURE);
+ }
+
+ /* The cookie count should be 1 */
+ if (ccount != 1) {
+ result = ddi_dma_unbind_handle(tw->tw_dmahandle);
+ ASSERT(result == DDI_SUCCESS);
+
+ ddi_dma_mem_free(&tw->tw_accesshandle);
+ ddi_dma_free_handle(&tw->tw_dmahandle);
+ kmem_free(tw, sizeof (ehci_trans_wrapper_t));
+
+ return (USB_FAILURE);
+ }
+
+ if (ehci_allocate_tds_for_tw(ehcip, pp, tw, qtd_count) == USB_SUCCESS) {
+ tw->tw_num_qtds = qtd_count;
+ } else {
+ ehci_deallocate_tw(ehcip, pp, tw);
+ return (USB_FAILURE);
+ }
+ tw->tw_cookie_idx = 0;
+ tw->tw_dma_offs = 0;
+
+ /*
+ * Only allow one wrapper to be added at a time. Insert the
+ * new transaction wrapper into the list for this pipe.
+ */
+ if (pp->pp_tw_head == NULL) {
+ pp->pp_tw_head = tw;
+ pp->pp_tw_tail = tw;
+ } else {
+ pp->pp_tw_tail->tw_next = tw;
+ pp->pp_tw_tail = tw;
+ }
+
+ /* Store the transfer length */
+ tw->tw_length = POLLED_RAW_BUF_SIZE;
+
+ /* Store a back pointer to the pipe private structure */
+ tw->tw_pipe_private = pp;
+
+ /* Store the transfer type - synchronous or asynchronous */
+ tw->tw_flags = usb_flags;
+
+ /* Get and Store 32bit ID */
+ tw->tw_id = EHCI_GET_ID((void *)tw);
+
+ pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
+ tw->tw_direction = (pipe_dir == USB_EP_DIR_OUT)?
+ EHCI_QTD_CTRL_OUT_PID : EHCI_QTD_CTRL_IN_PID;
+
+ USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
+ "ehci_create_transfer_wrapper: tw = 0x%p, ncookies = %u",
+ (void *)tw, tw->tw_ncookies);
+
+ return (USB_SUCCESS);
+}
+
+
+/*
+ * ehci_polled_insert_async_qh:
+ *
+ * Insert a bulk endpoint into the Host Controller's (HC)
+ * Asynchronous schedule endpoint list.
+ */
+static void
+ehci_polled_insert_async_qh(
+ ehci_state_t *ehcip,
+ ehci_pipe_private_t *pp)
+{
+ ehci_qh_t *qh = pp->pp_qh;
+ ehci_qh_t *async_head_qh;
+ ehci_qh_t *next_qh;
+ uintptr_t qh_addr;
+
+ /* Make sure this QH is not already in the list */
+ ASSERT((Get_QH(qh->qh_prev) & EHCI_QH_LINK_PTR) == NULL);
+
+ qh_addr = ehci_qh_cpu_to_iommu(ehcip, qh);
+
+ /* Obtain a ptr to the head of the Async schedule list */
+ async_head_qh = ehcip->ehci_head_of_async_sched_list;
+
+ if (async_head_qh == NULL) {
+ /* Set this QH to be the "head" of the circular list */
+ Set_QH(qh->qh_ctrl,
+ (Get_QH(qh->qh_ctrl) | EHCI_QH_CTRL_RECLAIM_HEAD));
+
+ /* Set new QH's link and previous pointer to itself */
+ Set_QH(qh->qh_link_ptr, qh_addr | EHCI_QH_LINK_REF_QH);
+ Set_QH(qh->qh_prev, qh_addr);
+
+ ehcip->ehci_head_of_async_sched_list = qh;
+
+ /* Set the head ptr to the new endpoint */
+ Set_OpReg(ehci_async_list_addr, qh_addr);
+
+ /*
+ * For some reason this register might get nulled out by
+ * the Uli M1575 South Bridge. To workaround the hardware
+ * problem, check the value after write and retry if the
+ * last write fails.
+ *
+ * If the ASYNCLISTADDR remains "stuck" after
+ * EHCI_MAX_RETRY retries, then the M1575 is broken
+ * and is stuck in an inconsistent state and is about
+ * to crash the machine with a trn_oor panic when it
+ * does a DMA read from 0x0. It is better to panic
+ * now rather than wait for the trn_oor crash; this
+ * way Customer Service will have a clean signature
+ * that indicts the M1575 chip rather than a
+ * mysterious and hard-to-diagnose trn_oor panic.
+ */
+ if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
+ (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) &&
+ (qh_addr != Get_OpReg(ehci_async_list_addr))) {
+ int retry = 0;
+
+ Set_OpRegRetry(ehci_async_list_addr, qh_addr, retry);
+ if (retry >= EHCI_MAX_RETRY)
+ cmn_err(CE_PANIC, "ehci_insert_async_qh:"
+ " ASYNCLISTADDR write failed.");
+
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_insert_async_qh: ASYNCLISTADDR "
+ "write failed, retry=%d", retry);
+ }
+ } else {
+ ASSERT(Get_QH(async_head_qh->qh_ctrl) &
+ EHCI_QH_CTRL_RECLAIM_HEAD);
+
+ /* Ensure this QH's "H" bit is not set */
+ Set_QH(qh->qh_ctrl,
+ (Get_QH(qh->qh_ctrl) & ~EHCI_QH_CTRL_RECLAIM_HEAD));
+
+ next_qh = ehci_qh_iommu_to_cpu(ehcip,
+ Get_QH(async_head_qh->qh_link_ptr) & EHCI_QH_LINK_PTR);
+
+ /* Set new QH's link and previous pointers */
+ Set_QH(qh->qh_link_ptr,
+ Get_QH(async_head_qh->qh_link_ptr) | EHCI_QH_LINK_REF_QH);
+ Set_QH(qh->qh_prev, ehci_qh_cpu_to_iommu(ehcip, async_head_qh));
+
+ /* Set next QH's prev pointer */
+ Set_QH(next_qh->qh_prev, ehci_qh_cpu_to_iommu(ehcip, qh));
+
+ /* Set QH Head's link pointer points to new QH */
+ Set_QH(async_head_qh->qh_link_ptr,
+ qh_addr | EHCI_QH_LINK_REF_QH);
+ }
+}
+
+
+/*
+ * ehci_remove_async_qh:
+ *
+ * Remove a control/bulk endpoint into the Host Controller's (HC)
+ * Asynchronous schedule endpoint list.
+ */
+static void
+ehci_polled_remove_async_qh(
+ ehci_state_t *ehcip,
+ ehci_pipe_private_t *pp)
+{
+ ehci_qh_t *qh = pp->pp_qh; /* qh to be removed */
+ ehci_qh_t *prev_qh, *next_qh;
+
+ prev_qh = ehci_qh_iommu_to_cpu(ehcip,
+ Get_QH(qh->qh_prev) & EHCI_QH_LINK_PTR);
+ next_qh = ehci_qh_iommu_to_cpu(ehcip,
+ Get_QH(qh->qh_link_ptr) & EHCI_QH_LINK_PTR);
+
+ /* Make sure this QH is in the list */
+ ASSERT(prev_qh != NULL);
+
+ /*
+ * If next QH and current QH are the same, then this is the last
+ * QH on the Asynchronous Schedule list.
+ */
+ if (qh == next_qh) {
+ ASSERT(Get_QH(qh->qh_ctrl) & EHCI_QH_CTRL_RECLAIM_HEAD);
+ /*
+ * Null our pointer to the async sched list, but do not
+ * touch the host controller's list_addr.
+ */
+ ehcip->ehci_head_of_async_sched_list = NULL;
+ } else {
+ /* If this QH is the HEAD then find another one to replace it */
+ if (ehcip->ehci_head_of_async_sched_list == qh) {
+
+ ASSERT(Get_QH(qh->qh_ctrl) & EHCI_QH_CTRL_RECLAIM_HEAD);
+ ehcip->ehci_head_of_async_sched_list = next_qh;
+ Set_QH(next_qh->qh_ctrl,
+ Get_QH(next_qh->qh_ctrl) |
+ EHCI_QH_CTRL_RECLAIM_HEAD);
+ }
+ Set_QH(prev_qh->qh_link_ptr, Get_QH(qh->qh_link_ptr));
+ Set_QH(next_qh->qh_prev, Get_QH(qh->qh_prev));
+ }
+
+ /* qh_prev to indicate it is no longer in the circular list */
+ Set_QH(qh->qh_prev, NULL);
+
+}
--- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c Thu Mar 19 10:21:31 2009 +0800
+++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c Thu Mar 19 14:02:20 2009 +0800
@@ -1744,6 +1744,17 @@
ehci_hcdi_polled_input_exit;
usba_hcdi_ops->usba_hcdi_console_input_fini =
ehci_hcdi_polled_input_fini;
+
+ usba_hcdi_ops->usba_hcdi_console_output_init =
+ ehci_hcdi_polled_output_init;
+ usba_hcdi_ops->usba_hcdi_console_output_enter =
+ ehci_hcdi_polled_output_enter;
+ usba_hcdi_ops->usba_hcdi_console_write =
+ ehci_hcdi_polled_write;
+ usba_hcdi_ops->usba_hcdi_console_output_exit =
+ ehci_hcdi_polled_output_exit;
+ usba_hcdi_ops->usba_hcdi_console_output_fini =
+ ehci_hcdi_polled_output_fini;
return (usba_hcdi_ops);
}
--- a/usr/src/uts/common/io/usb/hcd/openhci/ohci.c Thu Mar 19 10:21:31 2009 +0800
+++ b/usr/src/uts/common/io/usb/hcd/openhci/ohci.c Thu Mar 19 14:02:20 2009 +0800
@@ -325,7 +325,7 @@
ushort_t pkt_count,
size_t td_count,
uint_t usb_flags);
-static int ohci_allocate_tds_for_tw(
+int ohci_allocate_tds_for_tw(
ohci_state_t *ohcip,
ohci_trans_wrapper_t *tw,
size_t td_count);
@@ -2063,6 +2063,16 @@
usba_hcdi_ops->usba_hcdi_console_input_fini =
ohci_hcdi_polled_input_fini;
+ usba_hcdi_ops->usba_hcdi_console_output_init =
+ ohci_hcdi_polled_output_init;
+ usba_hcdi_ops->usba_hcdi_console_output_enter =
+ ohci_hcdi_polled_output_enter;
+ usba_hcdi_ops->usba_hcdi_console_write = ohci_hcdi_polled_write;
+ usba_hcdi_ops->usba_hcdi_console_output_exit =
+ ohci_hcdi_polled_output_exit;
+ usba_hcdi_ops->usba_hcdi_console_output_fini =
+ ohci_hcdi_polled_output_fini;
+
return (usba_hcdi_ops);
}
@@ -6752,7 +6762,7 @@
* Returns USB_NO_RESOURCES if it was not able to allocate all the requested TD
* otherwise USB_SUCCESS.
*/
-static int
+int
ohci_allocate_tds_for_tw(
ohci_state_t *ohcip,
ohci_trans_wrapper_t *tw,
--- a/usr/src/uts/common/io/usb/hcd/openhci/ohci_polled.c Thu Mar 19 10:21:31 2009 +0800
+++ b/usr/src/uts/common/io/usb/hcd/openhci/ohci_polled.c Thu Mar 19 14:02:20 2009 +0800
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -92,6 +92,19 @@
static void ohci_polled_finish_interrupt(
ohci_state_t *ohcip,
uint_t intr);
+static void ohci_polled_insert_bulk_td(
+ ohci_polled_t *ohci_polledp);
+static int ohci_polled_create_tw(
+ ohci_state_t *ohcip,
+ usba_pipe_handle_data_t *ph,
+ usb_flags_t usb_flags);
+static 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);
/*
* POLLED entry points
*
@@ -101,7 +114,7 @@
/*
* ohci_hcdi_polled_input_init:
*
- * This is the initialization routine for handling the USB keyboard
+ * This is the initialization routine for handling the USB input device
* in POLLED mode. This routine is not called from POLLED mode, so
* it is OK to acquire mutexes.
*/
@@ -113,7 +126,7 @@
{
ohci_polled_t *ohci_polledp;
ohci_state_t *ohcip;
- int ret;
+ int pipe_attr, ret;
ohcip = ohci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
@@ -134,7 +147,6 @@
}
ohci_polledp = (ohci_polled_t *)console_input_info->uci_private;
-
/*
* Mark the structure so that if we are using it, we don't free
* the structures if one of them is unplugged.
@@ -153,6 +165,13 @@
*polled_buf = ohci_polledp->ohci_polled_buf;
+ /* Insert bulkin td into endpoint's tds list */
+ pipe_attr = ohci_polledp->ohci_polled_input_pipe_handle->
+ p_ep.bmAttributes & USB_EP_ATTR_MASK;
+
+ if (pipe_attr == USB_EP_ATTR_BULK) {
+ ohci_polled_insert_bulk_td(ohci_polledp);
+ }
/*
* This is a software workaround to fix schizo hardware bug.
* Existence of "no-prom-cdma-sync" property means consistent
@@ -290,33 +309,30 @@
* Check whether any Frame Number Overflow interrupt is pending
* and if it is pending, process this interrupt.
*/
-
if (intr & HCR_INTR_FNO) {
ohci_handle_frame_number_overflow(ohcip);
/* Acknowledge the FNO interrupt */
ohci_polled_finish_interrupt(ohcip, HCR_INTR_FNO);
}
+
+ /* Check to see if there are any TD's for this input device */
+ if (ohci_polled_check_done_list(ohci_polledp) == USB_SUCCESS) {
+
+ /* Process any TD's on the input done list */
+ *num_characters =
+ ohci_polled_process_input_list(ohci_polledp);
+ }
+
+ /*
+ * To make sure after we get the done list from DoneHead,
+ * every input device get his own TD's in the
+ * ohci_polled_done_list and then clear the interrupt status.
+ */
if (intr & HCR_INTR_WDH) {
- /* Check to see if there are any TD's for this input device */
- if (ohci_polled_check_done_list(ohci_polledp) == USB_SUCCESS) {
-
- /* Process any TD's on the input done list */
- *num_characters =
- ohci_polled_process_input_list(ohci_polledp);
- }
-
- /*
- * To make sure after we get the done list from DoneHead,
- * every input device get his own TD's in the
- * ohci_polled_done_list and then clear the interrupt status.
- */
- if (ohcip->ohci_polled_done_list == NULL) {
-
- /* Acknowledge the WDH interrupt */
- ohci_polled_finish_interrupt(ohcip, HCR_INTR_WDH);
- }
+ /* Acknowledge the WDH interrupt */
+ ohci_polled_finish_interrupt(ohcip, HCR_INTR_WDH);
}
#ifndef lint
_NOTE(COMPETING_THREADS_NOW);
@@ -327,6 +343,232 @@
/*
+ * ohci_hcdi_polled_output_init:
+ *
+ * This is the initialization routine for handling the USB serial output
+ * in POLLED mode. This routine is not called from POLLED mode, so
+ * it is OK to acquire mutexes.
+ */
+int
+ohci_hcdi_polled_output_init(
+ usba_pipe_handle_data_t *ph,
+ usb_console_info_impl_t *console_output_info)
+{
+ ohci_polled_t *ohci_polledp;
+ ohci_state_t *ohcip;
+ int ret;
+
+ ohcip = ohci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
+
+ /*
+ * Grab the ohci_int_mutex so that things don't change on us
+ * if an interrupt comes in.
+ */
+ mutex_enter(&ohcip->ohci_int_mutex);
+
+ ret = ohci_polled_init(ph, ohcip, console_output_info);
+
+ if (ret != USB_SUCCESS) {
+
+ /* Allow interrupts to continue */
+ mutex_exit(&ohcip->ohci_int_mutex);
+
+ return (ret);
+ }
+
+ ohci_polledp = (ohci_polled_t *)console_output_info->uci_private;
+ /*
+ * Mark the structure so that if we are using it, we don't free
+ * the structures if one of them is unplugged.
+ */
+ ohci_polledp->ohci_polled_flags |= POLLED_OUTPUT_MODE;
+
+ /*
+ * This is a software workaround to fix schizo hardware bug.
+ * Existence of "no-prom-cdma-sync" property means consistent
+ * dma sync should not be done while in prom or polled mode.
+ */
+ if (ddi_prop_exists(DDI_DEV_T_ANY, ohcip->ohci_dip,
+ DDI_PROP_NOTPROM, "no-prom-cdma-sync")) {
+ ohci_polledp->ohci_polled_no_sync_flag = B_TRUE;
+ }
+
+ /* Allow interrupts to continue */
+ mutex_exit(&ohcip->ohci_int_mutex);
+
+ return (USB_SUCCESS);
+}
+
+/*
+ * ohci_hcdi_polled_output_fini:
+ */
+int
+ohci_hcdi_polled_output_fini(usb_console_info_impl_t *info)
+{
+ ohci_polled_t *ohci_polledp;
+ ohci_state_t *ohcip;
+ int ret;
+
+ ohci_polledp = (ohci_polled_t *)info->uci_private;
+
+ ohcip = ohci_polledp->ohci_polled_ohcip;
+
+ mutex_enter(&ohcip->ohci_int_mutex);
+
+ /*
+ * Reset the POLLED_INPUT_MODE flag so that we can tell if
+ * this structure is in use in the ohci_polled_fini routine.
+ */
+ ohci_polledp->ohci_polled_flags &= ~POLLED_OUTPUT_MODE;
+
+ ret = ohci_polled_fini(ohci_polledp);
+
+ info->uci_private = NULL;
+
+ mutex_exit(&ohcip->ohci_int_mutex);
+
+ return (ret);
+}
+
+
+/*
+ * ohci_hcdi_polled_output_enter:
+ *
+ * everything is done in input enter
+ */
+/*ARGSUSED*/
+int
+ohci_hcdi_polled_output_enter(usb_console_info_impl_t *info)
+{
+ return (USB_SUCCESS);
+}
+
+
+/*
+ * ohci_hcdi_polled_output_exit:
+ *
+ * everything is done in input exit
+ */
+/*ARGSUSED*/
+int
+ohci_hcdi_polled_output_exit(usb_console_info_impl_t *info)
+{
+ return (USB_SUCCESS);
+}
+
+
+/*
+ * ohci_hcdi_polled_write:
+ * Put a key character -- rewrite this!
+ */
+int
+ohci_hcdi_polled_write(usb_console_info_impl_t *info, uchar_t *buf,
+ uint_t num_characters, uint_t *num_characters_written)
+{
+ ohci_state_t *ohcip;
+ ohci_polled_t *ohci_polledp;
+ ohci_trans_wrapper_t *tw;
+ ohci_pipe_private_t *pp;
+ usba_pipe_handle_data_t *ph;
+ uint32_t ctrl;
+ uint_t intr, bulk_pkg_size;
+ int i;
+
+#ifndef lint
+ _NOTE(NO_COMPETING_THREADS_NOW);
+#endif
+
+ ohci_polledp = (ohci_polled_t *)info->uci_private;
+ ohcip = ohci_polledp->ohci_polled_ohcip;
+
+ /* Disable periodic list processing */
+ Set_OpReg(hcr_control,
+ (Get_OpReg(hcr_control) & (~HCR_CONTROL_PLE)));
+
+ /* Add the endpoint to the lattice */
+ for (i = ohcip->ohci_polled_enter_count; i < NUM_INTR_ED_LISTS;
+ i = i + MIN_LOW_SPEED_POLL_INTERVAL) {
+ Set_HCCA(ohcip->ohci_hccap->HccaIntTble[i],
+ ohci_ed_cpu_to_iommu(ohcip,
+ ohci_polledp->ohci_polled_ed));
+ }
+
+ ph = ohci_polledp->ohci_polled_input_pipe_handle;
+ pp = (ohci_pipe_private_t *)ph->p_hcd_private;
+ tw = pp->pp_tw_head;
+
+ ASSERT(tw != NULL);
+ if (tw->tw_hctd_free_list == NULL) {
+#ifndef lint
+ _NOTE(COMPETING_THREADS_NOW);
+#endif
+ return (USB_SUCCESS);
+ }
+
+ /* Copy transmit buffer */
+ if (num_characters > POLLED_RAW_BUF_SIZE) {
+ cmn_err(CE_NOTE, "polled write size %d bigger than %d",
+ num_characters, POLLED_RAW_BUF_SIZE);
+ num_characters = POLLED_RAW_BUF_SIZE;
+ }
+ tw->tw_length = num_characters;
+
+ ddi_rep_put8(tw->tw_accesshandle,
+ buf, (uint8_t *)tw->tw_buf,
+ tw->tw_length, DDI_DEV_AUTOINCR);
+ Sync_IO_Buffer_for_device(tw->tw_dmahandle, tw->tw_length);
+
+ /* Insert td into endpoint's tds list */
+ ctrl = tw->tw_direction | HC_TD_DT_0|HC_TD_1I | HC_TD_R;
+ bulk_pkg_size = min(tw->tw_length, OHCI_MAX_TD_XFER_SIZE);
+
+ (void) ohci_polled_insert_hc_td(ohcip, ctrl, 0, bulk_pkg_size, pp, tw);
+
+ /* Enable periodic list processing */
+ Set_OpReg(hcr_control,
+ (Get_OpReg(hcr_control) | HCR_CONTROL_PLE));
+
+ /* Wait for bulk out tds transfer completion */
+ for (;;) {
+ intr = Get_OpReg(hcr_intr_status);
+
+ if (intr & HCR_INTR_FNO) {
+ ohci_handle_frame_number_overflow(ohcip);
+ ohci_polled_finish_interrupt(ohcip, HCR_INTR_FNO);
+ }
+
+ if (intr & HCR_INTR_WDH) {
+ if (ohci_polled_check_done_list(ohci_polledp) ==
+ USB_SUCCESS) {
+ *num_characters_written =
+ ohci_polled_process_input_list(
+ ohci_polledp);
+ break;
+ }
+ }
+
+ Set_OpReg(hcr_intr_status, intr);
+ (void) Get_OpReg(hcr_intr_status);
+ }
+
+ /* Remove the endpoint from the lattice */
+ for (i = ohcip->ohci_polled_enter_count; i < NUM_INTR_ED_LISTS;
+ i = i + MIN_LOW_SPEED_POLL_INTERVAL) {
+ Set_HCCA(ohcip->ohci_hccap->HccaIntTble[i],
+ ohci_ed_cpu_to_iommu(ohcip,
+ ohci_polledp->ohci_polled_dummy_ed));
+ }
+
+ Set_OpReg(hcr_intr_status, intr);
+ (void) Get_OpReg(hcr_intr_status);
+#ifndef lint
+ _NOTE(COMPETING_THREADS_NOW);
+#endif
+ return (USB_SUCCESS);
+}
+
+
+/*
* Internal Functions
*/
@@ -349,6 +591,7 @@
{
ohci_polled_t *ohci_polledp;
ohci_pipe_private_t *pp;
+ int pipe_attr;
ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
@@ -450,8 +693,8 @@
}
/*
- * Allocate the interrupt endpoint. This ED will be inserted in
- * to the lattice chain for the keyboard device. This endpoint
+ * Allocate the endpoint. This ED will be inserted in
+ * to the lattice chain for the device. This endpoint
* will have the TDs hanging off of it for the processing.
*/
ohci_polledp->ohci_polled_ed = ohci_alloc_hc_ed(ohcip,
@@ -468,27 +711,41 @@
/* Insert the endpoint onto the pipe handle */
pp->pp_ept = ohci_polledp->ohci_polled_ed;
- /*
- * Set soft interrupt handler flag in the normal mode usb
- * pipe handle.
- */
- mutex_enter(&ph->p_mutex);
- ph->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
- mutex_exit(&ph->p_mutex);
+ pipe_attr = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
+
+ switch (pipe_attr) {
+ case USB_EP_ATTR_INTR:
+ /*
+ * Set soft interrupt handler flag in the normal mode usb
+ * pipe handle.
+ */
+ mutex_enter(&ph->p_mutex);
+ ph->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
+ mutex_exit(&ph->p_mutex);
- /*
- * Insert a Interrupt polling request onto the endpoint.
- *
- * There will now be two TDs on the ED, one is the dummy TD that
- * was allocated above in the ohci_alloc_hc_ed and this new one.
- */
- if ((ohci_start_periodic_pipe_polling(ohcip,
- ohci_polledp->ohci_polled_input_pipe_handle,
- NULL, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
-
- return (USB_NO_RESOURCES);
+ /*
+ * Insert a Interrupt polling request onto the endpoint.
+ *
+ * There will now be two TDs on the ED, one is the dummy TD
+ * that was allocated above in the ohci_alloc_hc_ed and
+ * this new one.
+ */
+ if ((ohci_start_periodic_pipe_polling(ohcip,
+ ohci_polledp->ohci_polled_input_pipe_handle,
+ NULL, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
+ return (USB_NO_RESOURCES);
+ }
+ break;
+ case USB_EP_ATTR_BULK:
+ if ((ohci_polled_create_tw(ohcip,
+ ohci_polledp->ohci_polled_input_pipe_handle,
+ USB_FLAGS_SLEEP)) != USB_SUCCESS) {
+ return (USB_NO_RESOURCES);
+ }
+ break;
+ default:
+ return (USB_FAILURE);
}
-
return (USB_SUCCESS);
}
@@ -1214,7 +1471,6 @@
Set_OpReg(hcr_intr_enable, mask | HCR_INTR_MIE);
}
}
-
#ifndef lint
_NOTE(COMPETING_THREADS_NOW);
#endif
@@ -1247,8 +1503,6 @@
/*
* Polled read routines
*/
-
-
/*
* ohci_polled_check_done_list:
*
@@ -1277,6 +1531,7 @@
if (done_head == NULL) {
if (ohcip->ohci_polled_done_list) {
done_head = ohcip->ohci_polled_done_list;
+ ohcip->ohci_polled_done_list = NULL;
} else {
return (USB_FAILURE);
@@ -1284,7 +1539,6 @@
} else {
/* Reset the done head to NULL */
Set_HCCA(ohcip->ohci_hccap->HccaDoneHead, NULL);
- ohcip->ohci_polled_done_list = NULL;
}
/* Sync ED and TD pool */
@@ -1309,6 +1563,7 @@
return (USB_SUCCESS);
}
+
/*
* ohci_polled_pickup_done_list:
*
@@ -1320,7 +1575,6 @@
ohci_td_t *done_head)
{
ohci_state_t *ohcip = ohci_polledp->ohci_polled_ohcip;
- ohci_td_t *reserve_head = NULL, *reserve_tail = NULL;
ohci_td_t *create_head = NULL, *current_td, *td;
ohci_trans_wrapper_t *tw;
ohci_pipe_private_t *pp;
@@ -1344,8 +1598,8 @@
pp = tw->tw_pipe_private;
/*
- * Figure out which done list to put this TD on and put it
- * there. If the pipe handle of the TD matches the pipe
+ * Figure out which done list to put this TD on and put it
+ * there. If the pipe handle of the TD matches the pipe
* handle we are using for the input device, then this must
* be an input TD, reverse the order and link to the list for
* this input device. Else put the TD to the reserve done list
@@ -1362,29 +1616,25 @@
create_head = current_td;
}
} else {
- if (reserve_head == NULL) {
- reserve_head = reserve_tail = current_td;
+ if (ohcip->ohci_polled_done_list == NULL) {
+ ohcip->ohci_polled_done_list = (ohci_td_t *)
+ (uintptr_t)ohci_td_cpu_to_iommu(ohcip,
+ current_td);
} else {
- Set_TD(reserve_tail->hctd_next_td,
- ohci_td_cpu_to_iommu(ohcip, current_td));
- reserve_tail = current_td;
+ Set_TD(current_td->hctd_next_td,
+ ohcip->ohci_polled_done_list);
+ ohcip->ohci_polled_done_list = (ohci_td_t *)
+ (uintptr_t)ohci_td_cpu_to_iommu(ohcip,
+ current_td);
}
}
current_td = td;
}
- /* Check if there is other TDs left for other input devices */
- if (reserve_head) {
- ohcip->ohci_polled_done_list = (ohci_td_t *)(uintptr_t)
- ohci_td_cpu_to_iommu(ohcip, reserve_head);
-
- } else {
- ohcip->ohci_polled_done_list = NULL;
- }
-
return (create_head);
}
+
/*
* ohci_polled_create_input_list:
*
@@ -1457,6 +1707,7 @@
uint_t num_characters;
ohci_trans_wrapper_t *tw;
ohci_pipe_private_t *pp;
+ int pipe_dir;
/*
* Get the first TD on the input done head.
@@ -1498,13 +1749,52 @@
/* Clear the halt bit */
Set_ED(pp->pp_ept->hced_headp,
(Get_ED(pp->pp_ept->hced_headp) & ~HC_EPT_Halt));
- } else {
- num_characters +=
- ohci_polled_handle_normal_td(ohci_polledp, td);
}
- /* Insert this interrupt TD back onto the ED's TD list */
- ohci_polled_insert_td(ohcip, td);
+ /* Obtain the transfer wrapper from the TD */
+ tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID(
+ (uint32_t)Get_TD(td->hctd_trans_wrapper));
+
+ /* Get the pipe direction for this transfer wrapper */
+ pipe_dir = tw->tw_pipe_private->pp_pipe_handle->
+ p_ep.bEndpointAddress & USB_EP_DIR_MASK;
+
+ switch (pipe_dir) {
+ case USB_EP_DIR_IN:
+ num_characters +=
+ ohci_polled_handle_normal_td(ohci_polledp,
+ td);
+
+ /*
+ * Insert this TD back
+ * onto the ED's TD list
+ */
+ ohci_polled_insert_td(ohcip, td);
+ break;
+ case USB_EP_DIR_OUT:
+ ASSERT((ohci_td_t *)tw->tw_hctd_head == td);
+
+ tw->tw_hctd_head = (ohci_td_t *)
+ ohci_td_iommu_to_cpu(ohcip,
+ Get_TD(td->hctd_tw_next_td));
+ Set_TD(td->hctd_state, HC_TD_DUMMY);
+
+ if (tw->tw_hctd_head == NULL) {
+ tw->tw_hctd_tail = NULL;
+ }
+
+ if (tw->tw_hctd_free_list != NULL) {
+ uint32_t td_addr;
+ td_addr = ohci_td_cpu_to_iommu(ohcip,
+ tw->tw_hctd_free_list);
+ Set_TD(td->hctd_tw_next_td, td_addr);
+ tw->tw_hctd_free_list = td;
+ } else {
+ tw->tw_hctd_free_list = td;
+ Set_TD(td->hctd_tw_next_td, NULL);
+ }
+ break;
+ }
td = next_td;
}
@@ -1535,7 +1825,6 @@
buf = (uchar_t *)tw->tw_buf;
length = tw->tw_length;
-
/*
* If "CurrentBufferPointer" of Transfer Descriptor (TD) is
* not equal to zero, then we received less data from the
@@ -1554,7 +1843,7 @@
Sync_IO_Buffer(tw->tw_dmahandle, length);
}
- /* Copy the data into the message */
+ /* Copy the data into the message */
ddi_rep_get8(tw->tw_accesshandle,
(uint8_t *)ohci_polledp->ohci_polled_buf,
(uint8_t *)buf, length, DDI_DEV_AUTOINCR);
@@ -1579,6 +1868,8 @@
ohci_trans_wrapper_t *tw;
ohci_td_t *cpu_current_dummy;
usb_intr_req_t *intr_req;
+ usba_pipe_handle_data_t *ph;
+ int pipe_attr;
/* Obtain the transfer wrapper from the TD */
tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID(
@@ -1611,16 +1902,27 @@
Set_TD(td->hctd_state, HC_TD_DUMMY);
pp = tw->tw_pipe_private;
+ ph = pp->pp_pipe_handle;
- /* Obtain the endpoint and interrupt request */
+ /* Obtain the endpoint and the request */
ept = pp->pp_ept;
- intr_req = (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
+ /* Get the pipe attribute */
+ pipe_attr = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
+
+ switch (pipe_attr) {
+ case USB_EP_ATTR_INTR:
+ intr_req = (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
- if (intr_req->intr_attributes & USB_ATTRS_SHORT_XFER_OK) {
- td_control = HC_TD_IN|HC_TD_1I|HC_TD_R;
- } else {
- td_control = HC_TD_IN|HC_TD_1I;
+ if (intr_req->intr_attributes & USB_ATTRS_SHORT_XFER_OK) {
+ td_control = HC_TD_IN|HC_TD_1I|HC_TD_R;
+ } else {
+ td_control = HC_TD_IN|HC_TD_1I;
+ }
+ break;
+ case USB_EP_ATTR_BULK:
+ td_control = tw->tw_direction|HC_TD_DT_0|HC_TD_1I|HC_TD_R;
+ break;
}
/* Get the current dummy */
@@ -1767,3 +2069,210 @@
*/
(void) Get_OpReg(hcr_intr_status);
}
+
+
+/*
+ * ohci_polled_buikin_start:
+ * Insert bulkin td into endpoint's td list.
+ */
+static void
+ohci_polled_insert_bulk_td(
+ ohci_polled_t *ohci_polledp)
+{
+ ohci_state_t *ohcip;
+ ohci_trans_wrapper_t *tw;
+ ohci_pipe_private_t *pp;
+ usba_pipe_handle_data_t *ph;
+ uint32_t ctrl;
+ uint_t bulk_pkg_size;
+
+ ohcip = ohci_polledp->ohci_polled_ohcip;
+ ph = ohci_polledp->ohci_polled_input_pipe_handle;
+ pp = (ohci_pipe_private_t *)ph->p_hcd_private;
+
+ tw = pp->pp_tw_head;
+ ASSERT(tw != NULL);
+
+ ctrl = tw->tw_direction | HC_TD_DT_0 | HC_TD_1I | HC_TD_R;
+ bulk_pkg_size = min(POLLED_RAW_BUF_SIZE, OHCI_MAX_TD_XFER_SIZE);
+
+ (void) ohci_polled_insert_hc_td(ohcip, ctrl, 0, bulk_pkg_size, pp, tw);
+}
+
+
+/*
+ * ohci_polled_create_tw:
+ * Create the transfer wrapper used in polled mode.
+ */
+static int
+ohci_polled_create_tw(
+ ohci_state_t *ohcip,
+ usba_pipe_handle_data_t *ph,
+ usb_flags_t usb_flags)
+{
+ uint_t ccount;
+ ohci_trans_wrapper_t *tw;
+ ddi_device_acc_attr_t dev_attr;
+ ddi_dma_attr_t dma_attr;
+ ohci_pipe_private_t *pp;
+ int result, pipe_dir, td_count;
+ size_t real_length;
+
+ pp = (ohci_pipe_private_t *)ph->p_hcd_private;
+ td_count = (POLLED_RAW_BUF_SIZE - 1) / OHCI_MAX_TD_XFER_SIZE + 1;
+
+ if ((tw = kmem_zalloc(sizeof (ohci_trans_wrapper_t),
+ KM_NOSLEEP)) == NULL) {
+ return (USB_FAILURE);
+ }
+
+ /* allow sg lists for transfer wrapper dma memory */
+ bcopy(&ohcip->ohci_dma_attr, &dma_attr, sizeof (ddi_dma_attr_t));
+ dma_attr.dma_attr_sgllen = OHCI_DMA_ATTR_TW_SGLLEN;
+ dma_attr.dma_attr_align = OHCI_DMA_ATTR_ALIGNMENT;
+
+ /* Allocate the DMA handle */
+ if ((result = ddi_dma_alloc_handle(ohcip->ohci_dip,
+ &dma_attr, DDI_DMA_DONTWAIT, 0, &tw->tw_dmahandle)) !=
+ DDI_SUCCESS) {
+ kmem_free(tw, sizeof (ohci_trans_wrapper_t));
+
+ return (USB_FAILURE);
+ }
+
+ dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+ dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+ dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+ /* Allocate the memory */
+ if ((result = ddi_dma_mem_alloc(tw->tw_dmahandle, POLLED_RAW_BUF_SIZE,
+ &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
+ &tw->tw_buf, &real_length, &tw->tw_accesshandle)) !=
+ DDI_SUCCESS) {
+ ddi_dma_free_handle(&tw->tw_dmahandle);
+ kmem_free(tw, sizeof (ohci_trans_wrapper_t));
+
+ return (USB_FAILURE);
+ }
+
+ /* Bind the handle */
+ if ((result = ddi_dma_addr_bind_handle(tw->tw_dmahandle, NULL,
+ tw->tw_buf, real_length, DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
+ DDI_DMA_DONTWAIT, NULL, &tw->tw_cookie, &ccount)) !=
+ DDI_DMA_MAPPED) {
+ ddi_dma_mem_free(&tw->tw_accesshandle);
+ ddi_dma_free_handle(&tw->tw_dmahandle);
+ kmem_free(tw, sizeof (ohci_trans_wrapper_t));
+
+ return (USB_FAILURE);
+ }
+
+ /* The cookie count should be 1 */
+ if (ccount != 1) {
+ result = ddi_dma_unbind_handle(tw->tw_dmahandle);
+ ASSERT(result == DDI_SUCCESS);
+
+ ddi_dma_mem_free(&tw->tw_accesshandle);
+ ddi_dma_free_handle(&tw->tw_dmahandle);
+ kmem_free(tw, sizeof (ohci_trans_wrapper_t));
+
+ return (USB_FAILURE);
+ }
+
+ if (ohci_allocate_tds_for_tw(ohcip, tw, td_count) == USB_SUCCESS) {
+ tw->tw_num_tds = td_count;
+ } else {
+ ohci_deallocate_tw_resources(ohcip, pp, tw);
+ return (USB_FAILURE);
+ }
+ tw->tw_cookie_idx = 0;
+ tw->tw_dma_offs = 0;
+
+ /*
+ * Only allow one wrapper to be added at a time. Insert the
+ * new transaction wrapper into the list for this pipe.
+ */
+ if (pp->pp_tw_head == NULL) {
+ pp->pp_tw_head = tw;
+ pp->pp_tw_tail = tw;
+ } else {
+ pp->pp_tw_tail->tw_next = tw;
+ pp->pp_tw_tail = tw;
+ }
+
+ /* Store the transfer length */
+ tw->tw_length = POLLED_RAW_BUF_SIZE;
+
+ /* Store a back pointer to the pipe private structure */
+ tw->tw_pipe_private = pp;
+
+ /* Store the transfer type - synchronous or asynchronous */
+ tw->tw_flags = usb_flags;
+
+ /* Get and Store 32bit ID */
+ tw->tw_id = OHCI_GET_ID((void *)tw);
+
+ ASSERT(tw->tw_id != NULL);
+
+ pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
+ tw->tw_direction = (pipe_dir == USB_EP_DIR_IN) ? HC_TD_IN : HC_TD_OUT;
+
+ USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
+ "ohci_create_transfer_wrapper: tw = 0x%p, ncookies = %u",
+ (void *)tw, tw->tw_ncookies);
+
+ return (USB_SUCCESS);
+}
+
+
+/*
+ * ohci_polled_insert_hc_td:
+ *
+ * Insert a Transfer Descriptor (TD) on an Endpoint Descriptor (ED).
+ */
+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)
+{
+ ohci_td_t *new_dummy;
+ ohci_td_t *cpu_current_dummy;
+ ohci_ed_t *ept = pp->pp_ept;
+
+ /* Retrieve preallocated td from the TW */
+ new_dummy = tw->tw_hctd_free_list;
+
+ ASSERT(new_dummy != NULL);
+
+ tw->tw_hctd_free_list = ohci_td_iommu_to_cpu(ohcip,
+ Get_TD(new_dummy->hctd_tw_next_td));
+ Set_TD(new_dummy->hctd_tw_next_td, NULL);
+
+ /* Fill in the current dummy */
+ cpu_current_dummy = (ohci_td_t *)
+ (ohci_td_iommu_to_cpu(ohcip, Get_ED(ept->hced_tailp)));
+
+ /*
+ * Fill in the current dummy td and
+ * add the new dummy to the end.
+ */
+ ohci_polled_fill_in_td(ohcip, cpu_current_dummy, new_dummy,
+ hctd_ctrl, hctd_dma_offs, hctd_length, tw);
+
+ /*
+ * add the new dummy to the ED's list. When
+ * this occurs, the Host Controller will see
+ * the newly filled in dummy TD.
+ */
+ Set_ED(ept->hced_tailp,
+ (ohci_td_cpu_to_iommu(ohcip, new_dummy)));
+
+ /* Insert this td onto the tw */
+ ohci_polled_insert_td_on_tw(ohcip, tw, cpu_current_dummy);
+
+ return (USB_SUCCESS);
+}
--- a/usr/src/uts/common/io/warlock/ehci.wlcmd Thu Mar 19 10:21:31 2009 +0800
+++ b/usr/src/uts/common/io/warlock/ehci.wlcmd Thu Mar 19 14:02:20 2009 +0800
@@ -68,6 +68,11 @@
root ehci_hcdi_polled_input_enter
root ehci_hcdi_polled_input_exit
root ehci_hcdi_polled_read
+root ehci_hcdi_polled_output_init
+root ehci_hcdi_polled_output_fini
+root ehci_hcdi_polled_output_enter
+root ehci_hcdi_polled_output_exit
+root ehci_hcdi_polled_write
### currently unused functions
--- a/usr/src/uts/common/io/warlock/ohci.wlcmd Thu Mar 19 10:21:31 2009 +0800
+++ b/usr/src/uts/common/io/warlock/ohci.wlcmd Thu Mar 19 14:02:20 2009 +0800
@@ -66,6 +66,11 @@
root ohci_hcdi_polled_input_enter
root ohci_hcdi_polled_input_exit
root ohci_hcdi_polled_read
+root ohci_hcdi_polled_output_init
+root ohci_hcdi_polled_output_fini
+root ohci_hcdi_polled_output_enter
+root ohci_hcdi_polled_output_exit
+root ohci_hcdi_polled_write
### currently unused functions
--- a/usr/src/uts/common/sys/usb/hcd/ehci/ehci_polled.h Thu Mar 19 10:21:31 2009 +0800
+++ b/usr/src/uts/common/sys/usb/hcd/ehci/ehci_polled.h Thu Mar 19 14:02:20 2009 +0800
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -50,6 +50,7 @@
* in use.
*/
#define POLLED_INPUT_MODE 0x01
+#define POLLED_OUTPUT_MODE 0x10
/*
* These two flags are used to determine if this structure is already in
@@ -57,6 +58,7 @@
* restore it once. These flags are used for the ehci_polled_flags below.
*/
#define POLLED_INPUT_MODE_INUSE 0x04
+#define POLLED_OUTPUT_MODE_INUSE 0x40
#define MAX_NUM_FOR_KEYBOARD 0x8
/*
* State structure for the POLLED switch off
--- a/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h Thu Mar 19 10:21:31 2009 +0800
+++ b/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h Thu Mar 19 14:02:20 2009 +0800
@@ -1151,7 +1151,20 @@
usb_console_info_impl_t *info);
int ehci_hcdi_polled_input_fini(
usb_console_info_impl_t *info);
-
+int ehci_hcdi_polled_output_init(
+ usba_pipe_handle_data_t *ph,
+ usb_console_info_impl_t *console_output_info);
+int ehci_hcdi_polled_output_enter(
+ usb_console_info_impl_t *info);
+int ehci_hcdi_polled_write(
+ usb_console_info_impl_t *info,
+ uchar_t *buf,
+ uint_t num_characters,
+ uint_t *num_characters_written);
+int ehci_hcdi_polled_output_exit(
+ usb_console_info_impl_t *info);
+int ehci_hcdi_polled_output_fini(
+ usb_console_info_impl_t *info);
/*
* EHCI Root Hub entry points function prototypes.
*/
--- a/usr/src/uts/common/sys/usb/hcd/openhci/ohci_polled.h Thu Mar 19 10:21:31 2009 +0800
+++ b/usr/src/uts/common/sys/usb/hcd/openhci/ohci_polled.h Thu Mar 19 14:02:20 2009 +0800
@@ -19,14 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_USB_OHCI_POLLED_H
#define _SYS_USB_OHCI_POLLED_H
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -51,6 +50,7 @@
* in use.
*/
#define POLLED_INPUT_MODE 0x01
+#define POLLED_OUTPUT_MODE 0x10
/*
* These two flags are used to determine if this structure is already in
@@ -58,6 +58,7 @@
* restore it once. These flags are used for the ohci_polled_flags below.
*/
#define POLLED_INPUT_MODE_INUSE 0x04
+#define POLLED_OUTPUT_MODE_INUSE 0x40
/*
* For ohci bandwidth of low speed interrupt devices limits,
--- a/usr/src/uts/common/sys/usb/hcd/openhci/ohcid.h Thu Mar 19 10:21:31 2009 +0800
+++ b/usr/src/uts/common/sys/usb/hcd/openhci/ohcid.h Thu Mar 19 14:02:20 2009 +0800
@@ -19,14 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_USB_OHCID_H
#define _SYS_USB_OHCID_H
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -807,6 +806,9 @@
#define Sync_IO_Buffer(dma_handle, length) \
(void) ddi_dma_sync(dma_handle, \
0, length, DDI_DMA_SYNC_FORCPU);
+#define Sync_IO_Buffer_for_device(dma_handle, length) \
+ (void) ddi_dma_sync(dma_handle, \
+ 0, length, DDI_DMA_SYNC_FORDEV);
/*
* Macros to speed handling of 32bit IDs
@@ -897,6 +899,21 @@
int ohci_hcdi_polled_input_fini(
usb_console_info_impl_t *info);
+int ohci_hcdi_polled_output_init(
+ usba_pipe_handle_data_t *ph,
+ usb_console_info_impl_t *console_output_info);
+int ohci_hcdi_polled_output_enter(
+ usb_console_info_impl_t *info);
+int ohci_hcdi_polled_write(
+ usb_console_info_impl_t *info,
+ uchar_t *buf,
+ uint_t num_characters,
+ uint_t *num_characters_written);
+int ohci_hcdi_polled_output_exit(
+ usb_console_info_impl_t *info);
+int ohci_hcdi_polled_output_fini(
+ usb_console_info_impl_t *info);
+
/* Root hub related functions */
int ohci_init_root_hub(
ohci_state_t *ohcip);
@@ -986,6 +1003,10 @@
void ohci_handle_outstanding_requests(
ohci_state_t *ohcip,
ohci_pipe_private_t *pp);
+int ohci_allocate_tds_for_tw(
+ ohci_state_t *ohcip,
+ ohci_trans_wrapper_t *tw,
+ size_t td_count);
#ifdef __cplusplus
}