当前位置:文档之家› 6-1 Linux驱动程序

6-1 Linux驱动程序

6
Linux设备基本知识
Linux的设备驱动程序通常在“/dev”下面存在一个 对应的逻辑设备节点。
主设备号 次设备号
c:字符设备
b:块设备
7
Linux设备分类
Linux 系统的设备文件分为四类:块设备文件、字 符设备文件、网络设备文件和杂项设备文件。 块设备:以块(如512字节)方式访问的设备, 如IDE硬盘、SCSI硬盘、光驱等; 字符型设备:可直接读写、没有缓冲区的设备, 如并口、虚拟控制台等;
13
设备驱动程序与外界接口
设备驱动程序与外界的接口可分为三个部分: 与操作系统内核的接口:这部分是通过数据结 构 file_operations来完成的。
与系统引导的接口:这部分利用驱动程序对设 备进行初始化。
与设备的接口:这部分描述了驱动程序如何与 设备进行交互,这与具体设备密切相关。
18
卸载模块
#rmmod hello.o
执行cleanup函数指针所指向的函数,主要是完成清 理干净该模块在内核中的垃圾 将hello模块代码清除出内核 将描述hello模块的变量从链表中删除
19
模块其他信息
常用信息有:作者、描述、版权等。 MODULE_AUTHOR("author"); MODULE_DESCRIPTION("the description");
Linux系统下有关主设备号的分配原则,可参看 documentation/device.txt。
10
内核模块
Linux驱动程序可通过两种方式集成到内核中去:
直接编译到内核;
随时调用,但占内核空间, 修改驱动要重新编译内核。
编写成模块,需要时内核将其调入。在配置 Linux内核时,可以选择“Enable loadable module support”选项,来支持可加载内核模块。
file_operations示例
file_operations包含了很多操作,但是用到的不多。例如 Linux中断实例中的文件操作定义如下: static struct file_operations key_fops { owner:THIS_MODULE, read:key_read, open:key_open, release:key_release, };
第6章 嵌入式Linux驱动程序开发
设备驱动程序
设备驱动就是“驱使硬件设备行动”:与底层硬 件直接打交道,按照硬件设备的具体工作方式读写 设备寄存器,完成设备的轮询、中断处理、DMA通纽带(接口), 在有操作系统情况下,设备驱动是硬件与操作系统 内核之间的接口,应按照相应的架构设计设备驱动, 才能方便整合到相应的操作系统中。
20
设备驱动相关数据结构
三个重要数据结构,在“include/linux/fs.h”中定义 :
file_operations(文件操作) file(文件)
inode(节点)
由于用户进程是通过设备文件同硬件打交道,对 设备文件的操作方式Linux同样也做出了一系列规范。
21
file_operations结构
file_operations:驱动模块提供的对设备进行操作 的函数指针,也就是设备驱动程序的入口点。
22
file_operations常用成员-1
struct module *owner; 指向拥有本模块的指针,该成员被使用时不允许卸 载模块,通常被初始化为THIS_MODULE。
23
file_operations常用成员-2
const struct file_operations *f_op;
前面介绍的文件操作。内核在执行open操作时对这个指针赋 值,以后需要处理这些操作时就读这个指针。
unsigned int f_flags; 文件标志,如O_RDWD、O_RDONLY、O_NONBLOCK和 O_SYNC。驱动程序应该检查O_NONBLOCK标志判断是否 为非阻塞操作请求。注意,读写权限通过f_mode成员检查而 不是f_flags。
14
Linux设备驱动程序的特点
内核代码
内核接口 内核机制和服务 可装载 可设置 动态性
15
驱动开发流程
设计模块时必须遵循Linux的标准,否则无法通过insmod 加入到内核中。 应用程序用main函数作为程序的入口点,驱动模块则是在 insmod时被加载,此时的入口点是init_module函数,完成设 备的注册。在 rmmod时被卸载,此时的入口点是 cleanup_module函数,完成设备的卸载。 在设备完成注册加载之后,应用程序就可以对该设备进行 规定的操作,如read、write等,而驱动程序就是用于实现这 些操作。注:init_module入口点函数不完成这些操作。
16
驱动开发流程
内核模块一般都至少包含两个函数:初始化函数和卸载函 数,其它函数则跟设备相关。 宏module_init和module_exit用于注册初始化函数和卸载函 数。
17
加载模块
#insmod hello.o(以hello.o为例)
将hello.o代码复制到内核 创建struct module变量,并为相应成员变量赋值,其中 name为模块名hello,init函数指针指向hello_init函数, cleanup函数指针指向hello_exit函数 执行init函数指针所指向的函数
2
驱动程序的功能
从应用程序方看,驱动程序应为应用程序提供访问 硬件设备的编程接口,主要提供以下功能: 从驱动开发人员看,驱动程序是直接操控硬件的软 应用程序通过驱动程序安全有效地访问硬件; 件,主要完成以下功能: 驱动程序隐藏底层细节,从而提高应用软件的可 初始化和释放设备; 移植性和可复用性; 直接读写硬件寄存器来控制硬件; 驱动程序文件节点可方便地提供访问权限控制。 实现内核与硬件之间的数据交换; 操作设备缓冲区; 操作输入、输出设备,如键盘、打印机等; 实现应用程序与设备之间的数据交换; 检测和处理设备出现的错误。 3
嵌入式Linux驱动基本原理
Linux中的设备大多数是被当做文件(称为设备文 件)来处理。上层的应用程序需要操作硬件时,只需 要获得设备的文件描述符,通过系统调用open(), read(),write(),ioctl(),close()等来操作设备,无 需关心硬件细节。
4
嵌入式Linux驱动基本原理
调用设备读写以外的一些命令。内核识别一部分ioctl命令, 如果没提供ioctl入口点,又不是内核定义的请求,ioctl系统 调用将返回-EINVAL。
int (*mmap) (struct file *, struct vm_area_struct *);
将设备内存映射到进程内存中,为NULL时,mmap系统调 用将返回-ENODEV错误信息。
25
file_operations常用成员-4
int (*open) (struct inode *, struct file *);
打开设备,如果为NULL,设备的打开操作永远成功。
int (*release) (struct inode *, struct file *);
关闭设备节点。
26
网络设备:网络设备访问的 BSD socket接口, 如网卡等;
杂项设备:特殊驱动程序,如IIC、USB等。
8
Linux设备号
设备号是一个数字,是设备的标志,由主设备号 和次设备号组成,主设备号表明某一类设备,主设 备号相同的设备使用相同的驱动程序;次设备号用 来标识具体设备的实例。
例如,系统中块设备IDE 硬盘的主设备号是 3, 而多个 IDE 硬盘及其各个分区分别赋予次设备号1、 2、……
29
file常用成员-2
fmode_t f_mode;
文件属性,可读、可写或者可读可写的,通过位 FMODE_READ和FMODE_WRITE实现。
loff_t f_pos;
当前读写位置。如果需要知道当前在文件中的位置,驱动程 序可以读该值,但是不应该改变该值。
一个设备文件(即设备节点)可通过mknod命令 来创建。如:mknod /dev/led c 200 0
9
Linux设备号
根据主、次设备号,可用宏MKDEV() 来合成设备号。该 宏在include/linux/kdev_t.h中定义: #define MKDEV(ma,mi) ((ma)<<8 | (mi)) 根据设备号,可用宏MAJOR()和MINOR()将主、次设备 号分离出来。该宏定义如下: #define MAJOR(dev) #define MINOR(dev) ((dev)>>8) ((dev) & 0xff)
按需调用,寻找驱动模块时会增加 一些系统资源的占用和运行时间但 可忽略,可动态地卸载旧版本并加 载新版本,而不用重新编译内核。
11
内核模块管理命令
可加载的内核模块通常情况下安装在系统“/lib/modules” 目录的一个子目录下。用户可通过模块操作命令来对模块 进行管理。
12
驱动层次结构
Linux 设备驱动程序包含设备服务子程 序和中断处理程序两部分: 设备服务子程序:包含所有与设备操 作相关的处理代码。它从面向用户进程 的设备文件系统中接受用户命令,并对 设备控制器执行操作。 中断处理程序:设备控制器需要获得 系统服务时有两种方式:查询和中断。 驱动程序是内核的一部分,在设备查询 期间系统不能运行其他代码,工作效率 比较低,故大多设备以中断方式向设备 驱动程序发出输入/输出请求。
27
file结构
file结构,即文件结构,代表一个打开的文件描述符,它不 同于应用程序空间的FILE指针,FILE指针定义在C库中, struct file只出现在内核代码中,不出现在用户程序中。
相关主题