字符设备的内核抽象[转]

顾名思义,字符设备驱动程序管理的核心对象是字符设备。从字符设备驱动程序的设计框架角度出发,内核为字符设备抽象出了一个具体的数据结构struct cdev,其定义如下:

<include/linux/cdev.h>

复制代码
 1 struct cdev {
 2 
 3        struct kobject kobj;
 4 
 5        struct module *owner;
 6 
 7        const struct file_operations *ops;
 8 
 9        struct list_head list;
10 
11        dev_t dev;
12 
13        unsigned int count;
14 
15 };
复制代码

在本章后续的内容中将陆续看到它们的实际用法,这里只把这些成员的作用简单描述如下:

struct kobject kobj

内嵌的内核对象,其用途将在“Linux设备驱动模型一章中讨论。

 

struct module *owner

字符设备驱动程序所在的内核模块对象指针。

 

const struct file_operations *ops

字符设备驱动程序中一个极其关键的数据结构,在应用程序通过文件系统接口呼叫到设备驱动程序中实现的文件操作类函数的过程中,ops指针起着桥梁纽带的作用。

 

struct list_head list

用来将系统中的字符设备形成链表。

 

dev_t dev

字符设备的设备号,由主设备号和次设备号构成。

 

unsigned int count

隶属于同一主设备号的次设备号的个数,用于表示由当前设备驱动程序控制的实际同类设备的数量。

 

 

设备驱动程序中可以用两种方式来产生struct cdev对象。一是静态定义的方式,比如在前面的那个示例程序中,通过下列代码静态定义了一个struct cdev对象:

static struct cdev chr_dev;

另一种是在程序的执行期通过动态分配的方式产生,比如:

static struct cdev *p = kmalloc(sizeof(struct cdev), GFP_KERNEL);

其实Linux内核源码中提供了一个函数cdev_alloc,专门用于动态分配struct cdev对象。cdev_alloc不仅会为struct cdev对象分配内存空间,还会对该对象进行必要的初始化:

<fs/char_dev.c>

复制代码
 1 struct cdev *cdev_alloc(void)
 2 
 3 {
 4 
 5        struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
 6 
 7        if (p) {
 8 
 9               INIT_LIST_HEAD(&p->list);
10 
11               kobject_init(&p->kobj, &ktype_cdev_dynamic);
12 
13        }
14 
15        return p;
16 
17 }
复制代码

 

需要注意的是,内核引入struct cdev数据结构作为字符设备的抽象,仅仅是为了满足系统对字符设备驱动程序框架结构设计的需要,现实中一个具体的字符硬件设备的数据结构的抽象往往要复杂得多,在这种情况下struct cdev常常作为一种内嵌的成员变量出现在实际设备的数据机构中,比如:

复制代码
 1 struct my_keypad_dev{
 2 
 3        //硬件相关的成员变量
 4 
 5        int a;
 6 
 7        int b;
 8 
 9        int c;
10 
1112 
13        //内嵌的struct cdev数据结构
14 
15        struct cdev cdev;
16 
17 };
复制代码

在这样的情况下,如果要动态分配一个struct real_char_dev对象,cdev_alloc函数显然就无能为力了,此时只能使用下面的方法:

static struct real_char_dev *p = kmalloc(sizeof(struct real_char_dev), GFP_KERNEL);

 

 

前面讨论了如何分配一个struct cdev对象,接下来的一个话题是如何初始化一个cdev对象,内核为此提供的函数是cdev_init

<fs/char_dev.c>

复制代码
 1 void cdev_init(struct cdev *cdev, const struct file_operations *fops)
 2 
 3 {
 4 
 5        memset(cdev, 0, sizeof *cdev);
 6 
 7        INIT_LIST_HEAD(&cdev->list);
 8 
 9        kobject_init(&cdev->kobj, &ktype_cdev_default);
10 
11        cdev->ops = fops;
12 
13 }
复制代码

函数的代码非常直白,不再赘述。一个struct cdev对象在被最终加入系统前,都应该被初始化,无论是直接通过cdev_init或者是其他途径。理由很简单,这是Linux系统中字符设备驱动程序框架设计的需要。

照理在谈完cdev对象的分配和初始化之后,下面应该讨论如何将一个cdev对象加入到系统了,但是由于这个过程需要用到设备号相关的技术点,所以暂且先来探讨设备号的问题。

 

——本段文字节选自《深入Linux设备驱动程序内核机制》

图书详细信息:http://blog.chinaunix.net/space.php?uid=13164110&do=blog&id=3078991

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值