#include "ngene.h"
 
+static int ci_tsfix = 1;
+module_param(ci_tsfix, int, 0444);
+MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifs in conjunction with CI expansions (default: 1/enabled)");
 
 /****************************************************************************/
 /* COMMAND API interface ****************************************************/
 /* start of filler packet */
 static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
 
+static int tsin_find_offset(void *buf, u32 len)
+{
+       int i, l;
+
+       l = len - sizeof(fill_ts);
+       if (l <= 0)
+               return -1;
+
+       for (i = 0; i < l; i++) {
+               if (((char *)buf)[i] == 0x47) {
+                       if (!memcmp(buf + i, fill_ts, sizeof(fill_ts)))
+                               return i % 188;
+               }
+       }
+
+       return -1;
+}
+
 static inline void tsin_copy_stripped(struct ngene *dev, void *buf)
 {
        if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) {
 {
        struct ngene_channel *chan = priv;
        struct ngene *dev = chan->dev;
-
+       int tsoff;
 
        if (flags & DF_SWAP32)
                swap_buffer(buf, len);
 
        if (dev->ci.en && chan->number == 2) {
+               /* blindly copy buffers if ci_tsfix is disabled */
+               if (!ci_tsfix) {
+                       while (len >= 188) {
+                               tsin_copy_stripped(dev, buf);
+
+                               buf += 188;
+                               len -= 188;
+                       }
+                       return NULL;
+               }
+
+               /* ci_tsfix = 1 */
+
+               /*
+                * since the remainder of the TS packet which got cut off
+                * in the previous tsin_exchange() run is at the beginning
+                * of the new TS buffer, append this to the temp buffer and
+                * send it to the DVB ringbuffer afterwards.
+                */
+               if (chan->tsin_offset) {
+                       memcpy(&chan->tsin_buffer[(188 - chan->tsin_offset)],
+                              buf, chan->tsin_offset);
+                       tsin_copy_stripped(dev, &chan->tsin_buffer);
+
+                       buf += chan->tsin_offset;
+                       len -= chan->tsin_offset;
+               }
+
+               /*
+                * copy TS packets to the DVB ringbuffer and detect new offset
+                * shifts by checking for a valid TS SYNC byte
+                */
                while (len >= 188) {
+                       if (*((char *)buf) != 0x47) {
+                               /*
+                                * no SYNC header, find new offset shift
+                                * (max. 188 bytes, tsoff will be mod 188)
+                                */
+                               tsoff = tsin_find_offset(buf, len);
+                               if (tsoff > 0) {
+                                       chan->tsin_offset += tsoff;
+                                       chan->tsin_offset %= 188;
+
+                                       buf += tsoff;
+                                       len -= tsoff;
+
+                                       dev_info(&dev->pci_dev->dev,
+                                                "%s(): tsin_offset shift by %d on channel %d\n",
+                                                __func__, tsoff,
+                                                chan->number);
+
+                                       /*
+                                        * offset corrected. re-check remaining
+                                        * len for a full TS frame, break and
+                                        * skip to fragment handling if < 188.
+                                        */
+                                       if (len < 188)
+                                               break;
+                               }
+                       }
+
                        tsin_copy_stripped(dev, buf);
 
                        buf += 188;
                        len -= 188;
                }
+
+               /*
+                * if a fragment is left, copy to temp buffer. The remainder
+                * will be appended in the next tsin_exchange() iteration.
+                */
+               if (len > 0 && len < 188)
+                       memcpy(&chan->tsin_buffer, buf, len);
+
                return NULL;
        }