From a3c83f2a08d8acac54dd68d8336bed123bf7ae3c Mon Sep 17 00:00:00 2001 From: TwolDE Date: Mon, 25 Nov 2024 16:10:02 +0100 Subject: [PATCH] [patches] remove unused --- dm9x0.patch | 1817 ------------------------------- fcc.patch | 3005 --------------------------------------------------- 2 files changed, 4822 deletions(-) delete mode 100644 dm9x0.patch delete mode 100644 fcc.patch diff --git a/dm9x0.patch b/dm9x0.patch deleted file mode 100644 index ab2107b90a9..00000000000 --- a/dm9x0.patch +++ /dev/null @@ -1,1817 +0,0 @@ -diff --git a/.github/workflows/buildbot.yml b/.github/workflows/buildbot.yml -index 0db1c7f0853..e46e714b074 100644 ---- a/.github/workflows/buildbot.yml -+++ b/.github/workflows/buildbot.yml -@@ -2,7 +2,7 @@ name: buildbot - - on: - push: -- branches: [ Developer ] -+ branches: [ Developer, dm9x0 ] - - workflow_dispatch: - -diff --git a/.github/workflows/enigma2.yml b/.github/workflows/enigma2.yml -index c681dd91b34..c955896a3ff 100644 ---- a/.github/workflows/enigma2.yml -+++ b/.github/workflows/enigma2.yml -@@ -2,12 +2,12 @@ name: Enigma2 Python 3 - - on: - push: -- branches: [ Release, Developer, FCC ] -+ branches: [ Release, Developer, FCC, dm9x0 ] - paths-ignore: - - '**/README' - - '**/DOCS' - pull_request: -- branches: [Release, Developer, FCC ] -+ branches: [Release, Developer, FCC, dm9x0 ] - paths-ignore: - - '**/README' - - '**/DOCS' -diff --git a/CI/build.sh b/CI/build.sh -index e340647b4e3..f58eeae85cd 100755 ---- a/CI/build.sh -+++ b/CI/build.sh -@@ -13,7 +13,7 @@ commit_files() { - rm -rf *.pyc - rm -rf *.pyo - rm -rf *.mo -- git checkout Developer -+ git checkout dm9x0 - ./CI/chmod.sh - ./CI/dos2unix.sh - ./CI/PEP8.sh -@@ -21,7 +21,7 @@ commit_files() { - - upload_files() { - git remote add upstream https://${GITHUB_TOKEN}@github.com/OpenViX/enigma2.git > /dev/null 2>&1 -- git push --quiet upstream Developer || echo "failed to push with error $?" -+ git push --quiet upstream dm9x0 || echo "failed to push with error $?" - } - - setup_git -diff --git a/configure.ac b/configure.ac -index 094c1ff5691..05988050c51 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -91,6 +91,8 @@ AM_CONDITIONAL(DM800, test "$BOXTYPE" == "dm800") - AM_CONDITIONAL(DM8000, test "$BOXTYPE" == "dm8000") - AM_CONDITIONAL(DM800SE, test "$BOXTYPE" == "dm800se") - AM_CONDITIONAL(DM800SEV2, test "$BOXTYPE" == "dm800sev2") -+AM_CONDITIONAL(DM900, test "$BOXTYPE" == "dm900") -+AM_CONDITIONAL(DM920, test "$BOXTYPE" == "dm920") - AM_CONDITIONAL(E3HD, test "$BOXTYPE" == "e3hd") - AM_CONDITIONAL(EBOX5000, test "$BOXTYPE" == "ebox5000") - AM_CONDITIONAL(EBOX5100, test "$BOXTYPE" == "ebox5100") -@@ -306,6 +308,17 @@ if test x"$withcolorlcd220" != xno ; then - fi - AM_CONDITIONAL(HAVE_COLORLCD220, test x"$withcolorlcd220" != xno) - -+AC_ARG_WITH(colorlcd390, -+ AS_HELP_STRING([--with-colorlcd390], [use 390x240 16bpp color display, yes or no]), -+ [[withcolorlcd390=$withval]], -+ [[withcolorlcd390=no]] -+) -+if test x"$withcolorlcd390" != xno ; then -+ AC_DEFINE(HAVE_COLORLCD390, 1,[Define when using a 390x240 color display device]) -+fi -+ -+AM_CONDITIONAL(HAVE_COLORLCD390, test x"$withcolorlcd390" != xno) -+ - AC_ARG_WITH(colorlcd400, - AS_HELP_STRING([--with-colorlcd400], [use 400x176 16bpp color display, yes or no]), - [[withcolorlcd400=$withval]], -@@ -402,6 +415,14 @@ if test `echo "$BOXTYPE" | cut -b 1-2` == "vu"; then - AC_DEFINE(FORCE_ADVANCED_REMOTE, 1,[define to fixup the input device identification when the remote control is actually an 'advanced' remote (with play/forward/rewind keys)]) - fi - -+if test "$BOXTYPE" == "dm900" -o "$BOXTYPE" == "dm920"; then -+ AC_DEFINE(CONFIG_ION, 1,[define BOX use ION Allocator]) -+ AC_DEFINE(HAVE_HDMIIN_DM, 1,[has hdmi in dm]) -+ AC_DEFINE(LCD_DM900_Y_OFFSET, 4,[define LCD Y offset for dm900 and dm920]) -+ AC_DEFINE(DREAMBOX_DUAL_TUNER, 1,[define it is dreambox dual tuner present]) -+ AC_DEFINE(FORCE_NO_BLENDING_ACCELERATION, 1,[define when the framebuffer acceleration does not have alphablending support, though the autodetection might indicate that it does]) -+fi -+ - if test `echo "$BOXTYPE" | cut -b 1-2` == "gb"; then - AC_DEFINE(KEY_PLAY_ACTUALLY_IS_KEY_PLAYPAUSE, 1,[define when rc sends a KEY_PLAY event for its KEY_PLAYPAUSE key]) - AC_DEFINE(FORCE_NO_BLENDING_ACCELERATION, 1,[define when the framebuffer acceleration does not have alphablending support, though the autodetection might indicate that it does]) -@@ -586,6 +607,7 @@ data/7segment/Makefile - data/display96/Makefile - data/display128/Makefile - data/display220/Makefile -+data/display390/Makefile - data/display400/Makefile - data/display480/Makefile - data/display720/Makefile -diff --git a/data/Makefile.am b/data/Makefile.am -index 72c31ec8d3a..123c4f64f6e 100644 ---- a/data/Makefile.am -+++ b/data/Makefile.am -@@ -41,6 +41,10 @@ if HAVE_COLORLCD220 - SUBDIRS += display220 - endif - -+if HAVE_COLORLCD390 -+SUBDIRS += display390 -+endif -+ - if HAVE_COLORLCD400 - SUBDIRS += display400 - endif -diff --git a/data/display400/skin_display.xml b/data/display400/skin_display.xml -index 55d0d8a26e7..6d45e70db6f 100644 ---- a/data/display400/skin_display.xml -+++ b/data/display400/skin_display.xml -@@ -238,24 +238,13 @@ - - - -- -- FullDate -+ -+ ShortDate - -- -+ - Format:%H:%M - -- -- -- -- -- -- -- -- -- -- - -- - - - -diff --git a/interfaces/ion.h b/interfaces/ion.h -new file mode 100644 -index 00000000000..6370495f8d0 ---- /dev/null -+++ b/interfaces/ion.h -@@ -0,0 +1,204 @@ -+/* -+ * drivers/staging/android/uapi/ion.h -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ */ -+ -+#ifndef _UAPI_LINUX_ION_H -+#define _UAPI_LINUX_ION_H -+ -+#include -+#include -+ -+typedef int ion_user_handle_t; -+ -+/** -+ * enum ion_heap_types - list of all possible types of heaps -+ * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc -+ * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc -+ * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved -+ * carveout heap, allocations are physically -+ * contiguous -+ * @ION_HEAP_TYPE_DMA: memory allocated via DMA API -+ * @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask -+ * is used to identify the heaps, so only 32 -+ * total heap types are supported -+ */ -+enum ion_heap_type { -+ ION_HEAP_TYPE_SYSTEM, -+ ION_HEAP_TYPE_SYSTEM_CONTIG, -+ ION_HEAP_TYPE_CARVEOUT, -+ ION_HEAP_TYPE_CHUNK, -+ ION_HEAP_TYPE_DMA, -+ ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always -+ are at the end of this enum */ -+ ION_NUM_HEAPS = 16, -+}; -+ -+#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM) -+#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG) -+#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT) -+#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA) -+ -+#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8 -+ -+/** -+ * allocation flags - the lower 16 bits are used by core ion, the upper 16 -+ * bits are reserved for use by the heaps themselves. -+ */ -+#define ION_FLAG_CACHED 1 /* mappings of this buffer should be -+ cached, ion will do cache -+ maintenance when the buffer is -+ mapped for dma */ -+#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created -+ at mmap time, if this is set -+ caches must be managed manually */ -+ -+/** -+ * DOC: Ion Userspace API -+ * -+ * create a client by opening /dev/ion -+ * most operations handled via following ioctls -+ * -+ */ -+ -+/** -+ * struct ion_allocation_data - metadata passed from userspace for allocations -+ * @len: size of the allocation -+ * @align: required alignment of the allocation -+ * @heap_id_mask: mask of heap ids to allocate from -+ * @flags: flags passed to heap -+ * @handle: pointer that will be populated with a cookie to use to -+ * refer to this allocation -+ * -+ * Provided by userspace as an argument to the ioctl -+ */ -+struct ion_allocation_data { -+ size_t len; -+ size_t align; -+ unsigned int heap_id_mask; -+ unsigned int flags; -+ ion_user_handle_t handle; -+}; -+ -+/** -+ * struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair -+ * @handle: a handle -+ * @fd: a file descriptor representing that handle -+ * -+ * For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with -+ * the handle returned from ion alloc, and the kernel returns the file -+ * descriptor to share or map in the fd field. For ION_IOC_IMPORT, userspace -+ * provides the file descriptor and the kernel returns the handle. -+ */ -+struct ion_fd_data { -+ ion_user_handle_t handle; -+ int fd; -+}; -+ -+/** -+ * struct ion_handle_data - a handle passed to/from the kernel -+ * @handle: a handle -+ */ -+struct ion_handle_data { -+ ion_user_handle_t handle; -+}; -+ -+/** -+ * struct ion_custom_data - metadata passed to/from userspace for a custom ioctl -+ * @cmd: the custom ioctl function to call -+ * @arg: additional data to pass to the custom ioctl, typically a user -+ * pointer to a predefined structure -+ * -+ * This works just like the regular cmd and arg fields of an ioctl. -+ */ -+struct ion_custom_data { -+ unsigned int cmd; -+ unsigned long arg; -+}; -+ -+struct ion_phys_data { -+ ion_user_handle_t handle; -+ unsigned long addr; -+ size_t len; -+}; -+ -+#define ION_IOC_MAGIC 'I' -+ -+/** -+ * DOC: ION_IOC_ALLOC - allocate memory -+ * -+ * Takes an ion_allocation_data struct and returns it with the handle field -+ * populated with the opaque handle for the allocation. -+ */ -+#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ -+ struct ion_allocation_data) -+ -+/** -+ * DOC: ION_IOC_FREE - free memory -+ * -+ * Takes an ion_handle_data struct and frees the handle. -+ */ -+#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) -+ -+/** -+ * DOC: ION_IOC_MAP - get a file descriptor to mmap -+ * -+ * Takes an ion_fd_data struct with the handle field populated with a valid -+ * opaque handle. Returns the struct with the fd field set to a file -+ * descriptor open in the current address space. This file descriptor -+ * can then be used as an argument to mmap. -+ */ -+#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data) -+ -+/** -+ * DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation -+ * -+ * Takes an ion_fd_data struct with the handle field populated with a valid -+ * opaque handle. Returns the struct with the fd field set to a file -+ * descriptor open in the current address space. This file descriptor -+ * can then be passed to another process. The corresponding opaque handle can -+ * be retrieved via ION_IOC_IMPORT. -+ */ -+#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data) -+ -+/** -+ * DOC: ION_IOC_IMPORT - imports a shared file descriptor -+ * -+ * Takes an ion_fd_data struct with the fd field populated with a valid file -+ * descriptor obtained from ION_IOC_SHARE and returns the struct with the handle -+ * filed set to the corresponding opaque handle. -+ */ -+#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data) -+ -+/** -+ * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory -+ * -+ * Deprecated in favor of using the dma_buf api's correctly (syncing -+ * will happend automatically when the buffer is mapped to a device). -+ * If necessary should be used after touching a cached buffer from the cpu, -+ * this will make the buffer in memory coherent. -+ */ -+#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data) -+ -+/** -+ * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl -+ * -+ * Takes the argument of the architecture specific ioctl to call and -+ * passes appropriate userdata for that ioctl -+ */ -+#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data) -+ -+#define ION_IOC_PHYS _IOWR(ION_IOC_MAGIC, 8, struct ion_phys_data) -+ -+#endif /* _UAPI_LINUX_ION_H */ -diff --git a/lib/driver/avswitch.cpp b/lib/driver/avswitch.cpp -index 955c6c59fd7..7d601b56f40 100644 ---- a/lib/driver/avswitch.cpp -+++ b/lib/driver/avswitch.cpp -@@ -255,7 +255,12 @@ int eAVSwitch::getResolutionY(int defaultVal, int flags) const - int eAVSwitch::getFrameRate(int defaultVal, int flags) const - { - -+#ifdef DREAMBOX -+ const char *fileName = "/proc/stb/vmpeg/0/fallback_framerate"; -+#else - const char *fileName = "/proc/stb/vmpeg/0/framerate"; -+#endif -+ - int value = 0; - int ret = CFile::parseInt(&value, fileName, __MODULE__, flags); - if (ret != 0) -diff --git a/lib/dvb/decoder.cpp b/lib/dvb/decoder.cpp -index 95f5609dd9c..4fb21ec1667 100644 ---- a/lib/dvb/decoder.cpp -+++ b/lib/dvb/decoder.cpp -@@ -147,7 +147,11 @@ int eDVBAudio::startPid(int pid, int type) - bypass = 0x40; - break; - case aDDP: -+#ifdef DREAMBOX -+ bypass = 7; -+#else - bypass = 0x22; -+#endif - break; - } - -@@ -341,7 +345,11 @@ eDVBVideo::eDVBVideo(eDVBDemux *demux, int dev, bool fcc_enable) - #define VIDEO_STREAMTYPE_MPEG4_Part2 4 - #define VIDEO_STREAMTYPE_VC1_SM 5 - #define VIDEO_STREAMTYPE_MPEG1 6 -+#ifdef DREAMBOX -+#define VIDEO_STREAMTYPE_H265_HEVC 22 -+#else - #define VIDEO_STREAMTYPE_H265_HEVC 7 -+#endif - #define VIDEO_STREAMTYPE_AVS 16 - #define VIDEO_STREAMTYPE_AVS2 40 - -diff --git a/lib/dvb/fbc.cpp b/lib/dvb/fbc.cpp -index 6d8b06d3cc2..56a4c4f98d3 100644 ---- a/lib/dvb/fbc.cpp -+++ b/lib/dvb/fbc.cpp -@@ -13,6 +13,24 @@ - - int eFBCTunerManager::ReadProcInt(int fe_index, const std::string & entry) - { -+#ifdef DREAMBOX -+ std::string value; -+ std::stringstream path; -+ std::ifstream file; -+ -+ path << "/proc/stb/frontend/" << fe_index << "/" << entry; -+ file.open(path.str().c_str()); -+ -+ if(!file.is_open()) -+ return(-1); -+ -+ file >> value; -+ -+ if(file.bad() || file.fail()) -+ return(-1); -+ eDebug("[eFBCTunerManager::ReadProcInt] val: %s", value.c_str()); -+ return(value == "A" ? 0 : 1); -+#else - int value; - std::stringstream path; - std::ifstream file; -@@ -29,6 +47,7 @@ int eFBCTunerManager::ReadProcInt(int fe_index, const std::string & entry) - return(-1); - - return(value); -+#endif - } - - void eFBCTunerManager::WriteProcInt(int fe_index, const std::string & entry, int value) -@@ -45,6 +64,41 @@ void eFBCTunerManager::WriteProcInt(int fe_index, const std::string & entry, int - file << value; - } - -+void eFBCTunerManager::WriteProcStr(int fe_index, const std::string & entry, int value) -+{ -+ std::stringstream path; -+ std::ofstream file; -+ -+ path << "/proc/stb/frontend/" << fe_index << "/" << entry; -+ file.open(path.str().c_str()); -+ -+ if(!file.is_open()) -+ return; -+ eDebug("[eFBCTunerManager::WriteProcStr] val: %d", value); -+ file << (value == 0 ? "A" : "B"); -+} -+ -+#ifdef DREAMBOX -+void eFBCTunerManager::LoadConnectChoices(int fe_index, std::string &choices) -+{ -+ std::stringstream path; -+ std::ifstream file; -+ std::string line; -+ std::string::const_iterator it; -+ int fbc_id; -+ -+ path << "/proc/stb/frontend/" << fe_index << "/input_choices"; -+ file.open(path.str().c_str()); -+ -+ if(!file.is_open()) -+ return; -+ -+ file >> choices; -+ -+ if(file.bad() || file.fail()) -+ return; -+} -+#else - void eFBCTunerManager::LoadConnectChoices(int fe_index, connect_choices_t &choices) - { - std::stringstream path; -@@ -77,6 +131,7 @@ void eFBCTunerManager::LoadConnectChoices(int fe_index, connect_choices_t &choic - } - } - } -+#endif - - DEFINE_REF(eFBCTunerManager); - -@@ -93,7 +148,7 @@ eFBCTunerManager::eFBCTunerManager(ePtr res_mgr) - eSmartPtrList &frontends = m_res_mgr->m_frontend; - eSmartPtrList &frontends_simulate = m_res_mgr->m_simulate_frontend; - tuner_t tuner; -- int fe_id, fbc_prev_set_id; -+ int fe_id, fbc_prev_set_id; - - if(!m_instance) - m_instance = this; -@@ -109,22 +164,34 @@ eFBCTunerManager::eFBCTunerManager(ePtr res_mgr) - continue; // ignore DVB-C/T FBC tuners because they need no special treatment - - fe_id = FESlotID(it); -- tuner.set_id = ReadProcInt(fe_id, "fbc_set_id"); - -+#ifdef DREAMBOX -+ tuner.set_id = ReadProcInt(fe_id, "input"); -+#else -+ tuner.set_id = ReadProcInt(fe_id, "fbc_set_id"); -+#endif - if(tuner.set_id >= 0) - { - if(fbc_prev_set_id != tuner.set_id) - { - fbc_prev_set_id = tuner.set_id; -+#ifdef DREAMBOX -+ LoadConnectChoices(fe_id, tuner.input_choices); -+#else - LoadConnectChoices(fe_id, tuner.connect_choices); -+#endif - tuner.id = 0; - } -- -+#ifdef DREAMBOX -+ tuner.is_root = tuner.id < 2; -+#else - if(tuner.id < (int)tuner.connect_choices.size()) - tuner.is_root = tuner.connect_choices.test(tuner.id); - else - tuner.is_root = false; - -+#endif -+ - tuner.default_id = tuner.is_root ? tuner.id : 0; - m_tuners[fe_id] = tuner; - SetProcFBCID(fe_id, tuner.default_id, false); -@@ -141,8 +208,14 @@ eFBCTunerManager::eFBCTunerManager(ePtr res_mgr) - if (!(it->m_frontend->supportsDeliverySystem(SYS_DVBS, false) || it->m_frontend->supportsDeliverySystem(SYS_DVBS2, false))) - continue; - -+#ifdef DREAMBOX -+ if(ReadProcInt(FESlotID(it), "input") >= 0) -+ it->m_frontend->set_FBCTuner(true); -+#else - if(ReadProcInt(FESlotID(it), "fbc_set_id") >= 0) - it->m_frontend->set_FBCTuner(true); -+#endif -+ - } - } - -@@ -154,8 +227,12 @@ eFBCTunerManager::~eFBCTunerManager() - - void eFBCTunerManager::SetProcFBCID(int fe_id, int fbc_connect, bool fbc_is_linked) - { -+#ifdef DREAMBOX -+ WriteProcStr(fe_id, "input", fbc_connect); -+#else - WriteProcInt(fe_id, "fbc_connect", fbc_connect); - WriteProcInt(fe_id, "fbc_link", fbc_is_linked ? 1 : 0); -+#endif - } - - int eFBCTunerManager::FESlotID(eDVBRegisteredFrontend *fe) -@@ -412,7 +489,7 @@ int eFBCTunerManager::IsCompatibleWith(ePtr &feparm, eDV - - if(IsSCR(*it)) - continue; -- -+ - // temporarily add this leaf to the current "linked" chain, at the tail - - fe_insert_point = GetTail(*it); -diff --git a/lib/dvb/fbc.h b/lib/dvb/fbc.h -index a479961086a..b70f9b7dfc9 100644 ---- a/lib/dvb/fbc.h -+++ b/lib/dvb/fbc.h -@@ -25,6 +25,7 @@ private: - int id; - int default_id; - connect_choices_t connect_choices; -+ std::string input_choices; - } tuner_t; - - typedef std::map tuners_t; -@@ -42,7 +43,12 @@ private: - - static int ReadProcInt(int, const std::string &); - static void WriteProcInt(int, const std::string &, int); -+ static void WriteProcStr(int, const std::string &, int); -+#ifdef DREAMBOX -+ static void LoadConnectChoices(int, std::string &); -+#else - static void LoadConnectChoices(int, connect_choices_t &); -+#endif - static void SetProcFBCID(int, int, bool); - static int FESlotID(eDVBRegisteredFrontend *); - static bool IsLinked(eDVBRegisteredFrontend *); -diff --git a/lib/dvb_ci/dvbci.cpp b/lib/dvb_ci/dvbci.cpp -index a4681b1ff39..a744ae6a70b 100644 ---- a/lib/dvb_ci/dvbci.cpp -+++ b/lib/dvb_ci/dvbci.cpp -@@ -6,6 +6,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -33,6 +34,78 @@ eDVBCIInterfaces *eDVBCIInterfaces::instance = 0; - pthread_mutex_t eDVBCIInterfaces::m_pmt_handler_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; - pthread_mutex_t eDVBCIInterfaces::m_slot_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; - -+static char* readInputCI(int NimNumber) -+{ -+ char id1[] = "NIM Socket"; -+ char id2[] = "Input_Name"; -+ char keys1[] = "1234567890"; -+ char keys2[] = "12ABCDabcd"; -+ char *inputName = 0; -+ char buf[256]; -+ FILE *f; -+ -+ f = fopen("/proc/bus/nim_sockets", "rt"); -+ if (f) -+ { -+ while (fgets(buf, sizeof(buf), f)) -+ { -+ char *p = strcasestr(buf, id1); -+ if (!p) -+ continue; -+ -+ p += strlen(id1); -+ p += strcspn(p, keys1); -+ if (*p && strtol(p, 0, 0) == NimNumber) -+ break; -+ } -+ -+ while (fgets(buf, sizeof(buf), f)) -+ { -+ if (strcasestr(buf, id1)) -+ break; -+ -+ char *p = strcasestr(buf, id2); -+ if (!p) -+ continue; -+ -+ p = strchr(p + strlen(id2), ':'); -+ if (!p) -+ continue; -+ -+ p++; -+ p += strcspn(p, keys2); -+ size_t len = strspn(p, keys2); -+ if (len > 0) -+ { -+ inputName = strndup(p, len); -+ break; -+ } -+ } -+ -+ fclose(f); -+ } -+ -+ return inputName; -+} -+ -+static std::string getTunerLetterDM(int NimNumber) -+{ -+ char *srcCI = readInputCI(NimNumber); -+ if (srcCI) { -+ std::string ret = std::string(srcCI); -+ free(srcCI); -+ if (ret.size() == 1){ -+ int corr = 1; -+ if (NimNumber > 7) { -+ corr = -7; -+ } -+ return ret + std::to_string(NimNumber + corr); -+ } -+ return ret; -+ } -+ return eDVBCISlot::getTunerLetter(NimNumber); -+} -+ - eDVBCIInterfaces::eDVBCIInterfaces() - : m_messagepump_thread(this,1, "dvbci"), m_messagepump_main(eApp,1, "dvbci"), m_runTimer(eTimer::create(this)) - { -@@ -69,7 +142,11 @@ eDVBCIInterfaces::eDVBCIInterfaces() - } - - for (eSmartPtrList::iterator it(m_slots.begin()); it != m_slots.end(); ++it) -+#ifdef DREAMBOX_DUAL_TUNER -+ it->setSource(getTunerLetterDM(0)); -+#else - it->setSource("A"); -+#endif - - for (int tuner_no = 0; tuner_no < 26; ++tuner_no) // NOTE: this assumes tuners are A .. Z max. - { -@@ -80,7 +157,11 @@ eDVBCIInterfaces::eDVBCIInterfaces() - if(::access(path.str().c_str(), R_OK) < 0) - break; - -+#ifdef DREAMBOX_DUAL_TUNER -+ setInputSource(tuner_no, getTunerLetterDM(tuner_no)); -+#else - setInputSource(tuner_no, eDVBCISlot::getTunerLetter(tuner_no)); -+#endif - } - - eDebug("[CI] done, found %d common interface slots", num_ci); -@@ -310,7 +391,11 @@ void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot) - if (slot->linked_next) - slot->linked_next->setSource(slot->current_source); - else // last CI in chain -+#ifdef DREAMBOX_DUAL_TUNER -+ setInputSource(slot->current_tuner, getTunerLetterDM(slot->current_tuner)); -+#else - setInputSource(slot->current_tuner, eDVBCISlot::getTunerLetter(slot->current_tuner)); -+#endif - slot->linked_next = 0; - slot->use_count=0; - slot->plugged=true; -@@ -581,7 +666,11 @@ void eDVBCIInterfaces::recheckPMTHandlers() - if (tunernum != -1) - { - setInputSource(tunernum, ci_source.str()); -+#ifdef DREAMBOX_DUAL_TUNER -+ ci_it->setSource(getTunerLetterDM(tunernum)); -+#else - ci_it->setSource(eDVBCISlot::getTunerLetter(tunernum)); -+#endif - } - else - { -@@ -711,7 +800,11 @@ void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) - { - case finish_use_tuner_a: - { -+#ifdef DREAMBOX_DUAL_TUNER -+ finish_source = getTunerLetterDM(0); -+#else - finish_source = "A"; -+#endif - break; - } - -@@ -734,7 +827,11 @@ void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) - if(finish_source == "") - { - eDebug("[CI] warning: CI streaming finish mode not set, assuming \"tuner A\""); -+#ifdef DREAMBOX_DUAL_TUNER -+ finish_source = getTunerLetterDM(0); -+#else - finish_source = "A"; -+#endif - } - - slot->setSource(finish_source); -@@ -746,7 +843,11 @@ void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) - if (slot->linked_next) - slot->linked_next->setSource(slot->current_source); - else -+#ifdef DREAMBOX_DUAL_TUNER -+ setInputSource(slot->current_tuner, getTunerLetterDM(slot->current_tuner)); -+#else - setInputSource(slot->current_tuner, eDVBCISlot::getTunerLetter(slot->current_tuner)); -+#endif - - if (base_slot != slot) - { -@@ -1134,7 +1235,11 @@ void eDVBCIInterfaces::setCIPlusRouting(int slotid) - new_input_source << "CI" << slot->getSlotID(); - - setInputSource(tunernum, new_input_source.str()); -+#ifdef DREAMBOX_DUAL_TUNER -+ slot->setSource(getTunerLetterDM(tunernum)); -+#else - slot->setSource(eDVBCISlot::getTunerLetter(tunernum)); -+#endif - - slot->setCIPlusRoutingParameter(tunernum, ciplus_routing_input, ciplus_routing_ci_input); - eDebug("[CI] CIRouting active slotid=%d tuner=%d old_input=%s old_ci_input=%s", slotid, tunernum, ciplus_routing_input.c_str(), ciplus_routing_ci_input.c_str()); -diff --git a/lib/dvb_ci/dvbci.h b/lib/dvb_ci/dvbci.h -index 511944b9770..5d11f624b45 100644 ---- a/lib/dvb_ci/dvbci.h -+++ b/lib/dvb_ci/dvbci.h -@@ -110,8 +110,8 @@ class eDVBCISlot: public iObject, public sigc::trackable - int setClockRate(const std::string &rate); - void determineCIVersion(); - int setEnabled(bool); -- static std::string getTunerLetter(int tuner_no) { return std::string(1, char(65 + tuner_no)); } - public: -+ static std::string getTunerLetter(int tuner_no) { return std::string(1, char(65 + tuner_no)); } - enum {stateRemoved, stateInserted, stateInvalid, stateResetted, stateDisabled}; - enum {versionUnknown = -1, versionCI = 0, versionCIPlus1 = 1, versionCIPlus2 = 2}; - eDVBCISlot(eMainloop *context, int nr); -diff --git a/lib/gdi/epng.cpp b/lib/gdi/epng.cpp -index 449ccc9c14e..8745975b723 100644 ---- a/lib/gdi/epng.cpp -+++ b/lib/gdi/epng.cpp -@@ -3,10 +3,15 @@ - #include - #include - #include --#include -+#include - #include - #include - #include -+#include -+ -+#include -+#include -+#include - - extern "C" { - #include -@@ -123,7 +128,7 @@ int loadPNG(ePtr &result, const char *filename, int accel, int cached) - - result = new gPixmap(width, height, bit_depth * channels, cached ? PixmapCache::PixmapDisposed : NULL, accel); - gUnmanagedSurface *surface = result->surface; -- -+ - png_bytep *rowptr = new png_bytep[height]; - for (unsigned int i = 0; i < height; i++) - rowptr[i] = ((png_byte*)(surface->data)) + i * surface->stride; -@@ -131,6 +136,18 @@ int loadPNG(ePtr &result, const char *filename, int accel, int cached) - - delete [] rowptr; - -+ if (color_type == PNG_COLOR_TYPE_RGBA || color_type == PNG_COLOR_TYPE_GA) -+ surface->transparent = true; -+ else -+ { -+ png_bytep trans_alpha = NULL; -+ int num_trans = 0; -+ png_color_16p trans_color = NULL; -+ -+ png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color); -+ surface->transparent = (trans_alpha != NULL); -+ } -+ - int num_palette = -1, num_trans = -1; - if (color_type == PNG_COLOR_TYPE_PALETTE) { - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) { -@@ -204,8 +221,8 @@ int loadJPG(ePtr &result, const char *filename, ePtr alpha, in - if (cached && (result = PixmapCache::Get(filename))) - return 0; - -- struct jpeg_decompress_struct cinfo = {}; -- struct my_error_mgr jerr = {}; -+ struct jpeg_decompress_struct cinfo; -+ struct my_error_mgr jerr; - JSAMPARRAY buffer; - int row_stride; - CFile infile(filename, "rb"); -@@ -248,13 +265,13 @@ int loadJPG(ePtr &result, const char *filename, ePtr alpha, in - } - if (grayscale) - { -- eWarning("[loadJPG] no support for grayscale + alpha at the moment"); -+ eWarning("[loadJPG] we don't support grayscale + alpha at the moment"); - alpha = 0; - } - } - - result = new gPixmap(cinfo.output_width, cinfo.output_height, grayscale ? 8 : 32, cached ? PixmapCache::PixmapDisposed : NULL); -- -+ result->surface->transparent = false; - row_stride = cinfo.output_width * cinfo.output_components; - buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); - while (cinfo.output_scanline < cinfo.output_height) { -@@ -480,14 +497,12 @@ int loadImage(ePtr &result, const char *filename, int accel, int width, - return loadSVG(result, filename, cached == -1 ? 1 : cached, width, height, scale, keepAspect, align); - else if (endsWith(filename, ".jpg")) - return loadJPG(result, filename, cached == -1 ? 0 : cached); -- - return 0; - } - - int savePNG(const char *filename, gPixmap *pixmap) - { - int result; -- - { - eDebug("[ePNG] saving to %s",filename); - CFile fp(filename, "wb"); -diff --git a/lib/gdi/fb.cpp b/lib/gdi/fb.cpp -index 66c1e5e56a8..99b7f599ed0 100644 ---- a/lib/gdi/fb.cpp -+++ b/lib/gdi/fb.cpp -@@ -13,9 +13,19 @@ - #define FBIO_WAITFORVSYNC _IOW('F', 0x20, uint32_t) - #endif - --#ifndef FBIO_BLIT -+#ifdef CONFIG_ION -+ -+#include -+#include -+#define ION_HEAP_TYPE_BMEM (ION_HEAP_TYPE_CUSTOM + 1) -+#define ION_HEAP_ID_MASK (1 << ION_HEAP_TYPE_BMEM) -+#define ACCEL_MEM_SIZE (32*1024*1024) -+ -+#elif !defined(FBIO_BLIT) -+ - #define FBIO_SET_MANUAL_BLIT _IOW('F', 0x21, __u8) - #define FBIO_BLIT 0x22 -+ - #endif - - fbClass *fbClass::instance; -@@ -38,6 +48,10 @@ fbClass::fbClass(const char *fb) - cmap.green=green; - cmap.blue=blue; - cmap.transp=trans; -+ -+#ifdef CONFIG_ION -+ int ion; -+#endif - - fbFd=open(fb, O_RDWR); - if (fbFd<0) -@@ -60,15 +74,96 @@ fbClass::fbClass(const char *fb) - goto nolfb; - } - -- available=fix.smem_len; -+ available = fix.smem_len; - m_phys_mem = fix.smem_start; - eDebug("[fb] %s: %dk video mem", fb, available/1024); -+#if defined(CONFIG_ION) -+ /* allocate accel memory here... its independent from the framebuffer */ -+ ion = open("/dev/ion", O_RDWR | O_CLOEXEC); -+ if (ion >= 0) -+ { -+ struct ion_allocation_data alloc_data; -+ struct ion_fd_data share_data; -+ struct ion_handle_data free_data; -+ struct ion_phys_data phys_data; -+ int ret; -+ unsigned char *lion; -+ -+ eDebug("[fb] Using ION allocator"); -+ -+ memset(&alloc_data, 0, sizeof(alloc_data)); -+ alloc_data.len = ACCEL_MEM_SIZE; -+ alloc_data.align = 4096; // 4k aligned -+ alloc_data.heap_id_mask = ION_HEAP_ID_MASK; -+ ret = ioctl(ion, ION_IOC_ALLOC, &alloc_data); -+ if (ret < 0) -+ { -+ eDebug("[fb] ION_IOC_ALLOC failed"); -+ eFatal("[fb] failed to allocate accel memory!!!"); -+ return; -+ } -+ -+ memset(&phys_data, 0, sizeof(phys_data)); -+ phys_data.handle = alloc_data.handle; -+ ret = ioctl(ion, ION_IOC_PHYS, &phys_data); -+ if (ret < 0) -+ { -+ eDebug("[fb] ION_IOC_PHYS failed"); -+ goto err_ioc_free; -+ } -+ -+ memset(&share_data, 0, sizeof(share_data)); -+ share_data.handle = alloc_data.handle; -+ ret = ioctl(ion, ION_IOC_SHARE, &share_data); -+ if (ret < 0) -+ { -+ eDebug("[fb] ION_IOC_SHARE failed"); -+ goto err_ioc_free; -+ } -+ -+ memset(&free_data, 0, sizeof(free_data)); -+ free_data.handle = alloc_data.handle; -+ if (ioctl(ion, ION_IOC_FREE, &free_data) < 0) -+ eDebug("[fb] ION_IOC_FREE failed"); -+ -+ m_accel_fd = share_data.fd; -+ lion=(unsigned char*)mmap(0, ACCEL_MEM_SIZE, PROT_WRITE|PROT_READ, MAP_SHARED, share_data.fd, 0); -+ -+ if (lion) -+ { -+ eDebug("[fb] %dkB available for acceleration surfaces (via ION).", ACCEL_MEM_SIZE / 1024); -+ gAccel::getInstance()->setAccelMemorySpace(lion, phys_data.addr, ACCEL_MEM_SIZE); -+ } -+ else -+ { -+ close(m_accel_fd); -+ eDebug("[fb] mmap lion failed"); -+err_ioc_free: -+ eFatal("[fb] failed to allocate accel memory via ION!!!"); -+ m_accel_fd = -1; -+ memset(&free_data, 0, sizeof(free_data)); -+ free_data.handle = alloc_data.handle; -+ if (ioctl(ion, ION_IOC_FREE, &free_data) < 0) -+ eDebug("[fb] ION_IOC_FREE %m"); -+ } -+ close(ion); -+ } -+ else -+ { -+ eFatal("[fb] failed to open ION device node! no allocate accel memory available !!"); -+ m_accel_fd = -1; -+ } -+#else -+ eDebug("[fb] %dk video mem", available/1024); - lfb=(unsigned char*)mmap(0, available, PROT_WRITE|PROT_READ, MAP_SHARED, fbFd, 0); -+#endif -+#ifndef CONFIG_ION - if (!lfb) - { -- eDebug("[fb] mmap: %m"); -+ eDebug("[fb] mmap %m"); - goto nolfb; - } -+#endif - - showConsole(0); - -@@ -80,7 +175,7 @@ nolfb: - ::close(fbFd); - fbFd = -1; - } -- eDebug("[fb] framebuffer %s not available", fb); -+ eDebug("[fb] framebuffer not available"); - return; - } - -@@ -101,6 +196,12 @@ int fbClass::showConsole(int state) - int fbClass::SetMode(int nxRes, int nyRes, int nbpp) - { - if (fbFd < 0) return -1; -+#ifdef CONFIG_ION -+ /* unmap old framebuffer with old size */ -+ if (lfb) -+ munmap(lfb, stride * screeninfo.yres_virtual); -+#endif -+ - screeninfo.xres_virtual=screeninfo.xres=nxRes; - screeninfo.yres_virtual=(screeninfo.yres=nyRes)*2; - screeninfo.height=0; -@@ -140,7 +241,7 @@ int fbClass::SetMode(int nxRes, int nyRes, int nbpp) - - if (ioctl(fbFd, FBIOPUT_VSCREENINFO, &screeninfo)<0) - { -- eDebug("[fb] FBIOPUT_VSCREENINFO: %m"); -+ eDebug("[fb] FBIOPUT_VSCREENINFO %m"); - return -1; - } - eDebug("[fb] double buffering not available."); -@@ -148,7 +249,7 @@ int fbClass::SetMode(int nxRes, int nyRes, int nbpp) - eDebug("[fb] double buffering available!"); - - m_number_of_pages = screeninfo.yres_virtual / nyRes; -- -+ - ioctl(fbFd, FBIOGET_VSCREENINFO, &screeninfo); - - if ((screeninfo.xres != (unsigned int)nxRes) || (screeninfo.yres != (unsigned int)nyRes) || -@@ -164,9 +265,17 @@ int fbClass::SetMode(int nxRes, int nyRes, int nbpp) - fb_fix_screeninfo fix; - if (ioctl(fbFd, FBIOGET_FSCREENINFO, &fix)<0) - { -- eDebug("[fb] FBIOGET_FSCREENINFO: %m"); -+ eDebug("[fb] FBIOGET_FSCREENINFO %m"); - } - stride=fix.line_length; -+ -+#ifdef CONFIG_ION -+ m_phys_mem = fix.smem_start; -+ available = fix.smem_len; -+ /* map new framebuffer */ -+ lfb=(unsigned char*)mmap(0, stride * screeninfo.yres_virtual, PROT_WRITE|PROT_READ, MAP_SHARED, fbFd, 0); -+#endif -+ - memset(lfb, 0, stride*yRes); - blit(); - return 0; -@@ -197,14 +306,20 @@ int fbClass::waitVSync() - void fbClass::blit() - { - if (fbFd < 0) return; -+#if !defined(CONFIG_ION) - if (m_manual_blit == 1) { - if (ioctl(fbFd, FBIO_BLIT) < 0) -- eDebug("[fb] FBIO_BLIT: %m"); -+ eDebug("[fb] FBIO_BLIT %m"); - } -+#endif - } - - fbClass::~fbClass() - { -+#ifdef CONFIG_ION -+ if (m_accel_fd > -1) -+ close(m_accel_fd); -+#endif - if (lfb) - { - msync(lfb, available, MS_SYNC); -@@ -252,21 +367,26 @@ void fbClass::unlock() - - void fbClass::enableManualBlit() - { -- unsigned char tmp = 1; - if (fbFd < 0) return; -+#ifndef CONFIG_ION -+ unsigned char tmp = 1; - if (ioctl(fbFd,FBIO_SET_MANUAL_BLIT, &tmp)<0) -- eDebug("[fb] enable FBIO_SET_MANUAL_BLIT: %m"); -+ eDebug("[fb] FBIO_SET_MANUAL_BLIT %m"); - else - m_manual_blit = 1; -+#endif - } - - void fbClass::disableManualBlit() - { -+#ifndef CONFIG_ION - unsigned char tmp = 0; - if (fbFd < 0) return; - if (ioctl(fbFd,FBIO_SET_MANUAL_BLIT, &tmp)<0) -- eDebug("[fb] disable FBIO_SET_MANUAL_BLIT: %m"); -+ eDebug("[fb] FBIO_SET_MANUAL_BLIT %m"); - else - m_manual_blit = 0; -+#endif - } - -+ -diff --git a/lib/gdi/fb.h b/lib/gdi/fb.h -index 0eb04915dce..6656dd84c57 100644 ---- a/lib/gdi/fb.h -+++ b/lib/gdi/fb.h -@@ -29,6 +29,9 @@ public: - #else - public: - unsigned char *lfb; -+#ifdef CONFIG_ION -+ int m_accel_fd; -+#endif - void enableManualBlit(); - void disableManualBlit(); - int showConsole(int state); -diff --git a/lib/gdi/gfbdc.cpp b/lib/gdi/gfbdc.cpp -index 19964401458..ffaf9873c4e 100644 ---- a/lib/gdi/gfbdc.cpp -+++ b/lib/gdi/gfbdc.cpp -@@ -15,7 +15,7 @@ - #include - #endif - --#if defined(CONFIG_HISILICON_FB) -+#if defined(CONFIG_ION) || defined(CONFIG_HISILICON_FB) - #include - - extern void bcm_accel_blit( -@@ -25,17 +25,18 @@ extern void bcm_accel_blit( - int dst_x, int dst_y, int dwidth, int dheight, - int pal_addr, int flags); - #endif -- - #ifdef HAVE_HISILICON_ACCEL - extern void dinobot_accel_register(void *p1,void *p2); - extern void dinibot_accel_notify(void); - #endif -+ - gFBDC::gFBDC() - { - fb=new fbClass; -- -+#ifndef CONFIG_ION - if (!fb->Available()) - eFatal("[gFBDC] no framebuffer available"); -+#endif - - int xres; - int yres; -@@ -171,9 +172,34 @@ void gFBDC::exec(const gOpcode *o) - gles_do_animation(); - else - fb->blit(); -+ gles_flush(); - #else - fb->blit(); - #endif -+#ifdef CONFIG_ION -+ if (surface_back.data_phys) -+ { -+ gUnmanagedSurface s(surface); -+ surface = surface_back; -+ surface_back = s; -+ -+ fb->waitVSync(); -+ if (surface.data_phys > surface_back.data_phys) -+ { -+ fb->setOffset(0); -+ } -+ else -+ { -+ fb->setOffset(surface_back.y); -+ } -+ bcm_accel_blit( -+ surface_back.data_phys, surface_back.x, surface_back.y, surface_back.stride, 0, -+ surface.data_phys, surface.x, surface.y, surface.stride, -+ 0, 0, surface.x, surface.y, -+ 0, 0, surface.x, surface.y, -+ 0, 0); -+ } -+#endif - #if defined(CONFIG_HISILICON_FB) - if(islocked()==0) - { -@@ -198,7 +224,7 @@ void gFBDC::exec(const gOpcode *o) - gles_set_buffer((unsigned int *)surface.data); - gles_set_animation(1, o->parm.setShowHideInfo->point.x(), o->parm.setShowHideInfo->point.y(), o->parm.setShowHideInfo->size.width(), o->parm.setShowHideInfo->size.height()); - #endif -- break; -+ break; - } - case gOpcode::sendHide: - { -@@ -209,16 +235,28 @@ void gFBDC::exec(const gOpcode *o) - gles_set_buffer((unsigned int *)surface.data); - gles_set_animation(0, o->parm.setShowHideInfo->point.x(), o->parm.setShowHideInfo->point.y(), o->parm.setShowHideInfo->size.width(), o->parm.setShowHideInfo->size.height()); - #endif -- break; -+ break; - } - #ifdef USE_LIBVUGLES2 -+ case gOpcode::sendShowItem: -+ { -+ gles_set_buffer((unsigned int *)surface.data); -+ gles_set_animation_listbox(o->parm.setShowItemInfo->dir, o->parm.setShowItemInfo->point.x(), o->parm.setShowItemInfo->point.y(), o->parm.setShowItemInfo->size.width(), o->parm.setShowItemInfo->size.height()); -+ delete o->parm.setShowItemInfo; -+ break; -+ } -+ case gOpcode::setFlush: -+ { -+ gles_set_flush(o->parm.setFlush->enable); -+ delete o->parm.setFlush; -+ break; -+ } - case gOpcode::setView: - { - gles_viewport(o->parm.setViewInfo->size.width(), o->parm.setViewInfo->size.height(), fb->Stride()); -- break; -+ break; - } - #endif -- - default: - gDC::exec(o); - break; -@@ -257,10 +295,14 @@ void gFBDC::setResolution(int xres, int yres, int bpp) - #endif - ) - return; -- -+#ifndef CONFIG_ION - if (gAccel::getInstance()) - gAccel::getInstance()->releaseAccelMemorySpace(); -- -+#else -+ gRC *grc = gRC::getInstance(); -+ if (grc) -+ grc->lock(); -+#endif - fb->SetMode(xres, yres, bpp); - - surface.x = xres; -@@ -290,12 +332,14 @@ void gFBDC::setResolution(int xres, int yres, int bpp) - surface_back.data_phys = 0; - } - -- eDebug("[gFBDC] resolution: %dx%dx%d stride=%d, %dkB available for acceleration surfaces.", -- surface.x, surface.y, surface.bpp, fb->Stride(), (fb->Available() - fb_size)/1024); -+ eDebug("[gFBDC] resolution: %d x %d x %d (stride: %d) pages: %d", surface.x, surface.y, surface.bpp, fb->Stride(), fb->getNumPages()); - -+#ifndef CONFIG_ION -+ /* accel is already set in fb.cpp */ -+ eDebug("[gFBDC] %dkB available for acceleration surfaces.", (fb->Available() - fb_size)/1024); - if (gAccel::getInstance()) - gAccel::getInstance()->setAccelMemorySpace(fb->lfb + fb_size, surface.data_phys + fb_size, fb->Available() - fb_size); -- -+#endif - #ifdef HAVE_HISILICON_ACCEL - dinobot_accel_register(&surface,&surface_back); - #endif -@@ -318,6 +362,11 @@ void gFBDC::setResolution(int xres, int yres, int bpp) - #endif - - m_pixmap = new gPixmap(&surface); -+ -+#ifdef CONFIG_ION -+ if (grc) -+ grc->unlock(); -+#endif - } - - void gFBDC::saveSettings() -diff --git a/lib/gdi/grc.h b/lib/gdi/grc.h -index 2c218c56167..c2df1bb42f5 100644 ---- a/lib/gdi/grc.h -+++ b/lib/gdi/grc.h -@@ -259,6 +259,11 @@ public: - virtual ~gRC(); - - void submit(const gOpcode &o); -+ -+#ifdef CONFIG_ION -+ void lock(); -+ void unlock(); -+#endif - - sigc::signal notify; - -diff --git a/lib/gdi/lcd.cpp b/lib/gdi/lcd.cpp -index f86e2d644f3..1b39b34407a 100644 ---- a/lib/gdi/lcd.cpp -+++ b/lib/gdi/lcd.cpp -@@ -30,10 +30,13 @@ eLCD *eLCD::getInstance() - - void eLCD::setSize(int xres, int yres, int bpp) - { -+ _stride = xres * bpp / 8; -+ _buffer = new unsigned char[xres * yres * bpp / 8]; -+#ifdef LCD_DM900_Y_OFFSET -+ xres -= LCD_DM900_Y_OFFSET; -+#endif - res = eSize(xres, yres); -- _buffer = new unsigned char[xres * yres * bpp/8]; -- memset(_buffer, 0, res.height() * res.width() * bpp / 8); -- _stride = res.width() * bpp / 8; -+ memset(_buffer, 0, xres * yres * bpp / 8); - eDebug("[eLCD] (%dx%dx%d) buffer %p %d bytes, stride %d", xres, yres, bpp, _buffer, xres * yres * bpp / 8, _stride); - } - -@@ -399,7 +402,20 @@ void eDBoxLCD::update() - } - else - { -+#if defined(LCD_DM900_Y_OFFSET) -+ unsigned char gb_buffer[_stride * res.height()]; -+ for (int offset = 0; offset < ((_stride * res.height()) >> 2); offset++) -+ { -+ unsigned int src = 0; -+ if (offset % (_stride >> 2) >= LCD_DM900_Y_OFFSET) -+ src = ((unsigned int *)_buffer)[offset - LCD_DM900_Y_OFFSET]; -+ // blue red green low green high -+ ((unsigned int *)gb_buffer)[offset] = ((src >> 3) & 0x001F001F) | ((src << 3) & 0xF800F800) | ((src >> 8) & 0x00E000E0) | ((src << 8) & 0x07000700); -+ } -+ write(lcdfd, gb_buffer, _stride * res.height()); -+#else - write(lcdfd, _buffer, _stride * res.height()); -+#endif - } - } - else /* lcd_type == 1 */ -@@ -437,4 +453,4 @@ void eDBoxLCD::update() - void eDBoxLCD::dumpLCD(bool png) - { - return; --} -+} -\ No newline at end of file -diff --git a/lib/python/Components/AVSwitch.py b/lib/python/Components/AVSwitch.py -index 3b3228792f3..18a40f551fc 100644 ---- a/lib/python/Components/AVSwitch.py -+++ b/lib/python/Components/AVSwitch.py -@@ -44,6 +44,12 @@ class AVSwitch: - "multi": {50: "2160p50", 60: "2160p"}, - "auto": {50: "2160p50", 60: "2160p", 24: "2160p24"}} - -+ if SystemInfo["boxtype"] in ("dm900", "dm920"): -+ rates["2160p"] = {"50Hz": {50: "2160p50"}, -+ "60Hz": {60: "2160p60"}, -+ "multi": {50: "2160p50", 60: "2160p60"}, -+ "auto": {50: "2160p50", 60: "2160p60", 24: "2160p24"}} -+ - rates["PC"] = { - "1024x768": {60: "1024x768"}, # not possible on DM7025 - "800x600": {60: "800x600"}, # also not possible -@@ -107,7 +113,6 @@ class AVSwitch: - self.on_hotplug("HDMI") # Must be HDMI. - - # Check if a high-level mode with a given rate is available. -- # - def isModeAvailable(self, port, mode, rate): - rateNew = self.rates[mode][rate] - for modeNew in rateNew.values(): -@@ -222,7 +227,7 @@ class AVSwitch: - ratelist = [] - for rate in rates: - if rate == "auto": -- if SystemInfo["Has24hz"]: -+ if SystemInfo["Has24hz"] or SystemInfo["boxtype"] in ("dm900", "dm920"): - ratelist.append((rate, mode == "2160p30" and "auto (25Hz/30Hz/24Hz)" or "auto (50Hz/60Hz/24Hz)")) - else: - ratelist.append((rate, rate == "multi" and (mode == "2160p30" and "multi (25Hz/30Hz)" or "multi (50Hz/60Hz)") or rate)) -@@ -270,8 +275,11 @@ class AVSwitch: - else: - wss = "auto" - print(f"[AVSwitch] setting wss:{wss} configElement.value:{configElement.value}") -- with open("/proc/stb/denc/0/wss", "w") as fd: -- fd.write(wss) -+ try: -+ with open("/proc/stb/denc/0/wss", "w") as fd: -+ fd.write(wss) -+ except (IOError, OSError): -+ pass - - def setPolicy43(self, configElement): - print(f"[AVSwitch] setting policy43:{configElement.value}") -@@ -634,6 +642,7 @@ def InitAVSwitch(): - config.av.autovolume.addNotifier(setAutoVolume) - else: - config.av.autovolume = ConfigNothing() -+ - if SystemInfo["supportPcmMultichannel"]: - def setPCMMultichannel(configElement): - open(SystemInfo["supportPcmMultichannel"], "w").write(configElement.value and "enable" or "disable") -diff --git a/lib/python/Components/About.py b/lib/python/Components/About.py -index bf5a28f805a..a81a96484a3 100644 ---- a/lib/python/Components/About.py -+++ b/lib/python/Components/About.py -@@ -1,10 +1,13 @@ --from sys import modules, version_info --from os import path as ospath --from time import time --import socket - import fcntl -+import socket - import struct - -+from os import path as ospath -+from os.path import join as pathjoin -+from sys import modules, version_info -+from time import time -+from Tools.Directories import fileExists, resolveFilename, SCOPE_LIBDIR -+ - from enigma import getEnigmaVersionString - - -@@ -69,7 +72,12 @@ def getChipSetString(): - try: - return str(open("/proc/stb/info/chipset").read().lower().replace("\n", "").replace("brcm", "").replace("bcm", "")) - except: -- return _("unavailable") -+ if fileExists("/proc/stb/info/model"): -+ getModel = str(open("/proc/stb/info/model").read()) -+ if getModel[0:5] in ("dm900", "dm920"): -+ return "7252s" -+ else: -+ return "unknown" - - - def getCPUSpeedMHzInt(): -@@ -110,7 +118,7 @@ def getCPUSpeedString(): - else: - cpu_speed = "%s MHz" % str(int(cpu_speed)) - return cpu_speed -- return _("unavailable") -+ return "unknown" - - - def getCPUArch(): -diff --git a/lib/python/Components/Harddisk.py b/lib/python/Components/Harddisk.py -index 30c2c8a8218..9836825bcf3 100644 ---- a/lib/python/Components/Harddisk.py -+++ b/lib/python/Components/Harddisk.py -@@ -4,7 +4,7 @@ from fcntl import ioctl - from time import sleep, time - - from enigma import eTimer --from Components.SystemInfo import SystemInfo -+from Components.SystemInfo import SystemInfo, BoxInfo - import Components.Task - from Tools.CList import CList - -@@ -632,6 +632,7 @@ class HarddiskManager: - rootMajor = None - # rootMinor = None - # print("[Harddisk] DEBUG: rootMajor = '%s', rootMinor = '%s'" % (rootMajor, rootMinor)) -+ boxModel = BoxInfo.getItem("model") - for device in sorted(listdir("/sys/block")): - try: - physicalDevice = ospath.realpath(ospath.join("/sys/block", device, "device")) -@@ -644,18 +645,24 @@ class HarddiskManager: - print("[Harddisk] Error: Device '%s' (%s) does not appear to have valid device numbers!" % (device, physicalDevice)) - continue - devMajor = int(data.split(":")[0]) -+ devMinor = int(data.split(":")[1]) - if devMajor in blacklistedDisks: - # print("[Harddisk] DEBUG: Major device number '%s' for device '%s' (%s) is blacklisted." % (devMajor, device, physicalDevice)) - continue -- if devMajor == 179 and not SystemInfo["HasSDnomount"]: # Lets handle Zgemma SD card mounts - uses SystemInfo to determine SDcard status -- # print("[Harddisk] DEBUG: Major device number '%s' for device '%s' (%s) doesn't have 'HasSDnomount' set." % (devMajor, device, physicalDevice)) -- continue -- if devMajor == 179 and devMajor == rootMajor and not SystemInfo["HasSDnomount"][0]: -- # print("[Harddisk] DEBUG: Major device number '%s' for device '%s' (%s) is the root disk." % (devMajor, device, physicalDevice)) -- continue -- if SystemInfo["HasSDnomount"] and device.startswith("%s" % (SystemInfo["HasSDnomount"][1])) and SystemInfo["HasSDnomount"][0]: -- # print("[Harddisk] DEBUG: Major device number '%s' for device '%s' (%s) starts with 'mmcblk0' and has 'HasSDnomount' set." % (devMajor, device, physicalDevice)) -- continue -+ print(f"[Harddisk] DEBUG: boxModel:{boxModel} device:{device} devMajor = '{devMajor}', devMinor = '{devMinor}'") -+ if devMajor == 179 and boxModel in ("dm900", "dm920"): -+ if devMinor != 0: -+ continue -+ else: -+ if devMajor == 179 and not SystemInfo["HasSDnomount"]: # Lets handle Zgemma SD card mounts - uses SystemInfo to determine SDcard status -+ # print(f"[Harddisk] DEBUG: Major device number '{devMajor,}' for device '{device}' ({physicalDevice}) doesn't have 'HasSDnomount' set.") -+ continue -+ if devMajor == 179 and devMajor == rootMajor and not SystemInfo["HasSDnomount"][0]: -+ # print(f"[Harddisk] DEBUG: Major device number '{devMajor} for device '{device} ({physicalDevice}) is the root disk.") -+ continue -+ if SystemInfo["HasSDnomount"] and device.startswith(f"{SystemInfo['HasSDnomount'][1]}") and SystemInfo["HasSDnomount"][0]: -+ # print("f[Harddisk] DEBUG: Major device number '{devMajor} for device '{device}' ({physicalDevice}) starts with 'mmcblk0' and has 'HasSDnomount' set.") -+ continue - description = self.getUserfriendlyDeviceName(device, physicalDevice) - isCdrom = devMajor in opticalDisks or device.startswith("sr") - if isCdrom: -@@ -699,6 +706,8 @@ class HarddiskManager: - # self.partitions.append(Partition(mountpoint = self.getMountpoint(device), description = description, force_mounted, device = device)) - # print("[Harddisk] DEBUG: Partition(mountpoint=%s, description=%s, force_mounted=True, device=%s)" % (self.getMountpoint(device), description, device)) - for partition in partitions: -+ if devMajor == 179 and boxModel in ("dm900", "dm920") and partition != "mmcblk0p3": -+ continue - description = self.getUserfriendlyDeviceName(partition, physicalDevice) - print("[Harddisk] Found partition '%s', description='%s', device='%s'." % (partition, description, physicalDevice)) - # part = Partition(mountpoint=self.getMountpoint(partition), description=description, force_mounted=True, device=partition) -diff --git a/lib/python/Components/Lcd.py b/lib/python/Components/Lcd.py -index 2fb9294ac49..501e124b070 100644 ---- a/lib/python/Components/Lcd.py -+++ b/lib/python/Components/Lcd.py -@@ -351,7 +351,10 @@ def InitLcd(): - def setLCDminitvfps(configElement): - ilcd.setLCDMiniTVFPS(configElement.value) - -- standby_default = 0 -+ if SystemInfo["boxtype"] in ('dm900', 'dm920'): -+ standby_default = 4 -+ else: -+ standby_default = 0 - - if not ilcd.isOled(): - config.lcd.contrast = ConfigSlider(default=5, limits=(0, 20)) -diff --git a/lib/python/Components/NimManager.py b/lib/python/Components/NimManager.py -index 2ecd94c3f84..c13cbf87463 100644 ---- a/lib/python/Components/NimManager.py -+++ b/lib/python/Components/NimManager.py -@@ -1,7 +1,7 @@ - from os import access, path, F_OK - - from Components.About import about --from Components.SystemInfo import SystemInfo -+from Components.SystemInfo import SystemInfo, MODEL - from Tools.BoundFunction import boundFunction - from Tools.Directories import fileReadXML - -@@ -535,8 +535,8 @@ class NIM: - sattype = None - - self.slot = slot -- self.type = sattype -- self.description = description -+ self.type = "DVB-S2X" if "45308X" in description.upper() and MODEL in ("dm900", "dm920") else sattype -+ self.description = "%s FBC" % description if "45308X" in description.upper() and MODEL in ("dm900", "dm920") else description - self.number_of_slots = number_of_slots - self.has_outputs = has_outputs - self.internally_connectable = internally_connectable -@@ -962,7 +962,7 @@ class NimManager: - entry["supports_blind_scan"] = False - - entry["fbc"] = [0, 0, 0] # not fbc -- if entry["name"] and ("fbc" in entry["name"].lower() or (entry["name"] in SystemInfo["HasFBCtuner"] and entry["frontend_device"] is not None and access("/proc/stb/frontend/%d/fbc_id" % entry["frontend_device"], F_OK))): -+ if entry["name"] and ("fbc" in entry["name"].lower() or ("45308X" in entry["name"].upper() and MODEL in ("dm900", "dm920")) or (entry["name"] in SystemInfo["HasFBCtuner"] and entry["frontend_device"] is not None and access("/proc/stb/frontend/%d/fbc_id" % entry["frontend_device"], F_OK))): - fbc_number += 1 - if fbc_number <= (entry["type"] and "DVB-C" in entry["type"] and 1 or 2): - entry["fbc"] = [1, fbc_number, fbc_tuner] # fbc root -diff --git a/lib/python/Components/SystemInfo.py b/lib/python/Components/SystemInfo.py -index 37119cb8750..f3ff95d3f09 100644 ---- a/lib/python/Components/SystemInfo.py -+++ b/lib/python/Components/SystemInfo.py -@@ -314,9 +314,9 @@ SystemInfo["VideoModes"] = getChipSetString() in ( # 2160p and 1080p capable ha - {"720p", "1080i"} # Widescreen modes. - ) - --SystemInfo["FbcTunerPowerAlwaysOn"] = SystemInfo["boxtype"] in ("vusolo4k", "vuduo4k", "vuduo4kse", "vuultimo4k", "vuuno4k", "vuuno4kse") -+SystemInfo["FbcTunerPowerAlwaysOn"] = SystemInfo["boxtype"] in ("vusolo4k", "vuduo4k", "vuduo4kse", "vuultimo4k", "vuuno4k", "vuuno4kse", "dm900", "dm920") - SystemInfo["HasPhysicalLoopthrough"] = ["Vuplus DVB-S NIM(AVL2108)", "GIGA DVB-S2 NIM (Internal)"] --SystemInfo["HasFBCtuner"] = ["Vuplus DVB-C NIM(BCM3158)", "Vuplus DVB-C NIM(BCM3148)", "Vuplus DVB-S NIM(7376 FBC)", "Vuplus DVB-S NIM(45308X FBC)", "Vuplus DVB-S NIM(45208 FBC)", "DVB-S2 NIM(45208 FBC)", "DVB-S2X NIM(45308X FBC)", "DVB-S2 NIM(45308 FBC)", "DVB-C NIM(3128 FBC)", "BCM45208", "BCM45308X", "BCM3158"] -+SystemInfo["HasFBCtuner"] = ["Vuplus DVB-C NIM(BCM3158)", "Vuplus DVB-C NIM(BCM3148)", "Vuplus DVB-S NIM(7376 FBC)", "Vuplus DVB-S NIM(45308X FBC)", "Vuplus DVB-S NIM(45208 FBC)", "DVB-S2 NIM(45208 FBC)", "DVB-S2X NIM(45308X FBC)", "DVB-S2 NIM(45308 FBC)", "DVB-C NIM(3128 FBC)", "BCM45208", "BCM45308X", "BCM45308X FBC", "BCM3158"] - SystemInfo["FCCactive"] = False - SystemInfo["rc_model"] = rc_model.getRcFolder() - SystemInfo["mapKeyInfoToEpgFunctions"] = SystemInfo["rc_model"] in ("vu", "vu2", "vu3", "vu4") # due to button limitations of the remote control -diff --git a/lib/python/Plugins/SystemPlugins/ViX/ImageManager.py b/lib/python/Plugins/SystemPlugins/ViX/ImageManager.py -index 020ff6645c7..d88c8437f7f 100644 ---- a/lib/python/Plugins/SystemPlugins/ViX/ImageManager.py -+++ b/lib/python/Plugins/SystemPlugins/ViX/ImageManager.py -@@ -586,34 +586,33 @@ class VIXImageManager(Screen): - def keyRestore6(self, ret): - MAINDEST = "%s/%s" % (self.TEMPDESTROOT, SystemInfo["imagedir"]) - print("[ImageManager] MAINDEST=%s" % MAINDEST) -- if ret == 0: -- CMD = "/usr/bin/ofgwrite -r -k '%s'" % MAINDEST # normal non multiboot receiver -- if SystemInfo["canMultiBoot"]: -- if self.multibootslot == 0 and SystemInfo["HasKexecMultiboot"]: # reset Vu Multiboot slot0 -- kz0 = SystemInfo["mtdkernel"] -- rz0 = SystemInfo["mtdrootfs"] -- CMD = "/usr/bin/ofgwrite -k%s -r%s '%s'" % (kz0, rz0, MAINDEST) # slot0 treat as kernel/root only multiboot receiver -- elif SystemInfo["HasHiSi"] and SystemInfo["canMultiBoot"][self.multibootslot]["rootsubdir"] is None: # sf8008 type receiver using SD card in multiboot -- CMD = "/usr/bin/ofgwrite -r%s -k%s -m0 '%s'" % (self.MTDROOTFS, self.MTDKERNEL, MAINDEST) -- print("[ImageManager] running commnd:%s slot = %s" % (CMD, self.multibootslot)) -- if fileExists("/boot/STARTUP") and fileExists("/boot/STARTUP_6"): -- copyfile("/boot/STARTUP_%s" % self.multibootslot, "/boot/STARTUP") -- elif SystemInfo["HasKexecMultiboot"]: -- if SystemInfo["HasKexecUSB"] and "mmcblk" not in self.MTDROOTFS: -- CMD = "/usr/bin/ofgwrite -r%s -kzImage -s'%s/linuxrootfs' -m%s '%s'" % (self.MTDROOTFS, SystemInfo["boxtype"][2:], self.multibootslot, MAINDEST) -- else: -- CMD = "/usr/bin/ofgwrite -r%s -kzImage -m%s '%s'" % (self.MTDROOTFS, self.multibootslot, MAINDEST) -- print("[ImageManager] running commnd:%s slot = %s" % (CMD, self.multibootslot)) -+ CMD = "/usr/bin/ofgwrite -r -k '%s'" % MAINDEST # normal non multiboot receiver -+ if SystemInfo["canMultiBoot"]: -+ if self.multibootslot == 0 and SystemInfo["HasKexecMultiboot"]: # reset Vu Multiboot slot0 -+ kz0 = SystemInfo["mtdkernel"] -+ rz0 = SystemInfo["mtdrootfs"] -+ CMD = "/usr/bin/ofgwrite -k%s -r%s '%s'" % (kz0, rz0, MAINDEST) # slot0 treat as kernel/root only multiboot receiver -+ elif SystemInfo["HasHiSi"] and SystemInfo["canMultiBoot"][self.multibootslot]["rootsubdir"] is None: # sf8008 type receiver using SD card in multiboot -+ CMD = "/usr/bin/ofgwrite -r%s -k%s -m0 '%s'" % (self.MTDROOTFS, self.MTDKERNEL, MAINDEST) -+ print("[ImageManager] running commnd:%s slot = %s" % (CMD, self.multibootslot)) -+ if fileExists("/boot/STARTUP") and fileExists("/boot/STARTUP_6"): -+ copyfile("/boot/STARTUP_%s" % self.multibootslot, "/boot/STARTUP") -+ elif SystemInfo["HasKexecMultiboot"]: -+ if SystemInfo["HasKexecUSB"] and "mmcblk" not in self.MTDROOTFS: -+ CMD = "/usr/bin/ofgwrite -r%s -kzImage -s'%s/linuxrootfs' -m%s '%s'" % (self.MTDROOTFS, SystemInfo["boxtype"][2:], self.multibootslot, MAINDEST) - else: -- CMD = "/usr/bin/ofgwrite -r -k -m%s '%s'" % (self.multibootslot, MAINDEST) # Normal multiboot -- elif SystemInfo["HasH9SD"]: -- if fileHas("/proc/cmdline", "root=/dev/mmcblk0p1") is True and fileExists("%s/rootfs.tar.bz2" % MAINDEST): # h9 using SD card -- CMD = "/usr/bin/ofgwrite -rmmcblk0p1 '%s'" % MAINDEST -- elif fileExists("%s/rootfs.ubi" % MAINDEST) and fileExists("%s/rootfs.tar.bz2" % MAINDEST): # h9 no SD card - build has both roots causes ofgwrite issue -- rename("%s/rootfs.tar.bz2" % MAINDEST, "%s/xx.txt" % MAINDEST) -- else: -- CMD = "/usr/bin/ofgwrite -rmtd4 -kmtd3 %s/" % MAINDEST # Xtrend ET8500 with OS2 multiboot -- print("[ImageManager] running commnd:", CMD) -+ CMD = "/usr/bin/ofgwrite -r%s -kzImage -m%s '%s'" % (self.MTDROOTFS, self.multibootslot, MAINDEST) -+ print("[ImageManager] running commnd:%s slot = %s" % (CMD, self.multibootslot)) -+ else: -+ CMD = "/usr/bin/ofgwrite -r -k -m%s '%s'" % (self.multibootslot, MAINDEST) # Normal multiboot -+ elif SystemInfo["HasH9SD"]: -+ if fileHas("/proc/cmdline", "root=/dev/mmcblk0p1") is True and fileExists("%s/rootfs.tar.bz2" % MAINDEST): # h9 using SD card -+ CMD = "/usr/bin/ofgwrite -rmmcblk0p1 '%s'" % MAINDEST -+ elif fileExists("%s/rootfs.ubi" % MAINDEST) and fileExists("%s/rootfs.tar.bz2" % MAINDEST): # h9 no SD card - build has both roots causes ofgwrite issue -+ rename("%s/rootfs.tar.bz2" % MAINDEST, "%s/xx.txt" % MAINDEST) -+ elif SystemInfo["machinebuild"] in ("dm900", "dm920"): # kernel:mmcblk0p1 root:mmcblk0p2 -+ CMD = "/usr/bin/ofgwrite -r%s '%s'" % (self.MTDROOTFS, MAINDEST) # No ofgwrite auto detection, so only flash root NOT kernel -+ print(f"[ImageManager] running command:{CMD} root:{self.MTDROOTFS}") - self.Console.ePopen(CMD, self.ofgwriteResult) - fbClass.getInstance().lock() - -diff --git a/lib/python/Plugins/SystemPlugins/ViX/MountManager.py b/lib/python/Plugins/SystemPlugins/ViX/MountManager.py -index b477a5d5bfa..6113f5e28a0 100644 ---- a/lib/python/Plugins/SystemPlugins/ViX/MountManager.py -+++ b/lib/python/Plugins/SystemPlugins/ViX/MountManager.py -@@ -10,7 +10,7 @@ from Components.ConfigList import ConfigListScreen - from Components.config import getConfigListEntry, ConfigSelection, NoSave - from Components.Console import Console - from Components.Sources.List import List --from Components.SystemInfo import SystemInfo -+from Components.SystemInfo import SystemInfo, BoxInfo - from Screens.MessageBox import MessageBox - from Screens.Screen import Screen - from Screens.Standby import QUIT_REBOOT, TryQuitMainloop -@@ -41,6 +41,7 @@ def readFile(filename): - - def getProcPartitions(partitionList): - partitions = [] -+ boxModel = BoxInfo.getItem("model") - with open("/proc/partitions", "r") as fd: - for line in fd.readlines(): - line = line.strip() -@@ -53,21 +54,26 @@ def getProcPartitions(partitionList): - devMajor = int(devmajor) - if devMajor in blacklistedDisks: # Ignore all blacklisted devices. - continue -- if devMajor == 179: -- if not SystemInfo["HasSDnomount"]: # Only interested in h9/i55/h9combo(+dups) mmc partitions. h9combo(+dups) uses mmcblk1p[0-3]. -+ if devMajor == 179 and boxModel in ("dm900", "dm920"): -+ print("[MountManager]2 device='%s', devmajor='%s', devminor='%s'." % (device, devmajor, devminor)) -+ if device != "mmcblk0p3": - continue -- if SystemInfo["HasH9SD"]: -- if not re.search("mmcblk0p1", device): # h9/i55 only mmcblk0p1 mmc partition -+ else: -+ if devMajor == 179: -+ if not SystemInfo["HasSDnomount"]: # Only interested in h9/i55/h9combo(+dups) mmc partitions. h9combo(+dups) uses mmcblk1p[0-3]. - continue -- if SystemInfo["HasMMC"]: # With h9/i55 reject mmcblk0p1 mmc partition if root device. -+ if SystemInfo["HasH9SD"]: -+ if not re.search("mmcblk0p1", device): # h9/i55 only mmcblk0p1 mmc partition -+ continue -+ if SystemInfo["HasMMC"]: # With h9/i55 reject mmcblk0p1 mmc partition if root device. -+ continue -+ if SystemInfo["HasSDnomount"][0] and not re.search("mmcblk1p[0-3]", device): # h9combo(+dups) uses mmcblk1p[0-3] include -+ continue -+ if devMajor == 8: -+ if not re.search("sd[a-z][1-9]", device): # If storage use partitions only. -+ continue -+ if SystemInfo["HasHiSi"] and path.exists("/dev/sda4") and re.search("sd[a][1-4]", device): # Sf8008 using SDcard for slots ---> exclude - continue -- if SystemInfo["HasSDnomount"][0] and not re.search("mmcblk1p[0-3]", device): # h9combo(+dups) uses mmcblk1p[0-3] include -- continue -- if devMajor == 8: -- if not re.search("sd[a-z][1-9]", device): # If storage use partitions only. -- continue -- if SystemInfo["HasHiSi"] and path.exists("/dev/sda4") and re.search("sd[a][1-4]", device): # Sf8008 using SDcard for slots ---> exclude -- continue - if device in partitions: # If device is already in partition list ignore it. - continue - buildPartitionInfo(device, partitionList) -diff --git a/lib/python/Screens/Satconfig.py b/lib/python/Screens/Satconfig.py -index 9cb43fd3e96..b64ffc2da21 100644 ---- a/lib/python/Screens/Satconfig.py -+++ b/lib/python/Screens/Satconfig.py -@@ -858,7 +858,7 @@ class NimSelection(Screen): - if x.isCompatible("DVB-S"): - if nimConfig.configMode.value in ("loopthrough", "equal", "satposdepends"): - if x.isFBCLink(): -- text = _("FBC automatic\nconnected to") -+ text = "%s %s" % (_("FBC automatic\nconnected to"), nimmanager.getNim(int(nimConfig.connectedTo.value)).slot_name) - else: - text = "%s %s" % ({"loopthrough": _("Loop through from"), "equal": _("Equal to"), "satposdepends": _("Second cable of motorized LNB")}[nimConfig.configMode.value], - nimmanager.getNim(int(nimConfig.connectedTo.value)).slot_name) -diff --git a/lib/python/Screens/SessionGlobals.py b/lib/python/Screens/SessionGlobals.py -index 6577b9052b0..a759f04c7b9 100644 ---- a/lib/python/Screens/SessionGlobals.py -+++ b/lib/python/Screens/SessionGlobals.py -@@ -9,6 +9,7 @@ from Components.Sources.Boolean import Boolean - from Components.Sources.RecordState import RecordState - from Components.Converter.Combine import Combine - from Components.Renderer.FrontpanelLed import FrontpanelLed -+from Components.SystemInfo import MODEL - - - class SessionGlobals(Screen): -@@ -46,5 +47,9 @@ class SessionGlobals(Screen): - if nr_leds == 1: - FrontpanelLed(which=0, boolean=False, patterns=[PATTERN_OFF, PATTERN_BLINK, PATTERN_OFF, PATTERN_BLINK]).connect(combine) - elif nr_leds == 2: -- FrontpanelLed(which=0, boolean=False, patterns=[PATTERN_OFF, PATTERN_BLINK, PATTERN_ON, PATTERN_BLINK]).connect(combine) -- FrontpanelLed(which=1, boolean=False, patterns=[PATTERN_ON, PATTERN_ON, PATTERN_OFF, PATTERN_OFF]).connect(combine) -+ if MODEL in ("dm900", "dm920"): -+ FrontpanelLed(which=1, boolean=False, patterns=[PATTERN_OFF, PATTERN_BLINK, PATTERN_OFF, PATTERN_BLINK]).connect(combine) -+ FrontpanelLed(which=0, boolean=False, patterns=[PATTERN_ON, PATTERN_ON, PATTERN_OFF, PATTERN_OFF]).connect(combine) -+ else: -+ FrontpanelLed(which=0, boolean=False, patterns=[PATTERN_OFF, PATTERN_BLINK, PATTERN_ON, PATTERN_BLINK]).connect(combine) -+ FrontpanelLed(which=1, boolean=False, patterns=[PATTERN_ON, PATTERN_ON, PATTERN_OFF, PATTERN_OFF]).connect(combine) -diff --git a/lib/python/Screens/UserInterfacePositioner.py b/lib/python/Screens/UserInterfacePositioner.py -index 91d39cab265..43e204eae29 100644 ---- a/lib/python/Screens/UserInterfacePositioner.py -+++ b/lib/python/Screens/UserInterfacePositioner.py -@@ -1,20 +1,23 @@ --from Screens.MessageBox import MessageBox --from Screens.Screen import Screen -+from os import access, R_OK -+import traceback -+from enigma import getDesktop -+ - from Components.ActionMap import ActionMap - from Components.config import config, configfile, getConfigListEntry, ConfigSelectionNumber, ConfigSelection, ConfigSlider, ConfigYesNo, NoSave, ConfigNumber - from Components.ConfigList import ConfigListScreen --from Components.SystemInfo import SystemInfo --from Components.Sources.StaticText import StaticText - from Components.Console import Console -+from Components.Sources.StaticText import StaticText -+from Components.SystemInfo import SystemInfo, BRAND -+from Screens.Screen import Screen -+from Screens.MessageBox import MessageBox - from Tools.Directories import fileCheck, fileExists --from enigma import getDesktop --from os import access, R_OK --import traceback - - - def getFilePath(setting): -- return "/proc/stb/fb/dst_%s" % (setting) -- -+ if BRAND in ("dreambox", ): -+ return "/proc/stb/vmpeg/0/dst_%s" % (setting) -+ else: -+ return "/proc/stb/fb/dst_%s" % (setting) - - def setPositionParameter(parameter, configElement): - f = open(getFilePath(parameter), "w") -@@ -65,7 +68,7 @@ def InitOsd(): - - def InitOsdPosition(): - SystemInfo["CanChangeOsdAlpha"] = access('/proc/stb/video/alpha', R_OK) and True or False -- SystemInfo["CanChangeOsdPosition"] = access('/proc/stb/fb/dst_left', R_OK) and True or False -+ SystemInfo["CanChangeOsdPosition"] = (access('/proc/stb/fb/dst_left', R_OK) or access('/proc/stb/vmpeg/0/dst_left', R_OK)) and True or False - SystemInfo["OsdSetup"] = SystemInfo["CanChangeOsdPosition"] - - if SystemInfo["CanChangeOsdAlpha"] is True or SystemInfo["CanChangeOsdPosition"] is True: diff --git a/fcc.patch b/fcc.patch deleted file mode 100644 index 12ea9a6e5c1..00000000000 --- a/fcc.patch +++ /dev/null @@ -1,3005 +0,0 @@ -diff --git a/configure.ac b/configure.ac -index 7ea83f92d3..01b7c9eaab 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -626,6 +626,8 @@ lib/python/Plugins/SystemPlugins/DefaultServicesScanner/Makefile - lib/python/Plugins/SystemPlugins/DefaultServicesScanner/meta/Makefile - lib/python/Plugins/SystemPlugins/DiseqcTester/Makefile - lib/python/Plugins/SystemPlugins/DiseqcTester/meta/Makefile -+lib/python/Plugins/SystemPlugins/FastChannelChange/Makefile -+lib/python/Plugins/SystemPlugins/FastChannelChange/meta/Makefile - lib/python/Plugins/SystemPlugins/FastScan/Makefile - lib/python/Plugins/SystemPlugins/FrontprocessorUpgrade/Makefile - lib/python/Plugins/SystemPlugins/FrontprocessorUpgrade/meta/Makefile -diff --git a/lib/dvb/Makefile.inc b/lib/dvb/Makefile.inc -index 96633c0346..5fbdcb7b75 100644 ---- a/lib/dvb/Makefile.inc -+++ b/lib/dvb/Makefile.inc -@@ -35,7 +35,9 @@ dvb_libenigma_dvb_a_SOURCES = \ - dvb/streamserver.cpp \ - dvb/pmtparse.cpp \ - dvb/encoder.cpp \ -- dvb/atsc.cpp -+ dvb/atsc.cpp \ -+ dvb/fcc.cpp \ -+ dvb/fccdecoder.cpp - - dvbincludedir = $(pkgincludedir)/lib/dvb - dvbinclude_HEADERS = \ -@@ -79,4 +81,6 @@ dvbinclude_HEADERS = \ - dvb/streamserver.h \ - dvb/pmtparse.h \ - dvb/encoder.h \ -- dvb/atsc.h -+ dvb/atsc.h \ -+ dvb/fcc.h \ -+ dvb/fccdecoder.h -diff --git a/lib/dvb/decoder.cpp b/lib/dvb/decoder.cpp -index f361a72abc..95f5609dd9 100644 ---- a/lib/dvb/decoder.cpp -+++ b/lib/dvb/decoder.cpp -@@ -16,6 +16,8 @@ - #include - #include - -+#include -+ - #ifndef VIDEO_SOURCE_HDMI - #define VIDEO_SOURCE_HDMI 2 - #endif -@@ -263,8 +265,8 @@ DEFINE_REF(eDVBVideo); - - int eDVBVideo::m_close_invalidates_attributes = -1; - --eDVBVideo::eDVBVideo(eDVBDemux *demux, int dev) -- : m_demux(demux), m_dev(dev), -+eDVBVideo::eDVBVideo(eDVBDemux *demux, int dev, bool fcc_enable) -+ : m_demux(demux), m_dev(dev), m_fcc_enable(fcc_enable), - m_width(-1), m_height(-1), m_framerate(-1), m_aspect(-1), m_progressive(-1), m_gamma(-1) - { - char filename[128] = {}; -@@ -345,6 +347,9 @@ eDVBVideo::eDVBVideo(eDVBDemux *demux, int dev) - - int eDVBVideo::startPid(int pid, int type) - { -+ if (m_fcc_enable) -+ return 0; -+ - if (m_fd >= 0) - { - int streamtype = VIDEO_STREAMTYPE_MPEG2; -@@ -440,6 +445,9 @@ int eDVBVideo::startPid(int pid, int type) - - void eDVBVideo::stop() - { -+ if (m_fcc_enable) -+ return; -+ - if (m_fd_demux >= 0) - { - eDebugNoNewLineStart("[eDVBVideo%d] DEMUX_STOP ", m_dev); -@@ -958,7 +966,7 @@ int eTSMPEGDecoder::setState() - { - if ((m_vpid >= 0) && (m_vpid < 0x1FFF)) - { -- m_video = new eDVBVideo(m_demux, m_decoder); -+ m_video = new eDVBVideo(m_demux, m_decoder, m_fcc_enable); - m_video->connectEvent(sigc::mem_fun(*this, &eTSMPEGDecoder::video_event), m_video_event_conn); - if (m_video->startPid(m_vpid, m_vtype)) - res = -1; -@@ -1073,7 +1081,8 @@ RESULT eTSMPEGDecoder::setAC3Delay(int delay) - eTSMPEGDecoder::eTSMPEGDecoder(eDVBDemux *demux, int decoder) - : m_demux(demux), - m_vpid(-1), m_vtype(-1), m_apid(-1), m_atype(-1), m_pcrpid(-1), m_textpid(-1), -- m_changed(0), m_decoder(decoder), m_video_clip_fd(-1), m_showSinglePicTimer(eTimer::create(eApp)) -+ m_changed(0), m_decoder(decoder), m_video_clip_fd(-1), m_showSinglePicTimer(eTimer::create(eApp)), -+ m_fcc_fd(-1), m_fcc_enable(false), m_fcc_state(fcc_state_stop), m_fcc_feid(-1), m_fcc_vpid(-1), m_fcc_vtype(-1), m_fcc_pcrpid(-1) - { - if (m_demux) - { -@@ -1099,6 +1108,8 @@ eTSMPEGDecoder::~eTSMPEGDecoder() - m_vpid = m_apid = m_pcrpid = m_textpid = pidNone; - m_changed = -1; - setState(); -+ fccStop(); -+ fccFreeFD(); - - if (m_demux && m_decoder == 0) // Tuxtxt caching actions only on primary decoder - { -@@ -1456,3 +1467,240 @@ int eTSMPEGDecoder::getVideoGamma() - return m_video->getGamma(); - return -1; - } -+ -+#define FCC_SET_VPID 100 -+#define FCC_SET_APID 101 -+#define FCC_SET_PCRPID 102 -+#define FCC_SET_VCODEC 103 -+#define FCC_SET_ACODEC 104 -+#define FCC_SET_FRONTEND_ID 105 -+#define FCC_START 106 -+#define FCC_STOP 107 -+#define FCC_DECODER_START 108 -+#define FCC_DECODER_STOP 109 -+ -+RESULT eTSMPEGDecoder::prepareFCC(int fe_id, int vpid, int vtype, int pcrpid) -+{ -+ //eDebug("[eTSMPEGDecoder] prepareFCC vp : %d, vt : %d, pp : %d, fe : %d", vpid, vtype, pcrpid, fe_id); -+ -+ if ((fccGetFD() == -1) || (fccSetPids(fe_id, vpid, vtype, pcrpid) < 0) || (fccStart() < 0)) -+ { -+ fccFreeFD(); -+ return -1; -+ } -+ -+ m_fcc_enable = true; -+ -+ return 0; -+} -+ -+RESULT eTSMPEGDecoder::fccDecoderStart() -+{ -+ if (m_fcc_fd == -1) -+ return -1; -+ -+ if (m_fcc_state != fcc_state_ready) -+ { -+ eDebug("[eTSMPEGDecoder] FCC decoder is already in decoding state."); -+ return 0; -+ } -+ -+ if (ioctl(m_fcc_fd, FCC_DECODER_START) < 0) -+ { -+ eDebug("[eTSMPEGDecoder] ioctl FCC_DECODER_START failed! (%m)"); -+ return -1; -+ } -+ -+ m_fcc_state = fcc_state_decoding; -+ -+ eDebug("[eTSMPEGDecoder] FCC_DECODER_START OK!"); -+ return 0; -+} -+ -+RESULT eTSMPEGDecoder::fccDecoderStop() -+{ -+ if (m_fcc_fd == -1) -+ return -1; -+ -+ if (m_fcc_state != fcc_state_decoding) -+ { -+ eDebug("[eTSMPEGDecoder] FCC decoder is not in decoding state."); -+ } -+ else if (ioctl(m_fcc_fd, FCC_DECODER_STOP) < 0) -+ { -+ eDebug("[eTSMPEGDecoder] ioctl FCC_DECODER_STOP failed! (%m)"); -+ return -1; -+ } -+ -+ m_fcc_state = fcc_state_ready; -+ -+ /* stop pcr, video, audio, text */ -+ finishShowSinglePic(); -+ -+ m_vpid = m_apid = m_pcrpid = m_textpid = pidNone; -+ m_changed = -1; -+ setState(); -+ -+ eDebug("[eTSMPEGDecoder] FCC_DECODER_STOP OK!"); -+ return 0; -+} -+ -+RESULT eTSMPEGDecoder::fccUpdatePids(int fe_id, int vpid, int vtype, int pcrpid) -+{ -+ //eDebug("[eTSMPEGDecoder] vp : %d, vt : %d, pp : %d, fe : %d", vpid, vtype, pcrpid, fe_id); -+ -+ if ((fe_id != m_fcc_feid) || (vpid != m_fcc_vpid) || (vtype != m_fcc_vtype) || (pcrpid != m_fcc_pcrpid)) -+ { -+ fccStop(); -+ if (prepareFCC(fe_id, vpid, vtype, pcrpid)) -+ { -+ eDebug("[eTSMPEGDecoder] prepare FCC failed!"); -+ return -1; -+ } -+ } -+ return 0; -+} -+ -+RESULT eTSMPEGDecoder::fccStart() -+{ -+ if (m_fcc_fd == -1) -+ return -1; -+ -+ if (m_fcc_state != fcc_state_stop) -+ { -+ eDebug("[eTSMPEGDecoder] FCC is already started!"); -+ return 0; -+ } -+ else if (ioctl(m_fcc_fd, FCC_START) < 0) -+ { -+ eDebug("[eTSMPEGDecoder] ioctl FCC_START failed! (%m)"); -+ return -1; -+ } -+ -+ eDebug("[eTSMPEGDecoder] FCC_START OK!"); -+ -+ m_fcc_state = fcc_state_ready; -+ return 0; -+} -+ -+RESULT eTSMPEGDecoder::fccStop() -+{ -+ if (m_fcc_fd == -1) -+ return -1; -+ -+ if (m_fcc_state == fcc_state_stop) -+ { -+ eDebug("[eTSMPEGDecoder] FCC is already stopped!"); -+ return 0; -+ } -+ -+ else if (m_fcc_state == fcc_state_decoding) -+ { -+ fccDecoderStop(); -+ } -+ -+ if (ioctl(m_fcc_fd, FCC_STOP) < 0) -+ { -+ eDebug("[eTSMPEGDecoder] ioctl FCC_STOP failed! (%m)"); -+ return -1; -+ } -+ -+ m_fcc_state = fcc_state_stop; -+ -+ eDebug("[eTSMPEGDecoder] FCC_STOP OK!"); -+ return 0; -+} -+ -+RESULT eTSMPEGDecoder::fccSetPids(int fe_id, int vpid, int vtype, int pcrpid) -+{ -+ int streamtype = VIDEO_STREAMTYPE_MPEG2; -+ -+ if (m_fcc_fd == -1) -+ return -1; -+ -+ if (ioctl(m_fcc_fd, FCC_SET_FRONTEND_ID, fe_id) < 0) -+ { -+ eDebug("[eTSMPEGDecoder] FCC_SET_FRONTEND_ID failed! (%m)"); -+ return -1; -+ } -+ -+ else if(ioctl(m_fcc_fd, FCC_SET_PCRPID, pcrpid) < 0) -+ { -+ eDebug("[eTSMPEGDecoder] FCC_SET_PCRPID failed! (%m)"); -+ return -1; -+ } -+ -+ else if (ioctl(m_fcc_fd, FCC_SET_VPID, vpid) < 0) -+ { -+ eDebug("[eTSMPEGDecoder] FCC_SET_VPID failed! (%m)"); -+ return -1; -+ } -+ -+ switch(vtype) -+ { -+ default: -+ case eDVBVideo::MPEG2: -+ break; -+ case eDVBVideo::MPEG4_H264: -+ streamtype = VIDEO_STREAMTYPE_MPEG4_H264; -+ break; -+ case eDVBVideo::MPEG1: -+ streamtype = VIDEO_STREAMTYPE_MPEG1; -+ break; -+ case eDVBVideo::MPEG4_Part2: -+ streamtype = VIDEO_STREAMTYPE_MPEG4_Part2; -+ break; -+ case eDVBVideo::VC1: -+ streamtype = VIDEO_STREAMTYPE_VC1; -+ break; -+ case eDVBVideo::VC1_SM: -+ streamtype = VIDEO_STREAMTYPE_VC1_SM; -+ break; -+ case eDVBVideo::H265_HEVC: -+ streamtype = VIDEO_STREAMTYPE_H265_HEVC; -+ break; -+ } -+ -+ if(ioctl(m_fcc_fd, FCC_SET_VCODEC, streamtype) < 0) -+ { -+ eDebug("[eTSMPEGDecoder] FCC_SET_VCODEC failed! (%m)"); -+ return -1; -+ } -+ -+ m_fcc_feid = fe_id; -+ m_fcc_vpid = vpid; -+ m_fcc_vtype = vtype; -+ m_fcc_pcrpid = pcrpid; -+ -+ //eDebug("[eTSMPEGDecoder] SET PIDS OK!"); -+ return 0; -+} -+ -+RESULT eTSMPEGDecoder::fccGetFD() -+{ -+ if (m_fcc_fd == -1) -+ { -+ eFCCDecoder* fcc = eFCCDecoder::getInstance(); -+ if (fcc != NULL) -+ { -+ m_fcc_fd = fcc->allocateFcc(); -+ } -+ } -+ -+ return m_fcc_fd; -+} -+ -+RESULT eTSMPEGDecoder::fccFreeFD() -+{ -+ if (m_fcc_fd != -1) -+ { -+ eFCCDecoder* fcc = eFCCDecoder::getInstance(); -+ if (fcc != NULL) -+ { -+ fcc->freeFcc(m_fcc_fd); -+ m_fcc_fd = -1; -+ } -+ } -+ -+ return 0; -+} -diff --git a/lib/dvb/decoder.h b/lib/dvb/decoder.h -index c99644fe9b..05cb4d4ea4 100644 ---- a/lib/dvb/decoder.h -+++ b/lib/dvb/decoder.h -@@ -32,6 +32,7 @@ class eDVBVideo: public iObject, public sigc::trackable - private: - ePtr m_demux; - int m_fd, m_fd_demux, m_dev; -+ bool m_fcc_enable; - static int m_close_invalidates_attributes; - int m_is_slow_motion, m_is_fast_forward, m_is_freezed; - ePtr m_sn; -@@ -41,7 +42,7 @@ private: - static int readApiSize(int fd, int &xres, int &yres, int &aspect); - public: - enum { UNKNOWN = -1, MPEG2, MPEG4_H264, VC1 = 3, MPEG4_Part2, VC1_SM, MPEG1, H265_HEVC, AVS = 16, AVS2 = 40 }; -- eDVBVideo(eDVBDemux *demux, int dev); -+ eDVBVideo(eDVBDemux *demux, int dev, bool fcc_enable=false); - void stop(); - int startPid(int pid, int type=MPEG2); - void flush(); -@@ -121,6 +122,13 @@ private: - sigc::signal m_video_event; - int m_video_clip_fd; - ePtr m_showSinglePicTimer; -+ int m_fcc_fd; -+ bool m_fcc_enable; -+ int m_fcc_state; -+ int m_fcc_feid; -+ int m_fcc_vpid; -+ int m_fcc_vtype; -+ int m_fcc_pcrpid; - void finishShowSinglePic(); // called by timer - public: - enum { pidNone = -1 }; -@@ -177,6 +185,23 @@ public: - int getVideoGamma(); - static RESULT setHwPCMDelay(int delay); - static RESULT setHwAC3Delay(int delay); -+ -+ enum -+ { -+ fcc_state_stop, -+ fcc_state_ready, -+ fcc_state_decoding -+ }; -+ -+ RESULT prepareFCC(int fe_id, int vpid, int vtype, int pcrpid); -+ RESULT fccStart(); -+ RESULT fccStop(); -+ RESULT fccDecoderStart(); -+ RESULT fccDecoderStop(); -+ RESULT fccUpdatePids(int fe_id, int vpid, int vtype, int pcrpid); -+ RESULT fccSetPids(int fe_id, int vpid, int vtype, int pcrpid); -+ RESULT fccGetFD(); -+ RESULT fccFreeFD(); - }; - - #endif -diff --git a/lib/dvb/dvb.cpp b/lib/dvb/dvb.cpp -index 135b560c47..254da63d77 100644 ---- a/lib/dvb/dvb.cpp -+++ b/lib/dvb/dvb.cpp -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include - #include "filepush.h" - -@@ -20,6 +21,7 @@ - #include - #include - #include -+#include - - #define MIN(a,b) (a < b ? a : b) - #define MAX(a,b) (a > b ? a : b) -@@ -111,6 +113,9 @@ eDVBResourceManager::eDVBResourceManager() - adapter->scanDevices(); - addAdapter(adapter, true); - } -+ -+ setUsbTuner(); -+ - eDebug("[eDVBResourceManager] found %zd adapter, %zd frontends(%zd sim) and %zd demux", - m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size()); - m_fbcmng = new eFBCTunerManager(instance); -@@ -682,6 +687,59 @@ void eDVBResourceManager::addAdapter(iDVBAdapter *adapter, bool front) - - } - -+void eDVBResourceManager::setUsbTuner() -+{ -+ std::ifstream in("/proc/bus/nim_sockets"); -+ std::string line; -+ -+ int res = -1; -+ int fe_idx = -1; -+ int usbtuner_idx[8] = {0}; -+ int usbtuner_count = 0; -+ -+ if (in.is_open()) -+ { -+ while(!in.eof()) -+ { -+ getline(in, line); -+ if ((res = sscanf(line.c_str(), "NIM Socket %d:", &fe_idx)) == 1) -+ continue; -+ -+ if ((fe_idx != -1) && (line.find("\tName: ") == 0) && (line.find("VTUNER") != std::string::npos)) -+ usbtuner_idx[usbtuner_count++] = fe_idx; -+ } -+ in.close(); -+ } -+ -+ if (usbtuner_count) -+ { -+ for (eSmartPtrList::iterator it(m_frontend.begin()); it != m_frontend.end(); ++it) -+ { -+ int slotid = it->m_frontend->getSlotID(); -+ for (int i=0; i < usbtuner_count ; i++) -+ { -+ if (slotid == usbtuner_idx[i]) -+ { -+ it->m_frontend->setUSBTuner(true); -+ break; -+ } -+ } -+ } -+ for (eSmartPtrList::iterator it(m_simulate_frontend.begin()); it != m_simulate_frontend.end(); ++it) -+ { -+ int slotid = it->m_frontend->getSlotID(); -+ for (int i=0; i < usbtuner_count ; i++) -+ { -+ if (slotid == usbtuner_idx[i]) -+ { -+ it->m_frontend->setUSBTuner(true); -+ break; -+ } -+ } -+ } -+ } -+} -+ - PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list) - { - if (!PyList_Check(list)) -@@ -1407,6 +1465,56 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons - int *decremented_cached_channel_fe_usecount=NULL, - *decremented_fe_usecount=NULL; - -+ /* check FCC channels */ -+ std::vector fcc_decremented_fe_usecounts; -+ std::map fcc_chids; -+ int apply_to_ignore = 0; -+ if (!eFCCServiceManager::getFCCChannelID(fcc_chids)) -+ { -+ for (std::map::iterator i(fcc_chids.begin()); i != fcc_chids.end(); ++i) -+ { -+ //eDebug("[eDVBResourceManager::canAllocateChannel] FCC NS : %08x, TSID : %04x, ONID : %04x", i->first.dvbnamespace.get(), i->first.transport_stream_id.get(), i->first.original_network_id.get()); -+ if (ignore == i->first) -+ { -+ apply_to_ignore = i->second; -+ continue; -+ } -+ for (std::list::iterator ii(active_channels.begin()); ii != active_channels.end(); ++ii) -+ { -+ eSmartPtrList &frontends = simulate ? m_simulate_frontend : m_frontend; -+ if (ii->m_channel_id == i->first) -+ { -+ eDVBChannel *channel = (eDVBChannel*) &(*ii->m_channel); -+ -+ int check_usecount = channel == &(*m_cached_channel) ? 1 : 0; -+ check_usecount += i->second * 2; // one is used in eDVBServicePMTHandler and another is used in eDVBScan. -+ //eDebug("[eDVBResourceManager::canAllocateChannel] channel->getUseCount() : %d , check_usecount : %d (cached : %d)", channel->getUseCount(), check_usecount, channel == &(*m_cached_channel)); -+ if (channel->getUseCount() == check_usecount) -+ { -+ ePtr fe; -+ if (!ii->m_channel->getFrontend(fe)) -+ { -+ for (eSmartPtrList::iterator iii(frontends.begin()); iii != frontends.end(); ++iii) -+ { -+ if ( &(*fe) == &(*iii->m_frontend) ) -+ { -+ //eDebug("[eDVBResourceManager::canAllocateChannel] fcc : decrease fcc fe use_count! feid : %d (%d -> %d)", iii->m_frontend->getSlotID(), iii->m_inuse, iii->m_inuse-1); -+ --iii->m_inuse; -+ int *tmp_decremented_fe_usecount = &iii->m_inuse; -+ fcc_decremented_fe_usecounts.push_back(tmp_decremented_fe_usecount); -+ if (channel == &(*m_cached_channel)) -+ decremented_cached_channel_fe_usecount = tmp_decremented_fe_usecount; -+ break; -+ } -+ } -+ } -+ } -+ break; -+ } -+ } -+ } -+ } -+ - for (std::list::iterator i(active_channels.begin()); i != active_channels.end(); ++i) - { - eSmartPtrList &frontends = simulate ? m_simulate_frontend : m_frontend; -@@ -1418,7 +1526,10 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons - // another on eUsePtr is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan) - // so we must check here if usecount is 3 (when the channel is equal to the cached channel) - // or 2 when the cached channel is not equal to the compared channel -- if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2) // channel only used once.. -+ int check_usecount = channel == &(*m_cached_channel) ? 1 : 0; -+ check_usecount += (apply_to_ignore+1) * 2; // one is used in eDVBServicePMTHandler and another is used in eDVBScan. -+ //eDebug("[eDVBResourceManager] canAllocateChannel channel->getUseCount() : %d , check_usecount : %d (cached : %d)", channel->getUseCount(), check_usecount, channel == &(*m_cached_channel)); -+ if (channel->getUseCount() == check_usecount) // channel only used once..(except fcc) - { - ePtr fe; - if (!i->m_channel->getFrontend(fe)) -@@ -1427,6 +1538,7 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons - { - if ( &(*fe) == &(*ii->m_frontend) ) - { -+ //eDebug("[eDVBResourceManager] canAllocateChannel ignore : decrease fcc fe use_count! feid : %d (%d -> %d)", ii->m_frontend->getSlotID(), ii->m_inuse, ii->m_inuse-1); - --ii->m_inuse; - decremented_fe_usecount = &ii->m_inuse; - if (channel == &(*m_cached_channel)) -@@ -1489,6 +1601,14 @@ error: - ++(*decremented_fe_usecount); - if (decremented_cached_channel_fe_usecount) - ++(*decremented_cached_channel_fe_usecount); -+ if (fcc_decremented_fe_usecounts.size()) -+ { -+ for (std::vector::iterator i(fcc_decremented_fe_usecounts.begin()); i != fcc_decremented_fe_usecounts.end(); ++i) -+ { -+ //eDebug("[eDVBResourceManager] canAllocateChannel fcc : increase fcc fe use_count!"); -+ ++(**i); -+ } -+ } - - return ret; - } -diff --git a/lib/dvb/dvb.h b/lib/dvb/dvb.h -index f2f2e82404..238c37d302 100644 ---- a/lib/dvb/dvb.h -+++ b/lib/dvb/dvb.h -@@ -166,6 +166,7 @@ class eDVBResourceManager: public iObject, public sigc::trackable - eSmartPtrList m_demux; - eSmartPtrList m_frontend, m_simulate_frontend; - void addAdapter(iDVBAdapter *adapter, bool front = false); -+ void setUsbTuner(); - - struct active_channel - { -diff --git a/lib/dvb/fcc.cpp b/lib/dvb/fcc.cpp -new file mode 100644 -index 0000000000..4c52613581 ---- /dev/null -+++ b/lib/dvb/fcc.cpp -@@ -0,0 +1,378 @@ -+#include -+#include -+#include -+#include -+#include -+ -+//#define FCC_DEBUG -+ -+void FCCServiceChannels::addFCCService(const eServiceReference &service) -+{ -+ eDVBChannelID fcc_chid; -+ -+ ((const eServiceReferenceDVB&)service).getChannelID(fcc_chid); -+ -+ if (m_fcc_chids.find(fcc_chid) != m_fcc_chids.end()) -+ m_fcc_chids[fcc_chid] += 1; -+ else -+ m_fcc_chids[fcc_chid] = 1; -+} -+ -+void FCCServiceChannels::removeFCCService(const eServiceReference &service) -+{ -+ eDVBChannelID fcc_chid; -+ ((const eServiceReferenceDVB&)service).getChannelID(fcc_chid); -+ -+ if (m_fcc_chids.find(fcc_chid) != m_fcc_chids.end()) -+ { -+ m_fcc_chids[fcc_chid] -= 1; -+ -+ if (m_fcc_chids[fcc_chid] == 0) -+ m_fcc_chids.erase(fcc_chid); -+ } -+} -+ -+int FCCServiceChannels::getFCCChannelID(std::map &fcc_chids) -+{ -+ if (!m_fcc_chids.size()) return -1; -+ -+ fcc_chids = m_fcc_chids; -+ return 0; -+} -+ -+eFCCServiceManager *eFCCServiceManager::m_instance = (eFCCServiceManager*)0; -+ -+eFCCServiceManager* eFCCServiceManager::getInstance() -+{ -+ return m_instance; -+} -+ -+eFCCServiceManager::eFCCServiceManager(eNavigation *navptr) -+ :m_core(navptr), m_fcc_enable(false) -+{ -+ if (!m_instance) -+ { -+ m_instance = this; -+ } -+} -+ -+eFCCServiceManager::~eFCCServiceManager() -+{ -+ if (m_instance == this) -+ { -+ m_instance = 0; -+ } -+} -+ -+RESULT eFCCServiceManager::playFCCService(const eServiceReference &ref, ePtr &service) -+{ -+ std::map< ePtr, FCCServiceElem >::iterator it = m_FCCServices.begin(); -+ for (;it != m_FCCServices.end();++it) -+ { -+ ASSERT (ref != it->second.m_service_reference); -+ } -+ -+ ASSERT(m_core->m_servicehandler); -+ RESULT res = m_core->m_servicehandler->play(ref, service); -+ if (res) -+ service = 0; -+ else -+ { -+ ePtr conn; -+ service->connectEvent(sigc::mem_fun(*this, &eFCCServiceManager::FCCEvent), conn); -+ -+ FCCServiceElem elem = {ref, conn, fcc_state_preparing, false}; -+ m_FCCServices[service] = elem; -+ -+ res = service->start(); -+ } -+ -+ printFCCServices(); -+ -+ return res; -+} -+ -+void eFCCServiceManager::FCCEvent(iPlayableService* service, int event) -+{ -+ std::map, FCCServiceElem >::iterator it = m_FCCServices.find(service); -+ if (it == m_FCCServices.end()) -+ { -+ eDebug("[eFCCServiceManager] Event for non registered FCC service"); -+ return; -+ } -+ -+ switch (event) -+ { -+ case iPlayableService::evStart: -+ { -+ m_fccServiceChannels.addFCCService(it->second.m_service_reference); -+ break; -+ } -+ case iPlayableService::evStopped: -+ { -+ m_fccServiceChannels.removeFCCService(it->second.m_service_reference); -+ break; -+ } -+ case iPlayableService::evTuneFailed: -+ case iPlayableService::evFccFailed: -+ { -+ eDebug("[eFCCServiceManager] FCCEvent [%s] set service to state failed.", it->second.m_service_reference.toString().c_str()); -+ it->second.m_state = fcc_state_failed; -+ break; -+ } -+ } -+ m_fcc_event(event); -+} -+ -+RESULT eFCCServiceManager::cleanupFCCService() -+{ -+ if (m_FCCServices.size()) -+ { -+ std::map, FCCServiceElem >::iterator it = m_FCCServices.begin(); -+ for (;it != m_FCCServices.end();++it) -+ { -+ eDebug("[eFCCServiceManager] Stop FCC service sref : %s", it->second.m_service_reference.toString().c_str()); -+ it->first->stop(); -+ } -+ -+ m_FCCServices.clear(); -+ } -+ return 0; -+} -+ -+RESULT eFCCServiceManager::stopFCCService(const eServiceReference &sref) -+{ -+ if (m_FCCServices.size()) -+ { -+ std::map, FCCServiceElem >::iterator it = m_FCCServices.begin(); -+ for (; it != m_FCCServices.end();) -+ { -+ if (it->second.m_service_reference == sref) -+ { -+ eDebug("[eFCCServiceManager] Stop FCC service sref : %s", it->second.m_service_reference.toString().c_str()); -+ it->first->stop(); -+ m_FCCServices.erase(it++); -+ } -+ else -+ { -+ ++it; -+ } -+ } -+ printFCCServices(); -+ } -+ return 0; -+} -+ -+RESULT eFCCServiceManager::stopFCCService() -+{ -+ if (m_FCCServices.size()) -+ { -+ std::map, FCCServiceElem >::iterator it = m_FCCServices.begin(); -+ for (; it != m_FCCServices.end();) -+ { -+ if (it->second.m_state == fcc_state_failed) -+ { -+ eDebug("[eFCCServiceManager] Stop FCC service sref : %s", it->second.m_service_reference.toString().c_str()); -+ it->first->stop(); -+ m_FCCServices.erase(it++); -+ } -+ else -+ { -+ ++it; -+ } -+ } -+ -+ printFCCServices(); -+ } -+ return 0; -+} -+ -+RESULT eFCCServiceManager::tryFCCService(const eServiceReference &sref, ePtr &service) -+{ -+ if (!isEnable()) -+ return -1; -+ -+ ePtr new_service = 0; -+ -+ printFCCServices(); -+ -+ int get_fcc_decoding = 0; -+ -+ /* stop previous decoding service */ -+ std::map< ePtr, FCCServiceElem >::iterator it; -+ for (it = m_FCCServices.begin();it != m_FCCServices.end();++it) -+ { -+ if (it->second.m_state == fcc_state_decoding) -+ { -+ ASSERT(get_fcc_decoding == 0); -+ get_fcc_decoding = 1; -+ -+ /* send end event */ -+ m_core->m_event(iPlayableService::evEnd); -+ -+ /* kill service and event */ -+ m_core->m_service_event_conn = 0; -+ m_core->m_runningService = 0; -+ -+ if (it->second.m_useNormalDecode) -+ { -+ /* stop service */ -+ it->first->stop(); -+ m_FCCServices.erase(it++); -+ } -+ else -+ { -+ /* connect to fcc event */ -+ ePtr conn; -+ it->first->connectEvent(sigc::mem_fun(*this, &eFCCServiceManager::FCCEvent), conn); -+ it->second.m_service_event_conn = conn; -+ it->second.m_state = fcc_state_preparing; -+ -+ /* switch to FCC prepare state */ -+ it->first->start(); -+ -+ /* update FCCServiceChannels */ -+ m_fccServiceChannels.addFCCService(it->second.m_service_reference); -+ } -+ break; -+ } -+ } -+ -+ /* search new service */ -+ for (it = m_FCCServices.begin();it != m_FCCServices.end();++it) -+ { -+ if (it->second.m_service_reference == sref) -+ { -+ eDebug("[eFCCServiceManager] Use FCC service sref : %s", it->second.m_service_reference.toString().c_str()); -+ it->second.m_service_event_conn = 0; /* disconnect FCC event */ -+ it->second.m_state = fcc_state_decoding; -+ new_service = it->first; -+ m_fccServiceChannels.removeFCCService(it->second.m_service_reference); -+ break; -+ } -+ } -+ -+ if (new_service) -+ { -+ service = new_service; -+ } -+ -+ else /* If new service is not found in FCC service list, cleanup all FCC prepared services and get new FCC service. */ -+ { -+ cleanupFCCService(); -+ m_core->stopService(); -+ if (eFCCServiceManager::checkAvailable(sref)) -+ { -+ ASSERT(m_core->m_servicehandler); -+ m_core->m_servicehandler->play(sref, service); -+ -+ if (service) -+ { -+ FCCServiceElem elem = {sref, 0, fcc_state_decoding, false}; -+ m_FCCServices[service] = elem; -+ service->start(); // do FCC preparing -+ } -+ } -+ else -+ { -+ return -1; -+ } -+ } -+ -+ printFCCServices(); -+ -+ return 0; -+} -+ -+PyObject *eFCCServiceManager::getFCCServiceList() -+{ -+ ePyObject dest = PyDict_New(); -+ if (dest) -+ { -+ std::map< ePtr, FCCServiceElem >::iterator it = m_FCCServices.begin(); -+ for (;it != m_FCCServices.end();++it) -+ { -+ ePyObject tplist = PyList_New(0); -+ PyList_Append(tplist, PyLong_FromLong((long)it->second.m_state)); -+ PyList_Append(tplist, PyLong_FromLong((long)isLocked(it->first))); -+ PyDict_SetItemString(dest, it->second.m_service_reference.toString().c_str(), tplist); -+ Py_DECREF(tplist); -+ } -+ } -+ -+ else -+ Py_RETURN_NONE; -+ return dest; -+} -+ -+int eFCCServiceManager::isLocked(ePtr service) -+{ -+ ePtr ptr; -+ service->frontendInfo(ptr); -+ return ptr->getFrontendInfo(iFrontendInformation_ENUMS::lockState); -+} -+ -+void eFCCServiceManager::printFCCServices() -+{ -+#ifdef FCC_DEBUG -+ eDebug("[eFCCServiceManager] printFCCServices [*] total size : %d", m_FCCServices.size()); -+ -+ std::map< ePtr, FCCServiceElem >::iterator it = m_FCCServices.begin(); -+ for (;it != m_FCCServices.end();++it) -+ { -+ int isLocked = isLocked(it->first); -+ eDebug("[eFCCServiceManager] printFCCServices [*] sref : %s, state : %d, tune : %d, useNormalDecode : %d", it->second.m_service_reference.toString().c_str(), it->second.m_state, isLocked, it->second.m_useNormalDecode); -+ } -+#else -+ ; -+#endif -+} -+ -+int eFCCServiceManager::getFCCChannelID(std::map &fcc_chids) -+{ -+ eFCCServiceManager *fcc_mng = eFCCServiceManager::getInstance(); -+ if (!fcc_mng) return -1; -+ return fcc_mng->m_fccServiceChannels.getFCCChannelID(fcc_chids); -+} -+ -+bool eFCCServiceManager::checkAvailable(const eServiceReference &ref) -+{ -+ int serviceType = ref.getData(0); -+ eFCCServiceManager *fcc_mng = eFCCServiceManager::getInstance(); -+ -+ if ((ref.type == 1) && ref.path.empty() && (serviceType != 2) && (serviceType != 10) && fcc_mng) // no PVR, streaming, radio channel.. -+ return fcc_mng->isEnable(); -+ return false; -+} -+ -+bool eFCCServiceManager::isStateDecoding(iPlayableService* service) -+{ -+ std::map, FCCServiceElem >::iterator it = m_FCCServices.find(service); -+ if (it != m_FCCServices.end()) -+ { -+ return (it->second.m_state == fcc_state_decoding); -+ } -+ else -+ { -+ eDebug("[eFCCServiceManager] Non registered FCC service"); -+ } -+ -+ return false; -+} -+ -+void eFCCServiceManager::setNormalDecoding(iPlayableService* service) -+{ -+ std::map, FCCServiceElem >::iterator it = m_FCCServices.find(service); -+ if (it != m_FCCServices.end()) -+ { -+ eDebug("[eFCCServiceManager] setNormalDecoding [%s] set to use normal decoding.", it->second.m_service_reference.toString().c_str()); -+ it->second.m_useNormalDecode = true; -+ } -+ else -+ { -+ eDebug("[eFCCServiceManager] Non registered FCC service"); -+ } -+} -+ -+DEFINE_REF(eFCCServiceManager); -+ -diff --git a/lib/dvb/fcc.h b/lib/dvb/fcc.h -new file mode 100644 -index 0000000000..136526a80f ---- /dev/null -+++ b/lib/dvb/fcc.h -@@ -0,0 +1,70 @@ -+#ifndef __dvb_fcc_h -+#define __dvb_fcc_h -+ -+#include -+#include -+#include -+#include -+ -+class eNavigation; -+ -+class FCCServiceChannels -+{ -+private: -+ std::map m_fcc_chids; -+ -+public: -+ void addFCCService(const eServiceReference &service); -+ void removeFCCService(const eServiceReference &service); -+ int getFCCChannelID(std::map &fcc_chids); -+}; -+ -+typedef struct _tagFccElem -+{ -+ eServiceReference m_service_reference; -+ ePtr m_service_event_conn; -+ int m_state; -+ bool m_useNormalDecode; -+}FCCServiceElem; -+ -+class eFCCServiceManager: public iObject, public sigc::trackable -+{ -+ DECLARE_REF(eFCCServiceManager); -+private: -+ eNavigation *m_core; -+ static eFCCServiceManager* m_instance; -+ std::map, FCCServiceElem, std::less > m_FCCServices; -+ FCCServiceChannels m_fccServiceChannels; -+ -+ bool m_fcc_enable; -+ -+ void FCCEvent(iPlayableService* service, int event); -+public: -+ PSignal1 m_fcc_event; -+ static eFCCServiceManager* getInstance(); -+ eFCCServiceManager(eNavigation *navptr); -+ ~eFCCServiceManager(); -+ -+ enum -+ { -+ fcc_state_preparing, -+ fcc_state_decoding, -+ fcc_state_failed -+ }; -+ SWIG_VOID(RESULT) playFCCService(const eServiceReference &ref, ePtr &SWIG_OUTPUT); -+ RESULT stopFCCService(const eServiceReference &sref); -+ RESULT stopFCCService(); -+ RESULT cleanupFCCService(); -+ RESULT tryFCCService(const eServiceReference &service, ePtr &ptr); -+ PyObject *getFCCServiceList(); -+ void printFCCServices(); -+ int isLocked(ePtr service); -+ static int getFCCChannelID(std::map &fcc_chids); -+ static bool checkAvailable(const eServiceReference &ref); -+ void setFCCEnable(int enable) { m_fcc_enable = (enable != 0); } -+ bool isEnable() { return m_fcc_enable; } -+ bool isStateDecoding(iPlayableService* service); -+ void setNormalDecoding(iPlayableService* service); -+}; -+ -+#endif /* __dvb_fcc_h */ -diff --git a/lib/dvb/fccdecoder.cpp b/lib/dvb/fccdecoder.cpp -new file mode 100644 -index 0000000000..68e9af2a40 ---- /dev/null -+++ b/lib/dvb/fccdecoder.cpp -@@ -0,0 +1,75 @@ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+bool eFCCDecoder::isDestroyed = false; -+eFCCDecoder::eFCCDecoder() -+{ -+ int index = 0; -+ -+ eDebug("[eFCCDecoder] Scanning for FCC device files.."); -+ while(1) -+ { -+ struct stat s; -+ char filename[128]; -+ sprintf(filename, "/dev/fcc%d", index); -+ if (stat(filename, &s)) -+ break; -+ -+ eDebug("[eFCCDecoder] %s found..", filename); -+ m_fccs.push_back(-1); -+ index++; -+ } -+} -+ -+eFCCDecoder::~eFCCDecoder() -+{ -+ isDestroyed = true; -+} -+ -+int eFCCDecoder::allocateFcc() -+{ -+ int fccFd = -1; -+ for(unsigned int i = 0; i < m_fccs.size(); i++) -+ { -+ if (m_fccs[i]== -1) -+ { -+ char filename[128]; -+ sprintf(filename, "/dev/fcc%d", i); -+ -+ fccFd = ::open(filename, O_RDWR); -+ if (fccFd < 0) -+ eDebug("[eFCCDecoder] Open %s failed!", filename); -+ -+ else -+ eDebug("[eFCCDecoder] Alloc %s", filename); -+ -+ m_fccs[i] = fccFd; -+ break; -+ } -+ } -+ -+ return fccFd; -+} -+ -+void eFCCDecoder::freeFcc(int fccFd) -+{ -+ if (fccFd < 0) -+ return; -+ -+ for(unsigned int i = 0; i < m_fccs.size(); i++) -+ { -+ if (m_fccs[i]== fccFd) -+ { -+ m_fccs[i] = -1; -+ eDebug("[eFCCDecoder] Close /dev/fcc%d", i); -+ ::close(fccFd); -+ break; -+ } -+ } -+} -+ -diff --git a/lib/dvb/fccdecoder.h b/lib/dvb/fccdecoder.h -new file mode 100644 -index 0000000000..c7b57c5378 ---- /dev/null -+++ b/lib/dvb/fccdecoder.h -@@ -0,0 +1,28 @@ -+#ifndef __dvb_fcc_decoder_h -+#define __dvb_fcc_decoder_h -+ -+#include -+ -+class eFCCDecoder -+{ -+ std::vector m_fccs; -+ static eFCCDecoder *instance; -+ static bool isDestroyed; -+ -+public: -+ eFCCDecoder(); -+ ~eFCCDecoder(); -+ int allocateFcc(); -+ void freeFcc(int fccFd); -+ -+ static eFCCDecoder* getInstance() -+ { -+ if (isDestroyed) -+ return NULL; -+ -+ static eFCCDecoder instance; -+ return &instance; -+ } -+}; -+ -+#endif /* __dvb_fcc_decoder_h */ -diff --git a/lib/dvb/frontend.cpp b/lib/dvb/frontend.cpp -index 98999839c0..37f19adf23 100644 ---- a/lib/dvb/frontend.cpp -+++ b/lib/dvb/frontend.cpp -@@ -556,7 +556,7 @@ int eDVBFrontend::PriorityOrder=0; - int eDVBFrontend::PreferredFrontendIndex = -1; - - eDVBFrontend::eDVBFrontend(const char *devicenodename, int fe, int &ok, bool simulate, eDVBFrontend *simulate_fe) -- :m_simulate(simulate), m_enabled(false), m_fbc(false), m_simulate_fe(simulate_fe), m_type(-1), m_dvbid(fe), m_slotid(fe) -+ :m_simulate(simulate), m_enabled(false), m_fbc(false), m_is_usbtuner(false), m_simulate_fe(simulate_fe), m_type(-1), m_dvbid(fe), m_slotid(fe) - ,m_fd(-1), m_dvbversion(0), m_rotor_mode(false), m_need_rotor_workaround(false), m_multitype(false), m_voltage5_terrestrial(-1) - ,m_state(stateClosed), m_timeout(0), m_tuneTimer(0) - { -@@ -1592,6 +1592,8 @@ int eDVBFrontend::readFrontendData(int type) - return !!(readFrontendData(iFrontendInformation_ENUMS::frontendStatus) & FE_HAS_SYNC); - case iFrontendInformation_ENUMS::frontendNumber: - return m_slotid; -+ case iFrontendInformation_ENUMS::isUsbTuner: -+ return m_is_usbtuner; - case iFrontendInformation_ENUMS::frontendStatus: - { - unsigned int status; -diff --git a/lib/dvb/frontend.h b/lib/dvb/frontend.h -index c6c74d7d56..4ee8b3b876 100644 ---- a/lib/dvb/frontend.h -+++ b/lib/dvb/frontend.h -@@ -86,6 +86,7 @@ private: - bool m_simulate; - bool m_enabled; - bool m_fbc; -+ bool m_is_usbtuner; - eDVBFrontend *m_simulate_fe; // only used to set frontend type in dvb.cpp - int m_type; - int m_dvbid; -@@ -181,6 +182,7 @@ public: - void set_FBCTuner(bool yesno) { m_fbc = yesno; } - bool getEnabled() { return m_enabled; } - void setEnabled(bool enable) { m_enabled = enable; } -+ void setUSBTuner(bool yesno) { m_is_usbtuner = yesno; } - bool is_multistream(); - std::string getCapabilities(); - }; -diff --git a/lib/dvb/idvb.h b/lib/dvb/idvb.h -index 0e140f9ef7..d6a8994520 100644 ---- a/lib/dvb/idvb.h -+++ b/lib/dvb/idvb.h -@@ -698,6 +698,7 @@ public: - virtual RESULT getCAAdapterID(uint8_t &id)=0; - virtual RESULT flush()=0; - virtual int openDVR(int flags)=0; -+ virtual int getSource()=0; - }; - - class iTSMPEGDecoder: public iObject -@@ -748,6 +749,14 @@ public: - /** Display any complete data as fast as possible */ - virtual RESULT setTrickmode()=0; - -+ virtual RESULT prepareFCC(int fe_id, int vpid, int vtype, int pcrpid)=0; -+ -+ virtual RESULT fccDecoderStart()=0; -+ -+ virtual RESULT fccDecoderStop()=0; -+ -+ virtual RESULT fccUpdatePids(int fe_id, int vpid, int vtype, int pcrpid)=0; -+ - virtual RESULT getPTS(int what, pts_t &pts) = 0; - - virtual RESULT showSinglePic(const char *filename) = 0; -diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp -index 1d3c454bcf..b8c8da4294 100644 ---- a/lib/dvb/pmt.cpp -+++ b/lib/dvb/pmt.cpp -@@ -32,6 +32,8 @@ eDVBServicePMTHandler::eDVBServicePMTHandler() - m_pmt_pid = -1; - m_dsmcc_pid = -1; - m_service_type = livetv; -+ m_ca_disabled = false; -+ m_pmt_ready = false; - eDVBResourceManager::getInstance(m_resourceManager); - CONNECT(m_PAT.tableReady, eDVBServicePMTHandler::PATready); - CONNECT(m_AIT.tableReady, eDVBServicePMTHandler::AITready); -@@ -150,6 +152,7 @@ void eDVBServicePMTHandler::PMTready(int error) - serviceEvent(eventNoPMT); - else - { -+ m_pmt_ready = true; - m_have_cached_program = false; - serviceEvent(eventNewProgramInfo); - switch (m_service_type) -@@ -174,8 +177,11 @@ void eDVBServicePMTHandler::PMTready(int error) - { - registerCAService(); - } -- eDVBCIInterfaces::getInstance()->recheckPMTHandlers(); -- eDVBCIInterfaces::getInstance()->gotPMT(this); -+ if (!m_ca_disabled) -+ { -+ eDVBCIInterfaces::getInstance()->recheckPMTHandlers(); -+ eDVBCIInterfaces::getInstance()->gotPMT(this); -+ } - } - if (m_ca_servicePtr) - { -@@ -646,6 +652,9 @@ int eDVBServicePMTHandler::getProgramInfo(program &program) - { - program.pmtPid = pmtpid; - } -+ -+ program.isCached = true; -+ - if ( vpidtype == -1 ) - vpidtype = videoStream::vtMPEG2; - if ( cached_vpid != -1 ) -@@ -901,11 +910,14 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, ePtr &s - if (!simulate) - eDebug("[eDVBServicePMTHandler] allocate Channel: res %d", res); - -+ if (!res) -+ serviceEvent(eventChannelAllocated); -+ - ePtr db; - if (!m_resourceManager->getChannelList(db)) - db->getService((eServiceReferenceDVB&)m_reference, m_service); - -- if (!res && !simulate) -+ if (!res && !simulate && !m_ca_disabled) - eDVBCIInterfaces::getInstance()->addPMTHandler(this); - } else if (!simulate) // no simulation of playback services - { -@@ -1038,3 +1050,24 @@ void eDVBServicePMTHandler::free() - m_pvr_channel = 0; - m_demux = 0; - } -+ -+void eDVBServicePMTHandler::addCaHandler() -+{ -+ m_ca_disabled = false; -+ if (m_channel) -+ { -+ eDVBCIInterfaces::getInstance()->addPMTHandler(this); -+ if (m_pmt_ready) -+ { -+ eDVBCIInterfaces::getInstance()->recheckPMTHandlers(); -+ eDVBCIInterfaces::getInstance()->gotPMT(this); -+ } -+ } -+} -+ -+void eDVBServicePMTHandler::removeCaHandler() -+{ -+ m_ca_disabled = true; -+ if (m_channel) -+ eDVBCIInterfaces::getInstance()->removePMTHandler(this); -+} -diff --git a/lib/dvb/pmt.h b/lib/dvb/pmt.h -index e47589946c..40dbe1c926 100644 ---- a/lib/dvb/pmt.h -+++ b/lib/dvb/pmt.h -@@ -82,6 +82,9 @@ class eDVBServicePMTHandler: public eDVBPMTParser - int m_use_decode_demux; - uint8_t m_decode_demux_num; - ePtr m_no_pat_entry_delay; -+ -+ bool m_pmt_ready; -+ bool m_ca_disabled; - public: - eDVBServicePMTHandler(); - ~eDVBServicePMTHandler(); -@@ -112,6 +115,7 @@ public: - eventHBBTVInfo, /* HBBTV information was detected in the AIT */ - - eventStopped, -+ eventChannelAllocated, - }; - #ifndef SWIG - sigc::signal serviceEvent; -@@ -131,6 +135,9 @@ public: - void resetCachedProgram() { m_have_cached_program = false; } - void sendEventNoPatEntry(); - void getHBBTVUrl(std::string &ret) const { ret = m_HBBTVUrl; } -+ void setCaDisable(bool disable) { m_ca_disabled = disable; } -+ void addCaHandler(); -+ void removeCaHandler(); - - enum serviceType - { -diff --git a/lib/dvb/pmtparse.cpp b/lib/dvb/pmtparse.cpp -index 5dff96c731..9e8293ebd4 100644 ---- a/lib/dvb/pmtparse.cpp -+++ b/lib/dvb/pmtparse.cpp -@@ -29,6 +29,8 @@ void eDVBPMTParser::clearProgramInfo(program &program) - program.pmtPid = -1; - program.textPid = -1; - program.aitPid = -1; -+ program.isCached = false; -+ program.pmtVersion = -1; - program.dsmccPid = -1; - program.serviceId = -1; - program.adapterId = -1; -@@ -67,6 +69,7 @@ int eDVBPMTParser::getProgramInfo(program &program) - eDVBTableSpec table_spec; - ptr->getSpec(table_spec); - program.pmtPid = table_spec.pid < 0x1fff ? table_spec.pid : -1; -+ program.pmtVersion = table_spec.version; - - for (const auto i : ptr->getSections()) - { -diff --git a/lib/dvb/pmtparse.h b/lib/dvb/pmtparse.h -index 3374355b87..8e82ead877 100644 ---- a/lib/dvb/pmtparse.h -+++ b/lib/dvb/pmtparse.h -@@ -90,6 +90,8 @@ public: - int serviceId; - int adapterId; - int demuxId; -+ int pmtVersion; -+ bool isCached; - bool isCrypted() { return !caids.empty(); } - }; - -diff --git a/lib/nav/core.cpp b/lib/nav/core.cpp -index 22fe033586..41ea421265 100644 ---- a/lib/nav/core.cpp -+++ b/lib/nav/core.cpp -@@ -1,6 +1,7 @@ - #include - #include - #include -+#include - - eNavigation* eNavigation::instance; - -@@ -26,10 +27,15 @@ void eNavigation::recordEvent(iRecordableService* service, int event) - - RESULT eNavigation::playService(const eServiceReference &service) - { -- stopService(); -+ RESULT res = -1; -+ -+ if (! m_fccmgr || m_fccmgr->tryFCCService(service, m_runningService) == -1) -+ { -+ stopService(); -+ ASSERT(m_servicehandler); -+ res = m_servicehandler->play(service, m_runningService); -+ } - -- ASSERT(m_servicehandler); -- RESULT res = m_servicehandler->play(service, m_runningService); - if (m_runningService) - { - m_runningService->setTarget(m_decoder); -@@ -72,6 +78,8 @@ RESULT eNavigation::stopService(void) - - /* kill service. */ - m_service_event_conn = 0; -+ -+ m_fccmgr && m_fccmgr->cleanupFCCService(); - return 0; - } - -@@ -160,6 +168,8 @@ eNavigation::eNavigation(iServiceHandler *serviceHandler, int decoder) - ASSERT(serviceHandler); - m_servicehandler = serviceHandler; - m_decoder = decoder; -+ if (decoder == 0 ) -+ m_fccmgr = new eFCCServiceManager(this); - instance = this; - } - -diff --git a/lib/nav/core.h b/lib/nav/core.h -index accc007c0e..2334c553c3 100644 ---- a/lib/nav/core.h -+++ b/lib/nav/core.h -@@ -6,6 +6,7 @@ - #include - #include - #include -+#include - - class eNavigation: public iObject, public sigc::trackable - { -@@ -25,6 +26,9 @@ class eNavigation: public iObject, public sigc::trackable - - sigc::signal,int)> m_record_event; - void recordEvent(iRecordableService* service, int event); -+ -+ friend class eFCCServiceManager; -+ ePtr m_fccmgr; - public: - - RESULT playService(const eServiceReference &service); -diff --git a/lib/python/Components/ServiceList.py b/lib/python/Components/ServiceList.py -index 10b693ca05..cf69e41e1e 100644 ---- a/lib/python/Components/ServiceList.py -+++ b/lib/python/Components/ServiceList.py -@@ -278,6 +278,9 @@ class ServiceList(GUIComponent): - self.l.getNext(r) - return r - -+ def getList(self): -+ return self.l.getList() -+ - def atBegin(self): - return self.instance.atBegin() - -diff --git a/lib/python/Components/SystemInfo.py b/lib/python/Components/SystemInfo.py -index 35530ec41a..6f612839fe 100644 ---- a/lib/python/Components/SystemInfo.py -+++ b/lib/python/Components/SystemInfo.py -@@ -301,6 +301,7 @@ SystemInfo["VideoModes"] = getChipSetString() in ( # 2160p and 1080p capable ha - SystemInfo["FbcTunerPowerAlwaysOn"] = getBoxType() in ("vusolo4k", "vuduo4k", "vuduo4kse", "vuultimo4k", "vuuno4k", "vuuno4kse") - SystemInfo["HasPhysicalLoopthrough"] = ["Vuplus DVB-S NIM(AVL2108)", "GIGA DVB-S2 NIM (Internal)"] - SystemInfo["HasFBCtuner"] = ["Vuplus DVB-C NIM(BCM3158)", "Vuplus DVB-C NIM(BCM3148)", "Vuplus DVB-S NIM(7376 FBC)", "Vuplus DVB-S NIM(45308X FBC)", "Vuplus DVB-S NIM(45208 FBC)", "DVB-S2 NIM(45208 FBC)", "DVB-S2X NIM(45308X FBC)", "DVB-S2 NIM(45308 FBC)", "DVB-C NIM(3128 FBC)", "BCM45208", "BCM45308X", "BCM3158"] -+SystemInfo["FCCactive"] = False - SystemInfo["rc_model"] = rc_model.getRcFolder() - SystemInfo["mapKeyInfoToEpgFunctions"] = SystemInfo["rc_model"] in ("vu", "vu2", "vu3", "vu4") # due to button limitations of the remote control - SystemInfo["hasDuplicateVideoAndPvrButtons"] = SystemInfo["rc_model"] in ("edision3",) # Allow multiple functions only if both buttons are present -diff --git a/lib/python/Navigation.py b/lib/python/Navigation.py -index 150cecb026..4b175a12ee 100644 ---- a/lib/python/Navigation.py -+++ b/lib/python/Navigation.py -@@ -38,6 +38,7 @@ class Navigation: - self.currentlyPlayingServiceReference = None - self.currentlyPlayingServiceOrGroup = None - self.currentlyPlayingService = None -+ self.skipServiceReferenceReset = False - self.RecordTimer = RecordTimer.RecordTimer() - self.PowerTimer = PowerTimer.PowerTimer() - self.__wasTimerWakeup = False -@@ -96,8 +97,9 @@ class Navigation: - for x in self.event: - x(i) - if i == iPlayableService.evEnd: -- self.currentlyPlayingServiceReference = None -- self.currentlyPlayingServiceOrGroup = None -+ if not self.skipServiceReferenceReset: -+ self.currentlyPlayingServiceReference = None -+ self.currentlyPlayingServiceOrGroup = None - self.currentlyPlayingService = None - - def dispatchRecordEvent(self, rec_service, event): -@@ -170,7 +172,10 @@ class Navigation: - else: - playref = ref - if self.pnav: -- self.pnav.stopService() -+ if not SystemInfo["FCCactive"]: -+ self.pnav.stopService() -+ else: -+ self.skipServiceReferenceReset = True - self.currentlyPlayingServiceReference = playref - self.currentlyPlayingServiceOrGroup = ref - if InfoBarInstance and InfoBarInstance.servicelist.servicelist.setCurrent(ref, adjust): -@@ -212,6 +217,7 @@ class Navigation: - self.retryServicePlayTimer = eTimer() - self.retryServicePlayTimer.callback.append(boundFunction(self.playService, ref, checkParentalControl, forceRestart, adjust)) - self.retryServicePlayTimer.start(500, True) -+ self.skipServiceReferenceReset = False - if setPriorityFrontend: - setPreferredTuner(int(config.usage.frontend_priority.value)) - return 0 -diff --git a/lib/python/Plugins/SystemPlugins/FastChannelChange/Makefile.am b/lib/python/Plugins/SystemPlugins/FastChannelChange/Makefile.am -new file mode 100644 -index 0000000000..ae91ed5776 ---- /dev/null -+++ b/lib/python/Plugins/SystemPlugins/FastChannelChange/Makefile.am -@@ -0,0 +1,7 @@ -+installdir = $(pkglibdir)/python/Plugins/SystemPlugins/FastChannelChange -+ -+SUBDIRS = meta -+ -+install_PYTHON = \ -+ __init__.py \ -+ plugin.py -diff --git a/lib/python/Plugins/SystemPlugins/FastChannelChange/__init__.py b/lib/python/Plugins/SystemPlugins/FastChannelChange/__init__.py -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/Makefile.am b/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/Makefile.am -new file mode 100644 -index 0000000000..4e3b9e942c ---- /dev/null -+++ b/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/Makefile.am -@@ -0,0 +1,3 @@ -+installdir = $(datadir)/meta -+ -+dist_install_DATA = plugin_fastchannelchange.xml -diff --git a/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/plugin_fastchannelchange.xml b/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/plugin_fastchannelchange.xml -new file mode 100644 -index 0000000000..1527085fca ---- /dev/null -+++ b/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/plugin_fastchannelchange.xml -@@ -0,0 +1,16 @@ -+ -+ -+ -+ -+ -+ hschang -+ FastChannelChange -+ enigma2-plugin-systemplugins-fastchannelchange -+ Fast Channel Change -+ Fast Channel Change -+ -+ -+ -+ -+ -+ -diff --git a/lib/python/Plugins/SystemPlugins/FastChannelChange/plugin.py b/lib/python/Plugins/SystemPlugins/FastChannelChange/plugin.py -new file mode 100644 -index 0000000000..570e036ca7 ---- /dev/null -+++ b/lib/python/Plugins/SystemPlugins/FastChannelChange/plugin.py -@@ -0,0 +1,576 @@ -+#!/usr/bin/python -+# -*- coding: utf-8 -*- -+from Plugins.Plugin import PluginDescriptor -+from Screens.Screen import Screen -+from Screens.InfoBar import InfoBar -+from Components.config import config, getConfigListEntry, ConfigSubsection, ConfigYesNo, ConfigSelection -+from Components.ConfigList import ConfigListScreen -+from Components.Sources.StaticText import StaticText -+from Components.ServiceEventTracker import ServiceEventTracker -+from Components.SystemInfo import SystemInfo -+from enigma import iPlayableService, eTimer, eServiceReference, iRecordableService -+import os -+import glob -+from enigma import eFCCServiceManager -+ -+g_max_fcc = len(glob.glob('/dev/fcc?')) -+g_default_fcc = (g_max_fcc) > 5 and 5 or g_max_fcc -+ -+config.plugins.fccsetup = ConfigSubsection() -+config.plugins.fccsetup.activate = ConfigYesNo(default = False) -+config.plugins.fccsetup.maxfcc = ConfigSelection(default = str(g_default_fcc), choices = list((str(n), str(n)) for n in range(2, g_max_fcc+1))) -+config.plugins.fccsetup.zapupdown = ConfigYesNo(default = True) -+config.plugins.fccsetup.history = ConfigYesNo(default = False) -+config.plugins.fccsetup.priority = ConfigSelection(default = "zapupdown", choices = { "zapupdown" : _("Zap Up/Down"), "historynextback" : _("History Prev/Next") }) -+config.plugins.fccsetup.disableforrec = ConfigYesNo(default = True) -+ -+FccInstance = None -+ -+def FCCChanged(): -+ if FccInstance: -+ FccInstance.FCCSetupChanged() -+ -+def checkSupportFCC(): -+ global g_max_fcc -+ return bool(g_max_fcc) -+ -+class FCCSupport: -+ def __init__(self, session): -+ self.session = session -+ -+ self.fccmgr = eFCCServiceManager.getInstance(); -+ -+ self.fccList = [] -+ -+ self.createListTimer = eTimer() -+ self.createListTimer.callback.append(self.FCCCreateList) -+ -+ self.getSrefTimer = eTimer() -+ self.getSrefTimer.callback.append(self.FCCGetCurSref) -+ -+ self.eventList = [] -+ self.fccEventTimer = eTimer() -+ self.fccEventTimer.callback.append(self.FCCApplyEvent) -+ -+ self.fccForceStartTimer = eTimer() -+ self.fccForceStartTimer.callback.append(self.FCCForceStart) -+ -+ self.fccResetTimer = eTimer() -+ self.fccResetTimer.callback.append(self.FCCResetTimerForREC) -+ -+ self.activating = False -+ -+ self.fccSetupActivate = checkSupportFCC() and config.plugins.fccsetup.activate.value -+ self.maxFCC = int(config.plugins.fccsetup.maxfcc.value) -+ self.zapdownEnable = config.plugins.fccsetup.zapupdown.value -+ self.historyEnable = config.plugins.fccsetup.history.value -+ self.priority = config.plugins.fccsetup.priority.value -+ self.disableforrec = config.plugins.fccsetup.disableforrec.value -+ self.fccmgr.setFCCEnable(int(self.fccSetupActivate)) -+ -+ self.setProcFCC(self.fccSetupActivate) -+ self.fccTimeoutTimer = eTimer() -+ self.fccTimeoutTimer.callback.append(self.FCCTimeout) -+ self.fccTimeoutEventCode = 0x102 -+ self.fccTimeoutWait = None -+ -+ self.fccmgr.m_fcc_event.get().append(self.FCCGetEvent) -+ -+ self.getRecordings() -+ -+ self.__event_tracker = None -+ self.onClose = [] -+ self.changeEventTracker() -+ SystemInfo["FCCactive"] = self.fccSetupActivate -+# from Screens.PictureInPicture import on_pip_start_stop -+# on_pip_start_stop.append(self.FCCForceStopforPIP) -+ -+ def setProcFCC(self, value): -+ procPath = "/proc/stb/frontend/fbc/fcc" -+ if os.access(procPath, os.W_OK): -+ open(procPath, 'w').write(value and "enable" or "disable") -+ else: -+ print("[FCCSupport] write fail! : ", procPath) -+ -+ def gotRecordEvent(self, service, event): -+ if self.disableforrec: -+ if (not self.recordings) and (event == iRecordableService.evTuneStart): -+ self.getRecordings() -+ if self.recordings: -+ self.FCCForceStopForREC() -+ -+ elif event == iRecordableService.evEnd: -+ self.getRecordings() -+ if not self.recordings: -+ self.FCCForceStart() -+ else: -+ if event == iRecordableService.evTuneStart: -+ self.FCCForceStopAndStart() -+ -+ elif event == iRecordableService.evEnd: -+ self.fccForceStartTimer.stop() -+ self.fccResetTimer.start(2000, True) -+ -+ def FCCForceStart(self): -+ self.enableEventTracker(True) -+ self.getEvStart() -+ self.getEvTunedIn() -+ -+ def FCCForceStop(self): -+ self.enableEventTracker(False) -+ self.FCCDisableServices() -+ self.FCCStopAllServices() -+ -+ def FCCForceStopAndStart(self): -+ self.fccResetTimer.stop() -+ self.FCCForceStop() -+ self.fccForceStartTimer.start(2000, True) -+ -+ def FCCForceStopforPIP(self): -+ self.FCCForceStopAndStart() -+ -+ def FCCForceStopForREC(self): -+ self.FCCForceStop() -+ -+ def FCCResetTimerForREC(self): -+ self.FCCForceStopForREC() -+ self.FCCForceStart() -+ -+ def FCCSetupChanged(self): -+ fcc_changed = False -+ -+ newFccSetupActivate = checkSupportFCC() and config.plugins.fccsetup.activate.value -+ if self.fccSetupActivate != newFccSetupActivate: -+ self.fccSetupActivate = newFccSetupActivate -+ self.setProcFCC(self.fccSetupActivate) -+ fcc_changed = True -+ -+ if int(config.plugins.fccsetup.maxfcc.value) != self.maxFCC: -+ self.maxFCC = int(config.plugins.fccsetup.maxfcc.value) -+ fcc_changed = True -+ -+ if self.zapdownEnable != config.plugins.fccsetup.zapupdown.value: -+ self.zapdownEnable = config.plugins.fccsetup.zapupdown.value -+ fcc_changed = True -+ -+ if self.historyEnable != config.plugins.fccsetup.history.value: -+ self.historyEnable = config.plugins.fccsetup.history.value -+ fcc_changed = True -+ -+ if self.priority != config.plugins.fccsetup.priority.value: -+ self.priority = config.plugins.fccsetup.priority.value -+ fcc_changed = True -+ -+ if self.disableforrec != config.plugins.fccsetup.disableforrec.value: -+ self.disableforrec = config.plugins.fccsetup.disableforrec.value -+ fcc_changed = True -+ -+ self.getRecordings() -+ self.changeEventTracker() -+ -+ if (not self.fccSetupActivate) or (self.disableforrec and self.recordings): -+ self.FCCDisableServices() -+ -+ if fcc_changed: -+ self.fccmgr.setFCCEnable(int(self.fccSetupActivate)) -+ SystemInfo["FCCactive"] = self.fccSetupActivate -+ curPlaying = self.session.nav.getCurrentlyPlayingServiceReference() -+ if curPlaying: -+ self.session.nav.stopService() -+ self.session.nav.playService(curPlaying) -+ -+ # get current recording state -+ def getRecordings(self): -+ self.recordings = bool(self.session.nav.getRecordings()) -+ -+ def addRecordEventCallback(self, enable=True): -+ if enable: -+ if self.gotRecordEvent not in self.session.nav.record_event: -+ self.session.nav.record_event.append(self.gotRecordEvent) -+ else: -+ if self.gotRecordEvent in self.session.nav.record_event: -+ self.session.nav.record_event.remove(self.gotRecordEvent) -+ -+ def changeEventTracker(self): -+ if self.fccSetupActivate: -+ self.addRecordEventCallback(True) -+ if self.disableforrec and self.recordings: -+ self.enableEventTracker(False) -+ else: -+ self.enableEventTracker(True) -+ else: -+ self.addRecordEventCallback(False) -+ self.enableEventTracker(False) -+ -+ def enableEventTracker(self, activate): -+ if activate: -+ if not self.__event_tracker: -+ self.__event_tracker = ServiceEventTracker(screen=self, eventmap= -+ { -+ iPlayableService.evStart: self.getEvStart, -+ iPlayableService.evEnd: self.getEvEnd, -+ iPlayableService.evTunedIn: self.getEvTunedIn, -+ iPlayableService.evTuneFailed: self.getEvTuneFailed -+ }) -+ -+ elif self.__event_tracker: -+ # run ServiceEventTracker.__del_event() -+ for x in self.onClose: -+ x() -+ -+ self.onClose = [] -+ self.__event_tracker = None -+ -+ def getEvStart(self): -+ self.createListTimer.start(0, True) -+ -+ def getEvEnd(self): -+ self.FCCDisableServices() -+ -+ def getEvTunedIn(self): -+ self.FCCTryStart() -+ -+ def getEvTuneFailed(self): -+ self.FCCTryStart() -+ -+ def isPlayableFCC(self, sref): -+ playable = True -+ if isinstance(sref, str): -+ sref = eServiceReference(sref) -+ -+ if sref.type != 1: -+ playable = False -+ -+ elif sref.getPath(): # is PVR? or streaming? -+ playable = False -+ -+ elif int(sref.getData(0)) in (2, 10): # is RADIO? -+ playable = False -+ -+ return playable -+ -+ def getZapUpDownList(self): -+ fccZapUpDownList = [] -+ serviceList = InfoBar.instance.servicelist.servicelist.getList() -+ curServiceRef = InfoBar.instance.servicelist.servicelist.getCurrent().toString() -+ -+ serviceRefList = [] -+ for idx in range(len(serviceList)): -+ sref = serviceList[idx].toString() -+ if (sref.split(':')[1] == '0') and self.isPlayableFCC(sref) : # remove marker -+ serviceRefList.append(sref) -+ -+ if curServiceRef in serviceRefList: -+ serviceRefListSize = len(serviceRefList) -+ curServiceIndex = serviceRefList.index(curServiceRef) -+ -+ for x in range(self.maxFCC-1): -+ if x > (serviceRefListSize-2): # if not ((x+1) <= (serviceRefListSize-1)) -+ break -+ -+ idx = (x // 2) + 1 -+ if x % 2: -+ idx *= -1 # idx : [ 1, -1, 2, -2, 3, -3, 4, -4 ....] -+ idx = (curServiceIndex+idx) % serviceRefListSize # calc wraparound -+ try: -+ fccZapUpDownList.append(serviceRefList[idx]) -+ except: -+ print("[FCCCreateList] append error, idx : %d" % idx) -+ break -+ -+ return fccZapUpDownList -+ -+ def getHistoryPrevNextList(self): -+ historyList = [] -+ history = InfoBar.instance.servicelist.history[:] -+ history_pos = InfoBar.instance.servicelist.history_pos -+ history_len = len(history) -+ -+ if history_len > 1 and history_pos > 0: -+ historyPrev = history[history_pos-1][:][-1].toString() -+ if self.isPlayableFCC(historyPrev): -+ historyList.append(historyPrev) -+ -+ if history_len > 1 and history_pos < (history_len-1): -+ historyNext = history[history_pos+1][:][-1].toString() -+ if self.isPlayableFCC(historyNext): -+ historyList.append(historyNext) -+ -+ return historyList -+ -+ def FCCCreateList(self): -+ if (not self.fccSetupActivate) or (self.disableforrec and self.recordings): -+ return -+ -+ if InfoBar.instance: -+ self.fccList = [] -+ fccZapUpDownList = [] -+ historyList = [] -+ -+ if self.zapdownEnable: -+ fccZapUpDownList = self.getZapUpDownList() -+ -+ if self.historyEnable: -+ historyList = self.getHistoryPrevNextList() -+ -+ if self.priority == "zapupdown": -+ fccZapDownLen = len(fccZapUpDownList) -+ if fccZapDownLen: -+ size = fccZapDownLen > 2 and 2 or fccZapDownLen -+ self.fccList = fccZapUpDownList[:size] -+ fccZapUpDownList = fccZapUpDownList[size:] -+ -+ self.addFCCList(historyList) -+ self.addFCCList(fccZapUpDownList) -+ else: -+ self.addFCCList(historyList) -+ self.addFCCList(fccZapUpDownList) -+ -+ self.FCCReconfigureFccList() -+ -+ def addFCCList(self, newlist): -+ fccListMaxLen = self.maxFCC-1 -+ for sref in newlist: -+ if len(self.fccList) >= fccListMaxLen: -+ break -+ -+ if sref not in self.fccList: -+ self.fccList.append(sref) -+ -+ def FCCReconfigureFccList(self): -+ stopFCCList = [] -+ currentFCCList = self.fccmgr.getFCCServiceList() -+ -+ for (sref, value) in currentFCCList.items(): -+ state = value[0] -+ -+ if state == 2: # fcc_state_failed -+ stopFCCList.append(sref) -+ -+ elif sref in self.fccList: # check conflict FCC channel (decoder/prepare) -+ self.fccList.remove(sref) -+ -+ elif state == 0: # fcc_state_preparing -+ stopFCCList.append(sref) -+ -+ for sref in stopFCCList: -+ self.fccmgr.stopFCCService(eServiceReference(sref)) -+ -+ def FCCTryStart(self): -+ self.getSrefTimer.start(0, True) -+ -+ def FCCGetCurSref(self): -+ if (not self.fccSetupActivate) or (self.disableforrec and self.recordings): -+ return -+ -+ if self.createListTimer.isActive(): -+ self.createListTimer.stop() -+ self.FCCCreateList() -+ -+ curSref = self.session.nav.getCurrentlyPlayingServiceReference() -+ -+ if curSref and self.isPlayableFCC(curSref): -+ self.FCCStart() -+ else: -+ print("[FCCSupport] FCCGetCurSref get current serviceReference failed!!") -+ -+ def FCCStart(self): -+ self.activating = True -+ self.FCCGetEvent(iPlayableService.evTunedIn) -+ -+ def FCCGetEvent(self, event): -+ if self.activating and event in (iPlayableService.evTunedIn, iPlayableService.evTuneFailed, iPlayableService.evFccFailed, self.fccTimeoutEventCode): -+ self.eventList.append(event) -+ self.fccEventTimer.start(0, True) -+ -+ def FCCApplyEvent(self): -+ if not self.activating: -+ return -+ -+ while self.eventList: -+ event = self.eventList.pop(0) -+ -+ self.FCCTimeoutTimerStop() -+ -+ if event in (iPlayableService.evTuneFailed, iPlayableService.evFccFailed): -+ self.fccmgr.stopFCCService() # stop FCC Services in failed state -+ -+ if not self.FCCCheckAndTimerStart() and len(self.fccList): -+ sref = self.fccList.pop(0) -+ if self.isPlayableFCC(sref): # remove PVR, streaming, radio channels -+ self.fccmgr.playFCCService(eServiceReference(sref)) -+ self.FCCTimeoutTimerStart(sref) -+ -+ def FCCStopAllServices(self): -+ self.FCCTimeoutTimerStop() -+ fccServiceList = self.fccmgr.getFCCServiceList() -+ for (sref, value) in fccServiceList.items(): -+ state = value[0] -+ if state != 1 : # 1 : fcc_state_decoding -+ self.fccmgr.stopFCCService(eServiceReference(sref)) -+ -+ def FCCDisableServices(self): -+ self.FCCTimeoutTimerStop() -+ self.getSrefTimer.stop() -+ self.activating = False -+ self.fccList = [] -+ -+ self.fccEventTimer.stop() -+ self.fccmgr.stopFCCService() -+ self.eventList = [] -+ -+ def FCCCheckNoLocked(self): -+ for (sref, value) in self.fccmgr.getFCCServiceList().items(): -+ state = value[0] -+ locked = value[1] -+ if state != 1 and locked == 0: # no fcc decoding and no locked -+ return sref -+ return None -+ -+ def FCCTimeout(self): -+ sref = self.FCCCheckNoLocked() -+ if sref and sref == self.fccTimeoutWait: -+ self.fccmgr.stopFCCService(eServiceReference(sref)) -+ self.FCCGetEvent(self.fccTimeoutEventCode) -+ -+ def FCCCheckAndTimerStart(self): -+ sref = self.FCCCheckNoLocked() -+ if sref: -+ self.FCCTimeoutTimerStart(sref) -+ return True -+ return False -+ -+ def FCCTimeoutTimerStart(self, sref): -+ self.fccTimeoutWait = sref -+ self.fccTimeoutTimer.start(5000, True) -+ -+ def FCCTimeoutTimerStop(self): -+ self.fccTimeoutWait = None -+ self.fccTimeoutTimer.stop() -+ -+class FCCSetup(Screen, ConfigListScreen): -+ def __init__(self, session): -+ Screen.__init__(self, session) -+ self.title = _("Fast Channel Change Setup") -+ self.skinName = ["FCCSetup", "Setup"] -+ self.session = session -+ self.list = [] -+ ConfigListScreen.__init__(self, self.list, session=self.session, on_change=self.setupChanged, fullUI=True) -+ -+ self.isSupport = checkSupportFCC() -+ -+ if self.isSupport: -+ self["description"] = StaticText("") -+ self.createConfig() -+ self.createSetup() -+ else: -+ self["description"] = StaticText(_("Receiver or driver does not support FCC")) -+ -+ def createConfig(self): -+ self.enableEntry = getConfigListEntry(_("FCC enabled"), config.plugins.fccsetup.activate) -+ self.fccmaxEntry = getConfigListEntry(_("Max channels"), config.plugins.fccsetup.maxfcc) -+ self.zapupdownEntry = getConfigListEntry(_("Zap Up/Down"), config.plugins.fccsetup.zapupdown) -+ self.historyEntry = getConfigListEntry(_("History Prev/Next"), config.plugins.fccsetup.history) -+ self.priorityEntry = getConfigListEntry(_("priority"), config.plugins.fccsetup.priority) -+ self.recEntry = getConfigListEntry(_("Disable FCC during recordings"), config.plugins.fccsetup.disableforrec) -+ -+ def createSetup(self): -+ self.list = [] -+ self.list.append( self.enableEntry ) -+ if self.enableEntry[1].value: -+ self.list.append( self.fccmaxEntry ) -+ self.list.append( self.zapupdownEntry ) -+ self.list.append( self.historyEntry ) -+ if self.zapupdownEntry[1].value and self.historyEntry[1].value: -+ self.list.append( self.priorityEntry ) -+ self.list.append(self.recEntry) -+ -+ self["config"].list = self.list -+ -+ def setupChanged(self): -+ currentEntry = self["config"].getCurrent() -+ if currentEntry in (self.zapupdownEntry, self.historyEntry, self.enableEntry): -+ if not (self.zapupdownEntry[1].value or self.historyEntry[1].value): -+ if currentEntry == self.historyEntry: -+ self.zapupdownEntry[1].value = True -+ else: -+ self.historyEntry[1].value = True -+ elif self.zapupdownEntry[1].value and self.historyEntry[1].value: -+ if int(self.fccmaxEntry[1].value) < 5: -+ if g_max_fcc < 5: -+ self.fccmaxEntry[1].value = str(g_max_fcc) -+ else: -+ self.fccmaxEntry[1].value = str(5) -+ -+ self.createSetup() -+ -+ def keySave(self): -+ if not self.isSupport: -+ self.keyCancel() -+ return -+ -+ ConfigListScreen.keySave(self) -+ FCCChanged() -+ -+def getExtensionName(): -+ if config.plugins.fccsetup.activate.value: -+ return _("Disable Fast Channel Change") -+ -+ return _("Enable Fast Channel Change") -+ -+def ToggleUpdate(): -+ if config.plugins.fccsetup.activate.value: -+ config.plugins.fccsetup.activate.value = False -+ else: -+ config.plugins.fccsetup.activate.value = True -+ config.plugins.fccsetup.activate.save() -+ FCCChanged() -+ -+def FCCSupportInit(reason, **kwargs): -+ if "session" in kwargs: -+ global FccInstance -+ FccInstance = FCCSupport(kwargs["session"]) -+ -+def showFCCExtentionMenu(): -+ currentScreenName = None -+ if FccInstance: -+ currentScreenName = FccInstance.session.current_dialog.__class__.__name__ -+ return (currentScreenName == "InfoBar") -+ -+def addExtentions(infobarExtensions): -+ infobarExtensions.addExtension((getExtensionName, ToggleUpdate, showFCCExtentionMenu), None) -+ -+def FCCStart(session, **kwargs): -+ session.open(FCCSetup) -+ -+def main(menuid, **kwargs): -+ if menuid == "scan": -+ return [(_("Fast Channel Change"), FCCStart, "FCCSetup", 5)] -+ else: -+ return [] -+ -+def Plugins(**kwargs): -+ list = [] -+ -+ global g_max_fcc -+ if g_max_fcc: -+ list.append( -+ PluginDescriptor(name="FCCSupport", -+ description="Fast Channel Change support", -+ where = [PluginDescriptor.WHERE_SESSIONSTART], -+ fnc = FCCSupportInit)) -+ -+ list.append( -+ PluginDescriptor(name="FCCExtensionMenu", -+ description="Fast Channel Change menu", -+ where = [PluginDescriptor.WHERE_EXTENSIONSINGLE], -+ fnc = addExtentions)) -+ -+ list.append( -+ PluginDescriptor(name=_("FCCSetup"), -+ description=_("Fast Channel Change setup"), -+ where = [PluginDescriptor.WHERE_MENU], -+ needsRestart = False, -+ fnc = main)) -+ -+ return list -diff --git a/lib/python/Plugins/SystemPlugins/Makefile.am b/lib/python/Plugins/SystemPlugins/Makefile.am -index 27281717a5..8fbea16704 100644 ---- a/lib/python/Plugins/SystemPlugins/Makefile.am -+++ b/lib/python/Plugins/SystemPlugins/Makefile.am -@@ -5,7 +5,8 @@ SUBDIRS = PositionerSetup Satfinder \ - DefaultServicesScanner CommonInterfaceAssignment \ - VideoClippingSetup \ - VideoEnhancement WirelessLan NetworkWizard \ -- SABnzbdSetup FastScan SatelliteEquipmentControl DiseqcTester -+ SABnzbdSetup FastScan SatelliteEquipmentControl DiseqcTester \ -+ FastChannelChange - - if VUSOLO2 - SUBDIRS += CableScan -diff --git a/lib/python/enigma_python.i b/lib/python/enigma_python.i -index d0fdab6674..fa520bfd31 100644 ---- a/lib/python/enigma_python.i -+++ b/lib/python/enigma_python.i -@@ -113,6 +113,7 @@ is usually caused by not marking PSignals as immutable. - #include - #include - #include -+#include - %} - - %feature("ref") iObject "$this->AddRef(); /* eDebug(\"AddRef (%s:%d)!\", __FILE__, __LINE__); */ " -@@ -187,6 +188,7 @@ typedef long time_t; - %immutable eHdmiCEC::addressChanged; - %immutable ePythonMessagePump::recv_msg; - %immutable eDVBLocalTimeHandler::m_timeUpdated; -+%immutable eFCCServiceManager::m_fcc_event; - %immutable iCryptoInfo::clientname; - %immutable iCryptoInfo::clientinfo; - %immutable iCryptoInfo::verboseinfo; -@@ -261,6 +263,7 @@ typedef long time_t; - %include - %include - %include -+%include - %include - /************** eptr **************/ - -@@ -427,6 +430,15 @@ int getLinkedSlotID(int fe) - } - %} - -+void setFCCEnable(int); -+%{ -+void setFCCEnable(int enable) -+{ -+ eFCCServiceManager *fcc_mng = eFCCServiceManager::getInstance(); -+ if (fcc_mng) setFCCEnable(enable); -+} -+%} -+ - PyObject *getFontFaces(); - %{ - PyObject *getFontFaces() -diff --git a/lib/service/Makefile.inc b/lib/service/Makefile.inc -index 520b5edc69..6434d7b43e 100644 ---- a/lib/service/Makefile.inc -+++ b/lib/service/Makefile.inc -@@ -9,6 +9,7 @@ service_libenigma_service_a_SOURCES = \ - service/service.cpp \ - service/servicedvb.cpp \ - service/servicedvbrecord.cpp \ -+ service/servicedvbfcc.cpp \ - service/servicefs.cpp \ - service/servicemp3.cpp \ - service/servicemp3record.cpp \ -@@ -27,6 +28,7 @@ serviceinclude_HEADERS = \ - service/service.h \ - service/servicedvb.h \ - service/servicedvbrecord.h \ -+ service/servicedvbfcc.h \ - service/servicefs.h \ - service/servicemp3.h \ - service/servicemp3record.h \ -diff --git a/lib/service/iservice.h b/lib/service/iservice.h -index 35fac0afe9..7f2a44367f 100644 ---- a/lib/service/iservice.h -+++ b/lib/service/iservice.h -@@ -468,6 +468,7 @@ public: - syncState, - frontendNumber, - signalQualitydB, -+ isUsbTuner, - frontendStatus, - snrValue, - frequency, -@@ -964,6 +965,8 @@ public: - - evVideoGammaChanged, - -+ evFccFailed, -+ - evUser = 0x100 - }; - }; -@@ -1022,6 +1025,8 @@ public: - evRecordFailed, - evRecordWriteError, - evNewEventInfo, -+ evTuneStart, -+ evPvrTuneStart, - evRecordAborted, - evGstRecordEnded, - }; -diff --git a/lib/service/listboxservice.cpp b/lib/service/listboxservice.cpp -index e5d72be71a..2787cbd901 100644 ---- a/lib/service/listboxservice.cpp -+++ b/lib/service/listboxservice.cpp -@@ -153,6 +153,17 @@ void eListboxServiceContent::getNext(eServiceReference &ref) - ref = eServiceReference(); - } - -+PyObject *eListboxServiceContent::getList() -+{ -+ ePyObject result = PyList_New(m_list.size()); -+ int pos=0; -+ for (list::iterator it(m_list.begin()); it != m_list.end(); ++it) -+ { -+ PyList_SET_ITEM(result, pos++, NEW_eServiceReference(*it)); -+ } -+ return result; -+} -+ - int eListboxServiceContent::getNextBeginningWithChar(char c) - { - // printf("Char: %c\n", c); -diff --git a/lib/service/listboxservice.h b/lib/service/listboxservice.h -index 898354739a..36d5136276 100644 ---- a/lib/service/listboxservice.h -+++ b/lib/service/listboxservice.h -@@ -23,6 +23,7 @@ public: - void getCurrent(eServiceReference &ref); - void getPrev(eServiceReference &ref); - void getNext(eServiceReference &ref); -+ PyObject *getList(); - - int getNextBeginningWithChar(char c); - int getPrevMarkerPos(); -diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp -index 91b0273288..e5d97096bd 100644 ---- a/lib/service/servicedvb.cpp -+++ b/lib/service/servicedvb.cpp -@@ -19,6 +19,7 @@ - #include // access to python config - #include - #include -+#include - #include "servicepeer.h" - - /* for subtitles */ -@@ -30,6 +31,8 @@ - #include - #include - -+#include -+ - #include - #include - using namespace std; -@@ -926,7 +929,10 @@ RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr &service, const eServ - return 0; - } - --eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): -+eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service, bool connect_event): - m_reference(ref), - m_dvb_service(service), -+ m_is_primary(1), - m_decoder_index(0), - m_have_video_pid(0), - m_tune_state(-1), -@@ -1044,7 +1051,8 @@ eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *serv - // m_is_streamx = m_is_stream; // sets to false if looking at fallback url at this point as m_is_stream(ref.path.find("://") is false. - eDebug("[servicedvb][eDVBServicePlay] now running: m_is_streamx set by m_is_stream %d", m_is_streamx); - eDebug("[servicedvb][eDVBServicePlay] now running: m_is_pvr set to; %d", m_is_pvr); -- CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent); -+ if (connect_event) -+ CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent); - CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift); - CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent); - CONNECT(m_subtitle_sync_timer->timeout, eDVBServicePlay::checkSubtitleTiming); -@@ -1461,6 +1469,7 @@ RESULT eDVBServicePlay::stop() - - RESULT eDVBServicePlay::setTarget(int target, bool noaudio = false) - { -+ m_is_primary = !target; - m_decoder_index = target; - m_noaudio = noaudio; - return 0; -@@ -2216,7 +2225,7 @@ int eDVBServicePlay::selectAudioStream(int i) - - m_current_audio_pid = apid; - -- if (!m_noaudio && m_decoder->setAudioPID(apid, apidtype)) -+ if ((m_is_primary || !m_noaudio) && m_decoder->setAudioPID(apid, apidtype)) - { - eDebug("[eDVBServicePlay] set audio pid %04x failed", apid); - return -4; -@@ -2231,7 +2240,7 @@ int eDVBServicePlay::selectAudioStream(int i) - int rdsPid = apid; - - /* if timeshift is not active and we are not in pip mode, check if we need to enable the rds reader */ -- if (!(m_timeshift_active || m_decoder_index || m_have_video_pid)) -+ if (!(m_timeshift_active || m_decoder_index || m_have_video_pid || !m_is_primary)) - { - int different_pid = program.videoStreams.empty() && program.audioStreams.size() == 1 && program.audioStreams[stream].rdsPid != -1; - if (different_pid) -diff --git a/lib/service/servicedvb.h b/lib/service/servicedvb.h -index ee97f458aa..c379a8ef38 100644 ---- a/lib/service/servicedvb.h -+++ b/lib/service/servicedvb.h -@@ -174,7 +174,7 @@ public: - RESULT setNextPlaybackFile(const char *fn); - RESULT saveTimeshiftFile(); - std::string getTimeshiftFilename(); -- void switchToLive(); -+ virtual void switchToLive(); - - // iTapService - bool startTapToFD(int fd, const std::vector &pids, int packetsize = 188); -@@ -209,6 +209,7 @@ protected: - ePtr m_dvb_service; - - ePtr m_decoder; -+ int m_is_primary; - int m_decoder_index; - int m_have_video_pid; - int m_tune_state; -@@ -220,7 +221,7 @@ protected: - int m_current_audio_pid; - int m_current_video_pid_type; - -- eDVBServicePlay(const eServiceReference &ref, eDVBService *service); -+ eDVBServicePlay(const eServiceReference &ref, eDVBService *service, bool connect_event=true); - - /* events */ - void gotNewEvent(int error); -diff --git a/lib/service/servicedvbfcc.cpp b/lib/service/servicedvbfcc.cpp -new file mode 100644 -index 0000000000..0005743f6e ---- /dev/null -+++ b/lib/service/servicedvbfcc.cpp -@@ -0,0 +1,503 @@ -+#include -+#include -+#include -+#include -+ -+eDVBServiceFCCPlay::eDVBServiceFCCPlay(const eServiceReference &ref, eDVBService *service) -+ :eDVBServicePlay(ref, service, false), m_fcc_flag(0), m_fcc_mode(fcc_mode_preparing), m_fcc_mustplay(false), -+ m_pmtVersion(-1), m_normal_decoding(false) -+{ -+ CONNECT(m_service_handler.serviceEvent, eDVBServiceFCCPlay::serviceEvent); -+} -+ -+eDVBServiceFCCPlay::~eDVBServiceFCCPlay() -+{ -+} -+ -+void eDVBServiceFCCPlay::serviceEvent(int event) -+{ -+ RESULT ret = 0; -+ -+ if (!m_is_primary) // PIP mode -+ { -+ ret = eDVBServicePlay::start(); -+ return ret; -+ } -+ -+ m_tune_state = event; -+ -+ switch (event) -+ { -+ case eDVBServicePMTHandler::eventTuned: -+ { -+ eDVBServicePlay::serviceEvent(event); -+ pushbackFCCEvents(evTunedIn); -+ break; -+ } -+ case eDVBServicePMTHandler::eventNoResources: -+ case eDVBServicePMTHandler::eventNoPAT: -+ case eDVBServicePMTHandler::eventNoPATEntry: -+ case eDVBServicePMTHandler::eventNoPMT: -+ case eDVBServicePMTHandler::eventTuneFailed: -+ case eDVBServicePMTHandler::eventMisconfiguration: -+ { -+ eDVBServicePlay::serviceEvent(event); -+ pushbackFCCEvents(evTuneFailed); -+ break; -+ } -+ case eDVBServicePMTHandler::eventChannelAllocated: -+ { -+ bool is_usb_tuner = checkUsbTuner(); -+ bool fcc_state_decoding = getFCCStateDecoding(); -+ -+ if (is_usb_tuner) -+ { -+ if (fcc_state_decoding) -+ { -+ m_normal_decoding = true; -+ setNormalDecoding(); -+ } -+ else -+ { -+ eDVBServicePlay::serviceEvent(eDVBServicePMTHandler::eventTuneFailed); -+ pushbackFCCEvents(evTuneFailed); -+ } -+ } -+ break; -+ } -+ case eDVBServicePMTHandler::eventNewProgramInfo: -+ { -+ if (m_fcc_flag & fcc_tune_failed) -+ return; -+ -+ eDebug("[eDVBServiceFCCPlay] eventNewProgramInfo %d %d %d", m_timeshift_enabled, m_timeshift_active, m_normal_decoding); -+ if (m_normal_decoding) -+ { -+ eDVBServicePlay::serviceEvent(event); -+ } -+ else -+ { -+ if (m_timeshift_enabled) -+ updateTimeshiftPids(); -+ -+ if (!m_timeshift_active) -+ processNewProgramInfo(); -+ -+ if (!m_timeshift_active) -+ { -+ m_event((iPlayableService*)this, evUpdatedInfo); -+ pushbackFCCEvents(evUpdatedInfo); -+ } -+ } -+ break; -+ } -+ case eDVBServicePMTHandler::eventPreStart: -+ case eDVBServicePMTHandler::eventEOF: -+ case eDVBServicePMTHandler::eventSOF: -+ { -+ eDVBServicePlay::serviceEvent(event); -+ break; -+ } -+ case eDVBServicePMTHandler::eventHBBTVInfo: -+ { -+ eDVBServicePlay::serviceEvent(event); -+ pushbackFCCEvents(evHBBTVInfo); -+ break; -+ } -+ } -+} -+ -+RESULT eDVBServiceFCCPlay::start() -+{ -+ if (!m_is_primary) // PIP mode -+ { -+ ret = eDVBServicePlay::start(); -+ return ret; -+ } -+ -+ if (m_fcc_flag & fcc_start) // already started -+ { -+ changeFCCMode(); -+ } -+ else -+ { -+ m_fcc_flag |= fcc_start; -+ pushbackFCCEvents(evStart); -+ -+ /* disable CA Interfaces on fcc_mode_preparing */ -+ m_service_handler.setCaDisable(true); -+ eDVBServicePlay::start(); -+ } -+ return 0; -+} -+ -+void eDVBServiceFCCPlay::pushbackFCCEvents(int event) -+{ -+ if (event == evTuneFailed) -+ m_fcc_flag |= fcc_tune_failed; -+ m_fcc_events.push_back(event); -+} -+ -+void eDVBServiceFCCPlay::popFCCEvents() -+{ -+ m_fcc_events.unique(); // remove duplicate evUpdatedInfo -+ for (std::list::iterator it = m_fcc_events.begin(); it != m_fcc_events.end(); ++it) -+ { -+ if (*it == evUpdatedInfo) -+ { -+ updateFCCDecoder(); -+ break; -+ } -+ } -+ -+ /* add CaHandler */ -+ m_service_handler.addCaHandler(); -+ -+ /* send events */ -+ for (std::list::iterator it = m_fcc_events.begin(); it != m_fcc_events.end(); ++it) -+ { -+ int event = *it; -+ m_event((iPlayableService*)this, event); -+ } -+} -+ -+void eDVBServiceFCCPlay::changeFCCMode() -+{ -+ if (m_fcc_mode == fcc_mode_decoding) -+ { -+ eDebug("[eDVBServiceFCCPlay] changeFCCMode [%s] disable FCC decoding.", m_reference.toString().c_str()); -+ m_fcc_mode = fcc_mode_preparing; -+ -+ /* stop timeshift */ -+ eDVBServicePlay::stopTimeshift(); -+ -+ /* remove CaHandler */ -+ m_service_handler.removeCaHandler(); -+ -+ if (m_fcc_flag & fcc_tune_failed) -+ m_event((iPlayableService*)this, evTuneFailed); -+ -+ else if (m_fcc_flag & fcc_failed) -+ m_event((iPlayableService*)this, evFccFailed); -+ -+ FCCDecoderStop(); -+ } -+ else -+ { -+ eDebug("[eDVBServiceFCCPlay] changeFCCMode [%s] enable FCC decoding.", m_reference.toString().c_str()); -+ m_fcc_mode = fcc_mode_decoding; -+ popFCCEvents(); -+ } -+} -+ -+void eDVBServiceFCCPlay::processNewProgramInfo(bool toLive) -+{ -+ updateFCCDecoder(toLive); -+ -+ if (m_fcc_flag & fcc_failed) -+ { -+ m_event((iPlayableService*)this, evFccFailed); -+ } -+} -+ -+void eDVBServiceFCCPlay::updateFCCDecoder(bool sendSeekableStateChanged) -+{ -+ eDebug("[eDVBServiceFCCPlay] updateFCCDecoder [%s]", m_reference.toString().c_str()); -+ int vpid = -1, vpidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1; -+ bool isProgramInfoCached = false; -+ bool pmtVersionChanged = false; -+ -+ eDVBServicePMTHandler &h = m_service_handler; -+ -+ eDVBServicePMTHandler::program program; -+ if (h.getProgramInfo(program)) -+ eDebug("[eDVBServiceFCCPlay] Getting program info failed."); -+ else -+ { -+ eDebugNoNewLine("have %zd video stream(s)", program.videoStreams.size()); -+ if (!program.videoStreams.empty()) -+ { -+ eDebugNoNewLine(" ("); -+ for (std::vector::const_iterator -+ i(program.videoStreams.begin()); -+ i != program.videoStreams.end(); ++i) -+ { -+ if (vpid == -1) -+ { -+ vpid = i->pid; -+ vpidtype = i->type; -+ } -+ if (i != program.videoStreams.begin()) -+ eDebugNoNewLine(", "); -+ eDebugNoNewLine("%04x", i->pid); -+ } -+ eDebugNoNewLine(")"); -+ } -+ eDebugNoNewLine(", and %zd audio stream(s)", program.audioStreams.size()); -+ if (!program.audioStreams.empty()) -+ { -+ eDebugNoNewLine(" ("); -+ for (std::vector::const_iterator -+ i(program.audioStreams.begin()); -+ i != program.audioStreams.end(); ++i) -+ { -+ if (i != program.audioStreams.begin()) -+ eDebugNoNewLine(", "); -+ eDebugNoNewLine("%04x", i->pid); -+ } -+ eDebugNoNewLine(")"); -+ } -+ eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid); -+ pcrpid = program.pcrPid; -+ eDebugNoNewLine(", and the text pid is %04x", program.textPid); -+ tpid = program.textPid; -+ eDebug(" %s", program.isCached ? "(Cached)":""); -+ isProgramInfoCached = program.isCached; -+ if (m_pmtVersion != program.pmtVersion) -+ { -+ if (m_pmtVersion != -1) -+ pmtVersionChanged = true; -+ m_pmtVersion = program.pmtVersion; -+ //eDebug("[eDVBServiceFCCPlay] updateFCCDecoder pmt version : %d", m_pmtVersion); -+ } -+ } -+ -+ if (!m_decoder) -+ { -+ h.getDecodeDemux(m_decode_demux); -+ if (m_decode_demux) -+ { -+ m_decode_demux->getMPEGDecoder(m_decoder, m_decoder_index); -+ if (m_decoder) -+ m_decoder->connectVideoEvent(sigc::mem_fun(*this, &eDVBServiceFCCPlay::video_event), m_video_event_connection); -+ } -+ m_fcc_mustplay = true; -+ } -+ -+ if (m_decoder) -+ { -+ if (!((m_fcc_flag & fcc_ready)||(m_fcc_flag & fcc_novideo))) -+ { -+ if (vpid == -1) -+ { -+ if (!isProgramInfoCached) -+ m_fcc_flag |= fcc_novideo; -+ } -+ else if ((vpidtype == -1) || (pcrpid== -1)) -+ { -+ if (!isProgramInfoCached) -+ m_fcc_flag |= fcc_failed; -+ } -+ else if (!m_decoder->prepareFCC(m_decode_demux->getSource(), vpid, vpidtype, pcrpid)) -+ m_fcc_flag |= fcc_ready; -+ else -+ m_fcc_flag |= fcc_failed; -+ } -+ else if (pmtVersionChanged) -+ { -+ m_decoder->fccUpdatePids(m_decode_demux->getSource(), vpid, vpidtype, pcrpid); -+ m_fcc_flag &=~fcc_decoding; -+ } -+ } -+ -+ if (m_fcc_mode != fcc_mode_decoding) -+ return; -+ -+ /* fcc_mode_decoding */ -+ if (!(m_fcc_flag & fcc_ready) && !(m_fcc_flag & fcc_novideo)) -+ { -+ eDebug("[eDVBServiceFCCPlay] updateFCCDecoder fcc is not ready."); -+ return; -+ } -+ -+ if (m_decode_demux) -+ { -+ if (m_is_primary) -+ { -+ m_teletext_parser = new eDVBTeletextParser(m_decode_demux); -+ m_teletext_parser->connectNewPage(sigc::mem_fun(*this, &eDVBServiceFCCPlay::newSubtitlePage), m_new_subtitle_page_connection); -+ m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux); -+ m_subtitle_parser->connectNewPage(sigc::mem_fun(*this, &eDVBServiceFCCPlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection); -+ if (m_timeshift_changed) -+ { -+ struct SubtitleTrack track; -+ if (getCachedSubtitle(track) >= 0) -+ { -+ if (track.type == 0) // dvb -+ m_subtitle_parser->start(track.pid, track.page_number, track.magazine_number); -+ else if (track.type == 1) // ttx -+ m_teletext_parser->setPageAndMagazine(track.page_number, track.magazine_number, track.language_code.c_str()); -+ } -+ } -+ } -+ } -+ -+ m_timeshift_changed = 0; -+ -+ if (m_decoder) -+ { -+ bool wasSeekable = m_decoder->getVideoProgressive() != -1; -+ -+ if (m_dvb_service) -+ { -+ achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL); -+ ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY); -+ pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY); -+ } -+ else // subservice -+ { -+ eServiceReferenceDVB ref; -+ m_service_handler.getServiceReference(ref); -+ eServiceReferenceDVB parent = ref.getParentServiceReference(); -+ if (!parent) -+ parent = ref; -+ if (parent) -+ { -+ ePtr res_mgr; -+ if (!eDVBResourceManager::getInstance(res_mgr)) -+ { -+ ePtr db; -+ if (!res_mgr->getChannelList(db)) -+ { -+ ePtr origService; -+ if (!db->getService(parent, origService)) -+ { -+ ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY); -+ pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY); -+ } -+ } -+ } -+ } -+ } -+ -+ setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay); -+ setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay); -+ -+ m_decoder->setVideoPID(vpid, vpidtype); -+ selectAudioStream(); -+ -+ if (!(m_is_pvr || m_is_stream || m_timeshift_active)) -+ m_decoder->setSyncPCR(pcrpid); -+ else -+ m_decoder->setSyncPCR(-1); -+ -+ if (m_is_primary) -+ { -+ m_decoder->setTextPID(tpid); -+ m_teletext_parser->start(program.textPid); -+ } -+ -+ if (vpid > 0 && vpid < 0x2000) -+ ; -+ else -+ { -+ std::string value; -+ bool showRadioBackground = eConfigManager::getConfigBoolValue("config.misc.showradiopic", true); -+ std::string radio_pic; -+ if (showRadioBackground) -+ radio_pic = eConfigManager::getConfigValue("config.misc.radiopic"); -+ else -+ radio_pic = eConfigManager::getConfigValue("config.misc.blackradiopic"); -+ m_decoder->setRadioPic(radio_pic); -+ } -+ -+ /* fcc stop and decoder start */ -+ if (!(m_fcc_flag & fcc_novideo)) -+ { -+ if (m_fcc_flag & fcc_decoding) -+ ; -+ else if(!m_decoder->fccDecoderStart()) -+ m_fcc_flag |= fcc_decoding; -+ } -+ -+ if (m_fcc_mustplay) -+ { -+ m_fcc_mustplay = false; -+ m_decoder->play(); -+ } -+ else -+ { -+ m_decoder->set(); -+ } -+ -+ m_decoder->setAudioChannel(achannel); -+ -+ /* don't worry about non-existing services, nor pvr services */ -+ if (m_dvb_service) -+ { -+ /* (audio pid will be set in selectAudioTrack */ -+ m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid); -+ m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype); -+ m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid); -+ m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid); -+ } -+ if (!sendSeekableStateChanged && (m_decoder->getVideoProgressive() != -1) != wasSeekable) -+ sendSeekableStateChanged = true; -+ } -+ m_have_video_pid = (vpid > 0 && vpid < 0x2000); -+ -+ if (sendSeekableStateChanged) -+ m_event((iPlayableService*)this, evSeekableStatusChanged); -+} -+ -+void eDVBServiceFCCPlay::FCCDecoderStop() -+{ -+ eDebug("[eDVBServiceFCCPlay] FCCDecoderStop [%s]", m_reference.toString().c_str()); -+ -+ if (m_decoder) -+ { -+ m_teletext_parser = 0; -+ m_new_subtitle_page_connection = 0; -+ m_subtitle_parser = 0; -+ m_new_dvb_subtitle_page_connection = 0; -+ -+ if (m_fcc_flag & fcc_ready) -+ { -+ m_decoder->fccDecoderStop(); -+ m_fcc_flag &=~fcc_decoding; -+ } -+ else if (m_fcc_flag & fcc_novideo) -+ { -+ m_video_event_connection = 0; -+ m_decoder = 0; -+ } -+ } -+} -+ -+void eDVBServiceFCCPlay::switchToLive() -+{ -+ if (!m_timeshift_active) -+ return; -+ -+ eDebug("[eDVBServiceFCCPlay] SwitchToLive"); -+ -+ resetTimeshift(0); -+ -+ m_is_paused = m_skipmode = m_fastforward = m_slowmotion = 0; /* not supported in live mode */ -+ -+ /* free the timeshift service handler, we need the resources */ -+ m_service_handler_timeshift.free(); -+ -+ m_fcc_flag &=~fcc_ready; -+ m_fcc_flag &=~fcc_decoding; -+ processNewProgramInfo(true); -+} -+ -+bool eDVBServiceFCCPlay::checkUsbTuner() -+{ -+ return (bool)getFrontendInfo(iFrontendInformation_ENUMS::isUsbTuner); -+} -+ -+bool eDVBServiceFCCPlay::getFCCStateDecoding() -+{ -+ eFCCServiceManager *fcc_service_mgr = eFCCServiceManager::getInstance(); -+ return fcc_service_mgr->isStateDecoding((iPlayableService*)this); -+} -+ -+void eDVBServiceFCCPlay::setNormalDecoding() -+{ -+ eFCCServiceManager *fcc_service_mgr = eFCCServiceManager::getInstance(); -+ return fcc_service_mgr->setNormalDecoding((iPlayableService*)this); -+} -+ -+DEFINE_REF(eDVBServiceFCCPlay) -diff --git a/lib/service/servicedvbfcc.h b/lib/service/servicedvbfcc.h -new file mode 100644 -index 0000000000..469b64cec1 ---- /dev/null -+++ b/lib/service/servicedvbfcc.h -@@ -0,0 +1,53 @@ -+#ifndef __servicedvbfcc_h -+#define __servicedvbfcc_h -+ -+#include -+#include -+ -+#include -+ -+class eDVBServiceFCCPlay: public eDVBServicePlay -+{ -+ DECLARE_REF(eDVBServiceFCCPlay); -+public: -+ eDVBServiceFCCPlay(const eServiceReference &ref, eDVBService *service); -+ virtual ~eDVBServiceFCCPlay(); -+ void serviceEvent(int event); -+ RESULT start(); -+protected: -+ void pushbackFCCEvents(int event); -+ void popFCCEvents(); -+ void changeFCCMode(); -+ void processNewProgramInfo(bool toLive=false); -+ void updateFCCDecoder(bool sendSeekableStateChanged=false); -+ void FCCDecoderStop(); -+ void switchToLive(); -+ bool checkUsbTuner(); -+ bool getFCCStateDecoding(); -+ void setNormalDecoding(); -+ -+ bool m_fcc_enable; -+ -+ enum { -+ fcc_start = 1, -+ fcc_tune_failed = 2, -+ fcc_failed = 4, -+ fcc_ready = 8, -+ fcc_decoding = 16, -+ fcc_novideo = 32, -+ }; -+ int m_fcc_flag; -+ -+ enum { -+ fcc_mode_preparing, -+ fcc_mode_decoding -+ }; -+ int m_fcc_mode; -+ -+ bool m_fcc_mustplay; -+ std::list m_fcc_events; -+ int m_pmtVersion; -+ bool m_normal_decoding; -+}; -+ -+#endif /* __servicedvbfcc_h */ -diff --git a/lib/service/servicedvbrecord.cpp b/lib/service/servicedvbrecord.cpp -index 94698bfcc6..c96c5f53e8 100644 ---- a/lib/service/servicedvbrecord.cpp -+++ b/lib/service/servicedvbrecord.cpp -@@ -263,6 +263,11 @@ int eDVBServiceRecord::doPrepare() - f->open(m_ref.path.c_str()); - source = ePtr(f); - } -+ m_event((iRecordableService*)this, evPvrTuneStart); -+ } -+ else -+ { -+ m_event((iRecordableService*)this, evTuneStart); - } - return m_service_handler.tuneExt(m_ref, source, m_ref.path.c_str(), 0, m_simulate, NULL, servicetype, m_descramble); - }