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