ngene-dvb.c (8400B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * ngene-dvb.c: nGene PCIe bridge driver - DVB functions 4 * 5 * Copyright (C) 2005-2007 Micronas 6 * 7 * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de> 8 * Modifications for new nGene firmware, 9 * support for EEPROM-copying, 10 * support for new dual DVB-S2 card prototype 11 */ 12 13#include <linux/module.h> 14#include <linux/init.h> 15#include <linux/delay.h> 16#include <linux/slab.h> 17#include <linux/poll.h> 18#include <linux/io.h> 19#include <asm/div64.h> 20#include <linux/pci.h> 21#include <linux/timer.h> 22#include <linux/byteorder/generic.h> 23#include <linux/firmware.h> 24#include <linux/vmalloc.h> 25 26#include "ngene.h" 27 28static int ci_tsfix = 1; 29module_param(ci_tsfix, int, 0444); 30MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifts in conjunction with CI expansions (default: 1/enabled)"); 31 32/****************************************************************************/ 33/* COMMAND API interface ****************************************************/ 34/****************************************************************************/ 35 36static ssize_t ts_write(struct file *file, const char __user *buf, 37 size_t count, loff_t *ppos) 38{ 39 struct dvb_device *dvbdev = file->private_data; 40 struct ngene_channel *chan = dvbdev->priv; 41 struct ngene *dev = chan->dev; 42 43 if (wait_event_interruptible(dev->tsout_rbuf.queue, 44 dvb_ringbuffer_free 45 (&dev->tsout_rbuf) >= count) < 0) 46 return 0; 47 48 dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count); 49 50 return count; 51} 52 53static ssize_t ts_read(struct file *file, char __user *buf, 54 size_t count, loff_t *ppos) 55{ 56 struct dvb_device *dvbdev = file->private_data; 57 struct ngene_channel *chan = dvbdev->priv; 58 struct ngene *dev = chan->dev; 59 int left, avail; 60 61 left = count; 62 while (left) { 63 if (wait_event_interruptible( 64 dev->tsin_rbuf.queue, 65 dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0) 66 return -EAGAIN; 67 avail = dvb_ringbuffer_avail(&dev->tsin_rbuf); 68 if (avail > left) 69 avail = left; 70 dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail); 71 left -= avail; 72 buf += avail; 73 } 74 return count; 75} 76 77static __poll_t ts_poll(struct file *file, poll_table *wait) 78{ 79 struct dvb_device *dvbdev = file->private_data; 80 struct ngene_channel *chan = dvbdev->priv; 81 struct ngene *dev = chan->dev; 82 struct dvb_ringbuffer *rbuf = &dev->tsin_rbuf; 83 struct dvb_ringbuffer *wbuf = &dev->tsout_rbuf; 84 __poll_t mask = 0; 85 86 poll_wait(file, &rbuf->queue, wait); 87 poll_wait(file, &wbuf->queue, wait); 88 89 if (!dvb_ringbuffer_empty(rbuf)) 90 mask |= EPOLLIN | EPOLLRDNORM; 91 if (dvb_ringbuffer_free(wbuf) >= 188) 92 mask |= EPOLLOUT | EPOLLWRNORM; 93 94 return mask; 95} 96 97static const struct file_operations ci_fops = { 98 .owner = THIS_MODULE, 99 .read = ts_read, 100 .write = ts_write, 101 .open = dvb_generic_open, 102 .release = dvb_generic_release, 103 .poll = ts_poll, 104 .mmap = NULL, 105}; 106 107struct dvb_device ngene_dvbdev_ci = { 108 .priv = NULL, 109 .readers = 1, 110 .writers = 1, 111 .users = 2, 112 .fops = &ci_fops, 113}; 114 115 116/****************************************************************************/ 117/* DVB functions and API interface ******************************************/ 118/****************************************************************************/ 119 120static void swap_buffer(u32 *p, u32 len) 121{ 122 while (len) { 123 *p = swab32(*p); 124 p++; 125 len -= 4; 126 } 127} 128 129/* start of filler packet */ 130static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER }; 131 132static int tsin_find_offset(void *buf, u32 len) 133{ 134 int i, l; 135 136 l = len - sizeof(fill_ts); 137 if (l <= 0) 138 return -1; 139 140 for (i = 0; i < l; i++) { 141 if (((char *)buf)[i] == 0x47) { 142 if (!memcmp(buf + i, fill_ts, sizeof(fill_ts))) 143 return i % 188; 144 } 145 } 146 147 return -1; 148} 149 150static inline void tsin_copy_stripped(struct ngene *dev, void *buf) 151{ 152 if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) { 153 if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { 154 dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); 155 wake_up(&dev->tsin_rbuf.queue); 156 } 157 } 158} 159 160void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) 161{ 162 struct ngene_channel *chan = priv; 163 struct ngene *dev = chan->dev; 164 int tsoff; 165 166 if (flags & DF_SWAP32) 167 swap_buffer(buf, len); 168 169 if (dev->ci.en && chan->number == 2) { 170 /* blindly copy buffers if ci_tsfix is disabled */ 171 if (!ci_tsfix) { 172 while (len >= 188) { 173 tsin_copy_stripped(dev, buf); 174 175 buf += 188; 176 len -= 188; 177 } 178 return NULL; 179 } 180 181 /* ci_tsfix = 1 */ 182 183 /* 184 * since the remainder of the TS packet which got cut off 185 * in the previous tsin_exchange() run is at the beginning 186 * of the new TS buffer, append this to the temp buffer and 187 * send it to the DVB ringbuffer afterwards. 188 */ 189 if (chan->tsin_offset) { 190 memcpy(&chan->tsin_buffer[(188 - chan->tsin_offset)], 191 buf, chan->tsin_offset); 192 tsin_copy_stripped(dev, &chan->tsin_buffer); 193 194 buf += chan->tsin_offset; 195 len -= chan->tsin_offset; 196 } 197 198 /* 199 * copy TS packets to the DVB ringbuffer and detect new offset 200 * shifts by checking for a valid TS SYNC byte 201 */ 202 while (len >= 188) { 203 if (*((char *)buf) != 0x47) { 204 /* 205 * no SYNC header, find new offset shift 206 * (max. 188 bytes, tsoff will be mod 188) 207 */ 208 tsoff = tsin_find_offset(buf, len); 209 if (tsoff > 0) { 210 chan->tsin_offset += tsoff; 211 chan->tsin_offset %= 188; 212 213 buf += tsoff; 214 len -= tsoff; 215 216 dev_info(&dev->pci_dev->dev, 217 "%s(): tsin_offset shift by %d on channel %d\n", 218 __func__, tsoff, 219 chan->number); 220 221 /* 222 * offset corrected. re-check remaining 223 * len for a full TS frame, break and 224 * skip to fragment handling if < 188. 225 */ 226 if (len < 188) 227 break; 228 } 229 } 230 231 tsin_copy_stripped(dev, buf); 232 233 buf += 188; 234 len -= 188; 235 } 236 237 /* 238 * if a fragment is left, copy to temp buffer. The remainder 239 * will be appended in the next tsin_exchange() iteration. 240 */ 241 if (len > 0 && len < 188) 242 memcpy(&chan->tsin_buffer, buf, len); 243 244 return NULL; 245 } 246 247 if (chan->users > 0) 248 dvb_dmx_swfilter(&chan->demux, buf, len); 249 250 return NULL; 251} 252 253void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) 254{ 255 struct ngene_channel *chan = priv; 256 struct ngene *dev = chan->dev; 257 u32 alen; 258 259 alen = dvb_ringbuffer_avail(&dev->tsout_rbuf); 260 alen -= alen % 188; 261 262 if (alen < len) 263 FillTSBuffer(buf + alen, len - alen, flags); 264 else 265 alen = len; 266 dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen); 267 if (flags & DF_SWAP32) 268 swap_buffer((u32 *)buf, alen); 269 wake_up_interruptible(&dev->tsout_rbuf.queue); 270 return buf; 271} 272 273 274 275int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed) 276{ 277 struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 278 struct ngene_channel *chan = dvbdmx->priv; 279 280 if (chan->users == 0) { 281 if (!chan->dev->cmd_timeout_workaround || !chan->running) 282 set_transfer(chan, 1); 283 } 284 285 return ++chan->users; 286} 287 288int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed) 289{ 290 struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 291 struct ngene_channel *chan = dvbdmx->priv; 292 293 if (--chan->users) 294 return chan->users; 295 296 if (!chan->dev->cmd_timeout_workaround) 297 set_transfer(chan, 0); 298 299 return 0; 300} 301 302int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, 303 int (*start_feed)(struct dvb_demux_feed *), 304 int (*stop_feed)(struct dvb_demux_feed *), 305 void *priv) 306{ 307 dvbdemux->priv = priv; 308 309 dvbdemux->filternum = 256; 310 dvbdemux->feednum = 256; 311 dvbdemux->start_feed = start_feed; 312 dvbdemux->stop_feed = stop_feed; 313 dvbdemux->write_to_decoder = NULL; 314 dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | 315 DMX_SECTION_FILTERING | 316 DMX_MEMORY_BASED_FILTERING); 317 return dvb_dmx_init(dvbdemux); 318} 319 320int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, 321 struct dvb_demux *dvbdemux, 322 struct dmx_frontend *hw_frontend, 323 struct dmx_frontend *mem_frontend, 324 struct dvb_adapter *dvb_adapter) 325{ 326 int ret; 327 328 dmxdev->filternum = 256; 329 dmxdev->demux = &dvbdemux->dmx; 330 dmxdev->capabilities = 0; 331 ret = dvb_dmxdev_init(dmxdev, dvb_adapter); 332 if (ret < 0) 333 return ret; 334 335 hw_frontend->source = DMX_FRONTEND_0; 336 dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); 337 mem_frontend->source = DMX_MEMORY_FE; 338 dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); 339 return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); 340}