first commit

This commit is contained in:
YXZhu
2022-08-06 13:35:32 +08:00
commit 2240710d39
1025 changed files with 472118 additions and 0 deletions
@@ -0,0 +1,33 @@
/*!
* @file usbd_class_cdc.h
*
* @brief CDC Class handler file head file
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#ifndef __CDC_CLASS_
#define __CDC_CLASS_
#include "usbd_core.h"
void USBD_ClassHandler(USBD_DevReqData_T* reqData);
#endif
@@ -0,0 +1,71 @@
/*!
* @file usbd_class_cdc.c
*
* @brief CDC Class handler file
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_class_cdc.h"
static uint8_t cmdBuf[8] = {0};
/*!
* @brief USB CDC Class request handler
*
* @param reqData : point to USBD_DevReqData_T structure
*
* @retval None
*/
void USBD_ClassHandler(USBD_DevReqData_T* reqData)
{
uint16_t length = ((uint16_t)reqData->byte.wLength[1] << 8) | \
reqData->byte.wLength[0] ;
if (!length)
{
if (!reqData->byte.bmRequestType.bit.dir)
{
USBD_CtrlTxStatus();
}
else
{
USBD_CtrlRxStatus();
}
}
else
{
switch (reqData->byte.bRequest)
{
case 0x20:
USBD_CtrlOutData(cmdBuf, length);
break;
case 0x21:
USBD_CtrlInData(cmdBuf, length);
break;
case 0x22:
USBD_CtrlOutData(cmdBuf, length);
break;
default:
break;
}
}
}
@@ -0,0 +1,37 @@
/*!
* @file usbd_class_hid.h
*
* @brief HID Class handler file head file
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_core.h"
#define HID_CLASS_REQ_SET_PROTOCOL 0x0B
#define HID_CLASS_REQ_GET_PROTOCOL 0x03
#define HID_CLASS_REQ_SET_IDLE 0x0A
#define HID_CLASS_REQ_GET_IDLE 0x02
#define HID_CLASS_REQ_SET_REPORT 0x09
#define HID_CLASS_REQ_GET_REPORT 0x01
void USBD_ClassHandler(USBD_DevReqData_T* reqData);
@@ -0,0 +1,63 @@
/*!
* @file usbd_class_hid.c
*
* @brief HID Class handler file
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_class_hid.h"
static uint8_t s_hidIdleState;
static uint8_t s_hidProtocol;
/*!
* @brief USB HID Class request handler
*
* @param reqData : point to USBD_DevReqData_T structure
*
* @retval None
*/
void USBD_ClassHandler(USBD_DevReqData_T* reqData)
{
switch (reqData->byte.bRequest)
{
case HID_CLASS_REQ_SET_IDLE:
s_hidIdleState = reqData->byte.wValue[1];
USBD_CtrlInData(NULL, 0);
break;
case HID_CLASS_REQ_GET_IDLE:
USBD_CtrlInData(&s_hidIdleState, 1);
break;
case HID_CLASS_REQ_SET_PROTOCOL:
s_hidProtocol = reqData->byte.wValue[0];
USBD_CtrlInData(NULL, 0);
break;
case HID_CLASS_REQ_GET_PROTOCOL:
USBD_CtrlInData(&s_hidProtocol, 1);
break;
default:
break;
}
}
@@ -0,0 +1,37 @@
/*!
* @file usbd_class_msc.h
*
* @brief MSC Class handler file head file
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#ifndef __USBD_CLASS_MSC
#define __USBD_CLASS_MSC
#include "usbd_core.h"
#define BOT_GET_MAX_LUN 0xFE
#define BOT_RESET 0xFF
void USBD_MSC_ClassHandler(USBD_DevReqData_T* reqData);
#endif
@@ -0,0 +1,106 @@
/*!
* @file usbd_msc_bot.h
*
* @brief MSC BOT protocol core functions
*
* @version V1.0.0
*
* @date 2021-12-25
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_core.h"
#ifndef __USBD_MSC_BOT_H
#define __USBD_MSC_BOT_H
#define MSC_BOT_CBW_SIGNATURE (uint32_t)(0x43425355)
#define MSC_BOT_CBW_LENGTH 31
#define MSC_BOT_CSW_SIGNATURE (uint32_t)(0x53425355)
#define MSC_BOT_CSW_LENGTH 13
typedef enum
{
BOT_STATE_IDLE, //!< Idle state
BOT_STATE_DATA_OUT, //!< Data Out state
BOT_STATE_DATA_IN, //!< Data In state
BOT_STATE_LAST_DATA_IN, //!< Last Data In Last
BOT_STATE_SEND_DATA //!< Send Immediate data
} BOT_STATE_T;
typedef enum
{
BOT_STATUS_NORMAL,
BOT_STATUS_RECOVERY,
BOT_STATUS_ERROR
} BOT_STATUS_T;
typedef enum
{
BOT_CSW_STATUS_CMD_OK,
BOT_CSW_STATUS_CMD_FAIL,
BOT_CSW_STATUS_PHASE_ERROR
} BOT_CSW_STATUS_T;
/**
* @brief Command Block Wrapper
*/
typedef struct
{
uint32_t dSignature;
uint32_t dTag;
uint32_t dDataXferLen;
uint8_t bmFlags;
uint8_t bLUN;
uint8_t bCBLen;
uint8_t CB[16];
} BOT_CBW_T;
/**
* @brief Command Status Wrapper
*/
typedef struct
{
uint32_t dSignature;
uint32_t dTag;
uint32_t dDataResidue;
uint8_t bStatus;
} BOT_CSW_T;
typedef struct
{
uint8_t state;
uint8_t status;
uint16_t dataLen;
BOT_CBW_T CBW;
BOT_CSW_T CSW;
uint8_t data[MSC_MEDIA_PACKET];
} BOT_Info_T;
extern BOT_Info_T g_BOTInfo;
void USBD_MSC_BOT_Reset(void);
void USBD_MSC_BOT_Init(void);
void USBD_MSC_BOT_OutData(uint8_t ep);
void USBD_MSC_BOT_InData(uint8_t ep);
void USBD_MSC_BOT_TxCSW(uint8_t cswStatus);
void USBD_MSC_BOT_Stall(void);
void USBD_MSV_BOT_ClearFeatureHandler(void);
#endif
@@ -0,0 +1,131 @@
/*!
* @file usbd_msc_scsi.h
*
* @brief MSC scsi
*
* @version V1.0.0
*
* @date 2021-12-25
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_core.h"
#ifndef __USBD_MSC_SCSI_H_
#define __USBD_MSC_SCSI_H_
/**
* @brief SCSI function status
*/
enum
{
SCSI_OK,
SCSI_FAIL
};
/**
* @brief SCSI Sense Key
*/
typedef enum
{
SCSI_SKEY_NO_SENSE,
SCSI_SKEY_RECOVERED_ERROR,
SCSI_SKEY_NOT_READY,
SCSI_SKEY_MEDIUM_ERROR,
SCSI_SKEY_HARDWARE_ERROR,
SCSI_SKEY_ILLEGAL_REQUEST,
SCSI_SKEY_UNIT_ATTENTION,
SCSI_SKEY_DATA_PROTECT,
SCSI_SKEY_BLANK_CHECK,
SCSI_SKEY_VENDOR_SPECIFIC,
SCSI_SKEY_COPY_ABORTED,
SCSI_SKEY_ABORTED_COMMAND,
SCSI_SKEY_VOLUME_OVERFLOW = 13,
SCSI_SKEY_MISCOMPARE = 14
} SCSI_SKEY_T;
/**
* @brief SCSI Sense
*/
typedef struct {
uint8_t sensekey;
uint8_t ASC;
uint8_t ASCQ;
} SCSI_Sense_T;
#define SCSI_SENSE_LIST_NUMBER 4
#define SCSI_INQUIRY_LENGTH 36
/** SCSI Commands */
#define SCSI_CMD_FORMAT_UNIT ((uint8_t)0x04)
#define SCSI_CMD_INQUIRY ((uint8_t)0x12)
#define SCSI_CMD_MODE_SELECT_6 ((uint8_t)0x15)
#define SCSI_CMD_MODE_SELECT_10 ((uint8_t)0x55)
#define SCSI_CMD_MODE_SENSE_6 ((uint8_t)0x1A)
#define SCSI_CMD_MODE_SENSE_10 ((uint8_t)0x5A)
#define SCSI_CMD_ALLOW_MEDIUM_REMOVAL ((uint8_t)0x1E)
#define SCSI_CMD_READ_6 ((uint8_t)0x08)
#define SCSI_CMD_READ_10 ((uint8_t)0x28)
#define SCSI_CMD_READ_12 ((uint8_t)0xA8)
#define SCSI_CMD_READ_16 ((uint8_t)0x88)
#define SCSI_CMD_READ_CAPACITY_10 ((uint8_t)0x25)
#define SCSI_CMD_READ_CAPACITY_16 ((uint8_t)0x9E)
#define SCSI_CMD_REQUEST_SENSE ((uint8_t)0x03)
#define SCSI_CMD_START_STOP_UNIT ((uint8_t)0x1B)
#define SCSI_CMD_TEST_UNIT_READY ((uint8_t)0x00)
#define SCSI_CMD_WRITE6 ((uint8_t)0x0A)
#define SCSI_CMD_WRITE10 ((uint8_t)0x2A)
#define SCSI_CMD_WRITE12 ((uint8_t)0xAA)
#define SCSI_CMD_WRITE16 ((uint8_t)0x8A)
#define SCSI_CMD_VERIFY_10 ((uint8_t)0x2F)
#define SCSI_CMD_VERIFY_12 ((uint8_t)0xAF)
#define SCSI_CMD_VERIFY_16 ((uint8_t)0x8F)
#define SCSI_CMD_SEND_DIAGNOSTIC ((uint8_t)0x1D)
#define SCSI_CMD_READ_FORMAT_CAPACITIES ((uint8_t)0x23)
#define SCSI_ASC_INVALID_CDB 0x20
#define SCSI_ASC_INVALID_FIELED_IN_COMMAND 0x24
#define SCSI_ASC_PARAMETER_LIST_LENGTH_ERROR 0x1A
#define SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26
#define SCSI_ASC_ADDRESS_OUT_OF_RANGE 0x21
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
#define SCSI_ASC_MEDIUM_HAVE_CHANGED 0x28
#define SCSI_ASC_WRITE_PROTECTED 0x27
#define SCSI_ASC_UNRECOVERED_READ_ERROR 0x11
#define SCSI_ASC_WRITE_FAULT 0x03
#define SCSI_READ_FORMAT_CAPACITY_DATA_LEN 0x0C
#define SCSI_READ_CAPACITY10_DATA_LEN 0x08
#define SCSI_MODE_SENSE10_DATA_LEN 0x08
#define SCSI_MODE_SENSE6_DATA_LEN 0x04
#define SCSI_REQUEST_SENSE_DATA_LEN 0x12
#define SCSI_STANDARD_INQUIRY_DATA_LEN 0x24
#define SCSI_BLKVFY 0x04
extern SCSI_Sense_T g_scsiSense[SCSI_SENSE_LIST_NUMBER];
extern uint8_t g_senseTxCnt;
extern uint8_t g_sensePutCnt;
uint8_t SCSI_CmdHandler(uint8_t lun, uint8_t *cmd);
void SCSI_PutSenseCode(uint8_t lun, uint8_t sKey, uint8_t ASC, uint8_t ASCQ);
#endif
@@ -0,0 +1,79 @@
/*!
* @file usbd_class_msc.c
*
* @brief MSC Class file
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_class_msc.h"
#include "usbd_msc_bot.h"
static uint8_t s_mscMaxLen = 0;
/*!
* @brief USB MSC Class request handler
*
* @param reqData : point to USBD_DevReqData_T structure
*
* @retval None
*/
void USBD_MSC_ClassHandler(USBD_DevReqData_T* reqData)
{
uint16_t wValue = ((uint16_t)reqData->byte.wValue[1] << 8) | \
reqData->byte.wValue[0];
uint16_t wLength = ((uint16_t)reqData->byte.wLength[1] << 8) | \
reqData->byte.wLength[0];
switch (reqData->byte.bRequest)
{
case BOT_GET_MAX_LUN :
if ((wValue == 0) && (wLength == 1) && \
(reqData->byte.bmRequestType.bit.dir == 1))
{
s_mscMaxLen = STORAGE_MAX_LUN - 1;
USBD_CtrlInData(&s_mscMaxLen, 1);
}
else
{
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_STALL, USBD_EP_STATUS_STALL);
}
break;
case BOT_RESET :
if ((wValue == 0) && (wLength == 0) && \
(reqData->byte.bmRequestType.bit.dir == 0))
{
USBD_CtrlInData(NULL, 0);
/** Reset */
USBD_MSC_BOT_Reset();
}
else
{
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_STALL, USBD_EP_STATUS_STALL);
}
break;
default:
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_STALL, USBD_EP_STATUS_STALL);
break;
}
}
@@ -0,0 +1,242 @@
/*!
* @file usbd_msv_bot.c
*
* @brief MSC BOT protocol core functions
*
* @version V1.0.0
*
* @date 2021-12-25
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_msc_bot.h"
#include "usbd_core.h"
#include "usbd_storage_disk.h"
#include "usbd_msc_scsi.h"
BOT_Info_T g_BOTInfo;
static void USBD_MSC_BOT_DecodeCBW(void);
static void USBD_MSC_BOT_TxData(uint8_t *txBuf, uint16_t len);
static void USBD_MSC_BOT_Stall(void);
/*!
* @brief BOT Process Reset.
*
* @param None
*
* @retval None
*/
void USBD_MSC_BOT_Reset(void)
{
g_BOTInfo.state = BOT_STATE_IDLE;
g_BOTInfo.status = BOT_STATUS_RECOVERY;
USBD_RxData(MSC_OUT_EP & 0x7f, (uint8_t *)&g_BOTInfo.CBW, MSC_BOT_CBW_LENGTH);
}
/*!
* @brief BOT Process initialization.
*
* @param None
*
* @retval None
*/
void USBD_MSC_BOT_Init(void)
{
g_BOTInfo.state = BOT_STATE_IDLE;
g_BOTInfo.status = BOT_STATUS_NORMAL;
g_storageCallBack.Init(0);
USBD_RxData(MSC_OUT_EP & 0x7f, (uint8_t *)&g_BOTInfo.CBW, MSC_BOT_CBW_LENGTH);
}
/*!
* @brief Bulk OUT data handler.
*
* @param ep : OUT endpoint
*
* @retval None
*/
void USBD_MSC_BOT_OutData(uint8_t ep)
{
if (g_BOTInfo.state == BOT_STATE_IDLE)
{
USBD_MSC_BOT_DecodeCBW();
}
else if (g_BOTInfo.state == BOT_STATE_DATA_OUT)
{
if (SCSI_CmdHandler(g_BOTInfo.CBW.bLUN, g_BOTInfo.CBW.CB) != SCSI_OK)
{
USBD_MSC_BOT_TxCSW(BOT_CSW_STATUS_CMD_FAIL);
}
}
}
/*!
* @brief Bulk IN data handler.
*
* @param ep : IN endpoint
*
* @retval None
*/
void USBD_MSC_BOT_InData(uint8_t ep)
{
if (g_BOTInfo.state == BOT_STATE_DATA_IN)
{
if (SCSI_CmdHandler(g_BOTInfo.CBW.bLUN, g_BOTInfo.CBW.CB) != SCSI_OK)
{
USBD_MSC_BOT_TxCSW(BOT_CSW_STATUS_CMD_FAIL);
}
}
else if ((g_BOTInfo.state == BOT_STATE_SEND_DATA) || \
(g_BOTInfo.state == BOT_STATE_LAST_DATA_IN))
{
USBD_MSC_BOT_TxCSW(BOT_CSW_STATUS_CMD_OK);
}
}
/*!
* @brief Decode CBW.
*
* @param None
*
* @retval None
*/
static void USBD_MSC_BOT_DecodeCBW(void)
{
uint32_t xferCnt = g_usbDev.outBuf[MSC_OUT_EP & 0x7f].xferCnt;
g_BOTInfo.CSW.dTag = g_BOTInfo.CBW.dTag;
g_BOTInfo.CSW.dDataResidue = g_BOTInfo.CBW.dDataXferLen;
if ((xferCnt != MSC_BOT_CBW_LENGTH) || \
(g_BOTInfo.CBW.dSignature != MSC_BOT_CBW_SIGNATURE) || \
(g_BOTInfo.CBW.bLUN > 1) || (g_BOTInfo.CBW.bCBLen < 1) || \
(g_BOTInfo.CBW.bCBLen > 16))
{
SCSI_PutSenseCode(g_BOTInfo.CBW.bLUN, SCSI_SKEY_ILLEGAL_REQUEST,
SCSI_ASC_INVALID_CDB, 0);
g_BOTInfo.status = BOT_STATUS_ERROR;
}
else
{
if (SCSI_CmdHandler(g_BOTInfo.CBW.bLUN, g_BOTInfo.CBW.CB) != SCSI_OK)
{
USBD_MSC_BOT_Stall();
}
else if ((g_BOTInfo.state == BOT_STATE_IDLE) || \
(g_BOTInfo.state == BOT_STATE_SEND_DATA))
{
if (g_BOTInfo.dataLen)
{
USBD_MSC_BOT_TxData(g_BOTInfo.data, g_BOTInfo.dataLen);
}
else
{
USBD_MSC_BOT_TxCSW(BOT_CSW_STATUS_CMD_OK);
}
}
}
}
/*!
* @brief MSC send data.
*
* @param txBuf : buffer to send
*
* @param len : buffer length
*
* @retval None
*/
static void USBD_MSC_BOT_TxData(uint8_t *txBuf, uint16_t len)
{
len = USB_MIN(len, g_BOTInfo.CBW.dDataXferLen);
g_BOTInfo.CSW.dDataResidue -= len;
g_BOTInfo.CSW.bStatus = BOT_CSW_STATUS_CMD_OK;
g_BOTInfo.state = BOT_STATE_SEND_DATA;
USBD_TxData(MSC_IN_EP & 0x7f, txBuf, len);
}
/*!
* @brief Send CSW.
*
* @param cswStatus : status of CSW
*
* @retval None
*/
void USBD_MSC_BOT_TxCSW(uint8_t cswStatus)
{
g_BOTInfo.CSW.dSignature = MSC_BOT_CSW_SIGNATURE;
g_BOTInfo.CSW.bStatus = cswStatus;
g_BOTInfo.state = BOT_STATE_IDLE;
USBD_TxData(MSC_IN_EP & 0x7f, (uint8_t*)&g_BOTInfo.CSW,
MSC_BOT_CSW_LENGTH);
USBD_RxData(MSC_OUT_EP & 0x7f, (uint8_t*)&g_BOTInfo.CBW,
MSC_BOT_CBW_LENGTH);
}
/*!
* @brief handler clearFeature in standard request.
*
* @param None
*
* @retval None
*/
void USBD_MSV_BOT_ClearFeatureHandler(void)
{
if (g_BOTInfo.status == BOT_STATUS_ERROR)
{
USBD_SetEPTxStatus(MSC_IN_EP & 0x7f, USBD_EP_STATUS_NAK);
g_BOTInfo.status = BOT_STATUS_NORMAL;
}
else if (((g_usbDev.reqData.byte.wIndex[0] & 0x80) == 0x80) && \
g_BOTInfo.status != BOT_STATUS_RECOVERY)
{
USBD_MSC_BOT_TxCSW(BOT_CSW_STATUS_CMD_FAIL);
}
}
/*!
* @brief Stall MSC.
*
* @param None
*
* @retval None
*/
static void USBD_MSC_BOT_Stall(void)
{
if ((g_BOTInfo.CBW.bmFlags == 0) && (g_BOTInfo.CBW.dDataXferLen != 0) && \
(g_BOTInfo.status == BOT_STATUS_NORMAL))
{
USBD_SetEPRxStatus(MSC_OUT_EP & 0x7f, USBD_EP_STATUS_STALL);
}
USBD_SetEPTxStatus(MSC_IN_EP & 0x7f, USBD_EP_STATUS_STALL);
if (g_BOTInfo.status == BOT_STATUS_ERROR)
{
USBD_RxData(MSC_OUT_EP & 0x7f, (uint8_t *)&g_BOTInfo.CBW,
MSC_BOT_CBW_LENGTH);
}
}
@@ -0,0 +1,701 @@
/*!
* @file usbd_msc_scsi.c
*
* @brief MSC scsi
*
* @version V1.0.0
*
* @date 2021-12-25
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_msc_bot.h"
#include "usbd_msc_scsi.h"
#include "usbd_storage_disk.h"
SCSI_Sense_T g_scsiSenseCode[SCSI_SENSE_LIST_NUMBER];
uint8_t g_senseTxCnt;
uint8_t g_sensePutCnt;
static uint32_t s_blkSize;
static uint32_t s_blkNbr;
static uint32_t s_blkAddr;
static uint32_t s_blkLen;
/** USB Mass storage Page 0 Inquiry Data */
static const uint8_t s_page00InquiryData[] =
{
0x00,
0x00,
0x00,
(7 - 4),
0x00,
0x80,
0x83
};
/** USB Mass storage sense 6 Data */
static const uint8_t s_modeSense6Data[] =
{
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00
};
/** USB Mass storage sense 10 Data */
static const uint8_t s_modeSense10Data[] =
{
0x00,
0x06,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00
};
static uint8_t SCSI_TestUnitReady(uint8_t lun);
static uint8_t SCSI_Inquiry(uint8_t lun, uint8_t* command);
static uint8_t SCSI_RequestSense(uint8_t lun, uint8_t* command);
static uint8_t SCSI_ReadFormatCapacity(uint8_t lun, uint8_t* command);
static uint8_t SCSI_ReadCapacity10(uint8_t lun, uint8_t* command);
static uint8_t SCSI_Read10(uint8_t lun, uint8_t* command);
static uint8_t SCSI_Write10(uint8_t lun, uint8_t* command);
static uint8_t SCSI_Verify10(uint8_t lun, uint8_t* command);
static uint8_t SCSI_StartStopUnit(void);
static uint8_t SCSI_ModeSense6(uint8_t lun, uint8_t* command);
static uint8_t SCSI_ModeSense10(uint8_t lun, uint8_t* command);
static uint8_t SCSI_Read(uint8_t lun);
static uint8_t SCSI_Write(uint8_t lun);
static uint8_t SCSI_CheckAddress(uint8_t lun, uint32_t blkOffset, uint16_t blkNbr);
/*!
* @brief SCSI command handler.
*
* @param lun: Logical unit number
*
* @param command: Command pointer
*
* @retval SCSI_OK or SCSI_FAILL
*/
uint8_t SCSI_CmdHandler(uint8_t lun, uint8_t* command)
{
uint8_t ret = SCSI_OK;
switch (command[0])
{
case SCSI_CMD_TEST_UNIT_READY:
ret = SCSI_TestUnitReady(lun);
break;
case SCSI_CMD_INQUIRY:
ret = SCSI_Inquiry(lun, command);
break;
case SCSI_CMD_REQUEST_SENSE:
ret = SCSI_RequestSense(lun, command);
break;
case SCSI_CMD_READ_FORMAT_CAPACITIES:
ret = SCSI_ReadFormatCapacity(lun, command);
break;
case SCSI_CMD_READ_CAPACITY_10:
ret = SCSI_ReadCapacity10(lun, command);
break;
case SCSI_CMD_READ_10:
ret = SCSI_Read10(lun, command);
break;
case SCSI_CMD_WRITE10:
ret = SCSI_Write10(lun, command);
break;
case SCSI_CMD_VERIFY_10:
ret = SCSI_Verify10(lun, command);
break;
case SCSI_CMD_ALLOW_MEDIUM_REMOVAL:
case SCSI_CMD_START_STOP_UNIT:
ret = SCSI_StartStopUnit();
break;
case SCSI_CMD_MODE_SENSE_6:
ret = SCSI_ModeSense6 (lun, command);
break;
case SCSI_CMD_MODE_SENSE_10:
ret = SCSI_ModeSense10 (lun, command);
break;
default:
SCSI_PutSenseCode(lun, SCSI_SKEY_ILLEGAL_REQUEST,
SCSI_ASC_INVALID_CDB, 0);
ret = SCSI_FAIL;
}
return ret;
}
/*!
* @brief Put the sense code to array.
*
* @param sKey: sense Key
*
* @param ASC: Additional Sense Code
*
* @param ASCQ: Additional Sense Code Qualifier
*
* @retval None
*/
void SCSI_PutSenseCode(uint8_t lun, uint8_t sKey, uint8_t ASC, uint8_t ASCQ)
{
g_scsiSenseCode[g_sensePutCnt].sensekey = sKey;
g_scsiSenseCode[g_sensePutCnt].ASC = ASC;
g_scsiSenseCode[g_sensePutCnt].ASCQ = ASCQ;
if ((++g_sensePutCnt) == SCSI_SENSE_LIST_NUMBER)
{
g_sensePutCnt = 0;
}
}
/*!
* @brief SCSI Test Unit Ready handler.
*
* @param lun: Logical unit number
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_TestUnitReady(uint8_t lun)
{
if (g_BOTInfo.CBW.dDataXferLen)
{
SCSI_PutSenseCode(g_BOTInfo.CBW.bLUN, SCSI_SKEY_ILLEGAL_REQUEST,
SCSI_ASC_INVALID_CDB, 0);
return SCSI_FAIL;
}
else if (g_storageCallBack.CheckReady(lun) != SCSI_OK)
{
SCSI_PutSenseCode(lun, SCSI_SKEY_NOT_READY,
SCSI_ASC_MEDIUM_NOT_PRESENT, 0);
return SCSI_FAIL;
}
else
{
g_BOTInfo.dataLen = 0;
return SCSI_OK;
}
}
/*!
* @brief SCSI Inquiry handler.
*
* @param lun: Logical unit number
*
* @param command: command pointer
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_Inquiry(uint8_t lun, uint8_t* command)
{
uint16_t i;
uint8_t* pInquiryData;
if (command[1] & 0x01)
{
pInquiryData = (uint8_t*)s_page00InquiryData;
g_BOTInfo.dataLen = s_page00InquiryData[3] + 4;
}
else
{
pInquiryData = &g_storageCallBack.pInquiryData[lun * SCSI_INQUIRY_LENGTH];
g_BOTInfo.dataLen = USB_MIN((pInquiryData[4] + 5), command[4]);
}
for (i = 0; i < g_BOTInfo.dataLen; i++)
{
g_BOTInfo.data[i] = pInquiryData[i];
}
return SCSI_OK;
}
/*!
* @brief SCSI Request Sense handler.
*
* @param lun: Logical unit number
*
* @param command: command pointer
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_RequestSense(uint8_t lun, uint8_t* command)
{
uint8_t i = 0;
while (i < SCSI_REQUEST_SENSE_DATA_LEN)
{
g_BOTInfo.data[i++] = 0;
}
g_BOTInfo.data[0] = 0x70;
g_BOTInfo.data[7] = SCSI_REQUEST_SENSE_DATA_LEN - 6;
if (g_senseTxCnt != g_sensePutCnt)
{
g_BOTInfo.data[2] = g_scsiSenseCode[g_senseTxCnt].sensekey;
g_BOTInfo.data[12] = g_scsiSenseCode[g_senseTxCnt].ASC;
g_BOTInfo.data[13] = g_scsiSenseCode[g_senseTxCnt].ASCQ;
if ((++g_senseTxCnt) == SCSI_SENSE_LIST_NUMBER)
{
g_senseTxCnt = 0;
}
}
g_BOTInfo.dataLen = (SCSI_REQUEST_SENSE_DATA_LEN < command[4]) ? \
SCSI_REQUEST_SENSE_DATA_LEN : command[4];
return SCSI_OK;
}
/*!
* @brief SCSI Read Format Capacity handler.
*
* @param lun: Logical unit number
*
* @param command: command pointer
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_ReadFormatCapacity(uint8_t lun, uint8_t* command)
{
uint16_t i = 0;
uint32_t blkSize;
uint32_t blkNbr;
while (i < 12)
{
g_BOTInfo.data[i++] = 0;
}
if (g_storageCallBack.ReadCapacity(lun, &blkNbr, &blkSize) != SCSI_OK)
{
SCSI_PutSenseCode(lun, SCSI_SKEY_NOT_READY,
SCSI_ASC_MEDIUM_NOT_PRESENT, 0);
return SCSI_FAIL;
}
else
{
blkNbr--;
g_BOTInfo.data[3] = 0x08;
g_BOTInfo.data[4] = (uint8_t)(blkNbr >> 24);
g_BOTInfo.data[5] = (uint8_t)(blkNbr >> 16);
g_BOTInfo.data[6] = (uint8_t)(blkNbr >> 8);
g_BOTInfo.data[7] = (uint8_t)(blkNbr);
g_BOTInfo.data[8] = 0x02;
g_BOTInfo.data[9] = (uint8_t)(blkSize >> 16);
g_BOTInfo.data[10] = (uint8_t)(blkSize >> 8);
g_BOTInfo.data[11] = (uint8_t)blkSize;
g_BOTInfo.dataLen = 12;
return SCSI_OK;
}
}
/*!
* @brief SCSI Read Capacity10 handler.
*
* @param lun: Logical unit number
*
* @param command: command pointer
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_ReadCapacity10(uint8_t lun, uint8_t* command)
{
if (g_storageCallBack.ReadCapacity(lun, &s_blkNbr, &s_blkSize) != SCSI_OK)
{
SCSI_PutSenseCode(lun, SCSI_SKEY_NOT_READY,
SCSI_ASC_MEDIUM_NOT_PRESENT, 0);
return SCSI_FAIL;
}
else
{
g_BOTInfo.data[0] = (uint8_t)((s_blkNbr - 1) >> 24);
g_BOTInfo.data[1] = (uint8_t)((s_blkNbr - 1) >> 16);
g_BOTInfo.data[2] = (uint8_t)((s_blkNbr - 1) >> 8);
g_BOTInfo.data[3] = (uint8_t)(s_blkNbr - 1);
g_BOTInfo.data[4] = (uint8_t)(s_blkSize >> 24);
g_BOTInfo.data[5] = (uint8_t)(s_blkSize >> 16);
g_BOTInfo.data[6] = (uint8_t)(s_blkSize >> 8);
g_BOTInfo.data[7] = (uint8_t)(s_blkSize);
g_BOTInfo.dataLen = 8;
return SCSI_OK;
}
}
/*!
* @brief SCSI Read10 handler.
*
* @param lun: Logical unit number
*
* @param command: command pointer
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_Read10(uint8_t lun, uint8_t* command)
{
uint8_t ret = SCSI_OK;
if (g_BOTInfo.state == BOT_STATE_IDLE)
{
if ((g_BOTInfo.CBW.bmFlags & 0x80) != 0x80)
{
SCSI_PutSenseCode(g_BOTInfo.CBW.bLUN, SCSI_SKEY_ILLEGAL_REQUEST,
SCSI_ASC_INVALID_CDB, 0);
return SCSI_FAIL;
}
if (g_storageCallBack.CheckReady(lun) != SCSI_OK)
{
SCSI_PutSenseCode(lun, SCSI_SKEY_NOT_READY,
SCSI_ASC_MEDIUM_NOT_PRESENT, 0);
return SCSI_FAIL;
}
s_blkAddr = ((uint32_t)command[2] << 24) | \
((uint32_t)command[3] << 16) | \
((uint32_t)command[4] << 8) | \
(uint32_t)command[5];
s_blkLen = ((uint16_t)command[7] << 8 | (uint8_t )command[8]);
if (SCSI_CheckAddress(lun, s_blkAddr, s_blkLen) != SCSI_OK)
{
return SCSI_FAIL;
}
g_BOTInfo.state = BOT_STATE_DATA_IN;
s_blkAddr *= s_blkSize;
s_blkLen *= s_blkSize;
if (g_BOTInfo.CBW.dDataXferLen != s_blkLen)
{
SCSI_PutSenseCode(g_BOTInfo.CBW.bLUN, SCSI_SKEY_ILLEGAL_REQUEST,
SCSI_ASC_INVALID_CDB, 0);
return SCSI_FAIL;
}
}
g_BOTInfo.dataLen = MSC_MEDIA_PACKET;
ret = SCSI_Read(lun);
return ret;
}
/*!
* @brief SCSI write10 handler.
*
* @param lun: Logical unit number
*
* @param command: command pointer
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_Write10(uint8_t lun, uint8_t* command)
{
uint8_t ret = SCSI_OK;
uint32_t len;
if (g_BOTInfo.state == BOT_STATE_IDLE)
{
if (g_BOTInfo.CBW.bmFlags & 0x80)
{
SCSI_PutSenseCode(g_BOTInfo.CBW.bLUN, SCSI_SKEY_ILLEGAL_REQUEST,
SCSI_ASC_INVALID_CDB, 0);
return SCSI_FAIL;
}
if (g_storageCallBack.CheckReady(lun) != SCSI_OK)
{
SCSI_PutSenseCode(lun, SCSI_SKEY_NOT_READY,
SCSI_ASC_MEDIUM_NOT_PRESENT, 0);
return SCSI_FAIL;
}
if (g_storageCallBack.CheckWPR(lun) != SCSI_OK)
{
SCSI_PutSenseCode(lun, SCSI_SKEY_NOT_READY,
SCSI_ASC_WRITE_PROTECTED, 0);
return SCSI_FAIL;
}
s_blkAddr = ((uint32_t)command[2] << 24) | \
((uint32_t)command[3] << 16) | \
((uint32_t)command[4] << 8) | \
(uint32_t)command[5];
s_blkLen = ((uint16_t)command[7] << 8 | (uint8_t )command[8]);
if (SCSI_CheckAddress(lun, s_blkAddr, s_blkLen) != SCSI_OK)
{
return SCSI_FAIL;
}
s_blkAddr *= s_blkSize;
s_blkLen *= s_blkSize;
if (g_BOTInfo.CBW.dDataXferLen != s_blkLen)
{
SCSI_PutSenseCode(g_BOTInfo.CBW.bLUN, SCSI_SKEY_ILLEGAL_REQUEST,
SCSI_ASC_INVALID_CDB, 0);
return SCSI_FAIL;
}
g_BOTInfo.state = BOT_STATE_DATA_OUT;
len = USB_MIN(s_blkLen, MSC_MEDIA_PACKET);
USBD_RxData(MSC_OUT_EP & 0x7F, g_BOTInfo.data, len);
}
else
{
ret = SCSI_Write(lun);
}
return ret;
}
/*!
* @brief SCSI Verify10 Handler.
*
* @param lun: Logical unit number
*
* @param command: command pointer
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_Verify10(uint8_t lun, uint8_t* command)
{
if (command[1] & 0x02)
{
SCSI_PutSenseCode(lun, SCSI_SKEY_ILLEGAL_REQUEST,
SCSI_ASC_INVALID_FIELED_IN_COMMAND, 0);
return SCSI_FAIL;
}
s_blkAddr = ((uint32_t)command[2] << 24) | \
((uint32_t)command[3] << 16) | \
((uint32_t)command[4] << 8) | \
(uint32_t)command[5];
s_blkLen = ((uint16_t)command[7] << 8 | (uint8_t )command[8]);
if (SCSI_CheckAddress(lun, s_blkAddr, s_blkLen) != SCSI_OK)
{
return SCSI_FAIL;
}
g_BOTInfo.dataLen = 0;
return SCSI_OK;
}
/*!
* @brief SCSI Start Stop Unit Handler.
*
* @param None
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_StartStopUnit(void)
{
g_BOTInfo.dataLen = 0;
return SCSI_OK;
}
/*!
* @brief SCSI Mode Sense6 Handler.
*
* @param lun: Logical unit number
*
* @param command: command pointer
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_ModeSense6(uint8_t lun, uint8_t* command)
{
for (uint16_t i = 0; i < 8; i++)
{
g_BOTInfo.data[i] = s_modeSense6Data[i];
}
g_BOTInfo.dataLen = 8;
return SCSI_OK;
}
/*!
* @brief SCSI Mode Sense10 Handler.
*
* @param lun: Logical unit number
*
* @param command: command pointer
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_ModeSense10(uint8_t lun, uint8_t* command)
{
for (uint16_t i = 0; i < 8; i++)
{
g_BOTInfo.data[i] = s_modeSense10Data[i];
}
g_BOTInfo.dataLen = 8;
return SCSI_OK;
}
/*!
* @brief SCSI Read Process.
*
* @param lun: Logical unit number
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_Read(uint8_t lun)
{
uint32_t len = USB_MIN(MSC_MEDIA_PACKET, s_blkLen);
if (g_storageCallBack.ReadData(len, g_BOTInfo.data, (s_blkAddr / s_blkSize),
(len / s_blkSize)) != SCSI_OK)
{
SCSI_PutSenseCode(lun, SCSI_SKEY_HARDWARE_ERROR,
SCSI_ASC_UNRECOVERED_READ_ERROR, 0);
return SCSI_FAIL;
}
USBD_TxData(MSC_IN_EP & 0x7F, g_BOTInfo.data, len);
s_blkAddr += len;
s_blkLen -= len;
g_BOTInfo.CSW.dDataResidue -= len;
if (s_blkLen == 0)
{
g_BOTInfo.state = BOT_STATE_LAST_DATA_IN;
}
return SCSI_OK;
}
/*!
* @brief SCSI Write Process.
*
* @param lun: Logical unit number
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_Write(uint8_t lun)
{
uint32_t len = USB_MIN(MSC_MEDIA_PACKET, s_blkLen);
if (s_blkLen - len)
{
__NOP();
}
if (g_storageCallBack.WriteData(lun, g_BOTInfo.data, s_blkAddr / s_blkSize,
len / s_blkSize) != SCSI_OK)
{
SCSI_PutSenseCode(lun, SCSI_SKEY_HARDWARE_ERROR, SCSI_ASC_WRITE_FAULT, 0);
return SCSI_FAIL;
}
s_blkAddr += len;
s_blkLen -= len;
g_BOTInfo.CSW.dDataResidue -= len;
if (s_blkLen)
{
len = USB_MIN(MSC_MEDIA_PACKET, s_blkLen);
USBD_RxData(MSC_OUT_EP & 0x7f, g_BOTInfo.data, len);
}
else
{
USBD_MSC_BOT_TxCSW(BOT_CSW_STATUS_CMD_OK);
}
return SCSI_OK;
}
/*!
* @brief SCSI Check Address Range.
*
* @param lun: Logical unit number
*
* @param blkOffset: first block address
*
* @param blkNbr: number of block to be processed
*
* @retval SCSI_OK or SCSI_FAILL
*/
static uint8_t SCSI_CheckAddress(uint8_t lun, uint32_t blkOffset, uint16_t blkNbr)
{
if (s_blkNbr < (blkNbr + blkOffset))
{
SCSI_PutSenseCode(lun, SCSI_SKEY_ILLEGAL_REQUEST,
SCSI_ASC_ADDRESS_OUT_OF_RANGE, 0);
return SCSI_FAIL;
}
return SCSI_OK;
}
@@ -0,0 +1,312 @@
/*!
* @file usbd_core.h
*
* @brief USB protocol core handler head file
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#ifndef __USBD_CORE_H_
#define __USBD_CORE_H_
#include "drv_usb_device.h"
/** Get minimum value */
#define USB_MIN(a, b) (a >= b ? b : a)
/** Get maximum value */
#define USB_MAX(a, b) (a >= b ? a : b)
/**
* @brief USB request type
*/
enum
{
USBD_REQ_TYPE_STANDARD = 0,
USBD_REQ_TYPE_CLASS = 1,
USBD_REQ_TYPE_VENDOR = 2,
USBD_REQ_TYPE_RESERVED = 3
};
/**
* @brief USB recipient
*/
enum
{
USBD_RECIPIENT_DEVICE = 0,
USBD_RECIPIENT_INTERFACE = 1,
USBD_RECIPIENT_ENDPOINT = 2,
USBD_RECIPIENT_OTHER = 3,
};
/**
* @brief USB standard device requests
*/
enum
{
USBD_GET_STATUS = 0,
USBD_CLEAR_FEATURE = 1,
USBD_SET_FEATURE = 3,
USBD_SET_ADDRESS = 5,
USBD_GET_DESCRIPTOR = 6,
USBD_SET_DESCRIPTOR = 7,
USBD_GET_CONFIGURATION = 8,
USBD_SET_CONFIGURATION = 9,
USBD_GET_INTERFACE = 10,
USBD_SET_INTERFACE = 11,
USBD_SYNCH_FRAME = 12,
};
/**
* @brief USB descriptor types
*/
enum
{
USBD_DESC_DEVICE = 1,
USBD_DESC_CONFIGURATION = 2,
USBD_DESC_STRING = 3,
USBD_DESC_INTERFACE = 4,
USBD_DESC_ENDPOINT = 5,
USBD_DESC_DEVICE_QUALIFIER = 6,
USBD_DESC_OTHER_SPEED = 7,
USBD_INTERFACE_POWER = 8,
};
/**
* @brief USB standard feature
*/
enum
{
USBD_FEATURE_ENDPOINT_HALT = 0,
USBD_FEATURE_REMOTE_WAKEUP = 1,
USBD_FEATURE_TEST_MODE = 2
};
/**
* @brief USB internal state machine
*/
typedef enum
{
USBD_CTRL_STATE_WAIT_SETUP,
USBD_CTRL_STATE_DATA_IN,
USBD_CTRL_STATE_DATA_OUT,
USBD_CTRL_STATE_WAIT_STATUS_IN,
USBD_CTRL_STATE_WAIT_STATUS_OUT,
USBD_CTRL_STATE_STALLED,
}USBD_CTRL_STATE_T;
/**
* @brief USBD Endpoint type for USB protocol
*/
typedef enum
{
USBD_EP_TYPE_CONTROL,
USBD_EP_TYPE_ISO,
USBD_EP_TYPE_BULK,
USBD_EP_TYPE_INTERRUPT
}USBD_EP_TYPE_T;
/**
* @brief USB request type
*/
typedef union
{
uint8_t byte;
struct
{
uint8_t recipient : 5;
uint8_t type : 2;
uint8_t dir : 1;
}bit;
}USBD_REQ_TYPE_T;
/**
* @brief USB device request data
*/
typedef struct
{
union
{
uint8_t pack[8];
struct
{
USBD_REQ_TYPE_T bmRequestType;
uint8_t bRequest;
uint8_t wValue[2];
uint8_t wIndex[2];
uint8_t wLength[2];
} byte;
};
} USBD_DevReqData_T;
/**
* @brief Descriptor structure
*/
typedef struct
{
const uint8_t *pDesc;
uint8_t size;
}USBD_Descriptor_T;
/** USB standard request callback handler */
typedef void (*USBD_StdReqHandler_T)(void);
/** USB request handler */
typedef void (*USBD_ReqHandler_T)(USBD_DevReqData_T *);
/** Ctrl Tx Status handler function define */
typedef void (*USBD_CtrlTxStatusHandler_T)(void);
/** Ctrl Rx Status handler function define */
typedef void (*USBD_CtrlRxStatusHandler_T)(void);
/** Endpoint handler */
typedef void (*USBD_EPHandler_T)(uint8_t ep);
/** Reset handler */
typedef void (*USBD_ResetHandler_T)(void);
/** Interrupt handler function define */
typedef void (*USBD_InterruptHandler_T)(void);
/**
* @brief USB Class Request handler
*/
typedef struct
{
USBD_StdReqHandler_T getConfigurationHandler;
USBD_StdReqHandler_T getDescriptorHandler;
USBD_StdReqHandler_T getInterfaceHandler;
USBD_StdReqHandler_T getStatusHandler;
USBD_StdReqHandler_T setAddressHandler;
USBD_StdReqHandler_T setConfigurationHandler;
USBD_StdReqHandler_T setDescriptorHandler;
USBD_StdReqHandler_T setFeatureHandler;
USBD_StdReqHandler_T setInterfaceHandler;
USBD_StdReqHandler_T clearFeatureHandler;
} USBD_StdReqCallback_T;
/**
* @brief Control transfer buffer
*/
typedef struct
{
uint8_t *pBuf; //!< Data buffer
uint32_t bufLen; //!< Length of the data buffer
uint8_t packNum; //!< Packet number of the data
uint8_t zeroPackFill; //!< Fill a zero pack for IN transfer or not
uint16_t maxPackSize; //!< Max pack size of this endpoint
uint32_t xferCnt; //!< Data count of one pack on from tansfer
} USBD_CtrlBuf_T;
/**
* @brief USB init parameter
*/
typedef struct
{
USBD_Descriptor_T *pDeviceDesc; //!< Device descriptor pointer
USBD_Descriptor_T *pConfigurationDesc; //!< Configuration descriptor pointer
USBD_Descriptor_T *pStringDesc; //!< String descriptor pointer
USBD_Descriptor_T *pQualifierDesc; //!< Device Qualifier descriptor pointer
USBD_Descriptor_T *pHidReportDesc; //!< HID report descriptor pointer
USBD_StdReqCallback_T *pStdReqCallback;
USBD_ReqHandler_T stdReqExceptionHandler; //!< Standard request exception handler
USBD_ReqHandler_T classReqHandler; //!< Class request handler
USBD_ReqHandler_T vendorReqHandler; //!< vendor request handler
USBD_CtrlTxStatusHandler_T txStatusHandler; //!< Send IN status early handler
USBD_CtrlRxStatusHandler_T rxStatusHandler; //!< Receive OUT status early handler
USBD_EPHandler_T outEpHandler; //!< OUT EP transfer done handler except EP0
USBD_EPHandler_T inEpHandler; //!< IN EP transfer done handler except EP0
USBD_ResetHandler_T resetHandler; //!< Reset handler
USBD_InterruptHandler_T intHandler; //!< Hadler the rest of interrupt.
} USBD_InitParam_T;
/**
* @brief USB infomation
*/
typedef struct
{
USBD_CTRL_STATE_T ctrlState;
uint8_t curFeature;
uint8_t curInterface;
uint8_t curAlternateSetting;
uint8_t curConfiguration;
uint8_t configurationNum;
/** Setup request data buffer */
USBD_DevReqData_T reqData;
/** Endpoint buffer management */
USBD_CtrlBuf_T inBuf[USB_EP_MAX_NUM];
USBD_CtrlBuf_T outBuf[USB_EP_MAX_NUM];
/** Descriptor pointer */
USBD_Descriptor_T *pDeviceDesc;
USBD_Descriptor_T *pConfigurationDesc;
USBD_Descriptor_T *pStringDesc;
USBD_Descriptor_T *pQualifierDesc;
USBD_Descriptor_T *pHidReportDesc;
/** Setup request callback handler */
USBD_StdReqCallback_T *pStdReqCallback;
USBD_ReqHandler_T stdReqExceptionHandler;
USBD_ReqHandler_T classReqHandler;
USBD_ReqHandler_T vendorReqHandler;
/** Control transfer status stage handler */
USBD_CtrlTxStatusHandler_T txStatusHandler;
USBD_CtrlRxStatusHandler_T rxStatusHandler;
/** Endpoint transfer done handler */
USBD_EPHandler_T outEpHandler;
USBD_EPHandler_T inEpHandler;
USBD_ResetHandler_T resetHandler;
USBD_InterruptHandler_T intHandler;
} USBD_Info_T;
extern USBD_Info_T g_usbDev;
/** control status function */
#define USBD_CtrlTxStatus() USBD_CtrlInData(NULL, 0);
#define USBD_CtrlRxStatus() USBD_CtrlOutData(NULL, 0)
/** Handler Endpoint 0 control transfer */
void USBD_SetupProcess(void);
void USBD_CtrlInProcess(void);
void USBD_CtrlOutProcess(void);
void USBD_CtrlOutData(uint8_t *buf, uint32_t len);
void USBD_CtrlInData(uint8_t *buf, uint32_t len);
/** Handler other Endpoint data transfer */
void USBD_DataInProcess(USBD_EP_T ep);
void USBD_DataOutProcess(USBD_EP_T ep);
void USBD_TxData(uint8_t ep, uint8_t *buf, uint32_t len);
void USBD_RxData(uint8_t ep, uint8_t *buf, uint32_t len);
#endif
@@ -0,0 +1,64 @@
/*!
* @file usbd_init.h
*
* @brief USB initialization management head file
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#ifndef USBD_INIT_H_
#define USBD_INIT_H_
#include "usbd_core.h"
/**
* @brief Endpoint Configuration Info
*/
typedef struct
{
USBD_EP_T epNum; //!< endpoint number
USBD_EP_TYPE_T epType; //!< endpoint type
uint8_t epKind; /**
* Which could be ENABLE or DISABLE, it is valid only for
* control and bulk Endpoint. The mean of ENABLE for them like :
* 1. Control endpoint : Only for OUT status which is zero data.
* 2. Bulk endpoint : Enable the double-buffer feature
*/
USBD_EP_STATUS_T epStatus; //!< Endpoint status
uint16_t epBufAddr; //!< buffer address for the endpoint
uint16_t maxPackSize; //!< max packet size for the endpoint
} USBD_EPConfig_T;
/** USB init */
void USBD_Init(USBD_InitParam_T *param);
void USBD_InitParamStructInit(USBD_InitParam_T *param);
/** power */
void USBD_PowerOn(void);
void USBD_PowerOff(void);
/** Endpoint init */
void USBD_OpenOutEP(USBD_EPConfig_T *epConfig);
void USBD_OpenInEP(USBD_EPConfig_T *epConfig);
void USBD_CloseOutEP(USBD_EP_T ep);
void USBD_CloseInEP(USBD_EP_T ep);
#endif
@@ -0,0 +1,31 @@
/*!
* @file usbd_interrupt.h
*
* @brief USB interrupt service routine header file
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#ifndef __USBD_INTERRUPT_H_
#define __USBD_INTERRUPT_H_
#include "apm32f10x.h"
#endif
@@ -0,0 +1,31 @@
/*!
* @file usbd_stdReq.h
*
* @brief USB standard request process head file
*
* @version V1.0.0
*
* @date 2021-12-30
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#ifndef __USBD_STDREQ_H_
#define __USBD_STDREQ_H_
void USBD_StandardReqeust(void);
#endif
@@ -0,0 +1,405 @@
/*!
* @file usbd_core.c
*
* @brief USB protocol core handler
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_core.h"
#include "usbd_stdReq.h"
/** USB information */
USBD_Info_T g_usbDev;
/*!
* @brief Endpoint 0 Setup process
*
* @param None
*
* @retval None
*/
void USBD_SetupProcess(void)
{
uint8_t reqType;
uint8_t dataBuf[8];
USBD_DevReqData_T *pReqData = &g_usbDev.reqData;
uint16_t xferLen = USBD_ReadEPRxCnt(USBD_EP_0);
if (xferLen)
{
USBD_ReadDataFromEP(USBD_EP_0, (uint8_t *)dataBuf, xferLen);
}
else
{
return;
}
pReqData->byte.bmRequestType.byte = dataBuf[0];
pReqData->byte.bRequest = dataBuf[1];
pReqData->byte.wValue[0] = dataBuf[2];
pReqData->byte.wValue[1] = dataBuf[3];
pReqData->byte.wIndex[0] = dataBuf[4];
pReqData->byte.wIndex[1] = dataBuf[5];
pReqData->byte.wLength[0] = dataBuf[6];
pReqData->byte.wLength[1] = dataBuf[7];
reqType = pReqData->byte.bmRequestType.bit.type;
if(reqType == USBD_REQ_TYPE_STANDARD)
{
USBD_StandardReqeust();
}
else if(reqType == USBD_REQ_TYPE_CLASS)
{
if(g_usbDev.classReqHandler)
{
g_usbDev.classReqHandler(pReqData);
}
}
else if(reqType == USBD_REQ_TYPE_VENDOR)
{
if(g_usbDev.vendorReqHandler)
{
g_usbDev.vendorReqHandler(pReqData);
}
}
else
{
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_STALL, USBD_EP_STATUS_STALL);
}
}
/*!
* @brief Endpoint 0 USB Control in process
*
* @param None
*
* @retval None
*/
void USBD_CtrlInProcess(void)
{
uint32_t tmp;
if(g_usbDev.ctrlState == USBD_CTRL_STATE_DATA_IN)
{
if(g_usbDev.inBuf[0].packNum)
{
tmp = USB_MIN(g_usbDev.inBuf[0].bufLen, g_usbDev.inBuf[0].maxPackSize);
USBD_WriteDataToEP(USBD_EP_0, g_usbDev.inBuf[0].pBuf, tmp);
USBD_SetEPTxCnt(USBD_EP_0, tmp);
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_VALID, USBD_EP_STATUS_NAK);
g_usbDev.inBuf[0].pBuf += tmp;
g_usbDev.inBuf[0].bufLen -= tmp;
g_usbDev.inBuf[0].packNum--;
}
else
{
if (g_usbDev.inBuf[USBD_EP_0].zeroPackFill)
{
USBD_SetEPTxCnt(USBD_EP_0, 0);
USBD_SetEPTxStatus(USBD_EP_0, USBD_EP_STATUS_VALID);
g_usbDev.inBuf[USBD_EP_0].zeroPackFill = 0;
}
else
{
if (g_usbDev.rxStatusHandler)
{
g_usbDev.rxStatusHandler();
}
g_usbDev.ctrlState = USBD_CTRL_STATE_WAIT_STATUS_OUT;
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_NAK, USBD_EP_STATUS_VALID);
}
}
}
else if(g_usbDev.ctrlState == USBD_CTRL_STATE_WAIT_STATUS_IN)
{
if(g_usbDev.reqData.byte.bRequest == USBD_SET_ADDRESS)
{
USBD_SetDeviceAddr(g_usbDev.reqData.byte.wValue[0]);
}
}
}
/*!
* @brief Endpoint 0 USB Control out process
*
* @param None
*
* @retval None
*/
void USBD_CtrlOutProcess(void)
{
uint32_t len;
if(g_usbDev.ctrlState == USBD_CTRL_STATE_DATA_OUT)
{
if(g_usbDev.outBuf[0].packNum)
{
len = USB_MIN(g_usbDev.outBuf[0].bufLen, g_usbDev.outBuf[0].maxPackSize);
USBD_ReadDataFromEP(USBD_EP_0, g_usbDev.outBuf[0].pBuf, len);
g_usbDev.outBuf[0].bufLen -= len;
g_usbDev.outBuf[0].pBuf += len;
g_usbDev.outBuf[0].packNum--;
if (g_usbDev.outBuf[0].packNum)
{
USBD_CtrlOutData(g_usbDev.outBuf[0].pBuf, g_usbDev.outBuf[0].bufLen);
}
else
{
USBD_CtrlTxStatus();
}
}
else
{
if (g_usbDev.txStatusHandler)
{
g_usbDev.txStatusHandler();
}
USBD_CtrlTxStatus();
}
}
}
/*!
* @brief Send data or status in control in transation
*
* @param buf: Buffer pointer
*
* @param len: Buffer length
*
* @retval None
*/
void USBD_CtrlInData(uint8_t *buf, uint32_t len)
{
uint16_t maxPackSize = g_usbDev.inBuf[0].maxPackSize;
uint16_t reqLen = *(uint16_t*)g_usbDev.reqData.byte.wLength;
if(len)
{
if ((len < reqLen) && ((len % maxPackSize) == 0))
{
g_usbDev.inBuf[USBD_EP_0].zeroPackFill = 1;
}
if(len >= g_usbDev.inBuf[0].maxPackSize)
{
/** Send a packet */
USBD_WriteDataToEP(USBD_EP_0, buf, g_usbDev.inBuf[0].maxPackSize);
USBD_SetEPTxCnt(USBD_EP_0, g_usbDev.inBuf[0].maxPackSize);
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_VALID, USBD_EP_STATUS_NAK);
/** deal with buffer */
g_usbDev.inBuf[0].bufLen = len - g_usbDev.inBuf[0].maxPackSize;
g_usbDev.inBuf[0].pBuf = buf + g_usbDev.inBuf[0].maxPackSize;
g_usbDev.inBuf[0].packNum = (g_usbDev.inBuf[0].bufLen + (maxPackSize - 1)) / maxPackSize;
g_usbDev.ctrlState = USBD_CTRL_STATE_DATA_IN;
}
else
{
USBD_WriteDataToEP(USBD_EP_0, buf, len);
USBD_SetEPTxCnt(USBD_EP_0, len);
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_VALID, USBD_EP_STATUS_NAK);
g_usbDev.ctrlState = g_usbDev.reqData.byte.bmRequestType.bit.dir ? \
USBD_CTRL_STATE_DATA_IN : \
USBD_CTRL_STATE_WAIT_STATUS_IN;
}
}
else
{
USBD_SetEPTxCnt(USBD_EP_0, 0);
USBD_SetEPTxStatus(USBD_EP_0, USBD_EP_STATUS_VALID);
g_usbDev.ctrlState = g_usbDev.reqData.byte.bmRequestType.bit.dir ? \
USBD_CTRL_STATE_DATA_IN : \
USBD_CTRL_STATE_WAIT_STATUS_IN;
}
}
/*!
* @brief Read data or status in control out transation
*
* @param buf: Buffer pointer
*
* @param len: Buffer length
*
* @retval None
*/
void USBD_CtrlOutData(uint8_t *buf, uint32_t len)
{
uint16_t maxPackSize = g_usbDev.outBuf[USBD_EP_0].maxPackSize;
if (len)
{
g_usbDev.outBuf[USBD_EP_0].pBuf = buf;
g_usbDev.outBuf[USBD_EP_0].bufLen = len;
g_usbDev.outBuf[USBD_EP_0].packNum = (len + (maxPackSize - 1)) / maxPackSize;
len = USB_MIN(g_usbDev.outBuf[0].bufLen, maxPackSize);
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_NAK, USBD_EP_STATUS_VALID);
g_usbDev.ctrlState = USBD_CTRL_STATE_DATA_OUT;
}
else
{
g_usbDev.ctrlState = USBD_CTRL_STATE_WAIT_STATUS_OUT;
}
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_NAK, USBD_EP_STATUS_VALID);
}
/*!
* @brief USB Data in process except endpoint 0
*
* @param ep : endpoint Number except endpoint 0
*
* @retval None
*/
void USBD_DataInProcess(USBD_EP_T ep)
{
uint16_t len;
if (g_usbDev.inBuf[ep].packNum)
{
len = g_usbDev.inBuf[ep].bufLen > g_usbDev.inBuf[ep].maxPackSize ? \
g_usbDev.inBuf[ep].maxPackSize : g_usbDev.inBuf[ep].bufLen;
USBD_WriteDataToEP(ep, g_usbDev.inBuf[ep].pBuf, len);
USBD_SetEPTxCnt(ep, len);
USBD_SetEPTxStatus(ep, USBD_EP_STATUS_VALID);
g_usbDev.inBuf[ep].pBuf += len;
g_usbDev.inBuf[ep].bufLen -= len;
g_usbDev.inBuf[ep].packNum--;
}
else
{
if(g_usbDev.inEpHandler)
{
g_usbDev.inEpHandler(ep);
}
}
}
/*!
* @brief USB Data out process except endpoint 0
*
* @param ep : endpoint Number except endpoint 0
*
* @retval None
*/
void USBD_DataOutProcess(USBD_EP_T ep)
{
if (g_usbDev.outBuf[ep].packNum)
{
g_usbDev.outBuf[ep].xferCnt = USBD_ReadEPRxCnt(ep);
if ((g_usbDev.outBuf[ep].xferCnt != 0) && (g_usbDev.outBuf[ep].pBuf != NULL))
{
USBD_ReadDataFromEP(ep, g_usbDev.outBuf[ep].pBuf, g_usbDev.outBuf[ep].xferCnt);
g_usbDev.outBuf[ep].bufLen -= g_usbDev.outBuf[ep].xferCnt;
g_usbDev.outBuf[ep].pBuf += g_usbDev.outBuf[ep].xferCnt;
g_usbDev.outBuf[ep].packNum--;
}
if (g_usbDev.outBuf[ep].packNum)
{
USBD_SetEPRxStatus(ep, USBD_EP_STATUS_VALID);
}
}
if(g_usbDev.outEpHandler && !g_usbDev.outBuf[ep].packNum)
{
g_usbDev.outEpHandler(ep);
}
}
/*!
* @brief Transfer data to host(except endpoint 0)
*
* @param ep: Endpoint number except endpoint 0
*
* @param buf: Buffer pointer
*
* @param len: Buffer length
*
* @retval None
*/
void USBD_TxData(uint8_t ep, uint8_t *buf, uint32_t len)
{
uint16_t maxPackSize = g_usbDev.inBuf[ep].maxPackSize;
if (len >= maxPackSize)
{
USBD_WriteDataToEP(ep, buf, maxPackSize);
USBD_SetEPTxCnt(ep, maxPackSize);
USBD_SetEPTxStatus(ep, USBD_EP_STATUS_VALID);
g_usbDev.inBuf[ep].pBuf = buf + maxPackSize;
g_usbDev.inBuf[ep].bufLen = len - maxPackSize;
g_usbDev.inBuf[ep].packNum =(g_usbDev.inBuf[ep].bufLen + (maxPackSize - 1)) / maxPackSize;
}
else
{
USBD_WriteDataToEP(ep, buf, len);
USBD_SetEPTxCnt(ep, len);
USBD_SetEPTxStatus(ep, USBD_EP_STATUS_VALID);
g_usbDev.inBuf[ep].packNum = 0;
g_usbDev.inBuf[ep].bufLen = 0;
}
}
/*!
* @brief Receive data from host(except endpoint 0)
*
* @param ep: Endpoint number except endpoint 0
*
* @param buf: Buffer pointer
*
* @param len: Buffer length
*
* @retval None
*/
void USBD_RxData(uint8_t ep, uint8_t *buf, uint32_t len)
{
uint16_t maxPackSize = g_usbDev.outBuf[ep].maxPackSize;
g_usbDev.outBuf[ep].pBuf = buf;
g_usbDev.outBuf[ep].bufLen = len;
g_usbDev.outBuf[ep].packNum = (len + (maxPackSize - 1)) / maxPackSize;
USBD_SetEPRxCnt(ep, USB_MIN(len, maxPackSize));
USBD_SetEPRxStatus(ep, USBD_EP_STATUS_VALID);
}
@@ -0,0 +1,237 @@
/*!
* @file usbd_init.c
*
* @brief USB initialization management
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_init.h"
#include "usb_bsp.h"
static USBD_REG_EP_TYPE_T USBD_ConvertEPType(USBD_EP_TYPE_T epType);
/*!
* @brief USB initialization
*
* @param param: Initialization parameter
*
* @retval None
*/
void USBD_Init(USBD_InitParam_T *param)
{
g_usbDev.pDeviceDesc = param->pDeviceDesc;
g_usbDev.pConfigurationDesc = param->pConfigurationDesc;
g_usbDev.pStringDesc = param->pStringDesc;
g_usbDev.pQualifierDesc = param->pQualifierDesc;
g_usbDev.pHidReportDesc = param->pHidReportDesc;
g_usbDev.pStdReqCallback = param->pStdReqCallback;
g_usbDev.classReqHandler = param->classReqHandler;
g_usbDev.vendorReqHandler = param->vendorReqHandler;
g_usbDev.stdReqExceptionHandler = param->stdReqExceptionHandler;
g_usbDev.txStatusHandler = param->txStatusHandler;
g_usbDev.rxStatusHandler = param->rxStatusHandler;
g_usbDev.inEpHandler = param->inEpHandler;
g_usbDev.outEpHandler = param->outEpHandler;
g_usbDev.resetHandler = param->resetHandler;
g_usbDev.intHandler = param->intHandler;
USBD_HardWareInit();
#ifndef APM32F0xx_USB
#if USB_SELECT == USB1
USBD2_Disable();
#else
USB2_Enable();
#endif
#endif
USBD_PowerOn();
}
/*!
* @brief Init parameter in param
*
* @param param: Initialization parameter
*
* @retval None
*/
void USBD_InitParamStructInit(USBD_InitParam_T *param)
{
param->pStdReqCallback = NULL;
param->stdReqExceptionHandler = NULL;
param->classReqHandler = NULL;
param->vendorReqHandler = NULL;
param->txStatusHandler = NULL;
param->rxStatusHandler = NULL;
param->outEpHandler = NULL;
param->inEpHandler = NULL;
param->resetHandler = NULL;
param->intHandler = NULL;
}
/*!
* @brief USB Power on
*
* @param None
*
* @retval None
*/
void USBD_PowerOn(void)
{
USBD_ResetPowerDown();
USBD_SetForceReset();
USBD_ResetForceReset();
USBD_DisableInterrupt(USBD_INT_ALL);
USBD_ClearIntFlag(USBD_INT_ALL);
USBD_EnableInterrupt(USB_INT_SOURCE);
}
/*!
* @brief USB Power off
*
* @param None
*
* @retval None
*/
void USBD_PowerOff(void)
{
USBD_DisableInterrupt(USBD_INT_ALL);
USBD_ClearIntFlag(USBD_INT_ALL);
/** Power down and Force USB Reset */
USBD_SetRegCTRL(0X03);
}
/*!
* @brief Open OUT endpoint.
*
* @param epConfig: Point to USBD_EPConfig_T structure
*
* @retval None
*/
void USBD_OpenOutEP(USBD_EPConfig_T *epConfig)
{
g_usbDev.outBuf[epConfig->epNum].maxPackSize = epConfig->maxPackSize;
USBD_SetEPType(epConfig->epNum, USBD_ConvertEPType(epConfig->epType));
if (epConfig->epKind)
{
USBD_SetEPKind(epConfig->epNum);
}
else
{
USBD_ResetEPKind(epConfig->epNum);
}
USBD_SetEPRxAddr(epConfig->epNum, epConfig->epBufAddr);
USBD_SetEPRxCnt(epConfig->epNum, epConfig->maxPackSize);
USBD_SetEPRxStatus(epConfig->epNum, epConfig->epStatus);
}
/*!
* @brief Open IN endpoint.
*
* @param epConfig: Point to USBD_EPConfig_T structure
*
* @retval None
*/
void USBD_OpenInEP(USBD_EPConfig_T *epConfig)
{
g_usbDev.inBuf[epConfig->epNum].maxPackSize = epConfig->maxPackSize;
USBD_SetEPType(epConfig->epNum, USBD_ConvertEPType(epConfig->epType));
if (epConfig->epKind)
{
USBD_SetEPKind(epConfig->epNum);
}
else
{
USBD_ResetEPKind(epConfig->epNum);
}
USBD_SetEPTxAddr(epConfig->epNum, epConfig->epBufAddr);
USBD_SetEPTxStatus(epConfig->epNum, epConfig->epStatus);
}
/*!
* @brief Close OUT endpoint.
*
* @param ep: OUT endpoint Number
*
* @retval None
*/
void USBD_CloseOutEP(USBD_EP_T ep)
{
g_usbDev.outBuf[ep].maxPackSize = 0;
USBD_SetEPRxStatus(ep, USBD_EP_STATUS_DISABLE);
}
/*!
* @brief Close IN endpoint.
*
* @param ep: IN endpoint Number
*
* @retval None
*/
void USBD_CloseInEP(USBD_EP_T ep)
{
g_usbDev.inBuf[ep].maxPackSize = 0;
USBD_SetEPTxStatus(ep, USBD_EP_STATUS_DISABLE);
}
/*!
* @brief Convert endpoint Type.
*
* @param epType: endpoint type
*
* @retval Value of USBD_REG_EP_TYPE_T
*/
static USBD_REG_EP_TYPE_T USBD_ConvertEPType(USBD_EP_TYPE_T epType)
{
switch (epType)
{
case USBD_EP_TYPE_CONTROL :
return USBD_REG_EP_TYPE_CONTROL;
case USBD_EP_TYPE_ISO :
return USBD_REG_EP_TYPE_ISO;
case USBD_EP_TYPE_BULK :
return USBD_REG_EP_TYPE_BULK;
case USBD_EP_TYPE_INTERRUPT :
return USBD_REG_EP_TYPE_INTERRUPT;
default :
return USBD_REG_EP_TYPE_CONTROL;
}
}
@@ -0,0 +1,349 @@
/*!
* @file usbd_interrupt.c
*
* @brief USB interrupt service routine
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_init.h"
static void USBD_LowPriorityProc(void);
static void USBD_ResetIsrHandler(void);
static void USBD_SuspendIsrHandler(void);
static void USBD_ResumeIsrHandler(void);
/*!
* @brief USB interrupt service routine
*
* @param None
*
* @retval None
*/
#ifdef APM32F0xx_USB
void USB_IRQHandler(void)
#else //!< APM32F10x_USB
#if USB_SELECT == USB1
void USBD1_LP_CAN1_RX0_IRQHandler(void)
#else
void USB2_LP_IRQHandler(void)
#endif
#endif
{
#if (USB_INT_SOURCE & USBD_INT_CTR)
if(USBD_ReadIntFlag(USBD_INT_CTR))
{
USBD_LowPriorityProc();
}
#endif
#if (USB_INT_SOURCE & USBD_INT_RST)
if(USBD_ReadIntFlag(USBD_INT_RST))
{
USBD_ClearIntFlag(USBD_INT_RST);
USBD_ResetIsrHandler();
}
#endif
#if USB_INT_SOURCE & USBD_INT_PMAOU
if(USB_ReadIntFlag(USB_INT_PMAOU))
{
USB_ClearIntFlag(USB_INT_PMAOU);
}
#endif
#if USB_INT_SOURCE & USBD_INT_ERR
if(USB_ReadIntFlag(USB_INT_ERROR))
{
USB_ClearIntFlag(USB_INT_ERROR);
}
#endif
#if USB_INT_SOURCE & USBD_INT_WKUP
if(USBD_ReadIntFlag(USBD_INT_WKUP))
{
USBD_ResumeIsrHandler();
USBD_ClearIntFlag(USBD_INT_WKUP);
}
#endif
#if USB_INT_SOURCE & USBD_INT_SUS
if(USBD_ReadIntFlag(USBD_INT_SUS))
{
USBD_SuspendIsrHandler();
USBD_ClearIntFlag(USBD_INT_SUS);
}
#endif
#if USB_INT_SOURCE & USBD_INT_SOF
if(USB_ReadIntFlag(USB_INT_SOF))
{
USB_ClearIntFlag(USB_INT_SOF);
}
#endif
#if USB_INT_SOURCE & USBD_INT_ESOF
if(USB_ReadIntFlag(USB_INT_ESOF))
{
USB_ClearIntFlag(USB_INT_ESOF);
}
#endif
}
/*!
* @brief USB low priority process
*
* @param None
*
* @retval None
*/
static void USBD_LowPriorityProc(void)
{
USBD_EP_T ep;
while(USBD_ReadIntFlag(USBD_INT_CTR))
{
ep = (USBD_EP_T)USBD_ReadEP();
/** Endpoint 0 */
if(ep == 0)
{
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_NAK, USBD_EP_STATUS_NAK);
/** Control in */
if(USBD_ReadDir() == 0)
{
USBD_ResetEPTxFlag(USBD_EP_0);
USBD_CtrlInProcess();
}
else
{
/** Setup */
if(USBD_ReadEPSetup(USBD_EP_0) == SET)
{
USBD_ResetEPRxFlag(USBD_EP_0);
USBD_SetupProcess();
}
/** Control out */
else
{
USBD_ResetEPRxFlag(USBD_EP_0);
USBD_CtrlOutProcess();
}
}
}
/** Transfer Handler Except endpoint 0 */
else
{
if (USBD_ReadEPRxFlag(ep))
{
USBD_ResetEPRxFlag(ep);
USBD_DataOutProcess(ep);
}
if (USBD_ReadEPTxFlag(ep))
{
USBD_ResetEPTxFlag(ep);
USBD_DataInProcess(ep);
}
}
}
}
/*!
* @brief USB Device Reset
*
* @param None
*
* @retval None
*/
static void USBD_ResetIsrHandler(void)
{
uint8_t i;
USBD_EPConfig_T epConfig;
g_usbDev.configurationNum = USB_CONFIGURATION_NUM;
g_usbDev.curConfiguration = 0;
g_usbDev.curInterface = 0;
g_usbDev.curAlternateSetting = 0;
g_usbDev.curFeature = 0;
g_usbDev.ctrlState = USBD_CTRL_STATE_WAIT_SETUP;
g_usbDev.inBuf[USBD_EP_0].maxPackSize = USB_EP0_PACKET_SIZE;
g_usbDev.outBuf[USBD_EP_0].maxPackSize = USB_EP0_PACKET_SIZE;
USBD_SetBufferTable(USB_BUFFER_TABLE_ADDR);
/** Endpoint 0 IN */
epConfig.epNum = USBD_EP_0;
epConfig.epType = USBD_EP_TYPE_CONTROL;
epConfig.epKind = DISABLE;
epConfig.epBufAddr = USB_EP0_TX_ADDR;
epConfig.maxPackSize = g_usbDev.inBuf[USBD_EP_0].maxPackSize;
epConfig.epStatus = USBD_EP_STATUS_NAK;
USBD_OpenInEP(&epConfig);
/** Endpoint 0 OUT */
epConfig.epBufAddr = USB_EP0_RX_ADDR;
epConfig.maxPackSize = g_usbDev.outBuf[USBD_EP_0].maxPackSize;
epConfig.epStatus = USBD_EP_STATUS_VALID;
USBD_OpenOutEP(&epConfig);
if(g_usbDev.resetHandler)
{
g_usbDev.resetHandler();
}
for(i = 0; i < USB_EP_MAX_NUM; i++)
{
USBD_SetEpAddr((USBD_EP_T)i, i);
}
USBD_SetDeviceAddr(0);
USBD_Enable();
}
/*!
* @brief USB Suspend
*
* @param None
*
* @retval None
*/
static void USBD_SuspendIsrHandler(void)
{
uint8_t i;
uint16_t bakEP[8];
#if USB_LOW_POWER_SWITCH
uint32_t bakPwrCR;
uint32_t tmp;
#endif
for(i = 0; i < 8; i++)
{
bakEP[i] = (uint16_t)USBD->EP[i].EP;
}
USBD_EnableInterrupt(USBD_INT_RST);
USBD_SetForceReset();
USBD_ResetForceReset();
while(USBD_ReadIntFlag(USBD_INT_RST) == RESET);
for(i = 0; i < 8; i++)
{
USBD->EP[i].EP = bakEP[i];
}
USBD_SetForceSuspend();
#if USB_LOW_POWER_SWITCH
USBD_SetLowerPowerMode();
bakPwrCR = PMU->CTRL;
tmp = PMU->CTRL;
tmp &= (uint32_t)0xfffffffc;
tmp |= PMU_REGULATOR_LOWPOWER;
PMU->CTRL = tmp;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
if(USBD_ReadIntFlag(USBD_INT_WKUP) == RESET)
{
__WFI();
SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
}
else
{
USBD_ClearIntFlag(USBD_INT_WKUP);
USBD_ResetForceSuspend();
PMU->CTRL = bakPwrCR;
SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
}
#endif
}
/*!
* @brief Resume
*
* @param None
*
* @retval None
*/
static void USBD_ResumeIsrHandler(void)
{
#if USB_LOW_POWER_SWITCH
USBD_ResetLowerPowerMode();
#endif
SystemInit();
USBD_SetRegCTRL(USB_INT_SOURCE);
}
#ifndef APM32F0xx_USB
/*!
* @brief USB High priority process
*
* @param None
*
* @retval None
*/
static void USBD_HighPriorityProc(void)
{
USBD_EP_T ep;
while(USBD_ReadIntFlag(USBD_INT_CTR))
{
USBD_ClearIntFlag(USBD_INT_CTR);
ep = USBD_ReadEP();
if(USBD_ReadEPRxFlag(ep))
{
USBD_ResetEPRxFlag(ep);
g_usbDev.outEpHandler(ep);
}
if(USBD_ReadEPTxFlag(ep))
{
USBD_ResetEPTxFlag(ep);
g_usbDev.inEpHandler(ep);
}
}
}
#if USB_SELECT == USB1
void USBD1_HP_CAN1_TX_IRQHandler(void)
#else
void USB2_HP_IRQHandler(void)
#endif
{
USBD_HighPriorityProc();
}
#endif
@@ -0,0 +1,369 @@
/*!
* @file usbd_stdReq.c
*
* @brief USB standard request process
*
* @version V1.0.0
*
* @date 2021-12-30
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "usbd_stdReq.h"
#include "usbd_core.h"
#include "usbd_descriptor.h"
static uint8_t USBD_StandardGetConfiguration(void);
static uint8_t USBD_StandardGetDescriptor(void);
static uint8_t USBD_StandardGetInterface(void);
static uint8_t USBD_StandardGetStatus(void);
static uint8_t USBD_StandardSetAddress(void);
static uint8_t USBD_StandardSetConfiguration(void);
static uint8_t USBD_StandardSetDescriptor(void);
static uint8_t USBD_StandardSetFeature(void);
static uint8_t USBD_StandardSetInterface(void);
static uint8_t USBD_StandardClearFeature(void);
/*!
* @brief USB request standard request
*
* @param None
*
* @retval None
*/
void USBD_StandardReqeust(void)
{
uint8_t result = 1;
uint8_t bRequest = g_usbDev.reqData.byte.bRequest;
switch(bRequest)
{
case USBD_GET_CONFIGURATION:
result = USBD_StandardGetConfiguration();
break;
case USBD_GET_DESCRIPTOR:
result = USBD_StandardGetDescriptor();
break;
case USBD_GET_INTERFACE:
result = USBD_StandardGetInterface();
break;
case USBD_GET_STATUS:
result = USBD_StandardGetStatus();
break;
case USBD_SET_ADDRESS:
result = USBD_StandardSetAddress();
break;
case USBD_SET_CONFIGURATION:
result = USBD_StandardSetConfiguration();
break;
case USBD_SET_DESCRIPTOR:
result = USBD_StandardSetDescriptor();
break;
case USBD_SET_FEATURE:
result = USBD_StandardSetFeature();
break;
case USBD_SET_INTERFACE:
result = USBD_StandardSetInterface();
break;
case USBD_CLEAR_FEATURE:
result = USBD_StandardClearFeature();
break;
default:
break;
}
if(!result)
{
if(g_usbDev.stdReqExceptionHandler != NULL)
{
g_usbDev.stdReqExceptionHandler(&g_usbDev.reqData);
}
}
}
/*!
* @brief Standard request get configuration
*
* @param None
*
* @retval ERROR: 0; SUCCESS : 1
*/
static uint8_t USBD_StandardGetConfiguration(void)
{
uint8_t recipient = g_usbDev.reqData.byte.bmRequestType.bit.recipient;
if(recipient == USBD_RECIPIENT_DEVICE)
{
USBD_CtrlInData(&g_usbDev.curConfiguration, 1);
if (g_usbDev.pStdReqCallback->getConfigurationHandler)
{
g_usbDev.pStdReqCallback->getConfigurationHandler();
}
return SUCCESS;
}
return ERROR;
}
/*!
* @brief Standard request get descriptor
*
* @param None
*
* @retval ERROR: 0; SUCCESS : 1
*/
static uint8_t USBD_StandardGetDescriptor(void)
{
uint8_t ret = SUCCESS;
uint32_t len = 0;
uint8_t wValue0 = g_usbDev.reqData.byte.wValue[0];
uint8_t wValue1 = g_usbDev.reqData.byte.wValue[1];
if(wValue1 == USBD_DESC_DEVICE)
{
len = USB_MIN(*(uint16_t *)g_usbDev.reqData.byte.wLength, g_usbDev.pDeviceDesc->size);
USBD_CtrlInData((uint8_t *)g_usbDev.pDeviceDesc->pDesc, len);
}
else if(wValue1 == USBD_DESC_CONFIGURATION)
{
len = USB_MIN(*(uint16_t *)g_usbDev.reqData.byte.wLength, g_usbDev.pConfigurationDesc->size);
USBD_CtrlInData((uint8_t *)g_usbDev.pConfigurationDesc->pDesc, len);
}
else if(wValue1 == USBD_DESC_STRING)
{
if (wValue0 < SRTING_DESC_NUM)
{
len = USB_MIN(*(uint16_t *)g_usbDev.reqData.byte.wLength, g_usbDev.pStringDesc[wValue0].size);
USBD_CtrlInData((uint8_t *)g_usbDev.pStringDesc[wValue0].pDesc, len);
}
else
{
ret = ERROR;
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_STALL, USBD_EP_STATUS_STALL);
}
}
else
{
ret = ERROR;
USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_STALL, USBD_EP_STATUS_STALL);
}
return ret;
}
/*!
* @brief Standard request get interface
*
* @param None
*
* @retval ERROR: 0; SUCCESS : 1
*/
static uint8_t USBD_StandardGetInterface(void)
{
return ERROR;
}
/*!
* @brief Standard request get status
*
* @param None
*
* @retval ERROR: 0; SUCCESS : 1
*/
static uint8_t USBD_StandardGetStatus(void)
{
uint8_t ret = 1;
uint8_t status[2] = {0, 0};
if((g_usbDev.reqData.byte.bmRequestType.bit.recipient) == USBD_RECIPIENT_DEVICE)
{
if(g_usbDev.curFeature & (1 << 5))
{
status[0] |= 0x02;
}
if(g_usbDev.curFeature & (1 << 6))
{
status[0] |= 0x01;
}
USBD_CtrlInData(status, 2);
}
else if((g_usbDev.reqData.byte.bmRequestType.bit.recipient) == USBD_RECIPIENT_INTERFACE)
{
USBD_CtrlInData(status, 2);
}
else if((g_usbDev.reqData.byte.bmRequestType.bit.recipient) == USBD_RECIPIENT_ENDPOINT)
{
if(g_usbDev.reqData.byte.wIndex[0] & 0x80)
{
if(USBD_ReadEPTxStatus(g_usbDev.reqData.byte.wIndex[0] & 0x0f) == USBD_EP_STATUS_STALL)
{
status[0] |= 0x01;
}
}
else
{
if(USBD_ReadEPRxStatus(g_usbDev.reqData.byte.wIndex[0] & 0x0f) == USBD_EP_STATUS_STALL)
{
status[0] |= 0x01;
}
}
USBD_CtrlInData(status, 2);
}
else
{
ret = 0;
}
return ret;
}
/*!
* @brief Standard request set address
*
* @param None
*
* @retval ERROR: 0; SUCCESS : 1
*/
static uint8_t USBD_StandardSetAddress(void)
{
USBD_DevReqData_T *reqData = &g_usbDev.reqData;
if((reqData->byte.wValue[0] < 127) && (reqData->byte.wValue[1] == 0) &&
(reqData->byte.bmRequestType.bit.recipient == USBD_RECIPIENT_DEVICE))
{
USBD_CtrlInData((void *)0, 0);
return 1;
}
return 0;
}
/*!
* @brief Standard request set configuration
*
* @param None
*
* @retval ERROR: 0; SUCCESS : 1
*/
static uint8_t USBD_StandardSetConfiguration(void)
{
USBD_DevReqData_T *reqData = &g_usbDev.reqData;
if((reqData->byte.wValue[0] <= g_usbDev.configurationNum) && \
(reqData->byte.bmRequestType.bit.recipient == USBD_RECIPIENT_DEVICE))
{
g_usbDev.curConfiguration = reqData->byte.wValue[0];
if (g_usbDev.pStdReqCallback->setConfigurationHandler)
{
g_usbDev.pStdReqCallback->setConfigurationHandler();
}
USBD_CtrlInData((void *)0, 0);
return 1;
}
return 0;
}
/*!
* @brief Standard request set descriptor
*
* @param None
*
* @retval 0: Failed; 1: Success
*/
static uint8_t USBD_StandardSetDescriptor(void)
{
return ERROR;
}
/*!
* @brief Standard request set feature
*
* @param None
*
* @retval 0: Failed; 1: Success
*/
static uint8_t USBD_StandardSetFeature(void)
{
uint8_t ret = 1;
return ret;
}
/*!
* @brief Standard request set interface
*
* @param None
*
* @retval 0: Failed; 1: Success
*/
static uint8_t USBD_StandardSetInterface(void)
{
return 0;
}
/*!
* @brief Standard request clear feature
*
* @param None
*
* @retval 0: Failed; 1: Success
*/
static uint8_t USBD_StandardClearFeature(void)
{
return 0;
}
@@ -0,0 +1,942 @@
/*!
* @file drv_usb_device.h
*
* @brief This file contains all the prototypes,enumeration and macros for USBD peripheral
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#ifndef __DRV_USB_DEVICE_H_
#define __DRV_USB_DEVICE_H_
#ifdef __cplusplus
extern "C" {
#endif
#if defined(APM32F070xB) || defined(APM32F072x8) || defined(APM32F072xB)
#define APM32F0xx_USB
#else
#define APM32F10x_USB
#endif
#ifdef APM32F0xx_USB
#include "apm32f0xx.h"
#include "apm32f0xx_pmu.h"
#include "apm32f0xx_eint.h"
#include "apm32f0xx_gpio.h"
#include "apm32f0xx_rcm.h"
#include "apm32f0xx_misc.h"
#include "usb_config.h"
#else
#include "apm32f10x.h"
#include "apm32f10x_pmu.h"
#include "apm32f10x_eint.h"
#include "apm32f10x_gpio.h"
#include "apm32f10x_rcm.h"
#include "apm32f10x_misc.h"
#include "usb_config.h"
#endif
/** @addtogroup Peripherals_Library Standard Peripheral Library
@{
*/
/** @addtogroup USBD_Driver USBD Driver
@{
*/
/** @addtogroup USBD_Enumerations Enumerations
@{
*/
/**
* @brief USBD Endpoint register bit definition
*/
typedef enum
{
USBD_EP_BIT_ADDR = (uint32_t)(BIT0 | BIT1 | BIT2 | BIT3),
USBD_EP_BIT_TXSTS = (uint32_t)(BIT4 | BIT5),
USBD_EP_BIT_TXDTOG = (uint32_t)(BIT6),
USBD_EP_BIT_CTFT = (uint32_t)(BIT7),
USBD_EP_BIT_KIND = (uint32_t)(BIT8),
USBD_EP_BIT_TYPE = (uint32_t)(BIT9 | BIT10),
USBD_EP_BIT_SETUP = (uint32_t)(BIT11),
USBD_EP_BIT_RXSTS = (uint32_t)(BIT12 | BIT13),
USBD_EP_BIT_RXDTOG = (uint32_t)(BIT14),
USBD_EP_BIT_CTFR = (uint32_t)(BIT15)
}USBD_EP_BIT_T;
/**
* @brief Endpoint id
*/
typedef enum
{
USBD_EP_0,
USBD_EP_1,
USBD_EP_2,
USBD_EP_3,
USBD_EP_4,
USBD_EP_5,
USBD_EP_6,
USBD_EP_7,
}USBD_EP_T;
/**
* @brief Endpoint status
*/
typedef enum
{
USBD_EP_STATUS_DISABLE = ((uint32_t)0),
USBD_EP_STATUS_STALL = ((uint32_t)1),
USBD_EP_STATUS_NAK = ((uint32_t)2),
USBD_EP_STATUS_VALID = ((uint32_t)3),
}USBD_EP_STATUS_T;
/**
* @brief USBD Endpoint type for register
*/
typedef enum
{
USBD_REG_EP_TYPE_BULK,
USBD_REG_EP_TYPE_CONTROL,
USBD_REG_EP_TYPE_ISO,
USBD_REG_EP_TYPE_INTERRUPT
}USBD_REG_EP_TYPE_T;
/**@} end of group USBD_Enumerations*/
/** @addtogroup USBD_Macros Macros
@{
*/
/** USBD packet memory area base address */
#define USBD_PMA_ADDR (0x40006000L)
/** Endpoint register mask value default */
#define USBD_EP_MASK_DEFAULT (USBD_EP_BIT_CTFR | USBD_EP_BIT_SETUP | USBD_EP_BIT_TYPE | USBD_EP_BIT_KIND | USBD_EP_BIT_CTFT |USBD_EP_BIT_ADDR)
/**
* @brief USBD interrupt source
*/
#define USBD_INT_ESOF 0X100
#define USBD_INT_SOF 0X200
#define USBD_INT_RST 0X400
#define USBD_INT_SUS 0x800
#define USBD_INT_WKUP 0X1000
#define USBD_INT_ERR 0X2000
#define USBD_INT_PMAOU 0X4000
#define USBD_INT_CTR 0X8000
#define USBD_INT_ALL 0XFF00
/**@} end of group USBD_Macros*/
/** @addtogroup USBD_Fuctions Fuctions
@{
*/
/*!
* @brief Set CTRL register
*
* @param val: Register value
*
* @retval None
*
*/
#define USBD_SetRegCTRL(val) (USBD->CTRL = val)
/*!
* @brief Set INTSTS register
*
* @param val: Register value
*
* @retval None
*/
#define USBD_SetRegINTSTS(val) (USBD->INTSTS = val)
/*!
* @brief Set force reset
*
* @param None
*
* @retval None
*/
#define USBD_SetForceReset() (USBD->CTRL_B.FORRST = BIT_SET)
/*!
* @brief Reset force reset
*
* @param None
*
* @retval None
*/
#define USBD_ResetForceReset() (USBD->CTRL_B.FORRST = BIT_RESET)
/*!
* @brief Set power down
*
* @param None
*
* @retval None
*/
#define USBD_SetPowerDown() (USBD->CTRL_B.PWRDOWN = BIT_SET)
/*!
* @brief Reset power down
*
* @param None
*
* @retval None
*/
#define USBD_ResetPowerDown() (USBD->CTRL_B.PWRDOWN = BIT_RESET)
/*!
* @brief Set low power mode
*
* @param None
*
* @retval None
*/
#define USBD_SetLowerPowerMode() (USBD->CTRL_B.LPWREN = BIT_SET)
/*!
* @brief Ret low power mode
*
* @param None
*
* @retval None
*/
#define USBD_ResetLowerPowerMode() (USBD->CTRL_B.LPWREN = BIT_RESET)
/*!
* @brief Set force suspend
*
* @param None
*
* @retval None
*/
#define USBD_SetForceSuspend() (USBD->CTRL_B.FORSUS = BIT_SET)
/*!
* @brief Reset force suspend
*
* @param None
*
* @retval None
*/
#define USBD_ResetForceSuspend() (USBD->CTRL_B.FORSUS = BIT_RESET)
/*!
* @brief Read force suspend status
*
* @param None
*
* @retval None
*/
#define USBD_ReadForceSuspend() (USBD->CTRL_B.FORSUS)
/*!
* @brief Set resume
*
* @param None
*
* @retval None
*/
#define USBD_SetResume() (USBD->CTRL_B.WUPREQ = BIT_SET)
/*!
* @brief Reset resume
*
* @param None
*
* @retval None
*/
#define USBD_ResetResume() (USBD->CTRL_B.WUPREQ = BIT_RESET)
/*!
* @brief Enable interrupt
*
* @param int: Interrupt source
*
* @retval None
*/
#define USBD_EnableInterrupt(int) (USBD->CTRL |= int)
/*!
* @brief Disable interrupt
*
* @param int: Interrupt source
*
* @retval None
*/
#define USBD_DisableInterrupt(int) (USBD->CTRL &= (uint32_t)~int)
/*!
* @brief Read the specified interrupt flag status
*
* @param int: Interrupt source
*
* @retval Flag status.0 or not 0
*/
#define USBD_ReadIntFlag(int) (USBD->INTSTS & int)
/*!
* @brief Clear the specified interrupt flag status
*
* @param int: Interrupt source
*
* @retval None
*/
#define USBD_ClearIntFlag(int) (USBD->INTSTS &= (uint32_t)~int)
/*!
* @brief Read DOT field value in INTSTS rigister
*
* @param None
*
* @retval DOT field value
*/
#define USBD_ReadDir() (USBD->INTSTS_B.DOT)
/*!
* @brief Read EPID field value in INTSTS rigister
*
* @param None
*
* @retval EPIDfield value
*/
#define USBD_ReadEP() ((USBD_EP_T)(USBD->INTSTS_B.EPID))
/*!
* @brief Read EP type
*
* @param ep: EP number
*
* @retval EP type
*/
#define USBD_ReadEPType(ep) (USBD->EP[ep].EP_B.TYPE)
/*!
* @brief Read EP Tx status
*
* @param ep: EP number
*
* @retval EP Tx status
*/
#define USBD_ReadEPTxStatus(ep) ((USBD_EP_STATUS_T)(USBD->EP[ep].EP_B.TXSTS))
/*!
* @brief Read EP Rx status
*
* @param ep: EP number
*
* @retval EP Rx status
*/
#define USBD_ReadEPRxStatus(ep) ((USBD_EP_STATUS_T)(USBD->EP[ep].EP_B.RXSTS))
/*!
* @brief Read SETUP field value in EP register
*
* @param ep: EP number
*
* @retval SETUP field value
*/
#define USBD_ReadEPSetup(ep) (USBD->EP[ep].EP_B.SETUP)
/*!
* @brief Set buffer table value
*
* @param tab: Buffer table value
*
* @retval None
*/
#define USBD_SetBufferTable(tab) (USBD->BUFFTB_B.BUFFTB = tab)
/*!
* @brief Set device address
*
* @param addr: Device address
*
* @retval None
*/
#define USBD_SetDeviceAddr(addr) (USBD->ADDR_B.ADDR = addr)
/*!
* @brief Read CTFR field value in EP register
*
* @param ep: Endpoint number
*
* @retval CTFR field value
*/
#define USBD_ReadEPRxFlag(ep) (USBD->EP[ep].EP_B.CTFR)
/*!
* @brief Read CTFT field value in EP register
*
* @param ep: Endpoint number
*
* @retval CTFT field value
*/
#define USBD_ReadEPTxFlag(ep) (USBD->EP[ep].EP_B.CTFT)
/*!
* @brief Enable USBD peripheral
*
* @param None
*
* @retval None
*/
#define USBD_Enable() (USBD->ADDR_B.USBDEN = BIT_SET)
/*!
* @brief Disable USBD peripheral
*
* @param None
*
* @retval None
*/
#define USBD_Disable() (USBD->ADDR_B.USBDEN = BIT_RESET)
/*!
* @brief Enable USBD2 peripheral
*
* @param None
*
* @retval None
*/
#define USBD2_Enable() (USBD->SWITCH = BIT_SET)
/*!
* @brief Disable USBD2 peripheral
*
* @param None
*
* @retval None
*/
#define USBD2_Disable() (USBD->SWITCH = BIT_RESET)
/*!
* @brief Read RXDPSTS field value in FRANUM register
*
* @param None
*
* @retval RXDPSTS field value
*/
#define USBD_ReadRDPS() (USBD->FRANUM_B.RXDPSTS)
/*!
* @brief Read RXDMSTS field value in FRANUM register
*
* @param None
*
* @retval RXDMSTS field value
*/
#define USBD_ReadRDMS() (USBD->FRANUM_B.RXDMSTS)
/*!
* @brief Read LOCK field value in FRANUM register
*
* @param None
*
* @retval LOCK field value
*/
#define USBD_ReadLOCK() (USBD->FRANUM_B.LOCK)
/*!
* @brief Read LSOFNUM field value in FRANUM register
*
* @param None
*
* @retval LSOFNUM field value
*/
#define USBD_ReadLSOF() (USBD->FRANUM_B.LSOFNUM)
/*!
* @brief Read FRANUM field value in FRANUM register
*
* @param None
*
* @retval FRANUM field value
*/
#define USBD_ReadFRANUM() (USBD->FRANUM_B.FRANUM)
#ifdef APM32F0xx_USB
/*!
* @brief Read EP Tx address pointer
*
* @param ep: EP number
*
* @retval EP Tx address pointer
*/
#define USBD_ReadEPTxAddrPointer(ep) (uint16_t *)((USBD->BUFFTB + ep * 8) + USBD_PMA_ADDR)
/*!
* @brief Read EP Tx count pointer
*
* @param ep: EP number
*
* @retval EP Tx count pointer
*/
#define USBD_ReadEPTxCntPointer(ep) (uint16_t *)((USBD->BUFFTB + ep * 8 + 2) + USBD_PMA_ADDR)
/*!
* @brief Read EP Rx address pointer
*
* @param ep: EP number
*
* @retval EP Rx address pointer
*/
#define USBD_ReadEPRxAddrPointer(ep) (uint16_t *)((USBD->BUFFTB + ep * 8 + 4) + USBD_PMA_ADDR)
/*!
* @brief Read EP Rx count pointer
*
* @param ep: EP number
*
* @retval EP Rx count pointer
*/
#define USBD_ReadEPRxCntPointer(ep) (uint16_t *)((USBD->BUFFTB + ep * 8 + 6) + USBD_PMA_ADDR)
/*!
* @brief Set EP Tx addr
*
* @param ep: EP number
*
* @param addr: Tx addr
*
* @retval None
*/
#define USBD_SetEPTxAddr(ep, addr) (*USBD_ReadEPTxAddrPointer(ep) = (addr >> 1) << 1)
/*!
* @brief Set EP Rx addr
*
* @param ep: EP number
*
* @param addr: Rx addr
*
* @retval None
*/
#define USBD_SetEPRxAddr(ep, addr) (*USBD_ReadEPRxAddrPointer(ep) = (addr >> 1) << 1)
/*!
* @brief Read EP Tx addr
*
* @param ep: EP number
*
* @retval EP Tx addr
*/
#define USBD_ReadEPTxAddr(ep) ((uint16_t)*USBD_ReadEPTxAddrPointer(ep))
/*!
* @brief Read EP Rx addr
*
* @param ep: EP number
*
* @retval EP Rx addr
*/
#define USBD_ReadEPRxAddr(ep) ((uint16_t)*USBD_ReadEPRxAddrPointer(ep))
/*!
* @brief Read EP Tx Buffer Pointer
*
* @param ep: EP number
*
* @retval EP Tx Buffer Pointer
*/
#define USBD_ReadEPTxBufferPointer(ep) (uint16_t *)(USBD_ReadEPTxAddr(ep) + USBD_PMA_ADDR)
/*!
* @brief Read EP Rx Buffer Pointer
*
* @param ep: EP number
*
* @retval EP Rx Buffer Pointer
*/
#define USBD_ReadEPRxBufferPointer(ep) (uint16_t *)(USBD_ReadEPRxAddr(ep) + USBD_PMA_ADDR)
/*!
* @brief Set EP Tx Count
*
* @param ep: EP number
*
* @param cnt: Tx count
*
* @retval None
*/
#define USBD_SetEPTxCnt(ep, cnt) (*USBD_ReadEPTxCntPointer(ep) = cnt)
/*!
* @brief Read EP Tx count
*
* @param ep: EP number
*
* @retval EP Tx count
*/
#define USBD_ReadEPTxCnt(ep) ((uint16_t)*USBD_ReadEPTxCntPointer(ep) & 0x3ff)
/*!
* @brief Read EP Rx count
*
* @param ep: EP number
*
* @retval EP Rx count
*/
#define USBD_ReadEPRxCnt(ep) ((uint16_t)*USBD_ReadEPRxCntPointer(ep) & 0x3ff)
/*!
* @brief Set BESL Value
*
* @param val: 4-bits BESL Value to be set
*
* @retval None
*/
#define USBD_SetBESL(val) (USBD->LPMCTRLSTS_B.BESL = val)
/*!
* @brief Set bRemoteWakew Value
*
* @param val: 1-bit bRemoteWakew Value to be set
*
* @retval None
*/
#define USBD_SetRemoteWakeVal(val) (USBD->LPMCTRLSTS_B.REMWAKE = val)
/*!
* @brief Enable LPM ACK
*
* @param None
*
* @retval None
*/
#define USBD_EnableAckLPM() (USBD->LPMCTRLSTS_B.LPMACKEN = 1)
/*!
* @brief Disable LPM ACK
*
* @param None
*
* @retval None
*/
#define USBD_DisableAckLPM() (USBD->LPMCTRLSTS_B.LPMACKEN = 0)
/*!
* @brief Disable LPM
*
* @param None
*
* @retval None
*/
#define USBD_EnableLPM() (USBD->LPMCTRLSTS_B.LPMEN = 1)
/*!
* @brief Disable LPM
*
* @param None
*
* @retval None
*/
#define USBD_DisableLPM() (USBD->LPMCTRLSTS_B.LPMEN = 0)
/*!
* @brief Enable Pull-up of DP line
*
* @param None
*
* @retval None
*/
#define USBD_EnablePullUpDP() (USBD->BCD_B.DPPUCTRL = 1)
/*!
* @brief Disable Pull-up of DP line
*
* @param None
*
* @retval None
*/
#define USBD_DisablePullUpDP() (USBD->BCD_B.DPPUCTRL = 0)
/*!
* @brief Read DM Pull-up Detection Status Flag
*
* @param None
*
* @retval DM Pull-up Detection Status Flag
*/
#define USBD_DMPullUpStatus() (USBD->BCD_B.DMPUDFLG)
/*!
* @brief Read Secondary Detection Status Flag
*
* @param None
*
* @retval Secondary Detection Status Flag
*/
#define USBD_SDStatus() (USBD->BCD_B.SDFLG)
/*!
* @brief Read Primary Detection Status Flag
*
* @param None
*
* @retval Primary Detection Status Flag
*/
#define USBD_PDStatus() (USBD->BCD_B.PDFLG)
/*!
* @brief Read Data Contact Detection Status Flag
*
* @param None
*
* @retval Data Contact Detection Status Flag
*/
#define USBD_DCDStatus() (USBD->BCD_B.DCDFLG)
/*!
* @brief Enable Secondary Detection Mode
*
* @param None
*
* @retval None
*/
#define USBD_EnableSDMode() (USBD->BCD_B.SDEN = 1)
/*!
* @brief Disable Secondary Detection Mode
*
* @param None
*
* @retval None
*/
#define USBD_DisableSDMode() (USBD->BCD_B.SDEN = 0)
/*!
* @brief Enable Primary Detection Mode
*
* @param None
*
* @retval None
*/
#define USBD_EnablePDMode() (USBD->BCD_B.PDEN = 1)
/*!
* @brief Disable Primary Detection Mode
*
* @param None
*
* @retval None
*/
#define USBD_DisablePDMode() (USBD->BCD_B.PDEN = 0)
/*!
* @brief Enable Data Contact Detection Mode
*
* @param None
*
* @retval None
*/
#define USBD_EnableDCDMode() (USBD->BCD_B.DCDEN = 1)
/*!
* @brief Disable Data Contact Detection Mode
*
* @param None
*
* @retval None
*/
#define USBD_DisableDCDMode() (USBD->BCD_B.DCDEN = 0)
/*!
* @brief Enable Battery Charging Detector
*
* @param None
*
* @retval None
*/
#define USBD_EnableBCD() (USBD->BCD_B.BCDEN = 1)
/*!
* @brief Disable Battery Charging Detector
*
* @param None
*
* @retval None
*/
#define USBD_DisableBCD() (USBD->BCD_B.BCDEN = 0)
#else //!< APM32F10x_USB
/*!
* @brief Read EP Tx address pointer
*
* @param ep: EP number
*
* @retval EP Tx address pointer
*/
#define USBD_ReadEPTxAddrPointer(ep) (uint16_t *)((USBD->BUFFTB + ep * 8) * 2 + USBD_PMA_ADDR)
/*!
* @brief Read EP Tx count pointer
*
* @param ep: EP number
*
* @retval EP Tx count pointer
*/
#define USBD_ReadEPTxCntPointer(ep) (uint16_t *)((USBD->BUFFTB + ep * 8 + 2) * 2 + USBD_PMA_ADDR)
/*!
* @brief Read EP Rx address pointer
*
* @param ep: EP number
*
* @retval EP Rx address pointer
*/
#define USBD_ReadEPRxAddrPointer(ep) (uint16_t *)((USBD->BUFFTB + ep * 8 + 4) * 2 + USBD_PMA_ADDR)
/*!
* @brief Read EP Rx count pointer
*
* @param ep: EP number
*
* @retval EP Rx count pointer
*/
#define USBD_ReadEPRxCntPointer(ep) (uint16_t *)((USBD->BUFFTB + ep * 8 + 6) * 2 + USBD_PMA_ADDR)
/*!
* @brief Set EP Tx addr
*
* @param ep: EP number
*
* @param addr: Tx addr
*
* @retval None
*/
#define USBD_SetEPTxAddr(ep, addr) (*USBD_ReadEPTxAddrPointer(ep) = (addr >> 1) << 1)
/*!
* @brief Set EP Rx addr
*
* @param ep: EP number
*
* @param addr: Rx addr
*
* @retval None
*/
#define USBD_SetEPRxAddr(ep, addr) (*USBD_ReadEPRxAddrPointer(ep) = (addr >> 1) << 1)
/*!
* @brief Read EP Tx addr
*
* @param ep: EP number
*
* @retval EP Tx addr
*/
#define USBD_ReadEPTxAddr(ep) ((uint16_t)*USBD_ReadEPTxAddrPointer(ep))
/*!
* @brief Read EP Rx addr
*
* @param ep: EP number
*
* @retval EP Rx addr
*/
#define USBD_ReadEPRxAddr(ep) ((uint16_t)*USBD_ReadEPRxAddrPointer(ep))
/*!
* @brief Read EP Tx Buffer Pointer
*
* @param ep: EP number
*
* @retval EP Tx Buffer Pointer
*/
#define USBD_ReadEPTxBufferPointer(ep) (uint32_t *)(((uint32_t)USBD_ReadEPTxAddr(ep) << 1) + USBD_PMA_ADDR)
/*!
* @brief Read EP Rx Buffer Pointer
*
* @param ep: EP number
*
* @retval EP Rx Buffer Pointer
*/
#define USBD_ReadEPRxBufferPointer(ep) (uint32_t *)(((uint32_t)USBD_ReadEPRxAddr(ep) << 1) + USBD_PMA_ADDR)
/*!
* @brief Set EP Tx Count
*
* @param ep: EP number
*
* @param cnt: Tx count
*
* @retval None
*/
#define USBD_SetEPTxCnt(ep, cnt) (*USBD_ReadEPTxCntPointer(ep) = cnt)
/*!
* @brief Read EP Tx count
*
* @param ep: EP number
*
* @retval EP Tx count
*/
#define USBD_ReadEPTxCnt(ep) ((uint16_t)*USBD_ReadEPTxCntPointer(ep) & 0x3ff)
/*!
* @brief Read EP Rx count
*
* @param ep: EP number
*
* @retval EP Rx count
*/
#define USBD_ReadEPRxCnt(ep) ((uint16_t)*USBD_ReadEPRxCntPointer(ep) & 0x3ff)
#endif
void USBD_SetEPType(uint8_t ep, USBD_REG_EP_TYPE_T type);
void USBD_SetEPKind(uint8_t ep);
void USBD_ResetEPKind(uint8_t ep);
void USBD_ResetEPRxFlag(uint8_t ep);
void USBD_ResetEPTxFlag(uint8_t ep);
void USBD_ToggleTx(uint8_t ep);
void USBD_ToggleRx(uint8_t ep);
void USBD_ResetTxToggle(uint8_t ep);
void USBD_ResetRxToggle(uint8_t ep);
void USBD_SetEpAddr(uint8_t ep, uint8_t addr);
void USBD_SetEPTxStatus(uint8_t ep, USBD_EP_STATUS_T status);
void USBD_SetEPRxStatus(uint8_t ep, USBD_EP_STATUS_T status);
void USBD_SetEPTxRxStatus(uint8_t ep, USBD_EP_STATUS_T txStatus, USBD_EP_STATUS_T rxStatus);
void USBD_SetEPRxCnt(uint8_t ep, uint32_t cnt);
void USBD_WriteDataToEP(uint8_t ep, uint8_t *wBuf, uint32_t wLen);
void USBD_ReadDataFromEP(uint8_t ep, uint8_t *rBuf, uint32_t rLen);
/**@} end of group USBD_Fuctions*/
/**@} end of group USBD_Driver*/
/**@} end of group Peripherals_Library*/
#ifdef __cplusplus
}
#endif
#endif /* __DRV_USB_DEVICE_H */
@@ -0,0 +1,403 @@
/*!
* @file drv_usb_device.c
*
* @brief This file contains all the functions for the USBD peripheral
*
* @version V1.0.0
*
* @date 2021-12-06
*
* @attention
*
* Copyright (C) 2020-2022 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
#include "drv_usb_device.h"
/*!
* @brief Set Endpoint type
*
* @param ep: Endpoint number
*
* @param type: Endpoint type
*
* @retval None
*/
void USBD_SetEPType(uint8_t ep, USBD_REG_EP_TYPE_T type)
{
__IOM uint32_t reg;
reg = USBD->EP[ep].EP;
reg &= (uint32_t)(USBD_EP_MASK_DEFAULT);
reg &= ~USBD_EP_BIT_TYPE;
reg |= type << 9;
USBD->EP[ep].EP = reg;
}
/*!
* @brief Set EP kind
*
* @param ep: Endpoint number
*
* @retval None
*/
void USBD_SetEPKind(uint8_t ep)
{
__IOM uint32_t reg;
reg = USBD->EP[ep].EP;
reg &= (uint32_t)(USBD_EP_MASK_DEFAULT);
reg |= USBD_EP_BIT_KIND;
USBD->EP[ep].EP = reg;
}
/*!
* @brief Reset EP kind
*
* @param ep: Endpoint number
*
* @retval None
*/
void USBD_ResetEPKind(uint8_t ep)
{
__IOM uint32_t reg;
reg = USBD->EP[ep].EP;
reg &= (uint32_t)(USBD_EP_MASK_DEFAULT);
reg &= ~USBD_EP_BIT_KIND;
USBD->EP[ep].EP = reg;
}
/*!
* @brief Reset EP CTFR bit
*
* @param ep: Endpoint number
*
* @retval None
*/
void USBD_ResetEPRxFlag(uint8_t ep)
{
__IOM uint32_t reg;
reg = USBD->EP[ep].EP;
reg &= (uint32_t)(USBD_EP_MASK_DEFAULT);
reg &= ~USBD_EP_BIT_CTFR;
USBD->EP[ep].EP = reg;
}
/*!
* @brief Reset EP CTFT bit
*
* @param ep: Endpoint number
*
* @retval None
*/
void USBD_ResetEPTxFlag(uint8_t ep)
{
__IOM uint32_t reg;
reg = USBD->EP[ep].EP;
reg &= (uint32_t)(USBD_EP_MASK_DEFAULT);
reg &= ~USBD_EP_BIT_CTFT;
USBD->EP[ep].EP = reg;
}
/*!
* @brief Toggle Tx DTOG
*
* @param ep: Endpoint number
*
* @retval None
*/
void USBD_ToggleTx(uint8_t ep)
{
__IOM uint32_t reg;
reg = USBD->EP[ep].EP;
reg &= (uint32_t)(USBD_EP_MASK_DEFAULT);
reg |= USBD_EP_BIT_TXDTOG;
USBD->EP[ep].EP = reg;
}
/*!
* @brief Toggle Rx DTOG
*
* @param ep: Endpoint number
*
* @retval None
*/
void USBD_ToggleRx(uint8_t ep)
{
__IOM uint32_t reg;
reg = USBD->EP[ep].EP;
reg &= (uint32_t)(USBD_EP_MASK_DEFAULT);
reg |= USBD_EP_BIT_RXDTOG;
USBD->EP[ep].EP = reg;
}
/*!
* @brief Reset Toggle Tx DTOG
*
* @param ep: Endpoint number
*
* @retval None
*/
void USBD_ResetTxToggle(uint8_t ep)
{
if(USBD->EP[ep].EP_B.TXDTOG)
{
USBD_ToggleTx(ep);
}
}
/*!
* @brief Reset Toggle Rx DTOG
*
* @param ep: Endpoint number
*
* @retval None
*/
void USBD_ResetRxToggle(uint8_t ep)
{
if(USBD->EP[ep].EP_B.RXDTOG)
{
USBD_ToggleRx(ep);
}
}
/*!
* @brief Set EP address
*
* @param ep: Endpoint number
*
* @param addr: Address
*
* @retval None
*/
void USBD_SetEpAddr(uint8_t ep, uint8_t addr)
{
__IOM uint32_t reg;
reg = USBD->EP[ep].EP;
reg &= (uint32_t)(USBD_EP_MASK_DEFAULT);
reg &= ~USBD_EP_BIT_ADDR;
reg |= addr;
USBD->EP[ep].EP = reg;
}
/*!
* @brief Set EP Tx status
*
* @param ep: Endpoint number
*
* @param status: status
*
* @retval None
*/
void USBD_SetEPTxStatus(uint8_t ep, USBD_EP_STATUS_T status)
{
__IOM uint32_t reg;
status <<= 4;
reg = USBD->EP[ep].EP;
reg &= (uint32_t)(USBD_EP_MASK_DEFAULT | USBD_EP_BIT_TXSTS);
reg ^= ((uint32_t)status & (uint32_t)USBD_EP_BIT_TXSTS);
USBD->EP[ep].EP = reg;
}
/*!
* @brief Set EP Rx status
*
* @param ep: Endpoint number
*
* @param status: status
*
* @retval None
*/
void USBD_SetEPRxStatus(uint8_t ep, USBD_EP_STATUS_T status)
{
__IOM uint32_t reg;
uint32_t tmp;
tmp = status << 12;
reg = USBD->EP[ep].EP;
reg &= (uint32_t)(USBD_EP_MASK_DEFAULT | USBD_EP_BIT_RXSTS);
reg ^= (tmp & USBD_EP_BIT_RXSTS);
USBD->EP[ep].EP = reg;
}
/*!
* @brief Set EP Tx and Rx status
*
* @param ep: Endpoint number
*
* @param status: status
*
* @retval None
*/
void USBD_SetEPTxRxStatus(uint8_t ep, USBD_EP_STATUS_T txStatus, USBD_EP_STATUS_T rxStatus)
{
__IOM uint32_t reg;
uint32_t tmp;
reg = USBD->EP[ep].EP;
reg &= (uint32_t)(USBD_EP_MASK_DEFAULT | USBD_EP_BIT_RXSTS | USBD_EP_BIT_TXSTS);
tmp = rxStatus << 12;
reg ^= (tmp & USBD_EP_BIT_RXSTS);
tmp = txStatus << 4;
reg ^= (tmp & USBD_EP_BIT_TXSTS);
USBD->EP[ep].EP = reg;
}
/*!
* @brief Set EP Rx Count
*
* @param ep: Endpoint number
*
* @param cnt: Rx count
*
* @retval None
*/
void USBD_SetEPRxCnt(uint8_t ep, uint32_t cnt)
{
__IOM uint16_t *p;
__IOM uint16_t block = 0;
p = USBD_ReadEPRxCntPointer(ep);
if(cnt > 62)
{
block = cnt >> 5;
if(!(cnt & 0x1f))
{
block -= 1;
}
*p = (block << 10) | 0x8000;
}
else
{
block = cnt >> 1;
if(cnt & 0x01)
{
block += 1;
}
*p = (block << 10);
}
}
/*!
* @brief Write a buffer of data to a selected endpoint
*
* @param ep: Endpoint number
*
* @retval wBuf: The pointer to the buffer of data to be written to the endpoint
*
* @param wLen: Number of data to be written (in bytes)
*
* @retval None
*/
void USBD_WriteDataToEP(uint8_t ep, uint8_t *wBuf, uint32_t wLen)
{
uint32_t i;
#ifdef APM32F0xx_USB
uint16_t *epAddr;
uint16_t tmp;
#else
uint32_t *epAddr;
uint32_t tmp;
#endif
wLen = (wLen + 1) >> 1;
epAddr = USBD_ReadEPTxBufferPointer(ep);
for(i = 0; i < wLen; i++)
{
tmp = *wBuf++;
tmp = ((*wBuf++) << 8) | tmp;
*epAddr++ = tmp;
}
}
/*!
* @brief Read a buffer of data to a selected endpoint
*
* @param ep: Endpoint number
*
* @retval wBuf: The pointer to the buffer of data to be read to the endpoint
*
* @param wLen: Number of data to be read (in bytes)
*
* @retval None
*/
void USBD_ReadDataFromEP(uint8_t ep, uint8_t *rBuf, uint32_t rLen)
{
#ifdef APM32F0xx_USB
uint16_t *epAddr;
#else
uint32_t *epAddr;
#endif
uint32_t i, tmp, cnt;
cnt = rLen >> 1;
epAddr = USBD_ReadEPRxBufferPointer(ep);
for(i = 0; i < cnt; i++)
{
tmp = *epAddr++;
*rBuf++ = tmp & 0xFF;
*rBuf++ = (tmp >> 8) & 0xFF;
}
if (rLen & 1)
{
tmp = *epAddr;
*rBuf = tmp & 0xFF;
}
}