-/*
+/*
* 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("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),
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
+ //
+ return FALSE;
+ }
+
+ if (ConfigurationDescriptor->bNumInterfaces < 2)
+ {
+ //
+ // composite device must have multiple interfaces
+ //
+ return FALSE;
+ }
+
+ if (DeviceDescriptor->bDeviceClass == 0)
+ {
+ //
+ // composite device
+ //
+ ASSERT(DeviceDescriptor->bDeviceSubClass == 0);
+ ASSERT(DeviceDescriptor->bDeviceProtocol == 0);
+ return TRUE;
+ }
+
+ if (DeviceDescriptor->bDeviceClass == 0xEF &&
+ DeviceDescriptor->bDeviceSubClass == 0x02 &&
+ DeviceDescriptor->bDeviceProtocol == 0x01)
+ {
+ //
+ // USB-IF association descriptor
+ //
+ return TRUE;
+ }
+
+ //
+ // not a composite device
+ //
+ return FALSE;
+}
+
NTSTATUS
CreateDeviceIds(
PDEVICE_OBJECT UsbChildDeviceObject)
{
- NTSTATUS Status;
+ NTSTATUS Status = STATUS_SUCCESS;
ULONG Index;
PWCHAR BufferPtr;
+ WCHAR Buffer[100];
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;
//
// Initialize the CompatibleIds String
//
- UsbChildExtension->usCompatibleIds.Length = 144;
+ UsbChildExtension->usCompatibleIds.Length = 144; //FIXME
UsbChildExtension->usCompatibleIds.MaximumLength = UsbChildExtension->usCompatibleIds.Length;
+ //
+ // allocate mem for compatible id string
+ //
BufferPtr = ExAllocatePoolWithTag(NonPagedPool,
UsbChildExtension->usCompatibleIds.Length,
USB_HUB_TAG);
}
RtlZeroMemory(BufferPtr, UsbChildExtension->usCompatibleIds.Length);
-
Index = 0;
+
+ //
+ // get device descriptor
+ //
+ DeviceDescriptor = &UsbChildExtension->DeviceDesc;
+
+ //
+ // get configuration descriptor
+ //
+ ConfigurationDescriptor = UsbChildExtension->FullConfigDesc;
+
+ //
+ // get interface descriptor
+ //
+ InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)(ConfigurationDescriptor + 1);
+
//
// Construct the CompatibleIds
//
- if (UsbChildExtension->DeviceDesc.bDeviceClass == 0)
+ if (IsCompositeDevice(DeviceDescriptor, ConfigurationDescriptor))
{
- PUSB_INTERFACE_DESCRIPTOR InterDesc = (PUSB_INTERFACE_DESCRIPTOR)
- ((ULONG_PTR)UsbChildExtension->FullConfigDesc + sizeof(USB_CONFIGURATION_DESCRIPTOR));
+ //
+ // sanity checks
+ //
+ ASSERT(DeviceDescriptor->bNumConfigurations == 1);
+ ASSERT(ConfigurationDescriptor->bNumInterfaces > 1);
Index += swprintf(&BufferPtr[Index],
- L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
- InterDesc->bInterfaceClass,InterDesc->bInterfaceSubClass,InterDesc->bInterfaceProtocol) + 1;
+ L"USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
+ DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol) + 1;
Index += swprintf(&BufferPtr[Index],
- L"USB\\Class_%02x&SubClass_%02x",
- InterDesc->bInterfaceClass,InterDesc->bInterfaceSubClass) + 1;
+ L"USB\\DevClass_%02x&SubClass_%02x",
+ DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass) + 1;
Index += swprintf(&BufferPtr[Index],
- L"USB\\Class_%02x",
- InterDesc->bInterfaceClass) + 1;
+ L"USB\\DevClass_%02x",
+ DeviceDescriptor->bDeviceClass) + 1;
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\COMPOSITE") + 1;
}
else
{
- PUSB_DEVICE_DESCRIPTOR DevDesc = &UsbChildExtension->DeviceDesc;
- Index += swprintf(&BufferPtr[Index],
+ //
+ // sanity checks for simple usb device
+ //
+ ASSERT(ConfigurationDescriptor->bNumInterfaces == 1);
+
+ //
+ // FIXME: support multiple configurations
+ //
+ ASSERT(DeviceDescriptor->bNumConfigurations == 1);
+
+ if (DeviceDescriptor->bDeviceClass == 0)
+ {
+ Index += swprintf(&BufferPtr[Index],
L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
- DevDesc->bDeviceClass,DevDesc->bDeviceSubClass,DevDesc->bDeviceProtocol) + 1;
- Index += swprintf(&BufferPtr[Index],
+ InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass, InterfaceDescriptor->bInterfaceProtocol) + 1;
+ Index += swprintf(&BufferPtr[Index],
L"USB\\Class_%02x&SubClass_%02x",
- DevDesc->bDeviceClass,DevDesc->bDeviceSubClass) + 1;
- Index += swprintf(&BufferPtr[Index],
+ InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass) + 1;
+ Index += swprintf(&BufferPtr[Index],
L"USB\\Class_%02x",
- DevDesc->bDeviceClass) + 1;
+ InterfaceDescriptor->bInterfaceClass) + 1;
+ }
+ else
+ {
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
+ DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol) + 1;
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\Class_%02x&SubClass_%02x",
+ DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass) + 1;
+ Index += swprintf(&BufferPtr[Index],
+ L"USB\\Class_%02x",
+ DeviceDescriptor->bDeviceClass) + 1;
+
+
+ }
}
+
BufferPtr[Index] = UNICODE_NULL;
- DPRINT1("usCompatibleIds %wZ\n", &UsbChildExtension->usCompatibleIds);
UsbChildExtension->usCompatibleIds.Buffer = BufferPtr;
+ DPRINT1("usCompatibleIds %wZ\n", &UsbChildExtension->usCompatibleIds);
//
// Initialize the DeviceId String
// Construct DeviceId
//
swprintf(BufferPtr, L"USB\\Vid_%04x&Pid_%04x\0", UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct);
- DPRINT1("usDeviceId) %wZ\n", &UsbChildExtension->usDeviceId);
UsbChildExtension->usDeviceId.Buffer = BufferPtr;
+ DPRINT1("usDeviceId %wZ\n", &UsbChildExtension->usDeviceId);
//
// Initialize the HardwareId String
L"USB\\Vid_%04x&Pid_%04x",
UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct) + 1;
BufferPtr[Index] = UNICODE_NULL;
- DPRINT1("usHardWareIds %wZ\n", &UsbChildExtension->usHardwareIds);
UsbChildExtension->usHardwareIds.Buffer = BufferPtr;
+ DPRINT1("usHardWareIds %wZ\n", &UsbChildExtension->usHardwareIds);
//
// FIXME: Handle Lang ids
//
//
- // Get the product string
+ // Get the product string if obe provided
//
- Status = GetUsbStringDescriptor(UsbChildDeviceObject,
- UsbChildExtension->DeviceDesc.iProduct,
- 0,
- (PVOID*)&UsbChildExtension->usTextDescription.Buffer,
- &UsbChildExtension->usTextDescription.Length);
- if (!NT_SUCCESS(Status))
+ if (UsbChildExtension->DeviceDesc.iProduct)
{
- DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
- goto Cleanup;
- }
+ 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);
+ UsbChildExtension->usTextDescription.MaximumLength = UsbChildExtension->usTextDescription.Length;
+ DPRINT1("Usb TextDescription %wZ\n", &UsbChildExtension->usTextDescription);
+ }
//
- // Get the Serial Number string
+ // Get the Serial Number string if obe provided
//
- Status = GetUsbStringDescriptor(UsbChildDeviceObject,
- UsbChildExtension->DeviceDesc.iSerialNumber,
- 0,
- (PVOID*)&UsbChildExtension->usInstanceId.Buffer,
- &UsbChildExtension->usInstanceId.Length);
- if (!NT_SUCCESS(Status))
+ if (UsbChildExtension->DeviceDesc.iSerialNumber)
{
- DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
- goto Cleanup;
+ 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);
}
- UsbChildExtension->usInstanceId.MaximumLength = UsbChildExtension->usInstanceId.Length;
- DPRINT1("Usb InstanceId %wZ\n", &UsbChildExtension->usInstanceId);
return Status;
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,
UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)NewChildDeviceObject->DeviceExtension;
RtlZeroMemory(UsbChildExtension, sizeof(HUB_CHILDDEVICE_EXTENSION));
UsbChildExtension->ParentDeviceObject = UsbHubDeviceObject;
+ UsbChildExtension->PortNumber = PortId;
//
// Create the UsbDeviceObject
}
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("Sending the initial SCE Request %x\n", DeviceObject);
+ DPRINT1("RootHubInitCallbackFunction Sending the initial SCE Request %x\n", 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);
+ }
+ }
+ }
+*/
//
// Send the first SCE Request
//
PHUB_DEVICE_EXTENSION HubDeviceExtension;
PDEVICE_OBJECT RootHubDeviceObject;
PVOID HubInterfaceBusContext , UsbDInterfaceBusContext;
+ //PORT_STATUS_CHANGE StatusChange;
HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
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);
}
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
{
+/*
+ //
+ // 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);
+ }
+ }
+ }
+*/
//
// Send the first SCE Request
//
QueryStatusChangeEndpoint(DeviceObject);
}
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Failed to set callback\n");
- }
-
ExFreePool(Urb);
break;
}