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