[USBOHCI]
[reactos.git] / drivers / usb / usbohci / usb_request.cpp
index f6762c0..48fc41d 100644 (file)
@@ -36,8 +36,8 @@ public:
     }
 
     // IUSBRequest interface functions
-    virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer);
-    virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp);
+    virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN USB_DEVICE_SPEED DeviceSpeed, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer);
+    virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp, IN USB_DEVICE_SPEED DeviceSpeed);
     virtual BOOLEAN IsRequestComplete();
     virtual ULONG GetTransferType();
     virtual NTSTATUS GetEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutEndpointDescriptor);
@@ -64,6 +64,8 @@ public:
     NTSTATUS CreateIsochronousTransferDescriptor(OUT POHCI_ISO_TD *OutDescriptor, ULONG FrameCount);
     UCHAR GetEndpointAddress();
     USHORT GetMaxPacketSize();
+    VOID CheckError(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
+
 
     // constructor / destructor
     CUSBRequest(IUnknown *OuterUnknown){}
@@ -134,6 +136,15 @@ protected:
     NTSTATUS m_NtStatusCode;
     ULONG m_UrbStatusCode;
 
+    //
+    // device speed
+    //
+    USB_DEVICE_SPEED m_DeviceSpeed;
+
+    //
+    // store urb
+    //
+    PURB m_Urb;
 };
 
 //----------------------------------------------------------------------------------------
@@ -153,6 +164,7 @@ CUSBRequest::InitializeWithSetupPacket(
     IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
     IN UCHAR DeviceAddress,
     IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
+    IN USB_DEVICE_SPEED DeviceSpeed,
     IN OUT ULONG TransferBufferLength,
     IN OUT PMDL TransferBuffer)
 {
@@ -172,6 +184,7 @@ CUSBRequest::InitializeWithSetupPacket(
     m_DeviceAddress = DeviceAddress;
     m_EndpointDescriptor = EndpointDescriptor;
     m_TotalBytesTransferred = 0;
+    m_DeviceSpeed = DeviceSpeed;
 
     //
     // Set Length Completed to 0
@@ -204,10 +217,10 @@ CUSBRequest::InitializeWithSetupPacket(
 NTSTATUS
 CUSBRequest::InitializeWithIrp(
     IN PDMAMEMORYMANAGER DmaManager,
-    IN OUT PIRP Irp)
+    IN OUT PIRP Irp,
+    IN USB_DEVICE_SPEED DeviceSpeed)
 {
     PIO_STACK_LOCATION IoStack;
-    PURB Urb;
 
     //
     // sanity checks
@@ -233,46 +246,51 @@ CUSBRequest::InitializeWithIrp(
     //
     // get urb
     //
-    Urb = (PURB)IoStack->Parameters.Others.Argument1;
+    m_Urb = (PURB)IoStack->Parameters.Others.Argument1;
 
     //
     // store irp
     //
     m_Irp = Irp;
 
+    //
+    // store speed
+    //
+    m_DeviceSpeed = DeviceSpeed;
+
     //
     // check function type
     //
-    switch (Urb->UrbHeader.Function)
+    switch (m_Urb->UrbHeader.Function)
     {
         case URB_FUNCTION_ISOCH_TRANSFER:
         {
             //
             // there must be at least one packet
             //
-            ASSERT(Urb->UrbIsochronousTransfer.NumberOfPackets);
+            ASSERT(m_Urb->UrbIsochronousTransfer.NumberOfPackets);
 
             //
             // is there data to be transferred
             //
-            if (Urb->UrbIsochronousTransfer.TransferBufferLength)
+            if (m_Urb->UrbIsochronousTransfer.TransferBufferLength)
             {
                 //
                 // Check if there is a MDL
                 //
-                if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
+                if (!m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
                 {
                     //
                     // sanity check
                     //
-                    PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
+                    PC_ASSERT(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
 
                     //
                     // Create one using TransferBuffer
                     //
-                    DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
-                    m_TransferBufferMDL = IoAllocateMdl(Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
-                                                        Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
+                    DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer, m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
+                    m_TransferBufferMDL = IoAllocateMdl(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
+                                                        m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
                                                         FALSE,
                                                         FALSE,
                                                         NULL);
@@ -296,14 +314,14 @@ CUSBRequest::InitializeWithIrp(
                     //
                     // use provided mdl
                     //
-                    m_TransferBufferMDL = Urb->UrbIsochronousTransfer.TransferBufferMDL;
+                    m_TransferBufferMDL = m_Urb->UrbIsochronousTransfer.TransferBufferMDL;
                 }
             }
  
             //
             // save buffer length
             //
-            m_TransferBufferLength = Urb->UrbIsochronousTransfer.TransferBufferLength;
+            m_TransferBufferLength = m_Urb->UrbIsochronousTransfer.TransferBufferLength;
 
             //
             // Set Length Completed to 0
@@ -313,7 +331,7 @@ CUSBRequest::InitializeWithIrp(
             //
             // get endpoint descriptor
             //
-            m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbIsochronousTransfer.PipeHandle;
+            m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)m_Urb->UrbIsochronousTransfer.PipeHandle;
 
             //
             // completed initialization
@@ -330,24 +348,24 @@ CUSBRequest::InitializeWithIrp(
             //
             // bulk interrupt transfer
             //
-            if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
+            if (m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
             {
                 //
                 // Check if there is a MDL
                 //
-                if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
+                if (!m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
                 {
                     //
                     // sanity check
                     //
-                    PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
+                    PC_ASSERT(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
 
                     //
                     // Create one using TransferBuffer
                     //
-                    DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
-                    m_TransferBufferMDL = IoAllocateMdl(Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
-                                                        Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
+                    DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer, m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
+                    m_TransferBufferMDL = IoAllocateMdl(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
+                                                        m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
                                                         FALSE,
                                                         FALSE,
                                                         NULL);
@@ -372,13 +390,13 @@ CUSBRequest::InitializeWithIrp(
                 }
                 else
                 {
-                    m_TransferBufferMDL = Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL;
+                    m_TransferBufferMDL = m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL;
                 }
 
                 //
                 // save buffer length
                 //
-                m_TransferBufferLength = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
+                m_TransferBufferLength = m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
 
                 //
                 // Set Length Completed to 0
@@ -388,13 +406,13 @@ CUSBRequest::InitializeWithIrp(
                 //
                 // get endpoint descriptor
                 //
-                m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
+                m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)m_Urb->UrbBulkOrInterruptTransfer.PipeHandle;
 
             }
             break;
         }
         default:
-            DPRINT1("URB Function: not supported %x\n", Urb->UrbHeader.Function);
+            DPRINT1("URB Function: not supported %x\n", m_Urb->UrbHeader.Function);
             PC_ASSERT(FALSE);
     }
 
@@ -654,7 +672,7 @@ NTSTATUS
 CUSBRequest::BuildIsochronousEndpoint(
     POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
 {
-    POHCI_ISO_TD FirstDescriptor, PreviousDescriptor = NULL, CurrentDescriptor;
+    POHCI_ISO_TD FirstDescriptor = NULL, PreviousDescriptor = NULL, CurrentDescriptor = NULL;
     POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
     ULONG Index = 0, SubIndex, NumberOfPackets, PageOffset, Page;
     NTSTATUS Status;
@@ -941,7 +959,7 @@ CUSBRequest::AllocateEndpointDescriptor(
     Descriptor->Flags |= OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(GetEndpointAddress());
     Descriptor->Flags |= OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(GetMaxPacketSize());
 
-    DPRINT1("Flags %x DeviceAddress %x EndpointAddress %x PacketSize %x\n", Descriptor->Flags, GetDeviceAddress(), GetEndpointAddress(), GetMaxPacketSize());
+    DPRINT("Flags %x DeviceAddress %x EndpointAddress %x PacketSize %x\n", Descriptor->Flags, GetDeviceAddress(), GetEndpointAddress(), GetMaxPacketSize());
 
     //
     // is there an endpoint descriptor
@@ -968,11 +986,30 @@ CUSBRequest::AllocateEndpointDescriptor(
 
     }
 
-
     //
-    // FIXME: detect type
+    // set type
     //
-    Descriptor->Flags |= OHCI_ENDPOINT_FULL_SPEED;
+    if (m_DeviceSpeed == UsbFullSpeed)
+    {
+        //
+        // device is full speed
+        //
+        Descriptor->Flags |= OHCI_ENDPOINT_FULL_SPEED;
+    }
+    else if (m_DeviceSpeed == UsbLowSpeed)
+    {
+        //
+        // device is full speed
+        //
+        Descriptor->Flags |= OHCI_ENDPOINT_LOW_SPEED;
+    }
+    else
+    {
+        //
+        // error
+        //
+        ASSERT(FALSE);
+    }
 
     Descriptor->HeadPhysicalDescriptor = 0;
     Descriptor->NextPhysicalEndpoint = 0;
@@ -1098,6 +1135,19 @@ CUSBRequest::BuildBulkInterruptEndpoint(
         CurrentDescriptor->BufferPhysical = MmGetPhysicalAddress(Buffer).LowPart;
         CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + CurrentSize - 1; 
 
+#if 0
+        if (m_Urb != NULL)
+        {
+            if (m_Urb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_SHORT_TRANSFER_OK)
+            {
+                //
+                // indicate short packet support
+                //
+                CurrentDescriptor->Flags |= OHCI_TD_BUFFER_ROUNDING;
+            }
+        }
+#endif
+
         //
         // is there a previous descriptor
         //
@@ -1269,20 +1319,49 @@ CUSBRequest::BuildControlTransferDescriptor(
         //
         // initialize data descriptor
         //
-        DataDescriptor->Flags = OHCI_TD_BUFFER_ROUNDING| OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE) | OHCI_TD_TOGGLE_CARRY | OHCI_TD_DIRECTION_PID_IN;
+        DataDescriptor->Flags = OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE) | OHCI_TD_TOGGLE_CARRY | OHCI_TD_TOGGLE_1;
+
+        if (m_EndpointDescriptor)
+        {
+            if (USB_ENDPOINT_DIRECTION_OUT(m_EndpointDescriptor->bEndpointAddress))
+            {
+                //
+                // direction out
+                //
+                DataDescriptor->Flags |= OHCI_TD_DIRECTION_PID_OUT;
+            }
+            else
+            {
+                //
+                // direction in
+                //
+                DataDescriptor->Flags |= OHCI_TD_DIRECTION_PID_IN;
+            }
+        }
+        else
+        {
+            //
+            // no end point address provided - assume its an in direction
+            //
+            DataDescriptor->Flags |= OHCI_TD_DIRECTION_PID_IN;
+        }
+
+        //
+        // use short packets
+        //
+        DataDescriptor->Flags |= OHCI_TD_BUFFER_ROUNDING;
 
         //
         // store physical address of buffer
         //
         DataDescriptor->BufferPhysical = MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL)).LowPart;
         DataDescriptor->LastPhysicalByteAddress = DataDescriptor->BufferPhysical + m_TransferBufferLength - 1; 
-
     }
 
     //
     // initialize setup descriptor
     //
-    SetupDescriptor->Flags = OHCI_TD_DIRECTION_PID_SETUP | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_TOGGLE_0 | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE);
+    SetupDescriptor->Flags = OHCI_TD_BUFFER_ROUNDING | OHCI_TD_DIRECTION_PID_SETUP | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_TOGGLE_0 | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE);
 
     if (m_SetupPacket)
     {
@@ -1561,13 +1640,14 @@ CUSBRequest::FreeEndpointDescriptor(
 }
 
 VOID
-CUSBRequest::CompletionCallback(
+CUSBRequest::CheckError(
     struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
 {
-    PIO_STACK_LOCATION IoStack;
+    POHCI_GENERAL_TD TransferDescriptor;
+    ULONG ConditionCode;
     PURB Urb;
+    PIO_STACK_LOCATION IoStack;
 
-    DPRINT("CUSBRequest::CompletionCallback Descriptor %p PhysicalAddress %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
 
     //
     // set status code
@@ -1575,12 +1655,138 @@ CUSBRequest::CompletionCallback(
     m_NtStatusCode = STATUS_SUCCESS;
     m_UrbStatusCode = USBD_STATUS_SUCCESS;
 
+
+    if (OutDescriptor->Flags & OHCI_ENDPOINT_ISOCHRONOUS_FORMAT)
+    {
+        //
+        // FIXME: handle isochronous support
+        //
+        ASSERT(FALSE);
+    }
+    else
+    {
+        //
+        // get first general transfer descriptor
+        //
+        TransferDescriptor = (POHCI_GENERAL_TD)OutDescriptor->HeadLogicalDescriptor;
+
+        while(TransferDescriptor)
+        {
+             //
+             // the descriptor must have been processed
+             //
+            ASSERT(OHCI_TD_GET_CONDITION_CODE(TransferDescriptor->Flags) != OHCI_TD_CONDITION_NOT_ACCESSED);
+
+            //
+            // get condition code
+            //
+            ConditionCode = OHCI_TD_GET_CONDITION_CODE(TransferDescriptor->Flags);
+            if (ConditionCode != OHCI_TD_CONDITION_NO_ERROR)
+            {
+                //
+                // FIXME status code
+                //
+                m_NtStatusCode = STATUS_UNSUCCESSFUL;
+
+                switch(ConditionCode)
+                {
+                    case OHCI_TD_CONDITION_CRC_ERROR:
+                        DPRINT1("OHCI_TD_CONDITION_CRC_ERROR detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
+                        m_UrbStatusCode = USBD_STATUS_CRC;
+                        break;
+                    case OHCI_TD_CONDITION_BIT_STUFFING:
+                        DPRINT1("OHCI_TD_CONDITION_BIT_STUFFING detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
+                        m_UrbStatusCode = USBD_STATUS_BTSTUFF;
+                        break;
+                    case OHCI_TD_CONDITION_TOGGLE_MISMATCH:
+                        DPRINT1("OHCI_TD_CONDITION_TOGGLE_MISMATCH detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
+                        m_UrbStatusCode = USBD_STATUS_DATA_TOGGLE_MISMATCH;
+                        break;
+                    case OHCI_TD_CONDITION_STALL:
+                        DPRINT1("OHCI_TD_CONDITION_STALL detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
+                        m_UrbStatusCode = USBD_STATUS_STALL_PID;
+                        break;
+                    case OHCI_TD_CONDITION_NO_RESPONSE:
+                        DPRINT1("OHCI_TD_CONDITION_NO_RESPONSE detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
+                        m_UrbStatusCode = USBD_STATUS_DEV_NOT_RESPONDING;
+                        break;
+                    case OHCI_TD_CONDITION_PID_CHECK_FAILURE:
+                        DPRINT1("OHCI_TD_CONDITION_PID_CHECK_FAILURE detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
+                        m_UrbStatusCode = USBD_STATUS_PID_CHECK_FAILURE;
+                        break;
+                    case OHCI_TD_CONDITION_UNEXPECTED_PID:
+                        DPRINT1("OHCI_TD_CONDITION_UNEXPECTED_PID detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
+                        m_UrbStatusCode = USBD_STATUS_UNEXPECTED_PID;
+                        break;
+                    case OHCI_TD_CONDITION_DATA_OVERRUN:
+                        DPRINT1("OHCI_TD_CONDITION_DATA_OVERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
+                        m_UrbStatusCode = USBD_STATUS_DATA_OVERRUN;
+                        break;
+                    case OHCI_TD_CONDITION_DATA_UNDERRUN:
+                        if (m_Irp)
+                        {
+                            //
+                            // get current irp stack location
+                            //
+                            IoStack = IoGetCurrentIrpStackLocation(m_Irp);
+
+                            //
+                            // get urb
+                            //
+                            Urb = (PURB)IoStack->Parameters.Others.Argument1;
+
+                            if(Urb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_SHORT_TRANSFER_OK)
+                            {
+                                //
+                                // short packets are ok
+                                //
+                                ASSERT(Urb->UrbHeader.Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER);
+                                m_NtStatusCode = STATUS_SUCCESS;
+                                break;
+                            }
+                        }
+                        DPRINT1("OHCI_TD_CONDITION_DATA_UNDERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
+                        m_UrbStatusCode = USBD_STATUS_DATA_UNDERRUN;
+                        break;
+                    case OHCI_TD_CONDITION_BUFFER_OVERRUN:
+                        DPRINT1("OHCI_TD_CONDITION_BUFFER_OVERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
+                        m_UrbStatusCode = USBD_STATUS_BUFFER_OVERRUN;
+                        break;
+                    case OHCI_TD_CONDITION_BUFFER_UNDERRUN:
+                        DPRINT1("OHCI_TD_CONDITION_BUFFER_UNDERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
+                        m_UrbStatusCode = USBD_STATUS_BUFFER_UNDERRUN;
+                        break;
+                }
+            }
+
+            //
+            // get next
+            //
+            TransferDescriptor = (POHCI_GENERAL_TD)TransferDescriptor->NextLogicalDescriptor;
+        }
+    }
+}
+
+VOID
+CUSBRequest::CompletionCallback(
+    struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
+{
+    PIO_STACK_LOCATION IoStack;
+    PURB Urb;
+
+    DPRINT("CUSBRequest::CompletionCallback Descriptor %p PhysicalAddress %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
+
+    //
+    // check for errors
+    //
+    CheckError(OutDescriptor);
+
     if (m_Irp)
     {
         //
         // set irp completion status
         //
-        m_Irp->IoStatus.Status = STATUS_SUCCESS; //FIXME
+        m_Irp->IoStatus.Status = m_NtStatusCode;
 
         //
         // get current irp stack location
@@ -1595,7 +1801,7 @@ CUSBRequest::CompletionCallback(
         //
         // store urb status
         //
-        Urb->UrbHeader.Status = USBD_STATUS_SUCCESS; //FIXME
+        Urb->UrbHeader.Status = m_UrbStatusCode;
 
         //
         // Check if the MDL was created