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