|
@@ -46,6 +46,7 @@
|
|
|
#include <linux/usb/cdc.h>
|
|
|
#include <asm/byteorder.h>
|
|
|
#include <asm/unaligned.h>
|
|
|
+#include <linux/idr.h>
|
|
|
#include <linux/list.h>
|
|
|
|
|
|
#include "cdc-acm.h"
|
|
@@ -56,27 +57,27 @@
|
|
|
|
|
|
static struct usb_driver acm_driver;
|
|
|
static struct tty_driver *acm_tty_driver;
|
|
|
-static struct acm *acm_table[ACM_TTY_MINORS];
|
|
|
|
|
|
-static DEFINE_MUTEX(acm_table_lock);
|
|
|
+static DEFINE_IDR(acm_minors);
|
|
|
+static DEFINE_MUTEX(acm_minors_lock);
|
|
|
|
|
|
static void acm_tty_set_termios(struct tty_struct *tty,
|
|
|
struct ktermios *termios_old);
|
|
|
|
|
|
/*
|
|
|
- * acm_table accessors
|
|
|
+ * acm_minors accessors
|
|
|
*/
|
|
|
|
|
|
/*
|
|
|
- * Look up an ACM structure by index. If found and not disconnected, increment
|
|
|
+ * Look up an ACM structure by minor. If found and not disconnected, increment
|
|
|
* its refcount and return it with its mutex held.
|
|
|
*/
|
|
|
-static struct acm *acm_get_by_index(unsigned index)
|
|
|
+static struct acm *acm_get_by_minor(unsigned int minor)
|
|
|
{
|
|
|
struct acm *acm;
|
|
|
|
|
|
- mutex_lock(&acm_table_lock);
|
|
|
- acm = acm_table[index];
|
|
|
+ mutex_lock(&acm_minors_lock);
|
|
|
+ acm = idr_find(&acm_minors, minor);
|
|
|
if (acm) {
|
|
|
mutex_lock(&acm->mutex);
|
|
|
if (acm->disconnected) {
|
|
@@ -87,7 +88,7 @@ static struct acm *acm_get_by_index(unsigned index)
|
|
|
mutex_unlock(&acm->mutex);
|
|
|
}
|
|
|
}
|
|
|
- mutex_unlock(&acm_table_lock);
|
|
|
+ mutex_unlock(&acm_minors_lock);
|
|
|
return acm;
|
|
|
}
|
|
|
|
|
@@ -98,14 +99,9 @@ static int acm_alloc_minor(struct acm *acm)
|
|
|
{
|
|
|
int minor;
|
|
|
|
|
|
- mutex_lock(&acm_table_lock);
|
|
|
- for (minor = 0; minor < ACM_TTY_MINORS; minor++) {
|
|
|
- if (!acm_table[minor]) {
|
|
|
- acm_table[minor] = acm;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- mutex_unlock(&acm_table_lock);
|
|
|
+ mutex_lock(&acm_minors_lock);
|
|
|
+ minor = idr_alloc(&acm_minors, acm, 0, ACM_TTY_MINORS, GFP_KERNEL);
|
|
|
+ mutex_unlock(&acm_minors_lock);
|
|
|
|
|
|
return minor;
|
|
|
}
|
|
@@ -113,9 +109,9 @@ static int acm_alloc_minor(struct acm *acm)
|
|
|
/* Release the minor number associated with 'acm'. */
|
|
|
static void acm_release_minor(struct acm *acm)
|
|
|
{
|
|
|
- mutex_lock(&acm_table_lock);
|
|
|
- acm_table[acm->minor] = NULL;
|
|
|
- mutex_unlock(&acm_table_lock);
|
|
|
+ mutex_lock(&acm_minors_lock);
|
|
|
+ idr_remove(&acm_minors, acm->minor);
|
|
|
+ mutex_unlock(&acm_minors_lock);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -497,7 +493,7 @@ static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
|
|
|
|
|
|
dev_dbg(tty->dev, "%s\n", __func__);
|
|
|
|
|
|
- acm = acm_get_by_index(tty->index);
|
|
|
+ acm = acm_get_by_minor(tty->index);
|
|
|
if (!acm)
|
|
|
return -ENODEV;
|
|
|
|
|
@@ -1316,7 +1312,7 @@ made_compressed_probe:
|
|
|
goto alloc_fail;
|
|
|
|
|
|
minor = acm_alloc_minor(acm);
|
|
|
- if (minor == ACM_TTY_MINORS) {
|
|
|
+ if (minor < 0) {
|
|
|
dev_err(&intf->dev, "no more free acm devices\n");
|
|
|
kfree(acm);
|
|
|
return -ENODEV;
|