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