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.

1630 lines
44 KiB

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