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