diff options
author | Frank Gevaerts <frank@gevaerts.be> | 2008-03-10 20:55:24 +0000 |
---|---|---|
committer | Frank Gevaerts <frank@gevaerts.be> | 2008-03-10 20:55:24 +0000 |
commit | 745133014e6161c4d8c7a7eab137b7d9b1174c55 (patch) | |
tree | 0731cf8a30b17dae164e4240e48b28782cdf5a06 /firmware/usbstack | |
parent | 9d32b6aa1776db210d5c01589704a65238240df2 (diff) |
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.h | 6 | ||||
-rw-r--r-- | firmware/usbstack/usb_core.c | 29 | ||||
-rw-r--r-- | firmware/usbstack/usb_storage.c | 86 | ||||
-rw-r--r-- | firmware/usbstack/usb_storage.h | 5 |
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 |