微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux字符设备驱动模型之点亮LED灯

Linux字符设备驱动模型之点亮LED灯

时间:04-09 来源:互联网 点击:

在前面的文章中,已经描述了整一个字符设备模型,那现在,可以来使用相应的模型进行操作硬件设备了。那么,从点亮一个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

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top