因此,驱动程序的设计,要求开发人员熟悉Linux的内核机制、驱动程序和用户级应用程序的接口关系、系统中对设备的并发操作,同时要求开发人员非常熟悉所开发硬件的工作原理。嵌入式Linux中的设备驱动程序有以下三个方面的特点。......
2023-11-19
上面介绍了字符设备驱动程序的重要的数据结构,那么如何设计一个字符设备驱动程序的数据结构?接下来介绍编写驱动程序的步骤和结构体之间的层次关系。
字符设备驱动程序的初始化流程一般可以用如下的过程来表示:
(1)定义相关的设备文件结构体[如file_operation()中的相关成员函数的定义]。
(2)向内核申请主设备号(建议采用动态方式)。
(3)申请成功后,通过调用MAJOR()函数获取主设备号。
(4)初始化cdev的结构体,可以通过调用cdev_init()函数实现。
(5)通过调用cdev_add()函数注册cdev到内核。
(6)注册设备模块,主要使用module_init()函数和module_exit()函数。
编写一个字符设备的驱动程序,首先要注册一个设备号。内核提供了三个函数来注册一组字符设备编号,这三个函数分别是:alloc_chrdev_region()、register_chrdev_region()和register_chrdev()。下面具体分析各个函数的参数原型和意义。
register_chrdev_region()函数用于向内核申请分配已知可用的设备号(次设备号通常为0)范围。下面是该函数原型:(www.chuimin.cn)
int register_chrdev_region(dev_t from,unsigned count,const char∗name)。
参数from是要分配的设备号的dev_t类型数据,表示了要分配的设备编号的起始值,参数count表示了允许分配设备编号的范围。
register_chrdev()是一个老版本内核的设备号分配函数,不过新内核对其还是兼容的。Register_chrdev()兼容了动态和静态两种分配方式。Register_chrdev()不仅分配了设备号,同时也注册了设备。这是register_chrdev()与前两个函数的最大区别。也就是说,如果使用alloc_chrdev_region()或register_chrdev_region()分配设备号,还需要对cdev结构体初始化。而register_chrdev()则把对cdev结构体的操作封装在了函数的内部。所以在一般的字符设备驱动程序中,不会看到对cdev的操作。
与注册分配字符设备编号的方法类似,内核提供了两个注销字符设备编号范围的函数unregister_chrdev_region()和unregister_chrdev()。这两个函数实际上都调用了__unregister_chrdev_region()函数,原理是一样的。
Register_chrdev()函数封装了cdev结构的操作,而alloc_chrdev_region()或register_chrdev_region()只提供了设备号的注册,并未真正的初始化一个设备,只有cdev这个表示设备的结构体初始化了,才可以说设备初始化了。
这里举出字符设备驱动程序的常见的两种编程架构。
架构一:
这两个结构中,前一个应用register_chrdev函数封装了cdev,后面可以直接定义file_operations结构体提供系统调用接口。后一种架构用alloc_chrdev_region注册设备号,然后用cdev_init初始化了一个设备,接着用cdev_add添加了该设备。两种架构在模块卸载函数中,分别用相应的卸载函数实现。
当file_operations结构与设备关联在一起后,就可以在驱动的架构中补全file_operations的内容,实现一个完整的驱动架构,比如:
有关ARM嵌入式系统原理与应用的文章
因此,驱动程序的设计,要求开发人员熟悉Linux的内核机制、驱动程序和用户级应用程序的接口关系、系统中对设备的并发操作,同时要求开发人员非常熟悉所开发硬件的工作原理。嵌入式Linux中的设备驱动程序有以下三个方面的特点。......
2023-11-19
用户应用程序调用设备的功能都是在设备驱动程序中定义的,也就是设备驱动程序中所定义的功能入口点函数。struct file_operations{};struct inode{};struct file{};编写设备驱动程序,很大一部分工作就是“填写”结构体中定义的函数。取得目录入口点,只用于与文件系统相关的设备驱动程序。一般编写设备驱动程序时并不一定要全部定义以上函数,只需定义对设备有意义的接口函数。fie结构主要是与文件系统对应的设备驱动程序使用。......
2023-11-19
对一个打开的文件而言,最常用到的就是对文件的读写操作,在Linux系统中,提供了系统调用函数实现文件的读写操作。读取文件数据时,文件的当前读写位置会向后移。以下几种读取文件数据情况下,返回的字节数会小于count值。......
2023-11-19
GPIO属于字符设备,其驱动可以归类为Linux设备驱动的字符设备驱动。编写一个程序gpio_led.c,实现对实验箱CVT_A8上连接在GPIO端口的LED驱动程序,使得实验箱上的发光二极管轮流点亮,既常见的流水灯。既然是这样,则编写设备驱动程序的主要工作就是编写子函数,并填充file_operations的各个域。函数分别为device ioctl并在模块初始化函数dev init中调用misc register函数进行注册ioctl操作函数实现。模块退出操作模块退出,必须删除设备驱动程序并释放占用的资源,使用unregister_chrdev删除设备驱动程序。......
2023-11-19
嵌入式系统的发展大致经历了嵌入式微控制器、嵌入式微处理器和嵌入式数字信号处理器、嵌入式片上系统和以Internet为标志的嵌入式系统等阶段。嵌入式系统的出现最初是基于单片机的,这一阶段的嵌入式系统硬件是单片机,软件停留在无操作系统阶段,采用汇编语言实现系统的功能。第四阶段是以Internet为标志的嵌入式系统。......
2023-11-19
Linux统按照文件中数据的特点对文件划分不同的类别,称做文件类型。Linux系统提供了一个file命令用来查看文件的类型,执行file<文件名>即可得到指定文件的类型。目录的第一项是目录本身,以“.”作为目录本身的名称。......
2023-11-19
GPIO是一组可编程控制的引脚,由多个寄存器同时控制。应用程序都能够通过相应的接口使用GPIO。GPIO驱动主要作用就是读取GPIO口的内容,或者设置GPIO口的状态。GPIO与硬件体系密切相关,在Linux内核目录下的相关文件中我们可以发现针对不同硬件芯片的GPIO定义和使用方法,如本书涉及的S5PV210芯片Linux内核中也有相应的驱动程序支持。本章主要讲的就是如何使用Linux内核封装好的GPIO接口函数在驱动开发中需要操作GPIO时候的使用。......
2023-11-19
按照惯例,所有的Makefile变量都应该是大写。如果变量的值发生变化,就只需要在一个地方修改,从而简化了Makefile的维护。现在利用变量把前面的Makefile重写一遍:除用户自定义的变量外,make还允许使用环境变量、自动变量和预定义变量。需要注意的是,如果用户在Makefile中定义了同名的变量,用户自定义变量将覆盖同名的环境变量。此外,Makefile中还有一些预定义变量和自动变量,但是看起来并不像自定义变量那样直观。......
2023-11-19
相关推荐