[USB-BRINGUP]
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Mon, 26 Dec 2011 21:51:05 +0000 (21:51 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Mon, 26 Dec 2011 21:51:05 +0000 (21:51 +0000)
- Implement retrieving device / configuration descriptor
- Partly implement hid descriptor parsing
- Select configuration when initialization is complete
- Implement starting up device

svn path=/branches/usb-bringup/; revision=54765

drivers/hid/hidusb/hidusb.c
drivers/hid/hidusb/hidusb.h

index db632c7..4557431 100644 (file)
@@ -86,13 +86,13 @@ HidInternalDeviceControl(
             //
             // store result
             //
-            ASSERT(HidDeviceExtension->HidDescriptor);
+            ASSERT(HidDeviceExtension->DeviceDescriptor);
             Irp->IoStatus.Information = sizeof(HID_DESCRIPTOR);
             Attributes = (PHID_DEVICE_ATTRIBUTES)Irp->UserBuffer;
             Attributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
-            Attributes->VendorID = HidDeviceExtension->VendorID;
-            Attributes->ProductID = HidDeviceExtension->ProductID;
-            Attributes->VersionNumber = HidDeviceExtension->VersionNumber;
+            Attributes->VendorID = HidDeviceExtension->DeviceDescriptor->idVendor;
+            Attributes->ProductID = HidDeviceExtension->DeviceDescriptor->idProduct;
+            Attributes->VersionNumber = HidDeviceExtension->DeviceDescriptor->bcdDevice;
 
             //
             // complete request
@@ -186,14 +186,6 @@ HidSystemControl(
     return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
 }
 
-NTSTATUS
-Hid_PnpStart(
-    IN PDEVICE_OBJECT DeviceObject)
-{
-    UNIMPLEMENTED
-    return STATUS_NOT_IMPLEMENTED;
-}
-
 NTSTATUS
 NTAPI
 Hid_PnpCompletion(
@@ -212,6 +204,437 @@ Hid_PnpCompletion(
     return STATUS_MORE_PROCESSING_REQUIRED;
 }
 
+NTSTATUS
+Hid_DispatchUrb(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PURB Urb)
+{
+    PIRP Irp;
+    KEVENT Event;
+    PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+    PHID_DEVICE_EXTENSION DeviceExtension;
+    IO_STATUS_BLOCK IoStatus;
+    PIO_STACK_LOCATION IoStack;
+    NTSTATUS Status;
+
+    //
+    // init event
+    //
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    //
+    // get device extension
+    //
+    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+
+    //
+    // build irp
+    //
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB, DeviceExtension->NextDeviceObject, NULL, 0, NULL, 0, TRUE, &Event, &IoStatus);
+    if (!Irp)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // get next stack location
+    //
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    //
+    // store urb
+    //
+    IoStack->Parameters.Others.Argument1 = (PVOID)Urb;
+
+    //
+    // set completion routine
+    //
+    IoSetCompletionRoutine(Irp, Hid_PnpCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
+
+    //
+    // call driver
+    //
+    Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+
+    //
+    // wait for the request to finish
+    //
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = IoStatus.Status;
+    }
+
+    //
+    // complete request
+    //
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+NTSTATUS
+Hid_GetDescriptor(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN USHORT UrbLength,
+    IN OUT PVOID *UrbBuffer,
+    IN OUT PULONG UrbBufferLength,
+    IN UCHAR DescriptorType, 
+    IN UCHAR Index,
+    IN USHORT LanguageIndex)
+{
+    PURB Urb;
+    NTSTATUS Status;
+    UCHAR Allocated = FALSE;
+
+    //
+    // allocate urb
+    //
+    Urb = (PURB)ExAllocatePool(NonPagedPool, UrbLength);
+    if (!Urb)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // is there an urb buffer
+    //
+    if (!*UrbBuffer)
+    {
+        //
+        // allocate buffer
+        //
+        *UrbBuffer = ExAllocatePool(NonPagedPool, *UrbBufferLength);
+        if (!*UrbBuffer)
+        {
+            //
+            // no memory
+            //
+            ExFreePool(Urb);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        //
+        // zero buffer
+        //
+        RtlZeroMemory(*UrbBuffer, *UrbBufferLength);
+        Allocated = TRUE;
+    }
+
+    //
+    // zero urb
+    //
+    RtlZeroMemory(Urb, UrbLength);
+
+    //
+    // build descriptor request
+    //
+    UsbBuildGetDescriptorRequest(Urb, UrbLength, DescriptorType, Index, LanguageIndex, *UrbBuffer, NULL, *UrbBufferLength, NULL);
+
+    //
+    // dispatch urb
+    //
+    Status = Hid_DispatchUrb(DeviceObject, Urb);
+
+    //
+    // did the request fail
+    //
+    if (!NT_SUCCESS(Status))
+    {
+        if (Allocated)
+        {
+            //
+            // free allocated buffer
+            //
+            ExFreePool(*UrbBuffer);
+            *UrbBuffer = NULL;
+        }
+
+        //
+        // free urb
+        //
+        ExFreePool(Urb);
+        *UrbBufferLength = 0;
+        return Status;
+    }
+
+    //
+    // did urb request fail
+    //
+    if (!NT_SUCCESS(Urb->UrbHeader.Status))
+    {
+        if (Allocated)
+        {
+            //
+            // free allocated buffer
+            //
+            ExFreePool(*UrbBuffer);
+            *UrbBuffer = NULL;
+        }
+
+        //
+        // free urb
+        //
+        ExFreePool(Urb);
+        *UrbBufferLength = 0;
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    //
+    // store result length
+    //
+    *UrbBufferLength = Urb->UrbControlDescriptorRequest.TransferBufferLength;
+
+    //
+    // free urb
+    //
+    ExFreePool(Urb);
+
+    //
+    // completed successfully
+    //
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+Hid_SelectConfiguration(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+    NTSTATUS Status;
+    USBD_INTERFACE_LIST_ENTRY InterfaceList[2];
+    PURB Urb;
+    PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+    PHID_DEVICE_EXTENSION DeviceExtension;
+
+    //
+    // get device extension
+    //
+    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+    //
+    // now parse the descriptors
+    //
+    InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(HidDeviceExtension->ConfigurationDescriptor,
+                                                              HidDeviceExtension->ConfigurationDescriptor,
+                                                             -1,
+                                                             -1,
+                                                              USB_DEVICE_CLASS_HUMAN_INTERFACE,
+                                                             -1,
+                                                             -1);
+
+    //
+    // sanity check
+    //
+    ASSERT(InterfaceDescriptor);
+    ASSERT(InterfaceDescriptor->bInterfaceClass == USB_DEVICE_CLASS_HUMAN_INTERFACE);
+    ASSERT(InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
+    ASSERT(InterfaceDescriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
+
+    //
+    // setup interface list
+    //
+    RtlZeroMemory(InterfaceList, sizeof(InterfaceList));
+    InterfaceList[0].InterfaceDescriptor = InterfaceDescriptor;
+
+    //
+    // build urb
+    //
+    Urb = USBD_CreateConfigurationRequestEx(HidDeviceExtension->ConfigurationDescriptor, InterfaceList);
+    if (!Urb)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // dispatch request
+    //
+    Status = Hid_DispatchUrb(DeviceObject, Urb);
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // store configuration handle
+        //
+        HidDeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
+
+        //
+        // copy interface info
+        //
+        HidDeviceExtension->InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)ExAllocatePool(NonPagedPool, Urb->UrbSelectConfiguration.Interface.Length);
+        if (HidDeviceExtension->InterfaceInfo)
+        {
+            //
+            // copy interface info
+            //
+            RtlCopyMemory(HidDeviceExtension->InterfaceInfo, &Urb->UrbSelectConfiguration.Interface, Urb->UrbSelectConfiguration.Interface.Length);
+        }
+    }
+
+    //
+    // free urb request
+    //
+    ExFreePool(Urb);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+
+NTSTATUS
+Hid_PnpStart(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+    PHID_DEVICE_EXTENSION DeviceExtension;
+    NTSTATUS Status;
+    ULONG DescriptorLength;
+    PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+    PHID_DESCRIPTOR HidDescriptor;
+
+    //
+    // get device extension
+    //
+    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+    //
+    // get device descriptor
+    //
+    DescriptorLength = sizeof(USB_DEVICE_DESCRIPTOR);
+    Status = Hid_GetDescriptor(DeviceObject, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), (PVOID*)&HidDeviceExtension->DeviceDescriptor, &DescriptorLength, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to obtain device descriptor
+        //
+        DPRINT1("Hid_PnpStart failed to get device descriptor %x\n", Status);
+        return Status;
+    }
+
+    //
+    // now get the configuration descriptor
+    //
+    DescriptorLength = sizeof(USB_CONFIGURATION_DESCRIPTOR);
+    Status = Hid_GetDescriptor(DeviceObject, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), (PVOID*)&HidDeviceExtension->ConfigurationDescriptor, &DescriptorLength, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to obtain device descriptor
+        //
+        DPRINT1("Hid_PnpStart failed to get device descriptor %x\n", Status);
+        return Status;
+    }
+
+    //
+    // sanity check
+    //
+    ASSERT(DescriptorLength);
+    ASSERT(HidDeviceExtension->ConfigurationDescriptor);
+    ASSERT(HidDeviceExtension->ConfigurationDescriptor->bLength);
+
+    //
+    // store full length
+    //
+    DescriptorLength = HidDeviceExtension->ConfigurationDescriptor->wTotalLength;
+
+    //
+    // delete partial configuration descriptor
+    //
+    ExFreePool(HidDeviceExtension->ConfigurationDescriptor);
+    HidDeviceExtension->ConfigurationDescriptor = NULL;
+
+    //
+    // get full configuration descriptor
+    //
+    Status = Hid_GetDescriptor(DeviceObject, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), (PVOID*)&HidDeviceExtension->ConfigurationDescriptor, &DescriptorLength, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to obtain device descriptor
+        //
+        DPRINT1("Hid_PnpStart failed to get device descriptor %x\n", Status);
+        return Status;
+    }
+
+    //
+    // now parse the descriptors
+    //
+    InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(HidDeviceExtension->ConfigurationDescriptor,
+                                                              HidDeviceExtension->ConfigurationDescriptor,
+                                                             -1,
+                                                             -1,
+                                                              USB_DEVICE_CLASS_HUMAN_INTERFACE,
+                                                             -1,
+                                                             -1);
+    if (!InterfaceDescriptor)
+    {
+        //
+        // no interface class
+        //
+        DPRINT1("NO HID Class found\n");
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    //
+    // sanity check
+    //
+    ASSERT(InterfaceDescriptor->bInterfaceClass == USB_DEVICE_CLASS_HUMAN_INTERFACE);
+    ASSERT(InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
+    ASSERT(InterfaceDescriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
+
+    //
+    // move to next descriptor
+    //
+    HidDescriptor = (PHID_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
+    ASSERT(HidDescriptor->bLength >= 2);
+
+    //
+    // check if this is the hid descriptor
+    //
+    if (HidDescriptor->bLength == sizeof(HID_DESCRIPTOR) && HidDescriptor->bDescriptorType == HID_HID_DESCRIPTOR_TYPE)
+    {
+        //
+        // found
+        //
+        HidDeviceExtension->HidDescriptor = HidDescriptor;
+
+        //
+        // select configuration
+        //
+        Status = Hid_SelectConfiguration(DeviceObject);
+
+        //
+        // done
+        //
+        return Status;
+    }
+
+    //
+    // FIXME parse hid descriptor
+    //
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_SUCCESS;
+}
+
+
 NTSTATUS
 NTAPI
 HidPnp(
index bfe9c6c..332c6db 100644 (file)
@@ -5,6 +5,11 @@
 #include <ntddk.h>
 #include <hidport.h>
 #include <debug.h>
+#include <hubbusif.h>
+#include <usbbusif.h>
+#include <usbioctl.h>
+#include <usb.h>
+#include <usbdlib.h>
 
 typedef struct
 {
@@ -19,13 +24,28 @@ typedef struct
     LIST_ENTRY PendingRequests;
 
     //
-    // hid descriptor
+    // device descriptor
     //
-    PHID_DESCRIPTOR HidDescriptor;
+    PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
+
+    //
+    // configuration descriptor
+    //
+    PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
+
+    //
+    // interface information
+    //
+    PUSBD_INTERFACE_INFORMATION InterfaceInfo;
 
-    USHORT VendorID;
-    USHORT ProductID;
-    USHORT VersionNumber;
+    //
+    // configuration handle
+    //
+    USBD_CONFIGURATION_HANDLE ConfigurationHandle;
 
+    //
+    // hid descriptor
+    //
+    PHID_DESCRIPTOR HidDescriptor;
 }HID_USB_DEVICE_EXTENSION, *PHID_USB_DEVICE_EXTENSION;