From 9699ea6a2f85c344296eb0046d9bad8f0c183d1a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 15 Apr 2014 19:56:32 +0100 Subject: [PATCH] stmhal: Fix USB MSC so that it unmounts correctly on Mac OS X. Mac OS X sends a SCSI command to remove the medium when it unmounts a drive. If this command is not honoured, then OS X will automatically remount the drive, making it impossible to eject. This patch disables the USB MSC when the right SCSI command is sent. --- stmhal/usbd_msc_storage.c | 25 +++++++++++++++ .../class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h | 1 + .../class/cdc_msc_hid/src/usbd_cdc_msc_hid.c | 16 ++++++++-- .../class/cdc_msc_hid/src/usbd_msc_scsi.c | 32 ++++++++++++++++++- 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/stmhal/usbd_msc_storage.c b/stmhal/usbd_msc_storage.c index f3ecd023d1..0225a2a23c 100644 --- a/stmhal/usbd_msc_storage.c +++ b/stmhal/usbd_msc_storage.c @@ -35,6 +35,11 @@ #include "diskio.h" #include "sdcard.h" +// These are needed to support removal of the medium, so that the USB drive +// can be unmounted, and won't be remounted automatically. +static uint8_t flash_removed = 0; +static uint8_t sdcard_removed = 0; + /******************************************************************************/ // Callback functions for when the internal flash is the mass storage device @@ -83,6 +88,9 @@ int8_t FLASH_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *blo * @retval Status */ int8_t FLASH_STORAGE_IsReady(uint8_t lun) { + if (flash_removed) { + return -1; + } return 0; } @@ -95,6 +103,12 @@ int8_t FLASH_STORAGE_IsWriteProtected(uint8_t lun) { return 0; } +// Remove the lun +int8_t FLASH_STORAGE_StopUnit(uint8_t lun) { + flash_removed = 1; + return 0; +} + /** * @brief Read data from the medium * @param lun : logical unit number @@ -150,6 +164,7 @@ const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops = { FLASH_STORAGE_GetCapacity, FLASH_STORAGE_IsReady, FLASH_STORAGE_IsWriteProtected, + FLASH_STORAGE_StopUnit, FLASH_STORAGE_Read, FLASH_STORAGE_Write, FLASH_STORAGE_GetMaxLun, @@ -236,6 +251,9 @@ int8_t SDCARD_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *bl * @retval Status */ int8_t SDCARD_STORAGE_IsReady(uint8_t lun) { + if (sdcard_removed) { + return -1; + } /* #ifndef USE_STM3210C_EVAL @@ -271,6 +289,12 @@ int8_t SDCARD_STORAGE_IsWriteProtected(uint8_t lun) { return 0; } +// Remove the lun +int8_t SDCARD_STORAGE_StopUnit(uint8_t lun) { + sdcard_removed = 1; + return 0; +} + /** * @brief Read data from the medium * @param lun : logical unit number @@ -315,6 +339,7 @@ const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops = { SDCARD_STORAGE_GetCapacity, SDCARD_STORAGE_IsReady, SDCARD_STORAGE_IsWriteProtected, + SDCARD_STORAGE_StopUnit, SDCARD_STORAGE_Read, SDCARD_STORAGE_Write, SDCARD_STORAGE_GetMaxLun, diff --git a/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h index 8423ad7759..9343994931 100644 --- a/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h +++ b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h @@ -53,6 +53,7 @@ typedef struct _USBD_STORAGE { int8_t (* GetCapacity) (uint8_t lun, uint32_t *block_num, uint16_t *block_size); int8_t (* IsReady) (uint8_t lun); int8_t (* IsWriteProtected) (uint8_t lun); + int8_t (* StopUnit)(uint8_t lun); int8_t (* Read) (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); int8_t (* GetMaxLun)(void); diff --git a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c index 6cb15ba210..6dc0af0e65 100644 --- a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c +++ b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c @@ -583,11 +583,18 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp /* printf("SU: %x %x %x %x\n", req->bmRequest, req->bRequest, req->wValue, req->wIndex); + This is what we get when MSC is IFACE=0 and CDC is IFACE=1,2: SU: 21 22 0 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_CONTROL_LINE_STATE SU: 21 20 0 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_LINE_CODING SU: a1 fe 0 0 -- 0x80 | USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; BOT_GET_MAX_LUN; 0; 0 SU: 21 22 3 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_CONTROL_LINE_STATE + + On a Mac OS X, with MSC then CDC: + SU: a1 fe 0 0 + SU: 21 22 2 1 + SU: 21 22 3 1 + SU: 21 20 0 1 */ switch (req->bmRequest & USB_REQ_TYPE_MASK) { @@ -723,6 +730,11 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp return USBD_OK; } +/* unused +static uint8_t EP0_TxSent(USBD_HandleTypeDef *pdev) { +} +*/ + static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) { if((CDC_fops != NULL) && (CDC_ClassData.CmdOpCode != 0xFF)) { CDC_fops->Control(CDC_ClassData.CmdOpCode, (uint8_t *)CDC_ClassData.data, CDC_ClassData.CmdLength); @@ -902,8 +914,8 @@ USBD_ClassTypeDef USBD_CDC_MSC_HID = { USBD_CDC_MSC_HID_DataIn, USBD_CDC_MSC_HID_DataOut, NULL, // SOF - NULL, - NULL, + NULL, // IsoINIncomplete + NULL, // IsoOUTIncomplete USBD_CDC_MSC_HID_GetCfgDesc, USBD_CDC_MSC_HID_GetCfgDesc, USBD_CDC_MSC_HID_GetCfgDesc, diff --git a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c index af3818d373..b00d1ae2ce 100644 --- a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c +++ b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c @@ -86,6 +86,7 @@ static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, ui static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params); @@ -122,6 +123,11 @@ int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) { + /* + if (params[0] != SCSI_READ10 && params[0] != SCSI_WRITE10) { + printf("SCSI_ProcessCmd(lun=%d, params=%x, %x)\n", lun, params[0], params[1]); + } + */ switch (params[0]) { @@ -137,7 +143,7 @@ int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, return SCSI_StartStopUnit(pdev, lun, params); case SCSI_ALLOW_MEDIUM_REMOVAL: - return SCSI_StartStopUnit(pdev, lun, params); + return SCSI_AllowMediumRemoval(pdev, lun, params); case SCSI_MODE_SENSE6: return SCSI_ModeSense6 (pdev, lun, params); @@ -439,6 +445,30 @@ void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_ * @retval status */ static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassData; + hmsc->bot_data_length = 0; + + // On Mac OS X, when the device is ejected a SCSI_START_STOP_UNIT command is sent. + // params[1]==0 means stop, param[1]==1 seems to be something else (happens after the + // device is plugged in and mounted for some time, probably a keep alive). + // If we get a stop, we must really stop the device so that the Mac does not + // automatically remount it. + if (params[1] == 0) { + ((USBD_StorageTypeDef *)pdev->pUserData)->StopUnit(lun); + } + + return 0; +} + +/** +* @brief SCSI_AllowMediumRemoval +* Process Allow Medium Removal command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) { USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassData; hmsc->bot_data_length = 0;