]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/dvb/dvb-core/dvbdev.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[linux-2.6-omap-h63xx.git] / drivers / media / dvb / dvb-core / dvbdev.c
index 665776d72a48c0456b712b25894760e60f48e4e8..6c571d9f011c6df050c23230c399390e5c3e7334 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,11 +228,31 @@ 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,
-                              MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
-                              NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+                              MKDEV(DVB_MAJOR, minor),
+                              dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
        if (IS_ERR(clsdev)) {
                printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
                       __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
@@ -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);
@@ -326,6 +345,9 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
        adap->name = name;
        adap->module = module;
        adap->device = device;
+       adap->mfe_shared = 0;
+       adap->mfe_dvbdev = NULL;
+       mutex_init (&adap->mfe_lock);
 
        list_add_tail (&adap->list_head, &dvb_adapter_list);
 
@@ -410,6 +432,15 @@ out:
        return err;
 }
 
+static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+       add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
+       add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
+       return 0;
+}
+
 static int __init init_dvbdev(void)
 {
        int retval;
@@ -431,6 +462,7 @@ static int __init init_dvbdev(void)
                retval = PTR_ERR(dvb_class);
                goto error;
        }
+       dvb_class->dev_uevent = dvb_uevent;
        return 0;
 
 error: