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 *******************************************************************/
14 //#include "ntstrsafe.h"
17 DeviceArrivalWorkItem(PDEVICE_OBJECT DeviceObject
, PVOID Context
)
19 PWORKITEM_DATA WorkItemData
;
20 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
22 WorkItemData
= (PWORKITEM_DATA
)Context
;
23 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
25 if (PdoDeviceExtension
->CallbackRoutine
)
26 PdoDeviceExtension
->CallbackRoutine(PdoDeviceExtension
->CallbackContext
);
28 DPRINT1("PdoDeviceExtension->CallbackRoutine is NULL!\n");
30 IoFreeWorkItem(WorkItemData
->IoWorkItem
);
31 ExFreePool(WorkItemData
);
35 EhciDefferedRoutine(PKDPC Dpc
, PVOID DeferredContext
, PVOID SystemArgument1
, PVOID SystemArgument2
)
37 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
38 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
41 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
) DeferredContext
;
42 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
) FdoDeviceExtension
->Pdo
->DeviceExtension
;
44 CStatus
= (ULONG
) SystemArgument2
;
47 if (CStatus
& EHCI_STS_PCD
)
53 Base
= (ULONG
)FdoDeviceExtension
->ResourceMemory
;
55 /* Loop through the ports */
56 for (i
= 0; i
< FdoDeviceExtension
->ECHICaps
.HCSParams
.PortCount
; i
++)
58 tmp
= READ_REGISTER_ULONG((PULONG
) ((Base
+ EHCI_PORTSC
) + (4 * i
)));
60 /* Check for port change on this port */
63 PWORKITEM_DATA WorkItemData
= NULL
;
64 /* Connect or Disconnect? */
67 DPRINT1("Device connected on port %d\n", i
);
69 /* Check if a companion host controller exists */
70 if (FdoDeviceExtension
->ECHICaps
.HCSParams
.CHCCount
)
72 tmp
= READ_REGISTER_ULONG((PULONG
)((Base
+ EHCI_PORTSC
) + (4 * i
)));
74 /* Port should be in disabled state, as per USB 2.0 specs */
77 DPRINT1("Warning: The port the device has just connected to is not disabled!\n");
80 /* Is this non high speed device */
83 DPRINT1("Releasing ownership to companion host controller!\n");
84 /* Release ownership to companion host controller */
85 WRITE_REGISTER_ULONG((PULONG
) ((Base
+ EHCI_PORTSC
) + (4 * i
)), 0x4000);
89 KeStallExecutionProcessor(30);
90 DPRINT("port tmp %x\n", tmp
);
92 /* As per USB 2.0 Specs, 9.1.2. Reset the port and clear the status change */
94 /* Sanity, Disable port */
97 WRITE_REGISTER_ULONG((PULONG
) ((Base
+ EHCI_PORTSC
) + (4 * i
)), tmp
);
99 KeStallExecutionProcessor(20);
101 tmp
= READ_REGISTER_ULONG((PULONG
)((Base
+ EHCI_PORTSC
) + (4 * i
)));
103 DPRINT("port tmp %x\n", tmp
);
104 GetDeviceDescriptor(FdoDeviceExtension
, 0, 0, FALSE
);
105 PdoDeviceExtension
->ChildDeviceCount
++;
106 WorkItemData
= ExAllocatePool(NonPagedPool
, sizeof(WORKITEM_DATA
));
107 if (!WorkItemData
) ASSERT(FALSE
);
108 WorkItemData
->IoWorkItem
= IoAllocateWorkItem(PdoDeviceExtension
->DeviceObject
);
109 WorkItemData
->PdoDeviceExtension
= PdoDeviceExtension
;
110 IoQueueWorkItem(WorkItemData
->IoWorkItem
,
111 (PIO_WORKITEM_ROUTINE
)DeviceArrivalWorkItem
,
117 DPRINT1("Device disconnected on port %d\n", i
);
119 /* Clear status change */
120 tmp
= READ_REGISTER_ULONG((PULONG
)((Base
+ EHCI_PORTSC
) + (4 * i
)));
122 WRITE_REGISTER_ULONG((PULONG
) ((Base
+ EHCI_PORTSC
) + (4 * i
)), tmp
);
130 InterruptService(PKINTERRUPT Interrupt
, PVOID ServiceContext
)
132 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
133 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
) ServiceContext
;
138 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
140 Base
= (ULONG
)FdoDeviceExtension
->ResourceMemory
;
142 /* Read device status */
143 CStatus
= READ_REGISTER_ULONG ((PULONG
) (Base
+ EHCI_USBSTS
));
144 CurrentFrame
= READ_REGISTER_ULONG((PULONG
) (Base
+ EHCI_FRINDEX
));
146 CStatus
&= (EHCI_ERROR_INT
| EHCI_STS_INT
| EHCI_STS_IAA
| EHCI_STS_PCD
| EHCI_STS_FLR
);
148 if ((!CStatus
) || (FdoDeviceExtension
->DeviceState
== 0))
150 /* This interrupt isnt for us or not ready for it. */
155 WRITE_REGISTER_ULONG((PULONG
) (Base
+ EHCI_USBSTS
), CStatus
);
157 if (CStatus
& EHCI_ERROR_INT
)
159 DPRINT1("EHCI Status=0x%x\n", CStatus
);
162 if (CStatus
& EHCI_STS_FATAL
)
164 DPRINT1("EHCI: Host System Error. Possible PCI problems.\n");
168 if (CStatus
& EHCI_STS_HALT
)
170 DPRINT1("EHCI: Host Controller unexpected halt.\n");
171 /* FIXME: Reset the controller */
174 if (CStatus
& EHCI_STS_INT
)
176 FdoDeviceExtension
->AsyncComplete
= TRUE
;
179 KeInsertQueueDpc(&FdoDeviceExtension
->DpcObject
, FdoDeviceExtension
, (PVOID
)CStatus
);
185 ResetPort(PDEVICE_OBJECT DeviceObject
)
187 /*FIXME: Implement me */
193 StopEhci(PDEVICE_OBJECT DeviceObject
)
195 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
196 PEHCI_USBCMD_CONTENT UsbCmd
;
200 DPRINT1("Stopping Ehci controller\n");
201 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
202 base
= (ULONG
)FdoDeviceExtension
->ResourceMemory
;
204 WRITE_REGISTER_ULONG((PULONG
) (base
+ EHCI_USBINTR
), 0);
206 tmp
= READ_REGISTER_ULONG((PULONG
) (base
+ EHCI_USBCMD
));
207 UsbCmd
= (PEHCI_USBCMD_CONTENT
) & tmp
;
209 WRITE_REGISTER_ULONG((PULONG
) (base
+ EHCI_USBCMD
), tmp
);
213 StartEhci(PDEVICE_OBJECT DeviceObject
)
215 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
216 PEHCI_USBCMD_CONTENT UsbCmd
;
217 PEHCI_USBSTS_CONTEXT usbsts
;
223 DPRINT1("Starting Ehci controller\n");
224 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
225 base
= (ULONG
)FdoDeviceExtension
->ResourceMemory
;
227 tmp
= READ_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBCMD
));
229 /* Stop the device */
230 UsbCmd
= (PEHCI_USBCMD_CONTENT
) &tmp
;
232 WRITE_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBCMD
), tmp
);
234 /* Wait for the device to stop */
237 KeStallExecutionProcessor(10);
238 tmp
= READ_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBSTS
));
239 usbsts
= (PEHCI_USBSTS_CONTEXT
)&tmp
;
241 if (usbsts
->HCHalted
)
245 DPRINT("Waiting for Halt, USBSTS: %x\n", READ_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBSTS
)));
248 tmp
= READ_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBCMD
));
250 /* Reset the device */
251 UsbCmd
= (PEHCI_USBCMD_CONTENT
) &tmp
;
252 UsbCmd
->HCReset
= TRUE
;
253 WRITE_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBCMD
), tmp
);
255 /* Wait for the device to reset */
258 KeStallExecutionProcessor(10);
259 tmp
= READ_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBCMD
));
260 UsbCmd
= (PEHCI_USBCMD_CONTENT
)&tmp
;
262 if (!UsbCmd
->HCReset
)
266 DPRINT("Waiting for reset, USBCMD: %x\n", READ_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBCMD
)));
269 UsbCmd
= (PEHCI_USBCMD_CONTENT
) &tmp
;
271 /* Disable Interrupts on the device */
272 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBINTR
), 0);
273 /* Clear the Status */
274 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBSTS
), 0x0000001f);
276 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_CTRLDSSEGMENT
), 0);
278 /* Set the Periodic Frame List */
279 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_PERIODICLISTBASE
), FdoDeviceExtension
->PeriodicFramListPhysAddr
.LowPart
);
280 /* Set the Async List Queue */
281 WRITE_REGISTER_ULONG((PULONG
) (base
+ EHCI_ASYNCLISTBASE
), FdoDeviceExtension
->AsyncListQueueHeadPtrPhysAddr
.LowPart
& ~(0x1f));
283 /* Set the ansync and periodic to disable */
284 UsbCmd
->PeriodicEnable
= 0;
285 UsbCmd
->AsyncEnable
= 0;
286 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBCMD
), tmp
);
288 /* Set the threshold */
289 UsbCmd
->IntThreshold
= 1;
290 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBCMD
), tmp
);
292 KeInitializeDpc(&FdoDeviceExtension
->DpcObject
,
296 Status
= IoConnectInterrupt(&FdoDeviceExtension
->EhciInterrupt
,
298 FdoDeviceExtension
->DeviceObject
,
300 FdoDeviceExtension
->Vector
,
301 FdoDeviceExtension
->Irql
,
302 FdoDeviceExtension
->Irql
,
303 FdoDeviceExtension
->Mode
,
304 FdoDeviceExtension
->IrqShared
,
305 FdoDeviceExtension
->Affinity
,
308 /* Turn back on interrupts */
309 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBINTR
),
310 EHCI_USBINTR_ERR
| EHCI_USBINTR_ASYNC
| EHCI_USBINTR_HSERR
311 | EHCI_USBINTR_FLROVR
| EHCI_USBINTR_PC
);
312 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBINTR
),
313 EHCI_USBINTR_INTE
| EHCI_USBINTR_ERR
| EHCI_USBINTR_ASYNC
| EHCI_USBINTR_HSERR
314 | EHCI_USBINTR_FLROVR
| EHCI_USBINTR_PC
);
317 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBCMD
), tmp
);
319 /* Wait for the device to start */
322 KeStallExecutionProcessor(10);
323 tmp2
= READ_REGISTER_ULONG((PULONG
)(base
+ EHCI_USBSTS
));
324 usbsts
= (PEHCI_USBSTS_CONTEXT
)&tmp2
;
326 if (!usbsts
->HCHalted
)
330 DPRINT("Waiting for start, USBSTS: %x\n", READ_REGISTER_ULONG ((PULONG
)(base
+ EHCI_USBSTS
)));
333 /* Set all port routing to ECHI controller */
334 WRITE_REGISTER_ULONG((PULONG
)(base
+ EHCI_CONFIGFLAG
), 1);
338 GetCapabilities(PFDO_DEVICE_EXTENSION DeviceExtension
, ULONG Base
)
341 PEHCI_HCS_CONTENT PHCS
;
344 if (!DeviceExtension
)
347 PCap
= &DeviceExtension
->ECHICaps
;
349 PCap
->Length
= READ_REGISTER_UCHAR((PUCHAR
)Base
);
350 PCap
->Reserved
= READ_REGISTER_UCHAR((PUCHAR
)(Base
+ 1));
351 PCap
->HCIVersion
= READ_REGISTER_USHORT((PUSHORT
)(Base
+ 2));
352 PCap
->HCSParamsLong
= READ_REGISTER_ULONG((PULONG
)(Base
+ 4));
353 PCap
->HCCParams
= READ_REGISTER_ULONG((PULONG
)(Base
+ 8));
355 DPRINT("Length %d\n", PCap
->Length
);
356 DPRINT("Reserved %d\n", PCap
->Reserved
);
357 DPRINT("HCIVersion %x\n", PCap
->HCIVersion
);
358 DPRINT("HCSParams %x\n", PCap
->HCSParamsLong
);
359 DPRINT("HCCParams %x\n", PCap
->HCCParams
);
361 if (PCap
->HCCParams
& 0x02)
362 DPRINT1("Frame list size is configurable\n");
364 if (PCap
->HCCParams
& 0x01)
365 DPRINT1("64bit address mode not supported!\n");
367 DPRINT1("Number of Ports: %d\n", PCap
->HCSParams
.PortCount
);
369 if (PCap
->HCSParams
.PortPowerControl
)
370 DPRINT1("Port Power Control is enabled\n");
372 if (!PCap
->HCSParams
.CHCCount
)
374 DPRINT1("Number of Companion Host controllers %x\n", PCap
->HCSParams
.CHCCount
);
375 DPRINT1("Number of Ports Per CHC: %d\n", PCap
->HCSParams
.PortPerCHC
);
378 /* Copied from USBDRIVER in trunk */
379 PHCS
= (PEHCI_HCS_CONTENT
)&DeviceExtension
->ECHICaps
.HCSParams
;
380 if (PHCS
->PortRouteRules
)
382 for (i
= 0; i
< 8; i
++)
384 PCap
->PortRoute
[i
] = READ_REGISTER_UCHAR((PUCHAR
) (Base
+ 12 + i
));
390 StartDevice(PDEVICE_OBJECT DeviceObject
, PCM_PARTIAL_RESOURCE_LIST raw
, PCM_PARTIAL_RESOURCE_LIST translated
)
392 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
393 PCM_PARTIAL_RESOURCE_DESCRIPTOR resource
;
394 DEVICE_DESCRIPTION DeviceDescription
;
395 ULONG NumberResources
;
402 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
404 RtlZeroMemory(&DeviceDescription
, sizeof(DEVICE_DESCRIPTION
));
405 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
406 DeviceDescription
.Master
= TRUE
;
407 DeviceDescription
.ScatterGather
= TRUE
;
408 DeviceDescription
.Dma32BitAddresses
= TRUE
;
409 DeviceDescription
.DmaWidth
= 2;
410 DeviceDescription
.InterfaceType
= PCIBus
;
411 DeviceDescription
.MaximumLength
= EHCI_MAX_SIZE_TRANSFER
;
413 FdoDeviceExtension
->pDmaAdapter
= IoGetDmaAdapter(FdoDeviceExtension
->LowerDevice
,
415 &FdoDeviceExtension
->MapRegisters
);
417 if (FdoDeviceExtension
->pDmaAdapter
== NULL
)
419 DPRINT1("IoGetDmaAdapter failed!\n");
423 /* Allocate Common Buffer for Periodic Frame List */
424 FdoDeviceExtension
->PeriodicFramList
=
425 FdoDeviceExtension
->pDmaAdapter
->DmaOperations
->AllocateCommonBuffer(FdoDeviceExtension
->pDmaAdapter
,
426 sizeof(ULONG
) * 1024, &FdoDeviceExtension
->PeriodicFramListPhysAddr
, FALSE
);
428 if (FdoDeviceExtension
->PeriodicFramList
== NULL
)
430 DPRINT1("FdoDeviceExtension->PeriodicFramList is null\n");
431 return STATUS_UNSUCCESSFUL
;
435 RtlZeroMemory(FdoDeviceExtension
->PeriodicFramList
, sizeof(ULONG
) * 1024);
437 /* Allocate Common Buffer for Async List Head Queue */
438 FdoDeviceExtension
->AsyncListQueueHeadPtr
=
439 FdoDeviceExtension
->pDmaAdapter
->DmaOperations
->AllocateCommonBuffer(FdoDeviceExtension
->pDmaAdapter
,
440 /* FIXME: Memory Size should be calculated using
441 structures sizes needed for queue head + 20480 (max data transfer */
443 &FdoDeviceExtension
->AsyncListQueueHeadPtrPhysAddr
, FALSE
);
445 if (FdoDeviceExtension
->AsyncListQueueHeadPtr
== NULL
)
447 DPRINT1("Failed to allocate common buffer for AsyncListQueueHeadPtr!\n");
448 return STATUS_UNSUCCESSFUL
;
452 RtlZeroMemory(FdoDeviceExtension
->AsyncListQueueHeadPtr
,
453 /* FIXME: Same as FIXME above */
456 Status
= IoGetDeviceProperty(FdoDeviceExtension
->LowerDevice
,
457 DevicePropertyAddress
,
461 if (NT_SUCCESS(Status
))
463 DPRINT1("--->DeviceAddress: %x\n", DeviceAddress
);
466 Status
= IoGetDeviceProperty(FdoDeviceExtension
->LowerDevice
,
467 DevicePropertyBusNumber
,
471 if (NT_SUCCESS(Status
))
473 DPRINT1("--->BusNumber: %x\n", BusNumber
);
476 /* Get the resources the PNP Manager gave */
477 NumberResources
= translated
->Count
;
478 DPRINT("NumberResources %d\n", NumberResources
);
479 for (iCount
= 0; iCount
< NumberResources
; iCount
++)
481 DPRINT("Resource Info %d:\n", iCount
);
482 resource
= &translated
->PartialDescriptors
[iCount
];
483 switch(resource
->Type
)
485 case CmResourceTypePort
:
487 DPRINT("Port Start: %x\n", resource
->u
.Port
.Start
);
488 DPRINT("Port Length %d\n", resource
->u
.Port
.Length
);
489 /* FIXME: Handle Ports */
492 case CmResourceTypeInterrupt
:
494 DPRINT("Interrupt Vector: %x\n", resource
->u
.Interrupt
.Vector
);
495 FdoDeviceExtension
->Vector
= resource
->u
.Interrupt
.Vector
;
496 FdoDeviceExtension
->Irql
= resource
->u
.Interrupt
.Level
;
497 FdoDeviceExtension
->Affinity
= resource
->u
.Interrupt
.Affinity
;
498 FdoDeviceExtension
->Mode
= (resource
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
) ? Latched
: LevelSensitive
;
499 FdoDeviceExtension
->IrqShared
= resource
->ShareDisposition
== CmResourceShareShared
;
502 case CmResourceTypeMemory
:
504 ULONG ResourceBase
= 0;
507 DPRINT("Mem Start: %x\n", resource
->u
.Memory
.Start
);
508 DPRINT("Mem Length: %d\n", resource
->u
.Memory
.Length
);
510 ResourceBase
= (ULONG
) MmMapIoSpace(resource
->u
.Memory
.Start
, resource
->u
.Memory
.Length
, FALSE
);
511 DPRINT("ResourceBase %x\n", ResourceBase
);
513 FdoDeviceExtension
->ResourceBase
= (PULONG
) ResourceBase
;
514 GetCapabilities(FdoDeviceExtension
, (ULONG
)ResourceBase
);
515 FdoDeviceExtension
->ResourceMemory
= (PULONG
)((ULONG
)ResourceBase
+ FdoDeviceExtension
->ECHICaps
.Length
);
516 DPRINT("ResourceMemory %x\n", FdoDeviceExtension
->ResourceMemory
);
517 if (FdoDeviceExtension
->ResourceBase
== NULL
)
519 DPRINT1("MmMapIoSpace failed!!!!!!!!!\n");
521 MemLength
= resource
->u
.Memory
.Length
;
522 FdoDeviceExtension
->Size
= MemLength
;
526 case CmResourceTypeDma
:
528 DPRINT("Dma Channel: %x\n", resource
->u
.Dma
.Channel
);
529 DPRINT("Dma Port: %d\n", resource
->u
.Dma
.Port
);
532 case CmResourceTypeDevicePrivate
:
534 /* Windows does this. */
535 DPRINT1("CmResourceTypeDevicePrivate not handled\n");
540 DPRINT1("PNP Manager gave resource type not handled!! Notify Developers!\n");
546 StartEhci(DeviceObject
);
547 FdoDeviceExtension
->DeviceState
= DEVICESTARTED
;
548 return STATUS_SUCCESS
;
552 FdoQueryBusRelations(
553 PDEVICE_OBJECT DeviceObject
,
554 PDEVICE_RELATIONS
* pDeviceRelations
)
556 PFDO_DEVICE_EXTENSION DeviceExtension
;
557 PDEVICE_RELATIONS DeviceRelations
= NULL
;
559 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
561 ULONG UsbDeviceNumber
= 0;
562 WCHAR CharDeviceName
[64];
564 UNICODE_STRING DeviceName
;
566 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
568 /* Create the PDO with the next available number */
571 /* FIXME: Use safe string */
572 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBPDO-%d", UsbDeviceNumber); */
573 swprintf(CharDeviceName
, L
"\\Device\\USBPDO-%d", UsbDeviceNumber
);
574 RtlInitUnicodeString(&DeviceName
, CharDeviceName
);
575 DPRINT("DeviceName %wZ\n", &DeviceName
);
577 Status
= IoCreateDevice(DeviceObject
->DriverObject
,
578 sizeof(PDO_DEVICE_EXTENSION
),
580 FILE_DEVICE_BUS_EXTENDER
,
585 if (NT_SUCCESS(Status
))
588 if ((Status
== STATUS_OBJECT_NAME_EXISTS
) || (Status
== STATUS_OBJECT_NAME_COLLISION
))
590 /* Try the next name */
595 /* Bail on any other error */
596 if (!NT_SUCCESS(Status
))
598 DPRINT1("UsbEhci: Failed to create PDO %wZ, Status %x\n", &DeviceName
, Status
);
603 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Pdo
->DeviceExtension
;
604 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
605 PdoDeviceExtension
->Common
.IsFdo
= FALSE
;
607 PdoDeviceExtension
->ControllerFdo
= DeviceObject
;
608 PdoDeviceExtension
->DeviceObject
= Pdo
;
610 InitializeListHead(&PdoDeviceExtension
->IrpQueue
);
611 KeInitializeSpinLock(&PdoDeviceExtension
->IrpQueueLock
);
613 Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
615 DeviceExtension
->Pdo
= Pdo
;
617 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, sizeof(DEVICE_RELATIONS
));
619 if (!DeviceRelations
)
621 return STATUS_INSUFFICIENT_RESOURCES
;
624 DeviceRelations
->Count
= 1;
625 DeviceRelations
->Objects
[0] = Pdo
;
626 ObReferenceObject(Pdo
);
628 *pDeviceRelations
= DeviceRelations
;
629 return STATUS_SUCCESS
;
633 FdoDispatchPnp(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
636 PIO_STACK_LOCATION Stack
= NULL
;
637 PCM_PARTIAL_RESOURCE_LIST raw
;
638 PCM_PARTIAL_RESOURCE_LIST translated
;
639 ULONG_PTR Information
= 0;
641 Stack
= IoGetCurrentIrpStackLocation(Irp
);
643 switch(Stack
->MinorFunction
)
645 case IRP_MN_START_DEVICE
:
647 DPRINT1("START_DEVICE\n");
648 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
649 Status
= ForwardAndWait(DeviceObject
, Irp
);
651 raw
= &Stack
->Parameters
.StartDevice
.AllocatedResources
->List
[0].PartialResourceList
;
652 translated
= &Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
->List
[0].PartialResourceList
;
653 Status
= StartDevice(DeviceObject
, raw
, translated
);
656 case IRP_MN_QUERY_DEVICE_RELATIONS
:
658 DPRINT1("IRP_MN_QUERY_DEVICE_RELATIONS\n");
659 switch(Stack
->Parameters
.QueryDeviceRelations
.Type
)
663 PDEVICE_RELATIONS DeviceRelations
= NULL
;
664 DPRINT("BusRelations\n");
665 Status
= FdoQueryBusRelations(DeviceObject
, &DeviceRelations
);
666 Information
= (ULONG_PTR
)DeviceRelations
;
671 DPRINT("Unknown query device relations type\n");
672 Status
= STATUS_NOT_IMPLEMENTED
;
678 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
680 DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
681 return ForwardIrpAndForget(DeviceObject
, Irp
);
684 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS
:
686 DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
688 case IRP_MN_QUERY_INTERFACE
:
690 Status
= STATUS_SUCCESS
;
692 Status
= ForwardIrpAndForget(DeviceObject
, Irp
);
698 DPRINT1("IRP_MJ_PNP / Unhandled minor function 0x%lx\n", Stack
->MinorFunction
);
699 return ForwardIrpAndForget(DeviceObject
, Irp
);
703 Irp
->IoStatus
.Information
= Information
;
704 Irp
->IoStatus
.Status
= Status
;
705 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
710 AddDevice(PDRIVER_OBJECT DriverObject
, PDEVICE_OBJECT Pdo
)
712 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
714 ULONG UsbDeviceNumber
= 0;
715 WCHAR CharDeviceName
[64];
716 WCHAR CharSymLinkName
[64];
717 UNICODE_STRING DeviceName
;
718 UNICODE_STRING SymLinkName
;
719 UNICODE_STRING InterfaceSymLinkName
;
721 PCI_COMMON_CONFIG PciConfig
;
723 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
725 DPRINT("Ehci AddDevice\n");
727 /* Create the FDO with next available number */
730 /* FIXME: Use safe string sprintf*/
731 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBFDO-%d", UsbDeviceNumber); */
732 swprintf(CharDeviceName
, L
"\\Device\\USBFDO-%d", UsbDeviceNumber
);
733 RtlInitUnicodeString(&DeviceName
, CharDeviceName
);
734 DPRINT("DeviceName %wZ\n", &DeviceName
);
736 Status
= IoCreateDevice(DriverObject
,
737 sizeof(FDO_DEVICE_EXTENSION
),
739 FILE_DEVICE_CONTROLLER
,
744 if (NT_SUCCESS(Status
))
747 if ((Status
== STATUS_OBJECT_NAME_EXISTS
) || (Status
== STATUS_OBJECT_NAME_COLLISION
))
749 /* Try the next name */
754 /* Bail on any other error */
755 if (!NT_SUCCESS(Status
))
757 DPRINT1("UsbEhci: Failed to create %wZ, Status %x\n", &DeviceName
, Status
);
762 swprintf(CharSymLinkName
, L
"\\Device\\HCD%d", UsbDeviceNumber
);
763 RtlInitUnicodeString(&SymLinkName
, CharSymLinkName
);
764 Status
= IoCreateSymbolicLink(&SymLinkName
, &DeviceName
);
766 if (!NT_SUCCESS(Status
))
768 DPRINT1("Warning: Unable to create symbolic link for ehci host controller!\n");
771 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
) Fdo
->DeviceExtension
;
772 RtlZeroMemory(FdoDeviceExtension
, sizeof(PFDO_DEVICE_EXTENSION
));
774 FdoDeviceExtension
->Common
.IsFdo
= TRUE
;
775 FdoDeviceExtension
->DeviceObject
= Fdo
;
777 FdoDeviceExtension
->LowerDevice
= IoAttachDeviceToDeviceStack(Fdo
, Pdo
);
779 if (FdoDeviceExtension
->LowerDevice
== NULL
)
781 DPRINT1("UsbEhci: Failed to attach to device stack!\n");
782 IoDeleteSymbolicLink(&SymLinkName
);
785 return STATUS_NO_SUCH_DEVICE
;
788 Fdo
->Flags
|= DO_BUFFERED_IO
;// | DO_POWER_PAGABLE;
790 ASSERT(FdoDeviceExtension
->LowerDevice
== Pdo
);
792 Status
= GetBusInterface(FdoDeviceExtension
->LowerDevice
, &FdoDeviceExtension
->BusInterface
);
794 if (!NT_SUCCESS(Status
))
796 DPRINT1("GetBusInterface() failed with %x\n", Status
);
797 IoDetachDevice(FdoDeviceExtension
->LowerDevice
);
798 IoDeleteSymbolicLink(&SymLinkName
);
803 BytesRead
= (*FdoDeviceExtension
->BusInterface
.GetBusData
)(
804 FdoDeviceExtension
->BusInterface
.Context
,
805 PCI_WHICHSPACE_CONFIG
,
808 PCI_COMMON_HDR_LENGTH
);
811 if (BytesRead
!= PCI_COMMON_HDR_LENGTH
)
813 DPRINT1("GetBusData failed!\n");
814 IoDetachDevice(FdoDeviceExtension
->LowerDevice
);
815 IoDeleteSymbolicLink(&SymLinkName
);
818 return STATUS_UNSUCCESSFUL
;
821 if (PciConfig
.Command
& PCI_ENABLE_IO_SPACE
)
822 DPRINT("PCI_ENABLE_IO_SPACE\n");
824 if (PciConfig
.Command
& PCI_ENABLE_MEMORY_SPACE
)
825 DPRINT("PCI_ENABLE_MEMORY_SPACE\n");
827 if (PciConfig
.Command
& PCI_ENABLE_BUS_MASTER
)
828 DPRINT("PCI_ENABLE_BUS_MASTER\n");
830 DPRINT("BaseAddress[0] %x\n", PciConfig
.u
.type0
.BaseAddresses
[0]);
831 DPRINT1("Vendor %x\n", PciConfig
.VendorID
);
832 DPRINT1("Device %x\n", PciConfig
.DeviceID
);
834 FdoDeviceExtension
->VendorId
= PciConfig
.VendorID
;
835 FdoDeviceExtension
->DeviceId
= PciConfig
.DeviceID
;
837 FdoDeviceExtension
->DeviceState
= DEVICEINTIALIZED
;
839 Status
= IoRegisterDeviceInterface(Pdo
, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER
, NULL
, &InterfaceSymLinkName
);
840 if (!NT_SUCCESS(Status
))
842 DPRINT1("Unable to register device interface!\n");
846 Status
= IoSetDeviceInterfaceState(&InterfaceSymLinkName
, TRUE
);
847 DPRINT1("SetInterfaceState %x\n", Status
);
849 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
851 return STATUS_SUCCESS
;