a2111cb1abebb482140ac593fedf10b5dbbf0a9d
[reactos.git] / reactos / drivers / wdm / audio / backpln / portcls / irp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS
4 * FILE: drivers/wdm/audio/backpln/portcls/irp.c
5 * PURPOSE: Port Class driver / IRP Handling
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 * HISTORY:
9 * 27 Jan 07 Created
10 */
11
12
13 #include "private.h"
14 #include <portcls.h>
15
16 /*
17 Handles IRP_MJ_CREATE, which occurs when someone wants to make use of
18 a device.
19 */
20 NTSTATUS
21 NTAPI
22 PortClsCreate(
23 IN PDEVICE_OBJECT DeviceObject,
24 IN PIRP Irp)
25 {
26 DPRINT("PortClsCreate called\n");
27
28 return KsDispatchIrp(DeviceObject, Irp);
29 }
30
31
32 /*
33 IRP_MJ_PNP handler
34 Used for things like IRP_MN_START_DEVICE
35 */
36 NTSTATUS
37 NTAPI
38 PortClsPnp(
39 IN PDEVICE_OBJECT DeviceObject,
40 IN PIRP Irp)
41 {
42 NTSTATUS Status;
43 PPCLASS_DEVICE_EXTENSION DeviceExt;
44 PIO_STACK_LOCATION IoStack;
45 IResourceList* resource_list = NULL;
46
47 DPRINT("PortClsPnp called\n");
48
49 DeviceExt = (PPCLASS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
50 IoStack = IoGetCurrentIrpStackLocation(Irp);
51
52 ASSERT(DeviceExt);
53
54 /*
55 if IRP_MN_START_DEVICE, call the driver's customer start device routine.
56 Before we do so, we must create a ResourceList to pass to the Start
57 routine.
58 */
59 switch (IoStack->MinorFunction)
60 {
61 case IRP_MN_START_DEVICE:
62 DPRINT("IRP_MN_START_DEVICE\n");
63
64 /* Create the resource list */
65 Status = PcNewResourceList(
66 &resource_list,
67 NULL,
68 PagedPool,
69 IoStack->Parameters.StartDevice.AllocatedResourcesTranslated,
70 IoStack->Parameters.StartDevice.AllocatedResources);
71 if (!NT_SUCCESS(Status))
72 {
73 DPRINT("PcNewResourceList failed [0x%8x]\n", Status);
74 Irp->IoStatus.Status = Status;
75 IoCompleteRequest(Irp, IO_NO_INCREMENT);
76 return Status;
77 }
78
79 /* forward irp to lower device object */
80 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
81
82 if (!NT_SUCCESS(Status))
83 {
84 /* lower device object failed to start */
85 resource_list->lpVtbl->Release(resource_list);
86 /* complete the request */
87 IoCompleteRequest(Irp, IO_NO_INCREMENT);
88 /* return result */
89 return Status;
90 }
91
92 /* sanity check */
93 ASSERT(DeviceExt->StartDevice);
94 /* Call the StartDevice routine */
95 DPRINT("Calling StartDevice at 0x%8p\n", DeviceExt->StartDevice);
96 Status = DeviceExt->StartDevice(DeviceObject, Irp, resource_list);
97 if (!NT_SUCCESS(Status))
98 {
99 DPRINT("StartDevice returned a failure code [0x%8x]\n", Status);
100 Irp->IoStatus.Status = Status;
101 IoCompleteRequest(Irp, IO_NO_INCREMENT);
102 return Status;
103 }
104
105 /* Assign the resource list to our extension */
106 DeviceExt->resources = resource_list;
107
108 Irp->IoStatus.Status = STATUS_SUCCESS;
109 IoCompleteRequest(Irp, IO_NO_INCREMENT);
110 return Status;
111
112 case IRP_MN_REMOVE_DEVICE:
113 /* Clean up */
114 DPRINT("IRP_MN_REMOVE_DEVICE\n");
115
116 DeviceExt->resources->lpVtbl->Release(DeviceExt->resources);
117 IoDeleteDevice(DeviceObject);
118
119 /* Do not complete? */
120 Irp->IoStatus.Status = STATUS_SUCCESS;
121 IoCompleteRequest(Irp, IO_NO_INCREMENT);
122 return STATUS_SUCCESS;
123
124 case IRP_MN_QUERY_INTERFACE:
125 DPRINT("IRP_MN_QUERY_INTERFACE\n");
126 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
127 return PcCompleteIrp(DeviceObject, Irp, Status);
128 case IRP_MN_QUERY_DEVICE_RELATIONS:
129 DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS\n");
130 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
131 return PcCompleteIrp(DeviceObject, Irp, Status);
132 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
133 DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
134 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
135 return PcCompleteIrp(DeviceObject, Irp, Status);
136 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
137 DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
138 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
139 return PcCompleteIrp(DeviceObject, Irp, Status);
140 }
141
142 DPRINT1("unhandled function %u\n", IoStack->MinorFunction);
143
144 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
145 IoCompleteRequest(Irp, IO_NO_INCREMENT);
146 return STATUS_UNSUCCESSFUL;
147 }
148
149 /*
150 Power management. Handles IRP_MJ_POWER
151 (not implemented)
152 */
153 NTSTATUS
154 NTAPI
155 PortClsPower(
156 IN PDEVICE_OBJECT DeviceObject,
157 IN PIRP Irp)
158 {
159 DPRINT("PortClsPower called\n");
160
161 /* TODO */
162
163 Irp->IoStatus.Status = STATUS_SUCCESS;
164 Irp->IoStatus.Information = 0;
165 IoCompleteRequest(Irp, IO_NO_INCREMENT);
166
167 return STATUS_SUCCESS;
168 }
169
170 /*
171 System control. Handles IRP_MJ_SYSTEM_CONTROL
172 (not implemented)
173 */
174 NTSTATUS
175 NTAPI
176 PortClsSysControl(
177 IN PDEVICE_OBJECT DeviceObject,
178 IN PIRP Irp)
179 {
180 DPRINT("PortClsSysControl called\n");
181
182 /* TODO */
183
184 Irp->IoStatus.Status = STATUS_SUCCESS;
185 Irp->IoStatus.Information = 0;
186 IoCompleteRequest(Irp, IO_NO_INCREMENT);
187
188 return STATUS_SUCCESS;
189 }
190
191 NTSTATUS
192 NTAPI
193 PortClsShutdown(
194 IN PDEVICE_OBJECT DeviceObject,
195 IN PIRP Irp)
196 {
197 PPCLASS_DEVICE_EXTENSION DeviceExtension;
198 PLIST_ENTRY Entry;
199 PPHYSICAL_CONNECTION Connection;
200 DPRINT("PortClsShutdown called\n");
201
202 /* get device extension */
203 DeviceExtension = (PPCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
204
205 while(!IsListEmpty(&DeviceExtension->PhysicalConnectionList))
206 {
207 /* get connection entry */
208 Entry = RemoveHeadList(&DeviceExtension->PhysicalConnectionList);
209 Connection = (PPHYSICAL_CONNECTION)CONTAINING_RECORD(Entry, PHYSICAL_CONNECTION, Entry);
210
211 if (Connection->FromSubDevice)
212 {
213 /* release subdevice */
214 Connection->FromSubDevice->lpVtbl->Release(Connection->FromSubDevice);
215 }
216
217 if (Connection->ToSubDevice)
218 {
219 /* release subdevice */
220 Connection->ToSubDevice->lpVtbl->Release(Connection->ToSubDevice);
221 }
222 FreeItem(Connection, TAG_PORTCLASS);
223 }
224
225 if (DeviceExtension->AdapterPowerManagement)
226 {
227 /* release adapter power management */
228 DPRINT1("Power %u\n", DeviceExtension->AdapterPowerManagement->lpVtbl->Release(DeviceExtension->AdapterPowerManagement));
229 }
230
231 Irp->IoStatus.Status = STATUS_SUCCESS;
232 Irp->IoStatus.Information = 0;
233 IoCompleteRequest(Irp, IO_NO_INCREMENT);
234
235 return STATUS_SUCCESS;
236 }
237
238
239
240 /*
241 ==========================================================================
242 API EXPORTS
243 ==========================================================================
244 */
245
246 /*
247 Drivers may implement their own IRP handlers. If a driver decides to let
248 PortCls handle the IRP, it can do so by calling this.
249 */
250 NTSTATUS NTAPI
251 PcDispatchIrp(
252 IN PDEVICE_OBJECT DeviceObject,
253 IN PIRP Irp)
254 {
255 PIO_STACK_LOCATION IoStack;
256
257 DPRINT("PcDispatchIrp called - handling IRP in PortCls\n");
258
259 IoStack = IoGetCurrentIrpStackLocation(Irp);
260
261 switch ( IoStack->MajorFunction )
262 {
263 /* PortCls */
264 case IRP_MJ_CREATE :
265 return PortClsCreate(DeviceObject, Irp);
266
267 case IRP_MJ_PNP :
268 return PortClsPnp(DeviceObject, Irp);
269
270 case IRP_MJ_POWER :
271 return PortClsPower(DeviceObject, Irp);
272
273 case IRP_MJ_DEVICE_CONTROL:
274 return KsDispatchIrp(DeviceObject, Irp);
275
276 case IRP_MJ_CLOSE:
277 return KsDispatchIrp(DeviceObject, Irp);
278
279 case IRP_MJ_SYSTEM_CONTROL :
280 return PortClsSysControl(DeviceObject, Irp);
281
282 case IRP_MJ_SHUTDOWN:
283 return PortClsShutdown(DeviceObject, Irp);
284
285 default:
286 DPRINT1("Unhandled function %x\n", IoStack->MajorFunction);
287 break;
288 };
289
290 /* If we reach here, we just complete the IRP */
291 Irp->IoStatus.Status = STATUS_SUCCESS;
292 Irp->IoStatus.Information = 0;
293 IoCompleteRequest(Irp, IO_NO_INCREMENT);
294
295 return STATUS_SUCCESS;
296 }
297
298 /*
299 * @implemented
300 */
301 NTSTATUS
302 NTAPI
303 PcCompleteIrp(
304 IN PDEVICE_OBJECT DeviceObject,
305 IN PIRP Irp,
306 IN NTSTATUS Status)
307 {
308 ASSERT(DeviceObject);
309 ASSERT(Irp);
310 ASSERT(Status != STATUS_PENDING);
311
312 Irp->IoStatus.Status = Status;
313 IoCompleteRequest(Irp, IO_NO_INCREMENT);
314
315 return Status;
316 }
317
318 NTSTATUS
319 NTAPI
320 CompletionRoutine(
321 IN PDEVICE_OBJECT DeviceObject,
322 IN PIRP Irp,
323 IN PVOID Context)
324 {
325 if (Irp->PendingReturned == TRUE)
326 {
327 KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
328 }
329 return STATUS_MORE_PROCESSING_REQUIRED;
330 }
331
332
333 /*
334 * @implemented
335 */
336 NTSTATUS NTAPI
337 PcForwardIrpSynchronous(
338 IN PDEVICE_OBJECT DeviceObject,
339 IN PIRP Irp)
340 {
341 KEVENT Event;
342 PPCLASS_DEVICE_EXTENSION DeviceExt;
343 NTSTATUS Status;
344
345 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
346
347 DeviceExt = (PPCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
348
349 /* initialize the notification event */
350 KeInitializeEvent(&Event, NotificationEvent, FALSE);
351
352 IoCopyCurrentIrpStackLocationToNext(Irp);
353
354 IoSetCompletionRoutine(Irp, CompletionRoutine, (PVOID)&Event, TRUE, TRUE, TRUE);
355
356 /* now call the driver */
357 Status = IoCallDriver(DeviceExt->PrevDeviceObject, Irp);
358 /* did the request complete yet */
359 if (Status == STATUS_PENDING)
360 {
361 /* not yet, lets wait a bit */
362 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
363 Status = Irp->IoStatus.Status;
364 }
365 return Status;
366 }