[USBEHCI]
[reactos.git] / drivers / usb / usbehci / hub_controller.cpp
index 8342a7d..1dc1962 100644 (file)
@@ -70,6 +70,9 @@ public:
     NTSTATUS HandleClassEndpoint(IN OUT PIRP Irp, PURB Urb);
     NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb);
     NTSTATUS HandleIsochronousTransfer(IN OUT PIRP Irp, PURB Urb);
+    NTSTATUS HandleClearStall(IN OUT PIRP Irp, PURB Urb);
+    NTSTATUS HandleSyncResetAndClearStall(IN OUT PIRP Irp, PURB Urb);
+    NTSTATUS HandleAbortPipe(IN OUT PIRP Irp, PURB Urb);
 
     friend VOID StatusChangeEndpointCallBack(PVOID Context);
 
@@ -824,7 +827,7 @@ CHubController::HandleBulkOrInterruptTransfer(
     PURB Urb)
 {
     PUSBDEVICE UsbDevice;
-    PUSB_ENDPOINT_DESCRIPTOR EndPointDesc = NULL;
+    PUSB_ENDPOINT EndPointDesc = NULL;
     //
     // First check if the request is for the Status Change Endpoint
     //
@@ -853,13 +856,13 @@ CHubController::HandleBulkOrInterruptTransfer(
     //
     // Check PipeHandle to determine if this is a Bulk or Interrupt Transfer Request
     //
-    EndPointDesc = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
+    EndPointDesc = (PUSB_ENDPOINT)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
 
     //
     // sanity checks
     //
     ASSERT(EndPointDesc);
-    ASSERT((EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK || (EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
+    ASSERT((EndPointDesc->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK || (EndPointDesc->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
 
     //
     // check if this is a valid usb device handle
@@ -878,7 +881,6 @@ CHubController::HandleBulkOrInterruptTransfer(
     // get device
     //
     UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
-
     return UsbDevice->SubmitIrp(Irp);
 }
 
@@ -1168,7 +1170,6 @@ CHubController::HandleGetStatusFromDevice(
     //
     // sanity checks
     //
-    PC_ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
     PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBufferLength >= sizeof(USHORT));
     PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBuffer);
 
@@ -1212,10 +1213,26 @@ CHubController::HandleGetStatusFromDevice(
      CtrlSetup.bRequest = USB_REQUEST_GET_STATUS;
      CtrlSetup.wValue.LowByte = 0;
      CtrlSetup.wValue.HiByte = 0;
-     CtrlSetup.wIndex.W = Urb->UrbControlGetStatusRequest.Index; 
+     CtrlSetup.wIndex.W = Urb->UrbControlGetStatusRequest.Index;
      CtrlSetup.wLength = (USHORT)Urb->UrbControlGetStatusRequest.TransferBufferLength;
      CtrlSetup.bmRequestType.B = 0x80;
 
+
+     if (Urb->UrbHeader.Function == URB_FUNCTION_GET_STATUS_FROM_INTERFACE)
+     {
+         //
+         // add interface type
+         //
+         CtrlSetup.bmRequestType.B |= 0x01;
+     }
+     else if (Urb->UrbHeader.Function == URB_FUNCTION_GET_STATUS_FROM_ENDPOINT)
+     {
+         //
+         // add interface type
+         //
+         CtrlSetup.bmRequestType.B |= 0x02;
+     }
+
     //
     // submit setup packet
     //
@@ -1675,12 +1692,21 @@ CHubController::HandleClassEndpoint(
     //
     // initialize setup packet
     //
-    CtrlSetup.bmRequestType.B = 0xa2; //FIXME: Const.
+    CtrlSetup.bmRequestType.B = 0x22; //FIXME: Const.
     CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
     CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
     CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
     CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength;
 
+    if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+    {
+        //
+        // data direction is device to host
+        //
+        CtrlSetup.bmRequestType.B |= 0x80;
+    }
+
+
     //
     // issue request
     //
@@ -1698,6 +1724,185 @@ CHubController::HandleClassEndpoint(
     return Status;
 }
 
+NTSTATUS
+CHubController::HandleSyncResetAndClearStall(
+    IN OUT PIRP Irp,
+    IN OUT PURB Urb)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PUSB_ENDPOINT EndpointDescriptor;
+    ULONG Type;
+
+    //
+    // sanity check
+    //
+    PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
+    PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST));
+    PC_ASSERT(Urb->UrbPipeRequest.PipeHandle);
+
+    //
+    // check if this is a valid usb device handle
+    //
+    if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+    {
+        DPRINT1("HandleAbortPipe invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // invalid device handle
+        //
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
+
+    //
+    // get endpoint descriptor
+    //
+    EndpointDescriptor = (PUSB_ENDPOINT)Urb->UrbPipeRequest.PipeHandle;
+
+    //
+    // get type
+    //
+    Type = (EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK);
+    if (Type != USB_ENDPOINT_TYPE_ISOCHRONOUS)
+    {
+        //
+        // clear stall
+        //
+        Status = HandleClearStall(Irp, Urb);
+    }
+    DPRINT1("URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL Status %x\n", Status);
+
+    //
+    // reset data toggle
+    //
+    ASSERT(NT_SUCCESS(Status));
+    EndpointDescriptor->DataToggle = 0x0;
+
+    //
+    // done
+    //
+    return Status;
+}
+
+NTSTATUS
+CHubController::HandleAbortPipe(
+    IN OUT PIRP Irp,
+    IN OUT PURB Urb)
+{
+    NTSTATUS Status;
+    PUSBDEVICE UsbDevice;
+    PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+
+    //
+    // sanity check
+    //
+    PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
+    PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST));
+    PC_ASSERT(Urb->UrbPipeRequest.PipeHandle);
+
+    //
+    // check if this is a valid usb device handle
+    //
+    if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+    {
+        DPRINT1("HandleAbortPipe invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // invalid device handle
+        //
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
+
+    //
+    // get endpoint descriptor
+    //
+    EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbPipeRequest.PipeHandle;
+
+    //
+    // get device
+    //
+    UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+
+    //
+    // issue request
+    //
+    Status = UsbDevice->AbortPipe(EndpointDescriptor);
+    DPRINT1("URB_FUNCTION_ABORT_PIPE Status %x\n", Status);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleClearStall(
+    IN OUT PIRP Irp,
+    IN OUT PURB Urb)
+{
+    USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+    NTSTATUS Status;
+    PUSBDEVICE UsbDevice;
+    PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+
+
+    //
+    // sanity check
+    //
+    PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
+    PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST));
+    PC_ASSERT(Urb->UrbPipeRequest.PipeHandle);
+
+    //
+    // check if this is a valid usb device handle
+    //
+    if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+    {
+        DPRINT1("HandleClearStall invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // invalid device handle
+        //
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
+
+    //
+    // get endpoint descriptor
+    //
+    EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbPipeRequest.PipeHandle;
+
+    //
+    // get device
+    //
+    UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+    DPRINT1("URB_FUNCTION_SYNC_CLEAR_STALL\n");
+
+    //
+    // initialize setup packet
+    //
+    CtrlSetup.bmRequestType.B = 0x02;
+    CtrlSetup.bRequest = USB_REQUEST_CLEAR_FEATURE;
+    CtrlSetup.wValue.W = USB_FEATURE_ENDPOINT_STALL;
+    CtrlSetup.wIndex.W = EndpointDescriptor->bEndpointAddress;
+    CtrlSetup.wLength = 0;
+    CtrlSetup.wValue.W = 0;
+
+    //
+    // issue request
+    //
+    Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, 0, 0);
+
+    DPRINT1("URB_FUNCTION_CLEAR_STALL Status %x\n", Status);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+
 //-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::HandleClassInterface(
@@ -1747,12 +1952,20 @@ CHubController::HandleClassInterface(
     //
     // initialize setup packet
     //
-    CtrlSetup.bmRequestType.B = 0xa1; //FIXME: Const.
+    CtrlSetup.bmRequestType.B = 0x21;
     CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
     CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
     CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
     CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength;
 
+    if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+    {
+        //
+        // data direction is device to host
+        //
+        CtrlSetup.bmRequestType.B |= 0x80;
+    }
+
     //
     // issue request
     //
@@ -1761,8 +1974,13 @@ CHubController::HandleClassInterface(
     //
     // assert on failure
     //
-    PC_ASSERT(NT_SUCCESS(Status));
-
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // display error
+        //
+        DPRINT1("URB_FUNCTION_CLASS_INTERFACE failed with Urb Status %x\n", Urb->UrbHeader.Status);
+    }
 
     //
     // done
@@ -1806,6 +2024,16 @@ CHubController::HandleDeviceControl(
 
             switch (Urb->UrbHeader.Function)
             {
+                case URB_FUNCTION_SYNC_RESET_PIPE:
+                case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL:
+                    Status = HandleSyncResetAndClearStall(Irp, Urb);
+                    break;
+                case URB_FUNCTION_ABORT_PIPE:
+                    Status = HandleAbortPipe(Irp, Urb);
+                    break;
+                case URB_FUNCTION_SYNC_CLEAR_STALL:
+                    Status = HandleClearStall(Irp, Urb);
+                    break;
                 case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE:
                     Status = HandleGetDescriptorFromInterface(Irp, Urb);
                     break;
@@ -1816,6 +2044,8 @@ CHubController::HandleDeviceControl(
                     Status = HandleClassDevice(Irp, Urb);
                     break;
                 case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
+                case URB_FUNCTION_GET_STATUS_FROM_INTERFACE:
+                case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT:
                     Status = HandleGetStatusFromDevice(Irp, Urb);
                     break;
                 case URB_FUNCTION_SELECT_CONFIGURATION:
@@ -2309,7 +2539,7 @@ USBHI_CreateUsbDevice(
     //
     // now initialize device
     //
-    Status = NewUsbDevice->Initialize(PHUBCONTROLLER(Controller), Controller->GetUsbHardware(),PVOID(Controller), PortNumber, PortStatus);
+    Status = NewUsbDevice->Initialize(PHUBCONTROLLER(Controller), Controller->GetUsbHardware(), HubDeviceHandle, PortNumber, PortStatus);
 
     //
     // check for success