Add .keep guard files in order to restore lost but empty directories we had with...
[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 (michael.martin@reactos.org)
8 */
9
10 #include "hwiface.h"
11 #include "usbehci.h"
12 #include "physmem.h"
13 #include <stdio.h>
14
15 VOID NTAPI
16 EhciDefferedRoutine(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
17 {
18 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
19 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
20 ULONG CStatus;
21 ULONG tmp;
22 ULONG OpRegisters;
23 PEHCI_HOST_CONTROLLER hcd;
24 int i;
25
26 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) DeferredContext;
27
28 /* Nothing is valid if the Pdo is NULL */
29 if (!FdoDeviceExtension->Pdo)
30 {
31 DPRINT1("PDO not set yet!\n");
32 return;
33 }
34
35 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION) FdoDeviceExtension->Pdo->DeviceExtension;
36
37 OpRegisters = (ULONG)FdoDeviceExtension->hcd.OpRegisters;
38
39 hcd = &FdoDeviceExtension->hcd;
40
41 CStatus = (ULONG) SystemArgument2;
42
43 /* If Reclamation (The QueueHead list has been transveresed twice),
44 look through the queuehead list and find queue heads that have been
45 1. Halted due to error
46 2. Transfer completion.
47 Move these QueueHeads to a temporary list that is used to pend memory release.
48 Either an Event is signalled or an Irp is completed depending on what was set during transfer request
49 setup. Next software issue a "DoorBell" that informs the controller the Asynchronous List is about to
50 be modified.
51 After the controller acks this with interrupt, the memory for queueheads are released. */
52
53 if (CStatus & (EHCI_STS_RECL| EHCI_STS_INT | EHCI_ERROR_INT))
54 {
55 PQUEUE_HEAD CurrentQH;
56 PQUEUE_TRANSFER_DESCRIPTOR CurrentTD;
57 BOOLEAN QueueHeadCompleted;
58
59 /* Go through the list and delink completed (not active) QueueHeads */
60 CurrentQH = hcd->AsyncListQueue;
61 CurrentQH = CurrentQH->NextQueueHead;
62
63 while ((CurrentQH) && (CurrentQH != hcd->AsyncListQueue))
64 {
65 DPRINT1("Checking QueueHead %x, Next %x\n", CurrentQH, CurrentQH->NextQueueHead);
66 DPRINT1("Active %d, Halted %d\n", CurrentQH->Token.Bits.Active, CurrentQH->Token.Bits.Halted);
67
68 /* if the QueueHead has completed */
69 if (!CurrentQH->Token.Bits.Active)
70 {
71 /* Assume success */
72 USBD_STATUS UrbStatus = USBD_STATUS_SUCCESS;
73
74 QueueHeadCompleted = TRUE;
75
76 /* Check the Status of the QueueHead */
77 if (CurrentQH->Token.Bits.Halted)
78 {
79 if (CurrentQH->Token.Bits.DataBufferError)
80 {
81 DPRINT1("Data buffer error\n");
82 UrbStatus = USBD_STATUS_DATA_BUFFER_ERROR;
83 }
84 else if (CurrentQH->Token.Bits.BabbleDetected)
85 {
86 DPRINT1("Babble Detected\n");
87 UrbStatus = USBD_STATUS_BABBLE_DETECTED;
88 }
89 else
90 {
91 DPRINT1("Stall PID\n");
92 UrbStatus = USBD_STATUS_STALL_PID;
93 }
94 }
95
96 /* Check the Descriptors */
97 CurrentTD = CurrentQH->FirstTransferDescriptor;
98 while (CurrentTD)
99 {
100 /* FIXME: What needs to happen if the QueueHead was marked as complete but descriptors was not */
101 if ((CurrentTD->Token.Bits.Active) || (CurrentTD->Token.Bits.Halted))
102 {
103 /* The descriptor was not completed */
104 QueueHeadCompleted = FALSE;
105 DPRINT1("QueueHead was marked as completed but contains descriptors that were not completed\n");
106 ASSERT(FALSE);
107 break;
108 }
109 CurrentTD = CurrentTD->NextDescriptor;
110 }
111
112 if ((QueueHeadCompleted) || (CurrentQH->Token.Bits.Halted))
113 {
114 PQUEUE_HEAD FreeQH;
115
116 FreeQH = CurrentQH;
117 CurrentQH = CurrentQH->NextQueueHead;
118 DPRINT1("QueueHead %x has completed. Removing\n", FreeQH);
119 /* Move it into the completed list */
120 UnlinkQueueHead(hcd, FreeQH);
121 LinkQueueHeadToCompletedList(hcd, FreeQH);
122 DPRINT1("Remove done\n");
123
124 /* If the Event is set then the caller is waiting on completion */
125 if (FreeQH->Event)
126 {
127 KeSetEvent(FreeQH->Event, IO_NO_INCREMENT, FALSE);
128 }
129
130 /* If there is an IrpToComplete then the caller did not wait on completion
131 and the IRP was marked as PENDING. Complete it now. */
132 if (FreeQH->IrpToComplete)
133 {
134 PIRP Irp;
135 PIO_STACK_LOCATION Stack;
136 PURB Urb;
137
138 Irp = FreeQH->IrpToComplete;
139 Stack = IoGetCurrentIrpStackLocation(Irp);
140 ASSERT(Stack);
141 Urb = (PURB) Stack->Parameters.Others.Argument1;
142 ASSERT(Urb);
143
144 /* Check for error */
145 if (CStatus & EHCI_ERROR_INT)
146 {
147 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
148 Irp->IoStatus.Information = 0;
149 /* Set BufferLength to 0 as there was error */
150 if (Urb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE)
151 {
152 Urb->UrbControlDescriptorRequest.TransferBufferLength = 0;
153 }
154 DPRINT1("There was an Error, TransferBufferLength set to 0\n");
155 }
156 else
157 {
158 if (Urb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE)
159 {
160 if (Urb->UrbControlDescriptorRequest.TransferBufferLength >=
161 ((PUSB_COMMON_DESCRIPTOR)(Urb->UrbControlDescriptorRequest.TransferBuffer))->bLength)
162 {
163 Urb->UrbControlDescriptorRequest.TransferBufferLength =
164 ((PUSB_COMMON_DESCRIPTOR)(Urb->UrbControlDescriptorRequest.TransferBuffer))->bLength;
165 }
166 }
167
168 Irp->IoStatus.Status = STATUS_SUCCESS;
169 Irp->IoStatus.Information = 0;
170 DPRINT1("Completing Irp\n");
171 }
172 Urb->UrbHeader.Status = UrbStatus;
173 IoCompleteRequest(Irp, IO_NO_INCREMENT);
174 }
175
176 /* FIXME: Move to static function */
177 PEHCI_USBCMD_CONTENT UsbCmd;
178 /* Ring the DoorBell so that host controller knows a QueueHead was removed */
179 DPRINT1("Ringing Doorbell\n");
180 tmp = READ_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBCMD));
181 UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
182 UsbCmd->DoorBell = TRUE;
183 WRITE_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBCMD), tmp);
184 continue;
185 }
186 }
187
188 CurrentQH = CurrentQH->NextQueueHead;
189 }
190 }
191
192
193 /* Port Change. */
194 /* FIXME: Use EnumControllerPorts instead */
195 if (CStatus & EHCI_STS_PCD)
196 {
197 /* Loop through the ports */
198 for (i = 0; i < hcd->ECHICaps.HCSParams.PortCount; i++)
199 {
200 tmp = READ_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)));
201
202 /* Check for port change on this port */
203 if (tmp & 0x02)
204 {
205 /* Clear status change */
206 tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
207 tmp |= 0x02;
208 WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)), tmp);
209
210 /* Connect or Disconnect? */
211 if (tmp & 0x01)
212 {
213 DPRINT1("Device connected on port %d\n", i);
214
215 /* Check if a companion host controller exists */
216 if (hcd->ECHICaps.HCSParams.CHCCount)
217 {
218 tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
219
220 /* Port should be in disabled state, as per USB 2.0 specs */
221 if (tmp & 0x04)
222 {
223 DPRINT1("Warning: The port the device has just connected to is not disabled!\n");
224 }
225
226 /* Is this non high speed device */
227 if (tmp & 0x400)
228 {
229 DPRINT1("Non HighSpeed device connected. Releasing ownership.\n");
230 /* Release ownership to companion host controller */
231 WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)), 0x2000);
232 continue;
233 }
234 }
235
236 KeStallExecutionProcessor(30);
237
238 /* FIXME: Hub driver does this also, is it needed here? */
239 /* As per USB 2.0 Specs, 9.1.2. Reset the port and clear the status change */
240 //tmp |= 0x100 | 0x02;
241 /* Sanity, Disable port */
242 //tmp &= ~0x04;
243
244 //WRITE_REGISTER_ULONG((PULONG) ((Base + EHCI_PORTSC) + (4 * i)), tmp);
245
246 //KeStallExecutionProcessor(20);
247
248 tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
249
250 PdoDeviceExtension->ChildDeviceCount++;
251 hcd->Ports[i].PortStatus &= ~0x8000;
252 hcd->Ports[i].PortStatus |= USB_PORT_STATUS_HIGH_SPEED;
253 hcd->Ports[i].PortStatus |= USB_PORT_STATUS_CONNECT;
254 hcd->Ports[i].PortChange |= USB_PORT_STATUS_CONNECT;
255 DPRINT1("Completing URB\n");
256 CompletePendingURBRequest(PdoDeviceExtension);
257 }
258 else
259 {
260 DPRINT1("Device disconnected on port %d\n", i);
261 }
262 }
263 }
264 }
265
266 /* Asnyc Advance */
267 if (CStatus & EHCI_STS_IAA)
268 {
269 DPRINT1("Async Advance!\n");
270 CleanupAsyncList(hcd);
271 }
272 }
273
274 BOOLEAN NTAPI
275 InterruptService(PKINTERRUPT Interrupt, PVOID ServiceContext)
276 {
277 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
278 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT) ServiceContext;
279 PEHCI_HOST_CONTROLLER hcd;
280 ULONG CStatus = 0;
281
282 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
283
284 hcd = &FdoDeviceExtension->hcd;
285
286 /* Read device status */
287 CStatus = ReadControllerStatus(hcd);
288
289 CStatus &= (EHCI_ERROR_INT | EHCI_STS_INT | EHCI_STS_IAA | EHCI_STS_PCD | EHCI_STS_FLR | EHCI_STS_RECL);
290
291 if ((!CStatus) || (FdoDeviceExtension->DeviceState == 0))
292 {
293 /* This interrupt isnt for us or not ready for it. */
294 return FALSE;
295 }
296
297 /* Clear status */
298 ClearControllerStatus(hcd, CStatus);
299
300 if (CStatus & EHCI_STS_RECL)
301 {
302 DPRINT("Reclamation\n");
303 }
304
305 if (CStatus & EHCI_ERROR_INT)
306 {
307 DPRINT1("EHCI Status=0x%x\n", CStatus);
308 /* This check added in case the NT USB Driver is still loading.
309 It will cause this error condition at every device connect. */
310 if(CStatus & EHCI_STS_PCD)
311 {
312 DPRINT1("EHCI Error: Another driver may be interfering with proper operation of this driver\n");
313 DPRINT1(" Hint: Ensure that the old NT Usb Driver has been removed!\n");
314 ASSERT(FALSE);
315 }
316 }
317
318 if (CStatus & EHCI_STS_FATAL)
319 {
320 DPRINT1("EHCI: Host System Error. Possible PCI problems.\n");
321 ASSERT(FALSE);
322 }
323
324 if (CStatus & EHCI_STS_HALT)
325 {
326 DPRINT1("EHCI: Host Controller unexpected halt.\n");
327 /* FIXME: Reset the controller */
328 }
329
330 KeInsertQueueDpc(&FdoDeviceExtension->DpcObject, FdoDeviceExtension, (PVOID)CStatus);
331 return TRUE;
332 }
333
334 NTSTATUS
335 StartDevice(PDEVICE_OBJECT DeviceObject, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated)
336 {
337 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
338 PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
339 DEVICE_DESCRIPTION DeviceDescription;
340 PEHCI_HOST_CONTROLLER hcd;
341 ULONG NumberResources;
342 ULONG iCount;
343 ULONG DeviceAddress;
344 ULONG PropertySize;
345 ULONG BusNumber;
346 NTSTATUS Status;
347
348 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
349 hcd = &FdoDeviceExtension->hcd;
350
351 /* Sanity Checks */
352 Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice,
353 DevicePropertyAddress,
354 sizeof(ULONG),
355 &DeviceAddress,
356 &PropertySize);
357
358 Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice,
359 DevicePropertyBusNumber,
360 sizeof(ULONG),
361 &BusNumber,
362 &PropertySize);
363
364
365 /* Get the resources the PNP Manager gave */
366 NumberResources = translated->Count;
367 DPRINT("NumberResources %d\n", NumberResources);
368 for (iCount = 0; iCount < NumberResources; iCount++)
369 {
370 DPRINT("Resource Info %d:\n", iCount);
371 resource = &translated->PartialDescriptors[iCount];
372 switch(resource->Type)
373 {
374 case CmResourceTypePort:
375 {
376 DPRINT("Port Start: %x\n", resource->u.Port.Start);
377 DPRINT("Port Length %d\n", resource->u.Port.Length);
378 /* FIXME: Handle Ports */
379 break;
380 }
381 case CmResourceTypeInterrupt:
382 {
383 DPRINT("Interrupt Vector: %x\n", resource->u.Interrupt.Vector);
384 FdoDeviceExtension->Vector = resource->u.Interrupt.Vector;
385 FdoDeviceExtension->Irql = resource->u.Interrupt.Level;
386 FdoDeviceExtension->Affinity = resource->u.Interrupt.Affinity;
387 FdoDeviceExtension->Mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
388 FdoDeviceExtension->IrqShared = resource->ShareDisposition == CmResourceShareShared;
389 break;
390 }
391 case CmResourceTypeMemory:
392 {
393 PVOID ResourceBase = 0;
394
395 DPRINT("Mem Start: %x\n", resource->u.Memory.Start);
396 DPRINT("Mem Length: %d\n", resource->u.Memory.Length);
397
398 ResourceBase = MmMapIoSpace(resource->u.Memory.Start, resource->u.Memory.Length, FALSE);
399 DPRINT("ResourceBase %x\n", ResourceBase);
400 if (ResourceBase == NULL)
401 {
402 DPRINT1("MmMapIoSpace failed!!!!!!!!!\n");
403 }
404
405 GetCapabilities(&FdoDeviceExtension->hcd.ECHICaps, (ULONG)ResourceBase);
406 DPRINT1("hcd.ECHICaps.Length %x\n", FdoDeviceExtension->hcd.ECHICaps.Length);
407 FdoDeviceExtension->hcd.OpRegisters = (ULONG)((ULONG)ResourceBase + FdoDeviceExtension->hcd.ECHICaps.Length);
408 break;
409 }
410 case CmResourceTypeDma:
411 {
412 DPRINT("Dma Channel: %x\n", resource->u.Dma.Channel);
413 DPRINT("Dma Port: %d\n", resource->u.Dma.Port);
414 break;
415 }
416 case CmResourceTypeDevicePrivate:
417 {
418 /* Windows does this. */
419 DPRINT1("CmResourceTypeDevicePrivate not handled\n");
420 break;
421 }
422 default:
423 {
424 DPRINT1("PNP Manager gave resource type not handled!! Notify Developers!\n");
425 break;
426 }
427 }
428 }
429
430 for (iCount = 0; iCount < hcd->ECHICaps.HCSParams.PortCount; iCount++)
431 {
432 hcd->Ports[iCount].PortStatus = 0x8000;
433 hcd->Ports[iCount].PortChange = 0;
434
435 if (hcd->ECHICaps.HCSParams.PortPowerControl)
436 hcd->Ports[iCount].PortStatus |= USB_PORT_STATUS_POWER;
437 }
438
439 KeInitializeDpc(&FdoDeviceExtension->DpcObject,
440 EhciDefferedRoutine,
441 FdoDeviceExtension);
442
443 RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
444
445 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
446 DeviceDescription.Master = TRUE;
447 DeviceDescription.ScatterGather = TRUE;
448 DeviceDescription.Dma32BitAddresses = TRUE;
449 DeviceDescription.DmaWidth = 2;
450 DeviceDescription.InterfaceType = PCIBus;
451 DeviceDescription.MaximumLength = EHCI_MAX_SIZE_TRANSFER;
452
453 hcd->pDmaAdapter = IoGetDmaAdapter(FdoDeviceExtension->LowerDevice,
454 &DeviceDescription,
455 &hcd->MapRegisters);
456
457 if (hcd->pDmaAdapter == NULL)
458 {
459 DPRINT1("Ehci: IoGetDmaAdapter failed!\n");
460 ASSERT(FALSE);
461 }
462
463 DPRINT1("MapRegisters %x\n", hcd->MapRegisters);
464
465 /* Allocate Common Buffer for Periodic Frame List */
466 FdoDeviceExtension->PeriodicFrameList.VirtualAddr =
467 hcd->pDmaAdapter->DmaOperations->AllocateCommonBuffer(hcd->pDmaAdapter,
468 sizeof(ULONG) * 1024,
469 &FdoDeviceExtension->PeriodicFrameList.PhysicalAddr,
470 FALSE);
471
472 if (FdoDeviceExtension->PeriodicFrameList.VirtualAddr == NULL)
473 {
474 DPRINT1("Ehci: FdoDeviceExtension->PeriodicFramList is null\n");
475 return STATUS_UNSUCCESSFUL;
476 }
477
478 /* Zeroize it */
479 RtlZeroMemory(FdoDeviceExtension->PeriodicFrameList.VirtualAddr, sizeof(ULONG) * 1024);
480
481 ExInitializeFastMutex(&FdoDeviceExtension->FrameListMutex);
482
483 /* Allocate initial page for queueheads and descriptors */
484 FdoDeviceExtension->hcd.CommonBufferVA[0] =
485 hcd->pDmaAdapter->DmaOperations->AllocateCommonBuffer(hcd->pDmaAdapter,
486 PAGE_SIZE,
487 &FdoDeviceExtension->hcd.CommonBufferPA[0],
488 FALSE);
489
490 if (FdoDeviceExtension->hcd.CommonBufferVA[0] == 0)
491 {
492 DPRINT1("Ehci: Failed to allocate common buffer!\n");
493 return STATUS_UNSUCCESSFUL;
494 }
495
496 hcd->CommonBufferSize = PAGE_SIZE * 16;
497
498 /* Zeroize it */
499 RtlZeroMemory(FdoDeviceExtension->hcd.CommonBufferVA[0],
500 PAGE_SIZE);
501
502 /* Init SpinLock for host controller device lock */
503 KeInitializeSpinLock(&hcd->Lock);
504
505 /* Reserved a Queue Head that will always be in the AsyncList Address Register. By setting it as the Head of Reclamation
506 the controller can know when it has reached the end of the QueueHead list */
507 hcd->AsyncListQueue = CreateQueueHead(hcd);
508
509 hcd->AsyncListQueue->HorizontalLinkPointer = hcd->AsyncListQueue->PhysicalAddr | QH_TYPE_QH;
510 hcd->AsyncListQueue->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
511 hcd->AsyncListQueue->Token.Bits.InterruptOnComplete = FALSE;
512 hcd->AsyncListQueue->EndPointCharacteristics.HeadOfReclamation = TRUE;
513 hcd->AsyncListQueue->Token.Bits.Halted = TRUE;
514 hcd->AsyncListQueue->NextQueueHead = hcd->AsyncListQueue;
515 hcd->AsyncListQueue->PreviousQueueHead = hcd->AsyncListQueue;
516
517 /* Reserve a Queue Head thats only purpose is for linking completed Queue Heads.
518 Completed QueueHeads are moved to this temporary. As the memory must still be valid
519 up until the controllers doorbell is rang to let it know info has been removed from QueueHead list */
520 hcd->CompletedListQueue = CreateQueueHead(hcd);
521 hcd->CompletedListQueue->NextQueueHead = hcd->CompletedListQueue;
522 hcd->CompletedListQueue->PreviousQueueHead = hcd->CompletedListQueue;
523
524 /* Ensure the controller is stopped */
525 StopEhci(hcd);
526
527 SetAsyncListQueueRegister(hcd, hcd->AsyncListQueue->PhysicalAddr);
528
529 /* FIXME: Implement Periodic Frame List */
530
531 Status = IoConnectInterrupt(&FdoDeviceExtension->EhciInterrupt,
532 InterruptService,
533 FdoDeviceExtension->DeviceObject,
534 NULL,
535 FdoDeviceExtension->Vector,
536 FdoDeviceExtension->Irql,
537 FdoDeviceExtension->Irql,
538 FdoDeviceExtension->Mode,
539 FdoDeviceExtension->IrqShared,
540 FdoDeviceExtension->Affinity,
541 FALSE);
542
543 StartEhci(hcd);
544 FdoDeviceExtension->DeviceState = DEVICESTARTED;
545 return STATUS_SUCCESS;
546 }
547
548 NTSTATUS
549 FdoQueryBusRelations(
550 PDEVICE_OBJECT DeviceObject,
551 PDEVICE_RELATIONS* pDeviceRelations)
552 {
553 PFDO_DEVICE_EXTENSION DeviceExtension;
554 PDEVICE_RELATIONS DeviceRelations = NULL;
555 PDEVICE_OBJECT Pdo;
556 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
557 NTSTATUS Status;
558 ULONG UsbDeviceNumber = 0;
559 WCHAR CharDeviceName[64];
560
561 UNICODE_STRING DeviceName;
562
563 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
564
565 DPRINT1("Ehci: QueryBusRelations\n");
566
567 /* FIXME: Currently only support for one ehci controller */
568 if (DeviceExtension->Pdo)
569 goto Done;
570
571 /* Create the PDO with the next available number */
572 while (TRUE)
573 {
574 /* FIXME: Use safe string */
575 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBPDO-%d", UsbDeviceNumber); */
576 swprintf(CharDeviceName, L"\\Device\\USBPDO-%d", UsbDeviceNumber);
577 RtlInitUnicodeString(&DeviceName, CharDeviceName);
578 DPRINT("DeviceName %wZ\n", &DeviceName);
579
580 Status = IoCreateDevice(DeviceObject->DriverObject,
581 sizeof(PDO_DEVICE_EXTENSION),
582 &DeviceName,
583 FILE_DEVICE_BUS_EXTENDER,
584 0,
585 FALSE,
586 &Pdo);
587
588 if (NT_SUCCESS(Status))
589 break;
590
591 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
592 {
593 /* Try the next name */
594 UsbDeviceNumber++;
595 continue;
596 }
597
598 /* Bail on any other error */
599 if (!NT_SUCCESS(Status))
600 {
601 DPRINT1("Ehci: Failed to create PDO %wZ, Status %x\n", &DeviceName, Status);
602 return Status;
603 }
604 }
605
606 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
607 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
608 PdoDeviceExtension->Common.IsFdo = FALSE;
609
610 PdoDeviceExtension->ControllerFdo = DeviceObject;
611 PdoDeviceExtension->DeviceObject = Pdo;
612 //PdoDeviceExtension->NumberOfPorts = DeviceExtension->hcd.ECHICaps.HCSParams.PortCount;
613
614 InitializeListHead(&PdoDeviceExtension->IrpQueue);
615
616 KeInitializeSpinLock(&PdoDeviceExtension->IrpQueueLock);
617
618 KeInitializeEvent(&PdoDeviceExtension->QueueDrainedEvent, SynchronizationEvent, TRUE);
619
620 ExInitializeFastMutex(&PdoDeviceExtension->ListLock);
621
622 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
623
624 DeviceExtension->Pdo = Pdo;
625 Done:
626 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
627
628 if (!DeviceRelations)
629 {
630 return STATUS_INSUFFICIENT_RESOURCES;
631 }
632
633 DeviceRelations->Count = 1;
634 DeviceRelations->Objects[0] = DeviceExtension->Pdo;
635 ObReferenceObject(DeviceExtension->Pdo);
636
637 *pDeviceRelations = DeviceRelations;
638 return STATUS_SUCCESS;
639 }
640
641 NTSTATUS NTAPI
642 FdoDispatchPnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
643 {
644 NTSTATUS Status;
645 PIO_STACK_LOCATION Stack = NULL;
646 PCM_PARTIAL_RESOURCE_LIST raw;
647 PCM_PARTIAL_RESOURCE_LIST translated;
648 ULONG_PTR Information = 0;
649
650 Stack = IoGetCurrentIrpStackLocation(Irp);
651
652 switch(Stack->MinorFunction)
653 {
654 case IRP_MN_START_DEVICE:
655 {
656 DPRINT1("Ehci: START_DEVICE\n");
657
658 Irp->IoStatus.Status = STATUS_SUCCESS;
659 Status = ForwardAndWait(DeviceObject, Irp);
660
661 raw = &Stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
662 translated = &Stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
663 Status = StartDevice(DeviceObject, raw, translated);
664 break;
665 }
666 case IRP_MN_QUERY_DEVICE_RELATIONS:
667 {
668 DPRINT1("Ehci: IRP_MN_QUERY_DEVICE_RELATIONS\n");
669 switch(Stack->Parameters.QueryDeviceRelations.Type)
670 {
671 case BusRelations:
672 {
673 PDEVICE_RELATIONS DeviceRelations = NULL;
674 DPRINT1("Ehci: BusRelations\n");
675 Status = FdoQueryBusRelations(DeviceObject, &DeviceRelations);
676 Information = (ULONG_PTR)DeviceRelations;
677 break;
678 }
679 default:
680 {
681 DPRINT1("Ehci: Unknown query device relations type\n");
682 Status = STATUS_NOT_IMPLEMENTED;
683 break;
684 }
685 }
686 break;
687 }
688 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
689 {
690 DPRINT1("Ehci: IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
691 return ForwardIrpAndForget(DeviceObject, Irp);
692 break;
693 }
694 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
695 {
696 DPRINT1("Ehci: IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
697 }
698 case IRP_MN_QUERY_INTERFACE:
699 {
700 DPRINT1("Ehci: IRP_MN_QUERY_INTERFACE\n");
701 Status = STATUS_SUCCESS;
702 Information = 0;
703 Status = ForwardIrpAndForget(DeviceObject, Irp);
704 return Status;
705 break;
706 }
707 default:
708 {
709 DPRINT1("Ehci: IRP_MJ_PNP / Unhandled minor function 0x%lx\n", Stack->MinorFunction);
710 return ForwardIrpAndForget(DeviceObject, Irp);
711 }
712 }
713
714 Irp->IoStatus.Information = Information;
715 Irp->IoStatus.Status = Status;
716 IoCompleteRequest(Irp, IO_NO_INCREMENT);
717 return Status;
718 }
719
720 NTSTATUS NTAPI
721 AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Pdo)
722 {
723 NTSTATUS Status = STATUS_UNSUCCESSFUL;
724 PDEVICE_OBJECT Fdo;
725 ULONG UsbDeviceNumber = 0;
726 WCHAR CharDeviceName[64];
727 WCHAR CharSymLinkName[64];
728 UNICODE_STRING DeviceName;
729 UNICODE_STRING SymLinkName;
730 UNICODE_STRING InterfaceSymLinkName;
731 ULONG BytesRead;
732 PCI_COMMON_CONFIG PciConfig;
733
734 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
735
736 DPRINT1("Ehci: AddDevice\n");
737
738 /* Create the FDO with next available number */
739 while (TRUE)
740 {
741 /* FIXME: Use safe string sprintf*/
742 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBFDO-%d", UsbDeviceNumber); */
743 swprintf(CharDeviceName, L"\\Device\\USBFDO-%d", UsbDeviceNumber);
744 RtlInitUnicodeString(&DeviceName, CharDeviceName);
745 DPRINT("DeviceName %wZ\n", &DeviceName);
746
747 Status = IoCreateDevice(DriverObject,
748 sizeof(FDO_DEVICE_EXTENSION),
749 &DeviceName,
750 FILE_DEVICE_CONTROLLER,
751 0,
752 FALSE,
753 &Fdo);
754
755 if (NT_SUCCESS(Status))
756 break;
757
758 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
759 {
760 /* Try the next name */
761 UsbDeviceNumber++;
762 continue;
763 }
764
765 /* Bail on any other error */
766 if (!NT_SUCCESS(Status))
767 {
768 DPRINT1("UsbEhci: Failed to create %wZ, Status %x\n", &DeviceName, Status);
769 return Status;
770 }
771 }
772
773 swprintf(CharSymLinkName, L"\\Device\\HCD%d", UsbDeviceNumber);
774 RtlInitUnicodeString(&SymLinkName, CharSymLinkName);
775 Status = IoCreateSymbolicLink(&SymLinkName, &DeviceName);
776
777 if (!NT_SUCCESS(Status))
778 {
779 DPRINT1("Warning: Unable to create symbolic link for ehci host controller!\n");
780 }
781
782 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) Fdo->DeviceExtension;
783 RtlZeroMemory(FdoDeviceExtension, sizeof(PFDO_DEVICE_EXTENSION));
784
785 KeInitializeTimerEx(&FdoDeviceExtension->UpdateTimer, SynchronizationTimer);
786
787 FdoDeviceExtension->Common.IsFdo = TRUE;
788 FdoDeviceExtension->DeviceObject = Fdo;
789
790 FdoDeviceExtension->LowerDevice = IoAttachDeviceToDeviceStack(Fdo, Pdo);
791
792 if (FdoDeviceExtension->LowerDevice == NULL)
793 {
794 DPRINT1("UsbEhci: Failed to attach to device stack!\n");
795 IoDeleteSymbolicLink(&SymLinkName);
796 IoDeleteDevice(Fdo);
797
798 return STATUS_NO_SUCH_DEVICE;
799 }
800
801 Fdo->Flags |= DO_BUFFERED_IO;// | DO_POWER_PAGABLE;
802
803 ASSERT(FdoDeviceExtension->LowerDevice == Pdo);
804
805 /* Get the EHCI Device ID and Vendor ID */
806 Status = GetBusInterface(FdoDeviceExtension->LowerDevice, &FdoDeviceExtension->BusInterface);
807
808 if (!NT_SUCCESS(Status))
809 {
810 DPRINT1("GetBusInterface() failed with %x\n", Status);
811 IoDetachDevice(FdoDeviceExtension->LowerDevice);
812 IoDeleteSymbolicLink(&SymLinkName);
813 IoDeleteDevice(Fdo);
814 return Status;
815 }
816
817 BytesRead = (*FdoDeviceExtension->BusInterface.GetBusData)(
818 FdoDeviceExtension->BusInterface.Context,
819 PCI_WHICHSPACE_CONFIG,
820 &PciConfig,
821 0,
822 PCI_COMMON_HDR_LENGTH);
823
824
825 if (BytesRead != PCI_COMMON_HDR_LENGTH)
826 {
827 DPRINT1("GetBusData failed!\n");
828 IoDetachDevice(FdoDeviceExtension->LowerDevice);
829 IoDeleteSymbolicLink(&SymLinkName);
830 IoDeleteDevice(Fdo);
831 return STATUS_UNSUCCESSFUL;
832 }
833
834 if (PciConfig.Command & PCI_ENABLE_IO_SPACE)
835 DPRINT("PCI_ENABLE_IO_SPACE\n");
836
837 if (PciConfig.Command & PCI_ENABLE_MEMORY_SPACE)
838 DPRINT("PCI_ENABLE_MEMORY_SPACE\n");
839
840 if (PciConfig.Command & PCI_ENABLE_BUS_MASTER)
841 DPRINT("PCI_ENABLE_BUS_MASTER\n");
842
843 DPRINT("BaseAddress[0] %x\n", PciConfig.u.type0.BaseAddresses[0]);
844 DPRINT1("Vendor %x\n", PciConfig.VendorID);
845 DPRINT1("Device %x\n", PciConfig.DeviceID);
846
847 FdoDeviceExtension->VendorId = PciConfig.VendorID;
848 FdoDeviceExtension->DeviceId = PciConfig.DeviceID;
849
850 FdoDeviceExtension->DeviceState = DEVICEINTIALIZED;
851
852 Status = IoRegisterDeviceInterface(Pdo, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL, &InterfaceSymLinkName);
853 if (!NT_SUCCESS(Status))
854 {
855 DPRINT1("Unable to register device interface!\n");
856 return Status;
857 }
858 else
859 {
860 Status = IoSetDeviceInterfaceState(&InterfaceSymLinkName, TRUE);
861 DPRINT1("SetInterfaceState %x\n", Status);
862 if (!NT_SUCCESS(Status))
863 return Status;
864 }
865 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
866
867 return STATUS_SUCCESS;
868 }
869
870 NTSTATUS NTAPI
871 FdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
872 {
873 /*FIXME: This should never be called by upper drivers as they should only be dealing with the pdo. */
874 DPRINT1("Upper Level Device Object shouldnt be calling this!!!!!!!!!!!!\n");
875 ASSERT(FALSE);
876 return STATUS_UNSUCCESSFUL;
877 }