summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--stmhal/adc.c32
-rw-r--r--stmhal/dac.c42
-rw-r--r--stmhal/i2c.c25
-rw-r--r--stmhal/main.c20
-rw-r--r--stmhal/qstrdefsport.h2
-rw-r--r--stmhal/timer.c27
-rw-r--r--stmhal/timer.h2
-rw-r--r--stmhal/usbd_msc_storage.c25
-rw-r--r--stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h1
-rw-r--r--stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c16
-rw-r--r--stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c32
11 files changed, 197 insertions, 27 deletions
diff --git a/stmhal/adc.c b/stmhal/adc.c
index 8a1c23c4f6..dafa3f7bce 100644
--- a/stmhal/adc.c
+++ b/stmhal/adc.c
@@ -11,6 +11,7 @@
#include "adc.h"
#include "pin.h"
#include "build/pins.h"
+#include "timer.h"
// Usage Model:
//
@@ -162,8 +163,39 @@ STATIC mp_obj_t adc_read(mp_obj_t self_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
+STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_in) {
+ pyb_obj_adc_t *self = self_in;
+
+ buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo);
+
+ // Init TIM6 at the required frequency (in Hz)
+ timer_tim6_init(mp_obj_get_int(freq_in));
+
+ // Start timer
+ HAL_TIM_Base_Start(&TIM6_Handle);
+
+ // This uses the timer in polling mode to do the sampling
+ // TODO use DMA
+ for (uint i = 0; i < bufinfo.len; i++) {
+ // Wait for the timer to trigger
+ while (__HAL_TIM_GET_FLAG(&TIM6_Handle, TIM_FLAG_UPDATE) == RESET) {
+ }
+ __HAL_TIM_CLEAR_FLAG(&TIM6_Handle, TIM_FLAG_UPDATE);
+ ((byte*)bufinfo.buf)[i] = adc_read_channel(&self->handle) >> 4;
+ }
+
+ // Stop timer
+ HAL_TIM_Base_Stop(&TIM6_Handle);
+
+ return mp_obj_new_int(bufinfo.len);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed);
+
STATIC const mp_map_elem_t adc_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj},
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read_timed), (mp_obj_t)&adc_read_timed_obj},
};
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
diff --git a/stmhal/dac.c b/stmhal/dac.c
index 5e809412e9..c018a4046a 100644
--- a/stmhal/dac.c
+++ b/stmhal/dac.c
@@ -10,9 +10,9 @@
#include "parse.h"
#include "obj.h"
#include "runtime.h"
+#include "timer.h"
#include "dac.h"
-TIM_HandleTypeDef TIM6_Handle;
STATIC DAC_HandleTypeDef DAC_Handle;
void dac_init(void) {
@@ -22,19 +22,8 @@ void dac_init(void) {
}
STATIC void TIM6_Config(uint freq) {
- // TIM6 clock enable
- __TIM6_CLK_ENABLE();
-
- // Compute the prescaler value so TIM6 triggers at freq-Hz
- uint16_t period = (uint16_t) ((SystemCoreClock / 2) / freq) - 1;
-
- // time base clock configuration
- TIM6_Handle.Instance = TIM6;
- TIM6_Handle.Init.Period = period;
- TIM6_Handle.Init.Prescaler = 0; // timer runs at SystemCoreClock / 2
- TIM6_Handle.Init.ClockDivision = 0; // unused for TIM6
- TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6
- HAL_TIM_Base_Init(&TIM6_Handle);
+ // Init TIM6 at the required frequency (in Hz)
+ timer_tim6_init(freq);
// TIM6 TRGO selection
TIM_MasterConfigTypeDef config;
@@ -203,17 +192,14 @@ mp_obj_t pyb_dac_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
DAC_Init(self->dac_channel, &DAC_InitStructure);
*/
- if (self->state != 3) {
- DAC_ChannelConfTypeDef config;
- config.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
- config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
- HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
- self->state = 3;
- }
-
// DMA1_Stream[67] channel7 configuration
DMA_HandleTypeDef DMA_Handle;
DMA_Handle.Instance = self->dma_stream;
+
+ // Need to deinit DMA first
+ DMA_Handle.State = HAL_DMA_STATE_READY;
+ HAL_DMA_DeInit(&DMA_Handle);
+
DMA_Handle.Init.Channel = DMA_CHANNEL_7;
DMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH;
DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE;
@@ -231,6 +217,18 @@ mp_obj_t pyb_dac_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
__HAL_LINKDMA(&DAC_Handle, DMA_Handle1, DMA_Handle);
+ DAC_Handle.Instance = DAC;
+ DAC_Handle.State = HAL_DAC_STATE_RESET;
+ HAL_DAC_Init(&DAC_Handle);
+
+ if (self->state != 3) {
+ DAC_ChannelConfTypeDef config;
+ config.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
+ config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
+ HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
+ self->state = 3;
+ }
+
HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel, (uint32_t*)bufinfo.buf, bufinfo.len, DAC_ALIGN_8B_R);
/*
diff --git a/stmhal/i2c.c b/stmhal/i2c.c
index 65bc3600ef..c0d53c9a92 100644
--- a/stmhal/i2c.c
+++ b/stmhal/i2c.c
@@ -98,14 +98,13 @@ STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
return (mp_obj_t)i2c_obj;
}
+// Check if an I2C device responds to the given address.
STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) {
pyb_i2c_obj_t *self = self_in;
machine_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o) << 1;
- //printf("IsDeviceReady\n");
for (int i = 0; i < 10; i++) {
HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c_handle, i2c_addr, 10, 200);
- //printf(" got %d\n", status);
if (status == HAL_OK) {
return mp_const_true;
}
@@ -116,6 +115,27 @@ STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) {
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready);
+// Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.
+STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
+ pyb_i2c_obj_t *self = self_in;
+
+ mp_obj_t list = mp_obj_new_list(0, NULL);
+
+ for (uint addr = 1; addr <= 127; addr++) {
+ for (int i = 0; i < 10; i++) {
+ HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c_handle, addr << 1, 10, 200);
+ if (status == HAL_OK) {
+ mp_obj_list_append(list, mp_obj_new_int(addr));
+ break;
+ }
+ }
+ }
+
+ return list;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan);
+
STATIC mp_obj_t pyb_i2c_mem_read(uint n_args, const mp_obj_t *args) {
pyb_i2c_obj_t *self = args[0];
machine_uint_t i2c_addr = mp_obj_get_int(args[1]) << 1;
@@ -166,6 +186,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_i2c_mem_write_obj, 4, 4, pyb_i2c_
STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_is_ready), (mp_obj_t)&pyb_i2c_is_ready_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&pyb_i2c_scan_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_read), (mp_obj_t)&pyb_i2c_mem_read_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_write), (mp_obj_t)&pyb_i2c_mem_write_obj },
};
diff --git a/stmhal/main.c b/stmhal/main.c
index 116a259955..cc41a195a3 100644
--- a/stmhal/main.c
+++ b/stmhal/main.c
@@ -137,6 +137,21 @@ static const char fresh_pybcdc_inf[] =
#include "pybcdc.h"
;
+static const char fresh_readme_txt[] =
+"This is a Micro Python board\r\n"
+"\r\n"
+"You can get started right away by writing your Python code in 'main.py'.\r\n"
+"\r\n"
+"For a serial prompt:\r\n"
+" - Windows: you need to go to 'Device manager', right click on the unknown device,\r\n"
+" then update the driver software, using the 'pybcdc.inf' file found on this drive.\r\n"
+" Then use a terminal program like Hyperterminal or putty.\r\n"
+" - Mac OS X: use the command: screen /dev/tty.usbmodem*\r\n"
+" - Linux: use the command: screen /dev/ttyACM0\r\n"
+"\r\n"
+"Please visit http://micropython.org/help/ for further help.\r\n"
+;
+
int main(void) {
// TODO disable JTAG
@@ -322,6 +337,11 @@ soft_reset:
f_write(&fp, fresh_pybcdc_inf, sizeof(fresh_pybcdc_inf) - 1 /* don't count null terminator */, &n);
f_close(&fp);
+ // create readme file
+ f_open(&fp, "0:/README.txt", FA_WRITE | FA_CREATE_ALWAYS);
+ f_write(&fp, fresh_readme_txt, sizeof(fresh_readme_txt) - 1 /* don't count null terminator */, &n);
+ f_close(&fp);
+
// keep LED on for at least 200ms
sys_tick_wait_at_least(start_tick, 200);
led_state(PYB_LED_R2, 0);
diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h
index 0dd8c2b61b..68b91c3d8d 100644
--- a/stmhal/qstrdefsport.h
+++ b/stmhal/qstrdefsport.h
@@ -82,6 +82,7 @@ Q(MODE_EVT_RISING_FALLING)
// for I2C object
Q(I2C)
Q(is_ready)
+Q(scan)
Q(mem_read)
Q(mem_write)
@@ -96,6 +97,7 @@ Q(filtered_xyz)
// for ADC object
Q(ADC)
Q(ADC_all)
+Q(read_timed)
Q(read_channel)
Q(read_core_temp)
Q(read_core_vbat)
diff --git a/stmhal/timer.c b/stmhal/timer.c
index 1e77f0fea3..5ea605039d 100644
--- a/stmhal/timer.c
+++ b/stmhal/timer.c
@@ -27,6 +27,7 @@
TIM_HandleTypeDef TIM3_Handle;
TIM_HandleTypeDef TIM5_Handle;
+TIM_HandleTypeDef TIM6_Handle;
// TIM3 is set-up for the USB CDC interface
void timer_tim3_init(void) {
@@ -57,6 +58,7 @@ void timer_tim3_deinit(void) {
*/
// TIM5 is set-up for the servo controller
+// This function inits but does not start the timer
void timer_tim5_init(void) {
// TIM5 clock enable
__TIM5_CLK_ENABLE();
@@ -74,6 +76,31 @@ void timer_tim5_init(void) {
HAL_TIM_PWM_Init(&TIM5_Handle);
}
+// Init TIM6 with a counter-overflow at the given frequency (given in Hz)
+// TIM6 is used by the DAC and ADC for auto sampling at a given frequency
+// This function inits but does not start the timer
+void timer_tim6_init(uint freq) {
+ // TIM6 clock enable
+ __TIM6_CLK_ENABLE();
+
+ // Timer runs at SystemCoreClock / 2
+ // Compute the prescaler value so TIM6 triggers at freq-Hz
+ uint32_t period = (SystemCoreClock / 2) / freq;
+ uint32_t prescaler = 1;
+ while (period > 0xffff) {
+ period >>= 1;
+ prescaler <<= 1;
+ }
+
+ // Time base clock configuration
+ TIM6_Handle.Instance = TIM6;
+ TIM6_Handle.Init.Period = period - 1;
+ TIM6_Handle.Init.Prescaler = prescaler - 1;
+ TIM6_Handle.Init.ClockDivision = 0; // unused for TIM6
+ TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6
+ HAL_TIM_Base_Init(&TIM6_Handle);
+}
+
// Interrupt dispatch
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim == &TIM3_Handle) {
diff --git a/stmhal/timer.h b/stmhal/timer.h
index 317b39b3f7..06e19bcc8b 100644
--- a/stmhal/timer.h
+++ b/stmhal/timer.h
@@ -5,6 +5,8 @@
extern TIM_HandleTypeDef TIM3_Handle;
extern TIM_HandleTypeDef TIM5_Handle;
+extern TIM_HandleTypeDef TIM6_Handle;
void timer_tim3_init(void);
void timer_tim5_init(void);
+void timer_tim6_init(uint freq);
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);
@@ -442,6 +448,30 @@ static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t
{
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;
return 0;
}