当前位置:文档之家› 嵌入式Linux驱动程序开发要点(20210201123523)

嵌入式Linux驱动程序开发要点(20210201123523)

嵌入式Linux驱动程序开发要点

在Linux操作系统下有3类主要的设备文件类型:块设备、字符设备和网络设备。 这种分类方法可以将控制输入/输出设备的驱动程序与其他操作系统软件分离开 来。|

字符设备与块设备的主要区别是:在对字符设备发出读 /写请求时,实际的硬件

I/O 一般紧接着发生。块设备则不然,它利用一块系统内存作为缓冲区,若用户 进程

对设备的请求能满足用户的要求, 就返回请求的数据;否则,就调用请求函数来

进行实际的I/O操作。块设备主要是针对磁盘等慢速设备设计的,以免耗费过多 的

CPU时间用来等待。网络设备可以通过 BSD套接口访问数据。

每个设备文件都有其文件属性(c/b),表示是字符设备还是块设备。另外每个文件 都

有2个设备号,第一个是主设备号,标识驱动程序;第二个是从设备号,标识使 用同一个设备驱动程序的、不同的硬件设备。设备文件的主设备号必须与设备驱 动程

序在登记时申请的主设备号一致,否则用户进程将无法访问驱动程序。

系统调用时操作系统内核与应用程序之间的接口, 设备驱动程序是操作系统内核

与机器硬件之间的接口。设备驱动程序是内核的一部分,它完成以下功能:

•对设备初始化和释放

•把数据从内核传送到硬件和从硬件读取数据

•读取应用程序传送给设备文件的数据和回送应用程序请求的数据

•佥测和处理设备出现的错误

MTD(Memory

Tech no logy

Device )设备是闪存芯片、小型闪存卡、记忆棒之类的设备,它们在嵌入式设备 中的使用正在不断增加。MTD驱动程序是在Linux下专门为嵌入式环境 开发的新的一类驱动程序。相对于常规块设备驱动程序,使用 MTD驱动程序的

优点在于他们能更好的支持、管理给予闪存设备,有基于扇区的擦除和读 /写操

作的

更好的接口。

驱动程序结构

Linux的设备驱动程序可以分为3个主要组成部分:

1. 自动配置和初始化子程序,负责监测所要驱动的硬件设备是否存在和能否正 常工作。如果该设备正常,则对这个设备及其相关的设备驱动程序需要的软件状 态进行初始化。这部分驱动程序仅在初始化时被调用一次。

2.

服务于I/O请求的子程序,又称为驱动程序的上半部分。调用这部分程序是由于 系统调用的结果。这部分程序在执行时,系统仍认为是与进行调用的进程属于同 个进程,只是由用户态变成了核心态,具有进行此系统调用的用户程序的运行环 境,因而可以在其中调用sleep()等与进行运行环境有关的函数。

3.

中断服务子程序,又称为驱动程序的下半部分。在 Linux系统中,并不是直接从

中断向量表中调用设备驱动程序的中断服务子程序,而是由 Linux系统来接

收硬件中断,再由系统调用中断服务子程序。中断可以在任何一个进程运行时产

生,因而在中断服务程序被调用时,不能依赖于任何进程的状态,也就不能调用 任何 与进程运行环境有关的函数。因为设备驱动程序一般支持同一类型的若干设备, 所以一般在系统调用中断服务子程序时, 都带有一个或多个参数,以唯一标识请

求服

务的设备。

在系统内部,I/O设备的存/取通过一组固定的入口点来进行, 这组入口点是由每

个设备的驱动程序提供的。具体到Linux系统,设备驱动程序所提供的这组入口

点由一个文件操作结构来向系统进行说明。 file_operation结构定义于linux/fs.h

文件中。

struct file_operati on{

int (*lseek)(struct inode *inode, struct file *filp, off_t off, int pos);

int (*read)(struct inode *ino de, struct file *filp, char *buf, i nt coun t);

int (*write)(struct inode *ino de, struct file *filp, const char *buf, i nt coun t);

int (* †readdir)(struct inode *ino de, struct file *filp, struct dire nt *dire nt, int coun

t);

int (*select)(struct inode *ino de, struct file *filp, i nt sel type, select table *wait);

int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned int arg);

int (*mmap)(void);

int (*open)(struct inode *inode, struct file *filp);

int (*release)(struct inode *inode, struct file *filp);

用户自己的驱动程序中,首先要根据驱动程序的功能,完成 file_operation结构

中函数实现。不需要的函数接口可以直接在

int (*fasync)(struct inode *inode, struct file *filp);

};

file_operation结构中的成员几乎全部是函数指针,所以实质上就是函数跳转表。

每个进程对设备的操作都会根据 major、mi nor设备号,转换成对file_operation

结构的访问。

常用的操作包括以下几种:

• lseek移动文件指针的位置,只能用于可以随机存取的设备。

• read,进行读操作,参数buf为存放读取结果的缓冲区,count为所要读取的数 据长度。返回值为负表示读取操作发生错误;否则,返回实际读取的字节数。对

于字符型,要求读取的字节数和返回的实际读取字节数都必须是 in ode-i_blksize

的倍数。

• write,进行写操作,与read类似

• readdir,取得下一个目录入口点,只有与文件系统相关的设备程序才使用。

• select进行选择操作。如果驱动程序没有提供select入口,select操作会认为设 备已经准备好进行任何I/O操作。

† ioctl,进行读、写以外的其他操作,参数 cmd为自定义的命令

• mmap,用于把设备的内容映射到地址空间,一般只有块设备驱动程序使用

• open,打开设备准备进行I/O操作。返回0表示打开成功,返回负数表示失败。 如果驱动程序没有提供open入口,则只要/dev/driver文件存在就认为打开成功。

• release即 close 操作。

void kfree(void *obj);

参数len为希望申请的字节数;obj为要释放的内存指针;priority为分配内存操 作的优先级,即在没有足够空闲内存时如何操作,一般用 GFP_KERNEL。 file_operatio n结构中初始化为 NULL。file_operatio n变量会在驱动程序初始化时

注册到系统内部。当操作系统对设备操作时,

会调用驱动程序注册的file_operation结构中的函数指针。

Linux对中断的处理

在Linux系统里,对中断的处理是属于系统核心部分, 因而如果设别与系统之间

以中断方式进行数据交换,就必须把该设备的驱动程序作为系统核心的一部分。

设备驱动程序通过调用request_irq函数来申请中断,通过free_irq来释放中断。 它们被定义为:

# i nelude

int request_irq (un sig ned int irq,

void (*ha ndler)(i nt irq, void dev_id, struct pt_regs *regs),

un sig ned long flags,

const char *device,

void *dev_id);

void free_irq(un sig ned int irq, void *dev_id);

数irq表示所要申请的硬件中断号;handler为向系统登记的中断处理子程序, 中

断产生时由系统来调用,调用时所带参数 irq为中断号;dev_id

为申请时告诉系统的设备标识;regs为中断发生时的寄存器内容;device为设备

名,将会出现在/proc/interrupts文件里;flag是

申请时的选项,它决定中断处理程序的一些特性, 其中最重要的是中断处理程序

是快速处理程序还是慢速处理程序。快速处理程序运行时,所有中断都被屏蔽, 而慢

速处理程序运行时,除了正在处理的中断外,其他中断都没有被屏蔽。在 Linux

系统中,中断可以被不同的中断处理程序共享。

作为系统核心的一部分,设备驱动程序在申请和释放内存时不是调用 malloc和

free,而代之以调用kmalloc和kfree,它们被定义为:

#

i nclude

void *kmalloc(unsigned int len, int priority);

相关主题