From 44a83a12cd229f160854d98dc4a239b206ba5f0f Mon Sep 17 00:00:00 2001 From: ksb Date: Sat, 11 Jul 2009 14:43:13 +0000 Subject: [PATCH] USB mass storage class --- cpu/arm/common/usb/msc/scsi_command.h | 70 ++++ cpu/arm/common/usb/msc/scsi_sense.h | 116 ++++++ cpu/arm/common/usb/msc/scsi_struct.h | 424 +++++++++++++++++++++ cpu/arm/common/usb/msc/usb-msc-bulk.c | 509 ++++++++++++++++++++++++++ cpu/arm/common/usb/msc/usb-msc-bulk.h | 132 +++++++ 5 files changed, 1251 insertions(+) create mode 100644 cpu/arm/common/usb/msc/scsi_command.h create mode 100644 cpu/arm/common/usb/msc/scsi_sense.h create mode 100644 cpu/arm/common/usb/msc/scsi_struct.h create mode 100644 cpu/arm/common/usb/msc/usb-msc-bulk.c create mode 100644 cpu/arm/common/usb/msc/usb-msc-bulk.h diff --git a/cpu/arm/common/usb/msc/scsi_command.h b/cpu/arm/common/usb/msc/scsi_command.h new file mode 100644 index 000000000..b8d84e5cd --- /dev/null +++ b/cpu/arm/common/usb/msc/scsi_command.h @@ -0,0 +1,70 @@ +#ifndef __SCSI_COMMAND_H__SR3ALQCZSH__ +#define __SCSI_COMMAND_H__SR3ALQCZSH__ + +#define SCSI_CMD_CHANGE_DEFINITION 0x40 +#define SCSI_CMD_COMPARE 0x39 +#define SCSI_CMD_COPY 0x18 +#define SCSI_CMD_COPY_AND_VERIFY 0x3a +#define SCSI_CMD_ERASE 0x19 +#define SCSI_CMD_FORMAT 0x04 +#define SCSI_CMD_INQUIRY 0x12 +#define SCSI_CMD_LOAD_UNLOAD 0x1b +#define SCSI_CMD_LOCATE 0x2b +#define SCSI_CMD_LOCK_UNLOCK_CACHE 0x36 +#define SCSI_CMD_LOG_SELECT 0x4c +#define SCSI_CMD_LOG_SENSE 0x4d +#define SCSI_CMD_MODE_SELECT_6 0x15 +#define SCSI_CMD_MODE_SELECT_10 0x55 +#define SCSI_CMD_MODE_SENSE_6 0x1a +#define SCSI_CMD_MODE_SENSE_10 0x5a +#define SCSI_CMD_PREFETCH 0x34 +#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define SCSI_CMD_PRINT 0x0a +#define SCSI_CMD_READ_6 0x08 +#define SCSI_CMD_READ_10 0x28 +#define SCSI_CMD_READ_BLOCK_LIMITS 0x05 +#define SCSI_CMD_READ_BUFFER 0x3c +#define SCSI_CMD_READ_CAPACITY 0x25 +#define SCSI_CMD_READ_DEFECT_DATA 0x37 +#define SCSI_CMD_READ_LONG 0x3e +#define SCSI_CMD_READ_POSITION 0x34 +#define SCSI_CMD_READ_REVERSE 0x0f +#define SCSI_CMD_REASSIGN BLOCKS 0x07 +#define SCSI_CMD_RECEIVE_DIAGNOSTIC_RESULTS 0x1c +#define SCSI_CMD_RECOVER_BUFFERED_DATA 0x14 +#define SCSI_CMD_RELEASE_UNIT 0x17 +#define SCSI_CMD_REQUEST_SENSE 0x03 +#define SCSI_CMD_RESERVE_UNIT 0x16 +#define SCSI_CMD_REWIND 0x01 +#define SCSI_CMD_REZERO_UNIT 0x01 +#define SCSI_CMD_SEARCH_DATA_EQUAL_10 0x31 +#define SCSI_CMD_SEARCH_DATA_EQUAL_12 0xb1 +#define SCSI_CMD_SEARCH_DATA_HIGH_10 0x30 +#define SCSI_CMD_SEARCH_DATA_HIGH_12 0xb0 +#define SCSI_CMD_SEARCH_DATA_LOW_10 0x32 +#define SCSI_CMD_SEARCH_DATA_LOW_12 0xb2 +#define SCSI_CMD_SEEK_6 0x0B +#define SCSI_CMD_SEEK_10 0x2B +#define SCSI_CMD_SEND_DIAGNOSTIC 0x1d +#define SCSI_CMD_SET_LIMITS 0x33 +#define SCSI_CMD_SLEW_AND_PRINT 0x0b +#define SCSI_CMD_SPACE 0x11 +#define SCSI_CMD_START_STOP_UNIT 0x1B +#define SCSI_CMD_STOP_PRINT 0x1b +#define SCSI_CMD_SYNCHRONIZE_CACHE 0x35 +#define SCSI_CMD_SYNCHRONIZE_BUFFER 0x10 +#define SCSI_CMD_TEST_UNIT_READY 0x00 +#define SCSI_CMD_VERIFY 0x13 +#define SCSI_CMD_WRITE_6 0x0a +#define SCSI_CMD_WRITE_10 0x2a +#define SCSI_CMD_WRITE_12 0xaa +#define SCSI_CMD_WRITE_AND_VERIFY_10 0x2e +#define SCSI_CMD_WRITE_AND_VERIFY_12 0xae +#define SCSI_CMD_WRITE_BUFFER 0x3b +#define SCSI_CMD_WRITE_FILEMARKS 0x10 +#define SCSI_CMD_WRITE_LONG 0x3f +#define SCSI_CMD_WRITE_SAME 0x41 + + + +#endif /* __SCSI_COMMAND_H__SR3ALQCZSH__ */ diff --git a/cpu/arm/common/usb/msc/scsi_sense.h b/cpu/arm/common/usb/msc/scsi_sense.h new file mode 100644 index 000000000..98364660c --- /dev/null +++ b/cpu/arm/common/usb/msc/scsi_sense.h @@ -0,0 +1,116 @@ +/* Sense keys */ +#define SCSI_SENSE_KEY_NO_SENSE 0x0 +#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x1 +#define SCSI_SENSE_KEY_NOT_READY 0x2 +#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x3 +#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x4 +#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x5 +#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x6 +#define SCSI_SENSE_KEY_DATA_PROTECT 0x7 +#define SCSI_SENSE_KEY_BLANK_CHECK 0x8 +#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x9 +#define SCSI_SENSE_KEY_COPY_ABORTED 0xA +#define SCSI_SENSE_KEY_ABORTED_COMMAND 0xB +#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0xD +#define SCSI_SENSE_KEY_MISCOMPARE 0xE + +/* Additional sense codes */ +#define SCSI_ASC_NO_SENSE 0x0000 +#define SCSI_ASC_FILEMARK_DETECTED 0x0001 +#define SCSI_ASC_END_OF_MEDIUM_DETECTED 0x0002 +#define SCSI_ASC_BEGINNING_OF_MEDIUM_DETECTED 0x0004 +#define SCSI_ASC_END_OF_DATA_DETECTED 0x0005 +#define SCSI_ASC_PERIPHERAL_DEVICE_WRITE_FAULT 0x0300 +#define SCSI_ASC_NO_WRITE_CURRENT 0x0301 +#define SCSI_ASC_EXCESSIVE_WRITE_ERRORS 0x0302 +#define SCSI_ASC_NOT_READY_CAUSE_NOT_REPORTABLE 0x0400 +#define SCSI_ASC_IN_PROCESS_OF_BECOMING_READY 0x0401 +#define SCSI_ASC_NOT_READY_INITIALIZING_COMMAND_REQUIRED 0x0402 +#define SCSI_ASC_NOT_READY_MANUAL_INTERVENTION_REQUIRED 0x0403 +#define SCSI_ASC_NOT_READY_FORMAT_IN_PROGRESS 0x0404 +#define SCSI_ASC_COMMUNICATION_FAILURE 0x0800 +#define SCSI_ASC_COMMUNICATION_TIME_OUT 0x0801 +#define SCSI_ASC_COMMUNICATION_PARITY_ERROR 0x0802 +#define SCSI_ASC_TRACK_FOLLOWING_ERROR 0x0900 +#define SCSI_ASC_ERROR_LOG_OVERFLOW 0x0a00 +#define SCSI_ASC_WRITE_ERROR 0x0c00 +#define SCSI_ASC_UNRECOVERED_READ_ERROR 0x1100 +#define SCSI_ASC_READ_RETRIES_EXHAUSTED 0x1101 +#define SCSI_ASC_ERROR_TOO_LONG_TO_CORRECT 0x1102 +#define SCSI_ASC_MULTIPLE_READ_ERRORS 0x1103 +#define SCSI_ASC_INCOMPLETE_BLOCK_READ 0x1108 +#define SCSI_ASC_NO_GAP_FOUND 0x1109 +#define SCSI_ASC_MISCORRECTED_ERROR 0x110a +#define SCSI_ASC_RECORDED_ENTITY_NOT_FOUND 0x1400 +#define SCSI_ASC_RECORD_NOT_FOUND 0x1401 +#define SCSI_ASC_FILEMARK_NOT_FOUND 0x1402 +#define SCSI_ASC_END_OF_DATA_NOT_FOUND 0x1403 +#define SCSI_ASC_BLOCK_SEQUENCE_ERROR 0x1404 +#define SCSI_ASC_RANDOM_POSITIONING_ERROR 0x1500 +#define SCSI_ASC_MECHANICAL_POSITIONING_ERROR 0x1501 +#define SCSI_ASC_POSITIONING_ERROR_DETECTED_BY_READ OF_MEDIUM 0x1502 +#define SCSI_ASC_RECOVERED_DATA_WITH_NO_ERROR_CORRECTION_APPLIED 0x1700 +#define SCSI_ASC_RECOVERED_DATA_WITH_RETRIES 0x1701 +#define SCSI_ASC_RECOVERED_DATA_WITH_POSITIVE_HEAD_OFFSET 0x1702 +#define SCSI_ASC_RECOVERED_DATA_WITH_NEGATIVE_HEAD_OFFSET 0x1703 +#define SCSI_ASC_RECOVERED_DATA_WITH_ERROR_CORRECTION_APPLIED 0x1800 +#define SCSI_ASC_DEFECTLIST_ERROR 0x1900 +#define SCSI_ASC_PARAMETER_LIST_LENGTH_ERROR 0x1a00 +#define SCSI_ASC_INVALID_COMMAND_OPERATION_CODE 0x2000 +#define SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x2100 +#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x2400 +#define SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED 0x2500 +#define SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x2600 +#define SCSI_ASC_PARAMETER_NOT_SUPPORTED 0x2601 +#define SCSI_ASC_PARAMETER_VALUE_INVALID 0x2602 +#define SCSI_ASC_THRESHOLD_PARAMETERS_NOT_SUPPORTED 0x2603 +#define SCSI_ASC_WRITE_PROTECTED 0x2700 +#define SCSI_ASC_NOT_READY_TO_READY_TRANSITION 0x2800 +#define SCSI_ASC_PARAMETERS_CHANGED 0x2a00 +#define SCSI_ASC_MODE_PARAMETERS_CHANGED 0x2a01 +#define SCSI_ASC_OVERWRITE_ERROR_ON_UPDATE_IN_PLACE 0x2d00 +#define SCSI_ASC_POWERON_RESET_OR_DEVICE_RESET_OCCURRED 0x2900 +#define SCSI_ASC_INCOMPATIBLE_MEDIUM_INSTALLED 0x3000 +#define SCSI_ASC_CANNOT_READ_MEDIUM_UNKNOWN_FORMAT 0x3001 +#define SCSI_ASC_CANNOT_READ_MEDIUM_INCOMPATIBLE_FORMAT 0x3002 +#define SCSI_ASC_CLEANING_CARTRIDGE_INSTALLED 0x3003 +#define SCSI_ASC_MEDIUM_FORMAT_CORRUPTED 0x3100 +#define SCSI_ASC_TAPE_LENGTH_ERROR 0x3300 +#define SCSI_ASC_ROUNDED_PARAMETER 0x3700 +#define SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x3900 +#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3a00 +#define SCSI_ASC_SEQUENTIAL_POSITIONING_ERROR 0x3b00 +#define SCSI_ASC_TAPE_POSITION_ERROR_AT_BEGINNING_OF_MEDIUM 0x3b01 +#define SCSI_ASC_TAPE_POSITION_ERROR_AT_END_OF_MEDIUM 0x3b02 +#define SCSI_ASC_REPOSITION_ERROR 0x3b08 +#define SCSI_ASC_NOT_SELF_CONFIGURED_YET 0x3e00 +#define SCSI_ASC_OPERATING_CONDITIONS_HAVE_CHANGED 0x3f00 +#define SCSI_ASC_MICROCODE_HAS_BEEN_CHANGED 0x3f01 +#define SCSI_ASC_INQUIRY_DATA_HAS_CHANGED 0x3f03 +/* 40 NN DIAGNOSTIC FAILURE ON COMPONENT NN (80H-FF H) */ +#define SCSI_ASC_INTERNAL_FAILURE 0x4400 +#define SCSI_ASC_UNSUCCESSFUL_DEVICE_RESET 0x4600 +#define SCSI_ASC_FAILED_SELF_CONFIGURATION 0x4c00 +#define SCSI_ASC_OVERLAPPED_COMMANDS_ATTEMPTED 0x4e00 +#define SCSI_ASC_WRITE_APPEND_ERROR 0x5000 +#define SCSI_ASC_WRITE_APPEND_POSITION_ERROR 0x5001 +#define SCSI_ASC_POSITION_ERROR_RELATED_TO_TIMING 0x5002 +#define SCSI_ASC_ERASE_FAILURE 0x5100 +#define SCSI_ASC_CARTRIDGE_FAULT 0x5200 +#define SCSI_ASC_MEDIA_LOAD_EJECT_FAILED 0x5300 +#define SCSI_ASC_UNLOAD_TAPE_FAILURE 0x5301 +#define SCSI_ASC_MEDIUM_REMOVAL_PREVENTED 0x5302 +#define SCSI_ASC_OPERATOR_REQUEST_OR_STATE_CHANGE_INPUT 0x5a00 +#define SCSI_ASC_OPERATOR_MEDIUM_REMOVAL_REQUEST 0x5a01 +#define SCSI_ASC_OPERATOR_SELECTED_WRITE_PROTECT 0x5a01 +#define SCSI_ASC_OPERATOR_SELECTED_WRITE_PERMIT 0x5a03 +#define SCSI_ASC_LOG_EXCEPTION 0x5b00 +#define SCSI_ASC_THRESHOLD_CONDITION_MET 0x5b01 +#define SCSI_ASC_LOG_COUNTER_AT_MAXIMUM 0x5b02 +#define SCSI_ASC_LOG_LIST_CODES_EXHAUSTED 0x5b03 +/* +70 NN DECOMPRES S ION EXCEP TION SHORT ALGORITHM ID OF NN +71 00 DECOMPRES S ION EXCEP TION LONG ALGORITHM ID +*/ + + diff --git a/cpu/arm/common/usb/msc/scsi_struct.h b/cpu/arm/common/usb/msc/scsi_struct.h new file mode 100644 index 000000000..0214c7833 --- /dev/null +++ b/cpu/arm/common/usb/msc/scsi_struct.h @@ -0,0 +1,424 @@ +#include +#include +#include + +#ifndef CC_BYTE_ALIGNED +#ifdef __GNUC__ +#define CC_BYTE_ALIGNED __attribute__ ((packed)) +#endif +#endif + +#ifndef CC_BYTE_ALIGNED +#define CC_BYTE_ALIGNED +#endif + +#define HOST16_TO_BE_BYTES(x) {(((x) >> 8) & 0xff), ((x) & 0xff)} +#define HOST24_TO_BE_BYTES(x) {(((x) >> 16) & 0xff), (((x) >> 8) & 0xff), \ + ((x) & 0xff)} +#define HOST32_TO_BE_BYTES(x) {(((x) >> 24) & 0xff), (((x) >> 16) & 0xff), \ + (((x) >> 8) & 0xff), ((x) & 0xff)} +#define HOST40_TO_BE_BYTES(x) {(((x) >> 32) & 0xff), (((x) >> 24) & 0xff), (((x) >> 16) & 0xff), \ + (((x) >> 8) & 0xff), ((x) & 0xff)} + +typedef uint8_t uint40_bytes[5]; +typedef uint8_t uint32_bytes[4]; +typedef uint8_t int24_bytes[3]; +typedef uint8_t uint24_bytes[3]; +typedef uint8_t uint16_bytes[2]; + +inline unsigned long +be16_to_host(uint16_bytes bytes) +{ + return bytes[0] << 8 | bytes[1]; +} + +inline unsigned long +be24_to_host(uint24_bytes bytes) +{ + return bytes[0] << 16 | bytes[1] << 8 | bytes[2]; +} + +inline long +signed_be24_to_host(int24_bytes bytes) +{ + return ((bytes[0] << 16 | bytes[1] << 8 | bytes[2]) ^ 0x800000) - 0x800000; +} + + +inline unsigned long +be32_to_host(uint32_bytes bytes) +{ + return (be16_to_host(bytes) << 16) | be16_to_host(bytes + 2); +} + + +#define BE16_TO_HOST(bytes) ((bytes)[0] << 8 | (bytes)[1]) +#define BE32_TO_HOST(bytes) \ +((BE16_TO_HOST(bytes) << 16) | BE16_TO_HOST((bytes)+2)) + +/* Flag field of INQUIRY command */ +#define SCSI_INQUIRY_FLAG_CMDDT 0x02 +#define SCSI_INQUIRY_FLAG_EVPD 0x01 +#define SCSI_INQUIRY_FLAG_LUN(a) ((a)<<5) + +struct scsi_inquiry_cmd +{ + uint8_t op_code; + uint8_t flags; + uint8_t page; + uint8_t reserved; + uint8_t allocation_length; + uint8_t control; +} CC_BYTE_ALIGNED; + +/* Constant for the standard inquiry data */ +#define SCSI_STD_INQUIRY_CONNECTED 0x00 +#define SCSI_STD_INQUIRY_NOT_CONNECTED 0x20 + +#define SCSI_STD_INQUIRY_VERSION_NONE 0x00 +#define SCSI_STD_INQUIRY_VERSION_SCSI1 0x01 +#define SCSI_STD_INQUIRY_VERSION_SCSI2 0x02 +#define SCSI_STD_INQUIRY_VERSION_SPC2 0x04 + +#define SCSI_STD_INQUIRY_RESPONSE_DATA_FORMAT_SCSI1 0x00 +#define SCSI_STD_INQUIRY_RESPONSE_DATA_FORMAT_SCSI2 0x02 + +#define SCSI_STD_INQUIRY_TYPE_DIRECT_ACCESS 0x00 +#define SCSI_STD_INQUIRY_TYPE_SEQUENTIAL 0x01 +#define SCSI_STD_INQUIRY_TYPE_PRINTER 0x02 +#define SCSI_STD_INQUIRY_TYPE_PROCESSOR 0x03 +#define SCSI_STD_INQUIRY_TYPE_WRITE_ONCE 0x04 +#define SCSI_STD_INQUIRY_TYPE_CD_ROM 0x05 +#define SCSI_STD_INQUIRY_TYPE_SCANNER 0x06 +#define SCSI_STD_INQUIRY_TYPE_OPTICAL 0x07 +#define SCSI_STD_INQUIRY_TYPE_CHANGER 0x08 +#define SCSI_STD_INQUIRY_TYPE_COMM 0x09 +#define SCSI_STD_INQUIRY_TYPE_RAID 0x0C +#define SCSI_STD_INQUIRY_TYPE_RBC 0x0E + +#define SCSI_STD_INQUIRY_FLAG1_RMB 0x80 + +#define SCSI_STD_INQUIRY_FLAG2_AERC 0x80 +#define SCSI_STD_INQUIRY_FLAG2_AENC 0x80 +#define SCSI_STD_INQUIRY_FLAG2_NORMACA 0x20 +#define SCSI_STD_INQUIRY_FLAG2_HISUP 0x10 +#define SCSI_STD_INQUIRY_FLAG2_RESPONSE_FORMAT 0x02 + +#define SCSI_STD_INQUIRY_FLAG3_SCCS 0x80 + +#define SCSI_STD_INQUIRY_FLAG4_BQUE 0x80 +#define SCSI_STD_INQUIRY_FLAG4_ENCSERV 0x40 +#define SCSI_STD_INQUIRY_FLAG4_VS 0x20 +#define SCSI_STD_INQUIRY_FLAG4_MULTIP 0x10 +#define SCSI_STD_INQUIRY_FLAG4_MCHNGR 0x08 +#define SCSI_STD_INQUIRY_FLAG4_ADDR16 0x01 + +#define SCSI_STD_INQUIRY_FLAG5_RELADR 0x80 +#define SCSI_STD_INQUIRY_FLAG5_WBUS 0x20 +#define SCSI_STD_INQUIRY_FLAG5_SYNC 0x10 +#define SCSI_STD_INQUIRY_FLAG5_LINKED 0x08 +#define SCSI_STD_INQUIRY_FLAG5_CMDQUE 0x02 + +struct scsi_std_inquiry_data +{ + uint8_t device; + uint8_t flags1; + uint8_t version; + uint8_t flags2; + uint8_t additional_length; + uint8_t flags3; + uint8_t flags4; + uint8_t flags5; + char vendor_id[8]; + char product_id[16]; + char product_rev[4]; +} CC_BYTE_ALIGNED; + +struct scsi_vital_product_data_head +{ + uint8_t device; + uint8_t page; + uint8_t reserved; + uint8_t page_length; +} CC_BYTE_ALIGNED; + +struct scsi_identification_descriptor +{ + uint8_t code_set; + uint8_t identifier_type; + uint8_t reserved; + uint8_t identifier_length; +}; + +struct scsi_request_sense_cmd +{ + uint8_t op_code; + uint8_t reserved1; + uint8_t reserved2; + uint8_t reserved3; + uint8_t allocation_length; + uint8_t control; +} CC_BYTE_ALIGNED; + +#define SCSI_SENSE_CURRENT_ERROR 0x70 +#define SCSI_SENSE_DEFERRED_ERROR 0x71 +#define SCSI_SENSE_INFORMATION_VALID 0x80 +#define SCSI_SENSE_FILEMARK 0x80 +#define SCSI_SENSE_EOM 0x40 +#define SCSI_SENSE_ILI 0x20 + +struct scsi_sense_data +{ + uint8_t response_code; + uint8_t obsolete; + uint8_t sense_key; + uint8_t information[4]; + uint8_t additional_length; + uint8_t command_specific[4]; + uint8_t asc; + uint8_t ascq; + uint8_t unit_code; + uint8_t sense_key_specific[3]; +} CC_BYTE_ALIGNED; + + +/* Flag field of INQUIRY command */ +#define SCSI_MODE_SENSE_FLAG_DBD 0x08 +#define SCSI_MODE_SENSE_FLAG_LUN(a) ((a)<<5) + +#define SCSI_MODE_SENSE_PC_CURRENT 0x00 +#define SCSI_MODE_SENSE_PC_CHANGEABLE 0x40 +#define SCSI_MODE_SENSE_PC_DEFAULT 0x80 +#define SCSI_MODE_SENSE_PC_SAVED 0xc0 + +struct scsi_mode_sence_6_cmd +{ + uint8_t op_code; + uint8_t flags; + uint8_t page_code; + uint8_t reserved; + uint8_t allocation_length; + uint8_t control; +} CC_BYTE_ALIGNED; + +struct scsi_mode_select_6_cmd +{ + uint8_t op_code; + uint8_t flags; + uint8_t reserved1; + uint8_t reserved2; + uint8_t parameter_list_length; + uint8_t control; +}; + +#define SCSI_MODE_PARAM_WP 0x80 +#define SCSI_MODE_PARAM_BUFFERED_MODE_SYNC 0x00 +#define SCSI_MODE_PARAM_BUFFERED_MODE_ASYNC 0x10 +#define SCSI_MODE_PARAM_BUFFERED_MODE_ALL_SYNC 0x10 +#define SCSI_MODE_PARAM_SPEED_DEFAULT 0x00 +#define SCSI_MODE_PARAM_SPEED_LOWEST 0x01 +#define SCSI_MODE_PARAM_SPEED_HIGHEST 0x0f + +struct scsi_mode_parameter_header_6 +{ + uint8_t mode_data_length; + uint8_t medium_type; + uint8_t device_specific_parameter; + uint8_t block_descriptor_length; +} CC_BYTE_ALIGNED; + +#define SCSI_DENSITY_9_800 0x01 +#define SCSI_DENSITY_9_1600 0x02 +#define SCSI_DENSITY_9_6250 0x03 +#define SCSI_DENSITY_4_9_8000 0x05 +#define SCSI_DENSITY_9_3200 0x06 +#define SCSI_DENSITY_4_6400 0x07 +#define SCSI_DENSITY_4_8000 0x08 +#define SCSI_DENSITY_18_37871 0x09 +#define SCSI_DENSITY_22_6667 0x0a +#define SCSI_DENSITY_4_1600 0x0b +#define SCSI_DENSITY_24_12690 0x0c +#define SCSI_DENSITY_24_25380 0xd +#define SCSI_DENSITY_15_10000 0x0f +#define SCSI_DENSITY_18_10000 0x10 +#define SCSI_DENSITY_26_16000 0x11 +#define SCSI_DENSITY_30_51667 0x12 +#define SCSI_DENSITY_1_2400 0x13 +#define SCSI_DENSITY_1_43245 0x14 +#define SCSI_DENSITY_1_45434 0x15 +#define SCSI_DENSITY_48_10000 0x16 +#define SCSI_DENSITY_48_42500 0x17 + + +struct scsi_mode_parameter_block_descriptor +{ + uint8_t density_code; + uint24_bytes number_of_blocks; + uint8_t reserved; + uint24_bytes block_length; +} CC_BYTE_ALIGNED; + + +#define SCSI_MODE_PAGE_PS 0x80 +#define SCSI_MODE_PAGE_CONTROL_MODE 0x0a +#define SCSI_MODE_PAGE_DEVICE_CONFIGURATION 0x10 +#define SCSI_MODE_PAGE_CONNECT 0x02 +#define SCSI_MODE_PAGE_MEDIUM_PARTITION_1 0x11 +#define SCSI_MODE_PAGE_MEDIUM_PARTITION_2 0x12 +#define SCSI_MODE_PAGE_MEDIUM_PARTITION_3 0x13 +#define SCSI_MODE_PAGE_MEDIUM_PARTITION_4 0x14 +#define SCSI_MODE_PAGE_PERIPHERIAL_DEVICE 0x09 +#define SCSI_MODE_PAGE_RW_ERROR_RECOVERY 0x01 +#define SCSI_MODE_PAGE_VENDOR_SPECIFIC 0x00 +#define SCSI_MODE_PAGE_ALL_PAGES 0x3f + +struct scsi_mode_page_header +{ + uint8_t page_code; + uint8_t page_length; +} CC_BYTE_ALIGNED; + +#define SCSI_MODE_PAGE_CONTROL_FLAGS1_RLEC 0x01 +#define SCSI_MODE_PAGE_CONTROL_FLAGS2_QERR 0x02 +#define SCSI_MODE_PAGE_CONTROL_FLAGS2_DQUE 0x02 +#define SCSI_MODE_PAGE_CONTROL_FLAGS2_RESTRICED_REORDERING 0x00 +#define SCSI_MODE_PAGE_CONTROL_FLAGS2_UNRESTRICED_REORDERING 0x01 +#define SCSI_MODE_PAGE_CONTROL_FLAGS3_EECA 0x80 +#define SCSI_MODE_PAGE_CONTROL_FLAGS3_UAAENP 0x02 +#define SCSI_MODE_PAGE_CONTROL_FLAGS3_EAENP 0x01 + +struct scsi_mode_page_control +{ + struct scsi_mode_page_header header; + uint8_t flags1; + uint8_t flags2; + uint8_t flags3; + uint8_t reserved; + uint16_bytes ready_AEN_holdoff_period; +} CC_BYTE_ALIGNED; + +#define SCSI_MODE_PAGE_CONNECT_FLAGS_DTDC_NONE 0x00 +#define SCSI_MODE_PAGE_CONNECT_FLAGS_DTDC_TRANSFERRED 0x01 +#define SCSI_MODE_PAGE_CONNECT_FLAGS_DTDC_COMPLETE 0x03 + +struct scsi_mode_page_connect +{ + struct scsi_mode_page_header header; + uint8_t buffer_full_ratio; + uint8_t buffer_empty_ratio; + uint16_bytes bus_inactivity_limit; + uint16_bytes disconnect_time_limit; + uint16_bytes connect_time_limit; + uint16_bytes maximum_burst_size; + uint8_t flags; + uint8_t reserved[3]; +} CC_BYTE_ALIGNED; + +struct scsi_mode_page_peripherial_device +{ + struct scsi_mode_page_header header; + uint16_bytes interface_identifier; + uint8_t reserved[4]; + uint16_bytes maximum_burst_size; +} CC_BYTE_ALIGNED; + +#define SCSI_MODE_PAGE_DEV_CONF_CAF 0x02 +#define SCSI_MODE_PAGE_DEV_CONF_CAP 0x04 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS1_REW 0x01 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS1_RBO 0x02 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS1_SOCF_IGNORE 0x00 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS1_SOCF_1 0x04 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS1_SOCF_2 0x08 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS1_SOCF_3 0xc0 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS1_AVC 0x10 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS1_RSMK 0x20 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS1_BIS 0x40 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS1_DBR 0x40 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS2_SEW 0x08 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS2_EEG 0x10 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS2_EOD_DEFAULT 0x00 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS2_EOD_ERASE_AREA 0x20 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS2_EOD_SOCF 0x40 +#define SCSI_MODE_PAGE_DEV_CONF_FLAGS2_EOD_NONE 0x60 + +#define SCSI_MODE_PAGE_DEV_CONF_COMPR_NONE 0x00 +#define SCSI_MODE_PAGE_DEV_CONF_COMPR_DEFAULT 0x01 + +struct scsi_mode_page_device_configuration +{ + struct scsi_mode_page_header header; + uint8_t active_format; + uint8_t active_partition; + uint8_t write_buffer_full_ratio; + uint8_t read_buffer_empty_ratio; + uint16_bytes write_delay_time; + uint8_t flags1; + uint8_t gap_size; + uint8_t flags2; + uint24_bytes buffer_size_at_early_warning; + uint8_t select_data_compression; + uint8_t reserved; +}; + +struct scsi_read_buffer_limits_cmd +{ + uint8_t op_code; + uint8_t lun; + uint8_t reserved[3]; + uint8_t control; +} CC_BYTE_ALIGNED; + +struct scsi_read_buffer_limits_data +{ + uint8_t reserved; + uint24_bytes maximum_block_length_limit; + uint16_bytes minimum_block_length_limit; +} CC_BYTE_ALIGNED; + +#define SCSI_READ_FLAGS_FIXED 0x01 +#define SCSI_READ_FLAGS_SILI 0x02 + +struct scsi_read_6_cmd +{ + uint8_t op_code; + uint8_t flags; + uint24_bytes transfer_length; + uint8_t control; +} CC_BYTE_ALIGNED; + +#define SCSI_WRITE_FLAGS_FIXED 0x01 + +struct scsi_write_6_cmd +{ + uint8_t op_code; + uint8_t flags; + uint24_bytes transfer_length; + uint8_t control; +} CC_BYTE_ALIGNED; + +#define SCSI_WRITE_FILEMARKS_FLAGS_IMMED 0x01 +#define SCSI_WRITE_FILEMARKS_FLAGS_WSMK 0x02 + +struct scsi_write_filemarks_6_cmd +{ + uint8_t op_code; + uint8_t flags; + int24_bytes transfer_length; + uint8_t control; +} CC_BYTE_ALIGNED; + +#define SCSI_SPACE_FLAGS_CODE 0x07 +#define SCSI_SPACE_FLAGS_CODE_BLOCKS 0x00 +#define SCSI_SPACE_FLAGS_CODE_FILEMARKS 0x01 +#define SCSI_SPACE_FLAGS_CODE_SEQ_FILEMARKS 0x02 +#define SCSI_SPACE_FLAGS_CODE_END_OF_DATA 0x03 +#define SCSI_SPACE_FLAGS_CODE_SETMARKS 0x04 +#define SCSI_SPACE_FLAGS_CODE_SEQ_SETMARKS 0x05 + +struct scsi_space_cmd +{ + uint8_t op_code; + uint8_t flags; + int24_bytes transfer_length; + uint8_t control; +} CC_BYTE_ALIGNED; diff --git a/cpu/arm/common/usb/msc/usb-msc-bulk.c b/cpu/arm/common/usb/msc/usb-msc-bulk.c new file mode 100644 index 000000000..e7c111668 --- /dev/null +++ b/cpu/arm/common/usb/msc/usb-msc-bulk.c @@ -0,0 +1,509 @@ +#include "usb-msc-bulk.h" +#include +#include +#include +#include +#include + +#define DEBUG + +#ifdef DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +static const uint8_t max_lun = 0; + +static USBBuffer data_usb_buffer[USB_MSC_BUFFERS]; +static unsigned int buffer_lengths[USB_MSC_BUFFERS]; + +static unsigned int buf_first = 0; /* First prepared buffer */ +static unsigned int buf_free = 0; /* First free buffer */ +static unsigned int buf_submitted = 0; /* Oldest submitted buffer */ + +#define USB_BUFFER_ID_UNUSED 0 +#define USB_BUFFER_ID_CBW 1 +#define USB_BUFFER_ID_CSW 2 +#define USB_BUFFER_ID_DATA 3 +#define USB_BUFFER_ID_DISCARD 4 +#define USB_BUFFER_ID_HALT 5 +#define USB_BUFFER_ID_MASK 0x07 + +static struct usb_msc_bulk_cbw cbw_buffer; +static struct usb_msc_bulk_csw csw_buffer; + +#define BULK_OUT 0x02 +#define BULK_IN 0x81 + +PROCESS(usb_mass_bulk_process, "USB mass storage bulk only process"); + +static process_event_t reset_event; + +static struct usb_msc_command_state state; + +/* Handle wrapping */ +#define PREV_BUF(x) (((x) == 0) ? USB_MSC_BUFFERS - 1 : (x) - 1) +#define NEXT_BUF(x) (((x) < (USB_MSC_BUFFERS-1)) ? (x) + 1 : 0) +void +usb_msc_send_data_buf_flags(const uint8_t *data, unsigned int len, + unsigned int flags, uint16_t buf_flags) +{ + USBBuffer *buffer = &data_usb_buffer[buf_free]; + if (buffer->id != USB_BUFFER_ID_UNUSED) { + printf("Data IN buffer busy\n"); + return; + } + buffer->flags = USB_BUFFER_NOTIFY | buf_flags; + buffer->next = NULL; + buffer->data = (uint8_t*)data; + buffer->left = len; + buffer_lengths[buf_free] = len; + buffer->id = USB_BUFFER_ID_DATA | flags; + if (buf_free != buf_first) { + data_usb_buffer[PREV_BUF(buf_free)].next = buffer; + } + state.cmd_data_submitted += len; + buf_free = NEXT_BUF(buf_free); +/* PRINTF("usb_msc_send_data: %d\n", len); */ + if (flags & USB_MSC_DATA_SEND) { + usb_submit_xmit_buffer(BULK_IN, &data_usb_buffer[buf_first]); + buf_first = buf_free; +/* PRINTF("usb_msc_send_data: sent\n"); */ + } else if (flags & USB_MSC_DATA_LAST) { + /* Cancel transmission */ + buf_first = buf_free; + process_poll(&usb_mass_bulk_process); + } +} + +void +usb_msc_send_data(const uint8_t *data, unsigned int len, unsigned int flags) +{ + usb_msc_send_data_buf_flags(data, len, flags,0); +} + +void +usb_msc_receive_data_buf_flags(uint8_t *data, unsigned int len, + unsigned int flags, uint16_t buf_flags) +{ + USBBuffer *buffer = &data_usb_buffer[buf_free]; + if (buffer->id != USB_BUFFER_ID_UNUSED) { + printf("Data IN buffer busy\n"); + return; + } + buffer->flags = USB_BUFFER_NOTIFY | buf_flags; + buffer->next = NULL; + buffer->data = data; + buffer->left = len; + buffer_lengths[buf_free] = len; + buffer->id = USB_BUFFER_ID_DATA | flags; + if (buf_free != buf_first) { + data_usb_buffer[PREV_BUF(buf_free)].next = buffer; + } + state.cmd_data_submitted += len; + buf_free = NEXT_BUF(buf_free); + if (flags & USB_MSC_DATA_RECEIVE) { + usb_submit_recv_buffer(BULK_OUT, &data_usb_buffer[buf_first]); + buf_first = buf_free; + } else if (flags & USB_MSC_DATA_LAST) { + usb_discard_all_buffers(BULK_OUT); + /* Mark the discarded buffers as unused */ + while(buf_submitted != PREV_BUF(buf_free)) { + data_usb_buffer[buf_submitted].id = USB_BUFFER_ID_UNUSED; + buf_submitted = NEXT_BUF(buf_submitted); + } + buf_first = buf_free; + process_poll(&usb_mass_bulk_process); + } +} + +void +usb_msc_receive_data(uint8_t *data, unsigned int len, unsigned int flags) +{ + usb_msc_receive_data_buf_flags(data,len,flags, 0); +} + +static unsigned int +handle_mass_bulk_requests() +{ + switch(usb_setup_buffer.bmRequestType) { + case 0x21: /* interface OUT requests */ + switch(usb_setup_buffer.bRequest) { + case MASS_BULK_RESET: + PRINTF("Mass storage reset\n"); + process_post(&usb_mass_bulk_process, reset_event, NULL); + return 1; + } + break; + case 0xa1: /* interface IN requests */ + switch(usb_setup_buffer.bRequest) { + case MASS_BULK_GET_MAX_LUN: + PRINTF("Get LUN\n"); + usb_send_ctrl_response(&max_lun, sizeof(max_lun)); + return 1; + } + break; + } + return 0; +} + +static const struct USBRequestHandler mass_bulk_request_handler = + { + 0x21, 0x7f, + 0x00, 0x00, + handle_mass_bulk_requests + }; + +static struct USBRequestHandlerHook mass_bulk_request_hook = + { + NULL, + &mass_bulk_request_handler + }; + +static void +send_csw(void) +{ + USBBuffer *buffer = &data_usb_buffer[buf_free]; + if (buffer->id != USB_BUFFER_ID_UNUSED) { + printf("CSW buffer busy\n"); + return; + } + + csw_buffer.dCSWSignature = MASS_BULK_CSW_SIGNATURE; + csw_buffer.dCSWTag = cbw_buffer.dCBWTag; + csw_buffer.dCSWDataResidue = + cbw_buffer.dCBWDataTransferLength - state.cmd_data_submitted; + csw_buffer.bCSWStatus = state.status; + + buffer->flags = USB_BUFFER_NOTIFY; + buffer->next = NULL; + buffer->data =(uint8_t*)&csw_buffer ; + buffer->left = sizeof(csw_buffer); + buffer->id = USB_BUFFER_ID_CSW; + if (buf_free != buf_first) { + data_usb_buffer[PREV_BUF(buf_free)].next = buffer; + } + buf_free = NEXT_BUF(buf_free); + usb_submit_xmit_buffer(BULK_IN, &data_usb_buffer[buf_first]); + buf_first = buf_free; + + PRINTF("CSW sent: %ld\n", sizeof(csw_buffer)); +} + +static void +submit_cbw_buffer(void) +{ + USBBuffer *buffer = &data_usb_buffer[buf_free]; + if (buffer->id != USB_BUFFER_ID_UNUSED) { + printf("CBW buffer busy\n"); + return; + } + buffer->flags = USB_BUFFER_NOTIFY; + buffer->next = NULL; + buffer->data = (uint8_t*)&cbw_buffer; + buffer->left = sizeof(cbw_buffer); + buffer->id = USB_BUFFER_ID_CBW; + if (buf_free != buf_first) { + data_usb_buffer[PREV_BUF(buf_free)].next = buffer; + } + buf_free = NEXT_BUF(buf_free); + usb_submit_recv_buffer(BULK_OUT, &data_usb_buffer[buf_first]); + PRINTF("CBW submitted: %d\n", buf_first); + buf_first = buf_free; +} + +static void +submit_halt(uint8_t addr) +{ + USBBuffer *buffer = &data_usb_buffer[buf_free]; + if (buffer->id != USB_BUFFER_ID_UNUSED) { + printf("CBW buffer busy\n"); + return; + } + buffer->flags = USB_BUFFER_NOTIFY | USB_BUFFER_HALT; + buffer->next = NULL; + buffer->data = NULL; + buffer->left = 0; + buffer->id = USB_BUFFER_ID_HALT; + if (buf_free != buf_first) { + data_usb_buffer[PREV_BUF(buf_free)].next = buffer; + } + buf_free = NEXT_BUF(buf_free); + if (addr & 0x80) { + usb_submit_xmit_buffer(addr, &data_usb_buffer[buf_first]); + } else { + usb_submit_recv_buffer(addr, &data_usb_buffer[buf_first]); + } + PRINTF("HALT submitted %p\n",buffer); + buf_first = buf_free; +} + +static USBBuffer * +get_next_buffer(uint8_t addr, uint32_t id) +{ + unsigned int events; + events = usb_get_ep_events(addr); + if (events & USB_EP_EVENT_NOTIFICATION) { + USBBuffer *buffer = &data_usb_buffer[buf_submitted]; + if (!(buffer->flags & USB_BUFFER_SUBMITTED)) { +#ifdef DEBUG + if (id != (buffer->id & USB_BUFFER_ID_MASK)) { + printf("Wrong buffer ID expected %d, got %d\n", + (int)id, (int)buffer->id); + } +#endif + if ((buffer->id & USB_BUFFER_ID_MASK) == USB_BUFFER_ID_DATA) { + state.cmd_data_transfered += + buffer_lengths[buf_submitted] - buffer->left; + } + buffer->id = USB_BUFFER_ID_UNUSED; + buf_submitted =NEXT_BUF(buf_submitted); + return buffer; + } + } + return NULL; +} + +PROCESS(usb_mass_bulk_request_process, "USB mass storage request process"); + +PROCESS_THREAD(usb_mass_bulk_request_process, ev , data) +{ + PROCESS_BEGIN(); + reset_state: + usb_discard_all_buffers(BULK_OUT); + usb_discard_all_buffers(BULK_IN); + memset(data_usb_buffer, 0, sizeof(data_usb_buffer)); + buf_first = 0; + buf_free = 0; + buf_submitted = 0; + submit_cbw_buffer(); + receive_cbw_state: + PRINTF("receive_cbw_state\n"); + while(1) { + PROCESS_WAIT_EVENT(); + if (ev == reset_event) goto reset_state; + if (ev == PROCESS_EVENT_POLL) { + USBBuffer *buffer; + if ((buffer = get_next_buffer(BULK_OUT, USB_BUFFER_ID_CBW))) { + + /* CBW */ + if (cbw_buffer.dCBWSignature == MASS_BULK_CBW_SIGNATURE) { + usb_msc_handler_status ret; + PRINTF("Got CBW seq %d\n",(int)cbw_buffer.dCBWTag); + state.command = cbw_buffer.CBWCB; + state.command_length = cbw_buffer.bCBWCBLength; + state.status = MASS_BULK_CSW_STATUS_FAILED; + state.data_cb = NULL; + state.cmd_data_submitted = 0; + state.cmd_data_transfered = 0; + ret = usb_msc_handle_command(&state); + if (ret == USB_MSC_HANDLER_OK) { + state.status = MASS_BULK_CSW_STATUS_PASSED; + } else if (ret == USB_MSC_HANDLER_FAILED) { + state.status = MASS_BULK_CSW_STATUS_FAILED; + } + if (ret != USB_MSC_HANDLER_DELAYED + && buf_submitted == buf_free) goto send_csw_state; + if (cbw_buffer.bmCBWFlags & MASS_BULK_CBW_FLAG_IN) { + goto send_data_state; + } else { + goto receive_data_state; + } + } else { + printf("Invalid CBW\n"); + submit_halt(BULK_IN); + submit_halt(BULK_OUT); + while(1) { + PROCESS_WAIT_EVENT(); + if (ev == reset_event) goto reset_state; + if (ev == PROCESS_EVENT_POLL) { + USBBuffer *buffer = get_next_buffer(BULK_IN, USB_BUFFER_ID_HALT); + if (buffer && (buffer->flags & USB_BUFFER_HALT)) break; + } + } + while(1) { + PROCESS_WAIT_EVENT(); + if (ev == reset_event) goto reset_state; + if (ev == PROCESS_EVENT_POLL) { + USBBuffer *buffer = get_next_buffer(BULK_OUT, USB_BUFFER_ID_HALT); + if (buffer && (buffer->flags & USB_BUFFER_HALT)) break; + } + } + /* CBW */ + goto receive_cbw_state; + } + } + } + } + + send_data_state: + PRINTF("send_data_state\n"); + while(1) { + uint8_t id = 0; + /* Wait for any data to be sent */ + while (buf_submitted == buf_free) { + PROCESS_WAIT_EVENT(); + } +#if 0 + /* Send CSW early to improve throughput, unless we need to HALT + the endpoint due to short data */ + if ((data_usb_buffer[PREV_BUF(buf_free)].id & USB_MSC_DATA_LAST) + && state.cmd_data_submitted == cbw_buffer.dCBWDataTransferLength) { + send_csw(); + } +#endif + /* Wait until the current buffer is free */ + while (data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED) { + PROCESS_WAIT_EVENT(); + } + while (!(data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED)) { + id = data_usb_buffer[buf_submitted].id; + /* PRINTF("id: %02x\n", id); */ + if (id == USB_BUFFER_ID_UNUSED) break; + state.cmd_data_transfered += buffer_lengths[buf_submitted]; + data_usb_buffer[buf_submitted].id = USB_BUFFER_ID_UNUSED; + buf_submitted =NEXT_BUF(buf_submitted); + if (id & USB_MSC_DATA_DO_CALLBACK) { + if (state.data_cb) { + state.data_cb(&state); + } + } + + + if (id & USB_MSC_DATA_LAST) { + break; + } + } + if (id & USB_MSC_DATA_LAST) { + break; + } + } + if (state.cmd_data_submitted < cbw_buffer.dCBWDataTransferLength) { + submit_halt(BULK_IN); + while(1) { + PROCESS_WAIT_EVENT(); + if (ev == reset_event) goto reset_state; + if (ev == PROCESS_EVENT_POLL) { + USBBuffer *buffer = get_next_buffer(BULK_IN , USB_BUFFER_ID_HALT); + if (buffer) { + if (buffer->flags & USB_BUFFER_HALT) break; + } + } + } + } + goto send_csw_state; + + receive_data_state: + PRINTF("receive_data_state\n"); + while(1) { + uint8_t id = 0; + /* Wait for any buffers to be submitted */ + while (buf_submitted == buf_free) { + PROCESS_WAIT_EVENT(); + } + /* Wait until the current buffer is free */ + while (data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED) { + PROCESS_WAIT_EVENT(); + } + while (!(data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED)) { + id = data_usb_buffer[buf_submitted].id; + /* PRINTF("id: %02x\n", id); */ + state.cmd_data_transfered += buffer_lengths[buf_submitted]; + if (id == USB_BUFFER_ID_UNUSED) break; + data_usb_buffer[buf_submitted].id = USB_BUFFER_ID_UNUSED; + buf_submitted =NEXT_BUF(buf_submitted); + if (id & USB_MSC_DATA_DO_CALLBACK) { + if (state.data_cb) { + state.data_cb(&state); + } + } + + if (id & USB_MSC_DATA_LAST) { + break; + } + } + if (id & USB_MSC_DATA_LAST) { + break; + } + + } + + if (state.cmd_data_submitted < cbw_buffer.dCBWDataTransferLength) { + submit_halt(BULK_OUT); + while(1) { + PROCESS_WAIT_EVENT(); + if (ev == reset_event) goto reset_state; + if (ev == PROCESS_EVENT_POLL) { + USBBuffer *buffer = get_next_buffer(BULK_OUT, USB_BUFFER_ID_HALT); + if (buffer && (buffer->flags & USB_BUFFER_HALT)) break; + } + } + } + goto send_csw_state; + + + send_csw_state: + PRINTF("send_csw_state\n"); + if (data_usb_buffer[PREV_BUF(buf_free)].id != USB_BUFFER_ID_CSW) { + send_csw(); + } + submit_cbw_buffer(); + while(1) { + if (ev == reset_event) goto reset_state; + PROCESS_WAIT_EVENT(); + if (ev == PROCESS_EVENT_POLL) { + USBBuffer *buffer; + if ((buffer = get_next_buffer(BULK_IN, USB_BUFFER_ID_CSW))) { + goto receive_cbw_state; + } + } + } + goto receive_cbw_state; + PROCESS_END(); +} + +PROCESS_THREAD(usb_mass_bulk_process, ev , data) +{ + PROCESS_BEGIN(); + reset_event = process_alloc_event(); + usb_msc_command_handler_init(); + usb_setup(); + usb_set_ep_event_process(BULK_IN, &usb_mass_bulk_request_process); + usb_set_ep_event_process(BULK_OUT, &usb_mass_bulk_request_process); + usb_set_global_event_process(process_current); + usb_register_request_handler(&mass_bulk_request_hook); + while(1) { + PROCESS_WAIT_EVENT(); + if (ev == PROCESS_EVENT_EXIT) break; + if (ev == PROCESS_EVENT_POLL) { + unsigned int events = usb_get_global_events(); + if (events) { + if (events & USB_EVENT_CONFIG) { + if (usb_get_current_configuration() != 0) { + PRINTF("Configured\n"); + memset(data_usb_buffer, 0, sizeof(data_usb_buffer)); + usb_setup_bulk_endpoint(BULK_IN); + usb_setup_bulk_endpoint(BULK_OUT); + process_start(&usb_mass_bulk_request_process,NULL); + } else { + process_exit(&usb_mass_bulk_request_process); + usb_disable_endpoint(BULK_IN); + usb_disable_endpoint(BULK_OUT); + } + } + if (events & USB_EVENT_RESET) { + PRINTF("RESET\n"); + process_exit(&usb_mass_bulk_request_process); + } + } + } + } + PROCESS_END(); +} + +void +usb_msc_bulk_setup() +{ + process_start(&usb_mass_bulk_process, NULL); +} diff --git a/cpu/arm/common/usb/msc/usb-msc-bulk.h b/cpu/arm/common/usb/msc/usb-msc-bulk.h new file mode 100644 index 000000000..0d2a7464b --- /dev/null +++ b/cpu/arm/common/usb/msc/usb-msc-bulk.h @@ -0,0 +1,132 @@ +#ifndef __USB_MSC_BULK_H__SHSP6ONHDJ__ +#define __USB_MSC_BULK_H__SHSP6ONHDJ__ + +#include +#include + +#define USB_MSC_BUFFERS 4 + +/* Communication Class */ +/* Class code */ +#define MASS_STORAGE 0x08 + +/* Interface subclass codes */ +#define MASS_RBC 0x01 +#define MASS_SFF_8020i 0x02 +#define MASS_MMC_2 0x02 +#define MASS_QIC_157 0x03 +#define MASS_UFI 0x04 +#define MASS_SFF_8070i 0x05 +#define MASS_SCSI_TRANSP 0x06 + +/* Protocols */ +#define MASS_CBI_COMPLETION 0x00 +#define MASS_CBI_NO_COMPLETION 0x01 +#define MASS_BULK_ONLY 0x50 + +/* Requests */ +#define MASS_BULK_RESET 0xff +#define MASS_BULK_GET_MAX_LUN 0xfe + +#define MASS_BULK_CBW_SIGNATURE 0x43425355 +#define MASS_BULK_CSW_SIGNATURE 0x53425355 + +#define MASS_BULK_CBW_FLAG_IN 0x80 + +#define MASS_BULK_CSW_STATUS_PASSED 0x00 +#define MASS_BULK_CSW_STATUS_FAILED 0x01 +#define MASS_BULK_CSW_STATUS_PHASE_ERROR 0x02 + +struct usb_msc_bulk_cbw +{ + uint32_t dCBWSignature; + uint32_t dCBWTag; + uint32_t dCBWDataTransferLength; + uint8_t bmCBWFlags; + uint8_t bCBWLUN; + uint8_t bCBWCBLength; + uint8_t CBWCB[16]; +} BYTE_ALIGNED; + +struct usb_msc_bulk_csw +{ + uint32_t dCSWSignature; + uint32_t dCSWTag; + uint32_t dCSWDataResidue; + uint8_t bCSWStatus; +} BYTE_ALIGNED; + +struct usb_msc_command_state +{ + const uint8_t *command; + unsigned int command_length; + unsigned int status; + /* Number of data bytes received or sent */ + unsigned int cmd_data_transfered; + /* Number of data bytes submitted for transmition or reception */ + unsigned int cmd_data_submitted; + /* Set by command handler or callback */ + void (*data_cb)(struct usb_msc_command_state *state); /* May be NULL */ +}; + +void +usb_msc_bulk_setup(); + +typedef enum { + USB_MSC_HANDLER_OK = 0, + USB_MSC_HANDLER_DELAYED, + USB_MSC_HANDLER_FAILED +} usb_msc_handler_status; + +usb_msc_handler_status +usb_msc_handle_command(struct usb_msc_command_state *state); + +void +usb_msc_command_handler_init(); + +/* Call data_cb when this data has been sent or received */ +#define USB_MSC_DATA_DO_CALLBACK 0x20 + +/* Actually send the data, not just buffer it */ +#define USB_MSC_DATA_SEND 0x40 + +/* Actually receive the data, not just queue buffers for it */ +#define USB_MSC_DATA_RECEIVE 0x40 + +/* The command don't want to send or receive anymore data */ +#define USB_MSC_DATA_LAST 0x80 + +/* Submit a buffer with data to send to the host. Use a callback to be + notified when data has been sent. Data is not copied so it must + remain constant while sending. */ +void +usb_msc_send_data(const uint8_t *data, unsigned int len, unsigned int flags); + +/* Same as usb_msc_send_data but allows one to set additional flags + in USBBuffer */ +void +usb_msc_send_data_buf_flags(const uint8_t *data, unsigned int len, + unsigned int flags, uint16_t buf_flags); + +#define USB_MSC_SEND_ABORT() \ +usb_msc_send_data_buf_flags(NULL, 0, USB_MSC_DATA_LAST, 0) + +/* Submit a buffer for receiving data from the host. Use a callback to + be notified when data has arrived. */ +void +usb_msc_receive_data(uint8_t *data, unsigned int len, unsigned int flags); + +/* Same as usb_msc_receive_data but allows one to set additional flags + in USBBuffer */ +void +usb_msc_receive_data_buf_flags(uint8_t *data, unsigned int len, + unsigned int flags, uint16_t buf_flags); +#define USB_MSC_RECEIVE_ABORT() \ + usb_msc_receive_data_buf_flags(NULL, 0, USB_MSC_DATA_LAST, 0) + +#define USB_MSC_DONE() \ + usb_msc_send_data_buf_flags(NULL, 0, USB_MSC_DATA_LAST, 0) + + + +#endif /* __USB_MSC_BULK_H__SHSP6ONHDJ__ */