xref: /minix3/minix/drivers/usb/usb_hub/usb_hub.c (revision 2d64210c1dbcd340904718f2d4e9e81adeab3c7d)
1 /*
2  * Minix3 USB hub driver implementation
3  */
4 
5 #include <string.h>			/* memset */
6 #include <stdint.h>
7 #include <time.h>			/* nanosleep */
8 
9 #include <ddekit/thread.h>
10 #include <minix/sef.h>
11 #include <minix/sysutil.h>		/* panic */
12 #include <minix/usb.h>			/* usb_ctrlrequest TODO: remove me */
13 
14 #include "common.h"
15 #include "urb_helper.h"
16 
17 
18 /*---------------------------*
19  *    declared functions     *
20  *---------------------------*/
21 /* TODO: these are missing from DDE header files */
22 extern void ddekit_minix_wait_exit(void);
23 extern void ddekit_shutdown(void);
24 
25 /* SEF related functions */
26 static int hub_sef_hdlr(int, sef_init_info_t *);
27 static void hub_signal_handler(int);
28 
29 /* DDEKit IPC related */
30 static void ddekit_usb_task(void *);
31 
32 /* DDEKit's USB driver callbacks */
33 static void usb_driver_completion(void *);
34 static void usb_driver_connect(struct ddekit_usb_dev *, unsigned int);
35 static void usb_driver_disconnect(struct ddekit_usb_dev *);
36 
37 /* Hub driver main task */
38 static void hub_task(void *);
39 
40 
41 /*---------------------------*
42  *    class specific stuff   *
43  *---------------------------*/
44 #define HUB_PACKED __attribute__((__packed__))
45 
46 /* How often to check for changes */
47 #define USB_HUB_POLLING_INTERVAL 1000
48 
49 /* Max number of hub ports */
50 #define USB_HUB_PORT_LIMIT 8
51 
52 /* Limits number of communication retries (when needed) */
53 #define USB_HUB_MAX_TRIES 3
54 
55 /* How long to wait between retries, in case of reset error (in nanoseconds) */
56 #define USB_HUB_RESET_DELAY 200000000 /* 200ms */
57 
58 /* Hub descriptor type */
59 #define USB_HUB_DESCRIPTOR_TYPE 0x29
60 
61 /* Hub descriptor structure */
62 typedef struct HUB_PACKED hub_descriptor {
63 
64 	uint8_t		bDescLength;
65 	uint8_t		bDescriptorType;
66 	uint8_t		bNbrPorts;
67 	uint16_t	wHubCharacteristics;
68 	uint8_t		bPwrOn2PwrGood;
69 	uint8_t		bHubContrCurrent;
70 	/* Remaining variable length fields are ignored for now */
71 }
72 hub_descriptor;
73 
74 /* Hub port status structure, as defined in USB 2.0 document */
75 typedef struct HUB_PACKED hub_port_status {
76 
77 	uint32_t	PORT_CONNECTION : 1;
78 	uint32_t	PORT_ENABLE : 1;
79 	uint32_t	PORT_SUSPEND : 1;
80 	uint32_t	PORT_OVER_CURRENT : 1;
81 	uint32_t	PORT_RESET : 1;
82 	uint32_t	RESERVED1 : 3;
83 
84 	uint32_t	PORT_POWER : 1;
85 	uint32_t	PORT_LOW_SPEED : 1;
86 	uint32_t	PORT_HIGH_SPEED : 1;
87 	uint32_t	PORT_TEST : 1;
88 	uint32_t	PORT_INDICATOR : 1;
89 	uint32_t	RESERVED2 : 3;
90 
91 	uint32_t	C_PORT_CONNECTION : 1;
92 	uint32_t	C_PORT_ENABLE : 1;
93 	uint32_t	C_PORT_SUSPEND : 1;
94 	uint32_t	C_PORT_OVER_CURRENT : 1;
95 	uint32_t	C_PORT_RESET : 1;
96 	uint32_t	RESERVED3 : 11;
97 }
98 hub_port_status;
99 
100 /* Hub Class Feature Selectors */
101 typedef enum {
102 
103 	C_HUB_LOCAL_POWER	= 0 ,
104 	C_HUB_OVER_CURRENT	= 1 ,
105 	PORT_CONNECTION		= 0 ,
106 	PORT_ENABLE		= 1 ,
107 	PORT_SUSPEND		= 2 ,
108 	PORT_OVER_CURRENT	= 3 ,
109 	PORT_RESET		= 4 ,
110 	PORT_POWER		= 8 ,
111 	PORT_LOW_SPEED		= 9 ,
112 	C_PORT_CONNECTION	= 16,
113 	C_PORT_ENABLE		= 17,
114 	C_PORT_SUSPEND		= 18,
115 	C_PORT_OVER_CURRENT	= 19,
116 	C_PORT_RESET		= 20,
117 	PORT_TEST		= 21,
118 	PORT_INDICATOR		= 22
119 }
120 class_feature;
121 
122 /* Hub Class Request Codes */
123 typedef enum {
124 
125 	GET_STATUS		= 0 ,
126 	CLEAR_FEATURE		= 1 ,
127 	RESERVED1		= 2 ,
128 	SET_FEATURE		= 3 ,
129 	RESERVED2		= 4 ,
130 	RESERVED3		= 5 ,
131 	GET_DESCRIPTOR		= 6 ,
132 	SET_DESCRIPTOR		= 7 ,
133 	CLEAR_TT_BUFFER		= 8 ,
134 	RESET_TT		= 9 ,
135 	GET_TT_STATE		= 10,
136 	STOP_TT			= 11
137 }
138 class_code;
139 
140 /* Hub port connection state */
141 typedef enum {
142 
143 	HUB_PORT_DISCONN = 0,
144 	HUB_PORT_CONN = 1,
145 	HUB_PORT_ERROR = 2
146 }
147 port_conn;
148 
149 /* Hub port connection changes */
150 typedef enum {
151 
152 	HUB_CHANGE_NONE = 0,		/* Nothing changed since last poll */
153 	HUB_CHANGE_CONN = 1,		/* Device was just connected */
154 	HUB_CHANGE_DISCONN= 2,		/* Device was just disconnected */
155 	HUB_CHANGE_STATUS_ERR = 3,	/* Port status mismatch */
156 	HUB_CHANGE_COM_ERR = 4		/* Something wrong happened to driver */
157 }
158 port_change;
159 
160 /* Hub get class specific descriptor call */
161 static int hub_get_descriptor(hub_descriptor *);
162 
163 /* Hub Set/ClearPortFeature call */
164 static int hub_port_feature(int, class_code, class_feature);
165 
166 /* Hub GetPortStatus call */
167 static int hub_get_port_status(int, hub_port_status *);
168 
169 /* Handle port status change */
170 static port_change hub_handle_change(int, hub_port_status *);
171 
172 /* Handle port connection */
173 static int hub_handle_connection(int, hub_port_status *);
174 
175 /* Handle port disconnection */
176 static int hub_handle_disconnection(int);
177 
178 
179 /*---------------------------*
180  *    defined variables      *
181  *---------------------------*/
182 /* USB hub driver state */
183 typedef struct hub_state {
184 
185 	hub_descriptor descriptor;		/* Class specific descriptor */
186 	struct ddekit_usb_dev * dev;		/* DDEKit device */
187 	int num_ports;				/* Number of hub ports */
188 	port_conn conn[USB_HUB_PORT_LIMIT];	/* Map of connected ports */
189 }
190 hub_state;
191 
192 /* Current hub driver state */
193 static hub_state driver_state;
194 
195 /* USB callback structure */
196 static struct ddekit_usb_driver usb_driver = {
197 	.completion	= usb_driver_completion,
198 	.connect	= usb_driver_connect,
199 	.disconnect	= usb_driver_disconnect
200 };
201 
202 /* Semaphore used to block hub thread to
203  * allow DDE dispatcher operation */
204 static ddekit_sem_t * hub_sem = NULL;
205 
206 /* USB hub thread */
207 ddekit_thread_t * hub_thread = NULL;
208 
209 /* DDEKit USB message handling thread */
210 ddekit_thread_t * ddekit_usb_thread = NULL;
211 
212 
213 /*---------------------------*
214  *    defined functions      *
215  *---------------------------*/
216 /*===========================================================================*
217  *    main                                                                   *
218  *===========================================================================*/
219 int
main(int argc,char * argv[])220 main(int argc, char * argv[])
221 {
222 	HUB_MSG("Starting driver... (built: %s %s)", __DATE__, __TIME__);
223 
224 	/* Store arguments for future parsing */
225 	env_setargs(argc, argv);
226 
227 	/* Clear current state */
228 	memset(&driver_state, 0, sizeof(driver_state));
229 
230 	/* Initialize SEF related callbacks */
231 	sef_setcb_init_fresh(hub_sef_hdlr);
232 	sef_setcb_init_lu(hub_sef_hdlr);
233 	sef_setcb_init_restart(hub_sef_hdlr);
234 	sef_setcb_signal_handler(hub_signal_handler);
235 
236 	/* Initialize DDEkit (involves sef_startup()) */
237 	ddekit_init();
238 	HUB_DEBUG_MSG("DDEkit ready...");
239 
240 	/* Semaphore initialization */
241 	hub_sem = ddekit_sem_init(0);
242 	if (NULL == hub_sem)
243 		panic("Initializing USB hub semaphore, failed!");
244 
245 	/* Starting hub thread */
246 	hub_thread = ddekit_thread_create(hub_task, NULL, "hub_task");
247 	if (NULL == hub_thread)
248 		panic("Initializing USB hub thread failed!");
249 
250 	HUB_DEBUG_MSG("USB HUB task ready...");
251 
252 	/* Run USB IPC task to collect messages */
253 	ddekit_usb_thread = ddekit_thread_create(ddekit_usb_task, NULL,
254 						"ddekit_task" );
255 	if (NULL == ddekit_usb_thread)
256 		panic("Initializing ddekit_usb_thread failed!");
257 
258 	HUB_DEBUG_MSG("USB IPC task ready...");
259 
260 	/* Block and wait until exit signal is received */
261 	ddekit_minix_wait_exit();
262 	HUB_DEBUG_MSG("Exiting...");
263 
264 	/* Release objects that were explicitly allocated above */
265 	ddekit_thread_terminate(ddekit_usb_thread);
266 	ddekit_thread_terminate(hub_thread);
267 	ddekit_sem_deinit(hub_sem);
268 
269 	/* TODO: No ddekit_deinit for proper cleanup? */
270 
271 	HUB_DEBUG_MSG("Cleanup completed...");
272 
273 	return EXIT_SUCCESS;
274 }
275 
276 
277 /*===========================================================================*
278  *    hub_sef_hdlr                                                           *
279  *===========================================================================*/
280 static int
hub_sef_hdlr(int type,sef_init_info_t * UNUSED (info))281 hub_sef_hdlr(int type, sef_init_info_t * UNUSED(info))
282 {
283 	HUB_DEBUG_DUMP;
284 
285 	switch (type) {
286 		case SEF_INIT_FRESH:
287 			return EXIT_SUCCESS;
288 		case SEF_INIT_LU:
289 		case SEF_INIT_RESTART:
290 			HUB_MSG("Only 'fresh' SEF initialization supported");
291 			break;
292 		default:
293 			HUB_MSG("Illegal SEF type");
294 			break;
295 	}
296 
297 	return EXIT_FAILURE;
298 }
299 
300 
301 /*===========================================================================*
302  *    hub_signal_handler                                                     *
303  *===========================================================================*/
304 static void
hub_signal_handler(int this_signal)305 hub_signal_handler(int this_signal)
306 {
307 	HUB_DEBUG_DUMP;
308 
309 	HUB_MSG("Handling signal 0x%X", this_signal);
310 
311 	/* TODO: Any signal means shutdown for now (it may be OK anyway) */
312 	/* Try graceful DDEKit exit */
313 	ddekit_shutdown();
314 
315 	/* Unreachable, when ddekit_shutdown works correctly */
316 	panic("Calling ddekit_shutdown failed!");
317 }
318 
319 
320 /*===========================================================================*
321  *    ddekit_usb_task                                                        *
322  *===========================================================================*/
323 static void
ddekit_usb_task(void * UNUSED (arg))324 ddekit_usb_task(void * UNUSED(arg))
325 {
326 	HUB_DEBUG_DUMP;
327 
328 	/* TODO: This call was meant to return 'int' but loops forever instead,
329 	 * so no return value is checked */
330 	ddekit_usb_init(&usb_driver, NULL, NULL);
331 }
332 
333 
334 /*===========================================================================*
335  *    usb_driver_completion                                                  *
336  *===========================================================================*/
337 static void
usb_driver_completion(void * UNUSED (priv))338 usb_driver_completion(void * UNUSED(priv))
339 {
340 	HUB_DEBUG_DUMP;
341 
342 	/* Last request was completed so allow continuing
343 	 * execution from place where semaphore was downed */
344 	ddekit_sem_up(hub_sem);
345 }
346 
347 
348 /*===========================================================================*
349  *    usb_driver_connect                                                     *
350  *===========================================================================*/
351 static void
usb_driver_connect(struct ddekit_usb_dev * dev,unsigned int interfaces)352 usb_driver_connect(struct ddekit_usb_dev * dev, unsigned int interfaces)
353 {
354 	HUB_DEBUG_DUMP;
355 
356 	if (NULL != driver_state.dev)
357 		panic("HUB device driver can be connected only once!");
358 
359 	/* Clear current state */
360 	memset(&driver_state, 0, sizeof(driver_state));
361 
362 	/* Hold host information for future use */
363 	driver_state.dev = dev;
364 
365 	/* Let driver logic work */
366 	ddekit_sem_up(hub_sem);
367 }
368 
369 
370 /*===========================================================================*
371  *    usb_driver_disconnect                                                  *
372  *===========================================================================*/
373 static void
usb_driver_disconnect(struct ddekit_usb_dev * UNUSED (dev))374 usb_driver_disconnect(struct ddekit_usb_dev * UNUSED(dev))
375 {
376 	HUB_DEBUG_DUMP;
377 
378 	if (NULL == driver_state.dev)
379 		panic("HUB device driver was never connected!");
380 
381 	/* Discard connected device information */
382 	driver_state.dev = NULL;
383 }
384 
385 
386 /*===========================================================================*
387  *    hub_task                                                               *
388  *===========================================================================*/
389 static void
hub_task(void * UNUSED (arg))390 hub_task(void * UNUSED(arg))
391 {
392 	hub_port_status port_status;
393 	hub_state * s;
394 	hub_descriptor * d;
395 	int port;
396 
397 	HUB_DEBUG_DUMP;
398 
399 	/* For short */
400 	s = &(driver_state);
401 	d = &(s->descriptor);
402 
403 	/* Wait for connection */
404 	ddekit_sem_down(hub_sem);
405 
406 	if (hub_get_descriptor(d)) {
407 		HUB_MSG("Getting hub descriptor failed");
408 		goto HUB_ERROR;
409 	}
410 
411 	/* Output hub descriptor in debug mode */
412 	HUB_DEBUG_MSG("bDescLength         %4X", d->bDescLength);
413 	HUB_DEBUG_MSG("bDescriptorType     %4X", d->bDescriptorType);
414 	HUB_DEBUG_MSG("bNbrPorts           %4X", d->bNbrPorts);
415 	HUB_DEBUG_MSG("wHubCharacteristics %4X", d->wHubCharacteristics);
416 	HUB_DEBUG_MSG("bPwrOn2PwrGood      %4X", d->bPwrOn2PwrGood);
417 	HUB_DEBUG_MSG("bHubContrCurrent    %4X", d->bHubContrCurrent);
418 
419 	/* Check for sane number of ports... */
420 	if (d->bNbrPorts > USB_HUB_PORT_LIMIT) {
421 		HUB_MSG("Too many hub ports declared: %d", d->bNbrPorts);
422 		goto HUB_ERROR;
423 	}
424 
425 	/* ...and reassign */
426 	s->num_ports = (int)d->bNbrPorts;
427 
428 	/* Initialize all available ports starting
429 	 * from 1, as defined by USB 2.0 document */
430 	for (port = 1; port <= s->num_ports; port++) {
431 		if (hub_port_feature(port, SET_FEATURE, PORT_POWER)) {
432 			HUB_MSG("Powering port%d failed", port);
433 			goto HUB_ERROR;
434 		}
435 	}
436 
437 	/*
438 	 * Connection polling loop
439 	 */
440 	for (;;) {
441 		for (port = 1; port <= s->num_ports; port++) {
442 
443 			/* Ignore previously blocked ports */
444 			if (HUB_PORT_ERROR == s->conn[port]) {
445 				HUB_DEBUG_MSG("Blocked hub port ignored");
446 				continue;
447 			}
448 
449 			/* Get port status */
450 			if (hub_get_port_status(port, &port_status)) {
451 				HUB_MSG("Reading port%d status failed", port);
452 				goto HUB_ERROR;
453 			}
454 
455 			/* Resolve port changes */
456 			switch (hub_handle_change(port, &port_status)) {
457 
458 				case HUB_CHANGE_NONE:
459 					break;
460 
461 				case HUB_CHANGE_CONN:
462 					s->conn[port] = HUB_PORT_CONN;
463 					break;
464 
465 				case HUB_CHANGE_DISCONN:
466 					s->conn[port] = HUB_PORT_DISCONN;
467 					break;
468 
469 				case HUB_CHANGE_STATUS_ERR:
470 					/* Turn off port */
471 					if (hub_port_feature(port,
472 							CLEAR_FEATURE,
473 							PORT_POWER)) {
474 						HUB_MSG("Halting port%d "
475 							"failed", port);
476 						goto HUB_ERROR;
477 					}
478 					/* Block this port forever */
479 					s->conn[port] = HUB_PORT_ERROR;
480 
481 					HUB_MSG("Port%d status ERROR", port);
482 					HUB_MSG("Port%d will be blocked, until "
483 						"hub is detached", port);
484 
485 					break;
486 
487 				case HUB_CHANGE_COM_ERR:
488 					/* Serious error, hang */
489 					HUB_MSG("Handling port%d "
490 						"change failed", port);
491 					goto HUB_ERROR;
492 			}
493 		}
494 
495 		ddekit_thread_msleep(USB_HUB_POLLING_INTERVAL);
496 		HUB_DEBUG_MSG("Polling USB hub for status change");
497 	}
498 
499 	return;
500 
501 	HUB_ERROR:
502 	for (;;) {
503 		/* Hang till removed by devmand */
504 		HUB_MSG("Hub driver error occurred, hanging up");
505 		ddekit_sem_down(hub_sem);
506 	}
507 }
508 
509 
510 /*===========================================================================*
511  *    hub_get_descriptor                                                     *
512  *===========================================================================*/
513 static int
hub_get_descriptor(hub_descriptor * descriptor)514 hub_get_descriptor(hub_descriptor * descriptor)
515 {
516 	/* URB to be send */
517 	struct ddekit_usb_urb urb;
518 
519 	/* Setup buffer to be attached */
520 	struct usb_ctrlrequest setup_buf;
521 
522 	/* Control EP configuration */
523 	urb_ep_config ep_conf;
524 
525 	HUB_DEBUG_DUMP;
526 
527 	/* Initialize EP configuration */
528 	ep_conf.ep_num = 0;
529 	ep_conf.direction = DDEKIT_USB_IN;
530 	ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
531 	ep_conf.max_packet_size = 0;
532 	ep_conf.interval = 0;
533 
534 	/* Reset URB and assign given values */
535 	init_urb(&urb, driver_state.dev, &ep_conf);
536 
537 	/* Clear setup data */
538 	memset(&setup_buf, 0, sizeof(setup_buf));
539 
540 	/* Class get hub descriptor request */
541 	setup_buf.bRequestType = 0xA0;
542 	setup_buf.bRequest = 0x06;
543 	setup_buf.wValue = USB_HUB_DESCRIPTOR_TYPE << 8;
544 	setup_buf.wIndex = 0x00;
545 	setup_buf.wLength = sizeof(*descriptor);
546 
547 	/* Attach buffers to URB */
548 	attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
549 			&setup_buf, sizeof(setup_buf));
550 	attach_urb_data(&urb, URB_BUF_TYPE_DATA,
551 			descriptor, sizeof(*descriptor));
552 
553 	/* Send and wait for response */
554 	if (blocking_urb_submit(&urb, hub_sem, URB_SUBMIT_CHECK_LEN)) {
555 		HUB_MSG("Submitting HUB URB failed");
556 		return EXIT_FAILURE;
557 	} else {
558 		HUB_DEBUG_MSG("HUB descriptor received");
559 		return EXIT_SUCCESS;
560 	}
561 }
562 
563 
564 /*===========================================================================*
565  *    hub_port_feature                                                       *
566  *===========================================================================*/
567 static int
hub_port_feature(int port_num,class_code code,class_feature feature)568 hub_port_feature(int port_num, class_code code, class_feature feature)
569 {
570 	/* URB to be send */
571 	struct ddekit_usb_urb urb;
572 
573 	/* Setup buffer to be attached */
574 	struct usb_ctrlrequest setup_buf;
575 
576 	/* Control EP configuration */
577 	urb_ep_config ep_conf;
578 
579 	HUB_DEBUG_DUMP;
580 
581 	/* TODO: Add more checks when needed */
582 	if (!((port_num <= driver_state.num_ports) && (port_num > 0)))
583 		return EXIT_FAILURE;
584 
585 	if (!((code == SET_FEATURE) || (code == CLEAR_FEATURE)))
586 		return EXIT_FAILURE;
587 
588 	if (!((feature == PORT_RESET) || (feature == PORT_POWER) ||
589 		(feature == C_PORT_CONNECTION) || (feature == C_PORT_RESET)))
590 		return EXIT_FAILURE;
591 
592 	/* Initialize EP configuration */
593 	ep_conf.ep_num = 0;
594 	ep_conf.direction = DDEKIT_USB_OUT;
595 	ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
596 	ep_conf.max_packet_size = 0;
597 	ep_conf.interval = 0;
598 
599 	/* Reset URB and assign given values */
600 	init_urb(&urb, driver_state.dev, &ep_conf);
601 
602 	/* Clear setup data */
603 	memset(&setup_buf, 0, sizeof(setup_buf));
604 
605 	/* Standard get endpoint request */
606 	setup_buf.bRequestType = 0x23;
607 	setup_buf.bRequest = (u8_t)code;
608 	setup_buf.wValue = (u16_t)feature;
609 	setup_buf.wIndex = (u16_t)port_num;
610 	setup_buf.wLength = 0;
611 
612 	/* Attach buffers to URB */
613 	attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
614 			&setup_buf, sizeof(setup_buf));
615 
616 	/* Send and wait for response */
617 	if (blocking_urb_submit(&urb, hub_sem, URB_SUBMIT_CHECK_LEN)) {
618 		HUB_MSG("Submitting HUB URB failed");
619 		return EXIT_FAILURE;
620 	} else {
621 		HUB_DEBUG_MSG("PortFeature operation completed");
622 		return EXIT_SUCCESS;
623 	}
624 }
625 
626 
627 /*===========================================================================*
628  *    hub_get_port_status                                                    *
629  *===========================================================================*/
630 static int
hub_get_port_status(int port_num,hub_port_status * p)631 hub_get_port_status(int port_num, hub_port_status * p)
632 {
633 	/* URB to be send */
634 	struct ddekit_usb_urb urb;
635 
636 	/* Setup buffer to be attached */
637 	struct usb_ctrlrequest setup_buf;
638 
639 	/* Control EP configuration */
640 	urb_ep_config ep_conf;
641 
642 	HUB_DEBUG_DUMP;
643 
644 	if (!((port_num <= driver_state.num_ports) && (port_num > 0)))
645 		return EXIT_FAILURE;
646 
647 	/* Initialize EP configuration */
648 	ep_conf.ep_num = 0;
649 	ep_conf.direction = DDEKIT_USB_IN;
650 	ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
651 	ep_conf.max_packet_size = 0;
652 	ep_conf.interval = 0;
653 
654 	/* Reset URB and assign given values */
655 	init_urb(&urb, driver_state.dev, &ep_conf);
656 
657 	/* Clear setup data */
658 	memset(&setup_buf, 0, sizeof(setup_buf));
659 
660 	/* Standard get endpoint request */
661 	setup_buf.bRequestType = 0xA3;
662 	setup_buf.bRequest = (u8_t)GET_STATUS;
663 	setup_buf.wValue = 0x00;
664 	setup_buf.wIndex = (u16_t)port_num;
665 	setup_buf.wLength = sizeof(*p);
666 
667 	/* Attach buffers to URB */
668 	attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
669 			&setup_buf, sizeof(setup_buf));
670 	attach_urb_data(&urb, URB_BUF_TYPE_DATA,
671 			p, sizeof(*p));
672 
673 	/* Send and wait for response */
674 	if (blocking_urb_submit(&urb, hub_sem, URB_SUBMIT_CHECK_LEN)) {
675 		HUB_MSG("Submitting HUB URB failed");
676 		return EXIT_FAILURE;
677 	} else {
678 		HUB_DEBUG_MSG("Port%d status:      ", port_num);
679 		HUB_DEBUG_MSG("PORT_CONNECTION   %01X", p->PORT_CONNECTION);
680 		HUB_DEBUG_MSG("PORT_ENABLE       %01X", p->PORT_ENABLE);
681 		HUB_DEBUG_MSG("PORT_POWER        %01X", p->PORT_POWER);
682 		HUB_DEBUG_MSG("C_PORT_CONNECTION %01X", p->C_PORT_CONNECTION);
683 		HUB_DEBUG_MSG("C_PORT_ENABLE     %01X", p->C_PORT_ENABLE);
684 		return EXIT_SUCCESS;
685 	}
686 }
687 
688 
689 /*===========================================================================*
690  *    hub_handle_change                                                      *
691  *===========================================================================*/
692 static port_change
hub_handle_change(int port_num,hub_port_status * status)693 hub_handle_change(int port_num, hub_port_status * status)
694 {
695 	port_conn * c;
696 
697 	HUB_DEBUG_DUMP;
698 
699 	/* Possible combinations: */
700 	/* Change = status->C_PORT_CONNECTION	(hub connection change bit)
701 	 * Local = driver_state.conn[port_num]	(local connection status)
702 	 * Remote = status->PORT_CONNECTION	(hub connection status) */
703 	/*
704 	Case	Change	Local	Remote	Description
705 	1.	1	1	1	Polling mismatch (quick disconn-conn)
706 	2.	1	1	0	Just disconnected
707 	3.	1	0	1	Just connected
708 	4.	1	0	0	Polling mismatch (quick conn-disconn)
709 	5.	0	1	1	Still connected
710 	6.	0	1	0	Serious ERROR
711 	7.	0	0	1	Serious ERROR
712 	8.	0	0	0	Still disconnected
713 	*/
714 
715 	/* Reassign for code cleanliness */
716 	c = driver_state.conn;
717 
718 	/* Resolve combination */
719 	if (status->C_PORT_CONNECTION) {
720 
721 		/* C_PORT_CONNECTION was set, so clear change bit
722 		 * to allow further polling */
723 		if (hub_port_feature(port_num, CLEAR_FEATURE,
724 					C_PORT_CONNECTION)) {
725 			HUB_MSG("Clearing port%d change bit failed", port_num);
726 			return HUB_CHANGE_COM_ERR;
727 		}
728 
729 		if (HUB_PORT_CONN == c[port_num]) {
730 			if (status->PORT_CONNECTION) {
731 
732 				/*
733 				 * 1
734 				 */
735 				/* Make hub disconnect and connect again */
736 				if (hub_handle_disconnection(port_num) ||
737 					hub_handle_connection(port_num, status))
738 					return HUB_CHANGE_STATUS_ERR;
739 				else
740 					return HUB_CHANGE_CONN;
741 
742 			} else {
743 
744 				/*
745 				 * 2
746 				 */
747 				/* Handle disconnection */
748 				if (hub_handle_disconnection(port_num))
749 					return HUB_CHANGE_STATUS_ERR;
750 				else
751 					return HUB_CHANGE_DISCONN;
752 
753 			}
754 		} else if (HUB_PORT_DISCONN == c[port_num]) {
755 			if (status->PORT_CONNECTION) {
756 
757 				/*
758 				 * 3
759 				 */
760 				/* Handle connection */
761 				if (hub_handle_connection(port_num, status))
762 					return HUB_CHANGE_STATUS_ERR;
763 				else
764 					return HUB_CHANGE_CONN;
765 
766 			} else {
767 
768 				/*
769 				 * 4
770 				 */
771 				/* Since we were disconnected before and
772 				 * are disconnected now, additional handling
773 				 * may be ignored */
774 				return HUB_CHANGE_NONE;
775 
776 			}
777 		}
778 	} else {
779 		if (HUB_PORT_CONN == c[port_num]) {
780 			if (status->PORT_CONNECTION) {
781 
782 				/*
783 				 * 5
784 				 */
785 				/* Connected (nothing changed) */
786 				return HUB_CHANGE_NONE;
787 
788 			} else {
789 
790 				/*
791 				 * 6
792 				 */
793 				/* Serious status error */
794 				return HUB_CHANGE_STATUS_ERR;
795 
796 			}
797 		} else if (HUB_PORT_DISCONN == c[port_num]) {
798 			if (status->PORT_CONNECTION) {
799 
800 				/*
801 				 * 7
802 				 */
803 				/* Serious status error */
804 				return HUB_CHANGE_STATUS_ERR;
805 
806 			} else {
807 
808 				/*
809 				 * 8
810 				 */
811 				/* Disconnected (nothing changed) */
812 				return HUB_CHANGE_NONE;
813 
814 			}
815 		}
816 	}
817 
818 	return HUB_CHANGE_COM_ERR;
819 }
820 
821 
822 /*===========================================================================*
823  *    hub_handle_connection                                                  *
824  *===========================================================================*/
825 static int
hub_handle_connection(int port_num,hub_port_status * status)826 hub_handle_connection(int port_num, hub_port_status * status)
827 {
828 	struct timespec wait_time;
829 	int reset_tries;
830 	long port_speed;
831 
832 	HUB_DEBUG_DUMP;
833 
834 	HUB_MSG("Device connected to port%d", port_num);
835 
836 	/* This should never happen if power-off works as intended */
837 	if (status->C_PORT_RESET) {
838 		HUB_MSG("Unexpected reset state for port%d", port_num);
839 		return EXIT_FAILURE;
840 	}
841 
842 	/* Start reset signaling for this port */
843 	if (hub_port_feature(port_num, SET_FEATURE, PORT_RESET)) {
844 		HUB_MSG("Resetting port%d failed", port_num);
845 		return EXIT_FAILURE;
846 	}
847 
848 	reset_tries = 0;
849 	wait_time.tv_sec = 0;
850 	wait_time.tv_nsec = USB_HUB_RESET_DELAY;
851 
852 	/* Wait for reset completion */
853 	while (!status->C_PORT_RESET) {
854 		/* To avoid endless loop */
855 		if (reset_tries >= USB_HUB_MAX_TRIES) {
856 			HUB_MSG("Port%d reset took too long", port_num);
857 			return EXIT_FAILURE;
858 		}
859 
860 		/* Get port status again */
861 		if (hub_get_port_status(port_num, status)) {
862 			HUB_MSG("Reading port%d status failed", port_num);
863 			return EXIT_FAILURE;
864 		}
865 
866 		reset_tries++;
867 
868 		/* Ignore potential signal interruption (no return value check),
869 		 * since it causes driver termination anyway */
870 		if (nanosleep(&wait_time, NULL))
871 			HUB_MSG("Calling nanosleep() failed");
872 	}
873 
874 	/* Reset completed */
875 	HUB_DEBUG_MSG("Port%d reset complete", port_num);
876 
877 	/* Dump full status for analysis (high-speed, ...) */
878 	HUB_DEBUG_MSG("C_PORT_CONNECTION   %1X", status->C_PORT_CONNECTION  );
879 	HUB_DEBUG_MSG("C_PORT_ENABLE       %1X", status->C_PORT_ENABLE      );
880 	HUB_DEBUG_MSG("C_PORT_OVER_CURRENT %1X", status->C_PORT_OVER_CURRENT);
881 	HUB_DEBUG_MSG("C_PORT_RESET        %1X", status->C_PORT_RESET       );
882 	HUB_DEBUG_MSG("C_PORT_SUSPEND      %1X", status->C_PORT_SUSPEND     );
883 	HUB_DEBUG_MSG("PORT_CONNECTION     %1X", status->PORT_CONNECTION    );
884 	HUB_DEBUG_MSG("PORT_ENABLE         %1X", status->PORT_ENABLE        );
885 	HUB_DEBUG_MSG("PORT_HIGH_SPEED     %1X", status->PORT_HIGH_SPEED    );
886 	HUB_DEBUG_MSG("PORT_INDICATOR      %1X", status->PORT_INDICATOR     );
887 	HUB_DEBUG_MSG("PORT_LOW_SPEED      %1X", status->PORT_LOW_SPEED     );
888 	HUB_DEBUG_MSG("PORT_OVER_CURRENT   %1X", status->PORT_OVER_CURRENT  );
889 	HUB_DEBUG_MSG("PORT_POWER          %1X", status->PORT_POWER         );
890 	HUB_DEBUG_MSG("PORT_RESET          %1X", status->PORT_RESET         );
891 	HUB_DEBUG_MSG("PORT_SUSPEND        %1X", status->PORT_SUSPEND       );
892 	HUB_DEBUG_MSG("PORT_TEST           %1X", status->PORT_TEST          );
893 
894 	/* Clear reset change bit for further devices */
895 	if (hub_port_feature(port_num, CLEAR_FEATURE, C_PORT_RESET)) {
896 		HUB_MSG("Clearing port%d reset bit failed", port_num);
897 		return EXIT_FAILURE;
898 	}
899 
900 	/* Should never happen */
901 	if (!status->PORT_CONNECTION || !status->PORT_ENABLE) {
902 		HUB_MSG("Port%d unexpectedly unavailable", port_num);
903 		return EXIT_FAILURE;
904 	}
905 
906 	/* Determine port speed from status bits */
907 	if (status->PORT_LOW_SPEED) {
908 		if (status->PORT_HIGH_SPEED) {
909 			HUB_MSG("Port%d has invalid speed flags", port_num);
910 			return EXIT_FAILURE;
911 		} else
912 			port_speed = (long)DDEKIT_HUB_PORT_LS_CONN;
913 	} else {
914 		if (status->PORT_HIGH_SPEED)
915 			port_speed = (long)DDEKIT_HUB_PORT_HS_CONN;
916 		else
917 			port_speed = (long)DDEKIT_HUB_PORT_FS_CONN;
918 	}
919 
920 	/* Signal to HCD that port has device connected at given speed */
921 	return ddekit_usb_info(driver_state.dev, port_speed, (long)port_num);
922 }
923 
924 
925 /*===========================================================================*
926  *    hub_handle_disconnection                                               *
927  *===========================================================================*/
928 static int
hub_handle_disconnection(int port_num)929 hub_handle_disconnection(int port_num)
930 {
931 	HUB_DEBUG_DUMP;
932 
933 	HUB_MSG("Device disconnected from port%d", port_num);
934 
935 	return ddekit_usb_info(driver_state.dev, (long)DDEKIT_HUB_PORT_DISCONN,
936 				(long)port_num);
937 }
938