rt-thread-official/bsp/gd32450z-eval/Libraries/GD32F4xx_usb_driver/Source/usbd_std.c

700 lines
22 KiB
C

/*!
\file usbd_std.c
\brief USB 2.0 standard handler driver
*/
/*
Copyright (C) 2016 GigaDevice
2016-08-15, V1.0.0, firmware for GD32F4xx
*/
#include "usbd_std.h"
#include "usb_core.h"
static usbd_status_enum usbd_standard_request (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static usbd_status_enum usbd_device_class_request (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static usbd_status_enum usbd_vendor_request (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_setup_request_parse(usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_getdescriptor (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_setaddress (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_setconfig (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_getconfig (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_getstatus (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_setfeature (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_clrfeature (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_reserved (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_setdescriptor (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_getinterface (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_setinterface (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static void usbd_synchframe (usb_core_handle_struct *pudev, usb_device_req_struct *req);
static uint8_t* usbd_device_descriptor_get (usb_core_handle_struct *pudev, uint8_t index, uint16_t *pLen);
static uint8_t* usbd_configuration_descriptor_get (usb_core_handle_struct *pudev, uint8_t index, uint16_t *pLen);
static uint8_t* usbd_string_descriptor_get (usb_core_handle_struct *pudev, uint8_t index, uint16_t *pLen);
static void (*StandardDeviceRequest[])(usb_core_handle_struct *pudev, usb_device_req_struct *req) =
{
usbd_getstatus,
usbd_clrfeature,
usbd_reserved,
usbd_setfeature,
usbd_reserved,
usbd_setaddress,
usbd_getdescriptor,
usbd_setdescriptor,
usbd_getconfig,
usbd_setconfig,
usbd_getinterface,
usbd_setinterface,
usbd_synchframe,
};
/* get standard descriptor handler */
static uint8_t* (*standard_descriptor_get[])(usb_core_handle_struct *pudev, uint8_t index, uint16_t *pLen) =
{
usbd_device_descriptor_get,
usbd_configuration_descriptor_get,
usbd_string_descriptor_get
};
/*!
\brief USB setup stage processing
\param[in] pudev: pointer to USB device instance
\param[out] none
\retval USB device operation status
*/
usbd_status_enum usbd_setup_transaction(usb_core_handle_struct *pudev)
{
usb_device_req_struct req;
usbd_setup_request_parse(pudev, &req);
switch (req.bmRequestType & USB_REQ_MASK) {
/* standard device request */
case USB_STANDARD_REQ:
usbd_standard_request(pudev, &req);
break;
/* device class request */
case USB_CLASS_REQ:
usbd_device_class_request(pudev, &req);
break;
/* vendor defined request */
case USB_VENDOR_REQ:
usbd_vendor_request(pudev, &req);
break;
default:
usbd_ep_stall(pudev, req.bmRequestType & 0x80U);
break;
}
return USBD_OK;
}
/*!
\brief data out stage processing
\param[in] pudev: pointer to USB device instance
\param[in] ep_id: endpoint identifier(0..7)
\param[out] none
\retval USB device operation status
*/
usbd_status_enum usbd_out_transaction (usb_core_handle_struct *pudev, uint8_t endp_num)
{
usb_ep_struct *ep;
if (0U == endp_num) {
ep = &pudev->dev.out_ep[0];
if (USB_CTRL_DATA_OUT == pudev->dev.ctl_status) {
if (pudev->dev.remain_len > ep->endp_mps) {
pudev->dev.remain_len -= ep->endp_mps;
if (1U == pudev->cfg.dma_enable) {
/* update buffer location */
ep->xfer_buff += ep->endp_mps;
}
usbd_ep_rx (pudev,
0U,
ep->xfer_buff,
(uint16_t)USB_MIN(pudev->dev.remain_len, ep->endp_mps));
} else {
if (USB_STATUS_CONFIGURED == pudev->dev.status) {
pudev->dev.class_data_handler(pudev, USBD_RX, 0U);
}
usbd_ctlstatus_tx(pudev);
}
}
} else if (USB_STATUS_CONFIGURED == pudev->dev.status) {
pudev->dev.class_data_handler(pudev, USBD_RX, endp_num);
} else {
/* no operation */
}
return USBD_OK;
}
/*!
\brief data in stage processing
\param[in] pudev: pointer to USB device instance
\param[in] ep_id: endpoint identifier(0..7)
\param[out] none
\retval USB device operation status
*/
usbd_status_enum usbd_in_transaction (usb_core_handle_struct *pudev, uint8_t endp_num)
{
usb_ep_struct *ep;
if (0U == endp_num) {
ep = &pudev->dev.in_ep[0];
if (USB_CTRL_DATA_IN == pudev->dev.ctl_status) {
if (pudev->dev.remain_len > ep->endp_mps) {
pudev->dev.remain_len -= ep->endp_mps;
if (1U == pudev->cfg.dma_enable) {
/* update buffer location */
ep->xfer_buff += ep->endp_mps;
}
usbd_ep_tx (pudev, 0U, ep->xfer_buff, pudev->dev.remain_len);
} else {
/* last packet is MPS multiple, so send ZLP packet */
if ((pudev->dev.sum_len % ep->endp_mps == 0U) &&
(pudev->dev.sum_len >= ep->endp_mps) &&
(pudev->dev.sum_len < pudev->dev.ctl_len)) {
usbd_ep_tx (pudev, 0U, NULL, 0U);
pudev->dev.ctl_len = 0U;
} else {
if (USB_STATUS_CONFIGURED == pudev->dev.status) {
pudev->dev.class_data_handler(pudev, USBD_TX, 0U);
}
usbd_ctlstatus_rx(pudev);
}
}
}
} else if (USB_STATUS_CONFIGURED == pudev->dev.status) {
pudev->dev.class_data_handler(pudev, USBD_TX, endp_num);
} else {
/* no operation */
}
return USBD_OK;
}
/*!
\brief handle USB standard device request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval USB device operation status
*/
static usbd_status_enum usbd_standard_request (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
/* call device request handle function */
(*StandardDeviceRequest[req->bRequest])(pudev, req);
return USBD_OK;
}
/*!
\brief handle USB device class request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device class request
\param[out] none
\retval USB device operation status
*/
static usbd_status_enum usbd_device_class_request (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
usbd_status_enum ret = USBD_OK;
switch (pudev->dev.status) {
case USB_STATUS_CONFIGURED:
if (LOWBYTE(req->wIndex) <= USBD_ITF_MAX_NUM) {
ret = (usbd_status_enum)(pudev->dev.class_req_handler(pudev, req));
if ((0U == req->wLength) && (USBD_OK == ret)) {
/* no data stage */
usbd_ctlstatus_tx(pudev);
}
} else {
usbd_enum_error(pudev, req);
}
break;
default:
usbd_enum_error(pudev, req);
break;
}
return ret;
}
/*!
\brief handle USB vendor request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB vendor request
\param[out] none
\retval USB device operation status
*/
static usbd_status_enum usbd_vendor_request (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
/* added by user... */
return USBD_OK;
}
/*!
\brief no operation, just for reserved
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_reserved (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
/* no operation... */
}
/*!
\brief get the device descriptor
\brief[in] index: no use
\param[in] none
\param[out] pLen: data length pointer
\retval descriptor buffer pointer
*/
static uint8_t* usbd_device_descriptor_get (usb_core_handle_struct *pudev, uint8_t index, uint16_t *pLen)
{
*pLen = pudev->dev.dev_desc[0];
return pudev->dev.dev_desc;
}
/*!
\brief get the configuration descriptor
\brief[in] index: no use
\param[in] none
\param[out] pLen: data length pointer
\retval descriptor buffer pointer
*/
static uint8_t* usbd_configuration_descriptor_get (usb_core_handle_struct *pudev, uint8_t index, uint16_t *pLen)
{
*pLen = pudev->dev.config_desc[2];
return pudev->dev.config_desc;
}
/*!
\brief get string descriptor
\param[in] index: string descriptor index
\param[in] pLen: pointer to string length
\param[out] none
\retval none
*/
static uint8_t* usbd_string_descriptor_get (usb_core_handle_struct *pudev, uint8_t index, uint16_t *pLen)
{
uint8_t *desc = pudev->dev.strings[index];
*pLen = desc[0];
return desc;
}
/*!
\brief handle Get_Status request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_getstatus (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
}
/*!
\brief handle USB Clear_Feature request
\param[in] pudev: pointer to USB device instance
\param[in] req: USB device request
\param[out] none
\retval none
*/
static void usbd_clrfeature (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
uint8_t ep_addr = 0U;
switch (req->bmRequestType & USB_REQTYPE_MASK) {
case USB_REQTYPE_DEVICE:
switch (pudev->dev.status) {
case USB_STATUS_ADDRESSED:
case USB_STATUS_CONFIGURED:
if (USB_FEATURE_REMOTE_WAKEUP == req->wValue) {
pudev->dev.remote_wakeup = 0U;
pudev->dev.class_req_handler(pudev, req);
usbd_ctlstatus_tx(pudev);
}
break;
default:
usbd_enum_error(pudev, req);
break;
}
break;
case USB_REQTYPE_INTERFACE:
switch (pudev->dev.status) {
case USB_STATUS_ADDRESSED:
usbd_enum_error(pudev, req);
break;
case USB_STATUS_CONFIGURED:
if (LOWBYTE(req->wIndex) <= USBD_ITF_MAX_NUM) {
/* no operation */
} else {
usbd_enum_error(pudev, req);
}
break;
default:
break;
}
break;
case USB_REQTYPE_ENDPOINT:
ep_addr = LOWBYTE(req->wIndex);
switch (pudev->dev.status) {
case USB_STATUS_ADDRESSED:
if (IS_NOT_EP0(ep_addr)) {
usbd_ep_stall(pudev, ep_addr);
}
break;
case USB_STATUS_CONFIGURED:
if (USB_FEATURE_ENDP_HALT == req->wValue) {
if (IS_NOT_EP0(ep_addr)) {
usbd_ep_clear_stall(pudev, ep_addr);
pudev->dev.class_req_handler(pudev, req);
}
}
usbd_ctlstatus_tx(pudev);
break;
default:
break;
}
break;
default:
usbd_enum_error(pudev, req);
break;
}
}
/*!
\brief handle USB Set_Feature request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_setfeature (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
uint8_t ep_addr = 0U;
__IO uint32_t DctlrStatus;
switch (req->bmRequestType & USB_REQ_MASK) {
case USB_REQTYPE_DEVICE:
switch (pudev->dev.status) {
case USB_STATUS_ADDRESSED:
case USB_STATUS_CONFIGURED:
if (USB_FEATURE_REMOTE_WAKEUP == req->wValue) {
pudev->dev.remote_wakeup = 1U;
pudev->dev.class_req_handler(pudev, req);
usbd_ctlstatus_tx(pudev);
} else if ((req->wValue == USB_FEATURE_TEST_MODE) &&
(0U == (req->wIndex & 0xFFU))) {
DctlrStatus = USB_DCTL;
usbd_ctlstatus_tx(pudev);
} else {
/* no operation */
}
break;
default:
break;
}
break;
case USB_REQTYPE_INTERFACE:
switch (pudev->dev.status) {
case USB_STATUS_ADDRESSED:
usbd_enum_error(pudev, req);
break;
case USB_STATUS_CONFIGURED:
if (LOWBYTE(req->wIndex) <= USBD_ITF_MAX_NUM) {
/* no operation */
} else {
usbd_enum_error(pudev, req);
}
break;
default:
break;
}
break;
case USB_REQTYPE_ENDPOINT:
switch (pudev->dev.status) {
case USB_STATUS_ADDRESSED:
if (IS_NOT_EP0(ep_addr)) {
usbd_ep_stall(pudev, ep_addr);
}
break;
case USB_STATUS_CONFIGURED:
if (USB_FEATURE_ENDP_HALT == req->wValue) {
if (IS_NOT_EP0(ep_addr)) {
usbd_ep_stall(pudev, ep_addr);
}
}
pudev->dev.class_req_handler(pudev, req);
usbd_ctlstatus_tx(pudev);
break;
default:
break;
}
break;
default:
usbd_enum_error(pudev, req);
break;
}
}
/*!
\brief handle USB Set_Address request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_setaddress (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
uint8_t DevAddr;
if ((0U == req->wIndex) && (0U == req->wLength)) {
DevAddr = (uint8_t)(req->wValue) & 0x7FU;
if (USB_STATUS_CONFIGURED == pudev->dev.status) {
usbd_enum_error(pudev, req);
} else {
USB_SET_DEVADDR((uint32_t)DevAddr);
usbd_ctlstatus_tx(pudev);
if (0U != DevAddr) {
pudev->dev.status = USB_STATUS_ADDRESSED;
} else {
pudev->dev.status = USB_STATUS_DEFAULT;
}
}
} else {
usbd_enum_error(pudev, req);
}
}
/*!
\brief handle USB Get_Descriptor request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_getdescriptor (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
if (USB_REQTYPE_DEVICE == (req->bmRequestType & USB_REQTYPE_MASK)) {
uint8_t desc_index = (uint8_t)(req->wValue >> 8U);
if (desc_index <= 0x03U) {
uint16_t len;
uint8_t *pbuf;
/* call corresponding descriptor get function */
pbuf = standard_descriptor_get[desc_index - 1U](pudev, (uint8_t)(req->wValue) & 0xFFU, &len);
if ((0U != len) && (0U != req->wLength)) {
len = USB_MIN(len, req->wLength);
if ((1U == desc_index) && (64U == req->wLength)) {
len = 8U;
}
usbd_ctltx(pudev, pbuf, len);
}
} else {
usbd_enum_error(pudev, req);
}
} else if (USB_REQTYPE_INTERFACE == (req->bmRequestType & USB_REQTYPE_MASK)) {
pudev->dev.class_req_handler(pudev, req);
} else {
/* no operation */
}
}
/*!
\brief handle USB Set_Descriptor request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_setdescriptor (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
/* no handle... */
}
/*!
\brief handle USB Get_Configuration request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_getconfig (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
uint32_t USBD_default_config = 0U;
if (1U != req->wLength) {
usbd_enum_error(pudev, req);
} else {
switch (pudev->dev.status) {
case USB_STATUS_ADDRESSED:
usbd_ctltx(pudev, (uint8_t *)&USBD_default_config, 1U);
break;
case USB_STATUS_CONFIGURED:
usbd_ctltx(pudev, &pudev->dev.config_num, 1U);
break;
default:
usbd_enum_error(pudev, req);
break;
}
}
}
/*!
\brief handle USB Set_Configuration request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_setconfig (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
static uint8_t cfgidx;
cfgidx = (uint8_t)(req->wValue);
if (cfgidx > USBD_CFG_MAX_NUM) {
usbd_enum_error(pudev, req);
} else {
switch (pudev->dev.status) {
case USB_STATUS_ADDRESSED:
if (cfgidx) {
pudev->dev.config_num = cfgidx;
pudev->dev.status = USB_STATUS_CONFIGURED;
pudev->dev.class_init(pudev, cfgidx);
}
usbd_ctlstatus_tx(pudev);
break;
case USB_STATUS_CONFIGURED:
if (0U == cfgidx) {
pudev->dev.status = USB_STATUS_ADDRESSED;
pudev->dev.config_num = cfgidx;
pudev->dev.class_deinit(pudev, cfgidx);
} else if (cfgidx != pudev->dev.config_num) {
/* clear old configuration */
pudev->dev.class_deinit(pudev, pudev->dev.config_num);
/* set new configuration */
pudev->dev.config_num = cfgidx;
pudev->dev.class_init(pudev, cfgidx);
} else {
/* no operation */
}
usbd_ctlstatus_tx(pudev);
break;
default:
usbd_enum_error(pudev, req);
break;
}
}
}
/*!
\brief handle USB Get_Interface request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_getinterface (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
pudev->dev.class_req_handler(pudev, req);
}
/*!
\brief handle USB Set_Interface request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_setinterface (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
pudev->dev.class_req_handler(pudev, req);
}
/*!
\brief handle USB SynchFrame request
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_synchframe (usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
/* no handle... */
}
/*!
\brief decode setup data packet
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
static void usbd_setup_request_parse(usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
uint8_t *psetup = pudev->dev.setup_packet;
req->bmRequestType = *psetup;
req->bRequest = *(uint8_t *)(psetup + 1U);
req->wValue = SWAPBYTE (psetup + 2U);
req->wIndex = SWAPBYTE (psetup + 4U);
req->wLength = SWAPBYTE (psetup + 6U);
pudev->dev.ctl_len = req->wLength;
}
/*!
\brief handle USB low level error event
\param[in] pudev: pointer to USB device instance
\param[in] req: pointer to USB device request
\param[out] none
\retval none
*/
void usbd_enum_error(usb_core_handle_struct *pudev, usb_device_req_struct *req)
{
usbd_ep_stall(pudev, 0x80U);
usbd_ep_stall(pudev, 0x00U);
usb_ep0_startout(pudev);
}