1 /*
2  * Copyright (c) 2025, A_Stupid_Liberal
3  * Copyright (c) 2025, sakumisu
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include "usbd_core.h"
9 #include "usbd_cdc_acm.h"
10 #include "general.h"
11 #include "gdb_if.h"
12 #include "hpm_l1c_drv.h"
13 
14 #define CDC_IN_EP  0x81
15 #define CDC_OUT_EP 0x01
16 #define CDC_INT_EP 0x83
17 
18 #define CDC_MAX_PACKET_SIZE 512
19 
20 #ifdef CONFIG_USB_HS
21 #if CDC_MAX_PACKET_SIZE != 512
22 #error "CDC_MAX_PACKET_SIZE must be 512 in hs"
23 #endif
24 #else
25 #if CDC_MAX_PACKET_SIZE != 64
26 #error "CDC_MAX_PACKET_SIZE must be 64 in fs"
27 #endif
28 #endif
29 
30 /*!< config descriptor size */
31 #define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN)
32 
33 static const uint8_t device_descriptor[] = {
34     USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
35 };
36 
37 static const uint8_t config_descriptor_hs[] = {
38     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
39     CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
40 };
41 
42 static const uint8_t config_descriptor_fs[] = {
43     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
44     CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
45 };
46 
47 static const uint8_t device_quality_descriptor[] = {
48     USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01),
49 };
50 
51 static const uint8_t other_speed_config_descriptor_hs[] = {
52     USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
53     CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
54 };
55 
56 static const uint8_t other_speed_config_descriptor_fs[] = {
57     USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
58     CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
59 };
60 
61 static const char *string_descriptors[] = {
62     (const char[]){ 0x09, 0x04 }, /* Langid */
63     "CherryUSB",                  /* Manufacturer */
64     "CherryUSB BMP DEMO",         /* Product */
65     "20250501",                   /* Serial Number */
66 };
67 
device_descriptor_callback(uint8_t speed)68 static const uint8_t *device_descriptor_callback(uint8_t speed)
69 {
70     (void)speed;
71 
72     return device_descriptor;
73 }
74 
config_descriptor_callback(uint8_t speed)75 static const uint8_t *config_descriptor_callback(uint8_t speed)
76 {
77     if (speed == USB_SPEED_HIGH) {
78         return config_descriptor_hs;
79     } else if (speed == USB_SPEED_FULL) {
80         return config_descriptor_fs;
81     } else {
82         return NULL;
83     }
84 }
85 
device_quality_descriptor_callback(uint8_t speed)86 static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
87 {
88     (void)speed;
89 
90     return device_quality_descriptor;
91 }
92 
other_speed_config_descriptor_callback(uint8_t speed)93 static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
94 {
95     if (speed == USB_SPEED_HIGH) {
96         return other_speed_config_descriptor_hs;
97     } else if (speed == USB_SPEED_FULL) {
98         return other_speed_config_descriptor_fs;
99     } else {
100         return NULL;
101     }
102 }
103 
string_descriptor_callback(uint8_t speed,uint8_t index)104 static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
105 {
106     (void)speed;
107 
108     if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
109         return NULL;
110     }
111     return string_descriptors[index];
112 }
113 
114 const struct usb_descriptor cdc_descriptor = {
115     .device_descriptor_callback = device_descriptor_callback,
116     .config_descriptor_callback = config_descriptor_callback,
117     .device_quality_descriptor_callback = device_quality_descriptor_callback,
118     .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
119     .string_descriptor_callback = string_descriptor_callback,
120 };
121 
122 #define USB_RX_BUFFER_SIZE 16384
123 __attribute__((aligned(64))) uint8_t g_usb_write_buffer[USB_RX_BUFFER_SIZE];
124 __attribute__((aligned(64))) uint8_t g_usb_read_buffer[USB_RX_BUFFER_SIZE];
125 
126 volatile bool g_usb_tx_busy_flag = false;
127 volatile uint32_t g_usb_tx_count = 0;
128 volatile uint32_t g_usb_rx_count = 0;
129 volatile uint32_t g_usb_rx_offset = 0;
130 
usbd_event_handler(uint8_t busid,uint8_t event)131 static void usbd_event_handler(uint8_t busid, uint8_t event)
132 {
133     switch (event) {
134         case USBD_EVENT_RESET:
135             g_usb_tx_busy_flag = false;
136             g_usb_rx_offset = 0;
137             g_usb_rx_count = 0;
138             g_usb_tx_count = 0;
139             break;
140         case USBD_EVENT_CONNECTED:
141             break;
142         case USBD_EVENT_DISCONNECTED:
143             g_usb_tx_busy_flag = false;
144             g_usb_rx_offset = 0;
145             g_usb_rx_count = 0;
146             g_usb_tx_count = 0;
147             break;
148         case USBD_EVENT_RESUME:
149             break;
150         case USBD_EVENT_SUSPEND:
151             break;
152         case USBD_EVENT_CONFIGURED:
153             /* setup first out ep read transfer */
154             usbd_ep_start_read(busid, CDC_OUT_EP, g_usb_read_buffer, USB_RX_BUFFER_SIZE);
155             break;
156         case USBD_EVENT_SET_REMOTE_WAKEUP:
157             break;
158         case USBD_EVENT_CLR_REMOTE_WAKEUP:
159             break;
160 
161         default:
162             break;
163     }
164 }
165 
usbd_cdc_acm_bulk_out(uint8_t busid,uint8_t ep,uint32_t nbytes)166 void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
167 {
168     (void)busid;
169 
170     usb_dcache_invalidate((uint32_t)g_usb_read_buffer, USB_ALIGN_UP(nbytes, 64));
171     g_usb_rx_count = nbytes;
172     g_usb_rx_offset = 0;
173 }
174 
usbd_cdc_acm_bulk_in(uint8_t busid,uint8_t ep,uint32_t nbytes)175 void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
176 {
177     (void)busid;
178 
179     if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
180         /* send zlp */
181         usbd_ep_start_write(busid, CDC_IN_EP, NULL, 0);
182     } else {
183         g_usb_tx_busy_flag = false;
184     }
185 }
186 
187 /*!< endpoint call back */
188 struct usbd_endpoint cdc_out_ep = {
189     .ep_addr = CDC_OUT_EP,
190     .ep_cb = usbd_cdc_acm_bulk_out
191 };
192 
193 struct usbd_endpoint cdc_in_ep = {
194     .ep_addr = CDC_IN_EP,
195     .ep_cb = usbd_cdc_acm_bulk_in
196 };
197 
198 static struct usbd_interface intf0;
199 static struct usbd_interface intf1;
200 
201 /* function ------------------------------------------------------------------*/
202 
cdc_acm_init(uint8_t busid,uint32_t reg_base)203 void cdc_acm_init(uint8_t busid, uint32_t reg_base)
204 {
205     usbd_desc_register(busid, &cdc_descriptor);
206     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
207     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
208     usbd_add_endpoint(busid, &cdc_out_ep);
209     usbd_add_endpoint(busid, &cdc_in_ep);
210     usbd_initialize(busid, reg_base, usbd_event_handler);
211 }
212 
213 volatile bool dtr_enable = false;
214 
usbd_cdc_acm_set_dtr(uint8_t busid,uint8_t intf,bool dtr)215 void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
216 {
217     if (dtr) {
218         //printf("remote attach \r\n");
219     } else {
220         //printf("remote detach \r\n");
221     }
222 
223     dtr_enable = dtr;
224 }
225 
gdb_if_putchar(const char c,const bool flush)226 void gdb_if_putchar(const char c, const bool flush)
227 {
228     g_usb_write_buffer[g_usb_tx_count++] = c;
229 
230     if (flush) {
231         g_usb_tx_busy_flag = true;
232         usb_dcache_clean((uint32_t)g_usb_write_buffer, USB_ALIGN_UP(g_usb_tx_count, 64));
233         usbd_ep_start_write(0, CDC_IN_EP, (uint8_t *)core_local_mem_to_sys_address(0, (uint32_t)g_usb_write_buffer), g_usb_tx_count);
234         while (g_usb_tx_busy_flag) {
235         }
236         g_usb_tx_count = 0;
237     }
238 }
239 
gdb_if_flush(const bool force)240 void gdb_if_flush(const bool force)
241 {
242     g_usb_tx_busy_flag = true;
243     usb_dcache_clean((uint32_t)g_usb_write_buffer, USB_ALIGN_UP(g_usb_tx_count, 64));
244     usbd_ep_start_write(0, CDC_IN_EP, (uint8_t *)core_local_mem_to_sys_address(0, (uint32_t)g_usb_write_buffer), g_usb_tx_count);
245     while (g_usb_tx_busy_flag) {
246     }
247     g_usb_tx_count = 0;
248 }
249 
__gdb_if_getchar(void)250 static int __gdb_if_getchar(void)
251 {
252     if (dtr_enable == false) {
253         return '\04';
254     }
255 
256     if (g_usb_rx_count > 0) {
257         if (g_usb_rx_offset < g_usb_rx_count) {
258             return g_usb_read_buffer[g_usb_rx_offset++];
259         } else {
260             g_usb_rx_count = 0;
261             /* setup first out ep read transfer */
262             usbd_ep_start_read(0, CDC_OUT_EP, g_usb_read_buffer, USB_RX_BUFFER_SIZE);
263             return -1;
264         }
265     } else {
266         return -1;
267     }
268 }
269 
gdb_if_getchar(void)270 char gdb_if_getchar(void)
271 {
272     int c;
273 
274     while ((c = __gdb_if_getchar()) == -1) {
275     }
276 
277     return (char)c;
278 }
279 
gdb_if_getchar_to(const uint32_t timeout)280 char gdb_if_getchar_to(const uint32_t timeout)
281 {
282     int c = 0;
283     platform_timeout_s receive_timeout;
284     platform_timeout_set(&receive_timeout, timeout);
285 
286     /* Wait while we need more data or until the timeout expires */
287     while (!platform_timeout_is_expired(&receive_timeout)) {
288         c = __gdb_if_getchar();
289         if (c != -1) {
290             return (char)c;
291         }
292     }
293     return -1;
294 }