diff options
Diffstat (limited to 'bootloader/ipod.c')
-rw-r--r-- | bootloader/ipod.c | 309 |
1 files changed, 69 insertions, 240 deletions
diff --git a/bootloader/ipod.c b/bootloader/ipod.c index b1b3114ac9..73b4fffc71 100644 --- a/bootloader/ipod.c +++ b/bootloader/ipod.c | |||
@@ -39,16 +39,22 @@ | |||
39 | #include "panic.h" | 39 | #include "panic.h" |
40 | #include "power.h" | 40 | #include "power.h" |
41 | #include "file.h" | 41 | #include "file.h" |
42 | #include "common.h" | ||
42 | 43 | ||
43 | #define XSC(X) #X | 44 | #define XSC(X) #X |
44 | #define SC(X) XSC(X) | 45 | #define SC(X) XSC(X) |
45 | 46 | ||
46 | #if (CONFIG_CPU == PP5020) | 47 | /* Maximum allowed firmware image size. The largest known current |
47 | #define DRAM_START 0x10000000 | 48 | (December 2006) firmware is about 7.5MB (Apple's firmware for the ipod video) |
48 | #else | 49 | so we set this to 8MB. */ |
49 | #define IPOD_LCD_BASE 0xc0001000 | 50 | #define MAX_LOADSIZE (8*1024*1024) |
50 | #define DRAM_START 0x28000000 | 51 | |
51 | #endif | 52 | /* A buffer to load the Linux kernel or Rockbox into */ |
53 | unsigned char *loadbuffer = (unsigned char *)DRAM_START; | ||
54 | |||
55 | /* Bootloader version */ | ||
56 | char version[] = APPSVERSION; | ||
57 | |||
52 | #define IPOD_HW_REVISION (*((volatile unsigned long*)(0x00002084))) | 58 | #define IPOD_HW_REVISION (*((volatile unsigned long*)(0x00002084))) |
53 | 59 | ||
54 | /* We copy the hardware revision to the last four bytes of SDRAM and then | 60 | /* We copy the hardware revision to the last four bytes of SDRAM and then |
@@ -61,17 +67,6 @@ | |||
61 | #define BUTTON_PLAY 4 | 67 | #define BUTTON_PLAY 4 |
62 | #define BUTTON_HOLD 5 | 68 | #define BUTTON_HOLD 5 |
63 | 69 | ||
64 | /* Size of the buffer to store the loaded Rockbox/Linux/AppleOS image */ | ||
65 | |||
66 | /* The largest known current (December 2006) firmware is about 7.5MB | ||
67 | (Apple's firmware for the ipod video) so we set this to 8MB. */ | ||
68 | |||
69 | #define MAX_LOADSIZE (8*1024*1024) | ||
70 | |||
71 | char version[] = APPSVERSION; | ||
72 | |||
73 | int line=0; | ||
74 | |||
75 | #if CONFIG_KEYPAD == IPOD_4G_PAD && !defined(IPOD_MINI) | 70 | #if CONFIG_KEYPAD == IPOD_4G_PAD && !defined(IPOD_MINI) |
76 | /* check if number of seconds has past */ | 71 | /* check if number of seconds has past */ |
77 | int timer_check(int clock_start, unsigned int usecs) | 72 | int timer_check(int clock_start, unsigned int usecs) |
@@ -157,54 +152,6 @@ int opto_keypad_read(void) | |||
157 | } | 152 | } |
158 | #endif | 153 | #endif |
159 | 154 | ||
160 | char *strerror(int error) | ||
161 | { | ||
162 | switch(error) | ||
163 | { | ||
164 | case 0: | ||
165 | return "OK"; | ||
166 | case -1: | ||
167 | return "File not found"; | ||
168 | case -2: | ||
169 | return "Read failed (chksum)"; | ||
170 | case -3: | ||
171 | return "Read failed (model)"; | ||
172 | case -4: | ||
173 | return "Read failed (image)"; | ||
174 | case -5: | ||
175 | return "Bad checksum"; | ||
176 | case -6: | ||
177 | return "File too big"; | ||
178 | default: | ||
179 | return "Unknown"; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | char printfbuf[256]; | ||
184 | |||
185 | void reset_screen(void) | ||
186 | { | ||
187 | lcd_clear_display(); | ||
188 | line = 0; | ||
189 | } | ||
190 | |||
191 | void printf(const char *format, ...) | ||
192 | { | ||
193 | int len; | ||
194 | unsigned char *ptr; | ||
195 | va_list ap; | ||
196 | va_start(ap, format); | ||
197 | |||
198 | ptr = printfbuf; | ||
199 | len = vsnprintf(ptr, sizeof(printfbuf), format, ap); | ||
200 | va_end(ap); | ||
201 | |||
202 | lcd_puts(0, line++, ptr); | ||
203 | lcd_update(); | ||
204 | if(line >= (LCD_HEIGHT/SYSFONT_HEIGHT)) | ||
205 | line = 0; | ||
206 | } | ||
207 | |||
208 | static int key_pressed(void) | 155 | static int key_pressed(void) |
209 | { | 156 | { |
210 | unsigned char state; | 157 | unsigned char state; |
@@ -240,101 +187,9 @@ bool button_hold(void) | |||
240 | return (GPIOA_INPUT_VAL & 0x20)?false:true; | 187 | return (GPIOA_INPUT_VAL & 0x20)?false:true; |
241 | } | 188 | } |
242 | 189 | ||
243 | int load_rockbox(unsigned char* buf, char* firmware) | ||
244 | { | ||
245 | int fd; | ||
246 | int rc; | ||
247 | int len; | ||
248 | unsigned long chksum; | ||
249 | char model[5]; | ||
250 | unsigned long sum; | ||
251 | int i; | ||
252 | char filename[MAX_PATH]; | ||
253 | |||
254 | snprintf(filename,sizeof(filename),"/.rockbox/%s",firmware); | ||
255 | fd = open(filename, O_RDONLY); | ||
256 | if(fd < 0) | ||
257 | { | ||
258 | snprintf(filename,sizeof(filename),"/%s",firmware); | ||
259 | fd = open(filename, O_RDONLY); | ||
260 | if(fd < 0) | ||
261 | return -1; | ||
262 | } | ||
263 | |||
264 | len = filesize(fd) - 8; | ||
265 | |||
266 | if (len > MAX_LOADSIZE) | ||
267 | return -6; | ||
268 | |||
269 | lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET); | ||
270 | |||
271 | rc = read(fd, &chksum, 4); | ||
272 | chksum=betoh32(chksum); /* Rockbox checksums are big-endian */ | ||
273 | if(rc < 4) | ||
274 | return -2; | ||
275 | |||
276 | rc = read(fd, model, 4); | ||
277 | if(rc < 4) | ||
278 | return -3; | ||
279 | |||
280 | model[4] = 0; | ||
281 | |||
282 | printf("Model: %s", model); | ||
283 | printf("Checksum: %x", chksum); | ||
284 | printf("Loading %s", firmware); | ||
285 | |||
286 | lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET); | ||
287 | |||
288 | rc = read(fd, buf, len); | ||
289 | if(rc < len) | ||
290 | return -4; | ||
291 | |||
292 | close(fd); | ||
293 | |||
294 | sum = MODEL_NUMBER; | ||
295 | |||
296 | for(i = 0;i < len;i++) { | ||
297 | sum += buf[i]; | ||
298 | } | ||
299 | |||
300 | printf("Sum: %x", sum); | ||
301 | |||
302 | if(sum != chksum) | ||
303 | return -5; | ||
304 | |||
305 | return len; | ||
306 | } | ||
307 | |||
308 | |||
309 | int load_linux(unsigned char* buf) { | ||
310 | int fd; | ||
311 | int rc; | ||
312 | int len; | ||
313 | |||
314 | fd=open("/linux.bin",O_RDONLY); | ||
315 | if (fd < 0) | ||
316 | return -1; | ||
317 | |||
318 | len=filesize(fd); | ||
319 | if (len > MAX_LOADSIZE) | ||
320 | return -6; | ||
321 | |||
322 | rc=read(fd,buf,len); | ||
323 | |||
324 | if (rc < len) | ||
325 | return -4; | ||
326 | |||
327 | printf("Loaded Linux: %d bytes", len); | ||
328 | |||
329 | return len; | ||
330 | } | ||
331 | |||
332 | |||
333 | /* A buffer to load the Linux kernel or Rockbox into */ | ||
334 | unsigned char loadbuffer[MAX_LOADSIZE]; | ||
335 | |||
336 | void fatal_error(void) | 190 | void fatal_error(void) |
337 | { | 191 | { |
192 | extern int line; | ||
338 | bool holdstatus=false; | 193 | bool holdstatus=false; |
339 | 194 | ||
340 | /* System font is 6 pixels wide */ | 195 | /* System font is 6 pixels wide */ |
@@ -423,7 +278,6 @@ void* main(void) | |||
423 | button_init(); | 278 | button_init(); |
424 | #endif | 279 | #endif |
425 | 280 | ||
426 | line=0; | ||
427 | 281 | ||
428 | lcd_setfont(FONT_SYSFIXED); | 282 | lcd_setfont(FONT_SYSFIXED); |
429 | 283 | ||
@@ -459,95 +313,74 @@ void* main(void) | |||
459 | printf("Partition 1: 0x%02x %ld MB", | 313 | printf("Partition 1: 0x%02x %ld MB", |
460 | pinfo->type, pinfo->size / 2048); | 314 | pinfo->type, pinfo->size / 2048); |
461 | 315 | ||
462 | /* See if there is an Apple firmware image in RAM */ | 316 | |
463 | haveretailos = (memcmp((void*)(DRAM_START+0x20),"portalplayer",12)==0); | 317 | /* Check for a keypress */ |
464 | 318 | i=key_pressed(); | |
465 | /* We don't load Rockbox if the hold button is enabled. */ | ||
466 | if (!button_was_held) { | ||
467 | /* Check for a keypress */ | ||
468 | i=key_pressed(); | ||
469 | |||
470 | if ((i!=BUTTON_MENU) && (i!=BUTTON_PLAY)) { | ||
471 | printf("Loading Rockbox..."); | ||
472 | rc=load_rockbox(loadbuffer, BOOTFILE); | ||
473 | if (rc < 0) { | ||
474 | printf("Error!"); | ||
475 | printf("Can't load rockbox.ipod:"); | ||
476 | printf(strerror(rc)); | ||
477 | } else { | ||
478 | printf("Rockbox loaded."); | ||
479 | memcpy((void*)DRAM_START,loadbuffer,rc); | ||
480 | return (void*)DRAM_START; | ||
481 | } | ||
482 | } | ||
483 | 319 | ||
484 | if (i==BUTTON_PLAY) { | 320 | if (button_was_held || (i==BUTTON_MENU)) { |
485 | printf("Loading Linux..."); | 321 | /* If either the hold switch was on, or the Menu button was held, then |
486 | rc=load_linux(loadbuffer); | 322 | try the Apple firmware */ |
487 | if (rc < 0) { | 323 | |
488 | printf("Error!"); | 324 | printf("Loading original firmware..."); |
489 | printf("Can't load linux.bin:"); | 325 | |
490 | printf(strerror(rc)); | 326 | /* First try an apple_os.ipod file on the FAT32 partition |
491 | } else { | 327 | (either in .rockbox or the root) |
492 | memcpy((void*)DRAM_START,loadbuffer,rc); | 328 | */ |
329 | |||
330 | rc=load_firmware(loadbuffer, "apple_os.ipod", MAX_LOADSIZE); | ||
331 | |||
332 | if(rc==EFILE_NOT_FOUND) { | ||
333 | /* If apple_os.ipod doesn't exist, then check if there is an Apple | ||
334 | firmware image in RAM */ | ||
335 | haveretailos = (memcmp((void*)(DRAM_START+0x20),"portalplayer",12)==0); | ||
336 | if (haveretailos) { | ||
337 | /* We have a copy of the retailos in RAM, lets just run it. */ | ||
493 | return (void*)DRAM_START; | 338 | return (void*)DRAM_START; |
494 | } | 339 | } |
340 | } else if (rc < EFILE_NOT_FOUND) { | ||
341 | printf("Error!"); | ||
342 | printf("Can't load apple_os.ipod:"); | ||
343 | printf(strerror(rc)); | ||
344 | } else if (rc > 0) { | ||
345 | printf("apple_os.ipod loaded."); | ||
346 | return (void*)DRAM_START; | ||
347 | } | ||
348 | |||
349 | /* Everything failed - just loop forever */ | ||
350 | printf("No RetailOS detected"); | ||
351 | |||
352 | } else if (i==BUTTON_PLAY) { | ||
353 | printf("Loading Linux..."); | ||
354 | rc=load_raw_firmware(loadbuffer, "/linux.bin", MAX_LOADSIZE); | ||
355 | if (rc < EOK) { | ||
356 | printf("Error!"); | ||
357 | printf("Can't load linux.bin:"); | ||
358 | printf(strerror(rc)); | ||
359 | } else { | ||
360 | return (void*)DRAM_START; | ||
361 | } | ||
362 | } else { | ||
363 | printf("Loading Rockbox..."); | ||
364 | rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE); | ||
365 | if (rc < EOK) { | ||
366 | printf("Error!"); | ||
367 | printf("Can't load rockbox.ipod:"); | ||
368 | printf(strerror(rc)); | ||
369 | } else { | ||
370 | printf("Rockbox loaded."); | ||
371 | return (void*)DRAM_START; | ||
495 | } | 372 | } |
496 | } | 373 | } |
497 | 374 | ||
498 | 375 | /* If we get to here, then we haven't been able to load any firmware */ | |
499 | /* If either the hold switch was on, or loading Rockbox/IPL | ||
500 | failed, then try the Apple firmware */ | ||
501 | |||
502 | printf("Loading original firmware..."); | ||
503 | |||
504 | /* First try an apple_os.ipod file on the FAT32 partition | ||
505 | (either in .rockbox or the root) | ||
506 | */ | ||
507 | |||
508 | rc=load_rockbox(loadbuffer, "apple_os.ipod"); | ||
509 | |||
510 | /* Only report errors if the file was found */ | ||
511 | if (rc < -1) { | ||
512 | printf("Error!"); | ||
513 | printf("Can't load apple_os.ipod:"); | ||
514 | printf(strerror(rc)); | ||
515 | } else if (rc > 0) { | ||
516 | printf("apple_os.ipod loaded."); | ||
517 | memcpy((void*)DRAM_START,loadbuffer,rc); | ||
518 | return (void*)DRAM_START; | ||
519 | } | ||
520 | |||
521 | if (haveretailos) { | ||
522 | /* We have a copy of the retailos in RAM, lets just run it. */ | ||
523 | return (void*)DRAM_START; | ||
524 | } | ||
525 | |||
526 | /* Everything failed - just loop forever */ | ||
527 | printf("No RetailOS detected"); | ||
528 | |||
529 | fatal_error(); | 376 | fatal_error(); |
530 | 377 | ||
531 | /* We never get here, but keep gcc happy */ | 378 | /* We never get here, but keep gcc happy */ |
532 | return (void*)0; | 379 | return (void*)0; |
533 | } | 380 | } |
534 | 381 | ||
535 | /* These functions are present in the firmware library, but we reimplement | 382 | /* These functions are present in the firmware library, but we reimplement |
536 | them here because the originals do a lot more than we want */ | 383 | them here because the originals do a lot more than we want */ |
537 | |||
538 | void reset_poweroff_timer(void) | ||
539 | { | ||
540 | } | ||
541 | |||
542 | int dbg_ports(void) | ||
543 | { | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | void mpeg_stop(void) | ||
548 | { | ||
549 | } | ||
550 | |||
551 | void usb_acknowledge(void) | 384 | void usb_acknowledge(void) |
552 | { | 385 | { |
553 | } | 386 | } |
@@ -555,7 +388,3 @@ void usb_acknowledge(void) | |||
555 | void usb_wait_for_disconnect(void) | 388 | void usb_wait_for_disconnect(void) |
556 | { | 389 | { |
557 | } | 390 | } |
558 | |||
559 | void sys_poweroff(void) | ||
560 | { | ||
561 | } | ||