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/fdo.c
5 * PURPOSE: USB EHCI device driver.
10 /* INCLUDES *******************************************************************/
15 EhciDefferedRoutine(PKDPC Dpc
, PVOID DeferredContext
, PVOID SystemArgument1
, PVOID SystemArgument2
)
17 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
18 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
21 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
) DeferredContext
;
22 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
) FdoDeviceExtension
->Pdo
->DeviceExtension
;
24 CStatus
= (ULONG
) SystemArgument2
;
27 if (CStatus
& EHCI_STS_PCD
)
33 Base
= (ULONG
)FdoDeviceExtension
->ResourceMemory
;
35 /* Loop through the ports */
36 for (i
= 0; i
< FdoDeviceExtension
->ECHICaps
.HCSParams
.PortCount
; i
++)
38 tmp
= READ_REGISTER_ULONG((PULONG
) ((Base
+ EHCI_PORTSC
) + (4 * i
)));
40 /* Check for port change on this port */
43 /* Connect or Disconnect? */
46 DPRINT1("Device connected on port %d\n", i
);
48 /* Check if a companion host controller exists */
49 if (FdoDeviceExtension
->ECHICaps
.HCSParams
.CHCCount
)
51 tmp
= READ_REGISTER_ULONG((PULONG
)((Base
+ EHCI_PORTSC
) + (4 * i
)));
53 /* Port should be in disabled state, as per USB 2.0 specs */
56 DPRINT1("Warning: The port the device has just connected to is not disabled!\n");
59 /* Is this non high speed device */
62 DPRINT1("Releasing ownership to companion host controller!\n");
63 /* Release ownership to companion host controller */
64 WRITE_REGISTER_ULONG((PULONG
) ((Base
+ EHCI_PORTSC
) + (4 * i
)), 0x4000);
69 KeStallExecutionProcessor(30);
71 /* As per USB 2.0 Specs, 9.1.2. Reset the port and clear the status change */
73 /* Sanity, Disable port */
76 WRITE_REGISTER_ULONG((PULONG
) ((Base
+ EHCI_PORTSC
) + (4 * i
)), tmp
);
78 KeStallExecutionProcessor(20);
80 tmp
= READ_REGISTER_ULONG((PULONG
)((Base
+ EHCI_PORTSC
) + (4 * i
)));
82 PdoDeviceExtension
->ChildDeviceCount
++;
83 PdoDeviceExtension
->Ports
[i
].PortStatus
|= USB_PORT_STATUS_HIGH_SPEED
| USB_PORT_STATUS_CONNECT
;
84 PdoDeviceExtension
->Ports
[i
].PortChange
|= USB_PORT_STATUS_CONNECT
;
86 PdoDeviceExtension
->HaltQueue
= FALSE
;
87 KeSetEvent(&PdoDeviceExtension
->QueueDrainedEvent
, 0, FALSE
);
91 DPRINT1("Device disconnected on port %d\n", i
);
93 /* Clear status change */
94 tmp
= READ_REGISTER_ULONG((PULONG
)((Base
+ EHCI_PORTSC
) + (4 * i
)));
96 WRITE_REGISTER_ULONG((PULONG
) ((Base
+ EHCI_PORTSC
) + (4 * i
)), tmp
);
104 InterruptService(PKINTERRUPT Interrupt
, PVOID ServiceContext
)
106 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
107 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
) ServiceContext
;
112 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
114 Base
= (ULONG
)FdoDeviceExtension
->ResourceMemory
;
116 /* Read device status */
117 CStatus
= READ_REGISTER_ULONG ((PULONG
) (Base
+ EHCI_USBSTS
));
118 CurrentFrame
= READ_REGISTER_ULONG((PULONG
) (Base
+ EHCI_FRINDEX
));
120 CStatus
&= (EHCI_ERROR_INT
| EHCI_STS_INT
| EHCI_STS_IAA
| EHCI_STS_PCD
| EHCI_STS_FLR
);
122 if ((!CStatus
) || (FdoDeviceExtension
->DeviceState
== 0))
124 /* This interrupt isnt for us or not ready for it. */
129 WRITE_REGISTER_ULONG((PULONG
) (Base
+ EHCI_USBSTS
), CStatus
);
131 if (CStatus
& EHCI_ERROR_INT
)
133 DPRINT1("EHCI Status=0x%x\n", CStatus
);
136 if (CStatus
& EHCI_STS_FATAL
)
138 DPRINT1("EHCI: Host System Error. Possible PCI problems.\n");
142 if (CStatus
& EHCI_STS_HALT
)
144 DPRINT1("EHCI: Host Controller unexpected halt.\n");
145 /* FIXME: Reset the controller */
148 if (CStatus
& EHCI_STS_INT
)
150 FdoDeviceExtension
->AsyncComplete
= TRUE
;
153 KeInsertQueueDpc(&FdoDeviceExtension
->DpcObject
, FdoDeviceExtension
, (PVOID
)CStatus
);
159 ResetPort(PDEVICE_OBJECT DeviceObject
)
161 /*FIXME: Implement me */
167 StopEhci(PDEVICE_OBJECT DeviceObject
)
169 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
170 PEHCI_USBCMD_CONTENT UsbCmd
;
174 DPRINT1("Stopping Ehci controller\n");
175 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
176 base
= (ULONG
)FdoDeviceExtension
->ResourceMemory
;
178 WRITE_REGISTER_ULONG((PULONG
) (base
+ EHCI_USBINTR
), 0);
180 tmp
= READ_REGISTER_ULONG((PULONG
) (base
+ EHCI_USBCMD
));
181 UsbCmd
= (PEHCI_USBCMD_CONTENT
) & tmp
;
183 WRITE_REGISTER_ULONG((PULONG
) (base
+ EHCI_USBCMD
), tmp
);
187 StartEhci(PDEVICE_OBJECT DeviceObject
)
189 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
190 PEHCI_USBCMD_CONTENT UsbCmd
;
191 PEHCI_USBSTS_CONTEXT usbsts
;
197 DPRINT1("Starting Ehci controller\n");
198 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
199 base
= (ULONG
)FdoDeviceExtension
->ResourceMemory
;
201 tmp
= READ_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBCMD
));
203 /* Stop the device */
204 UsbCmd
= (PEHCI_USBCMD_CONTENT
) &tmp
;
206 WRITE_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBCMD
), tmp
);
208 /* Wait for the device to stop */
211 KeStallExecutionProcessor(10);
212 tmp
= READ_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBSTS
));
213 usbsts
= (PEHCI_USBSTS_CONTEXT
)&tmp
;
215 if (usbsts
->HCHalted
)
219 DPRINT("Waiting for Halt, USBSTS: %x\n", READ_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBSTS
)));
222 tmp
= READ_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBCMD
));
224 /* Reset the device */
225 UsbCmd
= (PEHCI_USBCMD_CONTENT
) &tmp
;
226 UsbCmd
->HCReset
= TRUE
;
227 WRITE_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBCMD
), tmp
);
229 /* Wait for the device to reset */
232 KeStallExecutionProcessor(10);
233 tmp
= READ_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBCMD
));
234 UsbCmd
= (PEHCI_USBCMD_CONTENT
)&tmp
;
236 if (!UsbCmd
->HCReset
)
240 DPRINT("Waiting for reset, USBCMD: %x\n", READ_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBCMD
)));
243 UsbCmd
= (PEHCI_USBCMD_CONTENT
) &tmp
;
245 /* Disable Interrupts on the device */
246 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBINTR
), 0);
247 /* Clear the Status */
248 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBSTS
), 0x0000001f);
250 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_CTRLDSSEGMENT
), 0);
252 /* Set the Periodic Frame List */
253 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_PERIODICLISTBASE
), FdoDeviceExtension
->PeriodicFramListPhysAddr
.LowPart
);
254 /* Set the Async List Queue */
255 WRITE_REGISTER_ULONG((PULONG
) (base
+ EHCI_ASYNCLISTBASE
), FdoDeviceExtension
->AsyncListQueueHeadPtrPhysAddr
.LowPart
& ~(0x1f));
257 /* Set the ansync and periodic to disable */
258 UsbCmd
->PeriodicEnable
= 0;
259 UsbCmd
->AsyncEnable
= 0;
260 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBCMD
), tmp
);
262 /* Set the threshold */
263 UsbCmd
->IntThreshold
= 1;
264 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBCMD
), tmp
);
266 KeInitializeDpc(&FdoDeviceExtension
->DpcObject
,
270 Status
= IoConnectInterrupt(&FdoDeviceExtension
->EhciInterrupt
,
272 FdoDeviceExtension
->DeviceObject
,
274 FdoDeviceExtension
->Vector
,
275 FdoDeviceExtension
->Irql
,
276 FdoDeviceExtension
->Irql
,
277 FdoDeviceExtension
->Mode
,
278 FdoDeviceExtension
->IrqShared
,
279 FdoDeviceExtension
->Affinity
,
282 /* Turn back on interrupts */
283 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBINTR
),
284 EHCI_USBINTR_ERR
| EHCI_USBINTR_ASYNC
| EHCI_USBINTR_HSERR
285 | EHCI_USBINTR_FLROVR
| EHCI_USBINTR_PC
);
286 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBINTR
),
287 EHCI_USBINTR_INTE
| EHCI_USBINTR_ERR
| EHCI_USBINTR_ASYNC
| EHCI_USBINTR_HSERR
288 | EHCI_USBINTR_FLROVR
| EHCI_USBINTR_PC
);
291 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBCMD
), tmp
);
293 /* Wait for the device to start */
296 KeStallExecutionProcessor(10);
297 tmp2
= READ_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBSTS
));
298 usbsts
= (PEHCI_USBSTS_CONTEXT
)&tmp2
;
300 if (!usbsts
->HCHalted
)
304 DPRINT("Waiting for start, USBSTS: %x\n", READ_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBSTS
)));
307 /* Set all port routing to ECHI controller */
308 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_CONFIGFLAG
), 1);
312 GetCapabilities(PFDO_DEVICE_EXTENSION DeviceExtension
, ULONG Base
)
315 PEHCI_HCS_CONTENT PHCS
;
318 if (!DeviceExtension
)
321 PCap
= &DeviceExtension
->ECHICaps
;
323 PCap
->Length
= READ_REGISTER_UCHAR((PUCHAR
)Base
);
324 PCap
->Reserved
= READ_REGISTER_UCHAR((PUCHAR
)(Base
+ 1));
325 PCap
->HCIVersion
= READ_REGISTER_USHORT((PUSHORT
)(Base
+ 2));
326 PCap
->HCSParamsLong
= READ_REGISTER_ULONG((PULONG
)(Base
+ 4));
327 PCap
->HCCParams
= READ_REGISTER_ULONG((PULONG
)(Base
+ 8));
329 DPRINT("Length %d\n", PCap
->Length
);
330 DPRINT("Reserved %d\n", PCap
->Reserved
);
331 DPRINT("HCIVersion %x\n", PCap
->HCIVersion
);
332 DPRINT("HCSParams %x\n", PCap
->HCSParamsLong
);
333 DPRINT("HCCParams %x\n", PCap
->HCCParams
);
335 if (PCap
->HCCParams
& 0x02)
336 DPRINT1("Frame list size is configurable\n");
338 if (PCap
->HCCParams
& 0x01)
339 DPRINT1("64bit address mode not supported!\n");
341 DPRINT1("Number of Ports: %d\n", PCap
->HCSParams
.PortCount
);
343 if (PCap
->HCSParams
.PortPowerControl
)
344 DPRINT1("Port Power Control is enabled\n");
346 if (!PCap
->HCSParams
.CHCCount
)
348 DPRINT1("Number of Companion Host controllers %x\n", PCap
->HCSParams
.CHCCount
);
349 DPRINT1("Number of Ports Per CHC: %d\n", PCap
->HCSParams
.PortPerCHC
);
352 /* Copied from USBDRIVER in trunk */
353 PHCS
= (PEHCI_HCS_CONTENT
)&DeviceExtension
->ECHICaps
.HCSParams
;
354 if (PHCS
->PortRouteRules
)
356 for (i
= 0; i
< 8; i
++)
358 PCap
->PortRoute
[i
] = READ_REGISTER_UCHAR((PUCHAR
) (Base
+ 12 + i
));
364 StartDevice(PDEVICE_OBJECT DeviceObject
, PCM_PARTIAL_RESOURCE_LIST raw
, PCM_PARTIAL_RESOURCE_LIST translated
)
366 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
367 PCM_PARTIAL_RESOURCE_DESCRIPTOR resource
;
368 DEVICE_DESCRIPTION DeviceDescription
;
369 ULONG NumberResources
;
376 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
378 RtlZeroMemory(&DeviceDescription
, sizeof(DEVICE_DESCRIPTION
));
379 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
380 DeviceDescription
.Master
= TRUE
;
381 DeviceDescription
.ScatterGather
= TRUE
;
382 DeviceDescription
.Dma32BitAddresses
= TRUE
;
383 DeviceDescription
.DmaWidth
= 2;
384 DeviceDescription
.InterfaceType
= PCIBus
;
385 DeviceDescription
.MaximumLength
= EHCI_MAX_SIZE_TRANSFER
;
387 FdoDeviceExtension
->pDmaAdapter
= IoGetDmaAdapter(FdoDeviceExtension
->LowerDevice
,
389 &FdoDeviceExtension
->MapRegisters
);
391 if (FdoDeviceExtension
->pDmaAdapter
== NULL
)
393 DPRINT1("IoGetDmaAdapter failed!\n");
397 /* Allocate Common Buffer for Periodic Frame List */
398 FdoDeviceExtension
->PeriodicFramList
=
399 FdoDeviceExtension
->pDmaAdapter
->DmaOperations
->AllocateCommonBuffer(FdoDeviceExtension
->pDmaAdapter
,
400 sizeof(ULONG
) * 1024, &FdoDeviceExtension
->PeriodicFramListPhysAddr
, FALSE
);
402 if (FdoDeviceExtension
->PeriodicFramList
== NULL
)
404 DPRINT1("FdoDeviceExtension->PeriodicFramList is null\n");
405 return STATUS_UNSUCCESSFUL
;
409 RtlZeroMemory(FdoDeviceExtension
->PeriodicFramList
, sizeof(ULONG
) * 1024);
411 /* Allocate Common Buffer for Async List Head Queue */
412 FdoDeviceExtension
->AsyncListQueueHeadPtr
=
413 FdoDeviceExtension
->pDmaAdapter
->DmaOperations
->AllocateCommonBuffer(FdoDeviceExtension
->pDmaAdapter
,
414 /* FIXME: Memory Size should be calculated using
415 structures sizes needed for queue head + 20480 (max data transfer */
417 &FdoDeviceExtension
->AsyncListQueueHeadPtrPhysAddr
, FALSE
);
419 if (FdoDeviceExtension
->AsyncListQueueHeadPtr
== NULL
)
421 DPRINT1("Failed to allocate common buffer for AsyncListQueueHeadPtr!\n");
422 return STATUS_UNSUCCESSFUL
;
426 RtlZeroMemory(FdoDeviceExtension
->AsyncListQueueHeadPtr
,
427 /* FIXME: Same as FIXME above */
430 Status
= IoGetDeviceProperty(FdoDeviceExtension
->LowerDevice
,
431 DevicePropertyAddress
,
435 if (NT_SUCCESS(Status
))
437 DPRINT1("--->DeviceAddress: %x\n", DeviceAddress
);
440 Status
= IoGetDeviceProperty(FdoDeviceExtension
->LowerDevice
,
441 DevicePropertyBusNumber
,
445 if (NT_SUCCESS(Status
))
447 DPRINT1("--->BusNumber: %x\n", BusNumber
);
450 /* Get the resources the PNP Manager gave */
451 NumberResources
= translated
->Count
;
452 DPRINT("NumberResources %d\n", NumberResources
);
453 for (iCount
= 0; iCount
< NumberResources
; iCount
++)
455 DPRINT("Resource Info %d:\n", iCount
);
456 resource
= &translated
->PartialDescriptors
[iCount
];
457 switch(resource
->Type
)
459 case CmResourceTypePort
:
461 DPRINT("Port Start: %x\n", resource
->u
.Port
.Start
);
462 DPRINT("Port Length %d\n", resource
->u
.Port
.Length
);
463 /* FIXME: Handle Ports */
466 case CmResourceTypeInterrupt
:
468 DPRINT("Interrupt Vector: %x\n", resource
->u
.Interrupt
.Vector
);
469 FdoDeviceExtension
->Vector
= resource
->u
.Interrupt
.Vector
;
470 FdoDeviceExtension
->Irql
= resource
->u
.Interrupt
.Level
;
471 FdoDeviceExtension
->Affinity
= resource
->u
.Interrupt
.Affinity
;
472 FdoDeviceExtension
->Mode
= (resource
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
) ? Latched
: LevelSensitive
;
473 FdoDeviceExtension
->IrqShared
= resource
->ShareDisposition
== CmResourceShareShared
;
476 case CmResourceTypeMemory
:
478 ULONG ResourceBase
= 0;
481 DPRINT("Mem Start: %x\n", resource
->u
.Memory
.Start
);
482 DPRINT("Mem Length: %d\n", resource
->u
.Memory
.Length
);
484 ResourceBase
= (ULONG
) MmMapIoSpace(resource
->u
.Memory
.Start
, resource
->u
.Memory
.Length
, FALSE
);
485 DPRINT("ResourceBase %x\n", ResourceBase
);
487 FdoDeviceExtension
->ResourceBase
= (PULONG
) ResourceBase
;
488 GetCapabilities(FdoDeviceExtension
, (ULONG
)ResourceBase
);
489 FdoDeviceExtension
->ResourceMemory
= (PULONG
)((ULONG
)ResourceBase
+ FdoDeviceExtension
->ECHICaps
.Length
);
490 DPRINT("ResourceMemory %x\n", FdoDeviceExtension
->ResourceMemory
);
491 if (FdoDeviceExtension
->ResourceBase
== NULL
)
493 DPRINT1("MmMapIoSpace failed!!!!!!!!!\n");
495 MemLength
= resource
->u
.Memory
.Length
;
496 FdoDeviceExtension
->Size
= MemLength
;
500 case CmResourceTypeDma
:
502 DPRINT("Dma Channel: %x\n", resource
->u
.Dma
.Channel
);
503 DPRINT("Dma Port: %d\n", resource
->u
.Dma
.Port
);
506 case CmResourceTypeDevicePrivate
:
508 /* Windows does this. */
509 DPRINT1("CmResourceTypeDevicePrivate not handled\n");
514 DPRINT1("PNP Manager gave resource type not handled!! Notify Developers!\n");
520 StartEhci(DeviceObject
);
521 FdoDeviceExtension
->DeviceState
= DEVICESTARTED
;
523 return STATUS_SUCCESS
;
527 FdoQueryBusRelations(
528 PDEVICE_OBJECT DeviceObject
,
529 PDEVICE_RELATIONS
* pDeviceRelations
)
531 PFDO_DEVICE_EXTENSION DeviceExtension
;
532 PDEVICE_RELATIONS DeviceRelations
= NULL
;
534 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
536 ULONG UsbDeviceNumber
= 0;
537 WCHAR CharDeviceName
[64];
539 UNICODE_STRING DeviceName
;
541 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
543 /* Create the PDO with the next available number */
546 /* FIXME: Use safe string */
547 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBPDO-%d", UsbDeviceNumber); */
548 swprintf(CharDeviceName
, L
"\\Device\\USBPDO-%d", UsbDeviceNumber
);
549 RtlInitUnicodeString(&DeviceName
, CharDeviceName
);
550 DPRINT("DeviceName %wZ\n", &DeviceName
);
552 Status
= IoCreateDevice(DeviceObject
->DriverObject
,
553 sizeof(PDO_DEVICE_EXTENSION
),
555 FILE_DEVICE_BUS_EXTENDER
,
560 if (NT_SUCCESS(Status
))
563 if ((Status
== STATUS_OBJECT_NAME_EXISTS
) || (Status
== STATUS_OBJECT_NAME_COLLISION
))
565 /* Try the next name */
570 /* Bail on any other error */
571 if (!NT_SUCCESS(Status
))
573 DPRINT1("UsbEhci: Failed to create PDO %wZ, Status %x\n", &DeviceName
, Status
);
578 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Pdo
->DeviceExtension
;
579 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
580 PdoDeviceExtension
->Common
.IsFdo
= FALSE
;
582 PdoDeviceExtension
->ControllerFdo
= DeviceObject
;
583 PdoDeviceExtension
->DeviceObject
= Pdo
;
585 InitializeListHead(&PdoDeviceExtension
->IrpQueue
);
586 KeInitializeSpinLock(&PdoDeviceExtension
->IrpQueueLock
);
588 KeInitializeEvent(&PdoDeviceExtension
->QueueDrainedEvent
, SynchronizationEvent
, TRUE
);
590 ExInitializeFastMutex(&PdoDeviceExtension
->ListLock
);
592 Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
594 DeviceExtension
->Pdo
= Pdo
;
596 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, sizeof(DEVICE_RELATIONS
));
598 if (!DeviceRelations
)
600 return STATUS_INSUFFICIENT_RESOURCES
;
603 DeviceRelations
->Count
= 1;
604 DeviceRelations
->Objects
[0] = Pdo
;
605 ObReferenceObject(Pdo
);
607 *pDeviceRelations
= DeviceRelations
;
608 return STATUS_SUCCESS
;
612 FdoDispatchPnp(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
615 PIO_STACK_LOCATION Stack
= NULL
;
616 PCM_PARTIAL_RESOURCE_LIST raw
;
617 PCM_PARTIAL_RESOURCE_LIST translated
;
618 ULONG_PTR Information
= 0;
620 Stack
= IoGetCurrentIrpStackLocation(Irp
);
622 switch(Stack
->MinorFunction
)
624 case IRP_MN_START_DEVICE
:
626 DPRINT1("START_DEVICE\n");
627 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
628 Status
= ForwardAndWait(DeviceObject
, Irp
);
630 raw
= &Stack
->Parameters
.StartDevice
.AllocatedResources
->List
[0].PartialResourceList
;
631 translated
= &Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
->List
[0].PartialResourceList
;
632 Status
= StartDevice(DeviceObject
, raw
, translated
);
635 case IRP_MN_QUERY_DEVICE_RELATIONS
:
637 DPRINT1("IRP_MN_QUERY_DEVICE_RELATIONS\n");
638 switch(Stack
->Parameters
.QueryDeviceRelations
.Type
)
642 PDEVICE_RELATIONS DeviceRelations
= NULL
;
643 DPRINT("BusRelations\n");
644 Status
= FdoQueryBusRelations(DeviceObject
, &DeviceRelations
);
645 Information
= (ULONG_PTR
)DeviceRelations
;
650 DPRINT("Unknown query device relations type\n");
651 Status
= STATUS_NOT_IMPLEMENTED
;
657 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
659 DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
660 return ForwardIrpAndForget(DeviceObject
, Irp
);
663 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS
:
665 DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
667 case IRP_MN_QUERY_INTERFACE
:
669 Status
= STATUS_SUCCESS
;
671 Status
= ForwardIrpAndForget(DeviceObject
, Irp
);
677 DPRINT1("IRP_MJ_PNP / Unhandled minor function 0x%lx\n", Stack
->MinorFunction
);
678 return ForwardIrpAndForget(DeviceObject
, Irp
);
682 Irp
->IoStatus
.Information
= Information
;
683 Irp
->IoStatus
.Status
= Status
;
684 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
689 AddDevice(PDRIVER_OBJECT DriverObject
, PDEVICE_OBJECT Pdo
)
691 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
693 ULONG UsbDeviceNumber
= 0;
694 WCHAR CharDeviceName
[64];
695 WCHAR CharSymLinkName
[64];
696 UNICODE_STRING DeviceName
;
697 UNICODE_STRING SymLinkName
;
698 UNICODE_STRING InterfaceSymLinkName
;
700 PCI_COMMON_CONFIG PciConfig
;
702 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
704 DPRINT("Ehci AddDevice\n");
706 /* Create the FDO with next available number */
709 /* FIXME: Use safe string sprintf*/
710 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBFDO-%d", UsbDeviceNumber); */
711 swprintf(CharDeviceName
, L
"\\Device\\USBFDO-%d", UsbDeviceNumber
);
712 RtlInitUnicodeString(&DeviceName
, CharDeviceName
);
713 DPRINT("DeviceName %wZ\n", &DeviceName
);
715 Status
= IoCreateDevice(DriverObject
,
716 sizeof(FDO_DEVICE_EXTENSION
),
718 FILE_DEVICE_CONTROLLER
,
723 if (NT_SUCCESS(Status
))
726 if ((Status
== STATUS_OBJECT_NAME_EXISTS
) || (Status
== STATUS_OBJECT_NAME_COLLISION
))
728 /* Try the next name */
733 /* Bail on any other error */
734 if (!NT_SUCCESS(Status
))
736 DPRINT1("UsbEhci: Failed to create %wZ, Status %x\n", &DeviceName
, Status
);
741 swprintf(CharSymLinkName
, L
"\\Device\\HCD%d", UsbDeviceNumber
);
742 RtlInitUnicodeString(&SymLinkName
, CharSymLinkName
);
743 Status
= IoCreateSymbolicLink(&SymLinkName
, &DeviceName
);
745 if (!NT_SUCCESS(Status
))
747 DPRINT1("Warning: Unable to create symbolic link for ehci host controller!\n");
750 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
) Fdo
->DeviceExtension
;
751 RtlZeroMemory(FdoDeviceExtension
, sizeof(PFDO_DEVICE_EXTENSION
));
753 FdoDeviceExtension
->Common
.IsFdo
= TRUE
;
754 FdoDeviceExtension
->DeviceObject
= Fdo
;
756 FdoDeviceExtension
->LowerDevice
= IoAttachDeviceToDeviceStack(Fdo
, Pdo
);
758 if (FdoDeviceExtension
->LowerDevice
== NULL
)
760 DPRINT1("UsbEhci: Failed to attach to device stack!\n");
761 IoDeleteSymbolicLink(&SymLinkName
);
764 return STATUS_NO_SUCH_DEVICE
;
767 Fdo
->Flags
|= DO_BUFFERED_IO
;// | DO_POWER_PAGABLE;
769 ASSERT(FdoDeviceExtension
->LowerDevice
== Pdo
);
771 Status
= GetBusInterface(FdoDeviceExtension
->LowerDevice
, &FdoDeviceExtension
->BusInterface
);
773 if (!NT_SUCCESS(Status
))
775 DPRINT1("GetBusInterface() failed with %x\n", Status
);
776 IoDetachDevice(FdoDeviceExtension
->LowerDevice
);
777 IoDeleteSymbolicLink(&SymLinkName
);
782 BytesRead
= (*FdoDeviceExtension
->BusInterface
.GetBusData
)(
783 FdoDeviceExtension
->BusInterface
.Context
,
784 PCI_WHICHSPACE_CONFIG
,
787 PCI_COMMON_HDR_LENGTH
);
790 if (BytesRead
!= PCI_COMMON_HDR_LENGTH
)
792 DPRINT1("GetBusData failed!\n");
793 IoDetachDevice(FdoDeviceExtension
->LowerDevice
);
794 IoDeleteSymbolicLink(&SymLinkName
);
796 return STATUS_UNSUCCESSFUL
;
799 if (PciConfig
.Command
& PCI_ENABLE_IO_SPACE
)
800 DPRINT("PCI_ENABLE_IO_SPACE\n");
802 if (PciConfig
.Command
& PCI_ENABLE_MEMORY_SPACE
)
803 DPRINT("PCI_ENABLE_MEMORY_SPACE\n");
805 if (PciConfig
.Command
& PCI_ENABLE_BUS_MASTER
)
806 DPRINT("PCI_ENABLE_BUS_MASTER\n");
808 DPRINT("BaseAddress[0] %x\n", PciConfig
.u
.type0
.BaseAddresses
[0]);
809 DPRINT1("Vendor %x\n", PciConfig
.VendorID
);
810 DPRINT1("Device %x\n", PciConfig
.DeviceID
);
812 FdoDeviceExtension
->VendorId
= PciConfig
.VendorID
;
813 FdoDeviceExtension
->DeviceId
= PciConfig
.DeviceID
;
815 FdoDeviceExtension
->DeviceState
= DEVICEINTIALIZED
;
817 Status
= IoRegisterDeviceInterface(Pdo
, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER
, NULL
, &InterfaceSymLinkName
);
818 if (!NT_SUCCESS(Status
))
820 DPRINT1("Unable to register device interface!\n");
825 Status
= IoSetDeviceInterfaceState(&InterfaceSymLinkName
, TRUE
);
826 DPRINT1("SetInterfaceState %x\n", Status
);
827 if (!NT_SUCCESS(Status
))
830 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
832 return STATUS_SUCCESS
;