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 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 26 * 02110-1301, USA 27 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 28 */ 29 30#include <linux/module.h> 31#include <linux/init.h> 32#include <linux/delay.h> 33#include <linux/slab.h> 34#include <linux/poll.h> 35#include <linux/io.h> 36#include <asm/div64.h> 37#include <linux/pci.h> 38#include <linux/timer.h> 39#include <linux/byteorder/generic.h> 40#include <linux/firmware.h> 41#include <linux/vmalloc.h> 42 43#include "ngene.h" 44 45 46/****************************************************************************/ 47/* COMMAND API interface ****************************************************/ 48/****************************************************************************/ 49 50static ssize_t ts_write(struct file *file, const char __user *buf, 51 size_t count, loff_t *ppos) 52{ 53 struct dvb_device *dvbdev = file->private_data; 54 struct ngene_channel *chan = dvbdev->priv; 55 struct ngene *dev = chan->dev; 56 57 if (wait_event_interruptible(dev->tsout_rbuf.queue, 58 dvb_ringbuffer_free 59 (&dev->tsout_rbuf) >= count) < 0) 60 return 0; 61 62 dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count); 63 64 return count; 65} 66 67static ssize_t ts_read(struct file *file, char __user *buf, 68 size_t count, loff_t *ppos) 69{ 70 struct dvb_device *dvbdev = file->private_data; 71 struct ngene_channel *chan = dvbdev->priv; 72 struct ngene *dev = chan->dev; 73 int left, avail; 74 75 left = count; 76 while (left) { 77 if (wait_event_interruptible( 78 dev->tsin_rbuf.queue, 79 dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0) 80 return -EAGAIN; 81 avail = dvb_ringbuffer_avail(&dev->tsin_rbuf); 82 if (avail > left) 83 avail = left; 84 dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail); 85 left -= avail; 86 buf += avail; 87 } 88 return count; 89} 90 91static const struct file_operations ci_fops = { 92 .owner = THIS_MODULE, 93 .read = ts_read, 94 .write = ts_write, 95 .open = dvb_generic_open, 96 .release = dvb_generic_release, 97}; 98 99struct dvb_device ngene_dvbdev_ci = { 100 .readers = -1, 101 .writers = -1, 102 .users = -1, 103 .fops = &ci_fops, 104}; 105 106 107/****************************************************************************/ 108/* DVB functions and API interface ******************************************/ 109/****************************************************************************/ 110 111static void swap_buffer(u32 *p, u32 len) 112{ 113 while (len) { 114 *p = swab32(*p); 115 p++; 116 len -= 4; 117 } 118} 119 120/* start of filler packet */ 121static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER }; 122 123/* #define DEBUG_CI_XFER */ 124#ifdef DEBUG_CI_XFER 125static u32 ok; 126static u32 overflow; 127static u32 stripped; 128#endif 129 130void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) 131{ 132 struct ngene_channel *chan = priv; 133 struct ngene *dev = chan->dev; 134 135 136 if (flags & DF_SWAP32) 137 swap_buffer(buf, len); 138 139 if (dev->ci.en && chan->number == 2) { 140 while (len >= 188) { 141 if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) { 142 if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { 143 dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); 144 wake_up(&dev->tsin_rbuf.queue); 145#ifdef DEBUG_CI_XFER 146 ok++; 147#endif 148 } 149#ifdef DEBUG_CI_XFER 150 else 151 overflow++; 152#endif 153 } 154#ifdef DEBUG_CI_XFER 155 else 156 stripped++; 157 158 if (ok % 100 == 0 && overflow) 159 printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped); 160#endif 161 buf += 188; 162 len -= 188; 163 } 164 return NULL; 165 } 166 167 if (chan->users > 0) 168 dvb_dmx_swfilter(&chan->demux, buf, len); 169 170 return NULL; 171} 172 173void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) 174{ 175 struct ngene_channel *chan = priv; 176 struct ngene *dev = chan->dev; 177 u32 alen; 178 179 alen = dvb_ringbuffer_avail(&dev->tsout_rbuf); 180 alen -= alen % 188; 181 182 if (alen < len) 183 FillTSBuffer(buf + alen, len - alen, flags); 184 else 185 alen = len; 186 dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen); 187 if (flags & DF_SWAP32) 188 swap_buffer((u32 *)buf, alen); 189 wake_up_interruptible(&dev->tsout_rbuf.queue); 190 return buf; 191} 192 193 194 195int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed) 196{ 197 struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 198 struct ngene_channel *chan = dvbdmx->priv; 199 200 if (chan->users == 0) { 201 if (!chan->dev->cmd_timeout_workaround || !chan->running) 202 set_transfer(chan, 1); 203 } 204 205 return ++chan->users; 206} 207 208int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed) 209{ 210 struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 211 struct ngene_channel *chan = dvbdmx->priv; 212 213 if (--chan->users) 214 return chan->users; 215 216 if (!chan->dev->cmd_timeout_workaround) 217 set_transfer(chan, 0); 218 219 return 0; 220} 221 222int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, 223 int (*start_feed)(struct dvb_demux_feed *), 224 int (*stop_feed)(struct dvb_demux_feed *), 225 void *priv) 226{ 227 dvbdemux->priv = priv; 228 229 dvbdemux->filternum = 256; 230 dvbdemux->feednum = 256; 231 dvbdemux->start_feed = start_feed; 232 dvbdemux->stop_feed = stop_feed; 233 dvbdemux->write_to_decoder = NULL; 234 dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | 235 DMX_SECTION_FILTERING | 236 DMX_MEMORY_BASED_FILTERING); 237 return dvb_dmx_init(dvbdemux); 238} 239 240int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, 241 struct dvb_demux *dvbdemux, 242 struct dmx_frontend *hw_frontend, 243 struct dmx_frontend *mem_frontend, 244 struct dvb_adapter *dvb_adapter) 245{ 246 int ret; 247 248 dmxdev->filternum = 256; 249 dmxdev->demux = &dvbdemux->dmx; 250 dmxdev->capabilities = 0; 251 ret = dvb_dmxdev_init(dmxdev, dvb_adapter); 252 if (ret < 0) 253 return ret; 254 255 hw_frontend->source = DMX_FRONTEND_0; 256 dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); 257 mem_frontend->source = DMX_MEMORY_FE; 258 dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); 259 return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); 260} 261