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.

usbhub.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  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 <stdlib.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <errno.h>
  24. #include <assert.h>
  25. #include <byteswap.h>
  26. #include <ipxe/usb.h>
  27. #include "usbhub.h"
  28. /** @file
  29. *
  30. * USB hub driver
  31. *
  32. */
  33. /**
  34. * Refill interrupt ring
  35. *
  36. * @v hubdev Hub device
  37. */
  38. static void hub_refill ( struct usb_hub_device *hubdev ) {
  39. struct io_buffer *iobuf;
  40. size_t mtu = hubdev->intr.mtu;
  41. int rc;
  42. /* Enqueue any available I/O buffers */
  43. while ( ( iobuf = list_first_entry ( &hubdev->intrs, struct io_buffer,
  44. list ) ) ) {
  45. /* Reset size */
  46. iob_put ( iobuf, ( mtu - iob_len ( iobuf ) ) );
  47. /* Enqueue I/O buffer */
  48. if ( ( rc = usb_stream ( &hubdev->intr, iobuf, 0 ) ) != 0 ) {
  49. DBGC ( hubdev, "HUB %s could not enqueue interrupt: "
  50. "%s\n", hubdev->name, strerror ( rc ) );
  51. /* Leave in available list and wait for next refill */
  52. return;
  53. }
  54. /* Remove from available list */
  55. list_del ( &iobuf->list );
  56. }
  57. /* Stop refill process */
  58. process_del ( &hubdev->refill );
  59. }
  60. /** Refill process descriptor */
  61. static struct process_descriptor hub_refill_desc =
  62. PROC_DESC ( struct usb_hub_device, refill, hub_refill );
  63. /**
  64. * Complete interrupt transfer
  65. *
  66. * @v ep USB endpoint
  67. * @v iobuf I/O buffer
  68. * @v rc Completion status code
  69. */
  70. static void hub_complete ( struct usb_endpoint *ep,
  71. struct io_buffer *iobuf, int rc ) {
  72. struct usb_hub_device *hubdev =
  73. container_of ( ep, struct usb_hub_device, intr );
  74. struct usb_hub *hub = hubdev->hub;
  75. uint8_t *data = iobuf->data;
  76. unsigned int bits = ( 8 * iob_len ( iobuf ) );
  77. unsigned int i;
  78. /* Ignore packets cancelled when the endpoint closes */
  79. if ( ! ep->open )
  80. goto done;
  81. /* Ignore packets with errors */
  82. if ( rc != 0 ) {
  83. DBGC ( hubdev, "HUB %s interrupt failed: %s\n",
  84. hubdev->name, strerror ( rc ) );
  85. DBGC_HDA ( hubdev, 0, iobuf->data, iob_len ( iobuf ) );
  86. goto done;
  87. }
  88. /* Report any port status changes */
  89. for ( i = 1 ; i <= hub->ports ; i++ ) {
  90. /* Sanity check */
  91. if ( i > bits ) {
  92. DBGC ( hubdev, "HUB %s underlength interrupt:\n",
  93. hubdev->name );
  94. DBGC_HDA ( hubdev, 0, iobuf->data, iob_len ( iobuf ) );
  95. goto done;
  96. }
  97. /* Report port status change if applicable */
  98. if ( data[ i / 8 ] & ( 1 << ( i % 8 ) ) ) {
  99. DBGC2 ( hubdev, "HUB %s port %d status changed\n",
  100. hubdev->name, i );
  101. usb_port_changed ( usb_port ( hub, i ) );
  102. }
  103. }
  104. done:
  105. /* Return I/O buffer to available list */
  106. list_add_tail ( &iobuf->list, &hubdev->intrs );
  107. /* Start refill process */
  108. process_add ( &hubdev->refill );
  109. }
  110. /** Interrupt endpoint operations */
  111. static struct usb_endpoint_driver_operations usb_hub_intr_operations = {
  112. .complete = hub_complete,
  113. };
  114. /**
  115. * Open hub
  116. *
  117. * @v hub USB hub
  118. * @ret rc Return status code
  119. */
  120. static int hub_open ( struct usb_hub *hub ) {
  121. struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
  122. struct usb_device *usb = hubdev->usb;
  123. struct io_buffer *iobuf;
  124. struct io_buffer *tmp;
  125. unsigned int i;
  126. int rc;
  127. /* Ensure ports are powered */
  128. for ( i = 1 ; i <= hub->ports ; i++ ) {
  129. if ( ( rc = usb_hub_set_port_feature ( usb, i,
  130. USB_HUB_PORT_POWER,
  131. 0 ) ) != 0 ) {
  132. DBGC ( hubdev, "HUB %s port %d could not apply power: "
  133. "%s\n", hubdev->name, i, strerror ( rc ) );
  134. goto err_power;
  135. }
  136. }
  137. /* Allocate I/O buffers */
  138. for ( i = 0 ; i < USB_HUB_INTR_FILL ; i++ ) {
  139. iobuf = alloc_iob ( hubdev->intr.mtu );
  140. if ( ! iobuf ) {
  141. rc = -ENOMEM;
  142. goto err_alloc_iob;
  143. }
  144. list_add ( &iobuf->list, &hubdev->intrs );
  145. }
  146. /* Open interrupt endpoint */
  147. if ( ( rc = usb_endpoint_open ( &hubdev->intr ) ) != 0 ) {
  148. DBGC ( hubdev, "HUB %s could not register interrupt: %s\n",
  149. hubdev->name, strerror ( rc ) );
  150. goto err_open;
  151. }
  152. /* Start refill process */
  153. process_add ( &hubdev->refill );
  154. /* Refill interrupt ring */
  155. hub_refill ( hubdev );
  156. return 0;
  157. usb_endpoint_close ( &hubdev->intr );
  158. err_open:
  159. err_alloc_iob:
  160. list_for_each_entry_safe ( iobuf, tmp, &hubdev->intrs, list ) {
  161. list_del ( &iobuf->list );
  162. free_iob ( iobuf );
  163. }
  164. err_power:
  165. return rc;
  166. }
  167. /**
  168. * Close hub
  169. *
  170. * @v hub USB hub
  171. */
  172. static void hub_close ( struct usb_hub *hub ) {
  173. struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
  174. struct io_buffer *iobuf;
  175. struct io_buffer *tmp;
  176. /* Close interrupt endpoint */
  177. usb_endpoint_close ( &hubdev->intr );
  178. /* Stop refill process */
  179. process_del ( &hubdev->refill );
  180. /* Free I/O buffers */
  181. list_for_each_entry_safe ( iobuf, tmp, &hubdev->intrs, list ) {
  182. list_del ( &iobuf->list );
  183. free_iob ( iobuf );
  184. }
  185. }
  186. /**
  187. * Enable port
  188. *
  189. * @v hub USB hub
  190. * @v port USB port
  191. * @ret rc Return status code
  192. */
  193. static int hub_enable ( struct usb_hub *hub, struct usb_port *port ) {
  194. struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
  195. struct usb_device *usb = hubdev->usb;
  196. struct usb_hub_port_status status;
  197. unsigned int current;
  198. unsigned int i;
  199. int rc;
  200. /* Initiate reset if applicable */
  201. if ( ( hub->protocol < USB_PROTO_3_0 ) &&
  202. ( ( rc = usb_hub_set_port_feature ( usb, port->address,
  203. USB_HUB_PORT_RESET, 0 ) )!=0)){
  204. DBGC ( hubdev, "HUB %s port %d could not initiate reset: %s\n",
  205. hubdev->name, port->address, strerror ( rc ) );
  206. return rc;
  207. }
  208. /* Wait for port to become enabled */
  209. for ( i = 0 ; i < USB_HUB_ENABLE_MAX_WAIT_MS ; i++ ) {
  210. /* Check for port being enabled */
  211. if ( ( rc = usb_hub_get_port_status ( usb, port->address,
  212. &status ) ) != 0 ) {
  213. DBGC ( hubdev, "HUB %s port %d could not get status: "
  214. "%s\n", hubdev->name, port->address,
  215. strerror ( rc ) );
  216. return rc;
  217. }
  218. current = le16_to_cpu ( status.current );
  219. if ( current & ( 1 << USB_HUB_PORT_ENABLE ) )
  220. return 0;
  221. /* Delay */
  222. mdelay ( 1 );
  223. }
  224. DBGC ( hubdev, "HUB %s port %d timed out waiting for enable\n",
  225. hubdev->name, port->address );
  226. return -ETIMEDOUT;
  227. }
  228. /**
  229. * Disable port
  230. *
  231. * @v hub USB hub
  232. * @v port USB port
  233. * @ret rc Return status code
  234. */
  235. static int hub_disable ( struct usb_hub *hub, struct usb_port *port ) {
  236. struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
  237. struct usb_device *usb = hubdev->usb;
  238. int rc;
  239. /* Disable port */
  240. if ( ( rc = usb_hub_clear_port_feature ( usb, port->address,
  241. USB_HUB_PORT_ENABLE, 0 ) )!=0){
  242. DBGC ( hubdev, "HUB %s port %d could not disable: %s\n",
  243. hubdev->name, port->address, strerror ( rc ) );
  244. return rc;
  245. }
  246. return 0;
  247. }
  248. /**
  249. * Clear port status change bits
  250. *
  251. * @v hubdev USB hub device
  252. * @v port Port number
  253. * @v changed Port status change bits
  254. * @ret rc Return status code
  255. */
  256. static int hub_clear_changes ( struct usb_hub_device *hubdev,
  257. unsigned int port, uint16_t changed ) {
  258. struct usb_device *usb = hubdev->usb;
  259. unsigned int bit;
  260. unsigned int feature;
  261. int rc;
  262. /* Clear each set bit */
  263. for ( bit = 0 ; bit < 16 ; bit++ ) {
  264. /* Skip unset bits */
  265. if ( ! ( changed & ( 1 << bit ) ) )
  266. continue;
  267. /* Skip unused features */
  268. feature = USB_HUB_C_FEATURE ( bit );
  269. if ( ! ( hubdev->features & ( 1 << feature ) ) )
  270. continue;
  271. /* Clear bit */
  272. if ( ( rc = usb_hub_clear_port_feature ( usb, port,
  273. feature, 0 ) ) != 0 ) {
  274. DBGC ( hubdev, "HUB %s port %d could not clear feature "
  275. "%d: %s\n", hubdev->name, port, feature,
  276. strerror ( rc ) );
  277. return rc;
  278. }
  279. }
  280. return 0;
  281. }
  282. /**
  283. * Update port speed
  284. *
  285. * @v hub USB hub
  286. * @v port USB port
  287. * @ret rc Return status code
  288. */
  289. static int hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
  290. struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
  291. struct usb_device *usb = hubdev->usb;
  292. struct usb_hub_port_status status;
  293. unsigned int current;
  294. unsigned int changed;
  295. int rc;
  296. /* Get port status */
  297. if ( ( rc = usb_hub_get_port_status ( usb, port->address,
  298. &status ) ) != 0 ) {
  299. DBGC ( hubdev, "HUB %s port %d could not get status: %s\n",
  300. hubdev->name, port->address, strerror ( rc ) );
  301. return rc;
  302. }
  303. current = le16_to_cpu ( status.current );
  304. changed = le16_to_cpu ( status.changed );
  305. DBGC2 ( hubdev, "HUB %s port %d status is %04x:%04x\n",
  306. hubdev->name, port->address, changed, current );
  307. /* Update port speed */
  308. if ( current & ( 1 << USB_HUB_PORT_CONNECTION ) ) {
  309. if ( hub->protocol >= USB_PROTO_3_0 ) {
  310. port->speed = USB_SPEED_SUPER;
  311. } else if ( current & ( 1 << USB_HUB_PORT_LOW_SPEED ) ) {
  312. port->speed = USB_SPEED_LOW;
  313. } else if ( current & ( 1 << USB_HUB_PORT_HIGH_SPEED ) ) {
  314. port->speed = USB_SPEED_HIGH;
  315. } else {
  316. port->speed = USB_SPEED_FULL;
  317. }
  318. } else {
  319. port->speed = USB_SPEED_NONE;
  320. }
  321. /* Clear port status change bits */
  322. if ( ( rc = hub_clear_changes ( hubdev, port->address, changed ) ) != 0)
  323. return rc;
  324. return 0;
  325. }
  326. /** USB hub operations */
  327. static struct usb_hub_driver_operations hub_operations = {
  328. .open = hub_open,
  329. .close = hub_close,
  330. .enable = hub_enable,
  331. .disable = hub_disable,
  332. .speed = hub_speed,
  333. };
  334. /**
  335. * Probe USB hub
  336. *
  337. * @v func USB function
  338. * @v config Configuration descriptor
  339. * @ret rc Return status code
  340. */
  341. static int hub_probe ( struct usb_function *func,
  342. struct usb_configuration_descriptor *config ) {
  343. struct usb_device *usb = func->usb;
  344. struct usb_bus *bus = usb->port->hub->bus;
  345. struct usb_hub_device *hubdev;
  346. struct usb_interface_descriptor *interface;
  347. union usb_hub_descriptor desc;
  348. unsigned int depth;
  349. unsigned int ports;
  350. int enhanced;
  351. int rc;
  352. /* Allocate and initialise structure */
  353. hubdev = zalloc ( sizeof ( *hubdev ) );
  354. if ( ! hubdev ) {
  355. rc = -ENOMEM;
  356. goto err_alloc;
  357. }
  358. enhanced = ( usb->port->protocol >= USB_PROTO_3_0 );
  359. hubdev->name = func->name;
  360. hubdev->usb = usb;
  361. hubdev->features =
  362. ( enhanced ? USB_HUB_FEATURES_ENHANCED : USB_HUB_FEATURES );
  363. usb_endpoint_init ( &hubdev->intr, usb, &usb_hub_intr_operations );
  364. INIT_LIST_HEAD ( &hubdev->intrs );
  365. process_init_stopped ( &hubdev->refill, &hub_refill_desc, NULL );
  366. /* Locate hub interface descriptor */
  367. interface = usb_interface_descriptor ( config, func->interface[0], 0 );
  368. if ( ! interface ) {
  369. DBGC ( hubdev, "HUB %s has no interface descriptor\n",
  370. hubdev->name );
  371. rc = -EINVAL;
  372. goto err_interface;
  373. }
  374. /* Locate interrupt endpoint descriptor */
  375. if ( ( rc = usb_endpoint_described ( &hubdev->intr, config, interface,
  376. USB_INTERRUPT, 0 ) ) != 0 ) {
  377. DBGC ( hubdev, "HUB %s could not describe interrupt endpoint: "
  378. "%s\n", hubdev->name, strerror ( rc ) );
  379. goto err_endpoint;
  380. }
  381. /* Set hub depth */
  382. depth = usb_depth ( usb );
  383. if ( enhanced ) {
  384. if ( ( rc = usb_hub_set_hub_depth ( usb, depth ) ) != 0 ) {
  385. DBGC ( hubdev, "HUB %s could not set hub depth to %d: "
  386. "%s\n", hubdev->name, depth, strerror ( rc ) );
  387. goto err_set_hub_depth;
  388. }
  389. }
  390. /* Get hub descriptor */
  391. if ( ( rc = usb_hub_get_descriptor ( usb, enhanced, &desc ) ) != 0 ) {
  392. DBGC ( hubdev, "HUB %s could not get hub descriptor: %s\n",
  393. hubdev->name, strerror ( rc ) );
  394. goto err_hub_descriptor;
  395. }
  396. ports = desc.basic.ports;
  397. DBGC ( hubdev, "HUB %s has %d ports at depth %d%s\n", hubdev->name,
  398. ports, depth, ( enhanced ? " (enhanced)" : "" ) );
  399. /* Allocate hub */
  400. hubdev->hub = alloc_usb_hub ( bus, usb, ports, &hub_operations );
  401. if ( ! hubdev->hub ) {
  402. rc = -ENOMEM;
  403. goto err_alloc_hub;
  404. }
  405. usb_hub_set_drvdata ( hubdev->hub, hubdev );
  406. /* Register hub */
  407. if ( ( rc = register_usb_hub ( hubdev->hub ) ) != 0 ) {
  408. DBGC ( hubdev, "HUB %s could not register: %s\n",
  409. hubdev->name, strerror ( rc ) );
  410. goto err_register_hub;
  411. }
  412. usb_func_set_drvdata ( func, hubdev );
  413. return 0;
  414. unregister_usb_hub ( hubdev->hub );
  415. err_register_hub:
  416. free_usb_hub ( hubdev->hub );
  417. err_alloc_hub:
  418. err_hub_descriptor:
  419. err_set_hub_depth:
  420. err_endpoint:
  421. err_interface:
  422. free ( hubdev );
  423. err_alloc:
  424. return rc;
  425. }
  426. /**
  427. * Remove USB hub
  428. *
  429. * @v func USB function
  430. * @ret rc Return status code
  431. */
  432. static void hub_remove ( struct usb_function *func ) {
  433. struct usb_hub_device *hubdev = usb_func_get_drvdata ( func );
  434. struct usb_hub *hub = hubdev->hub;
  435. struct usb_device *usb = hubdev->usb;
  436. struct usb_port *port;
  437. unsigned int i;
  438. /* If hub has been unplugged, mark all ports as unplugged */
  439. if ( usb->port->speed == USB_SPEED_NONE ) {
  440. for ( i = 1 ; i <= hub->ports ; i++ ) {
  441. port = usb_port ( hub, i );
  442. port->speed = USB_SPEED_NONE;
  443. }
  444. }
  445. /* Unregister hub */
  446. unregister_usb_hub ( hubdev->hub );
  447. assert ( ! process_running ( &hubdev->refill ) );
  448. assert ( list_empty ( &hubdev->intrs ) );
  449. /* Free hub */
  450. free_usb_hub ( hubdev->hub );
  451. /* Free hub device */
  452. free ( hubdev );
  453. }
  454. /** USB hub device IDs */
  455. static struct usb_device_id hub_ids[] = {
  456. {
  457. .name = "hub-1",
  458. .vendor = USB_ANY_ID,
  459. .product = USB_ANY_ID,
  460. .class = {
  461. .class = USB_CLASS_HUB,
  462. .subclass = 0,
  463. .protocol = 0,
  464. },
  465. },
  466. {
  467. .name = "hub-2",
  468. .vendor = USB_ANY_ID,
  469. .product = USB_ANY_ID,
  470. .class = {
  471. .class = USB_CLASS_HUB,
  472. .subclass = 0,
  473. .protocol = 1,
  474. },
  475. },
  476. };
  477. /** USB hub driver */
  478. struct usb_driver usb_hub_driver __usb_driver = {
  479. .ids = hub_ids,
  480. .id_count = ( sizeof ( hub_ids ) / sizeof ( hub_ids[0] ) ),
  481. .probe = hub_probe,
  482. .remove = hub_remove,
  483. };