Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6cb4f4df authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

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: default avatarJohan Hovold <johan@kernel.org>
Acked-by: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 83ed07c5
Loading
Loading
Loading
Loading
+17 −21
Original line number Diff line number Diff line
@@ -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 @@ static int acm_probe(struct usb_interface *intf,
		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;