精华内容
下载资源
问答
  • 经常听到有一些同事抱百思特网怨自己的电脑太卡了,然后就想着清理文件或者是删除程序来加快电脑运行,后来有些文件或者程序就打不开了,其实不是文件和程序的问题,我想,你应该是误删了这三种类型的文件吧。...

    经常听到有一些同事抱百思特网怨自己的电脑太卡了,然后就想着清理文件或者是删除程序来加快电脑运行,后来有些文件或者程序就打不开了,其实不是文件和程序的问题,我想,你应该是误删了这三种类型的文件吧。

    82d2b10c4a2524f683b8c699e4859959.png

    首先我们需要一台电脑,并将电脑打开,桌面上打开【此电脑】,可以用双击的形式打开也可以使用快捷键【Window+E】快速打开。

    b22d5ca45c6269a58fdde268fd848039.png

    具体分类:

    第一类:搜索“Windows”

    windows文件主要用来存放Windows的系统文件和硬件驱动程序,这里被索引出来的这些文件夹中都是有关Windows驱动的程序包,通常删除/卸载后会使系统运行不稳定,不利于电脑正常工作,同时有些软件的功能也不能正常使用。

    e6bad957912e8ed1d81d01b1b12acbb4.png

    第二类:搜索“intel”

    intel文件是主板驱动文件,这样的程序文件通常是和处理器有关的百思特网,因此这些文件也不建议卸载,卸载后你会发现电脑的处理器不能正常工作哟!

    7ed9b94f795e58c8c1c6a14bcedd66a0.png

    第三类:搜索“microsoft”

    microsoft文件是系统自动生成的文件夹,主要放置系统账户的某些信息,部分软件主要是微软的软件的一些设置及数据等,不建议卸载,因为可能会导致word、Excel、PPT不能正常使用。

    57990016cc9c9f2c00ec7c8b783bb34a.png

    如果有小伙伴觉得你的“windows+E”打开不是“此电脑”而是“文件资源管理器”?可以这样设百思特网置下:

    a、先双击打开了【此电脑】,点击【查看】,点击【选项】中的【更改文件夹和搜索选择】。

    23a0bfa17ece62b446a16a60e2e62489.png

    b、随后将打开文件资源管理器时打开的位置选为【此电脑】,点击【确定】,再用快捷键【windows+E】就可以直接进入【此电脑】界面了。

    697c18eed291f3a5c2cce5709b4cae8f.png

    本文地址:https://www.best73.com/news/62186.html

    展开全文
  • PCI/PCIe接口卡Windows驱动程序(4)- 驱动程序代码(源文件) http://www.cnblogs.com/jacklu/p/4687325.html 本篇文章将对PCIe驱动程序的源文件代码作详细解释与说明。整个WDF驱动程序工程共包含4个头...
     
    

    本篇文章将对PCIe驱动程序的源文件代码作详细解释与说明。整个WDF驱动程序工程共包含4个头文件(已经在上篇文章中讲解)和3个.c文件(Driver.c  Device.c   Queue.c)

    Driver.c

    在看复杂的代码前,先给出程序流程图

     

    复制代码
      1 #include "driver.h"
      2 #include "driver.tmh"
      3 
      4 #ifdef ALLOC_PRAGMA
      5 #pragma alloc_text (INIT, DriverEntry)
      6 #pragma alloc_text (PAGE, Spw_PCIeEvtDeviceAdd)
      7 #pragma alloc_text (PAGE, Spw_PCIeEvtDriverContextCleanup)
      8 #endif
      9 
     10 
     11 NTSTATUS
     12 DriverEntry(
     13    IN PDRIVER_OBJECT  DriverObject,
     14    IN PUNICODE_STRING RegistryPath
     15     )
     16 {
     17     WDF_DRIVER_CONFIG config;
     18     //WDFDRIVER   driver;//????
     19     NTSTATUS status = STATUS_SUCCESS;
     20     WDF_OBJECT_ATTRIBUTES attributes;
     21 
     22     //
     23     // Initialize WPP Tracing
     24     //
     25     WPP_INIT_TRACING( DriverObject, RegistryPath );
     26 
     27     TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
     28 
     29     //
     30     // Register a cleanup callback so that we can call WPP_CLEANUP when
     31     // the framework driver object is deleted during driver unload.
     32     //
     33     
     34     WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
     35 
     36     attributes.EvtCleanupCallback = Spw_PCIeEvtDriverContextCleanup;
     37     
     38     WDF_DRIVER_CONFIG_INIT(&config,
     39         Spw_PCIeEvtDeviceAdd
     40         );
     41 
     42     status = WdfDriverCreate(DriverObject,
     43                              RegistryPath,
     44                              &attributes,
     45                              &config,
     46                              WDF_NO_HANDLE
     47                              );
     48 
     49     if (!NT_SUCCESS(status)) {
     50         TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status);
     51         WPP_CLEANUP(DriverObject);
     52         return status;
     53     }
     54 
     55     TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
     56 
     57     return status;
     58 }
     59 
     60 
     61 NTSTATUS
     62 Spw_PCIeEvtDeviceAdd(
     63     _In_    WDFDRIVER       Driver,
     64     _Inout_ PWDFDEVICE_INIT DeviceInit
     65     )
     66 {
     67     NTSTATUS status = STATUS_SUCCESS;
     68     WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
     69     WDF_OBJECT_ATTRIBUTES   deviceAttributes;
     70     WDFDEVICE device;
     71     PDEVICE_CONTEXT deviceContext;
     72 
     73     WDFQUEUE queue;
     74     WDF_IO_QUEUE_CONFIG    queueConfig;
     75 
     76     /*+++++Interrupt
     77     WDF_INTERRUPT_CONFIG    interruptConfig;
     78     -----*/
     79     //    WDF_IO_QUEUE_CONFIG        ioQueueConfig;
     80 
     81     UNREFERENCED_PARAMETER(Driver);
     82 
     83     PAGED_CODE();
     84 
     85     //采用WdfDeviceIoDirect方式
     86     WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);//WdfDeviceIoBuffered???重要吗?
     87     //When the I/O manager sends a request for buffered I/O, the IRP contains an internal copy of the caller's buffer
     88     //rather than the caller's buffer itself. The I/O manager copies data from the caller's buffer to the internal buffer
     89     //during a write request or from the internal buffer to the caller's buffer when the driver completes a read
     90     //request.
     91     //The WDF driver receives a WDF request object, which in turn contains an embedded WDF memory object.
     92     //The memory object contains the address of the buffer on which the driver should operate.
     93 
     94 
     95 
     96    // status = Spw_PCIeCreateDevice(DeviceInit);
     97 
     98     //初始化即插即用和电源管理例程配置结构
     99     WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
    100 
    101     //设置即插即用基本例程
    102     pnpPowerCallbacks.EvtDevicePrepareHardware = Spw_PCIeEvtDevicePrepareHardware;
    103     pnpPowerCallbacks.EvtDeviceReleaseHardware = Spw_PCIeEvtDeviceReleaseHardware;
    104     pnpPowerCallbacks.EvtDeviceD0Entry = Spw_PCIeEvtDeviceD0Entry;
    105     pnpPowerCallbacks.EvtDeviceD0Exit = Spw_PCIeEvtDeviceD0Exit;
    106 
    107     //注册即插即用和电源管理例程
    108     WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
    109 
    110     
    111     WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);
    112 
    113 
    114     //deviceAttributes.EvtCleanupCallback = Spw_PCIeEvtDriverContextCleanup;
    115     //
    116     // Set WDFDEVICE synchronization scope. By opting for device level
    117     // synchronization scope, all the queue and timer callbacks are
    118     // synchronized with the device-level spinlock.
    119     //
    120     deviceAttributes.SynchronizationScope = WdfSynchronizationScopeDevice;
    121 
    122     status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
    123     if (!NT_SUCCESS(status)) {
    124         return status;
    125     }
    126     deviceContext = GetDeviceContext(device);///????
    127     //deviceContext->Device = device;
    128     //
    129     // 初始化Context这个结构里的所有成员.
    130     //
    131     //deviceContext->PrivateDeviceData = 0;
    132     /*++++++Interrupt & DMA
    133     //设置中断服务例程和延迟过程调用
    134     WDF_INTERRUPT_CONFIG_INIT(&interruptConfig,
    135     PCISample_EvtInterruptIsr,
    136     PCISample_EvtInterruptDpc);
    137 
    138     //创建中断对象
    139     status = WdfInterruptCreate(device,
    140     &interruptConfig,
    141     WDF_NO_OBJECT_ATTRIBUTES,
    142     &pDeviceContext->Interrupt);
    143     if (!NT_SUCCESS (status)) {
    144     return status;
    145     }
    146 
    147     status = InitializeDMA(device);
    148 
    149     if (!NT_SUCCESS(status)) {
    150     return status;
    151     }
    152     -----*/
    153     //WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchSequential);
    154     //Initialize the Queue
    155     //        queueConfig.EvtIoDefault = Spw_PCIeEvtIoDefault;
    156     //        queueConfig.EvtIoWrite = Spw_PCIeEvtIoWrite;
    157     //queueConfig.EvtIoRead = Spw_PCIeEvtIoRead;
    158     //        queueConfig.EvtIoStop = Spw_PCIeEvtIoStop;
    159     //The driver must initialize the WDF_IO_QUEUE_CONFIG structure 
    160     //by calling WDF_IO_QUEUE_CONFIG_INIT or WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE.
    161     //用default初始化default 队列,用另一个初始化非default队列
    162     WDF_IO_QUEUE_CONFIG_INIT(
    163         &queueConfig,
    164         WdfIoQueueDispatchSequential
    165         );
    166 
    167     queueConfig.EvtIoDeviceControl = Spw_PCIeEvtIoDeviceControl;
    168 
    169 
    170     status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue);
    171     if (!NT_SUCCESS(status)) {
    172         return status;
    173     }
    174 
    175     //对于非默认队列,必须指定要分发的I/O请求类型
    176     //The WdfDeviceConfigureRequestDispatching method causes the framework to queue a specified type of I/O requests to a specified I/O queue.
    177     status = WdfDeviceConfigureRequestDispatching(
    178         device,
    179         queue,
    180         WdfRequestTypeDeviceControl
    181         );
    182     if (!NT_SUCCESS(status)) {
    183         return status;
    184     }
    185     //创建驱动程序接口与应用程序通信
    186     status = WdfDeviceCreateDeviceInterface(
    187         device,
    188         (LPGUID)&GUID_DEVINTERFACE_Spw_PCIe,
    189         NULL // ReferenceString
    190         );
    191     if (!NT_SUCCESS(status)) {
    192         return status;
    193     }
    194     /*
    195     if (NT_SUCCESS(status)) {
    196     //
    197     // Initialize the I/O Package and any Queues
    198     //
    199     status = Spw_PCIeQueueInitialize(device);
    200     }
    201     */
    202     //deviceContext->MemLength = MAXNLEN;
    203 
    204     //TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
    205 
    206     return status;
    207 }
    208 
    209 VOID
    210 Spw_PCIeEvtDriverContextCleanup(
    211     _In_ WDFOBJECT DriverObject
    212     )
    213 /*++
    214 Routine Description:
    215 
    216     Free all the resources allocated in DriverEntry.
    217 
    218 Arguments:
    219 
    220     DriverObject - handle to a WDF Driver object.
    221 
    222 Return Value:
    223 
    224     VOID.
    225 
    226 --*/
    227 {
    228     UNREFERENCED_PARAMETER(DriverObject);
    229 
    230     PAGED_CODE ();
    231 
    232     TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
    233 
    234     //没有必要清除WDFINTERRUPT对象,因为框架会自动清除
    235     // Stop WPP Tracing
    236     //
    237     WPP_CLEANUP( WdfDriverWdmGetDriverObject(DriverObject) );
    238 
    239 }
    复制代码

    4-8行是做一些预处理,驱动程序开发中,需要为每个函数指定位于分页内存还是非分页内存。INIT标识是指此函数为入口函数,驱动成功加载后可以从内存删除。PAGE标识是指此函数可以在驱动运行时被交换到硬盘上,如果不指定,将被编译器默认为非分页内存。

    11-58行定义了DriverEntry函数,每个 KMDF 驱动程序必须有一个 DriverEntry 例程,当操作系统检测到有新硬 件设备插入后,会查找它对应的驱动程序,找到这个驱动程序中的 DriverEntry 程。DriverEntry 是驱动程序的入口,它相当于 C 语言程序里的 main 函数。 DriverEntry 例程的原型声明如下:

    1 NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) ;

    函数返回类型 NTSTATUS  WDF 中的一个宏,它实际上是一个 32 位的二进制数,不同的数值表示不同的状态,在 PCIe 设备驱动程序开发中,需要用到的状态有: STATUS_SUCCESS STATUS_PENDING STATUS_UNSUCCESSFUL  别表示例程回调成功、 例程回调未完成、 例程回调失败。在传入参数里, IN 是一 个宏, 代表这个参数为入口参数,这与例程编写无关,只是为了让开发者能够更 容易的知道参数特性,其中 OUT 表示出口参数。关于参数标识, 还有另一种写法, _In__Out_ 两种写法对回调例程的编写都没影响。

    DriverEntry 的第一个参数是一个指向驱动程序对象的指针, 该对象就代表驱 动程序。 在 DriverEntry 例程中, 应该完成对这个对象的初始化并返回。 DriverEntry 的第二个参数是设备驱动对应服务键在注册表中的路径。DriverEntry 例程需要完成的任务主要包括:

    • 激活 WPP( Windows software trace preprocessor)软件调试,为可选任务;(对应代码25-27行)
    • 注册驱动程序的 EvtDriverDeviceAdd 回调函数;(对应代码38-40行)
    • 创建一个驱动程序对象, 向框架“注册”驱动程序;(对应代码42-53行)

    61-206行定义了EvtDriverDeviceAdd函数。每个支持即插即用的 KMDF 驱动程序必须有 EvtDriverDeviceAdd 回调例程, 每次操作系统枚举设备时, PnP 管理器就调用这个回调例程。 EvtDriverDeviceAdd 例程的主要任务包括:

    • 创建并初始化设备对象和相应的上下文区(122-126行);
    • 设置传输方式(86行)、 初始化即插即用和电源管理配置结构(99行), 注册即插即用和电源管理例程(101-108行);
    • 初始化队列配置结构(162-165行), 注册 I/O 处理例程(167行), 创建 I/O 队列(170行), 指定要分发的 I/O 请求类型(177-184行), 创建 GUID 接口(185-194行)。

    EvtDriverDeviceAdd 例程的原型声明如下:

    EvtDriverDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) ; 

    DeviceInit 指向 KMDF 自定义的一个结构体, 它在设置传输方式、 注册即插即 用和电源管理例程、 创建设备对象这些任务中起着传递重要数据的作用。

    209-239行定义了EvtDriverContextCleanup函数。EvtDriverContextCleanup 回调例程用来删除设备和回收操作系统分配给设备 的资源。对于即插即用设备,当手动拔出设备后, PnP 管理器会自动识别并删除设     Windows           EvtDriverContextCleanup 例程。

     

    Device.c

    复制代码
      1 #include "driver.h"
      2 #include "device.tmh"
      3 
      4 #pragma warning(disable:4013)  // assuming extern returning int
      5 #ifdef ALLOC_PRAGMA
      6 
      7 #pragma alloc_text(PAGE, Spw_PCIeEvtDevicePrepareHardware)
      8 #pragma alloc_text(PAGE, Spw_PCIeEvtDeviceReleaseHardware)
      9 #pragma alloc_text(PAGE, Spw_PCIeEvtDeviceD0Entry)
     10 #pragma alloc_text(PAGE, Spw_PCIeEvtDeviceD0Exit)
     11 
     12 #endif
     13 
     14 NTSTATUS
     15 Spw_PCIeEvtDevicePrepareHardware(
     16 IN WDFDEVICE Device,
     17 IN WDFCMRESLIST ResourceList,
     18 IN WDFCMRESLIST ResourceListTranslated
     19 )
     20 {
     21     ULONG            i;
     22     NTSTATUS        status = STATUS_SUCCESS;
     23     PDEVICE_CONTEXT pDeviceContext;
     24 
     25     PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor;//record the Hareware resource that OS dispatched to PCIe
     26     /*
     27     在Windows驱动开发中,PCM_PARTIAL_RESOURCE_DESCRIPTOR记录了为PCI设备分配的硬件资源,
     28     可能有CmResourceTypePort, CmResourceTypeMemory等,
     29     后者表示一段memory地址空间,顾名思义,是通过memory space访问的,
     30     前者表示一段I/O地址空间,但其flag有CM_RESOURCE_PORT_MEMORY和CM_RESOURCE_PORT_IO两种,
     31     分别表示通过memory space访问以及通过I/O space访问,这就是PCI请求与实际分配的差异,
     32     在x86下,CmResourceTypePort的flag都是CM_RESOURCE_PORT_IO,即表明PCI设备请求的是I/O地址空间,分配的也是I/O地址空间,
     33     而在ARM或Alpha等下,flag是CM_RESOURCE_PORT_MEMORY,表明即使PCI请求的I/O地址空间,但分配在了memory space,
     34     我们需要通过memory space访问I/O设备(通过MmMapIoSpace映射物理地址空间到虚拟地址空间,当然,是内核的虚拟地址空间,这样驱动就可以正常访问设备了)。
     35     */
     36     PAGED_CODE();
     37 
     38 //    UNREFERENCED_PARAMETER(Resources);//告诉编译器不要发出Resources没有被引用的警告
     39 
     40     pDeviceContext = GetDeviceContext(Device);
     41     pDeviceContext->MemBaseAddress = NULL;
     42     pDeviceContext->Counter_i = 0;
     43     //get resource
     44     for (i = 0; i < WdfCmResourceListGetCount(ResourceListTranslated); i++) {
     45 
     46         descriptor = WdfCmResourceListGetDescriptor(ResourceListTranslated, i);
     47         //if failed:
     48         if (!descriptor) {
     49             return STATUS_DEVICE_CONFIGURATION_ERROR;
     50         }
     51 
     52         switch (descriptor->Type) {
     53 
     54         case CmResourceTypeMemory:
     55             //MmMapIoSpace将物理地址转换成系统内核模式地址
     56             if (i == 0){
     57                 pDeviceContext->PhysicalAddressRegister = descriptor->u.Memory.Start.LowPart;
     58                 pDeviceContext->BAR0_VirtualAddress = MmMapIoSpace(
     59                     descriptor->u.Memory.Start,
     60                     descriptor->u.Memory.Length,
     61                     MmNonCached);
     62             }
     63             
     64             pDeviceContext->MemBaseAddress = MmMapIoSpace(
     65                 descriptor->u.Memory.Start,
     66                 descriptor->u.Memory.Length,
     67                 MmNonCached);
     68             pDeviceContext->MemLength = descriptor->u.Memory.Length;
     69 
     70             break;
     71 
     72         default:
     73             break;
     74         }
     75         if (!pDeviceContext->MemBaseAddress){
     76             return STATUS_INSUFFICIENT_RESOURCES;
     77         }
     78     }
     79     pDeviceContext->Counter_i = i;
     80     DbgPrint("EvtDevicePrepareHardware - ends\n");
     81 
     82     return STATUS_SUCCESS;
     83 }
     84 
     85 NTSTATUS
     86 Spw_PCIeEvtDeviceReleaseHardware(
     87 IN WDFDEVICE Device,
     88 IN WDFCMRESLIST ResourceListTranslated
     89 )
     90 {
     91     PDEVICE_CONTEXT    pDeviceContext = NULL;
     92 
     93     PAGED_CODE();
     94 
     95     DbgPrint("EvtDeviceReleaseHardware - begins\n");
     96 
     97     pDeviceContext = GetDeviceContext(Device);
     98 
     99     if (pDeviceContext->MemBaseAddress) {
    100         //MmUnmapIoSpace解除物理地址与系统内核模式地址的关联
    101         MmUnmapIoSpace(pDeviceContext->MemBaseAddress, pDeviceContext->MemLength);
    102         pDeviceContext->MemBaseAddress = NULL;
    103     }
    104 
    105     DbgPrint("EvtDeviceReleaseHardware - ends\n");
    106 
    107     return STATUS_SUCCESS;
    108 }
    109 
    110 NTSTATUS
    111 Spw_PCIeEvtDeviceD0Entry(
    112 IN  WDFDEVICE Device,
    113 IN  WDF_POWER_DEVICE_STATE PreviousState
    114 )
    115 {
    116     UNREFERENCED_PARAMETER(Device);
    117     UNREFERENCED_PARAMETER(PreviousState);
    118 
    119     return STATUS_SUCCESS;
    120 }
    121 
    122 
    123 NTSTATUS
    124 Spw_PCIeEvtDeviceD0Exit(
    125 IN  WDFDEVICE Device,
    126 IN  WDF_POWER_DEVICE_STATE TargetState
    127 )
    128 {
    129     UNREFERENCED_PARAMETER(Device);
    130     UNREFERENCED_PARAMETER(TargetState);
    131 
    132     PAGED_CODE();
    133 
    134     return STATUS_SUCCESS;
    135 }
    复制代码

    13-83行定义了EvtDevicePrepareHardware例程。EvtDevicePrepareHardwareEvtDeviceReleaseHardware两个例程对硬件设备能否获得Windows操作系统分配的资源起着至关重要的作用。EvtDevicePrepareHardware的任务主要包括获得内存资源、内存物理地址与虚拟地址的映射、I/O端口映射和中断资源分配。

    EvtDevicePrepareHardware例程的原型声明如下:

    1 NTSTATUS EvtDevicePrepareHardware(
    2 IN WDFDEVICE Device,
    3 IN WDFCMRESLIST ResourceList,
    4 IN WDFCMRESLIST ResourceListTranslated
    5 ) ;

    传入函数的三个参数,Device是在EvtDriverDeviceAdd创建的设备对象,另外两个参数是两个硬件资源列表,这两个硬件资源列表实际上代表了不同版本的同一份硬件资源集。ResourceList代表的硬件资源是通过总线地址描述的;ResourceListTranslated代表的硬件资源是通过内存物理地址描述的。

    WDF框架分配给硬件资源的具体过程如下:

    (1)用户插入PnP设备,总线驱动识别设备并枚举;

    (2)WDF框架调用总线驱动的EvtDeviceResourcesQuery,创建资源列表;

    (3)WDF框架调用总线驱动的EvtDeviceResourcesRequirementQuery,创建资源需求列表;

    (4)PnP管理器决定设备需要什么驱动程序;

    (5)PnP管理器创建设备资源列表并发送给驱动程序;

    (6)如果驱动程序调用WdfInterruptCreate例程,WDF框架就会在资源列表中分配给中断资源给驱动程序;

    (7)设备进入工作状态后,KMDF调用EvtDevicePrepareHardware例程传递两个资源列表,驱动程序保存这两个资源列表,直到WDF框架调用了EvtDeviceReleaseHardware例程。

    驱动程序通过EvtDevicePrepareHardware获得内存资源后,需要用MmMapIoSpace函数将物理地址映射成虚拟地址。

    85-108行定义了EvtDeviceReleaseHardware回调例程,其调用过程是EvtDevicePrepareHardware的逆过程,即获得虚拟地址后,利用MmUnMapIoSpace 函数将虚拟地址解映射成物理地址,然后再交给WDF框架释放,这里不再赘述。

    当 PCIe-SpaceWire接口卡设备被移除时,WDF框架会自动调用Spw_PCIeEvtDeviceReleaseHardware 函数释放设备和驱动程序的内存空间。由于系统每次检测到PCIe接口卡,会自动调用Spw_PCIeEvtDevicePrepareHardware函数提供内存资源,因此,断电或移除设备时,必须调用Spw_PCIeEvtDeviceReleaseHardware函数必须释放所分配的内存空间,否则,有可能导致内存溢出甚至操作系统崩溃。

    110-135定义了EvtDeviceD0Entry和EvtDeviceD0Exit例程,WDF框架会在设备进入工作状态后调用EvtDeviceD0Entry回调例程,设备进入工作状态会在以下几种情况下发生:

    • 即插即用设备被系统发现;
    • 操作系统和设备从睡眠状态被唤醒;
    • (如果设备支持低电压闲置状态)设备从低电压闲置状态被唤醒;
    • PnP管理器重新为设备分配资源。

    由于设备进入工作状态后,WDF框架就会根据事件调用各种回调例程,所以EvtDeviceD0Entry例程里一般不需要处理任何任务。设备离开工作状态后,WDF调EvtDeviceD0Exit回调例程,通常EvtDeviceD0Exit例程也不需要处理任何任务。需要注意的是,在注册这两个例程的时候,必须调用WdfDeviceInitSetPnpPowerEventCallbacks来注册设备即插即用和电源管理回调例程。

     

    Queue.c

    复制代码
      1 #include "driver.h"
      2 #include "queue.tmh"
      3 
      4 #pragma warning(disable:4013)  // assuming extern returning int
      5 
      6 #ifdef ALLOC_PRAGMA
      7 #pragma alloc_text (PAGE, Spw_PCIeEvtIoDeviceControl)
      8 
      9 #endif
     10 /*
     11 单一的默认I/O队列和单一的请求处理函数,EvtIoDefault。KMDF将会将设备所有的请求发送到默认I/O队列,
     12 然后它会调用驱动程序的EvtIoDefault来将每一个请求递交给驱动程序。
     13 
     14 *单一的默认I/O队列和多个请求处理函数,例如EvtIoRead、EvtIoWrite和EvtIoDeviceControl。KMDF会将设备所有的请求发送到默认I/O队列。
     15 然后会调用驱动程序的EvtIoRead处理函数来递交读请求、调用EvtIoWrite处理函数来递交写请求、调用EvtIoDeviceControl处理函数来递交设备I/O控制请求。
     16 */
     17 
     18 
     19 VOID
     20 Spw_PCIeEvtIoDeviceControl(
     21     IN WDFQUEUE Queue,
     22     IN WDFREQUEST Request,
     23     IN size_t OutputBufferLength,
     24     IN size_t InputBufferLength,
     25     IN ULONG IoControlCode
     26     )
     27 {
     28     WDFDEVICE device;
     29     PDEVICE_CONTEXT pDevContext;
     30 
     31     NTSTATUS  status;
     32 
     33     PVOID      inBuffer;
     34     PVOID     outBuffer;
     35     ULONG      AddressOffset;
     36 
     37     //PAGED_CODE(); do not uncomment this sentence
     38     device = WdfIoQueueGetDevice(Queue);
     39     pDevContext = GetDeviceContext(device);
     40 
     41     switch (IoControlCode) {
     42 //根据CTL_CODE请求码作相应的处理
     43     case Spw_PCIe_IOCTL_WRITE_OFFSETADDRESS:
     44         status = WdfRequestRetrieveInputBuffer(
     45             Request,
     46             sizeof(ULONG),
     47             &inBuffer,
     48             NULL
     49             );
     50         pDevContext->OffsetAddressFromApp = *(ULONG*)inBuffer;
     51         WdfRequestCompleteWithInformation(Request, status, sizeof(ULONG));
     52         if (!NT_SUCCESS(status)){
     53             goto Exit;
     54         }
     55         break;
     56 
     57     case Spw_PCIe_IOCTL_IN_BUFFERED:
     58             status = WdfRequestRetrieveInputBuffer(
     59                 Request,
     60                 sizeof(ULONG),
     61                 &inBuffer,
     62                 NULL
     63                 );
     64             AddressOffset = PCIE_WRITE_MEMORY_OFFSET + pDevContext->OffsetAddressFromApp;
     65             *(ULONG*)WDF_PTR_ADD_OFFSET(pDevContext->BAR0_VirtualAddress, AddressOffset) = *(ULONG*)inBuffer;
     66             WdfRequestCompleteWithInformation(Request, status, sizeof(ULONG));
     67             if (!NT_SUCCESS(status)){
     68                 goto Exit;
     69             }
     70         break;
     71         
     72     case Spw_PCIe_IOCTL_OUT_BUFFERED:
     73         status = WdfRequestRetrieveOutputBuffer(
     74             Request,
     75             sizeof(ULONG),
     76             &outBuffer,
     77             NULL
     78             );
     79         AddressOffset = PCIE_WRITE_MEMORY_OFFSET + pDevContext->OffsetAddressFromApp;
     80         //--------------------------------------------------------------------------
     81         *(ULONG*)outBuffer = *(ULONG*)WDF_PTR_ADD_OFFSET(pDevContext->BAR0_VirtualAddress, AddressOffset);
     82         //--------------------------------------------------------------------------
     83         //*(ULONG*)outBuffer = pDevContext->Counter_i;
     84         //--------------------------------------------------------------------------
     85         WdfRequestCompleteWithInformation(Request, status, sizeof(ULONG));
     86         if (!NT_SUCCESS(status)){
     87             goto Exit;
     88         }
     89         break;
     90     case Spw_PCIe_IOCTL_READ_PADDRESS:
     91             //Just think about the size of the data when you are choosing the METHOD.  
     92             //METHOD_BUFFERED is typically the fastest for small (less the 16KB) buffers, 
     93             //and METHOD_IN_DIRECT and METHOD_OUT_DIRECT should be used for larger buffers than that.
     94             //METHOD_BUFFERED,METHOD_OUT_DIRECT,METHOD_IN_DIRECT三种方式,
     95             //输入缓冲区地址可通过调用WdfRequestRetrieveInputBuffer函数获得
     96             //输出缓冲区地址可通过调用WdfRequestRetrieveOutputBuffer函数获得
     97     
     98             status = WdfRequestRetrieveOutputBuffer(
     99             Request,
    100             sizeof(ULONG),
    101             &outBuffer,
    102             NULL
    103             );
    104 
    105             *(ULONG*)outBuffer = pDevContext->PhysicalAddressRegister;//read BAR0 pysical address
    106 
    107             WdfRequestCompleteWithInformation(Request, status, sizeof(ULONG));
    108             if (!NT_SUCCESS(status)){
    109                 goto Exit;
    110             }
    111         break;
    112 
    113     default:
    114         status = STATUS_INVALID_DEVICE_REQUEST;
    115         WdfRequestCompleteWithInformation(Request, status, 0);
    116         break;
    117     }
    118 
    119 Exit:
    120     if (!NT_SUCCESS(status)) {
    121         WdfRequestCompleteWithInformation(
    122             Request,
    123             status,
    124             0
    125             );
    126     }
    127     return;
    128 }
    复制代码

    整个源代码文件只定义了一个例程EvtIoDeviceControl,当WDF框架处理I/O请求时,根据I/O 请求的副功能码执行相应的操作,I/O 请求处理结束后,需要通过一个例程完成I/O请求,以通知应用程序处理结束。否则,会因为应用程序无法正常退出而导致系统挂起。接口卡驱动程序中处理I/O请求的例程为Spw_PCIeEvtIoDeviceControl,它根据应用程序传入控制字的不同会执行不同的任务,包括读BAR0物理起始地址、读寄存器、写寄存器、写入偏移地址。

    Windows 2000及其以后的操作系统都是以I/O请求包的形式与驱动程序进行通信的。在WDF驱动程序中,处理I/O请求的关键判断哪些类型的I/O请求由驱动程序处理,哪些类型的I/O请求由WDF框架自动处理。当Windows操作系统收到一个从应用程序传送过来的I/O请求后,I/O管理器将它封装成I/O请求包发送给设备驱动程序。常见的I/O请求包括:create, close, read, write, 和 device I/O control,分别表示创建设备、关闭设备、读操作、写操作和控制命令字传输。

    应用程序执行I/O操作时,向I/O管理器提供了一个数据缓冲区。WDF框架提供三种数据传输方式:

    •  buffered方式:I/O管理器会创建与应用程序数据缓冲区完全相同的系统缓冲区,驱动程序在这个缓冲区工作,由I/O管理器完成复制数据任务;
    •  direct方式:I/O管理器锁定应用程序缓冲区的物理内存页,并创建一个MDL(内存描述符表)来描述该页,驱动程序将使用MDL工作;
    •  neither方式:I/O管理器把应用程序缓冲区的虚拟地址传递给驱动程序,一般不采用这种方式。

    在I/O请求处理中,WDF规定驱动程序必须包括以下一个或多个I/O回调例程,来处理从队列调度的I/O请求:

    •  EvtIoRead
    •  EvtIoWrite
    •  EvtIoDeviceIoControl
    •  EvtIoInternalDeeviceControl
    •  EvtIoDefault

     下面以完成一个读请求为例,描述WDF框架处理I/O请求的全过程

    第1步,应用程序调用Win32 API函数ReadFile进行读操作;第2步,ReadFile函数调用NTDLL.dll中的原生函数NtReadFile,从而进入内核服务,I/O管理器将接管读操作。第3步,I/O管理器为读请求构造类型为IRP_MJ_READ的请求包;第4步,I/O管理器找到由WDF框架创建的设备对象,并将请求包发送到它的读派遣函数;第5步,WDF框架收到请求包后,查看WDF驱动是否注册了读回调例程,如果注册了,就将请求包封装成一个I/O请求对象把它放到WDF驱动的某个指定队列中;第6步,队列将I/O请求对象发送给WDF驱动处理,WDF驱动注册的读回调例程被执行。

    现代操作系统比如Windows、Linux在内存管理上均采用分页机制。分页内存可被交换到硬盘,而非分页内存则不会交换到硬盘上。运行的程序代码中断请求优先级高于DISPATCH_LEVEL(包括DISPATCH_LEVEL)的,必须保证程序所在内存页为非分页内存,否则会造成系统挂起。在WDF驱动程序开发中,使用宏PAGE_CODE来标记某例程应在分页内存上。因此在驱动程序开发过程中要特别注意PAGE_CODE的使用。

    对于PCIe设备驱动开发,开发者还注意读写映射内存不能越界。比如在本次毕业设计中,BAR2为配置寄存器,编写程序时由于误写入BAR2映射的内存地址,造成操作系统一执行写操作就发生蓝屏。

     

    在看完这几篇文章后,将源代码通过VS2013+WDK8.1编译就能生成相应PCI/PCIe硬件板卡的Windows驱动程序(.sys文件),为了实现对驱动程序的安装与验证,还需要编写INF文件和应用程序文件,这部分将在下一篇文章中讲述。

     

    参考资料:

    武安河. Windows设备驱动程序WDF开发

    孔鹏. 基于WDF的光纤传输卡PCIe接口驱动的研究和实现

    杨阿锋基于WDF的PCIe接口高速数据传输卡的驱动程序开发

     

    展开全文
  • Windows驱动开发(1) - 驱动程序结构

    千次阅读 2016-04-10 15:07:01
    Windows驱动开发(1) - 驱动程序结构1、NT式1.1 头文件 ...Windows驱动程序的入口函数是DriverEntry函数。WDM式的驱动程序要导入的头文件是WDM.h。 说明:  1)采用C++编程,所以需要用extern “C”,因为我们导入的

    Windows驱动开发(1) - 驱动程序结构

    1、NT式

    1.1 头文件

      Driver.h头文件中包含了开发NT式驱动所需要的NTDDK.h,此外还定义了几个标志来指明函数和变量分配在分页内存还是非分页内存中。Windows驱动程序的入口函数是DriverEntry函数。WDM式的驱动程序要导入的头文件是WDM.h。
    说明:
      1)采用C++编程,所以需要用extern “C”,因为我们导入的是C的函数的符号表。
      2)在驱动中用到的变量或函数都需要指定分配在分页或非分页内存中,分页内存在物理内存不够的情况下可能会被交换出去,对于一些需要高IRQL的例程绝对不能被交换出页面,因此它们必须被定义为非分页内存。
      3)DriverEntry需要放在INIT标志的内存中。

    1.2 驱动程序的入口函数

    #pragma INITCODE
    extern "C" NTSTATUS DriverEntry (
        IN PDRIVER_OBJECT pDriverObject,
        IN PUNICODE_STRING pRegistryPath )
    {
    NTSTATUS status;
    KdPrint(("Enter DriverEntry\n"));
    
    //注册其他驱动调用函数入口
    pDriverObject->DriverUnload = HelloDDKUnload;
    pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine;
    pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine;
    pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine;
    pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine;
    
    //创建驱动设备对象
    status = CreateDevice(pDriverObject);
    KdPrint(("DriverEntry end\n"));
    return status;
    }

      1) 犹如控制台程序需要main、Win32 程序需要WinMain、DLL 程序需要DllMain 一样,驱动程序也有自己的入口点,即DriverEntry。DriverEntry 需要被加载到INIT 内存区域中,这样当驱动被卸载后它可以退出内存。
      2) DriverEntry 是由内核中的I/O 管理器负责调用的,它有两个参数DriverObject 和RegistryPath(当然形参的名字可以自己改变)。其中DriverObject 是由I/O管理器传递进来的驱动对象,RegistryPath 则指向此驱动负责的注册表。
      3)我们可以看到DriverEntry 首先是定义了一些变量,然后调用IoCreateDevice 创建设备对象,紧接着调用IoCreateSymbolicLink 创建符号链接。HelloDDKDispatchRoutine等是驱动程序在向Windows 的I/O 管理器注册一些回调函数。上面代码的含义是:当驱动程序将被卸载时自动调用HelloDDKUnload例程;当驱动程序接收到 IRP_MJ_CREATE 时自动调用HelloDDKDispatchRoutine。
      4)KdPrint是宏,用来输出。类似于MFC中的TRACE。
      5)#pragma INITCODE来指明此函数加载到INIT内存函数中。
      6)在驱动对象DriverObject 中,有个函数指针数组MajorFunction,它里面的每一个元素都记录着一个函数的地址对应着相应的IRP,我们可以通过简单地设置这个数组将IRP 与相应的派遣函数关联起来

    1.3 创建设备例程(函数)

    #pragma INITCODE
    NTSTATUS CreateDevice (IN PDRIVER_OBJECT pDriverObject)
    {
        NTSTATUS status;
        PDEVICE_OBJECT pDevObj;
        PDEVICE_EXTENSION pDevExt;
    
        //创建设备名称
        UNICODE_STRING devName;
        RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevice");
    
        //创建设备
        status = IoCreateDevice( pDriverObject,
                        sizeof(DEVICE_EXTENSION),
                        &(UNICODE_STRING)devName,
                        FILE_DEVICE_UNKNOWN,
                        0, TRUE,
                        &pDevObj );
    
        if (!NT_SUCCESS(status))
        return status;
        pDevObj->Flags |= DO_BUFFERED_IO;
        pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
        pDevExt->pDevice = pDevObj;
        pDevExt->ustrDeviceName = devName;
    
        //创建符号链接
        UNICODE_STRING symLinkName;
        RtlInitUnicodeString(&symLinkName,L"\\??\\HelloDDK");
        pDevExt->ustrSymLinkName = symLinkName;
        status = IoCreateSymbolicLink( &symLinkName,&devName );
        if (!NT_SUCCESS(status))
        {
            IoDeleteDevice( pDevObj );
            return status;
        }
        return STATUS_SUCCESS;
    }
    1. RtlInitUnicodeString

    2. IoCreateDevice

    NTSTATUS IoCreateDevice
    (
        IN PDRIVER_OBJECT DriverObject,
        IN ULONG DeviceExtensionSize,
        IN PUNICODE_STRING DeviceNameOPTIONAL,
        IN DEVICE_TYPE DeviceType,
        IN ULONG DeviceCharacteristics,
        IN BOOLEAN Exclusive,
        OUT PDEVICE_OBJECT *DeviceObject
    );
    • DriverObject:一个指向调用该函数的驱动程序对象.每一个驱动程序在它的DriverEntry过程里接收一个指向它的驱动程序对象.
    • DeviceExtensionSize:指定驱动程序为设备扩展对象而定义的结构体的大小.
    • DeviceName:(可选的参数)指向一个以零结尾的包含Unicode字符串的缓冲区,那是这个设备的名称,该字符串必须是一个完整的设备路径名.
    • DeviceType:指定一个由一个系统定义的FILE_DEVICE_XXX常量,表明了这个设备的类型
    • DeviceCharacteristics:指定一个或多个系统定义的常量,连接在一起,提供有关驱动程序的设备其他信息.对于可能的设备特征信息,见DEVICE_OBJECT结构体.
    • Exclusive:如果指定设备是独占的,大部分驱动程序设置这个值为FALSE,如果是独占的话设置为TRUE,非独占设置为FALSE.
    • DeviceObject:一个指向DEVICE_OBJECT结构体指针的指针,这是一个指针的指针,指向的指针用来接收DEVICE_OBJECT结构体的指针

        1) 前面我们创建的设备对象虽然有个参数指定了设备名称,但是这个设备名称只能在内核态可见,也就说ring3 的应用层程序是看不见它的,因此驱动程序需要向ring3 公布一个符号链接,这个链接指向真正的设备名称,而ring3 的应用程序可以通过该符号链接找到驱动程序进行通信。实际上我们经常所说的C 盘、D 盘就是一个符号链接,它们在内核中的真正设备对象是“\Device\HarddiskVolume1”和“\Device \HarddiskVolume2”。在内核模式下,符号链接是以“\??\”( 或“\DosDevices\”)开头的,如C 盘就是“\??\C:”,而在用户模式下,则是以“\.\”开头的,如C 盘就是“\.\C:”

    1.4 卸载驱动例程

    #pragma PAGEDCODE
    VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
    {
        PDEVICE_OBJECT pNextObj;
        KdPrint(("Enter DriverUnload\n"));
        pNextObj = pDriverObject->DeviceObject;//由驱动对象得到设备对象
    
        while (pNextObj != NULL)
        {
            PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
            pNextObj->DeviceExtension;
            //删除符号链接
            UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
            IoDeleteSymbolicLink(&pLinkName);
            //删除设备对象
            pNextObj = pNextObj->NextDevice;
            IoDeleteDevice( pDevExt->pDevice );
        }
    }

      卸载驱动例程是我们在DriverEntry 中自己定义的,当驱动被卸载时I/O管理器负责调用该例程,它主要做一些扫尾处理的工作。
      KdPrint:由于驱动程序工作于内核态,不像控制台的程序一样可以使用printf 输出一些信息,也不像Win32 程序可以通过MessageBox 来弹出一个对话框,它要想输出一些信息,就需要调用DbgPrint 函数,不过这个函数输出的信息我们无法直接看到,需要使用一些专门的工具,比如DbgView (KmdManager)等。
      有些内容我们只想在调试版输出,在发行版忽略,因此DDK 中定义了一个宏KdPrint,它在发行版不被编译,只在调试版才会运行。KdPrint是这样定义的:

    #define KdPrint(_x_) DbgPrint _x_ //在使用时最外层要有两个连续的括号。

    1.5 派遣例程

    #pragma PAGEDCODE
    NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj,IN PIRP pIrp)
    {
        KdPrint(("Enter HelloDDKDispatchRoutine\n"));
        NTSTATUS status = STATUS_SUCCESS;
        // 完成IRP
        pIrp->IoStatus.Status = status;
        pIrp->IoStatus.Information = 0; // bytes xfered
        IoCompleteRequest( pIrp, IO_NO_INCREMENT );
        KdPrint(("Leave HelloDDKDispatchRoutine\n"));
        return status;
    }

    派遣例程是处理IRP的。

    1.6 编译

    1. DDK方式
    2. VC方式:参见《VS2013 + WDK7.6搭建驱动开发环境》

    1.7 驱动安装

    用DriverStudio中的工具:DriverMonitor。

    2、WDM式驱动

    #pragma INITCODE
    extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,
    IN PUNICODE_STRING pRegistryPath)
    {
        KdPrint(("Enter DriverEntry\n"));
        pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice; //相比NT,此回调函数的作用是创建设备对象并由PNP管理器调用。
    ...
    }
    #pragma PAGEDCODE
    NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT PhysicalDeviceObject)
    {
        PAGED_CODE();
        KdPrint(("Enter HelloWDMAddDevice\n"));
    ...
    }
    • PAGED_CODE();//宏,只有check版本中有效,当此例程所在的中断请求超过APC_LEVEL时,会产生一个断言。
    • 对IRP_MN_REMOVE_DEVICE的处理,类似于NT式驱动中的卸载例程,而在WDM式驱动中,卸载例程几乎不做处理。

    2.1 编译:

    同NT

    2.2 安装:

    用EzDriverInstall安装或控制面版中添加硬件。

    3、小结

      实际上,常见的Windows 驱动程序是可以分成两类的:一类是不支持即插即用功能的NT 式驱动程序,另一类是支持即插即用的WDM 式驱动程序。NT 式驱动的安装是基于服务的,可以通过修改注册表进行,也可以直接通过服务函数如CreateService 进行安装;但WDM 式驱动不同,它安装的时候需要通过编写一个inf 文件进行控制。除此之外,它们所使用的头文件也不大相同,例如NT 式驱动往往需要导入一个名为“ntddk.h”的头文件,而WDM 式驱动需要的却是“wdm.h”头文件。我们在学习的过程中所编写的大多属于NT 式驱动,除非我们需要自己的设备支持即插即用,才需要考虑编写WDM 式驱动程序。

    展开全文
  • Windows驱动开发基础(五)驱动程序的数据结构

    Windows驱动开发基础:驱动程序的数据结构。转载请标明出处:http://blog.csdn.net/ikerpeng/article/details/38794405


    I/O管理器定义了一些数据结构,这些很重要。


    1. 驱动对象(DRIVER_OBJECT)


    通过一个typedef 定义的以一个struct:

    <span style="font-family:Microsoft YaHei;">typedef struct
    {
    PDEVICE_OBJECT DeviceObject; //指向驱动程序创建的设备对象</span>
    <span style="font-family:Microsoft YaHei;">UNICODE_STRING  Drivername // 驱动名称
    PUNICODE_STRING HardwareDatabase; //记录的是设备的硬件数据库名,这里同样用Unicode字符串记录
    PFAST_IO_DISPATCH FastIoDispatch;//文件驱动中用到的派遣函数
    PDRIVER_INITIALIZE DriverInit;//指向DriverEntry函数的,这是通过IO管理器来建立的。
    PDRIVER_STARTIO DriverStartIo;//记录StartIO例程的函数地址,用于串行化操作
    PDRIVER_UNLOAD DriverUnload;//指定驱动卸载时所用的回调函数地址
    PDRIVER_DISPATCH MajorFunction[IRP_MJ_NUM+1];//指向驱动程序的DispatchXXX函数指针的数组
    }DRIVER_OBJECT,*PDRIVER_OBJECT;指向驱动程序的DispatchXXX函数指针的数组</span>

     里面有一些重要的数据结构:


    DeviceObject: 设备对象,可能是一个或多个。由程序猿自己创建,驱动程序被卸载的时候,遍历每一个DriverObject并删除;

     

    DeviceName:设备名称,保存在Unicode字符串里面  

    HardwareDatabase:


    HardwareDatabase记录的是设备的硬件数据库名,这里同样用Unicode字符串记录。该字符串一般为HKEY_LOCAL_MACHINE\Hardware\DESCRIPTION\System,是一个注册表路径。
    FastIoDispatch:


    文件驱动中用到的派遣函数。指向这个驱动程序的FastIO入口点定义的一个结构。这个成员只能通过FSDs和网络传输驱动来使用。
    DriverInit:


    指向DriverEntry函数的,这是通过IO管理器来建立的。
    DriverStartIo:


    记录StartIO例程的函数地址,用于串行化操作,如果一个驱动程序没有StartIo函数,这个成员将是NULL。
    DriverUnload:


    指定驱动卸载时所用的回调函数地址,如果驱动程序没有卸载函数,这个成员将是NULL。
    MajorFunction[IRP_MJ_NUM+1]:


    指向驱动程序的DispatchXXX函数指针的数组。每个驱动程序至少要设置一个DispatchXXX函数指针在这个数组里来处理这个驱动程序IRP请求包。任何一个驱动程序可以设置和IRP_MJ_XXX代码一样多的DispatchXXX来处理IRP请求包.每个DispatchXXX结构如下:
    NTSTATUS DispatchXXX(IN PDEVICE_OBJECT DeviceObjec, IN PIRP Irp);


    2. 设备对象(DeviceObject):


    一张图理一下里面的成员的关系:

                                              

    每个驱动都会有设备对象,每一个设备对象都有一个指针指向下一个设备对象(最后一个为空)。结构体定义如下:

    <span style="font-family:Microsoft YaHei;">typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _DEVICE_OBJECT
    {
        CSHORT Type;
        USHORT Size;
        LONG ReferenceCount;
        /*指向驱动程序中驱动对象的指针*/
        struct _DRIVER_OBJECT *DriverObject;
        /*指向下一个设备对象的指针*/
        struct _DEVICE_OBJECT *NextDevice;
        struct _DEVICE_OBJECT *AttachedDevice;
        /*当前IRP结构*/
        struct _IRP *CurrentIrp;
        PIO_TIMER Timer;
        /*设备对象的特性标志*/
        ULONG Flags;
        ULONG Characteristics;
        _volatile PVPB Vpb;
        /*指向设备扩展对象的指针*/
        PVOID DeviceExtension;
        /*指明设备类型*/
        DEVICE_TYPE DeviceType;
        /*堆栈的最小层数*/
        CCHAR StackSize;
        union {
            LIST_ENTRY ListEntry;
            WAIT_CONTEXT_BLOCK Wcb;
        } Queue;
        /*内存对齐*/
        ULONG AlignmentRequirement;
        KDEVICE_QUEUE DeviceQueue;
        KDPC Dpc;
        /*
        *下列成员用于支持文件系统的互斥操作
        *以便对文件系统处理线程使用设备的计数保持跟踪
        */
        ULONG ActiveThreadCount;
        PSECURITY_DESCRIPTOR SecurityDescriptor;
        KEVENT DeviceLock;
     
        USHORT SectorSize;
        USHORT Spare1;
     
        struct _DEVOBJ_EXTENSION  *DeviceObjectExtension;
        PVOID  Reserved;
     
    } DEVICE_OBJECT;
    typedef struct _DEVICE_OBJECT *PDEVICE_OBJECT;</span>

    下面分别描述设备对象中驱动程序可访问成员的具体含义:


    PDRIVER_OBJECT DriverObject:指向驱动程序中的驱动对象。同属一个驱动程序的驱动对象指针都指向同一个驱动对象。

    PDEVICE_OBJECT NextDevice:指向下一个设备对象。这里的下一个设备对象是同一个驱动程序创建的若干设备对象中的一个。每个设备对象会根据

    NextDevice成员形成链表,从而遍历每个设备对象。在每次成功调用IoCreateDevice 后,I/O管理器就会更新该链表。当驱动被卸载时,需要遍历该链表,删除每个设备对象。


    PIRP CurrentIrp:如果驱动使用StartIO例程,此成员将指向当前的IRP结构,否则为NULL。


    ULONG Flags:此成员是一个32位的无符号整型变量,每个位有不同的含义。可通过按位取“或”操作为新创建的设备对象设置不同的特性。


    ULONG Characteristics:此成员说明设备对象的特性,当驱动程序调用IoCreate-Device时,可设置FILE_REMOVABLE_MEDIA(表示存储设备支持可移动介质)、FILE_READ_ONLY_DEVICE(表示设备不能写)、FILE_FLOPPY_DISKETTE(表示设备是软盘设备)等值。


    PVOID DeviceExtension:指向设备扩展对象。


    DEVICE_TYPE DeviceType:指明设备的类型,由IoCreateDevice设置,根据设备的需要填写相应的设备类型。


    CCHAR StackSize:在多层驱动的情况下,驱动与驱动之间形成类似堆栈的结构。IRP会依次从最高层传递到最底层。StackSize就是用于指定发送到该驱动的IRP在堆栈位置的最小层数的。IoCreateDevice在一个新创建的设备对象中设置该成员。


    ULONG AlignmentRequirement:进行数据传输的时候,规范设备的地址对齐


    其中的DeviceType:指明设备的类型,当作为一个虚拟的设备的时候选择:FILE_DEVICE_UNKNOWN.



    3. 设备扩展:


    设备对象记录的是通用的信息,而一些特殊的信息则要记录于设备扩展里面了。

    在驱动程序里面最好不要使用全局变量,这往往导致函数的不可重入性。将全局变量以设备扩展的形式存储,并加以保护措施,这样可以解决这个问题。


    参考文献:


    《Windows驱动开发技术详解》

    http://www.cnblogs.com/qintangtao/archive/2013/04/09/3009790.html

     
    展开全文
  • 文章简介 ...本文介绍了在 Windows 7 下手动删除驱动程序的方法。 安装网站下载的即插即用驱动程序前,建议先手动删除打印机驱动程序,然后再安装驱动程序。 适用机型 HP LaserJet 1018、HP LaserJe
  • 本篇文章将对PCIe驱动程序的源文件代码...整个WDF驱动程序工程共包含4个头文件(已经在上篇文章中讲解)和3个.c文件(Driver.c Device.c Queue.c) Driver.c 在看复杂的代码前,先给出程序流程图  
  • 搭建Windows驱动程序设计情况(Windows XP VC 6.0 WinXP_DDK DriverStudio 3.2) 研发windows内核驱动程序是一个非常具有挑战性的工作,你得忍耐调试过程中操作系统不断蓝屏、不断崩溃的噩梦,所以强烈建议你采用...
  • 一个PowerShell脚本,用于通过运行Windows 10的...用法从NVIDIA或AMD下载适用于您GPU的驱动程序包。 打开PowerShell,然后发出以下命令之一:PS> ./Remove-HypervisorChecks.ps1 -Nvidia -DriverPath“ path \ to \ dr
  • Windows系统出现“无法加载操作系统,原因是关键系统驱动程序丢失或包含错误”时解决方案解决方法:出现此问题的原因:注意: 有时Windows出现“无法加载操作系统,原因是关键系统驱动程序丢失或包含错误”,如下图...
  • Windows自动恢复报错:无法加载操作系统,原因是关键系统驱动程序丢失或包含错误 1. 问题 无法加载操作系统,原因是关键系统驱动程序丢失或包含错误 上午因为有点事就没有像往常一样打开电脑,下午回到家休息了一会...
  • Windows 2000内核模式驱动程序设计

    千次阅读 2007-07-04 09:27:00
    Windows 2000中,微软公司在Windows NT4.0的驱动程序结构基础上,同时引入了Windows9X的即插即入特性,推出了新的驱动程序结构模式(WDM)。WDM通过提供一种灵活的方式来简化驱动程序的开发,在实现对新硬件支持...
  • Display Driver Uninstaller是一个驱动程序删除实用程序,可以帮助您从系统中完全卸载AMD / NVIDIA / INTEL图形卡驱动程序程序包,尝试删除所有剩余的内容(包括注册表项,文件夹和文件,驱动程序存储)。...
  • WAIK: 离线安装Windows驱动程序

    千次阅读 2014-04-07 16:54:55
    方法一:通过dism命令注入 1.挂载WIM镜像: Dism /Mount-Wim /WimFile:install.wim /...2.删除之前安装的驱动: Dism /Image:mount /Remove-Driver /Driver:OEM1.inf /Driver:OEM2.inf ... /Driver:OEM99.inf 3.注
  • windows WDM驱动程序设计

    千次阅读 2011-12-05 19:56:39
    回顾微软10年,驱动开发模型从VxD->WDM->WDF,开发工具从VtoolsD-->DDK-->WDK,在这个过程中,出现了一些优秀的开发工具,windriver,driver studio 3.2 等。其中windriver适合用来调试硬件,driver studio 3.2 采用...
  • 卸载的时候,提示:windows Installer程序包有问题,....无法卸载。 解决办法: 1、删掉jdk安装文件和注册表信息 找到jdk1.6安装的目录,删除掉所有jdk1.6安装目录下的文件夹和文件(jdk和jre) 找到注册表,把...
  • 使用 WDF 框架构建的 Windows 内核模式类筛选器驱动程序 (KMDF)。 为每个输入输出键码 随附驱动程序安装程序应用程序 KeyboardTrapInstaller.exe 必须与打包文件在同一路径 以管理员身份安装...
  • 最近想对一个文件过滤驱动进行一下低资源测试,记得微软曾经提供了一个工具叫verifier的,可以对驱动进行各种测试,赶紧到网上搜查,终于找到了如下内容. 原文地址:...
  • 使用 WDF 框架构建的 Windows 内核模式类筛选器驱动程序 (KMDF)。 为每个鼠标反转滚轮 随附驱动程序安装程序应用程序 MouseTrapInstaller.exe 必须与打包文件在同一路径 以管理员身份安装“MouseTrapInstaller.exe...
  • 从零开始学习Windows WDF驱动程序开发

    千次阅读 2014-11-25 11:00:35
    摘要:本文通过简单的例子和精简的说明,带你快速了解和掌握基于WDF架构的Windows驱动程序的开发过程。WDF自带的文档非常详细而且冗长,读者需要一定的编程基础和英语水平,再加上一定的努力,才能看明白。而在网络...
  • 1·前言 开发windows内核驱动程序是一个非常具有挑战性的工作,你得忍耐调试过程中操作系统不断蓝屏、不断崩溃的噩梦,所以强烈建议你采用虚拟机做开发平台,这样即使把整个系统都搞蹦了,大不了从新装过虚拟机...
  • 在安装我的软件包之前,无论是经典 HDA 还是 UAD 格式,您都必须完全删除其他 Realtek 高清音频驱动程序,因为 Windows 偏爱具有更好硬件 ID 匹配的特定于硬件的驱动程序,即使比通用驱动程序旧。 请按照以下步骤...
  • 文章介绍了W indows设备驱动程序通过建立自定义I/O请求(IRP),并将IRP发送到文件系统驱动程序的方式,实现对文件的内核级操作的方法,该方法可实现文件建立、读、写、删除和改名等功能。文章给出了基于微软设备驱动...
  • 从或下载适用于您GPU的驱动程序包。 打开PowerShell并发出以下命令之一: PS > . / Remove-HypervisorChecks.ps1 - Nvidia - DriverPath " path\to\driver\package.exe " PS > . / Remove-HypervisorChecks.ps1 -...
  • 我觉得,做一个杀毒软件,大概要有以下的驱动程序。下面我给出了杀毒软件的大致设计框架。 由于一些事情的存在,程序代码暂时不上传到看雪论坛上,以免引起日后产生不必要的法律纠纷。这里还请各位朋友能够原谅。...
  • 彻底删除windos8 打印机驱动程序

    千次阅读 2014-09-11 14:51:48
    windows8 上彻底删除驱动程序是一件头病
  • Windows系统自动加载SATA驱动程序

    千次阅读 2007-01-11 10:30:00
    一直都想把驱动做到光盘或者硬盘上并让Windows安装程序自动加载,经过查资料和摸索,得出下面的方法: 安装Windows 2000/XP之类的基于NT内核的操作系统在RAID或SCSI或SATA硬盘上,它们的驱动程序必须在安装系统之前...
  • WindowsNT设备驱动程序开发基础

    千次阅读 2011-12-09 21:59:25
    一、背景介绍 1.1WindowsNT操作系统的组成 1.1.1用户模式(UserMode)与内核模式(KernelMode) ...运行于较低级别的代码不随意调用高级别的代码和访问较高级别的数据,而且也只有ring0层的代码可以直

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 99,711
精华内容 39,884
关键字:

windows驱动程序包能删除吗