设备文件指针操控llseek
来源:互联网 发布:网络图片搞笑有没有 编辑:程序博客网 时间:2024/06/06 16:34
llseek主要用来操作文件的指针.其实质是内核依赖filp->f_ops执行文件的定位.
1.原型:
llseek(struct file *filp, loff_t off, int whence);
各参数意义如下:
filp:用户空间打开的设备文件描述符;off:偏移量;whence:基址.一共有三个标识:SEEK_SET、SEEK_CUR和SEEK_END.这三个标识一般和off配合使用.如下:SEEK_SET:off即为新的读写位置;SEEK_CUR:当前读写位置后增加off个偏移量;SEEK_END:将读写位置指向文件尾后再增加off个偏移量.如下:
static loff_t mem_llseek(struct file *filp, loff_t offset, int whence){ loff_t newpos; switch(whence) { case 0: /* SEEK_SET */ newpos = offset; break; case 1: /* SEEK_CUR */ newpos = filp->f_pos + offset; break; case 2: /* SEEK_END */ newpos = MEMDEV_SIZE -1 + offset; break; default: /* can't happen */ return -EINVAL; } if ((newpos<0) || (newpos>MEMDEV_SIZE)) return -EINVAL; filp->f_pos = newpos; return newpos;}
2.llseek对write/read的影响:
当实现了llseek系统调用,在进行读写时,必须对文件位置指针进行"校准".如:
read:
static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos){ unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct mem_dev *dev = filp->private_data; if (p >= MEMDEV_SIZE) return 0; if (count > MEMDEV_SIZE - p) count = MEMDEV_SIZE - p; if (copy_to_user(buf, (void*)(dev->data + p), count)) { ret = - EFAULT; } else { *ppos += count; ret = count; printk(KERN_INFO "read %d bytes(s) from %d\n", count, p); } return ret;}
write:
static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos){ unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct mem_dev *dev = filp->private_data; if (p >= MEMDEV_SIZE) return 0; if (count > MEMDEV_SIZE - p) count = MEMDEV_SIZE - p; if (copy_from_user(dev->data + p, buf, count)) ret = - EFAULT; else { *ppos += count; ret = count; printk(KERN_INFO "written %d bytes(s) from %d\n", count, p); } return ret;}
3.实际的使用情况:
在驱动中,很少会用到llseek系统调用.相反,为了严谨编程,需要对其禁用.需要:
1).把filp标记为不可定位--通过在open方法中调用nonseekable_open;2).设置fops的llseek域为no_llseek;如下:
static int scull_p_open(struct inode *inode, struct file *filp){ struct scull_pipe *dev; dev = container_of(inode->i_cdev, struct scull_pipe, cdev); filp->private_data = dev; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; if (!dev->buffer) { /* allocate the buffer */ dev->buffer = kmalloc(scull_p_buffer, GFP_KERNEL); if (!dev->buffer) { up(&dev->sem); return -ENOMEM; } } dev->buffersize = scull_p_buffer; dev->end = dev->buffer + dev->buffersize; dev->rp = dev->wp = dev->buffer; /* rd and wr from the beginning */ /* use f_mode,not f_flags: it's cleaner (fs/open.c tells why) */ if (filp->f_mode & FMODE_READ) dev->nreaders++; if (filp->f_mode & FMODE_WRITE) dev->nwriters++; up(&dev->sem); return nonseekable_open(inode, filp);}
struct file_operations scull_pipe_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = scull_p_read, .write = scull_p_write, .poll = scull_p_poll, .ioctl = scull_ioctl, .open = scull_p_open, .release = scull_p_release, .fasync = scull_p_fasync,};
4.实例:
下面实例源于国嵌:
app:
#include <stdio.h>int main(){FILE *fp0 = NULL;char Buf[4096];strcpy(Buf,"Mem is char dev!");printf("BUF: %s\n",Buf);fp0 = fopen("/dev/memdev0","r+");if (fp0 == NULL){printf("Open Memdev0 Error!\n");return -1;}fwrite(Buf, sizeof(Buf), 1, fp0);fseek(fp0,0,SEEK_SET);strcpy(Buf,"Buf is NULL!");printf("BUF: %s\n",Buf);fread(Buf, sizeof(Buf), 1, fp0);printf("BUF: %s\n",Buf);return 0;}
drv:
memdev.h
#ifndef _MEMDEV_H_#define _MEMDEV_H_#ifndef MEMDEV_MAJOR#define MEMDEV_MAJOR 251 #endif#ifndef MEMDEV_NR_DEVS#define MEMDEV_NR_DEVS 2 #endif#ifndef MEMDEV_SIZE#define MEMDEV_SIZE 4096#endifstruct mem_dev { char *data; unsigned long size; };#endif /* _MEMDEV_H_ */memdev.c
#include <linux/module.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/cdev.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h>#include <linux/device.h> #include "memdev.h"static int mem_major = MEMDEV_MAJOR;module_param(mem_major, int, S_IRUGO);struct mem_dev *mem_devp; struct cdev cdev; int mem_open(struct inode *inode, struct file *filp){ struct mem_dev *dev; int num = MINOR(inode->i_rdev); if (num >= MEMDEV_NR_DEVS) return -ENODEV; dev = &mem_devp[num]; filp->private_data = dev; return 0; }int mem_release(struct inode *inode, struct file *filp){ return 0;}static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos){ unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct mem_dev *dev = filp->private_data; if (p >= MEMDEV_SIZE) return 0; if (count > MEMDEV_SIZE - p) count = MEMDEV_SIZE - p; if (copy_to_user(buf, (void*)(dev->data + p), count)) { ret = - EFAULT; } else { *ppos += count; ret = count; printk(KERN_INFO "read %d bytes(s) from %d\n", count, p); } return ret;}static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos){ unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct mem_dev *dev = filp->private_data; if (p >= MEMDEV_SIZE) return 0; if (count > MEMDEV_SIZE - p) count = MEMDEV_SIZE - p; if (copy_from_user(dev->data + p, buf, count)) ret = - EFAULT; else { *ppos += count; ret = count; printk(KERN_INFO "written %d bytes(s) from %d\n", count, p); } return ret;}static loff_t mem_llseek(struct file *filp, loff_t offset, int whence){ loff_t newpos; switch(whence) { case 0: /* SEEK_SET */ newpos = offset; break; case 1: /* SEEK_CUR */ newpos = filp->f_pos + offset; break; case 2: /* SEEK_END */ newpos = MEMDEV_SIZE -1 + offset; break; default: /* can't happen */ return -EINVAL; } if ((newpos<0) || (newpos>MEMDEV_SIZE)) return -EINVAL; filp->f_pos = newpos; return newpos;}static const struct file_operations mem_fops ={ .owner = THIS_MODULE, .llseek = mem_llseek, .read = mem_read, .write = mem_write, .open = mem_open, .release = mem_release,};static int memdev_init(void){struct class *myclass; int result; int i; dev_t devno = MKDEV(mem_major, 0); if (mem_major) result = register_chrdev_region(devno, 2, "memdev"); else { result = alloc_chrdev_region(&devno, 0, 2, "memdev"); mem_major = MAJOR(devno); } if (result < 0) return result; cdev_init(&cdev, &mem_fops); cdev.owner = THIS_MODULE; cdev.ops = &mem_fops; cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS); mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL); if (!mem_devp) { result = - ENOMEM; goto fail_malloc; } memset(mem_devp, 0, sizeof(struct mem_dev)); for (i=0; i < MEMDEV_NR_DEVS; i++) { mem_devp[i].size = MEMDEV_SIZE; mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL); memset(mem_devp[i].data, 0, MEMDEV_SIZE); }myclass = class_create(THIS_MODULE,"test_char"); device_create(myclass, NULL, MKDEV(mem_major,0), NULL, "memdev0"); return 0; fail_malloc: unregister_chrdev_region(devno, 1); return result;}static void memdev_exit(void){ cdev_del(&cdev); kfree(mem_devp); unregister_chrdev_region(MKDEV(mem_major, 0), 2);}MODULE_AUTHOR("David Xie");MODULE_LICENSE("GPL");module_init(memdev_init);module_exit(memdev_exit);
0 0
- 设备文件指针操控llseek
- 定位设备--llseek实现
- adb操控多个设备
- adb操控多个设备
- C# 键盘操控鼠标指针
- C++培训_007_指针地址内存_数据结构_文件操控(未完成)
- 通过电脑键盘按键操控android设备
- 字符设备驱动-中断方式操控按键
- Linux设备驱动程序学习(6)-高级字符驱动程序操作-ioctl and llseek
- 通知内核你的设备 不支持llseek, 通过在你的 open 方法中调用nonseekable_open
- Linux字符设备驱动程序(二)---------实现open,read,write,llseek函数
- Linux设备驱动程序第三版学习(9)- 高级字符驱动程序操作(续4) - llseek定位设备
- Linux设备驱动程序第三版学习(9)- 高级字符驱动程序操作(续4) - llseek定位设备
- winform如何这样操控xml文件
- 字符设备驱动-轮询方式操控按键
- 用控件指针操控窗体的控件的问题
- Linux设备驱动程式学习(4)-高级字符驱动程式操作[(1)ioctl and llseek]
- Linux设备驱动程式学习(4)-高级字符驱动程式操作[(1)ioctl and llseek]
- ngx_http_mysql_module.c
- 用于Oracle容灾和RAC的测试代码
- 比特币:原理,安全与未来
- Linux常用的网络命令
- MarkDown语法说明
- 设备文件指针操控llseek
- weblogic上部署应用程序时,web.xml文件编码错误
- u-boot移植出现的问题
- ngx_http_dav_ext_module.c
- Markdown: Basics (快速入门)
- flex和java实体类的映射关系(blazeds方式通信)
- 2013搜狗搜索广告事业部面试问的一个问题,觉得很受益
- rails字符转准换成对象及方法
- 输入10个数字将其按从小到大排序输出