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