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

相关推荐
aherhuo2 分钟前
kubevirt网络
linux·云原生·容器·kubernetes
爱码小白3 分钟前
网络编程(王铭东老师)笔记
服务器·网络·笔记
zzzhpzhpzzz11 分钟前
Ubuntu如何查看硬件型号
linux·运维·ubuntu
蜜獾云13 分钟前
linux firewalld 命令详解
linux·运维·服务器·网络·windows·网络安全·firewalld
yuanbenshidiaos31 分钟前
C++----------函数的调用机制
java·c++·算法
唐叔在学习35 分钟前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
o(╥﹏╥)1 小时前
linux(ubuntu )卡死怎么强制重启
linux·数据库·ubuntu·系统安全
娶不到胡一菲的汪大东1 小时前
Ubuntu概述
linux·运维·ubuntu
ALISHENGYA1 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
chengooooooo1 小时前
代码随想录训练营第二十七天| 贪心理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
算法·leetcode·职场和发展