35#define MSD_REQ_RESET 0xFF
36#define MSD_GET_MAX_LUN 0xFE
39#define MSD_CBW_SIGNATURE 0x43425355
40#define MSD_CSW_SIGNATURE 0x53425355
43#define MSD_SETUP_WORD(setup, index) (uint16_t)(((uint16_t)setup[index + 1] << 8) | (setup[index] & 0x00FF))
44#define MSD_SETUP_VALUE(setup) MSD_SETUP_WORD(setup, 2)
45#define MSD_SETUP_INDEX(setup) MSD_SETUP_WORD(setup, 4)
46#define MSD_SETUP_LENGTH(setup) MSD_SETUP_WORD(setup, 6)
49#define MSD_COMMAND_PASSED 0x00
50#define MSD_COMMAND_FAILED 0x01
51#define MSD_COMMAND_PHASE_ERROR 0x02
54#define SCSI_CMD_TEST_UNIT_READY 0x00
55#define SCSI_CMD_REQUEST_SENSE 0x03
56#define SCSI_CMD_FORMAT_UNIT 0x04
57#define SCSI_CMD_INQUIRY 0x12
58#define SCSI_CMD_MODE_SENSE_6 0x1A
59#define SCSI_CMD_START_STOP_UNIT 0x1B
60#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
61#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
62#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
63#define SCSI_CMD_READ_CAPACITY_10 0x25
64#define SCSI_CMD_READ_10 0x28
65#define SCSI_CMD_WRITE_10 0x2A
66#define SCSI_CMD_VERIFY_10 0x2F
69#define SCSI_SENSE_KEY_GOOD 0x00
70#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
71#define SCSI_SENSE_KEY_NOT_READY 0x02
72#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
73#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
74#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
75#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
76#define SCSI_SENSE_KEY_DATA_PROTECT 0x07
77#define SCSI_SENSE_KEY_BLANK_CHECK 0x08
78#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
79#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
80#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
81#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
82#define SCSI_SENSE_KEY_MISCOMPARE 0x0E
84#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00
85#define SCSI_ASENSE_WRITE_FAULT 0x03
86#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04
87#define SCSI_ASENSE_READ_ERROR 0x11
88#define SCSI_ASENSE_INVALID_COMMAND 0x20
89#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21
90#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24
91#define SCSI_ASENSE_WRITE_PROTECTED 0x27
92#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28
93#define SCSI_ASENSE_FORMAT_ERROR 0x31
94#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A
96#define SCSI_ASENSEQ_NO_QUALIFIER 0x00
97#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01
98#define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02
99#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07
142 DWORD v = ((
val << 8) & 0xFF00FF00) | ((
val >> 8) & 0xFF00FF);
143 return ((v << 16) & 0xFFFF0000) | ((v >> 16) & 0x0000FFFF);
151 return (((
val >> 8) & 0xff) | ((
val & 0xff) << 8));
218 switch (usbp->setup[1]) {
315 if (
msdp->bot_reset) {
316 msdp->config->usbp->transmitting = 0;
329 if (
msdp->bot_reset) {
330 msdp->config->usbp->receiving = 0;
341 msdp->sense.byte[2] = key;
357 if (cbw->scsi_cmd_data[1] & 0x01) {
360 switch (cbw->scsi_cmd_data[2]) {
429 if (!(cbw->scsi_cmd_data[1] & (1 << 2))) {
435 msdp->result =
false;
461 msdp->result =
false;
477 msdp->result =
false;
491 for (i = 0; i <
total; i++) {
493 if (i < (
total - 1)) {
506 msdp->result =
false;
512 if (i < (
total - 1)) {
529 msdp->result =
false;
536 for (i = 0; i <
total; i++) {
540 if (i < (
total - 1)) {
549 msdp->result =
false;
573 if ((
msdp->cbw.scsi_cmd_data[4] & 0x03) == 0x02) {
644 msdp->result =
false;
681 ((cbw->data_len > 0) && (cbw->flags & 0x1F)) ||
682 (cbw->scsi_cmd_len == 0) ||
683 (cbw->scsi_cmd_len > 16)) {
697 msdp->result =
false;
710 switch (cbw->scsi_cmd_data[0]) {
722 if (
msdp->config->rw_activity_callback) {
723 msdp->config->rw_activity_callback(
true);
726 if (
msdp->config->rw_activity_callback) {
727 msdp->config->rw_activity_callback(
false);
783 if (sleep & !
msdp->bot_reset) {
789 if (!
msdp->result && cbw->data_len) {
802 csw->data_residue = cbw->data_len;
819 msdp->bot_reset =
false;
820 msdp->reconfigured_or_reset_event =
false;
835 for (i = 0; i <
sizeof(
msdp->sense.byte); i++) {
836 msdp->sense.byte[i] = 0x00;
838 msdp->sense.byte[0] = 0x70;
839 msdp->sense.byte[7] = 0x0A;
842 msdp->inquiry.peripheral = 0x00;
843 msdp->inquiry.removable = 0x80;
844 msdp->inquiry.version = 0x04;
845 msdp->inquiry.response_data_format = 0x02;
846 msdp->inquiry.additional_length = 0x20;
847 msdp->inquiry.sccstp = 0x00;
848 msdp->inquiry.bqueetc = 0x00;
849 msdp->inquiry.cmdque = 0x00;
867 for (i = 0; i <
sizeof(
msdp->config->short_vendor_id); ++i) {
868 msdp->inquiry.vendor_id[i] =
config->short_vendor_id[i];
870 for (i = 0; i <
sizeof(
msdp->config->short_product_id); ++i) {
871 msdp->inquiry.product_id[i] =
config->short_product_id[i];
873 for (i = 0; i <
sizeof(
msdp->config->short_product_version); ++i) {
874 msdp->inquiry.product_rev[i] =
config->short_product_version[i];
914 msdp->config->usbp->in_params[
msdp->config->bulk_ep] =
NULL;
915 msdp->config->usbp->out_params[
msdp->config->bulk_ep] =
NULL;
1056 'S', 0,
'T', 0,
'M', 0,
'i', 0,
'c', 0,
'r', 0,
'o', 0,
'M', 0,
'S', 0,
'D', 0
1067 'M', 0,
'S', 0,
'D', 0,
' ', 0,
'E', 0,
'x', 0,
'a', 0,
'm', 0,
'p', 0,
'l', 0,
'e', 0
1078 '0', 0,
'1', 0,
'4', 0,
'2', 0,
'3', 0,
'0', 0,
'F', 0,
'K', 0,
'0', 0,
'0', 0,
'0', 0,
'1', 0
1172 if (
msdp->reconfigured_or_reset_event) {
1175 msdp->reconfigured_or_reset_event =
false;
1188 switch (
msdp->state) {
Specific RAM section for DMA usage on F7.
#define IN_DMA_SECTION_CLEAR(var)
static const struct usb_config_descriptor config
Driver configuration structure.
usbep_t bulk_ep
Index of the USB endpoint to use for transfers.
USBDriver * usbp
USB driver to use for communication.
static USBMassStorageConfig msdConfig
static void msd_start_transmit(USBMassStorageDriver *msdp, const uint8_t *buffer, size_t size)
Starts sending data.
static const USBDescriptor productDescriptor
static const uint8_t vendorDescriptorData[]
#define SCSI_SENSE_KEY_GOOD
#define SCSI_CMD_READ_FORMAT_CAPACITIES
static THD_WORKING_AREA(mass_storage_thread_wa, 1024)
#define SCSI_CMD_START_STOP_UNIT
#define SCSI_CMD_SEND_DIAGNOSTIC
#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION
#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE
#define SCSI_CMD_READ_CAPACITY_10
bool msdRequestsHook(USBDriver *usbp)
Default requests hook.
static void usbEvent(USBDriver *usbp, usbevent_t event)
void debug_snd_evt_i(eventmask_t evt)
void debug_snd_evt_inl(eventmask_t evt)
#define MSD_COMMAND_PASSED
static const USBDescriptor languageDescriptor
void init_msd_driver(void *dbgThreadPtr, USBMassStorageConfig *msdConfig)
static DWORD swap_uint32(const DWORD val)
Byte-swap a 32 bits unsigned integer.
#define SCSI_ASENSE_INVALID_FIELD_IN_CDB
#define SCSI_SENSE_KEY_RECOVERED_ERROR
static void msd_wait_for_isr(USBMassStorageDriver *msdp)
Wait until the end-point interrupt handler has been called.
#define SCSI_ASENSE_MEDIUM_NOT_PRESENT
static void msd_handle_end_point_notification(USBDriver *usbp, usbep_t ep)
Called when data can be read or written on the endpoint – wakes the thread up.
static const USBDescriptor vendorDescriptor
static WORD swap_uint16(const WORD val)
Byte-swap a 16 bits unsigned integer.
bool msd_scsi_process_inquiry(USBMassStorageDriver *msdp)
Processes an INQUIRY SCSI command.
#define MSD_COMMAND_FAILED
static const USBDescriptor * getDescriptor(USBDriver *usbp, uint8_t type, uint8_t index, uint16_t lang)
#define SCSI_ASENSE_WRITE_PROTECTED
#define SCSI_SENSE_KEY_DATA_PROTECT
static const USBDescriptor serialNumberDescriptor
#define MSD_SETUP_INDEX(setup)
#define MSD_SETUP_LENGTH(setup)
#define SCSI_ASENSEQ_NO_QUALIFIER
#define MSD_CBW_SIGNATURE
static const USBDescriptor deviceDescriptor
#define MSD_CSW_SIGNATURE
bool msd_scsi_process_mode_sense_6(USBMassStorageDriver *msdp)
Processes a MODE_SENSE_6 SCSI command.
static USBMassStorageDriver UMSD
#define SCSI_SENSE_KEY_NOT_READY
void msdStart(USBMassStorageDriver *msdp, const USBMassStorageConfig *config)
Starts a USB mass storage driver.
bool msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp)
Processes a READ_WRITE_10 SCSI command.
#define SCSI_CMD_VERIFY_10
bool msd_scsi_process_read_capacity_10(USBMassStorageDriver *msdp)
Processes a READ_CAPACITY_10 SCSI command.
void msdInit(USBMassStorageDriver *msdp)
Initializse a USB mass storage driver.
void msdConfigureHookI(USBMassStorageDriver *msdp)
USB device configured handler.
#define SCSI_ASENSE_INVALID_COMMAND
void msd_register_evt_connected(event_listener_t *elp, eventmask_t mask)
register connected event source in local event mask
bool msd_scsi_process_start_stop_unit(USBMassStorageDriver *msdp)
Processes a START_STOP_UNIT SCSI command.
#define SCSI_SENSE_KEY_ILLEGAL_REQUEST
void msd_register_evt_ejected(event_listener_t *elp, eventmask_t mask)
register ejected event source in local event mask
static void msd_scsi_set_sense(USBMassStorageDriver *msdp, uint8_t key, uint8_t acode, uint8_t aqual)
Changes the SCSI sense information.
static void msd_start_receive(USBMassStorageDriver *msdp, uint8_t *buffer, size_t size)
Starts receiving data.
static USBOutEndpointState ep1_out_state
OUT end-point 1 state.
bool msd_wait_for_command_block(USBMassStorageDriver *msdp)
Waits for a new command block.
static const USBDescriptor configurationDescriptor
#define MSD_SETUP_VALUE(setup)
static const uint8_t deviceDescriptorData[]
#define SCSI_CMD_TEST_UNIT_READY
static USBInEndpointState ep1_in_state
IN end-point 1 state.
void msdStop(USBMassStorageDriver *msdp)
Stops a USB mass storage driver.
static const uint8_t serialNumberDescriptorData[]
bool msd_read_command_block(USBMassStorageDriver *msdp)
Reads a newly received command block.
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
#define SCSI_CMD_MODE_SENSE_6
#define SCSI_ASENSE_WRITE_FAULT
#define SCSI_CMD_FORMAT_UNIT
static const uint8_t languageDescriptorData[]
bool msd_scsi_process_read_format_capacities(USBMassStorageDriver *msdp)
Processes a READ_FORMAT_CAPACITIES SCSI command.
void debug_snd_evt_nl(eventmask_t evt)
#define SCSI_CMD_REQUEST_SENSE
#define SCSI_CMD_WRITE_10
#define SCSI_ASENSE_READ_ERROR
bool msd_scsi_process_test_unit_ready(USBMassStorageDriver *msdp)
Processes a TEST_UNIT_READY SCSI command.
static const USBEndpointConfig ep_data_config
End-point 1 initialization structure.
bool msd_scsi_process_request_sense(USBMassStorageDriver *msdp)
Processes a REQUEST_SENSE SCSI command.
bool msd_scsi_process_send_diagnostic(USBMassStorageDriver *msdp)
Processes a SEND_DIAGNOSTIC SCSI command.
static const uint8_t productDescriptorData[]
static const uint8_t configurationDescriptorData[]
#define SCSI_SENSE_KEY_MEDIUM_ERROR
void deinit_msd_driver(void)
static void mass_storage_thread(void *arg)
Mass storage thread that processes commands.
static const USBConfig usbConfig
#define EVT_SCSI_PROC_INQ
const USBMassStorageConfig * config
#define EVT_SCSI_REQ_TEST_UNIT_READY
bool reconfigured_or_reset_event
#define EVT_WAIT_FOR_COMMAND_BLOCK
#define EVT_SCSI_REQ_READ_CAP10
event_source_t evt_ejected
uint8_t capacity_list_length
#define PACK_STRUCT_BEGIN
#define EVT_SCSI_REQ_READ_FMT_CAP
#define EVT_SCSI_REQ_SENSE6
event_source_t evt_connected
#define EVT_SCSI_REQ_SENSE10
uint32_t desc_and_block_length
Response to a READ_CAPACITY_10 SCSI command.
USB mass storage driver structure.
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.