|
@@ -59,6 +59,29 @@ void chrdev_show(struct seq_file *f, off_t offset)
|
|
|
|
|
|
#endif /* CONFIG_PROC_FS */
|
|
|
|
|
|
+static int find_dynamic_major(void)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ struct char_device_struct *cd;
|
|
|
+
|
|
|
+ for (i = ARRAY_SIZE(chrdevs)-1; i > CHRDEV_MAJOR_DYN_END; i--) {
|
|
|
+ if (chrdevs[i] == NULL)
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = CHRDEV_MAJOR_DYN_EXT_START;
|
|
|
+ i > CHRDEV_MAJOR_DYN_EXT_END; i--) {
|
|
|
+ for (cd = chrdevs[major_to_index(i)]; cd; cd = cd->next)
|
|
|
+ if (cd->major == i)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (cd == NULL || cd->major != i)
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -EBUSY;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Register a single major with a specified minor range.
|
|
|
*
|
|
@@ -84,22 +107,14 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
|
|
|
|
|
|
mutex_lock(&chrdevs_lock);
|
|
|
|
|
|
- /* temporary */
|
|
|
if (major == 0) {
|
|
|
- for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
|
|
|
- if (chrdevs[i] == NULL)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (i < CHRDEV_MAJOR_DYN_END)
|
|
|
- pr_warn("CHRDEV \"%s\" major number %d goes below the dynamic allocation range\n",
|
|
|
- name, i);
|
|
|
-
|
|
|
- if (i == 0) {
|
|
|
- ret = -EBUSY;
|
|
|
+ ret = find_dynamic_major();
|
|
|
+ if (ret < 0) {
|
|
|
+ pr_err("CHRDEV \"%s\" dynamic allocation region is full\n",
|
|
|
+ name);
|
|
|
goto out;
|
|
|
}
|
|
|
- major = i;
|
|
|
+ major = ret;
|
|
|
}
|
|
|
|
|
|
cd->major = major;
|