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 }
562