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
7 * Hervé Poussineau (hpoussin@reactos.org)
8 * Michael Martin (michael.martin@reactos.org)
9 * Johannes Anderwald (johannes.anderwald@reactos.org)
14 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
19 PDEVICE_OBJECT DeviceObject
,
24 DPRINT("Entered Urb Completion\n");
27 // Get the original Irp
29 OriginalIrp
= (PIRP
)Context
;
32 // Update it to match what was returned for the IRP that was passed to RootHub
34 OriginalIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
35 OriginalIrp
->IoStatus
.Information
= Irp
->IoStatus
.Information
;
36 DPRINT("Status %x, Information %x\n", Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
);
39 // Complete the original Irp
41 IoCompleteRequest(OriginalIrp
, IO_NO_INCREMENT
);
44 // Return this status so the IO Manager doesnt mess with the Irp
46 return STATUS_MORE_PROCESSING_REQUIRED
;
51 PDEVICE_OBJECT RootHubDeviceObject
,
52 IN ULONG IoControlCode
,
54 OUT PVOID OutParameter1
,
55 OUT PVOID OutParameter2
)
59 IO_STATUS_BLOCK IoStatus
;
60 PIO_STACK_LOCATION ForwardStack
, CurrentStack
;
64 // Get the current stack location for the Irp
66 CurrentStack
= IoGetCurrentIrpStackLocation(Irp
);
70 // Pull the Urb from that stack, it will be reused in the Irp sent to RootHub
72 Urb
= (PURB
)CurrentStack
->Parameters
.Others
.Argument1
;
76 // Create the Irp to forward to RootHub
78 ForwardIrp
= IoBuildAsynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
86 DPRINT1("Failed to allocate IRP\n");
87 return STATUS_INSUFFICIENT_RESOURCES
;
91 // Get the new Irps next stack
93 ForwardStack
= IoGetNextIrpStackLocation(ForwardIrp
);
96 // Copy the stack for the current irp into the next stack of new irp
98 RtlCopyMemory(ForwardStack
, CurrentStack
, sizeof(IO_STACK_LOCATION
));
100 IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
101 IoStatus
.Information
= 0;
104 // Mark the Irp from upper driver as pending
106 IoMarkIrpPending(Irp
);
109 // Now set the completion routine for the new Irp.
111 IoSetCompletionRoutine(ForwardIrp
,
118 Status
= IoCallDriver(RootHubDeviceObject
, ForwardIrp
);
121 // Always return pending as the completion routine will take care of it
123 return STATUS_PENDING
;
127 USBHUB_PdoHandleInternalDeviceControl(
128 IN PDEVICE_OBJECT DeviceObject
,
132 PIO_STACK_LOCATION Stack
;
133 ULONG_PTR Information
= 0;
134 PHUB_DEVICE_EXTENSION HubDeviceExtension
;
135 PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension
;
136 PDEVICE_OBJECT RootHubDeviceObject
;
139 //DPRINT1("UsbhubInternalDeviceControlPdo(%x) called\n", DeviceObject);
142 // get current stack location
144 Stack
= IoGetCurrentIrpStackLocation(Irp
);
148 // Set default status
150 Status
= Irp
->IoStatus
.Status
;
152 ChildDeviceExtension
= (PHUB_CHILDDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
153 ASSERT(ChildDeviceExtension
->Common
.IsFDO
== FALSE
);
154 HubDeviceExtension
= (PHUB_DEVICE_EXTENSION
)ChildDeviceExtension
->ParentDeviceObject
->DeviceExtension
;
155 RootHubDeviceObject
= HubDeviceExtension
->RootHubPhysicalDeviceObject
;
157 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
159 case IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO
:
161 PHUB_DEVICE_EXTENSION DeviceExtension
;
163 DPRINT1("IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO\n");
164 if (Irp
->AssociatedIrp
.SystemBuffer
== NULL
165 || Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= sizeof(PVOID
))
167 Status
= STATUS_INVALID_PARAMETER
;
172 DeviceExtension
= (PHUB_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
174 pHubPointer
= (PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
;
177 Information
= sizeof(PVOID
);
178 Status
= STATUS_SUCCESS
;
182 case IOCTL_INTERNAL_USB_SUBMIT_URB
:
184 //DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB\n");
189 Urb
= (PURB
)Stack
->Parameters
.Others
.Argument1
;
193 // Set the real device handle
195 //DPRINT("UsbdDeviceHandle %x, ChildDeviceHandle %x\n", Urb->UrbHeader.UsbdDeviceHandle, ChildDeviceExtension->UsbDeviceHandle);
197 Urb
->UrbHeader
.UsbdDeviceHandle
= ChildDeviceExtension
->UsbDeviceHandle
;
202 switch (Urb
->UrbHeader
.Function
)
207 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
:
208 DPRINT1("URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n");
210 case URB_FUNCTION_CLASS_DEVICE
:
211 DPRINT1("URB_FUNCTION_CLASS_DEVICE\n");
213 case URB_FUNCTION_GET_STATUS_FROM_DEVICE
:
214 DPRINT1("URB_FUNCTION_GET_STATUS_FROM_DEVICE\n");
216 case URB_FUNCTION_SELECT_CONFIGURATION
:
217 DPRINT1("URB_FUNCTION_SELECT_CONFIGURATION\n");
219 case URB_FUNCTION_SELECT_INTERFACE
:
220 DPRINT1("URB_FUNCTION_SELECT_INTERFACE\n");
222 case URB_FUNCTION_CLASS_OTHER
:
223 DPRINT1("URB_FUNCTION_CLASS_OTHER\n");
225 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
:
228 DPRINT1("URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n");
229 DPRINT1("PipeHandle %x\n", Urb->UrbBulkOrInterruptTransfer.PipeHandle);
230 DPRINT1("TransferFlags %x\n", Urb->UrbBulkOrInterruptTransfer.TransferFlags);
231 DPRINT1("Buffer %x\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
232 DPRINT1("BufferMDL %x\n", Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL);
233 DPRINT1("Length %x\n", Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
234 DPRINT1("UrbLink %x\n", Urb->UrbBulkOrInterruptTransfer.UrbLink);
235 DPRINT1("hca %x\n", Urb->UrbBulkOrInterruptTransfer.hca);
236 if (Urb->UrbBulkOrInterruptTransfer.TransferFlags == USBD_SHORT_TRANSFER_OK)
243 case URB_FUNCTION_CLASS_INTERFACE
:
244 DPRINT1("URB_FUNCTION_CLASS_INTERFACE\n");
247 DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x NOT IMPLEMENTED\n", Urb
->UrbHeader
.Function
);
250 Urb
->UrbHeader
.UsbdDeviceHandle
= ChildDeviceExtension
->UsbDeviceHandle
;
251 //DPRINT1("Stack->CompletionRoutine %x\n", Stack->CompletionRoutine);
253 // Send the request to RootHub
255 Status
= FowardUrbToRootHub(RootHubDeviceObject
, IOCTL_INTERNAL_USB_SUBMIT_URB
, Irp
, Urb
, NULL
);
260 // FIXME: Can these be sent to RootHub?
262 case IOCTL_INTERNAL_USB_RESET_PORT
:
263 DPRINT1("IOCTL_INTERNAL_USB_RESET_PORT\n");
265 case IOCTL_INTERNAL_USB_GET_PORT_STATUS
:
267 PORT_STATUS_CHANGE PortStatus
;
269 PUCHAR PortStatusBits
;
271 PortStatusBits
= (PUCHAR
)Stack
->Parameters
.Others
.Argument1
;
273 // USBD_PORT_ENABLED (bit 0) or USBD_PORT_CONNECTED (bit 1)
275 DPRINT1("IOCTL_INTERNAL_USB_GET_PORT_STATUS\n");
276 DPRINT1("Arg1 %x\n", *PortStatusBits
);
278 if (Stack
->Parameters
.Others
.Argument1
)
280 for (PortId
= 1; PortId
<= HubDeviceExtension
->UsbExtHubInfo
.NumberOfPorts
; PortId
++)
282 Status
= GetPortStatusAndChange(RootHubDeviceObject
, PortId
, &PortStatus
);
283 if (NT_SUCCESS(Status
))
285 DPRINT1("Connect %x\n", ((PortStatus
.Status
& USB_PORT_STATUS_CONNECT
) << 1) << ((PortId
- 1) * 2));
286 DPRINT1("Enable %x\n", ((PortStatus
.Status
& USB_PORT_STATUS_ENABLE
) >> 1) << ((PortId
- 1) * 2));
288 (((PortStatus
.Status
& USB_PORT_STATUS_CONNECT
) << 1) << ((PortId
- 1) * 2)) +
289 (((PortStatus
.Status
& USB_PORT_STATUS_ENABLE
) >> 1) << ((PortId
- 1) * 2));
295 DPRINT1("Arg1 %x\n", *PortStatusBits
);
296 Status
= STATUS_SUCCESS
;
299 case IOCTL_INTERNAL_USB_ENABLE_PORT
:
300 DPRINT1("IOCTL_INTERNAL_USB_ENABLE_PORT\n");
302 case IOCTL_INTERNAL_USB_CYCLE_PORT
:
303 DPRINT1("IOCTL_INTERNAL_USB_CYCLE_PORT\n");
305 case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE
:
306 DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n");
310 DPRINT1("Unknown IOCTL code 0x%lx\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
311 Information
= Irp
->IoStatus
.Information
;
312 Status
= Irp
->IoStatus
.Status
;
316 if (Status
!= STATUS_PENDING
)
318 Irp
->IoStatus
.Information
= Information
;
319 Irp
->IoStatus
.Status
= Status
;
320 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
326 USBHUB_PdoStartDevice(
327 IN PDEVICE_OBJECT DeviceObject
,
330 PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension
;
332 DPRINT1("USBHUB_PdoStartDevice %x\n", DeviceObject
);
333 ChildDeviceExtension
= (PHUB_CHILDDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
336 // This should be a PDO
338 ASSERT(ChildDeviceExtension
->Common
.IsFDO
== FALSE
);
341 // FIXME: Fow now assume success
345 return STATUS_SUCCESS
;
350 IN PDEVICE_OBJECT DeviceObject
,
352 OUT ULONG_PTR
* Information
)
354 PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension
;
356 PUNICODE_STRING SourceString
= NULL
;
357 PWCHAR ReturnString
= NULL
;
358 NTSTATUS Status
= STATUS_SUCCESS
;
360 IdType
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.QueryId
.IdType
;
361 ChildDeviceExtension
= (PHUB_CHILDDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
365 case BusQueryDeviceID
:
367 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
368 SourceString
= &ChildDeviceExtension
->usDeviceId
;
371 case BusQueryHardwareIDs
:
373 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
374 SourceString
= &ChildDeviceExtension
->usHardwareIds
;
377 case BusQueryCompatibleIDs
:
379 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
380 SourceString
= &ChildDeviceExtension
->usCompatibleIds
;
383 case BusQueryInstanceID
:
385 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
386 SourceString
= &ChildDeviceExtension
->usInstanceId
;
390 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType
);
391 return STATUS_NOT_SUPPORTED
;
399 ReturnString
= ExAllocatePool(PagedPool
, SourceString
->MaximumLength
);
405 return STATUS_INSUFFICIENT_RESOURCES
;
411 RtlCopyMemory(ReturnString
, SourceString
->Buffer
, SourceString
->MaximumLength
);
414 *Information
= (ULONG_PTR
)ReturnString
;
420 USBHUB_PdoQueryDeviceText(
421 IN PDEVICE_OBJECT DeviceObject
,
423 OUT ULONG_PTR
* Information
)
425 PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension
;
426 DEVICE_TEXT_TYPE DeviceTextType
;
427 PUNICODE_STRING SourceString
= NULL
;
428 PWCHAR ReturnString
= NULL
;
429 NTSTATUS Status
= STATUS_SUCCESS
;
432 DeviceTextType
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.QueryDeviceText
.DeviceTextType
;
433 LocaleId
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.QueryDeviceText
.LocaleId
;
434 ChildDeviceExtension
= (PHUB_CHILDDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
440 switch (DeviceTextType
)
442 case DeviceTextDescription
:
443 case DeviceTextLocationInformation
:
445 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
448 // does the device provide a text description
450 if (ChildDeviceExtension
->usTextDescription
.Buffer
&& ChildDeviceExtension
->usTextDescription
.Length
)
455 SourceString
= &ChildDeviceExtension
->usTextDescription
;
461 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown device text type 0x%lx\n", DeviceTextType
);
462 Status
= STATUS_NOT_SUPPORTED
;
469 ReturnString
= ExAllocatePool(PagedPool
, SourceString
->Length
);
470 RtlCopyMemory(ReturnString
, SourceString
->Buffer
, SourceString
->Length
);
471 DPRINT1("%S\n", ReturnString
);
472 *Information
= (ULONG_PTR
)ReturnString
;
480 IN PDEVICE_OBJECT DeviceObject
,
485 PIO_STACK_LOCATION Stack
;
486 ULONG_PTR Information
= 0;
487 PHUB_CHILDDEVICE_EXTENSION UsbChildExtension
;
490 PDEVICE_RELATIONS DeviceRelation
;
492 UsbChildExtension
= (PHUB_CHILDDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
493 Stack
= IoGetCurrentIrpStackLocation(Irp
);
494 MinorFunction
= Stack
->MinorFunction
;
496 switch (MinorFunction
)
498 case IRP_MN_START_DEVICE
:
500 DPRINT1("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
501 Status
= USBHUB_PdoStartDevice(DeviceObject
, Irp
);
504 case IRP_MN_QUERY_CAPABILITIES
:
506 PDEVICE_CAPABILITIES DeviceCapabilities
;
508 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
510 DeviceCapabilities
= (PDEVICE_CAPABILITIES
)Stack
->Parameters
.DeviceCapabilities
.Capabilities
;
511 // FIXME: capabilities can change with connected device
512 DeviceCapabilities
->LockSupported
= FALSE
;
513 DeviceCapabilities
->EjectSupported
= FALSE
;
514 DeviceCapabilities
->Removable
= TRUE
;
515 DeviceCapabilities
->DockDevice
= FALSE
;
516 DeviceCapabilities
->UniqueID
= FALSE
;
517 DeviceCapabilities
->SilentInstall
= FALSE
;
518 DeviceCapabilities
->RawDeviceOK
= FALSE
;
519 DeviceCapabilities
->SurpriseRemovalOK
= FALSE
;
520 DeviceCapabilities
->HardwareDisabled
= FALSE
;
521 //DeviceCapabilities->NoDisplayInUI = FALSE;
522 DeviceCapabilities
->Address
= UsbChildExtension
->PortNumber
;
523 DeviceCapabilities
->UINumber
= 0;
524 DeviceCapabilities
->DeviceState
[0] = PowerDeviceD0
;
525 for (i
= 1; i
< PowerSystemMaximum
; i
++)
526 DeviceCapabilities
->DeviceState
[i
] = PowerDeviceD3
;
527 //DeviceCapabilities->DeviceWake = PowerDeviceUndefined;
528 DeviceCapabilities
->D1Latency
= 0;
529 DeviceCapabilities
->D2Latency
= 0;
530 DeviceCapabilities
->D3Latency
= 0;
531 Status
= STATUS_SUCCESS
;
534 case IRP_MN_QUERY_RESOURCES
:
536 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
538 Information
= Irp
->IoStatus
.Information
;
539 Status
= Irp
->IoStatus
.Status
;
542 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS
:
544 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
546 Information
= Irp
->IoStatus
.Information
;
547 Status
= Irp
->IoStatus
.Status
;
550 case IRP_MN_QUERY_DEVICE_TEXT
:
552 Status
= USBHUB_PdoQueryDeviceText(DeviceObject
, Irp
, &Information
);
555 case IRP_MN_QUERY_ID
:
557 Status
= USBHUB_PdoQueryId(DeviceObject
, Irp
, &Information
);
560 case IRP_MN_QUERY_BUS_INFORMATION
:
562 PPNP_BUS_INFORMATION BusInfo
;
563 BusInfo
= (PPNP_BUS_INFORMATION
)ExAllocatePool(PagedPool
, sizeof(PNP_BUS_INFORMATION
));
564 RtlCopyMemory(&BusInfo
->BusTypeGuid
,
566 sizeof(BusInfo
->BusTypeGuid
));
567 BusInfo
->LegacyBusType
= PNPBus
;
569 BusInfo
->BusNumber
= 0;
570 Information
= (ULONG_PTR
)BusInfo
;
571 Status
= STATUS_SUCCESS
;
574 case IRP_MN_REMOVE_DEVICE
:
576 PHUB_DEVICE_EXTENSION HubDeviceExtension
= (PHUB_DEVICE_EXTENSION
)UsbChildExtension
->ParentDeviceObject
->DeviceExtension
;
577 PUSB_BUS_INTERFACE_HUB_V5 HubInterface
= &HubDeviceExtension
->HubInterface
;
579 DPRINT1("IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
581 /* remove us from pdo list */
583 for(Index
= 0; Index
< USB_MAXCHILDREN
; Index
++)
585 if (HubDeviceExtension
->ChildDeviceObject
[Index
] == DeviceObject
)
587 /* Remove the device */
588 Status
= HubInterface
->RemoveUsbDevice(HubDeviceExtension
->UsbDInterface
.BusContext
, UsbChildExtension
->UsbDeviceHandle
, 0);
590 /* FIXME handle error */
591 ASSERT(Status
== STATUS_SUCCESS
);
594 HubDeviceExtension
->ChildDeviceObject
[Index
] = NULL
;
600 /* Complete the IRP */
601 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
602 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
606 /* Delete the device object */
607 IoDeleteDevice(DeviceObject
);
610 return STATUS_SUCCESS
;
612 case IRP_MN_QUERY_DEVICE_RELATIONS
:
614 /* only target relations are supported */
615 if (Stack
->Parameters
.QueryDeviceRelations
.Type
!= TargetDeviceRelation
)
618 Status
= Irp
->IoStatus
.Status
;
622 /* allocate device relations */
623 DeviceRelation
= (PDEVICE_RELATIONS
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_RELATIONS
));
627 Status
= STATUS_INSUFFICIENT_RESOURCES
;
631 /* init device relation */
632 DeviceRelation
->Count
= 1;
633 DeviceRelation
->Objects
[0] = DeviceObject
;
634 ObReferenceObject(DeviceRelation
->Objects
[0]);
637 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelation
;
638 Status
= STATUS_SUCCESS
;
641 case IRP_MN_QUERY_STOP_DEVICE
:
642 case IRP_MN_QUERY_REMOVE_DEVICE
:
644 /* Sure, no problem */
645 Status
= STATUS_SUCCESS
;
651 DPRINT1("PDO IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction
);
652 Information
= Irp
->IoStatus
.Information
;
653 Status
= Irp
->IoStatus
.Status
;
657 Irp
->IoStatus
.Information
= Information
;
658 Irp
->IoStatus
.Status
= Status
;
659 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);