Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo

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

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

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

上一篇:《Linux驱动开发笔记(三):基于ubuntu的helloworld驱动源码编写、makefile编写以及驱动编译加载流程测试》
下一篇:敬请期待…


前言

  驱动的开发需要先熟悉基本概念类型,本篇讲解linux杂项设备基础,还是基于虚拟机ubuntu去制作驱动,只需要虚拟机就可以尝试编写注册杂项设备的基本流程。


linux三大设备驱动

  • 字符设备:IO的传输过程是以字符为单位的,没有缓冲,比如I2C(SDA、SCL),SPI(MISO、MOSI、SCLK、CS)。
  • 块设备:IO的传输过程是以块为单位的,跟存储相关的都属于块设备,比如tf卡,sd卡。
  • 网络设备:IO的传输以socket套接字来访问的。

杂项设备

  • 杂项设备是属于字符设备,可以自动生成设备节点,设备节点位于/dev/目录下,是设备名称,如/dev/ttyS9等。
  • 主设备号相同,统一为10,次设备号不同,主设备相同可以节省内核资源。
    通过下列指令,可以查看系统杂项设备
cat /proc/misc

  在虚拟机上测试,查看杂项:
  在这里插入图片描述

  • 设备号分为主设备号和次设备号,主设备号是唯一的,次设备号不一定唯一。
    通过下列指令,可以查看系统主设备号:
cat /proc/devices

  在这里插入图片描述

杂项设备描述结构体

  ubuntu来说,自带的/usr/src下的就是内核的头文件。

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

  定位到之前ubuntu自带的内核头文件下:
  在这里插入图片描述
  在这里插入图片描述

  查看到杂项设备的结构体:

struct miscdevice  {int minor;  // 次设备号const char *name;  // 设备节点名称(如/dev/ttyS8,则ttyS是名称)const struct file_operations *fops; // 文件操作集(非常重要)struct list_head list; struct device *parent;struct device *this_device;const struct attribute_group **groups; const char *nodename; umode_t mode;
};

  (注意:没打注释的,一般不管)

杂项设备文件操作集

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);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 *);
#endifssize_t (*copy_file_range)(struct file *, loff_t, struct file *,loff_t, size_t, unsigned int);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函数,其他的以此类推,还比较好理解。
  以我们一个registerHelloWorld为例子,来简单说明。


驱动编写空模板准备

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

cd ~/work/drive
cp -arf hellowolrd registerMiscDev

  在这里插入图片描述

cd registerMiscDev/
rm *.ko *.o *.order *.symvers

  这里删除起来麻烦,修改makefile,添加clean:
  在这里插入图片描述

  然后测试一下:
  在这里插入图片描述

  继续修改源码文件名称:

mv helloworld.c registerMiscDev.c

  修改完如下:
  在这里插入图片描述

  然后修改makefile里面的(obj-m模块名称改下),模板准备好了
  在这里插入图片描述

  下面基于registerMiscDev.c文件进行注册杂项设备,在修改.c文件:
  在这里插入图片描述

#include <linux/init.h>
#include <linux/module.h>static int registerMiscDev_init(void)
{ // 在内核里面无法使用基础c库printf,需要使用内核库printkprintk("Hello, I’m hongPangZi, registerMiscDev_init\n");	return 0;
}
static void registerMiscDev_exit(void)
{printk("bye-bye!!!\n");
}
MODULE_LICENSE("GPL");
module_init(registerMiscDev_init);module_exit(registerMiscDev_exit); 

杂项设备注册流程Demo

步骤一:填充miscdevice结构体

  在编写驱动的时候,代码中填充信息结构体。
  添加头文件miscdevice.h

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

  在这里插入图片描述

  然后填充杂项设备结构体:
  在这里插入图片描述

  (注意:开始为“.”,结束为“,”,最后一行习惯加“,”了,这样可以全部统一复制啥的,省的加没加的)

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

  在这里插入图片描述

步骤二:填充file_operations结构体

  在编写驱动的时候,代码中填充文件操作结构体。
  在这里插入图片描述

struct file_operations misc_fops {.owner = THIS_MODULE
}

  在这里插入图片描述

步骤三:注册杂项设备并生成设备节点

  注册到内核:

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

  在这里插入图片描述

  有注册就有注销:

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

  在这里插入图片描述

  完整的文件源码:

#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_misc", // 设备节点名称.fops = &misc_fops,  // 这个变量记住,自己起的,步骤二使用
};static int registerMiscDev_init(void)
{ // 在内核里面无法使用基础c库printf,需要使用内核库printkprintk("Hello, I’m hongPangZi, registerMiscDev_init\n");	int ret = 0;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);

步骤四:编译make

make

  直接在驱动工程目录编译:
  在这里插入图片描述

  下面这个警告,实际上定义要在任何使用函数之前:
  在这里插入图片描述

  修改下:
  在这里插入图片描述

  在这里插入图片描述

  编译成功
  在这里插入图片描述

步骤五:加载卸载驱动测试

  将驱动拷贝到开发板或者目标系统,然后使用加载指令:

sudo insmod registerMiscDev.ko

  会打印入口加载的printk输出。
  在这里插入图片描述

  出现问题可能原因一是内核编译使用的编译器和模块使用的编译器版本不一致。ubuntu中printk终端打入内核日志消息了,可以使用dmesg进行查看:

dmesg

  在这里插入图片描述

  然后查看是否加入了杂项设备节点:
  在这里插入图片描述

  然后注销:

sudo rmmod registerMiscDev.ko

  在这里插入图片描述

  跟随着,结点消失了:
  在这里插入图片描述


入坑

入坑一:编译报错,结构体之后未加分号

问题

  编译错误,结构体后面加分号

解决

  加分号,脑袋有点蒙
  在这里插入图片描述

入坑二:编译错误,文件操作指针问题

问题

  在这里插入图片描述

解决

  这是写错了,是指针,需要加取地址&。


上一篇:《Linux驱动开发笔记(三):基于ubuntu的helloworld驱动源码编写、makefile编写以及驱动编译加载流程测试》
下一篇:敬请期待…


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

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

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

相关文章

[AutoSar]在Davinci Configurator中导入Dbc Cdd 文件

目录 关键词平台说明一、实现步骤1.1 添加相关模块1.2 导入文件1.3 加载完成后点next而不是finish1.4 更新配置1.5 解决错误 关键词 嵌入式、C语言、autosar 平台说明 项目ValueOSautosar OSautosar厂商vector芯片厂商TI编程语言C&#xff0c;C编译器HighTec (GCC) 一、实现…

【码神之路】【Golang】博客网站的搭建【学习笔记整理 持续更新...】

介绍 一个用原生GO开发的博客网站&#xff0c;涉及Golang Web开发、Web服务器搭建和HTTP请求处理、模板与静态资源处理等 技术栈 后端&#xff1a;Go、Go并发机制前端&#xff1a;HTML模版链接直达 Golang搭建博客网站的学习视频 注&#xff1a;这里我只记录我实质✅学习到…

2021秋招-数据结构-栈、队列、数组、列表

栈、队列、数组、列表 实现方式 队列 class Queue:def __init__(self):self.items []def enqueue(self, item):self.items.append(item)def dequeue(self):return self.items.pop(0)def empty(self):return self.size() 0def size(self):return len(self.items)应用: 约瑟…

【Hello Go】Go语言文本文件处理

文本文件处理 字符串处理字符串操作ContainsJoinindexrepeatReplaceSplitTrimFields 字符串转换AppendFormatParse 正则表达式Json处理编码Json通过结构体生产Json通过map生产json 解码Json解析到结构体解析到interface 文件操作相关api介绍建立和打开文件关闭文件写文件读文件…

中国出海主力系列专访之三七互娱:亚马逊云科技助力三七互娱海外“出圈”之路

如果问&#xff0c;在众多的中国出海赛道中哪一条拥有基数最大的粉丝拥趸&#xff1f;以网络游戏、社交媒体、直播、短视频为代表的泛娱乐赛道便成为当仁不让的领跑者。 在东京、新加坡、开罗、伦敦、纽约、慕尼黑等国际都市&#xff0c;当地的年轻人会随时随地的打开“中国造”…

JOSEF 静态中间继电器 ZJY-420 DC220V 板前接线,带底座 增加触点

系列型号&#xff1a; ZJY-400中间继电器&#xff1b;ZJY-600中间继电器&#xff1b; ZJY-800中间继电器&#xff1b;ZJY-020中间继电器&#xff1b; ZJY-040中间继电器&#xff1b;ZJY-060中间继电器&#xff1b; ZJY-006中间继电器&#xff1b;ZJY-008中间继电器&#xff1b;…

SD-WAN技术:重新定义网络连接方式

随着数字化转型的不断加速&#xff0c;企业对网络的需求呼之欲出。传统的WAN网络由于配置复杂、成本高昂以及带宽利用率低等问题而面临挑战。这时SD-WAN技术的出现正好派上了用场&#xff0c;通过其虚拟化、自动化和智能化的技术手段&#xff0c;大幅度提高了企业网络性能和可靠…

Ps:裁剪工具 - 裁剪预设的应用

裁剪工具提供了两种类型的裁剪方式。 一种是仅按宽高比&#xff08;比例&#xff09;进行裁剪&#xff0c;常在对图像进行二次构图时采用。 另一种则按指定的图像尺寸&#xff08;宽度值和高度值&#xff09;及分辨率&#xff08;宽 x 高 x 分辨率&#xff09;进行裁剪。其实质…

关于一些网络的概述

语义分割网络是一种基于深度学习的计算机视觉技术,它能够将图像中的每个像素分配给特定的类别,从而实现对图像中不同对象的精确识别和定位。近年来,随着深度学习技术的不断发展,语义分割网络在各个领域都取得了显著的进展。 早期的语义分割网络主要采用全卷积神经网络(FC…

scala的schema函数(算子)

在翻阅一些代码的时候&#xff0c;schema算子好像没碰到过&#xff0c;比较好奇structField这个类型&#xff0c;为什么可以直接用name参数&#xff0c;就翻阅了下资料&#xff1a; 在 Apache Spark 中&#xff0c;DataFrame 是一种分布式的数据集&#xff0c;它是以类似于关系…

OFI libfabric原理及应用解析

Agenda 目录/议题 编译通信软件硬件和软件带来的挑战为什么需要libfabriclibfabric架构API分组socket应用 VS libfabric应用区别GPU数据传输示例 编译通信软件 可靠面向连接的TCP和无连接的数据报UDP协议高性能计算HPC或人工智能AI 软硬件复杂性带来的挑战 上千个节点的集群, …

8.Gin 自定义控制器

8.Gin 自定义控制器 前言 在上一篇路由文件抽离的过程中&#xff0c;我们发现接口的业务逻辑还写在路由配置中&#xff0c;如下&#xff1a; 1696385129126 但是如果业务逻辑比较多&#xff0c;如果写在路由之中&#xff0c;肯定不合适。 我们可以将业务逻辑抽离&#xff0c;单…

使用Pytorch实现linear_regression

使用Pytorch实现线性回归 # import necessary packages import torch import torch.nn as nn import numpy as np import matplotlib.pyplot as plt# Set necessary Hyper-parameters. input_size 1 output_size 1 num_epochs 60 learning_rate 0.001# Define a Toy datas…

操作系统 应用题 例题+参考答案(考研真题)

1.&#xff08;考研真题&#xff09;一个多道批处理系统中仅有P1和P2两个作业&#xff0c;P2比P1晚5ms到达&#xff0c;它们的计算和I/O操作顺序如下。 P1&#xff1a;计算60ms&#xff0c;I/O 80ms&#xff0c;计算20ms。 P2&#xff1a;计算120ms&#xff0c;I/O 40ms&…

<Linux>权限管理|权限分类|权限设置|权限掩码|粘滞位

文章目录 Linux权限的概念Linux权限管理a. 文件访问者的分类b. 文件类型和访问权限c. 文件权限表示方法d. 文件权限的设置权限掩码file指令粘滞位 权限总结权限作业 Linux权限的概念 Linux下有两种用户&#xff1a;超级用户(root)和普通用户。 超级用户&#xff1a;可以在Lin…

学生党的福利!移动云重磅升级存储产品体系

如今&#xff0c;随着科学技术不断发展进步&#xff0c;电子产品的生产技术也变得越来越成熟。一方面&#xff0c;电子产品的功能越来越强大&#xff0c;质量越来越可靠&#xff1b;另一方面&#xff0c;产品价格越来越便宜&#xff0c;在人们生活中越来越普及。大学生群体可以…

基于纳什博弈的多微网主体电热双层共享策略(matlab代码)

目录 ​1 主要内容 2 部分代码 3 程序结果 4 下载链接 ​1 主要内容 该程序复现《Multi-Micro-Grid Main Body Electric Heating Double-Layer Sharing Strategy Based on Nash Game》模型&#xff0c;主要做的是构建基于纳什博弈的多微网主体电热双层共享模型&#xff0c;…

java项目之木里风景文化管理平台(ssm+vue)

项目简介 木里风景文化管理平台实现了以下功能&#xff1a; 前台功能&#xff1a;用户进入系统可以实现首页&#xff0c;旅游公告&#xff0c;景区&#xff0c;景区商品&#xff0c;景区美食&#xff0c;旅游交通工具&#xff0c;红黑榜&#xff0c;个人中心&#xff0c;后台…

squid代理服务器(传统代理、透明代理、反向代理、ACL、日志分析)

一、Squid 代理服务器 &#xff08;一&#xff09;代理的工作机制 1、代替客户机向网站请求数据&#xff0c;从而可以隐藏用户的真实IP地址。 2、将获得的网页数据&#xff08;静态 Web 元素&#xff09;保存到缓存中并发送给客户机&#xff0c;以便下次请求相同的数据时快速…

Stable Diffusion XL网络结构-超详细原创

强烈推荐先看本人的这篇 Stable Diffusion1.5网络结构-超详细原创-CSDN博客 1 Unet 1.1 详细整体结构 1.2 缩小版整体结构 以生成图像1024x1024为例&#xff0c;与SD1.5的3个CrossAttnDownBlock2D和CrossAttnUpBlock2D相比&#xff0c;SDXL只有2个&#xff0c;但SDXL的Cros…