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 ¶->filter.mask[1], DMX_FILTER_SIZE - 1);
7453d6c2bc0SMauro Carvalho Chehab memcpy(&(*secfilter)->filter_mode[3],
7463d6c2bc0SMauro Carvalho Chehab ¶->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