summaryrefslogtreecommitdiff
path: root/utils/rbutilqt/base/bootloaderinstalls5l.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/rbutilqt/base/bootloaderinstalls5l.cpp')
-rw-r--r--utils/rbutilqt/base/bootloaderinstalls5l.cpp437
1 files changed, 437 insertions, 0 deletions
diff --git a/utils/rbutilqt/base/bootloaderinstalls5l.cpp b/utils/rbutilqt/base/bootloaderinstalls5l.cpp
new file mode 100644
index 0000000000..63a30ff2b0
--- /dev/null
+++ b/utils/rbutilqt/base/bootloaderinstalls5l.cpp
@@ -0,0 +1,437 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include <QtCore>
20#include "bootloaderinstallbase.h"
21#include "bootloaderinstalls5l.h"
22#include "Logger.h"
23#include "utils.h"
24#include "system.h"
25#include "rbsettings.h"
26#include "playerbuildinfo.h"
27
28#include "../mks5lboot/mks5lboot.h"
29
30
31BootloaderInstallS5l::BootloaderInstallS5l(QObject *parent)
32 : BootloaderInstallBase(parent)
33{
34}
35
36
37bool BootloaderInstallS5l::install(void)
38{
39 LOG_INFO() << "installing bootloader";
40 doInstall = true;
41 return installStage1();
42}
43
44
45bool BootloaderInstallS5l::uninstall(void)
46{
47 LOG_INFO() << "uninstalling bootloader";
48 doInstall = false;
49 return installStage1();
50}
51
52
53bool BootloaderInstallS5l::installStage1(void)
54{
55 LOG_INFO() << "installStage1";
56
57 mntpoint = RbSettings::value(RbSettings::Mountpoint).toString();
58
59 if (!Utils::mountpoints(Utils::MountpointsSupported).contains(mntpoint)) {
60 LOG_ERROR() << "iPod not mounted:" << mntpoint;
61 emit logItem(tr("Could not find mounted iPod."), LOGERROR);
62 emit done(true);
63 return false;
64 }
65
66 if (doInstall) {
67 // download firmware from server
68 emit logItem(tr("Downloading bootloader file..."), LOGINFO);
69 connect(this, &BootloaderInstallBase::downloadDone,
70 this, &BootloaderInstallS5l::installStageMkdfu);
71 downloadBlStart(m_blurl);
72 }
73 else {
74 installStageMkdfu();
75 }
76
77 return true;
78}
79
80
81void BootloaderInstallS5l::installStageMkdfu(void)
82{
83 int dfu_type;
84 QString dfu_arg;
85 char errstr[200];
86
87 LOG_INFO() << "installStageMkdfu";
88
89 setProgress(0);
90 aborted = false;
91 connect(this, &BootloaderInstallBase::installAborted,
92 this, &BootloaderInstallS5l::abortInstall);
93 connect(this, &BootloaderInstallBase::done,
94 this, &BootloaderInstallS5l::installDone);
95
96 if (doInstall) {
97 dfu_type = DFU_INST;
98 m_tempfile.open();
99 dfu_arg = m_tempfile.fileName();
100 m_tempfile.close();
101 }
102 else {
103 dfu_type = DFU_UNINST;
104 dfu_arg = RbSettings::value(RbSettings::Platform).toString();
105 }
106
107 // build DFU image
108 dfu_buf = mkdfu(dfu_type, dfu_arg.toLocal8Bit().data(),
109 &dfu_size, errstr, sizeof(errstr));
110 if (!dfu_buf) {
111 LOG_ERROR() << "mkdfu() failed:" << errstr;
112 emit logItem(errstr, LOGERROR);
113 emit logItem(tr("Could not make DFU image."), LOGERROR);
114 emit done(true);
115 return;
116 }
117
118 LOG_INFO() << "preparing installStageWaitForEject";
119 emit logItem(tr("Ejecting iPod..."), LOGINFO);
120 setProgress(10);
121 scanTimer.invalidate();
122 installStageWaitForEject();
123}
124
125
126void BootloaderInstallS5l::installStageWaitForEject(void)
127{
128 if (!updateProgress())
129 return; /* aborted */
130
131 if (!scanTimer.isValid() || (scanTimer.elapsed() > 3000)) {
132 scanSuccess = Utils::ejectDevice(mntpoint);
133 if (!scanSuccess) {
134 scanSuccess = !Utils::mountpoints(
135 Utils::MountpointsSupported).contains(mntpoint);
136 }
137 scanTimer.start();
138 }
139 if (!scanSuccess) {
140 if (!actionShown) {
141 emit logItem(tr("Action required:\n\n"
142 "Please make sure no programs are accessing "
143 "files on the device. If ejecting still fails "
144 "please use your computers eject functionality."),
145 LOGWARNING);
146 actionShown = true;
147 }
148 QTimer::singleShot(250, this, &BootloaderInstallS5l::installStageWaitForEject);
149 return;
150 }
151 emit logItem(tr("Device successfully ejected."), LOGINFO);
152
153 LOG_INFO() << "preparing installStageWaitForProcs";
154 setProgress(40, 18);
155 scanTimer.invalidate();
156 installStageWaitForProcs();
157}
158
159
160void BootloaderInstallS5l::installStageWaitForProcs(void)
161{
162 if (!updateProgress())
163 return; /* aborted */
164
165 if (!scanTimer.isValid() || (scanTimer.elapsed() > 1000)) {
166 scanSuccess = Utils::findRunningProcess(QStringList("iTunes")).isEmpty();
167 scanTimer.start();
168 }
169 if (!scanSuccess) {
170 if (!actionShown) {
171 emit logItem(tr("Action required:\n\n"
172 "Quit iTunes application."), LOGWARNING);
173 actionShown = true;
174 }
175 QTimer::singleShot(250, this, &BootloaderInstallS5l::installStageWaitForProcs);
176 return;
177 }
178 if (actionShown) {
179 emit logItem(tr("iTunes closed."), LOGINFO);
180 if (!updateProgress())
181 return; /* aborted */
182 }
183
184 QList<int> helperPids = Utils::findRunningProcess(
185#if defined(Q_OS_WIN32)
186 QStringList("iTunesHelper"))["iTunesHelper.exe"];
187#else
188 QStringList("iTunesHelper"))["iTunesHelper"];
189#endif
190 suspendedPids = Utils::suspendProcess(helperPids, true);
191 if (suspendedPids.size() != helperPids.size()) {
192 emit logItem(tr("Could not suspend iTunesHelper. Stop it "
193 "using the Task Manager, and try again."), LOGERROR);
194 emit done(true);
195 return;
196 }
197
198 LOG_INFO() << "preparing installStageWaitForSpindown";
199 // for Windows: skip waiting if the HDD was ejected a time ago
200 if (progressTimer.elapsed() < progressTimeout)
201 emit logItem(tr("Waiting for HDD spin-down..."), LOGINFO);
202 installStageWaitForSpindown();
203}
204
205
206void BootloaderInstallS5l::installStageWaitForSpindown(void)
207{
208 if (!updateProgress())
209 return; /* aborted */
210
211 if (progressTimer.elapsed() < progressTimeout) {
212 QTimer::singleShot(250, this, &BootloaderInstallS5l::installStageWaitForSpindown);
213 return;
214 }
215
216 LOG_INFO() << "preparing installStageWaitForDfu";
217 emit logItem(tr("Waiting for DFU mode..."), LOGINFO);
218 emit logItem(tr("Action required:\n\n"
219 "Press and hold SELECT+MENU buttons, after "
220 "about 12 seconds a new action will require "
221 "you to release the buttons, DO IT QUICKLY, "
222 "otherwise the process could fail."), LOGWARNING);
223 scanTimer.invalidate();
224 installStageWaitForDfu();
225}
226
227
228void BootloaderInstallS5l::installStageWaitForDfu(void)
229{
230 if (!updateProgress())
231 return; /* aborted */
232
233 if (!scanTimer.isValid() || (scanTimer.elapsed() > 2000)) {
234 scanSuccess = System::listUsbIds().contains(0x05ac1223);
235 scanTimer.start();
236 }
237 if (!scanSuccess) {
238 QTimer::singleShot(250, this, &BootloaderInstallS5l::installStageWaitForDfu);
239 return;
240 }
241 emit logItem(tr("DFU mode detected."), LOGINFO);
242
243 emit logItem(tr("Action required:\n\n"
244 "Release SELECT+MENU buttons and wait..."), LOGWARNING);
245
246 // Once the iPod enters DFU mode, the device will reset again if
247 // SELECT+MENU remains pressed for another 8 seconds. To avoid a
248 // reset while the NOR is being written, we wait ~10 seconds
249 // before sending the DFU image.
250 LOG_INFO() << "preparing installStageSendDfu";
251 setProgress(60, 10);
252 installStageSendDfu();
253}
254
255
256void BootloaderInstallS5l::installStageSendDfu(void)
257{
258 if (!updateProgress())
259 return; /* aborted */
260
261 if (progressTimer.elapsed() < progressTimeout) {
262 QTimer::singleShot(250, this, &BootloaderInstallS5l::installStageSendDfu);
263 return;
264 }
265
266 if (!System::listUsbIds().contains(0x05ac1223)) {
267 LOG_ERROR() << "device not in DFU mode";
268 emit logItem(tr("Device is not in DFU mode. It seems that "
269 "the previous required action failed, please "
270 "try again."), LOGERROR);
271 emit done(true);
272 return;
273 }
274
275 emit logItem(tr("Transfering DFU image..."), LOGINFO);
276 if (!updateProgress())
277 return; /* aborted */
278
279 char errstr[200];
280 if (!ipoddfu_send(0x1223, dfu_buf, dfu_size, errstr, sizeof(errstr))) {
281 LOG_ERROR() << "ipoddfu_send() failed:" << errstr;
282#if defined(Q_OS_WIN32)
283 if (strstr(errstr, "DFU device not found"))
284 {
285 emit logItem(tr("No valid DFU USB driver found.\n\n"
286 "Install iTunes (or the Apple Device Driver) "
287 "and try again."),
288 LOGERROR);
289 }
290 else
291#endif
292 {
293 emit logItem(errstr, LOGERROR);
294 emit logItem(tr("Could not transfer DFU image."), LOGERROR);
295 }
296 emit done(true);
297 return;
298 }
299 emit logItem(tr("DFU transfer completed."), LOGINFO);
300
301 LOG_INFO() << "preparing installStageWaitForRemount";
302 emit logItem(tr("Restarting iPod, waiting for remount..."), LOGINFO);
303 setProgress(99, 45);
304 scanTimer.invalidate();
305 installStageWaitForRemount();
306}
307
308
309void BootloaderInstallS5l::installStageWaitForRemount(void)
310{
311 if (!updateProgress())
312 return; /* aborted */
313
314 if (!scanTimer.isValid() || (scanTimer.elapsed() > 5000)) {
315 scanSuccess = Utils::mountpoints(
316 Utils::MountpointsSupported).contains(mntpoint);
317 scanTimer.start();
318 }
319 if (!scanSuccess) {
320 if (!actionShown && (progressTimer.elapsed() > progressTimeout)) {
321 emit logItem(tr("Action required:\n\n"
322 "Could not remount the device, try to do it "
323 "manually. If the iPod didn't restart, force "
324 "a reset by pressing SELECT+MENU buttons "
325 "for about 5 seconds. If the problem could "
326 "not be solved then click 'Abort' to cancel."),
327 LOGWARNING);
328 actionShown = true;
329 }
330 QTimer::singleShot(250, this, &BootloaderInstallS5l::installStageWaitForRemount);
331 return;
332 }
333 emit logItem(tr("Device remounted."), LOGINFO);
334
335 if (doInstall)
336 emit logItem(tr("Bootloader successfully installed."), LOGOK);
337 else
338 emit logItem(tr("Bootloader successfully uninstalled."), LOGOK);
339
340 logInstall(doInstall ? LogAdd : LogRemove);
341 emit logProgress(1, 1);
342 emit done(false);
343}
344
345
346void BootloaderInstallS5l::installDone(bool status)
347{
348 LOG_INFO() << "installDone, status:" << status;
349 if (Utils::suspendProcess(suspendedPids, false).size() != suspendedPids.size())
350 emit logItem(tr("Could not resume iTunesHelper."), LOGWARNING);
351}
352
353
354void BootloaderInstallS5l::abortInstall(void)
355{
356 LOG_INFO() << "abortInstall";
357 aborted = true;
358 disconnect(this, &BootloaderInstallBase::installAborted,
359 this, &BootloaderInstallS5l::abortInstall);
360}
361
362
363bool BootloaderInstallS5l::abortDetected(void)
364{
365 if (aborted) {
366 LOG_ERROR() << "abortDetected";
367 if (doInstall)
368 emit logItem(tr("Install aborted by user."), LOGERROR);
369 else
370 emit logItem(tr("Uninstall aborted by user."), LOGERROR);
371 emit done(true);
372 return true;
373 }
374 return false;
375}
376
377
378void BootloaderInstallS5l::setProgress(int progress, int secondsTimeout)
379{
380 progressTimer.start();
381 progressTimeout = secondsTimeout * 1000;
382 progOrigin = progTarget;
383 progTarget = progress;
384 actionShown = false;
385}
386
387
388bool BootloaderInstallS5l::updateProgress(void)
389{
390 if (progressTimeout) {
391 progCurrent = qMin(progTarget, progOrigin +
392 static_cast<int>(progressTimer.elapsed())
393 * (progTarget - progOrigin) / progressTimeout);
394 }
395 else {
396 progCurrent = progTarget;
397 }
398 emit logProgress(progCurrent, 100);
399 QCoreApplication::sendPostedEvents();
400 QCoreApplication::processEvents();
401 return !abortDetected();
402}
403
404
405BootloaderInstallBase::BootloaderType BootloaderInstallS5l::installed(void)
406{
407 bool rbblInstalled;
408
409 QString device = Utils::resolveDevicename(m_blfile);
410 if (device.isEmpty()) {
411 LOG_INFO() << "installed: BootloaderUnknown";
412 return BootloaderUnknown;
413 }
414
415 // rely on logfile
416 QString logfile = RbSettings::value(RbSettings::Mountpoint).toString()
417 + "/.rockbox/rbutil.log";
418 QSettings s(logfile, QSettings::IniFormat, this);
419 QString section = PlayerBuildInfo::instance()->value(
420 PlayerBuildInfo::BootloaderName).toString().section('/', -1);
421 rbblInstalled = s.contains("Bootloader/" + section);
422
423 if (rbblInstalled) {
424 LOG_INFO() << "installed: BootloaderRockbox";
425 return BootloaderRockbox;
426 }
427 else {
428 LOG_INFO() << "installed: BootloaderOther";
429 return BootloaderOther;
430 }
431}
432
433
434BootloaderInstallBase::Capabilities BootloaderInstallS5l::capabilities(void)
435{
436 return (Install | Uninstall);
437}