0-ARM Linux驱动开发-字符设备

一、字符设备概述

Linux 系统中,设备被分为字符设备、块设备和网络设备等。字符设备以字节流的方式进行数据传输,数据的访问是按顺序的,一个字节一个字节地进行读取和写入操作,没有缓冲区。例如,终端(/dev/tty)、鼠标、键盘等设备都是典型的字符设备。

字符设备通过特殊的设备文件来表示。这些设备文件通常位于/dev​目录下。设备文件有主设备号(major number)和次设备号(minor number)。主设备号用于标识设备驱动程序,内核通过主设备号来查找对应的驱动程序;次设备号用于标识同一类型设备中的不同个体。例如,系统中可能有多个串口设备,它们的主设备号相同(表示使用相同的驱动程序),但次设备号不同,用于区分不同的串口。

image

image

二、字符设备驱动开发

1、驱动文件

//添加头文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ide.h>

static char readbuf[100];  // 读缓冲区
static char writebuf[100]; // 写缓冲区
static char message[] = {"This message comes from kernel."};

static int drive_major; //设备号
static struct class *KernelPrint_cls;

//1.5.5 驱动程序的打开,读取,写入,关闭。
static int KernelPrint_open(struct inode *inode, struct file *filp) //打开函数
{
	//本DEMO无需申请资源,此处留白
	printk("-KernelPrint open-\n");
	return 0;
}
static ssize_t KernelPrint_read(struct file *filp, char __user *buf, size_t count, loff_t *fops) //用户读取,内核发送信息
{
	int flag = 0;
	memcpy(readbuf, message, sizeof(message)); //使用memcpy将内核中要发送的内容写入读缓冲区
	flag = copy_to_user(buf, readbuf, count);  //使用copy_to_user函数将读缓冲区的内容发送到用户态
	if (flag == 0)							   //返回0成功,否则失败
	{
		printk("Kernel send data success!\n");
	}
	else
	{
		printk("Kernel send data failed!\n");
	}
	printk("-KernelPrint read-\n");
	return 0;
}
static ssize_t KernelPrint_write(struct file *filp, const char __user *buf, size_t count, loff_t *fops) //用户发送,内核读取信息并打印
{
	int flag = 0;
	flag = copy_from_user(writebuf, buf, count); //使用copy_from_user读取用户态发送过来的数据
	if (flag == 0)
	{
		printk(KERN_CRIT "Kernel receive data: %s\n", writebuf);
	}
	else
	{
		printk("Kernel receive data failed!\n");
	}
	printk("-KernelPrint write-\n");
	return 0;
}
static int KernelPrint_release(struct inode *inode, struct file *filp) //释放设备
{
	//由于open函数并没有占用什么资源,因此无需释放
	printk("-KernelPrint release-\n");
	return 0;
}

//1.5.1 驱动文件描述集合
static struct file_operations drive_fops = {
	.owner = THIS_MODULE,
	.open = KernelPrint_open,
	.read = KernelPrint_read,
	.write = KernelPrint_write,
	.release = KernelPrint_release,
};

//1.5.2 装载入口函数
static __init int KernelPrint_init(void)
{
	printk("-------^v^-------\n");
	printk("-KernelPrint init-\n");

	//1.5.3 设备的申请
	//申请主设备号
	//参数1----需要的主设备号,>0静态分配, ==0自动分配
	//参数2----设备的描述 信息,体现在cat /proc/devices, 一般自定义
	//参数3----文件描述集合
	//返回值,小于0报错
	drive_major = register_chrdev(0, "KernelPrint", &drive_fops);
	if (drive_major < 0) //判断是否申请成功
	{
		printk("register chrdev faile!\n");
		return drive_major;
	}
	else
	{
		printk("register chrdev ok!\n");
	}


	//1.5.4 
	//自动创建设备节点
	//创建设备的类别
	//参数1----设备的拥有者,当前模块,直接填THIS_MODULE
	//参数2----设备类别的名字,自定义
	//返回值:类别结构体指针,其实就是分配了一个结构体空间
	KernelPrint_cls = class_create(THIS_MODULE, "KernelPrint_class");
	printk("class create ok!\n");

	//创建设备
	//参数1----设备对应的类别
	//参数2----当前设备的父类,直接填NULL
	//参数3----设备节点关联的设备号
	//参数4----私有数据直接填NULL
	//参数5----设备节点的名字
	device_create(KernelPrint_cls, NULL, MKDEV(drive_major, 0), NULL, "KernelPrint_%d", 0);
	printk("device create ok!\n");

	return 0;
}

//1.5.2 卸载入口函数
static __exit void KernelPrint_exit(void)
{
	//1.5.3 设备的注销
	device_destroy(KernelPrint_cls, MKDEV(drive_major, 0)); //删除设备
	class_destroy(KernelPrint_cls);							//删除类
	unregister_chrdev(drive_major, "KernelPrint");			//注销主设备号
	printk("-------^v^-------\n");
	printk("-KernelPrint exit-\n");
}

//申明装载入口函数和卸载入口函数
module_init(KernelPrint_init);
module_exit(KernelPrint_exit);

//添加各类信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Popeye");

2、应用文件

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

int main(int argc, char *argv[])
{
	int fd, retvalue;
	char *filename;
	char readbuf[100], writebuf[100];

	filename = argv[1];

	fd = open(filename, O_RDWR); //打开设备
	if (fd < 0)
	{
		printf("Can't open file %s\n", filename);
		return -1;
	}

	switch (*argv[2]) //对操作数进行解析
	{
	case 'r':
		if (argc != 3) //进行鲁棒性检查
		{
			printf("Unknow operation, use the formate: ./APPNAME /dev/DRIVENAME r to read date from kernel.\n");
			return -1;
		}
		retvalue = read(fd, readbuf, 100);
		if (retvalue < 0) //检查是否读取成功
		{
			printf("Read file %s failed!\n", filename);
		}
		else
		{
			printf("User receive data: %s\n", readbuf);
		}
		break;
	case 'w':
		if (argc != 4) //进行鲁棒性检查
		{
			printf("Unknow operation, use the formate: ./APPNAME /dev/DRIVENAME w \"USERDATE\" to write date to kernel.\n");
			return -2;
		}
		memcpy(writebuf, argv[3], strlen(argv[3])); //将内容拷贝到缓冲区
		retvalue = write(fd, writebuf, 50);			//写数据
		if (retvalue < 0)
		{
			printf("Write file %s failed!\n", filename);
		}
		else
		{
			printf("Write file success!\n");
		}
		break;
	default:
		printf("Unknow Operation: %d\n", *argv[2]);
		break;
	}

	retvalue = close(fd); //关闭设备
	if (retvalue < 0)
	{
		printf("Can't close file %s\n", filename);
		return -1;
	}

	return 0;
}

三、上板验证

安装驱动insmod kernel_print.ko​,查看驱动安装是否成功ls /dev/​,kernel_print内核打印测试./kernel_print_app /dev/KernelPrint_0 w "Popeye"

image

image

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

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

相关文章

flink 内存配置(一):设置Flink进程内存

Apache Flink通过严格控制各个组件的内存使用&#xff0c;在JVM之上提供了高效的工作负载。虽然Flink社区努力为所有配置提供合理的默认值&#xff0c;但由于用户部署在Flink上的应用范围很广&#xff0c;这并不总是可行的。为了给用户提供最大的生产价值&#xff0c;Flink支持…

Android启动流程_Zygote阶段

前言 上一篇文档中我们描述了 Android 启动中的 init 启动部分&#xff0c;本片文档将会继续 Android 启动流程的逻辑&#xff0c;继续梳理 Zygote 部分功能。 说明框架 对于 Zygote 进程&#xff0c;要从以下框架说明&#xff1a; 第一点&#xff0c;编译&#xff0c;zygo…

记本地第一次运行seatunnel示例项目

前置 静态源码编译通过&#xff1a;https://blog.csdn.net/u011924665/article/details/143372464 参考 seatunnel官方的开发环境搭建文档&#xff1a;https://seatunnel.incubator.apache.org/zh-CN/docs/2.3.5/contribution/setup 安装scala 下载scala 去官网下载&…

用流量策略做多出口实验

一、拓扑&#xff1a; 二、配置过程&#xff1a; 1、配置 IP 地址&#xff0c;配置动态路由协议 OSPF 2、AR2 上&#xff0c;配置高级 ACL&#xff0c;允许 ospf 流量、1 到 6、2 到 8、deny 所有 3、写流分类&#xff0c;抓取流量特征 4、写流行为&#xff0c;配置流量动作 5、…

ps技巧,来源于网络

魔棒工具 选个颜色之后 ctrlj复制图层 完成

【论文阅读】Associative Alignment for Few-shot Image Classification

用于小样本图像分类的关联对齐 引用&#xff1a;Afrasiyabi A, Lalonde J F, Gagn C. Associative alignment for few-shot image classification[C]//Computer Vision–ECCV 2020: 16th European Conference, Glasgow, UK, August 23–28, 2020, Proceedings, Part V 16. Spri…

《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列

《TCP/IP网络编程》学习笔记 | Chapter 3&#xff1a;地址族与数据序列 《TCP/IP网络编程》学习笔记 | Chapter 3&#xff1a;地址族与数据序列分配给套接字的IP地址和端口号网络地址网络地址分类和主机地址边界用于区分套接字的端口号数据传输过程示例 地址信息的表示表示IPv4…

Android Studio 中的Gemini 推出更多人工智能开发功能

谷歌公司&#xff08;Google LLC&#xff09;今天发布了由其人工智能模型 “双子座”&#xff08;Gemini&#xff09;驱动的Android Studio的更多功能。 Android Studio中的 "双子座 "作为Android Studio&#xff08;一种软件编辑器&#xff09;的人工智能升级版于今…

基于物联网的户外环境检测装置教学文章

引言 随着物联网&#xff08;IoT&#xff09;技术的发展&#xff0c;越来越多的应用被广泛研究和应用于我们的日常生活中。户外环境检测装置是一种利用传感器、网络连接和数据分析技术&#xff0c;监测和分析环境数据&#xff08;如温度、湿度、空气质量等&#xff09;的设备。…

Javaweb梳理3——SQL概述+DDL语句1

Javaweb梳理3——SQL概述DDL语句1 Javaweb梳理3——SQL概述DDL语句13.1 SQL简介3.2 通用语法3.3 SQL分类3.4 DDL:操作数据库3.4.1 查询数据库3.4.2 创建数据库3.4.3 删除数据库3.4.4 使用数据库 Javaweb梳理3——SQL概述DDL语句1 3.1 SQL简介 英文&#xff1a;Structured Que…

【MWorks】Ubuntu 系统搭建

升级 Ubuntu系统 sudo apt-get update sudo apt-get upgrade安装流程 sudo chmod x 路径/文件.run安装 sudo 路径/文件.run安装过程中两个选项都填 y 打开安装对应的文件夹 运行 syslab.sh 文件&#xff0c;运行结束后&#xff0c;就可以在左上角开始搜索到syslab了。

Linux Qt 6安装Oracle QOCI SQL Driver插件(适用WSL)

本文参考 QOCI for the Oracle Call Interface (OCI)。 除一般的 Linux 系统外&#xff0c;本文也适用于 WSL 2。 在开始之前&#xff0c;如果没有安装 QOCI 插件&#xff0c;则试图链接 Oracle 数据库时会报错&#xff1a; Failed to create wl_display (No such file or dire…

电磁兼容(EMC):整改案例(六)Y电容过大导致雷击浪涌炸机

目录 1. 异常现象 2. 原因分析 3. 整改方案 4. 总结 1. 异常现象 某金属外壳带接地线的产品按GB/T 17626.5进行雷击浪涌测试&#xff0c;在L&#xff0c;N线对PE进行4kV浪涌电压测试时&#xff0c;出现炸机现象&#xff0c;AC-DC电源芯片损坏。而在L&#xff0c;N线间进行2…

WPF怎么通过RestSharp向后端发请求

1.下载RestSharpNuGet包 2.请求类和响应类 public class ApiRequest {/// <summary>/// 请求地址/// </summary>public string Route { get; set; }/// <summary>/// 请求方式/// </summary>public Method Method { get; set; }/// <summary>//…

C语言 | Leetcode C语言题解之第520题检测大写字母

题目&#xff1a; 题解&#xff1a; bool detectCapitalUse(char * word){int len strlen(word);int res 0;int index -1;if(len 1)return true;else{for(int i 0; i < len; i){if(isupper(word[i])){res;index i;}}}return res len || res 0 || (res 1 &&…

VidPanos:从随手拍摄的平移视频生成全景视频

在当今数字化时代,视频拍摄已经成为人们记录生活和分享经历的重要方式。然而,普通手机拍摄的视频往往受到视角的限制,无法完整地展现一个广阔的场景。今天,我们要介绍的 VidPanos 技术,为解决这个问题提供了一种创新的方法。 VidPanos 是由来自华盛顿大学、谷歌 DeepMind…

使用 LlamaIndex 实现的检索增强生成(RAG)

Retrieval Augmented Generation (RAG) using LlamaIndex — ROCm Blogs (amd.com) 2024 年 4 月 4 日 作者&#xff1a;Clint Greene. 先决条件 要运行本博客&#xff0c;您需要具备以下条件&#xff1a; Linux: 参见受支持的 Linux 发行版 ROCm: 参见安装说明 AMD GPU: 参…

【计网】深入理解NAT机制,内网穿透与内网打洞,代理服务

我没胆量犯错 才把一切错过 --- 林夕 《我对不起我》--- 一文了解NAT机制&#xff0c;代理服务&#xff0c;内网穿透 1 再谈 NAT 机制2 内网穿透与内网打洞3 代理服务器 1 再谈 NAT 机制 NAT机制我们在解决IP地址不足的问题中提到过。为了解决IP地址不足的问题&#xff0c;采…

京东毫秒级热key探测框架JD-hotkey

前言 对任意突发性的&#xff0c;无法预先感知的热点数据&#xff0c;包括热点数据&#xff08;如突发大量请求同一个商品&#xff09;、热用户&#xff08;如恶意爬虫刷子&#xff09;、热接口&#xff08;突发海量请求同一个接口&#xff09;等&#xff0c;一瞬间打到我们的服…

2025生物发酵展(济南)为生物制造产业注入新活力共谱行业新篇章

2025第十四届国际生物发酵展将于3月3-5日济南盛大举办&#xff01;产业链逐步完整&#xff0c;展会面积再创历史新高&#xff0c;展览面积较上届增涨至60000平方米&#xff0c;专业观众40000&#xff0c;品牌展商800&#xff0c;同期活动会议增加至50场&#xff0c;展会同期将举…