From c63c0b4c7925408162bdc4ecc86246e206318ee6 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 11:39:05 +0400 Subject: [PATCH 001/200] driver/audioplay.cpp: reset state to STOP in stop(), in case it called in STOP state --- src/driver/audioplay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/driver/audioplay.cpp b/src/driver/audioplay.cpp index 3ea3fd4d4..5dea17d17 100644 --- a/src/driver/audioplay.cpp +++ b/src/driver/audioplay.cpp @@ -49,6 +49,7 @@ void CAudioPlayer::stop() if(thrPlay) pthread_join(thrPlay,NULL); thrPlay = 0; + state = CBaseDec::STOP; } void CAudioPlayer::pause() { From 15b781ab86d0a390910aa732a0bfae38bfbdb2a7 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 11:40:12 +0400 Subject: [PATCH 002/200] zapit/src/bouquets.cpp: bug fix, reset services changed flag after adding NOT_FOUND channels - else it trigger services save after load --- src/zapit/src/bouquets.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zapit/src/bouquets.cpp b/src/zapit/src/bouquets.cpp index 1c31159bb..d171acc63 100644 --- a/src/zapit/src/bouquets.cpp +++ b/src/zapit/src/bouquets.cpp @@ -409,6 +409,7 @@ void CBouquetManager::parseBouquetsXml(const char *fname, bool bUser) chan->flags = CZapitChannel::NOT_FOUND; chan->bAlwaysLocked = newBouquet->bLocked; newBouquet->addService(chan); + CServiceManager::getInstance()->SetServicesChanged(false); } channel_node = channel_node->xmlNextNode; From a99395cb058660cc0f939757078e342220ead2bb Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 11:41:05 +0400 Subject: [PATCH 003/200] locals: add locale for file start play dialog --- data/locale/english.locale | 1 + src/system/locals.h | 1 + src/system/locals_intern.h | 1 + 3 files changed, 3 insertions(+) diff --git a/data/locale/english.locale b/data/locale/english.locale index 0591a8f94..df59207f6 100644 --- a/data/locale/english.locale +++ b/data/locale/english.locale @@ -1407,6 +1407,7 @@ movieplayer.bookmarkname_hint2 movieplayer.defplugin Start-Plugin movieplayer.fileplayback File play movieplayer.head Movieplayer +movieplayer.starting Starting playback... movieplayer.toomanybookmarks There are too many bookmarks.\nYou need to delete one of them first. movieplayer.tshelp1 Stop movieplayer.tshelp10 approx. 10 minutes back diff --git a/src/system/locals.h b/src/system/locals.h index 79009dcf3..8cca97420 100644 --- a/src/system/locals.h +++ b/src/system/locals.h @@ -1434,6 +1434,7 @@ typedef enum LOCALE_MOVIEPLAYER_DEFPLUGIN, LOCALE_MOVIEPLAYER_FILEPLAYBACK, LOCALE_MOVIEPLAYER_HEAD, + LOCALE_MOVIEPLAYER_STARTING, LOCALE_MOVIEPLAYER_TOOMANYBOOKMARKS, LOCALE_MOVIEPLAYER_TSHELP1, LOCALE_MOVIEPLAYER_TSHELP10, diff --git a/src/system/locals_intern.h b/src/system/locals_intern.h index c3b8664cb..6d89d4a77 100644 --- a/src/system/locals_intern.h +++ b/src/system/locals_intern.h @@ -1434,6 +1434,7 @@ const char * locale_real_names[] = "movieplayer.defplugin", "movieplayer.fileplayback", "movieplayer.head", + "movieplayer.starting", "movieplayer.toomanybookmarks", "movieplayer.tshelp1", "movieplayer.tshelp10", From 418588e14ade974d4380ea14a57ad4eda5e853c3 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 11:41:34 +0400 Subject: [PATCH 004/200] lib/libupnpclient/UPNPDevice.cpp: fix fd leak --- lib/libupnpclient/UPNPDevice.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libupnpclient/UPNPDevice.cpp b/lib/libupnpclient/UPNPDevice.cpp index 98660c2b9..bc8aa49bb 100644 --- a/lib/libupnpclient/UPNPDevice.cpp +++ b/lib/libupnpclient/UPNPDevice.cpp @@ -438,6 +438,7 @@ std::string CUPnPDevice::HTTP(std::string url, std::string post, std::string act buf[received] = 0; reply << buf; } + close(t_socket); return reply.str(); } From e2f4eff5984fb110710b9e0a51b6e05dcfb3be4a Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 11:42:09 +0400 Subject: [PATCH 005/200] gui/mediaplayer.cpp: make upnpbrowsergui static --- src/gui/mediaplayer.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gui/mediaplayer.cpp b/src/gui/mediaplayer.cpp index 50e0a72b0..6ff2edbd7 100644 --- a/src/gui/mediaplayer.cpp +++ b/src/gui/mediaplayer.cpp @@ -149,7 +149,7 @@ int CMediaPlayerMenu::initMenuMedia(CMenuWidget *m, CPersonalizeGui *p) CMenuForwarder *fw_pviewer = NULL; CPictureViewerGui *pictureviewergui = NULL; #if ENABLE_UPNP - CUpnpBrowserGui *upnpbrowsergui = NULL; + static CUpnpBrowserGui *upnpbrowsergui = NULL; CMenuForwarder *fw_upnp = NULL; #endif CMenuWidget *moviePlayer = NULL; @@ -185,7 +185,8 @@ int CMediaPlayerMenu::initMenuMedia(CMenuWidget *m, CPersonalizeGui *p) fw_pviewer->setHint(NEUTRINO_ICON_HINT_PICVIEW, LOCALE_MENU_HINT_PICVIEW); #if ENABLE_UPNP //upnp browser - upnpbrowsergui = new CUpnpBrowserGui(); + if (!upnpbrowsergui) + upnpbrowsergui = new CUpnpBrowserGui(); fw_upnp = new CMenuForwarder(LOCALE_UPNPBROWSER_HEAD, true, NULL, upnpbrowsergui, NULL, CRCInput::RC_0, NEUTRINO_ICON_BUTTON_0); #endif // media->addIntroItems(NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, usage_mode == MODE_AUDIO ? CMenuWidget::BTN_TYPE_CANCEL : CMenuWidget::BTN_TYPE_BACK); @@ -237,7 +238,7 @@ int CMediaPlayerMenu::initMenuMedia(CMenuWidget *m, CPersonalizeGui *p) delete personalize; delete pictureviewergui; #if ENABLE_UPNP - delete upnpbrowsergui; + //delete upnpbrowsergui; #endif setUsageMode();//set default usage_mode From bb5bae7deb7c812d4a0e74e372bbd7d60191cad1 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 11:42:35 +0400 Subject: [PATCH 006/200] gui/Makefile.am: enable exeptions --- src/gui/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 737e33c21..bc3a64bc3 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -1,4 +1,4 @@ -AM_CPPFLAGS = -fno-rtti -fno-exceptions -D__STDC_FORMAT_MACROS +AM_CPPFLAGS = -fno-rtti -D__STDC_FORMAT_MACROS #AM_CPPFLAGS = -fno-rtti BUILT_SOURCES = version.h version.h: From b4cf20a9fda687d1d091155a446674d6a01c27e3 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 11:43:55 +0400 Subject: [PATCH 007/200] zapit/include/zapit/zapit.h: add EnablePlayback() to lock/unlock playback starting --- src/zapit/include/zapit/zapit.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zapit/include/zapit/zapit.h b/src/zapit/include/zapit/zapit.h index a80088ebc..f236fc4be 100644 --- a/src/zapit/include/zapit/zapit.h +++ b/src/zapit/include/zapit/zapit.h @@ -261,5 +261,6 @@ class CZapit : public OpenThreads::Thread bool StopPip(); void Lock() { mutex.lock(); } void Unlock() { mutex.unlock(); } + void EnablePlayback(bool enable) { playbackStopForced = !enable; } }; #endif /* __zapit_h__ */ From a876b074ed34d5eda9ed02361dac4433969655fa Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 12:10:56 +0400 Subject: [PATCH 008/200] driver/pictureviewer/pictureviewer.cpp: add support to get file from url, (c) martii --- src/driver/pictureviewer/pictureviewer.cpp | 34 ++++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/driver/pictureviewer/pictureviewer.cpp b/src/driver/pictureviewer/pictureviewer.cpp index 8c01f3ec4..26995e172 100644 --- a/src/driver/pictureviewer/pictureviewer.cpp +++ b/src/driver/pictureviewer/pictureviewer.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include @@ -101,7 +103,7 @@ CPictureViewer::CFormathandler * CPictureViewer::fh_getsize (const char *name, i return (NULL); } -bool CPictureViewer::DecodeImage (const std::string & name, bool showBusySign, bool unscaled) +bool CPictureViewer::DecodeImage (const std::string & _name, bool showBusySign, bool unscaled) { // dbout("DecodeImage {\n"); #if 0 // quick fix for issue #245. TODO more smart fix for this problem @@ -112,13 +114,37 @@ bool CPictureViewer::DecodeImage (const std::string & name, bool showBusySign, b #endif int x, y, imx, imy; -// int xs = CFrameBuffer::getInstance()->getScreenWidth(true); -// int ys = CFrameBuffer::getInstance()->getScreenHeight(true); + // int xs = CFrameBuffer::getInstance()->getScreenWidth(true); + // int ys = CFrameBuffer::getInstance()->getScreenHeight(true); // Show red block for "next ready" in view state if (showBusySign) showBusy (m_startx + 3, m_starty + 3, 10, 0xff, 00, 00); + std::string name = _name; + bool url = false; + + if (strstr(name.c_str(), "://")) { + std::string tmpname; + tmpname = "/tmp/pictureviewer" + name.substr(name.find_last_of(".")); + FILE *tmpFile = fopen(tmpname.c_str(), "wb"); + if (tmpFile) { + CURL *ch = curl_easy_init(); + curl_easy_setopt(ch, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(ch, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, NULL); + curl_easy_setopt(ch, CURLOPT_WRITEDATA, tmpFile); + curl_easy_setopt(ch, CURLOPT_FAILONERROR, 1L); + curl_easy_setopt(ch, CURLOPT_URL, name.c_str()); + curl_easy_perform(ch); + curl_easy_cleanup(ch); + fclose(tmpFile); + url = true; + } + name = tmpname; + } + CFormathandler *fh; if (unscaled) fh = fh_getsize (name.c_str (), &x, &y, INT_MAX, INT_MAX); @@ -201,6 +227,8 @@ bool CPictureViewer::DecodeImage (const std::string & name, bool showBusySign, b m_NextPic_YPan = 0; } m_NextPic_Name = name; + if (url) + unlink(name.c_str()); hideBusy (); // dbout("DecodeImage }\n"); return (m_NextPic_Buffer != NULL); From 2df40249d6a8f67f4b36750e39c107420943bfdb Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 12:12:36 +0400 Subject: [PATCH 009/200] nhttpd/tuxboxapi/coolstream/controlapi.cpp: call GetChannelEvents only if epg param present, add 'fav' param to get only user bouquets; add support to get bouquet's channel list with epg also in plain format --- .../tuxboxapi/coolstream/controlapi.cpp | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp index 960428a3c..029416f14 100644 --- a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp +++ b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp @@ -960,12 +960,24 @@ std::string CControlAPI::_GetBouquetWriteItem(CyhookHandler *hh, CZapitChannel * result = hh->outArrayItem("channel", result, false); } else { - result += string_printf("%u " - PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS - " %s\n", - nr, - channel->channel_id, - channel->getName().c_str()); + CChannelEvent *event; + event = NeutrinoAPI->ChannelListEvents[channel->channel_id]; + + if (event && isEPGdetails) { + result += string_printf("%u " + PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS + " %s (%s)\n", + nr, + channel->channel_id, + channel->getName().c_str(), event->description.c_str()); + } else { + result += string_printf("%u " + PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS + " %s\n", + nr, + channel->channel_id, + channel->getName().c_str()); + } } return result; } @@ -1073,7 +1085,8 @@ void CControlAPI::GetBouquetCGI(CyhookHandler *hh) { startBouquet = BouquetNr; bsize = BouquetNr+1; } - NeutrinoAPI->GetChannelEvents(); + if (!(hh->ParamList["epg"].empty())) + NeutrinoAPI->GetChannelEvents(); for (int i = startBouquet; i < bsize; i++) { channels = mode == CZapitClient::MODE_RADIO ? g_bouquetManager->Bouquets[i]->radioChannels : g_bouquetManager->Bouquets[i]->tvChannels; int num = 1 + (mode == CZapitClient::MODE_RADIO ? g_bouquetManager->radioChannelsBegin().getNrofFirstChannelofBouquet(i) @@ -1185,12 +1198,16 @@ void CControlAPI::GetBouquetsCGI(CyhookHandler *hh) { if (hh->ParamList["encode"] == "true") encode = true; + bool fav = false; + if (hh->ParamList["fav"] == "true") + fav = true; + int mode = NeutrinoAPI->Zapit->getMode(); std::string bouquet; for (int i = 0, size = (int) g_bouquetManager->Bouquets.size(); i < size; i++) { std::string item = ""; ZapitChannelList * channels = mode == CZapitClient::MODE_RADIO ? &g_bouquetManager->Bouquets[i]->radioChannels : &g_bouquetManager->Bouquets[i]->tvChannels; - if (!channels->empty() && (!g_bouquetManager->Bouquets[i]->bHidden || show_hidden)) { + if (!channels->empty() && (!g_bouquetManager->Bouquets[i]->bHidden || show_hidden) && (!fav || g_bouquetManager->Bouquets[i]->bUser)) { bouquet = std::string(g_bouquetManager->Bouquets[i]->bFav ? g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME) : g_bouquetManager->Bouquets[i]->Name.c_str()); if (encode) bouquet = encodeString(bouquet); // encode (URLencode) the bouquetname From 6fe70ff17d25a35c0c6739dd6a8f8aaaa835a67d Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 12:18:02 +0400 Subject: [PATCH 010/200] gui/movieplayer.cpp: add support to play files from upnp browser, add support to stop playback while open in progress, to interrupt i.e. ffmpeg analyze etc, based on code (c) martii --- src/gui/movieplayer.cpp | 93 ++++++++++++++++++++++++++++++++--------- src/gui/movieplayer.h | 7 ++++ 2 files changed, 80 insertions(+), 20 deletions(-) diff --git a/src/gui/movieplayer.cpp b/src/gui/movieplayer.cpp index 7572457bd..6c78bfbfe 100644 --- a/src/gui/movieplayer.cpp +++ b/src/gui/movieplayer.cpp @@ -50,6 +50,8 @@ #include #include #include +#include + #include #include #include @@ -138,6 +140,7 @@ void CMoviePlayerGui::Init(void) speed = 1; timeshift = 0; numpida = 0; + showStartingHint = false; } void CMoviePlayerGui::cutNeutrino() @@ -146,13 +149,17 @@ void CMoviePlayerGui::cutNeutrino() return; playing = true; + /* set g_InfoViewer update timer to 1 sec, should be reset to default from restoreNeutrino->set neutrino mode */ + g_InfoViewer->setUpdateTimer(1000 * 1000); + + if (isUPNP) + return; + g_Zapit->lockPlayBack(); g_Sectionsd->setPauseScanning(true); CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE, NeutrinoMessages::mode_ts); m_LastMode = (CNeutrinoApp::getInstance()->getLastMode() | NeutrinoMessages::norezap); - /* set g_InfoViewer update timer to 1 sec, should be reset to default from restoreNeutrino->set neutrino mode */ - g_InfoViewer->setUpdateTimer(1000 * 1000); } void CMoviePlayerGui::restoreNeutrino() @@ -162,6 +169,9 @@ void CMoviePlayerGui::restoreNeutrino() playing = false; + if (isUPNP) + return; + g_Zapit->unlockPlayBack(); g_Sectionsd->setPauseScanning(false); @@ -175,18 +185,12 @@ int CMoviePlayerGui::exec(CMenuTarget * parent, const std::string & actionKey) if (parent) parent->hide(); - file_name = ""; - full_name = ""; - - startposition = 0; - puts("[movieplayer.cpp] executing " MOVIEPLAYER_START_SCRIPT "."); if (my_system(MOVIEPLAYER_START_SCRIPT) != 0) perror(MOVIEPLAYER_START_SCRIPT " failed"); - - isMovieBrowser = false; - isBookmark = false; - timeshift = 0; + + Cleanup(); + if (actionKey == "tsmoviebrowser") { isMovieBrowser = true; moviebrowser->setMode(MB_SHOW_RECORDS); @@ -212,11 +216,17 @@ int CMoviePlayerGui::exec(CMenuTarget * parent, const std::string & actionKey) isBookmark = true; } #endif + else if (actionKey == "upnp") { + isUPNP = true; + p_movie_info = NULL; + is_file_player = 1; + PlayFile(); + } else { return menu_return::RETURN_REPAINT; } - while(SelectFile()) { + while(!isHTTP && !isUPNP && SelectFile()) { PlayFile(); if(timeshift) break; @@ -304,11 +314,8 @@ void CMoviePlayerGui::fillPids() vtype = p_movie_info->VideoType; } -bool CMoviePlayerGui::SelectFile() +void CMoviePlayerGui::Cleanup() { - bool ret = false; - menu_ret = menu_return::RETURN_REPAINT; - /*clear audiopids */ for (int i = 0; i < numpida; i++) { apids[i] = 0; @@ -319,9 +326,23 @@ bool CMoviePlayerGui::SelectFile() currentspid = -1; numsubs = 0; + startposition = 0; + isMovieBrowser = false; + isBookmark = false; + timeshift = 0; + isHTTP = false; + isUPNP = false; is_file_player = false; p_movie_info = NULL; +} + +bool CMoviePlayerGui::SelectFile() +{ + bool ret = false; + menu_ret = menu_return::RETURN_REPAINT; + file_name = ""; + full_name = ""; printf("CMoviePlayerGui::SelectFile: isBookmark %d timeshift %d isMovieBrowser %d\n", isBookmark, timeshift, isMovieBrowser); if (has_hdd) @@ -363,7 +384,7 @@ bool CMoviePlayerGui::SelectFile() is_file_player = true; } fillPids(); - + // get the start position for the movie startposition = 1000 * moviebrowser->getCurrentStartPos(); printf("CMoviePlayerGui::SelectFile: file %s start %d apid %X atype %d vpid %x vtype %d\n", full_name.c_str(), startposition, currentapid, currentac3, vpid, vtype); @@ -431,6 +452,27 @@ bool CMoviePlayerGui::SelectFile() return ret; } +void *CMoviePlayerGui::ShowStartHint(void *arg) +{ + set_threadname(__func__); + CMoviePlayerGui *caller = (CMoviePlayerGui *)arg; + + CHintBox hintbox(LOCALE_MOVIEPLAYER_STARTING, caller->file_name.c_str(), 450, NEUTRINO_ICON_MOVIEPLAYER); + hintbox.paint(); + + while (caller->showStartingHint) { + neutrino_msg_t msg; + neutrino_msg_data_t data; + g_RCInput->getMsg(&msg, &data, 1); + if (msg == CRCInput::RC_home || msg == CRCInput::RC_stop) { + if(caller->playback) + caller->playback->RequestAbort(); + } + } + hintbox.hide(); + return NULL; +} + void CMoviePlayerGui::PlayFile(void) { neutrino_msg_t msg; @@ -463,7 +505,18 @@ void CMoviePlayerGui::PlayFile(void) } file_prozent = 0; - if(!playback->Start((char *) full_name.c_str(), vpid, vtype, currentapid, currentac3, duration)) { + pthread_t thrStartHint; + if (is_file_player) { + showStartingHint = true; + pthread_create(&thrStartHint, NULL, CMoviePlayerGui::ShowStartHint, this); + } + bool res = playback->Start((char *) full_name.c_str(), vpid, vtype, currentapid, currentac3, duration); + if (thrStartHint) { + showStartingHint = false; + pthread_join(thrStartHint, NULL); + } + + if(!res) { playback->Close(); } else { playstate = CMoviePlayerGui::PLAY; @@ -847,7 +900,7 @@ void CMoviePlayerGui::addAudioFormat(int count, std::string &apidtitle, bool& en void CMoviePlayerGui::getCurrentAudioName( bool file_player, std::string &audioname) { - if(file_player && !numpida){ + if(file_player && !numpida){ playback->FindAllPids(apids, ac3flags, &numpida, language); if(numpida) currentapid = apids[0]; @@ -1344,7 +1397,7 @@ void CMoviePlayerGui::showSubtitle(neutrino_msg_data_t data) if (sub->format == 0) { int xres = 0, yres = 0, framerate; videoDecoder->getPictureInfo(xres, yres, framerate); - + double xc = (double) CFrameBuffer::getInstance()->getScreenWidth(/*true*/)/(double) xres; double yc = (double) CFrameBuffer::getInstance()->getScreenHeight(/*true*/)/(double) yres; diff --git a/src/gui/movieplayer.h b/src/gui/movieplayer.h index c3356e12e..46282be89 100644 --- a/src/gui/movieplayer.h +++ b/src/gui/movieplayer.h @@ -98,6 +98,9 @@ class CMoviePlayerGui : public CMenuTarget /* playback from MB */ bool isMovieBrowser; + bool isHTTP; + bool isUPNP; + bool showStartingHint; CMovieBrowser* moviebrowser; MI_MOVIE_INFO * p_movie_info; const static short MOVIE_HINT_BOX_TIMER = 5; // time to show bookmark hints in seconds @@ -138,6 +141,9 @@ class CMoviePlayerGui : public CMenuTarget void clearSubtitle(); void selectChapter(); + void Cleanup(); + static void *ShowStartHint(void *arg); + CMoviePlayerGui(const CMoviePlayerGui&) {}; CMoviePlayerGui(); @@ -155,6 +161,7 @@ class CMoviePlayerGui : public CMenuTarget void UpdatePosition(); int timeshift; int file_prozent; + void SetFile(std::string &name, std::string &file) { file_name = name; full_name = file; } }; #endif From 34985774609194254bc9f740e02bebb692448a3c Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 12:27:36 +0400 Subject: [PATCH 011/200] lib/libcoolstream2/playback_cs.h: update apollo header --- lib/libcoolstream2/playback_cs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libcoolstream2/playback_cs.h b/lib/libcoolstream2/playback_cs.h index f65bdc6f0..5a5c61fb6 100644 --- a/lib/libcoolstream2/playback_cs.h +++ b/lib/libcoolstream2/playback_cs.h @@ -66,6 +66,7 @@ public: void FindAllSubs(uint16_t *pids, unsigned short *supported, uint16_t *numpida, std::string *language); bool SelectSubtitles(int pid); void GetChapters(std::vector &positions, std::vector &titles); + void RequestAbort(); }; #endif // __PLAYBACK_CS_H_ From 0e72bf5905a5a3144e091acceb10e08928ffed7c Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 14:25:43 +0400 Subject: [PATCH 012/200] gui/channellist.cpp: disable show bouquet name on VFD --- src/gui/channellist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/channellist.cpp b/src/gui/channellist.cpp index 9ee495286..2be1be6ba 100644 --- a/src/gui/channellist.cpp +++ b/src/gui/channellist.cpp @@ -501,7 +501,7 @@ int CChannelList::exec() void CChannelList::calcSize() { - CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, name.c_str()); + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8 /*, name.c_str()*/); // recalculate theight, fheight and footerHeight for a possilble change of fontsize factor theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); From 4902c39f9502d22547148e1b3506d7a57200f84a Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 18:11:44 +0400 Subject: [PATCH 013/200] locals: add hint locale for xupnpd network service --- data/locale/english.locale | 1 + src/system/locals.h | 1 + src/system/locals_intern.h | 1 + 3 files changed, 3 insertions(+) diff --git a/data/locale/english.locale b/data/locale/english.locale index df59207f6..a54f507f3 100644 --- a/data/locale/english.locale +++ b/data/locale/english.locale @@ -961,6 +961,7 @@ menu.hint_net_ssid Enter SSID of wireless network\nyou want to connect to menu.hint_net_telnet Enable telnet login to your box menu.hint_net_test Test network connection: ping gateway,\n name server and external IP menu.hint_net_ushare Share connected HDD over uPnp +menu.hint_net_xupnpd Share live channels over UPNP menu.hint_network IP address, gateway, DNS, Time sync\nNetwork shares and services menu.hint_new_zap_mode Allow channel switch while browsing\n(toggle mode with 'mute' in channel list) menu.hint_numeric_adjust Adjust channel list mode on numeric zap diff --git a/src/system/locals.h b/src/system/locals.h index 8cca97420..cc038bc92 100644 --- a/src/system/locals.h +++ b/src/system/locals.h @@ -988,6 +988,7 @@ typedef enum LOCALE_MENU_HINT_NET_TELNET, LOCALE_MENU_HINT_NET_TEST, LOCALE_MENU_HINT_NET_USHARE, + LOCALE_MENU_HINT_NET_XUPNPD, LOCALE_MENU_HINT_NETWORK, LOCALE_MENU_HINT_NEW_ZAP_MODE, LOCALE_MENU_HINT_NUMERIC_ADJUST, diff --git a/src/system/locals_intern.h b/src/system/locals_intern.h index 6d89d4a77..477b78084 100644 --- a/src/system/locals_intern.h +++ b/src/system/locals_intern.h @@ -988,6 +988,7 @@ const char * locale_real_names[] = "menu.hint_net_telnet", "menu.hint_net_test", "menu.hint_net_ushare", + "menu.hint_net_xupnpd", "menu.hint_network", "menu.hint_new_zap_mode", "menu.hint_numeric_adjust", From 6527334a0e81834cb1d24fa6559e1ab4d8bbf188 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 18:12:14 +0400 Subject: [PATCH 014/200] gui/network_service.cpp: add xupnpd service --- src/gui/network_service.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/network_service.cpp b/src/gui/network_service.cpp index 9668f1e2e..2fa4c2c79 100644 --- a/src/gui/network_service.cpp +++ b/src/gui/network_service.cpp @@ -50,13 +50,14 @@ struct network_service int enabled; }; -#define SERVICE_COUNT 4 +#define SERVICE_COUNT 5 static struct network_service services[SERVICE_COUNT] = { { "FTP", "vsftpd", "", LOCALE_MENU_HINT_NET_FTPD, "", 0 }, { "Telnet", "telnetd", "-l/bin/login", LOCALE_MENU_HINT_NET_TELNET, "", 0 }, { "DjMount", "djmount", "-o iocharset=utf8 /media/00upnp/", LOCALE_MENU_HINT_NET_DJMOUNT, "", 0 }, - { "uShare", "ushare", "-D -n `cat /etc/hostname`", LOCALE_MENU_HINT_NET_USHARE, "", 0 } + { "uShare", "ushare", "-D -n `cat /etc/hostname`", LOCALE_MENU_HINT_NET_USHARE, "", 0 }, + { "xupnpd", "xupnpd", "", LOCALE_MENU_HINT_NET_XUPNPD, "", 0 }, }; CNetworkService::CNetworkService(std::string cmd, std::string opts) From 48d12add87f9abf7d4bf3232c70c4a5edbdabf1e Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 18:18:05 +0400 Subject: [PATCH 015/200] gui/upnpbrowser.cpp: re-work, reuse code; unify list scroll; change folder play key to 'play', OK/right select items; add picture display and video playback - parts based on code (c) martii ; work in progress, not complete --- src/gui/upnpbrowser.cpp | 1135 ++++++++++++++++++--------------------- src/gui/upnpbrowser.h | 35 +- 2 files changed, 545 insertions(+), 625 deletions(-) diff --git a/src/gui/upnpbrowser.cpp b/src/gui/upnpbrowser.cpp index 48ed0808c..7f266416f 100644 --- a/src/gui/upnpbrowser.cpp +++ b/src/gui/upnpbrowser.cpp @@ -36,7 +36,6 @@ #include #include -#include #include #include @@ -50,26 +49,23 @@ #include #include -#include - #include -#include #include -#include +#include #include #include #include -#include #include #include -#include -#include - #include +#include +#include #include + extern cVideo * videoDecoder; +extern CPictureViewer * g_PicViewer; const struct button_label RescanButton = {NEUTRINO_ICON_BUTTON_BLUE , LOCALE_UPNPBROWSER_RESCAN}; const struct button_label BrowseButtons[4] = @@ -80,51 +76,37 @@ const struct button_label BrowseButtons[4] = { NEUTRINO_ICON_BUTTON_OKAY , LOCALE_AUDIOPLAYER_PLAY } }; -//------------------------------------------------------------------------ - CUpnpBrowserGui::CUpnpBrowserGui() { m_socket = new CUPnPSocket(); m_frameBuffer = CFrameBuffer::getInstance(); m_playing_entry_is_shown = false; + dline = NULL; } -//------------------------------------------------------------------------ - CUpnpBrowserGui::~CUpnpBrowserGui() { delete m_socket; + delete dline; } -//------------------------------------------------------------------------ - int CUpnpBrowserGui::exec(CMenuTarget* parent, const std::string & /*actionKey*/) { - CAudioPlayer::getInstance()->init(); if (parent) - { parent->hide(); - } g_Zapit->stopPlayBack(); + //g_Zapit->lockPlayBack(); + CZapit::getInstance()->EnablePlayback(false); videoDecoder->ShowPicture(DATADIR "/neutrino/icons/mp3.jpg"); // tell neutrino we're in audio mode - CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , NeutrinoMessages::mode_audio ); + CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE , NeutrinoMessages::mode_audio); + // remember last mode -#if 0 - CZapitClient::responseGetLastChannel firstchannel; - g_Zapit->getLastChannel(firstchannel.channelNumber, firstchannel.mode); - if ((firstchannel.mode == 'r') ? - (CNeutrinoApp::getInstance()->zapto_radio_on_init_done) : - (CNeutrinoApp::getInstance()->zapto_tv_on_init_done)) - m_LastMode=(CNeutrinoApp::getInstance()->getLastMode() | NeutrinoMessages::norezap); - else - m_LastMode=(CNeutrinoApp::getInstance()->getLastMode()); -#endif m_LastMode=(CNeutrinoApp::getInstance()->getLastMode()); m_width = m_frameBuffer->getScreenWidthRel(); @@ -140,16 +122,17 @@ int CUpnpBrowserGui::exec(CMenuTarget* parent, const std::string & /*actionKey*/ m_listmaxshow = (m_height - m_info_height - m_title_height - m_theight - 2*m_buttonHeight) / (m_fheight); m_height = m_theight + m_info_height + m_title_height + 2*m_buttonHeight + m_listmaxshow * m_fheight; // recalc height - m_x=getScreenStartX( m_width ); + m_x=getScreenStartX(m_width); if (m_x < ConnectLineBox_Width) m_x = ConnectLineBox_Width; - m_y=getScreenStartY( m_height ); + m_y=getScreenStartY(m_height); // Stop sectionsd g_Sectionsd->setPauseScanning(true); - m_indexdevice=0; + m_deviceliststart=0; m_selecteddevice=0; + timeout = 0; selectDevice(); @@ -162,14 +145,14 @@ int CUpnpBrowserGui::exec(CMenuTarget* parent, const std::string & /*actionKey*/ g_Sectionsd->setPauseScanning(false); videoDecoder->StopPicture(); - CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , m_LastMode ); - g_RCInput->postMsg( NeutrinoMessages::SHOW_INFOBAR, 0 ); + //g_Zapit->unlockPlayBack(); + CZapit::getInstance()->EnablePlayback(true); + CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE , m_LastMode); + g_RCInput->postMsg(NeutrinoMessages::SHOW_INFOBAR, 0); - return menu_return::RETURN_EXIT_ALL; + return menu_return::RETURN_REPAINT; } -//------------------------------------------------------------------------ - void CUpnpBrowserGui::splitProtocol(std::string &protocol, std::string &prot, std::string &network, std::string &mime, std::string &additional) { std::string::size_type pos; @@ -204,7 +187,59 @@ void CUpnpBrowserGui::splitProtocol(std::string &protocol, std::string &prot, st //printf("%s -> %s - %s - %s - %s\n", protocol.c_str(), prot.c_str(), network.c_str(), mime.c_str(), additional.c_str()); } -//------------------------------------------------------------------------ +bool CUpnpBrowserGui::discoverDevices() +{ + if (!m_devices.empty()) + return true; + + CHintBox *scanBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_UPNPBROWSER_SCANNING)); // UTF-8 + scanBox->paint(); + + try { + m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); + } + catch (std::runtime_error error) + { + delete scanBox; + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); + return false; + } + delete scanBox; + if (m_devices.empty()) + { + ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, LOCALE_UPNPBROWSER_NOSERVERS, CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); + return false; + } + return true; +} + +bool CUpnpBrowserGui::getResults(std::string id, unsigned int start, unsigned int count, std::list &results) +{ + std::listattribs; + std::stringstream sindex; + std::stringstream scount; + + sindex << start; + scount << count; + + attribs.push_back(UPnPAttribute("ObjectID", id)); + attribs.push_back(UPnPAttribute("BrowseFlag", "BrowseDirectChildren")); + attribs.push_back(UPnPAttribute("Filter", "*")); + attribs.push_back(UPnPAttribute("StartingIndex", sindex.str())); + attribs.push_back(UPnPAttribute("RequestedCount", scount.str())); + attribs.push_back(UPnPAttribute("SortCriteria", "")); + + try + { + results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); + } + catch (std::runtime_error error) + { + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); + return false; + } + return true; +} std::vector *CUpnpBrowserGui::decodeResult(std::string result) { @@ -323,7 +358,11 @@ std::vector *CUpnpBrowserGui::decodeResult(std::string result) splitProtocol(protocol, prot, network, mime, additional); if (prot != "http-get") continue; -#if 0 + + if (mime.substr(0,6) == "image/" && pref < 1) + { + preferred=i; + } if (mime == "image/jpeg" && pref < 1) { preferred=i; @@ -334,7 +373,6 @@ std::vector *CUpnpBrowserGui::decodeResult(std::string result) preferred=i; pref=2; } -#endif if (mime == "audio/mpeg" && pref < 3) { preferred=i; @@ -345,6 +383,26 @@ std::vector *CUpnpBrowserGui::decodeResult(std::string result) preferred=i; pref=4; } + if (mime == "audio/x-flac" && pref < 5) + { + preferred=i; + pref=5; + } + if (mime.substr(0,6) == "video/" && pref < 6) + { + preferred=i; + pref=6; + } + if (mime == "video/x-flv" && pref < 7) + { + preferred=i; + pref=7; + } + if (mime == "video/mp4" && pref < 8) + { + preferred=i; + pref=8; + } } } p = node->GetAttributeValue("id"); @@ -366,109 +424,99 @@ std::vector *CUpnpBrowserGui::decodeResult(std::string result) return entries; } -//------------------------------------------------------------------------ +void CUpnpBrowserGui::updateDeviceSelection(int newpos) +{ + if((int) m_selecteddevice != newpos) { + int prev_selected = m_selecteddevice; + unsigned int oldliststart = m_deviceliststart; + + m_selecteddevice = newpos; + m_deviceliststart = (m_selecteddevice/m_listmaxshow)*m_listmaxshow; + if (oldliststart != m_deviceliststart) + paintDevices(); + else { + paintDevice(prev_selected - m_deviceliststart); + paintDevice(m_selecteddevice - m_deviceliststart); + } + } +} void CUpnpBrowserGui::selectDevice() { bool loop = true; - bool changed = true; + bool refresh = true; neutrino_msg_t msg; neutrino_msg_data_t data; - CHintBox *scanBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_UPNPBROWSER_SCANNING)); // UTF-8 - scanBox->paint(); -#if 0 - try { - m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); - } - catch (std::runtime_error error) - { - delete scanBox; - ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); + if (!discoverDevices()) return; - } -#endif - m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); - scanBox->hide(); - - if (m_devices.empty()) - { - ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, LOCALE_UPNPBROWSER_NOSERVERS, CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); - delete scanBox; - return; - } CAudioMute::getInstance()->enableMuteIcon(false); while (loop) { - if (changed) + if (refresh) { - paintDevice(); - changed=false; + paintDevices(); + refresh=false; } g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display neutrino_msg_t msg_repeatok = msg & ~CRCInput::RC_Repeat; - if ( msg == CRCInput::RC_timeout) + if (msg == CRCInput::RC_timeout) { // nothing } - - else if ( msg == CRCInput::RC_home) + else if (msg == CRCInput::RC_home) { loop=false; } - - else if (msg_repeatok == CRCInput::RC_up && m_selecteddevice > 0) - { - m_selecteddevice--; - if (m_selecteddevice < m_indexdevice) - m_indexdevice-=m_listmaxshow; - changed=true; + else if (msg_repeatok == (neutrino_msg_t) g_settings.key_list_start) { + updateDeviceSelection(0); } - - else if (msg_repeatok == CRCInput::RC_down && m_selecteddevice + 1 < m_devices.size()) - { - m_selecteddevice++; - if (m_selecteddevice + 1 > m_indexdevice + m_listmaxshow) - m_indexdevice+=m_listmaxshow; - changed=true; + else if (msg_repeatok == (neutrino_msg_t) g_settings.key_list_end) { + updateDeviceSelection(m_devices.size()-1); } - - else if ( msg == CRCInput::RC_right || msg == CRCInput::RC_ok) + else if (msg_repeatok == CRCInput::RC_up || (int) msg == g_settings.key_channelList_pageup) + { + int step = ((int) msg == g_settings.key_channelList_pageup) ? m_listmaxshow : 1; // browse or step 1 + int new_selected = m_selecteddevice - step; + if (new_selected < 0) { + if (m_selecteddevice != 0 && step != 1) + new_selected = 0; + else + new_selected = m_devices.size() - 1; + } + updateDeviceSelection(new_selected); + } + else if (msg_repeatok == CRCInput::RC_down || (int) msg == g_settings.key_channelList_pagedown) + { + int step = ((int) msg == g_settings.key_channelList_pagedown) ? m_listmaxshow : 1; // browse or step 1 + int new_selected = m_selecteddevice + step; + if (new_selected >= (int) m_devices.size()) { + if ((m_devices.size() - m_listmaxshow -1 < m_selecteddevice) && (m_selecteddevice != (m_devices.size() - 1)) && (step != 1)) + new_selected = m_devices.size() - 1; + else if (((m_devices.size() / m_listmaxshow) + 1) * m_listmaxshow == m_devices.size() + m_listmaxshow) // last page has full entries + new_selected = 0; + else + new_selected = ((step == (int) m_listmaxshow) && (new_selected < (int) (((m_devices.size() / m_listmaxshow)+1) * m_listmaxshow))) ? (m_devices.size() - 1) : 0; + } + updateDeviceSelection(new_selected); + } + else if (msg == CRCInput::RC_right || msg == CRCInput::RC_ok) { m_folderplay = false; selectItem("0"); - changed=true; + refresh=true; } - - else if ( msg == CRCInput::RC_blue) + else if (msg == CRCInput::RC_blue) { - scanBox->paint(); -#if 0 - try { - m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); - } - catch (std::runtime_error error) - { - delete scanBox; - ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); + m_devices.clear(); + if (!discoverDevices()) return; - } -#endif - m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); - scanBox->hide(); - if (m_devices.empty()) - { - ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, LOCALE_UPNPBROWSER_NOSERVERS, CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); - delete scanBox; - return; - } - changed=true; + refresh=true; } - else if (msg == NeutrinoMessages::RECORD_START || msg == NeutrinoMessages::ZAPTO || msg == NeutrinoMessages::STANDBY_ON || @@ -478,57 +526,34 @@ void CUpnpBrowserGui::selectDevice() loop=false; g_RCInput->postMsg(msg, data); } - else if (msg == NeutrinoMessages::EVT_TIMER) { - CNeutrinoApp::getInstance()->handleMsg( msg, data ); + CNeutrinoApp::getInstance()->handleMsg(msg, data); } - - else + else if (msg > CRCInput::RC_MaxRC) { - if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) loop = false; - changed=true; } } - delete scanBox; - CAudioMute::getInstance()->enableMuteIcon(true); } -//------------------------------------------------------------------------ - void CUpnpBrowserGui::playnext(void) { + std::vector *entries = NULL; while (true) { - std::listattribs; + timeout = 0; + std::listresults; std::list::iterator i; - std::stringstream sindex; - std::vector *entries = NULL; - sindex << m_playid; - attribs.push_back(UPnPAttribute("ObjectID", m_playfolder)); - attribs.push_back(UPnPAttribute("BrowseFlag", "BrowseDirectChildren")); - attribs.push_back(UPnPAttribute("Filter", "*")); - attribs.push_back(UPnPAttribute("StartingIndex", sindex.str())); - attribs.push_back(UPnPAttribute("RequestedCount", "1")); - attribs.push_back(UPnPAttribute("SortCriteria", "")); - -#if 0 - try - { - results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); - } - catch (std::runtime_error error) - { - ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); + printf("playnext: getResults m_playfolder %s m_playid %d\n", m_playfolder.c_str(), m_playid); + if (!getResults(m_playfolder, m_playid, 1, results)) { m_folderplay = false; return; } -#endif - results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); for (i=results.begin(); i!=results.end(); ++i) { if (i->first=="NumberReturned") @@ -539,15 +564,12 @@ void CUpnpBrowserGui::playnext(void) return; } } - if (i->first=="TotalMatches") - { - } - if (i->first=="Result") + else if (i->first=="Result") { entries=decodeResult(i->second); } } - m_playid++; + //m_playid++; if ((entries != NULL) && (!(*entries)[0].isdir)) { int preferred=(*entries)[0].preferred; @@ -556,285 +578,252 @@ void CUpnpBrowserGui::playnext(void) std::string protocol, prot, network, mime, additional; protocol=(*entries)[0].resources[preferred].protocol; splitProtocol(protocol, prot, network, mime, additional); - if (mime == "audio/mpeg") - { + if (mime == "audio/mpeg" || mime == "audio/x-vorbis+ogg" || mime == "audio/x-flac") { m_playing_entry = (*entries)[0]; m_playing_entry_is_shown = false; - CAudiofile mp3((*entries)[0].resources[preferred].url, CFile::FILE_MP3); - CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); - return; + playAudio((*entries)[0].resources[preferred].url, mime); } - else if (mime == "audio/x-vorbis+ogg") - { - m_playing_entry = (*entries)[0]; - m_playing_entry_is_shown = false; - CAudiofile mp3((*entries)[0].resources[preferred].url, CFile::FILE_OGG); - CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); - return; + else if (mime.substr(0,6) == "video/") { + playVideo((*entries)[0].title, (*entries)[0].resources[preferred].url); + m_folderplay = false; // FIXME else no way to stop in video folder } + else if (mime.substr(0,6) == "image/") { + if (m_folderplay) + timeout = time(NULL) + atoi(g_settings.picviewer_slide_time); + showPicture((*entries)[0].resources[preferred].url); + } + return; } } else { neutrino_msg_t msg; neutrino_msg_data_t data; g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display - if ( msg == CRCInput::RC_home) + if (msg == CRCInput::RC_home) { m_folderplay = false; break; } } } + delete entries; + m_frameBuffer->Clear(); } -//------------------------------------------------------------------------ +bool CUpnpBrowserGui::getItems(std::string id, unsigned int index, std::vector * &entries, unsigned int &total) +{ + bool tfound = false; + bool rfound = false; + bool nfound = false; + unsigned int returned = 0; + std::listresults; + std::list::iterator i; + + delete entries; + entries = NULL; + + printf("getItems: getResults: index %d count %d\n", index, m_listmaxshow); + if (!getResults(id, index, m_listmaxshow, results)) + return false; + + for (i=results.begin(); i!=results.end(); ++i) { + if (i->first=="NumberReturned") { + returned=atoi(i->second.c_str()); + nfound=true; + } else if (i->first=="TotalMatches") { + total=atoi(i->second.c_str()); + tfound=true; + } else if (i->first=="Result") { + entries=decodeResult(i->second); + rfound=true; + } + } + if (!entries || !nfound || !tfound || !rfound || returned != entries->size() || returned == 0) + return false; + + return true; +} + +bool CUpnpBrowserGui::updateItemSelection(std::string id, std::vector * &entries, int newpos, unsigned int &selected, unsigned int &liststart) +{ + if((int) selected != newpos) { + int prev_selected = selected; + unsigned int oldliststart = liststart; + + selected = newpos; + liststart = (selected/m_listmaxshow)*m_listmaxshow; + printf("updateItemSelection: list start old %d new %d selected old %d new %d\n", oldliststart, liststart, prev_selected, selected); + if (oldliststart != liststart) { + unsigned int total; + if (!getItems(id, liststart, entries, total)) + return false; + paintItems(entries, selected - liststart, total - liststart, liststart); + } else { + paintItem(entries, prev_selected - liststart, selected - liststart); + paintItem(entries, selected - liststart, selected - liststart); + } + } + return true; +} bool CUpnpBrowserGui::selectItem(std::string id) { bool loop = true; bool endall = false; - bool changed = true; - bool rchanged = true; + bool refresh = true; neutrino_msg_t msg; neutrino_msg_data_t data; std::vector *entries = NULL; - unsigned int index, selected, dirnum; - index=0; - selected=0; - dirnum=0; - - while (loop) - { + unsigned int liststart = 0; + unsigned int selected = 0; + unsigned int total = 0; + + printf("selectItem: [%s]\n", id.c_str()); + if (!getItems(id, liststart, entries, total)) + return endall; + + while (loop) { updateTimes(); - if (rchanged) - { - std::listattribs; - std::listresults; - std::list::iterator i; - std::stringstream sindex; - std::stringstream scount; - unsigned int returned = 0; - bool rfound = false; - bool nfound = false; - bool tfound = false; - - sindex << index; - scount << m_listmaxshow; - - attribs.push_back(UPnPAttribute("ObjectID", id)); - attribs.push_back(UPnPAttribute("BrowseFlag", "BrowseDirectChildren")); - attribs.push_back(UPnPAttribute("Filter", "*")); - attribs.push_back(UPnPAttribute("StartingIndex", sindex.str())); - attribs.push_back(UPnPAttribute("RequestedCount", scount.str())); - attribs.push_back(UPnPAttribute("SortCriteria", "")); -#if 0 - try - { - results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); - } - catch (std::runtime_error error) - { - ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); - if (entries) - delete entries; - return endall; - } -#endif - results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); - for (i=results.begin(); i!=results.end(); ++i) - { - if (i->first=="NumberReturned") - { - returned=atoi(i->second.c_str()); - nfound=true; - } - if (i->first=="TotalMatches") - { - dirnum=atoi(i->second.c_str()); - tfound=true; - } - if (i->first=="Result") - { - entries=decodeResult(i->second); - rfound=true; - } - } - if (!entries) - return endall; - if (!nfound || !tfound || !rfound) - { - delete entries; - return endall; - } - if (returned != entries->size()) - { - delete entries; - return endall; - } - - if (returned == 0) - { - delete entries; - return endall; - } - rchanged=false; - changed=true; - } - - if (changed) - { - paintItem(entries, selected - index, dirnum - index, index); - changed=false; + if (refresh) { + printf("selectItem: refresh, timeout = %d\n", (int) timeout); + if (!timeout) + paintItems(entries, selected - liststart, total - liststart, liststart); + refresh=false; } g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display neutrino_msg_t msg_repeatok = msg & ~CRCInput::RC_Repeat; - if ( msg == CRCInput::RC_timeout) - { + if (msg == CRCInput::RC_timeout) { // nothing } - else if (msg == CRCInput::RC_home) - { + else if (msg == CRCInput::RC_home) { loop=false; endall=true; } - else if (msg == CRCInput::RC_left) - { + else if (!timeout && (msg == CRCInput::RC_left)) { loop=false; } - - else if (msg_repeatok == CRCInput::RC_up && selected > 0) - { - selected--; - if (selected < index) - { - index-=m_listmaxshow; - rchanged=true; - } - changed=true; + else if (!timeout && (msg_repeatok == (neutrino_msg_t) g_settings.key_list_start)) { + updateItemSelection(id, entries, 0, selected, liststart); } - - else if (msg == CRCInput::RC_green && selected > 0) - { - if (index > 0) - { - index-=m_listmaxshow; - selected-=m_listmaxshow; - rchanged=true; - } - else - selected=0; - changed=true; + else if (!timeout && (msg_repeatok == (neutrino_msg_t) g_settings.key_list_end)) { + updateItemSelection(id, entries, total-1, selected, liststart); } - - else if (msg_repeatok == CRCInput::RC_down && selected + 1 < dirnum) - { - selected++; - if (selected + 1 > index + m_listmaxshow) - { - index+=m_listmaxshow; - rchanged=true; + else if (!timeout && (msg_repeatok == CRCInput::RC_up || (int) msg == g_settings.key_channelList_pageup)) { + int step = ((int) msg == g_settings.key_channelList_pageup) ? m_listmaxshow : 1; // browse or step 1 + int new_selected = selected - step; + if (new_selected < 0) { + if (selected != 0 && step != 1) + new_selected = 0; + else + new_selected = total - 1; } - changed=true; + updateItemSelection(id, entries, new_selected, selected, liststart); } - - else if (msg == CRCInput::RC_red && selected + 1 < dirnum) - { - if (index < ((dirnum - 1) / m_listmaxshow) * m_listmaxshow) - { - index+=m_listmaxshow; - selected+=m_listmaxshow; - if (selected + 1 >= dirnum) - selected=dirnum - 1; - rchanged=true; + else if (!timeout && (msg_repeatok == CRCInput::RC_down || (int) msg == g_settings.key_channelList_pagedown)) { + int step = ((int) msg == g_settings.key_channelList_pagedown) ? m_listmaxshow : 1; // browse or step 1 + int new_selected = selected + step; + if (new_selected >= (int) total) { + if ((total - m_listmaxshow -1 < selected) && (selected != (total - 1)) && (step != 1)) + new_selected = total - 1; + else if (((total / m_listmaxshow) + 1) * m_listmaxshow == total + m_listmaxshow) // last page has full entries + new_selected = 0; + else + new_selected = ((step == (int) m_listmaxshow) && (new_selected < (int) (((total / m_listmaxshow)+1) * m_listmaxshow))) ? (total - 1) : 0; } - else - selected=dirnum - 1; - changed=true; + updateItemSelection(id, entries, new_selected, selected, liststart); } - - else if (msg == CRCInput::RC_right) - { - if ((*entries)[selected - index].isdir) - { - endall=selectItem((*entries)[selected - index].id); + else if (!timeout && (msg == CRCInput::RC_ok || msg == CRCInput::RC_right)) { + if ((*entries)[selected - liststart].isdir) { + endall=selectItem((*entries)[selected - liststart].id); if (endall) loop=false; - } - changed=true; - } - else if (msg == CRCInput::RC_ok) - { - if (!(*entries)[selected - index].isdir) - { + refresh=true; + } else { m_folderplay = false; - int preferred=(*entries)[selected - index].preferred; + int preferred=(*entries)[selected - liststart].preferred; if (preferred != -1) { std::string protocol, prot, network, mime, additional; - protocol=(*entries)[selected - index].resources[preferred].protocol; + protocol=(*entries)[selected - liststart].resources[preferred].protocol; splitProtocol(protocol, prot, network, mime, additional); - if (mime == "audio/mpeg") + if (mime == "audio/mpeg" || mime == "audio/x-vorbis+ogg" || mime == "audio/x-flac") { - CAudiofile mp3((*entries)[selected - index].resources[preferred].url, CFile::FILE_MP3); - CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); + m_playing_entry = (*entries)[selected - liststart]; + m_playing_entry_is_shown = false; + playAudio((*entries)[selected - liststart].resources[preferred].url, mime); } - else if (mime == "audio/x-vorbis+ogg") + else if (mime.substr(0,6) == "video/") { - CAudiofile mp3((*entries)[selected - index].resources[preferred].url, CFile::FILE_OGG); - CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); - } - m_playing_entry = (*entries)[selected - index]; -#if 0 // TODO ! -// #ifdef ENABLE_PICTUREVIEWER - else if ((mime == "image/gif") || (mime == "image/jpeg")) - { - CPictureViewer *viewer = new CPictureViewer(); - bool loop=true; - viewer->SetScaling((CPictureViewer::ScalingMode)g_settings.picviewer_scaling); - viewer->SetVisible(g_settings.screen_StartX, g_settings.screen_EndX, g_settings.screen_StartY, g_settings.screen_EndY); - - if (g_settings.video_Format==1) - viewer->SetAspectRatio(16.0/9); - else - viewer->SetAspectRatio(4.0/3); - - m_frameBuffer->setMode(720, 576, 16); - m_frameBuffer->setTransparency(0); - viewer->ShowImage((*entries)[selected - index].resources[preferred].url, true); - while (loop) - { - g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display - - if ( msg == CRCInput::RC_home) - loop=false; - } - m_frameBuffer->setMode(720, 576, 8 * sizeof(fb_pixel_t)); m_frameBuffer->Clear(); - delete viewer; + playVideo((*entries)[selected - liststart].title, (*entries)[selected - liststart].resources[preferred].url); + videoDecoder->ShowPicture(DATADIR "/neutrino/icons/mp3.jpg"); + refresh = true; } -// #endif -#endif - } + else if (mime.substr(0,6) == "image/") + { + videoDecoder->setBlank(true); + showPicture((*entries)[selected - liststart].resources[preferred].url); + m_playid = selected; + while (true) + { + g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout - } else { - m_folderplay = true; - m_playfolder = (*entries)[selected - index].id; - m_playid = 0; - playnext(); + if (msg == CRCInput::RC_home || msg == CRCInput::RC_ok) + break; + else if (msg == CRCInput::RC_right || msg == CRCInput::RC_down) { + m_playfolder = id; + m_playid = (m_playid + 1)%total; + playnext(); + } + else if (msg == CRCInput::RC_left || msg == CRCInput::RC_up) { + m_playfolder = id; + m_playid--; + if (m_playid < 0) + m_playid = total - 1; + playnext(); + } else + CNeutrinoApp::getInstance()->handleMsg(msg, data); + } + m_frameBuffer->Clear(); + videoDecoder->setBlank(false); + refresh = true; + } + } } - changed=true; } - else if ( msg == CRCInput::RC_yellow) - { + else if (msg == CRCInput::RC_play) { + m_folderplay = true; + m_playfolder = (*entries)[selected - liststart].id; + m_playid = 0; + playnext(); + m_playid++; + } + else if (msg == CRCInput::RC_yellow) { if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP) CAudioPlayer::getInstance()->stop(); m_folderplay = false; } - + else if (m_folderplay && msg == (neutrino_msg_t) CRCInput::RC_stop) { + timeout = 0; + m_folderplay = false; + m_frameBuffer->Clear(); + refresh = true; + } + else if (m_folderplay && msg == (neutrino_msg_t) CRCInput::RC_prev) { + timeout = 0; + m_playid -= 2; + if (m_playid < 0) + m_playid = 0; + } + else if (m_folderplay && msg == (neutrino_msg_t) CRCInput::RC_next) { + timeout = 0; + if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP) + CAudioPlayer::getInstance()->stop(); + } else if (msg == NeutrinoMessages::RECORD_START || msg == NeutrinoMessages::ZAPTO || msg == NeutrinoMessages::STANDBY_ON || @@ -844,39 +833,80 @@ bool CUpnpBrowserGui::selectItem(std::string id) loop = false; g_RCInput->postMsg(msg, data); } - else if (msg == NeutrinoMessages::EVT_TIMER) { - CNeutrinoApp::getInstance()->handleMsg( msg, data ); + CNeutrinoApp::getInstance()->handleMsg(msg, data); } - - else + else if (msg > CRCInput::RC_MaxRC) { - if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) loop = false; - changed=true; + //refresh=true; } - if (m_folderplay && (CAudioPlayer::getInstance()->getState() == CBaseDec::STOP)) + if (m_folderplay && ((!timeout || (timeout <= time(NULL))) && (CAudioPlayer::getInstance()->getState() == CBaseDec::STOP))) { playnext(); + m_playid++; + } } - if (entries) - delete entries; + + delete entries; + timeout = 0; + m_frameBuffer->Clear(); + return endall; } -//------------------------------------------------------------------------ - -void CUpnpBrowserGui::paintDevicePos(unsigned int pos) +void CUpnpBrowserGui::paintDeviceInfo() { - int ypos = m_y + m_title_height + m_theight + pos*m_fheight; + std::string tmp; + int w, xstart; + + CVFD::getInstance()->showMenuText(0, m_devices[m_selecteddevice].friendlyname.c_str(), -1, true); + + // Info + m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10, COL_MENUCONTENT_PLUS_6, RADIUS_MID); + m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2, m_width - 4, m_title_height - 14, COL_MENUCONTENTSELECTED_PLUS_0, RADIUS_MID); + + // first line + tmp = m_devices[m_selecteddevice].manufacturer + " " + + m_devices[m_selecteddevice].manufacturerurl; + w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 + w = std::min(w, m_width - 20); + xstart = (m_width - w) / 2; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 1*m_mheight, m_width - 20, + tmp, COL_MENUCONTENTSELECTED_TEXT, 0, true); // UTF-8 + + // second line + tmp = m_devices[m_selecteddevice].modelname + " " + + m_devices[m_selecteddevice].modelnumber + " " + + m_devices[m_selecteddevice].modeldescription; + w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 + w = std::min(w, m_width - 20); + xstart = (m_width - w) / 2; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 2*m_mheight, m_width - 20, + tmp, COL_MENUCONTENTSELECTED_TEXT, 0, true); // UTF-8 + // third line + tmp = m_devices[m_selecteddevice].modelurl; + w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 + w = std::min(w, m_width - 20); + xstart = (m_width - w) / 2; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 3*m_mheight, m_width - 20, + tmp, COL_MENUCONTENTSELECTED_TEXT, 0, true); // UTF-8 +} + +void CUpnpBrowserGui::paintDevice(unsigned int _pos) +{ + int ypos = m_y + m_title_height + m_theight + _pos*m_fheight; fb_pixel_t color; fb_pixel_t bgcolor; + unsigned int pos = m_deviceliststart + _pos; if (pos == m_selecteddevice) { color = COL_MENUCONTENT_TEXT_PLUS_2; bgcolor = COL_MENUCONTENT_PLUS_2; + paintDeviceInfo(); } else { @@ -885,14 +915,14 @@ void CUpnpBrowserGui::paintDevicePos(unsigned int pos) } m_frameBuffer->paintBoxRel(m_x, ypos, m_width - 15, m_fheight, bgcolor); - if (pos + m_indexdevice >= m_devices.size()) + if (pos >= m_devices.size()) return; char sNr[20]; sprintf(sNr, "%2d", pos + 1); std::string num = sNr; - std::string name = m_devices[pos + m_indexdevice].friendlyname; + std::string name = m_devices[pos].friendlyname; int w = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getRenderWidth(name) + 5; g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 10, ypos + m_fheight, m_width - 30 - w, @@ -901,9 +931,44 @@ void CUpnpBrowserGui::paintDevicePos(unsigned int pos) w, name, color, m_fheight, true); // UTF-8 } -//------------------------------------------------------------------------ +void CUpnpBrowserGui::paintDevices() +{ + std::string tmp; + int ypos, top; -void CUpnpBrowserGui::paintItemPos(std::vector *entry, unsigned int pos, unsigned int selected) + // LCD + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, "Select UPnP Device"); + + // Head + CComponentsHeader header(m_x, m_y + m_title_height, m_width, m_theight, LOCALE_UPNPBROWSER_HEAD, NEUTRINO_ICON_UPNP); + if (CNeutrinoApp::getInstance()->isMuted()) + header.addButtonIcon(NEUTRINO_ICON_BUTTON_MUTE_SMALL); + header.paint(CC_SAVE_SCREEN_NO); + + // Items + for (unsigned int count=0; countpaintBoxRel(m_x + m_width - 15, ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc = ((m_devices.size() - 1) / m_listmaxshow) + 1; + int sbs = ((m_selecteddevice) / m_listmaxshow); + + m_frameBuffer->paintBoxRel(m_x + m_width - 13, ypos + 2 + sbs*(sb-4)/sbc, 11, (sb-4)/sbc, COL_MENUCONTENT_PLUS_3); + + // Foot + top = m_y + (m_height - m_info_height - 2 * m_buttonHeight); + + m_frameBuffer->paintBoxRel(m_x, top, m_width, m_buttonHeight+2, COL_INFOBAR_SHADOW_PLUS_1, RADIUS_LARGE, CORNER_BOTTOM); +// m_frameBuffer->paintHLine(m_x, m_x + m_width, top, COL_INFOBAR_SHADOW_PLUS_0); + ::paintButtons(m_x, top, 0, 1, &RescanButton, m_width, m_buttonHeight); + + paintItem2DetailsLine (-1); // clear it +} + +void CUpnpBrowserGui::paintItem(std::vector *entry, unsigned int pos, unsigned int selected) { int ypos = m_y + m_title_height + m_theight + pos*m_fheight; fb_pixel_t color; @@ -913,11 +978,12 @@ void CUpnpBrowserGui::paintItemPos(std::vector *entry, unsigned int p { color = COL_MENUCONTENT_TEXT_PLUS_2; bgcolor = COL_MENUCONTENT_PLUS_2; + paintItemInfo(entry, selected); paintDetails(entry, pos); if ((*entry)[pos].isdir) - paintItem2DetailsLine (-1, pos); // clear it + paintItem2DetailsLine (-1); // clear it else - paintItem2DetailsLine (pos, pos); + paintItem2DetailsLine (pos); } else { @@ -960,100 +1026,21 @@ void CUpnpBrowserGui::paintItemPos(std::vector *entry, unsigned int p w, info, color, m_fheight); g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 30, ypos + m_fheight, m_width - 50 - w, name, color, m_fheight, true); // UTF-8 - } -//------------------------------------------------------------------------ - -void CUpnpBrowserGui::paintDevice() -{ - std::string tmp; - int w, xstart, ypos, top; - int c_rad_mid = RADIUS_MID; - - // LCD - CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, "Select UPnP Device"); - CVFD::getInstance()->showMenuText(0, m_devices[m_selecteddevice].friendlyname.c_str(), -1, true); - - // Info - m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10, COL_MENUCONTENT_PLUS_6, c_rad_mid); - m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2, m_width - 4, m_title_height - 14, COL_MENUCONTENTSELECTED_PLUS_0, c_rad_mid); - - // first line - tmp = m_devices[m_selecteddevice].manufacturer + " " + - m_devices[m_selecteddevice].manufacturerurl; - w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 - xstart = (m_width - w) / 2; - if (xstart < 10) - xstart = 10; - g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 1*m_mheight, m_width - 20, - tmp, COL_MENUCONTENTSELECTED_TEXT, 0, true); // UTF-8 - - // second line - tmp = m_devices[m_selecteddevice].modelname + " " + - m_devices[m_selecteddevice].modelnumber + " " + - m_devices[m_selecteddevice].modeldescription; - w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 - xstart = (m_width - w) / 2; - if (xstart < 10) - xstart = 10; - g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 2*m_mheight, m_width - 20, - tmp, COL_MENUCONTENTSELECTED_TEXT, 0, true); // UTF-8 - // third line - tmp = m_devices[m_selecteddevice].modelurl; - w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 - xstart = (m_width - w) / 2; - if (xstart < 10) - xstart = 10; - g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 3*m_mheight, m_width - 20, - tmp, COL_MENUCONTENTSELECTED_TEXT, 0, true); // UTF-8 - - // Head - CComponentsHeader header(m_x, m_y + m_title_height, m_width, m_theight, LOCALE_UPNPBROWSER_HEAD, NEUTRINO_ICON_UPNP, CComponentsHeader::CC_BTN_MENU); - if (CNeutrinoApp::getInstance()->isMuted()) - header.addButtonIcon(NEUTRINO_ICON_BUTTON_MUTE_SMALL); - header.paint(CC_SAVE_SCREEN_NO); - - // Items - for (unsigned int count=0; countpaintBoxRel(m_x + m_width - 15, ypos, 15, sb, COL_MENUCONTENT_PLUS_1); - - int sbc = ((m_devices.size() - 1) / m_listmaxshow) + 1; - int sbs = ((m_selecteddevice) / m_listmaxshow); - - m_frameBuffer->paintBoxRel(m_x + m_width - 13, ypos + 2 + sbs*(sb-4)/sbc, 11, (sb-4)/sbc, COL_MENUCONTENT_PLUS_3); - - // Foot - top = m_y + (m_height - m_info_height - 2 * m_buttonHeight); - - //int ButtonWidth = (m_width - 20) / 4; - m_frameBuffer->paintBoxRel(m_x, top, m_width, m_buttonHeight+2, COL_INFOBAR_SHADOW_PLUS_1, c_rad_mid, CORNER_BOTTOM); -// m_frameBuffer->paintHLine(m_x, m_x + m_width, top, COL_INFOBAR_SHADOW_PLUS_0); - ::paintButtons(m_x, top, 0, 1, &RescanButton, m_width, m_buttonHeight); - - clearItem2DetailsLine(); // clear it -} - -//------------------------------------------------------------------------ - -void CUpnpBrowserGui::paintItem(std::vector *entry, unsigned int selected, unsigned int max, unsigned int offset) +void CUpnpBrowserGui::paintItemInfo(std::vector *entry, unsigned int selected) { std::string tmp; std::stringstream ts; - int w, xstart, ypos, top; + int w, xstart; int preferred=(*entry)[selected].preferred; // LCD - CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, "Select UPnP Entry"); CVFD::getInstance()->showMenuText(0, (*entry)[selected].title.c_str(), -1, true); // Info - m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10, COL_MENUCONTENT_PLUS_6); - m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2, m_width - 4, m_title_height - 14, COL_MENUCONTENTSELECTED_PLUS_0); + m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10, COL_MENUCONTENT_PLUS_6, RADIUS_MID); + m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2, m_width - 4, m_title_height - 14, COL_MENUCONTENTSELECTED_PLUS_0, RADIUS_MID); // first line ts << "Resources: " << (*entry)[selected].resources.size() << " Selected: " << preferred+1 << " "; @@ -1063,12 +1050,10 @@ void CUpnpBrowserGui::paintItem(std::vector *entry, unsigned int sele tmp = tmp + "Duration: " + (*entry)[selected].resources[preferred].duration; else tmp = tmp + "No resource for Item"; + w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 - if (w > m_width - 20) - w = m_width - 20; + w = std::min(w, m_width - 20); xstart = (m_width - w) / 2; - if (xstart < 10) - xstart = 10; g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 1*m_mheight, m_width - 20, tmp, COL_MENUCONTENTSELECTED_TEXT, 0, true); // UTF-8 @@ -1084,61 +1069,45 @@ void CUpnpBrowserGui::paintItem(std::vector *entry, unsigned int sele splitProtocol((*entry)[selected].resources[preferred].protocol, proto, network, mime, info); tmp = "Protocol: " + proto + ", MIME-Type: " + mime; } - } w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 - if (w > m_width - 20) - w = m_width - 20; + w = std::min(w, m_width - 20); xstart = (m_width - w) / 2; - if (xstart < 10) - xstart = 10; g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 2*m_mheight, m_width - 20, tmp, COL_MENUCONTENTSELECTED_TEXT, 0, true); // UTF-8 //third line tmp = ""; - if (!(*entry)[selected].isdir) - { - if (preferred != -1) - { - tmp = "URL: " + (*entry)[selected].resources[preferred].url; - } + if (!(*entry)[selected].isdir && preferred != -1) + tmp = "URL: " + (*entry)[selected].resources[preferred].url; - } w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 - if (w > m_width - 20) - w = m_width - 20; + w = std::min(w, m_width - 20); xstart = (m_width - w) / 2; - if (xstart < 10) - xstart = 10; g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 3*m_mheight, m_width - 20, tmp, COL_MENUCONTENTSELECTED_TEXT, 0, true); // UTF-8 +} +void CUpnpBrowserGui::paintItems(std::vector *entry, unsigned int selected, unsigned int max, unsigned int offset) +{ +printf("CUpnpBrowserGui::paintItem:s selected %d max %d offset %d\n", selected, max, offset); + int ypos, top; + + // LCD + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, "Select UPnP Entry"); // Head - tmp = g_Locale->getText(LOCALE_UPNPBROWSER_HEAD); - m_frameBuffer->paintBoxRel(m_x, m_y + m_title_height, m_width, m_theight, COL_MENUHEAD_PLUS_0); - m_frameBuffer->paintIcon(NEUTRINO_ICON_UPNP, m_x + 7, m_y + m_title_height + 6); - g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(m_x + 35, m_y + m_theight + m_title_height + 0, - m_width - 45, tmp, COL_MENUHEAD_TEXT, 0, true); // UTF-8 - ypos = m_y + m_title_height; - if (m_theight > 26) - ypos = (m_theight - 26) / 2 + m_y + m_title_height; - m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_MENU, m_x + m_width - 30, ypos); -#if 0 - if ( CNeutrinoApp::getInstance()->isMuted() ) - { - xpos = m_x + m_width - 75; - ypos = m_y + m_title_height; - if (m_theight > 32) - ypos = (m_theight - 32) / 2 + m_y + m_title_height; - m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_MUTE, xpos, ypos); - } -#endif + std::string name = g_Locale->getText(LOCALE_UPNPBROWSER_HEAD); + name += " : "; + name += m_devices[m_selecteddevice].friendlyname; + CComponentsHeader header(m_x, m_y + m_title_height, m_width, m_theight, name, NEUTRINO_ICON_UPNP); + if (CNeutrinoApp::getInstance()->isMuted()) + header.addButtonIcon(NEUTRINO_ICON_BUTTON_MUTE_SMALL); + header.paint(CC_SAVE_SCREEN_NO); // Items for (unsigned int count=0; count *entry, unsigned int sele ::paintButtons(m_x, top, 0, 4, BrowseButtons, m_width, m_buttonHeight); } - -//------------------------------------------------------------------------ - void CUpnpBrowserGui::paintDetails(std::vector *entry, unsigned int index, bool use_playing) { // Foot info int top = m_y + (m_height - m_info_height - 1 * m_buttonHeight) + 2; int text_start = m_x + 10; +printf("paintDetails: index %d use_playing %d shown %d\n", index, use_playing, m_playing_entry_is_shown); if ((!use_playing) && ((*entry)[index].isdir)) { - m_frameBuffer->paintBackgroundBoxRel(m_x+2, top + 2, m_width-4, 2 * m_buttonHeight+8); + m_frameBuffer->paintBackgroundBoxRel(m_x+2, top + 2, m_width-4, 2 * m_buttonHeight+8); + m_playing_entry_is_shown = false; } else { -// char cNoch[50]; // UTF-8 -// char cSeit[50]; // UTF-8 int ih = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getHeight(); - m_frameBuffer->paintBoxRel(m_x, top + 2, m_width-2, 2 * ih, COL_MENUCONTENTDARK_PLUS_0, RADIUS_LARGE); - if (use_playing) + //m_frameBuffer->paintBoxRel(m_x, top + 2, m_width-2, 2 * ih, COL_MENUCONTENTDARK_PLUS_0, RADIUS_LARGE); + if (use_playing) { - if (!m_playing_entry_is_shown) + if (!m_playing_entry_is_shown) { m_playing_entry_is_shown = true; + m_frameBuffer->paintBoxRel(m_x, top + 2, m_width-2, 2 * ih, COL_MENUCONTENTDARK_PLUS_0, RADIUS_LARGE); g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(text_start, top + 1 * m_buttonHeight + 4, m_x + m_width - 8, m_playing_entry.title + " - " + m_playing_entry.artist, COL_MENUCONTENTDARK_TEXT, 0, true); // UTF-8 g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(text_start, top + 2 * m_buttonHeight + 4, m_x + m_width - 8, m_playing_entry.album, COL_MENUCONTENTDARK_TEXT, 0, true); // UTF-8 } - } - else + } + else { if (entry == NULL) return; m_playing_entry_is_shown = false; + m_frameBuffer->paintBoxRel(m_x, top + 2, m_width-2, 2 * ih, COL_MENUCONTENTDARK_PLUS_0, RADIUS_LARGE); g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(text_start, top + 1 * m_buttonHeight + 4, m_x + m_width - 8, (*entry)[index].title + " - " + (*entry)[index].artist, COL_MENUCONTENTDARK_TEXT, 0, true); // UTF-8 g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(text_start, top + 2 * m_buttonHeight + 4, m_x + m_width - 8, (*entry)[index].album, COL_MENUCONTENTDARK_TEXT, 0, true); // UTF-8 } -//// printf("title = %s\n", (*entry)[selected].title.c_str()); -// printf("artist = %s\n", (*entry)[selected].artist.c_str()); -// printf("album = %s\n", (*entry)[selected].album.c_str()); -// printf("children = %s\n", (*entry)[selected].children.c_str()); -// printf("id = %s\n", (*entry)[selected].id.c_str()); -#if 0 - struct tm *pStartZeit = localtime(&chanlist[index]->currentEvent.startTime); - unsigned seit = ( time(NULL) - chanlist[index]->currentEvent.startTime ) / 60; - sprintf( cSeit, g_Locale->getText(LOCALE_CHANNELLIST_SINCE), pStartZeit->tm_hour, pStartZeit->tm_min); //, seit ); - int seit_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getRenderWidth(cSeit, true); // UTF-8 - - int noch = ( chanlist[index]->currentEvent.startTime + chanlist[index]->currentEvent.duration - time(NULL) ) / 60; - if ( (noch< 0) || (noch>=10000) ) - noch= 0; - sprintf( cNoch, "(%d / %d min)", seit, noch ); - int noch_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth(cNoch, true); // UTF-8 - - std::string text1= chanlist[index]->currentEvent.description; - std::string text2= chanlist[index]->currentEvent.text; - - int xstart = 10; - if (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text1) > (width - 30 - seit_len) ) - { - // zu breit, Umbruch versuchen... - int pos; - do - { - pos = text1.find_last_of("[ -.]+"); - if ( pos!=-1 ) - text1 = text1.substr( 0, pos ); - } while ( ( pos != -1 ) && (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text1) > (width - 30 - seit_len) ) ); - - std::string text3= chanlist[index]->currentEvent.description.substr(text1.length()+ 1); - if (!(text2.empty())) - text3 += " . "; - - xstart += g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text3); - g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ 2* fheight, width - 30- noch_len, text3, COL_MENUCONTENTDARK_TEXT); - } - - if (!(text2.empty())) - { - while ( text2.find_first_of("[ -.+*#?=!$%&/]+") == 0 ) - text2 = text2.substr( 1 ); - text2 = text2.substr( 0, text2.find('\n') ); - g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ xstart, y+ height+ 5+ 2* fheight, width- xstart- 20- noch_len, text2, COL_MENUCONTENTDARK_TEXT); - } - - g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ fheight, width - 30 - seit_len, text1, COL_MENUCONTENTDARK_TEXT); - g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString (x+ width- 10- seit_len, y+ height+ 5+ fheight , seit_len, cSeit, COL_MENUCONTENTDARK_TEXT, 0, true); // UTF-8 - g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(x+ width- 10- noch_len, y+ height+ 5+ 2* fheight- 2, noch_len, cNoch, COL_MENUCONTENTDARK_TEXT, 0, true); // UTF-8 -#endif - } } -//------------------------------------------------------------------------ - -// -// -- Decoreline to connect ChannelDisplayLine with ChannelDetail display -// -- 2002-03-17 rasc -// - -void CUpnpBrowserGui::clearItem2DetailsLine () +void CUpnpBrowserGui::paintItem2DetailsLine (int pos) { - paintItem2DetailsLine (-1, 0); -} + if (dline) { + dline->kill(); + delete dline; + dline = NULL; + } -//------------------------------------------------------------------------ + if (pos < 0) + return; -void CUpnpBrowserGui::paintItem2DetailsLine (int pos, unsigned int /*ch_index*/) -{ int xpos = m_x - ConnectLineBox_Width; int ypos1 = m_y + m_title_height+0 + m_theight + pos*m_fheight; int ypos2 = m_y + (m_height - m_info_height - 1 * m_buttonHeight) + 2; int ypos1a = ypos1 + (m_fheight/2); int ypos2a = ypos2 + (m_info_height/2)-4; - fb_pixel_t col1 = COL_MENUCONTENT_PLUS_6; - fb_pixel_t col2 = COL_MENUCONTENT_PLUS_1; - // Clear - m_frameBuffer->paintBackgroundBoxRel(xpos, m_y + m_title_height, ConnectLineBox_Width, m_height+m_info_height-(m_y + m_title_height)); - if (pos < 0) - m_frameBuffer->paintBackgroundBoxRel(m_x, m_y + (m_height - m_info_height - 1 * m_buttonHeight) + 2, m_width, m_info_height); - - // paint Line if detail info (and not valid list pos) - if (pos >= 0) - { - // 1. col thick line - // vertical - int mh = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getHeight() +2; - m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos1, 4, m_fheight, col1); //left from item - m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos2 + mh/2, 4, mh, col1); //left from detailbox - - // long vertical line - m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 4, ypos2a-ypos1a, col1); - - // short horizontal lines - m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 12, 4, col1); - m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos2a, 12, 4, col1); - - // 2. col small line - m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos1, 1, m_fheight, col2); - m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos2 + mh/2, 1, mh, col2); - - m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 1, ypos2a-ypos1a+4, col2); - - m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 12, 1, col2); - m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-12, ypos2a, 8, 1, col2); - - // small Frame around infobox - m_frameBuffer->paintBoxFrame(m_x, ypos2, m_width, mh*2-2, 2, col1, RADIUS_LARGE); - } + dline = new CComponentsDetailLine(xpos, ypos1a, ypos2a, m_fheight/2+1, m_info_height-RADIUS_LARGE*2); + dline->paint(CC_SAVE_SCREEN_NO); } -//------------------------------------------------------------------------ - void CUpnpBrowserGui::updateTimes(const bool force) { int top; @@ -1329,6 +1204,8 @@ void CUpnpBrowserGui::updateTimes(const bool force) m_time_played = CAudioPlayer::getInstance()->getTimePlayed(); updatePlayed = true; } + +printf("updateTimes: force %d updatePlayed %d\n", force, updatePlayed); char play_time[8]; snprintf(play_time, 7, "%ld:%02ld", m_time_played / 60, m_time_played % 60); char tmp_time[] = "000:00"; @@ -1344,3 +1221,33 @@ void CUpnpBrowserGui::updateTimes(const bool force) } } +void CUpnpBrowserGui::playAudio(std::string name, std::string mime) +{ + CFile::FileType type = mime == "audio/mpeg" ? CFile::FILE_MP3 : mime == "audio/x-vorbis+ogg" ? CFile::FILE_OGG : CFile::FILE_FLAC; + CAudiofile mp3(name, type); + CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); +} + +void CUpnpBrowserGui::showPicture(std::string name) +{ + g_PicViewer->SetScaling((CPictureViewer::ScalingMode)g_settings.picviewer_scaling); + g_PicViewer->SetVisible(g_settings.screen_StartX, g_settings.screen_EndX, g_settings.screen_StartY, g_settings.screen_EndY); + + if (g_settings.video_Format==3) + g_PicViewer->SetAspectRatio(16.0/9); + else + g_PicViewer->SetAspectRatio(4.0/3); + + g_PicViewer->ShowImage(name, false); + g_PicViewer->Cleanup(); +} + +void CUpnpBrowserGui::playVideo(std::string name, std::string url) +{ + if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP) + CAudioPlayer::getInstance()->stop(); + + videoDecoder->StopPicture(); + CMoviePlayerGui::getInstance().SetFile(name, url); + CMoviePlayerGui::getInstance().exec(NULL, "upnp"); +} diff --git a/src/gui/upnpbrowser.h b/src/gui/upnpbrowser.h index c4495d5fc..4014ff6aa 100644 --- a/src/gui/upnpbrowser.h +++ b/src/gui/upnpbrowser.h @@ -81,7 +81,7 @@ class CUpnpBrowserGui : public CMenuTarget int m_x; int m_y; unsigned int m_listmaxshow; - unsigned int m_indexdevice; + unsigned int m_deviceliststart; unsigned int m_selecteddevice; int m_fheight; // Fonthoehe Inhalt int m_theight; // Fonthoehe Titel @@ -95,21 +95,34 @@ class CUpnpBrowserGui : public CMenuTarget int m_playid; time_t m_time_played; bool m_playing_entry_is_shown; + time_t timeout; + CComponentsDetailLine * dline; - void selectDevice(); - bool selectItem(std::string); - void paintItem(std::vector *entry, unsigned int selected, unsigned int max, unsigned int offset); - void paintDevice(); - std::vector *decodeResult(std::string); - void playnext(); + bool discoverDevices(); void splitProtocol(std::string &protocol, std::string &prot, std::string &network, std::string &mime, std::string &additional); - void paintItemPos (std::vector *entry, unsigned int pos, unsigned int selected); - void paintDevicePos(unsigned int pos); + bool getResults(std::string id, unsigned int start, unsigned int count, std::list &results); + std::vector *decodeResult(std::string); + + void updateDeviceSelection(int newpos); + void selectDevice(); + void paintDevices(); + void paintDevice(unsigned int pos); + void paintDeviceInfo(); + void playnext(); + + bool getItems(std::string id, unsigned int index, std::vector * &entries, unsigned int &total); + bool updateItemSelection(std::string id, std::vector * &entries, int newpos, unsigned int &selected, unsigned int &liststart); + bool selectItem(std::string); + void paintItems(std::vector *entry, unsigned int selected, unsigned int max, unsigned int offset); + void paintItem (std::vector *entry, unsigned int pos, unsigned int selected); + void paintItemInfo(std::vector *entry, unsigned int selected); void paintDetails(std::vector *entry, unsigned int index, bool use_playing = false); - void clearItem2DetailsLine (void); - void paintItem2DetailsLine (int pos,unsigned int ch_index); + void paintItem2DetailsLine (int pos); void updateTimes(const bool force = false); + void playAudio(std::string name, std::string mime); + void showPicture(std::string name); + void playVideo(std::string name, std::string url); }; #endif From c2a11f6dd28555d60700440a8290e11d2ee22fb5 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 3 Sep 2013 18:38:01 +0400 Subject: [PATCH 016/200] lib/libcoolstream/playback_cs.h: update apollo header --- lib/libcoolstream/playback_cs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libcoolstream/playback_cs.h b/lib/libcoolstream/playback_cs.h index f65bdc6f0..5a5c61fb6 100644 --- a/lib/libcoolstream/playback_cs.h +++ b/lib/libcoolstream/playback_cs.h @@ -66,6 +66,7 @@ public: void FindAllSubs(uint16_t *pids, unsigned short *supported, uint16_t *numpida, std::string *language); bool SelectSubtitles(int pid); void GetChapters(std::vector &positions, std::vector &titles); + void RequestAbort(); }; #endif // __PLAYBACK_CS_H_ From 347ac82e502f5efc4f23bb884cb5cbc265af12e3 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Wed, 4 Sep 2013 02:20:59 +0200 Subject: [PATCH 017/200] Fix segfault in movieplayer (uninitialized variable) --- src/gui/movieplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/movieplayer.cpp b/src/gui/movieplayer.cpp index 6c78bfbfe..3df95b891 100644 --- a/src/gui/movieplayer.cpp +++ b/src/gui/movieplayer.cpp @@ -505,7 +505,7 @@ void CMoviePlayerGui::PlayFile(void) } file_prozent = 0; - pthread_t thrStartHint; + pthread_t thrStartHint = 0; if (is_file_player) { showStartingHint = true; pthread_create(&thrStartHint, NULL, CMoviePlayerGui::ShowStartHint, this); From a2240f46401ce508513fa6195d6ab576bd2d65f8 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Tue, 3 Sep 2013 23:15:32 +0200 Subject: [PATCH 018/200] Update deutsch.locale --- data/locale/deutsch.locale | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/locale/deutsch.locale b/data/locale/deutsch.locale index 564023935..31e1b3548 100644 --- a/data/locale/deutsch.locale +++ b/data/locale/deutsch.locale @@ -961,6 +961,7 @@ menu.hint_net_ssid Geben Sie die SSID des WLAN ein, mit dem Sie eine Verbindung menu.hint_net_telnet Aktiviert Telnet auf Ihrer Box menu.hint_net_test Testet die Netzwerkverbindung:\nPing auf Gateway, Name-Server und externe IP-Adressen menu.hint_net_ushare Freigabe verbundener Datenträger über UPnP +menu.hint_net_xupnpd Freigabe von Live Channels über UPNP menu.hint_network IP-Adresse, Gateway, DNS, Zeit-Sync, Netzwerk-Freigaben, Dienste und mehr menu.hint_new_zap_mode Aktiviert Quickzap in der Kanalliste. Nach Betätigen der Mute-Taste wird mit den Hoch/Runter-Tasten direkt umgeschalten menu.hint_numeric_adjust Adjust channel list mode on numeric zap @@ -1407,6 +1408,7 @@ movieplayer.bookmarkname_hint2 movieplayer.defplugin Start-Plugin movieplayer.fileplayback Abspielen (Multiformat) movieplayer.head Movieplayer +movieplayer.starting Wiedergabe starten... movieplayer.toomanybookmarks Sie haben bereits zu viele Lesezeichen angelegt.\nEs muß erst ein anderes gelöscht werden. movieplayer.tshelp1 Stopp movieplayer.tshelp10 ca. 10 Minuten zurück From 9bc7a6efca88766b7c36f86ef54c3dfe4202310b Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Wed, 4 Sep 2013 09:15:09 +0200 Subject: [PATCH 019/200] CPlugins: remove dub included header --- src/gui/plugins.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/plugins.cpp b/src/gui/plugins.cpp index 32640b4eb..0c5022ad8 100644 --- a/src/gui/plugins.cpp +++ b/src/gui/plugins.cpp @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include From 6eeb1a8305c75e0c15bfb3f841cdb2e0e67ebbcc Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Wed, 4 Sep 2013 13:46:13 +0400 Subject: [PATCH 020/200] gui/upnpbrowser.cpp: clear fb on exit --- src/gui/upnpbrowser.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/upnpbrowser.cpp b/src/gui/upnpbrowser.cpp index 7f266416f..9196eadd8 100644 --- a/src/gui/upnpbrowser.cpp +++ b/src/gui/upnpbrowser.cpp @@ -144,6 +144,7 @@ int CUpnpBrowserGui::exec(CMenuTarget* parent, const std::string & /*actionKey*/ // Start Sectionsd g_Sectionsd->setPauseScanning(false); videoDecoder->StopPicture(); + m_frameBuffer->Clear(); //g_Zapit->unlockPlayBack(); CZapit::getInstance()->EnablePlayback(true); From d30f216e1ad80341f6a60af3b9e2b332bb2be770 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Wed, 4 Sep 2013 10:14:04 +0200 Subject: [PATCH 021/200] CTestMenu: disable testmenu --- src/gui/test_menu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/test_menu.h b/src/gui/test_menu.h index c393504c4..39fd3913d 100644 --- a/src/gui/test_menu.h +++ b/src/gui/test_menu.h @@ -36,7 +36,7 @@ #include #include #include - #define TEST_MENU +// #define TEST_MENU #include From 4ddf59b17591b246cd0a0ead1fb42bcfafb3aa50 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Wed, 4 Sep 2013 11:47:54 +0200 Subject: [PATCH 022/200] CMenuOptionLanguageChooser:prevent alter of value conversion compiler warning: wconversion --- src/gui/widget/menue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widget/menue.cpp b/src/gui/widget/menue.cpp index 9d3cc6aad..41861f370 100644 --- a/src/gui/widget/menue.cpp +++ b/src/gui/widget/menue.cpp @@ -1664,7 +1664,7 @@ int CMenuOptionLanguageChooser::paint( bool selected ) //convert first letter to large std::string s_optionValue = optionValue; if(!s_optionValue.empty()) - s_optionValue[0] = toupper(s_optionValue[0]); + s_optionValue[0] = (char)toupper(s_optionValue[0]); //paint text paintItemCaption(selected, height , s_optionValue.c_str()); From cbc6c5867f0385bdb430ebaf2581ebb4a236e365 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Wed, 4 Sep 2013 17:39:45 +0400 Subject: [PATCH 023/200] gui/movieplayer.cpp: fix for 6fe70ff17d25a35c0c6739dd6a8f8aaaa835a67d, audio tracks not cleared --- src/gui/movieplayer.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/gui/movieplayer.cpp b/src/gui/movieplayer.cpp index 3df95b891..f3ff70c3b 100644 --- a/src/gui/movieplayer.cpp +++ b/src/gui/movieplayer.cpp @@ -191,6 +191,12 @@ int CMoviePlayerGui::exec(CMenuTarget * parent, const std::string & actionKey) Cleanup(); + isMovieBrowser = false; + isBookmark = false; + timeshift = 0; + isHTTP = false; + isUPNP = false; + if (actionKey == "tsmoviebrowser") { isMovieBrowser = true; moviebrowser->setMode(MB_SHOW_RECORDS); @@ -218,7 +224,6 @@ int CMoviePlayerGui::exec(CMenuTarget * parent, const std::string & actionKey) #endif else if (actionKey == "upnp") { isUPNP = true; - p_movie_info = NULL; is_file_player = 1; PlayFile(); } @@ -327,11 +332,6 @@ void CMoviePlayerGui::Cleanup() numsubs = 0; startposition = 0; - isMovieBrowser = false; - isBookmark = false; - timeshift = 0; - isHTTP = false; - isUPNP = false; is_file_player = false; p_movie_info = NULL; } @@ -341,6 +341,7 @@ bool CMoviePlayerGui::SelectFile() bool ret = false; menu_ret = menu_return::RETURN_REPAINT; + Cleanup(); file_name = ""; full_name = ""; From be74a66d7b2e406a7b9f6ffc67c32a3820dc9d1f Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Thu, 5 Sep 2013 20:42:16 +0200 Subject: [PATCH 024/200] channellist: disable scale window size with miniTV --- src/gui/channellist.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gui/channellist.cpp b/src/gui/channellist.cpp index 2be1be6ba..53e2e4634 100644 --- a/src/gui/channellist.cpp +++ b/src/gui/channellist.cpp @@ -512,8 +512,10 @@ void CChannelList::calcSize() fheight = 1; /* avoid div-by-zero crash on invalid font */ footerHeight = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight()+6; + bool pig_on_win = ( (g_settings.channellist_additional == 2) /* with miniTV */ && (CNeutrinoApp::getInstance()->getMode() != NeutrinoMessages::mode_ts) ); // calculate width - full_width = frameBuffer->getScreenWidthRel(); + full_width = pig_on_win ? (frameBuffer->getScreenWidth()-2*ConnectLineBox_Width) : frameBuffer->getScreenWidthRel(); + if (g_settings.channellist_additional) width = full_width / 3 * 2; else @@ -521,7 +523,8 @@ void CChannelList::calcSize() // calculate height (the infobox below mainbox is handled outside height) info_height = 2*fheight + fdescrheight + 10; - height = frameBuffer->getScreenHeightRel() - info_height; + height = pig_on_win ? frameBuffer->getScreenHeight(): frameBuffer->getScreenHeightRel(); + height = height - info_height; // calculate x position x = getScreenStartX(full_width); @@ -544,7 +547,7 @@ void CChannelList::calcSize() // calculate width/height of right info_zone and pip-box infozone_width = full_width - width; pig_width = infozone_width; - if ( (g_settings.channellist_additional == 2) /* with miniTV */ && (CNeutrinoApp::getInstance()->getMode() != NeutrinoMessages::mode_ts) ) + if ( pig_on_win /* with miniTV */ ) pig_height = (pig_width * 9) / 16; else pig_height = 0; From 7d1cb075e9ad021e65b787f373303301ba0300d7 Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Thu, 5 Sep 2013 20:59:21 +0200 Subject: [PATCH 025/200] CFlashTool::program: saveEpg only if on --- src/system/flashtool.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/system/flashtool.cpp b/src/system/flashtool.cpp index 636269a5b..12356e410 100644 --- a/src/system/flashtool.cpp +++ b/src/system/flashtool.cpp @@ -158,7 +158,8 @@ bool CFlashTool::program( const std::string & filename, int globalProgressEndEra ssize_t filesize; int globalProgressBegin = 0; - CNeutrinoApp::getInstance()->saveEpg(false); + if(g_settings.epg_save) + CNeutrinoApp::getInstance()->saveEpg(false); if(statusViewer) statusViewer->showLocalStatus(0); From 06e6fa5415420cc18432057271751ae3c2b0053a Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Fri, 6 Sep 2013 18:32:53 +0400 Subject: [PATCH 026/200] driver/netfile.cpp: fix crash, id3 struct not initialized --- src/driver/netfile.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/driver/netfile.cpp b/src/driver/netfile.cpp index c95a0ab35..03eb62763 100644 --- a/src/driver/netfile.cpp +++ b/src/driver/netfile.cpp @@ -340,6 +340,7 @@ int request_file(URL *url) char str[255], *ptr; int slot; ID3 id3; + memset(&id3, 0, sizeof(ID3)); /* get the cache slot for this stream. A negative return value */ /* indicates that no cache has been set up for this stream */ From 4111ff45cb36acbccc0c27e5a63d0a18da2217b2 Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Sat, 7 Sep 2013 16:17:27 +0200 Subject: [PATCH 027/200] CNeutrinoApp::handleMsg:zap to rec channel if box start from deepstandby --- src/neutrino.cpp | 12 +++++++++++- src/neutrino.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/neutrino.cpp b/src/neutrino.cpp index e2eb3d05c..478ee50b5 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -1799,7 +1799,7 @@ TIMER_START(); g_Zapit->setStandby(false); //timer start - bool timer_wakeup = false; + timer_wakeup = false;//init wake_up( timer_wakeup ); pthread_create (&timer_thread, NULL, timerd_main_thread, (void *) (timer_wakeup && g_settings.shutdown_timer_record_type)); timerd_thread_started = true; @@ -2642,6 +2642,7 @@ _repeat: return messages_return::handled; } else if (msg == NeutrinoMessages::RECORD_START) { + //FIXME better at announce ? if( mode == mode_standby ) { cpuFreq->SetCpuFreq(g_settings.cpufreq * 1000 * 1000); @@ -2650,6 +2651,15 @@ _repeat: g_CamHandler->exec(NULL, "ca_ci_reset1"); } } + //zap to rec channel if box start from deepstandby + if(timer_wakeup){ + timer_wakeup=false; + dvbsub_stop(); + CTimerd::RecordingInfo * eventinfo = (CTimerd::RecordingInfo *) data; + t_channel_id channel_id=eventinfo->channel_id; + g_Zapit->zapTo_serviceID_NOWAIT(channel_id); + } + if (g_settings.recording_type != CNeutrinoApp::RECORDING_OFF) { CRecordManager::getInstance()->Record((CTimerd::RecordingInfo *) data); autoshift = CRecordManager::getInstance()->TimeshiftOnly(); diff --git a/src/neutrino.h b/src/neutrino.h index d93fd5d3e..c2d2c6a4a 100644 --- a/src/neutrino.h +++ b/src/neutrino.h @@ -100,6 +100,7 @@ private: bool lockStandbyCall; bool pbBlinkChange; bool g_channel_list_changed; + bool timer_wakeup; int tvsort[LIST_MODE_LAST]; int radiosort[LIST_MODE_LAST]; From 352ab3e7c0cc190293c2cb81773a71ad44608780 Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Sat, 7 Sep 2013 16:39:30 +0200 Subject: [PATCH 028/200] supplement to 4111ff45cb36acbccc0c27e5a63d0a18da2217b2 --- src/neutrino.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/neutrino.cpp b/src/neutrino.cpp index 478ee50b5..a059ebc44 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -1811,6 +1811,7 @@ TIMER_START(); cecsetup.setCECSettings(); init_cec_setting = false; } + timer_wakeup = (timer_wakeup && g_settings.shutdown_timer_record_type); g_settings.shutdown_timer_record_type = false; timer_wakeup = false; From be28b961c7c4e1e1e88e57c22747203a2f9c4741 Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Sat, 7 Sep 2013 17:11:47 +0200 Subject: [PATCH 029/200] supplement to 4111ff45cb36acbccc0c27e5a63d0a18da2217b2 fix --- src/neutrino.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/neutrino.cpp b/src/neutrino.cpp index a059ebc44..eddea72df 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -1813,7 +1813,6 @@ TIMER_START(); } timer_wakeup = (timer_wakeup && g_settings.shutdown_timer_record_type); g_settings.shutdown_timer_record_type = false; - timer_wakeup = false; powerManager = new cPowerManager; powerManager->Open(); From ab1757a963334291102299a85df8e0a95cf43f59 Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Sat, 7 Sep 2013 21:16:47 +0200 Subject: [PATCH 030/200] CNeutrinoApp::handleMsg:zap to rec channel in standby-mode --- src/neutrino.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/neutrino.cpp b/src/neutrino.cpp index eddea72df..f4b85158a 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -2660,6 +2660,19 @@ _repeat: g_Zapit->zapTo_serviceID_NOWAIT(channel_id); } + //zap to rec channel in standby-mode + if(mode == mode_standby){ + CTimerd::RecordingInfo * eventinfo = (CTimerd::RecordingInfo *) data; + bool recordingStatus = CRecordManager::getInstance()->RecordingStatus(eventinfo->channel_id); + t_channel_id live_channel_id = CZapit::getInstance()->GetCurrentChannelID(); + + if( !recordingStatus && (eventinfo->channel_id != live_channel_id) && channelList->SameTP(eventinfo->channel_id) && !(SAME_TRANSPONDER(live_channel_id, eventinfo->channel_id)) ){ + dvbsub_stop(); + t_channel_id channel_id=eventinfo->channel_id; + g_Zapit->zapTo_serviceID_NOWAIT(channel_id); + } + } + if (g_settings.recording_type != CNeutrinoApp::RECORDING_OFF) { CRecordManager::getInstance()->Record((CTimerd::RecordingInfo *) data); autoshift = CRecordManager::getInstance()->TimeshiftOnly(); From ba4d30112db70851f7a48cbfe4e1c6cdda7f7d0d Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Sun, 8 Sep 2013 18:34:55 +0200 Subject: [PATCH 031/200] movieplayer fix youtube name --- src/gui/movieplayer.cpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/gui/movieplayer.cpp b/src/gui/movieplayer.cpp index f3ff70c3b..6473768fb 100644 --- a/src/gui/movieplayer.cpp +++ b/src/gui/movieplayer.cpp @@ -443,6 +443,13 @@ bool CMoviePlayerGui::SelectFile() std::replace(file_name.begin(), file_name.end(), '_', ' '); } else file_name = full_name; + + if(file_name.substr(0,14)=="videoplayback?"){//youtube name + if(!p_movie_info->epgTitle.empty()) + file_name = p_movie_info->epgTitle; + else + file_name = ""; + } printf("CMoviePlayerGui::SelectFile: full_name [%s] file_name [%s]\n", full_name.c_str(), file_name.c_str()); } //store last multiformat play dir @@ -457,20 +464,21 @@ void *CMoviePlayerGui::ShowStartHint(void *arg) { set_threadname(__func__); CMoviePlayerGui *caller = (CMoviePlayerGui *)arg; + if(!caller->file_name.empty()){ + CHintBox hintbox(LOCALE_MOVIEPLAYER_STARTING, caller->file_name.c_str(), 450, NEUTRINO_ICON_MOVIEPLAYER); + hintbox.paint(); - CHintBox hintbox(LOCALE_MOVIEPLAYER_STARTING, caller->file_name.c_str(), 450, NEUTRINO_ICON_MOVIEPLAYER); - hintbox.paint(); - - while (caller->showStartingHint) { - neutrino_msg_t msg; - neutrino_msg_data_t data; - g_RCInput->getMsg(&msg, &data, 1); - if (msg == CRCInput::RC_home || msg == CRCInput::RC_stop) { - if(caller->playback) - caller->playback->RequestAbort(); + while (caller->showStartingHint) { + neutrino_msg_t msg; + neutrino_msg_data_t data; + g_RCInput->getMsg(&msg, &data, 1); + if (msg == CRCInput::RC_home || msg == CRCInput::RC_stop) { + if(caller->playback) + caller->playback->RequestAbort(); + } } + hintbox.hide(); } - hintbox.hide(); return NULL; } From 073d7c93e3870f24938a95c49721488d5bd90202 Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Sun, 8 Sep 2013 19:04:34 +0200 Subject: [PATCH 032/200] movieplayer dont skip RequestAbort --- src/gui/movieplayer.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/gui/movieplayer.cpp b/src/gui/movieplayer.cpp index 6473768fb..ec9e3316a 100644 --- a/src/gui/movieplayer.cpp +++ b/src/gui/movieplayer.cpp @@ -464,20 +464,23 @@ void *CMoviePlayerGui::ShowStartHint(void *arg) { set_threadname(__func__); CMoviePlayerGui *caller = (CMoviePlayerGui *)arg; + CHintBox *hintbox = NULL; if(!caller->file_name.empty()){ - CHintBox hintbox(LOCALE_MOVIEPLAYER_STARTING, caller->file_name.c_str(), 450, NEUTRINO_ICON_MOVIEPLAYER); - hintbox.paint(); - - while (caller->showStartingHint) { - neutrino_msg_t msg; - neutrino_msg_data_t data; - g_RCInput->getMsg(&msg, &data, 1); - if (msg == CRCInput::RC_home || msg == CRCInput::RC_stop) { - if(caller->playback) - caller->playback->RequestAbort(); - } + hintbox = new CHintBox(LOCALE_MOVIEPLAYER_STARTING, caller->file_name.c_str(), 450, NEUTRINO_ICON_MOVIEPLAYER); + hintbox->paint(); + } + while (caller->showStartingHint) { + neutrino_msg_t msg; + neutrino_msg_data_t data; + g_RCInput->getMsg(&msg, &data, 1); + if (msg == CRCInput::RC_home || msg == CRCInput::RC_stop) { + if(caller->playback) + caller->playback->RequestAbort(); } - hintbox.hide(); + } + if(hintbox != NULL){ + hintbox->hide(); + delete hintbox; } return NULL; } From d7224f4c996598c0b56c3a7930f0d9e212b3583e Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Mon, 9 Sep 2013 08:03:29 +0200 Subject: [PATCH 033/200] neutrino: disable commit 4111ff45cb36acbccc0c27e5a63d0a18da2217b2 for test --- src/neutrino.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/neutrino.cpp b/src/neutrino.cpp index f4b85158a..5d4a5ca08 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -2651,6 +2651,7 @@ _repeat: g_CamHandler->exec(NULL, "ca_ci_reset1"); } } +#if 0 //zap to rec channel if box start from deepstandby if(timer_wakeup){ timer_wakeup=false; @@ -2659,7 +2660,7 @@ _repeat: t_channel_id channel_id=eventinfo->channel_id; g_Zapit->zapTo_serviceID_NOWAIT(channel_id); } - +#endif //zap to rec channel in standby-mode if(mode == mode_standby){ CTimerd::RecordingInfo * eventinfo = (CTimerd::RecordingInfo *) data; From d3ff93e12edc823eac16e00dd3eada8cae989ca2 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Mon, 9 Sep 2013 09:55:25 +0400 Subject: [PATCH 034/200] neutrino.cpp: fix malloc_stats call for uclibc --- src/neutrino.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/neutrino.cpp b/src/neutrino.cpp index 5d4a5ca08..7c83ff424 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -4040,6 +4040,10 @@ void CNeutrinoApp::Cleanup() delete CEitManager::getInstance(); printf("cleanup 6\n");fflush(stdout); delete CVFD::getInstance(); +#ifdef __UCLIBC__ + malloc_stats(NULL); +#else malloc_stats(); #endif +#endif } From 37accb627cac95c01271f0b4f62735892d3bf2f3 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Mon, 9 Sep 2013 09:56:01 +0400 Subject: [PATCH 035/200] cross-configure.apollo.debug: fix additional configure args --- cross-configure.apollo.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cross-configure.apollo.debug b/cross-configure.apollo.debug index ba8444848..4d7e066fe 100755 --- a/cross-configure.apollo.debug +++ b/cross-configure.apollo.debug @@ -29,5 +29,5 @@ export FREETYPE_CONFIG=$PREFIX/bin/freetype-config export CURL_CONFIG=$PREFIX/bin/curl-config ./autogen.sh -./configure --prefix=${PREFIX} --build=i386-pc-linux-gnu --host=$HOST --enable-flac --with-target=cdk --with-targetprefix="" --with-boxmodel=apollo --enable-mdev "$*" +./configure --prefix=${PREFIX} --build=i386-pc-linux-gnu --host=$HOST --enable-flac --with-target=cdk --with-targetprefix="" --with-boxmodel=apollo --enable-mdev "$@" From 381e59a54fafc6052d35ea56e604fa084719efa1 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Mon, 9 Sep 2013 12:41:50 +0400 Subject: [PATCH 036/200] lib/libupnpclient/UPNPDevice.cpp: change to non-blocking recv --- lib/libupnpclient/UPNPDevice.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/libupnpclient/UPNPDevice.cpp b/lib/libupnpclient/UPNPDevice.cpp index bc8aa49bb..6611b21ed 100644 --- a/lib/libupnpclient/UPNPDevice.cpp +++ b/lib/libupnpclient/UPNPDevice.cpp @@ -34,6 +34,8 @@ #include #include "upnpclient.h" #include +#include +#include struct ToLower { @@ -433,11 +435,32 @@ std::string CUPnPDevice::HTTP(std::string url, std::string post, std::string act commandstr = command.str(); send(t_socket, commandstr.c_str(), commandstr.size(), 0); +#if 0 while ((received = recv(t_socket, buf, sizeof(buf)-1, 0)) > 0) { buf[received] = 0; reply << buf; } +#endif + struct pollfd fds[1]; + fds[0].fd = t_socket; + fds[0].events = POLLIN; + while (true) { + int result = poll(fds, 1, 4000); + if (result < 0) { + printf("CUPnPDevice::HTTP: poll error %s\n", strerror(errno)); + break; + } + if (result == 0) { + printf("CUPnPDevice::HTTP: poll timeout\n"); + break; + } + received = recv(t_socket, buf, sizeof(buf)-1, 0); + if (received <= 0) + break; + buf[received] = 0; + reply << buf; + } close(t_socket); return reply.str(); } From 79e63c3f78157888a966b1c2f9e6f0c1dcfae5b0 Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Mon, 9 Sep 2013 19:25:37 +0200 Subject: [PATCH 037/200] movieplayer.cpp: add rtsp parse --- src/gui/movieplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/movieplayer.cpp b/src/gui/movieplayer.cpp index ec9e3316a..4d748ec31 100644 --- a/src/gui/movieplayer.cpp +++ b/src/gui/movieplayer.cpp @@ -420,7 +420,7 @@ bool CMoviePlayerGui::SelectFile() if (strlen(cLine) > 0 && cLine[0]!='#') { char *url = NULL; - if ( (url = strstr(cLine, "http://")) || (url = strstr(cLine, "rtmp://")) ){ + if ( (url = strstr(cLine, "http://")) || (url = strstr(cLine, "rtmp://")) || (url = strstr(cLine, "rtsp://")) ){ if (url != NULL) { printf("name %s [%d] url: %s\n", name, dur, url); full_name = url; From 17bc0f968dd503e87fb8c572bfdb033809a2c9d6 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Mon, 16 Sep 2013 14:36:22 +0400 Subject: [PATCH 038/200] gui/scan_setup.cpp: cleanup, fix FEC options on mixed sat+cable box --- src/gui/scan_setup.cpp | 135 +---------------------------------------- src/gui/scan_setup.h | 2 - 2 files changed, 1 insertion(+), 136 deletions(-) diff --git a/src/gui/scan_setup.cpp b/src/gui/scan_setup.cpp index 5a4e850a2..6f76968b4 100644 --- a/src/gui/scan_setup.cpp +++ b/src/gui/scan_setup.cpp @@ -195,15 +195,8 @@ const CMenuOptionChooser::keyval SATSETUP_FRONTEND_MODE[SATSETUP_FRONTEND_MODE_C CScanSetup::CScanSetup(bool wizard_mode) { width = w_max (40, 10); - r_system = g_info.delivery_system; - fec_count = (r_system == DVB_S) ? SATSETUP_SCANTP_FEC_COUNT : CABLESETUP_SCANTP_FEC_COUNT; - freq_length = (r_system == DVB_S) ? 8 : 6; - is_wizard = wizard_mode; - //define caption of some forwarders and widgets depends of current receiver type - satprov_locale = (r_system == DVB_S) ? LOCALE_SATSETUP_SATELLITE : LOCALE_CABLESETUP_PROVIDER; - satSelect = NULL; cableSelect = NULL; satOnOff = NULL; @@ -403,11 +396,6 @@ int CScanSetup::showScanMenu() //sat/provider selector if(CFEManager::getInstance()->haveSat() || CFEManager::getInstance()->getFrontendCount() > 1) { -#if 0 - CMenuWidget * setupMenu = new CMenuWidget(LOCALE_SATSETUP_FE_SETUP, NEUTRINO_ICON_SETTINGS, width, MN_WIDGET_ID_SCAN_FE_SETUP); - addScanMenuFrontendSetup(setupMenu); - mf = new CMenuDForwarder(LOCALE_SATSETUP_FE_SETUP, allow_start, NULL, setupMenu, "", CRCInput::convertDigitToKey(shortcut++)); -#endif mf = new CMenuForwarder(LOCALE_SATSETUP_FE_SETUP, allow_start, NULL, this, "setup_frontend", CRCInput::convertDigitToKey(shortcut++)); mf->setHint("", LOCALE_MENU_HINT_SCAN_FESETUP); settings->addItem(mf); @@ -423,13 +411,6 @@ int CScanSetup::showScanMenu() satOnOff = new CMenuWidget(LOCALE_SATSETUP_SATELLITE, NEUTRINO_ICON_SETTINGS, width); -#if 0 - CMenuWidget * setupMenu = new CMenuWidget(LOCALE_SATSETUP_FE_SETUP, NEUTRINO_ICON_SETTINGS, width, MN_WIDGET_ID_SCAN_FE_SETUP); - addScanMenuFrontendSetup(setupMenu); - mf = new CMenuDForwarder(LOCALE_SATSETUP_FE_SETUP, allow_start, NULL, setupMenu, "", CRCInput::convertDigitToKey(shortcut++)); - mf->setHint("", LOCALE_MENU_HINT_SCAN_FESETUP); - settings->addItem(mf); -#endif /* add configured satellites to satSelect */ fillSatSelect(satSelect); @@ -509,58 +490,6 @@ int CScanSetup::showScanMenu() fcableScan->setHint("", LOCALE_MENU_HINT_SCAN_CABLE_SIMPLE); settings->addItem(fcableScan); } -#if 0 - //-------------------------------------------------------------- - settings->addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_SCANTS_PREVERENCES_SCAN)); - //-------------------------------------------------------------- - - int w = getSatMenuListWidth(); - - //auto scan - char autoscan[64]; - std::string s_capt_part = g_Locale->getText(satprov_locale); - snprintf(autoscan, 64, g_Locale->getText(LOCALE_SATSETUP_AUTO_SCAN), s_capt_part.c_str()); - - /* FIXME leak, satSelect added to both auto and manual scan, so one of them cannot be deleted */ - CMenuWidget * autoScan = new CMenuWidget(LOCALE_SERVICEMENU_SCANTS, NEUTRINO_ICON_SETTINGS, w/*width*/, MN_WIDGET_ID_SCAN_AUTO_SCAN); - addScanMenuAutoScan(autoScan); - mf = new CMenuForwarderNonLocalized(autoscan, true, NULL, autoScan, "", CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN); - mf->setHint("", LOCALE_MENU_HINT_SCAN_AUTO); - settings->addItem(mf); - - //manual scan - CMenuWidget manualScan(LOCALE_SATSETUP_MANUAL_SCAN, NEUTRINO_ICON_SETTINGS, w/*width*/, MN_WIDGET_ID_SCAN_MANUAL_SCAN); - addScanMenuManualScan(&manualScan); - mf = new CMenuForwarder(LOCALE_SATSETUP_MANUAL_SCAN, true, NULL, &manualScan, "", CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW); - mf->setHint("", LOCALE_MENU_HINT_SCAN_MANUAL); - settings->addItem(mf); - - if (r_system == DVB_S) - { - //auto scan all - CMenuWidget * autoScanAll = new CMenuWidget(LOCALE_SATSETUP_AUTO_SCAN_ALL, NEUTRINO_ICON_SETTINGS, w/*width*/, MN_WIDGET_ID_SCAN_AUTO_SCAN_ALL); - addScanMenuAutoScanAll(autoScanAll); - fautoScanAll = new CMenuDForwarder(LOCALE_SATSETUP_AUTO_SCAN_ALL, true /*(dmode != NO_DISEQC)*/, NULL, autoScanAll, "", CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE); - fautoScanAll->setHint("", LOCALE_MENU_HINT_SCAN_AUTOALL); - settings->addItem(fautoScanAll); -#ifdef ENABLE_FASTSCAN - //fast scan - CMenuWidget * fastScanMenu = new CMenuWidget(LOCALE_SATSETUP_FASTSCAN_HEAD, NEUTRINO_ICON_SETTINGS, MN_WIDGET_ID_SCAN_FAST_SCAN); - addScanMenuFastScan(fastScanMenu); - mf = new CMenuDForwarder(LOCALE_SATSETUP_FASTSCAN_HEAD, true, NULL, fastScanMenu, "", CRCInput::convertDigitToKey(shortcut++)); - mf->setHint("", LOCALE_MENU_HINT_SCAN_FAST); - settings->addItem(mf); -#endif /*ENABLE_FASTSCAN*/ - } - else if (r_system == DVB_C) //cable - { - CMenuWidget * cableScan = new CMenuWidget(LOCALE_SATSETUP_CABLE, NEUTRINO_ICON_SETTINGS, w/*width*/, MN_WIDGET_ID_SCAN_CABLE_SCAN); - addScanMenuCable(cableScan); - CMenuForwarder * fcableScan = new CMenuDForwarder(LOCALE_SATSETUP_CABLE, true, NULL, cableScan, "", CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE); - fcableScan->setHint("", LOCALE_MENU_HINT_SCAN_CABLE_SIMPLE); - settings->addItem(fcableScan); - } -#endif int res = settings->exec(NULL, ""); //delete satSelect; @@ -947,10 +876,6 @@ void CScanSetup::fillSatSelect(CMenuOptionStringChooser * select) sfound = true; } } -#if 0 - if(CFEManager::getInstance()->getMode() != CFEManager::FE_MODE_ALONE) - break; -#endif } if(!sfound && !satpos.empty()) { tmpit = satpos.begin(); @@ -1082,10 +1007,6 @@ void CScanSetup::addScanMenuTempSat(CMenuWidget *temp_sat, sat_config_t & satcon satconfig.diseqc = 0; unilnb = new CMenuOptionNumberChooser(LOCALE_UNICABLE_LNB, &satconfig.diseqc, true, 0, 1); } -#if 0 - if(!satconfig.use_usals) - all_usals = 0; -#endif CIntInput* lofL = new CIntInput(LOCALE_SATSETUP_LOFL, (int&) satconfig.lnbOffsetLow, 5, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE); CIntInput* lofH = new CIntInput(LOCALE_SATSETUP_LOFH, (int&) satconfig.lnbOffsetHigh, 5, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE); @@ -1313,7 +1234,7 @@ int CScanSetup::addScanOptionsItems(CMenuWidget *options_menu, const int &shortc CStringInput *rate = new CStringInput(LOCALE_EXTRA_TP_RATE, (char *) scansettings.sat_TP_rate, 8, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "0123456789"); Rate = new CMenuDForwarder(LOCALE_EXTRA_TP_RATE, true, scansettings.sat_TP_rate, rate, "", CRCInput::convertDigitToKey(shortCut++)); Rate->setHint("", LOCALE_MENU_HINT_SCAN_RATE); - fec = new CMenuOptionChooser(LOCALE_EXTRA_TP_FEC, (int *)&scansettings.sat_TP_fec, SATSETUP_SCANTP_FEC, fec_count, true, NULL, CRCInput::convertDigitToKey(shortCut++), "", true); + fec = new CMenuOptionChooser(LOCALE_EXTRA_TP_FEC, (int *)&scansettings.sat_TP_fec, SATSETUP_SCANTP_FEC, SATSETUP_SCANTP_FEC_COUNT, true, NULL, CRCInput::convertDigitToKey(shortCut++), "", true); fec->setHint("", LOCALE_MENU_HINT_SCAN_FEC); mod_pol = new CMenuOptionChooser(LOCALE_EXTRA_TP_POL, (int *)&scansettings.sat_TP_pol, SATSETUP_SCANTP_POL, SATSETUP_SCANTP_POL_COUNT, true, NULL, CRCInput::convertDigitToKey(shortCut++)); mod_pol->setHint("", LOCALE_MENU_HINT_SCAN_POL); @@ -1404,14 +1325,6 @@ bool CScanSetup::changeNotify(const neutrino_locale_t OptionName, void * /*data* bool ret = false; if(ARE_LOCALES_EQUAL(OptionName, LOCALE_SATSETUP_USE_USALS)) { -#if 0 - CFrontend * fe = CFEManager::getInstance()->getFE(fenumber); - printf("[neutrino] CScanSetup::%s: all usals %d \n", __FUNCTION__, all_usals); - satellite_map_t & satmap = fe->getSatellites(); - for (sat_iterator_t sit = satmap.begin(); sit != satmap.end(); sit++) { - sit->second.use_usals = all_usals; - } -#endif } else if(ARE_LOCALES_EQUAL(OptionName, LOCALE_SATSETUP_DISEQC)) { printf("[neutrino] CScanSetup::%s: diseqc %d fenumber %d\n", __FUNCTION__, dmode, fenumber); @@ -1423,36 +1336,6 @@ bool CScanSetup::changeNotify(const neutrino_locale_t OptionName, void * /*data* fe->setDiseqcType((diseqc_t) dmode); fe->setTsidOnid(0); -#if 0 - if(femode != CFEManager::FE_MODE_ALONE) - CFEManager::getInstance()->saveSettings(true); - - fautoScanAll->setActive(dmode != NO_DISEQC); - uniSetup->setActive(dmode == DISEQC_UNICABLE); - if (dmode == NO_DISEQC || dmode == DISEQC_UNICABLE) { - ojDiseqcRepeats->setActive(false); - if(frontendSetup){ - if(femode == CFEManager::FE_MODE_TWIN && dmode == DISEQC_UNICABLE){ - frontendSetup->setActive(true); - } - else if( femode != CFEManager::FE_MODE_ALONE){ - frontendSetup->setActive(false); - } - } - } - else if(dmode < DISEQC_ADVANCED) { - ojDiseqcRepeats->setActive(true); - if(frontendSetup && femode != CFEManager::FE_MODE_ALONE){ - frontendSetup->setActive(false); - } - } - else if(dmode == DISEQC_ADVANCED) { - if(frontendSetup && femode != CFEManager::FE_MODE_ALONE){ - frontendSetup->setActive(false); - } - ojDiseqcRepeats->setActive(true); - } -#endif uniSetup->setActive(dmode == DISEQC_UNICABLE); bool enable = (dmode < DISEQC_ADVANCED) && (dmode != NO_DISEQC); ojDiseqcRepeats->setActive(enable && !CFrontend::linked(femode) && femode != CFrontend::FE_MODE_UNUSED); @@ -1461,22 +1344,6 @@ bool CScanSetup::changeNotify(const neutrino_locale_t OptionName, void * /*data* } else if(ARE_LOCALES_EQUAL(OptionName, LOCALE_SATSETUP_FE_MODE)) { printf("[neutrino] CScanSetup::%s: fe%d mode %d master %d\n", __FUNCTION__, fenumber, femode, femaster); -#if 0 - /* cable dont have this menu */ - bool twin_unicabel = false; - if(frontendSetup){ - CFrontend * fe = CFEManager::getInstance()->getLiveFE(); - frontend_config_t & fe_config = fe->getConfig(); - twin_unicabel = (femode == CFEManager::FE_MODE_TWIN && fe_config.diseqcType == DISEQC_UNICABLE); - frontendSetup->setActive(femode == CFEManager::FE_MODE_ALONE || twin_unicabel); - } - CFEManager::getInstance()->setMode((CFEManager::fe_mode_t) femode); - /* to copy settings from fe0 */ - if(femode != CFEManager::FE_MODE_ALONE) - CFEManager::getInstance()->saveSettings(true); - if (r_system == DVB_S) //sat - fillSatSelect(satSelect); -#endif CFrontend * fe = CFEManager::getInstance()->getFE(fenumber); if (fe->getMode() == femode) return ret; diff --git a/src/gui/scan_setup.h b/src/gui/scan_setup.h index c8314ee03..fe55c32ee 100644 --- a/src/gui/scan_setup.h +++ b/src/gui/scan_setup.h @@ -93,8 +93,6 @@ class CScanSetup : public CMenuTarget, public CChangeObserver bool is_wizard; - int fec_count; - int freq_length; int r_system; neutrino_locale_t satprov_locale; From a992f9695a231d49e750e639c51f2630b1707325 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Mon, 16 Sep 2013 14:36:55 +0400 Subject: [PATCH 039/200] zapit/src/frontend.cpp: fix 'unknown FEC' log for FEC_S2_AUTO --- src/zapit/src/frontend.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zapit/src/frontend.cpp b/src/zapit/src/frontend.cpp index 20dbce74b..9f2a1bb12 100644 --- a/src/zapit/src/frontend.cpp +++ b/src/zapit/src/frontend.cpp @@ -584,6 +584,7 @@ void CFrontend::getDelSys(uint8_t type, int f, int m, char *&fec, char *&sys, ch break; default: printf("[frontend] getDelSys: unknown FEC: %d !!!\n", f); + case FEC_S2_AUTO: case FEC_AUTO: fec = (char *)"AUTO"; break; From 5b3cea3ff6a2473254947ea94f3580ad25b78f00 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Mon, 16 Sep 2013 14:38:06 +0400 Subject: [PATCH 040/200] gui/upnpbrowser.cpp: revert keys handling, pass not-handled to CNeutrinoApp --- src/gui/upnpbrowser.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gui/upnpbrowser.cpp b/src/gui/upnpbrowser.cpp index 9196eadd8..a83460335 100644 --- a/src/gui/upnpbrowser.cpp +++ b/src/gui/upnpbrowser.cpp @@ -527,12 +527,16 @@ void CUpnpBrowserGui::selectDevice() loop=false; g_RCInput->postMsg(msg, data); } +#if 0 else if (msg == NeutrinoMessages::EVT_TIMER) { CNeutrinoApp::getInstance()->handleMsg(msg, data); } else if (msg > CRCInput::RC_MaxRC) +#endif + else { +printf("msg: %x\n", (int) msg); if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) loop = false; } @@ -834,11 +838,14 @@ bool CUpnpBrowserGui::selectItem(std::string id) loop = false; g_RCInput->postMsg(msg, data); } +#if 0 else if (msg == NeutrinoMessages::EVT_TIMER) { CNeutrinoApp::getInstance()->handleMsg(msg, data); } else if (msg > CRCInput::RC_MaxRC) +#endif + else { if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) loop = false; From 12d005d1ea844a866c055dddb4403d726b120ca2 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 17 Sep 2013 09:58:40 +0400 Subject: [PATCH 041/200] gui/audio_setup.cpp: disable nmgr settings on apollo --- src/gui/audio_setup.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/audio_setup.cpp b/src/gui/audio_setup.cpp index e35724472..f2fadc797 100644 --- a/src/gui/audio_setup.cpp +++ b/src/gui/audio_setup.cpp @@ -200,7 +200,9 @@ int CAudioSetup::showAudioSetup() audioSettings->addItem(GenericMenuSeparatorLine); audioSettings->addItem(as_oj_srsonoff); audioSettings->addItem(as_oj_algo); +#ifndef BOXMODEL_APOLLO audioSettings->addItem(as_oj_noise); +#endif audioSettings->addItem(as_oj_volrev); #if 0 audioSettings->addItem(mf); @@ -209,6 +211,9 @@ int CAudioSetup::showAudioSetup() int res = audioSettings->exec(NULL, ""); selected = audioSettings->getSelected(); delete audioSettings; +#ifdef BOXMODEL_APOLLO + delete as_oj_noise; +#endif return res; } From 8a8f996ca0ef34822cc5e67c8e12b7fb965c6476 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Wed, 18 Sep 2013 12:57:56 +0400 Subject: [PATCH 042/200] channel list: restrict adding channels to favorits only, show empty bouquets only in channel add mode --- src/gui/bouquetlist.cpp | 22 +++++++++++++++------- src/gui/channellist.cpp | 13 +++++++++++++ src/neutrino.cpp | 10 ++++++++-- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/gui/bouquetlist.cpp b/src/gui/bouquetlist.cpp index cf193828c..5c47e3e4e 100644 --- a/src/gui/bouquetlist.cpp +++ b/src/gui/bouquetlist.cpp @@ -396,39 +396,41 @@ int CBouquetList::show(bool bShowChannelList) loop=false; } else if(msg == CRCInput::RC_red || msg == CRCInput::RC_favorites) { - if (CNeutrinoApp::getInstance()->GetChannelMode() != LIST_MODE_FAV) { + if (!favonly && CNeutrinoApp::getInstance()->GetChannelMode() != LIST_MODE_FAV) { CNeutrinoApp::getInstance()->SetChannelMode(LIST_MODE_FAV); hide(); return -3; } } else if(msg == CRCInput::RC_green) { - if (CNeutrinoApp::getInstance()->GetChannelMode() != LIST_MODE_PROV) { + if (!favonly && CNeutrinoApp::getInstance()->GetChannelMode() != LIST_MODE_PROV) { CNeutrinoApp::getInstance()->SetChannelMode(LIST_MODE_PROV); hide(); return -3; } } else if(msg == CRCInput::RC_yellow || msg == CRCInput::RC_sat) { - if(bShowChannelList && CNeutrinoApp::getInstance()->GetChannelMode() != LIST_MODE_SAT) { + if(!favonly && bShowChannelList && CNeutrinoApp::getInstance()->GetChannelMode() != LIST_MODE_SAT) { CNeutrinoApp::getInstance()->SetChannelMode(LIST_MODE_SAT); hide(); return -3; } } else if(msg == CRCInput::RC_blue) { - if(bShowChannelList && CNeutrinoApp::getInstance()->GetChannelMode() != LIST_MODE_ALL) { + if(!favonly && bShowChannelList && CNeutrinoApp::getInstance()->GetChannelMode() != LIST_MODE_ALL) { CNeutrinoApp::getInstance()->SetChannelMode(LIST_MODE_ALL); hide(); return -3; } } else if ( msg == CRCInput::RC_setup) { - if (!Bouquets.empty()) { + if (!favonly && !Bouquets.empty()) { int ret = doMenu(); if(ret > 0) { CNeutrinoApp::getInstance()->MarkChannelListChanged(); res = -4; loop = false; - } else if(ret < 0) + } else if(ret < 0) { + paintHead(); paint(); + } } } else if ( msg == (neutrino_msg_t) g_settings.key_list_start ) { @@ -599,11 +601,17 @@ void CBouquetList::paint() frameBuffer->paintBoxRel(x, y+theight, width, height - theight - footerHeight, COL_MENUCONTENT_PLUS_0); int numbuttons = sizeof(CBouquetListButtons)/sizeof(CBouquetListButtons[0]); +#if 0 if (favonly) /* this actually shows favorites and providers button, but both are active anyway */ numbuttons = 2; ::paintButtons(x, y + (height - footerHeight), width, numbuttons, CBouquetListButtons, width, footerHeight); - +#endif + if (favonly) + frameBuffer->paintBoxRel(x, y + (height - footerHeight), width, footerHeight, COL_INFOBAR_SHADOW_PLUS_1, RADIUS_LARGE, CORNER_BOTTOM); //round + else + ::paintButtons(x, y + (height - footerHeight), width, numbuttons, CBouquetListButtons, width, footerHeight); + if(!Bouquets.empty()) { for(unsigned int count=0;countGetChannelMode() != LIST_MODE_FAV) CNeutrinoApp::getInstance()->SetChannelMode(LIST_MODE_FAV); @@ -430,6 +432,7 @@ int CChannelList::doChannelMenu(void) do { bouquet_id = bouquetList->exec(false); } while(bouquet_id == -3); + bouquet_id = bouquetList->exec(false); hide(); if(bouquet_id < 0) return 0; @@ -438,6 +441,16 @@ int CChannelList::doChannelMenu(void) bouquet_id = g_bouquetManager->existsUBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true); else bouquet_id = g_bouquetManager->existsBouquet(bouquetList->Bouquets[bouquet_id]->channelList->getName()); +#endif + bouquet_id = AllFavBouquetList->exec(false); + hide(); + if(bouquet_id < 0) + return 0; + + if(!strcmp(AllFavBouquetList->Bouquets[bouquet_id]->channelList->getName(), g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME))) + bouquet_id = g_bouquetManager->existsUBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true); + else + bouquet_id = g_bouquetManager->existsUBouquet(AllFavBouquetList->Bouquets[bouquet_id]->channelList->getName()); if (bouquet_id == -1) return 0; diff --git a/src/neutrino.cpp b/src/neutrino.cpp index 7c83ff424..eb6cd06cd 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -173,6 +173,8 @@ CBouquetList * RADIOsatList; CBouquetList * RADIOfavList; CBouquetList * RADIOallList; +CBouquetList * AllFavBouquetList; + CPlugins * g_PluginList; CRemoteControl * g_RemoteControl; CPictureViewer * g_PicViewer; @@ -1351,12 +1353,14 @@ void CNeutrinoApp::channelsInit(bool bOnly) TIMER_STOP("[neutrino] sats took"); } + delete AllFavBouquetList; + AllFavBouquetList = new CBouquetList(g_Locale->getText(LOCALE_CHANNELLIST_FAVS)); /* Favorites and providers bouquets */ tvi = ri = 0; for (i = 0; i < g_bouquetManager->Bouquets.size(); i++) { CZapitBouquet *b = g_bouquetManager->Bouquets[i]; if (!b->bHidden) { - if (b->getTvChannels(zapitList) || b->bUser) { + if (b->getTvChannels(zapitList) /* || b->bUser */) { if(b->bUser) tmp = TVfavList->addBouquet(b); else @@ -1365,7 +1369,7 @@ void CNeutrinoApp::channelsInit(bool bOnly) tmp->channelList->SetChannelList(&zapitList); tvi++; } - if (b->getRadioChannels(zapitList) || b->bUser) { + if (b->getRadioChannels(zapitList) /* || b->bUser */) { if(b->bUser) tmp = RADIOfavList->addBouquet(b); else @@ -1374,6 +1378,8 @@ void CNeutrinoApp::channelsInit(bool bOnly) tmp->channelList->SetChannelList(&zapitList); ri++; } + if(b->bUser) + AllFavBouquetList->addBouquet(b); } } printf("[neutrino] got %d TV and %d RADIO bouquets\n", tvi, ri); fflush(stdout); From 6e83576a1bd00312dc88cbad4220123429d772a9 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Sun, 30 Dec 2012 18:30:52 +0100 Subject: [PATCH 043/200] oggdec: remove old include to fix build with new tremor --- src/driver/audiodec/oggdec.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/driver/audiodec/oggdec.h b/src/driver/audiodec/oggdec.h index f3948d3d4..f945fa91a 100644 --- a/src/driver/audiodec/oggdec.h +++ b/src/driver/audiodec/oggdec.h @@ -38,7 +38,6 @@ #include #include #ifdef USE_TREMOR -#include #include #else #include From d750b8e27b5f6f5a35f6c622f8a665f6c1a786a5 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sat, 7 Sep 2013 00:33:30 +0200 Subject: [PATCH 044/200] CComponentsWindow: use members as protected Sub classes need these members. --- src/gui/components/cc_frm.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gui/components/cc_frm.h b/src/gui/components/cc_frm.h index e936eaf6f..4ee335c93 100644 --- a/src/gui/components/cc_frm.h +++ b/src/gui/components/cc_frm.h @@ -209,7 +209,7 @@ items like text, labels, pictures ... class CComponentsWindow : public CComponentsForm { - private: + protected: ///object: header object, to get access to header properties see also getHeaderObject() CComponentsHeader * ccw_head; ///object: body object, this is the container for all needed items, to add with addWindowItem() @@ -231,8 +231,6 @@ class CComponentsWindow : public CComponentsForm void initFooter(); ///initialze all window objects at once void initCCWItems(); - - protected: ///initialize all attributes void initVarWindow(); From f129db9b0cc496cb204c72373d56790d36b8bf24 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sat, 7 Sep 2013 02:01:03 +0200 Subject: [PATCH 045/200] Signalbars: move sorce files to gui/components --- src/gui/components/Makefile.am | 1 + .../{widget/signalbars.cpp => components/cc_frm_signalbars.cpp} | 2 +- src/gui/{widget/signalbars.h => components/cc_frm_signalbars.h} | 0 src/gui/widget/Makefile.am | 1 - 4 files changed, 2 insertions(+), 2 deletions(-) rename src/gui/{widget/signalbars.cpp => components/cc_frm_signalbars.cpp} (99%) rename src/gui/{widget/signalbars.h => components/cc_frm_signalbars.h} (100%) diff --git a/src/gui/components/Makefile.am b/src/gui/components/Makefile.am index cec7764f6..5181dc19e 100644 --- a/src/gui/components/Makefile.am +++ b/src/gui/components/Makefile.am @@ -32,6 +32,7 @@ libneutrino_gui_components_a_SOURCES = \ cc_frm_footer.cpp \ cc_frm_header.cpp \ cc_frm_icons.cpp \ + cc_frm_signalbars.cpp \ cc_frm_window.cpp \ cc_item.cpp \ cc_item_infobox.cpp \ diff --git a/src/gui/widget/signalbars.cpp b/src/gui/components/cc_frm_signalbars.cpp similarity index 99% rename from src/gui/widget/signalbars.cpp rename to src/gui/components/cc_frm_signalbars.cpp index a8268b11a..506d61001 100644 --- a/src/gui/widget/signalbars.cpp +++ b/src/gui/components/cc_frm_signalbars.cpp @@ -29,7 +29,7 @@ #include #include -#include "signalbars.h" +#include "cc_frm_signalbars.h" #include #define SB_MIN_HEIGHT 12 diff --git a/src/gui/widget/signalbars.h b/src/gui/components/cc_frm_signalbars.h similarity index 100% rename from src/gui/widget/signalbars.h rename to src/gui/components/cc_frm_signalbars.h diff --git a/src/gui/widget/Makefile.am b/src/gui/widget/Makefile.am index 24ef50127..df5c3ed58 100644 --- a/src/gui/widget/Makefile.am +++ b/src/gui/widget/Makefile.am @@ -38,7 +38,6 @@ libneutrino_gui_widget_a_SOURCES = \ messagebox.cpp \ mountchooser.cpp \ msgbox.cpp \ - signalbars.cpp \ stringinput.cpp \ stringinput_ext.cpp \ textbox.cpp From 4eb26988e9b412a6a8ea81d29a0439255cd94bb5 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sun, 8 Sep 2013 21:31:35 +0200 Subject: [PATCH 046/200] CComponentsForm/CComponentsWindow: add new members CComponentsForm: Overload member removeCCItem so we can use cc_item as parameter. CComponentsWindow: add member bool showFooter(). This allows to hide a footer in window. --- src/gui/components/cc_frm.cpp | 6 ++++++ src/gui/components/cc_frm.h | 6 ++++++ src/gui/components/cc_frm_window.cpp | 21 +++++++++++++++++---- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/gui/components/cc_frm.cpp b/src/gui/components/cc_frm.cpp index 9cd5eed0b..16f9eb423 100644 --- a/src/gui/components/cc_frm.cpp +++ b/src/gui/components/cc_frm.cpp @@ -254,6 +254,12 @@ void CComponentsForm::removeCCItem(const uint& cc_item_id) #endif } +void CComponentsForm::removeCCItem(CComponentsItem* cc_Item) +{ + uint id = getCCItemId(cc_Item); + removeCCItem(id); +} + void CComponentsForm::exchangeCCItem(const uint& cc_item_id_a, const uint& cc_item_id_b) { if (!v_cc_items.empty()) diff --git a/src/gui/components/cc_frm.h b/src/gui/components/cc_frm.h index 4ee335c93..551ce4ecc 100644 --- a/src/gui/components/cc_frm.h +++ b/src/gui/components/cc_frm.h @@ -58,6 +58,7 @@ class CComponentsForm : public CComponentsItem virtual void addCCItem(CComponentsItem* cc_Item); virtual void insertCCItem(const uint& cc_item_id, CComponentsItem* cc_Item); virtual void removeCCItem(const uint& cc_item_id); + virtual void removeCCItem(CComponentsItem* cc_Item); virtual void replaceCCItem(const uint& cc_item_id, CComponentsItem* new_cc_Item); virtual void replaceCCItem(CComponentsItem* old_cc_Item, CComponentsItem* new_cc_Item); virtual void exchangeCCItem(const uint& item_id_a, const uint& item_id_b); @@ -222,6 +223,8 @@ class CComponentsWindow : public CComponentsForm const char* ccw_icon_name; ///property: assigned default icon buttons in header, see also getHeaderObject() int ccw_buttons; + ///property: value = true, let show footer + bool ccw_show_footer; ///initialze header object void initHeader(); @@ -275,6 +278,9 @@ class CComponentsWindow : public CComponentsForm ///add item to body object, also usable is addCCItem() to add items to the windo object void addWindowItem(CComponentsItem* cc_Item); + + /// + void showFooter(bool show = true){ccw_show_footer = show;}; ///set caption in header with string, see also getHeaderObject() void setWindowCaption(const std::string& text){ccw_caption = text;}; diff --git a/src/gui/components/cc_frm_window.cpp b/src/gui/components/cc_frm_window.cpp index 9feaffcdf..47d188a31 100644 --- a/src/gui/components/cc_frm_window.cpp +++ b/src/gui/components/cc_frm_window.cpp @@ -140,6 +140,7 @@ void CComponentsWindow::initVarWindow() ccw_caption = ""; ccw_icon_name = NULL; ccw_buttons = 0; //no header buttons + ccw_show_footer = true; setShadowOnOff(true); } @@ -179,7 +180,9 @@ void CComponentsWindow::initBody() //set body properties if (ccw_body){ ccw_body->setCornerType(0); - int fh = ccw_footer->getHeight(); + int fh = 0; + if (ccw_footer) + fh = ccw_footer->getHeight(); int hh = ccw_head->getHeight(); int h_body = height - hh - fh; ccw_body->setDimensionsAll(0, CC_APPEND, width, h_body); @@ -216,7 +219,16 @@ void CComponentsWindow::initCCWItems() printf("[CComponentsWindow] [%s - %d] init items...\n", __FUNCTION__, __LINE__); #endif initHeader(); - initFooter(); + + //add footer if required + if (ccw_show_footer){ + initFooter(); + }else{ + if (ccw_footer != NULL){ + removeCCItem(ccw_footer); + ccw_footer = NULL; + } + } initBody(); //add header, body and footer items only one time @@ -224,8 +236,9 @@ void CComponentsWindow::initCCWItems() addCCItem(ccw_head); if (!isAdded(ccw_body)) addCCItem(ccw_body); - if (!isAdded(ccw_footer)) - addCCItem(ccw_footer); + if (ccw_footer) + if (!isAdded(ccw_footer)) + addCCItem(ccw_footer); } void CComponentsWindow::paint(bool do_save_bg) From 78cdee08a86472a8975c1fb67a9c8e4d965cbbe5 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sun, 8 Sep 2013 22:28:45 +0200 Subject: [PATCH 047/200] CComponentsHeader: add member that allows switching to small size --- src/gui/components/cc_frm.h | 8 ++++++++ src/gui/components/cc_frm_header.cpp | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/src/gui/components/cc_frm.h b/src/gui/components/cc_frm.h index 551ce4ecc..ec8149156 100644 --- a/src/gui/components/cc_frm.h +++ b/src/gui/components/cc_frm.h @@ -124,6 +124,7 @@ class CComponentsHeader : public CComponentsForm Font* cch_font; int cch_items_y, cch_icon_x, cch_icon_w, cch_text_x, cch_buttons, cch_buttons_w, cch_buttons_h, cch_buttons_space, cch_offset; std::vector v_cch_btn; + int cch_size_mode; void initIcon(); void initCaption(); @@ -149,6 +150,12 @@ class CComponentsHeader : public CComponentsForm CC_HEADER_ITEM_TEXT = 1, CC_HEADER_ITEM_BUTTONS = 2 }; + + enum + { + CC_HEADER_SIZE_LARGE = 0, + CC_HEADER_SIZE_SMALL = 1 + }; CComponentsHeader(); CComponentsHeader(const int x_pos, const int y_pos, const int w, const int h = 0, const std::string& caption = "header", const char* icon_name = NULL, const int buttons = 0, bool has_shadow = CC_SHADOW_OFF, fb_pixel_t color_frame = COL_MENUCONTENT_PLUS_6, fb_pixel_t color_body = COL_MENUHEAD_PLUS_0, fb_pixel_t color_shadow = COL_MENUCONTENTDARK_PLUS_0); @@ -168,6 +175,7 @@ class CComponentsHeader : public CComponentsForm virtual void setDefaultButtons(const int buttons); virtual void setButtonsSpace(const int buttons_space){cch_buttons_space = buttons_space;}; virtual void initCCItems(); + virtual void setSizeMode(const int& size_mode){cch_size_mode = size_mode;}; virtual void paint(bool do_save_bg = CC_SAVE_SCREEN_YES); }; diff --git a/src/gui/components/cc_frm_header.cpp b/src/gui/components/cc_frm_header.cpp index da53e5de2..2278eedd3 100644 --- a/src/gui/components/cc_frm_header.cpp +++ b/src/gui/components/cc_frm_header.cpp @@ -98,6 +98,7 @@ void CComponentsHeader::initVarHeader() corner_type = CORNER_TOP; //init header height + cch_size_mode = CC_HEADER_SIZE_LARGE; cch_font = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]; height = cch_font->getHeight(); @@ -343,6 +344,9 @@ void CComponentsHeader::initCaption() void CComponentsHeader::initCCItems() { + //set size + cch_font = (cch_size_mode == CC_HEADER_SIZE_LARGE? g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE] : g_Font[SNeutrinoSettings::FONT_TYPE_MENU]); + //init icon initIcon(); From b9f35bfc6db8ab1f94f4f9198c7388d9bb273ea2 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sun, 8 Sep 2013 22:49:27 +0200 Subject: [PATCH 048/200] CComponentsWindow: fix max width of base items, if frame was set Header, body and footer were too wide on the right side. --- src/gui/components/cc_frm_window.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/components/cc_frm_window.cpp b/src/gui/components/cc_frm_window.cpp index 47d188a31..c5cde1729 100644 --- a/src/gui/components/cc_frm_window.cpp +++ b/src/gui/components/cc_frm_window.cpp @@ -161,7 +161,7 @@ void CComponentsWindow::initHeader() //set header properties if (ccw_head){ ccw_head->setPos(0, 0); - ccw_head->setWidth(width); + ccw_head->setWidth(width-2*fr_thickness); ccw_head->setIcon(ccw_icon_name); ccw_head->setCaption(ccw_caption); ccw_head->initCCItems(); @@ -185,7 +185,7 @@ void CComponentsWindow::initBody() fh = ccw_footer->getHeight(); int hh = ccw_head->getHeight(); int h_body = height - hh - fh; - ccw_body->setDimensionsAll(0, CC_APPEND, width, h_body); + ccw_body->setDimensionsAll(0, CC_APPEND, width-2*fr_thickness, h_body); ccw_body->doPaintBg(false); } } @@ -202,7 +202,7 @@ void CComponentsWindow::initFooter() //set footer properties if (ccw_footer){ ccw_footer->setPos(0, CC_APPEND); - ccw_footer->setWidth(width); + ccw_footer->setWidth(width-2*fr_thickness); ccw_footer->setShadowOnOff(shadow); } } From 566698377d34b8c7d4d4619f649c94f497eaf4de Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Mon, 9 Sep 2013 21:01:43 +0200 Subject: [PATCH 049/200] CComponentsWindow: fix fit of footer if using frame Footer has been overpainted frame on bottom. --- src/gui/components/cc_frm_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/components/cc_frm_window.cpp b/src/gui/components/cc_frm_window.cpp index c5cde1729..f26aadd25 100644 --- a/src/gui/components/cc_frm_window.cpp +++ b/src/gui/components/cc_frm_window.cpp @@ -184,7 +184,7 @@ void CComponentsWindow::initBody() if (ccw_footer) fh = ccw_footer->getHeight(); int hh = ccw_head->getHeight(); - int h_body = height - hh - fh; + int h_body = height - hh - fh - 2*fr_thickness; ccw_body->setDimensionsAll(0, CC_APPEND, width-2*fr_thickness, h_body); ccw_body->doPaintBg(false); } From be8e47fe3f1ef8056ba23ea5effa3d8617b50671 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Mon, 9 Sep 2013 21:04:13 +0200 Subject: [PATCH 050/200] CComponentsButton: add localized button So it's possible to use locales for button caption. --- src/gui/components/cc_frm_button.cpp | 26 ++++++++++++++++++++++++++ src/gui/components/cc_frm_button.h | 16 ++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/gui/components/cc_frm_button.cpp b/src/gui/components/cc_frm_button.cpp index d78471f63..7b79202da 100644 --- a/src/gui/components/cc_frm_button.cpp +++ b/src/gui/components/cc_frm_button.cpp @@ -63,6 +63,32 @@ CComponentsButton::CComponentsButton( const int x_pos, const int y_pos, const i fr_thickness = FRAME_TH; } +CComponentsButton::CComponentsButton( const int x_pos, const int y_pos, const int w, const int h, + const neutrino_locale_t& caption_locale, const std::string& icon_name, + bool selected, bool enabled, bool has_shadow, + fb_pixel_t color_frame, fb_pixel_t color_body, fb_pixel_t color_shadow) +{ + initVarButton(); + cc_btn_icon = icon_name; + cc_btn_capt = g_Locale->getText(caption_locale);; + cc_btn_capt_col = COL_MENUCONTENT_TEXT; + cc_btn_text_w = cc_btn_font->getRenderWidth(cc_btn_capt, true); + cc_btn_text_h = cc_btn_font->getHeight(); + + x = x_pos; + y = y_pos; + width = max(w, cc_btn_text_w); + height = max(h, cc_btn_text_h); + shadow = has_shadow; + shadow_w = SHADOW_OFFSET; + col_frame = color_frame; + col_body = color_body; + col_shadow = color_shadow; + cc_item_enabled = enabled; + cc_item_selected = selected; + fr_thickness = FRAME_TH; +} + void CComponentsButton::initVarButton() { initVarForm(); diff --git a/src/gui/components/cc_frm_button.h b/src/gui/components/cc_frm_button.h index 915288498..8fea740b4 100644 --- a/src/gui/components/cc_frm_button.h +++ b/src/gui/components/cc_frm_button.h @@ -26,7 +26,8 @@ #ifndef __CC_BUTTONS_H__ #define __CC_BUTTONS_H__ -#include "config.h" +#include +#include #include "cc.h" #include "cc_frm.h" #include @@ -75,9 +76,21 @@ class CComponentsButton : public CComponentsForm const std::string& caption, const std::string& icon_name, bool selected = false, bool enabled = true, bool has_shadow = CC_SHADOW_OFF, fb_pixel_t color_frame = COL_LIGHT_GRAY, fb_pixel_t color_body = COL_MENUCONTENT_PLUS_0, fb_pixel_t color_shadow = COL_MENUCONTENTDARK_PLUS_0); + CComponentsButton( const int x_pos, const int y_pos, const int w, const int h, + const neutrino_locale_t& caption_locale, const std::string& icon_name, + bool selected = false, bool enabled = true, bool has_shadow = CC_SHADOW_OFF, + fb_pixel_t color_frame = COL_LIGHT_GRAY, fb_pixel_t color_body = COL_MENUCONTENT_PLUS_0, fb_pixel_t color_shadow = COL_MENUCONTENTDARK_PLUS_0); ///set text color virtual void setButtonTextColor(fb_pixel_t caption_color){cc_btn_capt_col = caption_color;}; + + ///set caption: parameter as string + virtual void setCaption(const std::string& text){cc_btn_capt = text;}; + ///set caption: parameter as locale + virtual void setCaption(const neutrino_locale_t locale_text){cc_btn_capt = g_Locale->getText(locale_text);}; + + ///reinitialize items + virtual void Refresh(){initCCBtnItems();}; ///paint button object void paint(bool do_save_bg = CC_SAVE_SCREEN_YES); @@ -151,5 +164,4 @@ class CComponentsButtonBlue : public CComponentsButton }; }; - #endif /*__CC_BUTTONS_H__*/ From c8356949db393d5a86de41010b4c1ed55cb4cdb0 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sun, 15 Sep 2013 11:12:57 +0200 Subject: [PATCH 051/200] CMenuItem:remove picked #ifdef statements Those cherry picks have no effect, but contain unfavorable maintainer tags or was mixed with other commits, therefore they may be removed or need separately revision. - g_settings.menu_numbers_as_icons: not exists - "active": was deliberately chosen so - g_settings.key_channelList_pageup: is intended for channel list handling --- src/gui/widget/menue.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/gui/widget/menue.cpp b/src/gui/widget/menue.cpp index 41861f370..6ed07b16b 100644 --- a/src/gui/widget/menue.cpp +++ b/src/gui/widget/menue.cpp @@ -214,11 +214,7 @@ void CMenuItem::paintItemButton(const bool select_mode, const int &item_height, int icon_h = 0; //define icon name depends of numeric value -#ifdef MARTII - if (g_settings.menu_numbers_as_icons && icon_name.empty() && CRCInput::isNumeric(directKey)) -#else if (icon_name.empty() && CRCInput::isNumeric(directKey)) -#endif { char i_name[6]; /* X +'\0' */ snprintf(i_name, 6, "%d", CRCInput::getNumericValue(directKey)); @@ -268,14 +264,8 @@ void CMenuItem::paintItemButton(const bool select_mode, const int &item_height, { frameBuffer->getIconSize(iconName_Info_right.c_str(), &icon_w, &icon_h); -#ifdef MARTII - if (icon_w>0 && icon_h>0) -#else if (active && icon_w>0 && icon_h>0) -#endif - { icon_painted = frameBuffer->paintIcon(iconName_Info_right, dx + icon_start_x - (icon_w + 20), y+ ((item_height/2- icon_h/2)) ); - } } } @@ -575,7 +565,7 @@ int CMenuWidget::exec(CMenuTarget* parent, const std::string &) break; } } -#ifdef MARTII +#if 0 if (msg == (uint32_t) g_settings.key_channelList_pageup) msg = CRCInput::RC_page_up; else if (msg == (uint32_t) g_settings.key_channelList_pagedown) From c6b9fe432b4ceac521dff3617403d52bd777394f Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sun, 15 Sep 2013 18:10:10 +0200 Subject: [PATCH 052/200] CComponents: add member setCorner() This replaces setCornerType() and setCornerRadius() soon --- src/gui/components/cc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/components/cc.h b/src/gui/components/cc.h index e86b43799..ecfb9d87d 100644 --- a/src/gui/components/cc.h +++ b/src/gui/components/cc.h @@ -184,6 +184,8 @@ class CComponents inline virtual void setCornerType(const int& type){corner_type = type;}; ///set corner radius inline virtual void setCornerRadius(const int& radius){corner_rad = radius;}; + ///set corner radius and type + inline virtual void setCorner(const int& radius, const int& type = CORNER_ALL){corner_rad = radius; corner_type = type;}; ///get corner types inline virtual int getCornerType(){return corner_type;}; ///get corner radius From a9a1c5dd68302ce05d21335b5eacc0eaa39cd368 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sun, 15 Sep 2013 18:15:10 +0200 Subject: [PATCH 053/200] CMenuItem: use CComponentsShapeSquare to paint color sector This is only a partial solution. CMenuItem class can principle completely be implemented with cc-items or cc-Forms. --- src/gui/widget/menue.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/gui/widget/menue.cpp b/src/gui/widget/menue.cpp index 6ed07b16b..3332192c4 100644 --- a/src/gui/widget/menue.cpp +++ b/src/gui/widget/menue.cpp @@ -35,7 +35,7 @@ #include #include - +#include #include #include #include @@ -161,8 +161,10 @@ void CMenuItem::paintItemCaption(const bool select_mode, const int &item_height, if (right_bgcol) { if (!right_text) stringstartposOption -= 60; - CFrameBuffer::getInstance()->paintBoxRel(stringstartposOption, y + 1, dx - stringstartposOption + x - 1, item_height - 2, right_bgcol, RADIUS_LARGE); - CFrameBuffer::getInstance()->paintBoxFrame(stringstartposOption, y + 1, dx - stringstartposOption + x - 1, item_height - 2, 1, COL_MENUCONTENT_PLUS_6, RADIUS_LARGE); + CComponentsShapeSquare col(stringstartposOption, y + 2, dx - stringstartposOption + x - 2, item_height - 4, false, COL_MENUCONTENT_PLUS_6, right_bgcol); + col.setFrameThickness(3); + col.setCorner(RADIUS_LARGE); + col.paint(false); } if (right_text) g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposOption, y+item_height,dx- (stringstartposOption- x), right_text, item_color, 0, true); From 33ec56ad6f9e75aaed50ae645d7e612cdce055cb Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sun, 15 Sep 2013 20:39:54 +0200 Subject: [PATCH 054/200] CComponents: remove member setCornerRadius(), setCorner() replaces this function, 2nd parameter sets type --- src/gui/audioplayer.cpp | 4 ++-- src/gui/bedit/bouqueteditor_channels.cpp | 2 +- src/gui/bedit/bouqueteditor_chanselect.cpp | 2 +- src/gui/channellist.cpp | 3 +-- src/gui/components/cc.h | 2 -- src/gui/components/cc_frm_button.cpp | 3 +-- src/gui/components/cc_frm_clock.cpp | 3 +-- src/gui/components/cc_frm_header.cpp | 9 +++------ src/gui/components/cc_frm_signalbars.cpp | 4 ++-- src/gui/infoviewer.cpp | 2 +- src/gui/volumebar.cpp | 6 ++---- src/gui/widget/menue.cpp | 2 +- 12 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/gui/audioplayer.cpp b/src/gui/audioplayer.cpp index c40a822ea..f8df608cb 100644 --- a/src/gui/audioplayer.cpp +++ b/src/gui/audioplayer.cpp @@ -1645,7 +1645,7 @@ void CAudioPlayerGui::paintHead() return; CComponentsHeader header(m_x, m_y + m_title_height, m_width, m_theight, LOCALE_AUDIOPLAYER_HEAD, NEUTRINO_ICON_MP3); - header.setCornerRadius(RADIUS_MID); + header.setCorner(RADIUS_MID); if (m_inetmode) header.setCaption(LOCALE_INETRADIO_NAME); @@ -1922,7 +1922,7 @@ void CAudioPlayerGui::paintItemID3DetailsLine (int pos) // paint id3 infobox if (ibox == NULL) ibox = new CComponentsInfoBox(m_x, ypos2, m_width, m_info_height); - ibox->setCornerRadius(RADIUS_LARGE); + ibox->setCorner(RADIUS_LARGE); ibox->setYPos(ypos2); ibox->setColorBody(COL_MENUCONTENTDARK_PLUS_0); ibox->paint(false); diff --git a/src/gui/bedit/bouqueteditor_channels.cpp b/src/gui/bedit/bouqueteditor_channels.cpp index 8b0f4a2ac..049eb9036 100644 --- a/src/gui/bedit/bouqueteditor_channels.cpp +++ b/src/gui/bedit/bouqueteditor_channels.cpp @@ -249,7 +249,7 @@ void CBEChannelWidget::initItem2DetailsLine (int pos, int /*ch_index*/) #if 0 ibox->paint(false,true); #endif - ibox->setCornerRadius(RADIUS_LARGE); + ibox->setCorner(RADIUS_LARGE); ibox->setShadowOnOff(CC_SHADOW_OFF); } } diff --git a/src/gui/bedit/bouqueteditor_chanselect.cpp b/src/gui/bedit/bouqueteditor_chanselect.cpp index 56bf80e6d..f3a02fde3 100644 --- a/src/gui/bedit/bouqueteditor_chanselect.cpp +++ b/src/gui/bedit/bouqueteditor_chanselect.cpp @@ -259,7 +259,7 @@ void CBEChannelSelectWidget::initItem2DetailsLine (int pos, int /*ch_index*/) if (ibox){ ibox->setDimensionsAll(x, ypos2, width, info_height); ibox->setFrameThickness(2); - ibox->setCornerRadius(RADIUS_LARGE); + ibox->setCorner(RADIUS_LARGE); ibox->setShadowOnOff(CC_SHADOW_OFF); } } diff --git a/src/gui/channellist.cpp b/src/gui/channellist.cpp index 78a26a227..4f6b7ad08 100644 --- a/src/gui/channellist.cpp +++ b/src/gui/channellist.cpp @@ -2108,8 +2108,7 @@ void CChannelList::paintHead() } headerClock->setClockFont(g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]); - headerClock->setCornerRadius(RADIUS_LARGE); - headerClock->setCornerType(CORNER_TOP_RIGHT); + headerClock->setCorner(RADIUS_LARGE, CORNER_TOP_RIGHT); headerClock->setYPos(y); headerClock->setHeight(theight); headerClock->setTextColor(COL_MENUHEAD_TEXT); diff --git a/src/gui/components/cc.h b/src/gui/components/cc.h index ecfb9d87d..fa7c455b7 100644 --- a/src/gui/components/cc.h +++ b/src/gui/components/cc.h @@ -182,8 +182,6 @@ class CComponents ///Possible corner types are defined in CFrameBuffer (see: driver/framebuffer.h) ///Note: default values are given from settings inline virtual void setCornerType(const int& type){corner_type = type;}; - ///set corner radius - inline virtual void setCornerRadius(const int& radius){corner_rad = radius;}; ///set corner radius and type inline virtual void setCorner(const int& radius, const int& type = CORNER_ALL){corner_rad = radius; corner_type = type;}; ///get corner types diff --git a/src/gui/components/cc_frm_button.cpp b/src/gui/components/cc_frm_button.cpp index 7b79202da..c43c7fe8a 100644 --- a/src/gui/components/cc_frm_button.cpp +++ b/src/gui/components/cc_frm_button.cpp @@ -164,8 +164,7 @@ void CComponentsButton::initCaption() cc_btn_capt_obj->doPaintBg(false); //corner of text item - cc_btn_capt_obj->setCornerRadius(corner_rad-fr_thickness); - cc_btn_capt_obj->setCornerType(corner_type); + cc_btn_capt_obj->setCorner(corner_rad-fr_thickness, corner_type); } } diff --git a/src/gui/components/cc_frm_clock.cpp b/src/gui/components/cc_frm_clock.cpp index eda580c72..aecf77fb0 100644 --- a/src/gui/components/cc_frm_clock.cpp +++ b/src/gui/components/cc_frm_clock.cpp @@ -136,8 +136,7 @@ void CComponentsFrmClock::initCCLockItems() lbl->doPaintBg(false); //set corner properties of label item - lbl->setCornerRadius(corner_rad-fr_thickness); - lbl->setCornerType(corner_type); + lbl->setCorner(corner_rad-fr_thickness, corner_type); //set text border to 0 lbl->setTextBorderWidth(0,0); diff --git a/src/gui/components/cc_frm_header.cpp b/src/gui/components/cc_frm_header.cpp index 2278eedd3..554601fb9 100644 --- a/src/gui/components/cc_frm_header.cpp +++ b/src/gui/components/cc_frm_header.cpp @@ -184,13 +184,12 @@ void CComponentsHeader::initIcon() cch_icon_obj->setPictureAlign(CC_ALIGN_HOR_CENTER | CC_ALIGN_VER_CENTER); //set corner mode of icon item - cch_icon_obj->setCornerRadius(corner_rad-fr_thickness); int cc_icon_corner_type = corner_type; if (corner_type == CORNER_TOP_LEFT || corner_type == CORNER_TOP) cc_icon_corner_type = CORNER_TOP_LEFT; else cc_icon_corner_type = CORNER_LEFT; - cch_icon_obj->setCornerType(cc_icon_corner_type); + cch_icon_obj->setCorner(corner_rad-fr_thickness, cc_icon_corner_type); //global set width of icon object cch_icon_w = cch_icon_obj->getWidth(); @@ -279,13 +278,12 @@ void CComponentsHeader::initButtons() cch_btn_obj->addIcon(v_cch_btn); //set corner mode of button item - cch_btn_obj->setCornerRadius(corner_rad-fr_thickness); int cc_btn_corner_type = corner_type; if (corner_type == CORNER_TOP_RIGHT || corner_type == CORNER_TOP) cc_btn_corner_type = CORNER_TOP_RIGHT; else cc_btn_corner_type = CORNER_RIGHT; - cch_btn_obj->setCornerType(cc_btn_corner_type); + cch_btn_obj->setCorner(corner_rad-fr_thickness, cc_btn_corner_type); //global adapt height height = max(height, cch_btn_obj->getHeight()); @@ -331,8 +329,7 @@ void CComponentsHeader::initCaption() cch_text_obj->setColorBody(col_body); //corner of text item - cch_text_obj->setCornerRadius(corner_rad-fr_thickness); - cch_text_obj->setCornerType(corner_type); + cch_text_obj->setCorner(corner_rad-fr_thickness, corner_type); /* global adapt height not needed here again diff --git a/src/gui/components/cc_frm_signalbars.cpp b/src/gui/components/cc_frm_signalbars.cpp index 506d61001..68359e1b0 100644 --- a/src/gui/components/cc_frm_signalbars.cpp +++ b/src/gui/components/cc_frm_signalbars.cpp @@ -327,12 +327,12 @@ void CSignalBox::initSignalItems() sbar->setDimensionsAll(sbar_x, fr_thickness, sbar_w, sbar_h); sbar->setFrontEnd(sbx_frontend); - sbar->setCornerRadius(0); + sbar->setCorner(0); sbar->setScaleHeight(scale_h); snrbar->setDimensionsAll(sbar_x, CC_APPEND, sbar_w, sbar_h); snrbar->setFrontEnd(sbx_frontend); - snrbar->setCornerRadius(0); + snrbar->setCorner(0); snrbar->setScaleHeight(scale_h); } diff --git a/src/gui/infoviewer.cpp b/src/gui/infoviewer.cpp index 26894555d..4f9a740a7 100644 --- a/src/gui/infoviewer.cpp +++ b/src/gui/infoviewer.cpp @@ -1868,7 +1868,7 @@ void CInfoViewer::showInfoFile() //set some properties for info object infobar_txt->setDimensionsAll(xStart, yStart, width, height); - infobar_txt->setCornerRadius(RADIUS_SMALL); + infobar_txt->setCorner(RADIUS_SMALL); infobar_txt->setShadowOnOff(true); infobar_txt->setTextColor(COL_INFOBAR_TEXT); infobar_txt->setColorBody(COL_INFOBAR_PLUS_0); diff --git a/src/gui/volumebar.cpp b/src/gui/volumebar.cpp index b28e1b3cb..f2c1ade75 100644 --- a/src/gui/volumebar.cpp +++ b/src/gui/volumebar.cpp @@ -175,8 +175,7 @@ void CVolumeBar::initVolumeBarIcon() vb_icon->setPictureAlign(CC_ALIGN_HOR_CENTER | CC_ALIGN_VER_CENTER); vb_icon->setColorBody(col_body); - vb_icon->setCornerRadius(cornerRad()); - vb_icon->setCornerType(CORNER_LEFT); + vb_icon->setCorner(cornerRad(), CORNER_LEFT); //add icon to container addCCItem(vb_icon); @@ -210,8 +209,7 @@ void CVolumeBar::initVolumeBarDigit() vb_digit->setDimensionsAll(vb_digit_x, 0, vb_digit_w, height); vb_digit->setTextColor(COL_MENUCONTENT_TEXT); - vb_digit->setCornerRadius(cornerRad()); - vb_digit->setCornerType(CORNER_RIGHT); + vb_digit->setCorner(cornerRad(), CORNER_RIGHT); initVolumeBarDigitValue(); //add digit label to container diff --git a/src/gui/widget/menue.cpp b/src/gui/widget/menue.cpp index 3332192c4..e9a0b35b2 100644 --- a/src/gui/widget/menue.cpp +++ b/src/gui/widget/menue.cpp @@ -1161,7 +1161,7 @@ void CMenuWidget::paintHint(int pos) info_box->setFrameThickness(2); info_box->removeLineBreaks(str); info_box->setText(str, CTextBox::AUTO_WIDTH, g_Font[SNeutrinoSettings::FONT_TYPE_MENU_HINT]); - info_box->setCornerRadius(RADIUS_LARGE); + info_box->setCorner(RADIUS_LARGE); info_box->syncSysColors(); info_box->setColorBody(COL_MENUCONTENTDARK_PLUS_0); info_box->setShadowOnOff(CC_SHADOW_ON); From 08e23a917c8d000d1de384d26247ca5d1ab29584 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Mon, 16 Sep 2013 11:42:50 +0200 Subject: [PATCH 055/200] CTextBox: ensure paint of background to avoid overlapped letters --- src/gui/widget/textbox.cpp | 26 ++++++++++++++++++++++---- src/gui/widget/textbox.h | 1 + 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/gui/widget/textbox.cpp b/src/gui/widget/textbox.cpp index d45ac125c..74ae8b9b7 100644 --- a/src/gui/widget/textbox.cpp +++ b/src/gui/widget/textbox.cpp @@ -135,13 +135,14 @@ CTextBox::~CTextBox() //TRACE("[CTextBox] del\r\n"); m_cLineArray.clear(); hide(); - + delete[] m_bgpixbuf; } void CTextBox::initVar(void) { //TRACE("[CTextBox]->InitVar\r\n"); frameBuffer = NULL; + m_bgpixbuf = NULL; m_showTextFrame = 0; m_nNrOfNewLine = 0; @@ -510,10 +511,27 @@ void CTextBox::refreshText(void) //TRACE("[CTextBox] m_nCurrentLine: %d, m_nNrOfLines %d, m_cLineArray[m_nCurrentLine]: %s\r\n",m_nCurrentLine, m_nNrOfLines, m_cLineArray[m_nCurrentLine].c_str()); + //bg variables + int ax = m_cFrameTextRel.iX+m_cFrame.iX; + int ay = /*m_cFrameTextRel.iY+*/m_cFrame.iY; + int dx = m_cFrameTextRel.iWidth; + int dy = m_cFrameTextRel.iHeight; + + //save screen + if (m_bgpixbuf == NULL){ + m_bgpixbuf= new fb_pixel_t[dx * dy]; + frameBuffer->SaveScreen(ax, ay, dx, dy, m_bgpixbuf); + } + //Paint Text Background - if (m_nPaintBackground) - frameBuffer->paintBoxRel(m_cFrameTextRel.iX+m_cFrame.iX, /*m_cFrameTextRel.iY+*/m_cFrame.iY, - m_cFrameTextRel.iWidth, m_cFrameTextRel.iHeight, m_textBackgroundColor, m_nBgRadius, m_nBgRadiusType); + if (m_nPaintBackground){ + if (m_bgpixbuf) + delete[] m_bgpixbuf; + m_bgpixbuf = NULL; + frameBuffer->paintBoxRel(ax, ay, dx, dy, m_textBackgroundColor, m_nBgRadius, m_nBgRadiusType); + } + else + frameBuffer->RestoreScreen(ax, ay, dx, dy, m_bgpixbuf); if( m_nNrOfLines <= 0) return; diff --git a/src/gui/widget/textbox.h b/src/gui/widget/textbox.h index 210db2717..39a1f9ff8 100644 --- a/src/gui/widget/textbox.h +++ b/src/gui/widget/textbox.h @@ -150,6 +150,7 @@ class CTextBox int m_nFontTextHeight; CFBWindow::color_t m_textBackgroundColor; fb_pixel_t m_textColor; + fb_pixel_t* m_bgpixbuf; CFrameBuffer * frameBuffer; /* int max_width;*/ From ccddafa427f7a35230f4fdbb1c1e59b150334f27 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Mon, 16 Sep 2013 11:43:43 +0200 Subject: [PATCH 056/200] CNeutrinoEventList: don't paint explicit background --- src/gui/eventlist.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/eventlist.cpp b/src/gui/eventlist.cpp index b581de234..c5834508a 100644 --- a/src/gui/eventlist.cpp +++ b/src/gui/eventlist.cpp @@ -838,7 +838,6 @@ void CNeutrinoEventList::paintDescription(int index) infozone_text = g_Locale->getText(LOCALE_EPGLIST_NOEVENTS); cc_infozone->setText(infozone_text, CTextBox::TOP, g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_EVENT]); - cc_infozone->doPaintTextBoxBg(true); cc_infozone->doPaintBg(false); cc_infozone->forceTextPaint(); cc_infozone->paint(CC_SAVE_SCREEN_NO); From 32ca9b848c9964d680085821da1dd84e1a63f4e9 Mon Sep 17 00:00:00 2001 From: Christian Schuett Date: Thu, 19 Sep 2013 09:28:42 +0200 Subject: [PATCH 057/200] CChannelList: mark current channel if not selected Signed-off-by: Thilo Graf --- src/gui/channellist.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/gui/channellist.cpp b/src/gui/channellist.cpp index 4f6b7ad08..318eb26b3 100644 --- a/src/gui/channellist.cpp +++ b/src/gui/channellist.cpp @@ -277,7 +277,9 @@ CZapitChannel* CChannelList::getChannel(t_channel_id channel_id) int CChannelList::getKey(int id) { - return chanlist[id]->number; + if (id > -1 && id < (int)chanlist.size()) + return chanlist[id]->number; + return 0; } static const std::string empty_string; @@ -294,8 +296,7 @@ t_satellite_position CChannelList::getActiveSatellitePosition(void) const { if (selected < chanlist.size()) return chanlist[selected]->getSatellitePosition(); - else - return 0; + return 0; } t_channel_id CChannelList::getActiveChannel_ChannelID(void) const @@ -309,7 +310,6 @@ t_channel_id CChannelList::getActiveChannel_ChannelID(void) const int CChannelList::getActiveChannelNumber(void) const { - //return (selected + 1); if (selected < chanlist.size()) return chanlist[selected]->number; return 0; @@ -1897,12 +1897,18 @@ void CChannelList::paintItem(int pos, const bool firstpaint) paintDetails(curr); c_rad_small = RADIUS_LARGE; paintbuttons = true; + } + else if (getKey(curr) == CNeutrinoApp::getInstance()->channelList->getActiveChannelNumber()) + { + color = !displayNext ? COL_MENUCONTENT_TEXT : COL_MENUCONTENTINACTIVE_TEXT; + bgcolor = !displayNext ? COL_MENUCONTENT_PLUS_1 : COL_MENUCONTENTINACTIVE_PLUS_0; + c_rad_small = RADIUS_LARGE; } else { color = iscurrent ? COL_MENUCONTENT_TEXT : COL_MENUCONTENTINACTIVE_TEXT; bgcolor = iscurrent ? COL_MENUCONTENT_PLUS_0 : COL_MENUCONTENTINACTIVE_PLUS_0; } - if(!firstpaint || (curr == selected)){ + if(!firstpaint || (curr == selected) || getKey(curr) == CNeutrinoApp::getInstance()->channelList->getActiveChannelNumber()){ frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor, c_rad_small); } From e655e94c8ab5208c5ed3493716d93407916f9452 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Thu, 19 Sep 2013 17:11:05 +0400 Subject: [PATCH 058/200] zapit/src/bouquets.cpp: fix scan bouquets saving, ignore user bouquets while copy --- src/zapit/include/zapit/bouquets.h | 2 +- src/zapit/src/bouquets.cpp | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/zapit/include/zapit/bouquets.h b/src/zapit/include/zapit/bouquets.h index c9eeb272e..ca26782a3 100644 --- a/src/zapit/include/zapit/bouquets.h +++ b/src/zapit/include/zapit/bouquets.h @@ -112,7 +112,7 @@ class CBouquetManager CZapitBouquet* addBouquet(const std::string & name, bool ub = false, bool myfav = false); void deleteBouquet(const unsigned int id); void deleteBouquet(const CZapitBouquet* bouquet); - int existsBouquet(char const * const name); + int existsBouquet(char const * const name, bool ignore_user = false); int existsUBouquet(char const * const name, bool myfav = false); void moveBouquet(const unsigned int oldId, const unsigned int newId); bool existsChannelInBouquet(unsigned int bq_id, const t_channel_id channel_id); diff --git a/src/zapit/src/bouquets.cpp b/src/zapit/src/bouquets.cpp index d171acc63..b26c51385 100644 --- a/src/zapit/src/bouquets.cpp +++ b/src/zapit/src/bouquets.cpp @@ -304,11 +304,11 @@ void CBouquetManager::saveBouquets(const CZapitClient::bouquetMode bouquetMode, if ((bouquetMode == CZapitClient::BM_UPDATEBOUQUETS) || (bouquetMode == CZapitClient::BM_DELETEBOUQUETS)) { while (!(Bouquets.empty())) { CZapitBouquet* bouquet; - int dest = g_bouquetManager->existsBouquet(Bouquets[0]->Name.c_str()); + int dest = g_bouquetManager->existsBouquet(Bouquets[0]->Name.c_str(), true); DBG("save Bouquets: dest %d for name %s\n", dest, Bouquets[0]->Name.c_str()); if(dest == -1) { bouquet = g_bouquetManager->addBouquet(Bouquets[0]->Name.c_str(), false); - dest = g_bouquetManager->existsBouquet(Bouquets[0]->Name.c_str()); + dest = g_bouquetManager->existsBouquet(Bouquets[0]->Name.c_str(), true); } else bouquet = g_bouquetManager->Bouquets[dest]; @@ -552,11 +552,10 @@ int str_compare_withoutspace(char const *s1, char const *s2) // -- Find Bouquet-Name, if BQ exists (2002-04-02 rasc) // -- Return: Bouqet-ID (found: 0..n) or -1 (Bouquet does not exist) -int CBouquetManager::existsBouquet(char const * const name) +int CBouquetManager::existsBouquet(char const * const name, bool ignore_user) { - unsigned int i; - for (i = 0; i < Bouquets.size(); i++) { - if (Bouquets[i]->Name == name) + for (unsigned int i = 0; i < Bouquets.size(); i++) { + if ((!ignore_user || !Bouquets[i]->bUser) && (Bouquets[i]->Name == name)) { return (int)i; } From 19fa5e64181945322d7fc835fdfdde264f1d99a9 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Fri, 20 Sep 2013 08:32:02 +0200 Subject: [PATCH 059/200] CComponentsButton: remove function blocks from header --- src/gui/components/cc_frm_button.cpp | 10 ++++++++++ src/gui/components/cc_frm_button.h | 5 ++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/gui/components/cc_frm_button.cpp b/src/gui/components/cc_frm_button.cpp index c43c7fe8a..56496b505 100644 --- a/src/gui/components/cc_frm_button.cpp +++ b/src/gui/components/cc_frm_button.cpp @@ -168,6 +168,16 @@ void CComponentsButton::initCaption() } } +void CComponentsButton::setCaption(const std::string& text) +{ + cc_btn_capt = text; +} + +void CComponentsButton::setCaption(const neutrino_locale_t locale_text) +{ + cc_btn_capt = g_Locale->getText(locale_text); +} + void CComponentsButton::initCCBtnItems() { initIcon(); diff --git a/src/gui/components/cc_frm_button.h b/src/gui/components/cc_frm_button.h index 8fea740b4..5c196d88e 100644 --- a/src/gui/components/cc_frm_button.h +++ b/src/gui/components/cc_frm_button.h @@ -27,7 +27,6 @@ #define __CC_BUTTONS_H__ #include -#include #include "cc.h" #include "cc_frm.h" #include @@ -85,9 +84,9 @@ class CComponentsButton : public CComponentsForm virtual void setButtonTextColor(fb_pixel_t caption_color){cc_btn_capt_col = caption_color;}; ///set caption: parameter as string - virtual void setCaption(const std::string& text){cc_btn_capt = text;}; + virtual void setCaption(const std::string& text); ///set caption: parameter as locale - virtual void setCaption(const neutrino_locale_t locale_text){cc_btn_capt = g_Locale->getText(locale_text);}; + virtual void setCaption(const neutrino_locale_t locale_text); ///reinitialize items virtual void Refresh(){initCCBtnItems();}; From c7b03680b4b99b09dd60306ebb034e1c67f98d88 Mon Sep 17 00:00:00 2001 From: svenhoefer Date: Fri, 20 Sep 2013 12:09:36 +0200 Subject: [PATCH 060/200] - yweb: add trinity rcu --- src/nhttpd/web/Y_Blocks.txt | 73 +++++++++++++++++++++++++++- src/nhttpd/web/Y_Settings_yWeb.yhtm | 2 + src/nhttpd/web/images/rc_cst_v6.jpg | Bin 0 -> 62925 bytes 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 src/nhttpd/web/images/rc_cst_v6.jpg diff --git a/src/nhttpd/web/Y_Blocks.txt b/src/nhttpd/web/Y_Blocks.txt index 8dab68a26..8ba672987 100644 --- a/src/nhttpd/web/Y_Blocks.txt +++ b/src/nhttpd/web/Y_Blocks.txt @@ -510,9 +510,11 @@ start-block~remote {=if-equal:{=var-get:boxtype=}~CST Neo Twin CABLE~ {=include-block:Y_Blocks.txt;rc_cst_v4=}~ {=if-equal:{=var-get:boxtype=}~CST Tank SAT~ {=include-block:Y_Blocks.txt;rc_cst_v5=}~ {=if-equal:{=var-get:boxtype=}~CST Tank CABLE~ {=include-block:Y_Blocks.txt;rc_cst_v5=}~ + {=if-equal:{=var-get:boxtype=}~CST Trinity SAT~ {=include-block:Y_Blocks.txt;rc_cst_v6=}~ + {=if-equal:{=var-get:boxtype=}~CST Trinity CABLE~ {=include-block:Y_Blocks.txt;rc_cst_v6=}~ {=comment:fallback~=} {=include-block:Y_Blocks.txt;rc_cst_v1=} - =}=}=}=}=}=}=}=} + =}=}=}=}=}=}=}=}=}=} =}=} ~ {=if-equal:{=var-get:yfbtype=}~-2~ {=include-block:Y_Blocks.txt;rc_dbox_philips=}~ @@ -522,9 +524,10 @@ start-block~remote {=if-equal:{=var-get:yfbtype=}~3~ {=include-block:Y_Blocks.txt;rc_cst_v3=}~ {=if-equal:{=var-get:yfbtype=}~4~ {=include-block:Y_Blocks.txt;rc_cst_v4=}~ {=if-equal:{=var-get:yfbtype=}~5~ {=include-block:Y_Blocks.txt;rc_cst_v5=}~ + {=if-equal:{=var-get:yfbtype=}~6~ {=include-block:Y_Blocks.txt;rc_cst_v6=}~ {=comment:fallback~=} {=include-block:Y_Blocks.txt;rc_cst_v1=} - =}=}=}=}=}=}=} + =}=}=}=}=}=}=}=} =} end-block~remote @@ -789,6 +792,72 @@ start-block~rc_cst_v5 end-block~rc_cst_v5 +# ------- Remote CST V6 (TRINITY) +start-block~rc_cst_v6 +remote + + standby + mute + sat + + tv-radio + + skip+ + skip- + picsize + picmode + + fav + t/s + audio + text + + + help + + + epg + info + menu + exit + ok + vol+ + page+ + vol- + page- + up + down + left + right + rec + + w + pause + ff + rew + stop + play + + red + green + yellow + blue + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + + sleep + +end-block~rc_cst_v6 + # ------- Remote d-Box Nokia old start-block~rc_dbox_nokia_old remote diff --git a/src/nhttpd/web/Y_Settings_yWeb.yhtm b/src/nhttpd/web/Y_Settings_yWeb.yhtm index 17a0991e8..bf3a914ab 100644 --- a/src/nhttpd/web/Y_Settings_yWeb.yhtm +++ b/src/nhttpd/web/Y_Settings_yWeb.yhtm @@ -20,6 +20,7 @@ function do_init(){ case "3": // cst zee/neo2 case "4": // cst neo twin case "5": // cst tank + case "6": // cst trinity sel=(sel*1+val*1); break; default: @@ -97,6 +98,7 @@ function do_init(){ + diff --git a/src/nhttpd/web/images/rc_cst_v6.jpg b/src/nhttpd/web/images/rc_cst_v6.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5a2b296ec610b957dad003e92cf5b4f6fbff1dc8 GIT binary patch literal 62925 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 Tp6aM?GlASES-L5m?lwXlIDTqgys78VC&@t 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 Date: Fri, 20 Sep 2013 13:36:42 +0200 Subject: [PATCH 061/200] - yweb: remove delivery_system from boxtype tank and avoid duplicate code --- .../tuxboxapi/coolstream/controlapi.cpp | 46 +------------------ .../tuxboxapi/coolstream/neutrinoyparser.cpp | 3 +- .../tuxboxapi/coolstream/neutrinoyparser.h | 4 +- src/nhttpd/web/Y_Blocks.txt | 5 +- 4 files changed, 9 insertions(+), 49 deletions(-) diff --git a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp index 029416f14..df5fe470d 100644 --- a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp +++ b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp @@ -600,55 +600,13 @@ void CControlAPI::InfoCGI(CyhookHandler *hh) void CControlAPI::HWInfoCGI(CyhookHandler *hh) { - unsigned int system_rev = cs_get_revision(); - std::string boxname = "CST "; + std::string boxname = NeutrinoAPI->NeutrinoYParser->func_get_boxtype(hh, ""); + static CNetAdapter netadapter; std::string eth_id = netadapter.getMacAddr(); std::transform(eth_id.begin(), eth_id.end(), eth_id.begin(), ::tolower); -#if HAVE_TRIPLEDRAGON - boxname = "Armas "; -#endif - - switch(system_rev) - { - case 1: - if( boxname == "Armas ") - boxname += "TripleDragon"; - break; - case 6: - boxname += "HD1"; - break; - case 7: - boxname += "BSE"; - break; - case 8: - boxname += "Neo"; - if (CFEManager::getInstance()->getFrontendCount() > 1) - boxname += " Twin"; - break; - case 9: - boxname += "Tank"; - break; - case 10: - boxname += "Zee"; - break; - case 11: - boxname += "Trinity"; - break; - - default: - char buffer[10]; - snprintf(buffer, sizeof(buffer), "%u\n", system_rev); - boxname += "Unknown nr. "; - boxname += buffer; - break; - } - - boxname += (g_info.delivery_system == DVB_S || (system_rev == 1)) ? " SAT":" CABLE"; hh->printf("%s\nMAC:%s\n", boxname.c_str(),eth_id.c_str()); - - } //----------------------------------------------------------------------------- void CControlAPI::ShutdownCGI(CyhookHandler *hh) diff --git a/src/nhttpd/tuxboxapi/coolstream/neutrinoyparser.cpp b/src/nhttpd/tuxboxapi/coolstream/neutrinoyparser.cpp index 8824c9342..85fcde1d1 100644 --- a/src/nhttpd/tuxboxapi/coolstream/neutrinoyparser.cpp +++ b/src/nhttpd/tuxboxapi/coolstream/neutrinoyparser.cpp @@ -729,7 +729,8 @@ std::string CNeutrinoYParser::func_get_boxtype(CyhookHandler *, std::string) break; } - boxname += (g_info.delivery_system == DVB_S || (system_rev == 1)) ? " SAT":" CABLE"; + if (system_rev != 9) // don't add delivery_system for Tank + boxname += (g_info.delivery_system == DVB_S || (system_rev == 1)) ? " SAT":" CABLE"; return boxname; } //------------------------------------------------------------------------- diff --git a/src/nhttpd/tuxboxapi/coolstream/neutrinoyparser.h b/src/nhttpd/tuxboxapi/coolstream/neutrinoyparser.h index b32f99c32..6b934c37d 100644 --- a/src/nhttpd/tuxboxapi/coolstream/neutrinoyparser.h +++ b/src/nhttpd/tuxboxapi/coolstream/neutrinoyparser.h @@ -43,7 +43,6 @@ private: std::string func_get_audio_pids_as_dropdown(CyhookHandler *hh, std::string para); std::string func_unmount_get_list(CyhookHandler *hh, std::string para); std::string func_get_partition_list(CyhookHandler *hh, std::string para); - std::string func_get_boxtype(CyhookHandler *hh, std::string para); std::string func_get_current_stream_info(CyhookHandler *hh, std::string para); std::string func_get_timer_list(CyhookHandler *hh, std::string para); std::string func_set_timer_form(CyhookHandler *hh, std::string para); @@ -65,6 +64,9 @@ public: virtual std::string getHookVersion(void) {return std::string("$Revision$");} virtual THandleStatus Hook_SendResponse(CyhookHandler *hh); virtual THandleStatus Hook_ReadConfig(CConfigFile *Config, CStringList &ConfigList); + + // func TUXBOX + std::string func_get_boxtype(CyhookHandler *hh, std::string para); }; #endif /*__nhttpd_neutrinoyparser_h__*/ diff --git a/src/nhttpd/web/Y_Blocks.txt b/src/nhttpd/web/Y_Blocks.txt index 8ba672987..8c2319421 100644 --- a/src/nhttpd/web/Y_Blocks.txt +++ b/src/nhttpd/web/Y_Blocks.txt @@ -508,13 +508,12 @@ start-block~remote {=if-equal:{=var-get:boxtype=}~CST Zee CABLE~ {=include-block:Y_Blocks.txt;rc_cst_v3=}~ {=if-equal:{=var-get:boxtype=}~CST Neo Twin SAT~ {=include-block:Y_Blocks.txt;rc_cst_v4=}~ {=if-equal:{=var-get:boxtype=}~CST Neo Twin CABLE~ {=include-block:Y_Blocks.txt;rc_cst_v4=}~ - {=if-equal:{=var-get:boxtype=}~CST Tank SAT~ {=include-block:Y_Blocks.txt;rc_cst_v5=}~ - {=if-equal:{=var-get:boxtype=}~CST Tank CABLE~ {=include-block:Y_Blocks.txt;rc_cst_v5=}~ + {=if-equal:{=var-get:boxtype=}~CST Tank~ {=include-block:Y_Blocks.txt;rc_cst_v5=}~ {=if-equal:{=var-get:boxtype=}~CST Trinity SAT~ {=include-block:Y_Blocks.txt;rc_cst_v6=}~ {=if-equal:{=var-get:boxtype=}~CST Trinity CABLE~ {=include-block:Y_Blocks.txt;rc_cst_v6=}~ {=comment:fallback~=} {=include-block:Y_Blocks.txt;rc_cst_v1=} - =}=}=}=}=}=}=}=}=}=} + =}=}=}=}=}=}=}=}=} =}=} ~ {=if-equal:{=var-get:yfbtype=}~-2~ {=include-block:Y_Blocks.txt;rc_dbox_philips=}~ From 85616227513f8f971e9f59b2bbc6e7116992fd36 Mon Sep 17 00:00:00 2001 From: svenhoefer Date: Fri, 20 Sep 2013 14:31:05 +0200 Subject: [PATCH 062/200] - yweb: fix typo in startpage definition --- src/nhttpd/web/Y_Blocks.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nhttpd/web/Y_Blocks.txt b/src/nhttpd/web/Y_Blocks.txt index 8c2319421..e604de86b 100644 --- a/src/nhttpd/web/Y_Blocks.txt +++ b/src/nhttpd/web/Y_Blocks.txt @@ -430,7 +430,7 @@ start-block~frame_boxcontrol {=var-set:work= {=if-equal:{=var-get:startpage=}~bouquets~Y_Boxcontrol_Bouquets.yhtm ~ - {=if-equal:{=var-get:startpage=}~control~Y_Tools_Boxcontrol.yhtm~Y_blank.yhtm=} + {=if-equal:{=var-get:startpage=}~control~Y_Tools_Boxcontrol.yhtm~Y_blank.htm=} =}=} {=include-block:Y_Blocks.txt;frame_secondary=} end-block~frame_boxcontrol From 18a24d18bd0815eafb36288db4c5179357b28429 Mon Sep 17 00:00:00 2001 From: svenhoefer Date: Fri, 20 Sep 2013 14:57:06 +0200 Subject: [PATCH 063/200] - yweb: disable non-working rec on/off buttons --- src/nhttpd/web/Y_Tools_Boxcontrol.yhtm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nhttpd/web/Y_Tools_Boxcontrol.yhtm b/src/nhttpd/web/Y_Tools_Boxcontrol.yhtm index d4b1b6fec..1e98c9d64 100644 --- a/src/nhttpd/web/Y_Tools_Boxcontrol.yhtm +++ b/src/nhttpd/web/Y_Tools_Boxcontrol.yhtm @@ -45,8 +45,10 @@ function goUrl(_url){ +{=comment:disable non-working rec on/off buttons~ +=} From 740e7e8129b7bd038a33d5c4733e65b27c060dfd Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sat, 21 Sep 2013 00:22:10 +0200 Subject: [PATCH 064/200] CTestMenu: fix build of test menu, name of member was changed --- src/gui/test_menu.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/gui/test_menu.cpp b/src/gui/test_menu.cpp index ed8ec9228..9f1e5bea0 100644 --- a/src/gui/test_menu.cpp +++ b/src/gui/test_menu.cpp @@ -415,16 +415,14 @@ int CTestMenu::exec(CMenuTarget* parent, const std::string &actionKey) ptmp->setHeight(28); ptmp->setPictureAlign(CC_ALIGN_HOR_CENTER | CC_ALIGN_VER_CENTER); ptmp->setColorBody(COL_BLUE); - ptmp->setCornerRadius(RADIUS_MID); - ptmp->setCornerType(CORNER_TOP_LEFT); + ptmp->setCorner(RADIUS_MID, CORNER_TOP_LEFT); form->addCCItem(ptmp); CComponentsText *t1 = new CComponentsText(28, 0, 100, 28, "Text1", CTextBox::NO_AUTO_LINEBREAK); form->addCCItem(t1); CComponentsText *t2 = new CComponentsText(t1->getXPos()+t1->getWidth(), 0, 200, 50, "Text2", CTextBox::NO_AUTO_LINEBREAK | CTextBox::RIGHT); - t2->setCornerRadius(RADIUS_MID); - t2->setCornerType(CORNER_TOP_RIGHT); + t2->setCorner(RADIUS_MID, CORNER_TOP_RIGHT); form->addCCItem(t2); CComponentsShapeCircle *c1 = new CComponentsShapeCircle(28, 40, 28); From c06e0c4bb42473b77a86245210bb09d47bfe4c6f Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Tue, 24 Sep 2013 12:39:54 +0200 Subject: [PATCH 065/200] CControlAPI::_GetBouquetWriteItem: -fix UTF-8 (THX Gaucho316) http://www.dbox2world.net/index.php?page=Thread&postID=157423 --- src/nhttpd/tuxboxapi/coolstream/controlapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp index df5fe470d..c4193a5a6 100644 --- a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp +++ b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp @@ -910,7 +910,7 @@ std::string CControlAPI::_GetBouquetWriteItem(CyhookHandler *hh, CZapitChannel * result += hh->outPair("number", string_printf("%u", nr), true); result += hh->outPair("id", string_printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, channel->channel_id), true); result += hh->outPair("short_id", string_printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, channel->channel_id&0xFFFFFFFFFFFFULL), true); - result += hh->outPair("name", channel->getName(), true); + result += hh->outPair("name", hh->outValue(channel->getName()), true); result += hh->outPair("logo", hh->outValue(NeutrinoAPI->getLogoFile(hh->WebserverConfigList["Tuxbox.LogosURL"], channel->channel_id)), true); result += hh->outPair("bouquetnr", string_printf("%d", bouquetNr), isEPGdetails); if(isEPGdetails) From ba4298b119bc120aff45e997aa0caf9c25281da7 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Fri, 24 May 2013 16:57:16 +0200 Subject: [PATCH 066/200] zapit: fix ordering of cleanup stuff --- src/zapit/src/zapit.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/zapit/src/zapit.cpp b/src/zapit/src/zapit.cpp index c1e598d66..7becbd740 100644 --- a/src/zapit/src/zapit.cpp +++ b/src/zapit/src/zapit.cpp @@ -2434,13 +2434,6 @@ void CZapit::run() INFO("demuxes/decoders deleted"); - delete CFEManager::getInstance(); - INFO("frontend(s) deleted"); - if (ca) { - INFO("stopping CA"); - ca->Stop(); - delete ca; - } #ifdef EXIT_CLEANUP INFO("cleanup..."); delete eventServer; @@ -2448,6 +2441,13 @@ void CZapit::run() delete CServiceManager::getInstance(); delete CServiceScan::getInstance(); #endif + delete CFEManager::getInstance(); + INFO("frontend(s) deleted"); + if (ca) { + INFO("stopping CA"); + ca->Stop(); + delete ca; + } INFO("shutdown complete"); return; } From 8d52885a5ed94ec0cf8397b253909f47ee32816c Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Wed, 25 Sep 2013 15:15:31 +0400 Subject: [PATCH 067/200] gui/channellist.cpp: add menu option to reset all 'new' channels --- data/locale/english.locale | 1 + src/gui/channellist.cpp | 12 +++++++++++- src/system/locals.h | 1 + src/system/locals_intern.h | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/data/locale/english.locale b/data/locale/english.locale index a54f507f3..9751434b4 100644 --- a/data/locale/english.locale +++ b/data/locale/english.locale @@ -233,6 +233,7 @@ channellist.nonefound No channels were found!\nPlease execute a scan\n(MENU-key channellist.numeric_adjust Numeric zap adjust channellist.provs Providers channellist.recording_not_possible Recording not possible! +channellist.reset_all Reset 'new' flag for all channels channellist.reset_flags Reset 'new' channel flag channellist.sats Satellites channellist.since since diff --git a/src/gui/channellist.cpp b/src/gui/channellist.cpp index 318eb26b3..dddbb7eac 100644 --- a/src/gui/channellist.cpp +++ b/src/gui/channellist.cpp @@ -367,6 +367,9 @@ int CChannelList::doChannelMenu(void) bool reset_enabled = chanlist[selected]->flags & CZapitChannel::NEW; menu->addItem(new CMenuForwarder(LOCALE_CHANNELLIST_RESET_FLAGS, reset_enabled, NULL, selector, cnt, CRCInput::convertDigitToKey(shortcut++)), old_selected == i++); snprintf(cnt, sizeof(cnt), "%d", i); + bool reset_all = (name == g_Locale->getText(LOCALE_BOUQUETNAME_NEW)); + menu->addItem(new CMenuForwarder(LOCALE_CHANNELLIST_RESET_ALL, reset_all, NULL, selector, cnt, CRCInput::convertDigitToKey(shortcut++)), old_selected == i++); + snprintf(cnt, sizeof(cnt), "%d", i); menu->addItem(new CMenuSeparator(CMenuSeparator::LINE)); menu->addItem(new CMenuForwarder(LOCALE_MAINMENU_SETTINGS, true, NULL, selector, cnt, CRCInput::convertDigitToKey(shortcut++)), old_selected == i++); menu->exec(NULL, ""); @@ -478,7 +481,14 @@ int CChannelList::doChannelMenu(void) if(g_settings.make_new_list) return 2; break; - case 5: // settings + case 5: // reset all new + for (unsigned int j = 0 ; j < chanlist.size(); j++) { + chanlist[j]->flags &= ~CZapitChannel::NEW; + } + if (g_settings.make_new_list) + return 2; + break; + case 6: // settings { previous_channellist_additional = g_settings.channellist_additional; COsdSetup osd_setup; diff --git a/src/system/locals.h b/src/system/locals.h index cc038bc92..882c15450 100644 --- a/src/system/locals.h +++ b/src/system/locals.h @@ -260,6 +260,7 @@ typedef enum LOCALE_CHANNELLIST_NUMERIC_ADJUST, LOCALE_CHANNELLIST_PROVS, LOCALE_CHANNELLIST_RECORDING_NOT_POSSIBLE, + LOCALE_CHANNELLIST_RESET_ALL, LOCALE_CHANNELLIST_RESET_FLAGS, LOCALE_CHANNELLIST_SATS, LOCALE_CHANNELLIST_SINCE, diff --git a/src/system/locals_intern.h b/src/system/locals_intern.h index 477b78084..e4ff3dd93 100644 --- a/src/system/locals_intern.h +++ b/src/system/locals_intern.h @@ -260,6 +260,7 @@ const char * locale_real_names[] = "channellist.numeric_adjust", "channellist.provs", "channellist.recording_not_possible", + "channellist.reset_all", "channellist.reset_flags", "channellist.sats", "channellist.since", From 1d63e4048e93511e365d53f1fd225b3a4049dabf Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Wed, 25 Sep 2013 15:44:18 +0400 Subject: [PATCH 068/200] src/gui/bouquetlist.cpp: do not add dublicate channels while copy bouquet to favorite, if favorite bouquet already exist --- src/gui/bouquetlist.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/gui/bouquetlist.cpp b/src/gui/bouquetlist.cpp index 5c47e3e4e..c3edab5a6 100644 --- a/src/gui/bouquetlist.cpp +++ b/src/gui/bouquetlist.cpp @@ -243,6 +243,7 @@ int CBouquetList::doMenu() delete menu; delete selector; printf("CBouquetList::doMenu: %d selected\n", select); + bool added = false; if(select >= 0) { old_selected = select; switch(select) { @@ -251,16 +252,28 @@ int CBouquetList::doMenu() bouquet_id = g_bouquetManager->existsUBouquet(Bouquets[selected]->channelList->getName()); if(bouquet_id < 0) { tmp = g_bouquetManager->addBouquet(Bouquets[selected]->channelList->getName(), true); + bouquet_id = g_bouquetManager->existsUBouquet(Bouquets[selected]->channelList->getName()); } else tmp = g_bouquetManager->Bouquets[bouquet_id]; + if(bouquet_id < 0) + return -1; + channels = &zapitBouquet->tvChannels; - for(int li = 0; li < (int) channels->size(); li++) - tmp->addService((*channels)[li]); + for(int li = 0; li < (int) channels->size(); li++) { + if (!g_bouquetManager->existsChannelInBouquet(bouquet_id, ((*channels)[li])->getChannelID())) { + added = true; + tmp->addService((*channels)[li]); + } + } channels = &zapitBouquet->radioChannels; - for(int li = 0; li < (int) channels->size(); li++) - tmp->addService((*channels)[li]); - return 1; + for(int li = 0; li < (int) channels->size(); li++) { + if (!g_bouquetManager->existsChannelInBouquet(bouquet_id, ((*channels)[li])->getChannelID())) { + added = true; + tmp->addService((*channels)[li]); + } + } + return added ? 1 : -1; break; default: break; From a2d5ccdce21f24c318fa256854c33e7bb500e507 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Wed, 25 Sep 2013 16:24:46 +0400 Subject: [PATCH 069/200] nhttpd/tuxboxapi/coolstream/neutrinoapi.cpp: fix memleak in GetChannelEvents() --- src/nhttpd/tuxboxapi/coolstream/neutrinoapi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nhttpd/tuxboxapi/coolstream/neutrinoapi.cpp b/src/nhttpd/tuxboxapi/coolstream/neutrinoapi.cpp index 65b433331..6ed67da7b 100644 --- a/src/nhttpd/tuxboxapi/coolstream/neutrinoapi.cpp +++ b/src/nhttpd/tuxboxapi/coolstream/neutrinoapi.cpp @@ -258,6 +258,7 @@ bool CNeutrinoAPI::GetStreamInfo(int bitInfo[10]) bool CNeutrinoAPI::GetChannelEvents(void) { + eList.clear(); CEitManager::getInstance()->getChannelEvents(eList); CChannelEventList::iterator eventIterator; From 173403120f9f9c00e781cdbd956ca4de77429046 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Thu, 26 Sep 2013 19:46:25 +0400 Subject: [PATCH 070/200] gui/channellist.cpp: fix reset 'new' channel flag --- src/gui/channellist.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/channellist.cpp b/src/gui/channellist.cpp index dddbb7eac..ae7d80086 100644 --- a/src/gui/channellist.cpp +++ b/src/gui/channellist.cpp @@ -475,7 +475,7 @@ int CChannelList::doChannelMenu(void) break; case 4: // reset new - chanlist[selected]->flags &= ~CZapitChannel::NEW; + chanlist[selected]->flags = CZapitChannel::UPDATED; CServiceManager::getInstance()->SetServicesChanged(true); /* if make_new_list == ON, signal to re-init services */ if(g_settings.make_new_list) @@ -483,7 +483,7 @@ int CChannelList::doChannelMenu(void) break; case 5: // reset all new for (unsigned int j = 0 ; j < chanlist.size(); j++) { - chanlist[j]->flags &= ~CZapitChannel::NEW; + chanlist[j]->flags = CZapitChannel::UPDATED; } if (g_settings.make_new_list) return 2; From 76d2cc17fb121bf3ad3a8dee721bb5cfde208901 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Wed, 25 Sep 2013 15:32:42 +0200 Subject: [PATCH 071/200] Update deutsch.locale --- data/locale/deutsch.locale | 1 + 1 file changed, 1 insertion(+) diff --git a/data/locale/deutsch.locale b/data/locale/deutsch.locale index 31e1b3548..8415ce25b 100644 --- a/data/locale/deutsch.locale +++ b/data/locale/deutsch.locale @@ -233,6 +233,7 @@ channellist.nonefound Es wurden keine Kanäle gefunden!\nFühren Sie bitte eine channellist.numeric_adjust Numeric zap adjust channellist.provs Anbieter channellist.recording_not_possible Aufnahme nicht möglich! +channellist.reset_all Entferne Markierung "Neu" für alle Kanäle channellist.reset_flags Entferne Kanal-Markierung "Neu" channellist.sats Satelliten channellist.since seit From 40dc93d9e8716e9c3aa553e473704954d3852729 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Thu, 29 Aug 2013 14:22:38 +0200 Subject: [PATCH 072/200] Neutrino build: Fix build with '--with-tremor-static' --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index f73ed0665..33af31d06 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,7 +31,7 @@ INCLUDES += -I$(top_srcdir)/lib/libtriple endif if USE_TREMOR -VORBISLIBS = @VORBISIDEC_LIBS@ +VORBISLIBS = @VORBISIDEC_LIBS@ -logg else VORBISLIBS = -lvorbisfile -lvorbis -logg endif From 720f52c0a0b5ccda24a5cee52f22da23119fdaca Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Thu, 26 Sep 2013 02:50:48 +0200 Subject: [PATCH 073/200] CFlashExpert: Add return value to showMTDSelector() & showFileSelector() --- src/gui/update.cpp | 23 ++++++++++++----------- src/gui/update.h | 4 ++-- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/gui/update.cpp b/src/gui/update.cpp index d4d63a9da..c286283b9 100644 --- a/src/gui/update.cpp +++ b/src/gui/update.cpp @@ -664,7 +664,7 @@ void CFlashExpert::writemtd(const std::string & filename, int mtdNumber) } } -void CFlashExpert::showMTDSelector(const std::string & actionkey) +int CFlashExpert::showMTDSelector(const std::string & actionkey) { int shortcut = 0; @@ -698,11 +698,12 @@ void CFlashExpert::showMTDSelector(const std::string & actionkey) if (actionkey == "writemtd") mtdselector->addItem(new CMenuForwarderNonLocalized("systemFS with settings", true, NULL, this, "writemtd10", CRCInput::convertDigitToKey(shortcut++))); #endif - mtdselector->exec(NULL,""); + int res = mtdselector->exec(NULL,""); delete mtdselector; + return res; } -void CFlashExpert::showFileSelector(const std::string & actionkey) +int CFlashExpert::showFileSelector(const std::string & actionkey) { CMenuWidget* fileselector = new CMenuWidget(LOCALE_SERVICEMENU_UPDATE, NEUTRINO_ICON_UPDATE, width, MN_WIDGET_ID_FILESELECTOR); fileselector->addIntroItems(LOCALE_FLASHUPDATE_FILESELECTOR, NONEXISTANT_LOCALE, CMenuWidget::BTN_TYPE_CANCEL); @@ -729,12 +730,14 @@ void CFlashExpert::showFileSelector(const std::string & actionkey) } free(namelist); } - fileselector->exec(NULL,""); + int res = fileselector->exec(NULL,""); delete fileselector; + return res; } int CFlashExpert::exec(CMenuTarget* parent, const std::string & actionKey) { + int res = menu_return::RETURN_REPAINT; if(parent) parent->hide(); @@ -742,13 +745,13 @@ int CFlashExpert::exec(CMenuTarget* parent, const std::string & actionKey) readmtd(-1); } else if(actionKey=="writeflash") { - showFileSelector(""); + res = showFileSelector(""); } else if(actionKey=="readflashmtd") { - showMTDSelector("readmtd"); + res = showMTDSelector("readmtd"); } else if(actionKey=="writeflashmtd") { - showMTDSelector("writemtd"); + res = showMTDSelector("writemtd"); } else { int iReadmtd = -1; @@ -774,10 +777,8 @@ int CFlashExpert::exec(CMenuTarget* parent, const std::string & actionKey) selectedMTD=-1; } } - hide(); - return menu_return::RETURN_EXIT_ALL; + res = menu_return::RETURN_REPAINT; } - hide(); - return menu_return::RETURN_REPAINT; + return res; } diff --git a/src/gui/update.h b/src/gui/update.h index ae9e436d5..1992b6aca 100644 --- a/src/gui/update.h +++ b/src/gui/update.h @@ -72,8 +72,8 @@ class CFlashExpert : public CProgressWindow int selectedMTD; int width; - void showMTDSelector(const std::string & actionkey); - void showFileSelector(const std::string & actionkey); + int showMTDSelector(const std::string & actionkey); + int showFileSelector(const std::string & actionkey); bool checkSize(int mtd, std::string &backupFile); void readmtd(int readmtd); From d8957d17acb21cdce8b67baa826a0d9125fd9963 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Sun, 1 Sep 2013 17:57:41 +0200 Subject: [PATCH 074/200] src/system/mtdutils: Add files from mtd-utils - based on mtd-utils http://git.infradead.org/mtd-utils.git commit ab8c6fb93ce9db0f09401c4b819b0b277dc00340 (2013-07-01) - Add files for create jffs2 image and using sumtool - Creating classes for mkfs.jffs2 and sumtool --- src/system/mtdutils/COPYING | 340 +++++ src/system/mtdutils/compr.cpp | 538 +++++++ src/system/mtdutils/compr.h | 119 ++ src/system/mtdutils/compr_lzo.cpp | 137 ++ src/system/mtdutils/compr_rtime.cpp | 124 ++ src/system/mtdutils/compr_zlib.cpp | 154 ++ src/system/mtdutils/include/common.h | 149 ++ src/system/mtdutils/include/crc32.h | 13 + src/system/mtdutils/include/libmtd.h | 352 +++++ src/system/mtdutils/include/linux/jffs2.h | 218 +++ src/system/mtdutils/include/mtd/ftl-user.h | 76 + src/system/mtdutils/include/mtd/inftl-user.h | 89 ++ src/system/mtdutils/include/mtd/jffs2-user.h | 82 + src/system/mtdutils/include/mtd/mtd-abi.h | 277 ++++ src/system/mtdutils/include/mtd/mtd-user.h | 34 + src/system/mtdutils/include/mtd/nftl-user.h | 76 + src/system/mtdutils/include/mtd/ubi-media.h | 378 +++++ src/system/mtdutils/include/mtd/ubi-user.h | 418 ++++++ src/system/mtdutils/include/mtd_swab.h | 51 + src/system/mtdutils/include/xalloc.h | 106 ++ src/system/mtdutils/lib/libcrc32.cpp | 104 ++ src/system/mtdutils/lib/libfec.cpp | 903 +++++++++++ src/system/mtdutils/lib/libmtd.cpp | 1419 ++++++++++++++++++ src/system/mtdutils/lib/libmtd_int.h | 107 ++ src/system/mtdutils/lib/libmtd_legacy.cpp | 379 +++++ src/system/mtdutils/mcast_image.h | 54 + src/system/mtdutils/mkfs.jffs2.cpp | 1266 ++++++++++++++++ src/system/mtdutils/mkfs.jffs2.h | 118 ++ src/system/mtdutils/rbtree.cpp | 390 +++++ src/system/mtdutils/rbtree.h | 171 +++ src/system/mtdutils/summary.h | 177 +++ src/system/mtdutils/sumtool.cpp | 766 ++++++++++ src/system/mtdutils/sumtool.h | 87 ++ 33 files changed, 9672 insertions(+) create mode 100644 src/system/mtdutils/COPYING create mode 100644 src/system/mtdutils/compr.cpp create mode 100644 src/system/mtdutils/compr.h create mode 100644 src/system/mtdutils/compr_lzo.cpp create mode 100644 src/system/mtdutils/compr_rtime.cpp create mode 100644 src/system/mtdutils/compr_zlib.cpp create mode 100644 src/system/mtdutils/include/common.h create mode 100644 src/system/mtdutils/include/crc32.h create mode 100644 src/system/mtdutils/include/libmtd.h create mode 100644 src/system/mtdutils/include/linux/jffs2.h create mode 100644 src/system/mtdutils/include/mtd/ftl-user.h create mode 100644 src/system/mtdutils/include/mtd/inftl-user.h create mode 100644 src/system/mtdutils/include/mtd/jffs2-user.h create mode 100644 src/system/mtdutils/include/mtd/mtd-abi.h create mode 100644 src/system/mtdutils/include/mtd/mtd-user.h create mode 100644 src/system/mtdutils/include/mtd/nftl-user.h create mode 100644 src/system/mtdutils/include/mtd/ubi-media.h create mode 100644 src/system/mtdutils/include/mtd/ubi-user.h create mode 100644 src/system/mtdutils/include/mtd_swab.h create mode 100644 src/system/mtdutils/include/xalloc.h create mode 100644 src/system/mtdutils/lib/libcrc32.cpp create mode 100644 src/system/mtdutils/lib/libfec.cpp create mode 100644 src/system/mtdutils/lib/libmtd.cpp create mode 100644 src/system/mtdutils/lib/libmtd_int.h create mode 100644 src/system/mtdutils/lib/libmtd_legacy.cpp create mode 100644 src/system/mtdutils/mcast_image.h create mode 100644 src/system/mtdutils/mkfs.jffs2.cpp create mode 100644 src/system/mtdutils/mkfs.jffs2.h create mode 100644 src/system/mtdutils/rbtree.cpp create mode 100644 src/system/mtdutils/rbtree.h create mode 100644 src/system/mtdutils/summary.h create mode 100644 src/system/mtdutils/sumtool.cpp create mode 100644 src/system/mtdutils/sumtool.h diff --git a/src/system/mtdutils/COPYING b/src/system/mtdutils/COPYING new file mode 100644 index 000000000..60549be51 --- /dev/null +++ b/src/system/mtdutils/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/system/mtdutils/compr.cpp b/src/system/mtdutils/compr.cpp new file mode 100644 index 000000000..898d550b6 --- /dev/null +++ b/src/system/mtdutils/compr.cpp @@ -0,0 +1,538 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2004 Ferenc Havasi , + * University of Szeged, Hungary + * + * For licensing information, see the file 'LICENCE' in this directory + * in the jffs2 directory. + */ + +#include "compr.h" +#include +#include +#include + +#define FAVOUR_LZO_PERCENT 80 + +extern int page_size; + +/* LIST IMPLEMENTATION (from linux/list.h) */ + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void __list_add(struct list_head *new_, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new_; + new_->next = next; + new_->prev = prev; + prev->next = new_; +} + +static inline void list_add(struct list_head *new_, struct list_head *head) +{ + __list_add(new_, head, head->next); +} + +static inline void list_add_tail(struct list_head *new_, struct list_head *head) +{ + __list_add(new_, head->prev, head); +} + +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = NULL; + entry->prev = NULL; +} + +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + + +/* Available compressors are on this_ list */ +static LIST_HEAD(jffs2_compressor_list); + +/* Actual compression mode */ +static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; + +void jffs2_set_compression_mode(int mode) +{ + jffs2_compression_mode = mode; +} + +int jffs2_get_compression_mode(void) +{ + return jffs2_compression_mode; +} + +/* Statistics for blocks stored without compression */ +static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0; + +/* Compression test stuffs */ + +static int jffs2_compression_check = 0; + +static unsigned char *jffs2_compression_check_buf = NULL; + +void jffs2_compression_check_set(int yesno) +{ + jffs2_compression_check = yesno; +} + +int jffs2_compression_check_get(void) +{ + return jffs2_compression_check; +} + +static int jffs2_error_cnt = 0; + +int jffs2_compression_check_errorcnt_get(void) +{ + return jffs2_error_cnt; +} + +#define JFFS2_BUFFER_FILL 0x55 + +/* Called before compression (if compression_check is setted) to prepare + the buffer for buffer overflow test */ +static void jffs2_decompression_test_prepare(unsigned char *buf, int size) +{ + memset(buf,JFFS2_BUFFER_FILL,size+1); +} + +/* Called after compression (if compression_check is setted) to test the result */ +static void jffs2_decompression_test(struct jffs2_compressor *compr, + unsigned char *data_in, unsigned char *output_buf, + uint32_t cdatalen, uint32_t datalen, uint32_t buf_size) +{ + uint32_t i; + + /* buffer overflow test */ + for (i=buf_size;i>cdatalen;i--) { + if (output_buf[i]!=JFFS2_BUFFER_FILL) { + fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. " + "(bs=%d csize=%d b[%d]=%d)\n", compr->name, + buf_size, cdatalen, i, (int)(output_buf[i])); + jffs2_error_cnt++; + return; + } + } + /* allocing temporary buffer for decompression */ + if (!jffs2_compression_check_buf) { + jffs2_compression_check_buf = (unsigned char*)malloc(page_size); + if (!jffs2_compression_check_buf) { + fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n"); + jffs2_compression_check = 0; + return; + } + } + /* decompressing */ + if (!compr->decompress) { + fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name); + jffs2_error_cnt++; + return; + } + if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen)) { + fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name); + jffs2_error_cnt++; + } + /* validate decompression */ + else { + for (i=0;iname, i); + jffs2_error_cnt++; + break; + } + } + } +} + +/* + * Return 1 to use this_ compression + */ +static int jffs2_is_best_compression(struct jffs2_compressor *this_, + struct jffs2_compressor *best, uint32_t size, uint32_t bestsize) +{ + switch (jffs2_compression_mode) { + case JFFS2_COMPR_MODE_SIZE: + if (bestsize > size) + return 1; + return 0; + case JFFS2_COMPR_MODE_FAVOURLZO: + if ((this_->compr == JFFS2_COMPR_LZO) && (bestsize > size)) + return 1; + if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size)) + return 1; + if ((this_->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100))) + return 1; + if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size) + return 1; + + return 0; + } + /* Shouldn't happen */ + return 0; +} + +/* jffs2_compress: + * @data: Pointer to uncompressed data + * @cdata: Pointer to returned pointer to buffer for compressed data + * @datalen: On entry, holds the amount of data available for compression. + * On exit, expected to hold the amount of data actually compressed. + * @cdatalen: On entry, holds the amount of space available for compressed + * data. On exit, expected to hold the actual size of the compressed + * data. + * + * Returns: Lower byte to be stored with data indicating compression type used. + * Zero is used to show that the data could not be compressed - the + * compressed version was actually larger than the original. + * Upper byte will be used later. (soon) + * + * If the cdata buffer isn't large enough to hold all the uncompressed data, + * jffs2_compress should compress as much as will fit, and should set + * *datalen accordingly to show the amount of data which were compressed. + */ +uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out, + uint32_t *datalen, uint32_t *cdatalen) +{ + int ret = JFFS2_COMPR_NONE; + int compr_ret; + struct jffs2_compressor *this_, *best=NULL; + unsigned char *output_buf = NULL, *tmp_buf; + uint32_t orig_slen, orig_dlen; + uint32_t best_slen=0, best_dlen=0; + + switch (jffs2_compression_mode) { + case JFFS2_COMPR_MODE_NONE: + break; + case JFFS2_COMPR_MODE_PRIORITY: + orig_slen = *datalen; + orig_dlen = *cdatalen; + output_buf = (unsigned char*)malloc(orig_dlen+jffs2_compression_check); + if (!output_buf) { + fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n"); + goto out; + } + list_for_each_entry(this_, &jffs2_compressor_list, list) { + /* Skip decompress-only backwards-compatibility and disabled modules */ + if ((!this_->compress)||(this_->disabled)) + continue; + + this_->usecount++; + + if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ + jffs2_decompression_test_prepare(output_buf, orig_dlen); + + *datalen = orig_slen; + *cdatalen = orig_dlen; + compr_ret = this_->compress(data_in, output_buf, datalen, cdatalen); + this_->usecount--; + if (!compr_ret) { + ret = this_->compr; + this_->stat_compr_blocks++; + this_->stat_compr_orig_size += *datalen; + this_->stat_compr_new_size += *cdatalen; + if (jffs2_compression_check) + jffs2_decompression_test(this_, data_in, output_buf, *cdatalen, *datalen, orig_dlen); + break; + } + } + if (ret == JFFS2_COMPR_NONE) free(output_buf); + break; + case JFFS2_COMPR_MODE_FAVOURLZO: + case JFFS2_COMPR_MODE_SIZE: + orig_slen = *datalen; + orig_dlen = *cdatalen; + list_for_each_entry(this_, &jffs2_compressor_list, list) { + uint32_t needed_buf_size; + + if (jffs2_compression_mode == JFFS2_COMPR_MODE_FAVOURLZO) + needed_buf_size = orig_slen + jffs2_compression_check; + else + needed_buf_size = orig_dlen + jffs2_compression_check; + + /* Skip decompress-only backwards-compatibility and disabled modules */ + if ((!this_->compress)||(this_->disabled)) + continue; + /* Allocating memory for output buffer if necessary */ + if ((this_->compr_buf_size < needed_buf_size) && (this_->compr_buf)) { + free(this_->compr_buf); + this_->compr_buf_size=0; + this_->compr_buf=NULL; + } + if (!this_->compr_buf) { + tmp_buf = (unsigned char*)malloc(needed_buf_size); + if (!tmp_buf) { + fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. (%d bytes)\n",orig_dlen); + continue; + } + else { + this_->compr_buf = tmp_buf; + this_->compr_buf_size = orig_dlen; + } + } + this_->usecount++; + if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ + jffs2_decompression_test_prepare(this_->compr_buf,this_->compr_buf_size); + *datalen = orig_slen; + *cdatalen = orig_dlen; + compr_ret = this_->compress(data_in, this_->compr_buf, datalen, cdatalen); + this_->usecount--; + if (!compr_ret) { + if (jffs2_compression_check) + jffs2_decompression_test(this_, data_in, this_->compr_buf, *cdatalen, *datalen, this_->compr_buf_size); + if (((!best_dlen) || jffs2_is_best_compression(this_, best, *cdatalen, best_dlen)) + && (*cdatalen < *datalen)) { + best_dlen = *cdatalen; + best_slen = *datalen; + best = this_; + } + } + } + if (best_dlen) { + *cdatalen = best_dlen; + *datalen = best_slen; + output_buf = best->compr_buf; + best->compr_buf = NULL; + best->compr_buf_size = 0; + best->stat_compr_blocks++; + best->stat_compr_orig_size += best_slen; + best->stat_compr_new_size += best_dlen; + ret = best->compr; + } + break; + default: + fprintf(stderr,"mkfs.jffs2: unknown compression mode.\n"); + } +out: + if (ret == JFFS2_COMPR_NONE) { + *cpage_out = data_in; + *datalen = *cdatalen; + none_stat_compr_blocks++; + none_stat_compr_size += *datalen; + } + else { + *cpage_out = output_buf; + } + return ret; +} + + +int jffs2_register_compressor(struct jffs2_compressor *comp) +{ + struct jffs2_compressor *this_; + + if (!comp->name) { + fprintf(stderr,"NULL compressor name at registering JFFS2 compressor. Failed.\n"); + return -1; + } + comp->compr_buf_size=0; + comp->compr_buf=NULL; + comp->usecount=0; + comp->stat_compr_orig_size=0; + comp->stat_compr_new_size=0; + comp->stat_compr_blocks=0; + comp->stat_decompr_blocks=0; + + list_for_each_entry(this_, &jffs2_compressor_list, list) { + if (this_->priority < comp->priority) { + list_add(&comp->list, this_->list.prev); + goto out; + } + } + list_add_tail(&comp->list, &jffs2_compressor_list); +out: + return 0; +} + +int jffs2_unregister_compressor(struct jffs2_compressor *comp) +{ + + if (comp->usecount) { + fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n"); + return -1; + } + list_del(&comp->list); + + return 0; +} + +#define JFFS2_STAT_BUF_SIZE 16000 + +char *jffs2_list_compressors(void) +{ + struct jffs2_compressor *this_; + char *buf, *act_buf; + + act_buf = buf = (char*)malloc(JFFS2_STAT_BUF_SIZE); + list_for_each_entry(this_, &jffs2_compressor_list, list) { + act_buf += sprintf(act_buf, "%10s priority:%d ", this_->name, this_->priority); + if ((this_->disabled)||(!this_->compress)) + act_buf += sprintf(act_buf,"disabled"); + else + act_buf += sprintf(act_buf,"enabled"); + act_buf += sprintf(act_buf,"\n"); + } + return buf; +} + +char *jffs2_stats(void) +{ + struct jffs2_compressor *this_; + char *buf, *act_buf; + + act_buf = buf = (char*)malloc(JFFS2_STAT_BUF_SIZE); + + act_buf += sprintf(act_buf,"Compression mode: "); + switch (jffs2_compression_mode) { + case JFFS2_COMPR_MODE_NONE: + act_buf += sprintf(act_buf,"none"); + break; + case JFFS2_COMPR_MODE_PRIORITY: + act_buf += sprintf(act_buf,"priority"); + break; + case JFFS2_COMPR_MODE_SIZE: + act_buf += sprintf(act_buf,"size"); + break; + case JFFS2_COMPR_MODE_FAVOURLZO: + act_buf += sprintf(act_buf, "favourlzo"); + break; + default: + act_buf += sprintf(act_buf, "unknown"); + break; + } + act_buf += sprintf(act_buf,"\nCompressors:\n"); + act_buf += sprintf(act_buf,"%10s ","none"); + act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks, + none_stat_compr_size, none_stat_decompr_blocks); + list_for_each_entry(this_, &jffs2_compressor_list, list) { + act_buf += sprintf(act_buf,"%10s (prio:%d) ",this_->name,this_->priority); + if ((this_->disabled)||(!this_->compress)) + act_buf += sprintf(act_buf,"- "); + else + act_buf += sprintf(act_buf,"+ "); + act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this_->stat_compr_blocks, + this_->stat_compr_new_size, this_->stat_compr_orig_size, + this_->stat_decompr_blocks); + act_buf += sprintf(act_buf,"\n"); + } + return buf; +} + +int jffs2_set_compression_mode_name(const char *name) +{ + if (!strcmp("none",name)) { + jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; + return 0; + } + if (!strcmp("priority",name)) { + jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; + return 0; + } + if (!strcmp("size",name)) { + jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; + return 0; + } + if (!strcmp("favourlzo", name)) { + jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO; + return 0; + } + + return 1; +} + +static int jffs2_compressor_Xable(const char *name, int disabled) +{ + struct jffs2_compressor *this_; + list_for_each_entry(this_, &jffs2_compressor_list, list) { + if (!strcmp(this_->name, name)) { + this_->disabled = disabled; + return 0; + } + } + return 1; +} + +int jffs2_enable_compressor_name(const char *name) +{ + return jffs2_compressor_Xable(name, 0); +} + +int jffs2_disable_compressor_name(const char *name) +{ + return jffs2_compressor_Xable(name, 1); +} + +int jffs2_set_compressor_priority(const char *name, int priority) +{ + struct jffs2_compressor *this_,*comp; + list_for_each_entry(this_, &jffs2_compressor_list, list) { + if (!strcmp(this_->name, name)) { + this_->priority = priority; + comp = this_; + goto reinsert; + } + } + fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name); + return 1; +reinsert: + /* list is sorted in the order of priority, so if + we change it we have to reinsert it into the + good place */ + list_del(&comp->list); + list_for_each_entry(this_, &jffs2_compressor_list, list) { + if (this_->priority < comp->priority) { + list_add(&comp->list, this_->list.prev); + return 0; + } + } + list_add_tail(&comp->list, &jffs2_compressor_list); + return 0; +} + + +int jffs2_compressors_init(void) +{ +#ifdef CONFIG_JFFS2_ZLIB + jffs2_zlib_init(); +#endif +#ifdef CONFIG_JFFS2_RTIME + jffs2_rtime_init(); +#endif +#ifdef CONFIG_JFFS2_LZO + jffs2_lzo_init(); +#endif + return 0; +} + +int jffs2_compressors_exit(void) +{ +#ifdef CONFIG_JFFS2_RTIME + jffs2_rtime_exit(); +#endif +#ifdef CONFIG_JFFS2_ZLIB + jffs2_zlib_exit(); +#endif +#ifdef CONFIG_JFFS2_LZO + jffs2_lzo_exit(); +#endif + return 0; +} diff --git a/src/system/mtdutils/compr.h b/src/system/mtdutils/compr.h new file mode 100644 index 000000000..a21e9351b --- /dev/null +++ b/src/system/mtdutils/compr.h @@ -0,0 +1,119 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2004 Ferenc Havasi , + * University of Szeged, Hungary + * + * For licensing information, see the file 'LICENCE' in the + * jffs2 directory. + */ + +#ifndef __JFFS2_COMPR_H__ +#define __JFFS2_COMPR_H__ + +#include +#include +#include +#include "linux/jffs2.h" + +#define CONFIG_JFFS2_ZLIB +#define CONFIG_JFFS2_RTIME +#define CONFIG_JFFS2_LZO + +#define JFFS2_RUBINMIPS_PRIORITY 10 +#define JFFS2_DYNRUBIN_PRIORITY 20 +#define JFFS2_RTIME_PRIORITY 50 +#define JFFS2_ZLIB_PRIORITY 60 +#define JFFS2_LZO_PRIORITY 80 + +#define JFFS2_COMPR_MODE_NONE 0 +#define JFFS2_COMPR_MODE_PRIORITY 1 +#define JFFS2_COMPR_MODE_SIZE 2 +#define JFFS2_COMPR_MODE_FAVOURLZO 3 + +#define kmalloc(a,b) malloc(a) +#define kfree(a) free(a) +#ifndef GFP_KERNEL +#define GFP_KERNEL 0 +#endif + +#define vmalloc(a) malloc(a) +#define vfree(a) free(a) + +#define printk(...) fprintf(stderr,__VA_ARGS__) + +#define KERN_EMERG +#define KERN_ALERT +#define KERN_CRIT +#define KERN_ERR +#define KERN_WARNING +#define KERN_NOTICE +#define KERN_INFO +#define KERN_DEBUG + +struct list_head { + struct list_head *next, *prev; +}; + +void jffs2_set_compression_mode(int mode); +int jffs2_get_compression_mode(void); +int jffs2_set_compression_mode_name(const char *mode_name); + +int jffs2_enable_compressor_name(const char *name); +int jffs2_disable_compressor_name(const char *name); + +int jffs2_set_compressor_priority(const char *name, int priority); + +struct jffs2_compressor { + struct list_head list; + int priority; /* used by prirority comr. mode */ + const char *name; + char compr; /* JFFS2_COMPR_XXX */ + int (*compress)(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *srclen, uint32_t *destlen); + int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, + uint32_t cdatalen, uint32_t datalen); + int usecount; + int disabled; /* if seted the compressor won't compress */ + unsigned char *compr_buf; /* used by size compr. mode */ + uint32_t compr_buf_size; /* used by size compr. mode */ + uint32_t stat_compr_orig_size; + uint32_t stat_compr_new_size; + uint32_t stat_compr_blocks; + uint32_t stat_decompr_blocks; +}; + +int jffs2_register_compressor(struct jffs2_compressor *comp); +int jffs2_unregister_compressor(struct jffs2_compressor *comp); + +int jffs2_compressors_init(void); +int jffs2_compressors_exit(void); + +uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out, + uint32_t *datalen, uint32_t *cdatalen); + +/* If it is setted, a decompress will be called after every compress */ +void jffs2_compression_check_set(int yesno); +int jffs2_compression_check_get(void); +int jffs2_compression_check_errorcnt_get(void); + +char *jffs2_list_compressors(void); +char *jffs2_stats(void); + +/* Compressor modules */ + +/* These functions will be called by jffs2_compressors_init/exit */ +#ifdef CONFIG_JFFS2_ZLIB +int jffs2_zlib_init(void); +void jffs2_zlib_exit(void); +#endif +#ifdef CONFIG_JFFS2_RTIME +int jffs2_rtime_init(void); +void jffs2_rtime_exit(void); +#endif +#ifdef CONFIG_JFFS2_LZO +int jffs2_lzo_init(void); +void jffs2_lzo_exit(void); +#endif + +#endif /* __JFFS2_COMPR_H__ */ diff --git a/src/system/mtdutils/compr_lzo.cpp b/src/system/mtdutils/compr_lzo.cpp new file mode 100644 index 000000000..72495d235 --- /dev/null +++ b/src/system/mtdutils/compr_lzo.cpp @@ -0,0 +1,137 @@ +/* + * JFFS2 LZO Compression Interface. + * + * Copyright (C) 2007 Nokia Corporation. All rights reserved. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#define WITHOUT_LZO + +#include +#include +#include + +#ifndef WITHOUT_LZO +#include +#include +#include +#include "compr.h" + +extern int page_size; + +static void *lzo_mem; +static void *lzo_compress_buf; + +/* + * Note about LZO compression. + * + * We want to use the _999_ compression routine which gives better compression + * rates at the expense of time. Decompression time is unaffected. We might as + * well use the standard lzo library routines for this but they will overflow + * the destination buffer since they don't check the destination size. + * + * We therefore compress to a temporary buffer and copy if it will fit. + * + */ +static int jffs2_lzo_cmpr(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *sourcelen, uint32_t *dstlen) +{ + lzo_uint compress_size; + int ret; + + ret = lzo1x_999_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); + + if (ret != LZO_E_OK) + return -1; + + if (compress_size > *dstlen) + return -1; + + memcpy(cpage_out, lzo_compress_buf, compress_size); + *dstlen = compress_size; + + return 0; +} + +static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t srclen, uint32_t destlen) +{ + int ret; + lzo_uint dl; + + ret = lzo1x_decompress_safe(data_in,srclen,cpage_out,&dl,NULL); + + if (ret != LZO_E_OK || dl != destlen) + return -1; + + return 0; +} + +static struct jffs2_compressor jffs2_lzo_comp = { + .priority = JFFS2_LZO_PRIORITY, + .name = "lzo", + .compr = JFFS2_COMPR_LZO, + .compress = &jffs2_lzo_cmpr, + .decompress = &jffs2_lzo_decompress, + .disabled = 1, +}; + +int jffs2_lzo_init(void) +{ + int ret; + + lzo_mem = malloc(LZO1X_999_MEM_COMPRESS); + if (!lzo_mem) + return -1; + + /* Worse case LZO compression size from their FAQ */ + lzo_compress_buf = malloc(page_size + (page_size / 16) + 64 + 3); + if (!lzo_compress_buf) { + free(lzo_mem); + return -1; + } + + ret = jffs2_register_compressor(&jffs2_lzo_comp); + if (ret < 0) { + free(lzo_compress_buf); + free(lzo_mem); + } + + return ret; +} + +void jffs2_lzo_exit(void) +{ + jffs2_unregister_compressor(&jffs2_lzo_comp); + free(lzo_compress_buf); + free(lzo_mem); +} + +#else + +int jffs2_lzo_init(void) +{ + return 0; +} + +void jffs2_lzo_exit(void) +{ +} + +#endif diff --git a/src/system/mtdutils/compr_rtime.cpp b/src/system/mtdutils/compr_rtime.cpp new file mode 100644 index 000000000..c8c6491e2 --- /dev/null +++ b/src/system/mtdutils/compr_rtime.cpp @@ -0,0 +1,124 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001-2003 Red Hat, Inc. + * + * Created by Arjan van de Ven + * + * For licensing information, see the file 'LICENCE' in this directory. + * + * Very simple lz77-ish encoder. + * + * Theory of operation: Both encoder and decoder have a list of "last + * occurrences" for every possible source-value; after sending the + * first source-byte, the second byte indicated the "run" length of + * matches + * + * The algorithm is intended to only send "whole bytes", no bit-messing. + * + */ + +#include +#include +#include "compr.h" + +/* _compress returns the compressed size, -1 if bigger */ +static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *sourcelen, uint32_t *dstlen) +{ + short positions[256]; + int outpos = 0; + int pos=0; + + memset(positions,0,sizeof(positions)); + + while (pos < (*sourcelen) && outpos+2 <= (*dstlen)) { + int backpos, runlen=0; + unsigned char value; + + value = data_in[pos]; + + cpage_out[outpos++] = data_in[pos++]; + + backpos = positions[value]; + positions[value]=pos; + + while ((backpos < pos) && (pos < (*sourcelen)) && + (data_in[pos]==data_in[backpos++]) && (runlen<255)) { + pos++; + runlen++; + } + cpage_out[outpos++] = runlen; + } + + if (outpos >= pos) { + /* We failed */ + return -1; + } + + /* Tell the caller how much we managed to compress, and how much space it took */ + *sourcelen = pos; + *dstlen = outpos; + return 0; +} + + +static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, + __attribute__((unused)) uint32_t srclen, uint32_t destlen) +{ + short positions[256]; + uint32_t outpos = 0; + int pos=0; + + memset(positions,0,sizeof(positions)); + + while (outpos= outpos) { + while(repeat) { + cpage_out[outpos++] = cpage_out[backoffs++]; + repeat--; + } + } else { + memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat); + outpos+=repeat; + } + } + } + return 0; +} + +static struct jffs2_compressor jffs2_rtime_comp; +void fill_jffs2_rtime_compressor_struct(); + +void fill_jffs2_rtime_compressor_struct() +{ + jffs2_rtime_comp.priority = JFFS2_RTIME_PRIORITY; + jffs2_rtime_comp.name = "rtime"; + jffs2_rtime_comp.disabled = 0; + jffs2_rtime_comp.compr = JFFS2_COMPR_RTIME; + jffs2_rtime_comp.compress = &jffs2_rtime_compress; + jffs2_rtime_comp.decompress = &jffs2_rtime_decompress; +} + +int jffs2_rtime_init(void) +{ + fill_jffs2_rtime_compressor_struct(); + return jffs2_register_compressor(&jffs2_rtime_comp); +} + +void jffs2_rtime_exit(void) +{ + fill_jffs2_rtime_compressor_struct(); + jffs2_unregister_compressor(&jffs2_rtime_comp); +} diff --git a/src/system/mtdutils/compr_zlib.cpp b/src/system/mtdutils/compr_zlib.cpp new file mode 100644 index 000000000..717053fc1 --- /dev/null +++ b/src/system/mtdutils/compr_zlib.cpp @@ -0,0 +1,154 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001 Red Hat, Inc. + * + * Created by David Woodhouse + * + * The original JFFS, from which the design for JFFS2 was derived, + * was designed and implemented by Axis Communications AB. + * + * The contents of this file are subject to the Red Hat eCos Public + * License Version 1.1 (the "Licence"); you may not use this file + * except in compliance with the Licence. You may obtain a copy of + * the Licence at http://www.redhat.com/ + * + * Software distributed under the Licence is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the Licence for the specific language governing rights and + * limitations under the Licence. + * + * The Original Code is JFFS2 - Journalling Flash File System, version 2 + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the RHEPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the RHEPL or the GPL. + */ + +#define PROGRAM_NAME "compr_zlib" + +#include +#define crc32 __zlib_crc32 +#include +#undef crc32 +#include +#include +#include +#include "common.h" +#include "compr.h" + +/* Plan: call deflate() with avail_in == *sourcelen, + avail_out = *dstlen - 12 and flush == Z_FINISH. + If it doesn't manage to finish, call it again with + avail_in == 0 and avail_out set to the remaining 12 + bytes for it to clean up. +Q: Is 12 bytes sufficient? + */ +#define STREAM_END_SPACE 12 + +static int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *sourcelen, uint32_t *dstlen) +{ + z_stream strm; + int ret; + + if (*dstlen <= STREAM_END_SPACE) + return -1; + + strm.zalloc = NULL; + strm.zfree = NULL; + + if (Z_OK != deflateInit(&strm, 3)) { + return -1; + } + strm.next_in = data_in; + strm.total_in = 0; + + strm.next_out = cpage_out; + strm.total_out = 0; + + while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) { + strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE); + strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out); + ret = deflate(&strm, Z_PARTIAL_FLUSH); + if (ret != Z_OK) { + deflateEnd(&strm); + return -1; + } + } + strm.avail_out += STREAM_END_SPACE; + strm.avail_in = 0; + ret = deflate(&strm, Z_FINISH); + if (ret != Z_STREAM_END) { + deflateEnd(&strm); + return -1; + } + deflateEnd(&strm); + + if (strm.total_out >= strm.total_in) + return -1; + + + *dstlen = strm.total_out; + *sourcelen = strm.total_in; + return 0; +} + +static int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t srclen, uint32_t destlen) +{ + z_stream strm; + int ret; + + strm.zalloc = NULL; + strm.zfree = NULL; + + if (Z_OK != inflateInit(&strm)) { + return 1; + } + strm.next_in = data_in; + strm.avail_in = srclen; + strm.total_in = 0; + + strm.next_out = cpage_out; + strm.avail_out = destlen; + strm.total_out = 0; + + while((ret = inflate(&strm, Z_FINISH)) == Z_OK) + ; + + inflateEnd(&strm); + return 0; +} + +static struct jffs2_compressor jffs2_zlib_comp; +void fill_jffs2_zlib_compressor_struct(); + +void fill_jffs2_zlib_compressor_struct() +{ + jffs2_zlib_comp.priority = JFFS2_ZLIB_PRIORITY; + jffs2_zlib_comp.name = "zlib"; + jffs2_zlib_comp.disabled = 0; + jffs2_zlib_comp.compr = JFFS2_COMPR_ZLIB; + jffs2_zlib_comp.compress = &jffs2_zlib_compress; + jffs2_zlib_comp.decompress = &jffs2_zlib_decompress; +} + +int jffs2_zlib_init(void) +{ + fill_jffs2_zlib_compressor_struct(); + return jffs2_register_compressor(&jffs2_zlib_comp); +} + +void jffs2_zlib_exit(void) +{ + fill_jffs2_zlib_compressor_struct(); + jffs2_unregister_compressor(&jffs2_zlib_comp); +} diff --git a/src/system/mtdutils/include/common.h b/src/system/mtdutils/include/common.h new file mode 100644 index 000000000..8e186ec69 --- /dev/null +++ b/src/system/mtdutils/include/common.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) Artem Bityutskiy, 2007, 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MTD_UTILS_COMMON_H__ +#define __MTD_UTILS_COMMON_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef PROGRAM_NAME +# error "You must define PROGRAM_NAME before including this header" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIN /* some C lib headers define this for us */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif +#define min(a, b) MIN(a, b) /* glue for linux kernel source */ +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +/* define a print format specifier for off_t */ +#ifdef __USE_FILE_OFFSET64 +#define PRIxoff_t PRIx64 +#define PRIdoff_t PRId64 +#else +#define PRIxoff_t "l"PRIx32 +#define PRIdoff_t "l"PRId32 +#endif + +/* Verbose messages */ +#define bareverbose(verbose, fmt, ...) do { \ + if (verbose) \ + printf(fmt, ##__VA_ARGS__); \ +} while(0) +#define verbose(verbose, fmt, ...) \ + bareverbose(verbose, "%s: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__) + +/* Normal messages */ +#define normsg_cont(fmt, ...) do { \ + printf("%s: " fmt, PROGRAM_NAME, ##__VA_ARGS__); \ +} while(0) +#define normsg(fmt, ...) do { \ + normsg_cont(fmt "\n", ##__VA_ARGS__); \ +} while(0) + +/* Error messages */ +#define errmsg(fmt, ...) ({ \ + fprintf(stderr, "%s: error!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \ + -1; \ +}) + +/* System error messages */ +#define sys_errmsg(fmt, ...) ({ \ + int _err = errno; \ + errmsg(fmt, ##__VA_ARGS__); \ + fprintf(stderr, "%*serror %d (%s)\n", (int)sizeof(PROGRAM_NAME) + 1,\ + "", _err, strerror(_err)); \ + -1; \ +}) + +/* Warnings */ +#define warnmsg(fmt, ...) do { \ + fprintf(stderr, "%s: warning!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \ +} while(0) + +static inline int is_power_of_2(unsigned long long n) +{ + return (n != 0 && ((n & (n - 1)) == 0)); +} + +/** + * simple_strtoX - convert a hex/dec/oct string into a number + * @snum: buffer to convert + * @error: set to 1 when buffer isn't fully consumed + * + * These functions are similar to the standard strtoX() functions, but they are + * a little bit easier to use if you want to convert full string of digits into + * the binary form. The typical usage: + * + * int error = 0; + * unsigned long num; + * + * num = simple_strtoul(str, &error); + * if (error || ... if needed, your check that num is not out of range ...) + * error_happened(); + */ +#define simple_strtoX(func, type) \ +static inline type simple_##func(const char *snum, int *error) \ +{ \ + char *endptr; \ + type ret = func(snum, &endptr, 0); \ + \ + if (error && (!*snum || *endptr)) { \ + errmsg("%s: unable to parse the number '%s'", #func, snum); \ + *error = 1; \ + } \ + \ + return ret; \ +} +simple_strtoX(strtol, long int) +simple_strtoX(strtoll, long long int) +simple_strtoX(strtoul, unsigned long int) +simple_strtoX(strtoull, unsigned long long int) + +/* Simple version-printing for utils */ +#define common_print_version() \ +do { \ + printf("%s %s\n", PROGRAM_NAME, X_VERSION); \ +} while (0) + +#include "xalloc.h" + +#ifdef __cplusplus +} +#endif + +#endif /* !__MTD_UTILS_COMMON_H__ */ diff --git a/src/system/mtdutils/include/crc32.h b/src/system/mtdutils/include/crc32.h new file mode 100644 index 000000000..9c1f742c6 --- /dev/null +++ b/src/system/mtdutils/include/crc32.h @@ -0,0 +1,13 @@ +/* + * This code was taken from the linux kernel. The license is GPL Version 2. + */ + +#ifndef __CRC32_H__ +#define __CRC32_H__ + +#include + +/* Return a 32-bit CRC of the contents of the buffer */ +extern uint32_t mtd_crc32(uint32_t val, const void *ss, int len); + +#endif /* __CRC32_H__ */ diff --git a/src/system/mtdutils/include/libmtd.h b/src/system/mtdutils/include/libmtd.h new file mode 100644 index 000000000..a78c8cb5c --- /dev/null +++ b/src/system/mtdutils/include/libmtd.h @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2008, 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem Bityutskiy + * + * MTD library. + */ + +#ifndef __LIBMTD_H__ +#define __LIBMTD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Maximum MTD device name length */ +#define MTD_NAME_MAX 127 +/* Maximum MTD device type string length */ +#define MTD_TYPE_MAX 64 + +/* MTD library descriptor */ +typedef void * libmtd_t; + +/* Forward decls */ +struct region_info_user; + +/** + * @mtd_dev_cnt: count of MTD devices in system + * @lowest_mtd_num: lowest MTD device number in system + * @highest_mtd_num: highest MTD device number in system + * @sysfs_supported: non-zero if sysfs is supported by MTD + */ +struct mtd_info +{ + int mtd_dev_cnt; + int lowest_mtd_num; + int highest_mtd_num; + unsigned int sysfs_supported:1; +}; + +/** + * struct mtd_dev_info - information about an MTD device. + * @mtd_num: MTD device number + * @major: major number of corresponding character device + * @minor: minor number of corresponding character device + * @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h) + * @type_str: static R/O flash type string + * @name: device name + * @size: device size in bytes + * @eb_cnt: count of eraseblocks + * @eb_size: eraseblock size + * @min_io_size: minimum input/output unit size + * @subpage_size: sub-page size + * @oob_size: OOB size (zero if the device does not have OOB area) + * @region_cnt: count of additional erase regions + * @writable: zero if the device is read-only + * @bb_allowed: non-zero if the MTD device may have bad eraseblocks + */ +struct mtd_dev_info +{ + int mtd_num; + int major; + int minor; + int type; + const char type_str[MTD_TYPE_MAX + 1]; + const char name[MTD_NAME_MAX + 1]; + long long size; + int eb_cnt; + int eb_size; + int min_io_size; + int subpage_size; + int oob_size; + int region_cnt; + unsigned int writable:1; + unsigned int bb_allowed:1; +}; + +/** + * libmtd_open - open MTD library. + * + * This function initializes and opens the MTD library and returns MTD library + * descriptor in case of success and %NULL in case of failure. In case of + * failure, errno contains zero if MTD is not present in the system, or + * contains the error code if a real error happened. + */ +libmtd_t libmtd_open(void); + +/** + * libmtd_close - close MTD library. + * @desc: MTD library descriptor + */ +void libmtd_close(libmtd_t desc); + +/** + * mtd_dev_present - check whether a MTD device is present. + * @desc: MTD library descriptor + * @mtd_num: MTD device number to check + * + * This function returns %1 if MTD device is present and %0 if not. + */ +int mtd_dev_present(libmtd_t desc, int mtd_num); + +/** + * mtd_get_info - get general MTD information. + * @desc: MTD library descriptor + * @info: the MTD device information is returned here + * + * This function fills the passed @info object with general MTD information and + * returns %0 in case of success and %-1 in case of failure. If MTD subsystem is + * not present in the system, errno is set to @ENODEV. + */ +int mtd_get_info(libmtd_t desc, struct mtd_info *info); + +/** + * mtd_get_dev_info - get information about an MTD device. + * @desc: MTD library descriptor + * @node: name of the MTD device node + * @mtd: the MTD device information is returned here + * + * This function gets information about MTD device defined by the @node device + * node file and saves this information in the @mtd object. Returns %0 in case + * of success and %-1 in case of failure. If MTD subsystem is not present in the + * system, or the MTD device does not exist, errno is set to @ENODEV. + */ +int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd); + +/** + * mtd_get_dev_info1 - get information about an MTD device. + * @desc: MTD library descriptor + * @mtd_num: MTD device number to fetch information about + * @mtd: the MTD device information is returned here + * + * This function is identical to 'mtd_get_dev_info()' except that it accepts + * MTD device number, not MTD character device. + */ +int mtd_get_dev_info1(libmtd_t desc, int mtd_num, struct mtd_dev_info *mtd); + +/** + * mtd_lock - lock eraseblocks. + * @desc: MTD library descriptor + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @eb: eraseblock to lock + * + * This function locks eraseblock @eb. Returns %0 in case of success and %-1 + * in case of failure. + */ +int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb); + +/** + * mtd_unlock - unlock eraseblocks. + * @desc: MTD library descriptor + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @eb: eraseblock to lock + * + * This function unlocks eraseblock @eb. Returns %0 in case of success and %-1 + * in case of failure. + */ +int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb); + +/** + * mtd_erase - erase an eraseblock. + * @desc: MTD library descriptor + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @eb: eraseblock to erase + * + * This function erases eraseblock @eb of MTD device described by @fd. Returns + * %0 in case of success and %-1 in case of failure. + */ +int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb); + +/** + * mtd_regioninfo - get information about an erase region. + * @fd: MTD device node file descriptor + * @regidx: index of region to look up + * @reginfo: the region information is returned here + * + * This function gets information about an erase region defined by the + * @regidx index and saves this information in the @reginfo object. + * Returns %0 in case of success and %-1 in case of failure. If the + * @regidx is not valid or unavailable, errno is set to @ENODEV. + */ +int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo); + +/** + * mtd_is_locked - see if the specified eraseblock is locked. + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @eb: eraseblock to check + * + * This function checks to see if eraseblock @eb of MTD device described + * by @fd is locked. Returns %0 if it is unlocked, %1 if it is locked, and + * %-1 in case of failure. If the ioctl is not supported (support was added in + * Linux kernel 2.6.36) or this particular device does not support it, errno is + * set to @ENOTSUPP. + */ +int mtd_is_locked(const struct mtd_dev_info *mtd, int fd, int eb); + +/** + * mtd_torture - torture an eraseblock. + * @desc: MTD library descriptor + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @eb: eraseblock to torture + * + * This function tortures eraseblock @eb. Returns %0 in case of success and %-1 + * in case of failure. + */ +int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb); + +/** + * mtd_is_bad - check if eraseblock is bad. + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @eb: eraseblock to check + * + * This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes, + * and %-1 in case of failure. + */ +int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb); + +/** + * mtd_mark_bad - mark an eraseblock as bad. + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @eb: eraseblock to mark as bad + * + * This function marks eraseblock @eb as bad. Returns %0 in case of success and + * %-1 in case of failure. + */ +int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb); + +/** + * mtd_read - read data from an MTD device. + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @eb: eraseblock to read from + * @offs: offset withing the eraseblock to read from + * @buf: buffer to read data to + * @len: how many bytes to read + * + * This function reads @len bytes of data from eraseblock @eb and offset @offs + * of the MTD device defined by @mtd and stores the read data at buffer @buf. + * Returns %0 in case of success and %-1 in case of failure. + */ +int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs, + void *buf, int len); + +/** + * mtd_write - write data to an MTD device. + * @desc: MTD library descriptor + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @eb: eraseblock to write to + * @offs: offset withing the eraseblock to write to + * @data: data buffer to write + * @len: how many data bytes to write + * @oob: OOB buffer to write + * @ooblen: how many OOB bytes to write + * @mode: write mode (e.g., %MTD_OOB_PLACE, %MTD_OOB_RAW) + * + * This function writes @len bytes of data to eraseblock @eb and offset @offs + * of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in + * case of failure. + * + * Can only write to a single page at a time if writing to OOB. + */ +int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb, + int offs, void *data, int len, void *oob, int ooblen, + uint8_t mode); + +/** + * mtd_read_oob - read out-of-band area. + * @desc: MTD library descriptor + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @start: page-aligned start address + * @length: number of OOB bytes to read + * @data: read buffer + * + * This function reads @length OOB bytes starting from address @start on + * MTD device described by @fd. The address is specified as page byte offset + * from the beginning of the MTD device. This function returns %0 in case of + * success and %-1 in case of failure. + */ +int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, + uint64_t start, uint64_t length, void *data); + +/** + * mtd_write_oob - write out-of-band area. + * @desc: MTD library descriptor + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @start: page-aligned start address + * @length: number of OOB bytes to write + * @data: write buffer + * + * This function writes @length OOB bytes starting from address @start on + * MTD device described by @fd. The address is specified as page byte offset + * from the beginning of the MTD device. Returns %0 in case of success and %-1 + * in case of failure. + */ +int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, + uint64_t start, uint64_t length, void *data); + +/** + * mtd_write_img - write a file to MTD device. + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @eb: eraseblock to write to + * @offs: offset withing the eraseblock to write to + * @img_name: the file to write + * + * This function writes an image @img_name the MTD device defined by @mtd. @eb + * and @offs are the starting eraseblock and offset on the MTD device. Returns + * %0 in case of success and %-1 in case of failure. + */ +int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs, + const char *img_name); + +/** + * mtd_probe_node - test MTD node. + * @desc: MTD library descriptor + * @node: the node to test + * + * This function tests whether @node is an MTD device node and returns %1 if it + * is, and %-1 if it is not (errno is %ENODEV in this case) or if an error + * occurred. + */ +int mtd_probe_node(libmtd_t desc, const char *node); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBMTD_H__ */ diff --git a/src/system/mtdutils/include/linux/jffs2.h b/src/system/mtdutils/include/linux/jffs2.h new file mode 100644 index 000000000..7306f86de --- /dev/null +++ b/src/system/mtdutils/include/linux/jffs2.h @@ -0,0 +1,218 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001-2003 Red Hat, Inc. + * + * Created by David Woodhouse + * + * For licensing information, see the file 'LICENCE' in the + * jffs2 directory. + * + * $Id: jffs2.h,v 1.38 2005/09/26 11:37:23 havasi Exp $ + * + */ + +#ifndef __LINUX_JFFS2_H__ +#define __LINUX_JFFS2_H__ + +/* You must include something which defines the C99 uintXX_t types. + We don't do it from here because this file is used in too many + different environments. */ + +#define JFFS2_SUPER_MAGIC 0x72b6 + +/* Values we may expect to find in the 'magic' field */ +#define JFFS2_OLD_MAGIC_BITMASK 0x1984 +#define JFFS2_MAGIC_BITMASK 0x1985 +#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ +#define JFFS2_EMPTY_BITMASK 0xffff +#define JFFS2_DIRTY_BITMASK 0x0000 + +/* Summary node MAGIC marker */ +#define JFFS2_SUM_MAGIC 0x02851885 + +/* We only allow a single char for length, and 0xFF is empty flash so + we don't want it confused with a real length. Hence max 254. +*/ +#define JFFS2_MAX_NAME_LEN 254 + +/* How small can we sensibly write nodes? */ +#define JFFS2_MIN_DATA_LEN 128 + +#define JFFS2_COMPR_NONE 0x00 +#define JFFS2_COMPR_ZERO 0x01 +#define JFFS2_COMPR_RTIME 0x02 +#define JFFS2_COMPR_RUBINMIPS 0x03 +#define JFFS2_COMPR_COPY 0x04 +#define JFFS2_COMPR_DYNRUBIN 0x05 +#define JFFS2_COMPR_ZLIB 0x06 +#define JFFS2_COMPR_LZO 0x07 +/* Compatibility flags. */ +#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ +#define JFFS2_NODE_ACCURATE 0x2000 +/* INCOMPAT: Fail to mount the filesystem */ +#define JFFS2_FEATURE_INCOMPAT 0xc000 +/* ROCOMPAT: Mount read-only */ +#define JFFS2_FEATURE_ROCOMPAT 0x8000 +/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */ +#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000 +/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */ +#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000 + +#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1) +#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2) +#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) +#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) + +#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) + +#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8) +#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9) + +/* XATTR Related */ +#define JFFS2_XPREFIX_USER 1 /* for "user." */ +#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */ +#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */ +#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */ +#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */ + +#define JFFS2_ACL_VERSION 0x0001 + +// Maybe later... +//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) +//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) + + +#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at + mount time, don't wait for it to + happen later */ +#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific + compression type */ + + +/* These can go once we've made sure we've caught all uses without + byteswapping */ + +typedef struct { + uint32_t v32; +} __attribute__((packed)) jint32_t; + +typedef struct { + uint32_t m; +} __attribute__((packed)) jmode_t; + +typedef struct { + uint16_t v16; +} __attribute__((packed)) jint16_t; + +struct jffs2_unknown_node +{ + /* All start like this */ + jint16_t magic; + jint16_t nodetype; + jint32_t totlen; /* So we can skip over nodes we don't grok */ + jint32_t hdr_crc; +} __attribute__((packed)); + +struct jffs2_raw_dirent +{ + jint16_t magic; + jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t pino; + jint32_t version; + jint32_t ino; /* == zero for unlink */ + jint32_t mctime; + uint8_t nsize; + uint8_t type; + uint8_t unused[2]; + jint32_t node_crc; + jint32_t name_crc; + uint8_t name[0]; +} __attribute__((packed)); + +/* The JFFS2 raw inode structure: Used for storage on physical media. */ +/* The uid, gid, atime, mtime and ctime members could be longer, but + are left like this for space efficiency. If and when people decide + they really need them extended, it's simple enough to add support for + a new type of raw node. +*/ +struct jffs2_raw_inode +{ + jint16_t magic; /* A constant magic number. */ + jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */ + jint32_t totlen; /* Total length of this node (inc data, etc.) */ + jint32_t hdr_crc; + jint32_t ino; /* Inode number. */ + jint32_t version; /* Version number. */ + jmode_t mode; /* The file's type or mode. */ + jint16_t uid; /* The file's owner. */ + jint16_t gid; /* The file's group. */ + jint32_t isize; /* Total resultant size of this inode (used for truncations) */ + jint32_t atime; /* Last access time. */ + jint32_t mtime; /* Last modification time. */ + jint32_t ctime; /* Change time. */ + jint32_t offset; /* Where to begin to write. */ + jint32_t csize; /* (Compressed) data size */ + jint32_t dsize; /* Size of the node's data. (after decompression) */ + uint8_t compr; /* Compression algorithm used */ + uint8_t usercompr; /* Compression algorithm requested by the user */ + jint16_t flags; /* See JFFS2_INO_FLAG_* */ + jint32_t data_crc; /* CRC for the (compressed) data. */ + jint32_t node_crc; /* CRC for the raw inode (excluding data) */ + uint8_t data[0]; +} __attribute__((packed)); + +struct jffs2_raw_xattr { + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t xid; /* XATTR identifier number */ + jint32_t version; + uint8_t xprefix; + uint8_t name_len; + jint16_t value_len; + jint32_t data_crc; + jint32_t node_crc; + uint8_t data[0]; +} __attribute__((packed)); + +struct jffs2_raw_xref +{ + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t ino; /* inode number */ + jint32_t xid; /* XATTR identifier number */ + jint32_t xseqno; /* xref sequencial number */ + jint32_t node_crc; +} __attribute__((packed)); + +struct jffs2_raw_summary +{ + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t sum_num; /* number of sum entries*/ + jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */ + jint32_t padded; /* sum of the size of padding nodes */ + jint32_t sum_crc; /* summary information crc */ + jint32_t node_crc; /* node crc */ + jint32_t sum[0]; /* inode summary info */ +} __attribute__((packed)); + +union jffs2_node_union +{ + struct jffs2_raw_inode i; + struct jffs2_raw_dirent d; + struct jffs2_raw_xattr x; + struct jffs2_raw_xref r; + struct jffs2_raw_summary s; + struct jffs2_unknown_node u; +}; + +#endif /* __LINUX_JFFS2_H__ */ diff --git a/src/system/mtdutils/include/mtd/ftl-user.h b/src/system/mtdutils/include/mtd/ftl-user.h new file mode 100644 index 000000000..53e94c284 --- /dev/null +++ b/src/system/mtdutils/include/mtd/ftl-user.h @@ -0,0 +1,76 @@ +/* + * $Id: ftl.h,v 1.7 2005/11/07 11:14:54 gleixner Exp $ + * + * Derived from (and probably identical to): + * ftl.h 1.7 1999/10/25 20:23:17 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef __MTD_FTL_USER_H__ +#define __MTD_FTL_USER_H__ + +typedef struct erase_unit_header_t { + u_int8_t LinkTargetTuple[5]; + u_int8_t DataOrgTuple[10]; + u_int8_t NumTransferUnits; + u_int32_t EraseCount; + u_int16_t LogicalEUN; + u_int8_t BlockSize; + u_int8_t EraseUnitSize; + u_int16_t FirstPhysicalEUN; + u_int16_t NumEraseUnits; + u_int32_t FormattedSize; + u_int32_t FirstVMAddress; + u_int16_t NumVMPages; + u_int8_t Flags; + u_int8_t Code; + u_int32_t SerialNumber; + u_int32_t AltEUHOffset; + u_int32_t BAMOffset; + u_int8_t Reserved[12]; + u_int8_t EndTuple[2]; +} erase_unit_header_t; + +/* Flags in erase_unit_header_t */ +#define HIDDEN_AREA 0x01 +#define REVERSE_POLARITY 0x02 +#define DOUBLE_BAI 0x04 + +/* Definitions for block allocation information */ + +#define BLOCK_FREE(b) ((b) == 0xffffffff) +#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe)) + +#define BLOCK_TYPE(b) ((b) & 0x7f) +#define BLOCK_ADDRESS(b) ((b) & ~0x7f) +#define BLOCK_NUMBER(b) ((b) >> 9) +#define BLOCK_CONTROL 0x30 +#define BLOCK_DATA 0x40 +#define BLOCK_REPLACEMENT 0x60 +#define BLOCK_BAD 0x70 + +#endif /* __MTD_FTL_USER_H__ */ diff --git a/src/system/mtdutils/include/mtd/inftl-user.h b/src/system/mtdutils/include/mtd/inftl-user.h new file mode 100644 index 000000000..45220ed76 --- /dev/null +++ b/src/system/mtdutils/include/mtd/inftl-user.h @@ -0,0 +1,89 @@ +/* + * $Id: inftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $ + * + * Parts of INFTL headers shared with userspace + * + */ + +#ifndef __MTD_INFTL_USER_H__ +#define __MTD_INFTL_USER_H__ + +#define OSAK_VERSION 0x5120 +#define PERCENTUSED 98 + +#define SECTORSIZE 512 + +/* Block Control Information */ + +struct inftl_bci { + uint8_t ECCsig[6]; + uint8_t Status; + uint8_t Status1; +} __attribute__((packed)); + +struct inftl_unithead1 { + uint16_t virtualUnitNo; + uint16_t prevUnitNo; + uint8_t ANAC; + uint8_t NACs; + uint8_t parityPerField; + uint8_t discarded; +} __attribute__((packed)); + +struct inftl_unithead2 { + uint8_t parityPerField; + uint8_t ANAC; + uint16_t prevUnitNo; + uint16_t virtualUnitNo; + uint8_t NACs; + uint8_t discarded; +} __attribute__((packed)); + +struct inftl_unittail { + uint8_t Reserved[4]; + uint16_t EraseMark; + uint16_t EraseMark1; +} __attribute__((packed)); + +union inftl_uci { + struct inftl_unithead1 a; + struct inftl_unithead2 b; + struct inftl_unittail c; +}; + +struct inftl_oob { + struct inftl_bci b; + union inftl_uci u; +}; + + +/* INFTL Media Header */ + +struct INFTLPartition { + __u32 virtualUnits; + __u32 firstUnit; + __u32 lastUnit; + __u32 flags; + __u32 spareUnits; + __u32 Reserved0; + __u32 Reserved1; +} __attribute__((packed)); + +struct INFTLMediaHeader { + char bootRecordID[8]; + __u32 NoOfBootImageBlocks; + __u32 NoOfBinaryPartitions; + __u32 NoOfBDTLPartitions; + __u32 BlockMultiplierBits; + __u32 FormatFlags; + __u32 OsakVersion; + __u32 PercentUsed; + struct INFTLPartition Partitions[4]; +} __attribute__((packed)); + +/* Partition flag types */ +#define INFTL_BINARY 0x20000000 +#define INFTL_BDTL 0x40000000 +#define INFTL_LAST 0x80000000 + +#endif /* __MTD_INFTL_USER_H__ */ diff --git a/src/system/mtdutils/include/mtd/jffs2-user.h b/src/system/mtdutils/include/mtd/jffs2-user.h new file mode 100644 index 000000000..bc5d99aba --- /dev/null +++ b/src/system/mtdutils/include/mtd/jffs2-user.h @@ -0,0 +1,82 @@ +/* + * $Id: jffs2-user.h,v 1.1 2004/05/05 11:57:54 dwmw2 Exp $ + * + * JFFS2 definitions for use in user space only + */ + +#ifndef __JFFS2_USER_H__ +#define __JFFS2_USER_H__ + +/* This file is blessed for inclusion by userspace */ +#include +#include +#include + +#undef cpu_to_je16 +#undef cpu_to_je32 +#undef cpu_to_jemode +#undef je16_to_cpu +#undef je32_to_cpu +#undef jemode_to_cpu + +extern int target_endian; + +#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); }) +#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); }) + +#define cpu_to_je16(x) ((jint16_t){t16(x)}) +#define cpu_to_je32(x) ((jint32_t){t32(x)}) +#define cpu_to_jemode(x) ((jmode_t){t32(x)}) + +#define je16_to_cpu(x) (t16((x).v16)) +#define je32_to_cpu(x) (t32((x).v32)) +#define jemode_to_cpu(x) (t32((x).m)) + +#define le16_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x)) +#define le32_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x)) +#define cpu_to_le16(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x)) +#define cpu_to_le32(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x)) + +/* XATTR/POSIX-ACL related definition */ +/* Namespaces copied from xattr.h and posix_acl_xattr.h */ +#define XATTR_USER_PREFIX "user." +#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1) +#define XATTR_SECURITY_PREFIX "security." +#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1) +#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access" +#define POSIX_ACL_XATTR_ACCESS_LEN (sizeof (POSIX_ACL_XATTR_ACCESS) - 1) +#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default" +#define POSIX_ACL_XATTR_DEFAULT_LEN (sizeof (POSIX_ACL_XATTR_DEFAULT) - 1) +#define XATTR_TRUSTED_PREFIX "trusted." +#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1) + +struct jffs2_acl_entry { + jint16_t e_tag; + jint16_t e_perm; + jint32_t e_id; +}; + +struct jffs2_acl_entry_short { + jint16_t e_tag; + jint16_t e_perm; +}; + +struct jffs2_acl_header { + jint32_t a_version; +}; + +/* copied from include/linux/posix_acl_xattr.h */ +#define POSIX_ACL_XATTR_VERSION 0x0002 + +struct posix_acl_xattr_entry { + uint16_t e_tag; + uint16_t e_perm; + uint32_t e_id; +}; + +struct posix_acl_xattr_header { + uint32_t a_version; + struct posix_acl_xattr_entry a_entries[0]; +}; + +#endif /* __JFFS2_USER_H__ */ diff --git a/src/system/mtdutils/include/mtd/mtd-abi.h b/src/system/mtdutils/include/mtd/mtd-abi.h new file mode 100644 index 000000000..4de167bf0 --- /dev/null +++ b/src/system/mtdutils/include/mtd/mtd-abi.h @@ -0,0 +1,277 @@ +/* + * Copyright © 1999-2010 David Woodhouse et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __MTD_ABI_H__ +#define __MTD_ABI_H__ + +#include + +struct erase_info_user { + __u32 start; + __u32 length; +}; + +struct erase_info_user64 { + __u64 start; + __u64 length; +}; + +struct mtd_oob_buf { + __u32 start; + __u32 length; + unsigned char *ptr; +}; + +struct mtd_oob_buf64 { + __u64 start; + __u32 pad; + __u32 length; + __u64 usr_ptr; +}; + +/** + * MTD operation modes + * + * @MTD_OPS_PLACE_OOB: OOB data are placed at the given offset (default) + * @MTD_OPS_AUTO_OOB: OOB data are automatically placed at the free areas + * which are defined by the internal ecclayout + * @MTD_OPS_RAW: data are transferred as-is, with no error correction; + * this mode implies %MTD_OPS_PLACE_OOB + * + * These modes can be passed to ioctl(MEMWRITE) and are also used internally. + * See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs. + * %MTD_FILE_MODE_RAW. + */ +enum { + MTD_OPS_PLACE_OOB = 0, + MTD_OPS_AUTO_OOB = 1, + MTD_OPS_RAW = 2, +}; + +/** + * struct mtd_write_req - data structure for requesting a write operation + * + * @start: start address + * @len: length of data buffer + * @ooblen: length of OOB buffer + * @usr_data: user-provided data buffer + * @usr_oob: user-provided OOB buffer + * @mode: MTD mode (see "MTD operation modes") + * @padding: reserved, must be set to 0 + * + * This structure supports ioctl(MEMWRITE) operations, allowing data and/or OOB + * writes in various modes. To write to OOB-only, set @usr_data == NULL, and to + * write data-only, set @usr_oob == NULL. However, setting both @usr_data and + * @usr_oob to NULL is not allowed. + */ +struct mtd_write_req { + __u64 start; + __u64 len; + __u64 ooblen; + __u64 usr_data; + __u64 usr_oob; + __u8 mode; + __u8 padding[7]; +}; + +#define MTD_ABSENT 0 +#define MTD_RAM 1 +#define MTD_ROM 2 +#define MTD_NORFLASH 3 +#define MTD_NANDFLASH 4 +#define MTD_DATAFLASH 6 +#define MTD_UBIVOLUME 7 +#define MTD_MLCNANDFLASH 8 + +#define MTD_WRITEABLE 0x400 /* Device is writeable */ +#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */ +#define MTD_NO_ERASE 0x1000 /* No erase necessary */ +#define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */ + +/* Some common devices / combinations of capabilities */ +#define MTD_CAP_ROM 0 +#define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE) +#define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE) +#define MTD_CAP_NANDFLASH (MTD_WRITEABLE) + +/* Obsolete ECC byte placement modes (used with obsolete MEMGETOOBSEL) */ +#define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended) +#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode) +#define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme +#define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read) +#define MTD_NANDECC_AUTOPL_USR 4 // Use the given autoplacement scheme rather than using the default + +/* OTP mode selection */ +#define MTD_OTP_OFF 0 +#define MTD_OTP_FACTORY 1 +#define MTD_OTP_USER 2 + +struct mtd_info_user { + __u8 type; + __u32 flags; + __u32 size; /* Total size of the MTD */ + __u32 erasesize; + __u32 writesize; + __u32 oobsize; /* Amount of OOB data per block (e.g. 16) */ + __u64 padding; /* Old obsolete field; do not use */ +}; + +struct region_info_user { + __u32 offset; /* At which this region starts, + * from the beginning of the MTD */ + __u32 erasesize; /* For this region */ + __u32 numblocks; /* Number of blocks in this region */ + __u32 regionindex; +}; + +struct otp_info { + __u32 start; + __u32 length; + __u32 locked; +}; + +/* + * Note, the following ioctl existed in the past and was removed: + * #define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) + * Try to avoid adding a new ioctl with the same ioctl number. + */ + +/* Get basic MTD characteristics info (better to use sysfs) */ +#define MEMGETINFO _IOR('M', 1, struct mtd_info_user) +/* Erase segment of MTD */ +#define MEMERASE _IOW('M', 2, struct erase_info_user) +/* Write out-of-band data from MTD */ +#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf) +/* Read out-of-band data from MTD */ +#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf) +/* Lock a chip (for MTD that supports it) */ +#define MEMLOCK _IOW('M', 5, struct erase_info_user) +/* Unlock a chip (for MTD that supports it) */ +#define MEMUNLOCK _IOW('M', 6, struct erase_info_user) +/* Get the number of different erase regions */ +#define MEMGETREGIONCOUNT _IOR('M', 7, int) +/* Get information about the erase region for a specific index */ +#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) +/* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */ +#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo) +/* Check if an eraseblock is bad */ +#define MEMGETBADBLOCK _IOW('M', 11, __kernel_loff_t) +/* Mark an eraseblock as bad */ +#define MEMSETBADBLOCK _IOW('M', 12, __kernel_loff_t) +/* Set OTP (One-Time Programmable) mode (factory vs. user) */ +#define OTPSELECT _IOR('M', 13, int) +/* Get number of OTP (One-Time Programmable) regions */ +#define OTPGETREGIONCOUNT _IOW('M', 14, int) +/* Get all OTP (One-Time Programmable) info about MTD */ +#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info) +/* Lock a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */ +#define OTPLOCK _IOR('M', 16, struct otp_info) +/* Get ECC layout (deprecated) */ +#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout_user) +/* Get statistics about corrected/uncorrected errors */ +#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats) +/* Set MTD mode on a per-file-descriptor basis (see "MTD file modes") */ +#define MTDFILEMODE _IO('M', 19) +/* Erase segment of MTD (supports 64-bit address) */ +#define MEMERASE64 _IOW('M', 20, struct erase_info_user64) +/* Write data to OOB (64-bit version) */ +#define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64) +/* Read data from OOB (64-bit version) */ +#define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64) +/* Check if chip is locked (for MTD that supports it) */ +#define MEMISLOCKED _IOR('M', 23, struct erase_info_user) +/* + * Most generic write interface; can write in-band and/or out-of-band in various + * modes (see "struct mtd_write_req") + */ +#define MEMWRITE _IOWR('M', 24, struct mtd_write_req) + +/* + * Obsolete legacy interface. Keep it in order not to break userspace + * interfaces + */ +struct nand_oobinfo { + __u32 useecc; + __u32 eccbytes; + __u32 oobfree[8][2]; + __u32 eccpos[32]; +}; + +struct nand_oobfree { + __u32 offset; + __u32 length; +}; + +#define MTD_MAX_OOBFREE_ENTRIES 8 +#define MTD_MAX_ECCPOS_ENTRIES 64 +/* + * OBSOLETE: ECC layout control structure. Exported to user-space via ioctl + * ECCGETLAYOUT for backwards compatbility and should not be mistaken as a + * complete set of ECC information. The ioctl truncates the larger internal + * structure to retain binary compatibility with the static declaration of the + * ioctl. Note that the "MTD_MAX_..._ENTRIES" macros represent the max size of + * the user struct, not the MAX size of the internal struct nand_ecclayout. + */ +struct nand_ecclayout_user { + __u32 eccbytes; + __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES]; + __u32 oobavail; + struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; +}; + +/** + * struct mtd_ecc_stats - error correction stats + * + * @corrected: number of corrected bits + * @failed: number of uncorrectable errors + * @badblocks: number of bad blocks in this partition + * @bbtblocks: number of blocks reserved for bad block tables + */ +struct mtd_ecc_stats { + __u32 corrected; + __u32 failed; + __u32 badblocks; + __u32 bbtblocks; +}; + +/* + * MTD file modes - for read/write access to MTD + * + * @MTD_FILE_MODE_NORMAL: OTP disabled, ECC enabled + * @MTD_FILE_MODE_OTP_FACTORY: OTP enabled in factory mode + * @MTD_FILE_MODE_OTP_USER: OTP enabled in user mode + * @MTD_FILE_MODE_RAW: OTP disabled, ECC disabled + * + * These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained + * separately for each open file descriptor. + * + * Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW - + * raw access to the flash, without error correction or autoplacement schemes. + * Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode + * (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is + * used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)). + */ +enum mtd_file_modes { + MTD_FILE_MODE_NORMAL = MTD_OTP_OFF, + MTD_FILE_MODE_OTP_FACTORY = MTD_OTP_FACTORY, + MTD_FILE_MODE_OTP_USER = MTD_OTP_USER, + MTD_FILE_MODE_RAW, +}; + +#endif /* __MTD_ABI_H__ */ diff --git a/src/system/mtdutils/include/mtd/mtd-user.h b/src/system/mtdutils/include/mtd/mtd-user.h new file mode 100644 index 000000000..83327c808 --- /dev/null +++ b/src/system/mtdutils/include/mtd/mtd-user.h @@ -0,0 +1,34 @@ +/* + * Copyright © 1999-2010 David Woodhouse + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __MTD_USER_H__ +#define __MTD_USER_H__ + +#include + +/* This file is blessed for inclusion by userspace */ +#include + +typedef struct mtd_info_user mtd_info_t; +typedef struct erase_info_user erase_info_t; +typedef struct region_info_user region_info_t; +typedef struct nand_oobinfo nand_oobinfo_t; +typedef struct nand_ecclayout_user nand_ecclayout_t; + +#endif /* __MTD_USER_H__ */ diff --git a/src/system/mtdutils/include/mtd/nftl-user.h b/src/system/mtdutils/include/mtd/nftl-user.h new file mode 100644 index 000000000..b2bca18e7 --- /dev/null +++ b/src/system/mtdutils/include/mtd/nftl-user.h @@ -0,0 +1,76 @@ +/* + * $Id: nftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $ + * + * Parts of NFTL headers shared with userspace + * + */ + +#ifndef __MTD_NFTL_USER_H__ +#define __MTD_NFTL_USER_H__ + +/* Block Control Information */ + +struct nftl_bci { + unsigned char ECCSig[6]; + uint8_t Status; + uint8_t Status1; +}__attribute__((packed)); + +/* Unit Control Information */ + +struct nftl_uci0 { + uint16_t VirtUnitNum; + uint16_t ReplUnitNum; + uint16_t SpareVirtUnitNum; + uint16_t SpareReplUnitNum; +} __attribute__((packed)); + +struct nftl_uci1 { + uint32_t WearInfo; + uint16_t EraseMark; + uint16_t EraseMark1; +} __attribute__((packed)); + +struct nftl_uci2 { + uint16_t FoldMark; + uint16_t FoldMark1; + uint32_t unused; +} __attribute__((packed)); + +union nftl_uci { + struct nftl_uci0 a; + struct nftl_uci1 b; + struct nftl_uci2 c; +}; + +struct nftl_oob { + struct nftl_bci b; + union nftl_uci u; +}; + +/* NFTL Media Header */ + +struct NFTLMediaHeader { + char DataOrgID[6]; + uint16_t NumEraseUnits; + uint16_t FirstPhysicalEUN; + uint32_t FormattedSize; + unsigned char UnitSizeFactor; +} __attribute__((packed)); + +#define MAX_ERASE_ZONES (8192 - 512) + +#define ERASE_MARK 0x3c69 +#define SECTOR_FREE 0xff +#define SECTOR_USED 0x55 +#define SECTOR_IGNORE 0x11 +#define SECTOR_DELETED 0x00 + +#define FOLD_MARK_IN_PROGRESS 0x5555 + +#define ZONE_GOOD 0xff +#define ZONE_BAD_ORIGINAL 0 +#define ZONE_BAD_MARKED 7 + + +#endif /* __MTD_NFTL_USER_H__ */ diff --git a/src/system/mtdutils/include/mtd/ubi-media.h b/src/system/mtdutils/include/mtd/ubi-media.h new file mode 100644 index 000000000..08bec3ed9 --- /dev/null +++ b/src/system/mtdutils/include/mtd/ubi-media.h @@ -0,0 +1,378 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Artem Bityutskiy (Битюцкий Артём) + * Thomas Gleixner + * Frank Haverkamp + * Oliver Lohmann + * Andreas Arnez + */ + +/* + * This file defines the layout of UBI headers and all the other UBI on-flash + * data structures. + */ + +#ifndef __UBI_MEDIA_H__ +#define __UBI_MEDIA_H__ + +#include + +/* The version of UBI images supported by this implementation */ +#define UBI_VERSION 1 + +/* The highest erase counter value supported by this implementation */ +#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF + +/* The initial CRC32 value used when calculating CRC checksums */ +#define UBI_CRC32_INIT 0xFFFFFFFFU + +/* Erase counter header magic number (ASCII "UBI#") */ +#define UBI_EC_HDR_MAGIC 0x55424923 +/* Volume identifier header magic number (ASCII "UBI!") */ +#define UBI_VID_HDR_MAGIC 0x55424921 + +/* + * Volume type constants used in the volume identifier header. + * + * @UBI_VID_DYNAMIC: dynamic volume + * @UBI_VID_STATIC: static volume + */ +enum { + UBI_VID_DYNAMIC = 1, + UBI_VID_STATIC = 2 +}; + +/* + * Volume flags used in the volume table record. + * + * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume + * + * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume + * table. UBI automatically re-sizes the volume which has this flag and makes + * the volume to be of largest possible size. This means that if after the + * initialization UBI finds out that there are available physical eraseblocks + * present on the device, it automatically appends all of them to the volume + * (the physical eraseblocks reserved for bad eraseblocks handling and other + * reserved physical eraseblocks are not taken). So, if there is a volume with + * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical + * eraseblocks will be zero after UBI is loaded, because all of them will be + * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared + * after the volume had been initialized. + * + * The auto-resize feature is useful for device production purposes. For + * example, different NAND flash chips may have different amount of initial bad + * eraseblocks, depending of particular chip instance. Manufacturers of NAND + * chips usually guarantee that the amount of initial bad eraseblocks does not + * exceed certain percent, e.g. 2%. When one creates an UBI image which will be + * flashed to the end devices in production, he does not know the exact amount + * of good physical eraseblocks the NAND chip on the device will have, but this + * number is required to calculate the volume sized and put them to the volume + * table of the UBI image. In this case, one of the volumes (e.g., the one + * which will store the root file system) is marked as "auto-resizable", and + * UBI will adjust its size on the first boot if needed. + * + * Note, first UBI reserves some amount of physical eraseblocks for bad + * eraseblock handling, and then re-sizes the volume, not vice-versa. This + * means that the pool of reserved physical eraseblocks will always be present. + */ +enum { + UBI_VTBL_AUTORESIZE_FLG = 0x01, +}; + +/* + * Compatibility constants used by internal volumes. + * + * @UBI_COMPAT_DELETE: delete this internal volume before anything is written + * to the flash + * @UBI_COMPAT_RO: attach this device in read-only mode + * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its + * physical eraseblocks, don't allow the wear-leveling + * sub-system to move them + * @UBI_COMPAT_REJECT: reject this UBI image + */ +enum { + UBI_COMPAT_DELETE = 1, + UBI_COMPAT_RO = 2, + UBI_COMPAT_PRESERVE = 4, + UBI_COMPAT_REJECT = 5 +}; + +/* Sizes of UBI headers */ +#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr) +#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr) + +/* Sizes of UBI headers without the ending CRC */ +#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32)) +#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32)) + +/** + * struct ubi_ec_hdr - UBI erase counter header. + * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC) + * @version: version of UBI implementation which is supposed to accept this + * UBI image + * @padding1: reserved for future, zeroes + * @ec: the erase counter + * @vid_hdr_offset: where the VID header starts + * @data_offset: where the user data start + * @image_seq: image sequence number + * @padding2: reserved for future, zeroes + * @hdr_crc: erase counter header CRC checksum + * + * The erase counter header takes 64 bytes and has a plenty of unused space for + * future usage. The unused fields are zeroed. The @version field is used to + * indicate the version of UBI implementation which is supposed to be able to + * work with this UBI image. If @version is greater than the current UBI + * version, the image is rejected. This may be useful in future if something + * is changed radically. This field is duplicated in the volume identifier + * header. + * + * The @vid_hdr_offset and @data_offset fields contain the offset of the the + * volume identifier header and user data, relative to the beginning of the + * physical eraseblock. These values have to be the same for all physical + * eraseblocks. + * + * The @image_seq field is used to validate a UBI image that has been prepared + * for a UBI device. The @image_seq value can be any value, but it must be the + * same on all eraseblocks. UBI will ensure that all new erase counter headers + * also contain this value, and will check the value when scanning at start-up. + * One way to make use of @image_seq is to increase its value by one every time + * an image is flashed over an existing image, then, if the flashing does not + * complete, UBI will detect the error when scanning. + */ +struct ubi_ec_hdr { + __be32 magic; + __u8 version; + __u8 padding1[3]; + __be64 ec; /* Warning: the current limit is 31-bit anyway! */ + __be32 vid_hdr_offset; + __be32 data_offset; + __be32 image_seq; + __u8 padding2[32]; + __be32 hdr_crc; +} __attribute__ ((packed)); + +/** + * struct ubi_vid_hdr - on-flash UBI volume identifier header. + * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC) + * @version: UBI implementation version which is supposed to accept this UBI + * image (%UBI_VERSION) + * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) + * @copy_flag: if this logical eraseblock was copied from another physical + * eraseblock (for wear-leveling reasons) + * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, + * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) + * @vol_id: ID of this volume + * @lnum: logical eraseblock number + * @padding1: reserved for future, zeroes + * @data_size: how many bytes of data this logical eraseblock contains + * @used_ebs: total number of used logical eraseblocks in this volume + * @data_pad: how many bytes at the end of this physical eraseblock are not + * used + * @data_crc: CRC checksum of the data stored in this logical eraseblock + * @padding2: reserved for future, zeroes + * @sqnum: sequence number + * @padding3: reserved for future, zeroes + * @hdr_crc: volume identifier header CRC checksum + * + * The @sqnum is the value of the global sequence counter at the time when this + * VID header was created. The global sequence counter is incremented each time + * UBI writes a new VID header to the flash, i.e. when it maps a logical + * eraseblock to a new physical eraseblock. The global sequence counter is an + * unsigned 64-bit integer and we assume it never overflows. The @sqnum + * (sequence number) is used to distinguish between older and newer versions of + * logical eraseblocks. + * + * There are 2 situations when there may be more than one physical eraseblock + * corresponding to the same logical eraseblock, i.e., having the same @vol_id + * and @lnum values in the volume identifier header. Suppose we have a logical + * eraseblock L and it is mapped to the physical eraseblock P. + * + * 1. Because UBI may erase physical eraseblocks asynchronously, the following + * situation is possible: L is asynchronously erased, so P is scheduled for + * erasure, then L is written to,i.e. mapped to another physical eraseblock P1, + * so P1 is written to, then an unclean reboot happens. Result - there are 2 + * physical eraseblocks P and P1 corresponding to the same logical eraseblock + * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the + * flash. + * + * 2. From time to time UBI moves logical eraseblocks to other physical + * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P + * to P1, and an unclean reboot happens before P is physically erased, there + * are two physical eraseblocks P and P1 corresponding to L and UBI has to + * select one of them when the flash is attached. The @sqnum field says which + * PEB is the original (obviously P will have lower @sqnum) and the copy. But + * it is not enough to select the physical eraseblock with the higher sequence + * number, because the unclean reboot could have happen in the middle of the + * copying process, so the data in P is corrupted. It is also not enough to + * just select the physical eraseblock with lower sequence number, because the + * data there may be old (consider a case if more data was added to P1 after + * the copying). Moreover, the unclean reboot may happen when the erasure of P + * was just started, so it result in unstable P, which is "mostly" OK, but + * still has unstable bits. + * + * UBI uses the @copy_flag field to indicate that this logical eraseblock is a + * copy. UBI also calculates data CRC when the data is moved and stores it at + * the @data_crc field of the copy (P1). So when UBI needs to pick one physical + * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is + * examined. If it is cleared, the situation* is simple and the newer one is + * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC + * checksum is correct, this physical eraseblock is selected (P1). Otherwise + * the older one (P) is selected. + * + * There are 2 sorts of volumes in UBI: user volumes and internal volumes. + * Internal volumes are not seen from outside and are used for various internal + * UBI purposes. In this implementation there is only one internal volume - the + * layout volume. Internal volumes are the main mechanism of UBI extensions. + * For example, in future one may introduce a journal internal volume. Internal + * volumes have their own reserved range of IDs. + * + * The @compat field is only used for internal volumes and contains the "degree + * of their compatibility". It is always zero for user volumes. This field + * provides a mechanism to introduce UBI extensions and to be still compatible + * with older UBI binaries. For example, if someone introduced a journal in + * future, he would probably use %UBI_COMPAT_DELETE compatibility for the + * journal volume. And in this case, older UBI binaries, which know nothing + * about the journal volume, would just delete this volume and work perfectly + * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image + * - it just ignores the Ext3fs journal. + * + * The @data_crc field contains the CRC checksum of the contents of the logical + * eraseblock if this is a static volume. In case of dynamic volumes, it does + * not contain the CRC checksum as a rule. The only exception is when the + * data of the physical eraseblock was moved by the wear-leveling sub-system, + * then the wear-leveling sub-system calculates the data CRC and stores it in + * the @data_crc field. And of course, the @copy_flag is %in this case. + * + * The @data_size field is used only for static volumes because UBI has to know + * how many bytes of data are stored in this eraseblock. For dynamic volumes, + * this field usually contains zero. The only exception is when the data of the + * physical eraseblock was moved to another physical eraseblock for + * wear-leveling reasons. In this case, UBI calculates CRC checksum of the + * contents and uses both @data_crc and @data_size fields. In this case, the + * @data_size field contains data size. + * + * The @used_ebs field is used only for static volumes and indicates how many + * eraseblocks the data of the volume takes. For dynamic volumes this field is + * not used and always contains zero. + * + * The @data_pad is calculated when volumes are created using the alignment + * parameter. So, effectively, the @data_pad field reduces the size of logical + * eraseblocks of this volume. This is very handy when one uses block-oriented + * software (say, cramfs) on top of the UBI volume. + */ +struct ubi_vid_hdr { + __be32 magic; + __u8 version; + __u8 vol_type; + __u8 copy_flag; + __u8 compat; + __be32 vol_id; + __be32 lnum; + __be32 leb_ver; + __be32 data_size; + __be32 used_ebs; + __be32 data_pad; + __be32 data_crc; + __u8 padding2[4]; + __be64 sqnum; + __u8 padding3[12]; + __be32 hdr_crc; +} __attribute__ ((packed)); + +/* Internal UBI volumes count */ +#define UBI_INT_VOL_COUNT 1 + +/* + * Starting ID of internal volumes. There is reserved room for 4096 internal + * volumes. + */ +#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096) + +/* The layout volume contains the volume table */ + +#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START +#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC +#define UBI_LAYOUT_VOLUME_ALIGN 1 +#define UBI_LAYOUT_VOLUME_EBS 2 +#define UBI_LAYOUT_VOLUME_NAME "layout volume" +#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT + +/* The maximum number of volumes per one UBI device */ +#define UBI_MAX_VOLUMES 128 + +/* The maximum volume name length */ +#define UBI_VOL_NAME_MAX 127 + +/* Size of the volume table record */ +#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record) + +/* Size of the volume table record without the ending CRC */ +#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32)) + +/** + * struct ubi_vtbl_record - a record in the volume table. + * @reserved_pebs: how many physical eraseblocks are reserved for this volume + * @alignment: volume alignment + * @data_pad: how many bytes are unused at the end of the each physical + * eraseblock to satisfy the requested alignment + * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * @upd_marker: if volume update was started but not finished + * @name_len: volume name length + * @name: the volume name + * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) + * @padding: reserved, zeroes + * @crc: a CRC32 checksum of the record + * + * The volume table records are stored in the volume table, which is stored in + * the layout volume. The layout volume consists of 2 logical eraseblock, each + * of which contains a copy of the volume table (i.e., the volume table is + * duplicated). The volume table is an array of &struct ubi_vtbl_record + * objects indexed by the volume ID. + * + * If the size of the logical eraseblock is large enough to fit + * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES + * records. Otherwise, it contains as many records as it can fit (i.e., size of + * logical eraseblock divided by sizeof(struct ubi_vtbl_record)). + * + * The @upd_marker flag is used to implement volume update. It is set to %1 + * before update and set to %0 after the update. So if the update operation was + * interrupted, UBI knows that the volume is corrupted. + * + * The @alignment field is specified when the volume is created and cannot be + * later changed. It may be useful, for example, when a block-oriented file + * system works on top of UBI. The @data_pad field is calculated using the + * logical eraseblock size and @alignment. The alignment must be multiple to the + * minimal flash I/O unit. If @alignment is 1, all the available space of + * the physical eraseblocks is used. + * + * Empty records contain all zeroes and the CRC checksum of those zeroes. + */ +struct ubi_vtbl_record { + __be32 reserved_pebs; + __be32 alignment; + __be32 data_pad; + __u8 vol_type; + __u8 upd_marker; + __be16 name_len; + __u8 name[UBI_VOL_NAME_MAX+1]; + __u8 flags; + __u8 padding[23]; + __be32 crc; +} __attribute__ ((packed)); + +#endif /* !__UBI_MEDIA_H__ */ diff --git a/src/system/mtdutils/include/mtd/ubi-user.h b/src/system/mtdutils/include/mtd/ubi-user.h new file mode 100644 index 000000000..1c06d8858 --- /dev/null +++ b/src/system/mtdutils/include/mtd/ubi-user.h @@ -0,0 +1,418 @@ +/* + * Copyright © International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +#ifndef __UBI_USER_H__ +#define __UBI_USER_H__ + +/* + * UBI device creation (the same as MTD device attachment) + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI + * control device. The caller has to properly fill and pass + * &struct ubi_attach_req object - UBI will attach the MTD device specified in + * the request and return the newly created UBI device number as the ioctl + * return value. + * + * UBI device deletion (the same as MTD device detachment) + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI + * control device. + * + * UBI volume creation + * ~~~~~~~~~~~~~~~~~~~ + * + * UBI volumes are created via the %UBI_IOCMKVOL ioctl command of UBI character + * device. A &struct ubi_mkvol_req object has to be properly filled and a + * pointer to it has to be passed to the ioctl. + * + * UBI volume deletion + * ~~~~~~~~~~~~~~~~~~~ + * + * To delete a volume, the %UBI_IOCRMVOL ioctl command of the UBI character + * device should be used. A pointer to the 32-bit volume ID hast to be passed + * to the ioctl. + * + * UBI volume re-size + * ~~~~~~~~~~~~~~~~~~ + * + * To re-size a volume, the %UBI_IOCRSVOL ioctl command of the UBI character + * device should be used. A &struct ubi_rsvol_req object has to be properly + * filled and a pointer to it has to be passed to the ioctl. + * + * UBI volumes re-name + * ~~~~~~~~~~~~~~~~~~~ + * + * To re-name several volumes atomically at one go, the %UBI_IOCRNVOL command + * of the UBI character device should be used. A &struct ubi_rnvol_req object + * has to be properly filled and a pointer to it has to be passed to the ioctl. + * + * UBI volume update + * ~~~~~~~~~~~~~~~~~ + * + * Volume update should be done via the %UBI_IOCVOLUP ioctl command of the + * corresponding UBI volume character device. A pointer to a 64-bit update + * size should be passed to the ioctl. After this, UBI expects user to write + * this number of bytes to the volume character device. The update is finished + * when the claimed number of bytes is passed. So, the volume update sequence + * is something like: + * + * fd = open("/dev/my_volume"); + * ioctl(fd, UBI_IOCVOLUP, &image_size); + * write(fd, buf, image_size); + * close(fd); + * + * Logical eraseblock erase + * ~~~~~~~~~~~~~~~~~~~~~~~~ + * + * To erase a logical eraseblock, the %UBI_IOCEBER ioctl command of the + * corresponding UBI volume character device should be used. This command + * unmaps the requested logical eraseblock, makes sure the corresponding + * physical eraseblock is successfully erased, and returns. + * + * Atomic logical eraseblock change + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Atomic logical eraseblock change operation is called using the %UBI_IOCEBCH + * ioctl command of the corresponding UBI volume character device. A pointer to + * a &struct ubi_leb_change_req object has to be passed to the ioctl. Then the + * user is expected to write the requested amount of bytes (similarly to what + * should be done in case of the "volume update" ioctl). + * + * Logical eraseblock map + * ~~~~~~~~~~~~~~~~~~~~~ + * + * To map a logical eraseblock to a physical eraseblock, the %UBI_IOCEBMAP + * ioctl command should be used. A pointer to a &struct ubi_map_req object is + * expected to be passed. The ioctl maps the requested logical eraseblock to + * a physical eraseblock and returns. Only non-mapped logical eraseblocks can + * be mapped. If the logical eraseblock specified in the request is already + * mapped to a physical eraseblock, the ioctl fails and returns error. + * + * Logical eraseblock unmap + * ~~~~~~~~~~~~~~~~~~~~~~~~ + * + * To unmap a logical eraseblock to a physical eraseblock, the %UBI_IOCEBUNMAP + * ioctl command should be used. The ioctl unmaps the logical eraseblocks, + * schedules corresponding physical eraseblock for erasure, and returns. Unlike + * the "LEB erase" command, it does not wait for the physical eraseblock being + * erased. Note, the side effect of this is that if an unclean reboot happens + * after the unmap ioctl returns, you may find the LEB mapped again to the same + * physical eraseblock after the UBI is run again. + * + * Check if logical eraseblock is mapped + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * To check if a logical eraseblock is mapped to a physical eraseblock, the + * %UBI_IOCEBISMAP ioctl command should be used. It returns %0 if the LEB is + * not mapped, and %1 if it is mapped. + * + * Set an UBI volume property + * ~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * To set an UBI volume property the %UBI_IOCSETPROP ioctl command should be + * used. A pointer to a &struct ubi_set_vol_prop_req object is expected to be + * passed. The object describes which property should be set, and to which value + * it should be set. + */ + +/* + * When a new UBI volume or UBI device is created, users may either specify the + * volume/device number they want to create or to let UBI automatically assign + * the number using these constants. + */ +#define UBI_VOL_NUM_AUTO (-1) +#define UBI_DEV_NUM_AUTO (-1) + +/* Maximum volume name length */ +#define UBI_MAX_VOLUME_NAME 127 + +/* ioctl commands of UBI character devices */ + +#define UBI_IOC_MAGIC 'o' + +/* Create an UBI volume */ +#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req) +/* Remove an UBI volume */ +#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t) +/* Re-size an UBI volume */ +#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) +/* Re-name volumes */ +#define UBI_IOCRNVOL _IOW(UBI_IOC_MAGIC, 3, struct ubi_rnvol_req) + +/* ioctl commands of the UBI control character device */ + +#define UBI_CTRL_IOC_MAGIC 'o' + +/* Attach an MTD device */ +#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req) +/* Detach an MTD device */ +#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t) + +/* ioctl commands of UBI volume character devices */ + +#define UBI_VOL_IOC_MAGIC 'O' + +/* Start UBI volume update */ +#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t) +/* LEB erasure command, used for debugging, disabled by default */ +#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t) +/* Atomic LEB change command */ +#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t) +/* Map LEB command */ +#define UBI_IOCEBMAP _IOW(UBI_VOL_IOC_MAGIC, 3, struct ubi_map_req) +/* Unmap LEB command */ +#define UBI_IOCEBUNMAP _IOW(UBI_VOL_IOC_MAGIC, 4, int32_t) +/* Check if LEB is mapped command */ +#define UBI_IOCEBISMAP _IOR(UBI_VOL_IOC_MAGIC, 5, int32_t) +/* Set an UBI volume property */ +#define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \ + struct ubi_set_vol_prop_req) + +/* Maximum MTD device name length supported by UBI */ +#define MAX_UBI_MTD_NAME_LEN 127 + +/* Maximum amount of UBI volumes that can be re-named at one go */ +#define UBI_MAX_RNVOL 32 + +/* + * UBI volume type constants. + * + * @UBI_DYNAMIC_VOLUME: dynamic volume + * @UBI_STATIC_VOLUME: static volume + */ +enum { + UBI_DYNAMIC_VOLUME = 3, + UBI_STATIC_VOLUME = 4, +}; + +/* + * UBI set volume property ioctl constants. + * + * @UBI_VOL_PROP_DIRECT_WRITE: allow (any non-zero value) or disallow (value 0) + * user to directly write and erase individual + * eraseblocks on dynamic volumes + */ +enum { + UBI_VOL_PROP_DIRECT_WRITE = 1, +}; + +/** + * struct ubi_attach_req - attach MTD device request. + * @ubi_num: UBI device number to create + * @mtd_num: MTD device number to attach + * @vid_hdr_offset: VID header offset (use defaults if %0) + * @max_beb_per1024: maximum expected number of bad PEB per 1024 PEBs + * @padding: reserved for future, not used, has to be zeroed + * + * This data structure is used to specify MTD device UBI has to attach and the + * parameters it has to use. The number which should be assigned to the new UBI + * device is passed in @ubi_num. UBI may automatically assign the number if + * @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in + * @ubi_num. + * + * Most applications should pass %0 in @vid_hdr_offset to make UBI use default + * offset of the VID header within physical eraseblocks. The default offset is + * the next min. I/O unit after the EC header. For example, it will be offset + * 512 in case of a 512 bytes page NAND flash with no sub-page support. Or + * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages. + * + * But in rare cases, if this optimizes things, the VID header may be placed to + * a different offset. For example, the boot-loader might do things faster if + * the VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. + * As the boot-loader would not normally need to read EC headers (unless it + * needs UBI in RW mode), it might be faster to calculate ECC. This is weird + * example, but it real-life example. So, in this example, @vid_hdr_offer would + * be 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes + * aligned, which is OK, as UBI is clever enough to realize this is 4th + * sub-page of the first page and add needed padding. + * + * The @max_beb_per1024 is the maximum amount of bad PEBs UBI expects on the + * UBI device per 1024 eraseblocks. This value is often given in an other form + * in the NAND datasheet (min NVB i.e. minimal number of valid blocks). The + * maximum expected bad eraseblocks per 1024 is then: + * 1024 * (1 - MinNVB / MaxNVB) + * Which gives 20 for most NAND devices. This limit is used in order to derive + * amount of eraseblock UBI reserves for handling new bad blocks. If the device + * has more bad eraseblocks than this limit, UBI does not reserve any physical + * eraseblocks for new bad eraseblocks, but attempts to use available + * eraseblocks (if any). The accepted range is 0-768. If 0 is given, the + * default kernel value of %CONFIG_MTD_UBI_BEB_LIMIT will be used. + */ +struct ubi_attach_req { + int32_t ubi_num; + int32_t mtd_num; + int32_t vid_hdr_offset; + int16_t max_beb_per1024; + int8_t padding[10]; +}; + +/** + * struct ubi_mkvol_req - volume description data structure used in + * volume creation requests. + * @vol_id: volume number + * @alignment: volume alignment + * @bytes: volume size in bytes + * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * @padding1: reserved for future, not used, has to be zeroed + * @name_len: volume name length + * @padding2: reserved for future, not used, has to be zeroed + * @name: volume name + * + * This structure is used by user-space programs when creating new volumes. The + * @used_bytes field is only necessary when creating static volumes. + * + * The @alignment field specifies the required alignment of the volume logical + * eraseblock. This means, that the size of logical eraseblocks will be aligned + * to this number, i.e., + * (UBI device logical eraseblock size) mod (@alignment) = 0. + * + * To put it differently, the logical eraseblock of this volume may be slightly + * shortened in order to make it properly aligned. The alignment has to be + * multiple of the flash minimal input/output unit, or %1 to utilize the entire + * available space of logical eraseblocks. + * + * The @alignment field may be useful, for example, when one wants to maintain + * a block device on top of an UBI volume. In this case, it is desirable to fit + * an integer number of blocks in logical eraseblocks of this UBI volume. With + * alignment it is possible to update this volume using plane UBI volume image + * BLOBs, without caring about how to properly align them. + */ +struct ubi_mkvol_req { + int32_t vol_id; + int32_t alignment; + int64_t bytes; + int8_t vol_type; + int8_t padding1; + int16_t name_len; + int8_t padding2[4]; + char name[UBI_MAX_VOLUME_NAME + 1]; +} __attribute__((packed)); + +/** + * struct ubi_rsvol_req - a data structure used in volume re-size requests. + * @vol_id: ID of the volume to re-size + * @bytes: new size of the volume in bytes + * + * Re-sizing is possible for both dynamic and static volumes. But while dynamic + * volumes may be re-sized arbitrarily, static volumes cannot be made to be + * smaller than the number of bytes they bear. To arbitrarily shrink a static + * volume, it must be wiped out first (by means of volume update operation with + * zero number of bytes). + */ +struct ubi_rsvol_req { + int64_t bytes; + int32_t vol_id; +} __attribute__((packed)); + +/** + * struct ubi_rnvol_req - volumes re-name request. + * @count: count of volumes to re-name + * @padding1: reserved for future, not used, has to be zeroed + * @vol_id: ID of the volume to re-name + * @name_len: name length + * @padding2: reserved for future, not used, has to be zeroed + * @name: new volume name + * + * UBI allows to re-name up to %32 volumes at one go. The count of volumes to + * re-name is specified in the @count field. The ID of the volumes to re-name + * and the new names are specified in the @vol_id and @name fields. + * + * The UBI volume re-name operation is atomic, which means that should power cut + * happen, the volumes will have either old name or new name. So the possible + * use-cases of this command is atomic upgrade. Indeed, to upgrade, say, volumes + * A and B one may create temporary volumes %A1 and %B1 with the new contents, + * then atomically re-name A1->A and B1->B, in which case old %A and %B will + * be removed. + * + * If it is not desirable to remove old A and B, the re-name request has to + * contain 4 entries: A1->A, A->A1, B1->B, B->B1, in which case old A1 and B1 + * become A and B, and old A and B will become A1 and B1. + * + * It is also OK to request: A1->A, A1->X, B1->B, B->Y, in which case old A1 + * and B1 become A and B, and old A and B become X and Y. + * + * In other words, in case of re-naming into an existing volume name, the + * existing volume is removed, unless it is re-named as well at the same + * re-name request. + */ +struct ubi_rnvol_req { + int32_t count; + int8_t padding1[12]; + struct { + int32_t vol_id; + int16_t name_len; + int8_t padding2[2]; + char name[UBI_MAX_VOLUME_NAME + 1]; + } ents[UBI_MAX_RNVOL]; +} __attribute__((packed)); + +/** + * struct ubi_leb_change_req - a data structure used in atomic LEB change + * requests. + * @lnum: logical eraseblock number to change + * @bytes: how many bytes will be written to the logical eraseblock + * @dtype: pass "3" for better compatibility with old kernels + * @padding: reserved for future, not used, has to be zeroed + * + * The @dtype field used to inform UBI about what kind of data will be written + * to the LEB: long term (value 1), short term (value 2), unknown (value 3). + * UBI tried to pick a PEB with lower erase counter for short term data and a + * PEB with higher erase counter for long term data. But this was not really + * used because users usually do not know this and could easily mislead UBI. We + * removed this feature in May 2012. UBI currently just ignores the @dtype + * field. But for better compatibility with older kernels it is recommended to + * set @dtype to 3 (unknown). + */ +struct ubi_leb_change_req { + int32_t lnum; + int32_t bytes; + int8_t dtype; /* obsolete, do not use! */ + int8_t padding[7]; +} __attribute__((packed)); + +/** + * struct ubi_map_req - a data structure used in map LEB requests. + * @dtype: pass "3" for better compatibility with old kernels + * @lnum: logical eraseblock number to unmap + * @padding: reserved for future, not used, has to be zeroed + */ +struct ubi_map_req { + int32_t lnum; + int8_t dtype; /* obsolete, do not use! */ + int8_t padding[3]; +} __attribute__((packed)); + + +/** + * struct ubi_set_vol_prop_req - a data structure used to set an UBI volume + * property. + * @property: property to set (%UBI_VOL_PROP_DIRECT_WRITE) + * @padding: reserved for future, not used, has to be zeroed + * @value: value to set + */ +struct ubi_set_vol_prop_req { + uint8_t property; + uint8_t padding[7]; + uint64_t value; +} __attribute__((packed)); + +#endif /* __UBI_USER_H__ */ diff --git a/src/system/mtdutils/include/mtd_swab.h b/src/system/mtdutils/include/mtd_swab.h new file mode 100644 index 000000000..c3340a643 --- /dev/null +++ b/src/system/mtdutils/include/mtd_swab.h @@ -0,0 +1,51 @@ +#ifndef MTD_SWAB_H +#define MTD_SWAB_H + +#include + +#define swab16(x) \ + ((uint16_t)( \ + (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \ + (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) )) +#define swab32(x) \ + ((uint32_t)( \ + (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) )) + +#define swab64(x) \ + ((uint64_t)( \ + (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \ + (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ + (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ + (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ + (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ + (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ + (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ + (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) )) + + +#if __BYTE_ORDER == __BIG_ENDIAN +#define cpu_to_le16(x) ({ uint16_t _x = x; swab16(_x); }) +#define cpu_to_le32(x) ({ uint32_t _x = x; swab32(_x); }) +#define cpu_to_le64(x) ({ uint64_t _x = x; swab64(_x); }) +#define cpu_to_be16(x) (x) +#define cpu_to_be32(x) (x) +#define cpu_to_be64(x) (x) +#else +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_le64(x) (x) +#define cpu_to_be16(x) ({ uint16_t _x = x; swab16(_x); }) +#define cpu_to_be32(x) ({ uint32_t _x = x; swab32(_x); }) +#define cpu_to_be64(x) ({ uint64_t _x = x; swab64(_x); }) +#endif +#define le16_to_cpu(x) cpu_to_le16(x) +#define be16_to_cpu(x) cpu_to_be16(x) +#define le32_to_cpu(x) cpu_to_le32(x) +#define be32_to_cpu(x) cpu_to_be32(x) +#define le64_to_cpu(x) cpu_to_le64(x) +#define be64_to_cpu(x) cpu_to_be64(x) + +#endif diff --git a/src/system/mtdutils/include/xalloc.h b/src/system/mtdutils/include/xalloc.h new file mode 100644 index 000000000..deb14b675 --- /dev/null +++ b/src/system/mtdutils/include/xalloc.h @@ -0,0 +1,106 @@ +/* + * memory wrappers + * + * Copyright (c) Artem Bityutskiy, 2007, 2008 + * Copyright 2001, 2002 Red Hat, Inc. + * 2001 David A. Schleef + * 2002 Axis Communications AB + * 2001, 2002 Erik Andersen + * 2004 University of Szeged, Hungary + * 2006 KaiGai Kohei + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MTD_UTILS_XALLOC_H__ +#define __MTD_UTILS_XALLOC_H__ + +#include +#include +#include + +/* + * Mark these functions as unused so that gcc does not emit warnings + * when people include this header but don't use every function. + */ + +__attribute__((unused)) +static void *xmalloc(size_t size) +{ + void *ptr = malloc(size); + + if (ptr == NULL && size != 0) + sys_errmsg("out of memory"); + return ptr; +} + +__attribute__((unused)) +static void *xcalloc(size_t nmemb, size_t size) +{ + void *ptr = calloc(nmemb, size); + + if (ptr == NULL && nmemb != 0 && size != 0) + sys_errmsg("out of memory"); + return ptr; +} + +__attribute__((unused)) +static void *xzalloc(size_t size) +{ + return xcalloc(1, size); +} + +__attribute__((unused)) +static void *xrealloc(void *ptr, size_t size) +{ + ptr = realloc(ptr, size); + if (ptr == NULL && size != 0) + sys_errmsg("out of memory"); + return ptr; +} + +__attribute__((unused)) +static char *xstrdup(const char *s) +{ + char *t; + + if (s == NULL) + return NULL; + t = strdup(s); + if (t == NULL) + sys_errmsg("out of memory"); + return t; +} + +#ifdef _GNU_SOURCE + +__attribute__((unused)) +static int xasprintf(char **strp, const char *fmt, ...) +{ + int cnt; + va_list ap; + + va_start(ap, fmt); + cnt = vasprintf(strp, fmt, ap); + va_end(ap); + + if (cnt == -1) + sys_errmsg("out of memory"); + + return cnt; +} +#endif + +#endif /* !__MTD_UTILS_XALLOC_H__ */ diff --git a/src/system/mtdutils/lib/libcrc32.cpp b/src/system/mtdutils/lib/libcrc32.cpp new file mode 100644 index 000000000..fb4934cd5 --- /dev/null +++ b/src/system/mtdutils/lib/libcrc32.cpp @@ -0,0 +1,104 @@ +/* + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + * + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + * + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1 + * + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly + * + * The feedback terms table consists of 256, 32-bit entries. Notes + * + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera + * tions for all combinations of data and CRC register values + * + * The values must be right-shifted by eight bits by the "updcrc + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions + * polynomial $edb88320 + */ + +#include + +static const uint32_t crc32_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +uint32_t mtd_crc32(uint32_t val, const void *ss, int len) +{ + const unsigned char *s = (unsigned char *)ss; + + while (--len >= 0) + val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); + return val; +} diff --git a/src/system/mtdutils/lib/libfec.cpp b/src/system/mtdutils/lib/libfec.cpp new file mode 100644 index 000000000..4a250047c --- /dev/null +++ b/src/system/mtdutils/lib/libfec.cpp @@ -0,0 +1,903 @@ +/* + * fec.c -- forward error correction based on Vandermonde matrices + * 980624 + * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it) + * + * Portions derived from code by Phil Karn (karn@ka9q.ampr.org), + * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari + * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +/* + * The following parameter defines how many bits are used for + * field elements. The code supports any value from 2 to 16 + * but fastest operation is achieved with 8 bit elements + * This is the only parameter you may want to change. + */ +#ifndef GF_BITS +#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */ +#endif + +#include +#include +#include + +/* + * stuff used for testing purposes only + */ + +#ifdef TEST +#define DEB(x) +#define DDB(x) x +#define DEBUG 0 /* minimal debugging */ +#ifdef MSDOS +#include +struct timeval { + unsigned long ticks; +}; +#define gettimeofday(x, dummy) { (x)->ticks = clock() ; } +#define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC ) +typedef unsigned long u_long ; +typedef unsigned short u_short ; +#else /* typically, unix systems */ +#include +#define DIFF_T(a,b) \ + (1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) ) +#endif + +#define TICK(t) \ + {struct timeval x ; \ + gettimeofday(&x, NULL) ; \ + t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \ + } +#define TOCK(t) \ + { u_long t1 ; TICK(t1) ; \ + if (t1 < t) t = 256000000 + t1 - t ; \ + else t = t1 - t ; \ + if (t == 0) t = 1 ;} + +u_long ticks[10]; /* vars for timekeeping */ +#else +#define DEB(x) +#define DDB(x) +#define TICK(x) +#define TOCK(x) +#endif /* TEST */ + +/* + * You should not need to change anything beyond this point. + * The first part of the file implements linear algebra in GF. + * + * gf is the type used to store an element of the Galois Field. + * Must constain at least GF_BITS bits. + * + * Note: unsigned char will work up to GF(256) but int seems to run + * faster on the Pentium. We use int whenever have to deal with an + * index, since they are generally faster. + */ +#if (GF_BITS < 2 && GF_BITS >16) +#error "GF_BITS must be 2 .. 16" +#endif +#if (GF_BITS <= 8) +typedef unsigned char gf; +#else +typedef unsigned short gf; +#endif + +#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */ + +/* + * Primitive polynomials - see Lin & Costello, Appendix A, + * and Lee & Messerschmitt, p. 453. + */ +static const char *allPp[] = { /* GF_BITS polynomial */ + NULL, /* 0 no code */ + NULL, /* 1 no code */ + "111", /* 2 1+x+x^2 */ + "1101", /* 3 1+x+x^3 */ + "11001", /* 4 1+x+x^4 */ + "101001", /* 5 1+x^2+x^5 */ + "1100001", /* 6 1+x+x^6 */ + "10010001", /* 7 1 + x^3 + x^7 */ + "101110001", /* 8 1+x^2+x^3+x^4+x^8 */ + "1000100001", /* 9 1+x^4+x^9 */ + "10010000001", /* 10 1+x^3+x^10 */ + "101000000001", /* 11 1+x^2+x^11 */ + "1100101000001", /* 12 1+x+x^4+x^6+x^12 */ + "11011000000001", /* 13 1+x+x^3+x^4+x^13 */ + "110000100010001", /* 14 1+x+x^6+x^10+x^14 */ + "1100000000000001", /* 15 1+x+x^15 */ + "11010000000010001" /* 16 1+x+x^3+x^12+x^16 */ +}; + + +/* + * To speed up computations, we have tables for logarithm, exponent + * and inverse of a number. If GF_BITS <= 8, we use a table for + * multiplication as well (it takes 64K, no big deal even on a PDA, + * especially because it can be pre-initialized an put into a ROM!), + * otherwhise we use a table of logarithms. + * In any case the macro gf_mul(x,y) takes care of multiplications. + */ + +static gf gf_exp[2*GF_SIZE]; /* index->poly form conversion table */ +static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */ +static gf inverse[GF_SIZE+1]; /* inverse of field elem. */ + /* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */ + +/* + * modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, + * without a slow divide. + */ +static inline gf +modnn(int x) +{ + while (x >= GF_SIZE) { + x -= GF_SIZE; + x = (x >> GF_BITS) + (x & GF_SIZE); + } + return x; +} + +#define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;} + +/* + * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much + * faster to use a multiplication table. + * + * USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying + * many numbers by the same constant. In this case the first + * call sets the constant, and others perform the multiplications. + * A value related to the multiplication is held in a local variable + * declared with USE_GF_MULC . See usage in addmul1(). + */ +#if (GF_BITS <= 8) +static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1]; + +#define gf_mul(x,y) gf_mul_table[x][y] + +#define USE_GF_MULC register gf * __gf_mulc_ +#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c] +#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x] + +static void +init_mul_table(void) +{ + int i, j; + for (i=0; i< GF_SIZE+1; i++) + for (j=0; j< GF_SIZE+1; j++) + gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j]) ] ; + + for (j=0; j< GF_SIZE+1; j++) + gf_mul_table[0][j] = gf_mul_table[j][0] = 0; +} +#else /* GF_BITS > 8 */ +static inline gf +gf_mul(x,y) +{ + if ( (x) == 0 || (y)==0 ) return 0; + + return gf_exp[gf_log[x] + gf_log[y] ] ; +} +#define init_mul_table() + +#define USE_GF_MULC register gf * __gf_mulc_ +#define GF_MULC0(c) __gf_mulc_ = &gf_exp[ gf_log[c] ] +#define GF_ADDMULC(dst, x) { if (x) dst ^= __gf_mulc_[ gf_log[x] ] ; } +#endif + +/* + * Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] + * Lookup tables: + * index->polynomial form gf_exp[] contains j= \alpha^i; + * polynomial form -> index form gf_log[ j = \alpha^i ] = i + * \alpha=x is the primitive element of GF(2^m) + * + * For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple + * multiplication of two numbers can be resolved without calling modnn + */ + +/* + * i use malloc so many times, it is easier to put checks all in + * one place. + */ +static void * +my_malloc(int sz, const char *err_string) +{ + void *p = malloc( sz ); + if (p == NULL) { + fprintf(stderr, "-- malloc failure allocating %s\n", err_string); + exit(1) ; + } + return p ; +} + +#define NEW_GF_MATRIX(rows, cols) \ + (gf *)my_malloc(rows * cols * sizeof(gf), " ## __LINE__ ## " ) + +/* + * initialize the data structures used for computations in GF. + */ +static void +generate_gf(void) +{ + int i; + gf mask; + const char *Pp = allPp[GF_BITS] ; + + mask = 1; /* x ** 0 = 1 */ + gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */ + /* + * first, generate the (polynomial representation of) powers of \alpha, + * which are stored in gf_exp[i] = \alpha ** i . + * At the same time build gf_log[gf_exp[i]] = i . + * The first GF_BITS powers are simply bits shifted to the left. + */ + for (i = 0; i < GF_BITS; i++, mask <<= 1 ) { + gf_exp[i] = mask; + gf_log[gf_exp[i]] = i; + /* + * If Pp[i] == 1 then \alpha ** i occurs in poly-repr + * gf_exp[GF_BITS] = \alpha ** GF_BITS + */ + if ( Pp[i] == '1' ) + gf_exp[GF_BITS] ^= mask; + } + /* + * now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als + * compute its inverse. + */ + gf_log[gf_exp[GF_BITS]] = GF_BITS; + /* + * Poly-repr of \alpha ** (i+1) is given by poly-repr of + * \alpha ** i shifted left one-bit and accounting for any + * \alpha ** GF_BITS term that may occur when poly-repr of + * \alpha ** i is shifted. + */ + mask = 1 << (GF_BITS - 1 ) ; + for (i = GF_BITS + 1; i < GF_SIZE; i++) { + if (gf_exp[i - 1] >= mask) + gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1); + else + gf_exp[i] = gf_exp[i - 1] << 1; + gf_log[gf_exp[i]] = i; + } + /* + * log(0) is not defined, so use a special value + */ + gf_log[0] = GF_SIZE ; + /* set the extended gf_exp values for fast multiply */ + for (i = 0 ; i < GF_SIZE ; i++) + gf_exp[i + GF_SIZE] = gf_exp[i] ; + + /* + * again special cases. 0 has no inverse. This used to + * be initialized to GF_SIZE, but it should make no difference + * since noone is supposed to read from here. + */ + inverse[0] = 0 ; + inverse[1] = 1; + for (i=2; i<=GF_SIZE; i++) + inverse[i] = gf_exp[GF_SIZE-gf_log[i]]; +} + +/* + * Various linear algebra operations that i use often. + */ + +/* + * addmul() computes dst[] = dst[] + c * src[] + * This is used often, so better optimize it! Currently the loop is + * unrolled 16 times, a good value for 486 and pentium-class machines. + * The case c=0 is also optimized, whereas c=1 is not. These + * calls are unfrequent in my typical apps so I did not bother. + * + * Note that gcc on + */ +#define addmul(dst, src, c, sz) \ + if (c != 0) addmul1(dst, src, c, sz) + +#define UNROLL 16 /* 1, 4, 8, 16 */ +static void +addmul1(gf *dst1, gf *src1, gf c, int sz) +{ + USE_GF_MULC ; + register gf *dst = dst1, *src = src1 ; + gf *lim = &dst[sz - UNROLL + 1] ; + + GF_MULC0(c) ; + +#if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */ + for (; dst < lim ; dst += UNROLL, src += UNROLL ) { + GF_ADDMULC( dst[0] , src[0] ); + GF_ADDMULC( dst[1] , src[1] ); + GF_ADDMULC( dst[2] , src[2] ); + GF_ADDMULC( dst[3] , src[3] ); +#if (UNROLL > 4) + GF_ADDMULC( dst[4] , src[4] ); + GF_ADDMULC( dst[5] , src[5] ); + GF_ADDMULC( dst[6] , src[6] ); + GF_ADDMULC( dst[7] , src[7] ); +#endif +#if (UNROLL > 8) + GF_ADDMULC( dst[8] , src[8] ); + GF_ADDMULC( dst[9] , src[9] ); + GF_ADDMULC( dst[10] , src[10] ); + GF_ADDMULC( dst[11] , src[11] ); + GF_ADDMULC( dst[12] , src[12] ); + GF_ADDMULC( dst[13] , src[13] ); + GF_ADDMULC( dst[14] , src[14] ); + GF_ADDMULC( dst[15] , src[15] ); +#endif + } +#endif + lim += UNROLL - 1 ; + for (; dst < lim; dst++, src++ ) /* final components */ + GF_ADDMULC( *dst , *src ); +} + +/* + * computes C = AB where A is n*k, B is k*m, C is n*m + */ +static void +matmul(gf *a, gf *b, gf *c, int n, int k, int m) +{ + int row, col, i ; + + for (row = 0; row < n ; row++) { + for (col = 0; col < m ; col++) { + gf *pa = &a[ row * k ]; + gf *pb = &b[ col ]; + gf acc = 0 ; + for (i = 0; i < k ; i++, pa++, pb += m ) + acc ^= gf_mul( *pa, *pb ) ; + c[ row * m + col ] = acc ; + } + } +} + +#ifdef DEBUG +/* + * returns 1 if the square matrix is identiy + * (only for test) + */ +static int +is_identity(gf *m, int k) +{ + int row, col ; + for (row=0; row 1) { + fprintf(stderr, "singular matrix\n"); + goto fail ; + } + } + } + } + if (icol == -1) { + fprintf(stderr, "XXX pivot not found!\n"); + goto fail ; + } +found_piv: + ++(ipiv[icol]) ; + /* + * swap rows irow and icol, so afterwards the diagonal + * element will be correct. Rarely done, not worth + * optimizing. + */ + if (irow != icol) { + for (ix = 0 ; ix < k ; ix++ ) { + SWAP( src[irow*k + ix], src[icol*k + ix], gf) ; + } + } + indxr[col] = irow ; + indxc[col] = icol ; + pivot_row = &src[icol*k] ; + c = pivot_row[icol] ; + if (c == 0) { + fprintf(stderr, "singular matrix 2\n"); + goto fail ; + } + if (c != 1 ) { /* otherwhise this is a NOP */ + /* + * this is done often , but optimizing is not so + * fruitful, at least in the obvious ways (unrolling) + */ + DEB( pivswaps++ ; ) + c = inverse[ c ] ; + pivot_row[icol] = 1 ; + for (ix = 0 ; ix < k ; ix++ ) + pivot_row[ix] = gf_mul(c, pivot_row[ix] ); + } + /* + * from all rows, remove multiples of the selected row + * to zero the relevant entry (in fact, the entry is not zero + * because we know it must be zero). + * (Here, if we know that the pivot_row is the identity, + * we can optimize the addmul). + */ + id_row[icol] = 1; + if (memcmp(pivot_row, id_row, k*sizeof(gf)) != 0) { + for (p = src, ix = 0 ; ix < k ; ix++, p += k ) { + if (ix != icol) { + c = p[icol] ; + p[icol] = 0 ; + addmul(p, pivot_row, c, k ); + } + } + } + id_row[icol] = 0; + } /* done all columns */ + for (col = k-1 ; col >= 0 ; col-- ) { + if (indxr[col] <0 || indxr[col] >= k) + fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]); + else if (indxc[col] <0 || indxc[col] >= k) + fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]); + else + if (indxr[col] != indxc[col] ) { + for (row = 0 ; row < k ; row++ ) { + SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ; + } + } + } + error = 0 ; +fail: + free(indxc); + free(indxr); + free(ipiv); + free(id_row); + free(temp_row); + return error ; +} + +/* + * fast code for inverting a vandermonde matrix. + * XXX NOTE: It assumes that the matrix + * is not singular and _IS_ a vandermonde matrix. Only uses + * the second column of the matrix, containing the p_i's. + * + * Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but + * largely revised for my purposes. + * p = coefficients of the matrix (p_i) + * q = values of the polynomial (known) + */ + +int +invert_vdm(gf *src, int k) +{ + int i, j, row, col ; + gf *b, *c, *p; + gf t, xx ; + + if (k == 1) /* degenerate case, matrix must be p^0 = 1 */ + return 0 ; + /* + * c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1 + * b holds the coefficient for the matrix inversion + */ + c = NEW_GF_MATRIX(1, k); + b = NEW_GF_MATRIX(1, k); + + p = NEW_GF_MATRIX(1, k); + + for ( j=1, i = 0 ; i < k ; i++, j+=k ) { + c[i] = 0 ; + p[i] = src[j] ; /* p[i] */ + } + /* + * construct coeffs. recursively. We know c[k] = 1 (implicit) + * and start P_0 = x - p_0, then at each stage multiply by + * x - p_i generating P_i = x P_{i-1} - p_i P_{i-1} + * After k steps we are done. + */ + c[k-1] = p[0] ; /* really -p(0), but x = -x in GF(2^m) */ + for (i = 1 ; i < k ; i++ ) { + gf p_i = p[i] ; /* see above comment */ + for (j = k-1 - ( i - 1 ) ; j < k-1 ; j++ ) + c[j] ^= gf_mul( p_i, c[j+1] ) ; + c[k-1] ^= p_i ; + } + + for (row = 0 ; row < k ; row++ ) { + /* + * synthetic division etc. + */ + xx = p[row] ; + t = 1 ; + b[k-1] = 1 ; /* this is in fact c[k] */ + for (i = k-2 ; i >= 0 ; i-- ) { + b[i] = c[i+1] ^ gf_mul(xx, b[i+1]) ; + t = gf_mul(xx, t) ^ b[i] ; + } + for (col = 0 ; col < k ; col++ ) + src[col*k + row] = gf_mul(inverse[t], b[col] ); + } + free(c) ; + free(b) ; + free(p) ; + return 0 ; +} + +static int fec_initialized = 0 ; +static void +init_fec(void) +{ + TICK(ticks[0]); + generate_gf(); + TOCK(ticks[0]); + DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);) + TICK(ticks[0]); + init_mul_table(); + TOCK(ticks[0]); + DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);) + fec_initialized = 1 ; +} + +/* + * This section contains the proper FEC encoding/decoding routines. + * The encoding matrix is computed starting with a Vandermonde matrix, + * and then transforming it into a systematic matrix. + */ + +#define FEC_MAGIC 0xFECC0DEC + +struct fec_parms { + u_long magic ; + int k, n ; /* parameters of the code */ + gf *enc_matrix ; +} ; +#define COMP_FEC_MAGIC(fec) \ + (((FEC_MAGIC ^ (fec)->k) ^ (fec)->n) ^ (unsigned long)((fec)->enc_matrix)) + +void +fec_free(struct fec_parms *p) +{ + if (p==NULL || p->magic != COMP_FEC_MAGIC(p)) { + fprintf(stderr, "bad parameters to fec_free\n"); + return ; + } + free(p->enc_matrix); + free(p); +} + +/* + * create a new encoder, returning a descriptor. This contains k,n and + * the encoding matrix. + */ +struct fec_parms * +fec_new(int k, int n) +{ + int row, col ; + gf *p, *tmp_m ; + + struct fec_parms *retval ; + + if (fec_initialized == 0) + init_fec(); + + if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n ) { + fprintf(stderr, "Invalid parameters k %d n %d GF_SIZE %d\n", + k, n, GF_SIZE ); + return NULL ; + } + retval = reinterpret_cast(my_malloc(sizeof(struct fec_parms), "new_code")); + retval->k = k ; + retval->n = n ; + retval->enc_matrix = NEW_GF_MATRIX(n, k); + retval->magic = COMP_FEC_MAGIC(retval); + tmp_m = NEW_GF_MATRIX(n, k); + /* + * fill the matrix with powers of field elements, starting from 0. + * The first row is special, cannot be computed with exp. table. + */ + tmp_m[0] = 1 ; + for (col = 1; col < k ; col++) + tmp_m[col] = 0 ; + for (p = tmp_m + k, row = 0; row < n-1 ; row++, p += k) { + for ( col = 0 ; col < k ; col ++ ) + p[col] = gf_exp[modnn(row*col)]; + } + + /* + * quick code to build systematic matrix: invert the top + * k*k vandermonde matrix, multiply right the bottom n-k rows + * by the inverse, and construct the identity matrix at the top. + */ + TICK(ticks[3]); + invert_vdm(tmp_m, k); /* much faster than invert_mat */ + matmul(tmp_m + k*k, tmp_m, retval->enc_matrix + k*k, n - k, k, k); + /* + * the upper matrix is I so do not bother with a slow multiply + */ + memset(retval->enc_matrix, '\0', k*k*sizeof(gf) ); + for (p = retval->enc_matrix, col = 0 ; col < k ; col++, p += k+1 ) + *p = 1 ; + free(tmp_m); + TOCK(ticks[3]); + + DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n", + ticks[3]);) + DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");) + return retval ; +} + +/* + * fec_encode accepts as input pointers to n data packets of size sz, + * and produces as output a packet pointed to by fec, computed + * with index "index". + */ +void +fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz) +{ + int k = code->k ; + + if (GF_BITS > 8) + sz /= 2 ; + + if (index < k) + memcpy(fec, src[index], sz*sizeof(gf) ) ; + else if (index < code->n) { + gf* p = &(code->enc_matrix[index*k] ); + memset(fec, '\0', sz*sizeof(gf)); + for (int i = 0; i < k ; i++) + addmul(fec, src[i], p[i], sz ) ; + } else + fprintf(stderr, "Invalid index %d (max %d)\n", + index, code->n - 1 ); +} + +void fec_encode_linear(struct fec_parms *code, gf *src, gf *fec, int index, int sz) +{ + int k = code->k ; + + if (GF_BITS > 8) + sz /= 2 ; + + if (index < k) + memcpy(fec, src + (index * sz), sz*sizeof(gf) ) ; + else if (index < code->n) { + gf* p = &(code->enc_matrix[index*k] ); + memset(fec, '\0', sz*sizeof(gf)); + for (int i = 0; i < k ; i++) + addmul(fec, src + (i * sz), p[i], sz ) ; + } else + fprintf(stderr, "Invalid index %d (max %d)\n", + index, code->n - 1 ); +} +/* + * shuffle move src packets in their position + */ +static int +shuffle(gf *pkt[], int index[], int k) +{ + int i; + + for ( i = 0 ; i < k ; ) { + if (index[i] >= k || index[i] == i) + i++ ; + else { + /* + * put pkt in the right position (first check for conflicts). + */ + int c = index[i] ; + + if (index[c] == c) { + DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);) + return 1 ; + } + SWAP(index[i], index[c], int) ; + SWAP(pkt[i], pkt[c], gf *) ; + } + } + DEB( /* just test that it works... */ + for ( i = 0 ; i < k ; i++ ) { + if (index[i] < k && index[i] != i) { + fprintf(stderr, "shuffle: after\n"); + for (i=0; ik ; + gf *p, *matrix = NEW_GF_MATRIX(k, k); + + TICK(ticks[9]); + for (i = 0, p = matrix ; i < k ; i++, p += k ) { +#if 1 /* this is simply an optimization, not very useful indeed */ + if (index[i] < k) { + memset(p, '\0', k*sizeof(gf) ); + p[i] = 1 ; + } else +#endif + if (index[i] < code->n ) + memcpy(p, &(code->enc_matrix[index[i]*k]), k*sizeof(gf) ); + else { + fprintf(stderr, "decode: invalid index %d (max %d)\n", + index[i], code->n - 1 ); + free(matrix) ; + return NULL ; + } + } + TICK(ticks[9]); + if (invert_mat(matrix, k)) { + free(matrix); + matrix = NULL ; + } + TOCK(ticks[9]); + return matrix ; +} + +/* + * fec_decode receives as input a vector of packets, the indexes of + * packets, and produces the correct vector as output. + * + * Input: + * code: pointer to code descriptor + * pkt: pointers to received packets. They are modified + * to store the output packets (in place) + * index: pointer to packet indexes (modified) + * sz: size of each packet + */ +int +fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz) +{ + gf *m_dec ; + gf **new_pkt ; + int row, col , k = code->k ; + + if (GF_BITS > 8) + sz /= 2 ; + + if (shuffle(pkt, index, k)) /* error if true */ + return 1 ; + m_dec = build_decode_matrix(code, index); + + if (m_dec == NULL) + return 1 ; /* error */ + /* + * do the actual decoding + */ + new_pkt = (gf**)my_malloc (k * sizeof (gf * ), "new pkt pointers" ); + for (row = 0 ; row < k ; row++ ) { + if (index[row] >= k) { + new_pkt[row] = (gf*)my_malloc (sz * sizeof (gf), "new pkt buffer" ); + memset(new_pkt[row], '\0', sz * sizeof(gf) ) ; + for (col = 0 ; col < k ; col++ ) + addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz) ; + } + } + /* + * move pkts to their final destination + */ + for (row = 0 ; row < k ; row++ ) { + if (index[row] >= k) { + memcpy(pkt[row], new_pkt[row], sz*sizeof(gf)); + free(new_pkt[row]); + } + } + free(new_pkt); + free(m_dec); + + return 0; +} + +/*********** end of FEC code -- beginning of test code ************/ + +#if (TEST || DEBUG) +void +test_gf(void) +{ + int i ; + /* + * test gf tables. Sufficiently tested... + */ + for (i=0; i<= GF_SIZE; i++) { + if (gf_exp[gf_log[i]] != i) + fprintf(stderr, "bad exp/log i %d log %d exp(log) %d\n", + i, gf_log[i], gf_exp[gf_log[i]]); + + if (i != 0 && gf_mul(i, inverse[i]) != 1) + fprintf(stderr, "bad mul/inv i %d inv %d i*inv(i) %d\n", + i, inverse[i], gf_mul(i, inverse[i]) ); + if (gf_mul(0,i) != 0) + fprintf(stderr, "bad mul table 0,%d\n",i); + if (gf_mul(i,0) != 0) + fprintf(stderr, "bad mul table %d,0\n",i); + } +} +#endif /* TEST */ diff --git a/src/system/mtdutils/lib/libmtd.cpp b/src/system/mtdutils/lib/libmtd.cpp new file mode 100644 index 000000000..da32324ba --- /dev/null +++ b/src/system/mtdutils/lib/libmtd.cpp @@ -0,0 +1,1419 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem Bityutskiy + * + * MTD library. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "libmtd_int.h" +#include "common.h" + +/** + * mkpath - compose full path from 2 given components. + * @path: the first component + * @name: the second component + * + * This function returns the resulting path in case of success and %NULL in + * case of failure. + */ +static char *mkpath(const char *path, const char *name) +{ + char *n; + size_t len1 = strlen(path); + size_t len2 = strlen(name); + + n = (char*)xmalloc(len1 + len2 + 2); + + memcpy(n, path, len1); + if (n[len1 - 1] != '/') + n[len1++] = '/'; + + memcpy(n + len1, name, len2 + 1); + return n; +} + +/** + * read_data - read data from a file. + * @file: the file to read from + * @buf: the buffer to read to + * @buf_len: buffer length + * + * This function returns number of read bytes in case of success and %-1 in + * case of failure. Note, if the file contains more then @buf_len bytes of + * date, this function fails with %EINVAL error code. + */ +static int read_data(const char *file, void *buf, int buf_len) +{ + int fd, rd, tmp, tmp1; + + fd = open(file, O_RDONLY | O_CLOEXEC); + if (fd == -1) + return -1; + + rd = read(fd, buf, buf_len); + if (rd == -1) { + sys_errmsg("cannot read \"%s\"", file); + goto out_error; + } + + if (rd == buf_len) { + errmsg("contents of \"%s\" is too long", file); + errno = EINVAL; + goto out_error; + } + + ((char *)buf)[rd] = '\0'; + + /* Make sure all data is read */ + tmp1 = read(fd, &tmp, 1); + if (tmp1 == 1) { + sys_errmsg("cannot read \"%s\"", file); + goto out_error; + } + if (tmp1) { + errmsg("file \"%s\" contains too much data (> %d bytes)", + file, buf_len); + errno = EINVAL; + goto out_error; + } + + if (close(fd)) { + sys_errmsg("close failed on \"%s\"", file); + return -1; + } + + return rd; + +out_error: + close(fd); + return -1; +} + +/** + * read_major - read major and minor numbers from a file. + * @file: name of the file to read from + * @major: major number is returned here + * @minor: minor number is returned here + * + * This function returns % in case of success, and %-1 in case of failure. + */ +static int read_major(const char *file, int *major, int *minor) +{ + int ret; + char buf[50]; + + ret = read_data(file, buf, 50); + if (ret < 0) + return ret; + + ret = sscanf(buf, "%d:%d\n", major, minor); + if (ret != 2) { + errno = EINVAL; + return errmsg("\"%s\" does not have major:minor format", file); + } + + if (*major < 0 || *minor < 0) { + errno = EINVAL; + return errmsg("bad major:minor %d:%d in \"%s\"", + *major, *minor, file); + } + + return 0; +} + +/** + * dev_get_major - get major and minor numbers of an MTD device. + * @lib: libmtd descriptor + * @mtd_num: MTD device number + * @major: major number is returned here + * @minor: minor number is returned here + * + * This function returns zero in case of success and %-1 in case of failure. + */ +static int dev_get_major(struct libmtd *lib, int mtd_num, int *major, int *minor) +{ + char file[strlen(lib->mtd_dev) + 50]; + + sprintf(file, lib->mtd_dev, mtd_num); + return read_major(file, major, minor); +} + +/** + * dev_read_data - read data from an MTD device's sysfs file. + * @patt: file pattern to read from + * @mtd_num: MTD device number + * @buf: buffer to read to + * @buf_len: buffer length + * + * This function returns number of read bytes in case of success and %-1 in + * case of failure. + */ +static int dev_read_data(const char *patt, int mtd_num, void *buf, int buf_len) +{ + char file[strlen(patt) + 100]; + + sprintf(file, patt, mtd_num); + return read_data(file, buf, buf_len); +} + +/** + * read_hex_ll - read a hex 'long long' value from a file. + * @file: the file to read from + * @value: the result is stored here + * + * This function reads file @file and interprets its contents as hexadecimal + * 'long long' integer. If this is not true, it fails with %EINVAL error code. + * Returns %0 in case of success and %-1 in case of failure. + */ +static int read_hex_ll(const char *file, long long *value) +{ + int fd, rd; + char buf[50]; + + fd = open(file, O_RDONLY | O_CLOEXEC); + if (fd == -1) + return -1; + + rd = read(fd, buf, sizeof(buf)); + if (rd == -1) { + sys_errmsg("cannot read \"%s\"", file); + goto out_error; + } + if (rd == sizeof(buf)) { + errmsg("contents of \"%s\" is too long", file); + errno = EINVAL; + goto out_error; + } + buf[rd] = '\0'; + + if (sscanf(buf, "%llx\n", value) != 1) { + errmsg("cannot read integer from \"%s\"\n", file); + errno = EINVAL; + goto out_error; + } + + if (*value < 0) { + errmsg("negative value %lld in \"%s\"", *value, file); + errno = EINVAL; + goto out_error; + } + + if (close(fd)) + return sys_errmsg("close failed on \"%s\"", file); + + return 0; + +out_error: + close(fd); + return -1; +} + +/** + * read_pos_ll - read a positive 'long long' value from a file. + * @file: the file to read from + * @value: the result is stored here + * + * This function reads file @file and interprets its contents as a positive + * 'long long' integer. If this is not true, it fails with %EINVAL error code. + * Returns %0 in case of success and %-1 in case of failure. + */ +static int read_pos_ll(const char *file, long long *value) +{ + int fd, rd; + char buf[50]; + + fd = open(file, O_RDONLY | O_CLOEXEC); + if (fd == -1) + return -1; + + rd = read(fd, buf, 50); + if (rd == -1) { + sys_errmsg("cannot read \"%s\"", file); + goto out_error; + } + if (rd == 50) { + errmsg("contents of \"%s\" is too long", file); + errno = EINVAL; + goto out_error; + } + + if (sscanf(buf, "%lld\n", value) != 1) { + errmsg("cannot read integer from \"%s\"\n", file); + errno = EINVAL; + goto out_error; + } + + if (*value < 0) { + errmsg("negative value %lld in \"%s\"", *value, file); + errno = EINVAL; + goto out_error; + } + + if (close(fd)) + return sys_errmsg("close failed on \"%s\"", file); + + return 0; + +out_error: + close(fd); + return -1; +} + +/** + * read_hex_int - read an 'int' value from a file. + * @file: the file to read from + * @value: the result is stored here + * + * This function is the same as 'read_pos_ll()', but it reads an 'int' + * value, not 'long long'. + */ +static int read_hex_int(const char *file, int *value) +{ + long long res; + + if (read_hex_ll(file, &res)) + return -1; + + /* Make sure the value has correct range */ + if (res > INT_MAX || res < INT_MIN) { + errmsg("value %lld read from file \"%s\" is out of range", + res, file); + errno = EINVAL; + return -1; + } + + *value = res; + return 0; +} + +/** + * read_pos_int - read a positive 'int' value from a file. + * @file: the file to read from + * @value: the result is stored here + * + * This function is the same as 'read_pos_ll()', but it reads an 'int' + * value, not 'long long'. + */ +static int read_pos_int(const char *file, int *value) +{ + long long res; + + if (read_pos_ll(file, &res)) + return -1; + + /* Make sure the value is not too big */ + if (res > INT_MAX) { + errmsg("value %lld read from file \"%s\" is out of range", + res, file); + errno = EINVAL; + return -1; + } + + *value = res; + return 0; +} + +/** + * dev_read_hex_int - read an hex 'int' value from an MTD device sysfs file. + * @patt: file pattern to read from + * @mtd_num: MTD device number + * @value: the result is stored here + * + * This function returns %0 in case of success and %-1 in case of failure. + */ +static int dev_read_hex_int(const char *patt, int mtd_num, int *value) +{ + char file[strlen(patt) + 50]; + + sprintf(file, patt, mtd_num); + return read_hex_int(file, value); +} + +/** + * dev_read_pos_int - read a positive 'int' value from an MTD device sysfs file. + * @patt: file pattern to read from + * @mtd_num: MTD device number + * @value: the result is stored here + * + * This function returns %0 in case of success and %-1 in case of failure. + */ +static int dev_read_pos_int(const char *patt, int mtd_num, int *value) +{ + char file[strlen(patt) + 50]; + + sprintf(file, patt, mtd_num); + return read_pos_int(file, value); +} + +/** + * dev_read_pos_ll - read a positive 'long long' value from an MTD device sysfs file. + * @patt: file pattern to read from + * @mtd_num: MTD device number + * @value: the result is stored here + * + * This function returns %0 in case of success and %-1 in case of failure. + */ +static int dev_read_pos_ll(const char *patt, int mtd_num, long long *value) +{ + char file[strlen(patt) + 50]; + + sprintf(file, patt, mtd_num); + return read_pos_ll(file, value); +} + +/** + * type_str2int - convert MTD device type to integer. + * @str: MTD device type string to convert + * + * This function converts MTD device type string @str, read from sysfs, into an + * integer. + */ +static int type_str2int(const char *str) +{ + if (!strcmp(str, "nand")) + return MTD_NANDFLASH; + if (!strcmp(str, "nor")) + return MTD_NORFLASH; + if (!strcmp(str, "rom")) + return MTD_ROM; + if (!strcmp(str, "absent")) + return MTD_ABSENT; + if (!strcmp(str, "dataflash")) + return MTD_DATAFLASH; + if (!strcmp(str, "ram")) + return MTD_RAM; + if (!strcmp(str, "ubi")) + return MTD_UBIVOLUME; + return -1; +} + +/** + * dev_node2num - find UBI device number by its character device node. + * @lib: MTD library descriptor + * @node: name of the MTD device node + * @mtd_num: MTD device number is returned here + * + * This function returns %0 in case of success and %-1 in case of failure. + */ +static int dev_node2num(struct libmtd *lib, const char *node, int *mtd_num) +{ + struct stat st; + int i, mjr, mnr; + struct mtd_info info; + + if (stat(node, &st)) + return sys_errmsg("cannot get information about \"%s\"", node); + + if (!S_ISCHR(st.st_mode)) { + errmsg("\"%s\" is not a character device", node); + errno = EINVAL; + return -1; + } + + mjr = major(st.st_rdev); + mnr = minor(st.st_rdev); + + if (mtd_get_info((libmtd_t *)lib, &info)) + return -1; + + for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; i++) { + int mjr1, mnr1, ret; + + ret = dev_get_major(lib, i, &mjr1, &mnr1); + if (ret) { + if (errno == ENOENT) + continue; + if (!errno) + break; + return -1; + } + + if (mjr1 == mjr && mnr1 == mnr) { + errno = 0; + *mtd_num = i; + return 0; + } + } + + errno = ENODEV; + return -1; +} + +/** + * sysfs_is_supported - check whether the MTD sub-system supports MTD. + * @lib: MTD library descriptor + * + * The Linux kernel MTD subsystem gained MTD support starting from kernel + * 2.6.30 and libmtd tries to use sysfs interface if possible, because the NAND + * sub-page size is available there (and not available at all in pre-sysfs + * kernels). + * + * Very old kernels did not have "/sys/class/mtd" directory. Not very old + * kernels (e.g., 2.6.29) did have "/sys/class/mtd/mtdX" directories, by there + * were no files there, e.g., the "name" file was not present. So all we can do + * is to check for a "/sys/class/mtd/mtdX/name" file. But this is not a + * reliable check, because if this is a new system with no MTD devices - we'll + * treat it as a pre-sysfs system. + */ +static int sysfs_is_supported(struct libmtd *lib) +{ + int fd, num = -1; + DIR *sysfs_mtd; + char file[strlen(lib->mtd_name) + 10]; + + sysfs_mtd = opendir(lib->sysfs_mtd); + if (!sysfs_mtd) { + if (errno == ENOENT) { + errno = 0; + return 0; + } + return sys_errmsg("cannot open \"%s\"", lib->sysfs_mtd); + } + + /* + * First of all find an "mtdX" directory. This is needed because there + * may be, for example, mtd1 but no mtd0. + */ + while (1) { + int ret, mtd_num; + char tmp_buf[256]; + struct dirent *dirent; + + dirent = readdir(sysfs_mtd); + if (!dirent) + break; + + if (strlen(dirent->d_name) >= 255) { + errmsg("invalid entry in %s: \"%s\"", + lib->sysfs_mtd, dirent->d_name); + errno = EINVAL; + closedir(sysfs_mtd); + return -1; + } + + ret = sscanf(dirent->d_name, MTD_NAME_PATT"%255s", + &mtd_num, tmp_buf); + if (ret == 1) { + num = mtd_num; + break; + } + } + + if (closedir(sysfs_mtd)) + return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_mtd); + + if (num == -1) + /* No mtd device, treat this as pre-sysfs system */ + return 0; + + sprintf(file, lib->mtd_name, num); + fd = open(file, O_RDONLY | O_CLOEXEC); + if (fd == -1) + return 0; + + if (close(fd)) { + sys_errmsg("close failed on \"%s\"", file); + return -1; + } + + return 1; +} + +libmtd_t libmtd_open(void) +{ + struct libmtd *lib; + + lib = reinterpret_cast(xzalloc(sizeof(*lib))); + + lib->offs64_ioctls = OFFS64_IOCTLS_UNKNOWN; + + lib->sysfs_mtd = mkpath("/sys", SYSFS_MTD); + if (!lib->sysfs_mtd) + goto out_error; + + lib->mtd = mkpath(lib->sysfs_mtd, MTD_NAME_PATT); + if (!lib->mtd) + goto out_error; + + lib->mtd_name = mkpath(lib->mtd, MTD_NAME); + if (!lib->mtd_name) + goto out_error; + + if (!sysfs_is_supported(lib)) { + free(lib->mtd); + free(lib->sysfs_mtd); + free(lib->mtd_name); + lib->mtd_name = lib->mtd = lib->sysfs_mtd = NULL; + return lib; + } + + lib->mtd_dev = mkpath(lib->mtd, MTD_DEV); + if (!lib->mtd_dev) + goto out_error; + + lib->mtd_type = mkpath(lib->mtd, MTD_TYPE); + if (!lib->mtd_type) + goto out_error; + + lib->mtd_eb_size = mkpath(lib->mtd, MTD_EB_SIZE); + if (!lib->mtd_eb_size) + goto out_error; + + lib->mtd_size = mkpath(lib->mtd, MTD_SIZE); + if (!lib->mtd_size) + goto out_error; + + lib->mtd_min_io_size = mkpath(lib->mtd, MTD_MIN_IO_SIZE); + if (!lib->mtd_min_io_size) + goto out_error; + + lib->mtd_subpage_size = mkpath(lib->mtd, MTD_SUBPAGE_SIZE); + if (!lib->mtd_subpage_size) + goto out_error; + + lib->mtd_oob_size = mkpath(lib->mtd, MTD_OOB_SIZE); + if (!lib->mtd_oob_size) + goto out_error; + + lib->mtd_region_cnt = mkpath(lib->mtd, MTD_REGION_CNT); + if (!lib->mtd_region_cnt) + goto out_error; + + lib->mtd_flags = mkpath(lib->mtd, MTD_FLAGS); + if (!lib->mtd_flags) + goto out_error; + + lib->sysfs_supported = 1; + return lib; + +out_error: + libmtd_close((libmtd_t)lib); + return NULL; +} + +void libmtd_close(libmtd_t desc) +{ + struct libmtd *lib = (struct libmtd *)desc; + + free(lib->mtd_flags); + free(lib->mtd_region_cnt); + free(lib->mtd_oob_size); + free(lib->mtd_subpage_size); + free(lib->mtd_min_io_size); + free(lib->mtd_size); + free(lib->mtd_eb_size); + free(lib->mtd_type); + free(lib->mtd_dev); + free(lib->mtd_name); + free(lib->mtd); + free(lib->sysfs_mtd); + free(lib); +} + +int mtd_dev_present(libmtd_t desc, int mtd_num) { + struct stat st; + struct libmtd *lib = (struct libmtd *)desc; + + if (!lib->sysfs_supported) + return legacy_dev_present(mtd_num); + else { + char file[strlen(lib->mtd) + 10]; + + sprintf(file, lib->mtd, mtd_num); + return !stat(file, &st); + } +} + +int mtd_get_info(libmtd_t desc, struct mtd_info *info) +{ + DIR *sysfs_mtd; + struct dirent *dirent; + struct libmtd *lib = (struct libmtd *)desc; + + memset(info, 0, sizeof(struct mtd_info)); + + if (!lib->sysfs_supported) + return legacy_mtd_get_info(info); + + info->sysfs_supported = 1; + + /* + * We have to scan the MTD sysfs directory to identify how many MTD + * devices are present. + */ + sysfs_mtd = opendir(lib->sysfs_mtd); + if (!sysfs_mtd) { + if (errno == ENOENT) { + errno = ENODEV; + return -1; + } + return sys_errmsg("cannot open \"%s\"", lib->sysfs_mtd); + } + + info->lowest_mtd_num = INT_MAX; + while (1) { + int mtd_num, ret; + char tmp_buf[256]; + + errno = 0; + dirent = readdir(sysfs_mtd); + if (!dirent) + break; + + if (strlen(dirent->d_name) >= 255) { + errmsg("invalid entry in %s: \"%s\"", + lib->sysfs_mtd, dirent->d_name); + errno = EINVAL; + goto out_close; + } + + ret = sscanf(dirent->d_name, MTD_NAME_PATT"%255s", + &mtd_num, tmp_buf); + if (ret == 1) { + info->mtd_dev_cnt += 1; + if (mtd_num > info->highest_mtd_num) + info->highest_mtd_num = mtd_num; + if (mtd_num < info->lowest_mtd_num) + info->lowest_mtd_num = mtd_num; + } + } + + if (!dirent && errno) { + sys_errmsg("readdir failed on \"%s\"", lib->sysfs_mtd); + goto out_close; + } + + if (closedir(sysfs_mtd)) + return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_mtd); + + if (info->lowest_mtd_num == INT_MAX) + info->lowest_mtd_num = 0; + + return 0; + +out_close: + closedir(sysfs_mtd); + return -1; +} + +int mtd_get_dev_info1(libmtd_t desc, int mtd_num, struct mtd_dev_info *mtd) +{ + int ret; + struct libmtd *lib = (struct libmtd *)desc; + + memset(mtd, 0, sizeof(struct mtd_dev_info)); + mtd->mtd_num = mtd_num; + + if (!mtd_dev_present(desc, mtd_num)) { + errno = ENODEV; + return -1; + } else if (!lib->sysfs_supported) + return legacy_get_dev_info1(mtd_num, mtd); + + if (dev_get_major(lib, mtd_num, &mtd->major, &mtd->minor)) + return -1; + + ret = dev_read_data(lib->mtd_name, mtd_num, (void*)&mtd->name, + MTD_NAME_MAX + 1); + if (ret < 0) + return -1; + ((char *)mtd->name)[ret - 1] = '\0'; + + ret = dev_read_data(lib->mtd_type, mtd_num, (void*)&mtd->type_str, + MTD_TYPE_MAX + 1); + if (ret < 0) + return -1; + ((char *)mtd->type_str)[ret - 1] = '\0'; + + if (dev_read_pos_int(lib->mtd_eb_size, mtd_num, &mtd->eb_size)) + return -1; + if (dev_read_pos_ll(lib->mtd_size, mtd_num, &mtd->size)) + return -1; + if (dev_read_pos_int(lib->mtd_min_io_size, mtd_num, &mtd->min_io_size)) + return -1; + if (dev_read_pos_int(lib->mtd_subpage_size, mtd_num, &mtd->subpage_size)) + return -1; + if (dev_read_pos_int(lib->mtd_oob_size, mtd_num, &mtd->oob_size)) + return -1; + if (dev_read_pos_int(lib->mtd_region_cnt, mtd_num, &mtd->region_cnt)) + return -1; + if (dev_read_hex_int(lib->mtd_flags, mtd_num, &ret)) + return -1; + mtd->writable = !!(ret & MTD_WRITEABLE); + + mtd->eb_cnt = mtd->size / mtd->eb_size; + mtd->type = type_str2int(mtd->type_str); + mtd->bb_allowed = !!(mtd->type == MTD_NANDFLASH); + + return 0; +} + +int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd) +{ + int mtd_num; + struct libmtd *lib = (struct libmtd *)desc; + + if (!lib->sysfs_supported) + return legacy_get_dev_info(node, mtd); + + if (dev_node2num(lib, node, &mtd_num)) + return -1; + + return mtd_get_dev_info1(desc, mtd_num, mtd); +} + +static inline int mtd_ioctl_error(const struct mtd_dev_info *mtd, int eb, + const char *sreq) +{ + return sys_errmsg("%s ioctl failed for eraseblock %d (mtd%d)", + sreq, eb, mtd->mtd_num); +} + +static int mtd_valid_erase_block(const struct mtd_dev_info *mtd, int eb) +{ + if (eb < 0 || eb >= mtd->eb_cnt) { + errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks", + eb, mtd->mtd_num, mtd->eb_cnt); + errno = EINVAL; + return -1; + } + return 0; +} + +static int mtd_xlock(const struct mtd_dev_info *mtd, int fd, int eb, int req, + const char *sreq) +{ + int ret; + struct erase_info_user ei; + + ret = mtd_valid_erase_block(mtd, eb); + if (ret) + return ret; + + ei.start = eb * mtd->eb_size; + ei.length = mtd->eb_size; + + ret = ioctl(fd, req, &ei); + if (ret < 0) + return mtd_ioctl_error(mtd, eb, sreq); + + return 0; +} +#define mtd_xlock(mtd, fd, eb, req) mtd_xlock(mtd, fd, eb, req, #req) + +int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb) +{ + return mtd_xlock(mtd, fd, eb, MEMLOCK); +} + +int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb) +{ + return mtd_xlock(mtd, fd, eb, MEMUNLOCK); +} + +int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb) +{ + int ret; + struct libmtd *lib = (struct libmtd *)desc; + struct erase_info_user64 ei64; + struct erase_info_user ei; + + ret = mtd_valid_erase_block(mtd, eb); + if (ret) + return ret; + + ei64.start = (__u64)eb * mtd->eb_size; + ei64.length = mtd->eb_size; + + if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED || + lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) { + ret = ioctl(fd, MEMERASE64, &ei64); + if (ret == 0) + return ret; + + if (errno != ENOTTY || + lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN) + return mtd_ioctl_error(mtd, eb, "MEMERASE64"); + + /* + * MEMERASE64 support was added in kernel version 2.6.31, so + * probably we are working with older kernel and this ioctl is + * not supported. + */ + lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED; + } + + if (ei64.start + ei64.length > 0xFFFFFFFF) { + errmsg("this system can address only %u eraseblocks", + 0xFFFFFFFFU / mtd->eb_size); + errno = EINVAL; + return -1; + } + + ei.start = ei64.start; + ei.length = ei64.length; + ret = ioctl(fd, MEMERASE, &ei); + if (ret < 0) + return mtd_ioctl_error(mtd, eb, "MEMERASE"); + return 0; +} + +int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo) +{ + int ret; + + if (regidx < 0) { + errno = ENODEV; + return -1; + } + + ret = ioctl(fd, MEMGETREGIONINFO, reginfo); + if (ret < 0) + return sys_errmsg("%s ioctl failed for erase region %d", + "MEMGETREGIONINFO", regidx); + + return 0; +} + +int mtd_is_locked(const struct mtd_dev_info *mtd, int fd, int eb) +{ + int ret; + erase_info_t ei; + + ei.start = eb * mtd->eb_size; + ei.length = mtd->eb_size; + + ret = ioctl(fd, MEMISLOCKED, &ei); + if (ret < 0) { + if (errno != ENOTTY && errno != EOPNOTSUPP) + return mtd_ioctl_error(mtd, eb, "MEMISLOCKED"); + else + errno = EOPNOTSUPP; + } + + return ret; +} + +/* Patterns to write to a physical eraseblock when torturing it */ +static uint8_t patterns[] = {0xa5, 0x5a, 0x0}; + +/** + * check_pattern - check if buffer contains only a certain byte pattern. + * @buf: buffer to check + * @patt: the pattern to check + * @size: buffer size in bytes + * + * This function returns %1 in there are only @patt bytes in @buf, and %0 if + * something else was also found. + */ +static int check_pattern(const void *buf, uint8_t patt, int size) +{ + int i; + + for (i = 0; i < size; i++) + if (((const uint8_t *)buf)[i] != patt) + return 0; + return 1; +} + +int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb) +{ + int err, i, patt_count; + void *buf; + + normsg("run torture test for PEB %d", eb); + patt_count = ARRAY_SIZE(patterns); + + buf = xmalloc(mtd->eb_size); + + for (i = 0; i < patt_count; i++) { + err = mtd_erase(desc, mtd, fd, eb); + if (err) + goto out; + + /* Make sure the PEB contains only 0xFF bytes */ + err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size); + if (err) + goto out; + + err = check_pattern(buf, 0xFF, mtd->eb_size); + if (err == 0) { + errmsg("erased PEB %d, but a non-0xFF byte found", eb); + errno = EIO; + goto out; + } + + /* Write a pattern and check it */ + memset(buf, patterns[i], mtd->eb_size); + err = mtd_write(desc, mtd, fd, eb, 0, buf, mtd->eb_size, NULL, + 0, 0); + if (err) + goto out; + + memset(buf, ~patterns[i], mtd->eb_size); + err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size); + if (err) + goto out; + + err = check_pattern(buf, patterns[i], mtd->eb_size); + if (err == 0) { + errmsg("pattern %x checking failed for PEB %d", + patterns[i], eb); + errno = EIO; + goto out; + } + } + + err = 0; + normsg("PEB %d passed torture test, do not mark it a bad", eb); + +out: + free(buf); + return -1; +} + +int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb) +{ + int ret; + loff_t seek; + + ret = mtd_valid_erase_block(mtd, eb); + if (ret) + return ret; + + if (!mtd->bb_allowed) + return 0; + + seek = (loff_t)eb * mtd->eb_size; + ret = ioctl(fd, MEMGETBADBLOCK, &seek); + if (ret == -1) + return mtd_ioctl_error(mtd, eb, "MEMGETBADBLOCK"); + return ret; +} + +int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb) +{ + int ret; + loff_t seek; + + if (!mtd->bb_allowed) { + errno = EINVAL; + return -1; + } + + ret = mtd_valid_erase_block(mtd, eb); + if (ret) + return ret; + + seek = (loff_t)eb * mtd->eb_size; + ret = ioctl(fd, MEMSETBADBLOCK, &seek); + if (ret == -1) + return mtd_ioctl_error(mtd, eb, "MEMSETBADBLOCK"); + return 0; +} + +int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs, + void *buf, int len) +{ + int ret, rd = 0; + off_t seek; + + ret = mtd_valid_erase_block(mtd, eb); + if (ret) + return ret; + + if (offs < 0 || offs + len > mtd->eb_size) { + errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d", + offs, len, mtd->mtd_num, mtd->eb_size); + errno = EINVAL; + return -1; + } + + /* Seek to the beginning of the eraseblock */ + seek = (off_t)eb * mtd->eb_size + offs; + if (lseek(fd, seek, SEEK_SET) != seek) + return sys_errmsg("cannot seek mtd%d to offset %"PRIdoff_t, + mtd->mtd_num, seek); + + while (rd < len) { + ret = read(fd, buf, len); + if (ret < 0) + return sys_errmsg("cannot read %d bytes from mtd%d (eraseblock %d, offset %d)", + len, mtd->mtd_num, eb, offs); + rd += ret; + } + + return 0; +} + +static int legacy_auto_oob_layout(const struct mtd_dev_info *mtd, int fd, + int ooblen, void *oob) { + struct nand_oobinfo old_oobinfo; + int start, len; + uint8_t *tmp_buf = NULL; + + /* Read the current oob info */ + if (ioctl(fd, MEMGETOOBSEL, &old_oobinfo)) + return sys_errmsg("MEMGETOOBSEL failed"); + + tmp_buf = (uint8_t*)malloc(ooblen); + memcpy(tmp_buf, oob, ooblen); + + /* + * We use autoplacement and have the oobinfo with the autoplacement + * information from the kernel available + */ + if (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) { + int i, tags_pos = 0; + for (i = 0; old_oobinfo.oobfree[i][1]; i++) { + /* Set the reserved bytes to 0xff */ + start = old_oobinfo.oobfree[i][0]; + len = old_oobinfo.oobfree[i][1]; + memcpy(((char*)oob + start), tmp_buf + tags_pos, len); + tags_pos += len; + } + } else { + /* Set at least the ecc byte positions to 0xff */ + start = old_oobinfo.eccbytes; + len = mtd->oob_size - start; + memcpy(((char*)oob + start), tmp_buf + start, len); + } + if (tmp_buf != NULL) + free(tmp_buf); + + return 0; +} + +int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb, + int offs, void *data, int len, void *oob, int ooblen, + uint8_t mode) +{ + int ret; + off_t seek; + struct mtd_write_req ops; + + ret = mtd_valid_erase_block(mtd, eb); + if (ret) + return ret; + + if (offs < 0 || offs + len > mtd->eb_size) { + errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d", + offs, len, mtd->mtd_num, mtd->eb_size); + errno = EINVAL; + return -1; + } + if (offs % mtd->subpage_size) { + errmsg("write offset %d is not aligned to mtd%d min. I/O size %d", + offs, mtd->mtd_num, mtd->subpage_size); + errno = EINVAL; + return -1; + } + if (len % mtd->subpage_size) { + errmsg("write length %d is not aligned to mtd%d min. I/O size %d", + len, mtd->mtd_num, mtd->subpage_size); + errno = EINVAL; + return -1; + } + + /* Calculate seek address */ + seek = (off_t)eb * mtd->eb_size + offs; + + if (oob) { + ops.start = seek; + ops.len = len; + ops.ooblen = ooblen; + ops.usr_data = (uint64_t)(unsigned long)data; + ops.usr_oob = (uint64_t)(unsigned long)oob; + ops.mode = mode; + + ret = ioctl(fd, MEMWRITE, &ops); + if (ret == 0) + return 0; + else if (errno != ENOTTY && errno != EOPNOTSUPP) + return mtd_ioctl_error(mtd, eb, "MEMWRITE"); + + /* Fall back to old OOB ioctl() if necessary */ + if (mode == MTD_OPS_AUTO_OOB) + if (legacy_auto_oob_layout(mtd, fd, ooblen, oob)) + return -1; + if (mtd_write_oob(desc, mtd, fd, seek, ooblen, oob) < 0) + return sys_errmsg("cannot write to OOB"); + } + if (data) { + /* Seek to the beginning of the eraseblock */ + if (lseek(fd, seek, SEEK_SET) != seek) + return sys_errmsg("cannot seek mtd%d to offset %"PRIdoff_t, + mtd->mtd_num, seek); + ret = write(fd, data, len); + if (ret != len) + return sys_errmsg("cannot write %d bytes to mtd%d " + "(eraseblock %d, offset %d)", + len, mtd->mtd_num, eb, offs); + } + + return 0; +} + +int do_oob_op(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, + uint64_t start, uint64_t length, void *data, unsigned int cmd64, + unsigned int cmd) +{ + int ret, oob_offs; + struct mtd_oob_buf64 oob64; + struct mtd_oob_buf oob; + unsigned long long max_offs; + const char *cmd64_str, *cmd_str; + struct libmtd *lib = (struct libmtd *)desc; + + if (cmd64 == MEMREADOOB64) { + cmd64_str = "MEMREADOOB64"; + cmd_str = "MEMREADOOB"; + } else { + cmd64_str = "MEMWRITEOOB64"; + cmd_str = "MEMWRITEOOB"; + } + + max_offs = (unsigned long long)mtd->eb_cnt * mtd->eb_size; + if (start >= max_offs) { + errmsg("bad page address %llu, mtd%d has %d eraseblocks (%llu bytes)", + start, mtd->mtd_num, mtd->eb_cnt, max_offs); + errno = EINVAL; + return -1; + } + + oob_offs = start & (mtd->min_io_size - 1); + if (oob_offs + length > (unsigned int)mtd->oob_size || length == 0) { + errmsg("Cannot write %llu OOB bytes to address %llu (OOB offset %u) - mtd%d OOB size is only %d bytes", + length, start, oob_offs, mtd->mtd_num, mtd->oob_size); + errno = EINVAL; + return -1; + } + + oob64.start = start; + oob64.length = length; + oob64.usr_ptr = (uint64_t)(unsigned long)data; + + if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED || + lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) { + ret = ioctl(fd, cmd64, &oob64); + if (ret == 0) + return ret; + + if (errno != ENOTTY || + lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN) { + sys_errmsg("%s ioctl failed for mtd%d, offset %llu (eraseblock %llu)", + cmd64_str, mtd->mtd_num, start, start / mtd->eb_size); + } + + /* + * MEMREADOOB64/MEMWRITEOOB64 support was added in kernel + * version 2.6.31, so probably we are working with older kernel + * and these ioctls are not supported. + */ + lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED; + } + + if (oob64.start > 0xFFFFFFFFULL) { + errmsg("this system can address only up to address %lu", + 0xFFFFFFFFUL); + errno = EINVAL; + return -1; + } + + oob.start = oob64.start; + oob.length = oob64.length; + oob.ptr = (unsigned char*)data; + + ret = ioctl(fd, cmd, &oob); + if (ret < 0) + sys_errmsg("%s ioctl failed for mtd%d, offset %llu (eraseblock %llu)", + cmd_str, mtd->mtd_num, start, start / mtd->eb_size); + return ret; +} + +int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, + uint64_t start, uint64_t length, void *data) +{ + return do_oob_op(desc, mtd, fd, start, length, data, + MEMREADOOB64, MEMREADOOB); +} + +int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, + uint64_t start, uint64_t length, void *data) +{ + return do_oob_op(desc, mtd, fd, start, length, data, + MEMWRITEOOB64, MEMWRITEOOB); +} + +int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs, + const char *img_name) +{ + int tmp, ret, in_fd, len, written = 0; + off_t seek; + struct stat st; + char *buf; + + ret = mtd_valid_erase_block(mtd, eb); + if (ret) + return ret; + + if (offs < 0 || offs >= mtd->eb_size) { + errmsg("bad offset %d, mtd%d eraseblock size is %d", + offs, mtd->mtd_num, mtd->eb_size); + errno = EINVAL; + return -1; + } + if (offs % mtd->subpage_size) { + errmsg("write offset %d is not aligned to mtd%d min. I/O size %d", + offs, mtd->mtd_num, mtd->subpage_size); + errno = EINVAL; + return -1; + } + + in_fd = open(img_name, O_RDONLY | O_CLOEXEC); + if (in_fd == -1) + return sys_errmsg("cannot open \"%s\"", img_name); + + if (fstat(in_fd, &st)) { + sys_errmsg("cannot stat %s", img_name); + goto out_close; + } + + len = st.st_size; + if (len % mtd->subpage_size) { + errmsg("size of \"%s\" is %d byte, which is not aligned to " + "mtd%d min. I/O size %d", img_name, len, mtd->mtd_num, + mtd->subpage_size); + errno = EINVAL; + goto out_close; + } + tmp = (offs + len + mtd->eb_size - 1) / mtd->eb_size; + if (eb + tmp > mtd->eb_cnt) { + errmsg("\"%s\" image size is %d bytes, mtd%d size is %d " + "eraseblocks, the image does not fit if we write it " + "starting from eraseblock %d, offset %d", + img_name, len, mtd->mtd_num, mtd->eb_cnt, eb, offs); + errno = EINVAL; + goto out_close; + } + + /* Seek to the beginning of the eraseblock */ + seek = (off_t)eb * mtd->eb_size + offs; + if (lseek(fd, seek, SEEK_SET) != seek) { + sys_errmsg("cannot seek mtd%d to offset %"PRIdoff_t, + mtd->mtd_num, seek); + goto out_close; + } + + buf = (char*)xmalloc(mtd->eb_size); + + while (written < len) { + int rd = 0; + + do { + ret = read(in_fd, buf, mtd->eb_size - offs - rd); + if (ret == -1) { + sys_errmsg("cannot read \"%s\"", img_name); + goto out_free; + } + rd += ret; + } while (ret && rd < mtd->eb_size - offs); + + ret = write(fd, buf, rd); + if (ret != rd) { + sys_errmsg("cannot write %d bytes to mtd%d (eraseblock %d, offset %d)", + len, mtd->mtd_num, eb, offs); + goto out_free; + } + + offs = 0; + eb += 1; + written += rd; + } + + free(buf); + close(in_fd); + return 0; + +out_free: + free(buf); +out_close: + close(in_fd); + return -1; +} + +int mtd_probe_node(libmtd_t desc, const char *node) +{ + struct stat st; + struct mtd_info info; + int i, mjr, mnr; + struct libmtd *lib = (struct libmtd *)desc; + + if (stat(node, &st)) + return sys_errmsg("cannot get information about \"%s\"", node); + + if (!S_ISCHR(st.st_mode)) { + errmsg("\"%s\" is not a character device", node); + errno = EINVAL; + return -1; + } + + mjr = major(st.st_rdev); + mnr = minor(st.st_rdev); + + if (mtd_get_info((libmtd_t *)lib, &info)) + return -1; + + if (!lib->sysfs_supported) + return 0; + + for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; i++) { + int mjr1, mnr1, ret; + + ret = dev_get_major(lib, i, &mjr1, &mnr1); + if (ret) { + if (errno == ENOENT) + continue; + if (!errno) + break; + return -1; + } + + if (mjr1 == mjr && mnr1 == mnr) + return 1; + } + + errno = 0; + return -1; +} diff --git a/src/system/mtdutils/lib/libmtd_int.h b/src/system/mtdutils/lib/libmtd_int.h new file mode 100644 index 000000000..7913e676c --- /dev/null +++ b/src/system/mtdutils/lib/libmtd_int.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem Bityutskiy + * + * MTD library. + */ + +#ifndef __LIBMTD_INT_H__ +#define __LIBMTD_INT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define PROGRAM_NAME "libmtd" + +#define SYSFS_MTD "class/mtd" +#define MTD_NAME_PATT "mtd%d" +#define MTD_DEV "dev" +#define MTD_NAME "name" +#define MTD_TYPE "type" +#define MTD_EB_SIZE "erasesize" +#define MTD_SIZE "size" +#define MTD_MIN_IO_SIZE "writesize" +#define MTD_SUBPAGE_SIZE "subpagesize" +#define MTD_OOB_SIZE "oobsize" +#define MTD_REGION_CNT "numeraseregions" +#define MTD_FLAGS "flags" + +#define OFFS64_IOCTLS_UNKNOWN 0 +#define OFFS64_IOCTLS_NOT_SUPPORTED 1 +#define OFFS64_IOCTLS_SUPPORTED 2 + +/** + * libmtd - MTD library description data structure. + * @sysfs_mtd: MTD directory in sysfs + * @mtd: MTD device sysfs directory pattern + * @mtd_dev: MTD device major/minor numbers file pattern + * @mtd_name: MTD device name file pattern + * @mtd_type: MTD device type file pattern + * @mtd_eb_size: MTD device eraseblock size file pattern + * @mtd_size: MTD device size file pattern + * @mtd_min_io_size: minimum I/O unit size file pattern + * @mtd_subpage_size: sub-page size file pattern + * @mtd_oob_size: MTD device OOB size file pattern + * @mtd_region_cnt: count of additional erase regions file pattern + * @mtd_flags: MTD device flags file pattern + * @sysfs_supported: non-zero if sysfs is supported by MTD + * @offs64_ioctls: %OFFS64_IOCTLS_SUPPORTED if 64-bit %MEMERASE64, + * %MEMREADOOB64, %MEMWRITEOOB64 MTD device ioctls are + * supported, %OFFS64_IOCTLS_NOT_SUPPORTED if not, and + * %OFFS64_IOCTLS_UNKNOWN if it is not known yet; + * + * Note, we cannot find out whether 64-bit ioctls are supported by MTD when we + * are initializing the library, because this requires an MTD device node. + * Indeed, we have to actually call the ioctl and check for %ENOTTY to find + * out whether it is supported or not. + * + * Thus, we leave %offs64_ioctls uninitialized in 'libmtd_open()', and + * initialize it later, when corresponding libmtd function is used, and when + * we actually have a device node and can invoke an ioctl command on it. + */ +struct libmtd +{ + char *sysfs_mtd; + char *mtd; + char *mtd_dev; + char *mtd_name; + char *mtd_type; + char *mtd_eb_size; + char *mtd_size; + char *mtd_min_io_size; + char *mtd_subpage_size; + char *mtd_oob_size; + char *mtd_region_cnt; + char *mtd_flags; + unsigned int sysfs_supported:1; + unsigned int offs64_ioctls:2; +}; + +int legacy_libmtd_open(void); +int legacy_dev_present(int mtd_num); +int legacy_mtd_get_info(struct mtd_info *info); +int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd); +int legacy_get_dev_info1(int dev_num, struct mtd_dev_info *mtd); + +#ifdef __cplusplus +} +#endif + +#endif /* !__LIBMTD_INT_H__ */ diff --git a/src/system/mtdutils/lib/libmtd_legacy.cpp b/src/system/mtdutils/lib/libmtd_legacy.cpp new file mode 100644 index 000000000..b8101e0ae --- /dev/null +++ b/src/system/mtdutils/lib/libmtd_legacy.cpp @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem Bityutskiy + * + * This file is part of the MTD library. Implements pre-2.6.30 kernels support, + * where MTD did not have sysfs interface. The main limitation of the old + * kernels was that the sub-page size was not exported to user-space, so it was + * not possible to get sub-page size. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "libmtd_int.h" +#include "common.h" + +#define MTD_PROC_FILE "/proc/mtd" +#define MTD_DEV_PATT "/dev/mtd%d" +#define MTD_DEV_MAJOR 90 + +#define PROC_MTD_FIRST "dev: size erasesize name\n" +#define PROC_MTD_FIRST_LEN (sizeof(PROC_MTD_FIRST) - 1) +#define PROC_MTD_MAX_LEN 4096 +#define PROC_MTD_PATT "mtd%d: %llx %x" + +/** + * struct proc_parse_info - /proc/mtd parsing information. + * @mtd_num: MTD device number + * @size: device size + * @eb_size: eraseblock size + * @name: device name + * @buf: contents of /proc/mtd + * @data_size: how much data was read into @buf + * @pos: next string in @buf to parse + */ +struct proc_parse_info +{ + int mtd_num; + long long size; + char name[MTD_NAME_MAX + 1]; + int eb_size; + char *buf; + int data_size; + char *next; +}; + +static int proc_parse_start(struct proc_parse_info *pi) +{ + int fd, ret; + + fd = open(MTD_PROC_FILE, O_RDONLY); + if (fd == -1) + return -1; + + pi->buf = (char*)xmalloc(PROC_MTD_MAX_LEN); + + ret = read(fd, pi->buf, PROC_MTD_MAX_LEN); + if (ret == -1) { + sys_errmsg("cannot read \"%s\"", MTD_PROC_FILE); + goto out_free; + } + + if (ret < (int)PROC_MTD_FIRST_LEN || + memcmp(pi->buf, PROC_MTD_FIRST, PROC_MTD_FIRST_LEN)) { + errmsg("\"%s\" does not start with \"%s\"", MTD_PROC_FILE, + PROC_MTD_FIRST); + goto out_free; + } + + pi->data_size = ret; + pi->next = pi->buf + PROC_MTD_FIRST_LEN; + + close(fd); + return 0; + +out_free: + free(pi->buf); + close(fd); + return -1; +} + +static int proc_parse_next(struct proc_parse_info *pi) +{ + int ret, len, pos = pi->next - pi->buf; + char *p, *p1; + + if (pos >= pi->data_size) { + free(pi->buf); + return 0; + } + + ret = sscanf(pi->next, PROC_MTD_PATT, &pi->mtd_num, &pi->size, + &pi->eb_size); + if (ret != 3) + return errmsg("\"%s\" pattern not found", PROC_MTD_PATT); + + p = (char*)memchr(pi->next, '\"', pi->data_size - pos); + if (!p) + return errmsg("opening \" not found"); + p += 1; + pos = p - pi->buf; + if (pos >= pi->data_size) + return errmsg("opening \" not found"); + + p1 = (char*)memchr(p, '\"', pi->data_size - pos); + if (!p1) + return errmsg("closing \" not found"); + pos = p1 - pi->buf; + if (pos >= pi->data_size) + return errmsg("closing \" not found"); + + len = p1 - p; + if (len > MTD_NAME_MAX) + return errmsg("too long mtd%d device name", pi->mtd_num); + + memcpy(pi->name, p, len); + pi->name[len] = '\0'; + + if (p1[1] != '\n') + return errmsg("opening \"\n\" not found"); + pi->next = p1 + 2; + return 1; +} + +/** + * legacy_libmtd_open - legacy version of 'libmtd_open()'. + * + * This function is just checks that MTD is present in the system. Returns + * zero in case of success and %-1 in case of failure. In case of failure, + * errno contains zero if MTD is not present in the system, or contains the + * error code if a real error happened. This is similar to the 'libmtd_open()' + * return conventions. + */ +int legacy_libmtd_open(void) +{ + int fd; + + fd = open(MTD_PROC_FILE, O_RDONLY); + if (fd == -1) { + if (errno == ENOENT) + errno = 0; + return -1; + } + + close(fd); + return 0; +} + +/** + * legacy_dev_presentl - legacy version of 'mtd_dev_present()'. + * @info: the MTD device information is returned here + * + * When the kernel does not provide sysfs files for the MTD subsystem, + * fall-back to parsing the /proc/mtd file to determine whether an mtd device + * number @mtd_num is present. + */ +int legacy_dev_present(int mtd_num) +{ + int ret; + struct proc_parse_info pi; + + ret = proc_parse_start(&pi); + if (ret) + return -1; + + while (proc_parse_next(&pi)) { + if (pi.mtd_num == mtd_num) + return 1; + } + + return 0; +} + +/** + * legacy_mtd_get_info - legacy version of 'mtd_get_info()'. + * @info: the MTD device information is returned here + * + * This function is similar to 'mtd_get_info()' and has the same conventions. + */ +int legacy_mtd_get_info(struct mtd_info *info) +{ + int ret; + struct proc_parse_info pi; + + ret = proc_parse_start(&pi); + if (ret) + return -1; + + info->lowest_mtd_num = INT_MAX; + while (proc_parse_next(&pi)) { + info->mtd_dev_cnt += 1; + if (pi.mtd_num > info->highest_mtd_num) + info->highest_mtd_num = pi.mtd_num; + if (pi.mtd_num < info->lowest_mtd_num) + info->lowest_mtd_num = pi.mtd_num; + } + + return 0; +} + +/** + * legacy_get_dev_info - legacy version of 'mtd_get_dev_info()'. + * @node: name of the MTD device node + * @mtd: the MTD device information is returned here + * + * This function is similar to 'mtd_get_dev_info()' and has the same + * conventions. + */ +int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd) +{ + struct stat st; + struct mtd_info_user ui; + int fd, ret; + loff_t offs = 0; + struct proc_parse_info pi; + + if (stat(node, &st)) { + sys_errmsg("cannot open \"%s\"", node); + if (errno == ENOENT) + normsg("MTD subsystem is old and does not support " + "sysfs, so MTD character device nodes have " + "to exist"); + } + + if (!S_ISCHR(st.st_mode)) { + errno = EINVAL; + return errmsg("\"%s\" is not a character device", node); + } + + memset(mtd, '\0', sizeof(struct mtd_dev_info)); + mtd->major = major(st.st_rdev); + mtd->minor = minor(st.st_rdev); + + if (mtd->major != MTD_DEV_MAJOR) { + errno = EINVAL; + return errmsg("\"%s\" has major number %d, MTD devices have " + "major %d", node, mtd->major, MTD_DEV_MAJOR); + } + + mtd->mtd_num = mtd->minor / 2; + + fd = open(node, O_RDONLY); + if (fd == -1) + return sys_errmsg("cannot open \"%s\"", node); + + if (ioctl(fd, MEMGETINFO, &ui)) { + sys_errmsg("MEMGETINFO ioctl request failed"); + goto out_close; + } + + ret = ioctl(fd, MEMGETBADBLOCK, &offs); + if (ret == -1) { + if (errno != EOPNOTSUPP) { + sys_errmsg("MEMGETBADBLOCK ioctl failed"); + goto out_close; + } + errno = 0; + mtd->bb_allowed = 0; + } else + mtd->bb_allowed = 1; + + mtd->type = ui.type; + mtd->size = ui.size; + mtd->eb_size = ui.erasesize; + mtd->min_io_size = ui.writesize; + mtd->oob_size = ui.oobsize; + + if (mtd->min_io_size <= 0) { + errmsg("mtd%d (%s) has insane min. I/O unit size %d", + mtd->mtd_num, node, mtd->min_io_size); + goto out_close; + } + if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) { + errmsg("mtd%d (%s) has insane eraseblock size %d", + mtd->mtd_num, node, mtd->eb_size); + goto out_close; + } + if (mtd->size <= 0 || mtd->size < mtd->eb_size) { + errmsg("mtd%d (%s) has insane size %lld", + mtd->mtd_num, node, mtd->size); + goto out_close; + } + mtd->eb_cnt = mtd->size / mtd->eb_size; + + switch(mtd->type) { + case MTD_ABSENT: + errmsg("mtd%d (%s) is removable and is not present", + mtd->mtd_num, node); + goto out_close; + case MTD_RAM: + strcpy((char *)mtd->type_str, "ram"); + break; + case MTD_ROM: + strcpy((char *)mtd->type_str, "rom"); + break; + case MTD_NORFLASH: + strcpy((char *)mtd->type_str, "nor"); + break; + case MTD_NANDFLASH: + strcpy((char *)mtd->type_str, "nand"); + break; + case MTD_DATAFLASH: + strcpy((char *)mtd->type_str, "dataflash"); + break; + case MTD_UBIVOLUME: + strcpy((char *)mtd->type_str, "ubi"); + break; + default: + goto out_close; + } + + if (ui.flags & MTD_WRITEABLE) + mtd->writable = 1; + mtd->subpage_size = mtd->min_io_size; + + close(fd); + + /* + * Unfortunately, the device name is not available via ioctl, and + * we have to parse /proc/mtd to get it. + */ + ret = proc_parse_start(&pi); + if (ret) + return -1; + + while (proc_parse_next(&pi)) { + if (pi.mtd_num == mtd->mtd_num) { + strcpy((char *)mtd->name, pi.name); + return 0; + } + } + + errmsg("mtd%d not found in \"%s\"", mtd->mtd_num, MTD_PROC_FILE); + errno = ENOENT; + return -1; + +out_close: + close(fd); + return -1; +} + +/** + * legacy_get_dev_info1 - legacy version of 'mtd_get_dev_info1()'. + * @node: name of the MTD device node + * @mtd: the MTD device information is returned here + * + * This function is similar to 'mtd_get_dev_info1()' and has the same + * conventions. + */ +int legacy_get_dev_info1(int mtd_num, struct mtd_dev_info *mtd) +{ + char node[sizeof(MTD_DEV_PATT) + 20]; + + sprintf(node, MTD_DEV_PATT, mtd_num); + return legacy_get_dev_info(node, mtd); +} diff --git a/src/system/mtdutils/mcast_image.h b/src/system/mtdutils/mcast_image.h new file mode 100644 index 000000000..8e94ffa42 --- /dev/null +++ b/src/system/mtdutils/mcast_image.h @@ -0,0 +1,54 @@ +#include + +#define PKT_SIZE 2820 + +struct image_pkt_hdr { + uint32_t resend; + uint32_t totcrc; + uint32_t nr_blocks; + uint32_t blocksize; + uint32_t block_crc; + uint32_t block_nr; + uint32_t pkt_sequence; + uint16_t pkt_nr; + uint16_t nr_pkts; + uint32_t thislen; + uint32_t thiscrc; +}; + +struct image_pkt { + struct image_pkt_hdr hdr; + unsigned char data[PKT_SIZE]; +}; + +struct fec_parms; + +/* k - number of actual data packets + * n - total number of packets including data and redundant packets + * (actual packet size isn't relevant here) */ +struct fec_parms *fec_new(int k, int n); +void fec_free(struct fec_parms *p); + +/* src - array of (n) pointers to data packets + * fec - buffer for packet to be generated + * index - index of packet to be generated (0 <= index < n) + * sz - data packet size + * + * _linear version just takes a pointer to the raw data; no + * mucking about with packet pointers. + */ +void fec_encode(struct fec_parms *code, unsigned char *src[], + unsigned char *fec, int index, int sz); +void fec_encode_linear(struct fec_parms *code, unsigned char *src, + unsigned char *fec, int index, int sz); + +/* data - array of (k) pointers to data packets, in arbitrary order (see i) + * i - indices of (data) packets + * sz - data packet size + * + * Will never fail as long as you give it (k) individual data packets. + * Will re-order the (data) pointers but not the indices -- data packets + * are ordered on return. + */ +int fec_decode(struct fec_parms *code, unsigned char *data[], + int i[], int sz); diff --git a/src/system/mtdutils/mkfs.jffs2.cpp b/src/system/mtdutils/mkfs.jffs2.cpp new file mode 100644 index 000000000..ed9168ea4 --- /dev/null +++ b/src/system/mtdutils/mkfs.jffs2.cpp @@ -0,0 +1,1266 @@ +/* + * Build a JFFS2 image in a file, from a given directory tree. + * + * Copyright 2001, 2002 Red Hat, Inc. + * 2001 David A. Schleef + * 2002 Axis Communications AB + * 2001, 2002 Erik Andersen + * 2004 University of Szeged, Hungary + * 2006 KaiGai Kohei + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Cross-endian support added by David Schleef . + * + * Major architectural rewrite by Erik Andersen + * to allow support for making hard links (though hard links support is + * not yet implemented), and for munging file permissions and ownership + * on the fly using --faketime, --squash, --devtable. And I plugged a + * few memory leaks, adjusted the error handling and fixed some little + * nits here and there. + * + * I also added a sample device table file. See device_table.txt + * -Erik, September 2001 + * + * Cleanmarkers support added by Axis Communications AB + * + * Rewritten again. Cleanly separated host and target filsystem + * activities (mainly so I can reuse all the host handling stuff as I + * rewrite other mkfs utils). Added a verbose option to list types + * and attributes as files are added to the file system. Major cleanup + * and scrubbing of the code so it can be read, understood, and + * modified by mere mortals. + * + * -Erik, November 2002 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rbtree.h" + +#define PROGRAM_NAME "mkfs.jffs2" + +int page_size = -1; +int target_endian = __BYTE_ORDER; +struct rb_root hardlinks; +struct filesystem_entry { + char *name; /* Name of this directory (think basename) */ + char *path; /* Path of this directory (think dirname) */ + char *fullname; /* Full name of this directory (i.e. path+name) */ + char *hostname; /* Full path to this file on the host filesystem */ + uint32_t ino; /* Inode number of this file in JFFS2 */ + struct stat sb; /* Stores directory permissions and whatnot */ + char *link; /* Target a symlink points to. */ + struct filesystem_entry *parent; /* Parent directory */ + struct filesystem_entry *prev; /* Only relevant to non-directories */ + struct filesystem_entry *next; /* Only relevant to non-directories */ + struct filesystem_entry *files; /* Only relevant to directories */ + struct rb_node hardlink_rb; +}; +struct filesystem_entry *fse_root = NULL; + +#include "common.h" +#include "mtd/jffs2-user.h" + +struct jffs2_unknown_node cleanmarker; + +#include "compr.h" + +#include "mkfs.jffs2.h" +#include "sumtool.h" + +/* Do not use the weird XPG version of basename */ +#undef basename + +//#define DMALLOC +//#define mkfs_debug_msg errmsg +#define mkfs_debug_msg(a...) { } + +#define PAD(x) (((x)+3)&~3) + +#define JFFS2_MAX_FILE_SIZE 0xFFFFFFFF +#ifndef JFFS2_MAX_SYMLINK_LEN +#define JFFS2_MAX_SYMLINK_LEN 254 +#endif + +CMkfsJFFS2::CMkfsJFFS2() +{ + Init(); +} + +CMkfsJFFS2::~CMkfsJFFS2() +{ + classClear(); +} + +bool CMkfsJFFS2::classInit() +{ + if (useSumtool_) { + sumName_ = imageName_; + imageName_ += ".tmp"; + } + + out_fd = open(imageName_.c_str(), O_CREAT | O_TRUNC | O_RDWR, 0644); + if (out_fd == -1) { + sys_errmsg("open output file: %s", imageName_.c_str()); + return false; + } + jffs2_compressors_init(); + compressorIsInit = true; + return true; +} + +void CMkfsJFFS2::classClear() +{ + if (fse_root != NULL) { + cleanup(fse_root); + fse_root = NULL; + } + if (out_fd > 0) { + close(out_fd); + out_fd = -1; + } + if (compressorIsInit) { + jffs2_compressors_exit(); + compressorIsInit = false; + } +} + +void CMkfsJFFS2::Init() +{ + out_fd = -1; + squash_uids = 0; + squash_perms = 0; + fake_times = 0; + target_endian = __BYTE_ORDER; + all_read = 0; + printProgress = 0; + kbUsed = 0; + progressBar = NULL; + progressBarGlobalX1 = 0; + progressBarGlobalX2 = 0; + + ino = 0; + out_ofs = 0; + erase_block_size = 65536; + pad_fs_size = 0; + add_cleanmarkers = 0; + cleanmarker_size = sizeof(cleanmarker); + compressorIsInit = false; + fse_root = NULL; + imageName_ = ""; + sumName_ = ""; + useSumtool_ = true; + + page_size = sysconf(_SC_PAGESIZE); + if (page_size < 0) /* System doesn't know so ... */ + page_size = 4096; /* ... we make an educated guess */ + + memset(ffbuf, 0xFF, sizeof(ffbuf)); +} + +char *CMkfsJFFS2::xreadlink(const char *path) +{ + static const int GROWBY = 80; /* how large we will grow strings by */ + + char *buf = NULL; + int bufsize = 0, readsize = 0; + + do { + buf = (char*)xrealloc(buf, bufsize += GROWBY); + readsize = readlink(path, buf, bufsize); /* 1st try */ + if (readsize == -1) { + sys_errmsg("%s:%s", PROGRAM_NAME, path); + return NULL; + } + } while (bufsize < readsize + 1); + + buf[readsize] = '\0'; + + return buf; +} + +void CMkfsJFFS2::cleanup(struct filesystem_entry *dir) +{ + struct filesystem_entry *e; + + e = dir->files; + while (e) { + if (e->name) + free(e->name); + if (e->path) + free(e->path); + if (e->fullname) + free(e->fullname); + e->name = NULL; + e->path = NULL; + e->fullname = NULL; + e->prev = NULL; + filesystem_entry *prev = e; + if (S_ISDIR(e->sb.st_mode)) { + cleanup(e); + } + e = e->next; + free(prev); + } +} + +struct filesystem_entry *CMkfsJFFS2::add_host_filesystem_entry(const char *name, + const char *path, unsigned long uid, unsigned long gid, + unsigned long mode, dev_t rdev, struct filesystem_entry *parent) { + int status; + char *tmp; + struct stat sb; + time_t timestamp = time(NULL); + struct filesystem_entry *entry; + + memset(&sb, 0, sizeof(struct stat)); + status = lstat(path, &sb); + + if (status >= 0) { + /* It is ok for some types of files to not exit on disk (such as + * device nodes), but if they _do_ exist the specified mode had + * better match the actual file or strange things will happen.... */ + if ((mode & S_IFMT) != (sb.st_mode & S_IFMT)) { + sys_errmsg ("%s: file type does not match specified type!", path); + } + timestamp = sb.st_mtime; + } else { + /* If this is a regular file, it _must_ exist on disk */ + if ((mode & S_IFMT) == S_IFREG) { + sys_errmsg("%s: does not exist!", path); + } + } + + /* Squash all permissions so files are owned by root, all + * timestamps are _right now_, and file permissions + * have group and other write removed */ + if (squash_uids) { + uid = gid = 0; + } + if (squash_perms) { + if (!S_ISLNK(mode)) { + mode &= ~(S_IWGRP | S_IWOTH); + mode &= ~(S_ISUID | S_ISGID); + } + } + if (fake_times) { + timestamp = 0; + } + + entry = reinterpret_cast(xcalloc(1, sizeof(struct filesystem_entry))); + + entry->hostname = xstrdup(path); + entry->fullname = xstrdup(name); + tmp = xstrdup(name); + entry->name = xstrdup(basename(tmp)); + free(tmp); + tmp = xstrdup(name); + entry->path = xstrdup(dirname(tmp)); + free(tmp); + + entry->sb.st_ino = sb.st_ino; + entry->sb.st_dev = sb.st_dev; + entry->sb.st_nlink = sb.st_nlink; + + entry->sb.st_uid = uid; + entry->sb.st_gid = gid; + entry->sb.st_mode = mode; + entry->sb.st_rdev = rdev; + entry->sb.st_atime = entry->sb.st_ctime = + entry->sb.st_mtime = timestamp; + if (S_ISREG(mode)) { + entry->sb.st_size = sb.st_size; + } + if (S_ISLNK(mode)) { + entry->link = xreadlink(path); + entry->sb.st_size = strlen(entry->link); + } + + /* This happens only for root */ + if (!parent) + return (entry); + + /* Hook the file into the parent directory */ + entry->parent = parent; + if (!parent->files) { + parent->files = entry; + } else { + struct filesystem_entry *prev; + for (prev = parent->files; prev->next; prev = prev->next); + prev->next = entry; + entry->prev = prev; + } + + return (entry); +} + +struct filesystem_entry *CMkfsJFFS2::find_filesystem_entry( + struct filesystem_entry *dir, char *fullname, uint32_t type) { + struct filesystem_entry *e = dir; + + if (S_ISDIR(dir->sb.st_mode)) { + /* If this is the first call, and we actually want this + * directory, then return it now */ + if (strcmp(fullname, e->fullname) == 0) + return e; + + e = dir->files; + } + while (e) { + if (S_ISDIR(e->sb.st_mode)) { + int len = strlen(e->fullname); + + /* Check if we are a parent of the correct path */ + if (strncmp(e->fullname, fullname, len) == 0) { + /* Is this an _exact_ match? */ + if (strcmp(fullname, e->fullname) == 0) { + return (e); + } + /* Looks like we found a parent of the correct path */ + if (fullname[len] == '/') { + if (e->files) { + return (find_filesystem_entry (e, fullname, type)); + } else { + return NULL; + } + } + } + } else { + if (strcmp(fullname, e->fullname) == 0) { + return (e); + } + } + e = e->next; + } + return (NULL); +} + +void CMkfsJFFS2::printProgressData(bool finish) +{ + static int p_old = -1; + int p = (finish) ? 100 : ((all_read/1024)*100 )/kbUsed; + if (p != p_old) { + p_old = p; + printf("mkfs.jffs2: %ld KB from %ld KB read (%d%%)\n", all_read / 1024, kbUsed, p); fflush(stdout); + } +} + +void CMkfsJFFS2::setProgressBarGlobal(int x1, int x2) +{ + progressBarGlobalX1 = x1; + progressBarGlobalX2 = x2; +} + +void CMkfsJFFS2::paintProgressBar() +{ + static int p_old = -1; + int p1 = ((all_read/1024)*100)/kbUsed; + if (p1 != p_old) { + p_old = p1; + int p2 = progressBarGlobalX1 + (((all_read/1024)*(progressBarGlobalX2-progressBarGlobalX1))/kbUsed); + progressBar->showLocalStatus(p1); + progressBar->showGlobalStatus(p2); + } +} + +unsigned int CMkfsJFFS2::write_regular_file(struct filesystem_entry *e) +{ + int fd, len; + uint32_t ver; + unsigned int offset; + unsigned char *buf, *cbuf, *wbuf; + struct jffs2_raw_inode ri; + struct stat *statbuf; + unsigned int totcomp = 0; + + statbuf = &(e->sb); + if ((uint32_t)statbuf->st_size >= JFFS2_MAX_FILE_SIZE) { + errmsg("Skipping file \"%s\" too large.", e->path); + return -1; + } + fd = open(e->hostname, O_RDONLY); + if (fd == -1) { + sys_errmsg("%s: open file", e->hostname); + } + + e->ino = ++ino; + mkfs_debug_msg("writing file '%s' ino=%lu parent_ino=%lu", + e->name, (unsigned long) e->ino, + (unsigned long) e->parent->ino); + write_dirent(e); + + buf = (unsigned char*)xmalloc(page_size); + cbuf = NULL; + + ver = 0; + offset = 0; + + memset(&ri, 0, sizeof(ri)); + ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + + ri.ino = cpu_to_je32(e->ino); + ri.mode = cpu_to_jemode(statbuf->st_mode); + ri.uid = cpu_to_je16(statbuf->st_uid); + ri.gid = cpu_to_je16(statbuf->st_gid); + ri.atime = cpu_to_je32(statbuf->st_atime); + ri.ctime = cpu_to_je32(statbuf->st_ctime); + ri.mtime = cpu_to_je32(statbuf->st_mtime); + ri.isize = cpu_to_je32(statbuf->st_size); + + while ((len = read(fd, buf, page_size))) { + unsigned char *tbuf = buf; + + if (len < 0) { + sys_errmsg("read"); + } + + if ((printProgress) || (progressBar)) { + all_read += len; + if (printProgress) + printProgressData(false); + if (progressBar) + paintProgressBar(); + } + + while (len) { + uint32_t dsize, space; + uint16_t compression; + + pad_block_if_less_than(sizeof(ri) + JFFS2_MIN_DATA_LEN); + + dsize = len; + space = + erase_block_size - (out_ofs % erase_block_size) - + sizeof(ri); + if (space > dsize) + space = dsize; + + compression = jffs2_compress(tbuf, &cbuf, &dsize, &space); + + ri.compr = compression & 0xff; + ri.usercompr = (compression >> 8) & 0xff; + + if (ri.compr) { + wbuf = cbuf; + } else { + wbuf = tbuf; + dsize = space; + } + + ri.totlen = cpu_to_je32(sizeof(ri) + space); + ri.hdr_crc = cpu_to_je32(mtd_crc32(0, + &ri, sizeof(struct jffs2_unknown_node) - 4)); + + ri.version = cpu_to_je32(++ver); + ri.offset = cpu_to_je32(offset); + ri.csize = cpu_to_je32(space); + ri.dsize = cpu_to_je32(dsize); + ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8)); + ri.data_crc = cpu_to_je32(mtd_crc32(0, wbuf, space)); + + full_write(out_fd, &ri, sizeof(ri)); + totcomp += sizeof(ri); + full_write(out_fd, wbuf, space); + totcomp += space; + padword(); + + if (tbuf != cbuf) { + free(cbuf); + cbuf = NULL; + } + + tbuf += dsize; + len -= dsize; + offset += dsize; + + } + } + if (!je32_to_cpu(ri.version)) { + /* Was empty file */ + pad_block_if_less_than(sizeof(ri)); + + ri.version = cpu_to_je32(++ver); + ri.totlen = cpu_to_je32(sizeof(ri)); + ri.hdr_crc = cpu_to_je32(mtd_crc32(0, + &ri, sizeof(struct jffs2_unknown_node) - 4)); + ri.csize = cpu_to_je32(0); + ri.dsize = cpu_to_je32(0); + ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8)); + + full_write(out_fd, &ri, sizeof(ri)); + padword(); + } + free(buf); + close(fd); + return totcomp; +} + +void CMkfsJFFS2::write_symlink(struct filesystem_entry *e) +{ + int len; + struct stat *statbuf; + struct jffs2_raw_inode ri; + + statbuf = &(e->sb); + e->ino = ++ino; + mkfs_debug_msg("writing symlink '%s' ino=%lu parent_ino=%lu", + e->name, (unsigned long) e->ino, + (unsigned long) e->parent->ino); + write_dirent(e); + + len = strlen(e->link); + if (len > JFFS2_MAX_SYMLINK_LEN) { + errmsg("symlink too large. Truncated to %d chars.", + JFFS2_MAX_SYMLINK_LEN); + len = JFFS2_MAX_SYMLINK_LEN; + } + + memset(&ri, 0, sizeof(ri)); + + ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri.totlen = cpu_to_je32(sizeof(ri) + len); + ri.hdr_crc = cpu_to_je32(mtd_crc32(0, + &ri, sizeof(struct jffs2_unknown_node) - 4)); + + ri.ino = cpu_to_je32(e->ino); + ri.mode = cpu_to_jemode(statbuf->st_mode); + ri.uid = cpu_to_je16(statbuf->st_uid); + ri.gid = cpu_to_je16(statbuf->st_gid); + ri.atime = cpu_to_je32(statbuf->st_atime); + ri.ctime = cpu_to_je32(statbuf->st_ctime); + ri.mtime = cpu_to_je32(statbuf->st_mtime); + ri.isize = cpu_to_je32(statbuf->st_size); + ri.version = cpu_to_je32(1); + ri.csize = cpu_to_je32(len); + ri.dsize = cpu_to_je32(len); + ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8)); + ri.data_crc = cpu_to_je32(mtd_crc32(0, e->link, len)); + + pad_block_if_less_than(sizeof(ri) + len); + full_write(out_fd, &ri, sizeof(ri)); + full_write(out_fd, e->link, len); + padword(); +} + +void CMkfsJFFS2::write_pipe(struct filesystem_entry *e) +{ + struct stat *statbuf; + struct jffs2_raw_inode ri; + + statbuf = &(e->sb); + e->ino = ++ino; + if (S_ISDIR(statbuf->st_mode)) { + mkfs_debug_msg("writing dir '%s' ino=%lu parent_ino=%lu", + e->name, (unsigned long) e->ino, + (unsigned long) (e->parent) ? e->parent->ino : 1); + } + write_dirent(e); + + memset(&ri, 0, sizeof(ri)); + + ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri.totlen = cpu_to_je32(sizeof(ri)); + ri.hdr_crc = cpu_to_je32(mtd_crc32(0, + &ri, sizeof(struct jffs2_unknown_node) - 4)); + + ri.ino = cpu_to_je32(e->ino); + ri.mode = cpu_to_jemode(statbuf->st_mode); + ri.uid = cpu_to_je16(statbuf->st_uid); + ri.gid = cpu_to_je16(statbuf->st_gid); + ri.atime = cpu_to_je32(statbuf->st_atime); + ri.ctime = cpu_to_je32(statbuf->st_ctime); + ri.mtime = cpu_to_je32(statbuf->st_mtime); + ri.isize = cpu_to_je32(0); + ri.version = cpu_to_je32(1); + ri.csize = cpu_to_je32(0); + ri.dsize = cpu_to_je32(0); + ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8)); + ri.data_crc = cpu_to_je32(0); + + pad_block_if_less_than(sizeof(ri)); + full_write(out_fd, &ri, sizeof(ri)); + padword(); +} + +void CMkfsJFFS2::write_special_file(struct filesystem_entry *e) +{ + jint16_t kdev; + struct stat *statbuf; + struct jffs2_raw_inode ri; + + statbuf = &(e->sb); + e->ino = ++ino; + write_dirent(e); + + kdev = cpu_to_je16((major(statbuf->st_rdev) << 8) + + minor(statbuf->st_rdev)); + + memset(&ri, 0, sizeof(ri)); + + ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri.totlen = cpu_to_je32(sizeof(ri) + sizeof(kdev)); + ri.hdr_crc = cpu_to_je32(mtd_crc32(0, + &ri, sizeof(struct jffs2_unknown_node) - 4)); + + ri.ino = cpu_to_je32(e->ino); + ri.mode = cpu_to_jemode(statbuf->st_mode); + ri.uid = cpu_to_je16(statbuf->st_uid); + ri.gid = cpu_to_je16(statbuf->st_gid); + ri.atime = cpu_to_je32(statbuf->st_atime); + ri.ctime = cpu_to_je32(statbuf->st_ctime); + ri.mtime = cpu_to_je32(statbuf->st_mtime); + ri.isize = cpu_to_je32(statbuf->st_size); + ri.version = cpu_to_je32(1); + ri.csize = cpu_to_je32(sizeof(kdev)); + ri.dsize = cpu_to_je32(sizeof(kdev)); + ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8)); + ri.data_crc = cpu_to_je32(mtd_crc32(0, &kdev, sizeof(kdev))); + + pad_block_if_less_than(sizeof(ri) + sizeof(kdev)); + full_write(out_fd, &ri, sizeof(ri)); + full_write(out_fd, &kdev, sizeof(kdev)); + padword(); +} + +void CMkfsJFFS2::write_dirent(struct filesystem_entry *e) +{ + char *name = e->name; + struct jffs2_raw_dirent rd; + struct stat *statbuf = &(e->sb); + static uint32_t version = 0; + + memset(&rd, 0, sizeof(rd)); + + rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); + rd.totlen = cpu_to_je32(sizeof(rd) + strlen(name)); + rd.hdr_crc = cpu_to_je32(mtd_crc32(0, &rd, + sizeof(struct jffs2_unknown_node) - 4)); + rd.pino = cpu_to_je32((e->parent) ? e->parent->ino : 1); + rd.version = cpu_to_je32(version++); + rd.ino = cpu_to_je32(e->ino); + rd.mctime = cpu_to_je32(statbuf->st_mtime); + rd.nsize = strlen(name); + rd.type = IFTODT(statbuf->st_mode); + //rd.unused[0] = 0; + //rd.unused[1] = 0; + rd.node_crc = cpu_to_je32(mtd_crc32(0, &rd, sizeof(rd) - 8)); + rd.name_crc = cpu_to_je32(mtd_crc32(0, name, strlen(name))); + + pad_block_if_less_than(sizeof(rd) + rd.nsize); + full_write(out_fd, &rd, sizeof(rd)); + full_write(out_fd, name, rd.nsize); + padword(); +} + +uint32_t CMkfsJFFS2::find_hardlink(struct filesystem_entry *e) +{ + struct rb_node **n = &hardlinks.rb_node; + struct rb_node *parent = NULL; + + while (*n) { + struct filesystem_entry *f; + parent = *n; + f = rb_entry(parent, struct filesystem_entry, hardlink_rb); + if ((f->sb.st_dev < e->sb.st_dev) || + (f->sb.st_dev == e->sb.st_dev && + f->sb.st_ino < e->sb.st_ino)) + n = &parent->rb_left; + else if ((f->sb.st_dev > e->sb.st_dev) || + (f->sb.st_dev == e->sb.st_dev && + f->sb.st_ino > e->sb.st_ino)) { + n = &parent->rb_right; + } else + return f->ino; + } + + rb_link_node(&e->hardlink_rb, parent, n); + rb_insert_color(&e->hardlink_rb, &hardlinks); + return 0; +} + +void CMkfsJFFS2::full_write(int fd, const void *buf, int len) +{ + char* buf1 = (char*)buf; + + while (len > 0) { + int ret = write(fd, buf1, len); + + if (ret < 0) + sys_errmsg("write"); + + if (ret == 0) + sys_errmsg("write returned zero"); + + len -= ret; + buf1 += ret; + out_ofs += ret; + } +} + +void CMkfsJFFS2::pad_block_if_less_than(int req) +{ + if (add_cleanmarkers) { + if ((out_ofs % erase_block_size) == 0) { + full_write(out_fd, &cleanmarker, sizeof(cleanmarker)); + pad(cleanmarker_size - sizeof(cleanmarker)); + padword(); + } + } + if ((out_ofs % erase_block_size) + req > erase_block_size) { + padblock(); + } + if (add_cleanmarkers) { + if ((out_ofs % erase_block_size) == 0) { + full_write(out_fd, &cleanmarker, sizeof(cleanmarker)); + pad(cleanmarker_size - sizeof(cleanmarker)); + padword(); + } + } +} + +void CMkfsJFFS2::padblock(void) +{ + while (out_ofs % erase_block_size) { + full_write(out_fd, ffbuf, min(sizeof(ffbuf), + erase_block_size - (out_ofs % erase_block_size))); + } +} + +void CMkfsJFFS2::pad(int req) +{ + while (req) { + if (req > (int)sizeof(ffbuf)) { + full_write(out_fd, ffbuf, sizeof(ffbuf)); + req -= sizeof(ffbuf); + } else { + full_write(out_fd, ffbuf, req); + req = 0; + } + } +} + +void CMkfsJFFS2::recursive_populate_directory(struct filesystem_entry *dir) +{ + struct filesystem_entry *e; + e = dir->files; + while (e) { + if (e->sb.st_nlink >= 1 && (e->ino = find_hardlink(e))) + write_dirent(e); + else { + switch (e->sb.st_mode & S_IFMT) { + case S_IFDIR: + write_pipe(e); + break; + case S_IFSOCK: + write_pipe(e); + break; + case S_IFIFO: + write_pipe(e); + break; + case S_IFCHR: + write_special_file(e); + break; + case S_IFBLK: + write_special_file(e); + break; + case S_IFLNK: + write_symlink(e); + break; + case S_IFREG: + write_regular_file(e); + break; + default: + errmsg("Unknown mode %o for %s", e->sb.st_mode, + e->fullname); + break; + } + + if ((printProgress) || (progressBar)) { + switch (e->sb.st_mode & S_IFMT) { + case S_IFDIR: + case S_IFSOCK: + case S_IFIFO: + case S_IFCHR: + case S_IFBLK: + case S_IFLNK: + all_read += e->sb.st_size; + break; + default: + break; + } + } + } + + if (printProgress) + printProgressData(false); + if (progressBar) + paintProgressBar(); + e = e->next; + } + + e = dir->files; + while (e) { + if (S_ISDIR(e->sb.st_mode)) { + if (e->files) { + recursive_populate_directory(e); + } + } + e = e->next; + } +} + +void CMkfsJFFS2::create_target_filesystem(struct filesystem_entry *root) +{ + cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); + cleanmarker.totlen = cpu_to_je32(cleanmarker_size); + cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4)); + + if (ino == 0) + ino = 1; + + root->ino = 1; + recursive_populate_directory(root); + + if (pad_fs_size == -1) { + padblock(); + } else { + if (pad_fs_size && add_cleanmarkers) { + padblock(); + while (out_ofs < pad_fs_size) { + full_write(out_fd, &cleanmarker, sizeof(cleanmarker)); + pad(cleanmarker_size - sizeof(cleanmarker)); + padblock(); + } + } else { + while (out_ofs < pad_fs_size) { + full_write(out_fd, ffbuf, min(sizeof(ffbuf), pad_fs_size - out_ofs)); + } + + } + } +} + +/* device table entries take the form of: + + /dev/mem c 640 0 0 1 1 0 0 - + + type can be one of: + f A regular file + d Directory + c Character special device file + b Block special device file + p Fifo (named pipe) + + I don't bother with symlinks (permissions are irrelevant), hard + links (special cases of regular files), or sockets (why bother). + + Regular files must exist in the target root directory. If a char, + block, fifo, or directory does not exist, it will be created. + */ +int CMkfsJFFS2::interpret_table_entry(struct filesystem_entry *root, char *line) +{ + char *hostpath; + char type; + char name[512]; + unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; + unsigned long start = 0, increment = 1, count = 0; + struct filesystem_entry *entry; + + memset(name, '\0', 512); + if (sscanf (line, "%511s %c %lo %lu %lu %lu %lu %lu %lu %lu", + name, &type, &mode, &uid, &gid, &major, &minor, &start, &increment, &count) < 0) + return 1; + + if (!strcmp(name, "/")) { + sys_errmsg("Device table entries require absolute paths"); + } + + xasprintf(&hostpath, "%s%s", rootdir.c_str(), name); + + /* Check if this file already exists... */ + switch (type) { + case 'd': + mode |= S_IFDIR; + break; + case 'f': + mode |= S_IFREG; + break; + case 'p': + mode |= S_IFIFO; + break; + case 'c': + mode |= S_IFCHR; + break; + case 'b': + mode |= S_IFBLK; + break; + case 'l': + mode |= S_IFLNK; + break; + default: + sys_errmsg("Unsupported file type '%c'", type); + } + entry = find_filesystem_entry(root, name, mode); + if (entry && !(count > 0 && (type == 'c' || type == 'b'))) { + /* Ok, we just need to fixup the existing entry + * and we will be all done... */ + entry->sb.st_uid = uid; + entry->sb.st_gid = gid; + entry->sb.st_mode = mode; + if (major && minor) { + entry->sb.st_rdev = makedev(major, minor); + } + } else { + /* If parent is NULL (happens with device table entries), + * try and find our parent now) */ + char *tmp, *dir; + struct filesystem_entry *parent; + tmp = strdup(name); + dir = dirname(tmp); + parent = find_filesystem_entry(root, dir, S_IFDIR); + free(tmp); + if (parent == NULL) { + errmsg ("skipping device_table entry '%s': no parent directory!", name); + free(hostpath); + return 1; + } + + switch (type) { + case 'd': + add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); + break; + case 'f': + add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); + break; + case 'p': + add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); + break; + case 'c': + case 'b': + if (count > 0) { + dev_t rdev; + unsigned long i; + char *dname, *hpath; + + for (i = start; i < (start + count); i++) { + xasprintf(&dname, "%s%lu", name, i); + xasprintf(&hpath, "%s/%s%lu", rootdir.c_str(), name, i); + rdev = makedev(major, minor + (i - start) * increment); + add_host_filesystem_entry(dname, hpath, uid, gid, + mode, rdev, parent); + free(dname); + free(hpath); + } + } else { + dev_t rdev = makedev(major, minor); + add_host_filesystem_entry(name, hostpath, uid, gid, + mode, rdev, parent); + } + break; + default: + sys_errmsg("Unsupported file type '%c'", type); + } + } + free(hostpath); + return 0; +} + +int CMkfsJFFS2::parse_device_table(struct filesystem_entry *root, FILE * file) +{ + char *line; + int status = 0; + size_t length = 0; + + /* Turn off squash, since we must ensure that values + * entered via the device table are not squashed */ + squash_uids = 0; + squash_perms = 0; + + /* Looks ok so far. The general plan now is to read in one + * line at a time, check for leading comment delimiters ('#'), + * then try and parse the line as a device table. If we fail + * to parse things, try and help the poor fool to fix their + * device table with a useful error msg... */ + line = NULL; + while (getline(&line, &length, file) != -1) { + /* First trim off any whitespace */ + int len = strlen(line); + + /* trim trailing whitespace */ + while (len > 0 && isspace(line[len - 1])) + line[--len] = '\0'; + /* trim leading whitespace */ + memmove(line, &line[strspn(line, " \n\r\t\v")], len); + + /* How long are we after trimming? */ + len = strlen(line); + + /* If this is NOT a comment line, try to interpret it */ + if (len && *line != '#') { + if (interpret_table_entry(root, line)) + status = 1; + } + + free(line); + line = NULL; + } + fclose(file); + + return status; +} + +struct filesystem_entry *CMkfsJFFS2::recursive_add_host_directory( + struct filesystem_entry *parent, const char *targetpath, + const char *hostpath, + bool skipSpezialFolders) { + int i, n; + struct stat sb; + char *hpath, *tpath; + struct dirent **namelist; + struct filesystem_entry *entry; + bool skipCheck = false; + + if (lstat(hostpath, &sb)) { + sys_errmsg("%s", hostpath); + } + if (skipSpezialFolders) { + // check for spezial folders and mounted folders + struct statfs s; + ::statfs(hostpath, &s); + switch (s.f_type) { + case 0xEF53L: /*EXT2 & EXT3*/ + case 0x6969L: /*NFS*/ + case 0xFF534D42L: /*CIFS*/ + case 0x517BL: /*SMB*/ + case 0x52654973L: /*REISERFS*/ + case 0x65735546L: /*fuse for ntfs*/ + case 0x58465342L: /*xfs*/ + case 0x4d44L: /*msdos*/ + skipCheck = true; + break; + } + + if (((sb.st_dev == dev_x[dev_dev]) && (strstr(targetpath, "/dev") == targetpath)) || + ((sb.st_dev == dev_x[dev_proc]) && (strstr(targetpath, "/proc") == targetpath)) || + ((sb.st_dev == dev_x[dev_sys]) && (strstr(targetpath, "/sys") == targetpath)) || + ((sb.st_dev == dev_x[dev_tmp]) && (strstr(targetpath, "/tmp") == targetpath))) { + skipCheck = true; + } + + if ((!skipCheck) && +#if 0 + (sb.st_dev != dev_x[dev_dev]) && /* /dev */ + (sb.st_dev != dev_x[dev_pts]) && /* /dev/pts */ +#endif + (sb.st_dev != dev_x[dev_jffs2])) /* jffs2 */ + return NULL; + } + + entry = add_host_filesystem_entry(targetpath, hostpath, + sb.st_uid, sb.st_gid, sb.st_mode, 0, parent); + + if ((skipSpezialFolders) && (skipCheck)) + return NULL; + +#if 0 + if (strstr(targetpath, "/var/epg") == targetpath) + return NULL; +#endif + + n = scandir(hostpath, &namelist, 0, alphasort); + if (n < 0) { + sys_errmsg("opening directory %s", hostpath); + } + + for (i=0; id_name[0] == '.' && (dp->d_name[1] == 0 || + (dp->d_name[1] == '.' && dp->d_name[2] == 0))) { + free(dp); + continue; + } + + xasprintf(&hpath, "%s/%s", hostpath, dp->d_name); + if (lstat(hpath, &sb)) { + sys_errmsg("%s", hpath); + } + if (strcmp(targetpath, "/") == 0) { + xasprintf(&tpath, "%s%s", targetpath, dp->d_name); + } else { + xasprintf(&tpath, "%s/%s", targetpath, dp->d_name); + } + + switch (sb.st_mode & S_IFMT) { + case S_IFDIR: + recursive_add_host_directory(entry, tpath, hpath, skipSpezialFolders); + break; + + case S_IFREG: + case S_IFSOCK: + case S_IFIFO: + case S_IFLNK: + case S_IFCHR: + case S_IFBLK: + add_host_filesystem_entry(tpath, hpath, sb.st_uid, + sb.st_gid, sb.st_mode, sb.st_rdev, entry); + break; + + default: + errmsg("Unknown file type %o for %s", sb.st_mode, hpath); + break; + } + free(dp); + free(hpath); + free(tpath); + } + free(namelist); + return (entry); +} + +#ifdef __GNUC__ +#define GETCWD_SIZE 0 +#else +#define GETCWD_SIZE -1 +#endif + +bool CMkfsJFFS2::makeJffs2Image(std::string& path, + std::string& imageName, + int eraseBlockSize/*=0x20000*/, + int padFsSize/*=0*/, + int addCleanmarkers/*=0*/, + int targetEndian/*=__LITTLE_ENDIAN*/, + bool skipSpezialFolders/*=true*/, + bool useSumtool/*=true*/, + CProgressWindow *progress/*=NULL*/, + bool useDevTable/*=true*/, + std::string devTable/*=""*/) +{ + + Init(); + + imageName_ = imageName; + useSumtool_ = useSumtool; + erase_block_size = eraseBlockSize; // -e + FILE *devtable = NULL; // -D + pad_fs_size = padFsSize; // -p + add_cleanmarkers = addCleanmarkers; // -n + target_endian = targetEndian; // -l + squash_uids = 1; // -U + rootdir = path; // -r + printProgress = 1; + progressBar = progress; + hardlinks.rb_node = NULL; + + printf("[%s] erase_block_size: 0x%X\n", __FUNCTION__, eraseBlockSize); + if (useDevTable) { + if (devTable == "") { + devTable = "/tmp/devtable.txt"; + devtable = fopen(devTable.c_str(), "w+"); + if (devtable) { + std::string dev = "/dev/console c 0600 0 0 5 1 0 0 0\n"; + fwrite(dev.c_str(), dev.length(), 1, devtable); + dev = "/dev/null c 0666 0 0 1 3 0 0 0\n"; + fwrite(dev.c_str(), dev.length(), 1, devtable); + fclose(devtable); + } + } + devtable = fopen(devTable.c_str(), "r"); + } + + classInit(); + + char *cwd; + struct stat sb; + if (lstat(rootdir.c_str(), &sb)) { + sys_errmsg("%s", rootdir.c_str()); + } + if (chdir(rootdir.c_str())) + sys_errmsg("%s", rootdir.c_str()); + if (!(cwd = getcwd(0, GETCWD_SIZE))) + sys_errmsg("getcwd failed"); + + if (skipSpezialFolders) { + std::string tmpPath = (path == "/") ? "" : path; +// std::string path_x[dev_max] = {tmpPath + "/sys", tmpPath + "/proc", tmpPath + "/tmp", tmpPath + "/dev/pts", tmpPath + "/dev", tmpPath + "/"}; + std::string path_x[dev_max] = {tmpPath + "/sys", tmpPath + "/proc", tmpPath + "/tmp", tmpPath + "/dev", tmpPath + "/"}; + + for (int ix = dev_sys; ix < dev_max; ix++) { + if (lstat(path_x[ix].c_str(), &sb) == 0) + dev_x[ix] = sb.st_dev; + else + dev_x[ix] = 0; + } + } + + fse_root = recursive_add_host_directory(NULL, "/", cwd, skipSpezialFolders); + if (devtable) + parse_device_table(fse_root, devtable); + + pid_t pid; + std::string pcmd = "du -sx " + rootdir; + FILE* fp = my_popen(pid, pcmd.c_str(), "r"); + if (fp != NULL) { + char buff[256]; + fgets(buff, sizeof(buff), fp); + fclose(fp); + kbUsed = atol(buff); + } + if (kbUsed == 0) + kbUsed = 60000; + + create_target_filesystem(fse_root); + if (printProgress) + printProgressData(true); + + classClear(); + + sync(); + if (useSumtool_) { + CSumtoolJFFS2 st; + st.sumtool(imageName_, sumName_, eraseBlockSize, ((padFsSize==0)?0:1), addCleanmarkers, targetEndian); + unlink(imageName_.c_str()); + sync(); + } + + progressBar = NULL; + return true; +} diff --git a/src/system/mtdutils/mkfs.jffs2.h b/src/system/mtdutils/mkfs.jffs2.h new file mode 100644 index 000000000..54f1a3333 --- /dev/null +++ b/src/system/mtdutils/mkfs.jffs2.h @@ -0,0 +1,118 @@ + +#ifndef __MKFS_JFFS2__ +#define __MKFS_JFFS2__ + +/* + Neutrino-HD + + License: GPL + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include + +#include +#include + +class CMkfsJFFS2 +{ + private: + enum { + dev_sys = 0, + dev_proc = 1, + dev_tmp = 2, +/* dev_pts = 3,*/ + dev_dev = 3, + dev_jffs2 = 4, + dev_max = 5 + }; + + int out_fd; + std::string rootdir; + int squash_uids; + int squash_perms; + int fake_times; + unsigned long int all_read; + int printProgress; + long kbUsed; + dev_t dev_x[dev_max]; + CProgressWindow *progressBar; + int progressBarGlobalX1; + int progressBarGlobalX2; + std::string imageName_, sumName_; + bool useSumtool_; + + uint32_t ino; + int out_ofs; + int erase_block_size; + int pad_fs_size; + int add_cleanmarkers; + int cleanmarker_size; + unsigned char ffbuf[16]; + bool compressorIsInit; + + void Init(); + void classClear(); + bool classInit(); + struct filesystem_entry *recursive_add_host_directory( + struct filesystem_entry *parent, const char *targetpath, + const char *hostpath, + bool skipSpezialFolders); + int parse_device_table(struct filesystem_entry *root, FILE * file); + int interpret_table_entry(struct filesystem_entry *root, char *line); + void create_target_filesystem(struct filesystem_entry *root); + void recursive_populate_directory(struct filesystem_entry *dir); + void padblock(void); + void pad(int req); + inline void padword(void) { if (out_ofs % 4) full_write(out_fd, ffbuf, 4 - (out_ofs % 4)); } + inline void pad_block_if_less_than(int req); + void full_write(int fd, const void *buf, int len); + static uint32_t find_hardlink(struct filesystem_entry *e); + void write_dirent(struct filesystem_entry *e); + void write_special_file(struct filesystem_entry *e); + void write_pipe(struct filesystem_entry *e); + void write_symlink(struct filesystem_entry *e); + unsigned int write_regular_file(struct filesystem_entry *e); + void paintProgressBar(); + void setProgressBarGlobal(int x1, int x2); + void printProgressData(bool finish); + struct filesystem_entry *find_filesystem_entry(struct filesystem_entry *dir, char *fullname, uint32_t type); + struct filesystem_entry *add_host_filesystem_entry(const char *name, + const char *path, unsigned long uid, unsigned long gid, + unsigned long mode, dev_t rdev, struct filesystem_entry *parent); + void cleanup(struct filesystem_entry *dir); + char *xreadlink(const char *path); + + public: + CMkfsJFFS2(); + ~CMkfsJFFS2(); + + bool makeJffs2Image(std::string& path, + std::string& imageName, + int eraseBlockSize=0x20000, + int padFsSize=0, + int addCleanmarkers=0, + int targetEndian=__LITTLE_ENDIAN, + bool skipSpezialFolders=true, + bool useSumtool=true, + CProgressWindow *progress=NULL, + bool useDevTable=true, + std::string devTable=""); + +}; + +#endif // __MKFS_JFFS2__ diff --git a/src/system/mtdutils/rbtree.cpp b/src/system/mtdutils/rbtree.cpp new file mode 100644 index 000000000..30d745ed3 --- /dev/null +++ b/src/system/mtdutils/rbtree.cpp @@ -0,0 +1,390 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + (C) 2002 David Woodhouse + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + linux/lib/rbtree.c +*/ + +#include +#include "rbtree.h" + +static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *right = node->rb_right; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_right = right->rb_left)) + rb_set_parent(right->rb_left, node); + right->rb_left = node; + + rb_set_parent(right, parent); + + if (parent) + { + if (node == parent->rb_left) + parent->rb_left = right; + else + parent->rb_right = right; + } + else + root->rb_node = right; + rb_set_parent(node, right); +} + +static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *left = node->rb_left; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_left = left->rb_right)) + rb_set_parent(left->rb_right, node); + left->rb_right = node; + + rb_set_parent(left, parent); + + if (parent) + { + if (node == parent->rb_right) + parent->rb_right = left; + else + parent->rb_left = left; + } + else + root->rb_node = left; + rb_set_parent(node, left); +} + +void rb_insert_color(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *parent, *gparent; + + while ((parent = rb_parent(node)) && rb_is_red(parent)) + { + gparent = rb_parent(parent); + + if (parent == gparent->rb_left) + { + { + register struct rb_node *uncle = gparent->rb_right; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_right == node) + { + register struct rb_node *tmp; + __rb_rotate_left(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_right(gparent, root); + } else { + { + register struct rb_node *uncle = gparent->rb_left; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_left == node) + { + register struct rb_node *tmp; + __rb_rotate_right(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_left(gparent, root); + } + } + + rb_set_black(root->rb_node); +} + +static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, + struct rb_root *root) +{ + struct rb_node *other; + + while ((!node || rb_is_black(node)) && node != root->rb_node) + { + if (parent->rb_left == node) + { + other = parent->rb_right; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_left(parent, root); + other = parent->rb_right; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_right || rb_is_black(other->rb_right)) + { + struct rb_node *o_left; + if ((o_left = other->rb_left)) + rb_set_black(o_left); + rb_set_red(other); + __rb_rotate_right(other, root); + other = parent->rb_right; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + if (other->rb_right) + rb_set_black(other->rb_right); + __rb_rotate_left(parent, root); + node = root->rb_node; + break; + } + } + else + { + other = parent->rb_left; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_right(parent, root); + other = parent->rb_left; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_left || rb_is_black(other->rb_left)) + { + register struct rb_node *o_right; + if ((o_right = other->rb_right)) + rb_set_black(o_right); + rb_set_red(other); + __rb_rotate_left(other, root); + other = parent->rb_left; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + if (other->rb_left) + rb_set_black(other->rb_left); + __rb_rotate_right(parent, root); + node = root->rb_node; + break; + } + } + } + if (node) + rb_set_black(node); +} + +void rb_erase(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *child, *parent; + int color; + + if (!node->rb_left) + child = node->rb_right; + else if (!node->rb_right) + child = node->rb_left; + else + { + struct rb_node *old = node, *left; + + node = node->rb_right; + while ((left = node->rb_left) != NULL) + node = left; + child = node->rb_right; + parent = rb_parent(node); + color = rb_color(node); + + if (child) + rb_set_parent(child, parent); + if (parent == old) { + parent->rb_right = child; + parent = node; + } else + parent->rb_left = child; + + node->rb_parent_color = old->rb_parent_color; + node->rb_right = old->rb_right; + node->rb_left = old->rb_left; + + if (rb_parent(old)) + { + if (rb_parent(old)->rb_left == old) + rb_parent(old)->rb_left = node; + else + rb_parent(old)->rb_right = node; + } else + root->rb_node = node; + + rb_set_parent(old->rb_left, node); + if (old->rb_right) + rb_set_parent(old->rb_right, node); + goto color; + } + + parent = rb_parent(node); + color = rb_color(node); + + if (child) + rb_set_parent(child, parent); + if (parent) + { + if (parent->rb_left == node) + parent->rb_left = child; + else + parent->rb_right = child; + } + else + root->rb_node = child; + + color: + if (color == RB_BLACK) + __rb_erase_color(child, parent, root); +} + +/* + * This function returns the first node (in sort order) of the tree. + */ +struct rb_node *rb_first(struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_left) + n = n->rb_left; + return n; +} + +struct rb_node *rb_last(struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_right) + n = n->rb_right; + return n; +} + +struct rb_node *rb_next(struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a right-hand child, go down and then left as far + as we can. */ + if (node->rb_right) { + node = node->rb_right; + while (node->rb_left) + node=node->rb_left; + return node; + } + + /* No right-hand children. Everything down and left is + smaller than us, so any 'next' node must be in the general + direction of our parent. Go up the tree; any time the + ancestor is a right-hand child of its parent, keep going + up. First time it's a left-hand child of its parent, said + parent is our 'next' node. */ + while ((parent = rb_parent(node)) && node == parent->rb_right) + node = parent; + + return parent; +} + +struct rb_node *rb_prev(struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a left-hand child, go down and then right as far + as we can. */ + if (node->rb_left) { + node = node->rb_left; + while (node->rb_right) + node=node->rb_right; + return node; + } + + /* No left-hand children. Go up till we find an ancestor which + is a right-hand child of its parent */ + while ((parent = rb_parent(node)) && node == parent->rb_left) + node = parent; + + return parent; +} + +void rb_replace_node(struct rb_node *victim, struct rb_node *new_, + struct rb_root *root) +{ + struct rb_node *parent = rb_parent(victim); + + /* Set the surrounding nodes to point to the replacement */ + if (parent) { + if (victim == parent->rb_left) + parent->rb_left = new_; + else + parent->rb_right = new_; + } else { + root->rb_node = new_; + } + if (victim->rb_left) + rb_set_parent(victim->rb_left, new_); + if (victim->rb_right) + rb_set_parent(victim->rb_right, new_); + + /* Copy the pointers/colour from the victim to the replacement */ + *new_ = *victim; +} diff --git a/src/system/mtdutils/rbtree.h b/src/system/mtdutils/rbtree.h new file mode 100644 index 000000000..0c5345b82 --- /dev/null +++ b/src/system/mtdutils/rbtree.h @@ -0,0 +1,171 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + linux/include/linux/rbtree.h + + To use rbtrees you'll have to implement your own insert and search cores. + This will avoid us to use callbacks and to drop drammatically performances. + I know it's not the cleaner way, but in C (not in C++) to get + performances and genericity... + + Some example of insert and search follows here. The search is a plain + normal search over an ordered tree. The insert instead must be implemented + int two steps: as first thing the code must insert the element in + order as a red leaf in the tree, then the support library function + rb_insert_color() must be called. Such function will do the + not trivial work to rebalance the rbtree if necessary. + +----------------------------------------------------------------------- +static inline struct page * rb_search_page_cache(struct inode * inode, + unsigned long offset) +{ + struct rb_node * n = inode->i_rb_page_cache.rb_node; + struct page * page; + + while (n) + { + page = rb_entry(n, struct page, rb_page_cache); + + if (offset < page->offset) + n = n->rb_left; + else if (offset > page->offset) + n = n->rb_right; + else + return page; + } + return NULL; +} + +static inline struct page * __rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct rb_node ** p = &inode->i_rb_page_cache.rb_node; + struct rb_node * parent = NULL; + struct page * page; + + while (*p) + { + parent = *p; + page = rb_entry(parent, struct page, rb_page_cache); + + if (offset < page->offset) + p = &(*p)->rb_left; + else if (offset > page->offset) + p = &(*p)->rb_right; + else + return page; + } + + rb_link_node(node, parent, p); + + return NULL; +} + +static inline struct page * rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct page * ret; + if ((ret = __rb_insert_page_cache(inode, offset, node))) + goto out; + rb_insert_color(node, &inode->i_rb_page_cache); + out: + return ret; +} +----------------------------------------------------------------------- +*/ + +#ifndef _LINUX_RBTREE_H +#define _LINUX_RBTREE_H + +#include +#include + +struct rb_node +{ + unsigned long rb_parent_color; +#define RB_RED 0 +#define RB_BLACK 1 + struct rb_node *rb_right; + struct rb_node *rb_left; +} __attribute__((aligned(sizeof(long)))); + /* The alignment might seem pointless, but allegedly CRIS needs it */ + +struct rb_root +{ + struct rb_node *rb_node; +}; + + +#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) +#define rb_color(r) ((r)->rb_parent_color & 1) +#define rb_is_red(r) (!rb_color(r)) +#define rb_is_black(r) rb_color(r) +#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) +#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) + +static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) +{ + rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p; +} +static inline void rb_set_color(struct rb_node *rb, int color) +{ + rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; +} + +#define RB_ROOT (struct rb_root) { NULL, } + +/* Newer gcc versions take care of exporting this */ +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define rb_entry(ptr, type, member) container_of(ptr, type, member) + +#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) +#define RB_EMPTY_NODE(node) (rb_parent(node) == node) +#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) + +extern void rb_insert_color(struct rb_node *, struct rb_root *); +extern void rb_erase(struct rb_node *, struct rb_root *); + +/* Find logical next and previous nodes in a tree */ +extern struct rb_node *rb_next(struct rb_node *); +extern struct rb_node *rb_prev(struct rb_node *); +extern struct rb_node *rb_first(struct rb_root *); +extern struct rb_node *rb_last(struct rb_root *); + +/* Fast replacement of a single node without remove/rebalance/add/rebalance */ +extern void rb_replace_node(struct rb_node *victim, struct rb_node *new_, + struct rb_root *root); + +static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, + struct rb_node ** rb_link) +{ + node->rb_parent_color = (unsigned long )parent; + node->rb_left = node->rb_right = NULL; + + *rb_link = node; +} + +#endif /* _LINUX_RBTREE_H */ diff --git a/src/system/mtdutils/summary.h b/src/system/mtdutils/summary.h new file mode 100644 index 000000000..e9d95a5e9 --- /dev/null +++ b/src/system/mtdutils/summary.h @@ -0,0 +1,177 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2004 Ferenc Havasi , + * Zoltan Sogor , + * Patrik Kluba , + * University of Szeged, Hungary + * + * For licensing information, see the file 'LICENCE' in this directory. + */ + +#ifndef JFFS2_SUMMARY_H +#define JFFS2_SUMMARY_H + +#include + +#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ + c->free_size -= _x; c->dirty_size += _x; \ + jeb->free_size -= _x ; jeb->dirty_size += _x; \ +}while(0) +#define USED_SPACE(x) do { typeof(x) _x = (x); \ + c->free_size -= _x; c->used_size += _x; \ + jeb->free_size -= _x ; jeb->used_size += _x; \ +}while(0) +#define WASTED_SPACE(x) do { typeof(x) _x = (x); \ + c->free_size -= _x; c->wasted_size += _x; \ + jeb->free_size -= _x ; jeb->wasted_size += _x; \ +}while(0) +#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \ + c->free_size -= _x; c->unchecked_size += _x; \ + jeb->free_size -= _x ; jeb->unchecked_size += _x; \ +}while(0) + +#define BLK_STATE_ALLFF 0 +#define BLK_STATE_CLEAN 1 +#define BLK_STATE_PARTDIRTY 2 +#define BLK_STATE_CLEANMARKER 3 +#define BLK_STATE_ALLDIRTY 4 +#define BLK_STATE_BADBLOCK 5 + +#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff +#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash)) +#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x)) +#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash)) +#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash)) + +/* Summary structures used on flash */ + +struct jffs2_sum_unknown_flash +{ + jint16_t nodetype; /* node type */ +} __attribute__((packed)); + +struct jffs2_sum_inode_flash +{ + jint16_t nodetype; /* node type */ + jint32_t inode; /* inode number */ + jint32_t version; /* inode version */ + jint32_t offset; /* offset on jeb */ + jint32_t totlen; /* record length */ +} __attribute__((packed)); + +struct jffs2_sum_dirent_flash +{ + jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ + jint32_t totlen; /* record length */ + jint32_t offset; /* ofset on jeb */ + jint32_t pino; /* parent inode */ + jint32_t version; /* dirent version */ + jint32_t ino; /* == zero for unlink */ + uint8_t nsize; /* dirent name size */ + uint8_t type; /* dirent type */ + uint8_t name[0]; /* dirent name */ +} __attribute__((packed)); + +struct jffs2_sum_xattr_flash +{ + jint16_t nodetype; /* == JFFS2_NODETYPE_XATR */ + jint32_t xid; /* xattr identifier */ + jint32_t version; /* version number */ + jint32_t offset; /* offset on jeb */ + jint32_t totlen; /* node length */ +} __attribute__((packed)); + +struct jffs2_sum_xref_flash +{ + jint16_t nodetype; /* == JFFS2_NODETYPE_XREF */ + jint32_t offset; /* offset on jeb */ +} __attribute__((packed)); + +union jffs2_sum_flash +{ + struct jffs2_sum_unknown_flash u; + struct jffs2_sum_inode_flash i; + struct jffs2_sum_dirent_flash d; + struct jffs2_sum_xattr_flash x; + struct jffs2_sum_xref_flash r; +}; + +/* Summary structures used in the memory */ + +struct jffs2_sum_unknown_mem +{ + union jffs2_sum_mem *next; + jint16_t nodetype; /* node type */ +} __attribute__((packed)); + +struct jffs2_sum_inode_mem +{ + union jffs2_sum_mem *next; + jint16_t nodetype; /* node type */ + jint32_t inode; /* inode number */ + jint32_t version; /* inode version */ + jint32_t offset; /* offset on jeb */ + jint32_t totlen; /* record length */ +} __attribute__((packed)); + +struct jffs2_sum_dirent_mem +{ + union jffs2_sum_mem *next; + jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ + jint32_t totlen; /* record length */ + jint32_t offset; /* ofset on jeb */ + jint32_t pino; /* parent inode */ + jint32_t version; /* dirent version */ + jint32_t ino; /* == zero for unlink */ + uint8_t nsize; /* dirent name size */ + uint8_t type; /* dirent type */ + uint8_t name[0]; /* dirent name */ +} __attribute__((packed)); + +struct jffs2_sum_xattr_mem +{ + union jffs2_sum_mem *next; + jint16_t nodetype; + jint32_t xid; + jint32_t version; + jint32_t offset; + jint32_t totlen; +} __attribute__((packed)); + +struct jffs2_sum_xref_mem +{ + union jffs2_sum_mem *next; + jint16_t nodetype; + jint32_t offset; +} __attribute__((packed)); + +union jffs2_sum_mem +{ + struct jffs2_sum_unknown_mem u; + struct jffs2_sum_inode_mem i; + struct jffs2_sum_dirent_mem d; + struct jffs2_sum_xattr_mem x; + struct jffs2_sum_xref_mem r; +}; + +struct jffs2_summary +{ + uint32_t sum_size; + uint32_t sum_num; + uint32_t sum_padded; + union jffs2_sum_mem *sum_list_head; + union jffs2_sum_mem *sum_list_tail; +}; + +/* Summary marker is stored at the end of every sumarized erase block */ + +struct jffs2_sum_marker +{ + jint32_t offset; /* offset of the summary node in the jeb */ + jint32_t magic; /* == JFFS2_SUM_MAGIC */ +}; + +#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker)) + +#endif diff --git a/src/system/mtdutils/sumtool.cpp b/src/system/mtdutils/sumtool.cpp new file mode 100644 index 000000000..97d1349b7 --- /dev/null +++ b/src/system/mtdutils/sumtool.cpp @@ -0,0 +1,766 @@ +/* + * sumtool.c + * + * Copyright (C) 2004 Zoltan Sogor , + * Ferenc Havasi + * University of Szeged, Hungary + * 2006 KaiGai Kohei + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Overview: + * This is a utility insert summary information into JFFS2 image for + * faster mount time + * + */ + +#define PROGRAM_NAME "sumtool" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "summary.h" +#include "common.h" +#include "sumtool.h" + +#define PAD(x) (((x)+3)&~3) + +struct jffs2_summary *sum_collected = NULL; + +extern struct jffs2_unknown_node cleanmarker; +extern int target_endian; + +CSumtoolJFFS2::CSumtoolJFFS2() +{ + Init(); +} + +CSumtoolJFFS2::~CSumtoolJFFS2() +{ + classClear(); +} + +bool CSumtoolJFFS2::classInit() +{ + out_fd = open(sumName_.c_str(), O_CREAT | O_TRUNC | O_RDWR, 0644); + if (out_fd == -1) { + sys_errmsg("open output file: %s", sumName_.c_str()); + return false; + } + in_fd = open(imageName_.c_str(), O_RDONLY); + if (in_fd == -1) { + sys_errmsg("open input file: %s", imageName_.c_str()); + return false; + } + init_buffers(); + init_sumlist(); + return true; +} + +void CSumtoolJFFS2::classClear() +{ + clean_buffers(); + clean_sumlist(); + + if (in_fd != -1) { + close(in_fd); + in_fd = -1; + } + if (out_fd != -1) { + close(out_fd); + out_fd = -1; + } +} + +void CSumtoolJFFS2::Init() +{ + verbose = 0; + sum_collected = NULL; + padto = 0; /* pad the output with 0xFF to the end of the final eraseblock */ + add_cleanmarkers = 1; /* add cleanmarker to output */ + use_input_cleanmarker_size = 1; /* use input file's cleanmarker size (default) */ + found_cleanmarkers = 0; /* cleanmarker found in input file */ + cleanmarker_size = sizeof(cleanmarker); + erase_block_size = 65536; + out_fd = -1; + in_fd = -1; + data_buffer = NULL; /* buffer for inodes */ + data_ofs = 0; /* inode buffer offset */ + file_buffer = NULL; /* file buffer contains the actual erase block*/ + file_ofs = 0; /* position in the buffer */ + imageName_ = ""; + sumName_ = ""; + memset(ffbuf, 0xFF, sizeof(ffbuf)); +} + +void CSumtoolJFFS2::setup_cleanmarker(void) +{ + cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); + cleanmarker.totlen = cpu_to_je32(cleanmarker_size); + cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4)); +} + +void CSumtoolJFFS2::add_sum_inode_mem(union jffs2_node_union *node) +{ + struct jffs2_sum_inode_mem *temp = reinterpret_cast(xmalloc(sizeof(*temp))); + + temp->nodetype = node->i.nodetype; + temp->inode = node->i.ino; + temp->version = node->i.version; + temp->offset = cpu_to_je32(data_ofs); + temp->totlen = node->i.totlen; + temp->next = NULL; + + add_sum_mem((union jffs2_sum_mem *) temp); +} + +void CSumtoolJFFS2::add_sum_dirent_mem(union jffs2_node_union *node) +{ + struct jffs2_sum_dirent_mem *temp = reinterpret_cast(xmalloc(sizeof(*temp) + node->d.nsize)); + + temp->nodetype = node->d.nodetype; + temp->totlen = node->d.totlen; + temp->offset = cpu_to_je32(data_ofs); + temp->pino = node->d.pino; + temp->version = node->d.version; + temp->ino = node->d.ino; + temp->nsize = node->d.nsize; + temp->type = node->d.type; + temp->next = NULL; + + memcpy(temp->name,node->d.name,node->d.nsize); + add_sum_mem((union jffs2_sum_mem *) temp); +} + +void CSumtoolJFFS2::add_sum_xattr_mem(union jffs2_node_union *node) +{ + struct jffs2_sum_xattr_mem *temp = reinterpret_cast(xmalloc(sizeof(*temp))); + + temp->nodetype = node->x.nodetype; + temp->xid = node->x.xid; + temp->version = node->x.version; + temp->offset = cpu_to_je32(data_ofs); + temp->totlen = node->x.totlen; + temp->next = NULL; + + add_sum_mem((union jffs2_sum_mem *) temp); +} + +void CSumtoolJFFS2::add_sum_xref_mem(union jffs2_node_union *node) +{ + struct jffs2_sum_xref_mem *temp = reinterpret_cast(xmalloc(sizeof(*temp))); + + temp->nodetype = node->r.nodetype; + temp->offset = cpu_to_je32(data_ofs); + temp->next = NULL; + + add_sum_mem((union jffs2_sum_mem *) temp); +} + +int CSumtoolJFFS2::add_sum_mem(union jffs2_sum_mem *item) +{ + + if (!sum_collected->sum_list_head) + sum_collected->sum_list_head = (union jffs2_sum_mem *) item; + if (sum_collected->sum_list_tail) + sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item; + sum_collected->sum_list_tail = (union jffs2_sum_mem *) item; + + switch (je16_to_cpu(item->u.nodetype)) { + case JFFS2_NODETYPE_INODE: + sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE; + sum_collected->sum_num++; + break; + + case JFFS2_NODETYPE_DIRENT: + sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize); + sum_collected->sum_num++; + break; + + case JFFS2_NODETYPE_XATTR: + sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE; + sum_collected->sum_num++; + break; + + case JFFS2_NODETYPE_XREF: + sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE; + sum_collected->sum_num++; + break; + + default: + sys_errmsg("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype)); + } + return 0; +} + +void CSumtoolJFFS2::write_dirent_to_buff(union jffs2_node_union *node) +{ + pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize)); + add_sum_dirent_mem(node); + full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen)); + padword(); +} + + +void CSumtoolJFFS2::write_inode_to_buff(union jffs2_node_union *node) +{ + pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE); + add_sum_inode_mem(node); /* Add inode summary mem to summary list */ + full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen)); /* Write out the inode to inode_buffer */ + padword(); +} + +void CSumtoolJFFS2::write_xattr_to_buff(union jffs2_node_union *node) +{ + pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE); + add_sum_xattr_mem(node); /* Add xdatum summary mem to summary list */ + full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen)); + padword(); +} + +void CSumtoolJFFS2::write_xref_to_buff(union jffs2_node_union *node) +{ + pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE); + add_sum_xref_mem(node); /* Add xref summary mem to summary list */ + full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen)); + padword(); +} + +void CSumtoolJFFS2::pad_block_if_less_than(int req,int plus) +{ + + int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8; + datasize += (4 - (datasize % 4)) % 4; + + if ((int)data_ofs + req > erase_block_size - datasize) { + dump_sum_records(); + write_buff_to_file(); + } + + if (add_cleanmarkers && found_cleanmarkers) { + if (!data_ofs) { + full_write(data_buffer, &cleanmarker, sizeof(cleanmarker)); + pad(cleanmarker_size - sizeof(cleanmarker)); + padword(); + } + } +} + +void CSumtoolJFFS2::pad(int req) +{ + while (req) { + if (req > (int)sizeof(ffbuf)) { + full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf)); + req -= sizeof(ffbuf); + } else { + full_write(data_buffer + data_ofs, ffbuf, req); + req = 0; + } + } +} + +void CSumtoolJFFS2::full_write(void *target_buff, const void *buf, int len) +{ + memcpy(target_buff, buf, len); + data_ofs += len; +} + +void CSumtoolJFFS2::write_buff_to_file(void) +{ + int len = data_ofs; + + uint8_t *buf = NULL; + + buf = data_buffer; + while (len > 0) { + int ret = write(out_fd, buf, len); + + if (ret < 0) + sys_errmsg("write"); + + if (ret == 0) + sys_errmsg("write returned zero"); + + len -= ret; + buf += ret; + } + + data_ofs = 0; +} + +void CSumtoolJFFS2::dump_sum_records(void) +{ + + struct jffs2_raw_summary isum; + struct jffs2_sum_marker *sm; + jint32_t offset; + jint32_t *tpage; + char *wpage; + int datasize, infosize, padsize; + jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC); + + if (!sum_collected->sum_num || !sum_collected->sum_list_head) + return; + + datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker); + infosize = sizeof(struct jffs2_raw_summary) + datasize; + padsize = erase_block_size - data_ofs - infosize; + infosize += padsize; datasize += padsize; + offset = cpu_to_je32(data_ofs); + + tpage = (jint32_t*)xmalloc(datasize); + + memset(tpage, 0xff, datasize); + memset(&isum, 0, sizeof(isum)); + + isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY); + isum.totlen = cpu_to_je32(infosize); + isum.hdr_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4)); + isum.padded = cpu_to_je32(0); + + if (add_cleanmarkers && found_cleanmarkers) { + isum.cln_mkr = cpu_to_je32(cleanmarker_size); + } else { + isum.cln_mkr = cpu_to_je32(0); + } + + isum.sum_num = cpu_to_je32(sum_collected->sum_num); + wpage = (char*)tpage; + + while (sum_collected->sum_num) { + switch (je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) { + + case JFFS2_NODETYPE_INODE : { + struct jffs2_sum_inode_flash *sino_ptr = reinterpret_cast(wpage); + + sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype; + sino_ptr->inode = sum_collected->sum_list_head->i.inode; + sino_ptr->version = sum_collected->sum_list_head->i.version; + sino_ptr->offset = sum_collected->sum_list_head->i.offset; + sino_ptr->totlen = sum_collected->sum_list_head->i.totlen; + + wpage += JFFS2_SUMMARY_INODE_SIZE; + break; + } + + case JFFS2_NODETYPE_DIRENT : { + struct jffs2_sum_dirent_flash *sdrnt_ptr = reinterpret_cast(wpage); + + sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype; + sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen; + sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset; + sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino; + sdrnt_ptr->version = sum_collected->sum_list_head->d.version; + sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino; + sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize; + sdrnt_ptr->type = sum_collected->sum_list_head->d.type; + + memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name, + sum_collected->sum_list_head->d.nsize); + + wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize); + break; + } + + case JFFS2_NODETYPE_XATTR: { + struct jffs2_sum_xattr_flash *sxattr_ptr = reinterpret_cast(wpage); + + sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype; + sxattr_ptr->xid = sum_collected->sum_list_head->x.xid; + sxattr_ptr->version = sum_collected->sum_list_head->x.version; + sxattr_ptr->offset = sum_collected->sum_list_head->x.offset; + sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen; + + wpage += JFFS2_SUMMARY_XATTR_SIZE; + break; + } + + case JFFS2_NODETYPE_XREF: { + struct jffs2_sum_xref_flash *sxref_ptr = reinterpret_cast(wpage); + + sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype; + sxref_ptr->offset = sum_collected->sum_list_head->r.offset; + + wpage += JFFS2_SUMMARY_XREF_SIZE; + break; + } + + default : { + warnmsg("Unknown node type!\n"); + } + } + + union jffs2_sum_mem *temp = sum_collected->sum_list_head; + sum_collected->sum_list_head = sum_collected->sum_list_head->u.next; + free(temp); + + sum_collected->sum_num--; + } + + sum_collected->sum_size = 0; + sum_collected->sum_num = 0; + sum_collected->sum_list_tail = NULL; + + wpage += padsize; + + sm = reinterpret_cast(wpage); + sm->offset = offset; + sm->magic = magic; + + isum.sum_crc = cpu_to_je32(mtd_crc32(0, tpage, datasize)); + isum.node_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(isum) - 8)); + + full_write(data_buffer + data_ofs, &isum, sizeof(isum)); + full_write(data_buffer + data_ofs, tpage, datasize); + + free(tpage); +} + +void CSumtoolJFFS2::clean_sumlist(void) +{ + if (sum_collected) { + while (sum_collected->sum_list_head) { + union jffs2_sum_mem *temp = sum_collected->sum_list_head; + sum_collected->sum_list_head = sum_collected->sum_list_head->u.next; + free(temp); + sum_collected->sum_num--; + } + + if (sum_collected->sum_num != 0) + warnmsg("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???"); + + free(sum_collected); + sum_collected = NULL; + } +} + +void CSumtoolJFFS2::flush_buffers(void) +{ + + if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */ + if ((int)data_ofs != cleanmarker_size) { /* INODE BUFFER */ + + int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8; + datasize += (4 - (datasize % 4)) % 4; + + /* If we have a full inode buffer, then write out inode and summary data */ + if ((int)data_ofs + (int)sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) { + dump_sum_records(); + write_buff_to_file(); + } else { /* else just write out inode data */ + if (padto) + pad(erase_block_size - data_ofs); + write_buff_to_file(); + } + } + } else { /* NO CLEANMARKER */ + if (data_ofs != 0) { /* INODE BUFFER */ + + int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8; + datasize += (4 - (datasize % 4)) % 4; + + /* If we have a full inode buffer, then write out inode and summary data */ + if ((int)data_ofs + (int)sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) { + dump_sum_records(); + write_buff_to_file(); + } else { /* Else just write out inode data */ + if (padto) + pad(erase_block_size - data_ofs); + write_buff_to_file(); + } + } + } +} + +void CSumtoolJFFS2::create_summed_image(int inp_size) +{ + uint8_t *p = file_buffer; + union jffs2_node_union *node; + uint32_t crc, length; + uint16_t type; + int bitchbitmask = 0; + int obsolete; + char name[256]; + + while ( p < (file_buffer + inp_size)) { + + node = (union jffs2_node_union *) p; + + /* Skip empty space */ + if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) { + p += 4; + continue; + } + + if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) { + if (!bitchbitmask++) + warnmsg("Wrong bitmask at 0x%08zx, 0x%04x\n", + p - file_buffer, je16_to_cpu (node->u.magic)); + p += 4; + continue; + } + + bitchbitmask = 0; + + type = je16_to_cpu(node->u.nodetype); + if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) { + obsolete = 1; + type |= JFFS2_NODE_ACCURATE; + } else { + obsolete = 0; + } + + node->u.nodetype = cpu_to_je16(type); + + crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4); + if (crc != je32_to_cpu (node->u.hdr_crc)) { + warnmsg("Wrong hdr_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", + p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc); + p += 4; + continue; + } + + switch (je16_to_cpu(node->u.nodetype)) { + case JFFS2_NODETYPE_INODE: + bareverbose(verbose, + "%8s Inode node at 0x%08zx, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n", + obsolete ? "Obsolete" : "", + p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino), + je32_to_cpu (node->i.version), je32_to_cpu (node->i.isize), + je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset)); + + crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8); + if (crc != je32_to_cpu (node->i.node_crc)) { + warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", + p - file_buffer, je32_to_cpu (node->i.node_crc), crc); + p += PAD(je32_to_cpu (node->i.totlen)); + continue; + } + + crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize)); + if (crc != je32_to_cpu(node->i.data_crc)) { + warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", + p - file_buffer, je32_to_cpu (node->i.data_crc), crc); + p += PAD(je32_to_cpu (node->i.totlen)); + continue; + } + + write_inode_to_buff(node); + + p += PAD(je32_to_cpu (node->i.totlen)); + break; + + case JFFS2_NODETYPE_DIRENT: + memcpy (name, node->d.name, node->d.nsize); + name [node->d.nsize] = 0x0; + + bareverbose(verbose, + "%8s Dirent node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n", + obsolete ? "Obsolete" : "", + p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino), + je32_to_cpu (node->d.version), je32_to_cpu (node->d.ino), + node->d.nsize, name); + + crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8); + if (crc != je32_to_cpu (node->d.node_crc)) { + warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", + p - file_buffer, je32_to_cpu (node->d.node_crc), crc); + p += PAD(je32_to_cpu (node->d.totlen)); + continue; + } + + crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize); + if (crc != je32_to_cpu(node->d.name_crc)) { + warnmsg("Wrong name_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", + p - file_buffer, je32_to_cpu (node->d.name_crc), crc); + p += PAD(je32_to_cpu (node->d.totlen)); + continue; + } + + write_dirent_to_buff(node); + + p += PAD(je32_to_cpu (node->d.totlen)); + break; + + case JFFS2_NODETYPE_XATTR: + if (je32_to_cpu(node->x.node_crc) == 0xffffffff) + obsolete = 1; + bareverbose(verbose, + "%8s Xdatum node at 0x%08zx, totlen 0x%08x, #xid %5u, version %5u\n", + obsolete ? "Obsolete" : "", + p - file_buffer, je32_to_cpu (node->x.totlen), + je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version)); + crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4); + if (crc != je32_to_cpu(node->x.node_crc)) { + warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", + p - file_buffer, je32_to_cpu(node->x.node_crc), crc); + p += PAD(je32_to_cpu (node->x.totlen)); + continue; + } + length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len); + crc = mtd_crc32(0, node->x.data, length); + if (crc != je32_to_cpu(node->x.data_crc)) { + warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", + p - file_buffer, je32_to_cpu(node->x.data_crc), crc); + p += PAD(je32_to_cpu (node->x.totlen)); + continue; + } + + write_xattr_to_buff(node); + p += PAD(je32_to_cpu (node->x.totlen)); + break; + + case JFFS2_NODETYPE_XREF: + if (je32_to_cpu(node->r.node_crc) == 0xffffffff) + obsolete = 1; + bareverbose(verbose, + "%8s Xref node at 0x%08zx, totlen 0x%08x, #ino %5u, xid %5u\n", + obsolete ? "Obsolete" : "", + p - file_buffer, je32_to_cpu(node->r.totlen), + je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid)); + crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xref) - 4); + if (crc != je32_to_cpu(node->r.node_crc)) { + warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", + p - file_buffer, je32_to_cpu(node->r.node_crc), crc); + p += PAD(je32_to_cpu (node->r.totlen)); + continue; + } + + write_xref_to_buff(node); + p += PAD(je32_to_cpu (node->r.totlen)); + break; + + case JFFS2_NODETYPE_CLEANMARKER: + bareverbose(verbose, + "%8s Cleanmarker at 0x%08zx, totlen 0x%08x\n", + obsolete ? "Obsolete" : "", + p - file_buffer, je32_to_cpu (node->u.totlen)); + + if (!found_cleanmarkers) { + found_cleanmarkers = 1; + + if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1) { + cleanmarker_size = je32_to_cpu (node->u.totlen); + setup_cleanmarker(); + } + } + + p += PAD(je32_to_cpu (node->u.totlen)); + break; + + case JFFS2_NODETYPE_PADDING: + bareverbose(verbose, + "%8s Padding node at 0x%08zx, totlen 0x%08x\n", + obsolete ? "Obsolete" : "", + p - file_buffer, je32_to_cpu (node->u.totlen)); + p += PAD(je32_to_cpu (node->u.totlen)); + break; + + case 0xffff: + p += 4; + break; + + default: + bareverbose(verbose, + "%8s Unknown node at 0x%08zx, totlen 0x%08x\n", + obsolete ? "Obsolete" : "", + p - file_buffer, je32_to_cpu (node->u.totlen)); + + p += PAD(je32_to_cpu (node->u.totlen)); + } + } +} + +int CSumtoolJFFS2::load_next_block(void) +{ + int ret; + ret = read(in_fd, file_buffer, erase_block_size); + file_ofs = 0; + bareverbose(verbose, "Load next block : %d bytes read\n", ret); + return ret; +} + +void CSumtoolJFFS2::init_buffers(void) +{ + if (data_buffer == NULL) + data_buffer = (uint8_t*)xmalloc(erase_block_size); + if (file_buffer == NULL) + file_buffer = (uint8_t*)xmalloc(erase_block_size); +} + +void CSumtoolJFFS2::init_sumlist(void) +{ + if (sum_collected == NULL) + sum_collected = reinterpret_cast(xzalloc(sizeof(*sum_collected))); +} + +void CSumtoolJFFS2::clean_buffers(void) +{ + if (data_buffer != NULL) { + free(data_buffer); + data_buffer = NULL; + } + if (file_buffer != NULL) { + free(file_buffer); + file_buffer = NULL; + } +} + +bool CSumtoolJFFS2::sumtool(std::string& imageName, + std::string& sumName, + int eraseBlockSize/*=0x20000*/, + int padTo/*=0*/, + int addCleanmarkers/*=0*/, + int targetEndian/*=__LITTLE_ENDIAN*/) +{ + Init(); + + imageName_ = imageName; + sumName_ = sumName; + erase_block_size = eraseBlockSize; // -e + padto = padTo; // -p + add_cleanmarkers = addCleanmarkers; // -n + target_endian = targetEndian; // -l + + classInit(); + + int ret; + while ((ret = load_next_block())) { + create_summed_image(ret); + } + + flush_buffers(); + classClear(); + + printf("##### sumtool OK.\n"); + return true; +} diff --git a/src/system/mtdutils/sumtool.h b/src/system/mtdutils/sumtool.h new file mode 100644 index 000000000..1de69a78f --- /dev/null +++ b/src/system/mtdutils/sumtool.h @@ -0,0 +1,87 @@ + +#ifndef __SUMTOOL_JFFS2__ +#define __SUMTOOL_JFFS2__ + +/* + Neutrino-HD + + License: GPL + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include + +class CSumtoolJFFS2 +{ + private: + int verbose; + int padto; + int add_cleanmarkers; + int use_input_cleanmarker_size; + int found_cleanmarkers; + int cleanmarker_size; + int erase_block_size; + int out_fd; + int in_fd; + uint8_t *data_buffer; + unsigned int data_ofs; + uint8_t *file_buffer; + unsigned int file_ofs; + unsigned char ffbuf[16]; + std::string imageName_, sumName_; + + void Init(); + void classClear(); + bool classInit(); + void clean_buffers(void); + static void init_sumlist(void); + void init_buffers(void); + int load_next_block(void); + void create_summed_image(int inp_size); + void flush_buffers(void); + static void clean_sumlist(void); + void dump_sum_records(void); + void write_buff_to_file(void); + void full_write(void *target_buff, const void *buf, int len); + void pad(int req); + inline void padword(void) { if (data_ofs % 4) full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4)); } + inline void pad_block_if_less_than(int req,int plus); + void write_xref_to_buff(union jffs2_node_union *node); + void write_xattr_to_buff(union jffs2_node_union *node); + void write_inode_to_buff(union jffs2_node_union *node); + void write_dirent_to_buff(union jffs2_node_union *node); + static int add_sum_mem(union jffs2_sum_mem *item); + void add_sum_xref_mem(union jffs2_node_union *node); + void add_sum_xattr_mem(union jffs2_node_union *node); + void add_sum_dirent_mem(union jffs2_node_union *node); + void add_sum_inode_mem(union jffs2_node_union *node); + void setup_cleanmarker(void); + + public: + CSumtoolJFFS2(); + ~CSumtoolJFFS2(); + + + bool sumtool(std::string& imageName, + std::string& sumName, + int eraseBlockSize=0x20000, + int padTo=0, + int addCleanmarkers=0, + int targetEndian=__LITTLE_ENDIAN); +}; + +#endif // __SUMTOOL_JFFS2__ From 2299807e11c170c03158ec37e4c46c32ca08a363 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Sun, 1 Sep 2013 17:57:41 +0200 Subject: [PATCH 075/200] src/system/mtdutils: Add and patch makefiles --- configure.ac | 6 ++++++ src/Makefile.am | 7 +++++++ src/system/Makefile.am | 4 ++++ src/system/mtdutils/Makefile.am | 27 +++++++++++++++++++++++++++ src/system/mtdutils/lib/Makefile.am | 16 ++++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 src/system/mtdutils/Makefile.am create mode 100644 src/system/mtdutils/lib/Makefile.am diff --git a/configure.ac b/configure.ac index 1b443ce9f..394eb677f 100644 --- a/configure.ac +++ b/configure.ac @@ -222,3 +222,9 @@ src/zapit/src/Makefile src/zapit/data/Makefile ]) +if test "$BOXMODEL" = "apollo"; then +AC_OUTPUT([ +src/system/mtdutils/Makefile +src/system/mtdutils/lib/Makefile +]) +fi diff --git a/src/Makefile.am b/src/Makefile.am index 33af31d06..8694896fd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,6 +49,12 @@ else FLACLIBS = endif +if BOXMODEL_APOLLO +MTDUTILSLIBS = \ + system/mtdutils/libneutrino_system_mtdutils.a \ + system/mtdutils/lib/libneutrino_system_mtdutils_lib.a +endif + neutrino_LDADD = \ daemonc/libneutrino_daemonc.a \ gui/bedit/libneutrino_gui_bedit.a \ @@ -58,6 +64,7 @@ neutrino_LDADD = \ gui/widget/libneutrino_gui_widget2.a \ driver/pictureviewer/libneutrino_pictureviewer.a \ system/libneutrino_system.a \ + $(MTDUTILSLIBS) \ gui/movieinfo.o \ gui/libneutrino_gui2.a \ gui/components/libneutrino_gui_components.a \ diff --git a/src/system/Makefile.am b/src/system/Makefile.am index 2ed9e2309..49bab1c92 100644 --- a/src/system/Makefile.am +++ b/src/system/Makefile.am @@ -1,3 +1,7 @@ +if BOXMODEL_APOLLO +SUBDIRS = mtdutils +endif + AM_CXXFLAGS = -fno-rtti -fno-exceptions INCLUDES = \ diff --git a/src/system/mtdutils/Makefile.am b/src/system/mtdutils/Makefile.am new file mode 100644 index 000000000..2e79b98fb --- /dev/null +++ b/src/system/mtdutils/Makefile.am @@ -0,0 +1,27 @@ +AM_CXXFLAGS = -D__STDC_FORMAT_MACROS + +SUBDIRS = lib + +INCLUDES = \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/system/mtdutils/include + +if BOXMODEL_APOLLO +INCLUDES += -I$(top_srcdir)/lib/libcoolstream2 +else +INCLUDES += -I$(top_srcdir)/lib/libcoolstream +endif + +noinst_LIBRARIES = libneutrino_system_mtdutils.a + +libneutrino_system_mtdutils_a_SOURCES = \ + compr.cpp \ + compr_lzo.cpp \ + compr_rtime.cpp \ + compr_zlib.cpp \ + mkfs.jffs2.cpp \ + rbtree.cpp \ + sumtool.cpp diff --git a/src/system/mtdutils/lib/Makefile.am b/src/system/mtdutils/lib/Makefile.am new file mode 100644 index 000000000..1d62a9cdb --- /dev/null +++ b/src/system/mtdutils/lib/Makefile.am @@ -0,0 +1,16 @@ +AM_CXXFLAGS = -D__STDC_FORMAT_MACROS + +INCLUDES = \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/system/mtdutils/include + +noinst_LIBRARIES = libneutrino_system_mtdutils_lib.a + +libneutrino_system_mtdutils_lib_a_SOURCES = \ + libcrc32.cpp \ + libfec.cpp \ + libmtd.cpp \ + libmtd_legacy.cpp From d4ca6a552e5498eb1640311afe53793176c61398 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Sat, 21 Sep 2013 18:26:38 +0200 Subject: [PATCH 076/200] Image backup apollo Part #1 - Use src/system/mtdutils for image creation --- src/gui/update.cpp | 30 ++++++++++++++ src/gui/update.h | 3 ++ src/system/mtdutils/mkfs.jffs2.cpp | 64 +++++++++++++++++++++--------- src/system/mtdutils/mkfs.jffs2.h | 11 ++--- 4 files changed, 83 insertions(+), 25 deletions(-) diff --git a/src/gui/update.cpp b/src/gui/update.cpp index c286283b9..941e44eb0 100644 --- a/src/gui/update.cpp +++ b/src/gui/update.cpp @@ -53,6 +53,9 @@ #include #include +#ifdef BOXMODEL_APOLLO +#include +#endif #include #include @@ -582,6 +585,27 @@ bool CFlashExpert::checkSize(int mtd, std::string &backupFile) return true; } +#ifdef BOXMODEL_APOLLO +void CFlashExpert::readmtdJFFS2(std::string &filename) +{ + int esize = CMTDInfo::getInstance()->getMTDEraseSize(CMTDInfo::getInstance()->findMTDsystem()); + CMkfsJFFS2 mkfs; + std::string path = "/"; + CProgressWindow *progress = new CProgressWindow; + progress->setTitle(LOCALE_FLASHUPDATE_TITLEREADFLASH); + progress->paint(); + mkfs.makeJffs2Image(path, filename, esize, 0, 0, __LITTLE_ENDIAN, true, true, progress); + progress->hide(); + delete progress; + + sleep(1); + char message[500]; + sprintf(message, g_Locale->getText(LOCALE_FLASHUPDATE_SAVESUCCESS), filename.c_str()); + ShowHintUTF(LOCALE_MESSAGEBOX_INFO, message); + +} +#endif + void CFlashExpert::readmtd(int preadmtd) { std::string filename; @@ -594,6 +618,12 @@ void CFlashExpert::readmtd(int preadmtd) else filename = (std::string)g_settings.update_dir + "/" + mtdInfo->getMTDName(preadmtd) + timeStr + ".img"; +#ifdef BOXMODEL_APOLLO + if (preadmtd == 0) { + readmtdJFFS2(filename); + return; + } +#endif if (preadmtd == -1) { filename = (std::string)g_settings.update_dir + "/flashimage.img"; // US-ASCII (subset of UTF-8 and ISO8859-1) preadmtd = MTD_OF_WHOLE_IMAGE; diff --git a/src/gui/update.h b/src/gui/update.h index 1992b6aca..a5a26da47 100644 --- a/src/gui/update.h +++ b/src/gui/update.h @@ -77,6 +77,9 @@ class CFlashExpert : public CProgressWindow bool checkSize(int mtd, std::string &backupFile); void readmtd(int readmtd); +#ifdef BOXMODEL_APOLLO + void readmtdJFFS2(std::string &filename); +#endif public: CFlashExpert(); diff --git a/src/system/mtdutils/mkfs.jffs2.cpp b/src/system/mtdutils/mkfs.jffs2.cpp index ed9168ea4..b80d4c799 100644 --- a/src/system/mtdutils/mkfs.jffs2.cpp +++ b/src/system/mtdutils/mkfs.jffs2.cpp @@ -169,8 +169,6 @@ void CMkfsJFFS2::Init() printProgress = 0; kbUsed = 0; progressBar = NULL; - progressBarGlobalX1 = 0; - progressBarGlobalX2 = 0; ino = 0; out_ofs = 0; @@ -371,6 +369,7 @@ struct filesystem_entry *CMkfsJFFS2::find_filesystem_entry( void CMkfsJFFS2::printProgressData(bool finish) { static int p_old = -1; + if (finish) p_old = -1; int p = (finish) ? 100 : ((all_read/1024)*100 )/kbUsed; if (p != p_old) { p_old = p; @@ -378,21 +377,14 @@ void CMkfsJFFS2::printProgressData(bool finish) } } -void CMkfsJFFS2::setProgressBarGlobal(int x1, int x2) -{ - progressBarGlobalX1 = x1; - progressBarGlobalX2 = x2; -} - -void CMkfsJFFS2::paintProgressBar() +void CMkfsJFFS2::paintProgressBar(bool finish) { static int p_old = -1; - int p1 = ((all_read/1024)*100)/kbUsed; - if (p1 != p_old) { - p_old = p1; - int p2 = progressBarGlobalX1 + (((all_read/1024)*(progressBarGlobalX2-progressBarGlobalX1))/kbUsed); - progressBar->showLocalStatus(p1); - progressBar->showGlobalStatus(p2); + if (finish) p_old = -1; + int p = (finish) ? 100 : ((all_read/1024)*100 )/kbUsed; + if (p != p_old) { + p_old = p; + progressBar->showLocalStatus(p); } } @@ -1050,8 +1042,8 @@ int CMkfsJFFS2::parse_device_table(struct filesystem_entry *root, FILE * file) struct filesystem_entry *CMkfsJFFS2::recursive_add_host_directory( struct filesystem_entry *parent, const char *targetpath, - const char *hostpath, - bool skipSpezialFolders) { + const char *hostpath, bool skipSpezialFolders, + CProgressWindow *progress) { int i, n; struct stat sb; char *hpath, *tpath; @@ -1111,6 +1103,10 @@ struct filesystem_entry *CMkfsJFFS2::recursive_add_host_directory( sys_errmsg("opening directory %s", hostpath); } + int i_pr = 0, n_pr = 0; + if (progress != NULL) { + n_pr = (n <= 2) ? 1 : n-2; + } for (i=0; id_name[0] == '.' && (dp->d_name[1] == 0 || @@ -1151,6 +1147,10 @@ struct filesystem_entry *CMkfsJFFS2::recursive_add_host_directory( free(dp); free(hpath); free(tpath); + if (progress != NULL) { + progress->showLocalStatus((i_pr * 100) / n_pr); + i_pr++; + } } free(namelist); return (entry); @@ -1190,6 +1190,11 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, progressBar = progress; hardlinks.rb_node = NULL; +/* if (progressBar != NULL) { + progressBar->setTitle(LOCALE_FLASHUPDATE_TITLEREADFLASH); + progressBar->paint(); + }*/ + printf("[%s] erase_block_size: 0x%X\n", __FUNCTION__, eraseBlockSize); if (useDevTable) { if (devTable == "") { @@ -1231,7 +1236,17 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, } } - fse_root = recursive_add_host_directory(NULL, "/", cwd, skipSpezialFolders); + if (progressBar != NULL) { + progressBar->showLocalStatus(0); + progressBar->showGlobalStatus(0); + progressBar->showStatusMessageUTF("Read Files and Directories"); + } + fse_root = recursive_add_host_directory(NULL, "/", cwd, skipSpezialFolders, progressBar); + if (progressBar != NULL) { + progressBar->showLocalStatus(100); + progressBar->showGlobalStatus(50); + } + if (devtable) parse_device_table(fse_root, devtable); @@ -1247,7 +1262,14 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, if (kbUsed == 0) kbUsed = 60000; + if (progressBar != NULL) { + progressBar->showLocalStatus(0); + progressBar->showStatusMessageUTF("Create Image"); + } create_target_filesystem(fse_root); + if (progressBar != NULL) { + progressBar->showGlobalStatus(90); + } if (printProgress) printProgressData(true); @@ -1260,6 +1282,12 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, unlink(imageName_.c_str()); sync(); } + if (progressBar != NULL) { + paintProgressBar(true); + progressBar->showGlobalStatus(100); + sync(); + sleep(2); + } progressBar = NULL; return true; diff --git a/src/system/mtdutils/mkfs.jffs2.h b/src/system/mtdutils/mkfs.jffs2.h index 54f1a3333..8275e2f72 100644 --- a/src/system/mtdutils/mkfs.jffs2.h +++ b/src/system/mtdutils/mkfs.jffs2.h @@ -51,8 +51,6 @@ class CMkfsJFFS2 long kbUsed; dev_t dev_x[dev_max]; CProgressWindow *progressBar; - int progressBarGlobalX1; - int progressBarGlobalX2; std::string imageName_, sumName_; bool useSumtool_; @@ -70,8 +68,8 @@ class CMkfsJFFS2 bool classInit(); struct filesystem_entry *recursive_add_host_directory( struct filesystem_entry *parent, const char *targetpath, - const char *hostpath, - bool skipSpezialFolders); + const char *hostpath, bool skipSpezialFolders, + CProgressWindow *progress=NULL); int parse_device_table(struct filesystem_entry *root, FILE * file); int interpret_table_entry(struct filesystem_entry *root, char *line); void create_target_filesystem(struct filesystem_entry *root); @@ -87,9 +85,8 @@ class CMkfsJFFS2 void write_pipe(struct filesystem_entry *e); void write_symlink(struct filesystem_entry *e); unsigned int write_regular_file(struct filesystem_entry *e); - void paintProgressBar(); - void setProgressBarGlobal(int x1, int x2); - void printProgressData(bool finish); + void paintProgressBar(bool finish=false); + void printProgressData(bool finish=false); struct filesystem_entry *find_filesystem_entry(struct filesystem_entry *dir, char *fullname, uint32_t type); struct filesystem_entry *add_host_filesystem_entry(const char *name, const char *path, unsigned long uid, unsigned long gid, From 2e360ca480aa1da116f732e8985f374b90a5d43a Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Sat, 21 Sep 2013 19:48:17 +0200 Subject: [PATCH 077/200] Image backup apollo Part #2 - Add locales for progressbar --- data/locale/deutsch.locale | 3 +++ data/locale/english.locale | 3 +++ src/system/locals.h | 3 +++ src/system/locals_intern.h | 3 +++ src/system/mtdutils/mkfs.jffs2.cpp | 9 ++++++--- 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/data/locale/deutsch.locale b/data/locale/deutsch.locale index 8415ce25b..03957d35e 100644 --- a/data/locale/deutsch.locale +++ b/data/locale/deutsch.locale @@ -486,6 +486,9 @@ flashupdate.md5check Imageprüfung flashupdate.md5sumerror Das Image ist fehlerhaft flashupdate.menu_apply_kernel Kernel flashen flashupdate.menu_apply_settings Settingsübernahme erlauben +flashupdate.mkfs_create_image Image erstellen +flashupdate.mkfs_preparing_files Dateien und Verzeichnisse vorbereiten +flashupdate.mkfs_using_sumtool Benutze Sumtool flashupdate.msgbox Es wurde folgendes neues File gefunden:\nDatum: %s, %s\nBasisImage: %s\nTyp: %s\n\nWollen Sie diese Version jetzt herunterladen\nund installieren? flashupdate.msgbox_manual Es wurde ein neues Image gefunden:\nDatum: %s, %s\nBasisImage: %s\nImageTyp: %s\n\nWollen Sie diese Version jetzt installieren? flashupdate.mtdselector Partitions-Auswahl diff --git a/data/locale/english.locale b/data/locale/english.locale index 9751434b4..df3a18081 100644 --- a/data/locale/english.locale +++ b/data/locale/english.locale @@ -486,6 +486,9 @@ flashupdate.md5check checking image flashupdate.md5sumerror image has errors flashupdate.menu_apply_kernel Flashing kernel flashupdate.menu_apply_settings Allow apply settings +flashupdate.mkfs_create_image Create image +flashupdate.mkfs_preparing_files Preparing files and directories +flashupdate.mkfs_using_sumtool Using sumtool flashupdate.msgbox Found the following new file:\nDate: %s, %s\nBaseImage: %s\nType: %s\n\nDo you want to download and install this version now? flashupdate.msgbox_manual Found the following new image:\nDate: %s, %s\nBaseImage: %s\nImageType: %s\n\nDo you want to install this version now? flashupdate.mtdselector Partition-Selector diff --git a/src/system/locals.h b/src/system/locals.h index 882c15450..b6c9d6d31 100644 --- a/src/system/locals.h +++ b/src/system/locals.h @@ -513,6 +513,9 @@ typedef enum LOCALE_FLASHUPDATE_MD5SUMERROR, LOCALE_FLASHUPDATE_MENU_APPLY_KERNEL, LOCALE_FLASHUPDATE_MENU_APPLY_SETTINGS, + LOCALE_FLASHUPDATE_MKFS_CREATE_IMAGE, + LOCALE_FLASHUPDATE_MKFS_PREPARING_FILES, + LOCALE_FLASHUPDATE_MKFS_USING_SUMTOOL, LOCALE_FLASHUPDATE_MSGBOX, LOCALE_FLASHUPDATE_MSGBOX_MANUAL, LOCALE_FLASHUPDATE_MTDSELECTOR, diff --git a/src/system/locals_intern.h b/src/system/locals_intern.h index e4ff3dd93..198e82d27 100644 --- a/src/system/locals_intern.h +++ b/src/system/locals_intern.h @@ -513,6 +513,9 @@ const char * locale_real_names[] = "flashupdate.md5sumerror", "flashupdate.menu_apply_kernel", "flashupdate.menu_apply_settings", + "flashupdate.mkfs_create_image", + "flashupdate.mkfs_preparing_files", + "flashupdate.mkfs_using_sumtool", "flashupdate.msgbox", "flashupdate.msgbox_manual", "flashupdate.mtdselector", diff --git a/src/system/mtdutils/mkfs.jffs2.cpp b/src/system/mtdutils/mkfs.jffs2.cpp index b80d4c799..2a1359d39 100644 --- a/src/system/mtdutils/mkfs.jffs2.cpp +++ b/src/system/mtdutils/mkfs.jffs2.cpp @@ -69,6 +69,9 @@ #include #include "rbtree.h" +#include + +extern CLocaleManager *g_Locale; #define PROGRAM_NAME "mkfs.jffs2" @@ -1239,7 +1242,7 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, if (progressBar != NULL) { progressBar->showLocalStatus(0); progressBar->showGlobalStatus(0); - progressBar->showStatusMessageUTF("Read Files and Directories"); + progressBar->showStatusMessageUTF(g_Locale->getText(LOCALE_FLASHUPDATE_MKFS_PREPARING_FILES)); } fse_root = recursive_add_host_directory(NULL, "/", cwd, skipSpezialFolders, progressBar); if (progressBar != NULL) { @@ -1264,11 +1267,12 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, if (progressBar != NULL) { progressBar->showLocalStatus(0); - progressBar->showStatusMessageUTF("Create Image"); + progressBar->showStatusMessageUTF(g_Locale->getText(LOCALE_FLASHUPDATE_MKFS_CREATE_IMAGE)); } create_target_filesystem(fse_root); if (progressBar != NULL) { progressBar->showGlobalStatus(90); + progressBar->showStatusMessageUTF(g_Locale->getText(LOCALE_FLASHUPDATE_MKFS_USING_SUMTOOL)); } if (printProgress) printProgressData(true); @@ -1280,7 +1284,6 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, CSumtoolJFFS2 st; st.sumtool(imageName_, sumName_, eraseBlockSize, ((padFsSize==0)?0:1), addCleanmarkers, targetEndian); unlink(imageName_.c_str()); - sync(); } if (progressBar != NULL) { paintProgressBar(true); From acea9818b8d9f7edaf5075e48e143c4d2ddeaa76 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Sat, 21 Sep 2013 18:35:34 +0200 Subject: [PATCH 078/200] Image backup apollo Part #3 - Add ".256k" string to imagename for tank boxes --- src/gui/update.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gui/update.cpp b/src/gui/update.cpp index 941e44eb0..d677c88fa 100644 --- a/src/gui/update.cpp +++ b/src/gui/update.cpp @@ -612,11 +612,15 @@ void CFlashExpert::readmtd(int preadmtd) CMTDInfo* mtdInfo = CMTDInfo::getInstance(); std::string hostName = netGetHostname(); std::string timeStr = getNowTimeStr("_%Y%m%d_%H%M"); - + std::string tankStr = ""; +#ifdef BOXMODEL_APOLLO + if ((preadmtd == 0) && (CMTDInfo::getInstance()->getMTDEraseSize(CMTDInfo::getInstance()->findMTDsystem()) == 0x40000)) + tankStr = ".256k"; +#endif if (g_settings.softupdate_name_mode_backup == CExtUpdate::SOFTUPDATE_NAME_HOSTNAME_TIME) - filename = (std::string)g_settings.update_dir + "/" + mtdInfo->getMTDName(preadmtd) + timeStr + "_" + hostName + ".img"; + filename = (std::string)g_settings.update_dir + "/" + mtdInfo->getMTDName(preadmtd) + timeStr + "_" + hostName + tankStr + ".img"; else - filename = (std::string)g_settings.update_dir + "/" + mtdInfo->getMTDName(preadmtd) + timeStr + ".img"; + filename = (std::string)g_settings.update_dir + "/" + mtdInfo->getMTDName(preadmtd) + timeStr + tankStr + ".img"; #ifdef BOXMODEL_APOLLO if (preadmtd == 0) { From 66b078cb926a11bac8ee7a3bb271a16ad6c4894c Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Sun, 22 Sep 2013 09:00:43 +0200 Subject: [PATCH 079/200] src/system/mtdutils: Creation devtable moved to update.cpp --- src/gui/update.cpp | 34 ++++++++++++++++++++---------- src/gui/update.h | 1 + src/system/mtdutils/mkfs.jffs2.cpp | 24 +++------------------ src/system/mtdutils/mkfs.jffs2.h | 1 - 4 files changed, 27 insertions(+), 33 deletions(-) diff --git a/src/gui/update.cpp b/src/gui/update.cpp index d677c88fa..e7ccecfa5 100644 --- a/src/gui/update.cpp +++ b/src/gui/update.cpp @@ -586,23 +586,35 @@ bool CFlashExpert::checkSize(int mtd, std::string &backupFile) } #ifdef BOXMODEL_APOLLO +void CFlashExpert::addDevtableEntry(int fd_dev, const char *entry) +{ + write(fd_dev, entry, strlen(entry)); +} + void CFlashExpert::readmtdJFFS2(std::string &filename) { - int esize = CMTDInfo::getInstance()->getMTDEraseSize(CMTDInfo::getInstance()->findMTDsystem()); - CMkfsJFFS2 mkfs; - std::string path = "/"; - CProgressWindow *progress = new CProgressWindow; - progress->setTitle(LOCALE_FLASHUPDATE_TITLEREADFLASH); - progress->paint(); - mkfs.makeJffs2Image(path, filename, esize, 0, 0, __LITTLE_ENDIAN, true, true, progress); - progress->hide(); - delete progress; + CProgressWindow progress; + progress.setTitle(LOCALE_FLASHUPDATE_TITLEREADFLASH); + progress.paint(); + + std::string devTable = "/tmp/devtable.txt"; + int fd_dev = open(devTable.c_str(), O_WRONLY|O_CREAT|O_TRUNC); + if (fd_dev != -1) { + addDevtableEntry(fd_dev, "/dev/console c 0600 0 0 5 1 0 0 0\n"); + addDevtableEntry(fd_dev, "/dev/null c 0666 0 0 1 3 0 0 0\n"); + close(fd_dev); + } + std::string path = "/"; + CMTDInfo *MTDInfo = CMTDInfo::getInstance(); + int esize = MTDInfo->getMTDEraseSize(MTDInfo->findMTDsystem()); + CMkfsJFFS2 mkfs; + mkfs.makeJffs2Image(path, filename, esize, 0, 0, __LITTLE_ENDIAN, true, true, &progress, devTable); + progress.hide(); + unlink(devTable.c_str()); - sleep(1); char message[500]; sprintf(message, g_Locale->getText(LOCALE_FLASHUPDATE_SAVESUCCESS), filename.c_str()); ShowHintUTF(LOCALE_MESSAGEBOX_INFO, message); - } #endif diff --git a/src/gui/update.h b/src/gui/update.h index a5a26da47..fffda824f 100644 --- a/src/gui/update.h +++ b/src/gui/update.h @@ -78,6 +78,7 @@ class CFlashExpert : public CProgressWindow bool checkSize(int mtd, std::string &backupFile); void readmtd(int readmtd); #ifdef BOXMODEL_APOLLO + void addDevtableEntry(int fd_dev, const char *entry); void readmtdJFFS2(std::string &filename); #endif diff --git a/src/system/mtdutils/mkfs.jffs2.cpp b/src/system/mtdutils/mkfs.jffs2.cpp index 2a1359d39..9076e60ab 100644 --- a/src/system/mtdutils/mkfs.jffs2.cpp +++ b/src/system/mtdutils/mkfs.jffs2.cpp @@ -1174,7 +1174,6 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, bool skipSpezialFolders/*=true*/, bool useSumtool/*=true*/, CProgressWindow *progress/*=NULL*/, - bool useDevTable/*=true*/, std::string devTable/*=""*/) { @@ -1193,26 +1192,7 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, progressBar = progress; hardlinks.rb_node = NULL; -/* if (progressBar != NULL) { - progressBar->setTitle(LOCALE_FLASHUPDATE_TITLEREADFLASH); - progressBar->paint(); - }*/ - - printf("[%s] erase_block_size: 0x%X\n", __FUNCTION__, eraseBlockSize); - if (useDevTable) { - if (devTable == "") { - devTable = "/tmp/devtable.txt"; - devtable = fopen(devTable.c_str(), "w+"); - if (devtable) { - std::string dev = "/dev/console c 0600 0 0 5 1 0 0 0\n"; - fwrite(dev.c_str(), dev.length(), 1, devtable); - dev = "/dev/null c 0666 0 0 1 3 0 0 0\n"; - fwrite(dev.c_str(), dev.length(), 1, devtable); - fclose(devtable); - } - } - devtable = fopen(devTable.c_str(), "r"); - } +// printf("[%s] erase_block_size: 0x%X\n", __FUNCTION__, eraseBlockSize); classInit(); @@ -1250,6 +1230,8 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, progressBar->showGlobalStatus(50); } + if (devTable != "") + devtable = fopen(devTable.c_str(), "r"); if (devtable) parse_device_table(fse_root, devtable); diff --git a/src/system/mtdutils/mkfs.jffs2.h b/src/system/mtdutils/mkfs.jffs2.h index 8275e2f72..6a2dd2828 100644 --- a/src/system/mtdutils/mkfs.jffs2.h +++ b/src/system/mtdutils/mkfs.jffs2.h @@ -107,7 +107,6 @@ class CMkfsJFFS2 bool skipSpezialFolders=true, bool useSumtool=true, CProgressWindow *progress=NULL, - bool useDevTable=true, std::string devTable=""); }; From 23163e78976dba8067efea7e75648f6fef3c60e8 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Sun, 22 Sep 2013 18:13:13 +0200 Subject: [PATCH 080/200] Image backup apollo Part #4 - Check of available disk space before image creation --- src/gui/update.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/gui/update.cpp b/src/gui/update.cpp index e7ccecfa5..b41a5ef6e 100644 --- a/src/gui/update.cpp +++ b/src/gui/update.cpp @@ -557,6 +557,9 @@ CFlashExpert* CFlashExpert::getInstance() bool CFlashExpert::checkSize(int mtd, std::string &backupFile) { +#ifndef BOXMODEL_APOLLO + if (mtd < 0) return false; +#endif char errMsg[1024] = {0}; std::string path = getPathName(backupFile); if (!file_exists(path.c_str())) { @@ -565,9 +568,22 @@ bool CFlashExpert::checkSize(int mtd, std::string &backupFile) return false; } - int mtdSize = CMTDInfo::getInstance()->getMTDSize(mtd) / 1024; - long btotal = 0, bused = 0, bsize = 0; + int backupRequiredSize = 0; +#ifdef BOXMODEL_APOLLO + if (mtd == -1) { // check disk space for image creation + if (!get_fs_usage("/", btotal, bused, &bsize)) { + snprintf(errMsg, sizeof(errMsg)-1, g_Locale->getText(LOCALE_FLASHUPDATE_READ_VOLUME_ERROR), "root0"); + ShowHintUTF(LOCALE_MESSAGEBOX_ERROR, errMsg); + return false; + } + backupRequiredSize = (int)((bused * bsize) / 1024) * 2; // twice disk space for summarized image + } + else +#endif + backupRequiredSize = CMTDInfo::getInstance()->getMTDSize(mtd) / 1024; + + btotal = 0; bused = 0; bsize = 0; if (!get_fs_usage(path.c_str(), btotal, bused, &bsize)) { snprintf(errMsg, sizeof(errMsg)-1, g_Locale->getText(LOCALE_FLASHUPDATE_READ_VOLUME_ERROR), path.c_str()); ShowHintUTF(LOCALE_MESSAGEBOX_ERROR, errMsg); @@ -576,8 +592,8 @@ bool CFlashExpert::checkSize(int mtd, std::string &backupFile) int backupMaxSize = (int)((btotal - bused) * bsize); int res = 10; // Reserved 10% of available space backupMaxSize = (backupMaxSize - ((backupMaxSize * res) / 100)) / 1024; - if (backupMaxSize < mtdSize) { - snprintf(errMsg, sizeof(errMsg)-1, g_Locale->getText(LOCALE_FLASHUPDATE_READ_NO_AVAILABLE_SPACE), path.c_str(), backupMaxSize, mtdSize); + if (backupMaxSize < backupRequiredSize) { + snprintf(errMsg, sizeof(errMsg)-1, g_Locale->getText(LOCALE_FLASHUPDATE_READ_NO_AVAILABLE_SPACE), path.c_str(), backupMaxSize, backupRequiredSize); ShowHintUTF(LOCALE_MESSAGEBOX_ERROR, errMsg); return false; } @@ -593,6 +609,8 @@ void CFlashExpert::addDevtableEntry(int fd_dev, const char *entry) void CFlashExpert::readmtdJFFS2(std::string &filename) { + if (!checkSize(-1, filename)) + return; CProgressWindow progress; progress.setTitle(LOCALE_FLASHUPDATE_TITLEREADFLASH); progress.paint(); @@ -603,7 +621,8 @@ void CFlashExpert::readmtdJFFS2(std::string &filename) addDevtableEntry(fd_dev, "/dev/console c 0600 0 0 5 1 0 0 0\n"); addDevtableEntry(fd_dev, "/dev/null c 0666 0 0 1 3 0 0 0\n"); close(fd_dev); - } + } else + devTable = ""; std::string path = "/"; CMTDInfo *MTDInfo = CMTDInfo::getInstance(); int esize = MTDInfo->getMTDEraseSize(MTDInfo->findMTDsystem()); From 9188c78751f643d59c98da693ab9780341176ec7 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Tue, 24 Sep 2013 07:51:10 +0200 Subject: [PATCH 081/200] Image backup apollo Part #5 - Rework handling devtable - Use file for devtable '/var/tuxbox/config/devtable.txt' - If file is empty or does not exist, will default entries '/dev/console' and '/dev/null' creates --- src/gui/update.cpp | 58 +++++++++++++----- src/gui/update.h | 5 +- src/system/mtdutils/mkfs.jffs2.cpp | 94 ++++++++++-------------------- src/system/mtdutils/mkfs.jffs2.h | 23 ++++---- 4 files changed, 90 insertions(+), 90 deletions(-) diff --git a/src/gui/update.cpp b/src/gui/update.cpp index b41a5ef6e..8c7376789 100644 --- a/src/gui/update.cpp +++ b/src/gui/update.cpp @@ -53,9 +53,6 @@ #include #include -#ifdef BOXMODEL_APOLLO -#include -#endif #include #include @@ -602,9 +599,37 @@ bool CFlashExpert::checkSize(int mtd, std::string &backupFile) } #ifdef BOXMODEL_APOLLO -void CFlashExpert::addDevtableEntry(int fd_dev, const char *entry) +bool CFlashExpert::readDevtableFile(std::string &devtableFile, CMkfsJFFS2::v_devtable_t &v_devtable) { - write(fd_dev, entry, strlen(entry)); + FILE *fd = fopen(devtableFile.c_str(), "r"); + if (!fd) return false; + char lineRead[1024]; + memset(lineRead, 0, sizeof(lineRead)); + bool status = false; + while (fgets(lineRead, sizeof(lineRead)-1, fd)) { + std::string line = lineRead; + line = trim(line); + // ignore comments + if (line.find_first_of("#") == 0) { + continue; + } + // ignore comments after the entry + size_t pos = line.find_first_of("#"); + if (pos != std::string::npos) { + line = line.substr(0, pos); + line = trim(line); + } + // minimal entry: "/dev/x x 0000" + // length = 13 + if (line.length() > 12) { + v_devtable.push_back(line); + status = true; + } + memset(lineRead, 0, sizeof(lineRead)); + } + fclose(fd); + if (!status) return false; + return true; } void CFlashExpert::readmtdJFFS2(std::string &filename) @@ -615,21 +640,24 @@ void CFlashExpert::readmtdJFFS2(std::string &filename) progress.setTitle(LOCALE_FLASHUPDATE_TITLEREADFLASH); progress.paint(); - std::string devTable = "/tmp/devtable.txt"; - int fd_dev = open(devTable.c_str(), O_WRONLY|O_CREAT|O_TRUNC); - if (fd_dev != -1) { - addDevtableEntry(fd_dev, "/dev/console c 0600 0 0 5 1 0 0 0\n"); - addDevtableEntry(fd_dev, "/dev/null c 0666 0 0 1 3 0 0 0\n"); - close(fd_dev); - } else - devTable = ""; + bool devtableFileIO = false; + CMkfsJFFS2::v_devtable_t v_devtable; + std::string devtableFile = (std::string)CONFIGDIR + "/devtable.txt"; + if (file_exists(devtableFile.c_str())) { + if (readDevtableFile(devtableFile, v_devtable)) + devtableFileIO = true; + } + if ((!devtableFileIO) || (v_devtable.empty())) { + v_devtable.push_back("/dev/console c 0600 0 0 5 1 0 0 0"); + v_devtable.push_back("/dev/null c 0666 0 0 1 3 0 0 0"); + } + std::string path = "/"; CMTDInfo *MTDInfo = CMTDInfo::getInstance(); int esize = MTDInfo->getMTDEraseSize(MTDInfo->findMTDsystem()); CMkfsJFFS2 mkfs; - mkfs.makeJffs2Image(path, filename, esize, 0, 0, __LITTLE_ENDIAN, true, true, &progress, devTable); + mkfs.makeJffs2Image(path, filename, esize, 0, 0, __LITTLE_ENDIAN, true, true, &progress, &v_devtable); progress.hide(); - unlink(devTable.c_str()); char message[500]; sprintf(message, g_Locale->getText(LOCALE_FLASHUPDATE_SAVESUCCESS), filename.c_str()); diff --git a/src/gui/update.h b/src/gui/update.h index fffda824f..2ae06f958 100644 --- a/src/gui/update.h +++ b/src/gui/update.h @@ -39,6 +39,9 @@ #include #include +#ifdef BOXMODEL_APOLLO +#include +#endif #include @@ -78,7 +81,7 @@ class CFlashExpert : public CProgressWindow bool checkSize(int mtd, std::string &backupFile); void readmtd(int readmtd); #ifdef BOXMODEL_APOLLO - void addDevtableEntry(int fd_dev, const char *entry); + bool readDevtableFile(std::string &devtableFile, CMkfsJFFS2::v_devtable_t &v_devtable); void readmtdJFFS2(std::string &filename); #endif diff --git a/src/system/mtdutils/mkfs.jffs2.cpp b/src/system/mtdutils/mkfs.jffs2.cpp index 9076e60ab..c82b4cfaf 100644 --- a/src/system/mtdutils/mkfs.jffs2.cpp +++ b/src/system/mtdutils/mkfs.jffs2.cpp @@ -69,6 +69,7 @@ #include #include "rbtree.h" +#include #include extern CLocaleManager *g_Locale; @@ -891,7 +892,7 @@ void CMkfsJFFS2::create_target_filesystem(struct filesystem_entry *root) Regular files must exist in the target root directory. If a char, block, fifo, or directory does not exist, it will be created. */ -int CMkfsJFFS2::interpret_table_entry(struct filesystem_entry *root, char *line) +bool CMkfsJFFS2::interpret_table_entry(struct filesystem_entry *root, const char *line) { char *hostpath; char type; @@ -901,9 +902,9 @@ int CMkfsJFFS2::interpret_table_entry(struct filesystem_entry *root, char *line) struct filesystem_entry *entry; memset(name, '\0', 512); - if (sscanf (line, "%511s %c %lo %lu %lu %lu %lu %lu %lu %lu", - name, &type, &mode, &uid, &gid, &major, &minor, &start, &increment, &count) < 0) - return 1; + if (sscanf(line, "%511s %c %lo %lu %lu %lu %lu %lu %lu %lu", + name, &type, &mode, &uid, &gid, &major, &minor, &start, &increment, &count) < 0) + return false; if (!strcmp(name, "/")) { sys_errmsg("Device table entries require absolute paths"); @@ -956,7 +957,7 @@ int CMkfsJFFS2::interpret_table_entry(struct filesystem_entry *root, char *line) if (parent == NULL) { errmsg ("skipping device_table entry '%s': no parent directory!", name); free(hostpath); - return 1; + return false; } switch (type) { @@ -996,50 +997,25 @@ int CMkfsJFFS2::interpret_table_entry(struct filesystem_entry *root, char *line) } } free(hostpath); - return 0; + return true; } -int CMkfsJFFS2::parse_device_table(struct filesystem_entry *root, FILE * file) +bool CMkfsJFFS2::parse_device_table(struct filesystem_entry *root, v_devtable_t *v_devtable) { - char *line; - int status = 0; - size_t length = 0; - /* Turn off squash, since we must ensure that values * entered via the device table are not squashed */ - squash_uids = 0; + squash_uids = 0; squash_perms = 0; - /* Looks ok so far. The general plan now is to read in one - * line at a time, check for leading comment delimiters ('#'), - * then try and parse the line as a device table. If we fail - * to parse things, try and help the poor fool to fix their - * device table with a useful error msg... */ - line = NULL; - while (getline(&line, &length, file) != -1) { - /* First trim off any whitespace */ - int len = strlen(line); - - /* trim trailing whitespace */ - while (len > 0 && isspace(line[len - 1])) - line[--len] = '\0'; - /* trim leading whitespace */ - memmove(line, &line[strspn(line, " \n\r\t\v")], len); - - /* How long are we after trimming? */ - len = strlen(line); - - /* If this is NOT a comment line, try to interpret it */ - if (len && *line != '#') { - if (interpret_table_entry(root, line)) - status = 1; - } - - free(line); - line = NULL; + bool status = false; + std::vector::iterator it = v_devtable->begin(); + while (it < v_devtable->end()) { + std::string line = *it; + line = trim(line); + if (interpret_table_entry(root, line.c_str())) + status = true; + ++it; } - fclose(file); - return status; } @@ -1075,18 +1051,13 @@ struct filesystem_entry *CMkfsJFFS2::recursive_add_host_directory( } if (((sb.st_dev == dev_x[dev_dev]) && (strstr(targetpath, "/dev") == targetpath)) || - ((sb.st_dev == dev_x[dev_proc]) && (strstr(targetpath, "/proc") == targetpath)) || - ((sb.st_dev == dev_x[dev_sys]) && (strstr(targetpath, "/sys") == targetpath)) || - ((sb.st_dev == dev_x[dev_tmp]) && (strstr(targetpath, "/tmp") == targetpath))) { + ((sb.st_dev == dev_x[dev_proc]) && (strstr(targetpath, "/proc") == targetpath)) || + ((sb.st_dev == dev_x[dev_sys]) && (strstr(targetpath, "/sys") == targetpath)) || + ((sb.st_dev == dev_x[dev_tmp]) && (strstr(targetpath, "/tmp") == targetpath))) { skipCheck = true; } - if ((!skipCheck) && -#if 0 - (sb.st_dev != dev_x[dev_dev]) && /* /dev */ - (sb.st_dev != dev_x[dev_pts]) && /* /dev/pts */ -#endif - (sb.st_dev != dev_x[dev_jffs2])) /* jffs2 */ + if ((!skipCheck) && (sb.st_dev != dev_x[dev_jffs2])) /* jffs2 */ return NULL; } @@ -1167,14 +1138,14 @@ struct filesystem_entry *CMkfsJFFS2::recursive_add_host_directory( bool CMkfsJFFS2::makeJffs2Image(std::string& path, std::string& imageName, - int eraseBlockSize/*=0x20000*/, - int padFsSize/*=0*/, - int addCleanmarkers/*=0*/, - int targetEndian/*=__LITTLE_ENDIAN*/, - bool skipSpezialFolders/*=true*/, - bool useSumtool/*=true*/, + int eraseBlockSize, + int padFsSize, + int addCleanmarkers, + int targetEndian, + bool skipSpezialFolders, + bool useSumtool, CProgressWindow *progress/*=NULL*/, - std::string devTable/*=""*/) + v_devtable_t *v_devtable/*=NULL*/) { Init(); @@ -1182,7 +1153,6 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, imageName_ = imageName; useSumtool_ = useSumtool; erase_block_size = eraseBlockSize; // -e - FILE *devtable = NULL; // -D pad_fs_size = padFsSize; // -p add_cleanmarkers = addCleanmarkers; // -n target_endian = targetEndian; // -l @@ -1193,7 +1163,6 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, hardlinks.rb_node = NULL; // printf("[%s] erase_block_size: 0x%X\n", __FUNCTION__, eraseBlockSize); - classInit(); char *cwd; @@ -1208,7 +1177,6 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, if (skipSpezialFolders) { std::string tmpPath = (path == "/") ? "" : path; -// std::string path_x[dev_max] = {tmpPath + "/sys", tmpPath + "/proc", tmpPath + "/tmp", tmpPath + "/dev/pts", tmpPath + "/dev", tmpPath + "/"}; std::string path_x[dev_max] = {tmpPath + "/sys", tmpPath + "/proc", tmpPath + "/tmp", tmpPath + "/dev", tmpPath + "/"}; for (int ix = dev_sys; ix < dev_max; ix++) { @@ -1230,10 +1198,8 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, progressBar->showGlobalStatus(50); } - if (devTable != "") - devtable = fopen(devTable.c_str(), "r"); - if (devtable) - parse_device_table(fse_root, devtable); + if ((v_devtable != NULL) && (!v_devtable->empty())) + parse_device_table(fse_root, v_devtable); pid_t pid; std::string pcmd = "du -sx " + rootdir; diff --git a/src/system/mtdutils/mkfs.jffs2.h b/src/system/mtdutils/mkfs.jffs2.h index 6a2dd2828..469aae537 100644 --- a/src/system/mtdutils/mkfs.jffs2.h +++ b/src/system/mtdutils/mkfs.jffs2.h @@ -24,18 +24,21 @@ */ #include +#include #include #include class CMkfsJFFS2 { + public: + typedef std::vector v_devtable_t; + private: enum { dev_sys = 0, dev_proc = 1, dev_tmp = 2, -/* dev_pts = 3,*/ dev_dev = 3, dev_jffs2 = 4, dev_max = 5 @@ -70,8 +73,8 @@ class CMkfsJFFS2 struct filesystem_entry *parent, const char *targetpath, const char *hostpath, bool skipSpezialFolders, CProgressWindow *progress=NULL); - int parse_device_table(struct filesystem_entry *root, FILE * file); - int interpret_table_entry(struct filesystem_entry *root, char *line); + bool parse_device_table(struct filesystem_entry *root, v_devtable_t *v_devtable); + bool interpret_table_entry(struct filesystem_entry *root, const char *line); void create_target_filesystem(struct filesystem_entry *root); void recursive_populate_directory(struct filesystem_entry *dir); void padblock(void); @@ -100,14 +103,14 @@ class CMkfsJFFS2 bool makeJffs2Image(std::string& path, std::string& imageName, - int eraseBlockSize=0x20000, - int padFsSize=0, - int addCleanmarkers=0, - int targetEndian=__LITTLE_ENDIAN, - bool skipSpezialFolders=true, - bool useSumtool=true, + int eraseBlockSize, + int padFsSize, + int addCleanmarkers, + int targetEndian, + bool skipSpezialFolders, + bool useSumtool, CProgressWindow *progress=NULL, - std::string devTable=""); + v_devtable_t *v_devtable=NULL); }; From d00cb6f8ec4a9dff4662dcd90ea5ed641f4a23d6 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Tue, 24 Sep 2013 23:22:25 +0200 Subject: [PATCH 082/200] Image backup apollo Part #6 - Menu option for including kernel/uldr/u-boot in the image backup - Menu option for creating an image with a different erasesize Tank <=> Trinity --- data/locale/deutsch.locale | 10 ++ data/locale/english.locale | 10 ++ src/gui/update.cpp | 175 ++++++++++++++++++++++++++++- src/gui/update.h | 23 +++- src/neutrino.cpp | 12 ++ src/neutrino_menue.h | 1 + src/system/locals.h | 10 ++ src/system/locals_intern.h | 10 ++ src/system/mtdutils/mkfs.jffs2.cpp | 2 +- src/system/settings.h | 6 + 10 files changed, 252 insertions(+), 7 deletions(-) diff --git a/data/locale/deutsch.locale b/data/locale/deutsch.locale index 03957d35e..38ffcefd6 100644 --- a/data/locale/deutsch.locale +++ b/data/locale/deutsch.locale @@ -466,6 +466,16 @@ flashupdate.cantopenfile kann Datei nicht öffnen flashupdate.cantopenmtd kann MTD nicht öffnen flashupdate.checkupdate_internet Online nach Updates suchen flashupdate.checkupdate_local Lokales Update +flashupdate.createimage Image speichern +flashupdate.createimage_add_env 'env' hinzufügen +flashupdate.createimage_add_kernel 'kernel' hinzufügen +flashupdate.createimage_add_spare 'spare' hinzufügen +flashupdate.createimage_add_u_boot 'u-boot' hinzufügen +flashupdate.createimage_add_uldr 'uldr' hinzufügen +flashupdate.createimage_menu Aktuelle Software sichern +flashupdate.createimage_options Einstellungen +flashupdate.createimage_other Image für %s STB erstellen +flashupdate.createimage_warning Nachfolgend wird ein Image für die %s STB erstellt.\nDieses Image wird auch nur auf einer %s STB lauffähig sein!\n \nTrotzdem fortsetzten? flashupdate.currentversion_sep Installierte Version flashupdate.currentversiondate Datum flashupdate.currentversiontime Uhrzeit diff --git a/data/locale/english.locale b/data/locale/english.locale index df3a18081..2142125b2 100644 --- a/data/locale/english.locale +++ b/data/locale/english.locale @@ -466,6 +466,16 @@ flashupdate.cantopenfile can't open file flashupdate.cantopenmtd can't open MTD flashupdate.checkupdate_internet Check for online updates flashupdate.checkupdate_local Local update +flashupdate.createimage Save image +flashupdate.createimage_add_env Add 'env' to image +flashupdate.createimage_add_kernel Add 'kernel' to image +flashupdate.createimage_add_spare Add 'spare' to image +flashupdate.createimage_add_u_boot Add 'u-boot' to image +flashupdate.createimage_add_uldr Add 'uldr' to image +flashupdate.createimage_menu Save current software +flashupdate.createimage_options Options +flashupdate.createimage_other Create image for %s STB +flashupdate.createimage_warning Now an image for the %s STB is created.\nThis image will also run on only one %s STB!\n \nNevertheless continued? flashupdate.currentversion_sep Current version flashupdate.currentversiondate Date flashupdate.currentversiontime Time diff --git a/src/gui/update.cpp b/src/gui/update.cpp index 8c7376789..f1da1d298 100644 --- a/src/gui/update.cpp +++ b/src/gui/update.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -542,6 +543,11 @@ CFlashExpert::CFlashExpert() { selectedMTD = -1; width = w_max (40, 10); +#ifdef BOXMODEL_APOLLO + forceOtherFilename = false; + otherFilename = ""; + createimage_other = 0; +#endif } CFlashExpert* CFlashExpert::getInstance() @@ -653,10 +659,13 @@ void CFlashExpert::readmtdJFFS2(std::string &filename) } std::string path = "/"; - CMTDInfo *MTDInfo = CMTDInfo::getInstance(); - int esize = MTDInfo->getMTDEraseSize(MTDInfo->findMTDsystem()); + int eSize = CMTDInfo::getInstance()->getMTDEraseSize(CMTDInfo::getInstance()->findMTDsystem()); + if (createimage_other == 1) { + if (eSize == 0x40000) eSize = 0x20000; + else if (eSize == 0x20000) eSize = 0x40000; + } CMkfsJFFS2 mkfs; - mkfs.makeJffs2Image(path, filename, esize, 0, 0, __LITTLE_ENDIAN, true, true, &progress, &v_devtable); + mkfs.makeJffs2Image(path, filename, eSize, 0, 0, __LITTLE_ENDIAN, true, true, &progress, &v_devtable); progress.hide(); char message[500]; @@ -673,8 +682,17 @@ void CFlashExpert::readmtd(int preadmtd) std::string timeStr = getNowTimeStr("_%Y%m%d_%H%M"); std::string tankStr = ""; #ifdef BOXMODEL_APOLLO - if ((preadmtd == 0) && (CMTDInfo::getInstance()->getMTDEraseSize(CMTDInfo::getInstance()->findMTDsystem()) == 0x40000)) - tankStr = ".256k"; + int eSize = CMTDInfo::getInstance()->getMTDEraseSize(CMTDInfo::getInstance()->findMTDsystem()); + if (preadmtd == 0) { + if (createimage_other == 0) { + if (eSize == 0x40000) tankStr = ".256k"; + if (eSize == 0x20000) tankStr = ""; + } + else if (createimage_other == 1) { + if (eSize == 0x40000) tankStr = ""; + if (eSize == 0x20000) tankStr = ".256k"; + } + } #endif if (g_settings.softupdate_name_mode_backup == CExtUpdate::SOFTUPDATE_NAME_HOSTNAME_TIME) filename = (std::string)g_settings.update_dir + "/" + mtdInfo->getMTDName(preadmtd) + timeStr + "_" + hostName + tankStr + ".img"; @@ -696,6 +714,9 @@ void CFlashExpert::readmtd(int preadmtd) #ifndef BOXMODEL_APOLLO if ((std::string)g_settings.update_dir == "/tmp") skipCheck = true; +#else + if (forceOtherFilename) + filename = otherFilename; #endif if ((!skipCheck) && (!checkSize(preadmtd, filename))) return; @@ -718,7 +739,12 @@ void CFlashExpert::readmtd(int preadmtd) sprintf(message, g_Locale->getText(LOCALE_FLASHUPDATE_SAVESUCCESS), filename.c_str()); sleep(1); hide(); +#ifdef BOXMODEL_APOLLO + if (!forceOtherFilename) + ShowHintUTF(LOCALE_MESSAGEBOX_INFO, message); +#else ShowHintUTF(LOCALE_MESSAGEBOX_INFO, message); +#endif } } @@ -779,6 +805,11 @@ int CFlashExpert::showMTDSelector(const std::string & actionkey) // disable write uboot / uldr, FIXME correct numbers if ((actionkey == "writemtd") && (lx == 5 || lx == 6)) enabled = false; + if ((actionkey == "readmtd") && (lx == 0)) { + CMenuForwarder *mf = new CMenuForwarderNonLocalized("root0", true, NULL, new CFlashExpertSetup(), NULL, CRCInput::convertDigitToKey(shortcut++)); + mtdselector->addItem(mf); + continue; + } #else // disable write uboot if ((actionkey == "writemtd") && (lx == 0)) @@ -875,3 +906,137 @@ int CFlashExpert::exec(CMenuTarget* parent, const std::string & actionKey) hide(); return res; } + +#ifdef BOXMODEL_APOLLO +CFlashExpertSetup::CFlashExpertSetup() +{ + width = w_max (40, 10); +} + +void CFlashExpertSetup::readMTDPart(int mtd, const std::string &fileName) +{ + CFlashExpert *cfe = CFlashExpert::getInstance(); + if (file_exists(fileName.c_str())) + unlink(fileName.c_str()); + cfe->otherFilename = fileName; + cfe->readmtd(mtd); + sync(); +} + +#define UBOOT_BIN +//#define ENV_SPARE_BIN + +int CFlashExpertSetup::exec(CMenuTarget* parent, const std::string &actionKey) +{ +#define UPDATEDIR "/var/update" + if (parent) + parent->hide(); + + if (actionKey == "readmtd0") { + CFlashExpert *cfe = CFlashExpert::getInstance(); + bool skipImage = false; + if (cfe->createimage_other == 1) { + char message[512] = {0}; + // create image warning + CMTDInfo *mtdInfo = CMTDInfo::getInstance(); + const char *box = (mtdInfo->getMTDEraseSize(mtdInfo->findMTDsystem()) == 0x40000) ? "Trinity" : "Tank"; + snprintf(message, sizeof(message)-1, g_Locale->getText(LOCALE_FLASHUPDATE_CREATEIMAGE_WARNING), box, box); + if (ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, message, CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo, NEUTRINO_ICON_UPDATE) != CMessageBox::mbrYes) + skipImage = true; + } + if (!skipImage) { + std::string uldrName = (std::string)UPDATEDIR + "/uldr.bin"; + cfe->forceOtherFilename = true; + if (g_settings.flashupdate_createimage_add_uldr == 1) + readMTDPart(2, uldrName); +#ifdef UBOOT_BIN + std::string ubootName = (std::string)UPDATEDIR + "/u-boot.bin"; + if (g_settings.flashupdate_createimage_add_u_boot == 1) + readMTDPart(3, ubootName); +#endif +#ifdef ENV_SPARE_BIN + std::string envName = (std::string)UPDATEDIR + "/env.bin"; + if (g_settings.flashupdate_createimage_add_env == 1) + readMTDPart(4, envName); + std::string spareName = (std::string)UPDATEDIR + "/spare.bin"; + if (g_settings.flashupdate_createimage_add_spare == 1) + readMTDPart(5, spareName); +#endif + std::string kernelName = (std::string)UPDATEDIR + "/vmlinux.ub.gz"; + if (g_settings.flashupdate_createimage_add_kernel == 1) + readMTDPart(6, kernelName); + cfe->forceOtherFilename = false; + cfe->otherFilename = ""; + + cfe->readmtd(0); + + if (g_settings.flashupdate_createimage_add_uldr == 1) + unlink(uldrName.c_str()); +#ifdef UBOOT_BIN + if (g_settings.flashupdate_createimage_add_u_boot == 1) + unlink(ubootName.c_str()); +#endif +#ifdef ENV_SPARE_BIN + if (g_settings.flashupdate_createimage_add_env == 1) + unlink(envName.c_str()); + if (g_settings.flashupdate_createimage_add_spare == 1) + unlink(spareName.c_str()); +#endif + if (g_settings.flashupdate_createimage_add_kernel == 1) + unlink(kernelName.c_str()); + sync(); + } + + cfe->createimage_other = 0; + return menu_return::RETURN_EXIT_ALL; + } + return showMenu(); +} + +int CFlashExpertSetup::showMenu() +{ + CFlashExpert *cfe = CFlashExpert::getInstance(); + CMenuWidget *rootfsSetup = new CMenuWidget(LOCALE_SERVICEMENU_UPDATE, NEUTRINO_ICON_UPDATE, width, MN_WIDGET_ID_MTDREAD_ROOT0); + rootfsSetup->addIntroItems(LOCALE_FLASHUPDATE_CREATEIMAGE_MENU); + + CMenuSeparator *s1 = new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_FLASHUPDATE_CREATEIMAGE_OPTIONS); + CMenuForwarder *m1 = new CMenuForwarder(LOCALE_FLASHUPDATE_CREATEIMAGE, true, NULL, this, "readmtd0", CRCInput::convertDigitToKey(0)); + CMenuOptionChooser *m2 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_ULDR, &g_settings.flashupdate_createimage_add_uldr, + MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); + CMenuOptionChooser *m3 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_U_BOOT, &g_settings.flashupdate_createimage_add_u_boot, + MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); +#ifdef ENV_SPARE_BIN + CMenuOptionChooser *m4 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_ENV, &g_settings.flashupdate_createimage_add_env, + MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, false); + CMenuOptionChooser *m5 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_SPARE, &g_settings.flashupdate_createimage_add_spare, + MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, false); +#endif + CMenuOptionChooser *m6 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_KERNEL, &g_settings.flashupdate_createimage_add_kernel, + MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); + + + CMTDInfo *mtdInfo = CMTDInfo::getInstance(); + const char *box = (mtdInfo->getMTDEraseSize(mtdInfo->findMTDsystem()) == 0x40000) ? "Trinity" : "Tank"; + char mText[512] = {0}; + snprintf(mText, sizeof(mText)-1, g_Locale->getText(LOCALE_FLASHUPDATE_CREATEIMAGE_OTHER), box); + CMenuOptionChooser *m7 = new CMenuOptionChooser(mText, &(cfe->createimage_other), MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); + + rootfsSetup->addItem(m1); // create image + rootfsSetup->addItem(s1); + rootfsSetup->addItem(m2); // include uldr + rootfsSetup->addItem(m3); // include u-boot +#ifdef ENV_SPARE_BIN + rootfsSetup->addItem(m4); // include env + rootfsSetup->addItem(m5); // include spare +#endif + rootfsSetup->addItem(m6); // include kernel + rootfsSetup->addItem(GenericMenuSeparatorLine); + rootfsSetup->addItem(m7); // create image for other STB + + int res = rootfsSetup->exec (NULL, ""); + delete rootfsSetup; + + cfe->createimage_other = 0; + return res; +} +#endif // BOXMODEL_APOLLO diff --git a/src/gui/update.h b/src/gui/update.h index 2ae06f958..05bb4cfe9 100644 --- a/src/gui/update.h +++ b/src/gui/update.h @@ -79,19 +79,40 @@ class CFlashExpert : public CProgressWindow int showFileSelector(const std::string & actionkey); bool checkSize(int mtd, std::string &backupFile); - void readmtd(int readmtd); #ifdef BOXMODEL_APOLLO bool readDevtableFile(std::string &devtableFile, CMkfsJFFS2::v_devtable_t &v_devtable); void readmtdJFFS2(std::string &filename); #endif public: +#ifdef BOXMODEL_APOLLO + bool forceOtherFilename; + std::string otherFilename; + int createimage_other; +#endif CFlashExpert(); static CFlashExpert* getInstance(); int exec(CMenuTarget* parent, const std::string & actionKey); void writemtd(const std::string & filename, int mtdNumber); + void readmtd(int readmtd); }; +#ifdef BOXMODEL_APOLLO +class CFlashExpertSetup : public CMenuTarget +{ + private: + int width; + + int showMenu(); + void readMTDPart(int mtd, const std::string &fileName); + + public: + CFlashExpertSetup(); +// ~CFlashExpertSetup(); + + int exec(CMenuTarget* parent, const std::string &actionKey); +}; +#endif // BOXMODEL_APOLLO #endif diff --git a/src/neutrino.cpp b/src/neutrino.cpp index eb6cd06cd..dfd8a9cb7 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -663,6 +663,12 @@ int CNeutrinoApp::loadSetup(const char * fname) g_settings.softupdate_name_mode_apply = configfile.getInt32( "softupdate_name_mode_apply", CExtUpdate::SOFTUPDATE_NAME_DEFAULT); g_settings.softupdate_name_mode_backup = configfile.getInt32( "softupdate_name_mode_backup", CExtUpdate::SOFTUPDATE_NAME_DEFAULT); + g_settings.flashupdate_createimage_add_uldr = configfile.getInt32( "flashupdate_createimage_add_uldr", 1); + g_settings.flashupdate_createimage_add_u_boot = configfile.getInt32( "flashupdate_createimage_add_u_boot", 0); + g_settings.flashupdate_createimage_add_env = configfile.getInt32( "flashupdate_createimage_add_env", 0); + g_settings.flashupdate_createimage_add_spare = configfile.getInt32( "flashupdate_createimage_add_spare", 0); + g_settings.flashupdate_createimage_add_kernel = configfile.getInt32( "flashupdate_createimage_add_kernel", 1); + strcpy(g_settings.softupdate_url_file, configfile.getString("softupdate_url_file", "/var/etc/update.urls").c_str()); strcpy(g_settings.softupdate_proxyserver, configfile.getString("softupdate_proxyserver", "" ).c_str()); strcpy(g_settings.softupdate_proxyusername, configfile.getString("softupdate_proxyusername", "" ).c_str()); @@ -1103,6 +1109,12 @@ void CNeutrinoApp::saveSetup(const char * fname) configfile.setInt32 ("softupdate_name_mode_apply", g_settings.softupdate_name_mode_apply); configfile.setInt32 ("softupdate_name_mode_backup", g_settings.softupdate_name_mode_backup); + configfile.setInt32("flashupdate_createimage_add_uldr", g_settings.flashupdate_createimage_add_uldr); + configfile.setInt32("flashupdate_createimage_add_u_boot", g_settings.flashupdate_createimage_add_u_boot); + configfile.setInt32("flashupdate_createimage_add_env", g_settings.flashupdate_createimage_add_env); + configfile.setInt32("flashupdate_createimage_add_spare", g_settings.flashupdate_createimage_add_spare); + configfile.setInt32("flashupdate_createimage_add_kernel", g_settings.flashupdate_createimage_add_kernel); + configfile.setString("softupdate_proxyserver" , g_settings.softupdate_proxyserver ); configfile.setString("softupdate_proxyusername" , g_settings.softupdate_proxyusername ); configfile.setString("softupdate_proxypassword" , g_settings.softupdate_proxypassword ); diff --git a/src/neutrino_menue.h b/src/neutrino_menue.h index 686fba91b..db23a4254 100644 --- a/src/neutrino_menue.h +++ b/src/neutrino_menue.h @@ -158,6 +158,7 @@ enum MN_WIDGET_ID MN_WIDGET_ID_MTDREAD_SELECTOR, MN_WIDGET_ID_MTDWRITE_SELECTOR, MN_WIDGET_ID_FILESELECTOR, + MN_WIDGET_ID_MTDREAD_ROOT0, //software update MN_WIDGET_ID_SOFTWAREUPDATE, diff --git a/src/system/locals.h b/src/system/locals.h index b6c9d6d31..cd9eaa275 100644 --- a/src/system/locals.h +++ b/src/system/locals.h @@ -493,6 +493,16 @@ typedef enum LOCALE_FLASHUPDATE_CANTOPENMTD, LOCALE_FLASHUPDATE_CHECKUPDATE_INTERNET, LOCALE_FLASHUPDATE_CHECKUPDATE_LOCAL, + LOCALE_FLASHUPDATE_CREATEIMAGE, + LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_ENV, + LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_KERNEL, + LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_SPARE, + LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_U_BOOT, + LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_ULDR, + LOCALE_FLASHUPDATE_CREATEIMAGE_MENU, + LOCALE_FLASHUPDATE_CREATEIMAGE_OPTIONS, + LOCALE_FLASHUPDATE_CREATEIMAGE_OTHER, + LOCALE_FLASHUPDATE_CREATEIMAGE_WARNING, LOCALE_FLASHUPDATE_CURRENTVERSION_SEP, LOCALE_FLASHUPDATE_CURRENTVERSIONDATE, LOCALE_FLASHUPDATE_CURRENTVERSIONTIME, diff --git a/src/system/locals_intern.h b/src/system/locals_intern.h index 198e82d27..09faabf4b 100644 --- a/src/system/locals_intern.h +++ b/src/system/locals_intern.h @@ -493,6 +493,16 @@ const char * locale_real_names[] = "flashupdate.cantopenmtd", "flashupdate.checkupdate_internet", "flashupdate.checkupdate_local", + "flashupdate.createimage", + "flashupdate.createimage_add_env", + "flashupdate.createimage_add_kernel", + "flashupdate.createimage_add_spare", + "flashupdate.createimage_add_u_boot", + "flashupdate.createimage_add_uldr", + "flashupdate.createimage_menu", + "flashupdate.createimage_options", + "flashupdate.createimage_other", + "flashupdate.createimage_warning", "flashupdate.currentversion_sep", "flashupdate.currentversiondate", "flashupdate.currentversiontime", diff --git a/src/system/mtdutils/mkfs.jffs2.cpp b/src/system/mtdutils/mkfs.jffs2.cpp index c82b4cfaf..33ea6ffe0 100644 --- a/src/system/mtdutils/mkfs.jffs2.cpp +++ b/src/system/mtdutils/mkfs.jffs2.cpp @@ -1162,7 +1162,7 @@ bool CMkfsJFFS2::makeJffs2Image(std::string& path, progressBar = progress; hardlinks.rb_node = NULL; -// printf("[%s] erase_block_size: 0x%X\n", __FUNCTION__, eraseBlockSize); + printf("[%s] erase_block_size: 0x%X\n", __FUNCTION__, eraseBlockSize); classInit(); char *cwd; diff --git a/src/system/settings.h b/src/system/settings.h index 006202c84..13417a945 100644 --- a/src/system/settings.h +++ b/src/system/settings.h @@ -482,6 +482,12 @@ struct SNeutrinoSettings int apply_settings; int apply_kernel; + int flashupdate_createimage_add_uldr; + int flashupdate_createimage_add_u_boot; + int flashupdate_createimage_add_env; + int flashupdate_createimage_add_spare; + int flashupdate_createimage_add_kernel; + //BouquetHandling int bouquetlist_mode; From c48a8cf6950b52ae7376920867fe063f376ee5be Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Thu, 26 Sep 2013 02:30:29 +0200 Subject: [PATCH 083/200] Image backup apollo Part #7 - Add image backup to menu 'Software Update' --- data/locale/deutsch.locale | 1 + data/locale/english.locale | 1 + src/gui/update_menue.cpp | 8 ++++++++ src/system/locals.h | 1 + src/system/locals_intern.h | 1 + 5 files changed, 12 insertions(+) diff --git a/data/locale/deutsch.locale b/data/locale/deutsch.locale index 38ffcefd6..6c83a557c 100644 --- a/data/locale/deutsch.locale +++ b/data/locale/deutsch.locale @@ -1119,6 +1119,7 @@ menu.hint_sleeptimer Zeitschaltuhr auf Ihrer Box aktivieren\nDie Box fährt dann menu.hint_soft_restart Neustarten von Neutrino-HD, ohne die Box neu zu starten menu.hint_softupdate_check Im Internet nach verfügbaren Updates suchen, herunterladen und installieren menu.hint_softupdate_check_local Lokal nach verfügbaren Updates suchen und installieren +menu.hint_softupdate_createimage_menu Sicherung der aktuellen Software inklusive aller Einstellungen menu.hint_softupdate_expert Einzelne Partitionen aus dem Flash lesen bzw. in den Flash schreiben menu.hint_softupdate_expert_read Einzelne Partitionen (U-Boot, Splash, Kernel, SystemFS) aus dem Flash lesen menu.hint_softupdate_expert_write Einzelne Partitionen (Splash, Kernel, SystemFS) in den Flash schreiben diff --git a/data/locale/english.locale b/data/locale/english.locale index 2142125b2..c37e7fbd6 100644 --- a/data/locale/english.locale +++ b/data/locale/english.locale @@ -1119,6 +1119,7 @@ menu.hint_sleeptimer Set timer to put your box\nin sleep mode menu.hint_soft_restart Restart Neutrino-HD without reboot menu.hint_softupdate_check Check online update, download and flash firmware menu.hint_softupdate_check_local Select and flash firmware from local file +menu.hint_softupdate_createimage_menu Backup of current software, including all settings menu.hint_softupdate_expert Separate partitions from the flash read / write to the flash menu.hint_softupdate_expert_read Separate partitions (U-Boot, Splash, Kernel, SystemFS) from the flash read menu.hint_softupdate_expert_write Separate partitions (Splash, Kernel, SystemFS) write to the flash diff --git a/src/gui/update_menue.cpp b/src/gui/update_menue.cpp index 55fe6ce46..0c23ef26b 100644 --- a/src/gui/update_menue.cpp +++ b/src/gui/update_menue.cpp @@ -112,6 +112,14 @@ int CSoftwareUpdate::showSoftwareUpdate() mf->setHint("", LOCALE_MENU_HINT_SOFTUPDATE_EXPERT); softUpdate.addItem(mf); +#ifdef BOXMODEL_APOLLO + softUpdate.addItem(GenericMenuSeparatorLine); + + mf = new CMenuForwarder(LOCALE_FLASHUPDATE_CREATEIMAGE_MENU, true, NULL, new CFlashExpertSetup(), NULL, CRCInput::convertDigitToKey(1)); + mf->setHint("", LOCALE_MENU_HINT_SOFTUPDATE_CREATEIMAGE_MENU); + softUpdate.addItem(mf); +#endif + int res = softUpdate.exec (NULL, ""); return res; } diff --git a/src/system/locals.h b/src/system/locals.h index cd9eaa275..b3b170ffa 100644 --- a/src/system/locals.h +++ b/src/system/locals.h @@ -1146,6 +1146,7 @@ typedef enum LOCALE_MENU_HINT_SOFT_RESTART, LOCALE_MENU_HINT_SOFTUPDATE_CHECK, LOCALE_MENU_HINT_SOFTUPDATE_CHECK_LOCAL, + LOCALE_MENU_HINT_SOFTUPDATE_CREATEIMAGE_MENU, LOCALE_MENU_HINT_SOFTUPDATE_EXPERT, LOCALE_MENU_HINT_SOFTUPDATE_EXPERT_READ, LOCALE_MENU_HINT_SOFTUPDATE_EXPERT_WRITE, diff --git a/src/system/locals_intern.h b/src/system/locals_intern.h index 09faabf4b..86e59c778 100644 --- a/src/system/locals_intern.h +++ b/src/system/locals_intern.h @@ -1146,6 +1146,7 @@ const char * locale_real_names[] = "menu.hint_soft_restart", "menu.hint_softupdate_check", "menu.hint_softupdate_check_local", + "menu.hint_softupdate_createimage_menu", "menu.hint_softupdate_expert", "menu.hint_softupdate_expert_read", "menu.hint_softupdate_expert_write", From d7d181a7aee2f95f3fd2ccd6a3060661f130160b Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Fri, 27 Sep 2013 12:52:52 +0400 Subject: [PATCH 084/200] gui/widget/menue.cpp: fix parent arg for exec using menu action keys --- src/gui/widget/menue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widget/menue.cpp b/src/gui/widget/menue.cpp index e9a0b35b2..fe36b3d6f 100644 --- a/src/gui/widget/menue.cpp +++ b/src/gui/widget/menue.cpp @@ -535,7 +535,7 @@ int CMenuWidget::exec(CMenuTarget* parent, const std::string &) std::map::iterator it = keyActionMap.find(msg); if (it != keyActionMap.end()) { fader.Stop(); - int rv = it->second.menue->exec(parent, it->second.action); + int rv = it->second.menue->exec(this, it->second.action); switch ( rv ) { case menu_return::RETURN_EXIT_ALL: retval = menu_return::RETURN_EXIT_ALL; From 537a60fe6b3936bb8377dc6861a976a287fe7a27 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Fri, 27 Sep 2013 12:53:12 +0400 Subject: [PATCH 085/200] eitd/sectionsd.cpp: add getEventsCount() --- src/eitd/sectionsd.cpp | 8 ++++++++ src/eitd/sectionsd.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/eitd/sectionsd.cpp b/src/eitd/sectionsd.cpp index 67c2d73e7..8e0914fe9 100644 --- a/src/eitd/sectionsd.cpp +++ b/src/eitd/sectionsd.cpp @@ -2821,3 +2821,11 @@ void CEitManager::setLanguages(const std::vector& newLanguages) SIlanguage::setLanguages(newLanguages); SIlanguage::saveLanguages(); } + +unsigned CEitManager::getEventsCount() +{ + readLockEvents(); + unsigned anzEvents = mySIeventsOrderUniqueKey.size(); + unlockEvents(); + return anzEvents; +} diff --git a/src/eitd/sectionsd.h b/src/eitd/sectionsd.h index 9f82b216a..3d3d398c1 100644 --- a/src/eitd/sectionsd.h +++ b/src/eitd/sectionsd.h @@ -65,6 +65,7 @@ class CEitManager : public OpenThreads::Thread, public OpenThreads::Mutex bool getLinkageDescriptorsUniqueKey(const event_id_t uniqueKey, CSectionsdClient::LinkageDescriptorList& descriptors); bool getNVODTimesServiceKey(const t_channel_id uniqueServiceKey, CSectionsdClient::NVODTimesList& nvod_list); void setLanguages(const std::vector& newLanguages); + unsigned getEventsCount(); }; #endif From 550ca1dedb3c95bb8db7096af0d8f296c19bfde5 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Fri, 27 Sep 2013 14:17:11 +0400 Subject: [PATCH 086/200] gui/miscsettings_menu.cpp: add 'info' action key in epg settings to show current eit event count --- src/gui/miscsettings_menu.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/gui/miscsettings_menu.cpp b/src/gui/miscsettings_menu.cpp index 0a2bfc008..84b59ffa4 100644 --- a/src/gui/miscsettings_menu.cpp +++ b/src/gui/miscsettings_menu.cpp @@ -45,11 +45,13 @@ #include #include +#include #include #include #include +#include #include @@ -115,6 +117,14 @@ int CMiscMenue::exec(CMenuTarget* parent, const std::string &actionKey) return menu_return::RETURN_REPAINT; } #endif /*ONE_KEY_PLUGIN*/ + else if(actionKey == "info") + { + unsigned num = CEitManager::getInstance()->getEventsCount(); + char str[128]; + sprintf(str, "Event count: %d", num); + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, str, CMessageBox::mbrBack, CMessageBox::mbBack); + return menu_return::RETURN_REPAINT; + } return showMiscSettingsMenu(); } @@ -311,7 +321,7 @@ void CMiscMenue::showMiscSettingsMenuEnergy(CMenuWidget *ms_energy) void CMiscMenue::showMiscSettingsMenuEpg(CMenuWidget *ms_epg) { ms_epg->addIntroItems(LOCALE_MISCSETTINGS_EPG_HEAD); - + ms_epg->addKey(CRCInput::RC_info, this, "info"); CMenuOptionChooser * mc1 = new CMenuOptionChooser(LOCALE_MISCSETTINGS_EPG_SAVE_STANDBY, &g_settings.epg_save_standby, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, g_settings.epg_save); mc1->setHint("", LOCALE_MENU_HINT_EPG_SAVE_STANDBY); From d26bc23f6b0375375cf47b71084ae0aff8aac6e9 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Fri, 27 Sep 2013 15:51:08 +0400 Subject: [PATCH 087/200] nhttpd/tuxboxapi/coolstream/controlapi.cpp: wakeup zapit before neutrino, to be sure zapit will process any next commands --- src/nhttpd/tuxboxapi/coolstream/controlapi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp index c4193a5a6..a472813ae 100644 --- a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp +++ b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp @@ -433,6 +433,7 @@ void CControlAPI::StandbyCGI(CyhookHandler *hh) } else if (hh->ParamList["1"] == "off")// standby mode off { + NeutrinoAPI->Zapit->setStandby(false); if(CNeutrinoApp::getInstance()->getMode() == 4) NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::STANDBY_OFF, CEventServer::INITID_HTTPD); hh->SendOk(); From f468f9c1764a7df47760b6cac93130da3a231842 Mon Sep 17 00:00:00 2001 From: svenhoefer Date: Fri, 27 Sep 2013 18:02:26 +0200 Subject: [PATCH 088/200] - eventlist: use left/right to switch channels --- src/gui/eventlist.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/gui/eventlist.cpp b/src/gui/eventlist.cpp index c5834508a..cf3c65b45 100644 --- a/src/gui/eventlist.cpp +++ b/src/gui/eventlist.cpp @@ -544,10 +544,11 @@ int CNeutrinoEventList::exec(const t_channel_id channel_id, const std::string& c loop = false; } } - else if ( msg==CRCInput::RC_left || msg==CRCInput::RC_red ){ + else if ( msg==CRCInput::RC_red ){ loop= false; } - else if ( msg==CRCInput::RC_rewind || msg==CRCInput::RC_forward) { + else if ( msg==CRCInput::RC_left || msg==CRCInput::RC_right || msg==CRCInput::RC_rewind || msg==CRCInput::RC_forward ) { + // maybe remove RC_rewind and RC_forward in the future? t_bouquet_id current_bouquet_id= bouquetList->getActiveBouquetNumber(); t_channel_id channel_id_tmp, _channel_id = channel_id; @@ -560,7 +561,7 @@ int CNeutrinoEventList::exec(const t_channel_id channel_id, const std::string& c { channel_id_tmp = bouquetList->Bouquets[current_bouquet_id]->channelList->getChannelFromIndex(channel)->channel_id; if(channel_id_tmp == channel_id){ - if ( msg==CRCInput::RC_forward) { + if ( msg==CRCInput::RC_right || msg==CRCInput::RC_forward ) { channel = (channel+1) %channel_nr; }else { //RC_rewind channel = (channel == 0) ? channel_nr -1 : channel - 1; @@ -606,7 +607,7 @@ int CNeutrinoEventList::exec(const t_channel_id channel_id, const std::string& c eplus.exec(NULL, ""); loop = false; } - else if (msg==CRCInput::RC_help || msg==CRCInput::RC_right || msg==CRCInput::RC_ok || msg==CRCInput::RC_info) + else if (msg==CRCInput::RC_help || msg==CRCInput::RC_ok || msg==CRCInput::RC_info) { if ( evtlist[selected].eventID != 0 ) { From dea8e8bbc8521339b54ef819ed4aeb1c5a7190ec Mon Sep 17 00:00:00 2001 From: svenhoefer Date: Fri, 27 Sep 2013 18:07:40 +0200 Subject: [PATCH 089/200] - eventlist: fix paint of background in right box --- src/gui/eventlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/eventlist.cpp b/src/gui/eventlist.cpp index cf3c65b45..6d407787a 100644 --- a/src/gui/eventlist.cpp +++ b/src/gui/eventlist.cpp @@ -549,7 +549,7 @@ int CNeutrinoEventList::exec(const t_channel_id channel_id, const std::string& c } else if ( msg==CRCInput::RC_left || msg==CRCInput::RC_right || msg==CRCInput::RC_rewind || msg==CRCInput::RC_forward ) { // maybe remove RC_rewind and RC_forward in the future? - + bgRightBoxPaint = false; t_bouquet_id current_bouquet_id= bouquetList->getActiveBouquetNumber(); t_channel_id channel_id_tmp, _channel_id = channel_id; const unsigned int channel_nr = bouquetList->Bouquets[current_bouquet_id]->channelList->getSize(); From 859ef920ccbf7f0da8345b398f2cf80d4755b1eb Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Sat, 28 Sep 2013 07:23:36 +0200 Subject: [PATCH 090/200] CMTDInfo: Add function findMTDNumberFromName() --- src/system/flashtool.cpp | 9 +++++++++ src/system/flashtool.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/system/flashtool.cpp b/src/system/flashtool.cpp index 12356e410..8d242a2b8 100644 --- a/src/system/flashtool.cpp +++ b/src/system/flashtool.cpp @@ -636,6 +636,15 @@ int CMTDInfo::findMTDNumber(const std::string & filename) return -1; } +int CMTDInfo::findMTDNumberFromName(const char* name) +{ + for (int i = 0; i < getMTDCount(); i++) { + if ((std::string)name == getMTDName(i)) + return i; + } + return -1; +} + std::string CMTDInfo::getMTDName(const std::string & filename) { return getMTDName( findMTDNumber(filename) ); diff --git a/src/system/flashtool.h b/src/system/flashtool.h index 1e1fcd625..7b19cb689 100644 --- a/src/system/flashtool.h +++ b/src/system/flashtool.h @@ -131,6 +131,7 @@ class CMTDInfo int getMTDEraseSize( const std::string & filename ); int findMTDNumber(const std::string & filename); + int findMTDNumberFromName(const char* name); std::string findMTDsystem(); }; From b25b1c4fb57c7efe5e745b324cefafbd9531e541 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Sat, 28 Sep 2013 07:23:27 +0200 Subject: [PATCH 091/200] CFlashExpert: Use findMTDNumberFromName() to find mtdnumber --- src/gui/update.cpp | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/gui/update.cpp b/src/gui/update.cpp index f1da1d298..2cdf44c33 100644 --- a/src/gui/update.cpp +++ b/src/gui/update.cpp @@ -792,7 +792,7 @@ int CFlashExpert::showMTDSelector(const std::string & actionkey) widget_id = MN_WIDGET_ID_MTDREAD_SELECTOR; else if (actionkey == "writemtd") widget_id = MN_WIDGET_ID_MTDWRITE_SELECTOR; - + //generate mtd-selector CMenuWidget* mtdselector = new CMenuWidget(LOCALE_SERVICEMENU_UPDATE, NEUTRINO_ICON_UPDATE, width, widget_id); mtdselector->addIntroItems(LOCALE_FLASHUPDATE_MTDSELECTOR, NONEXISTANT_LOCALE, CMenuWidget::BTN_TYPE_CANCEL); @@ -802,17 +802,18 @@ int CFlashExpert::showMTDSelector(const std::string & actionkey) char sActionKey[20]; bool enabled = true; #ifdef BOXMODEL_APOLLO - // disable write uboot / uldr, FIXME correct numbers - if ((actionkey == "writemtd") && (lx == 5 || lx == 6)) + // disable write uboot / uldr + if ((actionkey == "writemtd") && (lx == mtdInfo->findMTDNumberFromName("u-boot") || lx == mtdInfo->findMTDNumberFromName("uldr"))) enabled = false; - if ((actionkey == "readmtd") && (lx == 0)) { + // build jffs2 image from root0 + if ((actionkey == "readmtd") && (lx == mtdInfo->findMTDNumberFromName("root0"))) { CMenuForwarder *mf = new CMenuForwarderNonLocalized("root0", true, NULL, new CFlashExpertSetup(), NULL, CRCInput::convertDigitToKey(shortcut++)); mtdselector->addItem(mf); continue; } #else // disable write uboot - if ((actionkey == "writemtd") && (lx == 0)) + if ((actionkey == "writemtd") && (lx == mtdInfo->findMTDNumberFromName("u-boot"))) enabled = false; #endif sprintf(sActionKey, "%s%d", actionkey.c_str(), lx); @@ -934,11 +935,11 @@ int CFlashExpertSetup::exec(CMenuTarget* parent, const std::string &actionKey) if (actionKey == "readmtd0") { CFlashExpert *cfe = CFlashExpert::getInstance(); + CMTDInfo *mtdInfo = CMTDInfo::getInstance(); bool skipImage = false; if (cfe->createimage_other == 1) { char message[512] = {0}; // create image warning - CMTDInfo *mtdInfo = CMTDInfo::getInstance(); const char *box = (mtdInfo->getMTDEraseSize(mtdInfo->findMTDsystem()) == 0x40000) ? "Trinity" : "Tank"; snprintf(message, sizeof(message)-1, g_Locale->getText(LOCALE_FLASHUPDATE_CREATEIMAGE_WARNING), box, box); if (ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, message, CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo, NEUTRINO_ICON_UPDATE) != CMessageBox::mbrYes) @@ -948,23 +949,23 @@ int CFlashExpertSetup::exec(CMenuTarget* parent, const std::string &actionKey) std::string uldrName = (std::string)UPDATEDIR + "/uldr.bin"; cfe->forceOtherFilename = true; if (g_settings.flashupdate_createimage_add_uldr == 1) - readMTDPart(2, uldrName); + readMTDPart(mtdInfo->findMTDNumberFromName("uldr"), uldrName); #ifdef UBOOT_BIN std::string ubootName = (std::string)UPDATEDIR + "/u-boot.bin"; if (g_settings.flashupdate_createimage_add_u_boot == 1) - readMTDPart(3, ubootName); + readMTDPart(mtdInfo->findMTDNumberFromName("u-boot"), ubootName); #endif #ifdef ENV_SPARE_BIN std::string envName = (std::string)UPDATEDIR + "/env.bin"; if (g_settings.flashupdate_createimage_add_env == 1) - readMTDPart(4, envName); + readMTDPart(mtdInfo->findMTDNumberFromName("env"), envName); std::string spareName = (std::string)UPDATEDIR + "/spare.bin"; - if (g_settings.flashupdate_createimage_add_spare == 1) - readMTDPart(5, spareName); + if (g_settings.flashupdate_createimage_add_spare == 1) + readMTDPart(mtdInfo->findMTDNumberFromName("spare"), spareName); #endif std::string kernelName = (std::string)UPDATEDIR + "/vmlinux.ub.gz"; if (g_settings.flashupdate_createimage_add_kernel == 1) - readMTDPart(6, kernelName); + readMTDPart(mtdInfo->findMTDNumberFromName("kernel"), kernelName); cfe->forceOtherFilename = false; cfe->otherFilename = ""; @@ -1003,8 +1004,17 @@ int CFlashExpertSetup::showMenu() CMenuForwarder *m1 = new CMenuForwarder(LOCALE_FLASHUPDATE_CREATEIMAGE, true, NULL, this, "readmtd0", CRCInput::convertDigitToKey(0)); CMenuOptionChooser *m2 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_ULDR, &g_settings.flashupdate_createimage_add_uldr, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); +#ifndef UBOOT_BIN + g_settings.flashupdate_createimage_add_u_boot = 0; +#endif +#ifdef UBOOT_BIN CMenuOptionChooser *m3 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_U_BOOT, &g_settings.flashupdate_createimage_add_u_boot, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); +#endif +#ifndef ENV_SPARE_BIN +g_settings.flashupdate_createimage_add_env = 0; +g_settings.flashupdate_createimage_add_spare = 0; +#endif #ifdef ENV_SPARE_BIN CMenuOptionChooser *m4 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_ENV, &g_settings.flashupdate_createimage_add_env, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, false); @@ -1024,7 +1034,9 @@ int CFlashExpertSetup::showMenu() rootfsSetup->addItem(m1); // create image rootfsSetup->addItem(s1); rootfsSetup->addItem(m2); // include uldr +#ifdef UBOOT_BIN rootfsSetup->addItem(m3); // include u-boot +#endif #ifdef ENV_SPARE_BIN rootfsSetup->addItem(m4); // include env rootfsSetup->addItem(m5); // include spare From 5227f726c9c4d0135b61f047bedf81cba7f60dac Mon Sep 17 00:00:00 2001 From: svenhoefer Date: Sat, 28 Sep 2013 22:25:41 +0200 Subject: [PATCH 092/200] - yweb: fix /control/reboot --- src/driver/rcinput.cpp | 4 ++++ src/nhttpd/tuxboxapi/coolstream/controlapi.cpp | 10 +++++++--- src/nhttpd/tuxboxapi/coolstream/neutrinoapi.cpp | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/driver/rcinput.cpp b/src/driver/rcinput.cpp index 916613966..f035c1881 100644 --- a/src/driver/rcinput.cpp +++ b/src/driver/rcinput.cpp @@ -805,6 +805,10 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 *msg = NeutrinoMessages::SHUTDOWN; *data = 0; break; + case NeutrinoMessages::REBOOT : + *msg = NeutrinoMessages::REBOOT; + *data = 0; + break; case NeutrinoMessages::EVT_POPUP : *msg = NeutrinoMessages::EVT_POPUP; *data = (unsigned) p; diff --git a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp index a472813ae..9bb3b9f5e 100644 --- a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp +++ b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp @@ -624,9 +624,13 @@ void CControlAPI::ShutdownCGI(CyhookHandler *hh) //----------------------------------------------------------------------------- void CControlAPI::RebootCGI(CyhookHandler *hh) { - FILE *f = fopen("/tmp/.reboot", "w"); - fclose(f); - return ShutdownCGI(hh); + if (hh->ParamList.empty()) + { + NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::REBOOT, CEventServer::INITID_HTTPD); + hh->SendOk(); + } + else + hh->SendError(); } //----------------------------------------------------------------------------- diff --git a/src/nhttpd/tuxboxapi/coolstream/neutrinoapi.cpp b/src/nhttpd/tuxboxapi/coolstream/neutrinoapi.cpp index 6ed67da7b..e81b881c4 100644 --- a/src/nhttpd/tuxboxapi/coolstream/neutrinoapi.cpp +++ b/src/nhttpd/tuxboxapi/coolstream/neutrinoapi.cpp @@ -119,6 +119,7 @@ CNeutrinoAPI::CNeutrinoAPI() EventServer = new CEventServer; EventServer->registerEvent2( NeutrinoMessages::SHUTDOWN, CEventServer::INITID_HTTPD, "/tmp/neutrino.sock"); + EventServer->registerEvent2( NeutrinoMessages::REBOOT, CEventServer::INITID_HTTPD, "/tmp/neutrino.sock"); EventServer->registerEvent2( NeutrinoMessages::STANDBY_ON, CEventServer::INITID_HTTPD, "/tmp/neutrino.sock"); EventServer->registerEvent2( NeutrinoMessages::STANDBY_OFF, CEventServer::INITID_HTTPD, "/tmp/neutrino.sock"); EventServer->registerEvent2( NeutrinoMessages::STANDBY_TOGGLE, CEventServer::INITID_HTTPD, "/tmp/neutrino.sock"); From 4cb2465665305dc225b7f17d77bc5fff0af5c447 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Sun, 29 Sep 2013 11:10:14 +0200 Subject: [PATCH 093/200] CFlashExpert: Exclude 'env' from write flash --- src/gui/update.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/update.cpp b/src/gui/update.cpp index 2cdf44c33..d6bf363ad 100644 --- a/src/gui/update.cpp +++ b/src/gui/update.cpp @@ -802,8 +802,10 @@ int CFlashExpert::showMTDSelector(const std::string & actionkey) char sActionKey[20]; bool enabled = true; #ifdef BOXMODEL_APOLLO - // disable write uboot / uldr - if ((actionkey == "writemtd") && (lx == mtdInfo->findMTDNumberFromName("u-boot") || lx == mtdInfo->findMTDNumberFromName("uldr"))) + // disable write uboot / uldr / env + if ((actionkey == "writemtd") && (lx == mtdInfo->findMTDNumberFromName("u-boot") || + lx == mtdInfo->findMTDNumberFromName("uldr") || + lx == mtdInfo->findMTDNumberFromName("env"))) enabled = false; // build jffs2 image from root0 if ((actionkey == "readmtd") && (lx == mtdInfo->findMTDNumberFromName("root0"))) { From 96fd0ef59dbab8653bb7f06002522630b095994f Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Sun, 29 Sep 2013 11:30:39 +0200 Subject: [PATCH 094/200] CFlashExpertSetup: Disable backup u-boot --- src/gui/update.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/gui/update.cpp b/src/gui/update.cpp index d6bf363ad..62f5b08d3 100644 --- a/src/gui/update.cpp +++ b/src/gui/update.cpp @@ -926,8 +926,8 @@ void CFlashExpertSetup::readMTDPart(int mtd, const std::string &fileName) sync(); } -#define UBOOT_BIN -//#define ENV_SPARE_BIN +//#define UBOOT_BIN +//#define SPARE_BIN int CFlashExpertSetup::exec(CMenuTarget* parent, const std::string &actionKey) { @@ -956,11 +956,11 @@ int CFlashExpertSetup::exec(CMenuTarget* parent, const std::string &actionKey) std::string ubootName = (std::string)UPDATEDIR + "/u-boot.bin"; if (g_settings.flashupdate_createimage_add_u_boot == 1) readMTDPart(mtdInfo->findMTDNumberFromName("u-boot"), ubootName); -#endif -#ifdef ENV_SPARE_BIN std::string envName = (std::string)UPDATEDIR + "/env.bin"; if (g_settings.flashupdate_createimage_add_env == 1) readMTDPart(mtdInfo->findMTDNumberFromName("env"), envName); +#endif +#ifdef SPARE_BIN std::string spareName = (std::string)UPDATEDIR + "/spare.bin"; if (g_settings.flashupdate_createimage_add_spare == 1) readMTDPart(mtdInfo->findMTDNumberFromName("spare"), spareName); @@ -978,10 +978,10 @@ int CFlashExpertSetup::exec(CMenuTarget* parent, const std::string &actionKey) #ifdef UBOOT_BIN if (g_settings.flashupdate_createimage_add_u_boot == 1) unlink(ubootName.c_str()); -#endif -#ifdef ENV_SPARE_BIN if (g_settings.flashupdate_createimage_add_env == 1) unlink(envName.c_str()); +#endif +#ifdef SPARE_BIN if (g_settings.flashupdate_createimage_add_spare == 1) unlink(spareName.c_str()); #endif @@ -1008,20 +1008,20 @@ int CFlashExpertSetup::showMenu() MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); #ifndef UBOOT_BIN g_settings.flashupdate_createimage_add_u_boot = 0; +g_settings.flashupdate_createimage_add_env = 0; #endif #ifdef UBOOT_BIN CMenuOptionChooser *m3 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_U_BOOT, &g_settings.flashupdate_createimage_add_u_boot, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); + CMenuOptionChooser *m4 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_ENV, &g_settings.flashupdate_createimage_add_env, + MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); #endif -#ifndef ENV_SPARE_BIN -g_settings.flashupdate_createimage_add_env = 0; +#ifndef SPARE_BIN g_settings.flashupdate_createimage_add_spare = 0; #endif -#ifdef ENV_SPARE_BIN - CMenuOptionChooser *m4 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_ENV, &g_settings.flashupdate_createimage_add_env, - MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, false); +#ifdef SPARE_BIN CMenuOptionChooser *m5 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_SPARE, &g_settings.flashupdate_createimage_add_spare, - MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, false); + MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); #endif CMenuOptionChooser *m6 = new CMenuOptionChooser(LOCALE_FLASHUPDATE_CREATEIMAGE_ADD_KERNEL, &g_settings.flashupdate_createimage_add_kernel, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); @@ -1038,9 +1038,9 @@ g_settings.flashupdate_createimage_add_spare = 0; rootfsSetup->addItem(m2); // include uldr #ifdef UBOOT_BIN rootfsSetup->addItem(m3); // include u-boot -#endif -#ifdef ENV_SPARE_BIN rootfsSetup->addItem(m4); // include env +#endif +#ifdef SPARE_BIN rootfsSetup->addItem(m5); // include spare #endif rootfsSetup->addItem(m6); // include kernel From d9ee92f83df455069178deb21bf774fc80fcfda5 Mon Sep 17 00:00:00 2001 From: svenhoefer Date: Tue, 1 Oct 2013 08:32:29 +0200 Subject: [PATCH 095/200] - yweb: add missing trinity rcu entry --- src/nhttpd/web/images/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nhttpd/web/images/Makefile.am b/src/nhttpd/web/images/Makefile.am index 0b4d21667..a2c2c2015 100644 --- a/src/nhttpd/web/images/Makefile.am +++ b/src/nhttpd/web/images/Makefile.am @@ -69,6 +69,7 @@ install_DATA = accept.png \ rc_cst_v3.jpg \ rc_cst_v4.jpg \ rc_cst_v5.jpg \ + rc_cst_v6.jpg \ rc_dbox_nokia_old.jpg \ rc_dbox_philips.jpg \ record.gif \ From 76aa02db425f5e8806d435a8bbe255c9be75b2bd Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Fri, 13 Sep 2013 20:57:43 +0200 Subject: [PATCH 096/200] CListBox: remove float type Is not really required --- src/gui/widget/listbox.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/widget/listbox.cpp b/src/gui/widget/listbox.cpp index 57d37cfee..236f4137e 100644 --- a/src/gui/widget/listbox.cpp +++ b/src/gui/widget/listbox.cpp @@ -73,10 +73,10 @@ void CListBox::paint() if (sbc < 1) sbc = 1; - float sbh= (sb- 4)/ sbc; + int sbh= (sb- 4)/ sbc; int sbs= (selected/listmaxshow); - frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ int(sbs* sbh) , 11, int(sbh), COL_MENUCONTENT_PLUS_3); + frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ sbs* sbh , 11, sbh, COL_MENUCONTENT_PLUS_3); } void CListBox::paintHead() From 633fbe43dd455d927934c9d9bffe73f947319eca Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Fri, 27 Sep 2013 23:33:07 +0200 Subject: [PATCH 097/200] CTimeOSD: use matching data type required by updatePos() --- src/gui/timeosd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/timeosd.cpp b/src/gui/timeosd.cpp index 6b0cd6488..0978e927d 100644 --- a/src/gui/timeosd.cpp +++ b/src/gui/timeosd.cpp @@ -127,7 +127,7 @@ void CTimeOSD::update(int position, int duration) if(!visible) return; - int percent = 0; + short percent = 0; if(duration > 100) percent = (unsigned char) (position / (duration / 100)); if(m_mode == CTimeOSD::MODE_ASC) From 93f177b8aaca4f9a0e30fe0deb8959e5d59db617 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sun, 29 Sep 2013 13:35:19 +0200 Subject: [PATCH 098/200] CInfoViewer: remove unused code Logo background handling can be done with CComponentsChannelLogo object soon. --- src/gui/infoviewer.cpp | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/gui/infoviewer.cpp b/src/gui/infoviewer.cpp index 4f9a740a7..e4f392773 100644 --- a/src/gui/infoviewer.cpp +++ b/src/gui/infoviewer.cpp @@ -1995,32 +1995,7 @@ int CInfoViewer::showChannelLogo(const t_channel_id logo_channel_id, const int c { res = 0; } - /* TODO: g_settings.infobar_channellogo_background*/ -#if 0 - // paint logo background (shaded/framed) - if ((g_settings.infobar_channellogo_background !=0) && (res !=0)) // with background - { - int frame_w = 2, logo_bg_x=0, logo_bg_y=0, logo_bg_w=0, logo_bg_h=0; - if (g_settings.infobar_channellogo_background == 1) // framed - { - //sh_offset = 2; - logo_bg_x = logo_x-frame_w; - logo_bg_y = logo_y-frame_w; - logo_bg_w = logo_w+frame_w*2; - logo_bg_h = logo_h+frame_w*2; - } - else if (g_settings.infobar_channellogo_background == 2) // shaded - { - //sh_offset = 3; - logo_bg_x = logo_x+SHADOW_OFFSET; - logo_bg_y = logo_y+SHADOW_OFFSET; - logo_bg_w = logo_w; - logo_bg_h = logo_h; - } - frameBuffer->paintBoxRel(logo_bg_x, logo_bg_y, logo_bg_w, logo_bg_h, COL_INFOBAR_BUTTONS_BACKGROUND); - } -#endif // paint the logo if (res != 0) { if (!g_PicViewer->DisplayImage(strAbsIconPath, logo_x, logo_y, logo_w, logo_h)) From 648218fc999ff53779e30d9d67cbd10bf3bccf8c Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sun, 29 Sep 2013 21:35:41 +0200 Subject: [PATCH 099/200] CInfoViewer: fix missing displaying content of infobar.txt Text from infobar.txt was not painted after channel switch or in virtual zap mode. Thx snafed for suggestion. TODO: many flicker effects in "virtual zap mode" --- src/gui/infoviewer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/infoviewer.cpp b/src/gui/infoviewer.cpp index e4f392773..2e6dc7856 100644 --- a/src/gui/infoviewer.cpp +++ b/src/gui/infoviewer.cpp @@ -614,7 +614,6 @@ void CInfoViewer::showTitle(CZapitChannel * channel, const bool calledFromNumZap void CInfoViewer::showTitle(t_channel_id chid, const bool calledFromNumZap, int epgpos) { - CZapitChannel * channel = CServiceManager::getInstance()->FindChannel(chid); if(channel) { @@ -856,7 +855,7 @@ void CInfoViewer::loop(bool show_dot) #endif if (msg == (neutrino_msg_t) g_settings.key_screenshot) { res = CNeutrinoApp::getInstance()->handleMsg(msg, data); - + } else if (msg == CRCInput::RC_sat || msg == CRCInput::RC_favorites) { g_RCInput->postMsg (msg, 0); res = messages_return::cancel_info; @@ -1255,6 +1254,7 @@ int CInfoViewer::handleMsg (const neutrino_msg_t msg, neutrino_msg_data_t data) } else if ((msg == NeutrinoMessages::EVT_ZAP_COMPLETE) || (msg == NeutrinoMessages::EVT_ZAP_ISNVOD)) { channel_id = (*(t_channel_id *)data); + killInfobarText(); return messages_return::handled; } else if (msg == NeutrinoMessages::EVT_ZAP_CA_ID) { //chanready = 1; @@ -1876,7 +1876,7 @@ void CInfoViewer::showInfoFile() //paint info, don't save background, if already painted, global hide is also done by killTitle() bool save_bg = !infobar_txt->isPainted(); - if (infobar_txt->textChanged()) + if (infobar_txt->textChanged() || virtual_zap_mode) infobar_txt->paint(save_bg); } From 91b8b34a519c08595dbee9f46ee6bbfa631088bf Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Sun, 29 Sep 2013 22:46:57 +0200 Subject: [PATCH 100/200] CComponentsPIP: fix x position pig_x+2 was wrong. --- src/gui/components/cc_item_tvpic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/components/cc_item_tvpic.cpp b/src/gui/components/cc_item_tvpic.cpp index e06b7fb97..ac3e94fde 100644 --- a/src/gui/components/cc_item_tvpic.cpp +++ b/src/gui/components/cc_item_tvpic.cpp @@ -89,7 +89,7 @@ void CComponentsPIP::paint(bool do_save_bg) } if(CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_tv){ - videoDecoder->Pig(pig_x+2, pig_y, pig_w, pig_h, screen_w, screen_h); + videoDecoder->Pig(pig_x, pig_y, pig_w, pig_h, screen_w, screen_h); } else{ //paint an alternate image if no tv mode available CComponentsPicture pic = CComponentsPicture (pig_x, pig_y, pig_w, pig_h, pic_name, CC_ALIGN_LEFT); From a0a370047c5a97fb7e2a8280ebb7dbd9bc7d6a01 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Sun, 22 Sep 2013 14:30:59 +0200 Subject: [PATCH 101/200] infoviewer: don't check resolution in radio mode --- src/gui/infoviewer_bb.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/infoviewer_bb.cpp b/src/gui/infoviewer_bb.cpp index 7dd0cc7e4..2604bc194 100644 --- a/src/gui/infoviewer_bb.cpp +++ b/src/gui/infoviewer_bb.cpp @@ -514,6 +514,8 @@ void CInfoViewerBB::showIcon_Resolution() { if ((!is_visible) || (g_settings.infobar_show_res == 2)) //show resolution icon is off return; + if (CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_radio) + return; const char *icon_name = NULL; #if 0 if ((scrambledNoSig) || ((!fta) && (scrambledErr))) From 878d8a55beb9b33d58893811056129896971bdbf Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Mon, 30 Sep 2013 20:48:00 +0200 Subject: [PATCH 102/200] movieplayer: fix invalid type --- src/gui/movieplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/movieplayer.cpp b/src/gui/movieplayer.cpp index 4d748ec31..e01022382 100644 --- a/src/gui/movieplayer.cpp +++ b/src/gui/movieplayer.cpp @@ -1483,7 +1483,7 @@ void CMoviePlayerGui::showSubtitle(neutrino_msg_data_t data) } //printf("title: [%s]\n", txt); std::string str(txt); - unsigned int start = 0, end = 0; + size_t start = 0, end = 0; /* split string with \N as newline */ std::string delim("\\N"); while ((end = str.find(delim, start)) != string::npos) { From f485bceff7257d758a277619bba21d413b6737aa Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Mon, 30 Sep 2013 20:50:31 +0200 Subject: [PATCH 103/200] initialize variables (mostly to silence valgrind) Signed-off-by: Thilo Graf --- lib/timerdclient/timerdclient.h | 1 + src/gui/eventlist.cpp | 3 +++ src/timerd/timerd.cpp | 2 ++ src/timerd/timermanager.cpp | 1 + 4 files changed, 7 insertions(+) diff --git a/lib/timerdclient/timerdclient.h b/lib/timerdclient/timerdclient.h index f9e66625b..07e51f863 100644 --- a/lib/timerdclient/timerdclient.h +++ b/lib/timerdclient/timerdclient.h @@ -150,6 +150,7 @@ class CTimerdClient:private CBasicClient eventInfo.epgID = epgID; eventInfo.epg_starttime = epg_starttime; eventInfo.apids = apids; + eventInfo.recordingSafety = false; return addTimerEvent(CTimerd::TIMER_ZAPTO, &eventInfo, announcetime, alarmtime, stoptime); }; diff --git a/src/gui/eventlist.cpp b/src/gui/eventlist.cpp index 6d407787a..fdee6698f 100644 --- a/src/gui/eventlist.cpp +++ b/src/gui/eventlist.cpp @@ -221,6 +221,9 @@ void CNeutrinoEventList::readEvents(const t_channel_id channel_id) evt.description = g_Locale->getText(LOCALE_EPGLIST_NOEVENTS); evt.eventID = 0; + evt.channelID = 0; + evt.startTime = 0; + evt.duration = 0; evtlist.push_back(evt); } diff --git a/src/timerd/timerd.cpp b/src/timerd/timerd.cpp index 5eb5c509e..8037b9db2 100644 --- a/src/timerd/timerd.cpp +++ b/src/timerd/timerd.cpp @@ -144,6 +144,7 @@ bool timerd_parse_command(CBasicMessage::Header &rmsg, int connfd) for(CTimerEventMap::iterator lpos = events.begin();lpos != events.end();++lpos) { CTimerd::responseGetTimer lresp; + memset(&lresp, 0, sizeof(lresp)); /* valgrind... */ CTimerEvent *event = lpos->second; @@ -253,6 +254,7 @@ bool timerd_parse_command(CBasicMessage::Header &rmsg, int connfd) CTimerdMsg::responseAddTimer rspAddTimer; CTimerEvent* event; CTimerd::TransferEventInfo evInfo; + rspAddTimer.eventID = 0; /* silence valgrind */ switch(msgAddTimer.eventType) { case CTimerd::TIMER_STANDBY : diff --git a/src/timerd/timermanager.cpp b/src/timerd/timermanager.cpp index 4ae79b00c..eec444d50 100644 --- a/src/timerd/timermanager.cpp +++ b/src/timerd/timermanager.cpp @@ -63,6 +63,7 @@ void CTimerManager::Init(void) m_isTimeSet = false; timer_is_rec = false; wakeup = 0; + shutdown_eventID = -1; loadRecordingSafety(); //thread starten From a94d9ea8f8b1a261119a8f72a1528c3ce1c53fa4 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Sat, 28 Sep 2013 13:40:41 +0200 Subject: [PATCH 104/200] hdd_menu: avoid compiler warning Signed-off-by: Thilo Graf --- src/gui/hdd_menu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/hdd_menu.cpp b/src/gui/hdd_menu.cpp index 7c32f3230..fc2e46753 100644 --- a/src/gui/hdd_menu.cpp +++ b/src/gui/hdd_menu.cpp @@ -183,7 +183,8 @@ int CHDDMenuHandler::doMenu () if (ret != -1) { if ((int)(s.st_rdev & 0x0ffc0) == root_dev) { isroot = true; - printf("-> root device is on this disk, skipping\n"); + /* dev_t is different sized on different architectures :-( */ + printf("-> root device is on this disk 0x%04x, skipping\n", (int)s.st_rdev); } } close(fd); From 9d7751dc8c6b701065bbf2e1136151cfe2341a9e Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Tue, 1 Oct 2013 17:55:18 +0200 Subject: [PATCH 105/200] CControlAPI::SendChannelList: show only unique channellist & currenttpchannels --- src/nhttpd/tuxboxapi/coolstream/controlapi.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp index 9bb3b9f5e..bfb5680b2 100644 --- a/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp +++ b/src/nhttpd/tuxboxapi/coolstream/controlapi.cpp @@ -1614,6 +1614,8 @@ void CControlAPI::SendEventList(CyhookHandler *hh, t_channel_id channel_id) void CControlAPI::SendChannelList(CyhookHandler *hh, bool currentTP) { t_channel_id current_channel = 0; + std::vector v; + if(currentTP){ current_channel = CZapit::getInstance()->GetCurrentChannelID(); current_channel=(current_channel>>16); @@ -1625,6 +1627,12 @@ void CControlAPI::SendChannelList(CyhookHandler *hh, bool currentTP) for (; !(cit.EndOfChannels()); cit++) { CZapitChannel * channel = *cit; if(!currentTP || (channel->channel_id >>16) == current_channel){ + + size_t pos = std::find(v.begin(), v.end(), channel->channel_id) - v.begin(); + if( pos < v.size() ) + continue; + v.push_back(channel->channel_id); + hh->printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS " %s\n", channel->channel_id, channel->getName().c_str()); } } From 00a194990ed42c47089f488dedd02feef1f67ddb Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Tue, 1 Oct 2013 20:35:37 +0200 Subject: [PATCH 106/200] CFlashExpert::showMTDSelector(): Fixed typo at 'disable write uboot' --- src/gui/update.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/update.cpp b/src/gui/update.cpp index 62f5b08d3..6588ba1cc 100644 --- a/src/gui/update.cpp +++ b/src/gui/update.cpp @@ -815,7 +815,7 @@ int CFlashExpert::showMTDSelector(const std::string & actionkey) } #else // disable write uboot - if ((actionkey == "writemtd") && (lx == mtdInfo->findMTDNumberFromName("u-boot"))) + if ((actionkey == "writemtd") && (lx == mtdInfo->findMTDNumberFromName("U-Boot"))) enabled = false; #endif sprintf(sActionKey, "%s%d", actionkey.c_str(), lx); From acb256ba533e2bdb81d2c0c615fe67afe6890f9f Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Wed, 2 Oct 2013 10:07:34 +0200 Subject: [PATCH 107/200] CBouquetList: use required type fix some possible compiler warnings --- src/gui/bouquetlist.cpp | 4 ++-- src/gui/bouquetlist.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/bouquetlist.cpp b/src/gui/bouquetlist.cpp index c3edab5a6..16353856a 100644 --- a/src/gui/bouquetlist.cpp +++ b/src/gui/bouquetlist.cpp @@ -118,9 +118,9 @@ void CBouquetList::deleteBouquet(CBouquet*bouquet) } } -int CBouquetList::getActiveBouquetNumber() +t_bouquet_id CBouquetList::getActiveBouquetNumber() { - return selected; + return (t_bouquet_id)selected; } #if 0 diff --git a/src/gui/bouquetlist.h b/src/gui/bouquetlist.h index bad5fd4f2..c8eb4b3ec 100644 --- a/src/gui/bouquetlist.h +++ b/src/gui/bouquetlist.h @@ -112,7 +112,7 @@ class CBouquetList CBouquet* addBouquet(const char * const name, int BouquetKey=-1, bool locked=false ); CBouquet* addBouquet(CZapitBouquet * zapitBouquet); void deleteBouquet(CBouquet* bouquet); - int getActiveBouquetNumber(); + t_bouquet_id getActiveBouquetNumber(); int activateBouquet(int id, bool bShowChannelList); int show(bool bShowChannelList = true); int showChannelList(int nBouquet = -1); From 252c1925d8cf63c826fe58ddb75c1cfdca7115f4 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Wed, 2 Oct 2013 10:10:10 +0200 Subject: [PATCH 108/200] icons.h: add larger audio icon Taken from GNU/GPL icon package "Dark Glass" by Alessandro Rei http://www.mentalrey.it/ --- data/icons/Makefile.am | 1 + data/icons/audioplay.png | Bin 0 -> 29537 bytes src/gui/widget/icons.h | 1 + 3 files changed, 2 insertions(+) create mode 100644 data/icons/audioplay.png diff --git a/data/icons/Makefile.am b/data/icons/Makefile.am index 67d8b603d..71ee57bb2 100644 --- a/data/icons/Makefile.am +++ b/data/icons/Makefile.am @@ -39,6 +39,7 @@ install_DATA += \ ats.png \ ats_gray.png \ audio.png \ + audioplay.png \ biss_green.png \ biss_white.png \ biss_yellow.png \ diff --git a/data/icons/audioplay.png b/data/icons/audioplay.png new file mode 100644 index 0000000000000000000000000000000000000000..cf19b7ea9cf177c5eb4d19de2eb11a2bc9f6c1a8 GIT binary patch literal 29537 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

H3+#V>|Y z87UDfQtltrG7P(dRK_}TyTlfh>mc~pgAL{=2#Xjse9Lu+HaZ`>BPYEp@( zwzs=IMrlSE#V?`HPfO8NWWOmb5<-}MuXB>A4dc2$s|1~wLat)`b}8&lU>&#$Tn4U{ z&rMr^$rjKZxCb}4+R|u`#yR0I(<&_{4Dg8tyRlb0iD4(cfW)_LrSunYKI@fQ!S-$! z>nw|_b3Z>f6FXh(?G-Gez>iAr<*4W-{!i+p`p?eUf3dl-#jUs9LZcRQ{@i(v96ikG zlh5&Mzwk4B^S6IbS&p5PBr(o8qA11~?F&?N?rQ_2LKhjv_?o>as?%!3{MK*&8bAMY z|CK0=$h9F&Ge%j#+R6f}tBZ_A*~II&ZXCA@;d=>n+C7}3oOL|CMKhf`-P6R;;oI(w zhQpJi!Qd);oxf?vE@y)7rA+qt=?r0?NwTN{fTm&Mi2`KV=+#05oPr9#`-4r+gkV_ z06V)o%i3rr`Ma0N9ZqrWUh@3-bYlv$E>GiNlxdtw7#YcE&|_w{@h{PNr|9=62K~Kf zzmL_KPt+>=(o@>2IQI+II@;|H&N=S5;}%{xeTF>GId;qKeE0+J=NEtGKcS1PMAyu? zO}jP5<8UfK7X?L;Bc)(EBBXs8-dqqo?u`CG#~rW2l)KwK7)1AulzJ)I7%61eiY6F_uPfGp2{`mZIIXrb61O{~O~N3{slQtE5JdwB~+f-=Vcf&A6}qbz!cMxO_k{ zyoi$Z2^4(&Ap{Qf&#fuGnUMN!yF;_p;7i{55dZxnUJ3Re+|Tmr8by}!$R|F=XFmCH z_N}h6xV%EW(PVpLot^DXu3f!Co)-ue;It*nat3L}DA%NE&ckoHi}|@3y8YqA?3b9r zI0X!Jx_x$cyFT#~gyWkuLH%ArPo?UXmZjTXZ+2tJD3=D;r<_nCt)!>!vl^Cx-gN6oX=R-vO>Y|Jc78 z>^%SP)}Nl?IzMucU?qlwiAG6#!!2TbD4r2Q{j{@uzm#z0@->bgJHo>czlo20^wXR_ zdx37d!`#9=%PVVGW9avXw0BRDWvR~=S_?uU738_^{5eW9hG{{+Kjf_s-p>BjWjejd zRFx`x^Q+%qNKt6EcRHk*pL8z95z^FxnEH3J4M?mp?e6aOBU4vqnPl?%_?5mhCH!6d z-afic_^FE z7rVD>dAB!Ux6|_s<#LE~DdRnYpSoe*2XHQJZ*ToxQ52n09+fGtLb+`aG#mDP|!QfNcFJ0xngIC}e?A4s}$ z-!E-w{PtFVg|FlY!hrtJqB8wzt}{aLLKH?nnn?9ey@zi(`{H?y9zD!^|M!gh9dK9*(am2y=~6F91sU!iyvlGkVN%6~(Lhk~{2 z9=`MNFJ8TR?MIw(FN0i(>ooZ~@3sWDrI2W2+35@rVaSQQ?|bCP@nhe$@kD#z#LZYK z%f171G*%L{z8T9V=#u^$W$WJ{g?pQCWT83x;yLyoSmmqV`yL*D;u)TP_B5MYJ48|B z%d;tmO=!(%lrbt>(H=Rp%EJ%cM-YazJN-Qk8^^W&RkVZeOuoI-VYl5ys9@Z(W)E<3 z{e1$2lJvWsPY?V3lXyp{0(OQ>P`#Z}@H==*FkrIhzoC`CM*;4B?g+E(=1;sZf8j4| z?_68-Jl?%GdGB!p*I#&=bFK|Ly8}>?BX`~V_>m*GeiPPizM3hYK0+k12~b+|GM>Vo z@8TdWjQ)Rywdf-P8&>tymoHzX-yd?{y?1cu9VdA5>64tlaGBkmF1^99==VqT``z*TTRUm;;HrU8<@I#C1FmlDkQbJ?Uh}WtbFEW2e?{~N6xne2 zbg$F-O!=Y;!K)zM-BRc~O!oWfSpE&K{5=ZL_{E4@8*Aqd-hInI=ncF7wipe4kDZr= zqNg=`V&(>EPP;oqMG435d*BlXj~)M3>&zwRURwc@bb=rUr(aF@)pvjb{mG%^pVpJ` z?^+8&dJnAA>Co@>n46#F{`>CYO%L3|XgH!b7~sd+l<8_I8ICd!Qyb$kedjBS%IV`T zu|=aaj@vFWv`BkX* z1rz>Q0UrCdHdZ-W`w#rP)u;1&uRikZ_vvErk{9(Re+n*oEu$zNlUX=IvgN!{`Vtp^}%K>{%UJ20*Mm7Yv=a% zF1x!OKZZ6*2ttK1mNfUByL4I9SzVsB*5h~6jGgMUoNxKIzOlphP6sIiRG=mmKTw9L zg{za2fg|7Q!U#_{oM zJ`}z{;${rMoH|*8X#I zZt*9RrD(Ira@>u}>Tl|B1BVM}uSI z*_Du|#g0e3RXSps)cZTDUS~8;7@3@q1OPP$haQkN?7z4F-dhAP6UW{uJFuDnIPX z!6+S#KG*N;eyk{p%S?!wmB4S5s;xZyKd@E*iV9F2)*7&8cVXYkf5^4|56cHvXOo$^ zeR;o72Tv@I^v>pbdq{fXzyhCr{@N=}%zn*BMRa~0hZMeh*yYO`pLpc6+h6;Z2k-sm zdcAhY@6WQNs!s?U)lzq5NH_7;Cu8csv!u4R+g!Z7!C>Ueye3en_k~oT%I6u32K`U< zy4{Z#d3K&jYPMSS(`LT%?5jQg4_xTe$E&*M)|jf^uA`LdNa-6QIw{aaPNBab;pi9s z!h(Qyd-pTXoI3MWx1KoqADi{sLxB*OF-M_X^TLf)!1wK$s@N$-QE1K9PMZstHyEWw zS$yhBW%GRrkTSQ{o*NGOpY3KnyKL`veSt|BR0A0bhkem# z`*^QA_-v79Ph@F&);YJuBo#Yt&i_arU!XQ|e{>Jw=L+|-LjNz%ojUuwGc%39x4by_ zrOjqd1X7L399531>ij)Qb2hfN+1P56=Y}wfbW)4XI>BeMZ1icJ6_1XFgBPr|JNyw? z$*=eLA6@~R^V7U~yFJ?N&VRpr`SM53*Xv(8KR5TSb92qFiK1{d3!mqM&cDOQ9E_J={()z&;IWN^|NebGoYbk;KHw7=Mw@&|JK-v?%yw}UJ1 Qpa1{>07*qoM6N<$f*%pe8vp Date: Wed, 2 Oct 2013 09:31:23 +0200 Subject: [PATCH 109/200] CComponentsPIP: centering alternate backkground image --- src/gui/components/cc_item_tvpic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/components/cc_item_tvpic.cpp b/src/gui/components/cc_item_tvpic.cpp index ac3e94fde..9dc397c48 100644 --- a/src/gui/components/cc_item_tvpic.cpp +++ b/src/gui/components/cc_item_tvpic.cpp @@ -92,7 +92,7 @@ void CComponentsPIP::paint(bool do_save_bg) videoDecoder->Pig(pig_x, pig_y, pig_w, pig_h, screen_w, screen_h); } else{ //paint an alternate image if no tv mode available - CComponentsPicture pic = CComponentsPicture (pig_x, pig_y, pig_w, pig_h, pic_name, CC_ALIGN_LEFT); + CComponentsPicture pic = CComponentsPicture (pig_x, pig_y, pig_w, pig_h, pic_name, CC_ALIGN_HOR_CENTER | CC_ALIGN_VER_CENTER); pic.paint(CC_SAVE_SCREEN_NO); } From 30c7010c6bbd0996717e637549e2bf7e2e1f4408 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Wed, 2 Oct 2013 09:41:41 +0200 Subject: [PATCH 110/200] CChannelList: use CComponentsPIP object for minitv It's working with unified other implementations of minitv e.g. imageinfo, streaminfo and can provide better options for an implementation with native pip. Possible variants will follow soon. --- src/gui/channellist.cpp | 43 +++++++++++++++++------------------------ src/gui/channellist.h | 4 +++- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/gui/channellist.cpp b/src/gui/channellist.cpp index ae7d80086..f8c57ce4e 100644 --- a/src/gui/channellist.cpp +++ b/src/gui/channellist.cpp @@ -74,8 +74,6 @@ #include -#include - extern CBouquetList * bouquetList; /* neutrino.cpp */ extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */ extern CPictureViewer * g_PicViewer; @@ -94,7 +92,6 @@ extern bool autoshift; extern CBouquetManager *g_bouquetManager; extern int old_b_id; -extern cVideo * videoDecoder; static CComponentsFrmClock *headerClock = NULL; static int headerClockWidth = 0; @@ -122,6 +119,7 @@ CChannelList::CChannelList(const char * const pName, bool phistoryMode, bool _vl previous_channellist_additional = -1; eventFont = SNeutrinoSettings::FONT_TYPE_CHANNELLIST_EVENT; dline = NULL; + cc_minitv = NULL; logo_off = 0; //printf("************ NEW LIST %s : %x\n", name.c_str(), (int) this);fflush(stdout); } @@ -131,6 +129,8 @@ CChannelList::~CChannelList() //printf("************ DELETE LIST %s : %x\n", name.c_str(), this);fflush(stdout); chanlist.clear(); delete dline; + if (cc_minitv) + delete cc_minitv; if (headerClock) { headerClock->Stop(); if (headerClock->isPainted()) @@ -1007,7 +1007,9 @@ void CChannelList::hide() { if ((g_settings.channellist_additional == 2) || (previous_channellist_additional == 2)) // with miniTV { - videoDecoder->Pig(-1, -1, -1, -1); + if (cc_minitv) + delete cc_minitv; + cc_minitv = NULL; } if (headerClock) { headerClock->Stop(); @@ -2149,23 +2151,7 @@ void CChannelList::paint() updateEvents(this->historyMode ? 0:liststart, this->historyMode ? 0:(liststart + listmaxshow)); if (g_settings.channellist_additional == 2) // with miniTV - { - // paint box for miniTV again - important! - frameBuffer->paintBoxFrame(x+width, y+theight , pig_width, pig_height, 10, COL_MENUCONTENT_PLUS_0, 0); - // 5px offset - same value as in list below -#if 0 - /* focus: its possible now to scale video with still image, but on nevis - artifacts possible on SD osd */ - paint_pig(x+width+5, y+theight+5, pig_width-10, pig_height-10); -#else - if(CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_tv) { - paint_pig(x+width+5, y+theight+5, pig_width-10, pig_height-10); - } - else if(CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_radio) { - g_PicViewer->DisplayImage(DATADIR "/neutrino/icons/radiomode.jpg", x+width+5, y+theight+5, pig_width-10, pig_height-10, frameBuffer->TM_NONE); - } -#endif - } + paintPig(x+width, y+theight, pig_width, pig_height); // paint background for main box frameBuffer->paintBoxRel(x, y+theight, width, height-footerHeight-theight, COL_MENUCONTENT_PLUS_0); @@ -2258,11 +2244,18 @@ std::string CChannelList::MaxChanNr() return maxchansize; } -void CChannelList::paint_pig (int _x, int _y, int w, int h) +void CChannelList::paintPig (int _x, int _y, int w, int h) { - frameBuffer->paintBackgroundBoxRel (_x, _y, w, h); - //printf("CChannelList::paint_pig x %d y %d w %d h %d osd_w %d osd_w %d\n", _x, _y, w, h, frameBuffer->getScreenWidth(true), frameBuffer->getScreenHeight(true)); - videoDecoder->Pig(_x, _y, w, h, frameBuffer->getScreenWidth(true), frameBuffer->getScreenHeight(true)); + //init minitv object with basic properties + if (cc_minitv == NULL){ + cc_minitv = new CComponentsPIP (0, 0); + cc_minitv->setPicture(NEUTRINO_ICON_AUDIOPLAY); + cc_minitv->setFrameThickness(5); + } + //set changeable minitv properties + cc_minitv->setDimensionsAll(_x, _y, w, h); + cc_minitv->setColorFrame(COL_MENUCONTENT_PLUS_0); + cc_minitv->paint(false); } void CChannelList::paint_events(int index) diff --git a/src/gui/channellist.h b/src/gui/channellist.h index ce34914d1..d52e14ebd 100644 --- a/src/gui/channellist.h +++ b/src/gui/channellist.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,7 @@ class CChannelList { private: CFrameBuffer *frameBuffer; + CComponentsPIP *cc_minitv; unsigned int selected, selected_in_new_mode; unsigned int tuned; t_channel_id selected_chid; @@ -113,7 +115,7 @@ private: void showChannelLogo(); void calcSize(); std::string MaxChanNr(); - void paint_pig(int x, int y, int w, int h); + void paintPig(int x, int y, int w, int h); void paint_events(int index); CChannelEventList evtlist; void readEvents(const t_channel_id channel_id); From 3ccd5cca68698af24768a82b0306004f9864da27 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Wed, 2 Oct 2013 15:29:38 +0400 Subject: [PATCH 111/200] driver/scanepg.cpp: add support to scan all favorites --- src/driver/scanepg.cpp | 47 ++++++++++++++++++++++++++++++------------ src/driver/scanepg.h | 1 + 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/driver/scanepg.cpp b/src/driver/scanepg.cpp index b0e2075d5..e7a47f985 100644 --- a/src/driver/scanepg.cpp +++ b/src/driver/scanepg.cpp @@ -37,12 +37,14 @@ #include -extern CBouquetList * bouquetList; - +extern CBouquetList * bouquetList; +extern CBouquetList * TVfavList; + CEpgScan::CEpgScan() { current_bnum = -1; next_chid = 0; + current_mode = 0; } CEpgScan::~CEpgScan() @@ -74,18 +76,37 @@ void CEpgScan::handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t data) if(bouquetList->Bouquets.empty()) return; - if (current_bnum != bouquetList->getActiveBouquetNumber()) { - scanmap.clear(); - current_bnum = bouquetList->getActiveBouquetNumber(); - CChannelList * clist = bouquetList->Bouquets[current_bnum]->channelList; - int lsize = clist->Size(); - for (int i = 0; i < lsize; i++) { - CZapitChannel * chan = clist->getChannelFromIndex(i); - /* TODO: add interval check to clear scanned ? */ - if (scanned.find(chan->getTransponderId()) == scanned.end()) - scanmap.insert(eit_scanmap_pair_t(chan->getTransponderId(), chan->getChannelID())); + if (current_mode != g_settings.epg_scan) { + current_mode = g_settings.epg_scan; + Clear(); + } + if (g_settings.epg_scan == 1) { + /* current bouquet mode */ + if (current_bnum != bouquetList->getActiveBouquetNumber()) { + scanmap.clear(); + current_bnum = bouquetList->getActiveBouquetNumber(); + CChannelList * clist = bouquetList->Bouquets[current_bnum]->channelList; + for (unsigned i = 0; i < clist->Size(); i++) { + CZapitChannel * chan = clist->getChannelFromIndex(i); + /* TODO: add interval check to clear scanned ? */ + if (scanned.find(chan->getTransponderId()) == scanned.end()) + scanmap.insert(eit_scanmap_pair_t(chan->getTransponderId(), chan->getChannelID())); + } + INFO("EVT_ZAP_COMPLETE, scan map size: %d\n", scanmap.size()); + } + } else { + /* all favorites mode */ + if (scanmap.empty()) { + for (unsigned j = 0; j < TVfavList->Bouquets.size(); ++j) { + CChannelList * clist = TVfavList->Bouquets[j]->channelList; + for (unsigned i = 0; i < clist->Size(); i++) { + CZapitChannel * chan = clist->getChannelFromIndex(i); + if (scanned.find(chan->getTransponderId()) == scanned.end()) + scanmap.insert(eit_scanmap_pair_t(chan->getTransponderId(), chan->getChannelID())); + } + } + INFO("EVT_ZAP_COMPLETE, scan map size: %d\n", scanmap.size()); } - INFO("EVT_ZAP_COMPLETE, scan map size: %d\n", scanmap.size()); } } else if (msg == NeutrinoMessages::EVT_EIT_COMPLETE) { diff --git a/src/driver/scanepg.h b/src/driver/scanepg.h index bdd9f5c32..366b40a38 100644 --- a/src/driver/scanepg.h +++ b/src/driver/scanepg.h @@ -30,6 +30,7 @@ class CEpgScan { private: int current_bnum; + int current_mode; eit_scanmap_t scanmap; t_channel_id next_chid; std::set scanned; From da0bfde71558f17b9a7463df114cd8297b75d305 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Wed, 2 Oct 2013 15:30:10 +0400 Subject: [PATCH 112/200] locals: add locale for epg scan mode --- data/locale/english.locale | 4 +++- src/system/locals.h | 2 ++ src/system/locals_intern.h | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/data/locale/english.locale b/data/locale/english.locale index c37e7fbd6..2e69ef2ed 100644 --- a/data/locale/english.locale +++ b/data/locale/english.locale @@ -812,7 +812,7 @@ menu.hint_epg_max_events Maximum events to cache. After reaching limit\nEPG cach menu.hint_epg_old_events Hours after event end time to consider\nevent old and remove it from cache menu.hint_epg_save Save cached EPG to harddisk or usb flash\nand load it after boot menu.hint_epg_save_standby Save EPG on soft standby mode -menu.hint_epg_scan Enable background epg scan using free tuner +menu.hint_epg_scan Enable background epg scan using free tuner,\ncurrent bouquet or all favorites menu.hint_event_textcolor Change event color for colored-event options\nin channel list and infobar menu.hint_eventlist_additional Show additional informations\nin main box menu.hint_eventlist_fonts Change event list font sizes @@ -1197,6 +1197,8 @@ miscsettings.epg_old_events_hint2 Set in hours miscsettings.epg_save Save/Restore epg on reboot miscsettings.epg_save_standby Save epg on soft standby miscsettings.epg_scan EPG scan +miscsettings.epg_scan_bq bouquet +miscsettings.epg_scan_fav favorites miscsettings.general General miscsettings.head Extended settings miscsettings.infobar Infobar diff --git a/src/system/locals.h b/src/system/locals.h index b3b170ffa..0d620f257 100644 --- a/src/system/locals.h +++ b/src/system/locals.h @@ -1224,6 +1224,8 @@ typedef enum LOCALE_MISCSETTINGS_EPG_SAVE, LOCALE_MISCSETTINGS_EPG_SAVE_STANDBY, LOCALE_MISCSETTINGS_EPG_SCAN, + LOCALE_MISCSETTINGS_EPG_SCAN_BQ, + LOCALE_MISCSETTINGS_EPG_SCAN_FAV, LOCALE_MISCSETTINGS_GENERAL, LOCALE_MISCSETTINGS_HEAD, LOCALE_MISCSETTINGS_INFOBAR, diff --git a/src/system/locals_intern.h b/src/system/locals_intern.h index 86e59c778..ba691ea73 100644 --- a/src/system/locals_intern.h +++ b/src/system/locals_intern.h @@ -1224,6 +1224,8 @@ const char * locale_real_names[] = "miscsettings.epg_save", "miscsettings.epg_save_standby", "miscsettings.epg_scan", + "miscsettings.epg_scan_bq", + "miscsettings.epg_scan_fav", "miscsettings.general", "miscsettings.head", "miscsettings.infobar", From 41f6e03e3e9e2243663b15434cc2de68c2df9b4c Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Wed, 2 Oct 2013 15:30:22 +0400 Subject: [PATCH 113/200] gui/miscsettings_menu.cpp: add epg scan modes --- src/gui/miscsettings_menu.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gui/miscsettings_menu.cpp b/src/gui/miscsettings_menu.cpp index 84b59ffa4..923c82844 100644 --- a/src/gui/miscsettings_menu.cpp +++ b/src/gui/miscsettings_menu.cpp @@ -173,6 +173,14 @@ const CMenuOptionChooser::keyval_ext CPU_FREQ_OPTIONS[CPU_FREQ_OPTION_COUNT] = }; #endif /*CPU_FREQ*/ +#define EPG_SCAN_OPTION_COUNT 3 +const CMenuOptionChooser::keyval EPG_SCAN_OPTIONS[EPG_SCAN_OPTION_COUNT] = +{ + { 0, LOCALE_OPTIONS_OFF }, + { 1, LOCALE_MISCSETTINGS_EPG_SCAN_BQ }, + { 2, LOCALE_MISCSETTINGS_EPG_SCAN_FAV }, +}; + //show misc settings menue int CMiscMenue::showMiscSettingsMenu() { @@ -356,7 +364,7 @@ void CMiscMenue::showMiscSettingsMenuEpg(CMenuWidget *ms_epg) CMenuOptionChooser * mc = new CMenuOptionChooser(LOCALE_MISCSETTINGS_EPG_SAVE, &g_settings.epg_save, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true,miscEpgNotifier); mc->setHint("", LOCALE_MENU_HINT_EPG_SAVE); - CMenuOptionChooser * mc2 = new CMenuOptionChooser(LOCALE_MISCSETTINGS_EPG_SCAN, &g_settings.epg_scan, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, + CMenuOptionChooser * mc2 = new CMenuOptionChooser(LOCALE_MISCSETTINGS_EPG_SCAN, &g_settings.epg_scan, EPG_SCAN_OPTIONS, EPG_SCAN_OPTION_COUNT, CFEManager::getInstance()->getEnabledCount() > 1); mc2->setHint("", LOCALE_MENU_HINT_EPG_SCAN); From aff6f77cef93680021e38b8d331726de9cc112a8 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Wed, 2 Oct 2013 18:35:11 +0400 Subject: [PATCH 114/200] neutrino.cpp: fix epg_scan option saving --- src/neutrino.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neutrino.cpp b/src/neutrino.cpp index dfd8a9cb7..92713ad75 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -445,7 +445,7 @@ int CNeutrinoApp::loadSetup(const char * fname) g_settings.epg_save = configfile.getBool("epg_save", false); g_settings.epg_save_standby = configfile.getBool("epg_save_standby", true); - g_settings.epg_scan = configfile.getBool("epg_scan", false); + g_settings.epg_scan = configfile.getInt32("epg_scan", 0); //widget settings g_settings.widget_fade = false; g_settings.widget_fade = configfile.getBool("widget_fade" , false ); @@ -920,7 +920,7 @@ void CNeutrinoApp::saveSetup(const char * fname) // epg configfile.setBool("epg_save", g_settings.epg_save); configfile.setBool("epg_save_standby", g_settings.epg_save_standby); - configfile.setBool("epg_scan", g_settings.epg_scan); + configfile.setInt32("epg_scan", g_settings.epg_scan); configfile.setString("epg_cache_time" ,g_settings.epg_cache ); configfile.setString("epg_extendedcache_time" ,g_settings.epg_extendedcache); configfile.setString("epg_old_events" ,g_settings.epg_old_events ); From f41cb76e016f132c94deff073917ed4c3f552fad Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Wed, 2 Oct 2013 17:48:41 +0200 Subject: [PATCH 115/200] libfec.cpp: -fix compil with DEBUG --- src/system/mtdutils/lib/libfec.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/system/mtdutils/lib/libfec.cpp b/src/system/mtdutils/lib/libfec.cpp index 4a250047c..801477b1a 100644 --- a/src/system/mtdutils/lib/libfec.cpp +++ b/src/system/mtdutils/lib/libfec.cpp @@ -379,7 +379,8 @@ matmul(gf *a, gf *b, gf *c, int n, int k, int m) } } } - +#if 0 +//unused #ifdef DEBUG /* * returns 1 if the square matrix is identiy @@ -399,7 +400,7 @@ is_identity(gf *m, int k) return 1 ; } #endif /* debug */ - +#endif /* * invert_mat() takes a matrix and produces its inverse * k is the size of the matrix. From 6321bd181012adcd646bd6672e4fbf099453c2c9 Mon Sep 17 00:00:00 2001 From: Jacek Jendrzej Date: Wed, 2 Oct 2013 17:50:49 +0200 Subject: [PATCH 116/200] eitd: -fix wakeup epg scan with max_events==0 --- src/eitd/sectionsd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eitd/sectionsd.cpp b/src/eitd/sectionsd.cpp index 8e0914fe9..5515c0c0b 100644 --- a/src/eitd/sectionsd.cpp +++ b/src/eitd/sectionsd.cpp @@ -903,7 +903,7 @@ static void commandserviceChanged(int connfd, char *data, const unsigned dataLen /* assume live demux always 0, other means background scan */ if (cmd->dnum) { /* dont wakeup EIT, if we have max events allready */ - if (max_events && (mySIeventsOrderUniqueKey.size() < max_events)) { + if (max_events == 0 || (mySIeventsOrderUniqueKey.size() < max_events)) { threadEIT.setDemux(cmd->dnum); threadEIT.setCurrentService(uniqueServiceKey); } From 41d50d793f8cb57f27c681d361fa5f97a105ce10 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Tue, 30 Jul 2013 10:46:50 +0200 Subject: [PATCH 117/200] nederlands.locale: Fix sort order --- data/locale/nederlands.locale | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/data/locale/nederlands.locale b/data/locale/nederlands.locale index 6f90a4ca9..4814996a1 100644 --- a/data/locale/nederlands.locale +++ b/data/locale/nederlands.locale @@ -240,8 +240,8 @@ channellist.sats Satellieten channellist.since sinds channellist.start start tijd ci.clock CI kloksnelheid (Mhz) -ci.ignore_msg Negeer CA berichten ci.empty Geen CAM geplaatst +ci.ignore_msg Negeer CA berichten ci.init_failed Initialisatie CAM mislukt ci.init_ok Initialisatie CAM compleet ci.inserted Conditional access module herkend @@ -674,7 +674,6 @@ languagesetup.select OSD taal lcd_info_line Weergave in display lcd_info_line_channel kanaalnaam lcd_info_line_clock klok -reset_removed Gewiste kanalen definitief verwijderen lcdcontroler.brightness Normale helderheid lcdcontroler.brightnessdeepstandby Deep Standby helderheid lcdcontroler.brightnessstandby Standby Helderheid @@ -733,7 +732,6 @@ mainsettings.timezone Tijdzone mainsettings.video Video menu.back Terug menu.cancel Annuleer -menu.hint_ytplay Video's afspelen van de populaire video website Youtube menu.hint_a_pic Configureer audiospeler en afbeeldingen menu.hint_aplay Audiospeler menu.hint_audio Audio output, DD\nSRS True volume opties @@ -1105,6 +1103,7 @@ menu.hint_video_modes VF toets schakelt tussen de ingeschakelde opties menu.hint_video_scart_mode Selecteer analog output modus voor SCART aansluiting(en) menu.hint_volume_digits Numerieke weergave van de volume balk aan/uit menu.hint_volume_pos Selecteer positie volume indicator +menu.hint_ytplay Video's afspelen van de populaire video website Youtube menu.hint_zap_cycle Tijdens het schakelen tussen kanalen in huidige favorieten lijst menu.next Volgende (Druk op menu om af te sluiten) messagebox.back Terug @@ -1240,7 +1239,10 @@ moviebrowser.edit_book_type_info2 <0 terug , >0 voor, 0: geen moviebrowser.edit_serie Geef de naam van de serie op moviebrowser.error_no_movies geen films gevonden moviebrowser.foot_filter Filter: +moviebrowser.foot_focus Schakel venster +moviebrowser.foot_options Opties moviebrowser.foot_play Start film +moviebrowser.foot_refresh Lijst herladen moviebrowser.foot_sort Sorteer: moviebrowser.head Opnames afspelen moviebrowser.head_filter Filter flims per categorie: @@ -1330,8 +1332,6 @@ moviebrowser.update_if_dest_empty_only Kopieer indien doelbestemming leeg is moviebrowser.use_dir Gebruik directory moviebrowser.use_movie_dir Gebruik film directory moviebrowser.use_rec_dir Gebruik opname directory -moviebrowser.foot_focus Schakel venster -moviebrowser.foot_refresh Lijst herladen moviebrowser.yt_error Laden van youtube video mislukt moviebrowser.yt_max_results Maximaal aantal resultaten moviebrowser.yt_most_discussed Meest besproken @@ -1348,7 +1348,6 @@ moviebrowser.yt_related Gerelateerde video's moviebrowser.yt_search Trefwoord moviebrowser.yt_top_favorites Top favorieten moviebrowser.yt_top_rated Meest gewaardeerd -moviebrowser.foot_options Opties movieplayer.bookmark Markeerpunten movieplayer.bookmarkname Naam markeerpunt movieplayer.bookmarkname_hint1 Naam invoeren voor uw markeerpunt @@ -1448,12 +1447,12 @@ options.off Uit options.on Aan options.on.without_messages Zonder bericht options.serial serial -parentallock.changepin verander PIN code parentallock.bouquetmode Favorieten lijsten zijn standaard: -parentallock.defaultlocked Beveiligd met een PIN code -parentallock.defaultunlocked Onbeveiligd +parentallock.changepin verander PIN code parentallock.changepin_hint1 Geef de nieuwe jeugd-bescherm pin code hier in! parentallock.changetolocked bij vergrendelde zenderlijsten +parentallock.defaultlocked Beveiligd met een PIN code +parentallock.defaultunlocked Onbeveiligd parentallock.head Geef Lock PIN code in parentallock.lockage vergrendelde programma's parentallock.lockage12 tot aan 12 jaar @@ -1583,6 +1582,7 @@ repeatblocker.hint_2 Enter 0 to switch of the blocker (red is space) reset_all Fabrieksreset en herstart reset_channels Wis alle kanalen reset_confirm Weet u het zeker? +reset_removed Gewiste kanalen definitief verwijderen reset_settings Standaard instellingen herstellen satsetup.auto_scan Auto-Scan geselecteerd %s satsetup.auto_scan_all Auto-Scan meerdere satellieten @@ -1609,24 +1609,18 @@ satsetup.fastscan_prov_telesat TéléSAT satsetup.fastscan_prov_tvv TV Vlaanderen satsetup.fastscan_sd Enkel SD satsetup.fastscan_type Scantype +satsetup.fe_mode Tuner mode satsetup.fe_mode Tuner modus satsetup.fe_mode_alone Onafhankelijk - - -satsetup.fe_mode Tuner mode satsetup.fe_mode_independent Onafhankelijk satsetup.fe_mode_link_loop Doorgelust satsetup.fe_mode_link_twin Twin -satsetup.fe_mode_master Master -satsetup.fe_mode_unused Ongebruikt - - satsetup.fe_mode_loop Doorgelust +satsetup.fe_mode_master Master satsetup.fe_mode_single Single satsetup.fe_mode_twin Twin +satsetup.fe_mode_unused Ongebruikt satsetup.fe_setup Tuner instellen - - satsetup.lofh LNB High Offset satsetup.lofl LNB Low Offset satsetup.lofs LNB switch Offset From 117b7bae3c9047e9068c809a67034c0b9ed1d370 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Wed, 2 Oct 2013 18:32:31 +0200 Subject: [PATCH 118/200] Update deutsch.locale --- data/locale/deutsch.locale | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data/locale/deutsch.locale b/data/locale/deutsch.locale index 6c83a557c..18188d358 100644 --- a/data/locale/deutsch.locale +++ b/data/locale/deutsch.locale @@ -812,7 +812,7 @@ menu.hint_epg_max_events Maxiale Anzahl der Events im Zwischenspeicher menu.hint_epg_old_events Veraltete EPG-Daten werden nach dieser Zeit (in Stunden) verworfen menu.hint_epg_save Speichert die EPG-Daten auf einem externen Datenträger und läd es von dort nach einen Neustart menu.hint_epg_save_standby Speichert die EPG-Daten auch im Standby-Modus -menu.hint_epg_scan Aktivieren Sie den Hintergrundscan der EPG-Daten, wenn ein freier Tuner vorhanden ist +menu.hint_epg_scan Aktivieren Sie den Hintergrundscan der EPG-Daten, wenn ein freier Tuner vorhanden ist, im aktuellen Bouquet oder in allen Favoriten menu.hint_event_textcolor Ändern Sie die Farbe für farbige Events in der Kanalliste und der Infobar menu.hint_eventlist_additional Definiert, ob zusätzliche Informationen im Hauptfenster angezeigt werden sollen menu.hint_eventlist_fonts Ändern Sie die Schriftgröße in der Event-Liste @@ -1197,6 +1197,8 @@ miscsettings.epg_old_events_hint2 Angabe in Stunden miscsettings.epg_save EPG zwischenspeichern miscsettings.epg_save_standby EPG speichern in Standby-Modus miscsettings.epg_scan Hintergrundscan EPG +miscsettings.epg_scan_bq Aktuelles Bouquet +miscsettings.epg_scan_fav Alle Favoriten miscsettings.general Allgemein miscsettings.head Erweitert miscsettings.infobar Infobar From ab1c33f02422cb2f4e627f999e38dbf7809ae684 Mon Sep 17 00:00:00 2001 From: defans Date: Thu, 3 Oct 2013 16:50:21 +0200 Subject: [PATCH 119/200] Fix infoviewer global font zoom faktor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the zoom factor made ​​time display broken, left side --- src/gui/infoviewer.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/infoviewer.cpp b/src/gui/infoviewer.cpp index 2e6dc7856..f0f91474c 100644 --- a/src/gui/infoviewer.cpp +++ b/src/gui/infoviewer.cpp @@ -150,9 +150,6 @@ void CInfoViewer::Init() casysChange = g_settings.casystem_display; channellogoChange = g_settings.infobar_show_channellogo; - /* we need to calculate this only once */ - info_time_width = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getRenderWidth("22:22") + 10; - channel_id = CZapit::getInstance()->GetCurrentChannelID();; lcdUpdateTimer = 0; rt_x = rt_y = rt_h = rt_w = 0; @@ -186,6 +183,8 @@ void CInfoViewer::Init() */ void CInfoViewer::start () { + info_time_width = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getRenderWidth("22:22") + 10; + InfoHeightY = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->getHeight() * 9/8 + 2 * g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getHeight() + 25; infoViewerBB->Init(); From 4ab9dd6cb21bf7b600c3254498191addabceee9e Mon Sep 17 00:00:00 2001 From: svenhoefer Date: Fri, 4 Oct 2013 09:14:48 +0200 Subject: [PATCH 120/200] - add rcsim sources from martiis-neutrino-mp --- src/create_rcsim_h.sh | 57 ++++++++++ src/rcsim.c | 249 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100755 src/create_rcsim_h.sh create mode 100644 src/rcsim.c diff --git a/src/create_rcsim_h.sh b/src/create_rcsim_h.sh new file mode 100755 index 000000000..e82319a61 --- /dev/null +++ b/src/create_rcsim_h.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# +# create a rcsim.h file from the rcinput header +# (C) 2011 Stefan Seyfried +# License: GPL v2 +# +# usage: sh ./create_rcsim_h.sh > rcsim.h + +cat << EOF +#ifndef KEY_GAMES +#define KEY_GAMES 0x1a1 /* Media Select Games */ +#endif + +#ifndef KEY_TOPLEFT +#define KEY_TOPLEFT 0x1a2 +#endif + +#ifndef KEY_TOPRIGHT +#define KEY_TOPRIGHT 0x1a3 +#endif + +#ifndef KEY_BOTTOMLEFT +#define KEY_BOTTOMLEFT 0x1a4 +#endif + +#ifndef KEY_BOTTOMRIGHT +#define KEY_BOTTOMRIGHT 0x1a5 +#endif + +#define KEY_POWERON KEY_FN_F1 +#define KEY_POWEROFF KEY_FN_F2 +#define KEY_STANDBYON KEY_FN_F3 +#define KEY_STANDBYOFF KEY_FN_F4 +#define KEY_MUTEON KEY_FN_F5 +#define KEY_MUTEOFF KEY_FN_F6 +#define KEY_ANALOGON KEY_FN_F7 +#define KEY_ANALOGOFF KEY_FN_F8 + +enum { +EOF +sed -n '/^[[:space:]]*RC_0/,/^[[:space:]]*RC_analog_off/s/^[[:space:]]*/ /p' driver/rcinput.h +cat << EOF +}; + +struct key{ + char *name; + unsigned long code; +}; + +static const struct key keyname[] = { +EOF +sed -n '/^[[:space:]]*RC_0/,/^[[:space:]]*RC_analog_off/ s/^.*=[[:space:]]*\(KEY_.*\),.*/ { "\1", \1 },/p' driver/rcinput.h +cat << EOF +}; + +EOF + diff --git a/src/rcsim.c b/src/rcsim.c new file mode 100644 index 000000000..7cce83e39 --- /dev/null +++ b/src/rcsim.c @@ -0,0 +1,249 @@ +/****************************************************************************** + * rcsim - rcsim.c + * + * simulates the remote control, sends the requested key + * + * (c) 2003 Carsten Juttner (carjay@gmx.net) + * (c) 2009 Stefan Seyfried, add code to use the neutrino socket instead + * of the input subsystem for dreambox / tripledragon + * (c) 2011 Stefan Seyfried, convert driver/rcinput.h via script to + * rcsim.h for automated import of new keys + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * The Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA. + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* if you want use HAVE_XX_HARDWARE, better include config.h :-) */ +#include "config.h" + +#ifdef HAVE_DBOX_HARDWARE +#define EVENTDEV "/dev/input/event0" +#else +/* dreambox and tripledragon do not use a "normal" input device, so we cannot + (ab-)use the event repeating function of it. use the neutrino socket instead. */ +#include +#include +#define NEUTRINO_SOCKET "/tmp/neutrino.sock" + +/* those structs / values are stolen from libeventserver */ +struct eventHead +{ + unsigned int eventID; + unsigned int initiatorID; + unsigned int dataSize; +}; + +enum initiators +{ + INITID_CONTROLD, + INITID_SECTIONSD, + INITID_ZAPIT, + INITID_TIMERD, + INITID_HTTPD, + INITID_NEUTRINO, + INITID_GENERIC_INPUT_EVENT_PROVIDER +}; +#endif + +enum { // not defined in input.h but used like that, at least in 2.4.22 + KEY_RELEASED = 0, + KEY_PRESSED, + KEY_AUTOREPEAT +}; + +#include "rcsim.h" + +void usage(char *n){ + unsigned int keynum = sizeof(keyname)/sizeof(struct key); + unsigned int i; + printf ("rcsim v1.1\nUsage: %s [