《驱动学习 —— 杂项设备》
1.杂项设备
杂项设备,本质上就是字符设备驱动,只不过是一个特殊一点的。杂项设备的主设备号,被固定在 10,通过次设备号进行区分设备。杂项设备注册之后,在 /dev/ 目录下就有 name 设备节点,在 /sys/clas/misc 下面,也会自动生成的类信息,因此,一定程度上,比标准的的字符设备驱动简单了。
2.杂项设备的注册与注销
注册:
int misc_register(struct miscdevice * misc)
注销:
int misc_deregister(struct miscdevice *misc)
可以看到,基本就是围绕着miscdevice结构体。
struct miscdevice { int minor; const char *name; // 名字 const struct file_operations *fops; // 文件操作结构体 struct list_head list; struct device *parent; struct device *this_device; const char *nodename; mode_t mode; };
结构体中,name 是注册的名字,以后将会在 /dev 目录下,进行显示的 name,里面最主要的是 struct file_operations ,在注册杂项设备的时候,字符设备的结构体与杂项设备进行绑定, minor 为 MISC_DYNAMIC_MINOR 的时候,miscdevice 核心层会自动寻找一个空闲的次设备号。
3.杂项设备驱动编写流程
struct const file_operations xxxx_fops = { .unlock_ioctl = xxx_ioctl, xxxx }; struct miscdevice xxx_dev = { .minor = MISC_DYNAMIC_MINOR, .name = “xxx”, .fops = xxxx_fops }; static int __init xxx_init() { return misc_register(&xxx_dev ); } void __exit xxx_exit() { return misc_deregister(&xxx_dev) ; }
当调用 misc_register(&xxx_dev ); 的时候,会在 misc_open 的帮助下,实现将 xxx_dev 成为 file 的private_data,也就是 系统会帮助我们实现 file->private_data = xxx_dev。
4.实例
#include <linux/init.h> #include <linux/module.h> /*驱动注册的头文件,包含驱动的结构体和注册和卸载的函数*/ #include <linux/platform_device.h> /*注册杂项设备头文件*/ #include <linux/miscdevice.h> /*注册设备节点的文件结构体*/ #include <linux/fs.h> #define DRIVER_NAME "hello_ctl" #define DEVICE_NAME "hello_ctl123" MODULE_LICENSE("Dual BSD/GPL"); static long hello_ioctl( struct file *files, unsigned int cmd, unsigned long arg){ printk("cmd is %d,arg is %d\n",cmd,arg); return 0; } static int hello_release(struct inode *inode, struct file *file){ printk(KERN_EMERG "hello release\n"); return 0; } static int hello_open(struct inode *inode, struct file *file){ printk(KERN_EMERG "hello open\n"); return 0; } static struct file_operations hello_ops = { .owner = THIS_MODULE, .open = hello_open, .release = hello_release, .unlocked_ioctl = hello_ioctl, }; static struct miscdevice hello_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &hello_ops, }; static int hello_probe(struct platform_device *pdv){ printk(KERN_EMERG "\tinitialized\n"); misc_register(&hello_dev); return 0; } static int hello_remove(struct platform_device *pdv){ printk(KERN_EMERG "\tremove\n"); misc_deregister(&hello_dev); return 0; } static void hello_shutdown(struct platform_device *pdv){ ; } static int hello_suspend(struct platform_device *pdv,pm_message_t pmt){ return 0; } static int hello_resume(struct platform_device *pdv){ return 0; } struct platform_driver hello_driver = { .probe = hello_probe, .remove = hello_remove, .shutdown = hello_shutdown, .suspend = hello_suspend, .resume = hello_resume, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, } }; static int hello_init(void) { int DriverState; printk(KERN_EMERG "HELLO WORLD enter!\n"); DriverState = platform_driver_register(&hello_driver); printk(KERN_EMERG "\tDriverState is %d\n",DriverState); return 0; } static void hello_exit(void) { printk(KERN_EMERG "HELLO WORLD exit!\n"); platform_driver_unregister(&hello_driver); } module_init(hello_init); module_exit(hello_exit);
https://www.cnblogs.com/qxj511/p/5514271.html