-/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: USB hub driver
- * FILE: drivers/usb/cromwell/hub/fdo.c
- * PURPOSE: IRP_MJ_PNP operations for FDOs
- *
- * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
+/*
+ * PROJECT: ReactOS Universal Serial Bus Hub Driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/usb/usbhub/fdo.c
+ * PURPOSE: Handle FDO
+ * PROGRAMMERS:
+ * Michael Martin (michael.martin@reactos.org)
+ * Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#define INITGUID
-#define NDEBUG
#include "usbhub.h"
-#define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
+NTSTATUS
+QueryStatusChangeEndpoint(
+ IN PDEVICE_OBJECT DeviceObject);
+
+NTSTATUS
+CreateUsbChildDeviceObject(
+ IN PDEVICE_OBJECT UsbHubDeviceObject,
+ IN LONG PortId,
+ OUT PDEVICE_OBJECT *UsbChildDeviceObject,
+ IN ULONG PortStatus);
+
+NTSTATUS
+DestroyUsbChildDeviceObject(
+ IN PDEVICE_OBJECT UsbHubDeviceObject,
+ IN LONG PortId);
+
+
+NTSTATUS
+GetPortStatusAndChange(
+ IN PDEVICE_OBJECT RootHubDeviceObject,
+ IN ULONG PortId,
+ OUT PPORT_STATUS_CHANGE StatusChange)
+{
+ NTSTATUS Status;
+ PURB Urb;
+
+ //
+ // Allocate URB
+ //
+ Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
+ if (!Urb)
+ {
+ DPRINT1("Failed to allocate memory for URB!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Zero it
+ //
+ RtlZeroMemory(Urb, sizeof(URB));
+
+ //
+ // Initialize URB for getting Port Status
+ //
+ UsbBuildVendorRequest(Urb,
+ URB_FUNCTION_CLASS_OTHER,
+ sizeof(Urb->UrbControlVendorClassRequest),
+ USBD_TRANSFER_DIRECTION_OUT,
+ 0,
+ USB_REQUEST_GET_STATUS,
+ 0,
+ PortId,
+ StatusChange,
+ 0,
+ sizeof(PORT_STATUS_CHANGE),
+ 0);
+
+ // FIXME: support usb hubs
+ Urb->UrbHeader.UsbdDeviceHandle = NULL;
+
+
+ //
+ // Query the Root Hub
+ //
+ Status = SubmitRequestToRootHub(RootHubDeviceObject, IOCTL_INTERNAL_USB_SUBMIT_URB, Urb, NULL);
+
+ //
+ // Free URB
+ //
+ ExFreePool(Urb);
+
+ return Status;
+}
+
+NTSTATUS
+SetPortFeature(
+ IN PDEVICE_OBJECT RootHubDeviceObject,
+ IN ULONG PortId,
+ IN ULONG Feature)
+{
+ NTSTATUS Status;
+ PURB Urb;
+
+ //
+ // Allocate URB
+ //
+ Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
+ if (!Urb)
+ {
+ DPRINT1("Failed to allocate memory for URB!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Zero it
+ //
+ RtlZeroMemory(Urb, sizeof(URB));
+
+ //
+ // Initialize URB for Clearing Port Reset
+ //
+ UsbBuildVendorRequest(Urb,
+ URB_FUNCTION_CLASS_OTHER,
+ sizeof(Urb->UrbControlVendorClassRequest),
+ USBD_TRANSFER_DIRECTION_IN,
+ 0,
+ USB_REQUEST_SET_FEATURE,
+ Feature,
+ PortId,
+ NULL,
+ 0,
+ 0,
+ 0);
+
+ // FIXME support usbhubs
+ Urb->UrbHeader.UsbdDeviceHandle = NULL;
+
+ //
+ // Query the Root Hub
+ //
+ Status = SubmitRequestToRootHub(RootHubDeviceObject, IOCTL_INTERNAL_USB_SUBMIT_URB, Urb, NULL);
+
+ //
+ // Free URB
+ //
+ ExFreePool(Urb);
+
+ return Status;
+}
+
+NTSTATUS
+ClearPortFeature(
+ IN PDEVICE_OBJECT RootHubDeviceObject,
+ IN ULONG PortId,
+ IN ULONG Feature)
+{
+ NTSTATUS Status;
+ PURB Urb;
+
+ //
+ // Allocate a URB
+ //
+ Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
+ if (!Urb)
+ {
+ DPRINT1("Failed to allocate memory for URB!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Zero it
+ //
+ RtlZeroMemory(Urb, sizeof(URB));
+
+ //
+ // Initialize URB for Clearing Port Reset
+ //
+ UsbBuildVendorRequest(Urb,
+ URB_FUNCTION_CLASS_OTHER,
+ sizeof(Urb->UrbControlVendorClassRequest),
+ USBD_TRANSFER_DIRECTION_IN,
+ 0,
+ USB_REQUEST_CLEAR_FEATURE,
+ Feature,
+ PortId,
+ NULL,
+ 0,
+ 0,
+ 0);
+
+ // FIXME: support usb hubs
+ Urb->UrbHeader.UsbdDeviceHandle = NULL;
+
+ //
+ // Query the Root Hub
+ //
+ Status = SubmitRequestToRootHub(RootHubDeviceObject, IOCTL_INTERNAL_USB_SUBMIT_URB, Urb, NULL);
+
+ //
+ // Free URB
+ //
+ ExFreePool(Urb);
+
+ return Status;
+}
+
+VOID NTAPI
+DeviceStatusChangeThread(
+ IN PVOID Context)
+{
+ NTSTATUS Status;
+ PDEVICE_OBJECT DeviceObject, RootHubDeviceObject;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+ PWORK_ITEM_DATA WorkItemData;
+ PORT_STATUS_CHANGE PortStatus;
+ LONG PortId;
+ BOOLEAN SignalResetComplete = FALSE;
+
+ DPRINT("Entered DeviceStatusChangeThread, Context %x\n", Context);
+
+ WorkItemData = (PWORK_ITEM_DATA)Context;
+ DeviceObject = (PDEVICE_OBJECT)WorkItemData->Context;
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
+ //
+ // Loop all ports
+ //
+ for (PortId = 1; PortId <= HubDeviceExtension->UsbExtHubInfo.NumberOfPorts; PortId++)
+ {
+ //
+ // Get Port Status
+ //
+ Status = GetPortStatusAndChange(RootHubDeviceObject, PortId, &PortStatus);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to get port status for port %d, Status %x\n", PortId, Status);
+ // FIXME: Do we really want to halt further SCE requests?
+ return;
+ }
+
+ DPRINT1("Port %d Status %x\n", PortId, PortStatus.Status);
+ DPRINT1("Port %d Change %x\n", PortId, PortStatus.Change);
+
+
+ //
+ // Check for new device connection
+ //
+ if (PortStatus.Change & USB_PORT_STATUS_CONNECT)
+ {
+ //
+ // Clear Port Connect
+ //
+ Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to clear connection change for port %d\n", PortId);
+ continue;
+ }
+
+ //
+ // Is this a connect or disconnect?
+ //
+ if (!(PortStatus.Status & USB_PORT_STATUS_CONNECT))
+ {
+ DPRINT1("Device disconnected from port %d\n", PortId);
+
+ Status = DestroyUsbChildDeviceObject(DeviceObject, PortId);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to delete child device object after disconnect\n");
+ continue;
+ }
+ }
+ else
+ {
+ DPRINT1("Device connected from port %d\n", PortId);
+
+ // No SCE completion done for clearing C_PORT_CONNECT
+
+ //
+ // Reset Port
+ //
+ Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_RESET);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to reset port %d\n", PortId);
+ SignalResetComplete = TRUE;
+ continue;
+ }
+ }
+ }
+ else if (PortStatus.Change & USB_PORT_STATUS_ENABLE)
+ {
+ //
+ // Clear Enable
+ //
+ Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_ENABLE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to clear enable change on port %d\n", PortId);
+ continue;
+ }
+ }
+ else if (PortStatus.Change & USB_PORT_STATUS_RESET)
+ {
+ //
+ // Request event signalling later
+ //
+ SignalResetComplete = TRUE;
+
+ //
+ // Clear Reset
+ //
+ Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_RESET);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to clear reset change on port %d\n", PortId);
+ continue;
+ }
+
+ //
+ // Get Port Status
+ //
+ Status = GetPortStatusAndChange(RootHubDeviceObject, PortId, &PortStatus);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to get port status for port %d, Status %x\n", PortId, Status);
+ // FIXME: Do we really want to halt further SCE requests?
+ return;
+ }
+
+ DPRINT1("Port %d Status %x\n", PortId, PortStatus.Status);
+ DPRINT1("Port %d Change %x\n", PortId, PortStatus.Change);
+
+ //
+ // Check that reset was cleared
+ //
+ if(PortStatus.Change & USB_PORT_STATUS_RESET)
+ {
+ DPRINT1("Port did not clear reset! Possible Hardware problem!\n");
+ continue;
+ }
+
+ //
+ // Check if the device is still connected
+ //
+ if (!(PortStatus.Status & USB_PORT_STATUS_CONNECT))
+ {
+ DPRINT1("Device has been disconnected\n");
+ continue;
+ }
+
+ //
+ // Make sure its Connected and Enabled
+ //
+ if (!(PortStatus.Status & (USB_PORT_STATUS_CONNECT | USB_PORT_STATUS_ENABLE)))
+ {
+ DPRINT1("Usb Device is not connected and enabled!\n");
+ //
+ // Attempt another reset
+ //
+ Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_RESET);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to reset port %d\n", PortId);
+ }
+ continue;
+ }
+
+ //
+ // This is a new device
+ //
+ Status = CreateUsbChildDeviceObject(DeviceObject, PortId, NULL, PortStatus.Status);
+ }
+ }
+
+ ExFreePool(WorkItemData);
+
+ //
+ // Send another SCE Request
+ //
+ DPRINT("Sending another SCE!\n");
+ QueryStatusChangeEndpoint(DeviceObject);
+
+ //
+ // Check if a reset event was satisfied
+ //
+ if (SignalResetComplete)
+ {
+ //
+ // Signal anyone waiting on it
+ //
+ KeSetEvent(&HubDeviceExtension->ResetComplete, IO_NO_INCREMENT, FALSE);
+ }
+}
+
+NTSTATUS
+NTAPI
+StatusChangeEndpointCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PDEVICE_OBJECT RealDeviceObject;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+ PWORK_ITEM_DATA WorkItemData;
+
+ RealDeviceObject = (PDEVICE_OBJECT)Context;
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION)RealDeviceObject->DeviceExtension;
+
+ //
+ // NOTE: USBPORT frees this IRP
+ //
+ DPRINT("Received Irp %x, HubDeviceExtension->PendingSCEIrp %x\n", Irp, HubDeviceExtension->PendingSCEIrp);
+ //IoFreeIrp(Irp);
+
+ //
+ // Create and initialize work item data
+ //
+ WorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(WORK_ITEM_DATA), USB_HUB_TAG);
+ if (!WorkItemData)
+ {
+ DPRINT1("Failed to allocate memory!n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ WorkItemData->Context = RealDeviceObject;
+
+ DPRINT("Queuing work item\n");
+
+ //
+ // Queue the work item to handle initializing the device
+ //
+ ExInitializeWorkItem(&WorkItemData->WorkItem, DeviceStatusChangeThread, (PVOID)WorkItemData);
+ ExQueueWorkItem(&WorkItemData->WorkItem, DelayedWorkQueue);
+
+ //
+ // Return more processing required so the IO Manger doesn’t try to mess with IRP just freed
+ //
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+QueryStatusChangeEndpoint(
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ NTSTATUS Status;
+ PDEVICE_OBJECT RootHubDeviceObject;
+ PIO_STACK_LOCATION Stack;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+ PURB PendingSCEUrb;
+
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
+
+ //
+ // Allocate a URB
+ //
+ PendingSCEUrb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
+
+ //
+ // Initialize URB for Status Change Endpoint request
+ //
+ UsbBuildInterruptOrBulkTransferRequest(PendingSCEUrb,
+ sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+ HubDeviceExtension->PipeHandle,
+ HubDeviceExtension->PortStatusChange,
+ NULL,
+ sizeof(USHORT) * 2 * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
+ USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
+ NULL);
+
+ // Set the device handle
+ PendingSCEUrb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
+
+ //
+ // Allocate an Irp
+ //
+ HubDeviceExtension->PendingSCEIrp = ExAllocatePoolWithTag(NonPagedPool,
+ IoSizeOfIrp(RootHubDeviceObject->StackSize),
+ USB_HUB_TAG);
+/*
+ HubDeviceExtension->PendingSCEIrp = IoAllocateIrp(RootHubDeviceObject->StackSize,
+ FALSE);
+*/
+ DPRINT("Allocated IRP %x\n", HubDeviceExtension->PendingSCEIrp);
+
+ if (!HubDeviceExtension->PendingSCEIrp)
+ {
+ DPRINT1("USBHUB: Failed to allocate IRP for SCE request!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Initialize the IRP
+ //
+ IoInitializeIrp(HubDeviceExtension->PendingSCEIrp,
+ IoSizeOfIrp(RootHubDeviceObject->StackSize),
+ RootHubDeviceObject->StackSize);
-static VOID
-UsbhubGetUserBuffers(
- IN PIRP Irp,
- IN ULONG IoControlCode,
- OUT PVOID* BufferIn,
- OUT PVOID* BufferOut)
+ HubDeviceExtension->PendingSCEIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+ HubDeviceExtension->PendingSCEIrp->IoStatus.Information = 0;
+ HubDeviceExtension->PendingSCEIrp->Flags = 0;
+ HubDeviceExtension->PendingSCEIrp->UserBuffer = NULL;
+
+ //
+ // Get the Next Stack Location and Initialize it
+ //
+ Stack = IoGetNextIrpStackLocation(HubDeviceExtension->PendingSCEIrp);
+ Stack->DeviceObject = DeviceObject;
+ Stack->Parameters.Others.Argument1 = PendingSCEUrb;
+ Stack->Parameters.Others.Argument2 = NULL;
+ Stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ Stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+ //
+ // Set the completion routine for when device is connected to root hub
+ //
+ IoSetCompletionRoutine(HubDeviceExtension->PendingSCEIrp,
+ StatusChangeEndpointCompletion,
+ DeviceObject,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ //
+ // Send to RootHub
+ //
+ DPRINT("DeviceObject is %x\n", DeviceObject);
+ DPRINT("Iocalldriver %x with irp %x\n", RootHubDeviceObject, HubDeviceExtension->PendingSCEIrp);
+ Status = IoCallDriver(RootHubDeviceObject, HubDeviceExtension->PendingSCEIrp);
+
+ return STATUS_PENDING;
+}
+
+NTSTATUS
+QueryInterface(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN CONST GUID InterfaceType,
+ IN LONG Size,
+ IN LONG Version,
+ OUT PVOID Interface)
+{
+ KEVENT Event;
+ PIRP Irp;
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION Stack = NULL;
+
+ //
+ // Initialize the Event used to wait for Irp completion
+ //
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ //
+ // Build Control Request
+ //
+ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
+ DeviceObject,
+ NULL,
+ 0,
+ NULL,
+ &Event,
+ &IoStatus);
+
+ //
+ // Get Next Stack Location and Initialize it.
+ //
+ Stack = IoGetNextIrpStackLocation(Irp);
+ Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
+ Stack->Parameters.QueryInterface.InterfaceType= &InterfaceType;//USB_BUS_INTERFACE_HUB_GUID;
+ Stack->Parameters.QueryInterface.Size = Size;
+ Stack->Parameters.QueryInterface.Version = Version;
+ Stack->Parameters.QueryInterface.Interface = Interface;
+ Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
+
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING)
+ {
+ DPRINT("Operation pending\n");
+ KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
+ Status = IoStatus.Status;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+GetUsbDeviceDescriptor(
+ IN PDEVICE_OBJECT ChildDeviceObject,
+ IN UCHAR DescriptorType,
+ IN UCHAR Index,
+ IN USHORT LangId,
+ OUT PVOID TransferBuffer,
+ IN ULONG TransferBufferLength)
+{
+ NTSTATUS Status;
+ PDEVICE_OBJECT RootHubDeviceObject;
+ PURB Urb;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+ PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
+
+ //
+ // Get the Hubs Device Extension
+ //
+ ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)ChildDeviceObject->DeviceExtension;
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION) ChildDeviceExtension->ParentDeviceObject->DeviceExtension;
+ RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
+
+ //
+ // Allocate a URB
+ //
+ Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
+ if (!Urb)
+ {
+ DPRINT1("Failed to allocate memory for URB!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Zero it
+ //
+ RtlZeroMemory(Urb, sizeof(URB));
+
+ //
+ // Initialize URB for getting device descriptor
+ //
+ UsbBuildGetDescriptorRequest(Urb,
+ sizeof(Urb->UrbControlDescriptorRequest),
+ DescriptorType,
+ Index,
+ LangId,
+ TransferBuffer,
+ NULL,
+ TransferBufferLength,
+ NULL);
+
+ //
+ // Set the device handle
+ //
+ Urb->UrbHeader.UsbdDeviceHandle = (PVOID)ChildDeviceExtension->UsbDeviceHandle;
+
+ //
+ // Query the Root Hub
+ //
+ Status = SubmitRequestToRootHub(RootHubDeviceObject,
+ IOCTL_INTERNAL_USB_SUBMIT_URB,
+ Urb,
+ NULL);
+
+ return Status;
+}
+
+NTSTATUS
+GetUsbStringDescriptor(
+ IN PDEVICE_OBJECT ChildDeviceObject,
+ IN UCHAR Index,
+ IN USHORT LangId,
+ OUT PVOID *TransferBuffer,
+ OUT USHORT *Size)
{
- ASSERT(Irp);
- ASSERT(BufferIn);
- ASSERT(BufferOut);
-
- switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
- {
- case METHOD_BUFFERED:
- *BufferIn = *BufferOut = Irp->AssociatedIrp.SystemBuffer;
- break;
- case METHOD_IN_DIRECT:
- case METHOD_OUT_DIRECT:
- *BufferIn = Irp->AssociatedIrp.SystemBuffer;
- *BufferOut = MmGetSystemAddressForMdl(Irp->MdlAddress);
- break;
- case METHOD_NEITHER:
- *BufferIn = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.Type3InputBuffer;
- *BufferOut = Irp->UserBuffer;
- break;
- default:
- /* Should never happen */
- *BufferIn = NULL;
- *BufferOut = NULL;
- break;
- }
+ NTSTATUS Status;
+ PUSB_STRING_DESCRIPTOR StringDesc = NULL;
+ ULONG SizeNeeded;
+ LPWSTR Buffer;
+
+ StringDesc = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(USB_STRING_DESCRIPTOR),
+ USB_HUB_TAG);
+ if (!StringDesc)
+ {
+ DPRINT1("Failed to allocate buffer for string!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Get the index string descriptor length
+ // FIXME: Implement LangIds
+ //
+ Status = GetUsbDeviceDescriptor(ChildDeviceObject,
+ USB_STRING_DESCRIPTOR_TYPE,
+ Index,
+ 0x0409,
+ StringDesc,
+ sizeof(USB_STRING_DESCRIPTOR));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("GetUsbDeviceDescriptor failed with status %x\n", Status);
+ ExFreePool(StringDesc);
+ return Status;
+ }
+ DPRINT1("StringDesc->bLength %d\n", StringDesc->bLength);
+
+ //
+ // Did we get something more than the length of the first two fields of structure?
+ //
+ if (StringDesc->bLength == 2)
+ {
+ DPRINT1("USB Device Error!\n");
+ ExFreePool(StringDesc);
+ return STATUS_DEVICE_DATA_ERROR;
+ }
+ SizeNeeded = StringDesc->bLength + sizeof(WCHAR);
+
+ //
+ // Free String
+ //
+ ExFreePool(StringDesc);
+
+ //
+ // Recreate with appropriate size
+ //
+ StringDesc = ExAllocatePoolWithTag(NonPagedPool,
+ SizeNeeded,
+ USB_HUB_TAG);
+ if (!StringDesc)
+ {
+ DPRINT1("Failed to allocate buffer for string!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(StringDesc, SizeNeeded);
+
+ //
+ // Get the string
+ //
+ Status = GetUsbDeviceDescriptor(ChildDeviceObject,
+ USB_STRING_DESCRIPTOR_TYPE,
+ Index,
+ 0x0409,
+ StringDesc,
+ SizeNeeded);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("GetUsbDeviceDescriptor failed with status %x\n", Status);
+ ExFreePool(StringDesc);
+ return Status;
+ }
+
+ //
+ // Allocate Buffer to return
+ //
+ Buffer = ExAllocatePoolWithTag(NonPagedPool,
+ SizeNeeded,
+ USB_HUB_TAG);
+ if (!Buffer)
+ {
+ DPRINT1("Failed to allocate buffer for string!\n");
+ ExFreePool(StringDesc);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(Buffer, SizeNeeded);
+
+ //
+ // Copy the string to destination
+ //
+ RtlCopyMemory(Buffer, StringDesc->bString, SizeNeeded - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString));
+ *Size = SizeNeeded;
+ *TransferBuffer = Buffer;
+
+ ExFreePool(StringDesc);
+
+ return STATUS_SUCCESS;
}
-static NTSTATUS
-UsbhubFdoQueryBusRelations(
- IN PDEVICE_OBJECT DeviceObject,
- OUT PDEVICE_RELATIONS* pDeviceRelations)
+ULONG
+IsCompositeDevice(
+ IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
{
- PHUB_DEVICE_EXTENSION DeviceExtension;
- PDEVICE_RELATIONS DeviceRelations;
- PDEVICE_OBJECT Pdo;
- PHUB_DEVICE_EXTENSION PdoExtension;
- struct usb_device* dev;
- ULONG i;
- ULONG Children = 0;
- ULONG NeededSize;
- NTSTATUS Status;
- CHAR Buffer[3][40];
-
- DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
- dev = DeviceExtension->dev;
-
- /* Create PDOs that are missing */
- for (i = 0; i < dev->maxchild; i++)
- {
- if (dev->children[i] == NULL)
- {
- /* No child device at this place */
- continue;
- }
- Children++;
- if (DeviceExtension->Children[i] != NULL)
- {
- /* PDO already exists */
- continue;
- }
- /* Need to create the PDO */
- Status = IoCreateDevice(
- DeviceObject->DriverObject,
- sizeof(HUB_DEVICE_EXTENSION),
- NULL, /* Device name */
- FILE_DEVICE_CONTROLLER,
- FILE_AUTOGENERATED_DEVICE_NAME,
- FALSE,
- &DeviceExtension->Children[i]);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("Usbhub: IoCreateDevice() failed with status 0x%08lx\n", Status);
- return Status;
- }
-
- Pdo = DeviceExtension->Children[i];
- Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
-
- PdoExtension = Pdo->DeviceExtension;
- RtlZeroMemory(PdoExtension, sizeof(HUB_DEVICE_EXTENSION));
-
- PdoExtension->IsFDO = FALSE;
- PdoExtension->dev = dev->children[i];
-
- sprintf(Buffer[0], "%lu", i);
- Status = UsbhubInitMultiSzString(
- &PdoExtension->InstanceId,
- Buffer[0], NULL);
- if (!NT_SUCCESS(Status))
- goto ByeBye;
-
- DPRINT1("child #%lu: USB\\Vid_%04x&Pid_%04x&Rev_%04x\n",
- i,
- PdoExtension->dev->descriptor.idVendor,
- PdoExtension->dev->descriptor.idProduct,
- PdoExtension->dev->descriptor.bcdDevice);
- sprintf(Buffer[0], "USB\\Vid_%04x&Pid_%04x&Rev_%04x",
- PdoExtension->dev->descriptor.idVendor,
- PdoExtension->dev->descriptor.idProduct,
- PdoExtension->dev->descriptor.bcdDevice);
- sprintf(Buffer[1], "USB\\Vid_%04x&Pid_%04x",
- PdoExtension->dev->descriptor.idVendor,
- PdoExtension->dev->descriptor.idProduct);
- Status = UsbhubInitMultiSzString(
- &PdoExtension->HardwareIds,
- Buffer[0], Buffer[1], NULL);
- if (!NT_SUCCESS(Status))
- goto ByeBye;
-
- Status = UsbhubInitMultiSzString(
- &PdoExtension->DeviceId,
- Buffer[1], NULL);
- if (!NT_SUCCESS(Status))
- goto ByeBye;
-
- if (PdoExtension->dev->actconfig->desc.bNumInterfaces == 1)
- {
- /* Single-interface USB device */
- if (PdoExtension->dev->descriptor.bDeviceClass != 0)
- {
- /* Use these values for device class/sub class/protocol */
- sprintf(Buffer[0], "USB\\Class_%02x&SubClass_%02x&Prot_%02x",
- PdoExtension->dev->descriptor.bDeviceClass,
- PdoExtension->dev->descriptor.bDeviceSubClass,
- PdoExtension->dev->descriptor.bDeviceProtocol);
- sprintf(Buffer[1], "USB\\Class_%02x&SubClass_%02x",
- PdoExtension->dev->descriptor.bDeviceClass,
- PdoExtension->dev->descriptor.bDeviceSubClass);
- sprintf(Buffer[2], "USB\\Class_%02x",
- PdoExtension->dev->descriptor.bDeviceClass);
- }
- else
- {
- /* Use values specified in the interface descriptor */
- struct usb_host_interface *itf = PdoExtension->dev->actconfig->interface->altsetting;
- sprintf(Buffer[0], "USB\\Class_%02x&SubClass_%02x&Prot_%02x",
- itf->desc.bInterfaceClass,
- itf->desc.bInterfaceSubClass,
- itf->desc.bInterfaceProtocol);
- sprintf(Buffer[1], "USB\\Class_%02x&SubClass_%02x",
- itf->desc.bInterfaceClass,
- itf->desc.bInterfaceSubClass);
- sprintf(Buffer[2], "USB\\Class_%02x",
- itf->desc.bInterfaceClass);
- }
- Status = UsbhubInitMultiSzString(
- &PdoExtension->CompatibleIds,
- Buffer[0], Buffer[1], Buffer[2], NULL);
- }
- else
- {
- /* Multiple-interface USB device */
- sprintf(Buffer[0], "USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
- PdoExtension->dev->descriptor.bDeviceClass,
- PdoExtension->dev->descriptor.bDeviceSubClass,
- PdoExtension->dev->descriptor.bDeviceProtocol);
- sprintf(Buffer[1], "USB\\DevClass_%02x&SubClass_%02x",
- PdoExtension->dev->descriptor.bDeviceClass,
- PdoExtension->dev->descriptor.bDeviceSubClass);
- sprintf(Buffer[2], "USB\\DevClass_%02x",
- PdoExtension->dev->descriptor.bDeviceClass);
- Status = UsbhubInitMultiSzString(
- &PdoExtension->CompatibleIds,
- Buffer[0], Buffer[1], Buffer[2], "USB\\COMPOSITE", NULL);
- }
-
- if (!NT_SUCCESS(Status))
- goto ByeBye;
-
- Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
- }
-
- /* Fill returned structure */
- NeededSize = sizeof(DEVICE_RELATIONS);
- if (Children > 1)
- NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
- DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
- PagedPool,
- NeededSize);
- if (!DeviceRelations)
- return STATUS_INSUFFICIENT_RESOURCES;
- DeviceRelations->Count = Children;
- Children = 0;
- for (i = 0; i < USB_MAXCHILDREN; i++)
- {
- if (DeviceExtension->Children[i])
- {
- ObReferenceObject(DeviceExtension->Children[i]);
- DeviceRelations->Objects[Children++] = DeviceExtension->Children[i];
- }
- }
- ASSERT(Children == DeviceRelations->Count);
-
- *pDeviceRelations = DeviceRelations;
- return STATUS_SUCCESS;
-
-ByeBye:
- RtlFreeUnicodeString(&PdoExtension->DeviceId);
- RtlFreeUnicodeString(&PdoExtension->InstanceId);
- RtlFreeUnicodeString(&PdoExtension->HardwareIds);
- RtlFreeUnicodeString(&PdoExtension->CompatibleIds);
- IoDeleteDevice(Pdo);
- return Status;
+ if (DeviceDescriptor->bNumConfigurations != 1)
+ {
+ //
+ // composite device must have only one configuration
+ //
+ DPRINT1("IsCompositeDevice bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
+ return FALSE;
+ }
+
+ if (ConfigurationDescriptor->bNumInterfaces < 2)
+ {
+ //
+ // composite device must have multiple interfaces
+ //
+ DPRINT1("IsCompositeDevice bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
+ return FALSE;
+ }
+
+ if (DeviceDescriptor->bDeviceClass == 0)
+ {
+ //
+ // composite device
+ //
+ ASSERT(DeviceDescriptor->bDeviceSubClass == 0);
+ ASSERT(DeviceDescriptor->bDeviceProtocol == 0);
+ DPRINT1("IsCompositeDevice: TRUE\n");
+ return TRUE;
+ }
+
+ if (DeviceDescriptor->bDeviceClass == 0xEF &&
+ DeviceDescriptor->bDeviceSubClass == 0x02 &&
+ DeviceDescriptor->bDeviceProtocol == 0x01)
+ {
+ //
+ // USB-IF association descriptor
+ //
+ DPRINT1("IsCompositeDevice: TRUE\n");
+ return TRUE;
+ }
+
+ DPRINT1("DeviceDescriptor bDeviceClass %x bDeviceSubClass %x bDeviceProtocol %x\n", DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol);
+
+ //
+ // not a composite device
+ //
+ return FALSE;
}
-NTSTATUS NTAPI
-UsbhubPnpFdo(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
+NTSTATUS
+CreateDeviceIds(
+ PDEVICE_OBJECT UsbChildDeviceObject)
{
- PIO_STACK_LOCATION IrpSp;
- NTSTATUS Status;
- ULONG MinorFunction;
- ULONG_PTR Information = 0;
-
- IrpSp = IoGetCurrentIrpStackLocation(Irp);
- MinorFunction = IrpSp->MinorFunction;
-
- switch (MinorFunction)
- {
- case IRP_MN_START_DEVICE: /* 0x0 */
- {
- DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
- Status = ForwardIrpAndWait(DeviceObject, Irp);
- break;
- }
-
- case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */
- {
- switch (IrpSp->Parameters.QueryDeviceRelations.Type)
- {
- case BusRelations:
- {
- PDEVICE_RELATIONS DeviceRelations = NULL;
- DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
- Status = UsbhubFdoQueryBusRelations(DeviceObject, &DeviceRelations);
- Information = (ULONG_PTR)DeviceRelations;
- break;
- }
- case RemovalRelations:
- {
- DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
- return ForwardIrpAndForget(DeviceObject, Irp);
- }
- default:
- DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
- IrpSp->Parameters.QueryDeviceRelations.Type);
- return ForwardIrpAndForget(DeviceObject, Irp);
- }
- break;
- }
-
- default:
- {
- DPRINT1("Usbhub: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
- return ForwardIrpAndForget(DeviceObject, Irp);
- }
- }
- Irp->IoStatus.Information = Information;
- Irp->IoStatus.Status = Status;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return Status;
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG Index = 0;
+ LPWSTR DeviceString;
+ WCHAR Buffer[200];
+ PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+ PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
+ PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
+ PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+
+ //
+ // get child device extension
+ //
+ UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)UsbChildDeviceObject->DeviceExtension;
+
+ // get hub device extension
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION) UsbChildExtension->ParentDeviceObject->DeviceExtension;
+
+ //
+ // get device descriptor
+ //
+ DeviceDescriptor = &UsbChildExtension->DeviceDesc;
+
+ //
+ // get configuration descriptor
+ //
+ ConfigurationDescriptor = UsbChildExtension->FullConfigDesc;
+
+ //
+ // use first interface descriptor available
+ //
+ InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, 0, -1, -1, -1, -1);
+ ASSERT(InterfaceDescriptor);
+
+ //
+ // Construct the CompatibleIds
+ //
+ if (IsCompositeDevice(DeviceDescriptor, ConfigurationDescriptor))
+ {
+ //
+ // sanity checks
+ //
+ ASSERT(DeviceDescriptor->bNumConfigurations == 1);
+ ASSERT(ConfigurationDescriptor->bNumInterfaces > 1);
+ Index += swprintf(&Buffer[Index],
+ L"USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
+ DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol) + 1;
+ Index += swprintf(&Buffer[Index],
+ L"USB\\DevClass_%02x&SubClass_%02x",
+ DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass) + 1;
+ Index += swprintf(&Buffer[Index],
+ L"USB\\DevClass_%02x",
+ DeviceDescriptor->bDeviceClass) + 1;
+ Index += swprintf(&Buffer[Index],
+ L"USB\\COMPOSITE") + 1;
+ }
+ else
+ {
+ //
+ // FIXME: support multiple configurations
+ //
+ ASSERT(DeviceDescriptor->bNumConfigurations == 1);
+
+ if (DeviceDescriptor->bDeviceClass == 0)
+ {
+ Index += swprintf(&Buffer[Index],
+ L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
+ InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass, InterfaceDescriptor->bInterfaceProtocol) + 1;
+ Index += swprintf(&Buffer[Index],
+ L"USB\\Class_%02x&SubClass_%02x",
+ InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass) + 1;
+ Index += swprintf(&Buffer[Index],
+ L"USB\\Class_%02x",
+ InterfaceDescriptor->bInterfaceClass) + 1;
+ }
+ else
+ {
+ Index += swprintf(&Buffer[Index],
+ L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
+ DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol) + 1;
+ Index += swprintf(&Buffer[Index],
+ L"USB\\Class_%02x&SubClass_%02x",
+ DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass) + 1;
+ Index += swprintf(&Buffer[Index],
+ L"USB\\Class_%02x",
+ DeviceDescriptor->bDeviceClass) + 1;
+ }
+ }
+
+ //
+ // now allocate the buffer
+ //
+ DeviceString = ExAllocatePool(NonPagedPool, (Index + 1) * sizeof(WCHAR));
+ if (!DeviceString)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // copy buffer
+ //
+ RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
+ DeviceString[Index] = UNICODE_NULL;
+ UsbChildExtension->usCompatibleIds.Buffer = DeviceString;
+ UsbChildExtension->usCompatibleIds.Length = Index * sizeof(WCHAR);
+ UsbChildExtension->usCompatibleIds.MaximumLength = (Index + 1) * sizeof(WCHAR);
+ DPRINT("usCompatibleIds %wZ\n", &UsbChildExtension->usCompatibleIds);
+
+ //
+ // Construct DeviceId string
+ //
+ Index = swprintf(Buffer, L"USB\\Vid_%04x&Pid_%04x", UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct) + 1;
+
+ //
+ // now allocate the buffer
+ //
+ DeviceString = ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
+ if (!DeviceString)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // copy buffer
+ //
+ RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
+ UsbChildExtension->usDeviceId.Buffer = DeviceString;
+ UsbChildExtension->usDeviceId.Length = (Index-1) * sizeof(WCHAR);
+ UsbChildExtension->usDeviceId.MaximumLength = Index * sizeof(WCHAR);
+ DPRINT("usDeviceId %wZ\n", &UsbChildExtension->usDeviceId);
+
+ //
+ // Construct HardwareIds
+ //
+ Index = 0;
+ Index += swprintf(&Buffer[Index],
+ L"USB\\Vid_%04x&Pid_%04x&Rev_%04x",
+ UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct, UsbChildExtension->DeviceDesc.bcdDevice) + 1;
+ Index += swprintf(&Buffer[Index],
+ L"USB\\Vid_%04x&Pid_%04x",
+ UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct) + 1;
+
+ //
+ // now allocate the buffer
+ //
+ DeviceString = ExAllocatePool(NonPagedPool, (Index + 1) * sizeof(WCHAR));
+ if (!DeviceString)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // copy buffer
+ //
+ RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
+ DeviceString[Index] = UNICODE_NULL;
+ UsbChildExtension->usHardwareIds.Buffer = DeviceString;
+ UsbChildExtension->usHardwareIds.Length = (Index + 1) * sizeof(WCHAR);
+ UsbChildExtension->usHardwareIds.MaximumLength = (Index + 1) * sizeof(WCHAR);
+ DPRINT("usHardWareIds %wZ\n", &UsbChildExtension->usHardwareIds);
+
+ //
+ // FIXME: Handle Lang ids
+ //
+
+ //
+ // Get the product string if obe provided
+ //
+ if (UsbChildExtension->DeviceDesc.iProduct)
+ {
+ Status = GetUsbStringDescriptor(UsbChildDeviceObject,
+ UsbChildExtension->DeviceDesc.iProduct,
+ 0,
+ (PVOID*)&UsbChildExtension->usTextDescription.Buffer,
+ &UsbChildExtension->usTextDescription.Length);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
+ RtlInitUnicodeString(&UsbChildExtension->usTextDescription, L"USB Device"); // FIXME NON-NLS
+ }
+ else
+ {
+ UsbChildExtension->usTextDescription.MaximumLength = UsbChildExtension->usTextDescription.Length;
+ DPRINT("Usb TextDescription %wZ\n", &UsbChildExtension->usTextDescription);
+ }
+ }
+
+ //
+ // Get the Serial Number string if obe provided
+ //
+ if (UsbChildExtension->DeviceDesc.iSerialNumber)
+ {
+ LPWSTR SerialBuffer = NULL;
+
+ Status = GetUsbStringDescriptor(UsbChildDeviceObject,
+ UsbChildExtension->DeviceDesc.iSerialNumber,
+ 0,
+ (PVOID*)&SerialBuffer,
+ &UsbChildExtension->usInstanceId.Length);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
+ return Status;
+ }
+
+ // construct instance id buffer
+ Index = swprintf(Buffer, L"%04d&%s", HubDeviceExtension->InstanceCount, SerialBuffer) + 1;
+ UsbChildExtension->usInstanceId.Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
+ if (UsbChildExtension->usInstanceId.Buffer == NULL)
+ {
+ DPRINT1("Error: failed to allocate %lu bytes\n", Index * sizeof(WCHAR));
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ return Status;
+ }
+
+ //
+ // copy instance id
+ //
+ RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR));
+ UsbChildExtension->usInstanceId.Length = UsbChildExtension->usInstanceId.MaximumLength = Index * sizeof(WCHAR);
+ ExFreePool(SerialBuffer);
+
+ DPRINT("Usb InstanceId %wZ InstanceCount %x\n", &UsbChildExtension->usInstanceId, HubDeviceExtension->InstanceCount);
+ }
+ else
+ {
+ //
+ // the device did not provide a serial number, lets create a pseudo instance id
+ //
+ Index = swprintf(Buffer, L"%04d&%04d", HubDeviceExtension->InstanceCount, UsbChildExtension->PortNumber) + 1;
+ UsbChildExtension->usInstanceId.Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
+ if (UsbChildExtension->usInstanceId.Buffer == NULL)
+ {
+ DPRINT1("Error: failed to allocate %lu bytes\n", Index * sizeof(WCHAR));
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ return Status;
+ }
+
+ //
+ // copy instance id
+ //
+ RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR));
+ UsbChildExtension->usInstanceId.Length = UsbChildExtension->usInstanceId.MaximumLength = Index * sizeof(WCHAR);
+
+ DPRINT("usDeviceId %wZ\n", &UsbChildExtension->usInstanceId);
+ }
+
+ return STATUS_SUCCESS;
}
NTSTATUS
-UsbhubDeviceControlFdo(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
+DestroyUsbChildDeviceObject(
+ IN PDEVICE_OBJECT UsbHubDeviceObject,
+ IN LONG PortId)
{
- PIO_STACK_LOCATION Stack;
- ULONG IoControlCode;
- PHUB_DEVICE_EXTENSION DeviceExtension;
- ULONG LengthIn, LengthOut;
- ULONG_PTR Information = 0;
- PVOID BufferIn, BufferOut;
- NTSTATUS Status;
-
- Stack = IoGetCurrentIrpStackLocation(Irp);
- LengthIn = Stack->Parameters.DeviceIoControl.InputBufferLength;
- LengthOut = Stack->Parameters.DeviceIoControl.OutputBufferLength;
- DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
- IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
- UsbhubGetUserBuffers(Irp, IoControlCode, &BufferIn, &BufferOut);
-
- switch (IoControlCode)
- {
- case IOCTL_USB_GET_NODE_INFORMATION:
- {
- PUSB_NODE_INFORMATION NodeInformation;
- struct usb_device* dev;
- DPRINT("Usbhub: IOCTL_USB_GET_NODE_INFORMATION\n");
- if (LengthOut < sizeof(USB_NODE_INFORMATION))
- Status = STATUS_BUFFER_TOO_SMALL;
- else if (BufferOut == NULL)
- Status = STATUS_INVALID_PARAMETER;
- else
- {
- NodeInformation = (PUSB_NODE_INFORMATION)BufferOut;
- dev = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->dev;
- NodeInformation->NodeType = UsbHub;
- RtlCopyMemory(
- &NodeInformation->u.HubInformation.HubDescriptor,
- ((struct usb_hub *)usb_get_intfdata(to_usb_interface(&dev->actconfig->interface[0].dev)))->descriptor,
- sizeof(USB_HUB_DESCRIPTOR));
- NodeInformation->u.HubInformation.HubIsBusPowered = dev->actconfig->desc.bmAttributes & 0x80;
- Information = sizeof(USB_NODE_INFORMATION);
- Status = STATUS_SUCCESS;
- }
- break;
- }
- case IOCTL_USB_GET_NODE_CONNECTION_NAME:
- {
- PHUB_DEVICE_EXTENSION DeviceExtension;
- PUSB_NODE_CONNECTION_NAME ConnectionName;
- DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
- ConnectionName = (PUSB_NODE_CONNECTION_NAME)BufferOut;
-
- DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_NAME\n");
- if (LengthOut < sizeof(USB_NODE_CONNECTION_NAME))
- Status = STATUS_BUFFER_TOO_SMALL;
- else if (BufferOut == NULL)
- Status = STATUS_INVALID_PARAMETER;
- else if (ConnectionName->ConnectionIndex < 1
- || ConnectionName->ConnectionIndex > USB_MAXCHILDREN)
- Status = STATUS_INVALID_PARAMETER;
- else if (DeviceExtension->Children[ConnectionName->ConnectionIndex - 1] == NULL)
- Status = STATUS_INVALID_PARAMETER;
- else
- {
- ULONG NeededStructureSize;
- DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceExtension->Children[ConnectionName->ConnectionIndex - 1]->DeviceExtension;
- NeededStructureSize = DeviceExtension->SymbolicLinkName.Length + sizeof(UNICODE_NULL) + FIELD_OFFSET(USB_NODE_CONNECTION_NAME, NodeName);
- if (ConnectionName->ActualLength < NeededStructureSize / sizeof(WCHAR)
- || LengthOut < NeededStructureSize)
- {
- /* Buffer too small */
- ConnectionName->ActualLength = NeededStructureSize / sizeof(WCHAR);
- Information = sizeof(USB_NODE_CONNECTION_NAME);
- Status = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- RtlCopyMemory(
- ConnectionName->NodeName,
- DeviceExtension->SymbolicLinkName.Buffer,
- DeviceExtension->SymbolicLinkName.Length);
- ConnectionName->NodeName[DeviceExtension->SymbolicLinkName.Length / sizeof(WCHAR)] = UNICODE_NULL;
- DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_NAME returns '%S'\n", ConnectionName->NodeName);
- ConnectionName->ActualLength = NeededStructureSize / sizeof(WCHAR);
- Information = NeededStructureSize;
- Status = STATUS_SUCCESS;
- }
- Information = LengthOut;
- }
- break;
- }
- case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION:
- {
- PUSB_NODE_CONNECTION_INFORMATION ConnectionInformation;
- ULONG i, j, k;
- struct usb_device* dev;
- ULONG NumberOfOpenPipes = 0;
- ULONG SizeOfOpenPipesArray;
- ConnectionInformation = (PUSB_NODE_CONNECTION_INFORMATION)BufferOut;
-
- DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION\n");
- if (LengthOut < sizeof(USB_NODE_CONNECTION_INFORMATION))
- Status = STATUS_BUFFER_TOO_SMALL;
- else if (BufferOut == NULL)
- Status = STATUS_INVALID_PARAMETER;
- else if (ConnectionInformation->ConnectionIndex < 1
- || ConnectionInformation->ConnectionIndex > USB_MAXCHILDREN)
- Status = STATUS_INVALID_PARAMETER;
- else
- {
- dev = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->dev;
- dev = dev->children[ConnectionInformation->ConnectionIndex - 1];
- if (dev == NULL)
- {
- /* No device connected to this port */
- RtlZeroMemory(
- &ConnectionInformation->DeviceDescriptor,
- sizeof(USB_NODE_CONNECTION_INFORMATION) - FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION, DeviceDescriptor));
- ConnectionInformation->ConnectionStatus = NoDeviceConnected;
- Information = sizeof(USB_NODE_CONNECTION_INFORMATION);
- Status = STATUS_SUCCESS;
- break;
- }
- SizeOfOpenPipesArray = (LengthOut - FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION, PipeList)) / sizeof(USB_PIPE_INFO);
- RtlCopyMemory(
- &ConnectionInformation->DeviceDescriptor,
- &dev->descriptor,
- sizeof(USB_DEVICE_DESCRIPTOR));
- ConnectionInformation->CurrentConfigurationValue = dev->actconfig->desc.bConfigurationValue;
- ConnectionInformation->LowSpeed = dev->speed == USB_SPEED_LOW || dev->speed == USB_SPEED_FULL;
- ConnectionInformation->DeviceIsHub = dev->descriptor.bDeviceClass == USB_CLASS_HUB;
- ConnectionInformation->DeviceAddress = dev->devnum;
- ConnectionInformation->ConnectionStatus = DeviceConnected;
-
- for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
- for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++)
- for (k = 0; k < dev->actconfig->interface[i].altsetting[j].desc.bNumEndpoints; k++)
- {
- if (NumberOfOpenPipes < SizeOfOpenPipesArray)
- {
- PUSB_PIPE_INFO Pipe = &ConnectionInformation->PipeList[NumberOfOpenPipes];
- struct usb_host_endpoint* endpoint = &dev->actconfig->interface[i].altsetting[j].endpoint[k];
- RtlCopyMemory(
- &Pipe->EndpointDescriptor,
- &endpoint->desc,
- endpoint->desc.bLength);
- Pipe->ScheduleOffset = 0; /* FIXME */
- }
- NumberOfOpenPipes++;
- }
- ConnectionInformation->NumberOfOpenPipes = NumberOfOpenPipes;
-
- Information = sizeof(USB_NODE_CONNECTION_INFORMATION);
- if (NumberOfOpenPipes <= SizeOfOpenPipesArray)
- Status = STATUS_SUCCESS;
- else
- Status = STATUS_BUFFER_OVERFLOW;
- }
- break;
- }
- case IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION:
- {
- //PUSB_DESCRIPTOR_REQUEST Descriptor;
- DPRINT("Usbhub: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION\n");
- DPRINT1("Usbhub: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION unimplemented\n");
- Information = 0;
- Status = STATUS_NOT_IMPLEMENTED;
- break;
- }
- case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME:
- {
- PHUB_DEVICE_EXTENSION DeviceExtension;
- PUSB_NODE_CONNECTION_DRIVERKEY_NAME StringDescriptor;
- DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME\n");
- DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
- StringDescriptor = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)BufferOut;
- if (LengthOut < sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME))
- Status = STATUS_BUFFER_TOO_SMALL;
- else if (StringDescriptor == NULL)
- Status = STATUS_INVALID_PARAMETER;
- else if (StringDescriptor->ConnectionIndex < 1
- || StringDescriptor->ConnectionIndex > USB_MAXCHILDREN)
- Status = STATUS_INVALID_PARAMETER;
- else if (DeviceExtension->Children[StringDescriptor->ConnectionIndex - 1] == NULL)
- Status = STATUS_INVALID_PARAMETER;
- else
- {
- ULONG StringSize;
- Status = IoGetDeviceProperty(
- DeviceExtension->Children[StringDescriptor->ConnectionIndex - 1],
- DevicePropertyDriverKeyName,
- LengthOut - FIELD_OFFSET(USB_NODE_CONNECTION_DRIVERKEY_NAME, DriverKeyName),
- StringDescriptor->DriverKeyName,
- &StringSize);
- if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
- {
- StringDescriptor->ActualLength = StringSize + FIELD_OFFSET(USB_NODE_CONNECTION_DRIVERKEY_NAME, DriverKeyName);
- Information = LengthOut;
- Status = STATUS_SUCCESS;
- }
- }
- break;
- }
- default:
- {
- /* Pass Irp to lower driver */
- DPRINT1("Usbhub: Unknown IOCTL code 0x%lx\n", Stack->Parameters.DeviceIoControl.IoControlCode);
- return ForwardIrpAndForget(DeviceObject, Irp);
- }
- }
-
- Irp->IoStatus.Information = Information;
- Irp->IoStatus.Status = Status;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return Status;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension = (PHUB_DEVICE_EXTENSION)UsbHubDeviceObject->DeviceExtension;
+ PHUB_CHILDDEVICE_EXTENSION UsbChildExtension = NULL;
+ PDEVICE_OBJECT ChildDeviceObject = NULL;
+ ULONG Index = 0;
+
+ DPRINT("Removing device on port %d (Child index: %d)\n", PortId, Index);
+
+ for (Index = 0; Index < USB_MAXCHILDREN; Index++)
+ {
+ if (HubDeviceExtension->ChildDeviceObject[Index])
+ {
+ UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
+
+ /* Check if it matches the port ID */
+ if (UsbChildExtension->PortNumber == PortId)
+ {
+ /* We found it */
+ ChildDeviceObject = HubDeviceExtension->ChildDeviceObject[Index];
+ break;
+ }
+ }
+ }
+
+ /* Fail the request if the device doesn't exist */
+ if (!ChildDeviceObject)
+ {
+ DPRINT1("Removal request for non-existant device!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /* Remove the device from the table */
+ HubDeviceExtension->ChildDeviceObject[Index] = NULL;
+
+ /* Invalidate device relations for the root hub */
+ IoInvalidateDeviceRelations(HubDeviceExtension->RootHubPhysicalDeviceObject, BusRelations);
+
+ /* The rest of the removal process takes place in IRP_MN_REMOVE_DEVICE handling for the PDO */
+ return STATUS_SUCCESS;
}
+
+NTSTATUS
+CreateUsbChildDeviceObject(
+ IN PDEVICE_OBJECT UsbHubDeviceObject,
+ IN LONG PortId,
+ OUT PDEVICE_OBJECT *UsbChildDeviceObject,
+ IN ULONG PortStatus)
+{
+ NTSTATUS Status;
+ PDEVICE_OBJECT RootHubDeviceObject, NewChildDeviceObject;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+ PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
+ PUSB_BUS_INTERFACE_HUB_V5 HubInterface;
+ ULONG ChildDeviceCount, UsbDeviceNumber = 0;
+ WCHAR CharDeviceName[64];
+ UNICODE_STRING DeviceName;
+ ULONG ConfigDescSize, DeviceDescSize, DeviceInfoSize;
+ PVOID HubInterfaceBusContext;
+ USB_CONFIGURATION_DESCRIPTOR ConfigDesc;
+
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION) UsbHubDeviceObject->DeviceExtension;
+ HubInterface = &HubDeviceExtension->HubInterface;
+ RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
+ HubInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
+ //
+ // Find an empty slot in the child device array
+ //
+ for (ChildDeviceCount = 0; ChildDeviceCount < USB_MAXCHILDREN; ChildDeviceCount++)
+ {
+ if (HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] == NULL)
+ {
+ DPRINT("Found unused entry at %d\n", ChildDeviceCount);
+ break;
+ }
+ }
+
+ //
+ // Check if the limit has been reached for maximum usb devices
+ //
+ if (ChildDeviceCount == USB_MAXCHILDREN)
+ {
+ DPRINT1("USBHUB: Too many child devices!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ while (TRUE)
+ {
+ //
+ // Create a Device Name
+ //
+ swprintf(CharDeviceName, L"\\Device\\USBPDO-%d", UsbDeviceNumber);
+
+ //
+ // Initialize UnicodeString
+ //
+ RtlInitUnicodeString(&DeviceName, CharDeviceName);
+
+ //
+ // Create a DeviceObject
+ //
+ Status = IoCreateDevice(UsbHubDeviceObject->DriverObject,
+ sizeof(HUB_CHILDDEVICE_EXTENSION),
+ NULL,
+ FILE_DEVICE_CONTROLLER,
+ FILE_AUTOGENERATED_DEVICE_NAME,
+ FALSE,
+ &NewChildDeviceObject);
+
+ //
+ // Check if the name is already in use
+ //
+ if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
+ {
+ //
+ // Try next name
+ //
+ UsbDeviceNumber++;
+ continue;
+ }
+
+ //
+ // Check for other errors
+ //
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBHUB: IoCreateDevice failed with status %x\n", Status);
+ return Status;
+ }
+
+ DPRINT("USBHUB: Created Device %x\n", NewChildDeviceObject);
+ break;
+ }
+
+ NewChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
+
+ //
+ // Assign the device extensions
+ //
+ UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)NewChildDeviceObject->DeviceExtension;
+ RtlZeroMemory(UsbChildExtension, sizeof(HUB_CHILDDEVICE_EXTENSION));
+ UsbChildExtension->ParentDeviceObject = UsbHubDeviceObject;
+ UsbChildExtension->PortNumber = PortId;
+
+ // copy device interface
+ RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
+
+
+ //
+ // Create the UsbDeviceObject
+ //
+ Status = HubInterface->CreateUsbDevice(HubInterfaceBusContext,
+ (PVOID)&UsbChildExtension->UsbDeviceHandle,
+ HubDeviceExtension->RootHubHandle,
+ PortStatus,
+ PortId);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBHUB: CreateUsbDevice failed with status %x\n", Status);
+ goto Cleanup;
+ }
+
+ // copy device interface
+ RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
+
+ // FIXME replace buscontext
+ UsbChildExtension->DeviceInterface.BusContext = UsbChildExtension->UsbDeviceHandle;
+
+ //
+ // Initialize UsbDevice
+ //
+ Status = HubInterface->InitializeUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBHUB: InitializeUsbDevice failed with status %x\n", Status);
+ goto Cleanup;
+ }
+
+ DPRINT("Usb Device Handle %x\n", UsbChildExtension->UsbDeviceHandle);
+
+ ConfigDescSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
+ DeviceDescSize = sizeof(USB_DEVICE_DESCRIPTOR);
+
+ //
+ // Get the descriptors
+ //
+ Status = HubInterface->GetUsbDescriptors(HubInterfaceBusContext,
+ UsbChildExtension->UsbDeviceHandle,
+ (PUCHAR)&UsbChildExtension->DeviceDesc,
+ &DeviceDescSize,
+ (PUCHAR)&ConfigDesc,
+ &ConfigDescSize);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBHUB: GetUsbDescriptors failed with status %x\n", Status);
+ goto Cleanup;
+ }
+
+ DumpDeviceDescriptor(&UsbChildExtension->DeviceDesc);
+ DumpConfigurationDescriptor(&ConfigDesc);
+
+ //
+ // FIXME: Support more than one configuration and one interface?
+ //
+ if (UsbChildExtension->DeviceDesc.bNumConfigurations > 1)
+ {
+ DPRINT1("Warning: Device has more than one configuration. Only one configuration (the first) is supported!\n");
+ }
+
+ if (ConfigDesc.bNumInterfaces > 1)
+ {
+ DPRINT1("Warning: Device has more that one interface. Only one interface (the first) is currently supported\n");
+ }
+
+ ConfigDescSize = ConfigDesc.wTotalLength;
+
+ //
+ // Allocate memory for the first full descriptor, including interfaces and endpoints.
+ //
+ UsbChildExtension->FullConfigDesc = ExAllocatePoolWithTag(PagedPool, ConfigDescSize, USB_HUB_TAG);
+
+ //
+ // Retrieve the full configuration descriptor
+ //
+ Status = GetUsbDeviceDescriptor(NewChildDeviceObject,
+ USB_CONFIGURATION_DESCRIPTOR_TYPE,
+ 0,
+ 0,
+ UsbChildExtension->FullConfigDesc,
+ ConfigDescSize);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBHUB: GetUsbDeviceDescriptor failed with status %x\n", Status);
+ goto Cleanup;
+ }
+
+ // query device details
+ Status = HubInterface->QueryDeviceInformation(HubInterfaceBusContext,
+ UsbChildExtension->UsbDeviceHandle,
+ &UsbChildExtension->DeviceInformation,
+ sizeof(USB_DEVICE_INFORMATION_0),
+ &DeviceInfoSize);
+
+
+ //DumpFullConfigurationDescriptor(UsbChildExtension->FullConfigDesc);
+
+ //
+ // Construct all the strings that will described the device to PNP
+ //
+ Status = CreateDeviceIds(NewChildDeviceObject);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create strings needed to describe device to PNP.\n");
+ goto Cleanup;
+ }
+
+ HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] = NewChildDeviceObject;
+ HubDeviceExtension->InstanceCount++;
+
+ IoInvalidateDeviceRelations(RootHubDeviceObject, BusRelations);
+ return STATUS_SUCCESS;
+
+Cleanup:
+
+ //
+ // Remove the usb device if it was created
+ //
+ if (UsbChildExtension->UsbDeviceHandle)
+ HubInterface->RemoveUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle, 0);
+
+ //
+ // Free full configuration descriptor if one was allocated
+ //
+ if (UsbChildExtension->FullConfigDesc)
+ ExFreePool(UsbChildExtension->FullConfigDesc);
+
+ //
+ // Delete the device object
+ //
+ IoDeleteDevice(NewChildDeviceObject);
+ return Status;
+}
+
+NTSTATUS
+USBHUB_FdoQueryBusRelations(
+ IN PDEVICE_OBJECT DeviceObject,
+ OUT PDEVICE_RELATIONS* pDeviceRelations)
+{
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+ PDEVICE_RELATIONS DeviceRelations;
+ ULONG i;
+ ULONG Children = 0;
+ ULONG NeededSize;
+
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ //
+ // Count the number of children
+ //
+ for (i = 0; i < USB_MAXCHILDREN; i++)
+ {
+
+ if (HubDeviceExtension->ChildDeviceObject[i] == NULL)
+ {
+ continue;
+ }
+ Children++;
+ }
+
+ NeededSize = sizeof(DEVICE_RELATIONS);
+ if (Children > 1)
+ NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
+
+ //
+ // Allocate DeviceRelations
+ //
+ DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool,
+ NeededSize);
+
+ if (!DeviceRelations)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ DeviceRelations->Count = Children;
+ Children = 0;
+
+ //
+ // Fill in return structure
+ //
+ for (i = 0; i < USB_MAXCHILDREN; i++)
+ {
+ if (HubDeviceExtension->ChildDeviceObject[i])
+ {
+ ObReferenceObject(HubDeviceExtension->ChildDeviceObject[i]);
+ HubDeviceExtension->ChildDeviceObject[i]->Flags &= ~DO_DEVICE_INITIALIZING;
+ DeviceRelations->Objects[Children++] = HubDeviceExtension->ChildDeviceObject[i];
+ }
+ }
+
+ ASSERT(Children == DeviceRelations->Count);
+ *pDeviceRelations = DeviceRelations;
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+RootHubInitCallbackFunction(
+ PVOID Context)
+{
+ PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
+ NTSTATUS Status;
+ ULONG PortId;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+ PORT_STATUS_CHANGE StatusChange;
+
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ DPRINT("RootHubInitCallbackFunction Sending the initial SCE Request %x\n", DeviceObject);
+
+ //
+ // Send the first SCE Request
+ //
+ QueryStatusChangeEndpoint(DeviceObject);
+
+ for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
+ {
+ //
+ // get port status
+ //
+ Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
+ if (NT_SUCCESS(Status))
+ {
+ //
+ // is there a device connected
+ //
+ if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
+ {
+ //
+ // reset port
+ //
+ Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to reset on port %d\n", PortId);
+ }
+ else
+ {
+ //
+ // wait for the reset to be handled since we want to enumerate synchronously
+ //
+ KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(&HubDeviceExtension->ResetComplete);
+ }
+ }
+ }
+ }
+}
+
+BOOLEAN
+USBHUB_IsRootHubFDO(
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ NTSTATUS Status;
+ PDEVICE_OBJECT RootHubPhysicalDeviceObject = NULL;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+
+ // get hub device extension
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ // Get the Root Hub Pdo
+ Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
+ IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
+ &RootHubPhysicalDeviceObject,
+ NULL);
+
+ // FIXME handle error
+ ASSERT(NT_SUCCESS(Status));
+
+ // physical device object is only obtained for root hubs
+ return (RootHubPhysicalDeviceObject != NULL);
+}
+
+
+NTSTATUS
+USBHUB_FdoStartDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PURB Urb;
+ PUSB_INTERFACE_DESCRIPTOR Pid;
+ ULONG Result = 0, PortId;
+ USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}};
+ PURB ConfigUrb = NULL;
+ ULONG HubStatus;
+ PIO_STACK_LOCATION Stack;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+ PDEVICE_OBJECT RootHubDeviceObject;
+ PVOID HubInterfaceBusContext , UsbDInterfaceBusContext;
+ PORT_STATUS_CHANGE StatusChange;
+
+ // get current stack location
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ // get hub device extension
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
+
+ // Allocated size including the sizeof USBD_INTERFACE_LIST_ENTRY
+ Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY), USB_HUB_TAG);
+ if (!Urb)
+ {
+ // no memory
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // zero urb
+ RtlZeroMemory(Urb, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY));
+
+ // Get the Root Hub Pdo
+ Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
+ IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
+ &HubDeviceExtension->RootHubPhysicalDeviceObject,
+ &HubDeviceExtension->RootHubFunctionalDeviceObject);
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to obtain hub pdo
+ DPRINT1("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO failed with %x\n", Status);
+ ExFreePool(Urb);
+ return Status;
+ }
+
+ // sanity checks
+ ASSERT(HubDeviceExtension->RootHubPhysicalDeviceObject);
+ ASSERT(HubDeviceExtension->RootHubFunctionalDeviceObject);
+
+ // get roothub
+ RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
+
+ // Send the StartDevice to RootHub
+ Status = ForwardIrpAndWait(RootHubDeviceObject, Irp);
+
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to start pdo
+ DPRINT1("Failed to start the RootHub PDO\n");
+ ExFreePool(Urb);
+ return Status;
+ }
+
+ // Get the current number of hubs
+ Status = SubmitRequestToRootHub(RootHubDeviceObject,
+ IOCTL_INTERNAL_USB_GET_HUB_COUNT,
+ &HubDeviceExtension->NumberOfHubs, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to get number of hubs
+ DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_COUNT failed with %x\n", Status);
+ ExFreePool(Urb);
+ return Status;
+ }
+
+ // Get the Hub Interface
+ Status = QueryInterface(RootHubDeviceObject,
+ USB_BUS_INTERFACE_HUB_GUID,
+ sizeof(USB_BUS_INTERFACE_HUB_V5),
+ USB_BUSIF_HUB_VERSION_5,
+ (PVOID)&HubDeviceExtension->HubInterface);
+
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to get root hub interface
+ DPRINT1("Failed to get HUB_GUID interface with status 0x%08lx\n", Status);
+ ExFreePool(Urb);
+ return Status;
+ }
+
+ HubInterfaceBusContext = HubDeviceExtension->HubInterface.BusContext;
+
+ // Get the USBDI Interface
+ Status = QueryInterface(RootHubDeviceObject,
+ USB_BUS_INTERFACE_USBDI_GUID,
+ sizeof(USB_BUS_INTERFACE_USBDI_V2),
+ USB_BUSIF_USBDI_VERSION_2,
+ (PVOID)&HubDeviceExtension->UsbDInterface);
+
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to get usbdi interface
+ DPRINT1("Failed to get USBDI_GUID interface with status 0x%08lx\n", Status);
+ ExFreePool(Urb);
+ return Status;
+ }
+
+ UsbDInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
+
+ // Get Root Hub Device Handle
+ Status = SubmitRequestToRootHub(RootHubDeviceObject,
+ IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
+ &HubDeviceExtension->RootHubHandle,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ // failed
+ DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE failed with status 0x%08lx\n", Status);
+ ExFreePool(Urb);
+ return Status;
+ }
+
+ //
+ // Get Hub Device Information
+ //
+ Status = HubDeviceExtension->HubInterface.QueryDeviceInformation(HubInterfaceBusContext,
+ HubDeviceExtension->RootHubHandle,
+ &HubDeviceExtension->DeviceInformation,
+ sizeof(USB_DEVICE_INFORMATION_0),
+ &Result);
+
+ DPRINT1("Status %x, Result 0x%08lx\n", Status, Result);
+ DPRINT1("InformationLevel %x\n", HubDeviceExtension->DeviceInformation.InformationLevel);
+ DPRINT1("ActualLength %x\n", HubDeviceExtension->DeviceInformation.ActualLength);
+ DPRINT1("PortNumber %x\n", HubDeviceExtension->DeviceInformation.PortNumber);
+ DPRINT1("DeviceDescriptor %x\n", HubDeviceExtension->DeviceInformation.DeviceDescriptor);
+ DPRINT1("HubAddress %x\n", HubDeviceExtension->DeviceInformation.HubAddress);
+ DPRINT1("NumberofPipes %x\n", HubDeviceExtension->DeviceInformation.NumberOfOpenPipes);
+
+ // Get Root Hubs Device Descriptor
+ UsbBuildGetDescriptorRequest(Urb,
+ sizeof(Urb->UrbControlDescriptorRequest),
+ USB_DEVICE_DESCRIPTOR_TYPE,
+ 0,
+ 0,
+ &HubDeviceExtension->HubDeviceDescriptor,
+ NULL,
+ sizeof(USB_DEVICE_DESCRIPTOR),
+ NULL);
+
+ // set device handle
+ Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
+
+ // get hub device descriptor
+ Status = SubmitRequestToRootHub(RootHubDeviceObject,
+ IOCTL_INTERNAL_USB_SUBMIT_URB,
+ Urb,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to get device descriptor of hub
+ DPRINT1("Failed to get HubDeviceDescriptor!\n");
+ ExFreePool(Urb);
+ return Status;
+ }
+
+ // build configuration request
+ UsbBuildGetDescriptorRequest(Urb,
+ sizeof(Urb->UrbControlDescriptorRequest),
+ USB_CONFIGURATION_DESCRIPTOR_TYPE,
+ 0,
+ 0,
+ &HubDeviceExtension->HubConfigDescriptor,
+ NULL,
+ sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR),
+ NULL);
+
+ // set device handle
+ Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
+
+ // request configuration descriptor
+ Status = SubmitRequestToRootHub(RootHubDeviceObject,
+ IOCTL_INTERNAL_USB_SUBMIT_URB,
+ Urb,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to get configuration descriptor
+ DPRINT1("Failed to get RootHub Configuration with status %x\n", Status);
+ ExFreePool(Urb);
+ return Status;
+ }
+
+ // sanity checks
+ ASSERT(HubDeviceExtension->HubConfigDescriptor.wTotalLength == sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR));
+ ASSERT(HubDeviceExtension->HubConfigDescriptor.bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE);
+ ASSERT(HubDeviceExtension->HubConfigDescriptor.bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
+ ASSERT(HubDeviceExtension->HubConfigDescriptor.bNumInterfaces == 1);
+ ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
+ ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
+ ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bNumEndpoints == 1);
+ ASSERT(HubDeviceExtension->HubEndPointDescriptor.bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
+ ASSERT(HubDeviceExtension->HubEndPointDescriptor.bLength == sizeof(USB_ENDPOINT_DESCRIPTOR));
+ ASSERT(HubDeviceExtension->HubEndPointDescriptor.bmAttributes == USB_ENDPOINT_TYPE_INTERRUPT);
+ ASSERT(HubDeviceExtension->HubEndPointDescriptor.bEndpointAddress == 0x81); // interrupt in
+
+ // get hub information
+ Status = HubDeviceExtension->HubInterface.GetExtendedHubInformation(HubInterfaceBusContext,
+ RootHubDeviceObject,
+ &HubDeviceExtension->UsbExtHubInfo,
+ sizeof(USB_EXTHUB_INFORMATION_0),
+ &Result);
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to get hub information
+ DPRINT1("Failed to extended hub information. Unable to determine the number of ports!\n");
+ ExFreePool(Urb);
+ return Status;
+ }
+
+ if (!HubDeviceExtension->UsbExtHubInfo.NumberOfPorts)
+ {
+ // bogus port driver
+ DPRINT1("Failed to retrieve the number of ports\n");
+ ExFreePool(Urb);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ DPRINT1("HubDeviceExtension->UsbExtHubInfo.NumberOfPorts %x\n", HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
+
+ // Build hub descriptor request
+ UsbBuildVendorRequest(Urb,
+ URB_FUNCTION_CLASS_DEVICE,
+ sizeof(Urb->UrbControlVendorClassRequest),
+ USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
+ 0,
+ USB_REQUEST_GET_DESCRIPTOR,
+ USB_DEVICE_CLASS_RESERVED,
+ 0,
+ &HubDeviceExtension->HubDescriptor,
+ NULL,
+ sizeof(USB_HUB_DESCRIPTOR),
+ NULL);
+
+ // set device handle
+ Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
+
+ // send request
+ Status = SubmitRequestToRootHub(RootHubDeviceObject,
+ IOCTL_INTERNAL_USB_SUBMIT_URB,
+ Urb,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to get Hub Descriptor!\n");
+ ExFreePool(Urb);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // sanity checks
+ ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorLength == sizeof(USB_HUB_DESCRIPTOR));
+ ASSERT(HubDeviceExtension->HubDescriptor.bNumberOfPorts == HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
+ ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorType == 0x29);
+
+ // build get status request
+ HubStatus = 0;
+ UsbBuildGetStatusRequest(Urb,
+ URB_FUNCTION_GET_STATUS_FROM_DEVICE,
+ 0,
+ &HubStatus,
+ 0,
+ NULL);
+ // set device handle
+ Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
+
+ // send request
+ Status = SubmitRequestToRootHub(RootHubDeviceObject,
+ IOCTL_INTERNAL_USB_SUBMIT_URB,
+ Urb,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to get hub status
+ DPRINT1("Failed to get Hub Status!\n");
+ ExFreePool(Urb);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // Allocate memory for PortStatusChange to hold 2 USHORTs for each port on hub
+ HubDeviceExtension->PortStatusChange = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(ULONG) * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
+ USB_HUB_TAG);
+
+ // Get the first Configuration Descriptor
+ Pid = USBD_ParseConfigurationDescriptorEx(&HubDeviceExtension->HubConfigDescriptor,
+ &HubDeviceExtension->HubConfigDescriptor,
+ -1, -1, -1, -1, -1);
+ if (Pid == NULL)
+ {
+ // failed parse hub descriptor
+ DPRINT1("Failed to parse configuration descriptor\n");
+ ExFreePool(Urb);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // create configuration request
+ InterfaceList[0].InterfaceDescriptor = Pid;
+ ConfigUrb = USBD_CreateConfigurationRequestEx(&HubDeviceExtension->HubConfigDescriptor,
+ (PUSBD_INTERFACE_LIST_ENTRY)&InterfaceList);
+ if (ConfigUrb == NULL)
+ {
+ // failed to build urb
+ DPRINT1("Failed to allocate urb\n");
+ ExFreePool(Urb);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // send request
+ Status = SubmitRequestToRootHub(RootHubDeviceObject,
+ IOCTL_INTERNAL_USB_SUBMIT_URB,
+ ConfigUrb,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to select configuration
+ DPRINT1("Failed to select configuration with %x\n", Status);
+ ExFreePool(Urb);
+ ExFreePool(ConfigUrb);
+ return Status;
+ }
+
+ // store configuration & pipe handle
+ HubDeviceExtension->ConfigurationHandle = ConfigUrb->UrbSelectConfiguration.ConfigurationHandle;
+ HubDeviceExtension->PipeHandle = ConfigUrb->UrbSelectConfiguration.Interface.Pipes[0].PipeHandle;
+ DPRINT("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
+
+ FDO_QueryInterface(DeviceObject, &HubDeviceExtension->DeviceInterface);
+
+
+ // free urb
+ ExFreePool(ConfigUrb);
+
+ // check if function is available
+ if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed)
+ {
+ // is it high speed bus
+ if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed(HubInterfaceBusContext))
+ {
+ // initialize usb 2.0 hub
+ Status = HubDeviceExtension->HubInterface.Initialize20Hub(HubInterfaceBusContext,
+ HubDeviceExtension->RootHubHandle, 1);
+ DPRINT("Status %x\n", Status);
+
+ // FIXME handle error
+ ASSERT(Status == STATUS_SUCCESS);
+ }
+ }
+
+
+ // Enable power on all ports
+ DPRINT("Enabling PortPower on all ports!\n");
+ for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
+ {
+ Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_POWER);
+ if (!NT_SUCCESS(Status))
+ DPRINT1("Failed to power on port %d\n", PortId);
+
+ Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
+ if (!NT_SUCCESS(Status))
+ DPRINT1("Failed to power on port %d\n", PortId);
+ }
+
+ // init root hub notification
+ if (HubDeviceExtension->HubInterface.RootHubInitNotification)
+ {
+ Status = HubDeviceExtension->HubInterface.RootHubInitNotification(HubInterfaceBusContext,
+ DeviceObject,
+ RootHubInitCallbackFunction);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to set callback\n");
+ ExFreePool(Urb);
+ return Status;
+ }
+ }
+ else
+ {
+ // Send the first SCE Request
+ QueryStatusChangeEndpoint(DeviceObject);
+
+ //
+ // reset ports
+ //
+ for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
+ {
+ //
+ // get port status
+ //
+ Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
+ if (NT_SUCCESS(Status))
+ {
+ //
+ // is there a device connected
+ //
+ if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
+ {
+ //
+ // reset port
+ //
+ Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to reset on port %d\n", PortId);
+ }
+ else
+ {
+ //
+ // wait for the reset to be handled since we want to enumerate synchronously
+ //
+ KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(&HubDeviceExtension->ResetComplete);
+ }
+ }
+ }
+ }
+ }
+
+ // free urb
+ ExFreePool(Urb);
+
+ // done
+ return Status;
+}
+
+NTSTATUS
+USBHUB_FdoHandlePnp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION Stack;
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG_PTR Information = 0;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (Stack->MinorFunction)
+ {
+ case IRP_MN_START_DEVICE:
+ {
+ if (USBHUB_IsRootHubFDO(DeviceObject))
+ {
+ // start root hub fdo
+ Status = USBHUB_FdoStartDevice(DeviceObject, Irp);
+ }
+ else
+ {
+ Status = USBHUB_ParentFDOStartDevice(DeviceObject, Irp);
+ }
+ break;
+ }
+
+ case IRP_MN_QUERY_DEVICE_RELATIONS:
+ {
+ switch (Stack->Parameters.QueryDeviceRelations.Type)
+ {
+ case BusRelations:
+ {
+ PDEVICE_RELATIONS DeviceRelations = NULL;
+ DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
+
+ Status = USBHUB_FdoQueryBusRelations(DeviceObject, &DeviceRelations);
+
+ Information = (ULONG_PTR)DeviceRelations;
+ break;
+ }
+ case RemovalRelations:
+ {
+ DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ default:
+ DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
+ Stack->Parameters.QueryDeviceRelations.Type);
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ break;
+ }
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ case IRP_MN_QUERY_STOP_DEVICE:
+ {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ case IRP_MN_REMOVE_DEVICE:
+ {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ IoDetachDevice(HubDeviceExtension->LowerDeviceObject);
+ IoDeleteDevice(DeviceObject);
+
+ return STATUS_SUCCESS;
+ }
+ case IRP_MN_QUERY_BUS_INFORMATION:
+ {
+ DPRINT("IRP_MN_QUERY_BUS_INFORMATION\n");
+ break;
+ }
+ case IRP_MN_QUERY_ID:
+ {
+ DPRINT("IRP_MN_QUERY_ID\n");
+ break;
+ }
+ case IRP_MN_QUERY_CAPABILITIES:
+ {
+ DPRINT("IRP_MN_QUERY_CAPABILITIES\n");
+ break;
+ }
+ default:
+ {
+ DPRINT(" IRP_MJ_PNP / unknown minor function 0x%lx\n", Stack->MinorFunction);
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ }
+
+ Irp->IoStatus.Information = Information;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+}
+
+NTSTATUS
+USBHUB_FdoHandleDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION IoStack;
+ NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+ PUSB_NODE_INFORMATION NodeInformation;
+ PHUB_DEVICE_EXTENSION HubDeviceExtension;
+ PUSB_NODE_CONNECTION_INFORMATION NodeConnectionInfo;
+ PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
+ PUSB_NODE_CONNECTION_DRIVERKEY_NAME NodeKey;
+ PUSB_NODE_CONNECTION_NAME ConnectionName;
+ ULONG Index, Length;
+
+ // get stack location
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ // get device extension
+ HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_INFORMATION)
+ {
+ // is the buffer big enough
+ if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_INFORMATION))
+ {
+ // buffer too small
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ // get buffer
+ NodeInformation = (PUSB_NODE_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ // sanity check
+ ASSERT(NodeInformation);
+
+ // init buffer
+ NodeInformation->NodeType = UsbHub;
+ RtlCopyMemory(&NodeInformation->u.HubInformation.HubDescriptor, &HubDeviceExtension->HubDescriptor, sizeof(USB_HUB_DESCRIPTOR));
+
+ // FIXME is hub powered
+ NodeInformation->u.HubInformation.HubIsBusPowered = TRUE;
+
+ // done
+ Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
+ Status = STATUS_SUCCESS;
+ }
+
+
+ }
+ else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_INFORMATION)
+ {
+ if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_CONNECTION_INFORMATION))
+ {
+ // buffer too small
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ // get node connection info
+ NodeConnectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ // sanity checks
+ ASSERT(NodeConnectionInfo);
+
+ for(Index = 0; Index < USB_MAXCHILDREN; Index++)
+ {
+ if (HubDeviceExtension->ChildDeviceObject[Index] == NULL)
+ continue;
+
+ // get child device extension
+ ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
+
+ if (ChildDeviceExtension->PortNumber != NodeConnectionInfo->ConnectionIndex)
+ continue;
+
+ // init node connection info
+ RtlCopyMemory(&NodeConnectionInfo->DeviceDescriptor, &ChildDeviceExtension->DeviceDesc, sizeof(USB_DEVICE_DESCRIPTOR));
+ NodeConnectionInfo->CurrentConfigurationValue = ChildDeviceExtension->FullConfigDesc->bConfigurationValue;
+ NodeConnectionInfo->DeviceIsHub = FALSE; //FIXME support hubs
+ NodeConnectionInfo->LowSpeed = ChildDeviceExtension->DeviceInformation.DeviceSpeed == UsbLowSpeed;
+ NodeConnectionInfo->DeviceAddress = ChildDeviceExtension->DeviceInformation.DeviceAddress;
+ NodeConnectionInfo->NumberOfOpenPipes = ChildDeviceExtension->DeviceInformation.NumberOfOpenPipes;
+ NodeConnectionInfo->ConnectionStatus = DeviceConnected; //FIXME
+
+ if (NodeConnectionInfo->NumberOfOpenPipes)
+ {
+ DPRINT1("Need to copy pipe information\n");
+ }
+ break;
+ }
+ // done
+ Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME)
+ {
+ if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_CONNECTION_INFORMATION))
+ {
+ // buffer too small
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ // get node connection info
+ NodeKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
+
+ // sanity checks
+ ASSERT(NodeKey);
+
+ for(Index = 0; Index < USB_MAXCHILDREN; Index++)
+ {
+ if (HubDeviceExtension->ChildDeviceObject[Index] == NULL)
+ continue;
+
+ // get child device extension
+ ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
+
+ if (ChildDeviceExtension->PortNumber != NodeKey->ConnectionIndex)
+ continue;
+
+ // get driver key
+ Status = IoGetDeviceProperty(HubDeviceExtension->ChildDeviceObject[Index], DevicePropertyDriverKeyName,
+ IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME),
+ NodeKey->DriverKeyName,
+ &Length);
+
+ if (Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ // normalize status
+ Status = STATUS_SUCCESS;
+ }
+
+ if (Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME) > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
+ {
+ // terminate node key name
+ NodeKey->DriverKeyName[0] = UNICODE_NULL;
+ Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+ }
+ else
+ {
+ // result size
+ Irp->IoStatus.Information = Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+ }
+
+ // length of driver name
+ NodeKey->ActualLength = Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+ break;
+ }
+ }
+ }
+ else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_NAME)
+ {
+ if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_CONNECTION_NAME))
+ {
+ // buffer too small
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ // FIXME support hubs
+ ConnectionName = (PUSB_NODE_CONNECTION_NAME)Irp->AssociatedIrp.SystemBuffer;
+ ConnectionName->ActualLength = 0;
+ ConnectionName->NodeName[0] = UNICODE_NULL;
+
+ // done
+ Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_NAME);
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ DPRINT1("UNIMPLEMENTED FdoHandleDeviceControl IoCtl %x InputBufferLength %x OutputBufferLength %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode,
+ IoStack->Parameters.DeviceIoControl.InputBufferLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength);
+ }
+
+ // finish irp
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+