没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
Linux 添加字符设备驱动程序
摘要
Linux 作为一个开放的操作系统已经得到了越来越多人的认可与使用,成为全球使用率
仅次于 windows 的操作系统,并且在服务器领域,Linux 的使用频率要大于 windows,这些
归功与其开源的理念和无数 Linux 爱好者的贡献。Linux 的开放不仅体现在其开源的理念,
也体现在系统本身设计的方方面面,本文以 Ubuntu 12.04 为例,从设备驱动程序这一点入
手,通过向 Linux 添加一个字符设备驱动程序来了解 Linux 设备驱动程序的工作原理,从而
加深对 Linux 操作系统进一步的认识。其中设备驱动程序是被作为内核模块而动态的添加到
系统中去的,所以在实验前要对内核模块的加载有基本的了解。
【关键词】 Linux 内核模块 字符设备驱动程序
1. 基本原理概述
1.1 内核模块
模块是在内核空间运行的程序,实际上是一种目标文件,不能单独运行,但其代码可
以在运行时链接到系统中作为内核的一部分。Linux 内核模块是一种特有的机制,它由一组
函数和数据结构组成,可以作为独立程序来编译,当模块被安装时,它被链接到内核中。
模块在启动的时候进行安装,称为静态加载;也可以在系统运行时进行安装,称为动态加
载。模块的主要作用是动态的增加或减少内核功能,Linux 内核提供了一种称为可加载内核
模块(Loadable Kernel Modules, LKM)机制,它让一个文件系统或设备驱动程序以内核模
块的形式加载到内核空间去运行,通过模块机制来实现系统运行时对内核功能的动态扩充,
就能大大提高单内核操作系统的灵活性与可扩展性。
内核模块一般包括头文件声明,模块许可声明,初始化和清理函数声明几个部分,编
译内核模块一般使用 Makele 文件来实现,当模块被编译好了以后可以使用 insmod 命令把
需要加载的模块以目标代码的形式加载进内核中,该命令自动调用 modules_init()函数中定
义的过程运行,使用 rmmod 命令将已经加载到内核的模块从内核中卸载,该命令自动调用
modules_exit()函数中定义的过程运行。
初始化函数定义:
static int _init init_func(void)
{
/*初始化代码*/
}
modules_init(init_func);
清理函数定义:
static void_exit exit_func(void)
{
/*清理代码*/
}
modules_exit(exit_func);
1.2 字符设备
Linux 函数(系统调用)是应用程序和操作系统内核之间的接口,而设备驱动程序是
内核和硬件设备之间的接口,设备驱动程序屏蔽硬件细节,且设备被映射成特殊的文件进
行处理。每一个设备文件都对应一个文件名。此外,设备文件也和普通文件一样,受到文
件系统访问权限机制的保护。
Linux 将硬件设备分成两大类:块设备和字符设备。字符设备支持面向字符的 I/O 操
作,即逐个字符进行 I/O 操作,不经过系统的 I/O 缓冲区,所以需要管理自己的缓冲区结
构。
1.2.1 数据结构
在字符设备驱动程序中,主要涉及 3 个重要的内核数据结构,分别是
le_operation,
le 和 inode。内核通过这 3 个数据结构的关联,将用户对设备文件的操作转换为对驱动
程序相关函数的调用,进而实现对设备的驱动操作。
le_operation 是一组函数指针集合,在内核中,通过包含一个指向 le_oparation
的 f_op 字段,每个打开的设备文件都会与一组文件操作函数相关联,如
open(),release(),read(),write(),ioctl()等。
le 结构是驱动程序需要使用的第二个重要数据结构,le 代表一个打开了的文件。它
由内核在使用 open 函数时建立,并传递给该文件上进行操作的所有函数,直到最后的
close()函数。当文件的所有操作结束后,内核会释放该数据结构。
内核用 inode 结构在内部标识文件,它和 le 的结构不同,后者标识打开的文件描述
符,对于单个文件可能会有多个表示打开的文件描述符的 le 结构,但它们都指向同一个
inode 结构。
1.2.2 申请和释放设备编号
在创建字符设备之前,需要给设备申请设备编号。静态申请设备编号的内核函数为
register_chrdev_region(),其原型为:
int register_chrdev_region(dev_t from,unsigned count,const char *name);
动态申请块设备的内核函数原型为:
int alloc_chrdev_region(dev_t*dev,unsinged baseminor,unsigned
count,const char*name)
动态申请和静态申请都采用 unregister_chrdev)region()释放设备编号,该内核函
数原型为:
void unregister_chrdev_region(dev_t from,unsigned count);
1.2.3 设备注册与注销
内核用 cdev 结构来标识字符设备,在内核调用设备的驱动操作之前,必须分配并注
册一个上述结构,分配和初始化 cdev 结构有两种方式,如果打算在运行时获得一个独立
的 cdev 结构,可以采用如下代码:
struct cdev*my_cdev=cdev_alloc();
my_cdev->ops=&my_fops;
剩余10页未读,继续阅读
资源评论
juryoo
- 粉丝: 101
- 资源: 3
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功