因为PC里一条总线上可以连接很多设备,就像一棵树一样,需要遍历所有总线上所有子设备,并且为每一个子设备安装相应的驱动程序,下面这个函数,实现枚举所有子设备,实现代码如下:
#001 NTSTATUS
#002 IopEnumerateDevice(
#003 IN PDEVICE_OBJECT DeviceObject)
#004 {获取设备的节点。
#005 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
#006 DEVICETREE_TRAVERSE_CONTEXT Context;
#007 PDEVICE_RELATIONS DeviceRelations;
#008 PDEVICE_OBJECT ChildDeviceObject;
#009 IO_STATUS_BLOCK IoStatusBlock;
#010 PDEVICE_NODE ChildDeviceNode;
#011 IO_STACK_LOCATION Stack;
#012 NTSTATUS Status;
#013 ULONG i;
#014
#015 DPRINT("DeviceObject 0x%p\n", DeviceObject);
#016
#017 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
#018 报告这个设备到用户模式的即插即用管理器。
#019 /* Report the device to the user-mode pnp manager */
#020 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
#021 &DeviceNode->InstancePath);
#022
#023 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
#024
#025 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
#026 发送查询设备之间相互关系。
#027 Status = IopInitiatePnpIrp(
#028 DeviceObject,
#029 &IoStatusBlock,
#030 IRP_MN_QUERY_DEVICE_RELATIONS,
#031 &Stack);
#032 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
#033 {
#034 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
#035 return Status;
#036 }
#037获取设备相互关系。
#038 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
#039
#040 if (!DeviceRelations)
#041 {
#042 DPRINT("No PDOs\n");
#043 return STATUS_UNSUCCESSFUL;
#044 }
#045
#046 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
#047 创建所有这个根设备下面的子设备。
#048 /*
#049 * Create device nodes for all discovered devices
#050 */
#051 for (i = 0; i < DeviceRelations->Count; i++)
#052 {
#053 ChildDeviceObject = DeviceRelations->Objects[i];
#054 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
#055 获取子设备节点是否存在。
#056 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
#057 if (!ChildDeviceNode)
#058 {如果不存在,就创建这个子设备节点。
#059 /* One doesn't exist, create it */
#060 Status = IopCreateDeviceNode(
#061 DeviceNode,
#062 ChildDeviceObject,
#063 NULL,
#064 &ChildDeviceNode);
#065 if (NT_SUCCESS(Status))
#066 {
#067 /* Mark the node as enumerated */
#068 ChildDeviceNode->Flags |= DNF_ENUMERATED;
#069
#070 /* Mark the DO as bus enumerated */
#071 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
#072 }
#073 else
#074 {
#075 /* Ignore this DO */
#076 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
#077 ObDereferenceObject(ChildDeviceNode);
#078 }
#079 }
#080 else
#081 {
#082 /* Mark it as enumerated */
#083 ChildDeviceNode->Flags |= DNF_ENUMERATED;
#084 ObDereferenceObject(ChildDeviceObject);
#085 }
#086 }
#087 ExFreePool(DeviceRelations);
#088