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