<script>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>
作者:华清远见嵌入式学院。
在Linux操作系统下有3类主要的设备文件类型:块设备、字符设备和网络设备。这种分类方法可以将控制输入/输出设备的驱动程序与其他操作系统软件分离开来。
字符设备与块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般紧接着发生。块设备则不然,它利用一块系统内存作为缓冲区,若用户进程对设备的请求能满足用户的要求,就返回请求的数据;否则,就调用请求函数来进行实际的I/O操作。块设备主要是针对磁盘等慢速设备设计的,以免耗费过多的CPU时间用来等待。网络设备可以通过BSD套接口访问数据。
每个设备文件都有其文件属性(c/b),表示是字符设备还是块设备。另外每个文件都有2个设备号,第一个是主设备号,标识驱动程序;第二个是从设备号,标识使用同一个设备驱动程序的、不同的硬件设备。设备文件的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问驱动程序。
系统调用时操作系统内核与应用程序之间的接口,设备驱动程序是操作系统内核与机器硬件之间的接口。设备驱动程序是内核的一部分,它完成以下功能:
*对设备初始化和释放
*把数据从内核传送到硬件和从硬件读取数据
*读取应用程序传送给设备文件的数据和回送应用程序请求的数据
*检测和处理设备出现的错误
MTD(Memory Technology Device)设备是闪存芯片、小型闪存卡、记忆棒之类的设备,它们在嵌入式设备中的使用正在不断增加。MTD驱动程序是在Linux下专门为嵌入式环境开发的新的一类驱动程序。相对于常规块设备驱动程序,使用MTD驱动程序的优点在于他们能更好的支持、管理给予闪存设备,有基于扇区的擦除和读/写操作的更好的接口。
驱动程序结构
Linux的设备驱动程序可以分为3个主要组成部分:
1. 自动配置和初始化子程序,负责监测所要驱动的硬件设备是否存在和能否正常工作。如果该设备正常,则对这个设备及其相关的设备驱动程序需要的软件状态进行初始化。这部分驱动程序仅在初始化时被调用一次。
2. 服务于I/O请求的子程序,又称为驱动程序的上半部分。调用这部分程序是由于系统调用的结果。这部分程序在执行时,系统仍认为是与进行调用的进程属于同一个进程,只是由用户态变成了核心态,具有进行此系统调用的用户程序的运行环境,因而可以在其中调用sleep()等与进行运行环境有关的函数。
3. 中断服务子程序,又称为驱动程序的下半部分。在Linux系统中,并不是直接从中断向量表中调用设备驱动程序的中断服务子程序,而是由Linux系统来接收硬件中断,再由系统调用中断服务子程序。中断可以在任何一个进程运行时产生,因而在中断服务程序被调用时,不能依赖于任何进程的状态,也就不能调用任何与进程运行环境有关的函数。因为设备驱动程序一般支持同一类型的若干设备,所以一般在系统调用中断服务子程序时,都带有一个或多个参数,以唯一标识请求服务的设备。
在系统内部,I/O设备的存/取通过一组固定的入口点来进行,这组入口点是由每个设备的驱动程序提供的。具体到Linux系统,设备驱动程序所提供的这组入口点由一个文件操作结构来向系统进行说明。file_operation结构定义于linux/fs.h文件中。
struct file_operation{
int (*lseek)(struct inode *inode, struct file *filp, off_t off, int pos);
int (*read)(struct inode *inode, struct file *filp, char *buf, int count);
int (*write)(struct inode *inode, struct file *filp, const char *buf, int count);
int (*readdir)(struct inode *inode, struct file *filp, struct dirent *dirent, int count);
int (*select)(struct inode *inode, struct file *filp, int 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);
int (*fasync)(struct inode *inode, struct file *filp);
};
file_operation结构中的成员几乎全部是函数指针,所以实质上就是函数跳转表。每个进程对设备的操作都会根据major、minor设备号,转换成对file_operation结构的访问。
常用的操作包括以下几种:
*lseek, 移动文件指针的位置,只能用于可以随机存取的设备。
*read, 进行读操作,参数buf为存放读取结果的缓冲区,count为所要读取的数据长度。返回值为负表示读取操作发生错误;否则,返回实际读取的字节数。对于字符型,要求读取的字节数和返回的实际读取字节数都必须是inode-i_blksize的倍数。
*write, 进行写操作,与read类似
*readdir, 取得下一个目录入口点,只有与文件系统相关的设备程序才使用。
*select, 进行选择操作。如果驱动程序没有提供select入口,select操作会认为设备已经准备好进行任何I/O操作。
*ioctl, 进行读、写以外的其他操作,参数cmd为自定义的命令
*mmap, 用于把设备的内容映射到地址空间,一般只有块设备驱动程序使用
*open, 打开设备准备进行I/O操作。返回0表示打开成功,返回负数表示失败。如果驱动程序没有提供open入口,则只要/dev/driver文件存在就认为打开成功。
*release, 即close操作。
在用户自己的驱动程序中,首先要根据驱动程序的功能,完成file_operation结构中函数实现。不需要的函数接口可以直接在file_operation结构中初始化为NULL。file_operation变量会在驱动程序初始化时注册到系统内部。当操作系统对设备操作时,会调用驱动程序注册的file_operation结构中的函数指针。
Linux对中断的处理
在Linux系统里,对中断的处理是属于系统核心部分,因而如果设别与系统之间以中断方式进行数据交换,就必须把该设备的驱动程序作为系统核心的一部分。设备驱动程序通过调用request_irq函数来申请中断,通过free_irq来释放中断。它们被定义为:
#include
int request_irq(unsigned int irq,
void (*handler)(int irq, void dev_id, struct pt_regs *regs),
unsigned long flags,
const char *device,
void *dev_id);
void free_irq(unsigned int irq, void *dev_id);
参数irq表示所要申请的硬件中断号;handler为向系统登记的中断处理子程序,中断产生时由系统来调用,调用时所带参数irq为中断号;dev_id为申请时告诉系统的设备标识;regs为中断发生时的寄存器内容;device为设备名,将会出现在/proc/interrupts文件里;flag是申请时的选项,它决定中断处理程序的一些特性,其中最重要的是中断处理程序是快速处理程序还是慢速处理程序。快速处理程序运行时,所有中断都被屏蔽,而慢速处理程序运行时,除了正在处理的中断外,其他中断都没有被屏蔽。在Linux系统中,中断可以被不同的中断处理程序共享。
作为系统核心的一部分,设备驱动程序在申请和释放内存时不是调用malloc和free,而代之以调用kmalloc和kfree,它们被定义为:
#include
void *kmalloc(unsigned int len, int priority);
void kfree(void *obj);
参数len为希望申请的字节数;obj为要释放的内存指针;priority为分配内存操作的优先级,即在没有足够空闲内存时如何操作,一般用GFP_KERNEL。
分享到:
相关推荐
对于嵌入式开发需要移植linux的朋友建议看看,主要针对如何写嵌入式linux的驱动程序
最后,总结了嵌入式 Linux 驱动程序开发的要点。 知识点1:嵌入式 Linux 驱动程序结构 嵌入式 Linux 驱动程序是介于硬件和 Linux 内核之间的软件接口,是为特定硬件提供用户程序的一组标准化接口,对用户来说是不...
【Linux】嵌入式linux软件开发、嵌入式linux驱动开发、c语言、单片机开发、IOT开发等面试要点记录【PGJ】.zip 【Linux】嵌入式linux软件开发、嵌入式linux驱动开发、c语言、单片机开发、IOT开发等面试要点记录【PGJ...
在开发I.MX6U嵌入式Linux驱动时,需要了解的要点有很多。 首先,开发环境的搭建是驱动开发的前提。文档提到了Ubuntu系统的安装与入门,这对于在Linux环境下的驱动开发尤为关键。Ubuntu系统是一个广泛使用的Linux...
在嵌入式系统和ARM技术领域,嵌入式Linux驱动程序开发是至关重要的,它连接了硬件设备与操作系统,使得设备能够有效地与上层软件进行交互。Linux操作系统中,设备驱动程序主要分为三类:块设备、字符设备和网络设备...
因此,作者花费大量时间整理、编写本书,以期帮助读者更轻松地学习嵌入式Linux驱动开发的技术要点。 总体来说,本书内容全面、结构合理,将理论与实践紧密结合,深入浅出地介绍了嵌入式Linux驱动开发的关键知识点,...
《嵌入式Linux驱动程序设计从入门到精通》是一本深度探讨嵌入式系统中Linux驱动开发的专业书籍。源代码是学习此书的关键部分,它提供了理论知识与实践操作的结合,帮助读者深入理解并掌握驱动程序设计的技术要点。...
"嵌入式Linux设备驱动程序设计及其...本文提供了嵌入式Linux设备驱动程序设计和交叉编译的详细介绍和指导,旨在帮助开发者快速掌握嵌入式Linux设备驱动程序设计和交叉编译的技术,并开发出自己的嵌入式产品驱动程序。
从嵌入式处理器ARM开始,讲解了ARM处理器的资源、ARM的指令集、ADS开发工具、嵌入式系统硬件环境的构建、Bootloader、Linux内核移植、嵌入式文件系统、嵌入式Linux多任务程序开发、嵌入式Linux设备驱动开发、嵌入式...
从嵌入式处理器arm开始,讲解了arm处理器的资源、arm的指令集、ads开发工具、嵌入式系统硬件环境的构建、bootloader、linux内核移植、嵌入式文件系统、嵌入式linux多任务程序开发、嵌入式linux设备驱动开发、嵌入式...
嵌入式linux软件开发、嵌入式linux驱动开发、c语言、单片机开发、IOT开发等面试要点记录.zip 要点 c基础知识 数据结构(链表 hash表 排序算法 设计模式等) 外设(串口 网口 i2s i2c spi sdio等) ARM cortex-m0...
《嵌入式Linux应用开发完全手册》是一本详细介绍了嵌入式Linux系统开发全过程的技术书籍。作者韦东山通过该书向读者展示了如何从底层硬件支持到上层GUI应用的构建,涵盖了Linux操作系统的安装与使用、编程基础知识、...
嵌入式linux软件开发、嵌入式linux驱动开发、c语言、单片机开发、IOT开发等面试要点记录
在嵌入式Linux应用程序开发中,开发者需要理解Linux内核、文件系统、设备驱动、网络编程以及应用程序接口(API)等多个方面。 1. **Linux内核**:内核是操作系统的基石,负责管理硬件资源、进程调度、内存管理等。在...
总的来说,这本《嵌入式Linux应用程序开发详解》是一本全面覆盖了嵌入式Linux开发各个层面的教材,从环境配置到应用程序编写,再到设备驱动和图形界面,内容丰富且实用,适合初学者逐步掌握嵌入式Linux开发技能。...