[ros-diffs] [fireball] 30616: - Start implementing URB operations (so that at least roothub URB could come through).

fireball at svn.reactos.org fireball at svn.reactos.org
Wed Nov 21 10:51:03 CET 2007


Author: fireball
Date: Wed Nov 21 12:51:03 2007
New Revision: 30616

URL: http://svn.reactos.org/svn/reactos?rev=30616&view=rev
Log:
- Start implementing URB operations (so that at least roothub URB could come through).

Modified:
    trunk/reactos/drivers/usb/nt4compat/usbdriver/ohci.c
    trunk/reactos/drivers/usb/nt4compat/usbdriver/ohci.h

Modified: trunk/reactos/drivers/usb/nt4compat/usbdriver/ohci.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/nt4compat/usbdriver/ohci.c?rev=30616&r1=30615&r2=30616&view=diff
==============================================================================
--- trunk/reactos/drivers/usb/nt4compat/usbdriver/ohci.c (original)
+++ trunk/reactos/drivers/usb/nt4compat/usbdriver/ohci.c Wed Nov 21 12:51:03 2007
@@ -37,6 +37,7 @@
 //BOOLEAN ohci_start(PHCD hcd);
 VOID ohci_init_hcd_interface(POHCI_DEV ohci);
 BOOLEAN ohci_rh_reset_port(PHCD hcd, UCHAR port_idx);
+VOID ohci_generic_urb_completion(PURB purb, PVOID context);
 
 // shared with EHCI
 NTSTATUS ehci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp);
@@ -46,8 +47,10 @@
 UCHAR ehci_get_id(PHCD hcd);
 UCHAR ehci_alloc_addr(PHCD hcd);
 VOID ehci_free_addr(PHCD hcd, UCHAR addr);
-
 BOOLEAN NTAPI ehci_cal_cpu_freq(PVOID context);
+
+VOID rh_timer_svc_int_completion(PUSB_DEV pdev, PVOID context);
+VOID rh_timer_svc_reset_port_completion(PUSB_DEV pdev, PVOID context);
 
 extern USB_DEV_MANAGER g_dev_mgr;
 
@@ -109,6 +112,58 @@
 /* this timer value might be vendor-specific ... */
 #define	PORT_RESET_HW_MSEC	10
 
+#define DEFAULT_ENDP( enDP ) \
+( enDP->flags & USB_ENDP_FLAG_DEFAULT_ENDP )
+
+#define dev_from_endp( enDP ) \
+( DEFAULT_ENDP( enDP )\
+  ? ( ( PUSB_DEV )( enDP )->pusb_if )\
+  : ( ( enDP )->pusb_if->pusb_config->pusb_dev ) )
+
+#define endp_state( enDP ) ( ( enDP )->flags & USB_ENDP_FLAG_STAT_MASK )
+
+#define endp_num( enDP ) \
+( DEFAULT_ENDP( enDP )\
+  ? 0 \
+  : ( ( enDP )->pusb_endp_desc->bEndpointAddress & 0x0f ) )
+
+#define endp_dir( enDP ) \
+( DEFAULT_ENDP( enDP )\
+  ? 0L\
+  : ( ( enDP )->pusb_endp_desc->bEndpointAddress & USB_DIR_IN ) )
+
+#define dev_set_state( pdEV, staTE ) \
+( pdEV->flags = ( ( pdEV )->flags & ( ~USB_DEV_STATE_MASK ) ) | ( staTE ) )
+
+#define endp_max_packet_size( enDP ) \
+( DEFAULT_ENDP( enDP )\
+  ? ( ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc ? \
+	  ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc->bMaxPacketSize0\
+	  : 8 )\
+  : ( enDP->pusb_endp_desc->wMaxPacketSize & 0x7ff ) )
+
+#define endp_mult_count( endp ) ( ( ( endp->pusb_endp_desc->wMaxPacketSize & 0x1800 ) >> 11 ) + 1 )
+
+#define get_parent_hs_hub( pDEV, parent_HUB, port_IDX ) \
+{\
+	parent_HUB = pDEV->parent_dev;\
+	port_IDX = pdev->port_idx;\
+	while( parent_HUB )\
+	{\
+		if( ( parent_HUB->flags & USB_DEV_CLASS_MASK ) != USB_DEV_CLASS_HUB )\
+		{\
+			parent_HUB = NULL;\
+			break;\
+		}\
+		if( ( parent_HUB->flags & USB_DEV_FLAG_HIGH_SPEED ) == 0 )\
+		{\
+			port_IDX = parent_HUB->port_idx;\
+			parent_HUB = parent_HUB->parent_dev;\
+			continue;\
+		}\
+		break;\
+	}\
+}
 
 VOID
 ohci_wait_ms(POHCI_DEV ohci, LONG ms)
@@ -396,13 +451,6 @@
     }
 
 #if 0
-    //init ehci_caps
-    // i = ( ( PEHCI_HCS_CONTENT )( &pdev_ext->ehci->ehci_caps.hcs_params ) )->length;
-
-    ehci_get_capabilities(pdev_ext->ehci, pdev_ext->ehci->port_base);
-    i = pdev_ext->ehci->ehci_caps.length;
-    pdev_ext->ehci->port_base += i;
-
     if (ehci_init_schedule(pdev_ext->ehci, pdev_ext->padapter) == FALSE)
     {
         release_adapter(pdev_ext->padapter);
@@ -410,16 +458,18 @@
         ehci_delete_device(pdev);
         return NULL;
     }
-
-    InitializeListHead(&pdev_ext->ehci->urb_list);
-    KeInitializeSpinLock(&pdev_ext->ehci->pending_endp_list_lock);
-    InitializeListHead(&pdev_ext->ehci->pending_endp_list);
-
-    ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_alloc(): pending_endp_list=0x%x\n",
-                                    &pdev_ext->ehci->pending_endp_list));
-
-    init_pending_endp_pool(&pdev_ext->ehci->pending_endp_pool);
-
+#endif
+
+    InitializeListHead(&pdev_ext->ohci->urb_list);
+    KeInitializeSpinLock(&pdev_ext->ohci->pending_endp_list_lock);
+    InitializeListHead(&pdev_ext->ohci->pending_endp_list);
+
+    ohci_dbg_print(DBGLVL_MAXIMUM, ("ohci_alloc(): pending_endp_list=0x%x\n",
+                                    &pdev_ext->ohci->pending_endp_list));
+
+    init_pending_endp_pool(&pdev_ext->ohci->pending_endp_pool);
+
+#if 0
     vector = HalGetInterruptVector(PCIBus,
                                    bus,
                                    pdev_ext->res_interrupt.level,
@@ -660,6 +710,648 @@
     return TRUE;
 }
 
+static VOID NTAPI
+ohci_cancel_pending_endp_urb(IN PVOID Parameter)
+{
+    PLIST_ENTRY abort_list;
+    PUSB_DEV pdev;
+    PURB purb;
+    USE_BASIC_NON_PENDING_IRQL;
+
+    abort_list = (PLIST_ENTRY) Parameter;
+
+    if (abort_list == NULL)
+        return;
+
+    while (IsListEmpty(abort_list) == FALSE)
+    {
+        //these devs are protected by purb's ref-count
+        purb = (PURB) RemoveHeadList(abort_list);
+        pdev = purb->pdev;
+        // purb->status is set when they are added to abort_list
+
+        ohci_generic_urb_completion(purb, purb->context);
+
+        lock_dev(pdev, FALSE);
+        pdev->ref_count--;
+        unlock_dev(pdev, FALSE);
+    }
+    usb_free_mem(abort_list);
+    return;
+}
+
+static NTSTATUS
+ohci_internal_submit_bulk(POHCI_DEV ohci, PURB purb)
+{
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+ohci_internal_submit_ctrl(POHCI_DEV ohci, PURB purb)
+{
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+ohci_internal_submit_int(POHCI_DEV ohci, PURB purb)
+{
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+ohci_internal_submit_iso(POHCI_DEV ohci, PURB purb)
+{
+    return STATUS_SUCCESS;
+}
+
+
+static BOOLEAN
+ohci_process_pending_endp(POHCI_DEV ehci)
+{
+    PUSB_DEV pdev;
+    LIST_ENTRY temp_list, abort_list;
+    PLIST_ENTRY pthis;
+    PURB purb;
+    PUSB_ENDPOINT pendp;
+    NTSTATUS can_submit = STATUS_SUCCESS;
+    PWORK_QUEUE_ITEM pwork_item;
+    PLIST_ENTRY cancel_list;
+    PUSB_DEV pparent = NULL;
+    UCHAR port_idx = 0;
+    BOOLEAN tt_needed;
+    UCHAR hub_addr = 0;
+    USE_BASIC_IRQL;
+
+    if (ehci == NULL)
+        return FALSE;
+
+    InitializeListHead(&temp_list);
+    InitializeListHead(&abort_list);
+
+    purb = NULL;
+    ohci_dbg_print(DBGLVL_MEDIUM, ("ohci_process_pending_endp(): entering..., ehci=0x%x\n", ehci));
+
+    lock_pending_endp_list(&ehci->pending_endp_list_lock);
+    while (IsListEmpty(&ehci->pending_endp_list) == FALSE)
+    {
+
+        ehci_dbg_print(DBGLVL_MAXIMUM, ("ohci_process_pending_endp(): pending_endp_list=0x%x\n",
+                                        &ehci->pending_endp_list));
+
+        tt_needed = FALSE;
+        pthis = RemoveHeadList(&ehci->pending_endp_list);
+        pendp = ((PUHCI_PENDING_ENDP) pthis)->pendp;
+        pdev = dev_from_endp(pendp);
+        lock_dev(pdev, TRUE);
+
+        if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
+        {
+            unlock_dev(pdev, TRUE);
+            free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
+            //delegate to ehci_remove_device for remiving the purb queue on the endpoint
+            continue;
+        }
+        if ((pdev->flags & USB_DEV_FLAG_HIGH_SPEED) == 0)
+        {
+            // prepare split transaction
+            unlock_dev(pdev, TRUE);
+
+            // pparent won't be removed when pending_endp_list_lock is acquired.
+            get_parent_hs_hub(pdev, pparent, port_idx);
+
+            if (pparent == NULL)
+            {
+                TRAP();
+                ehci_dbg_print(DBGLVL_MEDIUM,
+                               ("ohci_process_pending_endp(): full/low speed device with no parent!!!\n"));
+                free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
+                continue;
+            }
+
+            if (hub_lock_tt(pparent, port_idx, (UCHAR) endp_type(pendp)) == FALSE)
+            {
+                lock_dev(pdev, TRUE);
+                if (dev_state(pdev) != USB_DEV_STATE_ZOMB)
+                {
+                    // reinsert the pending-endp to the list
+                    InsertTailList(&temp_list, pthis);
+                    unlock_dev(pdev, TRUE);
+                }
+                else
+                {
+                    // delegate to ehci_remove_device for purb removal
+                    unlock_dev(pdev, TRUE);
+                    free_pending_endp(&ehci->pending_endp_pool,
+                                      struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
+                }
+                continue;
+            }
+
+            // backup the hub address for future use
+            hub_addr = pparent->dev_addr;
+
+            lock_dev(pdev, TRUE);
+            if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
+            {
+                unlock_dev(pdev, TRUE);
+                free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
+                hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
+                continue;
+            }
+            tt_needed = TRUE;
+            // go on processing
+        }
+
+        if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
+        {
+            while (IsListEmpty(&pendp->urb_list) == FALSE)
+            {
+                purb = (PURB) RemoveHeadList(&pendp->urb_list);
+                purb->status = USB_STATUS_ENDPOINT_HALTED;
+                InsertTailList(&abort_list, (LIST_ENTRY *) purb);
+            }
+            InitializeListHead(&pendp->urb_list);
+            unlock_dev(pdev, TRUE);
+            free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
+            if (tt_needed)
+                hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
+            continue;
+        }
+
+        if (IsListEmpty(&pendp->urb_list) == FALSE)
+        {
+            purb = (PURB) RemoveHeadList(&pendp->urb_list);
+            ASSERT(purb);
+        }
+        else
+        {
+            InitializeListHead(&pendp->urb_list);
+            unlock_dev(pdev, TRUE);
+            free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
+            if (tt_needed)
+                hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
+            continue;
+        }
+
+        if (tt_needed)
+        {
+            ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->hub_addr = hub_addr;
+            ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->port_idx = port_idx;
+        }
+
+        // if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
+        switch (endp_type(pendp))
+        {
+            case USB_ENDPOINT_XFER_BULK:
+            {
+                can_submit = ohci_internal_submit_bulk(ehci, purb);
+                break;
+            }
+            case USB_ENDPOINT_XFER_CONTROL:
+            {
+                can_submit = ohci_internal_submit_ctrl(ehci, purb);
+                break;
+            }
+            case USB_ENDPOINT_XFER_INT:
+            {
+                can_submit = ohci_internal_submit_int(ehci, purb);
+                break;
+            }
+            case USB_ENDPOINT_XFER_ISOC:
+            {
+                can_submit = ohci_internal_submit_iso(ehci, purb);
+                break;
+            }
+        }
+
+        if (can_submit == STATUS_NO_MORE_ENTRIES)
+        {
+            //no enough bandwidth or tds
+            InsertHeadList(&pendp->urb_list, (PLIST_ENTRY) purb);
+            InsertTailList(&temp_list, pthis);
+        }
+        else
+        {
+            // otherwise error or success
+            free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
+
+            if (can_submit != STATUS_SUCCESS)
+            {
+                //abort these URBs
+                InsertTailList(&abort_list, (LIST_ENTRY *) purb);
+                purb->status = can_submit;
+            }
+        }
+        unlock_dev(pdev, TRUE);
+        if (can_submit != STATUS_SUCCESS && tt_needed)
+        {
+            hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
+        }
+    }
+
+    if (IsListEmpty(&temp_list) == FALSE)
+    {
+        //re-append them to the pending_endp_list
+        ListFirst(&temp_list, pthis);
+        RemoveEntryList(&temp_list);
+        MergeList(&ehci->pending_endp_list, pthis);
+    }
+    unlock_pending_endp_list(&ehci->pending_endp_list_lock);
+
+    if (IsListEmpty(&abort_list) == FALSE)
+    {
+        PLIST_ENTRY pthis;
+        cancel_list = (PLIST_ENTRY) usb_alloc_mem(NonPagedPool, sizeof(WORK_QUEUE_ITEM) + sizeof(LIST_ENTRY));
+        ASSERT(cancel_list);
+
+        ListFirst(&abort_list, pthis);
+        RemoveEntryList(&abort_list);
+        InsertTailList(pthis, cancel_list);
+
+        pwork_item = (PWORK_QUEUE_ITEM) & cancel_list[1];
+
+        // we do not need to worry the ehci_cancel_pending_endp_urb running when the
+        // driver is unloading since purb-reference count will prevent the dev_mgr to
+        // quit till all the reference count to the dev drop to zero.
+        ExInitializeWorkItem(pwork_item, ohci_cancel_pending_endp_urb, (PVOID) cancel_list);
+        ExQueueWorkItem(pwork_item, DelayedWorkQueue);
+    }
+    return TRUE;
+}
+
+NTSTATUS
+ohci_rh_submit_urb(PUSB_DEV pdev, PURB purb)
+{
+    PUSB_DEV_MANAGER dev_mgr;
+    PTIMER_SVC ptimer;
+    PUSB_CTRL_SETUP_PACKET psetup;
+    POHCI_DEV ohci;
+    NTSTATUS status;
+    PHUB2_EXTENSION hub_ext;
+    PUSB_PORT_STATUS ps, psret;
+    UCHAR port_count;
+
+    USE_NON_PENDING_IRQL;
+    if (pdev == NULL || purb == NULL)
+        return STATUS_INVALID_PARAMETER;
+
+    dev_mgr = dev_mgr_from_dev(pdev);
+
+    KeAcquireSpinLock(&dev_mgr->timer_svc_list_lock, &old_irql);
+    lock_dev(pdev, FALSE);
+    if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
+    {
+        unlock_dev(pdev, FALSE);
+        KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
+        return STATUS_DEVICE_DOES_NOT_EXIST;
+    }
+
+    ohci = ohci_from_hcd(pdev->hcd);
+    psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
+
+    hub_ext = ((PHUB2_EXTENSION) pdev->dev_ext);
+    port_count = ohci->num_ports;
+
+    switch (endp_type(purb->pendp))
+    {
+        case USB_ENDPOINT_XFER_CONTROL:
+        {
+            if (psetup->bmRequestType == 0xa3 && psetup->bRequest == USB_REQ_GET_STATUS)
+            {
+                //get-port-status
+                if (psetup->wIndex == 0 || psetup->wIndex > port_count || psetup->wLength < 4)
+                {
+                    purb->status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+
+                ps = &hub_ext->rh_port_status[psetup->wIndex];
+                psret = (PUSB_PORT_STATUS) purb->data_buffer;
+
+#if 0
+                i = EHCI_PORTSC + 4 * (psetup->wIndex - 1);     // USBPORTSC1;
+                status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
+                ps = &hub_ext->rh_port_status[psetup->wIndex];
+
+                psret = (PUSB_PORT_STATUS) purb->data_buffer;
+                ps->wPortStatus = 0;
+
+                if (status & PORT_CCS)
+                {
+                    ps->wPortStatus |= USB_PORT_STAT_CONNECTION;
+                }
+                if (status & PORT_PE)
+                {
+                    ps->wPortStatus |= USB_PORT_STAT_ENABLE;
+                    ps->wPortStatus |= USB_PORT_STAT_HIGH_SPEED;        // ehci spec
+                }
+                if (status & PORT_PR)
+                {
+                    ps->wPortStatus |= USB_PORT_STAT_RESET;
+                }
+                if (status & PORT_SUSP)
+                {
+                    ps->wPortStatus |= USB_PORT_STAT_SUSPEND;
+                }
+                if (PORT_USB11(status))
+                {
+                    ps->wPortStatus |= USB_PORT_STAT_LOW_SPEED;
+                }
+
+                //always power on
+                ps->wPortStatus |= USB_PORT_STAT_POWER;
+
+                //now set change field
+                if ((status & PORT_CSC) && !(ps->wPortStatus & USB_PORT_STAT_LOW_SPEED))
+                {
+                    ps->wPortChange |= USB_PORT_STAT_C_CONNECTION;
+                }
+                if ((status & PORT_PEC) && !(ps->wPortStatus & USB_PORT_STAT_LOW_SPEED))
+                {
+                    ps->wPortChange |= USB_PORT_STAT_C_ENABLE;
+                }
+#endif
+                //don't touch other fields, might be filled by
+                //other function
+
+                usb_dbg_print(DBGLVL_MAXIMUM,
+                              ("ohci_rh_submit_urb(): get port status, wPortStatus=0x%x, wPortChange=0x%x, address=0x%x\n",
+                               ps->wPortStatus, ps->wPortChange, ps));
+
+                psret->wPortChange = ps->wPortChange;
+                psret->wPortStatus = ps->wPortStatus;
+
+                purb->status = STATUS_SUCCESS;
+
+                break;
+            }
+            else if (psetup->bmRequestType == 0x23 && psetup->bRequest == USB_REQ_CLEAR_FEATURE)
+            {
+                //clear-port-feature
+                if (psetup->wIndex == 0 || psetup->wIndex > port_count)
+                {
+                    purb->status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+#if 0
+                i = EHCI_PORTSC + 4 * (psetup->wIndex - 1);     // USBPORTSC1;
+                ps = &hub_ext->rh_port_status[psetup->wIndex];
+
+                purb->status = STATUS_SUCCESS;
+                switch (psetup->wValue)
+                {
+                    case USB_PORT_FEAT_C_CONNECTION:
+                    {
+                        SET_RH2_PORTSTAT(i, USBPORTSC_CSC);
+                        status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
+                        usb_dbg_print(DBGLVL_MAXIMUM,
+                                      ("ehci_rh_submit_urb(): clear csc, port%d=0x%x\n", psetup->wIndex));
+                        ps->wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
+                        break;
+                    }
+                    case USB_PORT_FEAT_C_ENABLE:
+                    {
+                        SET_RH2_PORTSTAT(i, USBPORTSC_PEC);
+                        status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
+                        usb_dbg_print(DBGLVL_MAXIMUM,
+                                      ("ehci_rh_submit_urb(): clear pec, port%d=0x%x\n", psetup->wIndex));
+                        ps->wPortChange &= ~USB_PORT_STAT_C_ENABLE;
+                        break;
+                    }
+                    case USB_PORT_FEAT_C_RESET:
+                    {
+                        ps->wPortChange &= ~USB_PORT_STAT_C_RESET;
+                        //the reset signal is down in rh_timer_svc_reset_port_completion
+                        // enable or not is set by host controller
+                        // status = EHCI_READ_PORT_ULONG( ( PUSHORT ) ( ehci->port_base + i ) );
+                        usb_dbg_print(DBGLVL_MAXIMUM,
+                                      ("ehci_rh_submit_urb(): clear pr, enable pe, port%d=0x%x\n",
+                                       psetup->wIndex));
+                        break;
+                    }
+                    case USB_PORT_FEAT_ENABLE:
+                    {
+                        ps->wPortStatus &= ~USB_PORT_STAT_ENABLE;
+                        CLR_RH2_PORTSTAT(i, USBPORTSC_PE);
+                        status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
+                        usb_dbg_print(DBGLVL_MAXIMUM,
+                                      ("ehci_rh_submit_urb(): clear pe, port%d=0x%x\n", psetup->wIndex));
+                        break;
+                    }
+                    default:
+                        purb->status = STATUS_UNSUCCESSFUL;
+                }
+#endif
+                break;
+            }
+            else if (psetup->bmRequestType == 0xd3 && psetup->bRequest == HUB_REQ_GET_STATE)
+            {
+                // get bus state
+                if (psetup->wIndex == 0 || psetup->wIndex > port_count || psetup->wLength == 0)
+                {
+                    purb->status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+#if 0
+                i = EHCI_PORTSC + 4 * (psetup->wIndex - 1);     // USBPORTSC1;
+                status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
+                purb->data_buffer[0] = (status & USBPORTSC_LS);
+
+                // reverse the order
+                purb->data_buffer[0] ^= 0x3;
+#endif
+                purb->status = STATUS_SUCCESS;
+                break;
+            }
+            else if (psetup->bmRequestType == 0x23 && psetup->bRequest == USB_REQ_SET_FEATURE)
+            {
+                //reset port
+                if (psetup->wValue != USB_PORT_FEAT_RESET)
+                {
+                    purb->status = STATUS_INVALID_PARAMETER;
+                    ehci_dbg_print(DBGLVL_MAXIMUM,
+                                   ("ehci_rh_submit_urb(): set feature with wValue=0x%x\n", psetup->wValue));
+                    break;
+                }
+
+                ptimer = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
+                ptimer->threshold = 0;  // within [ 50ms, 60ms ], one tick is 10 ms
+                ptimer->context = (ULONG) purb;
+                ptimer->pdev = pdev;
+                ptimer->func = rh_timer_svc_reset_port_completion;
+
+                //start the timer
+                pdev->ref_count += 2;   //one for timer and one for purb
+
+                status =
+                    OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->roothub.portstatus[psetup->wIndex-1]);
+
+                usb_dbg_print(DBGLVL_MAXIMUM,
+                              ("ehci_rh_submit_urb(): reset port, port%d=0x%x\n", psetup->wIndex, status));
+                InsertTailList(&dev_mgr->timer_svc_list, &ptimer->timer_svc_link);
+                purb->status = STATUS_PENDING;
+            }
+            else
+            {
+                purb->status = STATUS_INVALID_PARAMETER;
+            }
+            break;
+        }
+        case USB_ENDPOINT_XFER_INT:
+        {
+            ptimer = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
+            ptimer->threshold = RH_INTERVAL;
+            ptimer->context = (ULONG) purb;
+            ptimer->pdev = pdev;
+            ptimer->func = rh_timer_svc_int_completion;
+
+            //start the timer
+            InsertTailList(&dev_mgr->timer_svc_list, &ptimer->timer_svc_link);
+
+            //usb_dbg_print(DBGLVL_MAXIMUM,
+            //              ("ehci_rh_submit_urb(): current rh's ref_count=0x%x\n", pdev->ref_count));
+            pdev->ref_count += 2;       //one for timer and one for purb
+
+            purb->status = STATUS_PENDING;
+            break;
+        }
+        case USB_ENDPOINT_XFER_BULK:
+        case USB_ENDPOINT_XFER_ISOC:
+        default:
+        {
+            purb->status = STATUS_INVALID_PARAMETER;
+            break;
+        }
+    }
+    unlock_dev(pdev, FALSE);
+    KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
+    return purb->status;
+}
+
+NTSTATUS
+ohci_submit_urb(POHCI_DEV ehci, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
+{
+    int i;
+    PUHCI_PENDING_ENDP pending_endp;
+    NTSTATUS status;
+    USE_BASIC_IRQL;
+
+    if (ehci == NULL)
+        return STATUS_INVALID_PARAMETER;
+
+    if (pdev == NULL || pendp == NULL || purb == NULL)
+    {
+        // give a chance to those pending urb, especially for clearing hub tt
+        ohci_process_pending_endp(ehci);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    lock_pending_endp_list(&ehci->pending_endp_list_lock);
+    lock_dev(pdev, TRUE);
+
+    if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
+    {
+        status = purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
+        goto LBL_OUT;
+    }
+
+    if (dev_class(pdev) == USB_DEV_CLASS_ROOT_HUB)
+    {
+        unlock_dev(pdev, TRUE);
+        unlock_pending_endp_list(&ehci->pending_endp_list_lock);
+        status = ohci_rh_submit_urb(pdev, purb);
+        return status;
+    }
+
+    if (pendp)
+        purb->pendp = pendp;
+    else
+        purb->pendp = &pdev->default_endp;
+
+    if (dev_from_endp(purb->pendp) != pdev)
+    {
+        status = purb->status = STATUS_INVALID_PARAMETER;
+        goto LBL_OUT;
+    }
+
+    if (endp_state(purb->pendp) == USB_ENDP_FLAG_STALL)
+    {
+        status = purb->status = USB_STATUS_ENDPOINT_HALTED;
+        goto LBL_OUT;
+    }
+
+    if ((pdev->flags & USB_DEV_FLAG_HIGH_SPEED) == 0)
+    {
+        // wait one ms
+        usb_wait_ms_dpc(1);
+    }
+
+    purb->pdev = pdev;
+    purb->rest_bytes = purb->data_length;
+
+    if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_BULK)
+        purb->bytes_to_transfer = (purb->data_length > EHCI_MAX_SIZE_TRANSFER ? EHCI_MAX_SIZE_TRANSFER : purb->data_length);    //multiple transfer for large data block
+    else
+        purb->bytes_to_transfer = purb->data_length;
+
+    ehci_dbg_print(DBGLVL_MEDIUM, ("ehci_submit_urb(): bytes_to_transfer=0x%x\n", purb->bytes_to_transfer));
+
+    purb->bytes_transfered = 0;
+    InitializeListHead(&purb->trasac_list);
+    purb->last_finished_td = &purb->trasac_list;
+    purb->flags &= ~(URB_FLAG_STATE_MASK | URB_FLAG_IN_SCHEDULE | URB_FLAG_FORCE_CANCEL);
+    purb->flags |= URB_FLAG_STATE_PENDING;
+
+
+    i = IsListEmpty(&pendp->urb_list);
+    InsertTailList(&pendp->urb_list, &purb->urb_link);
+
+    pdev->ref_count++;          //for purb reference
+
+    if (i == FALSE)
+    {
+        //there is purb pending, simply queue it and return
+        status = purb->status = STATUS_PENDING;
+        goto LBL_OUT;
+    }
+    else if (usb_endp_busy_count(purb->pendp) && endp_type(purb->pendp) != USB_ENDPOINT_XFER_ISOC)
+    {
+        //
+        //No purb waiting but purb overlap not allowed,
+        //so leave it in queue and return, will be scheduled
+        //later
+        //
+        status = purb->status = STATUS_PENDING;
+        goto LBL_OUT;
+    }
+
+    pending_endp = alloc_pending_endp(&ehci->pending_endp_pool, 1);
+    if (pending_endp == NULL)
+    {
+        //panic
+        status = purb->status = STATUS_UNSUCCESSFUL;
+        goto LBL_OUT2;
+    }
+
+    pending_endp->pendp = purb->pendp;
+    InsertTailList(&ehci->pending_endp_list, (PLIST_ENTRY) pending_endp);
+
+    unlock_dev(pdev, TRUE);
+    unlock_pending_endp_list(&ehci->pending_endp_list_lock);
+
+    ohci_process_pending_endp(ehci);
+    return STATUS_PENDING;
+
+  LBL_OUT2:
+    pdev->ref_count--;
+    RemoveEntryList((PLIST_ENTRY) purb);
+
+  LBL_OUT:
+    unlock_dev(pdev, TRUE);
+    unlock_pending_endp_list(&ehci->pending_endp_list_lock);
+    ohci_process_pending_endp(ehci);
+    return status;
+}
 
 ULONG
 ohci_get_type(PHCD hcd)
@@ -670,8 +1362,7 @@
 NTSTATUS
 ohci_submit_urb2(PHCD hcd, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
 {
-    DbgPrint("ohci_submit_urb2 caled, but not implemented!\n");
-    return STATUS_UNSUCCESSFUL;
+    return ohci_submit_urb(ohci_from_hcd(hcd), pdev, pendp, purb);
 }
 
 PUSB_DEV

Modified: trunk/reactos/drivers/usb/nt4compat/usbdriver/ohci.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/nt4compat/usbdriver/ohci.h?rev=30616&r1=30615&r2=30616&view=diff
==============================================================================
--- trunk/reactos/drivers/usb/nt4compat/usbdriver/ohci.h (original)
+++ trunk/reactos/drivers/usb/nt4compat/usbdriver/ohci.h Wed Nov 21 12:51:03 2007
@@ -315,6 +315,15 @@
 
     USHORT              num_ports;
 
+    LIST_HEAD           urb_list;                   	    // active urb-list
+
+	//
+    //for iso and int bandwidth claim, bandwidth schedule
+	//
+	KSPIN_LOCK 			pending_endp_list_lock;				//lock to access the following two
+	LIST_HEAD 			pending_endp_list;
+	UHCI_PENDING_ENDP_POOL  pending_endp_pool;
+
     KTIMER				reset_timer;						//used to reset the host controller
     struct _OHCI_DEVICE_EXTENSION    *pdev_ext;
     PUSB_DEV            root_hub;							//root hub




More information about the Ros-diffs mailing list