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