精华内容
下载资源
问答
  • 内核驱动程序的是什么意思和一般意义上的驱动应该怎么理解好 我很疑惑,请教了
  • 使用设备树时,给驱动程序调用的过程 我们把设备树.dts 变成plantform_device的资源 过程一步步了解清楚 吃

    使用设备树时,给驱动程序调用的过程

    我们把设备树.dts 变成plantform_device的资源 过程一步步了解清楚
    在这里插入图片描述

    设备树中运行时配置启动信息的处理

    设备树只是起一个信息传递的作用,对这些信息配置的处理,也比较简单,即从设备树的DTB文件中,把这些设备信息提取出来赋给内核中的某个变量即可。
    1./chosen节点中bootargs属性就是内核启动的命令行参数,它里面可以指定根文件系统在哪里,第一个运行的应用程序是哪一个,指定内核的打印信息从哪个设备里打印出来。

    2./memory中的reg属性指定了不同板子内存的大小和起始地址。

    3.根节点的#address-cells和#size-cells属性指定属性参数的位数,比如指定前面memory中的reg属性的地址是32位还是64位,大小是用一个32位表示,还是两个32位表示。

    设备树中平台信息的处理(选择machinedesc)

    一个编译成uImage的内核镜像文件,可以支持多个单板,这里假设支持smdk2410、smdk2440、jz2440(其中smdk2410、smdk2440是厂家的公板,国内的厂家参考公板设计出了自己的板子,比如jz2440)。
    这些板子的配置稍有不同,需要做一些单独的初始化,在内核里面,对于这些单板,都构造了一个machinedesc结构体,里面有.init和.nr。 对于JZ2440,它源自smdk2440,内核没有它的单独文件,它使用smdk2440的相关文件,代码。 在上一节视频里面我们说过,以前uboot使用ATAGS给内核传参数时,它会传入一个机器ID,内核会使用这个机器ID找到最合适的machinedesc。即机器ID与machine_desc里面的.nr比较,相等就表示找到了对应的machinedesc。 当我们的uboot不使用ATAGS传参数,而使用DTB文件时,那么这时内核是如何选择对应的machinedesc呢? 在设备树文件的根节点里,有如下两行:

    c model = "SMDK24440"; compatible = "samsung,smdk2440""samsung,smdk24140""samsung,smdk24xx";
    

    这里的compatible属性声明想要什么machinedesc,属性值可以是一系列字符串,依次与machinedesc匹配。 内核最好支持samsung,smdk2440,如果不支持,再尝试是否支持samsung,smdk24140,再不支持,最后尝试samsung,smdk24xx

    a. 设备树根节点的compatible属性列出了一系列的字符串, 表示它兼容的单板名,从"最兼容"到次之;
    b. 内核中有多个machinedesc, 其中有dtcompat成员, 它指向一个字符串数组, 里面表示该machine_desc支持哪些单板;

    c. 使用compatile属性的值, 跟’’‘每一个machinedesc.dtcompat’’'比较, 成绩为"吻合的compatile属性值的位置", 成绩越低越匹配, 对应的machine_desc即被选中

    dtb转换为devicenode

    在dts文件里,每个大括号{ }代表一个节点,比如根节点里有个大括号,对应一个devicenode结构体;memory也有一个大括号,也对应一个devicenode结构体。 节点里面有各种属性,也可能里面还有子节点,所以它们还有一些父子关系。 根节点下的memory、chosen、led等节点是并列关系,兄弟关系。 对于父子关系、兄弟关系,在device_node结构体里面肯定有成员来描述这些关系。

    打开include/linux/Of.h可以看到devicenode结构体的定义如下:
    struct devicenode { const char *name; // 来自节点中的name属性, 如果没有该属性, 则设为"NULL"
    const char *type; // 来自节点中的device_type属性, 如果没有该属性, 则设为"NULL"
    phandle phandle;
    const char *fullname; // 节点的名字, node-name[@unit-address] struct fwnodehandle fwnode;

    struct  property *properties;  // 节点的属性
            struct  property *deadprops;    /* removed properties */
            struct  device_node *parent;   // 节点的父亲
            struct  device_node *child;    // 节点的孩子(子节点)
            struct  device_node *sibling;  // 节点的兄弟(同级节点)
        #if defined(CONFIG_OF_KOBJ)
            struct  kobject kobj;
        #endif
            unsigned long _flags;
            void    *data;
        #if defined(CONFIG_SPARC)
            const char *path_component_name;
            unsigned int unique_id;
            struct of_irq_controller *irq_trans;
        #endif
        };
    

    把device_node 转换成planfrom_device

    哪些device_node可以转换为plantfrom_device?

    a.根节点下含有compatile属性的子节点
    b.除了根节点的子节点外,子节点的子节点里compatile属性里有特殊值(“simple-bus”,“simple-mfd”,“isa”,“arm,amba-bus”)之一,那么子节点的子节点可以转换为plantform_device
    c.i2c,spi已经转化为plantform_device,所以他们的子节点应该被,总线drv的probe来调用

    eg1:

    /dts-v1/;
    
    /memreserve/ 0x33f00000 0x100000;
    
    / {
    	model = "SMDK24440";
    	compatible = "samsung,smdk2440";
    
    	#address-cells = <1>;
    	#size-cells = <1>;
    		
    	memory {  /* /memory */
    		device_type = "memory";
    		reg =  <0x30000000 0x4000000 0 4096>;		
    	};
    
    	
    /*
    	cpus {
    		cpu {
    			compatible = "arm,arm926ej-s";
    		};
    	};
    */	
    	chosen {
    		bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200";
    	};
    
    	
    	led {
    		compatible = "jz2440_led";
    		pin = <S3C2410_GPF(5)>;
    	};
    };
    

    上面只有led节点有compatbile属性,他被转化为drv

    怎么转换device_node 变成planfrom_device

    a. platform_device中含有resource数组, 它来自device_node的reg, interrupts属性;
    b. platform_device.dev.of_node指向device_node, 可以通过它获得其他属性(我们自定义比如pin)
    eg:

     / {
              mytest {
                  compatile = "mytest", "simple-bus";
                  mytest@0 {
                        compatile = "mytest_0";
                  };
              };
              
              i2c {
                  compatile = "samsung,i2c";
                  at24c02 {
                        compatile = "at24c02";                      
                  };
              };
    
              spi {
                  compatile = "samsung,spi";              
                  flash@0 {
                        compatible = "winbond,w25q32dw";
                        spi-max-frequency = <25000000>;
                        reg = <0>;
                      };
              };
          };
    

    /mytest会被转换为platform_device,
    因为它兼容"simple-bus", 它的子节点/mytest/mytest@0 也会被转换为platform_device

    /i2c节点一般表示i2c控制器, 它会被转换为platform_device, 在内核中有对应的platform_driver;
    /i2c/at24c02节点不会被转换为platform_device, 它被如何处理完全由父节点的platform_driver决定, 一般是被创建为一个i2c_client。

    类似的也有/spi节点, 它一般也是用来表示SPI控制器, 它会被转换为platform_device, 在内核中有对应的platform_driver;
    /spi/flash@0节点不会被转换为platform_device, 它被如何处理完全由父节点的platform_driver决定, 一般是被创建为一个spi_device。

    platform_device跟platform_driver的匹配

    当我们把设备树文件转换为dev时,就能进行drv的匹配
    在这里插入图片描述
    比较的优先顺序:
    a. 比较 platform_dev.driver_override 和 platform_driver.drv->name
    b. 比较 platform_dev.dev.of_node的compatible属性 和 platform_driver.drv->of_match_table
    c. 比较 platform_dev.name 和 platform_driver.id_table
    d. 比较 platform_dev.name 和 platform_driver.drv->name
    有一个成功, 即匹配成功

    在根文件系统查看设备树(有助于调试)

    a. /sys/firmware/fdt // 原始dtb文件

    对这个文件使用命令

    hexdump -C /sys/firmware/fdt
    

    可以查看到原始的dtb文件
    在这里插入图片描述

    b. /sys/firmware/devicetree

    以目录结构程现的dtb文件, 根节点对应base目录, 每一个节点对应一个目录, 每一个属性对应一个文件
    同样用命令hexdump -C ./led 进行查看
    在这里插入图片描述

    /sys/devices/platform

    系统中所有的platform_device, 有来自设备树的, 也有来有.c文件中注册的
    对于来自设备树的platform_device,
    可以进入 /sys/devices/platform/<设备名>/of_node 查看它的设备树属性

    在这里插入图片描述

    /proc/device-tree

    /proc/device-tree 是链接文件, 指向 /sys/firmware/devicetree/base
    在这里插入图片描述

    展开全文
  • 在上一篇文章中提到了 Windows Vista 及之后版本的 Windows 操作系统在驱动程序加载完成后,驱动中调用的一些系统回调函数(如 ObRegisterCallbacks,可用来监控系统中进线程句柄的操作,如打开进程、复制线程句柄...

        转自:小刀志

        

    在上一篇文章中提到了 Windows Vista 及之后版本的 Windows 操作系统在驱动程序加载完成后,驱动中调用的一些系统回调函数(如 ObRegisterCallbacks,可用来监控系统中对进线程句柄的操作,如打开进程、复制线程句柄等)等 API 中会通过 MmVerifyCallbackFunction 函数对该驱动程序进行完整性检查,检测未通过则会返回 0xC0000022 拒绝访问的返回值。在这篇文章中将会对这个函数进行简单的分析,以明确其原理。

    0x0 获取函数地址

    通过 Windbg 连接 64 位的 Windows 7 SP1 虚拟机,并通过 u nt!MmVerifyCallbackFunction 命令得到该函数的基地址。接下来使用 lm 命令获得 nt 内核模块的基地址,通过与前面的函数首地址相减得到函数的地址偏移 4700B0。

    在 IDA 中加载 64 位 Windows 7 SP1 的 ntoskrnl.exe 文件并指定 pdb 文件,在 IDA View-A 页面中定位到前面获得的函数地址偏移位置 PAGE:00000001404700B0,即定位到该函数所在。


    0x1 简单分析

    如果 pdb 文件正确加载的话会在 IDA View-A 页面中看到 IDA 已正确识别该函数的名称符号。通过 IDA 获得初步的 C 代码,对其进行一些修正后得到下述代码。

    ULONG64 __fastcall MmVerifyCallbackFunction(PVOID pAddr)
    {
      PVOID    address;  // rsi@1
      ULONG64  result;   // rax@2
      PVOID    thread;   // rbx@3
      BOOLEAN  status;   // edi@3
      PVOID    ldrentry; // rax@3
      bool     disable;  // zf@6
    
      address = pAddr;
      if ( (ULONG64)(pAddr + 0x70000000000) > 0x7FFFFFFFFF )
      {
        thread = *MK_FP(__GS__, 0x188);  // get _ETHREAD pointer from KPCR
        --*(WORD *)(thread + 0x1C4);     // Disable Kernel APCs // Thread->KernelApcDisable--;
        status = FALSE;
        ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE);
        ldrentry = MiLookupDataTableEntry(address, TRUE);
        if ( ldrentry && *(BYTE *)(ldrentry + 0x68) & 0x20 )
          status = TRUE;
        ExReleaseResourceLite(&PsLoadedModuleResource);
        disable = (*(WORD *)(thread + 0x1C4))++ == -1;  // Enable Kernel APCs // Thread->KernelApcDisable++;
        // 1. Thread->KernelApcDisable == -1 before ++;
        // 2. EThread->ApcState->ApcListHead does not point to itself;
        // 3. EThread->SpecialApcDisable == 0;
        // means KernelApc/SpecialApc enabled && ApcList not empty now.
        if ( disable && *(QWORD *)(thread + 0x50) != thread + 0x50 && !*(WORD *)(thread + 0x1C6) )
          KiCheckForKernelApcDelivery();
        result = (ULONG)status;
      }
      else
      {
        result = FALSE;
      }
      return result;
    }

    0x2 代码解释

    首先是判断传入地址参数的有效性。为了更精确地理解 if ( (ULONG64)(pAddr + 0x70000000000) > 0x7FFFFFFFFF ) 这行语句执行的操作和作用,下面贴出其汇编指令代码。

    mov     rax, 70000000000h
    mov     rsi, rcx
    add     rax, rcx
    mov     rcx, 7FFFFFFFFFh
    cmp     rax, rcx
    ja      nt!MmVerifyCallbackFunction+0x3c

    其中 rcx 初始值是传入的地址参数的值。开始时并未明确这几行指令代码这样判断的目的是什么,通过 Windbg 跟踪 PsSetCreateProcessNotifyRoutineEx 等 API 函数对 MmVerifyCallbackFunction 的调用,发现 ecx 都是 0xfffff8800373c620 之类正常的地址数值,通过和 0x70000000000 相加得到的值 0xffffff800373c620 也远大于 0x7FFFFFFFFF 这个比较小的数。

    后经过计算得知,相加后的值在此处只有在一种情况才会小于 0x7FFFFFFFFF 值。地址参数是个 ULONG64 长度的数字,其值位于 [0xFFFFF900`00000000, 0xFFFFF97F`FFFFFFFF] 区间时,相加后的数值对 ja 条件成立,函数跳转到检测失败并返回的位置。后通过查阅资料得知,在 64 位 Windows 操作系统中,该地址空间区间范围正是内核地址空间中的会话空间(Session Space)。

    Session Space
    Session Data Structures, Session Pool and Session Images are loaded in this area.
    The session image space contains driver images like Win32K.sys (Window Manager), CDD.DLL (Canonical Display Driver), TSDDD.dll (Frame Buffer Display Driver), DXG.sys (DirectX Graphics Driver) etc.
    For any process that belongs to a session the field EPROCESS->Session points to a MM_SESSION_SPACE structure for that session. Session paged pool limits are pointed to by MM_SESSION_SPACE->PagesPoolStart and MM_SESSION_SPACE->PagesPoolEnd.

    在判断地址参数的有效性之后,首先通过 EThread->KernelApcDisable 禁用 Normal Kernel APC。GS 寄存器存储当前 CPU 核心的 _KPCR 结构地址。当前线程 EThread 地址位于 KPCR->Prcb->CurrentThread 位置,根据偏移 +0x188 获取到 EThread 的地址。对偏移为 0x1C4 的 EThread->KernelApcDisable 进行累减运算操作。

    在 EThread 结构中有个 ApcState 域,以及 KernelApcDisable 和 SpecialApcDisable 域。

    KernelApcDisable 和 SpecialApcDisable 域可以合并成一个 CombinedApcDisable 域,两者都是 16 位的整数值,0 表示不禁止 APC,负数表示禁止 APC。一个线程在执行过程中可以有多种因素要禁止 APC,这些因素以负值来表示,并累加起来,当因素消除的时候再减去相应的负值。

    只有当 KernelApcDisable 或 SpecialApcDisable 为 0 的时候,该线程才允许插入或提交 APC。这两个值分别控制普通的内核 APC 和特殊的内核 APC。

    ApcState 是一个结构成员,指定了一个线程的 APC 信息,包括 APC 链表、是否正在处理 APC 或者是否有内核 APC 或用户 APC 正在等待等信息。APC 链表头指针 ApcListHead 位于其结构第一个成员位置。

    为调用线程的共享读访问请求指定的资源。PsLoadedModuleResource 是一个 ERESOURCE 结构体数据类型的全局变量,在 MiInitializeLoadedModuleList 函数中初始化。通过 ExAcquireResourceSharedLite 函数请求 PsLoadedModuleResource 系列资源的读访问权限。根据 MSDN 上的描述,调用该函数之前必须禁用 Normal Kernel APC。直到资源释放之前,APC 投递必须保持禁用状态。以下是该函数的声明。

    BOOLEAN 
    ExAcquireResourceSharedLite(
      _Inout_ PERESOURCE Resource,
      _In_    BOOLEAN    Wait
    );

    ERESOURCE 结构类型是 Windows 操作系统内核中的读写锁对象类型。通过它和一系列的 Resource 例程可以实现同时只有一个 Writer 写入,多个 Reader 读访问的机制。

    详细信息:http://msdn.microsoft.com/en-us/library/windows/hardware/ff544363(v=vs.85).aspx

    在对指定资源的读访问请求完成后,通过 MiLookupDataTableEntry 函数对 PsLoadedModuleList 指针指向的已加载的内核模块链表进行遍历。MSDN 和其他文档中没有查到有关这个函数的定义信息,以下函数定义是通过 IDA 逆向 ntoskrnl.exe 推测得到的。其中的第二个参数 BOOLEAN bAcquiredResource 表示当前调用环境是否已获取到前述的系列资源的读访问权限,如果传入 FALSE 则在该函数内部会调用 ExAcquireResourceSharedLite 函数进行这些资源的读访问权限的获取。

    PLDR_DATA_TABLE_ENTRY
    NTAPI
    MiLookupDataTableEntry(
      IN PVOID Address, 
      IN BOOLEAN bAcquiredResource
    );
    PsLoadedModuleList 是一个 PLDR_DATA_TABLE_ENTRY 类型的全局指针,指向当前内核中已加载的内核模块的 LDR_DATA_TABLE_ENTRY 环形链表的第一个节点。每个节点是一个 LDR_DATA_TABLE_ENTRY 类型的结构体对象。以下是在 Windows 7 x64 SP1 操作系统环境下该结构体的数据类型定义。

    typedef struct _LDR_DATA_TABLE_ENTRY
    {
        LIST_ENTRY InLoadOrderLinks;
        LIST_ENTRY InMemoryOrderLinks;
        LIST_ENTRY InInitializationOrderLinks;
        PVOID DllBase;
        PVOID EntryPoint;
        ULONG SizeOfImage;
        UNICODE_STRING FullDllName;
        UNICODE_STRING BaseDllName;
        ULONG Flags;
        UINT16 LoadCount;
        UINT16 TlsIndex;
        union
        {
            LIST_ENTRY HashLinks;
            struct
            {
                PVOID SectionPointer;
                ULONG CheckSum;
            };
        };
        union
        {
            ULONG TimeDateStamp;
            PVOID LoadedImports;
        };
        PVOID EntryPointActivationContext;
        PVOID PatchInformation;
        LIST_ENTRY ForwarderLinks;
        LIST_ENTRY ServiceTagLinks;
        LIST_ENTRY StaticLinks;
        PVOID ContextInformation;
        ULONG_PTR OriginalBase;
        LARGE_INTEGER LoadTime;
    } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

    在 MiLookupDataTableEntry 函数中遍历链表时,通过结构体成员 DllBase 和 SizeOfImage 判断 Address 参数是否在该内核模块地址区间范围内。如果命中,则返回该 LDR_DATA_TABLE_ENTRY 链表节点的地址指针。

    在 MiLookupDataTableEntry 函数返回后,ldrentry 变量取得对应内核模块的 LDR_DATA_TABLE_ENTRY 指针。判断 lprentry + 0x68 位置的 BYTE 类型的数据是否对 0x20 标志位置位。通过上面的 LDR_DATA_TABLE_ENTRY 结构体定义发现,0x68 位置是 ULONG Flags 成员。该成员存储一些对应内核模块的属性标志。

    判断为真则赋值 status = TRUE,其在后面会用来赋值 result 并作为 MmVerifyCallbackFunction 函数的返回值。那么到现在可知该函数的关键判定就是在这一步了。如果在调用该函数之前就将对应的内核模块 LDR_DATA_TABLE_ENTRY 节点的 Flags 的 0x20 标志位置位,则会得到 MmVerifyCallbackFunction 函数校验通过的结果,达到绕过强制签名校验的目的。

    在判断标志位之后,函数会执行一些诸如资源权限释放、恢复 Normal Kernel APC、Kernel APC 投递检查并继续投递等操作。具体可以参考前面部分的内容,代码的注释已经写清楚。

    具体的验证可以通过 Windbg 跟一下。

    现在回想在编译链接驱动程序的时候,在 sources 文件中可选添加的 LINKER_FLAGS=/INTEGRITYCHECK 链接标记,其实就是给生成的 sys 文件的 PE 文件头中对应的 Flags 数据置位 0x20 标志位。

    0x3 备注

    文章中对部分 Windows 操作系统内核结构的解释参考自《Windows内核原理与实现(潘爱民著)》一书。

    ====================================================================================================

    博主后记:

        博主同样遇到了调用PsSetCreateProcessNotifyRoutineEx注册回调失败的情况。失败的机器运行在"Test Mode"下,并处于被调试状态。原作者可能遗漏了对这种情况的说明。下面分类说明:

    1.编译过程中不加/INTEGRITYCHECK标志。x64位调试机在Test Mode下可以加载驱动,但调用PsSetCreateProcessNotifyRoutineEx后失败;

    2.编译过程中添加加/INTEGRITYCHECK标志。x64位调试机在Test Mode下可以加载驱动,调用PsSetCreateProcessNotifyRoutineEx成功

    原因分析:

    出现上述原因正如MSDN所说:

    "If a kernel debugger is attached to the computer, Code Integrity still checks for a digital signature on every kernel-mode driver, but the operating system will load the drivers."(如果内核调试器已经附加到调试机,虽然OS仍会对每个驱动进行"Code Integrity"检测,但是OS仍会加载驱动)。因此出现了情况1.


    展开全文
  • 之前写了一篇移植2.4寸TFT驱动到树莓派的文章,那篇博文中的驱动代码是国外大牛写的,看了一下,还是有很多地方没理解,是得好好再学习一下内核驱动的编写,这里就从字符设备驱动开始,采用最简单的LED驱动来建立内核驱动...

            之前写了一篇移植2.4寸TFT驱动到树莓派的文章,那篇博文中的驱动代码是国外大牛写的,看了一下,还是有很多地方没理解,是得好好再学习一下内核驱动的编写,这里就从字符设备驱动开始,采用最简单的LED驱动来建立内核驱动移植的驱动框架.

           个人原创,转载请注明原文出处:      

                    http://blog.csdn.net/embbnux/article/details/17712547

          参考文章:

                    http://blog.csdn.net/hcx25909/article/details/16860725

          内核驱动与普通单片机模块驱动的差别就是在于,写内核驱动的时候,要提供内核调用的接口,使内核能找到相应的驱动入口,用户通过告诉内核要干嘛,内核再去调用那个驱动,驱动的最底层和单片机模块是一样的,同样是对GPIO的操作,配置输入输出,以及某些特殊的寄存器. LED的点亮就是对GPIO的操作 .

           对于ARM的GPIO调用需要通过IO映射的方法,要操作内存上对应的地址.

           对于bcm2708上的io对应关系,可以查看bcm2835的手册,和stm32基本上是一样的,因为同为ARM体系:

                  

         我参考的那博客讲这个比较清楚,可以参考下,由于树莓派的内核以及很好的提供了GPIO调用的接口,即把内存操作封装了很好,这里就不像那篇博客那样再自己写函数通过内存操作来进行GPIO操作,觉得有点麻烦,但是对于学好底层很有用.

      一  首先上个驱动程序


            这里直接把该程序添加到内核的源码目录里面,也可在自己的目录下,但是要写Makefile.

            在/drivers/char/新建rasp_led.c,内核中的kconfig文件和makefile文件,参照前一篇文章

     led.c:

    /********************************************************************/
    /***************Rasp led 驱动程序************************************/
    /***************作者: Embbnux Ji*************************************/
    /***************博客: http://blog.csdn.net/embbnux/ *****************/
    /********************************************************************/
    
    #include <linux/kernel.h>  
    #include <linux/module.h>
    #include <linux/device.h> 
    #include <mach/platform.h>       
    #include <linux/platform_device.h>
    #include <linux/types.h>  
    #include <linux/fs.h>   
    #include <linux/ioctl.h>  
    #include <linux/cdev.h>  
    #include <linux/delay.h>  
    #include <linux/uaccess.h>
    #include <linux/init.h> 
    #include <linux/gpio.h>
    
    #define DEVICE_NAME "Pi_Led"
    #define DRIVER_NAME "pi_led"
    
    //class声明内核模块驱动信息,是UDEV能够自动生成/dev下相应文件
    static dev_t pi_led_devno; //设备号
    static struct class *pi_led_class;
    static struct cdev pi_led_class_dev;
    
    struct gpio_chip *gpiochip;
    
    #define led_pin 4  //gpio 4
    
    //这部分函数为内核调用后open的设备IO操作,和裸板程序一样
    int open_flag=0;
    static int pi_led_open(struct inode *inode, struct file *filp)  
    {   
        printk("Open led ing!\n");  
        if(open_flag ==0){
           open_flag =1;
           printk("Open led success!\n");
           return 0;
        }
        else{
           printk("Led has opened!\n");     
        }
        return 0;  
    } 
    //这部分函数为内核调用后ioctl的设备IO操作,和裸板程序一样
    static long pi_led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 
    {  
        switch(cmd){
          case 0: 
              gpiochip->set(gpiochip, led_pin, 0);
                printk("Led  up!\n");
               break;
          case 1:
                gpiochip->set(gpiochip, led_pin, 1);
                printk("Led  down!\n");
               break;
        }
       
       
        return 0;
    } 
    
    static int pi_led_release(struct inode *inode,struct file *file){
         printk("Led has release!\n");
         return 0;
    }
    
    //file_operations使系统的open,ioctl等函数指针指向我们所写的led_open等函数,
    //这样系统才能够调用
    static struct file_operations pi_led_dev_fops = {  
       .owner          =THIS_MODULE,  
       .open	   =pi_led_open, 
       .unlocked_ioctl = pi_led_ioctl, 
       .release       = pi_led_release,
    }; 
    
    static int is_right_chip(struct gpio_chip *chip, void *data)
    {
    
    	if (strcmp(data, chip->label) == 0)
    		return 1;
    	return 0;
    }
    
    //内核加载后的初始化函数.
    static int __init pi_led_init(void)
    {
       struct device *dev;
       int major; //自动分配主设备号
       major = alloc_chrdev_region(&pi_led_devno,0,1,DRIVER_NAME);
       //register_chrdev 注册字符设备使系统知道有LED这个模块在.
       
       cdev_init(&pi_led_class_dev, &pi_led_dev_fops);
       major = cdev_add(&pi_led_class_dev,pi_led_devno,1);
       //注册class
       pi_led_class = class_create(THIS_MODULE,DRIVER_NAME);
       
       dev = device_create(pi_led_class ,NULL,pi_led_devno,NULL,DRIVER_NAME);
       
       gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
       gpiochip->direction_output(gpiochip, led_pin, 1);
       gpiochip->set(gpiochip, led_pin, 0);
       printk("pi led init ok!\n");
       return 0;
    }
    //内核卸载后的销毁函数.
    void pi_led_exit(void)
    {
       gpio_free(led_pin);
       device_destroy(pi_led_class,pi_led_devno);
       class_destroy(pi_led_class);
       cdev_del(&pi_led_class_dev);
       unregister_chrdev_region(pi_led_devno, 1);
       printk("pi led exit ok!\n");
       
    }
    
    module_init(pi_led_init);
    module_exit(pi_led_exit);
    
    MODULE_DESCRIPTION("Rasp Led Driver");
    MODULE_AUTHOR("Embbnux Ji < http://blog.csdn.net/embbnux >");
    MODULE_LICENSE("GPL");


    二  源码框架分析


        我们首先从内核模块的入口,module_init(pi_led_init)这个函数看起,可以看出初始化后调用pi_led_init这个函数.

       

    //内核加载后的初始化函数.
    static int __init pi_led_init(void)
    {
       struct device *dev;
       int major; //自动分配主设备号
       major = alloc_chrdev_region(&pi_led_devno,0,1,DRIVER_NAME);
       //register_chrdev 注册字符设备使系统知道有LED这个模块在.
       
       cdev_init(&pi_led_class_dev, &pi_led_dev_fops);
       major = cdev_add(&pi_led_class_dev,pi_led_devno,1);
       //注册class
       pi_led_class = class_create(THIS_MODULE,DRIVER_NAME);
       
       dev = device_create(pi_led_class ,NULL,pi_led_devno,NULL,DRIVER_NAME);
       
       gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
       gpiochip->direction_output(gpiochip, led_pin, 1);
       gpiochip->set(gpiochip, led_pin, 0);
       printk("pi led init ok!\n");
       return 0;
    }
       初始化时首先分配给这个函数设备号,注册该设备,通过class注册使能够在/dev/目录下自动生成相应的设备文件,用户通过操作这个文件,来告诉内核怎么做.

       由于是字符设备,所以对该文件的操作通过open,write,ioctl等函数,所以要把这个函数和底层的操作函数对应起来,这就要用到file_operation这个结构体,来声明:

      

    //file_operations使系统的open,ioctl等函数指针指向我们所写的led_open等函数,
    //这样系统才能够调用
    static struct file_operations pi_led_dev_fops = {  
       .owner          =THIS_MODULE,  
       .open	   =pi_led_open, 
       .unlocked_ioctl = pi_led_ioctl, 
       .release       = pi_led_release,
    };

        这里就让open函数对应到pi_led_open函数,ioctl函数对应到pi_led_ioctl函数;

        然后我们就只需要编写相应的pi_led_open以及pi_led_ioctl;这些函数里面的操作就是最底层的GPIO操作,和单片机是一样的.


    三  GPIO操作

         内核里面的GPIO操作函数,被定义在#include <linux/gpio.h>,这个头文件里面,树莓派官方做好了树莓派的GPIO在内核里面的注册,所以调用gpio.h里面的函数即可进行树莓派的GPIO操作.

        

    gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
        通过上面这个函数把内核的GPIO操作和BCM2708的GPIO操作关联起来;

         bcm2708的操作可以查看/arch/arm/mach-bcm2708/bcm2708_gpio.c文件,具体也是对内存地址的操作:

     

    #define GPIOFSEL(x)  (0x00+(x)*4)
    #define GPIOSET(x)   (0x1c+(x)*4)
    #define GPIOCLR(x)   (0x28+(x)*4)
    #define GPIOLEV(x)   (0x34+(x)*4)
    #define GPIOEDS(x)   (0x40+(x)*4)
    #define GPIOREN(x)   (0x4c+(x)*4)
    #define GPIOFEN(x)   (0x58+(x)*4)
    #define GPIOHEN(x)   (0x64+(x)*4)
    #define GPIOLEN(x)   (0x70+(x)*4)
    #define GPIOAREN(x)  (0x7c+(x)*4)
    #define GPIOAFEN(x)  (0x88+(x)*4)
    #define GPIOUD(x)    (0x94+(x)*4)
    #define GPIOUDCLK(x) (0x98+(x)*4)

        这里定义的就是相应的GPIO寄存器的地址.

    四  测试程序

        ssh进入树莓派,在主目录下新建led.c

        

     #include<stdio.h>
     #include <stdlib.h>
     #include <unistd.h>
     #include <sys/ioctl.h>
     #include <sys/time.h>
     int main(int argc, char **argv)
     {
        int on;
        int led_no;
        int fd;
        int i;
    
        fd = open("/dev/pi_led", 0);
        if (fd < 0) {
           fd = open("/dev/pi_led", 0);
        }
        if (fd < 0) {
          perror("open device led");
          exit(1);
        }
        for(i=0;i<=20;i++){
          on = i%2;
          ioctl(fd, on, led_no);
          sleep(1);
        }
        close(fd);
        return 0;
     }
    
    




    展开全文
  • Linux内核驱动程序

    千次阅读 2016-06-05 06:43:01
    本文译自Linux.orgDevynCJohnson的系列文章... 在上一篇文章Linux内核:源代码中我们探讨了源代码的组成结构以及各个部分的功能,今天我们来介绍一下Linux的驱动驱动是使内核能够与硬件或协议进行通信或控制的程

    本文译自Linux.orgDevynCJohnson的系列文章《Linux内核》,本篇链接:http://www.linux.org/threads/the-linux-kernel-drivers.4205/,转载请注明出处及原作者。

    在上一篇文章Linux内核:源代码中我们探讨了源代码的组成结构以及各个部分的功能,今天我们来介绍一下Linux的驱动。

    驱动是使内核能够与硬件或协议进行通信或控制的程序。如果没有驱动,内核无法与硬件或是协议进行通信(实际上,内核将指令发给BIOS,然后再由BIOS发给硬件)。Linux的内核代码在driver文件夹中包含了许多驱动程序。本文将逐一介绍driver文件夹中的驱动程序。理解驱动程序对于配置和编译内核是很有意义的。否则用户有可能在他们的内核中加入了不需要的驱动,或者是遗漏了重要的驱动程序。驱动的源代码中通常都会在注释中说明这个驱动的用途。例如,tc驱动的源代码就有一行的注释说明,这个驱动是用于TURBOchannel总线[1]的。用户可以通过阅读驱动程序的文档来了解该驱动的用途。

    在介绍各种驱动程序之前,我们先来介绍一些术语:
    - I/O设备是指输入/输出设备,例如调制解调器和网卡就属于输入输出设备。显示器属于输出设备,键盘鼠标以及游戏手柄属于输入设备。
    - 存储设备存储数据,诸如SD卡,硬盘,CD,存储卡等等。
    - CPU也被称为处理器,是计算机的大脑和心脏。如果没有了CPU,计算机将无法工作。
    - 主板是一块连接各种硬件的印刷电路板,主板及其组件对于计算机也是十分重要的。许多计算机用户也将主板称为计算机的核心。主板上还集成了外设端口。外设包括输入设备,输出设备,以及存储设备。
    - 总线是指将主板与外设连接起来的电路。
    - 网络设备将两台或以上的计算机连接起来。
    - 端口是用户可以插入外设或者线缆的设备,例如用户可以将FireWire记忆棒插入FireWire端口,以太网电缆插入以太网端口。
    - 32/64位系统,是指寄存器,地址总线以及数据总线的位数,以64位的主板为例,数据总线为64位线宽。
    - 内存地址是指以位的形式存在的指向内存中的地址,所以32位的内存地址使用了32位来描述某一个点在内存中存储的位置。

    许多驱动都是通用驱动,以通用键盘驱动为例,安装了通用键盘驱动的内核几乎可以使用所有的键盘。然而有些驱动则是专用的,例如Apple和Commodore就在他们的计算机或者系统中拥有专用驱动。Linux内核包含了诸如智能手机,Apple设备,Amigaxitong,Sony PlayStation 3,Andriod 平板电脑之类的驱动。

    有些驱动程序属于多种驱动类型,例如音频驱动在net文件夹和media文件夹中都存在。
    accessibility - 无障碍设备驱动
    acpi - 高级组态及能源界面,负责管理电源
    amba - 高级微处理器总线结构(AMBA),是一种运行在单片机系统(SoC)上的管理与协作协议。单片机是一种单个芯片包含多数或全部计算机必须组建的芯片。该文件夹中的驱动程序允许内核在SoC上运行。
    ata - 该文件夹中的驱动支持PATA和SATA设备,SATA是一种计算机总线界面,它负责将诸如硬盘的存储设备与主机总线适配器连接。PATA则是连接硬盘,软盘以及光驱在内的存储设备,PATA也被称为IDE。
    atm - 异步传送模式(ATM)是一种电信标准,在这个文件夹中有各种各样的总线来驱动PCI桥(他们与PCI总线连接)以及以太网控制器(以太网通信通过集成电路芯片控制)。
    auxdisplay - 该文件夹中包括三种驱动:LCD帧缓冲,LCD控制以及LCD驱动。他们都是液晶显示器(LCD)的驱动程序。
    base - 这个文件夹中包含了一些重要的驱动:组件,系统总线,虚拟机程序管理等等。
    bcma - 由Broadcom制作,基于AMBA协议的一些总线的驱动。
    block - 块设备驱动。
    bluetooth - 蓝牙驱动。
    bus - 包括三个驱动:ocp端口协议到scp协议转换驱动,设备间通信驱动,以及设备间通信纠错驱动。
    cdrom - 包括两个驱动:一个是CD驱动,包括读写DVD和CD。 另一个是GD驱动,GD是指GB级别只读存储,一张GD的容量为1.2GB,介于CD和DVD容量之间。
    char - 字符设备驱动,字符设备每次传输一个字符的数据,例如打印机。
    clk - 系统时钟驱动。
    clocksource - 允许将时钟用作计时器。
    connector - 该文件夹中的驱动支持内核了解进程何时fork或运行,并且通过proc连接器更改用户ID,用户组ID和会话ID。内核需要了解进程何时fork和执行,否则进程无法有效管理资源。
    cpufreq - 这些驱动程序通过更改电源消耗控制CPU频率。
    cpuidle - 这些驱动管理CPU的空闲状态,如果系统中有多个CPU,驱动会试图保持CPU的空闲一致。
    crypto - 加密驱动。
    dca - 直接高速缓存访问(DCA)驱动允许内核访问CPU的高速缓存(cache)。CPU的高速缓存就像是集成在CPU芯片上的RAM,但是较之于RAM芯片运行速度更快。然而CPU的高速缓存存储空间小,因此CPU仅将最重要的和执行的代码至于高速缓存上。
    devfreq - 这个驱动通过改变CPU的频路来达到节能的目的,也被称为CPU节流。
    dio - 数字输入输出总线驱动。
    dma - 直接取内存驱动(DMA)允许设备不通过CPU访问内存,降低了CPU的负担。
    edac - 错误检测与更正驱动。
    eisa - 工业标准体系扩展(EISA)驱动使得内核支持EISA协议。
    extcon - 外部连接驱动检测端口,并发现插入的外部设备。例如,该驱动可以发现用户插入的U盘。
    firewire - FireWire驱动。
    firmware - 该文件夹中的驱动与诸如BIOS之类设备的组件通信。BIOS是用于启动操作系统以及控制外设的硬件和组件。有些BIOS系统允许用户CPU超频,超频是指使CPU运行在更快的速度。CPU的运行速度是以MHz或GHz计的,一个3.7GHz的CPU显然比700MHz的处理器速度更快。
    gpio - 通用输入/输出端口(GPIO)是芯片上的通用引脚,用户可以控制其行为。本文件夹中的驱动用于控制GPIO。
    gpu - 本文件夹中的驱动用于控制VGA,GPU,以及DRM。VGA是640*480分辨率的模拟计算机显示。GPU是图像处理器,DRM是Unix的翻译系统。
    hid - 本文件夹中的驱动支持USB人机界面设备。
    hsi - 本文件夹中的驱动支持诺基亚N900中的蜂窝调制解调器。
    hv - 支持KVP的驱动程序。
    hwmon - 硬件监视驱动允许内核读取硬件中的传感器信息,例如,CPU中集成了热敏电阻,内核就可以通过监视CPU的温度来调节冷却风扇的转速。
    hwspinlock - 硬件自旋锁驱动允许系统拥有:两个及以上不同的处理器,或者是双核或多核的处理器。
    i2c - I2C驱动允许内核使用I2C协议,I2C协议支持与低速外设进行通信。
    ide - 这些驱动程序用于PATA/IDE设备,例如CD光驱和硬盘。
    idle - 这些驱动管理英特尔处理器的空闲状态。
    iio - 工业I/O内核驱动支持内核运行ADC或DAC。
    infiniband - 该驱动支持企业级数据中心或者是超级计算机所使用的高性能端口。
    input - 这一文件夹中包含了许多驱动,他们都用于驱动输入设备,例如游戏手柄,鼠标,键盘等等。
    iommu - 输入输出内存管理单元(IOMMU)是内存管理单元的一种,它通过总线与RAM相连,IOMMU可以使得外设不通过CPU访问RAM,从而降低了CPU的负担。
    ipack - 该驱动用于支持母板与子板之间的虚拟总线。
    irqchip - 该文件夹中的驱动支持中断请求(IRQ),IRQ是指由硬件向处理器提出的一种请求,通常情况下这一请求是使得处理器暂停一个正在运行的程序转而运行另一个特定程序。
    isdn - 该驱动支持ISDN,ISDN(综合业务数字网络)是一个通信标准的集合,它可以通过传统的电话网络传输音频,视频,数据以及其他的网络服务。
    leds - LED驱动。
    lguest - 管理虚拟机中操作系统的中断请求。
    macintosh - Apple硬件的驱动
    mailbox - 管理邮件系统。
    md - 该文件夹中的驱动支持RAID(独立硬盘冗余阵列),RAID是一种多个硬盘共享或备份数据的系统。
    media - 多媒体设备驱动。
    memory - 重要的RAM驱动。
    memstick - Sony记忆棒的驱动。
    message - LSI PCI芯片或适配器的驱动。LSI是指大规模集成电路。
    mfd - 多功能设备(MFD)驱动,MFD是指提供诸如邮件,传真,复印,打印等多种服务的设备。
    misc - 该文件夹中包含了一些无法归类的驱动程序。
    mmc - 多媒体卡(MMC)驱动,处理应用于闪存卡的MMC标准。
    mtd - 存储技术设备驱动是Linux用于与闪存卡的驱动。闪存卡与块设备或字符设备的运行方式不同。虽然USB存储卡和SD卡都是闪存设备,但是他们使用的是块设备的驱动,本文件夹中的驱动是新型闪存设备的驱动程序。
    net - 网络驱动提供诸如Appletalk,TCP以及其他网络协议,该文件夹中的驱动也同样支持调制解调器,USB2.0以太网设备。
    nfc - 该文件夹中的驱动是德州仪器公司的共享传输层和NCI核之间的界面。
    ntb - 提供PCIe系统间的非透明桥接,PCIe是一种高速扩展总线标准。
    nubus -NuBus是一种32位的并行计算机总线,该驱动用于Apple设备。
    oprofile - 这些驱动反映了从驱动到用户进程(用户运行的应用)的这个系统,帮助开发者寻找性能问题。
    parisc - 支持惠普公司的PA-RISC设备。
    parport - 支持Linux下的并行端口。
    pci - 提供PCI总线服务。
    pcmcia - 笔记本电脑的主板驱动。
    pinctrl - 引脚控制驱动。
    platform - 该文件夹中的驱动支持不同的计算机平台,诸如Acer,Dell,Toshiba,IBM等等。
    pnp - 即插即用设备驱动。
    power - 允许内核测量电池电量,检测充电以及电源管理。
    pps - 控制电脉冲频率以计算时间。
    ps3 - Sony的Playstation3的驱动。
    ptp - 图片传输协议(PTP)支持由数码相机传输图片。
    pwm - 控制向设备输出的电脉冲(PWM),主要用于控制CPU风扇的转速。
    regulator - 支持诸如温度调节一类的调节设备。
    remoteproc - 管理远程处理器。
    rpmsg - 这些驱动程序支持远程处理器消息总线。
    rtc - 实时时钟驱动支持内核读取时钟。
    sbus - 基于SPARC的总线的驱动程序。
    scsi - 应用SCSI标准的外设的驱动。
    spi - SPI总线的驱动程序。
    ssb - SSB驱动支持Broadcom芯片和嵌入式设备上的迷你总线。
    staging - 这一文件夹中的驱动程序未经过严格测试,所以并未被放入内核的主流驱动程序之中。
    target - SCSI目标的驱动程序。
    thermal - 确保CPU不会过热的驱动。
    tty - 管理与实际终端(如显示器)连接的驱动。
    uio - 允许用户使用运行在用户空间的驱动,确保用户制作的驱动不会导致内核崩溃。
    usb - USB驱动。
    vfio - 允许设备访问用户空间的驱动。
    video - 管理显卡和显示器的驱动。
    virt - 虚拟化驱动。
    virtio - 允许virtio设备通过PCI设备使用。
    watchdog - 管理watchdog计时器的驱动。
    xen - Xen虚拟机驱动。
    zorro - 支持Zorro Amiga总线。
    下一篇文章中我们来聊一聊系统安全

    下面是一些关于如何开发Linux驱动的教程链接:

    http://www.freesoftwaremagazine.com/articles/drivers_linux

    http://lwn.net/Kernel/LDD3/

    http://www.linuxdevcenter.com/pub/a…troduction-to-device-drivers-under-linux.html

    http://www.linux-drivers.org/

    [1]TURBOchannel总线是曾经被Digital公司广泛应用的总线,但目前已基本停用。https://en.wikipedia.org/wiki/TURBOchannel

    展开全文
  • 深入Linux设备驱动程序内核机制

    千次阅读 2012-02-21 20:24:16
    深入Linux设备驱动程序内核机制 陈学松 著 ISBN978-7-121-15052-4 2012年1月出版 定价:98.00元 16开 540页 内 容 简 介 这是一本系统阐述Linux设备驱动程序技术内幕的专业书籍,它的侧重点不是讨论如何在...
  • USB驱动程序理解

    千次阅读 2007-01-23 21:39:00
    USB驱动程序理解 学了两个多星期了,USB驱动程序的有一小小的理解。现在总结如下!!!!!!!!1、每个设备对应一个PDO,每个PDO又对应多个FDO,在驱动程序中直
  • 通常这是文件系统开发人员所关心的问题,但所有的内核模式驱动程序开发人员都能得益于运行环境的深入理解并能使驱动程序拥有更高的性能和更低的开销。  运行环境的概念程序例程的运行环境实际是指其线程和进程的...
  • 深入理解linux内核 触摸屏FT5X06驱动程序详细分析 文章目录1、数据手册2、连接图3、驱动程序:3.1、设备树配置3.2 驱动程序3.2.1、2c_driver的注册3.2.2、`probe`探测函数调用过程3.2.3、中断程序:4、测试程序4.1...
  • 【Linux 驱动】设备驱动程序理解

    千次阅读 2014-06-19 00:35:14
    学习设备驱动编程也有一段时间了,也写过了几个驱动程序,因此有设备驱动程序有了一些新的理解和认识,总结一下。 ★什么是驱动程序 刚开始学习设备驱动程序的时候,产生了许多的问题。什么是驱动程序驱动...
  • 今天移植了按键,LED,LCD,触摸屏等驱动程序,移植驱动程序相对于写驱动程序,就简单得多,前提是得理解驱动程序。 现在来大体总结一下如何移植一个新的驱动程序(不是内核自带的驱动程序)的大体思路以及流程。 ...
  • USB驱动程序理解(1)

    千次阅读 2005-10-15 19:35:00
    USB驱动程序理解(1)学了两个多星期了,USB驱动程序的有一小小的理解。现在总结如下!!!!!!!!1、每个设备对应一个PDO,每个PDO又对应多个FDO,在驱动程序中直接操作的不是硬件而是相应的PDO和FDO。在...
  • 对内核对象的理解

    千次阅读 2017-03-13 17:04:32
    内核对象 就是在操作系统内核中进行资源分配和管理的一种数据结构。 应用程序是无法在其管理的内存中找到这些资源并改变的。也就是说内核对象是属于某个进程的,而是属于操作系统的。
  • 使用 C++ 编写内核模式驱动程序的优点与缺点本页内容简介内核模式代码注意事项将 C++ 编译器用于内核模式代码内核模式驱动程序的 C++ 问题结束语参考资料   C++ 及其对象特性似乎与 Microsoft ...
  • linux内核Device Drivers设备驱动程序

    千次阅读 2015-10-14 11:25:37
    设备驱动程序 Generic Driver Options 驱动程序通用选项  Select only driversthat don't need compile-time external firmware 只显示那些不需要内核对外部设备的固件作map支持的驱动程序,除非你有某些怪异...
  • 理解驱动程序(个人理解

    千次阅读 2018-08-30 18:31:47
    理解驱动程序最重要的一句话是,寄存器是软件控制硬件的唯一途径。所以如何控制显卡,答案就是靠读写显卡提供的寄存器。   通过什么读写呢?据我所知的目前的显卡驱动,基本没有用低效的端口 IO 的方式读写。现在...
  • 我们植到,Winsock以网络协议为基础来访问网络,比如TCP/IP和IPX/SPX等,其相应的内核驱动程序为afd.sys。那么,像 afd.sys这样的网络 API 驱动程序在接收到针对特定协议的网络请求时,如何将请求转交给相应的协议...
  • 成为一名精通 Linux 程序设计的高级程序员一直是不少朋友孜孜以求的目标。根据中华英才网统计数据,北京地区 Linux 程序员月薪平均为 Windows 程序员的 1.8 倍、Java 程序员的 2.6 倍, Linux 程序员年终奖金平均为 ...
  • 成为一名精通 Linux 程序设计的高级程序员一直是不少朋友孜孜以求的目标。根据中华英才网统计数据,北京地区 Linux 程序员月薪平均为 Windows 程序员的 1.8 倍、Java 程序员的 2.6 倍, Linux 程序员年终奖金平均为 ...
  • 理解和使用NT驱动程序的执行上下文

    千次阅读 2013-09-25 14:39:06
    理解Windows NT驱动程序最重要的概念之一就是驱动程序...传统上文件系统开发者最关注这个问题,但所有类型的NT内核模式驱动程序的编写者都能从执行上下文的深刻理解中获益。小心谨慎地使用执行上下文的概念能帮助构建
  • 你为什么看不懂Linux内核驱动源码?

    千次阅读 2018-04-28 14:34:05
    而做到这一步的基础,就是你要看得懂Linux内核源码,了解其基本的框架和具体实现,了解其内核API的使用方法,然后才能根据自己的需求写出高质量的内核驱动程序。 说易行难,很多新人、甚至工作1-2年的开发者刚接触...
  • Kmd教程1-内核模式驱动程序基础

    千次阅读 2008-09-26 13:23:00
    转自:http://www.gomb.cn/?uid-2-action-viewspace-itemid-14481.Kernel Mode驱动程序基础 本教程讲述了如何在Windows NT为...开发Windows 95/98/ME使用的VxD驱动程序方面的知识并不在本教程讲述的范围内,另外,毫
  • 调试通用驱动程序 - 分步(Echo 内核模式) 本实验中引入了 WinDbg 内核调试器。 WinDbg 用于调试 Echo 内核模式的示例驱动程序代码。 实验目标 本实验包含以下练习:引入调试工具、介绍常见调试命令、阐述...
  • 第二章 Android内核驱动程序(转)

    千次阅读 2010-07-30 08:09:00
    2.1 Android内核特性 Android内核是基于Linux 2.6内核的(目前最新开发版本是2.6.31),它是一个增强内核版本,除了修改部分Bug外,它提供了用于支持Android平台的设备驱动,主要包括:Android Binder ...
  • 成为一名精通 Linux 程序设计的高级程序员一直是不少朋友孜孜以求的目标。根据中华英才网统计数据,北京地区 Linux 程序员月薪平均为 Windows 程序员的 1.8 倍、Java 程序员的 2.6 倍, Linux 程序员年终奖金...
  • 驱动程序提供的一组设备驱动接口函数Device Driver Interface给操作系统在linux中,这一组设备驱动接口函数一般包括open,close,read,write,ioctl等。 这一组函数是通过一个叫做file operations的结构体注册给linux...
  • 内核模式驱动程序框架 (KMDF)处理I/O请求的情况 在内核模式驱动程序框架 (KMDF) 中,一个 WDFREQUEST 对象代表一个 I/O 请求。每个 WDFREQUEST 对象都与一个或多个 WDFMEMORY 对象关联,每个这种 WDFMEMORY 对象都...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 88,851
精华内容 35,540
关键字:

对内核驱动程序的理解