- Fixed handling of IRP_MN_QUERY_BUS_INFORMATION.
[reactos.git] / reactos / drivers / bus / pci / fdo.c
1 /* $Id: fdo.c,v 1.7 2004/03/14 17:10:43 navaraf 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 WCHAR Buffer[MAX_PATH];
179 ULONG Size;
180 ULONG i;
181
182 DPRINT("Called\n");
183
184 ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
185
186 Status = STATUS_SUCCESS;
187
188 ErrorOccurred = FALSE;
189
190 FdoEnumerateDevices(DeviceObject);
191
192 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
193
194 if (Irp->IoStatus.Information) {
195 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
196 structure so we must merge this structure with our own */
197 }
198
199 Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *
200 (DeviceExtension->DeviceListCount - 1);
201 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
202 if (!Relations)
203 return STATUS_INSUFFICIENT_RESOURCES;
204
205 Relations->Count = DeviceExtension->DeviceListCount;
206
207 i = 0;
208 CurrentEntry = DeviceExtension->DeviceListHead.Flink;
209 while (CurrentEntry != &DeviceExtension->DeviceListHead) {
210 Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
211
212 PdoDeviceExtension = NULL;
213
214 if (!Device->Pdo) {
215 /* Create a physical device object for the
216 device as it does not already have one */
217 Status = IoCreateDevice(
218 DeviceObject->DriverObject,
219 sizeof(PDO_DEVICE_EXTENSION),
220 NULL,
221 FILE_DEVICE_CONTROLLER,
222 0,
223 FALSE,
224 &Device->Pdo);
225 if (!NT_SUCCESS(Status)) {
226 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
227 ErrorStatus = Status;
228 ErrorOccurred = TRUE;
229 break;
230 }
231
232 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
233
234 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
235
236 //Device->Pdo->Flags |= DO_POWER_PAGABLE;
237
238 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
239
240 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
241
242 PdoDeviceExtension->Common.IsFDO = FALSE;
243
244 PdoDeviceExtension->Common.DeviceObject = Device->Pdo;
245
246 PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0;
247
248 PdoDeviceExtension->Fdo = DeviceObject;
249
250 PdoDeviceExtension->BusNumber = Device->BusNumber;
251
252 RtlCopyMemory(
253 &PdoDeviceExtension->SlotNumber,
254 &Device->SlotNumber,
255 sizeof(PCI_SLOT_NUMBER));
256
257 /* FIXME: Get device properties (Hardware IDs, etc.) */
258
259 swprintf(
260 Buffer,
261 L"PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",
262 Device->PciConfig.VendorID,
263 Device->PciConfig.DeviceID,
264 (Device->PciConfig.u.type0.SubSystemID << 16) +
265 Device->PciConfig.u.type0.SubVendorID,
266 Device->PciConfig.RevisionID);
267
268 if (!PciCreateUnicodeString(
269 &PdoDeviceExtension->DeviceID,
270 Buffer,
271 PagedPool)) {
272 ErrorOccurred = TRUE;
273 break;
274 }
275
276 DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceID.Buffer);
277 }
278
279 if (!Device->RemovePending) {
280 /* Reference the physical device object. The PnP manager
281 will dereference it again when it is no longer needed */
282 ObReferenceObject(Device->Pdo);
283
284 Relations->Objects[i] = Device->Pdo;
285
286 i++;
287 }
288
289 CurrentEntry = CurrentEntry->Flink;
290 }
291
292 if (ErrorOccurred) {
293 /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */
294 /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
295 if (PdoDeviceExtension) {
296 RtlFreeUnicodeString(&PdoDeviceExtension->DeviceID);
297 ExFreePool(PdoDeviceExtension);
298 }
299
300 ExFreePool(Relations);
301 return ErrorStatus;
302 }
303
304 Irp->IoStatus.Information = (ULONG_PTR)Relations;
305
306 DPRINT("Done\n");
307
308 return Status;
309 }
310
311
312 static NTSTATUS
313 FdoStartDevice(
314 IN PDEVICE_OBJECT DeviceObject,
315 IN PIRP Irp)
316 {
317 PFDO_DEVICE_EXTENSION DeviceExtension;
318
319 DPRINT("Called\n");
320
321 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
322
323 assert(DeviceExtension->State == dsStopped);
324
325 InitializeListHead(&DeviceExtension->DeviceListHead);
326 KeInitializeSpinLock(&DeviceExtension->DeviceListLock);
327 DeviceExtension->DeviceListCount = 0;
328 DeviceExtension->State = dsStarted;
329
330 //Irp->IoStatus.Information = 0;
331
332 return STATUS_SUCCESS;
333 }
334
335
336 static NTSTATUS
337 FdoSetPower(
338 IN PDEVICE_OBJECT DeviceObject,
339 IN PIRP Irp,
340 PIO_STACK_LOCATION IrpSp)
341 {
342 PFDO_DEVICE_EXTENSION DeviceExtension;
343 NTSTATUS Status;
344
345 DPRINT("Called\n");
346
347 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
348
349 if (IrpSp->Parameters.Power.Type == DevicePowerState) {
350 /* FIXME: Set device power state for the device */
351 Status = STATUS_UNSUCCESSFUL;
352 } else {
353 Status = STATUS_UNSUCCESSFUL;
354 }
355
356 return Status;
357 }
358
359
360 /*** PUBLIC ******************************************************************/
361
362 NTSTATUS
363 FdoPnpControl(
364 PDEVICE_OBJECT DeviceObject,
365 PIRP Irp)
366 /*
367 * FUNCTION: Handle Plug and Play IRPs for the PCI device object
368 * ARGUMENTS:
369 * DeviceObject = Pointer to functional device object of the PCI driver
370 * Irp = Pointer to IRP that should be handled
371 * RETURNS:
372 * Status
373 */
374 {
375 PFDO_DEVICE_EXTENSION DeviceExtension;
376 PIO_STACK_LOCATION IrpSp;
377 NTSTATUS Status;
378
379 DPRINT("Called\n");
380
381 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
382
383 IrpSp = IoGetCurrentIrpStackLocation(Irp);
384 switch (IrpSp->MinorFunction) {
385 #if 0
386 case IRP_MN_CANCEL_REMOVE_DEVICE:
387 Status = STATUS_NOT_IMPLEMENTED;
388 break;
389
390 case IRP_MN_CANCEL_STOP_DEVICE:
391 Status = STATUS_NOT_IMPLEMENTED;
392 break;
393
394 case IRP_MN_DEVICE_USAGE_NOTIFICATION:
395 Status = STATUS_NOT_IMPLEMENTED;
396 break;
397
398 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
399 Status = STATUS_NOT_IMPLEMENTED;
400 break;
401 #endif
402 case IRP_MN_QUERY_DEVICE_RELATIONS:
403 Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp);
404 break;
405 #if 0
406 case IRP_MN_QUERY_PNP_DEVICE_STATE:
407 Status = STATUS_NOT_IMPLEMENTED;
408 break;
409
410 case IRP_MN_QUERY_REMOVE_DEVICE:
411 Status = STATUS_NOT_IMPLEMENTED;
412 break;
413
414 case IRP_MN_QUERY_STOP_DEVICE:
415 Status = STATUS_NOT_IMPLEMENTED;
416 break;
417
418 case IRP_MN_REMOVE_DEVICE:
419 Status = STATUS_NOT_IMPLEMENTED;
420 break;
421 #endif
422 case IRP_MN_START_DEVICE:
423 DPRINT("IRP_MN_START_DEVICE received\n");
424 Status = FdoStartDevice(DeviceObject, Irp);
425 break;
426 case IRP_MN_STOP_DEVICE:
427 /* Currently not supported */
428 Status = STATUS_UNSUCCESSFUL;
429 break;
430 #if 0
431 case IRP_MN_SURPRISE_REMOVAL:
432 Status = STATUS_NOT_IMPLEMENTED;
433 break;
434 #endif
435 default:
436 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
437
438 /*
439 * Do NOT complete the IRP as it will be processed by the lower
440 * device object, which will complete the IRP
441 */
442 IoSkipCurrentIrpStackLocation(Irp);
443 Status = IoCallDriver(DeviceExtension->Ldo, Irp);
444 return Status;
445 break;
446 }
447
448
449 if (Status != STATUS_PENDING) {
450 if (Status != STATUS_NOT_IMPLEMENTED)
451 Irp->IoStatus.Status = Status;
452 IoCompleteRequest(Irp, IO_NO_INCREMENT);
453 }
454
455 DPRINT("Leaving. Status 0x%X\n", Status);
456
457 return Status;
458 }
459
460
461 NTSTATUS
462 FdoPowerControl(
463 PDEVICE_OBJECT DeviceObject,
464 PIRP Irp)
465 /*
466 * FUNCTION: Handle power management 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 PIO_STACK_LOCATION IrpSp;
475 NTSTATUS Status;
476
477 DPRINT("Called\n");
478
479 IrpSp = IoGetCurrentIrpStackLocation(Irp);
480
481 switch (IrpSp->MinorFunction) {
482 case IRP_MN_SET_POWER:
483 Status = FdoSetPower(DeviceObject, Irp, IrpSp);
484 break;
485
486 default:
487 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
488 Status = STATUS_NOT_IMPLEMENTED;
489 break;
490 }
491
492 if (Status != STATUS_PENDING) {
493 Irp->IoStatus.Status = Status;
494 IoCompleteRequest(Irp, IO_NO_INCREMENT);
495 }
496
497 DPRINT("Leaving. Status 0x%X\n", Status);
498
499 return Status;
500 }
501
502 /* EOF */