From patchwork Sat May 2 03:22:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Almeida X-Patchwork-Id: 209983 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0F033C47254 for ; Sat, 2 May 2020 03:22:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CA7682184D for ; Sat, 2 May 2020 03:22:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="McUTt5gL" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726951AbgEBDWh (ORCPT ); Fri, 1 May 2020 23:22:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39892 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726439AbgEBDWg (ORCPT ); Fri, 1 May 2020 23:22:36 -0400 Received: from mail-qk1-x744.google.com (mail-qk1-x744.google.com [IPv6:2607:f8b0:4864:20::744]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A8076C061A0C; Fri, 1 May 2020 20:22:36 -0700 (PDT) Received: by mail-qk1-x744.google.com with SMTP id q7so11245119qkf.3; Fri, 01 May 2020 20:22:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=vOfGhTh2Jo/NyvBbJBpC6oj9kdoBU+4VAUZ3CEi4qes=; b=McUTt5gLkXayOgiy5NBbinWpsfM6qbr0a2WqnbFVMTs6HC8DyDbzDRFty0Os3voy/a 0vo5JKuYUD88ET2JEpnb/nRPNr1ZK0mqeYHXjzjEGD1rHZ2J51bSKGzbEPAIpoDdii1c wx4sGEJLJvHmvPwIVkfy4gD7NXCx1GdlebdUX/4WM4nbBrhrEWtE40N4s1jxgCx8z4ps 13I4llZPcnJIcTfPVZMM5k+fbhgDlaaFDGDkaa4uABQeKAHtVYzg4Mzwlvycwk1+e42q L23+JsG+XrIHFKcRboNqOdRWGtwnf0v6VlznbBT4eSZty+LG5Siyiv9/iuZBpuCN2jOM Y4Kg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=vOfGhTh2Jo/NyvBbJBpC6oj9kdoBU+4VAUZ3CEi4qes=; b=LdwYAszx+RjTqUAKEcX3T3uq5+5ruZesLhEu4w6wtYhazZ0qNkXYaUfCsiAvnyw8un ZR6TbzFg/H5uNcYKQDb5PF/EEtiMJzQKhvCsbRi0F6QCxBGmp5U0glT1Z3OAq9BqtaPv d2WG6Ak65wo47OfVrdYkj9I/03T6nMtHTzi4nuVtkANjwQakGJVeLm31a2Lr+qqDP6y+ HiXt4qH6vmoSFmLew0cht61JODJ4M8ANC4ovvmslh28nwX2oLJACuhMWY82tByMYzHqV 3EU8XhnaLgLhiLbGtYnUlVibSPAFGSS9etzEW/uGOOu3b4gWQOvomKjrPrL9N9FyyRmV 2YPw== X-Gm-Message-State: AGi0PubZcc5enmC1BLI27tioAkkCFvL5aRcUS897DjTcQ/QhMD2vDUFc 8Hff1GGfjnQGVWOl4NPWqPY= X-Google-Smtp-Source: APiQypJiotM5yN7QEX9KKPF6Q0K91HaEi84ECXmMB7K6p/rS8CQuozEN8guj7EmLXhdVJtw7/5rfAg== X-Received: by 2002:ae9:e214:: with SMTP id c20mr6717000qkc.107.1588389755774; Fri, 01 May 2020 20:22:35 -0700 (PDT) Received: from localhost.localdomain ([2804:18:602b:723a:1b2a:57a1:a611:34ed]) by smtp.gmail.com with ESMTPSA id c41sm4410399qta.96.2020.05.01.20.22.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 01 May 2020 20:22:35 -0700 (PDT) From: "Daniel W. S. Almeida" X-Google-Original-From: Daniel W. S. Almeida To: mchehab+huawei@kernel.org, sean@mess.org, kstewart@linuxfoundation.org, allison@lohutok.net, tglx@linutronix.de Cc: "Daniel W. S. Almeida" , linux-media@vger.kernel.org, skhan@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org, linux-kernel@vger.kernel.org Subject: [RFC, WIP, v4 02/11] media: vidtv: implement a tuner driver Date: Sat, 2 May 2020 00:22:07 -0300 Message-Id: <20200502032216.197977-3-dwlsalmeida@gmail.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200502032216.197977-1-dwlsalmeida@gmail.com> References: <20200502032216.197977-1-dwlsalmeida@gmail.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: "Daniel W. S. Almeida" The virtual DVB test driver serves as a reference DVB driver and helps validate the existing APIs in the media subsystem. It can also aid developers working on userspace applications. This dummy tuner should support common TV standards such as DVB-T/T2/S/S2, ISDB-T and ATSC when completed. Signed-off-by: Daniel W. S. Almeida --- drivers/media/test-drivers/vidtv/Makefile | 1 + .../media/test-drivers/vidtv/vidtv_tuner.c | 411 ++++++++++++++++++ 2 files changed, 412 insertions(+) create mode 100644 drivers/media/test-drivers/vidtv/vidtv_tuner.c diff --git a/drivers/media/test-drivers/vidtv/Makefile b/drivers/media/test-drivers/vidtv/Makefile index d1558d84eeaed..e625810a82603 100644 --- a/drivers/media/test-drivers/vidtv/Makefile +++ b/drivers/media/test-drivers/vidtv/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_DVB_VIDTV) += vidtv_tuner.o diff --git a/drivers/media/test-drivers/vidtv/vidtv_tuner.c b/drivers/media/test-drivers/vidtv/vidtv_tuner.c new file mode 100644 index 0000000000000..a790508f935b3 --- /dev/null +++ b/drivers/media/test-drivers/vidtv/vidtv_tuner.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * The Virtual DVB test driver serves as a reference DVB driver and helps + * validate the existing APIs in the media subsystem. It can also aid + * developers working on userspace applications. + * + * The vidtv tuner should support common TV standards such as + * DVB-T/T2/S/S2, ISDB-T and ATSC when completed. + * + * Written by Daniel W. S. Almeida + */ + +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Virtual DTV Tuner"); +MODULE_AUTHOR("Daniel W. S. Almeida"); +MODULE_LICENSE("GPL"); + +struct vidtv_tuner_config { + struct dvb_frontend *fe; + u32 mock_power_up_delay_msec; + u32 mock_tune_delay_msec; + u32 vidtv_valid_dvb_t_freqs[8]; + u32 vidtv_valid_dvb_c_freqs[8]; + u32 vidtv_valid_dvb_s_freqs[8]; + u8 max_frequency_shift_hz; +}; + +struct vidtv_tuner_cnr_to_qual_s { + /* attempt to use the same values as libdvbv5 */ + u32 modulation; + u32 fec; + u32 cnr_ok, cnr_good; +}; + +struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_c_cnr_2_qual[] = { + /* from libdvbv5 source code, in milli db */ + { QAM_256, FEC_NONE, 34000, 38000}, + { QAM_64, FEC_NONE, 30000, 34000}, +}; + +struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_s_cnr_2_qual[] = { + /* from libdvbv5 source code, in milli db */ + { QPSK, FEC_1_2, 7000, 10000}, + + { QPSK, FEC_2_3, 9000, 12000}, + { QPSK, FEC_3_4, 10000, 13000}, + { QPSK, FEC_5_6, 11000, 14000}, + + { QPSK, FEC_7_8, 12000, 15000}, +}; + +struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_s2_cnr_2_qual[] = { + /* from libdvbv5 source code, in milli db */ + { QPSK, FEC_1_2, 9000, 12000}, + { QPSK, FEC_2_3, 11000, 14000}, + { QPSK, FEC_3_4, 12000, 15000}, + { QPSK, FEC_5_6, 12000, 15000}, + { QPSK, FEC_8_9, 13000, 16000}, + { QPSK, FEC_9_10, 13500, 16500}, + { PSK_8, FEC_2_3, 14500, 17500}, + { PSK_8, FEC_3_4, 16000, 19000}, + { PSK_8, FEC_5_6, 17500, 20500}, + { PSK_8, FEC_8_9, 19000, 22000}, +}; + +static struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_t_cnr_2_qual[] = { + /* from libdvbv5 source code, in milli db*/ + { QPSK, FEC_1_2, 4100, 5900}, + { QPSK, FEC_2_3, 6100, 9600}, + { QPSK, FEC_3_4, 7200, 12400}, + { QPSK, FEC_5_6, 8500, 15600}, + { QPSK, FEC_7_8, 9200, 17500}, + + { QAM_16, FEC_1_2, 9800, 11800}, + { QAM_16, FEC_2_3, 12100, 15300}, + { QAM_16, FEC_3_4, 13400, 18100}, + { QAM_16, FEC_5_6, 14800, 21300}, + { QAM_16, FEC_7_8, 15700, 23600}, + + { QAM_64, FEC_1_2, 14000, 16000}, + { QAM_64, FEC_2_3, 19900, 25400}, + { QAM_64, FEC_3_4, 24900, 27900}, + { QAM_64, FEC_5_6, 21300, 23300}, + { QAM_64, FEC_7_8, 22000, 24000}, +}; + +struct vidtv_tuner_hardware_state { + bool asleep; + u32 lock_status; + u32 if_frequency; + u32 tuned_frequency; + u32 bandwidth; +}; + +struct vidtv_tuner_dev { + struct dvb_frontend *fe; + struct vidtv_tuner_hardware_state hw_state; + struct vidtv_tuner_config config; +}; + +static struct vidtv_tuner_dev* +vidtv_tuner_get_dev(struct dvb_frontend *fe) +{ + struct i2c_client *client = fe->tuner_priv; + + return i2c_get_clientdata(client); +} + +static s32 vidtv_tuner_check_frequency_shift(struct dvb_frontend *fe) +{ + struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct vidtv_tuner_config config = tuner_dev->config; + u32 *valid_freqs = NULL; + u32 array_sz = 0; + u32 i; + u32 shift; + + switch (c->delivery_system) { + case SYS_DVBT: + case SYS_DVBT2: + valid_freqs = config.vidtv_valid_dvb_t_freqs; + array_sz = ARRAY_SIZE(config.vidtv_valid_dvb_t_freqs); + break; + case SYS_DVBS: + case SYS_DVBS2: + valid_freqs = config.vidtv_valid_dvb_s_freqs; + array_sz = ARRAY_SIZE(config.vidtv_valid_dvb_s_freqs); + break; + case SYS_DVBC_ANNEX_A: + valid_freqs = config.vidtv_valid_dvb_c_freqs; + array_sz = ARRAY_SIZE(config.vidtv_valid_dvb_c_freqs); + break; + + default: + pr_warn("%s: unsupported delivery system: %u\n", + __func__, + c->delivery_system); + break; + } + + for (i = 0; i < array_sz; i++) { + shift = abs(c->frequency - valid_freqs[i]); + + if (!shift) + return 0; + + /* + * This will provide a value from 0 to 100 that would + * indicate how far is the tuned frequency from the + * right one. + */ + if (shift < config.max_frequency_shift_hz) + return shift * 100 / config.max_frequency_shift_hz; + } + + return -1; +} + +static int +vidtv_tuner_get_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct vidtv_tuner_cnr_to_qual_s *cnr2qual = NULL; + u32 array_size = 0; + s32 shift; + u32 i; + + shift = vidtv_tuner_check_frequency_shift(fe); + + switch (c->delivery_system) { + case SYS_DVBT: + case SYS_DVBT2: + cnr2qual = vidtv_tuner_t_cnr_2_qual; + array_size = ARRAY_SIZE(vidtv_tuner_t_cnr_2_qual); + break; + + case SYS_DVBS: + cnr2qual = vidtv_tuner_s_cnr_2_qual; + array_size = ARRAY_SIZE(vidtv_tuner_s_cnr_2_qual); + break; + + case SYS_DVBS2: + cnr2qual = vidtv_tuner_s2_cnr_2_qual; + array_size = ARRAY_SIZE(vidtv_tuner_s2_cnr_2_qual); + break; + + case SYS_DVBC_ANNEX_A: + cnr2qual = vidtv_tuner_c_cnr_2_qual; + array_size = ARRAY_SIZE(vidtv_tuner_c_cnr_2_qual); + break; + + default: + pr_warn("%s: unsupported delivery system: %u\n", + __func__, + c->delivery_system); + return -EINVAL; + } + + for (i = 0; i <= array_size; i++) { + if (cnr2qual[i].modulation != c->modulation || + cnr2qual[i].fec != c->fec_inner) + continue; + + if (!shift) { + *strength = cnr2qual[i].cnr_good; + return 0; + } + if (shift < 0) { /* Channel not tuned */ + *strength = 0; + return 0; + } + /* + * Channel tuned at wrong frequency. Simulate that the + * Carrier S/N ratio is not too good. + */ + + *strength = cnr2qual[i].cnr_ok - + (cnr2qual[i].cnr_good - cnr2qual[i].cnr_ok); + return 0; + } + + /* + * do a linear interpolation between 34dB and 10dB if we can't + * match against the table + */ + *strength = 34 - 24 * shift / 100; + return 0; +} + +static int vidtv_tuner_init(struct dvb_frontend *fe) +{ + struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe); + struct vidtv_tuner_config config = tuner_dev->config; + + msleep_interruptible(config.mock_power_up_delay_msec); + + tuner_dev->hw_state.asleep = false; + tuner_dev->hw_state.if_frequency = 5000; + + return 0; +} + +static int vidtv_tuner_sleep(struct dvb_frontend *fe) +{ + struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe); + + tuner_dev->hw_state.asleep = true; + return 0; +} + +static int vidtv_tuner_suspend(struct dvb_frontend *fe) +{ + struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe); + + tuner_dev->hw_state.asleep = true; + return 0; +} + +static int vidtv_tuner_resume(struct dvb_frontend *fe) +{ + struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe); + + tuner_dev->hw_state.asleep = false; + return 0; +} + +static int vidtv_tuner_set_params(struct dvb_frontend *fe) +{ + struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe); + struct vidtv_tuner_config config = tuner_dev->config; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 min_freq = fe->ops.tuner_ops.info.frequency_min_hz; + u32 max_freq = fe->ops.tuner_ops.info.frequency_max_hz; + u32 min_bw = fe->ops.tuner_ops.info.bandwidth_min; + u32 max_bw = fe->ops.tuner_ops.info.bandwidth_max; + + if (c->frequency < min_freq || c->frequency > max_freq || + c->bandwidth_hz < min_bw || c->bandwidth_hz > max_bw) { + tuner_dev->hw_state.lock_status = 0; + return -EINVAL; + } + + tuner_dev->hw_state.tuned_frequency = c->frequency; + tuner_dev->hw_state.bandwidth = c->bandwidth_hz; + tuner_dev->hw_state.lock_status = TUNER_STATUS_LOCKED; + + msleep_interruptible(config.mock_tune_delay_msec); + return 0; +} + +static int vidtv_tuner_set_config(struct dvb_frontend *fe, + void *priv_cfg) +{ + struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe); + + memcpy(&tuner_dev->config, priv_cfg, sizeof(tuner_dev->config)); + + return 0; +} + +static int vidtv_tuner_get_frequency(struct dvb_frontend *fe, + u32 *frequency) +{ + struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe); + + *frequency = tuner_dev->hw_state.tuned_frequency; + + return 0; +} + +static int vidtv_tuner_get_bandwidth(struct dvb_frontend *fe, + u32 *bandwidth) +{ + struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe); + + *bandwidth = tuner_dev->hw_state.bandwidth; + + return 0; +} + +static int vidtv_tuner_get_if_frequency(struct dvb_frontend *fe, + u32 *frequency) +{ + struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe); + + *frequency = tuner_dev->hw_state.if_frequency; + + return 0; +} + +static int vidtv_tuner_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe); + + *status = tuner_dev->hw_state.lock_status; + + return 0; +} + +static const struct dvb_tuner_ops vidtv_tuner_ops = { + .init = vidtv_tuner_init, + .sleep = vidtv_tuner_sleep, + .suspend = vidtv_tuner_suspend, + .resume = vidtv_tuner_resume, + .set_params = vidtv_tuner_set_params, + .set_config = vidtv_tuner_set_config, + .get_bandwidth = vidtv_tuner_get_bandwidth, + .get_frequency = vidtv_tuner_get_frequency, + .get_if_frequency = vidtv_tuner_get_if_frequency, + .get_status = vidtv_tuner_get_status, + .get_rf_strength = vidtv_tuner_get_signal_strength +}; + +static const struct i2c_device_id vidtv_tuner_i2c_id_table[] = { + {"vidtv_tuner", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, vidtv_tuner_i2c_id_table); + +static int vidtv_tuner_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct vidtv_tuner_config *config = client->dev.platform_data; + struct dvb_frontend *fe = config->fe; + struct vidtv_tuner_dev *tuner_dev = NULL; + + tuner_dev = kzalloc(sizeof(*tuner_dev), GFP_KERNEL); + if (!tuner_dev) + return -ENOMEM; + + tuner_dev->fe = config->fe; + i2c_set_clientdata(client, tuner_dev); + + memcpy(&fe->ops.tuner_ops, + &vidtv_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = client; + + return 0; +} + +static int vidtv_tuner_i2c_remove(struct i2c_client *client) +{ + struct vidtv_tuner_dev *tuner_dev = i2c_get_clientdata(client); + struct dvb_frontend *fe = tuner_dev->fe; + + memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = NULL; + kfree(tuner_dev); + + return 0; +} + +static struct i2c_driver vidtv_tuner_i2c_driver = { + .driver = { + .name = "vidtv_tuner", + .suppress_bind_attrs = true, + }, + .probe = vidtv_tuner_i2c_probe, + .remove = vidtv_tuner_i2c_remove, + .id_table = vidtv_tuner_i2c_id_table, +}; +module_i2c_driver(vidtv_tuner_i2c_driver); From patchwork Sat May 2 03:22:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Almeida X-Patchwork-Id: 209982 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B6B3CC4725A for ; Sat, 2 May 2020 03:22:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9534521974 for ; Sat, 2 May 2020 03:22:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="JmE/5Zgi" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727815AbgEBDWr (ORCPT ); Fri, 1 May 2020 23:22:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39916 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726439AbgEBDWq (ORCPT ); Fri, 1 May 2020 23:22:46 -0400 Received: from mail-qt1-x844.google.com (mail-qt1-x844.google.com [IPv6:2607:f8b0:4864:20::844]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 14B17C061A0C; Fri, 1 May 2020 20:22:44 -0700 (PDT) Received: by mail-qt1-x844.google.com with SMTP id g26so5683015qtv.13; Fri, 01 May 2020 20:22:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=M9aiXFxkkHzWycdBKzVgypNSiFv5YUSEcCj5fU/dHuw=; b=JmE/5ZgiMPx9+UBCjBmgrwStyLpG/LE6GYrB4oYYDLTaD/Jz2PePLbEm7ECxNKqs1N 0q8B4o8aH/+z4dAyLO+vzwtxoPsgk+8zwJCVDZM66ffREpzgI+kI7dSuqlJMONz+XsZd hO7RhWnWmcvSkDVG5w4KhLPFKIFsGrz0Vpf5gEg1eJjXuv5Agn8Nx1qj4JJ6cTnykENp N6BFgL4oM8ySj+C8/2w8m8QnEd6McSP3qlY25+YeKEZNrbT+Cpzpk7fnu1PnRgG46Qpe of9te20HNiuTlKNRwxX4aD9RccAKqCuU4S6E95pOnrkknlwd5Hg1Ifmc79lXO26O72BC MI+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=M9aiXFxkkHzWycdBKzVgypNSiFv5YUSEcCj5fU/dHuw=; b=PihALswj6GxklcvTyZfF3D6W9aHDVplIZWf3M9AhGhzI4A+iTTBKrp39dpCFUmVJzx TPsbkh4Xxf1+CueeOCVBL0l/+Iu9aQ8/iFFcRAHNMPVzoyq+ykp3tTt4eOfbTZregYi2 p2rsY5orRL5tE+2RtQBRDLchxG/WQnXmEBq6hMGO1iZg+e4CiMhAzB1RX4xkNA1Ikjmi A7F6eakjeuulnpUexP8kAspPjaaGUTUTTivrEfK9MelV8iYxE1m0qXb2yr/UU5u7VdNf +pmotsiIS1XM0r2hT4BGKV3v2MJql0C+g8eFq2e1BmgMxi5Alur+8BKw9uz6WeMZSvKZ Vo9w== X-Gm-Message-State: AGi0PuZEu9jwZLiiIJMTrrrhScvaqc3oTb3oZ1Nl9XM4ytXGuIt/zMcB xAXg3oJaUubmpFEC+WDn0vY= X-Google-Smtp-Source: APiQypIiceR1T8wkFb1LYT7VxbFeuyiaZkDwvF0YepOqRKrdB8mltj7qJA8UdOMUzUh6zDl2s7bqYw== X-Received: by 2002:aed:3e27:: with SMTP id l36mr6945915qtf.192.1588389764042; Fri, 01 May 2020 20:22:44 -0700 (PDT) Received: from localhost.localdomain ([2804:18:602b:723a:1b2a:57a1:a611:34ed]) by smtp.gmail.com with ESMTPSA id c41sm4410399qta.96.2020.05.01.20.22.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 01 May 2020 20:22:43 -0700 (PDT) From: "Daniel W. S. Almeida" X-Google-Original-From: Daniel W. S. Almeida To: mchehab+huawei@kernel.org, sean@mess.org, kstewart@linuxfoundation.org, allison@lohutok.net, tglx@linutronix.de Cc: "Daniel W. S. Almeida" , linux-media@vger.kernel.org, skhan@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org, linux-kernel@vger.kernel.org Subject: [RFC, WIP, v4 04/11] media: vidtv: move config structs into a separate header Date: Sat, 2 May 2020 00:22:09 -0300 Message-Id: <20200502032216.197977-5-dwlsalmeida@gmail.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200502032216.197977-1-dwlsalmeida@gmail.com> References: <20200502032216.197977-1-dwlsalmeida@gmail.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: "Daniel W. S. Almeida" Move config structs to a common header so they can be used by the bridge driver and by their respective drivers. Signed-off-by: Daniel W. S. Almeida --- .../media/test-drivers/vidtv/vidtv_config.h | 35 +++++++++++++++++++ .../media/test-drivers/vidtv/vidtv_demod.c | 1 + .../media/test-drivers/vidtv/vidtv_demod.h | 9 ----- .../media/test-drivers/vidtv/vidtv_tuner.c | 12 ++----- 4 files changed, 38 insertions(+), 19 deletions(-) create mode 100644 drivers/media/test-drivers/vidtv/vidtv_config.h diff --git a/drivers/media/test-drivers/vidtv/vidtv_config.h b/drivers/media/test-drivers/vidtv/vidtv_config.h new file mode 100644 index 0000000000000..7b95bf2444556 --- /dev/null +++ b/drivers/media/test-drivers/vidtv/vidtv_config.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * The Virtual DTV test driver serves as a reference DVB driver and helps + * validate the existing APIs in the media subsystem. It can also aid + * developers working on userspace applications. + * + * Written by Daniel W. S. Almeida + */ + +#ifndef VIDTV_CONFIG_H +#define VIDTV_CONFIG_H + +#include +#include + +struct vidtv_tuner_config { + struct dvb_frontend *fe; + u32 mock_power_up_delay_msec; + u32 mock_tune_delay_msec; + u32 vidtv_valid_dvb_t_freqs[8]; + u32 vidtv_valid_dvb_c_freqs[8]; + u32 vidtv_valid_dvb_s_freqs[8]; + u8 max_frequency_shift_hz; +}; + +struct vidtv_demod_config { + struct dvb_frontend *frontend; + /* probability of losing the lock due to low snr */ + u8 drop_tslock_prob_on_low_snr; + /* probability of recovering when the signal improves */ + u8 recover_tslock_prob_on_good_snr; + u8 chosen_delsys; +}; + +#endif //VIDTV_CONFIG_H diff --git a/drivers/media/test-drivers/vidtv/vidtv_demod.c b/drivers/media/test-drivers/vidtv/vidtv_demod.c index e5f157e4bbe48..15436e565a7b0 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_demod.c +++ b/drivers/media/test-drivers/vidtv/vidtv_demod.c @@ -19,6 +19,7 @@ #include #include #include "vidtv_demod.h" +#include "vidtv_config.h" MODULE_DESCRIPTION("Virtual DVB Demodulator Driver"); MODULE_AUTHOR("Daniel W. S. Almeida"); diff --git a/drivers/media/test-drivers/vidtv/vidtv_demod.h b/drivers/media/test-drivers/vidtv/vidtv_demod.h index 49c2a43f71661..269855efb77f3 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_demod.h +++ b/drivers/media/test-drivers/vidtv/vidtv_demod.h @@ -21,15 +21,6 @@ struct vidtv_demod_cnr_to_qual_s { u32 cnr_ok, cnr_good; }; -struct vidtv_demod_config { - struct dvb_frontend *frontend; - /* probability of losing the lock due to low snr */ - u8 drop_tslock_prob_on_low_snr; - /* probability of recovering when the signal improves */ - u8 recover_tslock_prob_on_good_snr; - u8 chosen_delsys; -}; - struct vidtv_demod_state { struct dvb_frontend frontend; struct vidtv_demod_config config; diff --git a/drivers/media/test-drivers/vidtv/vidtv_tuner.c b/drivers/media/test-drivers/vidtv/vidtv_tuner.c index a790508f935b3..ece4a94b0c3ac 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_tuner.c +++ b/drivers/media/test-drivers/vidtv/vidtv_tuner.c @@ -17,20 +17,12 @@ #include #include +#include "vidtv_config.h" + MODULE_DESCRIPTION("Virtual DTV Tuner"); MODULE_AUTHOR("Daniel W. S. Almeida"); MODULE_LICENSE("GPL"); -struct vidtv_tuner_config { - struct dvb_frontend *fe; - u32 mock_power_up_delay_msec; - u32 mock_tune_delay_msec; - u32 vidtv_valid_dvb_t_freqs[8]; - u32 vidtv_valid_dvb_c_freqs[8]; - u32 vidtv_valid_dvb_s_freqs[8]; - u8 max_frequency_shift_hz; -}; - struct vidtv_tuner_cnr_to_qual_s { /* attempt to use the same values as libdvbv5 */ u32 modulation; From patchwork Sat May 2 03:22:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Almeida X-Patchwork-Id: 209981 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9A8FDC47254 for ; Sat, 2 May 2020 03:22:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7709B24959 for ; Sat, 2 May 2020 03:22:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="PKcEoF52" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727866AbgEBDWy (ORCPT ); Fri, 1 May 2020 23:22:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39940 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726439AbgEBDWx (ORCPT ); Fri, 1 May 2020 23:22:53 -0400 Received: from mail-qk1-x741.google.com (mail-qk1-x741.google.com [IPv6:2607:f8b0:4864:20::741]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6C193C061A0C; Fri, 1 May 2020 20:22:53 -0700 (PDT) Received: by mail-qk1-x741.google.com with SMTP id c63so11238441qke.2; Fri, 01 May 2020 20:22:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=wLSxbksYe7vFAl+dAChpvHeW8F9QhUMpS/+xzmVyhR4=; b=PKcEoF52OoEQuSEvPnG7/F79zFA430vYjff3uLEaOAC77ileYYAVSA3SXQsDIKw+M3 HcDrfcuFrS/QUQDnpcCexhoyiNE6QsrA6UfmN9q4uiJTghyxQeUsPDShKXdG/o3qdYrU 9zeUjwc62srL/KTat/i1wO8BwvcelbUaGQUnZ4LmUpjrXbThKdrTP0i33IZVSfiIXT7W S7hxlYaUwhbEEaJkdnH+zwPfiAqI8DD3GGTLqEd6e0e9T+MDbfP3IVSDoTgMEDF0h/HM tsdL8nF1s3fr3RLhxwQybv0usgeJCk5BKLikcnCnJv0EdFROOp9pOVkcxoG2XGRwlTWj Ndbg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=wLSxbksYe7vFAl+dAChpvHeW8F9QhUMpS/+xzmVyhR4=; b=V3mLbD60WRWf4qNzGMP1GktEV163Dy6SnWCzoujOz95kUAod7rEzseGZayu1ny6sqH rbNdU3yTMootGxTpd/wXWWoZvNuZ00c4VBnuzmhoUYDU96gv+L6mvLQMensxkW8eL4XZ U1dPRBZJwy0KxDoL+14HTZv16MQtAO/9Ja8BsKayzrpz1acl5eq4M4OEyuJRM6t8K3jz 3cpXEDNo5zl7woFNNKIkgMOihK98ZWpZ9o/CTNGoMHbgGnt6PBa5F7yslBMwze38R8RT FHnPzszQtnMRzLFibIv3xlQdWOThux+EqlGdG1Mp5eQEJ/+fMzFiQ1o4LygpZFuiKU7C hUlg== X-Gm-Message-State: AGi0PuZBdnisxXNGt00hFAcK1AZkqJUPUzLna1TZdRk3qe+ZhlAzOZfh Shhqn30sD1yQ2et28LU1UQg= X-Google-Smtp-Source: APiQypJb3IAWNuPS7msR8bj0xvAODcxZmScGMJAQQ2/JpuoFHKaMLO78YDuwxGvzgaCnE85MOVC0nw== X-Received: by 2002:a37:792:: with SMTP id 140mr6325361qkh.58.1588389772555; Fri, 01 May 2020 20:22:52 -0700 (PDT) Received: from localhost.localdomain ([2804:18:602b:723a:1b2a:57a1:a611:34ed]) by smtp.gmail.com with ESMTPSA id c41sm4410399qta.96.2020.05.01.20.22.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 01 May 2020 20:22:52 -0700 (PDT) From: "Daniel W. S. Almeida" X-Google-Original-From: Daniel W. S. Almeida To: mchehab+huawei@kernel.org, sean@mess.org, kstewart@linuxfoundation.org, allison@lohutok.net, tglx@linutronix.de Cc: "Daniel W. S. Almeida" , linux-media@vger.kernel.org, skhan@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org, linux-kernel@vger.kernel.org Subject: [RFC, WIP, v4 06/11] media: vidtv: add wrappers for memcpy and memset Date: Sat, 2 May 2020 00:22:11 -0300 Message-Id: <20200502032216.197977-7-dwlsalmeida@gmail.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200502032216.197977-1-dwlsalmeida@gmail.com> References: <20200502032216.197977-1-dwlsalmeida@gmail.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: "Daniel W. S. Almeida" A lot of code in this driver is for serializing structures. This is error prone. Therefore, prevent buffer overflows by wrapping memcpy and memset, comparing the requested length against the buffer size. Signed-off-by: Daniel W. S. Almeida --- drivers/media/test-drivers/vidtv/Makefile | 3 ++ .../media/test-drivers/vidtv/vidtv_common.c | 44 +++++++++++++++++++ .../media/test-drivers/vidtv/vidtv_common.h | 28 ++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 drivers/media/test-drivers/vidtv/vidtv_common.c create mode 100644 drivers/media/test-drivers/vidtv/vidtv_common.h diff --git a/drivers/media/test-drivers/vidtv/Makefile b/drivers/media/test-drivers/vidtv/Makefile index a9f1993dd5443..9ea9485d42189 100644 --- a/drivers/media/test-drivers/vidtv/Makefile +++ b/drivers/media/test-drivers/vidtv/Makefile @@ -1,3 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +vidtv_demod-objs := vidtv_common.o +vidtv_bridge-objs := vidtv_common.o + obj-$(CONFIG_DVB_VIDTV) += vidtv_tuner.o vidtv_demod.o vidtv_bridge.o diff --git a/drivers/media/test-drivers/vidtv/vidtv_common.c b/drivers/media/test-drivers/vidtv/vidtv_common.c new file mode 100644 index 0000000000000..28f10630499a9 --- /dev/null +++ b/drivers/media/test-drivers/vidtv/vidtv_common.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * The Virtual DVB test driver serves as a reference DVB driver and helps + * validate the existing APIs in the media subsystem. It can also aid + * developers working on userspace applications. + * + * Written by Daniel W. S. Almeida + */ + +#include +#include +#include + +u32 vidtv_memcpy(void *to, + const void *from, + size_t len, + u32 offset, + u32 buf_sz) +{ + if (buf_sz && offset + len > buf_sz) { + pr_err("%s: overflow detected, skipping. Try increasing the buffer size", + __func__); + return 0; + } + + memcpy(to, from, len); + return len; +} + +u32 vidtv_memset(void *to, + int c, + size_t len, + u32 offset, + u32 buf_sz) +{ + if (buf_sz && offset + len > buf_sz) { + pr_err("%s: overflow detected, skipping. Try increasing the buffer size", + __func__); + return 0; + } + + memset(to, c, len); + return len; +} diff --git a/drivers/media/test-drivers/vidtv/vidtv_common.h b/drivers/media/test-drivers/vidtv/vidtv_common.h new file mode 100644 index 0000000000000..64072c010dc66 --- /dev/null +++ b/drivers/media/test-drivers/vidtv/vidtv_common.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * The Virtual DVB test driver serves as a reference DVB driver and helps + * validate the existing APIs in the media subsystem. It can also aid + * developers working on userspace applications. + * + * Written by Daniel W. S. Almeida + */ + +#ifndef VIDTV_COMMON_H +#define VIDTV_COMMON_H + +#include +#include + +u32 vidtv_memcpy(void *to, + const void *from, + size_t len, + u32 offset, + u32 buf_sz); + +u32 vidtv_memset(void *to, + int c, + size_t len, + u32 offset, + u32 buf_sz); + +#endif // VIDTV_COMMON_H From patchwork Sat May 2 03:22:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Almeida X-Patchwork-Id: 209980 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D5369C47254 for ; Sat, 2 May 2020 03:23:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B607324954 for ; Sat, 2 May 2020 03:23:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="KIin0d1i" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727943AbgEBDXJ (ORCPT ); Fri, 1 May 2020 23:23:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39982 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726439AbgEBDXI (ORCPT ); Fri, 1 May 2020 23:23:08 -0400 Received: from mail-qt1-x843.google.com (mail-qt1-x843.google.com [IPv6:2607:f8b0:4864:20::843]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F2BF4C061A0C; Fri, 1 May 2020 20:23:07 -0700 (PDT) Received: by mail-qt1-x843.google.com with SMTP id e17so9516633qtp.7; Fri, 01 May 2020 20:23:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=cAIbmftxDOrhV/ncqifVoZaPqlKMVj9TfphsMn6KJaY=; b=KIin0d1iXfxQF8sG+fa7qV1WtYNxBUIXOaiwqvO3xEWhsuSe3pod1bnh2y9naU3NSW Ln25ECiksTILIjnPUjmClwfvdQPESW+VtQz9H9LAosQ+028oAiiEAtfwMXlN2iGJcGFy r25UhM1knSer4G2nV3gd0dhK/O0hHSyp83M/pvQ7Tf9atwNCI74UB4BqvYVkWdUXdVoU Ih+LXAeWkU4Jt6fHPzetclO53r61bUXwYyCczujejT1sKY/YW/LwF7/r/W7to7skjXS4 Rpuis9/b5Czwo26rtym9cqsiEWIc2cNNU426nY/BKsaaoGf84a1+CkdgK5MYz5dmoWhA dQdg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=cAIbmftxDOrhV/ncqifVoZaPqlKMVj9TfphsMn6KJaY=; b=jX5bSm/iLD7IW+QRrf7do1aicV/0eBRJAENk2Qgw+edaTLBQjLN8t+qliGRnD0lTEl GDcbc/QiZaBLHZJskc2auoa9pZ+POBsyy9dW25nJjQaGjTIATQrCItSMdsTWf9Z1r7zK Gg62Ms3nqaHxkp/6dxerd1zzWEWAhJfHEKRFKW1dD4doJ1oEcGUtUn68UBcqsTvbPtlJ JC0wQJio4w7uRkQcc6lcsSKRYyAI5gZSRNjSOQma+76UsuBKF248B/IzHQ/WR4LHOW5S VkcjQPSoPeW6tL3RB9chJQVz33o4oQ8MSY361SwdnD+8FKWo6JjkZqfS2AuA+pNA+0uS EBXQ== X-Gm-Message-State: AGi0PuYYHZn0l+c7JliAzgXaK4sskHndv5RbsPBTk4PE+t6QZLGIwmze HH6bPDFQDm3uHHbIBkFNpYQ= X-Google-Smtp-Source: APiQypJWx+OPVCkmWEgiV0iWP7V9eGBH8r1pGGiHYg2dLmqQcLTS7rW5lhJOrBMIT1mCFXPRGsftVw== X-Received: by 2002:ac8:2c78:: with SMTP id e53mr6989149qta.365.1588389786934; Fri, 01 May 2020 20:23:06 -0700 (PDT) Received: from localhost.localdomain ([2804:18:602b:723a:1b2a:57a1:a611:34ed]) by smtp.gmail.com with ESMTPSA id c41sm4410399qta.96.2020.05.01.20.23.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 01 May 2020 20:23:06 -0700 (PDT) From: "Daniel W. S. Almeida" X-Google-Original-From: Daniel W. S. Almeida To: mchehab+huawei@kernel.org, sean@mess.org, kstewart@linuxfoundation.org, allison@lohutok.net, tglx@linutronix.de Cc: "Daniel W. S. Almeida" , linux-media@vger.kernel.org, skhan@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org, linux-kernel@vger.kernel.org Subject: [RFC, WIP, v4 09/11] media: vidtv: implement a PES packetizer Date: Sat, 2 May 2020 00:22:14 -0300 Message-Id: <20200502032216.197977-10-dwlsalmeida@gmail.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200502032216.197977-1-dwlsalmeida@gmail.com> References: <20200502032216.197977-1-dwlsalmeida@gmail.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: "Daniel W. S. Almeida" Implement the PES logic to convert encoder data into MPEG TS packets. These TS packets can then be fed into a TS multiplexer and eventually into userspace. Signed-off-by: Daniel W. S. Almeida --- drivers/media/test-drivers/vidtv/Makefile | 2 +- .../media/test-drivers/vidtv/vidtv_common.c | 7 + .../media/test-drivers/vidtv/vidtv_common.h | 2 + drivers/media/test-drivers/vidtv/vidtv_pes.c | 429 ++++++++++++++++++ drivers/media/test-drivers/vidtv/vidtv_pes.h | 185 ++++++++ 5 files changed, 624 insertions(+), 1 deletion(-) create mode 100644 drivers/media/test-drivers/vidtv/vidtv_pes.c create mode 100644 drivers/media/test-drivers/vidtv/vidtv_pes.h diff --git a/drivers/media/test-drivers/vidtv/Makefile b/drivers/media/test-drivers/vidtv/Makefile index e4f744aa53136..e3a6540f50e87 100644 --- a/drivers/media/test-drivers/vidtv/Makefile +++ b/drivers/media/test-drivers/vidtv/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 vidtv_demod-objs := vidtv_common.o -vidtv_bridge-objs := vidtv_common.o vidtv_ts.o vidtv_psi.o +vidtv_bridge-objs := vidtv_common.o vidtv_ts.o vidtv_psi.o vidtv_pes.o obj-$(CONFIG_DVB_VIDTV) += vidtv_tuner.o vidtv_demod.o vidtv_bridge.o diff --git a/drivers/media/test-drivers/vidtv/vidtv_common.c b/drivers/media/test-drivers/vidtv/vidtv_common.c index 28f10630499a9..b1412b497e1e3 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_common.c +++ b/drivers/media/test-drivers/vidtv/vidtv_common.c @@ -42,3 +42,10 @@ u32 vidtv_memset(void *to, memset(to, c, len); return len; } + +u64 vidtv_extract_bits(u64 value, u8 start_bit, u8 nbits) +{ + u64 mask = ((1 << nbits) - 1) << start_bit; + + return value & mask; +} diff --git a/drivers/media/test-drivers/vidtv/vidtv_common.h b/drivers/media/test-drivers/vidtv/vidtv_common.h index 64072c010dc66..3b68f95c5f6c8 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_common.h +++ b/drivers/media/test-drivers/vidtv/vidtv_common.h @@ -25,4 +25,6 @@ u32 vidtv_memset(void *to, u32 offset, u32 buf_sz); +u64 vidtv_extract_bits(u64 value, u8 start_bit, u8 nbits); + #endif // VIDTV_COMMON_H diff --git a/drivers/media/test-drivers/vidtv/vidtv_pes.c b/drivers/media/test-drivers/vidtv/vidtv_pes.c new file mode 100644 index 0000000000000..bc631bac07778 --- /dev/null +++ b/drivers/media/test-drivers/vidtv/vidtv_pes.c @@ -0,0 +1,429 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Vidtv serves as a reference DVB driver and helps validate the existing APIs + * in the media subsystem. It can also aid developers working on userspace + * applications. + * + * This file contains the logic to translate the ES data for one access unit + * from an encoder into MPEG TS packets. It does so by first encapsulating it + * with a PES header and then splitting it into TS packets. + * + * Written by Daniel W. S. Almeida + */ + +#include +#include +#include "vidtv_pes.h" +#include "vidtv_common.h" +#include "vidtv_ts.h" + +#define PRIVATE_STREAM_1_ID 0xbd /* private_stream_1. See SMPTE 302M-2007 p.6 */ +#define PES_HEADER_MAX_STUFFING_BYTES 32 +#define PES_TS_HEADER_MAX_STUFFING_BYTES 182 + +static u32 vidtv_pes_op_get_regular_len(bool send_pts, bool send_dts) +{ + u32 len = 0; + + /* the flags must always be sent */ + len += sizeof(struct vidtv_pes_optional); + + /* From all optionals, we might send these for now */ + if (send_pts && send_dts) + len += sizeof(struct vidtv_pes_optional_pts_dts); + else if (send_pts) + len += sizeof(struct vidtv_pes_optional_pts); + + return len; +} + +static u32 vidtv_pes_h_get_regular_len(bool send_pts, bool send_dts) +{ + /* PES header length notwithstanding stuffing bytes */ + u32 len = 0; + + len += sizeof(struct vidtv_mpeg_pes); + len += vidtv_pes_op_get_regular_len(send_pts, send_dts); + + return len; +} + +static u32 vidtv_pes_write_header_stuffing(struct vidtv_mpeg_pes *pes_h, + struct pes_header_write_args args) +{ + /* + * This is a fixed 8-bit value equal to '1111 1111' that can be inserted + * by the encoder, for example to meet the requirements of the channel. + * It is discarded by the decoder. No more than 32 stuffing bytes shall + * be present in one PES packet header. + */ + + WARN_ON(args.n_pes_h_s_bytes > PES_HEADER_MAX_STUFFING_BYTES); + + if (args.n_pes_h_s_bytes > PES_HEADER_MAX_STUFFING_BYTES) + args.n_pes_h_s_bytes = PES_HEADER_MAX_STUFFING_BYTES; + + /* gives the length of the remainder of the PES header in bytes */ + pes_h->length += args.n_pes_h_s_bytes; + + return vidtv_memset(args.dest_buf + args.dest_offset, + 0xff, + args.n_pes_h_s_bytes, + args.dest_offset, + args.dest_buf_sz); +} + +static u32 vidtv_pes_write_pts_dts(struct pes_header_write_args args) +{ + u32 nbytes = 0; /* the number of bytes written by this function */ + + struct vidtv_pes_optional_pts pts = {0}; + struct vidtv_pes_optional_pts_dts pts_dts = {0}; + void *op = NULL; + size_t op_sz = 0; + + if (!args.send_pts && args.send_dts) + return 0; + + /* see ISO/IEC 13818-1 : 2000 p. 32 */ + + if (args.send_pts && args.send_dts) { + cpu_to_be64s(&args.pts); + cpu_to_be64s(&args.dts); + pts_dts.three = 0x3; + + pts_dts.pts1 = vidtv_extract_bits(args.pts, 30, 3); + pts_dts.marker1 = 0x1; + pts_dts.pts2 = vidtv_extract_bits(args.pts, 15, 15); + pts_dts.marker2 = 0x1; + pts_dts.pts3 = vidtv_extract_bits(args.pts, 0, 15); + pts_dts.marker3 = 0x1; + + pts_dts.one = 0x1; + + pts_dts.dts1 = vidtv_extract_bits(args.dts, 30, 3); + pts_dts.marker1 = 0x1; + pts_dts.dts2 = vidtv_extract_bits(args.dts, 15, 15); + pts_dts.marker2 = 0x1; + pts_dts.dts3 = vidtv_extract_bits(args.dts, 0, 15); + pts_dts.marker3 = 0x1; + + be64_to_cpus(&args.pts); + be64_to_cpus(&args.dts); + + op = &pts_dts; + op_sz = sizeof(pts_dts); + + } else if (args.send_pts) { + cpu_to_be64s(&args.pts); + pts.two = 0x2; + pts.pts1 = vidtv_extract_bits(args.pts, 30, 3); + pts.marker1 = 0x1; + pts.pts2 = vidtv_extract_bits(args.pts, 15, 15); + pts.marker2 = 0x1; + pts.pts3 = vidtv_extract_bits(args.pts, 0, 15); + pts.marker3 = 0x1; + be64_to_cpus(&args.pts); + + op = &pts; + op_sz = sizeof(pts); + } + + /* copy PTS/DTS optional */ + nbytes += vidtv_memcpy(args.dest_buf + args.dest_offset + nbytes, + op, + op_sz, + args.dest_offset + nbytes, + args.dest_buf_sz); + + return nbytes; +} + +static u32 vidtv_pes_write_h(struct pes_header_write_args args) +{ + u32 nbytes = 0; /* the number of bytes written by this function */ + + struct vidtv_mpeg_pes pes_header = {0}; + struct vidtv_pes_optional pes_optional = {0}; + struct pes_header_write_args pts_dts_args = args; + + pes_header.packet_start_code_prefix = PES_START_CODE_PREFIX; + + pes_header.stream_id = (args.is_s302m_pkt) ? + PRIVATE_STREAM_1_ID : + args.stream_id; + + pes_header.length = vidtv_pes_op_get_regular_len(args.send_pts, + args.send_dts); + + pes_optional.two = 0x2; + + pes_optional.PTS_DTS = (args.send_pts && args.send_dts) ? + 0x3 : + (args.send_pts) ? + 0x2 : + 0x0; + + /* copy header */ + cpu_to_be32s(&pes_header.bitfield); + cpu_to_be16s(&pes_header.length); + + nbytes += vidtv_memcpy(args.dest_buf + args.dest_offset + nbytes, + &pes_header, + sizeof(pes_header), + args.dest_offset + nbytes, + args.dest_buf_sz); + + be32_to_cpus(&pes_header.bitfield); + be16_to_cpus(&pes_header.length); + + /* copy optional header */ + cpu_to_be16s(&pes_optional.bitfield); + + nbytes += vidtv_memcpy(args.dest_buf + args.dest_offset + nbytes, + &pes_optional, + sizeof(pes_optional), + args.dest_offset + nbytes, + args.dest_buf_sz); + + be16_to_cpus(&pes_optional.bitfield); + + pts_dts_args.dest_offset = args.dest_offset + nbytes; + nbytes += vidtv_pes_write_pts_dts(pts_dts_args); + + /* write any PES header stuffing */ + nbytes += vidtv_pes_write_header_stuffing(&pes_header, args); + + return nbytes; +} + +static u32 vidtv_pes_write_stuffing(struct vidtv_mpeg_ts *ts_h, + void *dest_buf, + u32 dest_offset, + u32 n_stuffing_bytes, + u32 buf_sz) +{ + /* + * For Transport Stream packets carrying PES packets, stuffing is + * needed when there is insufficient PES packet data to completely + * fill the Transport Stream packet payload bytes. Stuffing is + * accomplished by defining an adaptation field longer than the sum of + * the lengths of the data elements in it, so that the payload bytes + * remaining after the adaptation field exactly accommodates the + * available PES packet data. The extra space in the adaptation field + * is filled with stuffing bytes. + * + */ + + /* the number of bytes written by this function */ + u32 nbytes = 0; + struct vidtv_mpeg_ts_adaption ts_adap = {0}; + + if (!n_stuffing_bytes) + return nbytes; + + ts_h->adaptation_field = 1; + + WARN_ON(n_stuffing_bytes > PES_TS_HEADER_MAX_STUFFING_BYTES); + + if (n_stuffing_bytes > PES_TS_HEADER_MAX_STUFFING_BYTES) + n_stuffing_bytes = PES_TS_HEADER_MAX_STUFFING_BYTES; + + /* the AF will only be its 'length' field with a value of zero */ + if (n_stuffing_bytes == 1) { + nbytes += vidtv_memset(dest_buf + dest_offset + nbytes, + 0, + n_stuffing_bytes, + dest_offset + nbytes, + buf_sz); + + return nbytes; + } + + n_stuffing_bytes -= sizeof(ts_adap); + + /* length _immediately_ following 'adaptation_field_length' */ + ts_adap.length = sizeof(ts_adap) - + sizeof(ts_adap.length) + + n_stuffing_bytes; + + /* write the adap after the TS header */ + nbytes += vidtv_memcpy(dest_buf + dest_offset + nbytes, + &ts_adap, + sizeof(ts_adap), + dest_offset + nbytes, + buf_sz); + + /* write the stuffing bytes */ + nbytes += vidtv_memset(dest_buf + dest_offset + nbytes, + 0xff, + n_stuffing_bytes, + dest_offset + nbytes, + buf_sz); + + return nbytes; +} + +static u32 vidtv_pes_write_ts_h(struct pes_ts_header_write_args args) +{ + /* number of bytes written by this function */ + u32 nbytes = 0; + struct vidtv_mpeg_ts ts_header = {0}; + + ts_header.sync_byte = TS_SYNC_BYTE; + ts_header.tei = 0; + ts_header.pid = args.pid; + ts_header.priority = 0; + ts_header.scrambling = 0; /* not scrambled */ + ts_header.adaptation_field = 0; + ts_header.payload = 1; + + ts_header.payload_start = (!args.wrote_pes_header) ? 1 : 0; + ts_header.continuity_counter = *args.continuity_counter; + + vidtv_ts_inc_cc(args.continuity_counter); + + cpu_to_be16s(&ts_header.bitfield); + + /* write the TS header */ + nbytes += vidtv_memcpy(args.dest_buf + args.dest_offset + nbytes, + &ts_header, + sizeof(ts_header), + args.dest_offset + nbytes, + args.dest_buf_sz); + + be16_to_cpus(&ts_header.bitfield); + /* write stuffing, if any */ + nbytes += vidtv_pes_write_stuffing(&ts_header, + args.dest_buf, + args.dest_offset + nbytes, + args.n_stuffing_bytes, + args.dest_buf_sz); + + return nbytes; +} + +u32 vidtv_pes_write_into(struct pes_write_args args) +{ + u32 nbytes_past_boundary = (args.dest_offset % TS_PACKET_LEN); + bool aligned = (nbytes_past_boundary == 0); + + struct pes_ts_header_write_args ts_header_args = {0}; + struct pes_header_write_args pes_header_args = {0}; + + /* number of bytes written by this function */ + u32 nbytes = 0; + u32 remaining_len = args.access_unit_len; + + bool wrote_pes_header = false; + bool stuff = false; + + u32 available_space = 0; + u32 payload_write_len = 0; + u32 num_stuffing_bytes = 0; + + /* Just a sanity check, should not really happen because we stuff the + * TS packet when we finish writing the PES data, but if this happens + * then we have messed up the logic somewhere. + * + * Also note that, unlike packets for PSI data, we need to carry PES + * packets aligned with the payload of transport packets, that is the + * first byte of each PES header must be the first byte in the payload + * of a transport packet. As a consequence, the last byte of a PES + * packet must be the last byte of the payload of a transport packet. + */ + WARN_ON(!aligned); + + if (args.send_dts && !args.send_pts) { + pr_warn("%s: forbidden value '01' for PTS_DTS flags", __func__); + args.send_pts = true; + args.pts = args.dts; + } + + /* see SMPTE 302M clause 6.4 */ + if (args.is_s302m_pkt) { + args.send_dts = false; + args.send_pts = true; + } + + while (remaining_len) { + /* + * The amount of space initially available in the TS packet. + * if this is the beginning of the PES packet, we need to + * take into account the space needed for the TS header _and_ + * for the PES header + */ + available_space = (!wrote_pes_header) ? + TS_PAYLOAD_LEN - + vidtv_pes_h_get_regular_len(args.send_pts, + args.send_dts) : + TS_PAYLOAD_LEN; + + /* if the encoder has inserted stuffing bytes in the PES + * header, account for them. + */ + available_space -= args.n_pes_h_s_bytes; + + /* whether we need to stuff the TS packet to align the buffer */ + stuff = remaining_len < available_space; + + /* + * how much of the _actual_ payload we should write in this + * packet. + */ + payload_write_len = (stuff) ? + remaining_len : + available_space; + + num_stuffing_bytes = available_space - payload_write_len; + + /* write ts header */ + ts_header_args.dest_buf = args.dest_buf; + ts_header_args.dest_offset = args.dest_offset + nbytes; + ts_header_args.dest_buf_sz = args.dest_buf_sz; + ts_header_args.pid = args.pid; + ts_header_args.continuity_counter = args.continuity_counter; + ts_header_args.wrote_pes_header = wrote_pes_header; + ts_header_args.n_stuffing_bytes = num_stuffing_bytes; + + nbytes += vidtv_pes_write_ts_h(ts_header_args); + + if (!wrote_pes_header) { + /* write the PES header only once */ + pes_header_args.dest_buf = args.dest_buf; + + pes_header_args.dest_offset = args.dest_offset + + nbytes; + + pes_header_args.dest_buf_sz = args.dest_buf_sz; + pes_header_args.is_s302m_pkt = args.is_s302m_pkt; + pes_header_args.send_pts = args.send_pts; + pes_header_args.pts = args.pts; + pes_header_args.send_dts = args.send_dts; + pes_header_args.dts = args.dts; + pes_header_args.stream_id = args.stream_id; + pes_header_args.n_pes_h_s_bytes = args.n_pes_h_s_bytes; + + nbytes += vidtv_pes_write_h(pes_header_args); + wrote_pes_header = true; + } + + /* write as much of the payload as we possibly can */ + nbytes += vidtv_memcpy(args.dest_buf + + args.dest_offset + + nbytes, + args.from, + payload_write_len, + args.dest_offset + nbytes, + args.dest_buf_sz); + + args.from += payload_write_len; + args.dest_offset += nbytes; + + /* sanity check for underflow */ + WARN_ON(remaining_len - payload_write_len > remaining_len); + remaining_len -= payload_write_len; + } + + return nbytes; +} diff --git a/drivers/media/test-drivers/vidtv/vidtv_pes.h b/drivers/media/test-drivers/vidtv/vidtv_pes.h new file mode 100644 index 0000000000000..00ede32adf476 --- /dev/null +++ b/drivers/media/test-drivers/vidtv/vidtv_pes.h @@ -0,0 +1,185 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Vidtv serves as a reference DVB driver and helps validate the existing APIs + * in the media subsystem. It can also aid developers working on userspace + * applications. + * + * This file contains the logic to translate the ES data for one access unit + * from an encoder into MPEG TS packets. It does so by first encapsulating it + * with a PES header and then splitting it into TS packets. + * + * Written by Daniel W. S. Almeida + */ + +#ifndef VIDTV_PES_H +#define VIDTV_PES_H + +#include +#include +#include "vidtv_common.h" + +#define PES_MAX_LEN 65536 /* Set 'length' to 0 if greater */ +#define PES_START_CODE_PREFIX 0x001 /* 00 00 01 */ + +struct vidtv_pes_optional_pts { + struct { + #if defined(__LITTLE_ENDIAN_BITFIELD) + u8 marker3:1; /* always 0x1 */ + u16 pts3:15; + u8 marker2:1; /* always 0x1 */ + u16 pts2:15; + u8 marker1:1; /* always 0x1 */ + u8 pts1:3; + u8 two:4; /* always 0010b */ + #elif defined(__BIG_ENDIAN_BITFIELD) + u8 two:4; /* always 0010b */ + u8 pts1:3; + u8 marker1:1; /* always 0x1 */ + u16 pts2:15; + u8 marker2:1; /* always 0x1 */ + u16 pts3:15; + u8 marker3:1; /* always 0x1 */ + #else + #error "Please fix " + #endif + } __packed; +} __packed; + +struct vidtv_pes_optional_pts_dts { + struct { + #if defined(__LITTLE_ENDIAN_BITFIELD) + u8 marker6:1; /* always 0x1 */ + u16 dts3:15; + u8 marker5:1; /* always 0x1 */ + u16 dts2:15; + u8 marker4:1; /* always 0x1 */ + u8 dts1:3; + u8 one:4; /* always 0001b */ + u8 marker3:1; /* always 0x1 */ + u16 pts3:15; + u8 marker2:1; /* always 0x1 */ + u16 pts2:15; + u8 marker1:1; /* always 0x1 */ + u8 pts1:3; + u8 three:4; /* always 0011b */ + #elif defined(__BIG_ENDIAN_BITFIELD) + u8 three:4; /* always 0011b */ + u8 pts1:3; + u8 marker1:1; /* always 0x1 */ + u16 pts2:15; + u8 marker2:1; /* always 0x1 */ + u16 pts3:15; + u8 marker3:1; /* always 0x1 */ + u8 one:4; /* always 0001b */ + u8 dts1:3; + u8 marker4:1; /* always 0x1 */ + u16 dts2:15; + u8 marker5:1; /* always 0x1 */ + u16 dts3:15; + u8 marker6:1; /* always 0x1 */ + #else + #error "Please fix " + #endif + } __packed; +} __packed; + +struct vidtv_pes_optional { + union { + u16 bitfield; + struct { + u16 two:2; /* always 0x2*/ + u16 PES_scrambling_control:2; + u16 PES_priority:1; + u16 data_alignment_indicator:1; /* ununsed for us */ + u16 copyright:1; + u16 original_or_copy:1; + u16 PTS_DTS:2; + /* These flags show which components are actually + * present in the "optinal fields" in the optinal PES + * header and which are not. Vidtv currently does + * not need any of these. + */ + u16 ESCR:1; + u16 ES_rate:1; + u16 DSM_trick_mode:1; + u16 additional_copy_info:1; + u16 PES_CRC:1; + u16 PES_extension:1; + } __packed; + } __packed; + u8 length; +} __packed; + +struct vidtv_mpeg_pes { + union { + u32 bitfield; + struct { + /* These two together make the 32-bit start-code */ + u32 packet_start_code_prefix:24; + u32 stream_id:8; + } __packed; + } __packed; + /* after this field until the end of the PES data payload */ + u16 length; + struct vidtv_pes_optional optional[]; +} __packed; + +struct pes_header_write_args { + void *dest_buf; + u32 dest_offset; + u32 dest_buf_sz; + bool is_s302m_pkt; + + bool send_pts; + u64 pts; + + bool send_dts; + u64 dts; + + u16 stream_id; + /* might be used by an encoder if needed, gets discarded by decoder */ + u32 n_pes_h_s_bytes; +}; + +struct pes_ts_header_write_args { + void *dest_buf; + u32 dest_offset; + u32 dest_buf_sz; + u16 pid; + u8 *continuity_counter; + bool wrote_pes_header; + u32 n_stuffing_bytes; +}; + +struct pes_write_args { + void *dest_buf; /* pointer to a program mux buffer */ + void *from; /* pointer to the encoder buffer */ + + /* the size of one access unit (with any headers it might need) */ + u32 access_unit_len; + + u32 dest_offset; /* where to start writing in the program mux buffer */ + u32 dest_buf_sz; /* how big is the program mux buffer */ + u16 pid; /* TS packet ID */ + + /* use SMPTE 302M to packetize the data */ + bool is_s302m_pkt; + + u8 *continuity_counter; /* incremented for every TS packet */ + + /* Examples: Audio streams (0xc0-0xdf), Video streams (0xe0-0xef) */ + u16 stream_id; + + bool send_pts; + u64 pts; + + bool send_dts; + u64 dts; + + /* might be used by an encoder if needed, gets discarded by decoder */ + u32 n_pes_h_s_bytes; +}; + +u32 vidtv_pes_write_into(struct pes_write_args args); + +#endif // VIDTV_PES_H From patchwork Sat May 2 03:22:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Almeida X-Patchwork-Id: 209979 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C27CC4725B for ; Sat, 2 May 2020 03:23:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 46D3020731 for ; Sat, 2 May 2020 03:23:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="u28DUlFg" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727963AbgEBDXQ (ORCPT ); Fri, 1 May 2020 23:23:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39998 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726439AbgEBDXN (ORCPT ); Fri, 1 May 2020 23:23:13 -0400 Received: from mail-qk1-x744.google.com (mail-qk1-x744.google.com [IPv6:2607:f8b0:4864:20::744]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 27554C061A0C; Fri, 1 May 2020 20:23:13 -0700 (PDT) Received: by mail-qk1-x744.google.com with SMTP id c63so11238954qke.2; Fri, 01 May 2020 20:23:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=jDDEMN/30hOo7R+KjT+5XLDSXHeWUGBpj8iKrJCUbes=; b=u28DUlFgeZpTA5mZ7FhVnopwhyhlF2X7IzIv5Wr3ZS1LJUjA/awBqZUo4R6eTYY8Qg Lr8G3eENyTraRpbYGe89DcKsTb+ckp7Mfb+iLXymbcsYFE5xq7xcmygg0p2FEDr30nsp YlYezN6b0X+WF3faakwAt8/HDUGleQqZvTEr+xCWlRhTrdIL20DHF5U5KYV9UG6S9Q2j pNkw1D+OU5TBy2p3opJ2H9ChYhgej8iEQU6FOIZ+l3ckWqoW2sASuvONaIFhBH3kII9T L6SD57aiRDmR1H0GFfLK+uYQthsrTD3/6yfIiylLTYvNygNuA6J6CDzfnxIAdFSp/dgF WQwg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=jDDEMN/30hOo7R+KjT+5XLDSXHeWUGBpj8iKrJCUbes=; b=K42UTUxuyBQiUwn8Y1kHOolD6t9sMWTDC+75mgqKpfzs1SQQ4ej2g4MO7o9uMbbhBJ BEETq68CqchfcgWWSiB9oKgxfKQwX+j3dHr1W861R/OdWKiBQBwi1b6ChFGlz5QveEH2 ZeJneFZl9swpnGPmYBw6cs43Qg39wi2KWo23yJSMiVvU5eNiC63f20QsXGIpUe5qcIE9 AuodTiIVt48y5zMCyoBUzN0bI/I0wI1wIHdRFFYLrryUwOFsQc2EjZNPyZZKFm7KMv8U LGmJFsF7Olr0Ycg2v4Iqq0eZyx9BTiIXctdaOtOCReVWUBhct0ceVdGGssGcpBRIOa8g uoBg== X-Gm-Message-State: AGi0PuY2hEX9l0dP5IfoQbDwgRFbHQQQdGtFr1B7QBFozTpCk7m/TZ/K 7HTOS3pd3CSpMRuhXwTPclg= X-Google-Smtp-Source: APiQypKmX6Rc0pjYe6fd4ShoOMcqQ1blU277a8iyzpX7HQCyUMdyCvjBq/wW7znTfeVS6n2XMnO2Jg== X-Received: by 2002:a37:8d85:: with SMTP id p127mr6730585qkd.44.1588389791830; Fri, 01 May 2020 20:23:11 -0700 (PDT) Received: from localhost.localdomain ([2804:18:602b:723a:1b2a:57a1:a611:34ed]) by smtp.gmail.com with ESMTPSA id c41sm4410399qta.96.2020.05.01.20.23.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 01 May 2020 20:23:11 -0700 (PDT) From: "Daniel W. S. Almeida" X-Google-Original-From: Daniel W. S. Almeida To: mchehab+huawei@kernel.org, sean@mess.org, kstewart@linuxfoundation.org, allison@lohutok.net, tglx@linutronix.de Cc: "Daniel W. S. Almeida" , linux-media@vger.kernel.org, skhan@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org, linux-kernel@vger.kernel.org Subject: [RFC, WIP, v4 10/11] media: vidtv: Implement a SMPTE 302M encoder Date: Sat, 2 May 2020 00:22:15 -0300 Message-Id: <20200502032216.197977-11-dwlsalmeida@gmail.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200502032216.197977-1-dwlsalmeida@gmail.com> References: <20200502032216.197977-1-dwlsalmeida@gmail.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: "Daniel W. S. Almeida" Implement a S302M encoder to make it possible to insert PCM audio data in the generated MPEG Transport Stream. This shall enable passing an audio signal into userspace so it can be decoded and played by media software. Signed-off-by: Daniel W. S. Almeida --- drivers/media/test-drivers/vidtv/Makefile | 3 +- .../media/test-drivers/vidtv/vidtv_common.h | 2 + .../media/test-drivers/vidtv/vidtv_encoder.h | 103 +++ .../media/test-drivers/vidtv/vidtv_s302m.c | 608 ++++++++++++++++++ .../media/test-drivers/vidtv/vidtv_s302m.h | 99 +++ 5 files changed, 814 insertions(+), 1 deletion(-) create mode 100644 drivers/media/test-drivers/vidtv/vidtv_encoder.h create mode 100644 drivers/media/test-drivers/vidtv/vidtv_s302m.c create mode 100644 drivers/media/test-drivers/vidtv/vidtv_s302m.h diff --git a/drivers/media/test-drivers/vidtv/Makefile b/drivers/media/test-drivers/vidtv/Makefile index e3a6540f50e87..c916eb19d73bb 100644 --- a/drivers/media/test-drivers/vidtv/Makefile +++ b/drivers/media/test-drivers/vidtv/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 vidtv_demod-objs := vidtv_common.o -vidtv_bridge-objs := vidtv_common.o vidtv_ts.o vidtv_psi.o vidtv_pes.o +vidtv_bridge-objs := vidtv_common.o vidtv_ts.o vidtv_psi.o vidtv_pes.o \ + vidtv_s302m.o obj-$(CONFIG_DVB_VIDTV) += vidtv_tuner.o vidtv_demod.o vidtv_bridge.o diff --git a/drivers/media/test-drivers/vidtv/vidtv_common.h b/drivers/media/test-drivers/vidtv/vidtv_common.h index 3b68f95c5f6c8..170646497eb58 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_common.h +++ b/drivers/media/test-drivers/vidtv/vidtv_common.h @@ -13,6 +13,8 @@ #include #include +#define CLOCK_UNIT_90KHZ 90000 + u32 vidtv_memcpy(void *to, const void *from, size_t len, diff --git a/drivers/media/test-drivers/vidtv/vidtv_encoder.h b/drivers/media/test-drivers/vidtv/vidtv_encoder.h new file mode 100644 index 0000000000000..f483200fd781c --- /dev/null +++ b/drivers/media/test-drivers/vidtv/vidtv_encoder.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Vidtv serves as a reference DVB driver and helps validate the existing APIs + * in the media subsystem. It can also aid developers working on userspace + * applications. + * + * This file contains a generic encoder type that can provide data for a stream + * + * Written by Daniel W. S. Almeida + */ + +#ifndef VIDTV_ENCODER_H +#define VIDTV_ENCODER_H + +#include + +enum vidtv_encoder_id { + /* add IDs here when implementing new encoders */ + S302M, +}; + +struct vidtv_encoder { + /* so we can cast to a concrete implementation when needed */ + enum vidtv_encoder_id id; + /* usually same as the stream name */ + char *name; + + /* the encoder's internal buffer for the access units */ + u8 *encoder_buf; + /* the encoder buffer size, in bytes */ + u32 encoder_buf_sz; + + /* our byte position in the encoder buffer */ + u32 encoder_buf_offset; + + /* how many samples we have encoded in total */ + u32 sample_count; + + u32 previous_sample_count; + + /* the number of access units ready */ + u32 nunits; + /* the number of samples per access unit */ + u32 *samples_per_unit; + /* pts array mapping pts[i] -> AU[i] */ + u64 *pts; + /* dts array mapping dts[i] -> AU[i] */ + u64 *dts; + /* array mapping how many bytes were written per AU */ + u32 *nbytes; + /* array keeping track of AU offsets in buffer */ + u32 *offsets; + + /* + * the source of raw data to be encoded, encoder might set a default + * source if NULL + */ + void *src_buf; + /* the source buffer size, in bytes */ + u32 src_buf_sz; + + /* our byte position in the src buffer */ + u32 src_buf_offset; + + bool video; /* either video or audio */ + void *ctx; /* encoder-specific state */ + + /* Examples: Audio streams (0xc0-0xdf), Video streams (0xe0-0xef) */ + u16 stream_id; + + /* the TS PID to use for the elementary stream in this encoder */ + u16 es_pid; + + /* prepare enough AUs for the given amount of time */ + void *(*encode)(struct vidtv_encoder *e, u64 elapsed_time_usecs); + + /* clear the encoder output */ + u8 (*clear)(struct vidtv_encoder *e); + + /* attempt to synchronize with the encoder below */ + struct vidtv_encoder *sync; + + u32 sampling_rate_hz; /* or fps, if video */ + + /* controls dynamic memory allocation for the arrays */ + u8 access_unit_capacity; + + /* + * called when the encoder runs out of data + * the encoder might optionally wrap around the src data if this is not + * implemented + * this is so the source can read data in a piecemeal fashion instead + * of having to provide it all at once + */ + void (*last_sample_cb)(u32 sample_no); + + /* destroy this encoder, freeing any allocated resources */ + void (*destroy)(struct vidtv_encoder *e); + + struct vidtv_encoder *next; +}; + +#endif /* VIDTV_ENCODER_H */ diff --git a/drivers/media/test-drivers/vidtv/vidtv_s302m.c b/drivers/media/test-drivers/vidtv/vidtv_s302m.c new file mode 100644 index 0000000000000..b08bfff7b8f27 --- /dev/null +++ b/drivers/media/test-drivers/vidtv/vidtv_s302m.c @@ -0,0 +1,608 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Vidtv serves as a reference DVB driver and helps validate the existing APIs + * in the media subsystem. It can also aid developers working on userspace + * applications. + * + * This file contains the code for an AES3 (also known as AES/EBU) encoder. + * It is based on EBU Tech 3250 and SMPTE 302M technical documents. + * + * This encoder currently supports 16bit AES3 subframes using 16bit signed + * integers. + * + * Note: AU stands for Access Unit, and AAU stands for Audio Access Unit + * + * Written by Daniel W. S. Almeida + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "vidtv_s302m.h" +#include "vidtv_encoder.h" +#include "vidtv_common.h" + +#define S302M_SAMPLING_RATE_HZ 48000 + +/* see EBU Tech 3250 2004 clause 4 */ +#define CHANNEL_STATUS_BIT_LEN 92 + +#define S302M_2CHANNELS 0 +#define S302M_BITS_PER_SAMPLE_16 0 + +/* see preamble definition in EBU Tech 3250 2004 clause 2.4 */ +#define PREAMBLE_X_F0 0xe2 /* sub-frame 1 */ +#define PREAMBLE_Y_F0 0xe4 /* sub-frame 2 */ +#define PREAMBLE_Z_F0 0xe8 /* sub-frame 1 + block start */ +/* F0 and F1 refer to whether the F bit was set in the previous sub-frame */ +#define PREAMBLE_X_F1 0x1d /* sub-frame 1 */ +#define PREAMBLE_Y_F1 0X1b /* sub-frame 2 */ +#define PREAMBLE_Z_F1 0x17 /* sub-frame 1 + block start */ + +#define S302M_BLOCK_SZ 192 +#define S302M_SIN_LUT_SZ 1024 + +static int s302m_sin_lut[S302M_SIN_LUT_SZ] = { + 0x8000, 0x80c9, 0x8192, 0x825b, 0x8324, 0x83ed, 0x84b6, 0x857e, + 0x8647, 0x8710, 0x87d9, 0x88a1, 0x896a, 0x8a32, 0x8afb, 0x8bc3, + 0x8c8b, 0x8d53, 0x8e1b, 0x8ee3, 0x8fab, 0x9072, 0x9139, 0x9201, + 0x92c7, 0x938e, 0x9455, 0x951b, 0x95e1, 0x96a7, 0x976d, 0x9833, + 0x98f8, 0x99bd, 0x9a82, 0x9b47, 0x9c0b, 0x9ccf, 0x9d93, 0x9e56, + 0x9f19, 0x9fdc, 0xa09f, 0xa161, 0xa223, 0xa2e5, 0xa3a6, 0xa467, + 0xa527, 0xa5e8, 0xa6a7, 0xa767, 0xa826, 0xa8e5, 0xa9a3, 0xaa61, + 0xab1f, 0xabdc, 0xac98, 0xad55, 0xae10, 0xaecc, 0xaf87, 0xb041, + 0xb0fb, 0xb1b5, 0xb26e, 0xb326, 0xb3de, 0xb496, 0xb54d, 0xb603, + 0xb6b9, 0xb76f, 0xb824, 0xb8d8, 0xb98c, 0xba3f, 0xbaf2, 0xbba4, + 0xbc56, 0xbd07, 0xbdb7, 0xbe67, 0xbf17, 0xbfc5, 0xc073, 0xc121, + 0xc1cd, 0xc279, 0xc325, 0xc3d0, 0xc47a, 0xc524, 0xc5cc, 0xc675, + 0xc71c, 0xc7c3, 0xc869, 0xc90f, 0xc9b3, 0xca57, 0xcafb, 0xcb9d, + 0xcc3f, 0xcce0, 0xcd81, 0xce20, 0xcebf, 0xcf5d, 0xcffb, 0xd097, + 0xd133, 0xd1ce, 0xd268, 0xd302, 0xd39a, 0xd432, 0xd4c9, 0xd55f, + 0xd5f5, 0xd689, 0xd71d, 0xd7b0, 0xd842, 0xd8d3, 0xd964, 0xd9f3, + 0xda82, 0xdb0f, 0xdb9c, 0xdc28, 0xdcb3, 0xdd3d, 0xddc7, 0xde4f, + 0xded7, 0xdf5d, 0xdfe3, 0xe068, 0xe0eb, 0xe16e, 0xe1f0, 0xe271, + 0xe2f1, 0xe370, 0xe3ee, 0xe46b, 0xe4e8, 0xe563, 0xe5dd, 0xe656, + 0xe6cf, 0xe746, 0xe7bc, 0xe831, 0xe8a6, 0xe919, 0xe98b, 0xe9fc, + 0xea6d, 0xeadc, 0xeb4a, 0xebb7, 0xec23, 0xec8e, 0xecf8, 0xed61, + 0xedc9, 0xee30, 0xee96, 0xeefa, 0xef5e, 0xefc1, 0xf022, 0xf083, + 0xf0e2, 0xf140, 0xf19d, 0xf1f9, 0xf254, 0xf2ae, 0xf307, 0xf35e, + 0xf3b5, 0xf40a, 0xf45f, 0xf4b2, 0xf504, 0xf555, 0xf5a5, 0xf5f3, + 0xf641, 0xf68d, 0xf6d8, 0xf722, 0xf76b, 0xf7b3, 0xf7fa, 0xf83f, + 0xf884, 0xf8c7, 0xf909, 0xf94a, 0xf989, 0xf9c8, 0xfa05, 0xfa41, + 0xfa7c, 0xfab6, 0xfaee, 0xfb26, 0xfb5c, 0xfb91, 0xfbc5, 0xfbf8, + 0xfc29, 0xfc59, 0xfc88, 0xfcb6, 0xfce3, 0xfd0e, 0xfd39, 0xfd62, + 0xfd89, 0xfdb0, 0xfdd5, 0xfdfa, 0xfe1d, 0xfe3e, 0xfe5f, 0xfe7e, + 0xfe9c, 0xfeb9, 0xfed5, 0xfeef, 0xff09, 0xff21, 0xff37, 0xff4d, + 0xff61, 0xff74, 0xff86, 0xff97, 0xffa6, 0xffb4, 0xffc1, 0xffcd, + 0xffd8, 0xffe1, 0xffe9, 0xfff0, 0xfff5, 0xfff9, 0xfffd, 0xfffe, + 0xffff, 0xfffe, 0xfffd, 0xfff9, 0xfff5, 0xfff0, 0xffe9, 0xffe1, + 0xffd8, 0xffcd, 0xffc1, 0xffb4, 0xffa6, 0xff97, 0xff86, 0xff74, + 0xff61, 0xff4d, 0xff37, 0xff21, 0xff09, 0xfeef, 0xfed5, 0xfeb9, + 0xfe9c, 0xfe7e, 0xfe5f, 0xfe3e, 0xfe1d, 0xfdfa, 0xfdd5, 0xfdb0, + 0xfd89, 0xfd62, 0xfd39, 0xfd0e, 0xfce3, 0xfcb6, 0xfc88, 0xfc59, + 0xfc29, 0xfbf8, 0xfbc5, 0xfb91, 0xfb5c, 0xfb26, 0xfaee, 0xfab6, + 0xfa7c, 0xfa41, 0xfa05, 0xf9c8, 0xf989, 0xf94a, 0xf909, 0xf8c7, + 0xf884, 0xf83f, 0xf7fa, 0xf7b3, 0xf76b, 0xf722, 0xf6d8, 0xf68d, + 0xf641, 0xf5f3, 0xf5a5, 0xf555, 0xf504, 0xf4b2, 0xf45f, 0xf40a, + 0xf3b5, 0xf35e, 0xf307, 0xf2ae, 0xf254, 0xf1f9, 0xf19d, 0xf140, + 0xf0e2, 0xf083, 0xf022, 0xefc1, 0xef5e, 0xeefa, 0xee96, 0xee30, + 0xedc9, 0xed61, 0xecf8, 0xec8e, 0xec23, 0xebb7, 0xeb4a, 0xeadc, + 0xea6d, 0xe9fc, 0xe98b, 0xe919, 0xe8a6, 0xe831, 0xe7bc, 0xe746, + 0xe6cf, 0xe656, 0xe5dd, 0xe563, 0xe4e8, 0xe46b, 0xe3ee, 0xe370, + 0xe2f1, 0xe271, 0xe1f0, 0xe16e, 0xe0eb, 0xe068, 0xdfe3, 0xdf5d, + 0xded7, 0xde4f, 0xddc7, 0xdd3d, 0xdcb3, 0xdc28, 0xdb9c, 0xdb0f, + 0xda82, 0xd9f3, 0xd964, 0xd8d3, 0xd842, 0xd7b0, 0xd71d, 0xd689, + 0xd5f5, 0xd55f, 0xd4c9, 0xd432, 0xd39a, 0xd302, 0xd268, 0xd1ce, + 0xd133, 0xd097, 0xcffb, 0xcf5d, 0xcebf, 0xce20, 0xcd81, 0xcce0, + 0xcc3f, 0xcb9d, 0xcafb, 0xca57, 0xc9b3, 0xc90f, 0xc869, 0xc7c3, + 0xc71c, 0xc675, 0xc5cc, 0xc524, 0xc47a, 0xc3d0, 0xc325, 0xc279, + 0xc1cd, 0xc121, 0xc073, 0xbfc5, 0xbf17, 0xbe67, 0xbdb7, 0xbd07, + 0xbc56, 0xbba4, 0xbaf2, 0xba3f, 0xb98c, 0xb8d8, 0xb824, 0xb76f, + 0xb6b9, 0xb603, 0xb54d, 0xb496, 0xb3de, 0xb326, 0xb26e, 0xb1b5, + 0xb0fb, 0xb041, 0xaf87, 0xaecc, 0xae10, 0xad55, 0xac98, 0xabdc, + 0xab1f, 0xaa61, 0xa9a3, 0xa8e5, 0xa826, 0xa767, 0xa6a7, 0xa5e8, + 0xa527, 0xa467, 0xa3a6, 0xa2e5, 0xa223, 0xa161, 0xa09f, 0x9fdc, + 0x9f19, 0x9e56, 0x9d93, 0x9ccf, 0x9c0b, 0x9b47, 0x9a82, 0x99bd, + 0x98f8, 0x9833, 0x976d, 0x96a7, 0x95e1, 0x951b, 0x9455, 0x938e, + 0x92c7, 0x9201, 0x9139, 0x9072, 0x8fab, 0x8ee3, 0x8e1b, 0x8d53, + 0x8c8b, 0x8bc3, 0x8afb, 0x8a32, 0x896a, 0x88a1, 0x87d9, 0x8710, + 0x8647, 0x857e, 0x84b6, 0x83ed, 0x8324, 0x825b, 0x8192, 0x80c9, + 0x8000, 0x7f36, 0x7e6d, 0x7da4, 0x7cdb, 0x7c12, 0x7b49, 0x7a81, + 0x79b8, 0x78ef, 0x7826, 0x775e, 0x7695, 0x75cd, 0x7504, 0x743c, + 0x7374, 0x72ac, 0x71e4, 0x711c, 0x7054, 0x6f8d, 0x6ec6, 0x6dfe, + 0x6d38, 0x6c71, 0x6baa, 0x6ae4, 0x6a1e, 0x6958, 0x6892, 0x67cc, + 0x6707, 0x6642, 0x657d, 0x64b8, 0x63f4, 0x6330, 0x626c, 0x61a9, + 0x60e6, 0x6023, 0x5f60, 0x5e9e, 0x5ddc, 0x5d1a, 0x5c59, 0x5b98, + 0x5ad8, 0x5a17, 0x5958, 0x5898, 0x57d9, 0x571a, 0x565c, 0x559e, + 0x54e0, 0x5423, 0x5367, 0x52aa, 0x51ef, 0x5133, 0x5078, 0x4fbe, + 0x4f04, 0x4e4a, 0x4d91, 0x4cd9, 0x4c21, 0x4b69, 0x4ab2, 0x49fc, + 0x4946, 0x4890, 0x47db, 0x4727, 0x4673, 0x45c0, 0x450d, 0x445b, + 0x43a9, 0x42f8, 0x4248, 0x4198, 0x40e8, 0x403a, 0x3f8c, 0x3ede, + 0x3e32, 0x3d86, 0x3cda, 0x3c2f, 0x3b85, 0x3adb, 0x3a33, 0x398a, + 0x38e3, 0x383c, 0x3796, 0x36f0, 0x364c, 0x35a8, 0x3504, 0x3462, + 0x33c0, 0x331f, 0x327e, 0x31df, 0x3140, 0x30a2, 0x3004, 0x2f68, + 0x2ecc, 0x2e31, 0x2d97, 0x2cfd, 0x2c65, 0x2bcd, 0x2b36, 0x2aa0, + 0x2a0a, 0x2976, 0x28e2, 0x284f, 0x27bd, 0x272c, 0x269b, 0x260c, + 0x257d, 0x24f0, 0x2463, 0x23d7, 0x234c, 0x22c2, 0x2238, 0x21b0, + 0x2128, 0x20a2, 0x201c, 0x1f97, 0x1f14, 0x1e91, 0x1e0f, 0x1d8e, + 0x1d0e, 0x1c8f, 0x1c11, 0x1b94, 0x1b17, 0x1a9c, 0x1a22, 0x19a9, + 0x1930, 0x18b9, 0x1843, 0x17ce, 0x1759, 0x16e6, 0x1674, 0x1603, + 0x1592, 0x1523, 0x14b5, 0x1448, 0x13dc, 0x1371, 0x1307, 0x129e, + 0x1236, 0x11cf, 0x1169, 0x1105, 0x10a1, 0x103e, 0xfdd, 0xf7c, + 0xf1d, 0xebf, 0xe62, 0xe06, 0xdab, 0xd51, 0xcf8, 0xca1, + 0xc4a, 0xbf5, 0xba0, 0xb4d, 0xafb, 0xaaa, 0xa5a, 0xa0c, + 0x9be, 0x972, 0x927, 0x8dd, 0x894, 0x84c, 0x805, 0x7c0, + 0x77b, 0x738, 0x6f6, 0x6b5, 0x676, 0x637, 0x5fa, 0x5be, + 0x583, 0x549, 0x511, 0x4d9, 0x4a3, 0x46e, 0x43a, 0x407, + 0x3d6, 0x3a6, 0x377, 0x349, 0x31c, 0x2f1, 0x2c6, 0x29d, + 0x276, 0x24f, 0x22a, 0x205, 0x1e2, 0x1c1, 0x1a0, 0x181, + 0x163, 0x146, 0x12a, 0x110, 0xf6, 0xde, 0xc8, 0xb2, + 0x9e, 0x8b, 0x79, 0x68, 0x59, 0x4b, 0x3e, 0x32, + 0x27, 0x1e, 0x16, 0xf, 0xa, 0x6, 0x2, 0x1, + 0x0, 0x1, 0x2, 0x6, 0xa, 0xf, 0x16, 0x1e, + 0x27, 0x32, 0x3e, 0x4b, 0x59, 0x68, 0x79, 0x8b, + 0x9e, 0xb2, 0xc8, 0xde, 0xf6, 0x110, 0x12a, 0x146, + 0x163, 0x181, 0x1a0, 0x1c1, 0x1e2, 0x205, 0x22a, 0x24f, + 0x276, 0x29d, 0x2c6, 0x2f1, 0x31c, 0x349, 0x377, 0x3a6, + 0x3d6, 0x407, 0x43a, 0x46e, 0x4a3, 0x4d9, 0x511, 0x549, + 0x583, 0x5be, 0x5fa, 0x637, 0x676, 0x6b5, 0x6f6, 0x738, + 0x77b, 0x7c0, 0x805, 0x84c, 0x894, 0x8dd, 0x927, 0x972, + 0x9be, 0xa0c, 0xa5a, 0xaaa, 0xafb, 0xb4d, 0xba0, 0xbf5, + 0xc4a, 0xca1, 0xcf8, 0xd51, 0xdab, 0xe06, 0xe62, 0xebf, + 0xf1d, 0xf7c, 0xfdd, 0x103e, 0x10a1, 0x1105, 0x1169, 0x11cf, + 0x1236, 0x129e, 0x1307, 0x1371, 0x13dc, 0x1448, 0x14b5, 0x1523, + 0x1592, 0x1603, 0x1674, 0x16e6, 0x1759, 0x17ce, 0x1843, 0x18b9, + 0x1930, 0x19a9, 0x1a22, 0x1a9c, 0x1b17, 0x1b94, 0x1c11, 0x1c8f, + 0x1d0e, 0x1d8e, 0x1e0f, 0x1e91, 0x1f14, 0x1f97, 0x201c, 0x20a2, + 0x2128, 0x21b0, 0x2238, 0x22c2, 0x234c, 0x23d7, 0x2463, 0x24f0, + 0x257d, 0x260c, 0x269b, 0x272c, 0x27bd, 0x284f, 0x28e2, 0x2976, + 0x2a0a, 0x2aa0, 0x2b36, 0x2bcd, 0x2c65, 0x2cfd, 0x2d97, 0x2e31, + 0x2ecc, 0x2f68, 0x3004, 0x30a2, 0x3140, 0x31df, 0x327e, 0x331f, + 0x33c0, 0x3462, 0x3504, 0x35a8, 0x364c, 0x36f0, 0x3796, 0x383c, + 0x38e3, 0x398a, 0x3a33, 0x3adb, 0x3b85, 0x3c2f, 0x3cda, 0x3d86, + 0x3e32, 0x3ede, 0x3f8c, 0x403a, 0x40e8, 0x4198, 0x4248, 0x42f8, + 0x43a9, 0x445b, 0x450d, 0x45c0, 0x4673, 0x4727, 0x47db, 0x4890, + 0x4946, 0x49fc, 0x4ab2, 0x4b69, 0x4c21, 0x4cd9, 0x4d91, 0x4e4a, + 0x4f04, 0x4fbe, 0x5078, 0x5133, 0x51ef, 0x52aa, 0x5367, 0x5423, + 0x54e0, 0x559e, 0x565c, 0x571a, 0x57d9, 0x5898, 0x5958, 0x5a17, + 0x5ad8, 0x5b98, 0x5c59, 0x5d1a, 0x5ddc, 0x5e9e, 0x5f60, 0x6023, + 0x60e6, 0x61a9, 0x626c, 0x6330, 0x63f4, 0x64b8, 0x657d, 0x6642, + 0x6707, 0x67cc, 0x6892, 0x6958, 0x6a1e, 0x6ae4, 0x6baa, 0x6c71, + 0x6d38, 0x6dfe, 0x6ec6, 0x6f8d, 0x7054, 0x711c, 0x71e4, 0x72ac, + 0x7374, 0x743c, 0x7504, 0x75cd, 0x7695, 0x775e, 0x7826, 0x78ef, + 0x79b8, 0x7a81, 0x7b49, 0x7c12, 0x7cdb, 0x7da4, 0x7e6d, 0x7f36 +}; + +static void vidtv_s302m_compute_nunits(struct vidtv_encoder *e) +{ + /* + * match the amount of video units if we are trying to sync with a video + * encoder + */ + if (e->sync && e->sync->video) { + e->nunits = e->sync->nunits; + return; + } + + /* otherwise return enough samples for the timedelta in one AU */ + e->nunits = 1; +} + +static void +vidtv_s302m_compute_sample_count_v(struct vidtv_encoder *e) +{ + /* compute sample count for VAU[i] in 'sync' */ + u32 vau_duration_usecs; + u32 sample_duration_usecs; + u32 i; + u32 sample_count; + u32 s; + + vau_duration_usecs = USEC_PER_SEC / e->sync->sampling_rate_hz; + sample_duration_usecs = USEC_PER_SEC / e->sampling_rate_hz; + + for (i = 0; i < e->sync->nunits; ++i) { + sample_count = e->samples_per_unit[i]; + s = DIV_ROUND_UP(vau_duration_usecs, sample_duration_usecs); + e->samples_per_unit[i] = s; + } +} + +static void +vidtv_s302m_compute_sample_count(struct vidtv_encoder *e, + u64 elapsed_time_usecs) +{ + /* compute sample count for 'elapsed_time_usecs' */ + u32 sample_duration_usecs = USEC_PER_SEC / e->sampling_rate_hz; + + e->samples_per_unit[0] = elapsed_time_usecs / sample_duration_usecs; +} + +static void vidtv_s302m_compute_pts(struct vidtv_encoder *e) +{ + u32 count = e->previous_sample_count; + u32 i; + + for (i = 0; i < e->nunits; ++i) { + count += e->samples_per_unit[i]; + + e->pts[i] = count * + CLOCK_UNIT_90KHZ / e->sampling_rate_hz; + } +} + +static void vidtv_s302m_compute_pts_v(struct vidtv_encoder *e) +{ + u32 i; + + /* use the same pts for video */ + for (i = 0; i < e->sync->nunits; ++i) + e->pts[i] = e->sync->pts[i]; +} + +static bool vidtv_s302m_get_c_bit(struct vidtv_encoder *e) +{ + /* + * see EBU Tech 3250 2004 clause 5.2.1: minimal implementation of + * channel status + */ + struct vidtv_s302m_ctx *ctx = e->ctx; + bool start_was_z; + + start_was_z = ctx->last_start_preamble == PREAMBLE_Z_F0 || + ctx->last_start_preamble == PREAMBLE_Z_F1; + + if (!start_was_z) + return false; + + ++ctx->current_c_bit; + + /* set the bit only if it is the first C bit after a Z preamble */ + return !(ctx->current_c_bit % CHANNEL_STATUS_BIT_LEN); +} + +static s16 vidtv_s302m_get_sample(struct vidtv_encoder *e) +{ + s16 ret; + + /* bug somewhere */ + WARN_ON(e->src_buf_offset > e->src_buf_sz); + + if (e->src_buf_offset >= e->src_buf_sz) { + /* let the source know we are out of data */ + if (e->last_sample_cb) + e->last_sample_cb(e->sample_count); + + e->src_buf_offset = 0; + } + + ret = *(s16 *)(e->src_buf + e->src_buf_offset); + + e->sample_count++; + e->src_buf_offset += sizeof(s16); + + return ret; +} + +static void vidtv_s302m_toggle_subframe(struct vidtv_encoder *e) +{ + struct vidtv_s302m_ctx *ctx = e->ctx; + + ctx->is_subframe_a = !ctx->is_subframe_a; +} + +static bool vidtv_s302m_is_block_start(const struct vidtv_encoder *e) +{ + return e->sample_count % S302M_BLOCK_SZ; +} + +static bool vidtv_s302m_get_f_bit(const struct vidtv_encoder *e) +{ + const struct vidtv_s302m_ctx *ctx = e->ctx; + + return vidtv_s302m_is_block_start(e) && ctx->is_subframe_a; +} + +static u8 vidtv_s302m_get_preamble(struct vidtv_encoder *e) +{ + /* + * some codecs might disregard the preambles (e.g. ffmpeg s302m), but + * we implement them according to the specs anyway, because some other + * codecs might rely on them. + */ + + struct vidtv_s302m_ctx *ctx = e->ctx; + + bool start_was_x = ctx->last_start_preamble == PREAMBLE_X_F0 || + ctx->last_start_preamble == PREAMBLE_X_F1; + + bool start_was_z = ctx->last_start_preamble == PREAMBLE_Z_F0 || + ctx->last_start_preamble == PREAMBLE_Z_F1; + + bool is_block_start = vidtv_s302m_is_block_start(e); + + /* bug somewhere: a block always starts with an A subframe */ + WARN_ON(!ctx->is_subframe_a && is_block_start); + + if (!ctx->is_subframe_a) + return (ctx->last_f) ? PREAMBLE_Y_F1 : PREAMBLE_Y_F0; + + if (start_was_x && is_block_start) { + if (ctx->last_f) { + ctx->last_start_preamble = PREAMBLE_Z_F0; + return PREAMBLE_Z_F0; + } + + ctx->last_start_preamble = PREAMBLE_Z_F1; + return PREAMBLE_Z_F1; + } + + if (start_was_z && is_block_start) { + if (ctx->last_f) { + ctx->last_start_preamble = PREAMBLE_X_F0; + return PREAMBLE_X_F0; + } + + ctx->last_start_preamble = PREAMBLE_X_F1; + return PREAMBLE_X_F1; + } + + return PREAMBLE_X_F0; +} + +static u32 vidtv_s302m_write_subframe(struct vidtv_encoder *e, + struct vidtv_s302m_subframe_16 *f) +{ + u32 nbytes = 0; + + nbytes += vidtv_memcpy(e->encoder_buf + e->encoder_buf_offset, + f, + sizeof(*f), + e->encoder_buf_offset, + VIDTV_S302M_BUF_SZ); + + e->encoder_buf_offset += nbytes; + + return nbytes; +} + +static void vidtv_s302m_write_h(struct vidtv_encoder *e, u32 p_sz) +{ + struct vidtv_smpte_s302m_es h = {0}; + u32 nbytes = 0; + + h.bits_per_sample = S302M_BITS_PER_SAMPLE_16; + h.channel_identification = 0; + h.num_channels = S302M_2CHANNELS; + h.audio_packet_size = p_sz; + + cpu_to_be32s(&h.bitfield); + + nbytes += vidtv_memcpy(e->encoder_buf + e->encoder_buf_offset, + &h, + sizeof(h), + e->encoder_buf_offset, + e->encoder_buf_sz); + + be32_to_cpus(&h.bitfield); + + e->encoder_buf_offset += nbytes; +} + +static void vidtv_s302m_write_frames(struct vidtv_encoder *e) +{ + u32 nbytes = 0; + u32 nbytes_per_unit = 0; + u32 preamble_bit_num = 0; + const u8 preamble_bit_count = 4; + u32 au_sz = 0; + struct vidtv_s302m_ctx *ctx = e->ctx; + struct vidtv_s302m_subframe_16 a = {0}; + struct vidtv_s302m_subframe_16 b = {0}; + u8 preamble_a = 0; + u8 preamble_b = 0; + u8 aux = 0; + s16 sample = 0; + bool v = true; + bool u = false; + bool c; + bool f; + + u32 i; + u32 j; + + ctx->is_subframe_a = true; + + for (i = 0; i < e->nunits; ++i) { + /* stereo: each sample will generate two subframes */ + au_sz = e->samples_per_unit[i] * + sizeof(struct vidtv_s302m_subframe_16) * + 2; + + vidtv_s302m_write_h(e, au_sz); + + for (j = 0; j < e->samples_per_unit[i]; ++j) { + /* keep this in this order */ + preamble_a = vidtv_s302m_get_preamble(e); + sample = cpu_to_le16(vidtv_s302m_get_sample(e)); + c = vidtv_s302m_get_c_bit(e); + f = vidtv_s302m_get_f_bit(e); + + a.preamble = vidtv_extract_bits(preamble_a, + preamble_bit_num % 8, + preamble_bit_count); + a.aux = aux; + a.data_word = sample; + a.v = v; + a.u = u; + a.c = c; + a.f = f; + + vidtv_s302m_toggle_subframe(e); + + preamble_b = vidtv_s302m_get_preamble(e); + c = vidtv_s302m_get_c_bit(e); + f = vidtv_s302m_get_f_bit(e); + + b.preamble = vidtv_extract_bits(preamble_b, + preamble_bit_num % 8, + preamble_bit_count); + b.aux = aux; + b.data_word = sample; + b.v = v; + b.u = u; + b.c = c; + b.f = f; + + preamble_bit_num += preamble_bit_count; + + nbytes_per_unit += vidtv_s302m_write_subframe(e, &a); + nbytes_per_unit += vidtv_s302m_write_subframe(e, &b); + + nbytes += nbytes_per_unit; + + vidtv_s302m_toggle_subframe(e); + } + + e->nbytes[i] = nbytes; + + /* did we write more bytes than we initially computed? */ + WARN_ON(au_sz != nbytes_per_unit); + + e->offsets[i] = nbytes_per_unit; + nbytes_per_unit = 0; + } +} + +static void *vidtv_s302m_encode(struct vidtv_encoder *e, u64 elapsed_time) +{ + /* + * According to SMPTE 302M, an audio access unit is specified as those + * AES3 words that are associated with a corresponding video frame. + * Therefore we should write one AAU for every VAU in the corresponding + * video encoder ('sync'), using the same values for PTS as used by the + * video encoder. + * + * I assume that it is also possible to send audio without any + * associated video, as in a radio-like service. If this is the case, + * we are sending only _one_ AAU with enough audio data for + * 'elapsed_time' instead, computing the value for PTS manually. + */ + + vidtv_s302m_compute_nunits(e); + + if (e->sync && e->sync->video) { + vidtv_s302m_compute_sample_count_v(e); + vidtv_s302m_compute_pts_v(e); + } else { + vidtv_s302m_compute_sample_count(e, elapsed_time); + vidtv_s302m_compute_pts(e); + } + + vidtv_s302m_write_frames(e); + + return e->encoder_buf; +} + +static u8 vidtv_s302m_clear(struct vidtv_encoder *e) +{ + u8 ret = e->nunits; + + e->nunits = 0; + memset(e->samples_per_unit, 0, e->access_unit_capacity); + memset(e->nbytes, 0, e->access_unit_capacity); + memset(e->offsets, 0, e->access_unit_capacity); + memset(e->pts, 0, e->access_unit_capacity); + memset(e->dts, 0, e->access_unit_capacity); + + return ret; +} + +struct vidtv_encoder +*vidtv_s302m_encoder_init(struct vidtv_s302m_encoder_init_args args) +{ + struct vidtv_encoder *e = kzalloc(sizeof(e), GFP_KERNEL); + u32 priv_sz = sizeof(struct vidtv_s302m_ctx); + + if (args.sync) + args.access_unit_capacity = args.sync->access_unit_capacity; + + e->id = S302M; + + e->name = kzalloc(strlen(args.name), GFP_KERNEL); + strncpy(e->name, args.name, strlen(e->name)); + + e->encoder_buf = vzalloc(VIDTV_S302M_BUF_SZ); + e->encoder_buf_sz = VIDTV_S302M_BUF_SZ; + e->encoder_buf_offset = 0; + + e->sample_count = 0; + e->previous_sample_count = 0; + e->nunits = 0; + + e->samples_per_unit = kcalloc(args.access_unit_capacity, + sizeof(u32), + GFP_KERNEL); + + e->pts = kcalloc(args.access_unit_capacity, sizeof(u64), GFP_KERNEL); + e->dts = kcalloc(args.access_unit_capacity, sizeof(u64), GFP_KERNEL); + + e->nbytes = kcalloc(args.access_unit_capacity, + sizeof(u32), + GFP_KERNEL); + + e->offsets = kcalloc(args.access_unit_capacity, + sizeof(u32), + GFP_KERNEL); + + e->src_buf = (args.src_buf) ? args.src_buf : &s302m_sin_lut; + e->src_buf_sz = (args.src_buf) ? args.src_buf_sz : S302M_SIN_LUT_SZ; + e->src_buf_offset = 0; + + e->video = false; + e->ctx = kzalloc(priv_sz, GFP_KERNEL); + + e->encode = vidtv_s302m_encode; + e->clear = vidtv_s302m_clear; + + e->es_pid = args.es_pid; + + e->sync = args.sync; + e->sampling_rate_hz = S302M_SAMPLING_RATE_HZ; + e->access_unit_capacity = args.access_unit_capacity; + + /* we will wrap around 'src' if this is NULL */ + e->last_sample_cb = args.last_sample_cb; + + e->destroy = vidtv_s302m_encoder_destroy; + + if (args.head) { + while (args.head->next) + args.head = args.head->next; + + args.head->next = e; + } + + e->next = NULL; + + return e; +} + +void vidtv_s302m_encoder_destroy(struct vidtv_encoder *e) +{ + WARN_ON(e->id != S302M); + kfree(e->name); + kfree(e->encoder_buf); + kfree(e->samples_per_unit); + kfree(e->pts); + kfree(e->dts); + kfree(e->nbytes); + kfree(e->offsets); + kfree(e->ctx); + kfree(e); +} diff --git a/drivers/media/test-drivers/vidtv/vidtv_s302m.h b/drivers/media/test-drivers/vidtv/vidtv_s302m.h new file mode 100644 index 0000000000000..bfb8b0c80eddf --- /dev/null +++ b/drivers/media/test-drivers/vidtv/vidtv_s302m.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Vidtv serves as a reference DVB driver and helps validate the existing APIs + * in the media subsystem. It can also aid developers working on userspace + * applications. + * + * This file contains the code for an AES3 (also known as AES/EBU) encoder. + * It is based on EBU Tech 3250 and SMPTE 302M technical documents. + * + * This encoder currently supports 16bit AES3 subframes using 16bit signed + * integers. + * + * Note: AU stands for Access Unit, and AAU stands for Audio Access Unit + * + * Written by Daniel W. S. Almeida + */ + +#ifndef VIDTV_S302M_H +#define VIDTV_S302M_H + +#include +#include +#include "vidtv_encoder.h" + +/* see SMPTE 302M 2007 clause 7.3 */ +#define VIDTV_S302M_BUF_SZ 65024 + +/* see ETSI TS 102 154 v.1.2.1 clause 7.3.5 */ +#define VIDTV_S302M_FORMAT_IDENTIFIER 0x42535344 + +struct vidtv_s302m_ctx { + struct vidtv_encoder *enc; + + /* whether the F bit was set for the last sub-frame */ + bool last_f; + /* either X or Z */ + u8 last_start_preamble; + /* are we writing an A subframe now? */ + bool is_subframe_a; + /* we send a bit per subframe */ + u8 current_c_bit; +}; + +struct vidtv_smpte_s302m_es { + union { + u32 bitfield; + struct { + u16 audio_packet_size:16; + u16 num_channels:2; + u16 channel_identification:8; + u16 bits_per_sample:2; /* 0x0 for 16bits */ + u16 zero:4; + } __packed; + } __packed; +} __packed; + +struct vidtv_s302m_subframe_16 { +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 f:1; + u8 c:1; + u8 u:1; + u8 v:1; + u16 data_word:16; /* little endian, use cpu_to_le before writing */ + u8 zero:4; + u8 aux:4; + u8 preamble:4; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 preamble:4; + u8 aux:4; + u8 zero:4; + u16 data_word:16; /* little endian */ + u8 v:1; + u8 u:1; + u8 c:1; + u8 f:1; +#else +#error "Please fix " +#endif +}__packed; + +struct vidtv_s302m_encoder_init_args { + char *name; + void *src_buf; + u32 src_buf_sz; + u16 es_pid; + struct vidtv_encoder *sync; + u8 access_unit_capacity; + void (*last_sample_cb)(u32 sample_no); + + /* optionally chain to this encoder */ + struct vidtv_encoder *head; +}; + +struct vidtv_encoder +*vidtv_s302m_encoder_init(struct vidtv_s302m_encoder_init_args args); + +void vidtv_s302m_encoder_destroy(struct vidtv_encoder *encoder); + +#endif /* VIDTV_S302M_H */