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