Implement IRP_MN_QUERY_DEVICE_RELATIONS for USB hubs
Implement IRP_MN_QUERY_ID for devices enumerated by USB hubs
Modified: trunk/reactos/drivers/usb/cromwell/hub/fdo.c
Modified: trunk/reactos/drivers/usb/cromwell/hub/pdo.c
Modified: trunk/reactos/drivers/usb/cromwell/hub/usbhub.h

Modified: trunk/reactos/drivers/usb/cromwell/hub/fdo.c
--- trunk/reactos/drivers/usb/cromwell/hub/fdo.c	2005-06-19 14:12:59 UTC (rev 16092)
+++ trunk/reactos/drivers/usb/cromwell/hub/fdo.c	2005-06-19 14:15:39 UTC (rev 16093)
@@ -10,8 +10,6 @@
 #define NDEBUG
 #include "usbhub.h"
 
-extern struct usb_driver hub_driver;
-
 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
 
 static VOID
@@ -47,6 +45,147 @@
 	}
 }
 
+static NTSTATUS
+UsbhubFdoQueryBusRelations(
+	IN PDEVICE_OBJECT DeviceObject,
+	OUT PDEVICE_RELATIONS* pDeviceRelations)
+{
+	PHUB_DEVICE_EXTENSION DeviceExtension;
+	PDEVICE_RELATIONS DeviceRelations;
+	PDEVICE_OBJECT Pdo;
+	PHUB_DEVICE_EXTENSION PdoExtension;
+	struct usb_device* dev;
+	ULONG i;
+	ULONG Children = 0;
+	ULONG NeededSize;
+	NTSTATUS Status;
+	CHAR Buffer[3][40];
+	
+	DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+	dev = DeviceExtension->dev;
+	
+	/* Create PDOs that are missing */
+	for (i = 0; i < USB_MAXCHILDREN; i++)
+	{
+		if (dev->children[i] == NULL)
+		{
+			/* No child device at this place */
+			continue;
+		}
+		Children++;
+		if (DeviceExtension->Children[i] != NULL)
+		{
+			/* PDO already exists */
+			continue;
+		}
+		/* Need to create the PDO */
+		Status = IoCreateDevice(
+			DeviceObject->DriverObject,
+			sizeof(HUB_DEVICE_EXTENSION),
+			NULL, /* Device name */
+			FILE_DEVICE_CONTROLLER,
+			FILE_AUTOGENERATED_DEVICE_NAME,
+			FALSE,
+			&DeviceExtension->Children[i]);
+		if (!NT_SUCCESS(Status))
+		{
+			DPRINT("Usbhub: IoCreateDevice() failed with status 0x%08lx\n", Status);
+			return Status;
+		}
+		
+		Pdo = DeviceExtension->Children[i];
+		Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
+		
+		PdoExtension = Pdo->DeviceExtension;
+		RtlZeroMemory(PdoExtension, sizeof(HUB_DEVICE_EXTENSION));
+		
+		PdoExtension->IsFDO = FALSE;
+		PdoExtension->dev = dev->children[i];
+		
+		RtlInitUnicodeString(
+			&PdoExtension->DeviceDescription,
+			L"USB device"); /* FIXME */
+		
+		sprintf(Buffer[0], "%lu", i + 1);
+		Status = UsbhubInitMultiSzString(
+			&PdoExtension->InstanceId,
+			Buffer[0], NULL);
+		if (!NT_SUCCESS(Status))
+			goto ByeBye;
+		
+		/* FIXME: what if it is a multiple-interface usb device? */
+		sprintf(Buffer[0], "USB\\Vid_%04x&Pid_%04x&Rev_%04x",
+			PdoExtension->dev->descriptor.idVendor,
+			PdoExtension->dev->descriptor.idProduct,
+			0 /* FIXME: need to put the revision */);
+		sprintf(Buffer[1], "USB\\Vid_%04x&Pid_%04x",
+			PdoExtension->dev->descriptor.idVendor,
+			PdoExtension->dev->descriptor.idProduct);
+		Status = UsbhubInitMultiSzString(
+			&PdoExtension->HardwareIds,
+			Buffer[0], Buffer[1], NULL);
+		if (!NT_SUCCESS(Status))
+			goto ByeBye;
+		
+		Status = UsbhubInitMultiSzString(
+			&PdoExtension->DeviceId,
+			Buffer[1], NULL);
+		if (!NT_SUCCESS(Status))
+			goto ByeBye;
+		
+		/* FIXME: what if it is a multiple-interface usb device? */
+		sprintf(Buffer[0], "USB\\Class_%02x&SubClass_%02x&Prot_%02x",
+			PdoExtension->dev->descriptor.bDeviceClass,
+			PdoExtension->dev->descriptor.bDeviceSubClass,
+			PdoExtension->dev->descriptor.bDeviceProtocol);
+		sprintf(Buffer[1], "USB\\Class_%02x&SubClass_%02x",
+			PdoExtension->dev->descriptor.bDeviceClass,
+			PdoExtension->dev->descriptor.bDeviceSubClass);
+		sprintf(Buffer[2], "USB\\Class_%02x",
+			PdoExtension->dev->descriptor.bDeviceClass);
+		Status = UsbhubInitMultiSzString(
+			&PdoExtension->CompatibleIds,
+			Buffer[0], Buffer[1], Buffer[2], NULL);
+		if (!NT_SUCCESS(Status))
+			goto ByeBye;
+		
+		Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
+	}
+	
+	/* Fill returned structure */
+	NeededSize = sizeof(DEVICE_RELATIONS);
+	if (Children > 1)
+		NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
+	DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
+		PagedPool,
+		NeededSize);
+	if (!DeviceRelations)
+		return STATUS_INSUFFICIENT_RESOURCES;
+	DeviceRelations->Count = Children;
+	Children = 0;
+	for (i = 0; i < USB_MAXCHILDREN; i++)
+	{
+		if (DeviceExtension->Children[i])
+		{
+			ObReferenceObject(DeviceExtension->Children[i]);
+			DeviceRelations->Objects[Children++] = DeviceExtension->Children[i];
+		}
+	}
+	ASSERT(Children == DeviceRelations->Count);
+	
+	*pDeviceRelations = DeviceRelations;
+	return STATUS_SUCCESS;
+
+ByeBye:
+	RtlFreeUnicodeString(&PdoExtension->DeviceDescription);
+	RtlFreeUnicodeString(&PdoExtension->DeviceId);
+	RtlFreeUnicodeString(&PdoExtension->InstanceId);
+	RtlFreeUnicodeString(&PdoExtension->HardwareIds);
+	RtlFreeUnicodeString(&PdoExtension->CompatibleIds);
+	IoDeleteDevice(Pdo);
+	return Status;
+}
+
 NTSTATUS STDCALL
 UsbhubPnpFdo(
 	IN PDEVICE_OBJECT DeviceObject,
@@ -62,35 +201,37 @@
 
 	switch (MinorFunction)
 	{
-		case IRP_MN_START_DEVICE:
+		case IRP_MN_START_DEVICE: /* 0x0 */
 		{
 			DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
 			Status = ForwardIrpAndWait(DeviceObject, Irp);
-			//if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
-			//	Status = OHCD_PnPStartDevice(DeviceObject, Irp);
 			break;
 		}
 
-		case IRP_MN_REMOVE_DEVICE:
-		//case IRP_MN_QUERY_REMOVE_DEVICE:
-		//case IRP_MN_CANCEL_REMOVE_DEVICE:
-		case IRP_MN_SURPRISE_REMOVAL:
-
-		case IRP_MN_STOP_DEVICE:
+		case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */
 		{
-			DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
-			Status = ForwardIrpAndWait(DeviceObject, Irp);
-			if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
-				Status = STATUS_SUCCESS;
-			IoDeleteDevice(DeviceObject); // just delete device for now
+			switch (IrpSp->Parameters.QueryDeviceRelations.Type)
+			{
+				case BusRelations:
+				{
+					PDEVICE_RELATIONS DeviceRelations;
+					DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
+					Status = UsbhubFdoQueryBusRelations(DeviceObject, &DeviceRelations);
+					Information = (ULONG_PTR)DeviceRelations;
+					break;
+				}
+				case RemovalRelations:
+				{
+					DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
+					return ForwardIrpAndForget(DeviceObject, Irp);
+				}
+				default:
+					DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
+						IrpSp->Parameters.QueryDeviceRelations.Type);
+					return ForwardIrpAndForget(DeviceObject, Irp);
+			}
 			break;
 		}
-		case IRP_MN_QUERY_STOP_DEVICE:
-		case IRP_MN_CANCEL_STOP_DEVICE:
-		{
-			Status = STATUS_SUCCESS;
-			break;
-		}
 
 		default:
 		{
@@ -104,11 +245,6 @@
 	return Status;
 }
 
-static inline struct device *hubdev (struct usb_device *dev)
-{
-	return &dev->actconfig->interface [0].dev;
-}
-
 NTSTATUS
 UsbhubDeviceControlFdo(
 	IN PDEVICE_OBJECT DeviceObject,
@@ -147,7 +283,7 @@
 				NodeInformation->NodeType = UsbHub;
 				RtlCopyMemory(
 					&NodeInformation->u.HubInformation.HubDescriptor,
-					((struct usb_hub *)usb_get_intfdata(to_usb_interface(hubdev(dev))))->descriptor,
+					((struct usb_hub *)usb_get_intfdata(to_usb_interface(&dev->actconfig->interface[0].dev)))->descriptor,
 					sizeof(USB_HUB_DESCRIPTOR));
 				NodeInformation->u.HubInformation.HubIsBusPowered = TRUE; /* FIXME */
 				Information = sizeof(USB_NODE_INFORMATION);
@@ -189,17 +325,24 @@
 				ConnectionInformation = (PUSB_NODE_CONNECTION_INFORMATION)BufferOut;
 				DPRINT1("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION partially implemented\n");
 				dev = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->dev;
-				ConnectionInformation->ConnectionIndex = 0; /* FIXME */
+				dev = dev->children[ConnectionInformation->ConnectionIndex = 0];
+				if (dev == NULL)
+				{
+					/* No device connected to this port */
+					RtlZeroMemory(ConnectionInformation, sizeof(USB_NODE_CONNECTION_INFORMATION));
+					Status = STATUS_SUCCESS;
+					break;
+				}
 				RtlCopyMemory(
 					&ConnectionInformation->DeviceDescriptor,
 					&dev->descriptor,
 					sizeof(USB_DEVICE_DESCRIPTOR));
 				ConnectionInformation->CurrentConfigurationValue = 0; /* FIXME */
-				ConnectionInformation->LowSpeed = TRUE; /* FIXME */
-				ConnectionInformation->DeviceIsHub = TRUE;
-				RtlZeroMemory(&ConnectionInformation->DeviceAddress, sizeof(ConnectionInformation->DeviceAddress)); /* FIXME */
+				ConnectionInformation->LowSpeed = dev->speed == USB_SPEED_LOW || dev->speed == USB_SPEED_FULL;
+				ConnectionInformation->DeviceIsHub = dev->descriptor.bDeviceClass == USB_CLASS_HUB;
+				ConnectionInformation->DeviceAddress = dev->devnum;
 				RtlZeroMemory(&ConnectionInformation->NumberOfOpenPipes, sizeof(ConnectionInformation->NumberOfOpenPipes)); /* FIXME */
-				RtlZeroMemory(&ConnectionInformation->ConnectionStatus, sizeof(ConnectionInformation->ConnectionStatus)); /* FIXME */
+				ConnectionInformation->ConnectionStatus = DeviceConnected;
 				RtlZeroMemory(&ConnectionInformation->PipeList, sizeof(ConnectionInformation->PipeList)); /* FIXME */
 				/*for (i = 0; i < 32; i++)
 				{

Modified: trunk/reactos/drivers/usb/cromwell/hub/pdo.c
--- trunk/reactos/drivers/usb/cromwell/hub/pdo.c	2005-06-19 14:12:59 UTC (rev 16092)
+++ trunk/reactos/drivers/usb/cromwell/hub/pdo.c	2005-06-19 14:15:39 UTC (rev 16093)
@@ -8,10 +8,9 @@
  */
 
 //#define NDEBUG
+#include <stdio.h>
 #include "usbhub.h"
 
-extern struct usb_driver hub_driver;
-
 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
 
 NTSTATUS
@@ -44,6 +43,59 @@
 	return Status;
 }
 
+static NTSTATUS
+UsbhubPdoQueryId(
+	IN PDEVICE_OBJECT DeviceObject,
+	IN PIRP Irp,
+	OUT ULONG_PTR* Information)
+{
+	PHUB_DEVICE_EXTENSION DeviceExtension;
+	ULONG IdType;
+	PUNICODE_STRING SourceString;
+	UNICODE_STRING String;
+	NTSTATUS Status;
+	
+	IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
+	DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+	RtlInitUnicodeString(&String, NULL);
+	
+	switch (IdType)
+	{
+		case BusQueryDeviceID:
+		{
+			DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
+			SourceString = &DeviceExtension->DeviceId;
+			break;
+		}
+		case BusQueryHardwareIDs:
+		{
+			DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
+			SourceString = &DeviceExtension->HardwareIds;
+			break;
+		}
+		case BusQueryCompatibleIDs:
+			DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
+			SourceString = &DeviceExtension->CompatibleIds;
+			break;
+		case BusQueryInstanceID:
+		{
+			DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
+			SourceString = &DeviceExtension->InstanceId;
+			break;
+		}
+		default:
+			DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
+			return STATUS_NOT_SUPPORTED;
+	}
+	
+	Status = UsbhubDuplicateUnicodeString(
+		&String,
+		SourceString,
+		PagedPool);
+	*Information = (ULONG_PTR)String.Buffer;
+	return Status;
+}
+
 NTSTATUS STDCALL
 UsbhubPnpPdo(
 	IN PDEVICE_OBJECT DeviceObject,
@@ -59,6 +111,11 @@
 
 	switch (MinorFunction)
 	{
+		case IRP_MN_QUERY_ID: /* 0x13 */
+		{
+			Status = UsbhubPdoQueryId(DeviceObject, Irp, &Information);
+			break;
+		}
 		default:
 		{
 			/* We can't forward request to the lower driver, because

Modified: trunk/reactos/drivers/usb/cromwell/hub/usbhub.h
--- trunk/reactos/drivers/usb/cromwell/hub/usbhub.h	2005-06-19 14:12:59 UTC (rev 16092)
+++ trunk/reactos/drivers/usb/cromwell/hub/usbhub.h	2005-06-19 14:15:39 UTC (rev 16093)
@@ -19,6 +19,15 @@
 	BOOLEAN IsFDO;
 	struct usb_device* dev;
 	PDEVICE_OBJECT LowerDevice;
+
+	PDEVICE_OBJECT Children[USB_MAXCHILDREN];
+	
+	/* Fields valid only when IsFDO == FALSE */
+	UNICODE_STRING DeviceDescription; // REG_SZ
+	UNICODE_STRING DeviceId;          // REG_SZ
+	UNICODE_STRING InstanceId;        // REG_SZ
+	UNICODE_STRING HardwareIds;       // REG_MULTI_SZ
+	UNICODE_STRING CompatibleIds;     // REG_MULTI_SZ
 } HUB_DEVICE_EXTENSION, *PHUB_DEVICE_EXTENSION;
 
 /* createclose.c */