5.2.11.添加读写接口

5.2.11.添加读写接口

5.2.11.1、在驱动中添加

5.2.11.2、在应用中添加

5.2.11.3、测试

  1. app.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>

    #define FILE "/dev/test" // 刚才mknod创建的设备文件 名,必须保持一致

    char buf;

    int main(void)
    {
    int fd = -1;

    复制代码
     fd = open(FILE, O_RDWR);
     if(fd < 0)
     {
     	printf("open %s error \n",FILE);
     	return -1;
     }
     printf("open %s success..\n",FILE);
     
     //读文件
     write(fd, "hello world", 11);
     
     read(fd,buf,20);
     
     
     //关闭 文件
     close(fd);
     
     return 0;

    }

  2. Makefile 文件 没有改动 只是增加了 删除 app

    #ubuntu的内核源码树,如果要编译在ubuntu中安装的模块就打开这2个
    #KERN_VER = (shell uname -r) #KERN_DIR = /lib/modules/(KERN_VER)/build

    开发板的linux内核的源码树目录

    KERN_DIR = /root/driver/kernel

    obj-m += module_test.o

    all:
    make -C $(KERN_DIR) M=pwd modules
    # app 是在 开发板运行 所以 arm-linux-gcc
    arm-linux-gcc app.c -o app
    cp:
    cp *.ko app /root/rootfs/rootfs/driver_test
    #cp app /root/rootfs/rootfs/driver_test

    .PHONY: clean
    clean:
    rm -rf app
    make -C $(KERN_DIR) M=pwd modules clean

  3. module_test.c 添加 .write = test_chrdev_write,

.read = test_chrdev_read,

复制代码
#include <linux/module.h>		// module_init  module_exit
#include <linux/init.h>			// __init   __exit
#include <linux/fs.h>


#define MYMAJOR 200  /* 定义 register_chrdev 注册设备的 主设备号 */

#define MYNAME  "test_char" /* 定义 register_chrdev 注册设备的 设备名字 */

int mymajor; /* 定义 register_chrdev 注册设备号*/

/* NOTE  自己定义函数指针  test_chrdev_open  */
static int test_chrdev_open(struct inode *inode, struct file *file)
{
	/* 这个函数中真正应该 放置 打开这个硬件设备的 操作代码 ,我们先 printk 代替一下 */
	printk(KERN_INFO "test_chrdev_open test.c->test_chrdev_open \n");  
	
	return 0;

} /* test_chrdev_open() */




/* NOTE  自己定义函数指针 test_chrdev_release ,   release对应的就是 close  */
static int test_chrdev_release(struct inode *inode, struct file *file)
{
	printk(KERN_INFO "test_chrdev_release test.c->test_chrdev_release \n");

	return 0;
}


static ssize_t test_chrdev_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	printk(KERN_INFO "test_chrdev_release test.c->test_chrdev_read \n");
	return 0;
}

// 写函数的本质:将应用层 传递过来的数据先 复制到 内核中,然后将之正确的方式写入硬件完成的操作!(数据从应用层到驱动层的复制,)
// 内核有一个 虚拟地址空间,应用层有一个 虚拟地址空间
static ssize_t test_chrdev_write(struct file *file, const char __user *user_buf,
			size_t count, loff_t *ppos)
{
	printk(KERN_INFO "test_chrdev_release test.c->test_chrdev_write\n");
	return 0;	
}


//自定义  file_operations 结构体 及其元素填充
/* NOTE  定义 register_chrdev 注册设备的 设备结构体 test_fops */
static const struct file_operations test_fops = {
	.owner		= THIS_MODULE,                    /* 所有的驱动 代码这一行不需要动,所有的都是这样,不是函数指针, 惯例直接写即可 */
	
	.open		= test_chrdev_open,  /* 将来应用 open 打开这个设备时实际 调用的就是这个 .open  函数指针*/
	.release	= test_chrdev_release,         /* release对应的就是 close    函数指针 */
	.write		= test_chrdev_write, 
	.read		= test_chrdev_read, 
};









// 模块安装函数
static int __init chrdev_init(void)
{	
	int ret = -1;  /* 定义 register_chrdev 的返回值  */
	
	printk(KERN_INFO "chrdev_init helloworld init\n");
	
	
	// 在 module_init 宏 调用函数中去注册字符串 设备驱动
	mymajor = register_chrdev(0, "test_char", &test_fops);   /* major设成0,内核帮我们自动分配空白的设备号,分配的值会 做返回值 ,负数还是返回失败  */
	if(mymajor < 0)
	{
		printk(KERN_ERR "registe_chrdev fail \n");
		return -EINVAL;  /* 返回一个错误码 需要加 '-'负号*/
	}
	printk(KERN_INFO "自动分配 register_chrdev success....mymajor = %d \n",mymajor);
	
	return 0;
}

// 模块卸载函数
static void __exit chrdev_exit(void)
{
	printk(KERN_INFO "chrdev_exit helloworld exit\n");
	
	// 在 module_exit宏 调用函数中去注销 字符串 设备驱动
	unregister_chrdev(mymajor, "test_char");  /* 这里不判断返回值 了,一般不会出错 */
}


module_init(chrdev_init);
module_exit(chrdev_exit);

// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL");				// 描述模块的许可证
MODULE_AUTHOR("aston");				// 描述模块的作者
MODULE_DESCRIPTION("module test");	// 描述模块的介绍信息
MODULE_ALIAS("alias xxx");			// 描述模块的别名信息




/***********************************************************
如果 KERN_DEBUG 打印不出来,更改打印级别 或者  	
printk(KERN_DEBUG "chrdev_init helloworld init\n"); 

[root@liang_x210 driver_test]# cat /proc/sys/kernel/printk
7       4       1       7
[root@liang_x210 driver_test]# echo 8 > /proc/sys/kernel/printk
[root@liang_x210 driver_test]# cat /proc/sys/kernel/printk
8       4       1       7
************************************************************/

运行结果:

5.2.11.4、应用和驱动之间的数据交换

(1)copy_from_user,用来将数据从 用户空间复制到内核空间

(2)copy_to_user 从内核空间 复制 到 用户空间

注意:复制 是和 mmap的映射相对应去区分的

相关推荐
senijusene9 小时前
Linux软件编程:IO编程,标准IO(1)
linux·运维·服务器
power 雀儿9 小时前
Scaled Dot-Product Attention 分数计算 C++
算法
不像程序员的程序媛9 小时前
Nginx日志切分
服务器·前端·nginx
忧郁的橙子.9 小时前
02-本地部署Ollama、Python
linux·运维·服务器
醇氧9 小时前
【linux】查看发行版信息
linux·运维·服务器
琹箐9 小时前
最大堆和最小堆 实现思路
java·开发语言·算法
No8g攻城狮9 小时前
【Linux】Windows11 安装 WSL2 并运行 Ubuntu 22.04 详细操作步骤
linux·运维·ubuntu
renhongxia110 小时前
如何基于知识图谱进行故障原因、事故原因推理,需要用到哪些算法
人工智能·深度学习·算法·机器学习·自然语言处理·transformer·知识图谱
坚持就完事了10 小时前
数据结构之树(Java实现)
java·算法
算法备案代理10 小时前
大模型备案与算法备案,企业该如何选择?
人工智能·算法·大模型·算法备案