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