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