1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2017-11-19 ZYH first version 9 */ 10 11 #include <rtdevice.h> 12 #include "cdc.h" 13 14 15 #ifdef ECM_DEBUG 16 #define ECM_PRINTF rt_kprintf("[ECM] "); rt_kprintf 17 #else 18 #define ECM_PRINTF(...) 19 #endif /* ECM_DEBUG */ 20 21 /* RT-Thread LWIP ethernet interface */ 22 #include <netif/ethernetif.h> 23 24 #ifndef USB_ETH_MTU 25 #define USB_ETH_MTU 1514 26 #endif 27 #define MAX_ADDR_LEN 6 28 29 struct rt_ecm_eth 30 { 31 /* inherit from ethernet device */ 32 struct eth_device parent; 33 struct ufunction * func; 34 struct cdc_eps eps; 35 /* interface address info */ 36 rt_uint8_t host_addr[MAX_ADDR_LEN]; 37 rt_uint8_t dev_addr[MAX_ADDR_LEN]; 38 39 ALIGN(4) 40 rt_uint8_t rx_pool[512]; 41 ALIGN(4) 42 rt_size_t rx_size; 43 ALIGN(4) 44 rt_size_t rx_offset; 45 ALIGN(4) 46 char rx_buffer[USB_ETH_MTU]; 47 char tx_buffer[USB_ETH_MTU]; 48 49 struct rt_semaphore tx_buffer_free; 50 51 }; 52 typedef struct rt_ecm_eth * rt_ecm_eth_t; 53 54 ALIGN(4) 55 static struct udevice_descriptor _dev_desc = 56 { 57 USB_DESC_LENGTH_DEVICE, /* bLength */ 58 USB_DESC_TYPE_DEVICE, /* type */ 59 USB_BCD_VERSION, /* bcdUSB */ 60 USB_CLASS_CDC, /* bDeviceClass */ 61 USB_CDC_SUBCLASS_ETH, /* bDeviceSubClass */ 62 USB_CDC_PROTOCOL_NONE, /* bDeviceProtocol */ 63 0x40, /* bMaxPacketSize0 */ 64 _VENDOR_ID, /* idVendor */ 65 _PRODUCT_ID, /* idProduct */ 66 USB_BCD_DEVICE, /* bcdDevice */ 67 USB_STRING_MANU_INDEX, /* iManufacturer */ 68 USB_STRING_PRODUCT_INDEX, /* iProduct */ 69 USB_STRING_SERIAL_INDEX, /* iSerialNumber */ 70 USB_DYNAMIC /* bNumConfigurations */ 71 }; 72 73 /* communcation interface descriptor */ 74 ALIGN(4) 75 const static struct ucdc_eth_descriptor _comm_desc = 76 { 77 #ifdef RT_USB_DEVICE_COMPOSITE 78 /* Interface Association Descriptor */ 79 { 80 USB_DESC_LENGTH_IAD, 81 USB_DESC_TYPE_IAD, 82 USB_DYNAMIC, 83 0x02, 84 USB_CDC_CLASS_COMM, 85 USB_CDC_SUBCLASS_ETH, 86 USB_CDC_PROTOCOL_NONE, 87 0x00, 88 }, 89 #endif 90 /* Interface Descriptor */ 91 { 92 USB_DESC_LENGTH_INTERFACE, 93 USB_DESC_TYPE_INTERFACE, 94 USB_DYNAMIC, 95 0x00, 96 0x01, 97 USB_CDC_CLASS_COMM, 98 USB_CDC_SUBCLASS_ETH, 99 USB_CDC_PROTOCOL_NONE, 100 0x00, 101 }, 102 /* Header Functional Descriptor */ 103 { 104 sizeof(struct ucdc_header_descriptor), 105 USB_CDC_CS_INTERFACE, 106 USB_CDC_SCS_HEADER, 107 0x0110, 108 }, 109 /* Union Functional Descriptor */ 110 { 111 sizeof(struct ucdc_union_descriptor), 112 USB_CDC_CS_INTERFACE, 113 USB_CDC_SCS_UNION, 114 USB_DYNAMIC, 115 USB_DYNAMIC, 116 }, 117 /* Abstract Control Management Functional Descriptor */ 118 { 119 sizeof(struct ucdc_enet_descriptor), 120 USB_CDC_CS_INTERFACE, 121 USB_CDC_SCS_ETH, 122 USB_STRING_SERIAL_INDEX, 123 {0,0,0,0}, 124 USB_ETH_MTU, 125 0x00, 126 0x00, 127 }, 128 /* Endpoint Descriptor */ 129 { 130 USB_DESC_LENGTH_ENDPOINT, 131 USB_DESC_TYPE_ENDPOINT, 132 USB_DIR_IN | USB_DYNAMIC, 133 USB_EP_ATTR_INT, 134 0x08, 135 0xFF, 136 }, 137 }; 138 139 /* data interface descriptor */ 140 ALIGN(4) 141 const static struct ucdc_data_descriptor _data_desc = 142 { 143 /* interface descriptor */ 144 { 145 USB_DESC_LENGTH_INTERFACE, 146 USB_DESC_TYPE_INTERFACE, 147 USB_DYNAMIC, 148 0x00, 149 0x02, 150 USB_CDC_CLASS_DATA, 151 USB_CDC_SUBCLASS_ETH, 152 0x00, 153 0x00, 154 }, 155 /* endpoint, bulk out */ 156 { 157 USB_DESC_LENGTH_ENDPOINT, 158 USB_DESC_TYPE_ENDPOINT, 159 USB_DIR_OUT | USB_DYNAMIC, 160 USB_EP_ATTR_BULK, 161 USB_DYNAMIC, 162 0x00, 163 }, 164 /* endpoint, bulk in */ 165 { 166 USB_DESC_LENGTH_ENDPOINT, 167 USB_DESC_TYPE_ENDPOINT, 168 USB_DYNAMIC | USB_DIR_IN, 169 USB_EP_ATTR_BULK, 170 USB_DYNAMIC, 171 0x00, 172 }, 173 }; 174 175 ALIGN(4) 176 const static char* _ustring[] = 177 { 178 "Language", /* LANGID */ 179 "RT-Thread Team.", /* MANU */ 180 "RT-Thread ECM device", /* PRODUCT */ 181 "3497F694ECAB", /* SERIAL (MAC)*/ 182 "Configuration", /* CONFIG */ 183 "Interface", /* INTERFACE */ 184 }; 185 186 ALIGN(4) 187 //FS and HS needed 188 static struct usb_qualifier_descriptor dev_qualifier = 189 { 190 sizeof(dev_qualifier), //bLength 191 USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType 192 0x0200, //bcdUSB 193 USB_CLASS_CDC, //bDeviceClass 194 USB_CDC_SUBCLASS_ETH, //bDeviceSubClass 195 USB_CDC_PROTOCOL_NONE, //bDeviceProtocol 196 64, //bMaxPacketSize0 197 0x01, //bNumConfigurations 198 0, 199 }; 200 201 static rt_err_t _cdc_send_notifi(ufunction_t func,ucdc_notification_code_t notifi,rt_uint16_t wValue,rt_uint16_t wLength) 202 { 203 static struct ucdc_management_element_notifications _notifi; 204 cdc_eps_t eps; 205 RT_ASSERT(func!=RT_NULL) 206 eps = &((rt_ecm_eth_t)func->user_data)->eps; 207 _notifi.bmRequestType = 0xA1; 208 _notifi.bNotificatinCode = notifi; 209 _notifi.wValue = wValue; 210 _notifi.wLength = wLength; 211 212 eps->ep_cmd->request.buffer = (void *)&_notifi; 213 eps->ep_cmd->request.size = 8; 214 eps->ep_cmd->request.req_type = UIO_REQUEST_WRITE; 215 rt_usbd_io_request(func->device, eps->ep_cmd, &eps->ep_cmd->request); 216 return RT_EOK; 217 } 218 219 static rt_err_t _ecm_set_eth_packet_filter(ufunction_t func, ureq_t setup) 220 { 221 rt_ecm_eth_t _ecm_eth = (rt_ecm_eth_t)func->user_data; 222 dcd_ep0_send_status(func->device->dcd); 223 224 225 /* send link up. */ 226 eth_device_linkchange(&_ecm_eth->parent, RT_TRUE); 227 _cdc_send_notifi(func,UCDC_NOTIFI_NETWORK_CONNECTION,1,0); 228 return RT_EOK; 229 } 230 /** 231 * This function will handle rndis interface request. 232 * 233 * @param device the usb device object. 234 * @param setup the setup request. 235 * 236 * @return RT_EOK on successful. 237 */ 238 static rt_err_t _interface_handler(ufunction_t func, ureq_t setup) 239 { 240 RT_ASSERT(func != RT_NULL); 241 RT_ASSERT(setup != RT_NULL); 242 243 switch(setup->bRequest) 244 { 245 case CDC_SET_ETH_PACKET_FILTER: 246 _ecm_set_eth_packet_filter(func, setup); 247 break; 248 default: 249 rt_kprintf("setup->bRequest:0x%02X",setup->bRequest); 250 break; 251 } 252 return RT_EOK; 253 } 254 255 /** 256 * This function will handle rndis bulk in endpoint request. 257 * 258 * @param device the usb device object. 259 * @param size request size. 260 * 261 * @return RT_EOK. 262 */ 263 264 static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size) 265 { 266 rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data; 267 rt_sem_release(&ecm_device->tx_buffer_free); 268 return RT_EOK; 269 } 270 271 /** 272 * This function will handle RNDIS bulk out endpoint request. 273 * 274 * @param device the usb device object. 275 * @param size request size. 276 * 277 * @return RT_EOK. 278 */ 279 static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size) 280 { 281 rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data; 282 rt_memcpy((void *)(ecm_device->rx_buffer + ecm_device->rx_offset),ecm_device->rx_pool,size); 283 ecm_device->rx_offset += size; 284 if(size < EP_MAXPACKET(ecm_device->eps.ep_out)) 285 { 286 ecm_device->rx_size = ecm_device->rx_offset; 287 ecm_device->rx_offset = 0; 288 eth_device_ready(&ecm_device->parent); 289 290 }else 291 { 292 ecm_device->eps.ep_out->request.buffer = ecm_device->eps.ep_out->buffer; 293 ecm_device->eps.ep_out->request.size = EP_MAXPACKET(ecm_device->eps.ep_out); 294 ecm_device->eps.ep_out->request.req_type = UIO_REQUEST_READ_BEST; 295 rt_usbd_io_request(ecm_device->func->device, ecm_device->eps.ep_out, &ecm_device->eps.ep_out->request); 296 } 297 298 299 return RT_EOK; 300 } 301 static rt_err_t rt_ecm_eth_init(rt_device_t dev) 302 { 303 return RT_EOK; 304 } 305 306 static rt_err_t rt_ecm_eth_open(rt_device_t dev, rt_uint16_t oflag) 307 { 308 return RT_EOK; 309 } 310 311 static rt_err_t rt_ecm_eth_close(rt_device_t dev) 312 { 313 return RT_EOK; 314 } 315 316 static rt_size_t rt_ecm_eth_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) 317 { 318 rt_set_errno(-RT_ENOSYS); 319 return 0; 320 } 321 322 static rt_size_t rt_ecm_eth_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) 323 { 324 rt_set_errno(-RT_ENOSYS); 325 return 0; 326 } 327 static rt_err_t rt_ecm_eth_control(rt_device_t dev, int cmd, void *args) 328 { 329 rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev; 330 switch(cmd) 331 { 332 case NIOCTL_GADDR: 333 /* get mac address */ 334 if(args) rt_memcpy(args, ecm_eth_dev->dev_addr, MAX_ADDR_LEN); 335 else return -RT_ERROR; 336 break; 337 338 default : 339 break; 340 } 341 342 return RT_EOK; 343 } 344 345 #ifdef RT_USING_DEVICE_OPS 346 const static struct rt_device_ops ecm_device_ops = 347 { 348 rt_ecm_eth_init, 349 rt_ecm_eth_open, 350 rt_ecm_eth_close, 351 rt_ecm_eth_read, 352 rt_ecm_eth_write, 353 rt_ecm_eth_control 354 }; 355 #endif 356 357 struct pbuf *rt_ecm_eth_rx(rt_device_t dev) 358 { 359 struct pbuf* p = RT_NULL; 360 rt_uint32_t offset = 0; 361 rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev; 362 if(ecm_eth_dev->rx_size != 0) 363 { 364 /* allocate buffer */ 365 p = pbuf_alloc(PBUF_RAW, ecm_eth_dev->rx_size, PBUF_RAM); 366 if (p != RT_NULL) 367 { 368 struct pbuf* q; 369 370 for (q = p; q != RT_NULL; q= q->next) 371 { 372 /* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */ 373 rt_memcpy(q->payload, 374 (rt_uint8_t *)((ecm_eth_dev->rx_buffer) + offset), 375 q->len); 376 offset += q->len; 377 } 378 } 379 } 380 381 { 382 if(ecm_eth_dev->func->device->state == USB_STATE_CONFIGURED) 383 { 384 ecm_eth_dev->rx_size = 0; 385 ecm_eth_dev->rx_offset = 0; 386 ecm_eth_dev->eps.ep_out->request.buffer = ecm_eth_dev->eps.ep_out->buffer; 387 ecm_eth_dev->eps.ep_out->request.size = EP_MAXPACKET(ecm_eth_dev->eps.ep_out); 388 ecm_eth_dev->eps.ep_out->request.req_type = UIO_REQUEST_READ_BEST; 389 rt_usbd_io_request(ecm_eth_dev->func->device, ecm_eth_dev->eps.ep_out, &ecm_eth_dev->eps.ep_out->request); 390 } 391 } 392 393 return p; 394 } 395 396 rt_err_t rt_ecm_eth_tx(rt_device_t dev, struct pbuf* p) 397 { 398 struct pbuf* q; 399 char * pbuffer; 400 rt_err_t result = RT_EOK; 401 rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev; 402 403 if(!ecm_eth_dev->parent.link_status) 404 { 405 ECM_PRINTF("linkdown, drop pkg\r\n"); 406 return RT_EOK; 407 } 408 409 // RT_ASSERT(p->tot_len < USB_ETH_MTU); 410 if(p->tot_len > USB_ETH_MTU) 411 { 412 ECM_PRINTF("RNDIS MTU is:%d, but the send packet size is %d\r\n", 413 USB_ETH_MTU, p->tot_len); 414 p->tot_len = USB_ETH_MTU; 415 } 416 result = rt_sem_take(&ecm_eth_dev->tx_buffer_free, RT_WAITING_FOREVER); 417 if(result != RT_EOK) 418 { 419 return result; 420 } 421 pbuffer = (char *)&ecm_eth_dev->tx_buffer; 422 for (q = p; q != NULL; q = q->next) 423 { 424 rt_memcpy(pbuffer, q->payload, q->len); 425 pbuffer += q->len; 426 } 427 428 { 429 if(ecm_eth_dev->func->device->state == USB_STATE_CONFIGURED) 430 { 431 ecm_eth_dev->eps.ep_in->request.buffer = (void *)&ecm_eth_dev->tx_buffer; 432 ecm_eth_dev->eps.ep_in->request.size = p->tot_len; 433 ecm_eth_dev->eps.ep_in->request.req_type = UIO_REQUEST_WRITE; 434 rt_usbd_io_request(ecm_eth_dev->func->device, ecm_eth_dev->eps.ep_in, &ecm_eth_dev->eps.ep_in->request); 435 } 436 } 437 438 return result; 439 } 440 /** 441 * This function will handle RNDIS interrupt in endpoint request. 442 * 443 * @param device the usb device object. 444 * @param size request size. 445 * 446 * @return RT_EOK. 447 */ 448 static rt_err_t _ep_cmd_handler(ufunction_t func, rt_size_t size) 449 { 450 return RT_EOK; 451 } 452 453 /** 454 * This function will run cdc class, it will be called on handle set configuration request. 455 * 456 * @param device the usb device object. 457 * 458 * @return RT_EOK on successful. 459 */ 460 static rt_err_t _function_enable(ufunction_t func) 461 { 462 cdc_eps_t eps; 463 rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data; 464 eps = (cdc_eps_t)&ecm_device->eps; 465 eps->ep_out->buffer = ecm_device->rx_pool; 466 ecm_device->rx_size = 0; 467 ecm_device->rx_offset = 0; 468 469 eps->ep_out->request.buffer = (void *)eps->ep_out->buffer; 470 eps->ep_out->request.size = EP_MAXPACKET(eps->ep_out); 471 eps->ep_out->request.req_type = UIO_REQUEST_READ_BEST; 472 rt_usbd_io_request(func->device, eps->ep_out, &eps->ep_out->request); 473 return RT_EOK; 474 } 475 476 /** 477 * This function will stop cdc class, it will be called on handle set configuration request. 478 * 479 * @param device the usb device object. 480 * 481 * @return RT_EOK on successful. 482 */ 483 static rt_err_t _function_disable(ufunction_t func) 484 { 485 eth_device_linkchange(&((rt_ecm_eth_t)func->user_data)->parent, RT_FALSE); 486 return RT_EOK; 487 } 488 489 490 static struct ufunction_ops ops = 491 { 492 _function_enable, 493 _function_disable, 494 RT_NULL, 495 }; 496 497 /** 498 * This function will configure cdc descriptor. 499 * 500 * @param comm the communication interface number. 501 * @param data the data interface number. 502 * 503 * @return RT_EOK on successful. 504 */ 505 static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm, rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr, rt_uint8_t device_is_hs) 506 { 507 comm->call_mgmt_desc.data_interface = dintf_nr; 508 comm->union_desc.master_interface = cintf_nr; 509 comm->union_desc.slave_interface0 = dintf_nr; 510 #ifdef RT_USB_DEVICE_COMPOSITE 511 comm->iad_desc.bFirstInterface = cintf_nr; 512 #endif 513 data->ep_out_desc.wMaxPacketSize = device_is_hs ? 512 : 64; 514 data->ep_in_desc.wMaxPacketSize = device_is_hs ? 512 : 64; 515 return RT_EOK; 516 } 517 518 519 520 /** 521 * This function will create a cdc ecm class instance. 522 * 523 * @param device the usb device object. 524 * 525 * @return RT_EOK on successful. 526 */ 527 ufunction_t rt_usbd_function_ecm_create(udevice_t device) 528 { 529 ufunction_t cdc; 530 rt_ecm_eth_t _ecm_eth; 531 cdc_eps_t eps; 532 uintf_t intf_comm, intf_data; 533 ualtsetting_t comm_setting, data_setting; 534 ucdc_data_desc_t data_desc; 535 ucdc_eth_desc_t comm_desc; 536 537 /* parameter check */ 538 RT_ASSERT(device != RT_NULL); 539 540 /* set usb device string description */ 541 rt_usbd_device_set_string(device, _ustring); 542 543 /* create a cdc class */ 544 cdc = rt_usbd_function_new(device, &_dev_desc, &ops); 545 rt_usbd_device_set_qualifier(device, &dev_qualifier); 546 _ecm_eth= rt_malloc(sizeof(struct rt_ecm_eth)); 547 rt_memset(_ecm_eth, 0, sizeof(struct rt_ecm_eth)); 548 cdc->user_data = _ecm_eth; 549 550 _ecm_eth->func = cdc; 551 /* create a cdc class endpoints collection */ 552 eps = &_ecm_eth->eps; 553 /* create a cdc communication interface and a cdc data interface */ 554 intf_comm = rt_usbd_interface_new(device, _interface_handler); 555 intf_data = rt_usbd_interface_new(device, _interface_handler); 556 557 /* create a communication alternate setting and a data alternate setting */ 558 comm_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_eth_descriptor)); 559 data_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_data_descriptor)); 560 561 /* config desc in alternate setting */ 562 rt_usbd_altsetting_config_descriptor(comm_setting, &_comm_desc, 563 (rt_off_t)&((ucdc_eth_desc_t)0)->intf_desc); 564 rt_usbd_altsetting_config_descriptor(data_setting, &_data_desc, 0); 565 /* configure the cdc interface descriptor */ 566 _cdc_descriptor_config(comm_setting->desc, intf_comm->intf_num, data_setting->desc, intf_data->intf_num, device->dcd->device_is_hs); 567 568 /* create a command endpoint */ 569 comm_desc = (ucdc_eth_desc_t)comm_setting->desc; 570 eps->ep_cmd = rt_usbd_endpoint_new(&comm_desc->ep_desc, _ep_cmd_handler); 571 /* add the command endpoint to the cdc communication interface */ 572 rt_usbd_altsetting_add_endpoint(comm_setting, eps->ep_cmd); 573 574 /* add the communication alternate setting to the communication interface, 575 then set default setting of the interface */ 576 rt_usbd_interface_add_altsetting(intf_comm, comm_setting); 577 rt_usbd_set_altsetting(intf_comm, 0); 578 /* add the communication interface to the cdc class */ 579 rt_usbd_function_add_interface(cdc, intf_comm); 580 581 /* create a bulk in and a bulk out endpoint */ 582 data_desc = (ucdc_data_desc_t)data_setting->desc; 583 eps->ep_out = rt_usbd_endpoint_new(&data_desc->ep_out_desc, _ep_out_handler); 584 eps->ep_in = rt_usbd_endpoint_new(&data_desc->ep_in_desc, _ep_in_handler); 585 586 /* add the bulk out and bulk in endpoints to the data alternate setting */ 587 rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_in); 588 rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_out); 589 590 /* add the data alternate setting to the data interface 591 then set default setting of the interface */ 592 rt_usbd_interface_add_altsetting(intf_data, data_setting); 593 rt_usbd_set_altsetting(intf_data, 0); 594 595 /* add the cdc data interface to cdc class */ 596 rt_usbd_function_add_interface(cdc, intf_data); 597 598 rt_sem_init(&_ecm_eth->tx_buffer_free, "ue_tx", 1, RT_IPC_FLAG_FIFO); 599 /* OUI 00-00-00, only for test. */ 600 _ecm_eth->dev_addr[0] = 0x34; 601 _ecm_eth->dev_addr[1] = 0x97; 602 _ecm_eth->dev_addr[2] = 0xF6; 603 /* generate random MAC. */ 604 _ecm_eth->dev_addr[3] = 0x94;//*(const rt_uint8_t *)(0x1fff7a10); 605 _ecm_eth->dev_addr[4] = 0xEC;//*(const rt_uint8_t *)(0x1fff7a14); 606 _ecm_eth->dev_addr[5] = 0xAC;//(const rt_uint8_t *)(0x1fff7a18); 607 /* OUI 00-00-00, only for test. */ 608 _ecm_eth->host_addr[0] = 0x34; 609 _ecm_eth->host_addr[1] = 0x97; 610 _ecm_eth->host_addr[2] = 0xF6; 611 /* generate random MAC. */ 612 _ecm_eth->host_addr[3] = 0x94;//*(const rt_uint8_t *)(0x1fff7a10); 613 _ecm_eth->host_addr[4] = 0xEC;//*(const rt_uint8_t *)(0x1fff7a14); 614 _ecm_eth->host_addr[5] = 0xAB;//*(const rt_uint8_t *)(0x1fff7a18); 615 616 _ecm_eth->parent.parent.init = rt_ecm_eth_init; 617 _ecm_eth->parent.parent.open = rt_ecm_eth_open; 618 _ecm_eth->parent.parent.close = rt_ecm_eth_close; 619 _ecm_eth->parent.parent.read = rt_ecm_eth_read; 620 _ecm_eth->parent.parent.write = rt_ecm_eth_write; 621 _ecm_eth->parent.parent.control = rt_ecm_eth_control; 622 _ecm_eth->parent.parent.user_data = device; 623 624 _ecm_eth->parent.eth_rx = rt_ecm_eth_rx; 625 _ecm_eth->parent.eth_tx = rt_ecm_eth_tx; 626 /* register eth device */ 627 eth_device_init(&_ecm_eth->parent, "u0"); 628 629 /* send link up. */ 630 eth_device_linkchange(&_ecm_eth->parent, RT_FALSE); 631 632 return cdc; 633 } 634 635 struct udclass ecm_class = 636 { 637 .rt_usbd_function_create = rt_usbd_function_ecm_create 638 }; 639 640 int rt_usbd_ecm_class_register(void) 641 { 642 rt_usbd_class_register(&ecm_class); 643 return 0; 644 } 645 INIT_PREV_EXPORT(rt_usbd_ecm_class_register); 646