[USBAUDIO]
[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 ULONG PortId;
214 BOOLEAN SignalResetComplete = FALSE;
215
216 DPRINT("Entered DeviceStatusChangeThread, Context %x\n", Context);
217
218 WorkItemData = (PWORK_ITEM_DATA)Context;
219 DeviceObject = (PDEVICE_OBJECT)WorkItemData->Context;
220 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
221 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
222 //
223 // Loop all ports
224 //
225 for (PortId = 1; PortId <= HubDeviceExtension->UsbExtHubInfo.NumberOfPorts; PortId++)
226 {
227 //
228 // Get Port Status
229 //
230 Status = GetPortStatusAndChange(RootHubDeviceObject, PortId, &PortStatus);
231 if (!NT_SUCCESS(Status))
232 {
233 DPRINT1("Failed to get port status for port %d, Status %x\n", PortId, Status);
234 // FIXME: Do we really want to halt further SCE requests?
235 return;
236 }
237
238 DPRINT("Port %d Status %x\n", PortId, PortStatus.Status);
239 DPRINT("Port %d Change %x\n", PortId, PortStatus.Change);
240
241
242 //
243 // Check for new device connection
244 //
245 if (PortStatus.Change & USB_PORT_STATUS_CONNECT)
246 {
247 //
248 // Clear Port Connect
249 //
250 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
251 if (!NT_SUCCESS(Status))
252 {
253 DPRINT1("Failed to clear connection change for port %d\n", PortId);
254 continue;
255 }
256
257 //
258 // Is this a connect or disconnect?
259 //
260 if (!(PortStatus.Status & USB_PORT_STATUS_CONNECT))
261 {
262 DPRINT1("Device disconnected from port %d\n", PortId);
263
264 Status = DestroyUsbChildDeviceObject(DeviceObject, PortId);
265 if (!NT_SUCCESS(Status))
266 {
267 DPRINT1("Failed to delete child device object after disconnect\n");
268 continue;
269 }
270 }
271 else
272 {
273 DPRINT1("Device connected from port %d\n", PortId);
274
275 // No SCE completion done for clearing C_PORT_CONNECT
276
277 //
278 // Reset Port
279 //
280 Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_RESET);
281 if (!NT_SUCCESS(Status))
282 {
283 DPRINT1("Failed to reset port %d\n", PortId);
284 SignalResetComplete = TRUE;
285 continue;
286 }
287 }
288 }
289 else if (PortStatus.Change & USB_PORT_STATUS_ENABLE)
290 {
291 //
292 // Clear Enable
293 //
294 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_ENABLE);
295 if (!NT_SUCCESS(Status))
296 {
297 DPRINT1("Failed to clear enable change on port %d\n", PortId);
298 continue;
299 }
300 }
301 else if (PortStatus.Change & USB_PORT_STATUS_RESET)
302 {
303 //
304 // Request event signalling later
305 //
306 SignalResetComplete = TRUE;
307
308 //
309 // Clear Reset
310 //
311 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_RESET);
312 if (!NT_SUCCESS(Status))
313 {
314 DPRINT1("Failed to clear reset change on port %d\n", PortId);
315 continue;
316 }
317
318 //
319 // Get Port Status
320 //
321 Status = GetPortStatusAndChange(RootHubDeviceObject, PortId, &PortStatus);
322 if (!NT_SUCCESS(Status))
323 {
324 DPRINT1("Failed to get port status for port %d, Status %x\n", PortId, Status);
325 // FIXME: Do we really want to halt further SCE requests?
326 return;
327 }
328
329 DPRINT("Port %d Status %x\n", PortId, PortStatus.Status);
330 DPRINT("Port %d Change %x\n", PortId, PortStatus.Change);
331
332 //
333 // Check that reset was cleared
334 //
335 if(PortStatus.Change & USB_PORT_STATUS_RESET)
336 {
337 DPRINT1("Port did not clear reset! Possible Hardware problem!\n");
338 continue;
339 }
340
341 //
342 // Check if the device is still connected
343 //
344 if (!(PortStatus.Status & USB_PORT_STATUS_CONNECT))
345 {
346 DPRINT1("Device has been disconnected\n");
347 continue;
348 }
349
350 //
351 // Make sure its Connected and Enabled
352 //
353 if (!(PortStatus.Status & (USB_PORT_STATUS_CONNECT | USB_PORT_STATUS_ENABLE)))
354 {
355 DPRINT1("Usb Device is not connected and enabled!\n");
356 //
357 // Attempt another reset
358 //
359 Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_RESET);
360 if (!NT_SUCCESS(Status))
361 {
362 DPRINT1("Failed to reset port %d\n", PortId);
363 }
364 continue;
365 }
366
367 //
368 // This is a new device
369 //
370 Status = CreateUsbChildDeviceObject(DeviceObject, PortId, NULL, PortStatus.Status);
371 }
372 }
373
374 ExFreePool(WorkItemData);
375
376 //
377 // Send another SCE Request
378 //
379 DPRINT("Sending another SCE!\n");
380 QueryStatusChangeEndpoint(DeviceObject);
381
382 //
383 // Check if a reset event was satisfied
384 //
385 if (SignalResetComplete)
386 {
387 //
388 // Signal anyone waiting on it
389 //
390 KeSetEvent(&HubDeviceExtension->ResetComplete, IO_NO_INCREMENT, FALSE);
391 }
392 }
393
394 NTSTATUS
395 NTAPI
396 StatusChangeEndpointCompletion(
397 IN PDEVICE_OBJECT DeviceObject,
398 IN PIRP Irp,
399 IN PVOID Context)
400 {
401 PDEVICE_OBJECT RealDeviceObject;
402 PHUB_DEVICE_EXTENSION HubDeviceExtension;
403 PWORK_ITEM_DATA WorkItemData;
404
405 RealDeviceObject = (PDEVICE_OBJECT)Context;
406 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)RealDeviceObject->DeviceExtension;
407
408 //
409 // NOTE: USBPORT frees this IRP
410 //
411 DPRINT("Received Irp %x, HubDeviceExtension->PendingSCEIrp %x\n", Irp, HubDeviceExtension->PendingSCEIrp);
412 //IoFreeIrp(Irp);
413
414 //
415 // Create and initialize work item data
416 //
417 WorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(WORK_ITEM_DATA), USB_HUB_TAG);
418 if (!WorkItemData)
419 {
420 DPRINT1("Failed to allocate memory!n");
421 return STATUS_INSUFFICIENT_RESOURCES;
422 }
423 WorkItemData->Context = RealDeviceObject;
424
425 DPRINT("Queuing work item\n");
426
427 //
428 // Queue the work item to handle initializing the device
429 //
430 ExInitializeWorkItem(&WorkItemData->WorkItem, DeviceStatusChangeThread, (PVOID)WorkItemData);
431 ExQueueWorkItem(&WorkItemData->WorkItem, DelayedWorkQueue);
432
433 //
434 // Return more processing required so the IO Manger doesn’t try to mess with IRP just freed
435 //
436 return STATUS_MORE_PROCESSING_REQUIRED;
437 }
438
439 NTSTATUS
440 QueryStatusChangeEndpoint(
441 IN PDEVICE_OBJECT DeviceObject)
442 {
443 PDEVICE_OBJECT RootHubDeviceObject;
444 PIO_STACK_LOCATION Stack;
445 PHUB_DEVICE_EXTENSION HubDeviceExtension;
446 PURB PendingSCEUrb;
447
448 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
449 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
450
451 //
452 // Allocate a URB
453 //
454 PendingSCEUrb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
455
456 //
457 // Initialize URB for Status Change Endpoint request
458 //
459 UsbBuildInterruptOrBulkTransferRequest(PendingSCEUrb,
460 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
461 HubDeviceExtension->PipeHandle,
462 HubDeviceExtension->PortStatusChange,
463 NULL,
464 sizeof(USHORT) * 2 * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
465 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
466 NULL);
467
468 // Set the device handle
469 PendingSCEUrb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
470
471 //
472 // Allocate an Irp
473 //
474 HubDeviceExtension->PendingSCEIrp = ExAllocatePoolWithTag(NonPagedPool,
475 IoSizeOfIrp(RootHubDeviceObject->StackSize),
476 USB_HUB_TAG);
477 /*
478 HubDeviceExtension->PendingSCEIrp = IoAllocateIrp(RootHubDeviceObject->StackSize,
479 FALSE);
480 */
481 DPRINT("Allocated IRP %x\n", HubDeviceExtension->PendingSCEIrp);
482
483 if (!HubDeviceExtension->PendingSCEIrp)
484 {
485 DPRINT1("USBHUB: Failed to allocate IRP for SCE request!\n");
486 return STATUS_INSUFFICIENT_RESOURCES;
487 }
488
489 //
490 // Initialize the IRP
491 //
492 IoInitializeIrp(HubDeviceExtension->PendingSCEIrp,
493 IoSizeOfIrp(RootHubDeviceObject->StackSize),
494 RootHubDeviceObject->StackSize);
495
496 HubDeviceExtension->PendingSCEIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
497 HubDeviceExtension->PendingSCEIrp->IoStatus.Information = 0;
498 HubDeviceExtension->PendingSCEIrp->Flags = 0;
499 HubDeviceExtension->PendingSCEIrp->UserBuffer = NULL;
500
501 //
502 // Get the Next Stack Location and Initialize it
503 //
504 Stack = IoGetNextIrpStackLocation(HubDeviceExtension->PendingSCEIrp);
505 Stack->DeviceObject = DeviceObject;
506 Stack->Parameters.Others.Argument1 = PendingSCEUrb;
507 Stack->Parameters.Others.Argument2 = NULL;
508 Stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
509 Stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
510
511 //
512 // Set the completion routine for when device is connected to root hub
513 //
514 IoSetCompletionRoutine(HubDeviceExtension->PendingSCEIrp,
515 StatusChangeEndpointCompletion,
516 DeviceObject,
517 TRUE,
518 TRUE,
519 TRUE);
520
521 //
522 // Send to RootHub
523 //
524 DPRINT("DeviceObject is %x\n", DeviceObject);
525 DPRINT("Iocalldriver %x with irp %x\n", RootHubDeviceObject, HubDeviceExtension->PendingSCEIrp);
526 IoCallDriver(RootHubDeviceObject, HubDeviceExtension->PendingSCEIrp);
527
528 return STATUS_PENDING;
529 }
530
531 NTSTATUS
532 QueryInterface(
533 IN PDEVICE_OBJECT DeviceObject,
534 IN CONST GUID InterfaceType,
535 IN LONG Size,
536 IN LONG Version,
537 OUT PVOID Interface)
538 {
539 KEVENT Event;
540 PIRP Irp;
541 IO_STATUS_BLOCK IoStatus;
542 NTSTATUS Status;
543 PIO_STACK_LOCATION Stack = NULL;
544
545 //
546 // Initialize the Event used to wait for Irp completion
547 //
548 KeInitializeEvent(&Event, NotificationEvent, FALSE);
549
550 //
551 // Build Control Request
552 //
553 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
554 DeviceObject,
555 NULL,
556 0,
557 NULL,
558 &Event,
559 &IoStatus);
560
561 //
562 // Get Next Stack Location and Initialize it.
563 //
564 Stack = IoGetNextIrpStackLocation(Irp);
565 Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
566 Stack->Parameters.QueryInterface.InterfaceType= &InterfaceType;//USB_BUS_INTERFACE_HUB_GUID;
567 Stack->Parameters.QueryInterface.Size = Size;
568 Stack->Parameters.QueryInterface.Version = Version;
569 Stack->Parameters.QueryInterface.Interface = Interface;
570 Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
571
572 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
1039 ExFreePool(SerialBuffer);
1040
1041 UsbChildExtension->usInstanceId.Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
1042 if (UsbChildExtension->usInstanceId.Buffer == NULL)
1043 {
1044 DPRINT1("Error: failed to allocate %lu bytes\n", Index * sizeof(WCHAR));
1045 return STATUS_INSUFFICIENT_RESOURCES;
1046 }
1047
1048 //
1049 // copy instance id
1050 //
1051 RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR));
1052 UsbChildExtension->usInstanceId.Length = UsbChildExtension->usInstanceId.MaximumLength = Index * sizeof(WCHAR);
1053
1054 DPRINT("Usb InstanceId %wZ InstanceCount %x\n", &UsbChildExtension->usInstanceId, HubDeviceExtension->InstanceCount);
1055 return Status;
1056 }
1057 }
1058
1059 //
1060 // the device did not provide a serial number, or failed to retrieve the serial number
1061 // lets create a pseudo instance id
1062 //
1063 Index = swprintf(Buffer, L"%04d&%04d", HubDeviceExtension->InstanceCount, UsbChildExtension->PortNumber) + 1;
1064 UsbChildExtension->usInstanceId.Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
1065 if (UsbChildExtension->usInstanceId.Buffer == NULL)
1066 {
1067 DPRINT1("Error: failed to allocate %lu bytes\n", Index * sizeof(WCHAR));
1068 Status = STATUS_INSUFFICIENT_RESOURCES;
1069 return Status;
1070 }
1071
1072 //
1073 // copy instance id
1074 //
1075 RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR));
1076 UsbChildExtension->usInstanceId.Length = UsbChildExtension->usInstanceId.MaximumLength = Index * sizeof(WCHAR);
1077
1078 DPRINT("usDeviceId %wZ\n", &UsbChildExtension->usInstanceId);
1079 return STATUS_SUCCESS;
1080 }
1081
1082 NTSTATUS
1083 DestroyUsbChildDeviceObject(
1084 IN PDEVICE_OBJECT UsbHubDeviceObject,
1085 IN LONG PortId)
1086 {
1087 PHUB_DEVICE_EXTENSION HubDeviceExtension = (PHUB_DEVICE_EXTENSION)UsbHubDeviceObject->DeviceExtension;
1088 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension = NULL;
1089 PDEVICE_OBJECT ChildDeviceObject = NULL;
1090 ULONG Index = 0;
1091
1092 DPRINT("Removing device on port %d (Child index: %d)\n", PortId, Index);
1093
1094 for (Index = 0; Index < USB_MAXCHILDREN; Index++)
1095 {
1096 if (HubDeviceExtension->ChildDeviceObject[Index])
1097 {
1098 UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
1099
1100 /* Check if it matches the port ID */
1101 if (UsbChildExtension->PortNumber == PortId)
1102 {
1103 /* We found it */
1104 ChildDeviceObject = HubDeviceExtension->ChildDeviceObject[Index];
1105 break;
1106 }
1107 }
1108 }
1109
1110 /* Fail the request if the device doesn't exist */
1111 if (!ChildDeviceObject)
1112 {
1113 DPRINT1("Removal request for non-existant device!\n");
1114 return STATUS_UNSUCCESSFUL;
1115 }
1116
1117 /* Remove the device from the table */
1118 HubDeviceExtension->ChildDeviceObject[Index] = NULL;
1119
1120 /* Invalidate device relations for the root hub */
1121 IoInvalidateDeviceRelations(HubDeviceExtension->RootHubPhysicalDeviceObject, BusRelations);
1122
1123 /* The rest of the removal process takes place in IRP_MN_REMOVE_DEVICE handling for the PDO */
1124 return STATUS_SUCCESS;
1125 }
1126
1127 NTSTATUS
1128 CreateUsbChildDeviceObject(
1129 IN PDEVICE_OBJECT UsbHubDeviceObject,
1130 IN LONG PortId,
1131 OUT PDEVICE_OBJECT *UsbChildDeviceObject,
1132 IN ULONG PortStatus)
1133 {
1134 NTSTATUS Status;
1135 PDEVICE_OBJECT RootHubDeviceObject, NewChildDeviceObject;
1136 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1137 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
1138 PUSB_BUS_INTERFACE_HUB_V5 HubInterface;
1139 ULONG ChildDeviceCount, UsbDeviceNumber = 0;
1140 WCHAR CharDeviceName[64];
1141 UNICODE_STRING DeviceName;
1142 ULONG ConfigDescSize, DeviceDescSize, DeviceInfoSize;
1143 PVOID HubInterfaceBusContext;
1144 USB_CONFIGURATION_DESCRIPTOR ConfigDesc;
1145
1146 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) UsbHubDeviceObject->DeviceExtension;
1147 HubInterface = &HubDeviceExtension->HubInterface;
1148 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
1149 HubInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
1150 //
1151 // Find an empty slot in the child device array
1152 //
1153 for (ChildDeviceCount = 0; ChildDeviceCount < USB_MAXCHILDREN; ChildDeviceCount++)
1154 {
1155 if (HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] == NULL)
1156 {
1157 DPRINT("Found unused entry at %d\n", ChildDeviceCount);
1158 break;
1159 }
1160 }
1161
1162 //
1163 // Check if the limit has been reached for maximum usb devices
1164 //
1165 if (ChildDeviceCount == USB_MAXCHILDREN)
1166 {
1167 DPRINT1("USBHUB: Too many child devices!\n");
1168 return STATUS_UNSUCCESSFUL;
1169 }
1170
1171 while (TRUE)
1172 {
1173 //
1174 // Create a Device Name
1175 //
1176 swprintf(CharDeviceName, L"\\Device\\USBPDO-%d", UsbDeviceNumber);
1177
1178 //
1179 // Initialize UnicodeString
1180 //
1181 RtlInitUnicodeString(&DeviceName, CharDeviceName);
1182
1183 //
1184 // Create a DeviceObject
1185 //
1186 Status = IoCreateDevice(UsbHubDeviceObject->DriverObject,
1187 sizeof(HUB_CHILDDEVICE_EXTENSION),
1188 NULL,
1189 FILE_DEVICE_CONTROLLER,
1190 FILE_AUTOGENERATED_DEVICE_NAME,
1191 FALSE,
1192 &NewChildDeviceObject);
1193
1194 //
1195 // Check if the name is already in use
1196 //
1197 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
1198 {
1199 //
1200 // Try next name
1201 //
1202 UsbDeviceNumber++;
1203 continue;
1204 }
1205
1206 //
1207 // Check for other errors
1208 //
1209 if (!NT_SUCCESS(Status))
1210 {
1211 DPRINT1("USBHUB: IoCreateDevice failed with status %x\n", Status);
1212 return Status;
1213 }
1214
1215 DPRINT("USBHUB: Created Device %x\n", NewChildDeviceObject);
1216 break;
1217 }
1218
1219 NewChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
1220
1221 //
1222 // Assign the device extensions
1223 //
1224 UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)NewChildDeviceObject->DeviceExtension;
1225 RtlZeroMemory(UsbChildExtension, sizeof(HUB_CHILDDEVICE_EXTENSION));
1226 UsbChildExtension->ParentDeviceObject = UsbHubDeviceObject;
1227 UsbChildExtension->PortNumber = PortId;
1228
1229 // copy device interface
1230 RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
1231
1232
1233 //
1234 // Create the UsbDeviceObject
1235 //
1236 Status = HubInterface->CreateUsbDevice(HubInterfaceBusContext,
1237 (PVOID)&UsbChildExtension->UsbDeviceHandle,
1238 HubDeviceExtension->RootHubHandle,
1239 PortStatus,
1240 PortId);
1241 if (!NT_SUCCESS(Status))
1242 {
1243 DPRINT1("USBHUB: CreateUsbDevice failed with status %x\n", Status);
1244 goto Cleanup;
1245 }
1246
1247 // copy device interface
1248 RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
1249
1250 // FIXME replace buscontext
1251 UsbChildExtension->DeviceInterface.BusContext = UsbChildExtension->UsbDeviceHandle;
1252
1253 //
1254 // Initialize UsbDevice
1255 //
1256 Status = HubInterface->InitializeUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle);
1257 if (!NT_SUCCESS(Status))
1258 {
1259 DPRINT1("USBHUB: InitializeUsbDevice failed with status %x\n", Status);
1260 goto Cleanup;
1261 }
1262
1263 DPRINT("Usb Device Handle %x\n", UsbChildExtension->UsbDeviceHandle);
1264
1265 ConfigDescSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
1266 DeviceDescSize = sizeof(USB_DEVICE_DESCRIPTOR);
1267
1268 //
1269 // Get the descriptors
1270 //
1271 Status = HubInterface->GetUsbDescriptors(HubInterfaceBusContext,
1272 UsbChildExtension->UsbDeviceHandle,
1273 (PUCHAR)&UsbChildExtension->DeviceDesc,
1274 &DeviceDescSize,
1275 (PUCHAR)&ConfigDesc,
1276 &ConfigDescSize);
1277 if (!NT_SUCCESS(Status))
1278 {
1279 DPRINT1("USBHUB: GetUsbDescriptors failed with status %x\n", Status);
1280 goto Cleanup;
1281 }
1282
1283 //DumpDeviceDescriptor(&UsbChildExtension->DeviceDesc);
1284 //DumpConfigurationDescriptor(&ConfigDesc);
1285
1286 //
1287 // FIXME: Support more than one configuration and one interface?
1288 //
1289 if (UsbChildExtension->DeviceDesc.bNumConfigurations > 1)
1290 {
1291 DPRINT1("Warning: Device has more than one configuration. Only one configuration (the first) is supported!\n");
1292 }
1293
1294 if (ConfigDesc.bNumInterfaces > 1)
1295 {
1296 DPRINT1("Warning: Device has more than one interface. Only one interface (the first) is currently supported\n");
1297 }
1298
1299 ConfigDescSize = ConfigDesc.wTotalLength;
1300
1301 //
1302 // Allocate memory for the first full descriptor, including interfaces and endpoints.
1303 //
1304 UsbChildExtension->FullConfigDesc = ExAllocatePoolWithTag(PagedPool, ConfigDescSize, USB_HUB_TAG);
1305
1306 //
1307 // Retrieve the full configuration descriptor
1308 //
1309 Status = GetUsbDeviceDescriptor(NewChildDeviceObject,
1310 USB_CONFIGURATION_DESCRIPTOR_TYPE,
1311 0,
1312 0,
1313 UsbChildExtension->FullConfigDesc,
1314 ConfigDescSize);
1315
1316 if (!NT_SUCCESS(Status))
1317 {
1318 DPRINT1("USBHUB: GetUsbDeviceDescriptor failed with status %x\n", Status);
1319 goto Cleanup;
1320 }
1321
1322 // query device details
1323 Status = HubInterface->QueryDeviceInformation(HubInterfaceBusContext,
1324 UsbChildExtension->UsbDeviceHandle,
1325 &UsbChildExtension->DeviceInformation,
1326 sizeof(USB_DEVICE_INFORMATION_0),
1327 &DeviceInfoSize);
1328
1329
1330 //DumpFullConfigurationDescriptor(UsbChildExtension->FullConfigDesc);
1331
1332 //
1333 // Construct all the strings that will describe the device to PNP
1334 //
1335 Status = CreateDeviceIds(NewChildDeviceObject);
1336 if (!NT_SUCCESS(Status))
1337 {
1338 DPRINT1("Failed to create strings needed to describe device to PNP.\n");
1339 goto Cleanup;
1340 }
1341
1342 HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] = NewChildDeviceObject;
1343 HubDeviceExtension->InstanceCount++;
1344
1345 IoInvalidateDeviceRelations(RootHubDeviceObject, BusRelations);
1346 return STATUS_SUCCESS;
1347
1348 Cleanup:
1349
1350 //
1351 // Remove the usb device if it was created
1352 //
1353 if (UsbChildExtension->UsbDeviceHandle)
1354 HubInterface->RemoveUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle, 0);
1355
1356 //
1357 // Free full configuration descriptor if one was allocated
1358 //
1359 if (UsbChildExtension->FullConfigDesc)
1360 ExFreePool(UsbChildExtension->FullConfigDesc);
1361
1362 //
1363 // Free ID buffers if they were allocated in CreateDeviceIds()
1364 //
1365 if (UsbChildExtension->usCompatibleIds.Buffer)
1366 ExFreePool(UsbChildExtension->usCompatibleIds.Buffer);
1367
1368 if (UsbChildExtension->usDeviceId.Buffer)
1369 ExFreePool(UsbChildExtension->usDeviceId.Buffer);
1370
1371 if (UsbChildExtension->usHardwareIds.Buffer)
1372 ExFreePool(UsbChildExtension->usHardwareIds.Buffer);
1373
1374 if (UsbChildExtension->usInstanceId.Buffer)
1375 ExFreePool(UsbChildExtension->usInstanceId.Buffer);
1376
1377 //
1378 // Delete the device object
1379 //
1380 IoDeleteDevice(NewChildDeviceObject);
1381 return Status;
1382 }
1383
1384 NTSTATUS
1385 USBHUB_FdoQueryBusRelations(
1386 IN PDEVICE_OBJECT DeviceObject,
1387 OUT PDEVICE_RELATIONS* pDeviceRelations)
1388 {
1389 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1390 PDEVICE_RELATIONS DeviceRelations;
1391 ULONG i;
1392 ULONG Children = 0;
1393 ULONG NeededSize;
1394
1395 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1396
1397 //
1398 // Count the number of children
1399 //
1400 for (i = 0; i < USB_MAXCHILDREN; i++)
1401 {
1402
1403 if (HubDeviceExtension->ChildDeviceObject[i] == NULL)
1404 {
1405 continue;
1406 }
1407 Children++;
1408 }
1409
1410 NeededSize = sizeof(DEVICE_RELATIONS);
1411 if (Children > 1)
1412 NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
1413
1414 //
1415 // Allocate DeviceRelations
1416 //
1417 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool,
1418 NeededSize);
1419
1420 if (!DeviceRelations)
1421 return STATUS_INSUFFICIENT_RESOURCES;
1422 DeviceRelations->Count = Children;
1423 Children = 0;
1424
1425 //
1426 // Fill in return structure
1427 //
1428 for (i = 0; i < USB_MAXCHILDREN; i++)
1429 {
1430 if (HubDeviceExtension->ChildDeviceObject[i])
1431 {
1432 ObReferenceObject(HubDeviceExtension->ChildDeviceObject[i]);
1433 HubDeviceExtension->ChildDeviceObject[i]->Flags &= ~DO_DEVICE_INITIALIZING;
1434 DeviceRelations->Objects[Children++] = HubDeviceExtension->ChildDeviceObject[i];
1435 }
1436 }
1437
1438 ASSERT(Children == DeviceRelations->Count);
1439 *pDeviceRelations = DeviceRelations;
1440
1441 return STATUS_SUCCESS;
1442 }
1443
1444 VOID
1445 NTAPI
1446 RootHubInitCallbackFunction(
1447 PVOID Context)
1448 {
1449 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
1450 NTSTATUS Status;
1451 ULONG PortId;
1452 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1453 PORT_STATUS_CHANGE StatusChange;
1454
1455 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1456
1457 DPRINT("RootHubInitCallbackFunction Sending the initial SCE Request %x\n", DeviceObject);
1458
1459 //
1460 // Send the first SCE Request
1461 //
1462 QueryStatusChangeEndpoint(DeviceObject);
1463
1464 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1465 {
1466 //
1467 // get port status
1468 //
1469 Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
1470 if (NT_SUCCESS(Status))
1471 {
1472 //
1473 // is there a device connected
1474 //
1475 if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
1476 {
1477 //
1478 // reset port
1479 //
1480 Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
1481 if (!NT_SUCCESS(Status))
1482 {
1483 DPRINT1("Failed to reset on port %d\n", PortId);
1484 }
1485 else
1486 {
1487 //
1488 // wait for the reset to be handled since we want to enumerate synchronously
1489 //
1490 KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
1491 Executive,
1492 KernelMode,
1493 FALSE,
1494 NULL);
1495 KeClearEvent(&HubDeviceExtension->ResetComplete);
1496 }
1497 }
1498 }
1499 }
1500 }
1501
1502 BOOLEAN
1503 USBHUB_IsRootHubFDO(
1504 IN PDEVICE_OBJECT DeviceObject)
1505 {
1506 NTSTATUS Status;
1507 PDEVICE_OBJECT RootHubPhysicalDeviceObject = NULL;
1508 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1509
1510 // get hub device extension
1511 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1512
1513 // Get the Root Hub Pdo
1514 Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
1515 IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
1516 &RootHubPhysicalDeviceObject,
1517 NULL);
1518
1519 // FIXME handle error
1520 ASSERT(NT_SUCCESS(Status));
1521
1522 // physical device object is only obtained for root hubs
1523 return (RootHubPhysicalDeviceObject != NULL);
1524 }
1525
1526
1527 NTSTATUS
1528 USBHUB_FdoStartDevice(
1529 IN PDEVICE_OBJECT DeviceObject,
1530 IN PIRP Irp)
1531 {
1532 PURB Urb;
1533 PUSB_INTERFACE_DESCRIPTOR Pid;
1534 ULONG Result = 0, PortId;
1535 USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}};
1536 PURB ConfigUrb = NULL;
1537 ULONG HubStatus;
1538 NTSTATUS Status = STATUS_SUCCESS;
1539 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1540 PDEVICE_OBJECT RootHubDeviceObject;
1541 PVOID HubInterfaceBusContext;
1542 PORT_STATUS_CHANGE StatusChange;
1543
1544 // get hub device extension
1545 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1546
1547 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
1548
1549 // Allocated size including the sizeof USBD_INTERFACE_LIST_ENTRY
1550 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY), USB_HUB_TAG);
1551 if (!Urb)
1552 {
1553 // no memory
1554 return STATUS_INSUFFICIENT_RESOURCES;
1555 }
1556
1557 // zero urb
1558 RtlZeroMemory(Urb, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY));
1559
1560 // Get the Root Hub Pdo
1561 Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
1562 IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
1563 &HubDeviceExtension->RootHubPhysicalDeviceObject,
1564 &HubDeviceExtension->RootHubFunctionalDeviceObject);
1565 if (!NT_SUCCESS(Status))
1566 {
1567 // failed to obtain hub pdo
1568 DPRINT1("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO failed with %x\n", Status);
1569 ExFreePool(Urb);
1570 return Status;
1571 }
1572
1573 // sanity checks
1574 ASSERT(HubDeviceExtension->RootHubPhysicalDeviceObject);
1575 ASSERT(HubDeviceExtension->RootHubFunctionalDeviceObject);
1576
1577 // get roothub
1578 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
1579
1580 // Send the StartDevice to RootHub
1581 Status = ForwardIrpAndWait(RootHubDeviceObject, Irp);
1582
1583 if (!NT_SUCCESS(Status))
1584 {
1585 // failed to start pdo
1586 DPRINT1("Failed to start the RootHub PDO\n");
1587 ExFreePool(Urb);
1588 return Status;
1589 }
1590
1591 // Get the current number of hubs
1592 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1593 IOCTL_INTERNAL_USB_GET_HUB_COUNT,
1594 &HubDeviceExtension->NumberOfHubs, NULL);
1595 if (!NT_SUCCESS(Status))
1596 {
1597 // failed to get number of hubs
1598 DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_COUNT failed with %x\n", Status);
1599 ExFreePool(Urb);
1600 return Status;
1601 }
1602
1603 // Get the Hub Interface
1604 Status = QueryInterface(RootHubDeviceObject,
1605 USB_BUS_INTERFACE_HUB_GUID,
1606 sizeof(USB_BUS_INTERFACE_HUB_V5),
1607 USB_BUSIF_HUB_VERSION_5,
1608 (PVOID)&HubDeviceExtension->HubInterface);
1609
1610 if (!NT_SUCCESS(Status))
1611 {
1612 // failed to get root hub interface
1613 DPRINT1("Failed to get HUB_GUID interface with status 0x%08lx\n", Status);
1614 ExFreePool(Urb);
1615 return Status;
1616 }
1617
1618 HubInterfaceBusContext = HubDeviceExtension->HubInterface.BusContext;
1619
1620 // Get the USBDI Interface
1621 Status = QueryInterface(RootHubDeviceObject,
1622 USB_BUS_INTERFACE_USBDI_GUID,
1623 sizeof(USB_BUS_INTERFACE_USBDI_V2),
1624 USB_BUSIF_USBDI_VERSION_2,
1625 (PVOID)&HubDeviceExtension->UsbDInterface);
1626
1627 if (!NT_SUCCESS(Status))
1628 {
1629 // failed to get usbdi interface
1630 DPRINT1("Failed to get USBDI_GUID interface with status 0x%08lx\n", Status);
1631 ExFreePool(Urb);
1632 return Status;
1633 }
1634
1635 // Get Root Hub Device Handle
1636 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1637 IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
1638 &HubDeviceExtension->RootHubHandle,
1639 NULL);
1640
1641 if (!NT_SUCCESS(Status))
1642 {
1643 // failed
1644 DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE failed with status 0x%08lx\n", Status);
1645 ExFreePool(Urb);
1646 return Status;
1647 }
1648
1649 //
1650 // Get Hub Device Information
1651 //
1652 Status = HubDeviceExtension->HubInterface.QueryDeviceInformation(HubInterfaceBusContext,
1653 HubDeviceExtension->RootHubHandle,
1654 &HubDeviceExtension->DeviceInformation,
1655 sizeof(USB_DEVICE_INFORMATION_0),
1656 &Result);
1657
1658 DPRINT("Status %x, Result 0x%08lx\n", Status, Result);
1659 DPRINT("InformationLevel %x\n", HubDeviceExtension->DeviceInformation.InformationLevel);
1660 DPRINT("ActualLength %x\n", HubDeviceExtension->DeviceInformation.ActualLength);
1661 DPRINT("PortNumber %x\n", HubDeviceExtension->DeviceInformation.PortNumber);
1662 DPRINT("DeviceDescriptor %x\n", HubDeviceExtension->DeviceInformation.DeviceDescriptor);
1663 DPRINT("HubAddress %x\n", HubDeviceExtension->DeviceInformation.HubAddress);
1664 DPRINT("NumberofPipes %x\n", HubDeviceExtension->DeviceInformation.NumberOfOpenPipes);
1665
1666 // Get Root Hubs Device Descriptor
1667 UsbBuildGetDescriptorRequest(Urb,
1668 sizeof(Urb->UrbControlDescriptorRequest),
1669 USB_DEVICE_DESCRIPTOR_TYPE,
1670 0,
1671 0,
1672 &HubDeviceExtension->HubDeviceDescriptor,
1673 NULL,
1674 sizeof(USB_DEVICE_DESCRIPTOR),
1675 NULL);
1676
1677 // set device handle
1678 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1679
1680 // get hub device descriptor
1681 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1682 IOCTL_INTERNAL_USB_SUBMIT_URB,
1683 Urb,
1684 NULL);
1685
1686 if (!NT_SUCCESS(Status))
1687 {
1688 // failed to get device descriptor of hub
1689 DPRINT1("Failed to get HubDeviceDescriptor!\n");
1690 ExFreePool(Urb);
1691 return Status;
1692 }
1693
1694 // build configuration request
1695 UsbBuildGetDescriptorRequest(Urb,
1696 sizeof(Urb->UrbControlDescriptorRequest),
1697 USB_CONFIGURATION_DESCRIPTOR_TYPE,
1698 0,
1699 0,
1700 &HubDeviceExtension->HubConfigDescriptor,
1701 NULL,
1702 sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR),
1703 NULL);
1704
1705 // set device handle
1706 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1707
1708 // request configuration descriptor
1709 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1710 IOCTL_INTERNAL_USB_SUBMIT_URB,
1711 Urb,
1712 NULL);
1713
1714 if (!NT_SUCCESS(Status))
1715 {
1716 // failed to get configuration descriptor
1717 DPRINT1("Failed to get RootHub Configuration with status %x\n", Status);
1718 ExFreePool(Urb);
1719 return Status;
1720 }
1721
1722 // sanity checks
1723 ASSERT(HubDeviceExtension->HubConfigDescriptor.wTotalLength == sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR));
1724 ASSERT(HubDeviceExtension->HubConfigDescriptor.bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE);
1725 ASSERT(HubDeviceExtension->HubConfigDescriptor.bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
1726 ASSERT(HubDeviceExtension->HubConfigDescriptor.bNumInterfaces == 1);
1727 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
1728 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
1729 ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bNumEndpoints == 1);
1730 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
1731 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bLength == sizeof(USB_ENDPOINT_DESCRIPTOR));
1732 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bmAttributes == USB_ENDPOINT_TYPE_INTERRUPT);
1733 ASSERT(HubDeviceExtension->HubEndPointDescriptor.bEndpointAddress == 0x81); // interrupt in
1734
1735 // get hub information
1736 Status = HubDeviceExtension->HubInterface.GetExtendedHubInformation(HubInterfaceBusContext,
1737 RootHubDeviceObject,
1738 &HubDeviceExtension->UsbExtHubInfo,
1739 sizeof(USB_EXTHUB_INFORMATION_0),
1740 &Result);
1741 if (!NT_SUCCESS(Status))
1742 {
1743 // failed to get hub information
1744 DPRINT1("Failed to extended hub information. Unable to determine the number of ports!\n");
1745 ExFreePool(Urb);
1746 return Status;
1747 }
1748
1749 if (!HubDeviceExtension->UsbExtHubInfo.NumberOfPorts)
1750 {
1751 // bogus port driver
1752 DPRINT1("Failed to retrieve the number of ports\n");
1753 ExFreePool(Urb);
1754 return STATUS_UNSUCCESSFUL;
1755 }
1756
1757 DPRINT("HubDeviceExtension->UsbExtHubInfo.NumberOfPorts %x\n", HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
1758
1759 // Build hub descriptor request
1760 UsbBuildVendorRequest(Urb,
1761 URB_FUNCTION_CLASS_DEVICE,
1762 sizeof(Urb->UrbControlVendorClassRequest),
1763 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
1764 0,
1765 USB_REQUEST_GET_DESCRIPTOR,
1766 USB_DEVICE_CLASS_RESERVED,
1767 0,
1768 &HubDeviceExtension->HubDescriptor,
1769 NULL,
1770 sizeof(USB_HUB_DESCRIPTOR),
1771 NULL);
1772
1773 // set device handle
1774 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1775
1776 // send request
1777 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1778 IOCTL_INTERNAL_USB_SUBMIT_URB,
1779 Urb,
1780 NULL);
1781
1782 if (!NT_SUCCESS(Status))
1783 {
1784 DPRINT1("Failed to get Hub Descriptor!\n");
1785 ExFreePool(Urb);
1786 return STATUS_UNSUCCESSFUL;
1787 }
1788
1789 // sanity checks
1790 ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorLength == sizeof(USB_HUB_DESCRIPTOR));
1791 ASSERT(HubDeviceExtension->HubDescriptor.bNumberOfPorts == HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
1792 ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorType == 0x29);
1793
1794 // build get status request
1795 HubStatus = 0;
1796 UsbBuildGetStatusRequest(Urb,
1797 URB_FUNCTION_GET_STATUS_FROM_DEVICE,
1798 0,
1799 &HubStatus,
1800 0,
1801 NULL);
1802 // set device handle
1803 Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
1804
1805 // send request
1806 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1807 IOCTL_INTERNAL_USB_SUBMIT_URB,
1808 Urb,
1809 NULL);
1810 if (!NT_SUCCESS(Status))
1811 {
1812 // failed to get hub status
1813 DPRINT1("Failed to get Hub Status!\n");
1814 ExFreePool(Urb);
1815 return STATUS_UNSUCCESSFUL;
1816 }
1817
1818 // Allocate memory for PortStatusChange to hold 2 USHORTs for each port on hub
1819 HubDeviceExtension->PortStatusChange = ExAllocatePoolWithTag(NonPagedPool,
1820 sizeof(ULONG) * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
1821 USB_HUB_TAG);
1822
1823 // Get the first Configuration Descriptor
1824 Pid = USBD_ParseConfigurationDescriptorEx(&HubDeviceExtension->HubConfigDescriptor,
1825 &HubDeviceExtension->HubConfigDescriptor,
1826 -1, -1, -1, -1, -1);
1827 if (Pid == NULL)
1828 {
1829 // failed parse hub descriptor
1830 DPRINT1("Failed to parse configuration descriptor\n");
1831 ExFreePool(Urb);
1832 return STATUS_UNSUCCESSFUL;
1833 }
1834
1835 // create configuration request
1836 InterfaceList[0].InterfaceDescriptor = Pid;
1837 ConfigUrb = USBD_CreateConfigurationRequestEx(&HubDeviceExtension->HubConfigDescriptor,
1838 (PUSBD_INTERFACE_LIST_ENTRY)&InterfaceList);
1839 if (ConfigUrb == NULL)
1840 {
1841 // failed to build urb
1842 DPRINT1("Failed to allocate urb\n");
1843 ExFreePool(Urb);
1844 return STATUS_INSUFFICIENT_RESOURCES;
1845 }
1846
1847 // send request
1848 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1849 IOCTL_INTERNAL_USB_SUBMIT_URB,
1850 ConfigUrb,
1851 NULL);
1852 if (!NT_SUCCESS(Status))
1853 {
1854 // failed to select configuration
1855 DPRINT1("Failed to select configuration with %x\n", Status);
1856 ExFreePool(Urb);
1857 ExFreePool(ConfigUrb);
1858 return Status;
1859 }
1860
1861 // store configuration & pipe handle
1862 HubDeviceExtension->ConfigurationHandle = ConfigUrb->UrbSelectConfiguration.ConfigurationHandle;
1863 HubDeviceExtension->PipeHandle = ConfigUrb->UrbSelectConfiguration.Interface.Pipes[0].PipeHandle;
1864 DPRINT("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
1865
1866 FDO_QueryInterface(DeviceObject, &HubDeviceExtension->DeviceInterface);
1867
1868
1869 // free urb
1870 ExFreePool(ConfigUrb);
1871
1872 // check if function is available
1873 if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed)
1874 {
1875 // is it high speed bus
1876 if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed(HubInterfaceBusContext))
1877 {
1878 // initialize usb 2.0 hub
1879 Status = HubDeviceExtension->HubInterface.Initialize20Hub(HubInterfaceBusContext,
1880 HubDeviceExtension->RootHubHandle, 1);
1881 DPRINT("Status %x\n", Status);
1882
1883 // FIXME handle error
1884 ASSERT(Status == STATUS_SUCCESS);
1885 }
1886 }
1887
1888
1889 // Enable power on all ports
1890 DPRINT("Enabling PortPower on all ports!\n");
1891 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1892 {
1893 Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_POWER);
1894 if (!NT_SUCCESS(Status))
1895 DPRINT1("Failed to power on port %d\n", PortId);
1896
1897 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
1898 if (!NT_SUCCESS(Status))
1899 DPRINT1("Failed to power on port %d\n", PortId);
1900 }
1901
1902 // init root hub notification
1903 if (HubDeviceExtension->HubInterface.RootHubInitNotification)
1904 {
1905 Status = HubDeviceExtension->HubInterface.RootHubInitNotification(HubInterfaceBusContext,
1906 DeviceObject,
1907 RootHubInitCallbackFunction);
1908 if (!NT_SUCCESS(Status))
1909 {
1910 DPRINT1("Failed to set callback\n");
1911 ExFreePool(Urb);
1912 return Status;
1913 }
1914 }
1915 else
1916 {
1917 // Send the first SCE Request
1918 QueryStatusChangeEndpoint(DeviceObject);
1919
1920 //
1921 // reset ports
1922 //
1923 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1924 {
1925 //
1926 // get port status
1927 //
1928 Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
1929 if (NT_SUCCESS(Status))
1930 {
1931 //
1932 // is there a device connected
1933 //
1934 if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
1935 {
1936 //
1937 // reset port
1938 //
1939 Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
1940 if (!NT_SUCCESS(Status))
1941 {
1942 DPRINT1("Failed to reset on port %d\n", PortId);
1943 }
1944 else
1945 {
1946 //
1947 // wait for the reset to be handled since we want to enumerate synchronously
1948 //
1949 KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
1950 Executive,
1951 KernelMode,
1952 FALSE,
1953 NULL);
1954 KeClearEvent(&HubDeviceExtension->ResetComplete);
1955 }
1956 }
1957 }
1958 }
1959 }
1960
1961 // free urb
1962 ExFreePool(Urb);
1963
1964 // done
1965 return Status;
1966 }
1967
1968 NTSTATUS
1969 USBHUB_FdoHandlePnp(
1970 IN PDEVICE_OBJECT DeviceObject,
1971 IN PIRP Irp)
1972 {
1973 PIO_STACK_LOCATION Stack;
1974 NTSTATUS Status = STATUS_SUCCESS;
1975 ULONG_PTR Information = 0;
1976 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1977
1978 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1979
1980 Stack = IoGetCurrentIrpStackLocation(Irp);
1981
1982 switch (Stack->MinorFunction)
1983 {
1984 case IRP_MN_START_DEVICE:
1985 {
1986 if (USBHUB_IsRootHubFDO(DeviceObject))
1987 {
1988 // start root hub fdo
1989 Status = USBHUB_FdoStartDevice(DeviceObject, Irp);
1990 }
1991 else
1992 {
1993 Status = USBHUB_ParentFDOStartDevice(DeviceObject, Irp);
1994 }
1995 break;
1996 }
1997
1998 case IRP_MN_QUERY_DEVICE_RELATIONS:
1999 {
2000 switch (Stack->Parameters.QueryDeviceRelations.Type)
2001 {
2002 case BusRelations:
2003 {
2004 PDEVICE_RELATIONS DeviceRelations = NULL;
2005 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
2006
2007 Status = USBHUB_FdoQueryBusRelations(DeviceObject, &DeviceRelations);
2008
2009 Information = (ULONG_PTR)DeviceRelations;
2010 break;
2011 }
2012 case RemovalRelations:
2013 {
2014 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
2015 return ForwardIrpAndForget(DeviceObject, Irp);
2016 }
2017 default:
2018 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
2019 Stack->Parameters.QueryDeviceRelations.Type);
2020 return ForwardIrpAndForget(DeviceObject, Irp);
2021 }
2022 break;
2023 }
2024 case IRP_MN_QUERY_REMOVE_DEVICE:
2025 case IRP_MN_QUERY_STOP_DEVICE:
2026 {
2027 Irp->IoStatus.Status = STATUS_SUCCESS;
2028 return ForwardIrpAndForget(DeviceObject, Irp);
2029 }
2030 case IRP_MN_REMOVE_DEVICE:
2031 {
2032 Irp->IoStatus.Status = STATUS_SUCCESS;
2033 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2034
2035 IoDetachDevice(HubDeviceExtension->LowerDeviceObject);
2036 IoDeleteDevice(DeviceObject);
2037
2038 return STATUS_SUCCESS;
2039 }
2040 case IRP_MN_QUERY_BUS_INFORMATION:
2041 {
2042 DPRINT("IRP_MN_QUERY_BUS_INFORMATION\n");
2043 break;
2044 }
2045 case IRP_MN_QUERY_ID:
2046 {
2047 DPRINT("IRP_MN_QUERY_ID\n");
2048 break;
2049 }
2050 case IRP_MN_QUERY_CAPABILITIES:
2051 {
2052 DPRINT("IRP_MN_QUERY_CAPABILITIES\n");
2053 break;
2054 }
2055 default:
2056 {
2057 DPRINT(" IRP_MJ_PNP / unknown minor function 0x%lx\n", Stack->MinorFunction);
2058 return ForwardIrpAndForget(DeviceObject, Irp);
2059 }
2060 }
2061
2062 Irp->IoStatus.Information = Information;
2063 Irp->IoStatus.Status = Status;
2064 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2065 return Status;
2066 }
2067
2068 NTSTATUS
2069 USBHUB_FdoHandleDeviceControl(
2070 IN PDEVICE_OBJECT DeviceObject,
2071 IN PIRP Irp)
2072 {
2073 PIO_STACK_LOCATION IoStack;
2074 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
2075 PUSB_NODE_INFORMATION NodeInformation;
2076 PHUB_DEVICE_EXTENSION HubDeviceExtension;
2077 PUSB_NODE_CONNECTION_INFORMATION NodeConnectionInfo;
2078 PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
2079 PUSB_NODE_CONNECTION_DRIVERKEY_NAME NodeKey;
2080 PUSB_NODE_CONNECTION_NAME ConnectionName;
2081 ULONG Index, Length;
2082
2083 // get stack location
2084 IoStack = IoGetCurrentIrpStackLocation(Irp);
2085
2086 // get device extension
2087 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
2088
2089 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_INFORMATION)
2090 {
2091 // is the buffer big enough
2092 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_INFORMATION))
2093 {
2094 // buffer too small
2095 Status = STATUS_BUFFER_TOO_SMALL;
2096 }
2097 else
2098 {
2099 // get buffer
2100 NodeInformation = (PUSB_NODE_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2101
2102 // sanity check
2103 ASSERT(NodeInformation);
2104
2105 // init buffer
2106 NodeInformation->NodeType = UsbHub;
2107 RtlCopyMemory(&NodeInformation->u.HubInformation.HubDescriptor, &HubDeviceExtension->HubDescriptor, sizeof(USB_HUB_DESCRIPTOR));
2108
2109 // FIXME is hub powered
2110 NodeInformation->u.HubInformation.HubIsBusPowered = TRUE;
2111
2112 // done
2113 Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
2114 Status = STATUS_SUCCESS;
2115 }
2116
2117
2118 }
2119 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_INFORMATION)
2120 {
2121 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_CONNECTION_INFORMATION))
2122 {
2123 // buffer too small
2124 Status = STATUS_BUFFER_TOO_SMALL;
2125 }
2126 else
2127 {
2128 // get node connection info
2129 NodeConnectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2130
2131 // sanity checks
2132 ASSERT(NodeConnectionInfo);
2133
2134 for(Index = 0; Index < USB_MAXCHILDREN; Index++)
2135 {
2136 if (HubDeviceExtension->ChildDeviceObject[Index] == NULL)
2137 continue;
2138
2139 // get child device extension
2140 ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
2141
2142 if (ChildDeviceExtension->PortNumber != NodeConnectionInfo->ConnectionIndex)
2143 continue;
2144
2145 // init node connection info
2146 RtlCopyMemory(&NodeConnectionInfo->DeviceDescriptor, &ChildDeviceExtension->DeviceDesc, sizeof(USB_DEVICE_DESCRIPTOR));
2147 NodeConnectionInfo->CurrentConfigurationValue = ChildDeviceExtension->FullConfigDesc->bConfigurationValue;
2148 NodeConnectionInfo->DeviceIsHub = FALSE; //FIXME support hubs
2149 NodeConnectionInfo->LowSpeed = ChildDeviceExtension->DeviceInformation.DeviceSpeed == UsbLowSpeed;
2150 NodeConnectionInfo->DeviceAddress = ChildDeviceExtension->DeviceInformation.DeviceAddress;
2151 NodeConnectionInfo->NumberOfOpenPipes = ChildDeviceExtension->DeviceInformation.NumberOfOpenPipes;
2152 NodeConnectionInfo->ConnectionStatus = DeviceConnected; //FIXME
2153
2154 if (NodeConnectionInfo->NumberOfOpenPipes)
2155 {
2156 DPRINT1("Need to copy pipe information\n");
2157 }
2158 break;
2159 }
2160 // done
2161 Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
2162 Status = STATUS_SUCCESS;
2163 }
2164 }
2165 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME)
2166 {
2167 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_CONNECTION_INFORMATION))
2168 {
2169 // buffer too small
2170 Status = STATUS_BUFFER_TOO_SMALL;
2171 }
2172 else
2173 {
2174 // get node connection info
2175 NodeKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
2176
2177 // sanity checks
2178 ASSERT(NodeKey);
2179
2180 for(Index = 0; Index < USB_MAXCHILDREN; Index++)
2181 {
2182 if (HubDeviceExtension->ChildDeviceObject[Index] == NULL)
2183 continue;
2184
2185 // get child device extension
2186 ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
2187
2188 if (ChildDeviceExtension->PortNumber != NodeKey->ConnectionIndex)
2189 continue;
2190
2191 // get driver key
2192 Status = IoGetDeviceProperty(HubDeviceExtension->ChildDeviceObject[Index], DevicePropertyDriverKeyName,
2193 IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME),
2194 NodeKey->DriverKeyName,
2195 &Length);
2196
2197 if (Status == STATUS_BUFFER_TOO_SMALL)
2198 {
2199 // normalize status
2200 Status = STATUS_SUCCESS;
2201 }
2202
2203 if (Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME) > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
2204 {
2205 // terminate node key name
2206 NodeKey->DriverKeyName[0] = UNICODE_NULL;
2207 Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
2208 }
2209 else
2210 {
2211 // result size
2212 Irp->IoStatus.Information = Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
2213 }
2214
2215 // length of driver name
2216 NodeKey->ActualLength = Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
2217 break;
2218 }
2219 }
2220 }
2221 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_NAME)
2222 {
2223 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_CONNECTION_NAME))
2224 {
2225 // buffer too small
2226 Status = STATUS_BUFFER_TOO_SMALL;
2227 }
2228 else
2229 {
2230 // FIXME support hubs
2231 ConnectionName = (PUSB_NODE_CONNECTION_NAME)Irp->AssociatedIrp.SystemBuffer;
2232 ConnectionName->ActualLength = 0;
2233 ConnectionName->NodeName[0] = UNICODE_NULL;
2234
2235 // done
2236 Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_NAME);
2237 Status = STATUS_SUCCESS;
2238 }
2239 }
2240 else
2241 {
2242 DPRINT1("UNIMPLEMENTED FdoHandleDeviceControl IoCtl %x InputBufferLength %x OutputBufferLength %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode,
2243 IoStack->Parameters.DeviceIoControl.InputBufferLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength);
2244 }
2245
2246 // finish irp
2247 Irp->IoStatus.Status = Status;
2248 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2249
2250 return Status;
2251 }
2252