From a8a10e86502617313ced924691a014d94bd54c82 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 22 Sep 2013 23:54:44 +0700 Subject: [PATCH] added read capacity 10 with hacking code --- demos/host/src/msc_app.c | 15 ++- tinyusb/class/msc.h | 33 +++-- tinyusb/class/msc_host.c | 160 +++++++++++++++++++------ tinyusb/class/msc_host.h | 20 ++-- tinyusb/common/compiler/compiler_gcc.h | 4 + tinyusb/common/compiler/compiler_iar.h | 3 + tinyusb/common/errors.h | 2 + tinyusb/host/ehci/ehci.h | 2 +- 8 files changed, 179 insertions(+), 60 deletions(-) diff --git a/demos/host/src/msc_app.c b/demos/host/src/msc_app.c index e2e5d7e4..abd53a1d 100644 --- a/demos/host/src/msc_app.c +++ b/demos/host/src/msc_app.c @@ -66,13 +66,18 @@ void tusbh_msc_mounted_cb(uint8_t dev_addr) uint8_t const* p_vendor = tusbh_msc_get_vendor_name(dev_addr); uint8_t const* p_product = tusbh_msc_get_product_name(dev_addr); - printf("Vendor Id: "); + printf("Vendor Name: "); for(uint8_t i=0; i<8; i++) putchar(p_vendor[i]); - - printf("\nProduct Id: "); - for(uint8_t i=0; i<16; i++) putchar(p_product[i]); - putchar('\n'); + + printf("Product Name: "); + for(uint8_t i=0; i<16; i++) putchar(p_product[i]); + putchar('\n'); + + uint32_t last_lba, block_size; + tusbh_msc_get_capacity(dev_addr, &last_lba, &block_size); + printf("Disk Size: %d MB\n", (last_lba+1)/ ((1024*1024)/block_size) ); + printf("LBA 0-0x%X, Block Size: %d\n", last_lba, block_size); } //--------------------------------------------------------------------+ diff --git a/tinyusb/class/msc.h b/tinyusb/class/msc.h index f52cdc34..dd4c222f 100644 --- a/tinyusb/class/msc.h +++ b/tinyusb/class/msc.h @@ -80,6 +80,7 @@ typedef enum { SCSI_CMD_TEST_UNIT_READY = 0x00, SCSI_CMD_INQUIRY = 0x12, SCSI_CMD_READ_CAPACITY_10 = 0x25, + SCSI_CMD_REQUEST_SENSE = 0x03, SCSI_CMD_READ_10 = 0x28, SCSI_CMD_WRITE_10 = 0x2A, }scsi_cmd_type_t; @@ -115,12 +116,13 @@ STATIC_ASSERT(sizeof(msc_cmd_status_wrapper_t) == 13, "size is not correct"); // SCSI Primary Command (SPC-4) //--------------------------------------------------------------------+ typedef ATTR_PACKED_STRUCT(struct) { - uint8_t operation_code; - uint8_t reserve; - uint8_t page_code; - uint16_t alloc_length; - uint8_t control; -} scsi_inquiry_t; + uint8_t cmd_code; + uint8_t reserved1; + uint8_t page_code; + uint8_t reserved2; + uint8_t alloc_length; + uint8_t control; +} scsi_inquiry_t, scsi_request_sense_t; STATIC_ASSERT(sizeof(scsi_inquiry_t) == 6, "size is not correct"); @@ -172,12 +174,23 @@ STATIC_ASSERT(sizeof(scsi_inquiry_data_t) == 36, "size is not correct"); //--------------------------------------------------------------------+ // SCSI Block Command (SBC-3) //--------------------------------------------------------------------+ +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t cmd_code; + uint8_t reserved1; + uint32_t logical_block_addr; + uint16_t reserved2; + uint8_t partial_medium_indicator; + uint8_t control; +} scsi_read_capacity10_t; + +STATIC_ASSERT(sizeof(scsi_read_capacity10_t) == 10, "size is not correct"); + typedef struct { - uint8_t logical_block_addr[4]; - uint8_t block_length[4]; -} msc_scsi_read_capacity10_t; - + uint32_t last_lba; + uint32_t block_size; +} scsi_read_capacity10_data_t; +STATIC_ASSERT(sizeof(scsi_read_capacity10_data_t) == 8, "size is not correct"); #ifdef __cplusplus } diff --git a/tinyusb/class/msc_host.c b/tinyusb/class/msc_host.c index f4d72cf9..dc658850 100644 --- a/tinyusb/class/msc_host.c +++ b/tinyusb/class/msc_host.c @@ -53,15 +53,18 @@ //--------------------------------------------------------------------+ typedef struct { pipe_handle_t bulk_in, bulk_out; - uint8_t interface_number; - uint8_t max_lun; + uint8_t interface_number; + + uint8_t max_lun; + uint16_t block_size; + uint32_t last_lba; // last logical block address uint8_t vendor_id[8]; uint8_t product_id[16]; msc_cmd_block_wrapper_t cbw; msc_cmd_status_wrapper_t csw; - uint8_t buffer[100]; + ATTR_ALIGNED(4) uint8_t buffer[100]; }msch_interface_t; STATIC_VAR msch_interface_t msch_data[TUSB_CFG_HOST_DEVICE_MAX] TUSB_CFG_ATTR_USBRAM; // TODO to be static @@ -76,26 +79,106 @@ STATIC_VAR uint8_t msch_buffer[10] TUSB_CFG_ATTR_USBRAM; //--------------------------------------------------------------------+ // PUBLIC API //--------------------------------------------------------------------+ -bool tusbh_msc_is_mounted(uint8_t dev_addr) +bool tusbh_msc_is_mounted(uint8_t dev_addr) { return tusbh_device_is_configured(dev_addr) && pipehandle_is_valid(msch_data[dev_addr-1].bulk_in) && pipehandle_is_valid(msch_data[dev_addr-1].bulk_out); } -uint8_t const * tusbh_msc_get_vendor_name(uint8_t dev_addr) +uint8_t const* tusbh_msc_get_vendor_name(uint8_t dev_addr) { return tusbh_msc_is_mounted(dev_addr) ? msch_data[dev_addr-1].vendor_id : NULL; } -uint8_t const * tusbh_msc_get_product_name(uint8_t dev_addr) +uint8_t const* tusbh_msc_get_product_name(uint8_t dev_addr) { return tusbh_msc_is_mounted(dev_addr) ? msch_data[dev_addr-1].product_id : NULL; } +tusb_error_t tusbh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size) +{ + if ( !tusbh_msc_is_mounted(dev_addr) ) return TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED; + ASSERT(p_last_lba != NULL && p_block_size != NULL, TUSB_ERROR_INVALID_PARA); + + (*p_last_lba) = msch_data[dev_addr-1].last_lba; + (*p_block_size) = (uint32_t) msch_data[dev_addr-1].block_size; + + return TUSB_ERROR_NONE; +} + //--------------------------------------------------------------------+ // CLASS-USBH API (don't require to verify parameters) //--------------------------------------------------------------------+ +static tusb_error_t scsi_command_send(msch_interface_t * p_msch, scsi_cmd_type_t cmd_code, uint8_t lun) +{ + p_msch->cbw.signature = 0x43425355; + p_msch->cbw.tag = 0xCAFECAFE; + p_msch->cbw.lun = lun; + + switch ( cmd_code ) + { + case SCSI_CMD_INQUIRY: + p_msch->cbw.xfer_bytes = sizeof(scsi_inquiry_data_t); + p_msch->cbw.flags = TUSB_DIR_DEV_TO_HOST_MASK; + p_msch->cbw.cmd_len = sizeof(scsi_inquiry_t); + + scsi_inquiry_t cmd_inquiry = + { + .cmd_code = SCSI_CMD_INQUIRY, + .alloc_length = sizeof(scsi_inquiry_data_t) + }; + + memcpy(p_msch->cbw.command, &cmd_inquiry, sizeof(scsi_inquiry_t)); + break; + + case SCSI_CMD_READ_CAPACITY_10: + p_msch->cbw.xfer_bytes = sizeof(scsi_read_capacity10_data_t); + p_msch->cbw.flags = TUSB_DIR_DEV_TO_HOST_MASK; + p_msch->cbw.cmd_len = sizeof(scsi_read_capacity10_t); + + scsi_read_capacity10_t cmd_read_capacity10 = + { + .cmd_code = SCSI_CMD_READ_CAPACITY_10, + .logical_block_addr = 0, + .partial_medium_indicator = 0 + }; + + memcpy(p_msch->cbw.command, &cmd_read_capacity10, sizeof(scsi_read_capacity10_t)); + break; + + case SCSI_CMD_TEST_UNIT_READY: + break; + + case SCSI_CMD_READ_10: + break; + + case SCSI_CMD_WRITE_10: + break; + + case SCSI_CMD_REQUEST_SENSE: + p_msch->cbw.xfer_bytes = 18; + p_msch->cbw.flags = TUSB_DIR_DEV_TO_HOST_MASK; + p_msch->cbw.cmd_len = sizeof(scsi_request_sense_t); + + scsi_request_sense_t cmd_request_sense = + { + .cmd_code = SCSI_CMD_REQUEST_SENSE, + .alloc_length = 18 + }; + + memcpy(p_msch->cbw.command, &cmd_request_sense, sizeof(scsi_request_sense_t)); + break; + + default: + return TUSB_ERROR_MSCH_UNKNOWN_SCSI_COMMAND; + } + + ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cmd_block_wrapper_t), false) ); + ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_in , p_msch->buffer, p_msch->cbw.xfer_bytes, false) ); + //ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_in , &p_msch->csw, sizeof(msc_cmd_status_wrapper_t), true) ); +} + void msch_init(void) { memclr_(msch_data, sizeof(msch_interface_t)*TUSB_CFG_HOST_DEVICE_MAX); @@ -142,31 +225,26 @@ tusb_error_t msch_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t con SUBTASK_ASSERT( TUSB_ERROR_NONE == error /* && TODO STALL means zero */); msch_data[dev_addr-1].max_lun = msch_buffer[0]; - //------------- SCSI Inquiry -------------// - msch_data[dev_addr-1].cbw = (msc_cmd_block_wrapper_t) { - .signature = 0x43425355, - .tag = 0xCAFECAFE, - .xfer_bytes = sizeof(scsi_inquiry_data_t), - .flags = TUSB_DIR_DEV_TO_HOST_MASK, - .lun = 0, - .cmd_len = sizeof(scsi_inquiry_t), - }; - scsi_inquiry_t cmd_inquiry = - { - .operation_code = SCSI_CMD_INQUIRY, - .alloc_length = sizeof(scsi_inquiry_data_t) - }; - memcpy(msch_data[dev_addr-1].cbw.command, &cmd_inquiry, sizeof(scsi_inquiry_t)); +#if 0 + //------------- Reset -------------// + OSAL_SUBTASK_INVOKED_AND_WAIT( + usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_INTERFACE), + MSC_REQUEST_RESET, 0, msch_data[dev_addr-1].interface_number, + 0, NULL ), + error + ); +#endif - hcd_pipe_xfer(msch_data[dev_addr-1].bulk_out, &msch_data[dev_addr-1].cbw, sizeof(msc_cmd_block_wrapper_t), false); - hcd_pipe_xfer(msch_data[dev_addr-1].bulk_in , msch_data[dev_addr-1].buffer, sizeof(scsi_inquiry_data_t), false); - hcd_pipe_xfer(msch_data[dev_addr-1].bulk_in , &msch_data[dev_addr-1].csw, sizeof(msc_cmd_status_wrapper_t), true); // TODO timeout required, a proper synchronization // while( !hcd_pipe_is_idle(msch_data[dev_addr-1].bulk_in) ) - { - osal_task_delay(2); - } + + //------------- SCSI Inquiry -------------// + scsi_command_send(&msch_data[dev_addr-1], SCSI_CMD_INQUIRY, 0); + osal_task_delay(5); + ASSERT_STATUS( hcd_pipe_xfer(msch_data[dev_addr-1].bulk_in , (uint8_t*) &msch_data[dev_addr-1].csw, sizeof(msc_cmd_status_wrapper_t), true) ); + osal_task_delay(5); + // check csw memcpy(msch_data[dev_addr-1].vendor_id, ((scsi_inquiry_data_t*)msch_data[dev_addr-1].buffer)->vendor_id, @@ -175,6 +253,24 @@ tusb_error_t msch_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t con ((scsi_inquiry_data_t*)msch_data[dev_addr-1].buffer)->product_id, 16); +#if 0 + //------------- SCSI Request Sense -------------// + scsi_command_send(&msch_data[dev_addr-1], SCSI_CMD_REQUEST_SENSE, 0); + osal_task_delay(5); + ASSERT_STATUS( hcd_pipe_xfer(msch_data[dev_addr-1].bulk_in , (uint8_t*) &msch_data[dev_addr-1].csw, sizeof(msc_cmd_status_wrapper_t), true) ); + osal_task_delay(5); +#endif + + //------------- SCSI Read Capacity 10 -------------// + scsi_command_send(&msch_data[dev_addr-1], SCSI_CMD_READ_CAPACITY_10, 0); + osal_task_delay(5); + ASSERT_STATUS( hcd_pipe_xfer(msch_data[dev_addr-1].bulk_in , (uint8_t*) &msch_data[dev_addr-1].csw, sizeof(msc_cmd_status_wrapper_t), true) ); + osal_task_delay(5); + // check csw + + msch_data[dev_addr-1].last_lba = __be2le( ((scsi_read_capacity10_data_t*)msch_data[dev_addr-1].buffer)->last_lba ); + msch_data[dev_addr-1].block_size = (uint16_t) __be2le( ((scsi_read_capacity10_data_t*)msch_data[dev_addr-1].buffer)->block_size ); + tusbh_msc_mounted_cb(dev_addr); OSAL_SUBTASK_END @@ -198,16 +294,6 @@ void msch_close(uint8_t dev_addr) //--------------------------------------------------------------------+ // INTERNAL & HELPER //--------------------------------------------------------------------+ -//static tusb_error_t scsi_command_send(msc_cmd_block_wrapper_t const * cbw, uint8_t * buffer, msc_cmd_status_wrapper_t const * csw) -//{ -// tusb_error_t error; -// -// OSAL_SUBTASK_BEGIN -// -// hcd_pipe_xfer() -// -// OSAL_SUBTASK_END -//} #endif diff --git a/tinyusb/class/msc_host.h b/tinyusb/class/msc_host.h index 1fd99788..324dad98 100644 --- a/tinyusb/class/msc_host.h +++ b/tinyusb/class/msc_host.h @@ -60,14 +60,20 @@ //--------------------------------------------------------------------+ bool tusbh_msc_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT; tusb_interface_status_t tusbh_msc_status(uint8_t dev_addr) ATTR_WARN_UNUSED_RESULT; -uint8_t const * tusbh_msc_get_vendor_name(uint8_t dev_addr); -uint8_t const * tusbh_msc_get_product_name(uint8_t dev_addr); +uint8_t const* tusbh_msc_get_vendor_name(uint8_t dev_addr); +uint8_t const* tusbh_msc_get_product_name(uint8_t dev_addr); +tusb_error_t tusbh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size); + +tusb_error_t tusbh_msc_inquiry(uint8_t dev_addr, scsi_inquiry_data_t * p_inquiry_data) ATTR_WARN_UNUSED_RESULT; +tusb_error_t tusbh_msc_test_unit_ready(uint8_t dev_addr) ATTR_WARN_UNUSED_RESULT; +tusb_error_t tusbh_msc_read_capacity10(uint8_t dev_addr, scsi_read_capacity10_t * p_buffer) ATTR_WARN_UNUSED_RESULT; +tusb_error_t tusbh_msc_read10(uint8_t dev_addr, void * p_buffer, uint32_t length) ATTR_WARN_UNUSED_RESULT; +tusb_error_t tusbh_msc_write10(uint8_t dev_addr, void const * p_data, uint32_t length) ATTR_WARN_UNUSED_RESULT; + +//tusb_error_t tusbh_msc_scsi_send(uint8_t dev_addr, uint8_t lun, bool is_direction_in, +// uint8_t const * p_command, uint8_t cmd_len, +// uint8_t * p_response, uint32_t resp_len) ATTR_WARN_UNUSED_RESULT; -tusb_error_t tusbh_msc_inquiry(uint8_t dev_addr, uint8_t instance_num, scsi_inquiry_data_t * p_inquiry_data) ATTR_WARN_UNUSED_RESULT; -tusb_error_t tusbh_msc_test_unit_ready(uint8_t dev_addr, uint8_t instance_num) ATTR_WARN_UNUSED_RESULT; -tusb_error_t tusbh_msc_read_capacity10(uint8_t dev_addr, uint8_t instance_num, msc_scsi_read_capacity10_t * p_buffer) ATTR_WARN_UNUSED_RESULT; -tusb_error_t tusbh_msc_read10(uint8_t dev_addr, uint8_t instance_num, void * p_buffer, uint32_t length) ATTR_WARN_UNUSED_RESULT; -tusb_error_t tusbh_msc_write10(uint8_t dev_addr, uint8_t instance_num, void const * p_data, uint32_t length) ATTR_WARN_UNUSED_RESULT; //------------- Application Callback -------------// void tusbh_msc_mounted_cb(uint8_t dev_addr); diff --git a/tinyusb/common/compiler/compiler_gcc.h b/tinyusb/common/compiler/compiler_gcc.h index e9f83a5d..b0fff10c 100644 --- a/tinyusb/common/compiler/compiler_gcc.h +++ b/tinyusb/common/compiler/compiler_gcc.h @@ -130,6 +130,10 @@ * @{ */ +// built-in function to convert 32-bit Big-Endian to Little-Endian +#define __be2le __builtin_bswap32 + + /** You can use the built-in function \b __builtin_constant_p to determine if a value is known to be constant at compile time and hence that GCC can perform constant-folding on expressions involving that value. The argument of the function is the value to test. The function returns the integer 1 if the argument is known to be a compile-time constant and 0 if it is not known to be a compile-time constant. A return of 0 does not indicate that the value is not a constant, but merely that GCC cannot prove it is a constant with the specified value of the -O option. You typically use this function in an embedded application where memory is a critical resource. If you have some complex calculation, you may want it to be folded if it involves constants, but need to call a function if it does not. For example: \code diff --git a/tinyusb/common/compiler/compiler_iar.h b/tinyusb/common/compiler/compiler_iar.h index 80373c1c..82f5079d 100644 --- a/tinyusb/common/compiler/compiler_iar.h +++ b/tinyusb/common/compiler/compiler_iar.h @@ -83,6 +83,9 @@ #define ATTR_USED #define ATTR_UNUSED +// built-in function to convert 32-bit Big-Endian to Little-Endian +#define __be2le __REV + #if 0 /** Indicates to the compiler that the function can not ever return, so that any stack restoring or diff --git a/tinyusb/common/errors.h b/tinyusb/common/errors.h index fae65a1d..96681624 100644 --- a/tinyusb/common/errors.h +++ b/tinyusb/common/errors.h @@ -85,6 +85,8 @@ ENTRY(TUSB_ERROR_CDCH_UNSUPPORTED_PROTOCOL )\ ENTRY(TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED )\ ENTRY(TUSB_ERROR_MSCH_UNSUPPORTED_PROTOCOL )\ + ENTRY(TUSB_ERROR_MSCH_UNKNOWN_SCSI_COMMAND )\ + ENTRY(TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED )\ ENTRY(TUSB_ERROR_NOT_SUPPORTED_YET )\ ENTRY(TUSB_ERROR_FAILED )\ diff --git a/tinyusb/host/ehci/ehci.h b/tinyusb/host/ehci/ehci.h index 8377af0e..ec4b4030 100644 --- a/tinyusb/host/ehci/ehci.h +++ b/tinyusb/host/ehci/ehci.h @@ -78,7 +78,7 @@ // TODO allow user to configure #define EHCI_MAX_QHD 8 -#define EHCI_MAX_QTD 12 +#define EHCI_MAX_QTD 20 #define EHCI_MAX_ITD 4 #define EHCI_MAX_SITD 16