summaryrefslogtreecommitdiff
path: root/drivers/media/dvb-core/dvbdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb-core/dvbdev.c')
-rw-r--r--drivers/media/dvb-core/dvbdev.c36
1 files changed, 28 insertions, 8 deletions
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 675d877a67b2..2a857cf70c94 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -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);
@@ -243,7 +246,7 @@ static void dvb_media_device_free(struct dvb_device *dvbdev)
static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
const char *name, int npads)
{
- int i, ret = 0;
+ int i;
dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads),
GFP_KERNEL);
@@ -260,6 +263,7 @@ static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
for (i = 0; i < npads; i++) {
struct media_pad *pads = &dvbdev->tsout_pads[i];
struct media_entity *entity = &dvbdev->tsout_entity[i];
+ int ret;
entity->name = kasprintf(GFP_KERNEL, "%s #%d", name, i);
if (!entity->name)
@@ -332,6 +336,7 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
GFP_KERNEL);
if (!dvbdev->pads) {
kfree(dvbdev->entity);
+ dvbdev->entity = NULL;
return -ENOMEM;
}
}
@@ -478,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;
@@ -508,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);
@@ -553,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);
@@ -564,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);