嵌入式Linux(3):设备驱动--杂项驱动(MISC)
简介
Linux三大设备驱动:
- 字符设备:IO的传输过程是以字符为单位的,没有缓冲。比如I2C,SPI都是字符设备。
- 块设备:IO的传输过程是以块为单位的。跟存储相关的都属于块设备驱动。比如:TF卡,NAND flash等。
- 网络设备:与前两个不一样,这个是以socket套接字来访问的。
杂项设备属于字符设备的一种。
杂项设备会自动生成字符节点。我们的系统里面有很多杂项设备,可以通过输入cat /proc/misc
命令来查看。
杂项设备除了比字符设备代码简单,还有别的区别吗?
- 杂项设备的主设备号是相同的,均为10,次设备号是不同的,主设备号相同就可以节省内核的资源。
- 设备号包含了主设备和次设备号,主设备号在Linux系统里面是唯一的,次设备号不一定唯一。设备号是计算机识别设备的一种方式,主设备号相同的就被视为同一类设备。
- 可以通过命令
cat /proc/devices
来查看主设备号。
杂项设备的描述
杂项设备的描述在内核源码中的:include/linux/miscdevice.h
结构体:
struct miscdevice{int minor; // 次设备号const char* name; // 设备节点的名字const struct file_operations *fops; // 文件操作集struct list_head list;struct device *parent;struct device *this_device;const struct attribute_group **groups;const char* nodename;umode_t mode;
};
文件操作集的描述在:include/linux/fs.h
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 (*read_iter) (struct kiocb *, struct iov_iter *);ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);int (*iopoll)(struct kiocb *kiocb, bool spin);int (*iterate) (struct file *, struct dir_context *);int (*iterate_shared) (struct file *, struct dir_context *);__poll_t (*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 *);unsigned long mmap_supported_flags;int (*open) (struct inode *, struct file *);int (*flush) (struct file *, fl_owner_t id);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, loff_t, loff_t, 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 *);ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);int (*setlease)(struct file *, long, struct file_lock **, void **);long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMUunsigned (*mmap_capabilities)(struct file *);
#endifssize_t (*copy_file_range)(struct file *, loff_t, struct file *,loff_t, size_t, unsigned int);loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,struct file *file_out, loff_t pos_out,loff_t len, unsigned int remap_flags);int (*fadvise)(struct file *, loff_t, loff_t, int);
} __randomize_layout;
里面的一个结构体成员都对应一个调用。
extern int misc_register(struct miscdevice *misc); // 注册杂项设备extern int misc_deregister(struct miscdevice *misc); // 注销杂项设备
注册杂项设备
- (1)填充miscdevice这个结构体
- (2)填充file_operations这个结构体
- (3)注册杂项设备并生成设备节点
模板:
struct const file_operations xx_fops = {.owner = THIS_MODULE,
};
struct miscdevice xx_dev = {.minor = MISC_DYNAMIC_MINOR,.name = "xxx",.fops = xx_fops
}static int xxx_init(void)
{int ret;ret = misc_register(&xx_dev);if(ret < 0){printk("misc register error!\\n");return -1;}return 0;
}
static void xxx_exit(void)
{misc_deregister(&xx_dev);
}
编写一个杂项设备
include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>struct file_operations misc_fops = {.owner = THIS_MODULE
};struct miscdevice misc_dev = {.minor = MISC_DYNAMIC_MINOR,.name = "hello_misc",.fops = &misc_fops
};static int misc_init(void)
{int ret ;ret = misc_register(&misc_dev);if(ret < 0){printk("misc registe is error\\n");return -1;}printk("misc registe is ok\\n");return 0;
}static void misc_exit(void)
{misc_deregister(&misc_dev);printk("Bye Misc\\n");
}module_init(misc_init);
module_exit(misc_exit);/* 模块声明 */
MODULE_LICENSE("GPL");
Makefile
# 定义内核源码的目录
KERN_DIR ?=/home/liefyuan/Liefyuan/bingpi-v3s/linux-zero-5.2.y
# 定义当前目录
PWD :=$(shell pwd)
# 要生成的内核模块
obj-m +=misc_dev.oall:make -C $(KERN_DIR) M=$(PWD) modulesclean:rm -rf *.order *o *.symvers *.mod.c *.mod *.ko
编译:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j1
安装模块测试:
# insmod misc_dev.ko
[ 7242.641949] misc_dev: loading out-of-tree module taints kernel.
[ 7242.649182] misc registe is ok
# ls /dev
bus ptyvc ttydb
console ptyvd ttydc
cpu_dma_latency ptyve ttydd
fb0 ptyvf ttyde
fd ptyw0 ttydf
full ptyw1 ttye0
gpiochip0 ptyw2 ttye1
hello_misc ptyw3 ttye2
i2c-0 ptyw4 ttye3
kmsg ptyw5 ttye4
log ptyw6 ttye5
如上已经出现了hello_misc节点
# rmmod misc_dev
[ 7383.397375] Bye Misc