设备驱动程序学习笔记(1)-字符设备的生命周期

By:             潘云登

Date:          2009-5-25

Email:         intrepyd@gmail.com

Homepage: http://blog.csdn.net/intrepyd

Copyright: 该文章版权由潘云登所有。可在非商业目的下任意传播和复制。

对于商业目的下对本文的任何行为需经作者同意。


写在前面

1.          本文内容对应《linux设备驱动程序》第三章。

2.          希望本文对您有所帮助,也欢迎您给我提意见和建议。


字符设备的生命周期

1.          分配设备编号

在内核中,dev_t类型(32位)用来保存设备编号,包括主设备号(12位)和次设备号(20位)。主设备号标识设备对应的驱动程序。次设备号由内核和驱动程序使用,用于正确确定设备文件所指的设备。主设备号和设备名称的对应关系记录在/proc/devices中。

MAJOR(dev_t dev);

MINOR(dev_t dev);

MKDEV(int major, int minor);

分配设备编号的方式有两种:一是根据Documentation/devices.txt文件,选取尚未分配的设备号,进行静态分配。

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

二是使用动态分配机制获取。其缺点是分配的主设备号不能保证始终一致,所以无法预先创建设备文件。

int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);

2.          实例化设备对象

即为描述设备的结构分配内存并初始化。在内核中,cdev是表示字符设备的内部结构,包含字符设备的共有信息,如设备号dev_t和文件操作file_operations。具体设备相关的个性信息可以存放在自定义的设备结构中,如scull_dev,其中包含cdev结构。

struct scull_dev {

         struct scull_qset *data;  /* Pointer to first quantum set*/

         int quantum;              /* the current quantum size */

         int qset;                 /* the current array size */

         unsigned long size;       /* amount of data stored here */

         unsigned int access_key;  /* used by sculluid and scullpriv */

         struct semaphore sem;     /* mutual exclusion semaphore     */

         struct cdev cdev;           /* Char device structure          */

};

3.          初始化并注册设备

在内核调用设备的操作之前,必须将设备cdev与文件操作关联起来,并向内核注册设备结构cdev。注意,内核只认识字符设备的共有信息cdev,而不关心与具体设备相关的信息,如scull_dev

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

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

注册完成后,设备的操作就会被内核调用。在此之前,必须完全准备好处理设备上的操作。

4.          创建设备文件

通过手工执行mknod命令,或者通过mknod系统调用创建设备文件。在内核中,由inode结构表示,其中包含了设备编号dev_t和字符设备结构cdev。将设备虚拟化为文件,可以统一应用程序访问设备的接口,保持系统调用的精简。

设备号dev_t,设备cdev以及设备文件inode之间是一一对应关系。

5.          操作字符设备

应用程序通过系统调用,执行驱动程序定义的文件操作,从而完成对设备的访问。这些操作并不直接访问设备文件inode,而是访问一个称为文件描述符的file结构。该结构在打开设备文件时创建。可以有多个文件描述符file对应同一个设备文件inode,从而实现多个进程对单个设备的共享。

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

int (*release) (struct inode *, struct file *);

ssize_t (*read) (struct file *, char _ _user *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char _ _user *, size_t, loff_t *);

因为在对设备进行读写操作时没有传入inode,所以需要在打开设备时,即open操作中,将cdev的指针或者将包含设备个性信息的自定义结构指针赋给文件描述符file中的private_data字段。当然,也可以通过file->dentry->inode->cdev访问。

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

{

    struct scull_dev *dev; /* device information */

 

    dev = container_of(inode->i_cdev, struct scull_dev, cdev);

    filp->private_data = dev; /* for other methods */

    …….

}

6.          卸载字符设备

当字符设备的生命走到尽头时,应当以与创建设备相反的顺序,先向内核注销设备结构,然后释放设备编号。

void cdev_del(struct cdev *dev);

void unregister_chrdev_region(dev_t first, unsigned int count);


主要数据结构的关系

 主要数据结构的关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值