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