块设备注册 register_blkdev

 先看一下函数的实现:
  1. int register_blkdev(unsigned int major, const char *name)  
  2. {  
  3.   
  4.         //传入的参数是要注册的主设备号和设备名称  
  5.     struct blk_major_name **n, *p;  
  6.     int index, ret = 0;  
  7.   
  8.     mutex_lock(&block_subsys_lock);  
  9.   
  10.     /* temporary */  
  11.         //检查传入的主设备号是否为0,如果为0怎么办?  
  12.         //很明显,如果为0的话内核会自动去major_name这个指针数组中为你分配一个主设备号,至于major_name,如果你不是很了解的话,就先跳到后面去看一下吧。  
  13.         //但是,如果已经没有空闲的设备号的话,就会错误返回了  
  14.     if (major == 0) {  
  15.                 for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {  
  16.             if (major_names[index] == NULL)  
  17.                 break;  
  18.         }  
  19.   
  20.         if (index == 0) {  
  21.             printk("register_blkdev: failed to get major for %s\n",  
  22.                    name);  
  23.             ret = -EBUSY;  
  24.             goto out;  
  25.         }  
  26.         major = index;  
  27.         ret = major;  
  28.     }  
  29.   
  30.   
  31.         //如果主设备号不为0 ,我们就可以申请一个struct blk_major_name的结构体,并将它初始化,主要是将设备号和设备名称存储到这个结构体中  
  32.     p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);  
  33.     if (p == NULL) {  
  34.         ret = -ENOMEM;  
  35.         goto out;  
  36.     }  
  37.   
  38.     p->major = major;  
  39.     strlcpy(p->name, name, sizeof(p->name));  
  40.     p->next = NULL;  
  41.   
  42.         //这个函数是做模运算用来得到一个索引值(0-255),也许你要问了,如果我的主设备号大于255,是不是会将major_names指针数组中的元素覆盖掉?  
  43.         //我可以很负责的告诉你,你的担心是多余的。让我们看看下面的for循环你就明白了。我们假定主设备号是288好了,那么index = 288%255,就是33。  
  44.     index = major_to_index(major);  
  45.   
  46.   
  47.         //内核首先拿到索引值为33的元素,用*n判断此元素是否为空,如果为空,直接跳出for循环,将上面开辟的结构体赋值给*n好了,这样就将设备的信息注册到了全局        //数组中去了  
  48.         //如果此元素不为空,也就是已经有一个设备注册到这了,怎么办?那内核就会去比较已经注册的主设备号与我们将要注册的主设备号是否一致,如果一致,内核就会提示我们该设备号已经被占用了。如果不一致呢?记不记得刚才看过一个next指针,这个指针是指向下一个设备的结构体,直到找到一个空的结构体,并将前面申请的结构体进行赋值。  
  49.     for (n = &major_names[index]; *n; n = &(*n)->next) {  
  50.         if ((*n)->major == major)  
  51.             break;  
  52.     }  
  53.     if (!*n)  
  54.         *n = p;  
  55.     else  
  56.         ret = -EBUSY;  
  57.   
  58.     if (ret < 0) {  
  59.         printk("register_blkdev: cannot get major %d for %s\n",  
  60.                major, name);  
  61.         kfree(p);  
  62.     }  
  63. out:  
  64.     mutex_unlock(&block_subsys_lock);  
  65.     return ret;  
  66. }  

       major_name数组:

  1. static struct blk_major_name {  
  2.     struct blk_major_name *next;  
  3.     int major;  
  4.     char name[16];  
  5. } *major_names[BLKDEV_MAJOR_HASH_SIZE];  

其中BLKDEV_MAJOR_HASH_SIZE = 255.相信你一看就明白了,这是一个指针数组,其中的每一个元素都指向了一个 struct blk_major_name的结构体,该结构体就是用来存放设备的主设备号和设备名称的,至于struct blk_major_name *next这个指针,一会再看吧。现在可以回去继续看代码了。

      总结:

       1、注册块设备时,可以把0当做主设备号传入,从而让内核自动分配一个主设备号。但是,不提倡这么做!!

       2、块设备的主设备号理论上有2^32个,而不是必须小于255。

       3、通过此函数注册后,可以在/proc/devices下看到(cat /proc/device)。

       4、major_names数组(数组中的每个元素都是一个指针)可能的最终构成如图: