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