1
0
Fork 0

USB: cdc-acm: use idr to manage minor numbers

Use the idr-interface rather than a static table to manage minor-number
allocations.

This allows us to easily switch over to fully dynamic minor allocations
when the TTY-layer can handle that.

Signed-off-by: Johan Hovold <johan@kernel.org>
Acked-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
hifive-unleashed-5.1
Johan Hovold 2015-05-18 17:34:11 +02:00 committed by Greg Kroah-Hartman
parent 83ed07c5db
commit 6cb4f4df68
1 changed files with 17 additions and 21 deletions

View File

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