rockbox/rbutil/rbutilqt/base/bootloaderinstallsansa.cpp
Dominik Riebeling 38f03d4eae sansapatcher: factor out handling of bundled bootloaders.
Instead of handling bundled bootloaders in the sansapatcher functions leave
that to the caller. This removes the need to have Rockbox Utility specific
parts in sansapatcher. sansa_add_bootloader() now operates on an already loaded
bootloader. For loading a convenience function sansa_read_bootloader() is
added. This also introduces a new check on loading to prevent installing an
e200 bootloader on a c200 (and vice versa).

These changes will allow building a libsansapatcher for linking with Rockbox
Utility later.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31144 a1c6a512-1295-4272-9138-f99709370657
2011-12-04 19:40:43 +00:00

295 lines
8.5 KiB
C++

/***************************************************************************
* __________ __ ___.
* 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 <QtCore>
#include "bootloaderinstallbase.h"
#include "bootloaderinstallsansa.h"
#include "../sansapatcher/sansapatcher.h"
#include "utils.h"
BootloaderInstallSansa::BootloaderInstallSansa(QObject *parent)
: BootloaderInstallBase(parent)
{
(void)parent;
// initialize sector buffer. sansa_sectorbuf is instantiated by
// sansapatcher.
// The buffer itself is only present once, so make sure to not allocate
// it if it was already allocated. The application needs to take care
// no concurrent (i.e. multiple objects of this class running) requests
// are done.
if(sansa_sectorbuf == NULL)
sansa_alloc_buffer(&sansa_sectorbuf, BUFFER_SIZE);
}
BootloaderInstallSansa::~BootloaderInstallSansa()
{
if(sansa_sectorbuf) {
free(sansa_sectorbuf);
sansa_sectorbuf = NULL;
}
}
/** Start bootloader installation.
*/
bool BootloaderInstallSansa::install(void)
{
if(sansa_sectorbuf == NULL) {
emit logItem(tr("Error: can't allocate buffer memory!"), LOGERROR);
return false;
emit done(true);
}
emit logItem(tr("Searching for Sansa"), LOGINFO);
struct sansa_t sansa;
int n = sansa_scan(&sansa);
if(n == -1) {
emit logItem(tr("Permission for disc access denied!\n"
"This is required to install the bootloader"),
LOGERROR);
emit done(true);
return false;
}
if(n == 0) {
emit logItem(tr("No Sansa detected!"), LOGERROR);
emit done(true);
return false;
}
if(sansa.hasoldbootloader) {
emit logItem(tr("OLD ROCKBOX INSTALLATION DETECTED, ABORTING.\n"
"You must reinstall the original Sansa firmware before running\n"
"sansapatcher for the first time.\n"
"See http://www.rockbox.org/wiki/SansaE200Install\n"),
LOGERROR);
emit done(true);
return false;
}
emit logItem(tr("Downloading bootloader file"), LOGINFO);
downloadBlStart(m_blurl);
connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
return true;
}
/** Finish bootloader installation.
*/
void BootloaderInstallSansa::installStage2(void)
{
struct sansa_t sansa;
unsigned char* buf = NULL;
unsigned int len;
emit logItem(tr("Installing Rockbox bootloader"), LOGINFO);
QCoreApplication::processEvents();
if(!sansaInitialize(&sansa)) {
emit done(true);
return;
}
if(sansa_reopen_rw(&sansa) < 0) {
emit logItem(tr("Could not open Sansa in R/W mode"), LOGERROR);
emit done(true);
return;
}
// check model -- if sansapatcher reports a c200 don't install an e200
// bootloader and vice versa.
// The model is available in the mi4 file at offset 0x1fc and matches
// the targetname set by sansapatcher.
emit logItem(tr("Checking downloaded bootloader"), LOGINFO);
m_tempfile.open();
QString blfile = m_tempfile.fileName();
char magic[4];
m_tempfile.seek(0x1fc);
m_tempfile.read(magic, 4);
m_tempfile.close();
if(memcmp(sansa.targetname, magic, 4) != 0) {
emit logItem(tr("Bootloader mismatch! Aborting."), LOGERROR);
qDebug("[BootloaderInstallSansa] Targetname: %s, mi4 magic: %c%c%c%c",
sansa.targetname, magic[0], magic[1], magic[2], magic[3]);
emit done(true);
sansa_close(&sansa);
return;
}
len = sansa_read_bootloader(&sansa, blfile.toLatin1().data(), &buf);
if(sansa_add_bootloader(&sansa, buf, len) == 0) {
emit logItem(tr("Successfully installed bootloader"), LOGOK);
sansa_close(&sansa);
#if defined(Q_OS_MACX)
m_remountDevice = sansa.diskname;
connect(this, SIGNAL(remounted(bool)), this, SLOT(installStage3(bool)));
waitRemount();
#else
installStage3(true);
#endif
}
else {
emit logItem(tr("Failed to install bootloader"), LOGERROR);
sansa_close(&sansa);
emit done(true);
return;
}
}
void BootloaderInstallSansa::installStage3(bool mounted)
{
if(mounted) {
logInstall(LogAdd);
emit logItem(tr("Bootloader Installation complete."), LOGINFO);
emit done(false);
return;
}
else {
emit logItem(tr("Writing log aborted"), LOGERROR);
emit done(true);
}
qDebug() << "version installed:" << m_blversion.toString(Qt::ISODate);
}
/** Uninstall the bootloader.
*/
bool BootloaderInstallSansa::uninstall(void)
{
struct sansa_t sansa;
emit logItem(tr("Uninstalling bootloader"), LOGINFO);
QCoreApplication::processEvents();
if(!sansaInitialize(&sansa)) {
emit done(true);
return false;
}
if (sansa.hasoldbootloader) {
emit logItem(tr("OLD ROCKBOX INSTALLATION DETECTED, ABORTING.\n"
"You must reinstall the original Sansa firmware before running\n"
"sansapatcher for the first time.\n"
"See http://www.rockbox.org/wiki/SansaE200Install\n"),
LOGERROR);
emit done(true);
return false;
}
if (sansa_reopen_rw(&sansa) < 0) {
emit logItem(tr("Could not open Sansa in R/W mode"), LOGERROR);
emit done(true);
return false;
}
if (sansa_delete_bootloader(&sansa)==0) {
emit logItem(tr("Successfully removed bootloader"), LOGOK);
logInstall(LogRemove);
emit done(false);
sansa_close(&sansa);
return true;
}
else {
emit logItem(tr("Removing bootloader failed."),LOGERROR);
emit done(true);
sansa_close(&sansa);
return false;
}
return false;
}
/** Check if bootloader is already installed
*/
BootloaderInstallBase::BootloaderType BootloaderInstallSansa::installed(void)
{
struct sansa_t sansa;
int num;
if(!sansaInitialize(&sansa)) {
return BootloaderUnknown;
}
if((num = sansa_list_images(&sansa)) == 2) {
sansa_close(&sansa);
return BootloaderRockbox;
}
else if(num == 1) {
sansa_close(&sansa);
return BootloaderOther;
}
return BootloaderUnknown;
}
bool BootloaderInstallSansa::sansaInitialize(struct sansa_t *sansa)
{
if(!m_blfile.isEmpty()) {
QString devicename = Utils::resolveDevicename(m_blfile);
if(devicename.isEmpty()) {
emit logItem(tr("Error: could not retrieve device name"), LOGERROR);
return false;
}
#if defined(Q_OS_WIN32)
sprintf(sansa->diskname, "\\\\.\\PhysicalDrive%i", devicename.toInt());
#elif defined(Q_OS_MACX)
sprintf(sansa->diskname,
qPrintable(devicename.remove(QRegExp("s[0-9]+$"))));
#else
sprintf(sansa->diskname,
qPrintable(devicename.remove(QRegExp("[0-9]+$"))));
#endif
qDebug() << "[BootloaderInstallSansa] sansapatcher: overriding scan, using"
<< sansa->diskname;
}
else if(sansa_scan(sansa) != 1) {
emit logItem(tr("Can't find Sansa"), LOGERROR);
return false;
}
if (sansa_open(sansa, 0) < 0) {
emit logItem(tr("Could not open Sansa"), LOGERROR);
return false;
}
if (sansa_read_partinfo(sansa,0) < 0) {
emit logItem(tr("Could not read partition table"), LOGERROR);
sansa_close(sansa);
return false;
}
int i = is_sansa(sansa);
if(i < 0) {
emit logItem(tr("Disk is not a Sansa (Error %1), aborting.").arg(i), LOGERROR);
sansa_close(sansa);
return false;
}
return true;
}
/** Get capabilities of subclass installer.
*/
BootloaderInstallBase::Capabilities BootloaderInstallSansa::capabilities(void)
{
return (Install | Uninstall | IsRaw | CanCheckInstalled);
}