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));
169 USB_EP_MODE_TYPE_BULK,
191 chBSemSignalI(&msdp->
bsem);
209 if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) &&
210 ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) {
218 switch (usbp->setup[1]) {
221 if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_HOST2DEV) ||
244 chBSemResetI(&UMSD.
bsem,
false);
253 chSysUnlockFromISR();
257 usbSetupTransfer(usbp, 0, 0, NULL);
263 if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_DEV2HOST) ||
269 static uint8_t len_buf[1] = {0};
271 usbSetupTransfer(usbp, len_buf, 1, NULL);
289 chBSemWaitS(&msdp->
bsem);
305 chSysUnlockFromISR();
341 msdp->
sense.byte[2] = key;
342 msdp->
sense.byte[12] = acode;
343 msdp->
sense.byte[13] = aqual;
354 msd_cbw_t *cbw = &(msdp->
cbw);
357 if (cbw->scsi_cmd_data[1] & 0x01) {
360 switch (cbw->scsi_cmd_data[2]) {
410 static msd_scsi_read_capacity_10_response_t response;
427 msd_cbw_t *cbw = &(msdp->
cbw);
429 if (!(cbw->scsi_cmd_data[1] & (1 << 2))) {
452 msd_cbw_t *cbw = &(msdp->
cbw);
491 for (i = 0; i < total; i++) {
493 if (i < (total - 1)) {
500 if (blkWrite(msdp->
config->
bbdp, rw_block_address++, rw_buf[i % 2], 1) == HAL_FAILED) {
512 if (i < (total - 1)) {
523 if (blkRead(msdp->
config->
bbdp, rw_block_address++, rw_buf[i % 2], 1) == HAL_FAILED) {
536 for (i = 0; i < total; i++) {
540 if (i < (total - 1)) {
543 if (blkRead(msdp->
config->
bbdp, rw_block_address++, rw_buf[(i + 1) % 2], 1) == HAL_FAILED) {
573 if ((msdp->
cbw.scsi_cmd_data[4] & 0x03) == 0x02) {
612 msd_scsi_read_format_capacities_response_t response;
613 response.capacity_list_length = 1;
672 msd_cbw_t *cbw = &(msdp->
cbw);
681 ((cbw->data_len > 0) && (cbw->flags & 0x1F)) ||
682 (cbw->scsi_cmd_len == 0) ||
683 (cbw->scsi_cmd_len > 16)) {
710 switch (cbw->scsi_cmd_data[0]) {
787 msd_csw_t *csw = &(msdp->
csw);
789 if (!msdp->
result && cbw->data_len) {
802 csw->data_residue = cbw->data_len;
818 chDbgCheck(msdp != NULL);
830 chBSemObjectInit(&msdp->
bsem,
true);
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;
845 msdp->
inquiry.response_data_format = 0x02;
846 msdp->
inquiry.additional_length = 0x20;
858 chDbgCheck(msdp != NULL);
859 chDbgCheck(config != NULL);
860 chDbgCheck(msdp->
thread == NULL);
881 while (blkGetDriverState(config->
bbdp) != BLK_READY) {
882 chThdSleepMilliseconds(50);
890 config->
usbp->in_params[config->
bulk_ep] = (
void *)msdp;
891 config->
usbp->out_params[config->
bulk_ep] = (
void *)msdp;
894 msdp->
thread = chThdCreateStatic(mass_storage_thread_wa,
sizeof(mass_storage_thread_wa), NORMALPRIO,
mass_storage_thread, msdp);
903 chDbgCheck(msdp->
thread != NULL);
906 chThdTerminate(msdp->
thread);
909 chBSemSignal(&msdp->
bsem);
926 chSysUnlockFromISR();
945 static void usbEvent(USBDriver *usbp, usbevent_t event)
949 case USB_EVENT_CONFIGURED:
953 chSysUnlockFromISR();
956 case USB_EVENT_RESET:
960 case USB_EVENT_ADDRESS:
961 case USB_EVENT_SUSPEND:
962 case USB_EVENT_WAKEUP:
963 case USB_EVENT_STALLED:
996 USB_DESC_CONFIGURATION
1022 USB_EP_MODE_TYPE_BULK,
1031 USB_EP_MODE_TYPE_BULK,
1038 configurationDescriptorData
1044 USB_DESC_BYTE(USB_DESCRIPTOR_STRING),
1045 USB_DESC_WORD(0x0409)
1049 languageDescriptorData
1055 USB_DESC_BYTE(USB_DESCRIPTOR_STRING),
1056 'S', 0,
'T', 0,
'M', 0,
'i', 0,
'c', 0,
'r', 0,
'o', 0,
'M', 0,
'S', 0,
'D', 0
1060 vendorDescriptorData
1066 USB_DESC_BYTE(USB_DESCRIPTOR_STRING),
1067 'M', 0,
'S', 0,
'D', 0,
' ', 0,
'E', 0,
'x', 0,
'a', 0,
'm', 0,
'p', 0,
'l', 0,
'e', 0
1071 productDescriptorData
1077 USB_DESC_BYTE(USB_DESCRIPTOR_STRING),
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
1082 serialNumberDescriptorData
1093 case USB_DESCRIPTOR_DEVICE:
1096 case USB_DESCRIPTOR_CONFIGURATION:
1099 case USB_DESCRIPTOR_STRING:
1135 usbDisconnectBus(&
USBD);
1136 chThdSleepMilliseconds(1000);
1138 usbStart(&
USBD, &usbConfig);
1139 usbConnectBus(&
USBD);
1161 chRegSetThreadName(
"USB-MSD");
1163 bool wait_for_isr =
false;
1168 while (!chThdShouldTerminateX()) {
1183 wait_for_isr =
false;
1186 switch (msdp->
state) {
1200 chThdSleepMilliseconds(100);
1202 usb_lld_disable_endpoints(msdp->
config->
usbp);
1204 chThdSleepMilliseconds(100);
1208 chBSemReset(&msdp->
bsem,
false);
1212 wait_for_isr =
true;
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
Specific RAM section for DMA usage on F7.
#define SCSI_CMD_REQUEST_SENSE
bool msd_scsi_process_read_capacity_10(USBMassStorageDriver *msdp)
Processes a READ_CAPACITY_10 SCSI command.
static const USBEndpointConfig ep_data_config
End-point 1 initialization structure.
void msdStop(USBMassStorageDriver *msdp)
Stops a USB mass storage driver.
static const uint8_t productDescriptorData[]
static const uint8_t serialNumberDescriptorData[]
void debug_snd_evt_nl(eventmask_t evt)
#define SCSI_SENSE_KEY_DATA_PROTECT
static const uint8_t vendorDescriptorData[]
void msdConfigureHookI(USBMassStorageDriver *msdp)
USB device configured handler.
BlockDeviceInfo block_dev_info
static THD_WORKING_AREA(mass_storage_thread_wa, 1024)
static USBOutEndpointState ep1_out_state
OUT end-point 1 state.
#define SCSI_SENSE_KEY_ILLEGAL_REQUEST
bool msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp)
Processes a READ_WRITE_10 SCSI command.
static const USBDescriptor serialNumberDescriptor
static void mass_storage_thread(void *arg)
Mass storage thread that processes commands.
#define SCSI_CMD_READ_CAPACITY_10
#define SCSI_ASENSE_WRITE_FAULT
uint8_t capacity_list_length
void msdInit(USBMassStorageDriver *msdp)
Initializse a USB mass storage driver.
#define MSD_SETUP_INDEX(setup)
usbep_t bulk_ep
Index of the USB endpoint to use for transfers.
static USBInEndpointState ep1_in_state
IN end-point 1 state.
#define SCSI_SENSE_KEY_MEDIUM_ERROR
#define MSD_COMMAND_FAILED
static const USBConfig usbConfig
static uint8_t IN_DMA_SECTION_CLEAR(rw_buf[2][512])
Read-write buffers (TODO: need a way of specifying the size of this)
#define EVT_SCSI_PROC_INQ
bool msd_scsi_process_request_sense(USBMassStorageDriver *msdp)
Processes a REQUEST_SENSE SCSI command.
#define EVT_WAIT_FOR_COMMAND_BLOCK
#define SCSI_ASENSE_INVALID_FIELD_IN_CDB
bool msd_scsi_process_send_diagnostic(USBMassStorageDriver *msdp)
Processes a SEND_DIAGNOSTIC SCSI command.
Response to a READ_CAPACITY_10 SCSI command.
event_source_t evt_connected
const USBMassStorageConfig * config
bool msd_scsi_process_mode_sense_6(USBMassStorageDriver *msdp)
Processes a MODE_SENSE_6 SCSI command.
#define SCSI_SENSE_KEY_GOOD
event_source_t evt_ejected
#define SCSI_CMD_FORMAT_UNIT
uint8_t short_product_version[4]
Short product revision.
#define MSD_CSW_SIGNATURE
void debug_snd_evt_i(eventmask_t evt)
uint32_t desc_and_block_length
#define SCSI_CMD_MODE_SENSE_6
#define SCSI_CMD_TEST_UNIT_READY
#define MSD_COMMAND_PASSED
#define MSD_SETUP_LENGTH(setup)
void msd_register_evt_ejected(event_listener_t *elp, eventmask_t mask)
register ejected event source in local event mask
#define EVT_SCSI_REQ_READ_CAP10
void deinit_msd_driver(void)
#define SCSI_CMD_VERIFY_10
static void msd_start_receive(USBMassStorageDriver *msdp, uint8_t *buffer, size_t size)
Starts receiving data.
#define SCSI_ASENSE_INVALID_COMMAND
#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION
#define EVT_SCSI_REQ_TEST_UNIT_READY
USB mass storage driver structure.
Driver configuration structure.
#define SCSI_SENSE_KEY_NOT_READY
#define SCSI_ASENSE_READ_ERROR
bool reconfigured_or_reset_event
static void msd_scsi_set_sense(USBMassStorageDriver *msdp, uint8_t key, uint8_t acode, uint8_t aqual)
Changes the SCSI sense information.
static const USBDescriptor deviceDescriptor
#define SCSI_CMD_WRITE_10
void init_msd_driver(void *dbgThreadPtr, USBMassStorageConfig *msdConfig)
#define SCSI_ASENSE_MEDIUM_NOT_PRESENT
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
void debug_snd_evt_inl(eventmask_t evt)
static const uint8_t configurationDescriptorData[]
bool msd_read_command_block(USBMassStorageDriver *msdp)
Reads a newly received command block.
static WORD swap_uint16(const WORD val)
Byte-swap a 16 bits unsigned integer.
#define SCSI_CMD_SEND_DIAGNOSTIC
#define PACK_STRUCT_BEGIN
#define EVT_SCSI_REQ_READ_FMT_CAP
#define MSD_SETUP_VALUE(setup)
#define SCSI_ASENSEQ_NO_QUALIFIER
#define EVT_SCSI_REQ_SENSE6
bool msd_wait_for_command_block(USBMassStorageDriver *msdp)
Waits for a new command block.
static const struct usb_config_descriptor config
#define EVT_SCSI_REQ_SENSE10
static const uint8_t languageDescriptorData[]
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
void msd_register_evt_connected(event_listener_t *elp, eventmask_t mask)
register connected event source in local event mask
bool msd_scsi_process_read_format_capacities(USBMassStorageDriver *msdp)
Processes a READ_FORMAT_CAPACITIES SCSI command.
uint8_t short_vendor_id[8]
Short vendor identification.
#define SCSI_ASENSE_WRITE_PROTECTED
static const USBDescriptor configurationDescriptor
bool msd_scsi_process_start_stop_unit(USBMassStorageDriver *msdp)
Processes a START_STOP_UNIT SCSI command.
#define SCSI_SENSE_KEY_RECOVERED_ERROR
static const uint8_t deviceDescriptorData[]
#define SCSI_CMD_START_STOP_UNIT
bool msd_scsi_process_test_unit_ready(USBMassStorageDriver *msdp)
Processes a TEST_UNIT_READY SCSI command.
static void usbEvent(USBDriver *usbp, usbevent_t event)
void(* rw_activity_callback)(bool)
Optional callback that will be called whenever there is read/write activity.
static void msd_wait_for_isr(USBMassStorageDriver *msdp)
Wait until the end-point interrupt handler has been called.
static const USBDescriptor * getDescriptor(USBDriver *usbp, uint8_t type, uint8_t index, uint16_t lang)
void msdStart(USBMassStorageDriver *msdp, const USBMassStorageConfig *config)
Starts a USB mass storage driver.
msd_scsi_inquiry_response_t inquiry
BaseBlockDevice * bbdp
Block device to use for storage.
#define MSD_CBW_SIGNATURE
#define SCSI_CMD_READ_FORMAT_CAPACITIES
bool msd_scsi_process_inquiry(USBMassStorageDriver *msdp)
Processes an INQUIRY SCSI command.
bool msdRequestsHook(USBDriver *usbp)
Default requests hook.
static const USBDescriptor languageDescriptor
#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE
uint8_t short_product_id[16]
Short product identification.
static DWORD swap_uint32(const DWORD val)
Byte-swap a 32 bits unsigned integer.
msd_scsi_sense_response_t sense
static USBMassStorageDriver UMSD