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
PortClsCreate(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
PortClsPnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
PwrCompletionFunction(IN PDEVICE_OBJECT DeviceObject,IN UCHAR MinorFunction,IN POWER_STATE PowerState,IN PVOID Context,IN PIO_STATUS_BLOCK IoStatus)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
PortClsPower(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
PortClsSysControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
PortClsShutdown(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
PcDispatchIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
PcCompleteIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN NTSTATUS Status)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
CompletionRoutine(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)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
PcForwardIrpSynchronous(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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