1 /*
2 * Copyright (c) 2024, sakumisu
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include "netif/etharp.h"
7 #include "lwip/netif.h"
8 #include "lwip/pbuf.h"
9 #include "lwip/tcpip.h"
10 #if LWIP_DHCP
11 #include "lwip/dhcp.h"
12 #include "lwip/prot/dhcp.h"
13 #endif
14
15 #include <rtthread.h>
16 #include <rtdevice.h>
17 #include <netif/ethernetif.h>
18
19 #include "usbh_core.h"
20
21 #include "lwip/opt.h"
22
23 #ifndef RT_USING_LWIP212
24 #error must enable RT_USING_LWIP212
25 #endif
26
27 #ifndef LWIP_NO_RX_THREAD
28 #error must enable LWIP_NO_RX_THREAD, we do not use rtthread eth rx thread
29 #endif
30
31 #ifndef LWIP_NO_TX_THREAD
32 #warning suggest you to enable LWIP_NO_TX_THREAD, we do not use rtthread eth tx thread
33 #endif
34
35 #if LWIP_TCPIP_CORE_LOCKING_INPUT != 1
36 #warning suggest you to set LWIP_TCPIP_CORE_LOCKING_INPUT to 1, usb handles eth input with own thread
37 #endif
38
39 #if LWIP_TCPIP_CORE_LOCKING != 1
40 #error must set LWIP_TCPIP_CORE_LOCKING to 1
41 #endif
42
43 #if PBUF_POOL_BUFSIZE < 1600
44 #error PBUF_POOL_BUFSIZE must be larger than 1600
45 #endif
46
47 #if RT_LWIP_TCPTHREAD_STACKSIZE < 2048
48 #error RT_LWIP_TCPTHREAD_STACKSIZE must be >= 2048
49 #endif
50
51 // #define CONFIG_USBHOST_PLATFORM_CDC_ECM
52 // #define CONFIG_USBHOST_PLATFORM_CDC_RNDIS
53 // #define CONFIG_USBHOST_PLATFORM_CDC_NCM
54 // #define CONFIG_USBHOST_PLATFORM_ASIX
55 // #define CONFIG_USBHOST_PLATFORM_RTL8152
56
usbh_lwip_eth_output_common(struct pbuf * p,uint8_t * buf)57 void usbh_lwip_eth_output_common(struct pbuf *p, uint8_t *buf)
58 {
59 struct pbuf *q;
60 uint8_t *buffer;
61
62 buffer = buf;
63 for (q = p; q != NULL; q = q->next) {
64 usb_memcpy(buffer, q->payload, q->len);
65 buffer += q->len;
66 }
67 }
68
usbh_lwip_eth_input_common(struct netif * netif,uint8_t * buf,uint32_t len)69 void usbh_lwip_eth_input_common(struct netif *netif, uint8_t *buf, uint32_t len)
70 {
71 #if LWIP_TCPIP_CORE_LOCKING_INPUT
72 pbuf_type type = PBUF_REF;
73 #else
74 pbuf_type type = PBUF_POOL;
75 #endif
76 err_t err;
77 struct pbuf *p;
78
79 p = pbuf_alloc(PBUF_RAW, len, type);
80 if (p != NULL) {
81 #if LWIP_TCPIP_CORE_LOCKING_INPUT
82 p->payload = buf;
83 #else
84 usb_memcpy(p->payload, buf, len);
85 #endif
86 err = netif->input(p, netif);
87 if (err != ERR_OK) {
88 pbuf_free(p);
89 }
90 } else {
91 USB_LOG_ERR("No memory to alloc pbuf\r\n");
92 }
93 }
94
95 #ifdef CONFIG_USBHOST_PLATFORM_CDC_ECM
96 #include "usbh_cdc_ecm.h"
97
98 static struct eth_device g_cdc_ecm_dev;
99
rt_usbh_cdc_ecm_control(rt_device_t dev,int cmd,void * args)100 static rt_err_t rt_usbh_cdc_ecm_control(rt_device_t dev, int cmd, void *args)
101 {
102 struct usbh_cdc_ecm *cdc_ecm_class = (struct usbh_cdc_ecm *)dev->user_data;
103
104 switch (cmd) {
105 case NIOCTL_GADDR:
106
107 /* get mac address */
108 if (args)
109 rt_memcpy(args, cdc_ecm_class->mac, 6);
110 else
111 return -RT_ERROR;
112
113 break;
114
115 default:
116 break;
117 }
118
119 return RT_EOK;
120 }
121
rt_usbh_cdc_ecm_eth_tx(rt_device_t dev,struct pbuf * p)122 static rt_err_t rt_usbh_cdc_ecm_eth_tx(rt_device_t dev, struct pbuf *p)
123 {
124 int ret;
125 (void)dev;
126
127 usbh_lwip_eth_output_common(p, usbh_cdc_ecm_get_eth_txbuf());
128 ret = usbh_cdc_ecm_eth_output(p->tot_len);
129 if (ret < 0) {
130 return -RT_ERROR;
131 } else {
132 return RT_EOK;
133 }
134 }
135
usbh_cdc_ecm_eth_input(uint8_t * buf,uint32_t buflen)136 void usbh_cdc_ecm_eth_input(uint8_t *buf, uint32_t buflen)
137 {
138 usbh_lwip_eth_input_common(g_cdc_ecm_dev.netif, buf, buflen);
139 }
140
usbh_cdc_ecm_run(struct usbh_cdc_ecm * cdc_ecm_class)141 void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
142 {
143 memset(&g_cdc_ecm_dev, 0, sizeof(struct eth_device));
144
145 g_cdc_ecm_dev.parent.control = rt_usbh_cdc_ecm_control;
146 g_cdc_ecm_dev.eth_rx = NULL;
147 g_cdc_ecm_dev.eth_tx = rt_usbh_cdc_ecm_eth_tx;
148 g_cdc_ecm_dev.parent.user_data = cdc_ecm_class;
149
150 eth_device_init(&g_cdc_ecm_dev, "u0");
151 eth_device_linkchange(&g_cdc_ecm_dev, RT_TRUE);
152
153 usb_osal_thread_create("usbh_cdc_ecm_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_cdc_ecm_rx_thread, NULL);
154 }
155
usbh_cdc_ecm_stop(struct usbh_cdc_ecm * cdc_ecm_class)156 void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
157 {
158 (void)cdc_ecm_class;
159
160 eth_device_deinit(&g_cdc_ecm_dev);
161 }
162 #endif
163
164 #ifdef CONFIG_USBHOST_PLATFORM_CDC_RNDIS
165 #include "usbh_rndis.h"
166
167 static struct eth_device g_rndis_dev;
168
169 static rt_timer_t keep_timer = RT_NULL;
170
rndis_dev_keepalive_timeout(void * parameter)171 static void rndis_dev_keepalive_timeout(void *parameter)
172 {
173 struct usbh_rndis *rndis_class = (struct usbh_rndis *)parameter;
174 usbh_rndis_keepalive(rndis_class);
175 }
176
timer_init(struct usbh_rndis * rndis_class)177 static void timer_init(struct usbh_rndis *rndis_class)
178 {
179 keep_timer = rt_timer_create("keep",
180 rndis_dev_keepalive_timeout,
181 rndis_class,
182 5000,
183 RT_TIMER_FLAG_PERIODIC |
184 RT_TIMER_FLAG_SOFT_TIMER);
185
186 rt_timer_start(keep_timer);
187 }
188
rt_usbh_rndis_control(rt_device_t dev,int cmd,void * args)189 static rt_err_t rt_usbh_rndis_control(rt_device_t dev, int cmd, void *args)
190 {
191 struct usbh_rndis *rndis_class = (struct usbh_rndis *)dev->user_data;
192
193 switch (cmd) {
194 case NIOCTL_GADDR:
195
196 /* get mac address */
197 if (args)
198 rt_memcpy(args, rndis_class->mac, 6);
199 else
200 return -RT_ERROR;
201
202 break;
203
204 default:
205 break;
206 }
207
208 return RT_EOK;
209 }
210
rt_usbh_rndis_eth_tx(rt_device_t dev,struct pbuf * p)211 static rt_err_t rt_usbh_rndis_eth_tx(rt_device_t dev, struct pbuf *p)
212 {
213 int ret;
214 (void)dev;
215
216 usbh_lwip_eth_output_common(p, usbh_rndis_get_eth_txbuf());
217 ret = usbh_rndis_eth_output(p->tot_len);
218 if (ret < 0) {
219 return -RT_ERROR;
220 } else {
221 return RT_EOK;
222 }
223 }
224
usbh_rndis_eth_input(uint8_t * buf,uint32_t buflen)225 void usbh_rndis_eth_input(uint8_t *buf, uint32_t buflen)
226 {
227 usbh_lwip_eth_input_common(g_rndis_dev.netif, buf, buflen);
228 }
229
usbh_rndis_run(struct usbh_rndis * rndis_class)230 void usbh_rndis_run(struct usbh_rndis *rndis_class)
231 {
232 memset(&g_rndis_dev, 0, sizeof(struct eth_device));
233
234 g_rndis_dev.parent.control = rt_usbh_rndis_control;
235 g_rndis_dev.eth_rx = NULL;
236 g_rndis_dev.eth_tx = rt_usbh_rndis_eth_tx;
237 g_rndis_dev.parent.user_data = rndis_class;
238
239 eth_device_init(&g_rndis_dev, "u2");
240 eth_device_linkchange(&g_rndis_dev, RT_TRUE);
241
242 usb_osal_thread_create("usbh_rndis_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_rndis_rx_thread, NULL);
243 //timer_init(rndis_class);
244 }
245
usbh_rndis_stop(struct usbh_rndis * rndis_class)246 void usbh_rndis_stop(struct usbh_rndis *rndis_class)
247 {
248 (void)rndis_class;
249
250 eth_device_deinit(&g_rndis_dev);
251 // rt_timer_stop(keep_timer);
252 // rt_timer_delete(keep_timer);
253 }
254 #endif
255
256 #ifdef CONFIG_USBHOST_PLATFORM_CDC_NCM
257 #include "usbh_cdc_ncm.h"
258
259 static struct eth_device g_cdc_ncm_dev;
260
rt_usbh_cdc_ncm_control(rt_device_t dev,int cmd,void * args)261 static rt_err_t rt_usbh_cdc_ncm_control(rt_device_t dev, int cmd, void *args)
262 {
263 struct usbh_cdc_ncm *cdc_ncm_class = (struct usbh_cdc_ncm *)dev->user_data;
264
265 switch (cmd) {
266 case NIOCTL_GADDR:
267
268 /* get mac address */
269 if (args)
270 rt_memcpy(args, cdc_ncm_class->mac, 6);
271 else
272 return -RT_ERROR;
273
274 break;
275
276 default:
277 break;
278 }
279
280 return RT_EOK;
281 }
282
rt_usbh_cdc_ncm_eth_tx(rt_device_t dev,struct pbuf * p)283 static rt_err_t rt_usbh_cdc_ncm_eth_tx(rt_device_t dev, struct pbuf *p)
284 {
285 int ret;
286 (void)dev;
287
288 usbh_lwip_eth_output_common(p, usbh_cdc_ncm_get_eth_txbuf());
289 ret = usbh_cdc_ncm_eth_output(p->tot_len);
290 if (ret < 0) {
291 return -RT_ERROR;
292 } else {
293 return RT_EOK;
294 }
295 }
296
usbh_cdc_ncm_eth_input(uint8_t * buf,uint32_t buflen)297 void usbh_cdc_ncm_eth_input(uint8_t *buf, uint32_t buflen)
298 {
299 usbh_lwip_eth_input_common(g_cdc_ncm_dev.netif, buf, buflen);
300 }
301
usbh_cdc_ncm_run(struct usbh_cdc_ncm * cdc_ncm_class)302 void usbh_cdc_ncm_run(struct usbh_cdc_ncm *cdc_ncm_class)
303 {
304 memset(&g_cdc_ncm_dev, 0, sizeof(struct eth_device));
305
306 g_cdc_ncm_dev.parent.control = rt_usbh_cdc_ncm_control;
307 g_cdc_ncm_dev.eth_rx = NULL;
308 g_cdc_ncm_dev.eth_tx = rt_usbh_cdc_ncm_eth_tx;
309 g_cdc_ncm_dev.parent.user_data = cdc_ncm_class;
310
311 eth_device_init(&g_cdc_ncm_dev, "u1");
312 eth_device_linkchange(&g_cdc_ncm_dev, RT_TRUE);
313
314 usb_osal_thread_create("usbh_cdc_ncm_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_cdc_ncm_rx_thread, NULL);
315 }
316
usbh_cdc_ncm_stop(struct usbh_cdc_ncm * cdc_ncm_class)317 void usbh_cdc_ncm_stop(struct usbh_cdc_ncm *cdc_ncm_class)
318 {
319 (void)cdc_ncm_class;
320
321 eth_device_deinit(&g_cdc_ncm_dev);
322 }
323 #endif
324
325 #ifdef CONFIG_USBHOST_PLATFORM_ASIX
326 #include "usbh_asix.h"
327
328 static struct eth_device g_asix_dev;
329
rt_usbh_asix_control(rt_device_t dev,int cmd,void * args)330 static rt_err_t rt_usbh_asix_control(rt_device_t dev, int cmd, void *args)
331 {
332 struct usbh_asix *asix_class = (struct usbh_asix *)dev->user_data;
333
334 switch (cmd) {
335 case NIOCTL_GADDR:
336
337 /* get mac address */
338 if (args)
339 rt_memcpy(args, asix_class->mac, 6);
340 else
341 return -RT_ERROR;
342
343 break;
344
345 default:
346 break;
347 }
348
349 return RT_EOK;
350 }
351
rt_usbh_asix_eth_tx(rt_device_t dev,struct pbuf * p)352 static rt_err_t rt_usbh_asix_eth_tx(rt_device_t dev, struct pbuf *p)
353 {
354 int ret;
355 (void)dev;
356
357 usbh_lwip_eth_output_common(p, usbh_asix_get_eth_txbuf());
358 ret = usbh_asix_eth_output(p->tot_len);
359 if (ret < 0) {
360 return -RT_ERROR;
361 } else {
362 return RT_EOK;
363 }
364 }
365
usbh_asix_eth_input(uint8_t * buf,uint32_t buflen)366 void usbh_asix_eth_input(uint8_t *buf, uint32_t buflen)
367 {
368 usbh_lwip_eth_input_common(g_asix_dev.netif, buf, buflen);
369 }
370
usbh_asix_run(struct usbh_asix * asix_class)371 void usbh_asix_run(struct usbh_asix *asix_class)
372 {
373 memset(&g_asix_dev, 0, sizeof(struct eth_device));
374
375 g_asix_dev.parent.control = rt_usbh_asix_control;
376 g_asix_dev.eth_rx = NULL;
377 g_asix_dev.eth_tx = rt_usbh_asix_eth_tx;
378 g_asix_dev.parent.user_data = asix_class;
379
380 eth_device_init(&g_asix_dev, "u3");
381 eth_device_linkchange(&g_asix_dev, RT_TRUE);
382
383 usb_osal_thread_create("usbh_asix_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_asix_rx_thread, NULL);
384 }
385
usbh_asix_stop(struct usbh_asix * asix_class)386 void usbh_asix_stop(struct usbh_asix *asix_class)
387 {
388 (void)asix_class;
389
390 eth_device_deinit(&g_asix_dev);
391 }
392 #endif
393
394 #ifdef CONFIG_USBHOST_PLATFORM_RTL8152
395 #include "usbh_rtl8152.h"
396
397 static struct eth_device g_rtl8152_dev;
398
rt_usbh_rtl8152_control(rt_device_t dev,int cmd,void * args)399 static rt_err_t rt_usbh_rtl8152_control(rt_device_t dev, int cmd, void *args)
400 {
401 struct usbh_rtl8152 *rtl8152_class = (struct usbh_rtl8152 *)dev->user_data;
402
403 switch (cmd) {
404 case NIOCTL_GADDR:
405
406 /* get mac address */
407 if (args)
408 rt_memcpy(args, rtl8152_class->mac, 6);
409 else
410 return -RT_ERROR;
411
412 break;
413
414 default:
415 break;
416 }
417
418 return RT_EOK;
419 }
420
rt_usbh_rtl8152_eth_tx(rt_device_t dev,struct pbuf * p)421 static rt_err_t rt_usbh_rtl8152_eth_tx(rt_device_t dev, struct pbuf *p)
422 {
423 int ret;
424 (void)dev;
425
426 usbh_lwip_eth_output_common(p, usbh_rtl8152_get_eth_txbuf());
427 ret = usbh_rtl8152_eth_output(p->tot_len);
428 if (ret < 0) {
429 return -RT_ERROR;
430 } else {
431 return RT_EOK;
432 }
433 }
434
usbh_rtl8152_eth_input(uint8_t * buf,uint32_t buflen)435 void usbh_rtl8152_eth_input(uint8_t *buf, uint32_t buflen)
436 {
437 usbh_lwip_eth_input_common(g_rtl8152_dev.netif, buf, buflen);
438 }
439
usbh_rtl8152_run(struct usbh_rtl8152 * rtl8152_class)440 void usbh_rtl8152_run(struct usbh_rtl8152 *rtl8152_class)
441 {
442 memset(&g_rtl8152_dev, 0, sizeof(struct eth_device));
443
444 g_rtl8152_dev.parent.control = rt_usbh_rtl8152_control;
445 g_rtl8152_dev.eth_rx = NULL;
446 g_rtl8152_dev.eth_tx = rt_usbh_rtl8152_eth_tx;
447 g_rtl8152_dev.parent.user_data = rtl8152_class;
448
449 eth_device_init(&g_rtl8152_dev, "u4");
450 eth_device_linkchange(&g_rtl8152_dev, RT_TRUE);
451
452 usb_osal_thread_create("usbh_rtl8152_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_rtl8152_rx_thread, NULL);
453 }
454
usbh_rtl8152_stop(struct usbh_rtl8152 * rtl8152_class)455 void usbh_rtl8152_stop(struct usbh_rtl8152 *rtl8152_class)
456 {
457 (void)rtl8152_class;
458
459 eth_device_deinit(&g_rtl8152_dev);
460 }
461 #endif
462