diff options
author | Frank Gevaerts <frank@gevaerts.be> | 2008-11-01 16:14:28 +0000 |
---|---|---|
committer | Frank Gevaerts <frank@gevaerts.be> | 2008-11-01 16:14:28 +0000 |
commit | 2f8a0081c64534da23fc0fa9cc685eb7454fd9c9 (patch) | |
tree | 84dbdbd5326cb48f43d2ebd5a4c86e992c1d5288 /firmware/usbstack/usb_storage.c | |
parent | 646cac0bde7b11fa7bcb670d1d76eec78e360485 (diff) | |
download | rockbox-2f8a0081c64534da23fc0fa9cc685eb7454fd9c9.tar.gz rockbox-2f8a0081c64534da23fc0fa9cc685eb7454fd9c9.zip |
Apply FS#9500. This adds a storage_*() abstraction to replace ata_*(). To do that, it also introduces sd_*, nand_*, and mmc_*.
This should be a good first step to allow multi-driver targets, like the Elio (ATA/SD), or the D2 (NAND/SD).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18960 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/usbstack/usb_storage.c')
-rw-r--r-- | firmware/usbstack/usb_storage.c | 125 |
1 files changed, 49 insertions, 76 deletions
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index 198ff46a56..24ac00138d 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include "usb_drv.h" | 24 | #include "usb_drv.h" |
25 | //#define LOGF_ENABLE | 25 | //#define LOGF_ENABLE |
26 | #include "logf.h" | 26 | #include "logf.h" |
27 | #include "ata.h" | 27 | #include "storage.h" |
28 | #include "hotswap.h" | 28 | #include "hotswap.h" |
29 | #include "disk.h" | 29 | #include "disk.h" |
30 | /* Needed to get at the audio buffer */ | 30 | /* Needed to get at the audio buffer */ |
@@ -36,7 +36,7 @@ | |||
36 | 36 | ||
37 | /* The SD card driver on Sansa c200 and e200 can cause write corruption, | 37 | /* The SD card driver on Sansa c200 and e200 can cause write corruption, |
38 | * often triggered by simultaneous USB activity. This can be largely avoided | 38 | * often triggered by simultaneous USB activity. This can be largely avoided |
39 | * by not overlapping ata_write_sector() with USB transfers. This does reduce | 39 | * by not overlapping storage_write_sector() with USB transfers. This does reduce |
40 | * write performance, so we only do it for the affected DAPs | 40 | * write performance, so we only do it for the affected DAPs |
41 | */ | 41 | */ |
42 | #if (CONFIG_STORAGE & STORAGE_SD) | 42 | #if (CONFIG_STORAGE & STORAGE_SD) |
@@ -147,10 +147,8 @@ struct inquiry_data { | |||
147 | struct report_lun_data { | 147 | struct report_lun_data { |
148 | unsigned int lun_list_length; | 148 | unsigned int lun_list_length; |
149 | unsigned int reserved1; | 149 | unsigned int reserved1; |
150 | unsigned char lun0[8]; | 150 | // TODO this should be cleaned up with the VOLUMES vs DRIVES mess |
151 | #ifdef HAVE_HOTSWAP | 151 | unsigned char luns[NUM_VOLUMES][8]; |
152 | unsigned char lun1[8]; | ||
153 | #endif | ||
154 | } __attribute__ ((packed)); | 152 | } __attribute__ ((packed)); |
155 | 153 | ||
156 | struct sense_data { | 154 | struct sense_data { |
@@ -263,7 +261,7 @@ static void send_command_result(void *data,int size); | |||
263 | static void send_command_failed_result(void); | 261 | static void send_command_failed_result(void); |
264 | static void send_block_data(void *data,int size); | 262 | static void send_block_data(void *data,int size); |
265 | static void receive_block_data(void *data,int size); | 263 | static void receive_block_data(void *data,int size); |
266 | static void identify2inquiry(int lun); | 264 | static void fill_inquiry(IF_MV_NONVOID(int lun)); |
267 | static void send_and_read_next(void); | 265 | static void send_and_read_next(void); |
268 | static bool ejected[NUM_VOLUMES]; | 266 | static bool ejected[NUM_VOLUMES]; |
269 | 267 | ||
@@ -289,7 +287,7 @@ static bool check_disk_present(IF_MV_NONVOID(int volume)) | |||
289 | return true; | 287 | return true; |
290 | #else | 288 | #else |
291 | unsigned char sector[512]; | 289 | unsigned char sector[512]; |
292 | return ata_read_sectors(IF_MV2(volume,)0,1,sector) == 0; | 290 | return storage_read_sectors(IF_MV2(volume,)0,1,sector) == 0; |
293 | #endif | 291 | #endif |
294 | } | 292 | } |
295 | 293 | ||
@@ -460,7 +458,7 @@ void usb_storage_transfer_complete(int ep,int dir,int status,int length) | |||
460 | cur_cmd.data[cur_cmd.data_select], | 458 | cur_cmd.data[cur_cmd.data_select], |
461 | MIN(BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE); | 459 | MIN(BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE); |
462 | #else | 460 | #else |
463 | int result = ata_write_sectors(IF_MV2(cur_cmd.lun,) | 461 | int result = storage_write_sectors(IF_MV2(cur_cmd.lun,) |
464 | cur_cmd.sector, | 462 | cur_cmd.sector, |
465 | MIN(BUFFER_SIZE/SECTOR_SIZE, | 463 | MIN(BUFFER_SIZE/SECTOR_SIZE, |
466 | cur_cmd.count), | 464 | cur_cmd.count), |
@@ -639,7 +637,7 @@ static void send_and_read_next(void) | |||
639 | ramdisk_buffer + cur_cmd.sector*SECTOR_SIZE, | 637 | ramdisk_buffer + cur_cmd.sector*SECTOR_SIZE, |
640 | MIN(BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE); | 638 | MIN(BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE); |
641 | #else | 639 | #else |
642 | cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,) | 640 | cur_cmd.last_result = storage_read_sectors(IF_MV2(cur_cmd.lun,) |
643 | cur_cmd.sector, | 641 | cur_cmd.sector, |
644 | MIN(BUFFER_SIZE/SECTOR_SIZE, | 642 | MIN(BUFFER_SIZE/SECTOR_SIZE, |
645 | cur_cmd.count), | 643 | cur_cmd.count), |
@@ -654,6 +652,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
654 | /* USB Mass Storage assumes LBA capability. | 652 | /* USB Mass Storage assumes LBA capability. |
655 | TODO: support 48-bit LBA */ | 653 | TODO: support 48-bit LBA */ |
656 | 654 | ||
655 | struct storage_info info; | ||
657 | unsigned int length = cbw->data_transfer_length; | 656 | unsigned int length = cbw->data_transfer_length; |
658 | unsigned int block_size = 0; | 657 | unsigned int block_size = 0; |
659 | unsigned int block_count = 0; | 658 | unsigned int block_count = 0; |
@@ -664,25 +663,20 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
664 | unsigned char lun = cbw->lun; | 663 | unsigned char lun = cbw->lun; |
665 | #endif | 664 | #endif |
666 | unsigned int block_size_mult = 1; | 665 | unsigned int block_size_mult = 1; |
666 | storage_get_info(IF_MV2(lun,)&info); | ||
667 | #ifdef USB_USE_RAMDISK | 667 | #ifdef USB_USE_RAMDISK |
668 | block_size = SECTOR_SIZE; | 668 | block_size = SECTOR_SIZE; |
669 | block_count = RAMDISK_SIZE; | 669 | block_count = RAMDISK_SIZE; |
670 | #else | 670 | #else |
671 | #if (CONFIG_STORAGE & STORAGE_SD) || defined(HAVE_HOTSWAP) | 671 | block_size=info.sector_size; |
672 | tCardInfo* cinfo = card_get_info(lun); | 672 | block_count=info.num_sectors; |
673 | if(cinfo->initialized && cinfo->numblocks > 0) { | 673 | #endif |
674 | block_size = cinfo->blocksize; | 674 | |
675 | block_count = cinfo->numblocks; | 675 | #ifdef HAVE_HOTSWAP |
676 | } | 676 | if(storage_removable(IF_MV(lun)) && !storage_present(IF_MV(lun))) { |
677 | else { | ||
678 | ejected[lun] = true; | 677 | ejected[lun] = true; |
679 | try_release_ata(); | 678 | try_release_ata(); |
680 | } | 679 | } |
681 | #else | ||
682 | unsigned short* identify = ata_get_identify(); | ||
683 | block_size = SECTOR_SIZE; | ||
684 | block_count = (identify[61] << 16 | identify[60]); | ||
685 | #endif | ||
686 | #endif | 680 | #endif |
687 | 681 | ||
688 | if(ejected[lun]) | 682 | if(ejected[lun]) |
@@ -719,19 +713,22 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
719 | case SCSI_REPORT_LUNS: { | 713 | case SCSI_REPORT_LUNS: { |
720 | logf("scsi inquiry %d",lun); | 714 | logf("scsi inquiry %d",lun); |
721 | int allocation_length=0; | 715 | int allocation_length=0; |
716 | int i; | ||
722 | allocation_length|=(cbw->command_block[6]<<24); | 717 | allocation_length|=(cbw->command_block[6]<<24); |
723 | allocation_length|=(cbw->command_block[7]<<16); | 718 | allocation_length|=(cbw->command_block[7]<<16); |
724 | allocation_length|=(cbw->command_block[8]<<8); | 719 | allocation_length|=(cbw->command_block[8]<<8); |
725 | allocation_length|=(cbw->command_block[9]); | 720 | allocation_length|=(cbw->command_block[9]); |
726 | memset(tb.lun_data,0,sizeof(struct report_lun_data)); | 721 | memset(tb.lun_data,0,sizeof(struct report_lun_data)); |
722 | tb.lun_data->lun_list_length=htobe32(8*NUM_VOLUMES); | ||
723 | for(i=0;i<NUM_VOLUMES;i++) | ||
724 | { | ||
727 | #ifdef HAVE_HOTSWAP | 725 | #ifdef HAVE_HOTSWAP |
728 | tb.lun_data->lun_list_length=htobe32(16); | 726 | if(storage_removable(IF_MV(i))) |
729 | tb.lun_data->lun1[1]=1; | 727 | tb.lun_data->luns[i][1]=1; |
730 | #else | 728 | else |
731 | tb.lun_data->lun_list_length=htobe32(8); | ||
732 | #endif | 729 | #endif |
733 | tb.lun_data->lun0[1]=0; | 730 | tb.lun_data->luns[i][1]=0; |
734 | 731 | } | |
735 | send_command_result(tb.lun_data, | 732 | send_command_result(tb.lun_data, |
736 | MIN(sizeof(struct report_lun_data), length)); | 733 | MIN(sizeof(struct report_lun_data), length)); |
737 | break; | 734 | break; |
@@ -739,7 +736,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
739 | 736 | ||
740 | case SCSI_INQUIRY: | 737 | case SCSI_INQUIRY: |
741 | logf("scsi inquiry %d",lun); | 738 | logf("scsi inquiry %d",lun); |
742 | identify2inquiry(lun); | 739 | fill_inquiry(IF_MV(lun)); |
743 | length = MIN(length, cbw->command_block[4]); | 740 | length = MIN(length, cbw->command_block[4]); |
744 | send_command_result(tb.inquiry, | 741 | send_command_result(tb.inquiry, |
745 | MIN(sizeof(struct inquiry_data), length)); | 742 | MIN(sizeof(struct inquiry_data), length)); |
@@ -975,7 +972,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
975 | ramdisk_buffer + cur_cmd.sector*SECTOR_SIZE, | 972 | ramdisk_buffer + cur_cmd.sector*SECTOR_SIZE, |
976 | MIN(BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE); | 973 | MIN(BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count)*SECTOR_SIZE); |
977 | #else | 974 | #else |
978 | cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,) | 975 | cur_cmd.last_result = storage_read_sectors(IF_MV2(cur_cmd.lun,) |
979 | cur_cmd.sector, | 976 | cur_cmd.sector, |
980 | MIN(BUFFER_SIZE/SECTOR_SIZE, | 977 | MIN(BUFFER_SIZE/SECTOR_SIZE, |
981 | cur_cmd.count), | 978 | cur_cmd.count), |
@@ -1072,46 +1069,30 @@ static void send_csw(int status) | |||
1072 | } | 1069 | } |
1073 | } | 1070 | } |
1074 | 1071 | ||
1075 | /* convert ATA IDENTIFY to SCSI INQUIRY */ | 1072 | static void copy_padded(char *dest, char *src, int len) |
1076 | static void identify2inquiry(int lun) | ||
1077 | { | 1073 | { |
1078 | #ifdef HAVE_FLASH_STORAGE | 1074 | int i=0; |
1079 | if(lun==0) { | 1075 | while(src[i]!=0 && i<len) |
1080 | memcpy(&tb.inquiry->VendorId,"Rockbox ",8); | 1076 | { |
1081 | memcpy(&tb.inquiry->ProductId,"Internal Storage",16); | 1077 | dest[i]=src[i]; |
1082 | memcpy(&tb.inquiry->ProductRevisionLevel,"0.00",4); | 1078 | i++; |
1083 | } | 1079 | } |
1084 | else { | 1080 | while(i<len) |
1085 | memcpy(&tb.inquiry->VendorId,"Rockbox ",8); | 1081 | { |
1086 | memcpy(&tb.inquiry->ProductId,"SD Card Slot ",16); | 1082 | dest[i]=' '; |
1087 | memcpy(&tb.inquiry->ProductRevisionLevel,"0.00",4); | 1083 | i++; |
1088 | } | 1084 | } |
1089 | #else | 1085 | } |
1090 | unsigned int i; | ||
1091 | unsigned short* dest; | ||
1092 | unsigned short* src; | ||
1093 | unsigned short* identify = ata_get_identify(); | ||
1094 | (void)lun; | ||
1095 | memset(tb.inquiry, 0, sizeof(struct inquiry_data)); | ||
1096 | |||
1097 | #if 0 | ||
1098 | if (identify[82] & 4) | ||
1099 | tb.inquiry->DeviceTypeModifier = DEVICE_REMOVABLE; | ||
1100 | #endif | ||
1101 | 1086 | ||
1102 | /* ATA only has a 'model' field, so we copy the | 1087 | /* build SCSI INQUIRY */ |
1103 | first 8 bytes to 'vendor' and the rest to 'product' (they are | 1088 | static void fill_inquiry(IF_MV_NONVOID(int lun)) |
1104 | consecutive in the inquiry struct) */ | 1089 | { |
1105 | src = (unsigned short*)&identify[27]; | 1090 | memset(tb.inquiry, 0, sizeof(struct inquiry_data)); |
1106 | dest = (unsigned short*)&tb.inquiry->VendorId; | 1091 | struct storage_info info; |
1107 | for (i=0;i<12;i++) | 1092 | storage_get_info(IF_MV2(lun,)&info); |
1108 | dest[i] = htobe16(src[i]); | 1093 | copy_padded(tb.inquiry->VendorId,info.vendor,sizeof(tb.inquiry->VendorId)); |
1109 | 1094 | copy_padded(tb.inquiry->ProductId,info.product,sizeof(tb.inquiry->ProductId)); | |
1110 | src = (unsigned short*)&identify[23]; | 1095 | copy_padded(tb.inquiry->ProductRevisionLevel,info.revision,sizeof(tb.inquiry->ProductRevisionLevel)); |
1111 | dest = (unsigned short*)&tb.inquiry->ProductRevisionLevel; | ||
1112 | for (i=0;i<2;i++) | ||
1113 | dest[i] = htobe16(src[i]); | ||
1114 | #endif | ||
1115 | 1096 | ||
1116 | tb.inquiry->DeviceType = DIRECT_ACCESS_DEVICE; | 1097 | tb.inquiry->DeviceType = DIRECT_ACCESS_DEVICE; |
1117 | tb.inquiry->AdditionalLength = 0x1f; | 1098 | tb.inquiry->AdditionalLength = 0x1f; |
@@ -1119,14 +1100,6 @@ static void identify2inquiry(int lun) | |||
1119 | tb.inquiry->Versions = 4; /* SPC-2 */ | 1100 | tb.inquiry->Versions = 4; /* SPC-2 */ |
1120 | tb.inquiry->Format = 2; /* SPC-2/3 inquiry format */ | 1101 | tb.inquiry->Format = 2; /* SPC-2/3 inquiry format */ |
1121 | 1102 | ||
1122 | #if 0 | ||
1123 | #ifdef HAVE_HOTSWAP | ||
1124 | if(lun>0) | ||
1125 | tb.inquiry->DeviceTypeModifier = DEVICE_REMOVABLE; | ||
1126 | #endif | ||
1127 | #endif | ||
1128 | /* Mac OSX 10.5 doesn't like this driver if DEVICE_REMOVABLE is not set. | ||
1129 | TODO : this can probably be solved by providing caching mode page */ | ||
1130 | #ifdef TOSHIBA_GIGABEAT_S | 1103 | #ifdef TOSHIBA_GIGABEAT_S |
1131 | tb.inquiry->DeviceTypeModifier = 0; | 1104 | tb.inquiry->DeviceTypeModifier = 0; |
1132 | #else | 1105 | #else |