reactos/drivers/usb/usbhub_new/fdo.c
Cameron Gutman e7484d185a [PCI][HIDCLASS][HIDUSB][KBDHID][MOUHID][USBCCGP][USBOHCI][USBEHCI][USBHUB][USBSTOR]
- Handle query remove IRPs
- Fix some other removal bugs

svn path=/branches/usb-bringup-trunk/; revision=55399
2012-02-03 22:59:53 +00:00

1940 lines
63 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)
*/
#define INITGUID
#include "usbhub.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
SubmitRequestToRootHub(
IN PDEVICE_OBJECT RootHubDeviceObject,
IN ULONG IoControlCode,
OUT PVOID OutParameter1,
OUT PVOID OutParameter2)
{
KEVENT Event;
PIRP Irp;
IO_STATUS_BLOCK IoStatus;
NTSTATUS Status;
PIO_STACK_LOCATION Stack = NULL;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
//
// Build Control Request
//
Irp = IoBuildDeviceIoControlRequest(IoControlCode,
RootHubDeviceObject,
NULL, 0,
NULL, 0,
TRUE,
&Event,
&IoStatus);
if (Irp == NULL)
{
DPRINT("Usbhub: IoBuildDeviceIoControlRequest() failed\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize the status block before sending the IRP
//
IoStatus.Status = STATUS_NOT_SUPPORTED;
IoStatus.Information = 0;
//
// Get Next Stack Location and Initialize it
//
Stack = IoGetNextIrpStackLocation(Irp);
Stack->Parameters.Others.Argument1 = OutParameter1;
Stack->Parameters.Others.Argument2 = OutParameter2;
//
// Call RootHub
//
Status = IoCallDriver(RootHubDeviceObject, Irp);
//
// Its ok to block here as this function is called in an nonarbitrary thread
//
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}
//
// The IO Manager will free the IRP
//
return Status;
}
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);
//
// 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);
//
// 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);
//
// 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;
DPRINT1("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);
}
//
// 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");
}
}
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);
}
}
}
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);
}
}
else if (PortStatus.Change & USB_PORT_STATUS_RESET)
{
//
// Clear Reset
//
Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_RESET);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to clear reset change on port %d\n", 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 that reset was cleared
//
if(PortStatus.Change & USB_PORT_STATUS_RESET)
{
DPRINT1("Port did not clear reset! Possible Hardware problem!\n");
}
//
// 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);
}
}
KeSetEvent(&WorkItemData->Event, IO_NO_INCREMENT, FALSE);
//
// Send another SCE Request
//
DPRINT1("Sending another SCE!\n");
QueryStatusChangeEndpoint(DeviceObject);
}
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
//
DPRINT1("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;
KeInitializeEvent(&WorkItemData->Event, NotificationEvent, FALSE);
DPRINT1("Initialize work item\n");
ExInitializeWorkItem(&WorkItemData->WorkItem, DeviceStatusChangeThread, (PVOID)WorkItemData);
//
// Queue the work item to handle initializing the device
//
ExQueueWorkItem(&WorkItemData->WorkItem, DelayedWorkQueue);
//
// Wait for the work item
//
KeWaitForSingleObject(&WorkItemData->Event,
Executive,
KernelMode,
FALSE,
NULL);
ExFreePool(WorkItemData);
//
// 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)
{
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 to null for roothub
//
PendingSCEUrb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
//
// Allocate an Irp
//
HubDeviceExtension->PendingSCEIrp = ExAllocatePoolWithTag(NonPagedPool,
IoSizeOfIrp(RootHubDeviceObject->StackSize),
USB_HUB_TAG);
/*
HubDeviceExtension->PendingSCEIrp = IoAllocateIrp(RootHubDeviceObject->StackSize,
FALSE);
*/
DPRINT1("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
//
DPRINT1("DeviceObject is %x\n", DeviceObject);
DPRINT1("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)
{
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;
}
DPRINT1("Buffer %p\n", Buffer);
RtlZeroMemory(Buffer, SizeNeeded);
DPRINT1("Buffer %p\n", Buffer);
DPRINT1("SizeNeeded %lu\n", SizeNeeded);
DPRINT1("Offset %lu\n", FIELD_OFFSET(USB_STRING_DESCRIPTOR, bLength));
DPRINT1("Length %lu\n", SizeNeeded - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bLength));
//
// 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;
PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
//
// get child device extension
//
UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)UsbChildDeviceObject->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
{
//
// sanity checks for simple usb device
//
ASSERT(ConfigurationDescriptor->bNumInterfaces == 1);
//
// 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);
DPRINT1("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);
DPRINT1("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);
DPRINT1("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);
return Status;
}
UsbChildExtension->usTextDescription.MaximumLength = UsbChildExtension->usTextDescription.Length;
DPRINT1("Usb TextDescription %wZ\n", &UsbChildExtension->usTextDescription);
}
//
// Get the Serial Number string if obe provided
//
if (UsbChildExtension->DeviceDesc.iSerialNumber)
{
Status = GetUsbStringDescriptor(UsbChildDeviceObject,
UsbChildExtension->DeviceDesc.iSerialNumber,
0,
(PVOID*)&UsbChildExtension->usInstanceId.Buffer,
&UsbChildExtension->usInstanceId.Length);
if (!NT_SUCCESS(Status))
{
DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
return Status;
}
UsbChildExtension->usInstanceId.MaximumLength = UsbChildExtension->usInstanceId.Length;
DPRINT1("Usb InstanceId %wZ\n", &UsbChildExtension->usInstanceId);
}
else
{
//
// the device did not provide a serial number, lets create a pseudo instance id
//
Index = swprintf(Buffer, L"0&%04d", 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);
DPRINT1("usDeviceId %wZ\n", &UsbChildExtension->usInstanceId);
}
return Status;
}
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;
DPRINT1("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;
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)
{
DPRINT1("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;
}
DPRINT1("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;
//
// 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;
}
//
// Initialize UsbDevice
//
Status = HubInterface->InitializeUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("USBHUB: InitializeUsbDevice failed with status %x\n", Status);
goto Cleanup;
}
DPRINT1("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;
}
//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;
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;
DPRINT1("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);
}
}
}
}
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;
PDEVICE_OBJECT RootHubDeviceObject;
PVOID HubInterfaceBusContext , UsbDInterfaceBusContext;
PORT_STATUS_CHANGE StatusChange;
HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
Stack = IoGetCurrentIrpStackLocation(Irp);
switch (Stack->MinorFunction)
{
case IRP_MN_START_DEVICE:
{
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;
DPRINT1("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);
RtlZeroMemory(Urb, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY));
//
// Get the Root Hub Pdo
//
SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
&HubDeviceExtension->RootHubPhysicalDeviceObject,
&HubDeviceExtension->RootHubFunctionalDeviceObject);
RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
ASSERT(HubDeviceExtension->RootHubPhysicalDeviceObject);
ASSERT(HubDeviceExtension->RootHubFunctionalDeviceObject);
DPRINT1("RootPdo %x, RootFdo %x\n",
HubDeviceExtension->RootHubPhysicalDeviceObject,
HubDeviceExtension->RootHubFunctionalDeviceObject);
//
// Send the StartDevice to RootHub
//
Status = ForwardIrpAndWait(RootHubDeviceObject, Irp);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to start the RootHub PDO\n");
ASSERT(FALSE);
}
//
// Get the current number of hubs
//
Status = SubmitRequestToRootHub(RootHubDeviceObject,
IOCTL_INTERNAL_USB_GET_HUB_COUNT,
&HubDeviceExtension->NumberOfHubs, NULL);
//
// Get the Hub Interface
//
Status = QueryInterface(RootHubDeviceObject,
USB_BUS_INTERFACE_HUB_GUID,
sizeof(USB_BUS_INTERFACE_HUB_V5),
5,
(PVOID)&HubDeviceExtension->HubInterface);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to get HUB_GUID interface with status 0x%08lx\n", Status);
return STATUS_UNSUCCESSFUL;
}
HubInterfaceBusContext = HubDeviceExtension->HubInterface.BusContext;
//
// Get the USBDI Interface
//
Status = QueryInterface(RootHubDeviceObject,
USB_BUS_INTERFACE_USBDI_GUID,
sizeof(USB_BUS_INTERFACE_USBDI_V2),
2,
(PVOID)&HubDeviceExtension->UsbDInterface);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to get USBDI_GUID interface with status 0x%08lx\n", Status);
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))
{
DPRINT1("GetRootHubDeviceHandle failed with status 0x%08lx\n", Status);
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);
Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
Status = SubmitRequestToRootHub(RootHubDeviceObject,
IOCTL_INTERNAL_USB_SUBMIT_URB,
Urb,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to get HubDeviceDescriptor!\n");
}
DumpDeviceDescriptor(&HubDeviceExtension->HubDeviceDescriptor);
//
// Get Root Hubs Configuration Descriptor
//
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);
DPRINT1("RootHub Handle %x\n", HubDeviceExtension->RootHubHandle);
Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
Status = SubmitRequestToRootHub(RootHubDeviceObject,
IOCTL_INTERNAL_USB_SUBMIT_URB,
Urb,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to get RootHub Configuration with status %x\n", Status);
ASSERT(FALSE);
}
ASSERT(HubDeviceExtension->HubConfigDescriptor.wTotalLength);
DumpConfigurationDescriptor(&HubDeviceExtension->HubConfigDescriptor);
Status = HubDeviceExtension->HubInterface.GetExtendedHubInformation(HubInterfaceBusContext,
RootHubDeviceObject,
&HubDeviceExtension->UsbExtHubInfo,
sizeof(USB_EXTHUB_INFORMATION_0),
&Result);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to extended hub information. Unable to determine the number of ports!\n");
ASSERT(FALSE);
}
DPRINT1("HubDeviceExtension->UsbExtHubInfo.NumberOfPorts %x\n", HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
//
// Get the Hub Descriptor
//
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);
Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
Status = SubmitRequestToRootHub(RootHubDeviceObject,
IOCTL_INTERNAL_USB_SUBMIT_URB,
Urb,
NULL);
DPRINT1("bDescriptorType %x\n", HubDeviceExtension->HubDescriptor.bDescriptorType);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to get Hub Descriptor!\n");
ExFreePool(Urb);
return STATUS_UNSUCCESSFUL;
}
HubStatus = 0;
UsbBuildGetStatusRequest(Urb,
URB_FUNCTION_GET_STATUS_FROM_DEVICE,
0,
&HubStatus,
0,
NULL);
Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
Status = SubmitRequestToRootHub(RootHubDeviceObject,
IOCTL_INTERNAL_USB_SUBMIT_URB,
Urb,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to get Hub Status!\n");
ExFreePool(Urb);
return STATUS_UNSUCCESSFUL;
}
DPRINT1("HubStatus %x\n", HubStatus);
//
// 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);
ASSERT(Pid != NULL);
InterfaceList[0].InterfaceDescriptor = Pid;
ConfigUrb = USBD_CreateConfigurationRequestEx(&HubDeviceExtension->HubConfigDescriptor,
(PUSBD_INTERFACE_LIST_ENTRY)&InterfaceList);
ASSERT(ConfigUrb != NULL);
Status = SubmitRequestToRootHub(RootHubDeviceObject,
IOCTL_INTERNAL_USB_SUBMIT_URB,
ConfigUrb,
NULL);
HubDeviceExtension->ConfigurationHandle = ConfigUrb->UrbSelectConfiguration.ConfigurationHandle;
HubDeviceExtension->PipeHandle = ConfigUrb->UrbSelectConfiguration.Interface.Pipes[0].PipeHandle;
DPRINT1("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
//
// 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);
DPRINT1("Status %x\n", Status);
//
// FIXME handle error
//
ASSERT(Status == STATUS_SUCCESS);
}
}
ExFreePool(ConfigUrb);
//
// Enable power on all ports
//
DPRINT1("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);
}
DPRINT1("RootHubInitNotification %x\n", HubDeviceExtension->HubInterface.RootHubInitNotification);
//
// init roo hub notification
//
if (HubDeviceExtension->HubInterface.RootHubInitNotification)
{
Status = HubDeviceExtension->HubInterface.RootHubInitNotification(HubInterfaceBusContext,
DeviceObject,
RootHubInitCallbackFunction);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to set callback\n");
}
}
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);
}
}
}
}
ExFreePool(Urb);
break;
}
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
switch (Stack->Parameters.QueryDeviceRelations.Type)
{
case BusRelations:
{
PDEVICE_RELATIONS DeviceRelations = NULL;
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
Status = USBHUB_FdoQueryBusRelations(DeviceObject, &DeviceRelations);
Information = (ULONG_PTR)DeviceRelations;
break;
}
case RemovalRelations:
{
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
return ForwardIrpAndForget(DeviceObject, Irp);
}
default:
DPRINT1("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:
{
DPRINT1("IRP_MN_QUERY_BUS_INFORMATION\n");
break;
}
case IRP_MN_QUERY_ID:
{
DPRINT1("IRP_MN_QUERY_ID\n");
break;
}
case IRP_MN_QUERY_CAPABILITIES:
{
DPRINT1("IRP_MN_QUERY_CAPABILITIES\n");
break;
}
default:
{
DPRINT1(" 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)
{
DPRINT1("FdoHandleDeviceControl\n");
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
}