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