Linux内核设备驱动之字符设备驱动笔记整理

2019-01-16 20:44:33王振洲

unsigned int iminor(struct inode *inode) unsigned int imajor(struct inode *inode)

(4)字符设备的注册

内核内部使用struct cdev结构来表示一个字符设备。

我们的驱动要把自己的cdev注册到内核中去。见 <linux/cdev.h>

a.通常在设备的结构中加入cdev

struct scull_dev{ ... struct cdev cdev; /* 字符设备结构 */ }

b.初始化

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

c.设定cdev中的内容

dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &scull_fops;

d.向内核添加设定好的cdev

int cdev_add(struct cdev *dev, dev_t num, unsigned int count); //num: 设备对应的第一个编号 //count: 和设备关联的设备编号的数量,常取1 //一旦cdev_add返回,内核就认为设备可以使用了,所以要在调用之前完成设备的硬件初始化。

(5)老式的注册函数

2.4中的老式注册函数仍然在驱动函数中大量存在,但新的代码不应该使用这些代码。

注册:

int register_chrdev(unsigned int major, const char *name, struct file_operations *fops); //为给定的主设备号注册0~255作为次设备号,并为每个设备建立一个对应的默认cdev结构

注销:

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

(6)open和release

a.open

在驱动的open方法中完成设备的初始化工作,open完成后,硬件就可以使用,用户程序可以通过write等访问设备,open的工作有:

*检查设备的特定错误 *如果设备首次打开,则对其进行初始化(有可能多次调用open) *如有必要,更新f_op指针 *分配并填写置于filp->private_data中的数据

open原型;

int (*open) (struct inode *inode, struct file *filp); //在open中通过inode获得dev指针,并将其赋给file->private_data //struct scull_dev *dev; //dev = contain_of(inode->i_cdev, struct scull_dev, cdev); //filp->private_data = dev; //(如果dev是静态分配的,则在open或write等方法中可以直接访问dev,但如果dev是在module_init时动态分配的,则只能通过上面的方法获得其指针)

b.release

并不是每个close调用都会引起对release方法的调用,只有当file的计数器归零时,才会调用release,从而释放dev结构)

(7)read和write

read和write的工作是从用户空间拷贝数据到内核,或是将内核数据拷贝到用户空间。其原型为:

ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t *offp); ssize_t write(struct file *filp, const char __user *buff, size_t count, loff_t *offp); //buff: 用户空间的缓冲区指针 //offp: 用户在文件中进行存取操作的位置 //在read和write中,拷贝完数据后,应该更新offp,并将实际完成的拷贝字节数返回。