[USBHUB]
[reactos.git] / reactos / drivers / usb / usbhub / fdo.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Hub Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbhub/fdo.c
5 * PURPOSE: Handle FDO
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11 #define INITGUID
12 #include "usbhub.h"
13
14 NTSTATUS
15 QueryStatusChangeEndpoint(
16 IN PDEVICE_OBJECT DeviceObject);
17
18 NTSTATUS
19 CreateUsbChildDeviceObject(
20 IN PDEVICE_OBJECT UsbHubDeviceObject,
21 IN LONG PortId,
22 OUT PDEVICE_OBJECT *UsbChildDeviceObject,
23 IN ULONG PortStatus);
24
25 NTSTATUS
26 DestroyUsbChildDeviceObject(
27 IN PDEVICE_OBJECT UsbHubDeviceObject,
28 IN LONG PortId);
29
30
31 NTSTATUS
32 GetPortStatusAndChange(
33 IN PDEVICE_OBJECT RootHubDeviceObject,
34 IN ULONG PortId,
35 OUT PPORT_STATUS_CHANGE StatusChange)
36 {
37 NTSTATUS Status;
38 PURB Urb;
39
40 //
41 // Allocate URB
42 //
43 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
44 if (!Urb)
45 {
46 DPRINT1("Failed to allocate memory for URB!\n");
47 return STATUS_INSUFFICIENT_RESOURCES;
48 }
49
50 //
51 // Zero it
52 //
53 RtlZeroMemory(Urb, sizeof(URB));
54
55 //
56 // Initialize URB for getting Port Status
57 //
58 UsbBuildVendorRequest(Urb,
59 URB_FUNCTION_CLASS_OTHER,
60 sizeof(Urb->UrbControlVendorClassRequest),
61 USBD_TRANSFER_DIRECTION_OUT,
62 0,
63 USB_REQUEST_GET_STATUS,
64 0,
65 PortId,
66 StatusChange,
67 0,
68 sizeof(PORT_STATUS_CHANGE),
69 0);
70
71 // FIXME: support usb hubs
72 Urb->UrbHeader.UsbdDeviceHandle = NULL;
73
74
75 //
76 // Query the Root Hub
77 //
78 Status = SubmitRequestToRootHub(RootHubDeviceObject, IOCTL_INTERNAL_USB_SUBMIT_URB, Urb, NULL);
79
80 //
81 // Free URB
82 //
83 ExFreePool(Urb);
84
85 return Status;
86 }
87
88 NTSTATUS
89 SetPortFeature(
90 IN PDEVICE_OBJECT RootHubDeviceObject,
91 IN ULONG PortId,
92 IN ULONG Feature)
93 {
94 NTSTATUS Status;
95 PURB Urb;
96
97 //
98 // Allocate URB
99 //
100 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
101 if (!Urb)
102 {
103 DPRINT1("Failed to allocate memory for URB!\n");
104 return STATUS_INSUFFICIENT_RESOURCES;
105 }
106
107 //
108 // Zero it
109 //
110 RtlZeroMemory(Urb, sizeof(URB));
111
112 //
113 // Initialize URB for Clearing Port Reset
114 //
115 UsbBuildVendorRequest(Urb,
116 URB_FUNCTION_CLASS_OTHER,
117 sizeof(Urb->UrbControlVendorClassRequest),
118 USBD_TRANSFER_DIRECTION_IN,
119 0,
120 USB_REQUEST_SET_FEATURE,
121 Feature,
122 PortId,
123 NULL,
124 0,
125 0,
126 0);
127
128 // FIXME support usbhubs
129 Urb->UrbHeader.UsbdDeviceHandle = NULL;
130
131 //
132 // Query the Root Hub
133 //
134 Status = SubmitRequestToRootHub(RootHubDeviceObject, IOCTL_INTERNAL_USB_SUBMIT_URB, Urb, NULL);
135
136 //
137 // Free URB
138 //
139 ExFreePool(Urb);
140
141 return Status;
142 }
143
144 NTSTATUS
145 ClearPortFeature(
146 IN PDEVICE_OBJECT RootHubDeviceObject,
147 IN ULONG PortId,
148 IN ULONG Feature)
149 {
150 NTSTATUS Status;
151 PURB Urb;
152
153 //
154 // Allocate a URB
155 //
156 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
157 if (!Urb)
158 {
159 DPRINT1("Failed to allocate memory for URB!\n");
160 return STATUS_INSUFFICIENT_RESOURCES;
161 }
162
163 //
164 // Zero it
165 //
166 RtlZeroMemory(Urb, sizeof(URB));
167
168 //
169 // Initialize URB for Clearing Port Reset
170 //
171 UsbBuildVendorRequest(Urb,
172 URB_FUNCTION_CLASS_OTHER,
173 sizeof(Urb->UrbControlVendorClassRequest),
174 USBD_TRANSFER_DIRECTION_IN,
175 0,
176 USB_REQUEST_CLEAR_FEATURE,
177 Feature,
178 PortId,
179 NULL,
180 0,
181 0,
182 0);
183
184 // FIXME: support usb hubs
185 Urb->UrbHeader.UsbdDeviceHandle = NULL;
186
187 //
188 // Query the Root Hub
189 //
190 Status = SubmitRequestToRootHub(RootHubDeviceObject, IOCTL_INTERNAL_USB_SUBMIT_URB, Urb, NULL);
191
192 //
193 // Free URB
194 //
195 ExFreePool(Urb);
196
197 return Status;
198 }
199
200 VOID NTAPI
201 DeviceStatusChangeThread(
202 IN PVOID Context)
203 {
204 NTSTATUS Status;
205 PDEVICE_OBJECT DeviceObject, RootHubDeviceObject;
206 PHUB_DEVICE_EXTENSION HubDeviceExtension;
207 PWORK_ITEM_DATA WorkItemData;
208 PORT_STATUS_CHANGE PortStatus;
209 LONG PortId;
210 BOOLEAN SignalResetComplete = FALSE;
211
212 DPRINT("Entered DeviceStatusChangeThread, Context %x\n", Context);
213
214 WorkItemData = (PWORK_ITEM_DATA)Context;
215 DeviceObject = (PDEVICE_OBJECT)WorkItemData->Context;
216 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
217 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
218 //
219 // Loop all ports
220 //
221 for (PortId = 1; PortId <= HubDeviceExtension->UsbExtHubInfo.NumberOfPorts; PortId++)
222 {
223 //
224 // Get Port Status
225 //
226 Status = GetPortStatusAndChange(RootHubDeviceObject, PortId, &PortStatus);
227 if (!NT_SUCCESS(Status))
228 {
229 DPRINT1("Failed to get port status for port %d, Status %x\n", PortId, Status);
230 // FIXME: Do we really want to halt further SCE requests?
231 return;
232 }
233
234 DPRINT1("Port %d Status %x\n", PortId, PortStatus.Status);
235 DPRINT1("Port %d Change %x\n", PortId, PortStatus.Change);
236
237
238 //
239 // Check for new device connection
240 //
241 if (PortStatus.Change & USB_PORT_STATUS_CONNECT)
242 {
243 //
244 // Clear Port Connect
245 //
246 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
247 if (!NT_SUCCESS(Status))
248 {
249 DPRINT1("Failed to clear connection change for port %d\n", PortId);
250 continue;
251 }
252
253 //
254 // Is this a connect or disconnect?
255 //
256 if (!(PortStatus.Status & USB_PORT_STATUS_CONNECT))
257 {
258 DPRINT1("Device disconnected from port %d\n", PortId);
259
260 Status = DestroyUsbChildDeviceObject(DeviceObject, PortId);
261 if (!NT_SUCCESS(Status))
262 {
263 DPRINT1("Failed to delete child device object after disconnect\n");
264 continue;
265 }
266 }
267 else
268 {
269 DPRINT1("Device connected from port %d\n", PortId);
270
271 // No SCE completion done for clearing C_PORT_CONNECT
272
273 //
274 // Reset Port
275 //
276 Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_RESET);
277 if (!NT_SUCCESS(Status))
278 {
279 DPRINT1("Failed to reset port %d\n", PortId);
280 SignalResetComplete = TRUE;
281 continue;
282 }
283 }
284 }
285 else if (PortStatus.Change & USB_PORT_STATUS_ENABLE)
286 {
287 //
288 // Clear Enable
289 //
290 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_ENABLE);
291 if (!NT_SUCCESS(Status))
292 {
293 DPRINT1("Failed to clear enable change on port %d\n", PortId);
294 continue;
295 }
296 }
297 else if (PortStatus.Change & USB_PORT_STATUS_RESET)
298 {
299 //
300 // Request event signalling later
301 //
302 SignalResetComplete = TRUE;
303
304 //
305 // Clear Reset
306 //
307 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_RESET);
308 if (!NT_SUCCESS(Status))
309 {
310 DPRINT1("Failed to clear reset change on port %d\n", PortId);
311 continue;
312 }
313
314 //
315 // Get Port Status
316 //
317 Status = GetPortStatusAndChange(RootHubDeviceObject, PortId, &PortStatus);
318 if (!NT_SUCCESS(Status))
319 {
320 DPRINT1("Failed to get port status for port %d, Status %x\n", PortId, Status);
321 // FIXME: Do we really want to halt further SCE requests?
322 return;
323 }
324
325 DPRINT1("Port %d Status %x\n", PortId, PortStatus.Status);
326 DPRINT1("Port %d Change %x\n", PortId, PortStatus.Change);
327
328 //
329 // Check that reset was cleared
330 //
331 if(PortStatus.Change & USB_PORT_STATUS_RESET)
332 {
333 DPRINT1("Port did not clear reset! Possible Hardware problem!\n");
334 continue;
335 }
336
337 //
338 // Check if the device is still connected
339 //
340 if (!(PortStatus.Status & USB_PORT_STATUS_CONNECT))
341 {
342 DPRINT1("Device has been disconnected\n");
343 continue;
344 }
345
346 //
347 // Make sure its Connected and Enabled
348 //
349 if (!(PortStatus.Status & (USB_PORT_STATUS_CONNECT | USB_PORT_STATUS_ENABLE)))
350 {
351 DPRINT1("Usb Device is not connected and enabled!\n");
352 //
353 // Attempt another reset
354 //
355 Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_RESET);
356 if (!NT_SUCCESS(Status))
357 {
358 DPRINT1("Failed to reset port %d\n", PortId);
359 }
360 continue;
361 }
362
363 //
364 // This is a new device
365 //
366 Status = CreateUsbChildDeviceObject(DeviceObject, PortId, NULL, PortStatus.Status);
367 }
368 }
369
370 ExFreePool(WorkItemData);
371
372 //
373 // Send another SCE Request
374 //
375 DPRINT("Sending another SCE!\n");
376 QueryStatusChangeEndpoint(DeviceObject);
377
378 //
379 // Check if a reset event was satisfied
380 //
381 if (SignalResetComplete)
382 {
383 //
384 // Signal anyone waiting on it
385 //
386 KeSetEvent(&HubDeviceExtension->ResetComplete, IO_NO_INCREMENT, FALSE);
387 }
388 }
389
390 NTSTATUS
391 NTAPI
392 StatusChangeEndpointCompletion(
393 IN PDEVICE_OBJECT DeviceObject,
394 IN PIRP Irp,
395 IN PVOID Context)
396 {
397 PDEVICE_OBJECT RealDeviceObject;
398 PHUB_DEVICE_EXTENSION HubDeviceExtension;
399 PWORK_ITEM_DATA WorkItemData;
400
401 RealDeviceObject = (PDEVICE_OBJECT)Context;
402 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)RealDeviceObject->DeviceExtension;
403
404 //
405 // NOTE: USBPORT frees this IRP
406 //
407 DPRINT("Received Irp %x, HubDeviceExtension->PendingSCEIrp %x\n", Irp, HubDeviceExtension->PendingSCEIrp);
408 //IoFreeIrp(Irp);
409
410 //
411 // Create and initialize work item data
412 //
413 WorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(WORK_ITEM_DATA), USB_HUB_TAG);
414 if (!WorkItemData)
415 {
416 DPRINT1("Failed to allocate memory!n");
417 return STATUS_INSUFFICIENT_RESOURCES;
418 }
419 WorkItemData->Context = RealDeviceObject;
420
421 DPRINT("Queuing work item\n");
422
423 //
424 // Queue the work item to handle initializing the device
425 //
426 ExInitializeWorkItem(&WorkItemData->WorkItem, DeviceStatusChangeThread, (PVOID)WorkItemData);
427 ExQueueWorkItem(&WorkItemData->WorkItem, DelayedWorkQueue);
428
429 //
430 // Return more processing required so the IO Manger doesn’t try to mess with IRP just freed
431 //
432 return STATUS_MORE_PROCESSING_REQUIRED;
433 }
434
435 NTSTATUS
436 QueryStatusChangeEndpoint(
437 IN PDEVICE_OBJECT DeviceObject)
438 {
439 NTSTATUS Status;
440 PDEVICE_OBJECT RootHubDeviceObject;
441 PIO_STACK_LOCATION Stack;
442 PHUB_DEVICE_EXTENSION HubDeviceExtension;
443 PURB PendingSCEUrb;
444
445 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
446 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
447
448 //
449 // Allocate a URB
450 //
451 PendingSCEUrb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
452
453 //
454 // Initialize URB for Status Change Endpoint request
455 //
456 UsbBuildInterruptOrBulkTransferRequest(PendingSCEUrb,
457 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
458 HubDeviceExtension->PipeHandle,
459 HubDeviceExtension->PortStatusChange,
460 NULL,
461 sizeof(USHORT) * 2 * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
462 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
463 NULL);
464
465 // Set the device handle
466 PendingSCEUrb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
467
468 //
469 // Allocate an Irp
470 //
471 HubDeviceExtension->PendingSCEIrp = ExAllocatePoolWithTag(NonPagedPool,
472 IoSizeOfIrp(RootHubDeviceObject->StackSize),
473 USB_HUB_TAG);
474 /*
475 HubDeviceExtension->PendingSCEIrp = IoAllocateIrp(RootHubDeviceObject->StackSize,
476 FALSE);
477 */
478 DPRINT("Allocated IRP %x\n", HubDeviceExtension->PendingSCEIrp);
479
480 if (!HubDeviceExtension->PendingSCEIrp)
481 {
482 DPRINT1("USBHUB: Failed to allocate IRP for SCE request!\n");
483 return STATUS_INSUFFICIENT_RESOURCES;
484 }
485
486 //
487 // Initialize the IRP
488 //
489 IoInitializeIrp(HubDeviceExtension->PendingSCEIrp,
490 IoSizeOfIrp(RootHubDeviceObject->StackSize),
491 RootHubDeviceObject->StackSize);
492
493 HubDeviceExtension->PendingSCEIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
494 HubDeviceExtension->PendingSCEIrp->IoStatus.Information = 0;
495 HubDeviceExtension->PendingSCEIrp->Flags = 0;
496 HubDeviceExtension->PendingSCEIrp->UserBuffer = NULL;
497
498 //
499 // Get the Next Stack Location and Initialize it
500 //
501 Stack = IoGetNextIrpStackLocation(HubDeviceExtension->PendingSCEIrp);
502 Stack->DeviceObject = DeviceObject;
503 Stack->Parameters.Others.Argument1 = PendingSCEUrb;
504 Stack->Parameters.Others.Argument2 = NULL;
505 Stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
506 Stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
507
508 //
509 // Set the completion routine for when device is connected to root hub
510 //
511 IoSetCompletionRoutine(HubDeviceExtension->PendingSCEIrp,
512 StatusChangeEndpointCompletion,
513 DeviceObject,
514 TRUE,
515 TRUE,
516 TRUE);
517
518 //
519 // Send to RootHub
520 //
521 DPRINT("DeviceObject is %x\n", DeviceObject);
522 DPRINT("Iocalldriver %x with irp %x\n", RootHubDeviceObject, HubDeviceExtension->PendingSCEIrp);
523 Status = IoCallDriver(RootHubDeviceObject, HubDeviceExtension->PendingSCEIrp);
524
525 return STATUS_PENDING;
526 }
527
528 NTSTATUS
529 QueryInterface(
530 IN PDEVICE_OBJECT DeviceObject,
531 IN CONST GUID InterfaceType,
532 IN LONG Size,
533 IN LONG Version,
534 OUT PVOID Interface)
535 {
536 KEVENT Event;
537 PIRP Irp;
538 IO_STATUS_BLOCK IoStatus;
539 NTSTATUS Status;
540 PIO_STACK_LOCATION Stack = NULL;
541
542 //
543 // Initialize the Event used to wait for Irp completion
544 //
545 KeInitializeEvent(&Event, NotificationEvent, FALSE);
546
547 //
548 // Build Control Request
549 //
550 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
551 DeviceObject,
552 NULL,
553 0,
554 NULL,
555 &Event,
556 &IoStatus);
557
558 //
559 // Get Next Stack Location and Initialize it.
560 //
561 Stack = IoGetNextIrpStackLocation(Irp);
562 Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
563 Stack->Parameters.QueryInterface.InterfaceType= &InterfaceType;//USB_BUS_INTERFACE_HUB_GUID;
564 Stack->Parameters.QueryInterface.Size = Size;
565 Stack->Parameters.QueryInterface.Version = Version;
566 Stack->Parameters.QueryInterface.Interface = Interface;
567 Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
568
569 Status = IoCallDriver(DeviceObject, Irp);
570
571 if (Status == STATUS_PENDING)
572 {
573 DPRINT("Operation pending\n");
574 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
575 Status = IoStatus.Status;
576 }
577
578 return Status;
579 }
580
581 NTSTATUS
582 GetUsbDeviceDescriptor(
583 IN PDEVICE_OBJECT ChildDeviceObject,
584 IN UCHAR DescriptorType,
585 IN UCHAR Index,
586 IN USHORT LangId,
587 OUT PVOID TransferBuffer,
588 IN ULONG TransferBufferLength)
589 {
590 NTSTATUS Status;
591 PDEVICE_OBJECT RootHubDeviceObject;
592 PURB Urb;
593 PHUB_DEVICE_EXTENSION HubDeviceExtension;
594 PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
595
596 //
597 // Get the Hubs Device Extension
598 //
599 ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)ChildDeviceObject->DeviceExtension;
600 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) ChildDeviceExtension->ParentDeviceObject->DeviceExtension;
601 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
602
603 //
604 // Allocate a URB
605 //
606 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
607 if (!Urb)
608 {
609 DPRINT1("Failed to allocate memory for URB!\n");
610 return STATUS_INSUFFICIENT_RESOURCES;
611 }
612
613 //
614 // Zero it
615 //
616 RtlZeroMemory(Urb, sizeof(URB));
617
618 //
619 // Initialize URB for getting device descriptor
620 //
621 UsbBuildGetDescriptorRequest(Urb,
622 sizeof(Urb->UrbControlDescriptorRequest),
623 DescriptorType,
624 Index,
625 LangId,
626 TransferBuffer,
627 NULL,
628 TransferBufferLength,
629 NULL);
630
631 //
632 // Set the device handle
633 //
634 Urb->UrbHeader.UsbdDeviceHandle = (PVOID)ChildDeviceExtension->UsbDeviceHandle;
635
636 //
637 // Query the Root Hub
638 //
639 Status = SubmitRequestToRootHub(RootHubDeviceObject,
640 IOCTL_INTERNAL_USB_SUBMIT_URB,
641 Urb,
642 NULL);
643
644 return Status;
645 }
646
647 NTSTATUS
648 GetUsbStringDescriptor(
649 IN PDEVICE_OBJECT ChildDeviceObject,
650 IN UCHAR Index,
651 IN USHORT LangId,
652 OUT PVOID *TransferBuffer,
653 OUT USHORT *Size)
654 {
655 NTSTATUS Status;
656 PUSB_STRING_DESCRIPTOR StringDesc = NULL;
657 ULONG SizeNeeded;
658 LPWSTR Buffer;
659
660 StringDesc = ExAllocatePoolWithTag(NonPagedPool,
661 sizeof(USB_STRING_DESCRIPTOR),
662 USB_HUB_TAG);
663 if (!StringDesc)
664 {
665 DPRINT1("Failed to allocate buffer for string!\n");
666 return STATUS_INSUFFICIENT_RESOURCES;
667 }
668
669 //
670 // Get the index string descriptor length
671 // FIXME: Implement LangIds
672 //
673 Status = GetUsbDeviceDescriptor(ChildDeviceObject,
674 USB_STRING_DESCRIPTOR_TYPE,
675 Index,
676 0x0409,
677 StringDesc,
678 sizeof(USB_STRING_DESCRIPTOR));
679 if (!NT_SUCCESS(Status))
680 {
681 DPRINT1("GetUsbDeviceDescriptor failed with status %x\n", Status);
682 ExFreePool(StringDesc);
683 return Status;
684 }
685 DPRINT1("StringDesc->bLength %d\n", StringDesc->bLength);
686
687 //
688 // Did we get something more than the length of the first two fields of structure?
689 //
690 if (StringDesc->bLength == 2)
691 {
692 DPRINT1("USB Device Error!\n");
693 ExFreePool(StringDesc);
694 return STATUS_DEVICE_DATA_ERROR;
695 }
696 SizeNeeded = StringDesc->bLength + sizeof(WCHAR);
697
698 //
699 // Free String
700 //
701 ExFreePool(StringDesc);
702
703 //
704 // Recreate with appropriate size
705 //
706 StringDesc = ExAllocatePoolWithTag(NonPagedPool,
707 SizeNeeded,
708 USB_HUB_TAG);
709 if (!StringDesc)
710 {
711 DPRINT1("Failed to allocate buffer for string!\n");
712 return STATUS_INSUFFICIENT_RESOURCES;
713 }
714
715 RtlZeroMemory(StringDesc, SizeNeeded);
716
717 //
718 // Get the string
719 //
720 Status = GetUsbDeviceDescriptor(ChildDeviceObject,
721 USB_STRING_DESCRIPTOR_TYPE,
722 Index,
723 0x0409,
724 StringDesc,
725 SizeNeeded);
726 if (!NT_SUCCESS(Status))
727 {
728 DPRINT1("GetUsbDeviceDescriptor failed with status %x\n", Status);
729 ExFreePool(StringDesc);
730 return Status;
731 }
732
733 //
734 // Allocate Buffer to return
735 //
736 Buffer = ExAllocatePoolWithTag(NonPagedPool,
737 SizeNeeded,
738 USB_HUB_TAG);
739 if (!Buffer)
740 {
741 DPRINT1("Failed to allocate buffer for string!\n");
742 ExFreePool(StringDesc);
743 return STATUS_INSUFFICIENT_RESOURCES;
744 }
745
746 RtlZeroMemory(Buffer, SizeNeeded);
747
748 //
749 // Copy the string to destination
750 //
751 RtlCopyMemory(Buffer, StringDesc->bString, SizeNeeded - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString));
752 *Size = SizeNeeded;
753 *TransferBuffer = Buffer;
754
755 ExFreePool(StringDesc);
756
757 return STATUS_SUCCESS;
758 }
759
760 ULONG
761 IsCompositeDevice(
762 IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
763 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
764 {
765 if (DeviceDescriptor->bNumConfigurations != 1)
766 {
767 //
768 // composite device must have only one configuration
769 //
770 DPRINT1("IsCompositeDevice bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
771 return FALSE;
772 }
773
774 if (ConfigurationDescriptor->bNumInterfaces < 2)
775 {
776 //
777 // composite device must have multiple interfaces
778 //
779 DPRINT1("IsCompositeDevice bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
780 return FALSE;
781 }
782
783 if (DeviceDescriptor->bDeviceClass == 0)
784 {
785 //
786 // composite device
787 //
788 ASSERT(DeviceDescriptor->bDeviceSubClass == 0);
789 ASSERT(DeviceDescriptor->bDeviceProtocol == 0);
790 DPRINT1("IsCompositeDevice: TRUE\n");
791 return TRUE;
792 }
793
794 if (DeviceDescriptor->bDeviceClass == 0xEF &&
795 DeviceDescriptor->bDeviceSubClass == 0x02 &&
796 DeviceDescriptor->bDeviceProtocol == 0x01)
797 {
798 //
799 // USB-IF association descriptor
800 //
801 DPRINT1("IsCompositeDevice: TRUE\n");
802 return TRUE;
803 }
804
805 DPRINT1("DeviceDescriptor bDeviceClass %x bDeviceSubClass %x bDeviceProtocol %x\n", DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol);
806
807 //
808 // not a composite device
809 //
810 return FALSE;
811 }
812
813 NTSTATUS
814 CreateDeviceIds(
815 PDEVICE_OBJECT UsbChildDeviceObject)
816 {
817 NTSTATUS Status = STATUS_SUCCESS;
818 ULONG Index = 0;
819 LPWSTR DeviceString;
820 WCHAR Buffer[200];
821 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
822 PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
823 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
824 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
825
826 //
827 // get child device extension
828 //
829 UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)UsbChildDeviceObject->DeviceExtension;
830
831 //
832 // get device descriptor
833 //
834 DeviceDescriptor = &UsbChildExtension->DeviceDesc;
835
836 //
837 // get configuration descriptor
838 //
839 ConfigurationDescriptor = UsbChildExtension->FullConfigDesc;
840
841 //
842 // use first interface descriptor available
843 //
844 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, 0, -1, -1, -1, -1);
845 ASSERT(InterfaceDescriptor);
846
847 //
848 // Construct the CompatibleIds
849 //
850 if (IsCompositeDevice(DeviceDescriptor, ConfigurationDescriptor))
851 {
852 //
853 // sanity checks
854 //
855 ASSERT(DeviceDescriptor->bNumConfigurations == 1);
856 ASSERT(ConfigurationDescriptor->bNumInterfaces > 1);
857 Index += swprintf(&Buffer[Index],
858 L"USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
859 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol) + 1;
860 Index += swprintf(&Buffer[Index],
861 L"USB\\DevClass_%02x&SubClass_%02x",
862 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass) + 1;
863 Index += swprintf(&Buffer[Index],
864 L"USB\\DevClass_%02x",
865 DeviceDescriptor->bDeviceClass) + 1;
866 Index += swprintf(&Buffer[Index],
867 L"USB\\COMPOSITE") + 1;
868 }
869 else
870 {
871 //
872 // FIXME: support multiple configurations
873 //
874 ASSERT(DeviceDescriptor->bNumConfigurations == 1);
875
876 if (DeviceDescriptor->bDeviceClass == 0)
877 {
878 Index += swprintf(&Buffer[Index],
879 L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
880 InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass, InterfaceDescriptor->bInterfaceProtocol) + 1;
881 Index += swprintf(&Buffer[Index],
882 L"USB\\Class_%02x&SubClass_%02x",
883 InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass) + 1;
884 Index += swprintf(&Buffer[Index],
885 L"USB\\Class_%02x",
886 InterfaceDescriptor->bInterfaceClass) + 1;
887 }
888 else
889 {
890 Index += swprintf(&Buffer[Index],
891 L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
892 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol) + 1;
893 Index += swprintf(&Buffer[Index],
894 L"USB\\Class_%02x&SubClass_%02x",
895 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass) + 1;
896 Index += swprintf(&Buffer[Index],
897 L"USB\\Class_%02x",
898 DeviceDescriptor->bDeviceClass) + 1;
899 }
900 }
901
902 //
903 // now allocate the buffer
904 //
905 DeviceString = ExAllocatePool(NonPagedPool, (Index + 1) * sizeof(WCHAR));
906 if (!DeviceString)
907 {
908 //
909 // no memory
910 //
911 return STATUS_INSUFFICIENT_RESOURCES;
912 }
913
914 //
915 // copy buffer
916 //
917 RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
918 DeviceString[Index] = UNICODE_NULL;
919 UsbChildExtension->usCompatibleIds.Buffer = DeviceString;
920 UsbChildExtension->usCompatibleIds.Length = Index * sizeof(WCHAR);
921 UsbChildExtension->usCompatibleIds.MaximumLength = (Index + 1) * sizeof(WCHAR);
922 DPRINT("usCompatibleIds %wZ\n", &UsbChildExtension->usCompatibleIds);
923
924 //
925 // Construct DeviceId string
926 //
927 Index = swprintf(Buffer, L"USB\\Vid_%04x&Pid_%04x", UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct) + 1;
928
929 //
930 // now allocate the buffer
931 //
932 DeviceString = ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
933 if (!DeviceString)
934 {
935 //
936 // no memory
937 //
938 return STATUS_INSUFFICIENT_RESOURCES;
939 }
940
941 //
942 // copy buffer
943 //
944 RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
945 UsbChildExtension->usDeviceId.Buffer = DeviceString;
946 UsbChildExtension->usDeviceId.Length = (Index-1) * sizeof(WCHAR);
947 UsbChildExtension->usDeviceId.MaximumLength = Index * sizeof(WCHAR);
948 DPRINT("usDeviceId %wZ\n", &UsbChildExtension->usDeviceId);
949
950 //
951 // Construct HardwareIds
952 //
953 Index = 0;
954 Index += swprintf(&Buffer[Index],
955 L"USB\\Vid_%04x&Pid_%04x&Rev_%04x",
956 UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct, UsbChildExtension->DeviceDesc.bcdDevice) + 1;
957 Index += swprintf(&Buffer[Index],
958 L"USB\\Vid_%04x&Pid_%04x",
959 UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct) + 1;
960
961 //
962 // now allocate the buffer
963 //
964 DeviceString = ExAllocatePool(NonPagedPool, (Index + 1) * sizeof(WCHAR));
965 if (!DeviceString)
966 {
967 //
968 // no memory
969 //
970 return STATUS_INSUFFICIENT_RESOURCES;
971 }
972
973 //
974 // copy buffer
975 //
976 RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
977 DeviceString[Index] = UNICODE_NULL;
978 UsbChildExtension->usHardwareIds.Buffer = DeviceString;
979 UsbChildExtension->usHardwareIds.Length = (Index + 1) * sizeof(WCHAR);
980 UsbChildExtension->usHardwareIds.MaximumLength = (Index + 1) * sizeof(WCHAR);
981 DPRINT("usHardWareIds %wZ\n", &UsbChildExtension->usHardwareIds);
982
983 //
984 // FIXME: Handle Lang ids
985 //
986
987 //
988 // Get the product string if obe provided
989 //
990 if (UsbChildExtension->DeviceDesc.iProduct)
991 {
992 Status = GetUsbStringDescriptor(UsbChildDeviceObject,
993 UsbChildExtension->DeviceDesc.iProduct,
994 0,
995 (PVOID*)&UsbChildExtension->usTextDescription.Buffer,
996 &UsbChildExtension->usTextDescription.Length);
997 if (!NT_SUCCESS(Status))
998 {
999 DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
1000 RtlInitUnicodeString(&UsbChildExtension->usTextDescription, L"USB Device"); // FIXME NON-NLS
1001 }
1002 else
1003 {
1004 UsbChildExtension->usTextDescription.MaximumLength = UsbChildExtension->usTextDescription.Length;
1005 DPRINT("Usb TextDescription %wZ\n", &UsbChildExtension->usTextDescription);
1006 }
1007 }
1008
1009 //
1010 // Get the Serial Number string if obe provided
1011 //
1012 if (UsbChildExtension->DeviceDesc.iSerialNumber)
1013 {
1014 Status = GetUsbStringDescriptor(UsbChildDeviceObject,
1015 UsbChildExtension->DeviceDesc.iSerialNumber,
1016 0,
1017 (PVOID*)&UsbChildExtension->usInstanceId.Buffer,
1018 &UsbChildExtension->usInstanceId.Length);
1019 if (!NT_SUCCESS(Status))
1020 {
1021 DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
1022 return Status;
1023 }
1024
1025 UsbChildExtension->usInstanceId.MaximumLength = UsbChildExtension->usInstanceId.Length;
1026 DPRINT("Usb InstanceId %wZ\n", &UsbChildExtension->usInstanceId);
1027 }
1028 else
1029 {
1030 //
1031 // the device did not provide a serial number, lets create a pseudo instance id
1032 //
1033 Index = swprintf(Buffer, L"0&%04d", UsbChildExtension->PortNumber) + 1;
1034 UsbChildExtension->usInstanceId.Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
1035 if (UsbChildExtension->usInstanceId.Buffer == NULL)
1036 {
1037 DPRINT1("Error: failed to allocate %lu bytes\n", Index * sizeof(WCHAR));
1038 Status = STATUS_INSUFFICIENT_RESOURCES;
1039 return Status;
1040 }
1041
1042 //
1043 // copy instance id
1044 //
1045 RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR));
1046 UsbChildExtension->usInstanceId.Length = UsbChildExtension->usInstanceId.MaximumLength = Index * sizeof(WCHAR);
1047
1048 DPRINT("usDeviceId %wZ\n", &UsbChildExtension->usInstanceId);
1049 }
1050
1051 return STATUS_SUCCESS;
1052 }
1053
1054 NTSTATUS
1055 DestroyUsbChildDeviceObject(
1056 IN PDEVICE_OBJECT UsbHubDeviceObject,
1057 IN LONG PortId)
1058 {
1059 PHUB_DEVICE_EXTENSION HubDeviceExtension = (PHUB_DEVICE_EXTENSION)UsbHubDeviceObject->DeviceExtension;
1060 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension = NULL;
1061 PDEVICE_OBJECT ChildDeviceObject = NULL;
1062 ULONG Index = 0;
1063
1064 DPRINT("Removing device on port %d (Child index: %d)\n", PortId, Index);
1065
1066 for (Index = 0; Index < USB_MAXCHILDREN; Index++)
1067 {
1068 if (HubDeviceExtension->ChildDeviceObject[Index])
1069 {
1070 UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
1071
1072 /* Check if it matches the port ID */
1073 if (UsbChildExtension->PortNumber == PortId)
1074 {
1075 /* We found it */
1076 ChildDeviceObject = HubDeviceExtension->ChildDeviceObject[Index];
1077 break;
1078 }
1079 }
1080 }
1081
1082 /* Fail the request if the device doesn't exist */
1083 if (!ChildDeviceObject)
1084 {
1085 DPRINT1("Removal request for non-existant device!\n");
1086 return STATUS_UNSUCCESSFUL;
1087 }
1088
1089 /* Remove the device from the table */
1090 HubDeviceExtension->ChildDeviceObject[Index] = NULL;
1091
1092 /* Invalidate device relations for the root hub */
1093 IoInvalidateDeviceRelations(HubDeviceExtension->RootHubPhysicalDeviceObject, BusRelations);
1094
1095 /* The rest of the removal process takes place in IRP_MN_REMOVE_DEVICE handling for the PDO */
1096 return STATUS_SUCCESS;
1097 }
1098
1099 NTSTATUS
1100 CreateUsbChildDeviceObject(
1101 IN PDEVICE_OBJECT UsbHubDeviceObject,
1102 IN LONG PortId,
1103 OUT PDEVICE_OBJECT *UsbChildDeviceObject,
1104 IN ULONG PortStatus)
1105 {
1106 NTSTATUS Status;
1107 PDEVICE_OBJECT RootHubDeviceObject, NewChildDeviceObject;
1108 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1109 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
1110 PUSB_BUS_INTERFACE_HUB_V5 HubInterface;
1111 ULONG ChildDeviceCount, UsbDeviceNumber = 0;
1112 WCHAR CharDeviceName[64];
1113 UNICODE_STRING DeviceName;
1114 ULONG ConfigDescSize, DeviceDescSize;
1115 PVOID HubInterfaceBusContext;
1116 USB_CONFIGURATION_DESCRIPTOR ConfigDesc;
1117
1118 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) UsbHubDeviceObject->DeviceExtension;
1119 HubInterface = &HubDeviceExtension->HubInterface;
1120 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
1121 HubInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
1122 //
1123 // Find an empty slot in the child device array
1124 //
1125 for (ChildDeviceCount = 0; ChildDeviceCount < USB_MAXCHILDREN; ChildDeviceCount++)
1126 {
1127 if (HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] == NULL)
1128 {
1129 DPRINT("Found unused entry at %d\n", ChildDeviceCount);
1130 break;
1131 }
1132 }
1133
1134 //
1135 // Check if the limit has been reached for maximum usb devices
1136 //
1137 if (ChildDeviceCount == USB_MAXCHILDREN)
1138 {
1139 DPRINT1("USBHUB: Too many child devices!\n");
1140 return STATUS_UNSUCCESSFUL;
1141 }
1142
1143 while (TRUE)
1144 {
1145 //
1146 // Create a Device Name
1147 //
1148 swprintf(CharDeviceName, L"\\Device\\USBPDO-%d", UsbDeviceNumber);
1149
1150 //
1151 // Initialize UnicodeString
1152 //
1153 RtlInitUnicodeString(&DeviceName, CharDeviceName);
1154
1155 //
1156 // Create a DeviceObject
1157 //
1158 Status = IoCreateDevice(UsbHubDeviceObject->DriverObject,
1159 sizeof(HUB_CHILDDEVICE_EXTENSION),
1160 NULL,
1161 FILE_DEVICE_CONTROLLER,
1162 FILE_AUTOGENERATED_DEVICE_NAME,
1163 FALSE,
1164 &NewChildDeviceObject);
1165
1166 //
1167 // Check if the name is already in use
1168 //
1169 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
1170 {
1171 //
1172 // Try next name
1173 //
1174 UsbDeviceNumber++;
1175 continue;
1176 }
1177
1178 //
1179 // Check for other errors
1180 //
1181 if (!NT_SUCCESS(Status))
1182 {
1183 DPRINT1("USBHUB: IoCreateDevice failed with status %x\n", Status);
1184 return Status;
1185 }
1186
1187 DPRINT("USBHUB: Created Device %x\n", NewChildDeviceObject);
1188 break;
1189 }
1190
1191 NewChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
1192
1193 //
1194 // Assign the device extensions
1195 //
1196 UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)NewChildDeviceObject->DeviceExtension;
1197 RtlZeroMemory(UsbChildExtension, sizeof(HUB_CHILDDEVICE_EXTENSION));
1198 UsbChildExtension->ParentDeviceObject = UsbHubDeviceObject;
1199 UsbChildExtension->PortNumber = PortId;
1200
1201 //
1202 // Create the UsbDeviceObject
1203 //
1204 Status = HubInterface->CreateUsbDevice(HubInterfaceBusContext,
1205 (PVOID)&UsbChildExtension->UsbDeviceHandle,
1206 HubDeviceExtension->RootHubHandle,
1207 PortStatus,
1208 PortId);
1209 if (!NT_SUCCESS(Status))
1210 {
1211 DPRINT1("USBHUB: CreateUsbDevice failed with status %x\n", Status);
1212 goto Cleanup;
1213 }
1214
1215 //
1216 // Initialize UsbDevice
1217 //
1218 Status = HubInterface->InitializeUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle);
1219 if (!NT_SUCCESS(Status))
1220 {
1221 DPRINT1("USBHUB: InitializeUsbDevice failed with status %x\n", Status);
1222 goto Cleanup;
1223 }
1224
1225 DPRINT("Usb Device Handle %x\n", UsbChildExtension->UsbDeviceHandle);
1226
1227 ConfigDescSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
1228 DeviceDescSize = sizeof(USB_DEVICE_DESCRIPTOR);
1229
1230 //
1231 // Get the descriptors
1232 //
1233 Status = HubInterface->GetUsbDescriptors(HubInterfaceBusContext,
1234 UsbChildExtension->UsbDeviceHandle,
1235 (PUCHAR)&UsbChildExtension->DeviceDesc,
1236 &DeviceDescSize,
1237 (PUCHAR)&ConfigDesc,
1238 &ConfigDescSize);
1239 if (!NT_SUCCESS(Status))
1240 {
1241 DPRINT1("USBHUB: GetUsbDescriptors failed with status %x\n", Status);
1242 goto Cleanup;
1243 }
1244
1245 DumpDeviceDescriptor(&UsbChildExtension->DeviceDesc);
1246 DumpConfigurationDescriptor(&ConfigDesc);
1247
1248 //
1249 // FIXME: Support more than one configuration and one interface?
1250 //
1251 if (UsbChildExtension->DeviceDesc.bNumConfigurations > 1)
1252 {
1253 DPRINT1("Warning: Device has more than one configuration. Only one configuration (the first) is supported!\n");
1254 }
1255
1256 if (ConfigDesc.bNumInterfaces > 1)
1257 {
1258 DPRINT1("Warning: Device has more that one interface. Only one interface (the first) is currently supported\n");
1259 }
1260
1261 ConfigDescSize = ConfigDesc.wTotalLength;
1262
1263 //
1264 // Allocate memory for the first full descriptor, including interfaces and endpoints.
1265 //
1266 UsbChildExtension->FullConfigDesc = ExAllocatePoolWithTag(PagedPool, ConfigDescSize, USB_HUB_TAG);
1267
1268 //
1269 // Retrieve the full configuration descriptor
1270 //
1271 Status = GetUsbDeviceDescriptor(NewChildDeviceObject,
1272 USB_CONFIGURATION_DESCRIPTOR_TYPE,
1273 0,
1274 0,
1275 UsbChildExtension->FullConfigDesc,
1276 ConfigDescSize);
1277
1278 if (!NT_SUCCESS(Status))
1279 {
1280 DPRINT1("USBHUB: GetUsbDeviceDescriptor failed with status %x\n", Status);
1281 goto Cleanup;
1282 }
1283
1284 //DumpFullConfigurationDescriptor(UsbChildExtension->FullConfigDesc);
1285
1286 //
1287 // Construct all the strings that will described the device to PNP
1288 //
1289 Status = CreateDeviceIds(NewChildDeviceObject);
1290 if (!NT_SUCCESS(Status))
1291 {
1292 DPRINT1("Failed to create strings needed to describe device to PNP.\n");
1293 goto Cleanup;
1294 }
1295
1296 HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] = NewChildDeviceObject;
1297
1298 IoInvalidateDeviceRelations(RootHubDeviceObject, BusRelations);
1299 return STATUS_SUCCESS;
1300
1301 Cleanup:
1302
1303 //
1304 // Remove the usb device if it was created
1305 //
1306 if (UsbChildExtension->UsbDeviceHandle)
1307 HubInterface->RemoveUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle, 0);
1308
1309 //
1310 // Free full configuration descriptor if one was allocated
1311 //
1312 if (UsbChildExtension->FullConfigDesc)
1313 ExFreePool(UsbChildExtension->FullConfigDesc);
1314
1315 //
1316 // Delete the device object
1317 //
1318 IoDeleteDevice(NewChildDeviceObject);
1319 return Status;
1320 }
1321
1322 NTSTATUS
1323 USBHUB_FdoQueryBusRelations(
1324 IN PDEVICE_OBJECT DeviceObject,
1325 OUT PDEVICE_RELATIONS* pDeviceRelations)
1326 {
1327 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1328 PDEVICE_RELATIONS DeviceRelations;
1329 ULONG i;
1330 ULONG Children = 0;
1331 ULONG NeededSize;
1332
1333 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1334
1335 //
1336 // Count the number of children
1337 //
1338 for (i = 0; i < USB_MAXCHILDREN; i++)
1339 {
1340
1341 if (HubDeviceExtension->ChildDeviceObject[i] == NULL)
1342 {
1343 continue;
1344 }
1345 Children++;
1346 }
1347
1348 NeededSize = sizeof(DEVICE_RELATIONS);
1349 if (Children > 1)
1350 NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
1351
1352 //
1353 // Allocate DeviceRelations
1354 //
1355 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool,
1356 NeededSize);
1357
1358 if (!DeviceRelations)
1359 return STATUS_INSUFFICIENT_RESOURCES;
1360 DeviceRelations->Count = Children;
1361 Children = 0;
1362
1363 //
1364 // Fill in return structure
1365 //
1366 for (i = 0; i < USB_MAXCHILDREN; i++)
1367 {
1368 if (HubDeviceExtension->ChildDeviceObject[i])
1369 {
1370 ObReferenceObject(HubDeviceExtension->ChildDeviceObject[i]);
1371 HubDeviceExtension->ChildDeviceObject[i]->Flags &= ~DO_DEVICE_INITIALIZING;
1372 DeviceRelations->Objects[Children++] = HubDeviceExtension->ChildDeviceObject[i];
1373 }
1374 }
1375
1376 ASSERT(Children == DeviceRelations->Count);
1377 *pDeviceRelations = DeviceRelations;
1378
1379 return STATUS_SUCCESS;
1380 }
1381
1382 VOID
1383 NTAPI
1384 RootHubInitCallbackFunction(
1385 PVOID Context)
1386 {
1387 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
1388 NTSTATUS Status;
1389 ULONG PortId;
1390 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1391 PORT_STATUS_CHANGE StatusChange;
1392
1393 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1394
1395 DPRINT("RootHubInitCallbackFunction Sending the initial SCE Request %x\n", DeviceObject);
1396
1397 //
1398 // Send the first SCE Request
1399 //
1400 QueryStatusChangeEndpoint(DeviceObject);
1401
1402 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1403 {
1404 //
1405 // get port status
1406 //
1407 Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
1408 if (NT_SUCCESS(Status))
1409 {
1410 //
1411 // is there a device connected
1412 //
1413 if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
1414 {
1415 //
1416 // reset port
1417 //
1418 Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
1419 if (!NT_SUCCESS(Status))
1420 {
1421 DPRINT1("Failed to reset on port %d\n", PortId);
1422 }
1423 else
1424 {
1425 //
1426 // wait for the reset to be handled since we want to enumerate synchronously
1427 //
1428 KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
1429 Executive,
1430 KernelMode,
1431 FALSE,
1432 NULL);
1433 KeClearEvent(&HubDeviceExtension->ResetComplete);
1434 }
1435 }
1436 }
1437 }
1438 }
1439
1440 BOOLEAN
1441 USBHUB_IsRootHubFDO(
1442 IN PDEVICE_OBJECT DeviceObject)
1443 {
1444 NTSTATUS Status;
1445 PDEVICE_OBJECT RootHubPhysicalDeviceObject = NULL;
1446 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1447
1448 // get hub device extension
1449 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1450
1451 // Get the Root Hub Pdo
1452 Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
1453 IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
1454 &RootHubPhysicalDeviceObject,
1455 NULL);
1456
1457 // FIXME handle error
1458 ASSERT(NT_SUCCESS(Status));
1459
1460 // physical device object is only obtained for root hubs
1461 return (RootHubPhysicalDeviceObject != NULL);
1462 }
1463
1464
1465 NTSTATUS
1466 USBHUB_FdoStartDevice(
1467 IN PDEVICE_OBJECT DeviceObject,
1468 IN PIRP Irp)
1469 {
1470 PURB Urb;
1471 PUSB_INTERFACE_DESCRIPTOR Pid;
1472 ULONG Result = 0, PortId;
1473 USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}};
1474 PURB ConfigUrb = NULL;
1475 ULONG HubStatus;
1476 PIO_STACK_LOCATION Stack;
1477 NTSTATUS Status = STATUS_SUCCESS;
1478 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1479 PDEVICE_OBJECT RootHubDeviceObject;
1480 PVOID HubInterfaceBusContext , UsbDInterfaceBusContext;
1481 PORT_STATUS_CHANGE StatusChange;
1482
1483 // get current stack location
1484 Stack = IoGetCurrentIrpStackLocation(Irp);
1485
1486 // get hub device extension
1487 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1488
1489 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
1490
1491 // Allocated size including the sizeof USBD_INTERFACE_LIST_ENTRY
1492 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY), USB_HUB_TAG);
1493 if (!Urb)
1494 {
1495 // no memory
1496 return STATUS_INSUFFICIENT_RESOURCES;
1497 }
1498
1499 // zero urb
1500 RtlZeroMemory(Urb, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY));
1501
1502 // Get the Root Hub Pdo
1503 Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
1504 IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
1505 &HubDeviceExtension->RootHubPhysicalDeviceObject,
1506 &HubDeviceExtension->RootHubFunctionalDeviceObject);
1507 if (!NT_SUCCESS(Status))
1508 {
1509 // failed to obtain hub pdo
1510 DPRINT1("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO failed with %x\n", Status);
1511 ExFreePool(Urb);
1512 return Status;
1513 }
1514
1515 // sanity checks
1516 ASSERT(HubDeviceExtension->RootHubPhysicalDeviceObject);
1517 ASSERT(HubDeviceExtension->RootHubFunctionalDeviceObject);
1518
1519 // get roothub
1520 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
1521
1522 // Send the StartDevice to RootHub
1523 Status = ForwardIrpAndWait(RootHubDeviceObject, Irp);
1524
1525 if (!NT_SUCCESS(Status))
1526 {
1527 // failed to start pdo
1528 DPRINT1("Failed to start the RootHub PDO\n");
1529 ExFreePool(Urb);
1530 return Status;
1531 }
1532
1533 // Get the current number of hubs
1534 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1535 IOCTL_INTERNAL_USB_GET_HUB_COUNT,
1536 &HubDeviceExtension->NumberOfHubs, NULL);
1537 if (!NT_SUCCESS(Status))
1538 {
1539 // failed to get number of hubs
1540 DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_COUNT failed with %x\n", Status);
1541 ExFreePool(Urb);
1542 return Status;
1543 }
1544
1545 // Get the Hub Interface
1546 Status = QueryInterface(RootHubDeviceObject,
1547 USB_BUS_INTERFACE_HUB_GUID,
1548 sizeof(USB_BUS_INTERFACE_HUB_V5),
1549 USB_BUSIF_HUB_VERSION_5,
1550 (PVOID)&HubDeviceExtension->HubInterface);
1551
1552 if (!NT_SUCCESS(Status))
1553 {
1554 // failed to get root hub interface
1555 DPRINT1("Failed to get HUB_GUID interface with status 0x%08lx\n", Status);
1556 ExFreePool(Urb);
1557 return Status;
1558 }
1559
1560 HubInterfaceBusContext = HubDeviceExtension->HubInterface.BusContext;
1561
1562 // Get the USBDI Interface
1563 Status = QueryInterface(RootHubDeviceObject,
1564 USB_BUS_INTERFACE_USBDI_GUID,
1565 sizeof(USB_BUS_INTERFACE_USBDI_V2),
1566 USB_BUSIF_USBDI_VERSION_2,
1567 (PVOID)&HubDeviceExtension->UsbDInterface);
1568
1569 if (!NT_SUCCESS(Status))
1570 {
1571 // failed to get usbdi interface
1572 DPRINT1("Failed to get USBDI_GUID interface with status 0x%08lx\n", Status);
1573 ExFreePool(Urb);
1574 return Status;
1575 }
1576
1577 UsbDInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
1578
1579 // Get Root Hub Device Handle
1580 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1581 IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
1582 &HubDeviceExtension->RootHubHandle,
1583 NULL);
1584
1585 if (!NT_SUCCESS(Status))
1586 {
1587 // failed
1588 DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE failed with status 0x%08lx\n", Status);
1589 ExFreePool(Urb);
1590 return Status;
1591 }
1592
1593 //
1594 // Get Hub Device Information
1595 //
1596 Status = HubDeviceExtension->HubInterface.QueryDeviceInformation(HubInterfaceBusContext,
1597 HubDeviceExtension->RootHubHandle,
1598 &HubDeviceExtension->DeviceInformation,
1599 sizeof(USB_DEVICE_INFORMATION_0),
1600 &Result);
1601
1602 DPRINT1("Status %x, Result 0x%08lx\n", Status, Result);
1603 DPRINT1("InformationLevel %x\n", HubDeviceExtension->DeviceInformation.InformationLevel);
1604 DPRINT1("ActualLength %x\n", HubDeviceExtension->DeviceInformation.ActualLength);
1605 DPRINT1("PortNumber %x\n", HubDeviceExtension->DeviceInformation.PortNumber);
1606 DPRINT1("DeviceDescriptor %x\n", HubDeviceExtension->DeviceInformation.DeviceDescriptor);
1607 DPRINT1("HubAddress %x\n", HubDeviceExtension->DeviceInformation.HubAddress);
1608 DPRINT1("NumberofPipes %x\n", HubDeviceExtension->DeviceInformation.NumberOfOpenPipes);
1609
1610 // Get Root Hubs Device Descriptor
1611 UsbBuildGetDescriptorRequest(Urb,
1612 sizeof(Urb->UrbControlDescriptorRequest),
1613 USB_DEVICE_DESCRIPTOR_TYPE,
1614 0,
1615 0,
1616 &HubDeviceExtension->HubDeviceDescriptor,
1617 NULL,
1618 sizeof(USB_DEVICE_DESCRIPTOR),
1619 NULL);
1620
1621 // set device handle
1622 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1623
1624 // get hub device descriptor
1625 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1626 IOCTL_INTERNAL_USB_SUBMIT_URB,
1627 Urb,
1628 NULL);
1629
1630 if (!NT_SUCCESS(Status))
1631 {
1632 // failed to get device descriptor of hub
1633 DPRINT1("Failed to get HubDeviceDescriptor!\n");
1634 ExFreePool(Urb);
1635 return Status;
1636 }
1637
1638 // build configuration request
1639 UsbBuildGetDescriptorRequest(Urb,
1640 sizeof(Urb->UrbControlDescriptorRequest),
1641 USB_CONFIGURATION_DESCRIPTOR_TYPE,
1642 0,
1643 0,
1644 &HubDeviceExtension->HubConfigDescriptor,
1645 NULL,
1646 sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR),
1647 NULL);
1648
1649 // set device handle
1650 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1651
1652 // request configuration descriptor
1653 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1654 IOCTL_INTERNAL_USB_SUBMIT_URB,
1655 Urb,
1656 NULL);
1657
1658 if (!NT_SUCCESS(Status))
1659 {
1660 // failed to get configuration descriptor
1661 DPRINT1("Failed to get RootHub Configuration with status %x\n", Status);
1662 ExFreePool(Urb);
1663 return Status;
1664 }
1665
1666 // sanity checks
1667 ASSERT(HubDeviceExtension->HubConfigDescriptor.wTotalLength == sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR));
1668 ASSERT(HubDeviceExtension->HubConfigDescriptor.bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE);
1669 ASSERT(HubDeviceExtension->HubConfigDescriptor.bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
1670 ASSERT(HubDeviceExtension->HubConfigDescriptor.bNumInterfaces == 1);
1671 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
1672 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
1673 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bNumEndpoints == 1);
1674 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
1675 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bLength == sizeof(USB_ENDPOINT_DESCRIPTOR));
1676 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bmAttributes == USB_ENDPOINT_TYPE_INTERRUPT);
1677 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bEndpointAddress == 0x81); // interrupt in
1678
1679 // get hub information
1680 Status = HubDeviceExtension->HubInterface.GetExtendedHubInformation(HubInterfaceBusContext,
1681 RootHubDeviceObject,
1682 &HubDeviceExtension->UsbExtHubInfo,
1683 sizeof(USB_EXTHUB_INFORMATION_0),
1684 &Result);
1685 if (!NT_SUCCESS(Status))
1686 {
1687 // failed to get hub information
1688 DPRINT1("Failed to extended hub information. Unable to determine the number of ports!\n");
1689 ExFreePool(Urb);
1690 return Status;
1691 }
1692
1693 if (!HubDeviceExtension->UsbExtHubInfo.NumberOfPorts)
1694 {
1695 // bogus port driver
1696 DPRINT1("Failed to retrieve the number of ports\n");
1697 ExFreePool(Urb);
1698 return STATUS_UNSUCCESSFUL;
1699 }
1700
1701 DPRINT1("HubDeviceExtension->UsbExtHubInfo.NumberOfPorts %x\n", HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
1702
1703 // Build hub descriptor request
1704 UsbBuildVendorRequest(Urb,
1705 URB_FUNCTION_CLASS_DEVICE,
1706 sizeof(Urb->UrbControlVendorClassRequest),
1707 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
1708 0,
1709 USB_REQUEST_GET_DESCRIPTOR,
1710 USB_DEVICE_CLASS_RESERVED,
1711 0,
1712 &HubDeviceExtension->HubDescriptor,
1713 NULL,
1714 sizeof(USB_HUB_DESCRIPTOR),
1715 NULL);
1716
1717 // set device handle
1718 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1719
1720 // send request
1721 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1722 IOCTL_INTERNAL_USB_SUBMIT_URB,
1723 Urb,
1724 NULL);
1725
1726 if (!NT_SUCCESS(Status))
1727 {
1728 DPRINT1("Failed to get Hub Descriptor!\n");
1729 ExFreePool(Urb);
1730 return STATUS_UNSUCCESSFUL;
1731 }
1732
1733 // sanity checks
1734 ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorLength == sizeof(USB_HUB_DESCRIPTOR));
1735 ASSERT(HubDeviceExtension->HubDescriptor.bNumberOfPorts == HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
1736 ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorType == 0x29);
1737
1738 // build get status request
1739 HubStatus = 0;
1740 UsbBuildGetStatusRequest(Urb,
1741 URB_FUNCTION_GET_STATUS_FROM_DEVICE,
1742 0,
1743 &HubStatus,
1744 0,
1745 NULL);
1746 // set device handle
1747 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1748
1749 // send request
1750 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1751 IOCTL_INTERNAL_USB_SUBMIT_URB,
1752 Urb,
1753 NULL);
1754 if (!NT_SUCCESS(Status))
1755 {
1756 // failed to get hub status
1757 DPRINT1("Failed to get Hub Status!\n");
1758 ExFreePool(Urb);
1759 return STATUS_UNSUCCESSFUL;
1760 }
1761
1762 // Allocate memory for PortStatusChange to hold 2 USHORTs for each port on hub
1763 HubDeviceExtension->PortStatusChange = ExAllocatePoolWithTag(NonPagedPool,
1764 sizeof(ULONG) * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
1765 USB_HUB_TAG);
1766
1767 // Get the first Configuration Descriptor
1768 Pid = USBD_ParseConfigurationDescriptorEx(&HubDeviceExtension->HubConfigDescriptor,
1769 &HubDeviceExtension->HubConfigDescriptor,
1770 -1, -1, -1, -1, -1);
1771 if (Pid == NULL)
1772 {
1773 // failed parse hub descriptor
1774 DPRINT1("Failed to parse configuration descriptor\n");
1775 ExFreePool(Urb);
1776 return STATUS_UNSUCCESSFUL;
1777 }
1778
1779 // create configuration request
1780 InterfaceList[0].InterfaceDescriptor = Pid;
1781 ConfigUrb = USBD_CreateConfigurationRequestEx(&HubDeviceExtension->HubConfigDescriptor,
1782 (PUSBD_INTERFACE_LIST_ENTRY)&InterfaceList);
1783 if (ConfigUrb == NULL)
1784 {
1785 // failed to build urb
1786 DPRINT1("Failed to allocate urb\n");
1787 ExFreePool(Urb);
1788 return STATUS_INSUFFICIENT_RESOURCES;
1789 }
1790
1791 // send request
1792 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1793 IOCTL_INTERNAL_USB_SUBMIT_URB,
1794 ConfigUrb,
1795 NULL);
1796 if (!NT_SUCCESS(Status))
1797 {
1798 // failed to select configuration
1799 DPRINT1("Failed to select configuration with %x\n", Status);
1800 ExFreePool(Urb);
1801 ExFreePool(ConfigUrb);
1802 return Status;
1803 }
1804
1805 // store configuration & pipe handle
1806 HubDeviceExtension->ConfigurationHandle = ConfigUrb->UrbSelectConfiguration.ConfigurationHandle;
1807 HubDeviceExtension->PipeHandle = ConfigUrb->UrbSelectConfiguration.Interface.Pipes[0].PipeHandle;
1808 DPRINT("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
1809
1810 // free urb
1811 ExFreePool(ConfigUrb);
1812
1813 // check if function is available
1814 if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed)
1815 {
1816 // is it high speed bus
1817 if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed(HubInterfaceBusContext))
1818 {
1819 // initialize usb 2.0 hub
1820 Status = HubDeviceExtension->HubInterface.Initialize20Hub(HubInterfaceBusContext,
1821 HubDeviceExtension->RootHubHandle, 1);
1822 DPRINT("Status %x\n", Status);
1823
1824 // FIXME handle error
1825 ASSERT(Status == STATUS_SUCCESS);
1826 }
1827 }
1828
1829
1830 // Enable power on all ports
1831 DPRINT("Enabling PortPower on all ports!\n");
1832 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1833 {
1834 Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_POWER);
1835 if (!NT_SUCCESS(Status))
1836 DPRINT1("Failed to power on port %d\n", PortId);
1837
1838 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
1839 if (!NT_SUCCESS(Status))
1840 DPRINT1("Failed to power on port %d\n", PortId);
1841 }
1842
1843 // init root hub notification
1844 if (HubDeviceExtension->HubInterface.RootHubInitNotification)
1845 {
1846 Status = HubDeviceExtension->HubInterface.RootHubInitNotification(HubInterfaceBusContext,
1847 DeviceObject,
1848 RootHubInitCallbackFunction);
1849 if (!NT_SUCCESS(Status))
1850 {
1851 DPRINT1("Failed to set callback\n");
1852 ExFreePool(Urb);
1853 return Status;
1854 }
1855 }
1856 else
1857 {
1858 // Send the first SCE Request
1859 QueryStatusChangeEndpoint(DeviceObject);
1860
1861 //
1862 // reset ports
1863 //
1864 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1865 {
1866 //
1867 // get port status
1868 //
1869 Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
1870 if (NT_SUCCESS(Status))
1871 {
1872 //
1873 // is there a device connected
1874 //
1875 if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
1876 {
1877 //
1878 // reset port
1879 //
1880 Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
1881 if (!NT_SUCCESS(Status))
1882 {
1883 DPRINT1("Failed to reset on port %d\n", PortId);
1884 }
1885 else
1886 {
1887 //
1888 // wait for the reset to be handled since we want to enumerate synchronously
1889 //
1890 KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
1891 Executive,
1892 KernelMode,
1893 FALSE,
1894 NULL);
1895 KeClearEvent(&HubDeviceExtension->ResetComplete);
1896 }
1897 }
1898 }
1899 }
1900 }
1901
1902 // free urb
1903 ExFreePool(Urb);
1904
1905 // done
1906 return Status;
1907 }
1908
1909 NTSTATUS
1910 USBHUB_FdoHandlePnp(
1911 IN PDEVICE_OBJECT DeviceObject,
1912 IN PIRP Irp)
1913 {
1914 PIO_STACK_LOCATION Stack;
1915 NTSTATUS Status = STATUS_SUCCESS;
1916 ULONG_PTR Information = 0;
1917 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1918
1919 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1920
1921 Stack = IoGetCurrentIrpStackLocation(Irp);
1922
1923 switch (Stack->MinorFunction)
1924 {
1925 case IRP_MN_START_DEVICE:
1926 {
1927 if (USBHUB_IsRootHubFDO(DeviceObject))
1928 {
1929 // start root hub fdo
1930 Status = USBHUB_FdoStartDevice(DeviceObject, Irp);
1931 }
1932 else
1933 {
1934 Status = USBHUB_ParentFDOStartDevice(DeviceObject, Irp);
1935 }
1936 break;
1937 }
1938
1939 case IRP_MN_QUERY_DEVICE_RELATIONS:
1940 {
1941 switch (Stack->Parameters.QueryDeviceRelations.Type)
1942 {
1943 case BusRelations:
1944 {
1945 PDEVICE_RELATIONS DeviceRelations = NULL;
1946 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
1947
1948 Status = USBHUB_FdoQueryBusRelations(DeviceObject, &DeviceRelations);
1949
1950 Information = (ULONG_PTR)DeviceRelations;
1951 break;
1952 }
1953 case RemovalRelations:
1954 {
1955 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
1956 return ForwardIrpAndForget(DeviceObject, Irp);
1957 }
1958 default:
1959 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
1960 Stack->Parameters.QueryDeviceRelations.Type);
1961 return ForwardIrpAndForget(DeviceObject, Irp);
1962 }
1963 break;
1964 }
1965 case IRP_MN_QUERY_REMOVE_DEVICE:
1966 case IRP_MN_QUERY_STOP_DEVICE:
1967 {
1968 Irp->IoStatus.Status = STATUS_SUCCESS;
1969 return ForwardIrpAndForget(DeviceObject, Irp);
1970 }
1971 case IRP_MN_REMOVE_DEVICE:
1972 {
1973 Irp->IoStatus.Status = STATUS_SUCCESS;
1974 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1975
1976 IoDetachDevice(HubDeviceExtension->LowerDeviceObject);
1977 IoDeleteDevice(DeviceObject);
1978
1979 return STATUS_SUCCESS;
1980 }
1981 case IRP_MN_QUERY_BUS_INFORMATION:
1982 {
1983 DPRINT("IRP_MN_QUERY_BUS_INFORMATION\n");
1984 break;
1985 }
1986 case IRP_MN_QUERY_ID:
1987 {
1988 DPRINT("IRP_MN_QUERY_ID\n");
1989 break;
1990 }
1991 case IRP_MN_QUERY_CAPABILITIES:
1992 {
1993 DPRINT("IRP_MN_QUERY_CAPABILITIES\n");
1994 break;
1995 }
1996 default:
1997 {
1998 DPRINT(" IRP_MJ_PNP / unknown minor function 0x%lx\n", Stack->MinorFunction);
1999 return ForwardIrpAndForget(DeviceObject, Irp);
2000 }
2001 }
2002
2003 Irp->IoStatus.Information = Information;
2004 Irp->IoStatus.Status = Status;
2005 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2006 return Status;
2007 }
2008
2009 NTSTATUS
2010 USBHUB_FdoHandleDeviceControl(
2011 IN PDEVICE_OBJECT DeviceObject,
2012 IN PIRP Irp)
2013 {
2014 DPRINT1("FdoHandleDeviceControl\n");
2015 UNIMPLEMENTED
2016 return STATUS_NOT_IMPLEMENTED;
2017 }
2018