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 }
1 static struct char_device_struct *
2 __register_chrdev_region(unsigned int major, unsigned int baseminor,
3 int minorct, const char *name)
4 {
5 struct char_device_struct *cd, **cp;
6 int ret = 0;
7 int i;
8
9 cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
10 if (cd == NULL)
11 return ERR_PTR(-ENOMEM);
12
13 mutex_lock(&chrdevs_lock);
14
15 /* temporary */
16 if (major == 0) {
17 for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
18 if (chrdevs[i] == NULL)
19 break;
20 }
21
22 if (i == 0) {
23 ret = -EBUSY;
24 goto out;
25 }
26 major = i;
27 ret = major;
28 }
29
30 cd->major = major;
31 cd->baseminor = baseminor;
32 cd->minorct = minorct;
33 strlcpy(cd->name, name, sizeof(cd->name));
34
35 i = major_to_index(major);
36
37 for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
38 if ((*cp)->major > major ||
39 ((*cp)->major == major &&
40 (((*cp)->baseminor >= baseminor) ||
41 ((*cp)->baseminor + (*cp)->minorct > baseminor))))
42 break;
43
44 /* Check for overlapping minor ranges. */
45 if (*cp && (*cp)->major == major) {
46 int old_min = (*cp)->baseminor;
47 int old_max = (*cp)->baseminor + (*cp)->minorct - 1;
48 int new_min = baseminor;
49 int new_max = baseminor + minorct - 1;
50
51 /* New driver overlaps from the left. */
52 if (new_max >= old_min && new_max <= old_max) {
53 ret = -EBUSY;
54 goto out;
55 }
56
57 /* New driver overlaps from the right. */
58 if (new_min <= old_max && new_min >= old_min) {
59 ret = -EBUSY;
60 goto out;
61 }
62 }
63
64 cd->next = *cp;
65 *cp = cd;
66 mutex_unlock(&chrdevs_lock);
67 return cd;
68 out:
69 mutex_unlock(&chrdevs_lock);
70 kfree(cd);
71 return ERR_PTR(ret);
72 }