正点原子 I.MX6ULL MINI 开发板学习笔记:misc 设备——字符设备驱动的快捷方式

分享
字符设备注册方式演进

上两篇分别用手动 mknod 和 class_create+device_create 注册字符设备,调用链一长串。这篇用 misc(混杂)设备 一步搞定。代码来自实际工程 code/2026/20260803/05_misc_led,已验证可用。

1. 完成什么实验?

用 misc_register 重写 LED 驱动:一步完成设备号分配、字符设备注册、/dev/myled0 节点创建,同时保留上一篇的 sysfs 属性 led_status。

2. 什么是 misc 设备?

misc(混杂)设备是 Linux 给“不好归类的小字符设备”准备的快捷框架:所有 misc 设备共用主设备号 10,次设备号可以指定或用 MISC_DYNAMIC_MINOR 动态分配。注册后自动出现在 /sys/class/misc/ 下,/dev 节点由 mdev 自动创建。它底层仍然封装了 cdev 那一套,只是内核帮你把活干完了。

3. 关键代码

misc 设备对象把名字、次设备号、file_operations 打包在一起:

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

/* misc 设备对象:MISC_DYNAMIC_MINOR 表示次设备号动态分配(主设备号固定 10),
 * name 决定 /dev 节点名,fops 挂接文件操作集 */
struct miscdevice misc_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NODE,      /* "myled0" */
    .fops = &fops,
};

init 里一条语句替代了之前的一整串:

/* 注册 misc 设备:一步完成设备号分配(主 10)+ /dev/myled0 节点 +
 * /sys/class/misc/myled0/ 目录,成功后次设备号写回 misc_dev.minor */
ret = misc_register(&misc_dev);
if (ret)
{
    pr_err("misc_register error : %d\n", ret);
    return ret;
}

/* ... ioremap 四个寄存器(每个都检查 NULL,失败 goto 倒序释放)、配置 GPIO1_IO03 输出、默认关灯,与前两篇相同 ... */

pr_info("主设备号:%d, 次设备号:%d\r\n", 10, misc_dev.minor);

/* sysfs 属性挂在 misc 设备自己的 device 上:
 * /sys/class/misc/myled0/led_status;失败跳倒序释放链 */
ret = device_create_file(misc_dev.this_device, &attr);
if (ret)
    goto fail_unmap_pdata;

return 0;

/* 倒序释放链:ioremap 失败也会跳到这里 */
fail_unmap_pdata:
    iounmap(pdata);
fail_unmap_pdir:
    iounmap(pdir);
fail_unmap_ppad:
    iounmap(ppad);
fail_unmap_pmux:
    iounmap(pmux);
fail_misc:
    misc_deregister(&misc_dev);
    return ret;
/* exit:反序释放 */
device_remove_file(misc_dev.this_device, &attr);
iounmap(pmux);  iounmap(ppad);  iounmap(pdir);  iounmap(pdata);
misc_deregister(&misc_dev);   /* 注销后 /dev/myled0 一并删除 */

4. 三种注册方式对比

项目手动 mknodclass+devicemisc 设备
设备号动态申请,需先查询动态申请主设备号固定 10,次设备号动态
/dev 节点手动 mknodmdev 自动mdev 自动
sysfs 位置无/sys/class/led//sys/class/misc/
注册调用2 步 + 命令行4 步1 步
适用场景学习原理需要自定义类名简单小设备(推荐)

5. 关键点说明

  • minor 写回:misc_register 成功后会把实际分配到的次设备号写进 misc_dev.minor,所以打印设备号要在注册之后。
  • this_device:misc 注册后 misc_dev.this_device 指向内核创建的 device,sysfs 属性就挂在它上面。
  • 本质没变:misc 底层仍是字符设备 + cdev,应用层 open/read/write 的路径和前两篇完全一样。
  • goto 错误处理:更新后的工程代码里,ioremap 和 device_create_file 失败都会跳到倒序释放链,最末的 fail_misc 负责 misc_deregister,不会残留设备节点。
  • 别滥用:主设备号 10 是共享资源,正经的大类设备(input、framebuffer 等)都有自己的框架,misc 适合 LED、蜂鸣器这类小设备。

6. 实验现象

# insmod drv_led.ko 之后:
dmesg | tail -3            # 主设备号:10, 次设备号:55(动态分配,数值可能不同)
ls /dev/myled0             # 节点已自动存在
ls /sys/class/misc/myled0/ # 能看到 led_status

cat /sys/class/misc/myled0/led_status   # LED_OFF
echo 0 > /sys/class/misc/myled0/led_status   # 灯亮
rmmod drv_led              # /dev/myled0 和 /sys/class/misc/myled0/ 同时消失

总结

问题答案
misc 设备主设备号?固定 10,次设备号动态分配
注册/注销函数?misc_register / misc_deregister
/dev 节点还要 mknod 吗?不要,mdev 自动创建
sysfs 属性挂哪?misc_dev.this_device 上,/sys/class/misc/ 下
misc 底层是什么?还是字符设备 cdev 框架的封装

三篇下来,LED 驱动从手动 mknod 一路简化到 misc_register。下一篇是总结篇《Linux 驱动架构详解》:把驱动怎么编译(树内 zImage vs 树外 .ko)、每个操作在系统运行后到底产生了什么效果,从头到尾串一遍。

继续阅读

嵌入式开发面试知识手册

嵌入式开发工程师面试知识手册 适用对象:零基础起步、目标是通过嵌入式软件/驱动/BSP 方向面试的读者 编写依据:赵哲简历全部知识点 + 智能车 AGV 控制平台完整项目代码(i.MX6ULL Linux 端 + STM32F407 固件)+ Linux 驱动练习代码包 + embedded-agent 嵌入式开发智能体仓库 + 真实面试手撕代码与追问记录 使用方法:每篇按"通俗解释 → 原理细节 → 命令/API → 代码实例 → 项目结合 → 记忆口诀 → 面试问答"组织;口诀用于快速记忆,问答用于自测。第9篇是讲项目的演练场,第10篇是手撕代码实战题库。 总目录 * 第1篇 C语言与数据结构 * 1.1 编译链接全过程 * 1.2 数据类型与内存

作者:azhezhezhe

正点原子 I.MX6ULL MINI 开发板学习笔记:Linux 驱动架构详解——编译、树内树外与运行时效果

这是 Linux 驱动小系列的总结篇。前三篇把 LED 驱动从内核模块写到 misc 设备,属于“会用”;这篇把背后的架构讲透:驱动到底怎么编译、内核树内和树外两种方式的区别、以及驱动里每个操作在系统跑起来之后到底产生了什么效果。内容整理自我的学习笔记(note.pdf)和实际工程 code/2026/20260803。 1. 驱动代码到底怎么编译的? 不管哪种方式,最终都靠内核的 kbuild 系统。核心就三个文件的关系: * Kconfig:定义 menuconfig 里的选项(如 CONFIG_MYMODULE),三态 y/m/n——y 编进内核,m 编成模块,n 不编; * .config:menuconfig 的选择结果,保存在源码顶层; * Makefile:

作者:azhezhezhe

正点原子 I.MX6ULL MINI 开发板学习笔记:自动创建 /dev 节点与 sysfs 属性

上一篇的 LED 驱动还要手动 mknod 才能用。这篇在同一驱动上加两步:用 class_create + device_create 让内核自动生成 /dev 节点,再挂一个 sysfs 属性文件,用 cat/echo 就能看灯、控灯。代码来自实际工程 code/2026/20260803/04_led_sys,已验证可用。 1. 完成什么实验? 在 LED 字符设备驱动基础上:insmod 后自动生成 /dev/myled0(不再手动 mknod);同时在 /sys/class/LED/myled0/ 下挂出 led_status 属性文件,

作者:azhezhezhe