《嵌入式操作系统》_驱动开发_misc类设备与蜂鸣器_20261008

发布时间:2026/10/9 5:54:48

《嵌入式操作系统》_驱动开发_misc类设备与蜂鸣器_20261008 misc 类设备杂项设备 / Miscellaneous DeviceLinux 把所有无法归入标准大类、功能简单、零散小众的硬件统一收纳到 misc 框架下共用固定主设备号10MISC_MAJOR靠不同次设备号区分每个独立设备。适用场景蜂鸣器、看门狗、按键、LED、温度传感器、实时时钟、调试串口、虚拟控制节点等简单外设。[rootLXY210 misc]# ls CEC binder log_system s3c-jpg HPD cpu_dma_latency network_latency s3c-mfc adc device-mapper network_throughput sec-g2d alarm log_events pmem_gpu1 apm_bios log_main psaux ashmem log_radio rfkill[rootLXY210 dev]# ls buzzer -l crw-rw---- 1 0 0 10, 61 Jan 1 13:18 buzzer [rootLXY210 dev]# ls adc -l crw-rw---- 1 0 0 10, 131 Jan 1 13:18 adc核心底层原理统一主设备号 10内核提前注册主设备号 10 作为 misc 总入口所有 misc 设备共享该主号只分配独立次设备号省去单独申请主设备号的麻烦节约设备号资源。全局链表管理内核维护一条misc_list链表所有注册成功的struct miscdevice都会挂入链表用户层 open 设备时内核通过次设备号遍历链表匹配对应设备再调用其读写 /ioctl 接口。自动创建设备节点调用misc_register()注册时内核内部自动完成创建设备类/sys/class/misc→ 创建设备对象 → 在/dev/下自动生成设备文件不需要手动mknod。极简封装屏蔽 cdev 复杂操作普通字符设备需要手动申请设备号 →cdev_init→cdev_add misc 框架内部封装了全套 cdev 逻辑开发者只需要填充一个miscdevice结构体一行函数完成注册 / 注销。misc 类实例蜂鸣器驱动文件找到文件你怎么知道当前的源码中有没有蜂鸣器的驱动文件vscode在内核源码中直接搜索buzzer如果文件太多你去menuconfig中找buzzer也是可以的编译问题在menuconfig中都没有被选择这个肯定不会被编译。选择它但系统里还是没有buzzer的设备文件这个驱动的配置文件名和kconfig中的文件名不一致修改makefile中的定义文件为成功添加驱动。使用驱动该文件的open和close函数几乎什么也没干我们使用x210_pwm_ioctl去操控硬件static struct file_operations dev_fops { .owner THIS_MODULE, .open x210_pwm_open, .release x210_pwm_close, .ioctl x210_pwm_ioctl, }; static int x210_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case PWM_IOCTL_SET_FREQ: printk(PWM_IOCTL_SET_FREQ:\r\n); if (arg 0) return -EINVAL; PWM_Set_Freq(arg); break; case PWM_IOCTL_STOP: default: printk(PWM_IOCTL_STOP:\r\n); PWM_Stop(); break; } return 0; }程序文件#include stdio.h #include stdlib.h #include fcntl.h #include unistd.h #include sys/ioctl.h #include sys/stat.h #define DEVICE_NAME /dev/buzzer #define PWM_IOCTL_SET_FREQ 1 #define PWM_IOCTL_STOP 0 int main() { int fd; int ret; fd open(DEVICE_NAME, O_RDWR); if (fd 0) { perror(Failed to open buzzer device); return -1; } ret ioctl(fd, PWM_IOCTL_SET_FREQ, 10000); // Example ioctl call sleep(3); // Sleep for 3 seconds to let the buzzer sound ret ioctl(fd, PWM_IOCTL_SET_FREQ, 5000); // Example ioctl call sleep(3); // Sleep for 3 seconds to let the buzzer sound ret ioctl(fd, PWM_IOCTL_STOP); // Example ioctl call close(fd); return 0; }misc 类程序关键点内核部分misc类的创建misc_init#ifdef CONFIG_PROC_FS //是否使用proc文件系统 [rootLXY210 ]# ls /proc/ 1 4 cgroups kmsg softirqs 10 41 cmdline kpagecount stat 11 43 cpu kpageflags sys 12 44 cpuinfo loadavg sysrq-trigger 13 45 crypto locks sysvipc 14 48 devices meminfo timer_list 15 5 diskstats misc tty 16 54 driver modules uptime 17 6 execdomains mounts version 18 7 fb mtd vmallocinfo 19 73 filesystems net vmstat 2 8 fs pagetypeinfo wakelocks 20 9 interrupts partitions yaffs 3 apm iomem pvr yaffs_stats 32 asound ioports sched_debug zoneinfo 33 buddyinfo irq scsi 34 bus kallsyms self [rootLXY210 proc]# cat misc 51 network_throughput 52 network_latency 53 cpu_dma_latency 54 log_system 55 log_radio 56 log_events 57 log_main 58 binder 59 device-mapper 242 CEC 243 HPD 240 sec-g2d 254 s3c-jpg 252 s3c-mfc 60 alarm 1 psaux 0 pmem_gpu1 134 apm_bios 61 buzzer 62 ashmem 131 adc 63 rfkillmisc设备创建misc_registerint misc_register(struct miscdevice * misc) { struct miscdevice *c; dev_t dev; int err 0; //使用链表管理misc类设备 INIT_LIST_HEAD(misc-list); mutex_lock(misc_mtx); //查询次设备号是否被占用 list_for_each_entry(c, misc_list, list) { if (c-minor misc-minor) { mutex_unlock(misc_mtx); return -EBUSY; } } //使用位图的方法自动分配次设备号 if (misc-minor MISC_DYNAMIC_MINOR) { int i find_first_zero_bit(misc_minors, DYNAMIC_MINORS); if (i DYNAMIC_MINORS) { mutex_unlock(misc_mtx); return -EBUSY; } misc-minor DYNAMIC_MINORS - i - 1; set_bit(i, misc_minors); } //合成主、次设备号 dev MKDEV(MISC_MAJOR, misc-minor); //创建设备 misc-this_device device_create(misc_class, misc-parent, dev, misc, %s, misc-name); if (IS_ERR(misc-this_device)) { int i DYNAMIC_MINORS - misc-minor - 1; if (i DYNAMIC_MINORS i 0) clear_bit(i, misc_minors); err PTR_ERR(misc-this_device); goto out; } /* * Add it to the front, so that later devices can override * earlier defaults */ //将设备节点添加到内核misc链表中 list_add(misc-list, misc_list); out: mutex_unlock(misc_mtx); return err; }驱动工程师实现部分设备文件的读写接口//自定义设备文件操作结构体 static struct file_operations dev_fops { .owner THIS_MODULE, .open x210_pwm_open, .release x210_pwm_close, .ioctl x210_pwm_ioctl, }; //建立miscdevice结构体 static struct miscdevice misc { //自动分配次设备号 .minor MISC_DYNAMIC_MINOR, //这里的name只是用来记录 .name DEVICE_NAME, //关键自定义文件操作结构体 .fops dev_fops, }; static int __init dev_init(void) { int ret; //将信号量初始化为1也就成了互斥锁 init_MUTEX(lock); //注册misc设备 ret misc_register(misc); //申请引脚 /* GPD0_2 (PWMTOUT2) */ ret gpio_request(S5PV210_GPD0(2), GPD0); if(ret) printk(buzzer-x210: request gpio GPD0(2) fail); //设置为上拉 s3c_gpio_setpull(S5PV210_GPD0(2), S3C_GPIO_PULL_UP); //特殊模式设置为1也就是输出模式 s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(1)); //输出值为0 gpio_set_value(S5PV210_GPD0(2), 0); printk (x210 DEVICE_NAME initialized\n); return ret; }硬件操作相关代码// TCFG0在Uboot中设置这里不再重复设置 // Timer0输入频率Finputpclk/(prescaler11)/MUX1 // 66M/16/16 // TCFG0 tcnt (pclk/16/16)/freq; // PWM0输出频率Foutput Finput/TCFG0 freq static void PWM_Set_Freq( unsigned long freq ) { unsigned long tcon; unsigned long tcnt; unsigned long tcfg1; struct clk *clk_p; unsigned long pclk; //unsigned tmp; //设置GPD0_2为PWM输出 s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(2)); //读寄存器 tcon __raw_readl(S3C2410_TCON); tcfg1 __raw_readl(S3C2410_TCFG1); //mux 1/16 tcfg1 ~(0xf8); tcfg1 | (0x48); __raw_writel(tcfg1, S3C2410_TCFG1); //获取时钟频率pclk clk_p clk_get(NULL, pclk); pclk clk_get_rate(clk_p); tcnt (pclk/16/16)/freq; __raw_writel(tcnt, S3C2410_TCNTB(2)); __raw_writel(tcnt/2, S3C2410_TCMPB(2));//占空比为50% tcon ~(0xf12); tcon | (0xb12); //disable deadzone, auto-reload, inv-off, update TCNTB0TCMPB0, start timer 0 __raw_writel(tcon, S3C2410_TCON); tcon ~(212); //clear manual update bit __raw_writel(tcon, S3C2410_TCON); } void PWM_Stop( void ) { //将GPD0_2设置为input s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(0)); }内核中的互斥锁另一个进程访问到已经上锁的资源时会在此休眠进入等待序列直到锁被释放解决竞争状态mutex_lock(misc_mtx);mutex_unlock(misc_mtx);int misc_register(struct miscdevice * misc) { struct miscdevice *c; dev_t dev; int err 0; INIT_LIST_HEAD(misc-list); //建立互斥锁防止多线程访问时修改同一资源 mutex_lock(misc_mtx); list_for_each_entry(c, misc_list, list) { if (c-minor misc-minor) { mutex_unlock(misc_mtx); return -EBUSY; } }防止竞争的手段原子访问这次操作一下就能完成不可以被打断自旋锁一种忙等锁线程抢锁失败时不放弃 CPU、不进入休眠原地循环自旋反复查询锁状态直到锁被释放。 底层本质原子操作 CAS 实现靠原子指令保证锁状态修改不冲突。互斥锁只能计数一次只能被打开一次信号量通过计数来避免竞争
延伸阅读

更多相关文章

2026/10/9 5:49:48

WDM鼠标驱动开发实战:从源码解析到IRP数据过滤与签名安装

简介:这份资源是面向Windows底层驱动开发学习者的WDM鼠标驱动源代码包,适合已具备C/C基础、希望理解设备驱动模型与HID设备交互机制的开发者参考。压缩包共13个文件,约12KB,以4个h头文件、2个cpp实现文件为主,另有rc资…

2026/10/9 5:49:48

行测想上七十分,先把各模块目标正确率定下来

我备考前半年的状态,说出来很多人会有共鸣:每天雷打不动刷题,课也一节不落地听,可分数就是卡在一个地方不动。后来有个已经上岸的朋友问我一句话,你每个模块现在正确率多少,目标是多少。我当场答不上来。那…

2026/10/9 7:04:52

C++容器选型:vector、list、deque底层原理与性能对比

1. 内容整体设计与核心思路拆解做C开发这些年,跟容器打交道的时间可能比跟对象打交道的时间还多。vector、list、deque这三个标准库容器,几乎出现在每一段业务代码里,但真正能说清楚它们底层到底怎么干活、什么时候该选谁的人,其实…

2026/10/9 7:04:52

大模型分布式训练入门:并行策略、通信原理与PyTorch实践

1. 为什么大模型训练绕不开分布式在接触大模型之前,我训练最大的模型也就是一两亿参数的CV模型,单张V100能跑,顶多两张卡做一下DataParallel。直到开始接手真正的大语言模型训练,才发现情况完全不一样:参数规模从1亿跳…

2026/10/9 7:04:52

TimePro:基于Mamba的长期时间序列预测新架构,解决多延迟难题

1. TimePro 要解决的核心问题:为什么长期预测总会“差一口气”做过时间序列预测的人应该都有同感:短周期预测跑得挺漂亮,一旦把预测长度拉长到周、月级别,效果就开始“漏气”。误差不是均匀放大,而是集中在某些时间点上…

2026/10/9 7:04:52

Java 2048实战源码解析:Swing游戏开发与MVC架构实践

简介:这是一份面向Java初学者与课程设计学习者的2048小游戏实战项目源码包,帮助开发者快速掌握Swing GUI编程、事件驱动逻辑与二维数组状态管理等核心技能。资源包含18个文件,涵盖4个核心Java类(Launcher、Help、About、StrUtils&…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/8 10:03:20

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 0:04:27

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略当数万字的学位论文初稿经历开题、实验、问卷与多轮文献梳理最终成形时,绝大多数研究生都会面临一道全新的形式审查关卡:AIGC 疑似度排查。在高校毕业审核流程中,盲审前的文本检测通…

2026/10/9 0:04:27

食堂节能改造源头工厂,商用厨房设备焕新方案广受好评

商用厨房作为餐饮经营、单位供餐的核心后勤阵地,其设备配置、动线规划与运维体系直接决定后厨作业效率、运营成本与合规性。从基础的灶具、制冷存储设备,到油烟净化、水处理等配套系统,每一个环节的合理性都与食品安全、能耗管控、消防安全挂…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑