[USBHUB_NEW]
[reactos.git] / drivers / usb / usbhub_new / fdo.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Hub Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbhub/fdo.c
5 * PURPOSE: Handle FDO
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11 #define INITGUID
12 #include "usbhub.h"
13
14 NTSTATUS
15 QueryStatusChangeEndpoint(
16 IN PDEVICE_OBJECT DeviceObject);
17
18 NTSTATUS
19 CreateUsbChildDeviceObject(
20 IN PDEVICE_OBJECT UsbHubDeviceObject,
21 IN LONG PortId,
22 OUT PDEVICE_OBJECT *UsbChildDeviceObject);
23
24 NTSTATUS
25 DestroyUsbChildDeviceObject(
26 IN PDEVICE_OBJECT UsbHubDeviceObject,
27 IN LONG PortId);
28
29 NTSTATUS
30 SubmitRequestToRootHub(
31 IN PDEVICE_OBJECT RootHubDeviceObject,
32 IN ULONG IoControlCode,
33 OUT PVOID OutParameter1,
34 OUT PVOID OutParameter2)
35 {
36 KEVENT Event;
37 PIRP Irp;
38 IO_STATUS_BLOCK IoStatus;
39 NTSTATUS Status;
40 PIO_STACK_LOCATION Stack = NULL;
41
42 KeInitializeEvent(&Event, NotificationEvent, FALSE);
43
44 //
45 // Build Control Request
46 //
47 Irp = IoBuildDeviceIoControlRequest(IoControlCode,
48 RootHubDeviceObject,
49 NULL, 0,
50 NULL, 0,
51 TRUE,
52 &Event,
53 &IoStatus);
54
55 if (Irp == NULL)
56 {
57 DPRINT("Usbhub: IoBuildDeviceIoControlRequest() failed\n");
58 return STATUS_INSUFFICIENT_RESOURCES;
59 }
60
61 //
62 // Initialize the status block before sending the IRP
63 //
64 IoStatus.Status = STATUS_NOT_SUPPORTED;
65 IoStatus.Information = 0;
66
67 //
68 // Get Next Stack Location and Initialize it
69 //
70 Stack = IoGetNextIrpStackLocation(Irp);
71 Stack->Parameters.Others.Argument1 = OutParameter1;
72 Stack->Parameters.Others.Argument2 = OutParameter2;
73
74 //
75 // Call RootHub
76 //
77 Status = IoCallDriver(RootHubDeviceObject, Irp);
78
79 //
80 // Its ok to block here as this function is called in an nonarbitrary thread
81 //
82 if (Status == STATUS_PENDING)
83 {
84 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
85 Status = IoStatus.Status;
86 }
87
88 //
89 // The IO Manager will free the IRP
90 //
91
92 return Status;
93 }
94
95 NTSTATUS
96 GetPortStatusAndChange(
97 IN PDEVICE_OBJECT RootHubDeviceObject,
98 IN ULONG PortId,
99 OUT PPORT_STATUS_CHANGE StatusChange)
100 {
101 NTSTATUS Status;
102 PURB Urb;
103
104 //
105 // Allocate URB
106 //
107 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
108 if (!Urb)
109 {
110 DPRINT1("Failed to allocate memory for URB!\n");
111 return STATUS_INSUFFICIENT_RESOURCES;
112 }
113
114 //
115 // Zero it
116 //
117 RtlZeroMemory(Urb, sizeof(URB));
118
119 //
120 // Initialize URB for getting Port Status
121 //
122 UsbBuildVendorRequest(Urb,
123 URB_FUNCTION_CLASS_OTHER,
124 sizeof(Urb->UrbControlVendorClassRequest),
125 USBD_TRANSFER_DIRECTION_OUT,
126 0,
127 USB_REQUEST_GET_STATUS,
128 0,
129 PortId,
130 StatusChange,
131 0,
132 sizeof(PORT_STATUS_CHANGE),
133 0);
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 SetPortFeature(
150 IN PDEVICE_OBJECT RootHubDeviceObject,
151 IN ULONG PortId,
152 IN ULONG Feature)
153 {
154 NTSTATUS Status;
155 PURB Urb;
156
157 //
158 // Allocate 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_SET_FEATURE,
181 Feature,
182 PortId,
183 NULL,
184 0,
185 0,
186 0);
187 //
188 // Query the Root Hub
189 //
190 Status = SubmitRequestToRootHub(RootHubDeviceObject, IOCTL_INTERNAL_USB_SUBMIT_URB, Urb, NULL);
191
192 //
193 // Free URB
194 //
195 ExFreePool(Urb);
196
197 return Status;
198 }
199
200 NTSTATUS
201 ClearPortFeature(
202 IN PDEVICE_OBJECT RootHubDeviceObject,
203 IN ULONG PortId,
204 IN ULONG Feature)
205 {
206 NTSTATUS Status;
207 PURB Urb;
208
209 //
210 // Allocate a URB
211 //
212 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
213 if (!Urb)
214 {
215 DPRINT1("Failed to allocate memory for URB!\n");
216 return STATUS_INSUFFICIENT_RESOURCES;
217 }
218
219 //
220 // Zero it
221 //
222 RtlZeroMemory(Urb, sizeof(URB));
223
224 //
225 // Initialize URB for Clearing Port Reset
226 //
227 UsbBuildVendorRequest(Urb,
228 URB_FUNCTION_CLASS_OTHER,
229 sizeof(Urb->UrbControlVendorClassRequest),
230 USBD_TRANSFER_DIRECTION_IN,
231 0,
232 USB_REQUEST_CLEAR_FEATURE,
233 Feature,
234 PortId,
235 NULL,
236 0,
237 0,
238 0);
239 //
240 // Query the Root Hub
241 //
242 Status = SubmitRequestToRootHub(RootHubDeviceObject, IOCTL_INTERNAL_USB_SUBMIT_URB, Urb, NULL);
243
244 //
245 // Free URB
246 //
247 ExFreePool(Urb);
248
249 return Status;
250 }
251
252 VOID NTAPI
253 DeviceStatusChangeThread(
254 IN PVOID Context)
255 {
256 NTSTATUS Status;
257 PDEVICE_OBJECT DeviceObject, RootHubDeviceObject;
258 PHUB_DEVICE_EXTENSION HubDeviceExtension;
259 PWORK_ITEM_DATA WorkItemData;
260 PORT_STATUS_CHANGE PortStatus;
261 LONG PortId;
262
263 static LONG failsafe = 0;
264
265 DPRINT1("Entered DeviceStatusChangeThread, Context %x\n", Context);
266
267 WorkItemData = (PWORK_ITEM_DATA)Context;
268 DeviceObject = (PDEVICE_OBJECT)WorkItemData->Context;
269 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
270 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
271 //
272 // Loop all ports
273 //
274 for (PortId = 1; PortId <= HubDeviceExtension->UsbExtHubInfo.NumberOfPorts; PortId++)
275 {
276 //
277 // Get Port Status
278 //
279 Status = GetPortStatusAndChange(RootHubDeviceObject, PortId, &PortStatus);
280 if (!NT_SUCCESS(Status))
281 {
282 DPRINT1("Failed to get port status for port %d, Status %x\n", PortId, Status);
283 // FIXME: Do we really want to halt further SCE requests?
284 return;
285 }
286
287 DPRINT1("Port %d Status %x\n", PortId, PortStatus.Status);
288 DPRINT1("Port %d Change %x\n", PortId, PortStatus.Change);
289
290
291 //
292 // Check for new device connection
293 //
294 if (PortStatus.Change & USB_PORT_STATUS_CONNECT)
295 {
296 //
297 // Clear Port Connect
298 //
299 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
300 if (!NT_SUCCESS(Status))
301 {
302 DPRINT1("Failed to clear connection change for port %d\n", PortId);
303 }
304
305 //
306 // Is this a connect or disconnect?
307 //
308 if (!(PortStatus.Status & USB_PORT_STATUS_CONNECT))
309 {
310 DPRINT1("Device disconnected from port %d\n", PortId);
311
312 Status = DestroyUsbChildDeviceObject(DeviceObject, PortId);
313 if (!NT_SUCCESS(Status))
314 {
315 DPRINT1("Failed to delete child device object after disconnect\n");
316 }
317 }
318 else
319 {
320 DPRINT1("Device connected from port %d\n", PortId);
321
322 // No SCE completion done for clearing C_PORT_CONNECT
323
324 //
325 // Reset Port
326 //
327 Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_RESET);
328 if (!NT_SUCCESS(Status))
329 {
330 DPRINT1("Failed to reset port %d\n", PortId);
331 }
332 }
333 }
334 else if (PortStatus.Change & USB_PORT_STATUS_ENABLE)
335 {
336 //
337 // Clear Enable
338 //
339 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_ENABLE);
340 if (!NT_SUCCESS(Status))
341 {
342 DPRINT1("Failed to clear enable change on port %d\n", PortId);
343 }
344 }
345 else if (PortStatus.Change & USB_PORT_STATUS_RESET)
346 {
347 //
348 // Clear Reset
349 //
350 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_RESET);
351 if (!NT_SUCCESS(Status))
352 {
353 DPRINT1("Failed to clear reset change on port %d\n", PortId);
354 }
355
356 //
357 // Get Port Status
358 //
359 Status = GetPortStatusAndChange(RootHubDeviceObject, PortId, &PortStatus);
360 if (!NT_SUCCESS(Status))
361 {
362 DPRINT1("Failed to get port status for port %d, Status %x\n", PortId, Status);
363 // FIXME: Do we really want to halt further SCE requests?
364 return;
365 }
366
367 DPRINT1("Port %d Status %x\n", PortId, PortStatus.Status);
368 DPRINT1("Port %d Change %x\n", PortId, PortStatus.Change);
369
370 //
371 // Check that reset was cleared
372 //
373 if(PortStatus.Change & USB_PORT_STATUS_RESET)
374 {
375 DPRINT1("Port did not clear reset! Possible Hardware problem!\n");
376 }
377
378 //
379 // Check if the device is still connected
380 //
381 if (!(PortStatus.Status & USB_PORT_STATUS_CONNECT))
382 {
383 DPRINT1("Device has been disconnected\n");
384 continue;
385 }
386
387 //
388 // Make sure its Connected and Enabled
389 //
390 if (!(PortStatus.Status & (USB_PORT_STATUS_CONNECT | USB_PORT_STATUS_ENABLE)))
391 {
392 DPRINT1("Usb Device is not connected and enabled!\n");
393 //
394 // Attempt another reset
395 //
396 Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_RESET);
397 if (!NT_SUCCESS(Status))
398 {
399 DPRINT1("Failed to reset port %d\n", PortId);
400 }
401 continue;
402 }
403
404 //
405 // This is a new device
406 //
407 Status = CreateUsbChildDeviceObject(DeviceObject, PortId, NULL);
408 }
409 }
410
411 //
412 // FIXME: Still in testing
413 //
414 failsafe++;
415 if (failsafe > 100)
416 {
417 DPRINT1("SCE completed over 100 times but no action has been taken to clear the Change of any ports.\n");
418 //
419 // Return and dont send any more SCE Requests
420 //
421 return;
422 }
423
424 ExFreePool(WorkItemData);
425
426 //
427 // Send another SCE Request
428 //
429 DPRINT1("Sending another SCE!\n");
430 QueryStatusChangeEndpoint(DeviceObject);
431 }
432
433 NTSTATUS
434 NTAPI
435 StatusChangeEndpointCompletion(
436 IN PDEVICE_OBJECT DeviceObject,
437 IN PIRP Irp,
438 IN PVOID Context)
439 {
440 PDEVICE_OBJECT RealDeviceObject;
441 PHUB_DEVICE_EXTENSION HubDeviceExtension;
442 PWORK_ITEM_DATA WorkItemData;
443
444 RealDeviceObject = (PDEVICE_OBJECT)Context;
445 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)RealDeviceObject->DeviceExtension;
446
447 //
448 // NOTE: USBPORT frees this IRP
449 //
450 DPRINT1("Received Irp %x, HubDeviceExtension->PendingSCEIrp %x\n", Irp, HubDeviceExtension->PendingSCEIrp);
451 //IoFreeIrp(Irp);
452
453 //
454 // Create and initialize work item data
455 //
456 WorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(WORK_ITEM_DATA), USB_HUB_TAG);
457 if (!WorkItemData)
458 {
459 DPRINT1("Failed to allocate memory!n");
460 return STATUS_INSUFFICIENT_RESOURCES;
461 }
462 WorkItemData->Context = RealDeviceObject;
463 DPRINT1("Initialize work item\n");
464 ExInitializeWorkItem(&WorkItemData->WorkItem, DeviceStatusChangeThread, (PVOID)WorkItemData);
465
466 //
467 // Queue the work item to handle initializing the device
468 //
469 ExQueueWorkItem(&WorkItemData->WorkItem, DelayedWorkQueue);
470
471 //
472 // Return more processing required so the IO Manger doesn’t try to mess with IRP just freed
473 //
474 return STATUS_MORE_PROCESSING_REQUIRED;
475 }
476
477 NTSTATUS
478 QueryStatusChangeEndpoint(
479 IN PDEVICE_OBJECT DeviceObject)
480 {
481 NTSTATUS Status;
482 PDEVICE_OBJECT RootHubDeviceObject;
483 PIO_STACK_LOCATION Stack;
484 PHUB_DEVICE_EXTENSION HubDeviceExtension;
485 PURB PendingSCEUrb;
486
487 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
488 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
489
490 //
491 // Allocate a URB
492 //
493 PendingSCEUrb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
494
495 //
496 // Initialize URB for Status Change Endpoint request
497 //
498 UsbBuildInterruptOrBulkTransferRequest(PendingSCEUrb,
499 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
500 HubDeviceExtension->PipeHandle,
501 HubDeviceExtension->PortStatusChange,
502 NULL,
503 sizeof(USHORT) * 2 * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
504 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
505 NULL);
506
507 //
508 // Set the device handle to null for roothub
509 //
510 PendingSCEUrb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
511
512 //
513 // Allocate an Irp
514 //
515
516 HubDeviceExtension->PendingSCEIrp = ExAllocatePoolWithTag(NonPagedPool,
517 IoSizeOfIrp(RootHubDeviceObject->StackSize),
518 USB_HUB_TAG);
519 /*
520 HubDeviceExtension->PendingSCEIrp = IoAllocateIrp(RootHubDeviceObject->StackSize,
521 FALSE);
522 */
523 DPRINT1("Allocated IRP %x\n", HubDeviceExtension->PendingSCEIrp);
524
525 if (!HubDeviceExtension->PendingSCEIrp)
526 {
527 DPRINT1("USBHUB: Failed to allocate IRP for SCE request!\n");
528 return STATUS_INSUFFICIENT_RESOURCES;
529 }
530
531 //
532 // Initialize the IRP
533 //
534 IoInitializeIrp(HubDeviceExtension->PendingSCEIrp,
535 IoSizeOfIrp(RootHubDeviceObject->StackSize),
536 RootHubDeviceObject->StackSize);
537
538 HubDeviceExtension->PendingSCEIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
539 HubDeviceExtension->PendingSCEIrp->IoStatus.Information = 0;
540 HubDeviceExtension->PendingSCEIrp->Flags = 0;
541 HubDeviceExtension->PendingSCEIrp->UserBuffer = NULL;
542
543 //
544 // Get the Next Stack Location and Initialize it
545 //
546 Stack = IoGetNextIrpStackLocation(HubDeviceExtension->PendingSCEIrp);
547 Stack->DeviceObject = DeviceObject;
548 Stack->Parameters.Others.Argument1 = PendingSCEUrb;
549 Stack->Parameters.Others.Argument2 = NULL;
550 Stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
551 Stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
552
553 //
554 // Set the completion routine for when device is connected to root hub
555 //
556 IoSetCompletionRoutine(HubDeviceExtension->PendingSCEIrp,
557 StatusChangeEndpointCompletion,
558 DeviceObject,
559 TRUE,
560 TRUE,
561 TRUE);
562
563 //
564 // Send to RootHub
565 //
566 DPRINT1("DeviceObject is %x\n", DeviceObject);
567 DPRINT1("Iocalldriver %x with irp %x\n", RootHubDeviceObject, HubDeviceExtension->PendingSCEIrp);
568 Status = IoCallDriver(RootHubDeviceObject, HubDeviceExtension->PendingSCEIrp);
569
570 return STATUS_PENDING;
571 }
572
573 NTSTATUS
574 QueryInterface(
575 IN PDEVICE_OBJECT DeviceObject,
576 IN CONST GUID InterfaceType,
577 IN LONG Size,
578 IN LONG Version,
579 OUT PVOID Interface)
580 {
581 KEVENT Event;
582 PIRP Irp;
583 IO_STATUS_BLOCK IoStatus;
584 NTSTATUS Status;
585 PIO_STACK_LOCATION Stack = NULL;
586
587 //
588 // Initialize the Event used to wait for Irp completion
589 //
590 KeInitializeEvent(&Event, NotificationEvent, FALSE);
591
592 //
593 // Build Control Request
594 //
595 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
596 DeviceObject,
597 NULL,
598 0,
599 NULL,
600 &Event,
601 &IoStatus);
602
603 //
604 // Get Next Stack Location and Initialize it.
605 //
606 Stack = IoGetNextIrpStackLocation(Irp);
607 Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
608 Stack->Parameters.QueryInterface.InterfaceType= &InterfaceType;//USB_BUS_INTERFACE_HUB_GUID;
609 Stack->Parameters.QueryInterface.Size = Size;
610 Stack->Parameters.QueryInterface.Version = Version;
611 Stack->Parameters.QueryInterface.Interface = Interface;
612 Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
613
614 Status = IoCallDriver(DeviceObject, Irp);
615
616 if (Status == STATUS_PENDING)
617 {
618 DPRINT("Operation pending\n");
619 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
620 Status = IoStatus.Status;
621 }
622
623 return Status;
624 }
625
626 NTSTATUS
627 GetUsbDeviceDescriptor(
628 IN PDEVICE_OBJECT ChildDeviceObject,
629 IN UCHAR DescriptorType,
630 IN UCHAR Index,
631 IN USHORT LangId,
632 OUT PVOID TransferBuffer,
633 IN ULONG TransferBufferLength)
634 {
635 NTSTATUS Status;
636 PDEVICE_OBJECT RootHubDeviceObject;
637 PURB Urb;
638 PHUB_DEVICE_EXTENSION HubDeviceExtension;
639 PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
640
641 //
642 // Get the Hubs Device Extension
643 //
644 ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)ChildDeviceObject->DeviceExtension;
645 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) ChildDeviceExtension->ParentDeviceObject->DeviceExtension;
646 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
647
648 //
649 // Allocate a URB
650 //
651 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), USB_HUB_TAG);
652 if (!Urb)
653 {
654 DPRINT1("Failed to allocate memory for URB!\n");
655 return STATUS_INSUFFICIENT_RESOURCES;
656 }
657
658 //
659 // Zero it
660 //
661 RtlZeroMemory(Urb, sizeof(URB));
662
663 //
664 // Initialize URB for getting device descriptor
665 //
666 UsbBuildGetDescriptorRequest(Urb,
667 sizeof(Urb->UrbControlDescriptorRequest),
668 DescriptorType,
669 Index,
670 LangId,
671 TransferBuffer,
672 NULL,
673 TransferBufferLength,
674 NULL);
675
676 //
677 // Set the device handle
678 //
679 Urb->UrbHeader.UsbdDeviceHandle = (PVOID)ChildDeviceExtension->UsbDeviceHandle;
680
681 //
682 // Query the Root Hub
683 //
684 Status = SubmitRequestToRootHub(RootHubDeviceObject,
685 IOCTL_INTERNAL_USB_SUBMIT_URB,
686 Urb,
687 NULL);
688
689 return Status;
690 }
691
692 NTSTATUS
693 GetUsbStringDescriptor(
694 IN PDEVICE_OBJECT ChildDeviceObject,
695 IN UCHAR Index,
696 IN USHORT LangId,
697 OUT PVOID *TransferBuffer,
698 OUT USHORT *Size)
699 {
700 NTSTATUS Status;
701 PUSB_STRING_DESCRIPTOR StringDesc = NULL;
702 ULONG SizeNeeded;
703 LPWSTR Buffer;
704
705 StringDesc = ExAllocatePoolWithTag(NonPagedPool,
706 sizeof(USB_STRING_DESCRIPTOR),
707 USB_HUB_TAG);
708 if (!StringDesc)
709 {
710 DPRINT1("Failed to allocate buffer for string!\n");
711 return STATUS_INSUFFICIENT_RESOURCES;
712 }
713
714 //
715 // Get the index string descriptor length
716 // FIXME: Implement LangIds
717 //
718 Status = GetUsbDeviceDescriptor(ChildDeviceObject,
719 USB_STRING_DESCRIPTOR_TYPE,
720 Index,
721 0x0409,
722 StringDesc,
723 sizeof(USB_STRING_DESCRIPTOR));
724 if (!NT_SUCCESS(Status))
725 {
726 DPRINT1("GetUsbDeviceDescriptor failed with status %x\n", Status);
727 ExFreePool(StringDesc);
728 return Status;
729 }
730 DPRINT1("StringDesc->bLength %d\n", StringDesc->bLength);
731
732 //
733 // Did we get something more than the length of the first two fields of structure?
734 //
735 if (StringDesc->bLength == 2)
736 {
737 DPRINT1("USB Device Error!\n");
738 ExFreePool(StringDesc);
739 return STATUS_DEVICE_DATA_ERROR;
740 }
741 SizeNeeded = StringDesc->bLength + sizeof(WCHAR);
742
743 //
744 // Free String
745 //
746 ExFreePool(StringDesc);
747
748 //
749 // Recreate with appropriate size
750 //
751 StringDesc = ExAllocatePoolWithTag(NonPagedPool,
752 SizeNeeded,
753 USB_HUB_TAG);
754 if (!StringDesc)
755 {
756 DPRINT1("Failed to allocate buffer for string!\n");
757 return STATUS_INSUFFICIENT_RESOURCES;
758 }
759
760 RtlZeroMemory(StringDesc, SizeNeeded);
761
762 //
763 // Get the string
764 //
765 Status = GetUsbDeviceDescriptor(ChildDeviceObject,
766 USB_STRING_DESCRIPTOR_TYPE,
767 Index,
768 0x0409,
769 StringDesc,
770 SizeNeeded);
771 if (!NT_SUCCESS(Status))
772 {
773 DPRINT1("GetUsbDeviceDescriptor failed with status %x\n", Status);
774 ExFreePool(StringDesc);
775 return Status;
776 }
777
778 //
779 // Allocate Buffer to return
780 //
781 Buffer = ExAllocatePoolWithTag(NonPagedPool,
782 SizeNeeded,
783 USB_HUB_TAG);
784 if (!Buffer)
785 {
786 DPRINT1("Failed to allocate buffer for string!\n");
787 ExFreePool(StringDesc);
788 return STATUS_INSUFFICIENT_RESOURCES;
789 }
790 DPRINT1("Buffer %p\n", Buffer);
791 RtlZeroMemory(Buffer, SizeNeeded);
792
793 DPRINT1("Buffer %p\n", Buffer);
794 DPRINT1("SizeNeeded %lu\n", SizeNeeded);
795 DPRINT1("Offset %lu\n", FIELD_OFFSET(USB_STRING_DESCRIPTOR, bLength));
796 DPRINT1("Length %lu\n", SizeNeeded - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bLength));
797
798 //
799 // Copy the string to destination
800 //
801 RtlCopyMemory(Buffer, StringDesc->bString, SizeNeeded - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString));
802 *Size = SizeNeeded;
803 *TransferBuffer = Buffer;
804
805 ExFreePool(StringDesc);
806
807 return STATUS_SUCCESS;
808 }
809
810 ULONG
811 IsCompositeDevice(
812 IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
813 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
814 {
815 if (DeviceDescriptor->bNumConfigurations != 1)
816 {
817 //
818 // composite device must have only one configuration
819 //
820 return FALSE;
821 }
822
823 if (ConfigurationDescriptor->bNumInterfaces < 2)
824 {
825 //
826 // composite device must have multiple interfaces
827 //
828 return FALSE;
829 }
830
831 if (DeviceDescriptor->bDeviceClass == 0)
832 {
833 //
834 // composite device
835 //
836 ASSERT(DeviceDescriptor->bDeviceSubClass == 0);
837 ASSERT(DeviceDescriptor->bDeviceProtocol == 0);
838 return TRUE;
839 }
840
841 if (DeviceDescriptor->bDeviceClass == 0xEF &&
842 DeviceDescriptor->bDeviceSubClass == 0x02 &&
843 DeviceDescriptor->bDeviceProtocol == 0x01)
844 {
845 //
846 // USB-IF association descriptor
847 //
848 return TRUE;
849 }
850
851 //
852 // not a composite device
853 //
854 return FALSE;
855 }
856
857 NTSTATUS
858 CreateDeviceIds(
859 PDEVICE_OBJECT UsbChildDeviceObject)
860 {
861 NTSTATUS Status = STATUS_SUCCESS;
862 ULONG Index = 0;
863 LPWSTR DeviceString;
864 WCHAR Buffer[200];
865 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
866 PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
867 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
868 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
869
870 //
871 // get child device extension
872 //
873 UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)UsbChildDeviceObject->DeviceExtension;
874
875 //
876 // get device descriptor
877 //
878 DeviceDescriptor = &UsbChildExtension->DeviceDesc;
879
880 //
881 // get configuration descriptor
882 //
883 ConfigurationDescriptor = UsbChildExtension->FullConfigDesc;
884
885 //
886 // use first interface descriptor available
887 //
888 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, 0, -1, -1, -1, -1);
889 ASSERT(InterfaceDescriptor);
890
891 //
892 // Construct the CompatibleIds
893 //
894 if (IsCompositeDevice(DeviceDescriptor, ConfigurationDescriptor))
895 {
896 //
897 // sanity checks
898 //
899 ASSERT(DeviceDescriptor->bNumConfigurations == 1);
900 ASSERT(ConfigurationDescriptor->bNumInterfaces > 1);
901 Index += swprintf(&Buffer[Index],
902 L"USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
903 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol) + 1;
904 Index += swprintf(&Buffer[Index],
905 L"USB\\DevClass_%02x&SubClass_%02x",
906 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass) + 1;
907 Index += swprintf(&Buffer[Index],
908 L"USB\\DevClass_%02x",
909 DeviceDescriptor->bDeviceClass) + 1;
910 Index += swprintf(&Buffer[Index],
911 L"USB\\COMPOSITE") + 1;
912 }
913 else
914 {
915 //
916 // sanity checks for simple usb device
917 //
918 ASSERT(ConfigurationDescriptor->bNumInterfaces == 1);
919
920 //
921 // FIXME: support multiple configurations
922 //
923 ASSERT(DeviceDescriptor->bNumConfigurations == 1);
924
925 if (DeviceDescriptor->bDeviceClass == 0)
926 {
927 Index += swprintf(&Buffer[Index],
928 L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
929 InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass, InterfaceDescriptor->bInterfaceProtocol) + 1;
930 Index += swprintf(&Buffer[Index],
931 L"USB\\Class_%02x&SubClass_%02x",
932 InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass) + 1;
933 Index += swprintf(&Buffer[Index],
934 L"USB\\Class_%02x",
935 InterfaceDescriptor->bInterfaceClass) + 1;
936 }
937 else
938 {
939 Index += swprintf(&Buffer[Index],
940 L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
941 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass, DeviceDescriptor->bDeviceProtocol) + 1;
942 Index += swprintf(&Buffer[Index],
943 L"USB\\Class_%02x&SubClass_%02x",
944 DeviceDescriptor->bDeviceClass, DeviceDescriptor->bDeviceSubClass) + 1;
945 Index += swprintf(&Buffer[Index],
946 L"USB\\Class_%02x",
947 DeviceDescriptor->bDeviceClass) + 1;
948 }
949 }
950
951 //
952 // now allocate the buffer
953 //
954 DeviceString = ExAllocatePool(NonPagedPool, (Index + 1) * sizeof(WCHAR));
955 if (!DeviceString)
956 {
957 //
958 // no memory
959 //
960 return STATUS_INSUFFICIENT_RESOURCES;
961 }
962
963 //
964 // copy buffer
965 //
966 RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
967 DeviceString[Index] = UNICODE_NULL;
968 UsbChildExtension->usCompatibleIds.Buffer = DeviceString;
969 UsbChildExtension->usCompatibleIds.Length = Index * sizeof(WCHAR);
970 UsbChildExtension->usCompatibleIds.MaximumLength = (Index + 1) * sizeof(WCHAR);
971 DPRINT1("usCompatibleIds %wZ\n", &UsbChildExtension->usCompatibleIds);
972
973 //
974 // Construct DeviceId string
975 //
976 Index = swprintf(Buffer, L"USB\\Vid_%04x&Pid_%04x", UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct) + 1;
977
978 //
979 // now allocate the buffer
980 //
981 DeviceString = ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
982 if (!DeviceString)
983 {
984 //
985 // no memory
986 //
987 return STATUS_INSUFFICIENT_RESOURCES;
988 }
989
990 //
991 // copy buffer
992 //
993 RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
994 UsbChildExtension->usDeviceId.Buffer = DeviceString;
995 UsbChildExtension->usDeviceId.Length = (Index-1) * sizeof(WCHAR);
996 UsbChildExtension->usDeviceId.MaximumLength = Index * sizeof(WCHAR);
997 DPRINT1("usDeviceId %wZ\n", &UsbChildExtension->usDeviceId);
998
999 //
1000 // Construct HardwareIds
1001 //
1002 Index = 0;
1003 Index += swprintf(&Buffer[Index],
1004 L"USB\\Vid_%04x&Pid_%04x&Rev_%04x",
1005 UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct, UsbChildExtension->DeviceDesc.bcdDevice) + 1;
1006 Index += swprintf(&Buffer[Index],
1007 L"USB\\Vid_%04x&Pid_%04x",
1008 UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct) + 1;
1009
1010 //
1011 // now allocate the buffer
1012 //
1013 DeviceString = ExAllocatePool(NonPagedPool, (Index + 1) * sizeof(WCHAR));
1014 if (!DeviceString)
1015 {
1016 //
1017 // no memory
1018 //
1019 return STATUS_INSUFFICIENT_RESOURCES;
1020 }
1021
1022 //
1023 // copy buffer
1024 //
1025 RtlCopyMemory(DeviceString, Buffer, Index * sizeof(WCHAR));
1026 DeviceString[Index] = UNICODE_NULL;
1027 UsbChildExtension->usHardwareIds.Buffer = DeviceString;
1028 UsbChildExtension->usHardwareIds.Length = (Index + 1) * sizeof(WCHAR);
1029 UsbChildExtension->usHardwareIds.MaximumLength = (Index + 1) * sizeof(WCHAR);
1030 DPRINT1("usHardWareIds %wZ\n", &UsbChildExtension->usHardwareIds);
1031
1032 //
1033 // FIXME: Handle Lang ids
1034 //
1035
1036 //
1037 // Get the product string if obe provided
1038 //
1039 if (UsbChildExtension->DeviceDesc.iProduct)
1040 {
1041 Status = GetUsbStringDescriptor(UsbChildDeviceObject,
1042 UsbChildExtension->DeviceDesc.iProduct,
1043 0,
1044 (PVOID*)&UsbChildExtension->usTextDescription.Buffer,
1045 &UsbChildExtension->usTextDescription.Length);
1046 if (!NT_SUCCESS(Status))
1047 {
1048 DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
1049 return Status;
1050 }
1051
1052 UsbChildExtension->usTextDescription.MaximumLength = UsbChildExtension->usTextDescription.Length;
1053 DPRINT1("Usb TextDescription %wZ\n", &UsbChildExtension->usTextDescription);
1054 }
1055
1056 //
1057 // Get the Serial Number string if obe provided
1058 //
1059 if (UsbChildExtension->DeviceDesc.iSerialNumber)
1060 {
1061 Status = GetUsbStringDescriptor(UsbChildDeviceObject,
1062 UsbChildExtension->DeviceDesc.iSerialNumber,
1063 0,
1064 (PVOID*)&UsbChildExtension->usInstanceId.Buffer,
1065 &UsbChildExtension->usInstanceId.Length);
1066 if (!NT_SUCCESS(Status))
1067 {
1068 DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
1069 return Status;
1070 }
1071
1072 UsbChildExtension->usInstanceId.MaximumLength = UsbChildExtension->usInstanceId.Length;
1073 DPRINT1("Usb InstanceId %wZ\n", &UsbChildExtension->usInstanceId);
1074 }
1075 else
1076 {
1077 //
1078 // the device did not provide a serial number, lets create a pseudo instance id
1079 //
1080 Index = swprintf(Buffer, L"0&%04d", UsbChildExtension->PortNumber) + 1;
1081 UsbChildExtension->usInstanceId.Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
1082 if (UsbChildExtension->usInstanceId.Buffer == NULL)
1083 {
1084 DPRINT1("Error: failed to allocate %lu bytes\n", Index * sizeof(WCHAR));
1085 Status = STATUS_INSUFFICIENT_RESOURCES;
1086 return Status;
1087 }
1088
1089 //
1090 // copy instance id
1091 //
1092 RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR));
1093 UsbChildExtension->usInstanceId.Length = UsbChildExtension->usInstanceId.MaximumLength = Index * sizeof(WCHAR);
1094
1095 DPRINT1("usDeviceId %wZ\n", &UsbChildExtension->usInstanceId);
1096 }
1097
1098 return Status;
1099 }
1100
1101 NTSTATUS
1102 DestroyUsbChildDeviceObject(
1103 IN PDEVICE_OBJECT UsbHubDeviceObject,
1104 IN LONG PortId)
1105 {
1106 PHUB_DEVICE_EXTENSION HubDeviceExtension = (PHUB_DEVICE_EXTENSION)UsbHubDeviceObject->DeviceExtension;
1107 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension = NULL;
1108 PDEVICE_OBJECT ChildDeviceObject = NULL;
1109 ULONG Index = 0;
1110
1111 DPRINT1("Removing device on port %d (Child index: %d)\n", PortId, Index);
1112
1113 for (Index = 0; Index < USB_MAXCHILDREN; Index++)
1114 {
1115 if (HubDeviceExtension->ChildDeviceObject[Index])
1116 {
1117 UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
1118
1119 /* Check if it matches the port ID */
1120 if (UsbChildExtension->PortNumber == PortId)
1121 {
1122 /* We found it */
1123 ChildDeviceObject = HubDeviceExtension->ChildDeviceObject[Index];
1124 break;
1125 }
1126 }
1127 }
1128
1129 /* Fail the request if the device doesn't exist */
1130 if (!ChildDeviceObject)
1131 {
1132 DPRINT1("Removal request for non-existant device!\n");
1133 return STATUS_UNSUCCESSFUL;
1134 }
1135
1136 /* Remove the device from the table */
1137 HubDeviceExtension->ChildDeviceObject[Index] = NULL;
1138
1139 /* Invalidate device relations for the root hub */
1140 IoInvalidateDeviceRelations(HubDeviceExtension->RootHubPhysicalDeviceObject, BusRelations);
1141
1142 /* The rest of the removal process takes place in IRP_MN_REMOVE_DEVICE handling for the PDO */
1143 return STATUS_SUCCESS;
1144 }
1145
1146 NTSTATUS
1147 CreateUsbChildDeviceObject(
1148 IN PDEVICE_OBJECT UsbHubDeviceObject,
1149 IN LONG PortId,
1150 OUT PDEVICE_OBJECT *UsbChildDeviceObject)
1151 {
1152 NTSTATUS Status;
1153 PDEVICE_OBJECT RootHubDeviceObject, NewChildDeviceObject;
1154 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1155 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
1156 PUSB_BUS_INTERFACE_HUB_V5 HubInterface;
1157 ULONG ChildDeviceCount, UsbDeviceNumber = 0;
1158 WCHAR CharDeviceName[64];
1159 UNICODE_STRING DeviceName;
1160 ULONG ConfigDescSize, DeviceDescSize;
1161 PVOID HubInterfaceBusContext;
1162 USB_CONFIGURATION_DESCRIPTOR ConfigDesc;
1163
1164 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) UsbHubDeviceObject->DeviceExtension;
1165 HubInterface = &HubDeviceExtension->HubInterface;
1166 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
1167 HubInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
1168 //
1169 // Find an empty slot in the child device array
1170 //
1171 for (ChildDeviceCount = 0; ChildDeviceCount < USB_MAXCHILDREN; ChildDeviceCount++)
1172 {
1173 if (HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] == NULL)
1174 {
1175 DPRINT1("Found unused entry at %d\n", ChildDeviceCount);
1176 break;
1177 }
1178 }
1179
1180 //
1181 // Check if the limit has been reached for maximum usb devices
1182 //
1183 if (ChildDeviceCount == USB_MAXCHILDREN)
1184 {
1185 DPRINT1("USBHUB: Too many child devices!\n");
1186 return STATUS_UNSUCCESSFUL;
1187 }
1188
1189 while (TRUE)
1190 {
1191 //
1192 // Create a Device Name
1193 //
1194 swprintf(CharDeviceName, L"\\Device\\USBPDO-%d", UsbDeviceNumber);
1195
1196 //
1197 // Initialize UnicodeString
1198 //
1199 RtlInitUnicodeString(&DeviceName, CharDeviceName);
1200
1201 //
1202 // Create a DeviceObject
1203 //
1204 Status = IoCreateDevice(UsbHubDeviceObject->DriverObject,
1205 sizeof(HUB_CHILDDEVICE_EXTENSION),
1206 NULL,
1207 FILE_DEVICE_CONTROLLER,
1208 FILE_AUTOGENERATED_DEVICE_NAME,
1209 FALSE,
1210 &NewChildDeviceObject);
1211
1212 //
1213 // Check if the name is already in use
1214 //
1215 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
1216 {
1217 //
1218 // Try next name
1219 //
1220 UsbDeviceNumber++;
1221 continue;
1222 }
1223
1224 //
1225 // Check for other errors
1226 //
1227 if (!NT_SUCCESS(Status))
1228 {
1229 DPRINT1("USBHUB: IoCreateDevice failed with status %x\n", Status);
1230 return Status;
1231 }
1232
1233 DPRINT1("USBHUB: Created Device %x\n", NewChildDeviceObject);
1234 break;
1235 }
1236
1237 NewChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
1238
1239 //
1240 // Assign the device extensions
1241 //
1242 UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)NewChildDeviceObject->DeviceExtension;
1243 RtlZeroMemory(UsbChildExtension, sizeof(HUB_CHILDDEVICE_EXTENSION));
1244 UsbChildExtension->ParentDeviceObject = UsbHubDeviceObject;
1245 UsbChildExtension->PortNumber = PortId;
1246
1247 //
1248 // Create the UsbDeviceObject
1249 //
1250 Status = HubInterface->CreateUsbDevice(HubInterfaceBusContext,
1251 (PVOID)&UsbChildExtension->UsbDeviceHandle,
1252 HubDeviceExtension->RootHubHandle,
1253 0x501, //hack
1254 PortId);
1255 if (!NT_SUCCESS(Status))
1256 {
1257 DPRINT1("USBHUB: CreateUsbDevice failed with status %x\n", Status);
1258 goto Cleanup;
1259 }
1260
1261 //
1262 // Initialize UsbDevice
1263 //
1264 Status = HubInterface->InitializeUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle);
1265 if (!NT_SUCCESS(Status))
1266 {
1267 DPRINT1("USBHUB: InitializeUsbDevice failed with status %x\n", Status);
1268 goto Cleanup;
1269 }
1270
1271 DPRINT1("Usb Device Handle %x\n", UsbChildExtension->UsbDeviceHandle);
1272
1273 ConfigDescSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
1274 DeviceDescSize = sizeof(USB_DEVICE_DESCRIPTOR);
1275
1276 //
1277 // Get the descriptors
1278 //
1279 Status = HubInterface->GetUsbDescriptors(HubInterfaceBusContext,
1280 UsbChildExtension->UsbDeviceHandle,
1281 (PUCHAR)&UsbChildExtension->DeviceDesc,
1282 &DeviceDescSize,
1283 (PUCHAR)&ConfigDesc,
1284 &ConfigDescSize);
1285 if (!NT_SUCCESS(Status))
1286 {
1287 DPRINT1("USBHUB: GetUsbDescriptors failed with status %x\n", Status);
1288 goto Cleanup;
1289 }
1290
1291 DumpDeviceDescriptor(&UsbChildExtension->DeviceDesc);
1292 DumpConfigurationDescriptor(&ConfigDesc);
1293
1294 //
1295 // FIXME: Support more than one configuration and one interface?
1296 //
1297 if (UsbChildExtension->DeviceDesc.bNumConfigurations > 1)
1298 {
1299 DPRINT1("Warning: Device has more than one configuration. Only one configuration (the first) is supported!\n");
1300 }
1301
1302 if (ConfigDesc.bNumInterfaces > 1)
1303 {
1304 DPRINT1("Warning: Device has more that one interface. Only one interface (the first) is currently supported\n");
1305 }
1306
1307 ConfigDescSize = ConfigDesc.wTotalLength;
1308
1309 //
1310 // Allocate memory for the first full descriptor, including interfaces and endpoints.
1311 //
1312 UsbChildExtension->FullConfigDesc = ExAllocatePoolWithTag(PagedPool, ConfigDescSize, USB_HUB_TAG);
1313
1314 //
1315 // Retrieve the full configuration descriptor
1316 //
1317 Status = GetUsbDeviceDescriptor(NewChildDeviceObject,
1318 USB_CONFIGURATION_DESCRIPTOR_TYPE,
1319 0,
1320 0,
1321 UsbChildExtension->FullConfigDesc,
1322 ConfigDescSize);
1323
1324 if (!NT_SUCCESS(Status))
1325 {
1326 DPRINT1("USBHUB: GetUsbDeviceDescriptor failed with status %x\n", Status);
1327 goto Cleanup;
1328 }
1329
1330 DumpFullConfigurationDescriptor(UsbChildExtension->FullConfigDesc);
1331
1332 //
1333 // Construct all the strings that will described 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
1344 IoInvalidateDeviceRelations(RootHubDeviceObject, BusRelations);
1345 return STATUS_SUCCESS;
1346
1347 Cleanup:
1348
1349 //
1350 // Remove the usb device if it was created
1351 //
1352 if (UsbChildExtension->UsbDeviceHandle)
1353 HubInterface->RemoveUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle, 0);
1354
1355 //
1356 // Free full configuration descriptor if one was allocated
1357 //
1358 if (UsbChildExtension->FullConfigDesc)
1359 ExFreePool(UsbChildExtension->FullConfigDesc);
1360
1361 //
1362 // Delete the device object
1363 //
1364 IoDeleteDevice(NewChildDeviceObject);
1365 return Status;
1366 }
1367
1368 NTSTATUS
1369 USBHUB_FdoQueryBusRelations(
1370 IN PDEVICE_OBJECT DeviceObject,
1371 OUT PDEVICE_RELATIONS* pDeviceRelations)
1372 {
1373 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1374 PDEVICE_RELATIONS DeviceRelations;
1375 ULONG i;
1376 ULONG Children = 0;
1377 ULONG NeededSize;
1378
1379 HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1380
1381 //
1382 // Count the number of children
1383 //
1384 for (i = 0; i < USB_MAXCHILDREN; i++)
1385 {
1386
1387 if (HubDeviceExtension->ChildDeviceObject[i] == NULL)
1388 {
1389 continue;
1390 }
1391 Children++;
1392 }
1393
1394 NeededSize = sizeof(DEVICE_RELATIONS);
1395 if (Children > 1)
1396 NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
1397
1398 //
1399 // Allocate DeviceRelations
1400 //
1401 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool,
1402 NeededSize);
1403
1404 if (!DeviceRelations)
1405 return STATUS_INSUFFICIENT_RESOURCES;
1406 DeviceRelations->Count = Children;
1407 Children = 0;
1408
1409 //
1410 // Fill in return structure
1411 //
1412 for (i = 0; i < USB_MAXCHILDREN; i++)
1413 {
1414 if (HubDeviceExtension->ChildDeviceObject[i])
1415 {
1416 ObReferenceObject(HubDeviceExtension->ChildDeviceObject[i]);
1417 HubDeviceExtension->ChildDeviceObject[i]->Flags &= ~DO_DEVICE_INITIALIZING;
1418 DeviceRelations->Objects[Children++] = HubDeviceExtension->ChildDeviceObject[i];
1419 }
1420 }
1421
1422 ASSERT(Children == DeviceRelations->Count);
1423 *pDeviceRelations = DeviceRelations;
1424
1425 return STATUS_SUCCESS;
1426 }
1427
1428 VOID
1429 NTAPI
1430 RootHubInitCallbackFunction(
1431 PVOID Context)
1432 {
1433 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
1434 NTSTATUS Status;
1435 ULONG PortId;
1436 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1437 PORT_STATUS_CHANGE StatusChange;
1438
1439 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1440
1441 DPRINT1("RootHubInitCallbackFunction Sending the initial SCE Request %x\n", DeviceObject);
1442
1443 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1444 {
1445 //
1446 // get port status
1447 //
1448 Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
1449 if (NT_SUCCESS(Status))
1450 {
1451 //
1452 // is there a device connected
1453 //
1454 if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
1455 {
1456 //
1457 // reset port
1458 //
1459 Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
1460 if (!NT_SUCCESS(Status))
1461 DPRINT1("Failed to reset on port %d\n", PortId);
1462 }
1463 }
1464 }
1465
1466 //
1467 // Send the first SCE Request
1468 //
1469 QueryStatusChangeEndpoint(DeviceObject);
1470 }
1471
1472 NTSTATUS
1473 USBHUB_FdoHandlePnp(
1474 IN PDEVICE_OBJECT DeviceObject,
1475 IN PIRP Irp)
1476 {
1477 PIO_STACK_LOCATION Stack;
1478 NTSTATUS Status = STATUS_SUCCESS;
1479 ULONG_PTR Information = 0;
1480 PHUB_DEVICE_EXTENSION HubDeviceExtension;
1481 PDEVICE_OBJECT RootHubDeviceObject;
1482 PVOID HubInterfaceBusContext , UsbDInterfaceBusContext;
1483 PORT_STATUS_CHANGE StatusChange;
1484
1485 HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1486
1487 Stack = IoGetCurrentIrpStackLocation(Irp);
1488
1489 switch (Stack->MinorFunction)
1490 {
1491 case IRP_MN_START_DEVICE:
1492 {
1493 PURB Urb;
1494 PUSB_INTERFACE_DESCRIPTOR Pid;
1495 ULONG Result = 0, PortId;
1496 USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}};
1497 PURB ConfigUrb = NULL;
1498 ULONG HubStatus;
1499
1500 DPRINT1("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
1501
1502 //
1503 // Allocated size including the sizeof USBD_INTERFACE_LIST_ENTRY
1504 //
1505 Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY), USB_HUB_TAG);
1506 RtlZeroMemory(Urb, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY));
1507
1508 //
1509 // Get the Root Hub Pdo
1510 //
1511 SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
1512 IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
1513 &HubDeviceExtension->RootHubPhysicalDeviceObject,
1514 &HubDeviceExtension->RootHubFunctionalDeviceObject);
1515
1516 RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
1517 ASSERT(HubDeviceExtension->RootHubPhysicalDeviceObject);
1518 ASSERT(HubDeviceExtension->RootHubFunctionalDeviceObject);
1519 DPRINT1("RootPdo %x, RootFdo %x\n",
1520 HubDeviceExtension->RootHubPhysicalDeviceObject,
1521 HubDeviceExtension->RootHubFunctionalDeviceObject);
1522
1523 //
1524 // Send the StartDevice to RootHub
1525 //
1526 Status = ForwardIrpAndWait(RootHubDeviceObject, Irp);
1527
1528 if (!NT_SUCCESS(Status))
1529 {
1530 DPRINT1("Failed to start the RootHub PDO\n");
1531 ASSERT(FALSE);
1532 }
1533
1534 //
1535 // Get the current number of hubs
1536 //
1537 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1538 IOCTL_INTERNAL_USB_GET_HUB_COUNT,
1539 &HubDeviceExtension->NumberOfHubs, NULL);
1540
1541 //
1542 // Get the Hub Interface
1543 //
1544 Status = QueryInterface(RootHubDeviceObject,
1545 USB_BUS_INTERFACE_HUB_GUID,
1546 sizeof(USB_BUS_INTERFACE_HUB_V5),
1547 5,
1548 (PVOID)&HubDeviceExtension->HubInterface);
1549
1550 if (!NT_SUCCESS(Status))
1551 {
1552 DPRINT1("Failed to get HUB_GUID interface with status 0x%08lx\n", Status);
1553 return STATUS_UNSUCCESSFUL;
1554 }
1555
1556 HubInterfaceBusContext = HubDeviceExtension->HubInterface.BusContext;
1557
1558 //
1559 // Get the USBDI Interface
1560 //
1561 Status = QueryInterface(RootHubDeviceObject,
1562 USB_BUS_INTERFACE_USBDI_GUID,
1563 sizeof(USB_BUS_INTERFACE_USBDI_V2),
1564 2,
1565 (PVOID)&HubDeviceExtension->UsbDInterface);
1566
1567 if (!NT_SUCCESS(Status))
1568 {
1569 DPRINT1("Failed to get USBDI_GUID interface with status 0x%08lx\n", Status);
1570 return Status;
1571 }
1572
1573 UsbDInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
1574
1575 //
1576 // Get Root Hub Device Handle
1577 //
1578 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1579 IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
1580 &HubDeviceExtension->RootHubHandle,
1581 NULL);
1582
1583 if (!NT_SUCCESS(Status))
1584 {
1585 DPRINT1("GetRootHubDeviceHandle failed with status 0x%08lx\n", Status);
1586 return Status;
1587 }
1588
1589 //
1590 // Get Hub Device Information
1591 //
1592 Status = HubDeviceExtension->HubInterface.QueryDeviceInformation(HubInterfaceBusContext,
1593 HubDeviceExtension->RootHubHandle,
1594 &HubDeviceExtension->DeviceInformation,
1595 sizeof(USB_DEVICE_INFORMATION_0),
1596 &Result);
1597
1598 DPRINT1("Status %x, Result 0x%08lx\n", Status, Result);
1599 DPRINT1("InformationLevel %x\n", HubDeviceExtension->DeviceInformation.InformationLevel);
1600 DPRINT1("ActualLength %x\n", HubDeviceExtension->DeviceInformation.ActualLength);
1601 DPRINT1("PortNumber %x\n", HubDeviceExtension->DeviceInformation.PortNumber);
1602 DPRINT1("DeviceDescriptor %x\n", HubDeviceExtension->DeviceInformation.DeviceDescriptor);
1603 DPRINT1("HubAddress %x\n", HubDeviceExtension->DeviceInformation.HubAddress);
1604 DPRINT1("NumberofPipes %x\n", HubDeviceExtension->DeviceInformation.NumberOfOpenPipes);
1605
1606 //
1607 // Get Root Hubs Device Descriptor
1608 //
1609 UsbBuildGetDescriptorRequest(Urb,
1610 sizeof(Urb->UrbControlDescriptorRequest),
1611 USB_DEVICE_DESCRIPTOR_TYPE,
1612 0,
1613 0,
1614 &HubDeviceExtension->HubDeviceDescriptor,
1615 NULL,
1616 sizeof(USB_DEVICE_DESCRIPTOR),
1617 NULL);
1618
1619 Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
1620
1621 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1622 IOCTL_INTERNAL_USB_SUBMIT_URB,
1623 Urb,
1624 NULL);
1625
1626 if (!NT_SUCCESS(Status))
1627 {
1628 DPRINT1("Failed to get HubDeviceDescriptor!\n");
1629 }
1630
1631 DumpDeviceDescriptor(&HubDeviceExtension->HubDeviceDescriptor);
1632
1633 //
1634 // Get Root Hubs Configuration Descriptor
1635 //
1636 UsbBuildGetDescriptorRequest(Urb,
1637 sizeof(Urb->UrbControlDescriptorRequest),
1638 USB_CONFIGURATION_DESCRIPTOR_TYPE,
1639 0,
1640 0,
1641 &HubDeviceExtension->HubConfigDescriptor,
1642 NULL,
1643 sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR),
1644 NULL);
1645
1646 DPRINT1("RootHub Handle %x\n", HubDeviceExtension->RootHubHandle);
1647 Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
1648
1649 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1650 IOCTL_INTERNAL_USB_SUBMIT_URB,
1651 Urb,
1652 NULL);
1653
1654 if (!NT_SUCCESS(Status))
1655 {
1656 DPRINT1("Failed to get RootHub Configuration with status %x\n", Status);
1657 ASSERT(FALSE);
1658 }
1659 ASSERT(HubDeviceExtension->HubConfigDescriptor.wTotalLength);
1660
1661 DumpConfigurationDescriptor(&HubDeviceExtension->HubConfigDescriptor);
1662
1663 Status = HubDeviceExtension->HubInterface.GetExtendedHubInformation(HubInterfaceBusContext,
1664 RootHubDeviceObject,
1665 &HubDeviceExtension->UsbExtHubInfo,
1666 sizeof(USB_EXTHUB_INFORMATION_0),
1667 &Result);
1668 if (!NT_SUCCESS(Status))
1669 {
1670 DPRINT1("Failed to extended hub information. Unable to determine the number of ports!\n");
1671 ASSERT(FALSE);
1672 }
1673
1674 DPRINT1("HubDeviceExtension->UsbExtHubInfo.NumberOfPorts %x\n", HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
1675
1676 //
1677 // Get the Hub Descriptor
1678 //
1679 UsbBuildVendorRequest(Urb,
1680 URB_FUNCTION_CLASS_DEVICE,
1681 sizeof(Urb->UrbControlVendorClassRequest),
1682 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
1683 0,
1684 USB_REQUEST_GET_DESCRIPTOR,
1685 USB_DEVICE_CLASS_RESERVED,
1686 0,
1687 &HubDeviceExtension->HubDescriptor,
1688 NULL,
1689 sizeof(USB_HUB_DESCRIPTOR),
1690 NULL);
1691
1692 Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
1693
1694 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1695 IOCTL_INTERNAL_USB_SUBMIT_URB,
1696 Urb,
1697 NULL);
1698
1699 DPRINT1("bDescriptorType %x\n", HubDeviceExtension->HubDescriptor.bDescriptorType);
1700
1701 if (!NT_SUCCESS(Status))
1702 {
1703 DPRINT1("Failed to get Hub Descriptor!\n");
1704 ExFreePool(Urb);
1705 return STATUS_UNSUCCESSFUL;
1706 }
1707
1708 HubStatus = 0;
1709 UsbBuildGetStatusRequest(Urb,
1710 URB_FUNCTION_GET_STATUS_FROM_DEVICE,
1711 0,
1712 &HubStatus,
1713 0,
1714 NULL);
1715 Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
1716
1717 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1718 IOCTL_INTERNAL_USB_SUBMIT_URB,
1719 Urb,
1720 NULL);
1721 if (!NT_SUCCESS(Status))
1722 {
1723 DPRINT1("Failed to get Hub Status!\n");
1724 ExFreePool(Urb);
1725 return STATUS_UNSUCCESSFUL;
1726 }
1727
1728 DPRINT1("HubStatus %x\n", HubStatus);
1729
1730 //
1731 // Allocate memory for PortStatusChange to hold 2 USHORTs for each port on hub
1732 //
1733 HubDeviceExtension->PortStatusChange = ExAllocatePoolWithTag(NonPagedPool,
1734 sizeof(ULONG) * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
1735 USB_HUB_TAG);
1736
1737 //
1738 // Get the first Configuration Descriptor
1739 //
1740 Pid = USBD_ParseConfigurationDescriptorEx(&HubDeviceExtension->HubConfigDescriptor,
1741 &HubDeviceExtension->HubConfigDescriptor,
1742 -1, -1, -1, -1, -1);
1743
1744 ASSERT(Pid != NULL);
1745
1746 InterfaceList[0].InterfaceDescriptor = Pid;
1747 ConfigUrb = USBD_CreateConfigurationRequestEx(&HubDeviceExtension->HubConfigDescriptor,
1748 (PUSBD_INTERFACE_LIST_ENTRY)&InterfaceList);
1749 ASSERT(ConfigUrb != NULL);
1750
1751 Status = SubmitRequestToRootHub(RootHubDeviceObject,
1752 IOCTL_INTERNAL_USB_SUBMIT_URB,
1753 ConfigUrb,
1754 NULL);
1755
1756 HubDeviceExtension->ConfigurationHandle = ConfigUrb->UrbSelectConfiguration.ConfigurationHandle;
1757 HubDeviceExtension->PipeHandle = ConfigUrb->UrbSelectConfiguration.Interface.Pipes[0].PipeHandle;
1758 DPRINT1("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
1759
1760 //
1761 // check if function is available
1762 //
1763 if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed)
1764 {
1765 //
1766 // is it high speed bus
1767 //
1768 if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed(HubInterfaceBusContext))
1769 {
1770 //
1771 // initialize usb 2.0 hub
1772 //
1773 Status = HubDeviceExtension->HubInterface.Initialize20Hub(HubInterfaceBusContext,
1774 HubDeviceExtension->RootHubHandle, 1);
1775 DPRINT1("Status %x\n", Status);
1776
1777 //
1778 // FIXME handle error
1779 //
1780 ASSERT(Status == STATUS_SUCCESS);
1781 }
1782 }
1783
1784 ExFreePool(ConfigUrb);
1785
1786 //
1787 // Enable power on all ports
1788 //
1789
1790 DPRINT1("Enabling PortPower on all ports!\n");
1791
1792 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1793 {
1794 Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_POWER);
1795 if (!NT_SUCCESS(Status))
1796 DPRINT1("Failed to power on port %d\n", PortId);
1797
1798 Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
1799 if (!NT_SUCCESS(Status))
1800 DPRINT1("Failed to power on port %d\n", PortId);
1801 }
1802
1803 DPRINT1("RootHubInitNotification %x\n", HubDeviceExtension->HubInterface.RootHubInitNotification);
1804
1805 //
1806 // init roo hub notification
1807 //
1808 if (HubDeviceExtension->HubInterface.RootHubInitNotification)
1809 {
1810 Status = HubDeviceExtension->HubInterface.RootHubInitNotification(HubInterfaceBusContext,
1811 DeviceObject,
1812 RootHubInitCallbackFunction);
1813 if (!NT_SUCCESS(Status))
1814 {
1815 DPRINT1("Failed to set callback\n");
1816 }
1817 }
1818 else
1819 {
1820 //
1821 // reset ports
1822 //
1823 for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
1824 {
1825 //
1826 // get port status
1827 //
1828 Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
1829 if (NT_SUCCESS(Status))
1830 {
1831 //
1832 // is there a device connected
1833 //
1834 if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
1835 {
1836 //
1837 // reset port
1838 //
1839 Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
1840 if (!NT_SUCCESS(Status))
1841 DPRINT1("Failed to reset on port %d\n", PortId);
1842 }
1843 }
1844 }
1845
1846 //
1847 // Send the first SCE Request
1848 //
1849 QueryStatusChangeEndpoint(DeviceObject);
1850 }
1851
1852 ExFreePool(Urb);
1853 break;
1854 }
1855
1856 case IRP_MN_QUERY_DEVICE_RELATIONS:
1857 {
1858 switch (Stack->Parameters.QueryDeviceRelations.Type)
1859 {
1860 case BusRelations:
1861 {
1862 PDEVICE_RELATIONS DeviceRelations = NULL;
1863 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
1864
1865 Status = USBHUB_FdoQueryBusRelations(DeviceObject, &DeviceRelations);
1866
1867 Information = (ULONG_PTR)DeviceRelations;
1868 break;
1869 }
1870 case RemovalRelations:
1871 {
1872 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
1873 return ForwardIrpAndForget(DeviceObject, Irp);
1874 }
1875 default:
1876 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
1877 Stack->Parameters.QueryDeviceRelations.Type);
1878 return ForwardIrpAndForget(DeviceObject, Irp);
1879 }
1880 break;
1881 }
1882 case IRP_MN_QUERY_BUS_INFORMATION:
1883 {
1884 DPRINT1("IRP_MN_QUERY_BUS_INFORMATION\n");
1885 break;
1886 }
1887 case IRP_MN_QUERY_ID:
1888 {
1889 DPRINT1("IRP_MN_QUERY_ID\n");
1890 break;
1891 }
1892 case IRP_MN_QUERY_CAPABILITIES:
1893 {
1894 DPRINT1("IRP_MN_QUERY_CAPABILITIES\n");
1895 break;
1896 }
1897 default:
1898 {
1899 DPRINT1(" IRP_MJ_PNP / unknown minor function 0x%lx\n", Stack->MinorFunction);
1900 return ForwardIrpAndForget(DeviceObject, Irp);
1901 }
1902 }
1903
1904 Irp->IoStatus.Information = Information;
1905 Irp->IoStatus.Status = Status;
1906 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1907 return Status;
1908 }
1909
1910 NTSTATUS
1911 USBHUB_FdoHandleDeviceControl(
1912 IN PDEVICE_OBJECT DeviceObject,
1913 IN PIRP Irp)
1914 {
1915 DPRINT1("FdoHandleDeviceControl\n");
1916 UNIMPLEMENTED
1917 return STATUS_NOT_IMPLEMENTED;
1918 }
1919