From 8af87d3c250ac6a9ed0570ab5b8cf872e53eff24 Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Thu, 18 Apr 2013 15:33:46 +0200 Subject: [PATCH 01/11] Added support for the SCSI_CMD_READ_FORMAT_CAPACITIES command Added support for the VPD variant of the INQUIRY command (only page 0x80 is supported) Fixed missing ending 0 in the serial number descriptor Fixed end point status declarations Fixed incorrect chSysLockFromIsr calls --- mass_storage/usb_msd.c | 177 ++++++++++++++++++++++++++--------------- mass_storage/usb_msd.h | 12 ++- 2 files changed, 121 insertions(+), 68 deletions(-) diff --git a/mass_storage/usb_msd.c b/mass_storage/usb_msd.c index aeeb354..767ee79 100644 --- a/mass_storage/usb_msd.c +++ b/mass_storage/usb_msd.c @@ -82,7 +82,7 @@ static const uint8_t msd_configuration_descriptor_data[] = { USB_DESC_ENDPOINT (USB_MS_DATA_EP, 0x02, /* bmAttributes (Bulk). */ USB_MS_EP_SIZE,/* wMaxPacketSize. */ - 0x05) /* bInterval. 1ms */ + 0x05) /* bInterval. 1ms */ }; /* @@ -122,7 +122,7 @@ static const uint8_t msd_string2[] = { 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, 'R', 0, 'T', 0, ' ', 0, 'M', 0, 'a', 0, 's', 0, 's', 0, ' ', 0, 'S', 0, 't', 0, 'o', 0, 'r', 0, 'a', 0, 'g', 0, 'e', 0, ' ', 0, - 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e' + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0 }; static const uint8_t msd_string3[] = { @@ -215,7 +215,6 @@ bool_t msdRequestsHook(USBDriver *usbp) { } return FALSE; } - static void WaitForISR(USBMassStorageDriver *msdp) { /* sleep until it completes */ chSysLock(); @@ -227,15 +226,20 @@ void msdUsbEvent(USBDriver *usbp, usbep_t ep) { (void)usbp; (void)ep; - chSysLockFromIsr(); + chSysLockFromIsr(); chBSemSignalI(&((USBMassStorageDriver *)usbp->param)->bsem); - chSysUnlockFromIsr(); + chSysUnlockFromIsr(); } /** * @brief IN EP1 state. */ -static USBInEndpointState ep1InState, ep1OutState; +static USBInEndpointState ep1InState; + +/** + * @brief OUT EP1 state. + */ +static USBOutEndpointState ep1OutState; /** * @brief EP1 initialization structure (IN only). @@ -271,7 +275,7 @@ static void usb_event(USBDriver *usbp, usbevent_t event) { /* signal that the device is connected */ chEvtBroadcastI(&msdp->evt_connected); - chSysUnlockFromIsr(); + chSysUnlockFromIsr(); return; case USB_EVENT_SUSPEND: @@ -300,42 +304,62 @@ static inline void SCSISetSense(USBMassStorageDriver *msdp, uint8_t key, uint8_t bool_t SCSICommandInquiry(USBMassStorageDriver *msdp) { msd_cbw_t *cbw = &(msdp->cbw); - static const scsi_inquiry_response_t inquiry = { - 0x00, // direct access block device - 0x80, // removable - 0x04, // SPC-2 - 0x02, // response data format - 0x20, // response has 0x20 + 4 bytes - 0x00, - 0x00, - 0x00, - "Chibios", - "Mass Storage", - {'v',CH_KERNEL_MAJOR+'0','.',CH_KERNEL_MINOR+'0'}, - }; - - if((cbw->scsi_cmd_data[1] & ((1 << 0) | (1 << 1))) || - cbw->scsi_cmd_data[2]) { - /* Optional but unsupported bits set - update the SENSE key and fail the request */ - SCSISetSense( msdp, - SCSI_SENSE_KEY_ILLEGAL_REQUEST, - SCSI_ASENSE_INVALID_FIELD_IN_CDB, - SCSI_ASENSEQ_NO_QUALIFIER); - - return FALSE; - } - - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&inquiry, - sizeof(scsi_inquiry_response_t)); - - chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); - - msdp->result = TRUE; - - /* wait for ISR */ - return TRUE; + /* check the EVPD bit (Vital Product Data) */ + if(cbw->scsi_cmd_data[1] & 0x01) { + + /* check the Page Code byte to know the type of product data to reply */ + switch(cbw->scsi_cmd_data[2]) { + + /* unit serial number */ + case 0x80: { + uint8_t response[] = {'z', 'z', 'z'}; + usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, response, sizeof(response)); + chSysLock(); + usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); + msdp->result = TRUE; + + /* wait for ISR */ + return TRUE; + } + + /* unhandled */ + default: + SCSISetSense( msdp, + SCSI_SENSE_KEY_ILLEGAL_REQUEST, + SCSI_ASENSE_INVALID_FIELD_IN_CDB, + SCSI_ASENSEQ_NO_QUALIFIER); + return FALSE; + } + } + else + { + static const scsi_inquiry_response_t inquiry = { + 0x00, // direct access block device + 0x80, // removable + 0x04, // SPC-2 + 0x02, // response data format + 0x20, // response has 0x20 + 4 bytes + 0x00, + 0x00, + 0x00, + "Chibios", + "Mass Storage", + {'v',CH_KERNEL_MAJOR+'0','.',CH_KERNEL_MINOR+'0'}, + }; + + usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&inquiry, + sizeof(scsi_inquiry_response_t)); + + chSysLock(); + usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); + + msdp->result = TRUE; + + /* wait for ISR */ + return TRUE; + } } bool_t SCSICommandRequestSense(USBMassStorageDriver *msdp) { @@ -374,7 +398,7 @@ bool_t SCSICommandReadCapacity10(USBMassStorageDriver *msdp) { bool_t SCSICommandSendDiagnostic(USBMassStorageDriver *msdp) { msd_cbw_t *cbw = &(msdp->cbw); - if(!cbw->scsi_cmd_data[1] & (1 << 2)) { + if(!(cbw->scsi_cmd_data[1] & (1 << 2))) { /* Only self-test supported - update SENSE key and fail the command */ SCSISetSense( msdp, SCSI_SENSE_KEY_ILLEGAL_REQUEST, @@ -393,7 +417,6 @@ bool_t SCSICommandSendDiagnostic(USBMassStorageDriver *msdp) { bool_t SCSICommandStartReadWrite10(USBMassStorageDriver *msdp) { msd_cbw_t *cbw = &(msdp->cbw); - bool_t data_cached = FALSE; if((cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) && blkIsWriteProtected(msdp->bbdp)) { @@ -423,7 +446,7 @@ bool_t SCSICommandStartReadWrite10(USBMassStorageDriver *msdp) { return FALSE; } - if(cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) { + if(cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) { /* get the first packet */ usbPrepareReceive(msdp->usbp, USB_MS_DATA_EP, rw_buf[i % 2], msdp->block_dev_info.blk_size); @@ -449,8 +472,8 @@ bool_t SCSICommandStartReadWrite10(USBMassStorageDriver *msdp) { /* now write the block to the block device */ if(blkWrite(msdp->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { - /* TODO: handle this */ - chSysHalt(); + /* TODO: handle this */ + chSysHalt(); } if(i < (total -1 )) { @@ -462,8 +485,8 @@ bool_t SCSICommandStartReadWrite10(USBMassStorageDriver *msdp) { i = 0; /* read the first block from block device */ if(blkRead(msdp->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { - /* TODO: handle this */ - chSysHalt(); + /* TODO: handle this */ + chSysHalt(); } /* loop over each block */ @@ -481,14 +504,14 @@ bool_t SCSICommandStartReadWrite10(USBMassStorageDriver *msdp) { /* so read that whilst the USB transfer takes place */ if(blkRead(msdp->bbdp, rw_block_address++, rw_buf[(i+1) % 2], 1) == CH_FAILED) { - /* TODO: handle this */ - chSysHalt(); + /* TODO: handle this */ + chSysHalt(); } } WaitForISR(msdp); } - } + } msdp->result = TRUE; @@ -529,6 +552,25 @@ bool_t SCSICommandModeSense6(USBMassStorageDriver *msdp) { return TRUE; } +bool_t SCSICommandReadFormatCapacities(USBMassStorageDriver *msdp) +{ + SCSIReadFormatCapacitiesResponse_t response; + response.capacity_list_length = 1; + response.block_count = swap_uint32(msdp->block_dev_info.blk_num); + response.desc_and_block_length = swap_uint32((0x02 << 24) | (msdp->block_dev_info.blk_size & 0x00FFFFFF)); + + usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (const uint8_t*)&response, sizeof(response)); + + chSysLock(); + usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); + + msdp->result = TRUE; + + /* wait for ISR */ + return TRUE; +} + bool_t msdWaitForCommandBlock(USBMassStorageDriver *msdp) { usbPrepareReceive(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->cbw, sizeof(msd_cbw_t)); @@ -560,9 +602,9 @@ bool_t msdReadCommandBlock(USBMassStorageDriver *msdp) { (cbw->scsi_cmd_len > 16)) { /* stall both IN and OUT endpoints */ - chSysLockFromIsr(); + chSysLock(); usbStallReceiveI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlockFromIsr(); + chSysUnlock(); /* don't wait for ISR */ return FALSE; @@ -600,16 +642,19 @@ bool_t msdReadCommandBlock(USBMassStorageDriver *msdp) { case SCSI_CMD_START_STOP_UNIT: sleep = SCSICommandStartStopUnit(msdp); break; + case SCSI_CMD_READ_FORMAT_CAPACITIES: + sleep = SCSICommandReadFormatCapacities(msdp); + break; default: - SCSISetSense( msdp, + SCSISetSense( msdp, SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_COMMAND, SCSI_ASENSEQ_NO_QUALIFIER); /* stall IN endpoint */ - chSysLockFromIsr(); + chSysLock(); usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlockFromIsr(); + chSysUnlock(); cbw->data_len = 0; return FALSE; @@ -625,9 +670,9 @@ bool_t msdReadCommandBlock(USBMassStorageDriver *msdp) { SCSI_ASENSEQ_NO_QUALIFIER); } else { /* stall IN endpoint */ - chSysLockFromIsr(); + chSysLock(); usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlockFromIsr(); + chSysUnlock(); cbw->data_len = 0; return FALSE; @@ -641,10 +686,10 @@ bool_t msdReadCommandBlock(USBMassStorageDriver *msdp) { if(!msdp->result && cbw->data_len) { /* still bytes left to send, this is too early to send CSW? */ - chSysLockFromIsr(); + chSysLock(); usbStallReceiveI(msdp->usbp, USB_MS_DATA_EP); usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlockFromIsr(); + chSysUnlock(); return FALSE; } @@ -676,7 +721,7 @@ static msg_t MassStorageThd(void *arg) { WaitForISR(msdp); while (TRUE) { - wait_for_isr = FALSE; + wait_for_isr = FALSE; /* wait on data depending on the current state */ switch(msdp->state) { @@ -733,11 +778,11 @@ void msdInit(USBDriver *usbp, BaseBlockDevice *bbdp, USBMassStorageDriver *msdp) blkGetInfo(bbdp, &msdp->block_dev_info); - usbDisconnectBus(usbp); - chThdSleepMilliseconds(1000); + usbDisconnectBus(usbp); + chThdSleepMilliseconds(1000); usbp->param = (void *)msdp; - usbStart(usbp, &msd_usb_config); + usbStart(usbp, &msd_usb_config); usbConnectBus(usbp); if(msdThd == NULL) { diff --git a/mass_storage/usb_msd.h b/mass_storage/usb_msd.h index b6edf77..732c56d 100644 --- a/mass_storage/usb_msd.h +++ b/mass_storage/usb_msd.h @@ -27,6 +27,7 @@ #define SCSI_CMD_SEND_DIAGNOSTIC 0x1D #define SCSI_CMD_MODE_SENSE_6 0x1A #define SCSI_CMD_START_STOP_UNIT 0x1B +#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 #define MSD_COMMAND_PASSED 0x00 #define MSD_COMMAND_FAILED 0x01 @@ -77,9 +78,9 @@ PACK_STRUCT_BEGIN typedef struct { uint8_t status; } PACK_STRUCT_STRUCT msd_csw_t PACK_STRUCT_END; -typedef struct { +PACK_STRUCT_BEGIN typedef struct { uint8_t byte[18]; -} __attribute__ ((packed)) scsi_sense_response_t; +} PACK_STRUCT_STRUCT scsi_sense_response_t PACK_STRUCT_END; PACK_STRUCT_BEGIN typedef struct { @@ -110,6 +111,13 @@ PACK_STRUCT_BEGIN typedef struct { uint8_t control; } PACK_STRUCT_STRUCT SCSIStartStopUnitRequest_t; +PACK_STRUCT_BEGIN typedef struct { + uint8_t reserved[3]; + uint8_t capacity_list_length; + uint32_t block_count; + uint32_t desc_and_block_length; +} PACK_STRUCT_STRUCT SCSIReadFormatCapacitiesResponse_t PACK_STRUCT_END; + typedef struct USBMassStorageDriver USBMassStorageDriver; typedef enum { idle, read_cmd_block, ejected} msd_state_t; From 269c6434a07b032896f507bb83bad4c7e596f37f Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Fri, 19 Apr 2013 08:47:38 +0200 Subject: [PATCH 02/11] Cleaned, commented, fixed naming convention and white spaces (-> ChibiOS style) --- mass_storage/usb_msd.c | 1391 ++++++++++++++++++++++------------------ mass_storage/usb_msd.h | 154 ++--- 2 files changed, 829 insertions(+), 716 deletions(-) diff --git a/mass_storage/usb_msd.c b/mass_storage/usb_msd.c index 767ee79..5bbc55d 100644 --- a/mass_storage/usb_msd.c +++ b/mass_storage/usb_msd.c @@ -1,170 +1,278 @@ -#include "ch.h" -#include "hal.h" #include "usb_msd.h" -static WORKING_AREA(waMassStorage, 1024); -static msg_t MassStorageThd(void *arg); -static void WaitForISR(USBMassStorageDriver *msdp); -static Thread *msdThd = NULL; +/* End-point info */ +#define USB_MS_DATA_EP 1 /* data end-point index */ +#define USB_MS_EP_SIZE 64 /* end-point size */ + +/* Request types */ +#define MSD_REQ_RESET 0xFF +#define MSD_GET_MAX_LUN 0xFE + +/* CBW/CSW block signatures */ +#define MSD_CBW_SIGNATURE 0x43425355 +#define MSD_CSW_SIGNATURE 0x53425355 + +/* Setup packet access macros */ +#define MSD_SETUP_WORD(setup, index) (uint16_t)(((uint16_t)setup[index + 1] << 8) | (setup[index] & 0x00FF)) +#define MSD_SETUP_VALUE(setup) MSD_SETUP_WORD(setup, 2) +#define MSD_SETUP_INDEX(setup) MSD_SETUP_WORD(setup, 4) +#define MSD_SETUP_LENGTH(setup) MSD_SETUP_WORD(setup, 6) + +/* Command statuses */ +#define MSD_COMMAND_PASSED 0x00 +#define MSD_COMMAND_FAILED 0x01 +#define MSD_COMMAND_PHASE_ERROR 0x02 + +/* SCSI commands */ +#define SCSI_CMD_INQUIRY 0x12 +#define SCSI_CMD_REQUEST_SENSE 0x03 +#define SCSI_CMD_READ_CAPACITY_10 0x25 +#define SCSI_CMD_READ_10 0x28 +#define SCSI_CMD_WRITE_10 0x2A +#define SCSI_CMD_TEST_UNIT_READY 0x00 +#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_CMD_VERIFY_10 0x2F +#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D +#define SCSI_CMD_MODE_SENSE_6 0x1A +#define SCSI_CMD_START_STOP_UNIT 0x1B +#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 + +/* SCSI sense constants */ +#define SCSI_SENSE_KEY_GOOD 0x00 +#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 +#define SCSI_SENSE_KEY_NOT_READY 0x02 +#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03 +#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04 +#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05 +#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06 +#define SCSI_SENSE_KEY_DATA_PROTECT 0x07 +#define SCSI_SENSE_KEY_BLANK_CHECK 0x08 +#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09 +#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A +#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B +#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D +#define SCSI_SENSE_KEY_MISCOMPARE 0x0E +#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00 +#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04 +#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24 +#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28 +#define SCSI_ASENSE_WRITE_PROTECTED 0x27 +#define SCSI_ASENSE_FORMAT_ERROR 0x31 +#define SCSI_ASENSE_INVALID_COMMAND 0x20 +#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 +#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A +#define SCSI_ASENSEQ_NO_QUALIFIER 0x00 +#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01 +#define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02 +#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07 -/* TODO: need a way of specifying the size of this */ +/** + * @brief Response to a regular INQUIRY SCSI command + */ +PACK_STRUCT_BEGIN typedef struct +{ + uint8_t peripheral; + uint8_t removable; + uint8_t version; + uint8_t response_data_format; + uint8_t additional_length; + uint8_t sccstp; + uint8_t bqueetc; + uint8_t cmdque; + uint8_t vendorID[8]; + uint8_t productID[16]; + uint8_t productRev[4]; +} PACK_STRUCT_STRUCT msd_scsi_inquiry_response_t PACK_STRUCT_END; + +/** + * @brief Response to a READ_CAPACITY_10 SCSI command + */ +PACK_STRUCT_BEGIN typedef struct { + uint32_t last_block_addr; + uint32_t block_size; +} PACK_STRUCT_STRUCT msd_scsi_read_capacity_10_response_t PACK_STRUCT_END; + +/** + * @brief Response to a READ_FORMAT_CAPACITIES SCSI command + */ +PACK_STRUCT_BEGIN typedef struct { + uint8_t reserved[3]; + uint8_t capacity_list_length; + uint32_t block_count; + uint32_t desc_and_block_length; +} PACK_STRUCT_STRUCT msd_scsi_read_format_capacities_response_t PACK_STRUCT_END; + +/** + * @brief Read-write buffers (TODO: need a way of specifying the size of this) + */ static uint8_t rw_buf[2][512]; -inline uint32_t swap_uint32( uint32_t val ) { - val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF ); - return ((val << 16) & 0xFFFF0000) | ((val >> 16) & 0x0000FFFF); -} +/** + * @brief Byte-swap a 32 bits unsigned integer + */ +#define swap_uint32(x) ((((x) & 0x000000FF) << 24) \ + | (((x) & 0x0000FF00) << 8) \ + | (((x) & 0x00FF0000) >> 8) \ + | (((x) & 0xFF000000) >> 24)) -#define swap_uint16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) +/** + * @brief Byte-swap a 16 bits unsigned integer + */ +#define swap_uint16(x) ((((x) & 0x00FF) << 8) \ + | (((x) & 0xFF00) >> 8)) +/** + * @brief Macros that can be overriden to do something when read/write transfers are active + */ #if !defined(MSD_RW_LED_ON) -#define MSD_RW_LED_ON() + #define MSD_RW_LED_ON() #endif - #if !defined(MSD_RW_LED_OFF) -#define MSD_RW_LED_OFF() + #define MSD_RW_LED_OFF() #endif -/*===========================================================================*/ -/* USB related stuff. */ -/*===========================================================================*/ - -/* - * USB Device Descriptor. +/** + * @brief USB Device Descriptor */ static const uint8_t msd_device_descriptor_data[18] = { - USB_DESC_DEVICE (0x0200, /* bcdUSB (2.0). */ - 0x00, /* bDeviceClass (None). */ - 0x00, /* bDeviceSubClass. */ - 0x00, /* bDeviceProtocol. */ - 0x40, /* Control Endpoint Size. */ - 0x0483, /* idVendor (ST). */ - 0x5742, /* idProduct. */ - 0x0100, /* bcdDevice. */ - 1, /* iManufacturer. */ - 2, /* iProduct. */ - 3, /* iSerialNumber. */ - 1) /* bNumConfigurations. */ + USB_DESC_DEVICE(0x0200, /* bcdUSB (2.0). */ + 0x00, /* bDeviceClass (None). */ + 0x00, /* bDeviceSubClass. */ + 0x00, /* bDeviceProtocol. */ + 0x40, /* Control Endpoint Size. */ + 0x0483, /* idVendor (ST). */ + 0x5742, /* idProduct. */ + 0x0100, /* bcdDevice. */ + 1, /* iManufacturer. */ + 2, /* iProduct. */ + 3, /* iSerialNumber. */ + 1) /* bNumConfigurations. */ }; -/* - * Device Descriptor wrapper. +/** + * @brief Device Descriptor wrapper */ static const USBDescriptor msd_device_descriptor = { - sizeof msd_device_descriptor_data, - msd_device_descriptor_data + sizeof msd_device_descriptor_data, + msd_device_descriptor_data }; -/* Configuration Descriptor tree for a CDC.*/ +/** + * @brief Configuration Descriptor tree for a CDC + */ static const uint8_t msd_configuration_descriptor_data[] = { - /* Configuration Descriptor.*/ - USB_DESC_CONFIGURATION(0x0020, /* wTotalLength. */ - 0x01, /* bNumInterfaces. */ - 0x01, /* bConfigurationValue. */ - 0, /* iConfiguration. */ - 0xC0, /* bmAttributes (self powered). */ - 0x32), /* bMaxPower (100mA). */ - /* Interface Descriptor.*/ - USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ - 0x00, /* bAlternateSetting. */ - 0x02, /* bNumEndpoints. */ - 0x08, /* bInterfaceClass (Mass Storage) */ - 0x06, /* bInterfaceSubClass (SCSI - Transparent storage class) */ - 0x50, /* bInterfaceProtocol (Bulk Only) */ - 0), /* iInterface. (none) */ - /* Mass Storage Data In Endpoint Descriptor.*/ - USB_DESC_ENDPOINT (USB_MS_DATA_EP|0x80, - 0x02, /* bmAttributes (Bulk). */ - USB_MS_EP_SIZE,/* wMaxPacketSize. */ - 0x05), /* bInterval. 1ms */ - /* Mass Storage Data In Endpoint Descriptor.*/ - USB_DESC_ENDPOINT (USB_MS_DATA_EP, - 0x02, /* bmAttributes (Bulk). */ - USB_MS_EP_SIZE,/* wMaxPacketSize. */ - 0x05) /* bInterval. 1ms */ + /* Configuration Descriptor.*/ + USB_DESC_CONFIGURATION(0x0020, /* wTotalLength. */ + 0x01, /* bNumInterfaces. */ + 0x01, /* bConfigurationValue. */ + 0, /* iConfiguration. */ + 0xC0, /* bmAttributes (self powered). */ + 0x32), /* bMaxPower (100mA). */ + /* Interface Descriptor.*/ + USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x02, /* bNumEndpoints. */ + 0x08, /* bInterfaceClass (Mass Storage) */ + 0x06, /* bInterfaceSubClass (SCSI + Transparent storage class) */ + 0x50, /* bInterfaceProtocol (Bulk Only) */ + 0), /* iInterface. (none) */ + /* Mass Storage Data In Endpoint Descriptor.*/ + USB_DESC_ENDPOINT (USB_MS_DATA_EP|0x80, + 0x02, /* bmAttributes (Bulk). */ + USB_MS_EP_SIZE,/* wMaxPacketSize. */ + 0x05), /* bInterval. 1ms */ + /* Mass Storage Data In Endpoint Descriptor.*/ + USB_DESC_ENDPOINT (USB_MS_DATA_EP, + 0x02, /* bmAttributes (Bulk). */ + USB_MS_EP_SIZE,/* wMaxPacketSize. */ + 0x05) /* bInterval. 1ms */ }; -/* - * Configuration Descriptor wrapper. +/** + * @brief Configuration Descriptor wrapper */ static const USBDescriptor msd_configuration_descriptor = { - sizeof msd_configuration_descriptor_data, - msd_configuration_descriptor_data + sizeof msd_configuration_descriptor_data, + msd_configuration_descriptor_data }; -/* - * U.S. English language identifier. +/** + * @brief U.S. English language identifier */ static const uint8_t msd_string0[] = { - USB_DESC_BYTE(4), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */ + USB_DESC_BYTE(4), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */ }; -/* - * Vendor string. +/** + * @brief Vendor string */ static const uint8_t msd_string1[] = { - USB_DESC_BYTE(38), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, - 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, - 'c', 0, 's', 0 + USB_DESC_BYTE(38), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, + 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, + 'c', 0, 's', 0 }; -/* - * Device Description string. +/** + * @brief Device Description string */ static const uint8_t msd_string2[] = { - USB_DESC_BYTE(62), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, - 'R', 0, 'T', 0, ' ', 0, 'M', 0, 'a', 0, 's', 0, 's', 0, ' ', 0, - 'S', 0, 't', 0, 'o', 0, 'r', 0, 'a', 0, 'g', 0, 'e', 0, ' ', 0, - 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0 + USB_DESC_BYTE(62), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, + 'R', 0, 'T', 0, ' ', 0, 'M', 0, 'a', 0, 's', 0, 's', 0, ' ', 0, + 'S', 0, 't', 0, 'o', 0, 'r', 0, 'a', 0, 'g', 0, 'e', 0, ' ', 0, + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0 }; +/** + * @brief Device Serial Number string + */ static const uint8_t msd_string3[] = { - USB_DESC_BYTE(26), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - 'A', 0, 'E', 0, 'C', 0, 'C', 0, 'E', 0, 'C', 0, 'C', 0, 'C', 0, 'C', 0, - '0' + CH_KERNEL_MAJOR, 0, - '0' + CH_KERNEL_MINOR, 0, - '0' + CH_KERNEL_PATCH, 0 + USB_DESC_BYTE(26), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + 'A', 0, 'E', 0, 'C', 0, 'C', 0, 'E', 0, 'C', 0, 'C', 0, 'C', 0, 'C', 0, + '0' + CH_KERNEL_MAJOR, 0, + '0' + CH_KERNEL_MINOR, 0, + '0' + CH_KERNEL_PATCH, 0 }; -/* - * Strings wrappers array. +/** + * @brief Strings wrappers array */ static const USBDescriptor msd_strings[] = { - {sizeof msd_string0, msd_string0}, - {sizeof msd_string1, msd_string1}, - {sizeof msd_string2, msd_string2}, - {sizeof msd_string3, msd_string3} + {sizeof msd_string0, msd_string0}, + {sizeof msd_string1, msd_string1}, + {sizeof msd_string2, msd_string2}, + {sizeof msd_string3, msd_string3} }; -/* - * Handles the GET_DESCRIPTOR callback. All required descriptors must be - * handled here. - */ -static const USBDescriptor *get_descriptor(USBDriver *usbp, - uint8_t dtype, - uint8_t dindex, - uint16_t lang) { - - (void)usbp; - (void)lang; - switch (dtype) { - case USB_DESCRIPTOR_DEVICE: - return &msd_device_descriptor; - case USB_DESCRIPTOR_CONFIGURATION: - return &msd_configuration_descriptor; - case USB_DESCRIPTOR_STRING: - if (dindex < 4) - return &msd_strings[dindex]; - } - return NULL; +/** + * @brief Handles the GET_DESCRIPTOR callback. + * All required descriptors must be handled here. + */ +static const USBDescriptor *msd_get_descriptor(USBDriver *usbp, + uint8_t dtype, + uint8_t dindex, + uint16_t lang) { + + (void)usbp; + (void)lang; + + switch (dtype) { + case USB_DESCRIPTOR_DEVICE: + return &msd_device_descriptor; + case USB_DESCRIPTOR_CONFIGURATION: + return &msd_configuration_descriptor; + case USB_DESCRIPTOR_STRING: + if (dindex < 4) + return &msd_strings[dindex]; + } + return NULL; } /** @@ -175,618 +283,683 @@ static const USBDescriptor *get_descriptor(USBDriver *usbp, * @retval TRUE Message handled internally. * @retval FALSE Message not handled. */ -bool_t msdRequestsHook(USBDriver *usbp) { - if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) && - ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) { - /* check that the request is for interface 0.*/ - if(MSD_SETUP_INDEX(usbp->setup) != 0) - return FALSE; - - /* act depending on bRequest = setup[1] */ - switch(usbp->setup[1]) { - case MSD_REQ_RESET: - /* check that it is a HOST2DEV request */ - if(((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_HOST2DEV) || - (MSD_SETUP_LENGTH(usbp->setup) != 0) || - (MSD_SETUP_VALUE(usbp->setup) != 0)) - return FALSE; - - /* reset all endpoints */ - /* TODO!*/ - /* The device shall NAK the status stage of the device request until - * the Bulk-Only Mass Storage Reset is complete. - */ - return TRUE; - case MSD_GET_MAX_LUN: - /* check that it is a DEV2HOST request */ - if(((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_DEV2HOST) || - (MSD_SETUP_LENGTH(usbp->setup) != 1) || - (MSD_SETUP_VALUE(usbp->setup) != 0)) - return FALSE; - - static uint8_t len_buf[1] = {0}; - /* stall to indicate that we don't support LUN */ - usbSetupTransfer(usbp, len_buf, 1, NULL); - return TRUE; - default: - return FALSE; - break; - } - } - return FALSE; +bool_t msd_handle_requests(USBDriver *usbp) { + + /* check that the request is of type Class / Interface */ + if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) && + ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) { + + /* check that the request is for interface 0 */ + if (MSD_SETUP_INDEX(usbp->setup) != 0) + return FALSE; + + /* act depending on bRequest = setup[1] */ + switch (usbp->setup[1]) { + case MSD_REQ_RESET: + /* check that it is a HOST2DEV request */ + if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_HOST2DEV) || + (MSD_SETUP_LENGTH(usbp->setup) != 0) || + (MSD_SETUP_VALUE(usbp->setup) != 0)) + { + return FALSE; + } + + /* reset all endpoints */ + /* TODO!*/ + /* The device shall NAK the status stage of the device request until + * the Bulk-Only Mass Storage Reset is complete. + */ + return TRUE; + case MSD_GET_MAX_LUN: + /* check that it is a DEV2HOST request */ + if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_DEV2HOST) || + (MSD_SETUP_LENGTH(usbp->setup) != 1) || + (MSD_SETUP_VALUE(usbp->setup) != 0)) + { + return FALSE; + } + + static uint8_t len_buf[1] = {0}; + /* stall to indicate that we don't support LUN */ + usbSetupTransfer(usbp, len_buf, 1, NULL); + return TRUE; + default: + return FALSE; + break; + } + } + + return FALSE; } -static void WaitForISR(USBMassStorageDriver *msdp) { - /* sleep until it completes */ - chSysLock(); - chBSemWaitS(&msdp->bsem); - chSysUnlock(); + +/** + * @brief Wait until the end-point interrupt handler has been called + */ +static void msd_wait_for_isr(USBMassStorageDriver *msdp) { + + /* sleep until it completes */ + chSysLock(); + chBSemWaitS(&msdp->bsem); + chSysUnlock(); } -void msdUsbEvent(USBDriver *usbp, usbep_t ep) { - (void)usbp; - (void)ep; +static void msd_handle_end_point_notification(USBDriver *usbp, usbep_t ep) { + + (void)usbp; + (void)ep; chSysLockFromIsr(); - chBSemSignalI(&((USBMassStorageDriver *)usbp->param)->bsem); + chBSemSignalI(&((USBMassStorageDriver *)usbp->param)->bsem); chSysUnlockFromIsr(); } /** - * @brief IN EP1 state. + * @brief IN end-point 1 state */ -static USBInEndpointState ep1InState; +static USBInEndpointState ep1_in_state; /** - * @brief OUT EP1 state. + * @brief OUT end-point 1 state */ -static USBOutEndpointState ep1OutState; +static USBOutEndpointState ep1_out_state; /** - * @brief EP1 initialization structure (IN only). + * @brief End-point 1 initialization structure */ -static const USBEndpointConfig epDataConfig = { - USB_EP_MODE_TYPE_BULK, - NULL, - msdUsbEvent, - msdUsbEvent, - USB_MS_EP_SIZE, - USB_MS_EP_SIZE, - &ep1InState, - &ep1OutState, - 1, - NULL +static const USBEndpointConfig ep_data_config = { + USB_EP_MODE_TYPE_BULK, + NULL, + msd_handle_end_point_notification, + msd_handle_end_point_notification, + USB_MS_EP_SIZE, + USB_MS_EP_SIZE, + &ep1_in_state, + &ep1_out_state, + 1, + NULL }; -/* - * Handles the USB driver global events. +/** + * @brief Handles the USB driver global events */ -static void usb_event(USBDriver *usbp, usbevent_t event) { - USBMassStorageDriver *msdp = (USBMassStorageDriver *)usbp->param; - switch (event) { - case USB_EVENT_RESET: - return; - case USB_EVENT_ADDRESS: - return; - case USB_EVENT_CONFIGURED: - chSysLockFromIsr(); - usbInitEndpointI(usbp, USB_MS_DATA_EP, &epDataConfig); - /* initialise the thread */ - chBSemSignalI(&msdp->bsem); - - /* signal that the device is connected */ - chEvtBroadcastI(&msdp->evt_connected); - chSysUnlockFromIsr(); - - return; - case USB_EVENT_SUSPEND: - return; - case USB_EVENT_WAKEUP: - return; - case USB_EVENT_STALLED: +static void msd_usb_event(USBDriver *usbp, usbevent_t event) { + + USBMassStorageDriver *msdp = (USBMassStorageDriver *)usbp->param; + + switch (event) { + case USB_EVENT_RESET: + return; + case USB_EVENT_ADDRESS: + return; + case USB_EVENT_CONFIGURED: + chSysLockFromIsr(); + usbInitEndpointI(usbp, USB_MS_DATA_EP, &ep_data_config); + /* initialise the thread */ + chBSemSignalI(&msdp->bsem); + + /* signal that the device is connected */ + chEvtBroadcastI(&msdp->evt_connected); + chSysUnlockFromIsr(); + return; + case USB_EVENT_SUSPEND: + return; + case USB_EVENT_WAKEUP: + return; + case USB_EVENT_STALLED: + return; + } return; - } - return; } +/** + * @brief Global USB configuration + */ static const USBConfig msd_usb_config = { - usb_event, - get_descriptor, - msdRequestsHook, - NULL + msd_usb_event, + msd_get_descriptor, + msd_handle_requests, + NULL }; -static inline void SCSISetSense(USBMassStorageDriver *msdp, uint8_t key, uint8_t acode, uint8_t aqual) { - msdp->sense.byte[2] = key; - msdp->sense.byte[12] = acode; - msdp->sense.byte[13] = aqual; +/** + * @brief Changes the SCSI sense information + */ +static inline void msd_scsi_set_sense(USBMassStorageDriver *msdp, uint8_t key, uint8_t acode, uint8_t aqual) { + msdp->sense.byte[2] = key; + msdp->sense.byte[12] = acode; + msdp->sense.byte[13] = aqual; } -bool_t SCSICommandInquiry(USBMassStorageDriver *msdp) { - msd_cbw_t *cbw = &(msdp->cbw); +/** + * @brief Processes an INQUIRY SCSI command + */ +bool_t msd_scsi_process_inquiry(USBMassStorageDriver *msdp) { + + msd_cbw_t *cbw = &(msdp->cbw); /* check the EVPD bit (Vital Product Data) */ - if(cbw->scsi_cmd_data[1] & 0x01) { + if (cbw->scsi_cmd_data[1] & 0x01) { /* check the Page Code byte to know the type of product data to reply */ - switch(cbw->scsi_cmd_data[2]) { - - /* unit serial number */ - case 0x80: { - uint8_t response[] = {'z', 'z', 'z'}; - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, response, sizeof(response)); - chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); - msdp->result = TRUE; - - /* wait for ISR */ - return TRUE; - } + switch (cbw->scsi_cmd_data[2]) { + + /* unit serial number */ + case 0x80: { + uint8_t response[] = {'0'}; /* TODO */ + usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, response, sizeof(response)); + chSysLock(); + usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); + msdp->result = TRUE; + + /* wait for ISR */ + return TRUE; + } - /* unhandled */ - default: - SCSISetSense( msdp, - SCSI_SENSE_KEY_ILLEGAL_REQUEST, - SCSI_ASENSE_INVALID_FIELD_IN_CDB, - SCSI_ASENSEQ_NO_QUALIFIER); - return FALSE; + /* unhandled */ + default: + msd_scsi_set_sense(msdp, + SCSI_SENSE_KEY_ILLEGAL_REQUEST, + SCSI_ASENSE_INVALID_FIELD_IN_CDB, + SCSI_ASENSEQ_NO_QUALIFIER); + return FALSE; } } else { - static const scsi_inquiry_response_t inquiry = { - 0x00, // direct access block device - 0x80, // removable - 0x04, // SPC-2 - 0x02, // response data format - 0x20, // response has 0x20 + 4 bytes - 0x00, - 0x00, - 0x00, - "Chibios", - "Mass Storage", - {'v',CH_KERNEL_MAJOR+'0','.',CH_KERNEL_MINOR+'0'}, - }; - - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&inquiry, - sizeof(scsi_inquiry_response_t)); - - chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); - - msdp->result = TRUE; - - /* wait for ISR */ - return TRUE; + static const msd_scsi_inquiry_response_t inquiry = { + 0x00, /* direct access block device */ + 0x80, /* removable */ + 0x04, /* SPC-2 */ + 0x02, /* response data format */ + 0x20, /* response has 0x20 + 4 bytes */ + 0x00, + 0x00, + 0x00, + "Chibios", + "Mass Storage", + {'v', CH_KERNEL_MAJOR + '0', '.', CH_KERNEL_MINOR + '0'}, + }; + + usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&inquiry, + sizeof(msd_scsi_inquiry_response_t)); + + chSysLock(); + usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); + + msdp->result = TRUE; + + /* wait for ISR */ + return TRUE; } } -bool_t SCSICommandRequestSense(USBMassStorageDriver *msdp) { - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->sense, - sizeof(scsi_sense_response_t)); +/** + * @brief Processes a REQUEST_SENSE SCSI command + */ +bool_t msd_scsi_process_request_sense(USBMassStorageDriver *msdp) { - chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); + usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->sense, + sizeof(msdp->sense)); - msdp->result = TRUE; + chSysLock(); + usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); - /* wait for ISR */ - return TRUE; + msdp->result = TRUE; + + /* wait for ISR */ + return TRUE; } -bool_t SCSICommandReadCapacity10(USBMassStorageDriver *msdp) { - static SCSIReadCapacity10Response_t response; +/** + * @brief Processes a READ_CAPACITY_10 SCSI command + */ +bool_t msd_scsi_process_read_capacity_10(USBMassStorageDriver *msdp) { - response.block_size = swap_uint32(msdp->block_dev_info.blk_size); - response.last_block_addr = swap_uint32(msdp->block_dev_info.blk_num-1); + static msd_scsi_read_capacity_10_response_t response; - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&response, - sizeof(SCSIReadCapacity10Response_t)); + response.block_size = swap_uint32(msdp->block_dev_info.blk_size); + response.last_block_addr = swap_uint32(msdp->block_dev_info.blk_num-1); - chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); + usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&response, sizeof(response)); + + chSysLock(); + usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); - msdp->result = TRUE; + msdp->result = TRUE; - /* wait for ISR */ - return TRUE; + /* wait for ISR */ + return TRUE; } -bool_t SCSICommandSendDiagnostic(USBMassStorageDriver *msdp) { - msd_cbw_t *cbw = &(msdp->cbw); +/** + * @brief Processes a SEND_DIAGNOSTIC SCSI command + */ +bool_t msd_scsi_process_send_diagnostic(USBMassStorageDriver *msdp) { - if(!(cbw->scsi_cmd_data[1] & (1 << 2))) { - /* Only self-test supported - update SENSE key and fail the command */ - SCSISetSense( msdp, - SCSI_SENSE_KEY_ILLEGAL_REQUEST, - SCSI_ASENSE_INVALID_FIELD_IN_CDB, - SCSI_ASENSEQ_NO_QUALIFIER); + msd_cbw_t *cbw = &(msdp->cbw); - return FALSE; - } + if (!(cbw->scsi_cmd_data[1] & (1 << 2))) { + /* only self-test supported - update SENSE key and fail the command */ + msd_scsi_set_sense(msdp, + SCSI_SENSE_KEY_ILLEGAL_REQUEST, + SCSI_ASENSE_INVALID_FIELD_IN_CDB, + SCSI_ASENSEQ_NO_QUALIFIER); + return FALSE; + } - /* TODO: actually perform the test */ - msdp->result = TRUE; + /* TODO: actually perform the test */ + msdp->result = TRUE; - /* don't wait for ISR */ - return FALSE; + /* don't wait for ISR */ + return FALSE; } -bool_t SCSICommandStartReadWrite10(USBMassStorageDriver *msdp) { - msd_cbw_t *cbw = &(msdp->cbw); - - if((cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) && - blkIsWriteProtected(msdp->bbdp)) { - /* device is write protected and a write has been issued */ - /* Block address is invalid, update SENSE key and return command fail */ - SCSISetSense( msdp, - SCSI_SENSE_KEY_DATA_PROTECT, - SCSI_ASENSE_WRITE_PROTECTED, - SCSI_ASENSEQ_NO_QUALIFIER); - msdp->result = FALSE; - return FALSE; - } - - uint32_t rw_block_address = swap_uint32(*(uint32_t *)&cbw->scsi_cmd_data[2]); - uint16_t total = swap_uint16(*(uint16_t *)&cbw->scsi_cmd_data[7]); - uint16_t i = 0; - - if(rw_block_address >= msdp->block_dev_info.blk_num) { - /* Block address is invalid, update SENSE key and return command fail */ - SCSISetSense( msdp, - SCSI_SENSE_KEY_DATA_PROTECT, - SCSI_ASENSE_WRITE_PROTECTED, - SCSI_ASENSEQ_NO_QUALIFIER); - msdp->result = FALSE; - - /* don't wait for ISR */ - return FALSE; - } - - if(cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) { - /* get the first packet */ - usbPrepareReceive(msdp->usbp, USB_MS_DATA_EP, rw_buf[i % 2], - msdp->block_dev_info.blk_size); - - chSysLock(); - usbStartReceiveI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); - - WaitForISR(msdp); - /* loop over each block */ - for(i = 0; i < total; i++) { - - if(i < (total - 1)) { - /* There is at least one block of data left to be read over USB */ - /* queue this read before issuing the blocking write */ - usbPrepareReceive(msdp->usbp, USB_MS_DATA_EP, rw_buf[(i+1) % 2], - msdp->block_dev_info.blk_size); - - chSysLock(); - usbStartReceiveI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); - } - - /* now write the block to the block device */ - if(blkWrite(msdp->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { +/** + * @brief Processes a READ_WRITE_10 SCSI command + */ +bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { + + msd_cbw_t *cbw = &(msdp->cbw); + + if ((cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) && blkIsWriteProtected(msdp->bbdp)) { + /* device is write protected and a write has been issued */ + /* block address is invalid, update SENSE key and return command fail */ + msd_scsi_set_sense(msdp, + SCSI_SENSE_KEY_DATA_PROTECT, + SCSI_ASENSE_WRITE_PROTECTED, + SCSI_ASENSEQ_NO_QUALIFIER); + msdp->result = FALSE; + + /* don't wait for ISR */ + return FALSE; + } + + uint32_t rw_block_address = swap_uint32(*(uint32_t *)&cbw->scsi_cmd_data[2]); + uint16_t total = swap_uint16(*(uint16_t *)&cbw->scsi_cmd_data[7]); + uint16_t i = 0; + + if (rw_block_address >= msdp->block_dev_info.blk_num) { + /* block address is invalid, update SENSE key and return command fail */ + msd_scsi_set_sense(msdp, + SCSI_SENSE_KEY_DATA_PROTECT, + SCSI_ASENSE_WRITE_PROTECTED, + SCSI_ASENSEQ_NO_QUALIFIER); + msdp->result = FALSE; + + /* don't wait for ISR */ + return FALSE; + } + + if (cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) { + /* process a write command */ + + /* get the first packet */ + usbPrepareReceive(msdp->usbp, USB_MS_DATA_EP, rw_buf[i % 2], + msdp->block_dev_info.blk_size); + + chSysLock(); + usbStartReceiveI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); + + msd_wait_for_isr(msdp); + + /* loop over each block */ + for (i = 0; i < total; i++) { + + if (i < (total - 1)) { + /* there is at least one block of data left to be read over USB */ + /* queue this read before issuing the blocking write */ + usbPrepareReceive(msdp->usbp, USB_MS_DATA_EP, rw_buf[(i + 1) % 2], + msdp->block_dev_info.blk_size); + + chSysLock(); + usbStartReceiveI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); + } + + /* now write the block to the block device */ + if (blkWrite(msdp->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { /* TODO: handle this */ chSysHalt(); - } - - if(i < (total -1 )) { - /* now wait for the USB event to complete */ - WaitForISR(msdp); - } - } - } else { - i = 0; - /* read the first block from block device */ - if(blkRead(msdp->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { + } + + if (i < (total - 1)) { + /* now wait for the USB event to complete */ + msd_wait_for_isr(msdp); + } + } + } else { + /* process a read command */ + + i = 0; + + /* read the first block from block device */ + if (blkRead(msdp->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { /* TODO: handle this */ chSysHalt(); - } - - /* loop over each block */ - for(i = 0; i < total; i++) { - /* transmit the block */ - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, rw_buf[i % 2], - msdp->block_dev_info.blk_size); + } - chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); + /* loop over each block */ + for (i = 0; i < total; i++) { + /* transmit the block */ + usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, rw_buf[i % 2], + msdp->block_dev_info.blk_size); - if(i < (total - 1)) { - /* there is at least one more block to be read from device */ - /* so read that whilst the USB transfer takes place */ + chSysLock(); + usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); - if(blkRead(msdp->bbdp, rw_block_address++, rw_buf[(i+1) % 2], 1) == CH_FAILED) { + if (i < (total - 1)) { + /* there is at least one more block to be read from device */ + /* so read that whilst the USB transfer takes place */ + if (blkRead(msdp->bbdp, rw_block_address++, rw_buf[(i + 1) % 2], 1) == CH_FAILED) { /* TODO: handle this */ chSysHalt(); - } - } + } + } - WaitForISR(msdp); - } + /* wait for the USB event to complete */ + msd_wait_for_isr(msdp); + } } - msdp->result = TRUE; + msdp->result = TRUE; - /* don't wait for ISR */ - return FALSE; + /* don't wait for ISR */ + return FALSE; } -bool_t SCSICommandStartStopUnit(USBMassStorageDriver *msdp) { - SCSIStartStopUnitRequest_t *ssu = (SCSIStartStopUnitRequest_t *)&(msdp->cbw.scsi_cmd_data); - - if((ssu->loej_start & 0b00000011) == 0b00000010) { - /* device has been ejected */ - chEvtBroadcast(&msdp->evt_ejected); +/** + * @brief Processes a START_STOP_UNIT SCSI command + */ +bool_t msd_scsi_process_start_stop_unit(USBMassStorageDriver *msdp) { - msdp->state = ejected; - } + if ((msdp->cbw.scsi_cmd_data[4] & 0x03) == 0x02) { + /* device has been ejected */ + chEvtBroadcast(&msdp->evt_ejected); + msdp->state = MSD_EJECTED; + } - msdp->result = TRUE; + msdp->result = TRUE; - /* don't wait for ISR */ - return FALSE; + /* don't wait for ISR */ + return FALSE; } -bool_t SCSICommandModeSense6(USBMassStorageDriver *msdp) { - /* Send an empty header response with the Write Protect flag status */ - /* TODO set byte3 to 0x80 if disk is read only */ - static uint8_t response[4] = {0x00, 0x00, 0x00, 0x00}; +/** + * @brief Processes a MODE_SENSE_6 SCSI command + */ +bool_t msd_scsi_process_mode_sense_6(USBMassStorageDriver *msdp) { - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, response, 4); + /* Send an empty header response with the Write Protect flag status */ + /* TODO set byte3 to 0x80 if disk is read only */ + static uint8_t response[4] = {0x00, 0x00, 0x00, 0x00}; - chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); + usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, response, sizeof(response)); + + chSysLock(); + usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); - msdp->result = TRUE; + msdp->result = TRUE; - /* wait for ISR */ - return TRUE; + /* wait for ISR */ + return TRUE; } -bool_t SCSICommandReadFormatCapacities(USBMassStorageDriver *msdp) -{ - SCSIReadFormatCapacitiesResponse_t response; +/** + * @brief Processes a READ_FORMAT_CAPACITIES SCSI command + */ +bool_t msd_scsi_process_read_format_capacities(USBMassStorageDriver *msdp) { + + msd_scsi_read_format_capacities_response_t response; response.capacity_list_length = 1; response.block_count = swap_uint32(msdp->block_dev_info.blk_num); response.desc_and_block_length = swap_uint32((0x02 << 24) | (msdp->block_dev_info.blk_size & 0x00FFFFFF)); - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (const uint8_t*)&response, sizeof(response)); + usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (const uint8_t*)&response, sizeof(response)); - chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); + chSysLock(); + usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); - msdp->result = TRUE; + msdp->result = TRUE; - /* wait for ISR */ - return TRUE; + /* wait for ISR */ + return TRUE; } -bool_t msdWaitForCommandBlock(USBMassStorageDriver *msdp) { - usbPrepareReceive(msdp->usbp, USB_MS_DATA_EP, - (uint8_t *)&msdp->cbw, sizeof(msd_cbw_t)); +/** + * @brief Waits for a new command block + */ +bool_t msd_wait_for_command_block(USBMassStorageDriver *msdp) { + + usbPrepareReceive(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->cbw, sizeof(msdp->cbw)); chSysLock(); usbStartReceiveI(msdp->usbp, USB_MS_DATA_EP); chSysUnlock(); - msdp->state = read_cmd_block; + msdp->state = MSD_READ_COMMAND_BLOCK; /* wait for ISR */ return TRUE; } +/** + * @brief Reads a newly received command block + */ +bool_t msd_read_command_block(USBMassStorageDriver *msdp) { + msd_cbw_t *cbw = &(msdp->cbw); -/* A command block has been received */ -bool_t msdReadCommandBlock(USBMassStorageDriver *msdp) { - msd_cbw_t *cbw = &(msdp->cbw); - - /* by default transition back to the idle state */ - msdp->state = idle; - - /* check the command */ - if((cbw->signature != MSD_CBW_SIGNATURE) || - (cbw->lun > 0) || - ((cbw->data_len > 0) && (cbw->flags & 0x1F)) || - (cbw->scsi_cmd_len == 0) || - (cbw->scsi_cmd_len > 16)) { - - /* stall both IN and OUT endpoints */ - chSysLock(); - usbStallReceiveI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); - - /* don't wait for ISR */ - return FALSE; - } - - bool_t sleep = FALSE; - switch(cbw->scsi_cmd_data[0]) { - case SCSI_CMD_INQUIRY: - sleep = SCSICommandInquiry(msdp); - break; - case SCSI_CMD_REQUEST_SENSE: - sleep = SCSICommandRequestSense(msdp); - break; - case SCSI_CMD_READ_CAPACITY_10: - sleep = SCSICommandReadCapacity10(msdp); - break; - case SCSI_CMD_READ_10: - case SCSI_CMD_WRITE_10: - MSD_RW_LED_ON(); - sleep = SCSICommandStartReadWrite10(msdp); - MSD_RW_LED_OFF(); - break; - case SCSI_CMD_SEND_DIAGNOSTIC: - sleep = SCSICommandSendDiagnostic(msdp); - break; - case SCSI_CMD_TEST_UNIT_READY: - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - case SCSI_CMD_VERIFY_10: - /* don't handle */ - msdp->result = TRUE; - break; - case SCSI_CMD_MODE_SENSE_6: - sleep = SCSICommandModeSense6(msdp); - break; - case SCSI_CMD_START_STOP_UNIT: - sleep = SCSICommandStartStopUnit(msdp); - break; + /* by default transition back to the idle state */ + msdp->state = MSD_IDLE; + + /* check the command */ + if ((cbw->signature != MSD_CBW_SIGNATURE) || + (cbw->lun > 0) || + ((cbw->data_len > 0) && (cbw->flags & 0x1F)) || + (cbw->scsi_cmd_len == 0) || + (cbw->scsi_cmd_len > 16)) { + + /* stall both IN and OUT endpoints */ + chSysLock(); + usbStallReceiveI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); + + /* don't wait for ISR */ + return FALSE; + } + + bool_t sleep = FALSE; + + /* check the command */ + switch (cbw->scsi_cmd_data[0]) { + case SCSI_CMD_INQUIRY: + sleep = msd_scsi_process_inquiry(msdp); + break; + case SCSI_CMD_REQUEST_SENSE: + sleep = msd_scsi_process_request_sense(msdp); + break; + case SCSI_CMD_READ_CAPACITY_10: + sleep = msd_scsi_process_read_capacity_10(msdp); + break; + case SCSI_CMD_READ_10: + case SCSI_CMD_WRITE_10: + MSD_RW_LED_ON(); + sleep = msd_scsi_process_start_read_write_10(msdp); + MSD_RW_LED_OFF(); + break; + case SCSI_CMD_SEND_DIAGNOSTIC: + sleep = msd_scsi_process_send_diagnostic(msdp); + break; + case SCSI_CMD_MODE_SENSE_6: + sleep = msd_scsi_process_mode_sense_6(msdp); + break; + case SCSI_CMD_START_STOP_UNIT: + sleep = msd_scsi_process_start_stop_unit(msdp); + break; case SCSI_CMD_READ_FORMAT_CAPACITIES: - sleep = SCSICommandReadFormatCapacities(msdp); - break; - default: - SCSISetSense( msdp, - SCSI_SENSE_KEY_ILLEGAL_REQUEST, - SCSI_ASENSE_INVALID_COMMAND, - SCSI_ASENSEQ_NO_QUALIFIER); - - /* stall IN endpoint */ - chSysLock(); - usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); - - cbw->data_len = 0; - return FALSE; - } - - cbw->data_len = 0; - - if(msdp->result) { - /* update sense with success status */ - SCSISetSense( msdp, - SCSI_SENSE_KEY_GOOD, - SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, - SCSI_ASENSEQ_NO_QUALIFIER); - } else { - /* stall IN endpoint */ - chSysLock(); - usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); - - cbw->data_len = 0; - return FALSE; - } - - if(sleep) { - WaitForISR(msdp); - } - - msd_csw_t *csw = &(msdp->csw); - - if(!msdp->result && cbw->data_len) { - /* still bytes left to send, this is too early to send CSW? */ - chSysLock(); - usbStallReceiveI(msdp->usbp, USB_MS_DATA_EP); - usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); - - return FALSE; - } - - csw->status = (msdp->result) ? MSD_COMMAND_PASSED : MSD_COMMAND_FAILED; - csw->signature = MSD_CSW_SIGNATURE; - csw->data_residue = cbw->data_len; - csw->tag = cbw->tag; - - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)csw, - sizeof(msd_csw_t)); - - chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); - chSysUnlock(); - - /* wait on ISR */ - return TRUE; -} + sleep = msd_scsi_process_read_format_capacities(msdp); + break; + case SCSI_CMD_TEST_UNIT_READY: + case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + case SCSI_CMD_VERIFY_10: + /* don't handle */ + msdp->result = TRUE; + break; + default: + msd_scsi_set_sense(msdp, + SCSI_SENSE_KEY_ILLEGAL_REQUEST, + SCSI_ASENSE_INVALID_COMMAND, + SCSI_ASENSEQ_NO_QUALIFIER); + + /* stall IN endpoint */ + chSysLock(); + usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); + + cbw->data_len = 0; + return FALSE; + } -static msg_t MassStorageThd(void *arg) { - USBMassStorageDriver *msdp = (USBMassStorageDriver *)arg; + cbw->data_len = 0; + + if (msdp->result) { + /* update sense with success status */ + msd_scsi_set_sense(msdp, + SCSI_SENSE_KEY_GOOD, + SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, + SCSI_ASENSEQ_NO_QUALIFIER); + } else { + /* stall IN endpoint */ + chSysLock(); + usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); + + cbw->data_len = 0; + return FALSE; + } - chRegSetThreadName("USB-MSD"); + if (sleep) + msd_wait_for_isr(msdp); - bool_t wait_for_isr = FALSE; + msd_csw_t *csw = &(msdp->csw); - /* wait for the usb to be initialised */ - WaitForISR(msdp); + if (!msdp->result && cbw->data_len) { + /* still bytes left to send, this is too early to send CSW? */ + chSysLock(); + usbStallReceiveI(msdp->usbp, USB_MS_DATA_EP); + usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); - while (TRUE) { - wait_for_isr = FALSE; + return FALSE; + } - /* wait on data depending on the current state */ - switch(msdp->state) { - case idle: - wait_for_isr = msdWaitForCommandBlock(msdp); - break; - case read_cmd_block: - wait_for_isr = msdReadCommandBlock(msdp); - break; - case ejected: - /* disconnect usb device */ - usbDisconnectBus(msdp->usbp); - usbStop(msdp->usbp); - chThdExit(0); - return 0; - } - - /* wait until the ISR wakes thread */ - if(wait_for_isr) - WaitForISR(msdp); - } - - return 0; + csw->status = (msdp->result) ? MSD_COMMAND_PASSED : MSD_COMMAND_FAILED; + csw->signature = MSD_CSW_SIGNATURE; + csw->data_residue = cbw->data_len; + csw->tag = cbw->tag; + + usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)csw, sizeof(*csw)); + + chSysLock(); + usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + chSysUnlock(); + + /* wait on ISR */ + return TRUE; } -void msdInit(USBDriver *usbp, BaseBlockDevice *bbdp, USBMassStorageDriver *msdp) { - uint8_t i; - msdp->usbp = usbp; - msdp->state = idle; - msdp->bbdp = bbdp; +/** + * @brief Mass storage thread that processes commands + */ +static WORKING_AREA(mass_storage_thread_wa, 1024); +static msg_t mass_storage_thread(void *arg) { - chEvtInit(&msdp->evt_connected); - chEvtInit(&msdp->evt_ejected); + USBMassStorageDriver *msdp = (USBMassStorageDriver *)arg; - /* initialise binary semaphore as taken */ - chBSemInit(&msdp->bsem, TRUE); + chRegSetThreadName("USB-MSD"); - /* initialise sense values to zero */ - for(i = 0; i < sizeof(scsi_sense_response_t); i++) - msdp->sense.byte[i] = 0x00; + bool_t wait_for_isr = FALSE; - /* Response code = 0x70, additional sense length = 0x0A */ - msdp->sense.byte[0] = 0x70; - msdp->sense.byte[7] = 0x0A; + /* wait for the usb to be initialised */ + msd_wait_for_isr(msdp); - /* make sure block device is working and get info */ - while(TRUE) { - blkstate_t state = blkGetDriverState(bbdp); - if(state == BLK_READY) - break; + while (TRUE) { + wait_for_isr = FALSE; - chThdSleepMilliseconds(50); - } + /* wait on data depending on the current state */ + switch(msdp->state) { + case MSD_IDLE: + wait_for_isr = msd_wait_for_command_block(msdp); + break; + case MSD_READ_COMMAND_BLOCK: + wait_for_isr = msd_read_command_block(msdp); + break; + case MSD_EJECTED: + /* disconnect usb device */ + usbDisconnectBus(msdp->usbp); + usbStop(msdp->usbp); + chThdExit(0); + return 0; + } + + /* wait until the ISR wakes thread */ + if (wait_for_isr) + msd_wait_for_isr(msdp); + } + + return 0; +} + +static Thread *msd_thread = NULL; + +/** + * @brief Initialize USB mass storage on the given USB driver, using the given block device + */ +void msdInit(USBDriver *usbp, BaseBlockDevice *bbdp, USBMassStorageDriver *msdp) { + uint8_t i; + msdp->usbp = usbp; + msdp->state = MSD_IDLE; + msdp->bbdp = bbdp; + + chEvtInit(&msdp->evt_connected); + chEvtInit(&msdp->evt_ejected); + + /* initialise binary semaphore as taken */ + chBSemInit(&msdp->bsem, TRUE); + + /* initialise sense values to zero */ + for (i = 0; i < sizeof(msdp->sense.byte); i++) + msdp->sense.byte[i] = 0x00; + + /* response code = 0x70, additional sense length = 0x0A */ + msdp->sense.byte[0] = 0x70; + msdp->sense.byte[7] = 0x0A; + + /* make sure block device is working and get info */ + while (TRUE) { + blkstate_t state = blkGetDriverState(bbdp); + if(state == BLK_READY) + break; + chThdSleepMilliseconds(50); + } - blkGetInfo(bbdp, &msdp->block_dev_info); + blkGetInfo(bbdp, &msdp->block_dev_info); usbDisconnectBus(usbp); chThdSleepMilliseconds(1000); - usbp->param = (void *)msdp; + usbp->param = (void *)msdp; usbStart(usbp, &msd_usb_config); - usbConnectBus(usbp); + usbConnectBus(usbp); - if(msdThd == NULL) { - msdThd = chThdCreateStatic(waMassStorage, sizeof(waMassStorage), - NORMALPRIO, MassStorageThd, msdp); - } + if (msd_thread == NULL) + msd_thread = chThdCreateStatic(mass_storage_thread_wa, sizeof(mass_storage_thread_wa), NORMALPRIO, mass_storage_thread, msdp); } diff --git a/mass_storage/usb_msd.h b/mass_storage/usb_msd.h index 732c56d..ca3b6f0 100644 --- a/mass_storage/usb_msd.h +++ b/mass_storage/usb_msd.h @@ -1,66 +1,17 @@ +/** + * @file usb_msd.h + * @brief USB mass storage driver and functions + */ -#define USB_MS_DATA_EP 1 +#ifndef _USB_MSD_H_ +#define _USB_MSD_H_ -#define USB_MS_EP_SIZE 64 - -#define MSD_REQ_RESET 0xFF -#define MSD_GET_MAX_LUN 0xFE -#define MSD_CBW_SIGNATURE 0x43425355 -#define MSD_CSW_SIGNATURE 0x53425355 -#define MSD_COMMAND_DIR_DATA_OUT (0 << 7) -#define MSD_COMMAND_DIR_DATA_IN (1 << 7) - -#define MSD_SETUP_WORD(setup, index) (uint16_t)(((uint16_t)setup[index+1] << 8) | (setup[index] & 0x00FF)) - -#define MSD_SETUP_VALUE(setup) MSD_SETUP_WORD(setup, 2) -#define MSD_SETUP_INDEX(setup) MSD_SETUP_WORD(setup, 4) -#define MSD_SETUP_LENGTH(setup) MSD_SETUP_WORD(setup, 6) - -#define SCSI_CMD_INQUIRY 0x12 -#define SCSI_CMD_REQUEST_SENSE 0x03 -#define SCSI_CMD_READ_CAPACITY_10 0x25 -#define SCSI_CMD_READ_10 0x28 -#define SCSI_CMD_WRITE_10 0x2A -#define SCSI_CMD_TEST_UNIT_READY 0x00 -#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E -#define SCSI_CMD_VERIFY_10 0x2F -#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D -#define SCSI_CMD_MODE_SENSE_6 0x1A -#define SCSI_CMD_START_STOP_UNIT 0x1B -#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 - -#define MSD_COMMAND_PASSED 0x00 -#define MSD_COMMAND_FAILED 0x01 -#define MSD_COMMAND_PHASE_ERROR 0x02 - -#define SCSI_SENSE_KEY_GOOD 0x00 -#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 -#define SCSI_SENSE_KEY_NOT_READY 0x02 -#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03 -#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04 -#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05 -#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06 -#define SCSI_SENSE_KEY_DATA_PROTECT 0x07 -#define SCSI_SENSE_KEY_BLANK_CHECK 0x08 -#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09 -#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A -#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B -#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D -#define SCSI_SENSE_KEY_MISCOMPARE 0x0E -#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00 -#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04 -#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24 -#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28 -#define SCSI_ASENSE_WRITE_PROTECTED 0x27 -#define SCSI_ASENSE_FORMAT_ERROR 0x31 -#define SCSI_ASENSE_INVALID_COMMAND 0x20 -#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 -#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A -#define SCSI_ASENSEQ_NO_QUALIFIER 0x00 -#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01 -#define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02 -#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07 +#include "ch.h" +#include "hal.h" +/** + * @brief Command Block Wrapper structure + */ PACK_STRUCT_BEGIN typedef struct { uint32_t signature; uint32_t tag; @@ -71,6 +22,9 @@ PACK_STRUCT_BEGIN typedef struct { uint8_t scsi_cmd_data[16]; } PACK_STRUCT_STRUCT msd_cbw_t PACK_STRUCT_END; +/** + * @brief Command Status Wrapper structure + */ PACK_STRUCT_BEGIN typedef struct { uint32_t signature; uint32_t tag; @@ -78,52 +32,29 @@ PACK_STRUCT_BEGIN typedef struct { uint8_t status; } PACK_STRUCT_STRUCT msd_csw_t PACK_STRUCT_END; +/** + * @brief Structure holding sense data (status/error information) + */ PACK_STRUCT_BEGIN typedef struct { uint8_t byte[18]; -} PACK_STRUCT_STRUCT scsi_sense_response_t PACK_STRUCT_END; - -PACK_STRUCT_BEGIN typedef struct -{ - uint8_t peripheral; - uint8_t removable; - uint8_t version; - uint8_t response_data_format; - uint8_t additional_length; - uint8_t sccstp; - uint8_t bqueetc; - uint8_t cmdque; - uint8_t vendorID[8]; - uint8_t productID[16]; - uint8_t productRev[4]; -} PACK_STRUCT_STRUCT scsi_inquiry_response_t PACK_STRUCT_END; - -PACK_STRUCT_BEGIN typedef struct { - uint32_t last_block_addr; - uint32_t block_size; -} PACK_STRUCT_STRUCT SCSIReadCapacity10Response_t PACK_STRUCT_END; - -PACK_STRUCT_BEGIN typedef struct { - uint8_t op_code; - uint8_t lun_immed; - uint8_t res1; - uint8_t res2; - uint8_t loej_start; - uint8_t control; -} PACK_STRUCT_STRUCT SCSIStartStopUnitRequest_t; - -PACK_STRUCT_BEGIN typedef struct { - uint8_t reserved[3]; - uint8_t capacity_list_length; - uint32_t block_count; - uint32_t desc_and_block_length; -} PACK_STRUCT_STRUCT SCSIReadFormatCapacitiesResponse_t PACK_STRUCT_END; - -typedef struct USBMassStorageDriver USBMassStorageDriver; - -typedef enum { idle, read_cmd_block, ejected} msd_state_t; - +} PACK_STRUCT_STRUCT msd_scsi_sense_response_t PACK_STRUCT_END; + +/** + * @brief Possible states for the USB mass storage driver + */ +typedef enum { + MSD_IDLE, + MSD_READ_COMMAND_BLOCK, + MSD_EJECTED +} msd_state_t; + +/** + * @brief USB mass storage driver structure. + * @details This structure holds all the states and members of a USB mass + * storage driver. + */ struct USBMassStorageDriver { - USBDriver *usbp; + USBDriver *usbp; BinarySemaphore bsem; BaseBlockDevice *bbdp; EventSource evt_connected, evt_ejected; @@ -131,17 +62,26 @@ struct USBMassStorageDriver { msd_state_t state; msd_cbw_t cbw; msd_csw_t csw; - scsi_sense_response_t sense; + msd_scsi_sense_response_t sense; bool_t result; }; - -#define MSD_CONNECTED 0 -#define MSD_EJECTED 1 +typedef struct USBMassStorageDriver USBMassStorageDriver; #ifdef __cplusplus extern "C" { #endif + +/** + * @brief Initialize USB mass storage on the given USB driver, using the given block device. + * @details This function is sufficient to have USB mass storage running, it internally + * runs a thread that handles USB requests and transfers. + * The block device must be connected but no file system must be mounted, + * everything is handled by the host system. + */ void msdInit(USBDriver *usbp, BaseBlockDevice *bdp, USBMassStorageDriver *msdp); + #ifdef __cplusplus } #endif + +#endif /* _USB_MSD_H_ */ From c42416269629cc6557e60be8a475adfc03ab9f0c Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Fri, 19 Apr 2013 09:03:16 +0200 Subject: [PATCH 03/11] Added a configuration structure for the USBMassStorageDriver --- mass_storage/usb_msd.c | 87 ++++++++++++++++++++++-------------------- mass_storage/usb_msd.h | 27 +++++++++---- 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/mass_storage/usb_msd.c b/mass_storage/usb_msd.c index 5bbc55d..c5844dc 100644 --- a/mass_storage/usb_msd.c +++ b/mass_storage/usb_msd.c @@ -446,9 +446,9 @@ bool_t msd_scsi_process_inquiry(USBMassStorageDriver *msdp) { /* unit serial number */ case 0x80: { uint8_t response[] = {'0'}; /* TODO */ - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, response, sizeof(response)); + usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, response, sizeof(response)); chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); msdp->result = TRUE; @@ -481,11 +481,11 @@ bool_t msd_scsi_process_inquiry(USBMassStorageDriver *msdp) { {'v', CH_KERNEL_MAJOR + '0', '.', CH_KERNEL_MINOR + '0'}, }; - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&inquiry, + usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&inquiry, sizeof(msd_scsi_inquiry_response_t)); chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); msdp->result = TRUE; @@ -500,11 +500,11 @@ bool_t msd_scsi_process_inquiry(USBMassStorageDriver *msdp) { */ bool_t msd_scsi_process_request_sense(USBMassStorageDriver *msdp) { - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->sense, + usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->sense, sizeof(msdp->sense)); chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); msdp->result = TRUE; @@ -523,10 +523,10 @@ bool_t msd_scsi_process_read_capacity_10(USBMassStorageDriver *msdp) { response.block_size = swap_uint32(msdp->block_dev_info.blk_size); response.last_block_addr = swap_uint32(msdp->block_dev_info.blk_num-1); - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&response, sizeof(response)); + usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&response, sizeof(response)); chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); msdp->result = TRUE; @@ -565,7 +565,7 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { msd_cbw_t *cbw = &(msdp->cbw); - if ((cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) && blkIsWriteProtected(msdp->bbdp)) { + if ((cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) && blkIsWriteProtected(msdp->config->bbdp)) { /* device is write protected and a write has been issued */ /* block address is invalid, update SENSE key and return command fail */ msd_scsi_set_sense(msdp, @@ -598,11 +598,11 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { /* process a write command */ /* get the first packet */ - usbPrepareReceive(msdp->usbp, USB_MS_DATA_EP, rw_buf[i % 2], + usbPrepareReceive(msdp->config->usbp, USB_MS_DATA_EP, rw_buf[i % 2], msdp->block_dev_info.blk_size); chSysLock(); - usbStartReceiveI(msdp->usbp, USB_MS_DATA_EP); + usbStartReceiveI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); msd_wait_for_isr(msdp); @@ -613,16 +613,16 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { if (i < (total - 1)) { /* there is at least one block of data left to be read over USB */ /* queue this read before issuing the blocking write */ - usbPrepareReceive(msdp->usbp, USB_MS_DATA_EP, rw_buf[(i + 1) % 2], + usbPrepareReceive(msdp->config->usbp, USB_MS_DATA_EP, rw_buf[(i + 1) % 2], msdp->block_dev_info.blk_size); chSysLock(); - usbStartReceiveI(msdp->usbp, USB_MS_DATA_EP); + usbStartReceiveI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); } /* now write the block to the block device */ - if (blkWrite(msdp->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { + if (blkWrite(msdp->config->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { /* TODO: handle this */ chSysHalt(); } @@ -638,7 +638,7 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { i = 0; /* read the first block from block device */ - if (blkRead(msdp->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { + if (blkRead(msdp->config->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { /* TODO: handle this */ chSysHalt(); } @@ -646,17 +646,17 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { /* loop over each block */ for (i = 0; i < total; i++) { /* transmit the block */ - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, rw_buf[i % 2], + usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, rw_buf[i % 2], msdp->block_dev_info.blk_size); chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); if (i < (total - 1)) { /* there is at least one more block to be read from device */ /* so read that whilst the USB transfer takes place */ - if (blkRead(msdp->bbdp, rw_block_address++, rw_buf[(i + 1) % 2], 1) == CH_FAILED) { + if (blkRead(msdp->config->bbdp, rw_block_address++, rw_buf[(i + 1) % 2], 1) == CH_FAILED) { /* TODO: handle this */ chSysHalt(); } @@ -699,10 +699,10 @@ bool_t msd_scsi_process_mode_sense_6(USBMassStorageDriver *msdp) { /* TODO set byte3 to 0x80 if disk is read only */ static uint8_t response[4] = {0x00, 0x00, 0x00, 0x00}; - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, response, sizeof(response)); + usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, response, sizeof(response)); chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); msdp->result = TRUE; @@ -721,10 +721,10 @@ bool_t msd_scsi_process_read_format_capacities(USBMassStorageDriver *msdp) { response.block_count = swap_uint32(msdp->block_dev_info.blk_num); response.desc_and_block_length = swap_uint32((0x02 << 24) | (msdp->block_dev_info.blk_size & 0x00FFFFFF)); - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (const uint8_t*)&response, sizeof(response)); + usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (const uint8_t*)&response, sizeof(response)); chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); msdp->result = TRUE; @@ -738,10 +738,10 @@ bool_t msd_scsi_process_read_format_capacities(USBMassStorageDriver *msdp) { */ bool_t msd_wait_for_command_block(USBMassStorageDriver *msdp) { - usbPrepareReceive(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->cbw, sizeof(msdp->cbw)); + usbPrepareReceive(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->cbw, sizeof(msdp->cbw)); chSysLock(); - usbStartReceiveI(msdp->usbp, USB_MS_DATA_EP); + usbStartReceiveI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); msdp->state = MSD_READ_COMMAND_BLOCK; @@ -769,7 +769,7 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { /* stall both IN and OUT endpoints */ chSysLock(); - usbStallReceiveI(msdp->usbp, USB_MS_DATA_EP); + usbStallReceiveI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); /* don't wait for ISR */ @@ -821,7 +821,7 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { /* stall IN endpoint */ chSysLock(); - usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); + usbStallTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); cbw->data_len = 0; @@ -839,7 +839,7 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { } else { /* stall IN endpoint */ chSysLock(); - usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); + usbStallTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); cbw->data_len = 0; @@ -854,8 +854,8 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { if (!msdp->result && cbw->data_len) { /* still bytes left to send, this is too early to send CSW? */ chSysLock(); - usbStallReceiveI(msdp->usbp, USB_MS_DATA_EP); - usbStallTransmitI(msdp->usbp, USB_MS_DATA_EP); + usbStallReceiveI(msdp->config->usbp, USB_MS_DATA_EP); + usbStallTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); return FALSE; @@ -866,10 +866,10 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { csw->data_residue = cbw->data_len; csw->tag = cbw->tag; - usbPrepareTransmit(msdp->usbp, USB_MS_DATA_EP, (uint8_t *)csw, sizeof(*csw)); + usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)csw, sizeof(*csw)); chSysLock(); - usbStartTransmitI(msdp->usbp, USB_MS_DATA_EP); + usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); /* wait on ISR */ @@ -904,8 +904,8 @@ static msg_t mass_storage_thread(void *arg) { break; case MSD_EJECTED: /* disconnect usb device */ - usbDisconnectBus(msdp->usbp); - usbStop(msdp->usbp); + usbDisconnectBus(msdp->config->usbp); + usbStop(msdp->config->usbp); chThdExit(0); return 0; } @@ -923,11 +923,14 @@ static Thread *msd_thread = NULL; /** * @brief Initialize USB mass storage on the given USB driver, using the given block device */ -void msdInit(USBDriver *usbp, BaseBlockDevice *bbdp, USBMassStorageDriver *msdp) { +void msdInit(USBMassStorageDriver *msdp, const USBMassStorageConfig *config) { + + chDbgCheck(msdp != NULL, "msdInit"); + chDbgCheck(config != NULL, "msdInit"); + uint8_t i; - msdp->usbp = usbp; + msdp->config = config; msdp->state = MSD_IDLE; - msdp->bbdp = bbdp; chEvtInit(&msdp->evt_connected); chEvtInit(&msdp->evt_ejected); @@ -945,20 +948,20 @@ void msdInit(USBDriver *usbp, BaseBlockDevice *bbdp, USBMassStorageDriver *msdp) /* make sure block device is working and get info */ while (TRUE) { - blkstate_t state = blkGetDriverState(bbdp); + blkstate_t state = blkGetDriverState(config->bbdp); if(state == BLK_READY) break; chThdSleepMilliseconds(50); } - blkGetInfo(bbdp, &msdp->block_dev_info); + blkGetInfo(config->bbdp, &msdp->block_dev_info); - usbDisconnectBus(usbp); + usbDisconnectBus(config->usbp); chThdSleepMilliseconds(1000); - usbp->param = (void *)msdp; + config->usbp->param = (void *)msdp; - usbStart(usbp, &msd_usb_config); - usbConnectBus(usbp); + usbStart(config->usbp, &msd_usb_config); + usbConnectBus(config->usbp); if (msd_thread == NULL) msd_thread = chThdCreateStatic(mass_storage_thread_wa, sizeof(mass_storage_thread_wa), NORMALPRIO, mass_storage_thread, msdp); diff --git a/mass_storage/usb_msd.h b/mass_storage/usb_msd.h index ca3b6f0..1d6e75d 100644 --- a/mass_storage/usb_msd.h +++ b/mass_storage/usb_msd.h @@ -48,15 +48,29 @@ typedef enum { MSD_EJECTED } msd_state_t; +/** + * @brief Driver configuration structure + */ +typedef struct { + /** + * @brief USB driver to use for communication + */ + USBDriver *usbp; + + /** + * @brief Block device to use for storage + */ + BaseBlockDevice *bbdp; +} USBMassStorageConfig; + /** * @brief USB mass storage driver structure. * @details This structure holds all the states and members of a USB mass * storage driver. */ -struct USBMassStorageDriver { - USBDriver *usbp; +typedef struct { + const USBMassStorageConfig* config; BinarySemaphore bsem; - BaseBlockDevice *bbdp; EventSource evt_connected, evt_ejected; BlockDeviceInfo block_dev_info; msd_state_t state; @@ -64,21 +78,20 @@ struct USBMassStorageDriver { msd_csw_t csw; msd_scsi_sense_response_t sense; bool_t result; -}; -typedef struct USBMassStorageDriver USBMassStorageDriver; +} USBMassStorageDriver; #ifdef __cplusplus extern "C" { #endif /** - * @brief Initialize USB mass storage on the given USB driver, using the given block device. + * @brief Initialize USB mass storage with the given configuration. * @details This function is sufficient to have USB mass storage running, it internally * runs a thread that handles USB requests and transfers. * The block device must be connected but no file system must be mounted, * everything is handled by the host system. */ -void msdInit(USBDriver *usbp, BaseBlockDevice *bdp, USBMassStorageDriver *msdp); +void msdInit(USBMassStorageDriver *msdp, const USBMassStorageConfig *config); #ifdef __cplusplus } From 0113ff681a74b1c12d8566af7629c5b863ff6163 Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Fri, 19 Apr 2013 09:12:01 +0200 Subject: [PATCH 04/11] Replaced the RW_LED_ON/OFF macros with a callback that can be defined in the config structure --- mass_storage/usb_msd.c | 16 ++++------------ mass_storage/usb_msd.h | 8 ++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mass_storage/usb_msd.c b/mass_storage/usb_msd.c index c5844dc..d82a15f 100644 --- a/mass_storage/usb_msd.c +++ b/mass_storage/usb_msd.c @@ -121,16 +121,6 @@ static uint8_t rw_buf[2][512]; #define swap_uint16(x) ((((x) & 0x00FF) << 8) \ | (((x) & 0xFF00) >> 8)) -/** - * @brief Macros that can be overriden to do something when read/write transfers are active - */ -#if !defined(MSD_RW_LED_ON) - #define MSD_RW_LED_ON() -#endif -#if !defined(MSD_RW_LED_OFF) - #define MSD_RW_LED_OFF() -#endif - /** * @brief USB Device Descriptor */ @@ -791,9 +781,11 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { break; case SCSI_CMD_READ_10: case SCSI_CMD_WRITE_10: - MSD_RW_LED_ON(); + if (msdp->config->rw_activity_callback) + msdp->config->rw_activity_callback(TRUE); sleep = msd_scsi_process_start_read_write_10(msdp); - MSD_RW_LED_OFF(); + if (msdp->config->rw_activity_callback) + msdp->config->rw_activity_callback(FALSE); break; case SCSI_CMD_SEND_DIAGNOSTIC: sleep = msd_scsi_process_send_diagnostic(msdp); diff --git a/mass_storage/usb_msd.h b/mass_storage/usb_msd.h index 1d6e75d..f57d263 100644 --- a/mass_storage/usb_msd.h +++ b/mass_storage/usb_msd.h @@ -61,6 +61,14 @@ typedef struct { * @brief Block device to use for storage */ BaseBlockDevice *bbdp; + + /** + * @brief Optional callback that will be called whenever there is + * read/write activity + * @note The callback is called with argument TRUE when activity starts, + * and FALSE when activity stops. + */ + void (*rw_activity_callback)(bool_t); } USBMassStorageConfig; /** From c01e4c38edecb9875bb833f48be81dc039cf34af Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Fri, 19 Apr 2013 11:06:30 +0200 Subject: [PATCH 05/11] USB vendor & product ID/string and serial number string are now customizable in the configuration structure --- mass_storage/usb_msd.c | 119 ++++++++++++++++------------------------- mass_storage/usb_msd.h | 75 ++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 74 deletions(-) diff --git a/mass_storage/usb_msd.c b/mass_storage/usb_msd.c index d82a15f..65f1ccf 100644 --- a/mass_storage/usb_msd.c +++ b/mass_storage/usb_msd.c @@ -121,32 +121,6 @@ static uint8_t rw_buf[2][512]; #define swap_uint16(x) ((((x) & 0x00FF) << 8) \ | (((x) & 0xFF00) >> 8)) -/** - * @brief USB Device Descriptor - */ -static const uint8_t msd_device_descriptor_data[18] = { - USB_DESC_DEVICE(0x0200, /* bcdUSB (2.0). */ - 0x00, /* bDeviceClass (None). */ - 0x00, /* bDeviceSubClass. */ - 0x00, /* bDeviceProtocol. */ - 0x40, /* Control Endpoint Size. */ - 0x0483, /* idVendor (ST). */ - 0x5742, /* idProduct. */ - 0x0100, /* bcdDevice. */ - 1, /* iManufacturer. */ - 2, /* iProduct. */ - 3, /* iSerialNumber. */ - 1) /* bNumConfigurations. */ -}; - -/** - * @brief Device Descriptor wrapper - */ -static const USBDescriptor msd_device_descriptor = { - sizeof msd_device_descriptor_data, - msd_device_descriptor_data -}; - /** * @brief Configuration Descriptor tree for a CDC */ @@ -164,11 +138,11 @@ static const uint8_t msd_configuration_descriptor_data[] = { 0x02, /* bNumEndpoints. */ 0x08, /* bInterfaceClass (Mass Storage) */ 0x06, /* bInterfaceSubClass (SCSI - Transparent storage class) */ + Transparent storage class) */ 0x50, /* bInterfaceProtocol (Bulk Only) */ 0), /* iInterface. (none) */ /* Mass Storage Data In Endpoint Descriptor.*/ - USB_DESC_ENDPOINT (USB_MS_DATA_EP|0x80, + USB_DESC_ENDPOINT (USB_MS_DATA_EP | 0x80, 0x02, /* bmAttributes (Bulk). */ USB_MS_EP_SIZE,/* wMaxPacketSize. */ 0x05), /* bInterval. 1ms */ @@ -179,67 +153,51 @@ static const uint8_t msd_configuration_descriptor_data[] = { 0x05) /* bInterval. 1ms */ }; -/** - * @brief Configuration Descriptor wrapper - */ static const USBDescriptor msd_configuration_descriptor = { sizeof msd_configuration_descriptor_data, msd_configuration_descriptor_data }; /** - * @brief U.S. English language identifier + * @brief Default USB Device Descriptor */ -static const uint8_t msd_string0[] = { - USB_DESC_BYTE(4), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */ -}; +MSD_DECLARE_DEVICE_DESCRIPTOR(msd_device_descriptor, 0x0483, 0x5742); /** - * @brief Vendor string + * @brief U.S. English language identifier descriptor */ -static const uint8_t msd_string1[] = { - USB_DESC_BYTE(38), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, - 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, - 'c', 0, 's', 0 -}; +#define MSD_LANGUAGE_STRING \ + USB_DESC_WORD(0x0409) +MSD_DECLARE_STRING_DESCRIPTOR(msd_language_descriptor, 2, MSD_LANGUAGE_STRING); /** - * @brief Device Description string + * @brief Default vendor descriptor */ -static const uint8_t msd_string2[] = { - USB_DESC_BYTE(62), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, - 'R', 0, 'T', 0, ' ', 0, 'M', 0, 'a', 0, 's', 0, 's', 0, ' ', 0, - 'S', 0, 't', 0, 'o', 0, 'r', 0, 'a', 0, 'g', 0, 'e', 0, ' ', 0, - 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0 -}; +#define MSD_DEFAULT_VENDOR_STRING \ + 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, \ + 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, \ + 'c', 0, 's', 0 +MSD_DECLARE_STRING_DESCRIPTOR(msd_vendor_descriptor, 36, MSD_DEFAULT_VENDOR_STRING); /** - * @brief Device Serial Number string + * @brief Default product descriptor */ -static const uint8_t msd_string3[] = { - USB_DESC_BYTE(26), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - 'A', 0, 'E', 0, 'C', 0, 'C', 0, 'E', 0, 'C', 0, 'C', 0, 'C', 0, 'C', 0, - '0' + CH_KERNEL_MAJOR, 0, - '0' + CH_KERNEL_MINOR, 0, - '0' + CH_KERNEL_PATCH, 0 -}; +#define MSD_DEFAULT_PRODUCT_STRING \ + 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, \ + 'R', 0, 'T', 0, ' ', 0, 'M', 0, 'a', 0, 's', 0, 's', 0, ' ', 0, \ + 'S', 0, 't', 0, 'o', 0, 'r', 0, 'a', 0, 'g', 0, 'e', 0, ' ', 0, \ + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0 +MSD_DECLARE_STRING_DESCRIPTOR(msd_product_descriptor, 60, MSD_DEFAULT_PRODUCT_STRING); /** - * @brief Strings wrappers array + * @brief Default serial number descriptor */ -static const USBDescriptor msd_strings[] = { - {sizeof msd_string0, msd_string0}, - {sizeof msd_string1, msd_string1}, - {sizeof msd_string2, msd_string2}, - {sizeof msd_string3, msd_string3} -}; +#define MSD_DEFAULT_SERIAL_NUMBER_STRING \ + 'A', 0, 'E', 0, 'C', 0, 'C', 0, 'E', 0, 'C', 0, 'C', 0, 'C', 0, 'C', 0, \ + '0' + CH_KERNEL_MAJOR, 0, \ + '0' + CH_KERNEL_MINOR, 0, \ + '0' + CH_KERNEL_PATCH, 0 +MSD_DECLARE_STRING_DESCRIPTOR(msd_serial_number_descriptor, 24, MSD_DEFAULT_SERIAL_NUMBER_STRING); /** * @brief Handles the GET_DESCRIPTOR callback. @@ -250,17 +208,30 @@ static const USBDescriptor *msd_get_descriptor(USBDriver *usbp, uint8_t dindex, uint16_t lang) { - (void)usbp; + USBMassStorageDriver *msdp = (USBMassStorageDriver *)usbp->param; + (void)lang; switch (dtype) { case USB_DESCRIPTOR_DEVICE: - return &msd_device_descriptor; + return msdp->config->device_descriptor ? msdp->config->device_descriptor : + &msd_device_descriptor; case USB_DESCRIPTOR_CONFIGURATION: return &msd_configuration_descriptor; case USB_DESCRIPTOR_STRING: - if (dindex < 4) - return &msd_strings[dindex]; + switch (dindex) { + case 0: + return &msd_language_descriptor; + case 1: + return msdp->config->vendor_descriptor ? msdp->config->vendor_descriptor : + &msd_vendor_descriptor; + case 2: + return msdp->config->product_descriptor ? msdp->config->product_descriptor : + &msd_product_descriptor; + case 3: + return msdp->config->serial_number_descriptor ? msdp->config->serial_number_descriptor : + &msd_serial_number_descriptor; + } } return NULL; } diff --git a/mass_storage/usb_msd.h b/mass_storage/usb_msd.h index f57d263..f213851 100644 --- a/mass_storage/usb_msd.h +++ b/mass_storage/usb_msd.h @@ -48,6 +48,51 @@ typedef enum { MSD_EJECTED } msd_state_t; +/** + * @brief Declares a valid USBDecriptor instance from device properties + */ +#define MSD_DECLARE_DEVICE_DESCRIPTOR(name, vendor_id, product_id) \ + static const uint8_t name##_data_[] = { \ + USB_DESC_DEVICE(0x0200, /* bcdUSB (2.0). */ \ + 0x00, /* bDeviceClass (None). */ \ + 0x00, /* bDeviceSubClass. */ \ + 0x00, /* bDeviceProtocol. */ \ + 0x40, /* Control Endpoint Size. */ \ + vendor_id, /* idVendor (ST). */ \ + product_id, /* idProduct. */ \ + 0x0100, /* bcdDevice. */ \ + 1, /* iManufacturer. */ \ + 2, /* iProduct. */ \ + 3, /* iSerialNumber. */ \ + 1) /* bNumConfigurations. */ \ + }; \ + static const USBDescriptor name = { \ + sizeof name##_data_, \ + name##_data_ \ + } + +/** + * @brief Declares a valid USBDecriptor instance from a string + * @note The string will be used as a Unicode string, therefore each character + * must be followed by a 0. The length argument must include these zeroes. + * Since the string is a variable-length list of character literals, + * it cannot be passed directly to the macro, it must be first defined + * as a macro itself. + * Example: + * #define VENDOR_STRING 'm', 0, 'y', 0, 'c', 0, 'o', 0, 'm', 0, 'p', 0 + * MSD_DECLARE_DESCRIPTOR(mycomp_descriptor, 12, VENDOR_STRING); + */ +#define MSD_DECLARE_STRING_DESCRIPTOR(name, length, string) \ + static const uint8_t name##_data_[] = { \ + USB_DESC_BYTE(length + 2), \ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), \ + string \ + }; \ + static const USBDescriptor name = { \ + sizeof name##_data_, \ + name##_data_ \ + } + /** * @brief Driver configuration structure */ @@ -69,6 +114,36 @@ typedef struct { * and FALSE when activity stops. */ void (*rw_activity_callback)(bool_t); + + /** + * @brief Device description + * @note To define such a valid USBDescriptor, see the MSD_DECLARE_DEVICE_DESCRIPTOR macro. + * If null, a default device description is used. + */ + const USBDescriptor* device_descriptor; + + /** + * @brief Vendor description + * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. + * If null, a default vendor description is used. + */ + const USBDescriptor* vendor_descriptor; + + /** + * @brief Product description + * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. + * If null, a default product description is used. + */ + const USBDescriptor* product_descriptor; + + /** + * @brief Serial number description + * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. + * If null, a default serial number description is used. + * This description string must contain at least 12 valid digits. + */ + const USBDescriptor* serial_number_descriptor; + } USBMassStorageConfig; /** From baa8e93ed23b3f5b0dcca653dee8bd651dbe06a0 Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Fri, 19 Apr 2013 11:20:16 +0200 Subject: [PATCH 06/11] Updated the demo --- demos/mass_storage_OLIMEX_STM32E407/main.c | 96 +++++++++++++------ demos/mass_storage_OLIMEX_STM32E407/readme.md | 2 - 2 files changed, 69 insertions(+), 29 deletions(-) diff --git a/demos/mass_storage_OLIMEX_STM32E407/main.c b/demos/mass_storage_OLIMEX_STM32E407/main.c index 028b7ef..e4b8b73 100644 --- a/demos/mass_storage_OLIMEX_STM32E407/main.c +++ b/demos/mass_storage_OLIMEX_STM32E407/main.c @@ -1,40 +1,82 @@ +#include "usb_msd.h" +#include "ch.h" +#include "hal.h" #include #include -#include "ch.h" -#include "hal.h" +/* USB identifiers and strings that we'll send to the host */ +MSD_DECLARE_DEVICE_DESCRIPTOR(usbDeviceDescriptor, 0x0483, 0x5742); -#include "usb_msd.h" +#define USB_VENDOR_STRING \ + 'D', 0, 'e', 0, 'm', 0, 'o', 0, 'V', 0, 'e', 0, 'n', 0, 'd', 0, 'o', 0, 'r', 0 +MSD_DECLARE_STRING_DESCRIPTOR(usbVendorDescriptor, 20, USB_VENDOR_STRING); -/* - * Green LED blinker thread, times are in milliseconds. - */ -static WORKING_AREA(waThread1, 128); -static msg_t Thread1(void *arg) { - - (void)arg; - chRegSetThreadName("blinker"); - while (TRUE) { - palTogglePad(GPIOC, GPIOC_LED); - chThdSleepMilliseconds(500); - } +#define USB_PRODUCT_STRING \ + 'D', 0, 'e', 0, 'm', 0, 'o', 0, 'P', 0, 'r', 0, 'o', 0, 'd', 0, 'u', 0, 'c', 0, 't', 0 +MSD_DECLARE_STRING_DESCRIPTOR(usbProductDescriptor, 22, USB_PRODUCT_STRING); + +#define USB_SERIAL_NUMBER_STRING \ + '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '1', 0 +MSD_DECLARE_STRING_DESCRIPTOR(usbSerialNumberDescriptor, 24, USB_SERIAL_NUMBER_STRING); + +/* Turns on a LED when there is I/O activity on the USB port */ +static void usbActivity(bool_t on) +{ + if (on) + palSetPad(GPIOC, GPIOC_LED); + else + palClearPad(GPIOC, GPIOC_LED); } -int main(void) { - halInit(); - chSysInit(); +/* USB mass storage configuration */ +static USBMassStorageConfig msdConfig = +{ + &USBD2, + (BaseBlockDevice*)&SDCD1, + usbActivity, + &usbDeviceDescriptor, + &usbVendorDescriptor, + &usbProductDescriptor, + &usbSerialNumberDescriptor +}; + +/* USB mass storage driver */ +USBMassStorageDriver UMSD1; + +int main(void) +{ + /* system & hardware initialization */ + halInit(); + chSysInit(); + + /* initialize the SD card */ + sdcStart(&SDCD1, NULL); + sdcConnect(&SDCD1); - sdcStart(&SDCD1, NULL); - sdcConnect(&SDCD1); + /* turn off the test LED */ + palClearPad(GPIOC, GPIOC_LED); - //palSetPad(GPIOC, GPIOC_LED); + /* run the USB mass storage service */ + msdInit(&UMSD1, &msdConfig); - USBMassStorageDriver UMSD1; - msdInit(&USBD1, &SDCD1, &UMSD1); + /* watch the mass storage events */ + EventListener connected; + EventListener ejected; + chEvtRegisterMask(&UMSD1.evt_connected, &connected, EVENT_MASK(1)); + chEvtRegisterMask(&UMSD1.evt_ejected, &ejected, EVENT_MASK(2)); - chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); + while (TRUE) + { + eventmask_t event = chEvtWaitOne(EVENT_MASK(1) | EVENT_MASK(2)); + if (event == EVENT_MASK(1)) + { + /* media connected */ + } + else if (event == EVENT_MASK(2)) + { + /* media ejected */ + } + } - while (TRUE) { - chThdSleepMilliseconds(1000); - } + return 0; } diff --git a/demos/mass_storage_OLIMEX_STM32E407/readme.md b/demos/mass_storage_OLIMEX_STM32E407/readme.md index 2cdb823..4e5e8da 100644 --- a/demos/mass_storage_OLIMEX_STM32E407/readme.md +++ b/demos/mass_storage_OLIMEX_STM32E407/readme.md @@ -1,5 +1,3 @@ Mass Storage Demo for Olimex STM32E407 Uses SDC card + HS USB - -Note: not yet functional \ No newline at end of file From 85af2f218bbfc1606b7751c79cf9e37c66907dac Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Mon, 22 Apr 2013 10:23:15 +0200 Subject: [PATCH 07/11] Made the inquiry response (short vendor ID, short product ID and product revision) customizable in the config structure --- mass_storage/usb_msd.c | 59 +++++++------------ mass_storage/usb_msd.h | 129 ++++++++++++++++++++++++++--------------- 2 files changed, 103 insertions(+), 85 deletions(-) diff --git a/mass_storage/usb_msd.c b/mass_storage/usb_msd.c index 65f1ccf..6762dd3 100644 --- a/mass_storage/usb_msd.c +++ b/mass_storage/usb_msd.c @@ -66,24 +66,6 @@ #define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02 #define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07 -/** - * @brief Response to a regular INQUIRY SCSI command - */ -PACK_STRUCT_BEGIN typedef struct -{ - uint8_t peripheral; - uint8_t removable; - uint8_t version; - uint8_t response_data_format; - uint8_t additional_length; - uint8_t sccstp; - uint8_t bqueetc; - uint8_t cmdque; - uint8_t vendorID[8]; - uint8_t productID[16]; - uint8_t productRev[4]; -} PACK_STRUCT_STRUCT msd_scsi_inquiry_response_t PACK_STRUCT_END; - /** * @brief Response to a READ_CAPACITY_10 SCSI command */ @@ -428,22 +410,7 @@ bool_t msd_scsi_process_inquiry(USBMassStorageDriver *msdp) { } else { - static const msd_scsi_inquiry_response_t inquiry = { - 0x00, /* direct access block device */ - 0x80, /* removable */ - 0x04, /* SPC-2 */ - 0x02, /* response data format */ - 0x20, /* response has 0x20 + 4 bytes */ - 0x00, - 0x00, - 0x00, - "Chibios", - "Mass Storage", - {'v', CH_KERNEL_MAJOR + '0', '.', CH_KERNEL_MINOR + '0'}, - }; - - usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&inquiry, - sizeof(msd_scsi_inquiry_response_t)); + usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->inquiry, sizeof(msdp->inquiry)); chSysLock(); usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); @@ -901,13 +868,27 @@ void msdInit(USBMassStorageDriver *msdp, const USBMassStorageConfig *config) { /* initialise binary semaphore as taken */ chBSemInit(&msdp->bsem, TRUE); - /* initialise sense values to zero */ + /* initialise the sense data structure */ for (i = 0; i < sizeof(msdp->sense.byte); i++) msdp->sense.byte[i] = 0x00; - - /* response code = 0x70, additional sense length = 0x0A */ - msdp->sense.byte[0] = 0x70; - msdp->sense.byte[7] = 0x0A; + msdp->sense.byte[0] = 0x70; /* response code */ + msdp->sense.byte[7] = 0x0A; /* additional sense length */ + + /* initialize the inquiry data structure */ + msdp->inquiry.peripheral = 0x00; /* direct access block device */ + msdp->inquiry.removable = 0x80; /* removable */ + msdp->inquiry.version = 0x04; /* SPC-2 */ + msdp->inquiry.response_data_format = 0x02; /* response data format */ + msdp->inquiry.additional_length = 0x20; /* response has 0x20 + 4 bytes */ + msdp->inquiry.sccstp = 0x00; + msdp->inquiry.bqueetc = 0x00; + msdp->inquiry.cmdque = 0x00; + for (i = 0; i < sizeof(msdp->config->short_vendor_id); ++i) + msdp->inquiry.vendor_id[i] = config->short_vendor_id[i]; + for (i = 0; i < sizeof(msdp->config->short_product_id); ++i) + msdp->inquiry.product_id[i] = config->short_product_id[i]; + for (i = 0; i < sizeof(msdp->config->short_product_version); ++i) + msdp->inquiry.product_rev[i] = config->short_product_version[i]; /* make sure block device is working and get info */ while (TRUE) { diff --git a/mass_storage/usb_msd.h b/mass_storage/usb_msd.h index f213851..5433cfd 100644 --- a/mass_storage/usb_msd.h +++ b/mass_storage/usb_msd.h @@ -39,6 +39,24 @@ PACK_STRUCT_BEGIN typedef struct { uint8_t byte[18]; } PACK_STRUCT_STRUCT msd_scsi_sense_response_t PACK_STRUCT_END; +/** + * @brief structure holding the data to reply to an INQUIRY SCSI command + */ +PACK_STRUCT_BEGIN typedef struct +{ + uint8_t peripheral; + uint8_t removable; + uint8_t version; + uint8_t response_data_format; + uint8_t additional_length; + uint8_t sccstp; + uint8_t bqueetc; + uint8_t cmdque; + uint8_t vendor_id[8]; + uint8_t product_id[16]; + uint8_t product_rev[4]; +} PACK_STRUCT_STRUCT msd_scsi_inquiry_response_t PACK_STRUCT_END; + /** * @brief Possible states for the USB mass storage driver */ @@ -97,52 +115,70 @@ typedef enum { * @brief Driver configuration structure */ typedef struct { - /** - * @brief USB driver to use for communication - */ - USBDriver *usbp; - - /** - * @brief Block device to use for storage - */ - BaseBlockDevice *bbdp; - - /** - * @brief Optional callback that will be called whenever there is - * read/write activity - * @note The callback is called with argument TRUE when activity starts, - * and FALSE when activity stops. - */ - void (*rw_activity_callback)(bool_t); - - /** - * @brief Device description - * @note To define such a valid USBDescriptor, see the MSD_DECLARE_DEVICE_DESCRIPTOR macro. - * If null, a default device description is used. - */ - const USBDescriptor* device_descriptor; - - /** - * @brief Vendor description - * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. - * If null, a default vendor description is used. - */ - const USBDescriptor* vendor_descriptor; - - /** - * @brief Product description - * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. - * If null, a default product description is used. - */ - const USBDescriptor* product_descriptor; - - /** - * @brief Serial number description - * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. - * If null, a default serial number description is used. - * This description string must contain at least 12 valid digits. - */ - const USBDescriptor* serial_number_descriptor; + /** + * @brief USB driver to use for communication + */ + USBDriver *usbp; + + /** + * @brief Block device to use for storage + */ + BaseBlockDevice *bbdp; + + /** + * @brief Optional callback that will be called whenever there is + * read/write activity + * @note The callback is called with argument TRUE when activity starts, + * and FALSE when activity stops. + */ + void (*rw_activity_callback)(bool_t); + + /** + * @brief Device description + * @note To define such a valid USBDescriptor, see the MSD_DECLARE_DEVICE_DESCRIPTOR macro. + * If null, a default device description is used. + */ + const USBDescriptor* device_descriptor; + + /** + * @brief Vendor description + * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. + * If null, a default vendor description is used. + */ + const USBDescriptor* vendor_descriptor; + + /** + * @brief Product description + * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. + * If null, a default product description is used. + */ + const USBDescriptor* product_descriptor; + + /** + * @brief Serial number description + * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. + * If null, a default serial number description is used. + * This description string must contain at least 12 valid digits. + */ + const USBDescriptor* serial_number_descriptor; + + /** + * @brief Short vendor identification + * @note ASCII characters only, maximum 8 characters (pad with zeroes). + */ + uint8_t short_vendor_id[8]; + + /** + * @brief Short product identification + * @note ASCII characters only, maximum 16 characters (pad with zeroes). + */ + uint8_t short_product_id[16]; + + /** + * @brief Short product revision + * @note ASCII characters only, maximum 4 characters (pad with zeroes). + */ + uint8_t short_product_version[4]; } USBMassStorageConfig; @@ -160,6 +196,7 @@ typedef struct { msd_cbw_t cbw; msd_csw_t csw; msd_scsi_sense_response_t sense; + msd_scsi_inquiry_response_t inquiry; bool_t result; } USBMassStorageDriver; From fb1d298adc5bfcf55bfafcc8314c4b520dfa11fd Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Fri, 26 Apr 2013 08:47:32 +0200 Subject: [PATCH 08/11] Better handling of error cases, and made the API less self-contained (so that it can be used in a composite USB device, for example) --- demos/mass_storage_OLIMEX_STM32E407/main.c | 211 ++++++++++- mass_storage/usb_msd.c | 401 +++++++++------------ mass_storage/usb_msd.h | 115 +++--- 3 files changed, 408 insertions(+), 319 deletions(-) diff --git a/demos/mass_storage_OLIMEX_STM32E407/main.c b/demos/mass_storage_OLIMEX_STM32E407/main.c index e4b8b73..73902af 100644 --- a/demos/mass_storage_OLIMEX_STM32E407/main.c +++ b/demos/mass_storage_OLIMEX_STM32E407/main.c @@ -4,25 +4,194 @@ #include #include -/* USB identifiers and strings that we'll send to the host */ -MSD_DECLARE_DEVICE_DESCRIPTOR(usbDeviceDescriptor, 0x0483, 0x5742); +/* USB device descriptor */ +static const uint8_t deviceDescriptorData[] = +{ + USB_DESC_DEVICE + ( + 0x0200, /* supported USB version (2.0) */ + 0x00, /* device class (none, specified in interface) */ + 0x00, /* device sub-class (none, specified in interface) */ + 0x00, /* device protocol (none, specified in interface) */ + 64, /* max packet size of control end-point */ + 0x0483, /* vendor ID (STMicroelectronics!) */ + 0x5740, /* product ID (STM32F407) */ + 0x0100, /* device release number */ + 1, /* index of manufacturer string descriptor */ + 2, /* index of product string descriptor */ + 3, /* index of serial number string descriptor */ + 1 /* number of possible configurations */ + ) +}; +static const USBDescriptor deviceDescriptor = +{ + sizeof(deviceDescriptorData), + deviceDescriptorData +}; + +/* configuration descriptor */ +static const uint8_t configurationDescriptorData[] = +{ + /* configuration descriptor */ + USB_DESC_CONFIGURATION + ( + 32, /* total length */ + 1, /* number of interfaces */ + 1, /* value that selects this configuration */ + 0, /* index of string descriptor describing this configuration */ + 0xC0, /* attributes (self-powered) */ + 50 /* max power (100 mA) */ + ), + + /* interface descriptor */ + USB_DESC_INTERFACE + ( + 0, /* interface number */ + 0, /* value used to select alternative setting */ + 2, /* number of end-points used by this interface */ + 0x08, /* interface class (Mass Storage) */ + 0x06, /* interface sub-class (SCSI Transparent Storage) */ + 0x50, /* interface protocol (Bulk Only) */ + 0 /* index of string descriptor describing this interface */ + ), -#define USB_VENDOR_STRING \ + /* end-point descriptor */ + USB_DESC_ENDPOINT + ( + USB_MS_DATA_EP | 0x80, /* address (end point index | OUT direction) */ + USB_EP_MODE_TYPE_BULK, /* attributes (bulk) */ + 64, /* max packet size */ + 0x05 /* polling interval (ignored for bulk end-points) */ + ), + + /* end-point descriptor */ + USB_DESC_ENDPOINT + ( + USB_MS_DATA_EP | 0x00, /* address (end point index | IN direction) */ + USB_EP_MODE_TYPE_BULK, /* attributes (bulk) */ + 64, /* max packet size */ + 0x05 /* polling interval (ignored for bulk end-points) */ + ) +}; +static const USBDescriptor configurationDescriptor = +{ + sizeof(configurationDescriptorData), + configurationDescriptorData +}; + +/* Language descriptor */ +static const uint8_t languageDescriptorData[] = +{ + USB_DESC_BYTE(4), + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), + USB_DESC_WORD(0x0409) /* U.S. english */ +}; +static const USBDescriptor languageDescriptor = +{ + sizeof(languageDescriptorData), + languageDescriptorData +}; + +/* Vendor descriptor */ +static const uint8_t vendorDescriptorData[] = +{ + USB_DESC_BYTE(22), + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), 'D', 0, 'e', 0, 'm', 0, 'o', 0, 'V', 0, 'e', 0, 'n', 0, 'd', 0, 'o', 0, 'r', 0 -MSD_DECLARE_STRING_DESCRIPTOR(usbVendorDescriptor, 20, USB_VENDOR_STRING); +}; +static const USBDescriptor vendorDescriptor = +{ + sizeof(vendorDescriptorData), + vendorDescriptorData +}; -#define USB_PRODUCT_STRING \ +/* Product descriptor */ +static const uint8_t productDescriptorData[] = +{ + USB_DESC_BYTE(24), + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), 'D', 0, 'e', 0, 'm', 0, 'o', 0, 'P', 0, 'r', 0, 'o', 0, 'd', 0, 'u', 0, 'c', 0, 't', 0 -MSD_DECLARE_STRING_DESCRIPTOR(usbProductDescriptor, 22, USB_PRODUCT_STRING); +}; +static const USBDescriptor productDescriptor = +{ + sizeof(productDescriptorData), + productDescriptorData +}; -#define USB_SERIAL_NUMBER_STRING \ +/* Serial number descriptor */ +static const uint8_t serialNumberDescriptorData[] = +{ + USB_DESC_BYTE(26), + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '1', 0 -MSD_DECLARE_STRING_DESCRIPTOR(usbSerialNumberDescriptor, 24, USB_SERIAL_NUMBER_STRING); +}; +static const USBDescriptor serialNumberDescriptor = +{ + sizeof(serialNumberDescriptorData), + serialNumberDescriptorData +}; + +/* Handles GET_DESCRIPTOR requests from the USB host */ +static const USBDescriptor* getDescriptor(USBDriver* usbp, uint8_t type, uint8_t index, uint16_t lang) +{ + (void)usbp; + (void)lang; + + switch (type) + { + case USB_DESCRIPTOR_DEVICE: + return &deviceDescriptor; + + case USB_DESCRIPTOR_CONFIGURATION: + return &configurationDescriptor; + + case USB_DESCRIPTOR_STRING: + switch (index) + { + case 0: return &languageDescriptor; + case 1: return &vendorDescriptor; + case 2: return &productDescriptor; + case 3: return &serialNumberDescriptor; + } + } + + return 0; +} + +/* Handles global events of the USB driver */ +static void usbEvent(USBDriver* usbp, usbevent_t event) +{ + switch (event) + { + case USB_EVENT_CONFIGURED: + chSysLockFromIsr(); + msdConfigureHookI(usbp); + chSysUnlockFromIsr(); + break; + + case USB_EVENT_RESET: + case USB_EVENT_ADDRESS: + case USB_EVENT_SUSPEND: + case USB_EVENT_WAKEUP: + case USB_EVENT_STALLED: + default: + break; + } +} + +/* Configuration of the USB driver */ +const USBConfig usbConfig = +{ + usbEvent, + getDescriptor, + msdRequestsHook, + 0 +}; /* Turns on a LED when there is I/O activity on the USB port */ -static void usbActivity(bool_t on) +static void usbActivity(bool_t active) { - if (on) + if (active) palSetPad(GPIOC, GPIOC_LED); else palClearPad(GPIOC, GPIOC_LED); @@ -33,11 +202,10 @@ static USBMassStorageConfig msdConfig = { &USBD2, (BaseBlockDevice*)&SDCD1, - usbActivity, - &usbDeviceDescriptor, - &usbVendorDescriptor, - &usbProductDescriptor, - &usbSerialNumberDescriptor + &usbActivity, + "DVendor", + "DProduct", + "0.1" }; /* USB mass storage driver */ @@ -56,8 +224,17 @@ int main(void) /* turn off the test LED */ palClearPad(GPIOC, GPIOC_LED); - /* run the USB mass storage service */ - msdInit(&UMSD1, &msdConfig); + /* initialize the USB mass storage driver */ + msdInit(&UMSD1); + + /* start the USB mass storage service */ + msdStart(&UMSD1, &msdConfig); + + /* start the USB driver */ + usbDisconnectBus(&USBD2); + chThdSleepMilliseconds(1000); + usbStart(&USBD2, &usbConfig); + usbConnectBus(&USBD2); /* watch the mass storage events */ EventListener connected; diff --git a/mass_storage/usb_msd.c b/mass_storage/usb_msd.c index 6762dd3..71f5ade 100644 --- a/mass_storage/usb_msd.c +++ b/mass_storage/usb_msd.c @@ -1,9 +1,5 @@ #include "usb_msd.h" -/* End-point info */ -#define USB_MS_DATA_EP 1 /* data end-point index */ -#define USB_MS_EP_SIZE 64 /* end-point size */ - /* Request types */ #define MSD_REQ_RESET 0xFF #define MSD_GET_MAX_LUN 0xFE @@ -24,20 +20,21 @@ #define MSD_COMMAND_PHASE_ERROR 0x02 /* SCSI commands */ -#define SCSI_CMD_INQUIRY 0x12 +#define SCSI_CMD_TEST_UNIT_READY 0x00 #define SCSI_CMD_REQUEST_SENSE 0x03 +#define SCSI_CMD_FORMAT_UNIT 0x04 +#define SCSI_CMD_INQUIRY 0x12 +#define SCSI_CMD_MODE_SENSE_6 0x1A +#define SCSI_CMD_START_STOP_UNIT 0x1B +#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D +#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 #define SCSI_CMD_READ_CAPACITY_10 0x25 #define SCSI_CMD_READ_10 0x28 #define SCSI_CMD_WRITE_10 0x2A -#define SCSI_CMD_TEST_UNIT_READY 0x00 -#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E #define SCSI_CMD_VERIFY_10 0x2F -#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D -#define SCSI_CMD_MODE_SENSE_6 0x1A -#define SCSI_CMD_START_STOP_UNIT 0x1B -#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 -/* SCSI sense constants */ +/* SCSI sense keys */ #define SCSI_SENSE_KEY_GOOD 0x00 #define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 #define SCSI_SENSE_KEY_NOT_READY 0x02 @@ -52,15 +49,19 @@ #define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B #define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D #define SCSI_SENSE_KEY_MISCOMPARE 0x0E + #define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00 +#define SCSI_ASENSE_WRITE_FAULT 0x03 #define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04 +#define SCSI_ASENSE_READ_ERROR 0x11 +#define SCSI_ASENSE_INVALID_COMMAND 0x20 +#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 #define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24 -#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28 #define SCSI_ASENSE_WRITE_PROTECTED 0x27 +#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28 #define SCSI_ASENSE_FORMAT_ERROR 0x31 -#define SCSI_ASENSE_INVALID_COMMAND 0x20 -#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 #define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A + #define SCSI_ASENSEQ_NO_QUALIFIER 0x00 #define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01 #define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02 @@ -103,119 +104,48 @@ static uint8_t rw_buf[2][512]; #define swap_uint16(x) ((((x) & 0x00FF) << 8) \ | (((x) & 0xFF00) >> 8)) -/** - * @brief Configuration Descriptor tree for a CDC - */ -static const uint8_t msd_configuration_descriptor_data[] = { - /* Configuration Descriptor.*/ - USB_DESC_CONFIGURATION(0x0020, /* wTotalLength. */ - 0x01, /* bNumInterfaces. */ - 0x01, /* bConfigurationValue. */ - 0, /* iConfiguration. */ - 0xC0, /* bmAttributes (self powered). */ - 0x32), /* bMaxPower (100mA). */ - /* Interface Descriptor.*/ - USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ - 0x00, /* bAlternateSetting. */ - 0x02, /* bNumEndpoints. */ - 0x08, /* bInterfaceClass (Mass Storage) */ - 0x06, /* bInterfaceSubClass (SCSI - Transparent storage class) */ - 0x50, /* bInterfaceProtocol (Bulk Only) */ - 0), /* iInterface. (none) */ - /* Mass Storage Data In Endpoint Descriptor.*/ - USB_DESC_ENDPOINT (USB_MS_DATA_EP | 0x80, - 0x02, /* bmAttributes (Bulk). */ - USB_MS_EP_SIZE,/* wMaxPacketSize. */ - 0x05), /* bInterval. 1ms */ - /* Mass Storage Data In Endpoint Descriptor.*/ - USB_DESC_ENDPOINT (USB_MS_DATA_EP, - 0x02, /* bmAttributes (Bulk). */ - USB_MS_EP_SIZE,/* wMaxPacketSize. */ - 0x05) /* bInterval. 1ms */ -}; - -static const USBDescriptor msd_configuration_descriptor = { - sizeof msd_configuration_descriptor_data, - msd_configuration_descriptor_data -}; +static void msd_handle_end_point_notification(USBDriver *usbp, usbep_t ep); /** - * @brief Default USB Device Descriptor - */ -MSD_DECLARE_DEVICE_DESCRIPTOR(msd_device_descriptor, 0x0483, 0x5742); - -/** - * @brief U.S. English language identifier descriptor - */ -#define MSD_LANGUAGE_STRING \ - USB_DESC_WORD(0x0409) -MSD_DECLARE_STRING_DESCRIPTOR(msd_language_descriptor, 2, MSD_LANGUAGE_STRING); - -/** - * @brief Default vendor descriptor + * @brief IN end-point 1 state */ -#define MSD_DEFAULT_VENDOR_STRING \ - 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, \ - 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, \ - 'c', 0, 's', 0 -MSD_DECLARE_STRING_DESCRIPTOR(msd_vendor_descriptor, 36, MSD_DEFAULT_VENDOR_STRING); +static USBInEndpointState ep1_in_state; /** - * @brief Default product descriptor + * @brief OUT end-point 1 state */ -#define MSD_DEFAULT_PRODUCT_STRING \ - 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, \ - 'R', 0, 'T', 0, ' ', 0, 'M', 0, 'a', 0, 's', 0, 's', 0, ' ', 0, \ - 'S', 0, 't', 0, 'o', 0, 'r', 0, 'a', 0, 'g', 0, 'e', 0, ' ', 0, \ - 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0 -MSD_DECLARE_STRING_DESCRIPTOR(msd_product_descriptor, 60, MSD_DEFAULT_PRODUCT_STRING); +static USBOutEndpointState ep1_out_state; /** - * @brief Default serial number descriptor + * @brief End-point 1 initialization structure */ -#define MSD_DEFAULT_SERIAL_NUMBER_STRING \ - 'A', 0, 'E', 0, 'C', 0, 'C', 0, 'E', 0, 'C', 0, 'C', 0, 'C', 0, 'C', 0, \ - '0' + CH_KERNEL_MAJOR, 0, \ - '0' + CH_KERNEL_MINOR, 0, \ - '0' + CH_KERNEL_PATCH, 0 -MSD_DECLARE_STRING_DESCRIPTOR(msd_serial_number_descriptor, 24, MSD_DEFAULT_SERIAL_NUMBER_STRING); +static const USBEndpointConfig ep_data_config = { + USB_EP_MODE_TYPE_BULK, + NULL, + msd_handle_end_point_notification, + msd_handle_end_point_notification, + 64, + 64, + &ep1_in_state, + &ep1_out_state, + 1, + NULL +}; /** - * @brief Handles the GET_DESCRIPTOR callback. - * All required descriptors must be handled here. + * @brief USB device configured handler. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @iclass */ -static const USBDescriptor *msd_get_descriptor(USBDriver *usbp, - uint8_t dtype, - uint8_t dindex, - uint16_t lang) { - +void msdConfigureHookI(USBDriver *usbp) +{ USBMassStorageDriver *msdp = (USBMassStorageDriver *)usbp->param; - (void)lang; - - switch (dtype) { - case USB_DESCRIPTOR_DEVICE: - return msdp->config->device_descriptor ? msdp->config->device_descriptor : - &msd_device_descriptor; - case USB_DESCRIPTOR_CONFIGURATION: - return &msd_configuration_descriptor; - case USB_DESCRIPTOR_STRING: - switch (dindex) { - case 0: - return &msd_language_descriptor; - case 1: - return msdp->config->vendor_descriptor ? msdp->config->vendor_descriptor : - &msd_vendor_descriptor; - case 2: - return msdp->config->product_descriptor ? msdp->config->product_descriptor : - &msd_product_descriptor; - case 3: - return msdp->config->serial_number_descriptor ? msdp->config->serial_number_descriptor : - &msd_serial_number_descriptor; - } - } - return NULL; + usbInitEndpointI(usbp, USB_MS_DATA_EP, &ep_data_config); + chBSemSignalI(&msdp->bsem); + chEvtBroadcastI(&msdp->evt_connected); } /** @@ -226,7 +156,7 @@ static const USBDescriptor *msd_get_descriptor(USBDriver *usbp, * @retval TRUE Message handled internally. * @retval FALSE Message not handled. */ -bool_t msd_handle_requests(USBDriver *usbp) { +bool_t msdRequestsHook(USBDriver *usbp) { /* check that the request is of type Class / Interface */ if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) && @@ -296,74 +226,6 @@ static void msd_handle_end_point_notification(USBDriver *usbp, usbep_t ep) { chSysUnlockFromIsr(); } -/** - * @brief IN end-point 1 state - */ -static USBInEndpointState ep1_in_state; - -/** - * @brief OUT end-point 1 state - */ -static USBOutEndpointState ep1_out_state; - -/** - * @brief End-point 1 initialization structure - */ -static const USBEndpointConfig ep_data_config = { - USB_EP_MODE_TYPE_BULK, - NULL, - msd_handle_end_point_notification, - msd_handle_end_point_notification, - USB_MS_EP_SIZE, - USB_MS_EP_SIZE, - &ep1_in_state, - &ep1_out_state, - 1, - NULL -}; - -/** - * @brief Handles the USB driver global events - */ -static void msd_usb_event(USBDriver *usbp, usbevent_t event) { - - USBMassStorageDriver *msdp = (USBMassStorageDriver *)usbp->param; - - switch (event) { - case USB_EVENT_RESET: - return; - case USB_EVENT_ADDRESS: - return; - case USB_EVENT_CONFIGURED: - chSysLockFromIsr(); - usbInitEndpointI(usbp, USB_MS_DATA_EP, &ep_data_config); - /* initialise the thread */ - chBSemSignalI(&msdp->bsem); - - /* signal that the device is connected */ - chEvtBroadcastI(&msdp->evt_connected); - chSysUnlockFromIsr(); - return; - case USB_EVENT_SUSPEND: - return; - case USB_EVENT_WAKEUP: - return; - case USB_EVENT_STALLED: - return; - } - return; -} - -/** - * @brief Global USB configuration - */ -static const USBConfig msd_usb_config = { - msd_usb_event, - msd_get_descriptor, - msd_handle_requests, - NULL -}; - /** * @brief Changes the SCSI sense information */ @@ -428,8 +290,7 @@ bool_t msd_scsi_process_inquiry(USBMassStorageDriver *msdp) { */ bool_t msd_scsi_process_request_sense(USBMassStorageDriver *msdp) { - usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->sense, - sizeof(msdp->sense)); + usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->sense, sizeof(msdp->sense)); chSysLock(); usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); @@ -437,8 +298,11 @@ bool_t msd_scsi_process_request_sense(USBMassStorageDriver *msdp) { msdp->result = TRUE; - /* wait for ISR */ - return TRUE; + /* wait for ISR immediately, otherwise the caller may reset the sense bytes before they are sent to the host! */ + msd_wait_for_isr(msdp); + + /* ... don't wait for ISR, we just did it */ + return FALSE; } /** @@ -476,6 +340,7 @@ bool_t msd_scsi_process_send_diagnostic(USBMassStorageDriver *msdp) { SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_FIELD_IN_CDB, SCSI_ASENSEQ_NO_QUALIFIER); + msdp->result = FALSE; return FALSE; } @@ -513,8 +378,8 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { if (rw_block_address >= msdp->block_dev_info.blk_num) { /* block address is invalid, update SENSE key and return command fail */ msd_scsi_set_sense(msdp, - SCSI_SENSE_KEY_DATA_PROTECT, - SCSI_ASENSE_WRITE_PROTECTED, + SCSI_SENSE_KEY_ILLEGAL_REQUEST, + SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, SCSI_ASENSEQ_NO_QUALIFIER); msdp->result = FALSE; @@ -551,8 +416,15 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { /* now write the block to the block device */ if (blkWrite(msdp->config->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { - /* TODO: handle this */ - chSysHalt(); + /* write failed */ + msd_scsi_set_sense(msdp, + SCSI_SENSE_KEY_MEDIUM_ERROR, + SCSI_ASENSE_WRITE_FAULT, + SCSI_ASENSEQ_NO_QUALIFIER); + msdp->result = FALSE; + + /* don't wait for ISR */ + return FALSE; } if (i < (total - 1)) { @@ -567,8 +439,15 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { /* read the first block from block device */ if (blkRead(msdp->config->bbdp, rw_block_address++, rw_buf[i % 2], 1) == CH_FAILED) { - /* TODO: handle this */ - chSysHalt(); + /* read failed */ + msd_scsi_set_sense(msdp, + SCSI_SENSE_KEY_MEDIUM_ERROR, + SCSI_ASENSE_READ_ERROR, + SCSI_ASENSEQ_NO_QUALIFIER); + msdp->result = FALSE; + + /* don't wait for ISR */ + return FALSE; } /* loop over each block */ @@ -585,8 +464,15 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { /* there is at least one more block to be read from device */ /* so read that whilst the USB transfer takes place */ if (blkRead(msdp->config->bbdp, rw_block_address++, rw_buf[(i + 1) % 2], 1) == CH_FAILED) { - /* TODO: handle this */ - chSysHalt(); + /* read failed */ + msd_scsi_set_sense(msdp, + SCSI_SENSE_KEY_MEDIUM_ERROR, + SCSI_ASENSE_READ_ERROR, + SCSI_ASENSEQ_NO_QUALIFIER); + msdp->result = FALSE; + + /* wait for ISR (the previous transmission is still running) */ + return TRUE; } } @@ -623,9 +509,12 @@ bool_t msd_scsi_process_start_stop_unit(USBMassStorageDriver *msdp) { */ bool_t msd_scsi_process_mode_sense_6(USBMassStorageDriver *msdp) { - /* Send an empty header response with the Write Protect flag status */ - /* TODO set byte3 to 0x80 if disk is read only */ - static uint8_t response[4] = {0x00, 0x00, 0x00, 0x00}; + static uint8_t response[4] = { + 0x03, /* number of bytes that follow */ + 0x00, /* medium type is SBC */ + 0x00, /* not write protected (TODO handle it correctly) */ + 0x00 /* no block descriptor */ + }; usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, response, sizeof(response)); @@ -661,6 +550,27 @@ bool_t msd_scsi_process_read_format_capacities(USBMassStorageDriver *msdp) { return TRUE; } +/** + * @brief Processes a TEST_UNIT_READY SCSI command + */ +bool_t msd_scsi_process_test_unit_ready(USBMassStorageDriver *msdp) { + + if (blkIsInserted(msdp->config->bbdp)) { + /* device inserted and ready */ + msdp->result = TRUE; + } else { + /* device not present or not ready */ + msd_scsi_set_sense(msdp, + SCSI_SENSE_KEY_NOT_READY, + SCSI_ASENSE_MEDIUM_NOT_PRESENT, + SCSI_ASENSEQ_NO_QUALIFIER); + msdp->result = FALSE; + } + + /* don't wait for ISR */ + return FALSE; +} + /** * @brief Waits for a new command block */ @@ -698,6 +608,7 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { /* stall both IN and OUT endpoints */ chSysLock(); usbStallReceiveI(msdp->config->usbp, USB_MS_DATA_EP); + usbStallTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); /* don't wait for ISR */ @@ -738,7 +649,16 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { sleep = msd_scsi_process_read_format_capacities(msdp); break; case SCSI_CMD_TEST_UNIT_READY: + sleep = msd_scsi_process_test_unit_ready(msdp); + break; + case SCSI_CMD_FORMAT_UNIT: + /* don't handle */ + msdp->result = TRUE; + break; case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + /* don't handle */ + msdp->result = TRUE; + break; case SCSI_CMD_VERIFY_10: /* don't handle */ msdp->result = TRUE; @@ -754,28 +674,21 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { usbStallTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); - cbw->data_len = 0; return FALSE; } - cbw->data_len = 0; - if (msdp->result) { /* update sense with success status */ msd_scsi_set_sense(msdp, SCSI_SENSE_KEY_GOOD, SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, SCSI_ASENSEQ_NO_QUALIFIER); - } else { - /* stall IN endpoint */ - chSysLock(); - usbStallTransmitI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); + /* reset data length left */ cbw->data_len = 0; - return FALSE; } + /* wait for ISR if needed */ if (sleep) msd_wait_for_isr(msdp); @@ -788,9 +701,10 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { usbStallTransmitI(msdp->config->usbp, USB_MS_DATA_EP); chSysUnlock(); - return FALSE; + /*return FALSE;*/ } + /* update the command status wrapper and send it to the host */ csw->status = (msdp->result) ? MSD_COMMAND_PASSED : MSD_COMMAND_FAILED; csw->signature = MSD_CSW_SIGNATURE; csw->data_residue = cbw->data_len; @@ -821,11 +735,11 @@ static msg_t mass_storage_thread(void *arg) { /* wait for the usb to be initialised */ msd_wait_for_isr(msdp); - while (TRUE) { + while (!chThdShouldTerminate()) { wait_for_isr = FALSE; /* wait on data depending on the current state */ - switch(msdp->state) { + switch (msdp->state) { case MSD_IDLE: wait_for_isr = msd_wait_for_command_block(msdp); break; @@ -848,27 +762,26 @@ static msg_t mass_storage_thread(void *arg) { return 0; } -static Thread *msd_thread = NULL; - /** - * @brief Initialize USB mass storage on the given USB driver, using the given block device + * @brief Initializse a USB mass storage driver */ -void msdInit(USBMassStorageDriver *msdp, const USBMassStorageConfig *config) { +void msdInit(USBMassStorageDriver *msdp) { chDbgCheck(msdp != NULL, "msdInit"); - chDbgCheck(config != NULL, "msdInit"); - uint8_t i; - msdp->config = config; + msdp->config = NULL; + msdp->thread = NULL; msdp->state = MSD_IDLE; + /* initialize the driver events */ chEvtInit(&msdp->evt_connected); chEvtInit(&msdp->evt_ejected); - /* initialise binary semaphore as taken */ + /* initialise the binary semaphore as taken */ chBSemInit(&msdp->bsem, TRUE); /* initialise the sense data structure */ + size_t i; for (i = 0; i < sizeof(msdp->sense.byte); i++) msdp->sense.byte[i] = 0x00; msdp->sense.byte[0] = 0x70; /* response code */ @@ -883,6 +796,22 @@ void msdInit(USBMassStorageDriver *msdp, const USBMassStorageConfig *config) { msdp->inquiry.sccstp = 0x00; msdp->inquiry.bqueetc = 0x00; msdp->inquiry.cmdque = 0x00; +} + +/** + * @brief Starts a USB mass storage driver + */ +void msdStart(USBMassStorageDriver *msdp, const USBMassStorageConfig *config) { + + chDbgCheck(msdp != NULL, "msdStart"); + chDbgCheck(config != NULL, "msdStart"); + chDbgCheck(msdp->thread == NULL, "msdStart"); + + /* save the configuration */ + msdp->config = config; + + /* copy the config strings to the inquiry response structure */ + size_t i; for (i = 0; i < sizeof(msdp->config->short_vendor_id); ++i) msdp->inquiry.vendor_id[i] = config->short_vendor_id[i]; for (i = 0; i < sizeof(msdp->config->short_product_id); ++i) @@ -890,23 +819,37 @@ void msdInit(USBMassStorageDriver *msdp, const USBMassStorageConfig *config) { for (i = 0; i < sizeof(msdp->config->short_product_version); ++i) msdp->inquiry.product_rev[i] = config->short_product_version[i]; - /* make sure block device is working and get info */ - while (TRUE) { - blkstate_t state = blkGetDriverState(config->bbdp); - if(state == BLK_READY) - break; + /* set the initial state */ + msdp->state = MSD_IDLE; + + /* make sure block device is working */ + while (blkGetDriverState(config->bbdp) != BLK_READY) { chThdSleepMilliseconds(50); } + /* get block device information */ blkGetInfo(config->bbdp, &msdp->block_dev_info); - usbDisconnectBus(config->usbp); - chThdSleepMilliseconds(1000); + /* store the pointer to the mass storage driver into the user param + of the USB driver, so that we can find it back in callbacks */ config->usbp->param = (void *)msdp; - usbStart(config->usbp, &msd_usb_config); - usbConnectBus(config->usbp); + /* run the thread */ + msdp->thread = chThdCreateStatic(mass_storage_thread_wa, sizeof(mass_storage_thread_wa), NORMALPRIO, mass_storage_thread, msdp); +} + +/** + * @brief Stops a USB mass storage driver + */ +void msdStop(USBMassStorageDriver *msdp) { + + chDbgCheck(msdp->thread != NULL, "msdStop"); + + /* notify the thread that it's over */ + chThdTerminate(msdp->thread); - if (msd_thread == NULL) - msd_thread = chThdCreateStatic(mass_storage_thread_wa, sizeof(mass_storage_thread_wa), NORMALPRIO, mass_storage_thread, msdp); + /* wake the thread up and wait until it ends */ + chBSemSignal(&msdp->bsem); + chThdWait(msdp->thread); + msdp->thread = NULL; } diff --git a/mass_storage/usb_msd.h b/mass_storage/usb_msd.h index 5433cfd..300bb0b 100644 --- a/mass_storage/usb_msd.h +++ b/mass_storage/usb_msd.h @@ -67,49 +67,9 @@ typedef enum { } msd_state_t; /** - * @brief Declares a valid USBDecriptor instance from device properties + * @brief Index of the mass storage data endpoint */ -#define MSD_DECLARE_DEVICE_DESCRIPTOR(name, vendor_id, product_id) \ - static const uint8_t name##_data_[] = { \ - USB_DESC_DEVICE(0x0200, /* bcdUSB (2.0). */ \ - 0x00, /* bDeviceClass (None). */ \ - 0x00, /* bDeviceSubClass. */ \ - 0x00, /* bDeviceProtocol. */ \ - 0x40, /* Control Endpoint Size. */ \ - vendor_id, /* idVendor (ST). */ \ - product_id, /* idProduct. */ \ - 0x0100, /* bcdDevice. */ \ - 1, /* iManufacturer. */ \ - 2, /* iProduct. */ \ - 3, /* iSerialNumber. */ \ - 1) /* bNumConfigurations. */ \ - }; \ - static const USBDescriptor name = { \ - sizeof name##_data_, \ - name##_data_ \ - } - -/** - * @brief Declares a valid USBDecriptor instance from a string - * @note The string will be used as a Unicode string, therefore each character - * must be followed by a 0. The length argument must include these zeroes. - * Since the string is a variable-length list of character literals, - * it cannot be passed directly to the macro, it must be first defined - * as a macro itself. - * Example: - * #define VENDOR_STRING 'm', 0, 'y', 0, 'c', 0, 'o', 0, 'm', 0, 'p', 0 - * MSD_DECLARE_DESCRIPTOR(mycomp_descriptor, 12, VENDOR_STRING); - */ -#define MSD_DECLARE_STRING_DESCRIPTOR(name, length, string) \ - static const uint8_t name##_data_[] = { \ - USB_DESC_BYTE(length + 2), \ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), \ - string \ - }; \ - static const USBDescriptor name = { \ - sizeof name##_data_, \ - name##_data_ \ - } +#define USB_MS_DATA_EP 3 /** * @brief Driver configuration structure @@ -133,35 +93,6 @@ typedef struct { */ void (*rw_activity_callback)(bool_t); - /** - * @brief Device description - * @note To define such a valid USBDescriptor, see the MSD_DECLARE_DEVICE_DESCRIPTOR macro. - * If null, a default device description is used. - */ - const USBDescriptor* device_descriptor; - - /** - * @brief Vendor description - * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. - * If null, a default vendor description is used. - */ - const USBDescriptor* vendor_descriptor; - - /** - * @brief Product description - * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. - * If null, a default product description is used. - */ - const USBDescriptor* product_descriptor; - - /** - * @brief Serial number description - * @note To define such a valid USBDescriptor, see the MSD_DECLARE_STRING_DESCRIPTOR macro. - * If null, a default serial number description is used. - * This description string must contain at least 12 valid digits. - */ - const USBDescriptor* serial_number_descriptor; - /** * @brief Short vendor identification * @note ASCII characters only, maximum 8 characters (pad with zeroes). @@ -190,6 +121,7 @@ typedef struct { typedef struct { const USBMassStorageConfig* config; BinarySemaphore bsem; + Thread* thread; EventSource evt_connected, evt_ejected; BlockDeviceInfo block_dev_info; msd_state_t state; @@ -205,13 +137,50 @@ extern "C" { #endif /** - * @brief Initialize USB mass storage with the given configuration. + * @brief Initializes a USB mass storage driver. + */ +void msdInit(USBMassStorageDriver *msdp); + +/** + * @brief Starts a USB mass storage driver. * @details This function is sufficient to have USB mass storage running, it internally * runs a thread that handles USB requests and transfers. * The block device must be connected but no file system must be mounted, * everything is handled by the host system. */ -void msdInit(USBMassStorageDriver *msdp, const USBMassStorageConfig *config); +void msdStart(USBMassStorageDriver *msdp, const USBMassStorageConfig *config); + +/** + * @brief Stops a USB mass storage driver. + * @details This function waits for current tasks to be finished, if any, and then + * stops the mass storage thread. + */ +void msdStop(USBMassStorageDriver *msdp); + +/** + * @brief USB device configured handler. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @iclass + */ +void msdConfigureHookI(USBDriver *usbp); + +/** + * @brief Default requests hook. + * @details Applications wanting to use the Mass Storage over USB driver can use + * this function as requests hook in the USB configuration. + * The following requests are emulated: + * - MSD_REQ_RESET. + * - MSD_GET_MAX_LUN. + * . + * + * @param[in] usbp pointer to the @p USBDriver object + * @return The hook status. + * @retval TRUE Message handled internally. + * @retval FALSE Message not handled. + */ +bool_t msdRequestsHook(USBDriver *usbp); #ifdef __cplusplus } From a48fac22c603854f6a505d7054ea8789f127e922 Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Mon, 29 Apr 2013 10:03:28 +0200 Subject: [PATCH 09/11] The endpoint index is now part of the config structure. Refactored the send/receive code. --- demos/mass_storage_OLIMEX_STM32E407/main.c | 4 + mass_storage/usb_msd.c | 114 ++++++++------------- mass_storage/usb_msd.h | 10 +- 3 files changed, 52 insertions(+), 76 deletions(-) diff --git a/demos/mass_storage_OLIMEX_STM32E407/main.c b/demos/mass_storage_OLIMEX_STM32E407/main.c index 73902af..c2173df 100644 --- a/demos/mass_storage_OLIMEX_STM32E407/main.c +++ b/demos/mass_storage_OLIMEX_STM32E407/main.c @@ -4,6 +4,9 @@ #include #include +/* endpoint index */ +#define USB_MS_DATA_EP 1 + /* USB device descriptor */ static const uint8_t deviceDescriptorData[] = { @@ -202,6 +205,7 @@ static USBMassStorageConfig msdConfig = { &USBD2, (BaseBlockDevice*)&SDCD1, + USB_MS_DATA_EP, &usbActivity, "DVendor", "DProduct", diff --git a/mass_storage/usb_msd.c b/mass_storage/usb_msd.c index 71f5ade..64d9e4a 100644 --- a/mass_storage/usb_msd.c +++ b/mass_storage/usb_msd.c @@ -143,7 +143,7 @@ void msdConfigureHookI(USBDriver *usbp) { USBMassStorageDriver *msdp = (USBMassStorageDriver *)usbp->param; - usbInitEndpointI(usbp, USB_MS_DATA_EP, &ep_data_config); + usbInitEndpointI(usbp, msdp->config->bulk_ep, &ep_data_config); chBSemSignalI(&msdp->bsem); chEvtBroadcastI(&msdp->evt_connected); } @@ -216,6 +216,9 @@ static void msd_wait_for_isr(USBMassStorageDriver *msdp) { chSysUnlock(); } +/** + * @brief Called when data can be read or written on the endpoint -- wakes the thread up + */ static void msd_handle_end_point_notification(USBDriver *usbp, usbep_t ep) { (void)usbp; @@ -226,6 +229,28 @@ static void msd_handle_end_point_notification(USBDriver *usbp, usbep_t ep) { chSysUnlockFromIsr(); } +/** + * @brief Starts sending data + */ +static void msd_start_transmit(USBMassStorageDriver *msdp, const uint8_t* buffer, size_t size) { + + usbPrepareTransmit(msdp->config->usbp, msdp->config->bulk_ep, buffer, size); + chSysLock(); + usbStartTransmitI(msdp->config->usbp, msdp->config->bulk_ep); + chSysUnlock(); +} + +/** + * @brief Starts receiving data + */ +static void msd_start_receive(USBMassStorageDriver *msdp, uint8_t* buffer, size_t size) { + + usbPrepareReceive(msdp->config->usbp, msdp->config->bulk_ep, buffer, size); + chSysLock(); + usbStartReceiveI(msdp->config->usbp, msdp->config->bulk_ep); + chSysUnlock(); +} + /** * @brief Changes the SCSI sense information */ @@ -251,10 +276,7 @@ bool_t msd_scsi_process_inquiry(USBMassStorageDriver *msdp) { /* unit serial number */ case 0x80: { uint8_t response[] = {'0'}; /* TODO */ - usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, response, sizeof(response)); - chSysLock(); - usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); + msd_start_transmit(msdp, response, sizeof(response)); msdp->result = TRUE; /* wait for ISR */ @@ -272,12 +294,7 @@ bool_t msd_scsi_process_inquiry(USBMassStorageDriver *msdp) { } else { - usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->inquiry, sizeof(msdp->inquiry)); - - chSysLock(); - usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); - + msd_start_transmit(msdp, (const uint8_t *)&msdp->inquiry, sizeof(msdp->inquiry)); msdp->result = TRUE; /* wait for ISR */ @@ -290,12 +307,7 @@ bool_t msd_scsi_process_inquiry(USBMassStorageDriver *msdp) { */ bool_t msd_scsi_process_request_sense(USBMassStorageDriver *msdp) { - usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->sense, sizeof(msdp->sense)); - - chSysLock(); - usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); - + msd_start_transmit(msdp, (const uint8_t *)&msdp->sense, sizeof(msdp->sense)); msdp->result = TRUE; /* wait for ISR immediately, otherwise the caller may reset the sense bytes before they are sent to the host! */ @@ -315,12 +327,7 @@ bool_t msd_scsi_process_read_capacity_10(USBMassStorageDriver *msdp) { response.block_size = swap_uint32(msdp->block_dev_info.blk_size); response.last_block_addr = swap_uint32(msdp->block_dev_info.blk_num-1); - usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&response, sizeof(response)); - - chSysLock(); - usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); - + msd_start_transmit(msdp, (const uint8_t *)&response, sizeof(response)); msdp->result = TRUE; /* wait for ISR */ @@ -391,13 +398,7 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { /* process a write command */ /* get the first packet */ - usbPrepareReceive(msdp->config->usbp, USB_MS_DATA_EP, rw_buf[i % 2], - msdp->block_dev_info.blk_size); - - chSysLock(); - usbStartReceiveI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); - + msd_start_receive(msdp, rw_buf[i % 2], msdp->block_dev_info.blk_size); msd_wait_for_isr(msdp); /* loop over each block */ @@ -406,12 +407,7 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { if (i < (total - 1)) { /* there is at least one block of data left to be read over USB */ /* queue this read before issuing the blocking write */ - usbPrepareReceive(msdp->config->usbp, USB_MS_DATA_EP, rw_buf[(i + 1) % 2], - msdp->block_dev_info.blk_size); - - chSysLock(); - usbStartReceiveI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); + msd_start_receive(msdp, rw_buf[(i + 1) % 2], msdp->block_dev_info.blk_size); } /* now write the block to the block device */ @@ -453,12 +449,7 @@ bool_t msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp) { /* loop over each block */ for (i = 0; i < total; i++) { /* transmit the block */ - usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, rw_buf[i % 2], - msdp->block_dev_info.blk_size); - - chSysLock(); - usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); + msd_start_transmit(msdp, rw_buf[i % 2], msdp->block_dev_info.blk_size); if (i < (total - 1)) { /* there is at least one more block to be read from device */ @@ -516,12 +507,7 @@ bool_t msd_scsi_process_mode_sense_6(USBMassStorageDriver *msdp) { 0x00 /* no block descriptor */ }; - usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, response, sizeof(response)); - - chSysLock(); - usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); - + msd_start_transmit(msdp, response, sizeof(response)); msdp->result = TRUE; /* wait for ISR */ @@ -538,12 +524,7 @@ bool_t msd_scsi_process_read_format_capacities(USBMassStorageDriver *msdp) { response.block_count = swap_uint32(msdp->block_dev_info.blk_num); response.desc_and_block_length = swap_uint32((0x02 << 24) | (msdp->block_dev_info.blk_size & 0x00FFFFFF)); - usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (const uint8_t*)&response, sizeof(response)); - - chSysLock(); - usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); - + msd_start_transmit(msdp, (const uint8_t*)&response, sizeof(response)); msdp->result = TRUE; /* wait for ISR */ @@ -576,12 +557,7 @@ bool_t msd_scsi_process_test_unit_ready(USBMassStorageDriver *msdp) { */ bool_t msd_wait_for_command_block(USBMassStorageDriver *msdp) { - usbPrepareReceive(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)&msdp->cbw, sizeof(msdp->cbw)); - - chSysLock(); - usbStartReceiveI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); - + msd_start_receive(msdp, (uint8_t *)&msdp->cbw, sizeof(msdp->cbw)); msdp->state = MSD_READ_COMMAND_BLOCK; /* wait for ISR */ @@ -607,8 +583,8 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { /* stall both IN and OUT endpoints */ chSysLock(); - usbStallReceiveI(msdp->config->usbp, USB_MS_DATA_EP); - usbStallTransmitI(msdp->config->usbp, USB_MS_DATA_EP); + usbStallReceiveI(msdp->config->usbp, msdp->config->bulk_ep); + usbStallTransmitI(msdp->config->usbp, msdp->config->bulk_ep); chSysUnlock(); /* don't wait for ISR */ @@ -671,7 +647,7 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { /* stall IN endpoint */ chSysLock(); - usbStallTransmitI(msdp->config->usbp, USB_MS_DATA_EP); + usbStallTransmitI(msdp->config->usbp, msdp->config->bulk_ep); chSysUnlock(); return FALSE; @@ -697,8 +673,8 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { if (!msdp->result && cbw->data_len) { /* still bytes left to send, this is too early to send CSW? */ chSysLock(); - usbStallReceiveI(msdp->config->usbp, USB_MS_DATA_EP); - usbStallTransmitI(msdp->config->usbp, USB_MS_DATA_EP); + usbStallReceiveI(msdp->config->usbp, msdp->config->bulk_ep); + usbStallTransmitI(msdp->config->usbp, msdp->config->bulk_ep); chSysUnlock(); /*return FALSE;*/ @@ -710,13 +686,9 @@ bool_t msd_read_command_block(USBMassStorageDriver *msdp) { csw->data_residue = cbw->data_len; csw->tag = cbw->tag; - usbPrepareTransmit(msdp->config->usbp, USB_MS_DATA_EP, (uint8_t *)csw, sizeof(*csw)); - - chSysLock(); - usbStartTransmitI(msdp->config->usbp, USB_MS_DATA_EP); - chSysUnlock(); + msd_start_transmit(msdp, (const uint8_t *)csw, sizeof(*csw)); - /* wait on ISR */ + /* wait for ISR */ return TRUE; } diff --git a/mass_storage/usb_msd.h b/mass_storage/usb_msd.h index 300bb0b..7b65515 100644 --- a/mass_storage/usb_msd.h +++ b/mass_storage/usb_msd.h @@ -66,11 +66,6 @@ typedef enum { MSD_EJECTED } msd_state_t; -/** - * @brief Index of the mass storage data endpoint - */ -#define USB_MS_DATA_EP 3 - /** * @brief Driver configuration structure */ @@ -85,6 +80,11 @@ typedef struct { */ BaseBlockDevice *bbdp; + /** + * @brief Index of the USB endpoint to use for transfers + */ + usbep_t bulk_ep; + /** * @brief Optional callback that will be called whenever there is * read/write activity From ea2071288dd075bd6c80f818266ad7dd36d24ce5 Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Thu, 20 Jun 2013 09:24:36 +0200 Subject: [PATCH 10/11] Added .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..695f6c9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +mass_storage/debug.h From 41e3107659ee0efe93a68d2d70633d3dfb435efe Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Fri, 23 Aug 2013 09:32:52 +0200 Subject: [PATCH 11/11] Updated to match the latest ChibiOS revision --- mass_storage/usb_msd.c | 17 ++++++++++------- mass_storage/usb_msd.h | 4 ++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/mass_storage/usb_msd.c b/mass_storage/usb_msd.c index 64d9e4a..41f0188 100644 --- a/mass_storage/usb_msd.c +++ b/mass_storage/usb_msd.c @@ -135,15 +135,13 @@ static const USBEndpointConfig ep_data_config = { /** * @brief USB device configured handler. * - * @param[in] usbp pointer to the @p USBDriver object + * @param[in] msdp pointer to the @p USBMassStorageDriver object * * @iclass */ -void msdConfigureHookI(USBDriver *usbp) +void msdConfigureHookI(USBMassStorageDriver *msdp) { - USBMassStorageDriver *msdp = (USBMassStorageDriver *)usbp->param; - - usbInitEndpointI(usbp, msdp->config->bulk_ep, &ep_data_config); + usbInitEndpointI(msdp->config->usbp, msdp->config->bulk_ep, &ep_data_config); chBSemSignalI(&msdp->bsem); chEvtBroadcastI(&msdp->evt_connected); } @@ -225,7 +223,7 @@ static void msd_handle_end_point_notification(USBDriver *usbp, usbep_t ep) { (void)ep; chSysLockFromIsr(); - chBSemSignalI(&((USBMassStorageDriver *)usbp->param)->bsem); + chBSemSignalI(&((USBMassStorageDriver *)usbp->in_params[ep])->bsem); chSysUnlockFromIsr(); } @@ -804,7 +802,8 @@ void msdStart(USBMassStorageDriver *msdp, const USBMassStorageConfig *config) { /* store the pointer to the mass storage driver into the user param of the USB driver, so that we can find it back in callbacks */ - config->usbp->param = (void *)msdp; + config->usbp->in_params[config->bulk_ep] = (void *)msdp; + config->usbp->out_params[config->bulk_ep] = (void *)msdp; /* run the thread */ msdp->thread = chThdCreateStatic(mass_storage_thread_wa, sizeof(mass_storage_thread_wa), NORMALPRIO, mass_storage_thread, msdp); @@ -824,4 +823,8 @@ void msdStop(USBMassStorageDriver *msdp) { chBSemSignal(&msdp->bsem); chThdWait(msdp->thread); msdp->thread = NULL; + + /* release the user params in the USB driver */ + msdp->config->usbp->in_params[msdp->config->bulk_ep] = NULL; + msdp->config->usbp->out_params[msdp->config->bulk_ep] = NULL; } diff --git a/mass_storage/usb_msd.h b/mass_storage/usb_msd.h index 7b65515..81aa34c 100644 --- a/mass_storage/usb_msd.h +++ b/mass_storage/usb_msd.h @@ -160,11 +160,11 @@ void msdStop(USBMassStorageDriver *msdp); /** * @brief USB device configured handler. * - * @param[in] usbp pointer to the @p USBDriver object + * @param[in] msdp pointer to the @p USBMassStorageDriver object * * @iclass */ -void msdConfigureHookI(USBDriver *usbp); +void msdConfigureHookI(USBMassStorageDriver *msdp); /** * @brief Default requests hook.