root/drivers/media/pci/ngene/ngene-dvb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ts_write
  2. ts_read
  3. ts_poll
  4. swap_buffer
  5. tsin_find_offset
  6. tsin_copy_stripped
  7. tsin_exchange
  8. tsout_exchange
  9. ngene_start_feed
  10. ngene_stop_feed
  11. my_dvb_dmx_ts_card_init
  12. my_dvb_dmxdev_ts_card_init

   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 
  28 static int ci_tsfix = 1;
  29 module_param(ci_tsfix, int, 0444);
  30 MODULE_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 
  36 static 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 
  53 static 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 
  77 static __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 
  97 static 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 
 107 struct 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 
 120 static 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 */
 130 static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
 131 
 132 static 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 
 150 static 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 
 160 void *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 
 253 void *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 
 275 int 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 
 288 int 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 
 302 int 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 
 320 int 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 }

/* [<][>][^][v][top][bottom][index][help] */