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