diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2008-05-10 18:00:11 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2008-05-10 18:00:11 +0000 |
commit | 80278e45aa79cee66596c257c5d3870765233e00 (patch) | |
tree | 3a974d996f2bcf7f176175c904cf22edf9132ac9 /bootloader/gigabeat-s.c | |
parent | 6e812b1d2e7941ee1f3e7abdbc2a2eba601f17e3 (diff) | |
download | rockbox-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/gigabeat-s.c')
-rw-r--r-- | bootloader/gigabeat-s.c | 329 |
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 */ |
40 | static char * const tarbuf = (char *)0x00000040; | 44 | static char * const tarbuf = (char *)0x00000040; |
41 | static const size_t tarbuf_size = 0x01f00000 - 0x00000040; | 45 | static const size_t tarbuf_size = 0x01f00000 - 0x00000040; |
42 | /* Queue to get notifications when in USB mode */ | 46 | /* Firmware data */ |
43 | static struct event_queue usb_wait_queue; | 47 | static void * const load_buf = 0x00000000; |
48 | static const size_t load_buf_size = 0x20000000 - 0x100000; | ||
49 | static const void * const start_addr = 0x00000000; | ||
44 | 50 | ||
45 | static void show_splash(int timeout, const char *msg) | 51 | static 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 | ||
62 | static 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 */ | ||
87 | static 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 | |||
54 | static void untar(int tar_fd) | 151 | static 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 | ||
134 | void main(void) | 233 | /* Look for a tar file or rockbox binary in the MTP directory */ |
234 | static 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; | 298 | static 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 | ||
325 | static 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 | |||
332 | void 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 | } | ||