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