Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ngene-dvb.c: nGene PCIe bridge driver - DVB functions
0004  *
0005  * Copyright (C) 2005-2007 Micronas
0006  *
0007  * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
0008  *                         Modifications for new nGene firmware,
0009  *                         support for EEPROM-copying,
0010  *                         support for new dual DVB-S2 card prototype
0011  */
0012 
0013 #include <linux/module.h>
0014 #include <linux/init.h>
0015 #include <linux/delay.h>
0016 #include <linux/slab.h>
0017 #include <linux/poll.h>
0018 #include <linux/io.h>
0019 #include <asm/div64.h>
0020 #include <linux/pci.h>
0021 #include <linux/timer.h>
0022 #include <linux/byteorder/generic.h>
0023 #include <linux/firmware.h>
0024 #include <linux/vmalloc.h>
0025 
0026 #include "ngene.h"
0027 
0028 static int ci_tsfix = 1;
0029 module_param(ci_tsfix, int, 0444);
0030 MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifts in conjunction with CI expansions (default: 1/enabled)");
0031 
0032 /****************************************************************************/
0033 /* COMMAND API interface ****************************************************/
0034 /****************************************************************************/
0035 
0036 static ssize_t ts_write(struct file *file, const char __user *buf,
0037             size_t count, loff_t *ppos)
0038 {
0039     struct dvb_device *dvbdev = file->private_data;
0040     struct ngene_channel *chan = dvbdev->priv;
0041     struct ngene *dev = chan->dev;
0042 
0043     if (wait_event_interruptible(dev->tsout_rbuf.queue,
0044                      dvb_ringbuffer_free
0045                      (&dev->tsout_rbuf) >= count) < 0)
0046         return 0;
0047 
0048     dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count);
0049 
0050     return count;
0051 }
0052 
0053 static ssize_t ts_read(struct file *file, char __user *buf,
0054                size_t count, loff_t *ppos)
0055 {
0056     struct dvb_device *dvbdev = file->private_data;
0057     struct ngene_channel *chan = dvbdev->priv;
0058     struct ngene *dev = chan->dev;
0059     int left, avail;
0060 
0061     left = count;
0062     while (left) {
0063         if (wait_event_interruptible(
0064                 dev->tsin_rbuf.queue,
0065                 dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0)
0066             return -EAGAIN;
0067         avail = dvb_ringbuffer_avail(&dev->tsin_rbuf);
0068         if (avail > left)
0069             avail = left;
0070         dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail);
0071         left -= avail;
0072         buf += avail;
0073     }
0074     return count;
0075 }
0076 
0077 static __poll_t ts_poll(struct file *file, poll_table *wait)
0078 {
0079     struct dvb_device *dvbdev = file->private_data;
0080     struct ngene_channel *chan = dvbdev->priv;
0081     struct ngene *dev = chan->dev;
0082     struct dvb_ringbuffer *rbuf = &dev->tsin_rbuf;
0083     struct dvb_ringbuffer *wbuf = &dev->tsout_rbuf;
0084     __poll_t mask = 0;
0085 
0086     poll_wait(file, &rbuf->queue, wait);
0087     poll_wait(file, &wbuf->queue, wait);
0088 
0089     if (!dvb_ringbuffer_empty(rbuf))
0090         mask |= EPOLLIN | EPOLLRDNORM;
0091     if (dvb_ringbuffer_free(wbuf) >= 188)
0092         mask |= EPOLLOUT | EPOLLWRNORM;
0093 
0094     return mask;
0095 }
0096 
0097 static const struct file_operations ci_fops = {
0098     .owner   = THIS_MODULE,
0099     .read    = ts_read,
0100     .write   = ts_write,
0101     .open    = dvb_generic_open,
0102     .release = dvb_generic_release,
0103     .poll    = ts_poll,
0104     .mmap    = NULL,
0105 };
0106 
0107 struct dvb_device ngene_dvbdev_ci = {
0108     .priv    = NULL,
0109     .readers = 1,
0110     .writers = 1,
0111     .users   = 2,
0112     .fops    = &ci_fops,
0113 };
0114 
0115 
0116 /****************************************************************************/
0117 /* DVB functions and API interface ******************************************/
0118 /****************************************************************************/
0119 
0120 static void swap_buffer(u32 *p, u32 len)
0121 {
0122     while (len) {
0123         *p = swab32(*p);
0124         p++;
0125         len -= 4;
0126     }
0127 }
0128 
0129 /* start of filler packet */
0130 static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
0131 
0132 static int tsin_find_offset(void *buf, u32 len)
0133 {
0134     int i, l;
0135 
0136     l = len - sizeof(fill_ts);
0137     if (l <= 0)
0138         return -1;
0139 
0140     for (i = 0; i < l; i++) {
0141         if (((char *)buf)[i] == 0x47) {
0142             if (!memcmp(buf + i, fill_ts, sizeof(fill_ts)))
0143                 return i % 188;
0144         }
0145     }
0146 
0147     return -1;
0148 }
0149 
0150 static inline void tsin_copy_stripped(struct ngene *dev, void *buf)
0151 {
0152     if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) {
0153         if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) {
0154             dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188);
0155             wake_up(&dev->tsin_rbuf.queue);
0156         }
0157     }
0158 }
0159 
0160 void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
0161 {
0162     struct ngene_channel *chan = priv;
0163     struct ngene *dev = chan->dev;
0164     int tsoff;
0165 
0166     if (flags & DF_SWAP32)
0167         swap_buffer(buf, len);
0168 
0169     if (dev->ci.en && chan->number == 2) {
0170         /* blindly copy buffers if ci_tsfix is disabled */
0171         if (!ci_tsfix) {
0172             while (len >= 188) {
0173                 tsin_copy_stripped(dev, buf);
0174 
0175                 buf += 188;
0176                 len -= 188;
0177             }
0178             return NULL;
0179         }
0180 
0181         /* ci_tsfix = 1 */
0182 
0183         /*
0184          * since the remainder of the TS packet which got cut off
0185          * in the previous tsin_exchange() run is at the beginning
0186          * of the new TS buffer, append this to the temp buffer and
0187          * send it to the DVB ringbuffer afterwards.
0188          */
0189         if (chan->tsin_offset) {
0190             memcpy(&chan->tsin_buffer[(188 - chan->tsin_offset)],
0191                    buf, chan->tsin_offset);
0192             tsin_copy_stripped(dev, &chan->tsin_buffer);
0193 
0194             buf += chan->tsin_offset;
0195             len -= chan->tsin_offset;
0196         }
0197 
0198         /*
0199          * copy TS packets to the DVB ringbuffer and detect new offset
0200          * shifts by checking for a valid TS SYNC byte
0201          */
0202         while (len >= 188) {
0203             if (*((char *)buf) != 0x47) {
0204                 /*
0205                  * no SYNC header, find new offset shift
0206                  * (max. 188 bytes, tsoff will be mod 188)
0207                  */
0208                 tsoff = tsin_find_offset(buf, len);
0209                 if (tsoff > 0) {
0210                     chan->tsin_offset += tsoff;
0211                     chan->tsin_offset %= 188;
0212 
0213                     buf += tsoff;
0214                     len -= tsoff;
0215 
0216                     dev_info(&dev->pci_dev->dev,
0217                          "%s(): tsin_offset shift by %d on channel %d\n",
0218                          __func__, tsoff,
0219                          chan->number);
0220 
0221                     /*
0222                      * offset corrected. re-check remaining
0223                      * len for a full TS frame, break and
0224                      * skip to fragment handling if < 188.
0225                      */
0226                     if (len < 188)
0227                         break;
0228                 }
0229             }
0230 
0231             tsin_copy_stripped(dev, buf);
0232 
0233             buf += 188;
0234             len -= 188;
0235         }
0236 
0237         /*
0238          * if a fragment is left, copy to temp buffer. The remainder
0239          * will be appended in the next tsin_exchange() iteration.
0240          */
0241         if (len > 0 && len < 188)
0242             memcpy(&chan->tsin_buffer, buf, len);
0243 
0244         return NULL;
0245     }
0246 
0247     if (chan->users > 0)
0248         dvb_dmx_swfilter(&chan->demux, buf, len);
0249 
0250     return NULL;
0251 }
0252 
0253 void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
0254 {
0255     struct ngene_channel *chan = priv;
0256     struct ngene *dev = chan->dev;
0257     u32 alen;
0258 
0259     alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);
0260     alen -= alen % 188;
0261 
0262     if (alen < len)
0263         FillTSBuffer(buf + alen, len - alen, flags);
0264     else
0265         alen = len;
0266     dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);
0267     if (flags & DF_SWAP32)
0268         swap_buffer((u32 *)buf, alen);
0269     wake_up_interruptible(&dev->tsout_rbuf.queue);
0270     return buf;
0271 }
0272 
0273 
0274 
0275 int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
0276 {
0277     struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
0278     struct ngene_channel *chan = dvbdmx->priv;
0279 
0280     if (chan->users == 0) {
0281         if (!chan->dev->cmd_timeout_workaround || !chan->running)
0282             set_transfer(chan, 1);
0283     }
0284 
0285     return ++chan->users;
0286 }
0287 
0288 int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
0289 {
0290     struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
0291     struct ngene_channel *chan = dvbdmx->priv;
0292 
0293     if (--chan->users)
0294         return chan->users;
0295 
0296     if (!chan->dev->cmd_timeout_workaround)
0297         set_transfer(chan, 0);
0298 
0299     return 0;
0300 }
0301 
0302 int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
0303                 int (*start_feed)(struct dvb_demux_feed *),
0304                 int (*stop_feed)(struct dvb_demux_feed *),
0305                 void *priv)
0306 {
0307     dvbdemux->priv = priv;
0308 
0309     dvbdemux->filternum = 256;
0310     dvbdemux->feednum = 256;
0311     dvbdemux->start_feed = start_feed;
0312     dvbdemux->stop_feed = stop_feed;
0313     dvbdemux->write_to_decoder = NULL;
0314     dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
0315                       DMX_SECTION_FILTERING |
0316                       DMX_MEMORY_BASED_FILTERING);
0317     return dvb_dmx_init(dvbdemux);
0318 }
0319 
0320 int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
0321                    struct dvb_demux *dvbdemux,
0322                    struct dmx_frontend *hw_frontend,
0323                    struct dmx_frontend *mem_frontend,
0324                    struct dvb_adapter *dvb_adapter)
0325 {
0326     int ret;
0327 
0328     dmxdev->filternum = 256;
0329     dmxdev->demux = &dvbdemux->dmx;
0330     dmxdev->capabilities = 0;
0331     ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
0332     if (ret < 0)
0333         return ret;
0334 
0335     hw_frontend->source = DMX_FRONTEND_0;
0336     dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
0337     mem_frontend->source = DMX_MEMORY_FE;
0338     dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
0339     return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
0340 }