因为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
获取这个总线驱动程序上所有设备。
#089 /*
#090 * Retrieve information about all discovered children from the bus driver
#091 */
#092 IopInitDeviceTreeTraverseContext(
#093 &Context,
#094 DeviceNode,
#095 IopActionInterrogateDeviceStack,
#096 DeviceNode);
#097
#098 Status = IopTraverseDeviceTree(&Context);
#099 if (!NT_SUCCESS(Status))
#100 {
#101 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx/n", Status);
#102 return Status;
#103 }
#104
获取这个总线驱动程序上所有注册表里的信息。
#105 /*
#106 * Retrieve configuration from the registry for discovered children
#107 */
#108 IopInitDeviceTreeTraverseContext(
#109 &Context,
#110 DeviceNode,
#111 IopActionConfigureChildServices,
#112 DeviceNode);
#113
#114 Status = IopTraverseDeviceTree(&Context);
#115 if (!NT_SUCCESS(Status))
#116 {
#117 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx/n", Status);
#118 return Status;
#119 }
#120
初始化所有发现的PnP设备驱动程序。
#121 /*
#122 * Initialize services for discovered children.
#123 */
#124 Status = IopInitializePnpServices(DeviceNode);
#125 if (!NT_SUCCESS(Status))
#126 {
#127 DPRINT("IopInitializePnpServices() failed with status 0x%08lx/n", Status);
#128 return Status;
#129 }
#130
#131 DPRINT("IopEnumerateDevice() finished/n");
#132 return STATUS_SUCCESS;
#133 }
#134