summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootloader/gigabeat-s.c10
-rw-r--r--firmware/export/config/gigabeats.h13
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c44
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/usb-target.h13
-rw-r--r--firmware/usbstack/usb_storage.c59
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)
if (pre_usb && !usb_plugged())
return false;
- /* Exit if no button or only the menu (settings reset) button */
+ /* Exit if no button or only select buttons that have other
+ * functions */
switch (button)
{
- case BUTTON_MENU:
- case BUTTON_NONE:
+ case USB_BL_INSTALL_MODE_BTN:
+ if (!pre_usb)
+ break; /* Only before USB detect */
+ case BUTTON_MENU: /* Settings reset */
+ case BUTTON_NONE: /* Nothing pressed */
return true;
}
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 @@
/* define this if the unit can be powered or charged via USB */
#define HAVE_USB_POWER
-#define USBPOWER_BUTTON BUTTON_MENU
-#define USBPOWER_BTN_IGNORE BUTTON_POWER
+#define USBPOWER_BUTTON BUTTON_MENU
+
+#ifndef BOOTLOADER
+#define USBPOWER_BTN_IGNORE BUTTON_POWER
+#else
+/* Disable charging-only mode detection in bootloader */
+#define USBPOWER_BTN_IGNORE (BUTTON_MAIN | BUTTON_REMOTE)
+#endif
+
+/* Button that exposures boot partition rather than data during session */
+#define USB_BL_INSTALL_MODE_BTN BUTTON_VOL_DOWN
/* define this if the unit has a battery switch or battery can be removed
* 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 @@
*
****************************************************************************/
#include "config.h"
-#include "cpu.h"
#include "system.h"
#include "kernel.h"
#include "ata.h"
@@ -31,8 +30,10 @@
#include "ccm-imx31.h"
#include "avic-imx31.h"
#include "power-gigabeat-s.h"
+#include <string.h>
static int usb_status = USB_EXTRACTED;
+static bool bootloader_install_mode = false;
static void enable_transceiver(bool enable)
{
@@ -106,6 +107,16 @@ void usb_enable(bool on)
void usb_attach(void)
{
+ bootloader_install_mode = false;
+
+ if (usb_core_driver_enabled(USB_DRIVER_MASS_STORAGE))
+ {
+ /* Check if this will be bootloader install mode, exposing the
+ * boot partition instead of the data partition */
+ bootloader_install_mode =
+ (button_status() & USB_BL_INSTALL_MODE_BTN) != 0;
+ }
+
usb_drv_attach();
}
@@ -133,3 +144,34 @@ void usb_drv_usb_detect_event(void)
if (usb_drv_powered())
usb_status_event(USB_INSERTED);
}
+
+/* Called when reading the MBR */
+void usb_fix_mbr(unsigned char *mbr)
+{
+ unsigned char* p = mbr + 0x1be;
+ char tmp[16];
+
+ /* The Gigabeat S factory partition table contains invalid values for the
+ "active" flag in the MBR. This prevents at least the Linux kernel
+ from accepting the partition table, so we fix it on-the-fly. */
+ p[0x00] &= 0x80;
+ p[0x10] &= 0x80;
+ p[0x20] &= 0x80;
+ p[0x30] &= 0x80;
+
+ if (bootloader_install_mode)
+ return;
+
+ /* Windows ignores the partition flags and mounts the first partition it
+ sees when the device reports itself as removable. Swap the partitions
+ so the data partition appears to be partition 0. Mark the boot
+ partition 0 as hidden and make it partition 1. */
+
+ /* Mark the first partition as hidden */
+ p[0x04] |= 0x10;
+
+ /* Swap first and second partitions */
+ memcpy(tmp, &p[0x00], 16);
+ memcpy(&p[0x00], &p[0x10], 16);
+ memcpy(&p[0x10], tmp, 16);
+}
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);
/* Read the immediate state of the cable from the PMIC */
bool usb_plugged(void);
+/** Sector read/write filters **/
+
+/* Filter some things in the MBR - see usb-gigabeat-s.c */
+void usb_fix_mbr(unsigned char *mbr);
+#define USBSTOR_READ_SECTORS_FILTER() \
+ ({ if (cur_cmd.sector == 0) \
+ usb_fix_mbr(cur_cmd.data[cur_cmd.data_select]); \
+ 0; })
+
+/* Disallow MBR writes entirely since it was "fixed" in usb_fix_mbr */
+#define USBSTOR_WRITE_SECTORS_FILTER() \
+ ({ cur_cmd.sector != 0 ? 0 : -1; })
+
#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 @@
#include "usb_storage.h"
#include "timefuncs.h"
+/* For sector filter macro definitions */
+#include "usb-target.h"
/* Enable the following define to export only the SD card slot. This
* is useful for USBCV MSC tests, as those are destructive.
@@ -47,6 +49,15 @@
#define SECTOR_SIZE 512
#endif
+/* These defaults allow the operation */
+#ifndef USBSTOR_READ_SECTORS_FILTER
+#define USBSTOR_READ_SECTORS_FILTER() ({ 0; })
+#endif
+
+#ifndef USBSTOR_WRITE_SECTORS_FILTER
+#define USBSTOR_WRITE_SECTORS_FILTER() ({ 0; })
+#endif
+
/* the ARC driver currently supports up to 64k USB transfers. This is
* enough for efficient mass storage support, as commonly host OSes
* 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)
*m = i;
}
-#ifdef TOSHIBA_GIGABEAT_S
-
-/* The Gigabeat S factory partition table contains invalid values for the
- "active" flag in the MBR. This prevents at least the Linux kernel from
- accepting the partition table, so we fix it on-the-fly. */
-
-static void fix_mbr(unsigned char* mbr)
-{
- unsigned char* p = mbr + 0x1be;
-
- p[0x00] &= 0x80;
- p[0x10] &= 0x80;
- p[0x20] &= 0x80;
- p[0x30] &= 0x80;
-}
-#endif
-
static bool check_disk_present(IF_MD_NONVOID(int volume))
{
#ifdef USB_USE_RAMDISK
@@ -491,14 +485,7 @@ void usb_storage_init_connection(void)
int i;
for(i=0;i<storage_num_drives();i++) {
-#ifdef TOSHIBA_GIGABEAT_S
- /* As long as the Gigabeat S is a non-removable device, we need
- to mark the device as locked to avoid usb_storage_try_release_ata()
- to leave MSC mode while the device is in use */
- locked[i] = true;
-#else
locked[i] = false;
-#endif
ejected[i] = !check_disk_present(IF_MD(i));
queue_broadcast(SYS_USB_LUN_LOCKED, (i<<16)+0);
}
@@ -549,10 +536,15 @@ void usb_storage_transfer_complete(int ep,int dir,int status,int length)
cur_cmd.data[cur_cmd.data_select],
MIN(WRITE_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE);
#else
- int result = storage_write_sectors(IF_MD2(cur_cmd.lun,)
+ int result = USBSTOR_WRITE_SECTORS_FILTER();
+
+ if (result == 0) {
+ result = storage_write_sectors(IF_MD2(cur_cmd.lun,)
cur_cmd.sector,
MIN(WRITE_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count),
cur_cmd.data[cur_cmd.data_select]);
+ }
+
if(result != 0) {
send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_MEDIUM_ERROR;
@@ -725,6 +717,11 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req, unsigned char* des
static void send_and_read_next(void)
{
+ int result = USBSTOR_READ_SECTORS_FILTER();
+
+ if(result != 0 && cur_cmd.last_result == 0)
+ cur_cmd.last_result = result;
+
send_block_data(cur_cmd.data[cur_cmd.data_select],
MIN(READ_BUFFER_SIZE,cur_cmd.count*SECTOR_SIZE));
@@ -742,7 +739,7 @@ static void send_and_read_next(void)
ramdisk_buffer + cur_cmd.sector*SECTOR_SIZE,
MIN(READ_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE);
#else
- int result = storage_read_sectors(IF_MD2(cur_cmd.lun,)
+ result = storage_read_sectors(IF_MD2(cur_cmd.lun,)
cur_cmd.sector,
MIN(READ_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count),
cur_cmd.data[cur_cmd.data_select]);
@@ -1104,12 +1101,6 @@ static void handle_scsi(struct command_block_wrapper* cbw)
cur_cmd.sector,
MIN(READ_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count),
cur_cmd.data[cur_cmd.data_select]);
-
-#ifdef TOSHIBA_GIGABEAT_S
- if(cur_cmd.sector == 0) {
- fix_mbr(cur_cmd.data[cur_cmd.data_select]);
- }
-#endif
#endif
send_and_read_next();
}
@@ -1262,9 +1253,5 @@ static void fill_inquiry(IF_MD_NONVOID(int lun))
tb.inquiry->Versions = 4; /* SPC-2 */
tb.inquiry->Format = 2; /* SPC-2/3 inquiry format */
-#ifdef TOSHIBA_GIGABEAT_S
- tb.inquiry->DeviceTypeModifier = 0;
-#else
tb.inquiry->DeviceTypeModifier = DEVICE_REMOVABLE;
-#endif
}