[CMAKE]
[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 LONG i;
25
26 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) DeferredContext;
27
28 if (!FdoDeviceExtension->Pdo)
29 {
30 DPRINT1("PDO not set yet!\n");
31 return;
32 }
33
34 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION) FdoDeviceExtension->Pdo->DeviceExtension;
35
36 OpRegisters = (ULONG)FdoDeviceExtension->hcd.OpRegisters;
37
38 hcd = &FdoDeviceExtension->hcd;
39
40 CStatus = (ULONG) SystemArgument2;
41
42
43 /* TD retired or Error */
44 if (CStatus & (EHCI_STS_INT | EHCI_ERROR_INT))
45 {
46 DPRINT("Asyn Complete!\n");
47 ULONG CurrentAddr, OffSet;
48 PQUEUE_HEAD CompletedQH, NextQH;
49 PQUEUE_TRANSFER_DESCRIPTOR CompletedTD, NextTD;
50
51 /* AsyncListAddr Register will have the next QueueHead to execute */
52 CurrentAddr = GetAsyncListQueueRegister(hcd);
53
54 /* Calculate the VA for the next QueueHead */
55 OffSet = CurrentAddr - (ULONG)FdoDeviceExtension->hcd.CommonBufferPA.LowPart;
56 NextQH = (PQUEUE_HEAD)((ULONG)FdoDeviceExtension->hcd.CommonBufferVA + OffSet);
57
58 /* Get the previous QueueHead which is the QueueHead just completed */
59 CompletedQH = NextQH->PreviousQueueHead;
60 ASSERT(CompletedQH);
61 DPRINT("CompletedQH %x\n", CompletedQH);
62
63 //DumpQueueHead(CompletedQH);
64
65 /* Free memory for the Descriptors */
66 CompletedTD = CompletedQH->TransferDescriptor;
67 NextTD = CompletedTD;
68 while (NextTD)
69 {
70 CompletedTD = NextTD;
71 NextTD = NextTD->NextDescriptor;
72 FreeDescriptor(CompletedTD);
73 }
74
75 /* If the Event is set then release waiter */
76 if (CompletedQH->Event)
77 {
78 KeSetEvent(CompletedQH->Event, IO_NO_INCREMENT, FALSE);
79 }
80
81 /* Free the Mdl if there was one */
82 if(CompletedQH->MdlToFree)
83 IoFreeMdl(CompletedQH->MdlToFree);
84
85 /* Is there an IRP that needs to be completed */
86 if (CompletedQH->IrpToComplete)
87 {
88 PIRP Irp;
89 PIO_STACK_LOCATION Stack;
90 PURB Urb;
91
92 Irp = CompletedQH->IrpToComplete;
93 Stack = IoGetCurrentIrpStackLocation(Irp);
94 ASSERT(Stack);
95 Urb = (PURB) Stack->Parameters.Others.Argument1;
96
97 /* Check for error */
98 if (CStatus & EHCI_ERROR_INT)
99 {
100 /* Haled bit should be set */
101 if (CompletedQH->Token.Bits.Halted)
102 {
103 if (CompletedQH->Token.Bits.DataBufferError)
104 {
105 DPRINT1("Data buffer error\n");
106 Urb->UrbHeader.Status = USBD_STATUS_DATA_BUFFER_ERROR;
107 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
108 Irp->IoStatus.Information = 0;
109 }
110 else if (CompletedQH->Token.Bits.BabbleDetected)
111 {
112 DPRINT1("Babble Detected\n");
113 Urb->UrbHeader.Status = USBD_STATUS_BABBLE_DETECTED;
114 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
115 Irp->IoStatus.Information = 0;
116 }
117 else
118 {
119 DPRINT1("Stall PID\n");
120 Urb->UrbHeader.Status = USBD_STATUS_STALL_PID;
121 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
122 Irp->IoStatus.Information = 0;
123 }
124 }
125 }
126 else
127 {
128 Irp->IoStatus.Status = STATUS_SUCCESS;
129 Irp->IoStatus.Information = 0;
130 DPRINT1("Completing Irp\n");
131
132 }
133 IoCompleteRequest(Irp, IO_NO_INCREMENT);
134 }
135
136 /* Unlink QueueHead */
137 UnlinkQueueHead(hcd, CompletedQH);
138 /* Wait for a complete AsnycList tranversal before deleting? */
139 DeleteQueueHead(CompletedQH);
140 }
141
142 /* Port Change */
143 if (CStatus & EHCI_STS_PCD)
144 {
145 /* Loop through the ports */
146 for (i = 0; i < FdoDeviceExtension->hcd.ECHICaps.HCSParams.PortCount; i++)
147 {
148 tmp = READ_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)));
149
150 /* Check for port change on this port */
151 if (tmp & 0x02)
152 {
153 /* Connect or Disconnect? */
154 if (tmp & 0x01)
155 {
156 DPRINT1("Device connected on port %d\n", i);
157
158 /* Check if a companion host controller exists */
159 if (FdoDeviceExtension->hcd.ECHICaps.HCSParams.CHCCount)
160 {
161 tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
162
163 /* Port should be in disabled state, as per USB 2.0 specs */
164 if (tmp & 0x04)
165 {
166 DPRINT1("Warning: The port the device has just connected to is not disabled!\n");
167 }
168
169 /* Is this non high speed device */
170 if (tmp & 0x400)
171 {
172 DPRINT1("Non HighSpeed device connected. Releasing ownership.\n");
173 /* Release ownership to companion host controller */
174 WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)), 0x2000);
175 continue;
176 }
177 }
178
179 KeStallExecutionProcessor(30);
180
181 /* As per USB 2.0 Specs, 9.1.2. Reset the port and clear the status change */
182 //tmp |= 0x100 | 0x02;
183 /* Sanity, Disable port */
184 //tmp &= ~0x04;
185
186 //WRITE_REGISTER_ULONG((PULONG) ((Base + EHCI_PORTSC) + (4 * i)), tmp);
187
188 //KeStallExecutionProcessor(20);
189
190 tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
191
192 PdoDeviceExtension->ChildDeviceCount++;
193 PdoDeviceExtension->Ports[i].PortStatus &= ~0x8000;
194 PdoDeviceExtension->Ports[i].PortStatus |= USB_PORT_STATUS_HIGH_SPEED;
195 PdoDeviceExtension->Ports[i].PortStatus |= USB_PORT_STATUS_CONNECT;
196 PdoDeviceExtension->Ports[i].PortChange |= USB_PORT_STATUS_CONNECT;
197 DPRINT1("Completing URB\n");
198 CompletePendingURBRequest(PdoDeviceExtension);
199 }
200 else
201 {
202 DPRINT1("Device disconnected on port %d\n", i);
203
204 /* Clear status change */
205 tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
206 tmp |= 0x02;
207 WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)), tmp);
208 }
209 }
210 }
211 }
212
213 /* Asnyc Advance */
214 if (CStatus & EHCI_STS_IAA)
215 {
216 DPRINT1("Async Advance!\n");
217 }
218 }
219
220 BOOLEAN NTAPI
221 InterruptService(PKINTERRUPT Interrupt, PVOID ServiceContext)
222 {
223 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
224 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT) ServiceContext;
225 PEHCI_HOST_CONTROLLER hcd;
226 ULONG CStatus = 0;
227
228 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
229
230 hcd = &FdoDeviceExtension->hcd;
231
232 /* Read device status */
233 CStatus = ReadControllerStatus(hcd);
234
235 CStatus &= (EHCI_ERROR_INT | EHCI_STS_INT | EHCI_STS_IAA | EHCI_STS_PCD | EHCI_STS_FLR);
236
237 if ((!CStatus) || (FdoDeviceExtension->DeviceState == 0))
238 {
239 /* This interrupt isnt for us or not ready for it. */
240 return FALSE;
241 }
242
243 /* Clear status */
244 ClearControllerStatus(hcd, CStatus);
245
246 if (CStatus & EHCI_ERROR_INT)
247 {
248 DPRINT1("EHCI Status=0x%x\n", CStatus);
249 }
250
251 if (CStatus & EHCI_STS_FATAL)
252 {
253 DPRINT1("EHCI: Host System Error. Possible PCI problems.\n");
254 ASSERT(FALSE);
255 }
256
257 if (CStatus & EHCI_STS_HALT)
258 {
259 DPRINT1("EHCI: Host Controller unexpected halt.\n");
260 /* FIXME: Reset the controller */
261 }
262
263 KeInsertQueueDpc(&FdoDeviceExtension->DpcObject, FdoDeviceExtension, (PVOID)CStatus);
264 return TRUE;
265 }
266
267 NTSTATUS
268 StartDevice(PDEVICE_OBJECT DeviceObject, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated)
269 {
270 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
271 PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
272 DEVICE_DESCRIPTION DeviceDescription;
273 ULONG NumberResources;
274 ULONG iCount;
275 ULONG DeviceAddress;
276 ULONG PropertySize;
277 ULONG BusNumber;
278 NTSTATUS Status;
279
280 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
281
282 Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice,
283 DevicePropertyAddress,
284 sizeof(ULONG),
285 &DeviceAddress,
286 &PropertySize);
287 if (NT_SUCCESS(Status))
288 {
289 DPRINT1("--->DeviceAddress: %x\n", DeviceAddress);
290 }
291
292 Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice,
293 DevicePropertyBusNumber,
294 sizeof(ULONG),
295 &BusNumber,
296 &PropertySize);
297 if (NT_SUCCESS(Status))
298 {
299 DPRINT1("--->BusNumber: %x\n", BusNumber);
300 }
301
302 /* Get the resources the PNP Manager gave */
303 NumberResources = translated->Count;
304 DPRINT("NumberResources %d\n", NumberResources);
305 for (iCount = 0; iCount < NumberResources; iCount++)
306 {
307 DPRINT("Resource Info %d:\n", iCount);
308 resource = &translated->PartialDescriptors[iCount];
309 switch(resource->Type)
310 {
311 case CmResourceTypePort:
312 {
313 DPRINT("Port Start: %x\n", resource->u.Port.Start);
314 DPRINT("Port Length %d\n", resource->u.Port.Length);
315 /* FIXME: Handle Ports */
316 break;
317 }
318 case CmResourceTypeInterrupt:
319 {
320 DPRINT("Interrupt Vector: %x\n", resource->u.Interrupt.Vector);
321 FdoDeviceExtension->Vector = resource->u.Interrupt.Vector;
322 FdoDeviceExtension->Irql = resource->u.Interrupt.Level;
323 FdoDeviceExtension->Affinity = resource->u.Interrupt.Affinity;
324 FdoDeviceExtension->Mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
325 FdoDeviceExtension->IrqShared = resource->ShareDisposition == CmResourceShareShared;
326 break;
327 }
328 case CmResourceTypeMemory:
329 {
330 PVOID ResourceBase = 0;
331
332 DPRINT("Mem Start: %x\n", resource->u.Memory.Start);
333 DPRINT("Mem Length: %d\n", resource->u.Memory.Length);
334
335 ResourceBase = MmMapIoSpace(resource->u.Memory.Start, resource->u.Memory.Length, FALSE);
336 DPRINT("ResourceBase %x\n", ResourceBase);
337 if (ResourceBase == NULL)
338 {
339 DPRINT1("MmMapIoSpace failed!!!!!!!!!\n");
340 }
341
342 GetCapabilities(&FdoDeviceExtension->hcd.ECHICaps, (ULONG)ResourceBase);
343 DPRINT1("hcd.ECHICaps.Length %x\n", FdoDeviceExtension->hcd.ECHICaps.Length);
344 FdoDeviceExtension->hcd.OpRegisters = (ULONG)((ULONG)ResourceBase + FdoDeviceExtension->hcd.ECHICaps.Length);
345 break;
346 }
347 case CmResourceTypeDma:
348 {
349 DPRINT("Dma Channel: %x\n", resource->u.Dma.Channel);
350 DPRINT("Dma Port: %d\n", resource->u.Dma.Port);
351 break;
352 }
353 case CmResourceTypeDevicePrivate:
354 {
355 /* Windows does this. */
356 DPRINT1("CmResourceTypeDevicePrivate not handled\n");
357 break;
358 }
359 default:
360 {
361 DPRINT1("PNP Manager gave resource type not handled!! Notify Developers!\n");
362 break;
363 }
364 }
365 }
366
367 KeInitializeDpc(&FdoDeviceExtension->DpcObject,
368 EhciDefferedRoutine,
369 FdoDeviceExtension);
370
371 RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
372 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
373 DeviceDescription.Master = TRUE;
374 DeviceDescription.ScatterGather = TRUE;
375 DeviceDescription.Dma32BitAddresses = TRUE;
376 DeviceDescription.DmaWidth = 2;
377 DeviceDescription.InterfaceType = PCIBus;
378 DeviceDescription.MaximumLength = EHCI_MAX_SIZE_TRANSFER;
379
380 FdoDeviceExtension->pDmaAdapter = IoGetDmaAdapter(FdoDeviceExtension->LowerDevice,
381 &DeviceDescription,
382 &FdoDeviceExtension->MapRegisters);
383
384 if (FdoDeviceExtension->pDmaAdapter == NULL)
385 {
386 DPRINT1("Ehci: IoGetDmaAdapter failed!\n");
387 ASSERT(FALSE);
388 }
389
390 /* Allocate Common Buffer for Periodic Frame List */
391 FdoDeviceExtension->PeriodicFrameList.VirtualAddr =
392 FdoDeviceExtension->pDmaAdapter->DmaOperations->AllocateCommonBuffer(FdoDeviceExtension->pDmaAdapter,
393 sizeof(ULONG) * 1024, &FdoDeviceExtension->PeriodicFrameList.PhysicalAddr, FALSE);
394
395 if (FdoDeviceExtension->PeriodicFrameList.VirtualAddr == NULL)
396 {
397 DPRINT1("Ehci: FdoDeviceExtension->PeriodicFramList is null\n");
398 return STATUS_UNSUCCESSFUL;
399 }
400
401 /* Zeroize it */
402 RtlZeroMemory(FdoDeviceExtension->PeriodicFrameList.VirtualAddr, sizeof(ULONG) * 1024);
403
404 ExInitializeFastMutex(&FdoDeviceExtension->FrameListMutex);
405
406 /* Allocate pages for queueheads and descriptors */
407 FdoDeviceExtension->hcd.CommonBufferVA =
408 FdoDeviceExtension->pDmaAdapter->DmaOperations->AllocateCommonBuffer(FdoDeviceExtension->pDmaAdapter,
409 PAGE_SIZE * 16,
410 &FdoDeviceExtension->hcd.CommonBufferPA,
411 FALSE);
412
413 if (FdoDeviceExtension->hcd.CommonBufferVA == 0)
414 {
415 DPRINT1("Ehci: Failed to allocate common buffer!\n");
416 return STATUS_UNSUCCESSFUL;
417 }
418
419 FdoDeviceExtension->hcd.CommonBufferSize = PAGE_SIZE * 16;
420
421 /* Zeroize it */
422 RtlZeroMemory(FdoDeviceExtension->hcd.CommonBufferVA,
423 PAGE_SIZE * 16);
424
425 /* Init SpinLock for host controller device lock */
426 KeInitializeSpinLock(&FdoDeviceExtension->hcd.Lock);
427
428 /* Reserved a Queue Head that will always be in the AsyncList Address Register */
429 FdoDeviceExtension->hcd.AsyncListQueue = CreateQueueHead(&FdoDeviceExtension->hcd);
430 FdoDeviceExtension->hcd.AsyncListQueue->HorizontalLinkPointer = FdoDeviceExtension->hcd.AsyncListQueue->PhysicalAddr | QH_TYPE_QH;
431 FdoDeviceExtension->hcd.AsyncListQueue->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
432 FdoDeviceExtension->hcd.AsyncListQueue->Token.Bits.InterruptOnComplete = FALSE;
433
434 /* Ensure the controller is stopped */
435 StopEhci(&FdoDeviceExtension->hcd);
436
437 Status = IoConnectInterrupt(&FdoDeviceExtension->EhciInterrupt,
438 InterruptService,
439 FdoDeviceExtension->DeviceObject,
440 NULL,
441 FdoDeviceExtension->Vector,
442 FdoDeviceExtension->Irql,
443 FdoDeviceExtension->Irql,
444 FdoDeviceExtension->Mode,
445 FdoDeviceExtension->IrqShared,
446 FdoDeviceExtension->Affinity,
447 FALSE);
448
449 StartEhci(&FdoDeviceExtension->hcd);
450 DPRINT1("AsycnAddr %x\n", GetAsyncListQueueRegister(&FdoDeviceExtension->hcd));
451 FdoDeviceExtension->DeviceState = DEVICESTARTED;
452
453 return STATUS_SUCCESS;
454 }
455
456 NTSTATUS
457 FdoQueryBusRelations(
458 PDEVICE_OBJECT DeviceObject,
459 PDEVICE_RELATIONS* pDeviceRelations)
460 {
461 PFDO_DEVICE_EXTENSION DeviceExtension;
462 PDEVICE_RELATIONS DeviceRelations = NULL;
463 PDEVICE_OBJECT Pdo;
464 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
465 NTSTATUS Status;
466 ULONG UsbDeviceNumber = 0;
467 WCHAR CharDeviceName[64];
468
469 UNICODE_STRING DeviceName;
470
471 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
472
473 DPRINT1("Ehci: QueryBusRelations\n");
474
475 /* Create the PDO with the next available number */
476 while (TRUE)
477 {
478 /* FIXME: Use safe string */
479 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBPDO-%d", UsbDeviceNumber); */
480 swprintf(CharDeviceName, L"\\Device\\USBPDO-%d", UsbDeviceNumber);
481 RtlInitUnicodeString(&DeviceName, CharDeviceName);
482 DPRINT("DeviceName %wZ\n", &DeviceName);
483
484 Status = IoCreateDevice(DeviceObject->DriverObject,
485 sizeof(PDO_DEVICE_EXTENSION),
486 &DeviceName,
487 FILE_DEVICE_BUS_EXTENDER,
488 0,
489 FALSE,
490 &Pdo);
491
492 if (NT_SUCCESS(Status))
493 break;
494
495 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
496 {
497 /* Try the next name */
498 UsbDeviceNumber++;
499 continue;
500 }
501
502 /* Bail on any other error */
503 if (!NT_SUCCESS(Status))
504 {
505 DPRINT1("Ehci: Failed to create PDO %wZ, Status %x\n", &DeviceName, Status);
506 return Status;
507 }
508 }
509
510 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
511 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
512 PdoDeviceExtension->Common.IsFdo = FALSE;
513
514 PdoDeviceExtension->ControllerFdo = DeviceObject;
515 PdoDeviceExtension->DeviceObject = Pdo;
516 PdoDeviceExtension->NumberOfPorts = DeviceExtension->hcd.ECHICaps.HCSParams.PortCount;
517
518 InitializeListHead(&PdoDeviceExtension->IrpQueue);
519 KeInitializeSpinLock(&PdoDeviceExtension->IrpQueueLock);
520
521 KeInitializeEvent(&PdoDeviceExtension->QueueDrainedEvent, SynchronizationEvent, TRUE);
522
523 ExInitializeFastMutex(&PdoDeviceExtension->ListLock);
524
525 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
526
527 DeviceExtension->Pdo = Pdo;
528
529 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
530
531 if (!DeviceRelations)
532 {
533 return STATUS_INSUFFICIENT_RESOURCES;
534 }
535
536 DeviceRelations->Count = 1;
537 DeviceRelations->Objects[0] = Pdo;
538 ObReferenceObject(Pdo);
539
540 *pDeviceRelations = DeviceRelations;
541 return STATUS_SUCCESS;
542 }
543
544 NTSTATUS NTAPI
545 FdoDispatchPnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
546 {
547 NTSTATUS Status;
548 PIO_STACK_LOCATION Stack = NULL;
549 PCM_PARTIAL_RESOURCE_LIST raw;
550 PCM_PARTIAL_RESOURCE_LIST translated;
551 ULONG_PTR Information = 0;
552
553 Stack = IoGetCurrentIrpStackLocation(Irp);
554
555 switch(Stack->MinorFunction)
556 {
557 case IRP_MN_START_DEVICE:
558 {
559 DPRINT1("Ehci: START_DEVICE\n");
560
561 Irp->IoStatus.Status = STATUS_SUCCESS;
562 Status = ForwardAndWait(DeviceObject, Irp);
563
564 raw = &Stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
565 translated = &Stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
566 Status = StartDevice(DeviceObject, raw, translated);
567 break;
568 }
569 case IRP_MN_QUERY_DEVICE_RELATIONS:
570 {
571 DPRINT1("Ehci: IRP_MN_QUERY_DEVICE_RELATIONS\n");
572 switch(Stack->Parameters.QueryDeviceRelations.Type)
573 {
574 case BusRelations:
575 {
576 PDEVICE_RELATIONS DeviceRelations = NULL;
577 DPRINT1("Ehci: BusRelations\n");
578 Status = FdoQueryBusRelations(DeviceObject, &DeviceRelations);
579 Information = (ULONG_PTR)DeviceRelations;
580 break;
581 }
582 default:
583 {
584 DPRINT1("Ehci: Unknown query device relations type\n");
585 Status = STATUS_NOT_IMPLEMENTED;
586 break;
587 }
588 }
589 break;
590 }
591 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
592 {
593 DPRINT1("Ehci: IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
594 return ForwardIrpAndForget(DeviceObject, Irp);
595 break;
596 }
597 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
598 {
599 DPRINT1("Ehci: IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
600 }
601 case IRP_MN_QUERY_INTERFACE:
602 {
603 DPRINT1("Ehci: IRP_MN_QUERY_INTERFACE\n");
604 Status = STATUS_SUCCESS;
605 Information = 0;
606 Status = ForwardIrpAndForget(DeviceObject, Irp);
607 return Status;
608 break;
609 }
610 default:
611 {
612 DPRINT1("Ehci: IRP_MJ_PNP / Unhandled minor function 0x%lx\n", Stack->MinorFunction);
613 return ForwardIrpAndForget(DeviceObject, Irp);
614 }
615 }
616
617 Irp->IoStatus.Information = Information;
618 Irp->IoStatus.Status = Status;
619 IoCompleteRequest(Irp, IO_NO_INCREMENT);
620 return Status;
621 }
622
623 NTSTATUS NTAPI
624 AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Pdo)
625 {
626 NTSTATUS Status = STATUS_UNSUCCESSFUL;
627 PDEVICE_OBJECT Fdo;
628 ULONG UsbDeviceNumber = 0;
629 WCHAR CharDeviceName[64];
630 WCHAR CharSymLinkName[64];
631 UNICODE_STRING DeviceName;
632 UNICODE_STRING SymLinkName;
633 UNICODE_STRING InterfaceSymLinkName;
634 ULONG BytesRead;
635 PCI_COMMON_CONFIG PciConfig;
636
637 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
638
639 DPRINT1("Ehci: AddDevice\n");
640
641 /* Create the FDO with next available number */
642 while (TRUE)
643 {
644 /* FIXME: Use safe string sprintf*/
645 /* RtlStringCchPrintfW(CharDeviceName, 64, L"USBFDO-%d", UsbDeviceNumber); */
646 swprintf(CharDeviceName, L"\\Device\\USBFDO-%d", UsbDeviceNumber);
647 RtlInitUnicodeString(&DeviceName, CharDeviceName);
648 DPRINT("DeviceName %wZ\n", &DeviceName);
649
650 Status = IoCreateDevice(DriverObject,
651 sizeof(FDO_DEVICE_EXTENSION),
652 &DeviceName,
653 FILE_DEVICE_CONTROLLER,
654 0,
655 FALSE,
656 &Fdo);
657
658 if (NT_SUCCESS(Status))
659 break;
660
661 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
662 {
663 /* Try the next name */
664 UsbDeviceNumber++;
665 continue;
666 }
667
668 /* Bail on any other error */
669 if (!NT_SUCCESS(Status))
670 {
671 DPRINT1("UsbEhci: Failed to create %wZ, Status %x\n", &DeviceName, Status);
672 return Status;
673 }
674 }
675
676 swprintf(CharSymLinkName, L"\\Device\\HCD%d", UsbDeviceNumber);
677 RtlInitUnicodeString(&SymLinkName, CharSymLinkName);
678 Status = IoCreateSymbolicLink(&SymLinkName, &DeviceName);
679
680 if (!NT_SUCCESS(Status))
681 {
682 DPRINT1("Warning: Unable to create symbolic link for ehci host controller!\n");
683 }
684
685 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) Fdo->DeviceExtension;
686 RtlZeroMemory(FdoDeviceExtension, sizeof(PFDO_DEVICE_EXTENSION));
687
688 KeInitializeTimerEx(&FdoDeviceExtension->UpdateTimer, SynchronizationTimer);
689
690 FdoDeviceExtension->Common.IsFdo = TRUE;
691 FdoDeviceExtension->DeviceObject = Fdo;
692
693 FdoDeviceExtension->LowerDevice = IoAttachDeviceToDeviceStack(Fdo, Pdo);
694
695 if (FdoDeviceExtension->LowerDevice == NULL)
696 {
697 DPRINT1("UsbEhci: Failed to attach to device stack!\n");
698 IoDeleteSymbolicLink(&SymLinkName);
699 IoDeleteDevice(Fdo);
700
701 return STATUS_NO_SUCH_DEVICE;
702 }
703
704 Fdo->Flags |= DO_BUFFERED_IO;// | DO_POWER_PAGABLE;
705
706 ASSERT(FdoDeviceExtension->LowerDevice == Pdo);
707
708 Status = GetBusInterface(FdoDeviceExtension->LowerDevice, &FdoDeviceExtension->BusInterface);
709
710 if (!NT_SUCCESS(Status))
711 {
712 DPRINT1("GetBusInterface() failed with %x\n", Status);
713 IoDetachDevice(FdoDeviceExtension->LowerDevice);
714 IoDeleteSymbolicLink(&SymLinkName);
715 IoDeleteDevice(Fdo);
716 return Status;
717 }
718
719 BytesRead = (*FdoDeviceExtension->BusInterface.GetBusData)(
720 FdoDeviceExtension->BusInterface.Context,
721 PCI_WHICHSPACE_CONFIG,
722 &PciConfig,
723 0,
724 PCI_COMMON_HDR_LENGTH);
725
726
727 if (BytesRead != PCI_COMMON_HDR_LENGTH)
728 {
729 DPRINT1("GetBusData failed!\n");
730 IoDetachDevice(FdoDeviceExtension->LowerDevice);
731 IoDeleteSymbolicLink(&SymLinkName);
732 IoDeleteDevice(Fdo);
733 return STATUS_UNSUCCESSFUL;
734 }
735
736 if (PciConfig.Command & PCI_ENABLE_IO_SPACE)
737 DPRINT("PCI_ENABLE_IO_SPACE\n");
738
739 if (PciConfig.Command & PCI_ENABLE_MEMORY_SPACE)
740 DPRINT("PCI_ENABLE_MEMORY_SPACE\n");
741
742 if (PciConfig.Command & PCI_ENABLE_BUS_MASTER)
743 DPRINT("PCI_ENABLE_BUS_MASTER\n");
744
745 DPRINT("BaseAddress[0] %x\n", PciConfig.u.type0.BaseAddresses[0]);
746 DPRINT1("Vendor %x\n", PciConfig.VendorID);
747 DPRINT1("Device %x\n", PciConfig.DeviceID);
748
749 FdoDeviceExtension->VendorId = PciConfig.VendorID;
750 FdoDeviceExtension->DeviceId = PciConfig.DeviceID;
751
752 FdoDeviceExtension->DeviceState = DEVICEINTIALIZED;
753
754 Status = IoRegisterDeviceInterface(Pdo, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL, &InterfaceSymLinkName);
755 if (!NT_SUCCESS(Status))
756 {
757 DPRINT1("Unable to register device interface!\n");
758 return Status;
759 }
760 else
761 {
762 Status = IoSetDeviceInterfaceState(&InterfaceSymLinkName, TRUE);
763 DPRINT1("SetInterfaceState %x\n", Status);
764 if (!NT_SUCCESS(Status))
765 return Status;
766 }
767 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
768
769 return STATUS_SUCCESS;
770 }
771
772 NTSTATUS NTAPI
773 FdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
774 {
775 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
776 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
777 PIO_STACK_LOCATION Stack = NULL;
778 NTSTATUS Status = STATUS_UNSUCCESSFUL;
779 ULONG_PTR Information = 0;
780 PUSB_DEVICE UsbDevice = NULL;
781 URB *Urb;
782
783 /*FIXME: This should never be called by upper drivers as they should only be dealing with the pdo */
784
785 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
786 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION) FdoDeviceExtension->Pdo->DeviceExtension;
787
788 ASSERT(FdoDeviceExtension->Common.IsFdo == TRUE);
789
790 Stack = IoGetCurrentIrpStackLocation(Irp);
791
792 ASSERT(Stack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB);
793
794 Urb = (PURB) Stack->Parameters.Others.Argument1;
795 DPRINT("Header Length %d\n", Urb->UrbHeader.Length);
796 DPRINT("Header Function %d\n", Urb->UrbHeader.Function);
797
798 UsbDevice = DeviceHandleToUsbDevice(PdoDeviceExtension, Urb->UrbHeader.UsbdDeviceHandle);
799
800 if (!UsbDevice)
801 {
802 DPRINT1("Ehci: Invalid DeviceHandle or device not connected\n");
803 return STATUS_DEVICE_NOT_CONNECTED;
804 }
805 switch (Urb->UrbHeader.Function)
806 {
807 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
808 {
809 DPRINT1("Ehci: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:\n");
810 break;
811 }
812 case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
813 {
814 DPRINT1("Ehci: URB_FUNCTION_GET_STATUS_FROM_DEVICE\n");
815 break;
816 }
817 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
818 {
819 DPRINT1("Ehci: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n");
820 switch(Urb->UrbControlDescriptorRequest.DescriptorType)
821 {
822 case USB_DEVICE_DESCRIPTOR_TYPE:
823 {
824 DPRINT1("USB DEVICE DESC\n");
825 break;
826 }
827 case USB_CONFIGURATION_DESCRIPTOR_TYPE:
828 DPRINT1("USB CONFIG DESC\n");
829 //break;
830 case USB_STRING_DESCRIPTOR_TYPE:
831 {
832 DPRINT1("Usb String Descriptor\n");
833 break;
834 }
835 default:
836 {
837 DPRINT1("Ehci: Descriptor Type %x not supported!\n", Urb->UrbControlDescriptorRequest.DescriptorType);
838 }
839 }
840 break;
841 }
842 case URB_FUNCTION_SELECT_CONFIGURATION:
843 {
844 DPRINT1("Ehci: URB_FUNCTION_SELECT_CONFIGURATION\n");
845 DPRINT1("Urb->UrbSelectConfiguration.ConfigurationHandle %x\n",Urb->UrbSelectConfiguration.ConfigurationHandle);
846 break;
847 }
848 case URB_FUNCTION_CLASS_DEVICE:
849 {
850 DPRINT1("Ehci: URB_FUNCTION_CLASS_DEVICE %x\n",Urb->UrbControlVendorClassRequest.Request);
851 switch (Urb->UrbControlVendorClassRequest.Request)
852 {
853 case USB_REQUEST_GET_DESCRIPTOR:
854 {
855 DPRINT1("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags);
856 DPRINT1("Urb->UrbControlVendorClassRequest.Value %x\n", Urb->UrbControlVendorClassRequest.Value);
857
858 switch (Urb->UrbControlVendorClassRequest.Value >> 8)
859 {
860 case USB_DEVICE_CLASS_AUDIO:
861 {
862 DPRINT1("USB_DEVICE_CLASS_AUDIO\n");
863 break;
864 }
865 case USB_DEVICE_CLASS_COMMUNICATIONS:
866 {
867 DPRINT1("USB_DEVICE_CLASS_COMMUNICATIONS\n");
868 break;
869 }
870 case USB_DEVICE_CLASS_HUMAN_INTERFACE:
871 {
872 DPRINT1("USB_DEVICE_CLASS_HUMAN_INTERFACE\n");
873 break;
874 }
875 case USB_DEVICE_CLASS_MONITOR:
876 {
877 DPRINT1("USB_DEVICE_CLASS_MONITOR\n");
878 break;
879 }
880 case USB_DEVICE_CLASS_PHYSICAL_INTERFACE:
881 {
882 DPRINT1("USB_DEVICE_CLASS_PHYSICAL_INTERFACE\n");
883 break;
884 }
885 case USB_DEVICE_CLASS_POWER:
886 {
887 DPRINT1("USB_DEVICE_CLASS_POWER\n");
888 break;
889 }
890 case USB_DEVICE_CLASS_PRINTER:
891 {
892 DPRINT1("USB_DEVICE_CLASS_PRINTER\n");
893 break;
894 }
895 case USB_DEVICE_CLASS_STORAGE:
896 {
897 DPRINT1("USB_DEVICE_CLASS_STORAGE\n");
898 break;
899 }
900 case USB_DEVICE_CLASS_RESERVED:
901 DPRINT1("Reserved!!!\n");
902 case USB_DEVICE_CLASS_HUB:
903 {
904 DPRINT1("USB_DEVICE_CLASS_HUB request\n");
905 break;
906 }
907 default:
908 {
909 DPRINT1("Unknown UrbControlVendorClassRequest Value\n");
910 }
911 }
912 break;
913 }
914 case USB_REQUEST_GET_STATUS:
915 {
916 DPRINT1("DEVICE: USB_REQUEST_GET_STATUS for port %d\n", Urb->UrbControlVendorClassRequest.Index);
917 break;
918 }
919 default:
920 {
921 DPRINT1("Unhandled URB request for class device\n");
922 //Urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
923 }
924 }
925 break;
926 }
927 case URB_FUNCTION_CLASS_OTHER:
928 {
929 DPRINT1("Ehci: URB_FUNCTION_CLASS_OTHER\n");
930 switch (Urb->UrbControlVendorClassRequest.Request)
931 {
932 case USB_REQUEST_GET_STATUS:
933 {
934 DPRINT1("OTHER: USB_REQUEST_GET_STATUS for port %d\n", Urb->UrbControlVendorClassRequest.Index);
935 break;
936 }
937 case USB_REQUEST_CLEAR_FEATURE:
938 {
939 DPRINT1("USB_REQUEST_CLEAR_FEATURE Port %d, value %x\n", Urb->UrbControlVendorClassRequest.Index,
940 Urb->UrbControlVendorClassRequest.Value);
941 switch (Urb->UrbControlVendorClassRequest.Value)
942 {
943 case C_PORT_CONNECTION:
944 DPRINT1("Clearing Connect\n");
945 break;
946 case C_PORT_RESET:
947 DPRINT1("Clearing Reset\n");
948 break;
949 default:
950 DPRINT1("Unknown Value for Clear Feature %x \n", Urb->UrbControlVendorClassRequest.Value);
951 break;
952 }
953 break;
954 }
955 case USB_REQUEST_SET_FEATURE:
956 {
957 DPRINT1("USB_REQUEST_SET_FEATURE Port %d, value %x\n", Urb->UrbControlVendorClassRequest.Index,
958 Urb->UrbControlVendorClassRequest.Value);
959
960 switch(Urb->UrbControlVendorClassRequest.Value)
961 {
962 case PORT_RESET:
963 {
964 DPRINT1("Port reset\n");
965 break;
966 }
967 case PORT_ENABLE:
968 {
969 DPRINT1("Unhandled Set Feature\n");
970 break;
971 }
972 default:
973 {
974 DPRINT1("Unknown Set Feature!\n");
975 break;
976 }
977 }
978 break;
979 }
980 case USB_REQUEST_SET_ADDRESS:
981 {
982 DPRINT1("USB_REQUEST_SET_ADDRESS\n");
983 break;
984 }
985 case USB_REQUEST_GET_DESCRIPTOR:
986 {
987 DPRINT1("USB_REQUEST_GET_DESCRIPTOR\n");
988 break;
989 }
990 case USB_REQUEST_SET_DESCRIPTOR:
991 {
992 DPRINT1("USB_REQUEST_SET_DESCRIPTOR\n");
993 break;
994 }
995 case USB_REQUEST_GET_CONFIGURATION:
996 {
997 DPRINT1("USB_REQUEST_GET_CONFIGURATION\n");
998 break;
999 }
1000 case USB_REQUEST_SET_CONFIGURATION:
1001 {
1002 DPRINT1("USB_REQUEST_SET_CONFIGURATION\n");
1003 break;
1004 }
1005 case USB_REQUEST_GET_INTERFACE:
1006 {
1007 DPRINT1("USB_REQUEST_GET_INTERFACE\n");
1008 break;
1009 }
1010 case USB_REQUEST_SET_INTERFACE:
1011 {
1012 DPRINT1("USB_REQUEST_SET_INTERFACE\n");
1013 break;
1014 }
1015 case USB_REQUEST_SYNC_FRAME:
1016 {
1017 DPRINT1("USB_REQUEST_SYNC_FRAME\n");
1018 break;
1019 }
1020 default:
1021 {
1022 DPRINT1("Unknown Function Class Unknown request\n");
1023 break;
1024 }
1025 }
1026 break;
1027 }
1028 default:
1029 {
1030 DPRINT1("Ehci: Unhandled URB %x\n", Urb->UrbHeader.Function);
1031 //Urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
1032 }
1033 }
1034
1035 Irp->IoStatus.Information = Information;
1036
1037 if (Status != STATUS_PENDING)
1038 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1039
1040 return Status;
1041 }