[USB]
[reactos.git] / reactos / drivers / usb / usbd / usbd.c
index 2f5fac1..fa3735a 100644 (file)
@@ -5,6 +5,7 @@
  * PURPOSE:     Helper Library for USB
  * PROGRAMMERS:
  *              Filip Navara <xnavara@volny.cz>
+ *              Michael Martin <michael.martin@reactos.org>
  *
  */
 
@@ -33,6 +34,8 @@
 
 #include <ntddk.h>
 #include <usbdi.h>
+#define NDEBUG
+#include <debug.h>
 #ifndef PLUGPLAY_REGKEY_DRIVER
 #define PLUGPLAY_REGKEY_DRIVER              2
 #endif
@@ -71,7 +74,7 @@ DllUnload(VOID)
  */
 PVOID NTAPI
 USBD_Debug_GetHeap(ULONG Unknown1, POOL_TYPE PoolType, ULONG NumberOfBytes,
-       ULONG Tag)
+                   ULONG Tag)
 {
     return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
 }
@@ -100,6 +103,7 @@ USBD_Debug_LogEntry(PCHAR Name, ULONG_PTR Info1, ULONG_PTR Info2,
 PVOID NTAPI
 USBD_AllocateDeviceName(ULONG Unknown)
 {
+    UNIMPLEMENTED
     return NULL;
 }
 
@@ -137,6 +141,7 @@ USBD_CalculateUsbBandwidth(
 ULONG NTAPI
 USBD_Dispatch(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4)
 {
+    UNIMPLEMENTED
     return 1;
 }
 
@@ -146,6 +151,7 @@ USBD_Dispatch(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4)
 VOID NTAPI
 USBD_FreeDeviceMutex(PVOID Unknown)
 {
+    UNIMPLEMENTED
 }
 
 /*
@@ -154,6 +160,7 @@ USBD_FreeDeviceMutex(PVOID Unknown)
 VOID NTAPI
 USBD_FreeDeviceName(PVOID Unknown)
 {
+    UNIMPLEMENTED
 }
 
 /*
@@ -162,6 +169,7 @@ USBD_FreeDeviceName(PVOID Unknown)
 VOID NTAPI
 USBD_WaitDeviceMutex(PVOID Unknown)
 {
+    UNIMPLEMENTED
 }
 
 /*
@@ -170,6 +178,7 @@ USBD_WaitDeviceMutex(PVOID Unknown)
 ULONG NTAPI
 USBD_GetSuspendPowerState(ULONG Unknown1)
 {
+    UNIMPLEMENTED
     return 0;
 }
 
@@ -180,6 +189,7 @@ NTSTATUS NTAPI
 USBD_InitializeDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3,
     ULONG Unknown4, ULONG Unknown5, ULONG Unknown6)
 {
+    UNIMPLEMENTED
     return STATUS_NOT_SUPPORTED;
 }
 
@@ -191,6 +201,7 @@ USBD_RegisterHostController(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3,
     ULONG Unknown4, ULONG Unknown5, ULONG Unknown6, ULONG Unknown7,
     ULONG Unknown8, ULONG Unknown9, ULONG Unknown10)
 {
+    UNIMPLEMENTED
     return STATUS_NOT_SUPPORTED;
 }
 
@@ -200,6 +211,7 @@ USBD_RegisterHostController(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3,
 NTSTATUS NTAPI
 USBD_GetDeviceInformation(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
 {
+    UNIMPLEMENTED
     return STATUS_NOT_SUPPORTED;
 }
 
@@ -210,6 +222,7 @@ NTSTATUS NTAPI
 USBD_CreateDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3,
     ULONG Unknown4, ULONG Unknown5)
 {
+    UNIMPLEMENTED
     return STATUS_NOT_SUPPORTED;
 }
 
@@ -219,6 +232,7 @@ USBD_CreateDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3,
 NTSTATUS NTAPI
 USBD_RemoveDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
 {
+    UNIMPLEMENTED
     return STATUS_NOT_SUPPORTED;
 }
 
@@ -228,6 +242,7 @@ USBD_RemoveDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
 VOID NTAPI
 USBD_CompleteRequest(ULONG Unknown1, ULONG Unknown2)
 {
+    UNIMPLEMENTED
 }
 
 /*
@@ -239,6 +254,7 @@ USBD_RegisterHcFilter(
     PDEVICE_OBJECT FilterDeviceObject
     )
 {
+    UNIMPLEMENTED
 }
 
 /*
@@ -247,6 +263,7 @@ USBD_RegisterHcFilter(
 VOID NTAPI
 USBD_SetSuspendPowerState(ULONG Unknown1, ULONG Unknown2)
 {
+    UNIMPLEMENTED
 }
 
 /*
@@ -255,6 +272,7 @@ USBD_SetSuspendPowerState(ULONG Unknown1, ULONG Unknown2)
 NTSTATUS NTAPI
 USBD_MakePdoName(ULONG Unknown1, ULONG Unknown2)
 {
+    UNIMPLEMENTED
     return STATUS_NOT_SUPPORTED;
 }
 
@@ -267,6 +285,7 @@ USBD_QueryBusTime(
     PULONG CurrentFrame
     )
 {
+    UNIMPLEMENTED
     return STATUS_NOT_SUPPORTED;
 }
 
@@ -281,7 +300,7 @@ USBD_GetUSBDIVersion(
     if (Version != NULL)
     {
         Version->USBDI_Version = USBDI_VERSION;
-        Version->Supported_USB_Version = 0x100;
+        Version->Supported_USB_Version = 0x200;
     }
 }
 
@@ -291,6 +310,7 @@ USBD_GetUSBDIVersion(
 NTSTATUS NTAPI
 USBD_RestoreDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
 {
+    UNIMPLEMENTED
     return STATUS_NOT_SUPPORTED;
 }
 
@@ -301,47 +321,61 @@ VOID NTAPI
 USBD_RegisterHcDeviceCapabilities(ULONG Unknown1, ULONG Unknown2,
     ULONG Unknown3)
 {
+    UNIMPLEMENTED
 }
 
 /*
  * @implemented
- * FIXME: Test
  */
-PURB
-NTAPI
+PURB NTAPI
 USBD_CreateConfigurationRequestEx(
     PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
     PUSBD_INTERFACE_LIST_ENTRY InterfaceList
     )
 {
     PURB Urb;
-    ULONG UrbSize;
+    ULONG UrbSize = 0;
     ULONG InterfaceCount;
+    ULONG InterfaceNumber, EndPointNumber;
+    PUSBD_INTERFACE_INFORMATION InterfaceInfo;
 
     for (InterfaceCount = 0;
          InterfaceList[InterfaceCount].InterfaceDescriptor != NULL;
-         ++InterfaceCount)
-       ;
-    /* Include the NULL entry */
-    ++InterfaceCount;
+         InterfaceCount++)
+    {
+        UrbSize += sizeof(USBD_INTERFACE_INFORMATION);
+        UrbSize += (InterfaceList[InterfaceCount].InterfaceDescriptor->bNumEndpoints - 1) * sizeof(USBD_PIPE_INFORMATION);
+    }
+
+    UrbSize += sizeof(URB) + sizeof(USBD_INTERFACE_INFORMATION);
 
-    UrbSize = sizeof(Urb->UrbSelectConfiguration) +
-       (InterfaceCount * sizeof(PUSBD_INTERFACE_LIST_ENTRY));
     Urb = ExAllocatePool(NonPagedPool, UrbSize);
-    Urb->UrbSelectConfiguration.Hdr.Function =
-        URB_FUNCTION_SELECT_CONFIGURATION;
-    Urb->UrbSelectConfiguration.Hdr.Length =
-        sizeof(Urb->UrbSelectConfiguration);
-    Urb->UrbSelectConfiguration.ConfigurationDescriptor =
-       ConfigurationDescriptor;
-    memcpy((PVOID)&Urb->UrbSelectConfiguration.Interface, (PVOID)InterfaceList,
-       InterfaceCount * sizeof(PUSBD_INTERFACE_LIST_ENTRY));
+    RtlZeroMemory(Urb, UrbSize);
+    Urb->UrbSelectConfiguration.Hdr.Function =  URB_FUNCTION_SELECT_CONFIGURATION;
+    Urb->UrbSelectConfiguration.Hdr.Length = sizeof(Urb->UrbSelectConfiguration);
+    Urb->UrbSelectConfiguration.ConfigurationDescriptor = ConfigurationDescriptor;
+
+    InterfaceInfo = &Urb->UrbSelectConfiguration.Interface;
+    for (InterfaceNumber = 0; InterfaceNumber < InterfaceCount; InterfaceNumber++)
+    {
+        InterfaceList[InterfaceNumber].Interface = InterfaceInfo;
+        InterfaceInfo->Length = sizeof(USBD_INTERFACE_INFORMATION) +
+                                ((InterfaceList[InterfaceNumber].InterfaceDescriptor->bNumEndpoints - 1) * sizeof(USBD_PIPE_INFORMATION));
+        InterfaceInfo->InterfaceNumber = InterfaceList[InterfaceNumber].InterfaceDescriptor->bInterfaceNumber;
+        InterfaceInfo->AlternateSetting = InterfaceList[InterfaceNumber].InterfaceDescriptor->bAlternateSetting;
+        InterfaceInfo->NumberOfPipes = InterfaceList[InterfaceNumber].InterfaceDescriptor->bNumEndpoints;
+        for (EndPointNumber = 0; EndPointNumber < InterfaceInfo->NumberOfPipes; EndPointNumber++)
+        {
+            InterfaceInfo->Pipes[EndPointNumber].MaximumTransferSize = PAGE_SIZE;
+        }
+        InterfaceInfo = (PUSBD_INTERFACE_INFORMATION) ((ULONG_PTR)InterfaceInfo + InterfaceInfo->Length);
+    }
 
     return Urb;
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 PURB NTAPI
 USBD_CreateConfigurationRequest(
@@ -349,11 +383,12 @@ USBD_CreateConfigurationRequest(
     PUSHORT Size
     )
 {
+    /* WindowsXP returns NULL */
     return NULL;
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 ULONG NTAPI
 USBD_GetInterfaceLength(
@@ -363,18 +398,23 @@ USBD_GetInterfaceLength(
 {
     ULONG_PTR Current;
     PUSB_INTERFACE_DESCRIPTOR CurrentDescriptor = InterfaceDescriptor;
-    ULONG Length = CurrentDescriptor->bLength;
+    ULONG Length = 0;
+    BOOLEAN InterfaceFound = FALSE;
 
-    // USB_ENDPOINT_DESCRIPTOR_TYPE
-    if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
+    for (Current = (ULONG_PTR)CurrentDescriptor;
+         Current < (ULONG_PTR)BufferEnd;
+         Current += CurrentDescriptor->bLength)
     {
-        for (Current = (ULONG_PTR)CurrentDescriptor;
-             Current < (ULONG_PTR)BufferEnd;
-             Current += CurrentDescriptor->bLength)
-            CurrentDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Current;
-            Length += CurrentDescriptor->bLength;
+        CurrentDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Current;
+
+        if ((CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) && (InterfaceFound))
+            break;
+        else if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
+            InterfaceFound = TRUE;
 
+        Length += CurrentDescriptor->bLength;
     }
+
     return Length;
 }
 
@@ -389,16 +429,39 @@ USBD_ParseDescriptors(
     LONG  DescriptorType
     )
 {
-    PUSB_COMMON_DESCRIPTOR PComDes = StartPosition;
+    PUSB_COMMON_DESCRIPTOR CommonDescriptor;
 
-    while(PComDes)
+    /* use start position */
+    CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)StartPosition;
+
+
+    /* find next available descriptor */
+    while(CommonDescriptor)
     {
-       if (PComDes >= (PUSB_COMMON_DESCRIPTOR)
-                            ((PLONG)DescriptorBuffer + TotalLength) ) break;
-       if (PComDes->bDescriptorType == DescriptorType) return PComDes;
-       if (PComDes->bLength == 0) break;
-       PComDes = PComDes + PComDes->bLength;
+       if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)DescriptorBuffer + TotalLength))
+       {
+           /* end reached */
+           DPRINT("End reached %p\n", CommonDescriptor);
+           return NULL;
+       }
+
+       DPRINT("CommonDescriptor Type %x Length %x\n", CommonDescriptor->bDescriptorType, CommonDescriptor->bLength);
+
+       /* is the requested one */
+       if (CommonDescriptor->bDescriptorType == DescriptorType)
+       {
+           /* it is */
+           return CommonDescriptor;
+       }
+
+       /* sanity check */
+       ASSERT(CommonDescriptor->bLength);
+
+       /* move to next descriptor */
+       CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
     }
+
+    /* no descriptor found */
     return NULL;
 }
 
@@ -417,45 +480,97 @@ USBD_ParseConfigurationDescriptorEx(
     LONG InterfaceProtocol
     )
 {
-    int x = 0;
-    PUSB_INTERFACE_DESCRIPTOR UsbInterfaceDesc = StartPosition;
+    BOOLEAN Found;
+    PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+
+    /* set to start position */
+    InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)StartPosition;
+
+    DPRINT("USBD_ParseConfigurationDescriptorEx\n");
+    DPRINT("ConfigurationDescriptor %p Length %lu\n", ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength);
+    DPRINT("CurrentOffset %p Offset %lu\n", StartPosition, ((ULONG_PTR)StartPosition - (ULONG_PTR)ConfigurationDescriptor));
 
-    while(UsbInterfaceDesc)
+    while(InterfaceDescriptor)
     {
-       UsbInterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)
-                           USBD_ParseDescriptors(ConfigurationDescriptor,
-                                        ConfigurationDescriptor->wTotalLength,
-                                        UsbInterfaceDesc,
-                                        USB_INTERFACE_DESCRIPTOR_TYPE);
+       /* get interface descriptor */
+       InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, InterfaceDescriptor, USB_INTERFACE_DESCRIPTOR_TYPE);
+       if (!InterfaceDescriptor)
+       {
+           /* no more descriptors available */
+           break;
+       }
+
+       DPRINT("InterfaceDescriptor %p InterfaceNumber %x AlternateSetting %x Length %lu\n", InterfaceDescriptor, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting, InterfaceDescriptor->bLength);
 
-       if (!UsbInterfaceDesc) break;
+       /* set found */
+       Found = TRUE;
 
+       /* is there an interface number provided */
        if(InterfaceNumber != -1)
        {
-          if(InterfaceNumber != UsbInterfaceDesc->bInterfaceNumber) x = 1;
+          if(InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
+          {
+              /* interface number does not match */
+              Found = FALSE;
+          }
        }
+
+       /* is there an alternate setting provided */
        if(AlternateSetting != -1)
        {
-          if(AlternateSetting != UsbInterfaceDesc->bAlternateSetting) x = 1;
+          if(AlternateSetting != InterfaceDescriptor->bAlternateSetting)
+          {
+              /* alternate setting does not match */
+              Found = FALSE;
+          }
        }
+
+       /* match on interface class */
        if(InterfaceClass != -1)
        {
-          if(InterfaceClass != UsbInterfaceDesc->bInterfaceClass) x = 1;
+          if(InterfaceClass != InterfaceDescriptor->bInterfaceClass)
+          {
+              /* no match with interface class criteria */
+              Found = FALSE;
+          }
        }
+
+       /* match on interface sub class */
        if(InterfaceSubClass != -1)
        {
-          if(InterfaceSubClass != UsbInterfaceDesc->bInterfaceSubClass) x = 1;
+          if(InterfaceSubClass != InterfaceDescriptor->bInterfaceSubClass)
+          {
+              /* no interface sub class match */
+              Found = FALSE;
+          }
        }
+
+       /* interface protocol criteria */
        if(InterfaceProtocol != -1)
        {
-          if(InterfaceProtocol != UsbInterfaceDesc->bInterfaceProtocol) x = 1;
+          if(InterfaceProtocol != InterfaceDescriptor->bInterfaceProtocol)
+          {
+              /* no interface protocol match */
+              Found = FALSE;
+          }
        }
 
-       if (!x) return UsbInterfaceDesc;
+       if (Found)
+       {
+           /* the choosen one */
+           return InterfaceDescriptor;
+       }
 
-       if (UsbInterfaceDesc->bLength == 0) break;
-       UsbInterfaceDesc = UsbInterfaceDesc + UsbInterfaceDesc->bLength;
+       /* sanity check */
+       ASSERT(InterfaceDescriptor->bLength);
+
+       /* move to next descriptor */
+       InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
     }
+
+    DPRINT("No Descriptor With InterfaceNumber %ld AlternateSetting %ld InterfaceClass %ld InterfaceSubClass %ld InterfaceProtocol %ld found\n", InterfaceNumber,
+            AlternateSetting, InterfaceClass, InterfaceSubClass, InterfaceProtocol);
+
     return NULL;
 }
 
@@ -490,28 +605,58 @@ USBD_GetPdoRegistryParameter(
     NTSTATUS Status;
     HANDLE DevInstRegKey;
 
+    /* Open the device key */
     Status = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
-        PLUGPLAY_REGKEY_DRIVER, STANDARD_RIGHTS_ALL, &DevInstRegKey);
+        PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, &DevInstRegKey);
     if (NT_SUCCESS(Status))
     {
-        PKEY_VALUE_FULL_INFORMATION FullInfo;
+        PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
         UNICODE_STRING ValueName;
         ULONG Length;
 
-        RtlInitUnicodeString(&ValueName, KeyName);
-        Length = ParameterLength + KeyNameLength + sizeof(KEY_VALUE_FULL_INFORMATION);
-        FullInfo = ExAllocatePool(PagedPool, Length);
-        if (FullInfo)
+        /* Initialize the unicode string based on caller data */
+        ValueName.Buffer = KeyName;
+        ValueName.Length = ValueName.MaximumLength = KeyNameLength;
+
+        Length = ParameterLength + sizeof(KEY_VALUE_PARTIAL_INFORMATION);
+        PartialInfo = ExAllocatePool(PagedPool, Length);
+        if (PartialInfo)
         {
             Status = ZwQueryValueKey(DevInstRegKey, &ValueName,
-                KeyValueFullInformation, FullInfo, Length, &Length);
+                KeyValuePartialInformation, PartialInfo, Length, &Length);
+            if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
+            {
+                /* The caller doesn't want all the data */
+                ExFreePool(PartialInfo);
+                PartialInfo = ExAllocatePool(PagedPool, Length);
+                if (PartialInfo)
+                {
+                    Status = ZwQueryValueKey(DevInstRegKey, &ValueName,
+                       KeyValuePartialInformation, PartialInfo, Length, &Length);
+                }
+                else
+                {
+                    Status = STATUS_NO_MEMORY;
+                }
+            }
+
             if (NT_SUCCESS(Status))
             {
+                /* Compute the length to copy back */
+                if (ParameterLength < PartialInfo->DataLength)
+                    Length = ParameterLength;
+                else
+                    Length = PartialInfo->DataLength;
+
                 RtlCopyMemory(Parameter,
-                    ((PUCHAR)FullInfo) + FullInfo->DataOffset,
-                    ParameterLength /*FullInfo->DataLength*/);
+                              PartialInfo->Data,
+                              Length);
+            }
+
+            if (PartialInfo)
+            {
+                ExFreePool(PartialInfo);
             }
-            ExFreePool(FullInfo);
         } else
             Status = STATUS_NO_MEMORY;
         ZwClose(DevInstRegKey);