Google
  Web www.spinics.net

[PATCH/RFC] Dynamic DVB minor allocation

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


Hello,

recently we've exceeded the limit of minor devices, when we tried to
register five demux devices on an adapter instance. We circumvented
this limit by changing the macro nums2minor, which is not acceptable if
you want to stay backwards compatible.

So I went for a cleaner solution and added a new configuration option,
which allows dynamic minor allocation for DVB devices.

I haven't tested it yet. It is loosely based on drivers/usb/core/file.c.

Any comments?

Regards,
Andreas

diff -r 9273407ca6e1 linux/drivers/media/dvb/Kconfig
--- a/linux/drivers/media/dvb/Kconfig	Wed Oct 15 02:50:03 2008 +0400
+++ b/linux/drivers/media/dvb/Kconfig	Mon Oct 20 15:30:50 2008 +0200
@@ -8,6 +8,18 @@
 	default y
 	---help---
 	  Say Y to select Digital TV adapters
+
+config DVB_DYNAMIC_MINORS
+	bool "Dynamic DVB minor allocation"
+	depends on DVB_CORE
+	help
+	  If you say Y here, the DVB subsystem will use dynamic minor
+	  allocation for any device that uses the DVB major number.
+	  This means that you can have more than 4 of a single type
+	  of device (like demuxes and frontends) per adapter, but udev
+	  will be required to manage the device nodes.
+
+	  If you are unsure about this, say N here.
 
 if DVB_CAPTURE_DRIVERS && DVB_CORE
 
diff -r 9273407ca6e1 linux/drivers/media/dvb/dvb-core/dvbdev.c
--- a/linux/drivers/media/dvb/dvb-core/dvbdev.c	Wed Oct 15 02:50:03 2008 +0400
+++ b/linux/drivers/media/dvb/dvb-core/dvbdev.c	Mon Oct 20 15:30:50 2008 +0200
@@ -51,33 +51,27 @@
 	"net", "osd"
 };
 
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+#define MAX_DVB_MINORS		256
+#define DVB_MAX_IDS		MAX_DVB_MINORS
+#else
 #define DVB_MAX_IDS		4
 #define nums2minor(num,type,id)	((num << 6) | (id << 4) | type)
 #define MAX_DVB_MINORS		(DVB_MAX_ADAPTERS*64)
+#endif
 
 static struct class *dvb_class;
 
-static struct dvb_device* dvbdev_find_device (int minor)
-{
-	struct dvb_adapter *adap;
-
-	list_for_each_entry(adap, &dvb_adapter_list, list_head) {
-		struct dvb_device *dev;
-		list_for_each_entry(dev, &adap->device_list, list_head)
-			if (nums2minor(adap->num, dev->type, dev->id) == minor)
-				return dev;
-	}
-
-	return NULL;
-}
-
+static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
+static DECLARE_RWSEM(minor_rwsem);
 
 static int dvb_device_open(struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev;
 
 	lock_kernel();
-	dvbdev = dvbdev_find_device (iminor(inode));
+	down_read(&minor_rwsem);
+	dvbdev = dvb_minors[iminor(inode)];
 
 	if (dvbdev && dvbdev->fops) {
 		int err = 0;
@@ -97,9 +91,11 @@
 			file->f_op = fops_get(old_fops);
 		}
 		fops_put(old_fops);
+		up_read(&minor_rwsem);
 		unlock_kernel();
 		return err;
 	}
+	up_read(&minor_rwsem);
 	unlock_kernel();
 	return -ENODEV;
 }
@@ -201,6 +197,7 @@
 #else
 	struct class_device *clsdev;
 #endif
+	int minor;
 	int id;
 
 	mutex_lock(&dvbdev_register_lock);
@@ -240,15 +237,35 @@
 
 	list_add_tail (&dvbdev->list_head, &adap->device_list);
 
+	down_write(&minor_rwsem);
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+	for (minor = 0; minor < MAX_DVB_MINORS; minor++)
+		if (dvb_minors[minor] == NULL)
+			break;
+
+	if (minor == MAX_DVB_MINORS) {
+		kfree(dvbdevfops);
+		kfree(dvbdev);
+		mutex_unlock(&dvbdev_register_lock);
+		return -EINVAL;
+	}
+#else
+	minor = nums2minor(adap->num, type, id);
+#endif
+
+	dvbdev->minor = minor;
+	dvb_minors[minor] = dvbdev;
+	up_write(&minor_rwsem);
+
 	mutex_unlock(&dvbdev_register_lock);
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26)
 	clsdev = device_create_drvdata(dvb_class, adap->device,
-			       MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
+			       MKDEV(DVB_MAJOR, minor),
 			       NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
 #else
 	clsdev = device_create(dvb_class, adap->device,
-			       MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
+			       MKDEV(DVB_MAJOR, minor),
 			       "dvb%d.%s%d", adap->num, dnames[type], id);
 #endif
 	if (IS_ERR(clsdev)) {
@@ -258,8 +275,7 @@
 	}
 
 	dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
-		adap->num, dnames[type], id, nums2minor(adap->num, type, id),
-		nums2minor(adap->num, type, id));
+		adap->num, dnames[type], id, minor, minor);
 
 	return 0;
 }
@@ -271,8 +287,11 @@
 	if (!dvbdev)
 		return;
 
-	device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
-		       dvbdev->type, dvbdev->id)));
+	down_write(&minor_rwsem);
+	dvb_minors[dvbdev->minor] = NULL;
+	up_write(&minor_rwsem);
+
+	device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
 
 	list_del (&dvbdev->list_head);
 	kfree (dvbdev->fops);
diff -r 9273407ca6e1 linux/drivers/media/dvb/dvb-core/dvbdev.h
--- a/linux/drivers/media/dvb/dvb-core/dvbdev.h	Wed Oct 15 02:50:03 2008 +0400
+++ b/linux/drivers/media/dvb/dvb-core/dvbdev.h	Mon Oct 20 15:30:50 2008 +0200
@@ -70,6 +70,7 @@
 	struct file_operations *fops;
 	struct dvb_adapter *adapter;
 	int type;
+	int minor;
 	u32 id;
 
 	/* in theory, 'users' can vanish now,
_______________________________________________
v4l-dvb-maintainer mailing list
v4l-dvb-maintainer@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/v4l-dvb-maintainer

[Linux Media]     [Older V4L]     [Linux DVB]     [Video Disk Recorder]     [Asterisk]     [Photo]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Free Photo Albums]     [Fedora Users]     [Fedora Women]     [ALSA Users]     [ALSA Devel]     [SSH]     [Linux USB]

-->
Add to Google Powered by Linux

Google PageRank Checking tool