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.

2411 lines
53 KiB

  1. /*++
  2. Module Name:
  3. utils.c
  4. Environment:
  5. Kernel mode
  6. Revision History :
  7. --*/
  8. #include "precomp.h"
  9. NTSTATUS
  10. MoxaCompleteIfError(
  11. IN PDEVICE_OBJECT DeviceObject,
  12. IN PIRP Irp
  13. )
  14. /*++
  15. Routine Description:
  16. If the current irp is not an IOCTL_SERIAL_GET_COMMSTATUS request and
  17. there is an error and the application requested abort on errors,
  18. then cancel the irp.
  19. Arguments:
  20. DeviceObject - Pointer to the device object for this device
  21. Irp - Pointer to the IRP to test.
  22. Return Value:
  23. STATUS_SUCCESS or STATUS_CANCELLED.
  24. --*/
  25. {
  26. PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  27. NTSTATUS status = STATUS_SUCCESS;
  28. USHORT dataError;
  29. if (extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) {
  30. if (extension->ErrorWord) {
  31. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  32. //
  33. // There is a current error in the driver. No requests should
  34. // come through except for the GET_COMMSTATUS.
  35. //
  36. if ((irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL) ||
  37. (irpSp->Parameters.DeviceIoControl.IoControlCode !=
  38. IOCTL_SERIAL_GET_COMMSTATUS)) {
  39. status = STATUS_CANCELLED;
  40. Irp->IoStatus.Status = STATUS_CANCELLED;
  41. Irp->IoStatus.Information = 0;
  42. MoxaCompleteRequest(extension, Irp, 0);
  43. }
  44. }
  45. }
  46. return status;
  47. }
  48. //
  49. // t is 2ms
  50. //
  51. VOID
  52. MoxaDelay(
  53. IN ULONG t
  54. )
  55. {
  56. LARGE_INTEGER delay;
  57. t *= 20000; /* delay unit = 100 ns */
  58. delay = RtlConvertUlongToLargeInteger(t);
  59. delay = RtlLargeIntegerNegate(delay);
  60. KeDelayExecutionThread(
  61. KernelMode,
  62. FALSE,
  63. &delay
  64. );
  65. }
  66. /* Must migrate to MoxaFunc1 for performace resaon */
  67. VOID
  68. MoxaFunc(
  69. IN PUCHAR PortOfs,
  70. IN UCHAR Command,
  71. IN USHORT Argument
  72. )
  73. {
  74. *(PUSHORT)(PortOfs + FuncArg) = Argument;
  75. *(PortOfs + FuncCode) = Command;
  76. MoxaWaitFinish(PortOfs);
  77. }
  78. VOID
  79. MoxaFunc1(
  80. IN PUCHAR PortOfs,
  81. IN UCHAR Command,
  82. IN USHORT Argument
  83. )
  84. {
  85. *(PUSHORT)(PortOfs + FuncArg) = Argument;
  86. *(PortOfs + FuncCode) = Command;
  87. MoxaWaitFinish1(PortOfs);
  88. }
  89. VOID
  90. MoxaFuncWithDumbWait(
  91. IN PUCHAR PortOfs,
  92. IN UCHAR Command,
  93. IN USHORT Argument
  94. )
  95. {
  96. *(PUSHORT)(PortOfs + FuncArg) = Argument;
  97. *(PortOfs + FuncCode) = Command;
  98. MoxaDumbWaitFinish(PortOfs);
  99. }
  100. VOID
  101. MoxaFuncWithLock(
  102. IN PMOXA_DEVICE_EXTENSION Extension,
  103. IN UCHAR Command,
  104. IN USHORT Argument
  105. )
  106. {
  107. PUCHAR ofs;
  108. KIRQL oldIrql;
  109. KeAcquireSpinLock(
  110. &Extension->ControlLock,
  111. &oldIrql
  112. );
  113. ofs = Extension->PortOfs;
  114. *(PUSHORT)(ofs + FuncArg) = Argument;
  115. *(ofs + FuncCode) = Command;
  116. MoxaWaitFinish(ofs);
  117. KeReleaseSpinLock(
  118. &Extension->ControlLock,
  119. oldIrql
  120. );
  121. }
  122. VOID
  123. MoxaFuncGetLineStatus(
  124. IN PUCHAR PortOfs,
  125. IN PUSHORT Argument
  126. )
  127. {
  128. *Argument = *(PUSHORT)(PortOfs + FlagStat) >> 4;
  129. }
  130. VOID
  131. MoxaFuncGetDataError(
  132. IN PUCHAR PortOfs,
  133. IN PUSHORT Argument
  134. )
  135. {
  136. *Argument = *(PUSHORT)(PortOfs + Data_error);
  137. *(PUSHORT)(PortOfs + Data_error) = 0;
  138. }
  139. BOOLEAN
  140. MoxaDumbWaitFinish(
  141. IN PUCHAR PortOfs
  142. )
  143. {
  144. LARGE_INTEGER targetTc, newTc, currTc, newTc1;
  145. ULONG unit, count;
  146. LARGE_INTEGER interval; /* 0.5 ms */
  147. USHORT cnt = 1000; /* timeout = 500 ms */
  148. KeQueryTickCount(&currTc);
  149. unit = KeQueryTimeIncrement();
  150. currTc = RtlExtendedIntegerMultiply(currTc, unit);
  151. interval = RtlConvertUlongToLargeInteger(5000L);
  152. targetTc = RtlLargeIntegerAdd(currTc, interval);
  153. do {
  154. count = 0;
  155. /*********************************************************************
  156. NOTE! sometimes I cann't leave the while loop. beacuse
  157. newTc = 0 (I don't know why). So I must set boundary
  158. MoxaLoopCnt to quit!
  159. /*********************************************************************/
  160. do {
  161. KeQueryTickCount(&newTc);
  162. newTc = RtlExtendedIntegerMultiply(newTc, unit);
  163. if (++count > MoxaLoopCnt)
  164. break;
  165. } while (!RtlLargeIntegerGreaterThanOrEqualTo(newTc, targetTc));
  166. if (*(PortOfs + FuncCode))
  167. targetTc = RtlLargeIntegerAdd(targetTc, interval);
  168. else
  169. return TRUE;
  170. } while (cnt--);
  171. return FALSE;
  172. }
  173. BOOLEAN
  174. MoxaWaitFinish(
  175. IN PUCHAR PortOfs
  176. )
  177. {
  178. LARGE_INTEGER targetTc, newTc, currTc, newTc1;
  179. ULONG unit, count;
  180. LARGE_INTEGER interval; /* 0.5 ms */
  181. USHORT cnt = 1000; /* timeout = 500 ms */
  182. KeQueryTickCount(&currTc);
  183. unit = KeQueryTimeIncrement();
  184. currTc = RtlExtendedIntegerMultiply(currTc, unit);
  185. interval = RtlConvertUlongToLargeInteger(5000L);
  186. targetTc = RtlLargeIntegerAdd(currTc, interval);
  187. do {
  188. count = 0;
  189. /*********************************************************************
  190. NOTE! sometimes I cann't leave the while loop. beacuse
  191. newTc = 0 (I don't know why). So I must set boundary
  192. MoxaLoopCnt to quit!
  193. /*********************************************************************/
  194. do {
  195. KeQueryTickCount(&newTc);
  196. newTc = RtlExtendedIntegerMultiply(newTc, unit);
  197. if (++count > MoxaLoopCnt)
  198. break;
  199. } while (!RtlLargeIntegerGreaterThanOrEqualTo(newTc, targetTc));
  200. if (*(PortOfs + FuncCode))
  201. targetTc = RtlLargeIntegerAdd(targetTc, interval);
  202. else
  203. return TRUE;
  204. } while (cnt--);
  205. return FALSE;
  206. }
  207. BOOLEAN
  208. MoxaWaitFinish1(
  209. IN PUCHAR PortOfs
  210. )
  211. {
  212. USHORT cnt = 250; /* timeout = 500 ms */
  213. while (cnt--) {
  214. if (*(PortOfs + FuncCode))
  215. MoxaDelay(1L);
  216. else
  217. return TRUE;
  218. }
  219. return FALSE;
  220. }
  221. NTSTATUS
  222. MoxaGetDivisorFromBaud(
  223. IN ULONG ClockType,
  224. IN LONG DesiredBaud,
  225. OUT PSHORT AppropriateDivisor
  226. )
  227. {
  228. NTSTATUS status = STATUS_SUCCESS;
  229. ULONG clockRate;
  230. SHORT calculatedDivisor;
  231. ULONG denominator;
  232. ULONG remainder;
  233. //
  234. // Allow up to a 1 percent error
  235. //
  236. ULONG maxRemain98 = 98304;
  237. ULONG maxRemain11 = 110592;
  238. ULONG maxRemain14 = 147456;
  239. ULONG maxRemain;
  240. if (ClockType == 1)
  241. clockRate = 11059200;
  242. else if (ClockType == 2)
  243. clockRate = 14745600;
  244. else
  245. clockRate = 9830400;
  246. //
  247. // Reject any non-positive bauds.
  248. //
  249. denominator = DesiredBaud * (ULONG)16;
  250. if (DesiredBaud <= 0) {
  251. *AppropriateDivisor = -1;
  252. } else if ((LONG)denominator < DesiredBaud) {
  253. //
  254. // If the desired baud was so huge that it cause the denominator
  255. // calculation to wrap, don't support it.
  256. //
  257. *AppropriateDivisor = -1;
  258. } else {
  259. if (ClockType == 0) { /* ver1.0 BOX */
  260. maxRemain = maxRemain98;
  261. }
  262. else if (ClockType == 1) { /* ver2.0 BOX */
  263. maxRemain = maxRemain11;
  264. }
  265. else { /* ver3.0 BOX */
  266. maxRemain = maxRemain14;
  267. }
  268. calculatedDivisor = (SHORT)(clockRate / denominator);
  269. remainder = clockRate % denominator;
  270. //
  271. // Round up.
  272. //
  273. if (((remainder * 2) > clockRate) && (DesiredBaud != 110))
  274. calculatedDivisor++;
  275. //
  276. // Only let the remainder calculations effect us if
  277. // the baud rate is > 9600.
  278. //
  279. if (DesiredBaud >= 9600)
  280. //
  281. // If the remainder is less than the maximum remainder (wrt
  282. // the clockRate) or the remainder + the maximum remainder is
  283. // greater than or equal to the clockRate then assume that the
  284. // baud is ok.
  285. //
  286. if ((remainder >= maxRemain) && ((remainder+maxRemain) < clockRate))
  287. calculatedDivisor = -1;
  288. //
  289. // Don't support a baud that causes the denominator to
  290. // be larger than the clock.
  291. //
  292. if (denominator > clockRate)
  293. calculatedDivisor = -1;
  294. *AppropriateDivisor = calculatedDivisor;
  295. }
  296. if (*AppropriateDivisor == -1) {
  297. status = STATUS_INVALID_PARAMETER;
  298. }
  299. return status;
  300. }
  301. NTSTATUS
  302. MoxaStartOrQueue(
  303. IN PMOXA_DEVICE_EXTENSION Extension,
  304. IN PIRP Irp,
  305. IN PLIST_ENTRY QueueToExamine,
  306. IN PIRP *CurrentOpIrp,
  307. IN PMOXA_START_ROUTINE Starter
  308. )
  309. {
  310. KIRQL oldIrql;
  311. IoAcquireCancelSpinLock(&oldIrql);
  312. //
  313. // If this is a write irp then take the amount of characters
  314. // to write and add it to the count of characters to write.
  315. //
  316. if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction
  317. == IRP_MJ_WRITE)
  318. Extension->TotalCharsQueued +=
  319. IoGetCurrentIrpStackLocation(Irp)
  320. ->Parameters.Write.Length;
  321. if ((IsListEmpty(QueueToExamine)) &&
  322. !(*CurrentOpIrp)) {
  323. //
  324. // There were no current operation. Mark this one as
  325. // current and start it up.
  326. //
  327. *CurrentOpIrp = Irp;
  328. IoReleaseCancelSpinLock(oldIrql);
  329. return Starter(Extension);
  330. } else {
  331. //
  332. // We don't know how long the irp will be in the
  333. // queue. So we need to handle cancel.
  334. //
  335. if (Irp->Cancel) {
  336. Irp->IoStatus.Status = STATUS_CANCELLED;
  337. IoReleaseCancelSpinLock(oldIrql);
  338. MoxaCompleteRequest(Extension, Irp, 0);
  339. return STATUS_CANCELLED;
  340. } else {
  341. Irp->IoStatus.Status = STATUS_PENDING;
  342. IoMarkIrpPending(Irp);
  343. InsertTailList(
  344. QueueToExamine,
  345. &Irp->Tail.Overlay.ListEntry
  346. );
  347. IoSetCancelRoutine(
  348. Irp,
  349. MoxaCancelQueued
  350. );
  351. IoReleaseCancelSpinLock(oldIrql);
  352. return STATUS_PENDING;
  353. }
  354. }
  355. }
  356. VOID
  357. MoxaCancelQueued(
  358. PDEVICE_OBJECT DeviceObject,
  359. PIRP Irp
  360. )
  361. {
  362. PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  363. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  364. Irp->IoStatus.Status = STATUS_CANCELLED;
  365. Irp->IoStatus.Information = 0;
  366. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  367. //
  368. // If this is a write irp then take the amount of characters
  369. // to write and subtract it from the count of characters to write.
  370. //
  371. if (irpSp->MajorFunction == IRP_MJ_WRITE)
  372. extension->TotalCharsQueued -= irpSp->Parameters.Write.Length;
  373. IoReleaseCancelSpinLock(Irp->CancelIrql);
  374. MoxaCompleteRequest(extension,
  375. Irp,
  376. // IO_SERIAL_INCREMENT
  377. IO_NO_INCREMENT
  378. );
  379. }
  380. VOID
  381. MoxaGetNextIrp(
  382. IN PIRP *CurrentOpIrp,
  383. IN PLIST_ENTRY QueueToProcess,
  384. OUT PIRP *NextIrp,
  385. IN BOOLEAN CompleteCurrent,
  386. IN PMOXA_DEVICE_EXTENSION extension
  387. )
  388. {
  389. PIRP oldIrp;
  390. KIRQL oldIrql;
  391. IoAcquireCancelSpinLock(&oldIrql);
  392. oldIrp = *CurrentOpIrp;
  393. if (!IsListEmpty(QueueToProcess)) {
  394. PLIST_ENTRY headOfList;
  395. headOfList = RemoveHeadList(QueueToProcess);
  396. *CurrentOpIrp = CONTAINING_RECORD(
  397. headOfList,
  398. IRP,
  399. Tail.Overlay.ListEntry
  400. );
  401. IoSetCancelRoutine(
  402. *CurrentOpIrp,
  403. NULL
  404. );
  405. } else {
  406. *CurrentOpIrp = NULL;
  407. }
  408. *NextIrp = *CurrentOpIrp;
  409. IoReleaseCancelSpinLock(oldIrql);
  410. if (CompleteCurrent) {
  411. if (oldIrp) {
  412. MoxaCompleteRequest(extension,
  413. oldIrp,
  414. // IO_SERIAL_INCREMENT
  415. IO_NO_INCREMENT
  416. );
  417. }
  418. }
  419. }
  420. VOID
  421. MoxaTryToCompleteCurrent(
  422. IN PMOXA_DEVICE_EXTENSION Extension,
  423. IN PKSYNCHRONIZE_ROUTINE SynchRoutine OPTIONAL,
  424. IN KIRQL IrqlForRelease,
  425. IN NTSTATUS StatusToUse,
  426. IN PIRP *CurrentOpIrp,
  427. IN PLIST_ENTRY QueueToProcess OPTIONAL,
  428. IN PKTIMER IntervalTimer OPTIONAL,
  429. IN PKTIMER TotalTimer OPTIONAL,
  430. IN PMOXA_START_ROUTINE Starter OPTIONAL,
  431. IN PMOXA_GET_NEXT_ROUTINE GetNextIrp OPTIONAL
  432. )
  433. {
  434. if (*CurrentOpIrp == NULL) {
  435. IoReleaseCancelSpinLock(IrqlForRelease);
  436. return;
  437. }
  438. MOXA_DEC_REFERENCE(*CurrentOpIrp);
  439. if (SynchRoutine) {
  440. KeSynchronizeExecution(
  441. Extension->Interrupt,
  442. SynchRoutine,
  443. Extension
  444. );
  445. }
  446. MoxaRundownIrpRefs(
  447. CurrentOpIrp,
  448. IntervalTimer,
  449. TotalTimer,
  450. Extension
  451. );
  452. if (!MOXA_REFERENCE_COUNT(*CurrentOpIrp)) {
  453. PIRP newIrp;
  454. (*CurrentOpIrp)->IoStatus.Status = StatusToUse;
  455. if (StatusToUse == STATUS_CANCELLED)
  456. (*CurrentOpIrp)->IoStatus.Information = 0;
  457. if (GetNextIrp) {
  458. IoReleaseCancelSpinLock(IrqlForRelease);
  459. GetNextIrp(
  460. CurrentOpIrp,
  461. QueueToProcess,
  462. &newIrp,
  463. TRUE,
  464. Extension
  465. );
  466. if (newIrp)
  467. Starter(Extension);
  468. }
  469. else {
  470. PIRP oldIrp = *CurrentOpIrp;
  471. *CurrentOpIrp = NULL;
  472. IoReleaseCancelSpinLock(IrqlForRelease);
  473. MoxaCompleteRequest(Extension,
  474. oldIrp,
  475. // IO_SERIAL_INCREMENT
  476. IO_NO_INCREMENT
  477. );
  478. }
  479. } else {
  480. IoReleaseCancelSpinLock(IrqlForRelease);
  481. }
  482. }
  483. VOID
  484. MoxaRundownIrpRefs(
  485. IN PIRP *CurrentOpIrp,
  486. IN PKTIMER IntervalTimer OPTIONAL,
  487. IN PKTIMER TotalTimer OPTIONAL,
  488. IN PMOXA_DEVICE_EXTENSION pDevExt)
  489. {
  490. if ((*CurrentOpIrp)->CancelRoutine) {
  491. MOXA_DEC_REFERENCE(*CurrentOpIrp);
  492. IoSetCancelRoutine(
  493. *CurrentOpIrp,
  494. NULL
  495. );
  496. }
  497. if (IntervalTimer) {
  498. if (MoxaCancelTimer(IntervalTimer,pDevExt)) {
  499. MOXA_DEC_REFERENCE(*CurrentOpIrp);
  500. }
  501. }
  502. if (TotalTimer) {
  503. if (MoxaCancelTimer(TotalTimer,pDevExt)) {
  504. MOXA_DEC_REFERENCE(*CurrentOpIrp);
  505. }
  506. }
  507. }
  508. BOOLEAN
  509. MoxaInsertQueueDpc(IN PRKDPC PDpc, IN PVOID Sarg1, IN PVOID Sarg2,
  510. IN PMOXA_DEVICE_EXTENSION PDevExt)
  511. /*++
  512. Routine Description:
  513. This function must be called to queue DPC's for the serial driver.
  514. Arguments:
  515. PDpc thru Sarg2 - Standard args to KeInsertQueueDpc()
  516. PDevExt - Pointer to the device extension for the device that needs to
  517. queue a DPC
  518. Return Value:
  519. Kicks up return value from KeInsertQueueDpc()
  520. --*/
  521. {
  522. BOOLEAN queued;
  523. InterlockedIncrement(&PDevExt->DpcCount);
  524. queued = KeInsertQueueDpc(PDpc, Sarg1, Sarg2);
  525. if (!queued) {
  526. ULONG pendingCnt;
  527. pendingCnt = InterlockedDecrement(&PDevExt->DpcCount);
  528. if (pendingCnt == 0) {
  529. KeSetEvent(&PDevExt->PendingIRPEvent, IO_NO_INCREMENT, FALSE);
  530. }
  531. }
  532. return queued;
  533. }
  534. BOOLEAN
  535. MoxaSetTimer(IN PKTIMER Timer, IN LARGE_INTEGER DueTime,
  536. IN PKDPC Dpc OPTIONAL, IN PMOXA_DEVICE_EXTENSION PDevExt)
  537. /*++
  538. Routine Description:
  539. This function must be called to set timers for the serial driver.
  540. Arguments:
  541. Timer - pointer to timer dispatcher object
  542. DueTime - time at which the timer should expire
  543. Dpc - option Dpc
  544. PDevExt - Pointer to the device extension for the device that needs to
  545. set a timer
  546. Return Value:
  547. Kicks up return value from KeSetTimer()
  548. --*/
  549. {
  550. BOOLEAN set;
  551. InterlockedIncrement(&PDevExt->DpcCount);
  552. set = KeSetTimer(Timer, DueTime, Dpc);
  553. if (set) {
  554. InterlockedDecrement(&PDevExt->DpcCount);
  555. }
  556. return set;
  557. }
  558. BOOLEAN
  559. MoxaCancelTimer(IN PKTIMER Timer, IN PMOXA_DEVICE_EXTENSION PDevExt)
  560. /*++
  561. Routine Description:
  562. This function must be called to cancel timers for the serial driver.
  563. Arguments:
  564. Timer - pointer to timer dispatcher object
  565. PDevExt - Pointer to the device extension for the device that needs to
  566. set a timer
  567. Return Value:
  568. True if timer was cancelled
  569. --*/
  570. {
  571. BOOLEAN cancelled;
  572. cancelled = KeCancelTimer(Timer);
  573. if (cancelled) {
  574. MoxaDpcEpilogue(PDevExt, Timer->Dpc);
  575. }
  576. return cancelled;
  577. }
  578. VOID
  579. MoxaDpcEpilogue(IN PMOXA_DEVICE_EXTENSION PDevExt, PKDPC PDpc)
  580. /*++
  581. Routine Description:
  582. This function must be called at the end of every dpc function.
  583. Arguments:
  584. PDevObj - Pointer to the device object we are tracking dpc's for.
  585. Return Value:
  586. None.
  587. --*/
  588. {
  589. LONG pendingCnt;
  590. #if 1 // !DBG
  591. UNREFERENCED_PARAMETER(PDpc);
  592. #endif
  593. pendingCnt = InterlockedDecrement(&PDevExt->DpcCount);
  594. // ASSERT(pendingCnt >= 0);
  595. if (pendingCnt == 0) {
  596. KeSetEvent(&PDevExt->PendingDpcEvent, IO_NO_INCREMENT, FALSE);
  597. }
  598. }
  599. VOID
  600. MoxaKillAllReadsOrWrites(
  601. IN PDEVICE_OBJECT DeviceObject,
  602. IN PLIST_ENTRY QueueToClean,
  603. IN PIRP *CurrentOpIrp
  604. )
  605. {
  606. KIRQL cancelIrql;
  607. PDRIVER_CANCEL cancelRoutine;
  608. //
  609. // We acquire the cancel spin lock. This will prevent the
  610. // irps from moving around.
  611. //
  612. IoAcquireCancelSpinLock(&cancelIrql);
  613. //
  614. // Clean the list from back to front.
  615. //
  616. while (!IsListEmpty(QueueToClean)) {
  617. PIRP currentLastIrp = CONTAINING_RECORD(
  618. QueueToClean->Blink,
  619. IRP,
  620. Tail.Overlay.ListEntry
  621. );
  622. RemoveEntryList(QueueToClean->Blink);
  623. cancelRoutine = currentLastIrp->CancelRoutine;
  624. currentLastIrp->CancelIrql = cancelIrql;
  625. currentLastIrp->CancelRoutine = NULL;
  626. currentLastIrp->Cancel = TRUE;
  627. /* 8-30-01 by William
  628. cancelRoutine(
  629. DeviceObject,
  630. currentLastIrp
  631. );
  632. IoAcquireCancelSpinLock(&cancelIrql);
  633. */
  634. if (cancelRoutine) {
  635. cancelRoutine(
  636. DeviceObject,
  637. currentLastIrp
  638. );
  639. IoAcquireCancelSpinLock(&cancelIrql);
  640. }
  641. }
  642. //
  643. // The queue is clean. Now go after the current if
  644. // it's there.
  645. //
  646. if (*CurrentOpIrp) {
  647. cancelRoutine = (*CurrentOpIrp)->CancelRoutine;
  648. (*CurrentOpIrp)->Cancel = TRUE;
  649. //
  650. // If the current irp is not in a cancelable state
  651. // then it *will* try to enter one and the above
  652. // assignment will kill it. If it already is in
  653. // a cancelable state then the following will kill it.
  654. //
  655. if (cancelRoutine) {
  656. (*CurrentOpIrp)->CancelRoutine = NULL;
  657. (*CurrentOpIrp)->CancelIrql = cancelIrql;
  658. //
  659. // This irp is already in a cancelable state. We simply
  660. // mark it as canceled and call the cancel routine for
  661. // it.
  662. //
  663. cancelRoutine(
  664. DeviceObject,
  665. *CurrentOpIrp
  666. );
  667. }
  668. else
  669. IoReleaseCancelSpinLock(cancelIrql);
  670. }
  671. else
  672. IoReleaseCancelSpinLock(cancelIrql);
  673. }
  674. VOID
  675. MoxaCommError(
  676. IN PKDPC Dpc,
  677. IN PVOID DeferredContext,
  678. IN PVOID SystemContext1,
  679. IN PVOID SystemContext2
  680. )
  681. {
  682. PMOXA_DEVICE_EXTENSION extension = DeferredContext;
  683. MoxaKillAllReadsOrWrites(
  684. extension->DeviceObject,
  685. &extension->WriteQueue,
  686. &extension->CurrentWriteIrp
  687. );
  688. MoxaKillAllReadsOrWrites(
  689. extension->DeviceObject,
  690. &extension->ReadQueue,
  691. &extension->CurrentReadIrp
  692. );
  693. MoxaDpcEpilogue(extension, Dpc);
  694. }
  695. USHORT
  696. GetDeviceTxQueueWithLock(
  697. IN PMOXA_DEVICE_EXTENSION Extension
  698. )
  699. {
  700. KIRQL controlIrql, oldIrql;
  701. PUCHAR ofs;
  702. PUSHORT rptr, wptr;
  703. USHORT lenMask, count;
  704. IoAcquireCancelSpinLock(&oldIrql);
  705. ofs = Extension->PortOfs;
  706. rptr = (PUSHORT)(ofs + TXrptr);
  707. wptr = (PUSHORT)(ofs + TXwptr);
  708. lenMask = *(PUSHORT)(ofs + TX_mask);
  709. count = (*wptr >= *rptr) ? (*wptr - *rptr)
  710. : (*wptr - *rptr + lenMask + 1);
  711. KeAcquireSpinLock(
  712. &Extension->ControlLock,
  713. &controlIrql
  714. );
  715. *(ofs + FuncCode) = FC_ExtOQueue;
  716. MoxaWaitFinish(ofs);
  717. count += *(PUSHORT)(ofs + FuncArg);
  718. KeReleaseSpinLock(
  719. &Extension->ControlLock,
  720. controlIrql
  721. );
  722. IoReleaseCancelSpinLock(oldIrql);
  723. return count;
  724. }
  725. USHORT
  726. GetDeviceTxQueue(
  727. IN PMOXA_DEVICE_EXTENSION Extension
  728. )
  729. {
  730. PUCHAR ofs;
  731. PUSHORT rptr, wptr;
  732. USHORT lenMask, count;
  733. ofs = Extension->PortOfs;
  734. rptr = (PUSHORT)(ofs + TXrptr);
  735. wptr = (PUSHORT)(ofs + TXwptr);
  736. lenMask = *(PUSHORT)(ofs + TX_mask);
  737. count = (*wptr >= *rptr) ? (*wptr - *rptr)
  738. : (*wptr - *rptr + lenMask + 1);
  739. *(ofs + FuncCode) = FC_ExtOQueue;
  740. MoxaDumbWaitFinish(ofs);
  741. count += *(PUSHORT)(ofs + FuncArg);
  742. return count;
  743. }
  744. USHORT
  745. GetDeviceRxQueueWithLock(
  746. IN PMOXA_DEVICE_EXTENSION Extension
  747. )
  748. {
  749. KIRQL controlIrql, oldIrql;
  750. PUCHAR ofs;
  751. PUSHORT rptr, wptr;
  752. USHORT lenMask, count;
  753. IoAcquireCancelSpinLock(&oldIrql);
  754. ofs = Extension->PortOfs;
  755. rptr = (PUSHORT)(ofs + RXrptr);
  756. wptr = (PUSHORT)(ofs + RXwptr);
  757. lenMask = *(PUSHORT)(ofs + RX_mask);
  758. count = (*wptr >= *rptr) ? (*wptr - *rptr)
  759. : (*wptr - *rptr + lenMask + 1);
  760. KeAcquireSpinLock(
  761. &Extension->ControlLock,
  762. &controlIrql
  763. );
  764. *(ofs + FuncCode) = FC_ExtIQueue;
  765. MoxaWaitFinish(ofs);
  766. count += *(PUSHORT)(ofs + FuncArg);
  767. KeReleaseSpinLock(
  768. &Extension->ControlLock,
  769. controlIrql
  770. );
  771. IoReleaseCancelSpinLock(oldIrql);
  772. return count;
  773. }
  774. VOID
  775. MoxaLogError(
  776. IN PDRIVER_OBJECT DriverObject,
  777. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  778. IN PHYSICAL_ADDRESS P1,
  779. IN PHYSICAL_ADDRESS P2,
  780. IN ULONG SequenceNumber,
  781. IN UCHAR MajorFunctionCode,
  782. IN UCHAR RetryCount,
  783. IN ULONG UniqueErrorValue,
  784. IN NTSTATUS FinalStatus,
  785. IN NTSTATUS SpecificIOStatus,
  786. IN ULONG LengthOfInsert1,
  787. IN PWCHAR Insert1,
  788. IN ULONG LengthOfInsert2,
  789. IN PWCHAR Insert2
  790. )
  791. /*++
  792. Routine Description:
  793. This routine allocates an error log entry, copies the supplied data
  794. to it, and requests that it be written to the error log file.
  795. Arguments:
  796. DriverObject - A pointer to the driver object for the device.
  797. DeviceObject - A pointer to the device object associated with the
  798. device that had the error, early in initialization, one may not
  799. yet exist.
  800. P1,P2 - If phyical addresses for the controller ports involved
  801. with the error are available, put them through as dump data.
  802. SequenceNumber - A ulong value that is unique to an IRP over the
  803. life of the irp in this driver - 0 generally means an error not
  804. associated with an irp.
  805. MajorFunctionCode - If there is an error associated with the irp,
  806. this is the major function code of that irp.
  807. RetryCount - The number of times a particular operation has been
  808. retried.
  809. UniqueErrorValue - A unique long word that identifies the particular
  810. call to this function.
  811. FinalStatus - The final status given to the irp that was associated
  812. with this error. If this log entry is being made during one of
  813. the retries this value will be STATUS_SUCCESS.
  814. SpecificIOStatus - The IO status for a particular error.
  815. LengthOfInsert1 - The length in bytes (including the terminating NULL)
  816. of the first insertion string.
  817. Insert1 - The first insertion string.
  818. LengthOfInsert2 - The length in bytes (including the terminating NULL)
  819. of the second insertion string. NOTE, there must
  820. be a first insertion string for their to be
  821. a second insertion string.
  822. Insert2 - The second insertion string.
  823. Return Value:
  824. None.
  825. --*/
  826. {
  827. PIO_ERROR_LOG_PACKET errorLogEntry;
  828. PVOID objectToUse;
  829. SHORT dumpToAllocate = 0;
  830. PUCHAR ptrToFirstInsert;
  831. PUCHAR ptrToSecondInsert;
  832. //PAGED_CODE();
  833. if (Insert1 == NULL) {
  834. LengthOfInsert1 = 0;
  835. }
  836. if (Insert2 == NULL) {
  837. LengthOfInsert2 = 0;
  838. }
  839. if (ARGUMENT_PRESENT(DeviceObject)) {
  840. objectToUse = DeviceObject;
  841. } else {
  842. objectToUse = DriverObject;
  843. }
  844. if (MoxaMemCompare(
  845. P1,
  846. (ULONG)1,
  847. MoxaPhysicalZero,
  848. (ULONG)1
  849. ) != AddressesAreEqual) {
  850. dumpToAllocate = (SHORT)sizeof(PHYSICAL_ADDRESS);
  851. }
  852. if (MoxaMemCompare(
  853. P2,
  854. (ULONG)1,
  855. MoxaPhysicalZero,
  856. (ULONG)1
  857. ) != AddressesAreEqual) {
  858. dumpToAllocate += (SHORT)sizeof(PHYSICAL_ADDRESS);
  859. }
  860. errorLogEntry = IoAllocateErrorLogEntry(
  861. objectToUse,
  862. (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
  863. dumpToAllocate
  864. + LengthOfInsert1 +
  865. LengthOfInsert2)
  866. );
  867. if ( errorLogEntry != NULL ) {
  868. errorLogEntry->ErrorCode = SpecificIOStatus;
  869. errorLogEntry->SequenceNumber = SequenceNumber;
  870. errorLogEntry->MajorFunctionCode = MajorFunctionCode;
  871. errorLogEntry->RetryCount = RetryCount;
  872. errorLogEntry->UniqueErrorValue = UniqueErrorValue;
  873. errorLogEntry->FinalStatus = FinalStatus;
  874. errorLogEntry->DumpDataSize = dumpToAllocate;
  875. if (dumpToAllocate) {
  876. RtlCopyMemory(
  877. &errorLogEntry->DumpData[0],
  878. &P1,
  879. sizeof(PHYSICAL_ADDRESS)
  880. );
  881. if (dumpToAllocate > sizeof(PHYSICAL_ADDRESS)) {
  882. RtlCopyMemory(
  883. ((PUCHAR)&errorLogEntry->DumpData[0])
  884. +sizeof(PHYSICAL_ADDRESS),
  885. &P2,
  886. sizeof(PHYSICAL_ADDRESS)
  887. );
  888. ptrToFirstInsert =
  889. ((PUCHAR)&errorLogEntry->DumpData[0])+(2*sizeof(PHYSICAL_ADDRESS));
  890. } else {
  891. ptrToFirstInsert =
  892. ((PUCHAR)&errorLogEntry->DumpData[0])+sizeof(PHYSICAL_ADDRESS);
  893. }
  894. } else {
  895. ptrToFirstInsert = (PUCHAR)&errorLogEntry->DumpData[0];
  896. }
  897. ptrToSecondInsert = ptrToFirstInsert + LengthOfInsert1;
  898. if (LengthOfInsert1) {
  899. errorLogEntry->NumberOfStrings = 1;
  900. errorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert -
  901. (PUCHAR)errorLogEntry);
  902. RtlCopyMemory(
  903. ptrToFirstInsert,
  904. Insert1,
  905. LengthOfInsert1
  906. );
  907. if (LengthOfInsert2) {
  908. errorLogEntry->NumberOfStrings = 2;
  909. RtlCopyMemory(
  910. ptrToSecondInsert,
  911. Insert2,
  912. LengthOfInsert2
  913. );
  914. }
  915. }
  916. IoWriteErrorLogEntry(errorLogEntry);
  917. }
  918. }
  919. MOXA_MEM_COMPARES
  920. MoxaMemCompare(
  921. IN PHYSICAL_ADDRESS A,
  922. IN ULONG SpanOfA,
  923. IN PHYSICAL_ADDRESS B,
  924. IN ULONG SpanOfB
  925. )
  926. /*++
  927. Routine Description:
  928. Compare two phsical address.
  929. Arguments:
  930. A - One half of the comparison.
  931. SpanOfA - In units of bytes, the span of A.
  932. B - One half of the comparison.
  933. SpanOfB - In units of bytes, the span of B.
  934. Return Value:
  935. The result of the comparison.
  936. --*/
  937. {
  938. LARGE_INTEGER a;
  939. LARGE_INTEGER b;
  940. LARGE_INTEGER lower;
  941. ULONG lowerSpan;
  942. LARGE_INTEGER higher;
  943. //PAGED_CODE();
  944. a = A;
  945. b = B;
  946. if (a.QuadPart == b.QuadPart) {
  947. return AddressesAreEqual;
  948. }
  949. if (a.QuadPart > b.QuadPart) {
  950. higher = a;
  951. lower = b;
  952. lowerSpan = SpanOfB;
  953. } else {
  954. higher = b;
  955. lower = a;
  956. lowerSpan = SpanOfA;
  957. }
  958. if ((higher.QuadPart - lower.QuadPart) >= lowerSpan) {
  959. return AddressesAreDisjoint;
  960. }
  961. return AddressesOverlap;
  962. }
  963. VOID
  964. MoxaFilterCancelQueued(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  965. /*++
  966. Routine Description:
  967. This routine will be used cancel irps on the stalled queue.
  968. Arguments:
  969. PDevObj - Pointer to the device object.
  970. PIrp - Pointer to the Irp to cancel
  971. Return Value:
  972. None.
  973. --*/
  974. {
  975. PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  976. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  977. PIrp->IoStatus.Status = STATUS_CANCELLED;
  978. PIrp->IoStatus.Information = 0;
  979. RemoveEntryList(&PIrp->Tail.Overlay.ListEntry);
  980. IoReleaseCancelSpinLock(PIrp->CancelIrql);
  981. }
  982. VOID
  983. MoxaKillAllStalled(IN PDEVICE_OBJECT PDevObj)
  984. {
  985. KIRQL cancelIrql;
  986. PDRIVER_CANCEL cancelRoutine;
  987. PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  988. IoAcquireCancelSpinLock(&cancelIrql);
  989. while (!IsListEmpty(&pDevExt->StalledIrpQueue)) {
  990. PIRP currentLastIrp = CONTAINING_RECORD(pDevExt->StalledIrpQueue.Blink,
  991. IRP, Tail.Overlay.ListEntry);
  992. RemoveEntryList(pDevExt->StalledIrpQueue.Blink);
  993. cancelRoutine = currentLastIrp->CancelRoutine;
  994. currentLastIrp->CancelIrql = cancelIrql;
  995. currentLastIrp->CancelRoutine = NULL;
  996. currentLastIrp->Cancel = TRUE;
  997. cancelRoutine(PDevObj, currentLastIrp);
  998. IoAcquireCancelSpinLock(&cancelIrql);
  999. }
  1000. IoReleaseCancelSpinLock(cancelIrql);
  1001. }
  1002. NTSTATUS
  1003. MoxaFilterIrps(IN PIRP PIrp, IN PMOXA_DEVICE_EXTENSION PDevExt)
  1004. /*++
  1005. Routine Description:
  1006. This routine will be used to approve irps for processing.
  1007. If an irp is approved, success will be returned. If not,
  1008. the irp will be queued or rejected outright. The IoStatus struct
  1009. and return value will appropriately reflect the actions taken.
  1010. Arguments:
  1011. PIrp - Pointer to the Irp to cancel
  1012. PDevExt - Pointer to the device extension
  1013. Return Value:
  1014. None.
  1015. --*/
  1016. {
  1017. PIO_STACK_LOCATION pIrpStack;
  1018. KIRQL oldIrqlFlags;
  1019. pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
  1020. KeAcquireSpinLock(&PDevExt->FlagsLock, &oldIrqlFlags);
  1021. if ((PDevExt->DevicePNPAccept == SERIAL_PNPACCEPT_OK)
  1022. && ((PDevExt->Flags & SERIAL_FLAGS_BROKENHW) == 0)) {
  1023. KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
  1024. return STATUS_SUCCESS;
  1025. }
  1026. if ((PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_REMOVING)
  1027. || (PDevExt->Flags & SERIAL_FLAGS_BROKENHW)
  1028. || (PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_SURPRISE_REMOVING)) {
  1029. KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
  1030. //
  1031. // Accept all PNP IRP's -- we assume PNP can synchronize itself
  1032. //
  1033. if (pIrpStack->MajorFunction == IRP_MJ_PNP) {
  1034. return STATUS_SUCCESS;
  1035. }
  1036. PIrp->IoStatus.Status = STATUS_DELETE_PENDING;
  1037. return STATUS_DELETE_PENDING;
  1038. }
  1039. if (PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_STOPPING) {
  1040. KIRQL oldIrql;
  1041. KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
  1042. //
  1043. // Accept all PNP IRP's -- we assume PNP can synchronize itself
  1044. //
  1045. if (pIrpStack->MajorFunction == IRP_MJ_PNP) {
  1046. return STATUS_SUCCESS;
  1047. }
  1048. IoAcquireCancelSpinLock(&oldIrql);
  1049. if (PIrp->Cancel) {
  1050. IoReleaseCancelSpinLock(oldIrql);
  1051. PIrp->IoStatus.Status = STATUS_CANCELLED;
  1052. return STATUS_CANCELLED;
  1053. } else {
  1054. //
  1055. // Mark the Irp as pending
  1056. //
  1057. PIrp->IoStatus.Status = STATUS_PENDING;
  1058. IoMarkIrpPending(PIrp);
  1059. //
  1060. // Queue up the IRP
  1061. //
  1062. InsertTailList(&PDevExt->StalledIrpQueue,
  1063. &PIrp->Tail.Overlay.ListEntry);
  1064. IoSetCancelRoutine(PIrp, MoxaFilterCancelQueued);
  1065. IoReleaseCancelSpinLock(oldIrql);
  1066. return STATUS_PENDING;
  1067. }
  1068. }
  1069. KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
  1070. return STATUS_SUCCESS;
  1071. }
  1072. VOID
  1073. MoxaUnstallIrps(IN PMOXA_DEVICE_EXTENSION PDevExt)
  1074. /*++
  1075. Routine Description:
  1076. This routine will be used to restart irps temporarily stalled on
  1077. the stall queue due to a stop or some such nonsense.
  1078. Arguments:
  1079. PDevExt - Pointer to the device extension
  1080. Return Value:
  1081. None.
  1082. --*/
  1083. {
  1084. PLIST_ENTRY pIrpLink;
  1085. PIRP pIrp;
  1086. PIO_STACK_LOCATION pIrpStack;
  1087. PDEVICE_OBJECT pDevObj;
  1088. PDRIVER_OBJECT pDrvObj;
  1089. KIRQL oldIrql;
  1090. MoxaKdPrint(
  1091. MX_DBG_TRACE,
  1092. ("Entering MoxaUnstallIrps\n"));
  1093. IoAcquireCancelSpinLock(&oldIrql);
  1094. pIrpLink = PDevExt->StalledIrpQueue.Flink;
  1095. while (pIrpLink != &PDevExt->StalledIrpQueue) {
  1096. pIrp = CONTAINING_RECORD(pIrpLink, IRP, Tail.Overlay.ListEntry);
  1097. pIrpLink = pIrp->Tail.Overlay.ListEntry.Flink;
  1098. RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
  1099. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  1100. pDevObj = pIrpStack->DeviceObject;
  1101. pDrvObj = pDevObj->DriverObject;
  1102. IoSetCancelRoutine(pIrp, NULL);
  1103. IoReleaseCancelSpinLock(oldIrql);
  1104. MoxaKdPrint(MX_DBG_TRACE,("Unstalling Irp 0x%x with 0x%x\n",
  1105. pIrp, pIrpStack->MajorFunction));
  1106. pDrvObj->MajorFunction[pIrpStack->MajorFunction](pDevObj, pIrp);
  1107. IoAcquireCancelSpinLock(&oldIrql);
  1108. }
  1109. IoReleaseCancelSpinLock(oldIrql);
  1110. MoxaKdPrint(MX_DBG_TRACE,("Leaving MoxaUnstallIrps\n"));
  1111. }
  1112. NTSTATUS
  1113. MoxaIRPPrologue(IN PIRP PIrp, IN PMOXA_DEVICE_EXTENSION PDevExt)
  1114. /*++
  1115. Routine Description:
  1116. This function must be called at any IRP dispatch entry point. It,
  1117. with SerialIRPEpilogue(), keeps track of all pending IRP's for the given
  1118. PDevObj.
  1119. Arguments:
  1120. PDevObj - Pointer to the device object we are tracking pending IRP's for.
  1121. Return Value:
  1122. Tentative status of the Irp.
  1123. --*/
  1124. {
  1125. InterlockedIncrement(&PDevExt->PendingIRPCnt);
  1126. return MoxaFilterIrps(PIrp, PDevExt);
  1127. }
  1128. VOID
  1129. MoxaIRPEpilogue(IN PMOXA_DEVICE_EXTENSION PDevExt)
  1130. /*++
  1131. Routine Description:
  1132. This function must be called at any IRP dispatch entry point. It,
  1133. with MoxaIRPPrologue(), keeps track of all pending IRP's for the given
  1134. PDevObj.
  1135. Arguments:
  1136. PDevObj - Pointer to the device object we are tracking pending IRP's for.
  1137. Return Value:
  1138. None.
  1139. --*/
  1140. {
  1141. LONG pendingCnt;
  1142. pendingCnt = InterlockedDecrement(&PDevExt->PendingIRPCnt);
  1143. //MoxaKdPrint(MX_DBG_TRACE,("MoxaIRPEpilogue = %x\n",PDevExt));
  1144. // ASSERT(pendingCnt >= 0);
  1145. if (pendingCnt == 0) {
  1146. KeSetEvent(&PDevExt->PendingIRPEvent, IO_NO_INCREMENT, FALSE);
  1147. }
  1148. }
  1149. VOID
  1150. MoxaSetDeviceFlags(IN PMOXA_DEVICE_EXTENSION PDevExt, OUT PULONG PFlags,
  1151. IN ULONG Value, IN BOOLEAN Set)
  1152. /*++
  1153. Routine Description:
  1154. Sets flags in a value protected by the flags spinlock. This is used
  1155. to set values that would stop IRP's from being accepted.
  1156. Arguments:
  1157. PDevExt - Device extension attached to PDevObj
  1158. PFlags - Pointer to the flags variable that needs changing
  1159. Value - Value to modify flags variable with
  1160. Set - TRUE if |= , FALSE if &=
  1161. Return Value:
  1162. None.
  1163. --*/
  1164. {
  1165. KIRQL oldIrql;
  1166. KeAcquireSpinLock(&PDevExt->FlagsLock, &oldIrql);
  1167. if (Set) {
  1168. *PFlags |= Value;
  1169. } else {
  1170. *PFlags &= ~Value;
  1171. }
  1172. KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrql);
  1173. }
  1174. NTSTATUS
  1175. MoxaIoCallDriver(PMOXA_DEVICE_EXTENSION PDevExt, PDEVICE_OBJECT PDevObj,
  1176. PIRP PIrp)
  1177. /*++
  1178. Routine Description:
  1179. This function must be called instead of IoCallDriver. It automatically
  1180. updates Irp tracking for PDevObj.
  1181. Arguments:
  1182. PDevExt - Device extension attached to PDevObj
  1183. PDevObj - Pointer to the device object we are tracking pending IRP's for.
  1184. PIrp - Pointer to the Irp we are passing to the next driver.
  1185. Return Value:
  1186. None.
  1187. --*/
  1188. {
  1189. NTSTATUS status;
  1190. status = IoCallDriver(PDevObj, PIrp);
  1191. MoxaIRPEpilogue(PDevExt);
  1192. return status;
  1193. }
  1194. NTSTATUS
  1195. MoxaPoCallDriver(PMOXA_DEVICE_EXTENSION PDevExt, PDEVICE_OBJECT PDevObj,
  1196. PIRP PIrp)
  1197. /*++
  1198. Routine Description:
  1199. This function must be called instead of PoCallDriver. It automatically
  1200. updates Irp tracking for PDevObj.
  1201. Arguments:
  1202. PDevExt - Device extension attached to PDevObj
  1203. PDevObj - Pointer to the device object we are tracking pending IRP's for.
  1204. PIrp - Pointer to the Irp we are passing to the next driver.
  1205. Return Value:
  1206. None.
  1207. --*/
  1208. {
  1209. NTSTATUS status;
  1210. status = PoCallDriver(PDevObj, PIrp);
  1211. MoxaIRPEpilogue(PDevExt);
  1212. return status;
  1213. }
  1214. VOID
  1215. MoxaKillPendingIrps(PDEVICE_OBJECT PDevObj)
  1216. /*++
  1217. Routine Description:
  1218. This routine kills any irps pending for the passed device object.
  1219. Arguments:
  1220. PDevObj - Pointer to the device object whose irps must die.
  1221. Return Value:
  1222. VOID
  1223. --*/
  1224. {
  1225. PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  1226. KIRQL oldIrql;
  1227. MoxaKdPrint (MX_DBG_TRACE,("Enter MoxaKillPendingIrps\n"));
  1228. //
  1229. // First kill all the reads and writes.
  1230. //
  1231. MoxaKillAllReadsOrWrites(PDevObj, &pDevExt->WriteQueue,
  1232. &pDevExt->CurrentWriteIrp);
  1233. MoxaKillAllReadsOrWrites(PDevObj, &pDevExt->ReadQueue,
  1234. &pDevExt->CurrentReadIrp);
  1235. //
  1236. // Next get rid of purges.
  1237. //
  1238. MoxaKillAllReadsOrWrites(PDevObj, &pDevExt->PurgeQueue,
  1239. &pDevExt->CurrentPurgeIrp);
  1240. //
  1241. // Get rid of any mask operations.
  1242. //
  1243. MoxaKillAllReadsOrWrites(PDevObj, &pDevExt->MaskQueue,
  1244. &pDevExt->CurrentMaskIrp);
  1245. //
  1246. // Now get rid a pending wait mask irp.
  1247. //
  1248. IoAcquireCancelSpinLock(&oldIrql);
  1249. if (pDevExt->CurrentWaitIrp) {
  1250. PDRIVER_CANCEL cancelRoutine;
  1251. cancelRoutine = pDevExt->CurrentWaitIrp->CancelRoutine;
  1252. pDevExt->CurrentWaitIrp->Cancel = TRUE;
  1253. if (cancelRoutine) {
  1254. pDevExt->CurrentWaitIrp->CancelIrql = oldIrql;
  1255. pDevExt->CurrentWaitIrp->CancelRoutine = NULL;
  1256. cancelRoutine(PDevObj, pDevExt->CurrentWaitIrp);
  1257. }
  1258. } else {
  1259. IoReleaseCancelSpinLock(oldIrql);
  1260. }
  1261. //
  1262. // Cancel any pending wait-wake irps
  1263. //
  1264. if (pDevExt->PendingWakeIrp != NULL) {
  1265. IoCancelIrp(pDevExt->PendingWakeIrp);
  1266. pDevExt->PendingWakeIrp = NULL;
  1267. }
  1268. //
  1269. // Finally, dump any stalled IRPS
  1270. //
  1271. MoxaKillAllStalled(PDevObj);
  1272. MoxaKdPrint (MX_DBG_TRACE, ("Leave MoxaKillPendingIrps\n"));
  1273. }
  1274. VOID
  1275. MoxaReleaseResources(IN PMOXA_DEVICE_EXTENSION pDevExt)
  1276. /*++
  1277. Routine Description:
  1278. Releases resources (not pool) stored in the device extension.
  1279. Arguments:
  1280. pDevExt - Pointer to the device extension to release resources from.
  1281. Return Value:
  1282. VOID
  1283. --*/
  1284. {
  1285. // PAGED_CODE();
  1286. BOOLEAN anyPortExist = TRUE;
  1287. ULONG port,i;
  1288. PDEVICE_OBJECT pDevObj;
  1289. UNICODE_STRING deviceLinkUnicodeString;
  1290. PMOXA_DEVICE_EXTENSION pDevExt1;
  1291. MoxaKdPrint(MX_DBG_TRACE,("Enter MoxaReleaseResources\n"));
  1292. // KeSynchronizeExecution(pDevExt->Interrupt, MoxaCleanInterruptShareLists, pDevExt);
  1293. MoxaCleanInterruptShareLists(pDevExt);
  1294. //
  1295. // Stop servicing interrupts if we are the last one
  1296. //
  1297. for (i = 0; i < MoxaGlobalData->NumPorts[pDevExt->BoardNo]; i++) {
  1298. port = pDevExt->BoardNo*MAXPORT_PER_CARD + i;
  1299. if ((pDevExt1 = MoxaGlobalData->Extension[port]) != NULL) {
  1300. if (pDevExt1->PortIndex != pDevExt->PortIndex) {
  1301. MoxaKdPrint(MX_DBG_TRACE,("There is still a port in this board %d/%d\n",i,port));
  1302. break;
  1303. }
  1304. }
  1305. }
  1306. if ( i == MoxaGlobalData->NumPorts[pDevExt->BoardNo]) {
  1307. MoxaKdPrint(MX_DBG_TRACE,("It is the last port of this board\n"));
  1308. anyPortExist = FALSE;
  1309. for (i = 0; i < MAX_CARD; i++) {
  1310. if (MoxaGlobalData->CardType[i] && (i != pDevExt->BoardNo))
  1311. break;
  1312. }
  1313. if (i == MAX_CARD) {
  1314. MoxaKdPrint(MX_DBG_TRACE,("No more devices,so delete control device\n"));
  1315. RtlInitUnicodeString (
  1316. &deviceLinkUnicodeString,
  1317. CONTROL_DEVICE_LINK
  1318. );
  1319. IoDeleteSymbolicLink(&deviceLinkUnicodeString);
  1320. pDevObj=MoxaGlobalData->DriverObject->DeviceObject;
  1321. while (pDevObj) {
  1322. MoxaKdPrint(MX_DBG_TRACE,("There is still a devices\n"));
  1323. if (((PMOXA_DEVICE_EXTENSION)(pDevObj->DeviceExtension))->ControlDevice) {
  1324. MoxaKdPrint(MX_DBG_TRACE,("Is Control Device,so delete it\n"));
  1325. IoDeleteDevice(pDevObj);
  1326. break;
  1327. }
  1328. pDevObj=pDevObj->NextDevice;
  1329. }
  1330. }
  1331. }
  1332. pDevExt->Interrupt = NULL;
  1333. //
  1334. // Stop handling timers
  1335. //
  1336. MoxaCancelTimer(&pDevExt->ReadRequestTotalTimer, pDevExt);
  1337. MoxaCancelTimer(&pDevExt->ReadRequestIntervalTimer, pDevExt);
  1338. MoxaCancelTimer(&pDevExt->WriteRequestTotalTimer, pDevExt);
  1339. //
  1340. // Stop servicing DPC's
  1341. //
  1342. MoxaRemoveQueueDpc(&pDevExt->CompleteWriteDpc, pDevExt);
  1343. MoxaRemoveQueueDpc(&pDevExt->CompleteReadDpc, pDevExt);
  1344. MoxaRemoveQueueDpc(&pDevExt->TotalReadTimeoutDpc, pDevExt);
  1345. MoxaRemoveQueueDpc(&pDevExt->IntervalReadTimeoutDpc, pDevExt);
  1346. MoxaRemoveQueueDpc(&pDevExt->TotalWriteTimeoutDpc, pDevExt);
  1347. MoxaRemoveQueueDpc(&pDevExt->CommErrorDpc, pDevExt);
  1348. MoxaRemoveQueueDpc(&pDevExt->CommWaitDpc, pDevExt);
  1349. //
  1350. // Remove us from any lists we may be on
  1351. //
  1352. MoxaGlobalData->Extension[pDevExt->PortNo] = NULL;
  1353. MoxaExtension[MoxaGlobalData->ComNo[pDevExt->BoardNo][pDevExt->PortIndex]] = NULL;
  1354. if (anyPortExist == FALSE ) {
  1355. MoxaKdPrint(MX_DBG_TRACE,("Free the global info. associated with this board\n"));
  1356. MoxaGlobalData->Interrupt[pDevExt->BoardNo] = NULL;
  1357. MoxaGlobalData->CardType[pDevExt->BoardNo] = 0;
  1358. MoxaGlobalData->InterfaceType[pDevExt->BoardNo] = 0;
  1359. MoxaGlobalData->IntVector[pDevExt->BoardNo] = 0;
  1360. MoxaGlobalData->PciIntAckBase[pDevExt->BoardNo] = NULL;
  1361. MoxaGlobalData->CardBase[pDevExt->BoardNo] = 0;
  1362. MoxaGlobalData->IntNdx[pDevExt->BoardNo] = NULL;
  1363. MoxaGlobalData->IntPend[pDevExt->BoardNo] = NULL;
  1364. MoxaGlobalData->IntTable[pDevExt->BoardNo] = NULL;
  1365. MoxaGlobalData->NumPorts[pDevExt->BoardNo] = 0;
  1366. RtlZeroMemory(&MoxaGlobalData->PciIntAckPort[pDevExt->BoardNo],sizeof(PHYSICAL_ADDRESS));
  1367. RtlZeroMemory(&MoxaGlobalData->BankAddr[pDevExt->BoardNo],sizeof(PHYSICAL_ADDRESS));
  1368. }
  1369. }
  1370. VOID
  1371. MoxaDisableInterfacesResources(IN PDEVICE_OBJECT PDevObj,
  1372. BOOLEAN DisableUART)
  1373. {
  1374. PMOXA_DEVICE_EXTENSION pDevExt
  1375. = (PMOXA_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  1376. // PAGED_CODE();
  1377. MoxaKdPrint(MX_DBG_TRACE,("Enter MoxaDisableInterfaces\n"));
  1378. //
  1379. // Only do these many things if the device has started and still
  1380. // has resources allocated
  1381. //
  1382. // if (pDevExt->Flags & SERIAL_FLAGS_STARTED) {
  1383. if (!(pDevExt->Flags & SERIAL_FLAGS_STOPPED)) {
  1384. if (DisableUART) {
  1385. //
  1386. // Mask off interrupts
  1387. //
  1388. // ????? DISABLE_ALL_INTERRUPTS(pDevExt->Controller);
  1389. }
  1390. MoxaReleaseResources(pDevExt);
  1391. }
  1392. //
  1393. // Remove us from WMI consideration
  1394. //
  1395. IoWMIRegistrationControl(PDevObj, WMIREG_ACTION_DEREGISTER);
  1396. // }
  1397. //
  1398. // Undo external names
  1399. //
  1400. MoxaUndoExternalNaming(pDevExt);
  1401. }
  1402. NTSTATUS
  1403. MoxaRemoveDevObj(IN PDEVICE_OBJECT PDevObj)
  1404. /*++
  1405. Routine Description:
  1406. Removes a serial device object from the system.
  1407. Arguments:
  1408. PDevObj - A pointer to the Device Object we want removed.
  1409. Return Value:
  1410. Always TRUE
  1411. --*/
  1412. {
  1413. PMOXA_DEVICE_EXTENSION pDevExt
  1414. = (PMOXA_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  1415. //PAGED_CODE();
  1416. MoxaKdPrint (MX_DBG_TRACE,("Enter MoxaRemoveDevObj\n"));
  1417. if (!(pDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_SURPRISE_REMOVING)) {
  1418. //
  1419. // Disable all external interfaces and release resources
  1420. //
  1421. MoxaDisableInterfacesResources(PDevObj,TRUE);
  1422. }
  1423. IoDetachDevice(pDevExt->LowerDeviceObject);
  1424. //
  1425. // Free memory allocated in the extension
  1426. //
  1427. if (pDevExt->DeviceName.Buffer != NULL) {
  1428. ExFreePool(pDevExt->DeviceName.Buffer);
  1429. }
  1430. if (pDevExt->SymbolicLinkName.Buffer != NULL) {
  1431. ExFreePool(pDevExt->SymbolicLinkName.Buffer);
  1432. }
  1433. if (pDevExt->ObjectDirectory.Buffer) {
  1434. ExFreePool(pDevExt->ObjectDirectory.Buffer);
  1435. }
  1436. //
  1437. // Delete the devobj
  1438. //
  1439. IoDeleteDevice(PDevObj);
  1440. MoxaKdPrint (MX_DBG_TRACE, ("Leave SerialRemoveDevObj\n"));
  1441. return STATUS_SUCCESS;
  1442. }
  1443. NTSTATUS
  1444. MoxaIoSyncIoctlEx(ULONG Ioctl, BOOLEAN Internal, PDEVICE_OBJECT PDevObj,
  1445. PKEVENT PEvent, PIO_STATUS_BLOCK PIoStatusBlock,
  1446. PVOID PInBuffer, ULONG InBufferLen, PVOID POutBuffer, // output buffer - optional
  1447. ULONG OutBufferLen)
  1448. /*++
  1449. Routine Description:
  1450. Performs a synchronous IO control request by waiting on the event object
  1451. passed to it. The IRP is deallocated by the IO system when finished.
  1452. Return value:
  1453. NTSTATUS
  1454. --*/
  1455. {
  1456. PIRP pIrp;
  1457. NTSTATUS status;
  1458. KeClearEvent(PEvent);
  1459. // Allocate an IRP - No need to release
  1460. // When the next-lower driver completes this IRP, the IO Mgr releases it.
  1461. pIrp = IoBuildDeviceIoControlRequest(Ioctl, PDevObj, PInBuffer, InBufferLen,
  1462. POutBuffer, OutBufferLen, Internal,
  1463. PEvent, PIoStatusBlock);
  1464. if (pIrp == NULL) {
  1465. MoxaKdPrint (MX_DBG_TRACE, ("Failed to allocate IRP\n"));
  1466. return STATUS_INSUFFICIENT_RESOURCES;
  1467. }
  1468. status = MoxaIoSyncReq(PDevObj, pIrp, PEvent);
  1469. if (status == STATUS_SUCCESS) {
  1470. status = PIoStatusBlock->Status;
  1471. }
  1472. return status;
  1473. }
  1474. NTSTATUS
  1475. MoxaIoSyncReq(PDEVICE_OBJECT PDevObj, IN PIRP PIrp, PKEVENT PEvent)
  1476. /*++
  1477. Routine Description:
  1478. Performs a synchronous IO request by waiting on the event object
  1479. passed to it. The IRP is deallocated by the IO system when finished.
  1480. Return value:
  1481. NTSTATUS
  1482. --*/
  1483. {
  1484. NTSTATUS status;
  1485. status = IoCallDriver(PDevObj, PIrp);
  1486. if (status == STATUS_PENDING) {
  1487. // wait for it...
  1488. status = KeWaitForSingleObject(PEvent, Executive, KernelMode, FALSE,
  1489. NULL);
  1490. }
  1491. return status;
  1492. }
  1493. BOOLEAN
  1494. MoxaCleanInterruptShareLists(IN PMOXA_DEVICE_EXTENSION pDevExt )
  1495. /*++
  1496. Routine Description:
  1497. Removes a device object from any of the serial linked lists it may
  1498. appear on.
  1499. Arguments:
  1500. Context - Actually a PMOXA_DEVICE_EXTENSION (for the devobj being
  1501. removed).
  1502. Return Value:
  1503. --*/
  1504. {
  1505. PLIST_ENTRY interruptEntry;
  1506. PMOXA_CISR_SW cisrsw;
  1507. PMOXA_DEVICE_EXTENSION pDevExt1;
  1508. PMOXA_GLOBAL_DATA globalData = pDevExt->GlobalData;
  1509. ULONG cardNo,port,i;
  1510. PMOXA_MULTIPORT_DISPATCH dispatch;
  1511. // ASSERT(!IsListEmpty(pDevExt->InterruptShareList));
  1512. if (IsListEmpty(pDevExt->InterruptShareList))
  1513. return (FALSE);
  1514. //
  1515. // Stop servicing interrupts if we are the last one
  1516. //
  1517. for ( i = 0; i < globalData->NumPorts[pDevExt->BoardNo]; i++) {
  1518. port = pDevExt->BoardNo*MAXPORT_PER_CARD + i;
  1519. if ((pDevExt1 = globalData->Extension[port]) != NULL) {
  1520. if (pDevExt1->PortIndex != pDevExt->PortIndex) {
  1521. MoxaKdPrint(MX_DBG_TRACE,("There is still a port in this board %d/%d\n",i,port));
  1522. break;
  1523. }
  1524. }
  1525. }
  1526. if ( i != globalData->NumPorts[pDevExt->BoardNo])
  1527. return (TRUE);
  1528. MoxaKdPrint(MX_DBG_TRACE,("It is the last port of this board\n"));
  1529. MoxaKdPrint(MX_DBG_TRACE,("Interrupt share list = %x\n",pDevExt->InterruptShareList));
  1530. interruptEntry = (pDevExt->InterruptShareList)->Flink;
  1531. do {
  1532. MoxaKdPrint(MX_DBG_TRACE,("find list\n"));
  1533. cisrsw = CONTAINING_RECORD(interruptEntry,
  1534. MOXA_CISR_SW,
  1535. SharerList
  1536. );
  1537. MoxaKdPrint(MX_DBG_TRACE,("cisrsw = %x\n",cisrsw));
  1538. if (!cisrsw)
  1539. return (FALSE);
  1540. dispatch = &cisrsw->Dispatch;
  1541. cardNo = dispatch->BoardNo;
  1542. MoxaKdPrint(MX_DBG_TRACE,("cardNo = %x\n",cardNo));
  1543. if (cardNo == pDevExt->BoardNo) {
  1544. MoxaRemoveLists(interruptEntry);
  1545. MoxaKdPrint(MX_DBG_TRACE,("list removed\n"));
  1546. if (IsListEmpty(pDevExt->InterruptShareList)) {
  1547. MoxaKdPrint(MX_DBG_TRACE,("No more board use this IRQ so Disconnect it\n"));
  1548. IoDisconnectInterrupt(pDevExt->Interrupt);
  1549. MoxaKdPrint(MX_DBG_TRACE,("free share list\n"));
  1550. ExFreePool(pDevExt->InterruptShareList);
  1551. }
  1552. MoxaKdPrint(MX_DBG_TRACE,("free others\n"));
  1553. ExFreePool(cisrsw);
  1554. MoxaKdPrint(MX_DBG_TRACE,("free ok\n"));
  1555. return (TRUE);
  1556. }
  1557. interruptEntry = interruptEntry->Flink;
  1558. MoxaKdPrint(MX_DBG_TRACE,("get next\n"));
  1559. }
  1560. while (interruptEntry != pDevExt->InterruptShareList);
  1561. return (FALSE);
  1562. }
  1563. BOOLEAN
  1564. MoxaRemoveLists(IN PVOID Context)
  1565. /*++
  1566. Routine Description:
  1567. Removes a list entry from the InterruptShareList.
  1568. Arguments:
  1569. Context - Actually a list entry of InterruptShareList .
  1570. Return Value:
  1571. Always TRUE
  1572. --*/
  1573. {
  1574. PLIST_ENTRY pListEntry = (PLIST_ENTRY)Context;
  1575. RemoveEntryList(pListEntry);
  1576. return (TRUE);
  1577. }
  1578. VOID
  1579. MoxaUnlockPages(IN PKDPC PDpc, IN PVOID PDeferredContext,
  1580. IN PVOID PSysContext1, IN PVOID PSysContext2)
  1581. /*++
  1582. Routine Description:
  1583. This function is a DPC routine queue from the ISR if he released the
  1584. last lock on pending DPC's.
  1585. Arguments:
  1586. PDpdc, PSysContext1, PSysContext2 -- not used
  1587. PDeferredContext -- Really the device extension
  1588. Return Value:
  1589. None.
  1590. --*/
  1591. {
  1592. PMOXA_DEVICE_EXTENSION pDevExt
  1593. = (PMOXA_DEVICE_EXTENSION)PDeferredContext;
  1594. UNREFERENCED_PARAMETER(PDpc);
  1595. UNREFERENCED_PARAMETER(PSysContext1);
  1596. UNREFERENCED_PARAMETER(PSysContext2);
  1597. KeSetEvent(&pDevExt->PendingDpcEvent, IO_NO_INCREMENT, FALSE);
  1598. }
  1599. VOID
  1600. MoxaLoop()
  1601. {
  1602. LARGE_INTEGER targetTc, newTc, currTc, newTc1;
  1603. ULONG unit, count;
  1604. LARGE_INTEGER interval; /* 1 ms */
  1605. KeQueryTickCount(&currTc);
  1606. unit = KeQueryTimeIncrement();
  1607. currTc = RtlExtendedIntegerMultiply(currTc, unit);
  1608. interval = RtlConvertUlongToLargeInteger(10000L);
  1609. targetTc = RtlLargeIntegerAdd(currTc, interval);
  1610. MoxaLoopCnt = 0;
  1611. do {
  1612. KeQueryTickCount(&newTc);
  1613. newTc = RtlExtendedIntegerMultiply(newTc, unit);
  1614. MoxaLoopCnt++;
  1615. } while (!RtlLargeIntegerGreaterThanOrEqualTo(newTc, targetTc));
  1616. MoxaLoopCnt += 0x1000;
  1617. }