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",

#027         PortDeviceExtension->KeyboardInterrupt.Affinity);

你可能感兴趣的:(react)