现在的位置: 首页 > 综合 > 正文

字符设备驱动程序之二

2013年08月21日 ⁄ 综合 ⁄ 共 3062字 ⁄ 字号 评论关闭

4. 字符设备的注册

在内核调用设备的操作之前,必须分配并注册一个或多个struct cdev结构(在<linux/cdev.h>中定义)。

分配和初始化该结构有两种方式。如果在模块运行时需要获取一个独立的cdev结构,则应该编写如下代码:

struct cdev *my_cdev = cdev_alloc();

my_cdev->ops = &my_fops;

如果cdev结构需要嵌入到自己的设备特定结构中,就使用:

void cdev_init(struct cdev *dev, struct file_operations *fops);

在cdev结构设置好后,就可以调用如下函数告诉内核该结构的信息:

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

在使用cdev_add时,需要注意:一是这个调用可能会失败;二是只要cdev_add返回成功,就表明内核可以用该设备了。

从系统中移除一个字符设备:

void cdev_del(struct cdev *dev);

 

4.1. scddp中的设备注册

在scddp内部,是由下面这个结构来表示每个设备:

该结构需要被初始化并添加到系统中,代码如下:

  

4.2. 早期的设备注册

注册一个字符设备驱动程序的经典方式:

int register_chrdev(unsigned int major, const char*name,struct file_operations *fops);

从系统移除设备的对应函数是:

int unregister_chrdev(unsigned int major, const char*name);

 

5. open和release方法

5.1. open方法

open方法提供给驱动程序初始化的能力,完成的工作如下:

1) 检查设备特定的错误

2) 如果是首次打开,则对其进行初始化

3) 如有必要,初始化f_op指针

4) 分配并填写filep->private_data的数据结构

open方法原型:

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

我们通常不需要cdev结构,而是希望得到包含cdev结构的scddp结构。在这种情况下,内核帮助我们实现了此类技术,在<linux/kernel.h>中的container_of宏有实现。

container_of(pointer, container_type,container_field);

这个宏需要一个container_field字段的指针,该字段包含在container_type类型的结构中,然后返回包含该字段的结构指针。

另外一个确定要打开的设备的方法是:检查保存在inode结构中的次设备号。如果利用register_chrdev注册地设备,则必须使用该技术,而且一定要用iminor宏从inode结构中获取次设备号,并确保它对应于驱动程序真正准备打开的设备。

这段代码没有做什么工作,是因为scddp设备被设计为全局而持久。由于我们并不维护scddp的打开计数,而只维护模块的使用计数,因此没有类似"首次打开时要初始化设备"的工作。对设备唯一的实际操作是当设备以写方式打开时,它的长度将截为0。

 

5.2. release方法

relsease方法完成下面任务:

1) 释放由open分配、保存在filp->private_data中的所有内存

2) 在最后一次关闭操作时关闭设备

由于scddp没有需要关闭的硬件,因此代码简单:

int scddp_release(struct inode *inode, struct file *filp)

{

    return 0;

}

注意:并不是每个close系统调用都会引起对release方法的调用。内核对每个file结构维护其被使用多少次的计数器。无论是fork还是dup,都不会创建新的数据结构(进由open创建),只是增加已有结构的计数。只有在file结构的计数归为0时,close系统调用才会真正的调用release方法。同时,flush方法在应用程序每次调用close时都会被调用。

 

6. scddp内存使用

scddp使用的内存区域称为设备,其长度是可变的,写得越多,它就变得越长。Scddp驱动程序引入了Linux内核中用于内存管理的两个核心函数:

void *kmalloc(size_t size, inf flags);

void kfree(void *ptr);

在scddp中,每个设备都是一个指针链表,其中每个指针都指向一个scddp_qset结构:

下面是scddp_trim函数,负责释放整个数据区,并且在文件以写方式打开时由scddp_open调用。

模块的清除函数也调用scddp_trim函数,以把由scddp所使用的内存返回给系统。

 

 

 

抱歉!评论已关闭.