Implement InterfacePciDevicePresent(Ex) of PCI_DEVICE_PRESENT_INTERFACE
[reactos.git] / reactos / drivers / bus / pci / fdo.c
1 /*
2 * PROJECT: ReactOS PCI bus driver
3 * FILE: fdo.c
4 * PURPOSE: PCI device object dispatch routines
5 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * UPDATE HISTORY:
7 * 10-09-2001 CSH Created
8 */
9
10 #include <ddk/ntddk.h>
11
12 #include "pcidef.h"
13 #include "pci.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /*** PRIVATE *****************************************************************/
19
20 static NTSTATUS
21 FdoLocateChildDevice(
22 PPCI_DEVICE *Device,
23 PFDO_DEVICE_EXTENSION DeviceExtension,
24 PCI_SLOT_NUMBER SlotNumber,
25 PPCI_COMMON_CONFIG PciConfig)
26 {
27 PLIST_ENTRY CurrentEntry;
28 PPCI_DEVICE CurrentDevice;
29
30 DPRINT("Called\n");
31
32 CurrentEntry = DeviceExtension->DeviceListHead.Flink;
33 while (CurrentEntry != &DeviceExtension->DeviceListHead) {
34 CurrentDevice = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
35
36 /* If both vendor ID and device ID match, it is the same device */
37 if ((PciConfig->VendorID == CurrentDevice->PciConfig.VendorID) &&
38 (PciConfig->DeviceID == CurrentDevice->PciConfig.DeviceID) &&
39 (SlotNumber.u.AsULONG == CurrentDevice->SlotNumber.u.AsULONG)) {
40 *Device = CurrentDevice;
41 DPRINT("Done\n");
42 return STATUS_SUCCESS;
43 }
44
45 CurrentEntry = CurrentEntry->Flink;
46 }
47
48 *Device = NULL;
49 DPRINT("Done\n");
50 return STATUS_UNSUCCESSFUL;
51 }
52
53
54 static NTSTATUS
55 FdoEnumerateDevices(
56 PDEVICE_OBJECT DeviceObject)
57 {
58 PFDO_DEVICE_EXTENSION DeviceExtension;
59 PCI_COMMON_CONFIG PciConfig;
60 PLIST_ENTRY CurrentEntry;
61 PPCI_DEVICE Device;
62 PCI_SLOT_NUMBER SlotNumber;
63 ULONG DeviceNumber;
64 ULONG FunctionNumber;
65 ULONG Size;
66 NTSTATUS Status;
67
68 DPRINT("Called\n");
69
70 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
71
72 /* Mark all devices to be removed. If we don't discover them again during
73 enumeration, assume that they have been surprise removed */
74 CurrentEntry = DeviceExtension->DeviceListHead.Flink;
75 while (CurrentEntry != &DeviceExtension->DeviceListHead) {
76 Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
77 Device->RemovePending = TRUE;
78 CurrentEntry = CurrentEntry->Flink;
79 }
80
81 DeviceExtension->DeviceListCount = 0;
82
83 /* Enumerate devices on the PCI bus */
84 SlotNumber.u.AsULONG = 0;
85 for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
86 {
87 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
88 for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
89 {
90 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
91
92 DPRINT("Bus %1lu Device %2lu Func %1lu\n",
93 DeviceExtension->BusNumber,
94 DeviceNumber,
95 FunctionNumber);
96
97 RtlZeroMemory(&PciConfig,
98 sizeof(PCI_COMMON_CONFIG));
99
100 Size = HalGetBusData(PCIConfiguration,
101 DeviceExtension->BusNumber,
102 SlotNumber.u.AsULONG,
103 &PciConfig,
104 PCI_COMMON_HDR_LENGTH);
105 DPRINT("Size %lu\n", Size);
106 if (Size < PCI_COMMON_HDR_LENGTH)
107 {
108 if (FunctionNumber == 0)
109 {
110 break;
111 }
112 else
113 {
114 continue;
115 }
116 }
117
118 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
119 DeviceExtension->BusNumber,
120 DeviceNumber,
121 FunctionNumber,
122 PciConfig.VendorID,
123 PciConfig.DeviceID);
124
125 Status = FdoLocateChildDevice(&Device, DeviceExtension, SlotNumber, &PciConfig);
126 if (!NT_SUCCESS(Status))
127 {
128 Device = (PPCI_DEVICE)ExAllocatePool(NonPagedPool, sizeof(PCI_DEVICE));
129 if (!Device)
130 {
131 /* FIXME: Cleanup resources for already discovered devices */
132 return STATUS_INSUFFICIENT_RESOURCES;
133 }
134
135 RtlZeroMemory(Device,
136 sizeof(PCI_DEVICE));
137
138 Device->BusNumber = DeviceExtension->BusNumber;
139
140 RtlCopyMemory(&Device->SlotNumber,
141 &SlotNumber,
142 sizeof(PCI_SLOT_NUMBER));
143
144 RtlCopyMemory(&Device->PciConfig,
145 &PciConfig,
146 sizeof(PCI_COMMON_CONFIG));
147
148 ExInterlockedInsertTailList(
149 &DeviceExtension->DeviceListHead,
150 &Device->ListEntry,
151 &DeviceExtension->DeviceListLock);
152 }
153
154 /* Don't remove this device */
155 Device->RemovePending = FALSE;
156
157 DeviceExtension->DeviceListCount++;
158
159 /* Skip to next device if the current one is not a multifunction device */
160 if ((FunctionNumber == 0) &&
161 ((PciConfig.HeaderType & 0x80) == 0))
162 {
163 break;
164 }
165 }
166 }
167
168 DPRINT("Done\n");
169
170 return STATUS_SUCCESS;
171 }
172
173
174 static NTSTATUS
175 FdoQueryBusRelations(
176 IN PDEVICE_OBJECT DeviceObject,
177 IN PIRP Irp,
178 PIO_STACK_LOCATION IrpSp)
179 {
180 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
181 PFDO_DEVICE_EXTENSION DeviceExtension;
182 PDEVICE_RELATIONS Relations;
183 PLIST_ENTRY CurrentEntry;
184 PPCI_DEVICE Device;
185 NTSTATUS Status;
186 BOOLEAN ErrorOccurred;
187 NTSTATUS ErrorStatus;
188 ULONG Size;
189 ULONG i;
190
191 DPRINT("Called\n");
192
193 ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
194
195 Status = STATUS_SUCCESS;
196
197 ErrorOccurred = FALSE;
198
199 FdoEnumerateDevices(DeviceObject);
200
201 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
202
203 if (Irp->IoStatus.Information) {
204 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
205 structure so we must merge this structure with our own */
206 }
207
208 Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *
209 (DeviceExtension->DeviceListCount - 1);
210 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
211 if (!Relations)
212 return STATUS_INSUFFICIENT_RESOURCES;
213
214 Relations->Count = DeviceExtension->DeviceListCount;
215
216 i = 0;
217 CurrentEntry = DeviceExtension->DeviceListHead.Flink;
218 while (CurrentEntry != &DeviceExtension->DeviceListHead) {
219 Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
220
221 PdoDeviceExtension = NULL;
222
223 if (!Device->Pdo) {
224 /* Create a physical device object for the
225 device as it does not already have one */
226 Status = IoCreateDevice(
227 DeviceObject->DriverObject,
228 sizeof(PDO_DEVICE_EXTENSION),
229 NULL,
230 FILE_DEVICE_CONTROLLER,
231 FILE_AUTOGENERATED_DEVICE_NAME,
232 FALSE,
233 &Device->Pdo);
234 if (!NT_SUCCESS(Status)) {
235 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
236 ErrorStatus = Status;
237 ErrorOccurred = TRUE;
238 break;
239 }
240
241 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
242
243 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
244
245 //Device->Pdo->Flags |= DO_POWER_PAGABLE;
246
247 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
248
249 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
250
251 PdoDeviceExtension->Common.IsFDO = FALSE;
252
253 PdoDeviceExtension->Common.DeviceObject = Device->Pdo;
254
255 PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0;
256
257 PdoDeviceExtension->Fdo = DeviceObject;
258
259 PdoDeviceExtension->PciDevice = Device;
260
261 /* Add Device ID string */
262 Status = PciCreateDeviceIDString(&PdoDeviceExtension->DeviceID, Device);
263 if (!NT_SUCCESS(Status))
264 {
265 ErrorStatus = Status;
266 ErrorOccurred = TRUE;
267 break;
268 }
269
270 DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceID.Buffer);
271
272 /* Add Instance ID string */
273 Status = PciCreateInstanceIDString(&PdoDeviceExtension->InstanceID, Device);
274 if (!NT_SUCCESS(Status))
275 {
276 ErrorStatus = Status;
277 ErrorOccurred = TRUE;
278 break;
279 }
280
281 /* Add Hardware IDs string */
282 Status = PciCreateHardwareIDsString(&PdoDeviceExtension->HardwareIDs, Device);
283 if (!NT_SUCCESS(Status))
284 {
285 ErrorStatus = Status;
286 ErrorOccurred = TRUE;
287 break;
288 }
289
290 /* Add Compatible IDs string */
291 Status = PciCreateCompatibleIDsString(&PdoDeviceExtension->CompatibleIDs, Device);
292 if (!NT_SUCCESS(Status))
293 {
294 ErrorStatus = Status;
295 ErrorOccurred = TRUE;
296 break;
297 }
298
299 /* Add device description string */
300 Status = PciCreateDeviceDescriptionString(&PdoDeviceExtension->DeviceDescription, Device);
301 if (!NT_SUCCESS(Status))
302 {
303 ErrorStatus = Status;
304 ErrorOccurred = TRUE;
305 break;
306 }
307
308 /* Add device location string */
309 Status = PciCreateDeviceLocationString(&PdoDeviceExtension->DeviceLocation, Device);
310 if (!NT_SUCCESS(Status))
311 {
312 ErrorStatus = Status;
313 ErrorOccurred = TRUE;
314 break;
315 }
316 }
317
318 if (!Device->RemovePending) {
319 /* Reference the physical device object. The PnP manager
320 will dereference it again when it is no longer needed */
321 ObReferenceObject(Device->Pdo);
322
323 Relations->Objects[i] = Device->Pdo;
324
325 i++;
326 }
327
328 CurrentEntry = CurrentEntry->Flink;
329 }
330
331 if (ErrorOccurred) {
332 /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */
333 /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
334 if (PdoDeviceExtension) {
335 RtlFreeUnicodeString(&PdoDeviceExtension->DeviceID);
336 RtlFreeUnicodeString(&PdoDeviceExtension->InstanceID);
337 RtlFreeUnicodeString(&PdoDeviceExtension->HardwareIDs);
338 RtlFreeUnicodeString(&PdoDeviceExtension->CompatibleIDs);
339 RtlFreeUnicodeString(&PdoDeviceExtension->DeviceDescription);
340 RtlFreeUnicodeString(&PdoDeviceExtension->DeviceLocation);
341 }
342
343 ExFreePool(Relations);
344 return ErrorStatus;
345 }
346
347 Irp->IoStatus.Information = (ULONG_PTR)Relations;
348
349 DPRINT("Done\n");
350
351 return Status;
352 }
353
354
355 static NTSTATUS
356 FdoStartDevice(
357 IN PDEVICE_OBJECT DeviceObject,
358 IN PIRP Irp)
359 {
360 PFDO_DEVICE_EXTENSION DeviceExtension;
361 PCM_RESOURCE_LIST AllocatedResources;
362 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
363 ULONG FoundBusNumber = FALSE;
364 ULONG i;
365
366 DPRINT("Called\n");
367
368 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
369
370 AllocatedResources = IoGetCurrentIrpStackLocation(Irp)->Parameters.StartDevice.AllocatedResources;
371 if (!AllocatedResources)
372 {
373 DPRINT("No allocated resources sent to driver\n");
374 return STATUS_INSUFFICIENT_RESOURCES;
375 }
376 if (AllocatedResources->Count < 1)
377 {
378 DPRINT("Not enough allocated resources sent to driver\n");
379 return STATUS_INSUFFICIENT_RESOURCES;
380 }
381 if (AllocatedResources->List[0].PartialResourceList.Version != 1
382 || AllocatedResources->List[0].PartialResourceList.Revision != 1)
383 return STATUS_REVISION_MISMATCH;
384
385 ASSERT(DeviceExtension->State == dsStopped);
386
387 for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++)
388 {
389 ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i];
390 switch (ResourceDescriptor->Type)
391 {
392 case CmResourceTypeBusNumber:
393 {
394 if (FoundBusNumber || ResourceDescriptor->u.BusNumber.Length != 1)
395 return STATUS_INVALID_PARAMETER;
396 DeviceExtension->BusNumber = ResourceDescriptor->u.BusNumber.Start;
397 DPRINT("Found bus number resource: %lu\n", DeviceExtension->BusNumber);
398 FoundBusNumber = TRUE;
399 break;
400 }
401 default:
402 DPRINT1("Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
403 }
404 }
405 if (!FoundBusNumber)
406 {
407 DPRINT("Some required resources were not found in allocated resources list\n");
408 return STATUS_INSUFFICIENT_RESOURCES;
409 }
410
411 InitializeListHead(&DeviceExtension->DeviceListHead);
412 KeInitializeSpinLock(&DeviceExtension->DeviceListLock);
413 DeviceExtension->DeviceListCount = 0;
414 DeviceExtension->State = dsStarted;
415
416 ExInterlockedInsertTailList(
417 &DriverExtension->BusListHead,
418 &DeviceExtension->ListEntry,
419 &DriverExtension->BusListLock);
420
421 Irp->IoStatus.Information = 0;
422
423 return STATUS_SUCCESS;
424 }
425
426
427 static NTSTATUS
428 FdoSetPower(
429 IN PDEVICE_OBJECT DeviceObject,
430 IN PIRP Irp,
431 PIO_STACK_LOCATION IrpSp)
432 {
433 PFDO_DEVICE_EXTENSION DeviceExtension;
434 NTSTATUS Status;
435
436 DPRINT("Called\n");
437
438 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
439
440 if (IrpSp->Parameters.Power.Type == DevicePowerState) {
441 /* FIXME: Set device power state for the device */
442 Status = STATUS_UNSUCCESSFUL;
443 } else {
444 Status = STATUS_UNSUCCESSFUL;
445 }
446
447 return Status;
448 }
449
450
451 /*** PUBLIC ******************************************************************/
452
453 NTSTATUS
454 FdoPnpControl(
455 PDEVICE_OBJECT DeviceObject,
456 PIRP Irp)
457 /*
458 * FUNCTION: Handle Plug and Play IRPs for the PCI device object
459 * ARGUMENTS:
460 * DeviceObject = Pointer to functional device object of the PCI driver
461 * Irp = Pointer to IRP that should be handled
462 * RETURNS:
463 * Status
464 */
465 {
466 PFDO_DEVICE_EXTENSION DeviceExtension;
467 PIO_STACK_LOCATION IrpSp;
468 NTSTATUS Status;
469
470 DPRINT("Called\n");
471
472 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
473
474 IrpSp = IoGetCurrentIrpStackLocation(Irp);
475 switch (IrpSp->MinorFunction) {
476 #if 0
477 case IRP_MN_CANCEL_REMOVE_DEVICE:
478 Status = STATUS_NOT_IMPLEMENTED;
479 break;
480
481 case IRP_MN_CANCEL_STOP_DEVICE:
482 Status = STATUS_NOT_IMPLEMENTED;
483 break;
484
485 case IRP_MN_DEVICE_USAGE_NOTIFICATION:
486 Status = STATUS_NOT_IMPLEMENTED;
487 break;
488
489 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
490 Status = STATUS_NOT_IMPLEMENTED;
491 break;
492 #endif
493 case IRP_MN_QUERY_DEVICE_RELATIONS:
494 Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp);
495 break;
496 #if 0
497 case IRP_MN_QUERY_PNP_DEVICE_STATE:
498 Status = STATUS_NOT_IMPLEMENTED;
499 break;
500
501 case IRP_MN_QUERY_REMOVE_DEVICE:
502 Status = STATUS_NOT_IMPLEMENTED;
503 break;
504
505 case IRP_MN_QUERY_STOP_DEVICE:
506 Status = STATUS_NOT_IMPLEMENTED;
507 break;
508
509 case IRP_MN_REMOVE_DEVICE:
510 Status = STATUS_NOT_IMPLEMENTED;
511 break;
512 #endif
513 case IRP_MN_START_DEVICE:
514 DPRINT("IRP_MN_START_DEVICE received\n");
515 Status = FdoStartDevice(DeviceObject, Irp);
516 break;
517 case IRP_MN_STOP_DEVICE:
518 /* Currently not supported */
519 Status = STATUS_UNSUCCESSFUL;
520 break;
521 #if 0
522 case IRP_MN_SURPRISE_REMOVAL:
523 Status = STATUS_NOT_IMPLEMENTED;
524 break;
525 #endif
526 default:
527 DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
528
529 /*
530 * Do NOT complete the IRP as it will be processed by the lower
531 * device object, which will complete the IRP
532 */
533 IoSkipCurrentIrpStackLocation(Irp);
534 Status = IoCallDriver(DeviceExtension->Ldo, Irp);
535 return Status;
536 break;
537 }
538
539
540 if (Status != STATUS_PENDING) {
541 if (Status != STATUS_NOT_IMPLEMENTED)
542 Irp->IoStatus.Status = Status;
543 IoCompleteRequest(Irp, IO_NO_INCREMENT);
544 }
545
546 DPRINT("Leaving. Status 0x%X\n", Status);
547
548 return Status;
549 }
550
551
552 NTSTATUS
553 FdoPowerControl(
554 PDEVICE_OBJECT DeviceObject,
555 PIRP Irp)
556 /*
557 * FUNCTION: Handle power management IRPs for the PCI device object
558 * ARGUMENTS:
559 * DeviceObject = Pointer to functional device object of the PCI driver
560 * Irp = Pointer to IRP that should be handled
561 * RETURNS:
562 * Status
563 */
564 {
565 PIO_STACK_LOCATION IrpSp;
566 NTSTATUS Status;
567
568 DPRINT("Called\n");
569
570 IrpSp = IoGetCurrentIrpStackLocation(Irp);
571
572 switch (IrpSp->MinorFunction) {
573 case IRP_MN_SET_POWER:
574 Status = FdoSetPower(DeviceObject, Irp, IrpSp);
575 break;
576
577 default:
578 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
579 Status = STATUS_NOT_IMPLEMENTED;
580 break;
581 }
582
583 if (Status != STATUS_PENDING) {
584 Irp->IoStatus.Status = Status;
585 IoCompleteRequest(Irp, IO_NO_INCREMENT);
586 }
587
588 DPRINT("Leaving. Status 0x%X\n", Status);
589
590 return Status;
591 }
592
593 /* EOF */