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

相关推荐
肥猪猪爸21 分钟前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
blessing。。27 分钟前
I2C学习
linux·单片机·嵌入式硬件·嵌入式
readmancynn33 分钟前
二分基本实现
数据结构·算法
萝卜兽编程35 分钟前
优先级队列
c++·算法
2202_7544215442 分钟前
生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件
java·linux·开发语言
盼海43 分钟前
排序算法(四)--快速排序
数据结构·算法·排序算法
一直学习永不止步1 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
运维&陈同学1 小时前
【zookeeper03】消息队列与微服务之zookeeper集群部署
linux·微服务·zookeeper·云原生·消息队列·云计算·java-zookeeper
Rstln2 小时前
【DP】个人练习-Leetcode-2019. The Score of Students Solving Math Expression
算法·leetcode·职场和发展
旦沐已成舟2 小时前
DevOps-Jenkins-新手入门级
服务器