first 要分配的设备编号范围的起始值,次设备号经常为0
unsigned int
主设备号和次设备号
32位的dev_t类型(<linux/types.h>),内核用于保存设备编号。
(dev_t)-->主设备号、次设备号 | MAJOR(dev_t dev) |
主设备号、次设备号-->(dev_t) | MKDEV(int major,int minor) |
分配设备号的两种方法
①自行指定设备编号。由<linux/fs.h>声明的register_chrdev_region函数实现。
int register_chrdev_region(dev_t first, unsigned int count, char *name);
dev_t first 要分配的设备编号范围的起始值,次设备号经常为0
unsigned int cout 表示所请求的连续设备编号的个数(次设备)
char *name 与该编号范围关联设备名 (/dev)
②动态分配,由内核自动分配。由<linux/fs.h>声明的alloc_chrdev_region函数实现。
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
dev_t *dev 自动分配的设备号
unsigned int firstminor 要使用的被请求的第一个次设备号
释放设备的同一种方法
由<linux/fs.h>声明的unregister_chrdev_region函数实现
void unregister_chrdev_region(dev_t first, unsigned int count);
实现字符驱动程序的结构体
cdev结构体
<pre name="code" class="html">struct cdev {
<span style="white-space:pre"> </span>struct kobject kobj; //内嵌的kobject对象
<span style="white-space:pre"> </span>struct module *owner; //所属模块
<span style="white-space:pre"> </span>const struct file_operations *ops; //文件操作结构体,在写驱动时,其结构体内的大部分函数要被实现
<span style="white-space:pre"> </span>struct list_head list;
<span style="white-space:pre"> </span>dev_t dev; //设备号
<span style="white-space:pre"> </span>unsigned int count; };
linux内核提供的用于操作cdev的函数
void cdev_init(struct cdev *cdev,struct file_operations *fops);//初始化已分配的cdev结构,并建立cdev和file_operation之间的连接
struct cdev *cdev_alloc(void)//动态申请一个cdev内存
int cdev_add(struct cdev *dev, dev_t num, unsigned count); //向内核注册设备,通常发生在驱动模块的加载函数中
void cdev_del(struct cdev *cdev);//注销设备,通常发生在驱动模块的卸载函数中
file_operations结构体(在include/linux/fs.h)
主要成员:
struct module *owner:指向模块自身:THIS_MODULE
open read release write ioctl llseek mmap
file结构体
inode结构体
内核用inode结构在内部表示文件
dev_t i_rdev:对表示设备文件的inode结构,该字段包含了正真的设备编号
从inode中获得设备号的函数:
主:unsigned int iminor(struct inode *inode)
次:unsigned int imajor(struct inode *inode)
设备的注册与注销
在这里就是运用之前的cdev结构和内核提供用于操作cdev的函数。