简单的字符设备驱动模型
2016-10-13 23:46
253 查看
字符设备是指在I/O传输过程中以字符为单位进行传输的设备,这种设备没有缓存,例如键盘,打印机等。
#include< linux/module.h> #include< linux/sche.h> #include< linux/kernel.h> #include< linux/init.h> static loff_t test_llseek(struct file *filp, loff_t off, int whence); /* *linux 使用 llseek来改变驱动程序的llseek() 的值来修改设备(文件)的读写位置 *实质上是改变filp->f_pos的值 *它有三个参数 * 第一个是file指针,file结构是设备驱动程序最重要的一个数据结构(注意file!= FILE) * file代表一个“打开的文件”,它由内核在open()时创建且在close()前作为参数传递给操作 * 在设备上的函数,以下是具体构成 struct file{ struct list_head f_list; struct dentry * f_dentry; struct vfsmount * f_vfsmnt; struct file_operations * f_op; atomic_t f_count; unsigned int f_flags; mode_t f_mode; loff_t f_pos; unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin; int f_error; unsigned long f_version; void * private_data; struct kiobuf * f_iobuf; long f_iobuf_lock; }; 其中有几个常用成员: 1.f_mode 文件模式由 FMODE_READ && FMODE_WRITE 标识,驱动程序的ioctl()方法可能查看这个域, read()和write()在调用前已经检查,所以无需检查权限。 2.f_ops 当前读写位置,loff_t 是long long (64位整数)。如果定义了llseek()方法,就应该更新 f_pos 3.f_inode 打开文件对应的i节点(节点是内核中的一个概念,至于到底是啥我也不知道),inode指针 是内核传递给所有文件操作的第一个参数,所以驱动程序一般不需要访问file这个字段。 4.f_op 与文件对应的操作,内核在open()对这个指针赋值,以后需要分派操作时就读这些数据。 * 第二个参数loff_t 为要移动的偏移量 * 第三个参数wence 为偏移方式,0为从文件头移动, 1为从文件当前位置移动, 2为从文件尾移动 */ static ssize_t test_read(struct file *filp, char *buf, size_t count, loff_t f_pos); /* *如果数据全部传输完成,则返回值为count *如果数据部分传输完成, 则返回值为小于count的数,这种情况下一般会重新读数据 *如果已经到文件尾, 则返回值为0 *如果发生错误则返回负值 */ static ssize_t test_write(struct file *filp, char *buf, size_t count, loff_t f_pos); /* *如果数据全部传输完成,则返回值为count *如果数据部分传输完成, 则返回值为小于count的数,这种情况下一般会重新写数据 *如果已经到文件尾, 则返回值为0 *如果发生错误则返回负值 */ static int test_open(struct inode *inode, struct file *filp); /* *在linux使用设备前会调用驱动程序的这个方法 *open()方法最重要的是调用 MOD_INC_USE_COUNT,这个宏用来增加驱动程序使用计数器,避免在不正确 * 的卸载驱动程序 *inode作用是打开文件对应的i节点,主要作用是获取设备号 *filp代表一个打开的文件(设备) */ static int test_release(struct inode *inode, struct file *filp); /* */ static int test_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param); /* */ int test_init(void); int test_cleanup(void); #define MAJOR_DEV 125 #define DEVICE_NAME "my_simpledev" module_init(test_init); module_init(test_clenup); static struct file_operations test_fops = { .owner = THIS_MODULE, .llseek = test_llseek, .read = test_read, .write = test_write, .open = test_open, .release = test_release, .ioctl = test_ioctl, }; static loff_t test_llseek(struct file * filp, loff_t off, int whence) { printk("llseek called\n"); return 0; } static ssize_t test_read(struct file * filp, char * buf, size_t count, loff_t f_pos) { printk("read called\n"); return 0; } static ssize_t test_write(struct file * filp, char * buf, size_t count, loff_t f_pos) { printk("write called\n"); return 0; } static ssize_t test_open(struct inode *inode, struct file * filp) { printk("open called\n"); MOD_INC_USE_COUNT; return 0; } static int test_release(struct inode *inode, struct file * filp) { printk("release called\n"); MOD_DEC_USE_COUNT; return 0; } static int test_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { printk("ioctl called\n"); return 0; } int test_init(void) { int result = 0; result = register_chrdev(MAJOR_NR, DEVICE_NAME, &test_fops) if(result < 0) { printk(KERN_ERR_DEVICE_NAME ":Unable to get major %d\n", MAJOR_NR); return result; } printk(KERN_ERR_DEVICE_NAME ": init OK \n"); return 0; } void test_cleanup(void) { unregister_chrdev(MAJOR_NR, DEVICE_NAME); }
相关文章推荐
- 简单的一个字符设备驱动
- linux简单字符设备驱动
- Linux内核开发之简单字符设备驱动(上)
- 简单的LINUX字符设备驱动及编译进Linux内核…
- hello_world-2.2之简单设备驱动模型(二)---device,bus,driver结构介绍
- 简单字符设备驱动和自动创建设备文件
- Linux2.6内核下简单的字符设备驱动及测试
- Linux内核开发之简单字符设备驱动(下)
- 简单字符设备驱动——LED驱动
- 一个简单的字符设备驱动
- 简单字符设备驱动(driver of simple char device)
- 简单字符设备驱动代码+注释(ldd3第三章例子)
- Tiny6410 简单的LED字符设备驱动
- hello_world-2.3之简单设备驱动模型(三)---添加设备属性文件
- Linux内核开发之简单字符设备驱动(下)
- linux设备驱动程序之简单字符设备驱动
- Linux驱动编程 step-by-step (二) 简单字符设备驱动
- linux设备驱动--字符设备模型
- or1200下linux简单gpio字符设备驱动
- hello_world-2.2之简单设备驱动模型(一)