Path: blob/master/drivers/media/dvb/ngene/ngene-dvb.c
15111 views
/*1* ngene-dvb.c: nGene PCIe bridge driver - DVB functions2*3* Copyright (C) 2005-2007 Micronas4*5* Copyright (C) 2008-2009 Ralph Metzler <[email protected]>6* Modifications for new nGene firmware,7* support for EEPROM-copying,8* support for new dual DVB-S2 card prototype9*10*11* This program is free software; you can redistribute it and/or12* modify it under the terms of the GNU General Public License13* version 2 only, as published by the Free Software Foundation.14*15*16* This program is distributed in the hope that it will be useful,17* but WITHOUT ANY WARRANTY; without even the implied warranty of18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the19* GNU General Public License for more details.20*21*22* You should have received a copy of the GNU General Public License23* along with this program; if not, write to the Free Software24* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA25* 02110-1301, USA26* Or, point your browser to http://www.gnu.org/copyleft/gpl.html27*/2829#include <linux/module.h>30#include <linux/init.h>31#include <linux/delay.h>32#include <linux/slab.h>33#include <linux/poll.h>34#include <linux/io.h>35#include <asm/div64.h>36#include <linux/pci.h>37#include <linux/timer.h>38#include <linux/byteorder/generic.h>39#include <linux/firmware.h>40#include <linux/vmalloc.h>4142#include "ngene.h"434445/****************************************************************************/46/* COMMAND API interface ****************************************************/47/****************************************************************************/4849static ssize_t ts_write(struct file *file, const char *buf,50size_t count, loff_t *ppos)51{52struct dvb_device *dvbdev = file->private_data;53struct ngene_channel *chan = dvbdev->priv;54struct ngene *dev = chan->dev;5556if (wait_event_interruptible(dev->tsout_rbuf.queue,57dvb_ringbuffer_free58(&dev->tsout_rbuf) >= count) < 0)59return 0;6061dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count);6263return count;64}6566static ssize_t ts_read(struct file *file, char *buf,67size_t count, loff_t *ppos)68{69struct dvb_device *dvbdev = file->private_data;70struct ngene_channel *chan = dvbdev->priv;71struct ngene *dev = chan->dev;72int left, avail;7374left = count;75while (left) {76if (wait_event_interruptible(77dev->tsin_rbuf.queue,78dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0)79return -EAGAIN;80avail = dvb_ringbuffer_avail(&dev->tsin_rbuf);81if (avail > left)82avail = left;83dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail);84left -= avail;85buf += avail;86}87return count;88}8990static const struct file_operations ci_fops = {91.owner = THIS_MODULE,92.read = ts_read,93.write = ts_write,94.open = dvb_generic_open,95.release = dvb_generic_release,96};9798struct dvb_device ngene_dvbdev_ci = {99.priv = 0,100.readers = -1,101.writers = -1,102.users = -1,103.fops = &ci_fops,104};105106107/****************************************************************************/108/* DVB functions and API interface ******************************************/109/****************************************************************************/110111static void swap_buffer(u32 *p, u32 len)112{113while (len) {114*p = swab32(*p);115p++;116len -= 4;117}118}119120void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)121{122struct ngene_channel *chan = priv;123struct ngene *dev = chan->dev;124125126if (flags & DF_SWAP32)127swap_buffer(buf, len);128if (dev->ci.en && chan->number == 2) {129if (dvb_ringbuffer_free(&dev->tsin_rbuf) > len) {130dvb_ringbuffer_write(&dev->tsin_rbuf, buf, len);131wake_up_interruptible(&dev->tsin_rbuf.queue);132}133return 0;134}135if (chan->users > 0) {136dvb_dmx_swfilter(&chan->demux, buf, len);137}138return NULL;139}140141u8 fill_ts[188] = { 0x47, 0x1f, 0xff, 0x10 };142143void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)144{145struct ngene_channel *chan = priv;146struct ngene *dev = chan->dev;147u32 alen;148149alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);150alen -= alen % 188;151152if (alen < len)153FillTSBuffer(buf + alen, len - alen, flags);154else155alen = len;156dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);157if (flags & DF_SWAP32)158swap_buffer((u32 *)buf, alen);159wake_up_interruptible(&dev->tsout_rbuf.queue);160return buf;161}162163164165int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)166{167struct dvb_demux *dvbdmx = dvbdmxfeed->demux;168struct ngene_channel *chan = dvbdmx->priv;169170if (chan->users == 0) {171if (!chan->dev->cmd_timeout_workaround || !chan->running)172set_transfer(chan, 1);173}174175return ++chan->users;176}177178int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)179{180struct dvb_demux *dvbdmx = dvbdmxfeed->demux;181struct ngene_channel *chan = dvbdmx->priv;182183if (--chan->users)184return chan->users;185186if (!chan->dev->cmd_timeout_workaround)187set_transfer(chan, 0);188189return 0;190}191192int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,193int (*start_feed)(struct dvb_demux_feed *),194int (*stop_feed)(struct dvb_demux_feed *),195void *priv)196{197dvbdemux->priv = priv;198199dvbdemux->filternum = 256;200dvbdemux->feednum = 256;201dvbdemux->start_feed = start_feed;202dvbdemux->stop_feed = stop_feed;203dvbdemux->write_to_decoder = NULL;204dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |205DMX_SECTION_FILTERING |206DMX_MEMORY_BASED_FILTERING);207return dvb_dmx_init(dvbdemux);208}209210int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,211struct dvb_demux *dvbdemux,212struct dmx_frontend *hw_frontend,213struct dmx_frontend *mem_frontend,214struct dvb_adapter *dvb_adapter)215{216int ret;217218dmxdev->filternum = 256;219dmxdev->demux = &dvbdemux->dmx;220dmxdev->capabilities = 0;221ret = dvb_dmxdev_init(dmxdev, dvb_adapter);222if (ret < 0)223return ret;224225hw_frontend->source = DMX_FRONTEND_0;226dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);227mem_frontend->source = DMX_MEMORY_FE;228dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);229return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);230}231232233