• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "usbd_core.h"
7 #include "usbd_cdc_ecm.h"
8 
9 #define CDC_ECM_OUT_EP_IDX 0
10 #define CDC_ECM_IN_EP_IDX   1
11 #define CDC_ECM_INT_EP_IDX  2
12 
13 /* Describe EndPoints configuration */
14 static struct usbd_endpoint cdc_ecm_ep_data[3];
15 
16 #ifdef CONFIG_USB_HS
17 #define CDC_ECM_MAX_PACKET_SIZE 512
18 #else
19 #define CDC_ECM_MAX_PACKET_SIZE 64
20 #endif
21 
22 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
23 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
24 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_notify_buf[16];
25 
26 volatile uint8_t *g_cdc_ecm_rx_data_buffer = NULL;
27 volatile uint32_t g_cdc_ecm_rx_data_length = 0;
28 volatile uint32_t g_cdc_ecm_tx_data_length = 0;
29 
30 static volatile uint8_t g_current_net_status = 0;
31 static volatile uint8_t g_cmd_intf = 0;
32 
33 static uint32_t g_connect_speed_table[2] = { CDC_ECM_CONNECT_SPEED_UPSTREAM,
34                                              CDC_ECM_CONNECT_SPEED_DOWNSTREAM };
35 
usbd_cdc_ecm_send_notify(uint8_t notifycode,uint8_t value,uint32_t * speed)36 void usbd_cdc_ecm_send_notify(uint8_t notifycode, uint8_t value, uint32_t *speed)
37 {
38     struct cdc_ecm_notification *notify = (struct cdc_ecm_notification *)g_cdc_ecm_notify_buf;
39     uint8_t bytes2send = 0;
40 
41     notify->bmRequestType = CDC_ECM_BMREQUEST_TYPE_ECM;
42     notify->bNotificationType = notifycode;
43 
44     switch (notifycode) {
45         case CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION:
46             notify->wValue = value;
47             notify->wIndex = g_cmd_intf;
48             notify->wLength = 0U;
49 
50             for (uint8_t i = 0U; i < 8U; i++) {
51                 notify->data[i] = 0U;
52             }
53             bytes2send = 8U;
54             break;
55         case CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE:
56             notify->wValue = 0U;
57             notify->wIndex = g_cmd_intf;
58             notify->wLength = 0U;
59             for (uint8_t i = 0U; i < 8U; i++) {
60                 notify->data[i] = 0U;
61             }
62             bytes2send = 8U;
63             break;
64         case CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE:
65             notify->wValue = 0U;
66             notify->wIndex = g_cmd_intf;
67             notify->wLength = 0x0008U;
68             bytes2send = 16U;
69 
70             memcpy(notify->data, speed, 8);
71             break;
72 
73         default:
74             break;
75     }
76 
77     if (bytes2send) {
78         usbd_ep_start_write(cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr, g_cdc_ecm_notify_buf, bytes2send);
79     }
80 }
81 
cdc_ecm_class_interface_request_handler(struct usb_setup_packet * setup,uint8_t ** data,uint32_t * len)82 static int cdc_ecm_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
83 {
84     USB_LOG_DBG("CDC ECM Class request: "
85                 "bRequest 0x%02x\r\n",
86                 setup->bRequest);
87 
88     g_cmd_intf = LO_BYTE(setup->wIndex);
89 
90     switch (setup->bRequest) {
91         case CDC_REQUEST_SET_ETHERNET_PACKET_FILTER:
92             /* bit0 Promiscuous
93              * bit1 ALL Multicast
94              * bit2 Directed
95              * bit3 Broadcast
96              * bit4 Multicast
97             */
98             if (g_current_net_status == 0) {
99                 g_current_net_status = 1;
100                 usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, NULL);
101             }
102 
103             break;
104         default:
105             USB_LOG_WRN("Unhandled CDC ECM Class bRequest 0x%02x\r\n", setup->bRequest);
106             return -1;
107     }
108 
109     return 0;
110 }
111 
cdc_ecm_notify_handler(uint8_t event,void * arg)112 void cdc_ecm_notify_handler(uint8_t event, void *arg)
113 {
114     switch (event) {
115         case USBD_EVENT_RESET:
116             g_current_net_status = 0;
117             g_cdc_ecm_rx_data_length = 0;
118             g_cdc_ecm_tx_data_length = 0;
119             g_cdc_ecm_rx_data_buffer = NULL;
120             break;
121         case USBD_EVENT_CONFIGURED:
122             usbd_ep_start_read(cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], CDC_ECM_MAX_PACKET_SIZE);
123             break;
124 
125         default:
126             break;
127     }
128 }
129 
cdc_ecm_bulk_out(uint8_t ep,uint32_t nbytes)130 void cdc_ecm_bulk_out(uint8_t ep, uint32_t nbytes)
131 {
132     g_cdc_ecm_rx_data_length += nbytes;
133 
134     if (nbytes < CDC_ECM_MAX_PACKET_SIZE) {
135         g_cdc_ecm_rx_data_buffer = g_cdc_ecm_rx_buffer;
136         usbd_cdc_ecm_data_recv_done();
137     } else {
138         usbd_ep_start_read(ep, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], CDC_ECM_MAX_PACKET_SIZE);
139     }
140 }
141 
cdc_ecm_bulk_in(uint8_t ep,uint32_t nbytes)142 void cdc_ecm_bulk_in(uint8_t ep, uint32_t nbytes)
143 {
144     if ((nbytes % CDC_ECM_MAX_PACKET_SIZE) == 0 && nbytes) {
145         /* send zlp */
146         usbd_ep_start_write(ep, NULL, 0);
147     } else {
148         g_cdc_ecm_tx_data_length = 0;
149     }
150 }
151 
cdc_ecm_int_in(uint8_t ep,uint32_t nbytes)152 void cdc_ecm_int_in(uint8_t ep, uint32_t nbytes)
153 {
154     if (g_current_net_status == 1) {
155         g_current_net_status = 2;
156         usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, g_connect_speed_table);
157     }
158 }
159 
160 #ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
usbd_cdc_ecm_eth_rx(void)161 struct pbuf *usbd_cdc_ecm_eth_rx(void)
162 {
163     struct pbuf *p;
164 
165     if (g_cdc_ecm_rx_data_buffer == NULL) {
166         return NULL;
167     }
168     p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_data_length, PBUF_POOL);
169     if (p == NULL) {
170         return NULL;
171     }
172     memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length);
173     p->len = g_cdc_ecm_rx_data_length;
174 
175     USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_data_length);
176     g_cdc_ecm_rx_data_length = 0;
177     g_cdc_ecm_rx_data_buffer = NULL;
178     usbd_ep_start_read(cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, g_cdc_ecm_rx_buffer, CDC_ECM_MAX_PACKET_SIZE);
179 
180     return p;
181 }
182 
usbd_cdc_ecm_eth_tx(struct pbuf * p)183 int usbd_cdc_ecm_eth_tx(struct pbuf *p)
184 {
185     struct pbuf *q;
186     uint8_t *buffer;
187 
188     if (g_cdc_ecm_tx_data_length > 0) {
189         return -EBUSY;
190     }
191 
192     if (p->tot_len > sizeof(g_cdc_ecm_tx_buffer)) {
193         p->tot_len = sizeof(g_cdc_ecm_tx_buffer);
194     }
195 
196     buffer = g_cdc_ecm_tx_buffer;
197     for (q = p; q != NULL; q = q->next) {
198         memcpy(buffer, q->payload, q->len);
199         buffer += q->len;
200     }
201 
202     g_cdc_ecm_tx_data_length = p->tot_len;
203 
204     USB_LOG_DBG("txlen:%d\r\n", g_cdc_ecm_tx_data_length);
205     return usbd_ep_start_write(cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, g_cdc_ecm_tx_buffer, g_cdc_ecm_tx_data_length);
206 }
207 #endif
208 
usbd_cdc_ecm_init_intf(struct usbd_interface * intf,const uint8_t int_ep,const uint8_t out_ep,const uint8_t in_ep)209 struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const uint8_t int_ep, const uint8_t out_ep, const uint8_t in_ep)
210 {
211     intf->class_interface_handler = cdc_ecm_class_interface_request_handler;
212     intf->class_endpoint_handler = NULL;
213     intf->vendor_handler = NULL;
214     intf->notify_handler = cdc_ecm_notify_handler;
215 
216     cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr = out_ep;
217     cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_cb = cdc_ecm_bulk_out;
218     cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr = in_ep;
219     cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_cb = cdc_ecm_bulk_in;
220     cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr = int_ep;
221     cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_cb = cdc_ecm_int_in;
222 
223     usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX]);
224     usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX]);
225     usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX]);
226 
227     return intf;
228 }
229 
usbd_cdc_ecm_set_connect_speed(uint32_t speed[2])230 void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2])
231 {
232     memcpy(g_connect_speed_table, speed, 8);
233 }
234 
usbd_cdc_ecm_data_recv_done(void)235 __WEAK void usbd_cdc_ecm_data_recv_done(void)
236 {
237 }