Linux——驱动——自动设备

news2024/9/20 18:44:22

自动创建设备节点是Linux设备驱动开发中的一个重要环节,它允许设备驱动程序在内核中注册后,自动在/dev目录下创建对应的设备文件,从而使得用户空间程序可以通过标准的文件操作接口(如open、read、write等)与硬件设备进行交互。 ❤

一、自动创建设备节点的概念

在Linux中,一切皆文件,设备驱动程序也不例外。设备驱动程序通过设备文件的形式向上层程序提供接口。设备文件通常位于/dev目录下,包括字符设备文件、块设备文件、网络设备文件等。这些特殊类型的文件使用统一的文件操作函数(如open、read、write等)进行访问。

二、相关函数和宏定义

(1)class_create宏定义

#define class_create(owner, name)		\  
({						\  
	static struct lock_class_key __key;	\  
	__class_create(owner, name, &__key);	\  
})

实际上,class_create是一个宏定义,它内部调用了__class_create函数。

参数

  • owner:指向模块所有者的指针,通常为THIS_MODULE宏,表示当前模块。
  • name:设备类的名称,该名称将用于在/sys/class/目录下创建对应的目录。

返回值:返回指向新创建的struct class结构体的指针,如果创建失败则返回ERR_PTR错误码。

(2)class_destroy

/**
 * class_destroy - destroys a struct class structure
 * @cls: pointer to the struct class that is to be destroyed
 *
 * Note, the pointer to be destroyed must have been created with a call
 * to class_create().
 */
void class_destroy(struct class *cls)
{
	if ((cls == NULL) || (IS_ERR(cls)))
		return;

	class_unregister(cls);
}

功能class_destroy函数用于销毁之前通过class_create创建的设备类。它会删除/sys/class/目录下对应的目录,并清理相关的资源。

参数cls是指向要销毁的设备类的指针。

返回值:无返回值

(3)device_create

功能device_create函数用于在指定的设备类下创建一个新的设备,并自动在/dev目录下创建对应的设备文件(如果udev或mdev配置正确的话)。此外,它还会在/sys/devices//sys/class/<类名>/目录下创建相应的设备目录。

struct device *device_create(struct class *class, struct device *parent,  
			    dev_t devt, void *drvdata,  
			    const char *fmt, ...);

参数

  • class:设备所属的类。
  • parent:设备的父设备,如果设备没有父设备,则传递NULL
  • devt:设备的设备号,由主设备号和次设备号组成。
  • drvdata:传递给设备的私有数据,通常传递NULL
  • fmt:设备文件的名称格式字符串,后续可变参数将根据这个格式字符串生成设备文件的名称。

返回值:返回指向新创建的struct device结构体的指针,如果创建失败则返回ERR_PTR错误码

(4)device_destroy

功能device_destroy函数用于销毁之前通过device_create创建的设备。它会删除/sys/devices//sys/class/<类名>/目录下对应的设备目录,并尝试删除/dev目录下的设备文件(这通常依赖于udev或mdev的配置)

void device_destroy(struct class *class, dev_t devt);

参数

  • class:设备所属的类。
  • devt:设备的设备号。

返回值:无返回值。

三、实现方式

(1)设置class—create()

(2)出错处理

(3)实现步骤

①. 使用udev

udev通过读取sysfs中的设备信息,结合udev规则文件(通常位于/etc/udev/rules.d/目录下),来决定如何创建设备文件。但是,在设备驱动代码中,通常需要执行以下步骤来配合udev自动创建设备节点:

  • 使用class_create函数创建一个设备类(class),这个类会在/sys/class/目录下创建一个对应的目录。

  • 使用device_create函数在创建的设备类下创建一个设备,这个函数会在/sys/class/<类名>/目录下创建一个设备目录,并且udev会根据规则文件在/dev目录下创建对应的设备文件。

②. 使用mdev(嵌入式系统)

在嵌入式Linux系统中,由于资源限制,可能会使用mdev作为udev的简化版。mdev同样能够监听内核的设备事件,并自动创建或删除设备文件。但是,与udev不同,mdev的配置可能更加简单直接,通常通过配置文件或命令行参数来指定行为。

(4)具体代码

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/uaccess.h>
#include <linux/device.h>

#define MAJOR_NUM 253
#define MINOR_NUM 0
#define DEV_NAME "led"
#define DEV_NUM 1
#define GPBCON 0x56000010
#define GPBDAT 0x56000014

static volatile unsigned long * gpbcon;
static volatile unsigned long * gpbdat;

static void init_led(void)						
{
	// 配置GPB5引脚功能为输出
	*gpbcon &= ~(0xff << 10);
	*gpbcon |= (0x55 << 10);

	// 将GPB5引脚电平置高
	*gpbdat |= (0xf << 5);
}

static void led_on(void)
{
	// 将GPB5引脚电平置低
	*gpbdat &= ~(0xf << 5);
}

static void led_off(void)
{
	// 将GPB5引脚电平置高
	*gpbdat |= (0xf << 5);
}

static int open (struct inode * inode, struct file * file)
{
	init_led();
	printk("led open ...\n");
	return 0;
}

static ssize_t read (struct file * file, char __user * buf, size_t len, loff_t * offset)
{
	//copy_to_user(buf, data, len);
	printk("led read ...\n");
	return 0;
}

static ssize_t write (struct file * file, const char __user * buf, size_t len, loff_t * offset)
{
	unsigned char data[12] = {0};
	size_t len_cp = sizeof(data) < len ? sizeof(data) : len;
	copy_from_user(data, buf, len_cp);

	if(!strcmp(data, "ledon"))
		led_on();
	else if(!strcmp(data, "ledoff"))
		led_off();
	else
		 return -1;

	printk("led write ...\n");
	return len_cp;
}

static int close (struct inode * inode, struct file * file)
{
	printk("led close ...\n");
	return 0;
}

static struct file_operations fops = 
{
	.owner = THIS_MODULE,
	.open = open,
	.read = read,
	.write = write,
	.release = close
};
static struct cdev cdev;
static dev_t dev;
struct class * pclass;
struct device * pdev;

static int __init led_init(void) 
{
	int ret = 0;
	dev = MKDEV(MAJOR_NUM, MINOR_NUM);

	cdev_init(&cdev, &fops);

	ret = cdev_add(&cdev, dev, DEV_NUM);
	if(ret < 0)
		goto err_cdev_add;

	ret = register_chrdev_region(dev, DEV_NUM, DEV_NAME);
	if(ret < 0)
		goto err_register_chrdev_region;

	pclass = class_create(THIS_MODULE, "led_class");
	if(pclass == NULL)
		goto err_class_create;

	pdev = device_create(pclass, NULL, dev, NULL, DEV_NAME);
	if(pdev == NULL)
		goto err_device_create;

	gpbcon = ioremap(GPBCON, sizeof(*gpbcon));
	gpbdat = ioremap(GPBDAT, sizeof(*gpbdat));

	printk("led_init  ...\n");

	return ret;

err_cdev_add:
	cdev_del(&cdev);
	printk("led cdev_add failed\n");
	return ret;

err_register_chrdev_region:
	unregister_chrdev_region(dev, DEV_NUM);
	cdev_del(&cdev);
	printk("led register_chrdev_region failed\n");	
	return ret;

err_class_create:
	class_destroy(pclass);
	unregister_chrdev_region(dev, DEV_NUM);
	cdev_del(&cdev);
	printk("led class_create failed\n");	
	return -1;

err_device_create:
	device_destroy(pclass, dev);
	class_destroy(pclass);
	unregister_chrdev_region(dev, DEV_NUM);
	cdev_del(&cdev);
	printk("led device_create failed\n");	
	return -1;
}

static void __exit led_exit(void)
{
	iounmap(gpbcon);
	iounmap(gpbdat);
	device_destroy(pclass, dev);
	class_destroy(pclass);
	unregister_chrdev_region(dev, DEV_NUM);
	cdev_del(&cdev);
	printk("led_exit  ###############################\n");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

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

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

相关文章

Level3 — PART 4 机器学习算法 — 朴素贝叶斯

目录 贝叶斯定理 朴素贝叶斯模型&#xff08;Naive Bayes Model&#xff09; 估计 离散估计 极大似然估计 案例 朴素贝叶斯扩展 高斯贝叶斯分类器 原理 应用 源码分析 伯努利贝叶斯分类器 原理 源码分析 多项朴素贝叶斯分类器 半朴素贝叶斯分类器 模拟题 CDA…

Linux系统之jobs命令的基本使用

Linux系统之jobs命令的基本使用 一、jobs命令介绍二、jobs命令的使用帮助2.1 jobs命令的help帮助信息2.2 jobs命令的语法解释 三、jobs命令的基本使用3.1 运行一个后台任务3.2 列出后台所有的作业3.3 列出进程ID3.4 只列出进程ID3.5 终止后台任务3.6 只显示运行任务3.7 只显示停…

tcp 网络通信及抓包工具的使用

tcp网络通信 本地回环&#xff08;Loopback&#xff09;的概念 本地回环地址是一个特殊的IP地址&#xff0c;用于指向计算机本身的网络接口。在IPv4中&#xff0c;最常见的本地回环地址是127.0.0.1&#xff0c;而在IPv6中则是::1。这个地址用于测试网络软件&#xff0c;确保网…

【IoT】路由器/linux系统,如何使用shell查看系统硬件配置,传感器CPU温度,资源占用率等信息(以红米AX6000为例)

【IoT】路由器/linux系统&#xff0c;如何使用shell查看硬件配置&#xff0c;传感器CPU温度&#xff0c;系统资源占用率等信息&#xff08;以红米AX6000为例&#xff09; 文章目录 1、路由器拆机与测评&#xff08;Redmi AX6000&#xff09;2、通过telnet获得SSH3、linux系统信…

SpringBoot集成kafka接收消息

SpringBoot集成kafka接收消息 1、SpringBoot集成kafka接收消息2、Payload注解接收消息体内容3、Header注解接收消息头内容4、接收消息所有内容 1、SpringBoot集成kafka接收消息 生产者 package com.power.producer;import org.springframework.kafka.core.KafkaTemplate; imp…

【自动化】考试答题自动化完成答案,如何实现100%正确呢

一、科目仿真考试不能自动答题 我的答案是可以的&#xff0c;电脑程序可以模拟人的操作完成所有的答题并提交结束考试 二、分析页面内容 完成一个题目&#xff0c;包括判断题&#xff0c;对与错2选1答案&#xff0c;单选题ABCD4选1答案&#xff0c;多选题大家想一想 F12查看按…

基于机器学习的糖尿病数据分析与风险评估系统

B站视频及代码下载&#xff1a;基于机器学习的糖尿病数据分析与风险评估系统_哔哩哔哩_bilibili 1. 项目简介 糖尿病&#xff0c;作为一种在全球范围内广泛流行的慢性疾病&#xff0c;已经影响了数以百万计的人们的生活&#xff0c;给全球公共健康带来了严重的挑战。因此&#…

uni-app的示例项目--简单的登陆页面及列表页面

uni-app的示例项目--简单的登陆页面及列表页面 文章说明核心代码效果展示源码下载 文章说明 随着移动端使用占比升高&#xff0c;手机端的App、小程序也成了一些场景下的首选&#xff1b;采用uni-pp开发此类应用具有很多优势&#xff0c;它可以直接使用vue3进行开发&#xff0c…

集合论与位运算之间的转换

集合可以用二进制表示&#xff0c;二进制从低到高第 i 位为 1 表示 i 在集合中&#xff0c;为 0 表示 i 不在集合中。例如集合 {0,2,3} 可以用二进制数 1101(2)​ 表示&#xff1b;反过来&#xff0c;二进制数 1101(2)​ 就对应着集合 {0,2,3}。 例如集合 {0,2,3} 可以压缩成 …

干货|软件测试简历的编写以及注意事项

一、个人信息 1.年龄超过30岁的&#xff0c;就不体现年龄&#xff1b; 2.学历是本科的&#xff0c;以及专业是计算机的可以加上学历、专业2个标签&#xff0c;大专的则可以不体现&#xff1b; 3.英语过了四六级的可以加1个英语的标签&#xff1b; 4.如果你的户籍和面试城市…

Python入门级 序列全集 [ 继上篇 进阶版 持续更新中哞哞哞!!! ]例题较多

本文主要结合例题介绍了序列【常用函数、可迭代对象】&#xff0c;字典【函数、写法、定义、视图对象】&#xff0c;集合【常用函数】&#xff0c;运算符优先级。这几种数据集合在Python中也是蛮重要的&#xff0c;对于新手比较友好。 本文例题大多来自哔站up主鱼C-小甲鱼【Pyt…

系统编程 网络 http协议

http协议------应用层的协议 万维网&#xff1a;http解决万维网之间互联互通 计算机web端网络只能看到文字 1.如何在万维网中表示一个资源&#xff1f; url <协议>&#xff1a;//<主机>&#xff1a;<端口>/<路径> ------------------------------…

Adobe After Effects的插件--------CC Ball Action

CC Ball Action是粒子效果器,其将2D图层变为一个个由3D小球构成的图层。它是AE内置的3D插件。 使用条件 使用该插件的图层需是2D图层。 我们以一张图片素材为例: 给图片图层添加CC Ball Action效果控件,然后新建一个摄像机(利用摄像机旋转、平移、推拉工具,方便在各个角…

【LeetCode面试150】——36有效的数独

博客昵称&#xff1a;沈小农学编程 作者简介&#xff1a;一名在读硕士&#xff0c;定期更新相关算法面试题&#xff0c;欢迎关注小弟&#xff01; PS&#xff1a;哈喽&#xff01;各位CSDN的uu们&#xff0c;我是你的小弟沈小农&#xff0c;希望我的文章能帮助到你。欢迎大家在…

微服务基础与Spring Cloud框架

一、系统架构的演变 1.1单体应⽤架构 Web应⽤程序发展的早期&#xff0c;⼤部分web⼯程(包含前端⻚⾯,web层代码,service层代码,dao层代码)是将 所 有的功能模块,打包到⼀起并放在⼀个web容器中运⾏。 1.2 垂直应⽤架构 当访问量逐渐增⼤&#xff0c;单⼀应⽤增加机器带来的…

【Unity3D小技巧】Unity3D中实现FPS数值显示功能实现

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址QQ群&#xff1a;398291828 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 很简单也很使用的小技巧&#xff0c;就是在Unity…

PHP酒店宾馆民宿预订系统小程序源码

酒店宾馆民宿预订系统&#xff1a;一键解锁完美旅行住宿新体验 &#x1f31f; 开篇&#xff1a;告别繁琐&#xff0c;拥抱便捷预订新时代 在这个快节奏的时代&#xff0c;每一次旅行的规划都希望能尽可能高效与省心。想象一下&#xff0c;在规划一场说走就走的旅行时&#xf…

Nature | 小麦D基因组的起源和演化,野生近缘种对作物抗病改良具有重要潜力

image-20240815151428804 2024年8月14日沙特阿卜杜拉国王科技大学Brande B. H. Wulff 和 Simon G. Krattinger团队在Natue发表Origin and evolution of the bread wheat D genome研究论文&#xff0c;通过研究粗山羊草&#xff08;Aegilops tauschii&#xff0c;也被称为节节麦…

Ant-Design-Vue快速上手指南+排坑,操作详细步骤

Ant-Design-Vue是一款基于Vue.js的UI组件库&#xff0c;它不仅提供了丰富的高质量组件&#xff0c;还支持灵活的配置选项&#xff0c;使得开发者能够快速构建出既美观又功能强大的前端应用。下面将详细介绍Ant-Design-Vue的快速上手指南和排坑操作&#xff0c;帮助开发者顺利使…

Springboot整合mongodb和mysql两个数据库,mysql无法连接

一、问题 在日常开发中&#xff0c;难免需要用到mongodb和mysql数据库 当我在mongodb正常连接使用的时候&#xff0c;切换回mysql&#xff0c;发现无法连接 二、原因分析 1、端口查看被占用 winr打开命令提示符&#xff08;cmd&#xff09;&#xff0c;可以使用以下命令&…