Create a branch for header work.
[reactos.git] / drivers / usb / nt4compat / usbdriver / hub.c
1 /**
2 * hub.c - USB driver stack project for Windows NT 4.0
3 *
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
5 *
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program (in the main directory of the distribution, the file
18 * COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "usbdriver.h"
23
24 //----------------------------------------------------------
25 //event pool routines
26 #define crash_machine() \
27 { ( ( PUSB_DEV ) 0 )->flags = 0x12345; }
28
29 #define hub_if_from_dev( pdEV, pIF ) \
30 {\
31 int i;\
32 for( i = 0; i < pdEV->usb_config->if_count; i ++ )\
33 {\
34 if( pdEV->usb_config->interf[ i ].pusb_if_desc->bInterfaceClass\
35 == USB_CLASS_HUB )\
36 {\
37 break;\
38 }\
39 }\
40 \
41 if( i < pdEV->usb_config->if_count )\
42 pIF = &pdev->usb_config->interf[ i ];\
43 else\
44 pIF = NULL;\
45 \
46 }
47
48 extern ULONG cpu_clock_freq;
49
50 BOOLEAN hub_check_reset_port_status(PUSB_DEV pdev, LONG port_idx);
51
52 VOID hub_reexamine_port_status_queue(PUSB_DEV hub_dev, ULONG port_idx, BOOLEAN from_dpc);
53
54 void hub_int_completion(PURB purb, PVOID pcontext);
55
56 VOID hub_get_port_status_completion(PURB purb, PVOID context);
57
58 VOID hub_clear_port_feature_completion(PURB purb, PVOID context);
59
60 VOID hub_event_examine_status_que(PUSB_DEV pdev, ULONG event, ULONG context, //hub_ext
61 ULONG param //port_idx
62 );
63
64 VOID hub_timer_wait_dev_stable(PUSB_DEV pdev,
65 PVOID context //port-index
66 );
67
68 VOID hub_event_dev_stable(PUSB_DEV pdev,
69 ULONG event,
70 ULONG context, //hub_ext
71 ULONG param //port_idx
72 );
73
74 VOID hub_post_esq_event(PUSB_DEV pdev, BYTE port_idx, PROCESS_EVENT pe);
75
76 void hub_set_cfg_completion(PURB purb, PVOID pcontext);
77
78 void hub_get_hub_desc_completion(PURB purb, PVOID pcontext);
79
80 NTSTATUS hub_start_int_request(PUSB_DEV pdev);
81
82 BOOLEAN hub_connect(PDEV_CONNECT_DATA init_param, DEV_HANDLE dev_handle);
83
84 BOOLEAN hub_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);
85
86 BOOLEAN hub_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);
87
88 NTSTATUS hub_disable_port_request(PUSB_DEV pdev, UCHAR port_idx);
89
90 VOID hub_start_reset_port_completion(PURB purb, PVOID context);
91
92 BOOLEAN
93 init_event_pool(PUSB_EVENT_POOL pool)
94 {
95 int i;
96
97 if (pool == NULL)
98 return FALSE;
99
100 if ((pool->event_array = usb_alloc_mem(NonPagedPool, sizeof(USB_EVENT) * MAX_EVENTS)) == NULL)
101 return FALSE;
102
103 InitializeListHead(&pool->free_que);
104 KeInitializeSpinLock(&pool->pool_lock);
105 pool->total_count = MAX_EVENTS;
106 pool->free_count = 0;
107
108 for(i = 0; i < MAX_EVENTS; i++)
109 {
110 free_event(pool, &pool->event_array[i]);
111 }
112
113 return TRUE;
114 }
115
116 BOOLEAN
117 free_event(PUSB_EVENT_POOL pool, PUSB_EVENT pevent)
118 {
119 if (pool == NULL || pevent == NULL)
120 {
121 return FALSE;
122 }
123
124 RtlZeroMemory(pevent, sizeof(USB_EVENT));
125 InsertTailList(&pool->free_que, &pevent->event_link);
126 pool->free_count++;
127 usb_dbg_print(DBGLVL_MAXIMUM + 1,
128 ("free_event(): alloced=0x%x, addr=0x%x\n", MAX_EVENTS - pool->free_count, pevent));
129
130 return TRUE;
131 }
132
133 //null if failed
134 PUSB_EVENT
135 alloc_event(PUSB_EVENT_POOL pool, LONG count)
136 {
137 PUSB_EVENT NewEvent;
138 if (pool == NULL || count != 1)
139 return NULL;
140
141 if (pool->free_count == 0)
142 return NULL;
143
144 NewEvent = (PUSB_EVENT) RemoveHeadList(&pool->free_que);
145 pool->free_count--;
146
147 usb_dbg_print(DBGLVL_MAXIMUM + 1,
148 ("alloc_event(): alloced=0x%x, addr=0x%x\n", MAX_EVENTS - pool->free_count, NewEvent));
149 return NewEvent;
150 }
151
152 BOOLEAN
153 destroy_event_pool(PUSB_EVENT_POOL pool)
154 {
155 if (pool == NULL)
156 return FALSE;
157
158 InitializeListHead(&pool->free_que);
159 pool->free_count = pool->total_count = 0;
160 usb_free_mem(pool->event_array);
161 pool->event_array = NULL;
162
163 return TRUE;
164 }
165
166 VOID
167 event_list_default_process_event(PUSB_DEV pdev, ULONG event, ULONG context, ULONG param)
168 {
169 UNREFERENCED_PARAMETER(param);
170 UNREFERENCED_PARAMETER(context);
171 UNREFERENCED_PARAMETER(event);
172 UNREFERENCED_PARAMETER(pdev);
173 }
174
175 //----------------------------------------------------------
176 //timer_svc pool routines
177
178 BOOLEAN
179 init_timer_svc_pool(PTIMER_SVC_POOL pool)
180 {
181 int i;
182
183 if (pool == NULL)
184 return FALSE;
185
186 pool->timer_svc_array = usb_alloc_mem(NonPagedPool, sizeof(TIMER_SVC) * MAX_TIMER_SVCS);
187 InitializeListHead(&pool->free_que);
188 pool->free_count = 0;
189 pool->total_count = MAX_TIMER_SVCS;
190 KeInitializeSpinLock(&pool->pool_lock);
191
192 for(i = 0; i < MAX_TIMER_SVCS; i++)
193 {
194 free_timer_svc(pool, &pool->timer_svc_array[i]);
195 }
196
197 return TRUE;
198 }
199
200 BOOLEAN
201 free_timer_svc(PTIMER_SVC_POOL pool, PTIMER_SVC ptimer)
202 {
203 if (pool == NULL || ptimer == NULL)
204 return FALSE;
205
206 RtlZeroMemory(ptimer, sizeof(TIMER_SVC));
207 InsertTailList(&pool->free_que, &ptimer->timer_svc_link);
208 pool->free_count++;
209
210 return TRUE;
211 }
212
213 //null if failed
214 PTIMER_SVC
215 alloc_timer_svc(PTIMER_SVC_POOL pool, LONG count)
216 {
217 PTIMER_SVC NewTimer;
218
219 if (pool == NULL || count != 1)
220 return NULL;
221
222 if (pool->free_count <= 0)
223 return NULL;
224
225 NewTimer = (PTIMER_SVC) RemoveHeadList(&pool->free_que);
226 pool->free_count--;
227 return NewTimer;
228
229 }
230
231 BOOLEAN
232 destroy_timer_svc_pool(PTIMER_SVC_POOL pool)
233 {
234 if (pool == NULL)
235 return FALSE;
236
237 usb_free_mem(pool->timer_svc_array);
238 pool->timer_svc_array = NULL;
239 InitializeListHead(&pool->free_que);
240 pool->free_count = 0;
241 pool->total_count = 0;
242
243 return TRUE;
244 }
245
246 VOID
247 event_list_default_process_queue(PLIST_HEAD event_list,
248 PUSB_EVENT_POOL event_pool, PUSB_EVENT usb_event, PUSB_EVENT out_event)
249 {
250 //remove the first event from the event list, and copy it to
251 //out_event
252
253 if (event_list == NULL || event_pool == NULL || usb_event == NULL || out_event == NULL)
254 return;
255
256 RemoveEntryList(&usb_event->event_link);
257 RtlCopyMemory(out_event, usb_event, sizeof(USB_EVENT));
258 free_event(event_pool, usb_event);
259 return;
260 }
261
262 BOOLEAN
263 psq_enqueue(PPORT_STATUS_QUEUE psq, ULONG status)
264 {
265 if (psq == NULL)
266 return FALSE;
267
268 if (psq_is_full(psq))
269 return FALSE;
270
271 psq->port_status[psq->status_count].wPortChange = HIWORD(status);
272 psq->port_status[psq->status_count].wPortStatus = LOWORD(status);
273
274 psq->status_count++;
275
276 usb_dbg_print(DBGLVL_MAXIMUM, ("psq_enqueue(): last status=0x%x, status count=0x%x, port_flag=0x%x\n",
277 status, psq->status_count, psq->port_flags));
278 return TRUE;
279
280 }
281
282 VOID
283 psq_init(PPORT_STATUS_QUEUE psq)
284 {
285 RtlZeroMemory(psq, sizeof(PORT_STATUS_QUEUE));
286 psq->port_flags = STATE_IDLE | USB_PORT_FLAG_DISABLE;
287 }
288
289 //return 0xffffffff if no element
290 ULONG
291 psq_outqueue(PPORT_STATUS_QUEUE psq)
292 {
293 ULONG status;
294
295 if (psq == NULL)
296 return 0;
297
298 if (psq_is_empty(psq))
299 return 0;
300
301 status = ((PULONG) & psq->port_status)[0];
302 psq->port_status[0] = psq->port_status[1];
303 psq->port_status[1] = psq->port_status[2];
304 psq->port_status[2] = psq->port_status[3];
305 psq->status_count--;
306
307 return status;
308 }
309
310 BOOLEAN
311 psq_push(PPORT_STATUS_QUEUE psq, ULONG status)
312 {
313 if (psq == NULL)
314 return FALSE;
315
316 status = ((PULONG) & psq->port_status)[0];
317 psq->port_status[3] = psq->port_status[2];
318 psq->port_status[2] = psq->port_status[1];
319 psq->port_status[1] = psq->port_status[0];
320
321 ((PULONG) & psq->port_status)[0] = status;
322
323 psq->status_count++;
324 psq->status_count = ((4 > psq->status_count) ? psq->status_count : 4);
325
326 return TRUE;
327 }
328
329 BOOLEAN
330 hub_driver_init(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
331 {
332 UNREFERENCED_PARAMETER(dev_mgr);
333
334 //init driver structure, no PNP table functions
335 pdriver->driver_desc.flags = USB_DRIVER_FLAG_DEV_CAPABLE;
336 pdriver->driver_desc.vendor_id = 0xffff; // USB Vendor ID
337 pdriver->driver_desc.product_id = 0xffff; // USB Product ID.
338 pdriver->driver_desc.release_num = 0xffff; // Release Number of Device
339
340 pdriver->driver_desc.config_val = 0; // Configuration Value
341 pdriver->driver_desc.if_num = 0; // Interface Number
342 pdriver->driver_desc.if_class = USB_CLASS_HUB; // Interface Class
343 pdriver->driver_desc.if_sub_class = 0; // Interface SubClass
344 pdriver->driver_desc.if_protocol = 0; // Interface Protocol
345
346 pdriver->driver_desc.driver_name = "USB hub"; // Driver name for Name Registry
347 pdriver->driver_desc.dev_class = USB_CLASS_HUB;
348 pdriver->driver_desc.dev_sub_class = 0; // Device Subclass
349 pdriver->driver_desc.dev_protocol = 0; // Protocol Info.
350
351 //pdriver->driver_init = hub_driver_init; // initialized in dev_mgr_init_driver
352 //pdriver->driver_destroy = hub_driver_destroy;
353
354 pdriver->driver_ext = 0;
355 pdriver->driver_ext_size = 0;
356
357 pdriver->disp_tbl.version = 1;
358 pdriver->disp_tbl.dev_connect = hub_connect;
359 pdriver->disp_tbl.dev_disconnect = hub_disconnect;
360 pdriver->disp_tbl.dev_stop = hub_stop;
361 pdriver->disp_tbl.dev_reserved = NULL;
362
363 return TRUE;
364 }
365
366 BOOLEAN
367 hub_driver_destroy(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
368 {
369 UNREFERENCED_PARAMETER(dev_mgr);
370
371 pdriver->driver_ext = NULL;
372 return TRUE;
373 }
374
375 void
376 hub_reset_pipe_completion(PURB purb, //only for reference, can not be released
377 PVOID context)
378 {
379 PUSB_DEV pdev;
380 PUSB_ENDPOINT pendp;
381
382 USE_BASIC_NON_PENDING_IRQL;
383
384 UNREFERENCED_PARAMETER(context);
385
386 if (purb == NULL)
387 {
388 return;
389 }
390
391 pdev = purb->pdev;
392 pendp = purb->pendp;
393
394 lock_dev(pdev, TRUE);
395 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
396 {
397 unlock_dev(pdev, TRUE);
398 return;
399 }
400
401 if (usb_error(purb->status))
402 {
403 //simply retry it
404 unlock_dev(pdev, TRUE);
405 //usb_free_mem( purb );
406 return;
407 }
408 unlock_dev(pdev, TRUE);
409
410 pdev = purb->pdev;
411 hub_start_int_request(pdev);
412 return;
413 }
414
415 NTSTATUS
416 hub_start_int_request(PUSB_DEV pdev)
417 {
418 PURB purb;
419 PUSB_INTERFACE pif;
420 PHUB2_EXTENSION hub_ext;
421 NTSTATUS status;
422 PHCD hcd;
423 USE_BASIC_NON_PENDING_IRQL;
424
425 if (pdev == NULL)
426 return STATUS_INVALID_PARAMETER;
427
428 lock_dev(pdev, FALSE);
429 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
430 {
431 unlock_dev(pdev, FALSE);
432 return STATUS_DEVICE_DOES_NOT_EXIST;
433 }
434 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
435
436 if (purb == NULL)
437 {
438 unlock_dev(pdev, FALSE);
439 return STATUS_NO_MEMORY;
440 }
441
442 RtlZeroMemory(purb, sizeof(URB));
443
444 purb->flags = 0;
445 purb->status = STATUS_SUCCESS;
446 hub_ext = hub_ext_from_dev(pdev);
447 purb->data_buffer = hub_ext->int_data_buf;
448 purb->data_length = (hub_ext->port_count + 7) / 8;
449
450 hub_if_from_dev(pdev, pif);
451 usb_dbg_print(DBGLVL_ULTRA, ("hub_start_int_request(): pdev=0x%x, pif=0x%x\n", pdev, pif));
452 purb->pendp = &pif->endp[0];
453 purb->pdev = pdev;
454
455 purb->completion = hub_int_completion;
456 purb->context = hub_ext;
457
458 purb->pirp = NULL;
459 purb->reference = 0;
460 hcd = pdev->hcd;
461 unlock_dev(pdev, FALSE);
462
463 status = hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb);
464 if (status != STATUS_PENDING)
465 {
466 usb_free_mem(purb);
467 purb = NULL;
468 }
469
470 return status;
471 }
472
473 void
474 hub_int_completion(PURB purb, PVOID pcontext)
475 {
476
477 PUSB_DEV pdev;
478 PHUB2_EXTENSION hub_ext;
479 ULONG port_idx;
480 PUSB_CTRL_SETUP_PACKET psetup;
481 NTSTATUS status;
482 LONG i;
483 PHCD hcd;
484
485 USE_BASIC_NON_PENDING_IRQL;
486
487 if (purb == NULL)
488 return;
489
490 if (pcontext == NULL)
491 {
492 usb_free_mem(purb);
493 return;
494 }
495
496 usb_dbg_print(DBGLVL_ULTRA, ("hub_int_completion(): entering...\n"));
497
498 pdev = purb->pdev;
499 hub_ext = pcontext;
500
501 lock_dev(pdev, TRUE);
502 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
503 {
504 unlock_dev(pdev, TRUE);
505 usb_free_mem(purb);
506 return;
507 }
508
509 hcd = pdev->hcd;
510
511 if (purb->status == STATUS_SUCCESS)
512 {
513
514 for(i = 1; i <= hub_ext->port_count; i++)
515 {
516 if (hub_ext->int_data_buf[i >> 3] & (1 << i))
517 {
518 break;
519 }
520 }
521 if (i > hub_ext->port_count)
522 {
523 //no status change, re-initialize the int request
524 unlock_dev(pdev, TRUE);
525 usb_free_mem(purb);
526 hub_start_int_request(pdev);
527 return;
528 }
529
530 port_idx = (ULONG)i;
531
532 //re-use the urb to get port status
533 purb->pendp = &pdev->default_endp;
534 purb->data_buffer = (PUCHAR) & hub_ext->port_status;
535
536 purb->data_length = sizeof(USB_PORT_STATUS);
537 purb->pdev = pdev;
538
539 purb->context = hub_ext;
540 purb->pdev = pdev;
541 purb->completion = hub_get_port_status_completion;
542 purb->reference = port_idx;
543
544 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
545
546 psetup->bmRequestType = 0xa3; //host-device class other recepient
547 psetup->bRequest = USB_REQ_GET_STATUS;
548 psetup->wValue = 0;
549 psetup->wIndex = (USHORT) port_idx;
550 psetup->wLength = 4;
551
552 purb->pirp = NULL;
553 unlock_dev(pdev, TRUE);
554
555 status = hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb);
556 if (usb_error(status))
557 {
558 usb_free_mem(purb);
559 purb = NULL;
560 }
561 else if (status == STATUS_SUCCESS)
562 {
563 // this is for root hub
564 hcd->hcd_generic_urb_completion(purb, purb->context);
565 }
566 return;
567 }
568 else
569 {
570 unlock_dev(pdev, TRUE);
571 if (usb_halted(purb->status))
572 {
573 //let's reset pipe
574 usb_reset_pipe(pdev, purb->pendp, hub_reset_pipe_completion, NULL);
575 }
576 //unexpected error
577 usb_free_mem(purb);
578 purb = NULL;
579 }
580 return;
581 }
582
583 VOID
584 hub_get_port_status_completion(PURB purb, PVOID context)
585 {
586 PUSB_DEV pdev;
587 PUSB_ENDPOINT pendp;
588 BYTE port_idx;
589 PHUB2_EXTENSION hub_ext;
590 PUSB_CTRL_SETUP_PACKET psetup;
591 NTSTATUS status;
592 PHCD hcd;
593
594 USE_BASIC_NON_PENDING_IRQL;
595
596 if (purb == NULL || context == NULL)
597 return;
598
599 usb_dbg_print(DBGLVL_MAXIMUM, ("hub_get_port_feature_completion(): entering...\n"));
600
601 pdev = purb->pdev;
602 pendp = purb->pendp;
603
604 lock_dev(pdev, TRUE);
605 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
606 {
607 unlock_dev(pdev, TRUE);
608 usb_free_mem(purb);
609 return;
610 }
611
612 hcd = pdev->hcd;
613 if (usb_error(purb->status))
614 {
615 unlock_dev(pdev, TRUE);
616
617 purb->status = 0;
618 //simply retry the request refer to item 55 in document
619 status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
620 if (status != STATUS_PENDING)
621 {
622 if (status == STATUS_SUCCESS)
623 {
624 hcd->hcd_generic_urb_completion(purb, purb->context);
625
626 }
627 else
628 {
629 //
630 // must be fatal error
631 // FIXME: better to pass it to the completion for further
632 // processing?
633 //
634 usb_free_mem(purb);
635 }
636 }
637 return;
638 }
639
640 hub_ext = hub_ext_from_dev(pdev);
641 port_idx = (BYTE) purb->reference;
642
643 usb_dbg_print(DBGLVL_MAXIMUM, ("hub_get_port_stataus_completion(): port_idx=0x%x, hcd =0x%x, \
644 pdev=0x%x, purb=0x%x, hub_ext=0x%x, portsc=0x%x \n", port_idx, pdev->hcd, pdev,
645 purb, hub_ext, *((PULONG) purb->data_buffer)));
646
647 psq_enqueue(&hub_ext->port_status_queue[port_idx], *((PULONG) purb->data_buffer));
648
649 //reuse the urb to clear the feature
650 RtlZeroMemory(purb, sizeof(URB));
651
652 purb->data_buffer = NULL;
653 purb->data_length = 0;
654 purb->pendp = &pdev->default_endp;
655 purb->pdev = pdev;
656
657 purb->context = (PVOID) & hub_ext->port_status;
658 purb->pdev = pdev;
659 purb->completion = hub_clear_port_feature_completion;
660 purb->reference = port_idx;
661
662 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
663
664 psetup->bmRequestType = 0x23; //host-device class port recepient
665 psetup->bRequest = USB_REQ_CLEAR_FEATURE;
666 psetup->wIndex = port_idx;
667 psetup->wLength = 0;
668 purb->pirp = NULL;
669
670 if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_CONNECTION)
671 {
672 psetup->wValue = USB_PORT_FEAT_C_CONNECTION;
673 }
674 else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_ENABLE)
675 {
676 psetup->wValue = USB_PORT_FEAT_C_ENABLE;
677 }
678 else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_SUSPEND)
679 {
680 psetup->wValue = USB_PORT_FEAT_C_SUSPEND;
681 }
682 else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_OVERCURRENT)
683 {
684 psetup->wValue = USB_PORT_FEAT_C_OVER_CURRENT;
685 }
686 else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_RESET)
687 {
688 psetup->wValue = USB_PORT_FEAT_C_RESET;
689 }
690 unlock_dev(pdev, TRUE);
691
692 status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
693
694 // if( status != STATUS_SUCCESS )
695 if (status != STATUS_PENDING)
696 {
697 hcd->hcd_generic_urb_completion(purb, purb->context);
698 }
699 /*else if( usb_error( status ) )
700 {
701 usb_free_mem( purb );
702 return;
703 } */
704 return;
705
706 }
707
708 VOID
709 hub_clear_port_feature_completion(PURB purb, PVOID context)
710 {
711 BYTE port_idx;
712 LONG i;
713 BOOLEAN event_post, brh;
714 ULONG pc;
715 PHCD hcd;
716 NTSTATUS status;
717 PUSB_DEV pdev;
718 PHUB2_EXTENSION hub_ext = NULL;
719 PUSB_DEV_MANAGER dev_mgr;
720
721 PUSB_CTRL_SETUP_PACKET psetup;
722
723 USE_BASIC_NON_PENDING_IRQL;
724
725 if (purb == NULL)
726 return;
727
728 if (context == NULL)
729 {
730 usb_free_mem(purb);
731 return;
732 }
733
734 usb_dbg_print(DBGLVL_MAXIMUM, ("hub_clear_port_feature_completion(): entering...\n"));
735
736 pdev = purb->pdev;
737 port_idx = (BYTE) purb->reference;
738
739 lock_dev(pdev, TRUE);
740 dev_mgr = dev_mgr_from_dev(pdev);
741 hcd = pdev->hcd;
742 brh = (BOOLEAN) (dev_class(pdev) == USB_DEV_CLASS_ROOT_HUB);
743
744 if (usb_error(purb->status))
745 {
746 unlock_dev(pdev, TRUE);
747
748 purb->status = 0;
749
750 // retry the request
751 status = hcd->hcd_submit_urb(hcd, purb->pdev, purb->pendp, purb);
752 if (status != STATUS_PENDING)
753 {
754 if (status == STATUS_SUCCESS)
755 {
756 hcd->hcd_generic_urb_completion(purb, purb->context);
757 }
758 else
759 {
760 //
761 // FIXME: should we pass the error to the completion directly
762 // instead of forstall it here?
763 //
764 // do not think the device is workable, no requests to it any more.
765 // including the int polling
766
767 if (purb)
768 usb_free_mem(purb);
769
770 if (port_idx)
771 hub_check_reset_port_status(pdev, port_idx);
772 }
773 }
774 return;
775 }
776
777 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
778 {
779 unlock_dev(pdev, TRUE);
780 usb_free_mem(purb);
781 return;
782 }
783
784 pc = ((PUSB_PORT_STATUS) context)->wPortChange;
785
786 if (pc)
787 {
788 // the bits are tested in ascending order
789 if (pc & USB_PORT_STAT_C_CONNECTION)
790 {
791 pc &= ~USB_PORT_STAT_C_CONNECTION;
792 }
793 else if (pc & USB_PORT_STAT_C_ENABLE)
794 {
795 pc &= ~USB_PORT_STAT_C_ENABLE;
796 }
797 else if (pc & USB_PORT_STAT_C_SUSPEND)
798 {
799 pc &= ~USB_PORT_STAT_C_SUSPEND;
800 }
801 else if (pc & USB_PORT_STAT_C_OVERCURRENT)
802 {
803 pc &= ~USB_PORT_STAT_C_OVERCURRENT;
804 }
805 else if (pc & USB_PORT_STAT_C_RESET)
806 {
807 pc &= ~USB_PORT_STAT_C_RESET;
808 }
809 }
810 ((PUSB_PORT_STATUS) context)->wPortChange = (USHORT) pc;
811
812 hub_ext = hub_ext_from_dev(pdev);
813
814 if (pc)
815 {
816 //some other status change on the port still active
817 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
818
819 if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_CONNECTION)
820 {
821 psetup->wValue = USB_PORT_FEAT_C_CONNECTION;
822 }
823 else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_ENABLE)
824 {
825 psetup->wValue = USB_PORT_FEAT_C_ENABLE;
826 }
827 else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_SUSPEND)
828 {
829 psetup->wValue = USB_PORT_FEAT_C_SUSPEND;
830 }
831 else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_OVERCURRENT)
832 {
833 psetup->wValue = USB_PORT_FEAT_C_OVER_CURRENT;
834 }
835 else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_RESET)
836 {
837 psetup->wValue = USB_PORT_FEAT_C_RESET;
838 }
839 unlock_dev(pdev, TRUE);
840
841 status = hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb);
842 if (status != STATUS_PENDING)
843 {
844 if (status == STATUS_SUCCESS)
845 {
846 usb_dbg_print(DBGLVL_MAXIMUM,
847 ("hub_clear_port_status_completion(): port_idx=0x%x, hcd=0x%x, \
848 pdev=0x%x, purb=0x%x, hub_ext=0x%x, wPortChange=0x%x \n",
849 port_idx, pdev->hcd, pdev, purb, hub_ext, pc));
850
851 hcd->hcd_generic_urb_completion(purb, purb->context);
852 }
853 else
854 {
855 usb_dbg_print(DBGLVL_MAXIMUM, (" hub_clear_port_feature_completion(): \
856 error=0x%x\n", status));
857
858 // usb_free_mem( purb );
859 goto LBL_SCAN_PORT_STAT;
860 }
861 }
862 return;
863 }
864
865 for(i = 1; i <= hub_ext->port_count; i++)
866 {
867 if (hub_ext->int_data_buf[i >> 3] & (1 << i))
868 {
869 break;
870 }
871 }
872
873 //clear the port-change map, we have get port i's status.
874 hub_ext->int_data_buf[i >> 3] &= ~(1 << i);
875
876 //rescan to find some other port that has status change
877 for(i = 1; i <= hub_ext->port_count; i++)
878 {
879 if (hub_ext->int_data_buf[i >> 3] & (1 << i))
880 {
881 break;
882 }
883 }
884
885 if (i <= hub_ext->port_count)
886 {
887 //still has port-change pending, get the port status change
888 port_idx = (UCHAR) i;
889
890 //re-use the urb
891 purb->data_buffer = (PUCHAR) & hub_ext->port_status;
892 purb->data_length = sizeof(USB_PORT_STATUS);
893 purb->pendp = &pdev->default_endp;
894 purb->pdev = pdev;
895
896 purb->context = hub_ext;
897 purb->pdev = pdev;
898 purb->completion = hub_get_port_status_completion;
899 purb->reference = port_idx;
900
901 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
902
903 psetup->bmRequestType = 0xa3; //host-device class other recepient
904 psetup->bRequest = USB_REQ_GET_STATUS;
905 psetup->wValue = 0;
906 psetup->wIndex = port_idx;
907 psetup->wLength = 4;
908
909 purb->pirp = NULL;
910
911 unlock_dev(pdev, TRUE);
912
913 status = hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb);
914 if (status != STATUS_PENDING)
915 {
916 if (status == STATUS_SUCCESS)
917 {
918 hcd->hcd_generic_urb_completion(purb, purb->context);
919 }
920 else
921 { //must be fatal error
922 // usb_free_mem( purb );
923 goto LBL_SCAN_PORT_STAT;
924 }
925 }
926 return;
927 }
928
929 unlock_dev(pdev, TRUE);
930
931 LBL_SCAN_PORT_STAT:
932
933 //all status changes are cleared
934 if (purb)
935 usb_free_mem(purb);
936
937 purb = NULL;
938
939 KeAcquireSpinLockAtDpcLevel(&dev_mgr->event_list_lock);
940 lock_dev(pdev, TRUE);
941
942 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
943 {
944 //
945 // if reset is in process, the dev_mgr_disconnect_dev will continue
946 // the following resets
947 //
948 unlock_dev(pdev, TRUE);
949 KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
950 return;
951 }
952
953 //at last we wake up thread if some port have status change to process
954 port_idx = 0;
955 for(i = 1, event_post = FALSE; i <= hub_ext->port_count; i++)
956 {
957 if (psq_is_empty(&hub_ext->port_status_queue[i]) == FALSE)
958 {
959 if (port_state(hub_ext->port_status_queue[i].port_flags) == STATE_IDLE ||
960 port_state(hub_ext->port_status_queue[i].port_flags) == STATE_WAIT_ADDRESSED)
961 {
962 // have status in the queue pending
963 // STATE_WAIT_ADDRESSED is added to avoid some bad mannered
964 // hub to disturb the reset process
965 hub_post_esq_event(pdev, (BYTE) i, hub_event_examine_status_que);
966 }
967 else if (port_state(hub_ext->port_status_queue[i].port_flags) == STATE_WAIT_RESET_COMPLETE)
968 {
969 //there is only one reset at one time
970 port_idx = (BYTE) i;
971 }
972 }
973 }
974
975 unlock_dev(pdev, TRUE);
976 KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
977
978
979 if (port_idx)
980 hub_check_reset_port_status(pdev, port_idx);
981
982 //reinitialize the int request, here to reduce some uncertainty of concurrency
983 hub_start_int_request(pdev);
984
985 return;
986 }
987
988 VOID
989 hub_event_examine_status_que(PUSB_DEV pdev,
990 ULONG event,
991 ULONG context, //hub_ext
992 ULONG param //port_idx
993 )
994 {
995 PHUB2_EXTENSION hub_ext;
996 USB_PORT_STATUS ps;
997 PUSB_DEV pchild_dev;
998 PTIMER_SVC ptimer;
999 PUSB_DEV_MANAGER dev_mgr;
1000
1001 USE_NON_PENDING_IRQL;
1002
1003 UNREFERENCED_PARAMETER(event);
1004
1005 if (pdev == NULL || context == 0 || param == 0)
1006 return;
1007
1008 while (TRUE)
1009 {
1010 lock_dev(pdev, FALSE);
1011 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1012 {
1013 unlock_dev(pdev, FALSE);
1014 break;
1015 }
1016
1017 dev_mgr = dev_mgr_from_dev(pdev);
1018 hub_ext = hub_ext_from_dev(pdev);
1019
1020 if (psq_is_empty(&hub_ext->port_status_queue[param]))
1021 {
1022 set_port_state(hub_ext->port_status_queue[param].port_flags, STATE_IDLE);
1023 unlock_dev(pdev, FALSE);
1024 break;
1025 }
1026
1027 *((ULONG *) & ps) = psq_outqueue(&hub_ext->port_status_queue[param]);
1028
1029
1030 pchild_dev = hub_ext->child_dev[param];
1031 hub_ext->child_dev[param] = 0;
1032
1033 usb_dbg_print(DBGLVL_MAXIMUM,
1034 ("hub_event_examine_status_queue(): dev_addr=0x%x, port=0x%x, wPortChange=0x%x, wPortStatus=0x%x\n",
1035 pdev->dev_addr, param, ps.wPortChange, ps.wPortStatus));
1036
1037 unlock_dev(pdev, FALSE);
1038
1039 if (pchild_dev != NULL)
1040 dev_mgr_disconnect_dev(pchild_dev);
1041
1042 if (((ps.wPortChange & USB_PORT_STAT_C_ENABLE) &&
1043 ((pdev->flags & USB_DEV_CLASS_MASK) != USB_DEV_CLASS_ROOT_HUB))
1044 || (ps.wPortChange & USB_PORT_STAT_C_OVERCURRENT)
1045 || (ps.wPortChange & USB_PORT_STAT_C_RESET)
1046 || ((ps.wPortChange & USB_PORT_STAT_C_CONNECTION) &&
1047 !(ps.wPortStatus & USB_PORT_STAT_CONNECTION)))
1048 {
1049 usb_dbg_print(DBGLVL_MAXIMUM,
1050 ("hub_event_examine_status_queue(): error occured, portc=0x%x, ports=0x%x\n",
1051 ps.wPortChange, ps.wPortStatus));
1052
1053 lock_dev(pdev, FALSE);
1054 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1055 {
1056 unlock_dev(pdev, FALSE);
1057 break;
1058 }
1059 if (psq_is_empty(&hub_ext->port_status_queue[param]))
1060 {
1061 set_port_state(hub_ext->port_status_queue[param].port_flags, STATE_IDLE);
1062 }
1063 else
1064 {
1065 set_port_state(hub_ext->port_status_queue[param].port_flags, STATE_EXAMINE_STATUS_QUE);
1066 }
1067 unlock_dev(pdev, FALSE);
1068 continue;
1069
1070 }
1071 else if ((ps.wPortChange & USB_PORT_STAT_C_CONNECTION)
1072 && (ps.wPortStatus & USB_PORT_STAT_CONNECTION)
1073 && psq_is_empty(&hub_ext->port_status_queue[param]))
1074 {
1075 KeAcquireSpinLock(&dev_mgr->timer_svc_list_lock, &old_irql);
1076 lock_dev(pdev, TRUE);
1077 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1078 {
1079 unlock_dev(pdev, TRUE);
1080 KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
1081 usb_dbg_print(DBGLVL_MAXIMUM, ("hub_event_examine_status_queue(): dev lost\n"));
1082 break;
1083 }
1084 ptimer = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
1085 if (ptimer == NULL)
1086 {
1087 unlock_dev(pdev, TRUE);
1088 KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
1089 usb_dbg_print(DBGLVL_MAXIMUM,
1090 ("hub_event_examine_status_queue(): timer can not allocated\n"));
1091 break;
1092 }
1093
1094 //a new connection
1095 usb_dbg_print(DBGLVL_MAXIMUM, ("hub_event_examine_status_queue(): new connection comes\n"));
1096
1097 ptimer->counter = 0;
1098 ptimer->threshold = 21; //100 ms
1099
1100 if (ps.wPortStatus & USB_PORT_STAT_LOW_SPEED)
1101 ptimer->threshold = 51; //500 ms
1102
1103 ptimer->context = param;
1104 ptimer->pdev = pdev;
1105 ptimer->func = hub_timer_wait_dev_stable;
1106 InsertTailList(&dev_mgr->timer_svc_list, &ptimer->timer_svc_link);
1107 pdev->ref_count++;
1108 set_port_state(hub_ext->port_status_queue[param].port_flags, STATE_WAIT_STABLE);
1109 unlock_dev(pdev, TRUE);
1110 KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
1111 break;
1112
1113 }
1114 else
1115 {
1116 usb_dbg_print(DBGLVL_MAXIMUM, ("hub_event_examine_status_queue(): unknown error\n"));
1117 continue;
1118 }
1119 }
1120 return;
1121 }
1122
1123 VOID
1124 hub_timer_wait_dev_stable(PUSB_DEV pdev,
1125 PVOID context //port-index
1126 )
1127 {
1128
1129 PHUB2_EXTENSION hub_ext;
1130 ULONG param;
1131 PUSB_DEV_MANAGER dev_mgr;
1132
1133 USE_BASIC_NON_PENDING_IRQL;
1134
1135 if (pdev == NULL || context == 0)
1136 return;
1137
1138 dev_mgr = dev_mgr_from_dev(pdev);
1139 param = (ULONG) context;
1140 KeAcquireSpinLockAtDpcLevel(&dev_mgr->event_list_lock);
1141 lock_dev(pdev, TRUE);
1142
1143 pdev->ref_count--;
1144
1145 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1146 {
1147 goto LBL_OUT;
1148 }
1149
1150 hub_ext = hub_ext_from_dev(pdev);
1151
1152 if (!psq_is_empty(&hub_ext->port_status_queue[param]))
1153 {
1154 //error occured, normally we should not receive event here
1155 set_port_state(hub_ext->port_status_queue[param].port_flags, STATE_EXAMINE_STATUS_QUE);
1156
1157 hub_post_esq_event(pdev, (BYTE) param, hub_event_examine_status_que);
1158 }
1159 else
1160 {
1161 set_port_state(hub_ext->port_status_queue[param].port_flags, STATE_WAIT_RESET);
1162
1163 hub_post_esq_event(pdev, (BYTE) param, hub_event_dev_stable);
1164
1165 }
1166
1167 LBL_OUT:
1168 unlock_dev(pdev, TRUE);
1169 KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
1170 return;
1171 }
1172
1173 VOID
1174 hub_event_dev_stable(PUSB_DEV pdev,
1175 ULONG event,
1176 ULONG context, //hub_ext
1177 ULONG param //port_idx
1178 )
1179 {
1180
1181 PHUB2_EXTENSION hub_ext;
1182 PUSB_EVENT pevent, pevent1;
1183 PLIST_ENTRY pthis, pnext;
1184 BOOLEAN que_exist;
1185 PHCD hcd;
1186 PUSB_DEV_MANAGER dev_mgr;
1187 NTSTATUS status;
1188 PURB purb;
1189 PUSB_CTRL_SETUP_PACKET psetup;
1190
1191 USE_NON_PENDING_IRQL;
1192
1193 UNREFERENCED_PARAMETER(event);
1194
1195 if (pdev == NULL || context == 0 || param == 0)
1196 return;
1197
1198 dev_mgr = dev_mgr_from_dev(pdev);
1199 KeAcquireSpinLock(&dev_mgr->event_list_lock, &old_irql);
1200 lock_dev(pdev, TRUE);
1201
1202 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1203 goto LBL_OUT;
1204
1205 hub_ext = hub_ext_from_dev(pdev);
1206 hcd = pdev->hcd;
1207
1208 pevent = alloc_event(&dev_mgr->event_pool, 1);
1209 if (pevent == NULL)
1210 goto LBL_OUT;
1211
1212 pevent->event = USB_EVENT_WAIT_RESET_PORT;
1213 pevent->pdev = pdev;
1214 pevent->context = (ULONG) hub_ext;
1215 pevent->param = param;
1216 pevent->flags = USB_EVENT_FLAG_QUE_RESET;
1217 pevent->process_event = NULL; //hub_event_reset_port_complete;
1218 pevent->process_queue = NULL; //hub_event_reset_process_queue;
1219 pevent->pnext = NULL;
1220
1221 ListFirst(&dev_mgr->event_list, pthis);
1222 que_exist = FALSE;
1223
1224 while (pthis)
1225 {
1226 //insert the event in to the wait-queue
1227 pevent1 = (PUSB_EVENT) pthis;
1228 if (pevent1->event == USB_EVENT_WAIT_RESET_PORT)
1229 {
1230 while (pevent1->pnext)
1231 pevent1 = pevent1->pnext;
1232
1233 pevent1->pnext = pevent;
1234 que_exist = TRUE;
1235 break;
1236 }
1237 ListNext(&dev_mgr->event_list, pthis, pnext);
1238 pthis = pnext;
1239 }
1240
1241 if (!que_exist)
1242 {
1243 //Let's start a reset port request
1244 InsertHeadList(&dev_mgr->event_list, &pevent->event_link);
1245 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
1246 if (!purb) goto LBL_OUT;
1247 RtlZeroMemory(purb, sizeof(URB));
1248
1249 purb->data_buffer = NULL;
1250 purb->data_length = 0;
1251 purb->pendp = &pdev->default_endp;
1252
1253 purb->context = hub_ext;
1254 purb->pdev = pdev;
1255 purb->completion = hub_start_reset_port_completion; //hub_int_completion;
1256 purb->reference = param;
1257
1258 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
1259
1260 psetup->bmRequestType = 0x23; //host-device other recepient
1261 psetup->bRequest = USB_REQ_SET_FEATURE;
1262 psetup->wValue = USB_PORT_FEAT_RESET;
1263 psetup->wIndex = (USHORT) param;
1264 psetup->wLength = 0;
1265
1266 purb->pirp = NULL;
1267 //enter another state
1268 set_port_state(hub_ext->port_status_queue[param].port_flags, STATE_WAIT_RESET_COMPLETE);
1269
1270 unlock_dev(pdev, TRUE);
1271 KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
1272
1273 status = hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb);
1274 if (status != STATUS_PENDING)
1275 {
1276 //must be fatal error
1277 usb_free_mem(purb);
1278 hub_reexamine_port_status_queue(pdev, param, FALSE);
1279 if (hub_remove_reset_event(pdev, param, FALSE))
1280 hub_start_next_reset_port(dev_mgr, FALSE);
1281 }
1282 return;
1283 }
1284
1285 LBL_OUT:
1286 unlock_dev(pdev, TRUE);
1287 KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
1288 return;
1289 }
1290
1291 VOID
1292 hub_start_reset_port_completion(PURB purb, PVOID context)
1293 {
1294 PUSB_DEV pdev;
1295 PUSB_ENDPOINT pendp;
1296 PUSB_DEV_MANAGER dev_mgr = NULL;
1297 NTSTATUS status = STATUS_SUCCESS;
1298 ULONG port_idx;
1299 PHCD hcd;
1300
1301 USE_BASIC_NON_PENDING_IRQL;
1302 if (purb == NULL)
1303 return;
1304
1305 if (context == NULL)
1306 {
1307 //fatal error no retry.
1308 usb_free_mem(purb);
1309 return;
1310 }
1311
1312 pdev = purb->pdev;
1313 pendp = purb->pendp;
1314 port_idx = purb->reference;
1315
1316 lock_dev(pdev, TRUE);
1317
1318 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1319 {
1320 unlock_dev(pdev, TRUE);
1321 usb_free_mem(purb);
1322 goto LBL_FREE_EVENT;
1323 }
1324
1325 hcd = pdev->hcd;
1326 dev_mgr = dev_mgr_from_dev(pdev);
1327 unlock_dev(pdev, TRUE);
1328
1329 status = purb->status;
1330 usb_free_mem(purb);
1331
1332 if (!usb_error(status))
1333 {
1334 return;
1335 }
1336
1337 LBL_FREE_EVENT:
1338 //since we have no patient to retry the dev, we should remove the event of
1339 //wait_reset_port on the port from the event list. and if possible, start
1340 //another reset process. note other port on the dev still have chance to be
1341 //reset if necessary.
1342 hub_reexamine_port_status_queue(pdev, port_idx, TRUE);
1343 if (hub_remove_reset_event(pdev, port_idx, TRUE))
1344 hub_start_next_reset_port(dev_mgr, TRUE);
1345 return;
1346 }
1347
1348
1349 VOID
1350 hub_set_address_completion(PURB purb, PVOID context)
1351 {
1352 PUSB_DEV pdev, hub_dev;
1353 PUSB_ENDPOINT pendp;
1354 PUSB_DEV_MANAGER dev_mgr;
1355 NTSTATUS status;
1356 ULONG port_idx;
1357 PHCD hcd;
1358 USE_BASIC_NON_PENDING_IRQL;
1359
1360 hcd_dbg_print(DBGLVL_MAXIMUM, ("hub_set_address_completion: purb=%p context=%p\n", purb, context));
1361
1362 if (purb == NULL)
1363 return;
1364
1365 if (context == NULL)
1366 {
1367 //fatal error no retry.
1368 usb_free_mem(purb);
1369 return;
1370 }
1371
1372 pdev = purb->pdev;
1373 pendp = purb->pendp;
1374 port_idx = purb->reference;
1375
1376 lock_dev(pdev, TRUE);
1377
1378 hcd = pdev->hcd;
1379 dev_mgr = dev_mgr_from_dev(pdev);
1380 hub_dev = pdev->parent_dev;
1381 port_idx = pdev->port_idx;
1382
1383 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1384 {
1385 unlock_dev(pdev, TRUE);
1386 usb_free_mem(purb);
1387 //some error occured, let's start the next reset event
1388 goto LBL_RESET_NEXT;
1389 }
1390
1391 pdev->flags &= ~USB_DEV_STATE_MASK;
1392 pdev->flags |= USB_DEV_STATE_ADDRESSED;
1393
1394 unlock_dev(pdev, TRUE);
1395 status = purb->status;
1396
1397 if (usb_error(status))
1398 {
1399 //retry the urb
1400 purb->status = 0;
1401 hcd_dbg_print(DBGLVL_MAXIMUM, ("hub_set_address_completion: can not set address\n"));
1402 status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
1403 //some error occured, disable the port
1404 if (status != STATUS_PENDING)
1405 {
1406 usb_free_mem(purb);
1407 status = hub_disable_port_request(hub_dev, (UCHAR) port_idx);
1408 }
1409 return;
1410 }
1411
1412 usb_free_mem(purb);
1413 //let address settle
1414 usb_wait_ms_dpc(10);
1415
1416 //let's config the dev
1417 dev_mgr_start_config_dev(pdev);
1418
1419 LBL_RESET_NEXT:
1420 //second, remove the event in the queue
1421 hub_reexamine_port_status_queue(hub_dev, port_idx, TRUE);
1422 if (hub_remove_reset_event(hub_dev, port_idx, TRUE))
1423 hub_start_next_reset_port(dev_mgr, TRUE);
1424 return;
1425 };
1426
1427 VOID
1428 hub_disable_port_completion(PURB purb, PVOID pcontext)
1429 {
1430 PUSB_DEV pdev;
1431 PUSB_DEV_MANAGER dev_mgr;
1432 UCHAR port_idx;
1433 PUSB_ENDPOINT pendp;
1434 PUSB_CTRL_SETUP_PACKET psetup;
1435
1436 UNREFERENCED_PARAMETER(pcontext);
1437
1438 if (purb == NULL)
1439 return;
1440
1441 pdev = purb->pdev;
1442 pendp = purb->pendp;
1443 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
1444 port_idx = (UCHAR) psetup->wIndex;
1445
1446 dev_mgr = dev_mgr_from_dev(pdev);
1447
1448 usb_free_mem(purb);
1449
1450 hub_reexamine_port_status_queue(pdev, port_idx, TRUE);
1451 if (hub_remove_reset_event(pdev, port_idx, TRUE))
1452 hub_start_next_reset_port(dev_mgr, TRUE);
1453
1454 return;
1455 }
1456
1457 //caller should guarantee the validity of the dev
1458 NTSTATUS
1459 hub_disable_port_request(PUSB_DEV pdev, UCHAR port_idx)
1460 {
1461 PURB purb;
1462 PUSB_ENDPOINT pendp;
1463 PHUB2_EXTENSION hub_ext;
1464 PUSB_CTRL_SETUP_PACKET psetup;
1465 NTSTATUS status;
1466 PHCD hcd;
1467 USE_BASIC_NON_PENDING_IRQL;
1468
1469 if (pdev == NULL || port_idx == 0)
1470 return STATUS_INVALID_PARAMETER;
1471
1472 lock_dev(pdev, FALSE);
1473 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1474 {
1475 unlock_dev(pdev, FALSE);
1476 return STATUS_DEVICE_DOES_NOT_EXIST;
1477 }
1478
1479 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
1480 if (purb == NULL)
1481 {
1482 unlock_dev(pdev, FALSE);
1483 return STATUS_NO_MEMORY;
1484 }
1485
1486 RtlZeroMemory(purb, sizeof(URB));
1487
1488 purb->flags = 0;
1489 purb->status = STATUS_SUCCESS;
1490
1491 hub_ext = hub_ext_from_dev(pdev);
1492
1493 purb->data_buffer = NULL;
1494 purb->data_length = 0;
1495
1496 pendp = purb->pendp = &pdev->default_endp;
1497 purb->pdev = pdev;
1498
1499 purb->completion = hub_disable_port_completion;
1500 purb->context = hub_ext;
1501
1502 purb->pirp = NULL;
1503 purb->reference = 0;
1504
1505 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
1506
1507 psetup->bmRequestType = 0x23; //host-device other recepient
1508 psetup->bRequest = USB_REQ_CLEAR_FEATURE; //clear_feature
1509 psetup->wValue = USB_PORT_FEAT_ENABLE;
1510 psetup->wIndex = (USHORT) port_idx;
1511 psetup->wLength = 0;
1512
1513 purb->pirp = NULL;
1514 //enter another state
1515 hcd = pdev->hcd;
1516 unlock_dev(pdev, FALSE);
1517
1518 status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
1519 if (status == STATUS_PENDING)
1520 return status;
1521
1522 usb_free_mem(purb);
1523 return status;
1524 }
1525
1526
1527 BOOLEAN
1528 hub_remove_reset_event(PUSB_DEV pdev, ULONG port_idx, BOOLEAN from_dpc)
1529 {
1530 PUSB_DEV_MANAGER dev_mgr;
1531 PLIST_ENTRY pthis, pnext;
1532 PUSB_EVENT pevent, pnext_event;
1533 BOOLEAN found;
1534
1535 KIRQL old_irql = 0;
1536
1537 if (pdev == NULL)
1538 return FALSE;
1539
1540 if (port_idx == 0)
1541 return FALSE;
1542
1543 dev_mgr = dev_mgr_from_dev(pdev);
1544 found = FALSE;
1545
1546 if (from_dpc)
1547 KeAcquireSpinLockAtDpcLevel(&dev_mgr->event_list_lock);
1548 else
1549 KeAcquireSpinLock(&dev_mgr->event_list_lock, &old_irql);
1550
1551 ListFirst(&dev_mgr->event_list, pthis);
1552 while (pthis)
1553 {
1554 pevent = (PUSB_EVENT) pthis;
1555 if (pevent->event == USB_EVENT_WAIT_RESET_PORT &&
1556 (pevent->flags & USB_EVENT_FLAG_QUE_TYPE) == USB_EVENT_FLAG_QUE_RESET)
1557 {
1558 if (pevent->pdev == pdev && pevent->param == port_idx)
1559 {
1560 //remove it
1561 RemoveEntryList(&pevent->event_link);
1562 pnext_event = pevent->pnext;
1563 free_event(&dev_mgr->event_pool, pevent);
1564
1565 if (pnext_event)
1566 InsertHeadList(&dev_mgr->event_list, &pnext_event->event_link);
1567
1568 found = TRUE;
1569 break;
1570 }
1571 }
1572 ListNext(&dev_mgr->event_list, pthis, pnext);
1573 pthis = pnext;
1574 }
1575
1576 if (from_dpc)
1577 KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
1578 else
1579 KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
1580 return found;
1581 }
1582
1583 BOOLEAN
1584 hub_start_next_reset_port(PUSB_DEV_MANAGER dev_mgr, BOOLEAN from_dpc)
1585 {
1586 PLIST_ENTRY pthis, pnext;
1587 PUSB_EVENT pevent, pnext_event;
1588 PUSB_DEV pdev = NULL;
1589 PHUB2_EXTENSION hub_ext;
1590 BOOLEAN bret;
1591 PURB purb = NULL;
1592 BOOLEAN processed;
1593 PUSB_CTRL_SETUP_PACKET psetup;
1594 PHCD hcd = NULL;
1595
1596 USE_NON_PENDING_IRQL;
1597
1598 if (dev_mgr == NULL)
1599 return FALSE;
1600
1601 bret = FALSE;
1602 processed = FALSE;
1603
1604 if (from_dpc)
1605 KeAcquireSpinLockAtDpcLevel(&dev_mgr->event_list_lock);
1606 else
1607 KeAcquireSpinLock(&dev_mgr->event_list_lock, &old_irql);
1608
1609 ListFirst(&dev_mgr->event_list, pthis);
1610
1611 while ((pevent = (PUSB_EVENT) pthis))
1612 {
1613 while (pevent->event == USB_EVENT_WAIT_RESET_PORT &&
1614 (pevent->flags & USB_EVENT_FLAG_QUE_TYPE) == USB_EVENT_FLAG_QUE_RESET)
1615 {
1616
1617 processed = TRUE;
1618
1619 pdev = pevent->pdev;
1620 lock_dev(pdev, TRUE);
1621
1622 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1623 {
1624 unlock_dev(pdev, TRUE);
1625 pnext_event = pevent->pnext;
1626 free_event(&dev_mgr->event_pool, pevent);
1627 pevent = pnext_event;
1628 if (pevent == NULL)
1629 {
1630 bret = FALSE;
1631 break;
1632 }
1633 continue;
1634 }
1635
1636 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
1637 if (!purb)
1638 {
1639 if (from_dpc)
1640 KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
1641 else
1642 KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
1643 return FALSE;
1644 }
1645
1646 RtlZeroMemory(purb, sizeof(URB));
1647
1648 purb->data_buffer = NULL;
1649 purb->data_length = 0;
1650 purb->pendp = &pdev->default_endp;
1651
1652 hub_ext = hub_ext_from_dev(pdev);
1653 purb->context = hub_ext;
1654 purb->pdev = pdev;
1655 purb->completion = hub_start_reset_port_completion;
1656 purb->reference = pevent->param;
1657
1658 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
1659
1660 psetup->bmRequestType = 0x23; //host-device other recepient
1661 psetup->bRequest = 3; //set_feature
1662 psetup->wValue = USB_PORT_FEAT_RESET;
1663 psetup->wIndex = (USHORT) pevent->param;
1664 psetup->wLength = 0;
1665
1666 purb->pirp = NULL;
1667 hcd = pdev->hcd;
1668 set_port_state(hub_ext->port_status_queue[pevent->param].port_flags, STATE_WAIT_RESET_COMPLETE);
1669 unlock_dev(pdev, TRUE);
1670
1671 bret = TRUE;
1672 break;
1673 }
1674
1675 if (!processed)
1676 {
1677 ListNext(&dev_mgr->event_list, pthis, pnext);
1678 pthis = pnext;
1679 }
1680 else
1681 break;
1682 }
1683
1684 if (from_dpc)
1685 KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
1686 else
1687 KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
1688
1689 if (processed && bret)
1690 {
1691 if (hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb) != STATUS_PENDING)
1692 {
1693 //fatal error
1694 usb_free_mem(purb);
1695 bret = FALSE;
1696 //do not know what to do
1697 }
1698 }
1699
1700 if (pthis == NULL)
1701 bret = TRUE;
1702
1703 return bret;
1704 }
1705
1706 //
1707 //must have event-list-lock and dev-lock acquired
1708 //
1709 VOID
1710 hub_post_esq_event(PUSB_DEV pdev, BYTE port_idx, PROCESS_EVENT pe)
1711 {
1712 PUSB_DEV_MANAGER dev_mgr;
1713 PUSB_EVENT pevent;
1714
1715 if (pdev == NULL || port_idx == 0 || pe == NULL)
1716 return;
1717
1718 dev_mgr = dev_mgr_from_dev(pdev);
1719
1720 pevent = alloc_event(&dev_mgr->event_pool, 1);
1721 if (!pevent) return;
1722 pevent->event = USB_EVENT_DEFAULT;
1723 pevent->process_queue = event_list_default_process_queue;
1724 pevent->process_event = pe;
1725 pevent->context = (ULONG) hub_ext_from_dev(pdev);
1726 pevent->param = port_idx;
1727 pevent->flags = USB_EVENT_FLAG_ACTIVE;
1728 pevent->pdev = pdev;
1729 pevent->pnext = NULL;
1730
1731 InsertTailList(&dev_mgr->event_list, &pevent->event_link);
1732 KeSetEvent(&dev_mgr->wake_up_event, 0, FALSE);
1733 // usb_dbg_print( DBGLVL_MAXIMUM, ( "hub_post_esq_event(): current element in event list is 0x%x\n",
1734 // dbg_count_list( &dev_mgr->event_list ) ) );
1735 return;
1736 }
1737
1738 // called only in hub_clear_port_feature_completion
1739 BOOLEAN
1740 hub_check_reset_port_status(PUSB_DEV pdev, LONG port_idx)
1741 {
1742 PUSB_DEV_MANAGER dev_mgr;
1743 PHUB2_EXTENSION hub_ext;
1744 BOOLEAN bReset;
1745 USB_PORT_STATUS port_status;
1746 PUSB_DEV pdev2;
1747 PURB purb2;
1748 PHCD hcd;
1749
1750 PUSB_CTRL_SETUP_PACKET psetup;
1751 ULONG status;
1752
1753 USE_BASIC_NON_PENDING_IRQL;
1754
1755 //let's check whether the status change is a reset complete
1756 usb_dbg_print(DBGLVL_MAXIMUM, ("hub_check_reset_port_status(): entering...\n"));
1757 dev_mgr = dev_mgr_from_dev(pdev);
1758 KeAcquireSpinLockAtDpcLevel(&dev_mgr->dev_list_lock);
1759 lock_dev(pdev, TRUE);
1760
1761 dev_mgr = dev_mgr_from_dev(pdev);
1762 hcd = pdev->hcd;
1763
1764 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1765 {
1766 unlock_dev(pdev, TRUE);
1767 KeReleaseSpinLockFromDpcLevel(&dev_mgr->dev_list_lock);
1768 return FALSE;
1769 }
1770
1771 hub_ext = hub_ext_from_dev(pdev);
1772 port_status = psq_peek(&hub_ext->port_status_queue[port_idx], 0);
1773
1774 bReset = FALSE;
1775 if (port_status.wPortChange & USB_PORT_STAT_C_RESET)
1776 bReset = TRUE;
1777
1778 pdev2 = NULL;
1779 purb2 = NULL;
1780
1781 if (bReset
1782 && (port_state(hub_ext->port_status_queue[port_idx].port_flags) == STATE_WAIT_RESET_COMPLETE)
1783 && (psq_count(&hub_ext->port_status_queue[port_idx]) == 1))
1784 {
1785 // a port-reset complete, empty the queue, keep the state
1786 psq_outqueue(&hub_ext->port_status_queue[port_idx]);
1787 set_port_state(hub_ext->port_status_queue[port_idx].port_flags, STATE_WAIT_ADDRESSED);
1788
1789 //let's new a dev, and start the set-addr request
1790 if (hub_ext->child_dev[port_idx] == 0)
1791 {
1792 pdev2 = hub_ext->child_dev[port_idx] = dev_mgr_alloc_device(dev_mgr, hcd);
1793 if (pdev2)
1794 {
1795 purb2 = usb_alloc_mem(NonPagedPool, sizeof(URB));
1796 if (!purb2)
1797 {
1798 dev_mgr_free_device(dev_mgr, pdev2);
1799 pdev2 = hub_ext->child_dev[port_idx] = NULL;
1800 }
1801 else
1802 {
1803 if (port_status.wPortStatus & USB_PORT_STAT_LOW_SPEED)
1804 {
1805 pdev2->flags |= USB_DEV_FLAG_LOW_SPEED;
1806 }
1807 else if (port_status.wPortStatus & USB_PORT_STAT_HIGH_SPEED)
1808 pdev2->flags |= USB_DEV_FLAG_HIGH_SPEED;
1809
1810 pdev2->parent_dev = pdev;
1811 pdev2->port_idx = (UCHAR) port_idx;
1812 pdev2->ref_count++;
1813
1814 RtlZeroMemory(purb2, sizeof(URB));
1815
1816 purb2->pdev = pdev2;
1817 purb2->pendp = &pdev2->default_endp;
1818 purb2->context = hub_ext;
1819 purb2->completion = hub_set_address_completion;
1820
1821 InitializeListHead(&purb2->trasac_list);
1822 purb2->reference = port_idx;
1823 purb2->pirp = 0;
1824
1825 psetup = (PUSB_CTRL_SETUP_PACKET) purb2->setup_packet;
1826 psetup->bmRequestType = 0;
1827 psetup->bRequest = USB_REQ_SET_ADDRESS;
1828 psetup->wValue = pdev2->dev_addr;
1829 }
1830 }
1831 }
1832
1833 if (pdev2 && purb2)
1834 {
1835 //creation success, emit the urb
1836 //add to dev list
1837 InsertTailList(&dev_mgr->dev_list, &pdev2->dev_link);
1838
1839 unlock_dev(pdev, TRUE);
1840 KeReleaseSpinLockFromDpcLevel(&dev_mgr->dev_list_lock);
1841
1842 status = hcd->hcd_submit_urb(hcd, pdev2, purb2->pendp, purb2);
1843
1844 lock_dev(pdev2, TRUE);
1845 pdev2->ref_count--;
1846 usb_dbg_print(DBGLVL_MAXIMUM,
1847 ("hub_check_reset_port_status(): new dev ref_count=0x%x\n", pdev2->ref_count));
1848 unlock_dev(pdev2, TRUE);
1849
1850 if (status != STATUS_PENDING)
1851 {
1852 usb_free_mem(purb2);
1853 //??? do we need to lock it for SMP?
1854 //dev_mgr_free_device( dev_mgr, pdev2 ), let dev_mgr_thread to clean it;
1855 // disable the port
1856 if (hub_disable_port_request(pdev, (UCHAR) port_idx) != STATUS_PENDING)
1857 goto LBL_RESET_FAIL;
1858 }
1859
1860 return TRUE;
1861 }
1862 }
1863 else
1864 {
1865 usb_dbg_print(DBGLVL_MAXIMUM, ("hub_check_reset_port_status(): not a correct reset status\n"));
1866 }
1867 unlock_dev(pdev, TRUE);
1868 KeReleaseSpinLockFromDpcLevel(&dev_mgr->dev_list_lock);
1869
1870 LBL_RESET_FAIL:
1871 //Any event other than reset cause the reset process stall and another
1872 //pending reset-port requeset is serviced
1873 hub_reexamine_port_status_queue(pdev, port_idx, TRUE);
1874 if (hub_remove_reset_event(pdev, port_idx, TRUE))
1875 hub_start_next_reset_port(dev_mgr, TRUE);
1876
1877 return FALSE;
1878 }
1879
1880 VOID
1881 hub_reexamine_port_status_queue(PUSB_DEV hub_dev, ULONG port_idx, BOOLEAN from_dpc)
1882 {
1883
1884 PHUB2_EXTENSION hub_ext;
1885 PUSB_DEV_MANAGER dev_mgr;
1886
1887 USE_NON_PENDING_IRQL;
1888
1889 if (hub_dev == NULL || port_idx == 0)
1890 return;
1891
1892 dev_mgr = dev_mgr_from_dev(hub_dev);
1893 if (from_dpc)
1894 KeAcquireSpinLockAtDpcLevel(&dev_mgr->event_list_lock);
1895 else
1896 KeAcquireSpinLock(&dev_mgr->event_list_lock, &old_irql);
1897
1898 lock_dev(hub_dev, TRUE);
1899 if (dev_state(hub_dev) != USB_DEV_STATE_ZOMB)
1900 {
1901
1902 hub_ext = hub_ext_from_dev(hub_dev);
1903 if (psq_is_empty(&hub_ext->port_status_queue[port_idx]))
1904 {
1905 set_port_state(hub_ext->port_status_queue[port_idx].port_flags, STATE_IDLE);
1906
1907 }
1908 else
1909 {
1910 set_port_state(hub_ext->port_status_queue[port_idx].port_flags, STATE_EXAMINE_STATUS_QUE);
1911
1912 hub_post_esq_event(hub_dev, (UCHAR) port_idx, hub_event_examine_status_que);
1913 }
1914 }
1915 unlock_dev(hub_dev, TRUE);
1916
1917 if (from_dpc)
1918 KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
1919 else
1920 KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
1921 return;
1922 }
1923
1924 BOOLEAN
1925 hub_connect(PDEV_CONNECT_DATA param, DEV_HANDLE dev_handle)
1926 {
1927 URB urb, *purb;
1928 CHAR buf[512];
1929 DEV_HANDLE endp_handle;
1930 USB_DEVICE_DESC dev_desc;
1931 PUSB_CONFIGURATION_DESC pcfg_desc;
1932 PUSB_INTERFACE_DESC pif_desc;
1933 PUSB_CTRL_SETUP_PACKET psetup;
1934 NTSTATUS status;
1935 LONG i, j, found, cfg_val = 0;
1936 PUSB_DEV_MANAGER dev_mgr;
1937 PUSB_DEV pdev;
1938
1939
1940 if (param == NULL || dev_handle == 0)
1941 return FALSE;
1942
1943 dev_mgr = param->dev_mgr;
1944
1945 pcfg_desc = (PUSB_CONFIGURATION_DESC) buf;
1946 endp_handle = dev_handle | 0xffff;
1947 UsbBuildGetDescriptorRequest(&urb,
1948 endp_handle,
1949 USB_DT_DEVICE, 0, 0, (&dev_desc), (sizeof(USB_DEVICE_DESC)), NULL, 0, 0);
1950
1951 status = usb_submit_urb(dev_mgr, &urb);
1952 if (status != STATUS_SUCCESS)
1953 return FALSE;
1954
1955 found = FALSE;
1956 for(i = 0; i < dev_desc.bNumConfigurations; i++)
1957 {
1958 UsbBuildGetDescriptorRequest(&urb, endp_handle, USB_DT_CONFIG, (USHORT) i, 0, buf, 512, NULL, 0, 0);
1959
1960 status = usb_submit_urb(dev_mgr, &urb);
1961 if (status != STATUS_SUCCESS)
1962 {
1963 return FALSE;
1964 }
1965
1966 status = usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev);
1967 if (status != STATUS_SUCCESS)
1968 return FALSE;
1969
1970 pif_desc = (PUSB_INTERFACE_DESC) & buf[sizeof(USB_CONFIGURATION_DESC)];
1971 for(j = 0; j < pcfg_desc->bNumInterfaces; j++)
1972 {
1973 if (pif_desc->bInterfaceClass == USB_CLASS_HUB
1974 && pif_desc->bInterfaceSubClass == 0 && pif_desc->bNumEndpoints == 1)
1975 {
1976 if ((pif_desc->bInterfaceProtocol > 0 && pif_desc->bInterfaceProtocol < 3)
1977 || (pif_desc->bInterfaceProtocol == 0 && pdev->flags & USB_DEV_FLAG_HIGH_SPEED)
1978 || (pif_desc->bInterfaceProtocol == 0 && !usb2(pdev->hcd)))
1979 {
1980 found = TRUE;
1981 cfg_val = pcfg_desc->bConfigurationValue;
1982 break;
1983 }
1984 }
1985 if (usb_skip_if_and_altif((PBYTE *) & pif_desc) == FALSE)
1986 {
1987 break;
1988 }
1989 }
1990 usb_unlock_dev(pdev);
1991
1992 if (found)
1993 break;
1994
1995 if (usb_skip_one_config((PBYTE *) & pcfg_desc) == FALSE)
1996 {
1997 break;
1998 }
1999
2000 }
2001 if (found)
2002 {
2003 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
2004 if (purb == NULL)
2005 return FALSE;
2006
2007 psetup = (PUSB_CTRL_SETUP_PACKET) (purb)->setup_packet;
2008 urb_init((purb));
2009
2010 purb->endp_handle = endp_handle;
2011 purb->data_buffer = NULL;
2012 purb->data_length = 0;
2013 purb->completion = hub_set_cfg_completion;
2014 purb->context = dev_mgr;
2015 purb->reference = (LONG) param->pdriver;
2016 psetup->bmRequestType = 0;
2017 psetup->bRequest = USB_REQ_SET_CONFIGURATION;
2018 psetup->wValue = (USHORT) cfg_val;
2019 psetup->wIndex = 0;
2020 psetup->wLength = 0;
2021
2022 status = usb_submit_urb(dev_mgr, purb);
2023 if (status != STATUS_PENDING)
2024 {
2025 usb_free_mem(purb);
2026 return FALSE;
2027 }
2028 return TRUE;
2029 }
2030
2031 return FALSE;
2032 }
2033
2034 VOID hub_set_interface_completion(PURB purb, PVOID pcontext);
2035
2036 VOID
2037 hub_set_cfg_completion(PURB purb, PVOID pcontext)
2038 {
2039 PUSB_DEV_MANAGER dev_mgr;
2040 PUSB_DRIVER pdriver;
2041 ULONG endp_handle, dev_handle;
2042 PUSB_CTRL_SETUP_PACKET psetup;
2043 UCHAR if_idx = 0;
2044 PUSB_DEV pdev;
2045 PUSB_INTERFACE pif;
2046 BOOLEAN high_speed, multiple_tt;
2047 NTSTATUS status;
2048 USE_BASIC_NON_PENDING_IRQL;
2049
2050 if (purb == NULL || pcontext == NULL)
2051 return;
2052
2053 //pdev = NULL;
2054 dev_mgr = (PUSB_DEV_MANAGER) pcontext;
2055 endp_handle = purb->endp_handle;
2056 dev_handle = endp_handle & 0xffff0000;
2057 pdriver = (PUSB_DRIVER) purb->reference;
2058 high_speed = FALSE;
2059 multiple_tt = FALSE;
2060
2061 if (purb->status != STATUS_SUCCESS)
2062 {
2063 goto LBL_ERROR;
2064 }
2065
2066 status = usb_query_and_lock_dev(dev_mgr, purb->endp_handle, &pdev);
2067 if (status != STATUS_SUCCESS)
2068 {
2069 usb_unlock_dev(pdev);
2070 goto LBL_ERROR;
2071 }
2072 lock_dev(pdev, TRUE);
2073 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
2074 {
2075 unlock_dev(pdev, TRUE);
2076 usb_unlock_dev(pdev);
2077 goto LBL_ERROR;
2078 }
2079 if (pdev->flags & USB_DEV_FLAG_HIGH_SPEED)
2080 {
2081 high_speed = TRUE;
2082 hub_if_from_dev(pdev, pif);
2083 if (pif->altif_count)
2084 {
2085 multiple_tt = TRUE;
2086 if_idx = pif - &pdev->usb_config->interf[0];
2087 }
2088 }
2089 unlock_dev(pdev, TRUE);
2090 usb_unlock_dev(pdev);
2091
2092 if (!high_speed || !multiple_tt)
2093 {
2094 hub_set_interface_completion(purb, pcontext);
2095 return;
2096 }
2097
2098 psetup = (PUSB_CTRL_SETUP_PACKET) (purb)->setup_packet;
2099 urb_init((purb));
2100
2101 // set the mult-tt if exist
2102 purb->endp_handle = endp_handle;
2103 purb->data_buffer = NULL;
2104 purb->data_length = 0;
2105 purb->completion = hub_set_interface_completion;
2106 purb->context = dev_mgr;
2107 purb->reference = (LONG) pdriver;
2108 psetup->bmRequestType = 0;
2109 psetup->bRequest = USB_REQ_SET_INTERFACE;
2110 psetup->wValue = (USHORT) 1; // alternate tt
2111 psetup->wIndex = if_idx; // if index
2112 psetup->wLength = 0;
2113
2114 status = usb_submit_urb(dev_mgr, purb);
2115 if (status == STATUS_PENDING)
2116 return;
2117
2118 LBL_ERROR:
2119 usb_free_mem(purb);
2120 purb = NULL;
2121 return;
2122 }
2123
2124 void
2125 hub_set_interface_completion(PURB purb, PVOID pcontext)
2126 {
2127 NTSTATUS status;
2128 PUSB_CTRL_SETUP_PACKET psetup;
2129 PUSB_DEV_MANAGER dev_mgr;
2130 PBYTE dev_ext;
2131 DEV_HANDLE endp_handle;
2132 PUSB_DRIVER pdriver;
2133
2134 if (purb == NULL || pcontext == NULL)
2135 return;
2136
2137 //pdev = NULL;
2138 dev_mgr = (PUSB_DEV_MANAGER) pcontext;
2139 endp_handle = purb->endp_handle;
2140 pdriver = (PUSB_DRIVER) purb->reference;
2141
2142 if (purb->status != STATUS_SUCCESS)
2143 {
2144 usb_free_mem(purb);
2145 return;
2146 }
2147
2148 dev_ext = usb_alloc_mem(NonPagedPool, sizeof(HUB2_EXTENSION));
2149 if (dev_ext == NULL)
2150 {
2151 goto LBL_OUT;
2152 }
2153
2154 //
2155 //acquire hub descriptor
2156 //
2157 RtlZeroMemory(dev_ext, sizeof(HUB2_EXTENSION));
2158 urb_init(purb);
2159
2160 purb->data_buffer = (PUCHAR) & ((HUB2_EXTENSION *) dev_ext)->hub_desc;
2161 purb->endp_handle = endp_handle;
2162 purb->data_length = sizeof(USB_HUB_DESCRIPTOR);
2163 purb->completion = hub_get_hub_desc_completion;
2164 purb->context = (PVOID) dev_mgr;
2165 purb->reference = (ULONG) dev_ext;
2166 purb->pirp = (PIRP) pdriver;
2167
2168 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
2169 psetup->bmRequestType = 0xa0;
2170 psetup->bRequest = USB_REQ_GET_DESCRIPTOR;
2171 psetup->wValue = (0x29 << 8);
2172 psetup->wLength = sizeof(USB_HUB_DESCRIPTOR);
2173 status = usb_submit_urb(dev_mgr, purb);
2174
2175 if (status != STATUS_PENDING)
2176 {
2177 usb_free_mem(dev_ext);
2178 goto LBL_OUT;
2179 }
2180 return;
2181
2182 LBL_OUT:
2183 //clear the dev_driver fields in the dev.
2184 usb_free_mem(purb);
2185 return;
2186 }
2187
2188
2189 VOID
2190 hub_power_on_port_completion(PURB purb, PVOID pcontext)
2191 {
2192 PUSB_DEV_MANAGER dev_mgr;
2193
2194 if (purb == NULL)
2195 return;
2196 if (pcontext == NULL)
2197 goto LBL_OUT;
2198
2199 dev_mgr = (PUSB_DEV_MANAGER) pcontext;
2200
2201 if (purb->status != STATUS_SUCCESS)
2202 {
2203 usb_dbg_print(DBGLVL_MAXIMUM,
2204 ("hub_power_on_port_completion(): port%d power on failed\n", purb->reference));
2205 }
2206 else
2207 {
2208 usb_dbg_print(DBGLVL_MAXIMUM,
2209 ("hub_power_on_port_completion(): port%d power on succeed\n", purb->reference));
2210 }
2211
2212 LBL_OUT:
2213 usb_free_mem(purb);
2214 return;
2215 }
2216
2217 NTSTATUS
2218 hub_power_on_port(PUSB_DEV pdev, UCHAR port_idx)
2219 {
2220 NTSTATUS status;
2221 PUSB_CTRL_SETUP_PACKET psetup;
2222 PUSB_DEV_MANAGER dev_mgr;
2223 PURB purb;
2224 PHCD hcd;
2225
2226 USE_BASIC_NON_PENDING_IRQL;
2227 if (pdev == NULL || port_idx == 0)
2228 return STATUS_INVALID_PARAMETER;
2229
2230 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
2231 if (purb == NULL)
2232 return STATUS_NO_MEMORY;
2233
2234 urb_init(purb);
2235
2236 lock_dev(pdev, FALSE);
2237 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
2238 {
2239 unlock_dev(pdev, FALSE);
2240 status = STATUS_DEVICE_DOES_NOT_EXIST;
2241 goto LBL_OUT;
2242 }
2243 dev_mgr = dev_mgr_from_dev(pdev);
2244 hcd = pdev->hcd;
2245
2246 purb->completion = hub_power_on_port_completion;
2247 purb->context = (PVOID) dev_mgr;
2248 purb->reference = (ULONG) port_idx;
2249 purb->pdev = pdev;
2250 purb->pendp = &pdev->default_endp;
2251
2252 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
2253 psetup->bmRequestType = 0x23;
2254 psetup->bRequest = USB_REQ_SET_FEATURE;
2255 psetup->wValue = USB_PORT_FEAT_POWER;
2256 psetup->wIndex = (WORD) port_idx;
2257 psetup->wLength = 0;
2258
2259 unlock_dev(pdev, FALSE);
2260
2261 status = hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb);
2262
2263 if (status != STATUS_PENDING)
2264 {
2265 goto LBL_OUT;
2266 }
2267 return STATUS_PENDING;
2268
2269 LBL_OUT:
2270 usb_free_mem(purb);
2271 return status;
2272 }
2273
2274 void
2275 hub_get_hub_desc_completion(PURB purb, PVOID pcontext)
2276 {
2277 PUSB_DEV_MANAGER dev_mgr;
2278 PHUB2_EXTENSION hub_ext;
2279 PUSB_DEV pdev;
2280 LONG i;
2281 PUSB_INTERFACE pif = NULL;
2282 ULONG status;
2283 LONG port_count;
2284 PUSB_DRIVER pdriver;
2285 DEV_HANDLE dev_handle;
2286
2287 USE_BASIC_NON_PENDING_IRQL;
2288
2289 if (purb == NULL)
2290 {
2291 return;
2292 }
2293
2294 dev_mgr = (PUSB_DEV_MANAGER) pcontext;
2295 hub_ext = (PHUB2_EXTENSION) purb->reference;
2296 pdriver = (PUSB_DRIVER) purb->pirp;
2297 dev_handle = purb->endp_handle & 0xffff0000;
2298
2299 if (pcontext == NULL || purb->reference == 0)
2300 goto LBL_OUT;
2301
2302 if (purb->status != STATUS_SUCCESS)
2303 {
2304 goto LBL_OUT;
2305 }
2306
2307 // obtain the pointer to the dev
2308 status = usb_query_and_lock_dev(dev_mgr, purb->endp_handle, &pdev);
2309 if (status != STATUS_SUCCESS)
2310 {
2311 usb_unlock_dev(pdev);
2312 goto LBL_OUT;
2313 }
2314 // safe to release the pdev ref since we are in urb completion
2315 usb_unlock_dev(pdev);
2316
2317 lock_dev(pdev, TRUE);
2318 if (dev_state(pdev) == USB_DEV_STATE_ZOMB ||
2319 dev_mgr_set_driver(dev_mgr, dev_handle, pdriver, pdev) == FALSE)
2320 {
2321 unlock_dev(pdev, TRUE);
2322 goto LBL_OUT;
2323 }
2324
2325 //transit the state to configured
2326 pdev->flags &= ~USB_DEV_STATE_MASK;
2327 pdev->flags |= USB_DEV_STATE_CONFIGURED;
2328
2329 pdev->dev_ext = (PBYTE) hub_ext;
2330 pdev->dev_ext_size = sizeof(HUB2_EXTENSION);
2331
2332 port_count = hub_ext->port_count = hub_ext->hub_desc.bNbrPorts;
2333 hub_ext->pdev = pdev;
2334 for(i = 0; i < pdev->usb_config->if_count; i++)
2335 {
2336 pif = &pdev->usb_config->interf[i];
2337 if (pif->pusb_if_desc->bInterfaceClass == USB_CLASS_HUB
2338 && pif->pusb_if_desc->bInterfaceSubClass == 0
2339 && pif->pusb_if_desc->bInterfaceProtocol < 3 && pif->pusb_if_desc->bNumEndpoints == 1)
2340 {
2341 hub_ext->pif = pif;
2342 break;
2343 }
2344 }
2345 for(i = 0; i < MAX_HUB_PORTS + 1; i++)
2346 {
2347 psq_init((PPORT_STATUS_QUEUE) hub_ext->port_status_queue);
2348 }
2349
2350 hub_ext->multiple_tt = (pif->pusb_if_desc->bInterfaceProtocol == 2);
2351
2352 unlock_dev(pdev, TRUE);
2353 usb_free_mem(purb);
2354
2355 hub_start_int_request(pdev);
2356
2357 for(i = 0; i < port_count; i++)
2358 {
2359 hub_power_on_port(pdev, (UCHAR) (i + 1));
2360 }
2361 return;
2362
2363 LBL_OUT:
2364 if (purb)
2365 usb_free_mem(purb);
2366
2367 if (hub_ext)
2368 usb_free_mem(hub_ext);
2369 return;
2370 }
2371
2372 BOOLEAN
2373 hub_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
2374 {
2375 UNREFERENCED_PARAMETER(dev_mgr);
2376 UNREFERENCED_PARAMETER(dev_handle);
2377 return TRUE;
2378 }
2379
2380 BOOLEAN
2381 hub_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
2382 {
2383 PUSB_DEV pdev;
2384 //special use of usb_query and lock dev
2385 if (usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev) != STATUS_SUCCESS)
2386 {
2387 //will never be success, since the dev is already in zomb state
2388 //at this point, the dev is valid, ref_count is of none use,
2389 //no need to lock it
2390 if (pdev)
2391 {
2392 usb_free_mem(pdev->dev_ext);
2393 }
2394 }
2395
2396 return TRUE;
2397 }
2398
2399 static BOOLEAN
2400 hub_lock_unlock_tt(PUSB_DEV pdev, UCHAR port_idx, UCHAR type, BOOLEAN lock)
2401 {
2402 PHUB2_EXTENSION dev_ext;
2403 PULONG pmap = NULL;
2404
2405 USE_BASIC_NON_PENDING_IRQL;
2406
2407 if (pdev == NULL || port_idx > 127)
2408 return FALSE;
2409
2410 lock_dev(pdev, FALSE);
2411 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
2412 {
2413 unlock_dev(pdev, FALSE);
2414 return FALSE;
2415 }
2416
2417 dev_ext = hub_ext_from_dev(pdev);
2418 if (dev_ext == NULL)
2419 {
2420 unlock_dev(pdev, FALSE);
2421 return FALSE;
2422 }
2423 if (type == USB_ENDPOINT_XFER_INT || type == USB_ENDPOINT_XFER_ISOC)
2424 {
2425 pmap = dev_ext->tt_status_map;
2426 }
2427 else if (type == USB_ENDPOINT_XFER_BULK || type == USB_ENDPOINT_XFER_CONTROL)
2428 {
2429 pmap = dev_ext->tt_bulk_map;
2430 }
2431
2432 if (lock)
2433 {
2434 if (pmap[port_idx >> 5] & (1 << port_idx))
2435 {
2436 unlock_dev(pdev, FALSE);
2437 return FALSE;
2438 }
2439 pmap[port_idx >> 5] |= (1 << port_idx);
2440 }
2441 else
2442 {
2443 pmap[port_idx >> 5] &= ~(1 << port_idx);
2444 }
2445
2446 unlock_dev(pdev, FALSE);
2447 return TRUE;
2448 }
2449
2450 BOOLEAN
2451 hub_lock_tt(PUSB_DEV pdev,
2452 UCHAR port_idx,
2453 UCHAR type // transfer type
2454 )
2455 {
2456 return hub_lock_unlock_tt(pdev, port_idx, type, TRUE);
2457 }
2458
2459 BOOLEAN
2460 hub_unlock_tt(PUSB_DEV pdev, UCHAR port_idx, UCHAR type)
2461 {
2462 return hub_lock_unlock_tt(pdev, port_idx, type, FALSE);
2463 }
2464
2465 VOID
2466 hub_clear_tt_buffer_completion(PURB purb, PVOID context)
2467 {
2468 PUSB_CTRL_SETUP_PACKET psetup;
2469 PURB_HS_PIPE_CONTENT pipe_content;
2470 PHUB2_EXTENSION hub_ext;
2471 PHCD hcd;
2472
2473 if (purb == NULL || context == NULL)
2474 return;
2475
2476 hub_ext = (PHUB2_EXTENSION) context;
2477 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
2478 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->reference;
2479 hub_unlock_tt(purb->pdev, (UCHAR) psetup->wIndex, (UCHAR) pipe_content->trans_type);
2480 usb_free_mem(purb);
2481 purb = NULL;
2482 hcd = hub_ext->pdev->hcd;
2483
2484 // let those blocked urbs ( sharing the same tt )have chance to be scheduled
2485 if (hcd && usb2(hcd))
2486 hcd->hcd_submit_urb(hcd, NULL, NULL, NULL);
2487
2488 return;
2489 }
2490
2491 // send CLEAR_TT_BUFFER to the hub
2492 BOOLEAN
2493 hub_clear_tt_buffer(PUSB_DEV pdev, URB_HS_PIPE_CONTENT pipe_content, UCHAR port_idx)
2494 {
2495 PURB purb;
2496 PUSB_CTRL_SETUP_PACKET psetup;
2497 PHUB2_EXTENSION hub_ext;
2498 PHCD hcd;
2499 NTSTATUS status;
2500 USE_BASIC_NON_PENDING_IRQL;
2501
2502 if (pdev == NULL)
2503 return FALSE;
2504
2505 if (pipe_content.speed_high)
2506 return FALSE;
2507
2508 lock_dev(pdev, FALSE);
2509 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
2510 {
2511 unlock_dev(pdev, FALSE);
2512 return FALSE;
2513 }
2514
2515 hub_ext = hub_ext_from_dev(pdev);
2516 if (hub_ext == NULL)
2517 {
2518 unlock_dev(pdev, FALSE);
2519 return FALSE;
2520 }
2521 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
2522
2523 if (purb == NULL)
2524 {
2525 unlock_dev(pdev, FALSE);
2526 return FALSE;
2527 }
2528
2529 RtlZeroMemory(purb, sizeof(URB));
2530
2531 purb->flags = 0;
2532 purb->status = STATUS_SUCCESS;
2533 purb->data_buffer = NULL;
2534 purb->data_length = 0; // ( hub_ext->port_count + 7 ) / 8;
2535
2536 // hub_if_from_dev( pdev, pif );
2537 purb->pendp = &pdev->default_endp;
2538 purb->pdev = pdev;
2539
2540 purb->completion = hub_clear_tt_buffer_completion;
2541 purb->context = hub_ext;
2542 purb->reference = *((PLONG) & pipe_content);
2543
2544 purb->pirp = NULL;
2545 hcd = pdev->hcd;
2546
2547 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
2548 psetup->bmRequestType = 0x23; //host-device class other recepient
2549 psetup->bRequest = HUB_REQ_CLEAR_TT_BUFFER;
2550 psetup->wValue = (USHORT) ((pipe_content.endp_addr) | (pipe_content.dev_addr << 4) |
2551 (pipe_content.trans_type << 10) | (pipe_content.trans_dir << 15));
2552
2553 if (hub_ext->multiple_tt)
2554 {
2555 psetup->wIndex = (USHORT) port_idx;
2556 }
2557 else
2558 psetup->wIndex = 1;
2559
2560 psetup->wLength = 0;
2561 unlock_dev(pdev, FALSE);
2562
2563 status = hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb);
2564 if (status != STATUS_PENDING)
2565 {
2566 usb_free_mem(purb);
2567 purb = NULL;
2568 return FALSE;
2569 }
2570 return TRUE;
2571 }
2572
2573 VOID
2574 hub_event_clear_tt_buffer(PUSB_DEV pdev, //always null. we do not use this param
2575 ULONG event,
2576 ULONG context,
2577 ULONG param)
2578 {
2579 UNREFERENCED_PARAMETER(event);
2580 hub_clear_tt_buffer(pdev, *((PURB_HS_PIPE_CONTENT) & context), (UCHAR) param);
2581 return;
2582 }
2583
2584 VOID
2585 hub_post_clear_tt_event(PUSB_DEV pdev, BYTE port_idx, ULONG pipe)
2586 {
2587 PUSB_DEV_MANAGER dev_mgr;
2588 PUSB_EVENT pevent;
2589 USE_NON_PENDING_IRQL;
2590
2591 dev_mgr = dev_mgr_from_dev(pdev);
2592
2593 KeAcquireSpinLock(&dev_mgr->event_list_lock, &old_irql);
2594 lock_dev(pdev, TRUE);
2595 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
2596 {
2597 unlock_dev(pdev, TRUE);
2598 KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
2599 return;
2600 }
2601 pevent = alloc_event(&dev_mgr->event_pool, 1);
2602 if (pevent == NULL)
2603 {
2604 unlock_dev(pdev, TRUE);
2605 KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
2606 TRAP();
2607 return;
2608 }
2609
2610 pevent->event = USB_EVENT_WAIT_RESET_PORT;
2611 pevent->pdev = pdev;
2612 pevent->context = pipe;
2613 pevent->param = port_idx;
2614 pevent->flags = USB_EVENT_FLAG_ACTIVE;
2615 pevent->process_queue = event_list_default_process_queue;
2616 pevent->process_event = hub_event_clear_tt_buffer;
2617 pevent->pnext = NULL;
2618 InsertTailList(&dev_mgr->event_list, &pevent->event_link);
2619
2620 unlock_dev(pdev, TRUE);
2621 KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
2622
2623 KeSetEvent(&dev_mgr->wake_up_event, 0, FALSE);
2624 return;
2625 }
2626
2627 BOOLEAN
2628 init_irp_list(PIRP_LIST irp_list)
2629 {
2630 LONG i;
2631 KeInitializeSpinLock(&irp_list->irp_list_lock);
2632 InitializeListHead(&irp_list->irp_busy_list);
2633 InitializeListHead(&irp_list->irp_free_list);
2634 irp_list->irp_list_element_array =
2635 usb_alloc_mem(NonPagedPool, sizeof(IRP_LIST_ELEMENT) * MAX_IRP_LIST_SIZE);
2636
2637 if (irp_list->irp_list_element_array == NULL)
2638 return FALSE;
2639
2640 RtlZeroMemory(irp_list->irp_list_element_array, sizeof(IRP_LIST_ELEMENT) * MAX_IRP_LIST_SIZE);
2641 for(i = 0; i < MAX_IRP_LIST_SIZE; i++)
2642 {
2643 InsertTailList(&irp_list->irp_free_list, &irp_list->irp_list_element_array[i].irp_link);
2644 }
2645 irp_list->irp_free_list_count = MAX_IRP_LIST_SIZE;
2646 return TRUE;
2647 }
2648
2649 VOID
2650 destroy_irp_list(PIRP_LIST irp_list)
2651 {
2652 InitializeListHead(&irp_list->irp_busy_list);
2653 InitializeListHead(&irp_list->irp_free_list);
2654 usb_free_mem(irp_list->irp_list_element_array);
2655 irp_list->irp_list_element_array = NULL;
2656 irp_list->irp_free_list_count = 0;
2657 return;
2658 }
2659
2660 BOOLEAN
2661 add_irp_to_list(PIRP_LIST irp_list, PIRP pirp, PURB purb)
2662 {
2663 KIRQL old_irql;
2664 PIRP_LIST_ELEMENT pile;
2665
2666 if (irp_list == NULL || pirp == NULL || purb == NULL)
2667 return FALSE;
2668
2669 IoAcquireCancelSpinLock(&old_irql);
2670 KeAcquireSpinLockAtDpcLevel(&irp_list->irp_list_lock);
2671
2672 if (irp_list->irp_free_list_count == 0)
2673 {
2674 KeReleaseSpinLockFromDpcLevel(&irp_list->irp_list_lock);
2675 IoReleaseCancelSpinLock(old_irql);
2676 return FALSE;
2677 }
2678 pile = (PIRP_LIST_ELEMENT) RemoveHeadList(&irp_list->irp_free_list);
2679
2680 pile->pirp = pirp;
2681 pile->purb = purb;
2682
2683 irp_list->irp_free_list_count--;
2684 InsertTailList(&irp_list->irp_busy_list, &pile->irp_link);
2685 (void)IoSetCancelRoutine(pirp, dev_mgr_cancel_irp);
2686
2687 KeReleaseSpinLockFromDpcLevel(&irp_list->irp_list_lock);
2688 IoReleaseCancelSpinLock(old_irql);
2689 return TRUE;
2690 }
2691
2692 PURB
2693 remove_irp_from_list(PIRP_LIST irp_list,
2694 PIRP pirp,
2695 PUSB_DEV_MANAGER dev_mgr //if dev_mgr is not NULL, the urb needs to be canceled
2696 )
2697 {
2698 PIRP_LIST_ELEMENT pile;
2699 PLIST_ENTRY pthis, pnext;
2700 PURB purb;
2701 DEV_HANDLE endp_handle;
2702 PUSB_DEV pdev;
2703 PUSB_ENDPOINT pendp;
2704 PHCD hcd;
2705
2706 USE_NON_PENDING_IRQL;
2707
2708 if (irp_list == NULL || pirp == NULL)
2709 return NULL;
2710
2711 KeAcquireSpinLock(&irp_list->irp_list_lock, &old_irql);
2712
2713 if (irp_list->irp_free_list_count == MAX_IRP_LIST_SIZE)
2714 {
2715 KeReleaseSpinLock(&irp_list->irp_list_lock, old_irql);
2716 return NULL;
2717 }
2718
2719 purb = NULL;
2720 ListFirst(&irp_list->irp_busy_list, pthis);
2721 while (pthis)
2722 {
2723 pile = struct_ptr(pthis, IRP_LIST_ELEMENT, irp_link);
2724 if (pile->pirp == pirp)
2725 {
2726 purb = pile->purb;
2727 pile->pirp = NULL;
2728 pile->purb = NULL;
2729 RemoveEntryList(pthis);
2730 InsertTailList(&irp_list->irp_free_list, pthis);
2731 irp_list->irp_free_list_count++;
2732 break;
2733 }
2734 ListNext(&irp_list->irp_busy_list, pthis, pnext);
2735 pthis = pnext;
2736 }
2737
2738 if (purb == NULL)
2739 {
2740 // not found
2741 KeReleaseSpinLock(&irp_list->irp_list_lock, old_irql);
2742 return NULL;
2743 }
2744
2745 endp_handle = purb->endp_handle;
2746 KeReleaseSpinLock(&irp_list->irp_list_lock, old_irql);
2747
2748 if (dev_mgr)
2749 {
2750 // indicate we needs to cancel the urb, this condition happens only in cancel routine
2751 // we should notice that even the hcd_cancel_urb is called, the irp may not be canceled
2752 // if the urb does not exist in any queue of the host controller driver, indicating
2753 // it is being processed by dpc. Thus, the dpc will certainly prevent the irp in
2754 // completion from being canceled at the same time. On the other hand, if the
2755 // hcd_cancel_urb succeeds, it either directly complete the irp or queue the dpc for
2756 // irp completion. So, there won't be two simutaneous threads processing the same
2757 // irp.
2758
2759 if (usb_query_and_lock_dev(dev_mgr, endp_handle, &pdev) != STATUS_SUCCESS)
2760 return NULL;
2761
2762 lock_dev(pdev, TRUE);
2763 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
2764 {
2765 unlock_dev(pdev, FALSE);
2766 usb_unlock_dev(pdev);
2767 return NULL;
2768 }
2769
2770 hcd = pdev->hcd;
2771 endp_from_handle(pdev, endp_handle, pendp);
2772 unlock_dev(pdev, TRUE);
2773 hcd->hcd_cancel_urb(hcd, pdev, pendp, purb);
2774 usb_unlock_dev(pdev);
2775 return NULL;
2776 }
2777 return purb;
2778 }
2779
2780 BOOLEAN
2781 irp_list_empty(PIRP_LIST irp_list)
2782 {
2783 KIRQL old_irql;
2784 BOOLEAN ret;
2785 KeAcquireSpinLock(&irp_list->irp_list_lock, &old_irql);
2786 ret = (BOOLEAN) (irp_list->irp_free_list_count == MAX_IRP_LIST_SIZE);
2787 KeReleaseSpinLock(&irp_list->irp_list_lock, old_irql);
2788 return ret;
2789 }
2790
2791 BOOLEAN
2792 irp_list_full(PIRP_LIST irp_list)
2793 {
2794 KIRQL old_irql;
2795 BOOLEAN ret;
2796 KeAcquireSpinLock(&irp_list->irp_list_lock, &old_irql);
2797 ret = (BOOLEAN) (irp_list->irp_free_list_count == 0);
2798 KeReleaseSpinLock(&irp_list->irp_list_lock, old_irql);
2799 return ret;
2800 }