【IMX6ULL驱动开发学习】06.APP与驱动程序传输数据+自动创建设备节点(hello驱动)

news2024/11/25 18:51:22

一、APP与驱动之间传输数据

/*驱动从APP获取数据*/
unsigned long copy_from_user(void *to, const void *from, unsigned long n)

/*驱动传输数据到APP*/
unsigned long copy_to_user(void *to, const void *from, unsigned long n)

二、使用copy_to_user、copy_from_user在APP与hello驱动之间传输数据

测试方式:

./hello_test /dev/hello 1234abc    APP向驱动程序写入数据
./hello_test /dev/hello            APP从驱动程序读出刚才写入的数据

APP与驱动程序传输数据原理:

  1. APP调用open函数打开设备,使用系统IO函数write写入数据到设备
  2. 系统调用驱动程序的写操作函数(通过file_operations结构体指定),将APP中传入的参数传入该写操作函数
  3. 驱动程序的写操作函数调用copy_from_user函数从用户程序中拷贝数据到驱动程序中
  4. APP调用系统IO函数read,读取驱动数据
  5. 系统调用驱动程序的读操作函数(通过file_operations结构体指定),将驱动程序中的数据拷贝到APP

用一张图片形象的表示一下吧
在这里插入图片描述

三、驱动程序自动创建设备节点

第一步:class_create函数 创建设备类

/*
 * @description		: 创建一个class类型的对象
 * @param - owner	: THIS_MODULE
 * @param - name	: 类名字
 * @return 			: 成功,返回struct class的指针;其他 失败
 */
struct class *class_create(struct module *owner, const char *name)

/*举例*/
static struct class *hello_class;
hello_class = class_create(THIS_MODULE, "hello_class");

第二步:device_create函数 在/dev下创建设备节点(无需在开发板端执行mknod命令了)

/*
 * @description		: 生成设备节点并导出到用户空间(在/dev下创建设备节点)
 * @param - class	: 指向该设备应注册到的struct class的指针(上一个class_create函数返回值)
 * @param - parent	: 指向此新设备的父struct设备的指针(如果有),没有填NULL
 * @param - devt	: 要添加的char设备的dev_t(设备号)
 * @param - drvdata	: 要添加到设备中以进行回调的数据(如果有),没有填NULL
 * @param - fmt		: 设备名称的字符串
 * @return 			: 成功,返回struct device指针;其他 失败
 */
struct device *device_create(struct class *class, struct device *parent, 
								dev_t devt, void *drvdata, const char *fmt, ...)
/*举例*/
device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");

上代码
hello驱动程序代码:

#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/capability.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <asm/therm.h>
#include <linux/string.h>


static int major;
static unsigned char buff[100];
static struct class *hello_class;

static int hello_open (struct inode *node, struct file *filp)
{
	printk("hello_open\n");
	printk("%s %s %d\n",__FILE__, __FUNCTION__, __LINE__);

	return 0;
}

static ssize_t hello_read (struct file *filp, char *buf, size_t size, loff_t *offset)
{
	size_t len = size > 100 ? 100 : size;
	printk("hello_read\n");
	copy_to_user(buf, buff, len);
	return len;
}

static ssize_t hello_write (struct file *filp, const char *buf, size_t size, loff_t *offset)
{
	size_t len = size > 100 ? 100 : size;
	memset(buff, 0 ,sizeof(buff));
	printk("hello_write\n");
	copy_from_user(buff, buf, len);
	return len;
}

static int hello_release (struct inode *node, struct file *filp)
{
	printk("hello_release\n");
	return 0;
}

/*1.定义 file_operations 结构体*/
static const struct file_operations hello_drv = {
    .owner 		= THIS_MODULE,
	.read		= hello_read,
	.write		= hello_write,
	.open		= hello_open,
	.release    = hello_release,
};

/*3.入口函数*/
static int hello_init(void)
{
	//返回主设备号
	major = register_chrdev(0,"hello_drv",&hello_drv);
	
	printk("hello_open\n");
	printk("%s %s %d\n",__FILE__, __FUNCTION__, __LINE__);

	/*在内核中创建设备*/
	hello_class = class_create(THIS_MODULE, "hello_class");
	if (IS_ERR(hello_class)) {
		printk("hello class create failed!\n");
	}

	/*在设备类下面创建设备*/
	device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");
	if (IS_ERR(dev)) {
		printk("hello device_create  failed!\n");
	}
	return 0;
}

/*4.退出函数*/
static int hello_exit(void)
{
	//卸载设备
	unregister_chrdev(major,"hello_drv");

	//销毁设备
	device_destroy(hello_class, MKDEV(major, 0));
	//删除设备类
	class_destroy(hello_class);

	//删除注册的设备号
	// unregister_chrdev_region(major, 1);

	return 0;
}	

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

hello应用程序代码:

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

int main(int argc, char *argv[])
{
    int len;
    char read_buf[10];

    if(argc < 2){
        printf("please input  at least 2 args\n");
        printf("%s <dev> [string]\n", argv[0]);
        return -1;
    }

    /*open*/
    int fd;
    fd = open(argv[1], O_RDWR);
    if(fd < 0){
        printf("open failed\n");
        return -2;
    }

    /*read*/
    if(argc == 2){  
        read(fd, read_buf, 10);    //调用read函数,只为了触发系统调用hello驱动的read函数
        printf("read operation : %s\n", read_buf);
    }

    /*write*/
    if(argc == 3){
        len = write(fd, argv[2], strlen(argv[2]));   //调用write函数,只为了触发系统调用hello驱动的write函数
        printf("write length = %d \n", len);
    }

    close(fd);

    return 0;
}

测试结果:

[root@100ask:/mnt]# insmod hello_drv.ko  (向内核注册hello驱动)
[root@100ask:/mnt]# cat /proc/devices    (查看驱动设备号)
Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
 10 misc
 13 input
 29 fb
 81 video4linux
 89 i2c
 90 mtd
108 ppp
116 alsa
128 ptm
136 pts
166 ttyACM
180 usb
188 ttyUSB
189 usb_device
207 ttymxc
216 rfcomm
226 drm
238 hello_drv
[root@100ask:/mnt]# ls -l /dev/hello       (查看/dev下是否有hello设备节点)
crw------- 1 root root 238, 0 Jan  1 01:37 /dev/hello

#测试hello驱动读写操作
[root@100ask:/mnt]# ./hello_test /dev/hello 1234abc    (向驱动写)
write length = 7 
[root@100ask:/mnt]# ./hello_test /dev/hello            (读驱动)
read operation : 1234abc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/647680.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

32908字长文理解Large CV Model:Segment Anything

作者&#xff1a;猛码Memmat 目录 Abstract1. IntroductionTaskModelData engineDatasetResponsible AIExperimentsRelease 2. Segment Anything TaskTaskPre-trainingZero-shot transferRelated tasksDiscussion 3. Segment Anything ModelImage encoderPrompt encoderMask de…

十个实用MySQL函数

函数 0. 显示当前时间 命令&#xff1a;。 作用: 显示当前时间。 应用场景: 创建时间&#xff0c;修改时间等默认值。 例子&#xff1a; 1. 字符长度 命令&#xff1a;。 作用: 显示指定字符长度。 应用场景: 查看字符长度时。 例子&#xff1a; 2. 日期格式化 命令…

【群智能算法改进】一种改进的白鲸优化算法 改进白鲸优化算法 改进后的EBWO[1]算法【Matlab代码#40】

文章目录 【获取资源请见文章第5节&#xff1a;资源获取】1. 原始BWO算法2. 改进的白鲸优化算法EBWO2.1 Logistic映射2.2 透镜成像折射方向学习 3. 部分代码展示4. 仿真结果展示5. 资源获取 【获取资源请见文章第5节&#xff1a;资源获取】 1. 原始BWO算法 白鲸优化算法 (BWO&…

LeetCode —— 206. 反转链表

LeetCode —— 206. 反转链表 一、题目描述&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 示例 2&#xff1a; 输入&#xff1a;head …

【Shiro】第二章 Shiro概述

目录 1、Shiro简介 2、核心组件 1、Shiro简介 【1】什么是Shiro? Shiro是apache旗下一个开源框架&#xff0c;它将软件系统的安全认证相关的功能抽取出来&#xff0c;实现用户身份认证&#xff0c;权限授权、加密、会话管理等功能&#xff0c;组成了一个通用的安全认证框…

华为OD机试真题 JavaScript 实现【租车骑绿道】【2023Q1 100分】

一、题目描述 部门组织绿岛骑行团建活动&#xff0c;租用公共双人自行车骑行&#xff0c;每辆自行车最多坐两人、最大载重 M。 给出部门每个人的体重&#xff0c;请问最多需要租用多少双人自行车。 二、输入描述 第一行两个数字 m、n&#xff0c;自行车限重 m&#xff0c;代…

管理类联考——逻辑——技巧篇——论说文模块

正论模块 一直为社会、企业所重视。正是因为___让我们在应对挑战中超越自我&#xff0c;形成了一种保持可持续发展的能力与定力,涵养了自强不息、卧薪尝胆的品质&#xff0c;弥补了心智和能力的短板。古今中外这样的事例比比皆是/正如__所言“__”(事实证据或引典&#xff09;…

Mybatis学习之插件

Mybatis学习之插件 Plugins Mybatis中的插件虽然名称叫插件&#xff0c;但实质上是通过动态代理实现的。和我们平时讲的插件概念不一样&#xff0c;但是本质上都是给外部提供接口进行扩展。 MyBatis 允许我们在映射语句执行过程中的某一点进行拦截调用。MyBatis允许我们使用…

【C/C++】引用()的概念和用法

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

推荐几款可以大幅提高开发效率的vscode插件

1、Vue 2 Snippets 这是一款基于vue2的代码片段提示插件&#xff0c;特别好用&#xff0c;可以有效的提高我们的编码速度。 他的能力非常强大&#xff0c;具体还需要我们去看他的文档文档地址 &#xff0c;解锁更多能力。 2、Path Autocomplete 这是一款路劲提示插件 vscod…

计算机网络实验第一课:HTTP和DNS

实验准备 1.先安装好wireshark 2.开启抓包&#xff0c;然后用过滤器选中http。 3.输入http://gaia.cs.umass.edu 网址&#xff0c;摁下回车键。&#xff08;这里我做实验的时候出了点意外&#xff0c;我一开始开着梯子&#xff0c;然后一直都是通过代理访问的网页&#xff…

Spring Security Oauth2.1 最新版 1.1.0 整合 (基于 springboot 3.1.0)gateway 完成授权认证

目录 背景 版本 Spring Boot 3.1 Spring Authorization Server 1.1.0官方文档 基础 spring security OAuth2.0 模块构成 授权方式 集成过程 官方demo 代码集成 依赖 授权服务AuthorizationServerConfig配置 重要组件 测试 查看授权服务配置 访问授权服务 授…

简单实用的快递查询工具,支持批量查询

大家如果遇到快递一直没到的情况&#xff0c;是不是会很心急呢&#xff1f;这时候就要去查询一下快递具体的运输轨迹了&#xff0c;看看自己的快递运输到哪里了。今天小编给大家推荐一款快递信息查询软件&#xff1a;“固乔快递查询助手”&#xff0c;这款软件能够自动识别单号…

管理类联考——英语——知识篇——考研英语熟词生义

考研英语熟词生义 A 1.abandon【生义】放松&#xff0c;沉溺 2.abide【【生义】容忍&#xff0c;经受住 3.abroad【生义】广为流传&#xff0c;传开 4.abrupt【生义】陡峭的&#xff0c;险峻的 5.absent【生义】漫不经心的 6.absolute【【生义】基本的 7.absorb【生义】…

Redis 发布和订阅详细介绍

发布和订阅 发布和订阅是什么 一句话&#xff1a;Redis 发布订阅(pub/sub) 是一种消息通信模式&#xff1a;发送者(pub) 发送消息&#xff0c;订阅者(sub) 接收消息 Redis 客户端可以订阅任意数量的频道 一图胜千言 1、客户端订阅频道示意图 2、当给这个频道发布消息后&am…

[CKA]考试之网络策略NetworkPolicy

由于最新的CKA考试改版&#xff0c;不允许存储书签&#xff0c;本博客致力怎么一步步从官网把答案找到&#xff0c;如何修改把题做对&#xff0c;下面开始我们的 CKA之旅 题目为&#xff1a; Task 在现有的namespace fubar中创建一个名为allow-port-from-namespace的新Netwo…

云原生时代崛起的编程语言Go远程调用gRPC实战

文章目录 概述定义背景特点四种服务方法 实战环境配置proto文件简单RPCToken认证服务器流式RPC客户端流式RPC双向流式RPC 概述 定义 gRPC 官网地址 https://grpc.io/ 源码release最新版本v1.55.1 gRPC 官网文档地址 https://grpc.io/docs/ gRPC 源码地址 https://github.com/g…

【vue3】13-前端路由-Vue-Router的详解: 从入门到掌握

前端路由 前端路由的发展历程认识前端路由&#xff1a;后端路由阶段前后端分离阶段 Vue-Router的使用vue-router的基本使用vue-router的使用过程基本使用的细节补充 路由懒加载分包处理路由的其他属性动态路由路由嵌套路由的编程式导航动态管理路由对象路由导航守卫钩子 前端路…

【毕业N年系列】 毕业第五年

距离上一篇 【毕业N年系列】已经过去一年时间了。没想到自己当初的一个简单的想法竟然能坚持到第五年&#xff0c;希望自己能坚持下去吧&#xff0c;在耄耋古稀之年依然能回看自己的人生。当然本来想着今天能早点下班回来写这篇文章&#xff0c;显然又没有实现&#xff0c;加班…

termux安卓手机 无线adb调试安卓手机

调试机安转termux app Apk下载 安装 https://f-droid.org/packages/com.termux 打开termux 挂载内部存储到~/storage 目录 $ temux-setup-storage 换源加快下载与更新速度 termux-change-repo 选 Main 然后 清华 下载基础软件 pkg install git vim perl nodejs-lts wget…