Move interrupt clearing up.
[Rockbox.git] / bootloader / gigabeat-s.c
blob30c2955c19c3ff9256e48e0cac2d3328a34df866
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Greg White
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "config.h"
20 #include "system.h"
21 #include <sprintf.h>
22 #include "kernel.h"
23 #include "string.h"
24 #include "ata.h"
25 #include "dir.h"
26 #include "disk.h"
27 #include "common.h"
28 #include "usb.h"
29 #include "font.h"
30 #include "lcd.h"
31 #include "usb-target.h"
33 #define TAR_CHUNK 512
34 #define TAR_HEADER_SIZE 157
36 const char version[] = APPSVERSION;
37 /* Where files sent via MTP are stored */
38 static const char basedir[] = "/Content/0b00/00/";
39 /* Can use memory after vector table up to 0x01f00000 */
40 static char * const tarbuf = (char *)0x00000040;
41 static const size_t tarbuf_size = 0x01f00000 - 0x00000040;
42 /* Queue to get notifications when in USB mode */
43 static struct event_queue usb_wait_queue;
45 static void show_splash(int timeout, const char *msg)
47 lcd_putsxy( (LCD_WIDTH - (SYSFONT_WIDTH * strlen(msg))) / 2,
48 (LCD_HEIGHT - SYSFONT_HEIGHT) / 2, msg);
49 lcd_update();
51 sleep(timeout);
54 static void untar(int tar_fd)
56 char header[TAR_HEADER_SIZE];
57 char *ptr;
58 char path[102];
59 int fd, i;
60 int ret;
61 size_t size = filesize(tar_fd);
63 if (size > tarbuf_size) {
64 printf("tar file too large"); /* Paranoid but proper */
65 return;
68 ret = read(tar_fd, tarbuf, filesize(tar_fd));
69 if (ret < 0) {
70 printf("couldn't read tar file (%d)", ret);
71 return;
73 ptr = tarbuf;
75 while (1)
77 memcpy(header, ptr, TAR_HEADER_SIZE);
79 if (*header == '\0') /* Check for EOF */
80 break;
82 /* Parse the size field */
83 size = 0;
84 for (i = 124 ; i < 124 + 11 ; i++) {
85 size = (8 * size) + header[i] - '0';
88 /* Skip rest of header */
89 ptr += TAR_CHUNK;
91 /* Make the path absolute */
92 strcpy(path, "/");
93 strcat(path, header);
95 if (header[156] == '0') /* file */
97 int wc;
99 fd = creat(path);
100 if (fd < 0)
102 printf("failed to create file (%d)", fd);
104 else
106 wc = write(fd, ptr, size);
107 if (wc < 0)
109 printf("write failed (%d)", wc);
110 break;
112 close(fd);
114 ptr += (size + TAR_CHUNK-1) & (~(TAR_CHUNK-1));
116 else if (header[156] == '5') /* directory */
118 int ret;
120 /* Remove the trailing slash */
121 if (path[strlen(path) - 1] == '/')
122 path[strlen(path) - 1] = '\0';
124 /* Create the dir */
125 ret = mkdir(path);
126 if (ret < 0 && ret != -4)
128 printf("failed to create dir (%d)", ret);
134 void main(void)
136 char buf[MAX_PATH];
137 char tarstring[6];
138 char model[5];
140 /* Flush and invalidate all caches (because vectors were written) */
141 invalidate_icache();
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;
150 enable_interrupt(IRQ_FIQ_STATUS);
152 rc = ata_init();
153 if(rc)
155 reset_screen();
156 error(EATA, rc);
158 printf("ata init done");
160 disk_init();
161 printf("disk init done");
163 rc = disk_mount_all();
164 if (rc<=0)
166 error(EDISK,rc);
169 /* Look for a tar file */
170 struct dirent_uncached* entry;
171 DIR_UNCACHED* dir;
172 int fd;
173 dir = opendir_uncached(basedir);
174 while ((entry = readdir_uncached(dir)))
176 if (*entry->d_name != '.')
178 snprintf(buf, sizeof(buf), "%s%s", basedir, entry->d_name);
179 fd = open(buf, O_RDONLY);
180 if (fd >= 0)
182 /* Check whether the file is a rockbox binary. */
183 lseek(fd, 4, SEEK_SET);
184 rc = read(fd, model, 4);
185 if (rc == 4)
187 model[4] = 0;
188 if (strcmp(model, "gigs") == 0)
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;
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)
205 tarstring[5] = 0;
206 if (strcmp(tarstring, "ustar") == 0)
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;
217 close(fd);
222 if (usb_plugged())
224 /* Enter USB mode */
225 struct queue_event ev;
226 queue_init(&usb_wait_queue, true);
228 /* Start the USB driver */
229 usb_init();
230 usb_start_monitoring();
232 /* Wait for threads to connect or cable is pulled */
233 reset_screen();
234 show_splash(0, "Waiting for USB");
236 while (1)
238 queue_wait_w_tmo(&usb_wait_queue, &ev, HZ/2);
240 if (ev.id == SYS_USB_CONNECTED)
241 break; /* Hit */
243 if (!usb_plugged())
244 break; /* Cable pulled */
247 if (ev.id == SYS_USB_CONNECTED)
249 /* Got the message - wait for disconnect */
250 reset_screen();
251 show_splash(0, "Bootloader USB mode");
253 usb_acknowledge(SYS_USB_CONNECTED_ACK);
254 usb_wait_for_disconnect(&usb_wait_queue);
257 /* No more monitoring */
258 usb_stop_monitoring();
260 reset_screen();
262 else
264 /* Bang on the controller */
265 usb_init_device();
268 unsigned char *loadbuffer = (unsigned char *)0x0;
269 int buffer_size = 31*1024*1024;
271 rc = load_firmware(loadbuffer, "/.rockbox/rockbox.gigabeat", buffer_size);
272 if(rc < 0)
273 error(EBOOTFILE, rc);
275 system_prepare_fw_start();
277 if (rc == EOK)
279 invalidate_icache();
280 asm volatile ("bx %0": : "r"(loadbuffer));
283 /* Halt */
284 while (1)
285 core_idle();