字符设备驱动基础—sys文件系统,udev介绍,驱动模块在内核空间注册设备

文章目录

    • sys文件系统介绍
      • 设计思想
      • 应用和功能
    • udev介绍
      • 主要功能
      • 工作原理
      • 使用 `udevadm` 工具
    • 设备文件创建流程
      • 驱动程序的注册
      • device_create函数详解
      • 示例代码
      • 效果图

sys文件系统介绍

sysfs 是 Linux 内核中的一种虚拟文件系统,它为用户空间和内核之间提供了一种统一的接口。通过 sysfs,用户可以查看和修改内核对象的属性,比如设备、驱动程序和内核子系统的配置和状态。sysfs 通常挂载在 /sys 目录下。

设计思想

sysfs 的设计思想主要包括以下几个方面:

  1. 内核对象的可视化和组织

    • sysfs 将内核中的对象(如设备、驱动、类等)以文件和目录的形式展现给用户。这些对象按照层次结构组织,类似于文件系统中的目录结构。这使得内核对象的关系和层次变得清晰易懂。
  2. 统一的接口和操作方式

    • sysfs 提供了一种统一的方式来访问内核对象的属性。用户可以通过标准的文件操作(如 read, write 等)来查看和修改这些属性。每个属性通常对应一个文件,文件的内容即是该属性的值。
  3. 动态可配置性和可扩展性

    • sysfs 支持动态添加和删除节点。这意味着内核模块可以在运行时通过 sysfs 创建和删除文件或目录,以反映系统状态的变化。这种动态特性使 sysfs 适用于热插拔设备等需要实时更新的场景。
  4. 轻量级和高效

    • sysfs 是一个轻量级的文件系统,它没有存储数据的持久化特性,所有数据都驻留在内存中。这使得 sysfs 操作非常高效,适合频繁访问和快速响应的需求。
  5. 安全性和访问控制

    • sysfs 文件系统中的节点可以设置权限,控制不同用户和进程的访问。这有助于保护系统的关键数据和配置,防止未经授权的访问或修改。

应用和功能

sysfs 主要用于以下几个方面:

  1. 设备管理

    • sysfs 通过 /sys/class, /sys/bus, /sys/devices 等目录组织系统中的所有设备和设备驱动,用户可以查看设备的状态、属性,并可以通过写入相应的文件来控制设备。
  2. 驱动管理

    • 驱动程序可以通过 sysfs 暴露其支持的设备类型和属性,这样用户和其他系统组件可以通过读取 sysfs 节点来获取驱动程序的信息。
  3. 内核子系统配置

    • 一些内核子系统(如电源管理、内存管理等)提供了 sysfs 接口,允许用户调整相关配置或获取状态信息。例如,通过 /sys/power 目录,可以管理系统的电源状态。

sysfs 的设计和实现大大增强了内核与用户空间的交互能力,使得系统管理和设备控制变得更加直观和灵活。

udev介绍

udev 是 Linux 系统中的一个设备管理工具和守护进程,负责在用户空间管理设备节点。它是设备管理框架的一部分,用于响应系统中的设备事件,并在 /dev 目录中创建和删除设备节点。udev 是 Linux 系统中处理设备管理的重要组件。它提供了一种灵活而强大的方式来响应和管理设备事件,确保系统中的设备节点和权限设置是动态更新和适当配置的。对于系统管理员和开发者来说,理解和利用 udev 可以大大简化设备管理的工作。

主要功能

  1. 设备节点管理

    • udev 动态地在 /dev 目录下创建和删除设备节点,这些节点表示系统中的硬件设备。它根据系统中的设备出现或消失的情况更新设备节点。
  2. 设备事件处理

    • 当新的硬件设备插入或移除时,内核会生成相应的事件。udev 监听这些事件,并根据配置文件中的规则执行相应的操作,如创建设备节点、设置设备权限、加载固件等。
  3. 设备命名

    • udev 允许管理员通过规则文件对设备节点进行命名。例如,可以根据设备的类型、属性、序列号等为设备节点分配有意义的名称,这样在管理系统设备时更容易识别和区分设备。
  4. 权限设置

    • udev 规则文件可以指定设备节点的权限和所有者。这对于多用户系统非常重要,可以控制哪些用户或组可以访问特定的设备。
  5. 自动化任务

    • udev 可以在设备事件发生时触发脚本或程序。例如,当插入一个USB设备时,可以自动挂载它,或者当插入一个网络接口时,自动配置网络。

工作原理

  1. 内核事件

    • 当一个设备插入或移除时,内核会通过 netlink 接口通知 udev。这些事件包括设备的添加、移除、变化等。
  2. 规则匹配

    • udev 通过配置的规则文件(通常位于 /etc/udev/rules.d/)对事件进行匹配。规则文件指定了当匹配到特定设备时应该采取的操作。
  3. 执行操作

    • 根据匹配的规则,udev 执行相应的操作,如创建设备节点、设置权限、运行脚本等。

使用 udevadm 工具

udevadmudev 提供的命令行工具,用于管理和调试 udev。它可以用于触发设备事件、监视设备事件、查看设备信息等。例如:

  • 查看当前的 udev 规则:

    udevadm info --query=all --name=/dev/sda
    
  • 监视设备事件:

    udevadm monitor
    

设备文件创建流程

驱动程序的注册

  1. 定义和实现操作函数

    • 驱动程序必须定义一个 file_operations 结构体,包含设备操作函数的指针,如 openreleasereadwrite 等。这些函数定义了如何处理设备的各种操作请求。
    static const struct file_operations my_fops = {.open = my_open,.release = my_release,.read = my_read,.write = my_write,
    };
    
  2. 注册字符设备

    • 驱动程序使用 register_chrdev(或类似的函数)注册设备号,并将其与 file_operations 结构体相关联。这样,内核知道如何处理对该设备的操作。
    int major = register_chrdev(0, "my_device", &my_fops);
    

    这里,register_chrdev 返回主设备号,my_device 是设备名称,my_fops 是操作函数集合。

  3. 创建设备节点

    • 驱动程序可以使用 device_create 函数创建设备节点,通常在用户空间使用 udev 来自动创建和管理设备节点。
    struct class *my_class;
    struct device *my_device;my_class = class_create(THIS_MODULE, "my_class");
    my_device = device_create(my_class, NULL, MKDEV(major, 0), NULL, "my_device");
    

device_create函数详解

当驱动程序调用 device_create 时,它实际上是在内核中注册了一个新的设备对象。这个设备对象包含了设备的相关信息,包括设备名称、设备号、设备类等。

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

这里,cls 是设备的类结构体指针,devt 是设备号,fmt 是格式化字符串,用于生成设备名称。

内核在成功创建设备对象后,会生成一个 uevent 事件。这是一个内核通知事件,用于告知用户空间有新的设备注册或现有设备状态发生变化。这个事件包含了设备的属性和相关信息。

udev 守护进程监听这些 uevent 事件。每当内核发出这样的事件时,udev 会根据事件信息和系统中定义的 udev 规则文件,决定如何处理该事件。

udev 规则文件通常位于 /etc/udev/rules.d//lib/udev/rules.d/ 目录下,这些规则定义了如何为不同类型的设备创建设备节点、设置权限、指定设备文件名称等。

根据 udev 规则和 uevent 中的信息,udev/dev 目录下创建相应的设备文件(设备节点)。这些设备文件允许用户空间的应用程序与该设备进行交互。

除了创建设备文件外,udev 还可以根据规则设置设备文件的权限、所有者和其他属性。这确保了设备文件的安全性和可访问性。

示例代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>#define DEVICE_NAME "my_char_device"static int major_number;
static struct class *my_class = NULL;
static struct device *my_device = NULL;
static struct cdev mydev;  // 声明 cdev 结构体static int my_open(struct inode *inode, struct file *file)
{printk(KERN_INFO "my_char_device: open()\n");return 0;
}static int my_release(struct inode *inode, struct file *file)
{printk(KERN_INFO "my_char_device: release()\n");return 0;
}static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{printk(KERN_INFO "my_char_device: read()\n");return 0;
}static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{printk(KERN_INFO "my_char_device: write()\n");return count;
}static struct file_operations fops = {.owner = THIS_MODULE,.open = my_open,.release = my_release,.read = my_read,.write = my_write,
};static int __init test_init(void)
{int retval;dev_t dev;printk(KERN_INFO "module init success\n");// 1. 动态分配主次设备号retval = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);if (retval < 0){printk(KERN_ERR "Failed to allocate major number\n");goto fail_alloc_chrdev_region;}major_number = MAJOR(dev);printk(KERN_INFO "major number is: %d, minor number is: %d\n", major_number, MINOR(dev));// 2. 初始化 cdev 结构体并添加到内核cdev_init(&mydev, &fops);retval = cdev_add(&mydev, dev, 1);if (retval < 0){printk(KERN_ERR "Failed to add cdev\n");goto fail_cdev_add;}// 3. 创建设备类my_class = class_create(THIS_MODULE, "my_class");if (IS_ERR(my_class)){printk(KERN_ERR "Failed to create class\n");retval = PTR_ERR(my_class);goto fail_class_create;}// 4.  申请设备,内核空间就会通知用户空间的udev 进行创建设备,驱动程序本身自己是创建不了文件的!my_device = device_create(my_class, NULL, dev, NULL, DEVICE_NAME);if (IS_ERR(my_device)){printk(KERN_ERR "Failed to create device\n");retval = PTR_ERR(my_device);goto fail_device_create;}printk(KERN_INFO "my_char_device: module loaded\n");return 0;fail_device_create:class_destroy(my_class);
fail_class_create:cdev_del(&mydev);
fail_cdev_add:unregister_chrdev_region(dev, 1);
fail_alloc_chrdev_region:return retval;
}static void __exit test_exit(void)
{dev_t dev = MKDEV(major_number, 0);if (my_device)device_destroy(my_class, dev);if (my_class)class_destroy(my_class);cdev_del(&mydev);unregister_chrdev_region(dev, 1);printk(KERN_INFO "my_char_device: module unloaded\n");
}module_init(test_init);
module_exit(test_exit);MODULE_LICENSE("GPL");

效果图

当insmod 模块之后,在/dev目录下就可以查看由udev生成的设备文件了

在这里插入图片描述

如果使用cat 来查看设备文件,此时设备的文件操作结构体file_operations也会被触发,例如:

cat /dev/my_char_device 

在这里插入图片描述

cat 本质上就是读操作,相当于读取驱动程序,因此,Open read 会被触发,当读取完毕之后,就触发release操作

如果调用下方这个命令

echo 1 > /dev/my_char_device 

echo本质上就是写操作,相当于往驱动程序写值, 此时 open write会被触发,当写入完毕之后,就会触发release操作

在这里插入图片描述

当然,本次代码没有实现具体的读写逻辑,只是展示了cat 和echo的作用

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

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

相关文章

Kafka基本概念,工作流程介绍

1、消息队列与Kafka 1.1、Kafka简介 Kafka使用scala开发&#xff0c;支持多语言客户端&#xff08;c、java、python、go等&#xff09; Kafka最先由LinkedIn公司开发&#xff0c;之后成为Apache的顶级项目。 Kafka是一个分布式的、分区化、可复制提交的日志服务 LinkedIn使…

SpringBoot中的server.context-path

一、问题引入 书接上回&#xff0c;SpringBoot 在 idea中的 .idea和 .iml文件-CSDN博客&#xff0c;我在boot-test的测试项目中使用的 SpringBoot版本为 1.3.5.RELEASE&#xff0c;新项目 cps-task中使用的版本为 2.4.8&#xff0c;造成了连接异常&#xff0c;问题很好解决&…

(20240801)矿山固废基胶凝材料及混凝土中文期刊整理

一、篇名:固废 级别:EI + 篇名:固废混凝土/水泥/胶砂/胶凝材料 级别:EI

二叉树LeetCode热题

94.二叉树的中序遍历 题目 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 输入&#xff1a;root [1,null,2,3]输出&#xff1a;[1,3,2] 代码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* …

基于python的百度迁徙迁入、迁出数据分析(六)

书接上回&#xff0c;苏州市我选取了2024年5月1日——5月5日迁入、迁出城市前20名并求了均值&#xff0c;从数据中可以看出苏州市与上海市的关系还是很铁的&#xff0c;都互为对方的迁入、迁出的首选且迁徙比例也接近4分之一&#xff0c;名副其实的老铁了&#xff1b; 迁出城市…

Springboot学习-day16

Springboot学习-day16 Springboot是spring家族中的一个全新框架&#xff0c;用来简化spring程序的创建和开发过程。在以往我们通过SpringMVCSpringMybatis框架进行开发的时候&#xff0c;我们需要配置web.xml&#xff0c;spring配置&#xff0c;mybatis配置&#xff0c;然后整…

鸿蒙应用框架开发【JS注入与执行】 Web

JS注入与执行 介绍 本示例基于H5游戏&#xff0c;通过arkui的button实现对游戏实现基本控制&#xff0c;展示webview的JS注入与执行能力&#xff0c;及native应用与H5的通信能力。 效果预览 使用说明 1.设备连接热点&#xff0c;可访问互联网。 2.打开应用&#xff0c;通过…

RuoYi-3.0代码审计

1 第三方组件漏洞审计 本项目使用Maven构建的。因此我们直接看pom.xml文件引入了哪些组件。通过IDEA打 开该若依&#xff0c;发现本项目采用了多模块方式。因此每个模块下都会有一个pom.xml&#xff0c;项目 最外层的pom.xml为父POM。我们可以通过 pom.xml 或者 External Libr…

【C语言】简易版扫雷游戏(数组、函数的练习)

目录 一、分析和设计 1.1、扫雷游戏的功能分析 1.2、文件结构设计&#xff08;多文件的练习&#xff09; 1.3、数据结构的设计 二、代码 三、效果展示 三、优化 一、分析和设计 1.1、扫雷游戏的功能分析 以在线版的扫雷游戏为参考&#xff0c;分析它的功能&#xff1a;扫…

⌈ 传知代码 ⌋ 基于矩阵乘积态的生成模型

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

钉耙编程(3)

1001深度自同构 Problem Description 对于无向图中的点&#xff0c;定义一个点的度为与其相连的边的条数。 对于一棵有根树&#xff0c;定义一个点的深度为该点到根的距离。 对于由若干有根树构成的森林&#xff0c;定义该森林是深度自同构的&#xff0c;当且仅当森林中任意…

【论文解读|Data Intelligence】 Dr.ICL: Demonstration-Retrieved In-context Learning

论文链接&#xff1a; 来源&#xff1a; Data Intelligence 论文介绍&#xff1a; 该研究由亚利桑那州立大学和谷歌研究团队的专家撰写&#xff0c;深入探讨了通过利用基于检索的方法来提高大型语言模型&#xff08;LLM&#xff09;性能的策略。 主要亮点&#xff1a; • 创…

解开基于大模型的Text2SQL的神秘面纱

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

程序员修炼之路

成为一名优秀的程序员&#xff0c;需要广泛而深入地学习多个领域的知识。这些课程不仅帮助建立扎实的编程基础&#xff0c;还培养了问题解决、算法设计、系统思维等多方面的能力。以下是一些核心的必修课&#xff1a; 计算机基础 计算机组成原理&#xff1a;理解计算机的硬件组…

GD 32 滤波算法

快速排序知识补充 http://t.csdnimg.cn/gVOsohttp://t.csdnimg.cn/gVOso GD32硬件滤波算法 程序代码&#xff1a; #include <stdint.h> #include <stdio.h> #include "gd32f30x.h" #include "delay.h"static void GpioInit(void) {rcu_periph…

项目实战_表白墙(简易版)

你能学到什么 一个比较简单的项目&#xff1a;表白墙&#xff08;简易版&#xff09;&#xff0c;浏览器&#xff1a;谷歌升级版将在下个博客发布 效果如下 正文 说明 我们是从0开始一步一步做这个项目的&#xff0c;里面的各种问题&#xff0c;我也会以第一人称视角来解…

经验分享:大数据多头借贷风险对自身的不利影响?

在现代金融体系中&#xff0c;大数据技术的应用使得多头借贷成为一种普遍现象。多头借贷指的是个人或企业在短时间内同时或近期内申请多笔贷款或信用产品&#xff0c;这种行为可能带来一系列财务和信用风险。以下是大数据多头借贷风险对个人自身可能产生的不利影响&#xff1a;…

如何编写一个多线程、非阻塞的python代码

一、【写在前面】 最近csdn每天写两篇文章有推广券&#xff0c;趁这个机会写一个python相关的文章吧。 一般我们的任务都可以分为计算密集型任务和IO密集型任务。 python因为全局GIL锁的存在&#xff0c;任何时候只有一个python线程在运行&#xff0c;所以说不能利用多核CPU…

数字的位操作——326、504、263、190、191、476、461、477、693

326. 3 的幂&#xff08;简单&#xff09; 给定一个整数&#xff0c;写一个函数来判断它是否是 3 的幂次方。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 整数 n 是 3 的幂次方需满足&#xff1a;存在整数 x 使得 n 3x 示例 1&#xff1a; 输入&a…

程序员面试题------N皇后问题算法实现

N皇后问题是一个著名的计算机科学问题&#xff0c;它要求在NN的棋盘上放置N个皇后&#xff0c;使得它们之间不能相互攻击&#xff0c;即任意两个皇后都不能处于同一行、同一列或同一斜线上。这个问题可以看作是一个回溯算法问题&#xff0c;通过逐步尝试不同的放置位置&#xf…