字符设备如何分配设备号

前一篇对cdev结构体及初始化做了简单介绍

Linux内核有两个分配设备号的函数

 1 /**
 2  * register_chrdev_region() - register a range of device numbers
 3  * @from: the first in the desired range of device numbers; must include
 4  *        the major number.
 5  * @count: the number of consecutive device numbers required
 6  * @name: the name of the device or driver.
 7  *
 8  * Return value is zero on success, a negative error code on failure.
 9  */
10 int register_chrdev_region(dev_t from, unsigned count, const char *name)
11 {
12     struct char_device_struct *cd;
13     dev_t to = from + count;
14     dev_t n, next;
15
16     for (n = from; n < to; n = next) {
17         next = MKDEV(MAJOR(n)+1, 0);
18         if (next > to)
19             next = to;
20         cd = __register_chrdev_region(MAJOR(n), MINOR(n),
21                    next - n, name);
22         if (IS_ERR(cd))
23             goto fail;
24     }
25     return 0;
26 fail:
27     to = n;
28     for (n = from; n < to; n = next) {
29         next = MKDEV(MAJOR(n)+1, 0);
30         kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
31     }
32     return PTR_ERR(cd);
33 }

register_chrdev_region()

 1 /**
 2  * alloc_chrdev_region() - register a range of char device numbers
 3  * @dev: output parameter for first assigned number
 4  * @baseminor: first of the requested range of minor numbers
 5  * @count: the number of minor numbers required
 6  * @name: the name of the associated device or driver
 7  *
 8  * Allocates a range of char device numbers.  The major number will be
 9  * chosen dynamically, and returned (along with the first minor number)
10  * in @dev.  Returns zero or a negative error code.
11  */
12 int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
13             const char *name)
14 {
15     struct char_device_struct *cd;
16     cd = __register_chrdev_region(0, baseminor, count, name);
17     if (IS_ERR(cd))
18         return PTR_ERR(cd);
19     *dev = MKDEV(cd->major, cd->baseminor);
20     return 0;
21 }

alloc_chrdev_region()

1. 这两个函数最终都会调用__register_chrdev_region()函数。并且会用到一个重要的 struct char_device_struct结构体。

  1 #define CHRDEV_MAJOR_HASH_SIZE    255
  2 /*定义char_device_struct结构体并声明一个全局的指针数组*/
  3 static struct char_device_struct {
  4     struct char_device_struct *next;
  5     unsigned int major;
  6     unsigned int baseminor;
  7     int minorct;
  8     char name[64];
  9     struct cdev *cdev;        /* will die */
 10 } *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
 11 /*
 12  * Register a single major with a specified minor range.
 13  *
 14  * If major == 0 this functions will dynamically allocate a major and return
 15  * its number.
 16  *
 17  * If major > 0 this function will attempt to reserve the passed range of
 18  * minors and will return zero on success.
 19  *
 20  * Returns a -ve errno on failure.
 21  */
 22 static struct char_device_struct *
 23 __register_chrdev_region(unsigned int major, unsigned int baseminor,
 24                int minorct, const char *name)
 25 {
 26     struct char_device_struct *cd, **cp;
 27     int ret = 0;
 28     int i;
 29
 30     cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
 31     if (cd == NULL)
 32         return ERR_PTR(-ENOMEM);
 33
 34     mutex_lock(&chrdevs_lock);
 35
 36     /*--当调用alloc_chrdev_region时,传入的major为0,自动分配设备,
 37     *但是有一个缺点就是其分配的设备号只能在255内,而且并没有使用hash表,
 38     *从而大大减少了linux所支持的设备号数。
 39     */
 40     if (major == 0)
 41     {
 42         for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--)
 43         {
 44             if (chrdevs[i] == NULL)
 45                 break;
 46         }
 47
 48         if (i == 0)
 49         {
 50             ret = -EBUSY;
 51             goto out;
 52         }
 53         major = i;
 54         ret = major;
 55     }
 56
 57     cd->major = major;
 58     cd->baseminor = baseminor;
 59     cd->minorct = minorct;
 60     strlcpy(cd->name, name, sizeof(cd->name));
 61
 62     i = major_to_index(major);
 63
 64     for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
 65         if (
 66                     (*cp)->major > major       ||
 67
 68                     (
 69                             (*cp)->major == major    &&
 70                              (
 71                                      (*cp)->baseminor >= baseminor    ||
 72                                       (*cp)->baseminor + (*cp)->minorct > baseminor
 73                              )
 74                     )
 75            )
 76             break;
 77
 78     /* Check for overlapping minor ranges.  */
 79     if (*cp && (*cp)->major == major)
 80     {
 81         int old_min = (*cp)->baseminor;
 82         int old_max = (*cp)->baseminor + (*cp)->minorct - 1;
 83         int new_min = baseminor;
 84         int new_max = baseminor + minorct - 1;
 85
 86         /* New driver overlaps from the left.  */
 87         if (new_max >= old_min && new_max <= old_max) {
 88             ret = -EBUSY;
 89             goto out;
 90         }
 91
 92         /* New driver overlaps from the right.  */
 93         if (new_min <= old_max && new_min >= old_min) {
 94             ret = -EBUSY;
 95             goto out;
 96         }
 97     }
 98
 99     cd->next = *cp;
100     *cp = cd;
101     mutex_unlock(&chrdevs_lock);
102     return cd;
103 out:
104     mutex_unlock(&chrdevs_lock);
105     kfree(cd);
106     return ERR_PTR(ret);
107 }

2. 在分析函数前先参考关于hash表的知识

从上图我们可以发现哈希表是由数组+链表组成的,一个长度为16的数组中,每个元素存储的是一个链表的头结点。那么这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到。比如上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存储在数组下标为12的位置。

3. 分析如何指定分配设备号

时间: 2024-10-10 23:07:47

字符设备如何分配设备号的相关文章

linux字符设备-自动创建设备号和设备节点

Linux字符设备-自动创建设备号和设备节点 先写一个自动分配字符设备号和设备节点的例子及APP 手动安装步骤: Insmod my_char_dev.ko 不需要再安装设备节点 然后是测试app ./my_char_dev_app 1 1 #include <linux/module.h> 2 #include <linux/init.h> 3 #include <linux/io.h> 4 #include <linux/fs.h> 5 #include

【整理】--分配设备号register_chrdev_region()、alloc_chrdev_region() 和 register_chrdev()

(1) 分配设备编号,注册设备与注销设备的函数均在fs.h中声明,如下: extern int register_chrdev_region(dev_t,unsigned int,const char*);表示静态的申请和注册设备号 extern int alloc_chrdev_region(dev_t,unsigned int,const char*);表示动态的申请和注册设备号 extern int register_chrdev(unsigned int,const char*,stru

字符设备驱动、平台设备驱动、设备驱动模型、sysfs的关系

Linux驱动开发的童鞋们来膜拜吧:-)  学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关联的分析.对于开发者而言,能够熟悉某一点并分享出来已很难得,但对于专注传授技术和经验给

[kernel]字符设备驱动、平台设备驱动、设备驱动模型、sysfs几者之间的比较和关联

转自:http://www.2cto.com/kf/201510/444943.html Linux驱动开发经验总结,绝对干货! 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关

【原创】-- linux 字符设备,块设备,网络设备

参考地址:http://blog.chinaunix.net/uid-26322998-id-2981874.html 1.块设备 系统中能够随机(不需要按顺序)访问固定大小数据片(chunks)的设备被称作块设备,这些数据片就称作块.最常见的块设备是硬盘,除此以外,还有软盘驱动器.CD-ROM驱动器和闪存等等许多其他块设备.注意,它们都是以安装文件系统的方式使用的——这也是块设备一般的访问方式.一般访问单位为512k的整数倍. 2.字符设备 另一种基本的设备类型是字符设备.字符设备按照字符流的

驱动开发--【字符设备、块设备简介】【sky原创】

驱动开发   字符设备,块设备,网络设备 字符设备 以字节流的方式访问, 不能随机访问 有例外,显卡.EEPROM可以随机访问 EEPROM可以擦写1亿次,是一种字符设备,可以随机访问 读写是直接访问硬件的 flash 擦写次数有限,一百万次,容易有坏块 块设备 能随机访问 以”块“为单位进行访问 块大小一般为512字节 块的大小由硬件决定 是内核进行数据传输的基本单位 硬盘结构: 格式化分区是以柱面为单位的,即硬盘的柱面 如果有10个盘面,就有十个柱面 对于嵌入式设备 如果是flash的话,结

linux中的设备名称和设备号

看赵炯博士的<linux 0.11 源代码注释>已经两三周了,从今天起开始将一些个人总结和感悟分小标题写出来,聊作记忆以供后来查看.在linux0.11源码的 /linux/boot/bootsect.s中,有一个标号定义ROOT_DEV ! ROOT_DEV: 0x000 - same type of floppy as boot.! 0x301 - first partition on first drive etcROOT_DEV = 0x306 这里,ROOT_DEV是系统指定的根文件

Linux平台块设备到字符设备(裸设备)的三种映射方式(转载)

在Linux平台oracle rac的组建过程中,如果使用ASM+RAW的存储方式的话,由于asm不支持块设备,支持持字符访问设备,所以需要配置将Block Device Drive转变成Character Device Drive的访问方式.但是在Linux平台中,不像aix和HP-UX中,默认提供了块设备对应的字符设备文件,需要我们手工的将块设备映射为字符设备.在此,我们提供三种方式来讲块设备绑定到裸设备上,这三种方式创建裸设备的方式完全一样,区别在于对oracle用户的权限的处理方式不同,

KVM 介绍(4):I/O 设备直接分配和 SR-IOV [KVM PCI/PCIe Pass-Through SR-IOV]

学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分配和 SR-IOV (5)libvirt 介绍 (6)OpenStack 和 KVM 本文将分析 PCI/PCIe 设备直接分配(Pass-through)和 SR-IOV, 以及三种 I/O 虚拟化方式的比较. 1. PCI/PCI-E 设备直接分配给虚机 (PCI Pass-through) 设