ec56674fc09d5fdee2204be14f3adbfbcede0783
[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 // copy device interface
1202 RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
1203
1204
1205 //
1206 // Create the UsbDeviceObject
1207 //
1208 Status = HubInterface->CreateUsbDevice(HubInterfaceBusContext,
1209 (PVOID)&UsbChildExtension->UsbDeviceHandle,
1210 HubDeviceExtension->RootHubHandle,
1211 PortStatus,
1212 PortId);
1213 if (!NT_SUCCESS(Status))
1214 {
1215 DPRINT1("USBHUB: CreateUsbDevice failed with status %x\n", Status);
1216 goto Cleanup;
1217 }
1218
1219 // copy device interface
1220 RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
1221
1222 // FIXME replace buscontext
1223 UsbChildExtension->DeviceInterface.BusContext = UsbChildExtension->UsbDeviceHandle;
1224
1225 //
1226 // Initialize UsbDevice
1227 //
1228 Status = HubInterface->InitializeUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle);
1229 if (!NT_SUCCESS(Status))
1230 {
1231 DPRINT1("USBHUB: InitializeUsbDevice failed with status %x\n", Status);
1232 goto Cleanup;
1233 }
1234
1235 DPRINT("Usb Device Handle %x\n", UsbChildExtension->UsbDeviceHandle);
1236
1237 ConfigDescSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
1238 DeviceDescSize = sizeof(USB_DEVICE_DESCRIPTOR);
1239
1240 //
1241 // Get the descriptors
1242 //
1243 Status = HubInterface->GetUsbDescriptors(HubInterfaceBusContext,
1244 UsbChildExtension->UsbDeviceHandle,
1245 (PUCHAR)&UsbChildExtension->DeviceDesc,
1246 &DeviceDescSize,
1247 (PUCHAR)&ConfigDesc,
1248 &ConfigDescSize);
1249 if (!NT_SUCCESS(Status))
1250 {
1251 DPRINT1("USBHUB: GetUsbDescriptors failed with status %x\n", Status);
1252 goto Cleanup;
1253 }
1254
1255 DumpDeviceDescriptor(&UsbChildExtension->DeviceDesc);
1256 DumpConfigurationDescriptor(&ConfigDesc);
1257
1258 //
1259 // FIXME: Support more than one configuration and one interface?
1260 //
1261 if (UsbChildExtension->DeviceDesc.bNumConfigurations > 1)
1262 {
1263 DPRINT1("Warning: Device has more than one configuration. Only one configuration (the first) is supported!\n");
1264 }
1265
1266 if (ConfigDesc.bNumInterfaces > 1)
1267 {
1268 DPRINT1("Warning: Device has more that one interface. Only one interface (the first) is currently supported\n");
1269 }
1270
1271 ConfigDescSize = ConfigDesc.wTotalLength;
1272
1273 //
1274 // Allocate memory for the first full descriptor, including interfaces and endpoints.
1275 //
1276 UsbChildExtension->FullConfigDesc = ExAllocatePoolWithTag(PagedPool, ConfigDescSize, USB_HUB_TAG);
1277
1278 //
1279 // Retrieve the full configuration descriptor
1280 //
1281 Status = GetUsbDeviceDescriptor(NewChildDeviceObject,
1282 USB_CONFIGURATION_DESCRIPTOR_TYPE,
1283 0,
1284 0,
1285 UsbChildExtension->FullConfigDesc,
1286 ConfigDescSize);
1287
1288 if (!NT_SUCCESS(Status))
1289 {
1290 DPRINT1("USBHUB: GetUsbDeviceDescriptor failed with status %x\n", Status);
1291 goto Cleanup;
1292 }
1293
1294 //DumpFullConfigurationDescriptor(UsbChildExtension->FullConfigDesc);
1295
1296 //
1297 // Construct all the strings that will described the device to PNP
1298 //
1299 Status = CreateDeviceIds(NewChildDeviceObject);
1300 if (!NT_SUCCESS(Status))
1301 {
1302 DPRINT1("Failed to create strings needed to describe device to PNP.\n");
1303 goto Cleanup;
1304 }
1305
1306 HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] = NewChildDeviceObject;
1307
1308 IoInvalidateDeviceRelations(RootHubDeviceObject, BusRelations);
1309 return STATUS_SUCCESS;
1310
1311 Cleanup:
1312
1313 //
1314 // Remove the usb device if it was created
1315 //
1316 if (UsbChildExtension->UsbDeviceHandle)
1317 HubInterface->RemoveUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle, 0);
1318
1319 //
1320 // Free full configuration descriptor if one was allocated
1321 //
1322 if (UsbChildExtension->FullConfigDesc)
1323 ExFreePool(UsbChildExtension->FullConfigDesc);
1324
1325 //
1326 // Delete the device object
1327 //
1328 IoDeleteDevice(NewChildDeviceObject);
1329 return Status;
1330 }
1331
1332 NTSTATUS
1333 USBHUB_FdoQueryBusRelations(
1334 IN PDEVICE_OBJECT DeviceObject,
1335 OUT PDEVICE_RELATIONS* pDeviceRelations)
1336 {
1337 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1338 PDEVICE_RELATIONS DeviceRelations;
1339 ULONG i;
1340 ULONG Children = 0;
1341 ULONG NeededSize;
1342
1343 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1344
1345 //
1346 // Count the number of children
1347 //
1348 for (i = 0; i < USB_MAXCHILDREN; i++)
1349 {
1350
1351 if (HubDeviceExtension->ChildDeviceObject[i] == NULL)
1352 {
1353 continue;
1354 }
1355 Children++;
1356 }
1357
1358 NeededSize = sizeof(DEVICE_RELATIONS);
1359 if (Children > 1)
1360 NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
1361
1362 //
1363 // Allocate DeviceRelations
1364 //
1365 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool,
1366 NeededSize);
1367
1368 if (!DeviceRelations)
1369 return STATUS_INSUFFICIENT_RESOURCES;
1370 DeviceRelations->Count = Children;
1371 Children = 0;
1372
1373 //
1374 // Fill in return structure
1375 //
1376 for (i = 0; i < USB_MAXCHILDREN; i++)
1377 {
1378 if (HubDeviceExtension->ChildDeviceObject[i])
1379 {
1380 ObReferenceObject(HubDeviceExtension->ChildDeviceObject[i]);
1381 HubDeviceExtension->ChildDeviceObject[i]->Flags &= ~DO_DEVICE_INITIALIZING;
1382 DeviceRelations->Objects[Children++] = HubDeviceExtension->ChildDeviceObject[i];
1383 }
1384 }
1385
1386 ASSERT(Children == DeviceRelations->Count);
1387 *pDeviceRelations = DeviceRelations;
1388
1389 return STATUS_SUCCESS;
1390 }
1391
1392 VOID
1393 NTAPI
1394 RootHubInitCallbackFunction(
1395 PVOID Context)
1396 {
1397 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
1398 NTSTATUS Status;
1399 ULONG PortId;
1400 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1401 PORT_STATUS_CHANGE StatusChange;
1402
1403 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1404
1405 DPRINT("RootHubInitCallbackFunction Sending the initial SCE Request %x\n", DeviceObject);
1406
1407 //
1408 // Send the first SCE Request
1409 //
1410 QueryStatusChangeEndpoint(DeviceObject);
1411
1412 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1413 {
1414 //
1415 // get port status
1416 //
1417 Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
1418 if (NT_SUCCESS(Status))
1419 {
1420 //
1421 // is there a device connected
1422 //
1423 if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
1424 {
1425 //
1426 // reset port
1427 //
1428 Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
1429 if (!NT_SUCCESS(Status))
1430 {
1431 DPRINT1("Failed to reset on port %d\n", PortId);
1432 }
1433 else
1434 {
1435 //
1436 // wait for the reset to be handled since we want to enumerate synchronously
1437 //
1438 KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
1439 Executive,
1440 KernelMode,
1441 FALSE,
1442 NULL);
1443 KeClearEvent(&HubDeviceExtension->ResetComplete);
1444 }
1445 }
1446 }
1447 }
1448 }
1449
1450 BOOLEAN
1451 USBHUB_IsRootHubFDO(
1452 IN PDEVICE_OBJECT DeviceObject)
1453 {
1454 NTSTATUS Status;
1455 PDEVICE_OBJECT RootHubPhysicalDeviceObject = NULL;
1456 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1457
1458 // get hub device extension
1459 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1460
1461 // Get the Root Hub Pdo
1462 Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
1463 IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
1464 &RootHubPhysicalDeviceObject,
1465 NULL);
1466
1467 // FIXME handle error
1468 ASSERT(NT_SUCCESS(Status));
1469
1470 // physical device object is only obtained for root hubs
1471 return (RootHubPhysicalDeviceObject != NULL);
1472 }
1473
1474
1475 NTSTATUS
1476 USBHUB_FdoStartDevice(
1477 IN PDEVICE_OBJECT DeviceObject,
1478 IN PIRP Irp)
1479 {
1480 PURB Urb;
1481 PUSB_INTERFACE_DESCRIPTOR Pid;
1482 ULONG Result = 0, PortId;
1483 USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}};
1484 PURB ConfigUrb = NULL;
1485 ULONG HubStatus;
1486 PIO_STACK_LOCATION Stack;
1487 NTSTATUS Status = STATUS_SUCCESS;
1488 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1489 PDEVICE_OBJECT RootHubDeviceObject;
1490 PVOID HubInterfaceBusContext , UsbDInterfaceBusContext;
1491 PORT_STATUS_CHANGE StatusChange;
1492
1493 // get current stack location
1494 Stack = IoGetCurrentIrpStackLocation(Irp);
1495
1496 // get hub device extension
1497 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1498
1499 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
1500
1501 // Allocated size including the sizeof USBD_INTERFACE_LIST_ENTRY
1502 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY), USB_HUB_TAG);
1503 if (!Urb)
1504 {
1505 // no memory
1506 return STATUS_INSUFFICIENT_RESOURCES;
1507 }
1508
1509 // zero urb
1510 RtlZeroMemory(Urb, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY));
1511
1512 // Get the Root Hub Pdo
1513 Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
1514 IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
1515 &HubDeviceExtension->RootHubPhysicalDeviceObject,
1516 &HubDeviceExtension->RootHubFunctionalDeviceObject);
1517 if (!NT_SUCCESS(Status))
1518 {
1519 // failed to obtain hub pdo
1520 DPRINT1("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO failed with %x\n", Status);
1521 ExFreePool(Urb);
1522 return Status;
1523 }
1524
1525 // sanity checks
1526 ASSERT(HubDeviceExtension->RootHubPhysicalDeviceObject);
1527 ASSERT(HubDeviceExtension->RootHubFunctionalDeviceObject);
1528
1529 // get roothub
1530 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
1531
1532 // Send the StartDevice to RootHub
1533 Status = ForwardIrpAndWait(RootHubDeviceObject, Irp);
1534
1535 if (!NT_SUCCESS(Status))
1536 {
1537 // failed to start pdo
1538 DPRINT1("Failed to start the RootHub PDO\n");
1539 ExFreePool(Urb);
1540 return Status;
1541 }
1542
1543 // Get the current number of hubs
1544 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1545 IOCTL_INTERNAL_USB_GET_HUB_COUNT,
1546 &HubDeviceExtension->NumberOfHubs, NULL);
1547 if (!NT_SUCCESS(Status))
1548 {
1549 // failed to get number of hubs
1550 DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_COUNT failed with %x\n", Status);
1551 ExFreePool(Urb);
1552 return Status;
1553 }
1554
1555 // Get the Hub Interface
1556 Status = QueryInterface(RootHubDeviceObject,
1557 USB_BUS_INTERFACE_HUB_GUID,
1558 sizeof(USB_BUS_INTERFACE_HUB_V5),
1559 USB_BUSIF_HUB_VERSION_5,
1560 (PVOID)&HubDeviceExtension->HubInterface);
1561
1562 if (!NT_SUCCESS(Status))
1563 {
1564 // failed to get root hub interface
1565 DPRINT1("Failed to get HUB_GUID interface with status 0x%08lx\n", Status);
1566 ExFreePool(Urb);
1567 return Status;
1568 }
1569
1570 HubInterfaceBusContext = HubDeviceExtension->HubInterface.BusContext;
1571
1572 // Get the USBDI Interface
1573 Status = QueryInterface(RootHubDeviceObject,
1574 USB_BUS_INTERFACE_USBDI_GUID,
1575 sizeof(USB_BUS_INTERFACE_USBDI_V2),
1576 USB_BUSIF_USBDI_VERSION_2,
1577 (PVOID)&HubDeviceExtension->UsbDInterface);
1578
1579 if (!NT_SUCCESS(Status))
1580 {
1581 // failed to get usbdi interface
1582 DPRINT1("Failed to get USBDI_GUID interface with status 0x%08lx\n", Status);
1583 ExFreePool(Urb);
1584 return Status;
1585 }
1586
1587 UsbDInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
1588
1589 // Get Root Hub Device Handle
1590 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1591 IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
1592 &HubDeviceExtension->RootHubHandle,
1593 NULL);
1594
1595 if (!NT_SUCCESS(Status))
1596 {
1597 // failed
1598 DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE failed with status 0x%08lx\n", Status);
1599 ExFreePool(Urb);
1600 return Status;
1601 }
1602
1603 //
1604 // Get Hub Device Information
1605 //
1606 Status = HubDeviceExtension->HubInterface.QueryDeviceInformation(HubInterfaceBusContext,
1607 HubDeviceExtension->RootHubHandle,
1608 &HubDeviceExtension->DeviceInformation,
1609 sizeof(USB_DEVICE_INFORMATION_0),
1610 &Result);
1611
1612 DPRINT1("Status %x, Result 0x%08lx\n", Status, Result);
1613 DPRINT1("InformationLevel %x\n", HubDeviceExtension->DeviceInformation.InformationLevel);
1614 DPRINT1("ActualLength %x\n", HubDeviceExtension->DeviceInformation.ActualLength);
1615 DPRINT1("PortNumber %x\n", HubDeviceExtension->DeviceInformation.PortNumber);
1616 DPRINT1("DeviceDescriptor %x\n", HubDeviceExtension->DeviceInformation.DeviceDescriptor);
1617 DPRINT1("HubAddress %x\n", HubDeviceExtension->DeviceInformation.HubAddress);
1618 DPRINT1("NumberofPipes %x\n", HubDeviceExtension->DeviceInformation.NumberOfOpenPipes);
1619
1620 // Get Root Hubs Device Descriptor
1621 UsbBuildGetDescriptorRequest(Urb,
1622 sizeof(Urb->UrbControlDescriptorRequest),
1623 USB_DEVICE_DESCRIPTOR_TYPE,
1624 0,
1625 0,
1626 &HubDeviceExtension->HubDeviceDescriptor,
1627 NULL,
1628 sizeof(USB_DEVICE_DESCRIPTOR),
1629 NULL);
1630
1631 // set device handle
1632 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1633
1634 // get hub device descriptor
1635 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1636 IOCTL_INTERNAL_USB_SUBMIT_URB,
1637 Urb,
1638 NULL);
1639
1640 if (!NT_SUCCESS(Status))
1641 {
1642 // failed to get device descriptor of hub
1643 DPRINT1("Failed to get HubDeviceDescriptor!\n");
1644 ExFreePool(Urb);
1645 return Status;
1646 }
1647
1648 // build configuration request
1649 UsbBuildGetDescriptorRequest(Urb,
1650 sizeof(Urb->UrbControlDescriptorRequest),
1651 USB_CONFIGURATION_DESCRIPTOR_TYPE,
1652 0,
1653 0,
1654 &HubDeviceExtension->HubConfigDescriptor,
1655 NULL,
1656 sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR),
1657 NULL);
1658
1659 // set device handle
1660 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1661
1662 // request configuration descriptor
1663 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1664 IOCTL_INTERNAL_USB_SUBMIT_URB,
1665 Urb,
1666 NULL);
1667
1668 if (!NT_SUCCESS(Status))
1669 {
1670 // failed to get configuration descriptor
1671 DPRINT1("Failed to get RootHub Configuration with status %x\n", Status);
1672 ExFreePool(Urb);
1673 return Status;
1674 }
1675
1676 // sanity checks
1677 ASSERT(HubDeviceExtension->HubConfigDescriptor.wTotalLength == sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR));
1678 ASSERT(HubDeviceExtension->HubConfigDescriptor.bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE);
1679 ASSERT(HubDeviceExtension->HubConfigDescriptor.bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
1680 ASSERT(HubDeviceExtension->HubConfigDescriptor.bNumInterfaces == 1);
1681 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
1682 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
1683 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bNumEndpoints == 1);
1684 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
1685 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bLength == sizeof(USB_ENDPOINT_DESCRIPTOR));
1686 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bmAttributes == USB_ENDPOINT_TYPE_INTERRUPT);
1687 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bEndpointAddress == 0x81); // interrupt in
1688
1689 // get hub information
1690 Status = HubDeviceExtension->HubInterface.GetExtendedHubInformation(HubInterfaceBusContext,
1691 RootHubDeviceObject,
1692 &HubDeviceExtension->UsbExtHubInfo,
1693 sizeof(USB_EXTHUB_INFORMATION_0),
1694 &Result);
1695 if (!NT_SUCCESS(Status))
1696 {
1697 // failed to get hub information
1698 DPRINT1("Failed to extended hub information. Unable to determine the number of ports!\n");
1699 ExFreePool(Urb);
1700 return Status;
1701 }
1702
1703 if (!HubDeviceExtension->UsbExtHubInfo.NumberOfPorts)
1704 {
1705 // bogus port driver
1706 DPRINT1("Failed to retrieve the number of ports\n");
1707 ExFreePool(Urb);
1708 return STATUS_UNSUCCESSFUL;
1709 }
1710
1711 DPRINT1("HubDeviceExtension->UsbExtHubInfo.NumberOfPorts %x\n", HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
1712
1713 // Build hub descriptor request
1714 UsbBuildVendorRequest(Urb,
1715 URB_FUNCTION_CLASS_DEVICE,
1716 sizeof(Urb->UrbControlVendorClassRequest),
1717 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
1718 0,
1719 USB_REQUEST_GET_DESCRIPTOR,
1720 USB_DEVICE_CLASS_RESERVED,
1721 0,
1722 &HubDeviceExtension->HubDescriptor,
1723 NULL,
1724 sizeof(USB_HUB_DESCRIPTOR),
1725 NULL);
1726
1727 // set device handle
1728 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1729
1730 // send request
1731 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1732 IOCTL_INTERNAL_USB_SUBMIT_URB,
1733 Urb,
1734 NULL);
1735
1736 if (!NT_SUCCESS(Status))
1737 {
1738 DPRINT1("Failed to get Hub Descriptor!\n");
1739 ExFreePool(Urb);
1740 return STATUS_UNSUCCESSFUL;
1741 }
1742
1743 // sanity checks
1744 ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorLength == sizeof(USB_HUB_DESCRIPTOR));
1745 ASSERT(HubDeviceExtension->HubDescriptor.bNumberOfPorts == HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
1746 ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorType == 0x29);
1747
1748 // build get status request
1749 HubStatus = 0;
1750 UsbBuildGetStatusRequest(Urb,
1751 URB_FUNCTION_GET_STATUS_FROM_DEVICE,
1752 0,
1753 &HubStatus,
1754 0,
1755 NULL);
1756 // set device handle
1757 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1758
1759 // send request
1760 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1761 IOCTL_INTERNAL_USB_SUBMIT_URB,
1762 Urb,
1763 NULL);
1764 if (!NT_SUCCESS(Status))
1765 {
1766 // failed to get hub status
1767 DPRINT1("Failed to get Hub Status!\n");
1768 ExFreePool(Urb);
1769 return STATUS_UNSUCCESSFUL;
1770 }
1771
1772 // Allocate memory for PortStatusChange to hold 2 USHORTs for each port on hub
1773 HubDeviceExtension->PortStatusChange = ExAllocatePoolWithTag(NonPagedPool,
1774 sizeof(ULONG) * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
1775 USB_HUB_TAG);
1776
1777 // Get the first Configuration Descriptor
1778 Pid = USBD_ParseConfigurationDescriptorEx(&HubDeviceExtension->HubConfigDescriptor,
1779 &HubDeviceExtension->HubConfigDescriptor,
1780 -1, -1, -1, -1, -1);
1781 if (Pid == NULL)
1782 {
1783 // failed parse hub descriptor
1784 DPRINT1("Failed to parse configuration descriptor\n");
1785 ExFreePool(Urb);
1786 return STATUS_UNSUCCESSFUL;
1787 }
1788
1789 // create configuration request
1790 InterfaceList[0].InterfaceDescriptor = Pid;
1791 ConfigUrb = USBD_CreateConfigurationRequestEx(&HubDeviceExtension->HubConfigDescriptor,
1792 (PUSBD_INTERFACE_LIST_ENTRY)&InterfaceList);
1793 if (ConfigUrb == NULL)
1794 {
1795 // failed to build urb
1796 DPRINT1("Failed to allocate urb\n");
1797 ExFreePool(Urb);
1798 return STATUS_INSUFFICIENT_RESOURCES;
1799 }
1800
1801 // send request
1802 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1803 IOCTL_INTERNAL_USB_SUBMIT_URB,
1804 ConfigUrb,
1805 NULL);
1806 if (!NT_SUCCESS(Status))
1807 {
1808 // failed to select configuration
1809 DPRINT1("Failed to select configuration with %x\n", Status);
1810 ExFreePool(Urb);
1811 ExFreePool(ConfigUrb);
1812 return Status;
1813 }
1814
1815 // store configuration & pipe handle
1816 HubDeviceExtension->ConfigurationHandle = ConfigUrb->UrbSelectConfiguration.ConfigurationHandle;
1817 HubDeviceExtension->PipeHandle = ConfigUrb->UrbSelectConfiguration.Interface.Pipes[0].PipeHandle;
1818 DPRINT("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
1819
1820 FDO_QueryInterface(DeviceObject, &HubDeviceExtension->DeviceInterface);
1821
1822
1823 // free urb
1824 ExFreePool(ConfigUrb);
1825
1826 // check if function is available
1827 if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed)
1828 {
1829 // is it high speed bus
1830 if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed(HubInterfaceBusContext))
1831 {
1832 // initialize usb 2.0 hub
1833 Status = HubDeviceExtension->HubInterface.Initialize20Hub(HubInterfaceBusContext,
1834 HubDeviceExtension->RootHubHandle, 1);
1835 DPRINT("Status %x\n", Status);
1836
1837 // FIXME handle error
1838 ASSERT(Status == STATUS_SUCCESS);
1839 }
1840 }
1841
1842
1843 // Enable power on all ports
1844 DPRINT("Enabling PortPower on all ports!\n");
1845 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1846 {
1847 Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_POWER);
1848 if (!NT_SUCCESS(Status))
1849 DPRINT1("Failed to power on port %d\n", PortId);
1850
1851 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
1852 if (!NT_SUCCESS(Status))
1853 DPRINT1("Failed to power on port %d\n", PortId);
1854 }
1855
1856 // init root hub notification
1857 if (HubDeviceExtension->HubInterface.RootHubInitNotification)
1858 {
1859 Status = HubDeviceExtension->HubInterface.RootHubInitNotification(HubInterfaceBusContext,
1860 DeviceObject,
1861 RootHubInitCallbackFunction);
1862 if (!NT_SUCCESS(Status))
1863 {
1864 DPRINT1("Failed to set callback\n");
1865 ExFreePool(Urb);
1866 return Status;
1867 }
1868 }
1869 else
1870 {
1871 // Send the first SCE Request
1872 QueryStatusChangeEndpoint(DeviceObject);
1873
1874 //
1875 // reset ports
1876 //
1877 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1878 {
1879 //
1880 // get port status
1881 //
1882 Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
1883 if (NT_SUCCESS(Status))
1884 {
1885 //
1886 // is there a device connected
1887 //
1888 if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
1889 {
1890 //
1891 // reset port
1892 //
1893 Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
1894 if (!NT_SUCCESS(Status))
1895 {
1896 DPRINT1("Failed to reset on port %d\n", PortId);
1897 }
1898 else
1899 {
1900 //
1901 // wait for the reset to be handled since we want to enumerate synchronously
1902 //
1903 KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
1904 Executive,
1905 KernelMode,
1906 FALSE,
1907 NULL);
1908 KeClearEvent(&HubDeviceExtension->ResetComplete);
1909 }
1910 }
1911 }
1912 }
1913 }
1914
1915 // free urb
1916 ExFreePool(Urb);
1917
1918 // done
1919 return Status;
1920 }
1921
1922 NTSTATUS
1923 USBHUB_FdoHandlePnp(
1924 IN PDEVICE_OBJECT DeviceObject,
1925 IN PIRP Irp)
1926 {
1927 PIO_STACK_LOCATION Stack;
1928 NTSTATUS Status = STATUS_SUCCESS;
1929 ULONG_PTR Information = 0;
1930 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1931
1932 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1933
1934 Stack = IoGetCurrentIrpStackLocation(Irp);
1935
1936 switch (Stack->MinorFunction)
1937 {
1938 case IRP_MN_START_DEVICE:
1939 {
1940 if (USBHUB_IsRootHubFDO(DeviceObject))
1941 {
1942 // start root hub fdo
1943 Status = USBHUB_FdoStartDevice(DeviceObject, Irp);
1944 }
1945 else
1946 {
1947 Status = USBHUB_ParentFDOStartDevice(DeviceObject, Irp);
1948 }
1949 break;
1950 }
1951
1952 case IRP_MN_QUERY_DEVICE_RELATIONS:
1953 {
1954 switch (Stack->Parameters.QueryDeviceRelations.Type)
1955 {
1956 case BusRelations:
1957 {
1958 PDEVICE_RELATIONS DeviceRelations = NULL;
1959 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
1960
1961 Status = USBHUB_FdoQueryBusRelations(DeviceObject, &DeviceRelations);
1962
1963 Information = (ULONG_PTR)DeviceRelations;
1964 break;
1965 }
1966 case RemovalRelations:
1967 {
1968 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
1969 return ForwardIrpAndForget(DeviceObject, Irp);
1970 }
1971 default:
1972 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
1973 Stack->Parameters.QueryDeviceRelations.Type);
1974 return ForwardIrpAndForget(DeviceObject, Irp);
1975 }
1976 break;
1977 }
1978 case IRP_MN_QUERY_REMOVE_DEVICE:
1979 case IRP_MN_QUERY_STOP_DEVICE:
1980 {
1981 Irp->IoStatus.Status = STATUS_SUCCESS;
1982 return ForwardIrpAndForget(DeviceObject, Irp);
1983 }
1984 case IRP_MN_REMOVE_DEVICE:
1985 {
1986 Irp->IoStatus.Status = STATUS_SUCCESS;
1987 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1988
1989 IoDetachDevice(HubDeviceExtension->LowerDeviceObject);
1990 IoDeleteDevice(DeviceObject);
1991
1992 return STATUS_SUCCESS;
1993 }
1994 case IRP_MN_QUERY_BUS_INFORMATION:
1995 {
1996 DPRINT("IRP_MN_QUERY_BUS_INFORMATION\n");
1997 break;
1998 }
1999 case IRP_MN_QUERY_ID:
2000 {
2001 DPRINT("IRP_MN_QUERY_ID\n");
2002 break;
2003 }
2004 case IRP_MN_QUERY_CAPABILITIES:
2005 {
2006 DPRINT("IRP_MN_QUERY_CAPABILITIES\n");
2007 break;
2008 }
2009 default:
2010 {
2011 DPRINT(" IRP_MJ_PNP / unknown minor function 0x%lx\n", Stack->MinorFunction);
2012 return ForwardIrpAndForget(DeviceObject, Irp);
2013 }
2014 }
2015
2016 Irp->IoStatus.Information = Information;
2017 Irp->IoStatus.Status = Status;
2018 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2019 return Status;
2020 }
2021
2022 NTSTATUS
2023 USBHUB_FdoHandleDeviceControl(
2024 IN PDEVICE_OBJECT DeviceObject,
2025 IN PIRP Irp)
2026 {
2027 DPRINT1("FdoHandleDeviceControl\n");
2028 UNIMPLEMENTED
2029 return STATUS_NOT_IMPLEMENTED;
2030 }
2031