第三章 三个数据结构以及字符设备的注册

      上一篇讲到了注册设备编号,显然,注册设备编号只是编写驱动代码的第一个步骤。为了完成以后的一些步骤,先介绍三个重要的内核数据结构。

       file_operation囊括了所有设备操作到设备号的链接。在linux中驱动以文件的方式存在,而file_operation则是对文件(这里是是字符设备)的所有操作的集合。由于file_operation的成员太多,而当前scull项目仅仅用到了其中的几个。 scull项目的file_operation初始化如下:

1 struct file_operations scull_fops = {
2 .owner = THIS_MODULE,
3 .llseek = scull_llseek,
4 .read = scull_read,
5 .write = scull_write,
6 .ioctl = scull_ioctl,
7 .open = scull_open,
8 .release = scull_release,
9 };

  owner指向拥有这个结构的模块,几乎所有情况下,它的值都是THIS_MODULE,这是一个定义在<linux/module.h>中的宏;llseek 方法用作改变文件中的当前读/写位置, 并且新位置作为(正的)返回值;read用来从设备中获取数据;write用来发送数据给设备;.ioctl 用来发出设备特定命令(非read或write);open为打开设备文件,显然这应该是对设备文件进行的第一个操作;.release 释放文件结构。

       file数据结构代表一个打开的文件(记住设备被当做了文件)。如同file_operation指定了操作的集合,file就是这些操作的目标对象了。

      inode数据结构也表示文件,不过他跟file数据结构不同(估计这个区别以后才能了解)。对于编写驱动来说,这个数据结构就两个字段有用。dev_t i_rdev代表设备编号,struct cdev *i_cdev;代表一个字符设备。详细的信息到使用的时候再深入研究。

      要说明的是,linux源代码在初始化这些数据结构的时候一般都是用c语言的标记式结构初始化语法。

      linux内核在内部使用类型struct cdev来代表字符设备。而在scull中,使用一个自定义的struct scull_dev类型的

结构来表示每个设备,这个结构包括了一个struct cdev结构:

1 struct scull_dev {
2 struct scull_qset *data; /* Pointer to first quantum set */
3 int quantum; /* the current quantum size */
4 int qset; /* the current array size */
5 unsigned long size; /* amount of data stored here */
6 unsigned int access_key; /* used by sculluid and scullpriv */
7 struct semaphore sem; /* mutual exclusion semaphore */
8 struct cdev cdev; /* Char device structure */
9 };

  初始化这一结构并注册的函数如下:

 1 static void scull_setup_cdev(struct scull_dev *dev, int index)
2 {
3 int err, devno = MKDEV(scull_major, scull_minor + index);
4 cdev_init(&dev->cdev, &scull_fops);
5 dev->cdev.owner = THIS_MODULE;
6 dev->cdev.ops = &scull_fops;
7 err = cdev_add (&dev->cdev, devno, 1);
8 /* Fail gracefully if need be */
9 if (err)
10 printk(KERN_NOTICE "Error %d adding scull%d", err, index);
11 }

  这样就完成了一个字符设备的初始化和注册。

posted @ 2011-07-30 16:25  自由泳的青蛙  阅读(409)  评论(0编辑  收藏  举报