From e43ef1f3e7630a112378773e0ba9c6c020b2e65f Mon Sep 17 00:00:00 2001 From: Cástor Muñoz Date: Fri, 5 Feb 2016 00:25:31 +0100 Subject: rbutil: add support for iPod Classic 6G bootloader Change-Id: I0e237a81098a2d4df8d9f5d6deaaab3863a84fc6 --- rbutil/rbutilqt/Makefile.libs | 4 +- rbutil/rbutilqt/base/bootloaderinstallhelper.cpp | 4 + rbutil/rbutilqt/base/bootloaderinstalls5l.cpp | 428 +++++++++++++++++++++++ rbutil/rbutilqt/base/bootloaderinstalls5l.h | 71 ++++ rbutil/rbutilqt/changelog.txt | 1 + rbutil/rbutilqt/progressloggerfrm.ui | 9 +- rbutil/rbutilqt/rbutil.ini | 3 +- rbutil/rbutilqt/rbutilqt.pri | 2 + rbutil/rbutilqt/rbutilqt.pro | 2 +- 9 files changed, 519 insertions(+), 5 deletions(-) create mode 100644 rbutil/rbutilqt/base/bootloaderinstalls5l.cpp create mode 100644 rbutil/rbutilqt/base/bootloaderinstalls5l.h (limited to 'rbutil/rbutilqt') diff --git a/rbutil/rbutilqt/Makefile.libs b/rbutil/rbutilqt/Makefile.libs index ecb1c1814e..bd0dc121af 100644 --- a/rbutil/rbutilqt/Makefile.libs +++ b/rbutil/rbutilqt/Makefile.libs @@ -31,7 +31,7 @@ export CFLAGS=$(EXTRALIB_CFLAGS) export CC=$(EXTRALIBS_CC) export AR=$(EXTRALIBS_AR) -libs: librbspeex libucl libipodpatcher libsansapatcher libmkamsboot libmktccboot libmkmpioboot libchinachippatcher libmkimxboot +libs: librbspeex libucl libipodpatcher libsansapatcher libmkamsboot libmktccboot libmkmpioboot libchinachippatcher libmkimxboot libmks5lboot librbspeex: @@ -61,3 +61,5 @@ libchinachippatcher: libmkimxboot: $(SILENT)$(MAKE) -C $(RBBASE_DIR)/rbutil/mkimxboot BUILD_DIR=$(BUILD_DIR)/mkimxboot libmkimxboot.a +libmks5lboot: + $(SILENT)$(MAKE) -C $(RBBASE_DIR)/rbutil/mks5lboot BUILD_DIR=$(BUILD_DIR)/mks5lboot libmks5lboot.a diff --git a/rbutil/rbutilqt/base/bootloaderinstallhelper.cpp b/rbutil/rbutilqt/base/bootloaderinstallhelper.cpp index fe962d2b1d..d6d2dbc7a1 100644 --- a/rbutil/rbutilqt/base/bootloaderinstallhelper.cpp +++ b/rbutil/rbutilqt/base/bootloaderinstallhelper.cpp @@ -31,6 +31,7 @@ #include "bootloaderinstalltcc.h" #include "bootloaderinstallmpio.h" #include "bootloaderinstallimx.h" +#include "bootloaderinstalls5l.h" BootloaderInstallBase* BootloaderInstallHelper::createBootloaderInstaller(QObject* parent, QString type) { @@ -64,6 +65,9 @@ BootloaderInstallBase* BootloaderInstallHelper::createBootloaderInstaller(QObjec else if(type == "imx") { return new BootloaderInstallImx(parent); } + else if(type == "s5l") { + return new BootloaderInstallS5l(parent); + } else { return NULL; } diff --git a/rbutil/rbutilqt/base/bootloaderinstalls5l.cpp b/rbutil/rbutilqt/base/bootloaderinstalls5l.cpp new file mode 100644 index 0000000000..2442970655 --- /dev/null +++ b/rbutil/rbutilqt/base/bootloaderinstalls5l.cpp @@ -0,0 +1,428 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2008 by Dominik Riebeling + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include "bootloaderinstallbase.h" +#include "bootloaderinstalls5l.h" +#include "Logger.h" +#include "utils.h" +#include "system.h" +#include "rbsettings.h" +#include "systeminfo.h" + +#include "../mks5lboot/mks5lboot.h" + + +BootloaderInstallS5l::BootloaderInstallS5l(QObject *parent) + : BootloaderInstallBase(parent) +{ +} + + +bool BootloaderInstallS5l::install(void) +{ + LOG_INFO() << "installing bootloader"; + doInstall = true; + return installStage1(); +} + + +bool BootloaderInstallS5l::uninstall(void) +{ + LOG_INFO() << "uninstalling bootloader"; + doInstall = false; + return installStage1(); +} + + +bool BootloaderInstallS5l::installStage1(void) +{ + LOG_INFO() << "installStage1"; + + mntpoint = RbSettings::value(RbSettings::Mountpoint).toString(); + + if (!Utils::mountpoints(Utils::MountpointsSupported).contains(mntpoint)) { + LOG_ERROR() << "iPod not mounted:" << mntpoint; + emit logItem(tr("Could not find mounted iPod."), LOGERROR); + emit done(true); + return false; + } + + if (doInstall) { + // download firmware from server + emit logItem(tr("Downloading bootloader file..."), LOGINFO); + connect(this, SIGNAL(downloadDone()), this, SLOT(installStageMkdfu())); + downloadBlStart(m_blurl); + } + else { + installStageMkdfu(); + } + + return true; +} + + +void BootloaderInstallS5l::installStageMkdfu(void) +{ + int dfu_type; + QString dfu_arg; + char errstr[200]; + + LOG_INFO() << "installStageMkdfu"; + + setProgress(0); + aborted = false; + connect(this, SIGNAL(installAborted()), this, SLOT(abortInstall())); + connect(this, SIGNAL(done(bool)), this, SLOT(installDone(bool))); + + if (doInstall) { + dfu_type = DFU_INST; + m_tempfile.open(); + dfu_arg = m_tempfile.fileName(); + m_tempfile.close(); + } + else { + dfu_type = DFU_UNINST; + dfu_arg = RbSettings::value(RbSettings::Platform).toString(); + } + + // build DFU image + dfu_buf = mkdfu(dfu_type, dfu_arg.toLocal8Bit().data(), + &dfu_size, errstr, sizeof(errstr)); + if (!dfu_buf) { + LOG_ERROR() << "mkdfu() failed:" << errstr; + emit logItem(errstr, LOGERROR); + emit logItem(tr("Could not make DFU image."), LOGERROR); + emit done(true); + return; + } + + LOG_INFO() << "preparing installStageWaitForEject"; + emit logItem(tr("Ejecting iPod..."), LOGINFO); + setProgress(10); + scanTimer = QTime(); + installStageWaitForEject(); +} + + +void BootloaderInstallS5l::installStageWaitForEject(void) +{ + if (!updateProgress()) + return; /* aborted */ + + if (scanTimer.isNull() || (scanTimer.elapsed() > 3000)) { + scanSuccess = Utils::ejectDevice(mntpoint); + if (!scanSuccess) { + scanSuccess = !Utils::mountpoints( + Utils::MountpointsSupported).contains(mntpoint); + } + scanTimer.start(); + } + if (!scanSuccess) { + if (!actionShown) { + emit logItem(tr("Action required:\n" + " Please make sure no programs are accessing\n" + " files on the device. If ejecting still fails\n" + " please use your computers eject funtionality."), + LOGWARNING); + actionShown = true; + } + QTimer::singleShot(250, this, SLOT(installStageWaitForEject())); + return; + } + emit logItem(tr("Device successfully ejected."), LOGINFO); + + LOG_INFO() << "preparing installStageWaitForProcs"; + setProgress(40, 18); + scanTimer = QTime(); + installStageWaitForProcs(); +} + + +void BootloaderInstallS5l::installStageWaitForProcs(void) +{ + if (!updateProgress()) + return; /* aborted */ + + if (scanTimer.isNull() || (scanTimer.elapsed() > 1000)) { + scanSuccess = Utils::findRunningProcess(QStringList("iTunes")).isEmpty(); + scanTimer.start(); + } + if (!scanSuccess) { + if (!actionShown) { + emit logItem(tr("Action required:\n" + " Quit iTunes application."), LOGWARNING); + actionShown = true; + } + QTimer::singleShot(250, this, SLOT(installStageWaitForProcs())); + return; + } + if (actionShown) { + emit logItem(tr("iTunes closed."), LOGINFO); + if (!updateProgress()) + return; /* aborted */ + } + + QList helperPids = Utils::findRunningProcess( +#if defined(Q_OS_WIN32) + QStringList("iTunesHelper"))["iTunesHelper.exe"]; +#else + QStringList("iTunesHelper"))["iTunesHelper"]; +#endif + suspendedPids = Utils::suspendProcess(helperPids, true); + if (suspendedPids.size() != helperPids.size()) { + emit logItem(tr("Could not suspend iTunesHelper. Stop it\n" + "using the Task Manager, and try again."), LOGERROR); + emit done(true); + return; + } + + LOG_INFO() << "preparing installStageWaitForSpindown"; + // for Windows: skip waiting if the HDD was ejected a time ago + if (progressTimer.elapsed() < progressTimeout) + emit logItem(tr("Waiting for HDD spin-down..."), LOGINFO); + installStageWaitForSpindown(); +} + + +void BootloaderInstallS5l::installStageWaitForSpindown(void) +{ + if (!updateProgress()) + return; /* aborted */ + + if (progressTimer.elapsed() < progressTimeout) { + QTimer::singleShot(250, this, SLOT(installStageWaitForSpindown())); + return; + } + + LOG_INFO() << "preparing installStageWaitForDfu"; + emit logItem(tr("Waiting for DFU mode..."), LOGINFO); + emit logItem(tr("Action required:\n" + " Press and hold SELECT+MENU buttons, after\n" + " about 12 seconds a new action will require\n" + " you to release the buttons, DO IT QUICKLY,\n" + " otherwise the process could fail."), LOGWARNING); + scanTimer = QTime(); + installStageWaitForDfu(); +} + + +void BootloaderInstallS5l::installStageWaitForDfu(void) +{ + if (!updateProgress()) + return; /* aborted */ + + if (scanTimer.isNull() || (scanTimer.elapsed() > 2000)) { + scanSuccess = System::listUsbIds().contains(0x05ac1223); + scanTimer.start(); + } + if (!scanSuccess) { + QTimer::singleShot(250, this, SLOT(installStageWaitForDfu())); + return; + } + emit logItem(tr("DFU mode detected."), LOGINFO); + + emit logItem(tr("Action required:\n" + " Release SELECT+MENU buttons and wait..."), LOGWARNING); + + // Once the iPod enters DFU mode, the device will reset again if + // SELECT+MENU remains pressed for another 8 seconds. To avoid a + // reset while the NOR is being written, we wait ~10 seconds + // before sending the DFU image. + LOG_INFO() << "preparing installStageSendDfu"; + setProgress(60, 10); + installStageSendDfu(); +} + + +void BootloaderInstallS5l::installStageSendDfu(void) +{ + if (!updateProgress()) + return; /* aborted */ + + if (progressTimer.elapsed() < progressTimeout) { + QTimer::singleShot(250, this, SLOT(installStageSendDfu())); + return; + } + + if (!System::listUsbIds().contains(0x05ac1223)) { + LOG_ERROR() << "device not in DFU mode"; + emit logItem(tr("Device is not in DFU mode. It seems that\n" + "the previous required action failed, please\n" + "try again."), LOGERROR); + emit done(true); + return; + } + + emit logItem(tr("Transfering DFU image..."), LOGINFO); + if (!updateProgress()) + return; /* aborted */ + + char errstr[200]; + if (!ipoddfu_send(0x1223, dfu_buf, dfu_size, errstr, sizeof(errstr))) { + LOG_ERROR() << "ipoddfu_send() failed:" << errstr; +#if defined(Q_OS_WIN32) + if (strstr(errstr, "DFU device not found")) + { + emit logItem(tr("No valid DFU USB driver found.\n" + "Install iTunes (or the Apple Device Driver)\n" + "and try again."), + LOGERROR); + } + else +#endif + { + emit logItem(errstr, LOGERROR); + emit logItem(tr("Could not transfer DFU image."), LOGERROR); + } + emit done(true); + return; + } + emit logItem(tr("DFU transfer completed."), LOGINFO); + + LOG_INFO() << "preparing installStageWaitForRemount"; + emit logItem(tr("Restarting iPod, waiting for remount..."), LOGINFO); + setProgress(99, 45); + scanTimer = QTime(); + installStageWaitForRemount(); +} + + +void BootloaderInstallS5l::installStageWaitForRemount(void) +{ + if (!updateProgress()) + return; /* aborted */ + + if (scanTimer.isNull() || (scanTimer.elapsed() > 5000)) { + scanSuccess = Utils::mountpoints( + Utils::MountpointsSupported).contains(mntpoint); + scanTimer.start(); + } + if (!scanSuccess) { + if (!actionShown && (progressTimer.elapsed() > progressTimeout)) { + emit logItem(tr("Action required:\n" + " Could not remount the device, try to do it\n" + " manually. If the iPod didn't restart, force\n" + " a reset by pressing SELECT+MENU buttons\n" + " for about 5 seconds. If the problem could\n" + " not be solved then click 'Abort' to cancel."), + LOGWARNING); + actionShown = true; + } + QTimer::singleShot(250, this, SLOT(installStageWaitForRemount())); + return; + } + emit logItem(tr("Device remounted."), LOGINFO); + + emit logItem(tr("Bootloader successfully %1."). + arg(tr(doInstall ? "installed" : "uninstalled")), LOGOK); + + logInstall(doInstall ? LogAdd : LogRemove); + emit logProgress(1, 1); + emit done(false); +} + + +void BootloaderInstallS5l::installDone(bool status) +{ + LOG_INFO() << "installDone, status:" << status; + if (Utils::suspendProcess(suspendedPids, false).size() != suspendedPids.size()) + emit logItem(tr("Could not resume iTunesHelper."), LOGWARNING); +} + + +void BootloaderInstallS5l::abortInstall(void) +{ + LOG_INFO() << "abortInstall"; + aborted = true; + disconnect(this, SIGNAL(installAborted()), this, SLOT(abortInstall())); +} + + +bool BootloaderInstallS5l::abortDetected(void) +{ + if (aborted) { + LOG_ERROR() << "abortDetected"; + emit logItem(tr("%1 aborted by user."). + arg(tr(doInstall ? "Install" : "Uninstall")), LOGERROR); + emit done(true); + return true; + } + return false; +} + + +void BootloaderInstallS5l::setProgress(int progress, int secondsTimeout) +{ + progressTimer.start(); + progressTimeout = secondsTimeout * 1000; + progOrigin = progTarget; + progTarget = progress; + actionShown = false; +} + + +bool BootloaderInstallS5l::updateProgress(void) +{ + if (progressTimeout) { + progCurrent = qMin(progTarget, progOrigin + + progressTimer.elapsed()*(progTarget-progOrigin)/progressTimeout); + } + else { + progCurrent = progTarget; + } + emit logProgress(progCurrent, 100); + QCoreApplication::sendPostedEvents(); + QCoreApplication::processEvents(); + return !abortDetected(); +} + + +BootloaderInstallBase::BootloaderType BootloaderInstallS5l::installed(void) +{ + bool rbblInstalled; + + QString device = Utils::resolveDevicename(m_blfile); + if (device.isEmpty()) { + LOG_INFO() << "installed: BootloaderUnknown"; + return BootloaderUnknown; + } + + // rely on logfile + QString logfile = RbSettings::value(RbSettings::Mountpoint).toString() + + "/.rockbox/rbutil.log"; + QSettings s(logfile, QSettings::IniFormat, this); + QString section = SystemInfo::value( + SystemInfo::CurBootloaderName).toString().section('/', -1); + rbblInstalled = s.contains("Bootloader/" + section); + + if (rbblInstalled) { + LOG_INFO() << "installed: BootloaderRockbox"; + return BootloaderRockbox; + } + else { + LOG_INFO() << "installed: BootloaderOther"; + return BootloaderOther; + } +} + + +BootloaderInstallBase::Capabilities BootloaderInstallS5l::capabilities(void) +{ + return (Install | Uninstall); +} diff --git a/rbutil/rbutilqt/base/bootloaderinstalls5l.h b/rbutil/rbutilqt/base/bootloaderinstalls5l.h new file mode 100644 index 0000000000..a59e5d378b --- /dev/null +++ b/rbutil/rbutilqt/base/bootloaderinstalls5l.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2008 by Dominik Riebeling + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef BOOTLOADERINSTALLS5L_H +#define BOOTLOADERINSTALLS5L_H + +#include +#include "bootloaderinstallbase.h" + + +//! bootloader installation derivate based on mks5lboot +class BootloaderInstallS5l : public BootloaderInstallBase +{ + Q_OBJECT + + public: + BootloaderInstallS5l(QObject *parent); + bool install(void); + bool uninstall(void); + BootloaderInstallBase::BootloaderType installed(void); + Capabilities capabilities(void); + + private slots: + bool installStage1(void); + void installStageMkdfu(void); + void installStageWaitForEject(void); + void installStageWaitForSpindown(void); + void installStageWaitForProcs(void); + void installStageWaitForDfu(void); + void installStageSendDfu(void); + void installStageWaitForRemount(void); + void abortInstall(void); + void installDone(bool); + + private: + bool doInstall; + QString mntpoint; + unsigned char* dfu_buf; + int dfu_size; + QList suspendedPids; + bool aborted; + bool abortDetected(void); + QTime scanTimer; + bool scanSuccess; + // progress + QTime progressTimer; + int progressTimeout; + int progCurrent; + int progOrigin; + int progTarget; + bool actionShown; + void setProgress(int, int=0); + bool updateProgress(void); +}; + +#endif diff --git a/rbutil/rbutilqt/changelog.txt b/rbutil/rbutilqt/changelog.txt index c97105f651..0dec314155 100644 --- a/rbutil/rbutilqt/changelog.txt +++ b/rbutil/rbutilqt/changelog.txt @@ -25,3 +25,4 @@ Version 1.4.1 * Extend hint when uninstallation requires reinstalling the Original Firmware. * Improve update check information dialog. * Correct USB IDs for Sandisk Sansa c200v2. +* Add support for iPod Classic 6G bootloader. diff --git a/rbutil/rbutilqt/progressloggerfrm.ui b/rbutil/rbutilqt/progressloggerfrm.ui index c10e26a4af..cc4509081a 100644 --- a/rbutil/rbutilqt/progressloggerfrm.ui +++ b/rbutil/rbutilqt/progressloggerfrm.ui @@ -5,8 +5,13 @@ 0 0 - 315 - 302 + + 360 + 560 diff --git a/rbutil/rbutilqt/rbutil.ini b/rbutil/rbutilqt/rbutil.ini index e8ec8afb25..06dc622864 100644 --- a/rbutil/rbutilqt/rbutil.ini +++ b/rbutil/rbutilqt/rbutil.ini @@ -362,7 +362,8 @@ encoder=rbspeex [ipod6g] name="Ipod Classic (6th gen)" buildserver_modelname=ipod6g -bootloadermethod=none +bootloadermethod=s5l +bootloadername=/ipod/bootloader-ipod6g.ipod manualname= brand=Apple usbid=0x05ac1261 diff --git a/rbutil/rbutilqt/rbutilqt.pri b/rbutil/rbutilqt/rbutilqt.pri index 9f1aea694d..d9ef1071f4 100644 --- a/rbutil/rbutilqt/rbutilqt.pri +++ b/rbutil/rbutilqt/rbutilqt.pri @@ -66,6 +66,7 @@ SOURCES += \ base/bootloaderinstalltcc.cpp \ base/bootloaderinstallmpio.cpp \ base/bootloaderinstallimx.cpp \ + base/bootloaderinstalls5l.cpp \ base/rockboxinfo.cpp \ ../../tools/mkboot.c \ ../../tools/iriver.c \ @@ -142,6 +143,7 @@ HEADERS += \ base/bootloaderinstalltcc.h \ base/bootloaderinstallmpio.h \ base/bootloaderinstallimx.h \ + base/bootloaderinstalls5l.h \ base/rockboxinfo.h \ ../../tools/mkboot.h \ ../../tools/iriver.h \ diff --git a/rbutil/rbutilqt/rbutilqt.pro b/rbutil/rbutilqt/rbutilqt.pro index 745d9887b5..cfd6fb39ab 100644 --- a/rbutil/rbutilqt/rbutilqt.pro +++ b/rbutil/rbutilqt/rbutilqt.pro @@ -88,7 +88,7 @@ extralibs.commands = $$SILENT \ # Note: order is important for RBLIBS! The libs are appended to the linker # flags in this order, put libucl at the end. RBLIBS = rbspeex ipodpatcher sansapatcher mkamsboot mktccboot \ - mkmpioboot chinachippatcher mkimxboot ucl + mkmpioboot chinachippatcher mkimxboot mks5lboot ucl !win32-msvc* { QMAKE_EXTRA_TARGETS += extralibs PRE_TARGETDEPS += extralibs -- cgit v1.2.3