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.
This commit is contained in:
parent
4d7f4eb6a9
commit
9699ea6a2f
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user