summaryrefslogtreecommitdiff
path: root/bootloader
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-05-10 18:00:11 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-05-10 18:00:11 +0000
commit80278e45aa79cee66596c257c5d3870765233e00 (patch)
tree3a974d996f2bcf7f176175c904cf22edf9132ac9 /bootloader
parent6e812b1d2e7941ee1f3e7abdbc2a2eba601f17e3 (diff)
downloadrockbox-80278e45aa79cee66596c257c5d3870765233e00.tar.gz
rockbox-80278e45aa79cee66596c257c5d3870765233e00.zip
Bring Gigabeat S bootloader one step close to a release version.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17442 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'bootloader')
-rw-r--r--bootloader/gigabeat-s.c329
1 files changed, 209 insertions, 120 deletions
diff --git a/bootloader/gigabeat-s.c b/bootloader/gigabeat-s.c
index 30c2955c19..dfe13e4540 100644
--- a/bootloader/gigabeat-s.c
+++ b/bootloader/gigabeat-s.c
@@ -21,11 +21,15 @@
21#include <sprintf.h> 21#include <sprintf.h>
22#include "kernel.h" 22#include "kernel.h"
23#include "string.h" 23#include "string.h"
24#include "adc.h"
25#include "powermgmt.h"
24#include "ata.h" 26#include "ata.h"
25#include "dir.h" 27#include "dir.h"
26#include "disk.h" 28#include "disk.h"
27#include "common.h" 29#include "common.h"
30#include "backlight.h"
28#include "usb.h" 31#include "usb.h"
32#include "button.h"
29#include "font.h" 33#include "font.h"
30#include "lcd.h" 34#include "lcd.h"
31#include "usb-target.h" 35#include "usb-target.h"
@@ -39,11 +43,15 @@ static const char basedir[] = "/Content/0b00/00/";
39/* Can use memory after vector table up to 0x01f00000 */ 43/* Can use memory after vector table up to 0x01f00000 */
40static char * const tarbuf = (char *)0x00000040; 44static char * const tarbuf = (char *)0x00000040;
41static const size_t tarbuf_size = 0x01f00000 - 0x00000040; 45static const size_t tarbuf_size = 0x01f00000 - 0x00000040;
42/* Queue to get notifications when in USB mode */ 46/* Firmware data */
43static struct event_queue usb_wait_queue; 47static void * const load_buf = 0x00000000;
48static const size_t load_buf_size = 0x20000000 - 0x100000;
49static const void * const start_addr = 0x00000000;
44 50
45static void show_splash(int timeout, const char *msg) 51static void show_splash(int timeout, const char *msg)
46{ 52{
53 backlight_on();
54 reset_screen();
47 lcd_putsxy( (LCD_WIDTH - (SYSFONT_WIDTH * strlen(msg))) / 2, 55 lcd_putsxy( (LCD_WIDTH - (SYSFONT_WIDTH * strlen(msg))) / 2,
48 (LCD_HEIGHT - SYSFONT_HEIGHT) / 2, msg); 56 (LCD_HEIGHT - SYSFONT_HEIGHT) / 2, msg);
49 lcd_update(); 57 lcd_update();
@@ -51,6 +59,95 @@ static void show_splash(int timeout, const char *msg)
51 sleep(timeout); 59 sleep(timeout);
52} 60}
53 61
62static bool pause_if_button_pressed(bool pre_usb)
63{
64 while (1)
65 {
66 int button = button_read_device();
67
68 if (pre_usb && !usb_plugged())
69 return false;
70
71 /* Exit if no button or only the menu (settings reset) button */
72 switch (button)
73 {
74 case BUTTON_MENU:
75 case BUTTON_NONE:
76 return true;
77 }
78
79 sleep(HZ/5);
80
81 /* If the disk powers off, the firmware will lock at startup */
82 ata_spin();
83 }
84}
85
86/* TODO: Handle charging while connected */
87static void handle_usb(void)
88{
89 int button;
90
91 /* Check if plugged and pause to look at messages. If the cable was pulled
92 * while waiting, proceed as if it never was plugged. */
93 if (!usb_plugged() || !pause_if_button_pressed(true))
94 {
95 /* Bang on the controller */
96 usb_init_device();
97 return;
98 }
99
100 /** Enter USB mode **/
101
102 /* We need full button and backlight handling now */
103 backlight_init();
104 button_init();
105
106 /* Start the USB driver */
107 usb_init();
108 usb_start_monitoring();
109
110 /* Wait for threads to connect or cable is pulled */
111 show_splash(HZ/2, "Waiting for USB");
112
113 while (1)
114 {
115 button = button_get_w_tmo(HZ/2);
116
117 if (button == SYS_USB_CONNECTED)
118 break; /* Hit */
119
120 if (!usb_plugged())
121 break; /* Cable pulled */
122 }
123
124 if (button == SYS_USB_CONNECTED)
125 {
126 /* Got the message - wait for disconnect */
127 show_splash(0, "Bootloader USB mode");
128
129 usb_acknowledge(SYS_USB_CONNECTED_ACK);
130
131 while (1)
132 {
133 button = button_get(true);
134 if (button == SYS_USB_DISCONNECTED)
135 {
136 usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
137 break;
138 }
139 }
140 }
141
142 /* Put drivers initialized for USB connection into a known state */
143 backlight_on();
144 usb_close();
145 button_close();
146 backlight_close();
147
148 reset_screen();
149}
150
54static void untar(int tar_fd) 151static void untar(int tar_fd)
55{ 152{
56 char header[TAR_HEADER_SIZE]; 153 char header[TAR_HEADER_SIZE];
@@ -60,13 +157,15 @@ static void untar(int tar_fd)
60 int ret; 157 int ret;
61 size_t size = filesize(tar_fd); 158 size_t size = filesize(tar_fd);
62 159
63 if (size > tarbuf_size) { 160 if (size > tarbuf_size)
161 {
64 printf("tar file too large"); /* Paranoid but proper */ 162 printf("tar file too large"); /* Paranoid but proper */
65 return; 163 return;
66 } 164 }
67 165
68 ret = read(tar_fd, tarbuf, filesize(tar_fd)); 166 ret = read(tar_fd, tarbuf, filesize(tar_fd));
69 if (ret < 0) { 167 if (ret < 0)
168 {
70 printf("couldn't read tar file (%d)", ret); 169 printf("couldn't read tar file (%d)", ret);
71 return; 170 return;
72 } 171 }
@@ -131,153 +230,91 @@ static void untar(int tar_fd)
131 } 230 }
132} 231}
133 232
134void main(void) 233/* Look for a tar file or rockbox binary in the MTP directory */
234static void handle_untar(void)
135{ 235{
136 char buf[MAX_PATH]; 236 char buf[MAX_PATH];
137 char tarstring[6]; 237 char tarstring[6];
138 char model[5]; 238 char model[5];
139 239 struct dirent_uncached* entry;
140 /* Flush and invalidate all caches (because vectors were written) */ 240 DIR_UNCACHED* dir;
141 invalidate_icache(); 241 int fd;
142
143 lcd_clear_display();
144 printf("Gigabeat S Rockbox Bootloader v.00000013");
145 system_init();
146 kernel_init();
147 printf("kernel init done");
148 int rc; 242 int rc;
149 243
150 enable_interrupt(IRQ_FIQ_STATUS); 244 dir = opendir_uncached(basedir);
151 245
152 rc = ata_init(); 246 while ((entry = readdir_uncached(dir)))
153 if(rc)
154 { 247 {
155 reset_screen(); 248 if (*entry->d_name == '.')
156 error(EATA, rc); 249 continue;
157 }
158 printf("ata init done");
159 250
160 disk_init(); 251 snprintf(buf, sizeof(buf), "%s%s", basedir, entry->d_name);
161 printf("disk init done"); 252 fd = open(buf, O_RDONLY);
162 253
163 rc = disk_mount_all(); 254 if (fd < 0)
164 if (rc<=0) 255 continue;
165 {
166 error(EDISK,rc);
167 }
168 256
169 /* Look for a tar file */ 257 /* Check whether the file is a rockbox binary. */
170 struct dirent_uncached* entry; 258 lseek(fd, 4, SEEK_SET);
171 DIR_UNCACHED* dir; 259 rc = read(fd, model, 4);
172 int fd; 260 if (rc == 4)
173 dir = opendir_uncached(basedir);
174 while ((entry = readdir_uncached(dir)))
175 {
176 if (*entry->d_name != '.')
177 { 261 {
178 snprintf(buf, sizeof(buf), "%s%s", basedir, entry->d_name); 262 model[4] = 0;
179 fd = open(buf, O_RDONLY); 263 if (strcmp(model, "gigs") == 0)
180 if (fd >= 0)
181 { 264 {
182 /* Check whether the file is a rockbox binary. */ 265 printf("Found rockbox binary. Moving...");
183 lseek(fd, 4, SEEK_SET);
184 rc = read(fd, model, 4);
185 if (rc == 4)
186 {
187 model[4] = 0;
188 if (strcmp(model, "gigs") == 0)
189 {
190 printf("Found rockbox binary. Moving...");
191 close(fd);
192 remove("/.rockbox/rockbox.gigabeat");
193 int ret = rename(buf, "/.rockbox/rockbox.gigabeat");
194 printf("returned %d", ret);
195 sleep(HZ);
196 break;
197 }
198 }
199
200 /* Check whether the file is a tar file. */
201 lseek(fd, 257, SEEK_SET);
202 rc = read(fd, tarstring, 5);
203 if (rc == 5)
204 {
205 tarstring[5] = 0;
206 if (strcmp(tarstring, "ustar") == 0)
207 {
208 printf("Found tar file. Unarchiving...");
209 lseek(fd, 0, SEEK_SET);
210 untar(fd);
211 close(fd);
212 printf("Removing tar file");
213 remove(buf);
214 break;
215 }
216 }
217 close(fd); 266 close(fd);
267 remove("/.rockbox/rockbox.gigabeat");
268 int ret = rename(buf, "/.rockbox/rockbox.gigabeat");
269 printf("returned %d", ret);
270 sleep(HZ);
271 break;
218 } 272 }
219 } 273 }
220 }
221
222 if (usb_plugged())
223 {
224 /* Enter USB mode */
225 struct queue_event ev;
226 queue_init(&usb_wait_queue, true);
227
228 /* Start the USB driver */
229 usb_init();
230 usb_start_monitoring();
231
232 /* Wait for threads to connect or cable is pulled */
233 reset_screen();
234 show_splash(0, "Waiting for USB");
235
236 while (1)
237 {
238 queue_wait_w_tmo(&usb_wait_queue, &ev, HZ/2);
239
240 if (ev.id == SYS_USB_CONNECTED)
241 break; /* Hit */
242
243 if (!usb_plugged())
244 break; /* Cable pulled */
245 }
246 274
247 if (ev.id == SYS_USB_CONNECTED) 275 /* Check whether the file is a tar file. */
276 lseek(fd, 257, SEEK_SET);
277 rc = read(fd, tarstring, 5);
278 if (rc == 5)
248 { 279 {
249 /* Got the message - wait for disconnect */ 280 tarstring[5] = 0;
250 reset_screen(); 281 if (strcmp(tarstring, "ustar") == 0)
251 show_splash(0, "Bootloader USB mode"); 282 {
252 283 printf("Found tar file. Unarchiving...");
253 usb_acknowledge(SYS_USB_CONNECTED_ACK); 284 lseek(fd, 0, SEEK_SET);
254 usb_wait_for_disconnect(&usb_wait_queue); 285 untar(fd);
286 close(fd);
287 printf("Removing tar file");
288 remove(buf);
289 break;
290 }
255 } 291 }
256 292
257 /* No more monitoring */ 293 close(fd);
258 usb_stop_monitoring();
259
260 reset_screen();
261 }
262 else
263 {
264 /* Bang on the controller */
265 usb_init_device();
266 } 294 }
295}
267 296
268 unsigned char *loadbuffer = (unsigned char *)0x0; 297/* Try to load the firmware and run it */
269 int buffer_size = 31*1024*1024; 298static void __attribute__((noreturn)) handle_firmware_load(void)
299{
300 int rc = load_firmware(load_buf, "/.rockbox/rockbox.gigabeat",
301 load_buf_size);
270 302
271 rc = load_firmware(loadbuffer, "/.rockbox/rockbox.gigabeat", buffer_size);
272 if(rc < 0) 303 if(rc < 0)
273 error(EBOOTFILE, rc); 304 error(EBOOTFILE, rc);
274 305
306 /* Pause to look at messages */
307 pause_if_button_pressed(false);
308
309 /* Put drivers into a known state */
310 button_close_device();
311 ata_close();
275 system_prepare_fw_start(); 312 system_prepare_fw_start();
276 313
277 if (rc == EOK) 314 if (rc == EOK)
278 { 315 {
279 invalidate_icache(); 316 invalidate_icache();
280 asm volatile ("bx %0": : "r"(loadbuffer)); 317 asm volatile ("bx %0": : "r"(start_addr));
281 } 318 }
282 319
283 /* Halt */ 320 /* Halt */
@@ -285,3 +322,55 @@ void main(void)
285 core_idle(); 322 core_idle();
286} 323}
287 324
325static void check_battery(void)
326{
327 int batt = battery_adc_voltage();
328 printf("Battery: %d.%03d V", batt / 1000, batt % 1000);
329 /* TODO: warn on low battery or shut down */
330}
331
332void main(void)
333{
334 int rc;
335
336 /* Flush and invalidate all caches (because vectors were written) */
337 invalidate_icache();
338
339 lcd_clear_display();
340 printf("Gigabeat S Rockbox Bootloader");
341 printf("Version %s", version);
342 system_init();
343 kernel_init();
344
345 enable_interrupt(IRQ_FIQ_STATUS);
346
347 /* Initialize KPP so we can poll the button states */
348 button_init_device();
349
350 adc_init();
351
352 check_battery();
353
354 rc = ata_init();
355 if(rc)
356 {
357 reset_screen();
358 error(EATA, rc);
359 }
360
361 disk_init();
362
363 rc = disk_mount_all();
364 if (rc<=0)
365 {
366 error(EDISK,rc);
367 }
368
369 printf("Init complete");
370
371 /* Do USB first since a tar or binary could be added to the MTP directory
372 * at the time and we can untar or move after unplugging. */
373 handle_usb();
374 handle_untar();
375 handle_firmware_load(); /* No return */
376}