[PATCH] i2c/i2c-dev: use dynamic minor allocation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Right now i2c adapter 5 becomes minor 5 allocated. This is fine as long
as no adapter becomes a number > 256 allocated.
The Sodavile PCI driver uses (devfn << 3 | pci_bar) to come up with an
unique adapter number. So the first i2c adapter has the number 720.
This patch introduces dynamic minor allocation so the minor first
registered i2c adapter will be zero, next one one and so on. The name
which is exported to userland remains the same i.e. /dev/i2c-10 for
adapter number 10 (but its minor number may be zero and not 10).
I don't consider this as an ABI change however if someone does I could
add make this a CONFIG_ option and migrate in a year or so. i2c-tools
for instance abort on adapter number > 255 so we have to change this
in order to get the big numbers working.
Since the minors are not allocated dynamically I lowered the number of
max i2c devices to 32 so I don't waste much memory for the allocation.
If one has more than 32 devices then we could increase this again :)

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
Signed-off-by: Dirk Brandewie <dirk.brandewie@xxxxxxxxx>
---
 drivers/i2c/i2c-dev.c |   54 ++++++++++++++++++++++++++++++++++++------------
 1 files changed, 40 insertions(+), 14 deletions(-)

diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index cec0f3b..57eda78 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -52,9 +52,10 @@ struct i2c_dev {
 	struct list_head list;
 	struct i2c_adapter *adap;
 	struct device *dev;
+	int minor;
 };
 
-#define I2C_MINORS	256
+#define I2C_MINORS	32
 static LIST_HEAD(i2c_dev_list);
 static DEFINE_SPINLOCK(i2c_dev_list_lock);
 
@@ -64,7 +65,7 @@ static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
 
 	spin_lock(&i2c_dev_list_lock);
 	list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
-		if (i2c_dev->adap->nr == index)
+		if (i2c_dev->minor == index)
 			goto found;
 	}
 	i2c_dev = NULL;
@@ -73,22 +74,46 @@ found:
 	return i2c_dev;
 }
 
-static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
+static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
 {
 	struct i2c_dev *i2c_dev;
 
-	if (adap->nr >= I2C_MINORS) {
-		printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n",
-		       adap->nr);
-		return ERR_PTR(-ENODEV);
+	spin_lock(&i2c_dev_list_lock);
+	list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
+		if (i2c_dev->adap == adap)
+			goto found;
 	}
+	i2c_dev = NULL;
+found:
+	spin_unlock(&i2c_dev_list_lock);
+	return i2c_dev;
+}
+
+static DECLARE_BITMAP(minors, I2C_MINORS);
+
+static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
+{
+	struct i2c_dev *i2c_dev;
+	int minor;
+	int ret = 0;
 
 	i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);
 	if (!i2c_dev)
-		return ERR_PTR(-ENOMEM);
-	i2c_dev->adap = adap;
+		return ERR_PTR(ret);
 
 	spin_lock(&i2c_dev_list_lock);
+	minor = find_first_zero_bit(minors, I2C_MINORS);
+	if (minor >= I2C_MINORS) {
+		spin_unlock(&i2c_dev_list_lock);
+		kfree(i2c_dev);
+		printk(KERN_ERR "i2c-dev: Out of device minors.\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	i2c_dev->adap = adap;
+	i2c_dev->minor = minor;
+	set_bit(minor, minors);
+
 	list_add_tail(&i2c_dev->list, &i2c_dev_list);
 	spin_unlock(&i2c_dev_list_lock);
 	return i2c_dev;
@@ -97,6 +122,7 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
 static void return_i2c_dev(struct i2c_dev *i2c_dev)
 {
 	spin_lock(&i2c_dev_list_lock);
+	clear_bit(i2c_dev->minor, minors);
 	list_del(&i2c_dev->list);
 	spin_unlock(&i2c_dev_list_lock);
 	kfree(i2c_dev);
@@ -541,7 +567,7 @@ static int i2cdev_attach_adapter(struct i2c_adapter *adap)
 
 	/* register this i2c device with the driver core */
 	i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
-				     MKDEV(I2C_MAJOR, adap->nr), NULL,
+				     MKDEV(I2C_MAJOR, i2c_dev->minor), NULL,
 				     "i2c-%d", adap->nr);
 	if (IS_ERR(i2c_dev->dev)) {
 		res = PTR_ERR(i2c_dev->dev);
@@ -552,10 +578,10 @@ static int i2cdev_attach_adapter(struct i2c_adapter *adap)
 		goto error_destroy;
 
 	pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
-		 adap->name, adap->nr);
+		 adap->name, i2c_dev->minor);
 	return 0;
 error_destroy:
-	device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
+	device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, i2c_dev->minor));
 error:
 	return_i2c_dev(i2c_dev);
 	return res;
@@ -565,13 +591,13 @@ static int i2cdev_detach_adapter(struct i2c_adapter *adap)
 {
 	struct i2c_dev *i2c_dev;
 
-	i2c_dev = i2c_dev_get_by_minor(adap->nr);
+	i2c_dev = i2c_dev_get_by_adapter(adap);
 	if (!i2c_dev) /* attach_adapter must have failed */
 		return 0;
 
 	device_remove_file(i2c_dev->dev, &dev_attr_name);
 	return_i2c_dev(i2c_dev);
-	device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
+	device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, i2c_dev->minor));
 
 	pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
 	return 0;
-- 
1.7.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux