summaryrefslogtreecommitdiffstats
path: root/firmware/usbstack
diff options
context:
space:
mode:
authorFrank Gevaerts <frank@gevaerts.be>2008-03-10 20:55:24 +0000
committerFrank Gevaerts <frank@gevaerts.be>2008-03-10 20:55:24 +0000
commit745133014e6161c4d8c7a7eab137b7d9b1174c55 (patch)
tree0731cf8a30b17dae164e4240e48b28782cdf5a06 /firmware/usbstack
parent9d32b6aa1776db210d5c01589704a65238240df2 (diff)
downloadrockbox-745133014e6161c4d8c7a7eab137b7d9b1174c55.tar.gz
rockbox-745133014e6161c4d8c7a7eab137b7d9b1174c55.tar.bz2
rockbox-745133014e6161c4d8c7a7eab137b7d9b1174c55.zip
make the usb storage driver handle hotswap correctly, and exit the usb screen once all drives are "ejected" (either as a command from the OS or physically)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16617 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/usbstack')
-rw-r--r--firmware/usbstack/usb_class_driver.h6
-rw-r--r--firmware/usbstack/usb_core.c29
-rw-r--r--firmware/usbstack/usb_storage.c86
-rw-r--r--firmware/usbstack/usb_storage.h5
4 files changed, 107 insertions, 19 deletions
diff --git a/firmware/usbstack/usb_class_driver.h b/firmware/usbstack/usb_class_driver.h
index 631d5a3bc1..beeec86fb7 100644
--- a/firmware/usbstack/usb_class_driver.h
+++ b/firmware/usbstack/usb_class_driver.h
@@ -54,6 +54,12 @@ struct usb_class_driver {
able to handle it, it should ack the request, and return true. Otherwise
it should return false. */
bool (*control_request)(struct usb_ctrlrequest* req);
+
+#ifdef HAVE_HOTSWAP
+ /* Tells the driver that a hotswappable disk/card was inserted or
+ extracted */
+ void (*notify_hotswap)(int volume, bool inserted);
+#endif
};
#endif
diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c
index e0aaa9b2f4..aa4686500d 100644
--- a/firmware/usbstack/usb_core.c
+++ b/firmware/usbstack/usb_core.c
@@ -199,7 +199,10 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
.init = usb_storage_init,
.disconnect = NULL,
.transfer_complete = usb_storage_transfer_complete,
- .control_request = usb_storage_control_request
+ .control_request = usb_storage_control_request,
+#ifdef HAVE_HOTSWAP
+ .notify_hotswap = usb_storage_notify_hotswap,
+#endif
},
#endif
#ifdef USB_SERIAL
@@ -213,7 +216,10 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
.init = usb_serial_init,
.disconnect = usb_serial_disconnect,
.transfer_complete = usb_serial_transfer_complete,
- .control_request = usb_serial_control_request
+ .control_request = usb_serial_control_request,
+#ifdef HAVE_HOTSWAP
+ .notify_hotswap = NULL,
+#endif
},
#endif
#ifdef USB_CHARGING_ONLY
@@ -227,7 +233,10 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
.init = NULL,
.disconnect = NULL,
.transfer_complete = NULL,
- .control_request = NULL
+ .control_request = NULL,
+#ifdef HAVE_HOTSWAP
+ .notify_hotswap = NULL,
+#endif
},
#endif
};
@@ -386,6 +395,20 @@ bool usb_core_driver_enabled(int driver)
return drivers[driver].enabled;
}
+#ifdef HAVE_HOTSWAP
+void usb_core_hotswap_event(int volume,bool inserted)
+{
+ int i;
+ for(i=0;i<USB_NUM_DRIVERS;i++) {
+ if(drivers[i].enabled &&
+ drivers[i].notify_hotswap!=NULL)
+ {
+ drivers[i].notify_hotswap(volume,inserted);
+ }
+ }
+}
+#endif
+
static void usb_core_set_serial_function_id(void)
{
int id = 0;
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c
index 58578d958b..06d999d6de 100644
--- a/firmware/usbstack/usb_storage.c
+++ b/firmware/usbstack/usb_storage.c
@@ -262,15 +262,65 @@ static enum {
SENDING_CSW
} state = WAITING_FOR_COMMAND;
+static bool check_disk_present(int volume)
+{
+ unsigned char sector[512];
+ return ata_read_sectors(IF_MV2(volume,)0,1,sector) == 0;
+}
+
+static void try_release_ata(void)
+{
+ /* Check if there is a connected drive left. If not,
+ release excusive access */
+ bool canrelease=true;
+ int i;
+ for(i=0;i<NUM_VOLUMES;i++) {
+ if(ejected[i]==false){
+ canrelease=false;
+ break;
+ }
+ }
+ if(canrelease) {
+ logf("scsi release ata");
+ usb_release_exclusive_ata();
+ }
+}
+
+#ifdef HAVE_HOTSWAP
+void usb_storage_notify_hotswap(int volume,bool inserted)
+{
+ logf("notify %d",inserted);
+ if(inserted && check_disk_present(volume)) {
+ ejected[volume] = false;
+ }
+ else {
+ ejected[volume] = true;
+ try_release_ata();
+ }
+
+}
+#endif
+
+void usb_storage_reconnect(void)
+{
+ int i;
+ for(i=0;i<NUM_VOLUMES;i++)
+ ejected[i] = !check_disk_present(i);
+
+ usb_request_exclusive_ata();
+}
+
/* called by usb_code_init() */
void usb_storage_init(void)
{
int i;
- for(i=0;i<NUM_VOLUMES;i++)
- ejected[i]=false;
+ for(i=0;i<NUM_VOLUMES;i++) {
+ ejected[i] = !check_disk_present(i);
+ }
logf("usb_storage_init done");
}
+
int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size,
int interface_number,int endpoint)
{
@@ -348,7 +398,7 @@ void usb_storage_transfer_complete(bool in,int status,int length)
int result = ata_write_sectors(IF_MV2(cur_cmd.lun,)
cur_cmd.sector,
MIN(BUFFER_SIZE/SECTOR_SIZE,
- cur_cmd.count),
+ cur_cmd.count),
cur_cmd.data[cur_cmd.data_select]);
if(result != 0) {
send_csw(UMS_STATUS_FAIL);
@@ -508,7 +558,7 @@ static void send_and_read_next(void)
cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,)
cur_cmd.sector,
MIN(BUFFER_SIZE/SECTOR_SIZE,
- cur_cmd.count),
+ cur_cmd.count),
cur_cmd.data[cur_cmd.data_select]);
}
}
@@ -520,8 +570,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
TODO: support 48-bit LBA */
unsigned int length = cbw->data_transfer_length;
- unsigned int block_size;
- unsigned int block_count;
+ unsigned int block_size = 0;
+ unsigned int block_count = 0;
bool lun_present=true;
#ifdef ONLY_EXPOSE_CARD_SLOT
unsigned char lun = cbw->lun+1;
@@ -536,9 +586,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
block_count = cinfo->numblocks;
}
else {
- lun_present=false;
- block_size = 0;
- block_count = 0;
+ ejected[lun] = true;
+ try_release_ata();
}
#else
unsigned short* identify = ata_get_identify();
@@ -562,8 +611,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
if(!usb_exclusive_ata()) {
send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_NOT_READY;
- cur_sense_data.asc=ASC_NOT_READY;
- cur_sense_data.ascq=ASCQ_BECOMING_READY;
+ cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
+ cur_sense_data.ascq=0;
break;
}
if(lun_present) {
@@ -732,12 +781,17 @@ static void handle_scsi(struct command_block_wrapper* cbw)
case SCSI_START_STOP_UNIT:
logf("scsi start_stop unit %d",lun);
- if((cbw->command_block[4] & 0xf0) == 0)
+ if((cbw->command_block[4] & 0xf0) == 0) /*load/eject bit is valid*/
{ /* Process start and eject bits */
- if((cbw->command_block[4] & 0x01) == 0 &&
- (cbw->command_block[4] & 0x02) != 0) /* Stop and eject */
+ logf("scsi load/eject");
+ if((cbw->command_block[4] & 0x01) == 0) /* Don't start */
{
- ejected[lun]=true;
+ if((cbw->command_block[4] & 0x02) != 0) /* eject */
+ {
+ logf("scsi eject");
+ ejected[lun]=true;
+ try_release_ata();
+ }
}
}
send_csw(UMS_STATUS_GOOD);
@@ -828,7 +882,7 @@ static void handle_scsi(struct command_block_wrapper* cbw)
cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,)
cur_cmd.sector,
MIN(BUFFER_SIZE/SECTOR_SIZE,
- cur_cmd.count),
+ cur_cmd.count),
cur_cmd.data[cur_cmd.data_select]);
send_and_read_next();
}
diff --git a/firmware/usbstack/usb_storage.h b/firmware/usbstack/usb_storage.h
index 34bc0144dd..40f8ed9248 100644
--- a/firmware/usbstack/usb_storage.h
+++ b/firmware/usbstack/usb_storage.h
@@ -27,6 +27,11 @@ void usb_storage_init_connection(int interface,int endpoint);
void usb_storage_init(void);
void usb_storage_transfer_complete(bool in,int state,int length);
bool usb_storage_control_request(struct usb_ctrlrequest* req);
+#ifdef HAVE_HOTSWAP
+void usb_storage_notify_hotswap(int volume,bool inserted);
+#endif
+
+void usb_storage_reconnect(void);
#endif