驱动开发硬核特训 · Day 16:字符设备驱动模型与实战注册流程

news2025/7/19 5:42:50

🎥 视频教程请关注 B 站:“嵌入式 Jerry”


一、为什么要学习字符设备驱动?

在 Linux 驱动开发中,字符设备(Character Device)驱动 是最基础也是最常见的一类驱动类型。很多设备(如 LED、按键、串口、传感器)都可以以字符设备方式呈现,并通过 read()write()ioctl() 与用户空间通信。

理解字符设备驱动,不仅是掌握 Linux 驱动开发的起点,也为日后深入 platform、总线设备驱动、misc、input 等模型打下坚实基础。


在这里插入图片描述

二、字符设备驱动的核心模型

字符设备驱动的注册模型由内核 include/linux/cdev.h 文件中的结构与接口决定:

2.1 struct cdev 是关键结构

struct cdev {
    struct kobject kobj;
    struct module *owner;
    const struct file_operations *ops;
    ...
};

它是内核维护的代表“一个字符设备”的核心结构体。

2.2 file_operations 是接口描述

这是用户空间调用 open/read/write/ioctl 等系统调用时,最终调用的驱动函数集。

static const struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .open = my_open,
    .read = my_read,
    .write = my_write,
    .release = my_release,
};

2.3 主设备号 & 次设备号

  • 主设备号用于标识驱动程序
  • 次设备号用于区分同一类驱动下的不同设备实例

三、字符设备注册的五个步骤

学习字符设备注册的流程,可以总结为五步:

步骤 1:分配设备号

dev_t devno;
alloc_chrdev_region(&devno, 0, 1, "mychardev");
  • devno 是设备号(类型为 dev_t),用 MAJOR(devno)MINOR(devno) 分别提取主次设备号。
  • alloc_chrdev_region() 会自动分配主设备号。

步骤 2:初始化 cdev 结构

struct cdev my_cdev;
cdev_init(&my_cdev, &my_fops);
my_cdev.owner = THIS_MODULE;

步骤 3:添加 cdev 到系统中

cdev_add(&my_cdev, devno, 1);

这一步使得字符设备被内核正式管理。

步骤 4:创建设备节点

配合 udev 或手动创建设备节点:

mknod /dev/mydev c <主设备号> <次设备号>

更推荐在内核中通过 class_create + device_create 来自动创建节点。

步骤 5:卸载时释放

device_destroy(my_class, devno);
class_destroy(my_class);
cdev_del(&my_cdev);
unregister_chrdev_region(devno, 1);

四、完整实战代码:LED 字符设备驱动

我们用一个模拟的 LED 驱动为例,实现一个字符设备:

4.1 驱动核心代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>

#define DEV_NAME "myled"

static dev_t devno;
static struct cdev my_cdev;
static struct class *my_class;

static int led_value = 0;

static ssize_t led_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
    return copy_to_user(buf, &led_value, sizeof(led_value)) ? -EFAULT : sizeof(led_value);
}

static ssize_t led_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
    return copy_from_user(&led_value, buf, sizeof(led_value)) ? -EFAULT : sizeof(led_value);
}

static int led_open(struct inode *inode, struct file *file)
{
    pr_info("LED device opened\n");
    return 0;
}

static int led_release(struct inode *inode, struct file *file)
{
    pr_info("LED device closed\n");
    return 0;
}

static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .read = led_read,
    .write = led_write,
    .open = led_open,
    .release = led_release,
};

static int __init led_init(void)
{
    alloc_chrdev_region(&devno, 0, 1, DEV_NAME);
    cdev_init(&my_cdev, &led_fops);
    cdev_add(&my_cdev, devno, 1);

    my_class = class_create(THIS_MODULE, "myled_class");
    device_create(my_class, NULL, devno, NULL, DEV_NAME);

    pr_info("LED driver loaded: major=%d\n", MAJOR(devno));
    return 0;
}

static void __exit led_exit(void)
{
    device_destroy(my_class, devno);
    class_destroy(my_class);
    cdev_del(&my_cdev);
    unregister_chrdev_region(devno, 1);

    pr_info("LED driver unloaded\n");
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jerry");
MODULE_DESCRIPTION("Simple LED Char Device Driver");

五、测试方法与验证

编译并加载

make
insmod myled.ko

查看设备节点

ls /dev/myled

读写测试

echo 1 > /dev/myled
cat /dev/myled

六、文件系统中的呈现:/proc 与 /sys

字符设备驱动在加载后,会自动出现在以下路径中:

路径含义
/proc/devices显示当前注册的主设备号及驱动名
/sys/class/myled_class/myled/设备节点属性
/dev/myled用户空间访问入口

七、理论总结:字符设备模型的特点

  • 与平台设备无绑定关系,适合用于最简设备建模。
  • 所有用户空间 I/O 都通过 file_operations 映射函数实现。
  • 可作为更复杂模型(如 misc、input、platform)的基础。

八、常见问题答疑

Q1:字符设备必须创建设备节点吗?

A:必须。否则无法从用户空间访问。可使用 mknoddevice_create 自动生成。

Q2:file_operations 中哪些函数必须实现?

A:至少实现 openreleasereadwrite。也可以只实现 ioctl,视业务而定。

Q3:主设备号可以固定吗?

A:可以使用 register_chrdev() 指定固定主设备号,但建议使用动态分配。


九、结语与展望

字符设备模型虽是最基础的驱动类型,但它揭示了驱动与用户空间之间的交互机制,是理解 Linux 驱动架构的入口。后续我们将继续向上探索:

  • misc 模型
  • platform 总线匹配机制
  • device tree 配合 platform 驱动

敬请期待《驱动开发硬核特训 · Day 17》!


📺 视频教程请关注 B 站:“嵌入式 Jerry”

如有问题,欢迎评论区留言交流,也欢迎点赞收藏,让我们一起成为 Linux 驱动高手!


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

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

相关文章

Virtuoso ADE采用Spectre仿真中出现MOS管最小长宽比满足要求依然报错的情况解决方法

在ADE仿真中错误问题如下&#xff1a; ERROR (CMI-2440): "xxx.scs" 46338: I2.M1: The length, width, or area of the instance does not fit the given lmax-lmin, wmax-wmin, or areamax-areamin range for any model in the I2.M3.nch_hvt group. The channel w…

大模型应用开发之LLM入门

一、大模型概述 1、大模型概念 LLM是指用有大量参数的大型预训练语言模型&#xff0c;在解决各种自然语言处理任务方面表现出强大的能力&#xff0c;甚至可以展现出一些小规模语言模型所不具备的特殊能力 2、语言模型language model 语言建模旨在对词序列的生成概率进行建模…

武汉昊衡科技OLI光纤微裂纹检测仪:高密度光器件的精准守护者

随着AI技术应用越来越广&#xff0c;算力需求激增&#xff0c;光通信系统正加速向小型化、高密度、多通道方向演进。硅光芯片、高速光模块等核心器件内部的光纤通道数量成倍增加&#xff0c;波导结构愈发精细&#xff0c;传统检测手段因分辨率不足、效率低下&#xff0c;难以精…

SQL 函数进行左边自动补位fnPadLeft和FORMAT

目录 1.问题 2.解决 方式1 方式2 3.结果 1.问题 例如在SQL存储过程中&#xff0c;将1 或10 或 100 长度不足的时候&#xff0c;自动补足长度。 例如 1 → 001 10→ 010 100→100 2.解决 方式1 SELECT FORMAT (1, 000) AS FormattedNum; SELECT FORMAT(12, 000) AS Form…

Tailwind CSS实战:快速构建定制化UI的新思路

引言 在当今快节奏的前端开发环境中&#xff0c;开发者不断寻找能够提高效率并保持灵活性的工具。Tailwind CSS作为一个功能型优先的CSS框架&#xff0c;正在改变开发者构建用户界面的方式。与Bootstrap和Material UI等传统组件库不同&#xff0c;Tailwind不提供预设组件&…

【数据可视化-25】时尚零售销售数据集的机器学习可视化分析

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN人工智能领域的优质创作者,提供AI相关的技术咨询、项目开发和个…

UML 活动图深度解析:以在线购物系统为例

目录 一、UML 活动图的基本构成要素 二、题目原型 三、在线购物系统用户购物活动图详细剖析 &#xff08;一&#xff09;概述 &#xff08;二&#xff09;节点分析 三、注意事项 四、活动图绘画 五、UML 活动图在软件开发中的关键价值 六、总结 在软件开发与系统设计领…

【MFC】 VS2022打开低版本的MFC,双击.rc文件,DIalog加载失败,页面弹窗fatal error RC***:cannot open*****

打开以前的MFC示例报错&#xff0c;打开VS2019的实例以及更早VS版本的实例都一样,打不开&#xff0c;还报错&#xff1b; 错误 MSB8041 此项目需要 MFC 库。从 Visual Studio 安装程序(单个组件选项卡)为正在使用的任何工具集和体系结构安装它们。 GxCameraEvents_VS2015 C:\P…

Centos9 安装 nginx 及配置

1. 安装nginx 安装依赖软件&#xff0c;安装之前可以看一下是否已经安装过以下软件&#xff0c;dnf list installed | grep zlib dnf install gcc-c dnf install zlib dnf install pcre pcre-devel dnf install openssl openssl-devel下载nginx&#xff0c;这里是下载到opt文…

使用Handsontable实现动态表格和下载表格

1.效果 2.实现代码 首先要加载Handsontable&#xff0c;在示例中我是cdn的方式引入的&#xff0c;vue的话需要下载插件 let hot null;var exportPlugin null;function showHandsontable(param) {const container document.getElementById("hot-container");// 如果…

Action:Update your application‘s configuration

在使用Maven项目时&#xff0c;有一个报错信息是&#xff1a;Update your applications configuration 这类问题&#xff0c;就是我们的application.yml文件 或者 application.properties文件 内容哪里写错了 最有可能就是对齐方式有问题

【计算机网络】IP地址

IPv4 五类地址 1.0.0.0 ~ 126.255.255.255A类子网8位&#xff0c;主机24位128.0.0.0 ~ 191.255.255.255B类子网16位&#xff0c;主机16位192.0.0.0 ~ 223.255.255.255C类子网24位&#xff0c;主机8位224.0.0.0 ~ 239.255.255.255D类不分网络地址和主机地址&#xff0c;作为组播…

Rundeck 介绍及安装:自动化调度与执行工具

Rundeck介绍 概述&#xff1a;Rundeck 是什么&#xff1f; Rundeck 是一款开源的自动化调度和任务执行工具&#xff0c;专为运维场景设计&#xff0c;帮助工程师通过统一的平台管理和执行跨系统、跨节点的任务。它由 PagerDuty 维护&#xff08;2016 年收购&#xff09;&#…

vue element使用el-table时,切换tab,table表格列项发生错位问题

展示问题 问题描述&#xff1a;使用el-table的fixed"right"属性后&#xff0c;如果切换tab时&#xff0c;回出现最后一列错误的问题 官网提供解决方法&#xff1a;doLayout 需要注意的事项&#xff1a;我这里是通过组件使用的table组件&#xff0c;涉及多层组件封装…

第十二章 Python语言-大数据分析PySpark(终)

目录 一. PySpark前言介绍 二.基础准备 三.数据输入 四.数据计算 1.数据计算-map方法 2.数据计算-flatMap算子 3.数据计算-reduceByKey方法 4.数据计算-filter方法 5.数据计算-distinct方法 6.数据计算-sortBy方法 五.数据输出 1.输出Python对象 &#xff08;1&am…

AD相同网络的铜皮和导线连接不上

出现这样的情况是不是很烦恼&#xff0c;明明是相同的网络连接不上&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f; 直接修改铜皮属性&#xff08;选择所有相同这个选项&#xff09; 这样就可以连接上了

keil修改字体无效,修改字体为“微软雅黑”方法

在网上下载了微软雅黑字体&#xff0c;微软雅黑参考下载链接 结果在Edit->Configuration中找不到这个字体 这个时候可以在keil的安装目录中找到UV4/global.prop文件 用记事本打开它进行编辑&#xff0c;把字体名字改成微软雅黑 重新打开keil就发现字体成功修改了。 这个…

【网络编程】从零开始彻底了解网络编程(三)

本篇博客给大家带来的是网络编程的知识点. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅&#x1f680; 要开心要快乐顺便进步 TCP流…

NVIDIA --- 端到端自动驾驶

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、传统驾驶模型二、NVIDIA的端到端驾驶模型1.基本模型2.自查讯向量3.通用框架 总结 前言 端到端自动驾驶指的是系统接收来自摄像头雷达和激光雷达的原始传感…

CSRF请求伪造

该漏洞主要是关乎于用户&#xff0c;告诫用户不可乱点击链接&#xff0c;提升自我防范&#xff0c;才能不落入Hacker布置的陷阱&#xff01; 1. cookie与session 简单理解一下两者作用 1.1. &#x1f36a; Cookie&#xff1a;就像超市的会员卡 存储位置&#xff1a;你钱包里…