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