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.

346 lines
9.2 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. mask.c
  5. Abstract:
  6. This module contains the code that is very specific to initialization
  7. and unload operations in the irenum driver
  8. Author:
  9. Brian Lieuallen, 7-13-2000
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. --*/
  14. #include "internal.h"
  15. #include "ircomm.h"
  16. VOID
  17. WaitMaskCancelRoutine(
  18. PDEVICE_OBJECT DeviceObject,
  19. PIRP Irp
  20. );
  21. PIRP
  22. GetCurrentWaitIrp(
  23. PFDO_DEVICE_EXTENSION DeviceExtension
  24. );
  25. VOID
  26. MaskStartRoutine(
  27. PVOID Context,
  28. PIRP Irp
  29. )
  30. {
  31. PFDO_DEVICE_EXTENSION DeviceExtension=(PFDO_DEVICE_EXTENSION)Context;
  32. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  33. KIRQL OldIrql;
  34. PUCHAR SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
  35. ULONG InputLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  36. ULONG OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  37. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  38. case IOCTL_SERIAL_GET_WAIT_MASK:
  39. if (OutputLength >= sizeof(ULONG)) {
  40. *(PULONG)SystemBuffer=DeviceExtension->Mask.CurrentMask;
  41. Irp->IoStatus.Information=sizeof(ULONG);
  42. Irp->IoStatus.Status=STATUS_SUCCESS;
  43. } else {
  44. Irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
  45. }
  46. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  47. StartNextPacket(&DeviceExtension->Mask.Queue);
  48. break;
  49. case IOCTL_SERIAL_SET_WAIT_MASK: {
  50. ULONG NewMask=*(PULONG)SystemBuffer;
  51. if (InputLength >= sizeof(ULONG)) {
  52. PIRP WaitIrp=NULL;
  53. D_TRACE(DbgPrint("IRCOMM: mask %08lx\n",NewMask);)
  54. KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql);
  55. DeviceExtension->Mask.HistoryMask &= NewMask;
  56. DeviceExtension->Mask.CurrentMask=NewMask;
  57. Irp->IoStatus.Status=STATUS_SUCCESS;
  58. //
  59. // if there was a wait irp, clear ir out now
  60. //
  61. WaitIrp=GetCurrentWaitIrp(DeviceExtension);
  62. KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
  63. if (WaitIrp != NULL) {
  64. WaitIrp->IoStatus.Information=sizeof(ULONG);
  65. WaitIrp->IoStatus.Status=STATUS_SUCCESS;
  66. *(PULONG)WaitIrp->AssociatedIrp.SystemBuffer=0;
  67. IoCompleteRequest(WaitIrp,IO_NO_INCREMENT);
  68. }
  69. } else {
  70. Irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
  71. }
  72. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  73. StartNextPacket(&DeviceExtension->Mask.Queue);
  74. break;
  75. }
  76. case IOCTL_SERIAL_WAIT_ON_MASK:
  77. if (OutputLength >= sizeof(ULONG)) {
  78. KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql);
  79. if ((DeviceExtension->Mask.CurrentWaitMaskIrp == NULL) && (DeviceExtension->Mask.CurrentMask != 0)) {
  80. if (DeviceExtension->Mask.CurrentMask & DeviceExtension->Mask.HistoryMask) {
  81. //
  82. // we got an event while there a was no irp queue, complete this
  83. // one with the event, and clear the history
  84. //
  85. D_TRACE(DbgPrint("IRCOMM: Completing wait from histroy %08lx\n", DeviceExtension->Mask.HistoryMask & DeviceExtension->Mask.CurrentMask);)
  86. *(PULONG)Irp->AssociatedIrp.SystemBuffer=DeviceExtension->Mask.HistoryMask & DeviceExtension->Mask.CurrentMask;
  87. DeviceExtension->Mask.HistoryMask=0;
  88. Irp->IoStatus.Information=sizeof(ULONG);
  89. Irp->IoStatus.Status=STATUS_SUCCESS;
  90. } else {
  91. //
  92. // the irp will remain pending here until an event happens
  93. //
  94. KIRQL CancelIrql;
  95. IoAcquireCancelSpinLock(&CancelIrql);
  96. if (Irp->Cancel) {
  97. //
  98. // canceled already
  99. //
  100. Irp->IoStatus.Status=STATUS_CANCELLED;
  101. IoReleaseCancelSpinLock(CancelIrql);
  102. KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
  103. } else {
  104. //
  105. // not canceled, set the cancel routine and proceed
  106. //
  107. IoSetCancelRoutine(Irp,WaitMaskCancelRoutine);
  108. DeviceExtension->Mask.CurrentWaitMaskIrp=Irp;
  109. IoReleaseCancelSpinLock(CancelIrql);
  110. KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
  111. //
  112. // were done processing this so far, we can now handle more
  113. // requests from the irp queue
  114. //
  115. Irp=NULL;
  116. StartNextPacket(&DeviceExtension->Mask.Queue);
  117. return;
  118. }
  119. }
  120. } else {
  121. //
  122. // already have an wait event irp or there is not currently an event mask set, fail
  123. //
  124. D_ERROR(DbgPrint("IRCOMM: MaskStartRoutine: WaitOnMask failing, Current=&p, Mask=%08lx\n",DeviceExtension->Mask.CurrentWaitMaskIrp,DeviceExtension->Mask.CurrentMask);)
  125. Irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
  126. }
  127. KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
  128. } else {
  129. //
  130. // too small
  131. //
  132. Irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
  133. }
  134. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  135. StartNextPacket(&DeviceExtension->Mask.Queue);
  136. break;
  137. default:
  138. ASSERT(0);
  139. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  140. StartNextPacket(&DeviceExtension->Mask.Queue);
  141. break;
  142. }
  143. return;
  144. }
  145. VOID
  146. WaitMaskCancelRoutine(
  147. PDEVICE_OBJECT DeviceObject,
  148. PIRP Irp
  149. )
  150. {
  151. PFDO_DEVICE_EXTENSION DeviceExtension=DeviceObject->DeviceExtension;
  152. KIRQL OldIrql;
  153. IoReleaseCancelSpinLock(Irp->CancelIrql);
  154. KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql);
  155. //
  156. // since we only handle one mask irp at a time, it should not be possible for it to not
  157. // be the current one
  158. //
  159. ASSERT(DeviceExtension->Mask.CurrentWaitMaskIrp == Irp);
  160. DeviceExtension->Mask.CurrentWaitMaskIrp=NULL;
  161. KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
  162. Irp->IoStatus.Status=STATUS_CANCELLED;
  163. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  164. return;
  165. }
  166. VOID
  167. EventNotification(
  168. PFDO_DEVICE_EXTENSION DeviceExtension,
  169. ULONG SerialEvent
  170. )
  171. {
  172. PIRP WaitIrp=NULL;
  173. KIRQL OldIrql;
  174. KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql);
  175. if (SerialEvent & DeviceExtension->Mask.CurrentMask) {
  176. //
  177. // an event the the client is intereasted in occured
  178. //
  179. WaitIrp=GetCurrentWaitIrp(DeviceExtension);
  180. if (WaitIrp != NULL) {
  181. //
  182. // There is a wait irp pending
  183. //
  184. D_TRACE(DbgPrint("IRCOMM: Completing wait event %08lx\n", SerialEvent & DeviceExtension->Mask.CurrentMask);)
  185. *(PULONG)WaitIrp->AssociatedIrp.SystemBuffer=SerialEvent & DeviceExtension->Mask.CurrentMask;
  186. } else {
  187. //
  188. // this was an event the the client was interested in, but there was no wait irp
  189. // add it to the histrory mask
  190. //
  191. DeviceExtension->Mask.HistoryMask |= SerialEvent & DeviceExtension->Mask.CurrentMask;
  192. }
  193. }
  194. KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
  195. if (WaitIrp != NULL) {
  196. WaitIrp->IoStatus.Information=sizeof(ULONG);
  197. WaitIrp->IoStatus.Status=STATUS_SUCCESS;
  198. IoCompleteRequest(WaitIrp,IO_NO_INCREMENT);
  199. }
  200. return;
  201. }
  202. PIRP
  203. GetCurrentWaitIrp(
  204. PFDO_DEVICE_EXTENSION DeviceExtension
  205. )
  206. {
  207. PVOID OldCancelRoutine;
  208. PIRP WaitIrp;
  209. //
  210. // if there was a wait irp, clear ir out now
  211. //
  212. WaitIrp=DeviceExtension->Mask.CurrentWaitMaskIrp;
  213. if (WaitIrp != NULL) {
  214. OldCancelRoutine=IoSetCancelRoutine(WaitIrp,NULL);
  215. if (OldCancelRoutine == NULL) {
  216. //
  217. // the cancel routine has run and will complete the irp
  218. //
  219. WaitIrp=NULL;
  220. } else {
  221. //
  222. // the cancel routine will not be running, clear the irp out
  223. //
  224. DeviceExtension->Mask.CurrentWaitMaskIrp=NULL;
  225. }
  226. }
  227. return WaitIrp;
  228. }