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     Status = Irp->IoStatus.Status;
163     IoCompleteRequest(Irp, IO_NO_INCREMENT);
164     return Status;
165 }
166 
167 VOID
168 CALLBACK
169 PwrCompletionFunction(
170     IN PDEVICE_OBJECT DeviceObject,
171     IN UCHAR MinorFunction,
172     IN POWER_STATE PowerState,
173     IN PVOID Context,
174     IN PIO_STATUS_BLOCK IoStatus)
175 {
176     NTSTATUS Status;
177     PQUERY_POWER_CONTEXT PwrContext = (PQUERY_POWER_CONTEXT)Context;
178 
179     if (NT_SUCCESS(IoStatus->Status))
180     {
181         // forward request to lower device object
182         Status = PcForwardIrpSynchronous(PwrContext->DeviceObject, PwrContext->Irp);
183     }
184     else
185     {
186         // failed
187         Status = IoStatus->Status;
188     }
189 
190     // start next power irp
191     PoStartNextPowerIrp(PwrContext->Irp);
192 
193     // complete request
194     PwrContext->Irp->IoStatus.Status = Status;
195     IoCompleteRequest(PwrContext->Irp, IO_NO_INCREMENT);
196 
197     // free context
198     FreeItem(PwrContext, TAG_PORTCLASS);
199 }
200 
201 
202 NTSTATUS
203 NTAPI
204 PortClsPower(
205     IN  PDEVICE_OBJECT DeviceObject,
206     IN  PIRP Irp)
207 {
208     PIO_STACK_LOCATION IoStack;
209     PPCLASS_DEVICE_EXTENSION DeviceExtension;
210     PQUERY_POWER_CONTEXT PwrContext;
211     POWER_STATE PowerState;
212     NTSTATUS Status = STATUS_SUCCESS;
213 
214     DPRINT("PortClsPower called\n");
215 
216     // get currrent stack location
217     IoStack = IoGetCurrentIrpStackLocation(Irp);
218 
219     if (IoStack->MinorFunction != IRP_MN_SET_POWER && IoStack->MinorFunction != IRP_MN_QUERY_POWER)
220     {
221         // just forward the request
222         Status = PcForwardIrpSynchronous(DeviceObject, Irp);
223 
224         // start next power irp
225         PoStartNextPowerIrp(Irp);
226 
227         // complete request
228         Irp->IoStatus.Status = Status;
229         IoCompleteRequest(Irp, IO_NO_INCREMENT);
230 
231         // done
232         return Status;
233     }
234 
235 
236     // get device extension
237     DeviceExtension = (PPCLASS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
238 
239     // get current request type
240     if (IoStack->Parameters.Power.Type == DevicePowerState)
241     {
242         // request for device power state
243         if (DeviceExtension->DevicePowerState == IoStack->Parameters.Power.State.DeviceState)
244         {
245             // nothing has changed
246             if (IoStack->MinorFunction == IRP_MN_QUERY_POWER)
247             {
248                 // only forward query requests
249                 Status = PcForwardIrpSynchronous(DeviceObject, Irp);
250             }
251 
252             // start next power irp
253             PoStartNextPowerIrp(Irp);
254 
255             // complete request
256             Irp->IoStatus.Status = Status;
257             IoCompleteRequest(Irp, IO_NO_INCREMENT);
258 
259             // done
260             return Status;
261         }
262 
263         if (IoStack->MinorFunction == IRP_MN_QUERY_POWER)
264         {
265             // check if there is a registered adapter power management
266             if (DeviceExtension->AdapterPowerManagement)
267             {
268                 // it is query if the change can be changed
269                 PowerState = *((POWER_STATE*)&IoStack->Parameters.Power.State.DeviceState);
270                 Status = DeviceExtension->AdapterPowerManagement->QueryPowerChangeState(PowerState);
271 
272                 // sanity check
273                 PC_ASSERT(Status == STATUS_SUCCESS);
274             }
275 
276             // only forward query requests
277             PcForwardIrpSynchronous(DeviceObject, Irp);
278 
279             // start next power irp
280             PoStartNextPowerIrp(Irp);
281 
282             // complete request
283             Irp->IoStatus.Status = Status;
284             IoCompleteRequest(Irp, IO_NO_INCREMENT);
285 
286             // done
287             return Status;
288         }
289         else
290         {
291             // set power state
292             PowerState = *((POWER_STATE*)&IoStack->Parameters.Power.State.DeviceState);
293             PoSetPowerState(DeviceObject, DevicePowerState, PowerState);
294 
295             // check if there is a registered adapter power management
296             if (DeviceExtension->AdapterPowerManagement)
297             {
298                 // notify of a power change state
299                 DeviceExtension->AdapterPowerManagement->PowerChangeState(PowerState);
300             }
301 
302             // FIXME call all registered IPowerNotify interfaces via ISubdevice interface
303 
304             // store new power state
305            DeviceExtension->DevicePowerState = IoStack->Parameters.Power.State.DeviceState;
306 
307             // complete request
308             Irp->IoStatus.Status = Status;
309             IoCompleteRequest(Irp, IO_NO_INCREMENT);
310 
311             // done
312             return Status;
313         }
314     }
315     else
316     {
317         // sanity check
318         PC_ASSERT(IoStack->Parameters.Power.Type == SystemPowerState);
319 
320         if (IoStack->MinorFunction == IRP_MN_QUERY_POWER)
321         {
322             // mark irp as pending
323             IoMarkIrpPending(Irp);
324 
325             // allocate power completion context
326             PwrContext = (PQUERY_POWER_CONTEXT)AllocateItem(NonPagedPool, sizeof(QUERY_POWER_CONTEXT), TAG_PORTCLASS);
327 
328             if (!PwrContext)
329             {
330                 // no memory
331                 PoStartNextPowerIrp(Irp);
332 
333                 // complete and forget
334                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
335                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
336 
337                 // done
338                 return Status;
339             }
340 
341             // setup power context
342             PwrContext->Irp = Irp;
343             PwrContext->DeviceObject = DeviceObject;
344 
345             // pass the irp down
346             PowerState = *((POWER_STATE*)IoStack->Parameters.Power.State.SystemState);
347             Status = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject, IoStack->MinorFunction, PowerState, PwrCompletionFunction, (PVOID)PwrContext, NULL);
348 
349             // check for success
350             if (!NT_SUCCESS(Status))
351             {
352                 // failed
353                 Irp->IoStatus.Status = Status;
354                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
355 
356                 // done
357                 return Status;
358             }
359 
360             // done
361             return STATUS_PENDING;
362         }
363         else
364         {
365             // set power request
366             DeviceExtension->SystemPowerState = IoStack->Parameters.Power.State.SystemState;
367 
368             // only forward query requests
369             Status = PcForwardIrpSynchronous(DeviceObject, Irp);
370 
371             // start next power irp
372             PoStartNextPowerIrp(Irp);
373 
374             // complete request
375             Irp->IoStatus.Status = Status;
376             IoCompleteRequest(Irp, IO_NO_INCREMENT);
377 
378             // done
379             return Status;
380         }
381     }
382 }
383 
384 NTSTATUS
385 NTAPI
386 PortClsSysControl(
387     IN  PDEVICE_OBJECT DeviceObject,
388     IN  PIRP Irp)
389 {
390     DPRINT("PortClsSysControl called\n");
391 
392     // TODO
393 
394     Irp->IoStatus.Status = STATUS_SUCCESS;
395     Irp->IoStatus.Information = 0;
396     IoCompleteRequest(Irp, IO_NO_INCREMENT);
397 
398     return STATUS_SUCCESS;
399 }
400 
401 NTSTATUS
402 NTAPI
403 PortClsShutdown(
404     IN  PDEVICE_OBJECT DeviceObject,
405     IN  PIRP Irp)
406 {
407     PPCLASS_DEVICE_EXTENSION DeviceExtension;
408     DPRINT("PortClsShutdown called\n");
409 
410     // get device extension
411     DeviceExtension = (PPCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
412 
413     if (DeviceExtension->AdapterPowerManagement)
414     {
415         // release adapter power management
416         DPRINT("Power %u\n", DeviceExtension->AdapterPowerManagement->Release());
417     }
418 
419     Irp->IoStatus.Status = STATUS_SUCCESS;
420     Irp->IoStatus.Information = 0;
421     IoCompleteRequest(Irp, IO_NO_INCREMENT);
422 
423     return STATUS_SUCCESS;
424 }
425 
426 NTSTATUS
427 NTAPI
428 PcDispatchIrp(
429     IN  PDEVICE_OBJECT DeviceObject,
430     IN  PIRP Irp)
431 {
432     PIO_STACK_LOCATION IoStack;
433 
434     IoStack = IoGetCurrentIrpStackLocation(Irp);
435 
436     DPRINT("PcDispatchIrp called - handling IRP in PortCls MajorFunction %x MinorFunction %x\n", IoStack->MajorFunction, IoStack->MinorFunction);
437 
438     switch ( IoStack->MajorFunction )
439     {
440         // PortCls
441         case IRP_MJ_CREATE :
442             return PortClsCreate(DeviceObject, Irp);
443 
444         case IRP_MJ_PNP :
445             return PortClsPnp(DeviceObject, Irp);
446 
447         case IRP_MJ_POWER :
448             return PortClsPower(DeviceObject, Irp);
449 
450         case IRP_MJ_DEVICE_CONTROL:
451             return KsDispatchIrp(DeviceObject, Irp);
452 
453         case IRP_MJ_CLOSE:
454             return KsDispatchIrp(DeviceObject, Irp);
455 
456         case IRP_MJ_SYSTEM_CONTROL :
457             return PortClsSysControl(DeviceObject, Irp);
458 
459         case IRP_MJ_SHUTDOWN:
460             return PortClsShutdown(DeviceObject, Irp);
461 
462         default:
463             DPRINT("Unhandled function %x\n", IoStack->MajorFunction);
464             break;
465     };
466 
467     // If we reach here, we just complete the IRP
468     Irp->IoStatus.Status = STATUS_SUCCESS;
469     Irp->IoStatus.Information = 0;
470     IoCompleteRequest(Irp, IO_NO_INCREMENT);
471 
472     return STATUS_SUCCESS;
473 }
474 
475 
476 NTSTATUS
477 NTAPI
478 PcCompleteIrp(
479     IN  PDEVICE_OBJECT DeviceObject,
480     IN  PIRP Irp,
481     IN  NTSTATUS Status)
482 {
483 #if 0
484     PC_ASSERT(DeviceObject);
485     PC_ASSERT(Irp);
486     PC_ASSERT(Status != STATUS_PENDING);
487 #endif
488 
489     Irp->IoStatus.Status = Status;
490     IoCompleteRequest(Irp, IO_NO_INCREMENT);
491 
492     return Status;
493 }
494 
495 NTSTATUS
496 NTAPI
497 CompletionRoutine(
498     IN PDEVICE_OBJECT  DeviceObject,
499     IN PIRP  Irp,
500     IN PVOID  Context)
501 {
502     if (Irp->PendingReturned == TRUE)
503     {
504         KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
505     }
506     return STATUS_MORE_PROCESSING_REQUIRED;
507 }
508 
509 #undef IoSetCompletionRoutine
510 #define IoSetCompletionRoutine(_Irp, \
511                                _CompletionRoutine, \
512                                _Context, \
513                                _InvokeOnSuccess, \
514                                _InvokeOnError, \
515                                _InvokeOnCancel) \
516 { \
517   PIO_STACK_LOCATION _IrpSp; \
518   _IrpSp = IoGetNextIrpStackLocation(_Irp); \
519   _IrpSp->CompletionRoutine = (PIO_COMPLETION_ROUTINE)(_CompletionRoutine); \
520   _IrpSp->Context = (_Context); \
521   _IrpSp->Control = 0; \
522   if (_InvokeOnSuccess) _IrpSp->Control = SL_INVOKE_ON_SUCCESS; \
523   if (_InvokeOnError) _IrpSp->Control |= SL_INVOKE_ON_ERROR; \
524   if (_InvokeOnCancel) _IrpSp->Control |= SL_INVOKE_ON_CANCEL; \
525 }
526 
527 
528 
529 NTSTATUS
530 NTAPI
531 PcForwardIrpSynchronous(
532     IN  PDEVICE_OBJECT DeviceObject,
533     IN  PIRP Irp)
534 {
535     KEVENT Event;
536     PPCLASS_DEVICE_EXTENSION DeviceExt;
537     NTSTATUS Status;
538 
539     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
540 
541     DeviceExt = (PPCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
542 
543     // initialize the notification event
544     KeInitializeEvent(&Event, NotificationEvent, FALSE);
545 
546     IoCopyCurrentIrpStackLocationToNext(Irp);
547 
548     IoSetCompletionRoutine(Irp, CompletionRoutine, (PVOID)&Event, TRUE, TRUE, TRUE);
549 
550     // now call the driver
551     Status = IoCallDriver(DeviceExt->PrevDeviceObject, Irp);
552     // did the request complete yet
553     if (Status == STATUS_PENDING)
554     {
555         // not yet, lets wait a bit
556         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
557         Status = Irp->IoStatus.Status;
558     }
559     return Status;
560 }
561