linux驱动开发--字符设备:添加文件指针偏移的功能
来源:互联网 发布:马士兵java源代码 编辑:程序博客网 时间:2024/05/18 16:38
设备移位操作llseek
对应lseek系统调用的设备移位操作为llseek
默认情况为允许设备移位操作
大部分字符设备提供的都是数据流而不是一个数据区,比如串口,对于这些设备而言移位操作毫无意义
设备可选择是否支持移位操作
支持设备移位操作
loff_t (*llseek)(struct file *filp, loff_t off, int whence);
filp:待操作的设备文件file结构体指针
off:待操作的定位偏移值(可正可负)
whence:待操作的定位起始位置
返回:返回移位后的新文件读、写位置,并且新位置总为正值
定位起始位置
SEEK_SET:0,表示文件开头
SEEK_CUR:1,表示当前位置
完成设备移位操作函数
应该检查用户请求的定位操作合法性,若不合法,应该返回-EINVAL
在读、写操作中完成读、写更新文件位置
定义新位置变量
switch(whence)重新计算新位置
判断如果新位置为负或超过缓冲区最大值返回-EINVAL
用新位置更新filp中的f_pos
定义实际可读、写字节数变量
根据当前文件位置和缓冲区最大值判断新的实际可读、写字节数变量值
根据实际可读、写字节数变量读、写数据
根据实际可读、写字节数变量更新文件位置
对应lseek系统调用的设备移位操作为llseek
默认情况为允许设备移位操作
大部分字符设备提供的都是数据流而不是一个数据区,比如串口,对于这些设备而言移位操作毫无意义
设备可选择是否支持移位操作
支持设备移位操作
loff_t (*llseek)(struct file *filp, loff_t off, int whence);
filp:待操作的设备文件file结构体指针
off:待操作的定位偏移值(可正可负)
whence:待操作的定位起始位置
返回:返回移位后的新文件读、写位置,并且新位置总为正值
定位起始位置
SEEK_SET:0,表示文件开头
SEEK_CUR:1,表示当前位置
SEEK_END:2,表示文件尾
完成设备移位操作函数
应该检查用户请求的定位操作合法性,若不合法,应该返回-EINVAL
在读、写操作中完成读、写更新文件位置
应该根据当前文件位置检查当前读、写操作合法性
定义新位置变量
switch(whence)重新计算新位置
判断如果新位置为负或超过缓冲区最大值返回-EINVAL
用新位置更新filp中的f_pos
返回新位置
定义实际可读、写字节数变量
根据当前文件位置和缓冲区最大值判断新的实际可读、写字节数变量值
根据实际可读、写字节数变量读、写数据
根据实际可读、写字节数变量更新文件位置
返回实际可读、写字节数变量值
/***Copyright (c) 2013.TianYuan*All rights reserved.**文件名称: char_device_driver09.c*文件标识: copy_to_user 、copy_from_user函数的使用。添加偏移的功能**当前版本:1.0*作者:wuyq **取代版本:xxx*原作者:xxx*完成日期:2013-11-29*/#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/slab.h>#include <asm/uaccess.h>MODULE_LICENSE("GPL");#define CDD_MAJOR200//cat /proc/devices找一个尚未使用的#define CDD_MINOR0#define CDD_COUNT10dev_t dev = 0;u32 cdd_major = 0;u32 cdd_minor = 0;struct class *dev_class = NULL;#define BUF_SIZE100struct cdd_cdev{struct cdev cdev;struct device *dev_device;u8 led;char kbuf[BUF_SIZE];u32 data_len;//记录缓冲区中已经写入数据的长度};struct cdd_cdev *cdd_cdevp = NULL;int cdd_open(struct inode* inode, struct file *filp){struct cdd_cdev *pcdevp = NULL;printk("enter cdd_open!\n");pcdevp = container_of(inode->i_cdev, struct cdd_cdev, cdev);printk("led = %d\n", pcdevp->led);filp->private_data = pcdevp;return 0;}int cdd_read(struct file *filp, char __user *buf, size_t count, loff_t *offset){int ret = 0;u32 pos = *offset;u32 cnt = count;struct cdd_cdev *cdevp = filp->private_data;//printk("enter cdd_read!\n");if(cnt > (cdevp->data_len-pos) ){cnt = cdevp->data_len - pos;}ret = copy_to_user(buf, cdevp->kbuf+pos, cnt);//printk("kernel kbuf content:%s\n", cdevp->kbuf);*offset += cnt;return ret;}int cdd_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset){int ret = 0;struct cdd_cdev *cdevp = filp->private_data;u32 pos = *offset;u32 cnt = count;//printk("enter cdd_write!\n");if(cnt > (BUF_SIZE - pos) ){cnt = BUF_SIZE - pos;}ret = copy_from_user(cdevp->kbuf+pos, buf, cnt);*offset += cnt;if(*offset > cdevp->data_len){cdevp->data_len = *offset;}return ret;}int cdd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data){printk("enter cdd_ioctl!\n");return 0;}int cdd_release(struct inode *inode, struct file *filp){printk("enter cdd_release!\n");return 0;}loff_t cdd_llseek(struct file *filp, loff_t offset, int whence){struct cdd_cdev *pcdevp = filp->private_data;loff_t newpos = 0;switch(whence){case SEEK_SET:newpos = offset;break;case SEEK_CUR:newpos = filp->f_pos + offset;break;case SEEK_END:newpos = pcdevp->data_len + offset;break;default:return -EINVAL;//无效的参数}if( newpos<0 || newpos>= BUF_SIZE ){return -EINVAL;}filp->f_pos = newpos;return newpos;}struct file_operations cdd_fops = {.owner = THIS_MODULE,.open = cdd_open,.read = cdd_read,.write = cdd_write,.ioctl = cdd_ioctl,.release = cdd_release,.llseek = cdd_llseek,};int __init cdd_init(void){int ret = 0;int i = 0;if(cdd_major){dev = MKDEV(CDD_MAJOR, CDD_MINOR);//生成设备号//注册设备号;1、要注册的起始设备号2、连续注册的设备号个数3、名字ret = register_chrdev_region(dev, CDD_COUNT, "cdd_demo");}else{// 动态分配设备号ret = alloc_chrdev_region(&dev, cdd_minor, CDD_COUNT, "cdd_demo02");}if(ret < 0){printk("register_chrdev_region failed!\n");goto failure_register_chrdev;}//获取主设备号cdd_major = MAJOR(dev);printk("cdd_major = %d\n", cdd_major);cdd_cdevp = kzalloc(sizeof(struct cdd_cdev)*CDD_COUNT, GFP_KERNEL);if(IS_ERR(cdd_cdevp)){printk("kzalloc failed!\n");goto failure_kzalloc;}/*创建设备类*/dev_class = class_create(THIS_MODULE, "cdd_class");if(IS_ERR(dev_class)){printk("class_create failed!\n");goto failure_dev_class;}for(i=0; i<CDD_COUNT; i++){/*初始化cdev*/cdev_init(&(cdd_cdevp[i].cdev), &cdd_fops);/*添加cdev到内核*/cdev_add(&(cdd_cdevp[i].cdev), dev+i, 1);/* “/dev/xxx” */device_create(dev_class, NULL, dev+i, NULL, "cdd%d", i);cdd_cdevp[i].led = i;}return 0;failure_dev_class:kfree(cdd_cdevp);failure_kzalloc:unregister_chrdev_region(dev, CDD_COUNT);failure_register_chrdev:return ret;}void __exit cdd_exit(void){/*逆序消除*/int i = 0;for(; i < CDD_COUNT; i++){device_destroy(dev_class, dev+i);cdev_del(&(cdd_cdevp[i].cdev));//cdev_del(&((cdd_cdevp+i)->cdev));}class_destroy(dev_class);kfree(cdd_cdevp);unregister_chrdev_region(dev, CDD_COUNT);}module_init(cdd_init);module_exit(cdd_exit);
/***Copyright (c) 2013.TianYuan*All rights reserved.**文件名称: char_device_driver09_test.c*文件标识: 测试程序:测试内核空间的copy_to_user、copy_frome_user。添加偏移的功能*执行:先./char_device_driver08_testr、w、l、r、*当前版本:1.0*作者:wuyq **取代版本:xxx*原作者:xxx*完成日期:2013-11-29*/#include <stdio.h>#include <fcntl.h>#include <stdlib.h>#include <string.h>/*手工创建设备节点文件mknod /dev/cdd c 248 0*/int fd = 0;char rbuf[100];char wbuf[100] = "nihao!\n";int main(){char ch;fd = open("/dev/cdd5", O_RDWR);if(fd < 0){printf("open failed!\n");return -1;}printf("open successed fd = %d\n", fd);while(1){printf("starting to test /dev/cdd...\n");ch = getchar();getchar();//取走回车if(ch == 'q'){break;}switch(ch){case 'r':memset(rbuf, 0, 100);//清空read(fd, rbuf, 3);printf("user space from kernel: %s\n", rbuf);break;case 'w':write(fd, wbuf, strlen(wbuf) );break;case 'o':ioctl(fd, 0, 0);break;case 'l':lseek(fd, 0, SEEK_SET);//移动的文件的开头break;default:break;}sleep(1);}close(fd);return 0;}
0 0
- linux驱动开发--字符设备:添加文件指针偏移的功能
- linux设备驱动开发学习之旅--使用文件私有数据的字符设备驱动
- linux驱动开发-字符设备
- linux字符设备驱动开发
- Hasen的linux设备驱动开发学习之旅--使用文件私有数据的字符设备驱动
- Linux 驱动开发-字符设备驱动
- 字符设备驱动 - linux驱动开发
- 【驱动】linux设备驱动·字符设备驱动开发
- Hasen的linux设备驱动开发学习之旅--支持多设备的字符设备驱动
- linux设备驱动开发学习之旅--支持多设备的字符设备驱动
- Linux设备驱动开发基础---字符设备驱动程序开发之基于中断的按键驱动
- linux驱动开发--字符设备:简单的file_operations示例
- Linux设备驱动开发详解--笔记6--字符设备驱动
- Linux设备驱动开发学习(1)--字符设备驱动
- Linux字符设备驱动程序开发(1)-使用字符设备驱动
- linux 驱动-----字符设备驱动的组成
- Linux驱动编程--字符设备文件注册
- Linux驱动程序开发 004- 字符设备驱动
- python 不是内部或外部命令
- android模拟按键问题总结[使用IWindowManager.injectKeyEvent方法]
- Nginx防攻击工具教程一 ngx_http_limit_conn_module
- Hibernate Annotations 中英文注解
- jquery动态添加option示例
- linux驱动开发--字符设备:添加文件指针偏移的功能
- 一些概念
- 字符串匹配的Boyer-Moore算法实现
- openbravo-3.0MP30-vmware-i386.vmdk 转移至esxi5.0
- 关于C++,VC++.Net和C#.Net混合编程中系统库(System32目录中动态库)引用问题
- DAVINCI DM365-DM368开发攻略——开发环境搭建(DVSDK4.02)
- float与position的使用
- js+css实现的简单易用兼容好的分页
- Ubuntu12.04 搭建TFTP服务