diff options
author | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2021-12-15 21:04:28 +0100 |
---|---|---|
committer | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2021-12-24 18:05:53 +0100 |
commit | c876d3bbefe0dc00c27ca0c12d29da5874946962 (patch) | |
tree | 69f468a185a369b01998314bc3ecc19b70f4fcaa /utils/rbutilqt/base/bootloaderinstalls5l.cpp | |
parent | 6c6f0757d7a902feb293be165d1490c42bc8e7ad (diff) | |
download | rockbox-c876d3bbefe0dc00c27ca0c12d29da5874946962.tar.gz rockbox-c876d3bbefe0dc00c27ca0c12d29da5874946962.zip |
rbutil: Merge rbutil with utils folder.
rbutil uses several components from the utils folder, and can be
considered part of utils too. Having it in a separate folder is an
arbitrary split that doesn't help anymore these days, so merge them.
This also allows other utils to easily use libtools.make without the
need to navigate to a different folder.
Change-Id: I3fc2f4de19e3e776553efb5dea5f779dfec0dc21
Diffstat (limited to 'utils/rbutilqt/base/bootloaderinstalls5l.cpp')
-rw-r--r-- | utils/rbutilqt/base/bootloaderinstalls5l.cpp | 437 |
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 | |||
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, &BootloaderInstallBase::downloadDone, | ||
70 | this, &BootloaderInstallS5l::installStageMkdfu); | ||
71 | downloadBlStart(m_blurl); | ||
72 | } | ||
73 | else { | ||
74 | installStageMkdfu(); | ||
75 | } | ||
76 | |||
77 | return true; | ||
78 | } | ||
79 | |||
80 | |||
81 | void 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 | |||
126 | void 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 | |||
160 | void 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 | |||
206 | void 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 | |||
228 | void 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 | |||
256 | void 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 | |||
309 | void 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 | |||
346 | void 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 | |||
354 | void BootloaderInstallS5l::abortInstall(void) | ||
355 | { | ||
356 | LOG_INFO() << "abortInstall"; | ||
357 | aborted = true; | ||
358 | disconnect(this, &BootloaderInstallBase::installAborted, | ||
359 | this, &BootloaderInstallS5l::abortInstall); | ||
360 | } | ||
361 | |||
362 | |||
363 | bool 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 | |||
378 | void 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 | |||
388 | bool 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 | |||
405 | BootloaderInstallBase::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 | |||
434 | BootloaderInstallBase::Capabilities BootloaderInstallS5l::capabilities(void) | ||
435 | { | ||
436 | return (Install | Uninstall); | ||
437 | } | ||