You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ecm.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. /*
  2. * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. #include <stdint.h>
  21. #include <errno.h>
  22. #include <ipxe/netdevice.h>
  23. #include <ipxe/ethernet.h>
  24. #include <ipxe/if_ether.h>
  25. #include <ipxe/base16.h>
  26. #include <ipxe/profile.h>
  27. #include <ipxe/usb.h>
  28. #include "ecm.h"
  29. /** @file
  30. *
  31. * CDC-ECM USB Ethernet driver
  32. *
  33. */
  34. /** Interrupt completion profiler */
  35. static struct profiler ecm_intr_profiler __profiler =
  36. { .name = "ecm.intr" };
  37. /** Bulk IN completion profiler */
  38. static struct profiler ecm_in_profiler __profiler =
  39. { .name = "ecm.in" };
  40. /** Bulk OUT profiler */
  41. static struct profiler ecm_out_profiler __profiler =
  42. { .name = "ecm.out" };
  43. /******************************************************************************
  44. *
  45. * Ethernet functional descriptor
  46. *
  47. ******************************************************************************
  48. */
  49. /**
  50. * Locate Ethernet functional descriptor
  51. *
  52. * @v config Configuration descriptor
  53. * @v interface Interface descriptor
  54. * @ret desc Descriptor, or NULL if not found
  55. */
  56. struct ecm_ethernet_descriptor *
  57. ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
  58. struct usb_interface_descriptor *interface ) {
  59. struct ecm_ethernet_descriptor *desc;
  60. for_each_interface_descriptor ( desc, config, interface ) {
  61. if ( ( desc->header.type == USB_CS_INTERFACE_DESCRIPTOR ) &&
  62. ( desc->subtype == CDC_SUBTYPE_ETHERNET ) )
  63. return desc;
  64. }
  65. return NULL;
  66. }
  67. /**
  68. * Get hardware MAC address
  69. *
  70. * @v usb USB device
  71. * @v desc Ethernet functional descriptor
  72. * @v hw_addr Hardware address to fill in
  73. * @ret rc Return status code
  74. */
  75. int ecm_fetch_mac ( struct usb_device *usb,
  76. struct ecm_ethernet_descriptor *desc, uint8_t *hw_addr ) {
  77. char buf[ base16_encoded_len ( ETH_ALEN ) + 1 /* NUL */ ];
  78. int len;
  79. int rc;
  80. /* Fetch MAC address string */
  81. len = usb_get_string_descriptor ( usb, desc->mac, 0, buf,
  82. sizeof ( buf ) );
  83. if ( len < 0 ) {
  84. rc = len;
  85. return rc;
  86. }
  87. /* Sanity check */
  88. if ( len != ( ( int ) ( sizeof ( buf ) - 1 /* NUL */ ) ) )
  89. return -EINVAL;
  90. /* Decode MAC address */
  91. len = base16_decode ( buf, hw_addr );
  92. if ( len < 0 ) {
  93. rc = len;
  94. return rc;
  95. }
  96. return 0;
  97. }
  98. /******************************************************************************
  99. *
  100. * CDC-ECM communications interface
  101. *
  102. ******************************************************************************
  103. */
  104. /**
  105. * Complete interrupt transfer
  106. *
  107. * @v ep USB endpoint
  108. * @v iobuf I/O buffer
  109. * @v rc Completion status code
  110. */
  111. static void ecm_intr_complete ( struct usb_endpoint *ep,
  112. struct io_buffer *iobuf, int rc ) {
  113. struct ecm_device *ecm = container_of ( ep, struct ecm_device, intr );
  114. struct net_device *netdev = ecm->netdev;
  115. struct usb_setup_packet *message;
  116. size_t len = iob_len ( iobuf );
  117. /* Profile completions */
  118. profile_start ( &ecm_intr_profiler );
  119. /* Ignore packets cancelled when the endpoint closes */
  120. if ( ! ep->open )
  121. goto ignore;
  122. /* Drop packets with errors */
  123. if ( rc != 0 ) {
  124. DBGC ( ecm, "ECM %p interrupt failed: %s\n",
  125. ecm, strerror ( rc ) );
  126. DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
  127. goto error;
  128. }
  129. /* Extract message header */
  130. if ( len < sizeof ( *message ) ) {
  131. DBGC ( ecm, "ECM %p underlength interrupt:\n", ecm );
  132. DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
  133. rc = -EINVAL;
  134. goto error;
  135. }
  136. message = iobuf->data;
  137. /* Parse message header */
  138. switch ( message->request ) {
  139. case cpu_to_le16 ( CDC_NETWORK_CONNECTION ) :
  140. if ( message->value && ! netdev_link_ok ( netdev ) ) {
  141. DBGC ( ecm, "ECM %p link up\n", ecm );
  142. netdev_link_up ( netdev );
  143. } else if ( netdev_link_ok ( netdev ) && ! message->value ) {
  144. DBGC ( ecm, "ECM %p link down\n", ecm );
  145. netdev_link_down ( netdev );
  146. }
  147. break;
  148. case cpu_to_le16 ( CDC_CONNECTION_SPEED_CHANGE ) :
  149. /* Ignore */
  150. break;
  151. default:
  152. DBGC ( ecm, "ECM %p unrecognised interrupt:\n", ecm );
  153. DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
  154. rc = -ENOTSUP;
  155. goto error;
  156. }
  157. /* Free I/O buffer */
  158. free_iob ( iobuf );
  159. profile_stop ( &ecm_intr_profiler );
  160. return;
  161. error:
  162. netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
  163. ignore:
  164. free_iob ( iobuf );
  165. return;
  166. }
  167. /** Interrupt endpoint operations */
  168. static struct usb_endpoint_driver_operations ecm_intr_operations = {
  169. .complete = ecm_intr_complete,
  170. };
  171. /**
  172. * Open communications interface
  173. *
  174. * @v ecm CDC-ECM device
  175. * @ret rc Return status code
  176. */
  177. static int ecm_comms_open ( struct ecm_device *ecm ) {
  178. int rc;
  179. /* Open interrupt endpoint */
  180. if ( ( rc = usb_endpoint_open ( &ecm->intr ) ) != 0 ) {
  181. DBGC ( ecm, "ECM %p could not open interrupt: %s\n",
  182. ecm, strerror ( rc ) );
  183. goto err_open;
  184. }
  185. /* Refill interrupt endpoint */
  186. usb_refill ( &ecm->intr );
  187. return 0;
  188. usb_endpoint_close ( &ecm->intr );
  189. err_open:
  190. return rc;
  191. }
  192. /**
  193. * Close communications interface
  194. *
  195. * @v ecm CDC-ECM device
  196. */
  197. static void ecm_comms_close ( struct ecm_device *ecm ) {
  198. /* Close interrupt endpoint */
  199. usb_endpoint_close ( &ecm->intr );
  200. }
  201. /******************************************************************************
  202. *
  203. * CDC-ECM data interface
  204. *
  205. ******************************************************************************
  206. */
  207. /**
  208. * Complete bulk IN transfer
  209. *
  210. * @v ep USB endpoint
  211. * @v iobuf I/O buffer
  212. * @v rc Completion status code
  213. */
  214. static void ecm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
  215. int rc ) {
  216. struct ecm_device *ecm = container_of ( ep, struct ecm_device, in );
  217. struct net_device *netdev = ecm->netdev;
  218. /* Profile receive completions */
  219. profile_start ( &ecm_in_profiler );
  220. /* Ignore packets cancelled when the endpoint closes */
  221. if ( ! ep->open )
  222. goto ignore;
  223. /* Record USB errors against the network device */
  224. if ( rc != 0 ) {
  225. DBGC ( ecm, "ECM %p bulk IN failed: %s\n",
  226. ecm, strerror ( rc ) );
  227. goto error;
  228. }
  229. /* Hand off to network stack */
  230. netdev_rx ( netdev, iob_disown ( iobuf ) );
  231. profile_stop ( &ecm_in_profiler );
  232. return;
  233. error:
  234. netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
  235. ignore:
  236. free_iob ( iobuf );
  237. }
  238. /** Bulk IN endpoint operations */
  239. static struct usb_endpoint_driver_operations ecm_in_operations = {
  240. .complete = ecm_in_complete,
  241. };
  242. /**
  243. * Transmit packet
  244. *
  245. * @v ecm CDC-ECM device
  246. * @v iobuf I/O buffer
  247. * @ret rc Return status code
  248. */
  249. static int ecm_out_transmit ( struct ecm_device *ecm,
  250. struct io_buffer *iobuf ) {
  251. int rc;
  252. /* Profile transmissions */
  253. profile_start ( &ecm_out_profiler );
  254. /* Enqueue I/O buffer */
  255. if ( ( rc = usb_stream ( &ecm->out, iobuf, 1 ) ) != 0 )
  256. return rc;
  257. profile_stop ( &ecm_out_profiler );
  258. return 0;
  259. }
  260. /**
  261. * Complete bulk OUT transfer
  262. *
  263. * @v ep USB endpoint
  264. * @v iobuf I/O buffer
  265. * @v rc Completion status code
  266. */
  267. static void ecm_out_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
  268. int rc ) {
  269. struct ecm_device *ecm = container_of ( ep, struct ecm_device, out );
  270. struct net_device *netdev = ecm->netdev;
  271. /* Report TX completion */
  272. netdev_tx_complete_err ( netdev, iobuf, rc );
  273. }
  274. /** Bulk OUT endpoint operations */
  275. static struct usb_endpoint_driver_operations ecm_out_operations = {
  276. .complete = ecm_out_complete,
  277. };
  278. /**
  279. * Open data interface
  280. *
  281. * @v ecm CDC-ECM device
  282. * @ret rc Return status code
  283. */
  284. static int ecm_data_open ( struct ecm_device *ecm ) {
  285. struct usb_device *usb = ecm->usb;
  286. int rc;
  287. /* Select alternate setting for data interface */
  288. if ( ( rc = usb_set_interface ( usb, ecm->data,
  289. ECM_DATA_ALTERNATE ) ) != 0 ) {
  290. DBGC ( ecm, "ECM %p could not set alternate interface: %s\n",
  291. ecm, strerror ( rc ) );
  292. goto err_set_interface;
  293. }
  294. /* Open bulk IN endpoint */
  295. if ( ( rc = usb_endpoint_open ( &ecm->in ) ) != 0 ) {
  296. DBGC ( ecm, "ECM %p could not open bulk IN: %s\n",
  297. ecm, strerror ( rc ) );
  298. goto err_open_in;
  299. }
  300. /* Open bulk OUT endpoint */
  301. if ( ( rc = usb_endpoint_open ( &ecm->out ) ) != 0 ) {
  302. DBGC ( ecm, "ECM %p could not open bulk OUT: %s\n",
  303. ecm, strerror ( rc ) );
  304. goto err_open_out;
  305. }
  306. /* Refill bulk IN endpoint */
  307. usb_refill ( &ecm->in );
  308. return 0;
  309. usb_endpoint_close ( &ecm->out );
  310. err_open_out:
  311. usb_endpoint_close ( &ecm->in );
  312. err_open_in:
  313. usb_set_interface ( usb, ecm->data, 0 );
  314. err_set_interface:
  315. return rc;
  316. }
  317. /**
  318. * Close data interface
  319. *
  320. * @v ecm CDC-ECM device
  321. */
  322. static void ecm_data_close ( struct ecm_device *ecm ) {
  323. struct usb_device *usb = ecm->usb;
  324. /* Close endpoints */
  325. usb_endpoint_close ( &ecm->out );
  326. usb_endpoint_close ( &ecm->in );
  327. /* Reset data interface */
  328. usb_set_interface ( usb, ecm->data, 0 );
  329. }
  330. /******************************************************************************
  331. *
  332. * Network device interface
  333. *
  334. ******************************************************************************
  335. */
  336. /**
  337. * Open network device
  338. *
  339. * @v netdev Network device
  340. * @ret rc Return status code
  341. */
  342. static int ecm_open ( struct net_device *netdev ) {
  343. struct ecm_device *ecm = netdev->priv;
  344. struct usb_device *usb = ecm->usb;
  345. unsigned int filter;
  346. int rc;
  347. /* Open communications interface */
  348. if ( ( rc = ecm_comms_open ( ecm ) ) != 0 )
  349. goto err_comms_open;
  350. /* Open data interface */
  351. if ( ( rc = ecm_data_open ( ecm ) ) != 0 )
  352. goto err_data_open;
  353. /* Set packet filter */
  354. filter = ( ECM_PACKET_TYPE_PROMISCUOUS |
  355. ECM_PACKET_TYPE_ALL_MULTICAST |
  356. ECM_PACKET_TYPE_DIRECTED |
  357. ECM_PACKET_TYPE_BROADCAST );
  358. if ( ( rc = usb_control ( usb, ECM_SET_ETHERNET_PACKET_FILTER,
  359. filter, ecm->comms, NULL, 0 ) ) != 0 ) {
  360. DBGC ( ecm, "ECM %p could not set packet filter: %s\n",
  361. ecm, strerror ( rc ) );
  362. goto err_set_filter;
  363. }
  364. return 0;
  365. err_set_filter:
  366. ecm_data_close ( ecm );
  367. err_data_open:
  368. ecm_comms_close ( ecm );
  369. err_comms_open:
  370. return rc;
  371. }
  372. /**
  373. * Close network device
  374. *
  375. * @v netdev Network device
  376. */
  377. static void ecm_close ( struct net_device *netdev ) {
  378. struct ecm_device *ecm = netdev->priv;
  379. /* Close data interface */
  380. ecm_data_close ( ecm );
  381. /* Close communications interface */
  382. ecm_comms_close ( ecm );
  383. }
  384. /**
  385. * Transmit packet
  386. *
  387. * @v netdev Network device
  388. * @v iobuf I/O buffer
  389. * @ret rc Return status code
  390. */
  391. static int ecm_transmit ( struct net_device *netdev,
  392. struct io_buffer *iobuf ) {
  393. struct ecm_device *ecm = netdev->priv;
  394. int rc;
  395. /* Transmit packet */
  396. if ( ( rc = ecm_out_transmit ( ecm, iobuf ) ) != 0 )
  397. return rc;
  398. return 0;
  399. }
  400. /**
  401. * Poll for completed and received packets
  402. *
  403. * @v netdev Network device
  404. */
  405. static void ecm_poll ( struct net_device *netdev ) {
  406. struct ecm_device *ecm = netdev->priv;
  407. int rc;
  408. /* Poll USB bus */
  409. usb_poll ( ecm->bus );
  410. /* Refill interrupt endpoint */
  411. if ( ( rc = usb_refill ( &ecm->intr ) ) != 0 )
  412. netdev_rx_err ( netdev, NULL, rc );
  413. /* Refill bulk IN endpoint */
  414. if ( ( rc = usb_refill ( &ecm->in ) ) != 0 )
  415. netdev_rx_err ( netdev, NULL, rc );
  416. }
  417. /** CDC-ECM network device operations */
  418. static struct net_device_operations ecm_operations = {
  419. .open = ecm_open,
  420. .close = ecm_close,
  421. .transmit = ecm_transmit,
  422. .poll = ecm_poll,
  423. };
  424. /******************************************************************************
  425. *
  426. * USB interface
  427. *
  428. ******************************************************************************
  429. */
  430. /**
  431. * Probe device
  432. *
  433. * @v func USB function
  434. * @v config Configuration descriptor
  435. * @ret rc Return status code
  436. */
  437. static int ecm_probe ( struct usb_function *func,
  438. struct usb_configuration_descriptor *config ) {
  439. struct usb_device *usb = func->usb;
  440. struct net_device *netdev;
  441. struct ecm_device *ecm;
  442. struct usb_interface_descriptor *comms;
  443. struct usb_interface_descriptor *data;
  444. struct ecm_ethernet_descriptor *ethernet;
  445. int rc;
  446. /* Allocate and initialise structure */
  447. netdev = alloc_etherdev ( sizeof ( *ecm ) );
  448. if ( ! netdev ) {
  449. rc = -ENOMEM;
  450. goto err_alloc;
  451. }
  452. netdev_init ( netdev, &ecm_operations );
  453. netdev->dev = &func->dev;
  454. ecm = netdev->priv;
  455. memset ( ecm, 0, sizeof ( *ecm ) );
  456. ecm->usb = usb;
  457. ecm->bus = usb->port->hub->bus;
  458. ecm->netdev = netdev;
  459. usb_endpoint_init ( &ecm->intr, usb, &ecm_intr_operations );
  460. usb_endpoint_init ( &ecm->in, usb, &ecm_in_operations );
  461. usb_endpoint_init ( &ecm->out, usb, &ecm_out_operations );
  462. usb_refill_init ( &ecm->intr, 0, ECM_INTR_MAX_FILL );
  463. usb_refill_init ( &ecm->in, ECM_IN_MTU, ECM_IN_MAX_FILL );
  464. DBGC ( ecm, "ECM %p on %s\n", ecm, func->name );
  465. /* Identify interfaces */
  466. if ( func->count < ECM_INTERFACE_COUNT ) {
  467. DBGC ( ecm, "ECM %p has only %d interfaces\n",
  468. ecm, func->count );
  469. rc = -EINVAL;
  470. goto err_count;
  471. }
  472. ecm->comms = func->interface[ECM_INTERFACE_COMMS];
  473. ecm->data = func->interface[ECM_INTERFACE_DATA];
  474. /* Locate communications interface descriptor */
  475. comms = usb_interface_descriptor ( config, ecm->comms, 0 );
  476. if ( ! comms ) {
  477. DBGC ( ecm, "ECM %p has no communications interface\n", ecm );
  478. rc = -EINVAL;
  479. goto err_comms;
  480. }
  481. /* Locate data interface descriptor */
  482. data = usb_interface_descriptor ( config, ecm->data,
  483. ECM_DATA_ALTERNATE );
  484. if ( ! data ) {
  485. DBGC ( ecm, "ECM %p has no data interface\n", ecm );
  486. rc = -EINVAL;
  487. goto err_data;
  488. }
  489. /* Describe interrupt endpoint */
  490. if ( ( rc = usb_endpoint_described ( &ecm->intr, config, comms,
  491. USB_INTERRUPT, 0 ) ) != 0 ) {
  492. DBGC ( ecm, "ECM %p could not describe interrupt endpoint: "
  493. "%s\n", ecm, strerror ( rc ) );
  494. goto err_interrupt;
  495. }
  496. /* Describe bulk IN endpoint */
  497. if ( ( rc = usb_endpoint_described ( &ecm->in, config, data,
  498. USB_BULK_IN, 0 ) ) != 0 ) {
  499. DBGC ( ecm, "ECM %p could not describe bulk IN endpoint: "
  500. "%s\n", ecm, strerror ( rc ) );
  501. goto err_bulk_in;
  502. }
  503. /* Describe bulk OUT endpoint */
  504. if ( ( rc = usb_endpoint_described ( &ecm->out, config, data,
  505. USB_BULK_OUT, 0 ) ) != 0 ) {
  506. DBGC ( ecm, "ECM %p could not describe bulk OUT endpoint: "
  507. "%s\n", ecm, strerror ( rc ) );
  508. goto err_bulk_out;
  509. }
  510. /* Locate Ethernet descriptor */
  511. ethernet = ecm_ethernet_descriptor ( config, comms );
  512. if ( ! ethernet ) {
  513. DBGC ( ecm, "ECM %p has no Ethernet descriptor\n", ecm );
  514. rc = -EINVAL;
  515. goto err_ethernet;
  516. }
  517. /* Fetch MAC address */
  518. if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
  519. DBGC ( ecm, "ECM %p could not fetch MAC address: %s\n",
  520. ecm, strerror ( rc ) );
  521. goto err_fetch_mac;
  522. }
  523. /* Register network device */
  524. if ( ( rc = register_netdev ( netdev ) ) != 0 )
  525. goto err_register;
  526. usb_func_set_drvdata ( func, ecm );
  527. return 0;
  528. unregister_netdev ( netdev );
  529. err_register:
  530. err_fetch_mac:
  531. err_ethernet:
  532. err_bulk_out:
  533. err_bulk_in:
  534. err_interrupt:
  535. err_data:
  536. err_comms:
  537. err_count:
  538. netdev_nullify ( netdev );
  539. netdev_put ( netdev );
  540. err_alloc:
  541. return rc;
  542. }
  543. /**
  544. * Remove device
  545. *
  546. * @v func USB function
  547. */
  548. static void ecm_remove ( struct usb_function *func ) {
  549. struct ecm_device *ecm = usb_func_get_drvdata ( func );
  550. struct net_device *netdev = ecm->netdev;
  551. unregister_netdev ( netdev );
  552. netdev_nullify ( netdev );
  553. netdev_put ( netdev );
  554. }
  555. /** CDC-ECM device IDs */
  556. static struct usb_device_id ecm_ids[] = {
  557. {
  558. .name = "cdc-ecm",
  559. .vendor = USB_ANY_ID,
  560. .product = USB_ANY_ID,
  561. .class = {
  562. .class = USB_CLASS_CDC,
  563. .subclass = USB_SUBCLASS_CDC_ECM,
  564. .protocol = 0,
  565. },
  566. },
  567. };
  568. /** CDC-ECM driver */
  569. struct usb_driver ecm_driver __usb_driver = {
  570. .ids = ecm_ids,
  571. .id_count = ( sizeof ( ecm_ids ) / sizeof ( ecm_ids[0] ) ),
  572. .probe = ecm_probe,
  573. .remove = ecm_remove,
  574. };