Index: firmware/export/usb_drv.h =================================================================== --- firmware/export/usb_drv.h (revision 16246) +++ firmware/export/usb_drv.h (working copy) @@ -32,5 +32,6 @@ void usb_drv_reset_endpoint(int endpoint, bool send); void usb_drv_wait(int endpoint, bool send); bool usb_drv_powered(void); +int usb_drv_get_last_transfer_status(void); #endif Index: firmware/export/disk.h =================================================================== --- firmware/export/disk.h (revision 16246) +++ firmware/export/disk.h (working copy) @@ -39,4 +39,9 @@ int disk_mount(int drive); int disk_unmount(int drive); +/* The number of 512-byte sectors in a "logical" sector. Needed for ipod 5.5G */ +#ifdef MAX_LOG_SECTOR_SIZE +extern int disk_sector_multiplier; #endif + +#endif Index: firmware/usbstack/usb_core.c =================================================================== --- firmware/usbstack/usb_core.c (revision 16246) +++ firmware/usbstack/usb_core.c (working copy) @@ -23,10 +23,10 @@ //#define LOGF_ENABLE #include "logf.h" -//#define USB_STORAGE +#define USB_STORAGE //#define USB_SERIAL //#define USB_BENCHMARK -#define USB_CHARGING_ONLY +//#define USB_CHARGING_ONLY #include "usb_ch9.h" #include "usb_drv.h" @@ -136,7 +136,7 @@ .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = EP_TX | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, + .wMaxPacketSize = 64, .bInterval = 0 }, { @@ -144,7 +144,7 @@ .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = EP_RX | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, + .wMaxPacketSize = 64, .bInterval = 0 } #endif Index: firmware/usbstack/usb_storage.c =================================================================== --- firmware/usbstack/usb_storage.c (revision 16246) +++ firmware/usbstack/usb_storage.c (working copy) @@ -24,6 +24,7 @@ #include "logf.h" #include "ata.h" #include "hotswap.h" +#include "disk.h" #define SECTOR_SIZE 512 @@ -40,12 +41,14 @@ #define SCSI_TEST_UNIT_READY 0x00 #define SCSI_INQUIRY 0x12 #define SCSI_MODE_SENSE 0x1a +#define SCSI_REQUEST_SENSE 0x03 #define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e #define SCSI_READ_CAPACITY 0x25 #define SCSI_READ_10 0x28 #define SCSI_WRITE_10 0x2a #define SCSI_STATUS_GOOD 0x00 +#define SCSI_STATUS_FAIL 0x01 #define SCSI_STATUS_CHECK_CONDITION 0x02 @@ -62,6 +65,20 @@ unsigned char ProductRevisionLevel[4]; } __attribute__ ((packed)); +struct sense_data { + unsigned char ResponseCode; + unsigned char Obsolete; + unsigned char filemark_eom_ili_sensekey; + unsigned int Information; + unsigned char AdditionalSenseLength; + unsigned int CommandSpecificInformation; + unsigned char AdditionalSenseCode; + unsigned char AdditionalSenseCodeQualifier; + unsigned char FieldReplaceableUnitCode; + unsigned char SKSV; + unsigned short SenseKeySpecific; +} __attribute__ ((packed)); + struct command_block_wrapper { unsigned int signature; unsigned int tag; @@ -85,7 +102,7 @@ } __attribute__ ((packed)); /* the ARC USB controller can at most buffer 16KB unaligned data */ -static unsigned char _transfer_buffer[16384]; +static unsigned char _transfer_buffer[16384*8]; static unsigned char* transfer_buffer; static struct inquiry_data _inquiry; static struct inquiry_data* inquiry; @@ -99,6 +116,7 @@ unsigned int offset; /* if partial sector */ unsigned int count; unsigned int tag; + unsigned int lun; } current_cmd; void handle_scsi(struct command_block_wrapper* cbw); @@ -118,6 +136,7 @@ transfer_buffer = (void*)UNCACHED_ADDR(&_transfer_buffer); capacity_data = (void*)UNCACHED_ADDR(&_capacity_data); identify2inquiry(); + state = IDLE; } /* called by usb_core_transfer_complete() */ @@ -128,21 +147,37 @@ switch (endpoint) { case EP_RX: //logf("ums: %d bytes in", length); - switch (state) { - case IDLE: - handle_scsi(cbw); - break; - - default: - break; + if(state == RECEIVING) + { + logf("scsi write %d %d", current_cmd.sector, current_cmd.count); + if(usb_drv_get_last_transfer_status()==0) + { + ata_write_sectors(IF_MV2(current_cmd.lun,) current_cmd.sector, current_cmd.count, + transfer_buffer); + send_csw(current_cmd.tag, SCSI_STATUS_GOOD); + } + else + { + send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); + } } - - /* re-prime endpoint */ - usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer); + else + { + state = SENDING; + handle_scsi(cbw); + } + break; case EP_TX: - //logf("ums: %d bytes out", length); + //logf("ums: out complete"); + if(state != IDLE) + { + /* re-prime endpoint */ + state = IDLE; + usb_drv_recv(EP_RX, transfer_buffer, 16384/*sizeof _transfer_buffer*/); + } + break; } } @@ -156,7 +191,7 @@ switch (req->bRequest) { case USB_BULK_GET_MAX_LUN: { - static char maxlun = 0; + static char maxlun = NUM_VOLUMES - 1; logf("ums: getmaxlun"); usb_drv_send(EP_CONTROL, UNCACHED_ADDR(&maxlun), 1); usb_drv_recv(EP_CONTROL, NULL, 0); /* ack */ @@ -175,7 +210,8 @@ case USB_REQ_SET_CONFIGURATION: logf("ums: set config"); /* prime rx endpoint */ - usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer); + state = IDLE; + usb_drv_recv(EP_RX, transfer_buffer, 16384/*sizeof _transfer_buffer*/); handled = true; break; } @@ -190,21 +226,72 @@ /* USB Mass Storage assumes LBA capability. TODO: support 48-bit LBA */ + unsigned int sectors_per_transfer=0; unsigned int length = cbw->data_transfer_length; + unsigned int block_size; + unsigned char lun = cbw->lun; + unsigned int block_size_mult = 1; +#ifdef HAVE_HOTSWAP + tCardInfo* cinfo = card_get_info(lun); + block_size = cinfo->blocksize; + if(cinfo->initialized==1) + { + sectors_per_transfer=(sizeof _transfer_buffer/ block_size); + } +#else + block_size = SECTOR_SIZE; + sectors_per_transfer=(sizeof _transfer_buffer/ block_size); +#endif +#ifdef MAX_LOG_SECTOR_SIZE + block_size_mult = disk_sector_multiplier; +#endif + switch (cbw->command_block[0]) { case SCSI_TEST_UNIT_READY: logf("scsi test_unit_ready"); + #ifdef HAVE_HOTSWAP + if(cinfo->initialized==1) + send_csw(cbw->tag, SCSI_STATUS_GOOD); + else + send_csw(cbw->tag, SCSI_STATUS_FAIL); + #else send_csw(cbw->tag, SCSI_STATUS_GOOD); + #endif break; case SCSI_INQUIRY: logf("scsi inquiry"); + #ifdef HAVE_HOTSWAP + // Sansa OF always sets DEVICE_REMOVABLE + inquiry->DeviceTypeModifier |= DEVICE_REMOVABLE; + #endif length = MIN(length, cbw->command_block[4]); usb_drv_send(EP_TX, inquiry, MIN(sizeof _inquiry, length)); send_csw(cbw->tag, SCSI_STATUS_GOOD); break; + case SCSI_REQUEST_SENSE: { + static struct sense_data data; + static struct sense_data *uncached_data; + uncached_data=UNCACHED_ADDR(&data); + uncached_data->ResponseCode=0x70; + uncached_data->filemark_eom_ili_sensekey=2; + uncached_data->Information=2; + uncached_data->AdditionalSenseLength=10; + uncached_data->CommandSpecificInformation=0; + uncached_data->AdditionalSenseCode=0x3a; + uncached_data->AdditionalSenseCodeQualifier=0; + uncached_data->FieldReplaceableUnitCode=0; + uncached_data->SKSV=0; + uncached_data->SenseKeySpecific=0; + logf("scsi request_sense"); + usb_drv_send(EP_TX, UNCACHED_ADDR(&data), + sizeof(struct sense_data)); + send_csw(cbw->tag, SCSI_STATUS_GOOD); + break; + } + case SCSI_MODE_SENSE: { static unsigned char sense_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; logf("scsi mode_sense"); @@ -221,14 +308,24 @@ case SCSI_READ_CAPACITY: { logf("scsi read_capacity"); -#ifdef HAVE_FLASH_STORAGE - tCardInfo* cinfo = card_get_info(0); - capacity_data->block_count = htobe32(cinfo->numblocks); - capacity_data->block_size = htobe32(cinfo->blocksize); +#ifdef HAVE_HOTSWAP + // tCardInfo* cinfo = card_get_info(0); + // Careful : "block count" actually means the number of the last block + if(cinfo->initialized==1) + { + capacity_data->block_count = htobe32(cinfo->numblocks - 1); + capacity_data->block_size = htobe32(cinfo->blocksize); + } + else + { + capacity_data->block_count = htobe32(0); + capacity_data->block_size = htobe32(0); + } #else unsigned short* identify = ata_get_identify(); - capacity_data->block_count = htobe32(identify[60] << 16 | identify[61]); - capacity_data->block_size = htobe32(SECTOR_SIZE); + // Careful : "block count" actually means the number of the last block + capacity_data->block_count = htobe32((identify[61] << 16 | identify[60]) / block_size_mult - 1); + capacity_data->block_size = htobe32(block_size * block_size_mult); #endif usb_drv_send(EP_TX, capacity_data, MIN(sizeof _capacity_data, length)); @@ -237,38 +334,56 @@ } case SCSI_READ_10: - current_cmd.sector = - cbw->command_block[2] << 24 | + current_cmd.sector = block_size_mult * + (cbw->command_block[2] << 24 | cbw->command_block[3] << 16 | cbw->command_block[4] << 8 | - cbw->command_block[5] ; - current_cmd.count = - cbw->command_block[7] << 16 | - cbw->command_block[8]; + cbw->command_block[5] ); + current_cmd.count = block_size_mult * + (cbw->command_block[7] << 16 | + cbw->command_block[8]); current_cmd.offset = 0; current_cmd.tag = cbw->tag; + current_cmd.lun = cbw->lun; logf("scsi read %d %d", current_cmd.sector, current_cmd.count); - /* too much? */ - if (current_cmd.count > (sizeof _transfer_buffer / SECTOR_SIZE)) { - send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); - break; + logf("Asked for %d sectors",current_cmd.count); + if(current_cmd.count > sectors_per_transfer) + { + current_cmd.count = sectors_per_transfer; } + logf("Sending %d sectors",current_cmd.count); - ata_read_sectors(IF_MV2(0,) current_cmd.sector, current_cmd.count, + ata_read_sectors(IF_MV2(lun,) current_cmd.sector, current_cmd.count, transfer_buffer); - state = SENDING; - usb_drv_send(EP_TX, transfer_buffer, - MIN(current_cmd.count * SECTOR_SIZE, length)); + usb_drv_send(EP_TX, transfer_buffer, current_cmd.count*block_size); + send_csw(current_cmd.tag, SCSI_STATUS_GOOD); break; case SCSI_WRITE_10: logf("scsi write10"); + current_cmd.sector = block_size_mult * + (cbw->command_block[2] << 24 | + cbw->command_block[3] << 16 | + cbw->command_block[4] << 8 | + cbw->command_block[5] ); + current_cmd.count = block_size_mult * + (cbw->command_block[7] << 16 | + cbw->command_block[8]); + current_cmd.offset = 0; + current_cmd.tag = cbw->tag; + current_cmd.lun = cbw->lun; + // expect data + usb_drv_recv(EP_RX, transfer_buffer,current_cmd.count*block_size); + state = RECEIVING; + break; default: logf("scsi unknown cmd %x", cbw->command_block[0]); + usb_drv_stall(EP_TX, true); + send_csw(current_cmd.tag, SCSI_STATUS_FAIL); break; } } Index: firmware/target/arm/usb-fw-pp502x.c =================================================================== --- firmware/target/arm/usb-fw-pp502x.c (revision 16246) +++ firmware/target/arm/usb-fw-pp502x.c (working copy) @@ -57,6 +57,8 @@ void usb_enable(bool on) { if (on) { + usb_core_init(); +#if 0 /* until we have native mass-storage mode, we want to reboot on usb host connect */ #if defined(IRIVER_H10) || defined (IRIVER_H10_5GB) @@ -78,6 +80,7 @@ system_reboot(); /* Reboot */ } +#endif } else usb_core_exit(); Index: firmware/target/arm/usb-drv-pp502x.c =================================================================== --- firmware/target/arm/usb-drv-pp502x.c (revision 16246) +++ firmware/target/arm/usb-drv-pp502x.c (working copy) @@ -295,7 +295,9 @@ } __attribute__ ((packed)); static struct transfer_descriptor _td_array[NUM_ENDPOINTS*2] __attribute((aligned (32))); +static struct transfer_descriptor _extra_td_array[32] __attribute((aligned (32))); static struct transfer_descriptor* td_array; +static struct transfer_descriptor* extra_td_array; /* manual: 32.13.1 Endpoint Queue Head (dQH) */ struct queue_head { @@ -317,9 +319,13 @@ 0x04, 0x040000, }; +struct transfer_descriptor* first_td; +struct transfer_descriptor* last_td; + /*-------------------------------------------------------------------------*/ static void transfer_completed(void); static int prime_transfer(int endpoint, void* ptr, int len, bool send); +static void prepare_td(struct transfer_descriptor* td,struct transfer_descriptor* previous_td,void *ptr, int len); static void bus_reset(void); static void init_queue_heads(void); static void init_endpoints(void); @@ -340,7 +346,12 @@ REG_USBMODE = USBMODE_CTRL_MODE_DEVICE; + // Force device to full speed to see if that works better + // See 32.9.5.9.2 + REG_PORTSC1 |= PORTSCX_PORT_FORCE_FULL_SPEED; + td_array = (struct transfer_descriptor*)UNCACHED_ADDR(&_td_array); + extra_td_array = (struct transfer_descriptor*)UNCACHED_ADDR(&_extra_td_array); qh_array = (struct queue_head*)UNCACHED_ADDR(&_qh_array); init_queue_heads(); memset(td_array, 0, sizeof _td_array); @@ -482,6 +493,20 @@ while (REG_ENDPTFLUSH & mask); } +int usb_drv_get_last_transfer_status(void) +{ + struct transfer_descriptor* current_td = first_td; + while(!((unsigned int)current_td & DTD_NEXT_TERMINATE)) + { + if((current_td->size_ioc_sts & 0xff) != 0) + { + return current_td->size_ioc_sts & 0xff; + } + current_td=(struct transfer_descriptor*)current_td->next_td_ptr; + } + return 0; +} + /*-------------------------------------------------------------------------*/ /* manual: 32.14.5.2 */ @@ -490,24 +515,39 @@ int timeout; int pipe = endpoint * 2 + (send ? 1 : 0); unsigned int mask = pipe2mask[pipe]; - struct transfer_descriptor* td = &td_array[pipe]; + last_td = 0; struct queue_head* qh = &qh_array[pipe]; if (send && endpoint > EP_CONTROL) { logf("usb: sent %d bytes", len); } - memset(td, 0, sizeof(struct transfer_descriptor)); - td->next_td_ptr = DTD_NEXT_TERMINATE; - td->size_ioc_sts = (len << DTD_LENGTH_BIT_POS) | - DTD_STATUS_ACTIVE | DTD_IOC; - td->buff_ptr0 = (unsigned int)ptr; - td->buff_ptr1 = (unsigned int)ptr + 0x1000; - td->buff_ptr2 = (unsigned int)ptr + 0x2000; - td->buff_ptr3 = (unsigned int)ptr + 0x3000; - td->buff_ptr4 = (unsigned int)ptr + 0x4000; - td->reserved = len; - qh->dtd.next_td_ptr = (unsigned int)td; + if(len==0) + { + struct transfer_descriptor* new_td = &extra_td_array[0]; + prepare_td(new_td,0,ptr,0); + + last_td=new_td; + first_td=new_td; + } + else + { + int td_idx=0; + while(len>0) + { + int current_transfer_length = MIN(16384,len); + struct transfer_descriptor* new_td = &extra_td_array[td_idx]; + prepare_td(new_td,last_td,ptr,current_transfer_length); + + last_td=new_td; + len-=current_transfer_length; + td_idx++; + ptr+=current_transfer_length; + } + first_td=&extra_td_array[0]; + } + + qh->dtd.next_td_ptr = (unsigned int)first_td; qh->dtd.size_ioc_sts &= ~(QH_STATUS_HALT | QH_STATUS_ACTIVE); REG_ENDPTPRIME |= mask; @@ -521,7 +561,6 @@ logf("prime timeout"); return -2; } - if (!(REG_ENDPTSTATUS & mask)) { logf("no prime! %d %d %x", endpoint, pipe, qh->dtd.size_ioc_sts & 0xff ); return -3; @@ -530,22 +569,54 @@ if (send) { /* wait for transfer to finish */ timeout = 100000; - while ((td->size_ioc_sts & DTD_STATUS_ACTIVE) && --timeout) { - if (REG_ENDPTCOMPLETE & mask) - REG_ENDPTCOMPLETE |= mask; - if (REG_USBSTS & USBSTS_RESET) - return -4; + struct transfer_descriptor* current_td = first_td; + while(!((unsigned int)current_td & DTD_NEXT_TERMINATE)) + { + while ((current_td->size_ioc_sts & DTD_STATUS_ACTIVE) && --timeout) { + if (REG_ENDPTCOMPLETE & mask) + REG_ENDPTCOMPLETE |= mask; + + if (REG_USBSTS & USBSTS_RESET) + { + logf("td interrupted by reset"); + return -4; + } + } + if (!timeout) { + logf("td never finished"); + logf("status = %X",qh->dtd.size_ioc_sts&0xff); + return -5; + } + logf("td finished : %X",current_td->size_ioc_sts & 0xff); + current_td=(struct transfer_descriptor*)current_td->next_td_ptr; } - if (!timeout) { - logf("td never finished"); - return -5; - } + logf("all tds done"); } return 0; } +static void prepare_td(struct transfer_descriptor* td,struct transfer_descriptor* previous_td,void *ptr, int len) +{ + logf("adding a td : %d",len); + memset(td, 0, sizeof(struct transfer_descriptor)); + td->next_td_ptr = DTD_NEXT_TERMINATE; + td->size_ioc_sts = (len<< DTD_LENGTH_BIT_POS) | + DTD_STATUS_ACTIVE | DTD_IOC; + td->buff_ptr0 = (unsigned int)ptr; + td->buff_ptr1 = ((unsigned int)ptr & 0xfffff000) + 0x1000; + td->buff_ptr2 = ((unsigned int)ptr & 0xfffff000) + 0x2000; + td->buff_ptr3 = ((unsigned int)ptr & 0xfffff000) + 0x3000; + td->buff_ptr4 = ((unsigned int)ptr & 0xfffff000) + 0x4000; + + if(previous_td != 0) + { + previous_td->next_td_ptr=(unsigned int)td; + previous_td->size_ioc_sts&=~DTD_IOC;// Only an interrupt on the last one + } +} + static void transfer_completed(void) { int i; @@ -608,15 +679,15 @@ memset(qh_array, 0, sizeof _qh_array); /*** control ***/ - qh_array[EP_CONTROL].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS | QH_IOS; + qh_array[EP_CONTROL].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS | QH_IOS; qh_array[EP_CONTROL].dtd.next_td_ptr = QH_NEXT_TERMINATE; - qh_array[EP_CONTROL+1].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS; + qh_array[EP_CONTROL+1].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS; qh_array[EP_CONTROL+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; /*** bulk ***/ - qh_array[EP_RX*2].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS; + qh_array[EP_RX*2].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; qh_array[EP_RX*2].dtd.next_td_ptr = QH_NEXT_TERMINATE; - qh_array[EP_TX*2+1].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS; + qh_array[EP_TX*2+1].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; qh_array[EP_TX*2+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; } Index: firmware/common/disk.c =================================================================== --- firmware/common/disk.c (revision 16246) +++ firmware/common/disk.c (working copy) @@ -48,6 +48,9 @@ static struct partinfo part[8]; /* space for 4 partitions on 2 drives */ static int vol_drive[NUM_VOLUMES]; /* mounted to which drive (-1 if none) */ +#ifdef MAX_LOG_SECTOR_SIZE +int disk_sector_multiplier = 1; +#endif struct partinfo* disk_init(IF_MV_NONVOID(int drive)) { int i; @@ -168,6 +171,10 @@ mounted++; vol_drive[volume] = drive; /* remember the drive for this volume */ volume = get_free_volume(); /* prepare next entry */ + if(drive==0) + { + disk_sector_multiplier=j; + } break; } }