diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index a5c0e1a3e6d14f1cd41f55247af56409f2b9bb46..275df65fde992680b82631f7ee1ca98750a6d256 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 d2bee9ffe43cff81421bba33846c42cae9234f92..29746e70d3252dedaa2a40856b91472e55934603 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_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index 6d8d1c3df8631a4832b34954e44e5633cd3a34c6..f558ac9c09547bd27b2cd8c75ded25a6566314b1 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -1208,6 +1208,8 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dmx->disconnect_frontend = dvbdmx_disconnect_frontend; dmx->get_pes_pids = dvbdmx_get_pes_pids; + init_waitqueue_head (&dvbdemux->wait_queue); + mutex_init(&dvbdemux->mutex); spin_lock_init(&dvbdemux->lock); diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h index 2c5f915329ca9c5658e68628208f57c58c856364..e1e91399afd91fc43c0444e8a89687e4ae4a916c 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.h +++ b/drivers/media/dvb/dvb-core/dvb_demux.h @@ -119,6 +119,7 @@ struct dvb_demux { u16 pids[DMX_TS_PES_OTHER]; int playing; int recording; + wait_queue_head_t wait_queue; #define DMX_MAX_PID 0x2000 struct list_head feed_list; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 9783d392b7d3babddc9f7965a5f7130ed9b9a21f..f4e4ca2dcaded8083ac6927ba4630636be374de5 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -607,10 +607,6 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) kthread_stop(fepriv->thread); - if (fepriv->dvbdev->users < -1) - wait_event_interruptible(fepriv->dvbdev->wait_queue, - fepriv->dvbdev->users==-1); - init_MUTEX (&fepriv->sem); fepriv->state = FESTATE_IDLE; @@ -1043,7 +1039,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) if (dvbdev->users==-1 && fepriv->exit==1) { fops_put(file->f_op); file->f_op = NULL; - wake_up_interruptible (&dvbdev->wait_queue); + wake_up(&dvbdev->wait_queue); } return ret; } @@ -1104,7 +1100,14 @@ int dvb_unregister_frontend(struct dvb_frontend* fe) struct dvb_frontend_private *fepriv = fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); + mutex_lock(&frontend_mutex); 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);