Sync with trunk r58113.
[reactos.git] / drivers / bus / pcix / pdo.c
1 /*
2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/pdo.c
5 * PURPOSE: PDO 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 LONG PciPdoSequenceNumber;
18
19 C_ASSERT(FIELD_OFFSET(PCI_FDO_EXTENSION, DeviceState) == FIELD_OFFSET(PCI_PDO_EXTENSION, DeviceState));
20 C_ASSERT(FIELD_OFFSET(PCI_FDO_EXTENSION, TentativeNextState) == FIELD_OFFSET(PCI_PDO_EXTENSION, TentativeNextState));
21 C_ASSERT(FIELD_OFFSET(PCI_FDO_EXTENSION, List) == FIELD_OFFSET(PCI_PDO_EXTENSION, Next));
22
23 PCI_MN_DISPATCH_TABLE PciPdoDispatchPowerTable[] =
24 {
25 {IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciPdoWaitWake},
26 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
27 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoSetPowerState},
28 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryPower},
29 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported}
30 };
31
32 PCI_MN_DISPATCH_TABLE PciPdoDispatchPnpTable[] =
33 {
34 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpStartDevice},
35 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryRemoveDevice},
36 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpRemoveDevice},
37 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpCancelRemoveDevice},
38 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpStopDevice},
39 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryStopDevice},
40 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpCancelStopDevice},
41 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryDeviceRelations},
42 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryInterface},
43 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryCapabilities},
44 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryResources},
45 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryResourceRequirements},
46 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryDeviceText},
47 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
48 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
49 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpReadConfig},
50 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpWriteConfig},
51 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
52 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
53 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryId},
54 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryDeviceState},
55 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryBusInformation},
56 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpDeviceUsageNotification},
57 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpSurpriseRemoval},
58 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciPdoIrpQueryLegacyBusInformation},
59 {IRP_COMPLETE, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported}
60 };
61
62 PCI_MJ_DISPATCH_TABLE PciPdoDispatchTable =
63 {
64 IRP_MN_QUERY_LEGACY_BUS_INFORMATION,
65 PciPdoDispatchPnpTable,
66 IRP_MN_QUERY_POWER,
67 PciPdoDispatchPowerTable,
68 IRP_COMPLETE,
69 (PCI_DISPATCH_FUNCTION)PciIrpNotSupported,
70 IRP_COMPLETE,
71 (PCI_DISPATCH_FUNCTION)PciIrpInvalidDeviceRequest
72 };
73
74 /* FUNCTIONS ******************************************************************/
75
76 NTSTATUS
77 NTAPI
78 PciPdoWaitWake(IN PIRP Irp,
79 IN PIO_STACK_LOCATION IoStackLocation,
80 IN PPCI_PDO_EXTENSION DeviceExtension)
81 {
82 UNIMPLEMENTED;
83 ASSERT(FALSE); // while (TRUE);
84 return STATUS_NOT_SUPPORTED;
85 }
86
87 NTSTATUS
88 NTAPI
89 PciPdoSetPowerState(IN PIRP Irp,
90 IN PIO_STACK_LOCATION IoStackLocation,
91 IN PPCI_PDO_EXTENSION DeviceExtension)
92 {
93 UNIMPLEMENTED;
94 return STATUS_NOT_SUPPORTED;
95 }
96
97 NTSTATUS
98 NTAPI
99 PciPdoIrpQueryPower(IN PIRP Irp,
100 IN PIO_STACK_LOCATION IoStackLocation,
101 IN PPCI_PDO_EXTENSION DeviceExtension)
102 {
103 UNIMPLEMENTED;
104 ASSERT(FALSE); // while (TRUE);
105 return STATUS_NOT_SUPPORTED;
106 }
107
108 NTSTATUS
109 NTAPI
110 PciPdoIrpStartDevice(IN PIRP Irp,
111 IN PIO_STACK_LOCATION IoStackLocation,
112 IN PPCI_PDO_EXTENSION DeviceExtension)
113 {
114 NTSTATUS Status;
115 BOOLEAN Changed, DoReset;
116 POWER_STATE PowerState;
117 PAGED_CODE();
118
119 DoReset = FALSE;
120
121 /* Begin entering the start phase */
122 Status = PciBeginStateTransition((PVOID)DeviceExtension, PciStarted);
123 if (!NT_SUCCESS(Status)) return Status;
124
125 /* Check if this is a VGA device */
126 if (((DeviceExtension->BaseClass == PCI_CLASS_PRE_20) &&
127 (DeviceExtension->SubClass == PCI_SUBCLASS_PRE_20_VGA)) ||
128 ((DeviceExtension->BaseClass == PCI_CLASS_DISPLAY_CTLR) &&
129 (DeviceExtension->SubClass == PCI_SUBCLASS_VID_VGA_CTLR)))
130 {
131 /* Always force it on */
132 DeviceExtension->CommandEnables |= (PCI_ENABLE_IO_SPACE |
133 PCI_ENABLE_MEMORY_SPACE);
134 }
135
136 /* Check if native IDE is enabled and it owns the I/O ports */
137 if (DeviceExtension->IoSpaceUnderNativeIdeControl)
138 {
139 /* Then don't allow I/O access */
140 DeviceExtension->CommandEnables &= ~PCI_ENABLE_IO_SPACE;
141 }
142
143 /* Always enable bus mastering */
144 DeviceExtension->CommandEnables |= PCI_ENABLE_BUS_MASTER;
145
146 /* Check if the OS assigned resources differ from the PCI configuration */
147 Changed = PciComputeNewCurrentSettings(DeviceExtension,
148 IoStackLocation->Parameters.
149 StartDevice.AllocatedResources);
150 if (Changed)
151 {
152 /* Remember this for later */
153 DeviceExtension->MovedDevice = TRUE;
154 }
155 else
156 {
157 /* All good */
158 DPRINT1("PCI - START not changing resource settings.\n");
159 }
160
161 /* Check if the device was sleeping */
162 if (DeviceExtension->PowerState.CurrentDeviceState != PowerDeviceD0)
163 {
164 /* Power it up */
165 Status = PciSetPowerManagedDevicePowerState(DeviceExtension,
166 PowerDeviceD0,
167 FALSE);
168 if (!NT_SUCCESS(Status))
169 {
170 /* Powerup fail, fail the request */
171 PciCancelStateTransition((PVOID)DeviceExtension, PciStarted);
172 return STATUS_DEVICE_POWER_FAILURE;
173 }
174
175 /* Tell the power manager that the device is powered up */
176 PowerState.DeviceState = PowerDeviceD0;
177 PoSetPowerState(DeviceExtension->PhysicalDeviceObject,
178 DevicePowerState,
179 PowerState);
180
181 /* Update internal state */
182 DeviceExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
183
184 /* This device's resources and decodes will need to be reset */
185 DoReset = TRUE;
186 }
187
188 /* Update resource information now that the device is powered up and active */
189 Status = PciSetResources(DeviceExtension, DoReset, TRUE);
190 if (!NT_SUCCESS(Status))
191 {
192 /* That failed, so cancel the transition */
193 PciCancelStateTransition((PVOID)DeviceExtension, PciStarted);
194 }
195 else
196 {
197 /* Fully commit, as the device is now started up and ready to go */
198 PciCommitStateTransition((PVOID)DeviceExtension, PciStarted);
199 }
200
201 /* Return the result of the start request */
202 return Status;
203 }
204
205 NTSTATUS
206 NTAPI
207 PciPdoIrpQueryRemoveDevice(IN PIRP Irp,
208 IN PIO_STACK_LOCATION IoStackLocation,
209 IN PPCI_PDO_EXTENSION DeviceExtension)
210 {
211 UNIMPLEMENTED;
212 return STATUS_NOT_SUPPORTED;
213 }
214
215 NTSTATUS
216 NTAPI
217 PciPdoIrpRemoveDevice(IN PIRP Irp,
218 IN PIO_STACK_LOCATION IoStackLocation,
219 IN PPCI_PDO_EXTENSION DeviceExtension)
220 {
221 UNIMPLEMENTED;
222 ASSERT(FALSE); // while (TRUE);
223 return STATUS_NOT_SUPPORTED;
224 }
225
226 NTSTATUS
227 NTAPI
228 PciPdoIrpCancelRemoveDevice(IN PIRP Irp,
229 IN PIO_STACK_LOCATION IoStackLocation,
230 IN PPCI_PDO_EXTENSION DeviceExtension)
231 {
232 UNIMPLEMENTED;
233 ASSERT(FALSE); // while (TRUE);
234 return STATUS_NOT_SUPPORTED;
235 }
236
237 NTSTATUS
238 NTAPI
239 PciPdoIrpStopDevice(IN PIRP Irp,
240 IN PIO_STACK_LOCATION IoStackLocation,
241 IN PPCI_PDO_EXTENSION DeviceExtension)
242 {
243 UNIMPLEMENTED;
244 ASSERT(FALSE); // while (TRUE);
245 return STATUS_NOT_SUPPORTED;
246 }
247
248 NTSTATUS
249 NTAPI
250 PciPdoIrpQueryStopDevice(IN PIRP Irp,
251 IN PIO_STACK_LOCATION IoStackLocation,
252 IN PPCI_PDO_EXTENSION DeviceExtension)
253 {
254 UNIMPLEMENTED;
255 ASSERT(FALSE); // while (TRUE);
256 return STATUS_NOT_SUPPORTED;
257 }
258
259 NTSTATUS
260 NTAPI
261 PciPdoIrpCancelStopDevice(IN PIRP Irp,
262 IN PIO_STACK_LOCATION IoStackLocation,
263 IN PPCI_PDO_EXTENSION DeviceExtension)
264 {
265 UNIMPLEMENTED;
266 ASSERT(FALSE); // while (TRUE);
267 return STATUS_NOT_SUPPORTED;
268 }
269
270 NTSTATUS
271 NTAPI
272 PciPdoIrpQueryInterface(IN PIRP Irp,
273 IN PIO_STACK_LOCATION IoStackLocation,
274 IN PPCI_PDO_EXTENSION DeviceExtension)
275 {
276 UNIMPLEMENTED;
277 ASSERT(FALSE); // while (TRUE);
278 return STATUS_NOT_SUPPORTED;
279 }
280
281 NTSTATUS
282 NTAPI
283 PciPdoIrpQueryDeviceRelations(IN PIRP Irp,
284 IN PIO_STACK_LOCATION IoStackLocation,
285 IN PPCI_PDO_EXTENSION DeviceExtension)
286 {
287 NTSTATUS Status;
288 PAGED_CODE();
289
290 /* Are ejection relations being queried? */
291 if (IoStackLocation->Parameters.QueryDeviceRelations.Type == EjectionRelations)
292 {
293 /* Call the worker function */
294 Status = PciQueryEjectionRelations(DeviceExtension,
295 (PDEVICE_RELATIONS*)&Irp->
296 IoStatus.Information);
297 }
298 else if (IoStackLocation->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
299 {
300 /* The only other relation supported is the target device relation */
301 Status = PciQueryTargetDeviceRelations(DeviceExtension,
302 (PDEVICE_RELATIONS*)&Irp->
303 IoStatus.Information);
304 }
305 else
306 {
307 /* All other relations are unsupported */
308 Status = STATUS_NOT_SUPPORTED;
309 }
310
311 /* Return either the result of the worker function, or unsupported status */
312 return Status;
313 }
314
315 NTSTATUS
316 NTAPI
317 PciPdoIrpQueryCapabilities(IN PIRP Irp,
318 IN PIO_STACK_LOCATION IoStackLocation,
319 IN PPCI_PDO_EXTENSION DeviceExtension)
320 {
321 PAGED_CODE();
322
323 /* Call the worker function */
324 return PciQueryCapabilities(DeviceExtension,
325 IoStackLocation->
326 Parameters.DeviceCapabilities.Capabilities);
327 }
328
329 NTSTATUS
330 NTAPI
331 PciPdoIrpQueryResources(IN PIRP Irp,
332 IN PIO_STACK_LOCATION IoStackLocation,
333 IN PPCI_PDO_EXTENSION DeviceExtension)
334 {
335 PAGED_CODE();
336
337 /* Call the worker function */
338 return PciQueryResources(DeviceExtension,
339 (PCM_RESOURCE_LIST*)&Irp->IoStatus.Information);
340 }
341
342 NTSTATUS
343 NTAPI
344 PciPdoIrpQueryResourceRequirements(IN PIRP Irp,
345 IN PIO_STACK_LOCATION IoStackLocation,
346 IN PPCI_PDO_EXTENSION DeviceExtension)
347 {
348 PAGED_CODE();
349
350 /* Call the worker function */
351 return PciQueryRequirements(DeviceExtension,
352 (PIO_RESOURCE_REQUIREMENTS_LIST*)&Irp->
353 IoStatus.Information);
354 }
355
356 NTSTATUS
357 NTAPI
358 PciPdoIrpQueryDeviceText(IN PIRP Irp,
359 IN PIO_STACK_LOCATION IoStackLocation,
360 IN PPCI_PDO_EXTENSION DeviceExtension)
361 {
362 PAGED_CODE();
363
364 /* Call the worker function */
365 return PciQueryDeviceText(DeviceExtension,
366 IoStackLocation->
367 Parameters.QueryDeviceText.DeviceTextType,
368 IoStackLocation->
369 Parameters.QueryDeviceText.LocaleId,
370 (PWCHAR*)&Irp->IoStatus.Information);
371 }
372
373 NTSTATUS
374 NTAPI
375 PciPdoIrpQueryId(IN PIRP Irp,
376 IN PIO_STACK_LOCATION IoStackLocation,
377 IN PPCI_PDO_EXTENSION DeviceExtension)
378 {
379 PAGED_CODE();
380
381 /* Call the worker function */
382 return PciQueryId(DeviceExtension,
383 IoStackLocation->Parameters.QueryId.IdType,
384 (PWCHAR*)&Irp->IoStatus.Information);
385 }
386
387 NTSTATUS
388 NTAPI
389 PciPdoIrpQueryBusInformation(IN PIRP Irp,
390 IN PIO_STACK_LOCATION IoStackLocation,
391 IN PPCI_PDO_EXTENSION DeviceExtension)
392 {
393 PAGED_CODE();
394
395 /* Call the worker function */
396 return PciQueryBusInformation(DeviceExtension,
397 (PPNP_BUS_INFORMATION*)&Irp->
398 IoStatus.Information);
399 }
400
401 NTSTATUS
402 NTAPI
403 PciPdoIrpReadConfig(IN PIRP Irp,
404 IN PIO_STACK_LOCATION IoStackLocation,
405 IN PPCI_PDO_EXTENSION DeviceExtension)
406 {
407 UNIMPLEMENTED;
408 ASSERT(FALSE); // while (TRUE);
409 return STATUS_NOT_SUPPORTED;
410 }
411
412 NTSTATUS
413 NTAPI
414 PciPdoIrpWriteConfig(IN PIRP Irp,
415 IN PIO_STACK_LOCATION IoStackLocation,
416 IN PPCI_PDO_EXTENSION DeviceExtension)
417 {
418 UNIMPLEMENTED;
419 ASSERT(FALSE); // while (TRUE);
420 return STATUS_NOT_SUPPORTED;
421 }
422
423 NTSTATUS
424 NTAPI
425 PciPdoIrpQueryDeviceState(IN PIRP Irp,
426 IN PIO_STACK_LOCATION IoStackLocation,
427 IN PPCI_PDO_EXTENSION DeviceExtension)
428 {
429 UNIMPLEMENTED;
430 return STATUS_NOT_SUPPORTED;
431 }
432
433 NTSTATUS
434 NTAPI
435 PciPdoIrpDeviceUsageNotification(IN PIRP Irp,
436 IN PIO_STACK_LOCATION IoStackLocation,
437 IN PPCI_PDO_EXTENSION DeviceExtension)
438 {
439 UNIMPLEMENTED;
440 ASSERT(FALSE); // while (TRUE);
441 return STATUS_NOT_SUPPORTED;
442 }
443
444 NTSTATUS
445 NTAPI
446 PciPdoIrpSurpriseRemoval(IN PIRP Irp,
447 IN PIO_STACK_LOCATION IoStackLocation,
448 IN PPCI_PDO_EXTENSION DeviceExtension)
449 {
450 UNIMPLEMENTED;
451 ASSERT(FALSE); // while (TRUE);
452 return STATUS_NOT_SUPPORTED;
453 }
454
455 NTSTATUS
456 NTAPI
457 PciPdoIrpQueryLegacyBusInformation(IN PIRP Irp,
458 IN PIO_STACK_LOCATION IoStackLocation,
459 IN PPCI_PDO_EXTENSION DeviceExtension)
460 {
461 UNIMPLEMENTED;
462 ASSERT(FALSE); // while (TRUE);
463 return STATUS_NOT_SUPPORTED;
464 }
465
466 NTSTATUS
467 NTAPI
468 PciPdoCreate(IN PPCI_FDO_EXTENSION DeviceExtension,
469 IN PCI_SLOT_NUMBER Slot,
470 OUT PDEVICE_OBJECT *PdoDeviceObject)
471 {
472 WCHAR DeviceName[32];
473 UNICODE_STRING DeviceString;
474 NTSTATUS Status;
475 PDEVICE_OBJECT DeviceObject;
476 PPCI_PDO_EXTENSION PdoExtension;
477 ULONG SequenceNumber;
478 PAGED_CODE();
479
480 /* Pick an atomically unique sequence number for this device */
481 SequenceNumber = InterlockedIncrement(&PciPdoSequenceNumber);
482
483 /* Create the standard PCI device name for a PDO */
484 swprintf(DeviceName, L"\\Device\\NTPNP_PCI%04d", SequenceNumber);
485 RtlInitUnicodeString(&DeviceString, DeviceName);
486
487 /* Create the actual device now */
488 Status = IoCreateDevice(DeviceExtension->FunctionalDeviceObject->DriverObject,
489 sizeof(PCI_PDO_EXTENSION),
490 &DeviceString,
491 FILE_DEVICE_BUS_EXTENDER,
492 0,
493 0,
494 &DeviceObject);
495 ASSERT(NT_SUCCESS(Status));
496
497 /* Get the extension for it */
498 PdoExtension = (PPCI_PDO_EXTENSION)DeviceObject->DeviceExtension;
499 DPRINT1("PCI: New PDO (b=0x%x, d=0x%x, f=0x%x) @ %p, ext @ %p\n",
500 DeviceExtension->BaseBus,
501 Slot.u.bits.DeviceNumber,
502 Slot.u.bits.FunctionNumber,
503 DeviceObject,
504 DeviceObject->DeviceExtension);
505
506 /* Configure the extension */
507 PdoExtension->ExtensionType = PciPdoExtensionType;
508 PdoExtension->IrpDispatchTable = &PciPdoDispatchTable;
509 PdoExtension->PhysicalDeviceObject = DeviceObject;
510 PdoExtension->Slot = Slot;
511 PdoExtension->PowerState.CurrentSystemState = PowerDeviceD0;
512 PdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
513 PdoExtension->ParentFdoExtension = DeviceExtension;
514
515 /* Initialize the lock for arbiters and other interfaces */
516 KeInitializeEvent(&PdoExtension->SecondaryExtLock, SynchronizationEvent, TRUE);
517
518 /* Initialize the state machine */
519 PciInitializeState((PPCI_FDO_EXTENSION)PdoExtension);
520
521 /* Add the PDO to the parent's list */
522 PdoExtension->Next = NULL;
523 PciInsertEntryAtTail((PSINGLE_LIST_ENTRY)&DeviceExtension->ChildPdoList,
524 (PPCI_FDO_EXTENSION)PdoExtension,
525 &DeviceExtension->ChildListLock);
526
527 /* And finally return it to the caller */
528 *PdoDeviceObject = DeviceObject;
529 return STATUS_SUCCESS;
530 }
531
532 /* EOF */