Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

361 lines
8.5 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. acpiirp.c
  5. Abstract:
  6. This module contains routines for simplifying IRP handling
  7. Author:
  8. Adrian J. Oney (AdriaO)
  9. Environment:
  10. NT Kernel Model Driver only
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, ACPIIrpInvokeDispatchRoutine)
  16. #pragma alloc_text(PAGE, ACPIIrpSetPagableCompletionRoutineAndForward)
  17. #pragma alloc_text(PAGE, ACPIIrpCompletionRoutineWorker)
  18. #endif
  19. NTSTATUS
  20. ACPIIrpInvokeDispatchRoutine(
  21. IN PDEVICE_OBJECT DeviceObject,
  22. IN PIRP Irp,
  23. IN PVOID Context,
  24. IN ACPICALLBACKROUTINE CompletionRoutine,
  25. IN BOOLEAN InvokeOnSuccess,
  26. IN BOOLEAN InvokeIfUnhandled
  27. )
  28. {
  29. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  30. NTSTATUS status, returnStatus;
  31. PAGED_CODE();
  32. ACPIDebugEnter( "ACPIIrpInvokeDispatchRoutine" );
  33. //
  34. // Retrieve the status from the embedded IRP
  35. //
  36. status = Irp->IoStatus.Status;
  37. returnStatus = STATUS_NOT_SUPPORTED;
  38. //
  39. // And call the completion routine appropriately
  40. //
  41. if (NT_SUCCESS(status)) {
  42. if (InvokeOnSuccess) {
  43. returnStatus = CompletionRoutine(DeviceObject, Irp, Context, FALSE);
  44. }
  45. } else if (status == STATUS_NOT_SUPPORTED) {
  46. if (InvokeIfUnhandled) {
  47. returnStatus = CompletionRoutine(DeviceObject, Irp, Context, FALSE);
  48. }
  49. }
  50. if (deviceExtension->Flags & DEV_TYPE_PDO) {
  51. if (returnStatus != STATUS_PENDING) {
  52. if (returnStatus != STATUS_NOT_SUPPORTED) {
  53. Irp->IoStatus.Status = returnStatus;
  54. } else {
  55. returnStatus = Irp->IoStatus.Status;
  56. }
  57. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  58. }
  59. } else if (returnStatus != STATUS_PENDING) {
  60. if (returnStatus != STATUS_NOT_SUPPORTED) {
  61. Irp->IoStatus.Status = returnStatus;
  62. }
  63. if (NT_SUCCESS(returnStatus) || (returnStatus == STATUS_NOT_SUPPORTED)) {
  64. returnStatus = IoCallDriver( deviceExtension->TargetDeviceObject, Irp );
  65. } else {
  66. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  67. }
  68. }
  69. return returnStatus;
  70. ACPIDebugExit( "ACPIIrpInvokeDispatchRoutine" );
  71. }
  72. NTSTATUS
  73. ACPIIrpSetPagableCompletionRoutineAndForward(
  74. IN PDEVICE_OBJECT DeviceObject,
  75. IN PIRP Irp,
  76. IN ACPICALLBACKROUTINE CompletionRoutine,
  77. IN PVOID Context,
  78. IN BOOLEAN InvokeOnSuccess,
  79. IN BOOLEAN InvokeIfUnhandled,
  80. IN BOOLEAN InvokeOnError,
  81. IN BOOLEAN InvokeOnCancel
  82. )
  83. /*++
  84. Routine Description:
  85. This routine handles an ACPI Filter Irp call. Irp count referencing is
  86. automatically taken care of.
  87. Arguments:
  88. DeviceObject - Pointer to the device object we received the request
  89. for.
  90. Irp - Pointer to the request
  91. CompletionRoutine - Routine to call after completion of the Irp
  92. Return Value:
  93. NTSTATUS
  94. --*/
  95. {
  96. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  97. PACPI_IO_CONTEXT pIoContext ;
  98. PIO_WORKITEM pIoWorkItem ;
  99. PAGED_CODE() ;
  100. ACPIDebugEnter( "ACPIIrpSetPagableCompletionRoutineAndForward" );
  101. pIoContext = (PACPI_IO_CONTEXT) ExAllocatePool(
  102. NonPagedPool,
  103. sizeof(ACPI_IO_CONTEXT)
  104. );
  105. if (pIoContext == NULL) {
  106. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES ;
  107. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  108. return STATUS_INSUFFICIENT_RESOURCES ;
  109. }
  110. pIoWorkItem = IoAllocateWorkItem(DeviceObject);
  111. if (pIoWorkItem == NULL) {
  112. ExFreePool(pIoContext);
  113. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES ;
  114. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  115. return STATUS_INSUFFICIENT_RESOURCES ;
  116. }
  117. pIoContext->CompletionRoutine = CompletionRoutine ;
  118. pIoContext->DeviceObject = DeviceObject ;
  119. pIoContext->Context = Context ;
  120. pIoContext->InvokeOnSuccess = InvokeOnSuccess ;
  121. pIoContext->InvokeIfUnhandled = InvokeIfUnhandled ;
  122. pIoContext->InvokeOnError = InvokeOnError ;
  123. pIoContext->InvokeOnCancel = InvokeOnCancel ;
  124. pIoContext->Irp = Irp ;
  125. pIoContext->IoWorkItem = pIoWorkItem ;
  126. //
  127. // We have a callback routine --- so we need to make sure to
  128. // increment the ref count since we will handle it later
  129. //
  130. InterlockedIncrement( &(deviceExtension->OutstandingIrpCount) );
  131. //
  132. // Copy the stack location...
  133. //
  134. IoCopyCurrentIrpStackLocationToNext( Irp );
  135. //
  136. // Set the completion event to be called...
  137. //
  138. IoSetCompletionRoutine(
  139. Irp,
  140. ACPIIrpGenericFilterCompletionHandler,
  141. (PVOID) pIoContext,
  142. TRUE,
  143. TRUE,
  144. TRUE
  145. );
  146. //
  147. // Mark the IRP pending
  148. //
  149. IoMarkIrpPending(Irp);
  150. //
  151. // Send the request along
  152. //
  153. IoCallDriver( deviceExtension->TargetDeviceObject, Irp );
  154. //
  155. // We do this because we may change the status in the completion routine.
  156. //
  157. return STATUS_PENDING;
  158. ACPIDebugExit( "ACPIIrpSetPagableCompletionRoutineAndForward" );
  159. }
  160. NTSTATUS
  161. ACPIIrpGenericFilterCompletionHandler(
  162. IN PDEVICE_OBJECT DeviceObject,
  163. IN PIRP Irp,
  164. IN PVOID Context
  165. )
  166. /*++
  167. Routine Description:
  168. A rather generic "synchronize the IRP on this thread" completion routine.
  169. Argument:
  170. DeviceObject - Pointer to the device object we received the
  171. request for
  172. Irp - Pointer to the request
  173. Event - Pointer to structure containing the Irp handlers
  174. Return Value:
  175. NTSTATUS
  176. --*/
  177. {
  178. PACPI_IO_CONTEXT pIoContext = (PACPI_IO_CONTEXT) Context;
  179. ACPIDebugEnter( "ACPIIrpGenericFilterCompletionHandler" );
  180. if (Irp->PendingReturned) {
  181. IoMarkIrpPending(Irp);
  182. }
  183. if (KeGetCurrentIrql() != PASSIVE_LEVEL) {
  184. IoQueueWorkItem(
  185. pIoContext->IoWorkItem,
  186. ACPIIrpCompletionRoutineWorker,
  187. DelayedWorkQueue,
  188. pIoContext
  189. );
  190. } else {
  191. ACPIIrpCompletionRoutineWorker(DeviceObject, Context);
  192. }
  193. return STATUS_MORE_PROCESSING_REQUIRED;
  194. ACPIDebugExit( "ACPIIrpGenericFilterCompletionHandler" );
  195. }
  196. VOID
  197. ACPIIrpCompletionRoutineWorker(
  198. IN PDEVICE_OBJECT DeviceObject,
  199. IN PVOID Context
  200. )
  201. {
  202. PACPI_IO_CONTEXT pIoContext;
  203. PDEVICE_EXTENSION deviceExtension;
  204. ACPICALLBACKROUTINE completionRoutine;
  205. PIRP irp;
  206. NTSTATUS status, returnStatus;
  207. PVOID context;
  208. PAGED_CODE();
  209. ACPIDebugEnter( "ACPIIrpCompletionRoutineWorker" );
  210. //
  211. // Read out fields from the device object
  212. //
  213. deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  214. //
  215. // Cast the context and dig into it.
  216. //
  217. pIoContext = (PACPI_IO_CONTEXT) Context;
  218. completionRoutine = pIoContext->CompletionRoutine;
  219. context = pIoContext->Context;
  220. irp = pIoContext->Irp;
  221. //
  222. // Retrieve the status from the embedded IRP
  223. //
  224. status = irp->IoStatus.Status;
  225. returnStatus = STATUS_NOT_SUPPORTED;
  226. //
  227. // And call the completion routine appropriately
  228. //
  229. if (NT_SUCCESS(status)) {
  230. if (pIoContext->InvokeOnSuccess) {
  231. returnStatus = completionRoutine(DeviceObject, irp, context, TRUE);
  232. }
  233. } else if (status == STATUS_NOT_SUPPORTED) {
  234. if (pIoContext->InvokeIfUnhandled) {
  235. returnStatus = completionRoutine(DeviceObject, irp, context, TRUE);
  236. }
  237. } else {
  238. if ((pIoContext->InvokeOnError) ||
  239. (irp->Cancel && pIoContext->InvokeOnCancel)) {
  240. returnStatus = completionRoutine(DeviceObject, irp, context, TRUE);
  241. }
  242. }
  243. //
  244. // Remove our reference
  245. //
  246. ACPIInternalDecrementIrpReferenceCount( deviceExtension );
  247. IoFreeWorkItem(pIoContext->IoWorkItem);
  248. ExFreePool(pIoContext) ;
  249. if (returnStatus != STATUS_PENDING) {
  250. if (returnStatus != STATUS_NOT_SUPPORTED) {
  251. irp->IoStatus.Status = returnStatus;
  252. }
  253. IoCompleteRequest(irp, IO_NO_INCREMENT);
  254. }
  255. ACPIDebugExit( "ACPIIrpCompletionRoutineWorker" );
  256. }