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
,