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.

acm.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. /*
  2. * Copyright (C) 2015 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. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <stdint.h>
  25. #include <string.h>
  26. #include <errno.h>
  27. #include <byteswap.h>
  28. #include <ipxe/profile.h>
  29. #include <ipxe/usb.h>
  30. #include <ipxe/usbnet.h>
  31. #include <ipxe/rndis.h>
  32. #include "acm.h"
  33. /** @file
  34. *
  35. * USB RNDIS driver
  36. *
  37. */
  38. /** Interrupt completion profiler */
  39. static struct profiler acm_intr_profiler __profiler =
  40. { .name = "acm.intr" };
  41. /** Bulk IN completion profiler */
  42. static struct profiler acm_in_profiler __profiler =
  43. { .name = "acm.in" };
  44. /** Bulk OUT profiler */
  45. static struct profiler acm_out_profiler __profiler =
  46. { .name = "acm.out" };
  47. /******************************************************************************
  48. *
  49. * USB RNDIS communications interface
  50. *
  51. ******************************************************************************
  52. */
  53. /**
  54. * Complete interrupt transfer
  55. *
  56. * @v ep USB endpoint
  57. * @v iobuf I/O buffer
  58. * @v rc Completion status code
  59. */
  60. static void acm_intr_complete ( struct usb_endpoint *ep,
  61. struct io_buffer *iobuf, int rc ) {
  62. struct acm_device *acm = container_of ( ep, struct acm_device,
  63. usbnet.intr );
  64. struct rndis_device *rndis = acm->rndis;
  65. struct usb_setup_packet *message;
  66. /* Profile completions */
  67. profile_start ( &acm_intr_profiler );
  68. /* Ignore packets cancelled when the endpoint closes */
  69. if ( ! ep->open )
  70. goto ignore;
  71. /* Drop packets with errors */
  72. if ( rc != 0 ) {
  73. DBGC ( acm, "ACM %p interrupt failed: %s\n",
  74. acm, strerror ( rc ) );
  75. DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) );
  76. goto error;
  77. }
  78. /* Extract message header */
  79. if ( iob_len ( iobuf ) < sizeof ( *message ) ) {
  80. DBGC ( acm, "ACM %p underlength interrupt:\n", acm );
  81. DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) );
  82. rc = -EINVAL;
  83. goto error;
  84. }
  85. message = iobuf->data;
  86. /* Parse message header */
  87. switch ( message->request ) {
  88. case cpu_to_le16 ( CDC_RESPONSE_AVAILABLE ) :
  89. case cpu_to_le16 ( 0x0001 ) : /* qemu seems to use this value */
  90. acm->responded = 1;
  91. break;
  92. default:
  93. DBGC ( acm, "ACM %p unrecognised interrupt:\n", acm );
  94. DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) );
  95. rc = -ENOTSUP;
  96. goto error;
  97. }
  98. /* Free I/O buffer */
  99. free_iob ( iobuf );
  100. profile_stop ( &acm_intr_profiler );
  101. return;
  102. error:
  103. rndis_rx_err ( rndis, iob_disown ( iobuf ), rc );
  104. ignore:
  105. free_iob ( iobuf );
  106. return;
  107. }
  108. /** Interrupt endpoint operations */
  109. static struct usb_endpoint_driver_operations acm_intr_operations = {
  110. .complete = acm_intr_complete,
  111. };
  112. /******************************************************************************
  113. *
  114. * USB RNDIS data interface
  115. *
  116. ******************************************************************************
  117. */
  118. /**
  119. * Complete bulk IN transfer
  120. *
  121. * @v ep USB endpoint
  122. * @v iobuf I/O buffer
  123. * @v rc Completion status code
  124. */
  125. static void acm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
  126. int rc ) {
  127. struct acm_device *acm = container_of ( ep, struct acm_device,
  128. usbnet.in );
  129. struct rndis_device *rndis = acm->rndis;
  130. /* Profile receive completions */
  131. profile_start ( &acm_in_profiler );
  132. /* Ignore packets cancelled when the endpoint closes */
  133. if ( ! ep->open )
  134. goto ignore;
  135. /* Record USB errors against the RNDIS device */
  136. if ( rc != 0 ) {
  137. DBGC ( acm, "ACM %p bulk IN failed: %s\n",
  138. acm, strerror ( rc ) );
  139. goto error;
  140. }
  141. /* Hand off to RNDIS */
  142. rndis_rx ( rndis, iob_disown ( iobuf ) );
  143. profile_stop ( &acm_in_profiler );
  144. return;
  145. error:
  146. rndis_rx_err ( rndis, iob_disown ( iobuf ), rc );
  147. ignore:
  148. free_iob ( iobuf );
  149. }
  150. /** Bulk IN endpoint operations */
  151. static struct usb_endpoint_driver_operations acm_in_operations = {
  152. .complete = acm_in_complete,
  153. };
  154. /**
  155. * Transmit packet
  156. *
  157. * @v acm USB RNDIS device
  158. * @v iobuf I/O buffer
  159. * @ret rc Return status code
  160. */
  161. static int acm_out_transmit ( struct acm_device *acm,
  162. struct io_buffer *iobuf ) {
  163. int rc;
  164. /* Profile transmissions */
  165. profile_start ( &acm_out_profiler );
  166. /* Enqueue I/O buffer */
  167. if ( ( rc = usb_stream ( &acm->usbnet.out, iobuf, 0 ) ) != 0 )
  168. return rc;
  169. profile_stop ( &acm_out_profiler );
  170. return 0;
  171. }
  172. /**
  173. * Complete bulk OUT transfer
  174. *
  175. * @v ep USB endpoint
  176. * @v iobuf I/O buffer
  177. * @v rc Completion status code
  178. */
  179. static void acm_out_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
  180. int rc ) {
  181. struct acm_device *acm = container_of ( ep, struct acm_device,
  182. usbnet.out );
  183. struct rndis_device *rndis = acm->rndis;
  184. /* Report TX completion */
  185. rndis_tx_complete_err ( rndis, iobuf, rc );
  186. }
  187. /** Bulk OUT endpoint operations */
  188. static struct usb_endpoint_driver_operations acm_out_operations = {
  189. .complete = acm_out_complete,
  190. };
  191. /******************************************************************************
  192. *
  193. * USB RNDIS control interface
  194. *
  195. ******************************************************************************
  196. */
  197. /**
  198. * Send control packet
  199. *
  200. * @v acm USB RNDIS device
  201. * @v iobuf I/O buffer
  202. * @ret rc Return status code
  203. */
  204. static int acm_control_transmit ( struct acm_device *acm,
  205. struct io_buffer *iobuf ) {
  206. struct rndis_device *rndis = acm->rndis;
  207. struct usb_device *usb = acm->usb;
  208. int rc;
  209. /* Send packet as an encapsulated command */
  210. if ( ( rc = cdc_send_encapsulated_command ( usb, acm->usbnet.comms,
  211. iobuf->data,
  212. iob_len ( iobuf ) ) ) != 0){
  213. DBGC ( acm, "ACM %p could not send encapsulated command: %s\n",
  214. acm, strerror ( rc ) );
  215. return rc;
  216. }
  217. /* Complete packet immediately */
  218. rndis_tx_complete ( rndis, iobuf );
  219. return 0;
  220. }
  221. /**
  222. * Receive control packet
  223. *
  224. * @v acm USB RNDIS device
  225. * @ret rc Return status code
  226. */
  227. static int acm_control_receive ( struct acm_device *acm ) {
  228. struct rndis_device *rndis = acm->rndis;
  229. struct usb_device *usb = acm->usb;
  230. struct io_buffer *iobuf;
  231. struct rndis_header *header;
  232. size_t mtu = ACM_RESPONSE_MTU;
  233. size_t len;
  234. int rc;
  235. /* Allocate I/O buffer */
  236. iobuf = alloc_iob ( mtu );
  237. if ( ! iobuf ) {
  238. rc = -ENOMEM;
  239. goto err_alloc;
  240. }
  241. /* Get encapsulated response */
  242. if ( ( rc = cdc_get_encapsulated_response ( usb, acm->usbnet.comms,
  243. iobuf->data, mtu ) ) != 0 ){
  244. DBGC ( acm, "ACM %p could not get encapsulated response: %s\n",
  245. acm, strerror ( rc ) );
  246. goto err_get_response;
  247. }
  248. /* Fix up buffer length */
  249. header = iobuf->data;
  250. len = le32_to_cpu ( header->len );
  251. if ( len > mtu ) {
  252. DBGC ( acm, "ACM %p overlength encapsulated response\n", acm );
  253. DBGC_HDA ( acm, 0, iobuf->data, mtu );
  254. rc = -EPROTO;
  255. goto err_len;
  256. }
  257. iob_put ( iobuf, len );
  258. /* Hand off to RNDIS */
  259. rndis_rx ( rndis, iob_disown ( iobuf ) );
  260. return 0;
  261. err_len:
  262. err_get_response:
  263. free_iob ( iobuf );
  264. err_alloc:
  265. return rc;
  266. }
  267. /******************************************************************************
  268. *
  269. * RNDIS interface
  270. *
  271. ******************************************************************************
  272. */
  273. /**
  274. * Open RNDIS device
  275. *
  276. * @v rndis RNDIS device
  277. * @ret rc Return status code
  278. */
  279. static int acm_open ( struct rndis_device *rndis ) {
  280. struct acm_device *acm = rndis->priv;
  281. int rc;
  282. /* Open USB network device */
  283. if ( ( rc = usbnet_open ( &acm->usbnet ) ) != 0 )
  284. goto err_open;
  285. return 0;
  286. usbnet_close ( &acm->usbnet );
  287. err_open:
  288. return rc;
  289. }
  290. /**
  291. * Close RNDIS device
  292. *
  293. * @v rndis RNDIS device
  294. */
  295. static void acm_close ( struct rndis_device *rndis ) {
  296. struct acm_device *acm = rndis->priv;
  297. /* Close USB network device */
  298. usbnet_close ( &acm->usbnet );
  299. }
  300. /**
  301. * Transmit packet
  302. *
  303. * @v rndis RNDIS device
  304. * @v iobuf I/O buffer
  305. * @ret rc Return status code
  306. */
  307. static int acm_transmit ( struct rndis_device *rndis,
  308. struct io_buffer *iobuf ) {
  309. struct acm_device *acm = rndis->priv;
  310. struct rndis_header *header = iobuf->data;
  311. /* Sanity check */
  312. assert ( iob_len ( iobuf ) >= sizeof ( *header ) );
  313. assert ( iob_len ( iobuf ) == le32_to_cpu ( header->len ) );
  314. /* Transmit packet via appropriate mechanism */
  315. if ( header->type == cpu_to_le32 ( RNDIS_PACKET_MSG ) ) {
  316. return acm_out_transmit ( acm, iobuf );
  317. } else {
  318. return acm_control_transmit ( acm, iobuf );
  319. }
  320. }
  321. /**
  322. * Poll for completed and received packets
  323. *
  324. * @v rndis RNDIS device
  325. */
  326. static void acm_poll ( struct rndis_device *rndis ) {
  327. struct acm_device *acm = rndis->priv;
  328. int rc;
  329. /* Poll USB bus */
  330. usb_poll ( acm->bus );
  331. /* Refill rings */
  332. if ( ( rc = usbnet_refill ( &acm->usbnet ) ) != 0 )
  333. rndis_rx_err ( rndis, NULL, rc );
  334. /* Retrieve encapsulated response, if applicable */
  335. if ( acm->responded ) {
  336. /* Clear flag */
  337. acm->responded = 0;
  338. /* Get encapsulated response */
  339. if ( ( rc = acm_control_receive ( acm ) ) != 0 )
  340. rndis_rx_err ( rndis, NULL, rc );
  341. }
  342. }
  343. /** USB RNDIS operations */
  344. static struct rndis_operations acm_operations = {
  345. .open = acm_open,
  346. .close = acm_close,
  347. .transmit = acm_transmit,
  348. .poll = acm_poll,
  349. };
  350. /******************************************************************************
  351. *
  352. * USB interface
  353. *
  354. ******************************************************************************
  355. */
  356. /**
  357. * Probe device
  358. *
  359. * @v func USB function
  360. * @v config Configuration descriptor
  361. * @ret rc Return status code
  362. */
  363. static int acm_probe ( struct usb_function *func,
  364. struct usb_configuration_descriptor *config ) {
  365. struct usb_device *usb = func->usb;
  366. struct rndis_device *rndis;
  367. struct acm_device *acm;
  368. int rc;
  369. /* Allocate and initialise structure */
  370. rndis = alloc_rndis ( sizeof ( *acm ) );
  371. if ( ! rndis ) {
  372. rc = -ENOMEM;
  373. goto err_alloc;
  374. }
  375. rndis_init ( rndis, &acm_operations );
  376. rndis->netdev->dev = &func->dev;
  377. acm = rndis->priv;
  378. acm->usb = usb;
  379. acm->bus = usb->port->hub->bus;
  380. acm->rndis = rndis;
  381. usbnet_init ( &acm->usbnet, func, &acm_intr_operations,
  382. &acm_in_operations, &acm_out_operations );
  383. usb_refill_init ( &acm->usbnet.intr, 0, 0, ACM_INTR_MAX_FILL );
  384. usb_refill_init ( &acm->usbnet.in, 0, ACM_IN_MTU, ACM_IN_MAX_FILL );
  385. /* Describe USB network device */
  386. if ( ( rc = usbnet_describe ( &acm->usbnet, config ) ) != 0 ) {
  387. DBGC ( acm, "ACM %p could not describe: %s\n",
  388. acm, strerror ( rc ) );
  389. goto err_describe;
  390. }
  391. /* Register RNDIS device */
  392. if ( ( rc = register_rndis ( rndis ) ) != 0 )
  393. goto err_register;
  394. usb_func_set_drvdata ( func, acm );
  395. return 0;
  396. unregister_rndis ( rndis );
  397. err_register:
  398. err_describe:
  399. free_rndis ( rndis );
  400. err_alloc:
  401. return rc;
  402. }
  403. /**
  404. * Remove device
  405. *
  406. * @v func USB function
  407. */
  408. static void acm_remove ( struct usb_function *func ) {
  409. struct acm_device *acm = usb_func_get_drvdata ( func );
  410. struct rndis_device *rndis = acm->rndis;
  411. /* Unregister RNDIS device */
  412. unregister_rndis ( rndis );
  413. /* Free RNDIS device */
  414. free_rndis ( rndis );
  415. }
  416. /** USB CDC-ACM device IDs */
  417. static struct usb_device_id cdc_acm_ids[] = {
  418. {
  419. .name = "cdc-acm",
  420. .vendor = USB_ANY_ID,
  421. .product = USB_ANY_ID,
  422. },
  423. };
  424. /** USB CDC-ACM driver */
  425. struct usb_driver cdc_acm_driver __usb_driver = {
  426. .ids = cdc_acm_ids,
  427. .id_count = ( sizeof ( cdc_acm_ids ) / sizeof ( cdc_acm_ids[0] ) ),
  428. .class = USB_CLASS_ID ( USB_CLASS_CDC, USB_SUBCLASS_CDC_ACM,
  429. USB_PROTOCOL_ACM_RNDIS ),
  430. .score = USB_SCORE_DEPRECATED,
  431. .probe = acm_probe,
  432. .remove = acm_remove,
  433. };
  434. /** USB RF-RNDIS device IDs */
  435. static struct usb_device_id rf_rndis_ids[] = {
  436. {
  437. .name = "rf-rndis",
  438. .vendor = USB_ANY_ID,
  439. .product = USB_ANY_ID,
  440. },
  441. };
  442. /** USB RF-RNDIS driver */
  443. struct usb_driver rf_rndis_driver __usb_driver = {
  444. .ids = rf_rndis_ids,
  445. .id_count = ( sizeof ( rf_rndis_ids ) / sizeof ( rf_rndis_ids[0] ) ),
  446. .class = USB_CLASS_ID ( USB_CLASS_WIRELESS, USB_SUBCLASS_WIRELESS_RADIO,
  447. USB_PROTOCOL_RADIO_RNDIS ),
  448. .score = USB_SCORE_DEPRECATED,
  449. .probe = acm_probe,
  450. .remove = acm_remove,
  451. };