Merge tag 'driver-core-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / media / dvb-core / dvbdev.c
index 5b275a9395c12cc9c90c16e7dd14630354c56c06..0ed087caf7f3b28e8a51505353334597b2987835 100644 (file)
@@ -97,7 +97,7 @@ static int dvb_device_open(struct inode *inode, struct file *file)
                new_fops = fops_get(dvbdev->fops);
                if (!new_fops)
                        goto fail;
-               file->private_data = dvbdev;
+               file->private_data = dvb_device_get(dvbdev);
                replace_fops(file, new_fops);
                if (file->f_op->open)
                        err = file->f_op->open(inode, file);
@@ -161,6 +161,9 @@ int dvb_generic_release(struct inode *inode, struct file *file)
        }
 
        dvbdev->users++;
+
+       dvb_device_put(dvbdev);
+
        return 0;
 }
 EXPORT_SYMBOL(dvb_generic_release);
@@ -480,6 +483,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        }
 
        memcpy(dvbdev, template, sizeof(struct dvb_device));
+       kref_init(&dvbdev->ref);
        dvbdev->type = type;
        dvbdev->id = id;
        dvbdev->adapter = adap;
@@ -510,7 +514,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
 #endif
 
        dvbdev->minor = minor;
-       dvb_minors[minor] = dvbdev;
+       dvb_minors[minor] = dvb_device_get(dvbdev);
        up_write(&minor_rwsem);
 
        ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
@@ -555,6 +559,7 @@ void dvb_remove_device(struct dvb_device *dvbdev)
 
        down_write(&minor_rwsem);
        dvb_minors[dvbdev->minor] = NULL;
+       dvb_device_put(dvbdev);
        up_write(&minor_rwsem);
 
        dvb_media_device_free(dvbdev);
@@ -566,21 +571,34 @@ void dvb_remove_device(struct dvb_device *dvbdev)
 EXPORT_SYMBOL(dvb_remove_device);
 
 
-void dvb_free_device(struct dvb_device *dvbdev)
+static void dvb_free_device(struct kref *ref)
 {
-       if (!dvbdev)
-               return;
+       struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref);
 
        kfree (dvbdev->fops);
        kfree (dvbdev);
 }
-EXPORT_SYMBOL(dvb_free_device);
+
+
+struct dvb_device *dvb_device_get(struct dvb_device *dvbdev)
+{
+       kref_get(&dvbdev->ref);
+       return dvbdev;
+}
+EXPORT_SYMBOL(dvb_device_get);
+
+
+void dvb_device_put(struct dvb_device *dvbdev)
+{
+       if (dvbdev)
+               kref_put(&dvbdev->ref, dvb_free_device);
+}
 
 
 void dvb_unregister_device(struct dvb_device *dvbdev)
 {
        dvb_remove_device(dvbdev);
-       dvb_free_device(dvbdev);
+       dvb_device_put(dvbdev);
 }
 EXPORT_SYMBOL(dvb_unregister_device);
 
@@ -1010,9 +1028,9 @@ void dvb_module_release(struct i2c_client *client)
 EXPORT_SYMBOL_GPL(dvb_module_release);
 #endif
 
-static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int dvb_uevent(const struct device *dev, struct kobj_uevent_env *env)
 {
-       struct dvb_device *dvbdev = dev_get_drvdata(dev);
+       const struct dvb_device *dvbdev = dev_get_drvdata(dev);
 
        add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
        add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]);
@@ -1020,9 +1038,9 @@ static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
-static char *dvb_devnode(struct device *dev, umode_t *mode)
+static char *dvb_devnode(const struct device *dev, umode_t *mode)
 {
-       struct dvb_device *dvbdev = dev_get_drvdata(dev);
+       const struct dvb_device *dvbdev = dev_get_drvdata(dev);
 
        return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
                dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);