[acpi] Expose system MAC address via ${sysmac} setting
[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
114 /* Recycle I/O buffer */
115 usb_recycle ( &hubdev->intr, iobuf );
116
117 /* Start refill process */
118 process_add ( &hubdev->refill );
119 }
120
121 /** Interrupt endpoint operations */
122 static struct usb_endpoint_driver_operations usb_hub_intr_operations = {
123 .complete = hub_complete,
124 };
125
126 /**
127 * Open hub
128 *
129 * @v hub USB hub
130 * @ret rc Return status code
131 */
132 static int hub_open ( struct usb_hub *hub ) {
133 struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
134 struct usb_device *usb = hubdev->usb;
135 unsigned int i;
136 int rc;
137
138 /* Ensure ports are powered */
139 for ( i = 1 ; i <= hub->ports ; i++ ) {
140 if ( ( rc = usb_hub_set_port_feature ( usb, i,
141 USB_HUB_PORT_POWER,
142 0 ) ) != 0 ) {
143 DBGC ( hubdev, "HUB %s port %d could not apply power: "
144 "%s\n", hubdev->name, i, strerror ( rc ) );
145 goto err_power;
146 }
147 }
148
149 /* Open interrupt endpoint */
150 if ( ( rc = usb_endpoint_open ( &hubdev->intr ) ) != 0 ) {
151 DBGC ( hubdev, "HUB %s could not register interrupt: %s\n",
152 hubdev->name, strerror ( rc ) );
153 goto err_open;
154 }
155
156 /* Start refill process */
157 process_add ( &hubdev->refill );
158
159 /* Refill interrupt ring */
160 hub_refill ( hubdev );
161
162 /* Delay to allow ports to stabilise on out-of-spec hubs */
163 if ( hubdev->flags & USB_HUB_SLOW_START )
164 mdelay ( USB_HUB_SLOW_START_DELAY_MS );
165
166 return 0;
167
168 usb_endpoint_close ( &hubdev->intr );
169 err_open:
170 err_power:
171 return rc;
172 }
173
174 /**
175 * Close hub
176 *
177 * @v hub USB hub
178 */
179 static void hub_close ( struct usb_hub *hub ) {
180 struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
181
182 /* Close interrupt endpoint */
183 usb_endpoint_close ( &hubdev->intr );
184
185 /* Stop refill process */
186 process_del ( &hubdev->refill );
187 }
188
189 /**
190 * Enable port
191 *
192 * @v hub USB hub
193 * @v port USB port
194 * @ret rc Return status code
195 */
196 static int hub_enable ( struct usb_hub *hub, struct usb_port *port ) {
197 struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
198 struct usb_device *usb = hubdev->usb;
199 struct usb_hub_port_status status;
200 unsigned int current;
201 unsigned int i;
202 int rc;
203
204 /* Initiate reset if applicable */
205 if ( ( hub->protocol < USB_PROTO_3_0 ) &&
206 ( ( rc = usb_hub_set_port_feature ( usb, port->address,
207 USB_HUB_PORT_RESET, 0 ) )!=0)){
208 DBGC ( hubdev, "HUB %s port %d could not initiate reset: %s\n",
209 hubdev->name, port->address, strerror ( rc ) );
210 return rc;
211 }
212
213 /* Wait for port to become enabled */
214 for ( i = 0 ; i < USB_HUB_ENABLE_MAX_WAIT_MS ; i++ ) {
215
216 /* Check for port being enabled */
217 if ( ( rc = usb_hub_get_port_status ( usb, port->address,
218 &status ) ) != 0 ) {
219 DBGC ( hubdev, "HUB %s port %d could not get status: "
220 "%s\n", hubdev->name, port->address,
221 strerror ( rc ) );
222 return rc;
223 }
224 current = le16_to_cpu ( status.current );
225 if ( current & ( 1 << USB_HUB_PORT_ENABLE ) )
226 return 0;
227
228 /* Delay */
229 mdelay ( 1 );
230 }
231
232 DBGC ( hubdev, "HUB %s port %d timed out waiting for enable\n",
233 hubdev->name, port->address );
234 return -ETIMEDOUT;
235 }
236
237 /**
238 * Disable port
239 *
240 * @v hub USB hub
241 * @v port USB port
242 * @ret rc Return status code
243 */
244 static int hub_disable ( struct usb_hub *hub, struct usb_port *port ) {
245 struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
246 struct usb_device *usb = hubdev->usb;
247 int rc;
248
249 /* Disable port */
250 if ( ( hub->protocol < USB_PROTO_3_0 ) &&
251 ( ( rc = usb_hub_clear_port_feature ( usb, port->address,
252 USB_HUB_PORT_ENABLE,
253 0 ) ) != 0 ) ) {
254 DBGC ( hubdev, "HUB %s port %d could not disable: %s\n",
255 hubdev->name, port->address, strerror ( rc ) );
256 return rc;
257 }
258
259 return 0;
260 }
261
262 /**
263 * Clear port status change bits
264 *
265 * @v hubdev USB hub device
266 * @v port Port number
267 * @v changed Port status change bits
268 * @ret rc Return status code
269 */
270 static int hub_clear_changes ( struct usb_hub_device *hubdev,
271 unsigned int port, uint16_t changed ) {
272 struct usb_device *usb = hubdev->usb;
273 unsigned int bit;
274 unsigned int feature;
275 int rc;
276
277 /* Clear each set bit */
278 for ( bit = 0 ; bit < 16 ; bit++ ) {
279
280 /* Skip unset bits */
281 if ( ! ( changed & ( 1 << bit ) ) )
282 continue;
283
284 /* Skip unused features */
285 feature = USB_HUB_C_FEATURE ( bit );
286 if ( ! ( hubdev->features & ( 1 << feature ) ) )
287 continue;
288
289 /* Clear bit */
290 if ( ( rc = usb_hub_clear_port_feature ( usb, port,
291 feature, 0 ) ) != 0 ) {
292 DBGC ( hubdev, "HUB %s port %d could not clear feature "
293 "%d: %s\n", hubdev->name, port, feature,
294 strerror ( rc ) );
295 return rc;
296 }
297 }
298
299 return 0;
300 }
301
302 /**
303 * Update port speed
304 *
305 * @v hub USB hub
306 * @v port USB port
307 * @ret rc Return status code
308 */
309 static int hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
310 struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
311 struct usb_device *usb = hubdev->usb;
312 struct usb_hub_port_status status;
313 unsigned int current;
314 unsigned int changed;
315 int rc;
316
317 /* Get port status */
318 if ( ( rc = usb_hub_get_port_status ( usb, port->address,
319 &status ) ) != 0 ) {
320 DBGC ( hubdev, "HUB %s port %d could not get status: %s\n",
321 hubdev->name, port->address, strerror ( rc ) );
322 return rc;
323 }
324 current = le16_to_cpu ( status.current );
325 changed = le16_to_cpu ( status.changed );
326 DBGC2 ( hubdev, "HUB %s port %d status is %04x:%04x\n",
327 hubdev->name, port->address, changed, current );
328
329 /* Update port speed */
330 if ( current & ( 1 << USB_HUB_PORT_CONNECTION ) ) {
331 if ( hub->protocol >= USB_PROTO_3_0 ) {
332 port->speed = USB_SPEED_SUPER;
333 } else if ( current & ( 1 << USB_HUB_PORT_LOW_SPEED ) ) {
334 port->speed = USB_SPEED_LOW;
335 } else if ( current & ( 1 << USB_HUB_PORT_HIGH_SPEED ) ) {
336 port->speed = USB_SPEED_HIGH;
337 } else {
338 port->speed = USB_SPEED_FULL;
339 }
340 } else {
341 port->speed = USB_SPEED_NONE;
342 }
343
344 /* Record disconnections */
345 port->disconnected |= ( changed & ( 1 << USB_HUB_PORT_CONNECTION ) );
346
347 /* Clear port status change bits */
348 if ( ( rc = hub_clear_changes ( hubdev, port->address, changed ) ) != 0)
349 return rc;
350
351 return 0;
352 }
353
354 /**
355 * Clear transaction translator buffer
356 *
357 * @v hub USB hub
358 * @v port USB port
359 * @v ep USB endpoint
360 * @ret rc Return status code
361 */
362 static int hub_clear_tt ( struct usb_hub *hub, struct usb_port *port,
363 struct usb_endpoint *ep ) {
364 struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
365 struct usb_device *usb = hubdev->usb;
366 int rc;
367
368 /* Clear transaction translator buffer. All hubs must support
369 * single-TT operation; we simplify our code by supporting
370 * only this configuration.
371 */
372 if ( ( rc = usb_hub_clear_tt_buffer ( usb, ep->usb->address,
373 ep->address, ep->attributes,
374 USB_HUB_TT_SINGLE ) ) != 0 ) {
375 DBGC ( hubdev, "HUB %s port %d could not clear TT buffer: %s\n",
376 hubdev->name, port->address, strerror ( rc ) );
377 return rc;
378 }
379
380 return 0;
381 }
382
383 /** USB hub operations */
384 static struct usb_hub_driver_operations hub_operations = {
385 .open = hub_open,
386 .close = hub_close,
387 .enable = hub_enable,
388 .disable = hub_disable,
389 .speed = hub_speed,
390 .clear_tt = hub_clear_tt,
391 };
392
393 /**
394 * Probe USB hub
395 *
396 * @v func USB function
397 * @v config Configuration descriptor
398 * @ret rc Return status code
399 */
400 static int hub_probe ( struct usb_function *func,
401 struct usb_configuration_descriptor *config ) {
402 struct usb_device *usb = func->usb;
403 struct usb_bus *bus = usb->port->hub->bus;
404 struct usb_hub_device *hubdev;
405 struct usb_interface_descriptor *interface;
406 union usb_hub_descriptor desc;
407 unsigned int depth;
408 unsigned int ports;
409 int enhanced;
410 int rc;
411
412 /* Allocate and initialise structure */
413 hubdev = zalloc ( sizeof ( *hubdev ) );
414 if ( ! hubdev ) {
415 rc = -ENOMEM;
416 goto err_alloc;
417 }
418 enhanced = ( usb->port->protocol >= USB_PROTO_3_0 );
419 hubdev->name = func->name;
420 hubdev->usb = usb;
421 hubdev->features =
422 ( enhanced ? USB_HUB_FEATURES_ENHANCED : USB_HUB_FEATURES );
423 hubdev->flags = func->id->driver_data;
424 usb_endpoint_init ( &hubdev->intr, usb, &usb_hub_intr_operations );
425 usb_refill_init ( &hubdev->intr, 0, 0, USB_HUB_INTR_FILL );
426 process_init_stopped ( &hubdev->refill, &hub_refill_desc, NULL );
427
428 /* Locate hub interface descriptor */
429 interface = usb_interface_descriptor ( config, func->interface[0], 0 );
430 if ( ! interface ) {
431 DBGC ( hubdev, "HUB %s has no interface descriptor\n",
432 hubdev->name );
433 rc = -EINVAL;
434 goto err_interface;
435 }
436
437 /* Locate interrupt endpoint descriptor */
438 if ( ( rc = usb_endpoint_described ( &hubdev->intr, config, interface,
439 USB_INTERRUPT_IN, 0 ) ) != 0 ) {
440 DBGC ( hubdev, "HUB %s could not describe interrupt endpoint: "
441 "%s\n", hubdev->name, strerror ( rc ) );
442 goto err_endpoint;
443 }
444
445 /* Set hub depth */
446 depth = usb_depth ( usb );
447 if ( enhanced ) {
448 if ( ( rc = usb_hub_set_hub_depth ( usb, depth ) ) != 0 ) {
449 DBGC ( hubdev, "HUB %s could not set hub depth to %d: "
450 "%s\n", hubdev->name, depth, strerror ( rc ) );
451 goto err_set_hub_depth;
452 }
453 }
454
455 /* Get hub descriptor */
456 if ( ( rc = usb_hub_get_descriptor ( usb, enhanced, &desc ) ) != 0 ) {
457 DBGC ( hubdev, "HUB %s could not get hub descriptor: %s\n",
458 hubdev->name, strerror ( rc ) );
459 goto err_hub_descriptor;
460 }
461 ports = desc.basic.ports;
462 DBGC ( hubdev, "HUB %s has %d ports at depth %d%s\n", hubdev->name,
463 ports, depth, ( enhanced ? " (enhanced)" : "" ) );
464
465 /* Allocate hub */
466 hubdev->hub = alloc_usb_hub ( bus, usb, ports, &hub_operations );
467 if ( ! hubdev->hub ) {
468 rc = -ENOMEM;
469 goto err_alloc_hub;
470 }
471 usb_hub_set_drvdata ( hubdev->hub, hubdev );
472
473 /* Register hub */
474 if ( ( rc = register_usb_hub ( hubdev->hub ) ) != 0 ) {
475 DBGC ( hubdev, "HUB %s could not register: %s\n",
476 hubdev->name, strerror ( rc ) );
477 goto err_register_hub;
478 }
479
480 usb_func_set_drvdata ( func, hubdev );
481 return 0;
482
483 unregister_usb_hub ( hubdev->hub );
484 err_register_hub:
485 free_usb_hub ( hubdev->hub );
486 err_alloc_hub:
487 err_hub_descriptor:
488 err_set_hub_depth:
489 err_endpoint:
490 err_interface:
491 free ( hubdev );
492 err_alloc:
493 return rc;
494 }
495
496 /**
497 * Remove USB hub
498 *
499 * @v func USB function
500 * @ret rc Return status code
501 */
502 static void hub_remove ( struct usb_function *func ) {
503 struct usb_hub_device *hubdev = usb_func_get_drvdata ( func );
504 struct usb_hub *hub = hubdev->hub;
505 struct usb_device *usb = hubdev->usb;
506 struct usb_port *port;
507 unsigned int i;
508
509 /* If hub has been unplugged, mark all ports as unplugged */
510 if ( usb->port->disconnected ) {
511 for ( i = 1 ; i <= hub->ports ; i++ ) {
512 port = usb_port ( hub, i );
513 port->disconnected = 1;
514 port->speed = USB_SPEED_NONE;
515 }
516 }
517
518 /* Unregister hub */
519 unregister_usb_hub ( hubdev->hub );
520 assert ( ! process_running ( &hubdev->refill ) );
521
522 /* Free hub */
523 free_usb_hub ( hubdev->hub );
524
525 /* Free hub device */
526 free ( hubdev );
527 }
528
529 /** USB hub device IDs */
530 static struct usb_device_id hub_ids[] = {
531 {
532 .name = "avocent-hub",
533 .vendor = 0x0624,
534 .product = 0x0248,
535 .driver_data = USB_HUB_SLOW_START,
536 },
537 {
538 .name = "hub",
539 .vendor = USB_ANY_ID,
540 .product = USB_ANY_ID,
541 },
542 };
543
544 /** USB hub driver */
545 struct usb_driver usb_hub_driver __usb_driver = {
546 .ids = hub_ids,
547 .id_count = ( sizeof ( hub_ids ) / sizeof ( hub_ids[0] ) ),
548 .class = USB_CLASS_ID ( USB_CLASS_HUB, 0, USB_ANY_ID ),
549 .score = USB_SCORE_NORMAL,
550 .probe = hub_probe,
551 .remove = hub_remove,
552 };