-
Notifications
You must be signed in to change notification settings - Fork 260
/
Copy pathendpoints.c
450 lines (409 loc) · 13.3 KB
/
endpoints.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
/*
Copyright (C) 2018,2019 Jim Jiang <[email protected]>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "CH554_SDCC.h"
#include "compiler.h"
#include "descriptor.h"
#include "endpoints.h"
#define THIS_ENDP0_SIZE DEFAULT_ENDP0_SIZE
/**
* @brief 端点0/4缓冲区。
*
* 0x00-0x3F 为端点0的IN与OUT缓冲区
* 0x40-0x7F 端点4 OUT
* 0x80-0xBF 端点4 IN
*
*/
volatile uint8_t __XDATA Ep0Buffer[MAX_PACKET_SIZE * 3];
/**
* @brief 端点1缓冲区,用于键盘报文
*
* 地址0x88-0xC7为端点1OUT缓冲区 (实际使用1byte)
* 地址0xC8-0xCF为端点1IN缓冲区 (8byte)
*
*/
volatile uint8_t __XDATA Ep1Buffer[MAX_PACKET_SIZE * 2]; //端点1 IN缓冲区,必须是偶地址
/**
* @brief 端点2IN缓冲区,用于System包和Consumer包的发送
*
*/
volatile uint8_t __XDATA Ep2Buffer[MAX_PACKET_SIZE];
/**
* @brief 端点3IN&OUT缓冲区,用于传递配置
*
*/
volatile uint8_t __XDATA Ep3Buffer[MAX_PACKET_SIZE * 2]; //端点3 IN缓冲区,必须是偶地址
static uint8_t DataInLen, UsbConfig, UsbAddr;
static uint8_t* pDataIn;
// USB 状态
union UsbState usb_state = {
.protocol = true, // HID规范要求默认的Protocol是Report
};
static uint8_t keyboard_idle = 0;
#define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer)
static uint8_t ClassRequestHandler(PUSB_SETUP_REQ packet);
/**
* 重置端点0的状态。
* SETUP/OUT ACK
* IN NAK
*/
#define EP0_RESET() EP_SET(0, 0, UEP_R_RES_ACK | UEP_T_RES_NAK)
/**
* 端点0响应状态包的Status,ACK
*/
#define EP0_DATA1_ACK() EP_SET(0, (bUEP_R_TOG | bUEP_T_TOG), (UEP_R_RES_ACK | UEP_T_RES_ACK))
/**
* @brief 为SETUP请求响应STALL
*
*/
#define SETUP_STALL() EP_SET(0, bUEP_R_TOG | bUEP_T_TOG, UEP_R_RES_STALL | UEP_T_RES_STALL)
void nop()
{
}
void EP0_OUT()
{
switch (usb_state.setup_state) {
case SETUP_IDLE:
/* code */
break;
case SETUP_STATE_OUT:
// 重置端点状态,等待下次传输
UEP0_CTRL ^= bUEP_R_TOG; //同步标志位翻转
usb_state.setup_state = SETUP_IDLE;
break;
case SETUP_DATA_OUT:
// 似乎没有下传的数据
break;
default:
// ERROR
UEP0_CTRL ^= bUEP_R_TOG; //同步标志位翻转
usb_state.setup_state = SETUP_IDLE;
break;
}
}
void EP0_IN()
{
switch (usb_state.setup_state) {
case SETUP_IDLE:
/* code */
break;
case SETUP_DATA_IN:
if (DataInLen == 0) {
usb_state.setup_state = SETUP_STATE_OUT;
}
uint8_t len = DataInLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : DataInLen; //本次传输长度
memcpy(Ep0Buffer, pDataIn, len); //加载上传数据
DataInLen -= len;
pDataIn += len;
UEP0_T_LEN = len;
UEP0_CTRL ^= bUEP_T_TOG; //同步标志位翻转
break;
case SETUP_STATE_IN:
// 延迟设置USB设备的地址
if (UsbAddr) {
USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | UsbAddr;
UsbAddr = 0;
}
// 状态阶段完成中断或者是强制上传0长度数据包结束控制传输
UEP0_T_LEN = 0;
EP0_RESET();
usb_state.setup_state = SETUP_IDLE;
break;
default:
// ERROR
EP0_RESET();
usb_state.setup_state = SETUP_IDLE;
break;
}
}
void EP0_SETUP()
{
if (USB_RX_LEN != (sizeof(USB_SETUP_REQ))) {
SETUP_STALL();
return;
}
uint8_t datalen = 0;
DataInLen = UsbSetupBuf->wLength > 0xFF ? 0xFF : UsbSetupBuf->wLength; // 限制总长度
if (UsbSetupBuf->bmRequestType.Type == 0) //标准请求
{
switch (UsbSetupBuf->bRequest) //请求码
{
case USB_GET_DESCRIPTOR:
datalen = GetUsbDescriptor(UsbSetupBuf->wValueH, UsbSetupBuf->wValueL, UsbSetupBuf->wIndexL, &pDataIn);
usb_state.setup_state = SETUP_DATA_IN;
break;
case USB_SET_ADDRESS:
UsbAddr = UsbSetupBuf->wValueL; //暂存USB设备地址
usb_state.setup_state = SETUP_STATE_IN;
break;
case USB_GET_CONFIGURATION:
Ep0Buffer[0] = UsbConfig;
pDataIn = Ep0Buffer;
datalen = 1;
usb_state.setup_state = SETUP_DATA_IN;
break;
case USB_SET_CONFIGURATION:
UsbConfig = UsbSetupBuf->wValueL;
// USB枚举完毕
usb_state.is_ready = UsbConfig > 0;
usb_state.setup_state = SETUP_STATE_IN;
RESET_KEEP = 1;
break;
case USB_GET_INTERFACE:
Ep0Buffer[0] = 0x00;
pDataIn = Ep0Buffer;
datalen = 1;
usb_state.setup_state = SETUP_DATA_IN;
break;
case USB_CLEAR_FEATURE: {
switch (UsbSetupBuf->bmRequestType.Recipient) {
case USB_REQ_TO_ENDPOINT: {
switch (UsbSetupBuf->wIndexL) {
case 0x84:
EP_IN_NAK_TOG(4);
break;
case 0x83:
EP_IN_NAK_TOG(3);
break;
case 0x82:
EP_IN_NAK_TOG(2);
break;
case 0x81:
EP_IN_NAK_TOG(1);
break;
case 0x04:
EP_OUT_ACK_TOG(4);
break;
case 0x03:
EP_OUT_ACK_TOG(3);
break;
case 0x02:
EP_OUT_ACK_TOG(2);
break;
case 0x01:
EP_OUT_ACK_TOG(1);
break;
default:
SETUP_STALL();
return;
}
break;
}
case USB_REQ_TO_DEVICE:
if (UsbSetupBuf->wValue != 0x01) {
// 操作失败
SETUP_STALL();
return;
}
// 设置唤醒使能标志
usb_state.remote_wake = false;
break;
default: //unsupport
SETUP_STALL();
return;
}
usb_state.setup_state = SETUP_STATE_IN;
break;
}
case USB_SET_FEATURE: /* Set Feature */
{
switch (UsbSetupBuf->bmRequestType.Recipient) {
// 接口
case USB_REQ_TO_ENDPOINT: {
// 接口的Value始终为0
if (UsbSetupBuf->wValue != 0) {
SETUP_STALL();
return;
}
// Zero, Interface endpoint
switch (UsbSetupBuf->wIndex) {
case 0x84:
EP_IN_STALL_TOG(4);
break;
case 0x83:
EP_IN_STALL_TOG(3);
break;
case 0x82:
EP_IN_STALL_TOG(2);
break;
case 0x81:
EP_IN_STALL_TOG(1);
break;
case 0x02:
EP_OUT_STALL_TOG(2);
break;
default:
SETUP_STALL();
return;
}
break;
}
case USB_REQ_TO_DEVICE: {
if (UsbSetupBuf->wValue != 0x01) {
SETUP_STALL();
return;
}
// 设置唤醒使能标志
usb_state.remote_wake = true;
break;
}
default:
SETUP_STALL();
return;
}
usb_state.setup_state = SETUP_STATE_IN;
break;
}
case USB_GET_STATUS:
Ep0Buffer[0] = 0x00 | (usb_state.remote_wake ? 0x02 : 0x00);
Ep0Buffer[1] = 0x00;
datalen = 2;
usb_state.setup_state = SETUP_DATA_IN;
break;
default:
SETUP_STALL();
return;
}
} else if (UsbSetupBuf->bmRequestType.Type == 1) {
//HID类请求
datalen = ClassRequestHandler(UsbSetupBuf);
if (datalen == 0xFF) {
SETUP_STALL();
return;
}
if (datalen > 0) {
usb_state.setup_state = SETUP_STATE_IN;
} else {
pDataIn = Ep0Buffer;
usb_state.setup_state = SETUP_DATA_IN;
}
} else {
SETUP_STALL();
return;
}
switch (usb_state.setup_state) {
case SETUP_STATE_IN:
UEP0_T_LEN = 0; //虽然尚未到状态阶段,但是提前预置上传0长度数据包以防主机提前进入状态阶段
EP0_DATA1_ACK(); // 响应SETUP包的STATUS
// usb_state.setup_state = SETUP_IDLE;
break;
case SETUP_DATA_IN:
DataInLen = DataInLen > datalen ? datalen : DataInLen;
uint8_t len = DataInLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : DataInLen; //本次传输长度
memcpy(Ep0Buffer, pDataIn, len); //加载上传数据
DataInLen -= len;
pDataIn += len;
UEP0_T_LEN = len;
EP0_DATA1_ACK(); // 使用DATA1响应数据
if (DataInLen == 0)
usb_state.setup_state = SETUP_STATE_OUT;
break;
default:
break;
}
}
void EP1_IN()
{
EP_IN_FINISH(1);
usb_state.is_busy = false;
}
void EP2_IN()
{
EP_IN_FINISH(2);
usb_state.is_busy = false;
}
void EP3_IN()
{
EP_IN_FINISH(3);
usb_state.is_busy = false;
}
void EP4_IN()
{
EP_IN_FINISH(4);
UEP4_CTRL ^= bUEP_T_TOG;
usb_state.is_busy = false;
}
static uint8_t ClassRequestHandler(PUSB_SETUP_REQ packet)
{
uint8_t interface = packet->wIndexL;
uint8_t recipient = UsbSetupBuf->bmRequestType.Recipient;
switch (packet->bRequest) {
case 0x01: //GetReport
if (interface == 0 && recipient == USB_REQ_TO_INTERFACE) {
memcpy(Ep0Buffer, &Ep1Buffer[64], 8);
return 8;
}
break;
case 0x02: //GetIdle
if (interface == 0 && recipient == USB_REQ_TO_INTERFACE) {
Ep0Buffer[0] = keyboard_idle;
return 1;
}
break;
case 0x03: //GetProtocol
if (interface == 0 && recipient == USB_REQ_TO_INTERFACE) {
Ep0Buffer[0] = usb_state.protocol ? 1 : 0;
return 1;
}
break;
case 0x09: //SetReport
if (interface == 0 && recipient == USB_REQ_TO_INTERFACE) {
Ep1Buffer[0] = Ep0Buffer[0];
EP1_OUT();
}
break;
case 0x0A: //SetIdle
if (interface == 0 && recipient == USB_REQ_TO_INTERFACE) {
keyboard_idle = UsbSetupBuf->wValueH;
}
break;
case 0x0B: //SetProtocol
if (interface == 0 && recipient == USB_REQ_TO_INTERFACE) {
usb_state.protocol = UsbSetupBuf->wValueL > 0;
}
break;
default:
return 0xFF; /*命令不支持*/
break;
}
return 0;
}
/** \brief USB设备模式配置,设备模式启动,收发端点配置,中断开启
*
*/
void USBDeviceInit()
{
IE_USB = 0;
USB_CTRL = 0x00; // 先设定USB设备模式
UEP0_DMA = (uint16_t)Ep0Buffer; //端点0数据传输地址
UEP4_1_MOD |= bUEP4_RX_EN | bUEP4_TX_EN; //端点0单64字节收发缓冲区, 端点4单64字节收发缓冲区
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; //OUT事务返回ACK,IN事务返回NAK
UEP1_DMA = (uint16_t)Ep1Buffer; //端点1数据传输地址
UEP4_1_MOD = UEP4_1_MOD & ~bUEP1_BUF_MOD | bUEP1_TX_EN | bUEP1_RX_EN; //端点1收发使能 64字节收发缓冲区
UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK; //端点1自动翻转同步标志位,IN事务返回NAK
UEP2_DMA = (uint16_t)Ep2Buffer; //端点2数据传输地址
UEP2_3_MOD = UEP2_3_MOD & ~bUEP2_BUF_MOD | bUEP2_TX_EN; //端点2接收使能 64字节缓冲区
UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK; //端点2自动翻转同步标志位,IN事务返回NAK
UEP3_DMA = (uint16_t)Ep3Buffer; //端点3数据传输地址
UEP2_3_MOD = UEP2_3_MOD & ~bUEP3_BUF_MOD | bUEP3_TX_EN | bUEP1_RX_EN; //端点3接收使能 64字节缓冲区
UEP3_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK; //端点3自动翻转同步标志位,IN事务返回NAK
UEP4_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK; //端点4自动翻转同步标志位,IN事务返回NAK
USB_DEV_AD = 0x00;
UDEV_CTRL = bUD_PD_DIS; // 禁止DP/DM下拉电阻
USB_CTRL = bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN; // 启动USB设备及DMA,在中断期间中断标志未清除前自动返回NAK
UDEV_CTRL |= bUD_PORT_EN; // 允许USB端口
USB_INT_FG = 0xFF; // 清中断标志
USB_INT_EN = bUIE_SUSPEND | bUIE_TRANSFER | bUIE_BUS_RST;
IE_USB = 1;
}