Linux驱动中把无法归类的五花八门的设备定义为混杂设备(用miscdevice结构体表述)。miscdevice共享一个主设备号MISC_MAJOR(即10),但次设备号不同。 所有的miscdevice设备形成了一个链表,对设备访问时内核根据次设备号查找对应的miscdevice设备,然后调用其file_operations结构中注册的文件操作接口进行操作。 在内核中用struct miscdevice表示miscdevice设备,然后调用其file_operations结构中注册的文件操作接口进行操作。miscdevice的API实现在drivers/char/misc.c中。
混杂项设备驱动的程序组织架构:
新建一个first_led.c,先可能用到的头文件都引用上吧!
#include
#include
#include
//对应着相应机器平台的头文件 #include
#include
//给自己设备驱动定义一个名字
#define DEVICE_NAME \
名字有了,但样子是怎样的呢?现在就开始定义一个“样子”!
如果一个字符设备驱动要驱动多个设备,那么它就不应该用misc设备来实现。
通常情况下,一个字符设备都不得不在初始化的过程中进行下面的步骤:
通过alloc_chrdev_region()分配主次设备号。
使用cdev_init()和cdev_add()来以一个字符设备注册自己。
而一个misc驱动,则可以只用一个调用misc_register()
来完成这所有的步骤。(所以miscdevice是一种特殊的chrdev字符设备驱动) 所有的miscdevice设备形成一个链表,对设备访问时,内核根据次设备号查找 对应的miscdevice设备,然后调用其file_operations中注册的文件操作方法进行操作。
在Linux内核中,使用struct miscdevice来表示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; };
minor是这个混杂设备的次设备号,若由系统自动配置,则可以设置为 MISC_DYNANIC_MINOR,name是设备名
为了容易理解,我们先打大概的“样子”做好。只做minor、name、fops; 定义一个myfirst_led_dev设备:
static struct miscdevice myfirst_led_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &myfirst_led_dev_fops, };
Minor name 都已经定义好了。那么接下来实现一下myfirst_led_dev_fops方法。
内核中关于file_operations的结构体如下: struct file_operations { struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);