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