summaryrefslogtreecommitdiff
path: root/firmware/usbstack/usb_storage.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/usbstack/usb_storage.c')
-rw-r--r--firmware/usbstack/usb_storage.c86
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
265static 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
271static 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
290void 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
304void 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() */
266void usb_storage_init(void) 314void 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
274int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size, 324int 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 }