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.

1791 lines
41 KiB

  1. /*++
  2. Copyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation
  3. Module Name:
  4. utils.c
  5. Abstract:
  6. This module contains code that perform queueing and completion
  7. manipulation on requests. Also module generic functions such
  8. as error logging.
  9. Author:
  10. Anthony V. Ercolano 26-Sep-1991
  11. Environment:
  12. Kernel mode
  13. --*/
  14. #include "precomp.h"
  15. VOID
  16. SerialRundownIrpRefs(
  17. IN PIRP *CurrentOpIrp,
  18. IN PKTIMER IntervalTimer,
  19. IN PKTIMER TotalTimer,
  20. IN PSERIAL_DEVICE_EXTENSION PDevExt
  21. );
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGESER,SerialGetNextIrp)
  24. #pragma alloc_text(PAGESER, SerialGetNextIrpLocked)
  25. #pragma alloc_text(PAGESER,SerialTryToCompleteCurrent)
  26. #pragma alloc_text(PAGESER,SerialStartOrQueue)
  27. #pragma alloc_text(PAGESER,SerialCancelQueued)
  28. #pragma alloc_text(PAGESER,SerialCompleteIfError)
  29. #pragma alloc_text(PAGESER,SerialRundownIrpRefs)
  30. #pragma alloc_text(PAGESRP0, SerialLogError)
  31. #pragma alloc_text(PAGESRP0, SerialMarkHardwareBroken)
  32. #endif
  33. static const PHYSICAL_ADDRESS SerialPhysicalZero = {0};
  34. VOID
  35. SerialKillAllReadsOrWrites(
  36. IN PDEVICE_OBJECT DeviceObject,
  37. IN PLIST_ENTRY QueueToClean,
  38. IN PIRP *CurrentOpIrp
  39. )
  40. /*++
  41. Routine Description:
  42. This function is used to cancel all queued and the current irps
  43. for reads or for writes.
  44. Arguments:
  45. DeviceObject - A pointer to the serial device object.
  46. QueueToClean - A pointer to the queue which we're going to clean out.
  47. CurrentOpIrp - Pointer to a pointer to the current irp.
  48. Return Value:
  49. None.
  50. --*/
  51. {
  52. KIRQL cancelIrql;
  53. PDRIVER_CANCEL cancelRoutine;
  54. //
  55. // We acquire the cancel spin lock. This will prevent the
  56. // irps from moving around.
  57. //
  58. IoAcquireCancelSpinLock(&cancelIrql);
  59. //
  60. // Clean the list from back to front.
  61. //
  62. while (!IsListEmpty(QueueToClean)) {
  63. PIRP currentLastIrp = CONTAINING_RECORD(
  64. QueueToClean->Blink,
  65. IRP,
  66. Tail.Overlay.ListEntry
  67. );
  68. RemoveEntryList(QueueToClean->Blink);
  69. cancelRoutine = currentLastIrp->CancelRoutine;
  70. currentLastIrp->CancelIrql = cancelIrql;
  71. currentLastIrp->CancelRoutine = NULL;
  72. currentLastIrp->Cancel = TRUE;
  73. cancelRoutine(
  74. DeviceObject,
  75. currentLastIrp
  76. );
  77. IoAcquireCancelSpinLock(&cancelIrql);
  78. }
  79. //
  80. // The queue is clean. Now go after the current if
  81. // it's there.
  82. //
  83. if (*CurrentOpIrp) {
  84. cancelRoutine = (*CurrentOpIrp)->CancelRoutine;
  85. (*CurrentOpIrp)->Cancel = TRUE;
  86. //
  87. // If the current irp is not in a cancelable state
  88. // then it *will* try to enter one and the above
  89. // assignment will kill it. If it already is in
  90. // a cancelable state then the following will kill it.
  91. //
  92. if (cancelRoutine) {
  93. (*CurrentOpIrp)->CancelRoutine = NULL;
  94. (*CurrentOpIrp)->CancelIrql = cancelIrql;
  95. //
  96. // This irp is already in a cancelable state. We simply
  97. // mark it as canceled and call the cancel routine for
  98. // it.
  99. //
  100. cancelRoutine(
  101. DeviceObject,
  102. *CurrentOpIrp
  103. );
  104. } else {
  105. IoReleaseCancelSpinLock(cancelIrql);
  106. }
  107. } else {
  108. IoReleaseCancelSpinLock(cancelIrql);
  109. }
  110. }
  111. VOID
  112. SerialGetNextIrp(
  113. IN PIRP *CurrentOpIrp,
  114. IN PLIST_ENTRY QueueToProcess,
  115. OUT PIRP *NextIrp,
  116. IN BOOLEAN CompleteCurrent,
  117. IN PSERIAL_DEVICE_EXTENSION extension
  118. )
  119. /*++
  120. Routine Description:
  121. This function is used to make the head of the particular
  122. queue the current irp. It also completes the what
  123. was the old current irp if desired.
  124. Arguments:
  125. CurrentOpIrp - Pointer to a pointer to the currently active
  126. irp for the particular work list. Note that
  127. this item is not actually part of the list.
  128. QueueToProcess - The list to pull the new item off of.
  129. NextIrp - The next Irp to process. Note that CurrentOpIrp
  130. will be set to this value under protection of the
  131. cancel spin lock. However, if *NextIrp is NULL when
  132. this routine returns, it is not necessaryly true the
  133. what is pointed to by CurrentOpIrp will also be NULL.
  134. The reason for this is that if the queue is empty
  135. when we hold the cancel spin lock, a new irp may come
  136. in immediately after we release the lock.
  137. CompleteCurrent - If TRUE then this routine will complete the
  138. irp pointed to by the pointer argument
  139. CurrentOpIrp.
  140. Return Value:
  141. None.
  142. --*/
  143. {
  144. KIRQL oldIrql;
  145. SERIAL_LOCKED_PAGED_CODE();
  146. IoAcquireCancelSpinLock(&oldIrql);
  147. SerialGetNextIrpLocked(CurrentOpIrp, QueueToProcess, NextIrp,
  148. CompleteCurrent, extension, oldIrql);
  149. }
  150. VOID
  151. SerialGetNextIrpLocked(
  152. IN PIRP *CurrentOpIrp,
  153. IN PLIST_ENTRY QueueToProcess,
  154. OUT PIRP *NextIrp,
  155. IN BOOLEAN CompleteCurrent,
  156. IN PSERIAL_DEVICE_EXTENSION extension,
  157. IN KIRQL OldIrql
  158. )
  159. /*++
  160. Routine Description:
  161. This function is used to make the head of the particular
  162. queue the current irp. It also completes the what
  163. was the old current irp if desired. The difference between
  164. this and SerialGetNextIrp() is that for this we assume the caller
  165. holds the cancel spinlock and we should release it when we're done.
  166. Arguments:
  167. CurrentOpIrp - Pointer to a pointer to the currently active
  168. irp for the particular work list. Note that
  169. this item is not actually part of the list.
  170. QueueToProcess - The list to pull the new item off of.
  171. NextIrp - The next Irp to process. Note that CurrentOpIrp
  172. will be set to this value under protection of the
  173. cancel spin lock. However, if *NextIrp is NULL when
  174. this routine returns, it is not necessaryly true the
  175. what is pointed to by CurrentOpIrp will also be NULL.
  176. The reason for this is that if the queue is empty
  177. when we hold the cancel spin lock, a new irp may come
  178. in immediately after we release the lock.
  179. CompleteCurrent - If TRUE then this routine will complete the
  180. irp pointed to by the pointer argument
  181. CurrentOpIrp.
  182. OldIrql - IRQL which the cancel spinlock was acquired at and what we
  183. should restore it to.
  184. Return Value:
  185. None.
  186. --*/
  187. {
  188. PIRP oldIrp;
  189. SERIAL_LOCKED_PAGED_CODE();
  190. oldIrp = *CurrentOpIrp;
  191. #if DBG
  192. if (oldIrp) {
  193. if (CompleteCurrent) {
  194. ASSERT(!oldIrp->CancelRoutine);
  195. }
  196. }
  197. #endif
  198. //
  199. // Check to see if there is a new irp to start up.
  200. //
  201. if (!IsListEmpty(QueueToProcess)) {
  202. PLIST_ENTRY headOfList;
  203. headOfList = RemoveHeadList(QueueToProcess);
  204. *CurrentOpIrp = CONTAINING_RECORD(
  205. headOfList,
  206. IRP,
  207. Tail.Overlay.ListEntry
  208. );
  209. IoSetCancelRoutine(
  210. *CurrentOpIrp,
  211. NULL
  212. );
  213. } else {
  214. *CurrentOpIrp = NULL;
  215. }
  216. *NextIrp = *CurrentOpIrp;
  217. IoReleaseCancelSpinLock(OldIrql);
  218. if (CompleteCurrent) {
  219. if (oldIrp) {
  220. SerialDump(
  221. SERIRPPATH,
  222. ("SERIAL: Complete Irp: %x\n",oldIrp)
  223. );
  224. SerialCompleteRequest(extension, oldIrp, IO_SERIAL_INCREMENT);
  225. }
  226. }
  227. }
  228. VOID
  229. SerialTryToCompleteCurrent(
  230. IN PSERIAL_DEVICE_EXTENSION Extension,
  231. IN PKSYNCHRONIZE_ROUTINE SynchRoutine OPTIONAL,
  232. IN KIRQL IrqlForRelease,
  233. IN NTSTATUS StatusToUse,
  234. IN PIRP *CurrentOpIrp,
  235. IN PLIST_ENTRY QueueToProcess OPTIONAL,
  236. IN PKTIMER IntervalTimer OPTIONAL,
  237. IN PKTIMER TotalTimer OPTIONAL,
  238. IN PSERIAL_START_ROUTINE Starter OPTIONAL,
  239. IN PSERIAL_GET_NEXT_ROUTINE GetNextIrp OPTIONAL,
  240. IN LONG RefType
  241. )
  242. /*++
  243. Routine Description:
  244. This routine attempts to kill all of the reasons there are
  245. references on the current read/write. If everything can be killed
  246. it will complete this read/write and try to start another.
  247. NOTE: This routine assumes that it is called with the cancel
  248. spinlock held.
  249. Arguments:
  250. Extension - Simply a pointer to the device extension.
  251. SynchRoutine - A routine that will synchronize with the isr
  252. and attempt to remove the knowledge of the
  253. current irp from the isr. NOTE: This pointer
  254. can be null.
  255. IrqlForRelease - This routine is called with the cancel spinlock held.
  256. This is the irql that was current when the cancel
  257. spinlock was acquired.
  258. StatusToUse - The irp's status field will be set to this value, if
  259. this routine can complete the irp.
  260. Return Value:
  261. None.
  262. --*/
  263. {
  264. SERIAL_LOCKED_PAGED_CODE();
  265. //
  266. // We can decrement the reference to "remove" the fact
  267. // that the caller no longer will be accessing this irp.
  268. //
  269. SERIAL_CLEAR_REFERENCE(
  270. *CurrentOpIrp,
  271. RefType
  272. );
  273. if (SynchRoutine) {
  274. KeSynchronizeExecution(
  275. Extension->Interrupt,
  276. SynchRoutine,
  277. Extension
  278. );
  279. }
  280. //
  281. // Try to run down all other references to this irp.
  282. //
  283. SerialRundownIrpRefs(
  284. CurrentOpIrp,
  285. IntervalTimer,
  286. TotalTimer,
  287. Extension
  288. );
  289. //
  290. // See if the ref count is zero after trying to kill everybody else.
  291. //
  292. if (!SERIAL_REFERENCE_COUNT(*CurrentOpIrp)) {
  293. PIRP newIrp;
  294. //
  295. // The ref count was zero so we should complete this
  296. // request.
  297. //
  298. // The following call will also cause the current irp to be
  299. // completed.
  300. //
  301. (*CurrentOpIrp)->IoStatus.Status = StatusToUse;
  302. if (StatusToUse == STATUS_CANCELLED) {
  303. (*CurrentOpIrp)->IoStatus.Information = 0;
  304. }
  305. if (GetNextIrp) {
  306. IoReleaseCancelSpinLock(IrqlForRelease);
  307. GetNextIrp(
  308. CurrentOpIrp,
  309. QueueToProcess,
  310. &newIrp,
  311. TRUE,
  312. Extension
  313. );
  314. if (newIrp) {
  315. Starter(Extension);
  316. }
  317. } else {
  318. PIRP oldIrp = *CurrentOpIrp;
  319. //
  320. // There was no get next routine. We will simply complete
  321. // the irp. We should make sure that we null out the
  322. // pointer to the pointer to this irp.
  323. //
  324. *CurrentOpIrp = NULL;
  325. IoReleaseCancelSpinLock(IrqlForRelease);
  326. SerialDump(
  327. SERIRPPATH,
  328. ("SERIAL: Complete Irp: %x\n",oldIrp)
  329. );
  330. SerialCompleteRequest(Extension, oldIrp, IO_SERIAL_INCREMENT);
  331. }
  332. } else {
  333. IoReleaseCancelSpinLock(IrqlForRelease);
  334. }
  335. }
  336. VOID
  337. SerialRundownIrpRefs(IN PIRP *CurrentOpIrp, IN PKTIMER IntervalTimer OPTIONAL,
  338. IN PKTIMER TotalTimer OPTIONAL,
  339. IN PSERIAL_DEVICE_EXTENSION PDevExt)
  340. /*++
  341. Routine Description:
  342. This routine runs through the various items that *could*
  343. have a reference to the current read/write. It try's to kill
  344. the reason. If it does succeed in killing the reason it
  345. will decrement the reference count on the irp.
  346. NOTE: This routine assumes that it is called with the cancel
  347. spin lock held.
  348. Arguments:
  349. CurrentOpIrp - Pointer to a pointer to current irp for the
  350. particular operation.
  351. IntervalTimer - Pointer to the interval timer for the operation.
  352. NOTE: This could be null.
  353. TotalTimer - Pointer to the total timer for the operation.
  354. NOTE: This could be null.
  355. PDevExt - Pointer to device extension
  356. Return Value:
  357. None.
  358. --*/
  359. {
  360. SERIAL_LOCKED_PAGED_CODE();
  361. //
  362. // This routine is called with the cancel spin lock held
  363. // so we know only one thread of execution can be in here
  364. // at one time.
  365. //
  366. //
  367. // First we see if there is still a cancel routine. If
  368. // so then we can decrement the count by one.
  369. //
  370. if ((*CurrentOpIrp)->CancelRoutine) {
  371. SERIAL_CLEAR_REFERENCE(
  372. *CurrentOpIrp,
  373. SERIAL_REF_CANCEL
  374. );
  375. IoSetCancelRoutine(
  376. *CurrentOpIrp,
  377. NULL
  378. );
  379. }
  380. if (IntervalTimer) {
  381. //
  382. // Try to cancel the operations interval timer. If the operation
  383. // returns true then the timer did have a reference to the
  384. // irp. Since we've canceled this timer that reference is
  385. // no longer valid and we can decrement the reference count.
  386. //
  387. // If the cancel returns false then this means either of two things:
  388. //
  389. // a) The timer has already fired.
  390. //
  391. // b) There never was an interval timer.
  392. //
  393. // In the case of "b" there is no need to decrement the reference
  394. // count since the "timer" never had a reference to it.
  395. //
  396. // In the case of "a", then the timer itself will be coming
  397. // along and decrement it's reference. Note that the caller
  398. // of this routine might actually be the this timer, but it
  399. // has already decremented the reference.
  400. //
  401. if (SerialCancelTimer(IntervalTimer, PDevExt)) {
  402. SERIAL_CLEAR_REFERENCE(
  403. *CurrentOpIrp,
  404. SERIAL_REF_INT_TIMER
  405. );
  406. }
  407. }
  408. if (TotalTimer) {
  409. //
  410. // Try to cancel the operations total timer. If the operation
  411. // returns true then the timer did have a reference to the
  412. // irp. Since we've canceled this timer that reference is
  413. // no longer valid and we can decrement the reference count.
  414. //
  415. // If the cancel returns false then this means either of two things:
  416. //
  417. // a) The timer has already fired.
  418. //
  419. // b) There never was an total timer.
  420. //
  421. // In the case of "b" there is no need to decrement the reference
  422. // count since the "timer" never had a reference to it.
  423. //
  424. // In the case of "a", then the timer itself will be coming
  425. // along and decrement it's reference. Note that the caller
  426. // of this routine might actually be the this timer, but it
  427. // has already decremented the reference.
  428. //
  429. if (SerialCancelTimer(TotalTimer, PDevExt)) {
  430. SERIAL_CLEAR_REFERENCE(
  431. *CurrentOpIrp,
  432. SERIAL_REF_TOTAL_TIMER
  433. );
  434. }
  435. }
  436. }
  437. NTSTATUS
  438. SerialStartOrQueue(
  439. IN PSERIAL_DEVICE_EXTENSION Extension,
  440. IN PIRP Irp,
  441. IN PLIST_ENTRY QueueToExamine,
  442. IN PIRP *CurrentOpIrp,
  443. IN PSERIAL_START_ROUTINE Starter
  444. )
  445. /*++
  446. Routine Description:
  447. This routine is used to either start or queue any requst
  448. that can be queued in the driver.
  449. Arguments:
  450. Extension - Points to the serial device extension.
  451. Irp - The irp to either queue or start. In either
  452. case the irp will be marked pending.
  453. QueueToExamine - The queue the irp will be place on if there
  454. is already an operation in progress.
  455. CurrentOpIrp - Pointer to a pointer to the irp the is current
  456. for the queue. The pointer pointed to will be
  457. set with to Irp if what CurrentOpIrp points to
  458. is NULL.
  459. Starter - The routine to call if the queue is empty.
  460. Return Value:
  461. This routine will return STATUS_PENDING if the queue is
  462. not empty. Otherwise, it will return the status returned
  463. from the starter routine (or cancel, if the cancel bit is
  464. on in the irp).
  465. --*/
  466. {
  467. KIRQL oldIrql;
  468. SERIAL_LOCKED_PAGED_CODE();
  469. IoAcquireCancelSpinLock(&oldIrql);
  470. //
  471. // If this is a write irp then take the amount of characters
  472. // to write and add it to the count of characters to write.
  473. //
  474. if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction
  475. == IRP_MJ_WRITE) {
  476. Extension->TotalCharsQueued +=
  477. IoGetCurrentIrpStackLocation(Irp)
  478. ->Parameters.Write.Length;
  479. } else if ((IoGetCurrentIrpStackLocation(Irp)->MajorFunction
  480. == IRP_MJ_DEVICE_CONTROL) &&
  481. ((IoGetCurrentIrpStackLocation(Irp)
  482. ->Parameters.DeviceIoControl.IoControlCode ==
  483. IOCTL_SERIAL_IMMEDIATE_CHAR) ||
  484. (IoGetCurrentIrpStackLocation(Irp)
  485. ->Parameters.DeviceIoControl.IoControlCode ==
  486. IOCTL_SERIAL_XOFF_COUNTER))) {
  487. Extension->TotalCharsQueued++;
  488. }
  489. if ((IsListEmpty(QueueToExamine)) &&
  490. !(*CurrentOpIrp)) {
  491. //
  492. // There were no current operation. Mark this one as
  493. // current and start it up.
  494. //
  495. *CurrentOpIrp = Irp;
  496. IoReleaseCancelSpinLock(oldIrql);
  497. return Starter(Extension);
  498. } else {
  499. //
  500. // We don't know how long the irp will be in the
  501. // queue. So we need to handle cancel.
  502. //
  503. if (Irp->Cancel) {
  504. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  505. IoReleaseCancelSpinLock(oldIrql);
  506. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  507. IOCTL_SERIAL_SET_QUEUE_SIZE) {
  508. //
  509. // We shoved the pointer to the memory into the
  510. // the type 3 buffer pointer which we KNOW we
  511. // never use.
  512. //
  513. ASSERT(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  514. ExFreePool(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  515. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  516. }
  517. Irp->IoStatus.Status = STATUS_CANCELLED;
  518. SerialDump(
  519. SERIRPPATH,
  520. ("SERIAL: Complete Irp: %x\n",Irp)
  521. );
  522. SerialCompleteRequest(Extension, Irp, 0);
  523. return STATUS_CANCELLED;
  524. } else {
  525. Irp->IoStatus.Status = STATUS_PENDING;
  526. IoMarkIrpPending(Irp);
  527. InsertTailList(
  528. QueueToExamine,
  529. &Irp->Tail.Overlay.ListEntry
  530. );
  531. IoSetCancelRoutine(
  532. Irp,
  533. SerialCancelQueued
  534. );
  535. IoReleaseCancelSpinLock(oldIrql);
  536. return STATUS_PENDING;
  537. }
  538. }
  539. }
  540. VOID
  541. SerialCancelQueued(
  542. PDEVICE_OBJECT DeviceObject,
  543. PIRP Irp
  544. )
  545. /*++
  546. Routine Description:
  547. This routine is used to cancel Irps that currently reside on
  548. a queue.
  549. Arguments:
  550. DeviceObject - Pointer to the device object for this device
  551. Irp - Pointer to the IRP to be canceled.
  552. Return Value:
  553. None.
  554. --*/
  555. {
  556. PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  557. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  558. SERIAL_LOCKED_PAGED_CODE();
  559. Irp->IoStatus.Status = STATUS_CANCELLED;
  560. Irp->IoStatus.Information = 0;
  561. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  562. //
  563. // If this is a write irp then take the amount of characters
  564. // to write and subtract it from the count of characters to write.
  565. //
  566. if (irpSp->MajorFunction == IRP_MJ_WRITE) {
  567. extension->TotalCharsQueued -= irpSp->Parameters.Write.Length;
  568. } else if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
  569. //
  570. // If it's an immediate then we need to decrement the
  571. // count of chars queued. If it's a resize then we
  572. // need to deallocate the pool that we're passing on
  573. // to the "resizing" routine.
  574. //
  575. if ((irpSp->Parameters.DeviceIoControl.IoControlCode ==
  576. IOCTL_SERIAL_IMMEDIATE_CHAR) ||
  577. (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  578. IOCTL_SERIAL_XOFF_COUNTER)) {
  579. extension->TotalCharsQueued--;
  580. } else if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  581. IOCTL_SERIAL_SET_QUEUE_SIZE) {
  582. //
  583. // We shoved the pointer to the memory into the
  584. // the type 3 buffer pointer which we KNOW we
  585. // never use.
  586. //
  587. ASSERT(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  588. ExFreePool(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  589. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  590. }
  591. }
  592. IoReleaseCancelSpinLock(Irp->CancelIrql);
  593. SerialDump(
  594. SERIRPPATH,
  595. ("SERIAL: Complete Irp: %x\n",Irp)
  596. );
  597. SerialCompleteRequest(extension, Irp, IO_SERIAL_INCREMENT);
  598. }
  599. NTSTATUS
  600. SerialCompleteIfError(
  601. PDEVICE_OBJECT DeviceObject,
  602. PIRP Irp
  603. )
  604. /*++
  605. Routine Description:
  606. If the current irp is not an IOCTL_SERIAL_GET_COMMSTATUS request and
  607. there is an error and the application requested abort on errors,
  608. then cancel the irp.
  609. Arguments:
  610. DeviceObject - Pointer to the device object for this device
  611. Irp - Pointer to the IRP to test.
  612. Return Value:
  613. STATUS_SUCCESS or STATUS_CANCELLED.
  614. --*/
  615. {
  616. PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  617. NTSTATUS status = STATUS_SUCCESS;
  618. SERIAL_LOCKED_PAGED_CODE();
  619. if ((extension->HandFlow.ControlHandShake &
  620. SERIAL_ERROR_ABORT) && extension->ErrorWord) {
  621. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  622. //
  623. // There is a current error in the driver. No requests should
  624. // come through except for the GET_COMMSTATUS.
  625. //
  626. if ((irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL) ||
  627. (irpSp->Parameters.DeviceIoControl.IoControlCode !=
  628. IOCTL_SERIAL_GET_COMMSTATUS)) {
  629. status = STATUS_CANCELLED;
  630. Irp->IoStatus.Status = STATUS_CANCELLED;
  631. Irp->IoStatus.Information = 0;
  632. SerialDump(
  633. SERIRPPATH,
  634. ("SERIAL: Complete Irp: %x\n",Irp)
  635. );
  636. SerialCompleteRequest(extension, Irp, 0);
  637. }
  638. }
  639. return status;
  640. }
  641. VOID
  642. SerialFilterCancelQueued(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  643. /*++
  644. Routine Description:
  645. This routine will be used cancel irps on the stalled queue.
  646. Arguments:
  647. PDevObj - Pointer to the device object.
  648. PIrp - Pointer to the Irp to cancel
  649. Return Value:
  650. None.
  651. --*/
  652. {
  653. PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  654. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  655. PIrp->IoStatus.Status = STATUS_CANCELLED;
  656. PIrp->IoStatus.Information = 0;
  657. RemoveEntryList(&PIrp->Tail.Overlay.ListEntry);
  658. IoReleaseCancelSpinLock(PIrp->CancelIrql);
  659. }
  660. VOID
  661. SerialKillAllStalled(IN PDEVICE_OBJECT PDevObj)
  662. {
  663. KIRQL cancelIrql;
  664. PDRIVER_CANCEL cancelRoutine;
  665. PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  666. IoAcquireCancelSpinLock(&cancelIrql);
  667. while (!IsListEmpty(&pDevExt->StalledIrpQueue)) {
  668. PIRP currentLastIrp = CONTAINING_RECORD(pDevExt->StalledIrpQueue.Blink,
  669. IRP, Tail.Overlay.ListEntry);
  670. RemoveEntryList(pDevExt->StalledIrpQueue.Blink);
  671. cancelRoutine = currentLastIrp->CancelRoutine;
  672. currentLastIrp->CancelIrql = cancelIrql;
  673. currentLastIrp->CancelRoutine = NULL;
  674. currentLastIrp->Cancel = TRUE;
  675. cancelRoutine(PDevObj, currentLastIrp);
  676. IoAcquireCancelSpinLock(&cancelIrql);
  677. }
  678. IoReleaseCancelSpinLock(cancelIrql);
  679. }
  680. NTSTATUS
  681. SerialFilterIrps(IN PIRP PIrp, IN PSERIAL_DEVICE_EXTENSION PDevExt)
  682. /*++
  683. Routine Description:
  684. This routine will be used to approve irps for processing.
  685. If an irp is approved, success will be returned. If not,
  686. the irp will be queued or rejected outright. The IoStatus struct
  687. and return value will appropriately reflect the actions taken.
  688. Arguments:
  689. PIrp - Pointer to the Irp to cancel
  690. PDevExt - Pointer to the device extension
  691. Return Value:
  692. None.
  693. --*/
  694. {
  695. PIO_STACK_LOCATION pIrpStack;
  696. KIRQL oldIrqlFlags;
  697. pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
  698. KeAcquireSpinLock(&PDevExt->FlagsLock, &oldIrqlFlags);
  699. if ((PDevExt->DevicePNPAccept == SERIAL_PNPACCEPT_OK)
  700. && ((PDevExt->Flags & SERIAL_FLAGS_BROKENHW) == 0)) {
  701. KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
  702. return STATUS_SUCCESS;
  703. }
  704. if ((PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_REMOVING)
  705. || (PDevExt->Flags & SERIAL_FLAGS_BROKENHW)
  706. || (PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_SURPRISE_REMOVING)) {
  707. KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
  708. //
  709. // Accept all PNP IRP's -- we assume PNP can synchronize itself
  710. //
  711. if (pIrpStack->MajorFunction == IRP_MJ_PNP) {
  712. return STATUS_SUCCESS;
  713. }
  714. PIrp->IoStatus.Status = STATUS_DELETE_PENDING;
  715. return STATUS_DELETE_PENDING;
  716. }
  717. if (PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_STOPPING) {
  718. KIRQL oldIrql;
  719. KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
  720. //
  721. // Accept all PNP IRP's -- we assume PNP can synchronize itself
  722. //
  723. if (pIrpStack->MajorFunction == IRP_MJ_PNP) {
  724. return STATUS_SUCCESS;
  725. }
  726. IoAcquireCancelSpinLock(&oldIrql);
  727. if (PIrp->Cancel) {
  728. IoReleaseCancelSpinLock(oldIrql);
  729. PIrp->IoStatus.Status = STATUS_CANCELLED;
  730. return STATUS_CANCELLED;
  731. } else {
  732. //
  733. // Mark the Irp as pending
  734. //
  735. PIrp->IoStatus.Status = STATUS_PENDING;
  736. IoMarkIrpPending(PIrp);
  737. //
  738. // Queue up the IRP
  739. //
  740. InsertTailList(&PDevExt->StalledIrpQueue,
  741. &PIrp->Tail.Overlay.ListEntry);
  742. IoSetCancelRoutine(PIrp, SerialFilterCancelQueued);
  743. IoReleaseCancelSpinLock(oldIrql);
  744. return STATUS_PENDING;
  745. }
  746. }
  747. KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
  748. return STATUS_SUCCESS;
  749. }
  750. VOID
  751. SerialUnstallIrps(IN PSERIAL_DEVICE_EXTENSION PDevExt)
  752. /*++
  753. Routine Description:
  754. This routine will be used to restart irps temporarily stalled on
  755. the stall queue due to a stop or some such nonsense.
  756. Arguments:
  757. PDevExt - Pointer to the device extension
  758. Return Value:
  759. None.
  760. --*/
  761. {
  762. PLIST_ENTRY pIrpLink;
  763. PIRP pIrp;
  764. PIO_STACK_LOCATION pIrpStack;
  765. PDEVICE_OBJECT pDevObj;
  766. PDRIVER_OBJECT pDrvObj;
  767. KIRQL oldIrql;
  768. SerialDump(SERTRACECALLS, ("SERIAL: Entering SerialUnstallIrps\n"));
  769. IoAcquireCancelSpinLock(&oldIrql);
  770. pIrpLink = PDevExt->StalledIrpQueue.Flink;
  771. while (pIrpLink != &PDevExt->StalledIrpQueue) {
  772. pIrp = CONTAINING_RECORD(pIrpLink, IRP, Tail.Overlay.ListEntry);
  773. RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
  774. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  775. pDevObj = pIrpStack->DeviceObject;
  776. pDrvObj = pDevObj->DriverObject;
  777. IoSetCancelRoutine(pIrp, NULL);
  778. IoReleaseCancelSpinLock(oldIrql);
  779. SerialDump(SERPNPPOWER, ("SERIAL: Unstalling Irp 0x%x with 0x%x\n",
  780. pIrp, pIrpStack->MajorFunction));
  781. pDrvObj->MajorFunction[pIrpStack->MajorFunction](pDevObj, pIrp);
  782. IoAcquireCancelSpinLock(&oldIrql);
  783. pIrpLink = PDevExt->StalledIrpQueue.Flink;
  784. }
  785. IoReleaseCancelSpinLock(oldIrql);
  786. SerialDump(SERTRACECALLS, ("SERIAL: Leaving SerialUnstallIrps\n"));
  787. }
  788. NTSTATUS
  789. SerialIRPPrologue(IN PIRP PIrp, IN PSERIAL_DEVICE_EXTENSION PDevExt)
  790. /*++
  791. Routine Description:
  792. This function must be called at any IRP dispatch entry point. It,
  793. with SerialIRPEpilogue(), keeps track of all pending IRP's for the given
  794. PDevObj.
  795. Arguments:
  796. PDevObj - Pointer to the device object we are tracking pending IRP's for.
  797. Return Value:
  798. Tentative status of the Irp.
  799. --*/
  800. {
  801. InterlockedIncrement(&PDevExt->PendingIRPCnt);
  802. return SerialFilterIrps(PIrp, PDevExt);
  803. }
  804. VOID
  805. SerialIRPEpilogue(IN PSERIAL_DEVICE_EXTENSION PDevExt)
  806. /*++
  807. Routine Description:
  808. This function must be called at any IRP dispatch entry point. It,
  809. with SerialIRPPrologue(), keeps track of all pending IRP's for the given
  810. PDevObj.
  811. Arguments:
  812. PDevObj - Pointer to the device object we are tracking pending IRP's for.
  813. Return Value:
  814. None.
  815. --*/
  816. {
  817. LONG pendingCnt;
  818. pendingCnt = InterlockedDecrement(&PDevExt->PendingIRPCnt);
  819. ASSERT(pendingCnt >= 0);
  820. if (pendingCnt == 0) {
  821. KeSetEvent(&PDevExt->PendingIRPEvent, IO_NO_INCREMENT, FALSE);
  822. }
  823. }
  824. BOOLEAN
  825. SerialInsertQueueDpc(IN PRKDPC PDpc, IN PVOID Sarg1, IN PVOID Sarg2,
  826. IN PSERIAL_DEVICE_EXTENSION PDevExt)
  827. /*++
  828. Routine Description:
  829. This function must be called to queue DPC's for the serial driver.
  830. Arguments:
  831. PDpc thru Sarg2 - Standard args to KeInsertQueueDpc()
  832. PDevExt - Pointer to the device extension for the device that needs to
  833. queue a DPC
  834. Return Value:
  835. Kicks up return value from KeInsertQueueDpc()
  836. --*/
  837. {
  838. BOOLEAN queued;
  839. InterlockedIncrement(&PDevExt->DpcCount);
  840. queued = KeInsertQueueDpc(PDpc, Sarg1, Sarg2);
  841. if (!queued) {
  842. ULONG pendingCnt;
  843. pendingCnt = InterlockedDecrement(&PDevExt->DpcCount);
  844. if (pendingCnt == 0) {
  845. KeSetEvent(&PDevExt->PendingIRPEvent, IO_NO_INCREMENT, FALSE);
  846. }
  847. }
  848. #if 0 // DBG
  849. if (queued) {
  850. int i;
  851. for (i = 0; i < MAX_DPC_QUEUE; i++) {
  852. if (PDevExt->DpcQueued[i].Dpc == PDpc) {
  853. PDevExt->DpcQueued[i].QueuedCount++;
  854. break;
  855. }
  856. }
  857. ASSERT(i < MAX_DPC_QUEUE);
  858. }
  859. #endif
  860. return queued;
  861. }
  862. BOOLEAN
  863. SerialSetTimer(IN PKTIMER Timer, IN LARGE_INTEGER DueTime,
  864. IN PKDPC Dpc OPTIONAL, IN PSERIAL_DEVICE_EXTENSION PDevExt)
  865. /*++
  866. Routine Description:
  867. This function must be called to set timers for the serial driver.
  868. Arguments:
  869. Timer - pointer to timer dispatcher object
  870. DueTime - time at which the timer should expire
  871. Dpc - option Dpc
  872. PDevExt - Pointer to the device extension for the device that needs to
  873. set a timer
  874. Return Value:
  875. Kicks up return value from KeSetTimer()
  876. --*/
  877. {
  878. BOOLEAN set;
  879. InterlockedIncrement(&PDevExt->DpcCount);
  880. set = KeSetTimer(Timer, DueTime, Dpc);
  881. if (set) {
  882. InterlockedDecrement(&PDevExt->DpcCount);
  883. }
  884. #if 0 // DBG
  885. if (set) {
  886. int i;
  887. for (i = 0; i < MAX_DPC_QUEUE; i++) {
  888. if (PDevExt->DpcQueued[i].Dpc == Dpc) {
  889. PDevExt->DpcQueued[i].QueuedCount++;
  890. break;
  891. }
  892. }
  893. ASSERT(i < MAX_DPC_QUEUE);
  894. }
  895. #endif
  896. return set;
  897. }
  898. BOOLEAN
  899. SerialCancelTimer(IN PKTIMER Timer, IN PSERIAL_DEVICE_EXTENSION PDevExt)
  900. /*++
  901. Routine Description:
  902. This function must be called to cancel timers for the serial driver.
  903. Arguments:
  904. Timer - pointer to timer dispatcher object
  905. PDevExt - Pointer to the device extension for the device that needs to
  906. set a timer
  907. Return Value:
  908. True if timer was cancelled
  909. --*/
  910. {
  911. BOOLEAN cancelled;
  912. cancelled = KeCancelTimer(Timer);
  913. if (cancelled) {
  914. SerialDpcEpilogue(PDevExt, Timer->Dpc);
  915. }
  916. return cancelled;
  917. }
  918. VOID
  919. SerialDpcEpilogue(IN PSERIAL_DEVICE_EXTENSION PDevExt, PKDPC PDpc)
  920. /*++
  921. Routine Description:
  922. This function must be called at the end of every dpc function.
  923. Arguments:
  924. PDevObj - Pointer to the device object we are tracking dpc's for.
  925. Return Value:
  926. None.
  927. --*/
  928. {
  929. LONG pendingCnt;
  930. #if 1 // !DBG
  931. UNREFERENCED_PARAMETER(PDpc);
  932. #endif
  933. pendingCnt = InterlockedDecrement(&PDevExt->DpcCount);
  934. ASSERT(pendingCnt >= 0);
  935. #if 0 //DBG
  936. {
  937. int i;
  938. for (i = 0; i < MAX_DPC_QUEUE; i++) {
  939. if (PDevExt->DpcQueued[i].Dpc == PDpc) {
  940. PDevExt->DpcQueued[i].FlushCount++;
  941. ASSERT(PDevExt->DpcQueued[i].QueuedCount >=
  942. PDevExt->DpcQueued[i].FlushCount);
  943. break;
  944. }
  945. }
  946. ASSERT(i < MAX_DPC_QUEUE);
  947. }
  948. #endif
  949. if (pendingCnt == 0) {
  950. KeSetEvent(&PDevExt->PendingDpcEvent, IO_NO_INCREMENT, FALSE);
  951. }
  952. }
  953. VOID
  954. SerialUnlockPages(IN PKDPC PDpc, IN PVOID PDeferredContext,
  955. IN PVOID PSysContext1, IN PVOID PSysContext2)
  956. /*++
  957. Routine Description:
  958. This function is a DPC routine queue from the ISR if he released the
  959. last lock on pending DPC's.
  960. Arguments:
  961. PDpdc, PSysContext1, PSysContext2 -- not used
  962. PDeferredContext -- Really the device extension
  963. Return Value:
  964. None.
  965. --*/
  966. {
  967. PSERIAL_DEVICE_EXTENSION pDevExt
  968. = (PSERIAL_DEVICE_EXTENSION)PDeferredContext;
  969. UNREFERENCED_PARAMETER(PDpc);
  970. UNREFERENCED_PARAMETER(PSysContext1);
  971. UNREFERENCED_PARAMETER(PSysContext2);
  972. KeSetEvent(&pDevExt->PendingDpcEvent, IO_NO_INCREMENT, FALSE);
  973. }
  974. NTSTATUS
  975. SerialIoCallDriver(PSERIAL_DEVICE_EXTENSION PDevExt, PDEVICE_OBJECT PDevObj,
  976. PIRP PIrp)
  977. /*++
  978. Routine Description:
  979. This function must be called instead of IoCallDriver. It automatically
  980. updates Irp tracking for PDevObj.
  981. Arguments:
  982. PDevExt - Device extension attached to PDevObj
  983. PDevObj - Pointer to the device object we are tracking pending IRP's for.
  984. PIrp - Pointer to the Irp we are passing to the next driver.
  985. Return Value:
  986. None.
  987. --*/
  988. {
  989. NTSTATUS status;
  990. status = IoCallDriver(PDevObj, PIrp);
  991. SerialIRPEpilogue(PDevExt);
  992. return status;
  993. }
  994. NTSTATUS
  995. SerialPoCallDriver(PSERIAL_DEVICE_EXTENSION PDevExt, PDEVICE_OBJECT PDevObj,
  996. PIRP PIrp)
  997. /*++
  998. Routine Description:
  999. This function must be called instead of PoCallDriver. It automatically
  1000. updates Irp tracking for PDevObj.
  1001. Arguments:
  1002. PDevExt - Device extension attached to PDevObj
  1003. PDevObj - Pointer to the device object we are tracking pending IRP's for.
  1004. PIrp - Pointer to the Irp we are passing to the next driver.
  1005. Return Value:
  1006. None.
  1007. --*/
  1008. {
  1009. NTSTATUS status;
  1010. status = PoCallDriver(PDevObj, PIrp);
  1011. SerialIRPEpilogue(PDevExt);
  1012. return status;
  1013. }
  1014. VOID
  1015. SerialLogError(
  1016. IN PDRIVER_OBJECT DriverObject,
  1017. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  1018. IN PHYSICAL_ADDRESS P1,
  1019. IN PHYSICAL_ADDRESS P2,
  1020. IN ULONG SequenceNumber,
  1021. IN UCHAR MajorFunctionCode,
  1022. IN UCHAR RetryCount,
  1023. IN ULONG UniqueErrorValue,
  1024. IN NTSTATUS FinalStatus,
  1025. IN NTSTATUS SpecificIOStatus,
  1026. IN ULONG LengthOfInsert1,
  1027. IN PWCHAR Insert1,
  1028. IN ULONG LengthOfInsert2,
  1029. IN PWCHAR Insert2
  1030. )
  1031. /*++
  1032. Routine Description:
  1033. This routine allocates an error log entry, copies the supplied data
  1034. to it, and requests that it be written to the error log file.
  1035. Arguments:
  1036. DriverObject - A pointer to the driver object for the device.
  1037. DeviceObject - A pointer to the device object associated with the
  1038. device that had the error, early in initialization, one may not
  1039. yet exist.
  1040. P1,P2 - If phyical addresses for the controller ports involved
  1041. with the error are available, put them through as dump data.
  1042. SequenceNumber - A ulong value that is unique to an IRP over the
  1043. life of the irp in this driver - 0 generally means an error not
  1044. associated with an irp.
  1045. MajorFunctionCode - If there is an error associated with the irp,
  1046. this is the major function code of that irp.
  1047. RetryCount - The number of times a particular operation has been
  1048. retried.
  1049. UniqueErrorValue - A unique long word that identifies the particular
  1050. call to this function.
  1051. FinalStatus - The final status given to the irp that was associated
  1052. with this error. If this log entry is being made during one of
  1053. the retries this value will be STATUS_SUCCESS.
  1054. SpecificIOStatus - The IO status for a particular error.
  1055. LengthOfInsert1 - The length in bytes (including the terminating NULL)
  1056. of the first insertion string.
  1057. Insert1 - The first insertion string.
  1058. LengthOfInsert2 - The length in bytes (including the terminating NULL)
  1059. of the second insertion string. NOTE, there must
  1060. be a first insertion string for their to be
  1061. a second insertion string.
  1062. Insert2 - The second insertion string.
  1063. Return Value:
  1064. None.
  1065. --*/
  1066. {
  1067. PIO_ERROR_LOG_PACKET errorLogEntry;
  1068. PVOID objectToUse;
  1069. SHORT dumpToAllocate = 0;
  1070. PUCHAR ptrToFirstInsert;
  1071. PUCHAR ptrToSecondInsert;
  1072. PAGED_CODE();
  1073. if (Insert1 == NULL) {
  1074. LengthOfInsert1 = 0;
  1075. }
  1076. if (Insert2 == NULL) {
  1077. LengthOfInsert2 = 0;
  1078. }
  1079. if (ARGUMENT_PRESENT(DeviceObject)) {
  1080. objectToUse = DeviceObject;
  1081. } else {
  1082. objectToUse = DriverObject;
  1083. }
  1084. if (SerialMemCompare(
  1085. P1,
  1086. (ULONG)1,
  1087. SerialPhysicalZero,
  1088. (ULONG)1
  1089. ) != AddressesAreEqual) {
  1090. dumpToAllocate = (SHORT)sizeof(PHYSICAL_ADDRESS);
  1091. }
  1092. if (SerialMemCompare(
  1093. P2,
  1094. (ULONG)1,
  1095. SerialPhysicalZero,
  1096. (ULONG)1
  1097. ) != AddressesAreEqual) {
  1098. dumpToAllocate += (SHORT)sizeof(PHYSICAL_ADDRESS);
  1099. }
  1100. errorLogEntry = IoAllocateErrorLogEntry(
  1101. objectToUse,
  1102. (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
  1103. dumpToAllocate
  1104. + LengthOfInsert1 +
  1105. LengthOfInsert2)
  1106. );
  1107. if ( errorLogEntry != NULL ) {
  1108. errorLogEntry->ErrorCode = SpecificIOStatus;
  1109. errorLogEntry->SequenceNumber = SequenceNumber;
  1110. errorLogEntry->MajorFunctionCode = MajorFunctionCode;
  1111. errorLogEntry->RetryCount = RetryCount;
  1112. errorLogEntry->UniqueErrorValue = UniqueErrorValue;
  1113. errorLogEntry->FinalStatus = FinalStatus;
  1114. errorLogEntry->DumpDataSize = dumpToAllocate;
  1115. if (dumpToAllocate) {
  1116. RtlCopyMemory(
  1117. &errorLogEntry->DumpData[0],
  1118. &P1,
  1119. sizeof(PHYSICAL_ADDRESS)
  1120. );
  1121. if (dumpToAllocate > sizeof(PHYSICAL_ADDRESS)) {
  1122. RtlCopyMemory(
  1123. ((PUCHAR)&errorLogEntry->DumpData[0])
  1124. +sizeof(PHYSICAL_ADDRESS),
  1125. &P2,
  1126. sizeof(PHYSICAL_ADDRESS)
  1127. );
  1128. ptrToFirstInsert =
  1129. ((PUCHAR)&errorLogEntry->DumpData[0])+(2*sizeof(PHYSICAL_ADDRESS));
  1130. } else {
  1131. ptrToFirstInsert =
  1132. ((PUCHAR)&errorLogEntry->DumpData[0])+sizeof(PHYSICAL_ADDRESS);
  1133. }
  1134. } else {
  1135. ptrToFirstInsert = (PUCHAR)&errorLogEntry->DumpData[0];
  1136. }
  1137. ptrToSecondInsert = ptrToFirstInsert + LengthOfInsert1;
  1138. if (LengthOfInsert1) {
  1139. errorLogEntry->NumberOfStrings = 1;
  1140. errorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert -
  1141. (PUCHAR)errorLogEntry);
  1142. RtlCopyMemory(
  1143. ptrToFirstInsert,
  1144. Insert1,
  1145. LengthOfInsert1
  1146. );
  1147. if (LengthOfInsert2) {
  1148. errorLogEntry->NumberOfStrings = 2;
  1149. RtlCopyMemory(
  1150. ptrToSecondInsert,
  1151. Insert2,
  1152. LengthOfInsert2
  1153. );
  1154. }
  1155. }
  1156. IoWriteErrorLogEntry(errorLogEntry);
  1157. }
  1158. }
  1159. VOID
  1160. SerialMarkHardwareBroken(IN PSERIAL_DEVICE_EXTENSION PDevExt)
  1161. /*++
  1162. Routine Description:
  1163. Marks a UART as broken. This causes the driver stack to stop accepting
  1164. requests and eventually be removed.
  1165. Arguments:
  1166. PDevExt - Device extension attached to PDevObj
  1167. Return Value:
  1168. None.
  1169. --*/
  1170. {
  1171. PAGED_CODE();
  1172. //
  1173. // Mark as damaged goods
  1174. //
  1175. SerialSetFlags(PDevExt, SERIAL_FLAGS_BROKENHW);
  1176. //
  1177. // Write a log entry
  1178. //
  1179. SerialLogError(PDevExt->DriverObject, NULL, SerialPhysicalZero,
  1180. SerialPhysicalZero, 0, 0, 0, 88, STATUS_SUCCESS,
  1181. SERIAL_HARDWARE_FAILURE, PDevExt->DeviceName.Length
  1182. + sizeof(WCHAR), PDevExt->DeviceName.Buffer, 0, NULL);
  1183. //
  1184. // Invalidate the device
  1185. //
  1186. IoInvalidateDeviceState(PDevExt->Pdo);
  1187. }
  1188. VOID
  1189. SerialSetDeviceFlags(IN PSERIAL_DEVICE_EXTENSION PDevExt, OUT PULONG PFlags,
  1190. IN ULONG Value, IN BOOLEAN Set)
  1191. /*++
  1192. Routine Description:
  1193. Sets flags in a value protected by the flags spinlock. This is used
  1194. to set values that would stop IRP's from being accepted.
  1195. Arguments:
  1196. PDevExt - Device extension attached to PDevObj
  1197. PFlags - Pointer to the flags variable that needs changing
  1198. Value - Value to modify flags variable with
  1199. Set - TRUE if |= , FALSE if &=
  1200. Return Value:
  1201. None.
  1202. --*/
  1203. {
  1204. KIRQL oldIrql;
  1205. KeAcquireSpinLock(&PDevExt->FlagsLock, &oldIrql);
  1206. if (Set) {
  1207. *PFlags |= Value;
  1208. } else {
  1209. *PFlags &= ~Value;
  1210. }
  1211. KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrql);
  1212. }