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.
pull/498/head
Damien George 2014-04-15 19:56:32 +01:00
rodzic 4d7f4eb6a9
commit 9699ea6a2f
4 zmienionych plików z 71 dodań i 3 usunięć

Wyświetl plik

@ -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,

Wyświetl plik

@ -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);

Wyświetl plik

@ -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,

Wyświetl plik

@ -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;