Leaked source code of windows server 2003
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.

607 lines
17 KiB

  1. /*++
  2. Copyright (c) 1991, 1992, 1993 Microsoft Corporation
  3. Module Name:
  4. waitmask.c
  5. Abstract:
  6. This module contains the code that is very specific to get/set/wait
  7. on event mask operations in the serial driver
  8. Author:
  9. Anthony V. Ercolano 26-Sep-1991
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. --*/
  14. #include "precomp.h"
  15. // Prototypes
  16. BOOLEAN SerialGrabWaitFromIsr(IN PVOID Context);
  17. BOOLEAN SerialGiveWaitToIsr(IN PVOID Context);
  18. BOOLEAN SerialFinishOldWait(IN PVOID Context);
  19. // End of prototypes
  20. #ifdef ALLOC_PRAGMA
  21. #endif
  22. NTSTATUS
  23. SerialStartMask(IN PPORT_DEVICE_EXTENSION pPort)
  24. /*++
  25. Routine Description:
  26. This routine is used to process the set mask and wait
  27. mask ioctls. Calls to this routine are serialized by
  28. placing irps in the list under the protection of the
  29. cancel spin lock.
  30. Arguments:
  31. Extension - A pointer to the serial device extension.
  32. Return Value:
  33. Will return pending for everything put the first
  34. request that we actually process. Even in that
  35. case it will return pending unless it can complete
  36. it right away.
  37. --*/
  38. {
  39. //
  40. // The current stack location. This contains much of the
  41. // information we need to process this particular request.
  42. //
  43. PIO_STACK_LOCATION IrpSp;
  44. PIRP NewIrp;
  45. BOOLEAN SetFirstStatus = FALSE;
  46. NTSTATUS FirstStatus;
  47. SerialDump(SERDIAG3,("In SerialStartMask\n"));
  48. ASSERT(pPort->CurrentMaskIrp);
  49. do
  50. {
  51. SerialDump(SERDIAG4,("STARTMASK - CurrentMaskIrp: %x\n", pPort->CurrentMaskIrp));
  52. IrpSp = IoGetCurrentIrpStackLocation(pPort->CurrentMaskIrp);
  53. ASSERT((IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
  54. || (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_WAIT_MASK));
  55. if(IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_WAIT_MASK)
  56. {
  57. SerialDump(SERDIAG4, ("SERIAL - %x is a SETMASK irp\n", pPort->CurrentMaskIrp));
  58. // Complete the old wait if there is one.
  59. KeSynchronizeExecution(pPort->Interrupt, SerialFinishOldWait, pPort);
  60. //
  61. // Any current waits should be on its way to completion
  62. // at this point. There certainly shouldn't be any
  63. // irp mask location.
  64. //
  65. ASSERT(!pPort->IrpMaskLocation);
  66. pPort->CurrentMaskIrp->IoStatus.Status = STATUS_SUCCESS;
  67. if(!SetFirstStatus)
  68. {
  69. SerialDump(SERDIAG4,("%x was the first irp processed by this\n"
  70. "------- invocation of startmask\n", pPort->CurrentMaskIrp));
  71. FirstStatus = STATUS_SUCCESS;
  72. SetFirstStatus = TRUE;
  73. }
  74. // The following call will also cause the current call to be completed.
  75. SerialGetNextIrp(pPort, &pPort->CurrentMaskIrp, &pPort->MaskQueue, &NewIrp, TRUE);
  76. SerialDump(SERDIAG4,("Perhaps another mask irp was found in the queue\n"
  77. "------- %x/%x <- values should be the same\n", pPort->CurrentMaskIrp, NewIrp));
  78. }
  79. else
  80. {
  81. //
  82. // First make sure that we have a non-zero mask.
  83. // If the app queues a wait on a zero mask it can't
  84. // be statisfied so it makes no sense to start it.
  85. //
  86. if((!pPort->IsrWaitMask) || (pPort->CurrentWaitIrp))
  87. {
  88. SerialDump(SERDIAG4,("WaitIrp is invalid\n"
  89. "------- IsrWaitMask: %x\n"
  90. "------- CurrentWaitIrp: %x\n",
  91. pPort->IsrWaitMask,
  92. pPort->CurrentWaitIrp));
  93. pPort->CurrentMaskIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  94. if(!SetFirstStatus)
  95. {
  96. SerialDump(SERDIAG4,("%x was the first irp processed by this\n"
  97. "------- invocation of startmask\n", pPort->CurrentMaskIrp));
  98. FirstStatus = STATUS_INVALID_PARAMETER;
  99. SetFirstStatus = TRUE;
  100. }
  101. SerialGetNextIrp(pPort, &pPort->CurrentMaskIrp, &pPort->MaskQueue, &NewIrp, TRUE);
  102. SerialDump(SERDIAG4,("Perhaps another mask irp was found in the queue\n"
  103. "------- %x/%x <- values should be the same\n",
  104. pPort->CurrentMaskIrp,NewIrp));
  105. }
  106. else
  107. {
  108. KIRQL OldIrql;
  109. //
  110. // Make the current mask irp the current wait irp and
  111. // get a new current mask irp. Note that when we get
  112. // the new current mask irp we DO NOT complete the
  113. // old current mask irp (which is now the current wait
  114. // irp.
  115. //
  116. // Then under the protection of the cancel spin lock
  117. // we check to see if the current wait irp needs to
  118. // be canceled
  119. //
  120. IoAcquireCancelSpinLock(&OldIrql);
  121. if(pPort->CurrentMaskIrp->Cancel)
  122. {
  123. SerialDump(SERDIAG4, ("%x irp was already marked as cancelled\n", pPort->CurrentMaskIrp));
  124. IoReleaseCancelSpinLock(OldIrql);
  125. pPort->CurrentMaskIrp->IoStatus.Status = STATUS_CANCELLED;
  126. if(!SetFirstStatus)
  127. {
  128. SerialDump(SERDIAG4, ("%x was the first irp processed by this\n"
  129. "------- invocation of startmask\n", pPort->CurrentMaskIrp));
  130. FirstStatus = STATUS_CANCELLED;
  131. SetFirstStatus = TRUE;
  132. }
  133. SerialGetNextIrp(pPort, &pPort->CurrentMaskIrp, &pPort->MaskQueue, &NewIrp, TRUE);
  134. SerialDump(SERDIAG4,("Perhaps another mask irp was found in the queue\n"
  135. "------- %x/%x <- values should be the same\n", pPort->CurrentMaskIrp, NewIrp));
  136. }
  137. else
  138. {
  139. SerialDump(SERDIAG4, ("%x will become the current wait irp\n", pPort->CurrentMaskIrp));
  140. if(!SetFirstStatus)
  141. {
  142. SerialDump(SERDIAG4,("%x was the first irp processed by this\n"
  143. "------- invocation of startmask\n", pPort->CurrentMaskIrp));
  144. FirstStatus = STATUS_PENDING;
  145. SetFirstStatus = TRUE;
  146. //
  147. // If we haven't already set a first status
  148. // then there is a chance that this packet
  149. // was never on the queue. We should mark
  150. // it as pending.
  151. //
  152. IoMarkIrpPending(pPort->CurrentMaskIrp);
  153. }
  154. //
  155. // There should never be a mask location when
  156. // there isn't a current wait irp. At this point
  157. // there shouldn't be a current wait irp also.
  158. //
  159. ASSERT(!pPort->IrpMaskLocation);
  160. ASSERT(!pPort->CurrentWaitIrp);
  161. pPort->CurrentWaitIrp = pPort->CurrentMaskIrp;
  162. SERIAL_INIT_REFERENCE(pPort->CurrentWaitIrp);
  163. IoSetCancelRoutine(pPort->CurrentWaitIrp, SerialCancelWait);
  164. //
  165. // Since the cancel routine has a reference to#
  166. // the irp we need to update the reference
  167. // count.
  168. //
  169. SERIAL_SET_REFERENCE(pPort->CurrentWaitIrp, SERIAL_REF_CANCEL);
  170. KeSynchronizeExecution(pPort->Interrupt, SerialGiveWaitToIsr, pPort);
  171. //
  172. // Since it isn't really the mask irp anymore,
  173. // null out that pointer.
  174. //
  175. pPort->CurrentMaskIrp = NULL;
  176. IoReleaseCancelSpinLock(OldIrql);
  177. SerialGetNextIrp(pPort, &pPort->CurrentMaskIrp, &pPort->MaskQueue, &NewIrp, FALSE);
  178. SerialDump(SERDIAG4,("Perhaps another mask irp was found in the queue\n"
  179. "------- %x/%x <- values should be the same\n", pPort->CurrentMaskIrp, NewIrp));
  180. }
  181. }
  182. }
  183. } while (NewIrp);
  184. return FirstStatus;
  185. }
  186. BOOLEAN
  187. SerialGrabWaitFromIsr(IN PVOID Context)
  188. /*++
  189. Routine Description:
  190. This routine will check to see if the ISR still knows about
  191. a wait irp by checking to see if the IrpMaskLocation is non-null.
  192. If it is then it will zero the Irpmasklocation (which in effect
  193. grabs the irp away from the isr). This routine is only called
  194. buy the cancel code for the wait.
  195. NOTE: This is called by KeSynchronizeExecution.
  196. Arguments:
  197. Context - A pointer to the device extension
  198. Return Value:
  199. Always FALSE.
  200. --*/
  201. {
  202. PPORT_DEVICE_EXTENSION pPort = Context;
  203. SerialDump(SERDIAG3,("In SerialGrabWaitFromIsr\n"));
  204. if(pPort->IrpMaskLocation)
  205. {
  206. SerialDump(SERDIAG4,("The isr still owns the irp %x, mask location is %x\n"
  207. "------- and system buffer is %x\n",
  208. pPort->CurrentWaitIrp, pPort->IrpMaskLocation,
  209. pPort->CurrentWaitIrp->AssociatedIrp.SystemBuffer));
  210. // The isr still "owns" the irp.
  211. *pPort->IrpMaskLocation = 0;
  212. pPort->IrpMaskLocation = NULL;
  213. pPort->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  214. //
  215. // Since the isr no longer references the irp we need to
  216. // decrement the reference count.
  217. //
  218. SERIAL_CLEAR_REFERENCE(pPort->CurrentWaitIrp, SERIAL_REF_ISR);
  219. }
  220. return FALSE;
  221. }
  222. BOOLEAN
  223. SerialGiveWaitToIsr(IN PVOID Context)
  224. /*++
  225. Routine Description:
  226. This routine simply sets a variable in the device extension
  227. so that the isr knows that we have a wait irp.
  228. NOTE: This is called by KeSynchronizeExecution.
  229. NOTE: This routine assumes that it is called with the
  230. cancel spinlock held.
  231. Arguments:
  232. Context - Simply a pointer to the device extension.
  233. Return Value:
  234. Always FALSE.
  235. --*/
  236. {
  237. PPORT_DEVICE_EXTENSION pPort = Context;
  238. SerialDump(SERDIAG3,("In SerialGiveWaitToIsr\n"));
  239. //
  240. // There certainly shouldn't be a current mask location at
  241. // this point since we have a new current wait irp.
  242. //
  243. ASSERT(!pPort->IrpMaskLocation);
  244. //
  245. // The isr may or may not actually reference this irp. It
  246. // won't if the wait can be satisfied immediately. However,
  247. // since it will then go through the normal completion sequence,
  248. // we need to have an incremented reference count anyway.
  249. //
  250. SERIAL_SET_REFERENCE(pPort->CurrentWaitIrp, SERIAL_REF_ISR);
  251. if(!pPort->HistoryMask)
  252. {
  253. SerialDump(SERDIAG4, ("No events occured prior to the wait call\n"));
  254. //
  255. // Although this wait might not be for empty transmit
  256. // queue, it doesn't hurt anything to set it to false.
  257. //
  258. pPort->EmptiedTransmit = FALSE;
  259. //
  260. // Record where the "completion mask" should be set.
  261. //
  262. pPort->IrpMaskLocation = pPort->CurrentWaitIrp->AssociatedIrp.SystemBuffer;
  263. SerialDump(SERDIAG4,("The isr owns the irp %x, mask location is %x\n"
  264. "------- and system buffer is %x\n",
  265. pPort->CurrentWaitIrp, pPort->IrpMaskLocation,
  266. pPort->CurrentWaitIrp->AssociatedIrp.SystemBuffer));
  267. }
  268. else
  269. {
  270. SerialDump(SERDIAG4, ("%x occurred prior to the wait - starting the\n"
  271. "------- completion code for %x\n",
  272. pPort->HistoryMask, pPort->CurrentWaitIrp));
  273. *((ULONG *)pPort->CurrentWaitIrp->AssociatedIrp.SystemBuffer) = pPort->HistoryMask;
  274. pPort->HistoryMask = 0;
  275. pPort->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  276. pPort->CurrentWaitIrp->IoStatus.Status = STATUS_SUCCESS;
  277. // Mark IRP as about to complete normally to prevent cancel & timer DPCs
  278. // from doing so before DPC is allowed to run.
  279. //SERIAL_SET_REFERENCE(pPort->CurrentWaitIrp, SERIAL_REF_COMPLETING);
  280. KeInsertQueueDpc(&pPort->CommWaitDpc, NULL, NULL);
  281. }
  282. return FALSE;
  283. }
  284. BOOLEAN
  285. SerialFinishOldWait(IN PVOID Context)
  286. /*++
  287. Routine Description:
  288. This routine will check to see if the ISR still knows about
  289. a wait irp by checking to see if the Irpmasklocation is non-null.
  290. If it is then it will zero the Irpmasklocation (which in effect
  291. grabs the irp away from the isr). This routine is only called
  292. buy the cancel code for the wait.
  293. NOTE: This is called by KeSynchronizeExecution.
  294. Arguments:
  295. Context - A pointer to the device extension
  296. Return Value:
  297. Always FALSE.
  298. --*/
  299. {
  300. PPORT_DEVICE_EXTENSION pPort = Context;
  301. SerialDump(SERDIAG3,("In SerialFinishOldWait\n"));
  302. if(pPort->IrpMaskLocation)
  303. {
  304. SerialDump(SERDIAG4, ("The isr still owns the irp %x, mask location is %x\n"
  305. "------- and system buffer is %x\n",
  306. pPort->CurrentWaitIrp, pPort->IrpMaskLocation,
  307. pPort->CurrentWaitIrp->AssociatedIrp.SystemBuffer));
  308. //
  309. // The isr still "owns" the irp.
  310. //
  311. *pPort->IrpMaskLocation = 0;
  312. pPort->IrpMaskLocation = NULL;
  313. pPort->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  314. //
  315. // We don't decrement the reference since the completion routine
  316. // will do that.
  317. //
  318. // Mark IRP as about to complete normally to prevent cancel & timer DPCs
  319. // from doing so before DPC is allowed to run.
  320. //SERIAL_SET_REFERENCE(pPort->CurrentWaitIrp, SERIAL_REF_COMPLETING);
  321. KeInsertQueueDpc(&pPort->CommWaitDpc, NULL, NULL);
  322. }
  323. //
  324. // Don't wipe out any historical data we are still interested in.
  325. //
  326. pPort->HistoryMask &= *((ULONG *)pPort->CurrentMaskIrp->AssociatedIrp.SystemBuffer);
  327. pPort->IsrWaitMask = *((ULONG *)pPort->CurrentMaskIrp->AssociatedIrp.SystemBuffer);
  328. // Setup UART for special character detection
  329. if(pPort->IsrWaitMask & SERIAL_EV_RXFLAG)
  330. {
  331. pPort->UartConfig.SpecialMode |= UC_SM_DETECT_SPECIAL_CHAR;
  332. pPort->pUartLib->UL_SetConfig_XXXX(pPort->pUart, &pPort->UartConfig, UC_SPECIAL_MODE_MASK);
  333. }
  334. else
  335. {
  336. pPort->UartConfig.SpecialMode &= ~UC_SM_DETECT_SPECIAL_CHAR;
  337. pPort->pUartLib->UL_SetConfig_XXXX(pPort->pUart, &pPort->UartConfig, UC_SPECIAL_MODE_MASK);
  338. }
  339. SerialDump(SERDIAG4, ("Set mask location of %x, in irp %x, with system buffer of %x\n",
  340. pPort->IrpMaskLocation,
  341. pPort->CurrentMaskIrp, pPort->CurrentMaskIrp->AssociatedIrp.SystemBuffer));
  342. return FALSE;
  343. }
  344. VOID
  345. SerialCancelWait(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  346. /*++
  347. Routine Description:
  348. This routine is used to cancel a irp that is waiting on
  349. a comm event.
  350. Arguments:
  351. DeviceObject - Pointer to the device object for this device
  352. Irp - Pointer to the IRP for the current request
  353. Return Value:
  354. None.
  355. --*/
  356. {
  357. PPORT_DEVICE_EXTENSION pPort = DeviceObject->DeviceExtension;
  358. SerialDump(SERDIAG3, ("In SerialCancelWait\n"));
  359. SerialDump(SERDIAG4, ("Canceling wait for irp %x\n", pPort->CurrentWaitIrp));
  360. SerialTryToCompleteCurrent( pPort,
  361. SerialGrabWaitFromIsr,
  362. Irp->CancelIrql,
  363. STATUS_CANCELLED,
  364. &pPort->CurrentWaitIrp,
  365. NULL,
  366. NULL,
  367. NULL,
  368. NULL,
  369. NULL,
  370. SERIAL_REF_CANCEL);
  371. }
  372. VOID
  373. SerialCompleteWait(IN PKDPC Dpc,
  374. IN PVOID DeferredContext,
  375. IN PVOID SystemContext1,
  376. IN PVOID SystemContext2)
  377. {
  378. PPORT_DEVICE_EXTENSION pPort = DeferredContext;
  379. KIRQL OldIrql;
  380. SerialDump(SERDIAG3, ("In SerialCompleteWait\n"));
  381. UNREFERENCED_PARAMETER(Dpc);
  382. UNREFERENCED_PARAMETER(SystemContext1);
  383. UNREFERENCED_PARAMETER(SystemContext2);
  384. IoAcquireCancelSpinLock(&OldIrql);
  385. SerialDump(SERDIAG4, ("Completing wait for irp %x\n", pPort->CurrentWaitIrp));
  386. // Clear the normal complete reference.
  387. //SERIAL_CLEAR_REFERENCE(pPort->CurrentWaitIrp, SERIAL_REF_COMPLETING);
  388. SerialTryToCompleteCurrent( pPort,
  389. NULL,
  390. OldIrql,
  391. STATUS_SUCCESS,
  392. &pPort->CurrentWaitIrp,
  393. NULL,
  394. NULL,
  395. NULL,
  396. NULL,
  397. NULL,
  398. SERIAL_REF_ISR);
  399. }