通过应用访问驱动的常用接口函数(open,close,read,write,ioctl,mmap,poll,select,epoll,llseek)下篇

一.llseek函数使用

(1) llseek函数原型与解释

    原型:  loff_t (*llseek) (struct file* filp,loff_t  offset, int whence);

参数功能
struct file*代表上一级调用函数传入的已打开文件,该结构体与struct inode* 区别在于struct inode*用于代表一个文件,但是该文件可以是未打开的。
loff_t代表用户空间的文件光标移动数量值,可以是正数,也可以是负数。
 int whence代表移动光标的参考位置,有3种(即当前光标、文件开头、文件结尾)


返回值:非负数,当前文件的指针位置;负数,函数调用失败。
 

(2)代码讲解

        1.驱动代码

        llsee函数在驱动和应用程序都存在(即用户空间和内核空间都存在),应用程序调用llseek函数就会在内核驱动中被调用,实现的功能是修改驱动中write/read函数的文件指针。(直白的说就是:当文件指针offset发生变化,write/read函数的文件指针也跟着变化

#define DEV_SIZE    (4)
loff_t    first_chardev_llseek(struct file* filp,loff_t off,int whence){
    loff_t NewPos=0;
    int offset=off;
    switch(whence){
        case SEEK_SET:    //SEEK_SET代表以文件头为偏移起始值
            NewPos=offset;
        break;
        case SEEK_CUP:    //SEEK_CUP代表以当前位置为偏移起始值
            NewPos=filp->f_pos+offset;
        break;
        case SEEK_END:    //SEEK_END代表以文件结尾为偏移起始值
            NewPos=DEV_SIZE+offset;
        break;
        default:
            return -1;
    }
    if(NewPos<0)
        return -1;
    filp->f_pos=NewPos;
    return NewPos;
}

     2.应用层代码

lseek(int fd, off_t offset, int whence);

fd:文件句柄,要执行的文件;

offset:文件的偏移量;

whence:文件开始的位置. 

二.总结              

        在 Linux 中,所有设备都以文件的形式存放在 /dev 目录下,都是通过文件的方式进行访问,设备节点是 Linux 内核对设备的抽象,一个设备节点就是一个文件。应用程序主要通过file_operations 结构体的函数的调用执行访问设备,这些调用独立于任何特定的驱动程序。而驱动程序负责将这些标准调用映射到实际硬件的特有操作。

  (1)驱动关系调用图解

 

  (2)file_operations 结构体

        file_operations 结构体是访问驱动的函数,它的里面的每个结构体成员都对应一个调用,这个结构体里 面有很多的成员变量,并且结构体中的成员函数是字符设备驱动程序设计的主体内容,这些函数实际会在 应用程序进行 Linux open ()、 write ()、 read ()、 close ()等系统调用时最终被内核调用。 file_operations 文件操作集在定义在 include/linux/fs.h 下面。

struct file_operations {
 
	struct module *owner;
 
	loff_t (*llseek) (struct file *, loff_t, int);
 
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
 
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
 
	ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
 
	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long,loff_t);
 
	int (*readdir) (struct file *, void *, filldir_t);
 
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
 
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
 
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
 
	int (*mmap) (struct file *, struct vm_area_struct *);
 
	int (*open) (struct inode *, struct file *);
 
	int (*flush) (struct file *, fl_owner_t id);
 
	int (*release) (struct inode *, struct file *);
 
	int (*fsync) (struct file *, int datasync);
 
	int (*aio_fsync) (struct kiocb *, int datasync);
 
	int (*fasync) (int, struct file *, int);
 
	int (*lock) (struct file *, int, struct file_lock *);
 
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
 
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long,unsigned long, unsigned long);
 
	int (*check_flags)(int);
 
	int (*flock) (struct file *, int, struct file_lock *);
 
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t,unsigned int);
 
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *,size_t,unsigned int);
 
	int (*setlease)(struct file *, long, struct file_lock **);
 
	long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);
 
};

  (3)file_operations 结构体的函数描述

       file_operations 结构体中的主要成员进行分析表:

函数
功能
llseek ()函数
修改一个文件的当前读写位置,并将新位置返回,在出错时,这个函数返回一个负值。
read ()函数
用来从设备中读取数据,成功时函数返回读取的字节数,出错时返回一个负值。它与
用户空间应用程序中的 ssize_t read int fd void*buf size_t count )和 size_t fread
void*ptr size_t size size_t nmemb FILE*stream )对应。
write ()函数
向设备发送数据,成功时该函数返回写入的字节数。如果此函数未被实现,当用户进
write ()系统调用时,将得到 -EINVAL 返回值。它与用户空间应用程序中的 ssize_t
write int fd const void*buf size_t count )和 size_t fwrite const void*ptr size_t size
size_t nmemb FILE*stream )对应。
read ()和 write ()
如果返回 0 ,则暗示 end-of-file EOF )。
unlocked_ioctl ()
提供设备相关控制命令的实现(既不是读操作,也不是写操作),当调用成功时,返
回给调用程序一个非负值。它与用户空间应用程序调用的 int fcntl int fd int
cmd .../*arg*/ )和 int ioctl int d int request ... )对应。
mmap ()函数
将设备内存映射到进程的虚拟地址空间中,如果设备驱动未实现此函数,用户进行
mmap ()系统调用时将获得 -ENODEV 返回值。这个函数对于帧缓冲等设备特别有意
义,帧缓冲被映射到用户空间后,应用程序可以直接访问它而无须在内核和应用间进
行内存复制。它与用户空间应用程序中的 void*mmap( void*addr size_t length int prot int flags int fd off_t offset )函数对 应。
poll ()函数
一般用于询问设备是否可被非阻塞地立即读写。当询问的条件未触发时,用户空间进
select ()和 poll ()系统调用将引起进程的阻塞。
aio_read ( ) 和
aio_write ()函数
分别对与文件描述符对应的设备进行异步读、写操作。设备实现这
两个函数后,用户空间可以对该设备文件描述符执行 SYS_io_setup SYS_io_submit
SYS_io_getevents SYS_io_destroy 等系统调用进行读写。
open ()函数
当用户空间调用 Linux API 函数 open ()打开设备文件时,设备驱动的 open ()函数
最终被调用。驱动程序可以不实现这个函数,在这种情况下,设备的打开操作永远成
功。与 open ()函数对应的是 release ()函数。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我来挖坑啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值