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