diff options
-rw-r--r-- | bootloader/gigabeat-s.c | 10 | ||||
-rw-r--r-- | firmware/export/config/gigabeats.h | 13 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c | 44 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/usb-target.h | 13 | ||||
-rw-r--r-- | firmware/usbstack/usb_storage.c | 59 |
5 files changed, 97 insertions, 42 deletions
diff --git a/bootloader/gigabeat-s.c b/bootloader/gigabeat-s.c index 9c5ad93d1f..c29265ddad 100644 --- a/bootloader/gigabeat-s.c +++ b/bootloader/gigabeat-s.c | |||
@@ -71,11 +71,15 @@ static bool pause_if_button_pressed(bool pre_usb) | |||
71 | if (pre_usb && !usb_plugged()) | 71 | if (pre_usb && !usb_plugged()) |
72 | return false; | 72 | return false; |
73 | 73 | ||
74 | /* Exit if no button or only the menu (settings reset) button */ | 74 | /* Exit if no button or only select buttons that have other |
75 | * functions */ | ||
75 | switch (button) | 76 | switch (button) |
76 | { | 77 | { |
77 | case BUTTON_MENU: | 78 | case USB_BL_INSTALL_MODE_BTN: |
78 | case BUTTON_NONE: | 79 | if (!pre_usb) |
80 | break; /* Only before USB detect */ | ||
81 | case BUTTON_MENU: /* Settings reset */ | ||
82 | case BUTTON_NONE: /* Nothing pressed */ | ||
79 | return true; | 83 | return true; |
80 | } | 84 | } |
81 | 85 | ||
diff --git a/firmware/export/config/gigabeats.h b/firmware/export/config/gigabeats.h index fcfa274314..cf560aa35f 100644 --- a/firmware/export/config/gigabeats.h +++ b/firmware/export/config/gigabeats.h | |||
@@ -190,8 +190,17 @@ | |||
190 | 190 | ||
191 | /* define this if the unit can be powered or charged via USB */ | 191 | /* define this if the unit can be powered or charged via USB */ |
192 | #define HAVE_USB_POWER | 192 | #define HAVE_USB_POWER |
193 | #define USBPOWER_BUTTON BUTTON_MENU | 193 | #define USBPOWER_BUTTON BUTTON_MENU |
194 | #define USBPOWER_BTN_IGNORE BUTTON_POWER | 194 | |
195 | #ifndef BOOTLOADER | ||
196 | #define USBPOWER_BTN_IGNORE BUTTON_POWER | ||
197 | #else | ||
198 | /* Disable charging-only mode detection in bootloader */ | ||
199 | #define USBPOWER_BTN_IGNORE (BUTTON_MAIN | BUTTON_REMOTE) | ||
200 | #endif | ||
201 | |||
202 | /* Button that exposures boot partition rather than data during session */ | ||
203 | #define USB_BL_INSTALL_MODE_BTN BUTTON_VOL_DOWN | ||
195 | 204 | ||
196 | /* define this if the unit has a battery switch or battery can be removed | 205 | /* define this if the unit has a battery switch or battery can be removed |
197 | * when running */ | 206 | * when running */ |
diff --git a/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c index 016f24fc48..c52a9a6dec 100644 --- a/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "config.h" | 21 | #include "config.h" |
22 | #include "cpu.h" | ||
23 | #include "system.h" | 22 | #include "system.h" |
24 | #include "kernel.h" | 23 | #include "kernel.h" |
25 | #include "ata.h" | 24 | #include "ata.h" |
@@ -31,8 +30,10 @@ | |||
31 | #include "ccm-imx31.h" | 30 | #include "ccm-imx31.h" |
32 | #include "avic-imx31.h" | 31 | #include "avic-imx31.h" |
33 | #include "power-gigabeat-s.h" | 32 | #include "power-gigabeat-s.h" |
33 | #include <string.h> | ||
34 | 34 | ||
35 | static int usb_status = USB_EXTRACTED; | 35 | static int usb_status = USB_EXTRACTED; |
36 | static bool bootloader_install_mode = false; | ||
36 | 37 | ||
37 | static void enable_transceiver(bool enable) | 38 | static void enable_transceiver(bool enable) |
38 | { | 39 | { |
@@ -106,6 +107,16 @@ void usb_enable(bool on) | |||
106 | 107 | ||
107 | void usb_attach(void) | 108 | void usb_attach(void) |
108 | { | 109 | { |
110 | bootloader_install_mode = false; | ||
111 | |||
112 | if (usb_core_driver_enabled(USB_DRIVER_MASS_STORAGE)) | ||
113 | { | ||
114 | /* Check if this will be bootloader install mode, exposing the | ||
115 | * boot partition instead of the data partition */ | ||
116 | bootloader_install_mode = | ||
117 | (button_status() & USB_BL_INSTALL_MODE_BTN) != 0; | ||
118 | } | ||
119 | |||
109 | usb_drv_attach(); | 120 | usb_drv_attach(); |
110 | } | 121 | } |
111 | 122 | ||
@@ -133,3 +144,34 @@ void usb_drv_usb_detect_event(void) | |||
133 | if (usb_drv_powered()) | 144 | if (usb_drv_powered()) |
134 | usb_status_event(USB_INSERTED); | 145 | usb_status_event(USB_INSERTED); |
135 | } | 146 | } |
147 | |||
148 | /* Called when reading the MBR */ | ||
149 | void usb_fix_mbr(unsigned char *mbr) | ||
150 | { | ||
151 | unsigned char* p = mbr + 0x1be; | ||
152 | char tmp[16]; | ||
153 | |||
154 | /* The Gigabeat S factory partition table contains invalid values for the | ||
155 | "active" flag in the MBR. This prevents at least the Linux kernel | ||
156 | from accepting the partition table, so we fix it on-the-fly. */ | ||
157 | p[0x00] &= 0x80; | ||
158 | p[0x10] &= 0x80; | ||
159 | p[0x20] &= 0x80; | ||
160 | p[0x30] &= 0x80; | ||
161 | |||
162 | if (bootloader_install_mode) | ||
163 | return; | ||
164 | |||
165 | /* Windows ignores the partition flags and mounts the first partition it | ||
166 | sees when the device reports itself as removable. Swap the partitions | ||
167 | so the data partition appears to be partition 0. Mark the boot | ||
168 | partition 0 as hidden and make it partition 1. */ | ||
169 | |||
170 | /* Mark the first partition as hidden */ | ||
171 | p[0x04] |= 0x10; | ||
172 | |||
173 | /* Swap first and second partitions */ | ||
174 | memcpy(tmp, &p[0x00], 16); | ||
175 | memcpy(&p[0x00], &p[0x10], 16); | ||
176 | memcpy(&p[0x10], tmp, 16); | ||
177 | } | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/usb-target.h b/firmware/target/arm/imx31/gigabeat-s/usb-target.h index c93400ca0b..7931058241 100644 --- a/firmware/target/arm/imx31/gigabeat-s/usb-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/usb-target.h | |||
@@ -30,4 +30,17 @@ void usb_init_device(void); | |||
30 | /* Read the immediate state of the cable from the PMIC */ | 30 | /* Read the immediate state of the cable from the PMIC */ |
31 | bool usb_plugged(void); | 31 | bool usb_plugged(void); |
32 | 32 | ||
33 | /** Sector read/write filters **/ | ||
34 | |||
35 | /* Filter some things in the MBR - see usb-gigabeat-s.c */ | ||
36 | void usb_fix_mbr(unsigned char *mbr); | ||
37 | #define USBSTOR_READ_SECTORS_FILTER() \ | ||
38 | ({ if (cur_cmd.sector == 0) \ | ||
39 | usb_fix_mbr(cur_cmd.data[cur_cmd.data_select]); \ | ||
40 | 0; }) | ||
41 | |||
42 | /* Disallow MBR writes entirely since it was "fixed" in usb_fix_mbr */ | ||
43 | #define USBSTOR_WRITE_SECTORS_FILTER() \ | ||
44 | ({ cur_cmd.sector != 0 ? 0 : -1; }) | ||
45 | |||
33 | #endif /* USB_TARGET */ | 46 | #endif /* USB_TARGET */ |
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index 005697f6fa..1ff3b1ec4c 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include "usb_storage.h" | 32 | #include "usb_storage.h" |
33 | #include "timefuncs.h" | 33 | #include "timefuncs.h" |
34 | 34 | ||
35 | /* For sector filter macro definitions */ | ||
36 | #include "usb-target.h" | ||
35 | 37 | ||
36 | /* Enable the following define to export only the SD card slot. This | 38 | /* Enable the following define to export only the SD card slot. This |
37 | * is useful for USBCV MSC tests, as those are destructive. | 39 | * is useful for USBCV MSC tests, as those are destructive. |
@@ -47,6 +49,15 @@ | |||
47 | #define SECTOR_SIZE 512 | 49 | #define SECTOR_SIZE 512 |
48 | #endif | 50 | #endif |
49 | 51 | ||
52 | /* These defaults allow the operation */ | ||
53 | #ifndef USBSTOR_READ_SECTORS_FILTER | ||
54 | #define USBSTOR_READ_SECTORS_FILTER() ({ 0; }) | ||
55 | #endif | ||
56 | |||
57 | #ifndef USBSTOR_WRITE_SECTORS_FILTER | ||
58 | #define USBSTOR_WRITE_SECTORS_FILTER() ({ 0; }) | ||
59 | #endif | ||
60 | |||
50 | /* the ARC driver currently supports up to 64k USB transfers. This is | 61 | /* the ARC driver currently supports up to 64k USB transfers. This is |
51 | * enough for efficient mass storage support, as commonly host OSes | 62 | * enough for efficient mass storage support, as commonly host OSes |
52 | * don't do larger SCSI transfers anyway, so larger USB transfers | 63 | * don't do larger SCSI transfers anyway, so larger USB transfers |
@@ -342,23 +353,6 @@ static void yearday_to_daymonth(int yd, int y, int *d, int *m) | |||
342 | *m = i; | 353 | *m = i; |
343 | } | 354 | } |
344 | 355 | ||
345 | #ifdef TOSHIBA_GIGABEAT_S | ||
346 | |||
347 | /* The Gigabeat S factory partition table contains invalid values for the | ||
348 | "active" flag in the MBR. This prevents at least the Linux kernel from | ||
349 | accepting the partition table, so we fix it on-the-fly. */ | ||
350 | |||
351 | static void fix_mbr(unsigned char* mbr) | ||
352 | { | ||
353 | unsigned char* p = mbr + 0x1be; | ||
354 | |||
355 | p[0x00] &= 0x80; | ||
356 | p[0x10] &= 0x80; | ||
357 | p[0x20] &= 0x80; | ||
358 | p[0x30] &= 0x80; | ||
359 | } | ||
360 | #endif | ||
361 | |||
362 | static bool check_disk_present(IF_MD_NONVOID(int volume)) | 356 | static bool check_disk_present(IF_MD_NONVOID(int volume)) |
363 | { | 357 | { |
364 | #ifdef USB_USE_RAMDISK | 358 | #ifdef USB_USE_RAMDISK |
@@ -491,14 +485,7 @@ void usb_storage_init_connection(void) | |||
491 | 485 | ||
492 | int i; | 486 | int i; |
493 | for(i=0;i<storage_num_drives();i++) { | 487 | for(i=0;i<storage_num_drives();i++) { |
494 | #ifdef TOSHIBA_GIGABEAT_S | ||
495 | /* As long as the Gigabeat S is a non-removable device, we need | ||
496 | to mark the device as locked to avoid usb_storage_try_release_ata() | ||
497 | to leave MSC mode while the device is in use */ | ||
498 | locked[i] = true; | ||
499 | #else | ||
500 | locked[i] = false; | 488 | locked[i] = false; |
501 | #endif | ||
502 | ejected[i] = !check_disk_present(IF_MD(i)); | 489 | ejected[i] = !check_disk_present(IF_MD(i)); |
503 | queue_broadcast(SYS_USB_LUN_LOCKED, (i<<16)+0); | 490 | queue_broadcast(SYS_USB_LUN_LOCKED, (i<<16)+0); |
504 | } | 491 | } |
@@ -549,10 +536,15 @@ void usb_storage_transfer_complete(int ep,int dir,int status,int length) | |||
549 | cur_cmd.data[cur_cmd.data_select], | 536 | cur_cmd.data[cur_cmd.data_select], |
550 | MIN(WRITE_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE); | 537 | MIN(WRITE_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE); |
551 | #else | 538 | #else |
552 | int result = storage_write_sectors(IF_MD2(cur_cmd.lun,) | 539 | int result = USBSTOR_WRITE_SECTORS_FILTER(); |
540 | |||
541 | if (result == 0) { | ||
542 | result = storage_write_sectors(IF_MD2(cur_cmd.lun,) | ||
553 | cur_cmd.sector, | 543 | cur_cmd.sector, |
554 | MIN(WRITE_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count), | 544 | MIN(WRITE_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count), |
555 | cur_cmd.data[cur_cmd.data_select]); | 545 | cur_cmd.data[cur_cmd.data_select]); |
546 | } | ||
547 | |||
556 | if(result != 0) { | 548 | if(result != 0) { |
557 | send_csw(UMS_STATUS_FAIL); | 549 | send_csw(UMS_STATUS_FAIL); |
558 | cur_sense_data.sense_key=SENSE_MEDIUM_ERROR; | 550 | cur_sense_data.sense_key=SENSE_MEDIUM_ERROR; |
@@ -725,6 +717,11 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req, unsigned char* des | |||
725 | 717 | ||
726 | static void send_and_read_next(void) | 718 | static void send_and_read_next(void) |
727 | { | 719 | { |
720 | int result = USBSTOR_READ_SECTORS_FILTER(); | ||
721 | |||
722 | if(result != 0 && cur_cmd.last_result == 0) | ||
723 | cur_cmd.last_result = result; | ||
724 | |||
728 | send_block_data(cur_cmd.data[cur_cmd.data_select], | 725 | send_block_data(cur_cmd.data[cur_cmd.data_select], |
729 | MIN(READ_BUFFER_SIZE,cur_cmd.count*SECTOR_SIZE)); | 726 | MIN(READ_BUFFER_SIZE,cur_cmd.count*SECTOR_SIZE)); |
730 | 727 | ||
@@ -742,7 +739,7 @@ static void send_and_read_next(void) | |||
742 | ramdisk_buffer + cur_cmd.sector*SECTOR_SIZE, | 739 | ramdisk_buffer + cur_cmd.sector*SECTOR_SIZE, |
743 | MIN(READ_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE); | 740 | MIN(READ_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE); |
744 | #else | 741 | #else |
745 | int result = storage_read_sectors(IF_MD2(cur_cmd.lun,) | 742 | result = storage_read_sectors(IF_MD2(cur_cmd.lun,) |
746 | cur_cmd.sector, | 743 | cur_cmd.sector, |
747 | MIN(READ_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count), | 744 | MIN(READ_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count), |
748 | cur_cmd.data[cur_cmd.data_select]); | 745 | cur_cmd.data[cur_cmd.data_select]); |
@@ -1104,12 +1101,6 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
1104 | cur_cmd.sector, | 1101 | cur_cmd.sector, |
1105 | MIN(READ_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count), | 1102 | MIN(READ_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count), |
1106 | cur_cmd.data[cur_cmd.data_select]); | 1103 | cur_cmd.data[cur_cmd.data_select]); |
1107 | |||
1108 | #ifdef TOSHIBA_GIGABEAT_S | ||
1109 | if(cur_cmd.sector == 0) { | ||
1110 | fix_mbr(cur_cmd.data[cur_cmd.data_select]); | ||
1111 | } | ||
1112 | #endif | ||
1113 | #endif | 1104 | #endif |
1114 | send_and_read_next(); | 1105 | send_and_read_next(); |
1115 | } | 1106 | } |
@@ -1262,9 +1253,5 @@ static void fill_inquiry(IF_MD_NONVOID(int lun)) | |||
1262 | tb.inquiry->Versions = 4; /* SPC-2 */ | 1253 | tb.inquiry->Versions = 4; /* SPC-2 */ |
1263 | tb.inquiry->Format = 2; /* SPC-2/3 inquiry format */ | 1254 | tb.inquiry->Format = 2; /* SPC-2/3 inquiry format */ |
1264 | 1255 | ||
1265 | #ifdef TOSHIBA_GIGABEAT_S | ||
1266 | tb.inquiry->DeviceTypeModifier = 0; | ||
1267 | #else | ||
1268 | tb.inquiry->DeviceTypeModifier = DEVICE_REMOVABLE; | 1256 | tb.inquiry->DeviceTypeModifier = DEVICE_REMOVABLE; |
1269 | #endif | ||
1270 | } | 1257 | } |