-/*
+/*
* PROJECT: ReactOS Universal Serial Bus Hub Driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbhub/fdo.c
*/
#define INITGUID
-
-#define NDEBUG
#include "usbhub.h"
NTSTATUS
IN LONG PortId,
OUT PDEVICE_OBJECT *UsbChildDeviceObject);
+NTSTATUS
+DestroyUsbChildDeviceObject(
+ IN PDEVICE_OBJECT UsbHubDeviceObject,
+ IN LONG PortId);
+
NTSTATUS
SubmitRequestToRootHub(
IN PDEVICE_OBJECT RootHubDeviceObject,
//
Status = IoCallDriver(RootHubDeviceObject, Irp);
- if (Status == STATUS_PENDING)
+ //
+ // 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;
}
RtlZeroMemory(Urb, sizeof(URB));
//
- // Create URB for getting Port Status
+ // Initialize URB for getting Port Status
//
UsbBuildVendorRequest(Urb,
URB_FUNCTION_CLASS_OTHER,
RtlZeroMemory(Urb, sizeof(URB));
//
- // Create URB for Clearing Port Reset
+ // Initialize URB for Clearing Port Reset
//
UsbBuildVendorRequest(Urb,
URB_FUNCTION_CLASS_OTHER,
RtlZeroMemory(Urb, sizeof(URB));
//
- // Create URB for Clearing Port Reset
+ // Initialize URB for Clearing Port Reset
//
UsbBuildVendorRequest(Urb,
URB_FUNCTION_CLASS_OTHER,
PWORK_ITEM_DATA WorkItemData;
PORT_STATUS_CHANGE PortStatus;
LONG PortId;
- DPRINT1("Entered DeviceStatusChangeThread, Context %x\n", Context);
+
static LONG failsafe = 0;
+ DPRINT1("Entered DeviceStatusChangeThread, Context %x\n", Context);
+
WorkItemData = (PWORK_ITEM_DATA)Context;
DeviceObject = (PDEVICE_OBJECT)WorkItemData->Context;
HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
{
DPRINT1("Device disconnected from port %d\n", PortId);
- //
- // FIXME: Remove the device, and deallocate memory
- //
+ 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
//
{
DPRINT1("Failed to reset port %d\n", PortId);
}
- }
+ }
}
else if (PortStatus.Change & USB_PORT_STATUS_ENABLE)
{
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
//
}
NTSTATUS
+NTAPI
StatusChangeEndpointCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
}
WorkItemData->Context = RealDeviceObject;
DPRINT1("Initialize work item\n");
- ExInitializeWorkItem(&WorkItemData->WorkItem, (PWORKER_THREAD_ROUTINE)DeviceStatusChangeThread, (PVOID)WorkItemData);
+ ExInitializeWorkItem(&WorkItemData->WorkItem, DeviceStatusChangeThread, (PVOID)WorkItemData);
//
// Queue the work item to handle initializing the device
// Set the completion routine for when device is connected to root hub
//
IoSetCompletionRoutine(HubDeviceExtension->PendingSCEIrp,
- (PIO_COMPLETION_ROUTINE) StatusChangeEndpointCompletion,
+ StatusChangeEndpointCompletion,
DeviceObject,
TRUE,
TRUE,
RtlZeroMemory(Urb, sizeof(URB));
//
- // Create URB for getting device descriptor
+ // Initialize URB for getting device descriptor
//
UsbBuildGetDescriptorRequest(Urb,
sizeof(Urb->UrbControlDescriptorRequest),
IN PDEVICE_OBJECT ChildDeviceObject,
IN UCHAR Index,
IN USHORT LangId,
- OUT PVOID *TransferBuffer)
+ OUT PVOID *TransferBuffer,
+ OUT USHORT *Size)
{
NTSTATUS Status;
PUSB_STRING_DESCRIPTOR StringDesc = NULL;
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);
//
// Copy the string to destination
//
RtlCopyMemory(*TransferBuffer, StringDesc->bString, SizeNeeded - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bLength));
+ *Size = SizeNeeded;
ExFreePool(StringDesc);
return STATUS_SUCCESS;
}
+NTSTATUS
+CreateDeviceIds(
+ PDEVICE_OBJECT UsbChildDeviceObject)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG Index;
+ PWCHAR BufferPtr;
+ WCHAR Buffer[100];
+ PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
+
+ UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)UsbChildDeviceObject->DeviceExtension;
+
+ //
+ // Initialize the CompatibleIds String
+ //
+ UsbChildExtension->usCompatibleIds.Length = 144;
+ UsbChildExtension->usCompatibleIds.MaximumLength = UsbChildExtension->usCompatibleIds.Length;
+
+ BufferPtr = ExAllocatePoolWithTag(NonPagedPool,
+ UsbChildExtension->usCompatibleIds.Length,
+ USB_HUB_TAG);
+ if (!BufferPtr)
+ {
+ DPRINT1("Failed to allocate memory\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(BufferPtr, UsbChildExtension->usCompatibleIds.Length);
+
+ Index = 0;
+ //
+ // Construct the CompatibleIds
+ //
+ if (UsbChildExtension->DeviceDesc.bDeviceClass == 0)
+ {
+ PUSB_INTERFACE_DESCRIPTOR InterDesc = (PUSB_INTERFACE_DESCRIPTOR)
+ ((ULONG_PTR)UsbChildExtension->FullConfigDesc + sizeof(USB_CONFIGURATION_DESCRIPTOR));
+
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
+ InterDesc->bInterfaceClass,InterDesc->bInterfaceSubClass,InterDesc->bInterfaceProtocol) + 1;
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\Class_%02x&SubClass_%02x",
+ InterDesc->bInterfaceClass,InterDesc->bInterfaceSubClass) + 1;
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\Class_%02x",
+ InterDesc->bInterfaceClass) + 1;
+ }
+ else
+ {
+ PUSB_DEVICE_DESCRIPTOR DevDesc = &UsbChildExtension->DeviceDesc;
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
+ DevDesc->bDeviceClass,DevDesc->bDeviceSubClass,DevDesc->bDeviceProtocol) + 1;
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\Class_%02x&SubClass_%02x",
+ DevDesc->bDeviceClass,DevDesc->bDeviceSubClass) + 1;
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\Class_%02x",
+ DevDesc->bDeviceClass) + 1;
+ }
+ BufferPtr[Index] = UNICODE_NULL;
+ UsbChildExtension->usCompatibleIds.Buffer = BufferPtr;
+ DPRINT1("usCompatibleIds %wZ\n", &UsbChildExtension->usCompatibleIds);
+
+ //
+ // Initialize the DeviceId String
+ //
+ UsbChildExtension->usDeviceId.Length = 44;
+ UsbChildExtension->usDeviceId.MaximumLength = UsbChildExtension->usDeviceId.Length;
+ BufferPtr = ExAllocatePoolWithTag(NonPagedPool,
+ UsbChildExtension->usDeviceId.Length,
+ USB_HUB_TAG);
+ if (!BufferPtr)
+ {
+ DPRINT1("Failed to allocate memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Cleanup;
+ }
+
+ //
+ // Construct DeviceId
+ //
+ swprintf(BufferPtr, L"USB\\Vid_%04x&Pid_%04x\0", UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct);
+ UsbChildExtension->usDeviceId.Buffer = BufferPtr;
+ DPRINT1("usDeviceId %wZ\n", &UsbChildExtension->usDeviceId);
+
+ //
+ // Initialize the HardwareId String
+ //
+ UsbChildExtension->usHardwareIds.Length = 110;
+ UsbChildExtension->usHardwareIds.MaximumLength = UsbChildExtension->usHardwareIds.Length;
+ BufferPtr = ExAllocatePoolWithTag(NonPagedPool, UsbChildExtension->usHardwareIds.Length, USB_HUB_TAG);
+ if (!BufferPtr)
+ {
+ DPRINT1("Failed to allocate memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Cleanup;
+ }
+
+ RtlZeroMemory(BufferPtr, UsbChildExtension->usHardwareIds.Length);
+
+ //
+ // Consturct HardwareIds
+ //
+ Index = 0;
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\Vid_%04x&Pid_%04x&Rev_%04x",
+ UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct, UsbChildExtension->DeviceDesc.bcdDevice) + 1;
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\Vid_%04x&Pid_%04x",
+ UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct) + 1;
+ BufferPtr[Index] = UNICODE_NULL;
+ UsbChildExtension->usHardwareIds.Buffer = BufferPtr;
+ 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);
+ goto Cleanup;
+ }
+
+ 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);
+ goto Cleanup;
+ }
+
+ 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;
+ goto Cleanup;
+ }
+
+ //
+ // copy instance id
+ //
+ RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR));
+ UsbChildExtension->usInstanceId.Length = UsbChildExtension->usDeviceId.MaximumLength = Index * sizeof(WCHAR);
+
+ DPRINT1("usDeviceId %wZ\n", &UsbChildExtension->usInstanceId);
+ }
+
+
+ return Status;
+
+Cleanup:
+ //
+ // Free Memory
+ //
+ if (UsbChildExtension->usCompatibleIds.Buffer)
+ ExFreePool(UsbChildExtension->usCompatibleIds.Buffer);
+ if (UsbChildExtension->usDeviceId.Buffer)
+ ExFreePool(UsbChildExtension->usDeviceId.Buffer);
+ if (UsbChildExtension->usHardwareIds.Buffer)
+ ExFreePool(UsbChildExtension->usHardwareIds.Buffer);
+ if (UsbChildExtension->usTextDescription.Buffer)
+ ExFreePool(UsbChildExtension->usTextDescription.Buffer);
+ if (UsbChildExtension->usInstanceId.Buffer)
+ ExFreePool(UsbChildExtension->usInstanceId.Buffer);
+
+ 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,
UNICODE_STRING DeviceName;
ULONG ConfigDescSize, DeviceDescSize;
PVOID HubInterfaceBusContext;
+ USB_CONFIGURATION_DESCRIPTOR ConfigDesc;
HubDeviceExtension = (PHUB_DEVICE_EXTENSION) UsbHubDeviceObject->DeviceExtension;
HubInterface = &HubDeviceExtension->HubInterface;
//
// Create a DeviceObject
//
-
Status = IoCreateDevice(UsbHubDeviceObject->DriverObject,
sizeof(HUB_CHILDDEVICE_EXTENSION),
NULL,
UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)NewChildDeviceObject->DeviceExtension;
RtlZeroMemory(UsbChildExtension, sizeof(HUB_CHILDDEVICE_EXTENSION));
UsbChildExtension->ParentDeviceObject = UsbHubDeviceObject;
+ UsbChildExtension->PortNumber = PortId;
//
// Create the UsbDeviceObject
UsbChildExtension->UsbDeviceHandle,
(PUCHAR)&UsbChildExtension->DeviceDesc,
&DeviceDescSize,
- (PUCHAR)&UsbChildExtension->ConfigDesc,
+ (PUCHAR)&ConfigDesc,
&ConfigDescSize);
if (!NT_SUCCESS(Status))
{
}
DumpDeviceDescriptor(&UsbChildExtension->DeviceDesc);
+ DumpConfigurationDescriptor(&ConfigDesc);
//
- // Allocate memory for DeviceId
+ // FIXME: Support more than one configuration and one interface?
//
- UsbChildExtension->DeviceId = ExAllocatePoolWithTag(NonPagedPool, 32 * sizeof(WCHAR), USB_HUB_TAG);
+ if (UsbChildExtension->DeviceDesc.bNumConfigurations > 1)
+ {
+ DPRINT1("Warning: Device has more than one configuration. Only one configuration (the first) is supported!\n");
+ }
- //
- // Construct DeviceId from vendor and product values
- //
- swprintf(UsbChildExtension->DeviceId, L"USB\\Vid_%04x&Pid_%04x", UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct);
+ if (ConfigDesc.bNumInterfaces > 1)
+ {
+ DPRINT1("Warning: Device has more that one interface. Only one interface (the first) is currently supported\n");
+ }
- DPRINT1("Usb Device Id %S\n", UsbChildExtension->DeviceId);
+ ConfigDescSize = ConfigDesc.wTotalLength;
//
- // FIXME: Handle Lang ids, will use default for now
+ // Allocate memory for the first full descriptor, including interfaces and endpoints.
//
+ UsbChildExtension->FullConfigDesc = ExAllocatePoolWithTag(PagedPool, ConfigDescSize, USB_HUB_TAG);
//
- // Get the product string
+ // Retrieve the full configuration descriptor
//
- Status = GetUsbStringDescriptor(NewChildDeviceObject,
- UsbChildExtension->DeviceDesc.iProduct,
+ Status = GetUsbDeviceDescriptor(NewChildDeviceObject,
+ USB_CONFIGURATION_DESCRIPTOR_TYPE,
+ 0,
0,
- (PVOID*)&UsbChildExtension->TextDescription);
+ UsbChildExtension->FullConfigDesc,
+ ConfigDescSize);
+
if (!NT_SUCCESS(Status))
{
- DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
+ DPRINT1("USBHUB: GetUsbDeviceDescriptor failed with status %x\n", Status);
goto Cleanup;
}
- DPRINT1("Usb TextDescription %S\n", UsbChildExtension->TextDescription);
-
- Status = GetUsbStringDescriptor(NewChildDeviceObject,
- UsbChildExtension->DeviceDesc.iSerialNumber,
- 0,
- (PVOID*)&UsbChildExtension->InstanceId);
+ DumpFullConfigurationDescriptor(UsbChildExtension->FullConfigDesc);
- DPRINT1("Usb InstanceId %S\n", UsbChildExtension->InstanceId);
+ //
+ // Construct all the strings that will described the device to PNP
+ //
+ Status = CreateDeviceIds(NewChildDeviceObject);
if (!NT_SUCCESS(Status))
{
- DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
+ DPRINT1("Failed to create strings needed to describe device to PNP.\n");
goto Cleanup;
}
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;
}
}
VOID
+NTAPI
RootHubInitCallbackFunction(
PVOID Context)
{
DPRINT1("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
//
- // Initialize the Hub
+ // check if function is available
//
- Status = HubDeviceExtension->HubInterface.Initialize20Hub(HubInterfaceBusContext,
- HubDeviceExtension->RootHubHandle, 1);
- DPRINT1("Status %x\n", Status);
+ 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);
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,
- (PRH_INIT_CALLBACK)RootHubInitCallbackFunction);
+ RootHubInitCallbackFunction);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to set callback\n");
+ }
}
else
{
QueryStatusChangeEndpoint(DeviceObject);
}
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Failed to set callback\n");
- }
-
ExFreePool(Urb);
break;
}