621 lines
22 KiB
C
621 lines
22 KiB
C
/*
|
||
******************************************************************************
|
||
* @file usb_dev.c
|
||
* @author FreqChip Firmware Team
|
||
* @version V1.0.0
|
||
* @date 2021
|
||
* @brief This file provides all the USBD device functions.
|
||
******************************************************************************
|
||
* @attention
|
||
*
|
||
* Copyright (c) 2021 FreqChip.
|
||
* All rights reserved.
|
||
******************************************************************************
|
||
*/
|
||
#include "usb_dev.h"
|
||
|
||
uint16_t USB_Interface_Status; /* Interface status */
|
||
uint16_t USB_Device_Status = 0x0002; /* Device status */
|
||
uint16_t USB_IN_Endpoint_Status[5]; /* IN endpoints status */
|
||
uint16_t USB_OUT_Endpoint_Status[5]; /* OUT endpoints status */
|
||
|
||
uint8_t USB_Configuration; /* Configuration setting */
|
||
uint8_t USB_InterfaceAlternateSet[20]; /* Interface Alternate setting */
|
||
|
||
usb_DescriptorsTypeDef_t DevDescriptors;
|
||
|
||
usb_StandardRequest_t StandardRequest;
|
||
|
||
usb_ReturnData_t ReturnData;
|
||
|
||
void (*Endpoint_0_StandardClassRequest_Handler)(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData) = NULL;
|
||
void (*Endpoint_0_ClassRequest_Handler)(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData) = NULL;
|
||
void (*Endpoint_0_VendorRequest_Handler)(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData) = NULL;
|
||
|
||
void (*Endpoint_0_DataOut_Handler)(void) = NULL;
|
||
|
||
void (*Endpoints_Handler)(uint8_t RxStatus, uint8_t TxStatus) = NULL;
|
||
|
||
void (*USB_SOF_Handler)(void) = NULL;
|
||
void (*USB_Reset_Handler)(void) = NULL;
|
||
void (*USB_Resume_Handler)(void) = NULL;
|
||
void (*USB_Suspend_Handler)(void) = NULL;
|
||
void (*USB_Connect_Handler)(void) = NULL;
|
||
|
||
void (*USB_InterfaceAlternateSet_callback)(uint8_t Interface);
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_dev_desc
|
||
*
|
||
* @brief Get device descriptor buffer pointer.
|
||
*********************************************************************/
|
||
void usbdev_get_dev_desc(uint8_t *Descriptor)
|
||
{
|
||
DevDescriptors.DeviceDescriptor = Descriptor;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_config_desc
|
||
*
|
||
* @brief USB full speed device Get Configuration<6F><6E>Interface<63><65>
|
||
* Endpoint Descriptor.
|
||
*********************************************************************/
|
||
void usbdev_get_config_desc(uint8_t *Descriptor)
|
||
{
|
||
DevDescriptors.ConfigurationDescriptor = Descriptor;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_string_Manufacture
|
||
*
|
||
* @brief Get device Manufacture string Descriptor.
|
||
*********************************************************************/
|
||
void usbdev_get_string_Manufacture(uint8_t *Descriptor)
|
||
{
|
||
DevDescriptors.stringManufacture = Descriptor;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_string_Product
|
||
*
|
||
* @brief Get device Product string Descriptor.
|
||
*********************************************************************/
|
||
void usbdev_get_string_Product(uint8_t *Descriptor)
|
||
{
|
||
DevDescriptors.stringProduct = Descriptor;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_string_SerialNumber
|
||
*
|
||
* @brief Get device SerialNumber string Descriptor.
|
||
*********************************************************************/
|
||
void usbdev_get_string_SerialNumber(uint8_t *Descriptor)
|
||
{
|
||
DevDescriptors.stringSerialNumber = Descriptor;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_string_LanuageID
|
||
*
|
||
* @brief Get device LanuageID string Descriptor.
|
||
*********************************************************************/
|
||
void usbdev_get_string_LanuageID(uint8_t *Descriptor)
|
||
{
|
||
DevDescriptors.stringLanuageID = Descriptor;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_string_OS
|
||
*
|
||
* @brief Get OS String Descriptor.
|
||
*********************************************************************/
|
||
void usbdev_get_string_OS(uint8_t *Descriptor)
|
||
{
|
||
DevDescriptors.stringOS = Descriptor;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_device_status
|
||
*
|
||
* @brief Get device_status. bit0 : self-powered
|
||
* bit1 : device remove wakeup
|
||
*********************************************************************/
|
||
uint16_t usbdev_get_device_status(void)
|
||
{
|
||
return USB_Device_Status;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_in_endpoints_status
|
||
*
|
||
* @brief Get in endpoints status. bit0 : 0 normal
|
||
* bit0 : 1 endpoint_halt
|
||
* @param index: In endpoints index.
|
||
*********************************************************************/
|
||
uint16_t usbdev_get_in_endpoints_status(uint32_t index)
|
||
{
|
||
return USB_IN_Endpoint_Status[index];
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_out_endpoints_status
|
||
*
|
||
* @brief Get out endpoints status.
|
||
*
|
||
* @param index: Out endpoints index.
|
||
*********************************************************************/
|
||
uint16_t usbdev_get_out_endpoints_status(uint32_t index)
|
||
{
|
||
return USB_OUT_Endpoint_Status[index];
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_device_configuration_num
|
||
*
|
||
* @brief Get device configuration num
|
||
*********************************************************************/
|
||
uint8_t usbdev_get_device_configuration_num(void)
|
||
{
|
||
return USB_Configuration;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn usbdev_get_interface_alternate_num
|
||
*
|
||
* @brief Get device interface alternate num
|
||
*
|
||
* @param index: interface index.
|
||
*********************************************************************/
|
||
uint8_t usbdev_get_interface_alternate_num(uint32_t index)
|
||
{
|
||
return USB_InterfaceAlternateSet[index];
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn Endpoint_0_IRQHandler
|
||
*
|
||
* @brief USB endpoint0 Interrupt Request handler
|
||
*
|
||
* @param None.
|
||
* @return None.
|
||
*/
|
||
static void Endpoint_0_IRQHandler(void)
|
||
{
|
||
uint8_t lu8_RxCount;
|
||
|
||
static bool lb_WaitSetAddress = false;
|
||
static bool lb_PktMAX = false;
|
||
|
||
usb_selecet_endpoint(ENDPOINT_0);
|
||
|
||
/* Clear SetupEnd status */
|
||
if (USB_POINT0->CSR01 & USB_CSR01_SETUPEND)
|
||
{
|
||
USB_POINT0->CSR01 |= USB_CSR01_SVCSETUPEND;
|
||
}
|
||
|
||
|
||
/* endpoint 0 receive a packet */
|
||
if (usb_Endpoint0_GET_RxPktRdy())
|
||
{
|
||
/* Data Out packet */
|
||
if (Endpoint_0_DataOut_Handler != NULL)
|
||
{
|
||
Endpoint_0_DataOut_Handler();
|
||
}
|
||
/* Standard Request packet */
|
||
else
|
||
{
|
||
lu8_RxCount = usb_Endpoint0_get_RxCount();
|
||
|
||
usb_read_fifo(ENDPOINT_0, (uint8_t *)&StandardRequest, lu8_RxCount);
|
||
|
||
/* Standard Request */
|
||
if ((StandardRequest.bmRequestType & REQUEST_TYPE_MASK) == TYPE_STANDARD)
|
||
{
|
||
switch (StandardRequest.bRequest)
|
||
{
|
||
/* request descriptor */
|
||
case REQUEST_GET_DESCRIPTOR:
|
||
{
|
||
/* Build the returned data */
|
||
ReturnData.RequestLength = (uint16_t)StandardRequest.wLength[1] << 8;
|
||
ReturnData.RequestLength |= (uint16_t)StandardRequest.wLength[0];
|
||
|
||
switch (StandardRequest.wValue[1])
|
||
{
|
||
case DESCRIPTOR_DEVICE:
|
||
{
|
||
ReturnData.DataBuffer = DevDescriptors.DeviceDescriptor;
|
||
ReturnData.DataLength = ReturnData.DataBuffer[0];
|
||
}break;
|
||
|
||
case DESCRIPTOR_CONFIGURATION:
|
||
{
|
||
ReturnData.DataBuffer = DevDescriptors.ConfigurationDescriptor;
|
||
ReturnData.DataLength = (uint32_t)ReturnData.DataBuffer[3] << 8;
|
||
ReturnData.DataLength |= (uint32_t)ReturnData.DataBuffer[2];
|
||
}break;
|
||
|
||
case DESCRIPTOR_STRING:
|
||
{
|
||
switch (StandardRequest.wValue[0])
|
||
{
|
||
case STRING_MANUFACTURE:
|
||
{
|
||
ReturnData.DataBuffer = DevDescriptors.stringManufacture;
|
||
}break;
|
||
|
||
case STRING_PRODUCT:
|
||
{
|
||
ReturnData.DataBuffer = DevDescriptors.stringProduct;
|
||
}break;
|
||
|
||
case STRING_SERIAL_Number:
|
||
{
|
||
ReturnData.DataBuffer = DevDescriptors.stringSerialNumber;
|
||
}break;
|
||
|
||
case STRING_LANUAGE_ID:
|
||
{
|
||
ReturnData.DataBuffer = DevDescriptors.stringLanuageID;
|
||
}break;
|
||
|
||
case STRING_OS:
|
||
{
|
||
ReturnData.DataBuffer = DevDescriptors.stringOS;
|
||
}break;
|
||
|
||
default: break;
|
||
}
|
||
|
||
ReturnData.DataLength = ReturnData.DataBuffer[0];
|
||
}break;
|
||
|
||
case DESCRIPTOR_DEVICE_QUALIFIER:
|
||
{
|
||
/* USB2.0 full speed send stall */
|
||
usb_Endpoint0_SendStall();
|
||
}break;
|
||
|
||
case DESCRIPTOR_BOS:
|
||
{
|
||
/* USB2.0 does not support DESCRIPTOR_BOS */
|
||
usb_Endpoint0_SendStall();
|
||
}break;
|
||
|
||
case DESCRIPTOR_HID:
|
||
case DESCRIPTOR_HID_REPORT:
|
||
{
|
||
if (Endpoint_0_StandardClassRequest_Handler != NULL)
|
||
{
|
||
Endpoint_0_StandardClassRequest_Handler(&StandardRequest, &ReturnData);
|
||
}
|
||
}break;
|
||
|
||
default: break;
|
||
}
|
||
}break;
|
||
|
||
/* set device address */
|
||
case REQUEST_SET_ADDRESS:
|
||
{
|
||
/* wait an empty IN packet */
|
||
lb_WaitSetAddress = true;
|
||
}break;
|
||
|
||
/* set configuration */
|
||
case REQUEST_SET_CONFIGURATION:
|
||
{
|
||
USB_Configuration = StandardRequest.wValue[0];
|
||
}break;
|
||
/* get configuration */
|
||
case REQUEST_GET_CONFIGURATION:
|
||
{
|
||
ReturnData.RequestLength = 1;
|
||
ReturnData.DataBuffer = &USB_Configuration;
|
||
ReturnData.DataLength = 1;
|
||
}break;
|
||
|
||
/* set interface */
|
||
case REQUEST_SET_INTERFACE:
|
||
{
|
||
USB_InterfaceAlternateSet[StandardRequest.wIndex[0]] = StandardRequest.wValue[0];
|
||
if (USB_InterfaceAlternateSet_callback != NULL)
|
||
{
|
||
USB_InterfaceAlternateSet_callback(StandardRequest.wIndex[0]);
|
||
}
|
||
}break;
|
||
/* get interface */
|
||
case REQUEST_GET_INTERFACE:
|
||
{
|
||
ReturnData.RequestLength = (uint16_t)StandardRequest.wLength[1] << 8;
|
||
ReturnData.RequestLength |= (uint16_t)StandardRequest.wLength[0];
|
||
|
||
ReturnData.DataBuffer = &USB_InterfaceAlternateSet[StandardRequest.wIndex[0]];
|
||
ReturnData.DataLength = ReturnData.RequestLength;
|
||
}break;
|
||
|
||
/* get status */
|
||
case REQUEST_GET_STATUS:
|
||
{
|
||
/* Get Device status */
|
||
if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_DEVICE)
|
||
{
|
||
ReturnData.DataBuffer = (uint8_t *)&USB_Device_Status;
|
||
}
|
||
/* Get Interface status */
|
||
else if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_INTERFACE)
|
||
{
|
||
ReturnData.DataBuffer = (uint8_t *)&USB_Interface_Status;
|
||
}
|
||
/* Get Endpoints status */
|
||
else if((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_ENDPOINT)
|
||
{
|
||
if (StandardRequest.wIndex[0] & DIRECTION_IN)
|
||
{
|
||
ReturnData.DataBuffer = (uint8_t *)&USB_IN_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F];
|
||
}
|
||
else
|
||
{
|
||
ReturnData.DataBuffer = (uint8_t *)&USB_OUT_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F];
|
||
}
|
||
}
|
||
/* Build the returned data */
|
||
ReturnData.RequestLength = 2;
|
||
ReturnData.DataLength = 2;
|
||
}break;
|
||
|
||
/* Set feature */
|
||
case REQUEST_SET_FEATURE:
|
||
{
|
||
/* clear device feature */
|
||
if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_DEVICE)
|
||
{
|
||
if ((StandardRequest.wValue[0] == 1) && (StandardRequest.wValue[1] == 0))
|
||
{
|
||
USB_Device_Status |= 0x0002;
|
||
}
|
||
}
|
||
/* Set Endpoint feature */
|
||
else if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_ENDPOINT)
|
||
{
|
||
if ((StandardRequest.wValue[0] == 0) && (StandardRequest.wValue[1] == 0))
|
||
{
|
||
if (StandardRequest.wIndex[0] & DIRECTION_IN)
|
||
{
|
||
USB_IN_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F] = 0x0001;
|
||
}
|
||
else
|
||
{
|
||
USB_OUT_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F] = 0x0001;
|
||
}
|
||
}
|
||
}
|
||
}break;
|
||
/* Clear feature */
|
||
case REQUEST_CLEAR_FEATURE:
|
||
{
|
||
/* clear device feature */
|
||
if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_DEVICE)
|
||
{
|
||
if ((StandardRequest.wValue[0] == 1) && (StandardRequest.wValue[1] == 0))
|
||
{
|
||
USB_Device_Status &= ~0x0002;
|
||
}
|
||
}
|
||
/* clear Endpoint feature */
|
||
else if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_ENDPOINT)
|
||
{
|
||
if ((StandardRequest.wValue[0] == 0) && (StandardRequest.wValue[1] == 0))
|
||
{
|
||
if (StandardRequest.wIndex[0] & DIRECTION_IN)
|
||
{
|
||
USB_IN_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F] = 0x0000;
|
||
}
|
||
else
|
||
{
|
||
USB_OUT_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F] = 0x0000;
|
||
}
|
||
}
|
||
}
|
||
}break;
|
||
|
||
default: break;
|
||
}
|
||
}
|
||
/* Class Request */
|
||
else if ((StandardRequest.bmRequestType & REQUEST_TYPE_MASK) == TYPE_CLASS)
|
||
{
|
||
if (Endpoint_0_ClassRequest_Handler != NULL)
|
||
{
|
||
Endpoint_0_ClassRequest_Handler(&StandardRequest, &ReturnData);
|
||
}
|
||
}
|
||
/* Vendor Request */
|
||
else if ((StandardRequest.bmRequestType & REQUEST_TYPE_MASK) == TYPE_VENDOR)
|
||
{
|
||
if (Endpoint_0_VendorRequest_Handler != NULL)
|
||
{
|
||
Endpoint_0_VendorRequest_Handler(&StandardRequest, &ReturnData);
|
||
}
|
||
}
|
||
|
||
/* clear TxPktRdy/RxPktRdy */
|
||
usb_Endpoint0_FlushFIFO();
|
||
}
|
||
|
||
}
|
||
/* endpoint 0 transmit a packet */
|
||
else
|
||
{
|
||
if (lb_WaitSetAddress == true)
|
||
{
|
||
lb_WaitSetAddress = false;
|
||
|
||
usb_set_address(StandardRequest.wValue[0]);
|
||
}
|
||
}
|
||
|
||
/* DataBuffer needs to be sent */
|
||
if (ReturnData.DataLength)
|
||
{
|
||
if (ReturnData.RequestLength < ReturnData.DataLength)
|
||
{
|
||
ReturnData.DataLength = ReturnData.RequestLength;
|
||
}
|
||
|
||
if (ReturnData.DataLength > ENDPOINT0_MAX)
|
||
{
|
||
usb_write_fifo(ENDPOINT_0, ReturnData.DataBuffer, ENDPOINT0_MAX);
|
||
|
||
ReturnData.DataLength -= ENDPOINT0_MAX;
|
||
ReturnData.DataBuffer += ENDPOINT0_MAX;
|
||
}
|
||
else
|
||
{
|
||
usb_write_fifo(ENDPOINT_0, ReturnData.DataBuffer, ReturnData.DataLength);
|
||
|
||
if (ReturnData.DataLength == ENDPOINT0_MAX)
|
||
{ /* Packet length is equal to 64 byte, without DataEnd */
|
||
lb_PktMAX = true;
|
||
}
|
||
else
|
||
{
|
||
usb_Endpoint0_DataEnd();
|
||
}
|
||
|
||
ReturnData.DataLength = 0;
|
||
}
|
||
usb_Endpoint0_SET_TxPktRdy();
|
||
}
|
||
else
|
||
{
|
||
/* The packet length of 64 bytes was sent */
|
||
if (lb_PktMAX)
|
||
{
|
||
/* The next packet is empty */
|
||
usb_Endpoint0_DataEnd();
|
||
usb_Endpoint0_SET_TxPktRdy();
|
||
lb_PktMAX = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn Endpoints_IRQHandler
|
||
*
|
||
* @brief ALL Endpoint Interrupt Request handler
|
||
*
|
||
* @param None.
|
||
* @return None.
|
||
*/
|
||
static void Endpoints_IRQHandler(void)
|
||
{
|
||
volatile uint8_t lu8_RxStatus;
|
||
volatile uint8_t lu8_TxStatus;
|
||
volatile uint8_t lu8_EndpointBackup;
|
||
|
||
lu8_EndpointBackup = usb_get_endpoint();
|
||
|
||
lu8_TxStatus = usb_get_TxStatus();
|
||
lu8_RxStatus = usb_get_RxStatus();
|
||
|
||
/* endpoint 0 Interrupt handler */
|
||
if (lu8_TxStatus & ENDPOINT_0_MASK)
|
||
{
|
||
lu8_TxStatus &= ~ENDPOINT_0_MASK;
|
||
|
||
Endpoint_0_IRQHandler();
|
||
}
|
||
|
||
/* other endpoints Rx/Tx Interrupt handler */
|
||
if (lu8_RxStatus | lu8_TxStatus)
|
||
{
|
||
if (Endpoints_Handler != NULL)
|
||
{
|
||
Endpoints_Handler(lu8_RxStatus, lu8_TxStatus);
|
||
}
|
||
}
|
||
|
||
usb_selecet_endpoint((enum_Endpoint_t)lu8_EndpointBackup);
|
||
}
|
||
|
||
static void USB_Status_IRQHandler(void)
|
||
{
|
||
volatile uint8_t lu8_EndpointBackup;
|
||
volatile uint8_t lu8_USBStatus;
|
||
|
||
lu8_EndpointBackup = usb_get_endpoint();
|
||
|
||
lu8_USBStatus = usb_get_USBStatus();
|
||
|
||
/* USB Bus SOF packet */
|
||
if (lu8_USBStatus & USB_INT_STATUS_SOF)
|
||
{
|
||
if (USB_SOF_Handler != NULL)
|
||
{
|
||
USB_SOF_Handler();
|
||
}
|
||
}
|
||
/* USB Bus reset signal, Will be clear USB register */
|
||
/* need configure USB register again */
|
||
if (lu8_USBStatus & USB_INT_STATUS_RESET)
|
||
{
|
||
USB->IntrUSBE = 0x04; /* Enable Bus reset INT */
|
||
USB->IntrTx1E = 0x01; /* Enable Endpoint0 INT */
|
||
USB->IntrTx2E = 0x00;
|
||
USB->IntrRx1E = 0x00;
|
||
USB->IntrRx2E = 0x00;
|
||
|
||
if (USB_Reset_Handler != NULL)
|
||
{
|
||
USB_Reset_Handler();
|
||
}
|
||
}
|
||
/* USB Bus Resume signal */
|
||
if (lu8_USBStatus & USB_INT_STATUS_RESUME)
|
||
{
|
||
if (USB_Resume_Handler != NULL)
|
||
{
|
||
USB_Resume_Handler();
|
||
}
|
||
}
|
||
/* USB Bus Suspend signal */
|
||
if (lu8_USBStatus & USB_INT_STATUS_SUSPEND)
|
||
{
|
||
if (USB_Suspend_Handler != NULL)
|
||
{
|
||
USB_Suspend_Handler();
|
||
}
|
||
}
|
||
/* USB Bus connect signal */
|
||
if (lu8_USBStatus & USB_INT_STATUS_CONN)
|
||
{
|
||
if (USB_Connect_Handler != NULL)
|
||
{
|
||
USB_Connect_Handler();
|
||
}
|
||
}
|
||
|
||
usb_selecet_endpoint((enum_Endpoint_t)lu8_EndpointBackup);
|
||
}
|
||
|
||
#define USB_IRQHandler usbotg_irq
|
||
|
||
/*********************************************************************
|
||
* @fn USB_IRQHandler
|
||
*
|
||
* @brief USB interrupt Request handler
|
||
*
|
||
* @param None.
|
||
* @return None.
|
||
*/
|
||
void USB_IRQHandler(void)
|
||
{
|
||
Endpoints_IRQHandler();
|
||
|
||
USB_Status_IRQHandler();
|
||
}
|