first commit

This commit is contained in:
2022-08-24 08:41:00 +02:00
commit 5765dbd675
2497 changed files with 2244854 additions and 0 deletions
@@ -0,0 +1,132 @@
/**
******************************************************************************
* @file usbd_msc.h
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief Header for the usbd_msc.c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_MSC_H
#define __USBD_MSC_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_msc_bot.h"
#include "usbd_msc_scsi.h"
#include "usbd_ioreq.h"
/** @addtogroup USBD_MSC_BOT
* @{
*/
/** @defgroup USBD_MSC
* @brief This file is the Header file for usbd_msc.c
* @{
*/
/** @defgroup USBD_BOT_Exported_Defines
* @{
*/
#define MSC_MAX_FS_PACKET 0x40
#define MSC_MAX_HS_PACKET 0x200
#define BOT_GET_MAX_LUN 0xFE
#define BOT_RESET 0xFF
#define USB_MSC_CONFIG_DESC_SIZ 32
#define MSC_EPIN_ADDR 0x81
#define MSC_EPOUT_ADDR 0x01
/**
* @}
*/
/** @defgroup USB_CORE_Exported_Types
* @{
*/
typedef struct _USBD_STORAGE
{
int8_t (* Init) (uint8_t lun);
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 (* 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);
int8_t *pInquiry;
}USBD_StorageTypeDef;
typedef struct
{
uint32_t max_lun;
uint32_t interface;
uint8_t bot_state;
uint8_t bot_status;
uint16_t bot_data_length;
uint8_t bot_data[MSC_MEDIA_PACKET];
USBD_MSC_BOT_CBWTypeDef cbw;
USBD_MSC_BOT_CSWTypeDef csw;
USBD_SCSI_SenseTypeDef scsi_sense [SENSE_LIST_DEEPTH];
uint8_t scsi_sense_head;
uint8_t scsi_sense_tail;
uint16_t scsi_blk_size;
uint32_t scsi_blk_nbr;
uint32_t scsi_blk_addr;
uint32_t scsi_blk_len;
}
USBD_MSC_BOT_HandleTypeDef;
/* Structure for MSC process */
extern USBD_ClassTypeDef USBD_MSC;
#define USBD_MSC_CLASS &USBD_MSC
uint8_t USBD_MSC_RegisterStorage (USBD_HandleTypeDef *pdev,
USBD_StorageTypeDef *fops);
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBD_MSC_H */
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,158 @@
/**
******************************************************************************
* @file usbd_msc_bot.h
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief Header for the usbd_msc_bot.c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_MSC_BOT_H
#define __USBD_MSC_BOT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_core.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup MSC_BOT
* @brief This file is the Header file for usbd_msc_bot.c
* @{
*/
/** @defgroup USBD_CORE_Exported_Defines
* @{
*/
#define USBD_BOT_IDLE 0 /* Idle state */
#define USBD_BOT_DATA_OUT 1 /* Data Out state */
#define USBD_BOT_DATA_IN 2 /* Data In state */
#define USBD_BOT_LAST_DATA_IN 3 /* Last Data In Last */
#define USBD_BOT_SEND_DATA 4 /* Send Immediate data */
#define USBD_BOT_NO_DATA 5 /* No data Stage */
#define USBD_BOT_CBW_SIGNATURE 0x43425355
#define USBD_BOT_CSW_SIGNATURE 0x53425355
#define USBD_BOT_CBW_LENGTH 31
#define USBD_BOT_CSW_LENGTH 13
#define USBD_BOT_MAX_DATA 256
/* CSW Status Definitions */
#define USBD_CSW_CMD_PASSED 0x00
#define USBD_CSW_CMD_FAILED 0x01
#define USBD_CSW_PHASE_ERROR 0x02
/* BOT Status */
#define USBD_BOT_STATUS_NORMAL 0
#define USBD_BOT_STATUS_RECOVERY 1
#define USBD_BOT_STATUS_ERROR 2
#define USBD_DIR_IN 0
#define USBD_DIR_OUT 1
#define USBD_BOTH_DIR 2
/**
* @}
*/
/** @defgroup MSC_CORE_Private_TypesDefinitions
* @{
*/
typedef struct
{
uint32_t dSignature;
uint32_t dTag;
uint32_t dDataLength;
uint8_t bmFlags;
uint8_t bLUN;
uint8_t bCBLength;
uint8_t CB[16];
uint8_t ReservedForAlign;
}
USBD_MSC_BOT_CBWTypeDef;
typedef struct
{
uint32_t dSignature;
uint32_t dTag;
uint32_t dDataResidue;
uint8_t bStatus;
uint8_t ReservedForAlign[3];
}
USBD_MSC_BOT_CSWTypeDef;
/**
* @}
*/
/** @defgroup USBD_CORE_Exported_Types
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CORE_Exported_FunctionsPrototypes
* @{
*/
void MSC_BOT_Init (USBD_HandleTypeDef *pdev);
void MSC_BOT_Reset (USBD_HandleTypeDef *pdev);
void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev);
void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev,
uint8_t epnum);
void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev,
uint8_t epnum);
void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev,
uint8_t CSW_Status);
void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev,
uint8_t epnum);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBD_MSC_BOT_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,111 @@
/**
******************************************************************************
* @file usbd_msc_data.h
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief Header for the usbd_msc_data.c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_MSC_DATA_H
#define __USBD_MSC_DATA_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_conf.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup USB_INFO
* @brief general defines for the usb device library file
* @{
*/
/** @defgroup USB_INFO_Exported_Defines
* @{
*/
#define MODE_SENSE6_LEN 8
#define MODE_SENSE10_LEN 8
#define LENGTH_INQUIRY_PAGE00 7
#define LENGTH_FORMAT_CAPACITIES 20
/**
* @}
*/
/** @defgroup USBD_INFO_Exported_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_INFO_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_INFO_Exported_Variables
* @{
*/
extern const uint8_t MSC_Page00_Inquiry_Data[];
extern const uint8_t MSC_Mode_Sense6_data[];
extern const uint8_t MSC_Mode_Sense10_data[] ;
/**
* @}
*/
/** @defgroup USBD_INFO_Exported_FunctionsPrototype
* @{
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBD_MSC_DATA_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,201 @@
/**
******************************************************************************
* @file usbd_msc_scsi.h
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief Header for the usbd_msc_scsi.c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_MSC_SCSI_H
#define __USBD_MSC_SCSI_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_def.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_SCSI
* @brief header file for the storage disk file
* @{
*/
/** @defgroup USBD_SCSI_Exported_Defines
* @{
*/
#define SENSE_LIST_DEEPTH 4
/* SCSI Commands */
#define SCSI_FORMAT_UNIT 0x04
#define SCSI_INQUIRY 0x12
#define SCSI_MODE_SELECT6 0x15
#define SCSI_MODE_SELECT10 0x55
#define SCSI_MODE_SENSE6 0x1A
#define SCSI_MODE_SENSE10 0x5A
#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E
#define SCSI_READ6 0x08
#define SCSI_READ10 0x28
#define SCSI_READ12 0xA8
#define SCSI_READ16 0x88
#define SCSI_READ_CAPACITY10 0x25
#define SCSI_READ_CAPACITY16 0x9E
#define SCSI_REQUEST_SENSE 0x03
#define SCSI_START_STOP_UNIT 0x1B
#define SCSI_TEST_UNIT_READY 0x00
#define SCSI_WRITE6 0x0A
#define SCSI_WRITE10 0x2A
#define SCSI_WRITE12 0xAA
#define SCSI_WRITE16 0x8A
#define SCSI_VERIFY10 0x2F
#define SCSI_VERIFY12 0xAF
#define SCSI_VERIFY16 0x8F
#define SCSI_SEND_DIAGNOSTIC 0x1D
#define SCSI_READ_FORMAT_CAPACITIES 0x23
#define NO_SENSE 0
#define RECOVERED_ERROR 1
#define NOT_READY 2
#define MEDIUM_ERROR 3
#define HARDWARE_ERROR 4
#define ILLEGAL_REQUEST 5
#define UNIT_ATTENTION 6
#define DATA_PROTECT 7
#define BLANK_CHECK 8
#define VENDOR_SPECIFIC 9
#define COPY_ABORTED 10
#define ABORTED_COMMAND 11
#define VOLUME_OVERFLOW 13
#define MISCOMPARE 14
#define INVALID_CDB 0x20
#define INVALID_FIELED_IN_COMMAND 0x24
#define PARAMETER_LIST_LENGTH_ERROR 0x1A
#define INVALID_FIELD_IN_PARAMETER_LIST 0x26
#define ADDRESS_OUT_OF_RANGE 0x21
#define MEDIUM_NOT_PRESENT 0x3A
#define MEDIUM_HAVE_CHANGED 0x28
#define WRITE_PROTECTED 0x27
#define UNRECOVERED_READ_ERROR 0x11
#define WRITE_FAULT 0x03
#define READ_FORMAT_CAPACITY_DATA_LEN 0x0C
#define READ_CAPACITY10_DATA_LEN 0x08
#define MODE_SENSE10_DATA_LEN 0x08
#define MODE_SENSE6_DATA_LEN 0x04
#define REQUEST_SENSE_DATA_LEN 0x12
#define STANDARD_INQUIRY_DATA_LEN 0x24
#define BLKVFY 0x04
extern uint8_t Page00_Inquiry_Data[];
extern uint8_t Standard_Inquiry_Data[];
extern uint8_t Standard_Inquiry_Data2[];
extern uint8_t Mode_Sense6_data[];
extern uint8_t Mode_Sense10_data[];
extern uint8_t Scsi_Sense_Data[];
extern uint8_t ReadCapacity10_Data[];
extern uint8_t ReadFormatCapacity_Data [];
/**
* @}
*/
/** @defgroup USBD_SCSI_Exported_TypesDefinitions
* @{
*/
typedef struct _SENSE_ITEM {
char Skey;
union {
struct _ASCs {
char ASC;
char ASCQ;
}b;
unsigned int ASC;
char *pData;
} w;
} USBD_SCSI_SenseTypeDef;
/**
* @}
*/
/** @defgroup USBD_SCSI_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_SCSI_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBD_SCSI_Exported_FunctionsPrototype
* @{
*/
int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev,
uint8_t lun,
uint8_t *cmd);
void SCSI_SenseCode(USBD_HandleTypeDef *pdev,
uint8_t lun,
uint8_t sKey,
uint8_t ASC);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBD_MSC_SCSI_H */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,105 @@
/**
******************************************************************************
* @file usbd_msc_storage.h
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief Header file for the usbd_msc_storage.c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_MSC_STORAGE_H
#define __USBD_MSC_STORAGE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_msc.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_STORAGE
* @brief header file for the usbd_msc_storage.c file
* @{
*/
/** @defgroup USBD_STORAGE_Exported_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBD_STORAGE_Exported_Types
* @{
*/
/**
* @}
*/
/** @defgroup USBD_STORAGE_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_STORAGE_Exported_Variables
* @{
*/
extern USBD_StorageTypeDef USBD_MSC_Template_fops;
/**
* @}
*/
/** @defgroup USBD_STORAGE_Exported_FunctionsPrototype
* @{
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBD_MSC_STORAGE_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,609 @@
/**
******************************************************************************
* @file usbd_msc.c
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief This file provides all the MSC core functions.
*
* @verbatim
*
* ===================================================================
* MSC Class Description
* ===================================================================
* This module manages the MSC class V1.0 following the "Universal
* Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0
* Sep. 31, 1999".
* This driver implements the following aspects of the specification:
* - Bulk-Only Transport protocol
* - Subclass : SCSI transparent command set (ref. SCSI Primary Commands - 3 (SPC-3))
*
* @endverbatim
*
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_msc.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup MSC_CORE
* @brief Mass storage core module
* @{
*/
/** @defgroup MSC_CORE_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup MSC_CORE_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup MSC_CORE_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup MSC_CORE_Private_FunctionPrototypes
* @{
*/
uint8_t USBD_MSC_Init (USBD_HandleTypeDef *pdev,
uint8_t cfgidx);
uint8_t USBD_MSC_DeInit (USBD_HandleTypeDef *pdev,
uint8_t cfgidx);
uint8_t USBD_MSC_Setup (USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req);
uint8_t USBD_MSC_DataIn (USBD_HandleTypeDef *pdev,
uint8_t epnum);
uint8_t USBD_MSC_DataOut (USBD_HandleTypeDef *pdev,
uint8_t epnum);
uint8_t *USBD_MSC_GetHSCfgDesc (uint16_t *length);
uint8_t *USBD_MSC_GetFSCfgDesc (uint16_t *length);
uint8_t *USBD_MSC_GetOtherSpeedCfgDesc (uint16_t *length);
uint8_t *USBD_MSC_GetDeviceQualifierDescriptor (uint16_t *length);
/**
* @}
*/
/** @defgroup MSC_CORE_Private_Variables
* @{
*/
USBD_ClassTypeDef USBD_MSC =
{
USBD_MSC_Init,
USBD_MSC_DeInit,
USBD_MSC_Setup,
NULL, /*EP0_TxSent*/
NULL, /*EP0_RxReady*/
USBD_MSC_DataIn,
USBD_MSC_DataOut,
NULL, /*SOF */
NULL,
NULL,
USBD_MSC_GetHSCfgDesc,
USBD_MSC_GetFSCfgDesc,
USBD_MSC_GetOtherSpeedCfgDesc,
USBD_MSC_GetDeviceQualifierDescriptor,
};
/* USB Mass storage device Configuration Descriptor */
/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
__ALIGN_BEGIN uint8_t USBD_MSC_CfgHSDesc[USB_MSC_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuation Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
USB_MSC_CONFIG_DESC_SIZ,
0x00,
0x01, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: */
0x04, /* iConfiguration: */
0xC0, /* bmAttributes: */
0x32, /* MaxPower 100 mA */
/******************** Mass Storage interface ********************/
0x09, /* bLength: Interface Descriptor size */
0x04, /* bDescriptorType: */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints*/
0x08, /* bInterfaceClass: MSC Class */
0x06, /* bInterfaceSubClass : SCSI transparent*/
0x50, /* nInterfaceProtocol */
0x05, /* iInterface: */
/******************** Mass Storage Endpoints ********************/
0x07, /*Endpoint descriptor length = 7*/
0x05, /*Endpoint descriptor type */
MSC_EPIN_ADDR, /*Endpoint address (IN, address 1) */
0x02, /*Bulk endpoint type */
LOBYTE(MSC_MAX_HS_PACKET),
HIBYTE(MSC_MAX_HS_PACKET),
0x00, /*Polling interval in milliseconds */
0x07, /*Endpoint descriptor length = 7 */
0x05, /*Endpoint descriptor type */
MSC_EPOUT_ADDR, /*Endpoint address (OUT, address 1) */
0x02, /*Bulk endpoint type */
LOBYTE(MSC_MAX_HS_PACKET),
HIBYTE(MSC_MAX_HS_PACKET),
0x00 /*Polling interval in milliseconds*/
};
/* USB Mass storage device Configuration Descriptor */
/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
uint8_t USBD_MSC_CfgFSDesc[USB_MSC_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuation Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
USB_MSC_CONFIG_DESC_SIZ,
0x00,
0x01, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: */
0x04, /* iConfiguration: */
0xC0, /* bmAttributes: */
0x32, /* MaxPower 100 mA */
/******************** Mass Storage interface ********************/
0x09, /* bLength: Interface Descriptor size */
0x04, /* bDescriptorType: */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints*/
0x08, /* bInterfaceClass: MSC Class */
0x06, /* bInterfaceSubClass : SCSI transparent*/
0x50, /* nInterfaceProtocol */
0x05, /* iInterface: */
/******************** Mass Storage Endpoints ********************/
0x07, /*Endpoint descriptor length = 7*/
0x05, /*Endpoint descriptor type */
MSC_EPIN_ADDR, /*Endpoint address (IN, address 1) */
0x02, /*Bulk endpoint type */
LOBYTE(MSC_MAX_FS_PACKET),
HIBYTE(MSC_MAX_FS_PACKET),
0x00, /*Polling interval in milliseconds */
0x07, /*Endpoint descriptor length = 7 */
0x05, /*Endpoint descriptor type */
MSC_EPOUT_ADDR, /*Endpoint address (OUT, address 1) */
0x02, /*Bulk endpoint type */
LOBYTE(MSC_MAX_FS_PACKET),
HIBYTE(MSC_MAX_FS_PACKET),
0x00 /*Polling interval in milliseconds*/
};
__ALIGN_BEGIN uint8_t USBD_MSC_OtherSpeedCfgDesc[USB_MSC_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuation Descriptor size */
USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION,
USB_MSC_CONFIG_DESC_SIZ,
0x00,
0x01, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: */
0x04, /* iConfiguration: */
0xC0, /* bmAttributes: */
0x32, /* MaxPower 100 mA */
/******************** Mass Storage interface ********************/
0x09, /* bLength: Interface Descriptor size */
0x04, /* bDescriptorType: */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints*/
0x08, /* bInterfaceClass: MSC Class */
0x06, /* bInterfaceSubClass : SCSI transparent command set*/
0x50, /* nInterfaceProtocol */
0x05, /* iInterface: */
/******************** Mass Storage Endpoints ********************/
0x07, /*Endpoint descriptor length = 7*/
0x05, /*Endpoint descriptor type */
MSC_EPIN_ADDR, /*Endpoint address (IN, address 1) */
0x02, /*Bulk endpoint type */
0x40,
0x00,
0x00, /*Polling interval in milliseconds */
0x07, /*Endpoint descriptor length = 7 */
0x05, /*Endpoint descriptor type */
MSC_EPOUT_ADDR, /*Endpoint address (OUT, address 1) */
0x02, /*Bulk endpoint type */
0x40,
0x00,
0x00 /*Polling interval in milliseconds*/
};
/* USB Standard Device Descriptor */
__ALIGN_BEGIN uint8_t USBD_MSC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
{
USB_LEN_DEV_QUALIFIER_DESC,
USB_DESC_TYPE_DEVICE_QUALIFIER,
0x00,
0x02,
0x00,
0x00,
0x00,
MSC_MAX_FS_PACKET,
0x01,
0x00,
};
/**
* @}
*/
/** @defgroup MSC_CORE_Private_Functions
* @{
*/
/**
* @brief USBD_MSC_Init
* Initialize the mass storage configuration
* @param pdev: device instance
* @param cfgidx: configuration index
* @retval status
*/
uint8_t USBD_MSC_Init (USBD_HandleTypeDef *pdev,
uint8_t cfgidx)
{
int16_t ret = 0;
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
/* Open EP OUT */
USBD_LL_OpenEP(pdev,
MSC_EPOUT_ADDR,
USBD_EP_TYPE_BULK,
MSC_MAX_HS_PACKET);
/* Open EP IN */
USBD_LL_OpenEP(pdev,
MSC_EPIN_ADDR,
USBD_EP_TYPE_BULK,
MSC_MAX_HS_PACKET);
}
else
{
/* Open EP OUT */
USBD_LL_OpenEP(pdev,
MSC_EPOUT_ADDR,
USBD_EP_TYPE_BULK,
MSC_MAX_FS_PACKET);
/* Open EP IN */
USBD_LL_OpenEP(pdev,
MSC_EPIN_ADDR,
USBD_EP_TYPE_BULK,
MSC_MAX_FS_PACKET);
}
pdev->pClassData = USBD_malloc(sizeof (USBD_MSC_BOT_HandleTypeDef));
if(pdev->pClassData == NULL)
{
ret = 1;
}
else
{
/* Init the BOT layer */
MSC_BOT_Init(pdev);
ret = 0;
}
return ret;
}
/**
* @brief USBD_MSC_DeInit
* DeInitilaize the mass storage configuration
* @param pdev: device instance
* @param cfgidx: configuration index
* @retval status
*/
uint8_t USBD_MSC_DeInit (USBD_HandleTypeDef *pdev,
uint8_t cfgidx)
{
/* Close MSC EPs */
USBD_LL_CloseEP(pdev,
MSC_EPOUT_ADDR);
/* Open EP IN */
USBD_LL_CloseEP(pdev,
MSC_EPIN_ADDR);
/* De-Init the BOT layer */
MSC_BOT_DeInit(pdev);
/* Free MSC Class Resources */
if(pdev->pClassData != NULL)
{
USBD_free(pdev->pClassData);
pdev->pClassData = NULL;
}
return 0;
}
/**
* @brief USBD_MSC_Setup
* Handle the MSC specific requests
* @param pdev: device instance
* @param req: USB request
* @retval status
*/
uint8_t USBD_MSC_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*) pdev->pClassData;
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
/* Class request */
case USB_REQ_TYPE_CLASS :
switch (req->bRequest)
{
case BOT_GET_MAX_LUN :
if((req->wValue == 0) &&
(req->wLength == 1) &&
((req->bmRequest & 0x80) == 0x80))
{
hmsc->max_lun = ((USBD_StorageTypeDef *)pdev->pUserData)->GetMaxLun();
USBD_CtlSendData (pdev,
(uint8_t *)&hmsc->max_lun,
1);
}
else
{
USBD_CtlError(pdev , req);
return USBD_FAIL;
}
break;
case BOT_RESET :
if((req->wValue == 0) &&
(req->wLength == 0) &&
((req->bmRequest & 0x80) != 0x80))
{
MSC_BOT_Reset(pdev);
}
else
{
USBD_CtlError(pdev , req);
return USBD_FAIL;
}
break;
default:
USBD_CtlError(pdev , req);
return USBD_FAIL;
}
break;
/* Interface & Endpoint request */
case USB_REQ_TYPE_STANDARD:
switch (req->bRequest)
{
case USB_REQ_GET_INTERFACE :
USBD_CtlSendData (pdev,
(uint8_t *)&hmsc->interface,
1);
break;
case USB_REQ_SET_INTERFACE :
hmsc->interface = (uint8_t)(req->wValue);
break;
case USB_REQ_CLEAR_FEATURE:
/* Flush the FIFO and Clear the stall status */
USBD_LL_FlushEP(pdev, (uint8_t)req->wIndex);
/* Reactivate the EP */
USBD_LL_CloseEP (pdev , (uint8_t)req->wIndex);
if((((uint8_t)req->wIndex) & 0x80) == 0x80)
{
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
/* Open EP IN */
USBD_LL_OpenEP(pdev,
MSC_EPIN_ADDR,
USBD_EP_TYPE_BULK,
MSC_MAX_HS_PACKET);
}
else
{
/* Open EP IN */
USBD_LL_OpenEP(pdev,
MSC_EPIN_ADDR,
USBD_EP_TYPE_BULK,
MSC_MAX_FS_PACKET);
}
}
else
{
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
/* Open EP IN */
USBD_LL_OpenEP(pdev,
MSC_EPOUT_ADDR,
USBD_EP_TYPE_BULK,
MSC_MAX_HS_PACKET);
}
else
{
/* Open EP IN */
USBD_LL_OpenEP(pdev,
MSC_EPOUT_ADDR,
USBD_EP_TYPE_BULK,
MSC_MAX_FS_PACKET);
}
}
/* Handle BOT error */
MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex);
break;
}
break;
default:
break;
}
return 0;
}
/**
* @brief USBD_MSC_DataIn
* handle data IN Stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
uint8_t USBD_MSC_DataIn (USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
MSC_BOT_DataIn(pdev , epnum);
return 0;
}
/**
* @brief USBD_MSC_DataOut
* handle data OUT Stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
uint8_t USBD_MSC_DataOut (USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
MSC_BOT_DataOut(pdev , epnum);
return 0;
}
/**
* @brief USBD_MSC_GetHSCfgDesc
* return configuration descriptor
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
uint8_t *USBD_MSC_GetHSCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_MSC_CfgHSDesc);
return USBD_MSC_CfgHSDesc;
}
/**
* @brief USBD_MSC_GetFSCfgDesc
* return configuration descriptor
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
uint8_t *USBD_MSC_GetFSCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_MSC_CfgFSDesc);
return USBD_MSC_CfgFSDesc;
}
/**
* @brief USBD_MSC_GetOtherSpeedCfgDesc
* return other speed configuration descriptor
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
uint8_t *USBD_MSC_GetOtherSpeedCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_MSC_OtherSpeedCfgDesc);
return USBD_MSC_OtherSpeedCfgDesc;
}
/**
* @brief DeviceQualifierDescriptor
* return Device Qualifier descriptor
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
uint8_t *USBD_MSC_GetDeviceQualifierDescriptor (uint16_t *length)
{
*length = sizeof (USBD_MSC_DeviceQualifierDesc);
return USBD_MSC_DeviceQualifierDesc;
}
/**
* @brief USBD_MSC_RegisterStorage
* @param fops: storage callback
* @retval status
*/
uint8_t USBD_MSC_RegisterStorage (USBD_HandleTypeDef *pdev,
USBD_StorageTypeDef *fops)
{
if(fops != NULL)
{
pdev->pUserData= fops;
}
return 0;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,407 @@
/**
******************************************************************************
* @file usbd_msc_bot.c
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief This file provides all the BOT protocol core functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_msc_bot.h"
#include "usbd_msc.h"
#include "usbd_msc_scsi.h"
#include "usbd_ioreq.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup MSC_BOT
* @brief BOT protocol module
* @{
*/
/** @defgroup MSC_BOT_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup MSC_BOT_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup MSC_BOT_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup MSC_BOT_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup MSC_BOT_Private_FunctionPrototypes
* @{
*/
static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev);
static void MSC_BOT_SendData (USBD_HandleTypeDef *pdev,
uint8_t* pbuf,
uint16_t len);
static void MSC_BOT_Abort(USBD_HandleTypeDef *pdev);
/**
* @}
*/
/** @defgroup MSC_BOT_Private_Functions
* @{
*/
/**
* @brief MSC_BOT_Init
* Initialize the BOT Process
* @param pdev: device instance
* @retval None
*/
void MSC_BOT_Init (USBD_HandleTypeDef *pdev)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
hmsc->bot_state = USBD_BOT_IDLE;
hmsc->bot_status = USBD_BOT_STATUS_NORMAL;
hmsc->scsi_sense_tail = 0;
hmsc->scsi_sense_head = 0;
((USBD_StorageTypeDef *)pdev->pUserData)->Init(0);
USBD_LL_FlushEP(pdev, MSC_EPOUT_ADDR);
USBD_LL_FlushEP(pdev, MSC_EPIN_ADDR);
/* Prapare EP to Receive First BOT Cmd */
USBD_LL_PrepareReceive (pdev,
MSC_EPOUT_ADDR,
(uint8_t *)&hmsc->cbw,
USBD_BOT_CBW_LENGTH);
}
/**
* @brief MSC_BOT_Reset
* Reset the BOT Machine
* @param pdev: device instance
* @retval None
*/
void MSC_BOT_Reset (USBD_HandleTypeDef *pdev)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
hmsc->bot_state = USBD_BOT_IDLE;
hmsc->bot_status = USBD_BOT_STATUS_RECOVERY;
/* Prapare EP to Receive First BOT Cmd */
USBD_LL_PrepareReceive (pdev,
MSC_EPOUT_ADDR,
(uint8_t *)&hmsc->cbw,
USBD_BOT_CBW_LENGTH);
}
/**
* @brief MSC_BOT_DeInit
* Deinitialize the BOT Machine
* @param pdev: device instance
* @retval None
*/
void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
hmsc->bot_state = USBD_BOT_IDLE;
}
/**
* @brief MSC_BOT_DataIn
* Handle BOT IN data stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval None
*/
void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
switch (hmsc->bot_state)
{
case USBD_BOT_DATA_IN:
if(SCSI_ProcessCmd(pdev,
hmsc->cbw.bLUN,
&hmsc->cbw.CB[0]) < 0)
{
MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED);
}
break;
case USBD_BOT_SEND_DATA:
case USBD_BOT_LAST_DATA_IN:
MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED);
break;
default:
break;
}
}
/**
* @brief MSC_BOT_DataOut
* Process MSC OUT data
* @param pdev: device instance
* @param epnum: endpoint index
* @retval None
*/
void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
switch (hmsc->bot_state)
{
case USBD_BOT_IDLE:
MSC_BOT_CBW_Decode(pdev);
break;
case USBD_BOT_DATA_OUT:
if(SCSI_ProcessCmd(pdev,
hmsc->cbw.bLUN,
&hmsc->cbw.CB[0]) < 0)
{
MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED);
}
break;
default:
break;
}
}
/**
* @brief MSC_BOT_CBW_Decode
* Decode the CBW command and set the BOT state machine accordingly
* @param pdev: device instance
* @retval None
*/
static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
hmsc->csw.dTag = hmsc->cbw.dTag;
hmsc->csw.dDataResidue = hmsc->cbw.dDataLength;
if ((USBD_LL_GetRxDataSize (pdev ,MSC_EPOUT_ADDR) != USBD_BOT_CBW_LENGTH) ||
(hmsc->cbw.dSignature != USBD_BOT_CBW_SIGNATURE)||
(hmsc->cbw.bLUN > 1) ||
(hmsc->cbw.bCBLength < 1) ||
(hmsc->cbw.bCBLength > 16))
{
SCSI_SenseCode(pdev,
hmsc->cbw.bLUN,
ILLEGAL_REQUEST,
INVALID_CDB);
hmsc->bot_status = USBD_BOT_STATUS_ERROR;
MSC_BOT_Abort(pdev);
}
else
{
if(SCSI_ProcessCmd(pdev,
hmsc->cbw.bLUN,
&hmsc->cbw.CB[0]) < 0)
{
if(hmsc->bot_state == USBD_BOT_NO_DATA)
{
MSC_BOT_SendCSW (pdev,
USBD_CSW_CMD_FAILED);
}
else
{
MSC_BOT_Abort(pdev);
}
}
/*Burst xfer handled internally*/
else if ((hmsc->bot_state != USBD_BOT_DATA_IN) &&
(hmsc->bot_state != USBD_BOT_DATA_OUT) &&
(hmsc->bot_state != USBD_BOT_LAST_DATA_IN))
{
if (hmsc->bot_data_length > 0)
{
MSC_BOT_SendData(pdev,
hmsc->bot_data,
hmsc->bot_data_length);
}
else if (hmsc->bot_data_length == 0)
{
MSC_BOT_SendCSW (pdev,
USBD_CSW_CMD_PASSED);
}
}
}
}
/**
* @brief MSC_BOT_SendData
* Send the requested data
* @param pdev: device instance
* @param buf: pointer to data buffer
* @param len: Data Length
* @retval None
*/
static void MSC_BOT_SendData(USBD_HandleTypeDef *pdev,
uint8_t* buf,
uint16_t len)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
len = MIN (hmsc->cbw.dDataLength, len);
hmsc->csw.dDataResidue -= len;
hmsc->csw.bStatus = USBD_CSW_CMD_PASSED;
hmsc->bot_state = USBD_BOT_SEND_DATA;
USBD_LL_Transmit (pdev, MSC_EPIN_ADDR, buf, len);
}
/**
* @brief MSC_BOT_SendCSW
* Send the Command Status Wrapper
* @param pdev: device instance
* @param status : CSW status
* @retval None
*/
void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev,
uint8_t CSW_Status)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
hmsc->csw.dSignature = USBD_BOT_CSW_SIGNATURE;
hmsc->csw.bStatus = CSW_Status;
hmsc->bot_state = USBD_BOT_IDLE;
USBD_LL_Transmit (pdev,
MSC_EPIN_ADDR,
(uint8_t *)&hmsc->csw,
USBD_BOT_CSW_LENGTH);
/* Prepare EP to Receive next Cmd */
USBD_LL_PrepareReceive (pdev,
MSC_EPOUT_ADDR,
(uint8_t *)&hmsc->cbw,
USBD_BOT_CBW_LENGTH);
}
/**
* @brief MSC_BOT_Abort
* Abort the current transfer
* @param pdev: device instance
* @retval status
*/
static void MSC_BOT_Abort (USBD_HandleTypeDef *pdev)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
if ((hmsc->cbw.bmFlags == 0) &&
(hmsc->cbw.dDataLength != 0) &&
(hmsc->bot_status == USBD_BOT_STATUS_NORMAL) )
{
USBD_LL_StallEP(pdev, MSC_EPOUT_ADDR );
}
USBD_LL_StallEP(pdev, MSC_EPIN_ADDR);
if(hmsc->bot_status == USBD_BOT_STATUS_ERROR)
{
USBD_LL_PrepareReceive (pdev,
MSC_EPOUT_ADDR,
(uint8_t *)&hmsc->cbw,
USBD_BOT_CBW_LENGTH);
}
}
/**
* @brief MSC_BOT_CplClrFeature
* Complete the clear feature request
* @param pdev: device instance
* @param epnum: endpoint index
* @retval None
*/
void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
if(hmsc->bot_status == USBD_BOT_STATUS_ERROR )/* Bad CBW Signature */
{
USBD_LL_StallEP(pdev, MSC_EPIN_ADDR);
hmsc->bot_status = USBD_BOT_STATUS_NORMAL;
}
else if(((epnum & 0x80) == 0x80) && ( hmsc->bot_status != USBD_BOT_STATUS_RECOVERY))
{
MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED);
}
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,134 @@
/**
******************************************************************************
* @file usbd_msc_data.c
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief This file provides all the vital inquiry pages and sense data.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_msc_data.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup MSC_DATA
* @brief Mass storage info/data module
* @{
*/
/** @defgroup MSC_DATA_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup MSC_DATA_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup MSC_DATA_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup MSC_DATA_Private_Variables
* @{
*/
/* USB Mass storage Page 0 Inquiry Data */
const uint8_t MSC_Page00_Inquiry_Data[] = {//7
0x00,
0x00,
0x00,
(LENGTH_INQUIRY_PAGE00 - 4),
0x00,
0x80,
0x83
};
/* USB Mass storage sense 6 Data */
const uint8_t MSC_Mode_Sense6_data[] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00
};
/* USB Mass storage sense 10 Data */
const uint8_t MSC_Mode_Sense10_data[] = {
0x00,
0x06,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00
};
/**
* @}
*/
/** @defgroup MSC_DATA_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @defgroup MSC_DATA_Private_Functions
* @{
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,770 @@
/**
******************************************************************************
* @file usbd_msc_scsi.c
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief This file provides all the USBD SCSI layer functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_msc_bot.h"
#include "usbd_msc_scsi.h"
#include "usbd_msc.h"
#include "usbd_msc_data.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup MSC_SCSI
* @brief Mass storage SCSI layer module
* @{
*/
/** @defgroup MSC_SCSI_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup MSC_SCSI_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup MSC_SCSI_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup MSC_SCSI_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup MSC_SCSI_Private_FunctionPrototypes
* @{
*/
static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
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_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);
static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params);
static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev,
uint8_t lun ,
uint32_t blk_offset ,
uint16_t blk_nbr);
static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev,
uint8_t lun);
static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev,
uint8_t lun);
/**
* @}
*/
/** @defgroup MSC_SCSI_Private_Functions
* @{
*/
/**
* @brief SCSI_ProcessCmd
* Process SCSI commands
* @param pdev: device instance
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev,
uint8_t lun,
uint8_t *params)
{
switch (params[0])
{
case SCSI_TEST_UNIT_READY:
return SCSI_TestUnitReady(pdev, lun, params);
case SCSI_REQUEST_SENSE:
return SCSI_RequestSense (pdev, lun, params);
case SCSI_INQUIRY:
return SCSI_Inquiry(pdev, lun, params);
case SCSI_START_STOP_UNIT:
return SCSI_StartStopUnit(pdev, lun, params);
case SCSI_ALLOW_MEDIUM_REMOVAL:
return SCSI_StartStopUnit(pdev, lun, params);
case SCSI_MODE_SENSE6:
return SCSI_ModeSense6 (pdev, lun, params);
case SCSI_MODE_SENSE10:
return SCSI_ModeSense10 (pdev, lun, params);
case SCSI_READ_FORMAT_CAPACITIES:
return SCSI_ReadFormatCapacity(pdev, lun, params);
case SCSI_READ_CAPACITY10:
return SCSI_ReadCapacity10(pdev, lun, params);
case SCSI_READ10:
return SCSI_Read10(pdev, lun, params);
case SCSI_WRITE10:
return SCSI_Write10(pdev, lun, params);
case SCSI_VERIFY10:
return SCSI_Verify10(pdev, lun, params);
default:
SCSI_SenseCode(pdev,
lun,
ILLEGAL_REQUEST,
INVALID_CDB);
return -1;
}
}
/**
* @brief SCSI_TestUnitReady
* Process SCSI Test Unit Ready Command
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
/* case 9 : Hi > D0 */
if (hmsc->cbw.dDataLength != 0)
{
SCSI_SenseCode(pdev,
hmsc->cbw.bLUN,
ILLEGAL_REQUEST,
INVALID_CDB);
return -1;
}
if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
{
SCSI_SenseCode(pdev,
lun,
NOT_READY,
MEDIUM_NOT_PRESENT);
hmsc->bot_state = USBD_BOT_NO_DATA;
return -1;
}
hmsc->bot_data_length = 0;
return 0;
}
/**
* @brief SCSI_Inquiry
* Process Inquiry command
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
uint8_t* pPage;
uint16_t len;
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
if (params[1] & 0x01)/*Evpd is set*/
{
pPage = (uint8_t *)MSC_Page00_Inquiry_Data;
len = LENGTH_INQUIRY_PAGE00;
}
else
{
pPage = (uint8_t *)&((USBD_StorageTypeDef *)pdev->pUserData)->pInquiry[lun * STANDARD_INQUIRY_DATA_LEN];
len = pPage[4] + 5;
if (params[4] <= len)
{
len = params[4];
}
}
hmsc->bot_data_length = len;
while (len)
{
len--;
hmsc->bot_data[len] = pPage[len];
}
return 0;
}
/**
* @brief SCSI_ReadCapacity10
* Process Read Capacity 10 command
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size) != 0)
{
SCSI_SenseCode(pdev,
lun,
NOT_READY,
MEDIUM_NOT_PRESENT);
return -1;
}
else
{
hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 24);
hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 16);
hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 8);
hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1);
hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >> 24);
hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >> 16);
hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >> 8);
hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size);
hmsc->bot_data_length = 8;
return 0;
}
}
/**
* @brief SCSI_ReadFormatCapacity
* Process Read Format Capacity command
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
uint16_t blk_size;
uint32_t blk_nbr;
uint16_t i;
for(i=0 ; i < 12 ; i++)
{
hmsc->bot_data[i] = 0;
}
if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &blk_nbr, &blk_size) != 0)
{
SCSI_SenseCode(pdev,
lun,
NOT_READY,
MEDIUM_NOT_PRESENT);
return -1;
}
else
{
hmsc->bot_data[3] = 0x08;
hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1) >> 24);
hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1) >> 16);
hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1) >> 8);
hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1);
hmsc->bot_data[8] = 0x02;
hmsc->bot_data[9] = (uint8_t)(blk_size >> 16);
hmsc->bot_data[10] = (uint8_t)(blk_size >> 8);
hmsc->bot_data[11] = (uint8_t)(blk_size);
hmsc->bot_data_length = 12;
return 0;
}
}
/**
* @brief SCSI_ModeSense6
* Process Mode Sense6 command
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
uint16_t len = 8 ;
hmsc->bot_data_length = len;
while (len)
{
len--;
hmsc->bot_data[len] = MSC_Mode_Sense6_data[len];
}
return 0;
}
/**
* @brief SCSI_ModeSense10
* Process Mode Sense10 command
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
uint16_t len = 8;
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
hmsc->bot_data_length = len;
while (len)
{
len--;
hmsc->bot_data[len] = MSC_Mode_Sense10_data[len];
}
return 0;
}
/**
* @brief SCSI_RequestSense
* Process Request Sense command
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
uint8_t i;
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++)
{
hmsc->bot_data[i] = 0;
}
hmsc->bot_data[0] = 0x70;
hmsc->bot_data[7] = REQUEST_SENSE_DATA_LEN - 6;
if((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) {
hmsc->bot_data[2] = hmsc->scsi_sense[hmsc->scsi_sense_head].Skey;
hmsc->bot_data[12] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ;
hmsc->bot_data[13] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC;
hmsc->scsi_sense_head++;
if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH)
{
hmsc->scsi_sense_head = 0;
}
}
hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN;
if (params[4] <= REQUEST_SENSE_DATA_LEN)
{
hmsc->bot_data_length = params[4];
}
return 0;
}
/**
* @brief SCSI_SenseCode
* Load the last error code in the error list
* @param lun: Logical unit number
* @param sKey: Sense Key
* @param ASC: Additional Sense Key
* @retval none
*/
void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey = sKey;
hmsc->scsi_sense[hmsc->scsi_sense_tail].w.ASC = ASC << 8;
hmsc->scsi_sense_tail++;
if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH)
{
hmsc->scsi_sense_tail = 0;
}
}
/**
* @brief SCSI_StartStopUnit
* Process Start Stop Unit command
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*) pdev->pClassData;
hmsc->bot_data_length = 0;
return 0;
}
/**
* @brief SCSI_Read10
* Process Read10 command
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*) pdev->pClassData;
if(hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
{
/* case 10 : Ho <> Di */
if ((hmsc->cbw.bmFlags & 0x80) != 0x80)
{
SCSI_SenseCode(pdev,
hmsc->cbw.bLUN,
ILLEGAL_REQUEST,
INVALID_CDB);
return -1;
}
if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
{
SCSI_SenseCode(pdev,
lun,
NOT_READY,
MEDIUM_NOT_PRESENT);
return -1;
}
hmsc->scsi_blk_addr = (params[2] << 24) | \
(params[3] << 16) | \
(params[4] << 8) | \
params[5];
hmsc->scsi_blk_len = (params[7] << 8) | \
params[8];
if( SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr, hmsc->scsi_blk_len) < 0)
{
return -1; /* error */
}
hmsc->bot_state = USBD_BOT_DATA_IN;
hmsc->scsi_blk_addr *= hmsc->scsi_blk_size;
hmsc->scsi_blk_len *= hmsc->scsi_blk_size;
/* cases 4,5 : Hi <> Dn */
if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len)
{
SCSI_SenseCode(pdev,
hmsc->cbw.bLUN,
ILLEGAL_REQUEST,
INVALID_CDB);
return -1;
}
}
hmsc->bot_data_length = MSC_MEDIA_PACKET;
return SCSI_ProcessRead(pdev, lun);
}
/**
* @brief SCSI_Write10
* Process Write10 command
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
static int8_t SCSI_Write10 (USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*) pdev->pClassData;
if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
{
/* case 8 : Hi <> Do */
if ((hmsc->cbw.bmFlags & 0x80) == 0x80)
{
SCSI_SenseCode(pdev,
hmsc->cbw.bLUN,
ILLEGAL_REQUEST,
INVALID_CDB);
return -1;
}
/* Check whether Media is ready */
if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
{
SCSI_SenseCode(pdev,
lun,
NOT_READY,
MEDIUM_NOT_PRESENT);
return -1;
}
/* Check If media is write-protected */
if(((USBD_StorageTypeDef *)pdev->pUserData)->IsWriteProtected(lun) !=0 )
{
SCSI_SenseCode(pdev,
lun,
NOT_READY,
WRITE_PROTECTED);
return -1;
}
hmsc->scsi_blk_addr = (params[2] << 24) | \
(params[3] << 16) | \
(params[4] << 8) | \
params[5];
hmsc->scsi_blk_len = (params[7] << 8) | \
params[8];
/* check if LBA address is in the right range */
if(SCSI_CheckAddressRange(pdev,
lun,
hmsc->scsi_blk_addr,
hmsc->scsi_blk_len) < 0)
{
return -1; /* error */
}
hmsc->scsi_blk_addr *= hmsc->scsi_blk_size;
hmsc->scsi_blk_len *= hmsc->scsi_blk_size;
/* cases 3,11,13 : Hn,Ho <> D0 */
if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len)
{
SCSI_SenseCode(pdev,
hmsc->cbw.bLUN,
ILLEGAL_REQUEST,
INVALID_CDB);
return -1;
}
/* Prepare EP to receive first data packet */
hmsc->bot_state = USBD_BOT_DATA_OUT;
USBD_LL_PrepareReceive (pdev,
MSC_EPOUT_ADDR,
hmsc->bot_data,
MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET));
}
else /* Write Process ongoing */
{
return SCSI_ProcessWrite(pdev, lun);
}
return 0;
}
/**
* @brief SCSI_Verify10
* Process Verify10 command
* @param lun: Logical unit number
* @param params: Command parameters
* @retval status
*/
static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*) pdev->pClassData;
if ((params[1]& 0x02) == 0x02)
{
SCSI_SenseCode (pdev,
lun,
ILLEGAL_REQUEST,
INVALID_FIELED_IN_COMMAND);
return -1; /* Error, Verify Mode Not supported*/
}
if(SCSI_CheckAddressRange(pdev,
lun,
hmsc->scsi_blk_addr,
hmsc->scsi_blk_len) < 0)
{
return -1; /* error */
}
hmsc->bot_data_length = 0;
return 0;
}
/**
* @brief SCSI_CheckAddressRange
* Check address range
* @param lun: Logical unit number
* @param blk_offset: first block address
* @param blk_nbr: number of block to be processed
* @retval status
*/
static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev, uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*) pdev->pClassData;
if ((blk_offset + blk_nbr) > hmsc->scsi_blk_nbr )
{
SCSI_SenseCode(pdev,
lun,
ILLEGAL_REQUEST,
ADDRESS_OUT_OF_RANGE);
return -1;
}
return 0;
}
/**
* @brief SCSI_ProcessRead
* Handle Read Process
* @param lun: Logical unit number
* @retval status
*/
static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, uint8_t lun)
{
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData;
uint32_t len;
len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET);
if( ((USBD_StorageTypeDef *)pdev->pUserData)->Read(lun ,
hmsc->bot_data,
hmsc->scsi_blk_addr / hmsc->scsi_blk_size,
len / hmsc->scsi_blk_size) < 0)
{
SCSI_SenseCode(pdev,
lun,
HARDWARE_ERROR,
UNRECOVERED_READ_ERROR);
return -1;
}
USBD_LL_Transmit (pdev,
MSC_EPIN_ADDR,
hmsc->bot_data,
len);
hmsc->scsi_blk_addr += len;
hmsc->scsi_blk_len -= len;
/* case 6 : Hi = Di */
hmsc->csw.dDataResidue -= len;
if (hmsc->scsi_blk_len == 0)
{
hmsc->bot_state = USBD_BOT_LAST_DATA_IN;
}
return 0;
}
/**
* @brief SCSI_ProcessWrite
* Handle Write Process
* @param lun: Logical unit number
* @retval status
*/
static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, uint8_t lun)
{
uint32_t len;
USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*) pdev->pClassData;
len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET);
if(((USBD_StorageTypeDef *)pdev->pUserData)->Write(lun ,
hmsc->bot_data,
hmsc->scsi_blk_addr / hmsc->scsi_blk_size,
len / hmsc->scsi_blk_size) < 0)
{
SCSI_SenseCode(pdev,
lun,
HARDWARE_ERROR,
WRITE_FAULT);
return -1;
}
hmsc->scsi_blk_addr += len;
hmsc->scsi_blk_len -= len;
/* case 12 : Ho = Do */
hmsc->csw.dDataResidue -= len;
if (hmsc->scsi_blk_len == 0)
{
MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED);
}
else
{
/* Prepare EP to Receive next packet */
USBD_LL_PrepareReceive (pdev,
MSC_EPOUT_ADDR,
hmsc->bot_data,
MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET));
}
return 0;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,188 @@
/**
******************************************************************************
* @file usbd_msc_storage_template.c
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief Memory management layer
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_msc_storage_template.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Extern function prototypes ------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 0x10000
#define STORAGE_BLK_SIZ 0x200
int8_t STORAGE_Init (uint8_t lun);
int8_t STORAGE_GetCapacity (uint8_t lun,
uint32_t *block_num,
uint16_t *block_size);
int8_t STORAGE_IsReady (uint8_t lun);
int8_t STORAGE_IsWriteProtected (uint8_t lun);
int8_t STORAGE_Read (uint8_t lun,
uint8_t *buf,
uint32_t blk_addr,
uint16_t blk_len);
int8_t STORAGE_Write (uint8_t lun,
uint8_t *buf,
uint32_t blk_addr,
uint16_t blk_len);
int8_t STORAGE_GetMaxLun (void);
/* USB Mass storage Standard Inquiry Data */
int8_t STORAGE_Inquirydata[] = {//36
/* LUN 0 */
0x00,
0x80,
0x02,
0x02,
(STANDARD_INQUIRY_DATA_LEN - 5),
0x00,
0x00,
0x00,
'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'0', '.', '0' ,'1', /* Version : 4 Bytes */
};
USBD_StorageTypeDef USBD_MSC_Template_fops =
{
STORAGE_Init,
STORAGE_GetCapacity,
STORAGE_IsReady,
STORAGE_IsWriteProtected,
STORAGE_Read,
STORAGE_Write,
STORAGE_GetMaxLun,
STORAGE_Inquirydata,
};
/*******************************************************************************
* Function Name : Read_Memory
* Description : Handle the Read operation from the microSD card.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_Init (uint8_t lun)
{
return (0);
}
/*******************************************************************************
* Function Name : Read_Memory
* Description : Handle the Read operation from the STORAGE card.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_GetCapacity (uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
*block_num = STORAGE_BLK_NBR;
*block_size = STORAGE_BLK_SIZ;
return (0);
}
/*******************************************************************************
* Function Name : Read_Memory
* Description : Handle the Read operation from the STORAGE card.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_IsReady (uint8_t lun)
{
return (0);
}
/*******************************************************************************
* Function Name : Read_Memory
* Description : Handle the Read operation from the STORAGE card.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_IsWriteProtected (uint8_t lun)
{
return 0;
}
/*******************************************************************************
* Function Name : Read_Memory
* Description : Handle the Read operation from the STORAGE card.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_Read (uint8_t lun,
uint8_t *buf,
uint32_t blk_addr,
uint16_t blk_len)
{
return 0;
}
/*******************************************************************************
* Function Name : Write_Memory
* Description : Handle the Write operation to the STORAGE card.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_Write (uint8_t lun,
uint8_t *buf,
uint32_t blk_addr,
uint16_t blk_len)
{
return (0);
}
/*******************************************************************************
* Function Name : Write_Memory
* Description : Handle the Write operation to the STORAGE card.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_GetMaxLun (void)
{
return (STORAGE_LUN_NBR - 1);
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,169 @@
/**
******************************************************************************
* @file usbd_conf_template.h
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief Header file for the usbd_conf_template.c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_CONF_TEMPLATE_H
#define __USBD_CONF_TEMPLATE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32fxxx.h" /* replace 'stm32xxx' with your HAL driver header filename, ex: stm32f4xx.h */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_CONF
* @brief USB device low level driver configuration file
* @{
*/
/** @defgroup USBD_CONF_Exported_Defines
* @{
*/
#define USBD_MAX_NUM_INTERFACES 1
#define USBD_MAX_NUM_CONFIGURATION 1
#define USBD_MAX_STR_DESC_SIZ 0x100
#define USBD_SUPPORT_USER_STRING 0
#define USBD_SELF_POWERED 1
#define USBD_DEBUG_LEVEL 2
/* MSC Class Config */
#define MSC_MEDIA_PACKET 8192
/* CDC Class Config */
#define USBD_CDC_INTERVAL 2000
/* DFU Class Config */
#define USBD_DFU_MAX_ITF_NUM 1
#define USBD_DFU_XFERS_IZE 1024
/* AUDIO Class Config */
#define USBD_AUDIO_FREQ 22100
/** @defgroup USBD_Exported_Macros
* @{
*/
/* Memory management macros */
#define USBD_malloc malloc
#define USBD_free free
#define USBD_memset memset
#define USBD_memcpy memcpy
/* DEBUG macros */
#if (USBD_DEBUG_LEVEL > 0)
#define USBD_UsrLog(...) printf(__VA_ARGS__);\
printf("\n");
#else
#define USBD_UsrLog(...)
#endif
#if (USBD_DEBUG_LEVEL > 1)
#define USBD_ErrLog(...) printf("ERROR: ") ;\
printf(__VA_ARGS__);\
printf("\n");
#else
#define USBD_ErrLog(...)
#endif
#if (USBD_DEBUG_LEVEL > 2)
#define USBD_DbgLog(...) printf("DEBUG : ") ;\
printf(__VA_ARGS__);\
printf("\n");
#else
#define USBD_DbgLog(...)
#endif
/**
* @}
*/
/**
* @}
*/
/** @defgroup USBD_CONF_Exported_Types
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CONF_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CONF_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CONF_Exported_FunctionsPrototype
* @{
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBD_CONF_TEMPLATE_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,167 @@
/**
******************************************************************************
* @file usbd_core.h
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief Header file for usbd_core.c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_CORE_H
#define __USBD_CORE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_conf.h"
#include "usbd_def.h"
#include "usbd_ioreq.h"
#include "usbd_ctlreq.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_CORE
* @brief This file is the Header file for usbd_core.c file
* @{
*/
/** @defgroup USBD_CORE_Exported_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CORE_Exported_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CORE_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CORE_Exported_Variables
* @{
*/
#define USBD_SOF USBD_LL_SOF
/**
* @}
*/
/** @defgroup USBD_CORE_Exported_FunctionsPrototype
* @{
*/
USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id);
USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, USBD_ClassTypeDef *pclass);
USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup);
USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata);
USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata);
USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed);
USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);
USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);
USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev);
/* USBD Low Level Driver */
USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_DeInit (USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_Stop (USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_OpenEP (USBD_HandleTypeDef *pdev,
uint8_t ep_addr,
uint8_t ep_type,
uint16_t ep_mps);
USBD_StatusTypeDef USBD_LL_CloseEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
USBD_StatusTypeDef USBD_LL_FlushEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
USBD_StatusTypeDef USBD_LL_StallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
USBD_StatusTypeDef USBD_LL_ClearStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
uint8_t USBD_LL_IsStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
USBD_StatusTypeDef USBD_LL_SetUSBAddress (USBD_HandleTypeDef *pdev, uint8_t dev_addr);
USBD_StatusTypeDef USBD_LL_Transmit (USBD_HandleTypeDef *pdev,
uint8_t ep_addr,
uint8_t *pbuf,
uint16_t size);
USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev,
uint8_t ep_addr,
uint8_t *pbuf,
uint16_t size);
uint32_t USBD_LL_GetRxDataSize (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
void USBD_LL_Delay (uint32_t Delay);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBD_CORE_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,113 @@
/**
******************************************************************************
* @file usbd_req.h
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief Header file for the usbd_req.c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USB_REQUEST_H
#define __USB_REQUEST_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_def.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_REQ
* @brief header file for the usbd_req.c file
* @{
*/
/** @defgroup USBD_REQ_Exported_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBD_REQ_Exported_Types
* @{
*/
/**
* @}
*/
/** @defgroup USBD_REQ_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_REQ_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBD_REQ_Exported_FunctionsPrototype
* @{
*/
USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
void USBD_CtlError (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata);
void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USB_REQUEST_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,330 @@
/**
******************************************************************************
* @file usbd_def.h
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief General defines for the usb device library
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_DEF_H
#define __USBD_DEF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_conf.h"
/** @addtogroup STM32_USBD_DEVICE_LIBRARY
* @{
*/
/** @defgroup USB_DEF
* @brief general defines for the usb device library file
* @{
*/
/** @defgroup USB_DEF_Exported_Defines
* @{
*/
#ifndef NULL
#define NULL 0
#endif
#define USB_LEN_DEV_QUALIFIER_DESC 0x0A
#define USB_LEN_DEV_DESC 0x12
#define USB_LEN_CFG_DESC 0x09
#define USB_LEN_IF_DESC 0x09
#define USB_LEN_EP_DESC 0x07
#define USB_LEN_OTG_DESC 0x03
#define USB_LEN_LANGID_STR_DESC 0x04
#define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09
#define USBD_IDX_LANGID_STR 0x00
#define USBD_IDX_MFC_STR 0x01
#define USBD_IDX_PRODUCT_STR 0x02
#define USBD_IDX_SERIAL_STR 0x03
#define USBD_IDX_CONFIG_STR 0x04
#define USBD_IDX_INTERFACE_STR 0x05
#define USB_REQ_TYPE_STANDARD 0x00
#define USB_REQ_TYPE_CLASS 0x20
#define USB_REQ_TYPE_VENDOR 0x40
#define USB_REQ_TYPE_MASK 0x60
#define USB_REQ_RECIPIENT_DEVICE 0x00
#define USB_REQ_RECIPIENT_INTERFACE 0x01
#define USB_REQ_RECIPIENT_ENDPOINT 0x02
#define USB_REQ_RECIPIENT_MASK 0x03
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_DESC_TYPE_DEVICE 1
#define USB_DESC_TYPE_CONFIGURATION 2
#define USB_DESC_TYPE_STRING 3
#define USB_DESC_TYPE_INTERFACE 4
#define USB_DESC_TYPE_ENDPOINT 5
#define USB_DESC_TYPE_DEVICE_QUALIFIER 6
#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7
#define USB_DESC_TYPE_BOS 0x0F
#define USB_CONFIG_REMOTE_WAKEUP 2
#define USB_CONFIG_SELF_POWERED 1
#define USB_FEATURE_EP_HALT 0
#define USB_FEATURE_REMOTE_WAKEUP 1
#define USB_FEATURE_TEST_MODE 2
#define USB_DEVICE_CAPABITY_TYPE 0x10
#define USB_HS_MAX_PACKET_SIZE 512
#define USB_FS_MAX_PACKET_SIZE 64
#define USB_MAX_EP0_SIZE 64
/* Device Status */
#define USBD_STATE_DEFAULT 1
#define USBD_STATE_ADDRESSED 2
#define USBD_STATE_CONFIGURED 3
#define USBD_STATE_SUSPENDED 4
/* EP0 State */
#define USBD_EP0_IDLE 0
#define USBD_EP0_SETUP 1
#define USBD_EP0_DATA_IN 2
#define USBD_EP0_DATA_OUT 3
#define USBD_EP0_STATUS_IN 4
#define USBD_EP0_STATUS_OUT 5
#define USBD_EP0_STALL 6
#define USBD_EP_TYPE_CTRL 0
#define USBD_EP_TYPE_ISOC 1
#define USBD_EP_TYPE_BULK 2
#define USBD_EP_TYPE_INTR 3
/**
* @}
*/
/** @defgroup USBD_DEF_Exported_TypesDefinitions
* @{
*/
typedef struct usb_setup_req
{
uint8_t bmRequest;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
}USBD_SetupReqTypedef;
struct _USBD_HandleTypeDef;
typedef struct _Device_cb
{
uint8_t (*Init) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx);
uint8_t (*DeInit) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx);
/* Control Endpoints*/
uint8_t (*Setup) (struct _USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req);
uint8_t (*EP0_TxSent) (struct _USBD_HandleTypeDef *pdev );
uint8_t (*EP0_RxReady) (struct _USBD_HandleTypeDef *pdev );
/* Class Specific Endpoints*/
uint8_t (*DataIn) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
uint8_t (*DataOut) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
uint8_t (*SOF) (struct _USBD_HandleTypeDef *pdev);
uint8_t (*IsoINIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
uint8_t (*IsoOUTIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
uint8_t *(*GetHSConfigDescriptor)(uint16_t *length);
uint8_t *(*GetFSConfigDescriptor)(uint16_t *length);
uint8_t *(*GetOtherSpeedConfigDescriptor)(uint16_t *length);
uint8_t *(*GetDeviceQualifierDescriptor)(uint16_t *length);
#if (USBD_SUPPORT_USER_STRING == 1)
uint8_t *(*GetUsrStrDescriptor)(struct _USBD_HandleTypeDef *pdev ,uint8_t index, uint16_t *length);
#endif
} USBD_ClassTypeDef;
/* Following USB Device Speed */
typedef enum
{
USBD_SPEED_HIGH = 0,
USBD_SPEED_FULL = 1,
USBD_SPEED_LOW = 2,
}USBD_SpeedTypeDef;
/* Following USB Device status */
typedef enum {
USBD_OK = 0,
USBD_BUSY,
USBD_FAIL,
}USBD_StatusTypeDef;
/* USB Device descriptors structure */
typedef struct
{
uint8_t *(*GetDeviceDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t *(*GetLangIDStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t *(*GetManufacturerStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t *(*GetProductStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t *(*GetSerialStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t *(*GetConfigurationStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t *(*GetInterfaceStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
#if (USBD_LPM_ENABLED == 1)
uint8_t *(*GetBOSDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
#endif
} USBD_DescriptorsTypeDef;
/* USB Device handle structure */
typedef struct
{
uint32_t status;
uint32_t total_length;
uint32_t rem_length;
uint32_t maxpacket;
} USBD_EndpointTypeDef;
/* USB Device handle structure */
typedef struct _USBD_HandleTypeDef
{
uint8_t id;
uint32_t dev_config;
uint32_t dev_default_config;
uint32_t dev_config_status;
USBD_SpeedTypeDef dev_speed;
USBD_EndpointTypeDef ep_in[15];
USBD_EndpointTypeDef ep_out[15];
uint32_t ep0_state;
uint32_t ep0_data_len;
uint8_t dev_state;
uint8_t dev_old_state;
uint8_t dev_address;
uint8_t dev_connection_status;
uint8_t dev_test_mode;
uint32_t dev_remote_wakeup;
USBD_SetupReqTypedef request;
USBD_DescriptorsTypeDef *pDesc;
USBD_ClassTypeDef *pClass;
void *pClassData;
void *pUserData;
void *pData;
} USBD_HandleTypeDef;
/**
* @}
*/
/** @defgroup USBD_DEF_Exported_Macros
* @{
*/
#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \
(((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
#define LOBYTE(x) ((uint8_t)(x & 0x00FF))
#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#if defined ( __GNUC__ )
#ifndef __weak
#define __weak __attribute__((weak))
#endif /* __weak */
#ifndef __packed
#define __packed __attribute__((__packed__))
#endif /* __packed */
#endif /* __GNUC__ */
/* In HS mode and when the DMA is used, all variables and data structures dealing
with the DMA during the transaction process should be 4-bytes aligned */
#if defined (__GNUC__) /* GNU Compiler */
#define __ALIGN_END __attribute__ ((aligned (4)))
#define __ALIGN_BEGIN
#else
#define __ALIGN_END
#if defined (__CC_ARM) /* ARM Compiler */
#define __ALIGN_BEGIN __align(4)
#elif defined (__ICCARM__) /* IAR Compiler */
#define __ALIGN_BEGIN
#elif defined (__TASKING__) /* TASKING Compiler */
#define __ALIGN_BEGIN __align(4)
#endif /* __CC_ARM */
#endif /* __GNUC__ */
/**
* @}
*/
/** @defgroup USBD_DEF_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DEF_Exported_FunctionsPrototype
* @{
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBD_DEF_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,128 @@
/**
******************************************************************************
* @file usbd_ioreq.h
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief Header file for the usbd_ioreq.c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_IOREQ_H
#define __USBD_IOREQ_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_def.h"
#include "usbd_core.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_IOREQ
* @brief header file for the usbd_ioreq.c file
* @{
*/
/** @defgroup USBD_IOREQ_Exported_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBD_IOREQ_Exported_Types
* @{
*/
/**
* @}
*/
/** @defgroup USBD_IOREQ_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_IOREQ_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBD_IOREQ_Exported_FunctionsPrototype
* @{
*/
USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev,
uint8_t *buf,
uint16_t len);
USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev,
uint8_t *pbuf,
uint16_t len);
USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev,
uint8_t *pbuf,
uint16_t len);
USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev,
uint8_t *pbuf,
uint16_t len);
USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev);
uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev ,
uint8_t epnum);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBD_IOREQ_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,212 @@
/**
******************************************************************************
* @file usbd_conf_template.c
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief USB Device configuration and interface file
* This template should be copied to the user folder, renamed and customized
* following user needs.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_core.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @brief Initializes the Low Level portion of the Device driver.
* @param pdev: Device handle
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
{
return USBD_OK;
}
/**
* @brief De-Initializes the Low Level portion of the Device driver.
* @param pdev: Device handle
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev)
{
return USBD_OK;
}
/**
* @brief Starts the Low Level portion of the Device driver.
* @param pdev: Device handle
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev)
{
return USBD_OK;
}
/**
* @brief Stops the Low Level portion of the Device driver.
* @param pdev: Device handle
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev)
{
return USBD_OK;
}
/**
* @brief Opens an endpoint of the Low Level Driver.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @param ep_type: Endpoint Type
* @param ep_mps: Endpoint Max Packet Size
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev,
uint8_t ep_addr,
uint8_t ep_type,
uint16_t ep_mps)
{
return USBD_OK;
}
/**
* @brief Closes an endpoint of the Low Level Driver.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
return USBD_OK;
}
/**
* @brief Flushes an endpoint of the Low Level Driver.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
return USBD_OK;
}
/**
* @brief Sets a Stall condition on an endpoint of the Low Level Driver.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
return USBD_OK;
}
/**
* @brief Clears a Stall condition on an endpoint of the Low Level Driver.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
return USBD_OK;
}
/**
* @brief Returns Stall condition.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval Stall (1: Yes, 0: No)
*/
uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
return 0;
}
/**
* @brief Assigns a USB address to the device.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr)
{
return USBD_OK;
}
/**
* @brief Transmits data over an endpoint.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @param pbuf: Pointer to data to be sent
* @param size: Data size
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev,
uint8_t ep_addr,
uint8_t *pbuf,
uint16_t size)
{
return USBD_OK;
}
/**
* @brief Prepares an endpoint for reception.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @param pbuf: Pointer to data to be received
* @param size: Data size
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev,
uint8_t ep_addr,
uint8_t *pbuf,
uint16_t size)
{
return USBD_OK;
}
/**
* @brief Returns the last transferred packet size.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval Recived Data Size
*/
uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
return 0;
}
/**
* @brief Delays routine for the USB Device Library.
* @param Delay: Delay in ms
* @retval None
*/
void USBD_LL_Delay(uint32_t Delay)
{
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,565 @@
/**
******************************************************************************
* @file usbd_core.c
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief This file provides all the USBD core functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_core.h"
/** @addtogroup STM32_USBD_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_CORE
* @brief usbd core module
* @{
*/
/** @defgroup USBD_CORE_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CORE_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CORE_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CORE_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CORE_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CORE_Private_Functions
* @{
*/
/**
* @brief USBD_Init
* Initializes the device stack and load the class driver
* @param pdev: device instance
* @param pdesc: Descriptor structure address
* @param id: Low level core index
* @retval None
*/
USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id)
{
/* Check whether the USB Host handle is valid */
if(pdev == NULL)
{
USBD_ErrLog("Invalid Device handle");
return USBD_FAIL;
}
/* Unlink previous class*/
if(pdev->pClass != NULL)
{
pdev->pClass = NULL;
}
/* Assign USBD Descriptors */
if(pdesc != NULL)
{
pdev->pDesc = pdesc;
}
/* Set Device initial State */
pdev->dev_state = USBD_STATE_DEFAULT;
pdev->id = id;
/* Initialize low level driver */
USBD_LL_Init(pdev);
return USBD_OK;
}
/**
* @brief USBD_DeInit
* Re-Initialize th device library
* @param pdev: device instance
* @retval status: status
*/
USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev)
{
/* Set Default State */
pdev->dev_state = USBD_STATE_DEFAULT;
/* Free Class Resources */
pdev->pClass->DeInit(pdev, pdev->dev_config);
/* Stop the low level driver */
USBD_LL_Stop(pdev);
/* Initialize low level driver */
USBD_LL_DeInit(pdev);
return USBD_OK;
}
/**
* @brief USBD_RegisterClass
* Link class driver to Device Core.
* @param pDevice : Device Handle
* @param pclass: Class handle
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, USBD_ClassTypeDef *pclass)
{
USBD_StatusTypeDef status = USBD_OK;
if(pclass != 0)
{
/* link the class to the USB Device handle */
pdev->pClass = pclass;
status = USBD_OK;
}
else
{
USBD_ErrLog("Invalid Class handle");
status = USBD_FAIL;
}
return status;
}
/**
* @brief USBD_Start
* Start the USB Device Core.
* @param pdev: Device Handle
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev)
{
/* Start the low level driver */
USBD_LL_Start(pdev);
return USBD_OK;
}
/**
* @brief USBD_Stop
* Stop the USB Device Core.
* @param pdev: Device Handle
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev)
{
/* Free Class Resources */
pdev->pClass->DeInit(pdev, pdev->dev_config);
/* Stop the low level driver */
USBD_LL_Stop(pdev);
return USBD_OK;
}
/**
* @brief USBD_RunTestMode
* Launch test mode process
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev)
{
return USBD_OK;
}
/**
* @brief USBD_SetClassConfig
* Configure device and start the interface
* @param pdev: device instance
* @param cfgidx: configuration index
* @retval status
*/
USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
USBD_StatusTypeDef ret = USBD_FAIL;
if(pdev->pClass != NULL)
{
/* Set configuration and Start the Class*/
if(pdev->pClass->Init(pdev, cfgidx) == 0)
{
ret = USBD_OK;
}
}
return ret;
}
/**
* @brief USBD_ClrClassConfig
* Clear current configuration
* @param pdev: device instance
* @param cfgidx: configuration index
* @retval status: USBD_StatusTypeDef
*/
USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
/* Clear configuration and De-initialize the Class process*/
pdev->pClass->DeInit(pdev, cfgidx);
return USBD_OK;
}
/**
* @brief USBD_SetupStage
* Handle the setup stage
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup)
{
USBD_ParseSetupRequest(&pdev->request, psetup);
pdev->ep0_state = USBD_EP0_SETUP;
pdev->ep0_data_len = pdev->request.wLength;
switch (pdev->request.bmRequest & 0x1F)
{
case USB_REQ_RECIPIENT_DEVICE:
USBD_StdDevReq (pdev, &pdev->request);
break;
case USB_REQ_RECIPIENT_INTERFACE:
USBD_StdItfReq(pdev, &pdev->request);
break;
case USB_REQ_RECIPIENT_ENDPOINT:
USBD_StdEPReq(pdev, &pdev->request);
break;
default:
USBD_LL_StallEP(pdev , pdev->request.bmRequest & 0x80);
break;
}
return USBD_OK;
}
/**
* @brief USBD_DataOutStage
* Handle data OUT stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata)
{
USBD_EndpointTypeDef *pep;
if(epnum == 0)
{
pep = &pdev->ep_out[0];
if ( pdev->ep0_state == USBD_EP0_DATA_OUT)
{
if(pep->rem_length > pep->maxpacket)
{
pep->rem_length -= pep->maxpacket;
USBD_CtlContinueRx (pdev,
pdata,
MIN(pep->rem_length ,pep->maxpacket));
}
else
{
if((pdev->pClass->EP0_RxReady != NULL)&&
(pdev->dev_state == USBD_STATE_CONFIGURED))
{
pdev->pClass->EP0_RxReady(pdev);
}
USBD_CtlSendStatus(pdev);
}
}
}
else if((pdev->pClass->DataOut != NULL)&&
(pdev->dev_state == USBD_STATE_CONFIGURED))
{
pdev->pClass->DataOut(pdev, epnum);
}
return USBD_OK;
}
/**
* @brief USBD_DataInStage
* Handle data in stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev ,uint8_t epnum, uint8_t *pdata)
{
USBD_EndpointTypeDef *pep;
if(epnum == 0)
{
pep = &pdev->ep_in[0];
if ( pdev->ep0_state == USBD_EP0_DATA_IN)
{
if(pep->rem_length > pep->maxpacket)
{
pep->rem_length -= pep->maxpacket;
USBD_CtlContinueSendData (pdev,
pdata,
pep->rem_length);
/* Prepare endpoint for premature end of transfer */
USBD_LL_PrepareReceive (pdev,
0,
NULL,
0);
}
else
{ /* last packet is MPS multiple, so send ZLP packet */
if((pep->total_length % pep->maxpacket == 0) &&
(pep->total_length >= pep->maxpacket) &&
(pep->total_length < pdev->ep0_data_len ))
{
USBD_CtlContinueSendData(pdev , NULL, 0);
pdev->ep0_data_len = 0;
/* Prepare endpoint for premature end of transfer */
USBD_LL_PrepareReceive (pdev,
0,
NULL,
0);
}
else
{
if((pdev->pClass->EP0_TxSent != NULL)&&
(pdev->dev_state == USBD_STATE_CONFIGURED))
{
pdev->pClass->EP0_TxSent(pdev);
}
USBD_CtlReceiveStatus(pdev);
}
}
}
if (pdev->dev_test_mode == 1)
{
USBD_RunTestMode(pdev);
pdev->dev_test_mode = 0;
}
}
else if((pdev->pClass->DataIn != NULL)&&
(pdev->dev_state == USBD_STATE_CONFIGURED))
{
pdev->pClass->DataIn(pdev, epnum);
}
return USBD_OK;
}
/**
* @brief USBD_LL_Reset
* Handle Reset event
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev)
{
/* Open EP0 OUT */
USBD_LL_OpenEP(pdev,
0x00,
USBD_EP_TYPE_CTRL,
USB_MAX_EP0_SIZE);
pdev->ep_out[0].maxpacket = USB_MAX_EP0_SIZE;
/* Open EP0 IN */
USBD_LL_OpenEP(pdev,
0x80,
USBD_EP_TYPE_CTRL,
USB_MAX_EP0_SIZE);
pdev->ep_in[0].maxpacket = USB_MAX_EP0_SIZE;
/* Upon Reset call user call back */
pdev->dev_state = USBD_STATE_DEFAULT;
if (pdev->pClassData)
pdev->pClass->DeInit(pdev, pdev->dev_config);
return USBD_OK;
}
/**
* @brief USBD_LL_Reset
* Handle Reset event
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed)
{
pdev->dev_speed = speed;
return USBD_OK;
}
/**
* @brief USBD_Suspend
* Handle Suspend event
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev)
{
pdev->dev_old_state = pdev->dev_state;
pdev->dev_state = USBD_STATE_SUSPENDED;
return USBD_OK;
}
/**
* @brief USBD_Resume
* Handle Resume event
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev)
{
pdev->dev_state = pdev->dev_old_state;
return USBD_OK;
}
/**
* @brief USBD_SOF
* Handle SOF event
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev)
{
if(pdev->dev_state == USBD_STATE_CONFIGURED)
{
if(pdev->pClass->SOF != NULL)
{
pdev->pClass->SOF(pdev);
}
}
return USBD_OK;
}
/**
* @brief USBD_IsoINIncomplete
* Handle iso in incomplete event
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
return USBD_OK;
}
/**
* @brief USBD_IsoOUTIncomplete
* Handle iso out incomplete event
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
return USBD_OK;
}
/**
* @brief USBD_DevConnected
* Handle device connection event
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev)
{
return USBD_OK;
}
/**
* @brief USBD_DevDisconnected
* Handle device disconnection event
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev)
{
/* Free Class Resources */
pdev->dev_state = USBD_STATE_DEFAULT;
pdev->pClass->DeInit(pdev, pdev->dev_config);
return USBD_OK;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,782 @@
/**
******************************************************************************
* @file usbd_req.c
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief This file provides the standard USB requests following chapter 9.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_ctlreq.h"
#include "usbd_ioreq.h"
/** @addtogroup STM32_USBD_STATE_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_REQ
* @brief USB standard requests module
* @{
*/
/** @defgroup USBD_REQ_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_REQ_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBD_REQ_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_REQ_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBD_REQ_Private_FunctionPrototypes
* @{
*/
static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req);
static void USBD_SetAddress(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req);
static void USBD_SetConfig(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req);
static void USBD_GetConfig(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req);
static void USBD_GetStatus(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req);
static void USBD_SetFeature(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req);
static void USBD_ClrFeature(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req);
static uint8_t USBD_GetLen(uint8_t *buf);
/**
* @}
*/
/** @defgroup USBD_REQ_Private_Functions
* @{
*/
/**
* @brief USBD_StdDevReq
* Handle standard usb device requests
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req)
{
USBD_StatusTypeDef ret = USBD_OK;
switch (req->bRequest)
{
case USB_REQ_GET_DESCRIPTOR:
USBD_GetDescriptor (pdev, req) ;
break;
case USB_REQ_SET_ADDRESS:
USBD_SetAddress(pdev, req);
break;
case USB_REQ_SET_CONFIGURATION:
USBD_SetConfig (pdev , req);
break;
case USB_REQ_GET_CONFIGURATION:
USBD_GetConfig (pdev , req);
break;
case USB_REQ_GET_STATUS:
USBD_GetStatus (pdev , req);
break;
case USB_REQ_SET_FEATURE:
USBD_SetFeature (pdev , req);
break;
case USB_REQ_CLEAR_FEATURE:
USBD_ClrFeature (pdev , req);
break;
default:
USBD_CtlError(pdev , req);
break;
}
return ret;
}
/**
* @brief USBD_StdItfReq
* Handle standard usb interface requests
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req)
{
USBD_StatusTypeDef ret = USBD_OK;
switch (pdev->dev_state)
{
case USBD_STATE_CONFIGURED:
if (LOBYTE(req->wIndex) <= USBD_MAX_NUM_INTERFACES)
{
pdev->pClass->Setup (pdev, req);
if((req->wLength == 0)&& (ret == USBD_OK))
{
USBD_CtlSendStatus(pdev);
}
}
else
{
USBD_CtlError(pdev , req);
}
break;
default:
USBD_CtlError(pdev , req);
break;
}
return USBD_OK;
}
/**
* @brief USBD_StdEPReq
* Handle standard usb endpoint requests
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req)
{
uint8_t ep_addr;
USBD_StatusTypeDef ret = USBD_OK;
USBD_EndpointTypeDef *pep;
ep_addr = LOBYTE(req->wIndex);
/* Check if it is a class request */
if ((req->bmRequest & 0x60) == 0x20)
{
pdev->pClass->Setup (pdev, req);
return USBD_OK;
}
switch (req->bRequest)
{
case USB_REQ_SET_FEATURE :
switch (pdev->dev_state)
{
case USBD_STATE_ADDRESSED:
if ((ep_addr != 0x00) && (ep_addr != 0x80))
{
USBD_LL_StallEP(pdev , ep_addr);
}
break;
case USBD_STATE_CONFIGURED:
if (req->wValue == USB_FEATURE_EP_HALT)
{
if ((ep_addr != 0x00) && (ep_addr != 0x80))
{
USBD_LL_StallEP(pdev , ep_addr);
}
}
pdev->pClass->Setup (pdev, req);
USBD_CtlSendStatus(pdev);
break;
default:
USBD_CtlError(pdev , req);
break;
}
break;
case USB_REQ_CLEAR_FEATURE :
switch (pdev->dev_state)
{
case USBD_STATE_ADDRESSED:
if ((ep_addr != 0x00) && (ep_addr != 0x80))
{
USBD_LL_StallEP(pdev , ep_addr);
}
break;
case USBD_STATE_CONFIGURED:
if (req->wValue == USB_FEATURE_EP_HALT)
{
if ((ep_addr & 0x7F) != 0x00)
{
USBD_LL_ClearStallEP(pdev , ep_addr);
pdev->pClass->Setup (pdev, req);
}
USBD_CtlSendStatus(pdev);
}
break;
default:
USBD_CtlError(pdev , req);
break;
}
break;
case USB_REQ_GET_STATUS:
switch (pdev->dev_state)
{
case USBD_STATE_ADDRESSED:
if ((ep_addr & 0x7F) != 0x00)
{
USBD_LL_StallEP(pdev , ep_addr);
}
break;
case USBD_STATE_CONFIGURED:
pep = ((ep_addr & 0x80) == 0x80) ? &pdev->ep_in[ep_addr & 0x7F]:\
&pdev->ep_out[ep_addr & 0x7F];
if(USBD_LL_IsStallEP(pdev, ep_addr))
{
pep->status = 0x0001;
}
else
{
pep->status = 0x0000;
}
USBD_CtlSendData (pdev,
(uint8_t *)&pep->status,
2);
break;
default:
USBD_CtlError(pdev , req);
break;
}
break;
default:
break;
}
return ret;
}
/**
* @brief USBD_GetDescriptor
* Handle Get Descriptor requests
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req)
{
uint16_t len;
uint8_t *pbuf;
switch (req->wValue >> 8)
{
#if (USBD_LPM_ENABLED == 1)
case USB_DESC_TYPE_BOS:
pbuf = pdev->pDesc->GetBOSDescriptor(pdev->dev_speed, &len);
break;
#endif
case USB_DESC_TYPE_DEVICE:
pbuf = pdev->pDesc->GetDeviceDescriptor(pdev->dev_speed, &len);
break;
case USB_DESC_TYPE_CONFIGURATION:
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
pbuf = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(&len);
pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
}
else
{
pbuf = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(&len);
pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
}
break;
case USB_DESC_TYPE_STRING:
switch ((uint8_t)(req->wValue))
{
case USBD_IDX_LANGID_STR:
pbuf = pdev->pDesc->GetLangIDStrDescriptor(pdev->dev_speed, &len);
break;
case USBD_IDX_MFC_STR:
pbuf = pdev->pDesc->GetManufacturerStrDescriptor(pdev->dev_speed, &len);
break;
case USBD_IDX_PRODUCT_STR:
pbuf = pdev->pDesc->GetProductStrDescriptor(pdev->dev_speed, &len);
break;
case USBD_IDX_SERIAL_STR:
pbuf = pdev->pDesc->GetSerialStrDescriptor(pdev->dev_speed, &len);
break;
case USBD_IDX_CONFIG_STR:
pbuf = pdev->pDesc->GetConfigurationStrDescriptor(pdev->dev_speed, &len);
break;
case USBD_IDX_INTERFACE_STR:
pbuf = pdev->pDesc->GetInterfaceStrDescriptor(pdev->dev_speed, &len);
break;
default:
#if (USBD_SUPPORT_USER_STRING == 1)
pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue) , &len);
break;
#else
USBD_CtlError(pdev , req);
return;
#endif
}
break;
case USB_DESC_TYPE_DEVICE_QUALIFIER:
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
pbuf = (uint8_t *)pdev->pClass->GetDeviceQualifierDescriptor(&len);
break;
}
else
{
USBD_CtlError(pdev , req);
return;
}
case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
pbuf = (uint8_t *)pdev->pClass->GetOtherSpeedConfigDescriptor(&len);
pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION;
break;
}
else
{
USBD_CtlError(pdev , req);
return;
}
default:
USBD_CtlError(pdev , req);
return;
}
if((len != 0)&& (req->wLength != 0))
{
len = MIN(len , req->wLength);
USBD_CtlSendData (pdev,
pbuf,
len);
}
}
/**
* @brief USBD_SetAddress
* Set device address
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
static void USBD_SetAddress(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req)
{
uint8_t dev_addr;
if ((req->wIndex == 0) && (req->wLength == 0))
{
dev_addr = (uint8_t)(req->wValue) & 0x7F;
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
USBD_CtlError(pdev , req);
}
else
{
pdev->dev_address = dev_addr;
USBD_LL_SetUSBAddress(pdev, dev_addr);
USBD_CtlSendStatus(pdev);
if (dev_addr != 0)
{
pdev->dev_state = USBD_STATE_ADDRESSED;
}
else
{
pdev->dev_state = USBD_STATE_DEFAULT;
}
}
}
else
{
USBD_CtlError(pdev , req);
}
}
/**
* @brief USBD_SetConfig
* Handle Set device configuration request
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
static void USBD_SetConfig(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req)
{
static uint8_t cfgidx;
cfgidx = (uint8_t)(req->wValue);
if (cfgidx > USBD_MAX_NUM_CONFIGURATION )
{
USBD_CtlError(pdev , req);
}
else
{
switch (pdev->dev_state)
{
case USBD_STATE_ADDRESSED:
if (cfgidx)
{
pdev->dev_config = cfgidx;
pdev->dev_state = USBD_STATE_CONFIGURED;
if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL)
{
USBD_CtlError(pdev , req);
return;
}
USBD_CtlSendStatus(pdev);
}
else
{
USBD_CtlSendStatus(pdev);
}
break;
case USBD_STATE_CONFIGURED:
if (cfgidx == 0)
{
pdev->dev_state = USBD_STATE_ADDRESSED;
pdev->dev_config = cfgidx;
USBD_ClrClassConfig(pdev , cfgidx);
USBD_CtlSendStatus(pdev);
}
else if (cfgidx != pdev->dev_config)
{
/* Clear old configuration */
USBD_ClrClassConfig(pdev , pdev->dev_config);
/* set new configuration */
pdev->dev_config = cfgidx;
if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL)
{
USBD_CtlError(pdev , req);
return;
}
USBD_CtlSendStatus(pdev);
}
else
{
USBD_CtlSendStatus(pdev);
}
break;
default:
USBD_CtlError(pdev , req);
break;
}
}
}
/**
* @brief USBD_GetConfig
* Handle Get device configuration request
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
static void USBD_GetConfig(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req)
{
if (req->wLength != 1)
{
USBD_CtlError(pdev , req);
}
else
{
switch (pdev->dev_state )
{
case USBD_STATE_ADDRESSED:
pdev->dev_default_config = 0;
USBD_CtlSendData (pdev,
(uint8_t *)&pdev->dev_default_config,
1);
break;
case USBD_STATE_CONFIGURED:
USBD_CtlSendData (pdev,
(uint8_t *)&pdev->dev_config,
1);
break;
default:
USBD_CtlError(pdev , req);
break;
}
}
}
/**
* @brief USBD_GetStatus
* Handle Get Status request
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
static void USBD_GetStatus(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req)
{
switch (pdev->dev_state)
{
case USBD_STATE_ADDRESSED:
case USBD_STATE_CONFIGURED:
#if ( USBD_SELF_POWERED == 1)
pdev->dev_config_status = USB_CONFIG_SELF_POWERED;
#else
pdev->dev_config_status = 0;
#endif
if (pdev->dev_remote_wakeup)
{
pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP;
}
USBD_CtlSendData (pdev,
(uint8_t *)& pdev->dev_config_status,
2);
break;
default :
USBD_CtlError(pdev , req);
break;
}
}
/**
* @brief USBD_SetFeature
* Handle Set device feature request
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
static void USBD_SetFeature(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req)
{
if (req->wValue == USB_FEATURE_REMOTE_WAKEUP)
{
pdev->dev_remote_wakeup = 1;
pdev->pClass->Setup (pdev, req);
USBD_CtlSendStatus(pdev);
}
}
/**
* @brief USBD_ClrFeature
* Handle clear device feature request
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
static void USBD_ClrFeature(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req)
{
switch (pdev->dev_state)
{
case USBD_STATE_ADDRESSED:
case USBD_STATE_CONFIGURED:
if (req->wValue == USB_FEATURE_REMOTE_WAKEUP)
{
pdev->dev_remote_wakeup = 0;
pdev->pClass->Setup (pdev, req);
USBD_CtlSendStatus(pdev);
}
break;
default :
USBD_CtlError(pdev , req);
break;
}
}
/**
* @brief USBD_ParseSetupRequest
* Copy buffer into setup structure
* @param pdev: device instance
* @param req: usb request
* @retval None
*/
void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata)
{
req->bmRequest = *(uint8_t *) (pdata);
req->bRequest = *(uint8_t *) (pdata + 1);
req->wValue = SWAPBYTE (pdata + 2);
req->wIndex = SWAPBYTE (pdata + 4);
req->wLength = SWAPBYTE (pdata + 6);
}
/**
* @brief USBD_CtlError
* Handle USB low level Error
* @param pdev: device instance
* @param req: usb request
* @retval None
*/
void USBD_CtlError( USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req)
{
USBD_LL_StallEP(pdev , 0x80);
USBD_LL_StallEP(pdev , 0);
}
/**
* @brief USBD_GetString
* Convert Ascii string into unicode one
* @param desc : descriptor buffer
* @param unicode : Formatted string buffer (unicode)
* @param len : descriptor length
* @retval None
*/
void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len)
{
uint8_t idx = 0;
if (desc != NULL)
{
*len = USBD_GetLen(desc) * 2 + 2;
unicode[idx++] = *len;
unicode[idx++] = USB_DESC_TYPE_STRING;
while (*desc != '\0')
{
unicode[idx++] = *desc++;
unicode[idx++] = 0x00;
}
}
}
/**
* @brief USBD_GetLen
* return the string length
* @param buf : pointer to the ascii string buffer
* @retval string length
*/
static uint8_t USBD_GetLen(uint8_t *buf)
{
uint8_t len = 0;
while (*buf != '\0')
{
len++;
buf++;
}
return len;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,236 @@
/**
******************************************************************************
* @file usbd_ioreq.c
* @author MCD Application Team
* @version V2.4.2
* @date 11-December-2015
* @brief This file provides the IO requests APIs for control endpoints.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_ioreq.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_IOREQ
* @brief control I/O requests module
* @{
*/
/** @defgroup USBD_IOREQ_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_IOREQ_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBD_IOREQ_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_IOREQ_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBD_IOREQ_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @defgroup USBD_IOREQ_Private_Functions
* @{
*/
/**
* @brief USBD_CtlSendData
* send data on the ctl pipe
* @param pdev: device instance
* @param buff: pointer to data buffer
* @param len: length of data to be sent
* @retval status
*/
USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev,
uint8_t *pbuf,
uint16_t len)
{
/* Set EP0 State */
pdev->ep0_state = USBD_EP0_DATA_IN;
pdev->ep_in[0].total_length = len;
pdev->ep_in[0].rem_length = len;
/* Start the transfer */
USBD_LL_Transmit (pdev, 0x00, pbuf, len);
return USBD_OK;
}
/**
* @brief USBD_CtlContinueSendData
* continue sending data on the ctl pipe
* @param pdev: device instance
* @param buff: pointer to data buffer
* @param len: length of data to be sent
* @retval status
*/
USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev,
uint8_t *pbuf,
uint16_t len)
{
/* Start the next transfer */
USBD_LL_Transmit (pdev, 0x00, pbuf, len);
return USBD_OK;
}
/**
* @brief USBD_CtlPrepareRx
* receive data on the ctl pipe
* @param pdev: device instance
* @param buff: pointer to data buffer
* @param len: length of data to be received
* @retval status
*/
USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev,
uint8_t *pbuf,
uint16_t len)
{
/* Set EP0 State */
pdev->ep0_state = USBD_EP0_DATA_OUT;
pdev->ep_out[0].total_length = len;
pdev->ep_out[0].rem_length = len;
/* Start the transfer */
USBD_LL_PrepareReceive (pdev,
0,
pbuf,
len);
return USBD_OK;
}
/**
* @brief USBD_CtlContinueRx
* continue receive data on the ctl pipe
* @param pdev: device instance
* @param buff: pointer to data buffer
* @param len: length of data to be received
* @retval status
*/
USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev,
uint8_t *pbuf,
uint16_t len)
{
USBD_LL_PrepareReceive (pdev,
0,
pbuf,
len);
return USBD_OK;
}
/**
* @brief USBD_CtlSendStatus
* send zero lzngth packet on the ctl pipe
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev)
{
/* Set EP0 State */
pdev->ep0_state = USBD_EP0_STATUS_IN;
/* Start the transfer */
USBD_LL_Transmit (pdev, 0x00, NULL, 0);
return USBD_OK;
}
/**
* @brief USBD_CtlReceiveStatus
* receive zero lzngth packet on the ctl pipe
* @param pdev: device instance
* @retval status
*/
USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev)
{
/* Set EP0 State */
pdev->ep0_state = USBD_EP0_STATUS_OUT;
/* Start the transfer */
USBD_LL_PrepareReceive ( pdev,
0,
NULL,
0);
return USBD_OK;
}
/**
* @brief USBD_GetRxCount
* returns the received data length
* @param pdev: device instance
* @param ep_addr: endpoint address
* @retval Rx Data blength
*/
uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , uint8_t ep_addr)
{
return USBD_LL_GetRxDataSize(pdev, ep_addr);
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,233 @@
/**
******************************************************************************
* @file usbh_msc.h
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief This file contains all the prototypes for the usbh_msc.c
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive ----------------------------------------------*/
#ifndef __USBH_MSC_H
#define __USBH_MSC_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbh_core.h"
#include "usbh_msc_bot.h"
#include "usbh_msc_scsi.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_CLASS
* @{
*/
/** @addtogroup USBH_MSC_CLASS
* @{
*/
/** @defgroup USBH_MSC_CORE
* @brief This file is the Header file for usbh_msc.c
* @{
*/
/** @defgroup USBH_MSC_CORE_Exported_Types
* @{
*/
typedef enum
{
MSC_INIT = 0,
MSC_IDLE,
MSC_TEST_UNIT_READY,
MSC_READ_CAPACITY10,
MSC_READ_INQUIRY,
MSC_REQUEST_SENSE,
MSC_READ,
MSC_WRITE,
MSC_UNRECOVERED_ERROR,
MSC_PERIODIC_CHECK,
}
MSC_StateTypeDef;
typedef enum
{
MSC_OK,
MSC_NOT_READY,
MSC_ERROR,
}
MSC_ErrorTypeDef;
typedef enum
{
MSC_REQ_IDLE = 0,
MSC_REQ_RESET,
MSC_REQ_GET_MAX_LUN,
MSC_REQ_ERROR,
}
MSC_ReqStateTypeDef;
#ifndef MAX_SUPPORTED_LUN
#define MAX_SUPPORTED_LUN 2
#endif
/* Structure for LUN */
typedef struct
{
MSC_StateTypeDef state;
MSC_ErrorTypeDef error;
USBH_StatusTypeDef prev_ready_state;
SCSI_CapacityTypeDef capacity;
SCSI_SenseTypeDef sense;
SCSI_StdInquiryDataTypeDef inquiry;
uint8_t state_changed;
}
MSC_LUNTypeDef;
/* Structure for MSC process */
typedef struct _MSC_Process
{
uint32_t max_lun;
uint8_t InPipe;
uint8_t OutPipe;
uint8_t OutEp;
uint8_t InEp;
uint16_t OutEpSize;
uint16_t InEpSize;
MSC_StateTypeDef state;
MSC_ErrorTypeDef error;
MSC_ReqStateTypeDef req_state;
MSC_ReqStateTypeDef prev_req_state;
BOT_HandleTypeDef hbot;
MSC_LUNTypeDef unit[MAX_SUPPORTED_LUN];
uint16_t current_lun;
uint16_t rw_lun;
uint32_t timer;
}
MSC_HandleTypeDef;
/**
* @}
*/
/** @defgroup USBH_MSC_CORE_Exported_Defines
* @{
*/
#define USB_REQ_BOT_RESET 0xFF
#define USB_REQ_GET_MAX_LUN 0xFE
/* MSC Class Codes */
#define USB_MSC_CLASS 0x08
/* Interface Descriptor field values for HID Boot Protocol */
#define MSC_BOT 0x50
#define MSC_TRANSPARENT 0x06
/**
* @}
*/
/** @defgroup USBH_MSC_CORE_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_CORE_Exported_Variables
* @{
*/
extern USBH_ClassTypeDef USBH_msc;
#define USBH_MSC_CLASS &USBH_msc
/**
* @}
*/
/** @defgroup USBH_MSC_CORE_Exported_FunctionsPrototype
* @{
*/
/* Common APIs */
uint8_t USBH_MSC_IsReady (USBH_HandleTypeDef *phost);
/* APIs for LUN */
int8_t USBH_MSC_GetMaxLUN (USBH_HandleTypeDef *phost);
uint8_t USBH_MSC_UnitIsReady (USBH_HandleTypeDef *phost, uint8_t lun);
USBH_StatusTypeDef USBH_MSC_GetLUNInfo(USBH_HandleTypeDef *phost, uint8_t lun, MSC_LUNTypeDef *info);
USBH_StatusTypeDef USBH_MSC_Read(USBH_HandleTypeDef *phost,
uint8_t lun,
uint32_t address,
uint8_t *pbuf,
uint32_t length);
USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost,
uint8_t lun,
uint32_t address,
uint8_t *pbuf,
uint32_t length);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBH_MSC_H */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,241 @@
/**
******************************************************************************
* @file usbh_msc_bot.h
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief Header file for usbh_msc_bot.c
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive ----------------------------------------------*/
#ifndef __USBH_MSC_BOT_H
#define __USBH_MSC_BOT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbh_core.h"
#include "usbh_msc_bot.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_CLASS
* @{
*/
/** @addtogroup USBH_MSC_CLASS
* @{
*/
/** @defgroup USBH_MSC_BOT
* @brief This file is the Header file for usbh_msc_bot.c
* @{
*/
/** @defgroup USBH_MSC_BOT_Exported_Types
* @{
*/
typedef enum {
BOT_OK = 0,
BOT_FAIL = 1,
BOT_PHASE_ERROR = 2,
BOT_BUSY = 3
}
BOT_StatusTypeDef;
typedef enum {
BOT_CMD_IDLE = 0,
BOT_CMD_SEND,
BOT_CMD_WAIT,
}
BOT_CMDStateTypeDef;
/* CSW Status Definitions */
typedef enum
{
BOT_CSW_CMD_PASSED = 0x00,
BOT_CSW_CMD_FAILED = 0x01,
BOT_CSW_PHASE_ERROR = 0x02,
}
BOT_CSWStatusTypeDef;
typedef enum {
BOT_SEND_CBW = 1,
BOT_SEND_CBW_WAIT,
BOT_DATA_IN,
BOT_DATA_IN_WAIT,
BOT_DATA_OUT,
BOT_DATA_OUT_WAIT,
BOT_RECEIVE_CSW,
BOT_RECEIVE_CSW_WAIT,
BOT_ERROR_IN,
BOT_ERROR_OUT,
BOT_UNRECOVERED_ERROR
}
BOT_StateTypeDef;
typedef union
{
struct __CBW
{
uint32_t Signature;
uint32_t Tag;
uint32_t DataTransferLength;
uint8_t Flags;
uint8_t LUN;
uint8_t CBLength;
uint8_t CB[16];
}field;
uint8_t data[31];
}
BOT_CBWTypeDef;
typedef union
{
struct __CSW
{
uint32_t Signature;
uint32_t Tag;
uint32_t DataResidue;
uint8_t Status;
}field;
uint8_t data[13];
}
BOT_CSWTypeDef;
typedef struct
{
uint32_t data[16];
BOT_StateTypeDef state;
BOT_StateTypeDef prev_state;
BOT_CMDStateTypeDef cmd_state;
BOT_CBWTypeDef cbw;
uint8_t Reserved1;
BOT_CSWTypeDef csw;
uint8_t Reserved2[3];
uint8_t *pbuf;
}
BOT_HandleTypeDef;
/**
* @}
*/
/** @defgroup USBH_MSC_BOT_Exported_Defines
* @{
*/
#define BOT_CBW_SIGNATURE 0x43425355
#define BOT_CBW_TAG 0x20304050
#define BOT_CSW_SIGNATURE 0x53425355
#define BOT_CBW_LENGTH 31
#define BOT_CSW_LENGTH 13
#define BOT_SEND_CSW_DISABLE 0
#define BOT_SEND_CSW_ENABLE 1
#define BOT_DIR_IN 0
#define BOT_DIR_OUT 1
#define BOT_DIR_BOTH 2
#define BOT_PAGE_LENGTH 512
#define BOT_CBW_CB_LENGTH 16
#define USB_REQ_BOT_RESET 0xFF
#define USB_REQ_GET_MAX_LUN 0xFE
#define MAX_BULK_STALL_COUNT_LIMIT 0x04 /* If STALL is seen on Bulk
Endpoint continuously, this means
that device and Host has phase error
Hence a Reset is needed */
/**
* @}
*/
/** @defgroup USBH_MSC_BOT_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_BOT_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_BOT_Exported_FunctionsPrototype
* @{
*/
USBH_StatusTypeDef USBH_MSC_BOT_REQ_Reset(USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_MSC_BOT_REQ_GetMaxLUN(USBH_HandleTypeDef *phost, uint8_t *Maxlun);
USBH_StatusTypeDef USBH_MSC_BOT_Init(USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun);
USBH_StatusTypeDef USBH_MSC_BOT_Error(USBH_HandleTypeDef *phost, uint8_t lun);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBH_MSC_BOT_H__ */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,226 @@
/**
******************************************************************************
* @file usbh_msc_scsi.h
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief Header file for usbh_msc_scsi.c
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive ----------------------------------------------*/
#ifndef __USBH_MSC_SCSI_H
#define __USBH_MSC_SCSI_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbh_core.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_CLASS
* @{
*/
/** @addtogroup USBH_MSC_CLASS
* @{
*/
/** @defgroup USBH_MSC_SCSI
* @brief This file is the Header file for usbh_msc_scsi.c
* @{
*/
// Capacity data.
typedef struct
{
uint32_t block_nbr;
uint16_t block_size;
} SCSI_CapacityTypeDef;
// Sense data.
typedef struct
{
uint8_t key;
uint8_t asc;
uint8_t ascq;
} SCSI_SenseTypeDef;
// INQUIRY data.
typedef struct
{
uint8_t PeripheralQualifier;
uint8_t DeviceType;
uint8_t RemovableMedia;
uint8_t vendor_id[9];
uint8_t product_id[17];
uint8_t revision_id[5];
}SCSI_StdInquiryDataTypeDef;
/** @defgroup USBH_MSC_SCSI_Exported_Defines
* @{
*/
#define OPCODE_TEST_UNIT_READY 0x00
#define OPCODE_READ_CAPACITY10 0x25
#define OPCODE_READ10 0x28
#define OPCODE_WRITE10 0x2A
#define OPCODE_REQUEST_SENSE 0x03
#define OPCODE_INQUIRY 0x12
#define DATA_LEN_MODE_TEST_UNIT_READY 0
#define DATA_LEN_READ_CAPACITY10 8
#define DATA_LEN_INQUIRY 36
#define DATA_LEN_REQUEST_SENSE 14
#define CBW_CB_LENGTH 16
#define CBW_LENGTH 10
/** @defgroup USBH_MSC_SCSI_Exported_Defines
* @{
*/
#define SCSI_SENSE_KEY_NO_SENSE 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
/**
* @}
*/
/** @defgroup USBH_MSC_SCSI_Exported_Defines
* @{
*/
#define SCSI_ASC_NO_ADDITIONAL_SENSE_INFORMATION 0x00
#define SCSI_ASC_LOGICAL_UNIT_NOT_READY 0x04
#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24
#define SCSI_ASC_WRITE_PROTECTED 0x27
#define SCSI_ASC_FORMAT_ERROR 0x31
#define SCSI_ASC_INVALID_COMMAND_OPERATION_CODE 0x20
#define SCSI_ASC_NOT_READY_TO_READY_CHANGE 0x28
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
/**
* @}
*/
/** @defgroup USBH_MSC_SCSI_Exported_Defines
* @{
*/
#define SCSI_ASCQ_FORMAT_COMMAND_FAILED 0x01
#define SCSI_ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02
#define SCSI_ASCQ_OPERATION_IN_PROGRESS 0x07
/**
* @}
*/
/** @defgroup USBH_MSC_SCSI_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup _Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_SCSI_Exported_FunctionsPrototype
* @{
*/
USBH_StatusTypeDef USBH_MSC_SCSI_TestUnitReady (USBH_HandleTypeDef *phost,
uint8_t lun);
USBH_StatusTypeDef USBH_MSC_SCSI_ReadCapacity (USBH_HandleTypeDef *phost,
uint8_t lun,
SCSI_CapacityTypeDef *capacity);
USBH_StatusTypeDef USBH_MSC_SCSI_Inquiry (USBH_HandleTypeDef *phost,
uint8_t lun,
SCSI_StdInquiryDataTypeDef *inquiry);
USBH_StatusTypeDef USBH_MSC_SCSI_RequestSense (USBH_HandleTypeDef *phost,
uint8_t lun,
SCSI_SenseTypeDef *sense_data);
USBH_StatusTypeDef USBH_MSC_SCSI_Write(USBH_HandleTypeDef *phost,
uint8_t lun,
uint32_t address,
uint8_t *pbuf,
uint32_t length);
USBH_StatusTypeDef USBH_MSC_SCSI_Read(USBH_HandleTypeDef *phost,
uint8_t lun,
uint32_t address,
uint8_t *pbuf,
uint32_t length);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBH_MSC_SCSI_H */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,805 @@
/**
******************************************************************************
* @file usbh_msc.c
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief This file implements the MSC class driver functions
* ===================================================================
* MSC Class Description
* ===================================================================
* This module manages the MSC class V1.0 following the "Universal
* Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0
* Sep. 31, 1999".
* This driver implements the following aspects of the specification:
* - Bulk-Only Transport protocol
* - Subclass : SCSI transparent command set (ref. SCSI Primary Commands - 3 (SPC-3))
*
* @endverbatim
*
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbh_msc.h"
#include "usbh_msc_bot.h"
#include "usbh_msc_scsi.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_CLASS
* @{
*/
/** @addtogroup USBH_MSC_CLASS
* @{
*/
/** @defgroup USBH_MSC_CORE
* @brief This file includes the mass storage related functions
* @{
*/
/** @defgroup USBH_MSC_CORE_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_CORE_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_CORE_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_CORE_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_CORE_Private_FunctionPrototypes
* @{
*/
static USBH_StatusTypeDef USBH_MSC_InterfaceInit (USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_MSC_InterfaceDeInit (USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun);
USBH_ClassTypeDef USBH_msc =
{
"MSC",
USB_MSC_CLASS,
USBH_MSC_InterfaceInit,
USBH_MSC_InterfaceDeInit,
USBH_MSC_ClassRequest,
USBH_MSC_Process,
USBH_MSC_SOFProcess,
NULL,
};
/**
* @}
*/
/** @defgroup USBH_MSC_CORE_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_CORE_Private_Functions
* @{
*/
/**
* @brief USBH_MSC_InterfaceInit
* The function init the MSC class.
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_MSC_InterfaceInit (USBH_HandleTypeDef *phost)
{
uint8_t interface = 0;
USBH_StatusTypeDef status = USBH_FAIL ;
MSC_HandleTypeDef *MSC_Handle;
interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, MSC_TRANSPARENT, MSC_BOT);
if(interface == 0xFF) /* Not Valid Interface */
{
USBH_DbgLog ("Cannot Find the interface for %s class.", phost->pActiveClass->Name);
status = USBH_FAIL;
}
else
{
USBH_SelectInterface (phost, interface);
phost->pActiveClass->pData = (MSC_HandleTypeDef *)USBH_malloc (sizeof(MSC_HandleTypeDef));
MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress & 0x80)
{
MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress);
MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize;
}
else
{
MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress);
MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize;
}
if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress & 0x80)
{
MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress);
MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize;
}
else
{
MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress);
MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize;
}
MSC_Handle->current_lun = 0;
MSC_Handle->rw_lun = 0;
MSC_Handle->state = MSC_INIT;
MSC_Handle->error = MSC_OK;
MSC_Handle->req_state = MSC_REQ_IDLE;
MSC_Handle->OutPipe = USBH_AllocPipe(phost, MSC_Handle->OutEp);
MSC_Handle->InPipe = USBH_AllocPipe(phost, MSC_Handle->InEp);
USBH_MSC_BOT_Init(phost);
/* De-Initialize LUNs information */
USBH_memset(MSC_Handle->unit, 0, sizeof(MSC_Handle->unit));
/* Open the new channels */
USBH_OpenPipe (phost,
MSC_Handle->OutPipe,
MSC_Handle->OutEp,
phost->device.address,
phost->device.speed,
USB_EP_TYPE_BULK,
MSC_Handle->OutEpSize);
USBH_OpenPipe (phost,
MSC_Handle->InPipe,
MSC_Handle->InEp,
phost->device.address,
phost->device.speed,
USB_EP_TYPE_BULK,
MSC_Handle->InEpSize);
USBH_LL_SetToggle (phost, MSC_Handle->InPipe,0);
USBH_LL_SetToggle (phost, MSC_Handle->OutPipe,0);
status = USBH_OK;
}
return status;
}
/**
* @brief USBH_MSC_InterfaceDeInit
* The function DeInit the Pipes used for the MSC class.
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_InterfaceDeInit (USBH_HandleTypeDef *phost)
{
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
if ( MSC_Handle->OutPipe)
{
USBH_ClosePipe(phost, MSC_Handle->OutPipe);
USBH_FreePipe (phost, MSC_Handle->OutPipe);
MSC_Handle->OutPipe = 0; /* Reset the Channel as Free */
}
if ( MSC_Handle->InPipe)
{
USBH_ClosePipe(phost, MSC_Handle->InPipe);
USBH_FreePipe (phost, MSC_Handle->InPipe);
MSC_Handle->InPipe = 0; /* Reset the Channel as Free */
}
if(phost->pActiveClass->pData)
{
USBH_free (phost->pActiveClass->pData);
phost->pActiveClass->pData = 0;
}
return USBH_OK;
}
/**
* @brief USBH_MSC_ClassRequest
* The function is responsible for handling Standard requests
* for MSC class.
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost)
{
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
USBH_StatusTypeDef status = USBH_BUSY;
uint8_t i;
/* Switch MSC REQ state machine */
switch (MSC_Handle->req_state)
{
case MSC_REQ_IDLE:
case MSC_REQ_GET_MAX_LUN:
/* Issue GetMaxLUN request */
status = USBH_MSC_BOT_REQ_GetMaxLUN(phost, (uint8_t *)&MSC_Handle->max_lun);
/* When devices do not support the GetMaxLun request, this should
be considred as only one logical unit is supported */
if(status == USBH_NOT_SUPPORTED)
{
MSC_Handle->max_lun = 0;
status = USBH_OK;
}
if(status == USBH_OK)
{
MSC_Handle->max_lun = (uint8_t )(MSC_Handle->max_lun) + 1;
USBH_UsrLog ("Number of supported LUN: %lu", (int32_t)(MSC_Handle->max_lun));
for(i = 0; i < MSC_Handle->max_lun; i++)
{
MSC_Handle->unit[i].prev_ready_state = USBH_FAIL;
MSC_Handle->unit[i].state_changed = 0;
}
}
break;
case MSC_REQ_ERROR :
/* a Clear Feature should be issued here */
if(USBH_ClrFeature(phost, 0x00) == USBH_OK)
{
MSC_Handle->req_state = MSC_Handle->prev_req_state;
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_MSC_Process
* The function is for managing state machine for MSC data transfers
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost)
{
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
USBH_StatusTypeDef error = USBH_BUSY ;
USBH_StatusTypeDef scsi_status = USBH_BUSY ;
USBH_StatusTypeDef ready_status = USBH_BUSY ;
switch (MSC_Handle->state)
{
case MSC_INIT:
if(MSC_Handle->current_lun < MSC_Handle->max_lun)
{
MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY;
/* Switch MSC REQ state machine */
switch (MSC_Handle->unit[MSC_Handle->current_lun].state)
{
case MSC_INIT:
USBH_UsrLog ("LUN #%d: ", MSC_Handle->current_lun);
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_INQUIRY;
MSC_Handle->timer = phost->Timer;
case MSC_READ_INQUIRY:
scsi_status = USBH_MSC_SCSI_Inquiry(phost, MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].inquiry);
if( scsi_status == USBH_OK)
{
USBH_UsrLog ("Inquiry Vendor : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.vendor_id);
USBH_UsrLog ("Inquiry Product : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.product_id);
USBH_UsrLog ("Inquiry Version : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.revision_id);
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY;
}
if( scsi_status == USBH_FAIL)
{
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
}
else if(scsi_status == USBH_UNRECOVERED_ERROR)
{
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
}
break;
case MSC_TEST_UNIT_READY:
ready_status = USBH_MSC_SCSI_TestUnitReady(phost, MSC_Handle->current_lun);
if( ready_status == USBH_OK)
{
if( MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_OK)
{
MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1;
USBH_UsrLog ("MSC Device ready");
}
else
{
MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0;
}
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_CAPACITY10;
MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK;
MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_OK;
}
if( ready_status == USBH_FAIL)
{
/* Media not ready, so try to check again during 10s */
if( MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_FAIL)
{
MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1;
USBH_UsrLog ("MSC Device NOT ready");
}
else
{
MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0;
}
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY;
MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_FAIL;
}
else if(ready_status == USBH_UNRECOVERED_ERROR)
{
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
}
break;
case MSC_READ_CAPACITY10:
scsi_status = USBH_MSC_SCSI_ReadCapacity(phost,MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].capacity) ;
if(scsi_status == USBH_OK)
{
if(MSC_Handle->unit[MSC_Handle->current_lun].state_changed == 1)
{
USBH_UsrLog ("MSC Device capacity : %lu Bytes", \
(int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr * MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size));
USBH_UsrLog ("Block number : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr));
USBH_UsrLog ("Block Size : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size));
}
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK;
MSC_Handle->current_lun++;
}
else if( scsi_status == USBH_FAIL)
{
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
}
else if(scsi_status == USBH_UNRECOVERED_ERROR)
{
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
}
break;
case MSC_REQUEST_SENSE:
scsi_status = USBH_MSC_SCSI_RequestSense(phost, MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].sense);
if( scsi_status == USBH_OK)
{
if((MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_UNIT_ATTENTION) ||
(MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_NOT_READY) )
{
if((phost->Timer - MSC_Handle->timer) < 10000)
{
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY;
break;
}
}
USBH_UsrLog ("Sense Key : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.key);
USBH_UsrLog ("Additional Sense Code : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.asc);
USBH_UsrLog ("Additional Sense Code Qualifier: %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.ascq);
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
MSC_Handle->current_lun++;
}
if( scsi_status == USBH_FAIL)
{
USBH_UsrLog ("MSC Device NOT ready");
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_UNRECOVERED_ERROR;
}
else if(scsi_status == USBH_UNRECOVERED_ERROR)
{
MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
}
break;
case MSC_UNRECOVERED_ERROR:
MSC_Handle->current_lun++;
break;
default:
break;
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
#endif
}
else
{
MSC_Handle->current_lun = 0;
MSC_Handle->state = MSC_IDLE;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
#endif
phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
}
break;
case MSC_IDLE:
error = USBH_OK;
break;
default:
break;
}
return error;
}
/**
* @brief USBH_MSC_SOFProcess
* The function is for SOF state
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost)
{
return USBH_OK;
}
/**
* @brief USBH_MSC_RdWrProcess
* The function is for managing state machine for MSC I/O Process
* @param phost: Host handle
* @param lun: logical Unit Number
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun)
{
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
USBH_StatusTypeDef error = USBH_BUSY ;
USBH_StatusTypeDef scsi_status = USBH_BUSY ;
/* Switch MSC REQ state machine */
switch (MSC_Handle->unit[lun].state)
{
case MSC_READ:
scsi_status = USBH_MSC_SCSI_Read(phost,lun, 0, NULL, 0) ;
if(scsi_status == USBH_OK)
{
MSC_Handle->unit[lun].state = MSC_IDLE;
error = USBH_OK;
}
else if( scsi_status == USBH_FAIL)
{
MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE;
}
else if(scsi_status == USBH_UNRECOVERED_ERROR)
{
MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
error = USBH_FAIL;
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
#endif
break;
case MSC_WRITE:
scsi_status = USBH_MSC_SCSI_Write(phost,lun, 0, NULL, 0) ;
if(scsi_status == USBH_OK)
{
MSC_Handle->unit[lun].state = MSC_IDLE;
error = USBH_OK;
}
else if( scsi_status == USBH_FAIL)
{
MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE;
}
else if(scsi_status == USBH_UNRECOVERED_ERROR)
{
MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
error = USBH_FAIL;
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
#endif
break;
case MSC_REQUEST_SENSE:
scsi_status = USBH_MSC_SCSI_RequestSense(phost, lun, &MSC_Handle->unit[lun].sense);
if( scsi_status == USBH_OK)
{
USBH_UsrLog ("Sense Key : %x", MSC_Handle->unit[lun].sense.key);
USBH_UsrLog ("Additional Sense Code : %x", MSC_Handle->unit[lun].sense.asc);
USBH_UsrLog ("Additional Sense Code Qualifier: %x", MSC_Handle->unit[lun].sense.ascq);
MSC_Handle->unit[lun].state = MSC_IDLE;
MSC_Handle->unit[lun].error = MSC_ERROR;
error = USBH_FAIL;
}
if( scsi_status == USBH_FAIL)
{
USBH_UsrLog ("MSC Device NOT ready");
}
else if(scsi_status == USBH_UNRECOVERED_ERROR)
{
MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
error = USBH_FAIL;
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
#endif
break;
default:
break;
}
return error;
}
/**
* @brief USBH_MSC_IsReady
* The function check if the MSC function is ready
* @param phost: Host handle
* @retval USBH Status
*/
uint8_t USBH_MSC_IsReady (USBH_HandleTypeDef *phost)
{
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
if(phost->gState == HOST_CLASS)
{
return (MSC_Handle->state == MSC_IDLE);
}
else
{
return 0;
}
}
/**
* @brief USBH_MSC_GetMaxLUN
* The function return the Max LUN supported
* @param phost: Host handle
* @retval logical Unit Number supported
*/
int8_t USBH_MSC_GetMaxLUN (USBH_HandleTypeDef *phost)
{
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
if ((phost->gState == HOST_CLASS) && (MSC_Handle->state == MSC_IDLE))
{
return MSC_Handle->max_lun;
}
return 0xFF;
}
/**
* @brief USBH_MSC_UnitIsReady
* The function check whether a LUN is ready
* @param phost: Host handle
* @param lun: logical Unit Number
* @retval Lun status (0: not ready / 1: ready)
*/
uint8_t USBH_MSC_UnitIsReady (USBH_HandleTypeDef *phost, uint8_t lun)
{
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
if(phost->gState == HOST_CLASS)
{
return (MSC_Handle->unit[lun].error == MSC_OK);
}
else
{
return 0;
}
}
/**
* @brief USBH_MSC_GetLUNInfo
* The function return a LUN information
* @param phost: Host handle
* @param lun: logical Unit Number
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_GetLUNInfo(USBH_HandleTypeDef *phost, uint8_t lun, MSC_LUNTypeDef *info)
{
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
if(phost->gState == HOST_CLASS)
{
USBH_memcpy(info,&MSC_Handle->unit[lun], sizeof(MSC_LUNTypeDef));
return USBH_OK;
}
else
{
return USBH_FAIL;
}
}
/**
* @brief USBH_MSC_Read
* The function performs a Read operation
* @param phost: Host handle
* @param lun: logical Unit Number
* @param address: sector address
* @param pbuf: pointer to data
* @param length: number of sector to read
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_Read(USBH_HandleTypeDef *phost,
uint8_t lun,
uint32_t address,
uint8_t *pbuf,
uint32_t length)
{
uint32_t timeout;
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
if ((phost->device.is_connected == 0) ||
(phost->gState != HOST_CLASS) ||
(MSC_Handle->unit[lun].state != MSC_IDLE))
{
return USBH_FAIL;
}
MSC_Handle->state = MSC_READ;
MSC_Handle->unit[lun].state = MSC_READ;
MSC_Handle->rw_lun = lun;
USBH_MSC_SCSI_Read(phost,
lun,
address,
pbuf,
length);
timeout = phost->Timer;
while (USBH_MSC_RdWrProcess(phost, lun) == USBH_BUSY)
{
if(((phost->Timer - timeout) > (10000 * length)) || (phost->device.is_connected == 0))
{
MSC_Handle->state = MSC_IDLE;
return USBH_FAIL;
}
}
MSC_Handle->state = MSC_IDLE;
return USBH_OK;
}
/**
* @brief USBH_MSC_Write
* The function performs a Write operation
* @param phost: Host handle
* @param lun: logical Unit Number
* @param address: sector address
* @param pbuf: pointer to data
* @param length: number of sector to write
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost,
uint8_t lun,
uint32_t address,
uint8_t *pbuf,
uint32_t length)
{
uint32_t timeout;
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
if ((phost->device.is_connected == 0) ||
(phost->gState != HOST_CLASS) ||
(MSC_Handle->unit[lun].state != MSC_IDLE))
{
return USBH_FAIL;
}
MSC_Handle->state = MSC_WRITE;
MSC_Handle->unit[lun].state = MSC_WRITE;
MSC_Handle->rw_lun = lun;
USBH_MSC_SCSI_Write(phost,
lun,
address,
pbuf,
length);
timeout = phost->Timer;
while (USBH_MSC_RdWrProcess(phost, lun) == USBH_BUSY)
{
if(((phost->Timer - timeout) > (10000 * length)) || (phost->device.is_connected == 0))
{
MSC_Handle->state = MSC_IDLE;
return USBH_FAIL;
}
}
MSC_Handle->state = MSC_IDLE;
return USBH_OK;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,633 @@
/**
******************************************************************************
* @file usbh_msc_bot.c
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief This file includes the BOT protocol related functions
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbh_msc_bot.h"
#include "usbh_msc.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_CLASS
* @{
*/
/** @addtogroup USBH_MSC_CLASS
* @{
*/
/** @defgroup USBH_MSC_BOT
* @brief This file includes the mass storage related functions
* @{
*/
/** @defgroup USBH_MSC_BOT_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_BOT_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_BOT_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_BOT_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_BOT_Private_FunctionPrototypes
* @{
*/
static USBH_StatusTypeDef USBH_MSC_BOT_Abort(USBH_HandleTypeDef *phost, uint8_t lun, uint8_t dir);
static BOT_CSWStatusTypeDef USBH_MSC_DecodeCSW(USBH_HandleTypeDef *phost);
/**
* @}
*/
/** @defgroup USBH_MSC_BOT_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_BOT_Private_Functions
* @{
*/
/**
* @brief USBH_MSC_BOT_REQ_Reset
* The function the MSC BOT Reset request.
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_BOT_REQ_Reset(USBH_HandleTypeDef *phost)
{
phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \
USB_REQ_RECIPIENT_INTERFACE;
phost->Control.setup.b.bRequest = USB_REQ_BOT_RESET;
phost->Control.setup.b.wValue.w = 0;
phost->Control.setup.b.wIndex.w = 0;
phost->Control.setup.b.wLength.w = 0;
return USBH_CtlReq(phost, 0 , 0 );
}
/**
* @brief USBH_MSC_BOT_REQ_GetMaxLUN
* The function the MSC BOT GetMaxLUN request.
* @param phost: Host handle
* @param Maxlun: pointer to Maxlun variable
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_BOT_REQ_GetMaxLUN(USBH_HandleTypeDef *phost, uint8_t *Maxlun)
{
phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \
USB_REQ_RECIPIENT_INTERFACE;
phost->Control.setup.b.bRequest = USB_REQ_GET_MAX_LUN;
phost->Control.setup.b.wValue.w = 0;
phost->Control.setup.b.wIndex.w = 0;
phost->Control.setup.b.wLength.w = 1;
return USBH_CtlReq(phost, Maxlun , 1 );
}
/**
* @brief USBH_MSC_BOT_Init
* The function Initializes the BOT protocol.
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_BOT_Init(USBH_HandleTypeDef *phost)
{
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
MSC_Handle->hbot.cbw.field.Signature = BOT_CBW_SIGNATURE;
MSC_Handle->hbot.cbw.field.Tag = BOT_CBW_TAG;
MSC_Handle->hbot.state = BOT_SEND_CBW;
MSC_Handle->hbot.cmd_state = BOT_CMD_SEND;
return USBH_OK;
}
/**
* @brief USBH_MSC_BOT_Process
* The function handle the BOT protocol.
* @param phost: Host handle
* @param lun: Logical Unit Number
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun)
{
USBH_StatusTypeDef status = USBH_BUSY;
USBH_StatusTypeDef error = USBH_BUSY;
BOT_CSWStatusTypeDef CSW_Status = BOT_CSW_CMD_FAILED;
USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
uint8_t toggle = 0;
switch (MSC_Handle->hbot.state)
{
case BOT_SEND_CBW:
MSC_Handle->hbot.cbw.field.LUN = lun;
MSC_Handle->hbot.state = BOT_SEND_CBW_WAIT;
USBH_BulkSendData (phost,
MSC_Handle->hbot.cbw.data,
BOT_CBW_LENGTH,
MSC_Handle->OutPipe,
1);
break;
case BOT_SEND_CBW_WAIT:
URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe);
if(URB_Status == USBH_URB_DONE)
{
if ( MSC_Handle->hbot.cbw.field.DataTransferLength != 0 )
{
/* If there is Data Transfer Stage */
if (((MSC_Handle->hbot.cbw.field.Flags) & USB_REQ_DIR_MASK) == USB_D2H)
{
/* Data Direction is IN */
MSC_Handle->hbot.state = BOT_DATA_IN;
}
else
{
/* Data Direction is OUT */
MSC_Handle->hbot.state = BOT_DATA_OUT;
}
}
else
{/* If there is NO Data Transfer Stage */
MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
#endif
}
else if(URB_Status == USBH_URB_NOTREADY)
{
/* Re-send CBW */
MSC_Handle->hbot.state = BOT_SEND_CBW;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
#endif
}
else if(URB_Status == USBH_URB_STALL)
{
MSC_Handle->hbot.state = BOT_ERROR_OUT;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
#endif
}
break;
case BOT_DATA_IN:
/* Send first packet */
USBH_BulkReceiveData (phost,
MSC_Handle->hbot.pbuf,
MSC_Handle->InEpSize ,
MSC_Handle->InPipe);
MSC_Handle->hbot.state = BOT_DATA_IN_WAIT;
break;
case BOT_DATA_IN_WAIT:
URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe);
if(URB_Status == USBH_URB_DONE)
{
/* Adjust Data pointer and data length */
if(MSC_Handle->hbot.cbw.field.DataTransferLength > MSC_Handle->InEpSize)
{
MSC_Handle->hbot.pbuf += MSC_Handle->InEpSize;
MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->InEpSize;
}
else
{
MSC_Handle->hbot.cbw.field.DataTransferLength = 0;
}
/* More Data To be Received */
if(MSC_Handle->hbot.cbw.field.DataTransferLength > 0)
{
/* Send next packet */
USBH_BulkReceiveData (phost,
MSC_Handle->hbot.pbuf,
MSC_Handle->InEpSize ,
MSC_Handle->InPipe);
}
else
{
/* If value was 0, and successful transfer, then change the state */
MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
#endif
}
}
else if(URB_Status == USBH_URB_STALL)
{
/* This is Data IN Stage STALL Condition */
MSC_Handle->hbot.state = BOT_ERROR_IN;
/* Refer to USB Mass-Storage Class : BOT (www.usb.org)
6.7.2 Host expects to receive data from the device
3. On a STALL condition receiving data, then:
The host shall accept the data received.
The host shall clear the Bulk-In pipe.
4. The host shall attempt to receive a CSW.*/
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
#endif
}
break;
case BOT_DATA_OUT:
USBH_BulkSendData (phost,
MSC_Handle->hbot.pbuf,
MSC_Handle->OutEpSize ,
MSC_Handle->OutPipe,
1);
MSC_Handle->hbot.state = BOT_DATA_OUT_WAIT;
break;
case BOT_DATA_OUT_WAIT:
URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe);
if(URB_Status == USBH_URB_DONE)
{
/* Adjust Data pointer and data length */
if(MSC_Handle->hbot.cbw.field.DataTransferLength > MSC_Handle->OutEpSize)
{
MSC_Handle->hbot.pbuf += MSC_Handle->OutEpSize;
MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->OutEpSize;
}
else
{
MSC_Handle->hbot.cbw.field.DataTransferLength = 0;
}
/* More Data To be Sent */
if(MSC_Handle->hbot.cbw.field.DataTransferLength > 0)
{
USBH_BulkSendData (phost,
MSC_Handle->hbot.pbuf,
MSC_Handle->OutEpSize ,
MSC_Handle->OutPipe,
1);
}
else
{
/* If value was 0, and successful transfer, then change the state */
MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
#endif
}
else if(URB_Status == USBH_URB_NOTREADY)
{
/* Resend same data */
MSC_Handle->hbot.state = BOT_DATA_OUT;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
#endif
}
else if(URB_Status == USBH_URB_STALL)
{
MSC_Handle->hbot.state = BOT_ERROR_OUT;
/* Refer to USB Mass-Storage Class : BOT (www.usb.org)
6.7.3 Ho - Host expects to send data to the device
3. On a STALL condition sending data, then:
" The host shall clear the Bulk-Out pipe.
4. The host shall attempt to receive a CSW.
*/
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
#endif
}
break;
case BOT_RECEIVE_CSW:
USBH_BulkReceiveData (phost,
MSC_Handle->hbot.csw.data,
BOT_CSW_LENGTH ,
MSC_Handle->InPipe);
MSC_Handle->hbot.state = BOT_RECEIVE_CSW_WAIT;
break;
case BOT_RECEIVE_CSW_WAIT:
URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe);
/* Decode CSW */
if(URB_Status == USBH_URB_DONE)
{
MSC_Handle->hbot.state = BOT_SEND_CBW;
MSC_Handle->hbot.cmd_state = BOT_CMD_SEND;
CSW_Status = USBH_MSC_DecodeCSW(phost);
if(CSW_Status == BOT_CSW_CMD_PASSED)
{
status = USBH_OK;
}
else
{
status = USBH_FAIL;
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
#endif
}
else if(URB_Status == USBH_URB_STALL)
{
MSC_Handle->hbot.state = BOT_ERROR_IN;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
#endif
}
break;
case BOT_ERROR_IN:
error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_IN);
if (error == USBH_OK)
{
MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
}
else if (error == USBH_UNRECOVERED_ERROR)
{
/* This means that there is a STALL Error limit, Do Reset Recovery */
MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR;
}
break;
case BOT_ERROR_OUT:
error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_OUT);
if ( error == USBH_OK)
{
toggle = USBH_LL_GetToggle(phost, MSC_Handle->OutPipe);
USBH_LL_SetToggle(phost, MSC_Handle->OutPipe, 1- toggle);
USBH_LL_SetToggle(phost, MSC_Handle->InPipe, 0);
MSC_Handle->hbot.state = BOT_ERROR_IN;
}
else if (error == USBH_UNRECOVERED_ERROR)
{
MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR;
}
break;
case BOT_UNRECOVERED_ERROR:
status = USBH_MSC_BOT_REQ_Reset(phost);
if ( status == USBH_OK)
{
MSC_Handle->hbot.state = BOT_SEND_CBW;
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_MSC_BOT_Abort
* The function handle the BOT Abort process.
* @param phost: Host handle
* @param lun: Logical Unit Number
* @param dir: direction (0: out / 1 : in)
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_MSC_BOT_Abort(USBH_HandleTypeDef *phost, uint8_t lun, uint8_t dir)
{
USBH_StatusTypeDef status = USBH_FAIL;
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
switch (dir)
{
case BOT_DIR_IN :
/* send ClrFeture on Bulk IN endpoint */
status = USBH_ClrFeature(phost, MSC_Handle->InEp);
break;
case BOT_DIR_OUT :
/*send ClrFeature on Bulk OUT endpoint */
status = USBH_ClrFeature(phost, MSC_Handle->OutEp);
break;
default:
break;
}
return status;
}
/**
* @brief USBH_MSC_BOT_DecodeCSW
* This function decodes the CSW received by the device and updates the
* same to upper layer.
* @param phost: Host handle
* @retval USBH Status
* @notes
* Refer to USB Mass-Storage Class : BOT (www.usb.org)
* 6.3.1 Valid CSW Conditions :
* The host shall consider the CSW valid when:
* 1. dCSWSignature is equal to 53425355h
* 2. the CSW is 13 (Dh) bytes in length,
* 3. dCSWTag matches the dCBWTag from the corresponding CBW.
*/
static BOT_CSWStatusTypeDef USBH_MSC_DecodeCSW(USBH_HandleTypeDef *phost)
{
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
BOT_CSWStatusTypeDef status = BOT_CSW_CMD_FAILED;
/*Checking if the transfer length is different than 13*/
if(USBH_LL_GetLastXferSize(phost, MSC_Handle->InPipe) != BOT_CSW_LENGTH)
{
/*(4) Hi > Dn (Host expects to receive data from the device,
Device intends to transfer no data)
(5) Hi > Di (Host expects to receive data from the device,
Device intends to send data to the host)
(9) Ho > Dn (Host expects to send data to the device,
Device intends to transfer no data)
(11) Ho > Do (Host expects to send data to the device,
Device intends to receive data from the host)*/
status = BOT_CSW_PHASE_ERROR;
}
else
{ /* CSW length is Correct */
/* Check validity of the CSW Signature and CSWStatus */
if(MSC_Handle->hbot.csw.field.Signature == BOT_CSW_SIGNATURE)
{/* Check Condition 1. dCSWSignature is equal to 53425355h */
if(MSC_Handle->hbot.csw.field.Tag == MSC_Handle->hbot.cbw.field.Tag)
{
/* Check Condition 3. dCSWTag matches the dCBWTag from the
corresponding CBW */
if(MSC_Handle->hbot.csw.field.Status == 0)
{
/* Refer to USB Mass-Storage Class : BOT (www.usb.org)
Hn Host expects no data transfers
Hi Host expects to receive data from the device
Ho Host expects to send data to the device
Dn Device intends to transfer no data
Di Device intends to send data to the host
Do Device intends to receive data from the host
Section 6.7
(1) Hn = Dn (Host expects no data transfers,
Device intends to transfer no data)
(6) Hi = Di (Host expects to receive data from the device,
Device intends to send data to the host)
(12) Ho = Do (Host expects to send data to the device,
Device intends to receive data from the host)
*/
status = BOT_CSW_CMD_PASSED;
}
else if(MSC_Handle->hbot.csw.field.Status == 1)
{
status = BOT_CSW_CMD_FAILED;
}
else if(MSC_Handle->hbot.csw.field.Status == 2)
{
/* Refer to USB Mass-Storage Class : BOT (www.usb.org)
Section 6.7
(2) Hn < Di ( Host expects no data transfers,
Device intends to send data to the host)
(3) Hn < Do ( Host expects no data transfers,
Device intends to receive data from the host)
(7) Hi < Di ( Host expects to receive data from the device,
Device intends to send data to the host)
(8) Hi <> Do ( Host expects to receive data from the device,
Device intends to receive data from the host)
(10) Ho <> Di (Host expects to send data to the device,
Di Device intends to send data to the host)
(13) Ho < Do (Host expects to send data to the device,
Device intends to receive data from the host)
*/
status = BOT_CSW_PHASE_ERROR;
}
} /* CSW Tag Matching is Checked */
} /* CSW Signature Correct Checking */
else
{
/* If the CSW Signature is not valid, We sall return the Phase Error to
Upper Layers for Reset Recovery */
status = BOT_CSW_PHASE_ERROR;
}
} /* CSW Length Check*/
return status;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,458 @@
/**
******************************************************************************
* @file usbh_msc_scsi.c
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief This file implements the SCSI commands
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbh_msc.h"
#include "usbh_msc_scsi.h"
#include "usbh_msc_bot.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_CLASS
* @{
*/
/** @addtogroup USBH_MSC_CLASS
* @{
*/
/** @defgroup USBH_MSC_SCSI
* @brief This file includes the mass storage related functions
* @{
*/
/** @defgroup USBH_MSC_SCSI_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_SCSI_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_SCSI_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_SCSI_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_SCSI_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MSC_SCSI_Private_Functions
* @{
*/
/**
* @brief USBH_MSC_SCSI_TestUnitReady
* Issue TestUnitReady command.
* @param phost: Host handle
* @param lun: Logical Unit Number
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_SCSI_TestUnitReady (USBH_HandleTypeDef *phost,
uint8_t lun)
{
USBH_StatusTypeDef error = USBH_FAIL ;
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
switch(MSC_Handle->hbot.cmd_state)
{
case BOT_CMD_SEND:
/*Prepare the CBW and relevent field*/
MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_MODE_TEST_UNIT_READY;
MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT;
MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_TEST_UNIT_READY;
MSC_Handle->hbot.state = BOT_SEND_CBW;
MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
error = USBH_BUSY;
break;
case BOT_CMD_WAIT:
error = USBH_MSC_BOT_Process(phost, lun);
break;
default:
break;
}
return error;
}
/**
* @brief USBH_MSC_SCSI_ReadCapacity
* Issue Read Capacity command.
* @param phost: Host handle
* @param lun: Logical Unit Number
* @param capacity: pointer to the capacity structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_SCSI_ReadCapacity (USBH_HandleTypeDef *phost,
uint8_t lun,
SCSI_CapacityTypeDef *capacity)
{
USBH_StatusTypeDef error = USBH_BUSY ;
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
switch(MSC_Handle->hbot.cmd_state)
{
case BOT_CMD_SEND:
/*Prepare the CBW and relevent field*/
MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_READ_CAPACITY10;
MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_READ_CAPACITY10;
MSC_Handle->hbot.state = BOT_SEND_CBW;
MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;
error = USBH_BUSY;
break;
case BOT_CMD_WAIT:
error = USBH_MSC_BOT_Process(phost, lun);
if(error == USBH_OK)
{
/*assign the capacity*/
capacity->block_nbr = MSC_Handle->hbot.pbuf[3] | (MSC_Handle->hbot.pbuf[2] << 8) |\
(MSC_Handle->hbot.pbuf[1] << 16) | (MSC_Handle->hbot.pbuf[0] << 24);
/*assign the page length*/
capacity->block_size = MSC_Handle->hbot.pbuf[7] | (MSC_Handle->hbot.pbuf[6] << 8);
}
break;
default:
break;
}
return error;
}
/**
* @brief USBH_MSC_SCSI_Inquiry
* Issue Inquiry command.
* @param phost: Host handle
* @param lun: Logical Unit Number
* @param capacity: pointer to the inquiry structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_SCSI_Inquiry (USBH_HandleTypeDef *phost,
uint8_t lun,
SCSI_StdInquiryDataTypeDef *inquiry)
{
USBH_StatusTypeDef error = USBH_FAIL ;
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
switch(MSC_Handle->hbot.cmd_state)
{
case BOT_CMD_SEND:
/*Prepare the CBW and relevent field*/
MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_INQUIRY;
MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_LENGTH);
MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_INQUIRY;
MSC_Handle->hbot.cbw.field.CB[1] = (lun << 5);
MSC_Handle->hbot.cbw.field.CB[2] = 0;
MSC_Handle->hbot.cbw.field.CB[3] = 0;
MSC_Handle->hbot.cbw.field.CB[4] = 0x24;
MSC_Handle->hbot.cbw.field.CB[5] = 0;
MSC_Handle->hbot.state = BOT_SEND_CBW;
MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;
error = USBH_BUSY;
break;
case BOT_CMD_WAIT:
error = USBH_MSC_BOT_Process(phost, lun);
if(error == USBH_OK)
{
USBH_memset(inquiry, 0, sizeof(SCSI_StdInquiryDataTypeDef));
/*assign Inquiry Data */
inquiry->DeviceType = MSC_Handle->hbot.pbuf[0] & 0x1F;
inquiry->PeripheralQualifier = MSC_Handle->hbot.pbuf[0] >> 5;
inquiry->RemovableMedia = (MSC_Handle->hbot.pbuf[1] & 0x80)== 0x80;
USBH_memcpy (inquiry->vendor_id, &MSC_Handle->hbot.pbuf[8], 8);
USBH_memcpy (inquiry->product_id, &MSC_Handle->hbot.pbuf[16], 16);
USBH_memcpy (inquiry->revision_id, &MSC_Handle->hbot.pbuf[32], 4);
}
break;
default:
break;
}
return error;
}
/**
* @brief USBH_MSC_SCSI_RequestSense
* Issue RequestSense command.
* @param phost: Host handle
* @param lun: Logical Unit Number
* @param capacity: pointer to the sense data structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_SCSI_RequestSense (USBH_HandleTypeDef *phost,
uint8_t lun,
SCSI_SenseTypeDef *sense_data)
{
USBH_StatusTypeDef error = USBH_FAIL ;
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
switch(MSC_Handle->hbot.cmd_state)
{
case BOT_CMD_SEND:
/*Prepare the CBW and relevent field*/
MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_REQUEST_SENSE;
MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_REQUEST_SENSE;
MSC_Handle->hbot.cbw.field.CB[1] = (lun << 5);
MSC_Handle->hbot.cbw.field.CB[2] = 0;
MSC_Handle->hbot.cbw.field.CB[3] = 0;
MSC_Handle->hbot.cbw.field.CB[4] = DATA_LEN_REQUEST_SENSE;
MSC_Handle->hbot.cbw.field.CB[5] = 0;
MSC_Handle->hbot.state = BOT_SEND_CBW;
MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;
error = USBH_BUSY;
break;
case BOT_CMD_WAIT:
error = USBH_MSC_BOT_Process(phost, lun);
if(error == USBH_OK)
{
sense_data->key = MSC_Handle->hbot.pbuf[2] & 0x0F;
sense_data->asc = MSC_Handle->hbot.pbuf[12];
sense_data->ascq = MSC_Handle->hbot.pbuf[13];
}
break;
default:
break;
}
return error;
}
/**
* @brief USBH_MSC_SCSI_Write
* Issue write10 command.
* @param phost: Host handle
* @param lun: Logical Unit Number
* @param address: sector address
* @param pbuf: pointer to data
* @param length: number of sector to write
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_SCSI_Write(USBH_HandleTypeDef *phost,
uint8_t lun,
uint32_t address,
uint8_t *pbuf,
uint32_t length)
{
USBH_StatusTypeDef error = USBH_FAIL ;
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
switch(MSC_Handle->hbot.cmd_state)
{
case BOT_CMD_SEND:
/*Prepare the CBW and relevent field*/
MSC_Handle->hbot.cbw.field.DataTransferLength = length * 512;
MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT;
MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_WRITE10;
/*logical block address*/
MSC_Handle->hbot.cbw.field.CB[2] = (((uint8_t*)&address)[3]);
MSC_Handle->hbot.cbw.field.CB[3] = (((uint8_t*)&address)[2]);
MSC_Handle->hbot.cbw.field.CB[4] = (((uint8_t*)&address)[1]);
MSC_Handle->hbot.cbw.field.CB[5] = (((uint8_t*)&address)[0]);
/*Transfer length */
MSC_Handle->hbot.cbw.field.CB[7] = (((uint8_t *)&length)[1]) ;
MSC_Handle->hbot.cbw.field.CB[8] = (((uint8_t *)&length)[0]) ;
MSC_Handle->hbot.state = BOT_SEND_CBW;
MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
MSC_Handle->hbot.pbuf = pbuf;
error = USBH_BUSY;
break;
case BOT_CMD_WAIT:
error = USBH_MSC_BOT_Process(phost, lun);
break;
default:
break;
}
return error;
}
/**
* @brief USBH_MSC_SCSI_Read
* Issue Read10 command.
* @param phost: Host handle
* @param lun: Logical Unit Number
* @param address: sector address
* @param pbuf: pointer to data
* @param length: number of sector to read
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_MSC_SCSI_Read(USBH_HandleTypeDef *phost,
uint8_t lun,
uint32_t address,
uint8_t *pbuf,
uint32_t length)
{
USBH_StatusTypeDef error = USBH_FAIL ;
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
switch(MSC_Handle->hbot.cmd_state)
{
case BOT_CMD_SEND:
/*Prepare the CBW and relevent field*/
MSC_Handle->hbot.cbw.field.DataTransferLength = length * 512;
MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_READ10;
/*logical block address*/
MSC_Handle->hbot.cbw.field.CB[2] = (((uint8_t*)&address)[3]);
MSC_Handle->hbot.cbw.field.CB[3] = (((uint8_t*)&address)[2]);
MSC_Handle->hbot.cbw.field.CB[4] = (((uint8_t*)&address)[1]);
MSC_Handle->hbot.cbw.field.CB[5] = (((uint8_t*)&address)[0]);
/*Transfer length */
MSC_Handle->hbot.cbw.field.CB[7] = (((uint8_t *)&length)[1]) ;
MSC_Handle->hbot.cbw.field.CB[8] = (((uint8_t *)&length)[0]) ;
MSC_Handle->hbot.state = BOT_SEND_CBW;
MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
MSC_Handle->hbot.pbuf = pbuf;
error = USBH_BUSY;
break;
case BOT_CMD_WAIT:
error = USBH_MSC_BOT_Process(phost, lun);
break;
default:
break;
}
return error;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,157 @@
/**
******************************************************************************
* @file usbh_conf_template.h
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief Header file for usbh_conf_template.c
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBH_CONF_TEMPLATE_H
#define __USBH_CONF_TEMPLATE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/** @addtogroup USBH_OTG_DRIVER
* @{
*/
/** @defgroup USBH_CONF
* @brief usb otg low level driver configuration file
* @{
*/
/** @defgroup USBH_CONF_Exported_Defines
* @{
*/
#define USBH_MAX_NUM_ENDPOINTS 2
#define USBH_MAX_NUM_INTERFACES 2
#define USBH_MAX_NUM_CONFIGURATION 1
#define USBH_KEEP_CFG_DESCRIPTOR 1
#define USBH_MAX_NUM_SUPPORTED_CLASS 1
#define USBH_MAX_SIZE_CONFIGURATION 0x200
#define USBH_MAX_DATA_BUFFER 0x200
#define USBH_DEBUG_LEVEL 2
#define USBH_USE_OS 1
/** @defgroup USBH_Exported_Macros
* @{
*/
/* Memory management macros */
#define USBH_malloc malloc
#define USBH_free free
#define USBH_memset memset
#define USBH_memcpy memcpy
/* DEBUG macros */
#if (USBH_DEBUG_LEVEL > 0)
#define USBH_UsrLog(...) printf(__VA_ARGS__);\
printf("\n");
#else
#define USBH_UsrLog(...)
#endif
#if (USBH_DEBUG_LEVEL > 1)
#define USBH_ErrLog(...) printf("ERROR: ") ;\
printf(__VA_ARGS__);\
printf("\n");
#else
#define USBH_ErrLog(...)
#endif
#if (USBH_DEBUG_LEVEL > 2)
#define USBH_DbgLog(...) printf("DEBUG : ") ;\
printf(__VA_ARGS__);\
printf("\n");
#else
#define USBH_DbgLog(...)
#endif
/**
* @}
*/
/**
* @}
*/
/** @defgroup USBH_CONF_Exported_Types
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CONF_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CONF_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CONF_Exported_FunctionsPrototype
* @{
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBH_CONF_TEMPLATE_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,169 @@
/**
******************************************************************************
* @file usbh_core.h
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief Header file for usbh_core.c
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive ----------------------------------------------*/
#ifndef __USBH_CORE_H
#define __USBH_CORE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbh_conf.h"
#include "usbh_def.h"
#include "usbh_ioreq.h"
#include "usbh_pipes.h"
#include "usbh_ctlreq.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_LIB_CORE
* @{
*/
/** @defgroup USBH_CORE
* @brief This file is the Header file for usbh_core.c
* @{
*/
/** @defgroup USBH_CORE_Exported_Defines
* @{
*/
/**
* @}
*/
#define HOST_USER_SELECT_CONFIGURATION 1
#define HOST_USER_CLASS_ACTIVE 2
#define HOST_USER_CLASS_SELECTED 3
#define HOST_USER_CONNECTION 4
#define HOST_USER_DISCONNECTION 5
#define HOST_USER_UNRECOVERED_ERROR 6
/**
* @}
*/
/** @defgroup USBH_CORE_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CORE_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CORE_Exported_FunctionsPrototype
* @{
*/
USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost, void (*pUsrFunc)(USBH_HandleTypeDef *phost, uint8_t ), uint8_t id);
USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass);
USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface);
uint8_t USBH_FindInterface(USBH_HandleTypeDef *phost,
uint8_t Class,
uint8_t SubClass,
uint8_t Protocol);
uint8_t USBH_GetActiveClass(USBH_HandleTypeDef *phost);
uint8_t USBH_FindInterfaceIndex(USBH_HandleTypeDef *phost,
uint8_t interface_number,
uint8_t alt_settings);
USBH_StatusTypeDef USBH_Start (USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_Stop (USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_Process (USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_ReEnumerate (USBH_HandleTypeDef *phost);
/* USBH Low Level Driver */
USBH_StatusTypeDef USBH_LL_Init (USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_LL_DeInit (USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_LL_Start (USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_LL_Stop (USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_LL_Connect (USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_LL_Disconnect (USBH_HandleTypeDef *phost);
USBH_SpeedTypeDef USBH_LL_GetSpeed (USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_LL_ResetPort (USBH_HandleTypeDef *phost);
uint32_t USBH_LL_GetLastXferSize (USBH_HandleTypeDef *phost, uint8_t );
USBH_StatusTypeDef USBH_LL_DriverVBUS (USBH_HandleTypeDef *phost, uint8_t );
USBH_StatusTypeDef USBH_LL_OpenPipe (USBH_HandleTypeDef *phost, uint8_t, uint8_t, uint8_t, uint8_t , uint8_t, uint16_t );
USBH_StatusTypeDef USBH_LL_ClosePipe (USBH_HandleTypeDef *phost, uint8_t );
USBH_StatusTypeDef USBH_LL_SubmitURB (USBH_HandleTypeDef *phost, uint8_t, uint8_t,uint8_t, uint8_t, uint8_t*, uint16_t, uint8_t );
USBH_URBStateTypeDef USBH_LL_GetURBState (USBH_HandleTypeDef *phost, uint8_t );
#if (USBH_USE_OS == 1)
USBH_StatusTypeDef USBH_LL_NotifyURBChange (USBH_HandleTypeDef *phost);
#endif
USBH_StatusTypeDef USBH_LL_SetToggle (USBH_HandleTypeDef *phost, uint8_t , uint8_t );
uint8_t USBH_LL_GetToggle (USBH_HandleTypeDef *phost, uint8_t );
/* USBH Time base */
void USBH_Delay (uint32_t Delay);
void USBH_LL_SetTimer (USBH_HandleTypeDef *phost, uint32_t );
void USBH_LL_IncTimer (USBH_HandleTypeDef *phost);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBH_CORE_H */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,155 @@
/**
******************************************************************************
* @file usbh_ctlreq.h
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief Header file for usbh_ctlreq.c
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive ----------------------------------------------*/
#ifndef __USBH_CTLREQ_H
#define __USBH_CTLREQ_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbh_core.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_LIB_CORE
* @{
*/
/** @defgroup USBH_CTLREQ
* @brief This file is the
* @{
*/
/** @defgroup USBH_CTLREQ_Exported_Defines
* @{
*/
/*Standard Feature Selector for clear feature command*/
#define FEATURE_SELECTOR_ENDPOINT 0X00
#define FEATURE_SELECTOR_DEVICE 0X01
#define INTERFACE_DESC_TYPE 0x04
#define ENDPOINT_DESC_TYPE 0x05
#define INTERFACE_DESC_SIZE 0x09
/**
* @}
*/
/** @defgroup USBH_CTLREQ_Exported_Types
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CTLREQ_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CTLREQ_Exported_Variables
* @{
*/
extern uint8_t USBH_CfgDesc[512];
/**
* @}
*/
/** @defgroup USBH_CTLREQ_Exported_FunctionsPrototype
* @{
*/
USBH_StatusTypeDef USBH_CtlReq (USBH_HandleTypeDef *phost,
uint8_t *buff,
uint16_t length);
USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost,
uint8_t req_type,
uint16_t value_idx,
uint8_t* buff,
uint16_t length );
USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost,
uint8_t length);
USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost,
uint8_t string_index,
uint8_t *buff,
uint16_t length);
USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost,
uint16_t configuration_value);
USBH_StatusTypeDef USBH_Get_CfgDesc(USBH_HandleTypeDef *phost,
uint16_t length);
USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost,
uint8_t DeviceAddress);
USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost,
uint8_t ep_num, uint8_t altSetting);
USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost,
uint8_t ep_num);
USBH_DescHeader_t *USBH_GetNextDesc (uint8_t *pbuf,
uint16_t *ptr);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBH_CTLREQ_H */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,490 @@
/**
******************************************************************************
* @file usbh_def.h
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief Definitions used in the USB host library
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive ----------------------------------------------*/
#ifndef USBH_DEF_H
#define USBH_DEF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbh_conf.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_LIB_CORE
* @{
*/
/** @defgroup USBH_DEF
* @brief This file is includes USB descriptors
* @{
*/
#ifndef NULL
#define NULL 0
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#define ValBit(VAR,POS) (VAR & (1 << POS))
#define SetBit(VAR,POS) (VAR |= (1 << POS))
#define ClrBit(VAR,POS) (VAR &= ((1 << POS)^255))
#define LE16(addr) (((uint16_t)(*((uint8_t *)(addr))))\
+ (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
#define LE16S(addr) (uint16_t)(LE16((addr)))
#define LE32(addr) ((((uint32_t)(*(((uint8_t *)(addr)) + 0))) + \
(((uint32_t)(*(((uint8_t *)(addr)) + 1))) << 8) + \
(((uint32_t)(*(((uint8_t *)(addr)) + 2))) << 16) + \
(((uint32_t)(*(((uint8_t *)(addr)) + 3))) << 24)))
#define LE64(addr) ((((uint64_t)(*(((uint8_t *)(addr)) + 0))) + \
(((uint64_t)(*(((uint8_t *)(addr)) + 1))) << 8) +\
(((uint64_t)(*(((uint8_t *)(addr)) + 2))) << 16) +\
(((uint64_t)(*(((uint8_t *)(addr)) + 3))) << 24) +\
(((uint64_t)(*(((uint8_t *)(addr)) + 4))) << 32) +\
(((uint64_t)(*(((uint8_t *)(addr)) + 5))) << 40) +\
(((uint64_t)(*(((uint8_t *)(addr)) + 6))) << 48) +\
(((uint64_t)(*(((uint8_t *)(addr)) + 7))) << 56)))
#define LE24(addr) ((((uint32_t)(*(((uint8_t *)(addr)) + 0))) + \
(((uint32_t)(*(((uint8_t *)(addr)) + 1))) << 8) + \
(((uint32_t)(*(((uint8_t *)(addr)) + 2))) << 16)))
#define LE32S(addr) (int32_t)(LE32((addr)))
#define USB_LEN_DESC_HDR 0x02
#define USB_LEN_DEV_DESC 0x12
#define USB_LEN_CFG_DESC 0x09
#define USB_LEN_IF_DESC 0x09
#define USB_LEN_EP_DESC 0x07
#define USB_LEN_OTG_DESC 0x03
#define USB_LEN_SETUP_PKT 0x08
/* bmRequestType :D7 Data Phase Transfer Direction */
#define USB_REQ_DIR_MASK 0x80
#define USB_H2D 0x00
#define USB_D2H 0x80
/* bmRequestType D6..5 Type */
#define USB_REQ_TYPE_STANDARD 0x00
#define USB_REQ_TYPE_CLASS 0x20
#define USB_REQ_TYPE_VENDOR 0x40
#define USB_REQ_TYPE_RESERVED 0x60
/* bmRequestType D4..0 Recipient */
#define USB_REQ_RECIPIENT_DEVICE 0x00
#define USB_REQ_RECIPIENT_INTERFACE 0x01
#define USB_REQ_RECIPIENT_ENDPOINT 0x02
#define USB_REQ_RECIPIENT_OTHER 0x03
/* Table 9-4. Standard Request Codes */
/* bRequest , Value */
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
/* Table 9-5. Descriptor Types of USB Specifications */
#define USB_DESC_TYPE_DEVICE 1
#define USB_DESC_TYPE_CONFIGURATION 2
#define USB_DESC_TYPE_STRING 3
#define USB_DESC_TYPE_INTERFACE 4
#define USB_DESC_TYPE_ENDPOINT 5
#define USB_DESC_TYPE_DEVICE_QUALIFIER 6
#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7
#define USB_DESC_TYPE_INTERFACE_POWER 8
#define USB_DESC_TYPE_HID 0x21
#define USB_DESC_TYPE_HID_REPORT 0x22
#define USB_DEVICE_DESC_SIZE 18
#define USB_CONFIGURATION_DESC_SIZE 9
#define USB_HID_DESC_SIZE 9
#define USB_INTERFACE_DESC_SIZE 9
#define USB_ENDPOINT_DESC_SIZE 7
/* Descriptor Type and Descriptor Index */
/* Use the following values when calling the function USBH_GetDescriptor */
#define USB_DESC_DEVICE ((USB_DESC_TYPE_DEVICE << 8) & 0xFF00)
#define USB_DESC_CONFIGURATION ((USB_DESC_TYPE_CONFIGURATION << 8) & 0xFF00)
#define USB_DESC_STRING ((USB_DESC_TYPE_STRING << 8) & 0xFF00)
#define USB_DESC_INTERFACE ((USB_DESC_TYPE_INTERFACE << 8) & 0xFF00)
#define USB_DESC_ENDPOINT ((USB_DESC_TYPE_INTERFACE << 8) & 0xFF00)
#define USB_DESC_DEVICE_QUALIFIER ((USB_DESC_TYPE_DEVICE_QUALIFIER << 8) & 0xFF00)
#define USB_DESC_OTHER_SPEED_CONFIGURATION ((USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION << 8) & 0xFF00)
#define USB_DESC_INTERFACE_POWER ((USB_DESC_TYPE_INTERFACE_POWER << 8) & 0xFF00)
#define USB_DESC_HID_REPORT ((USB_DESC_TYPE_HID_REPORT << 8) & 0xFF00)
#define USB_DESC_HID ((USB_DESC_TYPE_HID << 8) & 0xFF00)
#define USB_EP_TYPE_CTRL 0x00
#define USB_EP_TYPE_ISOC 0x01
#define USB_EP_TYPE_BULK 0x02
#define USB_EP_TYPE_INTR 0x03
#define USB_EP_DIR_OUT 0x00
#define USB_EP_DIR_IN 0x80
#define USB_EP_DIR_MSK 0x80
#ifndef USBH_MAX_PIPES_NBR
#define USBH_MAX_PIPES_NBR 15
#endif /* USBH_MAX_PIPES_NBR */
#define USBH_DEVICE_ADDRESS_DEFAULT 0
#define USBH_MAX_ERROR_COUNT 2
#define USBH_DEVICE_ADDRESS 1
/**
* @}
*/
#define USBH_CONFIGURATION_DESCRIPTOR_SIZE (USB_CONFIGURATION_DESC_SIZE \
+ USB_INTERFACE_DESC_SIZE\
+ (USBH_MAX_NUM_ENDPOINTS * USB_ENDPOINT_DESC_SIZE))
#define CONFIG_DESC_wTOTAL_LENGTH (ConfigurationDescriptorData.ConfigDescfield.\
ConfigurationDescriptor.wTotalLength)
typedef union
{
uint16_t w;
struct BW
{
uint8_t msb;
uint8_t lsb;
}
bw;
}
uint16_t_uint8_t;
typedef union _USB_Setup
{
uint32_t d8[2];
struct _SetupPkt_Struc
{
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t_uint8_t wValue;
uint16_t_uint8_t wIndex;
uint16_t_uint8_t wLength;
} b;
}
USB_Setup_TypeDef;
typedef struct _DescHeader
{
uint8_t bLength;
uint8_t bDescriptorType;
}
USBH_DescHeader_t;
typedef struct _DeviceDescriptor
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB; /* USB Specification Number which device complies too */
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
/* If equal to Zero, each interface specifies its own class
code if equal to 0xFF, the class code is vendor specified.
Otherwise field is valid Class Code.*/
uint8_t bMaxPacketSize;
uint16_t idVendor; /* Vendor ID (Assigned by USB Org) */
uint16_t idProduct; /* Product ID (Assigned by Manufacturer) */
uint16_t bcdDevice; /* Device Release Number */
uint8_t iManufacturer; /* Index of Manufacturer String Descriptor */
uint8_t iProduct; /* Index of Product String Descriptor */
uint8_t iSerialNumber; /* Index of Serial Number String Descriptor */
uint8_t bNumConfigurations; /* Number of Possible Configurations */
}
USBH_DevDescTypeDef;
typedef struct _EndpointDescriptor
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress; /* indicates what endpoint this descriptor is describing */
uint8_t bmAttributes; /* specifies the transfer type. */
uint16_t wMaxPacketSize; /* Maximum Packet Size this endpoint is capable of sending or receiving */
uint8_t bInterval; /* is used to specify the polling interval of certain transfers. */
}
USBH_EpDescTypeDef;
typedef struct _InterfaceDescriptor
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting; /* Value used to select alternative setting */
uint8_t bNumEndpoints; /* Number of Endpoints used for this interface */
uint8_t bInterfaceClass; /* Class Code (Assigned by USB Org) */
uint8_t bInterfaceSubClass; /* Subclass Code (Assigned by USB Org) */
uint8_t bInterfaceProtocol; /* Protocol Code */
uint8_t iInterface; /* Index of String Descriptor Describing this interface */
USBH_EpDescTypeDef Ep_Desc[USBH_MAX_NUM_ENDPOINTS];
}
USBH_InterfaceDescTypeDef;
typedef struct _ConfigurationDescriptor
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength; /* Total Length of Data Returned */
uint8_t bNumInterfaces; /* Number of Interfaces */
uint8_t bConfigurationValue; /* Value to use as an argument to select this configuration*/
uint8_t iConfiguration; /*Index of String Descriptor Describing this configuration */
uint8_t bmAttributes; /* D7 Bus Powered , D6 Self Powered, D5 Remote Wakeup , D4..0 Reserved (0)*/
uint8_t bMaxPower; /*Maximum Power Consumption */
USBH_InterfaceDescTypeDef Itf_Desc[USBH_MAX_NUM_INTERFACES];
}
USBH_CfgDescTypeDef;
/* Following USB Host status */
typedef enum
{
USBH_OK = 0,
USBH_BUSY,
USBH_FAIL,
USBH_NOT_SUPPORTED,
USBH_UNRECOVERED_ERROR,
USBH_ERROR_SPEED_UNKNOWN,
}USBH_StatusTypeDef;
/** @defgroup USBH_CORE_Exported_Types
* @{
*/
typedef enum
{
USBH_SPEED_HIGH = 0,
USBH_SPEED_FULL = 1,
USBH_SPEED_LOW = 2,
}USBH_SpeedTypeDef;
/* Following states are used for gState */
typedef enum
{
HOST_IDLE =0,
HOST_DEV_WAIT_FOR_ATTACHMENT,
HOST_DEV_ATTACHED,
HOST_DEV_DISCONNECTED,
HOST_DETECT_DEVICE_SPEED,
HOST_ENUMERATION,
HOST_CLASS_REQUEST,
HOST_INPUT,
HOST_SET_CONFIGURATION,
HOST_CHECK_CLASS,
HOST_CLASS,
HOST_SUSPENDED,
HOST_ABORT_STATE,
}HOST_StateTypeDef;
/* Following states are used for EnumerationState */
typedef enum
{
ENUM_IDLE = 0,
ENUM_GET_FULL_DEV_DESC,
ENUM_SET_ADDR,
ENUM_GET_CFG_DESC,
ENUM_GET_FULL_CFG_DESC,
ENUM_GET_MFC_STRING_DESC,
ENUM_GET_PRODUCT_STRING_DESC,
ENUM_GET_SERIALNUM_STRING_DESC,
} ENUM_StateTypeDef;
/* Following states are used for CtrlXferStateMachine */
typedef enum
{
CTRL_IDLE =0,
CTRL_SETUP,
CTRL_SETUP_WAIT,
CTRL_DATA_IN,
CTRL_DATA_IN_WAIT,
CTRL_DATA_OUT,
CTRL_DATA_OUT_WAIT,
CTRL_STATUS_IN,
CTRL_STATUS_IN_WAIT,
CTRL_STATUS_OUT,
CTRL_STATUS_OUT_WAIT,
CTRL_ERROR,
CTRL_STALLED,
CTRL_COMPLETE
}CTRL_StateTypeDef;
/* Following states are used for RequestState */
typedef enum
{
CMD_IDLE =0,
CMD_SEND,
CMD_WAIT
} CMD_StateTypeDef;
typedef enum {
USBH_URB_IDLE = 0,
USBH_URB_DONE,
USBH_URB_NOTREADY,
USBH_URB_NYET,
USBH_URB_ERROR,
USBH_URB_STALL
}USBH_URBStateTypeDef;
typedef enum
{
USBH_PORT_EVENT = 1,
USBH_URB_EVENT,
USBH_CONTROL_EVENT,
USBH_CLASS_EVENT,
USBH_STATE_CHANGED_EVENT,
}
USBH_OSEventTypeDef;
/* Control request structure */
typedef struct
{
uint8_t pipe_in;
uint8_t pipe_out;
uint8_t pipe_size;
uint8_t *buff;
uint16_t length;
uint16_t timer;
USB_Setup_TypeDef setup;
CTRL_StateTypeDef state;
uint8_t errorcount;
} USBH_CtrlTypeDef;
/* Attached device structure */
typedef struct
{
#if (USBH_KEEP_CFG_DESCRIPTOR == 1)
uint8_t CfgDesc_Raw[USBH_MAX_SIZE_CONFIGURATION];
#endif
uint8_t Data[USBH_MAX_DATA_BUFFER];
uint8_t address;
uint8_t speed;
__IO uint8_t is_connected;
uint8_t current_interface;
USBH_DevDescTypeDef DevDesc;
USBH_CfgDescTypeDef CfgDesc;
}USBH_DeviceTypeDef;
struct _USBH_HandleTypeDef;
/* USB Host Class structure */
typedef struct
{
const char *Name;
uint8_t ClassCode;
USBH_StatusTypeDef (*Init) (struct _USBH_HandleTypeDef *phost);
USBH_StatusTypeDef (*DeInit) (struct _USBH_HandleTypeDef *phost);
USBH_StatusTypeDef (*Requests) (struct _USBH_HandleTypeDef *phost);
USBH_StatusTypeDef (*BgndProcess) (struct _USBH_HandleTypeDef *phost);
USBH_StatusTypeDef (*SOFProcess) (struct _USBH_HandleTypeDef *phost);
void* pData;
} USBH_ClassTypeDef;
/* USB Host handle structure */
typedef struct _USBH_HandleTypeDef
{
__IO HOST_StateTypeDef gState; /* Host State Machine Value */
ENUM_StateTypeDef EnumState; /* Enumeration state Machine */
CMD_StateTypeDef RequestState;
USBH_CtrlTypeDef Control;
USBH_DeviceTypeDef device;
USBH_ClassTypeDef* pClass[USBH_MAX_NUM_SUPPORTED_CLASS];
USBH_ClassTypeDef* pActiveClass;
uint32_t ClassNumber;
uint32_t Pipes[15];
__IO uint32_t Timer;
uint8_t id;
void* pData;
void (* pUser )(struct _USBH_HandleTypeDef *pHandle, uint8_t id);
#if (USBH_USE_OS == 1)
osMessageQId os_event;
osThreadId thread;
#endif
} USBH_HandleTypeDef;
#if defined ( __GNUC__ )
#ifndef __weak
#define __weak __attribute__((weak))
#endif /* __weak */
#ifndef __packed
#define __packed __attribute__((__packed__))
#endif /* __packed */
#endif /* __GNUC__ */
#ifdef __cplusplus
}
#endif
#endif /* USBH_DEF_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,168 @@
/**
******************************************************************************
* @file usbh_ioreq.h
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief Header file for usbh_ioreq.c
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive ----------------------------------------------*/
#ifndef __USBH_IOREQ_H
#define __USBH_IOREQ_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbh_conf.h"
#include "usbh_core.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_LIB_CORE
* @{
*/
/** @defgroup USBH_IOREQ
* @brief This file is the header file for usbh_ioreq.c
* @{
*/
/** @defgroup USBH_IOREQ_Exported_Defines
* @{
*/
#define USBH_PID_SETUP 0
#define USBH_PID_DATA 1
#define USBH_EP_CONTROL 0
#define USBH_EP_ISO 1
#define USBH_EP_BULK 2
#define USBH_EP_INTERRUPT 3
#define USBH_SETUP_PKT_SIZE 8
/**
* @}
*/
/** @defgroup USBH_IOREQ_Exported_Types
* @{
*/
/**
* @}
*/
/** @defgroup USBH_IOREQ_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_IOREQ_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_IOREQ_Exported_FunctionsPrototype
* @{
*/
USBH_StatusTypeDef USBH_CtlSendSetup (USBH_HandleTypeDef *phost,
uint8_t *buff,
uint8_t hc_num);
USBH_StatusTypeDef USBH_CtlSendData (USBH_HandleTypeDef *phost,
uint8_t *buff,
uint16_t length,
uint8_t hc_num,
uint8_t do_ping );
USBH_StatusTypeDef USBH_CtlReceiveData(USBH_HandleTypeDef *phost,
uint8_t *buff,
uint16_t length,
uint8_t hc_num);
USBH_StatusTypeDef USBH_BulkReceiveData(USBH_HandleTypeDef *phost,
uint8_t *buff,
uint16_t length,
uint8_t hc_num);
USBH_StatusTypeDef USBH_BulkSendData (USBH_HandleTypeDef *phost,
uint8_t *buff,
uint16_t length,
uint8_t hc_num,
uint8_t do_ping );
USBH_StatusTypeDef USBH_InterruptReceiveData(USBH_HandleTypeDef *phost,
uint8_t *buff,
uint8_t length,
uint8_t hc_num);
USBH_StatusTypeDef USBH_InterruptSendData(USBH_HandleTypeDef *phost,
uint8_t *buff,
uint8_t length,
uint8_t hc_num);
USBH_StatusTypeDef USBH_IsocReceiveData(USBH_HandleTypeDef *phost,
uint8_t *buff,
uint32_t length,
uint8_t hc_num);
USBH_StatusTypeDef USBH_IsocSendData(USBH_HandleTypeDef *phost,
uint8_t *buff,
uint32_t length,
uint8_t hc_num);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBH_IOREQ_H */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,131 @@
/**
******************************************************************************
* @file usbh_pipes.h
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief Header file for usbh_pipes.c
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive ----------------------------------------------*/
#ifndef __USBH_PIPES_H
#define __USBH_PIPES_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbh_core.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_LIB_CORE
* @{
*/
/** @defgroup USBH_PIPES
* @brief This file is the header file for usbh_pipes.c
* @{
*/
/** @defgroup USBH_PIPES_Exported_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBH_PIPES_Exported_Types
* @{
*/
/**
* @}
*/
/** @defgroup USBH_PIPES_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_PIPES_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_PIPES_Exported_FunctionsPrototype
* @{
*/
USBH_StatusTypeDef USBH_OpenPipe (USBH_HandleTypeDef *phost,
uint8_t ch_num,
uint8_t epnum,
uint8_t dev_address,
uint8_t speed,
uint8_t ep_type,
uint16_t mps);
USBH_StatusTypeDef USBH_ClosePipe (USBH_HandleTypeDef *phost,
uint8_t pipe_num);
uint8_t USBH_AllocPipe (USBH_HandleTypeDef *phost,
uint8_t ep_addr);
USBH_StatusTypeDef USBH_FreePipe (USBH_HandleTypeDef *phost,
uint8_t idx);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBH_PIPES_H */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,271 @@
/**
******************************************************************************
* @file usb_bsp.c
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief This file implements the board support package for the USB host library
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbh_core.h"
/**
* @brief USBH_LL_Init
* Initialize the Low Level portion of the Host driver.
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_LL_Init (USBH_HandleTypeDef *phost)
{
return USBH_OK;
}
/**
* @brief USBH_LL_DeInit
* De-Initialize the Low Level portion of the Host driver.
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_LL_DeInit (USBH_HandleTypeDef *phost)
{
return USBH_OK;
}
/**
* @brief USBH_LL_Start
* Start the Low Level portion of the Host driver.
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_LL_Start(USBH_HandleTypeDef *phost)
{
return USBH_OK;
}
/**
* @brief USBH_LL_Stop
* Stop the Low Level portion of the Host driver.
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_LL_Stop (USBH_HandleTypeDef *phost)
{
return USBH_OK;
}
/**
* @brief USBH_LL_GetSpeed
* Return the USB Host Speed from the Low Level Driver.
* @param phost: Host handle
* @retval USBH Speeds
*/
USBH_SpeedTypeDef USBH_LL_GetSpeed (USBH_HandleTypeDef *phost)
{
USBH_SpeedTypeDef speed = USBH_SPEED_FULL;
return speed;
}
/**
* @brief USBH_LL_ResetPort
* Reset the Host Port of the Low Level Driver.
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_LL_ResetPort (USBH_HandleTypeDef *phost)
{
return USBH_OK;
}
/**
* @brief USBH_LL_GetLastXferSize
* Return the last transferred packet size.
* @param phost: Host handle
* @param pipe: Pipe index
* @retval Packet Size
*/
uint32_t USBH_LL_GetLastXferSize (USBH_HandleTypeDef *phost, uint8_t pipe)
{
return 0;
}
/**
* @brief USBH_LL_OpenPipe
* Open a pipe of the Low Level Driver.
* @param phost: Host handle
* @param pipe_num: Pipe index
* @param epnum: Endpoint Number
* @param dev_address: Device USB address
* @param speed: Device Speed
* @param ep_type: Endpoint Type
* @param mps: Endpoint Max Packet Size
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_LL_OpenPipe (USBH_HandleTypeDef *phost,
uint8_t pipe_num,
uint8_t epnum,
uint8_t dev_address,
uint8_t speed,
uint8_t ep_type,
uint16_t mps)
{
return USBH_OK;
}
/**
* @brief USBH_LL_ClosePipe
* Close a pipe of the Low Level Driver.
* @param phost: Host handle
* @param pipe_num: Pipe index
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_LL_ClosePipe (USBH_HandleTypeDef *phost, uint8_t pipe)
{
return USBH_OK;
}
/**
* @brief USBH_LL_SubmitURB
* Submit a new URB to the low level driver.
* @param phost: Host handle
* @param pipe: Pipe index
* This parameter can be a value from 1 to 15
* @param direction : Channel number
* This parameter can be one of the these values:
* 0 : Output
* 1 : Input
* @param ep_type : Endpoint Type
* This parameter can be one of the these values:
* @arg EP_TYPE_CTRL: Control type
* @arg EP_TYPE_ISOC: Isochronous type
* @arg EP_TYPE_BULK: Bulk type
* @arg EP_TYPE_INTR: Interrupt type
* @param token : Endpoint Type
* This parameter can be one of the these values:
* @arg 0: PID_SETUP
* @arg 1: PID_DATA
* @param pbuff : pointer to URB data
* @param length : Length of URB data
* @param do_ping : activate do ping protocol (for high speed only)
* This parameter can be one of the these values:
* 0 : do ping inactive
* 1 : do ping active
* @retval Status
*/
USBH_StatusTypeDef USBH_LL_SubmitURB (USBH_HandleTypeDef *phost,
uint8_t pipe,
uint8_t direction ,
uint8_t ep_type,
uint8_t token,
uint8_t* pbuff,
uint16_t length,
uint8_t do_ping )
{
return USBH_OK;
}
/**
* @brief USBH_LL_GetURBState
* Get a URB state from the low level driver.
* @param phost: Host handle
* @param pipe: Pipe index
* This parameter can be a value from 1 to 15
* @retval URB state
* This parameter can be one of the these values:
* @arg URB_IDLE
* @arg URB_DONE
* @arg URB_NOTREADY
* @arg URB_NYET
* @arg URB_ERROR
* @arg URB_STALL
*/
USBH_URBStateTypeDef USBH_LL_GetURBState (USBH_HandleTypeDef *phost, uint8_t pipe)
{
return USBH_URB_IDLE;
}
/**
* @brief USBH_LL_DriverVBUS
* Drive VBUS.
* @param phost: Host handle
* @param state : VBUS state
* This parameter can be one of the these values:
* 0 : VBUS Active
* 1 : VBUS Inactive
* @retval Status
*/
USBH_StatusTypeDef USBH_LL_DriverVBUS (USBH_HandleTypeDef *phost, uint8_t state)
{
return USBH_OK;
}
/**
* @brief USBH_LL_SetToggle
* Set toggle for a pipe.
* @param phost: Host handle
* @param pipe: Pipe index
* @param pipe_num: Pipe index
* @param toggle: toggle (0/1)
* @retval Status
*/
USBH_StatusTypeDef USBH_LL_SetToggle (USBH_HandleTypeDef *phost, uint8_t pipe, uint8_t toggle)
{
return USBH_OK;
}
/**
* @brief USBH_LL_GetToggle
* Return the current toggle of a pipe.
* @param phost: Host handle
* @param pipe: Pipe index
* @retval toggle (0/1)
*/
uint8_t USBH_LL_GetToggle (USBH_HandleTypeDef *phost, uint8_t pipe)
{
uint8_t toggle = 0;
return toggle;
}
/**
* @brief USBH_Delay
* Delay routine for the USB Host Library
* @param Delay: Delay in ms
* @retval None
*/
void USBH_Delay (uint32_t Delay)
{
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,933 @@
/**
******************************************************************************
* @file usbh_core.c
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief This file implements the functions for the core state machine process
* the enumeration and the control transfer process
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbh_core.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_LIB_CORE
* @{
*/
/** @defgroup USBH_CORE
* @brief This file handles the basic enumeration when a device is connected
* to the host.
* @{
*/
/** @defgroup USBH_CORE_Private_Defines
* @{
*/
#define USBH_ADDRESS_DEFAULT 0
#define USBH_ADDRESS_ASSIGNED 1
#define USBH_MPS_DEFAULT 0x40
/**
* @}
*/
/** @defgroup USBH_CORE_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CORE_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CORE_Private_Functions
* @{
*/
static USBH_StatusTypeDef USBH_HandleEnum (USBH_HandleTypeDef *phost);
static void USBH_HandleSof (USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost);
#if (USBH_USE_OS == 1)
static void USBH_Process_OS(void const * argument);
#endif
/**
* @brief HCD_Init
* Initialize the HOST Core.
* @param phost: Host Handle
* @param pUsrFunc: User Callback
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost, void (*pUsrFunc)(USBH_HandleTypeDef *phost, uint8_t ), uint8_t id)
{
/* Check whether the USB Host handle is valid */
if(phost == NULL)
{
USBH_ErrLog("Invalid Host handle");
return USBH_FAIL;
}
/* Set DRiver ID */
phost->id = id;
/* Unlink class*/
phost->pActiveClass = NULL;
phost->ClassNumber = 0;
/* Restore default states and prepare EP0 */
DeInitStateMachine(phost);
/* Assign User process */
if(pUsrFunc != NULL)
{
phost->pUser = pUsrFunc;
}
#if (USBH_USE_OS == 1)
/* Create USB Host Queue */
osMessageQDef(USBH_Queue, 10, uint16_t);
phost->os_event = osMessageCreate (osMessageQ(USBH_Queue), NULL);
/*Create USB Host Task */
#if defined (USBH_PROCESS_STACK_SIZE)
osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0, USBH_PROCESS_STACK_SIZE);
#else
osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0, 8 * configMINIMAL_STACK_SIZE);
#endif
phost->thread = osThreadCreate (osThread(USBH_Thread), phost);
#endif
/* Initialize low level driver */
USBH_LL_Init(phost);
return USBH_OK;
}
/**
* @brief HCD_Init
* De-Initialize the Host portion of the driver.
* @param phost: Host Handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost)
{
DeInitStateMachine(phost);
if(phost->pData != NULL)
{
phost->pActiveClass->pData = NULL;
USBH_LL_Stop(phost);
}
return USBH_OK;
}
/**
* @brief DeInitStateMachine
* De-Initialize the Host state machine.
* @param phost: Host Handle
* @retval USBH Status
*/
static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost)
{
uint32_t i = 0;
/* Clear Pipes flags*/
for ( ; i < USBH_MAX_PIPES_NBR; i++)
{
phost->Pipes[i] = 0;
}
for(i = 0; i< USBH_MAX_DATA_BUFFER; i++)
{
phost->device.Data[i] = 0;
}
phost->gState = HOST_IDLE;
phost->EnumState = ENUM_IDLE;
phost->RequestState = CMD_SEND;
phost->Timer = 0;
phost->Control.state = CTRL_SETUP;
phost->Control.pipe_size = USBH_MPS_DEFAULT;
phost->Control.errorcount = 0;
phost->device.address = USBH_ADDRESS_DEFAULT;
phost->device.speed = USBH_SPEED_FULL;
return USBH_OK;
}
/**
* @brief USBH_RegisterClass
* Link class driver to Host Core.
* @param phost : Host Handle
* @param pclass: Class handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass)
{
USBH_StatusTypeDef status = USBH_OK;
if(pclass != 0)
{
if(phost->ClassNumber < USBH_MAX_NUM_SUPPORTED_CLASS)
{
/* link the class to the USB Host handle */
phost->pClass[phost->ClassNumber++] = pclass;
status = USBH_OK;
}
else
{
USBH_ErrLog("Max Class Number reached");
status = USBH_FAIL;
}
}
else
{
USBH_ErrLog("Invalid Class handle");
status = USBH_FAIL;
}
return status;
}
/**
* @brief USBH_SelectInterface
* Select current interface.
* @param phost: Host Handle
* @param interface: Interface number
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface)
{
USBH_StatusTypeDef status = USBH_OK;
if(interface < phost->device.CfgDesc.bNumInterfaces)
{
phost->device.current_interface = interface;
USBH_UsrLog ("Switching to Interface (#%d)", interface);
USBH_UsrLog ("Class : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass );
USBH_UsrLog ("SubClass : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass );
USBH_UsrLog ("Protocol : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceProtocol );
}
else
{
USBH_ErrLog ("Cannot Select This Interface.");
status = USBH_FAIL;
}
return status;
}
/**
* @brief USBH_GetActiveClass
* Return Device Class.
* @param phost: Host Handle
* @param interface: Interface index
* @retval Class Code
*/
uint8_t USBH_GetActiveClass(USBH_HandleTypeDef *phost)
{
return (phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass);
}
/**
* @brief USBH_FindInterface
* Find the interface index for a specific class.
* @param phost: Host Handle
* @param Class: Class code
* @param SubClass: SubClass code
* @param Protocol: Protocol code
* @retval interface index in the configuration structure
* @note : (1)interface index 0xFF means interface index not found
*/
uint8_t USBH_FindInterface(USBH_HandleTypeDef *phost, uint8_t Class, uint8_t SubClass, uint8_t Protocol)
{
USBH_InterfaceDescTypeDef *pif ;
USBH_CfgDescTypeDef *pcfg ;
int8_t if_ix = 0;
pif = (USBH_InterfaceDescTypeDef *)0;
pcfg = &phost->device.CfgDesc;
while (if_ix < USBH_MAX_NUM_INTERFACES)
{
pif = &pcfg->Itf_Desc[if_ix];
if(((pif->bInterfaceClass == Class) || (Class == 0xFF))&&
((pif->bInterfaceSubClass == SubClass) || (SubClass == 0xFF))&&
((pif->bInterfaceProtocol == Protocol) || (Protocol == 0xFF)))
{
return if_ix;
}
if_ix++;
}
return 0xFF;
}
/**
* @brief USBH_FindInterfaceIndex
* Find the interface index for a specific class interface and alternate setting number.
* @param phost: Host Handle
* @param interface_number: interface number
* @param alt_settings : alternate setting number
* @retval interface index in the configuration structure
* @note : (1)interface index 0xFF means interface index not found
*/
uint8_t USBH_FindInterfaceIndex(USBH_HandleTypeDef *phost, uint8_t interface_number, uint8_t alt_settings)
{
USBH_InterfaceDescTypeDef *pif ;
USBH_CfgDescTypeDef *pcfg ;
int8_t if_ix = 0;
pif = (USBH_InterfaceDescTypeDef *)0;
pcfg = &phost->device.CfgDesc;
while (if_ix < USBH_MAX_NUM_INTERFACES)
{
pif = &pcfg->Itf_Desc[if_ix];
if((pif->bInterfaceNumber == interface_number) && (pif->bAlternateSetting == alt_settings))
{
return if_ix;
}
if_ix++;
}
return 0xFF;
}
/**
* @brief USBH_Start
* Start the USB Host Core.
* @param phost: Host Handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_Start (USBH_HandleTypeDef *phost)
{
/* Start the low level driver */
USBH_LL_Start(phost);
/* Activate VBUS on the port */
USBH_LL_DriverVBUS (phost, TRUE);
return USBH_OK;
}
/**
* @brief USBH_Stop
* Stop the USB Host Core.
* @param phost: Host Handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_Stop (USBH_HandleTypeDef *phost)
{
/* Stop and cleanup the low level driver */
USBH_LL_Stop(phost);
/* DeActivate VBUS on the port */
USBH_LL_DriverVBUS (phost, FALSE);
/* FRee Control Pipes */
USBH_FreePipe (phost, phost->Control.pipe_in);
USBH_FreePipe (phost, phost->Control.pipe_out);
return USBH_OK;
}
/**
* @brief HCD_ReEnumerate
* Perform a new Enumeration phase.
* @param phost: Host Handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_ReEnumerate (USBH_HandleTypeDef *phost)
{
/*Stop Host */
USBH_Stop(phost);
/*Device has disconnected, so wait for 200 ms */
USBH_Delay(200);
/* Set State machines in default state */
DeInitStateMachine(phost);
/* Start again the host */
USBH_Start(phost);
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
#endif
return USBH_OK;
}
/**
* @brief USBH_Process
* Background process of the USB Core.
* @param phost: Host Handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost)
{
__IO USBH_StatusTypeDef status = USBH_FAIL;
uint8_t idx = 0;
switch (phost->gState)
{
case HOST_IDLE :
if (phost->device.is_connected)
{
/* Wait for 200 ms after connection */
phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT;
USBH_Delay(200);
USBH_LL_ResetPort(phost);
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
#endif
}
break;
case HOST_DEV_WAIT_FOR_ATTACHMENT:
break;
case HOST_DEV_ATTACHED :
USBH_UsrLog("USB Device Attached");
/* Wait for 100 ms after Reset */
USBH_Delay(100);
phost->device.speed = USBH_LL_GetSpeed(phost);
phost->gState = HOST_ENUMERATION;
phost->Control.pipe_out = USBH_AllocPipe (phost, 0x00);
phost->Control.pipe_in = USBH_AllocPipe (phost, 0x80);
/* Open Control pipes */
USBH_OpenPipe (phost,
phost->Control.pipe_in,
0x80,
phost->device.address,
phost->device.speed,
USBH_EP_CONTROL,
phost->Control.pipe_size);
/* Open Control pipes */
USBH_OpenPipe (phost,
phost->Control.pipe_out,
0x00,
phost->device.address,
phost->device.speed,
USBH_EP_CONTROL,
phost->Control.pipe_size);
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
#endif
break;
case HOST_ENUMERATION:
/* Check for enumeration status */
if ( USBH_HandleEnum(phost) == USBH_OK)
{
/* The function shall return USBH_OK when full enumeration is complete */
USBH_UsrLog ("Enumeration done.");
phost->device.current_interface = 0;
if(phost->device.DevDesc.bNumConfigurations == 1)
{
USBH_UsrLog ("This device has only 1 configuration.");
phost->gState = HOST_SET_CONFIGURATION;
}
else
{
phost->gState = HOST_INPUT;
}
}
break;
case HOST_INPUT:
{
/* user callback for end of device basic enumeration */
if(phost->pUser != NULL)
{
phost->pUser(phost, HOST_USER_SELECT_CONFIGURATION);
phost->gState = HOST_SET_CONFIGURATION;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
#endif
}
}
break;
case HOST_SET_CONFIGURATION:
/* set configuration */
if (USBH_SetCfg(phost, phost->device.CfgDesc.bConfigurationValue) == USBH_OK)
{
phost->gState = HOST_CHECK_CLASS;
USBH_UsrLog ("Default configuration set.");
}
break;
case HOST_CHECK_CLASS:
if(phost->ClassNumber == 0)
{
USBH_UsrLog ("No Class has been registered.");
}
else
{
phost->pActiveClass = NULL;
for (idx = 0; idx < USBH_MAX_NUM_SUPPORTED_CLASS ; idx ++)
{
if(phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass)
{
phost->pActiveClass = phost->pClass[idx];
}
}
if(phost->pActiveClass != NULL)
{
if(phost->pActiveClass->Init(phost)== USBH_OK)
{
phost->gState = HOST_CLASS_REQUEST;
USBH_UsrLog ("%s class started.", phost->pActiveClass->Name);
/* Inform user that a class has been activated */
phost->pUser(phost, HOST_USER_CLASS_SELECTED);
}
else
{
phost->gState = HOST_ABORT_STATE;
USBH_UsrLog ("Device not supporting %s class.", phost->pActiveClass->Name);
}
}
else
{
phost->gState = HOST_ABORT_STATE;
USBH_UsrLog ("No registered class for this device.");
}
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
#endif
break;
case HOST_CLASS_REQUEST:
/* process class standard control requests state machine */
if(phost->pActiveClass != NULL)
{
status = phost->pActiveClass->Requests(phost);
if(status == USBH_OK)
{
phost->gState = HOST_CLASS;
}
}
else
{
phost->gState = HOST_ABORT_STATE;
USBH_ErrLog ("Invalid Class Driver.");
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
#endif
}
break;
case HOST_CLASS:
/* process class state machine */
if(phost->pActiveClass != NULL)
{
phost->pActiveClass->BgndProcess(phost);
}
break;
case HOST_DEV_DISCONNECTED :
DeInitStateMachine(phost);
/* Re-Initilaize Host for new Enumeration */
if(phost->pActiveClass != NULL)
{
phost->pActiveClass->DeInit(phost);
phost->pActiveClass = NULL;
}
break;
case HOST_ABORT_STATE:
default :
break;
}
return USBH_OK;
}
/**
* @brief USBH_HandleEnum
* This function includes the complete enumeration process
* @param phost: Host Handle
* @retval USBH_Status
*/
static USBH_StatusTypeDef USBH_HandleEnum (USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef Status = USBH_BUSY;
switch (phost->EnumState)
{
case ENUM_IDLE:
/* Get Device Desc for only 1st 8 bytes : To get EP0 MaxPacketSize */
if ( USBH_Get_DevDesc(phost, 8) == USBH_OK)
{
phost->Control.pipe_size = phost->device.DevDesc.bMaxPacketSize;
phost->EnumState = ENUM_GET_FULL_DEV_DESC;
/* modify control channels configuration for MaxPacket size */
USBH_OpenPipe (phost,
phost->Control.pipe_in,
0x80,
phost->device.address,
phost->device.speed,
USBH_EP_CONTROL,
phost->Control.pipe_size);
/* Open Control pipes */
USBH_OpenPipe (phost,
phost->Control.pipe_out,
0x00,
phost->device.address,
phost->device.speed,
USBH_EP_CONTROL,
phost->Control.pipe_size);
}
break;
case ENUM_GET_FULL_DEV_DESC:
/* Get FULL Device Desc */
if ( USBH_Get_DevDesc(phost, USB_DEVICE_DESC_SIZE)== USBH_OK)
{
USBH_UsrLog("PID: %xh", phost->device.DevDesc.idProduct );
USBH_UsrLog("VID: %xh", phost->device.DevDesc.idVendor );
phost->EnumState = ENUM_SET_ADDR;
}
break;
case ENUM_SET_ADDR:
/* set address */
if ( USBH_SetAddress(phost, USBH_DEVICE_ADDRESS) == USBH_OK)
{
USBH_Delay(2);
phost->device.address = USBH_DEVICE_ADDRESS;
/* user callback for device address assigned */
USBH_UsrLog("Address (#%d) assigned.", phost->device.address);
phost->EnumState = ENUM_GET_CFG_DESC;
/* modify control channels to update device address */
USBH_OpenPipe (phost,
phost->Control.pipe_in,
0x80,
phost->device.address,
phost->device.speed,
USBH_EP_CONTROL,
phost->Control.pipe_size);
/* Open Control pipes */
USBH_OpenPipe (phost,
phost->Control.pipe_out,
0x00,
phost->device.address,
phost->device.speed,
USBH_EP_CONTROL,
phost->Control.pipe_size);
}
break;
case ENUM_GET_CFG_DESC:
/* get standard configuration descriptor */
if ( USBH_Get_CfgDesc(phost,
USB_CONFIGURATION_DESC_SIZE) == USBH_OK)
{
phost->EnumState = ENUM_GET_FULL_CFG_DESC;
}
break;
case ENUM_GET_FULL_CFG_DESC:
/* get FULL config descriptor (config, interface, endpoints) */
if (USBH_Get_CfgDesc(phost,
phost->device.CfgDesc.wTotalLength) == USBH_OK)
{
phost->EnumState = ENUM_GET_MFC_STRING_DESC;
}
break;
case ENUM_GET_MFC_STRING_DESC:
if (phost->device.DevDesc.iManufacturer != 0)
{ /* Check that Manufacturer String is available */
if ( USBH_Get_StringDesc(phost,
phost->device.DevDesc.iManufacturer,
phost->device.Data ,
0xff) == USBH_OK)
{
/* User callback for Manufacturing string */
USBH_UsrLog("Manufacturer : %s", (char *)phost->device.Data);
phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
#endif
}
}
else
{
USBH_UsrLog("Manufacturer : N/A");
phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
#endif
}
break;
case ENUM_GET_PRODUCT_STRING_DESC:
if (phost->device.DevDesc.iProduct != 0)
{ /* Check that Product string is available */
if ( USBH_Get_StringDesc(phost,
phost->device.DevDesc.iProduct,
phost->device.Data,
0xff) == USBH_OK)
{
/* User callback for Product string */
USBH_UsrLog("Product : %s", (char *)phost->device.Data);
phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
}
}
else
{
USBH_UsrLog("Product : N/A");
phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
#endif
}
break;
case ENUM_GET_SERIALNUM_STRING_DESC:
if (phost->device.DevDesc.iSerialNumber != 0)
{ /* Check that Serial number string is available */
if ( USBH_Get_StringDesc(phost,
phost->device.DevDesc.iSerialNumber,
phost->device.Data,
0xff) == USBH_OK)
{
/* User callback for Serial number string */
USBH_UsrLog("Serial Number : %s", (char *)phost->device.Data);
Status = USBH_OK;
}
}
else
{
USBH_UsrLog("Serial Number : N/A");
Status = USBH_OK;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
#endif
}
break;
default:
break;
}
return Status;
}
/**
* @brief USBH_LL_SetTimer
* Set the initial Host Timer tick
* @param phost: Host Handle
* @retval None
*/
void USBH_LL_SetTimer (USBH_HandleTypeDef *phost, uint32_t time)
{
phost->Timer = time;
}
/**
* @brief USBH_LL_IncTimer
* Increment Host Timer tick
* @param phost: Host Handle
* @retval None
*/
void USBH_LL_IncTimer (USBH_HandleTypeDef *phost)
{
phost->Timer ++;
USBH_HandleSof(phost);
}
/**
* @brief USBH_HandleSof
* Call SOF process
* @param phost: Host Handle
* @retval None
*/
void USBH_HandleSof (USBH_HandleTypeDef *phost)
{
if((phost->gState == HOST_CLASS)&&(phost->pActiveClass != NULL))
{
phost->pActiveClass->SOFProcess(phost);
}
}
/**
* @brief USBH_LL_Connect
* Handle USB Host connexion event
* @param phost: Host Handle
* @retval USBH_Status
*/
USBH_StatusTypeDef USBH_LL_Connect (USBH_HandleTypeDef *phost)
{
if(phost->gState == HOST_IDLE )
{
phost->device.is_connected = 1;
if(phost->pUser != NULL)
{
phost->pUser(phost, HOST_USER_CONNECTION);
}
}
else if(phost->gState == HOST_DEV_WAIT_FOR_ATTACHMENT )
{
phost->gState = HOST_DEV_ATTACHED ;
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
#endif
return USBH_OK;
}
/**
* @brief USBH_LL_Disconnect
* Handle USB Host disconnection event
* @param phost: Host Handle
* @retval USBH_Status
*/
USBH_StatusTypeDef USBH_LL_Disconnect (USBH_HandleTypeDef *phost)
{
/*Stop Host */
USBH_LL_Stop(phost);
/* FRee Control Pipes */
USBH_FreePipe (phost, phost->Control.pipe_in);
USBH_FreePipe (phost, phost->Control.pipe_out);
phost->device.is_connected = 0;
if(phost->pUser != NULL)
{
phost->pUser(phost, HOST_USER_DISCONNECTION);
}
USBH_UsrLog("USB Device disconnected");
/* Start the low level driver */
USBH_LL_Start(phost);
phost->gState = HOST_DEV_DISCONNECTED;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
#endif
return USBH_OK;
}
#if (USBH_USE_OS == 1)
/**
* @brief USB Host Thread task
* @param pvParameters not used
* @retval None
*/
static void USBH_Process_OS(void const * argument)
{
osEvent event;
for(;;)
{
event = osMessageGet(((USBH_HandleTypeDef *)argument)->os_event, osWaitForever );
if( event.status == osEventMessage )
{
USBH_Process((USBH_HandleTypeDef *)argument);
}
}
}
/**
* @brief USBH_LL_NotifyURBChange
* Notify URB state Change
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_LL_NotifyURBChange (USBH_HandleTypeDef *phost)
{
osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
return USBH_OK;
}
#endif
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,881 @@
/**
******************************************************************************
* @file usbh_ctlreq.c
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief This file implements the control requests for device enumeration
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbh_ctlreq.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_LIB_CORE
* @{
*/
/** @defgroup USBH_CTLREQ
* @brief This file implements the standard requests for device enumeration
* @{
*/
/** @defgroup USBH_CTLREQ_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CTLREQ_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CTLREQ_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CTLREQ_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_CTLREQ_Private_FunctionPrototypes
* @{
*/
static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost);
static void USBH_ParseDevDesc (USBH_DevDescTypeDef* , uint8_t *buf, uint16_t length);
static void USBH_ParseCfgDesc (USBH_CfgDescTypeDef* cfg_desc,
uint8_t *buf,
uint16_t length);
static void USBH_ParseEPDesc (USBH_EpDescTypeDef *ep_descriptor, uint8_t *buf);
static void USBH_ParseStringDesc (uint8_t* psrc, uint8_t* pdest, uint16_t length);
static void USBH_ParseInterfaceDesc (USBH_InterfaceDescTypeDef *if_descriptor, uint8_t *buf);
/**
* @}
*/
/** @defgroup USBH_CTLREQ_Private_Functions
* @{
*/
/**
* @brief USBH_Get_DevDesc
* Issue Get Device Descriptor command to the device. Once the response
* received, it parses the device descriptor and updates the status.
* @param phost: Host Handle
* @param length: Length of the descriptor
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost, uint8_t length)
{
USBH_StatusTypeDef status;
if((status = USBH_GetDescriptor(phost,
USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
USB_DESC_DEVICE,
phost->device.Data,
length)) == USBH_OK)
{
/* Commands successfully sent and Response Received */
USBH_ParseDevDesc(&phost->device.DevDesc, phost->device.Data, length);
}
return status;
}
/**
* @brief USBH_Get_CfgDesc
* Issues Configuration Descriptor to the device. Once the response
* received, it parses the configuration descriptor and updates the
* status.
* @param phost: Host Handle
* @param length: Length of the descriptor
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_Get_CfgDesc(USBH_HandleTypeDef *phost,
uint16_t length)
{
USBH_StatusTypeDef status;
uint8_t *pData;
#if (USBH_KEEP_CFG_DESCRIPTOR == 1)
pData = phost->device.CfgDesc_Raw;
#else
pData = phost->device.Data;
#endif
if((status = USBH_GetDescriptor(phost,
USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
USB_DESC_CONFIGURATION,
pData,
length)) == USBH_OK)
{
/* Commands successfully sent and Response Received */
USBH_ParseCfgDesc (&phost->device.CfgDesc,
pData,
length);
}
return status;
}
/**
* @brief USBH_Get_StringDesc
* Issues string Descriptor command to the device. Once the response
* received, it parses the string descriptor and updates the status.
* @param phost: Host Handle
* @param string_index: String index for the descriptor
* @param buff: Buffer address for the descriptor
* @param length: Length of the descriptor
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost,
uint8_t string_index,
uint8_t *buff,
uint16_t length)
{
USBH_StatusTypeDef status;
if((status = USBH_GetDescriptor(phost,
USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
USB_DESC_STRING | string_index,
phost->device.Data,
length)) == USBH_OK)
{
/* Commands successfully sent and Response Received */
USBH_ParseStringDesc(phost->device.Data,buff, length);
}
return status;
}
/**
* @brief USBH_GetDescriptor
* Issues Descriptor command to the device. Once the response received,
* it parses the descriptor and updates the status.
* @param phost: Host Handle
* @param req_type: Descriptor type
* @param value_idx: Value for the GetDescriptr request
* @param buff: Buffer to store the descriptor
* @param length: Length of the descriptor
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost,
uint8_t req_type,
uint16_t value_idx,
uint8_t* buff,
uint16_t length )
{
if(phost->RequestState == CMD_SEND)
{
phost->Control.setup.b.bmRequestType = USB_D2H | req_type;
phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR;
phost->Control.setup.b.wValue.w = value_idx;
if ((value_idx & 0xff00) == USB_DESC_STRING)
{
phost->Control.setup.b.wIndex.w = 0x0409;
}
else
{
phost->Control.setup.b.wIndex.w = 0;
}
phost->Control.setup.b.wLength.w = length;
}
return USBH_CtlReq(phost, buff , length );
}
/**
* @brief USBH_SetAddress
* This command sets the address to the connected device
* @param phost: Host Handle
* @param DeviceAddress: Device address to assign
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost,
uint8_t DeviceAddress)
{
if(phost->RequestState == CMD_SEND)
{
phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE | \
USB_REQ_TYPE_STANDARD;
phost->Control.setup.b.bRequest = USB_REQ_SET_ADDRESS;
phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress;
phost->Control.setup.b.wIndex.w = 0;
phost->Control.setup.b.wLength.w = 0;
}
return USBH_CtlReq(phost, 0 , 0 );
}
/**
* @brief USBH_SetCfg
* The command sets the configuration value to the connected device
* @param phost: Host Handle
* @param cfg_idx: Configuration value
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost,
uint16_t cfg_idx)
{
if(phost->RequestState == CMD_SEND)
{
phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE |\
USB_REQ_TYPE_STANDARD;
phost->Control.setup.b.bRequest = USB_REQ_SET_CONFIGURATION;
phost->Control.setup.b.wValue.w = cfg_idx;
phost->Control.setup.b.wIndex.w = 0;
phost->Control.setup.b.wLength.w = 0;
}
return USBH_CtlReq(phost, 0 , 0 );
}
/**
* @brief USBH_SetInterface
* The command sets the Interface value to the connected device
* @param phost: Host Handle
* @param altSetting: Interface value
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost,
uint8_t ep_num, uint8_t altSetting)
{
if(phost->RequestState == CMD_SEND)
{
phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | \
USB_REQ_TYPE_STANDARD;
phost->Control.setup.b.bRequest = USB_REQ_SET_INTERFACE;
phost->Control.setup.b.wValue.w = altSetting;
phost->Control.setup.b.wIndex.w = ep_num;
phost->Control.setup.b.wLength.w = 0;
}
return USBH_CtlReq(phost, 0 , 0 );
}
/**
* @brief USBH_ClrFeature
* This request is used to clear or disable a specific feature.
* @param phost: Host Handle
* @param ep_num: endpoint number
* @param hc_num: Host channel number
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost,
uint8_t ep_num)
{
if(phost->RequestState == CMD_SEND)
{
phost->Control.setup.b.bmRequestType = USB_H2D |
USB_REQ_RECIPIENT_ENDPOINT |
USB_REQ_TYPE_STANDARD;
phost->Control.setup.b.bRequest = USB_REQ_CLEAR_FEATURE;
phost->Control.setup.b.wValue.w = FEATURE_SELECTOR_ENDPOINT;
phost->Control.setup.b.wIndex.w = ep_num;
phost->Control.setup.b.wLength.w = 0;
}
return USBH_CtlReq(phost, 0 , 0 );
}
/**
* @brief USBH_ParseDevDesc
* This function Parses the device descriptor
* @param dev_desc: device_descriptor destination address
* @param buf: Buffer where the source descriptor is available
* @param length: Length of the descriptor
* @retval None
*/
static void USBH_ParseDevDesc (USBH_DevDescTypeDef* dev_desc,
uint8_t *buf,
uint16_t length)
{
dev_desc->bLength = *(uint8_t *) (buf + 0);
dev_desc->bDescriptorType = *(uint8_t *) (buf + 1);
dev_desc->bcdUSB = LE16 (buf + 2);
dev_desc->bDeviceClass = *(uint8_t *) (buf + 4);
dev_desc->bDeviceSubClass = *(uint8_t *) (buf + 5);
dev_desc->bDeviceProtocol = *(uint8_t *) (buf + 6);
dev_desc->bMaxPacketSize = *(uint8_t *) (buf + 7);
if (length > 8)
{ /* For 1st time after device connection, Host may issue only 8 bytes for
Device Descriptor Length */
dev_desc->idVendor = LE16 (buf + 8);
dev_desc->idProduct = LE16 (buf + 10);
dev_desc->bcdDevice = LE16 (buf + 12);
dev_desc->iManufacturer = *(uint8_t *) (buf + 14);
dev_desc->iProduct = *(uint8_t *) (buf + 15);
dev_desc->iSerialNumber = *(uint8_t *) (buf + 16);
dev_desc->bNumConfigurations = *(uint8_t *) (buf + 17);
}
}
/**
* @brief USBH_ParseCfgDesc
* This function Parses the configuration descriptor
* @param cfg_desc: Configuration Descriptor address
* @param buf: Buffer where the source descriptor is available
* @param length: Length of the descriptor
* @retval None
*/
static void USBH_ParseCfgDesc (USBH_CfgDescTypeDef* cfg_desc,
uint8_t *buf,
uint16_t length)
{
USBH_InterfaceDescTypeDef *pif ;
USBH_EpDescTypeDef *pep;
USBH_DescHeader_t *pdesc = (USBH_DescHeader_t *)buf;
uint16_t ptr;
int8_t if_ix = 0;
int8_t ep_ix = 0;
pdesc = (USBH_DescHeader_t *)buf;
/* Parse configuration descriptor */
cfg_desc->bLength = *(uint8_t *) (buf + 0);
cfg_desc->bDescriptorType = *(uint8_t *) (buf + 1);
cfg_desc->wTotalLength = LE16 (buf + 2);
cfg_desc->bNumInterfaces = *(uint8_t *) (buf + 4);
cfg_desc->bConfigurationValue = *(uint8_t *) (buf + 5);
cfg_desc->iConfiguration = *(uint8_t *) (buf + 6);
cfg_desc->bmAttributes = *(uint8_t *) (buf + 7);
cfg_desc->bMaxPower = *(uint8_t *) (buf + 8);
if (length > USB_CONFIGURATION_DESC_SIZE)
{
ptr = USB_LEN_CFG_DESC;
pif = (USBH_InterfaceDescTypeDef *)0;
while ((if_ix < USBH_MAX_NUM_INTERFACES ) && (ptr < cfg_desc->wTotalLength))
{
pdesc = USBH_GetNextDesc((uint8_t *)pdesc, &ptr);
if (pdesc->bDescriptorType == USB_DESC_TYPE_INTERFACE)
{
pif = &cfg_desc->Itf_Desc[if_ix];
USBH_ParseInterfaceDesc (pif, (uint8_t *)pdesc);
ep_ix = 0;
pep = (USBH_EpDescTypeDef *)0;
while ((ep_ix < pif->bNumEndpoints) && (ptr < cfg_desc->wTotalLength))
{
pdesc = USBH_GetNextDesc((uint8_t*) pdesc, &ptr);
if (pdesc->bDescriptorType == USB_DESC_TYPE_ENDPOINT)
{
pep = &cfg_desc->Itf_Desc[if_ix].Ep_Desc[ep_ix];
USBH_ParseEPDesc (pep, (uint8_t *)pdesc);
ep_ix++;
}
}
if_ix++;
}
}
}
}
/**
* @brief USBH_ParseInterfaceDesc
* This function Parses the interface descriptor
* @param if_descriptor : Interface descriptor destination
* @param buf: Buffer where the descriptor data is available
* @retval None
*/
static void USBH_ParseInterfaceDesc (USBH_InterfaceDescTypeDef *if_descriptor,
uint8_t *buf)
{
if_descriptor->bLength = *(uint8_t *) (buf + 0);
if_descriptor->bDescriptorType = *(uint8_t *) (buf + 1);
if_descriptor->bInterfaceNumber = *(uint8_t *) (buf + 2);
if_descriptor->bAlternateSetting = *(uint8_t *) (buf + 3);
if_descriptor->bNumEndpoints = *(uint8_t *) (buf + 4);
if_descriptor->bInterfaceClass = *(uint8_t *) (buf + 5);
if_descriptor->bInterfaceSubClass = *(uint8_t *) (buf + 6);
if_descriptor->bInterfaceProtocol = *(uint8_t *) (buf + 7);
if_descriptor->iInterface = *(uint8_t *) (buf + 8);
}
/**
* @brief USBH_ParseEPDesc
* This function Parses the endpoint descriptor
* @param ep_descriptor: Endpoint descriptor destination address
* @param buf: Buffer where the parsed descriptor stored
* @retval None
*/
static void USBH_ParseEPDesc (USBH_EpDescTypeDef *ep_descriptor,
uint8_t *buf)
{
ep_descriptor->bLength = *(uint8_t *) (buf + 0);
ep_descriptor->bDescriptorType = *(uint8_t *) (buf + 1);
ep_descriptor->bEndpointAddress = *(uint8_t *) (buf + 2);
ep_descriptor->bmAttributes = *(uint8_t *) (buf + 3);
ep_descriptor->wMaxPacketSize = LE16 (buf + 4);
ep_descriptor->bInterval = *(uint8_t *) (buf + 6);
}
/**
* @brief USBH_ParseStringDesc
* This function Parses the string descriptor
* @param psrc: Source pointer containing the descriptor data
* @param pdest: Destination address pointer
* @param length: Length of the descriptor
* @retval None
*/
static void USBH_ParseStringDesc (uint8_t* psrc,
uint8_t* pdest,
uint16_t length)
{
uint16_t strlength;
uint16_t idx;
/* The UNICODE string descriptor is not NULL-terminated. The string length is
computed by substracting two from the value of the first byte of the descriptor.
*/
/* Check which is lower size, the Size of string or the length of bytes read
from the device */
if ( psrc[1] == USB_DESC_TYPE_STRING)
{ /* Make sure the Descriptor is String Type */
/* psrc[0] contains Size of Descriptor, subtract 2 to get the length of string */
strlength = ( ( (psrc[0]-2) <= length) ? (psrc[0]-2) :length);
psrc += 2; /* Adjust the offset ignoring the String Len and Descriptor type */
for (idx = 0; idx < strlength; idx+=2 )
{/* Copy Only the string and ignore the UNICODE ID, hence add the src */
*pdest = psrc[idx];
pdest++;
}
*pdest = 0; /* mark end of string */
}
}
/**
* @brief USBH_GetNextDesc
* This function return the next descriptor header
* @param buf: Buffer where the cfg descriptor is available
* @param ptr: data pointer inside the cfg descriptor
* @retval next header
*/
USBH_DescHeader_t *USBH_GetNextDesc (uint8_t *pbuf, uint16_t *ptr)
{
USBH_DescHeader_t *pnext;
*ptr += ((USBH_DescHeader_t *)pbuf)->bLength;
pnext = (USBH_DescHeader_t *)((uint8_t *)pbuf + \
((USBH_DescHeader_t *)pbuf)->bLength);
return(pnext);
}
/**
* @brief USBH_CtlReq
* USBH_CtlReq sends a control request and provide the status after
* completion of the request
* @param phost: Host Handle
* @param req: Setup Request Structure
* @param buff: data buffer address to store the response
* @param length: length of the response
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_CtlReq (USBH_HandleTypeDef *phost,
uint8_t *buff,
uint16_t length)
{
USBH_StatusTypeDef status;
status = USBH_BUSY;
switch (phost->RequestState)
{
case CMD_SEND:
/* Start a SETUP transfer */
phost->Control.buff = buff;
phost->Control.length = length;
phost->Control.state = CTRL_SETUP;
phost->RequestState = CMD_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
break;
case CMD_WAIT:
status = USBH_HandleControl(phost);
if (status == USBH_OK)
{
/* Commands successfully sent and Response Received */
phost->RequestState = CMD_SEND;
phost->Control.state =CTRL_IDLE;
status = USBH_OK;
}
else if (status == USBH_FAIL)
{
/* Failure Mode */
phost->RequestState = CMD_SEND;
status = USBH_FAIL;
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_HandleControl
* Handles the USB control transfer state machine
* @param phost: Host Handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost)
{
uint8_t direction;
USBH_StatusTypeDef status = USBH_BUSY;
USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
switch (phost->Control.state)
{
case CTRL_SETUP:
/* send a SETUP packet */
USBH_CtlSendSetup (phost,
(uint8_t *)phost->Control.setup.d8 ,
phost->Control.pipe_out);
phost->Control.state = CTRL_SETUP_WAIT;
break;
case CTRL_SETUP_WAIT:
URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
/* case SETUP packet sent successfully */
if(URB_Status == USBH_URB_DONE)
{
direction = (phost->Control.setup.b.bmRequestType & USB_REQ_DIR_MASK);
/* check if there is a data stage */
if (phost->Control.setup.b.wLength.w != 0 )
{
if (direction == USB_D2H)
{
/* Data Direction is IN */
phost->Control.state = CTRL_DATA_IN;
}
else
{
/* Data Direction is OUT */
phost->Control.state = CTRL_DATA_OUT;
}
}
/* No DATA stage */
else
{
/* If there is No Data Transfer Stage */
if (direction == USB_D2H)
{
/* Data Direction is IN */
phost->Control.state = CTRL_STATUS_OUT;
}
else
{
/* Data Direction is OUT */
phost->Control.state = CTRL_STATUS_IN;
}
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if(URB_Status == USBH_URB_ERROR)
{
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
break;
case CTRL_DATA_IN:
/* Issue an IN token */
phost->Control.timer = phost->Timer;
USBH_CtlReceiveData(phost,
phost->Control.buff,
phost->Control.length,
phost->Control.pipe_in);
phost->Control.state = CTRL_DATA_IN_WAIT;
break;
case CTRL_DATA_IN_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in);
/* check is DATA packet transferred successfully */
if (URB_Status == USBH_URB_DONE)
{
phost->Control.state = CTRL_STATUS_OUT;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
/* manage error cases*/
if (URB_Status == USBH_URB_STALL)
{
/* In stall case, return to previous machine state*/
status = USBH_NOT_SUPPORTED;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_ERROR)
{
/* Device error */
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
break;
case CTRL_DATA_OUT:
USBH_CtlSendData (phost,
phost->Control.buff,
phost->Control.length ,
phost->Control.pipe_out,
1);
phost->Control.timer = phost->Timer;
phost->Control.state = CTRL_DATA_OUT_WAIT;
break;
case CTRL_DATA_OUT_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out);
if (URB_Status == USBH_URB_DONE)
{ /* If the Setup Pkt is sent successful, then change the state */
phost->Control.state = CTRL_STATUS_IN;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
/* handle error cases */
else if (URB_Status == USBH_URB_STALL)
{
/* In stall case, return to previous machine state*/
phost->Control.state = CTRL_STALLED;
status = USBH_NOT_SUPPORTED;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_NOTREADY)
{
/* Nack received from device */
phost->Control.state = CTRL_DATA_OUT;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_ERROR)
{
/* device error */
phost->Control.state = CTRL_ERROR;
status = USBH_FAIL;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
break;
case CTRL_STATUS_IN:
/* Send 0 bytes out packet */
USBH_CtlReceiveData (phost,
0,
0,
phost->Control.pipe_in);
phost->Control.timer = phost->Timer;
phost->Control.state = CTRL_STATUS_IN_WAIT;
break;
case CTRL_STATUS_IN_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in);
if ( URB_Status == USBH_URB_DONE)
{ /* Control transfers completed, Exit the State Machine */
phost->Control.state = CTRL_COMPLETE;
status = USBH_OK;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_ERROR)
{
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if(URB_Status == USBH_URB_STALL)
{
/* Control transfers completed, Exit the State Machine */
status = USBH_NOT_SUPPORTED;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
break;
case CTRL_STATUS_OUT:
USBH_CtlSendData (phost,
0,
0,
phost->Control.pipe_out,
1);
phost->Control.timer = phost->Timer;
phost->Control.state = CTRL_STATUS_OUT_WAIT;
break;
case CTRL_STATUS_OUT_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out);
if (URB_Status == USBH_URB_DONE)
{
status = USBH_OK;
phost->Control.state = CTRL_COMPLETE;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_NOTREADY)
{
phost->Control.state = CTRL_STATUS_OUT;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_ERROR)
{
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
break;
case CTRL_ERROR:
/*
After a halt condition is encountered or an error is detected by the
host, a control endpoint is allowed to recover by accepting the next Setup
PID; i.e., recovery actions via some other pipe are not required for control
endpoints. For the Default Control Pipe, a device reset will ultimately be
required to clear the halt or error condition if the next Setup PID is not
accepted.
*/
if (++ phost->Control.errorcount <= USBH_MAX_ERROR_COUNT)
{
/* try to recover control */
USBH_LL_Stop(phost);
/* Do the transmission again, starting from SETUP Packet */
phost->Control.state = CTRL_SETUP;
phost->RequestState = CMD_SEND;
}
else
{
phost->pUser(phost, HOST_USER_UNRECOVERED_ERROR);
phost->Control.errorcount = 0;
USBH_ErrLog("Control error");
status = USBH_FAIL;
}
break;
default:
break;
}
return status;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,358 @@
/**
******************************************************************************
* @file usbh_ioreq.c
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief This file handles the issuing of the USB transactions
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbh_ioreq.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_LIB_CORE
* @{
*/
/** @defgroup USBH_IOREQ
* @brief This file handles the standard protocol processing (USB v2.0)
* @{
*/
/** @defgroup USBH_IOREQ_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBH_IOREQ_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBH_IOREQ_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_IOREQ_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_IOREQ_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @defgroup USBH_IOREQ_Private_Functions
* @{
*/
/**
* @brief USBH_CtlSendSetup
* Sends the Setup Packet to the Device
* @param phost: Host Handle
* @param buff: Buffer pointer from which the Data will be send to Device
* @param pipe_num: Pipe Number
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_CtlSendSetup (USBH_HandleTypeDef *phost,
uint8_t *buff,
uint8_t pipe_num)
{
USBH_LL_SubmitURB (phost, /* Driver handle */
pipe_num, /* Pipe index */
0, /* Direction : OUT */
USBH_EP_CONTROL, /* EP type */
USBH_PID_SETUP, /* Type setup */
buff, /* data buffer */
USBH_SETUP_PKT_SIZE, /* data length */
0);
return USBH_OK;
}
/**
* @brief USBH_CtlSendData
* Sends a data Packet to the Device
* @param phost: Host Handle
* @param buff: Buffer pointer from which the Data will be sent to Device
* @param length: Length of the data to be sent
* @param pipe_num: Pipe Number
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_CtlSendData (USBH_HandleTypeDef *phost,
uint8_t *buff,
uint16_t length,
uint8_t pipe_num,
uint8_t do_ping )
{
if(phost->device.speed != USBH_SPEED_HIGH)
{
do_ping = 0;
}
USBH_LL_SubmitURB (phost, /* Driver handle */
pipe_num, /* Pipe index */
0, /* Direction : OUT */
USBH_EP_CONTROL, /* EP type */
USBH_PID_DATA, /* Type Data */
buff, /* data buffer */
length, /* data length */
do_ping); /* do ping (HS Only)*/
return USBH_OK;
}
/**
* @brief USBH_CtlReceiveData
* Receives the Device Response to the Setup Packet
* @param phost: Host Handle
* @param buff: Buffer pointer in which the response needs to be copied
* @param length: Length of the data to be received
* @param pipe_num: Pipe Number
* @retval USBH Status.
*/
USBH_StatusTypeDef USBH_CtlReceiveData(USBH_HandleTypeDef *phost,
uint8_t* buff,
uint16_t length,
uint8_t pipe_num)
{
USBH_LL_SubmitURB (phost, /* Driver handle */
pipe_num, /* Pipe index */
1, /* Direction : IN */
USBH_EP_CONTROL, /* EP type */
USBH_PID_DATA, /* Type Data */
buff, /* data buffer */
length, /* data length */
0);
return USBH_OK;
}
/**
* @brief USBH_BulkSendData
* Sends the Bulk Packet to the device
* @param phost: Host Handle
* @param buff: Buffer pointer from which the Data will be sent to Device
* @param length: Length of the data to be sent
* @param pipe_num: Pipe Number
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_BulkSendData (USBH_HandleTypeDef *phost,
uint8_t *buff,
uint16_t length,
uint8_t pipe_num,
uint8_t do_ping )
{
if(phost->device.speed != USBH_SPEED_HIGH)
{
do_ping = 0;
}
USBH_LL_SubmitURB (phost, /* Driver handle */
pipe_num, /* Pipe index */
0, /* Direction : IN */
USBH_EP_BULK, /* EP type */
USBH_PID_DATA, /* Type Data */
buff, /* data buffer */
length, /* data length */
do_ping); /* do ping (HS Only)*/
return USBH_OK;
}
/**
* @brief USBH_BulkReceiveData
* Receives IN bulk packet from device
* @param phost: Host Handle
* @param buff: Buffer pointer in which the received data packet to be copied
* @param length: Length of the data to be received
* @param pipe_num: Pipe Number
* @retval USBH Status.
*/
USBH_StatusTypeDef USBH_BulkReceiveData(USBH_HandleTypeDef *phost,
uint8_t *buff,
uint16_t length,
uint8_t pipe_num)
{
USBH_LL_SubmitURB (phost, /* Driver handle */
pipe_num, /* Pipe index */
1, /* Direction : IN */
USBH_EP_BULK, /* EP type */
USBH_PID_DATA, /* Type Data */
buff, /* data buffer */
length, /* data length */
0);
return USBH_OK;
}
/**
* @brief USBH_InterruptReceiveData
* Receives the Device Response to the Interrupt IN token
* @param phost: Host Handle
* @param buff: Buffer pointer in which the response needs to be copied
* @param length: Length of the data to be received
* @param pipe_num: Pipe Number
* @retval USBH Status.
*/
USBH_StatusTypeDef USBH_InterruptReceiveData(USBH_HandleTypeDef *phost,
uint8_t *buff,
uint8_t length,
uint8_t pipe_num)
{
USBH_LL_SubmitURB (phost, /* Driver handle */
pipe_num, /* Pipe index */
1, /* Direction : IN */
USBH_EP_INTERRUPT, /* EP type */
USBH_PID_DATA, /* Type Data */
buff, /* data buffer */
length, /* data length */
0);
return USBH_OK;
}
/**
* @brief USBH_InterruptSendData
* Sends the data on Interrupt OUT Endpoint
* @param phost: Host Handle
* @param buff: Buffer pointer from where the data needs to be copied
* @param length: Length of the data to be sent
* @param pipe_num: Pipe Number
* @retval USBH Status.
*/
USBH_StatusTypeDef USBH_InterruptSendData(USBH_HandleTypeDef *phost,
uint8_t *buff,
uint8_t length,
uint8_t pipe_num)
{
USBH_LL_SubmitURB (phost, /* Driver handle */
pipe_num, /* Pipe index */
0, /* Direction : OUT */
USBH_EP_INTERRUPT, /* EP type */
USBH_PID_DATA, /* Type Data */
buff, /* data buffer */
length, /* data length */
0);
return USBH_OK;
}
/**
* @brief USBH_IsocReceiveData
* Receives the Device Response to the Isochronous IN token
* @param phost: Host Handle
* @param buff: Buffer pointer in which the response needs to be copied
* @param length: Length of the data to be received
* @param pipe_num: Pipe Number
* @retval USBH Status.
*/
USBH_StatusTypeDef USBH_IsocReceiveData(USBH_HandleTypeDef *phost,
uint8_t *buff,
uint32_t length,
uint8_t pipe_num)
{
USBH_LL_SubmitURB (phost, /* Driver handle */
pipe_num, /* Pipe index */
1, /* Direction : IN */
USBH_EP_ISO, /* EP type */
USBH_PID_DATA, /* Type Data */
buff, /* data buffer */
length, /* data length */
0);
return USBH_OK;
}
/**
* @brief USBH_IsocSendData
* Sends the data on Isochronous OUT Endpoint
* @param phost: Host Handle
* @param buff: Buffer pointer from where the data needs to be copied
* @param length: Length of the data to be sent
* @param pipe_num: Pipe Number
* @retval USBH Status.
*/
USBH_StatusTypeDef USBH_IsocSendData(USBH_HandleTypeDef *phost,
uint8_t *buff,
uint32_t length,
uint8_t pipe_num)
{
USBH_LL_SubmitURB (phost, /* Driver handle */
pipe_num, /* Pipe index */
0, /* Direction : OUT */
USBH_EP_ISO, /* EP type */
USBH_PID_DATA, /* Type Data */
buff, /* data buffer */
length, /* data length */
0);
return USBH_OK;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,204 @@
/**
******************************************************************************
* @file usbh_pipes.c
* @author MCD Application Team
* @version V3.2.2
* @date 07-July-2015
* @brief This file implements functions for opening and closing Pipes
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbh_pipes.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_LIB_CORE
* @{
*/
/** @defgroup USBH_PIPES
* @brief This file includes opening and closing Pipes
* @{
*/
/** @defgroup USBH_PIPES_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBH_PIPES_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBH_PIPES_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_PIPES_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_PIPES_Private_Functions
* @{
*/
static uint16_t USBH_GetFreePipe (USBH_HandleTypeDef *phost);
/**
* @brief USBH_Open_Pipe
* Open a pipe
* @param phost: Host Handle
* @param pipe_num: Pipe Number
* @param dev_address: USB Device address allocated to attached device
* @param speed : USB device speed (Full/Low)
* @param ep_type: end point type (Bulk/int/ctl)
* @param mps: max pkt size
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_OpenPipe (USBH_HandleTypeDef *phost,
uint8_t pipe_num,
uint8_t epnum,
uint8_t dev_address,
uint8_t speed,
uint8_t ep_type,
uint16_t mps)
{
USBH_LL_OpenPipe(phost,
pipe_num,
epnum,
dev_address,
speed,
ep_type,
mps);
return USBH_OK;
}
/**
* @brief USBH_ClosePipe
* Close a pipe
* @param phost: Host Handle
* @param pipe_num: Pipe Number
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_ClosePipe (USBH_HandleTypeDef *phost,
uint8_t pipe_num)
{
USBH_LL_ClosePipe(phost, pipe_num);
return USBH_OK;
}
/**
* @brief USBH_Alloc_Pipe
* Allocate a new Pipe
* @param phost: Host Handle
* @param ep_addr: End point for which the Pipe to be allocated
* @retval Pipe number
*/
uint8_t USBH_AllocPipe (USBH_HandleTypeDef *phost, uint8_t ep_addr)
{
uint16_t pipe;
pipe = USBH_GetFreePipe(phost);
if (pipe != 0xFFFF)
{
phost->Pipes[pipe] = 0x8000 | ep_addr;
}
return pipe;
}
/**
* @brief USBH_Free_Pipe
* Free the USB Pipe
* @param phost: Host Handle
* @param idx: Pipe number to be freed
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_FreePipe (USBH_HandleTypeDef *phost, uint8_t idx)
{
if(idx < 11)
{
phost->Pipes[idx] &= 0x7FFF;
}
return USBH_OK;
}
/**
* @brief USBH_GetFreePipe
* @param phost: Host Handle
* Get a free Pipe number for allocation to a device endpoint
* @retval idx: Free Pipe number
*/
static uint16_t USBH_GetFreePipe (USBH_HandleTypeDef *phost)
{
uint8_t idx = 0;
for (idx = 0 ; idx < 11 ; idx++)
{
if ((phost->Pipes[idx] & 0x8000) == 0)
{
return idx;
}
}
return 0xFFFF;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/