V4L/DVB (9361): Dynamic DVB minor allocation
authorAndreas Oberritter <obi@linuxtv.org>
Thu, 23 Oct 2008 15:11:19 +0000 (12:11 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 29 Dec 2008 19:53:12 +0000 (17:53 -0200)
Implement dynamic minor allocation for DVB, to allow more than four
devices of the same type per adapter, based on drivers/usb/core/file.c.

Add a new config option, DVB_DYNAMIC_MINORS, to make use of this
feature, which defaults to no for backwards compatibility.

Signed-off-by: Andreas Oberritter <obi@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/Kconfig
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h

index 0bcd852576d686a2b556b05e72467d687d49181d..40ebde53b3ce22443a60be62357c5722f64f256d 100644 (file)
@@ -2,6 +2,19 @@
 # DVB device configuration
 #
 
+config DVB_DYNAMIC_MINORS
+       bool "Dynamic DVB minor allocation"
+       depends on DVB_CORE
+       default n
+       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.
+
 menuconfig DVB_CAPTURE_DRIVERS
        bool "DVB/ATSC adapters"
        depends on DVB_CORE
index a113744a56cc136c0355184b0af4504b0219970a..e363a3b5054c62c2ae7038a1b74c5564fcbc0f34 100644 (file)
@@ -50,33 +50,27 @@ static const char * const dnames[] = {
        "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;
@@ -92,9 +86,11 @@ static int dvb_device_open(struct inode *inode, struct file *file)
                        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;
 }
@@ -192,6 +188,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        struct dvb_device *dvbdev;
        struct file_operations *dvbdevfops;
        struct device *clsdev;
+       int minor;
        int id;
 
        mutex_lock(&dvbdev_register_lock);
@@ -231,6 +228,26 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
 
        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);
 
        clsdev = device_create(dvb_class, adap->device,
@@ -243,8 +260,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        }
 
        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;
 }
@@ -256,8 +272,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
        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);
index 574e336bac35b7b8d81471a32fea7c2558fc530c..dca49cf962e864c37cefad089669187735f8c524 100644 (file)
@@ -74,6 +74,7 @@ struct dvb_device {
        struct file_operations *fops;
        struct dvb_adapter *adapter;
        int type;
+       int minor;
        u32 id;
 
        /* in theory, 'users' can vanish now,