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/usb_storage.c | |
parent | 9d32b6aa1776db210d5c01589704a65238240df2 (diff) | |
download | rockbox-745133014e6161c4d8c7a7eab137b7d9b1174c55.tar.gz 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/usb_storage.c')
-rw-r--r-- | firmware/usbstack/usb_storage.c | 86 |
1 files changed, 70 insertions, 16 deletions
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 { | |||
262 | SENDING_CSW | 262 | SENDING_CSW |
263 | } state = WAITING_FOR_COMMAND; | 263 | } state = WAITING_FOR_COMMAND; |
264 | 264 | ||
265 | static bool check_disk_present(int volume) | ||
266 | { | ||
267 | unsigned char sector[512]; | ||
268 | return ata_read_sectors(IF_MV2(volume,)0,1,sector) == 0; | ||
269 | } | ||
270 | |||
271 | static void try_release_ata(void) | ||
272 | { | ||
273 | /* Check if there is a connected drive left. If not, | ||
274 | release excusive access */ | ||
275 | bool canrelease=true; | ||
276 | int i; | ||
277 | for(i=0;i<NUM_VOLUMES;i++) { | ||
278 | if(ejected[i]==false){ | ||
279 | canrelease=false; | ||
280 | break; | ||
281 | } | ||
282 | } | ||
283 | if(canrelease) { | ||
284 | logf("scsi release ata"); | ||
285 | usb_release_exclusive_ata(); | ||
286 | } | ||
287 | } | ||
288 | |||
289 | #ifdef HAVE_HOTSWAP | ||
290 | void usb_storage_notify_hotswap(int volume,bool inserted) | ||
291 | { | ||
292 | logf("notify %d",inserted); | ||
293 | if(inserted && check_disk_present(volume)) { | ||
294 | ejected[volume] = false; | ||
295 | } | ||
296 | else { | ||
297 | ejected[volume] = true; | ||
298 | try_release_ata(); | ||
299 | } | ||
300 | |||
301 | } | ||
302 | #endif | ||
303 | |||
304 | void usb_storage_reconnect(void) | ||
305 | { | ||
306 | int i; | ||
307 | for(i=0;i<NUM_VOLUMES;i++) | ||
308 | ejected[i] = !check_disk_present(i); | ||
309 | |||
310 | usb_request_exclusive_ata(); | ||
311 | } | ||
312 | |||
265 | /* called by usb_code_init() */ | 313 | /* called by usb_code_init() */ |
266 | void usb_storage_init(void) | 314 | void usb_storage_init(void) |
267 | { | 315 | { |
268 | int i; | 316 | int i; |
269 | for(i=0;i<NUM_VOLUMES;i++) | 317 | for(i=0;i<NUM_VOLUMES;i++) { |
270 | ejected[i]=false; | 318 | ejected[i] = !check_disk_present(i); |
319 | } | ||
271 | logf("usb_storage_init done"); | 320 | logf("usb_storage_init done"); |
272 | } | 321 | } |
273 | 322 | ||
323 | |||
274 | int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size, | 324 | int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size, |
275 | int interface_number,int endpoint) | 325 | int interface_number,int endpoint) |
276 | { | 326 | { |
@@ -348,7 +398,7 @@ void usb_storage_transfer_complete(bool in,int status,int length) | |||
348 | int result = ata_write_sectors(IF_MV2(cur_cmd.lun,) | 398 | int result = ata_write_sectors(IF_MV2(cur_cmd.lun,) |
349 | cur_cmd.sector, | 399 | cur_cmd.sector, |
350 | MIN(BUFFER_SIZE/SECTOR_SIZE, | 400 | MIN(BUFFER_SIZE/SECTOR_SIZE, |
351 | cur_cmd.count), | 401 | cur_cmd.count), |
352 | cur_cmd.data[cur_cmd.data_select]); | 402 | cur_cmd.data[cur_cmd.data_select]); |
353 | if(result != 0) { | 403 | if(result != 0) { |
354 | send_csw(UMS_STATUS_FAIL); | 404 | send_csw(UMS_STATUS_FAIL); |
@@ -508,7 +558,7 @@ static void send_and_read_next(void) | |||
508 | cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,) | 558 | cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,) |
509 | cur_cmd.sector, | 559 | cur_cmd.sector, |
510 | MIN(BUFFER_SIZE/SECTOR_SIZE, | 560 | MIN(BUFFER_SIZE/SECTOR_SIZE, |
511 | cur_cmd.count), | 561 | cur_cmd.count), |
512 | cur_cmd.data[cur_cmd.data_select]); | 562 | cur_cmd.data[cur_cmd.data_select]); |
513 | } | 563 | } |
514 | } | 564 | } |
@@ -520,8 +570,8 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
520 | TODO: support 48-bit LBA */ | 570 | TODO: support 48-bit LBA */ |
521 | 571 | ||
522 | unsigned int length = cbw->data_transfer_length; | 572 | unsigned int length = cbw->data_transfer_length; |
523 | unsigned int block_size; | 573 | unsigned int block_size = 0; |
524 | unsigned int block_count; | 574 | unsigned int block_count = 0; |
525 | bool lun_present=true; | 575 | bool lun_present=true; |
526 | #ifdef ONLY_EXPOSE_CARD_SLOT | 576 | #ifdef ONLY_EXPOSE_CARD_SLOT |
527 | unsigned char lun = cbw->lun+1; | 577 | unsigned char lun = cbw->lun+1; |
@@ -536,9 +586,8 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
536 | block_count = cinfo->numblocks; | 586 | block_count = cinfo->numblocks; |
537 | } | 587 | } |
538 | else { | 588 | else { |
539 | lun_present=false; | 589 | ejected[lun] = true; |
540 | block_size = 0; | 590 | try_release_ata(); |
541 | block_count = 0; | ||
542 | } | 591 | } |
543 | #else | 592 | #else |
544 | unsigned short* identify = ata_get_identify(); | 593 | unsigned short* identify = ata_get_identify(); |
@@ -562,8 +611,8 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
562 | if(!usb_exclusive_ata()) { | 611 | if(!usb_exclusive_ata()) { |
563 | send_csw(UMS_STATUS_FAIL); | 612 | send_csw(UMS_STATUS_FAIL); |
564 | cur_sense_data.sense_key=SENSE_NOT_READY; | 613 | cur_sense_data.sense_key=SENSE_NOT_READY; |
565 | cur_sense_data.asc=ASC_NOT_READY; | 614 | cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; |
566 | cur_sense_data.ascq=ASCQ_BECOMING_READY; | 615 | cur_sense_data.ascq=0; |
567 | break; | 616 | break; |
568 | } | 617 | } |
569 | if(lun_present) { | 618 | if(lun_present) { |
@@ -732,12 +781,17 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
732 | 781 | ||
733 | case SCSI_START_STOP_UNIT: | 782 | case SCSI_START_STOP_UNIT: |
734 | logf("scsi start_stop unit %d",lun); | 783 | logf("scsi start_stop unit %d",lun); |
735 | if((cbw->command_block[4] & 0xf0) == 0) | 784 | if((cbw->command_block[4] & 0xf0) == 0) /*load/eject bit is valid*/ |
736 | { /* Process start and eject bits */ | 785 | { /* Process start and eject bits */ |
737 | if((cbw->command_block[4] & 0x01) == 0 && | 786 | logf("scsi load/eject"); |
738 | (cbw->command_block[4] & 0x02) != 0) /* Stop and eject */ | 787 | if((cbw->command_block[4] & 0x01) == 0) /* Don't start */ |
739 | { | 788 | { |
740 | ejected[lun]=true; | 789 | if((cbw->command_block[4] & 0x02) != 0) /* eject */ |
790 | { | ||
791 | logf("scsi eject"); | ||
792 | ejected[lun]=true; | ||
793 | try_release_ata(); | ||
794 | } | ||
741 | } | 795 | } |
742 | } | 796 | } |
743 | send_csw(UMS_STATUS_GOOD); | 797 | send_csw(UMS_STATUS_GOOD); |
@@ -828,7 +882,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
828 | cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,) | 882 | cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,) |
829 | cur_cmd.sector, | 883 | cur_cmd.sector, |
830 | MIN(BUFFER_SIZE/SECTOR_SIZE, | 884 | MIN(BUFFER_SIZE/SECTOR_SIZE, |
831 | cur_cmd.count), | 885 | cur_cmd.count), |
832 | cur_cmd.data[cur_cmd.data_select]); | 886 | cur_cmd.data[cur_cmd.data_select]); |
833 | send_and_read_next(); | 887 | send_and_read_next(); |
834 | } | 888 | } |