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