Linux驱动开发笔记(六):用户层与内核层进行数据传递的原理和Demo

若该文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/135384355

红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…

Linux系统移植和驱动开发专栏

上一篇:《Linux驱动开发笔记(五):驱动连接用户层与内核层的文件操作集原理和Demo》
下一篇:敬请期待…


前言

  驱动作为桥梁,用户层调用预定义名称的系统函数与系统内核交互,而用户层与系统层不能直接进行数据传递,进行本篇主要就是理解清楚驱动如何让用户编程来实现与内核的数据交互传递。


温故知新

  • 设备节点是应用层(用户层)与内核层交互;
  • 使用预先的结构体进行操作,如系统open函数对应了驱动中文件操作及的open指针结构体:struct file_operations;
  • 文件操作集结构体,填充结构体对应指针,填充自己使用到的就行了,多余的可以不填充,调用也不会崩溃或返回错误,会返回0;
      在这里插入图片描述

  那么如何将应用层的输入写入进去可用,如何将内核层的数据通过read返回出来,就是本篇学习了。


驱动模板准备

  首先复制之前的testFileOpts的驱动,改个名字为:testFileOpts:

cd ~/work/drive/
ls
cp -arf 003_testFileOpts 004_testReadWrite
cd 004_testReadWrite/
make clean
ls
mv testFileOpts.c testReadWrite.c
vi Makefile 
ls

  在这里插入图片描述

  其中修改makefile里面的模块名称(obj-m模块名称),模板准备好了

gedit Makefile 

  在这里插入图片描述

  下面基于testReadWrite.c文件进行注册杂项设备,修改.c文件:

gedit testReadWrite.c

  在这里插入图片描述

  在这里插入图片描述

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>

// int (*open) (struct inode *, struct file *);
int misc_open(struct inode * pInode, struct file * pFile)
{
    printk("int misc_open(struct inode * pInode, struct file * pFile)\n");
    return 0;
}

// int (*release) (struct inode *, struct file *);
int misc_release(struct inode * pInde, struct file * pFile)
{
    printk("int misc_release(struct inode * pInde, struct file * pFile)\n");
    return 0;
}

// ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t misc_read(struct file * pFile, char __user * pUser, size_t size, loff_t *pLofft)
{
    printk("ssize_t misc_read(struct file * pFile, char __user * pUser, size_t size, loff_t *pLofft)\n");
    return 0;
}

// ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t misc_write(struct file * pFile, const char __user * pUser, size_t size, loff_t *pLofft)
{
    printk("ssize_t misc_write(struct file * pFile, const char __user * pUser, size_t size, loff_t *pLofft)\n");
    return 0;
}

struct file_operations misc_fops = {
  .owner = THIS_MODULE,
  .open = misc_open,
  .release = misc_release,
  .read = misc_read,
  .write = misc_write,
};

struct miscdevice misc_dev = {
    .minor = MISC_DYNAMIC_MINOR, // 这个宏是动态分配次设备号,避免冲突
    .name = "register_hongPangZi_testReadWrite", // 设备节点名称
    .fops = &misc_fops,  // 这个变量记住,自己起的,步骤二使用
};

static int registerMiscDev_init(void)
{ 
    int ret;
    // 在内核里面无法使用基础c库printf,需要使用内核库printk
    printk("Hello, I’m hongPangZi, registeraMiscDev_init\n");	
    ret = misc_register(&misc_dev);
    if(ret < 0)
    {
        printk("Failed to misc_register(&misc_dev)\n");	
        return -1;
    } 
    return 0;
}

static void registerMiscDev_exit(void)
{
    misc_deregister(&misc_dev);
    printk("bye-bye!!!\n");
}

MODULE_LICENSE("GPL");
module_init(registerMiscDev_init);
module_exit(registerMiscDev_exit);

概述

  内核层和用户层不能中是不能直接与用户数据交互,需要使用内核函数copy_to_user和copy_from_user。
  在内核中可以使用printk,memset,memcpy,strlen等函数。


内核函数

  头文件是:linux/uaccess.h(我们这是ubuntu,不是arm)
  可以在内核根目录下搜索下:

find . -type f -exec grep -l "copy_to_user(void" {} \;

  在这里插入图片描述

  在这里插入图片描述

copy_from_user函数:从用户层复制到内核层

static __always_inline unsigned long __must_check
copy_from_user(void *to, const void __user *from, unsigned long n)

  简化下:

static unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)

  参数分别是,复制到的地址(内核空间),从什么地址复制(用户空间),复制长度;

copy_to_user函数:从内核层复制到用户层

static __always_inline unsigned long __must_check
copy_to_user(void __user *to, const void *from, unsigned long n)

  简化下:

static unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)

  参数分别是,复制到的地址(用户空间),从什么地址复制(内核空间),复制长度;


杂项设备驱动添加数据传递函数Demo

步骤一:加入头文件和定义static缓存区

  在这里插入图片描述

#include <linux/uaccess.h>      // Demo_004 add
static char kBuf[256] = {0x00};  // Demo_004 add

步骤二:初始化缓存区

  在这里插入图片描述

// int (*open) (struct inode *, struct file *);
int misc_open(struct inode * pInode, struct file * pFile)
{
    printk("int misc_open(struct inode * pInode, struct file * pFile)\n");
    memcpy(kBuf, "init kBuf", sizeof("init kBuf"));
    printk("kBuf = %s\n", kBuf); 

    return 0;
}

步骤三:在驱动函数read中,添加从内核层到用户层的函数

  在这里插入图片描述

// ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t misc_read(struct file * pFile, char __user * pUser, size_t size, loff_t *pLofft)
{
    printk("ssize_t misc_read(struct file * pFile, char __user * pUser, size_t size, loff_t *pLofft)\n");
    if(copy_to_user(pUser, kBuf, strlen(kBuf)) != 0)
    {
        printk("Failed to copy_to_user(pUser, kBuf, strlen(kBuf)\n");
        return -1;
    }
    return 0;
}

步骤四:在驱动函数wirte中,添加从用户层到内核层的函数

  在这里插入图片描述

// ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t misc_write(struct file * pFile, const char __user * pUser, size_t size, loff_t *pLofft)
{
    printk("ssize_t misc_write(struct file * pFile, const char __user * pUser, size_t size, loff_t *pLofft)\n");
    if(copy_from_user(kBuf, pUser, size) != 0)
    {
        printk("Failed to copy_from_user(kBuf, pUser, size)\n");
        return -1;
    }
    return 0;
}

步骤五:在程序中读取、写入、再读取

  在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
  int fd = -1;
  char buf[32] = {0};
  int ret = -1;

  const char devPath[] = "/dev/register_hongPangZi_testReadWrite";
  fd = open(devPath, O_RDWR);
  if(fd < 0)
  {
    printf("Failed to open %s\n", devPath);
    return -1;
  }else{
    printf("Succeed to open %s\n", devPath);
  }
  // 读取
  ret = read(fd, buf, sizeof(buf) < 0);
  if(ret < 0)
  {
    printf("Failed to read %s\n", devPath);
    close(fd);
    return 0;
  }else{
    printf("Succeed to read [%s]\n", buf);
  }
  // 修改内容
  memset(buf, 0x00, sizeof(buf));
  memcpy(buf, "Get you content", strlen("Get you content"));
  // 写入
  ret = write(fd, buf, sizeof(buf));
  if(ret < 0)
  {
    printf("Failed to write %s\n", devPath);
    close(fd);
    return 0;
  }else{
    printf("Succeed to write [%s]\n", buf);
  }
  // 读取
  ret = read(fd, buf, sizeof(buf) < 0);
  if(ret < 0)
  {
    printf("Failed to read %s\n", devPath);
    close(fd);
    return 0;
  }else{
    printf("Succeed to read [%s]\n", buf);
  }

  close(fd);

  printf("exit\n");

  fd = -1;


  return 0;
}

步骤六:编译加载驱动

  在这里插入图片描述

make
sudo insmod testReadWrite.ko

步骤七:编译程序运行结果

gcc test.c
sudo ./a.out

  在这里插入图片描述

  测试结果与预期相同


入坑

入坑一:测试程序读取与预期不同

问题

  在这里插入图片描述

原因

  在这里插入图片描述

解决

  在这里插入图片描述


上一篇:《Linux驱动开发笔记(五):驱动连接用户层与内核层的文件操作集原理和Demo》
下一篇:敬请期待…


本文章博客地址:https://hpzwl.blog.csdn.net/article/details/135384355

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

互联网加竞赛 基于RSSI的室内wifi定位系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; wifi室内定位系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;…

list1.Sort((m, n) => m.Id - n.Id); id是double类型的为什么回报错

问题产生的地方 原因 对于 double 类型的属性&#xff0c;不能直接使用减法运算符进行比较。减法运算符只能用于数值类型&#xff0c;而 double 是浮点数类型。 要在 double 属性上进行排序&#xff0c;可以使用 CompareTo 方法或者使用自定义的比较器。 更改 要在 double 属性…

iOS UITextField复制、粘贴框显示为英文如何解决

问题描述&#xff1a; 使用UITextField&#xff0c;欲粘贴文本&#xff0c;长按或者双击展示的提示框显示为英文 解决方案&#xff1a; 在Xcode配置文件info,plist文件中&#xff0c;新增Localizas属性&#xff0c;填入Chinese 结果如下&#xff1a; 提示框成功展示为中文

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -后端架构搭建

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

Android Framework | Linux 基础知识:入门指南

Android Framework | Linux 基础知识&#xff1a;入门指南 进行Android Framework开发需要具备基本的Linux基本知识&#xff0c;下面是一份Linux基础知识入门指南&#xff0c;希望对你有所帮助&#xff01; 1. 简介 Linux 是一种免费、开源的操作系统&#xff0c;它是由芬兰…

基于Java SSM框架实现固定资产管理系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现固定资产管理系统演示 摘要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&a…

【科研绘图】手把手教你Origin安装以及汉化,附带网盘链接

Origin安装 1.下载文件压缩包2.&#xff08;软件安装部分&#xff09;解压&#xff0c;以管理员身份运行&#xff0c;.exe&#xff0c;下一步3. &#xff08;软件设置部分&#xff09;打开软件无需更改&#xff0c;点OK4. &#xff08;破解部分&#xff09;&#xff0c;找到刚才…

基于gitlab 12.8.0版本的完整镜像过程

目前已在一台服务器上安装了gitlab 12.8.0&#xff0c;并且稳定运行了有几年了&#xff0c;其上面也创建了大量的项目。目前要求对该gitlab及其上面的所有仓库做一个完整的镜像。具体操作过程如下&#xff1a; 1、确认现有的gitlab的版本号 2、到gitlab官网下载相同版本号的gi…

生活中危险的气体:一氧化碳与二氧化碳中毒的症状及安全预防措施

一氧化碳和血红蛋白亲和力超过氧气&#xff0c;会占用血红蛋白&#xff0c;导致缺氧。 二氧化碳会和血浆结合&#xff0c;导致血液pH值不正常&#xff0c;抑制呼吸&#xff0c;导致窒息。 通俗点说&#xff1a;一氧化碳是中毒&#xff0c;二氧化碳则是窒息。 一氧化碳中毒 …

d3dcompiler_43.dll丢失怎么修复?怎么解决

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“找不到d3dcompiler_43.dll文件”。那么&#xff0c;d3dcompiler_43.dll是什么文件&#xff1f;它的作用是什么&#xff1f;如果缺失了该如何修复呢&#xff1f;本文将详细介绍d3dcompiler_…

一款神仙级SpringCloud微服务开源项目,接私活吊到不行!(附源码)

今天给大家推荐一个牛逼的接私活项目&#xff0c;SpringCloud微服务架构项目&#xff01; 一个由商业级项目升级优化而来的微服务架构&#xff0c;采用SpringBoot 2.7 、SpringCloud 等核心技术构建&#xff0c;提供基于React和Vue的两个前端框架用于快速搭建企业级的SaaS多租…

CDD文件的制作

CDD文件 1、核查诊断调查表2、制作CDD3、Diva测试 1、核查诊断调查表 ECU级别&#xff1a;包括文档相关、控制器的诊断ID和时间参数&#xff0c;支持的服务&#xff0c;DTC、DID、刷写流程。 2、制作CDD 2.1、cddt编辑思路&#xff08;每一步都要根据调查表进行操作&#xf…

【Netapp数据恢复】Netapp存储lun被删除如何恢复数据?

Netapp存储数据恢复环境&故障情况&#xff1a; 某单位一台Netapp存储&#xff0c;该Netapp存储内共有数十块SAS硬盘。 工作人员误操作删除了Netapp存储中12个lun&#xff0c;删除的数据包括客户信息和其他重要数据。 Netapp存储数据恢复过程&#xff1a; 1、将故障存储中所…

在Go语言中处理HTTPS请求

随着互联网的发展&#xff0c;安全性变得越来越重要。HTTPS作为安全的HTTP协议&#xff0c;已经被广泛使用。在Go语言中&#xff0c;处理HTTPS请求需要一些特定的步骤。本文将详细介绍如何在Go语言中处理HTTPS请求。 首先&#xff0c;确保你已经安装了Go语言的开发环境&#x…

【Python机器学习】评估模型

以鸢尾花数据为例&#xff0c;将测试数据中的每朵鸢尾花进行预测&#xff0c;并将预测结果与已知标签结果进行对比&#xff0c;可以计算精度来衡量模型的优劣。精度就是品种预测正确的结果占比。 import numpy as np from sklearn.datasets import load_iris from sklearn.mod…

炼石白小勇:免改造数据安全技术,破局信创安全升级难点

2023年7月13日&#xff0c;由中国计算机学会主办&#xff0c;中国计算机学会抗恶劣环境计算机专委会、江苏省企业联合会、江苏省互联网协会、中国计算机学会南京会员活动中心联合承办的“2023&#xff08;第六届&#xff09;CCF自主可控计算机大会”在江苏南京盛大开幕。本次会…

深度学习中的大模型「幻觉」问题:解析、原因及未来展望

如何解决大模型的「幻觉」问题&#xff1f; 什么是大模型「幻觉」 大模型幻觉是指在深度学习领域中&#xff0c;尤其是涉及大型神经网络时&#xff0c;模型展现出在理论上不应具备的性能或能力。这种现象可能导致误导性的结果&#xff0c;表现为在训练数据上过度拟合&#xff0…

无线温振传感器在石油石化行业设备状态监测的使用场景

石油石化行业作为全球能源供应的重要支柱&#xff0c;在生产和加工过程中依赖大量设备和机械设施。为了确保设备的正常运行和生产的连续性&#xff0c;设备状态监测显得尤为关键。无线温振传感器作为一种先进的智能传感技术&#xff0c;为石油石化行业设备状态监测提供了全新的…

FBL刷写

刷写 1、刷写需求的理解2、刷写流程2.1、预编程阶段&#xff1a;保证在编程阶段的动作能够正常操作&#xff0c;控制器给响应。整车功能不会出现问题 刷写某一控制器时&#xff0c;避免其他控制器集DTC,85控制DTC&#xff1b; 28 通信控制.保证总线负载率不要过高&#xff08;下…