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
,
18 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
20 STDMETHODIMP_(ULONG
) AddRef()
22 InterlockedIncrement(&m_Ref
);
25 STDMETHODIMP_(ULONG
) Release()
27 InterlockedDecrement(&m_Ref
);
37 // IHCDController interface functions
38 NTSTATUS
Initialize(IN PROOTHDCCONTROLLER RootHCDController
, IN PDRIVER_OBJECT DriverObject
, IN PDEVICE_OBJECT PhysicalDeviceObject
);
40 // IDispatchIrp interface functions
41 NTSTATUS
HandlePnp(IN PDEVICE_OBJECT DeviceObject
, IN OUT PIRP Irp
);
42 NTSTATUS
HandlePower(IN PDEVICE_OBJECT DeviceObject
, IN OUT PIRP Irp
);
43 NTSTATUS
HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject
, IN OUT PIRP Irp
);
46 NTSTATUS
CreateFDO(PDRIVER_OBJECT DriverObject
, PDEVICE_OBJECT
* OutDeviceObject
);
47 NTSTATUS
SetSymbolicLink(BOOLEAN Enable
);
49 // constructor / destructor
50 CHCDController(IUnknown
*OuterUnknown
){}
51 virtual ~CHCDController(){}
55 PROOTHDCCONTROLLER m_RootController
;
56 PDRIVER_OBJECT m_DriverObject
;
57 PDEVICE_OBJECT m_PhysicalDeviceObject
;
58 PDEVICE_OBJECT m_FunctionalDeviceObject
;
59 PDEVICE_OBJECT m_NextDeviceObject
;
60 PUSBHARDWAREDEVICE m_Hardware
;
61 PHUBCONTROLLER m_HubController
;
62 ULONG m_FDODeviceNumber
;
65 //=================================================================================================
70 CHCDController::QueryInterface(
74 return STATUS_UNSUCCESSFUL
;
77 //-------------------------------------------------------------------------------------------------
79 CHCDController::Initialize(
80 IN PROOTHDCCONTROLLER RootHCDController
,
81 IN PDRIVER_OBJECT DriverObject
,
82 IN PDEVICE_OBJECT PhysicalDeviceObject
)
85 PCOMMON_DEVICE_EXTENSION DeviceExtension
;
88 // create usb hardware
90 Status
= CreateUSBHardware(&m_Hardware
);
91 if (!NT_SUCCESS(Status
))
94 // failed to create hardware object
96 DPRINT1("Failed to create hardware object\n");
97 return STATUS_INSUFFICIENT_RESOURCES
;
101 // initialize members
103 m_DriverObject
= DriverObject
;
104 m_PhysicalDeviceObject
= PhysicalDeviceObject
;
105 m_RootController
= RootHCDController
;
110 Status
= CreateFDO(m_DriverObject
, &m_FunctionalDeviceObject
);
111 if (!NT_SUCCESS(Status
))
114 // failed to create PDO
120 // now attach to device stack
122 m_NextDeviceObject
= IoAttachDeviceToDeviceStack(m_FunctionalDeviceObject
, m_PhysicalDeviceObject
);
123 if (!m_NextDeviceObject
)
126 // failed to attach to device stack
128 IoDeleteDevice(m_FunctionalDeviceObject
);
129 m_FunctionalDeviceObject
= 0;
131 return STATUS_NO_SUCH_DEVICE
;
135 // initialize hardware object
137 Status
= m_Hardware
->Initialize(m_DriverObject
, m_FunctionalDeviceObject
, m_PhysicalDeviceObject
, m_NextDeviceObject
);
138 if (!NT_SUCCESS(Status
))
140 DPRINT1("Failed to initialize hardware object %x\n", Status
);
143 // failed to initialize hardware object, detach from device stack
145 IoDetachDevice(m_NextDeviceObject
);
148 // now delete the device
150 IoDeleteDevice(m_FunctionalDeviceObject
);
153 // nullify pointers :)
155 m_FunctionalDeviceObject
= 0;
156 m_NextDeviceObject
= 0;
165 m_FunctionalDeviceObject
->Flags
|= DO_BUFFERED_IO
| DO_POWER_PAGABLE
;
169 // get device extension
171 DeviceExtension
= (PCOMMON_DEVICE_EXTENSION
)m_FunctionalDeviceObject
->DeviceExtension
;
172 PC_ASSERT(DeviceExtension
);
175 // initialize device extension
177 DeviceExtension
->IsFDO
= TRUE
;
178 DeviceExtension
->IsHub
= FALSE
;
179 DeviceExtension
->Dispatcher
= PDISPATCHIRP(this);
182 // device is initialized
184 m_FunctionalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
188 // is there a root controller
190 if (m_RootController
)
195 m_RootController
->AddRef();
198 // register with controller
200 m_RootController
->RegisterHCD(this);
207 return STATUS_SUCCESS
;
210 //-------------------------------------------------------------------------------------------------
212 CHCDController::HandleDeviceControl(
213 IN PDEVICE_OBJECT DeviceObject
,
216 PIO_STACK_LOCATION IoStack
;
217 PCOMMON_DEVICE_EXTENSION DeviceExtension
;
218 NTSTATUS Status
= STATUS_NOT_IMPLEMENTED
;
219 PUSB_HCD_DRIVERKEY_NAME DriverKey
;
223 // get current stack location
225 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
228 // get device extension
230 DeviceExtension
= (PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
235 PC_ASSERT(DeviceExtension
->IsFDO
);
237 DPRINT1("HandleDeviceControl>Type: IoCtl %x InputBufferLength %lu OutputBufferLength %lu\n",
238 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
,
239 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
,
240 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
);
243 // perform ioctl for FDO
245 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_GET_HCD_DRIVERKEY_NAME
)
248 // check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
250 if(IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>= sizeof(USB_HCD_DRIVERKEY_NAME
))
253 // get device property size
255 Status
= IoGetDeviceProperty(m_PhysicalDeviceObject
, DevicePropertyDriverKeyName
, 0, NULL
, &ResultLength
);
260 DriverKey
= (PUSB_HCD_DRIVERKEY_NAME
)Irp
->AssociatedIrp
.SystemBuffer
;
265 if (Status
== STATUS_BUFFER_TOO_SMALL
)
268 // does the caller provide enough buffer space
270 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>= ResultLength
)
275 Status
= IoGetDeviceProperty(m_PhysicalDeviceObject
, DevicePropertyDriverKeyName
, IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
- sizeof(ULONG
), DriverKey
->DriverKeyName
, &ResultLength
);
277 if (NT_SUCCESS(Status
))
280 // informal debug print
282 DPRINT1("Result %S\n", DriverKey
->DriverKeyName
);
289 DriverKey
->ActualLength
= ResultLength
+ FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME
, DriverKeyName
) + sizeof(WCHAR
);
290 Irp
->IoStatus
.Information
= IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
291 Status
= STATUS_SUCCESS
;
297 // buffer is certainly too small
299 Status
= STATUS_BUFFER_OVERFLOW
;
300 Irp
->IoStatus
.Information
= sizeof(USB_HCD_DRIVERKEY_NAME
);
303 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_USB_GET_ROOT_HUB_NAME
)
306 // check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
308 if(IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>= sizeof(USB_HCD_DRIVERKEY_NAME
))
313 PC_ASSERT(m_HubController
);
318 DriverKey
= (PUSB_HCD_DRIVERKEY_NAME
)Irp
->AssociatedIrp
.SystemBuffer
;
323 Status
= m_HubController
->GetHubControllerSymbolicLink(IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
- sizeof(ULONG
), DriverKey
->DriverKeyName
, &ResultLength
);
326 if (NT_SUCCESS(Status
))
331 PC_ASSERT(IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
- sizeof(ULONG
) - sizeof(WCHAR
) >= ResultLength
);
333 DriverKey
->DriverKeyName
[ResultLength
/ sizeof(WCHAR
)] = L
'\0';
334 DPRINT1("Result %S\n", DriverKey
->DriverKeyName
);
340 DriverKey
->ActualLength
= ResultLength
+ FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME
, DriverKeyName
) + sizeof(WCHAR
);
341 Irp
->IoStatus
.Information
= IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
342 Status
= STATUS_SUCCESS
;
347 // buffer is certainly too small
349 Status
= STATUS_BUFFER_OVERFLOW
;
350 Irp
->IoStatus
.Information
= sizeof(USB_HCD_DRIVERKEY_NAME
);
355 // complete the request
357 Irp
->IoStatus
.Status
= Status
;
358 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
367 CHCDController::HandlePnp(
368 IN PDEVICE_OBJECT DeviceObject
,
371 PIO_STACK_LOCATION IoStack
;
372 PCOMMON_DEVICE_EXTENSION DeviceExtension
;
373 PCM_RESOURCE_LIST RawResourceList
;
374 PCM_RESOURCE_LIST TranslatedResourceList
;
375 PDEVICE_RELATIONS DeviceRelations
;
379 // get device extension
381 DeviceExtension
= (PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
386 PC_ASSERT(DeviceExtension
->IsFDO
);
389 // get current stack location
391 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
393 switch(IoStack
->MinorFunction
)
395 case IRP_MN_START_DEVICE
:
397 DPRINT1("CHCDController::HandlePnp IRP_MN_START FDO\n");
400 // first start lower device object
402 Status
= SyncForwardIrp(m_NextDeviceObject
, Irp
);
404 if (NT_SUCCESS(Status
))
407 // operation succeeded, lets start the device
409 RawResourceList
= IoStack
->Parameters
.StartDevice
.AllocatedResources
;
410 TranslatedResourceList
= IoStack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
;
415 // start the hardware
417 Status
= m_Hardware
->PnpStart(RawResourceList
, TranslatedResourceList
);
421 // enable symbolic link
423 Status
= SetSymbolicLink(TRUE
);
426 DPRINT1("CHCDController::HandlePnp IRP_MN_START FDO: Status %x\n", Status
);
429 case IRP_MN_QUERY_DEVICE_RELATIONS
:
431 DPRINT1("CHCDController::HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %lx\n", IoStack
->Parameters
.QueryDeviceRelations
.Type
);
433 if (m_HubController
== NULL
)
436 // create hub controller
438 Status
= CreateHubController(&m_HubController
);
439 if (!NT_SUCCESS(Status
))
442 // failed to create hub controller
448 // initialize hub controller
450 Status
= m_HubController
->Initialize(m_DriverObject
, PHCDCONTROLLER(this), m_Hardware
, TRUE
, 0 /* FIXME*/);
451 if (!NT_SUCCESS(Status
))
454 // failed to initialize hub controller
460 // add reference to prevent it from getting deleting while hub driver adds / removes references
462 m_HubController
->AddRef();
465 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
== BusRelations
)
468 // allocate device relations
470 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, sizeof(DEVICE_RELATIONS
));
472 if (!DeviceRelations
)
477 Status
= STATUS_INSUFFICIENT_RESOURCES
;
482 // init device relations
484 DeviceRelations
->Count
= 1;
485 Status
= m_HubController
->GetHubControllerDeviceObject(&DeviceRelations
->Objects
[0]);
490 PC_ASSERT(Status
== STATUS_SUCCESS
);
492 ObReferenceObject(DeviceRelations
->Objects
[0]);
497 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
498 Status
= STATUS_SUCCESS
;
505 Status
= STATUS_NOT_SUPPORTED
;
509 case IRP_MN_STOP_DEVICE
:
511 DPRINT1("CHCDController::HandlePnp IRP_MN_STOP_DEVICE\n");
518 Status
= m_Hardware
->PnpStop();
525 Status
= STATUS_SUCCESS
;
528 if (NT_SUCCESS(Status
))
533 Status
= SyncForwardIrp(m_NextDeviceObject
, Irp
);
537 case IRP_MN_REMOVE_DEVICE
:
539 DPRINT1("CHCDController::HandlePnp IRP_MN_REMOVE_DEVICE FDO\n");
542 // detach device from device stack
544 IoDetachDevice(m_NextDeviceObject
);
549 IoDeleteDevice(m_FunctionalDeviceObject
);
551 Status
= STATUS_SUCCESS
;
557 // forward irp to next device object
559 IoSkipCurrentIrpStackLocation(Irp
);
560 return IoCallDriver(m_NextDeviceObject
, Irp
);
565 // store result and complete request
567 Irp
->IoStatus
.Status
= Status
;
568 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
574 CHCDController::HandlePower(
575 IN PDEVICE_OBJECT DeviceObject
,
580 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
581 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
583 return STATUS_NOT_IMPLEMENTED
;
587 CHCDController::CreateFDO(
588 PDRIVER_OBJECT DriverObject
,
589 PDEVICE_OBJECT
* OutDeviceObject
)
591 WCHAR CharDeviceName
[64];
593 ULONG UsbDeviceNumber
= 0;
594 UNICODE_STRING DeviceName
;
599 // construct device name
601 swprintf(CharDeviceName
, L
"\\Device\\USBFDO-%d", UsbDeviceNumber
);
604 // initialize device name
606 RtlInitUnicodeString(&DeviceName
, CharDeviceName
);
611 Status
= IoCreateDevice(DriverObject
,
612 sizeof(COMMON_DEVICE_EXTENSION
),
614 FILE_DEVICE_CONTROLLER
,
622 if (NT_SUCCESS(Status
))
626 // is there a device object with that same name
628 if ((Status
== STATUS_OBJECT_NAME_EXISTS
) || (Status
== STATUS_OBJECT_NAME_COLLISION
))
638 // bail out on other errors
640 if (!NT_SUCCESS(Status
))
642 DPRINT1("CreateFDO: Failed to create %wZ, Status %x\n", &DeviceName
, Status
);
650 m_FDODeviceNumber
= UsbDeviceNumber
;
652 DPRINT1("CreateFDO: DeviceName %wZ\n", &DeviceName
);
659 CHCDController::SetSymbolicLink(
665 UNICODE_STRING Link
, FDO
;
670 // create legacy link
672 swprintf(LinkName
, L
"\\DosDevices\\HCD%d", m_FDODeviceNumber
);
673 swprintf(FDOName
, L
"\\Device\\USBFDO-%d", m_FDODeviceNumber
);
674 RtlInitUnicodeString(&Link
, LinkName
);
675 RtlInitUnicodeString(&FDO
, FDOName
);
678 // create symbolic link
680 Status
= IoCreateSymbolicLink(&Link
, &FDO
);
682 if (!NT_SUCCESS(Status
))
693 // create legacy link
695 swprintf(LinkName
, L
"\\DosDevices\\HCD%d", m_FDODeviceNumber
);
696 RtlInitUnicodeString(&Link
, LinkName
);
699 // now delete the symbolic link
701 Status
= IoDeleteSymbolicLink(&Link
);
703 if (!NT_SUCCESS(Status
))
720 PHCDCONTROLLER
*OutHcdController
)
725 // allocate controller
727 This
= new(NonPagedPool
, TAG_USBEHCI
) CHCDController(0);
731 // failed to allocate
733 return STATUS_INSUFFICIENT_RESOURCES
;
737 // add reference count
744 *OutHcdController
= (PHCDCONTROLLER
)This
;
749 return STATUS_SUCCESS
;