cb9f166df3fcb4953ba3272dad8bbc3f1ca46c68
[reactos.git] / reactos / 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 //#include "ntstrsafe.h"
15
16 VOID NTAPI
17 EhciDefferedRoutine(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
18 {
19 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
20 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
21 ULONG CStatus;
22
23 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) DeferredContext;
24 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION) FdoDeviceExtension->Pdo->DeviceExtension;
25
26 CStatus = (ULONG) SystemArgument2;
27
28 /* Port Change */
29 if (CStatus & EHCI_STS_PCD)
30 {
31 LONG i;
32 ULONG tmp;
33 ULONG Base;
34
35 Base = (ULONG)FdoDeviceExtension->ResourceMemory;
36
37 /* Loop through the ports */
38 for (i = 0; i < FdoDeviceExtension->ECHICaps.HCSParams.PortCount; i++)
39 {
40 tmp = READ_REGISTER_ULONG((PULONG) ((Base + EHCI_PORTSC) + (4 * i)));
41
42 /* Check for port change on this port */
43 if (tmp & 0x02)
44 {
45 /* Connect or Disconnect? */
46 if (tmp & 0x01)
47 {
48 DPRINT1("Device connected on port %d\n", i);
49
50 /* Check if a companion host controller exists */
51 if (FdoDeviceExtension->ECHICaps.HCSParams.CHCCount)
52 {
53 tmp = READ_REGISTER_ULONG((PULONG)((Base + EHCI_PORTSC) + (4 * i)));
54
55 /* Port should be in disabled state, as per USB 2.0 specs */
56 if (tmp & 0x04)
57 {
58 DPRINT1("Warning: The port the device has just connected to is not disabled!\n");
59 }
60
61 /* Is this non high speed device */
62 if (tmp & 0x400)
63 {
64 DPRINT1("Releasing ownership to companion host controller!\n");
65 /* Release ownership to companion host controller */
66 WRITE_REGISTER_ULONG((PULONG) ((Base + EHCI_PORTSC) + (4 * i)), 0x4000);
67 }
68 }
69
70 KeStallExecutionProcessor(30);
71 DPRINT("port tmp %x\n", tmp);
72
73 /* As per USB 2.0 Specs, 9.1.2. Reset the port and clear the status change */
74 tmp |= 0x100 | 0x02;
75 /* Sanity, Disable port */
76 tmp &= ~0x04;
77
78 WRITE_REGISTER_ULONG((PULONG) ((Base + EHCI_PORTSC) + (4 * i)), tmp);
79
80 KeStallExecutionProcessor(20);
81
82 tmp = READ_REGISTER_ULONG((PULONG)((Base + EHCI_PORTSC) + (4 * i)));
83
84 DPRINT("port tmp %x\n", tmp);
85 GetDeviceDescriptor(FdoDeviceExtension, 0, 0, FALSE);
86 PdoDeviceExtension->ChildDeviceCount++;
87 //PdoDeviceExtension->CallbackRoutine(PdoDeviceExtension->CallbackContext);
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 return STATUS_SUCCESS;
523 }
524
525 NTSTATUS
526 FdoQueryBusRelations(
527 PDEVICE_OBJECT DeviceObject,
528 PDEVICE_RELATIONS* pDeviceRelations)
529 {
530 PFDO_DEVICE_EXTENSION DeviceExtension;
531 PDEVICE_RELATIONS DeviceRelations = NULL;
532 PDEVICE_OBJECT Pdo;
533 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
534 NTSTATUS Status;
535 ULONG UsbDeviceNumber = 0;
536 WCHAR CharDeviceName[64];
537
538 UNICODE_STRING DeviceName;
539
540 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
541
542 /* Create the PDO with the next available number */
543 while (TRUE)
544 {
545 /* FIXME: Use safe string */
546 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBPDO-%d", UsbDeviceNumber); */
547 swprintf(CharDeviceName, L"\\Device\\USBPDO-%d", UsbDeviceNumber);
548 RtlInitUnicodeString(&DeviceName, CharDeviceName);
549 DPRINT("DeviceName %wZ\n", &DeviceName);
550
551 Status = IoCreateDevice(DeviceObject->DriverObject,
552 sizeof(PDO_DEVICE_EXTENSION),
553 &DeviceName,
554 FILE_DEVICE_BUS_EXTENDER,
555 0,
556 FALSE,
557 &Pdo);
558
559 if (NT_SUCCESS(Status))
560 break;
561
562 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
563 {
564 /* Try the next name */
565 UsbDeviceNumber++;
566 continue;
567 }
568
569 /* Bail on any other error */
570 if (!NT_SUCCESS(Status))
571 {
572 DPRINT1("UsbEhci: Failed to create PDO %wZ, Status %x\n", &DeviceName, Status);
573 return Status;
574 }
575 }
576
577 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
578 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
579 PdoDeviceExtension->Common.IsFdo = FALSE;
580
581 PdoDeviceExtension->ControllerFdo = DeviceObject;
582 PdoDeviceExtension->DeviceObject = Pdo;
583
584 InitializeListHead(&PdoDeviceExtension->IrpQueue);
585 KeInitializeSpinLock(&PdoDeviceExtension->IrpQueueLock);
586
587 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
588
589 DeviceExtension->Pdo = Pdo;
590
591 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
592
593 if (!DeviceRelations)
594 {
595 return STATUS_INSUFFICIENT_RESOURCES;
596 }
597
598 DeviceRelations->Count = 1;
599 DeviceRelations->Objects[0] = Pdo;
600 ObReferenceObject(Pdo);
601
602 *pDeviceRelations = DeviceRelations;
603 return STATUS_SUCCESS;
604 }
605
606 NTSTATUS NTAPI
607 FdoDispatchPnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
608 {
609 NTSTATUS Status;
610 PIO_STACK_LOCATION Stack = NULL;
611 PCM_PARTIAL_RESOURCE_LIST raw;
612 PCM_PARTIAL_RESOURCE_LIST translated;
613 ULONG_PTR Information = 0;
614
615 Stack = IoGetCurrentIrpStackLocation(Irp);
616
617 switch(Stack->MinorFunction)
618 {
619 case IRP_MN_START_DEVICE:
620 {
621 DPRINT1("START_DEVICE\n");
622 Irp->IoStatus.Status = STATUS_SUCCESS;
623 Status = ForwardAndWait(DeviceObject, Irp);
624
625 raw = &Stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
626 translated = &Stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
627 Status = StartDevice(DeviceObject, raw, translated);
628 break;
629 }
630 case IRP_MN_QUERY_DEVICE_RELATIONS:
631 {
632 DPRINT1("IRP_MN_QUERY_DEVICE_RELATIONS\n");
633 switch(Stack->Parameters.QueryDeviceRelations.Type)
634 {
635 case BusRelations:
636 {
637 PDEVICE_RELATIONS DeviceRelations = NULL;
638 DPRINT("BusRelations\n");
639 Status = FdoQueryBusRelations(DeviceObject, &DeviceRelations);
640 Information = (ULONG_PTR)DeviceRelations;
641 break;
642 }
643 default:
644 {
645 DPRINT("Unknown query device relations type\n");
646 Status = STATUS_NOT_IMPLEMENTED;
647 break;
648 }
649 }
650 break;
651 }
652 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
653 {
654 DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
655 return ForwardIrpAndForget(DeviceObject, Irp);
656 break;
657 }
658 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
659 {
660 DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
661 }
662 case IRP_MN_QUERY_INTERFACE:
663 {
664 Status = STATUS_SUCCESS;
665 Information = 0;
666 Status = ForwardIrpAndForget(DeviceObject, Irp);
667 return Status;
668 break;
669 }
670 default:
671 {
672 DPRINT1("IRP_MJ_PNP / Unhandled minor function 0x%lx\n", Stack->MinorFunction);
673 return ForwardIrpAndForget(DeviceObject, Irp);
674 }
675 }
676
677 Irp->IoStatus.Information = Information;
678 Irp->IoStatus.Status = Status;
679 IoCompleteRequest(Irp, IO_NO_INCREMENT);
680 return Status;
681 }
682
683 NTSTATUS NTAPI
684 AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Pdo)
685 {
686 NTSTATUS Status = STATUS_UNSUCCESSFUL;
687 PDEVICE_OBJECT Fdo;
688 ULONG UsbDeviceNumber = 0;
689 WCHAR CharDeviceName[64];
690 WCHAR CharSymLinkName[64];
691 UNICODE_STRING DeviceName;
692 UNICODE_STRING SymLinkName;
693 UNICODE_STRING InterfaceSymLinkName;
694 ULONG BytesRead;
695 PCI_COMMON_CONFIG PciConfig;
696
697 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
698
699 DPRINT("Ehci AddDevice\n");
700
701 /* Create the FDO with next available number */
702 while (TRUE)
703 {
704 /* FIXME: Use safe string sprintf*/
705 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBFDO-%d", UsbDeviceNumber); */
706 swprintf(CharDeviceName, L"\\Device\\USBFDO-%d", UsbDeviceNumber);
707 RtlInitUnicodeString(&DeviceName, CharDeviceName);
708 DPRINT("DeviceName %wZ\n", &DeviceName);
709
710 Status = IoCreateDevice(DriverObject,
711 sizeof(FDO_DEVICE_EXTENSION),
712 &DeviceName,
713 FILE_DEVICE_CONTROLLER,
714 0,
715 FALSE,
716 &Fdo);
717
718 if (NT_SUCCESS(Status))
719 break;
720
721 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
722 {
723 /* Try the next name */
724 UsbDeviceNumber++;
725 continue;
726 }
727
728 /* Bail on any other error */
729 if (!NT_SUCCESS(Status))
730 {
731 DPRINT1("UsbEhci: Failed to create %wZ, Status %x\n", &DeviceName, Status);
732 return Status;
733 }
734 }
735
736 swprintf(CharSymLinkName, L"\\Device\\HCD%d", UsbDeviceNumber);
737 RtlInitUnicodeString(&SymLinkName, CharSymLinkName);
738 Status = IoCreateSymbolicLink(&SymLinkName, &DeviceName);
739
740 if (!NT_SUCCESS(Status))
741 {
742 DPRINT1("Warning: Unable to create symbolic link for ehci host controller!\n");
743 }
744
745 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) Fdo->DeviceExtension;
746 RtlZeroMemory(FdoDeviceExtension, sizeof(PFDO_DEVICE_EXTENSION));
747
748 FdoDeviceExtension->Common.IsFdo = TRUE;
749 FdoDeviceExtension->DeviceObject = Fdo;
750
751 FdoDeviceExtension->LowerDevice = IoAttachDeviceToDeviceStack(Fdo, Pdo);
752
753 if (FdoDeviceExtension->LowerDevice == NULL)
754 {
755 DPRINT1("UsbEhci: Failed to attach to device stack!\n");
756 IoDeleteSymbolicLink(&SymLinkName);
757 IoDeleteDevice(Fdo);
758
759 return STATUS_NO_SUCH_DEVICE;
760 }
761
762 Fdo->Flags |= DO_BUFFERED_IO;// | DO_POWER_PAGABLE;
763
764 ASSERT(FdoDeviceExtension->LowerDevice == Pdo);
765
766 Status = GetBusInterface(FdoDeviceExtension->LowerDevice, &FdoDeviceExtension->BusInterface);
767
768 if (!NT_SUCCESS(Status))
769 {
770 DPRINT1("GetBusInterface() failed with %x\n", Status);
771 IoDetachDevice(FdoDeviceExtension->LowerDevice);
772 IoDeleteSymbolicLink(&SymLinkName);
773 IoDeleteDevice(Fdo);
774 return Status;
775 }
776
777 BytesRead = (*FdoDeviceExtension->BusInterface.GetBusData)(
778 FdoDeviceExtension->BusInterface.Context,
779 PCI_WHICHSPACE_CONFIG,
780 &PciConfig,
781 0,
782 PCI_COMMON_HDR_LENGTH);
783
784
785 if (BytesRead != PCI_COMMON_HDR_LENGTH)
786 {
787 DPRINT1("GetBusData failed!\n");
788 IoDetachDevice(FdoDeviceExtension->LowerDevice);
789 IoDeleteSymbolicLink(&SymLinkName);
790 IoDeleteDevice(Fdo);
791
792 return STATUS_UNSUCCESSFUL;
793 }
794
795 if (PciConfig.Command & PCI_ENABLE_IO_SPACE)
796 DPRINT("PCI_ENABLE_IO_SPACE\n");
797
798 if (PciConfig.Command & PCI_ENABLE_MEMORY_SPACE)
799 DPRINT("PCI_ENABLE_MEMORY_SPACE\n");
800
801 if (PciConfig.Command & PCI_ENABLE_BUS_MASTER)
802 DPRINT("PCI_ENABLE_BUS_MASTER\n");
803
804 DPRINT("BaseAddress[0] %x\n", PciConfig.u.type0.BaseAddresses[0]);
805 DPRINT1("Vendor %x\n", PciConfig.VendorID);
806 DPRINT1("Device %x\n", PciConfig.DeviceID);
807
808 FdoDeviceExtension->VendorId = PciConfig.VendorID;
809 FdoDeviceExtension->DeviceId = PciConfig.DeviceID;
810
811 FdoDeviceExtension->DeviceState = DEVICEINTIALIZED;
812
813 Status = IoRegisterDeviceInterface(Pdo, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL, &InterfaceSymLinkName);
814 if (!NT_SUCCESS(Status))
815 {
816 DPRINT1("Unable to register device interface!\n");
817 }
818 else
819 {
820 Status = IoSetDeviceInterfaceState(&InterfaceSymLinkName, TRUE);
821 DPRINT1("SetInterfaceState %x\n", Status);
822 }
823 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
824
825 return STATUS_SUCCESS;
826 }