diff options
Diffstat (limited to 'drivers/media/dvb-core/dmxdev.c')
| -rw-r--r-- | drivers/media/dvb-core/dmxdev.c | 115 | 
1 files changed, 65 insertions, 50 deletions
| diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 6d53af00190e..61a750fae465 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -128,11 +128,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)  	struct dvb_device *dvbdev = file->private_data;  	struct dmxdev *dmxdev = dvbdev->priv;  	struct dmx_frontend *front; -#ifndef DVB_MMAP  	bool need_ringbuffer = false; -#else -	const bool need_ringbuffer = true; -#endif  	dprintk("%s\n", __func__); @@ -144,17 +140,31 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)  		return -ENODEV;  	} -#ifndef DVB_MMAP +	dmxdev->may_do_mmap = 0; + +	/* +	 * The logic here is a little tricky due to the ifdef. +	 * +	 * The ringbuffer is used for both read and mmap. +	 * +	 * It is not needed, however, on two situations: +	 *	- Write devices (access with O_WRONLY); +	 *	- For duplex device nodes, opened with O_RDWR. +	 */ +  	if ((file->f_flags & O_ACCMODE) == O_RDONLY)  		need_ringbuffer = true; -#else -	if ((file->f_flags & O_ACCMODE) == O_RDWR) { +	else if ((file->f_flags & O_ACCMODE) == O_RDWR) {  		if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { +#ifdef CONFIG_DVB_MMAP +			dmxdev->may_do_mmap = 1; +			need_ringbuffer = true; +#else  			mutex_unlock(&dmxdev->mutex);  			return -EOPNOTSUPP; +#endif  		}  	} -#endif  	if (need_ringbuffer) {  		void *mem; @@ -169,8 +179,9 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)  			return -ENOMEM;  		}  		dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); -		dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr", -			     file->f_flags & O_NONBLOCK); +		if (dmxdev->may_do_mmap) +			dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr", +				     file->f_flags & O_NONBLOCK);  		dvbdev->readers--;  	} @@ -200,11 +211,6 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)  {  	struct dvb_device *dvbdev = file->private_data;  	struct dmxdev *dmxdev = dvbdev->priv; -#ifndef DVB_MMAP -	bool need_ringbuffer = false; -#else -	const bool need_ringbuffer = true; -#endif  	mutex_lock(&dmxdev->mutex); @@ -213,15 +219,14 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)  		dmxdev->demux->connect_frontend(dmxdev->demux,  						dmxdev->dvr_orig_fe);  	} -#ifndef DVB_MMAP -	if ((file->f_flags & O_ACCMODE) == O_RDONLY) -		need_ringbuffer = true; -#endif -	if (need_ringbuffer) { -		if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) -			dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx); -		dvb_vb2_release(&dmxdev->dvr_vb2_ctx); +	if (((file->f_flags & O_ACCMODE) == O_RDONLY) || +	    dmxdev->may_do_mmap) { +		if (dmxdev->may_do_mmap) { +			if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) +				dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx); +			dvb_vb2_release(&dmxdev->dvr_vb2_ctx); +		}  		dvbdev->readers++;  		if (dmxdev->dvr_buffer.data) {  			void *mem = dmxdev->dvr_buffer.data; @@ -380,7 +385,8 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)  static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,  				       const u8 *buffer2, size_t buffer2_len, -				       struct dmx_section_filter *filter) +				       struct dmx_section_filter *filter, +				       u32 *buffer_flags)  {  	struct dmxdev_filter *dmxdevfilter = filter->priv;  	int ret; @@ -399,10 +405,12 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,  	dprintk("section callback %*ph\n", 6, buffer1);  	if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) {  		ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, -					  buffer1, buffer1_len); +					  buffer1, buffer1_len, +					  buffer_flags);  		if (ret == buffer1_len)  			ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, -						  buffer2, buffer2_len); +						  buffer2, buffer2_len, +						  buffer_flags);  	} else {  		ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,  					      buffer1, buffer1_len); @@ -422,11 +430,12 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,  static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,  				  const u8 *buffer2, size_t buffer2_len, -				  struct dmx_ts_feed *feed) +				  struct dmx_ts_feed *feed, +				  u32 *buffer_flags)  {  	struct dmxdev_filter *dmxdevfilter = feed->priv;  	struct dvb_ringbuffer *buffer; -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP  	struct dvb_vb2_ctx *ctx;  #endif  	int ret; @@ -440,20 +449,22 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,  	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP ||  	    dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {  		buffer = &dmxdevfilter->buffer; -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP  		ctx = &dmxdevfilter->vb2_ctx;  #endif  	} else {  		buffer = &dmxdevfilter->dev->dvr_buffer; -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP  		ctx = &dmxdevfilter->dev->dvr_vb2_ctx;  #endif  	}  	if (dvb_vb2_is_streaming(ctx)) { -		ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len); +		ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len, +					  buffer_flags);  		if (ret == buffer1_len) -			ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len); +			ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len, +						  buffer_flags);  	} else {  		if (buffer->error) {  			spin_unlock(&dmxdevfilter->dev->lock); @@ -802,6 +813,12 @@ static int dvb_demux_open(struct inode *inode, struct file *file)  	mutex_init(&dmxdevfilter->mutex);  	file->private_data = dmxdevfilter; +#ifdef CONFIG_DVB_MMAP +	dmxdev->may_do_mmap = 1; +#else +	dmxdev->may_do_mmap = 0; +#endif +  	dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);  	dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter",  		     file->f_flags & O_NONBLOCK); @@ -1111,7 +1128,7 @@ static int dvb_demux_do_ioctl(struct file *file,  		mutex_unlock(&dmxdevfilter->mutex);  		break; -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP  	case DMX_REQBUFS:  		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {  			mutex_unlock(&dmxdev->mutex); @@ -1160,7 +1177,7 @@ static int dvb_demux_do_ioctl(struct file *file,  		break;  #endif  	default: -		ret = -EINVAL; +		ret = -ENOTTY;  		break;  	}  	mutex_unlock(&dmxdev->mutex); @@ -1199,13 +1216,16 @@ static __poll_t dvb_demux_poll(struct file *file, poll_table *wait)  	return mask;  } -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP  static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma)  {  	struct dmxdev_filter *dmxdevfilter = file->private_data;  	struct dmxdev *dmxdev = dmxdevfilter->dev;  	int ret; +	if (!dmxdev->may_do_mmap) +		return -ENOTTY; +  	if (mutex_lock_interruptible(&dmxdev->mutex))  		return -ERESTARTSYS; @@ -1249,7 +1269,7 @@ static const struct file_operations dvb_demux_fops = {  	.release = dvb_demux_release,  	.poll = dvb_demux_poll,  	.llseek = default_llseek, -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP  	.mmap = dvb_demux_mmap,  #endif  }; @@ -1280,7 +1300,7 @@ static int dvb_dvr_do_ioctl(struct file *file,  		ret = dvb_dvr_set_buffer_size(dmxdev, arg);  		break; -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP  	case DMX_REQBUFS:  		ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg);  		break; @@ -1304,7 +1324,7 @@ static int dvb_dvr_do_ioctl(struct file *file,  		break;  #endif  	default: -		ret = -EINVAL; +		ret = -ENOTTY;  		break;  	}  	mutex_unlock(&dmxdev->mutex); @@ -1322,11 +1342,6 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait)  	struct dvb_device *dvbdev = file->private_data;  	struct dmxdev *dmxdev = dvbdev->priv;  	__poll_t mask = 0; -#ifndef DVB_MMAP -	bool need_ringbuffer = false; -#else -	const bool need_ringbuffer = true; -#endif  	dprintk("%s\n", __func__); @@ -1337,11 +1352,8 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait)  	poll_wait(file, &dmxdev->dvr_buffer.queue, wait); -#ifndef DVB_MMAP -	if ((file->f_flags & O_ACCMODE) == O_RDONLY) -		need_ringbuffer = true; -#endif -	if (need_ringbuffer) { +	if (((file->f_flags & O_ACCMODE) == O_RDONLY) || +	    dmxdev->may_do_mmap) {  		if (dmxdev->dvr_buffer.error)  			mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR); @@ -1353,13 +1365,16 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait)  	return mask;  } -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP  static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma)  {  	struct dvb_device *dvbdev = file->private_data;  	struct dmxdev *dmxdev = dvbdev->priv;  	int ret; +	if (!dmxdev->may_do_mmap) +		return -ENOTTY; +  	if (dmxdev->exit)  		return -ENODEV; @@ -1381,7 +1396,7 @@ static const struct file_operations dvb_dvr_fops = {  	.release = dvb_dvr_release,  	.poll = dvb_dvr_poll,  	.llseek = default_llseek, -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP  	.mmap = dvb_dvr_mmap,  #endif  }; | 

