即插即用(Plug and Play,PnP)是计算机系统I/O设备与部件配置的应用技术。PnP就是指插入就可以使用,不需要进行任何的硬件配置。其实还是需要安装相应的驱动程序才可以使用的。随着人们对计算机使用多样化,不断地需要添加各种各样的硬件卡到计算机的主板上,这样就需要配置硬件卡的中断、I/O所占用的资源,才能正常工作。这个过程是非常复杂的,经常需要手工配置,还需要查看计算机那里中断是空闲的,那些I/O端口是没有占用的。使用PnP技术以后,只需要操作系统做统一分配就行了。下面就来分析PnP初始化的实现代码:
#001 VOID INIT_FUNCTION
#002 PnpInit(VOID)
#003 {
#004 PDEVICE_OBJECT Pdo;
#005 NTSTATUS Status;
#006
#007 DPRINT("PnpInit()\n");
#008 初始化IO设备树锁。
#009 KeInitializeSpinLock(&IopDeviceTreeLock); #010
分配总线类型的GUID列表。
#011 /* Initialize the Bus Type GUID List */
#012 IopBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
#013 if (!IopBusTypeGuidList) {
#014 DPRINT1("ExAllocatePool() failed\n");
#015 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, STATUS_NO_MEMORY, 0, 0, 0);
#016 }
#017
#018 RtlZeroMemory(IopBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
#019 ExInitializeFastMutex(&IopBusTypeGuidList->Lock);
#020 初始化即插即用的事件通知支持。
#021 /* Initialize PnP-Event notification support */
#022 Status = IopInitPlugPlayEvents();
#023 if (!NT_SUCCESS(Status))
#024 {
#025 DPRINT1("IopInitPlugPlayEvents() failed\n");
#026 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
#027 }
#028 创建一个根设备驱动程序节点,保存在IopRootDriverObject里面。
#029 /*
#030 * Create root device node
#031 */
#032
#033 Status = IopCreateDriver(NULL, PnpDriverInitializeEmpty, NULL, 0, 0, &IopRootDriverObject);
#034 if (!NT_SUCCESS(Status))
#035 {
#036 DPRINT1("IoCreateDriverObject() failed\n");
#037 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
#038 }
#039 创建一个文件设备控制器对象保存到根驱动程序节点里。
#040 Status = IoCreateDevice(IopRootDriverObject, 0, NULL, FILE_DEVICE_CONTROLLER,
#041 0, FALSE, &Pdo);
#042 if (!NT_SUCCESS(Status))
#043 {
#044 DPRINT1("IoCreateDevice() failed\n");
#045 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
#046 }
#047 创建一个文件设备控制器对象节点。
#048 Status = IopCreateDeviceNode(NULL, Pdo, NULL, &IopRootDeviceNode);
#049 if (!NT_SUCCESS(Status))
#050 {
#051 DPRINT1("Insufficient resources\n");
#052 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
#053 }
#054 设置这个文件设备节点名称为HTREE\\ROOT\\。
#055 if (!RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
#056 L"HTREE\\ROOT\\0"))
#057 {
#058 DPRINT1("Failed to create the instance path!\n");
#059 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, STATUS_NO_MEMORY, 0, 0, 0);
#060 }
#061 报告这个设备到用户模式的PNP管理器。
#062 /* Report the device to the user-mode pnp manager */ #063 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, #064 &IopRootDeviceNode->InstancePath); #065 #066 IopRootDeviceNode->PhysicalDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; #067 PnpRootDriverEntry(IopRootDriverObject, NULL); #068 IopRootDeviceNode->PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; #069 IopRootDriverObject->DriverExtension->AddDevice( #070 IopRootDriverObject, #071 IopRootDeviceNode->PhysicalDeviceObject); #072
下面开始把Freeloader检测到的硬件信息移到注册表SYSTEM\CurrentControlSet\Root\键里。
#073 /* Move information about devices detected by Freeloader to SYSTEM\CurrentControlSet\Root\ */
#074 Status = IopUpdateRootKey();
#075 if (!NT_SUCCESS(Status))
#076 {
#077 DPRINT1("IopUpdateRootKey() failed\n");
#078 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
#079 }
#080 }