Linux驱动开发笔记(五):驱动连接用户层与内核层的文件操作集原理和Demo

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

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

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

上一篇:《Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo》
下一篇:敬请期待…


前言

  驱动写好后,用户层使用系统函数调用操作相关驱动从而实现与系统内核的关联,本篇主要就是理解清楚驱动如何让用户编程来实现与内核的交互。


杂项设备文件操作集

cd /usr/src/linux-headers-4.18.0-15
vi include/linux/fs.h

  搜索到(vi则直接使用“/”):
  

struct file_operations {
        struct module *owner;
        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
        ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
        ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
        int (*iterate) (struct file *, struct dir_context *);
        int (*iterate_shared) (struct file *, struct dir_context *);
        __poll_t (*poll) (struct file *, struct poll_table_struct *);
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
        unsigned long mmap_supported_flags;
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *, fl_owner_t id);
        int (*release) (struct inode *, struct file *);
        int (*fsync) (struct file *, loff_t, loff_t, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
        unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
        int (*check_flags)(int);
        int (*setfl)(struct file *, unsigned long);
        int (*flock) (struct file *, int, struct file_lock *);
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
        ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
                        loff_t, size_t, unsigned int);
        int (*setlease)(struct file *, long, struct file_lock **, void **);
        long (*fallocate)(struct file *file, int mode, loff_t offset,
                          loff_t len);
        void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
        unsigned (*mmap_capabilities)(struct file *);
#endif

        int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,
                        u64);
        ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
                        u64);
} __randomize_layout;

  例如read函数,那么就是打开驱动使用系统read,打开这个设备驱动的句柄,那么就会调用read函数,其他的以此类推,还比较好理解。


Linux文件操作集的意义

概述

  Linux一切都是文件,都有对应的打开、关闭和读写等相关操作,而这些操作都是使用打开文件后的句柄来表示,那么函数再根据句柄的类型,如打开的是杂项设备驱动,就会去调用杂项设备操作文件字符集里面对应的函数来执行操作了。
  在编程的时候会使用open打开一个设备节点(可以是文件打开,可以打开设备),这时候返回得到设备节点句柄标识fd(失败是-1),然后使用fd去read、write等各种操作则会相当于调用这个设备驱动里面文件操作集的read、write。
  下面是常用的文件操作。

open函数(实现测试)

int (*open) (struct inode *, struct file *);

read函数(实现测试)

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *)

write函数(实现测试)

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

poll/select函数(本篇没写)

__poll_t (*poll) (struct file *, struct poll_table_struct *);

ioctl函数(本篇没写)

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

close函数(实现测试)

int (*release) (struct inode *, struct file *);


驱动模板准备

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

cd ~/work/drive
cp -arf registerMiscDev testFileOpts
cd testFileOpts
make clean
mv registerMiscDev testFileOpts.c

  在这里插入图片描述

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

gedit Makefile  

  在这里插入图片描述

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

gedit testFileOpts.c

  在这里插入图片描述

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

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

struct file_operations misc_fops = {
  .owner = THIS_MODULE,
};

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

static int registerMiscDev_init(void)
{ 
    int ret;
    // 在内核里面无法使用基础c库printf,需要使用内核库printk
    printk("Hello, I’m hongPangZi, registerMiscDev_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);

杂项设备添加常用操作集open函数Demo

  注意,要是调用的函数没有写,则不会报错也不会有其他操作反应,所以并不是所有函数都是必须写的。

步骤一:实现open函数

// 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)");
    return 0;
}

  在这里插入图片描述

步骤二:(关键)赋值到文件操作集指针

  在这里插入图片描述

步骤三:编译加载驱动

  先编译试试:
  在这里插入图片描述

  然后加载驱动:

sudo insmod tesFileOpts.ko

  在这里插入图片描述

  在这里插入图片描述

  在这里插入图片描述

  这时候,设备节点注册成功了。

步骤四:在程序中调用打开设备节点open

  本步骤是c语言编程,使用linux系统函数打开设备节点:
  新建文件:

vi test.c

  输入代码:

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

int main(int argc, char **argv)
{
  int fd;
  const char devPath[] = "/dev/register_hongPangZi_testFileOpt";
  fd = open(devPath, O_RDWR);
  if(fd < 0)
  {
    printf("fialed to open %s\n", devPath);
    return -1;
  } else{
    printf("Succeed to open %s\n", devPath);
  }
  return 0;
}

  在这里插入图片描述

  编译:

gcc test.c

  在这里插入图片描述

  默认输出就是a.out,下面运行一下:
  在这里插入图片描述

  无法运行,是因为ubuntu对设备需要管理员权限,管理员权限运行:
  在这里插入图片描述

  查看内核打印输出(这里出现没有打印输出,查看“入坑一”):
  在这里插入图片描述

  至此,从用户编程层如何对设备结点,然后调用到内核层函数就基本清楚了。


补充其他函数Demo

补充read、write

#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_testFileOpt", // 设备节点名称
    .fops = &misc_fops,  // 这个变量记住,自己起的,步骤二使用
};

static int registerMiscDev_init(void)
{ 
    int ret;
    // 在内核里面无法使用基础c库printf,需要使用内核库printk
    printk("Hello, I’m hongPangZi, registerMiscDev_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);

修改test.c测试驱动源码

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

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

  const char devPath[] = "/dev/register_hongPangZi_testFileOpt";
  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);
  }

  read(fd, buf, sizeof(buf));
  write(fd, buf, sizeof(buf));

  close(fd);
  printf("exit\n");
  fd = -1;
  return 0;
}

查看输出

  在这里插入图片描述


入坑

入坑一:内核未打印open函数

问题

  程序打开设别节点,未打印open函数

原因

  打开函数没有赋值给文件操作集。

解决

  在这里插入图片描述

入坑二:dmesg少了close的release打印

问题

  在这里插入图片描述

测试

  在这里插入图片描述

  在这里插入图片描述

  研究了dmesg,就是没出来,这个不清楚了,后来问了驱动大佬,提醒是可能是换行的问题,后加上可以了。

解决方法

  在这里插入图片描述
  在这里插入图片描述


上一篇:《Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo》
下一篇:敬请期待…


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

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

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

相关文章

Vue 实现低代码开发平台,没想到这么好用!

前言 在众多开发技术中&#xff0c;Vue 组件化开发技术以其卓越的灵活性和高效性备受瞩目。 低代码平台相信不少人知道它的存在&#xff0c;而且现在大部分公司都在开发自己的低代码平台&#xff0c;首先我们来看看低代码平台可视化界面&#xff1a; 官网&#xff1a;https:/…

MySQL中自增id用完怎么办?

MySQL中自增id用完怎么办&#xff1f; MySQL里有很多自增的id&#xff0c;每个自增id都是定义了初始值&#xff0c;然后不停地往上加步长。虽然自然数是没有上限的&#xff0c;但是在计算机里&#xff0c;只要定义了表示这个数的字节长度&#xff0c;那它就有上限。比如&#…

第二十章,多线程

创建线程 有两种方式&#xff0c;分别为继承Java.lang.Thread类与实现Java.lang.Runnable接口 继承Thread类 Thread常用的两个构造方法语法 public Thread&#xff08;&#xff09;&#xff1b; public Thread&#xff08;String threadName&#xff09;&#xff1b; 继承…

新生儿腺体肥大:原因、科普和注意事项

引言&#xff1a; 新生儿的健康问题常常让父母感到焦虑&#xff0c;其中之一就是腺体肥大。了解腺体肥大的原因、科普相关知识&#xff0c;并采取一些建议的注意事项&#xff0c;对于保障新生儿的健康非常重要。本文将深入解析新生儿腺体肥大的原因、提供相关科普知识&#xf…

可移动框 弹窗 可拖拽的组件

电脑端: <template><divv-if"show"ref"infoBox"mousedown.stop"mouseDownHandler"class"info-box":style"styleObject"><slot></slot></div> </template> <script> export defa…

自媒体爆文采集工具,几个免费的网站让你每日爆文增加

随着自媒体的蓬勃发展&#xff0c;许多人憧憬着在这个领域获得成功和流行。然而&#xff0c;随着寒冷的冬天的降临&#xff0c;媒体从业者的日常生活并没有变得更加美好。在竞争激烈的环境中&#xff0c;为了生存&#xff0c;他们必须发布引人注目的内容&#xff0c;然而&#…

4个Python实战项目,让你瞬间读懂Python!

前言 Python 是一种极具可读性和通用性的编程语言。Python 这个名字的灵感来自于英国喜剧团体 Monty Python&#xff0c;它的开发团队有一个重要的基础目标&#xff0c;就是使语言使用起来很有趣。Python 易于设置&#xff0c;并且是用相对直接的风格来编写&#xff0c;对错误…

从裸机启动开始运行一个C++程序(十五)

前序文章请看&#xff1a; 从裸机启动开始运行一个C程序&#xff08;十四&#xff09; 从裸机启动开始运行一个C程序&#xff08;十三&#xff09; 从裸机启动开始运行一个C程序&#xff08;十二&#xff09; 从裸机启动开始运行一个C程序&#xff08;十一&#xff09; 从裸机启…

lightdb-ignore_row_on_dupkey_index

LightDB 支持 ignore_row_on_dupkey_index hint LightDB 从23.4 开始支持oracle的 ignore_row_on_dupkey_index hint&#xff0c; 这个hint是用来忽略唯一键冲突的。类似与mysql的 insert ignore。 语法如下&#xff1a; 在LightDB中ignore_row_on_dupkey_index的效果等同于o…

大坝安全监测的内容及作用

大坝安全监测是指对大坝水雨情沉降、倾斜、渗压以及大坝形状特征有效地进行监测&#xff0c;及时发现潜在的安全隐患和异常情况&#xff0c;以便大坝管理人员能够做出科学决策&#xff0c;以确保大坝安全稳定运行。 大坝安全监测的主要内容 1.表面位移监测&#xff1a;监测大坝…

Vue基础入门(三):Vue3的使用

Vue3的使用 一、首页案例修改 修改首页的信息&#xff1a;是在之前介绍的HelloWorld.vue文件中进行内容的修改。 页面展示效果&#xff1a; 此时就看到了我们新添加的文字了&#xff01; 同样的我们开发代码的时候只需要修改了项目中的内容然后保存就会自动刷新的浏览器&…

接口测试:Jmeter和Postman测试方法对比

前阶段做了一个小调查&#xff0c;发现软件测试行业做功能测试和接口测试的人相对比较多。在测试工作中&#xff0c;有高手&#xff0c;自然也会有小白&#xff0c;但有一点我们无法否认&#xff0c;就是每一个高手都是从小白开始的&#xff0c;所以今天我们就来谈谈一大部分人…

OpenSearch向量检索和大模型方案深度解读

大家好&#xff0c;我叫邢少敏&#xff0c;目前负责阿里云开放搜索OpenSearch的研发&#xff0c;很高兴在此跟大家分享OpenSearch在向量检索和大模型方面做的一些工作。 基于向量检索的分布式智能搜索引擎 通常&#xff0c;数据大致可以分为结构化数据和非结构化数据两种类型…

“2024上海智博会、2024北京智博会”双展联动,3月上海,6月北京

“2024上海智博会、2024北京智博会”双展联动&#xff0c;将分别于3月和6月在上海和北京举办。这两个展会旨在充分展示智慧城市、人工智能、物联网、大数据、软件等新兴行业的最新产品和技术。 作为中国最具影响力和创新力的智能科技展会&#xff0c;上海智博会和北京智博会吸引…

ArkTS-属性动画和显式动画

属性动画 组件的某些通用属性变化时&#xff0c;可以通过属性动画实现渐变过渡效果&#xff0c;提升用户体验。支持的属性包括width、height、backgroundColor、opacity、scale、rotate、translate等。 名称参数类型必填描述durationnumber否设置动画时长。默认值&#xff1a;1…

ArkUI 如何将$r(’app.string.xxx‘) 转成string字符串

一、正常引用字符串资源文件内容 在 ArkUI 中&#xff0c;string.json 中的字符串资源正常情况下使用如下方式引用&#xff1a; Entry Component struct LoginPage {build() {Column() {Text($r(app.string.title))}}}二、资源转string类型 上面的代码没问题是因为 Text(con…

探究Kafka原理-7.exactly once semantics 和 性能测试

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理&#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44…

盖茨表示GPT-5不会比GPT-4有太大改进;Intro to Large Language Models

&#x1f989; AI新闻 &#x1f680; 盖茨表示GPT-5不会比GPT-4有太大改进 摘要&#xff1a;比尔盖茨在与德国《商报》的采访中透露&#xff0c;虽然OpenAI内部有人相信GPT-5会优于GPT-4&#xff0c;但他认为目前的生成式人工智能已经达到极限。盖茨对GPT-5未来的发展并不乐观…

Vue基础入门(四):Vue3快速开发模板

快速开发Vue的解决方案 ​ Vue 的开发需要的 node 环境&#xff0c;其实上在开发的过程中会遇到一些你想不到的问题&#xff0c;比如 npm工具的版本和 node 环境不匹配&#xff08;你把其他项目导入到自己的环境&#xff09; ​ vue-element-admin&#xff08;是一个官方提供…

Ubuntu系统CLion安装

Ubuntu系统CLion安装 pycharm 同理。 参考官网安装过程&#xff1a;官网安装过程 下载linux tar.gz包 # 解压 sudo tar -xzvf CLion-*.tar.gz -C /opt/ sh /opt/clion-*/bin/clion.sh其中第二个命令是启动CLion命令 clion安装完以后&#xff0c;不会在桌面或者菜单栏建立图…