Sync to trunk head (r47736)
[reactos.git] / drivers / wdm / audio / backpln / portcls / irp.cpp
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS
4 * FILE: drivers/wdm/audio/backpln/portcls/irp.cpp
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.hpp"
14
15 typedef struct
16 {
17 PIRP Irp;
18 PDEVICE_OBJECT DeviceObject;
19 }QUERY_POWER_CONTEXT, *PQUERY_POWER_CONTEXT;
20
21
22 NTSTATUS
23 NTAPI
24 PortClsCreate(
25 IN PDEVICE_OBJECT DeviceObject,
26 IN PIRP Irp)
27 {
28 DPRINT("PortClsCreate called\n");
29
30 return KsDispatchIrp(DeviceObject, Irp);
31 }
32
33
34 NTSTATUS
35 NTAPI
36 PortClsPnp(
37 IN PDEVICE_OBJECT DeviceObject,
38 IN PIRP Irp)
39 {
40 NTSTATUS Status;
41 PPCLASS_DEVICE_EXTENSION DeviceExt;
42 PIO_STACK_LOCATION IoStack;
43 POWER_STATE PowerState;
44 IResourceList* resource_list = NULL;
45 //ULONG Index;
46 //PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor, UnPartialDescriptor;
47
48 DeviceExt = (PPCLASS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
49 IoStack = IoGetCurrentIrpStackLocation(Irp);
50
51
52 DPRINT("PortClsPnp called %u\n", IoStack->MinorFunction);
53
54 //PC_ASSERT(DeviceExt);
55
56 switch (IoStack->MinorFunction)
57 {
58 case IRP_MN_START_DEVICE:
59 DPRINT("IRP_MN_START_DEVICE\n");
60
61 // Create the resource list
62 Status = PcNewResourceList(
63 &resource_list,
64 NULL,
65 PagedPool,
66 IoStack->Parameters.StartDevice.AllocatedResourcesTranslated,
67 IoStack->Parameters.StartDevice.AllocatedResources);
68 if (!NT_SUCCESS(Status))
69 {
70 DPRINT("PcNewResourceList failed [0x%8x]\n", Status);
71 Irp->IoStatus.Status = Status;
72 IoCompleteRequest(Irp, IO_NO_INCREMENT);
73 return Status;
74 }
75
76 // forward irp to lower device object
77 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
78
79 if (!NT_SUCCESS(Status))
80 {
81 // lower device object failed to start
82 resource_list->Release();
83 // complete the request
84 IoCompleteRequest(Irp, IO_NO_INCREMENT);
85 // return result
86 return Status;
87 }
88
89 // sanity check
90 //PC_ASSERT(DeviceExt->StartDevice);
91 // Call the StartDevice routine
92 DPRINT("Calling StartDevice at 0x%8p\n", DeviceExt->StartDevice);
93 Status = DeviceExt->StartDevice(DeviceObject, Irp, resource_list);
94 if (!NT_SUCCESS(Status))
95 {
96 DPRINT("StartDevice returned a failure code [0x%8x]\n", Status);
97 Irp->IoStatus.Status = Status;
98 IoCompleteRequest(Irp, IO_NO_INCREMENT);
99 return Status;
100 }
101
102 // Assign the resource list to our extension
103 DeviceExt->resources = resource_list;
104
105 // store device power state
106 DeviceExt->DevicePowerState = PowerDeviceD0;
107 DeviceExt->SystemPowerState = PowerSystemWorking;
108
109 // notify power manager of current state
110 PowerState = *((POWER_STATE*)&DeviceExt->DevicePowerState);
111 PoSetPowerState(DeviceObject, DevicePowerState, PowerState);
112
113 Irp->IoStatus.Status = STATUS_SUCCESS;
114 IoCompleteRequest(Irp, IO_NO_INCREMENT);
115 return Status;
116
117 case IRP_MN_REMOVE_DEVICE:
118 // Clean up
119 DPRINT("IRP_MN_REMOVE_DEVICE\n");
120
121 // sanity check
122 PC_ASSERT(DeviceExt);
123
124 // FIXME more cleanup */
125 if (DeviceExt->resources)
126 {
127 // free resource list */
128 DeviceExt->resources->Release();
129
130 // set to null
131 DeviceExt->resources = NULL;
132 }
133
134 // Forward request
135 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
136
137 return PcCompleteIrp(DeviceObject, Irp, Status);
138
139 case IRP_MN_QUERY_INTERFACE:
140 DPRINT("IRP_MN_QUERY_INTERFACE\n");
141 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
142 return PcCompleteIrp(DeviceObject, Irp, Status);
143 case IRP_MN_QUERY_DEVICE_RELATIONS:
144 DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS\n");
145 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
146 return PcCompleteIrp(DeviceObject, Irp, Status);
147 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
148 DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
149 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
150 return PcCompleteIrp(DeviceObject, Irp, Status);
151 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
152 DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
153 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
154 return PcCompleteIrp(DeviceObject, Irp, Status);
155 case IRP_MN_READ_CONFIG:
156 DPRINT("IRP_MN_READ_CONFIG\n");
157 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
158 return PcCompleteIrp(DeviceObject, Irp, Status);
159 }
160
161 DPRINT("unhandled function %u\n", IoStack->MinorFunction);
162
163 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
164 IoCompleteRequest(Irp, IO_NO_INCREMENT);
165 return STATUS_UNSUCCESSFUL;
166 }
167
168 VOID
169 CALLBACK
170 PwrCompletionFunction(
171 IN PDEVICE_OBJECT DeviceObject,
172 IN UCHAR MinorFunction,
173 IN POWER_STATE PowerState,
174 IN PVOID Context,
175 IN PIO_STATUS_BLOCK IoStatus)
176 {
177 NTSTATUS Status;
178 PQUERY_POWER_CONTEXT PwrContext = (PQUERY_POWER_CONTEXT)Context;
179
180 if (NT_SUCCESS(IoStatus->Status))
181 {
182 // forward request to lower device object
183 Status = PcForwardIrpSynchronous(PwrContext->DeviceObject, PwrContext->Irp);
184 }
185 else
186 {
187 // failed
188 Status = IoStatus->Status;
189 }
190
191 // start next power irp
192 PoStartNextPowerIrp(PwrContext->Irp);
193
194 // complete request
195 PwrContext->Irp->IoStatus.Status = Status;
196 IoCompleteRequest(PwrContext->Irp, IO_NO_INCREMENT);
197
198 // free context
199 FreeItem(PwrContext, TAG_PORTCLASS);
200 }
201
202
203 NTSTATUS
204 NTAPI
205 PortClsPower(
206 IN PDEVICE_OBJECT DeviceObject,
207 IN PIRP Irp)
208 {
209 PIO_STACK_LOCATION IoStack;
210 PPCLASS_DEVICE_EXTENSION DeviceExtension;
211 PQUERY_POWER_CONTEXT PwrContext;
212 POWER_STATE PowerState;
213 NTSTATUS Status = STATUS_SUCCESS;
214
215 DPRINT("PortClsPower called\n");
216
217 // get currrent stack location
218 IoStack = IoGetCurrentIrpStackLocation(Irp);
219
220 if (IoStack->MinorFunction != IRP_MN_SET_POWER && IoStack->MinorFunction != IRP_MN_QUERY_POWER)
221 {
222 // just forward the request
223 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
224
225 // start next power irp
226 PoStartNextPowerIrp(Irp);
227
228 // complete request
229 Irp->IoStatus.Status = Status;
230 IoCompleteRequest(Irp, IO_NO_INCREMENT);
231
232 // done
233 return Status;
234 }
235
236
237 // get device extension
238 DeviceExtension = (PPCLASS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
239
240 // get current request type
241 if (IoStack->Parameters.Power.Type == DevicePowerState)
242 {
243 // request for device power state
244 if (DeviceExtension->DevicePowerState == IoStack->Parameters.Power.State.DeviceState)
245 {
246 // nothing has changed
247 if (IoStack->MinorFunction == IRP_MN_QUERY_POWER)
248 {
249 // only forward query requests
250 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
251 }
252
253 // start next power irp
254 PoStartNextPowerIrp(Irp);
255
256 // complete request
257 Irp->IoStatus.Status = Status;
258 IoCompleteRequest(Irp, IO_NO_INCREMENT);
259
260 // done
261 return Status;
262 }
263
264 if (IoStack->MinorFunction == IRP_MN_QUERY_POWER)
265 {
266 // check if there is a registered adapter power management
267 if (DeviceExtension->AdapterPowerManagement)
268 {
269 // it is query if the change can be changed
270 PowerState = *((POWER_STATE*)&IoStack->Parameters.Power.State.DeviceState);
271 Status = DeviceExtension->AdapterPowerManagement->QueryPowerChangeState(PowerState);
272
273 // sanity check
274 PC_ASSERT(Status == STATUS_SUCCESS);
275 }
276
277 // only forward query requests
278 PcForwardIrpSynchronous(DeviceObject, Irp);
279
280 // start next power irp
281 PoStartNextPowerIrp(Irp);
282
283 // complete request
284 Irp->IoStatus.Status = Status;
285 IoCompleteRequest(Irp, IO_NO_INCREMENT);
286
287 // done
288 return Status;
289 }
290 else
291 {
292 // set power state
293 PowerState = *((POWER_STATE*)&IoStack->Parameters.Power.State.DeviceState);
294 PoSetPowerState(DeviceObject, DevicePowerState, PowerState);
295
296 // check if there is a registered adapter power management
297 if (DeviceExtension->AdapterPowerManagement)
298 {
299 // notify of a power change state
300 DeviceExtension->AdapterPowerManagement->PowerChangeState(PowerState);
301 }
302
303 // FIXME call all registered IPowerNotify interfaces via ISubdevice interface
304
305 // store new power state
306 DeviceExtension->DevicePowerState = IoStack->Parameters.Power.State.DeviceState;
307
308 // complete request
309 Irp->IoStatus.Status = Status;
310 IoCompleteRequest(Irp, IO_NO_INCREMENT);
311
312 // done
313 return Status;
314 }
315 }
316 else
317 {
318 // sanity check
319 PC_ASSERT(IoStack->Parameters.Power.Type == SystemPowerState);
320
321 if (IoStack->MinorFunction == IRP_MN_QUERY_POWER)
322 {
323 // mark irp as pending
324 IoMarkIrpPending(Irp);
325
326 // allocate power completion context
327 PwrContext = (PQUERY_POWER_CONTEXT)AllocateItem(NonPagedPool, sizeof(QUERY_POWER_CONTEXT), TAG_PORTCLASS);
328
329 if (!PwrContext)
330 {
331 // no memory
332 PoStartNextPowerIrp(Irp);
333
334 // complete and forget
335 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
336 IoCompleteRequest(Irp, IO_NO_INCREMENT);
337
338 // done
339 return Status;
340 }
341
342 // setup power context
343 PwrContext->Irp = Irp;
344 PwrContext->DeviceObject = DeviceObject;
345
346 // pass the irp down
347 PowerState = *((POWER_STATE*)IoStack->Parameters.Power.State.SystemState);
348 Status = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject, IoStack->MinorFunction, PowerState, PwrCompletionFunction, (PVOID)PwrContext, NULL);
349
350 // check for success
351 if (!NT_SUCCESS(Status))
352 {
353 // failed
354 Irp->IoStatus.Status = Status;
355 IoCompleteRequest(Irp, IO_NO_INCREMENT);
356
357 // done
358 return Status;
359 }
360
361 // done
362 return STATUS_PENDING;
363 }
364 else
365 {
366 // set power request
367 DeviceExtension->SystemPowerState = IoStack->Parameters.Power.State.SystemState;
368
369 // only forward query requests
370 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
371
372 // start next power irp
373 PoStartNextPowerIrp(Irp);
374
375 // complete request
376 Irp->IoStatus.Status = Status;
377 IoCompleteRequest(Irp, IO_NO_INCREMENT);
378
379 // done
380 return Status;
381 }
382 }
383 }
384
385 NTSTATUS
386 NTAPI
387 PortClsSysControl(
388 IN PDEVICE_OBJECT DeviceObject,
389 IN PIRP Irp)
390 {
391 DPRINT("PortClsSysControl called\n");
392
393 // TODO
394
395 Irp->IoStatus.Status = STATUS_SUCCESS;
396 Irp->IoStatus.Information = 0;
397 IoCompleteRequest(Irp, IO_NO_INCREMENT);
398
399 return STATUS_SUCCESS;
400 }
401
402 NTSTATUS
403 NTAPI
404 PortClsShutdown(
405 IN PDEVICE_OBJECT DeviceObject,
406 IN PIRP Irp)
407 {
408 PPCLASS_DEVICE_EXTENSION DeviceExtension;
409 DPRINT("PortClsShutdown called\n");
410
411 // get device extension
412 DeviceExtension = (PPCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
413
414 if (DeviceExtension->AdapterPowerManagement)
415 {
416 // release adapter power management
417 DPRINT("Power %u\n", DeviceExtension->AdapterPowerManagement->Release());
418 }
419
420 Irp->IoStatus.Status = STATUS_SUCCESS;
421 Irp->IoStatus.Information = 0;
422 IoCompleteRequest(Irp, IO_NO_INCREMENT);
423
424 return STATUS_SUCCESS;
425 }
426
427 NTSTATUS
428 NTAPI
429 PcDispatchIrp(
430 IN PDEVICE_OBJECT DeviceObject,
431 IN PIRP Irp)
432 {
433 PIO_STACK_LOCATION IoStack;
434
435 IoStack = IoGetCurrentIrpStackLocation(Irp);
436
437 DPRINT("PcDispatchIrp called - handling IRP in PortCls MajorFunction %x MinorFunction %x\n", IoStack->MajorFunction, IoStack->MinorFunction);
438
439 switch ( IoStack->MajorFunction )
440 {
441 // PortCls
442 case IRP_MJ_CREATE :
443 return PortClsCreate(DeviceObject, Irp);
444
445 case IRP_MJ_PNP :
446 return PortClsPnp(DeviceObject, Irp);
447
448 case IRP_MJ_POWER :
449 return PortClsPower(DeviceObject, Irp);
450
451 case IRP_MJ_DEVICE_CONTROL:
452 return KsDispatchIrp(DeviceObject, Irp);
453
454 case IRP_MJ_CLOSE:
455 return KsDispatchIrp(DeviceObject, Irp);
456
457 case IRP_MJ_SYSTEM_CONTROL :
458 return PortClsSysControl(DeviceObject, Irp);
459
460 case IRP_MJ_SHUTDOWN:
461 return PortClsShutdown(DeviceObject, Irp);
462
463 default:
464 DPRINT("Unhandled function %x\n", IoStack->MajorFunction);
465 break;
466 };
467
468 // If we reach here, we just complete the IRP
469 Irp->IoStatus.Status = STATUS_SUCCESS;
470 Irp->IoStatus.Information = 0;
471 IoCompleteRequest(Irp, IO_NO_INCREMENT);
472
473 return STATUS_SUCCESS;
474 }
475
476
477 NTSTATUS
478 NTAPI
479 PcCompleteIrp(
480 IN PDEVICE_OBJECT DeviceObject,
481 IN PIRP Irp,
482 IN NTSTATUS Status)
483 {
484 #if 0
485 PC_ASSERT(DeviceObject);
486 PC_ASSERT(Irp);
487 PC_ASSERT(Status != STATUS_PENDING);
488 #endif
489
490 Irp->IoStatus.Status = Status;
491 IoCompleteRequest(Irp, IO_NO_INCREMENT);
492
493 return Status;
494 }
495
496 NTSTATUS
497 NTAPI
498 CompletionRoutine(
499 IN PDEVICE_OBJECT DeviceObject,
500 IN PIRP Irp,
501 IN PVOID Context)
502 {
503 if (Irp->PendingReturned == TRUE)
504 {
505 KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
506 }
507 return STATUS_MORE_PROCESSING_REQUIRED;
508 }
509
510 #undef IoSetCompletionRoutine
511 #define IoSetCompletionRoutine(_Irp, \
512 _CompletionRoutine, \
513 _Context, \
514 _InvokeOnSuccess, \
515 _InvokeOnError, \
516 _InvokeOnCancel) \
517 { \
518 PIO_STACK_LOCATION _IrpSp; \
519 _IrpSp = IoGetNextIrpStackLocation(_Irp); \
520 _IrpSp->CompletionRoutine = (PIO_COMPLETION_ROUTINE)(_CompletionRoutine); \
521 _IrpSp->Context = (_Context); \
522 _IrpSp->Control = 0; \
523 if (_InvokeOnSuccess) _IrpSp->Control = SL_INVOKE_ON_SUCCESS; \
524 if (_InvokeOnError) _IrpSp->Control |= SL_INVOKE_ON_ERROR; \
525 if (_InvokeOnCancel) _IrpSp->Control |= SL_INVOKE_ON_CANCEL; \
526 }
527
528
529
530 NTSTATUS
531 NTAPI
532 PcForwardIrpSynchronous(
533 IN PDEVICE_OBJECT DeviceObject,
534 IN PIRP Irp)
535 {
536 KEVENT Event;
537 PPCLASS_DEVICE_EXTENSION DeviceExt;
538 NTSTATUS Status;
539
540 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
541
542 DeviceExt = (PPCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
543
544 // initialize the notification event
545 KeInitializeEvent(&Event, NotificationEvent, FALSE);
546
547 IoCopyCurrentIrpStackLocationToNext(Irp);
548
549 IoSetCompletionRoutine(Irp, CompletionRoutine, (PVOID)&Event, TRUE, TRUE, TRUE);
550
551 // now call the driver
552 Status = IoCallDriver(DeviceExt->PrevDeviceObject, Irp);
553 // did the request complete yet
554 if (Status == STATUS_PENDING)
555 {
556 // not yet, lets wait a bit
557 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
558 Status = Irp->IoStatus.Status;
559 }
560 return Status;
561 }