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的映射相对应去区分的

相关推荐
Kalika0-038 分钟前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
sp_fyf_20241 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-02
人工智能·神经网络·算法·计算机视觉·语言模型·自然语言处理·数据挖掘
韩楚风2 小时前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
陈苏同学2 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
Ambition_LAO2 小时前
解决:进入 WSL(Windows Subsystem for Linux)以及将 PyCharm 2024 连接到 WSL
linux·pycharm
Pythonliu72 小时前
茴香豆 + Qwen-7B-Chat-Int8
linux·运维·服务器
你疯了抱抱我2 小时前
【RockyLinux 9.4】安装 NVIDIA 驱动,改变分辨率,避坑版本。(CentOS 系列也能用)
linux·运维·centos
追风赶月、2 小时前
【Linux】进程地址空间(初步了解)
linux
栎栎学编程2 小时前
Linux中环境变量
linux
我是哈哈hh3 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝