《linux设备驱动程序》第3章总结
来源:互联网 发布:登录淘宝要脸部拍摄 编辑:程序博客网 时间:2024/05/29 07:43
1 Scull的设计
书上没看懂 就搜了一下
Scull:scull(simple character utility for loading localities,"区域装载的简单字符工具")
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_fops4.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/
- 《linux设备驱动程序》第3章总结
- linux设备驱动程序第3,4章笔记
- linux 设备驱动程序第8章
- linux设备驱动程序第三版--第4章调试技术--读后总结
- linux设备驱动程序:第一章总结
- linux设备驱动程序第3版 ——第5章
- 《深入Linux设备驱动程序内核机制》第2章 字符设备驱动程序 V1.2
- 第二章 第三节 Linux设备驱动程序之--模块参数
- 第二章 第三节 Linux设备驱动程序之--模块参数
- LINUX设备驱动程序(第3版)[高清PDF]
- LINUX DEVICE DRIVER(2ND)第3章 字符设备驱动程序(1,待续)
- 《LINUX设备驱动程序》第3章(字符驱动)学习笔记
- LINUX DEVICE DRIVER(2ND)第3章 字符设备驱动程序(2,主设备号和次设备号)
- linux 设备驱动程序 时间流 总结
- LINUX字符设备驱动程序原理总结
- 《Linux设备驱动程序3》读书笔记
- linux设备驱动第一篇:设备驱动程序简介
- linux设备驱动第一篇:设备驱动程序简介
- spring boot 返回的json中去掉值为null的属性
- codeforces 237-C. Primes on Interval(尺取)
- 为RecyclerView添加ContextMenu
- 修改windows远程桌面端口
- app html5 上拉加载分页
- 《linux设备驱动程序》第3章总结
- SSM(四)WebService入门详解
- Error:Could not find com.android.tools.build:gradle:2.2.2.
- Two Sum IV
- Hibernate学习笔记—Hibernate4.3环境搭建
- linux下无法挂载ntfs硬盘解决方法
- 用Python和Pygame写游戏-从入门到精通(8)Move
- git diff 生成path
- SSM(五)基于webSocket的聊天室