标签:命令 button 个数 通过 lseek 集合 oct operation oid
概念:按字节流进行读写操作的设备,读写数据分先后。
举例:led、button、I2C、SPI、LCD等。
Linux应用程序对驱动程序的调用:
Linux一切皆文件,驱动程序加载成功之后就会在"/dev"目录下生成一个相对应的文件,应用程序通过对这个"/dev/xxx"进行open(),read(),write(),close()操作即可实现对硬件的操作。
例如:/dev/led驱动文件,打开和关闭使用open()函数和close()函数,如果要打开led/关闭led那么就使用write()函数向驱动中写入数据,这个数据就是打开/关闭led的控制参数。如果想要获取led的状态,就使用read()函数从驱动中读取状态。
应用程序运行于用户空间,而Linux驱动属于内核的一部分,运行于内核空间。
当我们在用户空间想要实现对内核的操作,比如使用open()函数打开"/dev/led"驱动文件,因为用户空间不能直接对内核进行操作,而必须使用一个叫做"系统调用"的方法来实现用户空间陷入内核空间,这样才能实现对底层驱动的操作。
应用程序使用到的函数在具体驱动中都有与之对应的函数。比如,应用程序中调用open这个函数,那么在驱动程序也得有一个open函数。每一个"系统调用",在具体驱动中都有与之对应的一个驱动函数。Linux内核下include/linux/fs.h中有个叫做file_operations的结构体,此结构体就是Linux内核驱动操作函数集合,内容如下:
struct file_operations { struct module *owner;//拥有该结构体模块的指针,一般设置为THIS_MODULE 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 *);//轮询函数,用于查询设备是否可以进行非阻塞的读写 int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); 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 *, struct dentry *, int datasync);//用于刷新待处理的数据,将缓冲区的数据刷新到磁盘中 int (*aio_fsync) (struct kiocb *, int datasync);//与fsync类似,用于异步刷新待处理的数据 int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *); 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 (*dir_notify)(struct file *filp, unsigned long arg); 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); };
字符设备驱动开发的步骤:
1.驱动模块的加载和卸载
Linux驱动有两种运行方式,第一种就是将驱动编译进Linux内核中,当Linux启动时就会自动运行驱动程序了。第二种就是将驱动编译成模块(Linux下驱动模块的扩展名为.ko),Linux内核启动以后再使用"insmod"命令加载驱动模块。第二种常用于驱动调试,至于要不要把驱动编译进内核,根据自己的需求决定。
模块有加载和卸载两种操作,我们在编写驱动的时候需要注册这两种操作函数,模块的加载和注册函数如下:
标签:命令 button 个数 通过 lseek 集合 oct operation oid
原文地址:https://www.cnblogs.com/huanian/p/12906264.html