Linux字符设备驱动模型之点亮LED灯
在前面的文章中,已经描述了整一个字符设备模型,那现在,可以来使用相应的模型进行操作硬件设备了。那么,从点亮一个LED灯开始。
一、设备控制操作
1.理论基础
大部分驱动程序除了需要提供读写设备的能力外,还需要具备控制设备的能力。比如设置UART波特率这样的操作。
实际上在Linux系统用户空间中,提供了ioctl系统调用函数来实现了控制设备的操作。其原型如下:
int ioctl(int fd,unsigned long cmd,...)
·fd: 要控制的设备文件描述符
·cmd: 发送给设备的控制命令
·…: 第3个参数是可选的参数,存在与否是依赖于控
制命令(第 2 个参数 )。
当应用程序在用户空间使用ioctl系统调用时,驱动程序将由如下函数来响应:
(1)Linux 2.6.36版本之前的内核
long (*ioctl) (struct inode* node ,struct file* filp, unsigned int cmd,unsigned long arg)
(2)Linux 2.6.36版本之后的内核
long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);
·参数cmd: 通过应用函数ioctl传递下来的命令
此函数方法由struct file_operations操作函数集实现,如下图:
在此笔者所使用的是3.0.8版本的Linux内核。
2.控制方法实现
(1)定义命令
命令从其实质而言就是一个整数, 但为了让这个整数具备更好的可读性,我们通常会把这个整数分为几个段:类型(8位),序号,参数传送方向,参数长度。
·Type(类型/幻数): 表明这是属于哪个设备的命令。
·Number(序号):用来区分同一设备的不同命令。
·Direction:参数传送的方向,可能的值是 _IOC_NONE(没有数据传输), _IOC_READ, _IOC_WRITE(向设备写入参数)。
·Size:参数长度
Linux系统提供了下面的宏来帮助定义命令:
·_IO(type,nr):不带参数的命令
·_IOR(type,nr,datatype):从设备中读参数的命令
·_IOW(type,nr,datatype):向设备写入参数的命令
示例:
#define MEM_MAGIC ‘m’ //定义幻数
#define MEM_SET _IOW(MEM_MAGIC, 0, int)
(2)实现操作
在Linux内核操作函数集中的unlocked_ioctl函数的实现通常是根据命令执行的一个switch语句。但是,当命令号不能匹配任何一个设备所支持的命令时,返回-EINVAL.
二、Linux内核空间操作硬件设备
1.确定硬件接口
在操作一个硬件设备前,必须要了解的是其所使用的硬件接口和硬件原理。在此笔者所使用的是S5PV210平台。
如上图可知,LED1和LED2由CPU的GPC0_3和GPC0_4这两个I/O口控制,并且GPIO口工作在输出模式时,当输出高电平时,灯亮;输出低电平时,灯灭。
如上图为GPC0口的控制寄存器GPC0CON(地址为0xe0200060),分析可知,当将[19:12]位配置为[00010001]时,GPC0_3和GPC0_4口工作在输出模式下。
如上图为GPC0口的数据寄存器GPC0DAT(0XE0200064),当I/O口工作在输出模式时,其每一位代表着每一个GPIO口的电平配置。所以GPC0DAT寄存器的位3代表着GPC0_3口,位4代表GPC0_4口。
在程序头文件led_driver.h中定义寄存器硬件地址:
2.命令和设备结构体定义
根据ioctl命令的定义方式,在程序头文件led_driver.h中定义命令,如下图:
如上图中定义了一个led设备相关的结构体struct led_device,成员struct class *led_class;代表led设备类,struct device *led_device;代表了的设备,unsigned int val;代表其可能需要的配置值。
对于LED的操作而言,实现可以单个点亮或熄灭LED,也可以全部点亮或熄灭LED。所以定义了__LED_SELECT枚举、ON和OFF命令,然后通过__IO()宏进行定义命令。
3.设备驱动模块初始化
(1)定义struct led_device结构体变量struct led_device *led_dev;和硬件操作相关变量gpc0con、gpc0dat。
并为指针led_device申请内存空间。
(2)静态申请主设备号
其中LED_MAJOR为静态定义的主设备号,在程序头文件led_driver.h中定义。led_fops为struct file_operations操作函数集。
#define LED_MAJOR 100
(3)自动创建设备节点文件
首先使用class_create函数创建一个设备类,然后再根据设备类由device_create函数创建一个名为led的设备节点文件,即为当在Linux内核中加载此驱动时,会自动在用户空间/dev目录下生成的设备节点文件led。
当操作失败时,处理方式如下:
(4)将硬件设备操作寄存器地址映射为虚拟地址。
在Linux内核中,是不允许直接操作设备的物理地址的,智能通过虚拟地址映射的方式进行操作或者配置CPU私有外设的寄存器地址,从而达到操作相关寄存器的目的。
在Linux内核中提供了ior
- DSP在LED大屏显示中的应用(03-14)
- DSP在LED显示中的应用(08-21)
- 基于μC/OS2II的LED显示屏控制器(08-14)
- 基于DSP的LED大屏幕显示系统(10-03)
- 基于单片机的彩灯设计方案(10-29)
- 基于μC/OS-II及Nios II的多窗口显示屏控制器的设计与实现(01-23)