[USBHUB]
[reactos.git] / reactos / drivers / usb / usbhub / fdo.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Hub Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbhub/fdo.c
5 * PURPOSE: Handle FDO
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11 #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 LONG 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 Status = IoCallDriver(DeviceObject, Irp);
573
574 if (Status == STATUS_PENDING)
575 {
576 DPRINT("Operation pending\n");
577 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
578 Status = IoStatus.Status;
579 }
580
581 return Status;
582 }
583
584 NTSTATUS
585 GetUsbDeviceDescriptor(
586 IN PDEVICE_OBJECT ChildDeviceObject,
587 IN UCHAR DescriptorType,
588 IN UCHAR Index,
589 IN USHORT LangId,
590 OUT PVOID TransferBuffer,
591 IN ULONG TransferBufferLength)
592 {
593 NTSTATUS Status;
594 PDEVICE_OBJECT RootHubDeviceObject;
595 PURB Urb;
596 PHUB_DEVICE_EXTENSION HubDeviceExtension;
597 PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
598
599 //
600 // Get the Hubs Device Extension
601 //
602 ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)ChildDeviceObject->DeviceExtension;
603 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) ChildDeviceExtension->ParentDeviceObject->DeviceExtension;
604 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
605
606 //
607 // Allocate a URB
608 //
609 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
610 if (!Urb)
611 {
612 DPRINT1("Failed to allocate memory for URB!\n");
613 return STATUS_INSUFFICIENT_RESOURCES;
614 }
615
616 //
617 // Zero it
618 //
619 RtlZeroMemory(Urb, sizeof(URB));
620
621 //
622 // Initialize URB for getting device descriptor
623 //
624 UsbBuildGetDescriptorRequest(Urb,
625 sizeof(Urb->UrbControlDescriptorRequest),
626 DescriptorType,
627 Index,
628 LangId,
629 TransferBuffer,
630 NULL,
631 TransferBufferLength,
632 NULL);
633
634 //
635 // Set the device handle
636 //
637 Urb->UrbHeader.UsbdDeviceHandle = (PVOID)ChildDeviceExtension->UsbDeviceHandle;
638
639 //
640 // Query the Root Hub
641 //
642 Status = SubmitRequestToRootHub(RootHubDeviceObject,
643 IOCTL_INTERNAL_USB_SUBMIT_URB,
644 Urb,
645 NULL);
646
647 return Status;
648 }
649
650 NTSTATUS
651 GetUsbStringDescriptor(
652 IN PDEVICE_OBJECT ChildDeviceObject,
653 IN UCHAR Index,
654 IN USHORT LangId,
655 OUT PVOID *TransferBuffer,
656 OUT USHORT *Size)
657 {
658 NTSTATUS Status;
659 PUSB_STRING_DESCRIPTOR StringDesc = NULL;
660 ULONG SizeNeeded;
661 LPWSTR Buffer;
662
663 StringDesc = ExAllocatePoolWithTag(NonPagedPool,
664 sizeof(USB_STRING_DESCRIPTOR),
665 USB_HUB_TAG);
666 if (!StringDesc)
667 {
668 DPRINT1("Failed to allocate buffer for string!\n");
669 return STATUS_INSUFFICIENT_RESOURCES;
670 }
671
672 //
673 // Get the index string descriptor length
674 // FIXME: Implement LangIds
675 //
676 Status = GetUsbDeviceDescriptor(ChildDeviceObject,
677 USB_STRING_DESCRIPTOR_TYPE,
678 Index,
679 0x0409,
680 StringDesc,
681 sizeof(USB_STRING_DESCRIPTOR));
682 if (!NT_SUCCESS(Status))
683 {
684 DPRINT1("GetUsbDeviceDescriptor failed with status %x\n", Status);
685 ExFreePool(StringDesc);
686 return Status;
687 }
688 DPRINT1("StringDesc->bLength %d\n", StringDesc->bLength);
689
690 //
691 // Did we get something more than the length of the first two fields of structure?
692 //
693 if (StringDesc->bLength == 2)
694 {
695 DPRINT1("USB Device Error!\n");
696 ExFreePool(StringDesc);
697 return STATUS_DEVICE_DATA_ERROR;
698 }
699 SizeNeeded = StringDesc->bLength + sizeof(WCHAR);
700
701 //
702 // Free String
703 //
704 ExFreePool(StringDesc);
705
706 //
707 // Recreate with appropriate size
708 //
709 StringDesc = ExAllocatePoolWithTag(NonPagedPool,
710 SizeNeeded,
711 USB_HUB_TAG);
712 if (!StringDesc)
713 {
714 DPRINT1("Failed to allocate buffer for string!\n");
715 return STATUS_INSUFFICIENT_RESOURCES;
716 }
717
718 RtlZeroMemory(StringDesc, SizeNeeded);
719
720 //
721 // Get the string
722 //
723 Status = GetUsbDeviceDescriptor(ChildDeviceObject,
724 USB_STRING_DESCRIPTOR_TYPE,
725 Index,
726 0x0409,
727 StringDesc,
728 SizeNeeded);
729 if (!NT_SUCCESS(Status))
730 {
731 DPRINT1("GetUsbDeviceDescriptor failed with status %x\n", Status);
732 ExFreePool(StringDesc);
733 return Status;
734 }
735
736 //
737 // Allocate Buffer to return
738 //
739 Buffer = ExAllocatePoolWithTag(NonPagedPool,
740 SizeNeeded,
741 USB_HUB_TAG);
742 if (!Buffer)
743 {
744 DPRINT1("Failed to allocate buffer for string!\n");
745 ExFreePool(StringDesc);
746 return STATUS_INSUFFICIENT_RESOURCES;
747 }
748
749 RtlZeroMemory(Buffer, SizeNeeded);
750
751 //
752 // Copy the string to destination
753 //
754 RtlCopyMemory(Buffer, StringDesc->bString, SizeNeeded - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString));
755 *Size = SizeNeeded;
756 *TransferBuffer = Buffer;
757
758 ExFreePool(StringDesc);
759
760 return STATUS_SUCCESS;
761 }
762
763 ULONG
764 IsCompositeDevice(
765 IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
766 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
767 {
768 if (DeviceDescriptor->bNumConfigurations != 1)
769 {
770 //
771 // composite device must have only one configuration
772 //
773 DPRINT1("IsCompositeDevice bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
774 return FALSE;
775 }
776
777 if (ConfigurationDescriptor->bNumInterfaces < 2)
778 {
779 //
780 // composite device must have multiple interfaces
781 //
782 DPRINT1("IsCompositeDevice bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
783 return FALSE;
784 }
785
786 if (DeviceDescriptor->bDeviceClass == 0)
787 {
788 //
789 // composite device
790 //
791 ASSERT(DeviceDescriptor->bDeviceSubClass == 0);
792 ASSERT(DeviceDescriptor->bDeviceProtocol == 0);
793 DPRINT1("IsCompositeDevice: TRUE\n");
794 return TRUE;
795 }
796
797 if (DeviceDescriptor->bDeviceClass == 0xEF &&
798 DeviceDescriptor->bDeviceSubClass == 0x02 &&
799 DeviceDescriptor->bDeviceProtocol == 0x01)
800 {
801 //
802 // USB-IF association descriptor
803 //
804 DPRINT1("IsCompositeDevice: TRUE\n");
805 return TRUE;
806 }
807
808 DPRINT1("DeviceDescriptor bDeviceClass %x bDeviceSubClass %x bDeviceProtocol %x\n", DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol);
809
810 //
811 // not a composite device
812 //
813 return FALSE;
814 }
815
816 NTSTATUS
817 CreateDeviceIds(
818 PDEVICE_OBJECT UsbChildDeviceObject)
819 {
820 NTSTATUS Status = STATUS_SUCCESS;
821 ULONG Index = 0;
822 LPWSTR DeviceString;
823 WCHAR Buffer[200];
824 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
825 PHUB_DEVICE_EXTENSION HubDeviceExtension;
826 PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
827 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
828 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
829
830 //
831 // get child device extension
832 //
833 UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)UsbChildDeviceObject->DeviceExtension;
834
835 // get hub device extension
836 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) UsbChildExtension->ParentDeviceObject->DeviceExtension;
837
838 //
839 // get device descriptor
840 //
841 DeviceDescriptor = &UsbChildExtension->DeviceDesc;
842
843 //
844 // get configuration descriptor
845 //
846 ConfigurationDescriptor = UsbChildExtension->FullConfigDesc;
847
848 //
849 // use first interface descriptor available
850 //
851 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, 0, -1, -1, -1, -1);
852 ASSERT(InterfaceDescriptor);
853
854 //
855 // Construct the CompatibleIds
856 //
857 if (IsCompositeDevice(DeviceDescriptor, ConfigurationDescriptor))
858 {
859 //
860 // sanity checks
861 //
862 ASSERT(DeviceDescriptor->bNumConfigurations == 1);
863 ASSERT(ConfigurationDescriptor->bNumInterfaces > 1);
864 Index += swprintf(&Buffer[Index],
865 L"USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
866 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol) + 1;
867 Index += swprintf(&Buffer[Index],
868 L"USB\\DevClass_%02x&SubClass_%02x",
869 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass) + 1;
870 Index += swprintf(&Buffer[Index],
871 L"USB\\DevClass_%02x",
872 DeviceDescriptor->bDeviceClass) + 1;
873 Index += swprintf(&Buffer[Index],
874 L"USB\\COMPOSITE") + 1;
875 }
876 else
877 {
878 //
879 // FIXME: support multiple configurations
880 //
881 ASSERT(DeviceDescriptor->bNumConfigurations == 1);
882
883 if (DeviceDescriptor->bDeviceClass == 0)
884 {
885 Index += swprintf(&Buffer[Index],
886 L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
887 InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass, InterfaceDescriptor->bInterfaceProtocol) + 1;
888 Index += swprintf(&Buffer[Index],
889 L"USB\\Class_%02x&SubClass_%02x",
890 InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass) + 1;
891 Index += swprintf(&Buffer[Index],
892 L"USB\\Class_%02x",
893 InterfaceDescriptor->bInterfaceClass) + 1;
894 }
895 else
896 {
897 Index += swprintf(&Buffer[Index],
898 L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
899 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol) + 1;
900 Index += swprintf(&Buffer[Index],
901 L"USB\\Class_%02x&SubClass_%02x",
902 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass) + 1;
903 Index += swprintf(&Buffer[Index],
904 L"USB\\Class_%02x",
905 DeviceDescriptor->bDeviceClass) + 1;
906 }
907 }
908
909 //
910 // now allocate the buffer
911 //
912 DeviceString = ExAllocatePool(NonPagedPool, (Index + 1) * sizeof(WCHAR));
913 if (!DeviceString)
914 {
915 //
916 // no memory
917 //
918 return STATUS_INSUFFICIENT_RESOURCES;
919 }
920
921 //
922 // copy buffer
923 //
924 RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
925 DeviceString[Index] = UNICODE_NULL;
926 UsbChildExtension->usCompatibleIds.Buffer = DeviceString;
927 UsbChildExtension->usCompatibleIds.Length = Index * sizeof(WCHAR);
928 UsbChildExtension->usCompatibleIds.MaximumLength = (Index + 1) * sizeof(WCHAR);
929 DPRINT("usCompatibleIds %wZ\n", &UsbChildExtension->usCompatibleIds);
930
931 //
932 // Construct DeviceId string
933 //
934 Index = swprintf(Buffer, L"USB\\Vid_%04x&Pid_%04x", UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct) + 1;
935
936 //
937 // now allocate the buffer
938 //
939 DeviceString = ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
940 if (!DeviceString)
941 {
942 //
943 // no memory
944 //
945 return STATUS_INSUFFICIENT_RESOURCES;
946 }
947
948 //
949 // copy buffer
950 //
951 RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
952 UsbChildExtension->usDeviceId.Buffer = DeviceString;
953 UsbChildExtension->usDeviceId.Length = (Index-1) * sizeof(WCHAR);
954 UsbChildExtension->usDeviceId.MaximumLength = Index * sizeof(WCHAR);
955 DPRINT("usDeviceId %wZ\n", &UsbChildExtension->usDeviceId);
956
957 //
958 // Construct HardwareIds
959 //
960 Index = 0;
961 Index += swprintf(&Buffer[Index],
962 L"USB\\Vid_%04x&Pid_%04x&Rev_%04x",
963 UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct, UsbChildExtension->DeviceDesc.bcdDevice) + 1;
964 Index += swprintf(&Buffer[Index],
965 L"USB\\Vid_%04x&Pid_%04x",
966 UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct) + 1;
967
968 //
969 // now allocate the buffer
970 //
971 DeviceString = ExAllocatePool(NonPagedPool, (Index + 1) * sizeof(WCHAR));
972 if (!DeviceString)
973 {
974 //
975 // no memory
976 //
977 return STATUS_INSUFFICIENT_RESOURCES;
978 }
979
980 //
981 // copy buffer
982 //
983 RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
984 DeviceString[Index] = UNICODE_NULL;
985 UsbChildExtension->usHardwareIds.Buffer = DeviceString;
986 UsbChildExtension->usHardwareIds.Length = (Index + 1) * sizeof(WCHAR);
987 UsbChildExtension->usHardwareIds.MaximumLength = (Index + 1) * sizeof(WCHAR);
988 DPRINT("usHardWareIds %wZ\n", &UsbChildExtension->usHardwareIds);
989
990 //
991 // FIXME: Handle Lang ids
992 //
993
994 //
995 // Get the product string if obe provided
996 //
997 if (UsbChildExtension->DeviceDesc.iProduct)
998 {
999 Status = GetUsbStringDescriptor(UsbChildDeviceObject,
1000 UsbChildExtension->DeviceDesc.iProduct,
1001 0,
1002 (PVOID*)&UsbChildExtension->usTextDescription.Buffer,
1003 &UsbChildExtension->usTextDescription.Length);
1004 if (!NT_SUCCESS(Status))
1005 {
1006 DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
1007 RtlInitUnicodeString(&UsbChildExtension->usTextDescription, L"USB Device"); // FIXME NON-NLS
1008 }
1009 else
1010 {
1011 UsbChildExtension->usTextDescription.MaximumLength = UsbChildExtension->usTextDescription.Length;
1012 DPRINT("Usb TextDescription %wZ\n", &UsbChildExtension->usTextDescription);
1013 }
1014 }
1015
1016 //
1017 // Get the Serial Number string if obe provided
1018 //
1019 if (UsbChildExtension->DeviceDesc.iSerialNumber)
1020 {
1021 LPWSTR SerialBuffer = NULL;
1022
1023 Status = GetUsbStringDescriptor(UsbChildDeviceObject,
1024 UsbChildExtension->DeviceDesc.iSerialNumber,
1025 0,
1026 (PVOID*)&SerialBuffer,
1027 &UsbChildExtension->usInstanceId.Length);
1028 if (NT_SUCCESS(Status))
1029 {
1030 // construct instance id buffer
1031 Index = swprintf(Buffer, L"%04d&%s", HubDeviceExtension->InstanceCount, SerialBuffer) + 1;
1032 UsbChildExtension->usInstanceId.Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
1033 if (UsbChildExtension->usInstanceId.Buffer == NULL)
1034 {
1035 DPRINT1("Error: failed to allocate %lu bytes\n", Index * sizeof(WCHAR));
1036 return STATUS_INSUFFICIENT_RESOURCES;
1037 }
1038
1039 //
1040 // copy instance id
1041 //
1042 RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR));
1043 UsbChildExtension->usInstanceId.Length = UsbChildExtension->usInstanceId.MaximumLength = Index * sizeof(WCHAR);
1044 ExFreePool(SerialBuffer);
1045
1046 DPRINT("Usb InstanceId %wZ InstanceCount %x\n", &UsbChildExtension->usInstanceId, HubDeviceExtension->InstanceCount);
1047 return Status;
1048 }
1049 }
1050
1051 //
1052 // the device did not provide a serial number, or failed to retrieve the serial number
1053 // lets create a pseudo instance id
1054 //
1055 Index = swprintf(Buffer, L"%04d&%04d", HubDeviceExtension->InstanceCount, UsbChildExtension->PortNumber) + 1;
1056 UsbChildExtension->usInstanceId.Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
1057 if (UsbChildExtension->usInstanceId.Buffer == NULL)
1058 {
1059 DPRINT1("Error: failed to allocate %lu bytes\n", Index * sizeof(WCHAR));
1060 Status = STATUS_INSUFFICIENT_RESOURCES;
1061 return Status;
1062 }
1063
1064 //
1065 // copy instance id
1066 //
1067 RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR));
1068 UsbChildExtension->usInstanceId.Length = UsbChildExtension->usInstanceId.MaximumLength = Index * sizeof(WCHAR);
1069
1070 DPRINT("usDeviceId %wZ\n", &UsbChildExtension->usInstanceId);
1071 return STATUS_SUCCESS;
1072 }
1073
1074 NTSTATUS
1075 DestroyUsbChildDeviceObject(
1076 IN PDEVICE_OBJECT UsbHubDeviceObject,
1077 IN LONG PortId)
1078 {
1079 PHUB_DEVICE_EXTENSION HubDeviceExtension = (PHUB_DEVICE_EXTENSION)UsbHubDeviceObject->DeviceExtension;
1080 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension = NULL;
1081 PDEVICE_OBJECT ChildDeviceObject = NULL;
1082 ULONG Index = 0;
1083
1084 DPRINT("Removing device on port %d (Child index: %d)\n", PortId, Index);
1085
1086 for (Index = 0; Index < USB_MAXCHILDREN; Index++)
1087 {
1088 if (HubDeviceExtension->ChildDeviceObject[Index])
1089 {
1090 UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
1091
1092 /* Check if it matches the port ID */
1093 if (UsbChildExtension->PortNumber == PortId)
1094 {
1095 /* We found it */
1096 ChildDeviceObject = HubDeviceExtension->ChildDeviceObject[Index];
1097 break;
1098 }
1099 }
1100 }
1101
1102 /* Fail the request if the device doesn't exist */
1103 if (!ChildDeviceObject)
1104 {
1105 DPRINT1("Removal request for non-existant device!\n");
1106 return STATUS_UNSUCCESSFUL;
1107 }
1108
1109 /* Remove the device from the table */
1110 HubDeviceExtension->ChildDeviceObject[Index] = NULL;
1111
1112 /* Invalidate device relations for the root hub */
1113 IoInvalidateDeviceRelations(HubDeviceExtension->RootHubPhysicalDeviceObject, BusRelations);
1114
1115 /* The rest of the removal process takes place in IRP_MN_REMOVE_DEVICE handling for the PDO */
1116 return STATUS_SUCCESS;
1117 }
1118
1119 NTSTATUS
1120 CreateUsbChildDeviceObject(
1121 IN PDEVICE_OBJECT UsbHubDeviceObject,
1122 IN LONG PortId,
1123 OUT PDEVICE_OBJECT *UsbChildDeviceObject,
1124 IN ULONG PortStatus)
1125 {
1126 NTSTATUS Status;
1127 PDEVICE_OBJECT RootHubDeviceObject, NewChildDeviceObject;
1128 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1129 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
1130 PUSB_BUS_INTERFACE_HUB_V5 HubInterface;
1131 ULONG ChildDeviceCount, UsbDeviceNumber = 0;
1132 WCHAR CharDeviceName[64];
1133 UNICODE_STRING DeviceName;
1134 ULONG ConfigDescSize, DeviceDescSize, DeviceInfoSize;
1135 PVOID HubInterfaceBusContext;
1136 USB_CONFIGURATION_DESCRIPTOR ConfigDesc;
1137
1138 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) UsbHubDeviceObject->DeviceExtension;
1139 HubInterface = &HubDeviceExtension->HubInterface;
1140 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
1141 HubInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
1142 //
1143 // Find an empty slot in the child device array
1144 //
1145 for (ChildDeviceCount = 0; ChildDeviceCount < USB_MAXCHILDREN; ChildDeviceCount++)
1146 {
1147 if (HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] == NULL)
1148 {
1149 DPRINT("Found unused entry at %d\n", ChildDeviceCount);
1150 break;
1151 }
1152 }
1153
1154 //
1155 // Check if the limit has been reached for maximum usb devices
1156 //
1157 if (ChildDeviceCount == USB_MAXCHILDREN)
1158 {
1159 DPRINT1("USBHUB: Too many child devices!\n");
1160 return STATUS_UNSUCCESSFUL;
1161 }
1162
1163 while (TRUE)
1164 {
1165 //
1166 // Create a Device Name
1167 //
1168 swprintf(CharDeviceName, L"\\Device\\USBPDO-%d", UsbDeviceNumber);
1169
1170 //
1171 // Initialize UnicodeString
1172 //
1173 RtlInitUnicodeString(&DeviceName, CharDeviceName);
1174
1175 //
1176 // Create a DeviceObject
1177 //
1178 Status = IoCreateDevice(UsbHubDeviceObject->DriverObject,
1179 sizeof(HUB_CHILDDEVICE_EXTENSION),
1180 NULL,
1181 FILE_DEVICE_CONTROLLER,
1182 FILE_AUTOGENERATED_DEVICE_NAME,
1183 FALSE,
1184 &NewChildDeviceObject);
1185
1186 //
1187 // Check if the name is already in use
1188 //
1189 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
1190 {
1191 //
1192 // Try next name
1193 //
1194 UsbDeviceNumber++;
1195 continue;
1196 }
1197
1198 //
1199 // Check for other errors
1200 //
1201 if (!NT_SUCCESS(Status))
1202 {
1203 DPRINT1("USBHUB: IoCreateDevice failed with status %x\n", Status);
1204 return Status;
1205 }
1206
1207 DPRINT("USBHUB: Created Device %x\n", NewChildDeviceObject);
1208 break;
1209 }
1210
1211 NewChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
1212
1213 //
1214 // Assign the device extensions
1215 //
1216 UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)NewChildDeviceObject->DeviceExtension;
1217 RtlZeroMemory(UsbChildExtension, sizeof(HUB_CHILDDEVICE_EXTENSION));
1218 UsbChildExtension->ParentDeviceObject = UsbHubDeviceObject;
1219 UsbChildExtension->PortNumber = PortId;
1220
1221 // copy device interface
1222 RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
1223
1224
1225 //
1226 // Create the UsbDeviceObject
1227 //
1228 Status = HubInterface->CreateUsbDevice(HubInterfaceBusContext,
1229 (PVOID)&UsbChildExtension->UsbDeviceHandle,
1230 HubDeviceExtension->RootHubHandle,
1231 PortStatus,
1232 PortId);
1233 if (!NT_SUCCESS(Status))
1234 {
1235 DPRINT1("USBHUB: CreateUsbDevice failed with status %x\n", Status);
1236 goto Cleanup;
1237 }
1238
1239 // copy device interface
1240 RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
1241
1242 // FIXME replace buscontext
1243 UsbChildExtension->DeviceInterface.BusContext = UsbChildExtension->UsbDeviceHandle;
1244
1245 //
1246 // Initialize UsbDevice
1247 //
1248 Status = HubInterface->InitializeUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle);
1249 if (!NT_SUCCESS(Status))
1250 {
1251 DPRINT1("USBHUB: InitializeUsbDevice failed with status %x\n", Status);
1252 goto Cleanup;
1253 }
1254
1255 DPRINT("Usb Device Handle %x\n", UsbChildExtension->UsbDeviceHandle);
1256
1257 ConfigDescSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
1258 DeviceDescSize = sizeof(USB_DEVICE_DESCRIPTOR);
1259
1260 //
1261 // Get the descriptors
1262 //
1263 Status = HubInterface->GetUsbDescriptors(HubInterfaceBusContext,
1264 UsbChildExtension->UsbDeviceHandle,
1265 (PUCHAR)&UsbChildExtension->DeviceDesc,
1266 &DeviceDescSize,
1267 (PUCHAR)&ConfigDesc,
1268 &ConfigDescSize);
1269 if (!NT_SUCCESS(Status))
1270 {
1271 DPRINT1("USBHUB: GetUsbDescriptors failed with status %x\n", Status);
1272 goto Cleanup;
1273 }
1274
1275 //DumpDeviceDescriptor(&UsbChildExtension->DeviceDesc);
1276 //DumpConfigurationDescriptor(&ConfigDesc);
1277
1278 //
1279 // FIXME: Support more than one configuration and one interface?
1280 //
1281 if (UsbChildExtension->DeviceDesc.bNumConfigurations > 1)
1282 {
1283 DPRINT1("Warning: Device has more than one configuration. Only one configuration (the first) is supported!\n");
1284 }
1285
1286 if (ConfigDesc.bNumInterfaces > 1)
1287 {
1288 DPRINT1("Warning: Device has more that one interface. Only one interface (the first) is currently supported\n");
1289 }
1290
1291 ConfigDescSize = ConfigDesc.wTotalLength;
1292
1293 //
1294 // Allocate memory for the first full descriptor, including interfaces and endpoints.
1295 //
1296 UsbChildExtension->FullConfigDesc = ExAllocatePoolWithTag(PagedPool, ConfigDescSize, USB_HUB_TAG);
1297
1298 //
1299 // Retrieve the full configuration descriptor
1300 //
1301 Status = GetUsbDeviceDescriptor(NewChildDeviceObject,
1302 USB_CONFIGURATION_DESCRIPTOR_TYPE,
1303 0,
1304 0,
1305 UsbChildExtension->FullConfigDesc,
1306 ConfigDescSize);
1307
1308 if (!NT_SUCCESS(Status))
1309 {
1310 DPRINT1("USBHUB: GetUsbDeviceDescriptor failed with status %x\n", Status);
1311 goto Cleanup;
1312 }
1313
1314 // query device details
1315 Status = HubInterface->QueryDeviceInformation(HubInterfaceBusContext,
1316 UsbChildExtension->UsbDeviceHandle,
1317 &UsbChildExtension->DeviceInformation,
1318 sizeof(USB_DEVICE_INFORMATION_0),
1319 &DeviceInfoSize);
1320
1321
1322 //DumpFullConfigurationDescriptor(UsbChildExtension->FullConfigDesc);
1323
1324 //
1325 // Construct all the strings that will described the device to PNP
1326 //
1327 Status = CreateDeviceIds(NewChildDeviceObject);
1328 if (!NT_SUCCESS(Status))
1329 {
1330 DPRINT1("Failed to create strings needed to describe device to PNP.\n");
1331 goto Cleanup;
1332 }
1333
1334 HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] = NewChildDeviceObject;
1335 HubDeviceExtension->InstanceCount++;
1336
1337 IoInvalidateDeviceRelations(RootHubDeviceObject, BusRelations);
1338 return STATUS_SUCCESS;
1339
1340 Cleanup:
1341
1342 //
1343 // Remove the usb device if it was created
1344 //
1345 if (UsbChildExtension->UsbDeviceHandle)
1346 HubInterface->RemoveUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle, 0);
1347
1348 //
1349 // Free full configuration descriptor if one was allocated
1350 //
1351 if (UsbChildExtension->FullConfigDesc)
1352 ExFreePool(UsbChildExtension->FullConfigDesc);
1353
1354 //
1355 // Delete the device object
1356 //
1357 IoDeleteDevice(NewChildDeviceObject);
1358 return Status;
1359 }
1360
1361 NTSTATUS
1362 USBHUB_FdoQueryBusRelations(
1363 IN PDEVICE_OBJECT DeviceObject,
1364 OUT PDEVICE_RELATIONS* pDeviceRelations)
1365 {
1366 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1367 PDEVICE_RELATIONS DeviceRelations;
1368 ULONG i;
1369 ULONG Children = 0;
1370 ULONG NeededSize;
1371
1372 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1373
1374 //
1375 // Count the number of children
1376 //
1377 for (i = 0; i < USB_MAXCHILDREN; i++)
1378 {
1379
1380 if (HubDeviceExtension->ChildDeviceObject[i] == NULL)
1381 {
1382 continue;
1383 }
1384 Children++;
1385 }
1386
1387 NeededSize = sizeof(DEVICE_RELATIONS);
1388 if (Children > 1)
1389 NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
1390
1391 //
1392 // Allocate DeviceRelations
1393 //
1394 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool,
1395 NeededSize);
1396
1397 if (!DeviceRelations)
1398 return STATUS_INSUFFICIENT_RESOURCES;
1399 DeviceRelations->Count = Children;
1400 Children = 0;
1401
1402 //
1403 // Fill in return structure
1404 //
1405 for (i = 0; i < USB_MAXCHILDREN; i++)
1406 {
1407 if (HubDeviceExtension->ChildDeviceObject[i])
1408 {
1409 ObReferenceObject(HubDeviceExtension->ChildDeviceObject[i]);
1410 HubDeviceExtension->ChildDeviceObject[i]->Flags &= ~DO_DEVICE_INITIALIZING;
1411 DeviceRelations->Objects[Children++] = HubDeviceExtension->ChildDeviceObject[i];
1412 }
1413 }
1414
1415 ASSERT(Children == DeviceRelations->Count);
1416 *pDeviceRelations = DeviceRelations;
1417
1418 return STATUS_SUCCESS;
1419 }
1420
1421 VOID
1422 NTAPI
1423 RootHubInitCallbackFunction(
1424 PVOID Context)
1425 {
1426 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
1427 NTSTATUS Status;
1428 ULONG PortId;
1429 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1430 PORT_STATUS_CHANGE StatusChange;
1431
1432 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1433
1434 DPRINT("RootHubInitCallbackFunction Sending the initial SCE Request %x\n", DeviceObject);
1435
1436 //
1437 // Send the first SCE Request
1438 //
1439 QueryStatusChangeEndpoint(DeviceObject);
1440
1441 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1442 {
1443 //
1444 // get port status
1445 //
1446 Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
1447 if (NT_SUCCESS(Status))
1448 {
1449 //
1450 // is there a device connected
1451 //
1452 if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
1453 {
1454 //
1455 // reset port
1456 //
1457 Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
1458 if (!NT_SUCCESS(Status))
1459 {
1460 DPRINT1("Failed to reset on port %d\n", PortId);
1461 }
1462 else
1463 {
1464 //
1465 // wait for the reset to be handled since we want to enumerate synchronously
1466 //
1467 KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
1468 Executive,
1469 KernelMode,
1470 FALSE,
1471 NULL);
1472 KeClearEvent(&HubDeviceExtension->ResetComplete);
1473 }
1474 }
1475 }
1476 }
1477 }
1478
1479 BOOLEAN
1480 USBHUB_IsRootHubFDO(
1481 IN PDEVICE_OBJECT DeviceObject)
1482 {
1483 NTSTATUS Status;
1484 PDEVICE_OBJECT RootHubPhysicalDeviceObject = NULL;
1485 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1486
1487 // get hub device extension
1488 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1489
1490 // Get the Root Hub Pdo
1491 Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
1492 IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
1493 &RootHubPhysicalDeviceObject,
1494 NULL);
1495
1496 // FIXME handle error
1497 ASSERT(NT_SUCCESS(Status));
1498
1499 // physical device object is only obtained for root hubs
1500 return (RootHubPhysicalDeviceObject != NULL);
1501 }
1502
1503
1504 NTSTATUS
1505 USBHUB_FdoStartDevice(
1506 IN PDEVICE_OBJECT DeviceObject,
1507 IN PIRP Irp)
1508 {
1509 PURB Urb;
1510 PUSB_INTERFACE_DESCRIPTOR Pid;
1511 ULONG Result = 0, PortId;
1512 USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}};
1513 PURB ConfigUrb = NULL;
1514 ULONG HubStatus;
1515 NTSTATUS Status = STATUS_SUCCESS;
1516 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1517 PDEVICE_OBJECT RootHubDeviceObject;
1518 PVOID HubInterfaceBusContext;
1519 PORT_STATUS_CHANGE StatusChange;
1520
1521 // get hub device extension
1522 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1523
1524 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
1525
1526 // Allocated size including the sizeof USBD_INTERFACE_LIST_ENTRY
1527 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY), USB_HUB_TAG);
1528 if (!Urb)
1529 {
1530 // no memory
1531 return STATUS_INSUFFICIENT_RESOURCES;
1532 }
1533
1534 // zero urb
1535 RtlZeroMemory(Urb, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY));
1536
1537 // Get the Root Hub Pdo
1538 Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
1539 IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
1540 &HubDeviceExtension->RootHubPhysicalDeviceObject,
1541 &HubDeviceExtension->RootHubFunctionalDeviceObject);
1542 if (!NT_SUCCESS(Status))
1543 {
1544 // failed to obtain hub pdo
1545 DPRINT1("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO failed with %x\n", Status);
1546 ExFreePool(Urb);
1547 return Status;
1548 }
1549
1550 // sanity checks
1551 ASSERT(HubDeviceExtension->RootHubPhysicalDeviceObject);
1552 ASSERT(HubDeviceExtension->RootHubFunctionalDeviceObject);
1553
1554 // get roothub
1555 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
1556
1557 // Send the StartDevice to RootHub
1558 Status = ForwardIrpAndWait(RootHubDeviceObject, Irp);
1559
1560 if (!NT_SUCCESS(Status))
1561 {
1562 // failed to start pdo
1563 DPRINT1("Failed to start the RootHub PDO\n");
1564 ExFreePool(Urb);
1565 return Status;
1566 }
1567
1568 // Get the current number of hubs
1569 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1570 IOCTL_INTERNAL_USB_GET_HUB_COUNT,
1571 &HubDeviceExtension->NumberOfHubs, NULL);
1572 if (!NT_SUCCESS(Status))
1573 {
1574 // failed to get number of hubs
1575 DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_COUNT failed with %x\n", Status);
1576 ExFreePool(Urb);
1577 return Status;
1578 }
1579
1580 // Get the Hub Interface
1581 Status = QueryInterface(RootHubDeviceObject,
1582 USB_BUS_INTERFACE_HUB_GUID,
1583 sizeof(USB_BUS_INTERFACE_HUB_V5),
1584 USB_BUSIF_HUB_VERSION_5,
1585 (PVOID)&HubDeviceExtension->HubInterface);
1586
1587 if (!NT_SUCCESS(Status))
1588 {
1589 // failed to get root hub interface
1590 DPRINT1("Failed to get HUB_GUID interface with status 0x%08lx\n", Status);
1591 ExFreePool(Urb);
1592 return Status;
1593 }
1594
1595 HubInterfaceBusContext = HubDeviceExtension->HubInterface.BusContext;
1596
1597 // Get the USBDI Interface
1598 Status = QueryInterface(RootHubDeviceObject,
1599 USB_BUS_INTERFACE_USBDI_GUID,
1600 sizeof(USB_BUS_INTERFACE_USBDI_V2),
1601 USB_BUSIF_USBDI_VERSION_2,
1602 (PVOID)&HubDeviceExtension->UsbDInterface);
1603
1604 if (!NT_SUCCESS(Status))
1605 {
1606 // failed to get usbdi interface
1607 DPRINT1("Failed to get USBDI_GUID interface with status 0x%08lx\n", Status);
1608 ExFreePool(Urb);
1609 return Status;
1610 }
1611
1612 // Get Root Hub Device Handle
1613 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1614 IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
1615 &HubDeviceExtension->RootHubHandle,
1616 NULL);
1617
1618 if (!NT_SUCCESS(Status))
1619 {
1620 // failed
1621 DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE failed with status 0x%08lx\n", Status);
1622 ExFreePool(Urb);
1623 return Status;
1624 }
1625
1626 //
1627 // Get Hub Device Information
1628 //
1629 Status = HubDeviceExtension->HubInterface.QueryDeviceInformation(HubInterfaceBusContext,
1630 HubDeviceExtension->RootHubHandle,
1631 &HubDeviceExtension->DeviceInformation,
1632 sizeof(USB_DEVICE_INFORMATION_0),
1633 &Result);
1634
1635 DPRINT1("Status %x, Result 0x%08lx\n", Status, Result);
1636 DPRINT1("InformationLevel %x\n", HubDeviceExtension->DeviceInformation.InformationLevel);
1637 DPRINT1("ActualLength %x\n", HubDeviceExtension->DeviceInformation.ActualLength);
1638 DPRINT1("PortNumber %x\n", HubDeviceExtension->DeviceInformation.PortNumber);
1639 DPRINT1("DeviceDescriptor %x\n", HubDeviceExtension->DeviceInformation.DeviceDescriptor);
1640 DPRINT1("HubAddress %x\n", HubDeviceExtension->DeviceInformation.HubAddress);
1641 DPRINT1("NumberofPipes %x\n", HubDeviceExtension->DeviceInformation.NumberOfOpenPipes);
1642
1643 // Get Root Hubs Device Descriptor
1644 UsbBuildGetDescriptorRequest(Urb,
1645 sizeof(Urb->UrbControlDescriptorRequest),
1646 USB_DEVICE_DESCRIPTOR_TYPE,
1647 0,
1648 0,
1649 &HubDeviceExtension->HubDeviceDescriptor,
1650 NULL,
1651 sizeof(USB_DEVICE_DESCRIPTOR),
1652 NULL);
1653
1654 // set device handle
1655 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1656
1657 // get hub device descriptor
1658 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1659 IOCTL_INTERNAL_USB_SUBMIT_URB,
1660 Urb,
1661 NULL);
1662
1663 if (!NT_SUCCESS(Status))
1664 {
1665 // failed to get device descriptor of hub
1666 DPRINT1("Failed to get HubDeviceDescriptor!\n");
1667 ExFreePool(Urb);
1668 return Status;
1669 }
1670
1671 // build configuration request
1672 UsbBuildGetDescriptorRequest(Urb,
1673 sizeof(Urb->UrbControlDescriptorRequest),
1674 USB_CONFIGURATION_DESCRIPTOR_TYPE,
1675 0,
1676 0,
1677 &HubDeviceExtension->HubConfigDescriptor,
1678 NULL,
1679 sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR),
1680 NULL);
1681
1682 // set device handle
1683 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1684
1685 // request configuration descriptor
1686 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1687 IOCTL_INTERNAL_USB_SUBMIT_URB,
1688 Urb,
1689 NULL);
1690
1691 if (!NT_SUCCESS(Status))
1692 {
1693 // failed to get configuration descriptor
1694 DPRINT1("Failed to get RootHub Configuration with status %x\n", Status);
1695 ExFreePool(Urb);
1696 return Status;
1697 }
1698
1699 // sanity checks
1700 ASSERT(HubDeviceExtension->HubConfigDescriptor.wTotalLength == sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR));
1701 ASSERT(HubDeviceExtension->HubConfigDescriptor.bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE);
1702 ASSERT(HubDeviceExtension->HubConfigDescriptor.bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
1703 ASSERT(HubDeviceExtension->HubConfigDescriptor.bNumInterfaces == 1);
1704 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
1705 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
1706 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bNumEndpoints == 1);
1707 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
1708 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bLength == sizeof(USB_ENDPOINT_DESCRIPTOR));
1709 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bmAttributes == USB_ENDPOINT_TYPE_INTERRUPT);
1710 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bEndpointAddress == 0x81); // interrupt in
1711
1712 // get hub information
1713 Status = HubDeviceExtension->HubInterface.GetExtendedHubInformation(HubInterfaceBusContext,
1714 RootHubDeviceObject,
1715 &HubDeviceExtension->UsbExtHubInfo,
1716 sizeof(USB_EXTHUB_INFORMATION_0),
1717 &Result);
1718 if (!NT_SUCCESS(Status))
1719 {
1720 // failed to get hub information
1721 DPRINT1("Failed to extended hub information. Unable to determine the number of ports!\n");
1722 ExFreePool(Urb);
1723 return Status;
1724 }
1725
1726 if (!HubDeviceExtension->UsbExtHubInfo.NumberOfPorts)
1727 {
1728 // bogus port driver
1729 DPRINT1("Failed to retrieve the number of ports\n");
1730 ExFreePool(Urb);
1731 return STATUS_UNSUCCESSFUL;
1732 }
1733
1734 DPRINT1("HubDeviceExtension->UsbExtHubInfo.NumberOfPorts %x\n", HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
1735
1736 // Build hub descriptor request
1737 UsbBuildVendorRequest(Urb,
1738 URB_FUNCTION_CLASS_DEVICE,
1739 sizeof(Urb->UrbControlVendorClassRequest),
1740 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
1741 0,
1742 USB_REQUEST_GET_DESCRIPTOR,
1743 USB_DEVICE_CLASS_RESERVED,
1744 0,
1745 &HubDeviceExtension->HubDescriptor,
1746 NULL,
1747 sizeof(USB_HUB_DESCRIPTOR),
1748 NULL);
1749
1750 // set device handle
1751 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1752
1753 // send request
1754 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1755 IOCTL_INTERNAL_USB_SUBMIT_URB,
1756 Urb,
1757 NULL);
1758
1759 if (!NT_SUCCESS(Status))
1760 {
1761 DPRINT1("Failed to get Hub Descriptor!\n");
1762 ExFreePool(Urb);
1763 return STATUS_UNSUCCESSFUL;
1764 }
1765
1766 // sanity checks
1767 ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorLength == sizeof(USB_HUB_DESCRIPTOR));
1768 ASSERT(HubDeviceExtension->HubDescriptor.bNumberOfPorts == HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
1769 ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorType == 0x29);
1770
1771 // build get status request
1772 HubStatus = 0;
1773 UsbBuildGetStatusRequest(Urb,
1774 URB_FUNCTION_GET_STATUS_FROM_DEVICE,
1775 0,
1776 &HubStatus,
1777 0,
1778 NULL);
1779 // set device handle
1780 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1781
1782 // send request
1783 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1784 IOCTL_INTERNAL_USB_SUBMIT_URB,
1785 Urb,
1786 NULL);
1787 if (!NT_SUCCESS(Status))
1788 {
1789 // failed to get hub status
1790 DPRINT1("Failed to get Hub Status!\n");
1791 ExFreePool(Urb);
1792 return STATUS_UNSUCCESSFUL;
1793 }
1794
1795 // Allocate memory for PortStatusChange to hold 2 USHORTs for each port on hub
1796 HubDeviceExtension->PortStatusChange = ExAllocatePoolWithTag(NonPagedPool,
1797 sizeof(ULONG) * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
1798 USB_HUB_TAG);
1799
1800 // Get the first Configuration Descriptor
1801 Pid = USBD_ParseConfigurationDescriptorEx(&HubDeviceExtension->HubConfigDescriptor,
1802 &HubDeviceExtension->HubConfigDescriptor,
1803 -1, -1, -1, -1, -1);
1804 if (Pid == NULL)
1805 {
1806 // failed parse hub descriptor
1807 DPRINT1("Failed to parse configuration descriptor\n");
1808 ExFreePool(Urb);
1809 return STATUS_UNSUCCESSFUL;
1810 }
1811
1812 // create configuration request
1813 InterfaceList[0].InterfaceDescriptor = Pid;
1814 ConfigUrb = USBD_CreateConfigurationRequestEx(&HubDeviceExtension->HubConfigDescriptor,
1815 (PUSBD_INTERFACE_LIST_ENTRY)&InterfaceList);
1816 if (ConfigUrb == NULL)
1817 {
1818 // failed to build urb
1819 DPRINT1("Failed to allocate urb\n");
1820 ExFreePool(Urb);
1821 return STATUS_INSUFFICIENT_RESOURCES;
1822 }
1823
1824 // send request
1825 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1826 IOCTL_INTERNAL_USB_SUBMIT_URB,
1827 ConfigUrb,
1828 NULL);
1829 if (!NT_SUCCESS(Status))
1830 {
1831 // failed to select configuration
1832 DPRINT1("Failed to select configuration with %x\n", Status);
1833 ExFreePool(Urb);
1834 ExFreePool(ConfigUrb);
1835 return Status;
1836 }
1837
1838 // store configuration & pipe handle
1839 HubDeviceExtension->ConfigurationHandle = ConfigUrb->UrbSelectConfiguration.ConfigurationHandle;
1840 HubDeviceExtension->PipeHandle = ConfigUrb->UrbSelectConfiguration.Interface.Pipes[0].PipeHandle;
1841 DPRINT("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
1842
1843 FDO_QueryInterface(DeviceObject, &HubDeviceExtension->DeviceInterface);
1844
1845
1846 // free urb
1847 ExFreePool(ConfigUrb);
1848
1849 // check if function is available
1850 if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed)
1851 {
1852 // is it high speed bus
1853 if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed(HubInterfaceBusContext))
1854 {
1855 // initialize usb 2.0 hub
1856 Status = HubDeviceExtension->HubInterface.Initialize20Hub(HubInterfaceBusContext,
1857 HubDeviceExtension->RootHubHandle, 1);
1858 DPRINT("Status %x\n", Status);
1859
1860 // FIXME handle error
1861 ASSERT(Status == STATUS_SUCCESS);
1862 }
1863 }
1864
1865
1866 // Enable power on all ports
1867 DPRINT("Enabling PortPower on all ports!\n");
1868 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1869 {
1870 Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_POWER);
1871 if (!NT_SUCCESS(Status))
1872 DPRINT1("Failed to power on port %d\n", PortId);
1873
1874 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
1875 if (!NT_SUCCESS(Status))
1876 DPRINT1("Failed to power on port %d\n", PortId);
1877 }
1878
1879 // init root hub notification
1880 if (HubDeviceExtension->HubInterface.RootHubInitNotification)
1881 {
1882 Status = HubDeviceExtension->HubInterface.RootHubInitNotification(HubInterfaceBusContext,
1883 DeviceObject,
1884 RootHubInitCallbackFunction);
1885 if (!NT_SUCCESS(Status))
1886 {
1887 DPRINT1("Failed to set callback\n");
1888 ExFreePool(Urb);
1889 return Status;
1890 }
1891 }
1892 else
1893 {
1894 // Send the first SCE Request
1895 QueryStatusChangeEndpoint(DeviceObject);
1896
1897 //
1898 // reset ports
1899 //
1900 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1901 {
1902 //
1903 // get port status
1904 //
1905 Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
1906 if (NT_SUCCESS(Status))
1907 {
1908 //
1909 // is there a device connected
1910 //
1911 if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
1912 {
1913 //
1914 // reset port
1915 //
1916 Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
1917 if (!NT_SUCCESS(Status))
1918 {
1919 DPRINT1("Failed to reset on port %d\n", PortId);
1920 }
1921 else
1922 {
1923 //
1924 // wait for the reset to be handled since we want to enumerate synchronously
1925 //
1926 KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
1927 Executive,
1928 KernelMode,
1929 FALSE,
1930 NULL);
1931 KeClearEvent(&HubDeviceExtension->ResetComplete);
1932 }
1933 }
1934 }
1935 }
1936 }
1937
1938 // free urb
1939 ExFreePool(Urb);
1940
1941 // done
1942 return Status;
1943 }
1944
1945 NTSTATUS
1946 USBHUB_FdoHandlePnp(
1947 IN PDEVICE_OBJECT DeviceObject,
1948 IN PIRP Irp)
1949 {
1950 PIO_STACK_LOCATION Stack;
1951 NTSTATUS Status = STATUS_SUCCESS;
1952 ULONG_PTR Information = 0;
1953 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1954
1955 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1956
1957 Stack = IoGetCurrentIrpStackLocation(Irp);
1958
1959 switch (Stack->MinorFunction)
1960 {
1961 case IRP_MN_START_DEVICE:
1962 {
1963 if (USBHUB_IsRootHubFDO(DeviceObject))
1964 {
1965 // start root hub fdo
1966 Status = USBHUB_FdoStartDevice(DeviceObject, Irp);
1967 }
1968 else
1969 {
1970 Status = USBHUB_ParentFDOStartDevice(DeviceObject, Irp);
1971 }
1972 break;
1973 }
1974
1975 case IRP_MN_QUERY_DEVICE_RELATIONS:
1976 {
1977 switch (Stack->Parameters.QueryDeviceRelations.Type)
1978 {
1979 case BusRelations:
1980 {
1981 PDEVICE_RELATIONS DeviceRelations = NULL;
1982 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
1983
1984 Status = USBHUB_FdoQueryBusRelations(DeviceObject, &DeviceRelations);
1985
1986 Information = (ULONG_PTR)DeviceRelations;
1987 break;
1988 }
1989 case RemovalRelations:
1990 {
1991 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
1992 return ForwardIrpAndForget(DeviceObject, Irp);
1993 }
1994 default:
1995 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
1996 Stack->Parameters.QueryDeviceRelations.Type);
1997 return ForwardIrpAndForget(DeviceObject, Irp);
1998 }
1999 break;
2000 }
2001 case IRP_MN_QUERY_REMOVE_DEVICE:
2002 case IRP_MN_QUERY_STOP_DEVICE:
2003 {
2004 Irp->IoStatus.Status = STATUS_SUCCESS;
2005 return ForwardIrpAndForget(DeviceObject, Irp);
2006 }
2007 case IRP_MN_REMOVE_DEVICE:
2008 {
2009 Irp->IoStatus.Status = STATUS_SUCCESS;
2010 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2011
2012 IoDetachDevice(HubDeviceExtension->LowerDeviceObject);
2013 IoDeleteDevice(DeviceObject);
2014
2015 return STATUS_SUCCESS;
2016 }
2017 case IRP_MN_QUERY_BUS_INFORMATION:
2018 {
2019 DPRINT("IRP_MN_QUERY_BUS_INFORMATION\n");
2020 break;
2021 }
2022 case IRP_MN_QUERY_ID:
2023 {
2024 DPRINT("IRP_MN_QUERY_ID\n");
2025 break;
2026 }
2027 case IRP_MN_QUERY_CAPABILITIES:
2028 {
2029 DPRINT("IRP_MN_QUERY_CAPABILITIES\n");
2030 break;
2031 }
2032 default:
2033 {
2034 DPRINT(" IRP_MJ_PNP / unknown minor function 0x%lx\n", Stack->MinorFunction);
2035 return ForwardIrpAndForget(DeviceObject, Irp);
2036 }
2037 }
2038
2039 Irp->IoStatus.Information = Information;
2040 Irp->IoStatus.Status = Status;
2041 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2042 return Status;
2043 }
2044
2045 NTSTATUS
2046 USBHUB_FdoHandleDeviceControl(
2047 IN PDEVICE_OBJECT DeviceObject,
2048 IN PIRP Irp)
2049 {
2050 PIO_STACK_LOCATION IoStack;
2051 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
2052 PUSB_NODE_INFORMATION NodeInformation;
2053 PHUB_DEVICE_EXTENSION HubDeviceExtension;
2054 PUSB_NODE_CONNECTION_INFORMATION NodeConnectionInfo;
2055 PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
2056 PUSB_NODE_CONNECTION_DRIVERKEY_NAME NodeKey;
2057 PUSB_NODE_CONNECTION_NAME ConnectionName;
2058 ULONG Index, Length;
2059
2060 // get stack location
2061 IoStack = IoGetCurrentIrpStackLocation(Irp);
2062
2063 // get device extension
2064 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
2065
2066 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_INFORMATION)
2067 {
2068 // is the buffer big enough
2069 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_INFORMATION))
2070 {
2071 // buffer too small
2072 Status = STATUS_BUFFER_TOO_SMALL;
2073 }
2074 else
2075 {
2076 // get buffer
2077 NodeInformation = (PUSB_NODE_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2078
2079 // sanity check
2080 ASSERT(NodeInformation);
2081
2082 // init buffer
2083 NodeInformation->NodeType = UsbHub;
2084 RtlCopyMemory(&NodeInformation->u.HubInformation.HubDescriptor, &HubDeviceExtension->HubDescriptor, sizeof(USB_HUB_DESCRIPTOR));
2085
2086 // FIXME is hub powered
2087 NodeInformation->u.HubInformation.HubIsBusPowered = TRUE;
2088
2089 // done
2090 Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
2091 Status = STATUS_SUCCESS;
2092 }
2093
2094
2095 }
2096 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_INFORMATION)
2097 {
2098 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_CONNECTION_INFORMATION))
2099 {
2100 // buffer too small
2101 Status = STATUS_BUFFER_TOO_SMALL;
2102 }
2103 else
2104 {
2105 // get node connection info
2106 NodeConnectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2107
2108 // sanity checks
2109 ASSERT(NodeConnectionInfo);
2110
2111 for(Index = 0; Index < USB_MAXCHILDREN; Index++)
2112 {
2113 if (HubDeviceExtension->ChildDeviceObject[Index] == NULL)
2114 continue;
2115
2116 // get child device extension
2117 ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
2118
2119 if (ChildDeviceExtension->PortNumber != NodeConnectionInfo->ConnectionIndex)
2120 continue;
2121
2122 // init node connection info
2123 RtlCopyMemory(&NodeConnectionInfo->DeviceDescriptor, &ChildDeviceExtension->DeviceDesc, sizeof(USB_DEVICE_DESCRIPTOR));
2124 NodeConnectionInfo->CurrentConfigurationValue = ChildDeviceExtension->FullConfigDesc->bConfigurationValue;
2125 NodeConnectionInfo->DeviceIsHub = FALSE; //FIXME support hubs
2126 NodeConnectionInfo->LowSpeed = ChildDeviceExtension->DeviceInformation.DeviceSpeed == UsbLowSpeed;
2127 NodeConnectionInfo->DeviceAddress = ChildDeviceExtension->DeviceInformation.DeviceAddress;
2128 NodeConnectionInfo->NumberOfOpenPipes = ChildDeviceExtension->DeviceInformation.NumberOfOpenPipes;
2129 NodeConnectionInfo->ConnectionStatus = DeviceConnected; //FIXME
2130
2131 if (NodeConnectionInfo->NumberOfOpenPipes)
2132 {
2133 DPRINT1("Need to copy pipe information\n");
2134 }
2135 break;
2136 }
2137 // done
2138 Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
2139 Status = STATUS_SUCCESS;
2140 }
2141 }
2142 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME)
2143 {
2144 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_CONNECTION_INFORMATION))
2145 {
2146 // buffer too small
2147 Status = STATUS_BUFFER_TOO_SMALL;
2148 }
2149 else
2150 {
2151 // get node connection info
2152 NodeKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
2153
2154 // sanity checks
2155 ASSERT(NodeKey);
2156
2157 for(Index = 0; Index < USB_MAXCHILDREN; Index++)
2158 {
2159 if (HubDeviceExtension->ChildDeviceObject[Index] == NULL)
2160 continue;
2161
2162 // get child device extension
2163 ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
2164
2165 if (ChildDeviceExtension->PortNumber != NodeKey->ConnectionIndex)
2166 continue;
2167
2168 // get driver key
2169 Status = IoGetDeviceProperty(HubDeviceExtension->ChildDeviceObject[Index], DevicePropertyDriverKeyName,
2170 IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME),
2171 NodeKey->DriverKeyName,
2172 &Length);
2173
2174 if (Status == STATUS_BUFFER_TOO_SMALL)
2175 {
2176 // normalize status
2177 Status = STATUS_SUCCESS;
2178 }
2179
2180 if (Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME) > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
2181 {
2182 // terminate node key name
2183 NodeKey->DriverKeyName[0] = UNICODE_NULL;
2184 Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
2185 }
2186 else
2187 {
2188 // result size
2189 Irp->IoStatus.Information = Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
2190 }
2191
2192 // length of driver name
2193 NodeKey->ActualLength = Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
2194 break;
2195 }
2196 }
2197 }
2198 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_NAME)
2199 {
2200 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_CONNECTION_NAME))
2201 {
2202 // buffer too small
2203 Status = STATUS_BUFFER_TOO_SMALL;
2204 }
2205 else
2206 {
2207 // FIXME support hubs
2208 ConnectionName = (PUSB_NODE_CONNECTION_NAME)Irp->AssociatedIrp.SystemBuffer;
2209 ConnectionName->ActualLength = 0;
2210 ConnectionName->NodeName[0] = UNICODE_NULL;
2211
2212 // done
2213 Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_NAME);
2214 Status = STATUS_SUCCESS;
2215 }
2216 }
2217 else
2218 {
2219 DPRINT1("UNIMPLEMENTED FdoHandleDeviceControl IoCtl %x InputBufferLength %x OutputBufferLength %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode,
2220 IoStack->Parameters.DeviceIoControl.InputBufferLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength);
2221 }
2222
2223 // finish irp
2224 Irp->IoStatus.Status = Status;
2225 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2226
2227 return Status;
2228 }
2229