reactos操作系统实现(95)
在PNP管理器里,最重要的处理,就是即插即用消息。下面来分析键盘的即插即用消息处理函数,实现的代码如下: #001 NTSTATUS NTAPI #002 i8042Pnp( #003 IN PDEVICE_OBJECT DeviceObject, #004 IN PIRP Irp) #005 { #006 PIO_STACK_LOCATION Stack; #007 ULONG MinorFunction; #008 I8042_DEVICE_TYPE DeviceType; #009 ULONG_PTR Information = 0; #010 NTSTATUS Status; #011
获取IRP的栈。 #012 Stack = IoGetCurrentIrpStackLocation(Irp);
获取IRP次功能代码。 #013 MinorFunction = Stack->MinorFunction;
获取设备类型。 #014 DeviceType = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Type; #015
根据即插即用次功能代码处理。 #016 switch (MinorFunction) #017 {
分配资源并启动一个设备。 #018 case IRP_MN_START_DEVICE: /* 0x00 */ #019 { #020 TRACE_(I8042PRT,"IRP_MJ_PNP / IRP_MN_START_DEVICE/n"); #021
如果设备类型不为物理设备类型,就处理。 #022 /* Call lower driver (if any) */ #023 if (DeviceType != PhysicalDeviceObject) #024 {
向前传送IRP,并等待回应。 #025 Status = ForwardIrpAndWait(DeviceObject,Irp);
如果回应IRP成功,就调用i8042PnpStartDevice函数来分配资源。 #026 if (NT_SUCCESS(Status)) #027 Status = i8042PnpStartDevice( #028 DeviceObject, #029 Stack->Parameters.StartDevice.AllocatedResources, #030 Stack->Parameters.StartDevice.AllocatedResourcesTranslated); #031 } #032 else #033 Status = STATUS_SUCCESS; #034 break; #035 }
查询是否有子设备。 #036 case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x07 */ #037 { #038 switch (Stack->Parameters.QueryDeviceRelations.Type) #039 {
PNP 管理器向设备发送一个带有 BusRelations 码的 IRP_MN_QUERY_DEVICE_RELATIONS 的请求来获得设备的子设备列表,这里回应的子设备列表为0个。 #040 case BusRelations: #041 { #042 PDEVICE_RELATIONS DeviceRelations; #043 #044 TRACE_(I8042PRT,"IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations/n"); #045 DeviceRelations = ExAllocatePool(PagedPool,sizeof(DEVICE_RELATIONS)); #046 if (DeviceRelations) #047 { #048 DeviceRelations->Count = 0; #049 Information = (ULONG_PTR)DeviceRelations; #050 Status = STATUS_SUCCESS; #051 } #052 else #053 Status = STATUS_INSUFFICIENT_RESOURCES; #054 break; #055 }
这里处理即插即用的删除子设备的IRP。 #056 case RemovalRelations: #057 { #058 TRACE_(I8042PRT,"IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations/n"); #059 return ForwardIrpAndForget(DeviceObject,Irp); #060 }
缺省的IRP处理。 #061 default: #062 ERR_(I8042PRT,"IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx/n", #063 Stack->Parameters.QueryDeviceRelations.Type); #064 ASSERT(FALSE); #065 return ForwardIrpAndForget(DeviceObject,Irp); #066 } #067 break; #068 }
过滤系统请求的资源。 #069 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* (optional) 0x0d */ #070 { #071 TRACE_(I8042PRT,"IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS/n"); #072 /* Nothing to do */ #073 Status = Irp->IoStatus.Status; #074 break; #075 } #076 default: #077 { #078 ERR_(I8042PRT,"IRP_MJ_PNP / unknown minor function 0x%x/n",MinorFunction); #079 ASSERT(FALSE); #080 return ForwardIrpAndForget(DeviceObject,Irp); #081 } #082 } #083
IRP完成设置。 #084 Irp->IoStatus.Information = Information; #085 Irp->IoStatus.Status = Status; #086 IoCompleteRequest(Irp,IO_NO_INCREMENT); #087 return Status; #088 } #089
接着来分析启动设备的消息,函数i8042PnpStartDevice的实现代码如下: #001 static NTSTATUS #002 i8042PnpStartDevice( #003 IN PDEVICE_OBJECT DeviceObject, #004 IN PCM_RESOURCE_LIST AllocatedResources, #005 IN PCM_RESOURCE_LIST AllocatedResourcesTranslated) #006 { #007 PFDO_DEVICE_EXTENSION DeviceExtension; #008 PPORT_DEVICE_EXTENSION PortDeviceExtension; #009 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor,ResourceDescriptorTranslated; #010 INTERRUPT_DATA InterruptData; #011 BOOLEAN FoundDataPort = FALSE; #012 BOOLEAN FoundControlPort = FALSE; #013 BOOLEAN FoundIrq = FALSE; #014 ULONG i; #015 NTSTATUS Status; #016 #017 TRACE_(I8042PRT,"i8042PnpStartDevice(%p)/n",DeviceObject);
获取设备扩展对象。 #018 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
获取当前端口对象。 #019 PortDeviceExtension = DeviceExtension->PortDeviceExtension; #020 #021 ASSERT(DeviceExtension->PnpState == dsStopped); #022
即插即用管理器分配资源失败,因此直接返回。 #023 if (!AllocatedResources) #024 { #025 WARN_(I8042PRT,"No allocated resources sent to driver/n"); #026 return STATUS_INSUFFICIENT_RESOURCES; #027 }
如果分配资源数量不对,就返回出错。 #028 if (AllocatedResources->Count != 1) #029 { #030 WARN_(I8042PRT,"Wrong number of allocated resources sent to driver/n"); #031 return STATUS_INSUFFICIENT_RESOURCES; #032 }
判断分配资源的版本是否一样,如果不一样也需要返回出错。 #033 if (AllocatedResources->List[0].PartialResourceList.Version != 1 #034 || AllocatedResources->List[0].PartialResourceList.Revision != 1 #035 || AllocatedResourcesTranslated->List[0].PartialResourceList.Version != 1 #036 || AllocatedResourcesTranslated->List[0].PartialResourceList.Revision != 1) #037 { #038 WARN_(I8042PRT,"Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1/n", #039 AllocatedResources->List[0].PartialResourceList.Version, #040 AllocatedResources->List[0].PartialResourceList.Revision, #041 AllocatedResourcesTranslated->List[0].PartialResourceList.Version, #042 AllocatedResourcesTranslated->List[0].PartialResourceList.Revision); #043 return STATUS_REVISION_MISMATCH; #044 } #045
获取操作系统分配资源,比如端口地址和使用内存,还有中断号等等。 #046 /* Get Irq and optionally control port and data port */ #047 for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++) #048 {
资源描述结构。 #049 ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i]; #050 ResourceDescriptorTranslated = &AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i];
根据资源类型来处理。 #051 switch (ResourceDescriptor->Type) #052 {
分配的端口资源。 #053 case CmResourceTypePort: #054 {
找到端口资源。 #055 if (ResourceDescriptor->u.Port.Length == 1) #056 { #057 /* We assume that the first ressource will #058 * be the control port and the second one #059 * will be the data port... #060 */
先判断是否数据端口。 #061 if (!FoundDataPort) #062 {
保存系统分配的数据端口地址。 #063 PortDeviceExtension->DataPort = ULongToPtr(ResourceDescriptor- #064 >u.Port.Start.u.LowPart); #065 INFO_(I8042PRT,"Found data port: %p/n",PortDeviceExtension->DataPort); #066 FoundDataPort = TRUE; #067 } #068 else if (!FoundControlPort) #069 {
保存系统分配的控制命令端口地址。 #070 PortDeviceExtension->ControlPort = ULongToPtr(ResourceDescriptor- #071 >u.Port.Start.u.LowPart); #072 INFO_(I8042PRT,"Found control port: %p/n",PortDeviceExtension->ControlPort); #073 FoundControlPort = TRUE; #074 } #075 else #076 {
其它是分配错误的端口地址。 #077 WARN_(I8042PRT,"Too much I/O ranges provided: 0x%lx/n",ResourceDescriptor- #078 >u.Port.Length); #079 return STATUS_INVALID_PARAMETER; #080 } #081 } #082 else #083 WARN_(I8042PRT,"Invalid I/O range length: 0x%lx/n",ResourceDescriptor->u.Port.Length); #084 break; #085 }
这里处理系统分配的中断资源。 #086 case CmResourceTypeInterrupt: #087 {
如果已经分配了中断,就返回出错。 #088 if (FoundIrq) #089 return STATUS_INVALID_PARAMETER;
保存中断资源。 #090 InterruptData.Dirql = (KIRQL)ResourceDescriptorTranslated->u.Interrupt.Level; #091 InterruptData.Vector = ResourceDescriptorTranslated->u.Interrupt.Vector; #092 InterruptData.Affinity = ResourceDescriptorTranslated->u.Interrupt.Affinity;
中断模式。 #093 if (ResourceDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED) #094 InterruptData.InterruptMode = Latched; #095 else #096 InterruptData.InterruptMode = LevelSensitive;
中断源是否共享。 #097 InterruptData.ShareInterrupt = (ResourceDescriptorTranslated->ShareDisposition == CmResourceShareShared); #098 INFO_(I8042PRT,"Found irq resource: %lu/n",ResourceDescriptor->u.Interrupt.Level); #099 FoundIrq = TRUE; #100 break; #101 } #102 default: #103 WARN_(I8042PRT,"Unknown resource descriptor type 0x%x/n",ResourceDescriptor->Type); #104 } #105 } #106
如果没有分配中断资源,就返回出错。 #107 if (!FoundIrq) #108 { #109 WARN_(I8042PRT,"Interrupt resource was not found in allocated resources list/n"); #110 return STATUS_INSUFFICIENT_RESOURCES; #111 } #112 else if (DeviceExtension->Type == Keyboard && (!FoundDataPort || !FoundControlPort)) #113 {
如果是键盘类型,但又没有分配数据端口和命令控制端口资源,也返回出错。 #114 WARN_(I8042PRT,"Some required resources were not found in allocated resources list/n"); #115 return STATUS_INSUFFICIENT_RESOURCES; #116 } #117 else if (DeviceExtension->Type == Mouse && (FoundDataPort || FoundControlPort)) #118 {
如果是鼠标类型,但又没有分配数据端口和命令控制端口资源,也返回出错。 #119 WARN_(I8042PRT,"Too much resources were provided in allocated resources list/n"); #120 return STATUS_INVALID_PARAMETER; #121 } #122
根据不同类型来处理。 #123 switch (DeviceExtension->Type) #124 { #125 case Keyboard: #126 {
键盘类型处理,调用函数StartProcedure来处理键盘中断设置,并启动键盘。 #127 RtlCopyMemory( #128 &PortDeviceExtension->KeyboardInterrupt, #129 &InterruptData, #130 sizeof(INTERRUPT_DATA)); #131 PortDeviceExtension->Flags |= KEYBOARD_STARTED; #132 Status = StartProcedure(PortDeviceExtension); #133 break; #134 } #135 case Mouse: #136 {
鼠标类型处理,调用函数StartProcedure来处理鼠标中断设置,并启动鼠标。 #137 RtlCopyMemory( #138 &PortDeviceExtension->MouseInterrupt, #139 &InterruptData, #140 sizeof(INTERRUPT_DATA)); #141 PortDeviceExtension->Flags |= MOUSE_STARTED; #142 Status = StartProcedure(PortDeviceExtension); #143 break; #144 } #145 default: #146 { #147 WARN_(I8042PRT,"Unknown FDO type %u/n",DeviceExtension->Type); #148 ASSERT(!(PortDeviceExtension->Flags & KEYBOARD_CONNECTED) || !(PortDeviceExtension->Flags & MOUSE_CONNECTED)); #149 Status = STATUS_INVALID_DEVICE_REQUEST; #150 } #151 } #152
这里设置即插即用初始化状态成功完成。 #153 if (NT_SUCCESS(Status)) #154 DeviceExtension->PnpState = dsStarted; #155 #156 return Status; #157 }
下面来分析函数StartProcedure的实现,代码如下: #001 static NTSTATUS #002 StartProcedure( #003 IN PPORT_DEVICE_EXTENSION DeviceExtension) #004 { #005 NTSTATUS Status; #006 UCHAR FlagsToDisable = 0; #007 UCHAR FlagsToEnable = 0; #008
如果检查没有数据端口,就立即返回。 #009 if (DeviceExtension->DataPort == 0) #010 { #011 /* Unable to do something at the moment */ #012 return STATUS_SUCCESS; #013 } #014
如果没有发现键盘或鼠标设备存在,就尽量尝试加载键盘或鼠标。 #015 if (!(DeviceExtension->Flags & (KEYBOARD_PRESENT | MOUSE_PRESENT))) #016 { #017 /* Try to detect them */ #018 TRACE_(I8042PRT,"Check if the controller is really a i8042/n");
检查设备是否存在。 #019 Status = i8042BasicDetect(DeviceExtension); #020 if (!NT_SUCCESS(Status)) #021 { #022 WARN_(I8042PRT,"i8042BasicDetect() failed with status 0x%08lx/n",Status);
找不到设备,就返回。 #023 return STATUS_UNSUCCESSFUL; #024 } #025 #026 /* First detect the mouse and then the keyboard! #027 If we do it the other way round,some systems throw away settings like the keyboard translation,when detecting the mouse. #028
如果不是首次安装模式,就检测鼠标是否存在。 #029 Don't detect the mouse if we're in 1st stage setup! */ #030 if(!IsFirstStageSetup()) #031 { #032 TRACE_(I8042PRT,"Detecting mouse/n"); #033 i8042DetectMouse(DeviceExtension); #034 } #035
检测键盘。 #036 TRACE_(I8042PRT,"Detecting keyboard/n"); #037 i8042DetectKeyboard(DeviceExtension); #038 #039 INFO_(I8042PRT,"Keyboard present: %s/n",DeviceExtension->Flags & KEYBOARD_PRESENT ? "YES" : "NO"); #040 INFO_(I8042PRT,"Mouse present : %s/n",DeviceExtension->Flags & MOUSE_PRESENT ? "YES" : "NO"); #041 } #042
设置键盘的中断处理。 #043 /* Connect interrupts */ #044 if (DeviceExtension->Flags & KEYBOARD_PRESENT && #045 DeviceExtension->Flags & KEYBOARD_CONNECTED && #046 DeviceExtension->Flags & KEYBOARD_STARTED && #047 !(DeviceExtension->Flags & KEYBOARD_INITIALIZED)) #048 {
调用函数i8042ConnectKeyboardInterrupt来设置键盘中断处理函数。 #049 /* Keyboard is ready to be initialized */ #050 Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension); #051 if (NT_SUCCESS(Status)) #052 { #053 DeviceExtension->Flags |= KEYBOARD_INITIALIZED; #054 FlagsToDisable |= CCB_KBD_DISAB; #055 FlagsToEnable |= CCB_KBD_INT_ENAB; #056 } #057 } #058
设置鼠标的中断处理。 #059 if (DeviceExtension->Flags & MOUSE_PRESENT && #060 DeviceExtension->Flags & MOUSE_CONNECTED && #061 DeviceExtension->Flags & MOUSE_STARTED && #062 !(DeviceExtension->Flags & MOUSE_INITIALIZED)) #063 {
调用函数i8042ConnectKeyboardInterrupt来设置鼠标中断处理。 #064 /* Mouse is ready to be initialized */ #065 Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension); #066 if (NT_SUCCESS(Status)) #067 { #068 DeviceExtension->Flags |= MOUSE_INITIALIZED; #069 FlagsToDisable |= CCB_MOUSE_DISAB; #070 FlagsToEnable |= CCB_MOUSE_INT_ENAB; #071 } #072 } #073
如果设置中断处理成功,就打开中断标志。 #074 if (FlagsToEnable) #075 Status = EnableInterrupts(DeviceExtension,FlagsToDisable,FlagsToEnable); #076 else #077 Status = STATUS_SUCCESS; #078 #079 return Status; #080 }
下面来分析中断设置函数i8042ConnectKeyboardInterrupt,代码如下: #001 static NTSTATUS #002 i8042ConnectKeyboardInterrupt( #003 IN PI8042_KEYBOARD_EXTENSION DeviceExtension) #004 { #005 PPORT_DEVICE_EXTENSION PortDeviceExtension; #006 KIRQL DirqlMax; #007 NTSTATUS Status; #008 #009 TRACE_(I8042PRT,"i8042ConnectKeyboardInterrupt()/n"); #010
获取设备端口。 #011 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
取得最大中断级别。 #012 DirqlMax = MAX( #013 PortDeviceExtension->KeyboardInterrupt.Dirql, #014 PortDeviceExtension->MouseInterrupt.Dirql); #015 #016 INFO_(I8042PRT,"KeyboardInterrupt.Vector %lu/n", #017 PortDeviceExtension->KeyboardInterrupt.Vector); #018 INFO_(I8042PRT,"KeyboardInterrupt.Dirql %lu/n", #019 PortDeviceExtension->KeyboardInterrupt.Dirql); #020 INFO_(I8042PRT,"KeyboardInterrupt.DirqlMax %lu/n", #021 DirqlMax); #022 INFO_(I8042PRT,"KeyboardInterrupt.InterruptMode %s/n", #023 PortDeviceExtension->KeyboardInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched"); #024 INFO_(I8042PRT,"KeyboardInterrupt.ShareInterrupt %s/n", #025 PortDeviceExtension->KeyboardInterrupt.ShareInterrupt ? "yes" : "no"); #026 INFO_(I8042PRT,"KeyboardInterrupt.Affinity 0x%lx/n", #027PortDeviceExtension->KeyboardInterrupt.Affinity); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |