commit
f5874d6073
@ -1,113 +0,0 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : CH58x_usbdev.c
|
||||
* Author : WCH
|
||||
* Version : V1.2
|
||||
* Date : 2021/11/17
|
||||
* Description
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "CH58x_common.h"
|
||||
|
||||
uint8_t *pEP0_RAM_Addr;
|
||||
uint8_t *pEP1_RAM_Addr;
|
||||
uint8_t *pEP2_RAM_Addr;
|
||||
uint8_t *pEP3_RAM_Addr;
|
||||
|
||||
/*********************************************************************
|
||||
* @fn USB_DeviceInit
|
||||
*
|
||||
* @brief USB设备功能初始化,4个端点,8个通道。
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void USB_DeviceInit(void)
|
||||
{
|
||||
R8_USB_CTRL = 0x00; // 先设定模式,取消 RB_UC_CLR_ALL
|
||||
|
||||
R8_UEP4_1_MOD = RB_UEP4_RX_EN | RB_UEP4_TX_EN | RB_UEP1_RX_EN | RB_UEP1_TX_EN; // 端点4 OUT+IN,端点1 OUT+IN
|
||||
R8_UEP2_3_MOD = RB_UEP2_RX_EN | RB_UEP2_TX_EN | RB_UEP3_RX_EN | RB_UEP3_TX_EN; // 端点2 OUT+IN,端点3 OUT+IN
|
||||
|
||||
R16_UEP0_DMA = (uint16_t)(uint32_t)pEP0_RAM_Addr;
|
||||
R16_UEP1_DMA = (uint16_t)(uint32_t)pEP1_RAM_Addr;
|
||||
R16_UEP2_DMA = (uint16_t)(uint32_t)pEP2_RAM_Addr;
|
||||
R16_UEP3_DMA = (uint16_t)(uint32_t)pEP3_RAM_Addr;
|
||||
|
||||
R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
||||
R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
|
||||
R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
|
||||
R8_UEP3_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
|
||||
R8_UEP4_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
||||
|
||||
R8_USB_DEV_AD = 0x00;
|
||||
R8_USB_CTRL = RB_UC_DEV_PU_EN | RB_UC_INT_BUSY | RB_UC_DMA_EN; // 启动USB设备及DMA,在中断期间中断标志未清除前自动返回NAK
|
||||
R16_PIN_ANALOG_IE |= RB_PIN_USB_IE | RB_PIN_USB_DP_PU; // 防止USB端口浮空及上拉电阻
|
||||
R8_USB_INT_FG = 0xFF; // 清中断标志
|
||||
R8_UDEV_CTRL = RB_UD_PD_DIS | RB_UD_PORT_EN; // 允许USB端口
|
||||
R8_USB_INT_EN = RB_UIE_SUSPEND | RB_UIE_BUS_RST | RB_UIE_TRANSFER;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn DevEP1_IN_Deal
|
||||
*
|
||||
* @brief 端点1数据上传
|
||||
*
|
||||
* @param l - 上传数据长度(<64B)
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void DevEP1_IN_Deal(uint8_t l)
|
||||
{
|
||||
R8_UEP1_T_LEN = l;
|
||||
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn DevEP2_IN_Deal
|
||||
*
|
||||
* @brief 端点2数据上传
|
||||
*
|
||||
* @param l - 上传数据长度(<64B)
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void DevEP2_IN_Deal(uint8_t l)
|
||||
{
|
||||
R8_UEP2_T_LEN = l;
|
||||
R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn DevEP3_IN_Deal
|
||||
*
|
||||
* @brief 端点3数据上传
|
||||
*
|
||||
* @param l - 上传数据长度(<64B)
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void DevEP3_IN_Deal(uint8_t l)
|
||||
{
|
||||
R8_UEP3_T_LEN = l;
|
||||
R8_UEP3_CTRL = (R8_UEP3_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn DevEP4_IN_Deal
|
||||
*
|
||||
* @brief 端点4数据上传
|
||||
*
|
||||
* @param l - 上传数据长度(<64B)
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void DevEP4_IN_Deal(uint8_t l)
|
||||
{
|
||||
R8_UEP4_T_LEN = l;
|
||||
R8_UEP4_CTRL = (R8_UEP4_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
|
||||
}
|
||||
@ -84,7 +84,6 @@
|
||||
#include "CH58x_sys.h"
|
||||
#include "CH58x_timer.h"
|
||||
#include "CH58x_spi.h"
|
||||
#include "CH58x_usbdev.h"
|
||||
#include "CH58x_usbhost.h"
|
||||
#include "ISP583.h"
|
||||
|
||||
|
||||
@ -1,177 +0,0 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : CH57x_usbdev.h
|
||||
* Author : WCH
|
||||
* Version : V1.2
|
||||
* Date : 2021/11/17
|
||||
* Description
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __CH58x_USBDEV_H__
|
||||
#define __CH58x_USBDEV_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* HID类请求 */
|
||||
#define DEF_USB_GET_IDLE 0x02 /* get idle for key or mouse */
|
||||
#define DEF_USB_GET_PROTOCOL 0x03 /* get protocol for bios type */
|
||||
#define DEF_USB_SET_REPORT 0x09 /* set report for key */
|
||||
#define DEF_USB_SET_IDLE 0x0A /* set idle for key or mouse */
|
||||
#define DEF_USB_SET_PROTOCOL 0x0B /* set protocol for bios type */
|
||||
|
||||
/* 以下缓存区是USB模块收发使用的数据缓冲区,总共9个通道(9块缓存),用户可根据实际使用的通道数定义相应缓存区 */
|
||||
extern uint8_t *pEP0_RAM_Addr; //ep0(64)+ep4_out(64)+ep4_in(64)
|
||||
extern uint8_t *pEP1_RAM_Addr; //ep1_out(64)+ep1_in(64)
|
||||
extern uint8_t *pEP2_RAM_Addr; //ep2_out(64)+ep2_in(64)
|
||||
extern uint8_t *pEP3_RAM_Addr; //ep3_out(64)+ep3_in(64)
|
||||
|
||||
extern uint8_t *pU2EP0_RAM_Addr; //ep0(64)+ep4_out(64)+ep4_in(64)
|
||||
extern uint8_t *pU2EP1_RAM_Addr; //ep1_out(64)+ep1_in(64)
|
||||
extern uint8_t *pU2EP2_RAM_Addr; //ep2_out(64)+ep2_in(64)
|
||||
extern uint8_t *pU2EP3_RAM_Addr; //ep3_out(64)+ep3_in(64)
|
||||
|
||||
#define pSetupReqPak ((PUSB_SETUP_REQ)pEP0_RAM_Addr)
|
||||
#define pEP0_DataBuf (pEP0_RAM_Addr)
|
||||
#define pEP1_OUT_DataBuf (pEP1_RAM_Addr)
|
||||
#define pEP1_IN_DataBuf (pEP1_RAM_Addr + 64)
|
||||
#define pEP2_OUT_DataBuf (pEP2_RAM_Addr)
|
||||
#define pEP2_IN_DataBuf (pEP2_RAM_Addr + 64)
|
||||
#define pEP3_OUT_DataBuf (pEP3_RAM_Addr)
|
||||
#define pEP3_IN_DataBuf (pEP3_RAM_Addr + 64)
|
||||
#define pEP4_OUT_DataBuf (pEP0_RAM_Addr + 64)
|
||||
#define pEP4_IN_DataBuf (pEP0_RAM_Addr + 128)
|
||||
|
||||
#define pU2SetupReqPak ((PUSB_SETUP_REQ)pU2EP0_RAM_Addr)
|
||||
#define pU2EP0_DataBuf (pU2EP0_RAM_Addr)
|
||||
#define pU2EP1_OUT_DataBuf (pU2EP1_RAM_Addr)
|
||||
#define pU2EP1_IN_DataBuf (pU2EP1_RAM_Addr + 64)
|
||||
#define pU2EP2_OUT_DataBuf (pU2EP2_RAM_Addr)
|
||||
#define pU2EP2_IN_DataBuf (pU2EP2_RAM_Addr + 64)
|
||||
#define pU2EP3_OUT_DataBuf (pU2EP3_RAM_Addr)
|
||||
#define pU2EP3_IN_DataBuf (pU2EP3_RAM_Addr + 64)
|
||||
#define pU2EP4_OUT_DataBuf (pU2EP0_RAM_Addr + 64)
|
||||
#define pU2EP4_IN_DataBuf (pU2EP0_RAM_Addr + 128)
|
||||
|
||||
/**
|
||||
* @brief USB设备功能初始化,4个端点,8个通道。
|
||||
*/
|
||||
void USB_DeviceInit(void);
|
||||
|
||||
/**
|
||||
* @brief USB设备应答传输处理
|
||||
*/
|
||||
void USB_DevTransProcess(void);
|
||||
|
||||
/**
|
||||
* @brief 端点1下传数据处理
|
||||
*
|
||||
* @param l - 待处理数据长度(<64B)
|
||||
*/
|
||||
void DevEP1_OUT_Deal(uint8_t l);
|
||||
|
||||
/**
|
||||
* @brief 端点2下传数据处理
|
||||
*
|
||||
* @param l - 待处理数据长度(<64B)
|
||||
*/
|
||||
void DevEP2_OUT_Deal(uint8_t l);
|
||||
|
||||
/**
|
||||
* @brief 端点3下传数据处理
|
||||
*
|
||||
* @param l - 待处理数据长度(<64B)
|
||||
*/
|
||||
void DevEP3_OUT_Deal(uint8_t l);
|
||||
|
||||
/**
|
||||
* @brief 端点4下传数据处理
|
||||
*
|
||||
* @param l - 待处理数据长度(<64B)
|
||||
*/
|
||||
void DevEP4_OUT_Deal(uint8_t l);
|
||||
|
||||
/**
|
||||
* @brief 端点1数据上传
|
||||
*
|
||||
* @param l - 上传数据长度(<64B)
|
||||
*/
|
||||
void DevEP1_IN_Deal(uint8_t l);
|
||||
|
||||
/**
|
||||
* @brief 端点2数据上传
|
||||
*
|
||||
* @param l - 上传数据长度(<64B)
|
||||
*/
|
||||
void DevEP2_IN_Deal(uint8_t l);
|
||||
|
||||
/**
|
||||
* @brief 端点3数据上传
|
||||
*
|
||||
* @param l - 上传数据长度(<64B)
|
||||
*/
|
||||
void DevEP3_IN_Deal(uint8_t l);
|
||||
|
||||
/**
|
||||
* @brief 端点4数据上传
|
||||
*
|
||||
* @param l - 上传数据长度(<64B)
|
||||
*/
|
||||
void DevEP4_IN_Deal(uint8_t l);
|
||||
|
||||
/**
|
||||
* @brief 查询端点1是否上传完成
|
||||
*
|
||||
* @return 0-未完成 (!0)-已完成
|
||||
*/
|
||||
#define EP1_GetINSta() (R8_UEP1_CTRL & UEP_T_RES_NAK)
|
||||
|
||||
/**
|
||||
* @brief 查询端点2是否上传完成
|
||||
*
|
||||
* @return 0-未完成 (!0)-已完成
|
||||
*/
|
||||
#define EP2_GetINSta() (R8_UEP2_CTRL & UEP_T_RES_NAK)
|
||||
|
||||
/**
|
||||
* @brief 查询端点3是否上传完成
|
||||
*
|
||||
* @return 0-未完成 (!0)-已完成
|
||||
*/
|
||||
#define EP3_GetINSta() (R8_UEP3_CTRL & UEP_T_RES_NAK)
|
||||
|
||||
/**
|
||||
* @brief 查询端点4是否上传完成
|
||||
*
|
||||
* @return 0-未完成 (!0)-已完成
|
||||
*/
|
||||
#define EP4_GetINSta() (R8_UEP4_CTRL & UEP_T_RES_NAK)
|
||||
|
||||
void USB2_DeviceInit(void); /* USB2设备功能初始化,4个端点,8个通道 */
|
||||
void USB2_DevTransProcess(void); /* USB2设备应答传输处理 */
|
||||
|
||||
void U2DevEP1_OUT_Deal(uint8_t l); /* 设备端点1下传通道处理 */
|
||||
void U2DevEP2_OUT_Deal(uint8_t l); /* 设备端点2下传通道处理 */
|
||||
void U2DevEP3_OUT_Deal(uint8_t l); /* 设备端点3下传通道处理 */
|
||||
void U2DevEP4_OUT_Deal(uint8_t l); /* 设备端点4下传通道处理 */
|
||||
|
||||
void U2DevEP1_IN_Deal(uint8_t l); /* 设备端点1上传通道处理 */
|
||||
void U2DevEP2_IN_Deal(uint8_t l); /* 设备端点2上传通道处理 */
|
||||
void U2DevEP3_IN_Deal(uint8_t l); /* 设备端点3上传通道处理 */
|
||||
void U2DevEP4_IN_Deal(uint8_t l); /* 设备端点4上传通道处理 */
|
||||
|
||||
// 0-未完成 (!0)-已完成
|
||||
#define U2EP1_GetINSta() (R8_U2EP1_CTRL & UEP_T_RES_NAK) /* 查询端点1是否上传完成 */
|
||||
#define U2EP2_GetINSta() (R8_U2EP2_CTRL & UEP_T_RES_NAK) /* 查询端点2是否上传完成 */
|
||||
#define U2EP3_GetINSta() (R8_U2EP3_CTRL & UEP_T_RES_NAK) /* 查询端点3是否上传完成 */
|
||||
#define U2EP4_GetINSta() (R8_U2EP4_CTRL & UEP_T_RES_NAK) /* 查询端点4是否上传完成 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __CH58x_USBDEV_H__
|
||||
15
Makefile
15
Makefile
@ -7,8 +7,8 @@ TARGET = badgemagic-ch582
|
||||
######################################
|
||||
# building variables
|
||||
######################################
|
||||
# debug build?
|
||||
DEBUG = 1
|
||||
# Uncomment below line to enable debugging
|
||||
# DEBUG = 1
|
||||
# optimization for size
|
||||
OPT = -Os
|
||||
|
||||
@ -37,7 +37,6 @@ CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_uart0.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer1.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_pwm.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usbhostClass.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usbdev.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_adc.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usbhostBase.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer3.c \
|
||||
@ -58,7 +57,13 @@ src/ble/profile/devinfo.c \
|
||||
src/ble/setup.c \
|
||||
src/ble/peripheral.c \
|
||||
src/data.c \
|
||||
|
||||
src/usb/utils.c \
|
||||
src/usb/setup.c \
|
||||
src/usb/ctrl.c \
|
||||
src/usb/debug.c \
|
||||
src/usb/dev.c \
|
||||
src/usb/composite/hiddev.c \
|
||||
src/usb/composite/cdc-serial.c \
|
||||
|
||||
# ASM sources
|
||||
ASM_SOURCES = \
|
||||
@ -108,7 +113,7 @@ ASFLAGS = $(MCU) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
|
||||
CFLAGS = $(MCU) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -g -gdwarf-2
|
||||
CFLAGS += -g -gdwarf-2 -DDEBUG=$(DEBUG)
|
||||
endif
|
||||
|
||||
|
||||
|
||||
52
src/main.c
52
src/main.c
@ -10,6 +10,8 @@
|
||||
#include "ble/setup.h"
|
||||
#include "ble/profile.h"
|
||||
|
||||
#include "usb/usb.h"
|
||||
|
||||
#define FB_WIDTH (LED_COLS * 4)
|
||||
#define SCROLL_IRATIO (16)
|
||||
#define SCAN_F (2000)
|
||||
@ -92,6 +94,40 @@ void ble_start()
|
||||
legacy_registerService();
|
||||
}
|
||||
|
||||
static void usb_receive(uint8_t *buf, uint16_t len)
|
||||
{
|
||||
static uint16_t rx_len, data_len;
|
||||
static uint8_t *data;
|
||||
|
||||
PRINT("dump first 8 bytes: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
buf[0], buf[1], buf[2], buf[3],
|
||||
buf[4], buf[5], buf[6], buf[7]);
|
||||
|
||||
if (rx_len == 0) {
|
||||
if (memcmp(buf, "wang", 5))
|
||||
return;
|
||||
|
||||
int init_len = len > LEGACY_HEADER_SIZE ? len : sizeof(data_legacy_t);
|
||||
init_len += MAX_PACKET_SIZE;
|
||||
data = malloc(init_len);
|
||||
}
|
||||
|
||||
memcpy(data + rx_len, buf, len);
|
||||
rx_len += len;
|
||||
|
||||
if (!data_len) {
|
||||
data_legacy_t *d = (data_legacy_t *)data;
|
||||
uint16_t n = bigendian16_sum(d->sizes, 8);
|
||||
data_len = LEGACY_HEADER_SIZE + LED_ROWS * n;
|
||||
data = realloc(data, data_len);
|
||||
}
|
||||
|
||||
if ((rx_len > LEGACY_HEADER_SIZE) && rx_len >= data_len) {
|
||||
data_flatSave(data, data_len);
|
||||
SYS_ResetExecute();
|
||||
}
|
||||
}
|
||||
|
||||
void handle_mode_transition()
|
||||
{
|
||||
static int prev_mode;
|
||||
@ -123,10 +159,26 @@ void handle_mode_transition()
|
||||
prev_mode = mode;
|
||||
}
|
||||
|
||||
static void debug_init()
|
||||
{
|
||||
GPIOA_SetBits(GPIO_Pin_9);
|
||||
GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
|
||||
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
|
||||
UART1_DefInit();
|
||||
UART1_BaudRateCfg(921600);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
SetSysClock(CLK_SOURCE_PLL_60MHz);
|
||||
|
||||
debug_init();
|
||||
PRINT("\nDebug console is on UART%d\n", DEBUG);
|
||||
|
||||
cdc_onWrite(usb_receive);
|
||||
hiddev_onWrite(usb_receive);
|
||||
usb_start();
|
||||
|
||||
led_init();
|
||||
TMR0_TimerInit(SCAN_T / 2);
|
||||
TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END);
|
||||
|
||||
202
src/usb/composite/cdc-serial.c
Normal file
202
src/usb/composite/cdc-serial.c
Normal file
@ -0,0 +1,202 @@
|
||||
#include <stdint.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "CH58x_common.h"
|
||||
|
||||
#include "../utils.h"
|
||||
#include "../debug.h"
|
||||
|
||||
#define NOTI_EP_NUM (2)
|
||||
#define DATA_EP_NUM (3)
|
||||
#define ACM_IF_NUM (1)
|
||||
|
||||
#define USB_DESCTYPE_CS_INTERFACE 0x24
|
||||
|
||||
static __attribute__((aligned(4))) uint8_t noti_ep_buf[64 + 64];
|
||||
static uint8_t *const noti_ep_out = noti_ep_buf;
|
||||
static uint8_t *const noti_ep_in = noti_ep_buf + 64;
|
||||
|
||||
static __attribute__((aligned(4))) uint8_t data_ep_buf[64 + 64];
|
||||
static uint8_t *const data_ep_out = data_ep_buf;
|
||||
static uint8_t *const data_ep_in = data_ep_buf + 64;
|
||||
|
||||
static void (*on_write)(uint8_t *buf, uint16_t len);
|
||||
|
||||
/* CDC Communication interface */
|
||||
static USB_ITF_DESCR acm_if_desc = {
|
||||
.bLength = sizeof(USB_ITF_DESCR),
|
||||
.bDescriptorType = USB_DESCR_TYP_INTERF,
|
||||
.bInterfaceNumber = ACM_IF_NUM,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 3, // A Notification and RX/TX Endpoint
|
||||
|
||||
.bInterfaceClass = 0x02, /* Communications and CDC Control */
|
||||
.bInterfaceSubClass = 2, /* ACM subclass */
|
||||
.bInterfaceProtocol = 1, /* AT Command V.250 protocol */
|
||||
|
||||
.iInterface = 0 /* No string descriptor */
|
||||
};
|
||||
|
||||
/* Header Functional descriptor */
|
||||
static uint8_t header_func_desc[] = {
|
||||
5, /* bLength */
|
||||
USB_DESCTYPE_CS_INTERFACE, /* bDescriptortype */
|
||||
0x00, /* bDescriptorsubtype, HEADER */
|
||||
0x10, 0x01, /* bcdCDC */
|
||||
};
|
||||
|
||||
/* ACM Functional descriptor */
|
||||
static uint8_t acm_func_desc[] = {
|
||||
4, /* bLength */
|
||||
USB_DESCTYPE_CS_INTERFACE, /* bDescriptortype */
|
||||
0x02, /* bDescriptorsubtype, ABSTRACT CONTROL MANAGEMENT */
|
||||
0x02, /* bmCapabilities: Supports subset of ACM commands */
|
||||
};
|
||||
|
||||
/* Call Management Functional descriptor */
|
||||
static uint8_t callmgr_func_desc[] = {
|
||||
4, /* bLength */
|
||||
USB_DESCTYPE_CS_INTERFACE, /* bDescriptortype */
|
||||
0x01, /* bDescriptorsubtype, CALL MANAGEMENT */
|
||||
0x03, /* bmCapabilities, DIY */
|
||||
};
|
||||
|
||||
/* Notification Endpoint descriptor */
|
||||
static USB_ENDP_DESCR noti_ep_desc = {
|
||||
.bLength = sizeof(USB_ENDP_DESCR),
|
||||
.bDescriptorType = USB_DESCR_TYP_ENDP,
|
||||
.bEndpointAddress = 0x80 | NOTI_EP_NUM, /* IN endpoint */
|
||||
.bmAttributes = 0x03, /* Interrupt transfer */
|
||||
.wMaxPacketSize = 64, /* bytes */
|
||||
.bInterval = 0xff
|
||||
};
|
||||
|
||||
/* Data TX Endpoint descriptor */
|
||||
static USB_ENDP_DESCR tx_ep_desc = {
|
||||
.bLength = sizeof(USB_ENDP_DESCR),
|
||||
.bDescriptorType = USB_DESCR_TYP_ENDP,
|
||||
.bEndpointAddress = 0x80 | DATA_EP_NUM, /* IN endpoint */
|
||||
.bmAttributes = 0x02, /* Bulk */
|
||||
.wMaxPacketSize = MAX_PACKET_SIZE, /* bytes */
|
||||
.bInterval = 0xff
|
||||
};
|
||||
|
||||
/* Data RX Endpoint descriptor */
|
||||
static USB_ENDP_DESCR rx_ep_desc = {
|
||||
.bLength = sizeof(USB_ENDP_DESCR),
|
||||
.bDescriptorType = USB_DESCR_TYP_ENDP,
|
||||
.bEndpointAddress = DATA_EP_NUM, /* OUT endpoint */
|
||||
.bmAttributes = 0x02, /* Bulk */
|
||||
.wMaxPacketSize = MAX_PACKET_SIZE, /* bytes */
|
||||
.bInterval = 0xff
|
||||
};
|
||||
|
||||
static void cdc_request_handler(USB_SETUP_REQ * request)
|
||||
{
|
||||
_TRACE();
|
||||
// Handle CDC Class Request here
|
||||
}
|
||||
|
||||
static void noti_ep_handler()
|
||||
{
|
||||
_TRACE();
|
||||
// Handle Subclass Request here
|
||||
}
|
||||
|
||||
static volatile uint16_t transferred;
|
||||
|
||||
static void data_ep_handler()
|
||||
{
|
||||
_TRACE();
|
||||
static int tog;
|
||||
|
||||
uint8_t token = R8_USB_INT_ST & MASK_UIS_TOKEN;
|
||||
switch(token) {
|
||||
case UIS_TOKEN_OUT:
|
||||
if (on_write)
|
||||
on_write(data_ep_out, R8_USB_RX_LEN);
|
||||
tog = !tog;
|
||||
set_handshake(DATA_EP_NUM, USB_ACK, tog, 0);
|
||||
break;
|
||||
|
||||
case UIS_TOKEN_IN:
|
||||
if (transferred == 0) {
|
||||
transferred = 1;
|
||||
} else {
|
||||
set_handshake(DATA_EP_NUM, USB_NAK, 1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// In case we want to send something to the host,
|
||||
// or want to see the log over ttyACMx
|
||||
void cdc_fill_IN(uint8_t *buf, uint8_t len)
|
||||
{
|
||||
if (len > tx_ep_desc.wMaxPacketSize)
|
||||
return;
|
||||
|
||||
static int tog;
|
||||
|
||||
memcpy(data_ep_in, buf, len);
|
||||
set_handshake(DATA_EP_NUM, USB_ACK, tog, len);
|
||||
|
||||
tog = !tog;
|
||||
transferred = 0;
|
||||
}
|
||||
|
||||
static int wait_until_sent(uint16_t timeout_ms)
|
||||
{
|
||||
while(timeout_ms--) {
|
||||
if (transferred) {
|
||||
return 0;
|
||||
}
|
||||
DelayMs(1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cdc_tx_poll(uint8_t *buf, int len, uint16_t timeout_ms)
|
||||
{
|
||||
int i = 0;
|
||||
while (len > tx_ep_desc.wMaxPacketSize) {
|
||||
cdc_fill_IN(buf + i, tx_ep_desc.wMaxPacketSize);
|
||||
if (wait_until_sent(timeout_ms))
|
||||
return -1;
|
||||
|
||||
i += tx_ep_desc.wMaxPacketSize;
|
||||
len -= tx_ep_desc.wMaxPacketSize;
|
||||
}
|
||||
cdc_fill_IN(buf + i, len);
|
||||
if (wait_until_sent(timeout_ms))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cdc_onWrite(void (*cb)(uint8_t *buf, uint16_t len))
|
||||
{
|
||||
on_write = cb;
|
||||
}
|
||||
|
||||
void cdc_acm_init()
|
||||
{
|
||||
cfg_desc_append(&acm_if_desc);
|
||||
cfg_desc_append(header_func_desc);
|
||||
cfg_desc_append(acm_func_desc);
|
||||
cfg_desc_append(callmgr_func_desc);
|
||||
|
||||
cfg_desc_append(¬i_ep_desc);
|
||||
cfg_desc_append(&rx_ep_desc);
|
||||
cfg_desc_append(&tx_ep_desc);
|
||||
|
||||
if_cb_register(ACM_IF_NUM, cdc_request_handler);
|
||||
ep_cb_register(NOTI_EP_NUM, noti_ep_handler);
|
||||
ep_cb_register(DATA_EP_NUM, data_ep_handler);
|
||||
|
||||
dma_register(NOTI_EP_NUM, noti_ep_buf);
|
||||
dma_register(DATA_EP_NUM, data_ep_buf);
|
||||
}
|
||||
230
src/usb/composite/hiddev.c
Normal file
230
src/usb/composite/hiddev.c
Normal file
@ -0,0 +1,230 @@
|
||||
#include <stdint.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "CH58x_common.h"
|
||||
|
||||
#include "../utils.h"
|
||||
#include "../debug.h"
|
||||
|
||||
#define EP_NUM (1)
|
||||
#define IF_NUM (0)
|
||||
|
||||
static __attribute__((aligned(4))) uint8_t ep_buf[64 + 64];
|
||||
static uint8_t *const ep_out = ep_buf;
|
||||
static uint8_t *const ep_in = ep_buf + 64;
|
||||
|
||||
static void (*on_write)(uint8_t *buf, uint16_t len);
|
||||
|
||||
static USB_ITF_DESCR if_desc = {
|
||||
.bLength = sizeof(USB_ITF_DESCR),
|
||||
.bDescriptorType = USB_DESCR_TYP_INTERF,
|
||||
.bInterfaceNumber = IF_NUM,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2, /* One for read, one for write */
|
||||
.bInterfaceClass = 0x03, /* HID class */
|
||||
.bInterfaceSubClass = 0, /* No subclass */
|
||||
.bInterfaceProtocol = 0, /* Not a Mouse nor Keyboard */
|
||||
.iInterface = 0 /* Index of string descriptor */
|
||||
};
|
||||
|
||||
static USB_HID_DESCR hid_desc = {
|
||||
.bLength = sizeof(USB_HID_DESCR),
|
||||
.bDescriptorType = USB_DESCR_TYP_HID,
|
||||
.bcdHID = 0x0100,
|
||||
.bCountryCode = 0x00,
|
||||
.bNumDescriptors = 0x01,
|
||||
.bDescriptorTypeX = 0x22,
|
||||
.wDescriptorLengthL = 0x22,
|
||||
.wDescriptorLengthH = 0x00
|
||||
};
|
||||
|
||||
static USB_ENDP_DESCR read_ep_desc = {
|
||||
.bLength = sizeof(USB_ENDP_DESCR),
|
||||
.bDescriptorType = USB_DESCR_TYP_ENDP,
|
||||
.bEndpointAddress = 0x80 | EP_NUM, /* IN endpoint */
|
||||
.bmAttributes = 0x03, /* exchange data over Interrupt */
|
||||
.wMaxPacketSize = MAX_PACKET_SIZE, /* bytes */
|
||||
.bInterval = 0xff /* polling interval */
|
||||
};
|
||||
|
||||
static USB_ENDP_DESCR write_ep_desc = {
|
||||
.bLength = sizeof(USB_ENDP_DESCR),
|
||||
.bDescriptorType = USB_DESCR_TYP_ENDP,
|
||||
.bEndpointAddress = EP_NUM, /* IN endpoint */
|
||||
.bmAttributes = 0x03, /* exchange data over Interrupt */
|
||||
.wMaxPacketSize = MAX_PACKET_SIZE, /* bytes */
|
||||
.bInterval = 8 /* polling interval */
|
||||
};
|
||||
|
||||
static const uint8_t report_desc[] = {
|
||||
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
|
||||
0x09, 0x01, // Usage (0x01)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
|
||||
/* IN */
|
||||
0x09, 0x02, // Usage (0x02)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0x00, 0xFF, // Logical Maximum (-256)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x40, // Report Count (64)
|
||||
0x81, 0x06, // INPUT
|
||||
|
||||
/* OUT */
|
||||
0x09, 0x02, // Usage (0x02)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0x00, 0xFF, // Logical Maximum (-256)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x40, // Report Count (64)
|
||||
0x91, 0x06, // OUTPUT
|
||||
|
||||
0xC0, // End Collection
|
||||
};
|
||||
|
||||
static void hid_request_handler(USB_SETUP_REQ * request)
|
||||
{
|
||||
_TRACE();
|
||||
static uint8_t report_val, idle_val;
|
||||
uint8_t req = request->bRequest;
|
||||
uint16_t type = request->wValue >> 8;
|
||||
|
||||
switch(req) {
|
||||
case USB_GET_DESCRIPTOR:
|
||||
PRINT("- USB_GET_DESCRIPTOR\n");
|
||||
PRINT("bDescriptorType: 0x%02x\n", type);
|
||||
switch (type)
|
||||
{
|
||||
case USB_DESCR_TYP_REPORT:
|
||||
PRINT("- USB_DESCR_TYP_REPORT\n");
|
||||
ctrl_start_load_block(report_desc, sizeof(report_desc));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_GET_REPORT:
|
||||
PRINT("- HID_GET_REPORT\n");
|
||||
break;
|
||||
|
||||
case HID_GET_IDLE:
|
||||
PRINT("- HID_GET_IDLE\n");
|
||||
ctrl_start_load_block(&idle_val, 1);
|
||||
break;
|
||||
|
||||
case HID_GET_PROTOCOL:
|
||||
PRINT("- HID_GET_PROTOCOL\n");
|
||||
ctrl_start_load_block(&report_val, 1);
|
||||
break;
|
||||
|
||||
case HID_SET_REPORT:
|
||||
PRINT("- HID_SET_REPORT\n");
|
||||
ctrl_ack();
|
||||
break;
|
||||
|
||||
case HID_SET_IDLE:
|
||||
PRINT("- HID_SET_IDLE\n");
|
||||
ctrl_ack();
|
||||
break;
|
||||
|
||||
case HID_SET_PROTOCOL:
|
||||
PRINT("- HID_SET_PROTOCOL\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static volatile uint16_t transferred;
|
||||
|
||||
static void ep_handler()
|
||||
{
|
||||
_TRACE();
|
||||
static int tog;
|
||||
uint8_t token = R8_USB_INT_ST & MASK_UIS_TOKEN;
|
||||
|
||||
switch(token) {
|
||||
case UIS_TOKEN_OUT:
|
||||
if (on_write)
|
||||
on_write(ep_out, R8_USB_RX_LEN);
|
||||
set_handshake(EP_NUM, USB_ACK, tog, 0);
|
||||
tog = !tog;
|
||||
break;
|
||||
|
||||
case UIS_TOKEN_IN:
|
||||
if (transferred == 0) {
|
||||
transferred = 1;
|
||||
} else {
|
||||
set_handshake(EP_NUM, USB_NAK, 1, 0);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// In case we want to send something to the host,
|
||||
// or want to see the log over hidraw by `cat /dev/hidrawX`
|
||||
void hiddev_fill_IN(uint8_t *buf, uint8_t len)
|
||||
{
|
||||
if (len > read_ep_desc.wMaxPacketSize)
|
||||
return;
|
||||
|
||||
static int tog;
|
||||
|
||||
memcpy(ep_in, buf, len);
|
||||
set_handshake(EP_NUM, USB_ACK, tog, len);
|
||||
|
||||
tog = !tog;
|
||||
transferred = 0;
|
||||
}
|
||||
|
||||
static int wait_until_sent(uint16_t timeout_ms)
|
||||
{
|
||||
while(timeout_ms--) {
|
||||
if (transferred) {
|
||||
return 0;
|
||||
}
|
||||
DelayMs(1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hiddev_tx_poll(uint8_t *buf, int len, uint16_t timeout_ms)
|
||||
{
|
||||
int i = 0;
|
||||
while (len > read_ep_desc.wMaxPacketSize) {
|
||||
hiddev_fill_IN(buf + i, read_ep_desc.wMaxPacketSize);
|
||||
if (wait_until_sent(timeout_ms))
|
||||
return -1;
|
||||
|
||||
i += read_ep_desc.wMaxPacketSize;
|
||||
len -= read_ep_desc.wMaxPacketSize;
|
||||
}
|
||||
hiddev_fill_IN(buf + i, len);
|
||||
if (wait_until_sent(timeout_ms))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hiddev_onWrite(void (*cb)(uint8_t *buf, uint16_t len))
|
||||
{
|
||||
on_write = cb;
|
||||
}
|
||||
|
||||
void hiddev_init()
|
||||
{
|
||||
cfg_desc_append(&if_desc);
|
||||
cfg_desc_append(&hid_desc);
|
||||
cfg_desc_append(&read_ep_desc);
|
||||
cfg_desc_append(&write_ep_desc);
|
||||
|
||||
if_cb_register(IF_NUM, hid_request_handler);
|
||||
ep_cb_register(EP_NUM, ep_handler);
|
||||
|
||||
dma_register(EP_NUM, ep_out);
|
||||
}
|
||||
151
src/usb/ctrl.c
Normal file
151
src/usb/ctrl.c
Normal file
@ -0,0 +1,151 @@
|
||||
|
||||
#include "CH58x_common.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "debug.h"
|
||||
|
||||
extern void (*if_handlers[])(USB_SETUP_REQ *request);
|
||||
extern void (*ep_handlers[])();
|
||||
|
||||
void handle_devreq(USB_SETUP_REQ *request);
|
||||
|
||||
static uint8_t address;
|
||||
|
||||
/* EP0 + EP4(IN + OUT) */
|
||||
__attribute__((aligned(4))) uint8_t ep0buf[64 + 64 + 64];
|
||||
|
||||
void usb_set_address(uint8_t ad)
|
||||
{
|
||||
address = ad;
|
||||
}
|
||||
|
||||
void ctrl_start_load_block(void *buf, uint16_t len)
|
||||
{
|
||||
usb_start_load_block(ep0buf, buf, len, 1);
|
||||
}
|
||||
|
||||
static void route_interfaces(USB_SETUP_REQ *request)
|
||||
{
|
||||
_TRACE();
|
||||
|
||||
uint8_t ifn = request->wIndex & 0xff;
|
||||
PRINT("wInterfaceNumber: 0x%02x\n", ifn);
|
||||
|
||||
if (if_handlers[ifn])
|
||||
if_handlers[ifn](request);
|
||||
}
|
||||
|
||||
static void ep_handler()
|
||||
{
|
||||
_TRACE();
|
||||
|
||||
USB_SETUP_REQ *request = (USB_SETUP_REQ *)ep0buf;
|
||||
uint8_t req = request->bRequest;
|
||||
|
||||
/* Each interface will have their own request handler */
|
||||
uint8_t recip = request->bRequestType & USB_REQ_RECIP_MASK;
|
||||
if (recip == USB_REQ_RECIP_INTERF) {
|
||||
route_interfaces(request);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t token = R8_USB_INT_ST & MASK_UIS_TOKEN;
|
||||
switch(token) {
|
||||
|
||||
case UIS_TOKEN_SETUP:
|
||||
print_setuppk(req);
|
||||
|
||||
if (recip == USB_REQ_RECIP_DEVICE) {
|
||||
handle_devreq(request);
|
||||
}
|
||||
break;
|
||||
|
||||
case UIS_TOKEN_OUT:
|
||||
if (req == USB_CLEAR_FEATURE) {
|
||||
ctrl_ack();
|
||||
}
|
||||
|
||||
case UIS_TOKEN_IN:
|
||||
R8_USB_DEV_AD = address;
|
||||
usb_load_next_chunk();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ctrl_init()
|
||||
{
|
||||
ep_cb_register(0, ep_handler);
|
||||
dma_register(0, ep0buf);
|
||||
}
|
||||
|
||||
static void route_enpoints()
|
||||
{
|
||||
_TRACE();
|
||||
|
||||
/* Workaround to solve a setup packet with EP 0x02 for unknown reason.
|
||||
This happens when return from the bootloader or after a sotfware reset. */
|
||||
uint8_t token = R8_USB_INT_ST & MASK_UIS_TOKEN;
|
||||
if (token == UIS_TOKEN_SETUP) {
|
||||
ep_handlers[0]();
|
||||
}
|
||||
|
||||
uint8_t ep_num = R8_USB_INT_ST & MASK_UIS_ENDP;
|
||||
|
||||
if (ep_num < 8 && ep_handlers[ep_num])
|
||||
ep_handlers[ep_num]();
|
||||
}
|
||||
|
||||
static void handle_busReset()
|
||||
{
|
||||
_TRACE();
|
||||
R8_USB_DEV_AD = 0;
|
||||
R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
||||
R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
||||
R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
||||
R8_UEP3_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
||||
R8_UEP4_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
||||
R8_UEP5_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
||||
R8_UEP6_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
||||
R8_UEP7_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
||||
}
|
||||
|
||||
static void handle_powerChange()
|
||||
{
|
||||
_TRACE();
|
||||
if (R8_USB_MIS_ST & RB_UMS_SUSPEND) {
|
||||
;// suspend
|
||||
}
|
||||
else {
|
||||
;// resume
|
||||
}
|
||||
}
|
||||
|
||||
__INTERRUPT
|
||||
__HIGH_CODE
|
||||
void USB_IRQHandler(void) {
|
||||
uint8_t intflag = R8_USB_INT_FG;
|
||||
clear_handshake_sent_flag();
|
||||
PRINT("\nusb: new interrupt\n");
|
||||
print_intflag_reg();
|
||||
|
||||
if (intflag & RB_UIF_TRANSFER) {
|
||||
PRINT("usb: RX Length reg: %d\n", R8_USB_RX_LEN);
|
||||
print_status_reg();
|
||||
|
||||
route_enpoints();
|
||||
}
|
||||
else if (intflag & RB_UIF_BUS_RST) {
|
||||
handle_busReset();
|
||||
}
|
||||
else if (intflag & RB_UIF_SUSPEND) {
|
||||
handle_powerChange();
|
||||
}
|
||||
|
||||
if (handshake_sent() == 0) {
|
||||
PRINT("WARN: This transaction is being IGNORED!\n");
|
||||
}
|
||||
R8_USB_INT_FG = intflag; // clear interrupt flags
|
||||
}
|
||||
82
src/usb/debug.c
Normal file
82
src/usb/debug.c
Normal file
@ -0,0 +1,82 @@
|
||||
#include "CH58x_common.h"
|
||||
|
||||
void print_setuppk(USB_SETUP_REQ *request)
|
||||
{
|
||||
PRINT("Setup request:\n");
|
||||
|
||||
char *dir[] = {"OUT", "IN"};
|
||||
char *type[] = {"Standard", "Class", "Vendor", "Reserved Type"};
|
||||
char *recipient[] = {
|
||||
"Device", "Interface", "Endpoint", "Other","Reserved Recipient"
|
||||
};
|
||||
char *bRequest[] = {
|
||||
"GET_STATUS",
|
||||
"CLEAR_FEATURE",
|
||||
"Reserved",
|
||||
"SET_FEATURE",
|
||||
"Reserved",
|
||||
"SET_ADDRESS",
|
||||
"GET_DESCRIPTOR",
|
||||
"SET_DESCRIPTOR",
|
||||
"GET_CONFIGURATION",
|
||||
"SET_CONFIGURATION",
|
||||
"GET_INTERFACE",
|
||||
"SET_INTERFACE",
|
||||
"SYNCH_FRAME",
|
||||
};
|
||||
|
||||
uint8_t t = request->bRequestType;
|
||||
uint8_t req = request->bRequest;
|
||||
uint8_t type_val = (t & USB_REQ_TYP_MASK) >> 5;
|
||||
uint8_t recip_val = t & USB_REQ_RECIP_MASK;
|
||||
if (recip_val > 4)
|
||||
recip_val = 4;
|
||||
|
||||
PRINT("\t- bRequestType: 0x%02x (%s|%s|%s)\n", t, dir[t>>7],
|
||||
type[type_val],
|
||||
recipient[recip_val]);
|
||||
|
||||
PRINT("\t- bRequest: 0x%02x (%s)\n", req, req > 12 ?
|
||||
"N/A" : bRequest[req]);
|
||||
PRINT("\t- wValue: 0x%04x\n", request->wValue);
|
||||
|
||||
PRINT("\t- wIndex%s: 0x%04x\n",
|
||||
recip_val == USB_REQ_RECIP_INTERF ? " (wInterfaceNumber)" : "",
|
||||
request->wIndex);
|
||||
|
||||
PRINT("\t- wLength: 0x%04x\n", request->wLength);
|
||||
}
|
||||
|
||||
void print_status_reg()
|
||||
{
|
||||
char *token_type[] = {
|
||||
"OUT", "SOF","IN", "SETUP",
|
||||
};
|
||||
uint8_t reg = R8_USB_INT_ST;
|
||||
uint8_t is_setup = reg & RB_UIS_SETUP_ACT;
|
||||
uint8_t toggle = reg & RB_UIS_TOG_OK;
|
||||
uint8_t token = (reg & MASK_UIS_TOKEN) >> 4;
|
||||
uint8_t ep_num = reg & MASK_UIS_ENDP;
|
||||
PRINT("usb: Status reg: 0x%02x (%s|%s|%s|EP:%d)\n", reg,
|
||||
is_setup ? "SETUP??" : "0",
|
||||
toggle ? "TOGGLE OK" : "0", token_type[token], ep_num);
|
||||
}
|
||||
|
||||
void print_intflag_reg()
|
||||
{
|
||||
uint8_t reg = R8_USB_INT_FG;
|
||||
uint8_t is_nak = reg & RB_U_IS_NAK;
|
||||
uint8_t tog_ok = reg & RB_U_TOG_OK;
|
||||
uint8_t sie = reg & RB_U_SIE_FREE;
|
||||
uint8_t overflow = reg & RB_UIF_FIFO_OV;
|
||||
uint8_t suspend = reg & RB_UIF_SUSPEND;
|
||||
uint8_t xfer_complete = reg & RB_UIF_TRANSFER;
|
||||
uint8_t bus_reset = reg & RB_UIF_BUS_RST;
|
||||
PRINT("usb: Interrupt reg: 0x%02x (%s|%s|%s|%s|%s|%s)\n", reg,
|
||||
is_nak ? "NAK received" : "0",
|
||||
tog_ok ? "Toggle ok" : "0",
|
||||
sie ? "SIE" : "0",
|
||||
overflow ? "FIFO overflow" : "0",
|
||||
suspend ? "Suspend" : "0",
|
||||
xfer_complete ? "Xfer completed" : "0");
|
||||
}
|
||||
14
src/usb/debug.h
Normal file
14
src/usb/debug.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
#include "CH58x_common.h"
|
||||
|
||||
|
||||
#define _TRACE() PRINT("> "); PRINT(__FILE__);PRINT(": "); PRINT(__func__); \
|
||||
PRINT("()\n")
|
||||
|
||||
void print_setuppk(USB_SETUP_REQ *setup_req_pk);
|
||||
void print_status_reg();
|
||||
void print_intflag_reg();
|
||||
|
||||
#endif /* __DEBUG_H__ */
|
||||
176
src/usb/dev.c
Normal file
176
src/usb/dev.c
Normal file
@ -0,0 +1,176 @@
|
||||
#include "CH58x_common.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "debug.h"
|
||||
|
||||
extern uint8_t *cfg_desc;
|
||||
|
||||
void usb_set_address(uint8_t ad);
|
||||
|
||||
USB_DEV_DESCR dev_desc = {
|
||||
.bLength = sizeof(USB_DEV_DESCR),
|
||||
.bDescriptorType = 0x01,
|
||||
.bcdUSB = 0x0110,
|
||||
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0x00,
|
||||
.bDeviceProtocol = 0x00,
|
||||
|
||||
.bMaxPacketSize0 = MAX_PACKET_SIZE,
|
||||
|
||||
.idVendor = 0x0416,
|
||||
.idProduct = 0x5020,
|
||||
.bcdDevice = 0x0000,
|
||||
.iManufacturer = 1,
|
||||
.iProduct = 2,
|
||||
.iSerialNumber = 3,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
/* String Descriptor Zero, Specifying Languages Supported by the Device */
|
||||
static uint8_t lang_desc[] = {
|
||||
0x04, /* bLength */
|
||||
0x03, /* bDescriptorType */
|
||||
0x09, 0x04 /* wLANGID - en-US */
|
||||
};
|
||||
|
||||
static uint16_t vendor_info[] = {
|
||||
36 | /* bLength */
|
||||
0x03 << 8, /* bDescriptorType */
|
||||
|
||||
/* bString */
|
||||
'F', 'O', 'S', 'S', 'A', 'S', 'I', 'A', ' ',
|
||||
'W', 'A', 'S', ' ', 'H', 'E', 'R', 'E'
|
||||
};
|
||||
|
||||
static uint16_t product_info[] = {
|
||||
32 | /* bLength */
|
||||
0x03 << 8, /* bDescriptorType */
|
||||
|
||||
/* bString */
|
||||
'L', 'E', 'D', ' ',
|
||||
'B', 'a', 'd', 'g', 'e', ' ',
|
||||
'M', 'a', 'g', 'i', 'c'
|
||||
};
|
||||
|
||||
// TODO: auto update firmware version by CI here
|
||||
static uint16_t serial_number[] = {
|
||||
47 * 2 | /* bLength */
|
||||
0x03 << 8, /* bDescriptorType */
|
||||
|
||||
/* bString */
|
||||
'N', 'o', 't', ' ', 'y', 'e', 't', ' ',
|
||||
'i', 'm', 'p', 'l', 'e', 'm', 'e', 'n', 't', 'e', 'd', '\n',
|
||||
'P', 'R', 'E', 'S', 'S', ' ', 'A', 'L', 'T', '+', 'F', '4', ' ',
|
||||
'T', 'O', ' ', 'C', 'O', 'N', 'T', 'I', 'N', 'U', 'E', '.'
|
||||
};
|
||||
|
||||
static void desc_dev(USB_SETUP_REQ *request)
|
||||
{
|
||||
ctrl_start_load_block(&dev_desc, dev_desc.bLength);
|
||||
}
|
||||
|
||||
static void desc_config(USB_SETUP_REQ *request)
|
||||
{
|
||||
ctrl_start_load_block(cfg_desc, request->wLength);
|
||||
}
|
||||
|
||||
static void desc_string(USB_SETUP_REQ *request)
|
||||
{
|
||||
uint8_t *string_index[32] = {
|
||||
lang_desc,
|
||||
vendor_info,
|
||||
product_info,
|
||||
serial_number
|
||||
};
|
||||
uint8_t index = request->wValue & 0xff;
|
||||
if (index <= sizeof(string_index))
|
||||
ctrl_start_load_block(string_index[index], string_index[index][0]);
|
||||
}
|
||||
|
||||
static void dev_getDesc(USB_SETUP_REQ *request)
|
||||
{
|
||||
_TRACE();
|
||||
uint8_t type = request->wValue >> 8;
|
||||
|
||||
PRINT("Descriptor type: 0x%02x\n", type);
|
||||
|
||||
static const void (*desc_type_handlers[4])(USB_SETUP_REQ *request) = {
|
||||
NULL,
|
||||
desc_dev,
|
||||
desc_config,
|
||||
desc_string
|
||||
};
|
||||
if (type <= 3 && desc_type_handlers[type])
|
||||
desc_type_handlers[type](request);
|
||||
}
|
||||
|
||||
static void dev_getStatus(USB_SETUP_REQ *request)
|
||||
{
|
||||
_TRACE();
|
||||
// Remote Wakeup disabled | Bus powered, hardcoded for now
|
||||
uint8_t buf[] = {0, 0};
|
||||
ctrl_start_load_block(buf, 2);
|
||||
}
|
||||
|
||||
static void dev_clearFeature(USB_SETUP_REQ *request)
|
||||
{
|
||||
_TRACE();
|
||||
// DEVICE_REMOTE_WAKEUP and TEST_MODE are not available, ignore.
|
||||
}
|
||||
|
||||
static void dev_setFeature(USB_SETUP_REQ *request)
|
||||
{
|
||||
_TRACE();
|
||||
// DEVICE_REMOTE_WAKEUP and TEST_MODE are not available, ignore.
|
||||
}
|
||||
|
||||
static void dev_setAddress(USB_SETUP_REQ *request)
|
||||
{
|
||||
_TRACE();
|
||||
/* new address will be loadled in the next IN poll,
|
||||
so here just sending a ACK */
|
||||
usb_set_address(request->wValue & 0xff);
|
||||
ctrl_ack();
|
||||
}
|
||||
|
||||
// For now, multiple configuration is not supported
|
||||
static uint8_t devcfg;
|
||||
|
||||
static void dev_getConfig(USB_SETUP_REQ *request)
|
||||
{
|
||||
_TRACE();
|
||||
ctrl_start_load_block(&devcfg, 1);
|
||||
}
|
||||
|
||||
static void dev_setConfig(USB_SETUP_REQ *request)
|
||||
{
|
||||
_TRACE();
|
||||
devcfg = (request->wValue) & 0xff;
|
||||
ctrl_ack();
|
||||
}
|
||||
|
||||
void handle_devreq(USB_SETUP_REQ *request)
|
||||
{
|
||||
_TRACE();
|
||||
|
||||
static const void (*dev_req_handlers[13])(USB_SETUP_REQ *request) = {
|
||||
dev_getStatus,
|
||||
dev_clearFeature,
|
||||
NULL, // Reserved
|
||||
dev_setFeature,
|
||||
NULL, // Reserved
|
||||
dev_setAddress,
|
||||
dev_getDesc,
|
||||
NULL, // set desc
|
||||
dev_getConfig,
|
||||
dev_setConfig,
|
||||
NULL, // get interface
|
||||
NULL, // set interface
|
||||
NULL, // sync frame
|
||||
};
|
||||
|
||||
uint8_t req = request->bRequest;
|
||||
if (req <= 12 && dev_req_handlers[req])
|
||||
dev_req_handlers[req](request);
|
||||
}
|
||||
132
src/usb/setup.c
Normal file
132
src/usb/setup.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CH58x_common.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
uint8_t *cfg_desc;
|
||||
|
||||
// FIXME: here wasting 1KiB of ram
|
||||
void (*if_handlers[256])(USB_SETUP_REQ *request);
|
||||
void (*ep_handlers[7])();
|
||||
|
||||
/* Configuration Descriptor template */
|
||||
USB_CFG_DESCR cfg_static = {
|
||||
.bLength = sizeof(USB_CFG_DESCR),
|
||||
.bDescriptorType = 0x02,
|
||||
.wTotalLength = sizeof(USB_CFG_DESCR), // will be updated on cfg_desc_add()
|
||||
.bNumInterfaces = 0, // will be updated on cfg_desc_add()
|
||||
.bConfigurationValue = 0x01,
|
||||
.iConfiguration = 4,
|
||||
.bmAttributes = 0xA0,
|
||||
.MaxPower = 50 // mA
|
||||
};
|
||||
|
||||
void cfg_desc_append(void *desc)
|
||||
{
|
||||
uint8_t cfg_len = 0;
|
||||
uint8_t len = ((uint8_t *)desc)[0];
|
||||
if (cfg_desc) // attempting to add a non-Configuration Descriptor
|
||||
cfg_len = ((USB_CFG_DESCR *)cfg_desc)->wTotalLength;
|
||||
uint8_t newlen = cfg_len + len;
|
||||
|
||||
cfg_desc = realloc(cfg_desc, newlen); // TODO: add a safe check here
|
||||
|
||||
memcpy(cfg_desc + cfg_len, desc, len);
|
||||
|
||||
((USB_CFG_DESCR *)cfg_desc)->wTotalLength = newlen;
|
||||
((USB_CFG_DESCR *)cfg_desc)->bNumInterfaces += ((uint8_t *)desc)[1] == 0x04;
|
||||
}
|
||||
|
||||
int ep_cb_register(int ep_num, void (*cb)())
|
||||
{
|
||||
if (ep_num > 8)
|
||||
return -1;
|
||||
if (ep_handlers[ep_num]) // already registerd
|
||||
return -1;
|
||||
|
||||
ep_handlers[ep_num] = cb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int if_cb_register(uint8_t if_num, void (*cb)(USB_SETUP_REQ *request))
|
||||
{
|
||||
if (if_handlers[if_num]) // already registered
|
||||
return -1;
|
||||
|
||||
if_handlers[if_num] = cb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dma_register(uint8_t ep_num, void *buf)
|
||||
{
|
||||
if (ep_num > 7) // CH582 support only 8 endpoint
|
||||
return;
|
||||
|
||||
volatile uint16_t *p_regs[] = {
|
||||
&R16_UEP0_DMA,
|
||||
&R16_UEP1_DMA,
|
||||
&R16_UEP2_DMA,
|
||||
&R16_UEP3_DMA,
|
||||
NULL,
|
||||
&R16_UEP5_DMA,
|
||||
&R16_UEP6_DMA,
|
||||
&R16_UEP7_DMA,
|
||||
};
|
||||
volatile uint8_t *ctrl_regs[] = {
|
||||
&R8_UEP0_CTRL,
|
||||
&R8_UEP1_CTRL,
|
||||
&R8_UEP2_CTRL,
|
||||
&R8_UEP3_CTRL,
|
||||
&R8_UEP4_CTRL,
|
||||
&R8_UEP5_CTRL,
|
||||
&R8_UEP6_CTRL,
|
||||
&R8_UEP7_CTRL,
|
||||
};
|
||||
// ep4's dma buffer is hardcoded pointing to
|
||||
// the next ep0
|
||||
if (ep_num != 4)
|
||||
*p_regs[ep_num] = (uint16_t)(uint32_t)buf;
|
||||
|
||||
*ctrl_regs[ep_num] = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
||||
}
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
R8_USB_CTRL = 0x00;
|
||||
|
||||
R8_UEP4_1_MOD = RB_UEP4_RX_EN | RB_UEP4_TX_EN |
|
||||
RB_UEP1_RX_EN | RB_UEP1_TX_EN;
|
||||
R8_UEP2_3_MOD = RB_UEP2_RX_EN | RB_UEP2_TX_EN |
|
||||
RB_UEP3_RX_EN | RB_UEP3_TX_EN;
|
||||
R8_UEP567_MOD = RB_UEP7_RX_EN | RB_UEP7_TX_EN |
|
||||
RB_UEP6_RX_EN | RB_UEP6_TX_EN |
|
||||
RB_UEP5_RX_EN | RB_UEP5_TX_EN;
|
||||
|
||||
R16_PIN_ANALOG_IE |= RB_PIN_USB_IE | RB_PIN_USB_DP_PU;
|
||||
R8_UDEV_CTRL = RB_UD_PD_DIS | RB_UD_PORT_EN;
|
||||
|
||||
R8_USB_DEV_AD = 0x00;
|
||||
R8_USB_INT_FG = 0xFF;
|
||||
R8_USB_CTRL = RB_UC_DEV_PU_EN | RB_UC_INT_BUSY | RB_UC_DMA_EN;
|
||||
R8_USB_INT_EN = RB_UIE_SUSPEND | RB_UIE_BUS_RST | RB_UIE_TRANSFER;
|
||||
}
|
||||
|
||||
void ctrl_init();
|
||||
void hiddev_init();
|
||||
void cdc_acm_init();
|
||||
|
||||
void usb_start() {
|
||||
cfg_desc_append(&cfg_static);
|
||||
|
||||
ctrl_init();
|
||||
|
||||
/* This should be placed first, the python script always looks
|
||||
for the first interface (not the interface number) */
|
||||
hiddev_init();
|
||||
|
||||
cdc_acm_init();
|
||||
|
||||
init();
|
||||
PFIC_EnableIRQ(USB_IRQn);
|
||||
}
|
||||
16
src/usb/usb.h
Normal file
16
src/usb/usb.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __USB_H__
|
||||
#define __USB_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void cdc_fill_IN(uint8_t *buf, uint8_t len);
|
||||
int cdc_tx_poll(uint8_t *buf, int len, uint16_t timeout_ms);
|
||||
void cdc_onWrite(void (*cb)(uint8_t *buf, uint16_t len));
|
||||
|
||||
void hiddev_fill_IN(uint8_t *buf, uint8_t len);
|
||||
int hiddev_tx_poll(uint8_t *buf, int len, uint16_t timeout_ms);
|
||||
void hiddev_onWrite(void (*cb)(uint8_t *buf, uint16_t len));
|
||||
|
||||
void usb_start();
|
||||
|
||||
#endif /* __USB_H__ */
|
||||
130
src/usb/utils.c
Normal file
130
src/usb/utils.c
Normal file
@ -0,0 +1,130 @@
|
||||
#include "CH58x_common.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "debug.h"
|
||||
|
||||
// A response a has been set, if not, that transaction is not handled
|
||||
int res_sent;
|
||||
|
||||
static uint8_t *current_IN_buf;
|
||||
|
||||
static volatile uint8_t *len_regs[] = {
|
||||
&R8_UEP0_T_LEN,
|
||||
&R8_UEP1_T_LEN,
|
||||
&R8_UEP2_T_LEN,
|
||||
&R8_UEP3_T_LEN,
|
||||
&R8_UEP4_T_LEN,
|
||||
&R8_UEP5_T_LEN,
|
||||
&R8_UEP6_T_LEN,
|
||||
&R8_UEP7_T_LEN
|
||||
};
|
||||
static volatile uint8_t *ctrl_regs[] = {
|
||||
&R8_UEP0_CTRL,
|
||||
&R8_UEP1_CTRL,
|
||||
&R8_UEP2_CTRL,
|
||||
&R8_UEP3_CTRL,
|
||||
&R8_UEP4_CTRL,
|
||||
&R8_UEP5_CTRL,
|
||||
&R8_UEP6_CTRL,
|
||||
&R8_UEP7_CTRL
|
||||
};
|
||||
|
||||
static void __handshake(uint8_t ep_num, int dir, int type, int tog, uint8_t len)
|
||||
{
|
||||
_TRACE();
|
||||
if (ep_num > 7)
|
||||
return;
|
||||
|
||||
char *type_mean[] = { "ACK", "NO_RESP", "NAK", "STALL"};
|
||||
PRINT("Loaded %d byte, DATA%d with an %s to EP%dIN.\n",
|
||||
len, tog != 0, type_mean[type], ep_num);
|
||||
|
||||
uint8_t ctrl = type << (dir ? 0 : 2);
|
||||
ctrl |= (tog) ? RB_UEP_T_TOG : RB_UEP_R_TOG;
|
||||
|
||||
res_sent = 1;
|
||||
*len_regs[ep_num] = len;
|
||||
*ctrl_regs[ep_num] = ctrl;
|
||||
}
|
||||
|
||||
void set_handshake(uint8_t ep_num, int type, int tog, uint8_t len)
|
||||
{
|
||||
_TRACE();
|
||||
__handshake(ep_num, 1, type, tog, len);
|
||||
}
|
||||
|
||||
void ctrl_ack()
|
||||
{
|
||||
_TRACE();
|
||||
set_handshake(0, USB_ACK, 1, 0);
|
||||
}
|
||||
|
||||
void clear_handshake_sent_flag()
|
||||
{
|
||||
res_sent = 0;
|
||||
}
|
||||
|
||||
int handshake_sent()
|
||||
{
|
||||
return res_sent;
|
||||
}
|
||||
|
||||
static uint8_t *p_buf;
|
||||
static uint16_t remain_len, req_len, _tog;
|
||||
|
||||
static uint16_t
|
||||
load_chunk(void *ep_buf, void *block, uint16_t block_len, uint16_t req_len,
|
||||
int tog)
|
||||
{
|
||||
_TRACE();
|
||||
uint16_t remain_len = 0;
|
||||
|
||||
if (req_len > MAX_PACKET_SIZE)
|
||||
req_len = MAX_PACKET_SIZE;
|
||||
|
||||
if (block_len >= req_len) {
|
||||
remain_len = block_len - req_len;
|
||||
block_len = req_len;
|
||||
}
|
||||
p_buf = block;
|
||||
|
||||
memcpy(ep_buf, p_buf, block_len);
|
||||
p_buf += block_len;
|
||||
|
||||
set_handshake(0, USB_ACK, tog, block_len);
|
||||
|
||||
PRINT("remain_len: %d\n", remain_len);
|
||||
return remain_len;
|
||||
}
|
||||
|
||||
void usb_flush()
|
||||
{
|
||||
_TRACE();
|
||||
remain_len = 0;
|
||||
_tog = 0;
|
||||
}
|
||||
|
||||
int usb_load_next_chunk()
|
||||
{
|
||||
_TRACE();
|
||||
if (remain_len) {
|
||||
remain_len = load_chunk(current_IN_buf, p_buf, remain_len, req_len,
|
||||
_tog);
|
||||
_tog = !_tog;
|
||||
} else {
|
||||
_tog = 0;
|
||||
return -1;
|
||||
}
|
||||
return remain_len;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
usb_start_load_block(void *ep_IN_buf, void *buf, uint16_t len, int tog)
|
||||
{
|
||||
_TRACE();
|
||||
req_len = len;
|
||||
current_IN_buf = ep_IN_buf;
|
||||
remain_len = load_chunk(ep_IN_buf, buf, len, len, tog);
|
||||
_tog = !tog;
|
||||
return remain_len;
|
||||
}
|
||||
30
src/usb/utils.h
Normal file
30
src/usb/utils.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#include "CH58x_common.h"
|
||||
|
||||
enum USB_RESPONSE_TYPE {
|
||||
USB_ACK = 0,
|
||||
USB_NO_RESP,
|
||||
USB_NAK,
|
||||
USB_STALL,
|
||||
};
|
||||
|
||||
void cfg_desc_append(void *desc);
|
||||
int ep_cb_register(int ep_num, void (*cb)());
|
||||
int if_cb_register(uint8_t if_num, void (*cb)(USB_SETUP_REQ *request));
|
||||
void dma_register(uint8_t endpoint_number, void *buf_addr);
|
||||
|
||||
uint16_t
|
||||
usb_start_load_block(void *ep_IN_buf, void *buf, uint16_t len, int tog);
|
||||
void ctrl_start_load_block(void *buf, uint16_t len);
|
||||
int usb_load_next_chunk();
|
||||
void usb_flush();
|
||||
|
||||
void set_handshake(uint8_t ep_num, int type, int tog, uint8_t len);
|
||||
void ctrl_ack();
|
||||
|
||||
void clear_handshake_sent_flag();
|
||||
int handshake_sent();
|
||||
|
||||
#endif /* __UTILS_H__ */
|
||||
Loading…
x
Reference in New Issue
Block a user