Gigabeat S: Make it a removable mass-storage device. Windows will assign a drive to only the main data partition by default. To access the bootloader partition instead, press 'Vol -' while it connects (in bootloader and firmware). Hopefully doesn't break anything for anyone.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28972 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2011-01-05 19:35:51 +00:00
parent f97b9f11e4
commit 89a7a8138e
5 changed files with 97 additions and 42 deletions

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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
}