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