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