新字符设备驱动详解

新字符设备驱动实验核心解读
Linux字符设备驱动开发的基本流程,老方法靠register_chrdev注册、unregister_chrdev注销,还得手动用mknod创建设备节点,不仅麻烦还浪费次设备号。如今Linux内核早已推荐新的驱动开发方式,新字符设备驱动的编写,核心要解决自动创建设备节点的问题,下面从原理到实践逐一拆解。

一、字符设备驱动原理

  1. 灵活分配与释放设备号
    用老方法注册字符设备时,只需指定主设备号,但存在两个明显弊端:一是得提前排查哪些主设备号未被占用,操作繁琐;二是一个主设备号会占满所有次设备号,比如给LED设主设备号200,0到1048575的次设备号就全被它独占,十分浪费——毕竟一个LED设备只需要一个主设备号和一个次设备号。

新方法的核心是按需向内核申请设备号,要几个申几个,由内核统一分配可用资源,完美规避上述问题。具体分两种情况操作:

  • 未指定设备号时,用alloc_chrdev_region函数申请,传入设备号存储指针、起始次设备号(通常设为0)、申请数量和设备名,函数会自动分配主次设备号。
  • 已指定主次设备号时,用register_chrdev_region函数注册,传入起始设备号、数量和设备名,完成设备号的预留。

驱动卸载后,不管通过哪种方式申请的设备号,都用unregister_chrdev_region统一释放,避免资源残留。

示例代码里会先判断是否预先定义了主设备号,如果定义了,就用MKDEV构建设备号,再用register_chrdev_region注册;若未定义,就调用alloc_chrdev_region申请,同时用MAJORMINOR提取主、次设备号。注销时只需一行代码调用释放函数,简单高效。

  1. 全新的字符设备注册流程
    老注册方式已被淘汰,现在靠cdev结构体和配套函数构建标准注册流程,分四步完成。
  • 定义字符设备结构体:在Linux内核中,字符设备用cdev结构体表示,里面最关键的是文件操作函数集合ops和设备号dev。编写驱动前,要先定义一个cdev变量,它就是字符设备的载体。
  • 初始化cdev变量:定义好cdev变量后,需用cdev_init函数初始化,传入要初始化的cdev变量和文件操作函数集合,完成基础配置。
  • 向内核添加字符设备:初始化完成后,调用cdev_add函数将字符设备添加到Linux系统。该函数需要传入指向cdev的指针、设备号和设备数量,正常添加后,内核就能识别这个字符设备了。
  • 从内核删除字符设备:驱动卸载时,必须用cdev_del函数从内核中删除字符设备。它和释放设备号的函数配合,作用等同于老方法的unregister_chrdev,能确保资源完全回收。

二、自动创建设备节点
过去加载驱动后,得手动用mknod创建设备节点,现在通过驱动内的机制,加载模块就能自动在/dev目录下生成设备文件,核心依赖mdev机制,具体分两步实现。

  1. 依托mdev实现自动管理
    在嵌入式Linux系统中,mdevudev的简化版,借助它可实现设备节点的自动创建与删除,还能管理热插拔事件。构建根文件系统时,通过一条配置语句让mdev接管热插拔事件,无需深究其底层原理,重点掌握借助它自动创建节点的方法即可。
  1. 类与设备的创建和销毁
    自动创建设备节点的操作在驱动入口函数中完成,且要在cdev_add之后执行,核心是先建类,再在类下建设备。
  • 创建和删除类:用class_create创建类,参数一般用THIS_MODULE和类名,函数返回类的指针。驱动卸载时,调用class_destroy删除类,传入要删除的类指针。
  • 创建和删除设备:类建好后,用device_create在类下创建设备,传入类指针、父设备(设为空)、设备号、设备数据(设为空)和设备名,函数返回创建好的设备指针。驱动卸载时,用device_destroy删除设备,传入类指针和设备号。

具体流程是,在驱动入口函数里先调用class_create建类,再用device_create在类下建设备;出口函数里则反过来,先删设备,再删类,形成完整闭环。

三、文件私有数据的封装
编写驱动时,把设备的所有属性写成独立变量虽然可行,但不够专业。更规范的做法是将这些属性封装成一个结构体,在open函数里把这个结构体设为文件的私有数据,后续在readwriteclose等函数中,通过读取文件的私有数据,就能直接获取设备的所有属性,既清晰又便于维护。

四、实验程序与测试

  1. LED驱动编写
    本次实验基于第2章的LED驱动,核心是用新驱动框架重构,同时封装私有数据、添加自动创建节点的逻辑。

驱动代码里先定义了LED操作相关的寄存器地址、设备结构体,结构体包含设备号、cdev、类、设备等核心信息。驱动入口函数里,先完成寄存器映射、时钟使能、引脚复用和GPIO配置,接着按新流程分配设备号、初始化并添加cdev,最后创建类和设备,实现自动生成设备节点。open函数将设备结构体设为文件私有数据,write函数根据用户指令控制LED开关。驱动出口函数则依次执行注销字符设备、删除设备和类、取消寄存器映射等操作,确保资源完全释放。

  1. 测试程序复用
    测试App直接复用第2章的ledApp,无需额外修改,它通过向/dev/newchrled设备文件发送指令,控制LED的亮灭。
  1. 编译与测试步骤
  • 编译:先修改Makefile,指定编译newchrled.o;接着用命令分别编译驱动模块和测试程序,生成newchrled.ko和ledApp文件。
  • 测试:把编译好的文件拷贝到开发板指定目录,重启后运行depmodmodprobe newchrled加载驱动,终端会输出申请到的主次设备号,且自动在/dev下生成newchrled设备文件。用ledApp发送指令即可控制LED,卸载驱动时执行rmmod newchrled,设备节点会自动删除。

五、总结
掌握Linux新字符设备驱动的开发模式,核心流程是申请设备号、初始化并注册cdev、创建类和设备,这套模式不仅解决了老方法资源浪费、操作繁琐的问题,还能自动创建设备节点,是当前Linux驱动开发的标准方法。通过LED驱动实验的落地,我们能将这套流程灵活应用到各类字符设备驱动开发中,后续各类外设驱动都能在此基础上拓展延伸。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容