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.
7 * Michael Martin (michael.martin@reactos.org)
16 EhciDefferedRoutine(PKDPC Dpc
, PVOID DeferredContext
, PVOID SystemArgument1
, PVOID SystemArgument2
)
18 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
19 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
23 PEHCI_HOST_CONTROLLER hcd
;
26 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
) DeferredContext
;
28 if (!FdoDeviceExtension
->Pdo
)
30 DPRINT1("PDO not set yet!\n");
34 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
) FdoDeviceExtension
->Pdo
->DeviceExtension
;
36 OpRegisters
= (ULONG
)FdoDeviceExtension
->hcd
.OpRegisters
;
38 hcd
= &FdoDeviceExtension
->hcd
;
40 CStatus
= (ULONG
) SystemArgument2
;
43 /* TD retired or Error */
44 if (CStatus
& (EHCI_STS_INT
| EHCI_ERROR_INT
))
46 DPRINT("Asyn Complete!\n");
47 ULONG CurrentAddr
, OffSet
;
48 PQUEUE_HEAD CompletedQH
, NextQH
;
49 PQUEUE_TRANSFER_DESCRIPTOR CompletedTD
, NextTD
;
51 /* AsyncListAddr Register will have the next QueueHead to execute */
52 CurrentAddr
= GetAsyncListQueueRegister(hcd
);
54 /* Calculate the VA for the next QueueHead */
55 OffSet
= CurrentAddr
- (ULONG
)FdoDeviceExtension
->hcd
.CommonBufferPA
.LowPart
;
56 NextQH
= (PQUEUE_HEAD
)((ULONG
)FdoDeviceExtension
->hcd
.CommonBufferVA
+ OffSet
);
58 /* Get the previous QueueHead which is the QueueHead just completed */
59 CompletedQH
= NextQH
->PreviousQueueHead
;
61 DPRINT("CompletedQH %x\n", CompletedQH
);
63 //DumpQueueHead(CompletedQH);
65 /* Free memory for the Descriptors */
66 CompletedTD
= CompletedQH
->TransferDescriptor
;
71 NextTD
= NextTD
->NextDescriptor
;
72 FreeDescriptor(CompletedTD
);
75 /* If the Event is set then release waiter */
76 if (CompletedQH
->Event
)
78 KeSetEvent(CompletedQH
->Event
, IO_NO_INCREMENT
, FALSE
);
81 /* Free the Mdl if there was one */
82 if(CompletedQH
->MdlToFree
)
83 IoFreeMdl(CompletedQH
->MdlToFree
);
85 /* Is there an IRP that needs to be completed */
86 if (CompletedQH
->IrpToComplete
)
89 PIO_STACK_LOCATION Stack
;
92 Irp
= CompletedQH
->IrpToComplete
;
93 Stack
= IoGetCurrentIrpStackLocation(Irp
);
95 Urb
= (PURB
) Stack
->Parameters
.Others
.Argument1
;
98 if (CStatus
& EHCI_ERROR_INT
)
100 /* Haled bit should be set */
101 if (CompletedQH
->Token
.Bits
.Halted
)
103 if (CompletedQH
->Token
.Bits
.DataBufferError
)
105 DPRINT1("Data buffer error\n");
106 Urb
->UrbHeader
.Status
= USBD_STATUS_DATA_BUFFER_ERROR
;
107 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
108 Irp
->IoStatus
.Information
= 0;
110 else if (CompletedQH
->Token
.Bits
.BabbleDetected
)
112 DPRINT1("Babble Detected\n");
113 Urb
->UrbHeader
.Status
= USBD_STATUS_BABBLE_DETECTED
;
114 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
115 Irp
->IoStatus
.Information
= 0;
119 DPRINT1("Stall PID\n");
120 Urb
->UrbHeader
.Status
= USBD_STATUS_STALL_PID
;
121 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
122 Irp
->IoStatus
.Information
= 0;
128 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
129 Irp
->IoStatus
.Information
= 0;
130 DPRINT1("Completing Irp\n");
133 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
136 /* Unlink QueueHead */
137 UnlinkQueueHead(hcd
, CompletedQH
);
138 /* Wait for a complete AsnycList tranversal before deleting? */
139 DeleteQueueHead(CompletedQH
);
143 if (CStatus
& EHCI_STS_PCD
)
145 /* Loop through the ports */
146 for (i
= 0; i
< FdoDeviceExtension
->hcd
.ECHICaps
.HCSParams
.PortCount
; i
++)
148 tmp
= READ_REGISTER_ULONG((PULONG
) ((OpRegisters
+ EHCI_PORTSC
) + (4 * i
)));
150 /* Check for port change on this port */
153 /* Connect or Disconnect? */
156 DPRINT1("Device connected on port %d\n", i
);
158 /* Check if a companion host controller exists */
159 if (FdoDeviceExtension
->hcd
.ECHICaps
.HCSParams
.CHCCount
)
161 tmp
= READ_REGISTER_ULONG((PULONG
)((OpRegisters
+ EHCI_PORTSC
) + (4 * i
)));
163 /* Port should be in disabled state, as per USB 2.0 specs */
166 DPRINT1("Warning: The port the device has just connected to is not disabled!\n");
169 /* Is this non high speed device */
172 DPRINT1("Non HighSpeed device connected. Releasing ownership.\n");
173 /* Release ownership to companion host controller */
174 WRITE_REGISTER_ULONG((PULONG
) ((OpRegisters
+ EHCI_PORTSC
) + (4 * i
)), 0x2000);
179 KeStallExecutionProcessor(30);
181 /* As per USB 2.0 Specs, 9.1.2. Reset the port and clear the status change */
182 //tmp |= 0x100 | 0x02;
183 /* Sanity, Disable port */
186 //WRITE_REGISTER_ULONG((PULONG) ((Base + EHCI_PORTSC) + (4 * i)), tmp);
188 //KeStallExecutionProcessor(20);
190 tmp
= READ_REGISTER_ULONG((PULONG
)((OpRegisters
+ EHCI_PORTSC
) + (4 * i
)));
192 PdoDeviceExtension
->ChildDeviceCount
++;
193 PdoDeviceExtension
->Ports
[i
].PortStatus
&= ~0x8000;
194 PdoDeviceExtension
->Ports
[i
].PortStatus
|= USB_PORT_STATUS_HIGH_SPEED
;
195 PdoDeviceExtension
->Ports
[i
].PortStatus
|= USB_PORT_STATUS_CONNECT
;
196 PdoDeviceExtension
->Ports
[i
].PortChange
|= USB_PORT_STATUS_CONNECT
;
197 DPRINT1("Completing URB\n");
198 CompletePendingURBRequest(PdoDeviceExtension
);
202 DPRINT1("Device disconnected on port %d\n", i
);
204 /* Clear status change */
205 tmp
= READ_REGISTER_ULONG((PULONG
)((OpRegisters
+ EHCI_PORTSC
) + (4 * i
)));
207 WRITE_REGISTER_ULONG((PULONG
) ((OpRegisters
+ EHCI_PORTSC
) + (4 * i
)), tmp
);
214 if (CStatus
& EHCI_STS_IAA
)
216 DPRINT1("Async Advance!\n");
221 InterruptService(PKINTERRUPT Interrupt
, PVOID ServiceContext
)
223 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
224 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
) ServiceContext
;
225 PEHCI_HOST_CONTROLLER hcd
;
228 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
230 hcd
= &FdoDeviceExtension
->hcd
;
232 /* Read device status */
233 CStatus
= ReadControllerStatus(hcd
);
235 CStatus
&= (EHCI_ERROR_INT
| EHCI_STS_INT
| EHCI_STS_IAA
| EHCI_STS_PCD
| EHCI_STS_FLR
);
237 if ((!CStatus
) || (FdoDeviceExtension
->DeviceState
== 0))
239 /* This interrupt isnt for us or not ready for it. */
244 ClearControllerStatus(hcd
, CStatus
);
246 if (CStatus
& EHCI_ERROR_INT
)
248 DPRINT1("EHCI Status=0x%x\n", CStatus
);
251 if (CStatus
& EHCI_STS_FATAL
)
253 DPRINT1("EHCI: Host System Error. Possible PCI problems.\n");
257 if (CStatus
& EHCI_STS_HALT
)
259 DPRINT1("EHCI: Host Controller unexpected halt.\n");
260 /* FIXME: Reset the controller */
263 KeInsertQueueDpc(&FdoDeviceExtension
->DpcObject
, FdoDeviceExtension
, (PVOID
)CStatus
);
268 StartDevice(PDEVICE_OBJECT DeviceObject
, PCM_PARTIAL_RESOURCE_LIST raw
, PCM_PARTIAL_RESOURCE_LIST translated
)
270 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
271 PCM_PARTIAL_RESOURCE_DESCRIPTOR resource
;
272 DEVICE_DESCRIPTION DeviceDescription
;
273 ULONG NumberResources
;
280 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
282 Status
= IoGetDeviceProperty(FdoDeviceExtension
->LowerDevice
,
283 DevicePropertyAddress
,
287 if (NT_SUCCESS(Status
))
289 DPRINT1("--->DeviceAddress: %x\n", DeviceAddress
);
292 Status
= IoGetDeviceProperty(FdoDeviceExtension
->LowerDevice
,
293 DevicePropertyBusNumber
,
297 if (NT_SUCCESS(Status
))
299 DPRINT1("--->BusNumber: %x\n", BusNumber
);
302 /* Get the resources the PNP Manager gave */
303 NumberResources
= translated
->Count
;
304 DPRINT("NumberResources %d\n", NumberResources
);
305 for (iCount
= 0; iCount
< NumberResources
; iCount
++)
307 DPRINT("Resource Info %d:\n", iCount
);
308 resource
= &translated
->PartialDescriptors
[iCount
];
309 switch(resource
->Type
)
311 case CmResourceTypePort
:
313 DPRINT("Port Start: %x\n", resource
->u
.Port
.Start
);
314 DPRINT("Port Length %d\n", resource
->u
.Port
.Length
);
315 /* FIXME: Handle Ports */
318 case CmResourceTypeInterrupt
:
320 DPRINT("Interrupt Vector: %x\n", resource
->u
.Interrupt
.Vector
);
321 FdoDeviceExtension
->Vector
= resource
->u
.Interrupt
.Vector
;
322 FdoDeviceExtension
->Irql
= resource
->u
.Interrupt
.Level
;
323 FdoDeviceExtension
->Affinity
= resource
->u
.Interrupt
.Affinity
;
324 FdoDeviceExtension
->Mode
= (resource
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
) ? Latched
: LevelSensitive
;
325 FdoDeviceExtension
->IrqShared
= resource
->ShareDisposition
== CmResourceShareShared
;
328 case CmResourceTypeMemory
:
330 PVOID ResourceBase
= 0;
332 DPRINT("Mem Start: %x\n", resource
->u
.Memory
.Start
);
333 DPRINT("Mem Length: %d\n", resource
->u
.Memory
.Length
);
335 ResourceBase
= MmMapIoSpace(resource
->u
.Memory
.Start
, resource
->u
.Memory
.Length
, FALSE
);
336 DPRINT("ResourceBase %x\n", ResourceBase
);
337 if (ResourceBase
== NULL
)
339 DPRINT1("MmMapIoSpace failed!!!!!!!!!\n");
342 GetCapabilities(&FdoDeviceExtension
->hcd
.ECHICaps
, (ULONG
)ResourceBase
);
343 DPRINT1("hcd.ECHICaps.Length %x\n", FdoDeviceExtension
->hcd
.ECHICaps
.Length
);
344 FdoDeviceExtension
->hcd
.OpRegisters
= (ULONG
)((ULONG
)ResourceBase
+ FdoDeviceExtension
->hcd
.ECHICaps
.Length
);
347 case CmResourceTypeDma
:
349 DPRINT("Dma Channel: %x\n", resource
->u
.Dma
.Channel
);
350 DPRINT("Dma Port: %d\n", resource
->u
.Dma
.Port
);
353 case CmResourceTypeDevicePrivate
:
355 /* Windows does this. */
356 DPRINT1("CmResourceTypeDevicePrivate not handled\n");
361 DPRINT1("PNP Manager gave resource type not handled!! Notify Developers!\n");
367 KeInitializeDpc(&FdoDeviceExtension
->DpcObject
,
371 RtlZeroMemory(&DeviceDescription
, sizeof(DEVICE_DESCRIPTION
));
372 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
373 DeviceDescription
.Master
= TRUE
;
374 DeviceDescription
.ScatterGather
= TRUE
;
375 DeviceDescription
.Dma32BitAddresses
= TRUE
;
376 DeviceDescription
.DmaWidth
= 2;
377 DeviceDescription
.InterfaceType
= PCIBus
;
378 DeviceDescription
.MaximumLength
= EHCI_MAX_SIZE_TRANSFER
;
380 FdoDeviceExtension
->pDmaAdapter
= IoGetDmaAdapter(FdoDeviceExtension
->LowerDevice
,
382 &FdoDeviceExtension
->MapRegisters
);
384 if (FdoDeviceExtension
->pDmaAdapter
== NULL
)
386 DPRINT1("Ehci: IoGetDmaAdapter failed!\n");
390 /* Allocate Common Buffer for Periodic Frame List */
391 FdoDeviceExtension
->PeriodicFrameList
.VirtualAddr
=
392 FdoDeviceExtension
->pDmaAdapter
->DmaOperations
->AllocateCommonBuffer(FdoDeviceExtension
->pDmaAdapter
,
393 sizeof(ULONG
) * 1024, &FdoDeviceExtension
->PeriodicFrameList
.PhysicalAddr
, FALSE
);
395 if (FdoDeviceExtension
->PeriodicFrameList
.VirtualAddr
== NULL
)
397 DPRINT1("Ehci: FdoDeviceExtension->PeriodicFramList is null\n");
398 return STATUS_UNSUCCESSFUL
;
402 RtlZeroMemory(FdoDeviceExtension
->PeriodicFrameList
.VirtualAddr
, sizeof(ULONG
) * 1024);
404 ExInitializeFastMutex(&FdoDeviceExtension
->FrameListMutex
);
406 /* Allocate pages for queueheads and descriptors */
407 FdoDeviceExtension
->hcd
.CommonBufferVA
=
408 FdoDeviceExtension
->pDmaAdapter
->DmaOperations
->AllocateCommonBuffer(FdoDeviceExtension
->pDmaAdapter
,
410 &FdoDeviceExtension
->hcd
.CommonBufferPA
,
413 if (FdoDeviceExtension
->hcd
.CommonBufferVA
== 0)
415 DPRINT1("Ehci: Failed to allocate common buffer!\n");
416 return STATUS_UNSUCCESSFUL
;
419 FdoDeviceExtension
->hcd
.CommonBufferSize
= PAGE_SIZE
* 16;
422 RtlZeroMemory(FdoDeviceExtension
->hcd
.CommonBufferVA
,
425 /* Init SpinLock for host controller device lock */
426 KeInitializeSpinLock(&FdoDeviceExtension
->hcd
.Lock
);
428 /* Reserved a Queue Head that will always be in the AsyncList Address Register */
429 FdoDeviceExtension
->hcd
.AsyncListQueue
= CreateQueueHead(&FdoDeviceExtension
->hcd
);
430 FdoDeviceExtension
->hcd
.AsyncListQueue
->HorizontalLinkPointer
= FdoDeviceExtension
->hcd
.AsyncListQueue
->PhysicalAddr
| QH_TYPE_QH
;
431 FdoDeviceExtension
->hcd
.AsyncListQueue
->EndPointCharacteristics
.QEDTDataToggleControl
= FALSE
;
432 FdoDeviceExtension
->hcd
.AsyncListQueue
->Token
.Bits
.InterruptOnComplete
= FALSE
;
434 /* Ensure the controller is stopped */
435 StopEhci(&FdoDeviceExtension
->hcd
);
437 Status
= IoConnectInterrupt(&FdoDeviceExtension
->EhciInterrupt
,
439 FdoDeviceExtension
->DeviceObject
,
441 FdoDeviceExtension
->Vector
,
442 FdoDeviceExtension
->Irql
,
443 FdoDeviceExtension
->Irql
,
444 FdoDeviceExtension
->Mode
,
445 FdoDeviceExtension
->IrqShared
,
446 FdoDeviceExtension
->Affinity
,
449 StartEhci(&FdoDeviceExtension
->hcd
);
450 DPRINT1("AsycnAddr %x\n", GetAsyncListQueueRegister(&FdoDeviceExtension
->hcd
));
451 FdoDeviceExtension
->DeviceState
= DEVICESTARTED
;
453 return STATUS_SUCCESS
;
457 FdoQueryBusRelations(
458 PDEVICE_OBJECT DeviceObject
,
459 PDEVICE_RELATIONS
* pDeviceRelations
)
461 PFDO_DEVICE_EXTENSION DeviceExtension
;
462 PDEVICE_RELATIONS DeviceRelations
= NULL
;
464 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
466 ULONG UsbDeviceNumber
= 0;
467 WCHAR CharDeviceName
[64];
469 UNICODE_STRING DeviceName
;
471 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
473 DPRINT1("Ehci: QueryBusRelations\n");
475 /* Create the PDO with the next available number */
478 /* FIXME: Use safe string */
479 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBPDO-%d", UsbDeviceNumber); */
480 swprintf(CharDeviceName
, L
"\\Device\\USBPDO-%d", UsbDeviceNumber
);
481 RtlInitUnicodeString(&DeviceName
, CharDeviceName
);
482 DPRINT("DeviceName %wZ\n", &DeviceName
);
484 Status
= IoCreateDevice(DeviceObject
->DriverObject
,
485 sizeof(PDO_DEVICE_EXTENSION
),
487 FILE_DEVICE_BUS_EXTENDER
,
492 if (NT_SUCCESS(Status
))
495 if ((Status
== STATUS_OBJECT_NAME_EXISTS
) || (Status
== STATUS_OBJECT_NAME_COLLISION
))
497 /* Try the next name */
502 /* Bail on any other error */
503 if (!NT_SUCCESS(Status
))
505 DPRINT1("Ehci: Failed to create PDO %wZ, Status %x\n", &DeviceName
, Status
);
510 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Pdo
->DeviceExtension
;
511 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
512 PdoDeviceExtension
->Common
.IsFdo
= FALSE
;
514 PdoDeviceExtension
->ControllerFdo
= DeviceObject
;
515 PdoDeviceExtension
->DeviceObject
= Pdo
;
516 PdoDeviceExtension
->NumberOfPorts
= DeviceExtension
->hcd
.ECHICaps
.HCSParams
.PortCount
;
518 InitializeListHead(&PdoDeviceExtension
->IrpQueue
);
519 KeInitializeSpinLock(&PdoDeviceExtension
->IrpQueueLock
);
521 KeInitializeEvent(&PdoDeviceExtension
->QueueDrainedEvent
, SynchronizationEvent
, TRUE
);
523 ExInitializeFastMutex(&PdoDeviceExtension
->ListLock
);
525 Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
527 DeviceExtension
->Pdo
= Pdo
;
529 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, sizeof(DEVICE_RELATIONS
));
531 if (!DeviceRelations
)
533 return STATUS_INSUFFICIENT_RESOURCES
;
536 DeviceRelations
->Count
= 1;
537 DeviceRelations
->Objects
[0] = Pdo
;
538 ObReferenceObject(Pdo
);
540 *pDeviceRelations
= DeviceRelations
;
541 return STATUS_SUCCESS
;
545 FdoDispatchPnp(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
548 PIO_STACK_LOCATION Stack
= NULL
;
549 PCM_PARTIAL_RESOURCE_LIST raw
;
550 PCM_PARTIAL_RESOURCE_LIST translated
;
551 ULONG_PTR Information
= 0;
553 Stack
= IoGetCurrentIrpStackLocation(Irp
);
555 switch(Stack
->MinorFunction
)
557 case IRP_MN_START_DEVICE
:
559 DPRINT1("Ehci: START_DEVICE\n");
561 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
562 Status
= ForwardAndWait(DeviceObject
, Irp
);
564 raw
= &Stack
->Parameters
.StartDevice
.AllocatedResources
->List
[0].PartialResourceList
;
565 translated
= &Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
->List
[0].PartialResourceList
;
566 Status
= StartDevice(DeviceObject
, raw
, translated
);
569 case IRP_MN_QUERY_DEVICE_RELATIONS
:
571 DPRINT1("Ehci: IRP_MN_QUERY_DEVICE_RELATIONS\n");
572 switch(Stack
->Parameters
.QueryDeviceRelations
.Type
)
576 PDEVICE_RELATIONS DeviceRelations
= NULL
;
577 DPRINT1("Ehci: BusRelations\n");
578 Status
= FdoQueryBusRelations(DeviceObject
, &DeviceRelations
);
579 Information
= (ULONG_PTR
)DeviceRelations
;
584 DPRINT1("Ehci: Unknown query device relations type\n");
585 Status
= STATUS_NOT_IMPLEMENTED
;
591 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
593 DPRINT1("Ehci: IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
594 return ForwardIrpAndForget(DeviceObject
, Irp
);
597 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS
:
599 DPRINT1("Ehci: IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
601 case IRP_MN_QUERY_INTERFACE
:
603 DPRINT1("Ehci: IRP_MN_QUERY_INTERFACE\n");
604 Status
= STATUS_SUCCESS
;
606 Status
= ForwardIrpAndForget(DeviceObject
, Irp
);
612 DPRINT1("Ehci: IRP_MJ_PNP / Unhandled minor function 0x%lx\n", Stack
->MinorFunction
);
613 return ForwardIrpAndForget(DeviceObject
, Irp
);
617 Irp
->IoStatus
.Information
= Information
;
618 Irp
->IoStatus
.Status
= Status
;
619 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
624 AddDevice(PDRIVER_OBJECT DriverObject
, PDEVICE_OBJECT Pdo
)
626 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
628 ULONG UsbDeviceNumber
= 0;
629 WCHAR CharDeviceName
[64];
630 WCHAR CharSymLinkName
[64];
631 UNICODE_STRING DeviceName
;
632 UNICODE_STRING SymLinkName
;
633 UNICODE_STRING InterfaceSymLinkName
;
635 PCI_COMMON_CONFIG PciConfig
;
637 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
639 DPRINT1("Ehci: AddDevice\n");
641 /* Create the FDO with next available number */
644 /* FIXME: Use safe string sprintf*/
645 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBFDO-%d", UsbDeviceNumber); */
646 swprintf(CharDeviceName
, L
"\\Device\\USBFDO-%d", UsbDeviceNumber
);
647 RtlInitUnicodeString(&DeviceName
, CharDeviceName
);
648 DPRINT("DeviceName %wZ\n", &DeviceName
);
650 Status
= IoCreateDevice(DriverObject
,
651 sizeof(FDO_DEVICE_EXTENSION
),
653 FILE_DEVICE_CONTROLLER
,
658 if (NT_SUCCESS(Status
))
661 if ((Status
== STATUS_OBJECT_NAME_EXISTS
) || (Status
== STATUS_OBJECT_NAME_COLLISION
))
663 /* Try the next name */
668 /* Bail on any other error */
669 if (!NT_SUCCESS(Status
))
671 DPRINT1("UsbEhci: Failed to create %wZ, Status %x\n", &DeviceName
, Status
);
676 swprintf(CharSymLinkName
, L
"\\Device\\HCD%d", UsbDeviceNumber
);
677 RtlInitUnicodeString(&SymLinkName
, CharSymLinkName
);
678 Status
= IoCreateSymbolicLink(&SymLinkName
, &DeviceName
);
680 if (!NT_SUCCESS(Status
))
682 DPRINT1("Warning: Unable to create symbolic link for ehci host controller!\n");
685 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
) Fdo
->DeviceExtension
;
686 RtlZeroMemory(FdoDeviceExtension
, sizeof(PFDO_DEVICE_EXTENSION
));
688 KeInitializeTimerEx(&FdoDeviceExtension
->UpdateTimer
, SynchronizationTimer
);
690 FdoDeviceExtension
->Common
.IsFdo
= TRUE
;
691 FdoDeviceExtension
->DeviceObject
= Fdo
;
693 FdoDeviceExtension
->LowerDevice
= IoAttachDeviceToDeviceStack(Fdo
, Pdo
);
695 if (FdoDeviceExtension
->LowerDevice
== NULL
)
697 DPRINT1("UsbEhci: Failed to attach to device stack!\n");
698 IoDeleteSymbolicLink(&SymLinkName
);
701 return STATUS_NO_SUCH_DEVICE
;
704 Fdo
->Flags
|= DO_BUFFERED_IO
;// | DO_POWER_PAGABLE;
706 ASSERT(FdoDeviceExtension
->LowerDevice
== Pdo
);
708 Status
= GetBusInterface(FdoDeviceExtension
->LowerDevice
, &FdoDeviceExtension
->BusInterface
);
710 if (!NT_SUCCESS(Status
))
712 DPRINT1("GetBusInterface() failed with %x\n", Status
);
713 IoDetachDevice(FdoDeviceExtension
->LowerDevice
);
714 IoDeleteSymbolicLink(&SymLinkName
);
719 BytesRead
= (*FdoDeviceExtension
->BusInterface
.GetBusData
)(
720 FdoDeviceExtension
->BusInterface
.Context
,
721 PCI_WHICHSPACE_CONFIG
,
724 PCI_COMMON_HDR_LENGTH
);
727 if (BytesRead
!= PCI_COMMON_HDR_LENGTH
)
729 DPRINT1("GetBusData failed!\n");
730 IoDetachDevice(FdoDeviceExtension
->LowerDevice
);
731 IoDeleteSymbolicLink(&SymLinkName
);
733 return STATUS_UNSUCCESSFUL
;
736 if (PciConfig
.Command
& PCI_ENABLE_IO_SPACE
)
737 DPRINT("PCI_ENABLE_IO_SPACE\n");
739 if (PciConfig
.Command
& PCI_ENABLE_MEMORY_SPACE
)
740 DPRINT("PCI_ENABLE_MEMORY_SPACE\n");
742 if (PciConfig
.Command
& PCI_ENABLE_BUS_MASTER
)
743 DPRINT("PCI_ENABLE_BUS_MASTER\n");
745 DPRINT("BaseAddress[0] %x\n", PciConfig
.u
.type0
.BaseAddresses
[0]);
746 DPRINT1("Vendor %x\n", PciConfig
.VendorID
);
747 DPRINT1("Device %x\n", PciConfig
.DeviceID
);
749 FdoDeviceExtension
->VendorId
= PciConfig
.VendorID
;
750 FdoDeviceExtension
->DeviceId
= PciConfig
.DeviceID
;
752 FdoDeviceExtension
->DeviceState
= DEVICEINTIALIZED
;
754 Status
= IoRegisterDeviceInterface(Pdo
, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER
, NULL
, &InterfaceSymLinkName
);
755 if (!NT_SUCCESS(Status
))
757 DPRINT1("Unable to register device interface!\n");
762 Status
= IoSetDeviceInterfaceState(&InterfaceSymLinkName
, TRUE
);
763 DPRINT1("SetInterfaceState %x\n", Status
);
764 if (!NT_SUCCESS(Status
))
767 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
769 return STATUS_SUCCESS
;
773 FdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
775 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
776 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
777 PIO_STACK_LOCATION Stack
= NULL
;
778 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
779 ULONG_PTR Information
= 0;
780 PUSB_DEVICE UsbDevice
= NULL
;
783 /*FIXME: This should never be called by upper drivers as they should only be dealing with the pdo */
785 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
786 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
) FdoDeviceExtension
->Pdo
->DeviceExtension
;
788 ASSERT(FdoDeviceExtension
->Common
.IsFdo
== TRUE
);
790 Stack
= IoGetCurrentIrpStackLocation(Irp
);
792 ASSERT(Stack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_SUBMIT_URB
);
794 Urb
= (PURB
) Stack
->Parameters
.Others
.Argument1
;
795 DPRINT("Header Length %d\n", Urb
->UrbHeader
.Length
);
796 DPRINT("Header Function %d\n", Urb
->UrbHeader
.Function
);
798 UsbDevice
= DeviceHandleToUsbDevice(PdoDeviceExtension
, Urb
->UrbHeader
.UsbdDeviceHandle
);
802 DPRINT1("Ehci: Invalid DeviceHandle or device not connected\n");
803 return STATUS_DEVICE_NOT_CONNECTED
;
805 switch (Urb
->UrbHeader
.Function
)
807 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
:
809 DPRINT1("Ehci: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:\n");
812 case URB_FUNCTION_GET_STATUS_FROM_DEVICE
:
814 DPRINT1("Ehci: URB_FUNCTION_GET_STATUS_FROM_DEVICE\n");
817 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
:
819 DPRINT1("Ehci: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n");
820 switch(Urb
->UrbControlDescriptorRequest
.DescriptorType
)
822 case USB_DEVICE_DESCRIPTOR_TYPE
:
824 DPRINT1("USB DEVICE DESC\n");
827 case USB_CONFIGURATION_DESCRIPTOR_TYPE
:
828 DPRINT1("USB CONFIG DESC\n");
830 case USB_STRING_DESCRIPTOR_TYPE
:
832 DPRINT1("Usb String Descriptor\n");
837 DPRINT1("Ehci: Descriptor Type %x not supported!\n", Urb
->UrbControlDescriptorRequest
.DescriptorType
);
842 case URB_FUNCTION_SELECT_CONFIGURATION
:
844 DPRINT1("Ehci: URB_FUNCTION_SELECT_CONFIGURATION\n");
845 DPRINT1("Urb->UrbSelectConfiguration.ConfigurationHandle %x\n",Urb
->UrbSelectConfiguration
.ConfigurationHandle
);
848 case URB_FUNCTION_CLASS_DEVICE
:
850 DPRINT1("Ehci: URB_FUNCTION_CLASS_DEVICE %x\n",Urb
->UrbControlVendorClassRequest
.Request
);
851 switch (Urb
->UrbControlVendorClassRequest
.Request
)
853 case USB_REQUEST_GET_DESCRIPTOR
:
855 DPRINT1("TransferFlags %x\n", Urb
->UrbControlVendorClassRequest
.TransferFlags
);
856 DPRINT1("Urb->UrbControlVendorClassRequest.Value %x\n", Urb
->UrbControlVendorClassRequest
.Value
);
858 switch (Urb
->UrbControlVendorClassRequest
.Value
>> 8)
860 case USB_DEVICE_CLASS_AUDIO
:
862 DPRINT1("USB_DEVICE_CLASS_AUDIO\n");
865 case USB_DEVICE_CLASS_COMMUNICATIONS
:
867 DPRINT1("USB_DEVICE_CLASS_COMMUNICATIONS\n");
870 case USB_DEVICE_CLASS_HUMAN_INTERFACE
:
872 DPRINT1("USB_DEVICE_CLASS_HUMAN_INTERFACE\n");
875 case USB_DEVICE_CLASS_MONITOR
:
877 DPRINT1("USB_DEVICE_CLASS_MONITOR\n");
880 case USB_DEVICE_CLASS_PHYSICAL_INTERFACE
:
882 DPRINT1("USB_DEVICE_CLASS_PHYSICAL_INTERFACE\n");
885 case USB_DEVICE_CLASS_POWER
:
887 DPRINT1("USB_DEVICE_CLASS_POWER\n");
890 case USB_DEVICE_CLASS_PRINTER
:
892 DPRINT1("USB_DEVICE_CLASS_PRINTER\n");
895 case USB_DEVICE_CLASS_STORAGE
:
897 DPRINT1("USB_DEVICE_CLASS_STORAGE\n");
900 case USB_DEVICE_CLASS_RESERVED
:
901 DPRINT1("Reserved!!!\n");
902 case USB_DEVICE_CLASS_HUB
:
904 DPRINT1("USB_DEVICE_CLASS_HUB request\n");
909 DPRINT1("Unknown UrbControlVendorClassRequest Value\n");
914 case USB_REQUEST_GET_STATUS
:
916 DPRINT1("DEVICE: USB_REQUEST_GET_STATUS for port %d\n", Urb
->UrbControlVendorClassRequest
.Index
);
921 DPRINT1("Unhandled URB request for class device\n");
922 //Urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
927 case URB_FUNCTION_CLASS_OTHER
:
929 DPRINT1("Ehci: URB_FUNCTION_CLASS_OTHER\n");
930 switch (Urb
->UrbControlVendorClassRequest
.Request
)
932 case USB_REQUEST_GET_STATUS
:
934 DPRINT1("OTHER: USB_REQUEST_GET_STATUS for port %d\n", Urb
->UrbControlVendorClassRequest
.Index
);
937 case USB_REQUEST_CLEAR_FEATURE
:
939 DPRINT1("USB_REQUEST_CLEAR_FEATURE Port %d, value %x\n", Urb
->UrbControlVendorClassRequest
.Index
,
940 Urb
->UrbControlVendorClassRequest
.Value
);
941 switch (Urb
->UrbControlVendorClassRequest
.Value
)
943 case C_PORT_CONNECTION
:
944 DPRINT1("Clearing Connect\n");
947 DPRINT1("Clearing Reset\n");
950 DPRINT1("Unknown Value for Clear Feature %x \n", Urb
->UrbControlVendorClassRequest
.Value
);
955 case USB_REQUEST_SET_FEATURE
:
957 DPRINT1("USB_REQUEST_SET_FEATURE Port %d, value %x\n", Urb
->UrbControlVendorClassRequest
.Index
,
958 Urb
->UrbControlVendorClassRequest
.Value
);
960 switch(Urb
->UrbControlVendorClassRequest
.Value
)
964 DPRINT1("Port reset\n");
969 DPRINT1("Unhandled Set Feature\n");
974 DPRINT1("Unknown Set Feature!\n");
980 case USB_REQUEST_SET_ADDRESS
:
982 DPRINT1("USB_REQUEST_SET_ADDRESS\n");
985 case USB_REQUEST_GET_DESCRIPTOR
:
987 DPRINT1("USB_REQUEST_GET_DESCRIPTOR\n");
990 case USB_REQUEST_SET_DESCRIPTOR
:
992 DPRINT1("USB_REQUEST_SET_DESCRIPTOR\n");
995 case USB_REQUEST_GET_CONFIGURATION
:
997 DPRINT1("USB_REQUEST_GET_CONFIGURATION\n");
1000 case USB_REQUEST_SET_CONFIGURATION
:
1002 DPRINT1("USB_REQUEST_SET_CONFIGURATION\n");
1005 case USB_REQUEST_GET_INTERFACE
:
1007 DPRINT1("USB_REQUEST_GET_INTERFACE\n");
1010 case USB_REQUEST_SET_INTERFACE
:
1012 DPRINT1("USB_REQUEST_SET_INTERFACE\n");
1015 case USB_REQUEST_SYNC_FRAME
:
1017 DPRINT1("USB_REQUEST_SYNC_FRAME\n");
1022 DPRINT1("Unknown Function Class Unknown request\n");
1030 DPRINT1("Ehci: Unhandled URB %x\n", Urb
->UrbHeader
.Function
);
1031 //Urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
1035 Irp
->IoStatus
.Information
= Information
;
1037 if (Status
!= STATUS_PENDING
)
1038 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);