reactos/drivers/usb/usbhub/fdo.c
Hermès Bélusca-Maïto b819608ed8 Create a branch for console restructuration work.
svn path=/branches/condrv_restructure/; revision=63104
2014-05-02 14:13:40 +00:00

2236 lines
74 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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)
*/
#include "usbhub.h"
#include <stdio.h>
#define NDEBUG
#include <debug.h>
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;
}
DPRINT("Port %d Status %x\n", PortId, PortStatus.Status);
DPRINT("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;
}
DPRINT("Port %d Status %x\n", PortId, PortStatus.Status);
DPRINT("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 doesnt try to mess with IRP just freed
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
QueryStatusChangeEndpoint(
IN PDEVICE_OBJECT DeviceObject)
{
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);
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);
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)
{
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;
}
ULONG
IsCompositeDevice(
IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
{
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
CreateDeviceIds(
PDEVICE_OBJECT UsbChildDeviceObject)
{
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);
if (InterfaceDescriptor == NULL)
{
DPRINT1("Error USBD_ParseConfigurationDescriptorEx failed to parse interface descriptor\n");
return STATUS_INVALID_PARAMETER;
}
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))
{
// 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));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// 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);
return Status;
}
}
//
// the device did not provide a serial number, or failed to retrieve the 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
DestroyUsbChildDeviceObject(
IN PDEVICE_OBJECT UsbHubDeviceObject,
IN LONG PortId)
{
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;
NTSTATUS Status = STATUS_SUCCESS;
PHUB_DEVICE_EXTENSION HubDeviceExtension;
PDEVICE_OBJECT RootHubDeviceObject;
PVOID HubInterfaceBusContext;
PORT_STATUS_CHANGE StatusChange;
// 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;
}
// 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;
}