30 #define MSD_REQ_RESET 0xFF
31 #define MSD_GET_MAX_LUN 0xFE
34 #define MSD_CBW_SIGNATURE 0x43425355
35 #define MSD_CSW_SIGNATURE 0x53425355
38 #define MSD_SETUP_WORD(setup, index) (uint16_t)(((uint16_t)setup[index + 1] << 8) | (setup[index] & 0x00FF))
39 #define MSD_SETUP_VALUE(setup) MSD_SETUP_WORD(setup, 2)
40 #define MSD_SETUP_INDEX(setup) MSD_SETUP_WORD(setup, 4)
41 #define MSD_SETUP_LENGTH(setup) MSD_SETUP_WORD(setup, 6)
44 #define MSD_COMMAND_PASSED 0x00
45 #define MSD_COMMAND_FAILED 0x01
46 #define MSD_COMMAND_PHASE_ERROR 0x02
49 #define SCSI_CMD_TEST_UNIT_READY 0x00
50 #define SCSI_CMD_REQUEST_SENSE 0x03
51 #define SCSI_CMD_FORMAT_UNIT 0x04
52 #define SCSI_CMD_INQUIRY 0x12
53 #define SCSI_CMD_MODE_SENSE_6 0x1A
54 #define SCSI_CMD_START_STOP_UNIT 0x1B
55 #define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
56 #define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
57 #define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
58 #define SCSI_CMD_READ_CAPACITY_10 0x25
59 #define SCSI_CMD_READ_10 0x28
60 #define SCSI_CMD_WRITE_10 0x2A
61 #define SCSI_CMD_VERIFY_10 0x2F
64 #define SCSI_SENSE_KEY_GOOD 0x00
65 #define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
66 #define SCSI_SENSE_KEY_NOT_READY 0x02
67 #define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
68 #define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
69 #define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
70 #define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
71 #define SCSI_SENSE_KEY_DATA_PROTECT 0x07
72 #define SCSI_SENSE_KEY_BLANK_CHECK 0x08
73 #define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
74 #define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
75 #define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
76 #define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
77 #define SCSI_SENSE_KEY_MISCOMPARE 0x0E
79 #define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00
80 #define SCSI_ASENSE_WRITE_FAULT 0x03
81 #define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04
82 #define SCSI_ASENSE_READ_ERROR 0x11
83 #define SCSI_ASENSE_INVALID_COMMAND 0x20
84 #define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21
85 #define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24
86 #define SCSI_ASENSE_WRITE_PROTECTED 0x27
87 #define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28
88 #define SCSI_ASENSE_FORMAT_ERROR 0x31
89 #define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A
91 #define SCSI_ASENSEQ_NO_QUALIFIER 0x00
92 #define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01
93 #define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02
94 #define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07
130 val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
131 return ((val << 16) & 0xFFFF0000) | ((val >> 16) & 0x0000FFFF);
136 #define swap_uint16(x) (((((WORD)(x)) >> 8) & 0xff) | ((((WORD)(x)) & 0xff) << 8))
154 USB_EP_MODE_TYPE_BULK,
176 chBSemSignalI(&msdp->
bsem);
192 if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) &&
193 ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) {
201 switch (usbp->setup[1]) {
204 if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_HOST2DEV) ||
218 if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_DEV2HOST) ||
224 static uint8_t len_buf[1] = {0};
226 usbSetupTransfer(usbp, len_buf, 1, NULL);
245 chBSemWaitS(&msdp->
bsem);
260 chSysUnlockFromISR();
288 msdp->
sense.byte[2] = key;
289 msdp->
sense.byte[12] = acode;
290 msdp->
sense.byte[13] = aqual;
299 msd_cbw_t *cbw = &(msdp->
cbw);
302 if (cbw->scsi_cmd_data[1] & 0x01) {
305 switch (cbw->scsi_cmd_data[2]) {
356 static msd_scsi_read_capacity_10_response_t response;
374 msd_cbw_t *cbw = &(msdp->
cbw);
376 if (!(cbw->scsi_cmd_data[1] & (1 << 2))) {
399 msd_cbw_t *cbw = &(msdp->
cbw);
438 for (i = 0; i < total; i++) {
440 if (i < (total - 1)) {
447 if (blkWrite(msdp->
config->
bbdp, rw_block_address++,
rw_buf[i % 2], 1) == HAL_FAILED) {
459 if (i < (total - 1)) {
470 if (blkRead(msdp->
config->
bbdp, rw_block_address++,
rw_buf[i % 2], 1) == HAL_FAILED) {
483 for (i = 0; i < total; i++) {
487 if (i < (total - 1)) {
490 if (blkRead(msdp->
config->
bbdp, rw_block_address++,
rw_buf[(i + 1) % 2], 1) == HAL_FAILED) {
520 if ((msdp->
cbw.scsi_cmd_data[4] & 0x03) == 0x02) {
558 msd_scsi_read_format_capacities_response_t response;
559 response.capacity_list_length = 1;
611 msd_cbw_t *cbw = &(msdp->
cbw);
619 ((cbw->data_len > 0) && (cbw->flags & 0x1F)) ||
620 (cbw->scsi_cmd_len == 0) ||
621 (cbw->scsi_cmd_len > 16)) {
636 switch (cbw->scsi_cmd_data[0]) {
713 msd_csw_t *csw = &(msdp->
csw);
715 if (!msdp->
result && cbw->data_len) {
728 csw->data_residue = cbw->data_len;
746 chRegSetThreadName(
"USB-MSD");
748 bool wait_for_isr =
false;
753 while (!chThdShouldTerminateX()) {
754 wait_for_isr =
false;
757 switch (msdp->
state) {
785 chDbgAssert(msdp != NULL,
"msdInit");
796 chBSemObjectInit(&msdp->
bsem,
true);
800 for (i = 0; i <
sizeof(msdp->
sense.byte); i++) {
801 msdp->
sense.byte[i] = 0x00;
803 msdp->
sense.byte[0] = 0x70;
804 msdp->
sense.byte[7] = 0x0A;
807 msdp->
inquiry.peripheral = 0x00;
808 msdp->
inquiry.removable = 0x80;
810 msdp->
inquiry.response_data_format = 0x02;
811 msdp->
inquiry.additional_length = 0x20;
823 chDbgAssert(msdp != NULL,
"msdStart");
824 chDbgAssert(config != NULL,
"msdStart");
825 chDbgAssert(msdp->
thread == NULL,
"msdStart");
846 while (blkGetDriverState(config->
bbdp) != BLK_READY) {
847 chThdSleepMilliseconds(50);
855 config->
usbp->in_params[config->
bulk_ep] = (
void *)msdp;
856 config->
usbp->out_params[config->
bulk_ep] = (
void *)msdp;
859 msdp->
thread = chThdCreateStatic(mass_storage_thread_wa,
sizeof(mass_storage_thread_wa), NORMALPRIO + 1,
869 chDbgAssert(msdp->
thread != NULL,
"msdStop");
872 chThdTerminate(msdp->
thread);
875 chBSemSignal(&msdp->
bsem);
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.
#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 uint8_t rw_buf[2][512]
Read-write buffers (TODO: need a way of specifying the size of this)
#define SCSI_SENSE_KEY_DATA_PROTECT
void msdConfigureHookI(USBMassStorageDriver *msdp)
USB device configured handler.
BlockDeviceInfo block_dev_info
static THD_WORKING_AREA(mass_storage_thread_wa, 1024)
Mass storage thread that processes commands.
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 DWORD swap_uint32(DWORD val)
Byte-swap a 32 bits unsigned integer.
static void mass_storage_thread(void *arg)
#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
bool msd_scsi_process_request_sense(USBMassStorageDriver *msdp)
Processes a REQUEST_SENSE SCSI command.
#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
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)
#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
USB mass storage driver structure.
Driver configuration structure.
#define SCSI_SENSE_KEY_NOT_READY
#define SCSI_ASENSE_READ_ERROR
static void msd_scsi_set_sense(USBMassStorageDriver *msdp, uint8_t key, uint8_t acode, uint8_t aqual)
Changes the SCSI sense information.
#define SCSI_CMD_WRITE_10
#define SCSI_ASENSE_MEDIUM_NOT_PRESENT
USBDriver * usbp
USB driver to use for communication.
static void msd_start_transmit(USBMassStorageDriver *msdp, const uint8_t *buffer, size_t size)
Starts sending data.
bool msd_read_command_block(USBMassStorageDriver *msdp)
Reads a newly received command block.
#define SCSI_CMD_SEND_DIAGNOSTIC
#define PACK_STRUCT_BEGIN
#define MSD_SETUP_VALUE(setup)
#define SCSI_ASENSEQ_NO_QUALIFIER
bool msd_wait_for_command_block(USBMassStorageDriver *msdp)
Waits for a new command block.
static const struct usb_config_descriptor config
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
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
bool msd_scsi_process_start_stop_unit(USBMassStorageDriver *msdp)
Processes a START_STOP_UNIT SCSI command.
#define SCSI_CMD_START_STOP_UNIT
bool msd_scsi_process_test_unit_ready(USBMassStorageDriver *msdp)
Processes a TEST_UNIT_READY SCSI command.
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.
#define swap_uint16(x)
Byte-swap a 16 bits unsigned integer.
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.
#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE
uint8_t short_product_id[16]
Short product identification.
msd_scsi_sense_response_t sense