新闻中心

EEPW首页 > 嵌入式系统 > 业界动态 > [ARM笔记]设备驱动概述

[ARM笔记]设备驱动概述

作者:时间:2016-11-24来源:网络收藏

  mknod命令建立一个目录项和一个特殊文件的对应索引节点。第一个参数Name项是设备的名称,选择一个描述性的设备名称。

本文引用地址:http://www.eepw.com.cn/article/201611/340660.htm

  mknod命令有两种形式,它们有不同的标志。mknod命令的第一种形式只能由root用户或系统组成员执行。在第一种形式中,使用了b或c标志。b标志表示这个特殊文件是面向块的设备(磁盘、软盘或磁带)。c标志表示这个特殊文件是面向字符的设备(其他设备)。在 mknod 命令的第二种形式中,使用了p标志来创建FIFO(已命名的管道)。

  因此,标志集合总共有三种选择,如下:

  * b 表示特殊文件是面向块的设备(磁盘、软盘或磁带)。

  * c 表示特殊文件是面向字符的设备(其他设备)。

  * p 创建 FIFO(已命名的管道)。

  在介绍创建设备文件时,主设备号和从设备号是不可或缺的。传统方式中的设备管理中,除了设备类型外,内核还需要一对主次设备号的参数,才能唯一标识一个设备。主设备号相同的设备使用相同的驱动程序,次设备号用于区分具体设备的实例。比如PC机中的IDE设备,一般主设备号使用3,WINDOWS下进行的分区,一般将主分区的次设备号为1,扩展分区的次设备号为2、3、4,逻辑分区使用5、6…。

  第一种形式的最后两个参数便是指定主设备号和次设备号,它帮助操作系统查找设备驱动程序代码,和指定具体的次设备。一个设备的主设备号和次设备号由该设备的配置方法分配。主设备号是由/usr/src/linux/include/linux/major.h定义的,如下定义了一个DOC设备:

  #define IGEL_FLASH_MAJOR 62

  如命令mknod doc b 62 0

  其中的doc为定义的名字,b指块设备,0指的是整个DOC。如果把0换为1,则1指的是DOC的第一个分区。2是第2个,依次类推。

  mknod console c 5 1

  console是设备的名字;c指字符设备,还可选b(块设备);5是该设备在major.h中定义的标记,主设备号/dev/devices里面记录现有的设备,创建设备文件时,找个系统中还没有用过的就可以了;1是指第一个子设备。当你要给两个同样的设备加载驱动的时候就要用到这些区别了。

  3. 驱动程序的加载和卸载

  内核中采用可加载的模块化设计,一般情况下编译的内核是支持可插入式模块的,也就是将最基本的核心代码编译在内核中,其它的代码可以选择是在内核中,或者编译为内核的模块文件。如果需要某种功能,比如需要访问一个NTFS分区,就加载相应的NTFS模块。这种设计可以使内核文件不至于太大,但是又可以支持很多的功能,必要时动态地加载。这是一种跟微内核设计不太一样,但却是切实可行的内核设计方案。

  3.1 Linux驱动的加载方式

  由于Linux系统内核有如上的特点,所以设备驱动程序也秉承了这种特性。常见的驱动程序就是作为内核模块动态加载的,比如声卡驱动和网卡驱动等。而Linux最基础的驱动,如CPU、PCI总线、TCP/IP协议、VFS等驱动程序则编译在内核文件中。因此,Linux驱动的加载可分为静态加载和动态加载两种不同的方式。

  * 静态加载:系统启动时自动加载驱动到内核,自动的注册设备并创建设备接点,也就是说把驱动程序直接编译到内核,系统启动后应用程序可以直接运行、调用。静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新编译下载内核,效率较低。

  * 动态加载:即模块加载,系统启动时不会进行加载驱动程序,需要人为手动加载,就是说系统启动后我们的应用程序不能直接应用驱动,而是我们必须手动的用insmod命令去加载模块,然后才能使用相应的设备和应用,在不需要的时候用rmmod命令来卸载。

  其中动态加载我们又可以分为三种去研究:

  加载驱动后,我们自己去创建主设备号,从设备号,利用cat /proc/devices 去查看主设备号是否重复,然后根据应用程序中使用的设备名称用mknod命令去创建设备文件接点。

  加载驱动后,驱动程序会利用register_chrdev()函数自动产生主设备号去在内核中注册设备,我们利用cat /proc/devices命令和驱动程序中注册的设备名去查询主设备号和从设备号后,在根据应用程序使用的设备名,去利用mknod去创建。(利用驱动中注册的设备名是查询自动生成的主设备号,驱动中的设备名称不一定要和创建的设备接点名相同,他们之间可以用主设备号去关联,而应用程序的设备名称则必须和创建的设备接点名相同)。

  加载驱动后,驱动程序利用devfs系统,这个系统可以自动的产生主设备号,然后自动的创建设备接点。我们只要加载驱动后,直接运行应用程序就行了。

  一般嵌入式驱动开发者会先用动态加载的方式来调试,调试完毕后再编译到内核里。下面我们将向读者介绍下如何使用insmod动态加载模块。

  3.2 Linux驱动加载和卸载

  当我们编写好需要加载的模块、创建了其在内核的设备挂载节点之后,下一步要进行的操作就是将该设备模块加载到内核,也就是把编译后的驱动程序的.ko文件加载到内核。这个工作将由insmod完成。这个程序将加载模块的代码段和数据段到内核,接着,执行一个类似ld的函数,它连接模块中任何未解决的符号连接到内核的符号表上。

  insmod接收许多命令行选项,它能够在连接到当前内核之前,为模块中的参数赋值,加载时配置比编译时配置给了用户更多的灵活性,感兴趣的读者可以查阅相关的资料。一般常用的命令方式为:

  #insmod /路径 模块编译后生成文件.ko

  模块可以用rmmod工具从内核去除。需要注意的是,如果内核认为模块还在用,或者内核被配置成不允许模块去除,模块去除会失败。除了上述两种命令,还有一些相关的命令,在模块加载时可以用到。如下所示:

  lsmod:列出当前系统中加载的模块,其中显示信息中分为三列,依次是:模块名、模块大小、模块使用的数量。

  modprobe:使用modprobe命令,可以智能插入模块,它可以根据模块间的依存关系,以及/etc/modules.conf文件中的内容智能插入模块。

  insmod:也是插入模块的命令,但是它不会自动解决依存关系。

  modinfo:用来查看模块信息。

  4. 学习Linux驱动程序的基础及方法

  Linux设备驱动的学习是一项浩大的工程,读者需要一定的基础。在前面,我们专门讲到过驱动程序是连接硬件设备和操作系统的桥梁。

  因此,驱动的开发不仅要有良好的硬件基础,懂得SRAM、Flash、SDRAM、磁盘的读写方式,UART、I2C、USB等设备的接口,轮询、中断、DMA的原理,PCI总线的工作方式以及CPU的内存管理单元(MMU)等硬件处理的方式;还需要对Linux内核有一定的了解,虽然并不要求工程师对内核各个部分有深入的研究,但至少要了解设备驱动与内核的接口,尤其是对于块设备、网络设备、Flash设备、串口设备等复杂设备的驱动框架等。

  另外,在应用中很有可能多个程序访问同一个设备,这也就需要具有良好的多任务并发控制和同步的基础。动手实践永远是学习任何软件开发的最好方法,学习Linux设备驱动也不例外。

  一般来说,编写一个Linux设备驱动程序的大致流程如下:

  (1)查看原理图、数据手册,了解设备的操作方法。

  (2)在内核中找到相近的驱动程序,以它为模板进行开发,有时候需要从零开始。

  (3)实现驱动程序的初始化:比如向内核注册这个驱动程序,这样应用程序传入文件名时,内核才能找到相应的驱动程序。

  (4)设计所要实现的操作,比如:open、close、read、write等函数。

  (5)实现中断函数(中断并不是每个设备驱动所必需的)。

  (6)编译该驱动程序到内核中,或者用insmod命令加载。

  (7)测试驱动程序。


上一页 1 2 3 下一页

关键词: ARM Linux

评论


相关推荐

技术专区

关闭