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.

usbnet.c 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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 <string.h>
  25. #include <errno.h>
  26. #include <ipxe/usb.h>
  27. #include <ipxe/usbnet.h>
  28. /** @file
  29. *
  30. * USB network devices
  31. *
  32. * USB network devices use a variety of packet formats and interface
  33. * descriptors, but tend to have several features in common:
  34. *
  35. * - a single bulk OUT endpoint
  36. *
  37. * - a single bulk IN endpoint using the generic refill mechanism
  38. *
  39. * - an optional interrupt endpoint using the generic refill mechanism
  40. *
  41. * - optional use of an alternate setting to enable the data interface
  42. *
  43. */
  44. /**
  45. * Open USB network device
  46. *
  47. * @v usbnet USB network device
  48. * @ret rc Return status code
  49. */
  50. int usbnet_open ( struct usbnet_device *usbnet ) {
  51. struct usb_device *usb = usbnet->func->usb;
  52. int rc;
  53. /* Open interrupt endpoint, if applicable */
  54. if ( usbnet_has_intr ( usbnet ) &&
  55. ( rc = usb_endpoint_open ( &usbnet->intr ) ) != 0 ) {
  56. DBGC ( usbnet, "USBNET %s could not open interrupt: %s\n",
  57. usbnet->func->name, strerror ( rc ) );
  58. goto err_open_intr;
  59. }
  60. /* Refill interrupt endpoint, if applicable */
  61. if ( usbnet_has_intr ( usbnet ) &&
  62. ( rc = usb_refill ( &usbnet->intr ) ) != 0 ) {
  63. DBGC ( usbnet, "USBNET %s could not refill interrupt: %s\n",
  64. usbnet->func->name, strerror ( rc ) );
  65. goto err_refill_intr;
  66. }
  67. /* Select alternate setting for data interface, if applicable */
  68. if ( usbnet->alternate &&
  69. ( ( rc = usb_set_interface ( usb, usbnet->data,
  70. usbnet->alternate ) ) != 0 ) ) {
  71. DBGC ( usbnet, "USBNET %s could not set alternate interface "
  72. "%d: %s\n", usbnet->func->name, usbnet->alternate,
  73. strerror ( rc ) );
  74. goto err_set_interface;
  75. }
  76. /* Open bulk IN endpoint */
  77. if ( ( rc = usb_endpoint_open ( &usbnet->in ) ) != 0 ) {
  78. DBGC ( usbnet, "USBNET %s could not open bulk IN: %s\n",
  79. usbnet->func->name, strerror ( rc ) );
  80. goto err_open_in;
  81. }
  82. /* Open bulk OUT endpoint */
  83. if ( ( rc = usb_endpoint_open ( &usbnet->out ) ) != 0 ) {
  84. DBGC ( usbnet, "USBNET %s could not open bulk OUT: %s\n",
  85. usbnet->func->name, strerror ( rc ) );
  86. goto err_open_out;
  87. }
  88. /* Refill bulk IN endpoint */
  89. if ( ( rc = usb_refill ( &usbnet->in ) ) != 0 ) {
  90. DBGC ( usbnet, "USBNET %s could not refill bulk IN: %s\n",
  91. usbnet->func->name, strerror ( rc ) );
  92. goto err_refill_in;
  93. }
  94. return 0;
  95. err_refill_in:
  96. usb_endpoint_close ( &usbnet->out );
  97. err_open_out:
  98. usb_endpoint_close ( &usbnet->in );
  99. err_open_in:
  100. if ( usbnet->alternate )
  101. usb_set_interface ( usb, usbnet->data, 0 );
  102. err_set_interface:
  103. err_refill_intr:
  104. if ( usbnet_has_intr ( usbnet ) )
  105. usb_endpoint_close ( &usbnet->intr );
  106. err_open_intr:
  107. return rc;
  108. }
  109. /**
  110. * Close USB network device
  111. *
  112. * @v usbnet USB network device
  113. */
  114. void usbnet_close ( struct usbnet_device *usbnet ) {
  115. struct usb_device *usb = usbnet->func->usb;
  116. /* Close bulk OUT endpoint */
  117. usb_endpoint_close ( &usbnet->out );
  118. /* Close bulk IN endpoint */
  119. usb_endpoint_close ( &usbnet->in );
  120. /* Reset alternate setting for data interface, if applicable */
  121. if ( usbnet->alternate )
  122. usb_set_interface ( usb, usbnet->data, 0 );
  123. /* Close interrupt endpoint, if applicable */
  124. if ( usbnet_has_intr ( usbnet ) )
  125. usb_endpoint_close ( &usbnet->intr );
  126. }
  127. /**
  128. * Refill USB network device bulk IN and interrupt endpoints
  129. *
  130. * @v usbnet USB network device
  131. * @ret rc Return status code
  132. */
  133. int usbnet_refill ( struct usbnet_device *usbnet ) {
  134. int rc;
  135. /* Refill bulk IN endpoint */
  136. if ( ( rc = usb_refill ( &usbnet->in ) ) != 0 )
  137. return rc;
  138. /* Refill interrupt endpoint, if applicable */
  139. if ( usbnet_has_intr ( usbnet ) &&
  140. ( rc = usb_refill ( &usbnet->intr ) ) != 0 ) {
  141. return rc;
  142. }
  143. return 0;
  144. }
  145. /**
  146. * Describe communications interface and interrupt endpoint
  147. *
  148. * @v usbnet USB network device
  149. * @v config Configuration descriptor
  150. * @ret rc Return status code
  151. */
  152. static int usbnet_comms_describe ( struct usbnet_device *usbnet,
  153. struct usb_configuration_descriptor *config){
  154. struct usb_interface_descriptor *desc;
  155. unsigned int comms;
  156. unsigned int i;
  157. int rc;
  158. /* Iterate over all available interfaces */
  159. for ( i = 0 ; i < usbnet->func->desc.count ; i++ ) {
  160. /* Get interface number */
  161. comms = usbnet->func->interface[i];
  162. /* Locate interface descriptor */
  163. desc = usb_interface_descriptor ( config, comms, 0 );
  164. if ( ! desc )
  165. continue;
  166. /* Describe interrupt endpoint */
  167. if ( ( rc = usb_endpoint_described ( &usbnet->intr, config,
  168. desc, USB_INTERRUPT_IN,
  169. 0 ) ) != 0 )
  170. continue;
  171. /* Record communications interface */
  172. usbnet->comms = comms;
  173. DBGC ( usbnet, "USBNET %s found communications interface %d\n",
  174. usbnet->func->name, comms );
  175. return 0;
  176. }
  177. DBGC ( usbnet, "USBNET %s found no communications interface\n",
  178. usbnet->func->name );
  179. return -ENOENT;
  180. }
  181. /**
  182. * Describe data interface and bulk endpoints
  183. *
  184. * @v usbnet USB network device
  185. * @v config Configuration descriptor
  186. * @ret rc Return status code
  187. */
  188. static int usbnet_data_describe ( struct usbnet_device *usbnet,
  189. struct usb_configuration_descriptor *config ){
  190. struct usb_interface_descriptor *desc;
  191. unsigned int data;
  192. unsigned int alt;
  193. unsigned int i;
  194. int rc;
  195. /* Iterate over all available interfaces */
  196. for ( i = 0 ; i < usbnet->func->desc.count ; i++ ) {
  197. /* Get interface number */
  198. data = usbnet->func->interface[i];
  199. /* Iterate over all existent alternate settings */
  200. for ( alt = 0 ; ; alt++ ) {
  201. /* Locate interface descriptor */
  202. desc = usb_interface_descriptor ( config, data, alt );
  203. if ( ! desc )
  204. break;
  205. /* Describe bulk IN endpoint */
  206. if ( ( rc = usb_endpoint_described ( &usbnet->in,
  207. config, desc,
  208. USB_BULK_IN,
  209. 0 ) ) != 0 )
  210. continue;
  211. /* Describe bulk OUT endpoint */
  212. if ( ( rc = usb_endpoint_described ( &usbnet->out,
  213. config, desc,
  214. USB_BULK_OUT,
  215. 0 ) ) != 0 )
  216. continue;
  217. /* Record data interface and alternate setting */
  218. usbnet->data = data;
  219. usbnet->alternate = alt;
  220. DBGC ( usbnet, "USBNET %s found data interface %d",
  221. usbnet->func->name, data );
  222. if ( alt )
  223. DBGC ( usbnet, " using alternate %d", alt );
  224. DBGC ( usbnet, "\n" );
  225. return 0;
  226. }
  227. }
  228. DBGC ( usbnet, "USBNET %s found no data interface\n",
  229. usbnet->func->name );
  230. return -ENOENT;
  231. }
  232. /**
  233. * Describe USB network device interfaces
  234. *
  235. * @v usbnet USB network device
  236. * @v config Configuration descriptor
  237. * @ret rc Return status code
  238. */
  239. int usbnet_describe ( struct usbnet_device *usbnet,
  240. struct usb_configuration_descriptor *config ) {
  241. int rc;
  242. /* Describe communications interface, if applicable */
  243. if ( usbnet_has_intr ( usbnet ) &&
  244. ( rc = usbnet_comms_describe ( usbnet, config ) ) != 0 ) {
  245. return rc;
  246. }
  247. /* Describe data interface */
  248. if ( ( rc = usbnet_data_describe ( usbnet, config ) ) != 0 )
  249. return rc;
  250. return 0;
  251. }