6.misc杂项
Misc杂项设备1. 什么是 MiscMiscMiscellaneous Device杂项设备是 Linux 提供的一种简化字符设备驱动框架本质上仍然属于字符设备。对于 LED、蜂鸣器、ADC 等功能较为简单的设备如果仍然按照普通字符设备的方式编写驱动需要完成申请设备号初始化cdev添加cdev创建class创建设备节点这些步骤在很多驱动中都是重复的因此 Linux 将这些公共代码进行了封装形成了Misc 驱动框架。开发者只需要定义miscdevice编写file_operations调用misc_register()即可完成字符设备注册大大减少了代码量。2. Misc 与普通字符设备的区别普通字符设备注册流程申请设备号 │ ▼ alloc_chrdev_region() │ ▼ cdev_init() │ ▼ cdev_add() │ ▼ class_create() │ ▼ device_create() │ ▼ 生成 /dev/xxxMisc 注册流程填写 miscdevice │ ▼ misc_register() │ ▼ 自动完成以上所有步骤因此misc_register() ≈ alloc_chrdev_region() cdev_init() cdev_add() class_create() device_create()3. 设备树修改3.1 添加 Beep 节点beep { compatible alientek,beep; pinctrl-names default; pinctrl-0 pinctrl_beep; beep-gpio gpio5 1 GPIO_ACTIVE_HIGH; status okay; };各属性说明属性说明compatible与 Platform Driver 进行匹配pinctrl-names默认使用的引脚配置pinctrl-0指向具体的引脚配置节点beep-gpio指定蜂鸣器所使用的 GPIOstatusokay表示启用设备3.2 添加 pinctrl 节点在iomuxc_snvs节点下添加pinctrl_beep: beepgrp { fsl,pins MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10B0 ; };说明配置作用pinctrl_beep标签供其它节点引用beepgrp节点名称MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01将引脚复用为 GPIO5_IO010x10B0PAD 电气属性配置4. 驱动主体框架整个 Misc Platform 驱动主要由六部分组成Platform Driver │ ├── file_operations 字符设备操作集 ├── miscdevice Misc设备描述 ├── probe() 设备初始化 ├── remove() 设备移除 ├── of_match_table 设备树匹配 └── platform_driver Platform驱动5. 驱动模板#includelinux/module.h#includelinux/kernel.h#includelinux/init.h#includelinux/fs.h#includelinux/uaccess.h#includelinux/gpio.h#includelinux/of.h#includelinux/of_gpio.h#includelinux/platform_device.h#includelinux/miscdevice.h#defineXXX_NAMExxx#defineXXX_MINOR144/*--------------------设备结构体--------------------*/structxxx_dev{structdevice_node*nd;intxxx_gpio;};staticstructxxx_devxxx;/*--------------------open--------------------*/staticintxxx_open(structinode*inode,structfile*filp){filp-private_dataxxx;return0;}/*--------------------release--------------------*/staticintxxx_release(structinode*inode,structfile*filp){return0;}/*--------------------write--------------------*/staticssize_txxx_write(structfile*filp,constchar__user*buf,size_tcount,loff_t*ppos){intret;unsignedchardatabuf[1];structxxx_dev*devfilp-private_data;retcopy_from_user(databuf,buf,count);if(ret)return-EFAULT;if(databuf[0])gpio_set_value(dev-xxx_gpio,1);elsegpio_set_value(dev-xxx_gpio,0);returncount;}/*--------------------文件操作集--------------------*/staticconststructfile_operationsxxx_fops{.ownerTHIS_MODULE,.openxxx_open,.writexxx_write,.releasexxx_release,};/*--------------------Misc设备--------------------*/staticstructmiscdevicexxx_miscdev{.minorXXX_MINOR,.nameXXX_NAME,.fopsxxx_fops,};/*--------------------probe--------------------*/staticintxxx_probe(structplatform_device*pdev){intret;/* 1. 获取设备树节点 */xxx.ndpdev-dev.of_node;/* 2. 获取GPIO */xxx.xxx_gpioof_get_named_gpio(xxx.nd,xxx-gpio,0);if(xxx.xxx_gpio0)return-EINVAL;/* 3. 申请GPIO */retgpio_request(xxx.xxx_gpio,xxx-gpio);if(ret)returnret;/* 4. 设置GPIO方向 */retgpio_direction_output(xxx.xxx_gpio,1);if(ret)gotofail_gpio;/* 5. 注册Misc设备 */retmisc_register(xxx_miscdev);if(ret)gotofail_gpio;printk(probe success!\n);return0;fail_gpio:gpio_free(xxx.xxx_gpio);returnret;}/*--------------------remove--------------------*/staticintxxx_remove(structplatform_device*pdev){gpio_set_value(xxx.xxx_gpio,1);gpio_free(xxx.xxx_gpio);misc_deregister(xxx_miscdev);printk(remove success!\n);return0;}/*--------------------设备树匹配表--------------------*/staticconststructof_device_idxxx_of_match[]{{.compatiblemanufacturer,xxx},{},};/*--------------------Platform Driver--------------------*/staticstructplatform_driverxxx_driver{.driver{.namexxx,.of_match_tablexxx_of_match,},.probexxx_probe,.removexxx_remove,};/*--------------------驱动入口--------------------*/staticint__initxxx_init(void){returnplatform_driver_register(xxx_driver);}/*--------------------驱动出口--------------------*/staticvoid__exitxxx_exit(void){platform_driver_unregister(xxx_driver);}module_init(xxx_init);module_exit(xxx_exit);MODULE_LICENSE(GPL);MODULE_AUTHOR(huangjiajing);6. probe() 初始化流程Platform 总线匹配成功后会自动调用probe()。整个初始化流程如下Platform匹配成功 │ ▼ probe() │ ├──① 获取设备树节点 ├──② 获取GPIO编号 ├──③ 申请GPIO资源 ├──④ 设置GPIO方向 ├──⑤ 注册Misc设备 │ ▼ 生成 /dev/xxx其中misc_register(xxx_miscdev);放在最后执行。原因是只有 GPIO 等硬件资源全部初始化完成后才允许用户访问/dev/xxx避免设备尚未初始化完成就被应用程序打开。因此 Linux 驱动遵循先初始化硬件再注册设备。7. remove() 流程驱动卸载时Linux 会自动调用remove()。主要完成以下工作remove() │ ├──关闭设备 ├──释放GPIO ├──注销Misc设备 └──释放资源对应代码gpio_set_value(xxx.xxx_gpio,1);gpio_free(xxx.xxx_gpio);misc_deregister(xxx_miscdev);8. 开发流程总结修改设备树 │ ▼ 添加 compatible │ ▼ 编写 file_operations │ ▼ 定义 miscdevice │ ▼ 编写 probe() │ ├──获取设备树 ├──获取GPIO ├──申请GPIO ├──配置GPIO └──misc_register() │ ▼ 编写 remove() │ ├──misc_deregister() └──gpio_free() │ ▼ 注册 Platform Driver │ ▼ Platform 自动匹配 │ ▼ 调用 probe() │ ▼ 生成 /dev/xxx9. 使用模板时需要修改的内容修改位置蜂鸣器LEDXXX_NAMEmiscbeepmiscledXXX_MINOR144145struct xxx_devbeep_gpioled_gpioGPIO 属性beep-gpioled-gpiocompatiblealientek,beepatkalpha,gpioledGPIO 控制逻辑控制蜂鸣器高低电平控制 LED 高低电平.namemiscbeepgpioled10. 普通字符设备与 Misc 对比普通字符设备Misc 杂项设备alloc_chrdev_region()misc_register()cdev_init()不需要cdev_add()不需要class_create()不需要device_create()不需要device_destroy()misc_deregister()class_destroy()不需要unregister_chrdev_region()不需要代码量较多代码量少开发效率高总结Misc 本质上仍然是字符设备只是 Linux 对字符设备注册流程进行了封装。对于 LED、蜂鸣器、按键、ADC 等简单外设优先使用 Misc 驱动可以减少大量重复代码提高开发效率。