IoRegisterPlugPlayNotification源码分析

原创 2016年08月30日 22:24:22

    IoRegisterPlugPlayNotification函数的作用是为指定guid的设备注册一个回调函数,当进入设备驱动并调用IoSetDeviceInterfaceState使能设备访问接口后,让系统调用之前注册的回调函数,以实现通知的目的.wrk1.2源码中并没有IO管理器的实现,因此,只能退而求其次,参考ReactOS中关于IoRegisterPlugPlayNotification的实现.

    ReactOS在系统初始化阶段调用PoInitSystem初始化电源管理器时,会以

        IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
                                       0, /* The registry has not been initialized yet */
                                       (PVOID)&GUID_DEVICE_SYS_BUTTON,
                                       IopRootDeviceNode->
                                       PhysicalDeviceObject->DriverObject,
                                       PopAddRemoveSysCapsCallback,
                                       NULL,
                                       &NotificationEntry);
的形式为集成在主板按键上的调用IoRegisterPlugPlayNotification.

    参数1 EventCategoryDeviceInterfaceChange表明Pnp管理器在接到设备接口状态变化(Enable/Disable)时调用先前注册的回调函数;

    参数3 GUID_DEVICE_SYS_BUTTON是指被IoSetDeviceInterfaceState操作的接口;

    参数5和6是回调函数的入口地址和参数;

    不得不说,系统中注册回调函数都有一定的相似性,步骤可归纳为2步:1).为一个Entry分配pool内存,并用回调函数入口地址和参数Context初始化Entry,并初始化其他域(如回调条件);2).将刚分配的Entry结构以互斥的方式加入到内核中相应的队列中.IoRegisterPlugPlayNotification也是如此:

{
//分配池内存
Entry = ExAllocatePoolWithTag(
		NonPagedPool,
		sizeof(PNP_NOTIFY_ENTRY),
		TAG_PNP_NOTIFY);
//从interface获得设备的名字
Status = IoGetDeviceInterfaces(
			(LPGUID)EventCategoryData,
			NULL, /* PhysicalDeviceObject OPTIONAL */
			0, /* Flags */
			&SymbolicLinkList);
NotificationInfos.Version = 1;//以下是初始化Entry结构
NotificationInfos.Size = sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION);
RtlCopyMemory(&NotificationInfos.Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID));
RtlCopyMemory(&NotificationInfos.InterfaceClassGuid, EventCategoryData, sizeof(GUID));


Entry->PnpNotificationProc = CallbackRoutine;
	Entry->EventCategory = EventCategory;
	Entry->Context = Context;
//最后,获得互斥锁,并插入PnpNotifyListHead
KeAcquireGuardedMutex(&PnpNotifyListLock);
InsertHeadList(&PnpNotifyListHead,
		&Entry->PnpNotifyList);
KeReleaseGuardedMutex(&PnpNotifyListLock);
}
    回调函数注册后,将在什么情况下才会被调用?通过搜索对PnpNotifyListHead的引用,可以发现端倪:

Pnpnotify.c!IopNotifyPlugPlayNotification中遍历PnpNotifyListHead:
	ListEntry = PnpNotifyListHead.Flink;
	while (ListEntry != &PnpNotifyListHead)
	{
		ChangeEntry = CONTAINING_RECORD(ListEntry, PNP_NOTIFY_ENTRY, 
PnpNotifyList);
		ListEntry = ListEntry->Flink;
	}
这是典型的遍历队列操作啊,有必要介绍一下IopNotifyPlugPlayNotification的流程:

一般IoSetDeviceInterfaceState会以下列方式调用IopNotifyPlugPlayNotification

    EventGuid = Enable ? &GUID_DEVICE_INTERFACE_ARRIVAL : &GUID_DEVICE_INTERFACE_REMOVAL;
    IopNotifyPlugPlayNotification(
        PhysicalDeviceObject,
        EventCategoryDeviceInterfaceChange,
        EventGuid,
        &GuidString,
        (PVOID)SymbolicLinkName);
    当IopNotifyPlugPlayNotification被调用时,它搜索PnpNotifyListHead链表,逐项比对已注册在PnpNotifyListHead队列中的PNP_NOTIFY_ENTRY各项,如果PNP_NOTIFY_ENTRY中接口GUID和产生设备插拔事件的接口GUID相同,则调用PNP_NOTIFY_ENTRY中的回调函数,去完成一些挂起的IRP请求.


版权声明:本文为博主原创文章,未经博主允许不得转载。

【Java源码分析】HashTable源码分析

类的定义 public class Hashtable extends Dictionary implements Map, Cloneable, java.io.Serializable {} 注...
  • Sugar_Z_
  • Sugar_Z_
  • 2016年07月17日 17:31
  • 1408

【Java源码分析】ArrayList源码分析

类的定义 public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java...
  • Sugar_Z_
  • Sugar_Z_
  • 2016年07月16日 17:49
  • 1296

深入源码分析go类型系统

深入源码分析go类型系统   Ø runtime/type.h    go类型描述的静态信息 //type  go类型最通用定义,go的类型系统通过这个数据结构来进行驱动 /...
  • hittata
  • hittata
  • 2016年03月17日 17:23
  • 1624

dubbo源码分析(二):超时原理以及应用场景

dubbo源码分析(二):超时原理以及应用场景 本篇主要记录dubbo中关于超时的常见问题,实现原理,解决的问题以及如何在服务降级中体现作用等。 超时问题 为了检查对dubbo超时的...
  • huxing998
  • huxing998
  • 2018年01月15日 20:51
  • 12

Handler使用场景以及源码分析

路漫漫其修远兮,吾将上下而求索 Handler的使用场景 子线程操作完成之后,通知主线程执行操作 首先在主线程创建一个Handler实例 private val MSG_WHAT:...
  • jking54
  • jking54
  • 2018年01月15日 20:51
  • 34

简单Spark源码分析

1 Master启动流程 1、在start-master.sh脚本中调用Mater.scala中的main方法 2、在main方法中封装spark参数,并调用startRpcEnvAndEndpo...
  • liguohuaBigdata
  • liguohuaBigdata
  • 2018年01月15日 19:53
  • 89

Jquery 源码分析一: 整体架构、链式调用、插件接口

jQuery 整体架构:JQuery框架的核心就是从HTML文档中匹配元素并对其执行操作,那么有两个问题值得我们思考? jQuery 对象构建的方式? jQuery 方法的调用方式? jQuery 对...
  • qq_36846234
  • qq_36846234
  • 2018年01月15日 16:14
  • 7

HashMap实现原理及源码分析

哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出...
  • l_215851356
  • l_215851356
  • 2018年01月15日 14:19
  • 9

Linux内核源码分析方法

一、内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次。如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径。我们...
  • sty124578
  • sty124578
  • 2018年01月15日 09:24
  • 99

ArrayList源码分析

ArrayList是有序列表,底层用数组实现,我们来读一读它的源码: //定义了一个静态常量,即默认容量为10 private static final int DEFAULT_CAPACITY...
  • lixiaobuaa
  • lixiaobuaa
  • 2018年01月12日 21:42
  • 10
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:IoRegisterPlugPlayNotification源码分析
举报原因:
原因补充:

(最多只允许输入30个字)