《linux设备驱动程序》第3章总结

来源:互联网 发布:登录淘宝要脸部拍摄 编辑:程序博客网 时间:2024/05/29 07:43
第3章字符驱动
1  Scull的设计
书上没看懂  就搜了一下

Scull:scull(simple character utility for loading localities,"区域装载的简单字符工具")


2    主次编号

2.1 每个驱动都有主次编号,由编号来控制设备驱动


主编号标识相连的驱动,

次编号由内核分配的指针来决定引用哪个设备

主次编号都在<linux/types.h>里

2.2 如果想获得一个dev_t的主次编号使用:

# <linux/kdev_t.h>

MAJOR(dev_t dev)

MINOR(dev_t dev)

相反转换一个dev_t 使用:

     MKDEV(int major,int minor)
2.3分配和释放设备
知道设备编号使用:

#<linux/fs.h>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)
当你不使用设备编号时  要释放掉

void unregister_chrdev_region(dev_t first,unsigned int count)

3一些重要的数据结构
注册设备编号只是第1步,还包括file_operations,file,inode
3.1 file_operations
是一个字符驱动如何建立连接的结构,定义在<linux/fs.h>里,是1个函数指针集合,结构中每个成员必须指向驱动中的函数
3.2 file(文件结构)
struct file 定义于<linux/fs.h>,是设备驱动中第二个最重要的数据结构,是内核结构,不出现在用户程序中
struct file中一些成员:
mode_t f_mode;文件模式是可读或者可写
loff_t f_pos;当前读写位置
unsigned int f_flags;文件标志
struct file_operations *f_op;内核安排指针为它的open而用
void *private_data;open系统调用这个指针为null
struct dentry *f_debtry;关联到文件的目录入口(dentry)结构
3.3 inode 结构
inode 只有2个成员对编写驱动代码有用:
dev_t  i_rdev;
代表设备文件节点,包含实际的设备编号
struct cdev *i_cdev;
struct cdev是内核内部结构,代表字符设备


4字符设备注册
4.1 分配和初始化这些结构

#<linux/cdev.h>struct cdev *my_cdev = cdev_alloc();my_cdev -> ops = &my_fops
4.2 如果嵌入设备特定的结构,使用

void cdev_init(struct cdev *cdev,struct file_operations *fops);
4.3 建立之后告诉内核,调用:

int cdev_add(struct cdev *dev,dev_t num,unsigned int count);
4.4 去除一个字符设备
void cdev_del(struct cdev *dev);

5 open和release
5.1 open方法在初始化之后准备后续的操作,包括
检查设备特定的错误
如果它第一次打开,初始化设备
如果需要,更新f_op指针
分配并填充要放进filp->private_data的任何数据结构
5.2 Open方法原型:

int (*open)(struct inode *inode,struct file *file);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 *//* now trim to 0 the length of the device if open was write-only */if ( (filp->f_flags & O_ACCMODE) == O_WRONLY){scull_trim(dev); /* ignore errors */}return 0; /* success */}


5.3 release方法和open相反,相当于关闭设备

int scull_release(struct inode *inode, struct file *filp){return 0;}

6 scull的内存使用


7读和写
7.1 读和写的原型

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);
7.2给read的参数方法:


ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos){struct scull_dev *dev = filp->private_data;struct scull_qset *dptr; /* the first listitem */int quantum = dev->quantum, qset = dev->qset;int itemsize = quantum * qset; /* how many bytes in the listitem */int item, s_pos, q_pos, rest;ssize_t retval = 0;if (down_interruptible(&dev->sem)return -ERESTARTSYS;if (*f_pos >= dev->size)goto out;if (*f_pos + count > dev->size)count = dev->size - *f_pos;/* find listitem, qset index, and offset in the quantum */item = (long)*f_pos / itemsize;rest = (long)*f_pos % itemsize;s_pos = rest / quantum;q_pos = rest % quantum;/* follow the list up to the right position (defined elsewhere) */dptr = scull_follow(dev, item);if (dptr == NULL || !dptr->data || ! dptr->data[s_pos])goto out; /* don't fill holes *//* read only up to the end of this quantum */if (count > quantum - q_pos)count = quantum - q_pos;if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)){retval = -EFAULT;goto out;}*f_pos += count;retval = count;out:up(&dev->sem);return retval;}


7.3 write方法

ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){struct scull_dev *dev = filp->private_data;struct scull_qset *dptr;int quantum = dev->quantum, qset = dev->qset;int itemsize = quantum * qset;int item, s_pos, q_pos, rest;ssize_t retval = -ENOMEM; /* value used in "goto out" statements */if (down_interruptible(&dev->sem))return -ERESTARTSYS;/* find listitem, qset index and offset in the quantum */item = (long)*f_pos / itemsize;rest = (long)*f_pos % itemsize;s_pos = rest / quantum;q_pos = rest % quantum;/* follow the list up to the right position */dptr = scull_follow(dev, item);if (dptr == NULL)goto out;if (!dptr->data){dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);if (!dptr->data)goto out;memset(dptr->data, 0, qset * sizeof(char *));}if (!dptr->data[s_pos]){dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);if (!dptr->data[s_pos])goto out;}/* write only up to the end of this quantum */if (count > quantum - q_pos)count = quantum - q_pos;if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)){retval = -EFAULT;goto out;}*f_pos += count;retval = count;/* update the size */if (dev->size < *f_pos)dev->size = *f_pos;out:up(&dev->sem);return retval;}
8使用新设备
一旦你装备好刚刚描述的 4 个方法, 驱动可以编译并测试了

9具体代码可以参考博客:

http://blog.csdn.net/yusiguyuan/article/details/10960519
http://mm1010114626.blog.163.com/blog/static/1640922492011510114536456/



阅读全文
0 0
原创粉丝点击