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_MMUunsigned (*mmap_capabilities)(struct file *);
#endifint (*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,需要使用内核库printkprintk("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,需要使用内核库printkprintk("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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1146:吃糖果(C语言)

题目描述 HOHO&#xff0c;终于从Speakless手上赢走了所有的糖果&#xff0c;是Gardon吃糖果时有个特殊的癖好&#xff0c;就是不喜欢连续两次吃一样的糖果&#xff0c;喜欢先吃一颗A种类的糖果&#xff0c;下一次换一种口味&#xff0c;吃一颗B种类的糖果&#xff0c;这样&…

开始使用Spring Boot Admin吧-使用Nacos注册SBA

什么是 Spring Boot Admin&#xff08;SBA&#xff09;? Spring Boot Admin 是 codecentric 公司开发的一款开源社区项目&#xff0c;目标是让用户更方便的管理以及监控 Spring Boot 应用。 应用可以通过我们的Spring Boot Admin客户端&#xff08;通过HTTP的方式&#xff0…

技术人如何实现颠覆式成长

前言 颠覆式成长要求个人不断创新、承担风险&#xff0c;并抓住机遇。通过创新的方法&#xff0c;充分发挥个人的优势&#xff0c;并在个人成长中突破传统、发挥独特的方式和思考&#xff0c;从而实现个人创造力和效能的突破。 颠覆式成长需要不断学习和个人发展&#xff0c;…

C#:程序发布的大小控制

.net不讨喜有个大原因就是.net平台本身太大了&#xff0c;不同版本没有兼容性&#xff0c;程序依赖哪个版本用户就要安装哪个版本&#xff0c;除非你恰好用的是操作系统默认安装的版本——问题是不同版本操作系统默认安装的不一样。 所以打包程序就很头疼&#xff0c;不打包平台…

VScode集成python开发环境和基本插件下载配置

VSCode开发工具 下载VSCode VSCode官方首页&#xff1a;Visual Studio Code - Code Editing. Redefined 点击Download for Windows下载 安装过程一路下一步即可&#xff0c;其中建议勾选 将"通过Code打开"操作添加到Windows资源管理器目录上下文菜单方便我们直接通过…

【电路笔记】-电阻器颜色代码与阻值计算

电阻器颜色代码与阻值计算 文章目录 电阻器颜色代码与阻值计算1、概述2、计算电阻器颜色代码值3、贴片电阻器 电阻器颜色编码使用色带轻松识别电阻器的电阻值及其百分比容差。 1、概述 由于有许多不同类型的电阻器可用&#xff0c;我们需要形成电阻器颜色代码系统以便能够识别…

视频字幕处理+AI绘画,Runway 全功能超详细使用教程(4)

runway的视频字幕处理、AI绘图功能介绍&#xff0c;感觉完全就是为了做电影而布局&#xff0c;一整套功能都上线了&#xff01;想系统学习的必收藏&#xff01; 在深度研究Runway各个功能后&#xff0c;无论是AI视频生成及后期处理技术&#xff0c;还是AI图像生成技术&#xff…

手把手教会你--渗透实战--最开始的靶机演示--项目二:Lampiao

有什么问题&#xff0c;请尽情问博主&#xff0c;QQ群796141573 前言。。。知识1.1 开头介绍1.2 22/80端口1.3 nmap1.4 IP地址1.5 开启靶机--网络模式1.6 信息收集(1) 查看源代码(2) 查看常见漏洞(3) 随便点一点\改一改 1.7 robots.txt。。。实战1.1 确定目标(1) 查看自己的ip地…

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

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

动态规划专项---状态机模型

文章目录 大盗阿福股票买卖IV股票买卖V设计密码修复DNA 一、大盗阿福OJ链接 本题思路:状态表示当前第i家店铺选择偷或者不偷的最大利益。状态计算:f[i][0]std::max(f[i-1][0],f[i-1][1]);//如果第i家店铺被偷,则第i-1家店铺不能被偷&#xff0c;f[i][1]f[i-1][0]w[i]…

如何实现经济破圈?跟随“绿色积分”先行一步!

近年来&#xff0c;随着消费升级和信息技术的发展&#xff0c;新型消费逐渐成为推动经济增长的重要力量。为了加快发展新型消费&#xff0c;国家政府出台了一系列政策措施&#xff0c;《关于以新业态新模式引流新型消费加快发展》文件就是其中之一。本文将从该文件的背景、目的…

MES系统中的工厂计时计件工资

在制造业中&#xff0c;为了提高工资核算的准确性和效率&#xff0c;实时的数据跟踪和数据处理成为了关键。本文将从多个方面详细介绍MES系统在工厂计时计件工资系统方面的解决方案&#xff0c;以及MES系统与ERP系统如何实现联动集成。 一、MES系统在工厂计时计件工资系统中的解…