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