summaryrefslogtreecommitdiff
path: root/bootloader
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2018-11-05 13:01:55 +0100
committerSolomon Peachy <pizza@shaftnet.org>2020-04-06 18:15:41 +0200
commit180cef835bf40d0081895773aaa637ac926bb0ac (patch)
tree48c380d76c0ea40931cb5e863b40fc5dfa1ecba4 /bootloader
parentced3a20aacf26642ccc3ffd136f64247c67e5769 (diff)
downloadrockbox-180cef835bf40d0081895773aaa637ac926bb0ac.tar.gz
rockbox-180cef835bf40d0081895773aaa637ac926bb0ac.zip
xDuoo X3II and X20 port
Provided by Roman Stolyarov Integration, Refactoring, and Upstreaming by Solomon Peachy X3II confirmed working by forum tester, X20 is nearly identical. This includes bootloader, main firmware, and the flash image patcher. Eventual Todo: * Further refactor AGPTek Rocker & xduoo hiby bootloaders * Further refactor AGPTek Rocker & xduoo hosted platform code Change-Id: I34a674051d368efcc75d1d18c725971fe46c3eee
Diffstat (limited to 'bootloader')
-rw-r--r--bootloader/SOURCES2
-rw-r--r--bootloader/rocker_linux.c4
-rw-r--r--bootloader/xduoo_linux.c555
3 files changed, 559 insertions, 2 deletions
diff --git a/bootloader/SOURCES b/bootloader/SOURCES
index ce73724f69..82ddcb80b9 100644
--- a/bootloader/SOURCES
+++ b/bootloader/SOURCES
@@ -78,6 +78,8 @@ mpio_hd200_hd300.c
78nwz_linux.c 78nwz_linux.c
79#elif defined(AGPTEK_ROCKER) 79#elif defined(AGPTEK_ROCKER)
80rocker_linux.c 80rocker_linux.c
81#elif (defined(XDUOO_X3II) || defined(XDUOO_X20))
82xduoo_linux.c
81#elif defined(RK27_GENERIC) || defined(HM60X) || defined(HM801) \ 83#elif defined(RK27_GENERIC) || defined(HM60X) || defined(HM801) \
82 || defined(MA9) || defined(MA9C) || defined(MA8) || defined(MA8C) \ 84 || defined(MA9) || defined(MA9C) || defined(MA8) || defined(MA8C) \
83 || defined(IHIFI760) || defined(IHIFI960) || defined(IHIFI800) \ 85 || defined(IHIFI760) || defined(IHIFI960) || defined(IHIFI800) \
diff --git a/bootloader/rocker_linux.c b/bootloader/rocker_linux.c
index cb0e5b66e5..80b3bfbab5 100644
--- a/bootloader/rocker_linux.c
+++ b/bootloader/rocker_linux.c
@@ -12,7 +12,7 @@
12 * 12 *
13 * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing 13 * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
14 * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach 14 * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
15 * 15 *
16 * This program is free software; you can redistribute it and/or 16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License 17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2 18 * as published by the Free Software Foundation; either version 2
@@ -464,7 +464,7 @@ static int open_log(void)
464 return fd; 464 return fd;
465 close(fd); 465 close(fd);
466 /* move file */ 466 /* move file */
467 rename("/mnt/sd_0/rockbox.log", "/mnt_sd0/rockbox.log.1"); 467 rename("/mnt/sd_0/rockbox.log", "/mnt_sd_0/rockbox.log.1");
468 /* re-open the file, truncate in case the move was unsuccessful */ 468 /* re-open the file, truncate in case the move was unsuccessful */
469 return open("/mnt/sd_0/rockbox.log", O_RDWR | O_CREAT | O_APPEND | O_TRUNC); 469 return open("/mnt/sd_0/rockbox.log", O_RDWR | O_CREAT | O_APPEND | O_TRUNC);
470} 470}
diff --git a/bootloader/xduoo_linux.c b/bootloader/xduoo_linux.c
new file mode 100644
index 0000000000..1071c6dc9b
--- /dev/null
+++ b/bootloader/xduoo_linux.c
@@ -0,0 +1,555 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 *
10 * Copyright (C) 2016 by Amaury Pouly
11 * 2018 by Marcin Bukat
12 * 2018 by Roman Stolyarov
13 *
14 * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
15 * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
21 *
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
24 *
25 ****************************************************************************/
26
27#include "system.h"
28#include "lcd.h"
29#include "backlight.h"
30#include "button-target.h"
31#include "button.h"
32#include "../kernel/kernel-internal.h"
33#include "core_alloc.h"
34#include "filesystem-app.h"
35#include "lcd.h"
36#include "font.h"
37#include "power.h"
38#include <string.h>
39#include <stdlib.h>
40#include <unistd.h>
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <fcntl.h>
44#include <dirent.h>
45#include <sys/wait.h>
46#include <stdarg.h>
47#include "version.h"
48
49/* all images must have the following size */
50#define ICON_WIDTH 130
51#define ICON_HEIGHT 130
52
53/* images */
54#include "bitmaps/rockboxicon.h"
55#include "bitmaps/hibyicon.h"
56#include "bitmaps/toolsicon.h"
57
58/* don't issue an error when parsing the file for dependencies */
59#if defined(BMPWIDTH_rockboxicon) && (BMPWIDTH_rockboxicon != ICON_WIDTH || \
60 BMPHEIGHT_rockboxicon != ICON_HEIGHT)
61#error rockboxicon has the wrong resolution
62#endif
63#if defined(BMPWIDTH_hibyicon) && (BMPWIDTH_hibyicon != ICON_WIDTH || \
64 BMPHEIGHT_hibyicon != ICON_HEIGHT)
65#error hibyicon has the wrong resolution
66#endif
67#if defined(BMPWIDTH_toolsicon) && (BMPWIDTH_toolsicon != ICON_WIDTH || \
68 BMPHEIGHT_toolsicon != ICON_HEIGHT)
69#error toolsicon has the wrong resolution
70#endif
71
72#ifndef BUTTON_UP
73#define BUTTON_UP BUTTON_PREV
74#endif
75#ifndef BUTTON_DOWN
76#define BUTTON_DOWN BUTTON_NEXT
77#endif
78#ifndef BUTTON_ENTER
79#define BUTTON_ENTER BUTTON_PLAY
80#endif
81
82/* return icon y position (x is always centered) */
83static int get_icon_y(void)
84{
85 int h;
86 lcd_getstringsize("X", NULL, &h);
87 return ((LCD_HEIGHT - ICON_HEIGHT)/2) - h;
88}
89
90/* Important Note: this bootloader is carefully written so that in case of
91 * error, the OF is run. This seems like the safest option since the OF is
92 * always there and might do magic things. */
93
94enum boot_mode
95{
96 BOOT_ROCKBOX,
97 BOOT_TOOLS,
98 BOOT_OF,
99 BOOT_COUNT,
100 BOOT_USB, /* special */
101 BOOT_STOP, /* power down/suspend */
102};
103
104static void display_text_center(int y, const char *text)
105{
106 int width;
107 lcd_getstringsize(text, &width, NULL);
108 lcd_putsxy(LCD_WIDTH / 2 - width / 2, y, text);
109}
110
111static void display_text_centerf(int y, const char *format, ...)
112{
113 char buf[1024];
114 va_list ap;
115 va_start(ap, format);
116
117 vsnprintf(buf, sizeof(buf), format, ap);
118 display_text_center(y, buf);
119}
120
121/* get timeout before taking action if the user doesn't touch the device */
122static int get_inactivity_tmo(void)
123{
124#if defined(HAS_BUTTON_HOLD)
125 if(button_hold())
126 return 5 * HZ; /* Inactivity timeout when on hold */
127 else
128#endif
129 return 10 * HZ; /* Inactivity timeout when not on hold */
130}
131
132/* return action on idle timeout */
133static enum boot_mode inactivity_action(enum boot_mode cur_selection)
134{
135#if defined(HAS_BUTTON_HOLD)
136 if(button_hold())
137 return BOOT_STOP; /* power down/suspend */
138 else
139#endif
140 return cur_selection; /* return last choice */
141}
142
143/* we store the boot mode in a file in /tmp so we can reload it between 'boots'
144 * (since the mostly suspends instead of powering down) */
145static enum boot_mode load_boot_mode(enum boot_mode mode)
146{
147 int fd = open("/data/rb_bl_mode.txt", O_RDONLY);
148 if(fd >= 0)
149 {
150 read(fd, &mode, sizeof(mode));
151 close(fd);
152 }
153 return mode;
154}
155
156static void save_boot_mode(enum boot_mode mode)
157{
158 int fd = open("/data/rb_bl_mode.txt", O_RDWR | O_CREAT | O_TRUNC);
159 if(fd >= 0)
160 {
161 write(fd, &mode, sizeof(mode));
162 close(fd);
163 }
164}
165
166static enum boot_mode get_boot_mode(void)
167{
168 /* load previous mode, or start with rockbox if none */
169 enum boot_mode init_mode = load_boot_mode(BOOT_ROCKBOX);
170 /* wait for user action */
171 enum boot_mode mode = init_mode;
172 int last_activity = current_tick;
173#if defined(HAS_BUTTON_HOLD)
174 bool hold_status = button_hold();
175#endif
176 while(true)
177 {
178 /* on usb detect, return to usb
179 * FIXME this is a hack, we need proper usb detection */
180 if(power_input_status() & POWER_INPUT_USB_CHARGER)
181 {
182 /* save last choice */
183 save_boot_mode(mode);
184 return BOOT_USB;
185 }
186 /* inactivity detection */
187 int timeout = last_activity + get_inactivity_tmo();
188 if(TIME_AFTER(current_tick, timeout))
189 {
190 /* save last choice */
191 save_boot_mode(mode);
192 return inactivity_action(mode);
193 }
194 /* redraw */
195 lcd_clear_display();
196 /* display top text */
197#if defined(HAS_BUTTON_HOLD)
198 if(button_hold())
199 {
200 lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
201 display_text_center(0, "ON HOLD!");
202 }
203 else
204#endif
205 {
206 lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
207 display_text_center(0, "SELECT PLAYER");
208 }
209 lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
210 /* display icon */
211 const struct bitmap *icon = (mode == BOOT_OF) ? &bm_hibyicon :
212 (mode == BOOT_ROCKBOX) ? &bm_rockboxicon : &bm_toolsicon;
213 lcd_bmp(icon, (LCD_WIDTH - ICON_WIDTH) / 2, get_icon_y());
214 /* display bottom description */
215 const char *desc = (mode == BOOT_OF) ? "HIBY PLAYER" :
216 (mode == BOOT_ROCKBOX) ? "ROCKBOX" : "TOOLS";
217
218 int desc_height;
219 lcd_getstringsize(desc, NULL, &desc_height);
220 display_text_center(LCD_HEIGHT - 3*desc_height, desc);
221
222 /* display arrows */
223 int arrow_width, arrow_height;
224 lcd_getstringsize("<", &arrow_width, &arrow_height);
225 int arrow_y = get_icon_y() + ICON_HEIGHT / 2 - arrow_height / 2;
226 lcd_putsxy(arrow_width / 2, arrow_y, "<");
227 lcd_putsxy(LCD_WIDTH - 3 * arrow_width / 2, arrow_y, ">");
228
229 lcd_set_foreground(LCD_RGBPACK(0, 255, 0));
230 display_text_centerf(LCD_HEIGHT - arrow_height * 3 / 2, "timeout in %d sec",
231 (timeout - current_tick + HZ - 1) / HZ);
232
233 lcd_update();
234
235 /* wait for a key */
236 int btn = button_get_w_tmo(HZ / 10);
237
238#if defined(HAS_BUTTON_HOLD)
239 /* record action, changing HOLD counts as action */
240 if(btn & BUTTON_MAIN || hold_status != button_hold())
241 last_activity = current_tick;
242
243 hold_status = button_hold();
244#else
245 if(btn & BUTTON_MAIN)
246 last_activity = current_tick;
247#endif
248 /* ignore release, allow repeat */
249 if(btn & BUTTON_REL)
250 continue;
251 if(btn & BUTTON_REPEAT)
252 btn &= ~BUTTON_REPEAT;
253 /* play -> stop loop and return mode */
254 if(btn == BUTTON_ENTER)
255 break;
256 /* left/right/up/down: change mode */
257 if(btn == BUTTON_UP || btn == BUTTON_VOL_UP)
258 mode = (mode + BOOT_COUNT - 1) % BOOT_COUNT;
259 if(btn == BUTTON_DOWN || btn == BUTTON_VOL_DOWN)
260 mode = (mode + 1) % BOOT_COUNT;
261 }
262
263 /* save mode */
264 save_boot_mode(mode);
265 return mode;
266}
267
268void error_screen(const char *msg)
269{
270 lcd_clear_display();
271 lcd_putsf(0, 0, msg);
272 lcd_update();
273}
274
275int choice_screen(const char *title, bool center, int nr_choices, const char *choices[])
276{
277 int choice = 0;
278 int max_len = 0;
279 int h;
280 lcd_getstringsize("x", NULL, &h);
281 for(int i = 0; i < nr_choices; i++)
282 {
283 int len = strlen(choices[i]);
284 if(len > max_len)
285 max_len = len;
286 }
287 char *buf = malloc(max_len + 10);
288 int top_y = 2 * h;
289 int nr_lines = (LCD_HEIGHT - top_y) / h;
290 while(true)
291 {
292 /* make sure choice is visible */
293 int offset = choice - nr_lines / 2;
294 if(offset < 0)
295 offset = 0;
296 lcd_clear_display();
297 /* display top text */
298 lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
299 display_text_center(0, title);
300 int line = 0;
301 for(int i = 0; i < nr_choices && line < nr_lines; i++)
302 {
303 if(i < offset)
304 continue;
305 if(i == choice)
306 lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
307 else
308 lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
309 sprintf(buf, "%s", choices[i]);
310 if(center)
311 display_text_center(top_y + h * line, buf);
312 else
313 lcd_putsxy(0, top_y + h * line, buf);
314 line++;
315 }
316
317 lcd_update();
318
319 /* wait for a key */
320 int btn = button_get_w_tmo(HZ / 10);
321 /* ignore release, allow repeat */
322 if(btn & BUTTON_REL)
323 continue;
324 if(btn & BUTTON_REPEAT)
325 btn &= ~BUTTON_REPEAT;
326 /* play -> stop loop and return mode */
327 if(btn == BUTTON_ENTER)
328 {
329 free(buf);
330 return btn == BUTTON_ENTER ? choice : -1;
331 }
332 /* left/right/up/down: change mode */
333 if(btn == BUTTON_UP || btn == BUTTON_VOL_UP)
334 choice = (choice + nr_choices - 1) % nr_choices;
335 if(btn == BUTTON_DOWN || btn == BUTTON_VOL_DOWN)
336 choice = (choice + 1) % nr_choices;
337 }
338}
339
340void run_file(const char *name)
341{
342 char *dirname = "/mnt/sd_0/";
343 char *buf = malloc(strlen(dirname) + strlen(name) + 1);
344 sprintf(buf, "%s%s", dirname, name);
345
346 lcd_clear_display();
347 lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
348 lcd_putsf(0, 0, "Running %s", name);
349 lcd_update();
350
351 pid_t pid = fork();
352 if(pid == 0)
353 {
354 execlp("sh", "sh", buf, NULL);
355 _exit(42);
356 }
357 int status;
358 waitpid(pid, &status, 0);
359 if(WIFEXITED(status))
360 {
361 lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
362 lcd_putsf(0, 1, "program returned %d", WEXITSTATUS(status));
363 }
364 else
365 {
366 lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
367 lcd_putsf(0, 1, "an error occured: %x", status);
368 }
369 lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
370 lcd_putsf(0, 3, "Press any key or wait");
371 lcd_update();
372 /* wait a small time */
373 sleep(HZ);
374 /* ignore event */
375 while(button_get(false) != 0) {}
376 /* wait for any key or timeout */
377 button_get_w_tmo(4 * HZ);
378}
379
380void run_script_menu(void)
381{
382 const char **entries = NULL;
383 int nr_entries = 0;
384 DIR *dir = opendir("/mnt/sd_0");
385 struct dirent *ent;
386 while((ent = readdir(dir)))
387 {
388 if(ent->d_type != DT_REG)
389 continue;
390 entries = realloc(entries, (nr_entries + 1) * sizeof(const char *));
391 entries[nr_entries++] = strdup(ent->d_name);
392 }
393 closedir(dir);
394 int idx = choice_screen("RUN SCRIPT", false, nr_entries, entries);
395 if(idx >= 0)
396 run_file(entries[idx]);
397 for(int i = 0; i < nr_entries; i++)
398 free((char *)entries[i]);
399 free(entries);
400}
401
402static void adb(int start)
403{
404 pid_t pid = fork();
405 if(pid == 0)
406 {
407 execlp("/etc/init.d/K90adb", "K90adb", start ? "start" : "stop", NULL);
408 _exit(42);
409 }
410 int status;
411 waitpid(pid, &status, 0);
412#if 0
413 if(WIFEXITED(status))
414 {
415 lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
416 lcd_putsf(0, 1, "program returned %d", WEXITSTATUS(status));
417 }
418 else
419 {
420 lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
421 lcd_putsf(0, 1, "an error occured: %x", status);
422 }
423#endif
424}
425
426static void tools_screen(void)
427{
428 const char *choices[] = {"ADB start", "ADB stop", "Run script", "Restart", "Shutdown"};
429 int choice = choice_screen("TOOLS MENU", true, 5, choices);
430 if(choice == 0)
431 {
432 /* run service menu */
433 printf("Starting ADB service...\n");
434 fflush(stdout);
435 adb(1);
436 }
437 else if(choice == 1)
438 {
439 printf("Stopping ADB service...\n");
440 fflush(stdout);
441 adb(0);
442 }
443 else if(choice == 2)
444 {
445 run_script_menu();
446 }
447 else if(choice == 3)
448 system_reboot();
449 else if(choice == 4)
450 power_off();
451}
452
453#if 0
454/* open log file */
455static int open_log(void)
456{
457 /* open regular log file */
458 int fd = open("/mnt/sd_0/rockbox.log", O_RDWR | O_CREAT | O_APPEND);
459 /* get its size */
460 struct stat stat;
461 if(fstat(fd, &stat) != 0)
462 return fd; /* on error, don't do anything */
463 /* if file is too large, rename it and start a new log file */
464 if(stat.st_size < 1000000)
465 return fd;
466 close(fd);
467 /* move file */
468 rename("/mnt/sd_0/rockbox.log", "/mnt/sd_0/rockbox.log.1");
469 /* re-open the file, truncate in case the move was unsuccessful */
470 return open("/mnt/sd_0/rockbox.log", O_RDWR | O_CREAT | O_APPEND | O_TRUNC);
471}
472#endif
473
474int main(int argc, char **argv)
475{
476 (void) argc;
477 (void) argv;
478#if 0
479 /* redirect stdout and stderr to have error messages logged somewhere on the
480 * user partition */
481 int fd = open_log();
482 if(fd >= 0)
483 {
484 dup2(fd, fileno(stdout));
485 dup2(fd, fileno(stderr));
486 close(fd);
487 }
488 /* print version */
489 printf("Rockbox boot loader\n");
490 printf("Version: %s\n", rbversion);
491 printf("%s\n", MODEL_NAME);
492#endif
493
494 system_init();
495 core_allocator_init();
496 kernel_init();
497 paths_init();
498 lcd_init();
499 font_init();
500 button_init();
501 backlight_init();
502 backlight_set_brightness(DEFAULT_BRIGHTNESS_SETTING);
503
504 /* try to load the extra font we install on the device */
505 //int font_id = font_load("/usr/rockbox/fonts/20-Terminus-Bold.fnt");
506 //if(font_id >= 0)
507 // lcd_setfont(font_id);
508
509 /* run all tools menu */
510 while(true)
511 {
512 enum boot_mode mode = get_boot_mode();
513 if(mode == BOOT_USB || mode == BOOT_OF)
514 {
515#if 0
516 fflush(stdout);
517 fflush(stderr);
518 close(fileno(stdout));
519 close(fileno(stderr));
520#endif
521 /* for now the only way we have to trigger USB mode it to run the OF */
522 /* boot OF */
523 execvp("/usr/bin/hiby_player", argv);
524 error_screen("Cannot boot OF");
525 sleep(5 * HZ);
526 }
527 else if(mode == BOOT_TOOLS)
528 {
529 tools_screen();
530 }
531 else if(mode == BOOT_ROCKBOX)
532 {
533 fflush(stdout);
534#if defined(XDUOO_X3II)
535 system("/bin/cp /mnt/sd_0/.rockbox/rockbox.x3ii /tmp");
536 execl("/tmp/rockbox.x3ii", "rockbox.x3ii", NULL);
537#elif defined(XDUOO_X20)
538 system("/bin/cp /mnt/sd_0/.rockbox/rockbox.x20 /tmp");
539 execl("/tmp/rockbox.x20", "rockbox.x20", NULL);
540#endif
541 printf("execvp failed: %s\n", strerror(errno));
542 /* fallback to OF in case of failure */
543 error_screen("Cannot boot Rockbox");
544 sleep(5 * HZ);
545 }
546 else
547 {
548 printf("suspend\n");
549// nwz_power_suspend();
550 }
551 }
552 /* if we reach this point, everything failed, so return an error so that
553 * sysmgrd knows something is wrong */
554 return 1;
555}