目录
0.前言
分享一句话:大事随心,小事随脑。
1.字符设备
Linux有三种驱动设备模型,字符设备、块设备、网络设备。
字符设备是面向字节流的。定义:是指只能一个字节一个字节的读写的设备,不能随机的读取设备中的某一段数据。
常见的字符设备:鼠标 键盘 串口 。。。
1.1字符设备驱动框架
init:
{
申请设备号(静态申请 动态申请)
创建字符设备
初始化字符设备
将设备号和字符设备关联
}
exit:
{
销毁字符设备
删除申请的设备号
}
设备号:是一个32bits位的无符号数,高12位是主设备号,低20位是次设备号。
主设备号标识设备对应的驱动程序,告诉Linux内核使用哪一个驱动程序为该设备(也就是/dev下的设备文件)服务。
次设备号则用来标识具体且唯一的某个设备。
2.步骤
2.1申请设备号
我以动态申请为例。
函数:alloc_chrdev_region
查看内核代码。
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
参数:
*dev:设备号指针
baseminor:子设备的第一个编号
count:子设备个数
*name:设备名称
返回值:成功为0
2.2创建字符设备
函数:cdev_alloc
(我用的是source insight看的内核代码)
struct cdev *cdev_alloc(void)
{
struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
if (p) {
INIT_LIST_HEAD(&p->list);
kobject_init(&p->kobj, &ktype_cdev_dynamic);
}
return p;
}
无入参
返回值:指向字符设备结构体的指针
在linux内核中,struct cdev用来描述一个字符设备。再来看一下这个struct cdev。
struct cdev {
struct kobject kobj; //内嵌的内核对象
struct module *owner; //该字符设备所在的内核模块的对象指针
const struct file_operations *ops; //该结构描述了字符设备所能实现的所有方法
struct list_head list; //用来将已向内核注册的所有的字符设备形成链表
dev_t dev; //设备号,由主设备和次设备构成
unsigned int count; //隶属于同一个主设备号的次设备个数
};
所以我们要搞一个struct cdev指针接收,这是后话。
2.3初始化字符设备
函数:cdev_init
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;
}
参数:
*cdev:被初始化的字符设备指针
*fops:字符设备操作函数指针集
无返回值
看下这个