> 文章列表 > 嵌入式Linux(3):设备驱动--杂项驱动(MISC)

嵌入式Linux(3):设备驱动--杂项驱动(MISC)

嵌入式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