aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/dvb-core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/dvb-core')
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c56
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.h2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c20
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c32
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.h1
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c1
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.h1
7 files changed, 108 insertions, 5 deletions
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index a5c0e1a3e6d1..275df65fde99 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -132,6 +132,11 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
+
if ((file->f_flags & O_ACCMODE) == O_RDWR) {
if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
mutex_unlock(&dmxdev->mutex);
@@ -171,6 +176,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
dmxdev->demux->disconnect_frontend(dmxdev->demux);
dmxdev->demux->connect_frontend(dmxdev->demux, front);
}
+ dvbdev->users++;
mutex_unlock(&dmxdev->mutex);
return 0;
}
@@ -198,7 +204,16 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
vfree(mem);
}
}
- mutex_unlock(&dmxdev->mutex);
+ /* TODO */
+ dvbdev->users--;
+ if(dvbdev->users==-1 && dmxdev->exit==1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ mutex_unlock(&dmxdev->mutex);
+ wake_up(&dvbdev->wait_queue);
+ } else
+ mutex_unlock(&dmxdev->mutex);
+
return 0;
}
@@ -215,6 +230,11 @@ static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
return -EINVAL;
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
+
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
ret = dmxdev->demux->write(dmxdev->demux, buf, count);
mutex_unlock(&dmxdev->mutex);
return ret;
@@ -227,6 +247,11 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
struct dmxdev *dmxdev = dvbdev->priv;
int ret;
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
+
//mutex_lock(&dmxdev->mutex);
ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
file->f_flags & O_NONBLOCK,
@@ -665,6 +690,8 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
dmxdevfilter->feed.ts = NULL;
init_timer(&dmxdevfilter->timer);
+ dvbdev->users++;
+
mutex_unlock(&dmxdev->mutex);
return 0;
}
@@ -943,7 +970,21 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev = dmxdevfilter->dev;
- return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+ int ret;
+
+ ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+
+ mutex_lock(&dmxdev->mutex);
+ dmxdev->dvbdev->users--;
+ if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ mutex_unlock(&dmxdev->mutex);
+ wake_up(&dmxdev->dvbdev->wait_queue);
+ } else
+ mutex_unlock(&dmxdev->mutex);
+
+ return ret;
}
static struct file_operations dvb_demux_fops = {
@@ -1027,6 +1068,7 @@ static struct file_operations dvb_dvr_fops = {
static struct dvb_device dvbdev_dvr = {
.priv = NULL,
.readers = 1,
+ .users = 1,
.fops = &dvb_dvr_fops
};
@@ -1064,6 +1106,16 @@ EXPORT_SYMBOL(dvb_dmxdev_init);
void dvb_dmxdev_release(struct dmxdev *dmxdev)
{
+ dmxdev->exit=1;
+ if (dmxdev->dvbdev->users > 1) {
+ wait_event(dmxdev->dvbdev->wait_queue,
+ dmxdev->dvbdev->users==1);
+ }
+ if (dmxdev->dvr_dvbdev->users > 1) {
+ wait_event(dmxdev->dvr_dvbdev->wait_queue,
+ dmxdev->dvr_dvbdev->users==1);
+ }
+
dvb_unregister_device(dmxdev->dvbdev);
dvb_unregister_device(dmxdev->dvr_dvbdev);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index d2bee9ffe43c..29746e70d325 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -91,6 +91,8 @@ struct dmxdev {
int filternum;
int capabilities;
+
+ unsigned int exit:1;
#define DMXDEV_CAP_DUPLEX 1
struct dmx_frontend *dvr_orig_fe;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index a21a894d3f98..f4e4ca2dcade 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -606,6 +606,7 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
return;
kthread_stop(fepriv->thread);
+
init_MUTEX (&fepriv->sem);
fepriv->state = FESTATE_IDLE;
@@ -1023,6 +1024,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend *fe = dvbdev->priv;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ int ret;
dprintk ("%s\n", __FUNCTION__);
@@ -1032,7 +1034,14 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
if (fe->ops.ts_bus_ctrl)
fe->ops.ts_bus_ctrl (fe, 0);
- return dvb_generic_release (inode, file);
+ ret = dvb_generic_release (inode, file);
+
+ if (dvbdev->users==-1 && fepriv->exit==1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ wake_up(&dvbdev->wait_queue);
+ }
+ return ret;
}
static struct file_operations dvb_frontend_fops = {
@@ -1092,8 +1101,15 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
dprintk ("%s\n", __FUNCTION__);
mutex_lock(&frontend_mutex);
- dvb_unregister_device (fepriv->dvbdev);
dvb_frontend_stop (fe);
+ mutex_unlock(&frontend_mutex);
+
+ if (fepriv->dvbdev->users < -1)
+ wait_event(fepriv->dvbdev->wait_queue,
+ fepriv->dvbdev->users==-1);
+
+ mutex_lock(&frontend_mutex);
+ dvb_unregister_device (fepriv->dvbdev);
/* fe is invalid now */
kfree(fepriv);
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 6a5ab409c4e7..4ebf33a5ffa2 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -1439,11 +1439,36 @@ static int dvb_net_ioctl(struct inode *inode, struct file *file,
return dvb_usercopy(inode, file, cmd, arg, dvb_net_do_ioctl);
}
+static int dvb_net_close(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_net *dvbnet = dvbdev->priv;
+
+ if (!dvbdev)
+ return -ENODEV;
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+ dvbdev->readers++;
+ } else {
+ dvbdev->writers++;
+ }
+
+ dvbdev->users++;
+
+ if(dvbdev->users == 1 && dvbnet->exit==1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ wake_up(&dvbdev->wait_queue);
+ }
+ return 0;
+}
+
+
static struct file_operations dvb_net_fops = {
.owner = THIS_MODULE,
.ioctl = dvb_net_ioctl,
.open = dvb_generic_open,
- .release = dvb_generic_release,
+ .release = dvb_net_close,
};
static struct dvb_device dvbdev_net = {
@@ -1458,6 +1483,11 @@ void dvb_net_release (struct dvb_net *dvbnet)
{
int i;
+ dvbnet->exit = 1;
+ if (dvbnet->dvbdev->users < 1)
+ wait_event(dvbnet->dvbdev->wait_queue,
+ dvbnet->dvbdev->users==1);
+
dvb_unregister_device(dvbnet->dvbdev);
for (i=0; i<DVB_NET_DEVICES_MAX; i++) {
diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h
index f14e4ca38570..3a3126cae03b 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.h
+++ b/drivers/media/dvb/dvb-core/dvb_net.h
@@ -36,6 +36,7 @@ struct dvb_net {
struct dvb_device *dvbdev;
struct net_device *device[DVB_NET_DEVICES_MAX];
int state[DVB_NET_DEVICES_MAX];
+ unsigned int exit:1;
struct dmx_demux *demux;
};
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 14a372a0fe8b..e23d8a0ea1d3 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -233,6 +233,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dvbdev->adapter = adap;
dvbdev->priv = priv;
dvbdev->fops = dvbdevfops;
+ init_waitqueue_head (&dvbdev->wait_queue);
memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
dvbdev->fops->owner = adap->module;
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 620e7887b3d3..6dff10ebf470 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -69,6 +69,7 @@ struct dvb_device {
int writers;
int users;
+ wait_queue_head_t wait_queue;
/* don't really need those !? -- FIXME: use video_usercopy */
int (*kernel_ioctl)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg);