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.

887 lines
21 KiB

  1. /*++
  2. Module Name:
  3. write.c
  4. Environment:
  5. Kernel mode
  6. Revision History :
  7. --*/
  8. #include "precomp.h"
  9. NTSTATUS
  10. MoxaWrite(
  11. IN PDEVICE_OBJECT DeviceObject,
  12. IN PIRP Irp
  13. )
  14. {
  15. NTSTATUS status;
  16. PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  17. // MoxaKdPrint(MX_DBG_TRACE,("Enter MoxaWrite\n"));
  18. if ((extension->ControlDevice == TRUE)||
  19. (extension->DeviceIsOpened == FALSE) ||
  20. (extension->PowerState != PowerDeviceD0) ) {
  21. Irp->IoStatus.Status = STATUS_CANCELLED;
  22. Irp->IoStatus.Information=0L;
  23. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  24. return STATUS_CANCELLED;
  25. }
  26. if ((status = MoxaIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
  27. MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  28. return status;
  29. }
  30. if (MoxaCompleteIfError(
  31. DeviceObject,
  32. Irp
  33. ) != STATUS_SUCCESS) {
  34. return STATUS_CANCELLED;
  35. }
  36. Irp->IoStatus.Information = 0L;
  37. //
  38. // Quick check for a zero length write. If it is zero length
  39. // then we are already done!
  40. //
  41. if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length) {
  42. //
  43. // Well it looks like we actually have to do some
  44. // work. Put the write on the queue so that we can
  45. // process it when our previous writes are done.
  46. //
  47. return MoxaStartOrQueue(
  48. extension,
  49. Irp,
  50. &extension->WriteQueue,
  51. &extension->CurrentWriteIrp,
  52. MoxaStartWrite
  53. );
  54. }
  55. else {
  56. Irp->IoStatus.Status = STATUS_SUCCESS;
  57. MoxaCompleteRequest(
  58. extension,
  59. Irp,
  60. 0
  61. );
  62. return STATUS_SUCCESS;
  63. }
  64. }
  65. NTSTATUS
  66. MoxaStartWrite(
  67. IN PMOXA_DEVICE_EXTENSION Extension
  68. )
  69. {
  70. PIRP newIrp;
  71. KIRQL oldIrql;
  72. KIRQL controlIrql;
  73. LARGE_INTEGER totalTime;
  74. PIO_STACK_LOCATION irpSp;
  75. BOOLEAN useATimer;
  76. SERIAL_TIMEOUTS timeouts;
  77. BOOLEAN setFirstStatus = FALSE;
  78. NTSTATUS firstStatus;
  79. do {
  80. irpSp = IoGetCurrentIrpStackLocation(
  81. Extension->CurrentWriteIrp
  82. );
  83. //
  84. // Check if MOXA_IOCTL_PutB request
  85. //
  86. if (irpSp->MajorFunction != IRP_MJ_WRITE) {
  87. KeAcquireSpinLock(
  88. &Extension->ControlLock,
  89. &controlIrql
  90. );
  91. IoAcquireCancelSpinLock(&oldIrql);
  92. if (Extension->CurrentWriteIrp->Cancel) {
  93. Extension->CurrentWriteIrp->IoStatus.Status = STATUS_CANCELLED;
  94. IoReleaseCancelSpinLock(oldIrql);
  95. KeReleaseSpinLock(
  96. &Extension->ControlLock,
  97. controlIrql
  98. );
  99. if (!setFirstStatus) {
  100. firstStatus = STATUS_CANCELLED;
  101. setFirstStatus = TRUE;
  102. }
  103. }
  104. else {
  105. KeSynchronizeExecution(
  106. Extension->Interrupt,
  107. MoxaPutB,
  108. Extension
  109. );
  110. if (!setFirstStatus) {
  111. setFirstStatus = TRUE;
  112. firstStatus = STATUS_SUCCESS;
  113. }
  114. Extension->CurrentWriteIrp->IoStatus.Status = STATUS_SUCCESS;
  115. Extension->CurrentWriteIrp->IoStatus.Information = sizeof(ULONG);
  116. IoReleaseCancelSpinLock(oldIrql);
  117. KeReleaseSpinLock(
  118. &Extension->ControlLock,
  119. controlIrql
  120. );
  121. }
  122. }
  123. else {
  124. /*
  125. * Extension->TotalCharsQueued NOT include current write
  126. *
  127. */
  128. IoAcquireCancelSpinLock(&oldIrql);
  129. Extension->TotalCharsQueued -=
  130. IoGetCurrentIrpStackLocation(Extension->CurrentWriteIrp)
  131. ->Parameters.Write.Length;
  132. IoReleaseCancelSpinLock(oldIrql);
  133. useATimer = FALSE;
  134. KeAcquireSpinLock(
  135. &Extension->ControlLock,
  136. &controlIrql
  137. );
  138. timeouts = Extension->Timeouts;
  139. KeReleaseSpinLock(
  140. &Extension->ControlLock,
  141. controlIrql
  142. );
  143. if (timeouts.WriteTotalTimeoutConstant ||
  144. timeouts.WriteTotalTimeoutMultiplier) {
  145. useATimer = TRUE;
  146. totalTime = RtlEnlargedUnsignedMultiply(
  147. irpSp->Parameters.Write.Length,
  148. timeouts.WriteTotalTimeoutMultiplier
  149. );
  150. totalTime = RtlLargeIntegerAdd(
  151. totalTime,
  152. RtlConvertUlongToLargeInteger(
  153. timeouts.WriteTotalTimeoutConstant
  154. )
  155. );
  156. totalTime = RtlExtendedIntegerMultiply(
  157. totalTime,
  158. -10000
  159. );
  160. }
  161. KeAcquireSpinLock(
  162. &Extension->ControlLock,
  163. &controlIrql
  164. );
  165. MOXA_INIT_REFERENCE(Extension->CurrentWriteIrp);
  166. IoAcquireCancelSpinLock(&oldIrql);
  167. if (Extension->CurrentWriteIrp->Cancel) {
  168. Extension->CurrentWriteIrp->IoStatus.Status = STATUS_CANCELLED;
  169. IoReleaseCancelSpinLock(oldIrql);
  170. KeReleaseSpinLock(
  171. &Extension->ControlLock,
  172. controlIrql
  173. );
  174. if (!setFirstStatus) {
  175. firstStatus = STATUS_CANCELLED;
  176. setFirstStatus = TRUE;
  177. }
  178. }
  179. else {
  180. KeSynchronizeExecution(
  181. Extension->Interrupt,
  182. MoxaOut,
  183. Extension
  184. );
  185. if (WRcompFlag) { /* complete write */
  186. if (!setFirstStatus) {
  187. setFirstStatus = TRUE;
  188. firstStatus = STATUS_SUCCESS;
  189. }
  190. Extension->CurrentWriteIrp->IoStatus.Status = STATUS_SUCCESS;
  191. Extension->CurrentWriteIrp->IoStatus.Information =
  192. irpSp->Parameters.Write.Length;
  193. IoReleaseCancelSpinLock(oldIrql);
  194. KeReleaseSpinLock(
  195. &Extension->ControlLock,
  196. controlIrql
  197. );
  198. }
  199. else {
  200. if (!setFirstStatus) {
  201. IoMarkIrpPending(Extension->CurrentWriteIrp);
  202. setFirstStatus = TRUE;
  203. firstStatus = STATUS_PENDING;
  204. }
  205. IoSetCancelRoutine(
  206. Extension->CurrentWriteIrp,
  207. MoxaCancelCurrentWrite
  208. );
  209. MOXA_INC_REFERENCE(Extension->CurrentWriteIrp);
  210. if (useATimer) {
  211. MoxaSetTimer(
  212. &Extension->WriteRequestTotalTimer,
  213. totalTime,
  214. &Extension->TotalWriteTimeoutDpc,
  215. Extension
  216. );
  217. MOXA_INC_REFERENCE(Extension->CurrentWriteIrp);
  218. }
  219. IoReleaseCancelSpinLock(oldIrql);
  220. KeReleaseSpinLock(
  221. &Extension->ControlLock,
  222. controlIrql
  223. );
  224. break;
  225. }
  226. }
  227. }
  228. MoxaGetNextWrite(
  229. &Extension->CurrentWriteIrp,
  230. &Extension->WriteQueue,
  231. &newIrp,
  232. TRUE,
  233. Extension
  234. );
  235. } while (newIrp);
  236. return firstStatus;
  237. }
  238. BOOLEAN
  239. MoxaPutB(
  240. IN PVOID Context
  241. )
  242. {
  243. PMOXA_DEVICE_EXTENSION extension = Context;
  244. PMOXA_IOCTL_PUTB Pb;
  245. /*
  246. PUCHAR base, ofs, buff, writeChar;
  247. PUSHORT rptr, wptr;
  248. USHORT txMask, spage, epage, bufHead;
  249. USHORT tail, head, count, count2;
  250. USHORT cnt, pageNo, pageOfs;
  251. ULONG dataLen;
  252. */
  253. Pb = (PMOXA_IOCTL_PUTB)extension->CurrentWriteIrp->AssociatedIrp.SystemBuffer;
  254. PBdataLen = Pb->DataLen;
  255. PBwriteChar = Pb->DataBuffer;
  256. PBbase = extension->PortBase;
  257. PBofs = extension->PortOfs;
  258. PBbuff = PBbase + DynPage_addr;
  259. PBrptr = (PUSHORT)(PBofs + TXrptr);
  260. PBwptr = (PUSHORT)(PBofs + TXwptr);
  261. PBtxMask = *(PUSHORT)(PBofs + TX_mask);
  262. PBspage = *(PUSHORT)(PBofs + Page_txb);
  263. PBepage = *(PUSHORT)(PBofs + EndPage_txb);
  264. PBtail = *PBwptr;
  265. PBhead = *PBrptr;
  266. PBcount = (PBhead > PBtail) ? (PBhead - PBtail - 1)
  267. : (PBhead - PBtail + PBtxMask);
  268. if (PBcount < PBdataLen) { /* Tx buffer no enough space! */
  269. *(PULONG)extension->CurrentWriteIrp->AssociatedIrp.SystemBuffer = 0;
  270. return FALSE;
  271. }
  272. if (PBspage == PBepage) {
  273. PBbufHead = *(PUSHORT)(PBofs + Ofs_txb);
  274. PBcount = (USHORT)PBdataLen;
  275. *(PBbase + Control_reg) = (UCHAR)PBspage;
  276. if (PBtail & 1) {
  277. PBbuff[PBbufHead+PBtail++] = *PBwriteChar++;
  278. PBtail &= PBtxMask;
  279. PBcount--;
  280. }
  281. PBcount2 = PBcount >> 1;
  282. while (PBcount2--) {
  283. *(PUSHORT)&(PBbuff[PBbufHead+PBtail]) = *((PUSHORT)PBwriteChar)++;
  284. PBtail += 2;
  285. PBtail &= PBtxMask;
  286. }
  287. if (PBcount & 1) {
  288. PBbuff[PBbufHead+PBtail++] = *PBwriteChar++;
  289. PBtail &= PBtxMask;
  290. }
  291. *PBwptr = PBtail;
  292. *(PBofs + CD180TXirq) = 1; /* start to send */
  293. }
  294. else {
  295. PBcount = (USHORT)PBdataLen;
  296. PBpageNo = PBspage + (PBtail >> 13);
  297. PBpageOfs = PBtail & Page_mask;
  298. do {
  299. PBcnt = Page_size - PBpageOfs;
  300. if (PBcnt > PBcount)
  301. PBcnt = PBcount;
  302. PBcount -= PBcnt;
  303. if (PBcnt) {
  304. *(PBbase + Control_reg) = (UCHAR)PBpageNo;
  305. if (PBpageOfs & 1) {
  306. PBbuff[PBpageOfs++] = *PBwriteChar++;
  307. PBcnt--;
  308. }
  309. PBcount2 = PBcnt >> 1;
  310. while (PBcount2--) {
  311. *(PUSHORT)&(PBbuff[PBpageOfs]) = *((PUSHORT)PBwriteChar)++;
  312. PBpageOfs += 2;
  313. }
  314. if (PBcnt & 1)
  315. PBbuff[PBpageOfs++] = *PBwriteChar++;
  316. }
  317. if (PBcount == 0)
  318. break;
  319. if (++PBpageNo == PBepage)
  320. PBpageNo = PBspage;
  321. PBpageOfs = 0;
  322. } while (TRUE);
  323. *PBwptr = (USHORT)((PBtail + PBdataLen) & PBtxMask);
  324. *(PBofs + CD180TXirq) = 1; /* start to send */
  325. }
  326. extension->PerfStats.TransmittedCount += PBdataLen;
  327. return FALSE;
  328. }
  329. BOOLEAN
  330. MoxaOut(
  331. IN PVOID Context
  332. )
  333. {
  334. PMOXA_DEVICE_EXTENSION extension = Context;
  335. PIO_STACK_LOCATION irpSp;
  336. irpSp = IoGetCurrentIrpStackLocation(
  337. extension->CurrentWriteIrp
  338. );
  339. extension->WriteLength = irpSp->Parameters.Write.Length;
  340. extension->WriteCurrentChar =
  341. extension->CurrentWriteIrp->AssociatedIrp.SystemBuffer;
  342. if (MoxaPutData(extension)) {
  343. MOXA_INC_REFERENCE(extension->CurrentWriteIrp);
  344. if (extension->PortFlag & NORMAL_TX_MODE)
  345. *(PUSHORT)(extension->PortOfs + HostStat) |= WakeupTx;
  346. else
  347. *(PUSHORT)(extension->PortOfs + HostStat) |= WakeupTxTrigger;
  348. WRcompFlag = FALSE;
  349. }
  350. else
  351. WRcompFlag = TRUE;
  352. return FALSE;
  353. }
  354. BOOLEAN
  355. MoxaPutData (
  356. IN PMOXA_DEVICE_EXTENSION Extension
  357. )
  358. {
  359. /*
  360. PUCHAR base, ofs, buff, writeChar;
  361. PUSHORT rptr, wptr;
  362. USHORT txMask, spage, epage, bufHead;
  363. USHORT tail, head, count, count2;
  364. USHORT cnt, len, pageNo, pageOfs;
  365. ULONG dataLen;
  366. */
  367. PDbase = Extension->PortBase;
  368. PDofs = Extension->PortOfs;
  369. PDbuff = PDbase + DynPage_addr;
  370. PDrptr = (PUSHORT)(PDofs + TXrptr);
  371. PDwptr = (PUSHORT)(PDofs + TXwptr);
  372. PDtxMask = *(PUSHORT)(PDofs + TX_mask);
  373. PDspage = *(PUSHORT)(PDofs + Page_txb);
  374. PDepage = *(PUSHORT)(PDofs + EndPage_txb);
  375. PDtail = *PDwptr;
  376. PDhead = *PDrptr;
  377. PDdataLen = Extension->WriteLength;
  378. PDwriteChar = Extension->WriteCurrentChar;
  379. PDcount = (PDhead > PDtail) ? (PDhead - PDtail - 1)
  380. : (PDhead - PDtail + PDtxMask);
  381. if (!PDcount) /* Tx buffer no space! */
  382. return TRUE;
  383. if (PDspage == PDepage) {
  384. PDbufHead = *(PUSHORT)(PDofs + Ofs_txb);
  385. if (PDcount > PDdataLen)
  386. PDcount = (USHORT)PDdataLen;
  387. PDdataLen -= PDcount;
  388. PDlen = PDcount;
  389. *(PDbase + Control_reg) = (UCHAR)PDspage;
  390. if (PDtail & 1) {
  391. PDbuff[PDbufHead+PDtail++] = *PDwriteChar++;
  392. PDtail &= PDtxMask;
  393. PDcount--;
  394. }
  395. PDcount2 = PDcount >> 1;
  396. while (PDcount2--) {
  397. *(PUSHORT)&(PDbuff[PDbufHead+PDtail]) = *((PUSHORT)PDwriteChar)++;
  398. PDtail += 2;
  399. PDtail &= PDtxMask;
  400. }
  401. if (PDcount & 1) {
  402. PDbuff[PDbufHead+PDtail++] = *PDwriteChar++;
  403. PDtail &= PDtxMask;
  404. }
  405. *PDwptr = PDtail;
  406. *(PDofs + CD180TXirq) = 1; /* start to send */
  407. }
  408. else {
  409. if (PDcount > PDdataLen)
  410. PDcount = (USHORT)PDdataLen;
  411. PDdataLen -= PDcount;
  412. PDlen = PDcount;
  413. PDpageNo = PDspage + (PDtail >> 13);
  414. PDpageOfs = PDtail & Page_mask;
  415. do {
  416. PDcnt = Page_size - PDpageOfs;
  417. if (PDcnt > PDcount)
  418. PDcnt = PDcount;
  419. PDcount -= PDcnt;
  420. if (PDcnt) {
  421. *(PDbase + Control_reg) = (UCHAR)PDpageNo;
  422. if (PDpageOfs & 1) {
  423. PDbuff[PDpageOfs++] = *PDwriteChar++;
  424. PDcnt--;
  425. }
  426. PDcount2 = PDcnt >> 1;
  427. while (PDcount2--) {
  428. *(PUSHORT)&(PDbuff[PDpageOfs]) = *((PUSHORT)PDwriteChar)++;
  429. PDpageOfs += 2;
  430. }
  431. if (PDcnt & 1)
  432. PDbuff[PDpageOfs++] = *PDwriteChar++;
  433. }
  434. if (PDcount == 0)
  435. break;
  436. if (++PDpageNo == PDepage)
  437. PDpageNo = PDspage;
  438. PDpageOfs = 0;
  439. } while (TRUE);
  440. *PDwptr = (PDtail + PDlen) & PDtxMask;
  441. *(PDofs + CD180TXirq) = 1;
  442. }
  443. Extension->PerfStats.TransmittedCount += PDlen;
  444. Extension->WriteLength = PDdataLen;
  445. if (PDdataLen) {
  446. Extension->WriteCurrentChar = PDwriteChar;
  447. return TRUE;
  448. }
  449. else if (Extension->PortFlag & NORMAL_TX_MODE) {
  450. return TRUE;
  451. }
  452. else {
  453. PDtail = *PDwptr;
  454. PDhead = *PDrptr;
  455. PDcount = (PDtail >= PDhead) ? (PDtail - PDhead)
  456. : (PDtail - PDhead + PDtxMask + 1);
  457. if (PDcount >= MoxaTxLowWater)
  458. return TRUE;
  459. else
  460. return FALSE;
  461. }
  462. }
  463. VOID
  464. MoxaGetNextWrite(
  465. IN PIRP *CurrentOpIrp,
  466. IN PLIST_ENTRY QueueToProcess,
  467. IN PIRP *NewIrp,
  468. IN BOOLEAN CompleteCurrent,
  469. IN PMOXA_DEVICE_EXTENSION Extension
  470. )
  471. {
  472. PMOXA_DEVICE_EXTENSION extension = CONTAINING_RECORD(
  473. QueueToProcess,
  474. MOXA_DEVICE_EXTENSION,
  475. WriteQueue
  476. );
  477. UNREFERENCED_PARAMETER(Extension);
  478. do {
  479. //
  480. // We could be completing a flush.
  481. //
  482. /*
  483. * extension->TotalCharsQueued NOT include current write
  484. *
  485. if (IoGetCurrentIrpStackLocation(*CurrentOpIrp)->MajorFunction
  486. == IRP_MJ_WRITE) {
  487. KIRQL oldIrql;
  488. IoAcquireCancelSpinLock(&oldIrql);
  489. extension->TotalCharsQueued -=
  490. IoGetCurrentIrpStackLocation(*CurrentOpIrp)
  491. ->Parameters.Write.Length;
  492. IoReleaseCancelSpinLock(oldIrql);
  493. }
  494. */
  495. MoxaGetNextIrp(
  496. CurrentOpIrp,
  497. QueueToProcess,
  498. NewIrp,
  499. CompleteCurrent,
  500. extension
  501. );
  502. if (!*NewIrp) {
  503. KIRQL oldIrql;
  504. IoAcquireCancelSpinLock(&oldIrql);
  505. KeSynchronizeExecution(
  506. extension->Interrupt,
  507. MoxaProcessEmptyTransmit,
  508. extension
  509. );
  510. IoReleaseCancelSpinLock(oldIrql);
  511. break;
  512. }
  513. else if (IoGetCurrentIrpStackLocation(*NewIrp)->MajorFunction
  514. == IRP_MJ_FLUSH_BUFFERS) {
  515. (*NewIrp)->IoStatus.Status = STATUS_SUCCESS;
  516. }
  517. else {
  518. break;
  519. }
  520. } while (TRUE);
  521. }
  522. VOID
  523. MoxaCancelCurrentWrite(
  524. PDEVICE_OBJECT DeviceObject,
  525. PIRP Irp
  526. )
  527. {
  528. PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  529. MoxaTryToCompleteCurrent(
  530. extension,
  531. MoxaGrabWriteFromIsr,
  532. Irp->CancelIrql,
  533. STATUS_CANCELLED,
  534. &extension->CurrentWriteIrp,
  535. &extension->WriteQueue,
  536. NULL,
  537. &extension->WriteRequestTotalTimer,
  538. MoxaStartWrite,
  539. MoxaGetNextWrite
  540. );
  541. }
  542. BOOLEAN
  543. MoxaGrabWriteFromIsr(
  544. IN PVOID Context
  545. )
  546. {
  547. PMOXA_DEVICE_EXTENSION extension = Context;
  548. if (*(PUSHORT)(extension->PortOfs + HostStat) & (WakeupTx|WakeupTxTrigger)) {
  549. extension->CurrentWriteIrp->IoStatus.Information =
  550. IoGetCurrentIrpStackLocation(
  551. extension->CurrentWriteIrp
  552. )->Parameters.Write.Length -
  553. extension->WriteLength -
  554. GetDeviceTxQueue(extension);
  555. *(PUSHORT)(extension->PortOfs + HostStat) &= ~(WakeupTx|WakeupTxTrigger);
  556. extension->WriteLength = 0;
  557. MOXA_DEC_REFERENCE(extension->CurrentWriteIrp);
  558. MoxaFuncWithDumbWait(extension->PortOfs, FC_FlushQueue, 1); // flush OQueue
  559. }
  560. return FALSE;
  561. }
  562. BOOLEAN
  563. MoxaProcessEmptyTransmit(
  564. IN PVOID Context
  565. )
  566. {
  567. PMOXA_DEVICE_EXTENSION extension = Context;
  568. if ((extension->IsrWaitMask & SERIAL_EV_TXEMPTY) &&
  569. (!extension->CurrentWriteIrp) &&
  570. IsListEmpty(&extension->WriteQueue)) {
  571. extension->HistoryMask |= SERIAL_EV_TXEMPTY;
  572. if (extension->IrpMaskLocation) {
  573. *extension->IrpMaskLocation = extension->HistoryMask;
  574. extension->IrpMaskLocation = NULL;
  575. extension->HistoryMask = 0;
  576. extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  577. MoxaInsertQueueDpc(
  578. &extension->CommWaitDpc,
  579. NULL,
  580. NULL,
  581. extension
  582. );
  583. }
  584. }
  585. return FALSE;
  586. }
  587. VOID
  588. MoxaCompleteWrite(
  589. IN PKDPC Dpc,
  590. IN PVOID DeferredContext,
  591. IN PVOID SystemContext1,
  592. IN PVOID SystemContext2
  593. )
  594. {
  595. PMOXA_DEVICE_EXTENSION extension = DeferredContext;
  596. KIRQL oldIrql;
  597. IoAcquireCancelSpinLock(&oldIrql);
  598. MoxaTryToCompleteCurrent(
  599. extension,
  600. NULL,
  601. oldIrql,
  602. STATUS_SUCCESS,
  603. &extension->CurrentWriteIrp,
  604. &extension->WriteQueue,
  605. NULL,
  606. &extension->WriteRequestTotalTimer,
  607. MoxaStartWrite,
  608. MoxaGetNextWrite
  609. );
  610. MoxaDpcEpilogue(extension, Dpc);
  611. }
  612. VOID
  613. MoxaWriteTimeout(
  614. IN PKDPC Dpc,
  615. IN PVOID DeferredContext,
  616. IN PVOID SystemContext1,
  617. IN PVOID SystemContext2
  618. )
  619. {
  620. PMOXA_DEVICE_EXTENSION extension = DeferredContext;
  621. KIRQL oldIrql;
  622. IoAcquireCancelSpinLock(&oldIrql);
  623. MoxaTryToCompleteCurrent(
  624. extension,
  625. MoxaGrabWriteFromIsr,
  626. oldIrql,
  627. STATUS_TIMEOUT,
  628. &extension->CurrentWriteIrp,
  629. &extension->WriteQueue,
  630. NULL,
  631. &extension->WriteRequestTotalTimer,
  632. MoxaStartWrite,
  633. MoxaGetNextWrite
  634. );
  635. MoxaDpcEpilogue(extension, Dpc);
  636. }