xref: /linux/drivers/media/dvb-core/dmxdev.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
18d395ce6SCai Huoqing // SPDX-License-Identifier: LGPL-2.1-or-later
23d6c2bc0SMauro Carvalho Chehab /*
33d6c2bc0SMauro Carvalho Chehab  * dmxdev.c - DVB demultiplexer device
43d6c2bc0SMauro Carvalho Chehab  *
53d6c2bc0SMauro Carvalho Chehab  * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
63d6c2bc0SMauro Carvalho Chehab  *		      for convergence integrated media GmbH
73d6c2bc0SMauro Carvalho Chehab  */
83d6c2bc0SMauro Carvalho Chehab 
9b3ad24d2SMauro Carvalho Chehab #define pr_fmt(fmt) "dmxdev: " fmt
10b3ad24d2SMauro Carvalho Chehab 
113d6c2bc0SMauro Carvalho Chehab #include <linux/sched.h>
123d6c2bc0SMauro Carvalho Chehab #include <linux/spinlock.h>
133d6c2bc0SMauro Carvalho Chehab #include <linux/slab.h>
143d6c2bc0SMauro Carvalho Chehab #include <linux/vmalloc.h>
153d6c2bc0SMauro Carvalho Chehab #include <linux/module.h>
163d6c2bc0SMauro Carvalho Chehab #include <linux/poll.h>
173d6c2bc0SMauro Carvalho Chehab #include <linux/ioctl.h>
183d6c2bc0SMauro Carvalho Chehab #include <linux/wait.h>
197c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
20fada1935SMauro Carvalho Chehab #include <media/dmxdev.h>
21fada1935SMauro Carvalho Chehab #include <media/dvb_vb2.h>
223d6c2bc0SMauro Carvalho Chehab 
233d6c2bc0SMauro Carvalho Chehab static int debug;
243d6c2bc0SMauro Carvalho Chehab 
253d6c2bc0SMauro Carvalho Chehab module_param(debug, int, 0644);
263d6c2bc0SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
273d6c2bc0SMauro Carvalho Chehab 
28b3ad24d2SMauro Carvalho Chehab #define dprintk(fmt, arg...) do {					\
29b3ad24d2SMauro Carvalho Chehab 	if (debug)							\
30b3ad24d2SMauro Carvalho Chehab 		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
31b3ad24d2SMauro Carvalho Chehab 			__func__, ##arg);				\
32b3ad24d2SMauro Carvalho Chehab } while (0)
333d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_buffer_write(struct dvb_ringbuffer * buf,const u8 * src,size_t len)343d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
353d6c2bc0SMauro Carvalho Chehab 				   const u8 *src, size_t len)
363d6c2bc0SMauro Carvalho Chehab {
373d6c2bc0SMauro Carvalho Chehab 	ssize_t free;
383d6c2bc0SMauro Carvalho Chehab 
393d6c2bc0SMauro Carvalho Chehab 	if (!len)
403d6c2bc0SMauro Carvalho Chehab 		return 0;
413d6c2bc0SMauro Carvalho Chehab 	if (!buf->data)
423d6c2bc0SMauro Carvalho Chehab 		return 0;
433d6c2bc0SMauro Carvalho Chehab 
443d6c2bc0SMauro Carvalho Chehab 	free = dvb_ringbuffer_free(buf);
453d6c2bc0SMauro Carvalho Chehab 	if (len > free) {
46b3ad24d2SMauro Carvalho Chehab 		dprintk("buffer overflow\n");
473d6c2bc0SMauro Carvalho Chehab 		return -EOVERFLOW;
483d6c2bc0SMauro Carvalho Chehab 	}
493d6c2bc0SMauro Carvalho Chehab 
503d6c2bc0SMauro Carvalho Chehab 	return dvb_ringbuffer_write(buf, src, len);
513d6c2bc0SMauro Carvalho Chehab }
523d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_buffer_read(struct dvb_ringbuffer * src,int non_blocking,char __user * buf,size_t count,loff_t * ppos)533d6c2bc0SMauro Carvalho Chehab static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
543d6c2bc0SMauro Carvalho Chehab 				      int non_blocking, char __user *buf,
553d6c2bc0SMauro Carvalho Chehab 				      size_t count, loff_t *ppos)
563d6c2bc0SMauro Carvalho Chehab {
573d6c2bc0SMauro Carvalho Chehab 	size_t todo;
583d6c2bc0SMauro Carvalho Chehab 	ssize_t avail;
593d6c2bc0SMauro Carvalho Chehab 	ssize_t ret = 0;
603d6c2bc0SMauro Carvalho Chehab 
613d6c2bc0SMauro Carvalho Chehab 	if (!src->data)
623d6c2bc0SMauro Carvalho Chehab 		return 0;
633d6c2bc0SMauro Carvalho Chehab 
643d6c2bc0SMauro Carvalho Chehab 	if (src->error) {
653d6c2bc0SMauro Carvalho Chehab 		ret = src->error;
663d6c2bc0SMauro Carvalho Chehab 		dvb_ringbuffer_flush(src);
673d6c2bc0SMauro Carvalho Chehab 		return ret;
683d6c2bc0SMauro Carvalho Chehab 	}
693d6c2bc0SMauro Carvalho Chehab 
703d6c2bc0SMauro Carvalho Chehab 	for (todo = count; todo > 0; todo -= ret) {
713d6c2bc0SMauro Carvalho Chehab 		if (non_blocking && dvb_ringbuffer_empty(src)) {
723d6c2bc0SMauro Carvalho Chehab 			ret = -EWOULDBLOCK;
733d6c2bc0SMauro Carvalho Chehab 			break;
743d6c2bc0SMauro Carvalho Chehab 		}
753d6c2bc0SMauro Carvalho Chehab 
763d6c2bc0SMauro Carvalho Chehab 		ret = wait_event_interruptible(src->queue,
773d6c2bc0SMauro Carvalho Chehab 					       !dvb_ringbuffer_empty(src) ||
783d6c2bc0SMauro Carvalho Chehab 					       (src->error != 0));
793d6c2bc0SMauro Carvalho Chehab 		if (ret < 0)
803d6c2bc0SMauro Carvalho Chehab 			break;
813d6c2bc0SMauro Carvalho Chehab 
823d6c2bc0SMauro Carvalho Chehab 		if (src->error) {
833d6c2bc0SMauro Carvalho Chehab 			ret = src->error;
843d6c2bc0SMauro Carvalho Chehab 			dvb_ringbuffer_flush(src);
853d6c2bc0SMauro Carvalho Chehab 			break;
863d6c2bc0SMauro Carvalho Chehab 		}
873d6c2bc0SMauro Carvalho Chehab 
883d6c2bc0SMauro Carvalho Chehab 		avail = dvb_ringbuffer_avail(src);
893d6c2bc0SMauro Carvalho Chehab 		if (avail > todo)
903d6c2bc0SMauro Carvalho Chehab 			avail = todo;
913d6c2bc0SMauro Carvalho Chehab 
923d6c2bc0SMauro Carvalho Chehab 		ret = dvb_ringbuffer_read_user(src, buf, avail);
933d6c2bc0SMauro Carvalho Chehab 		if (ret < 0)
943d6c2bc0SMauro Carvalho Chehab 			break;
953d6c2bc0SMauro Carvalho Chehab 
963d6c2bc0SMauro Carvalho Chehab 		buf += ret;
973d6c2bc0SMauro Carvalho Chehab 	}
983d6c2bc0SMauro Carvalho Chehab 
993d6c2bc0SMauro Carvalho Chehab 	return (count - todo) ? (count - todo) : ret;
1003d6c2bc0SMauro Carvalho Chehab }
1013d6c2bc0SMauro Carvalho Chehab 
get_fe(struct dmx_demux * demux,int type)1023d6c2bc0SMauro Carvalho Chehab static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
1033d6c2bc0SMauro Carvalho Chehab {
1043d6c2bc0SMauro Carvalho Chehab 	struct list_head *head, *pos;
1053d6c2bc0SMauro Carvalho Chehab 
1063d6c2bc0SMauro Carvalho Chehab 	head = demux->get_frontends(demux);
1073d6c2bc0SMauro Carvalho Chehab 	if (!head)
1083d6c2bc0SMauro Carvalho Chehab 		return NULL;
1093d6c2bc0SMauro Carvalho Chehab 	list_for_each(pos, head)
1103d6c2bc0SMauro Carvalho Chehab 		if (DMX_FE_ENTRY(pos)->source == type)
1113d6c2bc0SMauro Carvalho Chehab 			return DMX_FE_ENTRY(pos);
1123d6c2bc0SMauro Carvalho Chehab 
1133d6c2bc0SMauro Carvalho Chehab 	return NULL;
1143d6c2bc0SMauro Carvalho Chehab }
1153d6c2bc0SMauro Carvalho Chehab 
dvb_dvr_open(struct inode * inode,struct file * file)1163d6c2bc0SMauro Carvalho Chehab static int dvb_dvr_open(struct inode *inode, struct file *file)
1173d6c2bc0SMauro Carvalho Chehab {
1183d6c2bc0SMauro Carvalho Chehab 	struct dvb_device *dvbdev = file->private_data;
1193d6c2bc0SMauro Carvalho Chehab 	struct dmxdev *dmxdev = dvbdev->priv;
1203d6c2bc0SMauro Carvalho Chehab 	struct dmx_frontend *front;
1214021053eSMauro Carvalho Chehab 	bool need_ringbuffer = false;
1223d6c2bc0SMauro Carvalho Chehab 
123b3ad24d2SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1243d6c2bc0SMauro Carvalho Chehab 
1253d6c2bc0SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&dmxdev->mutex))
1263d6c2bc0SMauro Carvalho Chehab 		return -ERESTARTSYS;
1273d6c2bc0SMauro Carvalho Chehab 
1283d6c2bc0SMauro Carvalho Chehab 	if (dmxdev->exit) {
1293d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdev->mutex);
1303d6c2bc0SMauro Carvalho Chehab 		return -ENODEV;
1313d6c2bc0SMauro Carvalho Chehab 	}
1323d6c2bc0SMauro Carvalho Chehab 
1330b23498aSMauro Carvalho Chehab 	dmxdev->may_do_mmap = 0;
1340b23498aSMauro Carvalho Chehab 
1350b23498aSMauro Carvalho Chehab 	/*
1360b23498aSMauro Carvalho Chehab 	 * The logic here is a little tricky due to the ifdef.
1370b23498aSMauro Carvalho Chehab 	 *
1380b23498aSMauro Carvalho Chehab 	 * The ringbuffer is used for both read and mmap.
1390b23498aSMauro Carvalho Chehab 	 *
1400b23498aSMauro Carvalho Chehab 	 * It is not needed, however, on two situations:
1410b23498aSMauro Carvalho Chehab 	 *	- Write devices (access with O_WRONLY);
1420b23498aSMauro Carvalho Chehab 	 *	- For duplex device nodes, opened with O_RDWR.
1430b23498aSMauro Carvalho Chehab 	 */
1440b23498aSMauro Carvalho Chehab 
1454021053eSMauro Carvalho Chehab 	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
1464021053eSMauro Carvalho Chehab 		need_ringbuffer = true;
1470b23498aSMauro Carvalho Chehab 	else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
1483d6c2bc0SMauro Carvalho Chehab 		if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
1490b23498aSMauro Carvalho Chehab #ifdef CONFIG_DVB_MMAP
1500b23498aSMauro Carvalho Chehab 			dmxdev->may_do_mmap = 1;
1510b23498aSMauro Carvalho Chehab 			need_ringbuffer = true;
1520b23498aSMauro Carvalho Chehab #else
1533d6c2bc0SMauro Carvalho Chehab 			mutex_unlock(&dmxdev->mutex);
1543d6c2bc0SMauro Carvalho Chehab 			return -EOPNOTSUPP;
1554021053eSMauro Carvalho Chehab #endif
1560b23498aSMauro Carvalho Chehab 		}
1570b23498aSMauro Carvalho Chehab 	}
1583d6c2bc0SMauro Carvalho Chehab 
1594021053eSMauro Carvalho Chehab 	if (need_ringbuffer) {
1603d6c2bc0SMauro Carvalho Chehab 		void *mem;
161e90bbacdSdevendra sharma 
1623d6c2bc0SMauro Carvalho Chehab 		if (!dvbdev->readers) {
1633d6c2bc0SMauro Carvalho Chehab 			mutex_unlock(&dmxdev->mutex);
1643d6c2bc0SMauro Carvalho Chehab 			return -EBUSY;
1653d6c2bc0SMauro Carvalho Chehab 		}
1663d6c2bc0SMauro Carvalho Chehab 		mem = vmalloc(DVR_BUFFER_SIZE);
1673d6c2bc0SMauro Carvalho Chehab 		if (!mem) {
1683d6c2bc0SMauro Carvalho Chehab 			mutex_unlock(&dmxdev->mutex);
1693d6c2bc0SMauro Carvalho Chehab 			return -ENOMEM;
1703d6c2bc0SMauro Carvalho Chehab 		}
1713d6c2bc0SMauro Carvalho Chehab 		dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
1720b23498aSMauro Carvalho Chehab 		if (dmxdev->may_do_mmap)
17357868accSSatendra Singh Thakur 			dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr",
17457868accSSatendra Singh Thakur 				     file->f_flags & O_NONBLOCK);
1753d6c2bc0SMauro Carvalho Chehab 		dvbdev->readers--;
1763d6c2bc0SMauro Carvalho Chehab 	}
1773d6c2bc0SMauro Carvalho Chehab 
1783d6c2bc0SMauro Carvalho Chehab 	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
1793d6c2bc0SMauro Carvalho Chehab 		dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
1803d6c2bc0SMauro Carvalho Chehab 
1813d6c2bc0SMauro Carvalho Chehab 		if (!dmxdev->demux->write) {
1823d6c2bc0SMauro Carvalho Chehab 			mutex_unlock(&dmxdev->mutex);
1833d6c2bc0SMauro Carvalho Chehab 			return -EOPNOTSUPP;
1843d6c2bc0SMauro Carvalho Chehab 		}
1853d6c2bc0SMauro Carvalho Chehab 
1863d6c2bc0SMauro Carvalho Chehab 		front = get_fe(dmxdev->demux, DMX_MEMORY_FE);
1873d6c2bc0SMauro Carvalho Chehab 
1883d6c2bc0SMauro Carvalho Chehab 		if (!front) {
1893d6c2bc0SMauro Carvalho Chehab 			mutex_unlock(&dmxdev->mutex);
1903d6c2bc0SMauro Carvalho Chehab 			return -EINVAL;
1913d6c2bc0SMauro Carvalho Chehab 		}
1923d6c2bc0SMauro Carvalho Chehab 		dmxdev->demux->disconnect_frontend(dmxdev->demux);
1933d6c2bc0SMauro Carvalho Chehab 		dmxdev->demux->connect_frontend(dmxdev->demux, front);
1943d6c2bc0SMauro Carvalho Chehab 	}
1953d6c2bc0SMauro Carvalho Chehab 	dvbdev->users++;
1963d6c2bc0SMauro Carvalho Chehab 	mutex_unlock(&dmxdev->mutex);
1973d6c2bc0SMauro Carvalho Chehab 	return 0;
1983d6c2bc0SMauro Carvalho Chehab }
1993d6c2bc0SMauro Carvalho Chehab 
dvb_dvr_release(struct inode * inode,struct file * file)2003d6c2bc0SMauro Carvalho Chehab static int dvb_dvr_release(struct inode *inode, struct file *file)
2013d6c2bc0SMauro Carvalho Chehab {
2023d6c2bc0SMauro Carvalho Chehab 	struct dvb_device *dvbdev = file->private_data;
2033d6c2bc0SMauro Carvalho Chehab 	struct dmxdev *dmxdev = dvbdev->priv;
2043d6c2bc0SMauro Carvalho Chehab 
2053d6c2bc0SMauro Carvalho Chehab 	mutex_lock(&dmxdev->mutex);
2063d6c2bc0SMauro Carvalho Chehab 
2073d6c2bc0SMauro Carvalho Chehab 	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
2083d6c2bc0SMauro Carvalho Chehab 		dmxdev->demux->disconnect_frontend(dmxdev->demux);
2093d6c2bc0SMauro Carvalho Chehab 		dmxdev->demux->connect_frontend(dmxdev->demux,
2103d6c2bc0SMauro Carvalho Chehab 						dmxdev->dvr_orig_fe);
2113d6c2bc0SMauro Carvalho Chehab 	}
2124021053eSMauro Carvalho Chehab 
2130b23498aSMauro Carvalho Chehab 	if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
2140b23498aSMauro Carvalho Chehab 	    dmxdev->may_do_mmap) {
2150b23498aSMauro Carvalho Chehab 		if (dmxdev->may_do_mmap) {
21657868accSSatendra Singh Thakur 			if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
21757868accSSatendra Singh Thakur 				dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx);
21857868accSSatendra Singh Thakur 			dvb_vb2_release(&dmxdev->dvr_vb2_ctx);
2190b23498aSMauro Carvalho Chehab 		}
2203d6c2bc0SMauro Carvalho Chehab 		dvbdev->readers++;
2213d6c2bc0SMauro Carvalho Chehab 		if (dmxdev->dvr_buffer.data) {
2223d6c2bc0SMauro Carvalho Chehab 			void *mem = dmxdev->dvr_buffer.data;
223e90bbacdSdevendra sharma 			/*memory barrier*/
2243d6c2bc0SMauro Carvalho Chehab 			mb();
2253d6c2bc0SMauro Carvalho Chehab 			spin_lock_irq(&dmxdev->lock);
2263d6c2bc0SMauro Carvalho Chehab 			dmxdev->dvr_buffer.data = NULL;
2273d6c2bc0SMauro Carvalho Chehab 			spin_unlock_irq(&dmxdev->lock);
2283d6c2bc0SMauro Carvalho Chehab 			vfree(mem);
2293d6c2bc0SMauro Carvalho Chehab 		}
2303d6c2bc0SMauro Carvalho Chehab 	}
2313d6c2bc0SMauro Carvalho Chehab 	/* TODO */
2323d6c2bc0SMauro Carvalho Chehab 	dvbdev->users--;
2333d6c2bc0SMauro Carvalho Chehab 	if (dvbdev->users == 1 && dmxdev->exit == 1) {
2343d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdev->mutex);
2353d6c2bc0SMauro Carvalho Chehab 		wake_up(&dvbdev->wait_queue);
2363d6c2bc0SMauro Carvalho Chehab 	} else
2373d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdev->mutex);
2383d6c2bc0SMauro Carvalho Chehab 
2393d6c2bc0SMauro Carvalho Chehab 	return 0;
2403d6c2bc0SMauro Carvalho Chehab }
2413d6c2bc0SMauro Carvalho Chehab 
dvb_dvr_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)2423d6c2bc0SMauro Carvalho Chehab static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
2433d6c2bc0SMauro Carvalho Chehab 			     size_t count, loff_t *ppos)
2443d6c2bc0SMauro Carvalho Chehab {
2453d6c2bc0SMauro Carvalho Chehab 	struct dvb_device *dvbdev = file->private_data;
2463d6c2bc0SMauro Carvalho Chehab 	struct dmxdev *dmxdev = dvbdev->priv;
2473d6c2bc0SMauro Carvalho Chehab 	int ret;
2483d6c2bc0SMauro Carvalho Chehab 
2493d6c2bc0SMauro Carvalho Chehab 	if (!dmxdev->demux->write)
2503d6c2bc0SMauro Carvalho Chehab 		return -EOPNOTSUPP;
2513d6c2bc0SMauro Carvalho Chehab 	if ((file->f_flags & O_ACCMODE) != O_WRONLY)
2523d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
2533d6c2bc0SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&dmxdev->mutex))
2543d6c2bc0SMauro Carvalho Chehab 		return -ERESTARTSYS;
2553d6c2bc0SMauro Carvalho Chehab 
2563d6c2bc0SMauro Carvalho Chehab 	if (dmxdev->exit) {
2573d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdev->mutex);
2583d6c2bc0SMauro Carvalho Chehab 		return -ENODEV;
2593d6c2bc0SMauro Carvalho Chehab 	}
2603d6c2bc0SMauro Carvalho Chehab 	ret = dmxdev->demux->write(dmxdev->demux, buf, count);
2613d6c2bc0SMauro Carvalho Chehab 	mutex_unlock(&dmxdev->mutex);
2623d6c2bc0SMauro Carvalho Chehab 	return ret;
2633d6c2bc0SMauro Carvalho Chehab }
2643d6c2bc0SMauro Carvalho Chehab 
dvb_dvr_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)2653d6c2bc0SMauro Carvalho Chehab static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
2663d6c2bc0SMauro Carvalho Chehab 			    loff_t *ppos)
2673d6c2bc0SMauro Carvalho Chehab {
2683d6c2bc0SMauro Carvalho Chehab 	struct dvb_device *dvbdev = file->private_data;
2693d6c2bc0SMauro Carvalho Chehab 	struct dmxdev *dmxdev = dvbdev->priv;
2703d6c2bc0SMauro Carvalho Chehab 
2713d6c2bc0SMauro Carvalho Chehab 	if (dmxdev->exit)
2723d6c2bc0SMauro Carvalho Chehab 		return -ENODEV;
2733d6c2bc0SMauro Carvalho Chehab 
2743d6c2bc0SMauro Carvalho Chehab 	return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
2753d6c2bc0SMauro Carvalho Chehab 				      file->f_flags & O_NONBLOCK,
2763d6c2bc0SMauro Carvalho Chehab 				      buf, count, ppos);
2773d6c2bc0SMauro Carvalho Chehab }
2783d6c2bc0SMauro Carvalho Chehab 
dvb_dvr_set_buffer_size(struct dmxdev * dmxdev,unsigned long size)2793d6c2bc0SMauro Carvalho Chehab static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
2803d6c2bc0SMauro Carvalho Chehab 				      unsigned long size)
2813d6c2bc0SMauro Carvalho Chehab {
2823d6c2bc0SMauro Carvalho Chehab 	struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
2833d6c2bc0SMauro Carvalho Chehab 	void *newmem;
2843d6c2bc0SMauro Carvalho Chehab 	void *oldmem;
2853d6c2bc0SMauro Carvalho Chehab 
286b3ad24d2SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
2873d6c2bc0SMauro Carvalho Chehab 
2883d6c2bc0SMauro Carvalho Chehab 	if (buf->size == size)
2893d6c2bc0SMauro Carvalho Chehab 		return 0;
2903d6c2bc0SMauro Carvalho Chehab 	if (!size)
2913d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
2923d6c2bc0SMauro Carvalho Chehab 
2933d6c2bc0SMauro Carvalho Chehab 	newmem = vmalloc(size);
2943d6c2bc0SMauro Carvalho Chehab 	if (!newmem)
2953d6c2bc0SMauro Carvalho Chehab 		return -ENOMEM;
2963d6c2bc0SMauro Carvalho Chehab 
2973d6c2bc0SMauro Carvalho Chehab 	oldmem = buf->data;
2983d6c2bc0SMauro Carvalho Chehab 
2993d6c2bc0SMauro Carvalho Chehab 	spin_lock_irq(&dmxdev->lock);
3003d6c2bc0SMauro Carvalho Chehab 	buf->data = newmem;
3013d6c2bc0SMauro Carvalho Chehab 	buf->size = size;
3023d6c2bc0SMauro Carvalho Chehab 
3033d6c2bc0SMauro Carvalho Chehab 	/* reset and not flush in case the buffer shrinks */
3043d6c2bc0SMauro Carvalho Chehab 	dvb_ringbuffer_reset(buf);
3053d6c2bc0SMauro Carvalho Chehab 	spin_unlock_irq(&dmxdev->lock);
3063d6c2bc0SMauro Carvalho Chehab 
3073d6c2bc0SMauro Carvalho Chehab 	vfree(oldmem);
3083d6c2bc0SMauro Carvalho Chehab 
3093d6c2bc0SMauro Carvalho Chehab 	return 0;
3103d6c2bc0SMauro Carvalho Chehab }
3113d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_filter_state_set(struct dmxdev_filter * dmxdevfilter,int state)3123d6c2bc0SMauro Carvalho Chehab static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
3133d6c2bc0SMauro Carvalho Chehab 					       *dmxdevfilter, int state)
3143d6c2bc0SMauro Carvalho Chehab {
3153d6c2bc0SMauro Carvalho Chehab 	spin_lock_irq(&dmxdevfilter->dev->lock);
3163d6c2bc0SMauro Carvalho Chehab 	dmxdevfilter->state = state;
3173d6c2bc0SMauro Carvalho Chehab 	spin_unlock_irq(&dmxdevfilter->dev->lock);
3183d6c2bc0SMauro Carvalho Chehab }
3193d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_set_buffer_size(struct dmxdev_filter * dmxdevfilter,unsigned long size)3203d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
3213d6c2bc0SMauro Carvalho Chehab 				      unsigned long size)
3223d6c2bc0SMauro Carvalho Chehab {
3233d6c2bc0SMauro Carvalho Chehab 	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
3243d6c2bc0SMauro Carvalho Chehab 	void *newmem;
3253d6c2bc0SMauro Carvalho Chehab 	void *oldmem;
3263d6c2bc0SMauro Carvalho Chehab 
3273d6c2bc0SMauro Carvalho Chehab 	if (buf->size == size)
3283d6c2bc0SMauro Carvalho Chehab 		return 0;
3293d6c2bc0SMauro Carvalho Chehab 	if (!size)
3303d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
3313d6c2bc0SMauro Carvalho Chehab 	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
3323d6c2bc0SMauro Carvalho Chehab 		return -EBUSY;
3333d6c2bc0SMauro Carvalho Chehab 
3343d6c2bc0SMauro Carvalho Chehab 	newmem = vmalloc(size);
3353d6c2bc0SMauro Carvalho Chehab 	if (!newmem)
3363d6c2bc0SMauro Carvalho Chehab 		return -ENOMEM;
3373d6c2bc0SMauro Carvalho Chehab 
3383d6c2bc0SMauro Carvalho Chehab 	oldmem = buf->data;
3393d6c2bc0SMauro Carvalho Chehab 
3403d6c2bc0SMauro Carvalho Chehab 	spin_lock_irq(&dmxdevfilter->dev->lock);
3413d6c2bc0SMauro Carvalho Chehab 	buf->data = newmem;
3423d6c2bc0SMauro Carvalho Chehab 	buf->size = size;
3433d6c2bc0SMauro Carvalho Chehab 
3443d6c2bc0SMauro Carvalho Chehab 	/* reset and not flush in case the buffer shrinks */
3453d6c2bc0SMauro Carvalho Chehab 	dvb_ringbuffer_reset(buf);
3463d6c2bc0SMauro Carvalho Chehab 	spin_unlock_irq(&dmxdevfilter->dev->lock);
3473d6c2bc0SMauro Carvalho Chehab 
3483d6c2bc0SMauro Carvalho Chehab 	vfree(oldmem);
3493d6c2bc0SMauro Carvalho Chehab 
3503d6c2bc0SMauro Carvalho Chehab 	return 0;
3513d6c2bc0SMauro Carvalho Chehab }
3523d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_filter_timeout(struct timer_list * t)353e7e0e2cfSKees Cook static void dvb_dmxdev_filter_timeout(struct timer_list *t)
3543d6c2bc0SMauro Carvalho Chehab {
355e7e0e2cfSKees Cook 	struct dmxdev_filter *dmxdevfilter = from_timer(dmxdevfilter, t, timer);
3563d6c2bc0SMauro Carvalho Chehab 
3573d6c2bc0SMauro Carvalho Chehab 	dmxdevfilter->buffer.error = -ETIMEDOUT;
3583d6c2bc0SMauro Carvalho Chehab 	spin_lock_irq(&dmxdevfilter->dev->lock);
3593d6c2bc0SMauro Carvalho Chehab 	dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
3603d6c2bc0SMauro Carvalho Chehab 	spin_unlock_irq(&dmxdevfilter->dev->lock);
3613d6c2bc0SMauro Carvalho Chehab 	wake_up(&dmxdevfilter->buffer.queue);
3623d6c2bc0SMauro Carvalho Chehab }
3633d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_filter_timer(struct dmxdev_filter * dmxdevfilter)3643d6c2bc0SMauro Carvalho Chehab static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
3653d6c2bc0SMauro Carvalho Chehab {
3663d6c2bc0SMauro Carvalho Chehab 	struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
3673d6c2bc0SMauro Carvalho Chehab 
3683d6c2bc0SMauro Carvalho Chehab 	del_timer(&dmxdevfilter->timer);
3693d6c2bc0SMauro Carvalho Chehab 	if (para->timeout) {
3703d6c2bc0SMauro Carvalho Chehab 		dmxdevfilter->timer.expires =
3713d6c2bc0SMauro Carvalho Chehab 		    jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
3723d6c2bc0SMauro Carvalho Chehab 		add_timer(&dmxdevfilter->timer);
3733d6c2bc0SMauro Carvalho Chehab 	}
3743d6c2bc0SMauro Carvalho Chehab }
3753d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_section_callback(const u8 * buffer1,size_t buffer1_len,const u8 * buffer2,size_t buffer2_len,struct dmx_section_filter * filter,u32 * buffer_flags)3763d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
3773d6c2bc0SMauro Carvalho Chehab 				       const u8 *buffer2, size_t buffer2_len,
378fdbeb962SMauro Carvalho Chehab 				       struct dmx_section_filter *filter,
379fdbeb962SMauro Carvalho Chehab 				       u32 *buffer_flags)
3803d6c2bc0SMauro Carvalho Chehab {
3813d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_filter *dmxdevfilter = filter->priv;
3823d6c2bc0SMauro Carvalho Chehab 	int ret;
3833d6c2bc0SMauro Carvalho Chehab 
38457868accSSatendra Singh Thakur 	if (!dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx) &&
38557868accSSatendra Singh Thakur 	    dmxdevfilter->buffer.error) {
3863d6c2bc0SMauro Carvalho Chehab 		wake_up(&dmxdevfilter->buffer.queue);
3873d6c2bc0SMauro Carvalho Chehab 		return 0;
3883d6c2bc0SMauro Carvalho Chehab 	}
3893d6c2bc0SMauro Carvalho Chehab 	spin_lock(&dmxdevfilter->dev->lock);
3903d6c2bc0SMauro Carvalho Chehab 	if (dmxdevfilter->state != DMXDEV_STATE_GO) {
3913d6c2bc0SMauro Carvalho Chehab 		spin_unlock(&dmxdevfilter->dev->lock);
3923d6c2bc0SMauro Carvalho Chehab 		return 0;
3933d6c2bc0SMauro Carvalho Chehab 	}
3943d6c2bc0SMauro Carvalho Chehab 	del_timer(&dmxdevfilter->timer);
395b3ad24d2SMauro Carvalho Chehab 	dprintk("section callback %*ph\n", 6, buffer1);
39657868accSSatendra Singh Thakur 	if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) {
39757868accSSatendra Singh Thakur 		ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
398fdbeb962SMauro Carvalho Chehab 					  buffer1, buffer1_len,
399fdbeb962SMauro Carvalho Chehab 					  buffer_flags);
40057868accSSatendra Singh Thakur 		if (ret == buffer1_len)
40157868accSSatendra Singh Thakur 			ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
402fdbeb962SMauro Carvalho Chehab 						  buffer2, buffer2_len,
403fdbeb962SMauro Carvalho Chehab 						  buffer_flags);
40457868accSSatendra Singh Thakur 	} else {
40557868accSSatendra Singh Thakur 		ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
40657868accSSatendra Singh Thakur 					      buffer1, buffer1_len);
4073d6c2bc0SMauro Carvalho Chehab 		if (ret == buffer1_len) {
40857868accSSatendra Singh Thakur 			ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
40957868accSSatendra Singh Thakur 						      buffer2, buffer2_len);
41057868accSSatendra Singh Thakur 		}
4113d6c2bc0SMauro Carvalho Chehab 	}
412414abbd2SSoeren Moch 	if (ret < 0)
4133d6c2bc0SMauro Carvalho Chehab 		dmxdevfilter->buffer.error = ret;
4143d6c2bc0SMauro Carvalho Chehab 	if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
4153d6c2bc0SMauro Carvalho Chehab 		dmxdevfilter->state = DMXDEV_STATE_DONE;
4163d6c2bc0SMauro Carvalho Chehab 	spin_unlock(&dmxdevfilter->dev->lock);
4173d6c2bc0SMauro Carvalho Chehab 	wake_up(&dmxdevfilter->buffer.queue);
4183d6c2bc0SMauro Carvalho Chehab 	return 0;
4193d6c2bc0SMauro Carvalho Chehab }
4203d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_ts_callback(const u8 * buffer1,size_t buffer1_len,const u8 * buffer2,size_t buffer2_len,struct dmx_ts_feed * feed,u32 * buffer_flags)4213d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
4223d6c2bc0SMauro Carvalho Chehab 				  const u8 *buffer2, size_t buffer2_len,
423fdbeb962SMauro Carvalho Chehab 				  struct dmx_ts_feed *feed,
424fdbeb962SMauro Carvalho Chehab 				  u32 *buffer_flags)
4253d6c2bc0SMauro Carvalho Chehab {
4263d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_filter *dmxdevfilter = feed->priv;
4273d6c2bc0SMauro Carvalho Chehab 	struct dvb_ringbuffer *buffer;
428ec5b1004SArnd Bergmann #ifdef CONFIG_DVB_MMAP
42957868accSSatendra Singh Thakur 	struct dvb_vb2_ctx *ctx;
4304021053eSMauro Carvalho Chehab #endif
4313d6c2bc0SMauro Carvalho Chehab 	int ret;
4323d6c2bc0SMauro Carvalho Chehab 
4333d6c2bc0SMauro Carvalho Chehab 	spin_lock(&dmxdevfilter->dev->lock);
4343d6c2bc0SMauro Carvalho Chehab 	if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
4353d6c2bc0SMauro Carvalho Chehab 		spin_unlock(&dmxdevfilter->dev->lock);
4363d6c2bc0SMauro Carvalho Chehab 		return 0;
4373d6c2bc0SMauro Carvalho Chehab 	}
4383d6c2bc0SMauro Carvalho Chehab 
43957868accSSatendra Singh Thakur 	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP ||
44057868accSSatendra Singh Thakur 	    dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
4413d6c2bc0SMauro Carvalho Chehab 		buffer = &dmxdevfilter->buffer;
442ec5b1004SArnd Bergmann #ifdef CONFIG_DVB_MMAP
44357868accSSatendra Singh Thakur 		ctx = &dmxdevfilter->vb2_ctx;
4444021053eSMauro Carvalho Chehab #endif
44557868accSSatendra Singh Thakur 	} else {
4463d6c2bc0SMauro Carvalho Chehab 		buffer = &dmxdevfilter->dev->dvr_buffer;
447ec5b1004SArnd Bergmann #ifdef CONFIG_DVB_MMAP
44857868accSSatendra Singh Thakur 		ctx = &dmxdevfilter->dev->dvr_vb2_ctx;
4494021053eSMauro Carvalho Chehab #endif
45057868accSSatendra Singh Thakur 	}
45157868accSSatendra Singh Thakur 
45257868accSSatendra Singh Thakur 	if (dvb_vb2_is_streaming(ctx)) {
453fdbeb962SMauro Carvalho Chehab 		ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len,
454fdbeb962SMauro Carvalho Chehab 					  buffer_flags);
45557868accSSatendra Singh Thakur 		if (ret == buffer1_len)
456fdbeb962SMauro Carvalho Chehab 			ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len,
457fdbeb962SMauro Carvalho Chehab 						  buffer_flags);
45857868accSSatendra Singh Thakur 	} else {
4593d6c2bc0SMauro Carvalho Chehab 		if (buffer->error) {
4603d6c2bc0SMauro Carvalho Chehab 			spin_unlock(&dmxdevfilter->dev->lock);
4613d6c2bc0SMauro Carvalho Chehab 			wake_up(&buffer->queue);
4623d6c2bc0SMauro Carvalho Chehab 			return 0;
4633d6c2bc0SMauro Carvalho Chehab 		}
4643d6c2bc0SMauro Carvalho Chehab 		ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
4653d6c2bc0SMauro Carvalho Chehab 		if (ret == buffer1_len)
46657868accSSatendra Singh Thakur 			ret = dvb_dmxdev_buffer_write(buffer,
46757868accSSatendra Singh Thakur 						      buffer2, buffer2_len);
46857868accSSatendra Singh Thakur 	}
469414abbd2SSoeren Moch 	if (ret < 0)
4703d6c2bc0SMauro Carvalho Chehab 		buffer->error = ret;
4713d6c2bc0SMauro Carvalho Chehab 	spin_unlock(&dmxdevfilter->dev->lock);
4723d6c2bc0SMauro Carvalho Chehab 	wake_up(&buffer->queue);
4733d6c2bc0SMauro Carvalho Chehab 	return 0;
4743d6c2bc0SMauro Carvalho Chehab }
4753d6c2bc0SMauro Carvalho Chehab 
4763d6c2bc0SMauro Carvalho Chehab /* stop feed but only mark the specified filter as stopped (state set) */
dvb_dmxdev_feed_stop(struct dmxdev_filter * dmxdevfilter)4773d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
4783d6c2bc0SMauro Carvalho Chehab {
4793d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_feed *feed;
4803d6c2bc0SMauro Carvalho Chehab 
4813d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
4823d6c2bc0SMauro Carvalho Chehab 
4833d6c2bc0SMauro Carvalho Chehab 	switch (dmxdevfilter->type) {
4843d6c2bc0SMauro Carvalho Chehab 	case DMXDEV_TYPE_SEC:
4853d6c2bc0SMauro Carvalho Chehab 		del_timer(&dmxdevfilter->timer);
4863d6c2bc0SMauro Carvalho Chehab 		dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
4873d6c2bc0SMauro Carvalho Chehab 		break;
4883d6c2bc0SMauro Carvalho Chehab 	case DMXDEV_TYPE_PES:
4893d6c2bc0SMauro Carvalho Chehab 		list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
4903d6c2bc0SMauro Carvalho Chehab 			feed->ts->stop_filtering(feed->ts);
4913d6c2bc0SMauro Carvalho Chehab 		break;
4923d6c2bc0SMauro Carvalho Chehab 	default:
4933d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
4943d6c2bc0SMauro Carvalho Chehab 	}
4953d6c2bc0SMauro Carvalho Chehab 	return 0;
4963d6c2bc0SMauro Carvalho Chehab }
4973d6c2bc0SMauro Carvalho Chehab 
4983d6c2bc0SMauro Carvalho Chehab /* start feed associated with the specified filter */
dvb_dmxdev_feed_start(struct dmxdev_filter * filter)4993d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
5003d6c2bc0SMauro Carvalho Chehab {
5013d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_feed *feed;
5023d6c2bc0SMauro Carvalho Chehab 	int ret;
5033d6c2bc0SMauro Carvalho Chehab 
5043d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
5053d6c2bc0SMauro Carvalho Chehab 
5063d6c2bc0SMauro Carvalho Chehab 	switch (filter->type) {
5073d6c2bc0SMauro Carvalho Chehab 	case DMXDEV_TYPE_SEC:
5083d6c2bc0SMauro Carvalho Chehab 		return filter->feed.sec->start_filtering(filter->feed.sec);
5093d6c2bc0SMauro Carvalho Chehab 	case DMXDEV_TYPE_PES:
5103d6c2bc0SMauro Carvalho Chehab 		list_for_each_entry(feed, &filter->feed.ts, next) {
5113d6c2bc0SMauro Carvalho Chehab 			ret = feed->ts->start_filtering(feed->ts);
5123d6c2bc0SMauro Carvalho Chehab 			if (ret < 0) {
5133d6c2bc0SMauro Carvalho Chehab 				dvb_dmxdev_feed_stop(filter);
5143d6c2bc0SMauro Carvalho Chehab 				return ret;
5153d6c2bc0SMauro Carvalho Chehab 			}
5163d6c2bc0SMauro Carvalho Chehab 		}
5173d6c2bc0SMauro Carvalho Chehab 		break;
5183d6c2bc0SMauro Carvalho Chehab 	default:
5193d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
5203d6c2bc0SMauro Carvalho Chehab 	}
5213d6c2bc0SMauro Carvalho Chehab 
5223d6c2bc0SMauro Carvalho Chehab 	return 0;
5233d6c2bc0SMauro Carvalho Chehab }
5243d6c2bc0SMauro Carvalho Chehab 
5253d6c2bc0SMauro Carvalho Chehab /* restart section feed if it has filters left associated with it,
5263d6c2bc0SMauro Carvalho Chehab    otherwise release the feed */
dvb_dmxdev_feed_restart(struct dmxdev_filter * filter)5273d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
5283d6c2bc0SMauro Carvalho Chehab {
5293d6c2bc0SMauro Carvalho Chehab 	int i;
5303d6c2bc0SMauro Carvalho Chehab 	struct dmxdev *dmxdev = filter->dev;
5313d6c2bc0SMauro Carvalho Chehab 	u16 pid = filter->params.sec.pid;
5323d6c2bc0SMauro Carvalho Chehab 
5333d6c2bc0SMauro Carvalho Chehab 	for (i = 0; i < dmxdev->filternum; i++)
5343d6c2bc0SMauro Carvalho Chehab 		if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
5353d6c2bc0SMauro Carvalho Chehab 		    dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
5363d6c2bc0SMauro Carvalho Chehab 		    dmxdev->filter[i].params.sec.pid == pid) {
5373d6c2bc0SMauro Carvalho Chehab 			dvb_dmxdev_feed_start(&dmxdev->filter[i]);
5383d6c2bc0SMauro Carvalho Chehab 			return 0;
5393d6c2bc0SMauro Carvalho Chehab 		}
5403d6c2bc0SMauro Carvalho Chehab 
5413d6c2bc0SMauro Carvalho Chehab 	filter->dev->demux->release_section_feed(dmxdev->demux,
5423d6c2bc0SMauro Carvalho Chehab 						 filter->feed.sec);
5433d6c2bc0SMauro Carvalho Chehab 
5443d6c2bc0SMauro Carvalho Chehab 	return 0;
5453d6c2bc0SMauro Carvalho Chehab }
5463d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_filter_stop(struct dmxdev_filter * dmxdevfilter)5473d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
5483d6c2bc0SMauro Carvalho Chehab {
5493d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_feed *feed;
5503d6c2bc0SMauro Carvalho Chehab 	struct dmx_demux *demux;
5513d6c2bc0SMauro Carvalho Chehab 
5523d6c2bc0SMauro Carvalho Chehab 	if (dmxdevfilter->state < DMXDEV_STATE_GO)
5533d6c2bc0SMauro Carvalho Chehab 		return 0;
5543d6c2bc0SMauro Carvalho Chehab 
5553d6c2bc0SMauro Carvalho Chehab 	switch (dmxdevfilter->type) {
5563d6c2bc0SMauro Carvalho Chehab 	case DMXDEV_TYPE_SEC:
5573d6c2bc0SMauro Carvalho Chehab 		if (!dmxdevfilter->feed.sec)
5583d6c2bc0SMauro Carvalho Chehab 			break;
5593d6c2bc0SMauro Carvalho Chehab 		dvb_dmxdev_feed_stop(dmxdevfilter);
5603d6c2bc0SMauro Carvalho Chehab 		if (dmxdevfilter->filter.sec)
5613d6c2bc0SMauro Carvalho Chehab 			dmxdevfilter->feed.sec->
5623d6c2bc0SMauro Carvalho Chehab 			    release_filter(dmxdevfilter->feed.sec,
5633d6c2bc0SMauro Carvalho Chehab 					   dmxdevfilter->filter.sec);
5643d6c2bc0SMauro Carvalho Chehab 		dvb_dmxdev_feed_restart(dmxdevfilter);
5653d6c2bc0SMauro Carvalho Chehab 		dmxdevfilter->feed.sec = NULL;
5663d6c2bc0SMauro Carvalho Chehab 		break;
5673d6c2bc0SMauro Carvalho Chehab 	case DMXDEV_TYPE_PES:
5683d6c2bc0SMauro Carvalho Chehab 		dvb_dmxdev_feed_stop(dmxdevfilter);
5693d6c2bc0SMauro Carvalho Chehab 		demux = dmxdevfilter->dev->demux;
5703d6c2bc0SMauro Carvalho Chehab 		list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
5713d6c2bc0SMauro Carvalho Chehab 			demux->release_ts_feed(demux, feed->ts);
5723d6c2bc0SMauro Carvalho Chehab 			feed->ts = NULL;
5733d6c2bc0SMauro Carvalho Chehab 		}
5743d6c2bc0SMauro Carvalho Chehab 		break;
5753d6c2bc0SMauro Carvalho Chehab 	default:
5763d6c2bc0SMauro Carvalho Chehab 		if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
5773d6c2bc0SMauro Carvalho Chehab 			return 0;
5783d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
5793d6c2bc0SMauro Carvalho Chehab 	}
5803d6c2bc0SMauro Carvalho Chehab 
5813d6c2bc0SMauro Carvalho Chehab 	dvb_ringbuffer_flush(&dmxdevfilter->buffer);
5823d6c2bc0SMauro Carvalho Chehab 	return 0;
5833d6c2bc0SMauro Carvalho Chehab }
5843d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_delete_pids(struct dmxdev_filter * dmxdevfilter)5853d6c2bc0SMauro Carvalho Chehab static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
5863d6c2bc0SMauro Carvalho Chehab {
5873d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_feed *feed, *tmp;
5883d6c2bc0SMauro Carvalho Chehab 
5893d6c2bc0SMauro Carvalho Chehab 	/* delete all PIDs */
5903d6c2bc0SMauro Carvalho Chehab 	list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
5913d6c2bc0SMauro Carvalho Chehab 		list_del(&feed->next);
5923d6c2bc0SMauro Carvalho Chehab 		kfree(feed);
5933d6c2bc0SMauro Carvalho Chehab 	}
5943d6c2bc0SMauro Carvalho Chehab 
5953d6c2bc0SMauro Carvalho Chehab 	BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
5963d6c2bc0SMauro Carvalho Chehab }
5973d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_filter_reset(struct dmxdev_filter * dmxdevfilter)5983d6c2bc0SMauro Carvalho Chehab static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
5993d6c2bc0SMauro Carvalho Chehab {
6003d6c2bc0SMauro Carvalho Chehab 	if (dmxdevfilter->state < DMXDEV_STATE_SET)
6013d6c2bc0SMauro Carvalho Chehab 		return 0;
6023d6c2bc0SMauro Carvalho Chehab 
6033d6c2bc0SMauro Carvalho Chehab 	if (dmxdevfilter->type == DMXDEV_TYPE_PES)
6043d6c2bc0SMauro Carvalho Chehab 		dvb_dmxdev_delete_pids(dmxdevfilter);
6053d6c2bc0SMauro Carvalho Chehab 
6063d6c2bc0SMauro Carvalho Chehab 	dmxdevfilter->type = DMXDEV_TYPE_NONE;
6073d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
6083d6c2bc0SMauro Carvalho Chehab 	return 0;
6093d6c2bc0SMauro Carvalho Chehab }
6103d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_start_feed(struct dmxdev * dmxdev,struct dmxdev_filter * filter,struct dmxdev_feed * feed)6113d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
6123d6c2bc0SMauro Carvalho Chehab 				 struct dmxdev_filter *filter,
6133d6c2bc0SMauro Carvalho Chehab 				 struct dmxdev_feed *feed)
6143d6c2bc0SMauro Carvalho Chehab {
615dde67d50SJasmin Jessich 	ktime_t timeout = ktime_set(0, 0);
6163d6c2bc0SMauro Carvalho Chehab 	struct dmx_pes_filter_params *para = &filter->params.pes;
6173256b36eSMauro Carvalho Chehab 	enum dmx_output otype;
6183d6c2bc0SMauro Carvalho Chehab 	int ret;
6193d6c2bc0SMauro Carvalho Chehab 	int ts_type;
620fde04ab9SMauro Carvalho Chehab 	enum dmx_ts_pes ts_pes;
6213d6c2bc0SMauro Carvalho Chehab 	struct dmx_ts_feed *tsfeed;
6223d6c2bc0SMauro Carvalho Chehab 
6233d6c2bc0SMauro Carvalho Chehab 	feed->ts = NULL;
6243d6c2bc0SMauro Carvalho Chehab 	otype = para->output;
6253d6c2bc0SMauro Carvalho Chehab 
6263d6c2bc0SMauro Carvalho Chehab 	ts_pes = para->pes_type;
6273d6c2bc0SMauro Carvalho Chehab 
6283d6c2bc0SMauro Carvalho Chehab 	if (ts_pes < DMX_PES_OTHER)
6293d6c2bc0SMauro Carvalho Chehab 		ts_type = TS_DECODER;
6303d6c2bc0SMauro Carvalho Chehab 	else
6313d6c2bc0SMauro Carvalho Chehab 		ts_type = 0;
6323d6c2bc0SMauro Carvalho Chehab 
6333d6c2bc0SMauro Carvalho Chehab 	if (otype == DMX_OUT_TS_TAP)
6343d6c2bc0SMauro Carvalho Chehab 		ts_type |= TS_PACKET;
6353d6c2bc0SMauro Carvalho Chehab 	else if (otype == DMX_OUT_TSDEMUX_TAP)
6363d6c2bc0SMauro Carvalho Chehab 		ts_type |= TS_PACKET | TS_DEMUX;
6373d6c2bc0SMauro Carvalho Chehab 	else if (otype == DMX_OUT_TAP)
6383d6c2bc0SMauro Carvalho Chehab 		ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
6393d6c2bc0SMauro Carvalho Chehab 
6403d6c2bc0SMauro Carvalho Chehab 	ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
6413d6c2bc0SMauro Carvalho Chehab 					      dvb_dmxdev_ts_callback);
6423d6c2bc0SMauro Carvalho Chehab 	if (ret < 0)
6433d6c2bc0SMauro Carvalho Chehab 		return ret;
6443d6c2bc0SMauro Carvalho Chehab 
6453d6c2bc0SMauro Carvalho Chehab 	tsfeed = feed->ts;
6463d6c2bc0SMauro Carvalho Chehab 	tsfeed->priv = filter;
6473d6c2bc0SMauro Carvalho Chehab 
648dd79d27eSMauro Carvalho Chehab 	ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, timeout);
6493d6c2bc0SMauro Carvalho Chehab 	if (ret < 0) {
6503d6c2bc0SMauro Carvalho Chehab 		dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
6513d6c2bc0SMauro Carvalho Chehab 		return ret;
6523d6c2bc0SMauro Carvalho Chehab 	}
6533d6c2bc0SMauro Carvalho Chehab 
6543d6c2bc0SMauro Carvalho Chehab 	ret = tsfeed->start_filtering(tsfeed);
6553d6c2bc0SMauro Carvalho Chehab 	if (ret < 0) {
6563d6c2bc0SMauro Carvalho Chehab 		dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
6573d6c2bc0SMauro Carvalho Chehab 		return ret;
6583d6c2bc0SMauro Carvalho Chehab 	}
6593d6c2bc0SMauro Carvalho Chehab 
6603d6c2bc0SMauro Carvalho Chehab 	return 0;
6613d6c2bc0SMauro Carvalho Chehab }
6623d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_filter_start(struct dmxdev_filter * filter)6633d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
6643d6c2bc0SMauro Carvalho Chehab {
6653d6c2bc0SMauro Carvalho Chehab 	struct dmxdev *dmxdev = filter->dev;
6663d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_feed *feed;
6673d6c2bc0SMauro Carvalho Chehab 	void *mem;
6683d6c2bc0SMauro Carvalho Chehab 	int ret, i;
6693d6c2bc0SMauro Carvalho Chehab 
6703d6c2bc0SMauro Carvalho Chehab 	if (filter->state < DMXDEV_STATE_SET)
6713d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
6723d6c2bc0SMauro Carvalho Chehab 
6733d6c2bc0SMauro Carvalho Chehab 	if (filter->state >= DMXDEV_STATE_GO)
6743d6c2bc0SMauro Carvalho Chehab 		dvb_dmxdev_filter_stop(filter);
6753d6c2bc0SMauro Carvalho Chehab 
6763d6c2bc0SMauro Carvalho Chehab 	if (!filter->buffer.data) {
6773d6c2bc0SMauro Carvalho Chehab 		mem = vmalloc(filter->buffer.size);
6783d6c2bc0SMauro Carvalho Chehab 		if (!mem)
6793d6c2bc0SMauro Carvalho Chehab 			return -ENOMEM;
6803d6c2bc0SMauro Carvalho Chehab 		spin_lock_irq(&filter->dev->lock);
6813d6c2bc0SMauro Carvalho Chehab 		filter->buffer.data = mem;
6823d6c2bc0SMauro Carvalho Chehab 		spin_unlock_irq(&filter->dev->lock);
6833d6c2bc0SMauro Carvalho Chehab 	}
6843d6c2bc0SMauro Carvalho Chehab 
6853d6c2bc0SMauro Carvalho Chehab 	dvb_ringbuffer_flush(&filter->buffer);
6863d6c2bc0SMauro Carvalho Chehab 
6873d6c2bc0SMauro Carvalho Chehab 	switch (filter->type) {
6883d6c2bc0SMauro Carvalho Chehab 	case DMXDEV_TYPE_SEC:
6893d6c2bc0SMauro Carvalho Chehab 	{
6903d6c2bc0SMauro Carvalho Chehab 		struct dmx_sct_filter_params *para = &filter->params.sec;
6913d6c2bc0SMauro Carvalho Chehab 		struct dmx_section_filter **secfilter = &filter->filter.sec;
6923d6c2bc0SMauro Carvalho Chehab 		struct dmx_section_feed **secfeed = &filter->feed.sec;
6933d6c2bc0SMauro Carvalho Chehab 
6943d6c2bc0SMauro Carvalho Chehab 		*secfilter = NULL;
6953d6c2bc0SMauro Carvalho Chehab 		*secfeed = NULL;
6963d6c2bc0SMauro Carvalho Chehab 
6973d6c2bc0SMauro Carvalho Chehab 
6983d6c2bc0SMauro Carvalho Chehab 		/* find active filter/feed with same PID */
6993d6c2bc0SMauro Carvalho Chehab 		for (i = 0; i < dmxdev->filternum; i++) {
7003d6c2bc0SMauro Carvalho Chehab 			if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
7013d6c2bc0SMauro Carvalho Chehab 			    dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
7023d6c2bc0SMauro Carvalho Chehab 			    dmxdev->filter[i].params.sec.pid == para->pid) {
7033d6c2bc0SMauro Carvalho Chehab 				*secfeed = dmxdev->filter[i].feed.sec;
7043d6c2bc0SMauro Carvalho Chehab 				break;
7053d6c2bc0SMauro Carvalho Chehab 			}
7063d6c2bc0SMauro Carvalho Chehab 		}
7073d6c2bc0SMauro Carvalho Chehab 
7083d6c2bc0SMauro Carvalho Chehab 		/* if no feed found, try to allocate new one */
7093d6c2bc0SMauro Carvalho Chehab 		if (!*secfeed) {
7103d6c2bc0SMauro Carvalho Chehab 			ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
7113d6c2bc0SMauro Carvalho Chehab 								   secfeed,
7123d6c2bc0SMauro Carvalho Chehab 								   dvb_dmxdev_section_callback);
7133d42c93eSMauro Carvalho Chehab 			if (!*secfeed) {
714b3ad24d2SMauro Carvalho Chehab 				pr_err("DVB (%s): could not alloc feed\n",
7153d6c2bc0SMauro Carvalho Chehab 				       __func__);
7163d6c2bc0SMauro Carvalho Chehab 				return ret;
7173d6c2bc0SMauro Carvalho Chehab 			}
7183d6c2bc0SMauro Carvalho Chehab 
719dd79d27eSMauro Carvalho Chehab 			ret = (*secfeed)->set(*secfeed, para->pid,
7203d6c2bc0SMauro Carvalho Chehab 					      (para->flags & DMX_CHECK_CRC) ? 1 : 0);
7213d6c2bc0SMauro Carvalho Chehab 			if (ret < 0) {
722b3ad24d2SMauro Carvalho Chehab 				pr_err("DVB (%s): could not set feed\n",
7233d6c2bc0SMauro Carvalho Chehab 				       __func__);
7243d6c2bc0SMauro Carvalho Chehab 				dvb_dmxdev_feed_restart(filter);
7253d6c2bc0SMauro Carvalho Chehab 				return ret;
7263d6c2bc0SMauro Carvalho Chehab 			}
7273d6c2bc0SMauro Carvalho Chehab 		} else {
7283d6c2bc0SMauro Carvalho Chehab 			dvb_dmxdev_feed_stop(filter);
7293d6c2bc0SMauro Carvalho Chehab 		}
7303d6c2bc0SMauro Carvalho Chehab 
7313d6c2bc0SMauro Carvalho Chehab 		ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
7323d6c2bc0SMauro Carvalho Chehab 		if (ret < 0) {
7333d6c2bc0SMauro Carvalho Chehab 			dvb_dmxdev_feed_restart(filter);
7343d6c2bc0SMauro Carvalho Chehab 			filter->feed.sec->start_filtering(*secfeed);
7353d6c2bc0SMauro Carvalho Chehab 			dprintk("could not get filter\n");
7363d6c2bc0SMauro Carvalho Chehab 			return ret;
7373d6c2bc0SMauro Carvalho Chehab 		}
7383d6c2bc0SMauro Carvalho Chehab 
7393d6c2bc0SMauro Carvalho Chehab 		(*secfilter)->priv = filter;
7403d6c2bc0SMauro Carvalho Chehab 
7413d6c2bc0SMauro Carvalho Chehab 		memcpy(&((*secfilter)->filter_value[3]),
7423d6c2bc0SMauro Carvalho Chehab 		       &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
7433d6c2bc0SMauro Carvalho Chehab 		memcpy(&(*secfilter)->filter_mask[3],
7443d6c2bc0SMauro Carvalho Chehab 		       &para->filter.mask[1], DMX_FILTER_SIZE - 1);
7453d6c2bc0SMauro Carvalho Chehab 		memcpy(&(*secfilter)->filter_mode[3],
7463d6c2bc0SMauro Carvalho Chehab 		       &para->filter.mode[1], DMX_FILTER_SIZE - 1);
7473d6c2bc0SMauro Carvalho Chehab 
7483d6c2bc0SMauro Carvalho Chehab 		(*secfilter)->filter_value[0] = para->filter.filter[0];
7493d6c2bc0SMauro Carvalho Chehab 		(*secfilter)->filter_mask[0] = para->filter.mask[0];
7503d6c2bc0SMauro Carvalho Chehab 		(*secfilter)->filter_mode[0] = para->filter.mode[0];
7513d6c2bc0SMauro Carvalho Chehab 		(*secfilter)->filter_mask[1] = 0;
7523d6c2bc0SMauro Carvalho Chehab 		(*secfilter)->filter_mask[2] = 0;
7533d6c2bc0SMauro Carvalho Chehab 
7543d6c2bc0SMauro Carvalho Chehab 		filter->todo = 0;
7553d6c2bc0SMauro Carvalho Chehab 
7563d6c2bc0SMauro Carvalho Chehab 		ret = filter->feed.sec->start_filtering(filter->feed.sec);
7573d6c2bc0SMauro Carvalho Chehab 		if (ret < 0)
7583d6c2bc0SMauro Carvalho Chehab 			return ret;
7593d6c2bc0SMauro Carvalho Chehab 
7603d6c2bc0SMauro Carvalho Chehab 		dvb_dmxdev_filter_timer(filter);
7613d6c2bc0SMauro Carvalho Chehab 		break;
7623d6c2bc0SMauro Carvalho Chehab 	}
7633d6c2bc0SMauro Carvalho Chehab 	case DMXDEV_TYPE_PES:
7643d6c2bc0SMauro Carvalho Chehab 		list_for_each_entry(feed, &filter->feed.ts, next) {
7653d6c2bc0SMauro Carvalho Chehab 			ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
7663d6c2bc0SMauro Carvalho Chehab 			if (ret < 0) {
7673d6c2bc0SMauro Carvalho Chehab 				dvb_dmxdev_filter_stop(filter);
7683d6c2bc0SMauro Carvalho Chehab 				return ret;
7693d6c2bc0SMauro Carvalho Chehab 			}
7703d6c2bc0SMauro Carvalho Chehab 		}
7713d6c2bc0SMauro Carvalho Chehab 		break;
7723d6c2bc0SMauro Carvalho Chehab 	default:
7733d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
7743d6c2bc0SMauro Carvalho Chehab 	}
7753d6c2bc0SMauro Carvalho Chehab 
7763d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
7773d6c2bc0SMauro Carvalho Chehab 	return 0;
7783d6c2bc0SMauro Carvalho Chehab }
7793d6c2bc0SMauro Carvalho Chehab 
dvb_demux_open(struct inode * inode,struct file * file)7803d6c2bc0SMauro Carvalho Chehab static int dvb_demux_open(struct inode *inode, struct file *file)
7813d6c2bc0SMauro Carvalho Chehab {
7823d6c2bc0SMauro Carvalho Chehab 	struct dvb_device *dvbdev = file->private_data;
7833d6c2bc0SMauro Carvalho Chehab 	struct dmxdev *dmxdev = dvbdev->priv;
7843d6c2bc0SMauro Carvalho Chehab 	int i;
7853d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_filter *dmxdevfilter;
7863d6c2bc0SMauro Carvalho Chehab 
7873d6c2bc0SMauro Carvalho Chehab 	if (!dmxdev->filter)
7883d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
7893d6c2bc0SMauro Carvalho Chehab 
7903d6c2bc0SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&dmxdev->mutex))
7913d6c2bc0SMauro Carvalho Chehab 		return -ERESTARTSYS;
7923d6c2bc0SMauro Carvalho Chehab 
793*fd3d91abSTakashi Iwai 	if (dmxdev->exit) {
794*fd3d91abSTakashi Iwai 		mutex_unlock(&dmxdev->mutex);
795*fd3d91abSTakashi Iwai 		return -ENODEV;
796*fd3d91abSTakashi Iwai 	}
797*fd3d91abSTakashi Iwai 
7983d6c2bc0SMauro Carvalho Chehab 	for (i = 0; i < dmxdev->filternum; i++)
7993d6c2bc0SMauro Carvalho Chehab 		if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
8003d6c2bc0SMauro Carvalho Chehab 			break;
8013d6c2bc0SMauro Carvalho Chehab 
8023d6c2bc0SMauro Carvalho Chehab 	if (i == dmxdev->filternum) {
8033d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdev->mutex);
8043d6c2bc0SMauro Carvalho Chehab 		return -EMFILE;
8053d6c2bc0SMauro Carvalho Chehab 	}
8063d6c2bc0SMauro Carvalho Chehab 
8073d6c2bc0SMauro Carvalho Chehab 	dmxdevfilter = &dmxdev->filter[i];
8083d6c2bc0SMauro Carvalho Chehab 	mutex_init(&dmxdevfilter->mutex);
8093d6c2bc0SMauro Carvalho Chehab 	file->private_data = dmxdevfilter;
8103d6c2bc0SMauro Carvalho Chehab 
8110b23498aSMauro Carvalho Chehab #ifdef CONFIG_DVB_MMAP
8120b23498aSMauro Carvalho Chehab 	dmxdev->may_do_mmap = 1;
8130b23498aSMauro Carvalho Chehab #else
8140b23498aSMauro Carvalho Chehab 	dmxdev->may_do_mmap = 0;
8150b23498aSMauro Carvalho Chehab #endif
8160b23498aSMauro Carvalho Chehab 
8173d6c2bc0SMauro Carvalho Chehab 	dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
81857868accSSatendra Singh Thakur 	dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter",
81957868accSSatendra Singh Thakur 		     file->f_flags & O_NONBLOCK);
8203d6c2bc0SMauro Carvalho Chehab 	dmxdevfilter->type = DMXDEV_TYPE_NONE;
8213d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
822e7e0e2cfSKees Cook 	timer_setup(&dmxdevfilter->timer, dvb_dmxdev_filter_timeout, 0);
8233d6c2bc0SMauro Carvalho Chehab 
8243d6c2bc0SMauro Carvalho Chehab 	dvbdev->users++;
8253d6c2bc0SMauro Carvalho Chehab 
8263d6c2bc0SMauro Carvalho Chehab 	mutex_unlock(&dmxdev->mutex);
8273d6c2bc0SMauro Carvalho Chehab 	return 0;
8283d6c2bc0SMauro Carvalho Chehab }
8293d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_filter_free(struct dmxdev * dmxdev,struct dmxdev_filter * dmxdevfilter)8303d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
8313d6c2bc0SMauro Carvalho Chehab 				  struct dmxdev_filter *dmxdevfilter)
8323d6c2bc0SMauro Carvalho Chehab {
8333d6c2bc0SMauro Carvalho Chehab 	mutex_lock(&dmxdev->mutex);
8343d6c2bc0SMauro Carvalho Chehab 	mutex_lock(&dmxdevfilter->mutex);
83557868accSSatendra Singh Thakur 	if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
83657868accSSatendra Singh Thakur 		dvb_vb2_stream_off(&dmxdevfilter->vb2_ctx);
83757868accSSatendra Singh Thakur 	dvb_vb2_release(&dmxdevfilter->vb2_ctx);
83857868accSSatendra Singh Thakur 
8393d6c2bc0SMauro Carvalho Chehab 
8403d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_stop(dmxdevfilter);
8413d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_reset(dmxdevfilter);
8423d6c2bc0SMauro Carvalho Chehab 
8433d6c2bc0SMauro Carvalho Chehab 	if (dmxdevfilter->buffer.data) {
8443d6c2bc0SMauro Carvalho Chehab 		void *mem = dmxdevfilter->buffer.data;
8453d6c2bc0SMauro Carvalho Chehab 
8463d6c2bc0SMauro Carvalho Chehab 		spin_lock_irq(&dmxdev->lock);
8473d6c2bc0SMauro Carvalho Chehab 		dmxdevfilter->buffer.data = NULL;
8483d6c2bc0SMauro Carvalho Chehab 		spin_unlock_irq(&dmxdev->lock);
8493d6c2bc0SMauro Carvalho Chehab 		vfree(mem);
8503d6c2bc0SMauro Carvalho Chehab 	}
8513d6c2bc0SMauro Carvalho Chehab 
8523d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
8533d6c2bc0SMauro Carvalho Chehab 	wake_up(&dmxdevfilter->buffer.queue);
8543d6c2bc0SMauro Carvalho Chehab 	mutex_unlock(&dmxdevfilter->mutex);
8553d6c2bc0SMauro Carvalho Chehab 	mutex_unlock(&dmxdev->mutex);
8563d6c2bc0SMauro Carvalho Chehab 	return 0;
8573d6c2bc0SMauro Carvalho Chehab }
8583d6c2bc0SMauro Carvalho Chehab 
invert_mode(struct dmx_filter * filter)8593256b36eSMauro Carvalho Chehab static inline void invert_mode(struct dmx_filter *filter)
8603d6c2bc0SMauro Carvalho Chehab {
8613d6c2bc0SMauro Carvalho Chehab 	int i;
8623d6c2bc0SMauro Carvalho Chehab 
8633d6c2bc0SMauro Carvalho Chehab 	for (i = 0; i < DMX_FILTER_SIZE; i++)
8643d6c2bc0SMauro Carvalho Chehab 		filter->mode[i] ^= 0xff;
8653d6c2bc0SMauro Carvalho Chehab }
8663d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_add_pid(struct dmxdev * dmxdev,struct dmxdev_filter * filter,u16 pid)8673d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
8683d6c2bc0SMauro Carvalho Chehab 			      struct dmxdev_filter *filter, u16 pid)
8693d6c2bc0SMauro Carvalho Chehab {
8703d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_feed *feed;
8713d6c2bc0SMauro Carvalho Chehab 
8723d6c2bc0SMauro Carvalho Chehab 	if ((filter->type != DMXDEV_TYPE_PES) ||
8733d6c2bc0SMauro Carvalho Chehab 	    (filter->state < DMXDEV_STATE_SET))
8743d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
8753d6c2bc0SMauro Carvalho Chehab 
8763d6c2bc0SMauro Carvalho Chehab 	/* only TS packet filters may have multiple PIDs */
8773d6c2bc0SMauro Carvalho Chehab 	if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
8783d6c2bc0SMauro Carvalho Chehab 	    (!list_empty(&filter->feed.ts)))
8793d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
8803d6c2bc0SMauro Carvalho Chehab 
8813d6c2bc0SMauro Carvalho Chehab 	feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
8823d6c2bc0SMauro Carvalho Chehab 	if (feed == NULL)
8833d6c2bc0SMauro Carvalho Chehab 		return -ENOMEM;
8843d6c2bc0SMauro Carvalho Chehab 
8853d6c2bc0SMauro Carvalho Chehab 	feed->pid = pid;
8863d6c2bc0SMauro Carvalho Chehab 	list_add(&feed->next, &filter->feed.ts);
8873d6c2bc0SMauro Carvalho Chehab 
8883d6c2bc0SMauro Carvalho Chehab 	if (filter->state >= DMXDEV_STATE_GO)
8893d6c2bc0SMauro Carvalho Chehab 		return dvb_dmxdev_start_feed(dmxdev, filter, feed);
8903d6c2bc0SMauro Carvalho Chehab 
8913d6c2bc0SMauro Carvalho Chehab 	return 0;
8923d6c2bc0SMauro Carvalho Chehab }
8933d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_remove_pid(struct dmxdev * dmxdev,struct dmxdev_filter * filter,u16 pid)8943d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
8953d6c2bc0SMauro Carvalho Chehab 				  struct dmxdev_filter *filter, u16 pid)
8963d6c2bc0SMauro Carvalho Chehab {
8973d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_feed *feed, *tmp;
8983d6c2bc0SMauro Carvalho Chehab 
8993d6c2bc0SMauro Carvalho Chehab 	if ((filter->type != DMXDEV_TYPE_PES) ||
9003d6c2bc0SMauro Carvalho Chehab 	    (filter->state < DMXDEV_STATE_SET))
9013d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
9023d6c2bc0SMauro Carvalho Chehab 
9033d6c2bc0SMauro Carvalho Chehab 	list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
9043d6c2bc0SMauro Carvalho Chehab 		if ((feed->pid == pid) && (feed->ts != NULL)) {
9053d6c2bc0SMauro Carvalho Chehab 			feed->ts->stop_filtering(feed->ts);
9063d6c2bc0SMauro Carvalho Chehab 			filter->dev->demux->release_ts_feed(filter->dev->demux,
9073d6c2bc0SMauro Carvalho Chehab 							    feed->ts);
9083d6c2bc0SMauro Carvalho Chehab 			list_del(&feed->next);
9093d6c2bc0SMauro Carvalho Chehab 			kfree(feed);
9103d6c2bc0SMauro Carvalho Chehab 		}
9113d6c2bc0SMauro Carvalho Chehab 	}
9123d6c2bc0SMauro Carvalho Chehab 
9133d6c2bc0SMauro Carvalho Chehab 	return 0;
9143d6c2bc0SMauro Carvalho Chehab }
9153d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_filter_set(struct dmxdev * dmxdev,struct dmxdev_filter * dmxdevfilter,struct dmx_sct_filter_params * params)9163d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
9173d6c2bc0SMauro Carvalho Chehab 				 struct dmxdev_filter *dmxdevfilter,
9183d6c2bc0SMauro Carvalho Chehab 				 struct dmx_sct_filter_params *params)
9193d6c2bc0SMauro Carvalho Chehab {
920b3ad24d2SMauro Carvalho Chehab 	dprintk("%s: PID=0x%04x, flags=%02x, timeout=%d\n",
92117e67d4cSMauro Carvalho Chehab 		__func__, params->pid, params->flags, params->timeout);
9223d6c2bc0SMauro Carvalho Chehab 
9233d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_stop(dmxdevfilter);
9243d6c2bc0SMauro Carvalho Chehab 
9253d6c2bc0SMauro Carvalho Chehab 	dmxdevfilter->type = DMXDEV_TYPE_SEC;
9263d6c2bc0SMauro Carvalho Chehab 	memcpy(&dmxdevfilter->params.sec,
9273d6c2bc0SMauro Carvalho Chehab 	       params, sizeof(struct dmx_sct_filter_params));
9283d6c2bc0SMauro Carvalho Chehab 	invert_mode(&dmxdevfilter->params.sec.filter);
9293d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
9303d6c2bc0SMauro Carvalho Chehab 
9313d6c2bc0SMauro Carvalho Chehab 	if (params->flags & DMX_IMMEDIATE_START)
9323d6c2bc0SMauro Carvalho Chehab 		return dvb_dmxdev_filter_start(dmxdevfilter);
9333d6c2bc0SMauro Carvalho Chehab 
9343d6c2bc0SMauro Carvalho Chehab 	return 0;
9353d6c2bc0SMauro Carvalho Chehab }
9363d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_pes_filter_set(struct dmxdev * dmxdev,struct dmxdev_filter * dmxdevfilter,struct dmx_pes_filter_params * params)9373d6c2bc0SMauro Carvalho Chehab static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
9383d6c2bc0SMauro Carvalho Chehab 				     struct dmxdev_filter *dmxdevfilter,
9393d6c2bc0SMauro Carvalho Chehab 				     struct dmx_pes_filter_params *params)
9403d6c2bc0SMauro Carvalho Chehab {
9413d6c2bc0SMauro Carvalho Chehab 	int ret;
9423d6c2bc0SMauro Carvalho Chehab 
9433d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_stop(dmxdevfilter);
9443d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_reset(dmxdevfilter);
9453d6c2bc0SMauro Carvalho Chehab 
946e90bbacdSdevendra sharma 	if ((unsigned int)params->pes_type > DMX_PES_OTHER)
9473d6c2bc0SMauro Carvalho Chehab 		return -EINVAL;
9483d6c2bc0SMauro Carvalho Chehab 
9493d6c2bc0SMauro Carvalho Chehab 	dmxdevfilter->type = DMXDEV_TYPE_PES;
9503d6c2bc0SMauro Carvalho Chehab 	memcpy(&dmxdevfilter->params, params,
9513d6c2bc0SMauro Carvalho Chehab 	       sizeof(struct dmx_pes_filter_params));
9523d6c2bc0SMauro Carvalho Chehab 	INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
9533d6c2bc0SMauro Carvalho Chehab 
9543d6c2bc0SMauro Carvalho Chehab 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
9553d6c2bc0SMauro Carvalho Chehab 
9563d6c2bc0SMauro Carvalho Chehab 	ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
9573d6c2bc0SMauro Carvalho Chehab 				 dmxdevfilter->params.pes.pid);
9583d6c2bc0SMauro Carvalho Chehab 	if (ret < 0)
9593d6c2bc0SMauro Carvalho Chehab 		return ret;
9603d6c2bc0SMauro Carvalho Chehab 
9613d6c2bc0SMauro Carvalho Chehab 	if (params->flags & DMX_IMMEDIATE_START)
9623d6c2bc0SMauro Carvalho Chehab 		return dvb_dmxdev_filter_start(dmxdevfilter);
9633d6c2bc0SMauro Carvalho Chehab 
9643d6c2bc0SMauro Carvalho Chehab 	return 0;
9653d6c2bc0SMauro Carvalho Chehab }
9663d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_read_sec(struct dmxdev_filter * dfil,struct file * file,char __user * buf,size_t count,loff_t * ppos)9673d6c2bc0SMauro Carvalho Chehab static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
9683d6c2bc0SMauro Carvalho Chehab 				   struct file *file, char __user *buf,
9693d6c2bc0SMauro Carvalho Chehab 				   size_t count, loff_t *ppos)
9703d6c2bc0SMauro Carvalho Chehab {
9713d6c2bc0SMauro Carvalho Chehab 	int result, hcount;
9723d6c2bc0SMauro Carvalho Chehab 	int done = 0;
9733d6c2bc0SMauro Carvalho Chehab 
9743d6c2bc0SMauro Carvalho Chehab 	if (dfil->todo <= 0) {
9753d6c2bc0SMauro Carvalho Chehab 		hcount = 3 + dfil->todo;
9763d6c2bc0SMauro Carvalho Chehab 		if (hcount > count)
9773d6c2bc0SMauro Carvalho Chehab 			hcount = count;
9783d6c2bc0SMauro Carvalho Chehab 		result = dvb_dmxdev_buffer_read(&dfil->buffer,
9793d6c2bc0SMauro Carvalho Chehab 						file->f_flags & O_NONBLOCK,
9803d6c2bc0SMauro Carvalho Chehab 						buf, hcount, ppos);
9813d6c2bc0SMauro Carvalho Chehab 		if (result < 0) {
9823d6c2bc0SMauro Carvalho Chehab 			dfil->todo = 0;
9833d6c2bc0SMauro Carvalho Chehab 			return result;
9843d6c2bc0SMauro Carvalho Chehab 		}
9853d6c2bc0SMauro Carvalho Chehab 		if (copy_from_user(dfil->secheader - dfil->todo, buf, result))
9863d6c2bc0SMauro Carvalho Chehab 			return -EFAULT;
9873d6c2bc0SMauro Carvalho Chehab 		buf += result;
9883d6c2bc0SMauro Carvalho Chehab 		done = result;
9893d6c2bc0SMauro Carvalho Chehab 		count -= result;
9903d6c2bc0SMauro Carvalho Chehab 		dfil->todo -= result;
9913d6c2bc0SMauro Carvalho Chehab 		if (dfil->todo > -3)
9923d6c2bc0SMauro Carvalho Chehab 			return done;
9933d6c2bc0SMauro Carvalho Chehab 		dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;
9943d6c2bc0SMauro Carvalho Chehab 		if (!count)
9953d6c2bc0SMauro Carvalho Chehab 			return done;
9963d6c2bc0SMauro Carvalho Chehab 	}
9973d6c2bc0SMauro Carvalho Chehab 	if (count > dfil->todo)
9983d6c2bc0SMauro Carvalho Chehab 		count = dfil->todo;
9993d6c2bc0SMauro Carvalho Chehab 	result = dvb_dmxdev_buffer_read(&dfil->buffer,
10003d6c2bc0SMauro Carvalho Chehab 					file->f_flags & O_NONBLOCK,
10013d6c2bc0SMauro Carvalho Chehab 					buf, count, ppos);
10023d6c2bc0SMauro Carvalho Chehab 	if (result < 0)
10033d6c2bc0SMauro Carvalho Chehab 		return result;
10043d6c2bc0SMauro Carvalho Chehab 	dfil->todo -= result;
10053d6c2bc0SMauro Carvalho Chehab 	return (result + done);
10063d6c2bc0SMauro Carvalho Chehab }
10073d6c2bc0SMauro Carvalho Chehab 
10083d6c2bc0SMauro Carvalho Chehab static ssize_t
dvb_demux_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)10093d6c2bc0SMauro Carvalho Chehab dvb_demux_read(struct file *file, char __user *buf, size_t count,
10103d6c2bc0SMauro Carvalho Chehab 	       loff_t *ppos)
10113d6c2bc0SMauro Carvalho Chehab {
10123d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_filter *dmxdevfilter = file->private_data;
10133d6c2bc0SMauro Carvalho Chehab 	int ret;
10143d6c2bc0SMauro Carvalho Chehab 
10153d6c2bc0SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&dmxdevfilter->mutex))
10163d6c2bc0SMauro Carvalho Chehab 		return -ERESTARTSYS;
10173d6c2bc0SMauro Carvalho Chehab 
10183d6c2bc0SMauro Carvalho Chehab 	if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
10193d6c2bc0SMauro Carvalho Chehab 		ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
10203d6c2bc0SMauro Carvalho Chehab 	else
10213d6c2bc0SMauro Carvalho Chehab 		ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
10223d6c2bc0SMauro Carvalho Chehab 					     file->f_flags & O_NONBLOCK,
10233d6c2bc0SMauro Carvalho Chehab 					     buf, count, ppos);
10243d6c2bc0SMauro Carvalho Chehab 
10253d6c2bc0SMauro Carvalho Chehab 	mutex_unlock(&dmxdevfilter->mutex);
10263d6c2bc0SMauro Carvalho Chehab 	return ret;
10273d6c2bc0SMauro Carvalho Chehab }
10283d6c2bc0SMauro Carvalho Chehab 
dvb_demux_do_ioctl(struct file * file,unsigned int cmd,void * parg)10293d6c2bc0SMauro Carvalho Chehab static int dvb_demux_do_ioctl(struct file *file,
10303d6c2bc0SMauro Carvalho Chehab 			      unsigned int cmd, void *parg)
10313d6c2bc0SMauro Carvalho Chehab {
10323d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_filter *dmxdevfilter = file->private_data;
10333d6c2bc0SMauro Carvalho Chehab 	struct dmxdev *dmxdev = dmxdevfilter->dev;
10343d6c2bc0SMauro Carvalho Chehab 	unsigned long arg = (unsigned long)parg;
10353d6c2bc0SMauro Carvalho Chehab 	int ret = 0;
10363d6c2bc0SMauro Carvalho Chehab 
10373d6c2bc0SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&dmxdev->mutex))
10383d6c2bc0SMauro Carvalho Chehab 		return -ERESTARTSYS;
10393d6c2bc0SMauro Carvalho Chehab 
10403d6c2bc0SMauro Carvalho Chehab 	switch (cmd) {
10413d6c2bc0SMauro Carvalho Chehab 	case DMX_START:
10423d6c2bc0SMauro Carvalho Chehab 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
10433d6c2bc0SMauro Carvalho Chehab 			mutex_unlock(&dmxdev->mutex);
10443d6c2bc0SMauro Carvalho Chehab 			return -ERESTARTSYS;
10453d6c2bc0SMauro Carvalho Chehab 		}
10463d6c2bc0SMauro Carvalho Chehab 		if (dmxdevfilter->state < DMXDEV_STATE_SET)
10473d6c2bc0SMauro Carvalho Chehab 			ret = -EINVAL;
10483d6c2bc0SMauro Carvalho Chehab 		else
10493d6c2bc0SMauro Carvalho Chehab 			ret = dvb_dmxdev_filter_start(dmxdevfilter);
10503d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdevfilter->mutex);
10513d6c2bc0SMauro Carvalho Chehab 		break;
10523d6c2bc0SMauro Carvalho Chehab 
10533d6c2bc0SMauro Carvalho Chehab 	case DMX_STOP:
10543d6c2bc0SMauro Carvalho Chehab 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
10553d6c2bc0SMauro Carvalho Chehab 			mutex_unlock(&dmxdev->mutex);
10563d6c2bc0SMauro Carvalho Chehab 			return -ERESTARTSYS;
10573d6c2bc0SMauro Carvalho Chehab 		}
10583d6c2bc0SMauro Carvalho Chehab 		ret = dvb_dmxdev_filter_stop(dmxdevfilter);
10593d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdevfilter->mutex);
10603d6c2bc0SMauro Carvalho Chehab 		break;
10613d6c2bc0SMauro Carvalho Chehab 
10623d6c2bc0SMauro Carvalho Chehab 	case DMX_SET_FILTER:
10633d6c2bc0SMauro Carvalho Chehab 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
10643d6c2bc0SMauro Carvalho Chehab 			mutex_unlock(&dmxdev->mutex);
10653d6c2bc0SMauro Carvalho Chehab 			return -ERESTARTSYS;
10663d6c2bc0SMauro Carvalho Chehab 		}
10673d6c2bc0SMauro Carvalho Chehab 		ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);
10683d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdevfilter->mutex);
10693d6c2bc0SMauro Carvalho Chehab 		break;
10703d6c2bc0SMauro Carvalho Chehab 
10713d6c2bc0SMauro Carvalho Chehab 	case DMX_SET_PES_FILTER:
10723d6c2bc0SMauro Carvalho Chehab 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
10733d6c2bc0SMauro Carvalho Chehab 			mutex_unlock(&dmxdev->mutex);
10743d6c2bc0SMauro Carvalho Chehab 			return -ERESTARTSYS;
10753d6c2bc0SMauro Carvalho Chehab 		}
10763d6c2bc0SMauro Carvalho Chehab 		ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);
10773d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdevfilter->mutex);
10783d6c2bc0SMauro Carvalho Chehab 		break;
10793d6c2bc0SMauro Carvalho Chehab 
10803d6c2bc0SMauro Carvalho Chehab 	case DMX_SET_BUFFER_SIZE:
10813d6c2bc0SMauro Carvalho Chehab 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
10823d6c2bc0SMauro Carvalho Chehab 			mutex_unlock(&dmxdev->mutex);
10833d6c2bc0SMauro Carvalho Chehab 			return -ERESTARTSYS;
10843d6c2bc0SMauro Carvalho Chehab 		}
10853d6c2bc0SMauro Carvalho Chehab 		ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
10863d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdevfilter->mutex);
10873d6c2bc0SMauro Carvalho Chehab 		break;
10883d6c2bc0SMauro Carvalho Chehab 
10893d6c2bc0SMauro Carvalho Chehab 	case DMX_GET_PES_PIDS:
10903d6c2bc0SMauro Carvalho Chehab 		if (!dmxdev->demux->get_pes_pids) {
10913d6c2bc0SMauro Carvalho Chehab 			ret = -EINVAL;
10923d6c2bc0SMauro Carvalho Chehab 			break;
10933d6c2bc0SMauro Carvalho Chehab 		}
10943d6c2bc0SMauro Carvalho Chehab 		dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
10953d6c2bc0SMauro Carvalho Chehab 		break;
10963d6c2bc0SMauro Carvalho Chehab 
10973d6c2bc0SMauro Carvalho Chehab 	case DMX_GET_STC:
10983d6c2bc0SMauro Carvalho Chehab 		if (!dmxdev->demux->get_stc) {
10993d6c2bc0SMauro Carvalho Chehab 			ret = -EINVAL;
11003d6c2bc0SMauro Carvalho Chehab 			break;
11013d6c2bc0SMauro Carvalho Chehab 		}
11023d6c2bc0SMauro Carvalho Chehab 		ret = dmxdev->demux->get_stc(dmxdev->demux,
11033d6c2bc0SMauro Carvalho Chehab 					     ((struct dmx_stc *)parg)->num,
11043d6c2bc0SMauro Carvalho Chehab 					     &((struct dmx_stc *)parg)->stc,
11053d6c2bc0SMauro Carvalho Chehab 					     &((struct dmx_stc *)parg)->base);
11063d6c2bc0SMauro Carvalho Chehab 		break;
11073d6c2bc0SMauro Carvalho Chehab 
11083d6c2bc0SMauro Carvalho Chehab 	case DMX_ADD_PID:
11093d6c2bc0SMauro Carvalho Chehab 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
11103d6c2bc0SMauro Carvalho Chehab 			ret = -ERESTARTSYS;
11113d6c2bc0SMauro Carvalho Chehab 			break;
11123d6c2bc0SMauro Carvalho Chehab 		}
11133d6c2bc0SMauro Carvalho Chehab 		ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
11143d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdevfilter->mutex);
11153d6c2bc0SMauro Carvalho Chehab 		break;
11163d6c2bc0SMauro Carvalho Chehab 
11173d6c2bc0SMauro Carvalho Chehab 	case DMX_REMOVE_PID:
11183d6c2bc0SMauro Carvalho Chehab 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
11193d6c2bc0SMauro Carvalho Chehab 			ret = -ERESTARTSYS;
11203d6c2bc0SMauro Carvalho Chehab 			break;
11213d6c2bc0SMauro Carvalho Chehab 		}
11223d6c2bc0SMauro Carvalho Chehab 		ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
11233d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdevfilter->mutex);
11243d6c2bc0SMauro Carvalho Chehab 		break;
11253d6c2bc0SMauro Carvalho Chehab 
1126ec5b1004SArnd Bergmann #ifdef CONFIG_DVB_MMAP
112757868accSSatendra Singh Thakur 	case DMX_REQBUFS:
112857868accSSatendra Singh Thakur 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
112957868accSSatendra Singh Thakur 			mutex_unlock(&dmxdev->mutex);
113057868accSSatendra Singh Thakur 			return -ERESTARTSYS;
113157868accSSatendra Singh Thakur 		}
113257868accSSatendra Singh Thakur 		ret = dvb_vb2_reqbufs(&dmxdevfilter->vb2_ctx, parg);
113357868accSSatendra Singh Thakur 		mutex_unlock(&dmxdevfilter->mutex);
113457868accSSatendra Singh Thakur 		break;
113557868accSSatendra Singh Thakur 
113657868accSSatendra Singh Thakur 	case DMX_QUERYBUF:
113757868accSSatendra Singh Thakur 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
113857868accSSatendra Singh Thakur 			mutex_unlock(&dmxdev->mutex);
113957868accSSatendra Singh Thakur 			return -ERESTARTSYS;
114057868accSSatendra Singh Thakur 		}
114157868accSSatendra Singh Thakur 		ret = dvb_vb2_querybuf(&dmxdevfilter->vb2_ctx, parg);
114257868accSSatendra Singh Thakur 		mutex_unlock(&dmxdevfilter->mutex);
114357868accSSatendra Singh Thakur 		break;
114457868accSSatendra Singh Thakur 
114557868accSSatendra Singh Thakur 	case DMX_EXPBUF:
114657868accSSatendra Singh Thakur 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
114757868accSSatendra Singh Thakur 			mutex_unlock(&dmxdev->mutex);
114857868accSSatendra Singh Thakur 			return -ERESTARTSYS;
114957868accSSatendra Singh Thakur 		}
115057868accSSatendra Singh Thakur 		ret = dvb_vb2_expbuf(&dmxdevfilter->vb2_ctx, parg);
115157868accSSatendra Singh Thakur 		mutex_unlock(&dmxdevfilter->mutex);
115257868accSSatendra Singh Thakur 		break;
115357868accSSatendra Singh Thakur 
115457868accSSatendra Singh Thakur 	case DMX_QBUF:
115557868accSSatendra Singh Thakur 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
115657868accSSatendra Singh Thakur 			mutex_unlock(&dmxdev->mutex);
115757868accSSatendra Singh Thakur 			return -ERESTARTSYS;
115857868accSSatendra Singh Thakur 		}
115957868accSSatendra Singh Thakur 		ret = dvb_vb2_qbuf(&dmxdevfilter->vb2_ctx, parg);
116057868accSSatendra Singh Thakur 		if (ret == 0 && !dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
116157868accSSatendra Singh Thakur 			ret = dvb_vb2_stream_on(&dmxdevfilter->vb2_ctx);
116257868accSSatendra Singh Thakur 		mutex_unlock(&dmxdevfilter->mutex);
116357868accSSatendra Singh Thakur 		break;
116457868accSSatendra Singh Thakur 
116557868accSSatendra Singh Thakur 	case DMX_DQBUF:
116657868accSSatendra Singh Thakur 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
116757868accSSatendra Singh Thakur 			mutex_unlock(&dmxdev->mutex);
116857868accSSatendra Singh Thakur 			return -ERESTARTSYS;
116957868accSSatendra Singh Thakur 		}
117057868accSSatendra Singh Thakur 		ret = dvb_vb2_dqbuf(&dmxdevfilter->vb2_ctx, parg);
117157868accSSatendra Singh Thakur 		mutex_unlock(&dmxdevfilter->mutex);
117257868accSSatendra Singh Thakur 		break;
11734021053eSMauro Carvalho Chehab #endif
11743d6c2bc0SMauro Carvalho Chehab 	default:
1175a145f64cSMauro Carvalho Chehab 		ret = -ENOTTY;
11763d6c2bc0SMauro Carvalho Chehab 		break;
11773d6c2bc0SMauro Carvalho Chehab 	}
11783d6c2bc0SMauro Carvalho Chehab 	mutex_unlock(&dmxdev->mutex);
11793d6c2bc0SMauro Carvalho Chehab 	return ret;
11803d6c2bc0SMauro Carvalho Chehab }
11813d6c2bc0SMauro Carvalho Chehab 
dvb_demux_ioctl(struct file * file,unsigned int cmd,unsigned long arg)11823d6c2bc0SMauro Carvalho Chehab static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
11833d6c2bc0SMauro Carvalho Chehab 			    unsigned long arg)
11843d6c2bc0SMauro Carvalho Chehab {
11853d6c2bc0SMauro Carvalho Chehab 	return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
11863d6c2bc0SMauro Carvalho Chehab }
11873d6c2bc0SMauro Carvalho Chehab 
dvb_demux_poll(struct file * file,poll_table * wait)1188c23e0cb8SAl Viro static __poll_t dvb_demux_poll(struct file *file, poll_table *wait)
11893d6c2bc0SMauro Carvalho Chehab {
11903d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_filter *dmxdevfilter = file->private_data;
1191c23e0cb8SAl Viro 	__poll_t mask = 0;
11923d6c2bc0SMauro Carvalho Chehab 
1193c6f5c7c2SHans Verkuil 	poll_wait(file, &dmxdevfilter->buffer.queue, wait);
1194c6f5c7c2SHans Verkuil 
1195313ddec4SMauro Carvalho Chehab 	if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
1196a9a08845SLinus Torvalds 		return EPOLLERR;
119757868accSSatendra Singh Thakur 	if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
119857868accSSatendra Singh Thakur 		return dvb_vb2_poll(&dmxdevfilter->vb2_ctx, file, wait);
11993d6c2bc0SMauro Carvalho Chehab 
12003d6c2bc0SMauro Carvalho Chehab 	if (dmxdevfilter->state != DMXDEV_STATE_GO &&
12013d6c2bc0SMauro Carvalho Chehab 	    dmxdevfilter->state != DMXDEV_STATE_DONE &&
12023d6c2bc0SMauro Carvalho Chehab 	    dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
12033d6c2bc0SMauro Carvalho Chehab 		return 0;
12043d6c2bc0SMauro Carvalho Chehab 
12053d6c2bc0SMauro Carvalho Chehab 	if (dmxdevfilter->buffer.error)
1206a9a08845SLinus Torvalds 		mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
12073d6c2bc0SMauro Carvalho Chehab 
12083d6c2bc0SMauro Carvalho Chehab 	if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
1209a9a08845SLinus Torvalds 		mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
12103d6c2bc0SMauro Carvalho Chehab 
12113d6c2bc0SMauro Carvalho Chehab 	return mask;
12123d6c2bc0SMauro Carvalho Chehab }
12133d6c2bc0SMauro Carvalho Chehab 
1214ec5b1004SArnd Bergmann #ifdef CONFIG_DVB_MMAP
dvb_demux_mmap(struct file * file,struct vm_area_struct * vma)121557868accSSatendra Singh Thakur static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma)
121657868accSSatendra Singh Thakur {
121757868accSSatendra Singh Thakur 	struct dmxdev_filter *dmxdevfilter = file->private_data;
121857868accSSatendra Singh Thakur 	struct dmxdev *dmxdev = dmxdevfilter->dev;
121957868accSSatendra Singh Thakur 	int ret;
122057868accSSatendra Singh Thakur 
12210b23498aSMauro Carvalho Chehab 	if (!dmxdev->may_do_mmap)
1222fdbeb962SMauro Carvalho Chehab 		return -ENOTTY;
12230b23498aSMauro Carvalho Chehab 
122457868accSSatendra Singh Thakur 	if (mutex_lock_interruptible(&dmxdev->mutex))
122557868accSSatendra Singh Thakur 		return -ERESTARTSYS;
122657868accSSatendra Singh Thakur 
122757868accSSatendra Singh Thakur 	if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
122857868accSSatendra Singh Thakur 		mutex_unlock(&dmxdev->mutex);
122957868accSSatendra Singh Thakur 		return -ERESTARTSYS;
123057868accSSatendra Singh Thakur 	}
123157868accSSatendra Singh Thakur 	ret = dvb_vb2_mmap(&dmxdevfilter->vb2_ctx, vma);
123257868accSSatendra Singh Thakur 
123357868accSSatendra Singh Thakur 	mutex_unlock(&dmxdevfilter->mutex);
123457868accSSatendra Singh Thakur 	mutex_unlock(&dmxdev->mutex);
123557868accSSatendra Singh Thakur 
123657868accSSatendra Singh Thakur 	return ret;
123757868accSSatendra Singh Thakur }
12384021053eSMauro Carvalho Chehab #endif
123957868accSSatendra Singh Thakur 
dvb_demux_release(struct inode * inode,struct file * file)12403d6c2bc0SMauro Carvalho Chehab static int dvb_demux_release(struct inode *inode, struct file *file)
12413d6c2bc0SMauro Carvalho Chehab {
12423d6c2bc0SMauro Carvalho Chehab 	struct dmxdev_filter *dmxdevfilter = file->private_data;
12433d6c2bc0SMauro Carvalho Chehab 	struct dmxdev *dmxdev = dmxdevfilter->dev;
12443d6c2bc0SMauro Carvalho Chehab 	int ret;
12453d6c2bc0SMauro Carvalho Chehab 
12463d6c2bc0SMauro Carvalho Chehab 	ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
12473d6c2bc0SMauro Carvalho Chehab 
12483d6c2bc0SMauro Carvalho Chehab 	mutex_lock(&dmxdev->mutex);
12493d6c2bc0SMauro Carvalho Chehab 	dmxdev->dvbdev->users--;
12503d6c2bc0SMauro Carvalho Chehab 	if (dmxdev->dvbdev->users == 1 && dmxdev->exit == 1) {
12513d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdev->mutex);
12523d6c2bc0SMauro Carvalho Chehab 		wake_up(&dmxdev->dvbdev->wait_queue);
12533d6c2bc0SMauro Carvalho Chehab 	} else
12543d6c2bc0SMauro Carvalho Chehab 		mutex_unlock(&dmxdev->mutex);
12553d6c2bc0SMauro Carvalho Chehab 
12563d6c2bc0SMauro Carvalho Chehab 	return ret;
12573d6c2bc0SMauro Carvalho Chehab }
12583d6c2bc0SMauro Carvalho Chehab 
12593d6c2bc0SMauro Carvalho Chehab static const struct file_operations dvb_demux_fops = {
12603d6c2bc0SMauro Carvalho Chehab 	.owner = THIS_MODULE,
12613d6c2bc0SMauro Carvalho Chehab 	.read = dvb_demux_read,
12623d6c2bc0SMauro Carvalho Chehab 	.unlocked_ioctl = dvb_demux_ioctl,
1263b5d32061SArnd Bergmann 	.compat_ioctl = dvb_demux_ioctl,
12643d6c2bc0SMauro Carvalho Chehab 	.open = dvb_demux_open,
12653d6c2bc0SMauro Carvalho Chehab 	.release = dvb_demux_release,
12663d6c2bc0SMauro Carvalho Chehab 	.poll = dvb_demux_poll,
12673d6c2bc0SMauro Carvalho Chehab 	.llseek = default_llseek,
1268ec5b1004SArnd Bergmann #ifdef CONFIG_DVB_MMAP
126957868accSSatendra Singh Thakur 	.mmap = dvb_demux_mmap,
12704021053eSMauro Carvalho Chehab #endif
12713d6c2bc0SMauro Carvalho Chehab };
12723d6c2bc0SMauro Carvalho Chehab 
12738afd52efSMauro Carvalho Chehab static const struct dvb_device dvbdev_demux = {
12743d6c2bc0SMauro Carvalho Chehab 	.priv = NULL,
12753d6c2bc0SMauro Carvalho Chehab 	.users = 1,
12763d6c2bc0SMauro Carvalho Chehab 	.writers = 1,
12778afd52efSMauro Carvalho Chehab #if defined(CONFIG_MEDIA_CONTROLLER_DVB)
1278e4fd3bc5SMauro Carvalho Chehab 	.name = "dvb-demux",
12798afd52efSMauro Carvalho Chehab #endif
12803d6c2bc0SMauro Carvalho Chehab 	.fops = &dvb_demux_fops
12813d6c2bc0SMauro Carvalho Chehab };
12823d6c2bc0SMauro Carvalho Chehab 
dvb_dvr_do_ioctl(struct file * file,unsigned int cmd,void * parg)12833d6c2bc0SMauro Carvalho Chehab static int dvb_dvr_do_ioctl(struct file *file,
12843d6c2bc0SMauro Carvalho Chehab 			    unsigned int cmd, void *parg)
12853d6c2bc0SMauro Carvalho Chehab {
12863d6c2bc0SMauro Carvalho Chehab 	struct dvb_device *dvbdev = file->private_data;
12873d6c2bc0SMauro Carvalho Chehab 	struct dmxdev *dmxdev = dvbdev->priv;
12883d6c2bc0SMauro Carvalho Chehab 	unsigned long arg = (unsigned long)parg;
12893d6c2bc0SMauro Carvalho Chehab 	int ret;
12903d6c2bc0SMauro Carvalho Chehab 
12913d6c2bc0SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&dmxdev->mutex))
12923d6c2bc0SMauro Carvalho Chehab 		return -ERESTARTSYS;
12933d6c2bc0SMauro Carvalho Chehab 
12943d6c2bc0SMauro Carvalho Chehab 	switch (cmd) {
12953d6c2bc0SMauro Carvalho Chehab 	case DMX_SET_BUFFER_SIZE:
12963d6c2bc0SMauro Carvalho Chehab 		ret = dvb_dvr_set_buffer_size(dmxdev, arg);
12973d6c2bc0SMauro Carvalho Chehab 		break;
12983d6c2bc0SMauro Carvalho Chehab 
1299ec5b1004SArnd Bergmann #ifdef CONFIG_DVB_MMAP
130057868accSSatendra Singh Thakur 	case DMX_REQBUFS:
130157868accSSatendra Singh Thakur 		ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg);
130257868accSSatendra Singh Thakur 		break;
130357868accSSatendra Singh Thakur 
130457868accSSatendra Singh Thakur 	case DMX_QUERYBUF:
130557868accSSatendra Singh Thakur 		ret = dvb_vb2_querybuf(&dmxdev->dvr_vb2_ctx, parg);
130657868accSSatendra Singh Thakur 		break;
130757868accSSatendra Singh Thakur 
130857868accSSatendra Singh Thakur 	case DMX_EXPBUF:
130957868accSSatendra Singh Thakur 		ret = dvb_vb2_expbuf(&dmxdev->dvr_vb2_ctx, parg);
131057868accSSatendra Singh Thakur 		break;
131157868accSSatendra Singh Thakur 
131257868accSSatendra Singh Thakur 	case DMX_QBUF:
131357868accSSatendra Singh Thakur 		ret = dvb_vb2_qbuf(&dmxdev->dvr_vb2_ctx, parg);
131457868accSSatendra Singh Thakur 		if (ret == 0 && !dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
131557868accSSatendra Singh Thakur 			ret = dvb_vb2_stream_on(&dmxdev->dvr_vb2_ctx);
131657868accSSatendra Singh Thakur 		break;
131757868accSSatendra Singh Thakur 
131857868accSSatendra Singh Thakur 	case DMX_DQBUF:
131957868accSSatendra Singh Thakur 		ret = dvb_vb2_dqbuf(&dmxdev->dvr_vb2_ctx, parg);
132057868accSSatendra Singh Thakur 		break;
13214021053eSMauro Carvalho Chehab #endif
13223d6c2bc0SMauro Carvalho Chehab 	default:
1323fdbeb962SMauro Carvalho Chehab 		ret = -ENOTTY;
13243d6c2bc0SMauro Carvalho Chehab 		break;
13253d6c2bc0SMauro Carvalho Chehab 	}
13263d6c2bc0SMauro Carvalho Chehab 	mutex_unlock(&dmxdev->mutex);
13273d6c2bc0SMauro Carvalho Chehab 	return ret;
13283d6c2bc0SMauro Carvalho Chehab }
13293d6c2bc0SMauro Carvalho Chehab 
dvb_dvr_ioctl(struct file * file,unsigned int cmd,unsigned long arg)13303d6c2bc0SMauro Carvalho Chehab static long dvb_dvr_ioctl(struct file *file,
13313d6c2bc0SMauro Carvalho Chehab 			 unsigned int cmd, unsigned long arg)
13323d6c2bc0SMauro Carvalho Chehab {
13333d6c2bc0SMauro Carvalho Chehab 	return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
13343d6c2bc0SMauro Carvalho Chehab }
13353d6c2bc0SMauro Carvalho Chehab 
dvb_dvr_poll(struct file * file,poll_table * wait)1336c23e0cb8SAl Viro static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait)
13373d6c2bc0SMauro Carvalho Chehab {
13383d6c2bc0SMauro Carvalho Chehab 	struct dvb_device *dvbdev = file->private_data;
13393d6c2bc0SMauro Carvalho Chehab 	struct dmxdev *dmxdev = dvbdev->priv;
1340c23e0cb8SAl Viro 	__poll_t mask = 0;
13413d6c2bc0SMauro Carvalho Chehab 
1342b3ad24d2SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
13433d6c2bc0SMauro Carvalho Chehab 
1344c6f5c7c2SHans Verkuil 	poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
1345c6f5c7c2SHans Verkuil 
1346d102cac8SChangbing Xiong 	if (dmxdev->exit)
1347a9a08845SLinus Torvalds 		return EPOLLERR;
134857868accSSatendra Singh Thakur 	if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
134957868accSSatendra Singh Thakur 		return dvb_vb2_poll(&dmxdev->dvr_vb2_ctx, file, wait);
1350d102cac8SChangbing Xiong 
13510b23498aSMauro Carvalho Chehab 	if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
13520b23498aSMauro Carvalho Chehab 	    dmxdev->may_do_mmap) {
13533d6c2bc0SMauro Carvalho Chehab 		if (dmxdev->dvr_buffer.error)
1354a9a08845SLinus Torvalds 			mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
13553d6c2bc0SMauro Carvalho Chehab 
13563d6c2bc0SMauro Carvalho Chehab 		if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
1357a9a08845SLinus Torvalds 			mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
13583d6c2bc0SMauro Carvalho Chehab 	} else
1359a9a08845SLinus Torvalds 		mask |= (EPOLLOUT | EPOLLWRNORM | EPOLLPRI);
13603d6c2bc0SMauro Carvalho Chehab 
13613d6c2bc0SMauro Carvalho Chehab 	return mask;
13623d6c2bc0SMauro Carvalho Chehab }
13633d6c2bc0SMauro Carvalho Chehab 
1364ec5b1004SArnd Bergmann #ifdef CONFIG_DVB_MMAP
dvb_dvr_mmap(struct file * file,struct vm_area_struct * vma)136557868accSSatendra Singh Thakur static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma)
136657868accSSatendra Singh Thakur {
136757868accSSatendra Singh Thakur 	struct dvb_device *dvbdev = file->private_data;
136857868accSSatendra Singh Thakur 	struct dmxdev *dmxdev = dvbdev->priv;
136957868accSSatendra Singh Thakur 	int ret;
137057868accSSatendra Singh Thakur 
13710b23498aSMauro Carvalho Chehab 	if (!dmxdev->may_do_mmap)
1372fdbeb962SMauro Carvalho Chehab 		return -ENOTTY;
13730b23498aSMauro Carvalho Chehab 
137457868accSSatendra Singh Thakur 	if (dmxdev->exit)
137557868accSSatendra Singh Thakur 		return -ENODEV;
137657868accSSatendra Singh Thakur 
137757868accSSatendra Singh Thakur 	if (mutex_lock_interruptible(&dmxdev->mutex))
137857868accSSatendra Singh Thakur 		return -ERESTARTSYS;
137957868accSSatendra Singh Thakur 
138057868accSSatendra Singh Thakur 	ret = dvb_vb2_mmap(&dmxdev->dvr_vb2_ctx, vma);
138157868accSSatendra Singh Thakur 	mutex_unlock(&dmxdev->mutex);
138257868accSSatendra Singh Thakur 	return ret;
138357868accSSatendra Singh Thakur }
13844021053eSMauro Carvalho Chehab #endif
138557868accSSatendra Singh Thakur 
13863d6c2bc0SMauro Carvalho Chehab static const struct file_operations dvb_dvr_fops = {
13873d6c2bc0SMauro Carvalho Chehab 	.owner = THIS_MODULE,
13883d6c2bc0SMauro Carvalho Chehab 	.read = dvb_dvr_read,
13893d6c2bc0SMauro Carvalho Chehab 	.write = dvb_dvr_write,
13903d6c2bc0SMauro Carvalho Chehab 	.unlocked_ioctl = dvb_dvr_ioctl,
13913d6c2bc0SMauro Carvalho Chehab 	.open = dvb_dvr_open,
13923d6c2bc0SMauro Carvalho Chehab 	.release = dvb_dvr_release,
13933d6c2bc0SMauro Carvalho Chehab 	.poll = dvb_dvr_poll,
13943d6c2bc0SMauro Carvalho Chehab 	.llseek = default_llseek,
1395ec5b1004SArnd Bergmann #ifdef CONFIG_DVB_MMAP
139657868accSSatendra Singh Thakur 	.mmap = dvb_dvr_mmap,
13974021053eSMauro Carvalho Chehab #endif
13983d6c2bc0SMauro Carvalho Chehab };
13993d6c2bc0SMauro Carvalho Chehab 
14008afd52efSMauro Carvalho Chehab static const struct dvb_device dvbdev_dvr = {
14013d6c2bc0SMauro Carvalho Chehab 	.priv = NULL,
14023d6c2bc0SMauro Carvalho Chehab 	.readers = 1,
14033d6c2bc0SMauro Carvalho Chehab 	.users = 1,
14048afd52efSMauro Carvalho Chehab #if defined(CONFIG_MEDIA_CONTROLLER_DVB)
1405e4fd3bc5SMauro Carvalho Chehab 	.name = "dvb-dvr",
14068afd52efSMauro Carvalho Chehab #endif
14073d6c2bc0SMauro Carvalho Chehab 	.fops = &dvb_dvr_fops
14083d6c2bc0SMauro Carvalho Chehab };
dvb_dmxdev_init(struct dmxdev * dmxdev,struct dvb_adapter * dvb_adapter)14093d6c2bc0SMauro Carvalho Chehab int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
14103d6c2bc0SMauro Carvalho Chehab {
1411ab599eb1SWang Hai 	int i, ret;
14123d6c2bc0SMauro Carvalho Chehab 
14133d6c2bc0SMauro Carvalho Chehab 	if (dmxdev->demux->open(dmxdev->demux) < 0)
14143d6c2bc0SMauro Carvalho Chehab 		return -EUSERS;
14153d6c2bc0SMauro Carvalho Chehab 
141642bc47b3SKees Cook 	dmxdev->filter = vmalloc(array_size(sizeof(struct dmxdev_filter),
141742bc47b3SKees Cook 					    dmxdev->filternum));
14183d6c2bc0SMauro Carvalho Chehab 	if (!dmxdev->filter)
14193d6c2bc0SMauro Carvalho Chehab 		return -ENOMEM;
14203d6c2bc0SMauro Carvalho Chehab 
14213d6c2bc0SMauro Carvalho Chehab 	mutex_init(&dmxdev->mutex);
14223d6c2bc0SMauro Carvalho Chehab 	spin_lock_init(&dmxdev->lock);
14233d6c2bc0SMauro Carvalho Chehab 	for (i = 0; i < dmxdev->filternum; i++) {
14243d6c2bc0SMauro Carvalho Chehab 		dmxdev->filter[i].dev = dmxdev;
14253d6c2bc0SMauro Carvalho Chehab 		dmxdev->filter[i].buffer.data = NULL;
14263d6c2bc0SMauro Carvalho Chehab 		dvb_dmxdev_filter_state_set(&dmxdev->filter[i],
14273d6c2bc0SMauro Carvalho Chehab 					    DMXDEV_STATE_FREE);
14283d6c2bc0SMauro Carvalho Chehab 	}
14293d6c2bc0SMauro Carvalho Chehab 
1430ab599eb1SWang Hai 	ret = dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
1431df2f94e5SMauro Carvalho Chehab 			    DVB_DEVICE_DEMUX, dmxdev->filternum);
1432ab599eb1SWang Hai 	if (ret < 0)
1433ab599eb1SWang Hai 		goto err_register_dvbdev;
1434ab599eb1SWang Hai 
1435ab599eb1SWang Hai 	ret = dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
1436df2f94e5SMauro Carvalho Chehab 			    dmxdev, DVB_DEVICE_DVR, dmxdev->filternum);
1437ab599eb1SWang Hai 	if (ret < 0)
1438ab599eb1SWang Hai 		goto err_register_dvr_dvbdev;
14393d6c2bc0SMauro Carvalho Chehab 
14403d6c2bc0SMauro Carvalho Chehab 	dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
14413d6c2bc0SMauro Carvalho Chehab 
14423d6c2bc0SMauro Carvalho Chehab 	return 0;
1443ab599eb1SWang Hai 
1444ab599eb1SWang Hai err_register_dvr_dvbdev:
1445ab599eb1SWang Hai 	dvb_unregister_device(dmxdev->dvbdev);
1446ab599eb1SWang Hai err_register_dvbdev:
1447ab599eb1SWang Hai 	vfree(dmxdev->filter);
1448ab599eb1SWang Hai 	dmxdev->filter = NULL;
1449ab599eb1SWang Hai 	return ret;
14503d6c2bc0SMauro Carvalho Chehab }
14513d6c2bc0SMauro Carvalho Chehab 
14523d6c2bc0SMauro Carvalho Chehab EXPORT_SYMBOL(dvb_dmxdev_init);
14533d6c2bc0SMauro Carvalho Chehab 
dvb_dmxdev_release(struct dmxdev * dmxdev)14543d6c2bc0SMauro Carvalho Chehab void dvb_dmxdev_release(struct dmxdev *dmxdev)
14553d6c2bc0SMauro Carvalho Chehab {
1456*fd3d91abSTakashi Iwai 	mutex_lock(&dmxdev->mutex);
14573d6c2bc0SMauro Carvalho Chehab 	dmxdev->exit = 1;
1458*fd3d91abSTakashi Iwai 	mutex_unlock(&dmxdev->mutex);
1459*fd3d91abSTakashi Iwai 
14603d6c2bc0SMauro Carvalho Chehab 	if (dmxdev->dvbdev->users > 1) {
14613d6c2bc0SMauro Carvalho Chehab 		wait_event(dmxdev->dvbdev->wait_queue,
14623d6c2bc0SMauro Carvalho Chehab 				dmxdev->dvbdev->users == 1);
14633d6c2bc0SMauro Carvalho Chehab 	}
14643d6c2bc0SMauro Carvalho Chehab 	if (dmxdev->dvr_dvbdev->users > 1) {
14653d6c2bc0SMauro Carvalho Chehab 		wait_event(dmxdev->dvr_dvbdev->wait_queue,
14663d6c2bc0SMauro Carvalho Chehab 				dmxdev->dvr_dvbdev->users == 1);
14673d6c2bc0SMauro Carvalho Chehab 	}
14683d6c2bc0SMauro Carvalho Chehab 
14693d6c2bc0SMauro Carvalho Chehab 	dvb_unregister_device(dmxdev->dvbdev);
14703d6c2bc0SMauro Carvalho Chehab 	dvb_unregister_device(dmxdev->dvr_dvbdev);
14713d6c2bc0SMauro Carvalho Chehab 
14723d6c2bc0SMauro Carvalho Chehab 	vfree(dmxdev->filter);
14733d6c2bc0SMauro Carvalho Chehab 	dmxdev->filter = NULL;
14743d6c2bc0SMauro Carvalho Chehab 	dmxdev->demux->close(dmxdev->demux);
14753d6c2bc0SMauro Carvalho Chehab }
14763d6c2bc0SMauro Carvalho Chehab 
14773d6c2bc0SMauro Carvalho Chehab EXPORT_SYMBOL(dvb_dmxdev_release);
1478