sync with trunk r49322
[reactos.git] / drivers / bus / pcix / dispatch.c
1 /*
2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/dispatch.c
5 * PURPOSE: WDM Dispatch Routines
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <pci.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 /* FUNCTIONS ******************************************************************/
18
19 NTSTATUS
20 NTAPI
21 PciSetEventCompletion(IN PDEVICE_OBJECT DeviceObject,
22 IN PIRP Irp,
23 IN PVOID Context)
24 {
25 PKEVENT Event = (PVOID)Context;
26 ASSERT(Event);
27
28 /* Set the event and return the appropriate status code */
29 KeSetEvent(Event, FALSE, IO_NO_INCREMENT);
30 return STATUS_MORE_PROCESSING_REQUIRED;
31 }
32
33 NTSTATUS
34 NTAPI
35 PciCallDownIrpStack(IN PPCI_FDO_EXTENSION DeviceExtension,
36 IN PIRP Irp)
37 {
38 NTSTATUS Status;
39 KEVENT Event;
40 PAGED_CODE();
41 DPRINT1("PciCallDownIrpStack ...\n");
42 ASSERT_FDO(DeviceExtension);
43
44 /* Initialize the wait event */
45 KeInitializeEvent(&Event, SynchronizationEvent, 0);
46
47 /* Setup a completion routine */
48 IoCopyCurrentIrpStackLocationToNext(Irp);
49 IoSetCompletionRoutine(Irp, PciSetEventCompletion, &Event, TRUE, TRUE, TRUE);
50
51 /* Call the attached device */
52 Status = IofCallDriver(DeviceExtension->AttachedDeviceObject, Irp);
53 if (Status == STATUS_PENDING)
54 {
55 /* Wait for it to complete the request, and get its status */
56 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
57 Status = Irp->IoStatus.Status;
58 }
59
60 /* Return that status back to the caller */
61 return Status;
62 }
63
64 NTSTATUS
65 NTAPI
66 PciPassIrpFromFdoToPdo(IN PPCI_FDO_EXTENSION DeviceExtension,
67 IN PIRP Irp)
68 {
69 PIO_STACK_LOCATION IoStackLocation;
70 NTSTATUS Status;
71 DPRINT1("Pci PassIrp ...\n");
72
73 /* Get the stack location to check which function this is */
74 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
75 if (IoStackLocation->MajorFunction == IRP_MJ_POWER)
76 {
77 /* Power IRPs are special since we have to notify the Power Manager */
78 IoCopyCurrentIrpStackLocationToNext(Irp);
79 PoStartNextPowerIrp(Irp);
80 Status = PoCallDriver(DeviceExtension->AttachedDeviceObject, Irp);
81 }
82 else
83 {
84 /* For a normal IRP, just call the next driver in the stack */
85 IoSkipCurrentIrpStackLocation(Irp);
86 Status = IofCallDriver(DeviceExtension->AttachedDeviceObject, Irp);
87 }
88
89 /* Return the status back to the caller */
90 return Status;
91 }
92
93 NTSTATUS
94 NTAPI
95 PciDispatchIrp(IN PDEVICE_OBJECT DeviceObject,
96 IN PIRP Irp)
97 {
98 PPCI_FDO_EXTENSION DeviceExtension;
99 PIO_STACK_LOCATION IoStackLocation;
100 PPCI_MJ_DISPATCH_TABLE IrpDispatchTable;
101 BOOLEAN PassToPdo;
102 NTSTATUS Status;
103 PPCI_MN_DISPATCH_TABLE TableArray = NULL, Table;
104 USHORT MaxMinor;
105 PCI_DISPATCH_STYLE DispatchStyle = 0;
106 PCI_DISPATCH_FUNCTION DispatchFunction = NULL;
107 DPRINT1("PCI: Dispatch IRP\n");
108
109 /* Get the extension and I/O stack location for this IRP */
110 DeviceExtension = (PPCI_FDO_EXTENSION)DeviceObject->DeviceExtension;
111 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
112 ASSERT((DeviceExtension->ExtensionType == PciPdoExtensionType) ||
113 (DeviceExtension->ExtensionType == PciFdoExtensionType));
114
115 /* Deleted extensions don't respond to IRPs */
116 if (DeviceExtension->DeviceState == PciDeleted)
117 {
118 /* Fail this IRP */
119 Status = STATUS_NO_SUCH_DEVICE;
120 PassToPdo = FALSE;
121 }
122 else
123 {
124 /* Otherwise, get the dispatch table for the extension */
125 IrpDispatchTable = DeviceExtension->IrpDispatchTable;
126
127 /* And choose which function table to use */
128 switch (IoStackLocation->MajorFunction)
129 {
130 case IRP_MJ_POWER:
131
132 /* Power Manager IRPs */
133 TableArray = IrpDispatchTable->PowerIrpDispatchTable;
134 MaxMinor = IrpDispatchTable->PowerIrpMaximumMinorFunction;
135 break;
136
137 case IRP_MJ_PNP:
138
139 /* Plug-and-Play Manager IRPs */
140 TableArray = IrpDispatchTable->PnpIrpDispatchTable;
141 MaxMinor = IrpDispatchTable->PnpIrpMaximumMinorFunction;
142 break;
143
144 case IRP_MJ_SYSTEM_CONTROL:
145
146 /* WMI IRPs */
147 DispatchFunction = IrpDispatchTable->SystemControlIrpDispatchFunction;
148 DispatchStyle = IrpDispatchTable->SystemControlIrpDispatchStyle;
149 MaxMinor = 0xFFFF;
150 break;
151
152 default:
153
154 /* Unrecognized IRPs */
155 DispatchFunction = IrpDispatchTable->OtherIrpDispatchFunction;
156 DispatchStyle = IrpDispatchTable->OtherIrpDispatchStyle;
157 MaxMinor = 0xFFFF;
158 break;
159 }
160
161 /* Only deal with recognized IRPs */
162 if (MaxMinor != 0xFFFF)
163 {
164 /* Make sure the function is recognized */
165 if (IoStackLocation->MinorFunction > MaxMinor)
166 {
167 /* Pick the terminator, which should return unrecognized */
168 Table = &TableArray[MaxMinor + 1];
169 }
170 else
171 {
172 /* Pick the appropriate table for this function */
173 Table = &TableArray[IoStackLocation->MinorFunction];
174 }
175
176 /* From that table, get the function code and dispatch style */
177 DispatchStyle = Table->DispatchStyle;
178 DispatchFunction = Table->DispatchFunction;
179 }
180
181 /* Print out debugging information, and see if we should break */
182 if (PciDebugIrpDispatchDisplay(IoStackLocation,
183 DeviceExtension,
184 MaxMinor))
185 {
186 /* The developer/user wants us to break for this IRP, do it */
187 DbgBreakPoint();
188 }
189
190 /* Check if this IRP should be sent up the stack first */
191 if (DispatchStyle == IRP_UPWARD)
192 {
193 /* Do it now before handling it ourselves */
194 PciCallDownIrpStack(DeviceExtension, Irp);
195 }
196
197 /* Call the our driver's handler for this IRP and deal with the IRP */
198 Status = DispatchFunction(Irp, IoStackLocation, DeviceExtension);
199 switch (DispatchStyle)
200 {
201 /* Complete IRPs are completely immediately by our driver */
202 case IRP_COMPLETE:
203 PassToPdo = FALSE;
204 break;
205
206 /* Downward IRPs are send to the attached FDO */
207 case IRP_DOWNWARD:
208 PassToPdo = TRUE;
209 break;
210
211 /* Upward IRPs are completed immediately by our driver */
212 case IRP_UPWARD:
213 PassToPdo = FALSE;
214 break;
215
216 /* Dispatch IRPs are immediately returned */
217 case IRP_DISPATCH:
218 return Status;
219
220 /* There aren't any other dispatch styles! */
221 default:
222 ASSERT(FALSE);
223 return Status;
224 }
225 }
226
227 /* Pending IRPs are returned immediately */
228 if (Status == STATUS_PENDING) return Status;
229
230 /* Handled IRPs return their status in the status block */
231 if (Status != STATUS_NOT_SUPPORTED) Irp->IoStatus.Status = Status;
232
233 /* Successful, or unhandled IRPs that are "DOWNWARD" are sent to the PDO */
234 if ((PassToPdo) && ((NT_SUCCESS(Status)) || (Status == STATUS_NOT_SUPPORTED)))
235 {
236 /* Let the PDO deal with it */
237 Status = PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
238 }
239 else
240 {
241 /* Otherwise, the IRP is returned with its status */
242 Status = Irp->IoStatus.Status;
243
244 /* Power IRPs need to notify the Power Manager that the next IRP can go */
245 if (IoStackLocation->MajorFunction == IRP_MJ_POWER) PoStartNextPowerIrp(Irp);
246
247 /* And now this IRP can be completed */
248 IofCompleteRequest(Irp, IO_NO_INCREMENT);
249 }
250
251 /* And the status returned back to the caller */
252 return Status;
253 }
254
255 NTSTATUS
256 NTAPI
257 PciIrpNotSupported(IN PIRP Irp,
258 IN PIO_STACK_LOCATION IoStackLocation,
259 IN PPCI_FDO_EXTENSION DeviceExtension)
260 {
261 /* Not supported */
262 DPRINT1("WARNING: PCI received unsupported IRP!\n");
263 //DbgBreakPoint();
264 return STATUS_NOT_SUPPORTED;
265 }
266
267 NTSTATUS
268 NTAPI
269 PciIrpInvalidDeviceRequest(IN PIRP Irp,
270 IN PIO_STACK_LOCATION IoStackLocation,
271 IN PPCI_FDO_EXTENSION DeviceExtension)
272 {
273 /* Not supported */
274 return STATUS_INVALID_DEVICE_REQUEST;
275 }
276
277 /* EOF */