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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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,
  114. usbnet.intr );
  115. struct net_device *netdev = ecm->netdev;
  116. struct usb_setup_packet *message;
  117. size_t len = iob_len ( iobuf );
  118. /* Profile completions */
  119. profile_start ( &ecm_intr_profiler );
  120. /* Ignore packets cancelled when the endpoint closes */
  121. if ( ! ep->open )
  122. goto ignore;
  123. /* Drop packets with errors */
  124. if ( rc != 0 ) {
  125. DBGC ( ecm, "ECM %p interrupt failed: %s\n",
  126. ecm, strerror ( rc ) );
  127. DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
  128. goto error;
  129. }
  130. /* Extract message header */
  131. if ( len < sizeof ( *message ) ) {
  132. DBGC ( ecm, "ECM %p underlength interrupt:\n", ecm );
  133. DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
  134. rc = -EINVAL;
  135. goto error;
  136. }
  137. message = iobuf->data;
  138. /* Parse message header */
  139. switch ( message->request ) {
  140. case cpu_to_le16 ( CDC_NETWORK_CONNECTION ) :
  141. if ( message->value && ! netdev_link_ok ( netdev ) ) {
  142. DBGC ( ecm, "ECM %p link up\n", ecm );
  143. netdev_link_up ( netdev );
  144. } else if ( netdev_link_ok ( netdev ) && ! message->value ) {
  145. DBGC ( ecm, "ECM %p link down\n", ecm );
  146. netdev_link_down ( netdev );
  147. }
  148. break;
  149. case cpu_to_le16 ( CDC_CONNECTION_SPEED_CHANGE ) :
  150. /* Ignore */
  151. break;
  152. default:
  153. DBGC ( ecm, "ECM %p unrecognised interrupt:\n", ecm );
  154. DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
  155. rc = -ENOTSUP;
  156. goto error;
  157. }
  158. /* Free I/O buffer */
  159. free_iob ( iobuf );
  160. profile_stop ( &ecm_intr_profiler );
  161. return;
  162. error:
  163. netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
  164. ignore:
  165. free_iob ( iobuf );
  166. return;
  167. }
  168. /** Interrupt endpoint operations */
  169. static struct usb_endpoint_driver_operations ecm_intr_operations = {
  170. .complete = ecm_intr_complete,
  171. };
  172. /******************************************************************************
  173. *
  174. * CDC-ECM data interface
  175. *
  176. ******************************************************************************
  177. */
  178. /**
  179. * Complete bulk IN transfer
  180. *
  181. * @v ep USB endpoint
  182. * @v iobuf I/O buffer
  183. * @v rc Completion status code
  184. */
  185. static void ecm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
  186. int rc ) {
  187. struct ecm_device *ecm = container_of ( ep, struct ecm_device,
  188. usbnet.in );
  189. struct net_device *netdev = ecm->netdev;
  190. /* Profile receive completions */
  191. profile_start ( &ecm_in_profiler );
  192. /* Ignore packets cancelled when the endpoint closes */
  193. if ( ! ep->open )
  194. goto ignore;
  195. /* Record USB errors against the network device */
  196. if ( rc != 0 ) {
  197. DBGC ( ecm, "ECM %p bulk IN failed: %s\n",
  198. ecm, strerror ( rc ) );
  199. goto error;
  200. }
  201. /* Hand off to network stack */
  202. netdev_rx ( netdev, iob_disown ( iobuf ) );
  203. profile_stop ( &ecm_in_profiler );
  204. return;
  205. error:
  206. netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
  207. ignore:
  208. free_iob ( iobuf );
  209. }
  210. /** Bulk IN endpoint operations */
  211. static struct usb_endpoint_driver_operations ecm_in_operations = {
  212. .complete = ecm_in_complete,
  213. };
  214. /**
  215. * Transmit packet
  216. *
  217. * @v ecm CDC-ECM device
  218. * @v iobuf I/O buffer
  219. * @ret rc Return status code
  220. */
  221. static int ecm_out_transmit ( struct ecm_device *ecm,
  222. struct io_buffer *iobuf ) {
  223. int rc;
  224. /* Profile transmissions */
  225. profile_start ( &ecm_out_profiler );
  226. /* Enqueue I/O buffer */
  227. if ( ( rc = usb_stream ( &ecm->usbnet.out, iobuf, 1 ) ) != 0 )
  228. return rc;
  229. profile_stop ( &ecm_out_profiler );
  230. return 0;
  231. }
  232. /**
  233. * Complete bulk OUT transfer
  234. *
  235. * @v ep USB endpoint
  236. * @v iobuf I/O buffer
  237. * @v rc Completion status code
  238. */
  239. static void ecm_out_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
  240. int rc ) {
  241. struct ecm_device *ecm = container_of ( ep, struct ecm_device,
  242. usbnet.out );
  243. struct net_device *netdev = ecm->netdev;
  244. /* Report TX completion */
  245. netdev_tx_complete_err ( netdev, iobuf, rc );
  246. }
  247. /** Bulk OUT endpoint operations */
  248. static struct usb_endpoint_driver_operations ecm_out_operations = {
  249. .complete = ecm_out_complete,
  250. };
  251. /******************************************************************************
  252. *
  253. * Network device interface
  254. *
  255. ******************************************************************************
  256. */
  257. /**
  258. * Open network device
  259. *
  260. * @v netdev Network device
  261. * @ret rc Return status code
  262. */
  263. static int ecm_open ( struct net_device *netdev ) {
  264. struct ecm_device *ecm = netdev->priv;
  265. struct usb_device *usb = ecm->usb;
  266. unsigned int filter;
  267. int rc;
  268. /* Open USB network device */
  269. if ( ( rc = usbnet_open ( &ecm->usbnet ) ) != 0 ) {
  270. DBGC ( ecm, "ECM %p could not open: %s\n",
  271. ecm, strerror ( rc ) );
  272. goto err_open;
  273. }
  274. /* Set packet filter */
  275. filter = ( ECM_PACKET_TYPE_PROMISCUOUS |
  276. ECM_PACKET_TYPE_ALL_MULTICAST |
  277. ECM_PACKET_TYPE_DIRECTED |
  278. ECM_PACKET_TYPE_BROADCAST );
  279. if ( ( rc = usb_control ( usb, ECM_SET_ETHERNET_PACKET_FILTER,
  280. filter, ecm->usbnet.comms, NULL, 0 ) ) != 0 ){
  281. DBGC ( ecm, "ECM %p could not set packet filter: %s\n",
  282. ecm, strerror ( rc ) );
  283. goto err_set_filter;
  284. }
  285. return 0;
  286. err_set_filter:
  287. usbnet_close ( &ecm->usbnet );
  288. err_open:
  289. return rc;
  290. }
  291. /**
  292. * Close network device
  293. *
  294. * @v netdev Network device
  295. */
  296. static void ecm_close ( struct net_device *netdev ) {
  297. struct ecm_device *ecm = netdev->priv;
  298. /* Close USB network device */
  299. usbnet_close ( &ecm->usbnet );
  300. }
  301. /**
  302. * Transmit packet
  303. *
  304. * @v netdev Network device
  305. * @v iobuf I/O buffer
  306. * @ret rc Return status code
  307. */
  308. static int ecm_transmit ( struct net_device *netdev,
  309. struct io_buffer *iobuf ) {
  310. struct ecm_device *ecm = netdev->priv;
  311. int rc;
  312. /* Transmit packet */
  313. if ( ( rc = ecm_out_transmit ( ecm, iobuf ) ) != 0 )
  314. return rc;
  315. return 0;
  316. }
  317. /**
  318. * Poll for completed and received packets
  319. *
  320. * @v netdev Network device
  321. */
  322. static void ecm_poll ( struct net_device *netdev ) {
  323. struct ecm_device *ecm = netdev->priv;
  324. int rc;
  325. /* Poll USB bus */
  326. usb_poll ( ecm->bus );
  327. /* Refill endpoints */
  328. if ( ( rc = usbnet_refill ( &ecm->usbnet ) ) != 0 )
  329. netdev_rx_err ( netdev, NULL, rc );
  330. }
  331. /** CDC-ECM network device operations */
  332. static struct net_device_operations ecm_operations = {
  333. .open = ecm_open,
  334. .close = ecm_close,
  335. .transmit = ecm_transmit,
  336. .poll = ecm_poll,
  337. };
  338. /******************************************************************************
  339. *
  340. * USB interface
  341. *
  342. ******************************************************************************
  343. */
  344. /**
  345. * Probe device
  346. *
  347. * @v func USB function
  348. * @v config Configuration descriptor
  349. * @ret rc Return status code
  350. */
  351. static int ecm_probe ( struct usb_function *func,
  352. struct usb_configuration_descriptor *config ) {
  353. struct usb_device *usb = func->usb;
  354. struct net_device *netdev;
  355. struct ecm_device *ecm;
  356. struct usb_interface_descriptor *comms;
  357. struct ecm_ethernet_descriptor *ethernet;
  358. int rc;
  359. /* Allocate and initialise structure */
  360. netdev = alloc_etherdev ( sizeof ( *ecm ) );
  361. if ( ! netdev ) {
  362. rc = -ENOMEM;
  363. goto err_alloc;
  364. }
  365. netdev_init ( netdev, &ecm_operations );
  366. netdev->dev = &func->dev;
  367. ecm = netdev->priv;
  368. memset ( ecm, 0, sizeof ( *ecm ) );
  369. ecm->usb = usb;
  370. ecm->bus = usb->port->hub->bus;
  371. ecm->netdev = netdev;
  372. usbnet_init ( &ecm->usbnet, func, &ecm_intr_operations,
  373. &ecm_in_operations, &ecm_out_operations );
  374. usb_refill_init ( &ecm->usbnet.intr, 0, ECM_INTR_MAX_FILL );
  375. usb_refill_init ( &ecm->usbnet.in, ECM_IN_MTU, ECM_IN_MAX_FILL );
  376. DBGC ( ecm, "ECM %p on %s\n", ecm, func->name );
  377. /* Describe USB network device */
  378. if ( ( rc = usbnet_describe ( &ecm->usbnet, config ) ) != 0 ) {
  379. DBGC ( ecm, "ECM %p could not describe: %s\n",
  380. ecm, strerror ( rc ) );
  381. goto err_describe;
  382. }
  383. /* Locate Ethernet descriptor */
  384. comms = usb_interface_descriptor ( config, ecm->usbnet.comms, 0 );
  385. assert ( comms != NULL );
  386. ethernet = ecm_ethernet_descriptor ( config, comms );
  387. if ( ! ethernet ) {
  388. DBGC ( ecm, "ECM %p has no Ethernet descriptor\n", ecm );
  389. rc = -EINVAL;
  390. goto err_ethernet;
  391. }
  392. /* Fetch MAC address */
  393. if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
  394. DBGC ( ecm, "ECM %p could not fetch MAC address: %s\n",
  395. ecm, strerror ( rc ) );
  396. goto err_fetch_mac;
  397. }
  398. /* Register network device */
  399. if ( ( rc = register_netdev ( netdev ) ) != 0 )
  400. goto err_register;
  401. usb_func_set_drvdata ( func, ecm );
  402. return 0;
  403. unregister_netdev ( netdev );
  404. err_register:
  405. err_fetch_mac:
  406. err_ethernet:
  407. err_describe:
  408. netdev_nullify ( netdev );
  409. netdev_put ( netdev );
  410. err_alloc:
  411. return rc;
  412. }
  413. /**
  414. * Remove device
  415. *
  416. * @v func USB function
  417. */
  418. static void ecm_remove ( struct usb_function *func ) {
  419. struct ecm_device *ecm = usb_func_get_drvdata ( func );
  420. struct net_device *netdev = ecm->netdev;
  421. unregister_netdev ( netdev );
  422. netdev_nullify ( netdev );
  423. netdev_put ( netdev );
  424. }
  425. /** CDC-ECM device IDs */
  426. static struct usb_device_id ecm_ids[] = {
  427. {
  428. .name = "cdc-ecm",
  429. .vendor = USB_ANY_ID,
  430. .product = USB_ANY_ID,
  431. .class = {
  432. .class = USB_CLASS_CDC,
  433. .subclass = USB_SUBCLASS_CDC_ECM,
  434. .protocol = 0,
  435. },
  436. },
  437. };
  438. /** CDC-ECM driver */
  439. struct usb_driver ecm_driver __usb_driver = {
  440. .ids = ecm_ids,
  441. .id_count = ( sizeof ( ecm_ids ) / sizeof ( ecm_ids[0] ) ),
  442. .probe = ecm_probe,
  443. .remove = ecm_remove,
  444. };