719 lines
23 KiB
C
719 lines
23 KiB
C
/*!
|
|
\file usbd_std.c
|
|
\brief USB 2.0 standard handler driver
|
|
|
|
\version 2017-06-06, V1.0.0, firmware for GD32F3x0
|
|
\version 2019-06-01, V2.0.0, firmware for GD32F3x0
|
|
*/
|
|
|
|
/*
|
|
Copyright (c) 2019, GigaDevice Semiconductor Inc.
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice, this
|
|
list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
3. Neither the name of the copyright holder nor the names of its contributors
|
|
may be used to endorse or promote products derived from this software without
|
|
specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#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;
|
|
|
|
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, USB_RX, 0U);
|
|
}
|
|
|
|
usbd_ctlstatus_tx(pudev);
|
|
}
|
|
}
|
|
} else if (USB_STATUS_CONFIGURED == pudev->dev.status) {
|
|
pudev->dev.class_data_handler(pudev, USB_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;
|
|
|
|
usbd_ep_tx (pudev, 0U, ep->xfer_buff, pudev->dev.remain_len);
|
|
|
|
usbd_ep_rx (pudev, 0U, NULL, 0U);
|
|
} 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;
|
|
|
|
usbd_ep_rx (pudev, 0U, NULL, 0U);
|
|
} else {
|
|
if (USB_STATUS_CONFIGURED == pudev->dev.status) {
|
|
pudev->dev.class_data_handler(pudev, USB_TX, 0U);
|
|
}
|
|
|
|
usbd_ctlstatus_rx(pudev);
|
|
}
|
|
}
|
|
}
|
|
} else if (USB_STATUS_CONFIGURED == pudev->dev.status) {
|
|
pudev->dev.class_data_handler(pudev, USB_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_type = (uint8_t)(req->wValue >> 8);
|
|
uint8_t desc_index = (uint8_t)(req->wValue) & 0xFFU;
|
|
|
|
if ((desc_type <= 0x03U) && (desc_index <= 0x05U)) {
|
|
uint16_t len;
|
|
uint8_t *pbuf;
|
|
|
|
/* call corresponding descriptor get function */
|
|
pbuf = standard_descriptor_get[desc_type - 1U](pudev, desc_index, &len);
|
|
|
|
if ((0U != len) && (0U != req->wLength)) {
|
|
len = USB_MIN(len, req->wLength);
|
|
|
|
if ((1U == desc_type) && (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);
|
|
}
|