基本概念
驱动
driver
开发(个人理解)👇设备
device
(==对象==objcet
)- 设备号(住址号):区域
region
;(家庭住址,唯一性) - 注册设备(属性(名字
name
)+行为/操作operations
):name
|open
relaase
read
write
- 设备号(住址号):区域
👇设备节点
Node
(==类==class
)👆内核
kernel
有创建
create
就有销毁destory
字符设备
字符==设备号==的申请
设备号类型
dev_t
(无符号的 32 位整形类型unsigned int
:高12位表示主设备号,低20位表示次设备号)1
2
3
4
5
6/* kernel/include/linux/types.h */
typedef u32 __kernel_dev_t;
typedef __kernel_dev_t dev_t;
/* kernel/include/uapi/asm-generic/int-ll64.h */
typedef unsigned int __u32;1
2
3
4
5
6
7//API
/* kernel/include/linux/kdev_t.h */静态申请
1
2
3/* kernel/include/linux/fs.h */
//int register_chrdev_region(设备号, 设备数量, 设备名称)
int register_chrdev_region(dev_t from, unsigned count, const char *name);动态申请
1
2
3/* kernel/include/linux/fs.h */
//int alloc_chrdev_region(设备号(数组形式), 次设备号可申请最小值, 设备数量, 设备名称)
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
字符==设备==的注册与注销
字符设备
cdev
1
2
3
4
5
6
7
8
9
10
11/* kernel/include/linux/cdev.h */
struct cdev {
struct kobject kobj; //内嵌的内核对象.
struct module *owner; //该字符设备所在的内核模块的对象指针.
const struct file_operations *ops; //该结构描述了字符设备所能实现的方法,是极为关键的一个结构体.
struct list_head list; //用来将已经向内核注册的所有字符设备形成链表.
dev_t dev; //字符设备的设备号,由主设备号和次设备号构成.
unsigned int count; //隶属于同一主设备号的次设备号的个数.
};初始化
init
1
2
3/* kernel/include/linux/cdev.h */
//void cdev_init(字符设备/结构体/对象, 操作/结构体/行为)
void cdev_init(struct cdev *cdev, const struct file_operations *fops);添加
add
1
2
3/* kernel/include/linux/cdev.h */
//int cdev_add(字符设备/结构体/对象, 设备号, 设备数量)
int cdev_add(struct cdev *p, dev_t dev, unsigned count)删除
del
1
2
3/* kernel/include/linux/fs.h */
//void cdev_del(字符设备/结构体/对象)
void cdev_del(struct cdev *p)
字符设备的==操作==
文件操作集
file_operations
1
2
3
4
5
6
7
8/* kernel/include/linux/cdev.h */
static struct file_operations cdev_fops_test = {
.owner = THIS_MODULE, //将 owner 字段指向本模块,可以避免在模块的操作正在被使用时卸载该模块
.open = chrdev_open, //将 open 字段指向 chrdev_open(...)函数
.read = chrdev_read, //将 read 字段指向 chrdev_read(...)函数
.write = chrdev_write, //将 write 字段指向 chrdev_write(...)函数
.release = chrdev_release, //将 release 字段指向 chrdev_release(...)函数
}; //定义 file_operations 结构体类型的变量 cdev_test_ops操作函数(为应用层操作函数提供接口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22static int chrdev_open(struct inode *inode, struct file *file)
{
printk("This is chrdev_open \n");
return 0;
}
static ssize_t chrdev_read(struct file *file,char __user *buf, size_t size, loff_t *off)
{
printk("This is chrdev_read \n");
return 0;
}
static ssize_t chrdev_write(struct file *file,const char __user *buf,size_t size,loff_t *off)
{
printk("This is chrdev_write \n");
return 0;
}
static int chrdev_release(struct inode *inode, struct file *file)
{
return 0;
}
设备节点
节点创建
手动创建
1
2
3mknod 节点名称 设备类型 主设备号 从设备号
mknod NAME TYPE MAJOR MINOR
mknod /dev/device_test c 234 0自动创建
1
2
3/* kernel/include/linux/device/class.h */
//class_create(节点/结构体/类, 节点名称)
节点销毁
销毁
1
2
3/* kernel/include/linux/device/class.h */
//void class_destroy(节点/结构体/类)
void class_destroy(struct class *cls);
设备与节点
设备:字符设备、块设备、网络设备
节点:类
关联
设备创建
1
2
3/* kernel/include/linux/device.h */
//device_create(节点/结构体/类, 该设备的父设备或NULL, 设备号, 被添加到该设备回调的数据或NULL, 设备节点名称)
device_create( (struct class *cls, struct device *parent, dev_t devt,void *drvdata, const char *fmt);设备销毁
1
2
3/* kernel/include/linux/device.h */
//device_create(节点/结构体/类, 设备号)
void device_destroy(struct class *cls, dev_t devt);
模板记住
字符驱动(记住顺序)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/* 头文件 */
/* 1.定义字符设备结构体变量-对象 */
/* 2.定义设备号-家庭住址/唯一标识ID */
/* 3.定义file_operations结构体类型变量-操作 */
/* 1.定义设备节点-类 */
/* 4.实现file_operations中的操作函数集-请在3之前声明/放在3之前 */
/* 5.模块加载 */
/* 5.模块卸载 */
/* 参数传入(可选) */
/* 符号导出(可选) */
/* 开源协议(可选) */
/* 作者信息(可选) */杂项驱动
- 固定主设备号10
- 无需设置设备节点