1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 by Greg White
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
25 #include "gcc_extensions.h"
28 #include "powermgmt.h"
34 #include "backlight.h"
41 /* Show the Rockbox logo - in show_logo.c */
42 extern void show_logo(void);
45 #define TAR_HEADER_SIZE 157
47 /* Where files sent via MTP are stored */
48 static const char basedir
[] = "/Content/0b00/00/";
49 /* Can use memory after vector table up to 0x01f00000 */
50 static char * const tarbuf
= (char *)0x00000040;
51 static const size_t tarbuf_size
= 0x01f00000 - 0x00000040;
53 static void * const load_buf
= 0x00000000;
54 static const size_t load_buf_size
= 0x20000000 - 0x100000;
55 static const void * const start_addr
= 0x00000000;
57 /* Show a message + "Shutting down...", then power off the device */
58 static void display_message_and_power_off(int timeout
, const char *msg
)
62 printf("Shutting down...");
67 static void check_battery_safe(void)
69 if (battery_level_safe())
72 display_message_and_power_off(HZ
, "Battery low");
75 /* TODO: Handle charging while connected */
76 static void handle_usb(int connect_timeout
)
81 /* We need full button and backlight handling now */
86 /* Start the USB driver */
88 usb_start_monitoring();
90 /* Wait for threads to connect or cable is pulled */
91 printf("USB: Connecting");
93 if (connect_timeout
!= TIMEOUT_BLOCK
)
94 end_tick
= current_tick
+ connect_timeout
;
98 button
= button_get_w_tmo(HZ
/2);
100 if (button
== SYS_USB_CONNECTED
)
103 if (connect_timeout
!= TIMEOUT_BLOCK
&&
104 TIME_AFTER(current_tick
, end_tick
))
106 /* Timed out waiting for the connect - will happen when connected
107 * to a charger through the USB port */
108 printf("USB: Timed out");
112 if (usb_plugged() == USB_EXTRACTED
)
113 break; /* Cable pulled */
116 if (button
== SYS_USB_CONNECTED
)
118 /* Switch to verbose mode if not in it so that the status updates
121 /* Got the message - wait for disconnect */
122 printf("Bootloader USB mode");
124 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
128 button
= button_get_w_tmo(HZ
/2);
129 if (button
== SYS_USB_DISCONNECTED
)
132 check_battery_safe();
136 /* Sleep a little to let the backlight ramp up */
140 /* Put drivers initialized for USB connection into a known state */
146 static void untar(int tar_fd
)
148 char header
[TAR_HEADER_SIZE
];
153 size_t size
= filesize(tar_fd
);
155 if (size
> tarbuf_size
)
157 printf("tar file too large"); /* Paranoid but proper */
161 ret
= read(tar_fd
, tarbuf
, filesize(tar_fd
));
164 printf("couldn't read tar file (%d)", ret
);
171 memcpy(header
, ptr
, TAR_HEADER_SIZE
);
173 if (*header
== '\0') /* Check for EOF */
176 /* Parse the size field */
178 for (i
= 124 ; i
< 124 + 11 ; i
++) {
179 size
= (8 * size
) + header
[i
] - '0';
182 /* Skip rest of header */
185 /* Make the path absolute */
187 strcat(path
, header
);
189 if (header
[156] == '0') /* file */
193 fd
= creat(path
, 0666);
196 printf("failed to create file (%d)", fd
);
200 wc
= write(fd
, ptr
, size
);
203 printf("write failed (%d)", wc
);
208 ptr
+= (size
+ TAR_CHUNK
-1) & (~(TAR_CHUNK
-1));
210 else if (header
[156] == '5') /* directory */
214 /* Remove the trailing slash */
215 if (path
[strlen(path
) - 1] == '/')
216 path
[strlen(path
) - 1] = '\0';
220 if (ret
< 0 && ret
!= -4)
222 printf("failed to create dir (%d)", ret
);
228 /* Look for a tar file or rockbox binary in the MTP directory */
229 static void handle_untar(void)
234 struct dirent_uncached
* entry
;
239 dir
= opendir_uncached(basedir
);
241 while ((entry
= readdir_uncached(dir
)))
243 if (*entry
->d_name
== '.')
246 snprintf(buf
, sizeof(buf
), "%s%s", basedir
, entry
->d_name
);
247 fd
= open(buf
, O_RDONLY
);
252 /* Check whether the file is a rockbox binary. */
253 lseek(fd
, 4, SEEK_SET
);
254 rc
= read(fd
, model
, 4);
258 if (strcmp(model
, "gigs") == 0)
261 printf("Found rockbox binary. Moving...");
263 remove( BOOTDIR
"/" BOOTFILE
);
264 int ret
= rename(buf
, BOOTDIR
"/" BOOTFILE
);
265 printf("returned %d", ret
);
271 /* Check whether the file is a tar file. */
272 lseek(fd
, 257, SEEK_SET
);
273 rc
= read(fd
, tarstring
, 5);
277 if (strcmp(tarstring
, "ustar") == 0)
280 printf("Found tar file. Unarchiving...");
281 lseek(fd
, 0, SEEK_SET
);
284 printf("Removing tar file");
294 /* Try to load the firmware and run it */
295 static void NORETURN_ATTR
handle_firmware_load(void)
297 int rc
= load_firmware(load_buf
, BOOTFILE
, load_buf_size
);
300 error(EBOOTFILE
, rc
, true);
302 /* Pause to look at messages */
305 int button
= button_read_device();
307 /* Ignore settings reset */
308 if (button
== BUTTON_NONE
|| button
== BUTTON_MENU
)
313 check_battery_safe();
315 /* If the disk powers off, the firmware will lock at startup */
319 /* Put drivers into a known state */
320 button_close_device();
322 system_prepare_fw_start();
326 commit_discard_idcache();
327 asm volatile ("bx %0": : "r"(start_addr
));
343 /* Keep button_device_init early to delay calls to button_read_device */
344 button_init_device();
352 display_message_and_power_off(HZ
, "Hold switch on");
354 if (button_read_device() != BUTTON_NONE
)
357 printf("Gigabeat S Rockbox Bootloader");
358 printf("Version " RBVERSION
);
361 batt
= _battery_voltage();
362 printf("Battery: %d.%03d V", batt
/ 1000, batt
% 1000);
363 check_battery_safe();
367 error(EATA
, rc
, true);
371 rc
= disk_mount_all();
373 error(EDISK
, rc
, true);
375 printf("Init complete");
377 /* Do USB first since a tar or binary could be added to the MTP directory
378 * at the time and we can untar or move after unplugging. */
379 if (usb_plugged() == USB_INSERTED
)
383 handle_firmware_load(); /* No return */