mirror of
https://github.com/hardkernel/kernel_common_drivers.git
synced 2026-06-25 12:03:48 +09:00
eb02482bfd
PD#SWPL-140857 Problem: linux-meson compile warning while use gcc > 7.5 Solution: Fixed some code styles Verify: local build server Change-Id: Ia1f47cfa32291602747d7c0788a6362cf48af023 Signed-off-by: yao zhang1 <yao.zhang1@amlogic.com>
2667 lines
64 KiB
C
2667 lines
64 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/amlogic/media/frame_sync/timestamp.h>
|
|
#include <linux/amlogic/media/frame_sync/tsync.h>
|
|
#include <linux/amlogic/media/frame_sync/ptsserv.h>
|
|
#ifdef ARC_700
|
|
/* #include <asm/arch/am_regs.h> */
|
|
#else
|
|
/* #include <mach/am_regs.h> */
|
|
#endif
|
|
#include <linux/amlogic/media/utils/vdec_reg.h>
|
|
#include <linux/amlogic/media/frame_sync/tsync_pcr.h>
|
|
#include <linux/amlogic/media/registers/register.h>
|
|
#include <linux/amlogic/media/codec_mm/configs.h>
|
|
#include <linux/amlogic/major.h>
|
|
#include <linux/err.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/amlogic/media/registers/cpu_version.h>
|
|
|
|
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
|
|
/* TODO: for stream buffer register bit define only */
|
|
/* #endif */
|
|
#define TSYNC_DEVICE_NAME "tsync"
|
|
|
|
#if !defined(CONFIG_PREEMPT)
|
|
#define CONFIG_AM_TIMESYNC_LOG
|
|
#endif
|
|
|
|
#ifdef CONFIG_AM_TIMESYNC_LOG
|
|
#define AMLOG
|
|
#define LOG_LEVEL_ERROR 0
|
|
#define LOG_LEVEL_ATTENTION 1
|
|
#define LOG_LEVEL_INFO 2
|
|
#define LOG_LEVEL_VAR amlog_level_tsync
|
|
#define LOG_MASK_VAR amlog_mask_tsync
|
|
#endif
|
|
#include <linux/amlogic/media/utils/amlog.h>
|
|
MODULE_AMLOG(AMLOG_DEFAULT_LEVEL, 0, LOG_DEFAULT_LEVEL_DESC,
|
|
LOG_DEFAULT_MASK_DESC);
|
|
|
|
/* #define DEBUG */
|
|
#define AVEVENT_FLAG_PARAM 0x01
|
|
|
|
/* #define TSYNC_SLOW_SYNC */
|
|
|
|
#define PCR_CHECK_INTERVAL (HZ * 5)
|
|
#define PCR_DETECT_MARGIN_SHIFT_AUDIO_HI 7
|
|
#define PCR_DETECT_MARGIN_SHIFT_AUDIO_LO 7
|
|
#define PCR_DETECT_MARGIN_SHIFT_VIDEO_HI 4
|
|
#define PCR_DETECT_MARGIN_SHIFT_VIDEO_LO 4
|
|
#define PCR_MAINTAIN_MARGIN_SHIFT_AUDIO 4
|
|
#define PCR_MAINTAIN_MARGIN_SHIFT_VIDEO 1
|
|
#define PCR_RECOVER_PCR_ADJ 15
|
|
#define VIDEO_PTS_READY 0
|
|
|
|
#define TSYNC_INIT_STATE (0X01)
|
|
unsigned int tsync_flag;
|
|
|
|
enum {
|
|
PCR_SYNC_UNSET,
|
|
PCR_SYNC_HI,
|
|
PCR_SYNC_LO,
|
|
};
|
|
|
|
enum {
|
|
PCR_TRIGGER_AUDIO,
|
|
PCR_TRIGGER_VIDEO
|
|
};
|
|
|
|
enum tsync_stat_e {
|
|
TSYNC_STAT_PCRSCR_SETUP_NONE,
|
|
TSYNC_STAT_PCRSCR_SETUP_VIDEO,
|
|
TSYNC_STAT_PCRSCR_SETUP_AUDIO
|
|
};
|
|
|
|
enum {
|
|
/* Fixed: use the Nominal M/N values */
|
|
TOGGLE_MODE_FIXED = 0,
|
|
/* Toggle between the Nominal M/N values and the Low M/N values */
|
|
TOGGLE_MODE_NORMAL_LOW,
|
|
/* Toggle between the Nominal M/N values and the High M/N values */
|
|
TOGGLE_MODE_NORMAL_HIGH,
|
|
/* Toggle between the Low M/N values and the High M/N Values */
|
|
TOGGLE_MODE_LOW_HIGH,
|
|
};
|
|
|
|
static const struct {
|
|
const char *token;
|
|
const u32 token_size;
|
|
const enum avevent_e event;
|
|
const u32 flag;
|
|
} avevent_token[] = {
|
|
{
|
|
"VIDEO_START", 11, VIDEO_START, AVEVENT_FLAG_PARAM
|
|
}, {
|
|
"VIDEO_STOP", 10, VIDEO_STOP, 0
|
|
}, {
|
|
"VIDEO_PAUSE", 11, VIDEO_PAUSE, AVEVENT_FLAG_PARAM
|
|
}, {
|
|
"VIDEO_TSTAMP_DISCONTINUITY", 26, VIDEO_TSTAMP_DISCONTINUITY,
|
|
AVEVENT_FLAG_PARAM
|
|
}, {
|
|
"AUDIO_START", 11, AUDIO_START, AVEVENT_FLAG_PARAM
|
|
}, {
|
|
"AUDIO_RESUME", 12, AUDIO_RESUME, 0
|
|
}, {
|
|
"AUDIO_STOP", 10, AUDIO_STOP, 0
|
|
}, {
|
|
"AUDIO_PAUSE", 11, AUDIO_PAUSE, 0
|
|
}, {
|
|
"AUDIO_TSTAMP_DISCONTINUITY", 26, AUDIO_TSTAMP_DISCONTINUITY,
|
|
AVEVENT_FLAG_PARAM
|
|
}, {
|
|
"AUDIO_PRE_START", 15, AUDIO_PRE_START, 0
|
|
}, {
|
|
"AUDIO_WAIT", 10, AUDIO_WAIT, 0
|
|
}
|
|
};
|
|
|
|
static const char * const tsync_mode_str[] = {
|
|
"vmaster", "amaster", "pcrmaster"
|
|
};
|
|
|
|
static struct device *tsync_dev;
|
|
static DEFINE_SPINLOCK(lock);
|
|
static enum tsync_mode_e tsync_mode = TSYNC_MODE_AMASTER;
|
|
static enum tsync_stat_e tsync_stat = TSYNC_STAT_PCRSCR_SETUP_NONE;
|
|
static int tsync_enable; /* 1; */
|
|
static int apts_discontinue;
|
|
static int vpts_discontinue;
|
|
static int pts_discontinue;
|
|
static u32 apts_discontinue_diff;
|
|
static u32 vpts_discontinue_diff;
|
|
static int tsync_aBreak;
|
|
static bool tsync_pcr_recover_enable;
|
|
static int pcr_sync_stat = PCR_SYNC_UNSET;
|
|
static int pcr_recover_trigger;
|
|
static struct timer_list tsync_pcr_recover_timer;
|
|
static int tsync_trickmode;
|
|
static int vpause_flag;
|
|
static int apause_flag;
|
|
static bool dobly_avsync_test;
|
|
static int slowsync_enable;
|
|
static int apts_lookup_offset;
|
|
|
|
static bool new_arch;
|
|
static u32 checkin_apts_from_audiohal;
|
|
u8 demux_pcrscr_valid;
|
|
u8 audio_pid_valid;
|
|
u8 video_pid_valid;
|
|
u32 demux_pcrscr;
|
|
static u32 first_demux_pcrscr;
|
|
struct dmx_info demux_info;
|
|
|
|
pfun_amldemux_pcrscr_get amldemux_pcrscr_get_cb;
|
|
|
|
pfun_tsdemux_pcrscr_valid tsdemux_pcrscr_valid_cb;
|
|
|
|
pfun_tsdemux_pcrscr_get tsdemux_pcrscr_get_cb;
|
|
|
|
pfun_tsdemux_first_pcrscr_get tsdemux_first_pcrscr_get_cb;
|
|
|
|
pfun_tsdemux_pcraudio_valid tsdemux_pcraudio_valid_cb;
|
|
|
|
pfun_tsdemux_pcrvideo_valid tsdemux_pcrvideo_valid_cb;
|
|
|
|
pfun_get_buf_by_type get_buf_by_type_cb;
|
|
|
|
pfun_stbuf_level stbuf_level_cb;
|
|
|
|
pfun_stbuf_space stbuf_space_cb;
|
|
|
|
pfun_stbuf_size stbuf_size_cb;
|
|
|
|
/*
|
|
*used to set player start sync mode, 0-none; 1-smoothsync; 2-droppcm;
|
|
*default drop pcm
|
|
*/
|
|
static int startsync_mode = 2;
|
|
|
|
/*
|
|
* threshold_min threshold_max
|
|
* | |
|
|
*AMASTER<--------------> |<-----DYNAMIC VMASTER---->| VMASTER
|
|
*static mode | a dynamic | dynamic mode |static mode
|
|
*
|
|
*static mode(S), Amaster and Vmaster..
|
|
*dynamic mode (D) : discontinue....> min, < max, can switch to static mode,
|
|
* if diff is < min, and become to Sd mode if timerout.
|
|
*dynamicToStatic mode (A) : dynamic mode become to static mode, because timer out,
|
|
* Don't do switch before timeout.
|
|
*
|
|
*tsync_av_mode switch...
|
|
*(AMASTER S)<-->(D VMASTER)<--> (S VMASTER)
|
|
*(D VMASTER)--time out->(A AMASTER)--time out->((AMASTER S))
|
|
*/
|
|
unsigned int tsync_av_threshold_min = AV_DISCONTINUE_THRESHOLD_MIN;
|
|
unsigned int tsync_av_threshold_max = AV_DISCONTINUE_THRESHOLD_MAX;
|
|
#define TSYNC_STATE_S ('S')
|
|
#define TSYNC_STATE_A ('A')
|
|
#define TSYNC_STATE_D ('D')
|
|
static unsigned int tsync_av_mode = TSYNC_STATE_S; /* S=1,A=2,D=3; */
|
|
static u64
|
|
tsync_av_latest_switch_time_ms; /* the time on latset switch */
|
|
static unsigned int tsync_av_dynamic_duration_ms;/* hold for dynamic mode; */
|
|
static u64 tsync_av_dynamic_timeout_ms;/* hold for dynamic mode; */
|
|
static struct timer_list tsync_state_switch_timer;
|
|
#define jiffies_ms div64_u64(get_jiffies_64() * 1000, HZ)
|
|
#define jiffies_ms32 (jiffies * 1000 / HZ)
|
|
|
|
static unsigned int tsync_syncthresh = 1;
|
|
static int tsync_dec_reset_flag;
|
|
static int tsync_dec_reset_video_start;
|
|
static int tsync_automute_on;
|
|
static int tsync_video_started;
|
|
static int is_tunnel_mode;
|
|
|
|
static int debug_pts_checkin;
|
|
static int debug_pts_checkout;
|
|
static int debug_vpts;
|
|
static int debug_apts;
|
|
static int apts_error_num;
|
|
static int vpts_error_num;
|
|
|
|
#define M_HIGH_DIFF 2
|
|
#define M_LOW_DIFF 2
|
|
#define PLL_FACTOR 10000
|
|
|
|
#define LOW_TOGGLE_TIME 99
|
|
#define NORMAL_TOGGLE_TIME 499
|
|
#define HIGH_TOGGLE_TIME 99
|
|
|
|
#define PTS_CACHED_LO_NORMAL_TIME (90000)
|
|
#define PTS_CACHED_NORMAL_LO_TIME (45000)
|
|
#define PTS_CACHED_HI_NORMAL_TIME (135000)
|
|
#define PTS_CACHED_NORMAL_HI_TIME (180000)
|
|
|
|
int register_tsync_callbackfunc(enum tysnc_func_type_e ntype, void *pfunc)
|
|
{
|
|
if (ntype >= TSYNC_FUNC_TYPE_MAX) {
|
|
pr_debug("register_tync_func ntype is err.\n");
|
|
return -1;
|
|
}
|
|
switch (ntype) {
|
|
case TSYNC_PCRSCR_VALID:
|
|
tsdemux_pcrscr_valid_cb =
|
|
(pfun_tsdemux_pcrscr_valid)pfunc;
|
|
break;
|
|
case TSYNC_PCRSCR_GET:
|
|
tsdemux_pcrscr_get_cb =
|
|
(pfun_tsdemux_pcrscr_get)pfunc;
|
|
break;
|
|
case TSYNC_FIRST_PCRSCR_GET:
|
|
tsdemux_first_pcrscr_get_cb =
|
|
(pfun_tsdemux_first_pcrscr_get)pfunc;
|
|
break;
|
|
case TSYNC_PCRAUDIO_VALID:
|
|
tsdemux_pcraudio_valid_cb =
|
|
(pfun_tsdemux_pcraudio_valid)pfunc;
|
|
break;
|
|
case TSYNC_PCRVIDEO_VALID:
|
|
tsdemux_pcrvideo_valid_cb =
|
|
(pfun_tsdemux_pcrvideo_valid)pfunc;
|
|
break;
|
|
case TSYNC_BUF_BY_BYTE:
|
|
get_buf_by_type_cb =
|
|
(pfun_get_buf_by_type)pfunc;
|
|
break;
|
|
case TSYNC_STBUF_LEVEL:
|
|
stbuf_level_cb =
|
|
(pfun_stbuf_level)pfunc;
|
|
break;
|
|
case TSYNC_STBUF_SPACE:
|
|
stbuf_space_cb =
|
|
(pfun_stbuf_space)pfunc;
|
|
break;
|
|
case TSYNC_STBUF_SIZE:
|
|
stbuf_size_cb =
|
|
(pfun_stbuf_size)pfunc;
|
|
break;
|
|
case TSYNC_AMLDMX_PCR_GET:
|
|
amldemux_pcrscr_get_cb =
|
|
(pfun_amldemux_pcrscr_get)pfunc;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(register_tsync_callbackfunc);
|
|
|
|
static void tsync_pcr_recover_with_audio(void)
|
|
{
|
|
}
|
|
|
|
static void tsync_pcr_recover_with_video(void)
|
|
{
|
|
u32 vb_level = READ_DOSREG(VLD_MEM_VIFIFO_LEVEL);
|
|
u32 vb_size = READ_DOSREG(VLD_MEM_VIFIFO_END_PTR)
|
|
- READ_DOSREG(VLD_MEM_VIFIFO_START_PTR) + 8;
|
|
|
|
if (vb_level < (vb_size >> PCR_DETECT_MARGIN_SHIFT_VIDEO_LO)) {
|
|
timestamp_pcrscr_set_adj(-PCR_RECOVER_PCR_ADJ);
|
|
pr_info(" timestamp_pcrscr_set_adj(-%d);\n",
|
|
PCR_RECOVER_PCR_ADJ);
|
|
} else if ((vb_level + (vb_size >> PCR_DETECT_MARGIN_SHIFT_VIDEO_HI)) >
|
|
vb_size) {
|
|
timestamp_pcrscr_set_adj(PCR_RECOVER_PCR_ADJ);
|
|
pr_info(" timestamp_pcrscr_set_adj(%d);\n",
|
|
PCR_RECOVER_PCR_ADJ);
|
|
} else if ((vb_level > (vb_size >> PCR_MAINTAIN_MARGIN_SHIFT_VIDEO)) ||
|
|
(vb_level <
|
|
(vb_size -
|
|
(vb_size >> PCR_MAINTAIN_MARGIN_SHIFT_VIDEO))))
|
|
timestamp_pcrscr_set_adj(0);
|
|
}
|
|
|
|
static bool tsync_pcr_recover_use_video(void)
|
|
{
|
|
#define MEM_CTRL_EMPTY_EN BIT(2)
|
|
/*
|
|
*This is just a hacking to use audio output enable
|
|
*as the flag to check if this is a video only playback.
|
|
*Such processing can not handle an audio output with a
|
|
*mixer so audio playback has no direct relationship with
|
|
*applications. TODO.
|
|
*/
|
|
return ((READ_AIU_REG(AIU_MEM_I2S_CONTROL) &
|
|
(MEM_CTRL_EMPTY_EN | MEM_CTRL_EMPTY_EN)) == 0) ?
|
|
true : false;
|
|
}
|
|
|
|
static void tsync_pcr_recover_timer_real(void)
|
|
{
|
|
ulong flags;
|
|
|
|
spin_lock_irqsave(&lock, flags);
|
|
|
|
if (tsync_pcr_recover_enable) {
|
|
if (tsync_pcr_recover_use_video()) {
|
|
tsync_pcr_recover_with_video();
|
|
} else {
|
|
timestamp_pcrscr_set_adj(0);
|
|
tsync_pcr_recover_with_audio();
|
|
}
|
|
}
|
|
|
|
spin_unlock_irqrestore(&lock, flags);
|
|
}
|
|
|
|
static void tsync_pcr_recover_timer_func(struct timer_list *arg)
|
|
{
|
|
tsync_pcr_recover_timer_real();
|
|
tsync_pcr_recover_timer.expires = jiffies + PCR_CHECK_INTERVAL;
|
|
add_timer(&tsync_pcr_recover_timer);
|
|
}
|
|
|
|
/*
|
|
*mode:
|
|
*mode='V': diff_pts=|vpts-pcrscr|,jump_pts=vpts jump, video discontinue
|
|
*mode='A': diff_pts=|apts-pcrscr|,jump_pts=apts jump, audio discontinue
|
|
*mode='T': diff_pts=|vpts-apts|,timeout mode switch,
|
|
*/
|
|
|
|
static int tsync_mode_switch(int mode, unsigned long diff_pts, int jump_pts)
|
|
{
|
|
int debugCount = 0;
|
|
int old_tsync_mode = tsync_mode;
|
|
int old_tsync_av_mode = tsync_av_mode;
|
|
char VA[] = "VA--";
|
|
unsigned long oldtimeout = tsync_av_dynamic_timeout_ms;
|
|
u32 pcr, vpts, apts;
|
|
|
|
pcr = timestamp_pcrscr_get();
|
|
vpts = timestamp_vpts_get();
|
|
apts = timestamp_apts_get();
|
|
|
|
if (tsync_mode == TSYNC_MODE_PCRMASTER) {
|
|
pr_info
|
|
("[%s]tsync_mode is pcr master, do nothing\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
pr_info
|
|
("%c-discontinue,pcr=%d,vpts=%d,apts=%d,diff_pts=%lu,jump_Pts=%d\n",
|
|
mode, timestamp_pcrscr_get(), timestamp_vpts_get(),
|
|
timestamp_apts_get(), diff_pts, jump_pts);
|
|
if (!tsync_enable || !timestamp_apts_started()) {
|
|
if (tsync_mode != TSYNC_MODE_VMASTER)
|
|
tsync_mode = TSYNC_MODE_VMASTER;
|
|
tsync_av_mode = TSYNC_STATE_S;
|
|
tsync_av_dynamic_duration_ms = 0;
|
|
pr_info("tsync_enable [%d]\n", tsync_enable);
|
|
return 0;
|
|
}
|
|
if (mode == 'T') { /*D/A--> ... */
|
|
if (tsync_av_mode == TSYNC_STATE_D) {
|
|
debugCount |= 1 << 1;
|
|
tsync_av_mode = TSYNC_STATE_A;
|
|
tsync_mode = TSYNC_MODE_AMASTER;
|
|
tsync_av_latest_switch_time_ms = jiffies_ms;
|
|
tsync_av_dynamic_duration_ms =
|
|
200 + diff_pts * 1000 / TIME_UNIT90K;
|
|
if (tsync_av_dynamic_duration_ms > 5 * 1000)
|
|
tsync_av_dynamic_duration_ms = 5 * 1000;
|
|
} else if (tsync_av_mode == TSYNC_STATE_A) {
|
|
debugCount |= 1 << 2;
|
|
tsync_av_mode = TSYNC_STATE_S;
|
|
tsync_mode = TSYNC_MODE_AMASTER;
|
|
tsync_av_latest_switch_time_ms = jiffies_ms;
|
|
tsync_av_dynamic_duration_ms = 0;
|
|
} else {
|
|
/* / */
|
|
if (abs(vpts - apts) < tsync_av_threshold_min ||
|
|
diff_pts < tsync_av_threshold_min) {
|
|
pr_info("-wcs-< tsync_av_threshold_min--\n");
|
|
tsync_av_mode = TSYNC_STATE_S;
|
|
tsync_mode = TSYNC_MODE_AMASTER;
|
|
tsync_av_latest_switch_time_ms = jiffies_ms;
|
|
tsync_av_dynamic_duration_ms = 0;
|
|
} else if (abs(vpts - apts) < tsync_av_threshold_max ||
|
|
diff_pts < tsync_av_threshold_max) {
|
|
pr_info("-wcs-< tsync_av_threshold_max--\n");
|
|
tsync_av_mode = TSYNC_STATE_D;
|
|
tsync_mode = TSYNC_MODE_VMASTER;
|
|
tsync_av_latest_switch_time_ms = jiffies_ms;
|
|
tsync_av_dynamic_duration_ms = 20 * 1000;
|
|
}
|
|
}
|
|
if (tsync_mode != old_tsync_mode ||
|
|
tsync_av_mode != old_tsync_av_mode)
|
|
pr_info("mode changes:tsync_mode:%c->%c,state:%c->%c,",
|
|
VA[old_tsync_mode], VA[tsync_mode],
|
|
old_tsync_av_mode, tsync_av_mode);
|
|
pr_info("debugCount=0x%x,diff_pts=%lu\n",
|
|
debugCount,
|
|
diff_pts);
|
|
return 0;
|
|
}
|
|
|
|
if (diff_pts < tsync_av_threshold_min) {
|
|
/*->min*/
|
|
debugCount |= 1 << 1;
|
|
tsync_av_mode = TSYNC_STATE_S;
|
|
tsync_mode = TSYNC_MODE_AMASTER;
|
|
tsync_av_latest_switch_time_ms = jiffies_ms;
|
|
tsync_av_dynamic_duration_ms = 0;
|
|
} else if (diff_pts <= tsync_av_threshold_max) { /*min<-->max */
|
|
if (tsync_av_mode == TSYNC_STATE_S) {
|
|
debugCount |= 1 << 2;
|
|
tsync_av_mode = TSYNC_STATE_D;
|
|
tsync_mode = TSYNC_MODE_VMASTER;
|
|
tsync_av_latest_switch_time_ms = jiffies_ms;
|
|
tsync_av_dynamic_duration_ms = 20 * 1000;
|
|
} else if (tsync_av_mode ==
|
|
TSYNC_STATE_D) {
|
|
/*new discontinue,continue wait.... */
|
|
debugCount |= 1 << 7;
|
|
tsync_av_mode = TSYNC_STATE_D;
|
|
tsync_mode = TSYNC_MODE_VMASTER;
|
|
tsync_av_latest_switch_time_ms = jiffies_ms;
|
|
tsync_av_dynamic_duration_ms = 20 * 1000;
|
|
}
|
|
} else if (diff_pts >= tsync_av_threshold_max) { /*max<-- */
|
|
if (tsync_av_mode == TSYNC_STATE_D) {
|
|
debugCount |= 1 << 3;
|
|
tsync_av_mode = TSYNC_STATE_S;
|
|
tsync_mode = TSYNC_MODE_VMASTER;
|
|
tsync_av_latest_switch_time_ms = jiffies_ms;
|
|
tsync_av_dynamic_duration_ms = 0;
|
|
} else if (tsync_mode != TSYNC_MODE_VMASTER) {
|
|
debugCount |= 1 << 4;
|
|
tsync_av_mode = TSYNC_STATE_S;
|
|
tsync_mode = TSYNC_MODE_VMASTER;
|
|
tsync_av_latest_switch_time_ms = jiffies_ms;
|
|
tsync_av_dynamic_duration_ms = 0;
|
|
}
|
|
} else {
|
|
debugCount |= 1 << 16;
|
|
}
|
|
|
|
if (oldtimeout != tsync_av_latest_switch_time_ms +
|
|
tsync_av_dynamic_duration_ms) {
|
|
/*duration changed,update new timeout. */
|
|
tsync_av_dynamic_timeout_ms =
|
|
tsync_av_latest_switch_time_ms +
|
|
tsync_av_dynamic_duration_ms;
|
|
}
|
|
pr_info("discontinue-tsync_mode:%c->%c,state:%c->%c,jiffies=%x",
|
|
VA[old_tsync_mode], VA[tsync_mode],
|
|
old_tsync_av_mode, tsync_av_mode,
|
|
(u32)jiffies_ms32);
|
|
pr_info("debugCount=0x%x,diff_pts=%lu,tsync_mode=%d\n",
|
|
debugCount, diff_pts, tsync_mode);
|
|
return 0;
|
|
}
|
|
|
|
static void tsync_state_switch_timer_fun(struct timer_list *arg)
|
|
{
|
|
if (!vpause_flag && !apause_flag && timestamp_apts_started()) {
|
|
if (tsync_av_mode == TSYNC_STATE_D ||
|
|
tsync_av_mode == TSYNC_STATE_A) {
|
|
if (tsync_av_dynamic_timeout_ms < jiffies_ms) {
|
|
/* to be amaster? */
|
|
tsync_mode_switch('T',
|
|
abs(timestamp_vpts_get() -
|
|
timestamp_apts_get()),
|
|
0);
|
|
if (tsync_mode == TSYNC_MODE_AMASTER &&
|
|
abs(timestamp_apts_get() -
|
|
timestamp_pcrscr_get()) >
|
|
(TIME_UNIT90K * 50 / 1000)) {
|
|
timestamp_pcrscr_set
|
|
(timestamp_apts_get());
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
/* video&audio paused,changed the timeout time to latter. */
|
|
tsync_av_dynamic_timeout_ms =
|
|
jiffies_ms + tsync_av_dynamic_duration_ms;
|
|
}
|
|
tsync_state_switch_timer.expires = jiffies + msecs_to_jiffies(200);
|
|
add_timer(&tsync_state_switch_timer);
|
|
}
|
|
|
|
u8 tsync_get_demux_pcrscr_valid_for_newarch(void)
|
|
{
|
|
return demux_pcrscr_valid;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_demux_pcrscr_valid_for_newarch);
|
|
|
|
u8 tsync_get_demux_pcrscr_valid(void)
|
|
{
|
|
if (new_arch)
|
|
return tsync_get_demux_pcrscr_valid_for_newarch();
|
|
|
|
if (tsdemux_pcrscr_valid_cb)
|
|
demux_pcrscr_valid = tsdemux_pcrscr_valid_cb();
|
|
else
|
|
demux_pcrscr_valid = 0;
|
|
return demux_pcrscr_valid;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_demux_pcrscr_valid);
|
|
|
|
u8 tsync_get_audio_pid_valid_for_newarch(void)
|
|
{
|
|
return audio_pid_valid;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_audio_pid_valid_for_newarch);
|
|
|
|
u8 tsync_get_audio_pid_valid(void)
|
|
{
|
|
if (new_arch)
|
|
return tsync_get_audio_pid_valid_for_newarch();
|
|
|
|
if (tsdemux_pcraudio_valid_cb)
|
|
audio_pid_valid = tsdemux_pcraudio_valid_cb();
|
|
else
|
|
audio_pid_valid = 0;
|
|
return audio_pid_valid;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_audio_pid_valid);
|
|
|
|
u8 tsync_get_video_pid_valid_for_newarch(void)
|
|
{
|
|
return video_pid_valid;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_video_pid_valid_for_newarch);
|
|
|
|
u8 tsync_get_video_pid_valid(void)
|
|
{
|
|
if (new_arch)
|
|
return tsync_get_video_pid_valid_for_newarch();
|
|
if (tsdemux_pcrvideo_valid_cb)
|
|
video_pid_valid = (tsdemux_pcrvideo_valid_cb)();
|
|
else
|
|
video_pid_valid = 0;
|
|
return video_pid_valid;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_video_pid_valid);
|
|
|
|
void tsync_get_demux_pcr_for_newarch(void)
|
|
{
|
|
u64 pcr_u64 = -1;
|
|
|
|
if (amldemux_pcrscr_get_cb)
|
|
amldemux_pcrscr_get_cb(demux_info.demux_device_id,
|
|
demux_info.index, &pcr_u64);
|
|
demux_pcrscr = pcr_u64;
|
|
if (first_demux_pcrscr == 0)
|
|
first_demux_pcrscr = demux_pcrscr;
|
|
return;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_demux_pcr_for_newarch);
|
|
|
|
u8 tsync_get_demux_pcr(u32 *pcr)
|
|
{
|
|
u8 ret = 0;
|
|
|
|
if (new_arch) {
|
|
if (!demux_pcrscr_valid) {
|
|
*pcr = 0;
|
|
return 0;
|
|
}
|
|
tsync_get_demux_pcr_for_newarch();
|
|
*pcr = demux_pcrscr;
|
|
ret = 1;
|
|
} else {
|
|
if (tsdemux_pcrscr_get_cb) {
|
|
demux_pcrscr = tsdemux_pcrscr_get_cb();
|
|
*pcr = demux_pcrscr;
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_demux_pcr);
|
|
|
|
void tsync_get_first_demux_pcr_for_newarch(void)
|
|
{
|
|
tsync_get_demux_pcr_for_newarch();
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_first_demux_pcr_for_newarch);
|
|
|
|
u8 tsync_get_first_demux_pcr(u32 *first_pcr)
|
|
{
|
|
u8 ret = 0;
|
|
|
|
if (new_arch) {
|
|
if (!demux_pcrscr_valid) {
|
|
*first_pcr = 0;
|
|
return 0;
|
|
}
|
|
tsync_get_first_demux_pcr_for_newarch();
|
|
*first_pcr = first_demux_pcrscr;
|
|
ret = 1;
|
|
} else {
|
|
if (tsdemux_first_pcrscr_get_cb) {
|
|
first_demux_pcrscr = tsdemux_first_pcrscr_get_cb();
|
|
*first_pcr = first_demux_pcrscr;
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_first_demux_pcr);
|
|
|
|
void tsync_get_buf_by_type_for_newarch(u8 type, struct stream_buf_s *pbuf)
|
|
{
|
|
pbuf = NULL;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_buf_by_type_for_newarch);
|
|
|
|
u8 tsync_get_buf_by_type(u8 type, struct stream_buf_s *pbuf)
|
|
{
|
|
u8 ret = 0;
|
|
|
|
if (new_arch) {
|
|
tsync_get_buf_by_type_for_newarch(type, pbuf);
|
|
ret = 0;
|
|
} else {
|
|
if (get_buf_by_type_cb) {
|
|
pbuf = get_buf_by_type_cb(type);
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_buf_by_type);
|
|
|
|
void tsync_get_stbuf_level_for_newarch(struct stream_buf_s *pbuf,
|
|
u32 *buf_level)
|
|
{
|
|
*buf_level = 0;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_stbuf_level_for_newarch);
|
|
|
|
u8 tsync_get_stbuf_level(struct stream_buf_s *pbuf, u32 *buf_level)
|
|
{
|
|
u8 ret = 0;
|
|
|
|
if (!pbuf)
|
|
return 0;
|
|
|
|
if (new_arch) {
|
|
tsync_get_stbuf_level_for_newarch(pbuf, buf_level);
|
|
ret = 0;
|
|
} else {
|
|
if (stbuf_level_cb) {
|
|
*buf_level = stbuf_level_cb(pbuf);
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_stbuf_level);
|
|
|
|
void tsync_get_stbuf_space_for_newarch(struct stream_buf_s *pbuf,
|
|
u32 *buf_space)
|
|
{
|
|
*buf_space = 0;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_stbuf_space_for_newarch);
|
|
|
|
u8 tsync_get_stbuf_space(struct stream_buf_s *pbuf, u32 *buf_space)
|
|
{
|
|
u8 ret = 0;
|
|
|
|
if (!pbuf)
|
|
return 0;
|
|
|
|
if (new_arch) {
|
|
tsync_get_stbuf_space_for_newarch(pbuf, buf_space);
|
|
ret = 0;
|
|
} else {
|
|
if (stbuf_space_cb) {
|
|
*buf_space = stbuf_space_cb(pbuf);
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_stbuf_space);
|
|
|
|
void tsync_get_stbuf_size_for_newarch(struct stream_buf_s *pbuf, u32 *buf_size)
|
|
{
|
|
*buf_size = 0;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_stbuf_size_for_newarch);
|
|
|
|
u8 tsync_get_stbuf_size(struct stream_buf_s *pbuf, u32 *buf_size)
|
|
{
|
|
u8 ret = 0;
|
|
|
|
if (!pbuf)
|
|
return 0;
|
|
|
|
if (new_arch) {
|
|
tsync_get_stbuf_size_for_newarch(pbuf, buf_size);
|
|
ret = 1;
|
|
} else {
|
|
if (stbuf_size_cb) {
|
|
*buf_size = stbuf_size_cb(pbuf);
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_stbuf_size);
|
|
|
|
int tsync_check_pid_valid_for_newarch(struct dmx_info demux_info)
|
|
{
|
|
if (!new_arch)
|
|
return 0;
|
|
if (demux_info.vpid != 0x1FFF)
|
|
video_pid_valid = 1;
|
|
else
|
|
video_pid_valid = 0;
|
|
|
|
if (demux_info.apid != 0x1FFF)
|
|
audio_pid_valid = 1;
|
|
else
|
|
audio_pid_valid = 0;
|
|
|
|
if (demux_info.pcrpid != 0x1FFF)
|
|
demux_pcrscr_valid = 1;
|
|
else
|
|
demux_pcrscr_valid = 0;
|
|
if (!video_pid_valid)
|
|
pr_info("tsync exception video pid is valid.");
|
|
if (!audio_pid_valid)
|
|
pr_info("tsync exception audio pid is valid.");
|
|
if (!demux_pcrscr_valid)
|
|
pr_info("tsync exception demux pcr pid is valid.");
|
|
return 1;
|
|
}
|
|
|
|
void tsync_reset(void)
|
|
{
|
|
checkin_apts_from_audiohal = 0xffffffff;
|
|
first_demux_pcrscr = 0;
|
|
}
|
|
|
|
void tsync_mode_reinit(void)
|
|
{
|
|
tsync_av_mode = TSYNC_STATE_S;
|
|
tsync_av_dynamic_duration_ms = 0;
|
|
}
|
|
EXPORT_SYMBOL(tsync_mode_reinit);
|
|
void tsync_avevent_locked(enum avevent_e event, u32 param)
|
|
{
|
|
u32 t;
|
|
|
|
if (tsync_mode == TSYNC_MODE_PCRMASTER) {
|
|
amlog_level(LOG_LEVEL_INFO,
|
|
"[%s]", __func__);
|
|
amlog_level(LOG_LEVEL_INFO,
|
|
"PCR MASTER to use tsync pcr cmd deal ");
|
|
tsync_pcr_avevent_locked(event, param);
|
|
return;
|
|
}
|
|
|
|
switch (event) {
|
|
case VIDEO_START:
|
|
if (tsync_video_started == 0) {
|
|
pr_info("[%s %d]VIDEO_START-tsync_mode:%d(%c)\n",
|
|
__func__, __LINE__,
|
|
tsync_mode, tsync_av_mode);
|
|
pr_info("pcr:0x%x,param:0x%x,vpts:0x%x,apts:0x%x\n",
|
|
timestamp_pcrscr_get(), param,
|
|
timestamp_vpts_get(),
|
|
timestamp_apts_get());
|
|
}
|
|
tsync_video_started = 1;
|
|
tsync_set_av_state(0, 2);
|
|
|
|
//set tsync mode to vmaster to avoid video block caused
|
|
// by avpts-diff too much
|
|
//threshold 120s is an arbitrary value
|
|
|
|
if (tsync_enable && !get_vsync_pts_inc_mode()) {
|
|
t = abs(param - timestamp_apts_get());
|
|
if (tsync_av_mode == TSYNC_STATE_S ||
|
|
(tsync_av_mode == TSYNC_STATE_D &&
|
|
t < tsync_av_threshold_min)) {
|
|
tsync_mode = TSYNC_MODE_AMASTER;
|
|
}
|
|
} else {
|
|
tsync_mode = TSYNC_MODE_VMASTER;
|
|
if (get_vsync_pts_inc_mode())
|
|
tsync_stat = TSYNC_STAT_PCRSCR_SETUP_NONE;
|
|
|
|
}
|
|
|
|
if (tsync_dec_reset_flag)
|
|
tsync_dec_reset_video_start = 1;
|
|
|
|
if (slowsync_enable == 1) { /* slow sync enable */
|
|
timestamp_pcrscr_set(param);
|
|
set_pts_realign();
|
|
tsync_stat = TSYNC_STAT_PCRSCR_SETUP_VIDEO;
|
|
} else {
|
|
if (tsync_stat == TSYNC_STAT_PCRSCR_SETUP_NONE) {
|
|
if (tsync_syncthresh &&
|
|
tsync_mode == TSYNC_MODE_AMASTER) {
|
|
timestamp_pcrscr_set(param -
|
|
VIDEO_HOLD_THRESHOLD);
|
|
} else {
|
|
timestamp_pcrscr_set(param);
|
|
}
|
|
set_pts_realign();
|
|
tsync_stat = TSYNC_STAT_PCRSCR_SETUP_VIDEO;
|
|
}
|
|
}
|
|
amlog_level(LOG_LEVEL_INFO,
|
|
"vpts to scr, apts = 0x%x, vpts = 0x%x\n",
|
|
timestamp_apts_get(), timestamp_vpts_get());
|
|
|
|
if (tsync_stat == TSYNC_STAT_PCRSCR_SETUP_AUDIO) {
|
|
t = timestamp_pcrscr_get();
|
|
if (abs(param - t) > tsync_av_threshold_max) {
|
|
/* if this happens, then play */
|
|
tsync_stat = TSYNC_STAT_PCRSCR_SETUP_VIDEO;
|
|
tsync_mode = TSYNC_MODE_VMASTER;
|
|
tsync_enable = 0;
|
|
timestamp_pcrscr_set(param);
|
|
set_pts_realign();
|
|
}
|
|
}
|
|
if (!vpause_flag && !tsync_get_tunnel_mode())
|
|
timestamp_pcrscr_enable(1);
|
|
|
|
if (!timestamp_firstvpts_get() && param)
|
|
timestamp_firstvpts_set(param);
|
|
break;
|
|
|
|
case VIDEO_STOP:
|
|
tsync_stat = TSYNC_STAT_PCRSCR_SETUP_NONE;
|
|
tsync_set_av_state(0, 3);
|
|
timestamp_vpts_set(0);
|
|
timestamp_vpts_set_u64(0);
|
|
timestamp_pcrscr_set(0);
|
|
timestamp_pcrscr_enable(0);
|
|
timestamp_firstvpts_set(0);
|
|
tsync_reset();
|
|
tsync_video_started = 0;
|
|
break;
|
|
|
|
/*
|
|
* Note:
|
|
* Video and audio PTS discontinue happens typically with a loopback
|
|
* playback, with same bit stream play in loop and PTS wrap back from
|
|
* start point.
|
|
* When VIDEO_TSTAMP_DISCONTINUITY happens early, PCRSCR is set
|
|
* immediately to make video still keep running in VMASTER mode. This
|
|
* mode is restored to AMASTER mode when AUDIO_TSTAMP_DISCONTINUITY
|
|
* reports, or apts is close to scr later.
|
|
* When AUDIO_TSTAMP_DISCONTINUITY happens early, VMASTER mode is
|
|
* set to make video still keep running w/o setting PCRSCR. This mode
|
|
* is restored to AMASTER mode when VIDEO_TSTAMP_DISCONTINUITY
|
|
* reports, and scr is restored along with new video time stamp also.
|
|
*/
|
|
case VIDEO_TSTAMP_DISCONTINUITY: {
|
|
unsigned int old_pts = timestamp_vpts_get();
|
|
int oldmod = tsync_mode;
|
|
|
|
if (tsync_mode == TSYNC_MODE_VMASTER &&
|
|
timestamp_apts_started())
|
|
t = timestamp_apts_get();
|
|
else
|
|
t = timestamp_pcrscr_get();
|
|
if (tsync_get_demux_pcrscr_valid()) {
|
|
if (abs(param - old_pts) > tsync_av_threshold_min) {
|
|
vpts_discontinue = 1;
|
|
if (apts_discontinue == 1) {
|
|
apts_discontinue = 0;
|
|
vpts_discontinue = 0;
|
|
pr_info("set apts->pcrsrc,pcrsrc %x to %x,diff %d\n",
|
|
timestamp_pcrscr_get(),
|
|
timestamp_apts_get(),
|
|
timestamp_apts_get()
|
|
- timestamp_pcrscr_get());
|
|
timestamp_pcrscr_set(param);
|
|
} else {
|
|
pr_info("set para->pcrsrc,pcrsrc %x to %x,diff %d\n",
|
|
timestamp_pcrscr_get(), param,
|
|
param - timestamp_pcrscr_get());
|
|
timestamp_pcrscr_set
|
|
(timestamp_vpts_get());
|
|
}
|
|
}
|
|
timestamp_vpts_set(param);
|
|
vpts_error_num++;
|
|
break;
|
|
}
|
|
/*
|
|
*amlog_level(LOG_LEVEL_ATTENTION,
|
|
*"VIDEO_TSTAMP_DISCONTINUITY, 0x%x, 0x%x\n", t, param);
|
|
*/
|
|
if ((abs(param - old_pts) > tsync_av_threshold_min) &&
|
|
(!get_vsync_pts_inc_mode())) {
|
|
vpts_discontinue = 1;
|
|
vpts_discontinue_diff = abs(param - t);
|
|
tsync_mode_switch('V', abs(param - t),
|
|
param - old_pts);
|
|
}
|
|
|
|
timestamp_vpts_set(param);
|
|
vpts_error_num++;
|
|
if (tsync_mode == TSYNC_MODE_VMASTER) {
|
|
timestamp_pcrscr_set(param);
|
|
set_pts_realign();
|
|
} else if (tsync_mode != oldmod &&
|
|
tsync_mode == TSYNC_MODE_AMASTER) {
|
|
timestamp_pcrscr_set(timestamp_apts_get());
|
|
set_pts_realign();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case AUDIO_TSTAMP_DISCONTINUITY: {
|
|
unsigned int old_pts = timestamp_apts_get();
|
|
int oldmod = tsync_mode;
|
|
|
|
amlog_level(LOG_LEVEL_ATTENTION,
|
|
"audio discontinue, reset apts, 0x%x\n",
|
|
param);
|
|
if (tsync_get_demux_pcrscr_valid()) {
|
|
if (abs(param - old_pts) > tsync_av_threshold_min) {
|
|
apts_discontinue = 1;
|
|
if (vpts_discontinue == 1) {
|
|
pr_info("set para->pcrsrc,pcrsrc from %x to %x,diff %d\n",
|
|
timestamp_pcrscr_get(), param,
|
|
param - timestamp_pcrscr_get());
|
|
apts_discontinue = 0;
|
|
vpts_discontinue = 0;
|
|
timestamp_pcrscr_set(param);
|
|
} else {
|
|
pr_info("set vpts->pcrsrc,pcrsrc from %x to %x,diff %d\n",
|
|
timestamp_pcrscr_get(),
|
|
timestamp_vpts_get(),
|
|
timestamp_vpts_get()
|
|
- timestamp_pcrscr_get());
|
|
timestamp_pcrscr_set
|
|
(timestamp_vpts_get());
|
|
}
|
|
}
|
|
timestamp_apts_set(param);
|
|
apts_error_num++;
|
|
break;
|
|
}
|
|
timestamp_apts_set(param);
|
|
apts_error_num++;
|
|
if (!tsync_enable) {
|
|
timestamp_apts_set(param);
|
|
break;
|
|
}
|
|
if (tsync_mode == TSYNC_MODE_AMASTER)
|
|
t = timestamp_vpts_get();
|
|
else
|
|
t = timestamp_pcrscr_get();
|
|
amlog_level(LOG_LEVEL_ATTENTION,
|
|
"AUDIO_TSTAMP_DISCONTINUITY, 0x%x, 0x%x\n",
|
|
t, param);
|
|
if ((abs(param - old_pts) > tsync_av_threshold_min) &&
|
|
(!get_vsync_pts_inc_mode())) {
|
|
apts_discontinue = 1;
|
|
apts_discontinue_diff = abs(param - t);
|
|
tsync_mode_switch('A', abs(param - t),
|
|
param - old_pts);
|
|
}
|
|
timestamp_apts_set(param);
|
|
if (tsync_mode == TSYNC_MODE_AMASTER) {
|
|
timestamp_pcrscr_set(param);
|
|
set_pts_realign();
|
|
} else if (tsync_mode != oldmod &&
|
|
tsync_mode == TSYNC_MODE_VMASTER) {
|
|
//When no first pic coming, the vpts value is invalid
|
|
if (get_first_pic_coming())
|
|
t = timestamp_vpts_get();
|
|
else
|
|
t = timestamp_firstvpts_get();
|
|
timestamp_pcrscr_set(t);
|
|
set_pts_realign();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case AUDIO_PRE_START:
|
|
timestamp_apts_start(0);
|
|
break;
|
|
|
|
case AUDIO_WAIT:
|
|
timestamp_pcrscr_set(timestamp_vpts_get());
|
|
break;
|
|
case AUDIO_START:
|
|
/* reset discontinue var */
|
|
tsync_set_av_state(1, AUDIO_START);
|
|
tsync_set_sync_adiscont(0);
|
|
tsync_set_sync_adiscont_diff(0);
|
|
tsync_set_sync_vdiscont(0);
|
|
tsync_set_sync_vdiscont_diff(0);
|
|
|
|
timestamp_apts_set(param);
|
|
|
|
amlog_level(LOG_LEVEL_INFO, "audio start, reset apts = 0x%x\n",
|
|
param);
|
|
|
|
timestamp_apts_enable(1);
|
|
|
|
timestamp_apts_start(1);
|
|
|
|
if (!tsync_enable)
|
|
break;
|
|
|
|
t = timestamp_pcrscr_get();
|
|
|
|
pr_info("[%s]param %d, t %d\n",
|
|
__func__, param, t);
|
|
|
|
tsync_aBreak = 0;
|
|
/* after reset, video should be played first */
|
|
if (tsync_dec_reset_flag) {
|
|
int vpts = timestamp_vpts_get();
|
|
|
|
if (param < vpts || !tsync_dec_reset_video_start)
|
|
timestamp_pcrscr_set(param);
|
|
else
|
|
timestamp_pcrscr_set(vpts);
|
|
set_pts_realign();
|
|
tsync_dec_reset_flag = 0;
|
|
tsync_dec_reset_video_start = 0;
|
|
} else if (tsync_mode == TSYNC_MODE_AMASTER) {
|
|
timestamp_pcrscr_set(param);
|
|
set_pts_realign();
|
|
}
|
|
|
|
tsync_stat = TSYNC_STAT_PCRSCR_SETUP_AUDIO;
|
|
|
|
amlog_level(LOG_LEVEL_INFO, "apts reset scr = 0x%x\n", param);
|
|
|
|
timestamp_pcrscr_enable(1);
|
|
apause_flag = 0;
|
|
break;
|
|
|
|
case AUDIO_RESUME:
|
|
timestamp_apts_enable(1);
|
|
apause_flag = 0;
|
|
if (!tsync_enable)
|
|
break;
|
|
timestamp_pcrscr_enable(1);
|
|
|
|
break;
|
|
|
|
case AUDIO_STOP:
|
|
tsync_set_av_state(1, AUDIO_STOP);
|
|
timestamp_apts_enable(0);
|
|
timestamp_apts_set(-1);
|
|
tsync_aBreak = 0;
|
|
if (tsync_trickmode)
|
|
tsync_stat = TSYNC_STAT_PCRSCR_SETUP_VIDEO;
|
|
else
|
|
tsync_stat = TSYNC_STAT_PCRSCR_SETUP_NONE;
|
|
apause_flag = 0;
|
|
timestamp_apts_start(0);
|
|
tsync_reset();
|
|
|
|
break;
|
|
|
|
case AUDIO_PAUSE:
|
|
apause_flag = 1;
|
|
timestamp_apts_enable(0);
|
|
|
|
if (!tsync_enable)
|
|
break;
|
|
|
|
timestamp_pcrscr_enable(0);
|
|
break;
|
|
|
|
case VIDEO_PAUSE:
|
|
if (param == 1)
|
|
vpause_flag = 1;
|
|
else
|
|
vpause_flag = 0;
|
|
if (param == 1) {
|
|
timestamp_pcrscr_enable(0);
|
|
amlog_level(LOG_LEVEL_INFO, "video pause!\n");
|
|
} else {
|
|
if (!apause_flag || !tsync_enable) {
|
|
timestamp_pcrscr_enable(1);
|
|
amlog_level(LOG_LEVEL_INFO, "video resume\n");
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
switch (event) {
|
|
case VIDEO_START:
|
|
case AUDIO_START:
|
|
case AUDIO_RESUME:
|
|
/*amvdev_resume();*//*DEBUG_TMP*/
|
|
break;
|
|
case VIDEO_STOP:
|
|
case AUDIO_STOP:
|
|
case AUDIO_PAUSE:
|
|
/*amvdev_pause();*//*DEBUG_TMP*/
|
|
break;
|
|
case VIDEO_PAUSE:
|
|
/*
|
|
*if (vpause_flag)
|
|
* amvdev_pause();
|
|
*else
|
|
* amvdev_resume();
|
|
*/
|
|
//DEBUG_TMP
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(tsync_avevent_locked);
|
|
|
|
void tsync_avevent(enum avevent_e event, u32 param)
|
|
{
|
|
ulong flags;
|
|
ulong fiq_flag;
|
|
|
|
amlog_level(LOG_LEVEL_INFO, "[%s]event:%d, param %d\n",
|
|
__func__, event, param);
|
|
spin_lock_irqsave(&lock, flags);
|
|
|
|
raw_local_save_flags(fiq_flag);
|
|
|
|
tsync_avevent_locked(event, param);
|
|
|
|
raw_local_irq_restore(fiq_flag);
|
|
|
|
spin_unlock_irqrestore(&lock, flags);
|
|
}
|
|
EXPORT_SYMBOL(tsync_avevent);
|
|
|
|
void tsync_audio_break(int audio_break)
|
|
{
|
|
tsync_aBreak = audio_break;
|
|
}
|
|
EXPORT_SYMBOL(tsync_audio_break);
|
|
|
|
void tsync_trick_mode(int trick_mode)
|
|
{
|
|
tsync_trickmode = trick_mode;
|
|
}
|
|
EXPORT_SYMBOL(tsync_trick_mode);
|
|
|
|
void tsync_set_avthresh(unsigned int av_thresh)
|
|
{
|
|
/* tsync_av_thresh = av_thresh; */
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_avthresh);
|
|
|
|
void tsync_set_syncthresh(unsigned int sync_thresh)
|
|
{
|
|
tsync_syncthresh = sync_thresh;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_syncthresh);
|
|
|
|
void tsync_set_dec_reset(void)
|
|
{
|
|
tsync_dec_reset_flag = 1;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_dec_reset);
|
|
|
|
void tsync_set_enable(int enable)
|
|
{
|
|
tsync_enable = enable;
|
|
tsync_av_mode = TSYNC_STATE_S;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_enable);
|
|
|
|
int tsync_get_sync_adiscont(void)
|
|
{
|
|
return apts_discontinue;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_sync_adiscont);
|
|
|
|
int tsync_get_sync_vdiscont(void)
|
|
{
|
|
return vpts_discontinue;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_sync_vdiscont);
|
|
|
|
u32 tsync_get_sync_adiscont_diff(void)
|
|
{
|
|
return apts_discontinue_diff;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_sync_adiscont_diff);
|
|
|
|
u32 tsync_get_sync_vdiscont_diff(void)
|
|
{
|
|
return vpts_discontinue_diff;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_sync_vdiscont_diff);
|
|
|
|
void tsync_set_sync_adiscont_diff(u32 discontinue_diff)
|
|
{
|
|
apts_discontinue_diff = discontinue_diff;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_sync_adiscont_diff);
|
|
|
|
void tsync_set_sync_vdiscont_diff(u32 discontinue_diff)
|
|
{
|
|
vpts_discontinue_diff = discontinue_diff;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_sync_vdiscont_diff);
|
|
|
|
void tsync_set_sync_adiscont(int sync_discontinue)
|
|
{
|
|
apts_discontinue = sync_discontinue;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_sync_adiscont);
|
|
|
|
void tsync_set_sync_vdiscont(int sync_discontinue)
|
|
{
|
|
vpts_discontinue = sync_discontinue;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_sync_vdiscont);
|
|
|
|
int tsync_set_video_runmode(void)
|
|
{
|
|
if (tsync_get_demux_pcrscr_valid()) {
|
|
if (vpts_discontinue == 1 || apts_discontinue == 1)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_video_runmode);
|
|
|
|
void tsync_set_automute_on(int automute_on)
|
|
{
|
|
tsync_automute_on = automute_on;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_automute_on);
|
|
|
|
int tsync_set_apts(unsigned int pts)
|
|
{
|
|
unsigned int t;
|
|
/* ssize_t r; */
|
|
unsigned int old_pts = timestamp_apts_get();
|
|
int oldmod = tsync_mode;
|
|
|
|
if (tsync_mode == TSYNC_MODE_PCRMASTER) {
|
|
tsync_pcr_set_apts(pts);
|
|
return 0;
|
|
}
|
|
|
|
if (tsync_aBreak)
|
|
tsync_aBreak = 0;
|
|
if (!tsync_enable) {
|
|
timestamp_apts_set(pts);
|
|
return 0;
|
|
}
|
|
if (tsync_mode == TSYNC_MODE_AMASTER)
|
|
t = timestamp_vpts_get();
|
|
else
|
|
t = timestamp_pcrscr_get();
|
|
if (tsync_get_demux_pcrscr_valid()) {
|
|
timestamp_apts_set(pts);
|
|
if ((int)(timestamp_apts_get() - timestamp_pcrscr_get())
|
|
> 30 * TIME_UNIT90K / 1000 ||
|
|
(int)(timestamp_pcrscr_get() - timestamp_apts_get())
|
|
> 80 * TIME_UNIT90K / 1000) {
|
|
timestamp_pcrscr_set(pts);
|
|
set_pts_realign();
|
|
}
|
|
return 0;
|
|
}
|
|
/* do not switch tsync mode until first video toggled. */
|
|
if ((abs(old_pts - pts) > tsync_av_threshold_min) &&
|
|
(timestamp_firstvpts_get() > 0)) { /* is discontinue */
|
|
apts_discontinue = 1;
|
|
/*if in VMASTER ,just wait */
|
|
tsync_mode_switch('A', abs(pts - t),
|
|
pts - old_pts);
|
|
}
|
|
timestamp_apts_set(pts);
|
|
|
|
if (get_vsync_pts_inc_mode() && tsync_mode != TSYNC_MODE_VMASTER)
|
|
tsync_mode = TSYNC_MODE_VMASTER;
|
|
|
|
if (tsync_mode == TSYNC_MODE_AMASTER)
|
|
t = timestamp_pcrscr_get();
|
|
|
|
if (tsync_mode == TSYNC_MODE_AMASTER) {
|
|
/* special used for Dobly Certification AVSync test */
|
|
if (dobly_avsync_test) {
|
|
if (get_vsync_pts_inc_mode() &&
|
|
(((int)(timestamp_apts_get() - t) >
|
|
60 * TIME_UNIT90K / 1000) ||
|
|
(int)(t - timestamp_apts_get()) >
|
|
100 * TIME_UNIT90K / 1000)) {
|
|
pr_info
|
|
("[%d:avsync_test]reset apts:0x%x-->0x%x,",
|
|
__LINE__, old_pts, pts);
|
|
pr_info(" pcr 0x%x, diff %d\n",
|
|
t, pts - t);
|
|
timestamp_pcrscr_set(pts);
|
|
} else if ((!get_vsync_pts_inc_mode()) &&
|
|
((int)(timestamp_apts_get() - t) >
|
|
30 * TIME_UNIT90K / 1000 ||
|
|
(int)(t -
|
|
timestamp_apts_get()) >
|
|
80 * TIME_UNIT90K / 1000))
|
|
timestamp_pcrscr_set(pts);
|
|
} else {
|
|
if (get_vsync_pts_inc_mode() &&
|
|
(((int)(timestamp_apts_get() - t) >
|
|
100 * TIME_UNIT90K / 1000) ||
|
|
(int)(t - timestamp_apts_get()) >
|
|
500 * TIME_UNIT90K / 1000)) {
|
|
pr_info
|
|
("[%d]reset apts:0x%x-->0x%x, ",
|
|
__LINE__, old_pts, pts);
|
|
pr_info("pcr 0x%x, diff %d\n",
|
|
t, pts - t);
|
|
timestamp_pcrscr_set(pts);
|
|
set_pts_realign();
|
|
} else if ((!get_vsync_pts_inc_mode()) &&
|
|
(abs(timestamp_apts_get() - t) >
|
|
100 * TIME_UNIT90K / 1000)) {
|
|
pr_info
|
|
("[%d]reset apts:0x%x-->0x%x, ",
|
|
__LINE__, old_pts, pts);
|
|
pr_info("pcr 0x%x, diff %d\n",
|
|
t, pts - t);
|
|
timestamp_pcrscr_set(pts);
|
|
set_pts_realign();
|
|
}
|
|
}
|
|
} else if ((oldmod != tsync_mode) && (tsync_mode == TSYNC_MODE_VMASTER))
|
|
timestamp_pcrscr_set(get_first_pic_coming()
|
|
? timestamp_vpts_get() : timestamp_firstvpts_get());
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_apts);
|
|
|
|
/*********************************************************/
|
|
|
|
static ssize_t pcr_recover_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "%s %s\n",
|
|
((tsync_pcr_recover_enable) ? "on" : "off"),
|
|
((pcr_sync_stat ==
|
|
PCR_SYNC_UNSET) ? ("UNSET") : ((pcr_sync_stat ==
|
|
PCR_SYNC_LO) ? "LO" :
|
|
"HI")));
|
|
}
|
|
|
|
void tsync_pcr_recover(void)
|
|
{
|
|
}
|
|
EXPORT_SYMBOL(tsync_pcr_recover);
|
|
|
|
int tsync_get_mode(void)
|
|
{
|
|
return tsync_mode;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_mode);
|
|
|
|
int tsync_get_debug_pts_checkin(void)
|
|
{
|
|
return debug_pts_checkin;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_debug_pts_checkin);
|
|
|
|
int tsync_get_debug_pts_checkout(void)
|
|
{
|
|
return debug_pts_checkout;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_debug_pts_checkout);
|
|
|
|
int tsync_get_debug_vpts(void)
|
|
{
|
|
return debug_vpts;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_debug_vpts);
|
|
|
|
int tsync_get_debug_apts(void)
|
|
{
|
|
return debug_apts;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_debug_apts);
|
|
|
|
int tsync_get_av_threshold_min(void)
|
|
{
|
|
return tsync_av_threshold_min;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_av_threshold_min);
|
|
|
|
int tsync_get_av_threshold_max(void)
|
|
{
|
|
return tsync_av_threshold_max;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_av_threshold_max);
|
|
|
|
int tsync_set_av_threshold_min(int min)
|
|
{
|
|
return tsync_av_threshold_min = min;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_av_threshold_min);
|
|
|
|
int tsync_set_av_threshold_max(int max)
|
|
{
|
|
return tsync_av_threshold_max = max;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_av_threshold_max);
|
|
|
|
int tsync_get_vpause_flag(void)
|
|
{
|
|
return vpause_flag;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_vpause_flag);
|
|
|
|
int tsync_set_vpause_flag(int mode)
|
|
{
|
|
return vpause_flag = mode;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_vpause_flag);
|
|
|
|
int tsync_get_slowsync_enable(void)
|
|
{
|
|
return slowsync_enable;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_slowsync_enable);
|
|
|
|
int tsync_set_slowsync_enable(int enable)
|
|
{
|
|
return slowsync_enable = enable;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_slowsync_enable);
|
|
|
|
int tsync_get_startsync_mode(void)
|
|
{
|
|
return startsync_mode;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_startsync_mode);
|
|
|
|
int tsync_set_startsync_mode(int mode)
|
|
{
|
|
return startsync_mode = mode;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_startsync_mode);
|
|
|
|
int tsync_set_tunnel_mode(int mode)
|
|
{
|
|
tsync_mode = TSYNC_MODE_AMASTER;
|
|
return is_tunnel_mode = mode;
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_tunnel_mode);
|
|
|
|
int tsync_get_tunnel_mode(void)
|
|
{
|
|
return is_tunnel_mode;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_tunnel_mode);
|
|
|
|
bool tsync_check_vpts_discontinuity(unsigned int vpts)
|
|
{
|
|
unsigned int systemtime;
|
|
|
|
if (tsync_get_mode() != TSYNC_MODE_PCRMASTER)
|
|
return false;
|
|
if (tsync_pcr_demux_pcr_used() == 0)
|
|
systemtime = timestamp_pcrscr_get();
|
|
else
|
|
systemtime = timestamp_pcrscr_get()
|
|
+ timestamp_get_pcrlatency();
|
|
if (vpts > systemtime &&
|
|
(vpts - systemtime) > tsync_vpts_discontinuity_margin())
|
|
return true;
|
|
else if (systemtime > vpts &&
|
|
(systemtime - vpts) > tsync_vpts_discontinuity_margin())
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
EXPORT_SYMBOL(tsync_check_vpts_discontinuity);
|
|
|
|
int tsync_get_vpts_error_num(void)
|
|
{
|
|
return vpts_error_num;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_vpts_error_num);
|
|
|
|
int tsync_get_apts_error_num(void)
|
|
{
|
|
return apts_error_num;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_apts_error_num);
|
|
|
|
bool tsync_get_new_arch(void)
|
|
{
|
|
return new_arch;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_new_arch);
|
|
|
|
u32 tsync_get_checkin_apts(void)
|
|
{
|
|
return checkin_apts_from_audiohal;
|
|
}
|
|
EXPORT_SYMBOL(tsync_get_checkin_apts);
|
|
|
|
void tsync_set_mode(int mode)
|
|
{
|
|
tsync_mode = mode;
|
|
pr_info("[%s]tsync_mode=%d\n", __func__, tsync_mode);
|
|
}
|
|
EXPORT_SYMBOL(tsync_set_mode);
|
|
|
|
static ssize_t pcr_recover_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
return size;
|
|
}
|
|
|
|
static ssize_t pts_video_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "0x%x\n", timestamp_vpts_get());
|
|
}
|
|
|
|
static ssize_t pts_video_u64_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
u64 pts_val;
|
|
|
|
pts_val = div64_u64(timestamp_vpts_get_u64() * 9, 100);
|
|
return sprintf(buf, "0x%llx\n", pts_val);
|
|
}
|
|
|
|
static ssize_t pts_video_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int pts;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "0x%x", &pts);*/
|
|
r = kstrtouint(buf, 0, &pts);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
timestamp_vpts_set(pts);
|
|
return size;
|
|
}
|
|
|
|
static ssize_t demux_pcr_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "0x%x\n", timestamp_tsdemux_pcr_get());
|
|
}
|
|
|
|
static ssize_t pts_audio_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "0x%x\n", timestamp_apts_get());
|
|
}
|
|
|
|
static ssize_t pts_audio_u64_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
u64 pts_val;
|
|
|
|
pts_val = div64_u64(timestamp_apts_get_u64() * 9, 100);
|
|
return sprintf(buf, "0x%llx\n", pts_val);
|
|
}
|
|
|
|
static ssize_t pts_audio_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int pts;
|
|
ssize_t r;
|
|
|
|
r = kstrtouint(buf, 0, &pts);
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
tsync_set_apts(pts);
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t dobly_av_sync_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf,
|
|
"avsync:cur value is %d\n 0:no set(default)\n 1:avsync test\n",
|
|
dobly_avsync_test ? 1 : 0);
|
|
}
|
|
|
|
static ssize_t dobly_av_sync_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int value;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%u", &value);*/
|
|
r = kstrtoint(buf, 0, &value);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
if (value == 1)
|
|
dobly_avsync_test = true;
|
|
else
|
|
dobly_avsync_test = false;
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t pts_pcrscr_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "0x%x\n", timestamp_pcrscr_get());
|
|
}
|
|
|
|
static ssize_t pts_pcrscr_u64_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
u64 pts_val;
|
|
|
|
pts_val = div64_u64(timestamp_pcrscr_get_u64() * 9, 100);
|
|
return sprintf(buf, "0x%llx\n", pts_val);
|
|
}
|
|
|
|
static ssize_t apts_checkin_flag_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "%d\n", first_pts_checkin_complete(PTS_TYPE_AUDIO));
|
|
}
|
|
|
|
static ssize_t pts_pcrscr_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int pts;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "0x%x", &pts);*/
|
|
r = kstrtouint(buf, 0, &pts);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
timestamp_pcrscr_set(pts);
|
|
set_pts_realign();
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t event_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(avevent_token); i++) {
|
|
if (strncmp
|
|
(avevent_token[i].token, buf,
|
|
avevent_token[i].token_size) == 0) {
|
|
if (avevent_token[i].flag & AVEVENT_FLAG_PARAM) {
|
|
char *param_str = strchr(buf, ':');
|
|
unsigned long value;
|
|
int ret;
|
|
|
|
if (!param_str)
|
|
return -EINVAL;
|
|
ret = kstrtoul(param_str + 1, 0,
|
|
(unsigned long *)&value);
|
|
if (ret < 0)
|
|
return -EINVAL;
|
|
tsync_avevent(avevent_token[i].event,
|
|
value);
|
|
} else {
|
|
tsync_avevent(avevent_token[i].event, 0);
|
|
}
|
|
|
|
return size;
|
|
}
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static ssize_t mode_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
if (tsync_mode <= TSYNC_MODE_PCRMASTER) {
|
|
return sprintf(buf, "%d: %s\n", tsync_mode,
|
|
tsync_mode_str[tsync_mode]);
|
|
}
|
|
|
|
return sprintf(buf, "invalid mode");
|
|
}
|
|
|
|
static ssize_t mode_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int mode;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &mode);*/
|
|
r = kstrtoint(buf, 0, &mode);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
if (mode == TSYNC_MODE_PCRMASTER)
|
|
tsync_mode = TSYNC_MODE_PCRMASTER;
|
|
else if (mode == TSYNC_MODE_VMASTER)
|
|
tsync_mode = TSYNC_MODE_VMASTER;
|
|
else
|
|
tsync_mode = TSYNC_MODE_AMASTER;
|
|
|
|
pr_info("[%s]tsync_mode=%d, buf=%s\n", __func__, tsync_mode, buf);
|
|
return size;
|
|
}
|
|
|
|
static ssize_t enable_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
if (tsync_enable)
|
|
return sprintf(buf, "1: enabled\n");
|
|
|
|
return sprintf(buf, "0: disabled\n");
|
|
}
|
|
|
|
static ssize_t enable_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int mode;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &mode);*/
|
|
r = kstrtoint(buf, 0, &mode);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
if (!tsync_automute_on)
|
|
tsync_enable = mode ? 1 : 0;
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t discontinue_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
pts_discontinue = vpts_discontinue || apts_discontinue;
|
|
if (pts_discontinue) {
|
|
return sprintf(buf, "apts diff %d, vpts diff=%d\n",
|
|
apts_discontinue_diff, vpts_discontinue_diff);
|
|
}
|
|
|
|
return sprintf(buf, "0: pts_continue\n");
|
|
}
|
|
|
|
static ssize_t discontinue_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int discontinue;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &discontinue);*/
|
|
r = kstrtoint(buf, 0, &discontinue);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
pts_discontinue = discontinue ? 1 : 0;
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t debug_pts_checkin_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
if (debug_pts_checkin)
|
|
return sprintf(buf, "1: debug pts checkin on\n");
|
|
|
|
return sprintf(buf, "0: debug pts checkin off\n");
|
|
}
|
|
|
|
static ssize_t debug_pts_checkin_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int mode;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &mode);*/
|
|
r = kstrtoint(buf, 0, &mode);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
debug_pts_checkin = mode ? 1 : 0;
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t debug_pts_checkout_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
if (debug_pts_checkout)
|
|
return sprintf(buf, "1: debug pts checkout on\n");
|
|
|
|
return sprintf(buf, "0: debug pts checkout off\n");
|
|
}
|
|
|
|
static ssize_t debug_pts_checkout_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int mode;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &mode);*/
|
|
r = kstrtoint(buf, 0, &mode);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
debug_pts_checkout = mode ? 1 : 0;
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t debug_video_pts_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
if (debug_vpts)
|
|
return sprintf(buf, "1: debug vpts on\n");
|
|
|
|
return sprintf(buf, "0: debug vpts off\n");
|
|
}
|
|
|
|
static ssize_t debug_video_pts_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int mode;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &mode);*/
|
|
r = kstrtoint(buf, 0, &mode);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
debug_vpts = mode ? 1 : 0;
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t debug_audio_pts_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
if (debug_apts)
|
|
return sprintf(buf, "1: debug apts on\n");
|
|
|
|
return sprintf(buf, "0: debug apts off\n");
|
|
}
|
|
|
|
static ssize_t debug_audio_pts_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int mode;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &mode);*/
|
|
r = kstrtoint(buf, 0, &mode);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
debug_apts = mode ? 1 : 0;
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t av_threshold_min_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "tsync_av_threshold_min=%d\n",
|
|
tsync_av_threshold_min);
|
|
}
|
|
|
|
static ssize_t av_threshold_min_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int min;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &min);*/
|
|
r = kstrtoint(buf, 0, &min);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
tsync_set_av_threshold_min(min);
|
|
return size;
|
|
}
|
|
|
|
static ssize_t av_threshold_max_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "tsync_av_threshold_max=%d\n",
|
|
tsync_av_threshold_max);
|
|
}
|
|
|
|
static ssize_t av_threshold_max_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int max;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &max);*/
|
|
r = kstrtoint(buf, 0, &max);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
tsync_set_av_threshold_max(max);
|
|
return size;
|
|
}
|
|
|
|
static ssize_t last_checkin_apts_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
unsigned int last_apts;
|
|
|
|
last_apts = get_last_checkin_pts(PTS_TYPE_AUDIO);
|
|
return sprintf(buf, "0x%x\n", last_apts);
|
|
}
|
|
|
|
static ssize_t last_checkin_vpts_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
unsigned int last_vpts;
|
|
|
|
last_vpts = get_last_checkin_pts(PTS_TYPE_VIDEO);
|
|
return sprintf(buf, "0x%x\n", last_vpts);
|
|
}
|
|
|
|
static ssize_t firstvpts_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "0x%x\n", timestamp_firstvpts_get());
|
|
}
|
|
|
|
static ssize_t videostarted_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "0x%x\n", tsync_video_started);
|
|
}
|
|
|
|
static ssize_t firstapts_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "0x%x\n", timestamp_firstapts_get());
|
|
}
|
|
|
|
static ssize_t firstapts_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int pts;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "0x%x", &pts);*/
|
|
r = kstrtoint(buf, 0, &pts);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
timestamp_firstapts_set(pts);
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t checkin_firstvpts_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "0x%x\n", timestamp_checkin_firstvpts_get());
|
|
}
|
|
|
|
static ssize_t checkin_firstapts_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "0x%x\n", timestamp_checkin_firstapts_get());
|
|
}
|
|
|
|
static ssize_t vpause_flag_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "0x%x\n", tsync_get_vpause_flag());
|
|
}
|
|
|
|
static ssize_t vpause_flag_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int mode;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &mode);*/
|
|
r = kstrtoint(buf, 0, &mode);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
tsync_set_vpause_flag(mode);
|
|
return size;
|
|
}
|
|
|
|
static ssize_t slowsync_enable_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "slowsync enable:0x%x\n",
|
|
tsync_get_slowsync_enable());
|
|
}
|
|
|
|
static ssize_t slowsync_enable_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int mode;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &mode);*/
|
|
r = kstrtoint(buf, 0, &mode);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
tsync_set_slowsync_enable(mode);
|
|
return size;
|
|
}
|
|
|
|
static ssize_t startsync_mode_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "0x%x\n", tsync_get_startsync_mode());
|
|
}
|
|
|
|
static ssize_t pts_latency_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "%u\n", timestamp_get_pcrlatency());
|
|
}
|
|
|
|
static ssize_t pts_latency_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int latency = 0;
|
|
ssize_t r;
|
|
|
|
r = kstrtoint(buf, 0, &latency);
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
timestamp_set_pcrlatency(latency);
|
|
return size;
|
|
}
|
|
|
|
static ssize_t avsync_count_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "%u\n", timestamp_avsync_counter_get());
|
|
}
|
|
|
|
static ssize_t avsync_count_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int counts = 0;
|
|
ssize_t r;
|
|
|
|
r = kstrtouint(buf, 0, &counts);
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
timestamp_avsync_counter_set(counts);
|
|
return size;
|
|
}
|
|
|
|
static ssize_t apts_lookup_show(struct class *class,
|
|
struct class_attribute *attribute, char *buf)
|
|
{
|
|
u32 frame_size;
|
|
unsigned int pts = 0xffffffff;
|
|
|
|
pts_lookup_offset(PTS_TYPE_AUDIO, apts_lookup_offset,
|
|
&pts, &frame_size, 300);
|
|
return sprintf(buf, "0x%x\n", pts);
|
|
}
|
|
|
|
static ssize_t apts_lookup_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf,
|
|
size_t size)
|
|
{
|
|
unsigned int offset;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &mode);*/
|
|
r = kstrtoint(buf, 0, &offset);
|
|
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
apts_lookup_offset = offset;
|
|
return size;
|
|
}
|
|
|
|
static ssize_t startsync_mode_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
unsigned int mode;
|
|
ssize_t r;
|
|
|
|
/*r = sscanf(buf, "%d", &mode);*/
|
|
r = kstrtoint(buf, 0, &mode);
|
|
if (r != 0)
|
|
return -EINVAL;
|
|
|
|
tsync_set_startsync_mode(mode);
|
|
return size;
|
|
}
|
|
|
|
static CLASS_ATTR_RW(pts_video);
|
|
static CLASS_ATTR_RO(pts_video_u64);
|
|
static CLASS_ATTR_RW(pts_audio);
|
|
static CLASS_ATTR_RO(pts_audio_u64);
|
|
static CLASS_ATTR_RW(dobly_av_sync);
|
|
static CLASS_ATTR_RW(pts_pcrscr);
|
|
static CLASS_ATTR_RO(pts_pcrscr_u64);
|
|
static CLASS_ATTR_RO(apts_checkin_flag);
|
|
static CLASS_ATTR_WO(event);
|
|
static CLASS_ATTR_RW(mode);
|
|
static CLASS_ATTR_RW(enable);
|
|
static CLASS_ATTR_RW(pcr_recover);
|
|
static CLASS_ATTR_RW(discontinue);
|
|
static CLASS_ATTR_RW(debug_pts_checkin);
|
|
static CLASS_ATTR_RW(debug_pts_checkout);
|
|
static CLASS_ATTR_RW(debug_video_pts);
|
|
static CLASS_ATTR_RW(debug_audio_pts);
|
|
static CLASS_ATTR_RW(av_threshold_min);
|
|
static CLASS_ATTR_RW(av_threshold_max);
|
|
static CLASS_ATTR_RO(last_checkin_apts);
|
|
static CLASS_ATTR_RO(firstvpts);
|
|
static CLASS_ATTR_RW(vpause_flag);
|
|
static CLASS_ATTR_RW(slowsync_enable);
|
|
static CLASS_ATTR_RW(startsync_mode);
|
|
static CLASS_ATTR_RW(firstapts);
|
|
static CLASS_ATTR_RO(checkin_firstvpts);
|
|
static CLASS_ATTR_RW(apts_lookup);
|
|
static CLASS_ATTR_RO(demux_pcr);
|
|
static CLASS_ATTR_RO(checkin_firstapts);
|
|
static CLASS_ATTR_RW(pts_latency);
|
|
static CLASS_ATTR_RO(videostarted);
|
|
static CLASS_ATTR_RW(avsync_count);
|
|
static CLASS_ATTR_RO(last_checkin_vpts);
|
|
|
|
static struct attribute *tsync_class_attrs[] = {
|
|
&class_attr_pts_video.attr,
|
|
&class_attr_pts_video_u64.attr,
|
|
&class_attr_pts_audio.attr,
|
|
&class_attr_pts_audio_u64.attr,
|
|
&class_attr_dobly_av_sync.attr,
|
|
&class_attr_pts_pcrscr.attr,
|
|
&class_attr_pts_pcrscr_u64.attr,
|
|
&class_attr_apts_checkin_flag.attr,
|
|
&class_attr_event.attr,
|
|
&class_attr_mode.attr,
|
|
&class_attr_enable.attr,
|
|
&class_attr_pcr_recover.attr,
|
|
&class_attr_discontinue.attr,
|
|
&class_attr_debug_pts_checkin.attr,
|
|
&class_attr_debug_pts_checkout.attr,
|
|
&class_attr_debug_video_pts.attr,
|
|
&class_attr_debug_audio_pts.attr,
|
|
&class_attr_av_threshold_min.attr,
|
|
&class_attr_av_threshold_max.attr,
|
|
&class_attr_last_checkin_apts.attr,
|
|
&class_attr_firstvpts.attr,
|
|
&class_attr_vpause_flag.attr,
|
|
&class_attr_slowsync_enable.attr,
|
|
&class_attr_startsync_mode.attr,
|
|
&class_attr_firstapts.attr,
|
|
&class_attr_checkin_firstvpts.attr,
|
|
&class_attr_apts_lookup.attr,
|
|
&class_attr_demux_pcr.attr,
|
|
&class_attr_checkin_firstapts.attr,
|
|
&class_attr_pts_latency.attr,
|
|
&class_attr_videostarted.attr,
|
|
&class_attr_avsync_count.attr,
|
|
&class_attr_last_checkin_vpts.attr,
|
|
NULL
|
|
};
|
|
|
|
ATTRIBUTE_GROUPS(tsync_class);
|
|
|
|
static struct class tsync_class = {
|
|
.name = "tsync",
|
|
.class_groups = tsync_class_groups,
|
|
};
|
|
|
|
int tsync_store_fun(const char *trigger, int id, const char *buf, int size)
|
|
{
|
|
int ret = size;
|
|
|
|
switch (id) {
|
|
case 0: return pts_video_store(NULL, NULL, buf, size);
|
|
case 1: return pts_audio_store(NULL, NULL, buf, size);
|
|
case 2: return dobly_av_sync_store(NULL, NULL, buf, size);
|
|
case 3: return pts_pcrscr_store(NULL, NULL, buf, size);
|
|
case 4: return event_store(NULL, NULL, buf, size);
|
|
case 5: return mode_store(NULL, NULL, buf, size);
|
|
case 6: return enable_store(NULL, NULL, buf, size);
|
|
case 7: return pcr_recover_store(NULL, NULL, buf, size);
|
|
case 8: return discontinue_store(NULL, NULL, buf, size);
|
|
case 9: return debug_pts_checkin_store(NULL, NULL, buf, size);
|
|
case 10:return debug_pts_checkout_store(NULL, NULL, buf, size);
|
|
case 11:return debug_video_pts_store(NULL, NULL, buf, size);
|
|
case 12:return debug_audio_pts_store(NULL, NULL, buf, size);
|
|
case 13:return av_threshold_min_store(NULL, NULL, buf, size);
|
|
case 14:return av_threshold_max_store(NULL, NULL, buf, size);
|
|
/*case 15:return -1;*/
|
|
/*case 16:return -1;*/
|
|
case 17:return vpause_flag_store(NULL, NULL, buf, size);
|
|
case 18:return slowsync_enable_store(NULL, NULL, buf, size);
|
|
case 19:return startsync_mode_store(NULL, NULL, buf, size);
|
|
case 20:return firstapts_store(NULL, NULL, buf, size);
|
|
case 21:return -1;
|
|
default:
|
|
ret = -1;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
int tsync_show_fun(const char *trigger, int id, char *sbuf, int size)
|
|
{
|
|
int ret = -1;
|
|
void *buf, *getbuf = NULL;
|
|
|
|
if (size < PAGE_SIZE) {
|
|
getbuf = (void *)__get_free_page(GFP_KERNEL);
|
|
if (!getbuf)
|
|
return -ENOMEM;
|
|
buf = getbuf;
|
|
} else {
|
|
buf = sbuf;
|
|
}
|
|
|
|
switch (id) {
|
|
case 0:
|
|
ret = pts_video_show(NULL, NULL, buf);
|
|
break;
|
|
case 1:
|
|
ret = pts_audio_show(NULL, NULL, buf);
|
|
break;
|
|
case 2:
|
|
ret = dobly_av_sync_show(NULL, NULL, buf);
|
|
break;
|
|
case 3:
|
|
ret = pts_pcrscr_show(NULL, NULL, buf);
|
|
break;
|
|
case 4:
|
|
ret = -1;
|
|
break;
|
|
case 5:
|
|
ret = mode_show(NULL, NULL, buf);
|
|
break;
|
|
case 6:
|
|
ret = enable_show(NULL, NULL, buf);
|
|
break;
|
|
case 7:
|
|
ret = pcr_recover_show(NULL, NULL, buf);
|
|
break;
|
|
case 8:
|
|
ret = discontinue_show(NULL, NULL, buf);
|
|
break;
|
|
case 9:
|
|
ret = debug_pts_checkin_show(NULL, NULL, buf);
|
|
break;
|
|
case 10:
|
|
ret = debug_pts_checkout_show(NULL, NULL, buf);
|
|
break;
|
|
case 11:
|
|
ret = debug_video_pts_show(NULL, NULL, buf);
|
|
break;
|
|
case 12:
|
|
ret = debug_audio_pts_show(NULL, NULL, buf);
|
|
break;
|
|
case 13:
|
|
ret = av_threshold_min_show(NULL, NULL, buf);
|
|
break;
|
|
case 14:
|
|
ret = av_threshold_max_show(NULL, NULL, buf);
|
|
break;
|
|
case 15:
|
|
ret = last_checkin_apts_show(NULL, NULL, buf);
|
|
break;
|
|
case 16:
|
|
ret = firstvpts_show(NULL, NULL, buf);
|
|
break;
|
|
case 17:
|
|
ret = vpause_flag_show(NULL, NULL, buf);
|
|
break;
|
|
case 18:
|
|
ret = slowsync_enable_show(NULL, NULL, buf);
|
|
break;
|
|
case 19:
|
|
ret = startsync_mode_show(NULL, NULL, buf);
|
|
break;
|
|
case 20:
|
|
ret = firstapts_show(NULL, NULL, buf);
|
|
break;
|
|
case 21:
|
|
ret = checkin_firstvpts_show(NULL, NULL, buf);
|
|
break;
|
|
case 22:
|
|
ret = videostarted_show(NULL, NULL, buf);
|
|
break;
|
|
case 23:
|
|
ret = pts_video_u64_show(NULL, NULL, buf);
|
|
break;
|
|
case 24:
|
|
ret = pts_audio_u64_show(NULL, NULL, buf);
|
|
break;
|
|
case 25:
|
|
ret = pts_pcrscr_u64_show(NULL, NULL, buf);
|
|
break;
|
|
case 26:
|
|
ret = last_checkin_vpts_show(NULL, NULL, buf);
|
|
break;
|
|
default:
|
|
ret = -1;
|
|
}
|
|
if (ret > 0 && getbuf) {
|
|
ret = min_t(int, ret, size);
|
|
strncpy(sbuf, buf, ret);
|
|
}
|
|
if (getbuf)
|
|
free_page((unsigned long)getbuf);
|
|
return ret;
|
|
}
|
|
|
|
static struct mconfig tsync_configs[] = {
|
|
MC_FUN_ID("pts_video", tsync_show_fun, tsync_store_fun, 0),
|
|
MC_FUN_ID("pts_audio", tsync_show_fun, tsync_store_fun, 1),
|
|
MC_FUN_ID("dobly_av_sync", tsync_show_fun, tsync_store_fun, 2),
|
|
MC_FUN_ID("pts_pcrscr", tsync_show_fun, tsync_store_fun, 3),
|
|
MC_FUN_ID("event", tsync_show_fun, tsync_store_fun, 4),
|
|
MC_FUN_ID("mode", tsync_show_fun, tsync_store_fun, 5),
|
|
MC_FUN_ID("enable", tsync_show_fun, tsync_store_fun, 6),
|
|
MC_FUN_ID("pcr_recover", tsync_show_fun, tsync_store_fun, 7),
|
|
MC_FUN_ID("discontinue", tsync_show_fun, tsync_store_fun, 8),
|
|
MC_FUN_ID("debug_pts_checkin", tsync_show_fun, tsync_store_fun, 9),
|
|
MC_FUN_ID("debug_pts_checkout", tsync_show_fun, tsync_store_fun, 10),
|
|
MC_FUN_ID("debug_video_pts", tsync_show_fun, tsync_store_fun, 11),
|
|
MC_FUN_ID("debug_audio_pts", tsync_show_fun, tsync_store_fun, 12),
|
|
MC_FUN_ID("av_threshold_min", tsync_show_fun, tsync_store_fun, 13),
|
|
MC_FUN_ID("av_threshold_max", tsync_show_fun, tsync_store_fun, 14),
|
|
MC_FUN_ID("last_checkin_apts", tsync_show_fun, NULL, 15),
|
|
MC_FUN_ID("firstvpts", tsync_show_fun, NULL, 16),
|
|
MC_FUN_ID("vpause_flag", tsync_show_fun, tsync_store_fun, 17),
|
|
MC_FUN_ID("slowsync_enable", tsync_show_fun, tsync_store_fun, 18),
|
|
MC_FUN_ID("startsync_mode", tsync_show_fun, tsync_store_fun, 19),
|
|
MC_FUN_ID("firstapts", tsync_show_fun, tsync_store_fun, 20),
|
|
MC_FUN_ID("checkin_firstvpts", tsync_show_fun, NULL, 21),
|
|
MC_FUN_ID("videostarted", tsync_show_fun, NULL, 22),
|
|
MC_FUN_ID("pts_video_u64", tsync_show_fun, NULL, 23),
|
|
MC_FUN_ID("pts_audio_u64", tsync_show_fun, NULL, 24),
|
|
MC_FUN_ID("pts_pcrscr_u64", tsync_show_fun, NULL, 25),
|
|
};
|
|
|
|
static int tsync_open(struct inode *inode, struct file *file)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int tsync_release(struct inode *inode, struct file *file)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static long tsync_ioctl(struct file *file, unsigned int cmd, ulong arg)
|
|
{
|
|
long ret = 0;
|
|
unsigned int tmp_pts = 0;
|
|
void __user *argp = (void __user *)arg;
|
|
|
|
switch (cmd) {
|
|
case TSYNC_IOC_SET_TUNNEL_MODE:{
|
|
u32 tunnel_mode;
|
|
|
|
if (copy_from_user(&tunnel_mode,
|
|
argp, sizeof(is_tunnel_mode)) == 0)
|
|
tsync_set_tunnel_mode(tunnel_mode);
|
|
else
|
|
ret = -EFAULT;
|
|
break;
|
|
}
|
|
case TSYNC_IOC_SET_VIDEO_PEEK:
|
|
set_video_peek();
|
|
break;
|
|
|
|
case TSYNC_IOC_GET_FIRST_FRAME_TOGGLED:
|
|
put_user(get_first_frame_toggled(), (u32 __user *)argp);
|
|
break;
|
|
|
|
case TSYNC_IOC_SET_FIRST_CHECKIN_APTS:
|
|
if (new_arch && get_user(tmp_pts, (unsigned int *)arg) >= 0)
|
|
timestamp_checkin_firstapts_set(tmp_pts);
|
|
break;
|
|
|
|
case TSYNC_IOC_SET_LAST_CHECKIN_APTS:
|
|
if (new_arch)
|
|
get_user(checkin_apts_from_audiohal,
|
|
(unsigned int *)arg);
|
|
break;
|
|
|
|
case TSYNC_IOC_SET_DEMUX_INFO:
|
|
if (new_arch &&
|
|
(copy_from_user((void *)&demux_info, (void *)arg,
|
|
sizeof(demux_info)) == 0)) {
|
|
tsync_check_pid_valid_for_newarch(demux_info);
|
|
ret = pts_start(PTS_TYPE_VIDEO);
|
|
if (ret < 0) {
|
|
pr_err("pts_start failed, retry\n");
|
|
ret = pts_stop(PTS_TYPE_VIDEO);
|
|
if (ret < 0)
|
|
pr_warn("pts_stop failed when retrying...");
|
|
ret = pts_start(PTS_TYPE_VIDEO);
|
|
if (ret < 0)
|
|
pr_err("pts_start failed\n");
|
|
}
|
|
tsync_pcr_start();
|
|
}
|
|
break;
|
|
|
|
case TSYNC_IOC_STOP_TSYNC_PCR:
|
|
if (new_arch) {
|
|
ret = pts_stop(PTS_TYPE_VIDEO);
|
|
if (ret < 0)
|
|
pr_err("pts_stop failed=%ld\n", ret);
|
|
|
|
tsync_pcr_stop();
|
|
}
|
|
break;
|
|
default:
|
|
pr_info("invalid cmd:%d\n", cmd);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
static long tsync_compat_ioctl(struct file *file, unsigned int cmd, ulong arg)
|
|
{
|
|
long ret = 0;
|
|
|
|
switch (cmd) {
|
|
case TSYNC_IOC_SET_TUNNEL_MODE:
|
|
case TSYNC_IOC_SET_VIDEO_PEEK:
|
|
case TSYNC_IOC_GET_FIRST_FRAME_TOGGLED:
|
|
case TSYNC_IOC_SET_FIRST_CHECKIN_APTS:
|
|
case TSYNC_IOC_SET_LAST_CHECKIN_APTS:
|
|
case TSYNC_IOC_SET_DEMUX_INFO:
|
|
case TSYNC_IOC_STOP_TSYNC_PCR:
|
|
return tsync_ioctl(file, cmd, arg);
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations tsync_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = tsync_open,
|
|
.release = tsync_release,
|
|
.unlocked_ioctl = tsync_ioctl,
|
|
#ifdef CONFIG_COMPAT
|
|
.compat_ioctl = tsync_compat_ioctl,
|
|
#endif
|
|
};
|
|
|
|
int __init tsync_module_init(void)
|
|
{
|
|
int r;
|
|
int chip = -1;
|
|
|
|
r = class_register(&tsync_class);
|
|
|
|
if (r) {
|
|
amlog_level(LOG_LEVEL_ERROR, "tsync class create fail.\n");
|
|
return r;
|
|
}
|
|
|
|
/* create tsync device */
|
|
r = register_chrdev(TSYNC_MAJOR, "tsync", &tsync_fops);
|
|
if (r < 0) {
|
|
pr_info("Can't register major for tsync\n");
|
|
goto err2;
|
|
}
|
|
|
|
tsync_dev = device_create(&tsync_class, NULL, MKDEV(TSYNC_MAJOR, 0),
|
|
NULL, TSYNC_DEVICE_NAME);
|
|
|
|
if (IS_ERR(tsync_dev)) {
|
|
amlog_level(LOG_LEVEL_ERROR, "Can't create tsync_dev device\n");
|
|
goto err1;
|
|
}
|
|
|
|
/* init audio pts to -1, others to 0 */
|
|
timestamp_apts_set(-1);
|
|
timestamp_vpts_set(0);
|
|
timestamp_vpts_set_u64(0);
|
|
timestamp_pcrscr_set(0);
|
|
|
|
timer_setup(&tsync_pcr_recover_timer, tsync_pcr_recover_timer_func, 0);
|
|
tsync_pcr_recover_timer.expires = jiffies + PCR_CHECK_INTERVAL;
|
|
pcr_sync_stat = PCR_SYNC_UNSET;
|
|
pcr_recover_trigger = 0;
|
|
|
|
apts_error_num = 0;
|
|
vpts_error_num = 0;
|
|
|
|
add_timer(&tsync_pcr_recover_timer);
|
|
|
|
timer_setup(&tsync_state_switch_timer, tsync_state_switch_timer_fun, 0);
|
|
tsync_state_switch_timer.expires = jiffies + 1;
|
|
add_timer(&tsync_state_switch_timer);
|
|
|
|
REG_PATH_CONFIGS("media.tsync", tsync_configs);
|
|
|
|
first_demux_pcrscr = 0;
|
|
demux_pcrscr = 0;
|
|
audio_pid_valid = 0;
|
|
video_pid_valid = 0;
|
|
demux_pcrscr_valid = 0;
|
|
|
|
chip = get_cpu_type();
|
|
/*
|
|
*"new_arch" is true means X4 demux was used.
|
|
we use the conditions "chip type >= sc2 and exclude some
|
|
X2 demux chip types, such as: such as T5/T5D".
|
|
*/
|
|
if (chip >= MESON_CPU_MAJOR_ID_SC2 &&
|
|
chip != MESON_CPU_MAJOR_ID_T5 &&
|
|
chip != MESON_CPU_MAJOR_ID_T5D &&
|
|
chip != MESON_CPU_MAJOR_ID_TXHD2)
|
|
new_arch = true;
|
|
else
|
|
new_arch = false;
|
|
|
|
pr_info("new arch is :%d.", new_arch);
|
|
|
|
return 0;
|
|
|
|
err1:
|
|
unregister_chrdev(TSYNC_MAJOR, "tsync");
|
|
err2:
|
|
class_unregister(&tsync_class);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __exit tsync_module_exit(void)
|
|
{
|
|
del_timer_sync(&tsync_pcr_recover_timer);
|
|
device_destroy(&tsync_class, MKDEV(TSYNC_MAJOR, 0));
|
|
unregister_chrdev(TSYNC_MAJOR, "tsync");
|
|
class_unregister(&tsync_class);
|
|
}
|
|
|
|
MODULE_PARM_DESC(is_tunnel_mode, "\n is_tunnel_mode\n");
|
|
module_param(is_tunnel_mode, uint, 0664);
|
|
//MODULE_DESCRIPTION("AMLOGIC time sync management driver");
|
|
//MODULE_LICENSE("GPL");
|
|
//MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
|