11899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller/*
21899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * ngene-dvb.c: nGene PCIe bridge driver - DVB functions
31899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller *
41899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * Copyright (C) 2005-2007 Micronas
51899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller *
61899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
71899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller *                         Modifications for new nGene firmware,
81899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller *                         support for EEPROM-copying,
91899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller *                         support for new dual DVB-S2 card prototype
101899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller *
111899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller *
121899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * This program is free software; you can redistribute it and/or
131899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * modify it under the terms of the GNU General Public License
141899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * version 2 only, as published by the Free Software Foundation.
151899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller *
161899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller *
171899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * This program is distributed in the hope that it will be useful,
181899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * but WITHOUT ANY WARRANTY; without even the implied warranty of
191899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
201899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * GNU General Public License for more details.
211899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller *
221899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller *
231899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * You should have received a copy of the GNU General Public License
241899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * along with this program; if not, write to the Free Software
251899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
261899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * 02110-1301, USA
271899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
281899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller */
291899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
301899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <linux/module.h>
311899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <linux/init.h>
321899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <linux/delay.h>
331899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <linux/slab.h>
341899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <linux/poll.h>
351899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <linux/io.h>
361899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <asm/div64.h>
371899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <linux/pci.h>
381899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <linux/timer.h>
391899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <linux/byteorder/generic.h>
401899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <linux/firmware.h>
411899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include <linux/vmalloc.h>
421899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
431899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller#include "ngene.h"
441899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
451899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
461899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller/****************************************************************************/
471899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller/* COMMAND API interface ****************************************************/
481899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller/****************************************************************************/
491899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
500f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzlerstatic ssize_t ts_write(struct file *file, const char *buf,
510f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler			size_t count, loff_t *ppos)
520f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler{
530f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	struct dvb_device *dvbdev = file->private_data;
540f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	struct ngene_channel *chan = dvbdev->priv;
550f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	struct ngene *dev = chan->dev;
560f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler
570f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	if (wait_event_interruptible(dev->tsout_rbuf.queue,
580f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler				     dvb_ringbuffer_free
590f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler				     (&dev->tsout_rbuf) >= count) < 0)
600f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler		return 0;
610f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler
620f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count);
630f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler
640f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	return count;
650f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler}
660f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler
670f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzlerstatic ssize_t ts_read(struct file *file, char *buf,
680f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler		       size_t count, loff_t *ppos)
690f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler{
700f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	struct dvb_device *dvbdev = file->private_data;
710f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	struct ngene_channel *chan = dvbdev->priv;
720f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	struct ngene *dev = chan->dev;
730f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	int left, avail;
740f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler
750f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	left = count;
760f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	while (left) {
770f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler		if (wait_event_interruptible(
780f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler			    dev->tsin_rbuf.queue,
790f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler			    dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0)
800f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler			return -EAGAIN;
810f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler		avail = dvb_ringbuffer_avail(&dev->tsin_rbuf);
820f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler		if (avail > left)
830f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler			avail = left;
840f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler		dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail);
850f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler		left -= avail;
860f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler		buf += avail;
870f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	}
880f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	return count;
890f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler}
900f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler
910f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzlerstatic const struct file_operations ci_fops = {
920f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	.owner   = THIS_MODULE,
930f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	.read    = ts_read,
940f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	.write   = ts_write,
950f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	.open    = dvb_generic_open,
960f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	.release = dvb_generic_release,
970f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler};
980f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler
990f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzlerstruct dvb_device ngene_dvbdev_ci = {
1000f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	.priv    = 0,
1010f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	.readers = -1,
1020f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	.writers = -1,
1030f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	.users   = -1,
1040f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	.fops    = &ci_fops,
1050f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler};
1060f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler
1070f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler
1081899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller/****************************************************************************/
1091899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller/* DVB functions and API interface ******************************************/
1101899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller/****************************************************************************/
1111899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
1121899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmuellerstatic void swap_buffer(u32 *p, u32 len)
1131899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller{
1141899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	while (len) {
1151899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller		*p = swab32(*p);
1161899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller		p++;
1171899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller		len -= 4;
1181899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	}
1191899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller}
1201899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
12136e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss/* start of filler packet */
12236e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endrissstatic u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
12336e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss
12436e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss/* #define DEBUG_CI_XFER */
12536e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss#ifdef DEBUG_CI_XFER
12636e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endrissstatic u32 ok;
12736e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endrissstatic u32 overflow;
12836e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endrissstatic u32 stripped;
12936e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss#endif
13036e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss
1311899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmuellervoid *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
1321899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller{
1331899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	struct ngene_channel *chan = priv;
1340f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	struct ngene *dev = chan->dev;
1351899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
1361899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
1370f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	if (flags & DF_SWAP32)
1380f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler		swap_buffer(buf, len);
13936e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss
1400f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	if (dev->ci.en && chan->number == 2) {
14136e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss		while (len >= 188) {
14236e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss			if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) {
14336e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss				if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) {
14436e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss					dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188);
14536e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss					wake_up(&dev->tsin_rbuf.queue);
14636e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss#ifdef DEBUG_CI_XFER
14736e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss					ok++;
14836e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss#endif
14936e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss				}
15036e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss#ifdef DEBUG_CI_XFER
15136e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss				else
15236e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss					overflow++;
15336e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss#endif
15436e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss			}
15536e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss#ifdef DEBUG_CI_XFER
15636e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss			else
15736e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss				stripped++;
15836e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss
15936e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss			if (ok % 100 == 0 && overflow)
16036e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss				printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped);
16136e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss#endif
16236e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss			buf += 188;
16336e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss			len -= 188;
1640f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler		}
16536e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss		return NULL;
1660f0b270f905bbb0c8e75988ceaf10ff9a401e712Ralph Metzler	}
16736e3fc8957abffa3218a6e3b61bef335eea80c03Oliver Endriss
1689143a437cc2fe329c271115903a3884950aba57dOliver Endriss	if (chan->users > 0)
1691899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller		dvb_dmx_swfilter(&chan->demux, buf, len);
1709143a437cc2fe329c271115903a3884950aba57dOliver Endriss
1711899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	return NULL;
1721899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller}
1731899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
1741899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmuellervoid *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
1751899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller{
1761899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	struct ngene_channel *chan = priv;
1771899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	struct ngene *dev = chan->dev;
1781899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	u32 alen;
1791899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
1801899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);
1811899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	alen -= alen % 188;
1821899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
1831899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	if (alen < len)
1841899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller		FillTSBuffer(buf + alen, len - alen, flags);
1851899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	else
1861899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller		alen = len;
1871899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);
1881899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	if (flags & DF_SWAP32)
1891899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller		swap_buffer((u32 *)buf, alen);
1901899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	wake_up_interruptible(&dev->tsout_rbuf.queue);
1911899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	return buf;
1921899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller}
1931899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
1941899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
1951899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
1961899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmuellerint ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
1971899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller{
1981899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
1991899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	struct ngene_channel *chan = dvbdmx->priv;
2001899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
2011899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	if (chan->users == 0) {
2025a2a1848a7d744a437f96b79a655c13b8090e74dOliver Endriss		if (!chan->dev->cmd_timeout_workaround || !chan->running)
2031899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller			set_transfer(chan, 1);
2041899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	}
2051899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
2061899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	return ++chan->users;
2071899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller}
2081899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
2091899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmuellerint ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
2101899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller{
2111899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
2121899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	struct ngene_channel *chan = dvbdmx->priv;
2131899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
2141899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	if (--chan->users)
2151899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller		return chan->users;
2161899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
2175a2a1848a7d744a437f96b79a655c13b8090e74dOliver Endriss	if (!chan->dev->cmd_timeout_workaround)
2185a2a1848a7d744a437f96b79a655c13b8090e74dOliver Endriss		set_transfer(chan, 0);
2191899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
2201899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	return 0;
2211899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller}
2221899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
2231899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmuellerint my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
2241899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller			    int (*start_feed)(struct dvb_demux_feed *),
2251899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller			    int (*stop_feed)(struct dvb_demux_feed *),
2261899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller			    void *priv)
2271899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller{
2281899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dvbdemux->priv = priv;
2291899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
2301899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dvbdemux->filternum = 256;
2311899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dvbdemux->feednum = 256;
2321899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dvbdemux->start_feed = start_feed;
2331899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dvbdemux->stop_feed = stop_feed;
2341899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dvbdemux->write_to_decoder = NULL;
2351899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
2361899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller				      DMX_SECTION_FILTERING |
2371899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller				      DMX_MEMORY_BASED_FILTERING);
2381899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	return dvb_dmx_init(dvbdemux);
2391899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller}
2401899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
2411899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmuellerint my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
2421899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller			       struct dvb_demux *dvbdemux,
2431899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller			       struct dmx_frontend *hw_frontend,
2441899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller			       struct dmx_frontend *mem_frontend,
2451899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller			       struct dvb_adapter *dvb_adapter)
2461899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller{
2471899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	int ret;
2481899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
2491899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dmxdev->filternum = 256;
2501899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dmxdev->demux = &dvbdemux->dmx;
2511899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dmxdev->capabilities = 0;
2521899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
2531899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	if (ret < 0)
2541899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller		return ret;
2551899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller
2561899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	hw_frontend->source = DMX_FRONTEND_0;
2571899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
2581899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	mem_frontend->source = DMX_MEMORY_FE;
2591899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
2601899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller	return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
2611899e97c52b80c734ead7a98f54ed6fd6e1db96aDevin Heitmueller}
262