2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbehci/hcd_controller.cpp
5 * PURPOSE: USB EHCI device driver.
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
14 class CHCDController
: public IHCDController
17 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
19 STDMETHODIMP_(ULONG
) AddRef()
21 InterlockedIncrement(&m_Ref
);
24 STDMETHODIMP_(ULONG
) Release()
26 InterlockedDecrement(&m_Ref
);
36 // interface functions
37 NTSTATUS
Initialize(IN PROOTHDCCONTROLLER RootHCDController
, IN PDRIVER_OBJECT DriverObject
, IN PDEVICE_OBJECT PhysicalDeviceObject
);
38 NTSTATUS
HandlePnp(IN PDEVICE_OBJECT DeviceObject
, IN OUT PIRP Irp
);
39 NTSTATUS
HandlePower(IN PDEVICE_OBJECT DeviceObject
, IN OUT PIRP Irp
);
40 NTSTATUS
HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject
, IN OUT PIRP Irp
);
43 NTSTATUS
CreateFDO(PDRIVER_OBJECT DriverObject
, PDEVICE_OBJECT
* OutDeviceObject
);
44 NTSTATUS
CreatePDO(PDRIVER_OBJECT DriverObject
, PDEVICE_OBJECT
* OutDeviceObject
);
45 NTSTATUS
HandleQueryInterface(PIO_STACK_LOCATION IoStack
);
46 NTSTATUS
SetDeviceInterface(BOOLEAN bEnable
);
48 // constructor / destructor
49 CHCDController(IUnknown
*OuterUnknown
){}
50 virtual ~CHCDController(){}
54 PROOTHDCCONTROLLER m_RootController
;
55 PDRIVER_OBJECT m_DriverObject
;
56 PDEVICE_OBJECT m_PhysicalDeviceObject
;
57 PDEVICE_OBJECT m_FunctionalDeviceObject
;
58 PDEVICE_OBJECT m_NextDeviceObject
;
59 PUSBHARDWAREDEVICE m_Hardware
;
60 PDEVICE_OBJECT m_BusPDO
;
61 UNICODE_STRING m_HubDeviceInterfaceString
;
62 BOOLEAN m_InterfaceEnabled
;
63 ULONG m_PDODeviceNumber
;
64 ULONG m_FDODeviceNumber
;
67 //=================================================================================================
72 CHCDController::QueryInterface(
76 UNICODE_STRING GuidString
;
78 if (IsEqualGUIDAligned(refiid
, IID_IUnknown
))
80 *Output
= PVOID(PUNKNOWN(this));
81 PUNKNOWN(*Output
)->AddRef();
82 return STATUS_SUCCESS
;
85 return STATUS_UNSUCCESSFUL
;
88 //-------------------------------------------------------------------------------------------------
90 CHCDController::Initialize(
91 IN PROOTHDCCONTROLLER RootHCDController
,
92 IN PDRIVER_OBJECT DriverObject
,
93 IN PDEVICE_OBJECT PhysicalDeviceObject
)
96 PCOMMON_DEVICE_EXTENSION DeviceExtension
;
99 // create usb hardware
101 Status
= CreateUSBHardware(&m_Hardware
);
102 if (!NT_SUCCESS(Status
))
105 // failed to create hardware object
107 DPRINT1("Failed to create hardware object\n");
108 return STATUS_INSUFFICIENT_RESOURCES
;
112 // initialize members
114 m_DriverObject
= DriverObject
;
115 m_PhysicalDeviceObject
= PhysicalDeviceObject
;
116 m_RootController
= RootHCDController
;
121 Status
= CreateFDO(m_DriverObject
, &m_FunctionalDeviceObject
);
122 if (!NT_SUCCESS(Status
))
125 // failed to create PDO
131 // now attach to device stack
133 m_NextDeviceObject
= IoAttachDeviceToDeviceStack(m_FunctionalDeviceObject
, m_PhysicalDeviceObject
);
134 if (!m_NextDeviceObject
)
137 // failed to attach to device stack
139 IoDeleteDevice(m_FunctionalDeviceObject
);
140 m_FunctionalDeviceObject
= 0;
142 return STATUS_NO_SUCH_DEVICE
;
146 // initialize hardware object
148 Status
= m_Hardware
->Initialize(m_DriverObject
, m_FunctionalDeviceObject
, m_PhysicalDeviceObject
, m_NextDeviceObject
);
149 if (!NT_SUCCESS(Status
))
151 DPRINT1("Failed to initialize hardware object %x\n", Status
);
154 // failed to initialize hardware object, detach from device stack
156 IoDetachDevice(m_NextDeviceObject
);
159 // now delete the device
161 IoDeleteDevice(m_FunctionalDeviceObject
);
164 // nullify pointers :)
166 m_FunctionalDeviceObject
= 0;
167 m_NextDeviceObject
= 0;
176 m_FunctionalDeviceObject
->Flags
|= DO_BUFFERED_IO
| DO_POWER_PAGABLE
;
180 // get device extension
182 DeviceExtension
= (PCOMMON_DEVICE_EXTENSION
)m_FunctionalDeviceObject
->DeviceExtension
;
183 PC_ASSERT(DeviceExtension
);
186 // initialize device extension
188 DeviceExtension
->IsFDO
= TRUE
;
189 DeviceExtension
->IsHub
= FALSE
;
190 DeviceExtension
->HcdController
= PHCDCONTROLLER(this);
193 // device is initialized
195 m_FunctionalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
199 // is there a root controller
201 if (m_RootController
)
206 m_RootController
->AddRef();
209 // register with controller
211 m_RootController
->RegisterHCD(this);
218 return STATUS_SUCCESS
;
221 //-------------------------------------------------------------------------------------------------
223 CHCDController::HandleDeviceControl(
224 IN PDEVICE_OBJECT DeviceObject
,
227 PIO_STACK_LOCATION IoStack
;
228 PCOMMON_DEVICE_EXTENSION DeviceExtension
;
229 NTSTATUS Status
= STATUS_NOT_IMPLEMENTED
;
230 PUSB_HCD_DRIVERKEY_NAME DriverKey
;
234 // get current stack location
236 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
239 // get device extension
241 DeviceExtension
= (PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
244 DPRINT1("HandleDeviceControl>Type: FDO %u IoCtl %x InputBufferLength %lu OutputBufferLength %lu\n",
245 DeviceExtension
->IsFDO
,
246 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
,
247 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
,
248 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
);
253 if (DeviceExtension
->IsFDO
)
256 // perform ioctl for FDO
258 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_GET_HCD_DRIVERKEY_NAME
)
261 // check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
263 if(IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>= sizeof(USB_HCD_DRIVERKEY_NAME
))
266 // get device property size
268 Status
= IoGetDeviceProperty(m_PhysicalDeviceObject
, DevicePropertyDriverKeyName
, 0, NULL
, &ResultLength
);
270 DriverKey
= (PUSB_HCD_DRIVERKEY_NAME
)Irp
->AssociatedIrp
.SystemBuffer
;
275 if (Status
== STATUS_BUFFER_TOO_SMALL
)
278 // does the caller provide enough buffer space
280 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>= ResultLength
)
285 Status
= IoGetDeviceProperty(m_PhysicalDeviceObject
, DevicePropertyDriverKeyName
, IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
- sizeof(ULONG
), DriverKey
->DriverKeyName
, &ResultLength
);
287 if (NT_SUCCESS(Status
))
290 // informal debug print
292 DPRINT1("Result %S\n", DriverKey
->DriverKeyName
);
299 DriverKey
->ActualLength
= ResultLength
+ FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME
, DriverKeyName
) + sizeof(WCHAR
);
300 Irp
->IoStatus
.Information
= IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
301 Status
= STATUS_SUCCESS
;
307 // buffer is certainly too small
309 Status
= STATUS_BUFFER_OVERFLOW
;
310 Irp
->IoStatus
.Information
= sizeof(USB_HCD_DRIVERKEY_NAME
);
313 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_USB_GET_ROOT_HUB_NAME
)
315 DPRINT1("IOCTL_USB_GET_ROOT_HUB_NAME is not implemented yet\n");
321 // the PDO does not support any device IOCTLs
323 Status
= STATUS_SUCCESS
;
327 // complete the request
329 Irp
->IoStatus
.Status
= Status
;
330 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
339 CHCDController::HandlePnp(
340 IN PDEVICE_OBJECT DeviceObject
,
343 PIO_STACK_LOCATION IoStack
;
344 PCOMMON_DEVICE_EXTENSION DeviceExtension
;
345 PCM_RESOURCE_LIST RawResourceList
;
346 PCM_RESOURCE_LIST TranslatedResourceList
;
347 PDEVICE_RELATIONS DeviceRelations
;
348 PDEVICE_CAPABILITIES DeviceCapabilities
;
353 DPRINT("HandlePnp\n");
356 // get device extension
358 DeviceExtension
= (PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
361 // get current stack location
363 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
365 switch(IoStack
->MinorFunction
)
367 case IRP_MN_START_DEVICE
:
369 DPRINT1("IRP_MN_START FDO: %lu\n", DeviceExtension
->IsFDO
);
371 if (DeviceExtension
->IsFDO
)
374 // first start lower device object
376 Status
= SyncForwardIrp(m_NextDeviceObject
, Irp
);
378 if (NT_SUCCESS(Status
))
381 // operation succeeded, lets start the device
383 RawResourceList
= IoStack
->Parameters
.StartDevice
.AllocatedResources
;
384 TranslatedResourceList
= IoStack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
;
389 // start the hardware
391 Status
= m_Hardware
->PnpStart(RawResourceList
, TranslatedResourceList
);
396 // HACK / FIXME: Windows XP SP3 fails to enumerate the PDO correctly, which
397 // causes the PDO device never to startup.
399 Status
= SetDeviceInterface(TRUE
);
404 // start the PDO device
409 //FIXME create the parent root hub device
413 // register device interface
415 Status
= SetDeviceInterface(TRUE
);
418 DPRINT1("IRP_MN_START FDO: %lu Status %x\n", DeviceExtension
->IsFDO
, Status
);
422 case IRP_MN_QUERY_DEVICE_RELATIONS
:
424 DPRINT1("IRP_MN_QUERY_DEVICE_RELATIONS Type %lx FDO: \n", IoStack
->Parameters
.QueryDeviceRelations
.Type
, DeviceExtension
->IsFDO
);
426 if (m_BusPDO
== NULL
)
431 Status
= CreatePDO(m_DriverObject
, &m_BusPDO
);
433 if (!NT_SUCCESS(Status
))
436 // failed to create bus device object
442 // initialize extension
444 DeviceExtension
= (PCOMMON_DEVICE_EXTENSION
)m_BusPDO
->DeviceExtension
;
445 DeviceExtension
->IsFDO
= FALSE
;
446 DeviceExtension
->IsHub
= FALSE
;
447 DeviceExtension
->HcdController
= (this);
452 m_BusPDO
->Flags
&= ~DO_DEVICE_INITIALIZING
;
455 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
== BusRelations
)
458 // allocate device relations
460 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, sizeof(DEVICE_RELATIONS
));
462 if (!DeviceRelations
)
467 Status
= STATUS_INSUFFICIENT_RESOURCES
;
472 // init device relations
474 DeviceRelations
->Count
= 1;
475 DeviceRelations
->Objects
[0] = m_BusPDO
;
477 ObReferenceObject(m_BusPDO
);
482 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
483 Status
= STATUS_SUCCESS
;
488 case IRP_MN_STOP_DEVICE
:
490 DPRINT1("IRP_MN_STOP_DEVICE FDO: %lu\n", DeviceExtension
->IsFDO
);
497 Status
= m_Hardware
->PnpStop();
504 Status
= STATUS_SUCCESS
;
507 if (NT_SUCCESS(Status
))
512 Status
= SyncForwardIrp(m_NextDeviceObject
, Irp
);
516 case IRP_MN_QUERY_CAPABILITIES
:
518 DPRINT1("IRP_MN_QUERY_CAPABILITIES FDO: %lu\n", DeviceExtension
->IsFDO
);
520 if (DeviceExtension
->IsFDO
== FALSE
)
522 DeviceCapabilities
= (PDEVICE_CAPABILITIES
)IoStack
->Parameters
.DeviceCapabilities
.Capabilities
;
524 DeviceCapabilities
->LockSupported
= FALSE
;
525 DeviceCapabilities
->EjectSupported
= FALSE
;
526 DeviceCapabilities
->Removable
= FALSE
;
527 DeviceCapabilities
->DockDevice
= FALSE
;
528 DeviceCapabilities
->UniqueID
= FALSE
;
529 DeviceCapabilities
->SilentInstall
= FALSE
;
530 DeviceCapabilities
->RawDeviceOK
= FALSE
;
531 DeviceCapabilities
->SurpriseRemovalOK
= FALSE
;
532 DeviceCapabilities
->Address
= 0;
533 DeviceCapabilities
->UINumber
= 0;
534 DeviceCapabilities
->DeviceD2
= 1;
537 DeviceCapabilities
->HardwareDisabled
= FALSE
;
538 DeviceCapabilities
->NoDisplayInUI
= FALSE
;
539 DeviceCapabilities
->DeviceState
[0] = PowerDeviceD0
;
540 for (Index
= 0; Index
< PowerSystemMaximum
; Index
++)
541 DeviceCapabilities
->DeviceState
[Index
] = PowerDeviceD3
;
542 DeviceCapabilities
->DeviceWake
= PowerDeviceUnspecified
;
543 DeviceCapabilities
->D1Latency
= 0;
544 DeviceCapabilities
->D2Latency
= 0;
545 DeviceCapabilities
->D3Latency
= 0;
547 Status
= STATUS_SUCCESS
;
552 // forward irp to next device object
554 IoSkipCurrentIrpStackLocation(Irp
);
555 return IoCallDriver(m_NextDeviceObject
, Irp
);
560 case IRP_MN_QUERY_INTERFACE
:
562 DPRINT1("IRP_MN_QUERY_INTERFACE FDO %u\n", DeviceExtension
->IsFDO
);
564 // check if the device is FDO
566 if (DeviceExtension
->IsFDO
)
569 // just pass the irp to next device object
571 IoSkipCurrentIrpStackLocation(Irp
);
572 return IoCallDriver(m_NextDeviceObject
, Irp
);
576 // handle device interface requests
578 Status
= HandleQueryInterface(IoStack
);
581 case IRP_MN_QUERY_BUS_INFORMATION
:
583 DPRINT1("IRP_MN_QUERY_BUS_INFORMATION FDO %lx\n", DeviceExtension
->IsFDO
);
585 if (DeviceExtension
->IsFDO
== FALSE
)
588 // allocate buffer for bus guid
590 Guid
= (LPGUID
)ExAllocatePool(PagedPool
, sizeof(GUID
));
596 RtlMoveMemory(Guid
, &GUID_BUS_TYPE_USB
, sizeof(GUID
));
597 Status
= STATUS_SUCCESS
;
598 Irp
->IoStatus
.Information
= (ULONG_PTR
)Guid
;
603 case IRP_MN_REMOVE_DEVICE
:
605 DPRINT1("IRP_MN_REMOVE_DEVICE FDO: %lu\n", DeviceExtension
->IsFDO
);
607 if (DeviceExtension
->IsFDO
== FALSE
)
610 // deactivate device interface for BUS PDO
612 SetDeviceInterface(FALSE
);
615 // complete the request first
617 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
618 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
623 IoDeleteDevice(m_BusPDO
);
629 return STATUS_SUCCESS
;
634 // detach device from device stack
636 IoDetachDevice(m_NextDeviceObject
);
641 IoDeleteDevice(m_FunctionalDeviceObject
);
644 Status
= STATUS_SUCCESS
;
649 if (DeviceExtension
->IsFDO
)
651 DPRINT1("HandlePnp> FDO Dispatch to lower device object %lu\n", IoStack
->MinorFunction
);
654 // forward irp to next device object
656 IoSkipCurrentIrpStackLocation(Irp
);
657 return IoCallDriver(m_NextDeviceObject
, Irp
);
661 DPRINT1("UNHANDLED PDO Request %lu\n", IoStack
->MinorFunction
);
667 // store result and complete request
669 Irp
->IoStatus
.Status
= Status
;
670 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
676 CHCDController::HandlePower(
677 IN PDEVICE_OBJECT DeviceObject
,
682 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
683 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
685 return STATUS_NOT_IMPLEMENTED
;
689 CHCDController::HandleQueryInterface(
690 PIO_STACK_LOCATION IoStack
)
692 UNICODE_STRING GuidBuffer
;
695 if (IsEqualGUIDAligned(*IoStack
->Parameters
.QueryInterface
.InterfaceType
, USB_BUS_INTERFACE_HUB_GUID
))
697 DPRINT1("HandleQueryInterface> UNIMPLEMENTED USB_BUS_INTERFACE_HUB_GUID Version %x\n", IoStack
->Parameters
.QueryInterface
.Version
);
700 else if (IsEqualGUIDAligned(*IoStack
->Parameters
.QueryInterface
.InterfaceType
, USB_BUS_INTERFACE_USBDI_GUID
))
702 DPRINT1("HandleQueryInterface> UNIMPLEMENTED USB_BUS_INTERFACE_USBDI_GUID Version %x\n", IoStack
->Parameters
.QueryInterface
.Version
);
707 // convert guid to string
709 Status
= RtlStringFromGUID(*IoStack
->Parameters
.QueryInterface
.InterfaceType
, &GuidBuffer
);
710 if (NT_SUCCESS(Status
))
715 DPRINT1("HandleQueryInterface GUID: %wZ Version %x\n", &GuidBuffer
, IoStack
->Parameters
.QueryInterface
.Version
);
720 RtlFreeUnicodeString(&GuidBuffer
);
723 return STATUS_NOT_SUPPORTED
;
727 CHCDController::CreateFDO(
728 PDRIVER_OBJECT DriverObject
,
729 PDEVICE_OBJECT
* OutDeviceObject
)
731 WCHAR CharDeviceName
[64];
733 ULONG UsbDeviceNumber
= 0;
734 UNICODE_STRING DeviceName
;
739 // construct device name
741 swprintf(CharDeviceName
, L
"\\Device\\USBFDO-%d", UsbDeviceNumber
);
744 // initialize device name
746 RtlInitUnicodeString(&DeviceName
, CharDeviceName
);
751 Status
= IoCreateDevice(DriverObject
,
752 sizeof(COMMON_DEVICE_EXTENSION
),
754 FILE_DEVICE_CONTROLLER
,
762 if (NT_SUCCESS(Status
))
766 // is there a device object with that same name
768 if ((Status
== STATUS_OBJECT_NAME_EXISTS
) || (Status
== STATUS_OBJECT_NAME_COLLISION
))
778 // bail out on other errors
780 if (!NT_SUCCESS(Status
))
782 DPRINT1("CreateFDO: Failed to create %wZ, Status %x\n", &DeviceName
, Status
);
790 m_FDODeviceNumber
= UsbDeviceNumber
;
792 DPRINT1("CreateFDO: DeviceName %wZ\n", &DeviceName
);
799 CHCDController::SetDeviceInterface(
805 UNICODE_STRING Link
, FDO
;
810 // register device interface
812 Status
= IoRegisterDeviceInterface(m_PhysicalDeviceObject
, &GUID_DEVINTERFACE_USB_HUB
, 0, &m_HubDeviceInterfaceString
);
814 if (NT_SUCCESS(Status
))
817 // now enable the device interface
819 Status
= IoSetDeviceInterfaceState(&m_HubDeviceInterfaceString
, TRUE
);
824 m_InterfaceEnabled
= TRUE
;
828 // create legacy link
830 swprintf(LinkName
, L
"\\DosDevices\\HCD%d", m_PDODeviceNumber
);
831 swprintf(FDOName
, L
"\\Device\\USBFDO-%d", m_FDODeviceNumber
);
832 RtlInitUnicodeString(&Link
, LinkName
);
833 RtlInitUnicodeString(&FDO
, FDOName
);
836 // create symbolic link
838 Status
= IoCreateSymbolicLink(&Link
, &FDO
);
840 if (!NT_SUCCESS(Status
))
848 else if (m_InterfaceEnabled
)
851 // disable device interface
853 Status
= IoSetDeviceInterfaceState(&m_HubDeviceInterfaceString
, FALSE
);
855 if (NT_SUCCESS(Status
))
858 // now delete interface string
860 RtlFreeUnicodeString(&m_HubDeviceInterfaceString
);
866 m_InterfaceEnabled
= FALSE
;
877 CHCDController::CreatePDO(
878 PDRIVER_OBJECT DriverObject
,
879 PDEVICE_OBJECT
* OutDeviceObject
)
881 WCHAR CharDeviceName
[64];
883 ULONG UsbDeviceNumber
= 0;
884 UNICODE_STRING DeviceName
;
889 // construct device name
891 swprintf(CharDeviceName
, L
"\\Device\\USBPDO-%d", UsbDeviceNumber
);
894 // initialize device name
896 RtlInitUnicodeString(&DeviceName
, CharDeviceName
);
901 Status
= IoCreateDevice(DriverObject
,
902 sizeof(COMMON_DEVICE_EXTENSION
),
904 FILE_DEVICE_CONTROLLER
,
909 /* check for success */
910 if (NT_SUCCESS(Status
))
914 // is there a device object with that same name
916 if ((Status
== STATUS_OBJECT_NAME_EXISTS
) || (Status
== STATUS_OBJECT_NAME_COLLISION
))
926 // bail out on other errors
928 if (!NT_SUCCESS(Status
))
930 DPRINT1("CreatePDO: Failed to create %wZ, Status %x\n", &DeviceName
, Status
);
938 m_PDODeviceNumber
= UsbDeviceNumber
;
940 DPRINT1("CreateFDO: DeviceName %wZ\n", &DeviceName
);
948 PHCDCONTROLLER
*OutHcdController
)
953 // allocate controller
955 This
= new(NonPagedPool
, TAG_USBEHCI
) CHCDController(0);
959 // failed to allocate
961 return STATUS_INSUFFICIENT_RESOURCES
;
965 // add reference count
972 *OutHcdController
= (PHCDCONTROLLER
)This
;
977 return STATUS_SUCCESS
;