[media] media: lirc_dev: use an IDA instead of an array to keep track of registered devices

Using the kernel-provided IDA simplifies the code and makes it possible
to remove the lirc_dev_lock mutex.

Signed-off-by: David Härdeman <david@hardeman.nu>
Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index c83fffe..a2c5ed0 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -24,6 +24,7 @@
 #include <linux/mutex.h>
 #include <linux/device.h>
 #include <linux/cdev.h>
+#include <linux/idr.h>
 
 #include <media/rc-core.h>
 #include <media/lirc.h>
@@ -46,10 +47,9 @@ struct irctl {
 	struct cdev cdev;
 };
 
-/* This mutex protects the irctls array */
-static DEFINE_MUTEX(lirc_dev_lock);
-
-static struct irctl *irctls[MAX_IRCTL_DEVICES];
+/* Used to keep track of allocated lirc devices */
+#define LIRC_MAX_DEVICES 256
+static DEFINE_IDA(lirc_ida);
 
 /* Only used for sysfs but defined to void otherwise */
 static struct class *lirc_class;
@@ -69,9 +69,6 @@ static void lirc_release(struct device *ld)
 {
 	struct irctl *ir = container_of(ld, struct irctl, dev);
 
-	mutex_lock(&lirc_dev_lock);
-	irctls[ir->d.minor] = NULL;
-	mutex_unlock(&lirc_dev_lock);
 	lirc_free_buffer(ir);
 	kfree(ir);
 }
@@ -109,7 +106,7 @@ static int lirc_allocate_buffer(struct irctl *ir)
 int lirc_register_driver(struct lirc_driver *d)
 {
 	struct irctl *ir;
-	unsigned int minor;
+	int minor;
 	int err;
 
 	if (!d) {
@@ -171,28 +168,17 @@ int lirc_register_driver(struct lirc_driver *d)
 		d->rbuf = ir->buf;
 	}
 
-	mutex_lock(&lirc_dev_lock);
-
-	/* find first free slot for driver */
-	for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++)
-		if (!irctls[minor])
-			break;
-
-	if (minor == MAX_IRCTL_DEVICES) {
-		dev_err(d->dev, "no free slots for drivers!\n");
-		mutex_unlock(&lirc_dev_lock);
+	minor = ida_simple_get(&lirc_ida, 0, LIRC_MAX_DEVICES, GFP_KERNEL);
+	if (minor < 0) {
 		lirc_free_buffer(ir);
 		kfree(ir);
-		return -ENOMEM;
+		return minor;
 	}
 
-	irctls[minor] = ir;
 	d->irctl = ir;
 	d->minor = minor;
 	ir->d.minor = minor;
 
-	mutex_unlock(&lirc_dev_lock);
-
 	device_initialize(&ir->dev);
 	ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor);
 	ir->dev.class = lirc_class;
@@ -206,6 +192,7 @@ int lirc_register_driver(struct lirc_driver *d)
 
 	err = cdev_device_add(&ir->cdev, &ir->dev);
 	if (err) {
+		ida_simple_remove(&lirc_ida, minor);
 		put_device(&ir->dev);
 		return err;
 	}
@@ -244,6 +231,7 @@ void lirc_unregister_driver(struct lirc_driver *d)
 
 	mutex_unlock(&ir->mutex);
 
+	ida_simple_remove(&lirc_ida, d->minor);
 	put_device(&ir->dev);
 }
 EXPORT_SYMBOL(lirc_unregister_driver);
@@ -540,7 +528,7 @@ static int __init lirc_dev_init(void)
 		return PTR_ERR(lirc_class);
 	}
 
-	retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES,
+	retval = alloc_chrdev_region(&lirc_base_dev, 0, LIRC_MAX_DEVICES,
 				     "BaseRemoteCtl");
 	if (retval) {
 		class_destroy(lirc_class);
@@ -557,7 +545,7 @@ static int __init lirc_dev_init(void)
 static void __exit lirc_dev_exit(void)
 {
 	class_destroy(lirc_class);
-	unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES);
+	unregister_chrdev_region(lirc_base_dev, LIRC_MAX_DEVICES);
 	pr_info("module unloaded\n");
 }