From patchwork Sat Feb 24 18:55:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Scheller X-Patchwork-Id: 10240469 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id B7889602A0 for ; Sat, 24 Feb 2018 18:55:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id ABC5029BE3 for ; Sat, 24 Feb 2018 18:55:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A070F29BFC; Sat, 24 Feb 2018 18:55:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 637E529BE3 for ; Sat, 24 Feb 2018 18:55:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751508AbeBXSzy (ORCPT ); Sat, 24 Feb 2018 13:55:54 -0500 Received: from mail-wr0-f175.google.com ([209.85.128.175]:43081 "EHLO mail-wr0-f175.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751399AbeBXSzt (ORCPT ); Sat, 24 Feb 2018 13:55:49 -0500 Received: by mail-wr0-f175.google.com with SMTP id u49so17217244wrc.10 for ; Sat, 24 Feb 2018 10:55:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=yzOUsXaxrwygQUMnJCJp1dxSzAO3jUaKsGLTMZlAvF4=; b=EqOFbu830a+P3TlWszmv0336EvudbcOUOfgDMpu6umfzzahPFZ6coPr9GhTH4zgXbQ y0F5DCJNp5dGBwqT8EXQJbCIODObPZ1nTeVUtwUY5cF/zJYX9oficUZ0vkA9E+Zdbdzh /ccBMxiqkqz91+6batG7rCGPnTIf6Xsn3ONt02RxqIZxtQBu34/JJ9CubFyScAzdAfhN t6VySFSbw8OAC2S++7aFXd5jlU5TaFbDxB3bGzl4TDdXBrMMvpH5gmXjmUt5njbAlKiR SlLK7W1y1cnvBWhktVgYsvBEX3LRzcZHfK2rKsdme0AZK0yvYxPZazfkXItVovj/p6/K y+jw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=yzOUsXaxrwygQUMnJCJp1dxSzAO3jUaKsGLTMZlAvF4=; b=FfZkxFIwKWdM2gqA/4VwtKZvT8W2s94NXkeqkrRjjMPklEF9XkLccgzynmICY5LlJr wohd1D8V9mSyKsfthGNszSoh0VD5feqgqGsaTz3NCR40+AacxZbFyP8znh54rGI8l9kS 2eIj1PjQjwMGRcC4dpNB5J8KIQwAz7GLj42FlR8VpnOKTTIb02Mapm0BR6q/fMJINR/V WYjZSatOvgweuAwAYN1ysceP+/fH1QcjLeDdCaxU70fu1WMQC36TCyqn8Hb5ldS0N813 gQGzyoB8BOAvE0a9KOs+Ogj799/VYLMa03pNMKmYaMaZLtdD+NR+PDFOdpg43uWdb5PS GJ1g== X-Gm-Message-State: APf1xPBD9cXvplgkA8RaZ+6E+myfsaX70Q7yjq40MnbHjTWwVwyAfJ6N JU8Z9vVkpbqgyxCg0Mvb2MrLww== X-Google-Smtp-Source: AH8x226zChw887gJ0/g2Nu+wWHH8ukMehi5bNtnj1hN2btY3EjQS39+KmIl0lOq+m9xRmxRgMdGioA== X-Received: by 10.223.187.19 with SMTP id r19mr4898375wrg.110.1519498548101; Sat, 24 Feb 2018 10:55:48 -0800 (PST) Received: from dvbdev.wuest.de (ip-84-118-193-200.unity-media.net. [84.118.193.200]) by smtp.gmail.com with ESMTPSA id 3sm526270wry.29.2018.02.24.10.55.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 24 Feb 2018 10:55:47 -0800 (PST) From: Daniel Scheller To: linux-media@vger.kernel.org, mchehab@kernel.org, mchehab@s-opensource.com Subject: [PATCH 12/12] [media] ngene: compensate for TS buffer offset shifts Date: Sat, 24 Feb 2018 19:55:34 +0100 Message-Id: <20180224185534.13792-13-d.scheller.oss@gmail.com> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180224185534.13792-1-d.scheller.oss@gmail.com> References: <20180224185534.13792-1-d.scheller.oss@gmail.com> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Daniel Scheller A possible hardware bug was discovered when using CA addon hardware attached to the ngene hardware, in that the TS input buffer much likely will shift and thus become unaligned to 188 byte blocks (a full TS frame) when things like CA module initialisation (which happens via differing communication paths) takes place. This causes the TS NULL removal in tsin_exchange() to fail to detect this previously inserted data and thus causes userspace applications to receive data they didn't sent beforehand and ultimately can cause troubles. On driver load with an inserted CAM, buffers are fine at first (note that the driver has to keep the communication running from/to the card by inserting TS NULL frames, this is done in tsout_exchange() via FillTSBuffer() - that data is simply sent back by the hardware): offset | 0 1 2 3 4 5 .... 188 189 190 191 192 193 .... 376 data | 47 1f ff 10 6f 6f .... 47 1f ff 10 6f 6f .... 47 After a few seconds, the CA module is recognised and initialised, which is signalled by dvb_ca_en50221: dvb_ca adapter X: DVB CAM detected and initialised successfully This is where the first shift happens (this is always four bytes), buffer becomes like this: offset | 0 1 2 3 4 5 .... 188 189 190 191 192 193 .... 376 data | 6f 6f 6f 6f 47 1f .... 6f 6f 6f 6f 47 1f .... 6f Next, VDR, TVHeadend or any other CI aware application is started, buffers will shift by even more bytes. It is believed this is due to the hardware not handling control and data bytes properly distinct, and control data having an influence on the actual data stream, which we cannot properly detect at the driver level. Workaround this hardware quirk by adding a detection for the TS sync byte 0x47 before each TS frame copy, scan for a new SYNC byte and a TS NULL packet if buffers become unaligned, take note of that offset and apply that when copying data to the DVB ring buffers. The last <188 bytes from the hardware buffers are stored in a temp buffer (tsin_buffer), for which the remainder will be in the beginning of the next hardware buffer (next iteration if tsin_exchange()). That remainder will be appended to the temp buffer and finally sent to the DVB ring buffer. The resulting TS stream is perfectly fine, and the TS NULL packets inserted by the driver which are sent back are properly removed. The resulting offset is being clamped to 188 byte segments (one TS packet). Though this can result in a repeated TS packet if the overall offset grows beyond this (and it will grow only on CA initialisation), this is still way better than unaligned TS frames and data sent to userspace that just isn't supposed to be there. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-dvb.c | 80 ++++++++++++++++++++++++++++++++++++- drivers/media/pci/ngene/ngene.h | 3 ++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index 6d72b9f69418..5abf69f6bc4b 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -38,6 +38,9 @@ #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 ****************************************************/ @@ -123,6 +126,24 @@ static u32 overflow; static u32 stripped; #endif +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; + } + } + + return -1; +} + static inline void tsin_copy_stripped(struct ngene *dev, void *buf) { if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) { @@ -153,18 +174,75 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { 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 */ + 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); + } + } + 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; } diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 66d8eaa28549..01d9f1b58fcb 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -732,6 +732,9 @@ struct ngene_channel { #endif int running; + + int tsin_offset; + u8 tsin_buffer[188]; };