一、设备编号概念
在内核中,dev_t类型用来保存设备编号。
dev_t是一个32位的数,其中12位用来表示主设备号,20位用来表示此设备号。
1.获得主设备号或此设备号
MAJOR(dev_t dev); //主设备号
MINOR(dev_t dev); //次设备号
2.将设备号转换成dev_t类型
MKDEV(int major, int minor);
二、申请设备号
1.静态申请
int register_chrdev_region(dev_t first, unsigned int count, char *name);
1.first 是要分配的设备编号范围的起始值。
2.count 是所请求的连续设备编号的个数。
3.name 是驱动名称。
int register_chrdev_region(dev_t from, unsigned count, const char *name)
{
struct char_device_struct *cd; //定义一个struct char_device_struct类型的结构体。
dev_t to = from + count; //to为总设备号(主设备号+次设备号)。
dev_t n, next;
for (n = from; n < to; n = next) { //循环的每个状态为设备号,并且循环开始的第一个设备号为from
next = MKDEV(MAJOR(n)+1, 0); //下一个设备号状态=(当前主设备号+1,次设备号)的组合
if (next > to) //判断下一状态是否大于最后的末状态
next = to; //若是,则末状态变为下一状态。
cd = __register_chrdev_region(MAJOR(n), MINOR(n),next - n, name); //申请设备号,参数1为主设备号,参数2位次设备号,参数3位设备名称
if (IS_ERR(cd)) //若失败,则跳转
goto fail;
}
return 0;
fail:
to = n;
for (n = from; n < to; n = next) {
next = MKDEV(MAJOR(n)+1, 0);
kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); //销毁申请的设备号
}
return PTR_ERR(cd);
}
struct char_device_struct类型的结构体
static struct char_device_struct {
struct char_device_struct *next;/*指向下一个此类型的指针*/
unsigned int major;/*主设备号*/
unsigned int baseminor;/*次设备号*/
int minorct; /*申请设备号的个数*/
char name[64];/*驱动名称*/
struct cdev *cdev;/* 字符驱动结构体 */
}
2.动态申请
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
1.dev是仅用于输出的参数,在成功完成调用后将保存已分配的范围的第一个编号。
2.firstminor是要使用的被请求的第一个次设备号,通常为0;
3.count是设备个数
4.name是驱动名称
具体用法:
//定义全局变量(主次设备号初始化)
int scull_major = 0;
int scull_minor = 0;
int scull_init_module(void)
{
int result;
dev_t dev = 0;//在linux中是unsigned int 类型,32位,用于在驱动程序中定义设备编号,高12位为主设备号,低20位为次设备号
result=alloc_chrdev_region(&dev,scull_minor,1,"name");
scull_major=MAJOR(dev);
}
三、释放设备号
void unregister_chrdev_region(dev_t first, unsigned int count);
//eg:
unregister_chrdev_region(dev,1);
四、字符设备相关API
1.初始化已经分配到的结构
void cdev_init(struct cdev *cdev,struct file_operations *fops);
2.添加设备
int cdev_add(struct cdev *dev,dev_t num,unsigned int count);
3.移除
void cdev_del(struct cdev *dev);
五、将驱动程序连接到设备号上
利用file_operations结果来建立连接。
file_operations结构或指向这类结构的指针称为fops。这个结构体的每一个字段都必须指向驱动程序中实现特定操作的函数,对于不支持的操作,对于字段可置为0.
struct file_operations scull_fops = {
.owner = THIS_MODULE ,
.llseek = secull_llseek,
.read = scull_read ,
.write = scull_write ,
.ioctl = scull_ioctl,
.open = scull_open ,
.release = scull_release ,
};
//定义全局变量(主次设备号初始化)
int scull_major = 0;
int scull_minor = 0;
struct cdev cdev;
int scull_init_module(void)
{
int result;
dev_t dev = 0;//在linux中是unsigned int 类型,32位,用于在驱动程序中定义设备编号,高12位为主设备号,低20位为次设备号
result=alloc_chrdev_region(&dev,scull_minor,1,"name"); //动态创建字符设备
scull_major=MAJOR(dev);
//通过 cdev_init( ) 建立cdev与 file_operations之间的连接,通过 cdev_add( ) 向系统添加一个cdev以完成注册;
cdev_init(&cdev,&scull_fops);//用上面声明的scull_fops初始化cdev
cdev.owner = THIS_MODULE;
cdev.ops = &scull_fops;
restult=cdev_add(&cdev,dev,1); //创建设备;
if(result){
printf("error\n");
unregister_chrdev_region(dev,1);
return result;
}
}