linux/drivers/media/pci/ngene/ngene-dvb.c
<<
>>
Prefs
   1/*
   2 * ngene-dvb.c: nGene PCIe bridge driver - DVB functions
   3 *
   4 * Copyright (C) 2005-2007 Micronas
   5 *
   6 * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
   7 *                         Modifications for new nGene firmware,
   8 *                         support for EEPROM-copying,
   9 *                         support for new dual DVB-S2 card prototype
  10 *
  11 *
  12 * This program is free software; you can redistribute it and/or
  13 * modify it under the terms of the GNU General Public License
  14 * version 2 only, as published by the Free Software Foundation.
  15 *
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 *
  22 * To obtain the license, point your browser to
  23 * http://www.gnu.org/copyleft/gpl.html
  24 */
  25
  26#include <linux/module.h>
  27#include <linux/init.h>
  28#include <linux/delay.h>
  29#include <linux/slab.h>
  30#include <linux/poll.h>
  31#include <linux/io.h>
  32#include <asm/div64.h>
  33#include <linux/pci.h>
  34#include <linux/timer.h>
  35#include <linux/byteorder/generic.h>
  36#include <linux/firmware.h>
  37#include <linux/vmalloc.h>
  38
  39#include "ngene.h"
  40
  41
  42/****************************************************************************/
  43/* COMMAND API interface ****************************************************/
  44/****************************************************************************/
  45
  46static ssize_t ts_write(struct file *file, const char __user *buf,
  47                        size_t count, loff_t *ppos)
  48{
  49        struct dvb_device *dvbdev = file->private_data;
  50        struct ngene_channel *chan = dvbdev->priv;
  51        struct ngene *dev = chan->dev;
  52
  53        if (wait_event_interruptible(dev->tsout_rbuf.queue,
  54                                     dvb_ringbuffer_free
  55                                     (&dev->tsout_rbuf) >= count) < 0)
  56                return 0;
  57
  58        dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count);
  59
  60        return count;
  61}
  62
  63static ssize_t ts_read(struct file *file, char __user *buf,
  64                       size_t count, loff_t *ppos)
  65{
  66        struct dvb_device *dvbdev = file->private_data;
  67        struct ngene_channel *chan = dvbdev->priv;
  68        struct ngene *dev = chan->dev;
  69        int left, avail;
  70
  71        left = count;
  72        while (left) {
  73                if (wait_event_interruptible(
  74                            dev->tsin_rbuf.queue,
  75                            dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0)
  76                        return -EAGAIN;
  77                avail = dvb_ringbuffer_avail(&dev->tsin_rbuf);
  78                if (avail > left)
  79                        avail = left;
  80                dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail);
  81                left -= avail;
  82                buf += avail;
  83        }
  84        return count;
  85}
  86
  87static const struct file_operations ci_fops = {
  88        .owner   = THIS_MODULE,
  89        .read    = ts_read,
  90        .write   = ts_write,
  91        .open    = dvb_generic_open,
  92        .release = dvb_generic_release,
  93};
  94
  95struct dvb_device ngene_dvbdev_ci = {
  96        .readers = -1,
  97        .writers = -1,
  98        .users   = -1,
  99        .fops    = &ci_fops,
 100};
 101
 102
 103/****************************************************************************/
 104/* DVB functions and API interface ******************************************/
 105/****************************************************************************/
 106
 107static void swap_buffer(u32 *p, u32 len)
 108{
 109        while (len) {
 110                *p = swab32(*p);
 111                p++;
 112                len -= 4;
 113        }
 114}
 115
 116/* start of filler packet */
 117static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
 118
 119/* #define DEBUG_CI_XFER */
 120#ifdef DEBUG_CI_XFER
 121static u32 ok;
 122static u32 overflow;
 123static u32 stripped;
 124#endif
 125
 126void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
 127{
 128        struct ngene_channel *chan = priv;
 129        struct ngene *dev = chan->dev;
 130
 131
 132        if (flags & DF_SWAP32)
 133                swap_buffer(buf, len);
 134
 135        if (dev->ci.en && chan->number == 2) {
 136                while (len >= 188) {
 137                        if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) {
 138                                if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) {
 139                                        dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188);
 140                                        wake_up(&dev->tsin_rbuf.queue);
 141#ifdef DEBUG_CI_XFER
 142                                        ok++;
 143#endif
 144                                }
 145#ifdef DEBUG_CI_XFER
 146                                else
 147                                        overflow++;
 148#endif
 149                        }
 150#ifdef DEBUG_CI_XFER
 151                        else
 152                                stripped++;
 153
 154                        if (ok % 100 == 0 && overflow)
 155                                printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped);
 156#endif
 157                        buf += 188;
 158                        len -= 188;
 159                }
 160                return NULL;
 161        }
 162
 163        if (chan->users > 0)
 164                dvb_dmx_swfilter(&chan->demux, buf, len);
 165
 166        return NULL;
 167}
 168
 169void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
 170{
 171        struct ngene_channel *chan = priv;
 172        struct ngene *dev = chan->dev;
 173        u32 alen;
 174
 175        alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);
 176        alen -= alen % 188;
 177
 178        if (alen < len)
 179                FillTSBuffer(buf + alen, len - alen, flags);
 180        else
 181                alen = len;
 182        dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);
 183        if (flags & DF_SWAP32)
 184                swap_buffer((u32 *)buf, alen);
 185        wake_up_interruptible(&dev->tsout_rbuf.queue);
 186        return buf;
 187}
 188
 189
 190
 191int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
 192{
 193        struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 194        struct ngene_channel *chan = dvbdmx->priv;
 195
 196        if (chan->users == 0) {
 197                if (!chan->dev->cmd_timeout_workaround || !chan->running)
 198                        set_transfer(chan, 1);
 199        }
 200
 201        return ++chan->users;
 202}
 203
 204int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 205{
 206        struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 207        struct ngene_channel *chan = dvbdmx->priv;
 208
 209        if (--chan->users)
 210                return chan->users;
 211
 212        if (!chan->dev->cmd_timeout_workaround)
 213                set_transfer(chan, 0);
 214
 215        return 0;
 216}
 217
 218int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
 219                            int (*start_feed)(struct dvb_demux_feed *),
 220                            int (*stop_feed)(struct dvb_demux_feed *),
 221                            void *priv)
 222{
 223        dvbdemux->priv = priv;
 224
 225        dvbdemux->filternum = 256;
 226        dvbdemux->feednum = 256;
 227        dvbdemux->start_feed = start_feed;
 228        dvbdemux->stop_feed = stop_feed;
 229        dvbdemux->write_to_decoder = NULL;
 230        dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
 231                                      DMX_SECTION_FILTERING |
 232                                      DMX_MEMORY_BASED_FILTERING);
 233        return dvb_dmx_init(dvbdemux);
 234}
 235
 236int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
 237                               struct dvb_demux *dvbdemux,
 238                               struct dmx_frontend *hw_frontend,
 239                               struct dmx_frontend *mem_frontend,
 240                               struct dvb_adapter *dvb_adapter)
 241{
 242        int ret;
 243
 244        dmxdev->filternum = 256;
 245        dmxdev->demux = &dvbdemux->dmx;
 246        dmxdev->capabilities = 0;
 247        ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
 248        if (ret < 0)
 249                return ret;
 250
 251        hw_frontend->source = DMX_FRONTEND_0;
 252        dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
 253        mem_frontend->source = DMX_MEMORY_FE;
 254        dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
 255        return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
 256}
 257