Sync trunk.
[reactos.git] / drivers / usb / usbehci / fdo.c
1 /*
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.
6 * PROGRAMMERS:
7 * Michael Martin
8 */
9
10 /* INCLUDES *******************************************************************/
11 #include "usbehci.h"
12 #include <stdio.h>
13
14 VOID NTAPI
15 EhciDefferedRoutine(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
16 {
17 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
18 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
19 ULONG CStatus;
20
21 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) DeferredContext;
22 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION) FdoDeviceExtension->Pdo->DeviceExtension;
23
24 CStatus = (ULONG) SystemArgument2;
25
26 /* Port Change */
27 if (CStatus & EHCI_STS_PCD)
28 {
29 LONG i;
30 ULONG tmp;
31 ULONG Base;
32
33 Base = (ULONG)FdoDeviceExtension->ResourceMemory;
34
35 /* Loop through the ports */
36 for (i = 0; i < FdoDeviceExtension->ECHICaps.HCSParams.PortCount; i++)
37 {
38 tmp = READ_REGISTER_ULONG((PULONG) ((Base + EHCI_PORTSC) + (4 * i)));
39
40 /* Check for port change on this port */
41 if (tmp & 0x02)
42 {
43 /* Connect or Disconnect? */
44 if (tmp & 0x01)
45 {
46 DPRINT1("Device connected on port %d\n", i);
47
48 /* Check if a companion host controller exists */
49 if (FdoDeviceExtension->ECHICaps.HCSParams.CHCCount)
50 {
51 tmp = READ_REGISTER_ULONG((PULONG)((Base + EHCI_PORTSC) + (4 * i)));
52
53 /* Port should be in disabled state, as per USB 2.0 specs */
54 if (tmp & 0x04)
55 {
56 DPRINT1("Warning: The port the device has just connected to is not disabled!\n");
57 }
58
59 /* Is this non high speed device */
60 if (tmp & 0x400)
61 {
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);
65 continue;
66 }
67 }
68
69 KeStallExecutionProcessor(30);
70
71 /* As per USB 2.0 Specs, 9.1.2. Reset the port and clear the status change */
72 tmp |= 0x100 | 0x02;
73 /* Sanity, Disable port */
74 tmp &= ~0x04;
75
76 WRITE_REGISTER_ULONG((PULONG) ((Base + EHCI_PORTSC) + (4 * i)), tmp);
77
78 KeStallExecutionProcessor(20);
79
80 tmp = READ_REGISTER_ULONG((PULONG)((Base + EHCI_PORTSC) + (4 * i)));
81
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;
85
86 PdoDeviceExtension->HaltQueue = FALSE;
87 KeSetEvent(&PdoDeviceExtension->QueueDrainedEvent, 0, FALSE);
88 }
89 else
90 {
91 DPRINT1("Device disconnected on port %d\n", i);
92
93 /* Clear status change */
94 tmp = READ_REGISTER_ULONG((PULONG)((Base + EHCI_PORTSC) + (4 * i)));
95 tmp |= 0x02;
96 WRITE_REGISTER_ULONG((PULONG) ((Base + EHCI_PORTSC) + (4 * i)), tmp);
97 }
98 }
99 }
100 }
101 }
102
103 BOOLEAN NTAPI
104 InterruptService(PKINTERRUPT Interrupt, PVOID ServiceContext)
105 {
106 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
107 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT) ServiceContext;
108 ULONG CurrentFrame;
109 ULONG Base;
110 ULONG CStatus = 0;
111
112 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
113
114 Base = (ULONG)FdoDeviceExtension->ResourceMemory;
115
116 /* Read device status */
117 CStatus = READ_REGISTER_ULONG ((PULONG) (Base + EHCI_USBSTS));
118 CurrentFrame = READ_REGISTER_ULONG((PULONG) (Base + EHCI_FRINDEX));
119
120 CStatus &= (EHCI_ERROR_INT | EHCI_STS_INT | EHCI_STS_IAA | EHCI_STS_PCD | EHCI_STS_FLR);
121
122 if ((!CStatus) || (FdoDeviceExtension->DeviceState == 0))
123 {
124 /* This interrupt isnt for us or not ready for it. */
125 return FALSE;
126 }
127
128 /* Clear status */
129 WRITE_REGISTER_ULONG((PULONG) (Base + EHCI_USBSTS), CStatus);
130
131 if (CStatus & EHCI_ERROR_INT)
132 {
133 DPRINT1("EHCI Status=0x%x\n", CStatus);
134 }
135
136 if (CStatus & EHCI_STS_FATAL)
137 {
138 DPRINT1("EHCI: Host System Error. Possible PCI problems.\n");
139 ASSERT(FALSE);
140 }
141
142 if (CStatus & EHCI_STS_HALT)
143 {
144 DPRINT1("EHCI: Host Controller unexpected halt.\n");
145 /* FIXME: Reset the controller */
146 }
147
148 if (CStatus & EHCI_STS_INT)
149 {
150 FdoDeviceExtension->AsyncComplete = TRUE;
151 }
152
153 KeInsertQueueDpc(&FdoDeviceExtension->DpcObject, FdoDeviceExtension, (PVOID)CStatus);
154
155 return TRUE;
156 }
157
158 BOOLEAN
159 ResetPort(PDEVICE_OBJECT DeviceObject)
160 {
161 /*FIXME: Implement me */
162
163 return TRUE;
164 }
165
166 VOID
167 StopEhci(PDEVICE_OBJECT DeviceObject)
168 {
169 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
170 PEHCI_USBCMD_CONTENT UsbCmd;
171 ULONG base;
172 LONG tmp;
173
174 DPRINT1("Stopping Ehci controller\n");
175 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
176 base = (ULONG)FdoDeviceExtension->ResourceMemory;
177
178 WRITE_REGISTER_ULONG((PULONG) (base + EHCI_USBINTR), 0);
179
180 tmp = READ_REGISTER_ULONG((PULONG) (base + EHCI_USBCMD));
181 UsbCmd = (PEHCI_USBCMD_CONTENT) & tmp;
182 UsbCmd->Run = 0;
183 WRITE_REGISTER_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
184 }
185
186 VOID
187 StartEhci(PDEVICE_OBJECT DeviceObject)
188 {
189 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
190 PEHCI_USBCMD_CONTENT UsbCmd;
191 PEHCI_USBSTS_CONTEXT usbsts;
192 NTSTATUS Status;
193 LONG tmp;
194 LONG tmp2;
195 ULONG base;
196
197 DPRINT1("Starting Ehci controller\n");
198 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
199 base = (ULONG)FdoDeviceExtension->ResourceMemory;
200
201 tmp = READ_REGISTER_ULONG ((PULONG)(base + EHCI_USBCMD));
202
203 /* Stop the device */
204 UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
205 UsbCmd->Run = 0;
206 WRITE_REGISTER_ULONG ((PULONG)(base + EHCI_USBCMD), tmp);
207
208 /* Wait for the device to stop */
209 for (;;)
210 {
211 KeStallExecutionProcessor(10);
212 tmp = READ_REGISTER_ULONG((PULONG)(base + EHCI_USBSTS));
213 usbsts = (PEHCI_USBSTS_CONTEXT)&tmp;
214
215 if (usbsts->HCHalted)
216 {
217 break;
218 }
219 DPRINT("Waiting for Halt, USBSTS: %x\n", READ_REGISTER_ULONG ((PULONG)(base + EHCI_USBSTS)));
220 }
221
222 tmp = READ_REGISTER_ULONG ((PULONG)(base + EHCI_USBCMD));
223
224 /* Reset the device */
225 UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
226 UsbCmd->HCReset = TRUE;
227 WRITE_REGISTER_ULONG ((PULONG)(base + EHCI_USBCMD), tmp);
228
229 /* Wait for the device to reset */
230 for (;;)
231 {
232 KeStallExecutionProcessor(10);
233 tmp = READ_REGISTER_ULONG((PULONG)(base + EHCI_USBCMD));
234 UsbCmd = (PEHCI_USBCMD_CONTENT)&tmp;
235
236 if (!UsbCmd->HCReset)
237 {
238 break;
239 }
240 DPRINT("Waiting for reset, USBCMD: %x\n", READ_REGISTER_ULONG ((PULONG)(base + EHCI_USBCMD)));
241 }
242
243 UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
244
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);
249
250 WRITE_REGISTER_ULONG((PULONG)(base + EHCI_CTRLDSSEGMENT), 0);
251
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));
256
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);
261
262 /* Set the threshold */
263 UsbCmd->IntThreshold = 1;
264 WRITE_REGISTER_ULONG((PULONG)(base + EHCI_USBCMD), tmp);
265
266 KeInitializeDpc(&FdoDeviceExtension->DpcObject,
267 EhciDefferedRoutine,
268 FdoDeviceExtension);
269
270 Status = IoConnectInterrupt(&FdoDeviceExtension->EhciInterrupt,
271 InterruptService,
272 FdoDeviceExtension->DeviceObject,
273 NULL,
274 FdoDeviceExtension->Vector,
275 FdoDeviceExtension->Irql,
276 FdoDeviceExtension->Irql,
277 FdoDeviceExtension->Mode,
278 FdoDeviceExtension->IrqShared,
279 FdoDeviceExtension->Affinity,
280 FALSE);
281
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);
289
290 UsbCmd->Run = 1;
291 WRITE_REGISTER_ULONG((PULONG)(base + EHCI_USBCMD), tmp);
292
293 /* Wait for the device to start */
294 for (;;)
295 {
296 KeStallExecutionProcessor(10);
297 tmp2 = READ_REGISTER_ULONG((PULONG)(base + EHCI_USBSTS));
298 usbsts = (PEHCI_USBSTS_CONTEXT)&tmp2;
299
300 if (!usbsts->HCHalted)
301 {
302 break;
303 }
304 DPRINT("Waiting for start, USBSTS: %x\n", READ_REGISTER_ULONG ((PULONG)(base + EHCI_USBSTS)));
305 }
306
307 /* Set all port routing to ECHI controller */
308 WRITE_REGISTER_ULONG((PULONG)(base + EHCI_CONFIGFLAG), 1);
309 }
310
311 VOID
312 GetCapabilities(PFDO_DEVICE_EXTENSION DeviceExtension, ULONG Base)
313 {
314 PEHCI_CAPS PCap;
315 PEHCI_HCS_CONTENT PHCS;
316 LONG i;
317
318 if (!DeviceExtension)
319 return;
320
321 PCap = &DeviceExtension->ECHICaps;
322
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));
328
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);
334
335 if (PCap->HCCParams & 0x02)
336 DPRINT1("Frame list size is configurable\n");
337
338 if (PCap->HCCParams & 0x01)
339 DPRINT1("64bit address mode not supported!\n");
340
341 DPRINT1("Number of Ports: %d\n", PCap->HCSParams.PortCount);
342
343 if (PCap->HCSParams.PortPowerControl)
344 DPRINT1("Port Power Control is enabled\n");
345
346 if (!PCap->HCSParams.CHCCount)
347 {
348 DPRINT1("Number of Companion Host controllers %x\n", PCap->HCSParams.CHCCount);
349 DPRINT1("Number of Ports Per CHC: %d\n", PCap->HCSParams.PortPerCHC);
350 }
351
352 /* Copied from USBDRIVER in trunk */
353 PHCS = (PEHCI_HCS_CONTENT)&DeviceExtension->ECHICaps.HCSParams;
354 if (PHCS->PortRouteRules)
355 {
356 for (i = 0; i < 8; i++)
357 {
358 PCap->PortRoute[i] = READ_REGISTER_UCHAR((PUCHAR) (Base + 12 + i));
359 }
360 }
361 }
362
363 NTSTATUS
364 StartDevice(PDEVICE_OBJECT DeviceObject, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated)
365 {
366 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
367 PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
368 DEVICE_DESCRIPTION DeviceDescription;
369 ULONG NumberResources;
370 ULONG iCount;
371 ULONG DeviceAddress;
372 ULONG PropertySize;
373 ULONG BusNumber;
374 NTSTATUS Status;
375
376 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
377
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;
386
387 FdoDeviceExtension->pDmaAdapter = IoGetDmaAdapter(FdoDeviceExtension->LowerDevice,
388 &DeviceDescription,
389 &FdoDeviceExtension->MapRegisters);
390
391 if (FdoDeviceExtension->pDmaAdapter == NULL)
392 {
393 DPRINT1("IoGetDmaAdapter failed!\n");
394 ASSERT(FALSE);
395 }
396
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);
401
402 if (FdoDeviceExtension->PeriodicFramList == NULL)
403 {
404 DPRINT1("FdoDeviceExtension->PeriodicFramList is null\n");
405 return STATUS_UNSUCCESSFUL;
406 }
407
408 /* Zeroize it */
409 RtlZeroMemory(FdoDeviceExtension->PeriodicFramList, sizeof(ULONG) * 1024);
410
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 */
416 20800,
417 &FdoDeviceExtension->AsyncListQueueHeadPtrPhysAddr, FALSE);
418
419 if (FdoDeviceExtension->AsyncListQueueHeadPtr == NULL)
420 {
421 DPRINT1("Failed to allocate common buffer for AsyncListQueueHeadPtr!\n");
422 return STATUS_UNSUCCESSFUL;
423 }
424
425 /* Zeroize it */
426 RtlZeroMemory(FdoDeviceExtension->AsyncListQueueHeadPtr,
427 /* FIXME: Same as FIXME above */
428 20800);
429
430 Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice,
431 DevicePropertyAddress,
432 sizeof(ULONG),
433 &DeviceAddress,
434 &PropertySize);
435 if (NT_SUCCESS(Status))
436 {
437 DPRINT1("--->DeviceAddress: %x\n", DeviceAddress);
438 }
439
440 Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice,
441 DevicePropertyBusNumber,
442 sizeof(ULONG),
443 &BusNumber,
444 &PropertySize);
445 if (NT_SUCCESS(Status))
446 {
447 DPRINT1("--->BusNumber: %x\n", BusNumber);
448 }
449
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++)
454 {
455 DPRINT("Resource Info %d:\n", iCount);
456 resource = &translated->PartialDescriptors[iCount];
457 switch(resource->Type)
458 {
459 case CmResourceTypePort:
460 {
461 DPRINT("Port Start: %x\n", resource->u.Port.Start);
462 DPRINT("Port Length %d\n", resource->u.Port.Length);
463 /* FIXME: Handle Ports */
464 break;
465 }
466 case CmResourceTypeInterrupt:
467 {
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;
474 break;
475 }
476 case CmResourceTypeMemory:
477 {
478 ULONG ResourceBase = 0;
479 ULONG MemLength;
480
481 DPRINT("Mem Start: %x\n", resource->u.Memory.Start);
482 DPRINT("Mem Length: %d\n", resource->u.Memory.Length);
483
484 ResourceBase = (ULONG) MmMapIoSpace(resource->u.Memory.Start, resource->u.Memory.Length, FALSE);
485 DPRINT("ResourceBase %x\n", ResourceBase);
486
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)
492 {
493 DPRINT1("MmMapIoSpace failed!!!!!!!!!\n");
494 }
495 MemLength = resource->u.Memory.Length;
496 FdoDeviceExtension->Size = MemLength;
497
498 break;
499 }
500 case CmResourceTypeDma:
501 {
502 DPRINT("Dma Channel: %x\n", resource->u.Dma.Channel);
503 DPRINT("Dma Port: %d\n", resource->u.Dma.Port);
504 break;
505 }
506 case CmResourceTypeDevicePrivate:
507 {
508 /* Windows does this. */
509 DPRINT1("CmResourceTypeDevicePrivate not handled\n");
510 break;
511 }
512 default:
513 {
514 DPRINT1("PNP Manager gave resource type not handled!! Notify Developers!\n");
515 break;
516 }
517 }
518 }
519
520 StartEhci(DeviceObject);
521 FdoDeviceExtension->DeviceState = DEVICESTARTED;
522
523 return STATUS_SUCCESS;
524 }
525
526 NTSTATUS
527 FdoQueryBusRelations(
528 PDEVICE_OBJECT DeviceObject,
529 PDEVICE_RELATIONS* pDeviceRelations)
530 {
531 PFDO_DEVICE_EXTENSION DeviceExtension;
532 PDEVICE_RELATIONS DeviceRelations = NULL;
533 PDEVICE_OBJECT Pdo;
534 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
535 NTSTATUS Status;
536 ULONG UsbDeviceNumber = 0;
537 WCHAR CharDeviceName[64];
538
539 UNICODE_STRING DeviceName;
540
541 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
542
543 /* Create the PDO with the next available number */
544 while (TRUE)
545 {
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);
551
552 Status = IoCreateDevice(DeviceObject->DriverObject,
553 sizeof(PDO_DEVICE_EXTENSION),
554 &DeviceName,
555 FILE_DEVICE_BUS_EXTENDER,
556 0,
557 FALSE,
558 &Pdo);
559
560 if (NT_SUCCESS(Status))
561 break;
562
563 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
564 {
565 /* Try the next name */
566 UsbDeviceNumber++;
567 continue;
568 }
569
570 /* Bail on any other error */
571 if (!NT_SUCCESS(Status))
572 {
573 DPRINT1("UsbEhci: Failed to create PDO %wZ, Status %x\n", &DeviceName, Status);
574 return Status;
575 }
576 }
577
578 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
579 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
580 PdoDeviceExtension->Common.IsFdo = FALSE;
581
582 PdoDeviceExtension->ControllerFdo = DeviceObject;
583 PdoDeviceExtension->DeviceObject = Pdo;
584
585 InitializeListHead(&PdoDeviceExtension->IrpQueue);
586 KeInitializeSpinLock(&PdoDeviceExtension->IrpQueueLock);
587
588 KeInitializeEvent(&PdoDeviceExtension->QueueDrainedEvent, SynchronizationEvent, TRUE);
589
590 ExInitializeFastMutex(&PdoDeviceExtension->ListLock);
591
592 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
593
594 DeviceExtension->Pdo = Pdo;
595
596 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
597
598 if (!DeviceRelations)
599 {
600 return STATUS_INSUFFICIENT_RESOURCES;
601 }
602
603 DeviceRelations->Count = 1;
604 DeviceRelations->Objects[0] = Pdo;
605 ObReferenceObject(Pdo);
606
607 *pDeviceRelations = DeviceRelations;
608 return STATUS_SUCCESS;
609 }
610
611 NTSTATUS NTAPI
612 FdoDispatchPnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
613 {
614 NTSTATUS Status;
615 PIO_STACK_LOCATION Stack = NULL;
616 PCM_PARTIAL_RESOURCE_LIST raw;
617 PCM_PARTIAL_RESOURCE_LIST translated;
618 ULONG_PTR Information = 0;
619
620 Stack = IoGetCurrentIrpStackLocation(Irp);
621
622 switch(Stack->MinorFunction)
623 {
624 case IRP_MN_START_DEVICE:
625 {
626 DPRINT1("START_DEVICE\n");
627 Irp->IoStatus.Status = STATUS_SUCCESS;
628 Status = ForwardAndWait(DeviceObject, Irp);
629
630 raw = &Stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
631 translated = &Stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
632 Status = StartDevice(DeviceObject, raw, translated);
633 break;
634 }
635 case IRP_MN_QUERY_DEVICE_RELATIONS:
636 {
637 DPRINT1("IRP_MN_QUERY_DEVICE_RELATIONS\n");
638 switch(Stack->Parameters.QueryDeviceRelations.Type)
639 {
640 case BusRelations:
641 {
642 PDEVICE_RELATIONS DeviceRelations = NULL;
643 DPRINT("BusRelations\n");
644 Status = FdoQueryBusRelations(DeviceObject, &DeviceRelations);
645 Information = (ULONG_PTR)DeviceRelations;
646 break;
647 }
648 default:
649 {
650 DPRINT("Unknown query device relations type\n");
651 Status = STATUS_NOT_IMPLEMENTED;
652 break;
653 }
654 }
655 break;
656 }
657 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
658 {
659 DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
660 return ForwardIrpAndForget(DeviceObject, Irp);
661 break;
662 }
663 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
664 {
665 DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
666 }
667 case IRP_MN_QUERY_INTERFACE:
668 {
669 Status = STATUS_SUCCESS;
670 Information = 0;
671 Status = ForwardIrpAndForget(DeviceObject, Irp);
672 return Status;
673 break;
674 }
675 default:
676 {
677 DPRINT1("IRP_MJ_PNP / Unhandled minor function 0x%lx\n", Stack->MinorFunction);
678 return ForwardIrpAndForget(DeviceObject, Irp);
679 }
680 }
681
682 Irp->IoStatus.Information = Information;
683 Irp->IoStatus.Status = Status;
684 IoCompleteRequest(Irp, IO_NO_INCREMENT);
685 return Status;
686 }
687
688 NTSTATUS NTAPI
689 AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Pdo)
690 {
691 NTSTATUS Status = STATUS_UNSUCCESSFUL;
692 PDEVICE_OBJECT Fdo;
693 ULONG UsbDeviceNumber = 0;
694 WCHAR CharDeviceName[64];
695 WCHAR CharSymLinkName[64];
696 UNICODE_STRING DeviceName;
697 UNICODE_STRING SymLinkName;
698 UNICODE_STRING InterfaceSymLinkName;
699 ULONG BytesRead;
700 PCI_COMMON_CONFIG PciConfig;
701
702 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
703
704 DPRINT("Ehci AddDevice\n");
705
706 /* Create the FDO with next available number */
707 while (TRUE)
708 {
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);
714
715 Status = IoCreateDevice(DriverObject,
716 sizeof(FDO_DEVICE_EXTENSION),
717 &DeviceName,
718 FILE_DEVICE_CONTROLLER,
719 0,
720 FALSE,
721 &Fdo);
722
723 if (NT_SUCCESS(Status))
724 break;
725
726 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
727 {
728 /* Try the next name */
729 UsbDeviceNumber++;
730 continue;
731 }
732
733 /* Bail on any other error */
734 if (!NT_SUCCESS(Status))
735 {
736 DPRINT1("UsbEhci: Failed to create %wZ, Status %x\n", &DeviceName, Status);
737 return Status;
738 }
739 }
740
741 swprintf(CharSymLinkName, L"\\Device\\HCD%d", UsbDeviceNumber);
742 RtlInitUnicodeString(&SymLinkName, CharSymLinkName);
743 Status = IoCreateSymbolicLink(&SymLinkName, &DeviceName);
744
745 if (!NT_SUCCESS(Status))
746 {
747 DPRINT1("Warning: Unable to create symbolic link for ehci host controller!\n");
748 }
749
750 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) Fdo->DeviceExtension;
751 RtlZeroMemory(FdoDeviceExtension, sizeof(PFDO_DEVICE_EXTENSION));
752
753 FdoDeviceExtension->Common.IsFdo = TRUE;
754 FdoDeviceExtension->DeviceObject = Fdo;
755
756 FdoDeviceExtension->LowerDevice = IoAttachDeviceToDeviceStack(Fdo, Pdo);
757
758 if (FdoDeviceExtension->LowerDevice == NULL)
759 {
760 DPRINT1("UsbEhci: Failed to attach to device stack!\n");
761 IoDeleteSymbolicLink(&SymLinkName);
762 IoDeleteDevice(Fdo);
763
764 return STATUS_NO_SUCH_DEVICE;
765 }
766
767 Fdo->Flags |= DO_BUFFERED_IO;// | DO_POWER_PAGABLE;
768
769 ASSERT(FdoDeviceExtension->LowerDevice == Pdo);
770
771 Status = GetBusInterface(FdoDeviceExtension->LowerDevice, &FdoDeviceExtension->BusInterface);
772
773 if (!NT_SUCCESS(Status))
774 {
775 DPRINT1("GetBusInterface() failed with %x\n", Status);
776 IoDetachDevice(FdoDeviceExtension->LowerDevice);
777 IoDeleteSymbolicLink(&SymLinkName);
778 IoDeleteDevice(Fdo);
779 return Status;
780 }
781
782 BytesRead = (*FdoDeviceExtension->BusInterface.GetBusData)(
783 FdoDeviceExtension->BusInterface.Context,
784 PCI_WHICHSPACE_CONFIG,
785 &PciConfig,
786 0,
787 PCI_COMMON_HDR_LENGTH);
788
789
790 if (BytesRead != PCI_COMMON_HDR_LENGTH)
791 {
792 DPRINT1("GetBusData failed!\n");
793 IoDetachDevice(FdoDeviceExtension->LowerDevice);
794 IoDeleteSymbolicLink(&SymLinkName);
795 IoDeleteDevice(Fdo);
796 return STATUS_UNSUCCESSFUL;
797 }
798
799 if (PciConfig.Command & PCI_ENABLE_IO_SPACE)
800 DPRINT("PCI_ENABLE_IO_SPACE\n");
801
802 if (PciConfig.Command & PCI_ENABLE_MEMORY_SPACE)
803 DPRINT("PCI_ENABLE_MEMORY_SPACE\n");
804
805 if (PciConfig.Command & PCI_ENABLE_BUS_MASTER)
806 DPRINT("PCI_ENABLE_BUS_MASTER\n");
807
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);
811
812 FdoDeviceExtension->VendorId = PciConfig.VendorID;
813 FdoDeviceExtension->DeviceId = PciConfig.DeviceID;
814
815 FdoDeviceExtension->DeviceState = DEVICEINTIALIZED;
816
817 Status = IoRegisterDeviceInterface(Pdo, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL, &InterfaceSymLinkName);
818 if (!NT_SUCCESS(Status))
819 {
820 DPRINT1("Unable to register device interface!\n");
821 ASSERT(FALSE);
822 }
823 else
824 {
825 Status = IoSetDeviceInterfaceState(&InterfaceSymLinkName, TRUE);
826 DPRINT1("SetInterfaceState %x\n", Status);
827 if (!NT_SUCCESS(Status))
828 ASSERT(FALSE);
829 }
830 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
831
832 return STATUS_SUCCESS;
833 }