mirror of
https://github.com/oliverschmidt/contiki.git
synced 2024-12-23 01:29:33 +00:00
USB mass storage class
This commit is contained in:
parent
c5e62b7205
commit
44a83a12cd
70
cpu/arm/common/usb/msc/scsi_command.h
Normal file
70
cpu/arm/common/usb/msc/scsi_command.h
Normal file
@ -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__ */
|
116
cpu/arm/common/usb/msc/scsi_sense.h
Normal file
116
cpu/arm/common/usb/msc/scsi_sense.h
Normal file
@ -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
|
||||
*/
|
||||
|
||||
|
424
cpu/arm/common/usb/msc/scsi_struct.h
Normal file
424
cpu/arm/common/usb/msc/scsi_struct.h
Normal file
@ -0,0 +1,424 @@
|
||||
#include <stdint.h>
|
||||
#include <scsi_sense.h>
|
||||
#include <scsi_command.h>
|
||||
|
||||
#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;
|
509
cpu/arm/common/usb/msc/usb-msc-bulk.c
Normal file
509
cpu/arm/common/usb/msc/usb-msc-bulk.c
Normal file
@ -0,0 +1,509 @@
|
||||
#include "usb-msc-bulk.h"
|
||||
#include <usb-api.h>
|
||||
#include <usb-core.h>
|
||||
#include <sys/process.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
132
cpu/arm/common/usb/msc/usb-msc-bulk.h
Normal file
132
cpu/arm/common/usb/msc/usb-msc-bulk.h
Normal file
@ -0,0 +1,132 @@
|
||||
#ifndef __USB_MSC_BULK_H__SHSP6ONHDJ__
|
||||
#define __USB_MSC_BULK_H__SHSP6ONHDJ__
|
||||
|
||||
#include <usb.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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__ */
|
Loading…
Reference in New Issue
Block a user