2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
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.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
42 * Refill interrupt ring
44 * @v hubdev Hub device
46 static void hub_refill ( struct usb_hub_device *hubdev ) {
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 */
57 /* Stop refill process */
58 process_del ( &hubdev->refill );
61 /** Refill process descriptor */
62 static struct process_descriptor hub_refill_desc =
63 PROC_DESC ( struct usb_hub_device, refill, hub_refill );
66 * Complete interrupt transfer
70 * @v rc Completion status code
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 ) );
81 /* Ignore packets cancelled when the endpoint closes */
85 /* Ignore packets with errors */
87 DBGC ( hubdev, "HUB %s interrupt failed: %s\n",
88 hubdev->name, strerror ( rc ) );
89 DBGC_HDA ( hubdev, 0, iobuf->data, iob_len ( iobuf ) );
93 /* Report any port status changes */
94 for ( i = 1 ; i <= hub->ports ; i++ ) {
98 DBGC ( hubdev, "HUB %s underlength interrupt:\n",
100 DBGC_HDA ( hubdev, 0, iobuf->data, iob_len ( iobuf ) );
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",
108 usb_port_changed ( usb_port ( hub, i ) );
113 /* Start refill process */
114 process_add ( &hubdev->refill );
117 /** Interrupt endpoint operations */
118 static struct usb_endpoint_driver_operations usb_hub_intr_operations = {
119 .complete = hub_complete,
126 * @ret rc Return status code
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;
134 /* Ensure ports are powered */
135 for ( i = 1 ; i <= hub->ports ; i++ ) {
136 if ( ( rc = usb_hub_set_port_feature ( usb, i,
139 DBGC ( hubdev, "HUB %s port %d could not apply power: "
140 "%s\n", hubdev->name, i, strerror ( rc ) );
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 ) );
152 /* Start refill process */
153 process_add ( &hubdev->refill );
155 /* Refill interrupt ring */
156 hub_refill ( hubdev );
160 usb_endpoint_close ( &hubdev->intr );
171 static void hub_close ( struct usb_hub *hub ) {
172 struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
174 /* Close interrupt endpoint */
175 usb_endpoint_close ( &hubdev->intr );
177 /* Stop refill process */
178 process_del ( &hubdev->refill );
186 * @ret rc Return status code
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;
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 ) );
205 /* Wait for port to become enabled */
206 for ( i = 0 ; i < USB_HUB_ENABLE_MAX_WAIT_MS ; i++ ) {
208 /* Check for port being enabled */
209 if ( ( rc = usb_hub_get_port_status ( usb, port->address,
211 DBGC ( hubdev, "HUB %s port %d could not get status: "
212 "%s\n", hubdev->name, port->address,
216 current = le16_to_cpu ( status.current );
217 if ( current & ( 1 << USB_HUB_PORT_ENABLE ) )
224 DBGC ( hubdev, "HUB %s port %d timed out waiting for enable\n",
225 hubdev->name, port->address );
234 * @ret rc Return status code
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;
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 ) );
253 * Clear port status change bits
255 * @v hubdev USB hub device
256 * @v port Port number
257 * @v changed Port status change bits
258 * @ret rc Return status code
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;
264 unsigned int feature;
267 /* Clear each set bit */
268 for ( bit = 0 ; bit < 16 ; bit++ ) {
270 /* Skip unset bits */
271 if ( ! ( changed & ( 1 << bit ) ) )
274 /* Skip unused features */
275 feature = USB_HUB_C_FEATURE ( bit );
276 if ( ! ( hubdev->features & ( 1 << feature ) ) )
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,
297 * @ret rc Return status code
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;
307 /* Get port status */
308 if ( ( rc = usb_hub_get_port_status ( usb, port->address,
310 DBGC ( hubdev, "HUB %s port %d could not get status: %s\n",
311 hubdev->name, port->address, strerror ( rc ) );
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 );
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;
328 port->speed = USB_SPEED_FULL;
331 port->speed = USB_SPEED_NONE;
334 /* Record disconnections */
335 port->disconnected |= ( changed & ( 1 << USB_HUB_PORT_CONNECTION ) );
337 /* Clear port status change bits */
338 if ( ( rc = hub_clear_changes ( hubdev, port->address, changed ) ) != 0)
345 * Clear transaction translator buffer
350 * @ret rc Return status code
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;
358 /* Clear transaction translator buffer. All hubs must support
359 * single-TT operation; we simplify our code by supporting
360 * only this configuration.
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 ) );
373 /** USB hub operations */
374 static struct usb_hub_driver_operations hub_operations = {
377 .enable = hub_enable,
378 .disable = hub_disable,
380 .clear_tt = hub_clear_tt,
386 * @v func USB function
387 * @v config Configuration descriptor
388 * @ret rc Return status code
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;
402 /* Allocate and initialise structure */
403 hubdev = zalloc ( sizeof ( *hubdev ) );
408 enhanced = ( usb->port->protocol >= USB_PROTO_3_0 );
409 hubdev->name = func->name;
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 );
417 /* Locate hub interface descriptor */
418 interface = usb_interface_descriptor ( config, func->interface[0], 0 );
420 DBGC ( hubdev, "HUB %s has no interface descriptor\n",
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 ) );
435 depth = usb_depth ( usb );
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;
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;
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)" : "" ) );
455 hubdev->hub = alloc_usb_hub ( bus, usb, ports, &hub_operations );
456 if ( ! hubdev->hub ) {
460 usb_hub_set_drvdata ( hubdev->hub, hubdev );
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;
469 usb_func_set_drvdata ( func, hubdev );
472 unregister_usb_hub ( hubdev->hub );
474 free_usb_hub ( hubdev->hub );
488 * @v func USB function
489 * @ret rc Return status code
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;
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;
507 unregister_usb_hub ( hubdev->hub );
508 assert ( ! process_running ( &hubdev->refill ) );
511 free_usb_hub ( hubdev->hub );
513 /* Free hub device */
517 /** USB hub device IDs */
518 static struct usb_device_id hub_ids[] = {
521 .vendor = USB_ANY_ID,
522 .product = USB_ANY_ID,
524 .class = USB_CLASS_HUB,
531 .vendor = USB_ANY_ID,
532 .product = USB_ANY_ID,
534 .class = USB_CLASS_HUB,
541 /** USB hub driver */
542 struct usb_driver usb_hub_driver __usb_driver = {
544 .id_count = ( sizeof ( hub_ids ) / sizeof ( hub_ids[0] ) ),
546 .remove = hub_remove,