驱动开发之始,(二)字符设备驱动——Part1驱动模型

字符设备驱动将会分为三个部分,Part1:宏观上了解驱动模型,Part2:具体分析其中重要的三个数据结构,文件操作集file_operations,文件file以及inode结构。Part3:用一个简单的实例来演示字符设备驱动的实现

字符设备是面向字节流的方式,一个字节一个字节传输数据的设备,通常是按照先后顺序传递,常见的字符设备有鼠标、键盘、串口等设备。

对字符设备的访问是通过文件系统内的设备名称进行的。设备文件为文件系统树的节点,通常位于/dev目录下。

1.主设备号与次设备号

主设备号标示设备对应的驱动程序,例如/dev/rtc0由驱动程序251管理

次设备号由内核使用,用于正确确定设备文件所指的设备

2.设备号的内部表达

在内核中,dev_t类型(在<linux/types.h>中定义)用来保存设备号——包括主设备号和次设备号

typedef unsigned int __u32;
typedef __u32 __kernel_dev_t;
typedef __kernel_dev_t	dev_t;

在<linux/kdev_t.h>中定义的宏,用于获取dev_t的主设备号和次设备号

#define MINORBITS	20
#define MINORMASK	((1U << MINORBITS) - 1)

#define MAJOR(dev)	((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev)	((unsigned int) ((dev) & MINORMASK))

dev_t是一个32位的数,其中的12位用来表示主设备号,其余20位用来标示次设备号。如果知道主设备号和次设备号可以转换成dev_t类型

#define MKDEV(ma,mi)	(((ma) << MINORBITS) | (mi))

下面我们整体上认识一下字符设备驱动模型组成结构,随后再一个个分析

3.分配和释放设备号

在<linux/fs.h>中声明,静态申请设备号的方式:

int register_chrdev_region(dev_t from, unsigned count, const char *name);

函数参数说明

 @from: the first in the desired range of device numbers; must include the major number.
 @count: the number of consecutive device numbers required
 @name: the name of the device or driver.
 函数返回值:
 Return value is zero on success, a negative error code on failure.

在<linux/fs.h>中声明,动态分配备号的方式:

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

函数参数说明: 

@dev: output parameter for first assigned number
@baseminor: first of the requested range of minor numbers
@count: the number of minor numbers required
@name: the name of the associated device or driver
函数返回值:
Allocates a range of char device numbers.  The major number will be chosen dynamically, and returned (along with the first minor number)
in @dev.  Returns zero or a negative error code.
不论采用哪种方式分配的设备号,都应该在不再使用的时候释放这些设备号,及释放设备号函数

void unregister_chrdev_region(dev_t from, unsigned count)

函数参数说明: 

@from: the first in the range of numbers to unregister
@count: the number of device numbers to unregister
函数返回值:
This function will unregister a range of @count device numbers, starting with @from.  The caller should normally be the one who allocated those numbers in the first place...
 4.字符设备的注册

在用户空间可访问上述设备号之前,驱动程序需要将设备号和内部函数连接起来,这些内部函数用来实现设备的操作。内核使用struct cdev结构来表示字符设备。在<linux/cdev.h>中使用下面代码来获取一个cdev 结构

struct cdev *cdev_alloc(void)

这时,初始化已分配到的cdev结构,将cdev与file_operations关联起来

void cdev_init(struct cdev *cdev, const struct file_operations *fops)

函数参数说明:

 @cdev: the structure to initialize
 @fops: the file_operations for this device

cdev结构设置后,需要添加到系统,告诉内核该结构的信息:

int cdev_add(struct cdev *p, dev_t dev, unsigned count)

函数参数说明:

 @p: the cdev structure for the device
 @dev: the first device number for which this device is responsible
 @count: the number of consecutive minor numbers corresponding to this device

函数返回值:

cdev_add() adds the device represented by @p to the system, making it live immediately.  A negative error code is returned on failure.

注意:这个调用可能失败,如果它返回一个负的错误码,则设备不会添加到系统中。

最后,将cdev结构从系统中删除:

void cdev_del(struct cdev *p)

函数参数说明:

@p: the cdev structure to be removed

本章小结:

在Linux字符设备驱动中:

a.模块加载通过register_chrdev_region()或alloc_chrdev_region()来静态或动态获取设备号

b.通过cdev_alloc()获取设备结构

   通过cdev_init()初始化cdev结构,建立cdev与file_operations间的连接

   通过cdev_add()注册,向内核注册一个cdev结构,建立cdev与dev_t间的联系

c.模块卸载cdev_del()来注销cdev,通过unregister_chrdev_region()来释放设备号

用户空间访问该字符设备:

通过系统调用,如open、read、write来实现字符设备驱动在file_operations的接口

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值