IRP_MN_START_DEVICE implement for ROOT FDO (PciFdoStartDevice)
[reactos.git] / reactos / drivers / bus / pcix / fdo.c
1 /*
2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/fdo.c
5 * PURPOSE: FDO Device Management
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <pci.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 SINGLE_LIST_ENTRY PciFdoExtensionListHead;
18 BOOLEAN PciBreakOnDefault;
19
20 PCI_MN_DISPATCH_TABLE PciFdoDispatchPowerTable[] =
21 {
22 {IRP_DISPATCH, PciFdoWaitWake},
23 {IRP_DOWNWARD, PciIrpNotSupported},
24 {IRP_DOWNWARD, PciFdoSetPowerState},
25 {IRP_DOWNWARD, PciFdoIrpQueryPower},
26 {IRP_DOWNWARD, PciIrpNotSupported}
27 };
28
29 PCI_MN_DISPATCH_TABLE PciFdoDispatchPnpTable[] =
30 {
31 {IRP_UPWARD, PciFdoIrpStartDevice},
32 {IRP_DOWNWARD, PciFdoIrpQueryRemoveDevice},
33 {IRP_DISPATCH, PciFdoIrpRemoveDevice},
34 {IRP_DOWNWARD, PciFdoIrpCancelRemoveDevice},
35 {IRP_DOWNWARD, PciFdoIrpStopDevice},
36 {IRP_DOWNWARD, PciFdoIrpQueryStopDevice},
37 {IRP_DOWNWARD, PciFdoIrpCancelStopDevice},
38 {IRP_DOWNWARD, PciFdoIrpQueryDeviceRelations},
39 {IRP_DISPATCH, PciFdoIrpQueryInterface},
40 {IRP_UPWARD, PciFdoIrpQueryCapabilities},
41 {IRP_DOWNWARD, PciIrpNotSupported},
42 {IRP_DOWNWARD, PciIrpNotSupported},
43 {IRP_DOWNWARD, PciIrpNotSupported},
44 {IRP_DOWNWARD, PciIrpNotSupported},
45 {IRP_DOWNWARD, PciIrpNotSupported},
46 {IRP_DOWNWARD, PciIrpNotSupported},
47 {IRP_DOWNWARD, PciIrpNotSupported},
48 {IRP_DOWNWARD, PciIrpNotSupported},
49 {IRP_DOWNWARD, PciIrpNotSupported},
50 {IRP_DOWNWARD, PciIrpNotSupported},
51 {IRP_DOWNWARD, PciIrpNotSupported},
52 {IRP_DOWNWARD, PciIrpNotSupported},
53 {IRP_UPWARD, PciFdoIrpDeviceUsageNotification},
54 {IRP_DOWNWARD, PciFdoIrpSurpriseRemoval},
55 {IRP_DOWNWARD, PciFdoIrpQueryLegacyBusInformation},
56 {IRP_DOWNWARD, PciIrpNotSupported}
57 };
58
59 PCI_MJ_DISPATCH_TABLE PciFdoDispatchTable =
60 {
61 IRP_MN_QUERY_LEGACY_BUS_INFORMATION,
62 PciFdoDispatchPnpTable,
63 IRP_MN_QUERY_POWER,
64 PciFdoDispatchPowerTable,
65 IRP_DOWNWARD,
66 PciIrpNotSupported,
67 IRP_DOWNWARD,
68 PciIrpNotSupported
69 };
70
71 /* FUNCTIONS ******************************************************************/
72
73 NTSTATUS
74 NTAPI
75 PciFdoIrpStartDevice(IN PIRP Irp,
76 IN PIO_STACK_LOCATION IoStackLocation,
77 IN PPCI_FDO_EXTENSION DeviceExtension)
78 {
79 NTSTATUS Status;
80 PCM_RESOURCE_LIST Resources;
81 PAGED_CODE();
82
83 /* The device stack must be starting the FDO in a success path */
84 if (!NT_SUCCESS(Irp->IoStatus.Status)) return STATUS_NOT_SUPPORTED;
85
86 /* Attempt to switch the state machine to the started state */
87 Status = PciBeginStateTransition(DeviceExtension, PciStarted);
88 if (!NT_SUCCESS(Status)) return Status;
89
90 /* Check for any boot-provided resources */
91 Resources = IoStackLocation->Parameters.StartDevice.AllocatedResources;
92 DPRINT1("Resources: %p\n", Resources);
93 if ((Resources) && !(PCI_IS_ROOT_FDO(DeviceExtension)))
94 {
95 /* These resources would only be for non-root FDOs, unhandled for now */
96 ASSERT(Resources->Count == 1);
97 UNIMPLEMENTED;
98 while (TRUE);
99 }
100
101 /* Initialize the arbiter for this FDO */
102 Status = PciInitializeArbiterRanges(DeviceExtension, Resources);
103 if (!NT_SUCCESS(Status))
104 {
105 /* Cancel the transition if this failed */
106 PciCancelStateTransition(DeviceExtension, PciStarted);
107 return Status;
108 }
109
110 /* Again, check for boot-provided resources for non-root FDO */
111 if ((Resources) && !(PCI_IS_ROOT_FDO(DeviceExtension)))
112 {
113 /* Unhandled for now */
114 ASSERT(Resources->Count == 1);
115 UNIMPLEMENTED;
116 while (TRUE);
117 }
118
119 /* Commit the transition to the started state */
120 PciCommitStateTransition(DeviceExtension, PciStarted);
121 return STATUS_SUCCESS;
122 }
123
124 NTSTATUS
125 NTAPI
126 PciFdoIrpQueryRemoveDevice(IN PIRP Irp,
127 IN PIO_STACK_LOCATION IoStackLocation,
128 IN PPCI_FDO_EXTENSION DeviceExtension)
129 {
130 UNIMPLEMENTED;
131 while (TRUE);
132 return STATUS_NOT_SUPPORTED;
133 }
134
135 NTSTATUS
136 NTAPI
137 PciFdoIrpRemoveDevice(IN PIRP Irp,
138 IN PIO_STACK_LOCATION IoStackLocation,
139 IN PPCI_FDO_EXTENSION DeviceExtension)
140 {
141 UNIMPLEMENTED;
142 while (TRUE);
143 return STATUS_NOT_SUPPORTED;
144 }
145
146 NTSTATUS
147 NTAPI
148 PciFdoIrpCancelRemoveDevice(IN PIRP Irp,
149 IN PIO_STACK_LOCATION IoStackLocation,
150 IN PPCI_FDO_EXTENSION DeviceExtension)
151 {
152 UNIMPLEMENTED;
153 while (TRUE);
154 return STATUS_NOT_SUPPORTED;
155 }
156
157 NTSTATUS
158 NTAPI
159 PciFdoIrpStopDevice(IN PIRP Irp,
160 IN PIO_STACK_LOCATION IoStackLocation,
161 IN PPCI_FDO_EXTENSION DeviceExtension)
162 {
163 UNIMPLEMENTED;
164 while (TRUE);
165 return STATUS_NOT_SUPPORTED;
166 }
167
168 NTSTATUS
169 NTAPI
170 PciFdoIrpQueryStopDevice(IN PIRP Irp,
171 IN PIO_STACK_LOCATION IoStackLocation,
172 IN PPCI_FDO_EXTENSION DeviceExtension)
173 {
174 UNIMPLEMENTED;
175 while (TRUE);
176 return STATUS_NOT_SUPPORTED;
177 }
178
179 NTSTATUS
180 NTAPI
181 PciFdoIrpCancelStopDevice(IN PIRP Irp,
182 IN PIO_STACK_LOCATION IoStackLocation,
183 IN PPCI_FDO_EXTENSION DeviceExtension)
184 {
185 UNIMPLEMENTED;
186 while (TRUE);
187 return STATUS_NOT_SUPPORTED;
188 }
189
190 NTSTATUS
191 NTAPI
192 PciFdoIrpQueryDeviceRelations(IN PIRP Irp,
193 IN PIO_STACK_LOCATION IoStackLocation,
194 IN PPCI_FDO_EXTENSION DeviceExtension)
195 {
196 UNIMPLEMENTED;
197 while (TRUE);
198 return STATUS_NOT_SUPPORTED;
199 }
200
201 NTSTATUS
202 NTAPI
203 PciFdoIrpQueryInterface(IN PIRP Irp,
204 IN PIO_STACK_LOCATION IoStackLocation,
205 IN PPCI_FDO_EXTENSION DeviceExtension)
206 {
207 NTSTATUS Status;
208 PAGED_CODE();
209 ASSERT(DeviceExtension->ExtensionType == PciFdoExtensionType);
210
211 /* Deleted extensions don't respond to IRPs */
212 if (DeviceExtension->DeviceState == PciDeleted)
213 {
214 /* Hand it bacO try to deal with it */
215 return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
216 }
217
218 /* Query our driver for this interface */
219 Status = PciQueryInterface(DeviceExtension,
220 IoStackLocation->Parameters.QueryInterface.
221 InterfaceType,
222 IoStackLocation->Parameters.QueryInterface.
223 Size,
224 IoStackLocation->Parameters.QueryInterface.
225 Version,
226 IoStackLocation->Parameters.QueryInterface.
227 InterfaceSpecificData,
228 IoStackLocation->Parameters.QueryInterface.
229 Interface,
230 FALSE);
231 if (NT_SUCCESS(Status))
232 {
233 /* We found it, let the PDO handle it */
234 Irp->IoStatus.Status = Status;
235 return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
236 }
237 else if (Status == STATUS_NOT_SUPPORTED)
238 {
239 /* Otherwise, we can't handle it, let someone else down the stack try */
240 Status = PciCallDownIrpStack(DeviceExtension, Irp);
241 if (Status == STATUS_NOT_SUPPORTED)
242 {
243 /* They can't either, try a last-resort interface lookup */
244 Status = PciQueryInterface(DeviceExtension,
245 IoStackLocation->Parameters.QueryInterface.
246 InterfaceType,
247 IoStackLocation->Parameters.QueryInterface.
248 Size,
249 IoStackLocation->Parameters.QueryInterface.
250 Version,
251 IoStackLocation->Parameters.QueryInterface.
252 InterfaceSpecificData,
253 IoStackLocation->Parameters.QueryInterface.
254 Interface,
255 TRUE);
256 }
257 }
258
259 /* Has anyone claimed this interface yet? */
260 if (Status == STATUS_NOT_SUPPORTED)
261 {
262 /* No, return the original IRP status */
263 Status = Irp->IoStatus.Status;
264 }
265 else
266 {
267 /* Yes, set the new IRP status */
268 Irp->IoStatus.Status = Status;
269 }
270
271 /* Complete this IRP */
272 IoCompleteRequest(Irp, IO_NO_INCREMENT);
273 return Status;
274 }
275
276 NTSTATUS
277 NTAPI
278 PciFdoIrpQueryCapabilities(IN PIRP Irp,
279 IN PIO_STACK_LOCATION IoStackLocation,
280 IN PPCI_FDO_EXTENSION DeviceExtension)
281 {
282 UNIMPLEMENTED;
283 while (TRUE);
284 return STATUS_NOT_SUPPORTED;
285 }
286
287 NTSTATUS
288 NTAPI
289 PciFdoIrpDeviceUsageNotification(IN PIRP Irp,
290 IN PIO_STACK_LOCATION IoStackLocation,
291 IN PPCI_FDO_EXTENSION DeviceExtension)
292 {
293 UNIMPLEMENTED;
294 while (TRUE);
295 return STATUS_NOT_SUPPORTED;
296 }
297
298 NTSTATUS
299 NTAPI
300 PciFdoIrpSurpriseRemoval(IN PIRP Irp,
301 IN PIO_STACK_LOCATION IoStackLocation,
302 IN PPCI_FDO_EXTENSION DeviceExtension)
303 {
304 UNIMPLEMENTED;
305 while (TRUE);
306 return STATUS_NOT_SUPPORTED;
307 }
308
309 NTSTATUS
310 NTAPI
311 PciFdoIrpQueryLegacyBusInformation(IN PIRP Irp,
312 IN PIO_STACK_LOCATION IoStackLocation,
313 IN PPCI_FDO_EXTENSION DeviceExtension)
314 {
315 UNIMPLEMENTED;
316 while (TRUE);
317 return STATUS_NOT_SUPPORTED;
318 }
319
320 VOID
321 NTAPI
322 PciGetHotPlugParameters(IN PPCI_FDO_EXTENSION FdoExtension)
323 {
324 ACPI_EVAL_INPUT_BUFFER InputBuffer;
325 PACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
326 ULONG Length;
327 NTSTATUS Status;
328 PAGED_CODE();
329
330 /* We should receive 4 parameters, per the HPP specification */
331 Length = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 4 * sizeof(ACPI_METHOD_ARGUMENT);
332
333 /* Allocate the buffer to hold the parameters */
334 OutputBuffer = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG);
335 if (!OutputBuffer) return;
336
337 /* Initialize the output and input buffers. The method is _HPP */
338 RtlZeroMemory(OutputBuffer, Length);
339 *(PULONG)InputBuffer.MethodName = 'PPH_';
340 InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
341 do
342 {
343 /* Send the IOCTL to the ACPI driver */
344 Status = PciSendIoctl(FdoExtension->PhysicalDeviceObject,
345 IOCTL_ACPI_EVAL_METHOD,
346 &InputBuffer,
347 sizeof(InputBuffer),
348 OutputBuffer,
349 Length);
350 if (!NT_SUCCESS(Status))
351 {
352 /* The method failed, check if we can salvage data from parent */
353 if (!PCI_IS_ROOT_FDO(FdoExtension))
354 {
355 /* Copy the root bus' hot plug parameters */
356 FdoExtension->HotPlugParameters = FdoExtension->ParentFdoExtension->HotPlugParameters;
357 }
358
359 /* Nothing more to do on this path */
360 break;
361 }
362
363 /* ACPI sent back some data. 4 parameters are expected in the output */
364 if (OutputBuffer->Count != 4) break;
365
366 /* HotPlug PCI Support not yet implemented */
367 UNIMPLEMENTED;
368 while (TRUE);
369 } while (FALSE);
370
371 /* Free the buffer and return */
372 ExFreePoolWithTag(OutputBuffer, 0);
373 }
374
375 VOID
376 NTAPI
377 PciInitializeFdoExtensionCommonFields(PPCI_FDO_EXTENSION FdoExtension,
378 IN PDEVICE_OBJECT DeviceObject,
379 IN PDEVICE_OBJECT PhysicalDeviceObject)
380 {
381 /* Initialize the extension */
382 RtlZeroMemory(FdoExtension, sizeof(PCI_FDO_EXTENSION));
383
384 /* Setup the common fields */
385 FdoExtension->PhysicalDeviceObject = PhysicalDeviceObject;
386 FdoExtension->FunctionalDeviceObject = DeviceObject;
387 FdoExtension->ExtensionType = PciFdoExtensionType;
388 FdoExtension->PowerState.CurrentSystemState = PowerSystemWorking;
389 FdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
390 FdoExtension->IrpDispatchTable = &PciFdoDispatchTable;
391
392 /* Initialize the extension locks */
393 KeInitializeEvent(&FdoExtension->SecondaryExtLock, SynchronizationEvent, TRUE);
394 KeInitializeEvent(&FdoExtension->ChildListLock, SynchronizationEvent, TRUE);
395
396 /* Initialize the default state */
397 PciInitializeState(FdoExtension);
398 }
399
400 NTSTATUS
401 NTAPI
402 PciAddDevice(IN PDRIVER_OBJECT DriverObject,
403 IN PDEVICE_OBJECT PhysicalDeviceObject)
404 {
405 PCM_RESOURCE_LIST Descriptor;
406 PDEVICE_OBJECT AttachedTo;
407 PPCI_FDO_EXTENSION FdoExtension;
408 PPCI_FDO_EXTENSION ParentExtension;
409 PDEVICE_OBJECT DeviceObject;
410 UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
411 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
412 NTSTATUS Status;
413 HANDLE KeyHandle;
414 UNICODE_STRING ValueName;
415 ULONG ResultLength;
416 PAGED_CODE();
417 DPRINT1("PCI - AddDevice (a new bus). PDO: %p (Driver: %wZ)\n",
418 PhysicalDeviceObject, &PhysicalDeviceObject->DriverObject->DriverName);
419
420 /* Zero out variables so failure path knows what to do */
421 AttachedTo = NULL;
422 do
423 {
424 /* Check if there's already a device extension for this bus */
425 ParentExtension = PciFindParentPciFdoExtension(PhysicalDeviceObject,
426 &PciGlobalLock);
427 if (ParentExtension)
428 {
429 /* More than one PCI bus, this is not expected yet */
430 UNIMPLEMENTED;
431 while (TRUE);
432 }
433
434 /* Create the FDO for the bus */
435 Status = IoCreateDevice(DriverObject,
436 sizeof(PCI_FDO_EXTENSION),
437 NULL,
438 FILE_DEVICE_BUS_EXTENDER,
439 0,
440 0,
441 &DeviceObject);
442 if (!NT_SUCCESS(Status)) break;
443
444 /* Initialize the extension for the FDO */
445 FdoExtension = DeviceObject->DeviceExtension;
446 PciInitializeFdoExtensionCommonFields(DeviceObject->DeviceExtension,
447 DeviceObject,
448 PhysicalDeviceObject);
449
450 /* Attach to the root PDO */
451 Status = STATUS_NO_SUCH_DEVICE;
452 AttachedTo = IoAttachDeviceToDeviceStack(DeviceObject,
453 PhysicalDeviceObject);
454 ASSERT(AttachedTo != NULL);
455 if (!AttachedTo) break;
456 FdoExtension->AttachedDeviceObject = AttachedTo;
457 if (ParentExtension)
458 {
459 /* More than one PCI bus, this is not expected yet */
460 UNIMPLEMENTED;
461 while (TRUE);
462 }
463 else
464 {
465 /* Query the boot configuration */
466 Status = PciGetDeviceProperty(PhysicalDeviceObject,
467 DevicePropertyBootConfiguration,
468 (PVOID*)&Descriptor);
469 if (!NT_SUCCESS(Status))
470 {
471 /* No configuration has been set */
472 Descriptor = NULL;
473 }
474 else
475 {
476 /* Root PDO in ReactOS does not assign boot resources */
477 UNIMPLEMENTED;
478 while (TRUE);
479 }
480
481 if (Descriptor)
482 {
483 /* Root PDO in ReactOS does not assign boot resources */
484 UNIMPLEMENTED;
485 while (TRUE);
486 }
487 else
488 {
489 /* Default configuration isn't the normal path on Windows */
490 if (PciBreakOnDefault)
491 {
492 /* If a second bus is found and there's still no data, crash */
493 KeBugCheckEx(PCI_BUS_DRIVER_INTERNAL,
494 0xDEAD0010u,
495 (ULONG_PTR)DeviceObject,
496 0,
497 0);
498 }
499
500 /* Warn that a default configuration will be used, and set bus 0 */
501 DPRINT1("PCI Will use default configuration.\n");
502 PciBreakOnDefault = TRUE;
503 FdoExtension->BaseBus = 0;
504 }
505
506 /* This is the root bus */
507 FdoExtension->BusRootFdoExtension = FdoExtension;
508 }
509
510 /* Get the HAL or ACPI Bus Handler Callbacks for Configuration Access */
511 Status = PciGetConfigHandlers(FdoExtension);
512 if (!NT_SUCCESS(Status)) break;
513
514 /* Initialize all the supported PCI arbiters */
515 Status = PciInitializeArbiters(FdoExtension);
516 if (!NT_SUCCESS(Status)) break;
517
518 /* This is a real FDO, insert it into the list */
519 FdoExtension->Fake = FALSE;
520 PciInsertEntryAtTail(&PciFdoExtensionListHead,
521 FdoExtension,
522 &PciGlobalLock);
523
524 /* Open the device registry key so that we can query the errata flags */
525 IoOpenDeviceRegistryKey(DeviceObject,
526 PLUGPLAY_REGKEY_DEVICE,
527 KEY_ALL_ACCESS,
528 &KeyHandle),
529
530 /* Open the value that contains errata flags for this bus instance */
531 RtlInitUnicodeString(&ValueName, L"HackFlags");
532 Status = ZwQueryValueKey(KeyHandle,
533 &ValueName,
534 KeyValuePartialInformation,
535 ValueInfo,
536 sizeof(Buffer),
537 &ResultLength);
538 ZwClose(KeyHandle);
539 if (NT_SUCCESS(Status))
540 {
541 /* Make sure the data is of expected type and size */
542 if ((ValueInfo->Type == REG_DWORD) &&
543 (ValueInfo->DataLength == sizeof(ULONG)))
544 {
545 /* Read the flags for this bus */
546 FdoExtension->BusHackFlags = *(PULONG)&ValueInfo->Data;
547 }
548 }
549
550 /* Query ACPI for PCI HotPlug Support */
551 PciGetHotPlugParameters(FdoExtension);
552
553 /* The Bus FDO is now initialized */
554 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
555 DPRINT1("PCI Root FDO Added: %p %p\n", DeviceObject, FdoExtension);
556 return STATUS_SUCCESS;
557 } while (FALSE);
558
559 /* This is the failure path */
560 ASSERT(!NT_SUCCESS(Status));
561 if (AttachedTo) IoDetachDevice(AttachedTo);
562 if (DeviceObject) IoDeleteDevice(DeviceObject);
563 return Status;
564 }
565
566 /* EOF */