咱就浅谈一下字符设备驱动的内部实现~
1、当我们在应用程序中使用open打开文件的时候,会自动在/dev/mycdev下生成一个inode号。
2、只要文件存在于系统中,在系统内核就会存在一个inode结构体,里面存储文件的一些相关信息,其中信息之一有设备号,设备号是设备驱动的唯一标识,inode结构体中的共用体里边保存有一些块设备、字符设备等等信息。
3、其中字符设备也是一个结构体类型,struct cdev类型的对象用于描述一个字符设备的驱动,注册驱动的本质就是分配一个cdev的空间并初始化,然后通知内核。
4、struct cdev结构体中包含了操作方法结构体,在操作方法结构体里边定义我们要打开open、读read、写write、关闭close的函数指针。
从而实现应用程序访问驱动的过程。
***********************************************分界线*******************************************************
注册注销一个字符设备驱动的步骤:
- 分配一个struct cdev空间(驱动对象)
- 初始化驱动对象
- 注册驱动对象
- 注销
实现过程用到的API:
***********注册流程********************
1.为驱动对象申请空间
a:struct cdev cdev;//这种方法不是自己申请的,不知道什么时候空间能释放,用起来不灵活
b.//struct cdev *cdev_alloc(void);
//功能:申请一个字符对象空间
//参数:无
//返回值:成功返回对象空间首地址,失败返回NULL
struct cdev*cdev=cdev_alloc();
2.对象的初始化
void cdev_init(struct cdev *cdev, const struct file_operations *ops);
功能:实现字符设备驱动对象的部分初始化
参数:
cdev:字符设备驱动对象指针
ops:操作方法结构体指针
返回值:无
3.申请设备号
a.int register_chrdev_region(dev_t from, unsigned count, const char *name)
功能:静态指定设备号(不常用,因为一次申请256个,用不了那么多会造成资源浪费)
参数:
from:申请第一个设备的设备号
count:申请的设备资源数量
name:设备名或者驱动名
返回值:成功返回0,失败返回错误码
b.int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name)
功能:动态申请设备号
参数:
dev:存放设备号的变量指针
baseminor:次设备号的起始值
count:设备资源数量
name:设备名或者驱动名
返回值:成功返回0,失败返回错误码
4.注册驱动对象
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
功能:实现驱动对象的注册
参数:
p:字符设备驱动对象指针
dev:申请得到的设备号
count:申请的设备数量
返回值:成功返回0,失败返回错误码
**********注销流程*******************
1.注销驱动对象
void cdev_del(struct cdev *cdev)
参数:
cdev:要注销的驱动对象指针
返回值:无
2.释放设备号
void unregister_chrdev_region(dev_t from, unsigned count)
功能:释放设备号
参数:
from:第一个设备的设备号
count:设备资源的数量
返回值:无
3.static void kfree(void *p)
功能:释放kmalloc申请的空间
参数:
p:要释放的空间首地址
返回值:无