usb: add support for hardware handled SET ADDR/CONFIG
[maemo-rb.git] / bootloader / gigabeat-s.c
blob04c32423a006a3d7c9398650dfa29affc8aa0670
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
21 #include "config.h"
22 #include "system.h"
23 #include <stdio.h>
24 #include "kernel.h"
25 #include "gcc_extensions.h"
26 #include "string.h"
27 #include "adc.h"
28 #include "powermgmt.h"
29 #include "storage.h"
30 #include "dir.h"
31 #include "disk.h"
32 #include "common.h"
33 #include "power.h"
34 #include "backlight.h"
35 #include "usb.h"
36 #include "button.h"
37 #include "font.h"
38 #include "lcd.h"
39 #include "version.h"
41 /* Show the Rockbox logo - in show_logo.c */
42 extern void show_logo(void);
44 #define TAR_CHUNK 512
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;
52 /* Firmware data */
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)
60 verbose = true;
61 printf(msg);
62 printf("Shutting down...");
63 sleep(timeout);
64 power_off();
67 static void check_battery_safe(void)
69 if (battery_level_safe())
70 return;
72 display_message_and_power_off(HZ, "Battery low");
75 /* TODO: Handle charging while connected */
76 static void handle_usb(int connect_timeout)
78 long end_tick = 0;
79 int button;
81 /* We need full button and backlight handling now */
82 backlight_init();
83 button_init();
84 backlight_on();
86 /* Start the USB driver */
87 usb_init();
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;
96 while (1)
98 button = button_get_w_tmo(HZ/2);
100 if (button == SYS_USB_CONNECTED)
101 break; /* Hit */
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");
109 break;
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
119 * are shown */
120 verbose = true;
121 /* Got the message - wait for disconnect */
122 printf("Bootloader USB mode");
124 usb_acknowledge(SYS_USB_CONNECTED_ACK);
126 while (1)
128 button = button_get_w_tmo(HZ/2);
129 if (button == SYS_USB_DISCONNECTED)
130 break;
132 check_battery_safe();
135 backlight_on();
136 /* Sleep a little to let the backlight ramp up */
137 sleep(HZ*5/4);
140 /* Put drivers initialized for USB connection into a known state */
141 usb_close();
142 button_close();
143 backlight_close();
146 static void untar(int tar_fd)
148 char header[TAR_HEADER_SIZE];
149 char *ptr;
150 char path[102];
151 int fd, i;
152 int ret;
153 size_t size = filesize(tar_fd);
155 if (size > tarbuf_size)
157 printf("tar file too large"); /* Paranoid but proper */
158 return;
161 ret = read(tar_fd, tarbuf, filesize(tar_fd));
162 if (ret < 0)
164 printf("couldn't read tar file (%d)", ret);
165 return;
167 ptr = tarbuf;
169 while (1)
171 memcpy(header, ptr, TAR_HEADER_SIZE);
173 if (*header == '\0') /* Check for EOF */
174 break;
176 /* Parse the size field */
177 size = 0;
178 for (i = 124 ; i < 124 + 11 ; i++) {
179 size = (8 * size) + header[i] - '0';
182 /* Skip rest of header */
183 ptr += TAR_CHUNK;
185 /* Make the path absolute */
186 strcpy(path, "/");
187 strcat(path, header);
189 if (header[156] == '0') /* file */
191 int wc;
193 fd = creat(path, 0666);
194 if (fd < 0)
196 printf("failed to create file (%d)", fd);
198 else
200 wc = write(fd, ptr, size);
201 if (wc < 0)
203 printf("write failed (%d)", wc);
204 break;
206 close(fd);
208 ptr += (size + TAR_CHUNK-1) & (~(TAR_CHUNK-1));
210 else if (header[156] == '5') /* directory */
212 int ret;
214 /* Remove the trailing slash */
215 if (path[strlen(path) - 1] == '/')
216 path[strlen(path) - 1] = '\0';
218 /* Create the dir */
219 ret = mkdir(path);
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)
231 char buf[MAX_PATH];
232 char tarstring[6];
233 char model[5];
234 struct dirent_uncached* entry;
235 DIR_UNCACHED* dir;
236 int fd;
237 int rc;
239 dir = opendir_uncached(basedir);
241 while ((entry = readdir_uncached(dir)))
243 if (*entry->d_name == '.')
244 continue;
246 snprintf(buf, sizeof(buf), "%s%s", basedir, entry->d_name);
247 fd = open(buf, O_RDONLY);
249 if (fd < 0)
250 continue;
252 /* Check whether the file is a rockbox binary. */
253 lseek(fd, 4, SEEK_SET);
254 rc = read(fd, model, 4);
255 if (rc == 4)
257 model[4] = 0;
258 if (strcmp(model, "gigs") == 0)
260 verbose = true;
261 printf("Found rockbox binary. Moving...");
262 close(fd);
263 remove( BOOTDIR "/" BOOTFILE);
264 int ret = rename(buf, BOOTDIR "/" BOOTFILE);
265 printf("returned %d", ret);
266 sleep(HZ);
267 break;
271 /* Check whether the file is a tar file. */
272 lseek(fd, 257, SEEK_SET);
273 rc = read(fd, tarstring, 5);
274 if (rc == 5)
276 tarstring[5] = 0;
277 if (strcmp(tarstring, "ustar") == 0)
279 verbose = true;
280 printf("Found tar file. Unarchiving...");
281 lseek(fd, 0, SEEK_SET);
282 untar(fd);
283 close(fd);
284 printf("Removing tar file");
285 remove(buf);
286 break;
290 close(fd);
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);
299 if(rc < 0)
300 error(EBOOTFILE, rc, true);
302 /* Pause to look at messages */
303 while (1)
305 int button = button_read_device();
307 /* Ignore settings reset */
308 if (button == BUTTON_NONE || button == BUTTON_MENU)
309 break;
311 sleep(HZ/5);
313 check_battery_safe();
315 /* If the disk powers off, the firmware will lock at startup */
316 storage_spin();
319 /* Put drivers into a known state */
320 button_close_device();
321 storage_close();
322 system_prepare_fw_start();
324 if (rc == EOK)
326 commit_discard_idcache();
327 asm volatile ("bx %0": : "r"(start_addr));
330 /* Halt */
331 while (1)
332 core_idle();
335 void main(void)
337 int rc;
338 int batt;
340 system_init();
341 kernel_init();
343 /* Keep button_device_init early to delay calls to button_read_device */
344 button_init_device();
346 lcd_init();
347 font_init();
348 show_logo();
349 lcd_clear_display();
351 if (button_hold())
352 display_message_and_power_off(HZ, "Hold switch on");
354 if (button_read_device() != BUTTON_NONE)
355 verbose = true;
357 printf("Gigabeat S Rockbox Bootloader");
358 printf("Version " RBVERSION);
360 adc_init();
361 batt = _battery_voltage();
362 printf("Battery: %d.%03d V", batt / 1000, batt % 1000);
363 check_battery_safe();
365 rc = storage_init();
366 if(rc)
367 error(EATA, rc, true);
369 disk_init();
371 rc = disk_mount_all();
372 if (rc <= 0)
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)
380 handle_usb(HZ*2);
382 handle_untar();
383 handle_firmware_load(); /* No return */