Linux misc驱动实践

发布时间:2026/10/15 4:08:09

Linux misc驱动实践 阅读了正点原子的《I.MX6U嵌入式Linux驱动开发指南》第五十七章Linux MISC驱动实验了解到misc驱动也是字符设备驱动并且嵌套在platform总线驱动中既然前面学习了platform总线驱动的框架所以决定在理解misc驱动原理后自己不看例程独立完成misc驱动编写。先学习一下misc驱动的原理。所有的MISC设备驱动的主设备号都是10从设备号分配给不同的设备。Linux系统预定义了一些从设备号在include/linux/miscdevice.h文件中可以查到。Linux为misc设备定义了一个结构体定义在include/linux/miscdevice.h中struct miscdevice { int minor; const char *name; const struct file_operations *fos; struct list_head list; struct device *parent; struct device *this_device; const struct attribute_group **group; const char *nodename; umode_t mode; };我们需要设置minor、name和fops这三个成员变量。minor可以自己定义一个尚未使用的子设备号。name就是要编写的misc设备名字当它注册成功后会在/dev目录下生成一个名为name的设备文件。fops是字符设备的操作集合。设置好miscdevice结构体后就需要向系统注册一个MISC设备使用函数int misc_register(struct miscdevice * misc)卸载MISC设备驱动模块时要调用的函数int misc_deregister(struct miscdevice *misc)使用了misc_register()函数后传统的创建设备过程中调用的申请设备号函数alloc_chrdev_region()、初始化cdev函数cdev_init()、添加cdev函数cdev_add()、创建类函数class_create()、创建设备函数device_create()都不需要了用一个misc_register()函数就可以搞定注册和创建设备。同样的注销misc设备驱动时以前需要调用的删除cdev函数cdev_del()、注销设备号函数unregister_chrdev_region()、删除设备函数device_destroy()、删除类函数class_destroy()也不需要了用misc_deregister()函数就可以完成。MISC驱动实验还是去驱动IMX6U-ALPHA开发板上的BEEP峰鸣器。编写完miscbeep驱动程序编译通过运行后出现“Unable to handle kernel NULL pointer dereference at virtual address 00000000报错如下图。针对报错信息怀疑是有未初始的指针被引用了。查看编写的源码看到定义在beepdev_dev结构体时将struct miscdevice 变量也封装进来了然后在beep_probe()函数中对这个变量进行minor、name、fops赋值最后再进行注册。考虑到misc设备结构体是Linux内核提供的这个结构体需要我们定义的成员有3个其他成员并没有定义这就可能造成是空指针。因此不封装struct miscdevice变量而是在驱动程序文件中声明这个变量对变量的name、minor、fops赋值。 修改后的源码如下#include linux/types.h #include linux/kernel.h #include linux/delay.h #include linux/ide.h #include linux/init.h #include linux/module.h #include linux/errno.h #include linux/gpio.h #include linux/cdev.h #include linux/device.h #include linux/of_gpio.h #include linux/semaphore.h #include linux/timer.h #include linux/irq.h #include linux/wait.h #include linux/poll.h #include linux/fs.h #include linux/fcntl.h #include linux/miscdevice.h #include linux/platform_device.h #include asm/mach/map.h #include asm/uaccess.h #include asm/io.h /*************************************************************** Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved. 文件名 : leddriver.c 作者 : 版本 : V1.0 描述 : platform驱动 其他 : 无 论坛 : www.openedv.com 日志 : 初版V1.0 2019/8/13 左忠凯创建 ***************************************************************/ #define BEEPDEV_CNT 1 /* 设备号长度 */ #define BEEPDEV_NAME miscbeep /* 设备名字 */ #define BEEPOFF 0 #define BEEPON 1 #define MISC_BEEP_MINOR 240 /* beepdev设备结构体 */ struct beepdev_dev { dev_t devid; /* 设备号 */ struct device_node *node; /*struct miscdevice *miscdev;*/ int beep0; }; struct beepdev_dev beepdev; /* led设备 */ /* * description : beep打开/关闭 * param - sta : BEEPON(0) 打开BEEPBEEPOFF(1) 关闭BEEP * return : 无 */ void beep0_switch(u8 sta) { if(sta BEEPON){ gpio_set_value(beepdev.beep0, 0); }else if(sta BEEPOFF){ gpio_set_value(beepdev.beep0, 1); } } /* * description : 打开设备 * param - inode : 传递给驱动的inode * param - filp : 设备文件file结构体有个叫做private_data的成员变量 * 一般在open的时候将private_data指向设备结构体。 * return : 0 成功;其他 失败 */ static int beep_open(struct inode *inode, struct file *filp) { filp-private_data beepdev; /* 设置私有数据 */ return 0; } /* * description : 向设备写数据 * param - filp : 设备文件表示打开的文件描述符 * param - buf : 要写给设备写入的数据 * param - cnt : 要写入的数据长度 * param - offt : 相对于文件首地址的偏移 * return : 写入的字节数如果为负值表示写入失败 */ static ssize_t beep_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int retvalue; unsigned char databuf[1]; unsigned char beepstat; retvalue copy_from_user(databuf, buf, cnt); if(retvalue 0) { return -EFAULT; } beepstat databuf[0]; /* 获取状态值 */ if(beepstat BEEPON) { beep0_switch(BEEPON); /* 打开LED灯 */ }else if(beepstat BEEPOFF) { beep0_switch(BEEPOFF); /* 关闭LED灯 */ } return 0; } /* 设备操作函数 */ static struct file_operations beep_fops { .owner THIS_MODULE, .open beep_open, .write beep_write, }; #if 1 static struct miscdevice beep_dev { .minor MISC_BEEP_MINOR, .name miscbeep, .fops beep_fops }; #endif /* * description : flatform驱动的probe函数当驱动与 * 设备匹配以后此函数就会执行 * param - dev : platform设备 * return : 0成功;其他负值,失败 */ static int beep_probe(struct platform_device *dev) { int ret 0; printk(beep driver and device has matched!\r\n); #if 0 beepdev.miscdev-minor MISC_BEEP_MINOR; beepdev.miscdev-name miscbeep; beepdev.miscdev-fops beep_fops; #endif ret misc_register(beep_dev); if (ret 0) { printk(beepdev not register!\r\n); return ret; } beepdev.node of_find_node_by_path(/gpiobeep); if (beepdev.node NULL) { printk(gpiobeep node not find!\r\n); return -EINVAL; } beepdev.beep0 of_get_named_gpio(beepdev.node, beep-gpio, 0 ); if (beepdev.beep0 0) { printk(cant get beep-gpio\r\n); return -EINVAL; } gpio_request(beepdev.beep0, beep0); gpio_direction_output(beepdev.beep0, 1); return 0; } /* * description : platform驱动的remove函数移除platform驱动的时候此函数会执行 * param - dev : platform设备 * return : 0成功;其他负值,失败 */ static int beep_remove(struct platform_device *dev) { gpio_set_value(beepdev.beep0, 1); misc_deregister(beep_dev); return 0; } static const struct of_device_id beep_of_match[] { { .compatible atkalpha-beep }, { } }; /* platform驱动结构体 */ static struct platform_driver beep_driver { .driver { .name imx6ul-beep, /* 驱动名字用于和设备匹配 */ .of_match_table beep_of_match, }, .probe beep_probe, .remove beep_remove, }; /* * description : 驱动模块加载函数 * param : 无 * return : 无 */ static int __init beepdriver_init(void) { return platform_driver_register(beep_driver); } /* * description : 驱动模块卸载函数 * param : 无 * return : 无 */ static void __exit beepdriver_exit(void) { platform_driver_unregister(beep_driver); } module_init(beepdriver_init); module_exit(beepdriver_exit); MODULE_LICENSE(GPL); MODULE_AUTHOR(bobluo);重新编译后开始加载miscbeep.ko驱动在/sys/class/misc目录下可以看到“miscbeep”的子目录驱动与设备匹配成功后用ls /dev/miscbeep -l命令可以查看主次设备号如下图。输入打开或关闭BEEP的命令如下图可以正常开关蜂鸣器至此自己编写的misc驱动运行成功。参考资料1.I.MX6Uq嵌入式Linux驱动开发指南V2.0.1正点原子2. Linux设备驱动开发 详解基于最新的Linux 4.0内核
延伸阅读

更多相关文章

2026/10/15 4:08:09

优化开票任务Demo开发(章节2)

听起来很复杂像是ConcurrentHashMap把线程隔离开了,但其实就是创建了两个线程池,这两个线程池本来就是隔开的,跟ConcurrentHashMap没啥关系ConcurrentHashMap只是为了解决数据争用项目中通过一个Cache类,把用户的相关开票数据搬到…

2026/10/15 4:03:08

家长怎么远程控制孩子手机 家长控制孩子手机的方法

家长怎么远程控制孩子手机?很多家长日常工作忙碌,无法时刻陪伴孩子,难以实时掌握孩子的手机使用情况,管控十分被动。家长怎么远程控制孩子手机呢?无需复杂设备和繁琐设置,无界趣连2.0适配亲子远程管控场景&…

2026/10/15 5:18:12

河北工业大学Java期末复习题:25道选择题考点剖析

简介:河北工业大学Java期末考试复习题(部分答案)是一份面向该校Java课程本科生的期末备考资料,适用于考前集中复习、常见题型演练和查漏补缺,也可供任课教师出题或备课参考。资源包共包含1个doc文档,整体约…

2026/10/15 5:18:12

FileChannel深度解析:零拷贝与内存映射实战指南

在Java的NIO体系里,FileChannel是很多人学完Buffer之后第一个真正上手的通道类。它解决的问题很朴素:让文件的读写不再像传统IO那样一边读一边频繁拷贝,而是把文件抽象成一个可定位、可映射、可高效搬移的通道。作为整个NIO中唯一和本地文件系…

2026/10/15 5:18:12

分数阶Calderón问题贝叶斯反演:MCMC与MATLAB实现全解析

做反问题这些年,我发现一个特别有意思的共识:只要把经典算子换成分数阶,问题难度往往会跳一个台阶,但能解释的物理现象也瞬间丰富很多。分数阶Caldern问题就是这个方向的典型代表——它既要处理边界测量反演内部参数的经典难点&am…

2026/10/15 5:18:12

LLM推理性能测试指南:并发压测与指标归因实战

性能测试这件事,最怕的不是结果不好看,而是结果说不出为什么,换个环境就崩。上个月我把 vLLM 和 SGLang 两个推理引擎拉到一起做并发实验,前前后后折腾了两周,最后发现坑全不在引擎本身,而在实验设计和指标…

2026/10/15 5:18:12

一文搞懂分类问题:算法选型、评估指标与实战避坑

1. 分类问题到底在解决什么:先想清楚边界在哪很多人一上来就背模型:逻辑回归、决策树、SVM、随机森林……但真到项目里,第一个卡住的往往不是模型不会调,而是"这个问题到底该不该当成分类来做"。我见过不少同学把回归问…

2026/10/15 5:13:12

PostgreSQL生产库备份方案:Barman全量备份与WAL归档实战

很多DBA做PostgreSQL备份,第一反应就是写个 cron 脚本,定时调 pg_dump。这套逻辑在几十 GB 的小库上确实够用,但当你手里管着几百 GB 甚至上 TB 的生产库,还要回答“我能恢复到什么时间点”“备份到底能不能用”这两个问题时&…

2026/10/14 11:31:03

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/14 17:41:07

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/14 2:32:55

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/15 0:02:22

防关联浏览器哪个好?三款产品实测差异解析

新手做多店铺,最纠结的就是防关联浏览器选哪个。飞跨、网易、站斧这三款被问得最多,先给结论:要一体化省心、长期便宜,选站斧;要网易招牌和稳,选网易;预算紧做东南亚 Lazada,选飞跨。…

2026/10/15 0:02:22

影刀RPA深度实战:大模型Fine-tuning定制RPA专用Prompt与指令生成

影刀RPA深度实战:大模型Fine-tuning定制RPA专用Prompt与指令生成 一、技术背景 大模型(LLM)在通用场景下表现强大,但当我们将 GPT-4 或 Qwen 直接用于生成影刀RPA操作指令和 XPath 定位时,准确率通常只有 40%-60%。原因…

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

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

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