mirror of
https://github.com/WeActStudio/WeActStudio.EpaperModule.git
synced 2026-08-16 13:13:45 +02:00
first commit
This commit is contained in:
+261
@@ -0,0 +1,261 @@
|
||||
/*!
|
||||
\file audio_core.h
|
||||
\brief the header file of USB audio device class core functions
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_CORE_H
|
||||
#define __AUDIO_CORE_H
|
||||
|
||||
#include "usbd_enum.h"
|
||||
|
||||
#define FORMAT_24BIT(x) (uint8_t)(x);(uint8_t)((x) >> 8);(uint8_t)((x) >> 16)
|
||||
|
||||
/* audio_freq * data_size (2 bytes) * num_channels (stereo: 2) */
|
||||
#define DEFAULT_OUT_BIT_RESOLUTION 16U
|
||||
#define DEFAULT_OUT_CHANNEL_NBR 2U /* mono = 1, stereo = 2 */
|
||||
#define AUDIO_OUT_PACKET (uint32_t)(((USBD_AUDIO_FREQ_16K * \
|
||||
(DEFAULT_OUT_BIT_RESOLUTION / 8U) *\
|
||||
DEFAULT_OUT_CHANNEL_NBR) / 1000U))
|
||||
|
||||
/* number of sub-packets in the audio transfer buffer. you can modify this value but always make sure
|
||||
that it is an even number and higher than 3 */
|
||||
#define OUT_PACKET_NUM 4U
|
||||
|
||||
/* total size of the audio transfer buffer */
|
||||
#define OUT_BUF_MARGIN 4U
|
||||
#define TOTAL_OUT_BUF_SIZE ((uint32_t)((AUDIO_OUT_PACKET + OUT_BUF_MARGIN) * OUT_PACKET_NUM))
|
||||
|
||||
#define AUDIO_CONFIG_DESC_SET_LEN 109U
|
||||
#define AUDIO_INTERFACE_DESC_SIZE 9U
|
||||
|
||||
#define USB_AUDIO_DESC_SIZ 0x09U
|
||||
#define AUDIO_STANDARD_EP_DESC_SIZE 0x09U
|
||||
#define AUDIO_STREAMING_EP_DESC_SIZE 0x07U
|
||||
|
||||
/* audio interface class code */
|
||||
#define USB_CLASS_AUDIO 0x01U
|
||||
|
||||
/* audio interface subclass codes */
|
||||
#define AUDIO_SUBCLASS_CONTROL 0x01U
|
||||
#define AUDIO_SUBCLASS_AUDIOSTREAMING 0x02U
|
||||
#define AUDIO_SUBCLASS_MIDISTREAMING 0x03U
|
||||
|
||||
/* audio interface protocol codes */
|
||||
#define AUDIO_PROTOCOL_UNDEFINED 0x00U
|
||||
#define AUDIO_STREAMING_GENERAL 0x01U
|
||||
#define AUDIO_STREAMING_FORMAT_TYPE 0x02U
|
||||
|
||||
/* audio class-specific descriptor types */
|
||||
#define AUDIO_DESCTYPE_UNDEFINED 0x20U
|
||||
#define AUDIO_DESCTYPE_DEVICE 0x21U
|
||||
#define AUDIO_DESCTYPE_CONFIGURATION 0x22U
|
||||
#define AUDIO_DESCTYPE_STRING 0x23U
|
||||
#define AUDIO_DESCTYPE_INTERFACE 0x24U
|
||||
#define AUDIO_DESCTYPE_ENDPOINT 0x25U
|
||||
|
||||
/* audio control interface descriptor subtypes */
|
||||
#define AUDIO_CONTROL_HEADER 0x01U
|
||||
#define AUDIO_CONTROL_INPUT_TERMINAL 0x02U
|
||||
#define AUDIO_CONTROL_OUTPUT_TERMINAL 0x03U
|
||||
#define AUDIO_CONTROL_MIXER_UNIT 0x04U
|
||||
#define AUDIO_CONTROL_SELECTOR_UNIT 0x05U
|
||||
#define AUDIO_CONTROL_FEATURE_UNIT 0x06U
|
||||
#define AUDIO_CONTROL_PROCESSING_UNIT 0x07U
|
||||
#define AUDIO_CONTROL_EXTENSION_UNIT 0x08U
|
||||
|
||||
#define AUDIO_INPUT_TERMINAL_DESC_SIZE 0x0CU
|
||||
#define AUDIO_OUTPUT_TERMINAL_DESC_SIZE 0x09U
|
||||
#define AUDIO_STREAMING_INTERFACE_DESC_SIZE 0x07U
|
||||
|
||||
#define AUDIO_CONTROL_MUTE 0x0001U
|
||||
|
||||
#define AUDIO_FORMAT_TYPE_I 0x01U
|
||||
#define AUDIO_FORMAT_TYPE_III 0x03U
|
||||
|
||||
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01U
|
||||
#define AUDIO_ENDPOINT_GENERAL 0x01U
|
||||
|
||||
#define AUDIO_REQ_GET_CUR 0x81U
|
||||
#define AUDIO_REQ_SET_CUR 0x01U
|
||||
|
||||
#define AUDIO_OUT_STREAMING_CTRL 0x02U
|
||||
|
||||
#define PACKET_SIZE(freq) (((freq) * 2U) * 2U / 1000U)
|
||||
|
||||
#define AUDIO_PACKET_SIZE(frq) (uint8_t)(PACKET_SIZE(frq) & 0xFFU), \
|
||||
(uint8_t)((PACKET_SIZE(frq) >> 8U) & 0xFFU)
|
||||
|
||||
#define SAMPLE_FREQ(frq) (uint8_t)(frq), (uint8_t)((frq) >> 8U), \
|
||||
(uint8_t)((frq) >> 16U)
|
||||
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bDescriptorSubtype; /*!< header descriptor subtype */
|
||||
uint16_t bcdADC; /*!< audio device class specification release number in binary-coded decimal */
|
||||
uint16_t wTotalLength; /*!< total number of bytes */
|
||||
uint8_t bInCollection; /*!< the number of the streaming interfaces */
|
||||
uint8_t baInterfaceNr; /*!< interface number of the streaming interfaces */
|
||||
} usb_desc_AC_itf;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bDescriptorSubtype; /*!< AS_GENERAL descriptor subtype */
|
||||
uint8_t bTerminalLink; /*!< the terminal ID */
|
||||
uint8_t bDelay; /*!< delay introduced by the data path */
|
||||
uint16_t wFormatTag; /*!< the audio data format */
|
||||
} usb_desc_AS_itf;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bDescriptorSubtype; /*!< INPUT_TERMINAL descriptor subtype. */
|
||||
uint8_t bTerminalID; /*!< constant uniquely identifying the terminal within the audio function */
|
||||
uint16_t wTerminalType; /*!< constant characterizing the type of terminal */
|
||||
uint8_t bAssocTerminal; /*!< ID of the output terminal */
|
||||
uint8_t bNrChannels; /*!< number of logical output channels */
|
||||
uint16_t wChannelConfig; /*!< describes the spatial location of the logical channels */
|
||||
uint8_t iChannelNames; /*!< index of a string descriptor */
|
||||
uint8_t iTerminal; /*!< index of a string descriptor */
|
||||
} usb_desc_input_terminal;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bDescriptorSubtype; /*!< OUTPUT_TERMINAL descriptor subtype */
|
||||
uint8_t bTerminalID; /*!< constant uniquely identifying the terminal within the audio function */
|
||||
uint16_t wTerminalType; /*!< constant characterizing the type of terminal */
|
||||
uint8_t bAssocTerminal; /*!< constant, identifying the input terminal to which this output terminal is associated */
|
||||
uint8_t bSourceID; /*!< ID of the unit or terminal */
|
||||
uint8_t iTerminal; /*!< index of a string descriptor */
|
||||
} usb_desc_output_terminal;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bDescriptorSubtype; /*!< FEATURE_UNIT descriptor subtype */
|
||||
uint8_t bUnitID; /*!< constant uniquely identifying the unit within the audio function */
|
||||
uint8_t bSourceID; /*!< ID of the unit or terminal */
|
||||
uint8_t bControlSize; /*!< size in bytes of an element of the bmaControls() array */
|
||||
uint8_t bmaControls0; /*!< a bit set to 1 indicates that the mentioned control is supported for master channel 0 */
|
||||
uint8_t bmaControls1; /*!< a bit set to 1 indicates that the mentioned control is supported for logical channel 1 */
|
||||
uint8_t iFeature; /*!< index of a string descriptor */
|
||||
} usb_desc_mono_feature_unit;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bDescriptorSubtype; /*!< FEATURE_UNIT descriptor subtype */
|
||||
uint8_t bUnitID; /*!< constant uniquely identifying the unit within the audio function */
|
||||
uint8_t bSourceID; /*!< ID of the unit or terminal */
|
||||
uint8_t bControlSize; /*!< size in bytes of an element of the bmaControls() array */
|
||||
uint16_t bmaControls0; /*!< a bit set to 1 indicates that the mentioned control is supported for master channel 0 */
|
||||
uint16_t bmaControls1; /*!< a bit set to 1 indicates that the mentioned control is supported for logical channel 1 */
|
||||
uint16_t bmaControls2; /*!< a bit set to 1 indicates that the mentioned control is supported for logical channel 2 */
|
||||
uint8_t iFeature; /*!< index of a string descriptor */
|
||||
} usb_desc_stereo_feature_unit;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bDescriptorSubtype; /*!< FORMAT_TYPE descriptor subtype */
|
||||
uint8_t bFormatType; /*!< constant identifying the format type */
|
||||
uint8_t bNrChannels; /*!< indicates the number of physical channels in the audio data stream */
|
||||
uint8_t bSubFrameSize; /*!< the number of bytes occupied by one audio sub frame */
|
||||
uint8_t bBitResolution; /*!< the number of effectively used bits from the available bits in an audio sub frame */
|
||||
uint8_t bSamFreqType; /*!< indicates how the sampling frequency can be programmed */
|
||||
uint8_t bSamFreq[3]; /*!< sampling frequency ns in Hz for this isochronous data endpoint */
|
||||
} usb_desc_format_type;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bEndpointAddress; /*!< the address of the endpoint */
|
||||
uint8_t bmAttributes; /*!< transfer type and synchronization type */
|
||||
uint16_t wMaxPacketSize; /*!< maximum packet size this endpoint is capable of sending or receiving */
|
||||
uint8_t bInterval; /*!< left to the designer's discretion */
|
||||
uint8_t bRefresh; /*!< reset to 0 */
|
||||
uint8_t bSynchAddress; /*!< reset to 0 */
|
||||
} usb_desc_std_ep;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bDescriptorSubtype; /*!< EP_GENERAL descriptor subtype */
|
||||
uint8_t bmAttributes; /*!< transfer type and synchronization type */
|
||||
uint8_t bLockDelayUnits; /*!< indicates the units used for the wLockDelay field */
|
||||
uint16_t wLockDelay; /*!< indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry */
|
||||
} usb_desc_AS_ep;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
/* USB configuration descriptor structure */
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_config config;
|
||||
usb_desc_itf std_itf;
|
||||
usb_desc_AC_itf ac_itf;
|
||||
usb_desc_input_terminal in_terminal;
|
||||
usb_desc_mono_feature_unit feature_unit;
|
||||
usb_desc_output_terminal out_terminal;
|
||||
usb_desc_itf std_as_itf_zeroband;
|
||||
usb_desc_itf std_as_itf_opera;
|
||||
usb_desc_AS_itf as_itf;
|
||||
usb_desc_format_type format_typeI;
|
||||
usb_desc_std_ep std_endpoint;
|
||||
usb_desc_AS_ep as_endpoint;
|
||||
} usb_desc_config_set;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* main buffer for audio data out transfers and its relative pointers */
|
||||
uint8_t isoc_out_buff[TOTAL_OUT_BUF_SIZE * 2U];
|
||||
uint8_t* isoc_out_wrptr;
|
||||
uint8_t* isoc_out_rdptr;
|
||||
|
||||
/* main buffer for audio control requests transfers and its relative variables */
|
||||
uint8_t audioctl[64];
|
||||
uint8_t audioctl_unit;
|
||||
uint32_t audioctl_len;
|
||||
|
||||
uint32_t play_flag;
|
||||
} usbd_audio_handler;
|
||||
|
||||
extern usb_desc audio_desc;
|
||||
extern usb_class audio_class;
|
||||
|
||||
#endif /* __AUDIO_CORE_H */
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*!
|
||||
\file audio_out_itf.h
|
||||
\brief audio OUT (playback) interface header file
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_OUT_ITF_H
|
||||
#define __AUDIO_OUT_ITF_H
|
||||
|
||||
#include "usbd_conf.h"
|
||||
|
||||
/* audio commands enumeration */
|
||||
typedef enum
|
||||
{
|
||||
AUDIO_CMD_PLAY = 1U,
|
||||
AUDIO_CMD_PAUSE,
|
||||
AUDIO_CMD_STOP,
|
||||
}audio_cmd_enum;
|
||||
|
||||
/* mute commands */
|
||||
#define AUDIO_MUTE 0x01U
|
||||
#define AUDIO_UNMUTE 0x00U
|
||||
|
||||
/* functions return value */
|
||||
#define AUDIO_OK 0x00U
|
||||
#define AUDIO_FAIL 0xFFU
|
||||
|
||||
/* audio machine states */
|
||||
#define AUDIO_STATE_INACTIVE 0x00U
|
||||
#define AUDIO_STATE_ACTIVE 0x01U
|
||||
#define AUDIO_STATE_PLAYING 0x02U
|
||||
#define AUDIO_STATE_PAUSED 0x03U
|
||||
#define AUDIO_STATE_STOPPED 0x04U
|
||||
#define AUDIO_STATE_ERROR 0x05U
|
||||
|
||||
typedef struct {
|
||||
uint8_t (*audio_init) (uint32_t audio_freq, uint32_t volume, uint32_t options);
|
||||
uint8_t (*audio_deinit) (uint32_t options);
|
||||
uint8_t (*audio_cmd) (uint8_t* pbuf, uint32_t size, uint8_t cmd);
|
||||
uint8_t (*audio_volume_ctl) (uint8_t vol);
|
||||
uint8_t (*audio_mute_ctl) (uint8_t cmd);
|
||||
uint8_t (*audio_periodic_tc) (uint8_t cmd);
|
||||
uint8_t (*audio_state_get) (void);
|
||||
} audio_fops_struct;
|
||||
|
||||
extern audio_fops_struct audio_out_fops;
|
||||
|
||||
#endif /* __AUDIO_OUT_ITF_H */
|
||||
+549
@@ -0,0 +1,549 @@
|
||||
/*!
|
||||
\file audio_core.c
|
||||
\brief USB audio device class core functions
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_transc.h"
|
||||
#include "audio_out_itf.h"
|
||||
#include "audio_core.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define USBD_VID 0x28E9U
|
||||
#define USBD_PID 0x9574U
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint8_t usbd_audio_sof (usb_dev *udev);
|
||||
static uint8_t audio_init (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t audio_deinit (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t audio_req_handler (usb_dev *udev, usb_req *req);
|
||||
static uint8_t audio_ctlx_out (usb_dev *udev);
|
||||
static void audio_data_out (usb_dev *udev, uint8_t ep_num);
|
||||
|
||||
usb_class audio_class = {
|
||||
.init = audio_init,
|
||||
.deinit = audio_deinit,
|
||||
.req_process = audio_req_handler,
|
||||
.ctlx_out = audio_ctlx_out,
|
||||
.data_out = audio_data_out
|
||||
};
|
||||
|
||||
usbd_int_cb_struct usb_inthandler =
|
||||
{
|
||||
usbd_audio_sof,
|
||||
};
|
||||
|
||||
/* note:it should use the c99 standard when compiling the below codes */
|
||||
/* USB standard device descriptor */
|
||||
usb_desc_dev audio_dev_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_DEV_DESC_LEN,
|
||||
.bDescriptorType = USB_DESCTYPE_DEV
|
||||
},
|
||||
.bcdUSB = 0x0200U,
|
||||
.bDeviceClass = 0x00U,
|
||||
.bDeviceSubClass = 0x00U,
|
||||
.bDeviceProtocol = 0x00U,
|
||||
.bMaxPacketSize0 = USBD_EP0_MAX_SIZE,
|
||||
.idVendor = USBD_VID,
|
||||
.idProduct = USBD_PID,
|
||||
.bcdDevice = 0x0100U,
|
||||
.iManufacturer = STR_IDX_MFC,
|
||||
.iProduct = STR_IDX_PRODUCT,
|
||||
.iSerialNumber = STR_IDX_SERIAL,
|
||||
.bNumberConfigurations = USBD_CFG_MAX_NUM
|
||||
};
|
||||
|
||||
/* USB device configuration descriptor */
|
||||
usb_desc_config_set audio_config_set =
|
||||
{
|
||||
.config =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_config),
|
||||
.bDescriptorType = USB_DESCTYPE_CONFIG
|
||||
},
|
||||
.wTotalLength = AUDIO_CONFIG_DESC_SET_LEN,
|
||||
.bNumInterfaces = 0x02U,
|
||||
.bConfigurationValue = 0x01U,
|
||||
.iConfiguration = 0x00U,
|
||||
.bmAttributes = 0xC0U,
|
||||
.bMaxPower = 0x32U
|
||||
},
|
||||
|
||||
.std_itf =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_itf),
|
||||
.bDescriptorType = USB_DESCTYPE_ITF
|
||||
},
|
||||
.bInterfaceNumber = 0x00U,
|
||||
.bAlternateSetting = 0x00U,
|
||||
.bNumEndpoints = 0x00U,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = AUDIO_SUBCLASS_CONTROL,
|
||||
.bInterfaceProtocol = AUDIO_PROTOCOL_UNDEFINED,
|
||||
.iInterface = 0x00U
|
||||
},
|
||||
|
||||
.ac_itf =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_AC_itf),
|
||||
.bDescriptorType = AUDIO_DESCTYPE_INTERFACE
|
||||
},
|
||||
.bDescriptorSubtype = 0x01U,
|
||||
.bcdADC = 0x0100U,
|
||||
.wTotalLength = 0x0027U,
|
||||
.bInCollection = 0x01U,
|
||||
.baInterfaceNr = 0x01U
|
||||
},
|
||||
|
||||
.in_terminal =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_input_terminal),
|
||||
.bDescriptorType = AUDIO_DESCTYPE_INTERFACE
|
||||
},
|
||||
.bDescriptorSubtype = 0x02U,
|
||||
.bTerminalID = 0x01U,
|
||||
.wTerminalType = 0x0101U,
|
||||
.bAssocTerminal = 0x00U,
|
||||
.bNrChannels = 0x01U,
|
||||
.wChannelConfig = 0x0000U,
|
||||
.iChannelNames = 0x00U,
|
||||
.iTerminal = 0x00U
|
||||
},
|
||||
|
||||
.feature_unit =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_mono_feature_unit),
|
||||
.bDescriptorType = AUDIO_DESCTYPE_INTERFACE
|
||||
},
|
||||
.bDescriptorSubtype = AUDIO_CONTROL_FEATURE_UNIT,
|
||||
.bUnitID = AUDIO_OUT_STREAMING_CTRL,
|
||||
.bSourceID = 0x01U,
|
||||
.bControlSize = 0x01U,
|
||||
.bmaControls0 = AUDIO_CONTROL_MUTE,
|
||||
.bmaControls1 = 0x00U,
|
||||
.iFeature = 0x00U
|
||||
},
|
||||
|
||||
.out_terminal =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_output_terminal),
|
||||
.bDescriptorType = AUDIO_DESCTYPE_INTERFACE
|
||||
},
|
||||
.bDescriptorSubtype = AUDIO_CONTROL_OUTPUT_TERMINAL,
|
||||
.bTerminalID = 0x03U,
|
||||
.wTerminalType = 0x0301U,
|
||||
.bAssocTerminal = 0x00U,
|
||||
.bSourceID = 0x02U,
|
||||
.iTerminal = 0x00U
|
||||
},
|
||||
|
||||
.std_as_itf_zeroband =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_itf),
|
||||
.bDescriptorType = USB_DESCTYPE_ITF
|
||||
},
|
||||
.bInterfaceNumber = 0x01U,
|
||||
.bAlternateSetting = 0x00U,
|
||||
.bNumEndpoints = 0x00U,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = AUDIO_SUBCLASS_AUDIOSTREAMING,
|
||||
.bInterfaceProtocol = AUDIO_PROTOCOL_UNDEFINED,
|
||||
.iInterface = 0x00U
|
||||
},
|
||||
|
||||
.std_as_itf_opera =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_itf),
|
||||
.bDescriptorType = USB_DESCTYPE_ITF
|
||||
},
|
||||
.bInterfaceNumber = 0x01U,
|
||||
.bAlternateSetting = 0x01U,
|
||||
.bNumEndpoints = 0x01U,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = AUDIO_SUBCLASS_AUDIOSTREAMING,
|
||||
.bInterfaceProtocol = AUDIO_PROTOCOL_UNDEFINED,
|
||||
.iInterface = 0x00U
|
||||
},
|
||||
|
||||
.as_itf =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_AS_itf),
|
||||
.bDescriptorType = AUDIO_DESCTYPE_INTERFACE
|
||||
},
|
||||
.bDescriptorSubtype = AUDIO_STREAMING_GENERAL,
|
||||
.bTerminalLink = 0x01U,
|
||||
.bDelay = 0x01U,
|
||||
.wFormatTag = 0x0001U,
|
||||
},
|
||||
|
||||
.format_typeI =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_format_type),
|
||||
.bDescriptorType = AUDIO_DESCTYPE_INTERFACE
|
||||
},
|
||||
.bDescriptorSubtype = AUDIO_STREAMING_FORMAT_TYPE,
|
||||
.bFormatType = AUDIO_FORMAT_TYPE_III,
|
||||
.bNrChannels = 0x02U,
|
||||
.bSubFrameSize = 0x02U,
|
||||
.bBitResolution = 0x10U,
|
||||
.bSamFreqType = 0x01U,
|
||||
.bSamFreq[0] = (uint8_t)USBD_AUDIO_FREQ_16K,
|
||||
.bSamFreq[1] = USBD_AUDIO_FREQ_16K >> 8,
|
||||
.bSamFreq[2] = USBD_AUDIO_FREQ_16K >> 16
|
||||
},
|
||||
|
||||
.std_endpoint =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_std_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP
|
||||
},
|
||||
.bEndpointAddress = AUDIO_OUT_EP,
|
||||
.bmAttributes = USB_ENDPOINT_TYPE_ISOCHRONOUS,
|
||||
.wMaxPacketSize = PACKET_SIZE(USBD_AUDIO_FREQ_16K),
|
||||
.bInterval = 0x01U,
|
||||
.bRefresh = 0x00U,
|
||||
.bSynchAddress = 0x00U
|
||||
},
|
||||
|
||||
.as_endpoint =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_AS_ep),
|
||||
.bDescriptorType = AUDIO_DESCTYPE_ENDPOINT
|
||||
},
|
||||
.bDescriptorSubtype = AUDIO_ENDPOINT_GENERAL,
|
||||
.bmAttributes = 0x00U,
|
||||
.bLockDelayUnits = 0x00U,
|
||||
.wLockDelay = 0x0000U,
|
||||
}
|
||||
};
|
||||
|
||||
/* USB language ID descriptor */
|
||||
static usb_desc_LANGID usbd_language_id_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_LANGID),
|
||||
.bDescriptorType = USB_DESCTYPE_STR
|
||||
},
|
||||
|
||||
.wLANGID = ENG_LANGID
|
||||
};
|
||||
|
||||
/* USB manufacture string */
|
||||
static usb_desc_str manufacturer_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(10U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
|
||||
};
|
||||
|
||||
/* USB product string */
|
||||
static usb_desc_str product_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(14U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'A', 'u', 'd', 'i', 'o'}
|
||||
};
|
||||
|
||||
/* USBD serial string */
|
||||
static usb_desc_str serial_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(12U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
}
|
||||
};
|
||||
|
||||
/* USB string descriptor */
|
||||
static uint8_t* usbd_audio_strings[] =
|
||||
{
|
||||
[STR_IDX_LANGID] = (uint8_t *)&usbd_language_id_desc,
|
||||
[STR_IDX_MFC] = (uint8_t *)&manufacturer_string,
|
||||
[STR_IDX_PRODUCT] = (uint8_t *)&product_string,
|
||||
[STR_IDX_SERIAL] = (uint8_t *)&serial_string
|
||||
};
|
||||
|
||||
usb_desc audio_desc = {
|
||||
.dev_desc = (uint8_t *)&audio_dev_desc,
|
||||
.config_desc = (uint8_t *)&audio_config_set,
|
||||
.strings = usbd_audio_strings
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief initialize the audio device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t audio_init (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
usb_desc_std_ep std_ep = audio_config_set.std_endpoint;
|
||||
|
||||
static usbd_audio_handler audio_handler;
|
||||
|
||||
memset((void *)&audio_handler, 0, sizeof(usbd_audio_handler));
|
||||
|
||||
usb_desc_ep ep = {
|
||||
.header = std_ep.header,
|
||||
.bEndpointAddress = std_ep.bEndpointAddress,
|
||||
.bmAttributes = std_ep.bmAttributes,
|
||||
.wMaxPacketSize = std_ep.wMaxPacketSize,
|
||||
.bInterval = std_ep.bInterval
|
||||
};
|
||||
|
||||
/* initialize RX endpoint */
|
||||
usbd_ep_init(udev, EP_BUF_DBL, AUDIO_BUF_ADDR, &ep);
|
||||
|
||||
usbd_int_fops = &usb_inthandler;
|
||||
|
||||
audio_handler.isoc_out_rdptr = audio_handler.isoc_out_buff;
|
||||
audio_handler.isoc_out_wrptr = audio_handler.isoc_out_buff;
|
||||
|
||||
/* initialize the audio output hardware layer */
|
||||
if (USBD_OK != audio_out_fops.audio_init(USBD_AUDIO_FREQ_16K, DEFAULT_VOLUME, 0U)) {
|
||||
return USBD_FAIL;
|
||||
}
|
||||
|
||||
udev->ep_transc[AUDIO_OUT_EP][TRANSC_OUT] = audio_class.data_out;
|
||||
|
||||
/* prepare out endpoint to receive audio data */
|
||||
usbd_ep_recev (udev, AUDIO_OUT_EP, (uint8_t*)audio_handler.isoc_out_buff, (uint16_t)AUDIO_OUT_PACKET);
|
||||
|
||||
udev->class_data[USBD_AUDIO_INTERFACE] = (void *)&audio_handler;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief de-initialize the audio device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t audio_deinit (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
/* deinitialize audio endpoints */
|
||||
usbd_ep_deinit(udev, AUDIO_OUT_EP);
|
||||
|
||||
/* deinitialize the audio output hardware layer */
|
||||
if (USBD_OK != audio_out_fops.audio_deinit(0U)) {
|
||||
return USBD_FAIL;
|
||||
}
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the audio class-specific requests
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: device class-specific request
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t audio_req_handler (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
uint8_t status = REQ_NOTSUPP;
|
||||
|
||||
usbd_audio_handler *audio = (usbd_audio_handler *)udev->class_data[USBD_AUDIO_INTERFACE];
|
||||
|
||||
switch (req->bRequest) {
|
||||
case AUDIO_REQ_GET_CUR:
|
||||
usb_transc_config(&udev->transc_in[0], audio->audioctl, req->wLength, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case AUDIO_REQ_SET_CUR:
|
||||
if (req->wLength) {
|
||||
usb_transc_config(&udev->transc_out[0], audio->audioctl, req->wLength, 0U);
|
||||
|
||||
udev->class_core->req_cmd = AUDIO_REQ_SET_CUR;
|
||||
|
||||
audio->audioctl_len = req->wLength;
|
||||
audio->audioctl_unit = BYTE_HIGH(req->wIndex);
|
||||
|
||||
status = REQ_SUPP;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handles the audio out data stage
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static void audio_data_out (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
usbd_audio_handler *audio = (usbd_audio_handler *)udev->class_data[USBD_AUDIO_INTERFACE];
|
||||
|
||||
if (AUDIO_OUT_EP == ep_num) {
|
||||
/* increment the Buffer pointer or roll it back when all buffers are full */
|
||||
if (audio->isoc_out_wrptr >= (audio->isoc_out_buff + (AUDIO_OUT_PACKET * OUT_PACKET_NUM))) {
|
||||
/* all buffers are full: roll back */
|
||||
audio->isoc_out_wrptr = audio->isoc_out_buff;
|
||||
} else {
|
||||
/* increment the buffer pointer */
|
||||
audio->isoc_out_wrptr += AUDIO_OUT_PACKET;
|
||||
}
|
||||
|
||||
/* prepare out endpoint to receive next audio packet */
|
||||
usbd_ep_recev (udev, AUDIO_OUT_EP, (uint8_t*)(audio->isoc_out_wrptr), (uint16_t)AUDIO_OUT_PACKET);
|
||||
|
||||
/* trigger the start of streaming only when half buffer is full */
|
||||
if ((0U == audio->play_flag) && (audio->isoc_out_wrptr >= (audio->isoc_out_buff + ((AUDIO_OUT_PACKET * OUT_PACKET_NUM) / 2U)))) {
|
||||
/* enable start of streaming */
|
||||
audio->play_flag = 1U;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handles audio control request data
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t audio_ctlx_out (usb_dev *udev)
|
||||
{
|
||||
usbd_audio_handler *audio = (usbd_audio_handler *)udev->class_data[USBD_AUDIO_INTERFACE];
|
||||
|
||||
/* check if an audio_control request has been issued */
|
||||
if (AUDIO_REQ_SET_CUR == udev->class_core->req_cmd) {
|
||||
/* in this driver, to simplify code, only SET_CUR request is managed */
|
||||
|
||||
/* check for which addressed unit the audio_control request has been issued */
|
||||
if (AUDIO_OUT_STREAMING_CTRL == audio->audioctl_unit) {
|
||||
/* in this driver, to simplify code, only one unit is manage */
|
||||
|
||||
/* call the audio interface mute function */
|
||||
audio_out_fops.audio_mute_ctl(audio->audioctl[0]);
|
||||
|
||||
/* reset the audioctl_cmd variable to prevent re-entering this function */
|
||||
udev->class_core->req_cmd = 0U;
|
||||
|
||||
audio->audioctl_len = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handles the SOF event (data buffer update and synchronization)
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t usbd_audio_sof (usb_dev *udev)
|
||||
{
|
||||
usbd_audio_handler *audio = (usbd_audio_handler *)udev->class_data[USBD_AUDIO_INTERFACE];
|
||||
|
||||
/* check if there are available data in stream buffer.
|
||||
in this function, a single variable (play_flag) is used to avoid software delays.
|
||||
the play operation must be executed as soon as possible after the SOF detection. */
|
||||
if (audio->play_flag) {
|
||||
/* start playing received packet */
|
||||
audio_out_fops.audio_cmd((uint8_t*)(audio->isoc_out_rdptr), /* samples buffer pointer */
|
||||
AUDIO_OUT_PACKET, /* number of samples in Bytes */
|
||||
AUDIO_CMD_PLAY); /* command to be processed */
|
||||
|
||||
/* increment the Buffer pointer or roll it back when all buffers all full */
|
||||
if (audio->isoc_out_rdptr >= (audio->isoc_out_buff + (AUDIO_OUT_PACKET * OUT_PACKET_NUM))) {
|
||||
/* roll back to the start of buffer */
|
||||
audio->isoc_out_rdptr = audio->isoc_out_buff;
|
||||
} else {
|
||||
/* increment to the next sub-buffer */
|
||||
audio->isoc_out_rdptr += AUDIO_OUT_PACKET;
|
||||
}
|
||||
|
||||
/* if all available buffers have been consumed, stop playing */
|
||||
if (audio->isoc_out_rdptr == audio->isoc_out_wrptr) {
|
||||
/* pause the audio stream */
|
||||
audio_out_fops.audio_cmd((uint8_t*)(audio->isoc_out_buff), /* samples buffer pointer */
|
||||
AUDIO_OUT_PACKET, /* number of samples in Bytes */
|
||||
AUDIO_CMD_PAUSE); /* command to be processed */
|
||||
|
||||
/* stop entering play loop */
|
||||
audio->play_flag = 0U;
|
||||
|
||||
/* reset buffer pointers */
|
||||
audio->isoc_out_rdptr = audio->isoc_out_buff;
|
||||
audio->isoc_out_wrptr = audio->isoc_out_buff;
|
||||
}
|
||||
}
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
/*!
|
||||
\file audio_out_itf.c
|
||||
\brief audio OUT (playback) interface functions
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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 "audio_core.h"
|
||||
#include "audio_out_itf.h"
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint8_t init (uint32_t audio_freq, uint32_t volume, uint32_t options);
|
||||
static uint8_t deinit (uint32_t options);
|
||||
static uint8_t audio_cmd (uint8_t* pbuf, uint32_t size, uint8_t cmd);
|
||||
static uint8_t volume_ctl (uint8_t vol);
|
||||
static uint8_t mute_ctl (uint8_t cmd);
|
||||
static uint8_t periodic_tc (uint8_t cmd);
|
||||
static uint8_t get_state (void);
|
||||
|
||||
audio_fops_struct audio_out_fops =
|
||||
{
|
||||
init,
|
||||
deinit,
|
||||
audio_cmd,
|
||||
volume_ctl,
|
||||
mute_ctl,
|
||||
periodic_tc,
|
||||
get_state
|
||||
};
|
||||
|
||||
static uint8_t audio_state = AUDIO_STATE_INACTIVE;
|
||||
|
||||
/*!
|
||||
\brief initialize and configures all required resources for audio play function
|
||||
\param[in] audio_freq: statrt_up audio frequency
|
||||
\param[in] volume: start_up volume to be set
|
||||
\param[in] options: specific options passed to low layer function
|
||||
\param[out] none
|
||||
\retval AUDIO_OK if all operations succeed, otherwise, AUDIO_FAIL.
|
||||
*/
|
||||
static uint8_t init (uint32_t audio_freq, uint32_t volume, uint32_t options)
|
||||
{
|
||||
static uint32_t initialized = 0U;
|
||||
|
||||
/* check if the low layer has already been initialized */
|
||||
if (0U == initialized) {
|
||||
/* call low layer function */
|
||||
if (0U != eval_audio_init(OUTPUT_DEVICE_AUTO, volume, audio_freq)) {
|
||||
audio_state = AUDIO_STATE_ERROR;
|
||||
|
||||
return AUDIO_FAIL;
|
||||
}
|
||||
|
||||
/* set the initialization flag to prevent reinitializing the interface again */
|
||||
initialized = 1U;
|
||||
}
|
||||
|
||||
/* update the audio state machine */
|
||||
audio_state = AUDIO_STATE_ACTIVE;
|
||||
|
||||
return AUDIO_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief free all resources used by low layer and stops audio-play function
|
||||
\param[in] options: specific options passed to low layer function
|
||||
\param[out] none
|
||||
\retval AUDIO_OK if all operations succeed, otherwise, AUDIO_FAIL.
|
||||
*/
|
||||
static uint8_t deinit (uint32_t options)
|
||||
{
|
||||
/* update the audio state machine */
|
||||
audio_state = AUDIO_STATE_INACTIVE;
|
||||
|
||||
return AUDIO_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief play, stop, pause or resume current file
|
||||
\param[in] pbuf: address from which file should be played
|
||||
\param[in] size: size of the current buffer/file
|
||||
\param[in] cmd: command to be executed, can be:
|
||||
\arg AUDIO_CMD_PLAY
|
||||
\arg AUDIO_CMD_PAUSE
|
||||
\arg AUDIO_CMD_RESUME
|
||||
\arg AUDIO_CMD_STOP
|
||||
\param[out] none
|
||||
\retval AUDIO_OK if all operations succeed, otherwise, AUDIO_FAIL.
|
||||
*/
|
||||
static uint8_t audio_cmd (uint8_t* pbuf, uint32_t size, uint8_t cmd)
|
||||
{
|
||||
uint8_t status = AUDIO_OK;
|
||||
|
||||
/* check the current state */
|
||||
if ((AUDIO_STATE_INACTIVE == audio_state) || (AUDIO_STATE_ERROR == audio_state)) {
|
||||
audio_state = AUDIO_STATE_ERROR;
|
||||
|
||||
return AUDIO_FAIL;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
/* process the play command */
|
||||
case AUDIO_CMD_PLAY:
|
||||
/* if current state is active or stopped */
|
||||
if ((AUDIO_STATE_ACTIVE == audio_state) || \
|
||||
(AUDIO_STATE_STOPPED == audio_state) || \
|
||||
(AUDIO_STATE_PLAYING == audio_state)) {
|
||||
audio_mal_play((uint32_t)pbuf, (size / 2U));
|
||||
audio_state = AUDIO_STATE_PLAYING;
|
||||
} else if (AUDIO_STATE_PAUSED == audio_state) {
|
||||
if (eval_audio_pause_resume(AUDIO_RESUME, (uint32_t)pbuf, (size / 2U))) {
|
||||
audio_state = AUDIO_STATE_ERROR;
|
||||
|
||||
status = AUDIO_FAIL;
|
||||
} else {
|
||||
audio_state = AUDIO_STATE_PLAYING;
|
||||
}
|
||||
} else {
|
||||
status = AUDIO_FAIL;
|
||||
}
|
||||
break;
|
||||
|
||||
/* process the stop command */
|
||||
case AUDIO_CMD_STOP:
|
||||
if (AUDIO_STATE_PLAYING != audio_state) {
|
||||
/* unsupported command */
|
||||
status = AUDIO_FAIL;
|
||||
} else if (eval_audio_stop(CODEC_PDWN_SW)) {
|
||||
audio_state = AUDIO_STATE_ERROR;
|
||||
|
||||
status = AUDIO_FAIL;
|
||||
} else {
|
||||
audio_state = AUDIO_STATE_STOPPED;
|
||||
}
|
||||
break;
|
||||
|
||||
/* process the pause command */
|
||||
case AUDIO_CMD_PAUSE:
|
||||
if (AUDIO_STATE_PLAYING != audio_state) {
|
||||
/* unsupported command */
|
||||
status = AUDIO_FAIL;
|
||||
} else if (eval_audio_pause_resume(AUDIO_PAUSE, (uint32_t)pbuf, (size / 2U))) {
|
||||
audio_state = AUDIO_STATE_ERROR;
|
||||
|
||||
status = AUDIO_FAIL;
|
||||
} else {
|
||||
audio_state = AUDIO_STATE_PAUSED;
|
||||
}
|
||||
break;
|
||||
|
||||
/* unsupported command */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the volume level
|
||||
\param[in] vol: volume level to be set in % (from 0% to 100%)
|
||||
\param[out] none
|
||||
\retval AUDIO_OK if all operations succeed, otherwise, AUDIO_FAIL.
|
||||
*/
|
||||
static uint8_t volume_ctl (uint8_t vol)
|
||||
{
|
||||
/* call low layer volume setting function */
|
||||
if (eval_audio_volume_ctl(vol)) {
|
||||
audio_state = AUDIO_STATE_ERROR;
|
||||
|
||||
return AUDIO_FAIL;
|
||||
}
|
||||
|
||||
return AUDIO_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief mute or unmute the audio current output
|
||||
\param[in] cmd: can be 0 to unmute, or 1 to mute
|
||||
\param[out] none
|
||||
\retval AUDIO_OK if all operations succeed, otherwise, AUDIO_FAIL.
|
||||
*/
|
||||
static uint8_t mute_ctl (uint8_t cmd)
|
||||
{
|
||||
/* call low layer mute setting function */
|
||||
if (eval_audio_mute((uint32_t)cmd)) {
|
||||
audio_state = AUDIO_STATE_ERROR;
|
||||
|
||||
return AUDIO_FAIL;
|
||||
}
|
||||
|
||||
return AUDIO_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief periodic transfer control
|
||||
\param[in] cmd: command
|
||||
\param[out] none
|
||||
\retval AUDIO_OK if all operations succeed, otherwise, AUDIO_FAIL.
|
||||
*/
|
||||
static uint8_t periodic_tc (uint8_t cmd)
|
||||
{
|
||||
return AUDIO_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief return the current state of the audio machine
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval AUDIO_OK if all operations succeed, otherwise, AUDIO_FAIL.
|
||||
*/
|
||||
static uint8_t get_state (void)
|
||||
{
|
||||
return audio_state;
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/*!
|
||||
\file cdc_acm_core.h
|
||||
\brief the header file of CDC ACM driver
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __CDC_ACM_CORE_H
|
||||
#define __CDC_ACM_CORE_H
|
||||
|
||||
#include "usbd_enum.h"
|
||||
|
||||
/* communications device class code */
|
||||
#define USB_CLASS_CDC 0x02U
|
||||
|
||||
/* CDC subclass code */
|
||||
#define USB_CDC_SUBCLASS_DLCM 0x01U
|
||||
#define USB_CDC_SUBCLASS_ACM 0x02U
|
||||
|
||||
/* communications interface class control protocol codes */
|
||||
#define USB_CDC_PROTOCOL_NONE 0x00U
|
||||
#define USB_CDC_PROTOCOL_AT 0x01U
|
||||
|
||||
/* data interface class code */
|
||||
#define USB_CLASS_DATA 0x0AU
|
||||
|
||||
#define USB_DESCTYPE_CDC_ACM 0x21U
|
||||
#define USB_DESCTYPE_CS_INTERFACE 0x24U
|
||||
|
||||
#define USB_CDC_ACM_CONFIG_DESC_SIZE 0x43U
|
||||
|
||||
/* class-specific notification codes for PSTN subclasses */
|
||||
#define USB_CDC_NOTIFY_SERIAL_STATE 0x20U
|
||||
|
||||
/* class-specific request codes */
|
||||
#define SEND_ENCAPSULATED_COMMAND 0x00U
|
||||
#define GET_ENCAPSULATED_RESPONSE 0x01U
|
||||
#define SET_COMM_FEATURE 0x02U
|
||||
#define GET_COMM_FEATURE 0x03U
|
||||
#define CLEAR_COMM_FEATURE 0x04U
|
||||
#define SET_LINE_CODING 0x20U
|
||||
#define GET_LINE_CODING 0x21U
|
||||
#define SET_CONTROL_LINE_STATE 0x22U
|
||||
#define SEND_BREAK 0x23U
|
||||
#define NO_CMD 0xFFU
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/* CDC ACM line coding structure */
|
||||
typedef struct {
|
||||
uint32_t dwDTERate; /*!< data terminal rate */
|
||||
uint8_t bCharFormat; /*!< stop bits */
|
||||
uint8_t bParityType; /*!< parity */
|
||||
uint8_t bDataBits; /*!< data bits */
|
||||
} acm_line;
|
||||
|
||||
/* notification structure */
|
||||
typedef struct {
|
||||
uint8_t bmRequestType; /*!< type of request */
|
||||
uint8_t bNotification; /*!< communication interface class notifications */
|
||||
uint16_t wValue; /*!< value of notification */
|
||||
uint16_t wIndex; /*!< index of interface */
|
||||
uint16_t wLength; /*!< length of notification data */
|
||||
} acm_notification;
|
||||
|
||||
/* header function structure */
|
||||
typedef struct {
|
||||
usb_desc_header header; /*!< descriptor header, including type and size. */
|
||||
uint8_t bDescriptorSubtype; /*!< bDescriptorSubtype: header function descriptor */
|
||||
uint16_t bcdCDC; /*!< bcdCDC: low byte of spec release number (CDC1.10) */
|
||||
} usb_desc_header_func;
|
||||
|
||||
/* call management function structure */
|
||||
typedef struct {
|
||||
usb_desc_header header; /*!< descriptor header, including type and size. */
|
||||
uint8_t bDescriptorSubtype; /*!< bDescriptorSubtype: call management function descriptor */
|
||||
uint8_t bmCapabilities; /*!< bmCapabilities: D0 is reset, D1 is ignored */
|
||||
uint8_t bDataInterface; /*!< bDataInterface: 1 interface used for call management */
|
||||
} usb_desc_call_managment_func;
|
||||
|
||||
/* ACM function structure */
|
||||
typedef struct {
|
||||
usb_desc_header header; /*!< descriptor header, including type and size. */
|
||||
uint8_t bDescriptorSubtype; /*!< bDescriptorSubtype: abstract control management descriptor */
|
||||
uint8_t bmCapabilities; /*!< bmCapabilities: D1 */
|
||||
} usb_desc_acm_func;
|
||||
|
||||
/* union function structure */
|
||||
typedef struct {
|
||||
usb_desc_header header; /*!< descriptor header, including type and size. */
|
||||
uint8_t bDescriptorSubtype; /*!< bDescriptorSubtype: union function descriptor */
|
||||
uint8_t bMasterInterface; /*!< bMasterInterface: communication class interface */
|
||||
uint8_t bSlaveInterface0; /*!< bSlaveInterface0: data class interface */
|
||||
} usb_desc_union_func;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
/* configuration descriptor structure */
|
||||
typedef struct {
|
||||
usb_desc_config config;
|
||||
usb_desc_itf cmd_itf;
|
||||
usb_desc_header_func cdc_header;
|
||||
usb_desc_call_managment_func cdc_call_managment;
|
||||
usb_desc_acm_func cdc_acm;
|
||||
usb_desc_union_func cdc_union;
|
||||
usb_desc_ep cdc_cmd_endpoint;
|
||||
usb_desc_itf cdc_data_interface;
|
||||
usb_desc_ep cdc_out_endpoint;
|
||||
usb_desc_ep cdc_in_endpoint;
|
||||
} usb_cdc_desc_config_set;
|
||||
|
||||
#define USB_CDC_RX_LEN 64U
|
||||
|
||||
typedef struct {
|
||||
uint8_t pre_packet_send;
|
||||
uint8_t packet_sent;
|
||||
uint8_t packet_receive;
|
||||
|
||||
uint8_t data[USB_CDC_RX_LEN];
|
||||
|
||||
uint32_t receive_length;
|
||||
|
||||
acm_line line_coding;
|
||||
} usb_cdc_handler;
|
||||
|
||||
extern usb_desc cdc_desc;
|
||||
extern usb_class cdc_class;
|
||||
|
||||
/* function declarations */
|
||||
/* receive CDC ACM data */
|
||||
void cdc_acm_data_receive(usb_dev *udev);
|
||||
/* send CDC ACM data */
|
||||
void cdc_acm_data_send(usb_dev *udev);
|
||||
/* check CDC ACM is ready for data transfer */
|
||||
uint8_t cdc_acm_check_ready(usb_dev *udev);
|
||||
|
||||
#endif /* __CDC_ACM_CORE_H */
|
||||
+509
@@ -0,0 +1,509 @@
|
||||
/*!
|
||||
\file cdc_acm_core.c
|
||||
\brief CDC ACM driver
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_transc.h"
|
||||
#include "cdc_acm_core.h"
|
||||
|
||||
#define USBD_VID 0x28E9U
|
||||
#define USBD_PID 0x018AU
|
||||
|
||||
/* note:it should use the C99 standard when compiling the below codes */
|
||||
/* USB standard device descriptor */
|
||||
usb_desc_dev cdc_dev_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_DEV_DESC_LEN,
|
||||
.bDescriptorType = USB_DESCTYPE_DEV,
|
||||
},
|
||||
.bcdUSB = 0x0200U,
|
||||
.bDeviceClass = USB_CLASS_CDC,
|
||||
.bDeviceSubClass = 0x00U,
|
||||
.bDeviceProtocol = 0x00U,
|
||||
.bMaxPacketSize0 = USBD_EP0_MAX_SIZE,
|
||||
.idVendor = USBD_VID,
|
||||
.idProduct = USBD_PID,
|
||||
.bcdDevice = 0x0100U,
|
||||
.iManufacturer = STR_IDX_MFC,
|
||||
.iProduct = STR_IDX_PRODUCT,
|
||||
.iSerialNumber = STR_IDX_SERIAL,
|
||||
.bNumberConfigurations = USBD_CFG_MAX_NUM,
|
||||
};
|
||||
|
||||
/* USB device configuration descriptor */
|
||||
usb_cdc_desc_config_set cdc_config_desc =
|
||||
{
|
||||
.config =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_config),
|
||||
.bDescriptorType = USB_DESCTYPE_CONFIG,
|
||||
},
|
||||
.wTotalLength = USB_CDC_ACM_CONFIG_DESC_SIZE,
|
||||
.bNumInterfaces = 0x02U,
|
||||
.bConfigurationValue = 0x01U,
|
||||
.iConfiguration = 0x00U,
|
||||
.bmAttributes = 0x80U,
|
||||
.bMaxPower = 0x32U
|
||||
},
|
||||
|
||||
.cmd_itf =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_itf),
|
||||
.bDescriptorType = USB_DESCTYPE_ITF
|
||||
},
|
||||
.bInterfaceNumber = 0x00U,
|
||||
.bAlternateSetting = 0x00U,
|
||||
.bNumEndpoints = 0x01U,
|
||||
.bInterfaceClass = USB_CLASS_CDC,
|
||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
||||
.bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
|
||||
.iInterface = 0x00U
|
||||
},
|
||||
|
||||
.cdc_header =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_header_func),
|
||||
.bDescriptorType = USB_DESCTYPE_CS_INTERFACE
|
||||
},
|
||||
.bDescriptorSubtype = 0x00U,
|
||||
.bcdCDC = 0x0110U
|
||||
},
|
||||
|
||||
.cdc_call_managment =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_call_managment_func),
|
||||
.bDescriptorType = USB_DESCTYPE_CS_INTERFACE
|
||||
},
|
||||
.bDescriptorSubtype = 0x01U,
|
||||
.bmCapabilities = 0x00U,
|
||||
.bDataInterface = 0x01U
|
||||
},
|
||||
|
||||
.cdc_acm =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_acm_func),
|
||||
.bDescriptorType = USB_DESCTYPE_CS_INTERFACE
|
||||
},
|
||||
.bDescriptorSubtype = 0x02U,
|
||||
.bmCapabilities = 0x02U,
|
||||
},
|
||||
|
||||
.cdc_union =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_union_func),
|
||||
.bDescriptorType = USB_DESCTYPE_CS_INTERFACE
|
||||
},
|
||||
.bDescriptorSubtype = 0x06U,
|
||||
.bMasterInterface = 0x00U,
|
||||
.bSlaveInterface0 = 0x01U,
|
||||
},
|
||||
|
||||
.cdc_cmd_endpoint =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP,
|
||||
},
|
||||
.bEndpointAddress = CDC_CMD_EP,
|
||||
.bmAttributes = USB_EP_ATTR_INT,
|
||||
.wMaxPacketSize = CDC_ACM_CMD_PACKET_SIZE,
|
||||
.bInterval = 0x0AU
|
||||
},
|
||||
|
||||
.cdc_data_interface =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_itf),
|
||||
.bDescriptorType = USB_DESCTYPE_ITF,
|
||||
},
|
||||
.bInterfaceNumber = 0x01U,
|
||||
.bAlternateSetting = 0x00U,
|
||||
.bNumEndpoints = 0x02U,
|
||||
.bInterfaceClass = USB_CLASS_DATA,
|
||||
.bInterfaceSubClass = 0x00U,
|
||||
.bInterfaceProtocol = USB_CDC_PROTOCOL_NONE,
|
||||
.iInterface = 0x00U
|
||||
},
|
||||
|
||||
.cdc_out_endpoint =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP,
|
||||
},
|
||||
.bEndpointAddress = CDC_OUT_EP,
|
||||
.bmAttributes = USB_EP_ATTR_BULK,
|
||||
.wMaxPacketSize = CDC_ACM_DATA_PACKET_SIZE,
|
||||
.bInterval = 0x00U
|
||||
},
|
||||
|
||||
.cdc_in_endpoint =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP
|
||||
},
|
||||
.bEndpointAddress = CDC_IN_EP,
|
||||
.bmAttributes = USB_EP_ATTR_BULK,
|
||||
.wMaxPacketSize = CDC_ACM_DATA_PACKET_SIZE,
|
||||
.bInterval = 0x00U
|
||||
}
|
||||
};
|
||||
|
||||
/* USB language ID descriptor */
|
||||
static usb_desc_LANGID usbd_language_id_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_LANGID),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.wLANGID = ENG_LANGID
|
||||
};
|
||||
|
||||
/* USB manufacture string */
|
||||
static usb_desc_str manufacturer_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(10U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
|
||||
};
|
||||
|
||||
/* USB product string */
|
||||
static usb_desc_str product_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(12U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'D', '3', '2', '-', 'C', 'D', 'C', '_', 'A', 'C', 'M'}
|
||||
};
|
||||
|
||||
/* USBD serial string */
|
||||
static usb_desc_str serial_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(12U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
}
|
||||
};
|
||||
|
||||
/* USB string descriptor set */
|
||||
uint8_t* usbd_cdc_strings[] =
|
||||
{
|
||||
[STR_IDX_LANGID] = (uint8_t *)&usbd_language_id_desc,
|
||||
[STR_IDX_MFC] = (uint8_t *)&manufacturer_string,
|
||||
[STR_IDX_PRODUCT] = (uint8_t *)&product_string,
|
||||
[STR_IDX_SERIAL] = (uint8_t *)&serial_string
|
||||
};
|
||||
|
||||
usb_desc cdc_desc = {
|
||||
.dev_desc = (uint8_t *)&cdc_dev_desc,
|
||||
.config_desc = (uint8_t *)&cdc_config_desc,
|
||||
.strings = usbd_cdc_strings
|
||||
};
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint8_t cdc_acm_init (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t cdc_acm_deinit (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t cdc_acm_req_handler (usb_dev *udev, usb_req *req);
|
||||
static uint8_t cdc_acm_ctlx_out (usb_dev *udev);
|
||||
static void cdc_acm_data_in (usb_dev *udev, uint8_t ep_num);
|
||||
static void cdc_acm_data_out (usb_dev *udev, uint8_t ep_num);
|
||||
|
||||
usb_class cdc_class = {
|
||||
.req_cmd = NO_CMD,
|
||||
|
||||
.init = cdc_acm_init,
|
||||
.deinit = cdc_acm_deinit,
|
||||
.req_process = cdc_acm_req_handler,
|
||||
.ctlx_out = cdc_acm_ctlx_out,
|
||||
.data_in = cdc_acm_data_in,
|
||||
.data_out = cdc_acm_data_out
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief receive CDC ACM data
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
void cdc_acm_data_receive(usb_dev *udev)
|
||||
{
|
||||
usb_cdc_handler *cdc = (usb_cdc_handler *)udev->class_data[CDC_COM_INTERFACE];
|
||||
|
||||
cdc->packet_receive = 0U;
|
||||
cdc->pre_packet_send = 0U;
|
||||
|
||||
usbd_ep_recev(udev, CDC_OUT_EP, (uint8_t*)(cdc->data), USB_CDC_RX_LEN);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief send CDC ACM data
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
void cdc_acm_data_send (usb_dev *udev)
|
||||
{
|
||||
usb_cdc_handler *cdc = (usb_cdc_handler *)udev->class_data[CDC_COM_INTERFACE];
|
||||
uint32_t data_len = cdc->receive_length;
|
||||
|
||||
if ((0U != data_len) && (1U == cdc->packet_sent)) {
|
||||
cdc->packet_sent = 0U;
|
||||
usbd_ep_send(udev, CDC_IN_EP, (uint8_t*)(cdc->data), (uint16_t)data_len);
|
||||
cdc->receive_length = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief check CDC ACM is ready for data transfer
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval 0 if CDC is ready, 5 otherwise
|
||||
*/
|
||||
uint8_t cdc_acm_check_ready(usb_dev *udev)
|
||||
{
|
||||
if (udev->class_data[CDC_COM_INTERFACE] != NULL) {
|
||||
usb_cdc_handler *cdc = (usb_cdc_handler *)udev->class_data[CDC_COM_INTERFACE];
|
||||
|
||||
if ((1U == cdc->packet_receive) && (1U == cdc->pre_packet_send)) {
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
|
||||
return 5U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize the CDC ACM device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t cdc_acm_init (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
static usb_cdc_handler cdc_handler;
|
||||
|
||||
/* initialize the data endpoints */
|
||||
usbd_ep_init(udev, EP_BUF_SNG, BULK_TX_ADDR, &(cdc_config_desc.cdc_in_endpoint));
|
||||
usbd_ep_init(udev, EP_BUF_SNG, BULK_RX_ADDR, &(cdc_config_desc.cdc_out_endpoint));
|
||||
|
||||
/* initialize the command endpoint */
|
||||
usbd_ep_init(udev, EP_BUF_SNG, INT_TX_ADDR, &(cdc_config_desc.cdc_cmd_endpoint));
|
||||
|
||||
udev->ep_transc[EP_ID(CDC_IN_EP)][TRANSC_IN] = cdc_class.data_in;
|
||||
udev->ep_transc[CDC_OUT_EP][TRANSC_OUT] = cdc_class.data_out;
|
||||
|
||||
/* initialize CDC handler structure */
|
||||
cdc_handler.packet_receive = 0U;
|
||||
cdc_handler.packet_sent = 1U;
|
||||
cdc_handler.pre_packet_send = 1U;
|
||||
cdc_handler.receive_length = 0U;
|
||||
|
||||
cdc_handler.line_coding = (acm_line){
|
||||
.dwDTERate = 115200U,
|
||||
.bCharFormat = 0U,
|
||||
.bParityType = 0U,
|
||||
.bDataBits = 0x08U
|
||||
};
|
||||
|
||||
udev->class_data[CDC_COM_INTERFACE] = (void *)&cdc_handler;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief deinitialize the CDC ACM device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t cdc_acm_deinit (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
/* deinitialize the data endpoints */
|
||||
usbd_ep_deinit(udev, CDC_IN_EP);
|
||||
usbd_ep_deinit(udev, CDC_OUT_EP);
|
||||
|
||||
/* deinitialize the command endpoint */
|
||||
usbd_ep_deinit(udev, CDC_CMD_EP);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief command data received on control endpoint
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t cdc_acm_ctlx_out (usb_dev *udev)
|
||||
{
|
||||
usb_cdc_handler *cdc = (usb_cdc_handler *)udev->class_data[CDC_COM_INTERFACE];
|
||||
|
||||
if (NO_CMD != udev->class_core->req_cmd) {
|
||||
cdc->packet_receive = 1U;
|
||||
cdc->pre_packet_send = 1U;
|
||||
|
||||
udev->class_core->req_cmd = NO_CMD;
|
||||
}
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle CDC ACM data in transaction
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static void cdc_acm_data_in (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
usb_transc *transc = &udev->transc_in[ep_num];
|
||||
usb_cdc_handler *cdc = (usb_cdc_handler *)udev->class_data[CDC_COM_INTERFACE];
|
||||
|
||||
if (transc->xfer_count == transc->max_len) {
|
||||
usbd_ep_send(udev, EP_ID(ep_num), NULL, 0U);
|
||||
} else {
|
||||
cdc->packet_sent = 1U;
|
||||
cdc->pre_packet_send = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle CDC ACM data out transaction
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static void cdc_acm_data_out (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
usb_cdc_handler *cdc = (usb_cdc_handler *)udev->class_data[CDC_COM_INTERFACE];
|
||||
|
||||
cdc->packet_receive = 1U;
|
||||
|
||||
cdc->receive_length = udev->transc_out[ep_num].xfer_count;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the CDC ACM class-specific requests
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: device class-specific request
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t cdc_acm_req_handler (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
uint8_t status = REQ_NOTSUPP, noti_buf[10] = {0U};
|
||||
usb_cdc_handler *cdc = (usb_cdc_handler *)udev->class_data[CDC_COM_INTERFACE];
|
||||
|
||||
acm_notification *notif = (void *)noti_buf;
|
||||
|
||||
switch (req->bRequest) {
|
||||
case SEND_ENCAPSULATED_COMMAND:
|
||||
break;
|
||||
|
||||
case GET_ENCAPSULATED_RESPONSE:
|
||||
break;
|
||||
|
||||
case SET_COMM_FEATURE:
|
||||
break;
|
||||
|
||||
case GET_COMM_FEATURE:
|
||||
break;
|
||||
|
||||
case CLEAR_COMM_FEATURE:
|
||||
break;
|
||||
|
||||
case SET_LINE_CODING:
|
||||
/* set the value of the current command to be processed */
|
||||
udev->class_core->req_cmd = req->bRequest;
|
||||
|
||||
usb_transc_config(&udev->transc_out[0U], (uint8_t *)&cdc->line_coding, req->wLength, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case GET_LINE_CODING:
|
||||
usb_transc_config(&udev->transc_in[0U], (uint8_t *)&cdc->line_coding, 7U, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case SET_CONTROL_LINE_STATE:
|
||||
notif->bmRequestType = 0xA1U;
|
||||
notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
|
||||
notif->wIndex = 0U;
|
||||
notif->wValue = 0U;
|
||||
notif->wLength = 2U;
|
||||
noti_buf[8] = (uint8_t)req->wValue & 3U;
|
||||
noti_buf[9] = 0U;
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case SEND_BREAK:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/*!
|
||||
\file dfu_core.h
|
||||
\brief the header file of USB DFU device class core functions
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __DFU_CORE_H
|
||||
#define __DFU_CORE_H
|
||||
|
||||
#include "usbd_enum.h"
|
||||
|
||||
/* DFU class code */
|
||||
#define USB_DFU_CLASS 0xFEU
|
||||
|
||||
/* DFU subclass code */
|
||||
#define USB_DFU_SUBCLASS_UPGRADE 0x01U
|
||||
|
||||
/* DFU protocol code */
|
||||
#define USB_DFU_PROTOCL_RUNTIME 0x01U
|
||||
#define USB_DFU_PROTOCL_DFU 0x02U
|
||||
|
||||
/* manifestation state */
|
||||
#define MANIFEST_COMPLETE 0x00U
|
||||
#define MANIFEST_IN_PROGRESS 0x01U
|
||||
|
||||
/* DFU attributes code */
|
||||
#define USB_DFU_CAN_DOWNLOAD 0x01U
|
||||
#define USB_DFU_CAN_UPLOAD 0x02U
|
||||
#define USB_DFU_MANIFEST_TOLERANT 0x04U
|
||||
#define USB_DFU_WILL_DETACH 0x08U
|
||||
|
||||
/* special commands with download request */
|
||||
#define GET_COMMANDS 0x00U
|
||||
#define SET_ADDRESS_POINTER 0x21U
|
||||
#define ERASE 0x41U
|
||||
|
||||
/* memory operation command */
|
||||
#define CMD_ERASE 0U
|
||||
#define CMD_WRITE 1U
|
||||
|
||||
#define _BYTE1(x) (uint8_t)((x) & 0xFFU) /*!< addressing cycle 1st byte */
|
||||
#define _BYTE2(x) (uint8_t)(((x) & 0xFF00U) >> 8U) /*!< addressing cycle 2nd byte */
|
||||
#define _BYTE3(x) (uint8_t)(((x) & 0xFF0000U) >> 16U) /*!< addressing cycle 3rd byte */
|
||||
|
||||
#define SET_POLLING_TIMEOUT(x) do { \
|
||||
dfu->bwPollTimeout0 = _BYTE1(x);\
|
||||
dfu->bwPollTimeout1 = _BYTE2(x);\
|
||||
dfu->bwPollTimeout2 = _BYTE3(x);\
|
||||
} while(0)
|
||||
|
||||
#define FLASH_ERASE_TIMEOUT 60U
|
||||
#define FLASH_WRITE_TIMEOUT 80U
|
||||
|
||||
/* bit detach capable = bit 3 in bmAttributes field */
|
||||
#define DFU_DETACH_MASK (uint8_t)(0x10U)
|
||||
#define USB_DFU_CONFIG_DESC_SIZE (18U + (9U * USBD_ITF_MAX_NUM))
|
||||
#define DFU_DESC_TYPE 0x21U
|
||||
|
||||
/* DFU device state enumeration */
|
||||
typedef enum {
|
||||
STATE_APP_IDLE = 0x00U,
|
||||
STATE_APP_DETACH,
|
||||
STATE_DFU_IDLE,
|
||||
STATE_DFU_DNLOAD_SYNC,
|
||||
STATE_DFU_DNBUSY,
|
||||
STATE_DFU_DNLOAD_IDLE,
|
||||
STATE_DFU_MANIFEST_SYNC,
|
||||
STATE_DFU_MANIFEST,
|
||||
STATE_DFU_MANIFEST_WAIT_RESET,
|
||||
STATE_DFU_UPLOAD_IDLE,
|
||||
STATE_DFU_ERROR
|
||||
} dfu_state;
|
||||
|
||||
/* DFU device status enumeration */
|
||||
typedef enum {
|
||||
STATUS_OK = 0x00U,
|
||||
STATUS_ERR_TARGET,
|
||||
STATUS_ERR_FILE,
|
||||
STATUS_ERR_WRITE,
|
||||
STATUS_ERR_ERASE,
|
||||
STATUS_ERR_CHECK_ERASED,
|
||||
STATUS_ERR_PROG,
|
||||
STATUS_ERR_VERIFY,
|
||||
STATUS_ERR_ADDRESS,
|
||||
STATUS_ERR_NOTDONE,
|
||||
STATUS_ERR_FIRMWARE,
|
||||
STATUS_ERR_VENDOR,
|
||||
STATUS_ERR_USBR,
|
||||
STATUS_ERR_POR,
|
||||
STATUS_ERR_UNKNOWN,
|
||||
STATUS_ERR_STALLEDPKT
|
||||
} dfu_status;
|
||||
|
||||
/* DFU class-specific requests enumeration */
|
||||
typedef enum {
|
||||
DFU_DETACH = 0U,
|
||||
DFU_DNLOAD,
|
||||
DFU_UPLOAD,
|
||||
DFU_GETSTATUS,
|
||||
DFU_CLRSTATUS,
|
||||
DFU_GETSTATE,
|
||||
DFU_ABORT,
|
||||
DFU_REQ_MAX
|
||||
} dfu_requests;
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/* USB DFU function descriptor structure */
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bmAttributes; /*!< DFU attributes */
|
||||
uint16_t wDetachTimeOut; /*!< time, in milliseconds, that the device will wait after receipt of the DFU_DETACH request. If */
|
||||
uint16_t wTransferSize; /*!< maximum number of bytes that the device can accept per control-write transaction */
|
||||
uint16_t bcdDFUVersion; /*!< numeric expression identifying the version of the DFU specification release. */
|
||||
} usb_desc_dfu_func;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
/* USB configuration descriptor structure */
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_config config;
|
||||
usb_desc_itf dfu_itf;
|
||||
usb_desc_dfu_func dfu_func;
|
||||
} usb_dfu_desc_config_set;
|
||||
|
||||
/* USB DFU handler structure */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bStatus;
|
||||
uint8_t bwPollTimeout0;
|
||||
uint8_t bwPollTimeout1;
|
||||
uint8_t bwPollTimeout2;
|
||||
uint8_t bState;
|
||||
uint8_t iString;
|
||||
|
||||
uint8_t manifest_state;
|
||||
uint16_t data_len;
|
||||
uint16_t block_num;
|
||||
uint32_t base_addr;
|
||||
|
||||
uint8_t buf[TRANSFER_SIZE];
|
||||
} usbd_dfu_handler;
|
||||
|
||||
typedef void (*app_func) (void);
|
||||
|
||||
extern usb_desc dfu_desc;
|
||||
extern usb_class dfu_class;
|
||||
|
||||
#endif /* __DFU_CORE_H */
|
||||
+675
@@ -0,0 +1,675 @@
|
||||
/*!
|
||||
\file dfu_core.c
|
||||
\brief USB DFU device class core functions
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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 "dfu_core.h"
|
||||
#include "systick.h"
|
||||
#include <string.h>
|
||||
|
||||
#define USBD_VID 0x28E9U
|
||||
#define USBD_PID 0x0189U
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint8_t dfu_init (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t dfu_deinit (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t dfu_req_handler (usb_dev *udev, usb_req *req);
|
||||
static uint8_t dfu_ctlx_in (usb_dev *udev);
|
||||
|
||||
/* DFU requests management functions */
|
||||
static void dfu_detach (usb_dev *udev, usb_req *req);
|
||||
static void dfu_dnload (usb_dev *udev, usb_req *req);
|
||||
static void dfu_upload (usb_dev *udev, usb_req *req);
|
||||
static void dfu_getstatus (usb_dev *udev, usb_req *req);
|
||||
static void dfu_clrstatus (usb_dev *udev, usb_req *req);
|
||||
static void dfu_getstate (usb_dev *udev, usb_req *req);
|
||||
static void dfu_abort (usb_dev *udev, usb_req *req);
|
||||
|
||||
static void dfu_mode_leave (usb_dev *udev);
|
||||
static uint8_t dfu_getstatus_complete (usb_dev *udev);
|
||||
|
||||
static void (*dfu_request_process[])(usb_dev *udev, usb_req *req) =
|
||||
{
|
||||
[DFU_DETACH] = dfu_detach,
|
||||
[DFU_DNLOAD] = dfu_dnload,
|
||||
[DFU_UPLOAD] = dfu_upload,
|
||||
[DFU_GETSTATUS] = dfu_getstatus,
|
||||
[DFU_CLRSTATUS] = dfu_clrstatus,
|
||||
[DFU_GETSTATE] = dfu_getstate,
|
||||
[DFU_ABORT] = dfu_abort
|
||||
};
|
||||
|
||||
/* note:it should use the c99 standard when compiling the below codes */
|
||||
/* USB standard device descriptor */
|
||||
usb_desc_dev dfu_dev_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_DEV_DESC_LEN,
|
||||
.bDescriptorType = USB_DESCTYPE_DEV
|
||||
},
|
||||
.bcdUSB = 0x0200U,
|
||||
.bDeviceClass = 0x00U,
|
||||
.bDeviceSubClass = 0x00U,
|
||||
.bDeviceProtocol = 0x00U,
|
||||
.bMaxPacketSize0 = USBD_EP0_MAX_SIZE,
|
||||
.idVendor = USBD_VID,
|
||||
.idProduct = USBD_PID,
|
||||
.bcdDevice = 0x0100U,
|
||||
.iManufacturer = STR_IDX_MFC,
|
||||
.iProduct = STR_IDX_PRODUCT,
|
||||
.iSerialNumber = STR_IDX_SERIAL,
|
||||
.bNumberConfigurations = USBD_CFG_MAX_NUM
|
||||
};
|
||||
|
||||
/* USB device configuration descriptor */
|
||||
usb_dfu_desc_config_set dfu_config_desc =
|
||||
{
|
||||
.config =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_config),
|
||||
.bDescriptorType = USB_DESCTYPE_CONFIG
|
||||
},
|
||||
.wTotalLength = USB_DFU_CONFIG_DESC_SIZE,
|
||||
.bNumInterfaces = 0x01U,
|
||||
.bConfigurationValue = 0x01U,
|
||||
.iConfiguration = 0x00U,
|
||||
.bmAttributes = 0x80U,
|
||||
.bMaxPower = 0x32U
|
||||
},
|
||||
|
||||
.dfu_itf =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_itf),
|
||||
.bDescriptorType = USB_DESCTYPE_ITF
|
||||
},
|
||||
.bInterfaceNumber = 0x00U,
|
||||
.bAlternateSetting = 0x00U,
|
||||
.bNumEndpoints = 0x00U,
|
||||
.bInterfaceClass = USB_DFU_CLASS,
|
||||
.bInterfaceSubClass = USB_DFU_SUBCLASS_UPGRADE,
|
||||
.bInterfaceProtocol = USB_DFU_PROTOCL_DFU,
|
||||
.iInterface = 0x00U
|
||||
},
|
||||
|
||||
.dfu_func =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_dfu_func),
|
||||
.bDescriptorType = DFU_DESC_TYPE
|
||||
},
|
||||
.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_CAN_UPLOAD | USB_DFU_WILL_DETACH,
|
||||
.wDetachTimeOut = 0x00FFU,
|
||||
.wTransferSize = TRANSFER_SIZE,
|
||||
.bcdDFUVersion = 0x011AU,
|
||||
},
|
||||
};
|
||||
|
||||
/* USB language ID descriptor */
|
||||
static usb_desc_LANGID usbd_language_id_desc =
|
||||
{
|
||||
.header = {
|
||||
.bLength = sizeof(usb_desc_LANGID),
|
||||
.bDescriptorType = USB_DESCTYPE_STR
|
||||
},
|
||||
.wLANGID = ENG_LANGID
|
||||
};
|
||||
|
||||
/* USB manufacture string */
|
||||
static usb_desc_str manufacturer_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(10U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
|
||||
};
|
||||
|
||||
/* USB product string */
|
||||
static usb_desc_str product_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(12U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'D', 'F', 'U'}
|
||||
};
|
||||
|
||||
/* USB serial string */
|
||||
static usb_desc_str serial_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(2U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
}
|
||||
};
|
||||
|
||||
/* USB configure string */
|
||||
static usb_desc_str config_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(15U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'D', '3', '2', ' ', 'U', 'S', 'B', ' ', 'C', 'O', 'N', 'F', 'I', 'G'}
|
||||
};
|
||||
|
||||
/* USB interface string */
|
||||
static usb_desc_str interface_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(15U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'@', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'F', 'l', 'a', 's', 'h', ' ', '/', '0', 'x', '0', '8', '0', '0',
|
||||
'0', '0', '0', '0', '/', '1', '6', '*', '0', '0', '1', 'K', 'a', ',', '4', '8', '*', '0', '0', '1', 'K', 'g'}
|
||||
};
|
||||
|
||||
uint8_t* usbd_dfu_strings[] =
|
||||
{
|
||||
[STR_IDX_LANGID] = (uint8_t *)&usbd_language_id_desc,
|
||||
[STR_IDX_MFC] = (uint8_t *)&manufacturer_string,
|
||||
[STR_IDX_PRODUCT] = (uint8_t *)&product_string,
|
||||
[STR_IDX_SERIAL] = (uint8_t *)&serial_string,
|
||||
[STR_IDX_CONFIG] = (uint8_t *)&config_string,
|
||||
[STR_IDX_ITF] = (uint8_t *)&interface_string
|
||||
};
|
||||
|
||||
usb_desc dfu_desc = {
|
||||
.dev_desc = (uint8_t *)&dfu_dev_desc,
|
||||
.config_desc = (uint8_t *)&dfu_config_desc,
|
||||
.strings = usbd_dfu_strings
|
||||
};
|
||||
|
||||
usb_class dfu_class = {
|
||||
.init = dfu_init,
|
||||
.deinit = dfu_deinit,
|
||||
.req_process = dfu_req_handler,
|
||||
.ctlx_in = dfu_ctlx_in
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief initialize the USB DFU device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t dfu_init (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
static usbd_dfu_handler dfu_handler;
|
||||
|
||||
/* unlock the internal flash */
|
||||
fmc_unlock();
|
||||
|
||||
systick_config();
|
||||
|
||||
memset((void *)&dfu_handler, 0, sizeof(usbd_dfu_handler));
|
||||
|
||||
dfu_handler.base_addr = APP_LOADED_ADDR;
|
||||
dfu_handler.manifest_state = MANIFEST_COMPLETE;
|
||||
dfu_handler.bState = STATE_DFU_IDLE;
|
||||
dfu_handler.bStatus = STATUS_OK;
|
||||
|
||||
udev->class_data[USBD_DFU_INTERFACE] = (void *)&dfu_handler;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief deinitialize the USB DFU device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t dfu_deinit (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->class_data[USBD_DFU_INTERFACE];
|
||||
|
||||
/* restore device default state */
|
||||
memset(udev->class_data[USBD_DFU_INTERFACE], 0, sizeof(usbd_dfu_handler));
|
||||
|
||||
dfu->bState = STATE_DFU_IDLE;
|
||||
dfu->bStatus = STATUS_OK;
|
||||
|
||||
/* lock the internal flash */
|
||||
fmc_lock();
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the USB DFU class-specific requests
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: device class-specific request
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t dfu_req_handler (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
if (req->bRequest < DFU_REQ_MAX) {
|
||||
dfu_request_process[req->bRequest](udev, req);
|
||||
} else {
|
||||
return USBD_FAIL;
|
||||
}
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle data stage
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t dfu_ctlx_in (usb_dev *udev)
|
||||
{
|
||||
dfu_getstatus_complete(udev);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle data in stage in control endpoint 0
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t dfu_getstatus_complete (usb_dev *udev)
|
||||
{
|
||||
uint32_t addr;
|
||||
|
||||
usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->class_data[USBD_DFU_INTERFACE];
|
||||
|
||||
if (STATE_DFU_DNBUSY == dfu->bState) {
|
||||
/* decode the special command */
|
||||
if (0U == dfu->block_num) {
|
||||
if (1U == dfu->data_len){
|
||||
if (GET_COMMANDS == dfu->buf[0]) {
|
||||
/* no operation */
|
||||
}
|
||||
} else if (5U == dfu->data_len) {
|
||||
if (SET_ADDRESS_POINTER == dfu->buf[0]) {
|
||||
/* set flash operation address */
|
||||
dfu->base_addr = *(uint32_t *)(dfu->buf + 1U);
|
||||
} else if (ERASE == dfu->buf[0]) {
|
||||
dfu->base_addr = *(uint32_t *)(dfu->buf + 1U);
|
||||
|
||||
fmc_page_erase(dfu->base_addr);
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
} else if (dfu->block_num > 1U) { /* regular download command */
|
||||
/* preform the write operation */
|
||||
uint32_t idx = 0U;
|
||||
|
||||
/* decode the required address */
|
||||
addr = (dfu->block_num - 2U) * TRANSFER_SIZE + dfu->base_addr;
|
||||
|
||||
if (dfu->data_len & 0x03U) { /* not an aligned data */
|
||||
for (idx = dfu->data_len; idx < ((dfu->data_len & 0xFFFCU) + 4U); idx++) {
|
||||
dfu->buf[idx] = 0xFFU;
|
||||
}
|
||||
}
|
||||
|
||||
/* data received are word multiple */
|
||||
for (idx = 0U; idx < dfu->data_len; idx += 4U) {
|
||||
fmc_word_program(addr, *(uint32_t *)(dfu->buf + idx));
|
||||
|
||||
addr += 4U;
|
||||
}
|
||||
|
||||
dfu->block_num = 0U;
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
dfu->data_len = 0U;
|
||||
|
||||
/* update the device state and poll timeout */
|
||||
dfu->bState = STATE_DFU_DNLOAD_SYNC;
|
||||
|
||||
return USBD_OK;
|
||||
} else if (STATE_DFU_MANIFEST == dfu->bState) { /* manifestation in progress */
|
||||
/* start leaving DFU mode */
|
||||
dfu_mode_leave(udev);
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the DFU_DETACH request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: DFU class request
|
||||
\param[out] none
|
||||
\retval none.
|
||||
*/
|
||||
static void dfu_detach(usb_dev *udev, usb_req *req)
|
||||
{
|
||||
usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->class_data[USBD_DFU_INTERFACE];
|
||||
|
||||
switch (dfu->bState) {
|
||||
case STATE_DFU_IDLE:
|
||||
case STATE_DFU_DNLOAD_SYNC:
|
||||
case STATE_DFU_DNLOAD_IDLE:
|
||||
case STATE_DFU_MANIFEST_SYNC:
|
||||
case STATE_DFU_UPLOAD_IDLE:
|
||||
dfu->bStatus = STATUS_OK;
|
||||
dfu->bState = STATE_DFU_IDLE;
|
||||
dfu->iString = 0U; /* iString */
|
||||
|
||||
dfu->block_num = 0U;
|
||||
dfu->data_len = 0U;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* check the detach capability in the DFU functional descriptor */
|
||||
if (dfu_config_desc.dfu_func.wDetachTimeOut & DFU_DETACH_MASK) {
|
||||
usbd_disconnect(udev);
|
||||
|
||||
usbd_connect(udev);
|
||||
} else {
|
||||
/* wait for the period of time specified in detach request */
|
||||
delay_1ms(4U);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the DFU_DNLOAD request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: DFU class request
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void dfu_dnload(usb_dev *udev, usb_req *req)
|
||||
{
|
||||
usb_transc *transc = &udev->transc_out[0];
|
||||
|
||||
usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->class_data[USBD_DFU_INTERFACE];
|
||||
|
||||
switch (dfu->bState) {
|
||||
case STATE_DFU_IDLE:
|
||||
case STATE_DFU_DNLOAD_IDLE:
|
||||
if (req->wLength > 0U) {
|
||||
/* update the global length and block number */
|
||||
dfu->block_num = req->wValue;
|
||||
dfu->data_len = req->wLength;
|
||||
|
||||
dfu->bState = STATE_DFU_DNLOAD_SYNC;
|
||||
|
||||
transc->xfer_len = dfu->data_len;
|
||||
transc->xfer_buf = dfu->buf;
|
||||
transc->xfer_count = 0U;
|
||||
} else {
|
||||
dfu->manifest_state = MANIFEST_IN_PROGRESS;
|
||||
dfu->bState = STATE_DFU_MANIFEST_SYNC;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handles the DFU UPLOAD request.
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: DFU class request
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void dfu_upload (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
uint8_t *phy_addr = NULL;
|
||||
uint32_t addr = 0U;
|
||||
|
||||
usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->class_data[USBD_DFU_INTERFACE];
|
||||
|
||||
if(req->wLength <= 0U) {
|
||||
dfu->bState = STATE_DFU_IDLE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
usb_transc *transc = &udev->transc_in[0];
|
||||
|
||||
switch (dfu->bState) {
|
||||
case STATE_DFU_IDLE:
|
||||
case STATE_DFU_UPLOAD_IDLE:
|
||||
/* update the global length and block number */
|
||||
dfu->block_num = req->wValue;
|
||||
dfu->data_len = req->wLength;
|
||||
|
||||
/* DFU get command */
|
||||
if (0U == dfu->block_num) {
|
||||
/* update the state machine */
|
||||
dfu->bState = (dfu->data_len > 3U) ? STATE_DFU_IDLE : STATE_DFU_UPLOAD_IDLE;
|
||||
|
||||
/* store the values of all supported commands */
|
||||
dfu->buf[0] = GET_COMMANDS;
|
||||
dfu->buf[1] = SET_ADDRESS_POINTER;
|
||||
dfu->buf[2] = ERASE;
|
||||
|
||||
/* send the status data over EP0 */
|
||||
transc->xfer_buf = &(dfu->buf[0]);
|
||||
transc->xfer_len = 3U;
|
||||
} else if (dfu->block_num > 1U) {
|
||||
dfu->bState = STATE_DFU_UPLOAD_IDLE;
|
||||
|
||||
/* change is accelerated */
|
||||
addr = (dfu->block_num - 2U) * TRANSFER_SIZE + dfu->base_addr;
|
||||
|
||||
/* return the physical address where data are stored */
|
||||
phy_addr = (uint8_t *)(addr);
|
||||
|
||||
/* send the status data over EP0 */
|
||||
transc->xfer_buf = phy_addr;
|
||||
transc->xfer_len = dfu->data_len;
|
||||
} else {
|
||||
dfu->bState = STATUS_ERR_STALLEDPKT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dfu->data_len = 0U;
|
||||
dfu->block_num = 0U;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the DFU_GETSTATUS request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: DFU class request
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void dfu_getstatus (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
usb_transc *transc = &udev->transc_in[0];
|
||||
|
||||
usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->class_data[USBD_DFU_INTERFACE];
|
||||
|
||||
switch (dfu->bState) {
|
||||
case STATE_DFU_DNLOAD_SYNC:
|
||||
if (0U != dfu->data_len) {
|
||||
dfu->bState = STATE_DFU_DNBUSY;
|
||||
|
||||
if (0U == dfu->block_num) {
|
||||
if (ERASE == dfu->buf[0]) {
|
||||
SET_POLLING_TIMEOUT(FLASH_ERASE_TIMEOUT);
|
||||
} else {
|
||||
SET_POLLING_TIMEOUT(FLASH_WRITE_TIMEOUT);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dfu->bState = STATE_DFU_DNLOAD_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_DFU_MANIFEST_SYNC:
|
||||
if (MANIFEST_IN_PROGRESS == dfu->manifest_state) {
|
||||
dfu->bState = STATE_DFU_MANIFEST;
|
||||
dfu->bwPollTimeout0 = 1U;
|
||||
} else if ((MANIFEST_COMPLETE == dfu->manifest_state) && \
|
||||
(dfu_config_desc.dfu_func.bmAttributes & 0x04U)){
|
||||
dfu->bState = STATE_DFU_IDLE;
|
||||
dfu->bwPollTimeout0 = 0U;
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* send the status data of DFU interface to host over EP0 */
|
||||
transc->xfer_buf = (uint8_t *)&(dfu->bStatus);
|
||||
transc->xfer_len = 6U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the DFU_CLRSTATUS request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: DFU class request
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void dfu_clrstatus (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->class_data[USBD_DFU_INTERFACE];
|
||||
|
||||
if (STATE_DFU_ERROR == dfu->bState) {
|
||||
dfu->bStatus = STATUS_OK;
|
||||
dfu->bState = STATE_DFU_IDLE;
|
||||
} else {
|
||||
/* state error */
|
||||
dfu->bStatus = STATUS_ERR_UNKNOWN;
|
||||
dfu->bState = STATE_DFU_ERROR;
|
||||
}
|
||||
|
||||
dfu->iString = 0U; /* iString: index = 0 */
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the DFU_GETSTATE request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: DFU class request
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void dfu_getstate (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
usb_transc *transc = &udev->transc_in[0];
|
||||
|
||||
usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->class_data[USBD_DFU_INTERFACE];
|
||||
|
||||
/* send the current state of the DFU interface to host */
|
||||
transc->xfer_buf = &(dfu->bState);
|
||||
transc->xfer_len = 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the DFU_ABORT request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: DFU class request
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void dfu_abort (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->class_data[USBD_DFU_INTERFACE];
|
||||
|
||||
switch (dfu->bState){
|
||||
case STATE_DFU_IDLE:
|
||||
case STATE_DFU_DNLOAD_SYNC:
|
||||
case STATE_DFU_DNLOAD_IDLE:
|
||||
case STATE_DFU_MANIFEST_SYNC:
|
||||
case STATE_DFU_UPLOAD_IDLE:
|
||||
dfu->bStatus = STATUS_OK;
|
||||
dfu->bState = STATE_DFU_IDLE;
|
||||
dfu->iString = 0U; /* iString: index = 0 */
|
||||
|
||||
dfu->block_num = 0U;
|
||||
dfu->data_len = 0U;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief leave DFU mode and reset device to jump to user loaded code
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void dfu_mode_leave (usb_dev *udev)
|
||||
{
|
||||
usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->class_data[USBD_DFU_INTERFACE];
|
||||
|
||||
dfu->manifest_state = MANIFEST_COMPLETE;
|
||||
|
||||
if (dfu_config_desc.dfu_func.bmAttributes & 0x04U) {
|
||||
dfu->bState = STATE_DFU_MANIFEST_SYNC;
|
||||
} else {
|
||||
dfu->bState = STATE_DFU_MANIFEST_WAIT_RESET;
|
||||
|
||||
/* lock the internal flash */
|
||||
fmc_lock();
|
||||
|
||||
/* generate system reset to allow jumping to the user code */
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*!
|
||||
\file custom_hid_core.h
|
||||
\brief definitions for HID core
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __CUSTOM_HID_CORE_H
|
||||
#define __CUSTOM_HID_CORE_H
|
||||
|
||||
#include "usbd_enum.h"
|
||||
#include "usb_hid.h"
|
||||
|
||||
#define DESC_LEN_REPORT 96U
|
||||
#define DESC_LEN_CONFIG 41U
|
||||
|
||||
#define MAX_PERIPH_NUM 4U
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[2];
|
||||
|
||||
uint8_t reportID;
|
||||
uint8_t idlestate;
|
||||
uint8_t protocol;
|
||||
} custom_hid_handler;
|
||||
|
||||
typedef struct {
|
||||
void (*periph_config[MAX_PERIPH_NUM])(void);
|
||||
} hid_fop_handler;
|
||||
|
||||
extern usb_desc custom_hid_desc;
|
||||
extern usb_class custom_hid_class;
|
||||
|
||||
/* function declarations */
|
||||
/* register HID interface operation functions */
|
||||
uint8_t custom_hid_itfop_register (usb_dev *udev, hid_fop_handler *hid_fop);
|
||||
/* send custom HID report */
|
||||
uint8_t custom_hid_report_send (usb_dev *udev, uint8_t *report, uint16_t len);
|
||||
|
||||
#endif /* __CUSTOM_HID_CORE_H */
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*!
|
||||
\file standard_hid_core.h
|
||||
\brief definitions for HID core
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __STANDARD_HID_CORE_H
|
||||
#define __STANDARD_HID_CORE_H
|
||||
|
||||
#include "usbd_enum.h"
|
||||
#include "usb_hid.h"
|
||||
|
||||
#define USB_HID_CONFIG_DESC_LEN 0x22U
|
||||
#define USB_HID_REPORT_DESC_LEN 0x2EU
|
||||
|
||||
typedef struct {
|
||||
uint32_t protocol;
|
||||
uint32_t idle_state;
|
||||
|
||||
uint8_t data[HID_IN_PACKET];
|
||||
__IO uint8_t prev_transfer_complete;
|
||||
} standard_hid_handler;
|
||||
|
||||
typedef struct {
|
||||
void (*hid_itf_config) (void);
|
||||
void (*hid_itf_data_process) (usb_dev *udev);
|
||||
} hid_fop_handler;
|
||||
|
||||
extern usb_desc hid_desc;
|
||||
extern usb_class hid_class;
|
||||
|
||||
/* function declarations */
|
||||
/* register HID interface operation functions */
|
||||
uint8_t hid_itfop_register (usb_dev *udev, hid_fop_handler *hid_fop);
|
||||
/* send HID report */
|
||||
uint8_t hid_report_send (usb_dev *udev, uint8_t *report, uint16_t len);
|
||||
|
||||
#endif /* __STANDARD_HID_CORE_H */
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*!
|
||||
\file usb_hid.h
|
||||
\brief definitions for the USB HID class
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USB_HID_H
|
||||
#define __USB_HID_H
|
||||
|
||||
#include "usb_ch9_std.h"
|
||||
|
||||
#define USB_HID_CLASS 0x03U
|
||||
|
||||
#define USB_DESCTYPE_HID 0x21U
|
||||
#define USB_DESCTYPE_REPORT 0x22U
|
||||
|
||||
/* HID subclass code */
|
||||
#define USB_HID_SUBCLASS_BOOT_ITF 0x01U
|
||||
|
||||
/* HID protocol codes */
|
||||
#define USB_HID_PROTOCOL_KEYBOARD 0x01U
|
||||
#define USB_HID_PROTOCOL_MOUSE 0x02U
|
||||
|
||||
#define GET_REPORT 0x01U
|
||||
#define GET_IDLE 0x02U
|
||||
#define GET_PROTOCOL 0x03U
|
||||
#define SET_REPORT 0x09U
|
||||
#define SET_IDLE 0x0AU
|
||||
#define SET_PROTOCOL 0x0BU
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_header header; /*!< regular descriptor header containing the descriptor's type and length */
|
||||
|
||||
uint16_t bcdHID; /*!< BCD encoded version that the HID descriptor and device complies to */
|
||||
uint8_t bCountryCode; /*!< country code of the localized device, or zero if universal */
|
||||
uint8_t bNumDescriptors; /*!< total number of HID report descriptors for the interface */
|
||||
uint8_t bDescriptorType; /*!< type of HID report */
|
||||
uint16_t wDescriptorLength; /*!< length of the associated HID report descriptor, in bytes */
|
||||
} usb_desc_hid;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_config config;
|
||||
usb_desc_itf hid_itf;
|
||||
usb_desc_hid hid_vendor;
|
||||
usb_desc_ep hid_epin;
|
||||
usb_desc_ep hid_epout;
|
||||
} usb_hid_desc_config_set;
|
||||
|
||||
#endif /* __USB_HID_H */
|
||||
+510
@@ -0,0 +1,510 @@
|
||||
/*!
|
||||
\file custom_hid_core.c
|
||||
\brief custom HID class driver
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
\version 2021-06-22, V3.0.1, firmware for GD32F10x
|
||||
\version 2021-11-09, V3.0.2, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_transc.h"
|
||||
#include "custom_hid_core.h"
|
||||
#include <string.h>
|
||||
|
||||
#define USBD_VID 0x28E9U
|
||||
#define USBD_PID 0x128AU
|
||||
|
||||
/* Note:it should use the C99 standard when compiling the below codes */
|
||||
/* USB standard device descriptor */
|
||||
usb_desc_dev custom_hid_dev_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_DEV_DESC_LEN,
|
||||
.bDescriptorType = USB_DESCTYPE_DEV,
|
||||
},
|
||||
.bcdUSB = 0x0200U,
|
||||
.bDeviceClass = 0x00U,
|
||||
.bDeviceSubClass = 0x00U,
|
||||
.bDeviceProtocol = 0x00U,
|
||||
.bMaxPacketSize0 = USBD_EP0_MAX_SIZE,
|
||||
.idVendor = USBD_VID,
|
||||
.idProduct = USBD_PID,
|
||||
.bcdDevice = 0x0100U,
|
||||
.iManufacturer = STR_IDX_MFC,
|
||||
.iProduct = STR_IDX_PRODUCT,
|
||||
.iSerialNumber = STR_IDX_SERIAL,
|
||||
.bNumberConfigurations = USBD_CFG_MAX_NUM,
|
||||
};
|
||||
|
||||
/* USB device configure descriptor */
|
||||
usb_hid_desc_config_set custom_hid_config_desc =
|
||||
{
|
||||
.config =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_config),
|
||||
.bDescriptorType = USB_DESCTYPE_CONFIG
|
||||
},
|
||||
.wTotalLength = DESC_LEN_CONFIG,
|
||||
.bNumInterfaces = 0x01U,
|
||||
.bConfigurationValue = 0x01U,
|
||||
.iConfiguration = 0x00U,
|
||||
.bmAttributes = 0x80U,
|
||||
.bMaxPower = 0x32U
|
||||
},
|
||||
|
||||
.hid_itf =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_itf),
|
||||
.bDescriptorType = USB_DESCTYPE_ITF
|
||||
},
|
||||
.bInterfaceNumber = 0x00U,
|
||||
.bAlternateSetting = 0x00U,
|
||||
.bNumEndpoints = 0x02U,
|
||||
.bInterfaceClass = USB_HID_CLASS,
|
||||
.bInterfaceSubClass = 0x00U,
|
||||
.bInterfaceProtocol = 0x00U,
|
||||
.iInterface = 0x00U
|
||||
},
|
||||
|
||||
.hid_vendor =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_hid),
|
||||
.bDescriptorType = USB_DESCTYPE_HID
|
||||
},
|
||||
.bcdHID = 0x0111U,
|
||||
.bCountryCode = 0x00U,
|
||||
.bNumDescriptors = 0x01U,
|
||||
.bDescriptorType = USB_DESCTYPE_REPORT,
|
||||
.wDescriptorLength = DESC_LEN_REPORT,
|
||||
},
|
||||
|
||||
.hid_epin =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP
|
||||
},
|
||||
.bEndpointAddress = CUSTOMHID_IN_EP,
|
||||
.bmAttributes = USB_EP_ATTR_INT,
|
||||
.wMaxPacketSize = CUSTOMHID_IN_PACKET,
|
||||
.bInterval = 0x20U
|
||||
},
|
||||
|
||||
.hid_epout =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP
|
||||
},
|
||||
.bEndpointAddress = CUSTOMHID_OUT_EP,
|
||||
.bmAttributes = USB_EP_ATTR_INT,
|
||||
.wMaxPacketSize = CUSTOMHID_OUT_PACKET,
|
||||
.bInterval = 0x20U
|
||||
}
|
||||
};
|
||||
|
||||
/* USB language ID descriptor */
|
||||
static usb_desc_LANGID usbd_language_id_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_LANGID),
|
||||
.bDescriptorType = USB_DESCTYPE_STR
|
||||
},
|
||||
.wLANGID = ENG_LANGID
|
||||
};
|
||||
|
||||
/* USB manufacture string */
|
||||
static usb_desc_str manufacturer_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(10U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
|
||||
};
|
||||
|
||||
/* USB product string */
|
||||
static usb_desc_str product_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(14U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'D', '3', '2', '-', 'C', 'u', 's', 't', 'o', 'm', 'H', 'I', 'D'}
|
||||
};
|
||||
|
||||
/* USB serial string */
|
||||
static usb_desc_str serial_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(12U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
}
|
||||
};
|
||||
|
||||
/* USB string descriptor set */
|
||||
static uint8_t* usbd_hid_strings[] =
|
||||
{
|
||||
[STR_IDX_LANGID] = (uint8_t *)&usbd_language_id_desc,
|
||||
[STR_IDX_MFC] = (uint8_t *)&manufacturer_string,
|
||||
[STR_IDX_PRODUCT] = (uint8_t *)&product_string,
|
||||
[STR_IDX_SERIAL] = (uint8_t *)&serial_string
|
||||
};
|
||||
|
||||
usb_desc custom_hid_desc = {
|
||||
.dev_desc = (uint8_t *)&custom_hid_dev_desc,
|
||||
.config_desc = (uint8_t *)&custom_hid_config_desc,
|
||||
.strings = usbd_hid_strings
|
||||
};
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint8_t custom_hid_init (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t custom_hid_deinit (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t custom_hid_req_handler (usb_dev *udev, usb_req *req);
|
||||
static void custom_hid_data_in (usb_dev *udev, uint8_t ep_num);
|
||||
static void custom_hid_data_out (usb_dev *udev, uint8_t ep_num);
|
||||
|
||||
usb_class custom_hid_class = {
|
||||
.req_cmd = 0xFFU,
|
||||
|
||||
.init = custom_hid_init,
|
||||
.deinit = custom_hid_deinit,
|
||||
.req_process = custom_hid_req_handler,
|
||||
.data_in = custom_hid_data_in,
|
||||
.data_out = custom_hid_data_out
|
||||
};
|
||||
|
||||
const uint8_t customhid_report_descriptor[DESC_LEN_REPORT] =
|
||||
{
|
||||
0x06, 0x00, 0xFF, /* USAGE_PAGE (Vendor Defined: 0xFF00) */
|
||||
0x09, 0x00, /* USAGE (Custom Device) */
|
||||
0xa1, 0x01, /* COLLECTION (Application) */
|
||||
|
||||
/* led 1 */
|
||||
0x85, 0x11, /* REPORT_ID (0x11) */
|
||||
0x09, 0x01, /* USAGE (LED 1) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x95, 0x01, /* REPORT_COUNT (1) */
|
||||
0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vol) */
|
||||
|
||||
/* led 2 */
|
||||
0x85, 0x12, /* REPORT_ID (0x12) */
|
||||
0x09, 0x02, /* USAGE (LED 2) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x95, 0x01, /* REPORT_COUNT (1) */
|
||||
0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vol) */
|
||||
|
||||
/* led 3 */
|
||||
0x85, 0x13, /* REPORT_ID (0x13) */
|
||||
0x09, 0x03, /* USAGE (LED 3) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x95, 0x01, /* REPORT_COUNT (1) */
|
||||
0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vol) */
|
||||
|
||||
/* led 4 */
|
||||
0x85, 0x14, /* REPORT_ID (0x14) */
|
||||
0x09, 0x04, /* USAGE (LED 4) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x95, 0x01, /* REPORT_COUNT (1) */
|
||||
0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vol) */
|
||||
|
||||
/* wakeup key */
|
||||
0x85, 0x15, /* REPORT_ID (0x15) */
|
||||
0x09, 0x05, /* USAGE (Push Button) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
|
||||
0x75, 0x01, /* REPORT_SIZE (1) */
|
||||
0x81, 0x02, /* INPUT (Data,Var,Abs,Vol) */
|
||||
|
||||
0x75, 0x07, /* REPORT_SIZE (7) */
|
||||
0x81, 0x03, /* INPUT (Cnst,Var,Abs,Vol) */
|
||||
|
||||
/* tamper key */
|
||||
0x85, 0x16, /* REPORT_ID (0x16) */
|
||||
0x09, 0x06, /* USAGE (Push Button) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
|
||||
0x75, 0x01, /* REPORT_SIZE (1) */
|
||||
0x81, 0x02, /* INPUT (Data,Var,Abs,Vol) */
|
||||
|
||||
0x75, 0x07, /* REPORT_SIZE (7) */
|
||||
0x81, 0x03, /* INPUT (Cnst,Var,Abs,Vol) */
|
||||
|
||||
0xc0 /* END_COLLECTION */
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief register HID interface operation functions
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] hid_fop: HID operation functions structure
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
uint8_t custom_hid_itfop_register (usb_dev *udev, hid_fop_handler *hid_fop)
|
||||
{
|
||||
if (NULL != hid_fop) {
|
||||
udev->user_data = hid_fop;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
return USBD_FAIL;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief send custom HID report
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] report: pointer to HID report
|
||||
\param[in] len: data length
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
uint8_t custom_hid_report_send (usb_dev *udev, uint8_t *report, uint16_t len)
|
||||
{
|
||||
usbd_ep_send (udev, CUSTOMHID_IN_EP, report, len);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize the HID device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t custom_hid_init (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
static custom_hid_handler hid_handler;
|
||||
|
||||
memset((void *)&hid_handler, 0, sizeof(custom_hid_handler));
|
||||
|
||||
/* initialize the data endpoints */
|
||||
usbd_ep_init(udev, EP_BUF_SNG, HID_TX_ADDR, &(custom_hid_config_desc.hid_epin));
|
||||
usbd_ep_init(udev, EP_BUF_SNG, HID_RX_ADDR, &(custom_hid_config_desc.hid_epout));
|
||||
|
||||
usbd_ep_recev (udev, CUSTOMHID_OUT_EP, hid_handler.data, 2U);
|
||||
|
||||
udev->ep_transc[EP_ID(CUSTOMHID_IN_EP)][TRANSC_IN] = custom_hid_class.data_in;
|
||||
udev->ep_transc[EP_ID(CUSTOMHID_OUT_EP)][TRANSC_OUT] = custom_hid_class.data_out;
|
||||
|
||||
udev->class_data[CUSTOM_HID_INTERFACE] = (void *)&hid_handler;
|
||||
|
||||
if (udev->user_data != NULL) {
|
||||
for (uint8_t i = 0U; i < MAX_PERIPH_NUM; i++) {
|
||||
if (((hid_fop_handler *)udev->user_data)->periph_config[i] != NULL) {
|
||||
((hid_fop_handler *)udev->user_data)->periph_config[i]();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief de-initialize the HID device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t custom_hid_deinit (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
/* deinitialize HID endpoints */
|
||||
usbd_ep_deinit(udev, CUSTOMHID_IN_EP);
|
||||
usbd_ep_deinit(udev, CUSTOMHID_OUT_EP);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the HID class-specific requests
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: device class-specific request
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t custom_hid_req_handler (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
uint8_t status = REQ_NOTSUPP;
|
||||
|
||||
custom_hid_handler *hid = (custom_hid_handler *)udev->class_data[CUSTOM_HID_INTERFACE];
|
||||
|
||||
switch (req->bRequest) {
|
||||
case USB_GET_DESCRIPTOR:
|
||||
if (USB_DESCTYPE_REPORT == (req->wValue >> 8)) {
|
||||
usb_transc_config(&udev->transc_in[0],
|
||||
(uint8_t *)customhid_report_descriptor,
|
||||
USB_MIN(DESC_LEN_REPORT, req->wLength),
|
||||
0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
} else if (USB_DESCTYPE_HID == (req->wValue >> 8U)) {
|
||||
usb_transc_config(&udev->transc_in[0U],
|
||||
(uint8_t *)(&(custom_hid_config_desc.hid_vendor)),
|
||||
USB_MIN(9U, req->wLength),
|
||||
0U);
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_REPORT:
|
||||
if (2U == req->wLength) {
|
||||
usb_transc_config(&udev->transc_in[0], hid->data, 2U, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_IDLE:
|
||||
usb_transc_config(&udev->transc_in[0], (uint8_t *)&hid->idlestate, 1U, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case GET_PROTOCOL:
|
||||
usb_transc_config(&udev->transc_in[0], (uint8_t *)&hid->protocol, 1U, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case SET_REPORT:
|
||||
hid->reportID = (uint8_t)(req->wValue);
|
||||
|
||||
usb_transc_config(&udev->transc_out[0], hid->data, req->wLength, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case SET_IDLE:
|
||||
hid->idlestate = (uint8_t)(req->wValue >> 8);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case SET_PROTOCOL:
|
||||
hid->protocol = (uint8_t)(req->wValue);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle custom HID data in transaction
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void custom_hid_data_in (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle custom HID data out transaction
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void custom_hid_data_out (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
custom_hid_handler *hid = (custom_hid_handler *)udev->class_data[CUSTOM_HID_INTERFACE];
|
||||
|
||||
if (CUSTOMHID_OUT_EP == ep_num){
|
||||
switch (hid->data[0]){
|
||||
case 0x11:
|
||||
if (RESET != hid->data[1]) {
|
||||
/* turn on led5 */
|
||||
gd_eval_led_on(LED5);
|
||||
} else {
|
||||
gd_eval_led_off(LED5);
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
if (RESET != hid->data[1]) {
|
||||
gd_eval_led_on(LED2);
|
||||
} else {
|
||||
gd_eval_led_off(LED2);
|
||||
}
|
||||
break;
|
||||
case 0x13:
|
||||
if (RESET != hid->data[1]) {
|
||||
gd_eval_led_on(LED3);
|
||||
} else {
|
||||
gd_eval_led_off(LED3);
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
if (RESET != hid->data[1]) {
|
||||
gd_eval_led_on(LED4);
|
||||
} else {
|
||||
gd_eval_led_off(LED4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* turn off all leds */
|
||||
gd_eval_led_off(LED2);
|
||||
gd_eval_led_off(LED3);
|
||||
gd_eval_led_off(LED4);
|
||||
gd_eval_led_off(LED5);
|
||||
break;
|
||||
}
|
||||
|
||||
usbd_ep_recev(udev, CUSTOMHID_OUT_EP, hid->data, 2U);
|
||||
}
|
||||
}
|
||||
+427
@@ -0,0 +1,427 @@
|
||||
/*!
|
||||
\file standard_hid_core.c
|
||||
\brief HID class driver
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_transc.h"
|
||||
#include "standard_hid_core.h"
|
||||
#include <string.h>
|
||||
|
||||
#define USBD_VID 0x28E9U
|
||||
#define USBD_PID 0x0380U
|
||||
|
||||
/* Note:it should use the C99 standard when compiling the below codes */
|
||||
/* USB standard device descriptor */
|
||||
usb_desc_dev hid_dev_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_DEV_DESC_LEN,
|
||||
.bDescriptorType = USB_DESCTYPE_DEV
|
||||
},
|
||||
#ifdef LPM_ENABLED
|
||||
.bcdUSB = 0x0201U,
|
||||
#else
|
||||
.bcdUSB = 0x0200U,
|
||||
#endif /* LPM_ENABLED */
|
||||
.bDeviceClass = 0x00U,
|
||||
.bDeviceSubClass = 0x00U,
|
||||
.bDeviceProtocol = 0x00U,
|
||||
.bMaxPacketSize0 = USBD_EP0_MAX_SIZE,
|
||||
.idVendor = USBD_VID,
|
||||
.idProduct = USBD_PID,
|
||||
.bcdDevice = 0x0100U,
|
||||
.iManufacturer = STR_IDX_MFC,
|
||||
.iProduct = STR_IDX_PRODUCT,
|
||||
.iSerialNumber = STR_IDX_SERIAL,
|
||||
.bNumberConfigurations = USBD_CFG_MAX_NUM
|
||||
};
|
||||
|
||||
#ifdef LPM_ENABLED
|
||||
|
||||
/* BOS descriptor */
|
||||
uint8_t USBD_BOSDesc[USB_BOS_DESC_LEN] =
|
||||
{
|
||||
0x05,
|
||||
USB_DESCTYPE_BOS,
|
||||
0x0C,
|
||||
0x00,
|
||||
0x01, /* 1 device capability descriptor */
|
||||
|
||||
/* device capability*/
|
||||
0x07,
|
||||
USB_DEVICE_CAPABITY,
|
||||
0x02,
|
||||
0x06, /* LPM capability bit set */
|
||||
0x00,
|
||||
0x00,
|
||||
0x00
|
||||
};
|
||||
|
||||
#endif /* LPM_ENABLED */
|
||||
|
||||
usb_hid_desc_config_set hid_config_desc =
|
||||
{
|
||||
.config =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_config),
|
||||
.bDescriptorType = USB_DESCTYPE_CONFIG
|
||||
},
|
||||
.wTotalLength = USB_HID_CONFIG_DESC_LEN,
|
||||
.bNumInterfaces = 0x01U,
|
||||
.bConfigurationValue = 0x01U,
|
||||
.iConfiguration = 0x00U,
|
||||
.bmAttributes = 0xA0U,
|
||||
.bMaxPower = 0x32U
|
||||
},
|
||||
|
||||
.hid_itf =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_itf),
|
||||
.bDescriptorType = USB_DESCTYPE_ITF
|
||||
},
|
||||
.bInterfaceNumber = 0x00U,
|
||||
.bAlternateSetting = 0x00U,
|
||||
.bNumEndpoints = 0x01U,
|
||||
.bInterfaceClass = USB_HID_CLASS,
|
||||
.bInterfaceSubClass = USB_HID_SUBCLASS_BOOT_ITF,
|
||||
.bInterfaceProtocol = USB_HID_PROTOCOL_KEYBOARD,
|
||||
.iInterface = 0x00U
|
||||
},
|
||||
|
||||
.hid_vendor =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_hid),
|
||||
.bDescriptorType = USB_DESCTYPE_HID
|
||||
},
|
||||
.bcdHID = 0x0111U,
|
||||
.bCountryCode = 0x00U,
|
||||
.bNumDescriptors = 0x01U,
|
||||
.bDescriptorType = USB_DESCTYPE_REPORT,
|
||||
.wDescriptorLength = USB_HID_REPORT_DESC_LEN,
|
||||
},
|
||||
|
||||
.hid_epin =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP
|
||||
},
|
||||
.bEndpointAddress = HID_IN_EP,
|
||||
.bmAttributes = USB_EP_ATTR_INT,
|
||||
.wMaxPacketSize = HID_IN_PACKET,
|
||||
.bInterval = 0x40U
|
||||
}
|
||||
};
|
||||
|
||||
/* USB language ID Descriptor */
|
||||
static usb_desc_LANGID usbd_language_id_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_LANGID),
|
||||
.bDescriptorType = USB_DESCTYPE_STR
|
||||
},
|
||||
.wLANGID = ENG_LANGID
|
||||
};
|
||||
|
||||
/* USB manufacture string */
|
||||
static usb_desc_str manufacturer_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(10U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
|
||||
};
|
||||
|
||||
/* USB product string */
|
||||
static usb_desc_str product_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(17U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'K', 'e', 'y', 'b', 'o', 'a', 'r', 'd'}
|
||||
};
|
||||
|
||||
/* USB serial string */
|
||||
static usb_desc_str serial_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(12U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
}
|
||||
};
|
||||
|
||||
/* USB string descriptor set */
|
||||
static uint8_t* usbd_hid_strings[] =
|
||||
{
|
||||
[STR_IDX_LANGID] = (uint8_t *)&usbd_language_id_desc,
|
||||
[STR_IDX_MFC] = (uint8_t *)&manufacturer_string,
|
||||
[STR_IDX_PRODUCT] = (uint8_t *)&product_string,
|
||||
[STR_IDX_SERIAL] = (uint8_t *)&serial_string
|
||||
};
|
||||
|
||||
usb_desc hid_desc = {
|
||||
#ifdef LPM_ENABLED
|
||||
.bos_desc = (uint8_t *)&USBD_BOSDesc,
|
||||
#endif /* LPM_ENABLED */
|
||||
.dev_desc = (uint8_t *)&hid_dev_desc,
|
||||
.config_desc = (uint8_t *)&hid_config_desc,
|
||||
.strings = usbd_hid_strings
|
||||
};
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint8_t hid_init (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t hid_deinit (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t hid_req_handler (usb_dev *udev, usb_req *req);
|
||||
static void hid_data_in_handler (usb_dev *udev, uint8_t ep_num);
|
||||
|
||||
usb_class hid_class = {
|
||||
.init = hid_init,
|
||||
.deinit = hid_deinit,
|
||||
.req_process = hid_req_handler,
|
||||
.data_in = hid_data_in_handler
|
||||
};
|
||||
|
||||
const uint8_t hid_report_desc[USB_HID_REPORT_DESC_LEN] =
|
||||
{
|
||||
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
|
||||
0x09, 0x06, /* USAGE (Keyboard) */
|
||||
0xa1, 0x01, /* COLLECTION (Application) */
|
||||
|
||||
0x05, 0x07, /* USAGE_PAGE (Keyboard/Keypad) */
|
||||
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
|
||||
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
|
||||
0x95, 0x08, /* REPORT_COUNT (8) */
|
||||
0x75, 0x01, /* REPORT_SIZE (1) */
|
||||
0x81, 0x02, /* INPUT (Data,Var,Abs) */
|
||||
|
||||
0x95, 0x01, /* REPORT_COUNT (1) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
|
||||
|
||||
0x95, 0x06, /* REPORT_COUNT (6) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x26, 0xFF, 0x00, /* LOGICAL_MAXIMUM (255) */
|
||||
0x05, 0x07, /* USAGE_PAGE (Keyboard/Keypad) */
|
||||
0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */
|
||||
0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */
|
||||
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
|
||||
|
||||
0xc0 /* END_COLLECTION */
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief register HID interface operation functions
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] hid_fop: HID operation functions structure
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
uint8_t hid_itfop_register (usb_dev *udev, hid_fop_handler *hid_fop)
|
||||
{
|
||||
if (NULL != hid_fop) {
|
||||
udev->user_data = (void *)hid_fop;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
return USBD_FAIL;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief send HID report
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] report: pointer to HID report
|
||||
\param[in] len: data length
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
uint8_t hid_report_send (usb_dev *udev, uint8_t *report, uint16_t len)
|
||||
{
|
||||
standard_hid_handler *hid = (standard_hid_handler *)udev->class_data[USBD_HID_INTERFACE];
|
||||
|
||||
/* check if USB is configured */
|
||||
hid->prev_transfer_complete = 0U;
|
||||
|
||||
usbd_ep_send(udev, HID_IN_EP, report, len);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize the HID device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t hid_init (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
static standard_hid_handler hid_handler;
|
||||
|
||||
memset((void *)&hid_handler, 0, sizeof(standard_hid_handler));
|
||||
|
||||
/* initialize TX endpoint */
|
||||
usbd_ep_init(udev, EP_BUF_SNG, INT_TX_ADDR, &(hid_config_desc.hid_epin));
|
||||
|
||||
udev->ep_transc[EP_ID(HID_IN_EP)][TRANSC_IN] = hid_class.data_in;
|
||||
|
||||
hid_handler.prev_transfer_complete = 1U;
|
||||
|
||||
udev->class_data[USBD_HID_INTERFACE] = (void *)&hid_handler;
|
||||
|
||||
if (NULL != udev->user_data) {
|
||||
((hid_fop_handler *)udev->user_data)->hid_itf_config();
|
||||
}
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief deinitialize the HID device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t hid_deinit (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
/* deinitialize HID endpoints */
|
||||
usbd_ep_deinit (udev, HID_IN_EP);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the HID class-specific requests
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: device class-specific request
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t hid_req_handler (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
uint8_t status = REQ_NOTSUPP;
|
||||
|
||||
standard_hid_handler *hid = (standard_hid_handler *)udev->class_data[USBD_HID_INTERFACE];
|
||||
|
||||
switch (req->bRequest) {
|
||||
case GET_REPORT:
|
||||
/* no use for this driver */
|
||||
break;
|
||||
|
||||
case GET_IDLE:
|
||||
usb_transc_config(&udev->transc_in[0U], (uint8_t *)&hid->idle_state, 1U, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case GET_PROTOCOL:
|
||||
usb_transc_config(&udev->transc_in[0U], (uint8_t *)&hid->protocol, 1U, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case SET_REPORT:
|
||||
/* no use for this driver */
|
||||
break;
|
||||
|
||||
case SET_IDLE:
|
||||
hid->idle_state = (uint8_t)(req->wValue >> 8);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case SET_PROTOCOL:
|
||||
hid->protocol = (uint8_t)(req->wValue);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case USB_GET_DESCRIPTOR:
|
||||
if (USB_DESCTYPE_REPORT == (req->wValue >> 8)) {
|
||||
usb_transc_config(&udev->transc_in[0U],
|
||||
(uint8_t *)hid_report_desc,
|
||||
USB_MIN(USB_HID_REPORT_DESC_LEN, req->wLength),
|
||||
0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
} else if (USB_DESCTYPE_HID == (req->wValue >> 8U)) {
|
||||
usb_transc_config(&udev->transc_in[0U],
|
||||
(uint8_t *)(&(hid_config_desc.hid_vendor)),
|
||||
USB_MIN(9U, req->wLength),
|
||||
0U);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle data stage in DATA IN transaction
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint identifier
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void hid_data_in_handler (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
standard_hid_handler *hid = (standard_hid_handler *)udev->class_data[USBD_HID_INTERFACE];
|
||||
|
||||
if (hid->data[2]) {
|
||||
hid->data[2] = 0x00U;
|
||||
|
||||
usbd_ep_send(udev, HID_IN_EP, hid->data, HID_IN_PACKET);
|
||||
} else {
|
||||
hid->prev_transfer_complete = 1U;
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*!
|
||||
\file usb_iap_core.h
|
||||
\brief the header file of IAP driver
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USB_IAP_CORE_H
|
||||
#define __USB_IAP_CORE_H
|
||||
|
||||
#include "usbd_enum.h"
|
||||
#include "usb_hid.h"
|
||||
|
||||
#define USB_DESC_LEN_IAP_REPORT 35U
|
||||
#define USB_DESC_LEN_IAP_CONFIG_SET 41U
|
||||
|
||||
/* special commands with download request */
|
||||
#define IAP_OPTION_BYTE 0x01U
|
||||
#define IAP_ERASE 0x02U
|
||||
#define IAP_DNLOAD 0x03U
|
||||
#define IAP_LEAVE 0x04U
|
||||
#define IAP_GETBIN_ADDRESS 0x05U
|
||||
|
||||
typedef void (*app_func) (void);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t report_buf[IAP_OUT_PACKET + 1U];
|
||||
uint8_t option_byte[IAP_IN_PACKET];
|
||||
|
||||
/* state machine variables */
|
||||
uint8_t dev_status[IAP_IN_PACKET];
|
||||
uint8_t bin_addr[IAP_IN_PACKET];
|
||||
|
||||
uint8_t reportID;
|
||||
uint8_t flag;
|
||||
|
||||
uint32_t protocol;
|
||||
uint32_t idlestate;
|
||||
|
||||
uint16_t transfer_times;
|
||||
uint16_t page_count;
|
||||
uint16_t lps; /* last packet size */
|
||||
uint32_t file_length;
|
||||
uint32_t base_address;
|
||||
} usbd_iap_handler;
|
||||
|
||||
extern usb_desc iap_desc;
|
||||
extern usb_class iap_class;
|
||||
|
||||
/* function declarations */
|
||||
/* send IAP report */
|
||||
uint8_t iap_report_send(usb_dev *udev, uint8_t *report, uint16_t len);
|
||||
|
||||
#endif /* __USB_IAP_CORE_H */
|
||||
+596
@@ -0,0 +1,596 @@
|
||||
/*!
|
||||
\file usb_iap_core.c
|
||||
\brief IAP driver
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_transc.h"
|
||||
#include "usb_iap_core.h"
|
||||
#include <string.h>
|
||||
|
||||
#define USBD_VID 0x28E9U
|
||||
#define USBD_PID 0x028BU
|
||||
|
||||
/* Note:it should use the C99 standard when compiling the below codes */
|
||||
/* USB standard device descriptor */
|
||||
usb_desc_dev iap_dev_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_DEV_DESC_LEN,
|
||||
.bDescriptorType = USB_DESCTYPE_DEV
|
||||
},
|
||||
.bcdUSB = 0x0200U,
|
||||
.bDeviceClass = 0x00U,
|
||||
.bDeviceSubClass = 0x00U,
|
||||
.bDeviceProtocol = 0x00U,
|
||||
.bMaxPacketSize0 = USBD_EP0_MAX_SIZE,
|
||||
.idVendor = USBD_VID,
|
||||
.idProduct = USBD_PID,
|
||||
.bcdDevice = 0x0100U,
|
||||
.iManufacturer = STR_IDX_MFC,
|
||||
.iProduct = STR_IDX_PRODUCT,
|
||||
.iSerialNumber = STR_IDX_SERIAL,
|
||||
.bNumberConfigurations = USBD_CFG_MAX_NUM
|
||||
};
|
||||
|
||||
/* USB device configure descriptor */
|
||||
usb_hid_desc_config_set iap_config_desc =
|
||||
{
|
||||
.config =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_config),
|
||||
.bDescriptorType = USB_DESCTYPE_CONFIG
|
||||
},
|
||||
.wTotalLength = USB_DESC_LEN_IAP_CONFIG_SET,
|
||||
.bNumInterfaces = 0x01U,
|
||||
.bConfigurationValue = 0x01U,
|
||||
.iConfiguration = 0x00U,
|
||||
.bmAttributes = 0x80U,
|
||||
.bMaxPower = 0x32U
|
||||
},
|
||||
|
||||
.hid_itf =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_itf),
|
||||
.bDescriptorType = USB_DESCTYPE_ITF
|
||||
},
|
||||
.bInterfaceNumber = 0x00U,
|
||||
.bAlternateSetting = 0x00U,
|
||||
.bNumEndpoints = 0x02U,
|
||||
.bInterfaceClass = USB_HID_CLASS,
|
||||
.bInterfaceSubClass = 0x00U,
|
||||
.bInterfaceProtocol = 0x01U,
|
||||
.iInterface = 0x00U
|
||||
},
|
||||
|
||||
.hid_vendor =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_hid),
|
||||
.bDescriptorType = USB_DESCTYPE_HID
|
||||
},
|
||||
.bcdHID = 0x0111U,
|
||||
.bCountryCode = 0x00U,
|
||||
.bNumDescriptors = 0x01U,
|
||||
.bDescriptorType = USB_DESCTYPE_REPORT,
|
||||
.wDescriptorLength = USB_DESC_LEN_IAP_REPORT,
|
||||
},
|
||||
|
||||
.hid_epin =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP
|
||||
},
|
||||
.bEndpointAddress = IAP_IN_EP,
|
||||
.bmAttributes = USB_EP_ATTR_INT,
|
||||
.wMaxPacketSize = IAP_IN_PACKET,
|
||||
.bInterval = 0x01U
|
||||
},
|
||||
|
||||
.hid_epout =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP
|
||||
},
|
||||
.bEndpointAddress = IAP_OUT_EP,
|
||||
.bmAttributes = USB_EP_ATTR_INT,
|
||||
.wMaxPacketSize = IAP_OUT_PACKET,
|
||||
.bInterval = 0x01U
|
||||
}
|
||||
};
|
||||
|
||||
/* USB language ID Descriptor */
|
||||
usb_desc_LANGID usbd_language_id_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_LANGID),
|
||||
.bDescriptorType = USB_DESCTYPE_STR
|
||||
},
|
||||
.wLANGID = ENG_LANGID
|
||||
};
|
||||
|
||||
/* USB manufacture string */
|
||||
static usb_desc_str manufacturer_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(10U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
|
||||
};
|
||||
|
||||
/* USB product string */
|
||||
static usb_desc_str product_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(12U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'I', 'A', 'P'}
|
||||
};
|
||||
|
||||
/* USB serial string */
|
||||
static usb_desc_str serial_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(2U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
}
|
||||
};
|
||||
|
||||
/* USB string descriptor set */
|
||||
uint8_t* usbd_iap_strings[] =
|
||||
{
|
||||
[STR_IDX_LANGID] = (uint8_t *)&usbd_language_id_desc,
|
||||
[STR_IDX_MFC] = (uint8_t *)&manufacturer_string,
|
||||
[STR_IDX_PRODUCT] = (uint8_t *)&product_string,
|
||||
[STR_IDX_SERIAL] = (uint8_t *)&serial_string
|
||||
};
|
||||
|
||||
usb_desc iap_desc = {
|
||||
.dev_desc = (uint8_t *)&iap_dev_desc,
|
||||
.config_desc = (uint8_t *)&iap_config_desc,
|
||||
.strings = usbd_iap_strings
|
||||
};
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint8_t iap_init (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t iap_deinit (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t iap_req_handler (usb_dev *udev, usb_req *req);
|
||||
static void iap_data_out (usb_dev *udev, uint8_t ep_num);
|
||||
|
||||
usb_class iap_class = {
|
||||
.init = iap_init,
|
||||
.deinit = iap_deinit,
|
||||
.req_process = iap_req_handler,
|
||||
.data_out = iap_data_out
|
||||
};
|
||||
|
||||
/* USB custom HID device report descriptor */
|
||||
const uint8_t iap_report_desc[USB_DESC_LEN_IAP_REPORT] =
|
||||
{
|
||||
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
|
||||
0x09, 0x00, /* USAGE (Custom Device) */
|
||||
0xa1, 0x01, /* COLLECTION (Application) */
|
||||
|
||||
/* IAP command and data */
|
||||
0x85, 0x01, /* REPORT_ID (0x01) */
|
||||
0x09, 0x01, /* USAGE (IAP command) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0xff, /* LOGICAL_MAXIMUM (255) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x95, 0x3f, /* REPORT_COUNT (63) */
|
||||
0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vol) */
|
||||
|
||||
/* device status and option byte */
|
||||
0x85, 0x02, /* REPORT_ID (0x02) */
|
||||
0x09, 0x02, /* USAGE (Status and option byte) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0xff, /* LOGICAL_MAXIMUM (255) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x95, 0x10, /* REPORT_COUNT (16) */
|
||||
0x81, 0x82, /* INPUT (Data,Var,Abs,Vol) */
|
||||
|
||||
0xc0 /* END_COLLECTION */
|
||||
};
|
||||
|
||||
/* IAP requests management functions */
|
||||
static void iap_req_erase (usb_dev *udev);
|
||||
static void iap_req_dnload (usb_dev *udev);
|
||||
static void iap_req_optionbyte(usb_dev *udev);
|
||||
static void iap_req_leave (usb_dev *udev);
|
||||
static void iap_address_send (usb_dev *udev);
|
||||
static void iap_data_write (uint8_t *data, uint32_t addr, uint32_t len);
|
||||
|
||||
/*!
|
||||
\brief initialize the HID device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t iap_init (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
static usbd_iap_handler iap_handler;
|
||||
|
||||
/* initialize TX endpoint */
|
||||
usbd_ep_init(udev, EP_BUF_SNG, INT_TX_ADDR, &(iap_config_desc.hid_epin));
|
||||
|
||||
/* initialize RX endpoint */
|
||||
usbd_ep_init(udev, EP_BUF_SNG, INT_RX_ADDR, &(iap_config_desc.hid_epout));
|
||||
|
||||
/* unlock the internal flash */
|
||||
fmc_unlock();
|
||||
|
||||
memset((void *)&iap_handler, 0, sizeof(usbd_iap_handler));
|
||||
|
||||
/* prepare receive Data */
|
||||
usbd_ep_recev(udev, IAP_OUT_EP, iap_handler.report_buf, IAP_OUT_PACKET);
|
||||
|
||||
udev->ep_transc[EP_ID(IAP_OUT_EP)][TRANSC_OUT] = iap_class.data_out;
|
||||
|
||||
iap_handler.base_address = APP_LOADED_ADDR;
|
||||
|
||||
udev->class_data[USBD_IAP_INTERFACE] = (void *)&iap_handler;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief deinitialize the HID device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t iap_deinit (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
/* deinitialize HID endpoints */
|
||||
usbd_ep_deinit (udev, IAP_IN_EP);
|
||||
usbd_ep_deinit (udev, IAP_OUT_EP);
|
||||
|
||||
/* lock the internal flash */
|
||||
fmc_lock();
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the HID class-specific requests
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: device class-specific request
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t iap_req_handler (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
uint8_t status = REQ_NOTSUPP;
|
||||
|
||||
usbd_iap_handler *iap = (usbd_iap_handler *)udev->class_data[USBD_IAP_INTERFACE];
|
||||
|
||||
switch (req->bRequest) {
|
||||
case GET_REPORT:
|
||||
/* no use for this driver */
|
||||
break;
|
||||
|
||||
case GET_IDLE:
|
||||
usb_transc_config(&udev->transc_in[0], (uint8_t *)&iap->idlestate, 1U, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case GET_PROTOCOL:
|
||||
usb_transc_config(&udev->transc_in[0], (uint8_t *)&iap->protocol, 1U, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case SET_REPORT:
|
||||
iap->reportID = (uint8_t)(req->wValue);
|
||||
|
||||
usb_transc_config(&udev->transc_out[0], iap->report_buf, req->wLength, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case SET_IDLE:
|
||||
iap->idlestate = (uint8_t)(req->wValue >> 8);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case SET_PROTOCOL:
|
||||
iap->protocol = (uint8_t)(req->wValue);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case USB_GET_DESCRIPTOR:
|
||||
if (USB_DESCTYPE_REPORT == (req->wValue >> 8)) {
|
||||
usb_transc_config(&udev->transc_in[0],
|
||||
(uint8_t *)iap_report_desc,
|
||||
USB_MIN(USB_DESC_LEN_IAP_REPORT, req->wLength),
|
||||
0U);
|
||||
|
||||
return REQ_SUPP;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle data out stage
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void iap_data_out (usb_dev *udev ,uint8_t ep_num)
|
||||
{
|
||||
usbd_iap_handler *iap = (usbd_iap_handler *)udev->class_data[USBD_IAP_INTERFACE];
|
||||
|
||||
if (0x01U == iap->report_buf[0]) {
|
||||
switch(iap->report_buf[1]) {
|
||||
case IAP_DNLOAD:
|
||||
iap_req_dnload(udev);
|
||||
break;
|
||||
|
||||
case IAP_ERASE:
|
||||
iap_req_erase(udev);
|
||||
break;
|
||||
|
||||
case IAP_OPTION_BYTE:
|
||||
iap_req_optionbyte(udev);
|
||||
break;
|
||||
|
||||
case IAP_LEAVE:
|
||||
iap_req_leave(udev);
|
||||
break;
|
||||
|
||||
case IAP_GETBIN_ADDRESS:
|
||||
iap_address_send(udev);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
usbd_ep_recev(udev, IAP_OUT_EP, iap->report_buf, IAP_OUT_PACKET);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief send IAP report
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] report: pointer to HID report
|
||||
\param[in] len: data length
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
uint8_t iap_report_send (usb_dev *udev, uint8_t *report, uint16_t len)
|
||||
{
|
||||
usbd_ep_send (udev, IAP_IN_EP, report, len);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the IAP_DNLOAD request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void iap_req_dnload (usb_dev *udev)
|
||||
{
|
||||
usbd_iap_handler *iap = (usbd_iap_handler *)udev->class_data[USBD_IAP_INTERFACE];
|
||||
|
||||
if (0U != iap->transfer_times) {
|
||||
if (1U == iap->transfer_times) {
|
||||
if (0U == iap->lps) {
|
||||
iap_data_write(&iap->report_buf[2], iap->base_address, TRANSFER_SIZE);
|
||||
} else {
|
||||
iap_data_write(&iap->report_buf[2], iap->base_address, iap->file_length % TRANSFER_SIZE);
|
||||
iap->lps = 0U;
|
||||
}
|
||||
|
||||
iap->dev_status[0] = 0x02U;
|
||||
iap->dev_status[1] = 0x02U;
|
||||
iap_report_send (udev, iap->dev_status, IAP_IN_PACKET);
|
||||
} else {
|
||||
iap_data_write(&iap->report_buf[2], iap->base_address, TRANSFER_SIZE);
|
||||
|
||||
iap->base_address += TRANSFER_SIZE;
|
||||
}
|
||||
|
||||
iap->transfer_times--;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the IAP_ERASE request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void iap_req_erase (usb_dev *udev)
|
||||
{
|
||||
uint32_t i, addr = 0U;
|
||||
|
||||
usbd_iap_handler *iap = (usbd_iap_handler *)udev->class_data[USBD_IAP_INTERFACE];
|
||||
|
||||
/* get base address to erase */
|
||||
iap->base_address = iap->report_buf[2];
|
||||
iap->base_address |= (uint32_t)iap->report_buf[3] << 8;
|
||||
iap->base_address |= (uint32_t)iap->report_buf[4] << 16;
|
||||
iap->base_address |= (uint32_t)iap->report_buf[5] << 24;
|
||||
|
||||
iap->page_count = iap->report_buf[6];
|
||||
|
||||
/* get file length */
|
||||
iap->file_length = iap->report_buf[7];
|
||||
iap->file_length |= (uint32_t)iap->report_buf[8] << 8;
|
||||
iap->file_length |= (uint32_t)iap->report_buf[9] << 16;
|
||||
iap->file_length |= (uint32_t)iap->report_buf[10] << 24;
|
||||
|
||||
/* compute last packet size and transfer times */
|
||||
iap->lps = iap->file_length % TRANSFER_SIZE;
|
||||
if (0U == iap->lps) {
|
||||
iap->transfer_times = (uint16_t)iap->file_length / TRANSFER_SIZE;
|
||||
} else {
|
||||
iap->transfer_times = (uint16_t)iap->file_length / TRANSFER_SIZE + 1U;
|
||||
}
|
||||
|
||||
/* check if the address is in protected area */
|
||||
if (IS_PROTECTED_AREA(iap->base_address)) {
|
||||
return;
|
||||
}
|
||||
|
||||
addr = iap->base_address;
|
||||
|
||||
for (i = 0U; i < iap->page_count; i ++) {
|
||||
/* call the standard flash erase-page function */
|
||||
fmc_page_erase(addr);
|
||||
|
||||
addr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
iap->dev_status[0] = 0x02U;
|
||||
iap->dev_status[1] = 0x01U;
|
||||
|
||||
usbd_ep_send(udev, IAP_IN_EP, iap->dev_status, IAP_IN_PACKET);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the IAP_OPTION_BYTE request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void iap_req_optionbyte (usb_dev *udev)
|
||||
{
|
||||
uint8_t i = 0U;
|
||||
uint32_t address = 0x1FFFF800U;
|
||||
|
||||
usbd_iap_handler *iap = (usbd_iap_handler *)udev->class_data[USBD_IAP_INTERFACE];
|
||||
|
||||
iap->option_byte[0] = 0x02U;
|
||||
|
||||
for (i = 1U; i < 17U; i++) {
|
||||
iap->option_byte[i] = *(uint8_t *)address;
|
||||
address++;
|
||||
}
|
||||
|
||||
iap_report_send(udev, iap->option_byte, IAP_IN_PACKET);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the IAP_LEAVE request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void iap_req_leave (usb_dev *udev)
|
||||
{
|
||||
/* lock the internal flash */
|
||||
fmc_lock();
|
||||
|
||||
/* generate system reset to allow jumping to the user code */
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the IAP_SEND_ADDRESS request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void iap_address_send(usb_dev *udev)
|
||||
{
|
||||
usbd_iap_handler *iap = (usbd_iap_handler *)udev->class_data[USBD_IAP_INTERFACE];
|
||||
|
||||
iap->bin_addr[0] = 0x02U;
|
||||
|
||||
iap->bin_addr[1] = (uint8_t)(APP_LOADED_ADDR);
|
||||
iap->bin_addr[2] = (uint8_t)(APP_LOADED_ADDR >> 8);
|
||||
iap->bin_addr[3] = (uint8_t)(APP_LOADED_ADDR >> 16);
|
||||
iap->bin_addr[4] = (uint8_t)(APP_LOADED_ADDR >> 24);
|
||||
|
||||
iap_report_send (udev, iap->bin_addr, IAP_IN_PACKET);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief write data to sectors of memory
|
||||
\param[in] data: data to be written
|
||||
\param[in] addr: sector address/code
|
||||
\param[in] len: length of data to be written (in bytes)
|
||||
\param[out] none
|
||||
\retval MAL_OK if all operations are OK, MAL_FAIL else
|
||||
*/
|
||||
static void iap_data_write (uint8_t *data, uint32_t addr, uint32_t len)
|
||||
{
|
||||
uint32_t index = 0U;
|
||||
|
||||
/* check if the address is in protected area */
|
||||
if (IS_PROTECTED_AREA(addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (len & 0x03U) {/* not an aligned data */
|
||||
for (index = len; index < ((len & 0xFFFCU) + 4U); index++) {
|
||||
data[index] = 0xFFU;
|
||||
}
|
||||
}
|
||||
|
||||
/* data received are word multiple */
|
||||
for (index = 0U; index < len; index += 4U) {
|
||||
fmc_word_program(addr, *(uint32_t *)(data + index));
|
||||
addr += 4U;
|
||||
}
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/*!
|
||||
\file usbd_msc_bbb.h
|
||||
\brief the header file of the usbd_msc_bot.c file
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USBD_MSC_BBB_H
|
||||
#define __USBD_MSC_BBB_H
|
||||
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_msc_mem.h"
|
||||
#include "usbd_msc_scsi.h"
|
||||
|
||||
#define BBB_CBW_SIGNATURE 0x43425355U
|
||||
#define BBB_CSW_SIGNATURE 0x53425355U
|
||||
#define BBB_CBW_LENGTH 31U
|
||||
#define BBB_CSW_LENGTH 13U
|
||||
|
||||
typedef struct {
|
||||
uint32_t dCBWSignature;
|
||||
uint32_t dCBWTag;
|
||||
uint32_t dCBWDataTransferLength;
|
||||
uint8_t bmCBWFlags;
|
||||
uint8_t bCBWLUN;
|
||||
uint8_t bCBWCBLength;
|
||||
uint8_t CBWCB[16];
|
||||
}msc_bbb_cbw;
|
||||
|
||||
typedef struct {
|
||||
uint32_t dCSWSignature;
|
||||
uint32_t dCSWTag;
|
||||
uint32_t dCSWDataResidue;
|
||||
uint8_t bCSWStatus;
|
||||
}msc_bbb_csw;
|
||||
|
||||
/* CSW command status */
|
||||
enum msc_csw_status {
|
||||
CSW_CMD_PASSED = 0,
|
||||
CSW_CMD_FAILED,
|
||||
CSW_PHASE_ERROR
|
||||
};
|
||||
|
||||
/* MSC BBB state */
|
||||
enum msc_bbb_state {
|
||||
BBB_IDLE = 0U, /*!< idle state */
|
||||
BBB_DATA_OUT, /*!< data OUT state */
|
||||
BBB_DATA_IN, /*!< data IN state */
|
||||
BBB_LAST_DATA_IN, /*!< last data IN state */
|
||||
BBB_SEND_DATA /*!< send immediate data state */
|
||||
};
|
||||
|
||||
/* MSC BBB status */
|
||||
enum msc_bbb_status {
|
||||
BBB_STATUS_NORMAL = 0U, /*!< normal status */
|
||||
BBB_STATUS_RECOVERY, /*!< recovery status*/
|
||||
BBB_STATUS_ERROR /*!< error status */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bbb_data[MSC_MEDIA_PACKET_SIZE];
|
||||
|
||||
uint8_t max_lun;
|
||||
uint8_t bbb_state;
|
||||
uint8_t bbb_status;
|
||||
|
||||
uint32_t bbb_datalen;
|
||||
|
||||
msc_bbb_cbw bbb_cbw;
|
||||
msc_bbb_csw bbb_csw;
|
||||
|
||||
uint8_t scsi_sense_head;
|
||||
uint8_t scsi_sense_tail;
|
||||
|
||||
uint32_t scsi_blk_size[MEM_LUN_NUM];
|
||||
uint32_t scsi_blk_nbr[MEM_LUN_NUM];
|
||||
|
||||
uint32_t scsi_blk_addr;
|
||||
uint32_t scsi_blk_len;
|
||||
// uint32_t scsi_disk_pop;
|
||||
|
||||
msc_scsi_sense scsi_sense[SENSE_LIST_DEEPTH];
|
||||
} usbd_msc_handler;
|
||||
|
||||
/* function declarations */
|
||||
/* initialize the bbb process */
|
||||
void msc_bbb_init (usb_dev *udev);
|
||||
/* reset the BBB machine */
|
||||
void msc_bbb_reset (usb_dev *udev);
|
||||
/* deinitialize the BBB machine */
|
||||
void msc_bbb_deinit (usb_dev *udev);
|
||||
/* handle BBB data IN stage */
|
||||
void msc_bbb_data_in (usb_dev *udev, uint8_t ep_num);
|
||||
/* handle BBB data OUT stage */
|
||||
void msc_bbb_data_out (usb_dev *udev, uint8_t ep_num);
|
||||
/* send the CSW(command status wrapper) */
|
||||
void msc_bbb_csw_send (usb_dev *udev, uint8_t csw_status);
|
||||
/* complete the clear feature request */
|
||||
void msc_bbb_clrfeature (usb_dev *udev, uint8_t ep_num);
|
||||
|
||||
#endif /* __USBD_MSC_BBB_H */
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*!
|
||||
\file usbd_msc_core.h
|
||||
\brief the header file of USB MSC device class core functions
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USBD_MSC_CORE_H
|
||||
#define __USBD_MSC_CORE_H
|
||||
|
||||
#include "usbd_core.h"
|
||||
|
||||
/* mass storage device class code */
|
||||
#define USB_CLASS_MSC 0x08U
|
||||
|
||||
/* mass storage subclass code */
|
||||
#define USB_MSC_SUBCLASS_RBC 0x01U
|
||||
#define USB_MSC_SUBCLASS_ATAPI 0x02U
|
||||
#define USB_MSC_SUBCLASS_UFI 0x04U
|
||||
#define USB_MSC_SUBCLASS_SCSI 0x06U
|
||||
#define USB_MSC_SUBCLASS_LOCKABLE 0x07U
|
||||
#define USB_MSC_SUBCLASS_IEEE1667 0x08U
|
||||
|
||||
/* mass storage interface class control protocol codes */
|
||||
#define USB_MSC_PROTOCOL_CBI 0x00U
|
||||
#define USB_MSC_PROTOCOL_CBI_ALT 0x01U
|
||||
#define USB_MSC_PROTOCOL_BBB 0x50U
|
||||
|
||||
/* mass storage request codes */
|
||||
#define USB_MSC_REQ_CODES_ADSC 0x00U
|
||||
#define USB_MSC_REQ_CODES_GET 0xFCU
|
||||
#define USB_MSC_REQ_CODES_PUT 0xFDU
|
||||
#define USB_MSC_REQ_CODES_GML 0xFEU
|
||||
#define USB_MSC_REQ_CODES_BOMSR 0xFFU
|
||||
|
||||
/* mass storage class-specific request codes */
|
||||
#define BBB_GET_MAX_LUN 0xFEU
|
||||
#define BBB_RESET 0xFFU
|
||||
|
||||
#define USB_MSC_CONFIG_DESC_SIZE 32U
|
||||
|
||||
#define MSC_EPIN_SIZE MSC_DATA_PACKET_SIZE
|
||||
#define MSC_EPOUT_SIZE MSC_DATA_PACKET_SIZE
|
||||
|
||||
/* USB configuration descriptor structure */
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_config config;
|
||||
|
||||
usb_desc_itf msc_itf;
|
||||
usb_desc_ep msc_epin;
|
||||
usb_desc_ep msc_epout;
|
||||
} usb_desc_config_set;
|
||||
|
||||
extern usb_desc msc_desc;
|
||||
extern usb_class msc_class;
|
||||
|
||||
#endif /* __USBD_MSC_CORE_H */
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*!
|
||||
\file usbd_msc_data.h
|
||||
\brief the header file of the usbd_msc_data.c file
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USBD_MSC_DATA_H
|
||||
#define __USBD_MSC_DATA_H
|
||||
|
||||
#include "usbd_conf.h"
|
||||
|
||||
#define MODE_SENSE6_LENGTH 8U
|
||||
#define MODE_SENSE10_LENGTH 8U
|
||||
#define INQUIRY_PAGE00_LENGTH 96U
|
||||
#define FORMAT_CAPACITIES_LENGTH 20U
|
||||
|
||||
extern const uint8_t msc_page00_inquiry_data[];
|
||||
extern const uint8_t msc_mode_sense6_data[];
|
||||
extern const uint8_t msc_mode_sense10_data[];
|
||||
|
||||
#endif /* __USBD_MSC_DATA_H */
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*!
|
||||
\file usbd_msc_mem.h
|
||||
\brief header file for storage memory
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USBD_MSC_MEM_H
|
||||
#define __USBD_MSC_MEM_H
|
||||
|
||||
#include "usbd_conf.h"
|
||||
|
||||
#define USBD_STD_INQUIRY_LENGTH 36U
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int8_t (*mem_init) (uint8_t lun);
|
||||
int8_t (*mem_ready) (uint8_t lun);
|
||||
int8_t (*mem_protected) (uint8_t lun);
|
||||
int8_t (*mem_read) (uint8_t lun, uint8_t *buf, uint32_t block_addr, uint16_t block_len);
|
||||
int8_t (*mem_write) (uint8_t lun, uint8_t *buf, uint32_t block_addr, uint16_t block_len);
|
||||
int8_t (*mem_maxlun) (void);
|
||||
|
||||
uint8_t *mem_toc_data;
|
||||
uint8_t *mem_inquiry_data[MEM_LUN_NUM];
|
||||
uint32_t mem_block_size[MEM_LUN_NUM];
|
||||
uint32_t mem_block_len[MEM_LUN_NUM];
|
||||
}usbd_mem_cb;
|
||||
|
||||
extern usbd_mem_cb *usbd_mem_fops;
|
||||
|
||||
#endif /* __USBD_MSC_MEM_H */
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/*!
|
||||
\file usbd_msc_scsi.h
|
||||
\brief the header file of the usbd_msc_scsi.c file
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USBD_MSC_SCSI_H
|
||||
#define __USBD_MSC_SCSI_H
|
||||
|
||||
#include "usbd_msc_data.h"
|
||||
#include "usbd_msc_bbb.h"
|
||||
|
||||
#define SENSE_LIST_DEEPTH 4U
|
||||
|
||||
/* SCSI commands */
|
||||
#define SCSI_FORMAT_UNIT 0x04U
|
||||
#define SCSI_INQUIRY 0x12U
|
||||
#define SCSI_MODE_SELECT6 0x15U
|
||||
#define SCSI_MODE_SELECT10 0x55U
|
||||
#define SCSI_MODE_SENSE6 0x1AU
|
||||
#define SCSI_READ_TOC_DATA 0x43U
|
||||
#define SCSI_MODE_SENSE10 0x5AU
|
||||
#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1EU
|
||||
#define SCSI_READ6 0x08U
|
||||
#define SCSI_READ10 0x28U
|
||||
#define SCSI_READ12 0xA8U
|
||||
#define SCSI_READ16 0x88U
|
||||
|
||||
#define SCSI_READ_CAPACITY10 0x25U
|
||||
#define SCSI_READ_CAPACITY16 0x9EU
|
||||
|
||||
#define SCSI_REQUEST_SENSE 0x03U
|
||||
#define SCSI_START_STOP_UNIT 0x1BU
|
||||
#define SCSI_TEST_UNIT_READY 0x00U
|
||||
#define SCSI_WRITE6 0x0AU
|
||||
#define SCSI_WRITE10 0x2AU
|
||||
#define SCSI_WRITE12 0xAAU
|
||||
#define SCSI_WRITE16 0x8AU
|
||||
|
||||
#define SCSI_VERIFY10 0x2FU
|
||||
#define SCSI_VERIFY12 0xAFU
|
||||
#define SCSI_VERIFY16 0x8FU
|
||||
|
||||
#define SCSI_SEND_DIAGNOSTIC 0x1DU
|
||||
#define SCSI_READ_FORMAT_CAPACITIES 0x23U
|
||||
|
||||
#define INVALID_CDB 0x20U
|
||||
#define INVALID_FIELED_IN_COMMAND 0x24U
|
||||
#define PARAMETER_LIST_LENGTH_ERROR 0x1AU
|
||||
#define INVALID_FIELD_IN_PARAMETER_LIST 0x26U
|
||||
#define ADDRESS_OUT_OF_RANGE 0x21U
|
||||
#define MEDIUM_NOT_PRESENT 0x3AU
|
||||
#define MEDIUM_HAVE_CHANGED 0x28U
|
||||
#define WRITE_PROTECTED 0x27U
|
||||
#define UNRECOVERED_READ_ERROR 0x11U
|
||||
#define WRITE_FAULT 0x03U
|
||||
|
||||
#define READ_FORMAT_CAPACITY_DATA_LEN 0x0CU
|
||||
#define READ_CAPACITY10_DATA_LEN 0x08U
|
||||
#define MODE_SENSE10_DATA_LEN 0x08U
|
||||
#define MODE_SENSE6_DATA_LEN 0x04U
|
||||
#define READ_TOC_CMD_LEN 0x14U
|
||||
#define REQUEST_SENSE_DATA_LEN 0x12U
|
||||
#define STANDARD_INQUIRY_DATA_LEN 0x24U
|
||||
#define BLKVFY 0x04U
|
||||
|
||||
enum sense_state {
|
||||
NO_SENSE = 0U,
|
||||
RECOVERED_ERROR,
|
||||
NOT_READY,
|
||||
MEDIUM_ERROR,
|
||||
HARDWARE_ERROR,
|
||||
ILLEGAL_REQUEST,
|
||||
UNIT_ATTENTION,
|
||||
DATA_PROTECT,
|
||||
BLANK_CHECK,
|
||||
VENDOR_SPECIFIC,
|
||||
COPY_ABORTED,
|
||||
ABORTED_COMMAND,
|
||||
RESERVED,
|
||||
VOLUME_OVERFLOW,
|
||||
MISCOMPARE
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t SenseKey;
|
||||
uint32_t Information;
|
||||
uint8_t ASC;
|
||||
uint8_t ASCQ;
|
||||
} msc_scsi_sense;
|
||||
|
||||
/* function declarations */
|
||||
/* process SCSI commands */
|
||||
int8_t scsi_process_cmd (usb_dev *udev, uint8_t lun, uint8_t *cmd);
|
||||
/* load the last error code in the error list */
|
||||
void scsi_sense_code (usb_dev *udev, uint8_t lun, uint8_t skey, uint8_t asc);
|
||||
|
||||
#endif /* __USBD_MSC_SCSI_H */
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
/*!
|
||||
\file usbd_msc_bbb.c
|
||||
\brief USB BBB(Bulk/Bulk/Bulk) protocol core functions
|
||||
\note BBB means Bulk-only transport protocol for USB MSC
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_enum.h"
|
||||
#include "usbd_msc_bbb.h"
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static void msc_bbb_cbw_decode (usb_dev *udev);
|
||||
static void msc_bbb_data_send (usb_dev *udev, uint8_t *pbuf, uint32_t Len);
|
||||
static void msc_bbb_abort (usb_dev *udev);
|
||||
|
||||
/*!
|
||||
\brief initialize the bbb process
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void msc_bbb_init (usb_dev *udev)
|
||||
{
|
||||
uint8_t lun_num;
|
||||
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->bbb_state = BBB_IDLE;
|
||||
msc->bbb_status = BBB_STATUS_NORMAL;
|
||||
|
||||
/* initializes the storage logic unit */
|
||||
for(lun_num = 0U; lun_num < MEM_LUN_NUM; lun_num++) {
|
||||
usbd_mem_fops->mem_init(lun_num);
|
||||
}
|
||||
|
||||
/* prepare endpoint to receive the first BBB CBW */
|
||||
usbd_ep_recev (udev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reset the BBB machine
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void msc_bbb_reset (usb_dev *udev)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->bbb_state = BBB_IDLE;
|
||||
msc->bbb_status = BBB_STATUS_RECOVERY;
|
||||
|
||||
/* prepare endpoint to receive the first BBB command */
|
||||
usbd_ep_recev (udev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief deinitialize the BBB machine
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void msc_bbb_deinit (usb_dev *udev)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->bbb_state = BBB_IDLE;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle BBB data IN stage
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void msc_bbb_data_in (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
switch (msc->bbb_state) {
|
||||
case BBB_DATA_IN:
|
||||
if (scsi_process_cmd (udev, msc->bbb_cbw.bCBWLUN, &msc->bbb_cbw.CBWCB[0]) < 0) {
|
||||
msc_bbb_csw_send (udev, CSW_CMD_FAILED);
|
||||
}
|
||||
break;
|
||||
|
||||
case BBB_SEND_DATA:
|
||||
case BBB_LAST_DATA_IN:
|
||||
msc_bbb_csw_send (udev, CSW_CMD_PASSED);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle BBB data OUT stage
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void msc_bbb_data_out (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
switch (msc->bbb_state) {
|
||||
case BBB_IDLE:
|
||||
msc_bbb_cbw_decode (udev);
|
||||
break;
|
||||
|
||||
case BBB_DATA_OUT:
|
||||
if (scsi_process_cmd (udev, msc->bbb_cbw.bCBWLUN, &msc->bbb_cbw.CBWCB[0]) < 0) {
|
||||
msc_bbb_csw_send (udev, CSW_CMD_FAILED);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief send the CSW(command status wrapper)
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] csw_status: CSW status
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void msc_bbb_csw_send (usb_dev *udev, uint8_t csw_status)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->bbb_csw.dCSWSignature = BBB_CSW_SIGNATURE;
|
||||
msc->bbb_csw.bCSWStatus = csw_status;
|
||||
msc->bbb_state = BBB_IDLE;
|
||||
|
||||
usbd_ep_send (udev, MSC_IN_EP, (uint8_t *)&msc->bbb_csw, BBB_CSW_LENGTH);
|
||||
|
||||
/* prepare endpoint to receive next command */
|
||||
usbd_ep_recev (udev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief complete the clear feature request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void msc_bbb_clrfeature (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
if (msc->bbb_status == BBB_STATUS_ERROR)/* bad CBW signature */ {
|
||||
usbd_ep_stall(udev, MSC_IN_EP);
|
||||
|
||||
msc->bbb_status = BBB_STATUS_NORMAL;
|
||||
} else if(((ep_num & 0x80U) == 0x80U) && (msc->bbb_status != BBB_STATUS_RECOVERY)) {
|
||||
msc_bbb_csw_send (udev, CSW_CMD_FAILED);
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief decode the CBW command and set the BBB state machine accordingly
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void msc_bbb_cbw_decode (usb_dev *udev)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
uint16_t rx_len = udev->transc_out[MSC_OUT_EP].xfer_count;
|
||||
|
||||
msc->bbb_csw.dCSWTag = msc->bbb_cbw.dCBWTag;
|
||||
msc->bbb_csw.dCSWDataResidue = msc->bbb_cbw.dCBWDataTransferLength;
|
||||
|
||||
if ((BBB_CBW_LENGTH != rx_len) ||
|
||||
(BBB_CBW_SIGNATURE != msc->bbb_cbw.dCBWSignature)||
|
||||
(msc->bbb_cbw.bCBWLUN > 1U) ||
|
||||
(msc->bbb_cbw.bCBWCBLength < 1U) ||
|
||||
(msc->bbb_cbw.bCBWCBLength > 16U)) {
|
||||
/* illegal command handler */
|
||||
scsi_sense_code (udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
|
||||
|
||||
msc->bbb_status = BBB_STATUS_ERROR;
|
||||
|
||||
msc_bbb_abort (udev);
|
||||
} else {
|
||||
if (scsi_process_cmd (udev, msc->bbb_cbw.bCBWLUN, &msc->bbb_cbw.CBWCB[0]) < 0) {
|
||||
msc_bbb_abort (udev);
|
||||
} else if ((BBB_DATA_IN != msc->bbb_state) &&
|
||||
(BBB_DATA_OUT != msc->bbb_state) &&
|
||||
(BBB_LAST_DATA_IN != msc->bbb_state)) { /* burst xfer handled internally */
|
||||
if (msc->bbb_datalen > 0U) {
|
||||
msc_bbb_data_send (udev, msc->bbb_data, msc->bbb_datalen);
|
||||
} else if (0U == msc->bbb_datalen) {
|
||||
msc_bbb_csw_send (udev, CSW_CMD_PASSED);
|
||||
} else {
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief send the requested data
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] buf: pointer to data buffer
|
||||
\param[in] len: data length
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void msc_bbb_data_send (usb_dev *udev, uint8_t *buf, uint32_t len)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
len = USB_MIN (msc->bbb_cbw.dCBWDataTransferLength, len);
|
||||
|
||||
msc->bbb_csw.dCSWDataResidue -= len;
|
||||
msc->bbb_csw.bCSWStatus = CSW_CMD_PASSED;
|
||||
msc->bbb_state = BBB_SEND_DATA;
|
||||
|
||||
usbd_ep_send (udev, MSC_IN_EP, buf, len);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief abort the current transfer
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void msc_bbb_abort (usb_dev *udev)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
if ((0U == msc->bbb_cbw.bmCBWFlags) &&
|
||||
(0U != msc->bbb_cbw.dCBWDataTransferLength) &&
|
||||
(BBB_STATUS_NORMAL == msc->bbb_status)) {
|
||||
usbd_ep_stall(udev, MSC_OUT_EP);
|
||||
}
|
||||
|
||||
usbd_ep_stall(udev, MSC_IN_EP);
|
||||
|
||||
if (msc->bbb_status == BBB_STATUS_ERROR) {
|
||||
usbd_ep_recev (udev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
|
||||
}
|
||||
}
|
||||
+316
@@ -0,0 +1,316 @@
|
||||
/*!
|
||||
\file usbd_msc_core.c
|
||||
\brief USB MSC device class core functions
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
\version 2020-12-07, V3.0.1, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_enum.h"
|
||||
#include "usbd_msc_bbb.h"
|
||||
#include "usbd_msc_core.h"
|
||||
#include "usbd_transc.h"
|
||||
#include <string.h>
|
||||
|
||||
#define USBD_VID 0x28E9U
|
||||
#define USBD_PID 0x128FU
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint8_t msc_core_init (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t msc_core_deinit (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t msc_core_req (usb_dev *udev, usb_req *req);
|
||||
static void msc_core_in (usb_dev *udev, uint8_t ep_num);
|
||||
static void msc_core_out (usb_dev *udev, uint8_t ep_num);
|
||||
|
||||
usb_class msc_class =
|
||||
{
|
||||
.init = msc_core_init,
|
||||
.deinit = msc_core_deinit,
|
||||
|
||||
.req_process = msc_core_req,
|
||||
|
||||
.data_in = msc_core_in,
|
||||
.data_out = msc_core_out
|
||||
};
|
||||
|
||||
/* note: it should use the C99 standard when compiling the below codes */
|
||||
/* USB standard device descriptor */
|
||||
const usb_desc_dev msc_dev_desc =
|
||||
{
|
||||
.header = {
|
||||
.bLength = USB_DEV_DESC_LEN,
|
||||
.bDescriptorType = USB_DESCTYPE_DEV
|
||||
},
|
||||
.bcdUSB = 0x0200U,
|
||||
.bDeviceClass = 0x00U,
|
||||
.bDeviceSubClass = 0x00U,
|
||||
.bDeviceProtocol = 0x00U,
|
||||
.bMaxPacketSize0 = USBD_EP0_MAX_SIZE,
|
||||
.idVendor = USBD_VID,
|
||||
.idProduct = USBD_PID,
|
||||
.bcdDevice = 0x0100U,
|
||||
.iManufacturer = STR_IDX_MFC,
|
||||
.iProduct = STR_IDX_PRODUCT,
|
||||
.iSerialNumber = STR_IDX_SERIAL,
|
||||
.bNumberConfigurations = USBD_CFG_MAX_NUM
|
||||
};
|
||||
|
||||
/* USB device configuration descriptor */
|
||||
const usb_desc_config_set msc_config_desc =
|
||||
{
|
||||
.config =
|
||||
{
|
||||
.header = {
|
||||
.bLength = sizeof(usb_desc_config),
|
||||
.bDescriptorType = USB_DESCTYPE_CONFIG
|
||||
},
|
||||
.wTotalLength = USB_MSC_CONFIG_DESC_SIZE,
|
||||
.bNumInterfaces = 0x01U,
|
||||
.bConfigurationValue = 0x01U,
|
||||
.iConfiguration = 0x00U,
|
||||
.bmAttributes = 0xC0U,
|
||||
.bMaxPower = 0x32U
|
||||
},
|
||||
|
||||
.msc_itf =
|
||||
{
|
||||
.header = {
|
||||
.bLength = sizeof(usb_desc_itf),
|
||||
.bDescriptorType = USB_DESCTYPE_ITF
|
||||
},
|
||||
.bInterfaceNumber = 0x00U,
|
||||
.bAlternateSetting = 0x00U,
|
||||
.bNumEndpoints = 0x02U,
|
||||
.bInterfaceClass = USB_CLASS_MSC,
|
||||
.bInterfaceSubClass = USB_MSC_SUBCLASS_SCSI,
|
||||
.bInterfaceProtocol = USB_MSC_PROTOCOL_BBB,
|
||||
.iInterface = 0x00U
|
||||
},
|
||||
|
||||
.msc_epin =
|
||||
{
|
||||
.header = {
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP
|
||||
},
|
||||
.bEndpointAddress = MSC_IN_EP,
|
||||
.bmAttributes = USB_EP_ATTR_BULK,
|
||||
.wMaxPacketSize = MSC_EPIN_SIZE,
|
||||
.bInterval = 0x00U
|
||||
},
|
||||
|
||||
.msc_epout =
|
||||
{
|
||||
.header = {
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP
|
||||
},
|
||||
.bEndpointAddress = MSC_OUT_EP,
|
||||
.bmAttributes = USB_EP_ATTR_BULK,
|
||||
.wMaxPacketSize = MSC_EPOUT_SIZE,
|
||||
.bInterval = 0x00U
|
||||
}
|
||||
};
|
||||
|
||||
/* USB language ID descriptor */
|
||||
const usb_desc_LANGID usbd_language_id_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_LANGID),
|
||||
.bDescriptorType = USB_DESCTYPE_STR
|
||||
},
|
||||
.wLANGID = ENG_LANGID
|
||||
};
|
||||
|
||||
/* USB manufacture string */
|
||||
static const usb_desc_str manufacturer_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(10U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
|
||||
};
|
||||
|
||||
/* USB product string */
|
||||
static const usb_desc_str product_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(12U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'M', 'S', 'C'}
|
||||
};
|
||||
|
||||
/* USBD serial string */
|
||||
static usb_desc_str serial_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(12U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
}
|
||||
};
|
||||
|
||||
/* USB string descriptor */
|
||||
uint8_t* usbd_msc_strings[] =
|
||||
{
|
||||
[STR_IDX_LANGID] = (uint8_t *)&usbd_language_id_desc,
|
||||
[STR_IDX_MFC] = (uint8_t *)&manufacturer_string,
|
||||
[STR_IDX_PRODUCT] = (uint8_t *)&product_string,
|
||||
[STR_IDX_SERIAL] = (uint8_t *)&serial_string
|
||||
};
|
||||
|
||||
usb_desc msc_desc = {
|
||||
.dev_desc = (uint8_t *)&msc_dev_desc,
|
||||
.config_desc = (uint8_t *)&msc_config_desc,
|
||||
.strings = usbd_msc_strings
|
||||
};
|
||||
|
||||
static uint8_t usbd_msc_maxlun = 0U;
|
||||
|
||||
/*!
|
||||
\brief initialize the MSC device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t msc_core_init (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
static usbd_msc_handler msc_handler;
|
||||
|
||||
memset((void *)&msc_handler, 0U, sizeof(usbd_msc_handler));
|
||||
|
||||
udev->class_data[USBD_MSC_INTERFACE] = (void *)&msc_handler;
|
||||
|
||||
/* initialize Tx endpoint */
|
||||
usbd_ep_init(udev, EP_BUF_SNG, BULK_TX_ADDR, &(msc_config_desc.msc_epin));
|
||||
|
||||
/* initialize Rx endpoint */
|
||||
usbd_ep_init(udev, EP_BUF_SNG, BULK_RX_ADDR, &(msc_config_desc.msc_epout));
|
||||
|
||||
udev->ep_transc[EP_ID(MSC_IN_EP)][TRANSC_IN] = msc_class.data_in;
|
||||
udev->ep_transc[MSC_OUT_EP][TRANSC_OUT] = msc_class.data_out;
|
||||
|
||||
/* initialize the BBB layer */
|
||||
msc_bbb_init(udev);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief deinitialize the MSC device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t msc_core_deinit (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
/* clear MSC endpoints */
|
||||
usbd_ep_deinit (udev, MSC_IN_EP);
|
||||
usbd_ep_deinit (udev, MSC_OUT_EP);
|
||||
|
||||
/* deinitialize the BBB layer */
|
||||
msc_bbb_deinit(udev);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the MSC class-specific and standard requests
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: device class-specific request
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t msc_core_req (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
switch (req->bRequest) {
|
||||
case BBB_GET_MAX_LUN :
|
||||
if((0U == req->wValue) &&
|
||||
(1U == req->wLength) &&
|
||||
(0x80U == (req->bmRequestType & 0x80U))) {
|
||||
usbd_msc_maxlun = (uint8_t)usbd_mem_fops->mem_maxlun();
|
||||
|
||||
usb_transc_config(&udev->transc_in[0], &usbd_msc_maxlun, 1U, 0U);
|
||||
} else {
|
||||
return USBD_FAIL;
|
||||
}
|
||||
break;
|
||||
|
||||
case BBB_RESET :
|
||||
if((0U == req->wValue) &&
|
||||
(0U == req->wLength) &&
|
||||
(0x80U != (req->bmRequestType & 0x80U))) {
|
||||
msc_bbb_reset(udev);
|
||||
} else {
|
||||
return USBD_FAIL;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_CLEAR_FEATURE:
|
||||
msc_bbb_clrfeature (udev, (uint8_t)req->wIndex);
|
||||
break;
|
||||
|
||||
default:
|
||||
return USBD_FAIL;
|
||||
}
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle data in stage
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: the endpoint number
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void msc_core_in (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
msc_bbb_data_in(udev, ep_num);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle data out stage
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: the endpoint number
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void msc_core_out (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
msc_bbb_data_out (udev, ep_num);
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*!
|
||||
\file usbd_msc_data.c
|
||||
\brief USB MSC vital inquiry pages and sense data
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_msc_data.h"
|
||||
|
||||
/* USB mass storage page 0 inquiry data */
|
||||
const uint8_t msc_page00_inquiry_data[] =
|
||||
{
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U,
|
||||
(INQUIRY_PAGE00_LENGTH - 4U),
|
||||
0x80U,
|
||||
0x83U,
|
||||
};
|
||||
|
||||
/* USB mass storage sense 6 data */
|
||||
const uint8_t msc_mode_sense6_data[] =
|
||||
{
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U
|
||||
};
|
||||
|
||||
/* USB mass storage sense 10 data */
|
||||
const uint8_t msc_mode_sense10_data[] =
|
||||
{
|
||||
0x00U,
|
||||
0x06U,
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U,
|
||||
0x00U
|
||||
};
|
||||
+728
@@ -0,0 +1,728 @@
|
||||
/*!
|
||||
\file usbd_msc_scsi.c
|
||||
\brief USB SCSI layer functions
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_enum.h"
|
||||
#include "usbd_msc_bbb.h"
|
||||
#include "usbd_msc_scsi.h"
|
||||
#include "usbd_msc_data.h"
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static int8_t scsi_test_unit_ready (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_mode_select6 (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_mode_select10 (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_inquiry (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_read_format_capacity (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_read_capacity10 (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_request_sense (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_mode_sense6 (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_toc_cmd_read (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_mode_sense10 (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_write10 (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_read10 (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static int8_t scsi_verify10 (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
|
||||
static int8_t scsi_process_read (usb_dev *udev, uint8_t lun);
|
||||
static int8_t scsi_process_write (usb_dev *udev, uint8_t lun);
|
||||
|
||||
static inline int8_t scsi_check_address_range (usb_dev *udev, uint8_t lun, uint32_t blk_offset, uint16_t blk_nbr);
|
||||
static inline int8_t scsi_format_cmd (usb_dev *udev, uint8_t lun);
|
||||
static inline int8_t scsi_start_stop_unit (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
static inline int8_t scsi_allow_medium_removal (usb_dev *udev, uint8_t lun, uint8_t *params);
|
||||
|
||||
/*!
|
||||
\brief process SCSI commands
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
int8_t scsi_process_cmd(usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
switch (params[0]) {
|
||||
case SCSI_TEST_UNIT_READY:
|
||||
return scsi_test_unit_ready (udev, lun, params);
|
||||
|
||||
case SCSI_REQUEST_SENSE:
|
||||
return scsi_request_sense (udev, lun, params);
|
||||
|
||||
case SCSI_INQUIRY:
|
||||
return scsi_inquiry (udev, lun, params);
|
||||
|
||||
case SCSI_START_STOP_UNIT:
|
||||
return scsi_start_stop_unit (udev, lun, params);
|
||||
|
||||
case SCSI_ALLOW_MEDIUM_REMOVAL:
|
||||
return scsi_allow_medium_removal (udev, lun, params);
|
||||
|
||||
case SCSI_MODE_SENSE6:
|
||||
return scsi_mode_sense6 (udev, lun, params);
|
||||
|
||||
case SCSI_MODE_SENSE10:
|
||||
return scsi_mode_sense10 (udev, lun, params);
|
||||
|
||||
case SCSI_READ_FORMAT_CAPACITIES:
|
||||
return scsi_read_format_capacity (udev, lun, params);
|
||||
|
||||
case SCSI_READ_CAPACITY10:
|
||||
return scsi_read_capacity10 (udev, lun, params);
|
||||
|
||||
case SCSI_READ10:
|
||||
return scsi_read10 (udev, lun, params);
|
||||
|
||||
case SCSI_WRITE10:
|
||||
return scsi_write10 (udev, lun, params);
|
||||
|
||||
case SCSI_VERIFY10:
|
||||
return scsi_verify10 (udev, lun, params);
|
||||
|
||||
case SCSI_FORMAT_UNIT:
|
||||
return scsi_format_cmd (udev, lun);
|
||||
|
||||
case SCSI_READ_TOC_DATA:
|
||||
return scsi_toc_cmd_read (udev, lun, params);
|
||||
|
||||
case SCSI_MODE_SELECT6:
|
||||
return scsi_mode_select6 (udev, lun, params);
|
||||
|
||||
case SCSI_MODE_SELECT10:
|
||||
return scsi_mode_select10 (udev, lun, params);
|
||||
|
||||
default:
|
||||
scsi_sense_code (udev, lun, ILLEGAL_REQUEST, INVALID_CDB);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief load the last error code in the error list
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] skey: sense key
|
||||
\param[in] asc: additional sense key
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void scsi_sense_code (usb_dev *udev, uint8_t lun, uint8_t skey, uint8_t asc)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->scsi_sense[msc->scsi_sense_tail].SenseKey = skey;
|
||||
msc->scsi_sense[msc->scsi_sense_tail].ASC = asc << 8U;
|
||||
msc->scsi_sense_tail++;
|
||||
|
||||
if (SENSE_LIST_DEEPTH == msc->scsi_sense_tail) {
|
||||
msc->scsi_sense_tail = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process SCSI Test Unit Ready command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_test_unit_ready (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
/* case 9 : Hi > D0 */
|
||||
if (0U != msc->bbb_cbw.dCBWDataTransferLength) {
|
||||
scsi_sense_code (udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 != usbd_mem_fops->mem_ready(lun)) {
|
||||
scsi_sense_code(udev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if (1U == msc->scsi_disk_pop) {
|
||||
// usbd_disconnect (udev);
|
||||
// }
|
||||
|
||||
msc->bbb_datalen = 0U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Inquiry command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_mode_select6 (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->bbb_datalen = 0U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Inquiry command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_mode_select10 (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->bbb_datalen = 0U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Inquiry command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_inquiry (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
uint8_t *page = NULL;
|
||||
uint16_t len = 0U;
|
||||
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
if (params[1] & 0x01U) {
|
||||
page = (uint8_t *)msc_page00_inquiry_data;
|
||||
|
||||
len = INQUIRY_PAGE00_LENGTH;
|
||||
} else {
|
||||
page = (uint8_t *)usbd_mem_fops->mem_inquiry_data[lun];
|
||||
|
||||
len = (uint16_t)(page[4] + 5U);
|
||||
|
||||
if (params[4] <= len) {
|
||||
len = params[4];
|
||||
}
|
||||
}
|
||||
|
||||
msc->bbb_datalen = len;
|
||||
|
||||
while (len) {
|
||||
len--;
|
||||
msc->bbb_data[len] = page[len];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Read Capacity 10 command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_read_capacity10 (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
uint32_t blk_num = usbd_mem_fops->mem_block_len[lun] - 1U;
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->scsi_blk_nbr[lun] = usbd_mem_fops->mem_block_len[lun];
|
||||
msc->scsi_blk_size[lun] = usbd_mem_fops->mem_block_size[lun];
|
||||
|
||||
msc->bbb_data[0] = (uint8_t)(blk_num >> 24U);
|
||||
msc->bbb_data[1] = (uint8_t)(blk_num >> 16U);
|
||||
msc->bbb_data[2] = (uint8_t)(blk_num >> 8U);
|
||||
msc->bbb_data[3] = (uint8_t)(blk_num);
|
||||
|
||||
msc->bbb_data[4] = (uint8_t)(msc->scsi_blk_size[lun] >> 24U);
|
||||
msc->bbb_data[5] = (uint8_t)(msc->scsi_blk_size[lun] >> 16U);
|
||||
msc->bbb_data[6] = (uint8_t)(msc->scsi_blk_size[lun] >> 8U);
|
||||
msc->bbb_data[7] = (uint8_t)(msc->scsi_blk_size[lun]);
|
||||
|
||||
msc->bbb_datalen = 8U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Read Format Capacity command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_read_format_capacity (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
uint16_t i = 0U;
|
||||
uint32_t blk_size = usbd_mem_fops->mem_block_size[lun];
|
||||
uint32_t blk_num = usbd_mem_fops->mem_block_len[lun];
|
||||
uint32_t blk_nbr = blk_num - 1U;
|
||||
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
for (i = 0U; i < 12U; i++) {
|
||||
msc->bbb_data[i] = 0U;
|
||||
}
|
||||
|
||||
msc->bbb_data[3] = 0x08U;
|
||||
msc->bbb_data[4] = (uint8_t)(blk_nbr >> 24U);
|
||||
msc->bbb_data[5] = (uint8_t)(blk_nbr >> 16U);
|
||||
msc->bbb_data[6] = (uint8_t)(blk_nbr >> 8U);
|
||||
msc->bbb_data[7] = (uint8_t)(blk_nbr);
|
||||
|
||||
msc->bbb_data[8] = 0x02U;
|
||||
msc->bbb_data[9] = (uint8_t)(blk_size >> 16U);
|
||||
msc->bbb_data[10] = (uint8_t)(blk_size >> 8U);
|
||||
msc->bbb_data[11] = (uint8_t)(blk_size);
|
||||
|
||||
msc->bbb_datalen = 12U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Mode Sense6 command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_mode_sense6 (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
uint16_t len = 8U;
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->bbb_datalen = len;
|
||||
|
||||
while (len) {
|
||||
len--;
|
||||
msc->bbb_data[len] = msc_mode_sense6_data[len];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Mode Sense10 command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_mode_sense10 (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
uint16_t len = 8U;
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->bbb_datalen = len;
|
||||
|
||||
while (len) {
|
||||
len--;
|
||||
msc->bbb_data[len] = msc_mode_sense10_data[len];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Request Sense command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_request_sense (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
uint8_t i = 0U;
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
for (i = 0U; i < REQUEST_SENSE_DATA_LEN; i++) {
|
||||
msc->bbb_data[i] = 0U;
|
||||
}
|
||||
|
||||
msc->bbb_data[0] = 0x70U;
|
||||
msc->bbb_data[7] = REQUEST_SENSE_DATA_LEN - 6U;
|
||||
|
||||
if ((msc->scsi_sense_head != msc->scsi_sense_tail)) {
|
||||
msc->bbb_data[2] = msc->scsi_sense[msc->scsi_sense_head].SenseKey;
|
||||
msc->bbb_data[12] = msc->scsi_sense[msc->scsi_sense_head].ASCQ;
|
||||
msc->bbb_data[13] = msc->scsi_sense[msc->scsi_sense_head].ASC;
|
||||
msc->scsi_sense_head++;
|
||||
|
||||
if (msc->scsi_sense_head == SENSE_LIST_DEEPTH) {
|
||||
msc->scsi_sense_head = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
msc->bbb_datalen = USB_MIN(REQUEST_SENSE_DATA_LEN, params[4]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Start Stop Unit command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static inline int8_t scsi_start_stop_unit (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->bbb_datalen = 0U;
|
||||
// msc->scsi_disk_pop = 1U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Allow Medium Removal command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static inline int8_t scsi_allow_medium_removal (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
msc->bbb_datalen = 0U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Read10 command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_read10 (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
if (msc->bbb_state == BBB_IDLE) {
|
||||
/* direction is from device to host */
|
||||
if (0x80U != (msc->bbb_cbw.bmCBWFlags & 0x80U)) {
|
||||
scsi_sense_code (udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 != usbd_mem_fops->mem_ready(lun)) {
|
||||
scsi_sense_code (udev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
msc->scsi_blk_addr = (params[2] << 24U) | (params[3] << 16U) | \
|
||||
(params[4] << 8U) | params[5];
|
||||
|
||||
msc->scsi_blk_len = (params[7] << 8U) | params[8];
|
||||
|
||||
if (scsi_check_address_range (udev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
|
||||
return -1; /* error */
|
||||
}
|
||||
|
||||
msc->bbb_state = BBB_DATA_IN;
|
||||
|
||||
msc->scsi_blk_addr *= msc->scsi_blk_size[lun];
|
||||
msc->scsi_blk_len *= msc->scsi_blk_size[lun];
|
||||
|
||||
/* cases 4,5 : Hi <> Dn */
|
||||
if (msc->bbb_cbw.dCBWDataTransferLength != msc->scsi_blk_len) {
|
||||
scsi_sense_code (udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
msc->bbb_datalen = MSC_MEDIA_PACKET_SIZE;
|
||||
|
||||
return scsi_process_read (udev, lun);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Write10 command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_write10 (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
if (BBB_IDLE == msc->bbb_state) {
|
||||
/* case 8 : Hi <> Do */
|
||||
if (0x80U == (msc->bbb_cbw.bmCBWFlags & 0x80U)) {
|
||||
scsi_sense_code (udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check whether media is ready */
|
||||
if (0 != usbd_mem_fops->mem_ready(lun)) {
|
||||
scsi_sense_code (udev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check if media is write-protected */
|
||||
if (0 != usbd_mem_fops->mem_protected(lun)) {
|
||||
scsi_sense_code (udev, lun, NOT_READY, WRITE_PROTECTED);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
msc->scsi_blk_addr = (params[2] << 24U) | (params[3] << 16U) | \
|
||||
(params[4] << 8U) | params[5];
|
||||
|
||||
msc->scsi_blk_len = (params[7] << 8U) | params[8];
|
||||
|
||||
/* check if LBA address is in the right range */
|
||||
if (scsi_check_address_range (udev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
|
||||
return -1; /* error */
|
||||
}
|
||||
|
||||
msc->scsi_blk_addr *= msc->scsi_blk_size[lun];
|
||||
msc->scsi_blk_len *= msc->scsi_blk_size[lun];
|
||||
|
||||
/* cases 3,11,13 : Hn,Ho <> D0 */
|
||||
if (msc->bbb_cbw.dCBWDataTransferLength != msc->scsi_blk_len) {
|
||||
scsi_sense_code (udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* prepare endpoint to receive first data packet */
|
||||
msc->bbb_state = BBB_DATA_OUT;
|
||||
|
||||
usbd_ep_recev (udev,
|
||||
MSC_OUT_EP,
|
||||
msc->bbb_data,
|
||||
USB_MIN (msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE));
|
||||
} else { /* write process ongoing */
|
||||
return scsi_process_write (udev, lun);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Verify10 command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_verify10 (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
if (0x02U == (params[1] & 0x02U)) {
|
||||
scsi_sense_code (udev, lun, ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
|
||||
|
||||
return -1; /* error, verify mode not supported*/
|
||||
}
|
||||
|
||||
if (scsi_check_address_range (udev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
|
||||
return -1; /* error */
|
||||
}
|
||||
|
||||
msc->bbb_datalen = 0U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief check address range
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] blk_offset: block offset
|
||||
\param[in] blk_nbr: number of block to be processed
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static inline int8_t scsi_check_address_range (usb_dev *udev, uint8_t lun, uint32_t blk_offset, uint16_t blk_nbr)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
if ((blk_offset + blk_nbr) > msc->scsi_blk_nbr[lun]) {
|
||||
scsi_sense_code (udev, lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle read process
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_process_read (usb_dev *udev, uint8_t lun)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
uint32_t len = USB_MIN(msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE);
|
||||
|
||||
if (usbd_mem_fops->mem_read(lun,
|
||||
msc->bbb_data,
|
||||
msc->scsi_blk_addr,
|
||||
(uint16_t)(len / msc->scsi_blk_size[lun])) < 0) {
|
||||
scsi_sense_code(udev, lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
usbd_ep_send (udev, MSC_IN_EP, msc->bbb_data, len);
|
||||
|
||||
msc->scsi_blk_addr += len;
|
||||
msc->scsi_blk_len -= len;
|
||||
|
||||
/* case 6 : Hi = Di */
|
||||
msc->bbb_csw.dCSWDataResidue -= len;
|
||||
|
||||
if (0U == msc->scsi_blk_len) {
|
||||
msc->bbb_state = BBB_LAST_DATA_IN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle write process
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_process_write (usb_dev *udev, uint8_t lun)
|
||||
{
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
uint32_t len = USB_MIN(msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE);
|
||||
|
||||
if (usbd_mem_fops->mem_write (lun,
|
||||
msc->bbb_data,
|
||||
msc->scsi_blk_addr,
|
||||
(uint16_t)(len / msc->scsi_blk_size[lun])) < 0) {
|
||||
scsi_sense_code(udev, lun, HARDWARE_ERROR, WRITE_FAULT);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
msc->scsi_blk_addr += len;
|
||||
msc->scsi_blk_len -= len;
|
||||
|
||||
/* case 12 : Ho = Do */
|
||||
msc->bbb_csw.dCSWDataResidue -= len;
|
||||
|
||||
if (0U == msc->scsi_blk_len) {
|
||||
msc_bbb_csw_send (udev, CSW_CMD_PASSED);
|
||||
} else {
|
||||
/* prepare endpoint to receive next packet */
|
||||
usbd_ep_recev (udev,
|
||||
MSC_OUT_EP,
|
||||
msc->bbb_data,
|
||||
USB_MIN (msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Format Unit command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static inline int8_t scsi_format_cmd (usb_dev *udev, uint8_t lun)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief process Read_Toc command
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] lun: logical unit number
|
||||
\param[in] params: command parameters
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static int8_t scsi_toc_cmd_read (usb_dev *udev, uint8_t lun, uint8_t *params)
|
||||
{
|
||||
uint8_t* pPage;
|
||||
uint16_t len;
|
||||
|
||||
usbd_msc_handler *msc = (usbd_msc_handler *)udev->class_data[USBD_MSC_INTERFACE];
|
||||
|
||||
pPage = (uint8_t *)&usbd_mem_fops->mem_toc_data[lun * READ_TOC_CMD_LEN];
|
||||
len = (uint16_t)pPage[1] + 2U;
|
||||
|
||||
msc->bbb_datalen = len;
|
||||
|
||||
while (len) {
|
||||
len--;
|
||||
msc->bbb_data[len] = pPage[len];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*!
|
||||
\file printer_core.h
|
||||
\brief the header file of USB printer device class core functions
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __PRINTER_CORE_H
|
||||
#define __PRINTER_CORE_H
|
||||
|
||||
#include "usbd_enum.h"
|
||||
|
||||
/* USB printing device class code */
|
||||
#define USB_CLASS_PRINTER 0x07U
|
||||
|
||||
/* printing device subclass code */
|
||||
#define USB_SUBCLASS_PRINTER 0x01U
|
||||
|
||||
/* printing device protocol code */
|
||||
#define PROTOCOL_UNIDIRECTIONAL_ITF 0x01U
|
||||
#define PROTOCOL_BI_DIRECTIONAL_ITF 0x02U
|
||||
#define PROTOCOL_1284_4_ITF 0x03U
|
||||
#define PROTOCOL_VENDOR 0xFFU
|
||||
|
||||
#define DEVICE_ID_LEN 103U
|
||||
|
||||
#define USB_PRINTER_CONFIG_DESC_LEN 32U
|
||||
|
||||
/* printing device specific-class request */
|
||||
#define GET_DEVICE_ID 0x00U
|
||||
#define GET_PORT_STATUS 0x01U
|
||||
#define SOFT_RESET 0x02U
|
||||
|
||||
/* USB configuration descriptor structure */
|
||||
typedef struct
|
||||
{
|
||||
usb_desc_config config;
|
||||
usb_desc_itf printer_itf;
|
||||
usb_desc_ep printer_epin;
|
||||
usb_desc_ep printer_epout;
|
||||
} usb_printer_desc_config_set;
|
||||
|
||||
extern usb_desc printer_desc;
|
||||
extern usb_class printer_class;
|
||||
|
||||
#endif /* __PRINTER_CORE_H */
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
/*!
|
||||
\file printer_core.c
|
||||
\brief USB printer device class core functions
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_transc.h"
|
||||
#include "printer_core.h"
|
||||
|
||||
#define USBD_VID 0x28E9U
|
||||
#define USBD_PID 0x028DU
|
||||
|
||||
/* printer port status: paper not empty/selected/no error */
|
||||
static uint8_t g_port_status = 0x18U;
|
||||
uint8_t g_printer_data_buf[PRINTER_OUT_PACKET];
|
||||
|
||||
uint8_t Printer_DEVICE_ID[DEVICE_ID_LEN] =
|
||||
{
|
||||
0x00, 0x67,
|
||||
'M', 'A', 'N', 'U', 'F', 'A', 'C', 'T', 'U', 'R', 'E', 'R', ':',
|
||||
'G', 'I', 'G', 'A', ' ', 'D', 'E', 'V', 'I', 'C', 'E', '-', ';',
|
||||
'C', 'O', 'M', 'M', 'A', 'N', 'D', ' ', 'S', 'E', 'T', ':',
|
||||
'P', 'C', 'L', ',', 'M', 'P', 'L', ';',
|
||||
'M', 'O', 'D', 'E', 'L', ':',
|
||||
'L', 'a', 's', 'e', 'r', 'B', 'e', 'a', 'm', '?', ';',
|
||||
'C', 'O', 'M', 'M', 'E', 'N', 'T', ':',
|
||||
'G', 'o', 'o', 'd', ' ', '!', ';',
|
||||
'A', 'C', 'T', 'I', 'V', 'E', ' ', 'C', 'O', 'M', 'M', 'A', 'N', 'D', ' ', 'S', 'E', 'T', ':',
|
||||
'P', 'C', 'L', ';'
|
||||
};
|
||||
|
||||
/* USB standard device descriptor */
|
||||
usb_desc_dev printer_dev_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_DEV_DESC_LEN,
|
||||
.bDescriptorType = USB_DESCTYPE_DEV,
|
||||
},
|
||||
.bcdUSB = 0x0200U,
|
||||
.bDeviceClass = 0x00U,
|
||||
.bDeviceSubClass = 0x00U,
|
||||
.bDeviceProtocol = 0x00U,
|
||||
.bMaxPacketSize0 = USBD_EP0_MAX_SIZE,
|
||||
.idVendor = USBD_VID,
|
||||
.idProduct = USBD_PID,
|
||||
.bcdDevice = 0x0100U,
|
||||
.iManufacturer = STR_IDX_MFC,
|
||||
.iProduct = STR_IDX_PRODUCT,
|
||||
.iSerialNumber = STR_IDX_SERIAL,
|
||||
.bNumberConfigurations = USBD_CFG_MAX_NUM,
|
||||
};
|
||||
|
||||
/* USB device configuration descriptor */
|
||||
usb_printer_desc_config_set printer_config_desc =
|
||||
{
|
||||
.config =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_config),
|
||||
.bDescriptorType = USB_DESCTYPE_CONFIG
|
||||
},
|
||||
.wTotalLength = USB_PRINTER_CONFIG_DESC_LEN,
|
||||
.bNumInterfaces = 0x01U,
|
||||
.bConfigurationValue = 0x01U,
|
||||
.iConfiguration = 0x00U,
|
||||
.bmAttributes = 0xA0U,
|
||||
.bMaxPower = 0x32U
|
||||
},
|
||||
|
||||
.printer_itf =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_itf),
|
||||
.bDescriptorType = USB_DESCTYPE_ITF
|
||||
},
|
||||
.bInterfaceNumber = 0x00U,
|
||||
.bAlternateSetting = 0x00U,
|
||||
.bNumEndpoints = 0x02U,
|
||||
.bInterfaceClass = USB_CLASS_PRINTER,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_PRINTER,
|
||||
.bInterfaceProtocol = PROTOCOL_BI_DIRECTIONAL_ITF,
|
||||
.iInterface = 0x00U
|
||||
},
|
||||
|
||||
.printer_epin =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP
|
||||
},
|
||||
.bEndpointAddress = PRINTER_IN_EP,
|
||||
.bmAttributes = USB_EP_ATTR_BULK,
|
||||
.wMaxPacketSize = PRINTER_IN_PACKET,
|
||||
.bInterval = 0x00U
|
||||
},
|
||||
|
||||
.printer_epout =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_ep),
|
||||
.bDescriptorType = USB_DESCTYPE_EP
|
||||
},
|
||||
.bEndpointAddress = PRINTER_OUT_EP,
|
||||
.bmAttributes = USB_EP_ATTR_BULK,
|
||||
.wMaxPacketSize = PRINTER_OUT_PACKET,
|
||||
.bInterval = 0x00U
|
||||
},
|
||||
};
|
||||
|
||||
/* USB language ID Descriptor */
|
||||
static usb_desc_LANGID usbd_language_id_desc =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = sizeof(usb_desc_LANGID),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.wLANGID = ENG_LANGID
|
||||
};
|
||||
|
||||
/* USB manufacture string */
|
||||
static usb_desc_str manufacturer_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(10U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
|
||||
};
|
||||
|
||||
/* USB product string */
|
||||
static usb_desc_str product_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(16U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
},
|
||||
.unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'P', 'r', 'i', 'n', 't', 'e', 'r'}
|
||||
};
|
||||
|
||||
/* USB serial string */
|
||||
static usb_desc_str serial_string =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.bLength = USB_STRING_LEN(12U),
|
||||
.bDescriptorType = USB_DESCTYPE_STR,
|
||||
}
|
||||
};
|
||||
|
||||
/* USB string descriptor set */
|
||||
static uint8_t* usbd_msc_strings[] =
|
||||
{
|
||||
[STR_IDX_LANGID] = (uint8_t *)&usbd_language_id_desc,
|
||||
[STR_IDX_MFC] = (uint8_t *)&manufacturer_string,
|
||||
[STR_IDX_PRODUCT] = (uint8_t *)&product_string,
|
||||
[STR_IDX_SERIAL] = (uint8_t *)&serial_string
|
||||
};
|
||||
|
||||
usb_desc printer_desc = {
|
||||
.dev_desc = (uint8_t *)&printer_dev_desc,
|
||||
.config_desc = (uint8_t *)&printer_config_desc,
|
||||
.strings = usbd_msc_strings
|
||||
};
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint8_t printer_init (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t printer_deinit (usb_dev *udev, uint8_t config_index);
|
||||
static uint8_t printer_req_handler (usb_dev *udev, usb_req *req);
|
||||
static void printer_data_in (usb_dev *udev, uint8_t ep_num);
|
||||
static void printer_data_out (usb_dev *udev, uint8_t ep_num);
|
||||
|
||||
usb_class printer_class = {
|
||||
.init = printer_init,
|
||||
.deinit = printer_deinit,
|
||||
.req_process = printer_req_handler,
|
||||
.data_in = printer_data_in,
|
||||
.data_out = printer_data_out
|
||||
};
|
||||
/*!
|
||||
\brief initialize the printer device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t printer_init (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
/* initialize the data TX/RX endpoint */
|
||||
usbd_ep_init(udev, EP_BUF_SNG, BULK_TX_ADDR, &(printer_config_desc.printer_epin));
|
||||
usbd_ep_init(udev, EP_BUF_SNG, BULK_RX_ADDR, &(printer_config_desc.printer_epout));
|
||||
|
||||
udev->ep_transc[EP_ID(PRINTER_IN_EP)][TRANSC_IN] = printer_class.data_in;
|
||||
udev->ep_transc[PRINTER_OUT_EP][TRANSC_OUT] = printer_class.data_out;
|
||||
|
||||
/* prepare to receive data */
|
||||
usbd_ep_recev(udev, PRINTER_OUT_EP, g_printer_data_buf, PRINTER_OUT_PACKET);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief deinitialize the printer device
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] config_index: configuration index
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t printer_deinit (usb_dev *udev, uint8_t config_index)
|
||||
{
|
||||
/* deinitialize the data TX/RX endpoint */
|
||||
usbd_ep_deinit(udev, PRINTER_IN_EP);
|
||||
usbd_ep_deinit(udev, PRINTER_OUT_EP);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the printer class-specific requests
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: device class-specific request
|
||||
\param[out] none
|
||||
\retval USB device operation status
|
||||
*/
|
||||
static uint8_t printer_req_handler (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
uint8_t status = REQ_NOTSUPP;
|
||||
|
||||
switch (req->bRequest) {
|
||||
case GET_DEVICE_ID:
|
||||
usb_transc_config(&udev->transc_in[0], Printer_DEVICE_ID, DEVICE_ID_LEN, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case GET_PORT_STATUS:
|
||||
usb_transc_config(&udev->transc_in[0], (uint8_t *)&g_port_status, 1U, 0U);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case SOFT_RESET:
|
||||
usbd_ep_recev(udev, PRINTER_OUT_EP, g_printer_data_buf, PRINTER_OUT_PACKET);
|
||||
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle printer data
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void printer_data_in (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle printer data
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void printer_data_out (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
/*!
|
||||
\file usb_ch9_std.h
|
||||
\brief USB 2.0 standard defines
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USB_CH9_STD_H
|
||||
#define __USB_CH9_STD_H
|
||||
|
||||
#include "usbd_conf.h"
|
||||
|
||||
#define USB_DEV_QUALIFIER_DESC_LEN 0x0AU /*!< USB device qualifier descriptor length */
|
||||
#define USB_DEV_DESC_LEN 0x12U /*!< USB device descriptor length */
|
||||
#define USB_CFG_DESC_LEN 0x09U /*!< USB configuration descriptor length */
|
||||
#define USB_ITF_DESC_LEN 0x09U /*!< USB interface descriptor length */
|
||||
#define USB_EP_DESC_LEN 0x07U /*!< USB endpoint descriptor length */
|
||||
#define USB_BOS_DESC_LEN 0x0CU /*!< USB BOS descriptor length */
|
||||
#define USB_OTG_DESC_LEN 0x03U /*!< USB device OTG descriptor length */
|
||||
#define USB_SETUP_PACKET_LEN 0x08U /*!< USB SETUP packet length */
|
||||
#define USB_DEVICE_CAPABITY 0x10U /*!< USB device capabity */
|
||||
|
||||
/* bit 7 of bmRequestType: data phase transfer direction */
|
||||
#define USB_TRX_MASK 0x80U /*!< USB transfer direction mask */
|
||||
#define USB_TRX_OUT 0x00U /*!< USB transfer OUT direction */
|
||||
#define USB_TRX_IN 0x80U /*!< USB transfer IN direction */
|
||||
|
||||
/* bit 6..5 of bmRequestType: request type */
|
||||
#define USB_REQTYPE_STRD 0x00U /*!< USB standard request */
|
||||
#define USB_REQTYPE_CLASS 0x20U /*!< USB class request */
|
||||
#define USB_REQTYPE_VENDOR 0x40U /*!< USB vendor request */
|
||||
#define USB_REQTYPE_MASK 0x60U /*!< USB request mask */
|
||||
|
||||
#define USBD_BUS_POWERED 0x00U /*!< USB bus power supply */
|
||||
#define USBD_SELF_POWERED 0x01U /*!< USB self power supply */
|
||||
|
||||
#define USB_STATUS_REMOTE_WAKEUP 2U /*!< USB is in remote wakeup status */
|
||||
#define USB_STATUS_SELF_POWERED 1U /*!< USB is in self powered status */
|
||||
|
||||
/* bit 4..0 of bmRequestType: recipient type */
|
||||
enum _usb_recp_type {
|
||||
USB_RECPTYPE_DEV = 0x0U, /*!< USB device request type */
|
||||
USB_RECPTYPE_ITF = 0x1U, /*!< USB interface request type */
|
||||
USB_RECPTYPE_EP = 0x2U, /*!< USB endpoint request type */
|
||||
USB_RECPTYPE_MASK = 0x3U /*!< USB request type mask */
|
||||
};
|
||||
|
||||
/* bRequest value */
|
||||
enum _usb_request {
|
||||
USB_GET_STATUS = 0x0U, /*!< USB get status request */
|
||||
USB_CLEAR_FEATURE = 0x1U, /*!< USB clear feature request */
|
||||
USB_RESERVED2 = 0x2U, /*!< USB reserved2 */
|
||||
USB_SET_FEATURE = 0x3U, /*!< USB set feature request */
|
||||
USB_RESERVED4 = 0x4U, /*!< USB reserved4 */
|
||||
USB_SET_ADDRESS = 0x5U, /*!< USB set address request */
|
||||
USB_GET_DESCRIPTOR = 0x6U, /*!< USB get descriptor request */
|
||||
USB_SET_DESCRIPTOR = 0x7U, /*!< USB set descriptor request */
|
||||
USB_GET_CONFIGURATION = 0x8U, /*!< USB get configuration request */
|
||||
USB_SET_CONFIGURATION = 0x9U, /*!< USB set configuration request */
|
||||
USB_GET_INTERFACE = 0xAU, /*!< USB get interface request */
|
||||
USB_SET_INTERFACE = 0xBU, /*!< USB set interface request */
|
||||
USB_SYNCH_FRAME = 0xCU /*!< USB synchronized frame request */
|
||||
};
|
||||
|
||||
/* descriptor types of USB specifications */
|
||||
enum _usb_desctype {
|
||||
USB_DESCTYPE_DEV = 0x1U, /*!< USB device descriptor type */
|
||||
USB_DESCTYPE_CONFIG = 0x2U, /*!< USB configuration descriptor type */
|
||||
USB_DESCTYPE_STR = 0x3U, /*!< USB string descriptor type */
|
||||
USB_DESCTYPE_ITF = 0x4U, /*!< USB interface descriptor type */
|
||||
USB_DESCTYPE_EP = 0x5U, /*!< USB endpoint descriptor type */
|
||||
USB_DESCTYPE_DEV_QUALIFIER = 0x6U, /*!< USB device qualifier descriptor type */
|
||||
USB_DESCTYPE_OTHER_SPD_CONFIG = 0x7U, /*!< USB other speed configuration descriptor type */
|
||||
USB_DESCTYPE_ITF_POWER = 0x8U, /*!< USB interface power descriptor type */
|
||||
USB_DESCTYPE_BOS = 0xFU /*!< USB BOS descriptor type */
|
||||
};
|
||||
|
||||
/* USB endpoint descriptor bmAttributes bit definitions */
|
||||
/* bits 1..0 : transfer type */
|
||||
enum _usbx_type {
|
||||
USB_EP_ATTR_CTL = 0x0U, /*!< USB endpoint control attributes*/
|
||||
USB_EP_ATTR_ISO = 0x1U, /*!< USB endpoint isochronous attributes*/
|
||||
USB_EP_ATTR_BULK = 0x2U, /*!< USB endpoint bulk attributes*/
|
||||
USB_EP_ATTR_INT = 0x3U /*!< USB endpoint interrupt attributes*/
|
||||
};
|
||||
|
||||
/* bits 3..2 : Sync type (only if ISOCHRONOUS) */
|
||||
#define USB_EP_ATTR_NOSYNC 0x00U /*!< USB endpoint no SYNC attributes*/
|
||||
#define USB_EP_ATTR_ASYNC 0x04U /*!< USB endpoint ASYNC attributes*/
|
||||
#define USB_EP_ATTR_ADAPTIVE 0x08U /*!< USB endpoint adaptive attributes*/
|
||||
#define USB_EP_ATTR_SYNC 0x0CU /*!< USB endpoint SYNC attributes*/
|
||||
#define USB_EP_ATTR_SYNCTYPE 0x0CU /*!< USB endpoint SYNC type attributes*/
|
||||
|
||||
/* bits 5..4 : usage type (only if ISOCHRONOUS) */
|
||||
#define USB_EP_ATTR_DATA 0x00U /*!< USB endpoint data attributes*/
|
||||
#define USB_EP_ATTR_FEEDBACK 0x10U /*!< USB endpoint feedback attributes*/
|
||||
#define USB_EP_ATTR_IMPLICIT_FEEDBACK_DATA 0x20U /*!< USB endpoint implicit feedback attributes*/
|
||||
#define USB_EP_ATTR_USAGETYPE 0x30U /*!< USB endpoint usage type attributes*/
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/* USB standard device request structure */
|
||||
typedef struct _usb_req {
|
||||
uint8_t bmRequestType; /*!< type of request */
|
||||
uint8_t bRequest; /*!< request of setup packet */
|
||||
uint16_t wValue; /*!< value of setup packet */
|
||||
uint16_t wIndex; /*!< index of setup packet */
|
||||
uint16_t wLength; /*!< length of setup packet */
|
||||
} usb_req;
|
||||
|
||||
/* USB setup packet definition */
|
||||
typedef union _usb_setup {
|
||||
uint8_t data[8]; /*!< USB setup data */
|
||||
|
||||
usb_req req; /*!< USB setup request */
|
||||
} usb_setup;
|
||||
|
||||
/* USB descriptor definition */
|
||||
typedef struct _usb_desc_header {
|
||||
uint8_t bLength; /*!< size of the descriptor */
|
||||
uint8_t bDescriptorType; /*!< type of the descriptor */
|
||||
} usb_desc_header;
|
||||
|
||||
typedef struct _usb_desc_dev {
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint16_t bcdUSB; /*!< BCD of the supported USB specification */
|
||||
uint8_t bDeviceClass; /*!< USB device class */
|
||||
uint8_t bDeviceSubClass; /*!< USB device subclass */
|
||||
uint8_t bDeviceProtocol; /*!< USB device protocol */
|
||||
uint8_t bMaxPacketSize0; /*!< size of the control (address 0) endpoint's bank in bytes */
|
||||
uint16_t idVendor; /*!< vendor ID for the USB product */
|
||||
uint16_t idProduct; /*!< unique product ID for the USB product */
|
||||
uint16_t bcdDevice; /*!< product release (version) number */
|
||||
uint8_t iManufacturer; /*!< string index for the manufacturer's name */
|
||||
uint8_t iProduct; /*!< string index for the product name/details */
|
||||
uint8_t iSerialNumber; /*!< string index for the product's globally unique hexadecimal serial number */
|
||||
uint8_t bNumberConfigurations; /*!< total number of configurations supported by the device */
|
||||
} usb_desc_dev;
|
||||
|
||||
typedef struct _usb_desc_config {
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint16_t wTotalLength; /*!< size of the configuration descriptor header, and all sub descriptors inside the configuration */
|
||||
uint8_t bNumInterfaces; /*!< total number of interfaces in the configuration */
|
||||
uint8_t bConfigurationValue; /*!< configuration index of the current configuration */
|
||||
uint8_t iConfiguration; /*!< index of a string descriptor describing the configuration */
|
||||
uint8_t bmAttributes; /*!< configuration attributes */
|
||||
uint8_t bMaxPower; /*!< maximum power consumption of the device while in the current configuration */
|
||||
} usb_desc_config;
|
||||
|
||||
typedef struct _usb_desc_itf {
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bInterfaceNumber; /*!< index of the interface in the current configuration */
|
||||
uint8_t bAlternateSetting; /*!< alternate setting for the interface number */
|
||||
uint8_t bNumEndpoints; /*!< total number of endpoints in the interface */
|
||||
uint8_t bInterfaceClass; /*!< interface class ID */
|
||||
uint8_t bInterfaceSubClass; /*!< interface subclass ID */
|
||||
uint8_t bInterfaceProtocol; /*!< interface protocol ID */
|
||||
uint8_t iInterface; /*!< index of the string descriptor describing the interface */
|
||||
} usb_desc_itf;
|
||||
|
||||
typedef struct _usb_desc_ep {
|
||||
usb_desc_header header; /*!< descriptor header, including type and size */
|
||||
uint8_t bEndpointAddress; /*!< logical address of the endpoint */
|
||||
uint8_t bmAttributes; /*!< endpoint attribute */
|
||||
uint16_t wMaxPacketSize; /*!< size of the endpoint bank, in bytes */
|
||||
uint8_t bInterval; /*!< polling interval in milliseconds for the endpoint if it is an INTERRUPT or ISOCHRONOUS type */
|
||||
} usb_desc_ep;
|
||||
|
||||
typedef struct _usb_desc_LANGID {
|
||||
usb_desc_header header; /*!< descriptor header, including type and size. */
|
||||
uint16_t wLANGID; /*!< LANGID code */
|
||||
} usb_desc_LANGID;
|
||||
|
||||
typedef struct _usb_desc_str {
|
||||
usb_desc_header header; /*!< descriptor header, including type and size. */
|
||||
uint16_t unicode_string[64]; /*!< unicode string data */
|
||||
} usb_desc_str;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
/* compute string descriptor length */
|
||||
#define USB_STRING_LEN(unicode_chars) (sizeof(usb_desc_header) + ((unicode_chars) << 1))
|
||||
|
||||
#endif /* __USB_CH9_STD_H */
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
/*!
|
||||
\file usbd_core.h
|
||||
\brief USB device driver core
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
\version 2021-08-10, V3.0.1, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USBD_CORE_H
|
||||
#define __USBD_CORE_H
|
||||
|
||||
#include "usb_ch9_std.h"
|
||||
|
||||
/* endpoints definitions */
|
||||
#define EP_IN(x) ((uint8_t)(0x80U | (x)))
|
||||
#define EP_OUT(x) ((uint8_t)(x))
|
||||
|
||||
#define EP_DIR(x) ((uint8_t)((x) >> 7U))
|
||||
#define EP_ID(x) ((uint8_t)((x) & 0x7FU))
|
||||
|
||||
/* USB device endpoint0 max packet size */
|
||||
#define USBD_EP0_MAX_SIZE 64U
|
||||
|
||||
#define USBD_TRANSC_COUNT 3U
|
||||
|
||||
/* USB device operation status */
|
||||
enum usbd_status {
|
||||
USBD_UNCONNECTED = 0U, /*!< USB device unconnected status */
|
||||
USBD_DEFAULT, /*!< USB device default status */
|
||||
USBD_ADDRESSED, /*!< USB device addressed status */
|
||||
USBD_CONFIGURED, /*!< USB device configured status */
|
||||
USBD_SUSPENDED, /*!< USB device suspended status */
|
||||
USBD_CONNECTED /*!< USB device connected status */
|
||||
};
|
||||
|
||||
/* USB device operation state */
|
||||
enum usbd_state {
|
||||
USBD_OK = 0U, /*!< USB device OK state */
|
||||
USBD_BUSY, /*!< USB device busy state */
|
||||
USBD_FAIL /*!< USB device fail state */
|
||||
};
|
||||
|
||||
/* USB device type */
|
||||
enum usbd_transc {
|
||||
TRANSC_SETUP = 0U, /*!< SETUP transaction */
|
||||
TRANSC_OUT, /*!< OUT transaction */
|
||||
TRANSC_IN, /*!< IN transaction */
|
||||
TRANSC_UNKNOWN /*!< unknown transaction */
|
||||
};
|
||||
|
||||
/* USB device endpoint buffer type */
|
||||
enum usbd_ep_kind {
|
||||
EP_BUF_SNG = 0U, /*!< single buffer endpoint type value */
|
||||
EP_BUF_DBL /*!< double buffer endpoint type value */
|
||||
};
|
||||
|
||||
/* USB device transaction structure */
|
||||
typedef struct {
|
||||
uint16_t max_len; /*!< packet max length */
|
||||
uint8_t ep_stall; /*!< endpoint STALL */
|
||||
|
||||
uint8_t *xfer_buf; /*!< transfer buffer */
|
||||
uint16_t xfer_len; /*!< transfer length */
|
||||
uint16_t xfer_count; /*!< transfer count */
|
||||
} usb_transc;
|
||||
|
||||
/* USB device basic structure */
|
||||
typedef struct {
|
||||
uint8_t max_ep_count; /*!< endpoint max count */
|
||||
uint8_t twin_buf; /*!< double buffer */
|
||||
uint16_t ram_size; /*!< ram size */
|
||||
} usb_basic;
|
||||
|
||||
/* USB descriptor */
|
||||
typedef struct {
|
||||
uint8_t *dev_desc; /*!< device descriptor */
|
||||
uint8_t *config_desc; /*!< configure descriptor */
|
||||
uint8_t *bos_desc; /*!< BOS descriptor */
|
||||
uint8_t **strings; /*!< strings descriptor */
|
||||
} usb_desc;
|
||||
|
||||
/* USB power management */
|
||||
typedef struct {
|
||||
uint8_t power_mode; /*!< power mode */
|
||||
uint8_t power_low; /*!< power low */
|
||||
uint8_t esof_count; /*!< ESOF count */
|
||||
uint8_t suspend_enabled; /*!< suspend enabled flag */
|
||||
uint8_t remote_wakeup; /*!< remote wakeup */
|
||||
uint8_t remote_wakeup_on; /*!< remote wakeup enable */
|
||||
uint8_t lpm_enable; /*!< LPM enable */
|
||||
} usb_pm;
|
||||
|
||||
/* USB LPM management */
|
||||
typedef struct {
|
||||
uint32_t besl; /*!< BESL */
|
||||
uint32_t L1_resume; /*!< L1 resume */
|
||||
uint32_t L1_remote_wakeup; /*!< L1 remote wakeup */
|
||||
} usb_lpm;
|
||||
|
||||
/* USB control information */
|
||||
typedef struct {
|
||||
usb_req req; /*!< USB request */
|
||||
uint8_t ctl_zlp; /*!< control zero length packet */
|
||||
} usb_control;
|
||||
|
||||
typedef struct _usb_dev usb_dev;
|
||||
typedef struct _usb_handler usb_handler;
|
||||
typedef void (*usb_ep_transc) (usb_dev *usbd_dev, uint8_t ep_num);
|
||||
|
||||
/* USB class structure */
|
||||
typedef struct {
|
||||
uint8_t req_cmd;
|
||||
uint8_t req_altset;
|
||||
|
||||
uint8_t (*init) (usb_dev *udev, uint8_t config_index);
|
||||
uint8_t (*deinit) (usb_dev *udev, uint8_t config_index);
|
||||
|
||||
uint8_t (*req_process) (usb_dev *udev, usb_req *req);
|
||||
|
||||
uint8_t (*ctlx_in) (usb_dev *udev);
|
||||
uint8_t (*ctlx_out) (usb_dev *udev);
|
||||
|
||||
void (*data_in) (usb_dev *udev, uint8_t ep_num);
|
||||
void (*data_out) (usb_dev *udev, uint8_t ep_num);
|
||||
} usb_class;
|
||||
|
||||
/* USB core driver structure */
|
||||
struct _usb_dev {
|
||||
/* basic parameters */
|
||||
uint8_t config;
|
||||
uint8_t dev_addr;
|
||||
|
||||
__IO uint8_t cur_status;
|
||||
__IO uint8_t backup_status;
|
||||
|
||||
usb_pm pm;
|
||||
#ifdef LPM_ENABLED
|
||||
usb_lpm lpm;
|
||||
#endif /* LPM_ENABLED */
|
||||
usb_control control;
|
||||
|
||||
usb_transc transc_out[EP_COUNT];
|
||||
usb_transc transc_in[EP_COUNT];
|
||||
|
||||
usb_ep_transc ep_transc[EP_COUNT][USBD_TRANSC_COUNT];
|
||||
|
||||
/* device class */
|
||||
usb_desc *desc;
|
||||
usb_class *class_core;
|
||||
usb_handler *drv_handler;
|
||||
|
||||
void *class_data[USBD_ITF_MAX_NUM];
|
||||
void *user_data;
|
||||
void *data;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t (*SOF) (usb_dev *udev); /*!< SOF ISR callback */
|
||||
} usbd_int_cb_struct;
|
||||
|
||||
/* USB handler structure */
|
||||
struct _usb_handler {
|
||||
void (*init) (void);
|
||||
void (*deinit) (void);
|
||||
|
||||
void (*dp_pullup) (FlagStatus status);
|
||||
void (*set_addr) (usb_dev *udev);
|
||||
void (*suspend) (void);
|
||||
void (*suspend_leave) (void);
|
||||
void (*resume) (usb_dev *udev);
|
||||
|
||||
void (*ep_reset) (usb_dev *udev);
|
||||
void (*ep_setup) (usb_dev *udev, uint8_t buf_kind, uint32_t buf_addr, const usb_desc_ep *ep_desc);
|
||||
void (*ep_disable) (usb_dev *udev, uint8_t ep_addr);
|
||||
void (*ep_rx_enable) (usb_dev *udev, uint8_t ep_num);
|
||||
void (*ep_write) (uint8_t *fifo, uint8_t ep_num, uint16_t bytes);
|
||||
uint16_t (*ep_read) (uint8_t *fifo, uint8_t ep_num, uint8_t buf_kind);
|
||||
void (*ep_stall_set) (usb_dev *udev, uint8_t ep_addr);
|
||||
void (*ep_stall_clear) (usb_dev *udev, uint8_t ep_addr);
|
||||
uint8_t (*ep_status_get) (usb_dev *udev, uint8_t ep_addr);
|
||||
};
|
||||
|
||||
extern usbd_int_cb_struct *usbd_int_fops;
|
||||
|
||||
/* static inline function definitions */
|
||||
/*!
|
||||
\brief device connect
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usbd_connect (usb_dev *udev)
|
||||
{
|
||||
udev->drv_handler->dp_pullup(SET);
|
||||
|
||||
udev->cur_status = (uint8_t)USBD_CONNECTED;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief device disconnect
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usbd_disconnect (usb_dev *udev)
|
||||
{
|
||||
udev->drv_handler->dp_pullup(RESET);
|
||||
|
||||
udev->cur_status = (uint8_t)USBD_UNCONNECTED;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief device core register configure when stop device
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usbd_core_deinit (usb_dev *udev)
|
||||
{
|
||||
udev->drv_handler->deinit();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize endpoint
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] buf_kind: endpoint buffer kind
|
||||
\param[in] buf_addr: buffer address
|
||||
\param[in] ep_desc: pointer to endpoint descriptor
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usbd_ep_init (usb_dev *udev, uint8_t buf_kind, uint32_t buf_addr, const usb_desc_ep *ep_desc)
|
||||
{
|
||||
udev->drv_handler->ep_setup(udev, buf_kind, buf_addr, ep_desc);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the endpoint when it is disabled
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
in this parameter:
|
||||
bit0..bit6: endpoint number (0..7)
|
||||
bit7: endpoint direction which can be IN(1) or OUT(0)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usbd_ep_deinit (usb_dev *udev, uint8_t ep_addr)
|
||||
{
|
||||
udev->drv_handler->ep_disable(udev, ep_addr);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set an endpoint to STALL status
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
in this parameter:
|
||||
bit0..bit6: endpoint number (0..7)
|
||||
bit7: endpoint direction which can be IN(1) or OUT(0)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usbd_ep_stall (usb_dev *udev, uint8_t ep_addr)
|
||||
{
|
||||
udev->drv_handler->ep_stall_set(udev, ep_addr);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear endpoint stalled status
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
in this parameter:
|
||||
bit0..bit6: endpoint number (0..7)
|
||||
bit7: endpoint direction which can be IN(1) or OUT(0)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usbd_ep_clear_stall (usb_dev *udev, uint8_t ep_addr)
|
||||
{
|
||||
udev->drv_handler->ep_stall_clear(udev, ep_addr);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get endpoint status
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
in this parameter:
|
||||
bit0..bit6: endpoint number (0..7)
|
||||
bit7: endpoint direction which can be IN(1) or OUT(0)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE uint8_t usbd_ep_status_get (usb_dev *udev, uint8_t ep_addr)
|
||||
{
|
||||
return udev->drv_handler->ep_status_get(udev, ep_addr);
|
||||
}
|
||||
|
||||
/* function declarations */
|
||||
/* initialize USBD */
|
||||
void usbd_init(usb_dev *udev, usb_desc *desc, usb_class *usbc);
|
||||
/* endpoint prepare to transmit data */
|
||||
void usbd_ep_send (usb_dev *udev, uint8_t ep_addr, uint8_t *pbuf, uint16_t buf_len);
|
||||
/* endpoint prepare to receive data */
|
||||
void usbd_ep_recev (usb_dev *udev, uint8_t ep_addr, uint8_t *pbuf, uint16_t buf_len);
|
||||
|
||||
#endif /* __USBD_CORE_H */
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*!
|
||||
\file usbd_enum.h
|
||||
\brief USB enumeration definitions
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USBD_ENUM_H
|
||||
#define __USBD_ENUM_H
|
||||
|
||||
#include "usbd_core.h"
|
||||
#include "usb_ch9_std.h"
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0U
|
||||
#endif
|
||||
|
||||
/* request state enumeration */
|
||||
typedef enum _usb_reqsta
|
||||
{
|
||||
REQ_SUPP = 0x0U, /* supported request */
|
||||
REQ_NOTSUPP = 0x1U /* unsupported request */
|
||||
} usb_reqsta;
|
||||
|
||||
/* string descriptor index enumeration */
|
||||
enum _str_index
|
||||
{
|
||||
STR_IDX_LANGID = 0x0U, /* language ID string index */
|
||||
STR_IDX_MFC = 0x1U, /* manufacturer string index */
|
||||
STR_IDX_PRODUCT = 0x2U, /* product string index */
|
||||
STR_IDX_SERIAL = 0x3U, /* serial string index */
|
||||
STR_IDX_CONFIG = 0x4U, /* configuration string index */
|
||||
STR_IDX_ITF = 0x5U, /* interface string index */
|
||||
STR_IDX_MAX = 0x6U /* string index max value */
|
||||
};
|
||||
|
||||
/* PWR status enumeration */
|
||||
typedef enum
|
||||
{
|
||||
USB_PWRSTA_SELF_POWERED = 0x1U, /* USB is in self powered status */
|
||||
USB_PWRSTA_REMOTE_WAKEUP = 0x2U, /* USB is in remote wakeup status */
|
||||
} usb_pwrsta;
|
||||
|
||||
/* USB endpoint feature enumeration */
|
||||
typedef enum
|
||||
{
|
||||
USB_FEATURE_EP_HALT = 0x0U, /* USB has endpoint halt feature */
|
||||
USB_FEATURE_REMOTE_WAKEUP = 0x1U, /* USB has endpoint remote wakeup feature */
|
||||
USB_FEATURE_TEST_MODE = 0x2U /* USB has endpoint test mode feature */
|
||||
} usb_feature;
|
||||
|
||||
#define ENG_LANGID 0x0409U /* english language ID */
|
||||
#define CHN_LANGID 0x0804U /* chinese language ID */
|
||||
|
||||
/* device unique ID */
|
||||
#define DEVICE_ID1 (0x1FFFF7E8U) /* device ID1 */
|
||||
#define DEVICE_ID2 (0x1FFFF7ECU) /* device ID2 */
|
||||
#define DEVICE_ID3 (0x1FFFF7F0U) /* device ID3 */
|
||||
|
||||
#define DEVICE_ID (0x40022100U) /* device ID information */
|
||||
|
||||
//#define USB_SERIAL_STRING_SIZE 0x1AU
|
||||
|
||||
/* USB device exported macros */
|
||||
#define BYTE_SWAP(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \
|
||||
(uint16_t)(((uint16_t)(*(((uint8_t *)(addr)) + 1U))) << 8U))
|
||||
#define BYTE_LOW(x) ((uint8_t)((x) & 0x00FFU))
|
||||
#define BYTE_HIGH(x) ((uint8_t)(((x) & 0xFF00U) >> 8U))
|
||||
|
||||
#define USB_MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define CTL_EP(ep) (((ep) == 0x00U) || ((ep) == 0x80U))
|
||||
|
||||
/* function declarations */
|
||||
/* handle USB standard device request */
|
||||
usb_reqsta usbd_standard_request (usb_dev *udev, usb_req *req);
|
||||
/* handle device class request */
|
||||
usb_reqsta usbd_class_request (usb_dev *udev, usb_req *req);
|
||||
/* handle USB vendor request */
|
||||
usb_reqsta usbd_vendor_request (usb_dev *udev, usb_req *req);
|
||||
/* get serial string */
|
||||
void serial_string_get (uint16_t *unicode_str);
|
||||
|
||||
#endif /* __USBD_ENUM_H */
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*!
|
||||
\file usbd_pwr.h
|
||||
\brief USB device power management functions prototype
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USBD_PWR_H
|
||||
#define __USBD_PWR_H
|
||||
|
||||
#include "usbd_core.h"
|
||||
|
||||
/* static inline function definitions */
|
||||
/*!
|
||||
\brief first operation of USB wakeup is to wakeup MCU
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void resume_mcu (usb_dev *udev)
|
||||
{
|
||||
udev->drv_handler->suspend_leave();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set USB device to suspend mode
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usbd_to_suspend (usb_dev *udev)
|
||||
{
|
||||
udev->drv_handler->suspend();
|
||||
}
|
||||
|
||||
/* function declarations */
|
||||
/* start to remote wakeup */
|
||||
void usbd_remote_wakeup_active (usb_dev *udev);
|
||||
|
||||
#endif /* __USBD_PWR_H */
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*!
|
||||
\file usbd_transc.h
|
||||
\brief USBD transaction
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USB_TRANSC_H
|
||||
#define __USB_TRANSC_H
|
||||
|
||||
#include "usbd_core.h"
|
||||
|
||||
/*!
|
||||
\brief USB transaction configure
|
||||
\param[in] transc: pointer to USB device transaction instance
|
||||
\param[in] buf: transfer data buffer
|
||||
\param[in] len: transfer data length
|
||||
\param[in] count: transfer data counter
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_transc_config (usb_transc *transc, uint8_t *buf, uint16_t len, uint16_t count)
|
||||
{
|
||||
transc->xfer_buf = buf;
|
||||
transc->xfer_len = len;
|
||||
transc->xfer_count = count;
|
||||
}
|
||||
|
||||
/* function declarations */
|
||||
/* process USB SETUP transaction */
|
||||
void _usb_setup_transc (usb_dev *udev, uint8_t ep_num);
|
||||
/* process USB OUT transaction */
|
||||
void _usb_out0_transc (usb_dev *udev, uint8_t ep_num);
|
||||
/* process USB IN transaction */
|
||||
void _usb_in0_transc (usb_dev *udev, uint8_t ep_num);
|
||||
|
||||
#endif /* __USB_TRANSC_H */
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*!
|
||||
\file usbd_core.c
|
||||
\brief USB device driver
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_core.h"
|
||||
#include "usbd_enum.h"
|
||||
#include "usbd_transc.h"
|
||||
#include "usbd_lld_core.h"
|
||||
|
||||
usbd_int_cb_struct *usbd_int_fops = NULL;
|
||||
|
||||
/*!
|
||||
\brief configure USB device initialization
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] desc: pointer to USB descriptor
|
||||
\param[in] usbc: USB class
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usbd_init (usb_dev *udev, usb_desc *desc, usb_class *usbc)
|
||||
{
|
||||
/* configure USBD core basic attributes */
|
||||
usbd_core.basic.max_ep_count = 8U;
|
||||
usbd_core.basic.twin_buf = 1U;
|
||||
usbd_core.basic.ram_size = 512U;
|
||||
|
||||
usbd_core.dev = udev;
|
||||
|
||||
udev->desc = desc;
|
||||
udev->class_core = usbc;
|
||||
udev->drv_handler = &usbd_drv_handler;
|
||||
|
||||
udev->ep_transc[0][TRANSC_SETUP] = _usb_setup_transc;
|
||||
udev->ep_transc[0][TRANSC_OUT] = _usb_out0_transc;
|
||||
udev->ep_transc[0][TRANSC_IN] = _usb_in0_transc;
|
||||
|
||||
/* configure power management */
|
||||
udev->pm.power_mode = (udev->desc->config_desc[7] & 0x40U) >> 5;
|
||||
|
||||
/* enable USB suspend */
|
||||
udev->pm.suspend_enabled = 1U;
|
||||
|
||||
/* USB low level initialization */
|
||||
udev->drv_handler->init();
|
||||
|
||||
/* create serial string */
|
||||
serial_string_get((uint16_t *)udev->desc->strings[STR_IDX_SERIAL]);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief endpoint prepare to receive data
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
in this parameter:
|
||||
bit0..bit6: endpoint number (0..7)
|
||||
bit7: endpoint direction which can be IN(1) or OUT(0)
|
||||
\param[in] pbuf: user buffer address pointer
|
||||
\param[in] buf_len: buffer length
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usbd_ep_recev (usb_dev *udev, uint8_t ep_addr, uint8_t *pbuf, uint16_t buf_len)
|
||||
{
|
||||
/* configure the transaction level parameters */
|
||||
usb_transc *transc = &udev->transc_out[EP_ID(ep_addr)];
|
||||
|
||||
usb_transc_config(transc, pbuf, buf_len, 0U);
|
||||
|
||||
/* enable endpoint to receive */
|
||||
udev->drv_handler->ep_rx_enable(udev, ep_addr);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief endpoint prepare to transmit data
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
in this parameter:
|
||||
bit0..bit6: endpoint number (0..7)
|
||||
bit7: endpoint direction which can be IN(1) or OUT(0)
|
||||
\param[in] pbuf: transmit buffer address pointer
|
||||
\param[in] buf_len: buffer length
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usbd_ep_send (usb_dev *udev, uint8_t ep_addr, uint8_t *pbuf, uint16_t buf_len)
|
||||
{
|
||||
uint8_t ep_num = EP_ID(ep_addr);
|
||||
|
||||
usb_transc *transc = &udev->transc_in[ep_num];
|
||||
|
||||
uint16_t len = USB_MIN(buf_len, transc->max_len);
|
||||
|
||||
/* configure the transaction level parameters */
|
||||
udev->drv_handler->ep_write(pbuf, ep_num, len);
|
||||
|
||||
usb_transc_config(transc, pbuf + len, buf_len - len, len);
|
||||
}
|
||||
+747
@@ -0,0 +1,747 @@
|
||||
/*!
|
||||
\file usbd_enum.c
|
||||
\brief USB enumeration function
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_enum.h"
|
||||
#include "usbd_transc.h"
|
||||
|
||||
/* USB enumeration handle functions */
|
||||
static usb_reqsta _usb_std_getstatus (usb_dev *udev, usb_req *req);
|
||||
static usb_reqsta _usb_std_clearfeature (usb_dev *udev, usb_req *req);
|
||||
static usb_reqsta _usb_std_setfeature (usb_dev *udev, usb_req *req);
|
||||
static usb_reqsta _usb_std_setaddress (usb_dev *udev, usb_req *req);
|
||||
static usb_reqsta _usb_std_getdescriptor (usb_dev *udev, usb_req *req);
|
||||
static usb_reqsta _usb_std_setdescriptor (usb_dev *udev, usb_req *req);
|
||||
static usb_reqsta _usb_std_getconfiguration (usb_dev *udev, usb_req *req);
|
||||
static usb_reqsta _usb_std_setconfiguration (usb_dev *udev, usb_req *req);
|
||||
static usb_reqsta _usb_std_reserved (usb_dev *udev, usb_req *req);
|
||||
static usb_reqsta _usb_std_getinterface (usb_dev *udev, usb_req *req);
|
||||
static usb_reqsta _usb_std_setinterface (usb_dev *udev, usb_req *req);
|
||||
static usb_reqsta _usb_std_synchframe (usb_dev *udev, usb_req *req);
|
||||
|
||||
static uint8_t* _usb_dev_desc_get (usb_dev *udev, uint8_t index, uint16_t *len);
|
||||
static uint8_t* _usb_config_desc_get (usb_dev *udev, uint8_t index, uint16_t *len);
|
||||
static uint8_t* _usb_str_desc_get (usb_dev *udev, uint8_t index, uint16_t *len);
|
||||
static uint8_t* _usb_bos_desc_get (usb_dev *udev, uint8_t index, uint16_t *len);
|
||||
|
||||
static void int_to_unicode (uint32_t value, uint8_t *pbuf, uint8_t len);
|
||||
|
||||
/* standard device request handler */
|
||||
static usb_reqsta (*_std_dev_req[]) (usb_dev *udev, usb_req *req) = {
|
||||
[USB_GET_STATUS] = _usb_std_getstatus,
|
||||
[USB_CLEAR_FEATURE] = _usb_std_clearfeature,
|
||||
[USB_RESERVED2] = _usb_std_reserved,
|
||||
[USB_SET_FEATURE] = _usb_std_setfeature,
|
||||
[USB_RESERVED4] = _usb_std_reserved,
|
||||
[USB_SET_ADDRESS] = _usb_std_setaddress,
|
||||
[USB_GET_DESCRIPTOR] = _usb_std_getdescriptor,
|
||||
[USB_SET_DESCRIPTOR] = _usb_std_setdescriptor,
|
||||
[USB_GET_CONFIGURATION] = _usb_std_getconfiguration,
|
||||
[USB_SET_CONFIGURATION] = _usb_std_setconfiguration,
|
||||
[USB_GET_INTERFACE] = _usb_std_getinterface,
|
||||
[USB_SET_INTERFACE] = _usb_std_setinterface,
|
||||
[USB_SYNCH_FRAME] = _usb_std_synchframe,
|
||||
};
|
||||
|
||||
/* get standard descriptor handler */
|
||||
static uint8_t* (*std_desc_get[])(usb_dev *udev, uint8_t index, uint16_t *len) = {
|
||||
[USB_DESCTYPE_DEV - 1U] = _usb_dev_desc_get,
|
||||
[USB_DESCTYPE_CONFIG - 1U] = _usb_config_desc_get,
|
||||
[USB_DESCTYPE_STR - 1U] = _usb_str_desc_get
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief handle USB standard device request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device operation cur_status
|
||||
*/
|
||||
usb_reqsta usbd_standard_request (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
/* call device request handle function */
|
||||
return (*_std_dev_req[req->bRequest]) (udev, req);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB device class request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device class request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
usb_reqsta usbd_class_request (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
if ((uint8_t)USBD_CONFIGURED == udev->cur_status) {
|
||||
if (BYTE_LOW(req->wIndex) < USBD_ITF_MAX_NUM) {
|
||||
/* call device class handle function */
|
||||
return (usb_reqsta)udev->class_core->req_process(udev, req);
|
||||
}
|
||||
}
|
||||
|
||||
return REQ_NOTSUPP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB vendor request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB vendor request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
usb_reqsta usbd_vendor_request (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
(void)udev;
|
||||
(void)req;
|
||||
|
||||
/* added by user */
|
||||
|
||||
return REQ_NOTSUPP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief no operation, just for reserved
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
static usb_reqsta _usb_std_reserved (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
(void)udev;
|
||||
(void)req;
|
||||
|
||||
/* no operation */
|
||||
return REQ_NOTSUPP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the device descriptor
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] index: no use
|
||||
\param[out] len: data length pointer
|
||||
\retval descriptor buffer pointer
|
||||
*/
|
||||
static uint8_t* _usb_dev_desc_get (usb_dev *udev, uint8_t index, uint16_t *len)
|
||||
{
|
||||
(void)index;
|
||||
|
||||
*len = udev->desc->dev_desc[0];
|
||||
|
||||
return udev->desc->dev_desc;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the configuration descriptor
|
||||
\brief[in] udev: pointer to USB device instance
|
||||
\brief[in] index: no use
|
||||
\param[out] len: data length pointer
|
||||
\retval descriptor buffer pointer
|
||||
*/
|
||||
static uint8_t* _usb_config_desc_get (usb_dev *udev, uint8_t index, uint16_t *len)
|
||||
{
|
||||
(void)index;
|
||||
|
||||
*len = udev->desc->config_desc[2] | (udev->desc->config_desc[3]<< 8U);
|
||||
|
||||
return udev->desc->config_desc;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the BOS descriptor
|
||||
\brief[in] udev: pointer to USB device instance
|
||||
\brief[in] index: no use
|
||||
\param[out] len: data length pointer
|
||||
\retval descriptor buffer pointer
|
||||
*/
|
||||
static uint8_t* _usb_bos_desc_get (usb_dev *udev, uint8_t index, uint16_t *len)
|
||||
{
|
||||
if (NULL != udev->desc->bos_desc) {
|
||||
(void)index;
|
||||
|
||||
*len = (uint16_t)udev->desc->bos_desc[2] | (uint16_t)((uint16_t)udev->desc->bos_desc[3] << 8);
|
||||
|
||||
return udev->desc->bos_desc;
|
||||
} else {
|
||||
*len = 0U;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get string descriptor
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] index: string descriptor index
|
||||
\param[out] len: pointer to string length
|
||||
\retval string descriptor
|
||||
*/
|
||||
static uint8_t* _usb_str_desc_get (usb_dev *udev, uint8_t index, uint16_t *len)
|
||||
{
|
||||
uint8_t* desc = udev->desc->strings[index];
|
||||
|
||||
*len = desc[0];
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle Get_Status request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
static usb_reqsta _usb_std_getstatus (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
uint8_t recp = BYTE_LOW(req->wIndex);
|
||||
|
||||
usb_reqsta req_status = REQ_NOTSUPP;
|
||||
|
||||
static uint8_t status[2] = {0U};
|
||||
|
||||
switch(req->bmRequestType & USB_RECPTYPE_MASK) {
|
||||
/* handle device get status request */
|
||||
case USB_RECPTYPE_DEV:
|
||||
switch (udev->cur_status) {
|
||||
case USBD_ADDRESSED:
|
||||
case USBD_CONFIGURED:
|
||||
if (udev->pm.power_mode) {
|
||||
status[0] = USB_STATUS_SELF_POWERED;
|
||||
} else {
|
||||
status[0] = 0U;
|
||||
}
|
||||
|
||||
if (udev->pm.remote_wakeup) {
|
||||
status[0] |= USB_STATUS_REMOTE_WAKEUP;
|
||||
} else {
|
||||
status[0] = 0U;
|
||||
}
|
||||
|
||||
req_status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* handle interface get status request */
|
||||
case USB_RECPTYPE_ITF:
|
||||
if (((uint8_t)USBD_CONFIGURED == udev->cur_status) && (recp < USBD_ITF_MAX_NUM)) {
|
||||
req_status = REQ_SUPP;
|
||||
}
|
||||
break;
|
||||
|
||||
/* handle endpoint get status request */
|
||||
case USB_RECPTYPE_EP:
|
||||
if ((uint8_t)USBD_CONFIGURED == udev->cur_status) {
|
||||
if (0x80U == (recp & 0x80U)) {
|
||||
status[0] = udev->transc_in[EP_ID(recp)].ep_stall;
|
||||
} else {
|
||||
status[0] = udev->transc_out[recp].ep_stall;
|
||||
}
|
||||
req_status = REQ_SUPP;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (REQ_SUPP == req_status) {
|
||||
usb_transc_config(&udev->transc_in[0], status, 2U, 2U);
|
||||
}
|
||||
|
||||
return req_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB Clear_Feature request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: USB device request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
static usb_reqsta _usb_std_clearfeature (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
uint8_t ep = 0U;
|
||||
|
||||
switch (req->bmRequestType & (uint8_t)USB_RECPTYPE_MASK) {
|
||||
case USB_RECPTYPE_DEV:
|
||||
switch (udev->cur_status) {
|
||||
case USBD_ADDRESSED:
|
||||
case USBD_CONFIGURED:
|
||||
/* clear device remote wakeup feature */
|
||||
if ((uint16_t)USB_FEATURE_REMOTE_WAKEUP == req->wValue) {
|
||||
udev->pm.remote_wakeup = 0U;
|
||||
|
||||
return REQ_SUPP;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_RECPTYPE_EP:
|
||||
/* get endpoint address */
|
||||
ep = BYTE_LOW(req->wIndex);
|
||||
|
||||
if ((uint8_t)USBD_CONFIGURED == udev->cur_status) {
|
||||
/* clear endpoint halt feature */
|
||||
if (((uint16_t)USB_FEATURE_EP_HALT == req->wValue) && (!CTL_EP(ep))) {
|
||||
usbd_ep_clear_stall(udev, ep);
|
||||
|
||||
udev->class_core->req_process(udev, req);
|
||||
|
||||
return REQ_SUPP;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_RECPTYPE_ITF:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return REQ_NOTSUPP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB Set_Feature request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
static usb_reqsta _usb_std_setfeature (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
uint8_t ep = 0U;
|
||||
|
||||
switch (req->bmRequestType & (uint8_t)USB_RECPTYPE_MASK) {
|
||||
case USB_RECPTYPE_DEV:
|
||||
switch (udev->cur_status) {
|
||||
case USBD_ADDRESSED:
|
||||
case USBD_CONFIGURED:
|
||||
/* set device remote wakeup feature */
|
||||
if ((uint16_t)USB_FEATURE_REMOTE_WAKEUP == req->wValue) {
|
||||
udev->pm.remote_wakeup = 1U;
|
||||
|
||||
return REQ_SUPP;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_RECPTYPE_EP:
|
||||
/* get endpoint address */
|
||||
ep = BYTE_LOW(req->wIndex);
|
||||
|
||||
if ((uint8_t)USBD_CONFIGURED == udev->cur_status) {
|
||||
/* set endpoint halt feature */
|
||||
if (((uint8_t)USB_FEATURE_EP_HALT == req->wValue) && (!CTL_EP(ep))) {
|
||||
usbd_ep_stall(udev, ep);
|
||||
|
||||
return REQ_SUPP;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_RECPTYPE_ITF:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return REQ_NOTSUPP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB Set_Address request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
static usb_reqsta _usb_std_setaddress (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
if ((0U == req->wIndex) && (0U == req->wLength)) {
|
||||
udev->dev_addr = (uint8_t)(req->wValue) & 0x7FU;
|
||||
|
||||
if (udev->cur_status != (uint8_t)USBD_CONFIGURED) {
|
||||
if (udev->dev_addr) {
|
||||
udev->cur_status = (uint8_t)USBD_ADDRESSED;
|
||||
} else {
|
||||
udev->cur_status = (uint8_t)USBD_DEFAULT;
|
||||
}
|
||||
|
||||
return REQ_SUPP;
|
||||
}
|
||||
}
|
||||
|
||||
return REQ_NOTSUPP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB Get_Descriptor request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
static usb_reqsta _usb_std_getdescriptor (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
uint8_t desc_type = 0U;
|
||||
uint8_t desc_index = 0U;
|
||||
|
||||
usb_reqsta status = REQ_NOTSUPP;
|
||||
|
||||
usb_transc *transc = &udev->transc_in[0];
|
||||
|
||||
switch (req->bmRequestType & USB_RECPTYPE_MASK) {
|
||||
case USB_RECPTYPE_DEV:
|
||||
desc_type = BYTE_HIGH(req->wValue);
|
||||
desc_index = BYTE_LOW(req->wValue);
|
||||
|
||||
switch (desc_type) {
|
||||
case USB_DESCTYPE_DEV:
|
||||
transc->xfer_buf = std_desc_get[desc_type - 1U](udev, desc_index, &transc->xfer_len);
|
||||
if (64U == req->wLength) {
|
||||
transc->xfer_len = 8U;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DESCTYPE_CONFIG:
|
||||
transc->xfer_buf = std_desc_get[desc_type - 1U](udev, desc_index, &transc->xfer_len);
|
||||
break;
|
||||
|
||||
case USB_DESCTYPE_STR:
|
||||
if (desc_index < STR_IDX_MAX) {
|
||||
transc->xfer_buf = std_desc_get[desc_type - 1U](udev, desc_index, &transc->xfer_len);
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DESCTYPE_ITF:
|
||||
case USB_DESCTYPE_EP:
|
||||
case USB_DESCTYPE_DEV_QUALIFIER:
|
||||
case USB_DESCTYPE_OTHER_SPD_CONFIG:
|
||||
case USB_DESCTYPE_ITF_POWER:
|
||||
break;
|
||||
|
||||
case USB_DESCTYPE_BOS:
|
||||
transc->xfer_buf = _usb_bos_desc_get(udev, desc_index, &transc->xfer_len);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_RECPTYPE_ITF:
|
||||
/* get device class special descriptor */
|
||||
status = (usb_reqsta)(udev->class_core->req_process(udev, req));
|
||||
break;
|
||||
|
||||
case USB_RECPTYPE_EP:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((transc->xfer_len) && (req->wLength)) {
|
||||
transc->xfer_len = USB_MIN(transc->xfer_len, req->wLength);
|
||||
|
||||
if ((transc->xfer_len < udev->control.req.wLength) &&
|
||||
(0U == transc->xfer_len % transc->max_len)) {
|
||||
udev->control.ctl_zlp = 1U;
|
||||
}
|
||||
|
||||
status = REQ_SUPP;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB Set_Descriptor request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
static usb_reqsta _usb_std_setdescriptor (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
(void)udev;
|
||||
(void)req;
|
||||
|
||||
/* no handle */
|
||||
return REQ_SUPP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB Get_Configuration request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
static usb_reqsta _usb_std_getconfiguration (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
(void)req;
|
||||
|
||||
usb_reqsta req_status = REQ_NOTSUPP;
|
||||
|
||||
switch (udev->cur_status) {
|
||||
case USBD_ADDRESSED:
|
||||
if (0U == udev->config) {
|
||||
req_status = REQ_SUPP;
|
||||
}
|
||||
break;
|
||||
|
||||
case USBD_CONFIGURED:
|
||||
if (udev->config) {
|
||||
req_status = REQ_SUPP;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (REQ_SUPP == req_status) {
|
||||
usb_transc_config(&udev->transc_in[0], &(udev->config), 1U, 1U);
|
||||
}
|
||||
|
||||
return req_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB Set_Configuration request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device operation cur_status
|
||||
*/
|
||||
static usb_reqsta _usb_std_setconfiguration (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
static uint8_t config;
|
||||
usb_reqsta status = REQ_NOTSUPP;
|
||||
|
||||
config = (uint8_t)(req->wValue);
|
||||
|
||||
if (config <= USBD_CFG_MAX_NUM) {
|
||||
switch (udev->cur_status) {
|
||||
case USBD_ADDRESSED:
|
||||
if (config){
|
||||
(void)udev->class_core->init(udev, config);
|
||||
|
||||
udev->config = config;
|
||||
udev->cur_status = (uint8_t)USBD_CONFIGURED;
|
||||
}
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case USBD_CONFIGURED:
|
||||
if (0U == config) {
|
||||
(void)udev->class_core->deinit(udev, config);
|
||||
|
||||
udev->config = config;
|
||||
udev->cur_status = (uint8_t)USBD_ADDRESSED;
|
||||
} else if (config != udev->config) {
|
||||
/* clear old configuration */
|
||||
(void)udev->class_core->deinit(udev, udev->config);
|
||||
|
||||
/* set new configuration */
|
||||
udev->config = config;
|
||||
|
||||
(void)udev->class_core->init(udev, config);
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
status = REQ_SUPP;
|
||||
break;
|
||||
|
||||
case USBD_DEFAULT:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB Get_Interface request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
static usb_reqsta _usb_std_getinterface (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
switch (udev->cur_status) {
|
||||
case USBD_DEFAULT:
|
||||
break;
|
||||
|
||||
case USBD_ADDRESSED:
|
||||
break;
|
||||
|
||||
case USBD_CONFIGURED:
|
||||
if (BYTE_LOW(req->wIndex) < USBD_ITF_MAX_NUM) {
|
||||
usb_transc_config(&udev->transc_in[0], &(udev->class_core->req_altset), 1U, 1U);
|
||||
|
||||
return REQ_SUPP;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return REQ_NOTSUPP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB Set_Interface request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
static usb_reqsta _usb_std_setinterface (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
switch (udev->cur_status) {
|
||||
case USBD_DEFAULT:
|
||||
break;
|
||||
|
||||
case USBD_ADDRESSED:
|
||||
break;
|
||||
|
||||
case USBD_CONFIGURED:
|
||||
if (BYTE_LOW(req->wIndex) < USBD_ITF_MAX_NUM) {
|
||||
udev->class_core->req_altset = (uint8_t)req->wValue;
|
||||
|
||||
return REQ_SUPP;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return REQ_NOTSUPP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB SynchFrame request
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] req: pointer to USB device request
|
||||
\param[out] none
|
||||
\retval USB device request status
|
||||
*/
|
||||
static usb_reqsta _usb_std_synchframe (usb_dev *udev, usb_req *req)
|
||||
{
|
||||
(void)udev;
|
||||
(void)req;
|
||||
|
||||
/* no handle */
|
||||
return REQ_SUPP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief convert hex 32bits value into unicode char
|
||||
\param[in] value: Hex 32bits value
|
||||
\param[in] pbuf: buffer pointer to store unicode char
|
||||
\param[in] len: value length
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void int_to_unicode (uint32_t value, uint8_t *pbuf, uint8_t len)
|
||||
{
|
||||
uint8_t index = 0U;
|
||||
|
||||
for (index = 0U; index < len; index++) {
|
||||
if ((value >> 28U) < 0x0AU) {
|
||||
pbuf[2U * index] = (uint8_t)((value >> 28) + '0');
|
||||
} else {
|
||||
pbuf[2U * index] = (uint8_t)((value >> 28) + 'A' - 10U);
|
||||
}
|
||||
|
||||
value = value << 4U;
|
||||
|
||||
pbuf[2U * index + 1U] = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief convert hex 32bits value into unicode char
|
||||
\param[in] unicode_str: pointer to unicode string
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void serial_string_get (uint16_t *unicode_str)
|
||||
{
|
||||
if (6U != (unicode_str[0] & 0x00FFU)) {
|
||||
uint32_t DeviceSerial0, DeviceSerial1, DeviceSerial2;
|
||||
|
||||
DeviceSerial0 = *(uint32_t*)DEVICE_ID1;
|
||||
DeviceSerial1 = *(uint32_t*)DEVICE_ID2;
|
||||
DeviceSerial2 = *(uint32_t*)DEVICE_ID3;
|
||||
|
||||
DeviceSerial0 += DeviceSerial2;
|
||||
|
||||
if (0U != DeviceSerial0) {
|
||||
int_to_unicode(DeviceSerial0, (uint8_t*)&(unicode_str[1]), 8U);
|
||||
int_to_unicode(DeviceSerial1, (uint8_t*)&(unicode_str[9]), 4U);
|
||||
}
|
||||
} else {
|
||||
uint32_t device_serial = *(uint32_t*)DEVICE_ID;
|
||||
|
||||
if (0U != device_serial) {
|
||||
unicode_str[1] = (uint16_t)(device_serial & 0x0000FFFFU);
|
||||
unicode_str[2] = (uint16_t)((device_serial & 0xFFFF0000U) >> 16U);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*!
|
||||
\file usbd_pwr.c
|
||||
\brief USB device power management driver
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_pwr.h"
|
||||
|
||||
/*!
|
||||
\brief start to remote wakeup
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usbd_remote_wakeup_active(usb_dev *udev)
|
||||
{
|
||||
resume_mcu(udev);
|
||||
|
||||
#ifdef LPM_ENABLED
|
||||
if(1U == udev->lpm.L1_remote_wakeup){
|
||||
udev->drv_handler->resume(udev);
|
||||
|
||||
udev->lpm.L1_resume = 1U;
|
||||
}
|
||||
#endif /* LPM_ENABLED */
|
||||
|
||||
if(1U == udev->pm.remote_wakeup){
|
||||
udev->pm.remote_wakeup_on = 1U;
|
||||
udev->pm.esof_count = 15U;
|
||||
udev->drv_handler->resume(udev);
|
||||
}
|
||||
}
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
/*!
|
||||
\file usbd_transc.c
|
||||
\brief USBD transaction function
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_enum.h"
|
||||
#include "usbd_transc.h"
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static inline void usb_stall_transc (usb_dev *udev);
|
||||
static inline void usb_ctl_status_in (usb_dev *udev);
|
||||
static inline void usb_ctl_data_in (usb_dev *udev);
|
||||
static inline void usb_ctl_out (usb_dev *udev);
|
||||
static inline void usb_0len_packet_send (usb_dev *udev);
|
||||
|
||||
/*!
|
||||
\brief USB setup stage processing
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint identifier(0..7)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void _usb_setup_transc (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
(void)ep_num;
|
||||
|
||||
usb_reqsta reqstat = REQ_NOTSUPP;
|
||||
|
||||
uint16_t count = udev->drv_handler->ep_read((uint8_t *)(&udev->control.req), 0U, (uint8_t)EP_BUF_SNG);
|
||||
|
||||
if (count != USB_SETUP_PACKET_LEN) {
|
||||
usb_stall_transc(udev);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (udev->control.req.bmRequestType & USB_REQTYPE_MASK) {
|
||||
/* standard device request */
|
||||
case USB_REQTYPE_STRD:
|
||||
reqstat = usbd_standard_request(udev, &udev->control.req);
|
||||
break;
|
||||
|
||||
/* device class request */
|
||||
case USB_REQTYPE_CLASS:
|
||||
reqstat = usbd_class_request(udev, &udev->control.req);
|
||||
break;
|
||||
|
||||
/* vendor defined request */
|
||||
case USB_REQTYPE_VENDOR:
|
||||
reqstat = usbd_vendor_request(udev, &udev->control.req);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (REQ_SUPP == reqstat) {
|
||||
if (0U == udev->control.req.wLength) {
|
||||
/* USB control transfer status in stage */
|
||||
usb_ctl_status_in(udev);
|
||||
} else {
|
||||
if (udev->control.req.bmRequestType & 0x80U) {
|
||||
usb_ctl_data_in(udev);
|
||||
} else {
|
||||
/* USB control transfer data out stage */
|
||||
usb_ctl_out(udev);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
usb_stall_transc(udev);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief data out stage processing
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint identifier(0..7)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void _usb_out0_transc (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
if (((uint8_t)USBD_CONFIGURED == udev->cur_status) && (udev->class_core->ctlx_out != NULL)) {
|
||||
/* device class handle */
|
||||
(void)udev->class_core->ctlx_out(udev);
|
||||
}
|
||||
|
||||
usb_transc_config(&udev->transc_out[ep_num], NULL, 0U, 0U);
|
||||
|
||||
/* enter the control transaction status in stage */
|
||||
usb_ctl_status_in(udev);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief data in stage processing
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint identifier(0..7)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void _usb_in0_transc (usb_dev *udev, uint8_t ep_num)
|
||||
{
|
||||
(void)ep_num;
|
||||
|
||||
if (udev->control.ctl_zlp) {
|
||||
/* send 0 length packet */
|
||||
usb_0len_packet_send(udev);
|
||||
|
||||
udev->control.ctl_zlp = 0U;
|
||||
}
|
||||
|
||||
if (((uint8_t)USBD_CONFIGURED == udev->cur_status) && (udev->class_core->ctlx_in != NULL)) {
|
||||
(void)udev->class_core->ctlx_in(udev);
|
||||
}
|
||||
|
||||
/* USB control transfer status out stage */
|
||||
usb_ctl_out(udev);
|
||||
|
||||
if (0U != udev->dev_addr) {
|
||||
udev->drv_handler->set_addr(udev);
|
||||
|
||||
udev->dev_addr = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB stalled transaction
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static inline void usb_stall_transc (usb_dev *udev)
|
||||
{
|
||||
usbd_ep_stall(udev, 0x0U);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB control transaction status in stage
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static inline void usb_ctl_status_in (usb_dev *udev)
|
||||
{
|
||||
udev->drv_handler->ep_write(udev->transc_in[0].xfer_buf, 0U, 0U);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB control transaction data in stage
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static inline void usb_ctl_data_in (usb_dev *udev)
|
||||
{
|
||||
usbd_ep_send(udev, 0U, udev->transc_in[0].xfer_buf, udev->transc_in[0].xfer_len);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB control transaction data out & status out stage
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static inline void usb_ctl_out (usb_dev *udev)
|
||||
{
|
||||
udev->drv_handler->ep_rx_enable(udev, 0U);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB send 0 length data packet
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static inline void usb_0len_packet_send (usb_dev *udev)
|
||||
{
|
||||
udev->drv_handler->ep_write(udev->transc_in[0].xfer_buf, 0U, 0U);
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*!
|
||||
\file usbd_lld_core.h
|
||||
\brief USB device low level driver core
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USBD_LLD_CORE_H
|
||||
#define __USBD_LLD_CORE_H
|
||||
|
||||
#include "usbd_lld_regs.h"
|
||||
#include "usbd_core.h"
|
||||
|
||||
/* double buffer endpoint direction enumeration */
|
||||
enum dbuf_ep_dir
|
||||
{
|
||||
DBUF_EP_IN, /*!< double buffer in direction */
|
||||
DBUF_EP_OUT, /*!< double buffer out direction */
|
||||
DBUF_EP_ERR, /*!< double buffer error direction */
|
||||
};
|
||||
|
||||
/* USBD endpoint ram structure */
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t tx_addr; /*!< transmission address */
|
||||
__IO uint32_t tx_count; /*!< transmission count */
|
||||
__IO uint32_t rx_addr; /*!< reception address */
|
||||
__IO uint32_t rx_count; /*!< reception count */
|
||||
} usbd_ep_ram;
|
||||
|
||||
extern struct _usb_handler usbd_drv_handler;
|
||||
|
||||
/* USB core driver structure */
|
||||
typedef struct
|
||||
{
|
||||
usb_basic basic;
|
||||
usb_dev *dev;
|
||||
} usb_core_drv;
|
||||
|
||||
extern usb_core_drv usbd_core;
|
||||
|
||||
/* function declarations */
|
||||
/* free buffer used from application by toggling the SW_BUF byte */
|
||||
void user_buffer_free (uint8_t ep_num, uint8_t dir);
|
||||
|
||||
#endif /* __USBD_LLD_CORE_H */
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*!
|
||||
\file usbd_lld_int.h
|
||||
\brief USB device low level interrupt handler
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USBD_LLD_INT_H
|
||||
#define __USBD_LLD_INT_H
|
||||
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_enum.h"
|
||||
#include "usbd_pwr.h"
|
||||
|
||||
/* function declarations */
|
||||
/* USB device interrupt service routine */
|
||||
void usbd_isr (void);
|
||||
/* handle USB high priority successful transfer event */
|
||||
void usbd_int_hpst (usb_dev *udev);
|
||||
|
||||
#endif /* __USBD_LLD_INT_H */
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
/*!
|
||||
\file usbd_lld_regs.h
|
||||
\brief USB device low level registers
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef __USBD_LLD_REGS_H
|
||||
#define __USBD_LLD_REGS_H
|
||||
|
||||
#include "usbd_conf.h"
|
||||
|
||||
/* USB device registers base address */
|
||||
#define USBD USBD_BASE
|
||||
#define USBD_RAM USBD_RAM_BASE
|
||||
|
||||
/* registers definitions */
|
||||
/* common registers */
|
||||
#define USBD_CTL (REG32(USBD + 0x40U)) /*!< control register */
|
||||
#define USBD_INTF (REG32(USBD + 0x44U)) /*!< interrupt flag register */
|
||||
#define USBD_STAT (REG32(USBD + 0x48U)) /*!< status register */
|
||||
#define USBD_DADDR (REG32(USBD + 0x4CU)) /*!< device address register */
|
||||
#define USBD_BADDR (REG32(USBD + 0x50U)) /*!< buffer address register */
|
||||
#define USBD_LPMCS (REG32(USBD + 0x54U)) /*!< USBD LPM control and status register */
|
||||
|
||||
/* endpoint control and status register */
|
||||
#define USBD_EPxCS(ep_num) (REG32(USBD + (ep_num) * 4U)) /*!< endpoint x control and status register address */
|
||||
|
||||
/* bits definitions */
|
||||
/* USBD_CTL */
|
||||
#define CTL_STIE BIT(15) /*!< successful transfer interrupt enable mask */
|
||||
#define CTL_PMOUIE BIT(14) /*!< packet memory overrun/underrun interrupt enable mask */
|
||||
#define CTL_ERRIE BIT(13) /*!< error interrupt enable mask */
|
||||
#define CTL_WKUPIE BIT(12) /*!< wakeup interrupt enable mask */
|
||||
#define CTL_SPSIE BIT(11) /*!< suspend state interrupt enable mask */
|
||||
#define CTL_RSTIE BIT(10) /*!< reset interrupt enable mask */
|
||||
#define CTL_SOFIE BIT(9) /*!< start of frame interrupt enable mask */
|
||||
#define CTL_ESOFIE BIT(8) /*!< expected start of frame interrupt enable mask */
|
||||
#define CTL_L1REQIE BIT(7) /*!< LPM L1 state request interrupt enable */
|
||||
#define CTL_L1RSREQ BIT(5) /*!< LPM L1 resume request */
|
||||
#define CTL_RSREQ BIT(4) /*!< resume request */
|
||||
#define CTL_SETSPS BIT(3) /*!< set suspend state */
|
||||
#define CTL_LOWM BIT(2) /*!< low-power mode at suspend state */
|
||||
#define CTL_CLOSE BIT(1) /*!< goes to close state */
|
||||
#define CTL_SETRST BIT(0) /*!< set USB reset */
|
||||
|
||||
#ifdef LPM_ENABLED
|
||||
#define USBD_INTEN BITS(7, 15) /*!< USBD interrupt enable bits */
|
||||
#else
|
||||
#define USBD_INTEN BITS(8, 15) /*!< USBD interrupt enable bits */
|
||||
#endif
|
||||
/* USBD_INTF */
|
||||
#define INTF_STIF BIT(15) /*!< successful transfer interrupt flag (read only bit) */
|
||||
#define INTF_PMOUIF BIT(14) /*!< packet memory overrun/underrun interrupt flag (clear-only bit) */
|
||||
#define INTF_ERRIF BIT(13) /*!< error interrupt flag (clear-only bit) */
|
||||
#define INTF_WKUPIF BIT(12) /*!< wakeup interrupt flag (clear-only bit) */
|
||||
#define INTF_SPSIF BIT(11) /*!< suspend state interrupt flag (clear-only bit) */
|
||||
#define INTF_RSTIF BIT(10) /*!< reset interrupt flag (clear-only bit) */
|
||||
#define INTF_SOFIF BIT(9) /*!< start of frame interrupt flag (clear-only bit) */
|
||||
#define INTF_ESOFIF BIT(8) /*!< expected start of frame interrupt flag(clear-only bit) */
|
||||
#define INTF_L1REQ BIT(7) /*!< LPM L1 transaction is successfully received and acknowledged */
|
||||
#define INTF_DIR BIT(4) /*!< direction of transaction (read-only bit) */
|
||||
#define INTF_EPNUM BITS(0, 3) /*!< endpoint number (read-only bit) */
|
||||
|
||||
/* USBD_STAT */
|
||||
#define STAT_RXDP BIT(15) /*!< data plus line status */
|
||||
#define STAT_RXDM BIT(14) /*!< data minus line status */
|
||||
#define STAT_LOCK BIT(13) /*!< locked the USB */
|
||||
#define STAT_SOFLN BITS(11, 12) /*!< SOF lost number */
|
||||
#define STAT_FCNT BITS(0, 10) /*!< frame number count */
|
||||
|
||||
/* USBD_DADDR */
|
||||
#define DADDR_USBEN BIT(7) /*!< USB module enable */
|
||||
#define DADDR_USBADDR BITS(0, 6) /*!< USB device address */
|
||||
|
||||
/* USBD_EPxCS */
|
||||
#define EPxCS_RX_ST BIT(15) /*!< endpoint reception successful transferred */
|
||||
#define EPxCS_RX_DTG BIT(14) /*!< endpoint reception data PID toggle */
|
||||
#define EPxCS_RX_STA BITS(12, 13) /*!< endpoint reception status bits */
|
||||
#define EPxCS_SETUP BIT(11) /*!< endpoint setup transaction completed */
|
||||
#define EPxCS_CTL BITS(9, 10) /*!< endpoint type control */
|
||||
#define EPxCS_KCTL BIT(8) /*!< endpoint kind control */
|
||||
#define EPxCS_TX_ST BIT(7) /*!< endpoint transmission successful transfer */
|
||||
#define EPxCS_TX_DTG BIT(6) /*!< endpoint transmission data toggle */
|
||||
#define EPxCS_TX_STA BITS(4, 5) /*!< endpoint transmission transfers status bits */
|
||||
#define EPxCS_AR BITS(0, 3) /*!< endpoint address */
|
||||
|
||||
/* USBD_LPMCS */
|
||||
#define LPMCS_BLSTAT BITS(4, 7) /*!< bLinkState value */
|
||||
#define LPMCS_REMWK BIT(3) /*!< bRemoteWake value */
|
||||
#define LPMCS_LPMACK BIT(1) /*!< LPM token acknowledge enable */
|
||||
#define LPMCS_LPMEN BIT(0) /*!< LPM support enable */
|
||||
|
||||
/* constants definitions */
|
||||
/* endpoint control and status register mask (no toggle fields) */
|
||||
#define EPCS_MASK (EPxCS_RX_ST | EPxCS_SETUP | \
|
||||
EPxCS_CTL | EPxCS_KCTL | EPxCS_TX_ST | EPxCS_AR)
|
||||
|
||||
/* EPxCS_CTL[1:0] endpoint type control */
|
||||
#define ENDP_TYPE(regval) (EPxCS_CTL & ((regval) << 9U))
|
||||
|
||||
#define EP_BULK ENDP_TYPE(0U) /* bulk transfers */
|
||||
#define EP_CONTROL ENDP_TYPE(1U) /* control transfers */
|
||||
#define EP_ISO ENDP_TYPE(2U) /* isochronous transfers */
|
||||
#define EP_INTERRUPT ENDP_TYPE(3U) /* interrupt transfers */
|
||||
#define EP_CTL_MASK (~EPxCS_CTL & EPCS_MASK)
|
||||
|
||||
/* endpoint kind control mask */
|
||||
#define EPKCTL_MASK (~EPxCS_KCTL & EPCS_MASK)
|
||||
|
||||
/* EPxCS_TX_STA[1:0] status for TX transfer */
|
||||
#define ENDP_TXSTAT(regval) (EPxCS_TX_STA & ((regval) << 4U))
|
||||
|
||||
#define EPTX_DISABLED ENDP_TXSTAT(0U) /* transmission state is disabled */
|
||||
#define EPTX_STALL ENDP_TXSTAT(1U) /* transmission state is STALL */
|
||||
#define EPTX_NAK ENDP_TXSTAT(2U) /* transmission state is NAK */
|
||||
#define EPTX_VALID ENDP_TXSTAT(3U) /* transmission state is enabled */
|
||||
#define EPTX_DTGMASK (EPxCS_TX_STA | EPCS_MASK)
|
||||
|
||||
/* EPxCS_RX_STA[1:0] status for RX transfer */
|
||||
#define ENDP_RXSTAT(regval) (EPxCS_RX_STA & ((regval) << 12U))
|
||||
|
||||
#define EPRX_DISABLED ENDP_RXSTAT(0U) /* reception state is disabled */
|
||||
#define EPRX_STALL ENDP_RXSTAT(1U) /* reception state is STALL */
|
||||
#define EPRX_NAK ENDP_RXSTAT(2U) /* reception state is NAK */
|
||||
#define EPRX_VALID ENDP_RXSTAT(3U) /* reception state is enabled */
|
||||
#define EPRX_DTGMASK (EPxCS_RX_STA | EPCS_MASK)
|
||||
|
||||
/* endpoint receive/transmission counter register bit definitions */
|
||||
#define EPRCNT_BLKSIZ BIT(15) /* reception data block size */
|
||||
#define EPRCNT_BLKNUM BITS(10, 14) /* reception data block number */
|
||||
#define EPRCNT_CNT BITS(0, 9) /* reception data count */
|
||||
|
||||
#define EPTCNT_CNT BITS(0, 9) /* transmisson data count */
|
||||
|
||||
/* interrupt flag clear bits */
|
||||
#define CLR(x) (USBD_INTF = ~INTF_##x)
|
||||
|
||||
/* endpoint receive/transmission counter register bit offset */
|
||||
#define BLKSIZE_OFFSET (0x01U)
|
||||
#define BLKNUM_OFFSET (0x05U)
|
||||
#define RXCNT_OFFSET (0x0AU)
|
||||
|
||||
#define TXCNT_OFFSET (0x0AU)
|
||||
|
||||
#define BLKSIZE32_MASK (0x1fU)
|
||||
#define BLKSIZE2_MASK (0x01U)
|
||||
|
||||
#define BLKSIZE32_OFFSETMASK (0x05U)
|
||||
#define BLKSIZE2_OFFSETMASK (0x01U)
|
||||
|
||||
/* USBD operation macros */
|
||||
|
||||
/* TX or RX transfer status setting (bits EPTX_STA[1:0]) */
|
||||
|
||||
#define USBD_EP_TX_STAT_SET(ep, stat) do {\
|
||||
USBD_EPxCS(ep) = (USBD_EPxCS(ep) & (uint16_t)EPTX_DTGMASK) ^ (stat); \
|
||||
} while(0)
|
||||
|
||||
#define USBD_EP_RX_STAT_SET(ep, stat) do {\
|
||||
USBD_EPxCS(ep) = (USBD_EPxCS(ep) & (uint16_t)EPRX_DTGMASK) ^ (stat); \
|
||||
} while(0)
|
||||
|
||||
/* clear bit EPxCS_RX_ST/EPxCS_TX_ST in the endpoint control and status register */
|
||||
|
||||
#define USBD_EP_TX_ST_CLEAR(ep) do {\
|
||||
USBD_EPxCS(ep) &= ~EPxCS_TX_ST & (uint16_t)EPCS_MASK; \
|
||||
} while(0)
|
||||
|
||||
#define USBD_EP_RX_ST_CLEAR(ep) do {\
|
||||
USBD_EPxCS(ep) &= ~EPxCS_RX_ST & (uint16_t)EPCS_MASK; \
|
||||
} while(0)
|
||||
|
||||
/* toggle EPxCS_RX_DTG or EPxCS_TX_DTG bit in the endpoint control and status register */
|
||||
|
||||
#define USBD_TX_DTG_TOGGLE(ep) do {\
|
||||
USBD_EPxCS(ep) = EPxCS_TX_DTG | (USBD_EPxCS(ep) & EPCS_MASK); \
|
||||
} while(0)
|
||||
|
||||
#define USBD_RX_DTG_TOGGLE(ep) do {\
|
||||
USBD_EPxCS(ep) = EPxCS_RX_DTG | (USBD_EPxCS(ep) & EPCS_MASK); \
|
||||
} while(0)
|
||||
|
||||
/* clear EPxCS_RX_DTG or EPxCS_TX_DTG bit in the endpoint control and status register */
|
||||
|
||||
#define USBD_TX_DTG_CLEAR(ep) do {\
|
||||
if ((USBD_EPxCS(ep_num) & EPxCS_TX_DTG) != 0U) {\
|
||||
USBD_TX_DTG_TOGGLE(ep);\
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define USBD_RX_DTG_CLEAR(ep) do {\
|
||||
if ((USBD_EPxCS(ep_num) & EPxCS_RX_DTG) != 0U) {\
|
||||
USBD_RX_DTG_TOGGLE(ep);\
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define USBD_EP_DBL_BUF_SET(ep) (USBD_EPxCS(ep) = (USBD_EPxCS(ep) | EPxCS_KCTL) & EPCS_MASK)
|
||||
|
||||
#endif /* __USBD_LLD_REGS_H */
|
||||
+632
@@ -0,0 +1,632 @@
|
||||
/*!
|
||||
\file usbd_lld_core.c
|
||||
\brief USB device low level driver core
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
\version 2021-08-10, V3.0.1, firmware for GD32F10x
|
||||
\version 2021-08-18, V3.0.2, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_lld_core.h"
|
||||
#include "usbd_enum.h"
|
||||
|
||||
#define USB_EPTYPE_MASK 0x03U
|
||||
|
||||
#if defined (__CC_ARM) /* ARM Compiler */
|
||||
static usbd_ep_ram btable_ep[EP_COUNT]__attribute__((at(USBD_RAM + 2 * (BTABLE_OFFSET & 0xFFF8))));
|
||||
#elif defined (__ICCARM__) /* IAR Compiler */
|
||||
__no_init usbd_ep_ram btable_ep[EP_COUNT] @(USBD_RAM + 2 * (BTABLE_OFFSET & 0xFFF8));
|
||||
#elif defined (__GNUC__) /* GNU GCC Compiler */
|
||||
usbd_ep_ram *btable_ep = (usbd_ep_ram *)(USBD_RAM + 2 * (BTABLE_OFFSET & 0xFFF8));
|
||||
#endif
|
||||
|
||||
usb_core_drv usbd_core;
|
||||
|
||||
static const uint32_t ep_type[] = {
|
||||
[USB_EP_ATTR_CTL] = EP_CONTROL,
|
||||
[USB_EP_ATTR_BULK] = EP_BULK,
|
||||
[USB_EP_ATTR_INT] = EP_INTERRUPT,
|
||||
[USB_EP_ATTR_ISO] = EP_ISO
|
||||
};
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static void usbd_dp_pullup (FlagStatus status);
|
||||
static void usbd_core_reset (void);
|
||||
static void usbd_core_stop (void);
|
||||
static void usbd_address_set (usb_dev *udev);
|
||||
static void usbd_ep_reset (usb_dev *udev);
|
||||
static void usbd_ep_setup (usb_dev *udev, uint8_t buf_kind, uint32_t buf_addr, const usb_desc_ep *ep_desc);
|
||||
static void usbd_ep_rx_enable (usb_dev *udev, uint8_t ep_addr);
|
||||
static void usbd_ep_disable (usb_dev *udev, uint8_t ep_addr);
|
||||
static void usbd_ep_stall_set (usb_dev *udev, uint8_t ep_addr);
|
||||
static void usbd_ep_stall_clear (usb_dev *udev, uint8_t ep_addr);
|
||||
static void usbd_ep_data_write (uint8_t *user_fifo, uint8_t ep_num, uint16_t bytes);
|
||||
static uint16_t usbd_ep_data_read (uint8_t *user_fifo, uint8_t ep_num, uint8_t buf_kind);
|
||||
static void usbd_resume (usb_dev *udev);
|
||||
static void usbd_suspend (void);
|
||||
static void usbd_leave_suspend (void);
|
||||
static uint8_t usbd_ep_status (usb_dev *udev, uint8_t ep_addr);
|
||||
|
||||
struct _usb_handler usbd_drv_handler = {
|
||||
.dp_pullup = usbd_dp_pullup,
|
||||
.init = usbd_core_reset,
|
||||
.deinit = usbd_core_stop,
|
||||
.suspend = usbd_suspend,
|
||||
.suspend_leave = usbd_leave_suspend,
|
||||
.resume = usbd_resume,
|
||||
.set_addr = usbd_address_set,
|
||||
.ep_reset = usbd_ep_reset,
|
||||
.ep_disable = usbd_ep_disable,
|
||||
.ep_setup = usbd_ep_setup,
|
||||
.ep_rx_enable = usbd_ep_rx_enable,
|
||||
.ep_write = usbd_ep_data_write,
|
||||
.ep_read = usbd_ep_data_read,
|
||||
.ep_stall_set = usbd_ep_stall_set,
|
||||
.ep_stall_clear = usbd_ep_stall_clear,
|
||||
.ep_status_get = usbd_ep_status
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief free buffer used from application by toggling the SW_BUF byte
|
||||
\param[in] ep_num: endpoint identifier (0..7)
|
||||
\param[in] dir: endpoint direction which can be OUT(0) or IN(1)
|
||||
\param[out] none
|
||||
\retval None
|
||||
*/
|
||||
void user_buffer_free (uint8_t ep_num, uint8_t dir)
|
||||
{
|
||||
if ((uint8_t)DBUF_EP_OUT == dir) {
|
||||
USBD_TX_DTG_TOGGLE(ep_num);
|
||||
} else if ((uint8_t)DBUF_EP_IN == dir) {
|
||||
USBD_RX_DTG_TOGGLE(ep_num);
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the status of pull-up pin
|
||||
\param[in] status: SET or RESET
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_dp_pullup (FlagStatus status)
|
||||
{
|
||||
if (SET == status) {
|
||||
gpio_bit_set(USB_PULLUP, USB_PULLUP_PIN);
|
||||
} else {
|
||||
gpio_bit_reset(USB_PULLUP, USB_PULLUP_PIN);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief device core register initialization
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_core_reset (void)
|
||||
{
|
||||
/* reset the CLOSE bit */
|
||||
USBD_CTL = CTL_SETRST;
|
||||
|
||||
/* may be need wait some time(tSTARTUP) ... */
|
||||
|
||||
/* clear SETRST bit in USBD_CTL register */
|
||||
USBD_CTL = 0U;
|
||||
|
||||
/* clear all pending interrupts */
|
||||
USBD_INTF = 0U;
|
||||
|
||||
/* set descriptors table offset in USB dedicated SRAM */
|
||||
USBD_BADDR = BTABLE_OFFSET & 0xFFF8U;
|
||||
|
||||
#ifdef LPM_ENABLED
|
||||
/* enable L1REQ interrupt */
|
||||
USBD_CTL = CTL_L1REQIE;
|
||||
|
||||
USBD_LPMCS = LPMCS_LPMACK | LPMCS_LPMEN;
|
||||
#endif /* LPM_ENABLED */
|
||||
|
||||
/* enable all interrupts mask bits */
|
||||
USBD_CTL |= CTL_STIE | CTL_WKUPIE | CTL_SPSIE | CTL_SOFIE | CTL_ESOFIE | CTL_RSTIE;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief device core register configure when stop device
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_core_stop (void)
|
||||
{
|
||||
/* disable all interrupts and set USB reset */
|
||||
USBD_CTL = CTL_SETRST;
|
||||
|
||||
/* clear all interrupt flags */
|
||||
USBD_INTF = 0U;
|
||||
|
||||
/* close device */
|
||||
USBD_CTL = CTL_SETRST | CTL_CLOSE;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set device address
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_address_set (usb_dev *udev)
|
||||
{
|
||||
USBD_DADDR = DADDR_USBEN | udev->dev_addr;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB reset event
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_ep_reset (usb_dev *udev)
|
||||
{
|
||||
uint8_t i = 0U;
|
||||
|
||||
usb_transc *transc = &udev->transc_in[0];
|
||||
|
||||
btable_ep[0].tx_addr = EP0_TX_ADDR;
|
||||
btable_ep[0].tx_count = 0U;
|
||||
|
||||
transc->max_len = USBD_EP0_MAX_SIZE;
|
||||
|
||||
transc = &udev->transc_out[0];
|
||||
|
||||
btable_ep[0].rx_addr = EP0_RX_ADDR;
|
||||
|
||||
transc->max_len = USBD_EP0_MAX_SIZE;
|
||||
|
||||
if (transc->max_len > 62U) {
|
||||
btable_ep[0].rx_count = ((uint16_t)((uint16_t)transc->max_len << 5) - 1U) | 0x8000U;
|
||||
} else {
|
||||
btable_ep[0].rx_count = ((transc->max_len + 1U) & ~1U) << 9U;
|
||||
}
|
||||
|
||||
/* reset non-control endpoints */
|
||||
for (i = 1U; i < EP_COUNT; i++) {
|
||||
USBD_EPxCS(i) = (USBD_EPxCS(i) & (~EPCS_MASK)) | i;
|
||||
}
|
||||
|
||||
/* clear endpoint 0 register */
|
||||
USBD_EPxCS(0U)= (uint16_t)(USBD_EPxCS(0U));
|
||||
|
||||
USBD_EPxCS(0U) = EP_CONTROL | EPRX_VALID | EPTX_NAK;
|
||||
|
||||
/* set device address as default address 0 */
|
||||
USBD_DADDR = DADDR_USBEN;
|
||||
|
||||
udev->cur_status = (uint8_t)USBD_DEFAULT;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief endpoint initialization
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] buf_kind: endpoint buffer kind
|
||||
\param[in] buf_addr: endpoint buffer address
|
||||
\param[in] ep_desc: pointer to endpoint descriptor
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_ep_setup (usb_dev *udev, uint8_t buf_kind, uint32_t buf_addr, const usb_desc_ep *ep_desc)
|
||||
{
|
||||
uint8_t ep_addr = ep_desc->bEndpointAddress;
|
||||
uint8_t ep_num = EP_ID(ep_addr);
|
||||
uint16_t max_len = ep_desc->wMaxPacketSize;
|
||||
|
||||
usb_transc *transc = NULL;
|
||||
|
||||
/* set the endpoint type */
|
||||
USBD_EPxCS(ep_num) = ep_type[ep_desc->bmAttributes & USB_EPTYPE_MASK] | ep_num;
|
||||
|
||||
if (EP_DIR(ep_addr)) {
|
||||
transc = &udev->transc_in[ep_num];
|
||||
|
||||
transc->max_len = max_len;
|
||||
|
||||
if ((uint8_t)EP_BUF_SNG == buf_kind) {
|
||||
btable_ep[ep_num].tx_addr = buf_addr;
|
||||
|
||||
/* configure the endpoint status as NAK status */
|
||||
USBD_EP_TX_STAT_SET(ep_num, EPTX_NAK);
|
||||
} else if ((uint8_t)EP_BUF_DBL == buf_kind) {
|
||||
USBD_EP_DBL_BUF_SET(ep_num);
|
||||
|
||||
btable_ep[ep_num].tx_addr = buf_addr & 0xFFFFU;
|
||||
btable_ep[ep_num].rx_addr = (buf_addr & 0xFFFF0000U) >> 16U;
|
||||
|
||||
USBD_EP_TX_STAT_SET(ep_num, EPTX_VALID);
|
||||
USBD_EP_RX_STAT_SET(ep_num, EPRX_DISABLED);
|
||||
} else {
|
||||
/* error operation */
|
||||
}
|
||||
} else {
|
||||
transc = &udev->transc_out[ep_num];
|
||||
|
||||
transc->max_len = max_len;
|
||||
|
||||
if ((uint8_t)EP_BUF_SNG == buf_kind) {
|
||||
btable_ep[ep_num].rx_addr = buf_addr;
|
||||
} else if ((uint8_t)EP_BUF_DBL == buf_kind) {
|
||||
USBD_EP_DBL_BUF_SET(ep_num);
|
||||
|
||||
USBD_TX_DTG_TOGGLE(ep_num);
|
||||
|
||||
btable_ep[ep_num].tx_addr = buf_addr & 0xFFFFU;
|
||||
btable_ep[ep_num].rx_addr = (buf_addr & 0xFFFF0000U) >> 16U;
|
||||
|
||||
if (max_len > 62U) {
|
||||
btable_ep[ep_num].tx_count = (((uint32_t)max_len << 5) - 1U) | 0x8000U;
|
||||
} else {
|
||||
btable_ep[ep_num].tx_count = ((max_len + 1U) & ~1U) << 9U;
|
||||
}
|
||||
} else {
|
||||
/* error operation */
|
||||
}
|
||||
|
||||
if (max_len > 62U) {
|
||||
btable_ep[ep_num].rx_count = (((uint32_t)max_len << 5U) - 1U) | 0x8000U;
|
||||
} else {
|
||||
btable_ep[ep_num].rx_count = ((max_len + 1U) & ~1U) << 9U;
|
||||
}
|
||||
|
||||
if ((uint8_t)EP_BUF_SNG == buf_kind) {
|
||||
/* configure the endpoint status as NAK status */
|
||||
USBD_EP_RX_STAT_SET(ep_num, EPRX_NAK);
|
||||
} else if ((uint8_t)EP_BUF_DBL == buf_kind) {
|
||||
USBD_EP_RX_STAT_SET(ep_num, EPRX_DISABLED);
|
||||
USBD_EP_TX_STAT_SET(ep_num, EPTX_NAK);
|
||||
} else {
|
||||
/* error operation */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the endpoint when it is disabled
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
in this parameter:
|
||||
bit0..bit6: endpoint number (0..7)
|
||||
bit7: endpoint direction which can be IN(1) or OUT(0)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_ep_disable (usb_dev *udev, uint8_t ep_addr)
|
||||
{
|
||||
(void)udev;
|
||||
|
||||
uint8_t ep_num = EP_ID(ep_addr);
|
||||
|
||||
if (EP_DIR(ep_addr)) {
|
||||
USBD_TX_DTG_CLEAR(ep_num);
|
||||
|
||||
/* configure the endpoint status as DISABLED */
|
||||
USBD_EP_TX_STAT_SET(ep_num, EPTX_DISABLED);
|
||||
} else {
|
||||
USBD_RX_DTG_CLEAR(ep_num);
|
||||
|
||||
/* configure the endpoint status as DISABLED */
|
||||
USBD_EP_RX_STAT_SET(ep_num, EPRX_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable endpoint to receive
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
in this parameter:
|
||||
bit0..bit6: endpoint number (0..7)
|
||||
bit7: endpoint direction which can be IN(1) or OUT(0)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_ep_rx_enable (usb_dev *udev, uint8_t ep_addr)
|
||||
{
|
||||
(void)udev;
|
||||
|
||||
/* enable endpoint to receive */
|
||||
USBD_EP_RX_STAT_SET(EP_ID(ep_addr), EPRX_VALID);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set an endpoint to STALL status
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
in this parameter:
|
||||
bit0..bit6: endpoint number (0..7)
|
||||
bit7: endpoint direction which can be IN(1) or OUT(0)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_ep_stall_set (usb_dev *udev, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t ep_num = EP_ID(ep_addr);
|
||||
|
||||
if (0U == ep_num) {
|
||||
USBD_EP_TX_STAT_SET(0U, EPTX_STALL);
|
||||
USBD_EP_RX_STAT_SET(0U, EPRX_STALL);
|
||||
} else {
|
||||
if (EP_DIR(ep_addr)) {
|
||||
udev->transc_in[ep_num].ep_stall = 1U;
|
||||
|
||||
USBD_EP_TX_STAT_SET(ep_num, EPTX_STALL);
|
||||
} else {
|
||||
udev->transc_out[ep_num].ep_stall = 1U;
|
||||
|
||||
USBD_EP_RX_STAT_SET(ep_num, EPRX_STALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear endpoint stalled status
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
in this parameter:
|
||||
bit0..bit6: endpoint number (0..7)
|
||||
bit7: endpoint direction which can be IN(1) or OUT(0)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_ep_stall_clear (usb_dev *udev, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t ep_num = EP_ID(ep_addr);
|
||||
|
||||
if (EP_DIR(ep_addr)) {
|
||||
/* clear endpoint data toggle bit */
|
||||
USBD_TX_DTG_CLEAR(ep_num);
|
||||
|
||||
udev->transc_in[ep_num].ep_stall = 0U;
|
||||
|
||||
/* clear endpoint stall status */
|
||||
USBD_EP_TX_STAT_SET(ep_num, EPTX_VALID);
|
||||
} else {
|
||||
/* clear endpoint data toggle bit */
|
||||
USBD_RX_DTG_CLEAR(ep_num);
|
||||
|
||||
udev->transc_out[ep_num].ep_stall = 0U;
|
||||
|
||||
/* clear endpoint stall status */
|
||||
USBD_EP_RX_STAT_SET(ep_num, EPRX_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the endpoint status
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
in this parameter:
|
||||
bit0..bit6: endpoint number (0..7)
|
||||
bit7: endpoint direction which can be IN(1) or OUT(0)
|
||||
\param[out] none
|
||||
\retval endpoint status
|
||||
*/
|
||||
static uint8_t usbd_ep_status (usb_dev *udev, uint8_t ep_addr)
|
||||
{
|
||||
(void)udev;
|
||||
|
||||
uint32_t epcs = USBD_EPxCS(EP_ID(ep_addr));
|
||||
|
||||
if (EP_DIR(ep_addr)) {
|
||||
return (uint8_t)(epcs & EPxCS_TX_STA);
|
||||
} else {
|
||||
return (uint8_t)(epcs & EPxCS_RX_STA);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief write data from user FIFO to USB RAM
|
||||
\param[in] user_fifo: pointer to user FIFO
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[in] bytes: the bytes count of the write data
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_ep_data_write (uint8_t *user_fifo, uint8_t ep_num, uint16_t bytes)
|
||||
{
|
||||
if (0U != bytes) {
|
||||
uint32_t n;
|
||||
uint32_t *write_addr = (uint32_t *)(btable_ep[ep_num].tx_addr * 2U + USBD_RAM);
|
||||
|
||||
for (n = 0U; n < (bytes + 1U) / 2U; n++) {
|
||||
*write_addr++ = *((uint16_t*)user_fifo);
|
||||
user_fifo += 2U;
|
||||
}
|
||||
}
|
||||
|
||||
btable_ep[ep_num].tx_count = bytes;
|
||||
|
||||
USBD_EP_TX_STAT_SET(ep_num, EPTX_VALID);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read data from USBRAM to user FIFO
|
||||
\param[in] user_fifo: pointer to user FIFO
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[in] buf_kind: endpoint buffer kind
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static uint16_t usbd_ep_data_read (uint8_t *user_fifo, uint8_t ep_num, uint8_t buf_kind)
|
||||
{
|
||||
uint16_t n = 0U, bytes = 0U;
|
||||
uint32_t *read_addr = NULL;
|
||||
|
||||
if ((uint8_t)EP_BUF_SNG == buf_kind) {
|
||||
bytes = (uint16_t)(btable_ep[ep_num].rx_count & EPRCNT_CNT);
|
||||
|
||||
read_addr = (uint32_t *)(btable_ep[ep_num].rx_addr * 2U + USBD_RAM);
|
||||
} else if ((uint8_t)EP_BUF_DBL == buf_kind) {
|
||||
if (USBD_EPxCS(ep_num) & EPxCS_TX_DTG) {
|
||||
bytes = (uint16_t)(btable_ep[ep_num].tx_count & EPRCNT_CNT);
|
||||
|
||||
read_addr = (uint32_t *)(btable_ep[ep_num].tx_addr * 2U + USBD_RAM);
|
||||
} else {
|
||||
bytes = (uint16_t)(btable_ep[ep_num].rx_count & EPRCNT_CNT);
|
||||
|
||||
read_addr = (uint32_t *)(btable_ep[ep_num].rx_addr * 2U + USBD_RAM);
|
||||
}
|
||||
} else {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
for (n = 0U; n < (bytes + 1U) / 2U; n++) {
|
||||
*((uint16_t*)user_fifo) = (uint16_t)*read_addr++;
|
||||
user_fifo += 2U;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
#ifdef USBD_LOWPWR_MODE_ENABLE
|
||||
|
||||
/*!
|
||||
\brief restore system clocks and power while exiting from suspend mode
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void lowpower_mode_exit (void)
|
||||
{
|
||||
/* restore system clock */
|
||||
|
||||
#ifdef LPM_ENABLED
|
||||
/* enable IRC8M */
|
||||
rcu_osci_on(RCU_IRC8M);
|
||||
|
||||
/* wait till IRC8M is ready */
|
||||
while (RESET == rcu_flag_get(RCU_FLAG_IRC8MSTB)) {
|
||||
}
|
||||
#else
|
||||
/* enable HXTAL */
|
||||
rcu_osci_on(RCU_HXTAL);
|
||||
|
||||
/* wait till HXTAL is ready */
|
||||
while(RESET == rcu_flag_get(RCU_FLAG_HXTALSTB)) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* enable PLL */
|
||||
rcu_osci_on(RCU_PLL_CK);
|
||||
|
||||
/* wait till PLL is ready */
|
||||
while(RESET == rcu_flag_get(RCU_FLAG_PLLSTB)) {
|
||||
}
|
||||
|
||||
/* select PLL as system clock source */
|
||||
rcu_system_clock_source_config(RCU_CKSYSSRC_PLL);
|
||||
|
||||
/* wait till PLL is used as system clock source */
|
||||
while(0x08U != rcu_system_clock_source_get()) {
|
||||
}
|
||||
|
||||
/* low power sleep on exit disabled */
|
||||
system_lowpower_reset(SCB_LPM_DEEPSLEEP);
|
||||
}
|
||||
|
||||
#endif /* USBD_LOWPWR_MODE_ENABLE */
|
||||
|
||||
/*!
|
||||
\brief resume the USB device
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_resume (usb_dev *udev)
|
||||
{
|
||||
#ifdef LPM_ENABLED
|
||||
if(1 == udev->lpm.L1_remote_wakeup){
|
||||
USBD_CTL |= CTL_L1RSREQ;
|
||||
}
|
||||
#endif /* LPM_ENABLED */
|
||||
|
||||
if(1U == usbd_core.dev->pm.remote_wakeup){
|
||||
/* make USB resume */
|
||||
USBD_CTL |= CTL_RSREQ;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set USB device to leave mode
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_leave_suspend (void)
|
||||
{
|
||||
/* clear low_power mode bit in USBD_CTL */
|
||||
USBD_CTL &= ~CTL_LOWM;
|
||||
|
||||
#ifdef USBD_LOWPWR_MODE_ENABLE
|
||||
|
||||
/* restore normal operations */
|
||||
lowpower_mode_exit();
|
||||
|
||||
#endif /* USBD_LOWPWR_MODE_ENABLE */
|
||||
|
||||
/* clear SETSPS bit */
|
||||
USBD_CTL &= ~CTL_SETSPS;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set USB device to enter suspend mode
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_suspend (void)
|
||||
{
|
||||
/* set USB module to suspend and low-power mode */
|
||||
USBD_CTL |= CTL_SETSPS | CTL_LOWM;
|
||||
|
||||
#ifdef USBD_LOWPWR_MODE_ENABLE
|
||||
|
||||
/* check wakeup flag is set */
|
||||
if (0U == (USBD_INTF & INTF_WKUPIF)) {
|
||||
/* enter DEEP_SLEEP mode with LDO in low power mode */
|
||||
pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, WFI_CMD);
|
||||
} else {
|
||||
/* clear wakeup interrupt flag */
|
||||
CLR(WKUPIF);
|
||||
|
||||
/* clear set_suspend flag */
|
||||
USBD_CTL &= ~CTL_SETSPS;
|
||||
}
|
||||
|
||||
#endif /* USBD_LOWPWR_MODE_ENABLE */
|
||||
}
|
||||
+276
@@ -0,0 +1,276 @@
|
||||
/*!
|
||||
\file usbd_lld_int.c
|
||||
\brief USB device low level interrupt routines
|
||||
|
||||
\version 2020-07-17, V3.0.0, firmware for GD32F10x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2020, 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_lld_int.h"
|
||||
#include "usbd_lld_core.h"
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static void usbd_int_suspend (usb_dev *udev);
|
||||
|
||||
/*!
|
||||
\brief handle USB high priority successful transfer event
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usbd_int_hpst (usb_dev *udev)
|
||||
{
|
||||
__IO uint16_t int_status = 0U;
|
||||
|
||||
/* wait till interrupts are not pending */
|
||||
while ((int_status = (uint16_t)USBD_INTF) & (uint16_t)INTF_STIF) {
|
||||
/* get endpoint number */
|
||||
uint8_t ep_num = (uint8_t)(int_status & INTF_EPNUM);
|
||||
|
||||
uint8_t transc_num = (uint8_t)TRANSC_UNKNOWN;
|
||||
|
||||
if (int_status & INTF_DIR) {
|
||||
if (USBD_EPxCS(ep_num) & EPxCS_RX_ST) {
|
||||
uint16_t count = 0U;
|
||||
|
||||
usb_transc *transc = &udev->transc_out[ep_num];
|
||||
|
||||
/* clear successful receive interrupt flag */
|
||||
USBD_EP_RX_ST_CLEAR(ep_num);
|
||||
|
||||
count = udev->drv_handler->ep_read (transc->xfer_buf, ep_num, (uint8_t)EP_BUF_DBL);
|
||||
|
||||
user_buffer_free(ep_num, (uint8_t)DBUF_EP_OUT);
|
||||
|
||||
transc->xfer_buf += count;
|
||||
transc->xfer_count += count;
|
||||
transc->xfer_len -= count;
|
||||
|
||||
if ((0U == transc->xfer_len) || (count < transc->max_len)) {
|
||||
USBD_EP_RX_STAT_SET(ep_num, EPRX_NAK);
|
||||
|
||||
transc_num = (uint8_t)TRANSC_OUT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* handle the in direction transaction */
|
||||
if (USBD_EPxCS(ep_num) & EPxCS_TX_ST) {
|
||||
/* clear successful transmit interrupt flag */
|
||||
USBD_EP_TX_ST_CLEAR(ep_num);
|
||||
|
||||
transc_num = (uint8_t)TRANSC_IN;
|
||||
}
|
||||
}
|
||||
|
||||
if ((uint8_t)TRANSC_UNKNOWN != transc_num) {
|
||||
udev->ep_transc[ep_num][transc_num](udev, ep_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB interrupt events service routine
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usbd_isr (void)
|
||||
{
|
||||
__IO uint16_t int_status = (uint16_t)USBD_INTF;
|
||||
__IO uint16_t int_flag = (uint16_t)(USBD_INTF & (USBD_CTL & USBD_INTEN));
|
||||
|
||||
usb_dev *udev = usbd_core.dev;
|
||||
|
||||
if (INTF_STIF & int_flag) {
|
||||
/* wait till interrupts are not pending */
|
||||
while ((int_status = (uint16_t)USBD_INTF) & (uint16_t)INTF_STIF) {
|
||||
/* get endpoint number */
|
||||
uint8_t ep_num = (uint8_t)(int_status & INTF_EPNUM);
|
||||
|
||||
if (int_status & INTF_DIR) {
|
||||
/* handle the USB OUT direction transaction */
|
||||
if (USBD_EPxCS(ep_num) & EPxCS_RX_ST) {
|
||||
/* clear successful receive interrupt flag */
|
||||
USBD_EP_RX_ST_CLEAR(ep_num);
|
||||
|
||||
if (USBD_EPxCS(ep_num) & EPxCS_SETUP) {
|
||||
|
||||
if (ep_num == 0U) {
|
||||
udev->ep_transc[ep_num][TRANSC_SETUP](udev, ep_num);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
usb_transc *transc = &udev->transc_out[ep_num];
|
||||
|
||||
uint16_t count = udev->drv_handler->ep_read (transc->xfer_buf, ep_num, (uint8_t)EP_BUF_SNG);
|
||||
|
||||
transc->xfer_buf += count;
|
||||
transc->xfer_count += count;
|
||||
|
||||
if ((transc->xfer_count >= transc->xfer_len) || (count < transc->max_len)) {
|
||||
if (udev->ep_transc[ep_num][TRANSC_OUT]) {
|
||||
udev->ep_transc[ep_num][TRANSC_OUT](udev, ep_num);
|
||||
}
|
||||
} else {
|
||||
udev->drv_handler->ep_rx_enable(udev, ep_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* handle the USB IN direction transaction */
|
||||
if (USBD_EPxCS(ep_num) & EPxCS_TX_ST) {
|
||||
/* clear successful transmit interrupt flag */
|
||||
USBD_EP_TX_ST_CLEAR(ep_num);
|
||||
|
||||
usb_transc *transc = &udev->transc_in[ep_num];
|
||||
|
||||
if (transc->xfer_len == 0U) {
|
||||
if (udev->ep_transc[ep_num][TRANSC_IN]) {
|
||||
udev->ep_transc[ep_num][TRANSC_IN](udev, ep_num);
|
||||
}
|
||||
} else {
|
||||
usbd_ep_send(udev, ep_num, transc->xfer_buf, transc->xfer_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (INTF_WKUPIF & int_flag) {
|
||||
/* clear wakeup interrupt flag in INTF */
|
||||
CLR(WKUPIF);
|
||||
|
||||
/* restore the old cur_status */
|
||||
udev->cur_status = udev->backup_status;
|
||||
|
||||
#ifdef LPM_ENABLED
|
||||
if ((0U == udev->pm.remote_wakeup_on) && (0U == udev->lpm.L1_resume)) {
|
||||
resume_mcu(udev);
|
||||
} else if (1U == udev->pm.remote_wakeup_on) {
|
||||
/* no operation */
|
||||
} else {
|
||||
udev->lpm.L1_resume = 0U;
|
||||
}
|
||||
|
||||
/* clear L1 remote wakeup flag */
|
||||
udev->lpm.L1_remote_wakeup = 0U;
|
||||
#else
|
||||
if (0U == udev->pm.remote_wakeup_on) {
|
||||
resume_mcu(udev);
|
||||
}
|
||||
#endif /* LPM_ENABLED */
|
||||
}
|
||||
|
||||
if (INTF_SPSIF & int_flag) {
|
||||
if(!(USBD_CTL & CTL_RSREQ)) {
|
||||
usbd_int_suspend (udev);
|
||||
|
||||
/* clear of suspend interrupt flag bit must be done after setting of CTLR_SETSPS */
|
||||
CLR(SPSIF);
|
||||
}
|
||||
}
|
||||
|
||||
if (INTF_SOFIF & int_flag) {
|
||||
/* clear SOF interrupt flag in INTF */
|
||||
CLR(SOFIF);
|
||||
|
||||
/* if necessary, user can add code here */
|
||||
if (NULL != usbd_int_fops) {
|
||||
(void)usbd_int_fops->SOF(udev);
|
||||
}
|
||||
}
|
||||
|
||||
if (INTF_ESOFIF & int_flag) {
|
||||
/* clear ESOF interrupt flag in INTF */
|
||||
CLR(ESOFIF);
|
||||
|
||||
/* control resume time by ESOFs */
|
||||
if (udev->pm.esof_count > 0U) {
|
||||
if (0U == --udev->pm.esof_count) {
|
||||
if (udev->pm.remote_wakeup_on) {
|
||||
USBD_CTL &= ~CTL_RSREQ;
|
||||
|
||||
udev->pm.remote_wakeup_on = 0U;
|
||||
} else {
|
||||
USBD_CTL |= CTL_RSREQ;
|
||||
|
||||
udev->pm.esof_count = 3U;
|
||||
udev->pm.remote_wakeup_on = 1U;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (INTF_RSTIF & int_flag) {
|
||||
/* clear reset interrupt flag in INTF */
|
||||
CLR(RSTIF);
|
||||
|
||||
udev->drv_handler->ep_reset(udev);
|
||||
}
|
||||
|
||||
#ifdef LPM_ENABLED
|
||||
if (INTF_L1REQ & int_flag) {
|
||||
/* clear L1 ST bit in LPM INTF */
|
||||
USBD_INTF = CLR(L1REQ);
|
||||
|
||||
/* read BESL field from subendpoint0 register which corresponds to HIRD parameter in LPM spec */
|
||||
udev->lpm.besl = (USBD_LPMCS & LPMCS_BLSTAT) >> 4;
|
||||
|
||||
/* read BREMOTEWAKE bit from subendpoint0 register which corresponding to bRemoteWake bit in LPM request */
|
||||
udev->lpm.L1_remote_wakeup = (USBD_LPMCS & LPMCS_REMWK) >> 3;
|
||||
|
||||
/* process USB device core layer suspend routine */
|
||||
usbd_int_suspend(udev);
|
||||
}
|
||||
#endif /* LPM_ENABLED */
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB suspend event
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usbd_int_suspend (usb_dev *udev)
|
||||
{
|
||||
/* store the device current status */
|
||||
udev->backup_status = udev->cur_status;
|
||||
|
||||
/* set device in suspended state */
|
||||
udev->cur_status = (uint8_t)USBD_SUSPENDED;
|
||||
|
||||
/* usb enter in suspend mode and mcu system in low power mode */
|
||||
if (udev->pm.suspend_enabled) {
|
||||
usbd_to_suspend(udev);
|
||||
} else {
|
||||
/* if not possible then resume after xx ms */
|
||||
udev->pm.esof_count = 3U;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user