在一个非套接字上尝试了一个操作。_如何在一个最简单的驱动模块上加入open、read、write文件操作?...

看了我前面的文章,基本能掌握如何从0写一个最简单的驱动模块并进行测试了。那么接下来的文章都是在这个最基本的代码上不断的堆叠,添加更加复杂的功能。

1. open、read、write文件操作的第一步先填充file_operations结构体

file_operations结构体的存在让应用层可以使用统一的接口访问硬件,只需要调用xxx_fops.open、xxx_fops.read等,至于你的驱动如何操作硬件的写应用程序的人不必关心,完全由驱动程序的xxx_open、xxx_read等具体的接口去实现,这也是典型的分层思想。

886fcf66dd154297e7cc21dfd43ce8fc.png

2. 实现hello驱动的hello_open函数

关于函数的命名是自由的,但为了规范,一般都是xxx_open,xxx即此设备驱动对应的设备的名字,比如key、lcd、mpu6050等。出于对设备文件的保护,所以当应用程序要使用某个设备的时候是需要先打开这个设备的,然后才能读写使用,那么当执行打开设备的动作时,内核就会调用驱动里面的这个.open函数,即我们即将实现的xxx_open函数,所以在这个函数里面我们要做的就是对设备进行初始化操作。

88e2af0b009f1a56b42694915f57a2e1.png

目前我们先实现框架,没有具体的设备,所以这个函数里面暂时什么事情都不做,只加一个打印,便于我们跟踪。

3. 实现hello驱动的hello_close函数

对设备文件有打开的操作,那么必然也有关闭的操作,对应file_operations里面的.release函数,这个函数的实现我们一般命名为xxx_close函数,要实现的功能就是设备读写完毕后关闭或者释放掉这个设备所申请的所有资源,以便下一个应用程序再次操作这个设备。

65b6cf1bac945b789ef6cf2d579d85c0.png

4. 实现hello驱动的hello_read函数

当应用程序打开设备文件,对设备文件进行读操作的时候,会调用到fops里面的xxx_read函数,所以再这个函数里面要把资源cp给应用程序。

7803afa49dd923936c74a16079a446bc.png

这个地方有个需要注意的地方,我们把资源cp给应用程序,即read函数的buf参数,不是直接赋值的,而是调用的copy_to_user函数,这是因为驱动里面的数据是保存在内核空间的,而应用程序的数据是在用户空间的,这涉及到用户空间(应用程序)和内核空间(驱动)数据的交互,就不能使用简单的赋值了。

5. 实现hello驱动的hello_write函数

531e23dabde09e6340dca5c4c6a0655a.png

以上就是实现open、read、write文件操作的核心代码,下一篇文章将详细讲解如何测试这个代码以及分析应用程序调用驱动的整体过程。

谢谢阅读,如需完整代码直接私信我!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的字符设备驱动程序,它可以读取设备的状态并将其显示在终端上: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <asm/uaccess.h> #define DEVICE_NAME "mydevice" #define CLASS_NAME "myclass" static dev_t dev_num; static struct cdev my_cdev; static struct class *my_class = NULL; static char message[256] = "Device is working\n"; static int message_len = 0; static int my_open(struct inode *inode, struct file *file) { printk(KERN_INFO "mydevice: device opened\n"); return 0; } static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { ssize_t ret; if (*offset >= message_len) return 0; if (count > message_len - *offset) count = message_len - *offset; ret = copy_to_user(buf, message + *offset, count); if (ret == count) { printk(KERN_INFO "mydevice: read %ld bytes\n", count); return -EFAULT; } *offset += count - ret; return count - ret; } static int my_release(struct inode *inode, struct file *file) { printk(KERN_INFO "mydevice: device closed\n"); return 0; } static struct file_operations my_fops = { .owner = THIS_MODULE, .open = my_open, .read = my_read, .release = my_release, }; static int __init my_init(void) { int ret; ret = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME); if (ret < 0) { printk(KERN_ERR "mydevice: failed to allocate major number\n"); return ret; } cdev_init(&my_cdev, &my_fops); my_cdev.owner = THIS_MODULE; ret = cdev_add(&my_cdev, dev_num, 1); if (ret < 0) { printk(KERN_ERR "mydevice: failed to add device\n"); goto cdev_fail; } my_class = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(my_class)) { printk(KERN_ERR "mydevice: failed to create class\n"); ret = PTR_ERR(my_class); goto class_fail; } device_create(my_class, NULL, dev_num, NULL, DEVICE_NAME); printk(KERN_INFO "mydevice: device registered\n"); message_len = strlen(message); return 0; class_fail: cdev_del(&my_cdev); cdev_fail: unregister_chrdev_region(dev_num, 1); return ret; } static void __exit my_exit(void) { device_destroy(my_class, dev_num); class_destroy(my_class); cdev_del(&my_cdev); unregister_chrdev_region(dev_num, 1); printk(KERN_INFO "mydevice: device unregistered\n"); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple character device driver for displaying device status"); ``` 该驱动程序实现了一个字符设备,当用户打开设备时,它会显示一条消息,当用户读取设备时,它会将设备状态消息返回给用户。该驱动程序使用了内核中的字符设备 API 来进行注册和添加设备,以及实现 openread 和 release 操作

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值