|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: write.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains the code that is very specific to write ! 12: operations in the serial driver ! 13: ! 14: Author: ! 15: ! 16: Anthony V. Ercolano 26-Sep-1991 ! 17: ! 18: Environment: ! 19: ! 20: Kernel mode ! 21: ! 22: Revision History : ! 23: ! 24: --*/ ! 25: ! 26: #include <stddef.h> ! 27: #include "ntddk.h" ! 28: #include "ntddser.h" ! 29: #include "serial.h" ! 30: #include "serialp.h" ! 31: ! 32: ! 33: ! 34: BOOLEAN ! 35: SerialGiveWriteToIsr( ! 36: IN PVOID Context ! 37: ); ! 38: ! 39: VOID ! 40: SerialCancelCurrentWrite( ! 41: PDEVICE_OBJECT DeviceObject, ! 42: PIRP Irp ! 43: ); ! 44: ! 45: BOOLEAN ! 46: SerialGrabWriteFromIsr( ! 47: IN PVOID Context ! 48: ); ! 49: ! 50: BOOLEAN ! 51: SerialGrabXoffFromIsr( ! 52: IN PVOID Context ! 53: ); ! 54: ! 55: VOID ! 56: SerialCancelCurrentXoff( ! 57: PDEVICE_OBJECT DeviceObject, ! 58: PIRP Irp ! 59: ); ! 60: ! 61: BOOLEAN ! 62: SerialGiveXoffToIsr( ! 63: IN PVOID Context ! 64: ); ! 65: ! 66: ! 67: ! 68: NTSTATUS ! 69: SerialWrite( ! 70: IN PDEVICE_OBJECT DeviceObject, ! 71: IN PIRP Irp ! 72: ) ! 73: ! 74: /*++ ! 75: ! 76: Routine Description: ! 77: ! 78: This is the dispatch routine for write. It validates the parameters ! 79: for the write request and if all is ok then it places the request ! 80: on the work queue. ! 81: ! 82: Arguments: ! 83: ! 84: DeviceObject - Pointer to the device object for this device ! 85: ! 86: Irp - Pointer to the IRP for the current request ! 87: ! 88: Return Value: ! 89: ! 90: If the io is zero length then it will return STATUS_SUCCESS, ! 91: otherwise this routine will return STATUS_PENDING. ! 92: ! 93: --*/ ! 94: ! 95: { ! 96: ! 97: PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension; ! 98: ! 99: SerialDump( ! 100: SERIRPPATH, ! 101: ("SERIAL: Dispatch entry for: %x\n",Irp) ! 102: ); ! 103: if (SerialCompleteIfError( ! 104: DeviceObject, ! 105: Irp ! 106: ) != STATUS_SUCCESS) { ! 107: ! 108: return STATUS_CANCELLED; ! 109: ! 110: } ! 111: ! 112: Irp->IoStatus.Information = 0L; ! 113: ! 114: // ! 115: // Quick check for a zero length write. If it is zero length ! 116: // then we are already done! ! 117: // ! 118: ! 119: if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length) { ! 120: ! 121: // ! 122: // Well it looks like we actually have to do some ! 123: // work. Put the write on the queue so that we can ! 124: // process it when our previous writes are done. ! 125: // ! 126: ! 127: return SerialStartOrQueue( ! 128: Extension, ! 129: Irp, ! 130: &Extension->WriteQueue, ! 131: &Extension->CurrentWriteIrp, ! 132: SerialStartWrite ! 133: ); ! 134: ! 135: } else { ! 136: ! 137: Irp->IoStatus.Status = STATUS_SUCCESS; ! 138: SerialDump( ! 139: SERIRPPATH, ! 140: ("SERIAL: Complete Irp: %x\n",Irp) ! 141: ); ! 142: IoCompleteRequest( ! 143: Irp, ! 144: 0 ! 145: ); ! 146: ! 147: return STATUS_SUCCESS; ! 148: ! 149: } ! 150: ! 151: } ! 152: ! 153: NTSTATUS ! 154: SerialStartWrite( ! 155: IN PSERIAL_DEVICE_EXTENSION Extension ! 156: ) ! 157: ! 158: /*++ ! 159: ! 160: Routine Description: ! 161: ! 162: This routine is used to start off any write. It initializes ! 163: the Iostatus fields of the irp. It will set up any timers ! 164: that are used to control the write. ! 165: ! 166: Arguments: ! 167: ! 168: Extension - Points to the serial device extension ! 169: ! 170: Return Value: ! 171: ! 172: This routine will return STATUS_PENDING for all writes ! 173: other than those that we find are cancelled. ! 174: ! 175: --*/ ! 176: ! 177: { ! 178: ! 179: PIRP NewIrp; ! 180: KIRQL OldIrql; ! 181: LARGE_INTEGER TotalTime; ! 182: BOOLEAN UseATimer; ! 183: SERIAL_TIMEOUTS Timeouts; ! 184: BOOLEAN SetFirstStatus = FALSE; ! 185: NTSTATUS FirstStatus; ! 186: ! 187: do { ! 188: ! 189: // ! 190: // If there is an xoff counter then complete it. ! 191: // ! 192: ! 193: IoAcquireCancelSpinLock(&OldIrql); ! 194: ! 195: // ! 196: // We see if there is a actually an Xoff counter irp. ! 197: // ! 198: // If there is, we put the write irp back on the head ! 199: // of the write list. We then kill the xoff counter. ! 200: // The xoff counter killing code will actually make the ! 201: // xoff counter back into the current write irp, and ! 202: // in the course of completing the xoff (which is now ! 203: // the current write) we will restart this irp. ! 204: // ! 205: ! 206: if (Extension->CurrentXoffIrp) { ! 207: ! 208: InsertHeadList( ! 209: &Extension->WriteQueue, ! 210: &Extension->CurrentWriteIrp->Tail.Overlay.ListEntry ! 211: ); ! 212: ! 213: if (!SetFirstStatus) { ! 214: ! 215: IoMarkIrpPending(Extension->CurrentWriteIrp); ! 216: SetFirstStatus = TRUE; ! 217: FirstStatus = STATUS_PENDING; ! 218: ! 219: } ! 220: ! 221: if (SERIAL_REFERENCE_COUNT(Extension->CurrentXoffIrp)) { ! 222: ! 223: // ! 224: // The reference count is non-zero. This implies that ! 225: // the xoff irp has not made it through the completion ! 226: // path yet. We will increment the reference count ! 227: // and attempt to complete it ourseleves. ! 228: // ! 229: ! 230: SERIAL_INC_REFERENCE(Extension->CurrentXoffIrp); ! 231: ! 232: Extension->CurrentWriteIrp = Extension->CurrentXoffIrp; ! 233: ! 234: // ! 235: // The following call will actually release the ! 236: // cancel spin lock. ! 237: // ! 238: ! 239: SerialTryToCompleteCurrent( ! 240: Extension, ! 241: SerialGrabXoffFromIsr, ! 242: OldIrql, ! 243: STATUS_SERIAL_MORE_WRITES, ! 244: &Extension->CurrentWriteIrp, ! 245: &Extension->WriteQueue, ! 246: NULL, ! 247: &Extension->XoffCountTimer, ! 248: SerialStartWrite, ! 249: SerialGetNextWrite ! 250: ); ! 251: ! 252: return FirstStatus; ! 253: ! 254: } else { ! 255: ! 256: // ! 257: // The irp is well on its way to being finished. ! 258: // We can let the regular completion code do the ! 259: // work. Just release the spin lock. ! 260: // ! 261: ! 262: IoReleaseCancelSpinLock(OldIrql); ! 263: ! 264: return FirstStatus; ! 265: ! 266: } ! 267: ! 268: } else { ! 269: ! 270: IoReleaseCancelSpinLock(OldIrql); ! 271: ! 272: } ! 273: ! 274: UseATimer = FALSE; ! 275: ! 276: // ! 277: // Calculate the timeout value needed for the ! 278: // request. Note that the values stored in the ! 279: // timeout record are in milliseconds. Note that ! 280: // if the timeout values are zero then we won't start ! 281: // the timer. ! 282: // ! 283: ! 284: KeAcquireSpinLock( ! 285: &Extension->ControlLock, ! 286: &OldIrql ! 287: ); ! 288: ! 289: Timeouts = Extension->Timeouts; ! 290: ! 291: KeReleaseSpinLock( ! 292: &Extension->ControlLock, ! 293: OldIrql ! 294: ); ! 295: ! 296: if (Timeouts.WriteTotalTimeoutConstant || ! 297: Timeouts.WriteTotalTimeoutMultiplier) { ! 298: ! 299: PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( ! 300: Extension->CurrentWriteIrp ! 301: ); ! 302: UseATimer = TRUE; ! 303: ! 304: // ! 305: // We have some timer values to calculate. ! 306: // ! 307: // Take care, we might have an xoff counter masquerading ! 308: // as a write. ! 309: // ! 310: ! 311: TotalTime = RtlEnlargedUnsignedMultiply( ! 312: (IrpSp->MajorFunction == IRP_MJ_WRITE)? ! 313: (IrpSp->Parameters.Write.Length): ! 314: (1), ! 315: Timeouts.WriteTotalTimeoutMultiplier ! 316: ); ! 317: ! 318: TotalTime = RtlLargeIntegerAdd( ! 319: TotalTime, ! 320: RtlConvertUlongToLargeInteger( ! 321: Timeouts.WriteTotalTimeoutConstant ! 322: ) ! 323: ); ! 324: ! 325: TotalTime = RtlExtendedIntegerMultiply( ! 326: TotalTime, ! 327: -10000 ! 328: ); ! 329: ! 330: } ! 331: ! 332: // ! 333: // The irp may be going to the isr shortly. Now ! 334: // is a good time to initialize its reference counts. ! 335: // ! 336: ! 337: SERIAL_INIT_REFERENCE(Extension->CurrentWriteIrp); ! 338: ! 339: // ! 340: // We need to see if this irp should be canceled. ! 341: // ! 342: ! 343: IoAcquireCancelSpinLock(&OldIrql); ! 344: if (Extension->CurrentWriteIrp->Cancel) { ! 345: ! 346: IoReleaseCancelSpinLock(OldIrql); ! 347: Extension->CurrentWriteIrp->IoStatus.Status = STATUS_CANCELLED; ! 348: ! 349: if (!SetFirstStatus) { ! 350: ! 351: FirstStatus = STATUS_CANCELLED; ! 352: SetFirstStatus = TRUE; ! 353: ! 354: } ! 355: ! 356: } else { ! 357: ! 358: if (!SetFirstStatus) { ! 359: ! 360: // ! 361: // If we haven't set our first status, then ! 362: // this is the only irp that could have possibly ! 363: // not been on the queue. (It could have been ! 364: // on the queue if this routine is being invoked ! 365: // from the completion routine.) Since this ! 366: // irp might never have been on the queue we ! 367: // should mark it as pending. ! 368: // ! 369: ! 370: IoMarkIrpPending(Extension->CurrentWriteIrp); ! 371: SetFirstStatus = TRUE; ! 372: FirstStatus = STATUS_PENDING; ! 373: ! 374: } ! 375: ! 376: // ! 377: // We give the irp to to the isr to write out. ! 378: // We set a cancel routine that knows how to ! 379: // grab the current write away from the isr. ! 380: // ! 381: // Since the cancel routine has an implicit reference ! 382: // to this irp up the reference count. ! 383: // ! 384: ! 385: IoSetCancelRoutine( ! 386: Extension->CurrentWriteIrp, ! 387: SerialCancelCurrentWrite ! 388: ); ! 389: ! 390: SERIAL_INC_REFERENCE(Extension->CurrentWriteIrp); ! 391: ! 392: if (UseATimer) { ! 393: ! 394: KeSetTimer( ! 395: &Extension->WriteRequestTotalTimer, ! 396: TotalTime, ! 397: &Extension->TotalWriteTimeoutDpc ! 398: ); ! 399: ! 400: // ! 401: // This timer now has a reference to the irp. ! 402: // ! 403: ! 404: SERIAL_INC_REFERENCE(Extension->CurrentWriteIrp); ! 405: } ! 406: ! 407: KeSynchronizeExecution( ! 408: Extension->Interrupt, ! 409: SerialGiveWriteToIsr, ! 410: Extension ! 411: ); ! 412: ! 413: IoReleaseCancelSpinLock(OldIrql); ! 414: break; ! 415: ! 416: } ! 417: ! 418: // ! 419: // Well the write was canceled before we could start it up. ! 420: // Try to get another. ! 421: // ! 422: ! 423: SerialGetNextWrite( ! 424: &Extension->CurrentWriteIrp, ! 425: &Extension->WriteQueue, ! 426: &NewIrp, ! 427: TRUE ! 428: ); ! 429: ! 430: } while (NewIrp); ! 431: ! 432: return FirstStatus; ! 433: ! 434: } ! 435: ! 436: VOID ! 437: SerialGetNextWrite( ! 438: IN PIRP *CurrentOpIrp, ! 439: IN PLIST_ENTRY QueueToProcess, ! 440: IN PIRP *NewIrp, ! 441: IN BOOLEAN CompleteCurrent ! 442: ) ! 443: ! 444: /*++ ! 445: ! 446: Routine Description: ! 447: ! 448: This routine completes the old write as well as getting ! 449: a pointer to the next write. ! 450: ! 451: The reason that we have have pointers to the current write ! 452: queue as well as the current write irp is so that this ! 453: routine may be used in the common completion code for ! 454: read and write. ! 455: ! 456: Arguments: ! 457: ! 458: CurrentOpIrp - Pointer to the pointer that points to the ! 459: current write irp. ! 460: ! 461: QueueToProcess - Pointer to the write queue. ! 462: ! 463: NewIrp - A pointer to a pointer to the irp that will be the ! 464: current irp. Note that this could end up pointing ! 465: to a null pointer. This does NOT necessaryly mean ! 466: that there is no current write. What could occur ! 467: is that while the cancel lock is held the write ! 468: queue ended up being empty, but as soon as we release ! 469: the cancel spin lock a new irp came in from ! 470: SerialStartWrite. ! 471: ! 472: CompleteCurrent - Flag indicates whether the CurrentOpIrp should ! 473: be completed. ! 474: ! 475: Return Value: ! 476: ! 477: None. ! 478: ! 479: --*/ ! 480: ! 481: { ! 482: ! 483: PSERIAL_DEVICE_EXTENSION Extension = CONTAINING_RECORD( ! 484: QueueToProcess, ! 485: SERIAL_DEVICE_EXTENSION, ! 486: WriteQueue ! 487: ); ! 488: ! 489: do { ! 490: ! 491: ! 492: // ! 493: // We could be completing a flush. ! 494: // ! 495: ! 496: if (IoGetCurrentIrpStackLocation(*CurrentOpIrp)->MajorFunction ! 497: == IRP_MJ_WRITE) { ! 498: ! 499: KIRQL OldIrql; ! 500: ! 501: ASSERT(Extension->TotalCharsQueued >= ! 502: (IoGetCurrentIrpStackLocation(*CurrentOpIrp) ! 503: ->Parameters.Write.Length)); ! 504: ! 505: IoAcquireCancelSpinLock(&OldIrql); ! 506: Extension->TotalCharsQueued -= ! 507: IoGetCurrentIrpStackLocation(*CurrentOpIrp) ! 508: ->Parameters.Write.Length; ! 509: IoReleaseCancelSpinLock(OldIrql); ! 510: ! 511: } else if (IoGetCurrentIrpStackLocation(*CurrentOpIrp)->MajorFunction ! 512: == IRP_MJ_DEVICE_CONTROL) { ! 513: ! 514: KIRQL OldIrql; ! 515: ! 516: IoAcquireCancelSpinLock(&OldIrql); ! 517: ! 518: // ! 519: // If CurrentXoffIrp is not equal to null, this ! 520: // implies that this is the "second" time around ! 521: // for this irp, which implies that we should really ! 522: // be completing it this time. ! 523: // ! 524: ! 525: if (Extension->CurrentXoffIrp) { ! 526: ! 527: Extension->CurrentXoffIrp = NULL; ! 528: IoReleaseCancelSpinLock(OldIrql); ! 529: ! 530: } else { ! 531: ! 532: PIRP Irp = *CurrentOpIrp; ! 533: ! 534: PSERIAL_XOFF_COUNTER Xc = Irp->AssociatedIrp.SystemBuffer; ! 535: ! 536: // ! 537: // We absolutely shouldn't have a cancel routine ! 538: // at this point. ! 539: // ! 540: ! 541: ASSERT(!Irp->CancelRoutine); ! 542: ! 543: // ! 544: // This could only be a xoff counter masquerading as ! 545: // a write irp. ! 546: // ! 547: ! 548: Extension->TotalCharsQueued--; ! 549: ! 550: // ! 551: // Check to see of the xoff irp has been set with success. ! 552: // This means that the write completed normally. If that ! 553: // is the case, and it hasn't been set to cancel in the ! 554: // meanwhile, then go on and make it the CurrentXoffIrp. ! 555: // ! 556: ! 557: if (Irp->IoStatus.Status != STATUS_SUCCESS) { ! 558: ! 559: // ! 560: // Oh well, we can just finish it off. ! 561: // ! 562: NOTHING; ! 563: ! 564: } else if (Irp->Cancel) { ! 565: ! 566: Irp->IoStatus.Status = STATUS_CANCELLED; ! 567: ! 568: } else { ! 569: ! 570: // ! 571: // Give it a new cancel routine, and increment the ! 572: // reference count because the cancel routine has ! 573: // a reference to it. ! 574: // ! 575: ! 576: IoSetCancelRoutine( ! 577: Irp, ! 578: SerialCancelCurrentXoff ! 579: ); ! 580: ! 581: SERIAL_INC_REFERENCE(Irp); ! 582: ! 583: // ! 584: // We don't want to complete the current irp now. This ! 585: // will now get completed by the Xoff counter code. ! 586: // ! 587: ! 588: CompleteCurrent = FALSE; ! 589: ! 590: // ! 591: // Give the counter to the isr. ! 592: // ! 593: ! 594: Extension->CurrentXoffIrp = Irp; ! 595: KeSynchronizeExecution( ! 596: Extension->Interrupt, ! 597: SerialGiveXoffToIsr, ! 598: Extension ! 599: ); ! 600: ! 601: // ! 602: // Start the timer for the counter and increment ! 603: // the reference count since the timer has a ! 604: // reference to the irp. ! 605: // ! 606: ! 607: if (Xc->Timeout) { ! 608: ! 609: KeSetTimer( ! 610: &Extension->XoffCountTimer, ! 611: RtlLargeIntegerNegate( ! 612: RtlEnlargedUnsignedMultiply( ! 613: 10000, ! 614: Xc->Timeout ! 615: ) ! 616: ), ! 617: &Extension->XoffCountTimeoutDpc ! 618: ); ! 619: ! 620: SERIAL_INC_REFERENCE(Irp); ! 621: ! 622: } ! 623: ! 624: } ! 625: ! 626: IoReleaseCancelSpinLock(OldIrql); ! 627: ! 628: } ! 629: ! 630: } ! 631: ! 632: // ! 633: // Note that the following call will (probably) also cause ! 634: // the current irp to be completed. ! 635: // ! 636: ! 637: SerialGetNextIrp( ! 638: CurrentOpIrp, ! 639: QueueToProcess, ! 640: NewIrp, ! 641: CompleteCurrent ! 642: ); ! 643: ! 644: if (!*NewIrp) { ! 645: ! 646: KIRQL OldIrql; ! 647: ! 648: IoAcquireCancelSpinLock(&OldIrql); ! 649: KeSynchronizeExecution( ! 650: Extension->Interrupt, ! 651: SerialProcessEmptyTransmit, ! 652: Extension ! 653: ); ! 654: IoReleaseCancelSpinLock(OldIrql); ! 655: ! 656: break; ! 657: ! 658: } else if (IoGetCurrentIrpStackLocation(*NewIrp)->MajorFunction ! 659: == IRP_MJ_FLUSH_BUFFERS) { ! 660: ! 661: // ! 662: // If we encounter a flush request we just want to get ! 663: // the next irp and complete the flush. ! 664: // ! 665: // Note that if NewIrp is non-null then it is also ! 666: // equal to CurrentWriteIrp. ! 667: // ! 668: ! 669: ! 670: ASSERT((*NewIrp) == (*CurrentOpIrp)); ! 671: (*NewIrp)->IoStatus.Status = STATUS_SUCCESS; ! 672: ! 673: } else { ! 674: ! 675: break; ! 676: ! 677: } ! 678: ! 679: } while (TRUE); ! 680: ! 681: } ! 682: ! 683: VOID ! 684: SerialCompleteWrite( ! 685: IN PKDPC Dpc, ! 686: IN PVOID DeferredContext, ! 687: IN PVOID SystemContext1, ! 688: IN PVOID SystemContext2 ! 689: ) ! 690: ! 691: /*++ ! 692: ! 693: Routine Description: ! 694: ! 695: This routine is merely used to complete any write. It ! 696: assumes that the status and the information fields of ! 697: the irp are already correctly filled in. ! 698: ! 699: Arguments: ! 700: ! 701: Dpc - Not Used. ! 702: ! 703: DeferredContext - Really points to the device extension. ! 704: ! 705: SystemContext1 - Not Used. ! 706: ! 707: SystemContext2 - Not Used. ! 708: ! 709: Return Value: ! 710: ! 711: None. ! 712: ! 713: --*/ ! 714: ! 715: { ! 716: ! 717: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext; ! 718: KIRQL OldIrql; ! 719: ! 720: UNREFERENCED_PARAMETER(Dpc); ! 721: UNREFERENCED_PARAMETER(SystemContext1); ! 722: UNREFERENCED_PARAMETER(SystemContext2); ! 723: ! 724: IoAcquireCancelSpinLock(&OldIrql); ! 725: ! 726: SerialTryToCompleteCurrent( ! 727: Extension, ! 728: NULL, ! 729: OldIrql, ! 730: STATUS_SUCCESS, ! 731: &Extension->CurrentWriteIrp, ! 732: &Extension->WriteQueue, ! 733: NULL, ! 734: &Extension->WriteRequestTotalTimer, ! 735: SerialStartWrite, ! 736: SerialGetNextWrite ! 737: ); ! 738: ! 739: } ! 740: ! 741: BOOLEAN ! 742: SerialProcessEmptyTransmit( ! 743: IN PVOID Context ! 744: ) ! 745: ! 746: /*++ ! 747: ! 748: Routine Description: ! 749: ! 750: This routine is used to determine if conditions are appropriate ! 751: to satisfy a wait for transmit empty event, and if so to complete ! 752: the irp that is waiting for that event. It also call the code ! 753: that checks to see if we should lower the RTS line if we are ! 754: doing transmit toggling. ! 755: ! 756: NOTE: This routine is called by KeSynchronizeExecution. ! 757: ! 758: NOTE: This routine assumes that it is called with the cancel ! 759: spinlock held. ! 760: ! 761: Arguments: ! 762: ! 763: Context - Really a pointer to the device extension. ! 764: ! 765: Return Value: ! 766: ! 767: This routine always returns FALSE. ! 768: ! 769: --*/ ! 770: ! 771: { ! 772: ! 773: PSERIAL_DEVICE_EXTENSION Extension = Context; ! 774: ! 775: if (Extension->IsrWaitMask && (Extension->IsrWaitMask & SERIAL_EV_TXEMPTY) && ! 776: Extension->EmptiedTransmit && (!Extension->TransmitImmediate) && ! 777: (!Extension->CurrentWriteIrp) && IsListEmpty(&Extension->WriteQueue)) { ! 778: ! 779: Extension->HistoryMask |= SERIAL_EV_TXEMPTY; ! 780: if (Extension->IrpMaskLocation) { ! 781: ! 782: *Extension->IrpMaskLocation = Extension->HistoryMask; ! 783: Extension->IrpMaskLocation = NULL; ! 784: Extension->HistoryMask = 0; ! 785: ! 786: Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG); ! 787: KeInsertQueueDpc( ! 788: &Extension->CommWaitDpc, ! 789: NULL, ! 790: NULL ! 791: ); ! 792: ! 793: } ! 794: ! 795: Extension->CountOfTryingToLowerRTS++; ! 796: SerialPerhapsLowerRTS(Extension); ! 797: ! 798: } ! 799: ! 800: return FALSE; ! 801: ! 802: } ! 803: ! 804: BOOLEAN ! 805: SerialGiveWriteToIsr( ! 806: IN PVOID Context ! 807: ) ! 808: ! 809: /*++ ! 810: ! 811: Routine Description: ! 812: ! 813: Try to start off the write by slipping it in behind ! 814: a transmit immediate char, or if that isn't available ! 815: and the transmit holding register is empty, "tickle" ! 816: the UART into interrupting with a transmit buffer ! 817: empty. ! 818: ! 819: NOTE: This routine is called by KeSynchronizeExecution. ! 820: ! 821: NOTE: This routine assumes that it is called with the ! 822: cancel spin lock held. ! 823: ! 824: Arguments: ! 825: ! 826: Context - Really a pointer to the device extension. ! 827: ! 828: Return Value: ! 829: ! 830: This routine always returns FALSE. ! 831: ! 832: --*/ ! 833: ! 834: { ! 835: ! 836: PSERIAL_DEVICE_EXTENSION Extension = Context; ! 837: ! 838: // ! 839: // The current stack location. This contains all of the ! 840: // information we need to process this particular request. ! 841: // ! 842: PIO_STACK_LOCATION IrpSp; ! 843: ! 844: IrpSp = IoGetCurrentIrpStackLocation(Extension->CurrentWriteIrp); ! 845: ! 846: // ! 847: // We might have a xoff counter request masquerading as a ! 848: // write. The length of these requests will always be one ! 849: // and we can get a pointer to the actual character from ! 850: // the data supplied by the user. ! 851: // ! 852: ! 853: if (IrpSp->MajorFunction == IRP_MJ_WRITE) { ! 854: ! 855: Extension->WriteLength = IrpSp->Parameters.Write.Length; ! 856: Extension->WriteCurrentChar = ! 857: Extension->CurrentWriteIrp->AssociatedIrp.SystemBuffer; ! 858: ! 859: } else { ! 860: ! 861: Extension->WriteLength = 1; ! 862: Extension->WriteCurrentChar = ! 863: ((PUCHAR)Extension->CurrentWriteIrp->AssociatedIrp.SystemBuffer) + ! 864: FIELD_OFFSET( ! 865: SERIAL_XOFF_COUNTER, ! 866: XoffChar ! 867: ); ! 868: ! 869: } ! 870: ! 871: // ! 872: // The isr now has a reference to the irp. ! 873: // ! 874: ! 875: SERIAL_INC_REFERENCE(Extension->CurrentWriteIrp); ! 876: ! 877: // ! 878: // Check first to see if an immediate char is transmitting. ! 879: // If it is then we'll just slip in behind it when its ! 880: // done. ! 881: // ! 882: ! 883: if (!Extension->TransmitImmediate) { ! 884: ! 885: // ! 886: // If there is no immediate char transmitting then we ! 887: // will "re-enable" the transmit holding register empty ! 888: // interrupt. The 8250 family of devices will always ! 889: // signal a transmit holding register empty interrupt ! 890: // *ANY* time this bit is set to one. By doing things ! 891: // this way we can simply use the normal interrupt code ! 892: // to start off this write. ! 893: // ! 894: // We've been keeping track of whether the transmit holding ! 895: // register is empty so it we only need to do this ! 896: // if the register is empty. ! 897: // ! 898: ! 899: if (Extension->HoldingEmpty) { ! 900: ! 901: DISABLE_ALL_INTERRUPTS(Extension->Controller); ! 902: ENABLE_ALL_INTERRUPTS(Extension->Controller); ! 903: ! 904: } ! 905: ! 906: } ! 907: ! 908: // ! 909: // The rts line may already be up from previous writes, ! 910: // however, it won't take much additional time to turn ! 911: // on the RTS line if we are doing transmit toggling. ! 912: // ! 913: ! 914: if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == ! 915: SERIAL_TRANSMIT_TOGGLE) { ! 916: ! 917: SerialSetRTS(Extension); ! 918: ! 919: } ! 920: ! 921: return FALSE; ! 922: ! 923: } ! 924: ! 925: VOID ! 926: SerialCancelCurrentWrite( ! 927: PDEVICE_OBJECT DeviceObject, ! 928: PIRP Irp ! 929: ) ! 930: ! 931: /*++ ! 932: ! 933: Routine Description: ! 934: ! 935: This routine is used to cancel the current write. ! 936: ! 937: Arguments: ! 938: ! 939: DeviceObject - Pointer to the device object for this device ! 940: ! 941: Irp - Pointer to the IRP to be canceled. ! 942: ! 943: Return Value: ! 944: ! 945: None. ! 946: ! 947: --*/ ! 948: ! 949: { ! 950: ! 951: PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension; ! 952: ! 953: SerialTryToCompleteCurrent( ! 954: Extension, ! 955: SerialGrabWriteFromIsr, ! 956: Irp->CancelIrql, ! 957: STATUS_CANCELLED, ! 958: &Extension->CurrentWriteIrp, ! 959: &Extension->WriteQueue, ! 960: NULL, ! 961: &Extension->WriteRequestTotalTimer, ! 962: SerialStartWrite, ! 963: SerialGetNextWrite ! 964: ); ! 965: ! 966: } ! 967: ! 968: VOID ! 969: SerialWriteTimeout( ! 970: IN PKDPC Dpc, ! 971: IN PVOID DeferredContext, ! 972: IN PVOID SystemContext1, ! 973: IN PVOID SystemContext2 ! 974: ) ! 975: ! 976: /*++ ! 977: ! 978: Routine Description: ! 979: ! 980: This routine will try to timeout the current write. ! 981: ! 982: Arguments: ! 983: ! 984: Dpc - Not Used. ! 985: ! 986: DeferredContext - Really points to the device extension. ! 987: ! 988: SystemContext1 - Not Used. ! 989: ! 990: SystemContext2 - Not Used. ! 991: ! 992: Return Value: ! 993: ! 994: None. ! 995: ! 996: --*/ ! 997: ! 998: { ! 999: ! 1000: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext; ! 1001: KIRQL OldIrql; ! 1002: ! 1003: UNREFERENCED_PARAMETER(Dpc); ! 1004: UNREFERENCED_PARAMETER(SystemContext1); ! 1005: UNREFERENCED_PARAMETER(SystemContext2); ! 1006: ! 1007: IoAcquireCancelSpinLock(&OldIrql); ! 1008: ! 1009: SerialTryToCompleteCurrent( ! 1010: Extension, ! 1011: SerialGrabWriteFromIsr, ! 1012: OldIrql, ! 1013: STATUS_TIMEOUT, ! 1014: &Extension->CurrentWriteIrp, ! 1015: &Extension->WriteQueue, ! 1016: NULL, ! 1017: &Extension->WriteRequestTotalTimer, ! 1018: SerialStartWrite, ! 1019: SerialGetNextWrite ! 1020: ); ! 1021: ! 1022: } ! 1023: ! 1024: BOOLEAN ! 1025: SerialGrabWriteFromIsr( ! 1026: IN PVOID Context ! 1027: ) ! 1028: ! 1029: /*++ ! 1030: ! 1031: Routine Description: ! 1032: ! 1033: ! 1034: This routine is used to grab the current irp, which could be timing ! 1035: out or canceling, from the ISR ! 1036: ! 1037: NOTE: This routine is being called from KeSynchronizeExecution. ! 1038: ! 1039: NOTE: This routine assumes that the cancel spin lock is held ! 1040: when this routine is called. ! 1041: ! 1042: Arguments: ! 1043: ! 1044: Context - Really a pointer to the device extension. ! 1045: ! 1046: Return Value: ! 1047: ! 1048: Always false. ! 1049: ! 1050: --*/ ! 1051: ! 1052: { ! 1053: ! 1054: PSERIAL_DEVICE_EXTENSION Extension = Context; ! 1055: ! 1056: // ! 1057: // Check if the write length is non-zero. If it is non-zero ! 1058: // then the ISR still owns the irp. We calculate the the number ! 1059: // of characters written and update the information field of the ! 1060: // irp with the characters written. We then clear the write length ! 1061: // the isr sees. ! 1062: // ! 1063: ! 1064: if (Extension->WriteLength) { ! 1065: ! 1066: // ! 1067: // We could have an xoff counter masquerading as a ! 1068: // write irp. If so, don't update the write length. ! 1069: // ! 1070: ! 1071: if (IoGetCurrentIrpStackLocation(Extension->CurrentWriteIrp) ! 1072: ->MajorFunction == IRP_MJ_WRITE) { ! 1073: ! 1074: Extension->CurrentWriteIrp->IoStatus.Information = ! 1075: IoGetCurrentIrpStackLocation( ! 1076: Extension->CurrentWriteIrp ! 1077: )->Parameters.Write.Length - ! 1078: Extension->WriteLength; ! 1079: ! 1080: } else { ! 1081: ! 1082: Extension->CurrentWriteIrp->IoStatus.Information = 0; ! 1083: ! 1084: } ! 1085: ! 1086: // ! 1087: // Since the isr no longer references this irp, we can ! 1088: // decrement it's reference count. ! 1089: // ! 1090: ! 1091: SERIAL_DEC_REFERENCE(Extension->CurrentWriteIrp); ! 1092: ! 1093: Extension->WriteLength = 0; ! 1094: ! 1095: } ! 1096: ! 1097: return FALSE; ! 1098: ! 1099: } ! 1100: ! 1101: BOOLEAN ! 1102: SerialGrabXoffFromIsr( ! 1103: IN PVOID Context ! 1104: ) ! 1105: ! 1106: /*++ ! 1107: ! 1108: Routine Description: ! 1109: ! 1110: This routine is used to grab an xoff counter irp from the ! 1111: isr when it is no longer masquerading as a write irp. This ! 1112: routine is called by the cancel and timeout code for the ! 1113: xoff counter ioctl. ! 1114: ! 1115: ! 1116: NOTE: This routine is being called from KeSynchronizeExecution. ! 1117: ! 1118: NOTE: This routine assumes that the cancel spin lock is held ! 1119: when this routine is called. ! 1120: ! 1121: Arguments: ! 1122: ! 1123: Context - Really a pointer to the device extension. ! 1124: ! 1125: Return Value: ! 1126: ! 1127: Always false. ! 1128: ! 1129: --*/ ! 1130: ! 1131: { ! 1132: ! 1133: PSERIAL_DEVICE_EXTENSION Extension = Context; ! 1134: ! 1135: if (Extension->CountSinceXoff) { ! 1136: ! 1137: // ! 1138: // This is only non-zero when there actually is a Xoff ioctl ! 1139: // counting down. ! 1140: // ! 1141: ! 1142: Extension->CountSinceXoff = 0; ! 1143: ! 1144: // ! 1145: // We decrement the count since the isr no longer owns ! 1146: // the irp. ! 1147: // ! 1148: ! 1149: SERIAL_DEC_REFERENCE(Extension->CurrentXoffIrp); ! 1150: ! 1151: } ! 1152: ! 1153: return FALSE; ! 1154: ! 1155: } ! 1156: ! 1157: VOID ! 1158: SerialCompleteXoff( ! 1159: IN PKDPC Dpc, ! 1160: IN PVOID DeferredContext, ! 1161: IN PVOID SystemContext1, ! 1162: IN PVOID SystemContext2 ! 1163: ) ! 1164: ! 1165: /*++ ! 1166: ! 1167: Routine Description: ! 1168: ! 1169: This routine is merely used to truely complete an xoff counter irp. It ! 1170: assumes that the status and the information fields of the irp are ! 1171: already correctly filled in. ! 1172: ! 1173: Arguments: ! 1174: ! 1175: Dpc - Not Used. ! 1176: ! 1177: DeferredContext - Really points to the device extension. ! 1178: ! 1179: SystemContext1 - Not Used. ! 1180: ! 1181: SystemContext2 - Not Used. ! 1182: ! 1183: Return Value: ! 1184: ! 1185: None. ! 1186: ! 1187: --*/ ! 1188: ! 1189: { ! 1190: ! 1191: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext; ! 1192: KIRQL OldIrql; ! 1193: ! 1194: UNREFERENCED_PARAMETER(Dpc); ! 1195: UNREFERENCED_PARAMETER(SystemContext1); ! 1196: UNREFERENCED_PARAMETER(SystemContext2); ! 1197: ! 1198: IoAcquireCancelSpinLock(&OldIrql); ! 1199: ! 1200: // ! 1201: // Turn this irp back into the current write irp so ! 1202: // that it will start of any writes behind it. ! 1203: // ! 1204: ! 1205: Extension->CurrentWriteIrp = Extension->CurrentXoffIrp; ! 1206: ! 1207: SerialTryToCompleteCurrent( ! 1208: Extension, ! 1209: NULL, ! 1210: OldIrql, ! 1211: STATUS_SUCCESS, ! 1212: &Extension->CurrentWriteIrp, ! 1213: &Extension->WriteQueue, ! 1214: NULL, ! 1215: &Extension->XoffCountTimer, ! 1216: SerialStartWrite, ! 1217: SerialGetNextWrite ! 1218: ); ! 1219: ! 1220: } ! 1221: ! 1222: VOID ! 1223: SerialTimeoutXoff( ! 1224: IN PKDPC Dpc, ! 1225: IN PVOID DeferredContext, ! 1226: IN PVOID SystemContext1, ! 1227: IN PVOID SystemContext2 ! 1228: ) ! 1229: ! 1230: /*++ ! 1231: ! 1232: Routine Description: ! 1233: ! 1234: This routine is merely used to truely complete an xoff counter irp, ! 1235: if its timer has run out. ! 1236: ! 1237: Arguments: ! 1238: ! 1239: Dpc - Not Used. ! 1240: ! 1241: DeferredContext - Really points to the device extension. ! 1242: ! 1243: SystemContext1 - Not Used. ! 1244: ! 1245: SystemContext2 - Not Used. ! 1246: ! 1247: Return Value: ! 1248: ! 1249: None. ! 1250: ! 1251: --*/ ! 1252: ! 1253: { ! 1254: ! 1255: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext; ! 1256: KIRQL OldIrql; ! 1257: ! 1258: UNREFERENCED_PARAMETER(Dpc); ! 1259: UNREFERENCED_PARAMETER(SystemContext1); ! 1260: UNREFERENCED_PARAMETER(SystemContext2); ! 1261: ! 1262: IoAcquireCancelSpinLock(&OldIrql); ! 1263: ! 1264: // ! 1265: // Turn this irp back into the current write irp so ! 1266: // that it will start of any writes behind it. ! 1267: // ! 1268: ! 1269: Extension->CurrentWriteIrp = Extension->CurrentXoffIrp; ! 1270: ! 1271: SerialTryToCompleteCurrent( ! 1272: Extension, ! 1273: SerialGrabXoffFromIsr, ! 1274: OldIrql, ! 1275: STATUS_SERIAL_COUNTER_TIMEOUT, ! 1276: &Extension->CurrentWriteIrp, ! 1277: &Extension->WriteQueue, ! 1278: NULL, ! 1279: &Extension->XoffCountTimer, ! 1280: SerialStartWrite, ! 1281: SerialGetNextWrite ! 1282: ); ! 1283: ! 1284: } ! 1285: ! 1286: VOID ! 1287: SerialCancelCurrentXoff( ! 1288: PDEVICE_OBJECT DeviceObject, ! 1289: PIRP Irp ! 1290: ) ! 1291: ! 1292: /*++ ! 1293: ! 1294: Routine Description: ! 1295: ! 1296: This routine is used to cancel the current write. ! 1297: ! 1298: Arguments: ! 1299: ! 1300: DeviceObject - Pointer to the device object for this device ! 1301: ! 1302: Irp - Pointer to the IRP to be canceled. ! 1303: ! 1304: Return Value: ! 1305: ! 1306: None. ! 1307: ! 1308: --*/ ! 1309: ! 1310: { ! 1311: ! 1312: PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension; ! 1313: ! 1314: // ! 1315: // Turn this irp back into the current write irp so ! 1316: // that it will start of any writes behind it. ! 1317: // ! 1318: ! 1319: Extension->CurrentWriteIrp = Extension->CurrentXoffIrp; ! 1320: ! 1321: SerialTryToCompleteCurrent( ! 1322: Extension, ! 1323: SerialGrabXoffFromIsr, ! 1324: Irp->CancelIrql, ! 1325: STATUS_CANCELLED, ! 1326: &Extension->CurrentWriteIrp, ! 1327: &Extension->WriteQueue, ! 1328: NULL, ! 1329: &Extension->XoffCountTimer, ! 1330: SerialStartWrite, ! 1331: SerialGetNextWrite ! 1332: ); ! 1333: ! 1334: } ! 1335: ! 1336: BOOLEAN ! 1337: SerialGiveXoffToIsr( ! 1338: IN PVOID Context ! 1339: ) ! 1340: ! 1341: /*++ ! 1342: ! 1343: Routine Description: ! 1344: ! 1345: ! 1346: This routine starts off the xoff counter. It merely ! 1347: has to set the xoff count and increment the reference ! 1348: count to denote that the isr has a reference to the irp. ! 1349: ! 1350: NOTE: This routine is called by KeSynchronizeExecution. ! 1351: ! 1352: NOTE: This routine assumes that it is called with the ! 1353: cancel spin lock held. ! 1354: ! 1355: Arguments: ! 1356: ! 1357: Context - Really a pointer to the device extension. ! 1358: ! 1359: Return Value: ! 1360: ! 1361: This routine always returns FALSE. ! 1362: ! 1363: --*/ ! 1364: ! 1365: { ! 1366: ! 1367: PSERIAL_DEVICE_EXTENSION Extension = Context; ! 1368: ! 1369: // ! 1370: // The current stack location. This contains all of the ! 1371: // information we need to process this particular request. ! 1372: // ! 1373: PSERIAL_XOFF_COUNTER Xc = ! 1374: Extension->CurrentXoffIrp->AssociatedIrp.SystemBuffer; ! 1375: ! 1376: Extension->CountSinceXoff = Xc->Counter; ! 1377: ! 1378: // ! 1379: // The isr now has a reference to the irp. ! 1380: // ! 1381: ! 1382: SERIAL_INC_REFERENCE(Extension->CurrentXoffIrp); ! 1383: ! 1384: return FALSE; ! 1385: ! 1386: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.