IN LONG PortId,
OUT PDEVICE_OBJECT *UsbChildDeviceObject);
+NTSTATUS
+DestroyUsbChildDeviceObject(
+ IN PDEVICE_OBJECT UsbHubDeviceObject,
+ IN LONG PortId);
+
NTSTATUS
SubmitRequestToRootHub(
IN PDEVICE_OBJECT RootHubDeviceObject,
{
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
{
}
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,
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",
+ 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",
- DevDesc->bDeviceClass) + 1;
+ DeviceDescriptor->bDeviceClass) + 1;
+
+
+ }
}
+
BufferPtr[Index] = UNICODE_NULL;
UsbChildExtension->usCompatibleIds.Buffer = BufferPtr;
DPRINT1("usCompatibleIds %wZ\n", &UsbChildExtension->usCompatibleIds);
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;
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,
}
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;
{
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
//