1 /*
2 * Copyright (c) 2017 Intel Corporation
3 * Copyright (c) 2023 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT zephyr_cdc_ecm_ethernet
9
10 #include <zephyr/net/net_pkt.h>
11 #include <zephyr/net/ethernet.h>
12
13 #include <eth.h>
14
15 #include <zephyr/usb/usbd.h>
16 #include <zephyr/usb/usb_ch9.h>
17 #include <zephyr/usb/class/usb_cdc.h>
18 #include <zephyr/drivers/usb/udc.h>
19
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(cdc_ecm, CONFIG_USBD_CDC_ECM_LOG_LEVEL);
22
23 #define CDC_ECM_EP_MPS_INT 16
24 #define CDC_ECM_INTERVAL_DEFAULT 10000UL
25 #define CDC_ECM_FS_INT_EP_INTERVAL USB_FS_INT_EP_INTERVAL(10000U)
26 #define CDC_ECM_HS_INT_EP_INTERVAL USB_HS_INT_EP_INTERVAL(10000U)
27
28 enum {
29 CDC_ECM_IFACE_UP,
30 CDC_ECM_DATA_IFACE_ENABLED,
31 CDC_ECM_CLASS_SUSPENDED,
32 CDC_ECM_OUT_ENGAGED,
33 };
34
35 /*
36 * Transfers through two endpoints proceed in a synchronous manner,
37 * with maximum block of NET_ETH_MAX_FRAME_SIZE.
38 */
39 UDC_BUF_POOL_DEFINE(cdc_ecm_ep_pool,
40 DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) * 2,
41 NET_ETH_MAX_FRAME_SIZE,
42 sizeof(struct udc_buf_info), NULL);
43
44 struct cdc_ecm_notification {
45 union {
46 uint8_t bmRequestType;
47 struct usb_req_type_field RequestType;
48 };
49 uint8_t bNotificationType;
50 uint16_t wValue;
51 uint16_t wIndex;
52 uint16_t wLength;
53 } __packed;
54
55 /*
56 * Collection of descriptors used to assemble specific function descriptors.
57 * This structure is used by CDC ECM implementation to update and fetch
58 * properties at runtime. We currently support full and high speed.
59 */
60 struct usbd_cdc_ecm_desc {
61 struct usb_association_descriptor iad;
62
63 struct usb_if_descriptor if0;
64 struct cdc_header_descriptor if0_header;
65 struct cdc_union_descriptor if0_union;
66 struct cdc_ecm_descriptor if0_ecm;
67 struct usb_ep_descriptor if0_int_ep;
68 struct usb_ep_descriptor if0_hs_int_ep;
69
70 struct usb_if_descriptor if1_0;
71
72 struct usb_if_descriptor if1_1;
73 struct usb_ep_descriptor if1_1_in_ep;
74 struct usb_ep_descriptor if1_1_out_ep;
75 struct usb_ep_descriptor if1_1_hs_in_ep;
76 struct usb_ep_descriptor if1_1_hs_out_ep;
77
78 struct usb_desc_header nil_desc;
79 };
80
81 struct cdc_ecm_eth_data {
82 struct usbd_class_data *c_data;
83 struct usbd_desc_node *const mac_desc_data;
84 struct usbd_cdc_ecm_desc *const desc;
85 const struct usb_desc_header **const fs_desc;
86 const struct usb_desc_header **const hs_desc;
87
88 struct net_if *iface;
89 uint8_t mac_addr[6];
90
91 struct k_sem sync_sem;
92 atomic_t state;
93 };
94
cdc_ecm_get_ctrl_if(struct cdc_ecm_eth_data * const data)95 static uint8_t cdc_ecm_get_ctrl_if(struct cdc_ecm_eth_data *const data)
96 {
97 struct usbd_cdc_ecm_desc *desc = data->desc;
98
99 return desc->if0.bInterfaceNumber;
100 }
101
cdc_ecm_get_int_in(struct usbd_class_data * const c_data)102 static uint8_t cdc_ecm_get_int_in(struct usbd_class_data *const c_data)
103 {
104 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
105 const struct device *dev = usbd_class_get_private(c_data);
106 struct cdc_ecm_eth_data *data = dev->data;
107 struct usbd_cdc_ecm_desc *desc = data->desc;
108
109 if (USBD_SUPPORTS_HIGH_SPEED &&
110 usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
111 return desc->if0_hs_int_ep.bEndpointAddress;
112 }
113
114 return desc->if0_int_ep.bEndpointAddress;
115 }
116
cdc_ecm_get_bulk_in(struct usbd_class_data * const c_data)117 static uint8_t cdc_ecm_get_bulk_in(struct usbd_class_data *const c_data)
118 {
119 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
120 const struct device *dev = usbd_class_get_private(c_data);
121 struct cdc_ecm_eth_data *data = dev->data;
122 struct usbd_cdc_ecm_desc *desc = data->desc;
123
124 if (USBD_SUPPORTS_HIGH_SPEED &&
125 usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
126 return desc->if1_1_hs_in_ep.bEndpointAddress;
127 }
128
129 return desc->if1_1_in_ep.bEndpointAddress;
130 }
131
cdc_ecm_get_bulk_in_mps(struct usbd_class_data * const c_data)132 static uint16_t cdc_ecm_get_bulk_in_mps(struct usbd_class_data *const c_data)
133 {
134 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
135
136 if (USBD_SUPPORTS_HIGH_SPEED &&
137 usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
138 return 512U;
139 }
140
141 return 64U;
142 }
143
cdc_ecm_get_bulk_out(struct usbd_class_data * const c_data)144 static uint8_t cdc_ecm_get_bulk_out(struct usbd_class_data *const c_data)
145 {
146 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
147 const struct device *dev = usbd_class_get_private(c_data);
148 struct cdc_ecm_eth_data *data = dev->data;
149 struct usbd_cdc_ecm_desc *desc = data->desc;
150
151 if (USBD_SUPPORTS_HIGH_SPEED &&
152 usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
153 return desc->if1_1_hs_out_ep.bEndpointAddress;
154 }
155
156 return desc->if1_1_out_ep.bEndpointAddress;
157 }
158
cdc_ecm_buf_alloc(const uint8_t ep)159 static struct net_buf *cdc_ecm_buf_alloc(const uint8_t ep)
160 {
161 struct net_buf *buf = NULL;
162 struct udc_buf_info *bi;
163
164 buf = net_buf_alloc(&cdc_ecm_ep_pool, K_NO_WAIT);
165 if (!buf) {
166 return NULL;
167 }
168
169 bi = udc_get_buf_info(buf);
170 bi->ep = ep;
171
172 return buf;
173 }
174
175 /* Retrieve expected pkt size from ethernet/ip header */
ecm_eth_size(void * const ecm_pkt,const size_t len)176 static size_t ecm_eth_size(void *const ecm_pkt, const size_t len)
177 {
178 uint8_t *ip_data = (uint8_t *)ecm_pkt + sizeof(struct net_eth_hdr);
179 struct net_eth_hdr *hdr = (void *)ecm_pkt;
180 uint16_t ip_len;
181
182 if (len < NET_IPV6H_LEN + sizeof(struct net_eth_hdr)) {
183 /* Too short */
184 return 0;
185 }
186
187 switch (ntohs(hdr->type)) {
188 case NET_ETH_PTYPE_IP:
189 __fallthrough;
190 case NET_ETH_PTYPE_ARP:
191 ip_len = ntohs(((struct net_ipv4_hdr *)ip_data)->len);
192 break;
193 case NET_ETH_PTYPE_IPV6:
194 ip_len = ntohs(((struct net_ipv6_hdr *)ip_data)->len);
195 break;
196 default:
197 LOG_DBG("Unknown hdr type 0x%04x", hdr->type);
198 return 0;
199 }
200
201 return sizeof(struct net_eth_hdr) + ip_len;
202 }
203
cdc_ecm_out_start(struct usbd_class_data * const c_data)204 static int cdc_ecm_out_start(struct usbd_class_data *const c_data)
205 {
206 const struct device *dev = usbd_class_get_private(c_data);
207 struct cdc_ecm_eth_data *data = dev->data;
208 struct net_buf *buf;
209 uint8_t ep;
210 int ret;
211
212 if (atomic_test_and_set_bit(&data->state, CDC_ECM_OUT_ENGAGED)) {
213 return -EBUSY;
214 }
215
216 ep = cdc_ecm_get_bulk_out(c_data);
217 buf = cdc_ecm_buf_alloc(ep);
218 if (buf == NULL) {
219 return -ENOMEM;
220 }
221
222 ret = usbd_ep_enqueue(c_data, buf);
223 if (ret) {
224 LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep);
225 net_buf_unref(buf);
226 }
227
228 return ret;
229 }
230
cdc_ecm_acl_out_cb(struct usbd_class_data * const c_data,struct net_buf * const buf,const int err)231 static int cdc_ecm_acl_out_cb(struct usbd_class_data *const c_data,
232 struct net_buf *const buf, const int err)
233 {
234 const struct device *dev = usbd_class_get_private(c_data);
235 struct cdc_ecm_eth_data *data = dev->data;
236 struct net_pkt *pkt;
237
238 if (err || buf->len == 0) {
239 if (err != -ECONNABORTED) {
240 LOG_ERR("Bulk OUT transfer error (%d) or zero length", err);
241 }
242
243 goto restart_out_transfer;
244 }
245
246 /* Linux considers by default that network usb device controllers are
247 * not able to handle Zero Length Packet (ZLP) and then generates
248 * a short packet containing a null byte. Handle by checking the IP
249 * header length and dropping the extra byte.
250 */
251 if (buf->data[buf->len - 1] == 0U) {
252 /* Last byte is null */
253 if (ecm_eth_size(buf->data, buf->len) == (buf->len - 1)) {
254 /* last byte has been appended as delimiter, drop it */
255 net_buf_remove_u8(buf);
256 }
257 }
258
259 pkt = net_pkt_rx_alloc_with_buffer(data->iface, buf->len,
260 AF_UNSPEC, 0, K_FOREVER);
261 if (!pkt) {
262 LOG_ERR("No memory for net_pkt");
263 goto restart_out_transfer;
264 }
265
266 if (net_pkt_write(pkt, buf->data, buf->len)) {
267 LOG_ERR("Unable to write into pkt");
268 net_pkt_unref(pkt);
269 goto restart_out_transfer;
270 }
271
272 LOG_DBG("Received packet len %zu", net_pkt_get_len(pkt));
273 if (net_recv_data(data->iface, pkt) < 0) {
274 LOG_ERR("Packet %p dropped by network stack", pkt);
275 net_pkt_unref(pkt);
276 }
277
278 restart_out_transfer:
279 net_buf_unref(buf);
280 atomic_clear_bit(&data->state, CDC_ECM_OUT_ENGAGED);
281
282 if (atomic_test_bit(&data->state, CDC_ECM_DATA_IFACE_ENABLED)) {
283 return cdc_ecm_out_start(c_data);
284 }
285
286 return 0;
287 }
288
usbd_cdc_ecm_request(struct usbd_class_data * const c_data,struct net_buf * buf,int err)289 static int usbd_cdc_ecm_request(struct usbd_class_data *const c_data,
290 struct net_buf *buf, int err)
291 {
292 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
293 const struct device *dev = usbd_class_get_private(c_data);
294 struct cdc_ecm_eth_data *data = dev->data;
295 struct udc_buf_info *bi;
296
297 bi = udc_get_buf_info(buf);
298
299 if (bi->ep == cdc_ecm_get_bulk_out(c_data)) {
300 return cdc_ecm_acl_out_cb(c_data, buf, err);
301 }
302
303 if (bi->ep == cdc_ecm_get_bulk_in(c_data)) {
304 k_sem_give(&data->sync_sem);
305
306 return 0;
307 }
308
309 if (bi->ep == cdc_ecm_get_int_in(c_data)) {
310 LOG_INF("Notification %s", err ? "cancelled or failed" : "sent");
311 }
312
313 return usbd_ep_buf_free(uds_ctx, buf);
314 }
315
cdc_ecm_send_notification(const struct device * dev,const bool connected)316 static int cdc_ecm_send_notification(const struct device *dev,
317 const bool connected)
318 {
319 struct cdc_ecm_eth_data *data = dev->data;
320 struct usbd_class_data *c_data = data->c_data;
321 struct cdc_ecm_notification notification = {
322 .RequestType = {
323 .direction = USB_REQTYPE_DIR_TO_HOST,
324 .type = USB_REQTYPE_TYPE_CLASS,
325 .recipient = USB_REQTYPE_RECIPIENT_INTERFACE,
326 },
327 .bNotificationType = USB_CDC_NETWORK_CONNECTION,
328 .wValue = sys_cpu_to_le16((uint16_t)connected),
329 .wIndex = sys_cpu_to_le16(cdc_ecm_get_ctrl_if(data)),
330 .wLength = 0,
331 };
332 struct net_buf *buf;
333 uint8_t ep;
334 int ret;
335
336 if (!atomic_test_bit(&data->state, CDC_ECM_DATA_IFACE_ENABLED)) {
337 LOG_INF("USB configuration is not enabled");
338 return 0;
339 }
340
341 if (atomic_test_bit(&data->state, CDC_ECM_CLASS_SUSPENDED)) {
342 LOG_INF("USB device is suspended (FIXME)");
343 return 0;
344 }
345
346 ep = cdc_ecm_get_int_in(c_data);
347 buf = usbd_ep_buf_alloc(c_data, ep, sizeof(struct cdc_ecm_notification));
348 if (buf == NULL) {
349 return -ENOMEM;
350 }
351
352 net_buf_add_mem(buf, ¬ification, sizeof(struct cdc_ecm_notification));
353 ret = usbd_ep_enqueue(c_data, buf);
354 if (ret) {
355 LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep);
356 net_buf_unref(buf);
357 return ret;
358 }
359
360 return 0;
361 }
362
usbd_cdc_ecm_update(struct usbd_class_data * const c_data,const uint8_t iface,const uint8_t alternate)363 static void usbd_cdc_ecm_update(struct usbd_class_data *const c_data,
364 const uint8_t iface, const uint8_t alternate)
365 {
366 const struct device *dev = usbd_class_get_private(c_data);
367 struct cdc_ecm_eth_data *data = dev->data;
368 struct usbd_cdc_ecm_desc *desc = data->desc;
369 const uint8_t data_iface = desc->if1_1.bInterfaceNumber;
370
371 LOG_INF("New configuration, interface %u alternate %u",
372 iface, alternate);
373
374 if (data_iface == iface && alternate == 0) {
375 atomic_clear_bit(&data->state, CDC_ECM_DATA_IFACE_ENABLED);
376 net_if_carrier_off(data->iface);
377 }
378
379 if (data_iface == iface && alternate == 1) {
380 atomic_set_bit(&data->state, CDC_ECM_DATA_IFACE_ENABLED);
381
382 if (atomic_test_bit(&data->state, CDC_ECM_IFACE_UP)) {
383 net_if_carrier_on(data->iface);
384 if (cdc_ecm_send_notification(dev, true)) {
385 LOG_ERR("Failed to send connected notification");
386 }
387 }
388
389 if (cdc_ecm_out_start(c_data)) {
390 LOG_ERR("Failed to start OUT transfer");
391 }
392 }
393 }
394
usbd_cdc_ecm_enable(struct usbd_class_data * const c_data)395 static void usbd_cdc_ecm_enable(struct usbd_class_data *const c_data)
396 {
397 LOG_INF("Enabled %s", c_data->name);
398 }
399
usbd_cdc_ecm_disable(struct usbd_class_data * const c_data)400 static void usbd_cdc_ecm_disable(struct usbd_class_data *const c_data)
401 {
402 const struct device *dev = usbd_class_get_private(c_data);
403 struct cdc_ecm_eth_data *data = dev->data;
404
405 atomic_clear_bit(&data->state, CDC_ECM_DATA_IFACE_ENABLED);
406 atomic_clear_bit(&data->state, CDC_ECM_CLASS_SUSPENDED);
407 LOG_INF("Disabled %s", c_data->name);
408 }
409
usbd_cdc_ecm_suspended(struct usbd_class_data * const c_data)410 static void usbd_cdc_ecm_suspended(struct usbd_class_data *const c_data)
411 {
412 const struct device *dev = usbd_class_get_private(c_data);
413 struct cdc_ecm_eth_data *data = dev->data;
414
415 atomic_set_bit(&data->state, CDC_ECM_CLASS_SUSPENDED);
416 }
417
usbd_cdc_ecm_resumed(struct usbd_class_data * const c_data)418 static void usbd_cdc_ecm_resumed(struct usbd_class_data *const c_data)
419 {
420 const struct device *dev = usbd_class_get_private(c_data);
421 struct cdc_ecm_eth_data *data = dev->data;
422
423 atomic_clear_bit(&data->state, CDC_ECM_CLASS_SUSPENDED);
424 }
425
usbd_cdc_ecm_ctd(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup,const struct net_buf * const buf)426 static int usbd_cdc_ecm_ctd(struct usbd_class_data *const c_data,
427 const struct usb_setup_packet *const setup,
428 const struct net_buf *const buf)
429 {
430 if (setup->RequestType.recipient == USB_REQTYPE_RECIPIENT_INTERFACE &&
431 setup->bRequest == SET_ETHERNET_PACKET_FILTER) {
432 LOG_INF("bRequest 0x%02x (SetPacketFilter) not implemented",
433 setup->bRequest);
434
435 return 0;
436 }
437
438 LOG_DBG("bmRequestType 0x%02x bRequest 0x%02x unsupported",
439 setup->bmRequestType, setup->bRequest);
440 errno = -ENOTSUP;
441
442 return 0;
443 }
444
usbd_cdc_ecm_init(struct usbd_class_data * const c_data)445 static int usbd_cdc_ecm_init(struct usbd_class_data *const c_data)
446 {
447 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
448 const struct device *dev = usbd_class_get_private(c_data);
449 struct cdc_ecm_eth_data *const data = dev->data;
450 struct usbd_cdc_ecm_desc *desc = data->desc;
451 const uint8_t if_num = desc->if0.bInterfaceNumber;
452
453 /* Update relevant b*Interface fields */
454 desc->if0_union.bControlInterface = if_num;
455 desc->if0_union.bSubordinateInterface0 = if_num + 1;
456 LOG_DBG("CDC ECM class initialized");
457
458 if (usbd_add_descriptor(uds_ctx, data->mac_desc_data)) {
459 LOG_ERR("Failed to add iMACAddress string descriptor");
460 } else {
461 desc->if0_ecm.iMACAddress = usbd_str_desc_get_idx(data->mac_desc_data);
462 }
463
464 return 0;
465 }
466
usbd_cdc_ecm_shutdown(struct usbd_class_data * const c_data)467 static void usbd_cdc_ecm_shutdown(struct usbd_class_data *const c_data)
468 {
469 const struct device *dev = usbd_class_get_private(c_data);
470 struct cdc_ecm_eth_data *const data = dev->data;
471 struct usbd_cdc_ecm_desc *desc = data->desc;
472
473 desc->if0_ecm.iMACAddress = 0;
474 sys_dlist_remove(&data->mac_desc_data->node);
475 }
476
usbd_cdc_ecm_get_desc(struct usbd_class_data * const c_data,const enum usbd_speed speed)477 static void *usbd_cdc_ecm_get_desc(struct usbd_class_data *const c_data,
478 const enum usbd_speed speed)
479 {
480 const struct device *dev = usbd_class_get_private(c_data);
481 struct cdc_ecm_eth_data *const data = dev->data;
482
483 if (USBD_SUPPORTS_HIGH_SPEED && speed == USBD_SPEED_HS) {
484 return data->hs_desc;
485 }
486
487 return data->fs_desc;
488 }
489
cdc_ecm_send(const struct device * dev,struct net_pkt * const pkt)490 static int cdc_ecm_send(const struct device *dev, struct net_pkt *const pkt)
491 {
492 struct cdc_ecm_eth_data *const data = dev->data;
493 struct usbd_class_data *c_data = data->c_data;
494 size_t len = net_pkt_get_len(pkt);
495 struct net_buf *buf;
496 uint8_t ep;
497 int ret;
498
499 if (len > NET_ETH_MAX_FRAME_SIZE) {
500 LOG_WRN("Trying to send too large packet, drop");
501 return -ENOMEM;
502 }
503
504 if (!atomic_test_bit(&data->state, CDC_ECM_DATA_IFACE_ENABLED) ||
505 !atomic_test_bit(&data->state, CDC_ECM_IFACE_UP)) {
506 LOG_INF("Configuration is not enabled or interface not ready");
507 return -EACCES;
508 }
509
510 ep = cdc_ecm_get_bulk_in(c_data);
511 buf = cdc_ecm_buf_alloc(ep);
512 if (buf == NULL) {
513 LOG_ERR("Failed to allocate buffer");
514 return -ENOMEM;
515 }
516
517 if (net_pkt_read(pkt, buf->data, len)) {
518 LOG_ERR("Failed copy net_pkt");
519 net_buf_unref(buf);
520
521 return -ENOBUFS;
522 }
523
524 net_buf_add(buf, len);
525
526 if (!(buf->len % cdc_ecm_get_bulk_in_mps(c_data))) {
527 udc_ep_buf_set_zlp(buf);
528 }
529
530 ret = usbd_ep_enqueue(c_data, buf);
531 if (ret) {
532 LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep);
533 net_buf_unref(buf);
534 return ret;
535 }
536
537 k_sem_take(&data->sync_sem, K_FOREVER);
538 net_buf_unref(buf);
539
540 return 0;
541 }
542
cdc_ecm_set_config(const struct device * dev,const enum ethernet_config_type type,const struct ethernet_config * config)543 static int cdc_ecm_set_config(const struct device *dev,
544 const enum ethernet_config_type type,
545 const struct ethernet_config *config)
546 {
547 struct cdc_ecm_eth_data *data = dev->data;
548
549 if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) {
550 memcpy(data->mac_addr, config->mac_address.addr,
551 sizeof(data->mac_addr));
552
553 return 0;
554 }
555
556 return -ENOTSUP;
557 }
558
cdc_ecm_get_capabilities(const struct device * dev)559 static enum ethernet_hw_caps cdc_ecm_get_capabilities(const struct device *dev)
560 {
561 ARG_UNUSED(dev);
562
563 return ETHERNET_LINK_10BASE;
564 }
565
cdc_ecm_iface_start(const struct device * dev)566 static int cdc_ecm_iface_start(const struct device *dev)
567 {
568 struct cdc_ecm_eth_data *data = dev->data;
569
570 LOG_DBG("Start interface %p", data->iface);
571
572 atomic_set_bit(&data->state, CDC_ECM_IFACE_UP);
573
574 if (atomic_test_bit(&data->state, CDC_ECM_DATA_IFACE_ENABLED)) {
575 net_if_carrier_on(data->iface);
576 if (cdc_ecm_send_notification(dev, true)) {
577 LOG_ERR("Failed to send connected notification");
578 }
579 }
580
581 return 0;
582 }
583
cdc_ecm_iface_stop(const struct device * dev)584 static int cdc_ecm_iface_stop(const struct device *dev)
585 {
586 struct cdc_ecm_eth_data *data = dev->data;
587
588 LOG_DBG("Stop interface %p", data->iface);
589
590 atomic_clear_bit(&data->state, CDC_ECM_IFACE_UP);
591
592 if (atomic_test_bit(&data->state, CDC_ECM_DATA_IFACE_ENABLED)) {
593 if (cdc_ecm_send_notification(dev, false)) {
594 LOG_ERR("Failed to send disconnected notification");
595 }
596 }
597
598 return 0;
599 }
600
cdc_ecm_iface_init(struct net_if * const iface)601 static void cdc_ecm_iface_init(struct net_if *const iface)
602 {
603 const struct device *dev = net_if_get_device(iface);
604 struct cdc_ecm_eth_data *data = dev->data;
605
606 data->iface = iface;
607 ethernet_init(iface);
608 net_if_set_link_addr(iface, data->mac_addr,
609 sizeof(data->mac_addr),
610 NET_LINK_ETHERNET);
611
612 net_if_carrier_off(iface);
613
614 LOG_DBG("CDC ECM interface initialized");
615 }
616
usbd_cdc_ecm_preinit(const struct device * dev)617 static int usbd_cdc_ecm_preinit(const struct device *dev)
618 {
619 struct cdc_ecm_eth_data *data = dev->data;
620
621 if (sys_get_le48(data->mac_addr) == sys_cpu_to_le48(0)) {
622 gen_random_mac(data->mac_addr, 0, 0, 0);
623 }
624
625 LOG_DBG("CDC ECM device initialized");
626
627 return 0;
628 }
629
630 static struct usbd_class_api usbd_cdc_ecm_api = {
631 .request = usbd_cdc_ecm_request,
632 .update = usbd_cdc_ecm_update,
633 .enable = usbd_cdc_ecm_enable,
634 .disable = usbd_cdc_ecm_disable,
635 .suspended = usbd_cdc_ecm_suspended,
636 .resumed = usbd_cdc_ecm_resumed,
637 .control_to_dev = usbd_cdc_ecm_ctd,
638 .init = usbd_cdc_ecm_init,
639 .shutdown = usbd_cdc_ecm_shutdown,
640 .get_desc = usbd_cdc_ecm_get_desc,
641 };
642
643 static const struct ethernet_api cdc_ecm_eth_api = {
644 .iface_api.init = cdc_ecm_iface_init,
645 .set_config = cdc_ecm_set_config,
646 .get_capabilities = cdc_ecm_get_capabilities,
647 .send = cdc_ecm_send,
648 .start = cdc_ecm_iface_start,
649 .stop = cdc_ecm_iface_stop,
650 };
651
652 #define CDC_ECM_DEFINE_DESCRIPTOR(n) \
653 static struct usbd_cdc_ecm_desc cdc_ecm_desc_##n = { \
654 .iad = { \
655 .bLength = sizeof(struct usb_association_descriptor), \
656 .bDescriptorType = USB_DESC_INTERFACE_ASSOC, \
657 .bFirstInterface = 0, \
658 .bInterfaceCount = 0x02, \
659 .bFunctionClass = USB_BCC_CDC_CONTROL, \
660 .bFunctionSubClass = ECM_SUBCLASS, \
661 .bFunctionProtocol = 0, \
662 .iFunction = 0, \
663 }, \
664 \
665 .if0 = { \
666 .bLength = sizeof(struct usb_if_descriptor), \
667 .bDescriptorType = USB_DESC_INTERFACE, \
668 .bInterfaceNumber = 0, \
669 .bAlternateSetting = 0, \
670 .bNumEndpoints = 1, \
671 .bInterfaceClass = USB_BCC_CDC_CONTROL, \
672 .bInterfaceSubClass = ECM_SUBCLASS, \
673 .bInterfaceProtocol = 0, \
674 .iInterface = 0, \
675 }, \
676 \
677 .if0_header = { \
678 .bFunctionLength = sizeof(struct cdc_header_descriptor), \
679 .bDescriptorType = USB_DESC_CS_INTERFACE, \
680 .bDescriptorSubtype = HEADER_FUNC_DESC, \
681 .bcdCDC = sys_cpu_to_le16(USB_SRN_1_1), \
682 }, \
683 \
684 .if0_union = { \
685 .bFunctionLength = sizeof(struct cdc_union_descriptor), \
686 .bDescriptorType = USB_DESC_CS_INTERFACE, \
687 .bDescriptorSubtype = UNION_FUNC_DESC, \
688 .bControlInterface = 0, \
689 .bSubordinateInterface0 = 1, \
690 }, \
691 \
692 .if0_ecm = { \
693 .bFunctionLength = sizeof(struct cdc_ecm_descriptor), \
694 .bDescriptorType = USB_DESC_CS_INTERFACE, \
695 .bDescriptorSubtype = ETHERNET_FUNC_DESC, \
696 .iMACAddress = 0, \
697 .bmEthernetStatistics = sys_cpu_to_le32(0), \
698 .wMaxSegmentSize = sys_cpu_to_le16(NET_ETH_MAX_FRAME_SIZE), \
699 .wNumberMCFilters = sys_cpu_to_le16(0), \
700 .bNumberPowerFilters = 0, \
701 }, \
702 \
703 .if0_int_ep = { \
704 .bLength = sizeof(struct usb_ep_descriptor), \
705 .bDescriptorType = USB_DESC_ENDPOINT, \
706 .bEndpointAddress = 0x81, \
707 .bmAttributes = USB_EP_TYPE_INTERRUPT, \
708 .wMaxPacketSize = sys_cpu_to_le16(CDC_ECM_EP_MPS_INT), \
709 .bInterval = CDC_ECM_FS_INT_EP_INTERVAL, \
710 }, \
711 \
712 .if0_hs_int_ep = { \
713 .bLength = sizeof(struct usb_ep_descriptor), \
714 .bDescriptorType = USB_DESC_ENDPOINT, \
715 .bEndpointAddress = 0x81, \
716 .bmAttributes = USB_EP_TYPE_INTERRUPT, \
717 .wMaxPacketSize = sys_cpu_to_le16(CDC_ECM_EP_MPS_INT), \
718 .bInterval = CDC_ECM_HS_INT_EP_INTERVAL, \
719 }, \
720 \
721 .if1_0 = { \
722 .bLength = sizeof(struct usb_if_descriptor), \
723 .bDescriptorType = USB_DESC_INTERFACE, \
724 .bInterfaceNumber = 1, \
725 .bAlternateSetting = 0, \
726 .bNumEndpoints = 0, \
727 .bInterfaceClass = USB_BCC_CDC_DATA, \
728 .bInterfaceSubClass = 0, \
729 .bInterfaceProtocol = 0, \
730 .iInterface = 0, \
731 }, \
732 \
733 .if1_1 = { \
734 .bLength = sizeof(struct usb_if_descriptor), \
735 .bDescriptorType = USB_DESC_INTERFACE, \
736 .bInterfaceNumber = 1, \
737 .bAlternateSetting = 1, \
738 .bNumEndpoints = 2, \
739 .bInterfaceClass = USB_BCC_CDC_DATA, \
740 .bInterfaceSubClass = ECM_SUBCLASS, \
741 .bInterfaceProtocol = 0, \
742 .iInterface = 0, \
743 }, \
744 \
745 .if1_1_in_ep = { \
746 .bLength = sizeof(struct usb_ep_descriptor), \
747 .bDescriptorType = USB_DESC_ENDPOINT, \
748 .bEndpointAddress = 0x82, \
749 .bmAttributes = USB_EP_TYPE_BULK, \
750 .wMaxPacketSize = sys_cpu_to_le16(64U), \
751 .bInterval = 0, \
752 }, \
753 \
754 .if1_1_out_ep = { \
755 .bLength = sizeof(struct usb_ep_descriptor), \
756 .bDescriptorType = USB_DESC_ENDPOINT, \
757 .bEndpointAddress = 0x01, \
758 .bmAttributes = USB_EP_TYPE_BULK, \
759 .wMaxPacketSize = sys_cpu_to_le16(64U), \
760 .bInterval = 0, \
761 }, \
762 \
763 .if1_1_hs_in_ep = { \
764 .bLength = sizeof(struct usb_ep_descriptor), \
765 .bDescriptorType = USB_DESC_ENDPOINT, \
766 .bEndpointAddress = 0x82, \
767 .bmAttributes = USB_EP_TYPE_BULK, \
768 .wMaxPacketSize = sys_cpu_to_le16(512U), \
769 .bInterval = 0, \
770 }, \
771 \
772 .if1_1_hs_out_ep = { \
773 .bLength = sizeof(struct usb_ep_descriptor), \
774 .bDescriptorType = USB_DESC_ENDPOINT, \
775 .bEndpointAddress = 0x01, \
776 .bmAttributes = USB_EP_TYPE_BULK, \
777 .wMaxPacketSize = sys_cpu_to_le16(512U), \
778 .bInterval = 0, \
779 }, \
780 \
781 .nil_desc = { \
782 .bLength = 0, \
783 .bDescriptorType = 0, \
784 }, \
785 }; \
786 \
787 const static struct usb_desc_header *cdc_ecm_fs_desc_##n[] = { \
788 (struct usb_desc_header *) &cdc_ecm_desc_##n.iad, \
789 (struct usb_desc_header *) &cdc_ecm_desc_##n.if0, \
790 (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_header, \
791 (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_union, \
792 (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_ecm, \
793 (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_int_ep, \
794 (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_0, \
795 (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1, \
796 (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1_in_ep, \
797 (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1_out_ep, \
798 (struct usb_desc_header *) &cdc_ecm_desc_##n.nil_desc, \
799 }; \
800 \
801 const static struct usb_desc_header *cdc_ecm_hs_desc_##n[] = { \
802 (struct usb_desc_header *) &cdc_ecm_desc_##n.iad, \
803 (struct usb_desc_header *) &cdc_ecm_desc_##n.if0, \
804 (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_header, \
805 (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_union, \
806 (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_ecm, \
807 (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_hs_int_ep, \
808 (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_0, \
809 (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1, \
810 (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1_hs_in_ep, \
811 (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1_hs_out_ep, \
812 (struct usb_desc_header *) &cdc_ecm_desc_##n.nil_desc, \
813 }
814
815 #define USBD_CDC_ECM_DT_DEVICE_DEFINE(n) \
816 CDC_ECM_DEFINE_DESCRIPTOR(n); \
817 USBD_DESC_STRING_DEFINE(mac_desc_data_##n, \
818 DT_INST_PROP(n, remote_mac_address), \
819 USBD_DUT_STRING_INTERFACE); \
820 \
821 USBD_DEFINE_CLASS(cdc_ecm_##n, \
822 &usbd_cdc_ecm_api, \
823 (void *)DEVICE_DT_GET(DT_DRV_INST(n)), NULL); \
824 \
825 static struct cdc_ecm_eth_data eth_data_##n = { \
826 .c_data = &cdc_ecm_##n, \
827 .mac_addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \
828 .sync_sem = Z_SEM_INITIALIZER(eth_data_##n.sync_sem, 0, 1), \
829 .mac_desc_data = &mac_desc_data_##n, \
830 .desc = &cdc_ecm_desc_##n, \
831 .fs_desc = cdc_ecm_fs_desc_##n, \
832 .hs_desc = cdc_ecm_hs_desc_##n, \
833 }; \
834 \
835 ETH_NET_DEVICE_DT_INST_DEFINE(n, usbd_cdc_ecm_preinit, NULL, \
836 ð_data_##n, NULL, \
837 CONFIG_ETH_INIT_PRIORITY, \
838 &cdc_ecm_eth_api, \
839 NET_ETH_MTU);
840
841 DT_INST_FOREACH_STATUS_OKAY(USBD_CDC_ECM_DT_DEVICE_DEFINE);
842