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