1 /******************************************************************************
2 * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
3 * All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************/
18 #include "common/utility.h"
19 #include "drivers.h"
20 #include "myudb.h"
21 #include "myudb_usbdesc.h"
22 #include <string.h>
23
24 #if (VCD_EN || DUMP_STR_EN)
25
26 typedef struct myudb_cfg {
27 u16 id;
28 u16 response_len;
29
30 u8 *response;
31 u32 tick_sync;
32
33 u8 stall;
34 u8 rptr;
35 u16 cmd_len;
36 } myudb_cfg_t;
37
38 myudb_cfg_t myudb = {0x120};
39
40 static USB_Request_Header_t control_request;
41
42 my_fifo_t *myudb_print_fifo = 0;
43
44 // USB device handling
45 // -----------------------------------------------------------------------------------------
46 enum {
47 MYUDB_USB_IRQ_SETUP_REQ = 0,
48 MYUDB_USB_IRQ_DATA_REQ,
49 };
50
51 // -----------------------------------------------------------------------------------------
myudb_usb_send_response(void)52 void myudb_usb_send_response(void)
53 {
54 u16 n;
55 if (myudb.response_len < 8) {
56 n = myudb.response_len;
57 } else {
58 n = 8;
59 }
60 myudb.response_len -= n;
61 usbhw_reset_ctrl_ep_ptr();
62 while (n-- > 0) {
63 usbhw_write_ctrl_ep_data(*myudb.response);
64 ++myudb.response;
65 }
66 }
67
myudb_usb_prepare_desc_data(void)68 void myudb_usb_prepare_desc_data(void)
69 {
70 u8 value_l = (control_request.wValue) & 0xff;
71 u8 value_h = (control_request.wValue >> 8) & 0xff;
72
73 myudb.response = 0;
74 myudb.response_len = 0;
75
76 switch (value_h) {
77 case DTYPE_Device:
78 myudb.response = myudb_usbdesc_get_device();
79 myudb.response_len = sizeof(USB_Descriptor_Device_t);
80 break;
81
82 case DTYPE_Configuration:
83 myudb.response = myudb_usbdesc_get_configuration();
84 myudb.response_len = sizeof(MYUDB_USB_Descriptor_Configuration_t);
85 break;
86
87 case DTYPE_String:
88 if (MYUDB_USB_STRING_LANGUAGE == value_l) {
89 myudb.response = myudb_usbdesc_get_language();
90 myudb.response_len = sizeof(LANGUAGE_ID_ENG);
91 } else if (MYUDB_USB_STRING_VENDOR == value_l) {
92 myudb.response = myudb_usbdesc_get_vendor();
93 myudb.response_len = sizeof(MYUDB_STRING_VENDOR);
94 } else if (MYUDB_USB_STRING_PRODUCT == value_l) {
95 myudb.response = myudb_usbdesc_get_product();
96 myudb.response_len = sizeof(MYUDB_STRING_PRODUCT);
97 } else if (MYUDB_USB_STRING_SERIAL == value_l) {
98 myudb.response = myudb_usbdesc_get_serial();
99 myudb.response_len = sizeof(MYUDB_STRING_SERIAL);
100 } else {
101 myudb.stall = 1;
102 }
103 break;
104
105 default:
106 myudb.stall = 1;
107 break;
108 }
109
110 if (control_request.wLength < myudb.response_len) {
111 myudb.response_len = control_request.wLength;
112 }
113
114 return;
115 }
116
myudb_usb_handle_in_class_intf_req()117 void myudb_usb_handle_in_class_intf_req()
118 {
119 u8 property = control_request.bRequest;
120 switch (property) {
121 case 0x00:
122 usbhw_write_ctrl_ep_data(0x00);
123 break;
124 default:
125 myudb.stall = 1;
126 break;
127 }
128 }
129
myudb_usb_handle_request(u8 data_request)130 void myudb_usb_handle_request(u8 data_request)
131 {
132 u8 bmRequestType = control_request.bmRequestType;
133 u8 bRequest = control_request.bRequest;
134
135 usbhw_reset_ctrl_ep_ptr();
136 switch (bmRequestType) {
137 case (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE):
138 if (REQ_GetDescriptor == bRequest) {
139 if (MYUDB_USB_IRQ_SETUP_REQ == data_request) {
140 myudb_usb_prepare_desc_data();
141 }
142 myudb_usb_send_response();
143 }
144 break;
145 case (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE):
146 myudb_usb_handle_in_class_intf_req();
147 break;
148 case (REQDIR_DEVICETOHOST | REQTYPE_VENDOR | REQREC_INTERFACE):
149 if (MYUDB_USB_IRQ_SETUP_REQ == data_request) {
150 if (bRequest == 0xc0) { // Get board version
151 usbhw_reset_ctrl_ep_ptr();
152 usbhw_write_ctrl_ep_data(myudb.id);
153 usbhw_write_ctrl_ep_data(myudb.id >> 8);
154 } else {
155 myudb.stall = 1;
156 }
157 }
158 break;
159 case (REQDIR_DEVICETOHOST | REQTYPE_VENDOR | REQREC_DEVICE): // 0xc0
160 if (MYUDB_USB_IRQ_SETUP_REQ == data_request) {
161 if (bRequest == 0xc0) { // Get board version
162 usbhw_reset_ctrl_ep_ptr();
163 usbhw_write_ctrl_ep_data(0x40);
164 usbhw_write_ctrl_ep_data(0x25);
165 usbhw_write_ctrl_ep_data(0x40);
166 usbhw_write_ctrl_ep_data(0x05);
167 usbhw_write_ctrl_ep_data(0x03);
168 usbhw_write_ctrl_ep_data(0x00);
169 usbhw_write_ctrl_ep_data(0x01);
170 usbhw_write_ctrl_ep_data(0x00);
171 } else if (bRequest == 0xc6) { //
172 usbhw_reset_ctrl_ep_ptr();
173 usbhw_write_ctrl_ep_data(0x04);
174 } else {
175 myudb.stall = 1;
176 }
177 }
178 break;
179 case (REQDIR_HOSTTODEVICE | REQTYPE_VENDOR | REQREC_DEVICE): // 0x40
180 myudb.stall = 1;
181 break;
182 default:
183 myudb.stall = 1;
184 break;
185 }
186
187 return;
188 }
189
myudb_usb_handle_ctl_ep_setup()190 void myudb_usb_handle_ctl_ep_setup()
191 {
192 usbhw_reset_ctrl_ep_ptr();
193 control_request.bmRequestType = usbhw_read_ctrl_ep_data();
194 control_request.bRequest = usbhw_read_ctrl_ep_data();
195 control_request.wValue = usbhw_read_ctrl_ep_u16();
196 control_request.wIndex = usbhw_read_ctrl_ep_u16();
197 control_request.wLength = usbhw_read_ctrl_ep_u16();
198 myudb.stall = 0;
199 myudb_usb_handle_request(MYUDB_USB_IRQ_SETUP_REQ);
200 if (myudb.stall)
201 usbhw_write_ctrl_ep_ctrl(FLD_EP_DAT_STALL);
202 else
203 usbhw_write_ctrl_ep_ctrl(FLD_EP_DAT_ACK);
204 }
205
myudb_usb_handle_ctl_ep_data(void)206 void myudb_usb_handle_ctl_ep_data(void)
207 {
208 usbhw_reset_ctrl_ep_ptr();
209 myudb.stall = 0;
210 myudb_usb_handle_request(MYUDB_USB_IRQ_DATA_REQ);
211 if (myudb.stall)
212 usbhw_write_ctrl_ep_ctrl(FLD_EP_DAT_STALL);
213 else
214 usbhw_write_ctrl_ep_ctrl(FLD_EP_DAT_ACK);
215 }
216
myudb_usb_handle_ctl_ep_status()217 void myudb_usb_handle_ctl_ep_status()
218 {
219 if (myudb.stall)
220 usbhw_write_ctrl_ep_ctrl(FLD_EP_STA_STALL);
221 else
222 usbhw_write_ctrl_ep_ctrl(FLD_EP_STA_ACK);
223 }
224
myudb_print_fifo_full(void)225 _attribute_ram_code_ int myudb_print_fifo_full(void)
226 {
227 u8 n = myudb_print_fifo->wptr - myudb_print_fifo->rptr;
228 return n >= myudb_print_fifo->num;
229 }
230
usb_send_status_pkt(u8 status,u8 buffer_num,u8 * pkt,u16 len)231 _attribute_ram_code_ void usb_send_status_pkt(u8 status, u8 buffer_num, u8 *pkt, u16 len)
232 {
233 u8 *p = myudb_print_fifo->p + (myudb_print_fifo->wptr & (myudb_print_fifo->num - 1)) * myudb_print_fifo->size;
234 if (len > 272) {
235 len = 272;
236 }
237 *p++ = len + 2;
238 *p++ = (len + 2) >> 8;
239 p += 2;
240 *p++ = status;
241 *p++ = buffer_num;
242 while (len--) {
243 *p++ = *pkt++;
244 }
245 myudb_print_fifo->wptr++;
246 }
247
usb_send_str_data(char * str,u8 * ph,int n)248 _attribute_ram_code_ void usb_send_str_data(char *str, u8 *ph, int n)
249 {
250 u32 rie = core_interrupt_disable();
251 u8 *ps = myudb_print_fifo->p + (myudb_print_fifo->wptr & (myudb_print_fifo->num - 1)) * myudb_print_fifo->size;
252 ;
253 u8 *pd = ps;
254
255 int ns = str ? strlen(str) : 0;
256 if (ns > myudb_print_fifo->size - 12) {
257 ns = myudb_print_fifo->size - 12;
258 n = 0;
259 }
260 if (n + ns > myudb_print_fifo->size - 12) {
261 n = myudb_print_fifo->size - 12 - ns;
262 }
263
264 int len = n + ns + 2 + 3;
265 *pd++ = len;
266 *pd++ = len >> 8;
267 *pd++ = 0;
268 *pd++ = 0;
269 *pd++ = 0x82;
270 *pd++ = 8;
271
272 *pd++ = 0x22;
273 *pd++ = n;
274 *pd++ = n >> 8;
275
276 while (n--) {
277 *pd++ = *ph++;
278 }
279 while (ns--) {
280 *pd++ = *str++;
281 }
282 myudb_print_fifo->wptr++;
283 core_restore_interrupt(rie);
284 }
285
usb_send_str_u32s(char * str,u32 d0,u32 d1,u32 d2,u32 d3)286 _attribute_ram_code_ void usb_send_str_u32s(char *str, u32 d0, u32 d1, u32 d2, u32 d3)
287 {
288 u32 d[4];
289 d[0] = d0;
290 d[1] = d1;
291 d[2] = d2;
292 d[3] = d3;
293 usb_send_str_data(str, (u8 *)d, 16);
294 }
295
myudb_to_usb()296 _attribute_ram_code_ void myudb_to_usb()
297 {
298 static u16 len = 0;
299 static u8 *p = 0;
300
301 if (usbhw_is_ep_busy(MYUDB_EDP_IN_HCI))
302 return;
303 if (!p && (myudb_print_fifo->wptr != myudb_print_fifo->rptr)) { // first packet
304 p = myudb_print_fifo->p + (myudb_print_fifo->rptr++ & (myudb_print_fifo->num - 1)) * myudb_print_fifo->size;
305 len = p[0] + p[1] * 256;
306 p += 4;
307 }
308 if (p) {
309 int n = len < 64 ? len : 64;
310 usbhw_reset_ep_ptr(MYUDB_EDP_IN_HCI);
311 for (int i = 0; i < n; i++) {
312 usbhw_write_ep_data(MYUDB_EDP_IN_HCI, *p++);
313 }
314 usbhw_data_ep_ack(MYUDB_EDP_IN_HCI);
315 len -= n;
316 if (n < 64) {
317 p = 0;
318 }
319 }
320 }
321
usb_send_str_int(char * str,int w)322 int usb_send_str_int(char *str, int w)
323 {
324 if (myudb_print_fifo_full()) {
325 return -1;
326 }
327 int len;
328
329 u32 rie = core_interrupt_disable();
330 char buf[13], tmp, *p;
331 int u;
332 char symbol = ' ';
333 int int_len = 0;
334 int n = strlen(str);
335 if (n == 0) {
336 return -2;
337 }
338
339 p = buf + 12;
340 *p = '\0';
341 u = w;
342 if (w < 0) {
343 symbol = '-';
344 u = -w;
345 }
346 do { // at least one time..
347 tmp = u % 10;
348 *--p = tmp + '0';
349 u /= 10;
350 int_len++;
351 } while (u);
352
353 u8 *pd = myudb_print_fifo->p + (myudb_print_fifo->wptr & (myudb_print_fifo->num - 1)) * myudb_print_fifo->size;
354 len = n + 2 + 1 + 1 + int_len; // str_len + '0x20' + symbol + int_len
355 *pd++ = len;
356 *pd++ = len >> 8;
357
358 *pd++ = 0;
359 *pd++ = 0;
360 *pd++ = 0x82;
361 *pd++ = 8;
362
363 *pd++ = 0x20;
364 while (n--) {
365 *pd++ = *str++;
366 }
367 *pd++ = symbol;
368 while (int_len--) {
369 *pd++ = *p++;
370 }
371 myudb_print_fifo->wptr++;
372 core_restore_interrupt(rie);
373 return len;
374 }
375
376 #define USB_ENDPOINT_BULK_OUT_FLAG (1 << (MYUDB_EDP_OUT_HCI & 7))
377
myudb_usb_get_packet(u8 * p)378 _attribute_ram_code_ int myudb_usb_get_packet(u8 *p)
379 {
380 if (reg_usb_irq & USB_ENDPOINT_BULK_OUT_FLAG) {
381 // clear interrupt flag
382 reg_usb_irq = USB_ENDPOINT_BULK_OUT_FLAG;
383
384 // read data
385 int n = reg_usb_ep_ptr(MYUDB_EDP_OUT_HCI);
386 reg_usb_ep_ptr(MYUDB_EDP_OUT_HCI) = 0;
387 for (int i = 0; i < n; i++) {
388 p[myudb.cmd_len++] = reg_usb_ep_dat(MYUDB_EDP_OUT_HCI);
389 }
390 reg_usb_ep_ctrl(MYUDB_EDP_OUT_HCI) = 1; // ACK
391 if (n < 64) {
392 n = myudb.cmd_len;
393 myudb.cmd_len = 0;
394 return n;
395 }
396 }
397 return 0;
398 }
399
400 func_myudb_hci_cmd_cb_t myudb_hci_cmd_cb = 0;
401
myudb_register_hci_cb(void * p)402 void myudb_register_hci_cb(void *p)
403 {
404 myudb_hci_cmd_cb = p;
405 }
406
407 func_myudb_hci_cmd_cb_t myudb_hci_debug_cb = 0;
myudb_register_hci_debug_cb(void * p)408 void myudb_register_hci_debug_cb(void *p)
409 {
410 myudb_hci_debug_cb = p;
411 }
412
413 #define MYHCI_FW_DOWNLOAD 0xfe
414 int fw_download = 0;
415
myudb_mem_cmd(u8 * p,int nbyte)416 _attribute_ram_code_ int myudb_mem_cmd(u8 *p, int nbyte)
417 {
418 int len = nbyte;
419 int cmd = p[0];
420 u8 rsp[280];
421
422 int ret = 0;
423
424 ////////////////////////// Memory Read ////////////////////////////////////
425 if (cmd == 0x28 && len >= 8) {
426 usb_send_status_pkt(0x81, 8, p, 12);
427 rsp[0] = 0x29;
428 memcpy(rsp + 1, p + 1, 5);
429 int type = p[1];
430 u32 adr = p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24);
431 int n = p[6] | (p[7] << 8);
432 if (n > 256) {
433 n = 256;
434 }
435
436 if (type == 0) {
437 memcpy(rsp + 6, (void *)(adr | 0), n);
438 } else if (type == 1) {
439 for (int i = 0; i < n; i++) {
440 rsp[i + 6] = analog_read_reg8(adr + i);
441 }
442 } else if (type == 2 || type == 3) {
443 // flash
444 flash_read_page(adr, n, rsp + 6);
445 }
446
447 usb_send_status_pkt(0x82, 8, rsp, n + 6);
448 } else if (cmd == 0x2a && len > 6) {
449 ////////////////////////// Memory Write ////////////////////////////////////
450 usb_send_status_pkt(0x81, 8, p, 12);
451 rsp[0] = 0x2b;
452 memcpy(rsp + 1, p + 1, 16);
453 u8 type = p[1];
454 u32 adr = p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24);
455 int n = len - 6;
456
457 if (type == 0) { // RAM
458 memcpy((void *)adr, p + 6, n);
459 } else if (type == 1) { // Analog Register
460 for (int i = 0; i < n; i++) {
461 analog_write_reg8(adr + i, p[i + 6]);
462 }
463 } else if (type == 2) { // flash
464 if (fw_download && (adr & 0xfff) == 0) {
465 flash_erase_sector(adr);
466 }
467 flash_write_page(adr, n, p + 6);
468 } else if (type == 3) {
469 int nb = p[6];
470 if (n > 1)
471 nb += p[7] << 8;
472 if (n > 2)
473 nb += p[8] << 16;
474 if (n > 3)
475 nb += p[9] << 24;
476
477 if (nb) {
478 for (int i = 0; i < nb; i += 4096) {
479 flash_erase_sector(adr + i);
480 }
481 } else {
482 flash_erase_chip();
483 }
484 } else if (type == MYHCI_FW_DOWNLOAD) {
485 core_interrupt_disable();
486
487 myudb_print_fifo->rptr = myudb_print_fifo->wptr;
488 ret = MYHCI_FW_DOWNLOAD;
489 }
490 usb_send_status_pkt(0x82, 8, rsp, 14);
491 } else {
492 ret = 1;
493 }
494 return ret;
495 }
496
497 u8 buff_usb_cmd[320];
myudb_hci_cmd_from_usb(void)498 _attribute_ram_code_ int myudb_hci_cmd_from_usb(void)
499 {
500 fw_download = 0;
501 do {
502 int n = myudb_usb_get_packet(buff_usb_cmd);
503 if (n) {
504 int r = myudb_mem_cmd(buff_usb_cmd, n);
505 if (r == MYHCI_FW_DOWNLOAD) {
506 fw_download = MYHCI_FW_DOWNLOAD;
507 } else if (buff_usb_cmd[0] == 0x11 && myudb_hci_debug_cb && !fw_download) {
508 myudb_hci_debug_cb(buff_usb_cmd, n);
509 } else if (r && myudb_hci_cmd_cb && !fw_download) {
510 myudb_hci_cmd_cb(buff_usb_cmd, n);
511 }
512 }
513 if (fw_download) {
514 myudb_to_usb();
515 }
516 } while (fw_download);
517
518 return 0;
519 }
520
udb_usb_handle_irq(void)521 void udb_usb_handle_irq(void)
522 {
523 if (1) { // do nothing when in suspend. Maybe not unnecessary
524 u32 irq = usbhw_get_ctrl_ep_irq();
525 if (irq & FLD_CTRL_EP_IRQ_SETUP) {
526 usbhw_clr_ctrl_ep_irq(FLD_CTRL_EP_IRQ_SETUP);
527 myudb_usb_handle_ctl_ep_setup();
528 if (!myudb.tick_sync) {
529 myudb.tick_sync = clock_time() | 1;
530 }
531 }
532 if (irq & FLD_CTRL_EP_IRQ_DATA) {
533 usbhw_clr_ctrl_ep_irq(FLD_CTRL_EP_IRQ_DATA);
534 myudb_usb_handle_ctl_ep_data();
535 }
536 if (irq & FLD_CTRL_EP_IRQ_STA) {
537 usbhw_clr_ctrl_ep_irq(FLD_CTRL_EP_IRQ_STA);
538 myudb_usb_handle_ctl_ep_status();
539 }
540
541 if (reg_usb_irq_mask & FLD_USB_IRQ_RESET_O) {
542 reg_usb_irq_mask |= FLD_USB_IRQ_RESET_O; // Clear USB reset flag
543 myudb_usb_bulkout_ready();
544 }
545 myudb.stall = 0;
546 }
547
548 myudb_to_usb();
549
550 myudb_hci_cmd_from_usb();
551
552 if (myudb.tick_sync && clock_time_exceed(myudb.tick_sync, 10000)) {
553 myudb.tick_sync = clock_time() | 1;
554 log_sync(SL_STACK_EN);
555 }
556 }
557
myudb_usb_bulkout_ready(void)558 void myudb_usb_bulkout_ready(void)
559 {
560 reg_usb_ep_ctrl(MYUDB_EDP_OUT_HCI) = FLD_EP_DAT_ACK;
561 }
562
myudb_usb_init(u16 id,void * p_print)563 void myudb_usb_init(u16 id, void *p_print)
564 {
565 if (!myudb_print_fifo) {
566 myudb_print_fifo = p_print;
567 }
568
569 myudb_print_fifo->wptr = myudb_print_fifo->rptr = 0;
570
571 memset(&myudb, 0, sizeof(myudb));
572
573 myudb.id = id;
574 reg_usb_ep_max_size = (128 >> 2);
575 reg_usb_ep8_send_thre = 0x40;
576 reg_usb_ep8_send_max = 128 >> 3;
577 reg_usb_ep_buf_addr(MYUDB_EDP_IN_HCI) = 128;
578 reg_usb_ep_buf_addr(MYUDB_EDP_OUT_HCI) = 192;
579 reg_usb_ep_buf_addr(MYUDB_EDP_IN_VCD) = 0;
580 reg_usb_ep8_fifo_mode = 1;
581 reg_usb_mdev &= ~BIT(3); // vendor command: bRequest[7] = 0
582
583 usbhw_enable_manual_interrupt(FLD_CTRL_EP_AUTO_STD | FLD_CTRL_EP_AUTO_DESC);
584
585 myudb_usb_bulkout_ready();
586 usbhw_data_ep_ack(MYUDB_EDP_IN_HCI); // add log 1st log info
587 }
588
usb_send_upper_tester_result(u8 err)589 _attribute_ram_code_ void usb_send_upper_tester_result(u8 err)
590 {
591 u32 rie = core_interrupt_disable();
592 u8 *ps = myudb_print_fifo->p + (myudb_print_fifo->wptr & (myudb_print_fifo->num - 1)) * myudb_print_fifo->size;
593 ;
594
595 *((u32 *)ps) = 3;
596 u8 *pd = (ps + 4);
597
598 *pd++ = 0x04; // HCI_TYPE_EVENT;
599 *pd++ = 0xF0; // HCI_EVT_HT_ERR_FLAG;
600 *pd++ = err;
601
602 myudb_print_fifo->wptr++;
603 core_restore_interrupt(rie);
604 }
605
606 #endif // ending of #if(VCD_EN || DUMP_STR_EN)
607