|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: openclos.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains the code that is very specific to ! 12: opening, closing, and cleaning up 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: BOOLEAN ! 34: SerialMarkOpen( ! 35: IN PVOID Context ! 36: ); ! 37: ! 38: BOOLEAN ! 39: SerialCheckOpen( ! 40: IN PVOID Context ! 41: ); ! 42: ! 43: typedef struct _SERIAL_CHECK_OPEN { ! 44: PSERIAL_DEVICE_EXTENSION Extension; ! 45: NTSTATUS *StatusOfOpen; ! 46: } SERIAL_CHECK_OPEN,*PSERIAL_CHECK_OPEN; ! 47: ! 48: // ! 49: // Just a bogus little routine to make sure that we ! 50: // can synch with the ISR. ! 51: // ! 52: BOOLEAN ! 53: SerialNullSynch( ! 54: IN PVOID Context ! 55: ) { ! 56: ! 57: UNREFERENCED_PARAMETER(Context); ! 58: return FALSE; ! 59: } ! 60: ! 61: NTSTATUS ! 62: SerialCreateOpen( ! 63: IN PDEVICE_OBJECT DeviceObject, ! 64: IN PIRP Irp ! 65: ) ! 66: ! 67: /*++ ! 68: ! 69: Routine Description: ! 70: ! 71: We connect up to the interrupt for the create/open and initialize ! 72: the structures needed to maintain an open for a device. ! 73: ! 74: Arguments: ! 75: ! 76: DeviceObject - Pointer to the device object for this device ! 77: ! 78: Irp - Pointer to the IRP for the current request ! 79: ! 80: Return Value: ! 81: ! 82: The function value is the final status of the call ! 83: ! 84: --*/ ! 85: ! 86: { ! 87: ! 88: PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension; ! 89: SERIAL_CHECK_OPEN checkOpen; ! 90: NTSTATUS localStatus; ! 91: ! 92: SerialDump( ! 93: SERIRPPATH, ! 94: ("SERIAL: Dispatch entry for: %x\n",Irp) ! 95: ); ! 96: SerialDump( ! 97: SERDIAG3, ! 98: ("SERIAL: In SerialCreateOpen\n") ! 99: ); ! 100: ! 101: // ! 102: // Before we do anything, let's make sure they aren't trying ! 103: // to create a directory. This is a silly, but what's a driver to do!? ! 104: // ! 105: ! 106: if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Create.Options & ! 107: FILE_DIRECTORY_FILE) { ! 108: ! 109: Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY; ! 110: Irp->IoStatus.Information = 0; ! 111: ! 112: SerialDump( ! 113: SERIRPPATH, ! 114: ("SERIAL: Complete Irp: %x\n",Irp) ! 115: ); ! 116: IoCompleteRequest( ! 117: Irp, ! 118: IO_NO_INCREMENT ! 119: ); ! 120: return STATUS_NOT_A_DIRECTORY; ! 121: ! 122: } ! 123: ! 124: // ! 125: // Create a buffer for the RX data when no reads are outstanding. ! 126: // ! 127: ! 128: extension->InterruptReadBuffer = NULL; ! 129: extension->BufferSize = 0; ! 130: ! 131: switch (MmQuerySystemSize()) { ! 132: ! 133: case MmLargeSystem: { ! 134: ! 135: extension->BufferSize = 4096; ! 136: extension->InterruptReadBuffer = ExAllocatePool( ! 137: NonPagedPool, ! 138: extension->BufferSize ! 139: ); ! 140: ! 141: if (extension->InterruptReadBuffer) { ! 142: ! 143: break; ! 144: ! 145: } ! 146: ! 147: } ! 148: ! 149: case MmMediumSystem: { ! 150: ! 151: extension->BufferSize = 1024; ! 152: extension->InterruptReadBuffer = ExAllocatePool( ! 153: NonPagedPool, ! 154: extension->BufferSize ! 155: ); ! 156: ! 157: if (extension->InterruptReadBuffer) { ! 158: ! 159: break; ! 160: ! 161: } ! 162: ! 163: } ! 164: ! 165: case MmSmallSystem: { ! 166: ! 167: extension->BufferSize = 128; ! 168: extension->InterruptReadBuffer = ExAllocatePool( ! 169: NonPagedPool, ! 170: extension->BufferSize ! 171: ); ! 172: ! 173: } ! 174: ! 175: } ! 176: ! 177: if (!extension->InterruptReadBuffer) { ! 178: ! 179: extension->BufferSize = 0; ! 180: Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; ! 181: Irp->IoStatus.Information = 0; ! 182: ! 183: SerialDump( ! 184: SERIRPPATH, ! 185: ("SERIAL: Complete Irp: %x\n",Irp) ! 186: ); ! 187: IoCompleteRequest( ! 188: Irp, ! 189: IO_NO_INCREMENT ! 190: ); ! 191: return STATUS_INSUFFICIENT_RESOURCES; ! 192: ! 193: } ! 194: ! 195: // ! 196: // On a new open we "flush" the read queue by initializing the ! 197: // count of characters. ! 198: // ! 199: ! 200: extension->CharsInInterruptBuffer = 0; ! 201: extension->LastCharSlot = extension->InterruptReadBuffer + ! 202: (extension->BufferSize - 1); ! 203: ! 204: extension->ReadBufferBase = extension->InterruptReadBuffer; ! 205: extension->CurrentCharSlot = extension->InterruptReadBuffer; ! 206: extension->FirstReadableChar = extension->InterruptReadBuffer; ! 207: ! 208: extension->TotalCharsQueued = 0; ! 209: ! 210: // ! 211: // We set up the default xon/xoff limits. ! 212: // ! 213: ! 214: extension->HandFlow.XoffLimit = extension->BufferSize >> 3; ! 215: extension->HandFlow.XonLimit = extension->BufferSize >> 1; ! 216: ! 217: extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+ ! 218: (extension->BufferSize>>4)); ! 219: ! 220: extension->IrpMaskLocation = NULL; ! 221: extension->HistoryMask = 0; ! 222: extension->IsrWaitMask = 0; ! 223: ! 224: extension->SendXonChar = FALSE; ! 225: extension->SendXoffChar = FALSE; ! 226: ! 227: // ! 228: // The escape char replacement must be reset upon every open. ! 229: // ! 230: ! 231: extension->EscapeChar = 0; ! 232: ! 233: #if !defined(SERIAL_CRAZY_INTERRUPTS) ! 234: ! 235: if (!extension->InterruptShareable) { ! 236: ! 237: checkOpen.Extension = extension; ! 238: checkOpen.StatusOfOpen = &Irp->IoStatus.Status; ! 239: ! 240: KeSynchronizeExecution( ! 241: extension->Interrupt, ! 242: SerialCheckOpen, ! 243: &checkOpen ! 244: ); ! 245: ! 246: } else { ! 247: ! 248: KeSynchronizeExecution( ! 249: extension->Interrupt, ! 250: SerialMarkOpen, ! 251: extension ! 252: ); ! 253: ! 254: Irp->IoStatus.Status = STATUS_SUCCESS; ! 255: ! 256: } ! 257: #else ! 258: ! 259: // ! 260: // Synchronize with the ISR and let it know that the device ! 261: // has been successfully opened. ! 262: // ! 263: ! 264: KeSynchronizeExecution( ! 265: extension->Interrupt, ! 266: SerialMarkOpen, ! 267: extension ! 268: ); ! 269: ! 270: Irp->IoStatus.Status = STATUS_SUCCESS; ! 271: #endif ! 272: ! 273: localStatus = Irp->IoStatus.Status; ! 274: Irp->IoStatus.Information=0L; ! 275: ! 276: SerialDump( ! 277: SERIRPPATH, ! 278: ("SERIAL: Complete Irp: %x\n",Irp) ! 279: ); ! 280: IoCompleteRequest( ! 281: Irp, ! 282: IO_NO_INCREMENT ! 283: ); ! 284: ! 285: return localStatus; ! 286: ! 287: } ! 288: ! 289: NTSTATUS ! 290: SerialClose( ! 291: IN PDEVICE_OBJECT DeviceObject, ! 292: IN PIRP Irp ! 293: ) ! 294: ! 295: /*++ ! 296: ! 297: Routine Description: ! 298: ! 299: We simpley disconnect the interrupt for now. ! 300: ! 301: Arguments: ! 302: ! 303: DeviceObject - Pointer to the device object for this device ! 304: ! 305: Irp - Pointer to the IRP for the current request ! 306: ! 307: Return Value: ! 308: ! 309: The function value is the final status of the call ! 310: ! 311: --*/ ! 312: ! 313: { ! 314: ! 315: // ! 316: // This "timer value" is used to wait 10 character times ! 317: // after the hardware is empty before we actually "run down" ! 318: // all of the flow control/break junk. ! 319: // ! 320: LARGE_INTEGER tenCharDelay; ! 321: ! 322: // ! 323: // Holds a character time. ! 324: // ! 325: LARGE_INTEGER charTime; ! 326: ! 327: // ! 328: // Just what it says. This is the serial specific device ! 329: // extension of the device object create for the serial driver. ! 330: // ! 331: PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension; ! 332: ! 333: SerialDump( ! 334: SERIRPPATH, ! 335: ("SERIAL: Dispatch entry for: %x\n",Irp) ! 336: ); ! 337: SerialDump( ! 338: SERDIAG3, ! 339: ("SERIAL: In SerialClose\n") ! 340: ); ! 341: ! 342: charTime = RtlLargeIntegerNegate(SerialGetCharTime(extension)); ! 343: ! 344: // ! 345: // Synchronize with the ISR to let it know that interrupts are ! 346: // no longer important. ! 347: // ! 348: ! 349: KeSynchronizeExecution( ! 350: extension->Interrupt, ! 351: SerialMarkClose, ! 352: extension ! 353: ); ! 354: ! 355: // ! 356: // Synchronize with the isr to turn off break if it ! 357: // is already on. ! 358: // ! 359: ! 360: KeSynchronizeExecution( ! 361: extension->Interrupt, ! 362: SerialTurnOffBreak, ! 363: extension ! 364: ); ! 365: ! 366: // ! 367: // If the driver has automatically transmitted an Xoff in ! 368: // the context of automatic receive flow control then we ! 369: // should transmit an Xon. ! 370: // ! 371: ! 372: if (extension->RXHolding & SERIAL_RX_XOFF) { ! 373: ! 374: // ! 375: // Loop until the holding register is empty. ! 376: // ! 377: ! 378: while (!(READ_LINE_STATUS(extension->Controller) & ! 379: SERIAL_LSR_THRE)) { ! 380: ! 381: KeDelayExecutionThread( ! 382: KernelMode, ! 383: FALSE, ! 384: &charTime ! 385: ); ! 386: ! 387: } ! 388: ! 389: WRITE_TRANSMIT_HOLDING( ! 390: extension->Controller, ! 391: extension->SpecialChars.XonChar ! 392: ); ! 393: ! 394: } ! 395: ! 396: // ! 397: // Wait until all characters have been emptied out of the hardware. ! 398: // ! 399: ! 400: while ((READ_LINE_STATUS(extension->Controller) & ! 401: (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) != ! 402: (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) { ! 403: ! 404: KeDelayExecutionThread( ! 405: KernelMode, ! 406: FALSE, ! 407: &charTime ! 408: ); ! 409: ! 410: } ! 411: ! 412: // ! 413: // The hardware is empty. Delay 10 character times before ! 414: // shut down all the flow control. ! 415: // ! 416: ! 417: tenCharDelay = RtlExtendedIntegerMultiply( ! 418: charTime, ! 419: 10 ! 420: ); ! 421: ! 422: KeDelayExecutionThread( ! 423: KernelMode, ! 424: TRUE, ! 425: &tenCharDelay ! 426: ); ! 427: ! 428: SerialClrDTR(extension); ! 429: ! 430: // ! 431: // We have to be very careful how we clear the RTS line. ! 432: // Transmit toggling might have been on at some point. ! 433: // ! 434: // We know that there is nothing left that could start ! 435: // out the "polling" execution path. We need to ! 436: // check the counter that indicates that the execution ! 437: // path is active. If it is then we loop delaying one ! 438: // character time. After each delay we check to see if ! 439: // the counter has gone to zero. When it has we know that ! 440: // the execution path should be just about finished. We ! 441: // make sure that we still aren't in the routine that ! 442: // synchronized execution with the ISR by synchronizing ! 443: // ourselve with the ISR. ! 444: // ! 445: ! 446: if (extension->CountOfTryingToLowerRTS) { ! 447: ! 448: do { ! 449: ! 450: KeDelayExecutionThread( ! 451: KernelMode, ! 452: FALSE, ! 453: &charTime ! 454: ); ! 455: ! 456: } while (extension->CountOfTryingToLowerRTS); ! 457: ! 458: KeSynchronizeExecution( ! 459: extension->Interrupt, ! 460: SerialNullSynch, ! 461: NULL ! 462: ); ! 463: ! 464: // ! 465: // The execution path should no longer exist that ! 466: // is trying to push down the RTS. Well just ! 467: // make sure it's down by falling through to ! 468: // code that forces it down. ! 469: // ! 470: ! 471: } ! 472: ! 473: SerialClrRTS(extension); ! 474: ! 475: // ! 476: // Clean out the holding reasons (since we are closed). ! 477: // ! 478: ! 479: extension->RXHolding = 0; ! 480: extension->TXHolding = 0; ! 481: ! 482: // ! 483: // All is done. The port has been disabled from interrupting ! 484: // so there is no point in keeping the memory around. ! 485: // ! 486: ! 487: extension->BufferSize = 0; ! 488: ExFreePool(extension->InterruptReadBuffer); ! 489: extension->InterruptReadBuffer = NULL; ! 490: ! 491: Irp->IoStatus.Status = STATUS_SUCCESS; ! 492: Irp->IoStatus.Information=0L; ! 493: ! 494: SerialDump( ! 495: SERIRPPATH, ! 496: ("SERIAL: Complete Irp: %x\n",Irp) ! 497: ); ! 498: IoCompleteRequest( ! 499: Irp, ! 500: IO_NO_INCREMENT ! 501: ); ! 502: ! 503: return STATUS_SUCCESS; ! 504: ! 505: } ! 506: ! 507: BOOLEAN ! 508: SerialCheckOpen( ! 509: IN PVOID Context ! 510: ) ! 511: ! 512: /*++ ! 513: ! 514: Routine Description: ! 515: ! 516: This routine will traverse the circular doubly linked list ! 517: of devices that are using the same interrupt object. It will look ! 518: for other devices that are open. If it doesn't find any ! 519: it will indicate that it is ok to open this device. ! 520: ! 521: If it finds another device open we have two cases: ! 522: ! 523: 1) The device we are trying to open is on a multiport card. ! 524: ! 525: If the already open device is part of a multiport device ! 526: this code will indicate it is ok to open. We do this on the ! 527: theory that the multiport devices are daisy chained ! 528: and the cards can correctly arbitrate the interrupt ! 529: line. Note this assumption could be wrong. Somebody ! 530: could put two non-daisychained multiports on the ! 531: same interrupt. However, only a total clod would do ! 532: such a thing, and in my opinion deserves everthing they ! 533: get. ! 534: ! 535: 2) The device we are trying to open is not on a multiport card. ! 536: ! 537: We indicate that it is not ok to open. ! 538: ! 539: Arguments: ! 540: ! 541: Context - This is a structure that contains a pointer to the ! 542: extension of the device we are trying to open, and ! 543: a pointer to an NTSTATUS that will indicate whether ! 544: the device was opened or not. ! 545: ! 546: Return Value: ! 547: ! 548: This routine always returns FALSE. ! 549: ! 550: --*/ ! 551: ! 552: { ! 553: ! 554: PSERIAL_DEVICE_EXTENSION extensionToOpen = ! 555: ((PSERIAL_CHECK_OPEN)Context)->Extension; ! 556: NTSTATUS *status = ((PSERIAL_CHECK_OPEN)Context)->StatusOfOpen; ! 557: PLIST_ENTRY firstEntry = &extensionToOpen->CommonInterruptObject; ! 558: PLIST_ENTRY currentEntry = firstEntry; ! 559: PSERIAL_DEVICE_EXTENSION currentExtension; ! 560: ! 561: do { ! 562: ! 563: currentExtension = CONTAINING_RECORD( ! 564: currentEntry, ! 565: SERIAL_DEVICE_EXTENSION, ! 566: CommonInterruptObject ! 567: ); ! 568: ! 569: if (currentExtension->DeviceIsOpened) { ! 570: ! 571: break; ! 572: ! 573: } ! 574: ! 575: currentEntry = currentExtension->CommonInterruptObject.Flink; ! 576: ! 577: } while (currentEntry != firstEntry); ! 578: ! 579: if (currentEntry == firstEntry) { ! 580: ! 581: // ! 582: // We searched the whole list and found no other opens ! 583: // mark the status as successful and call the regular ! 584: // opening routine. ! 585: // ! 586: ! 587: *status = STATUS_SUCCESS; ! 588: SerialMarkOpen(extensionToOpen); ! 589: ! 590: } else { ! 591: ! 592: if (!extensionToOpen->PortOnAMultiportCard) { ! 593: ! 594: *status = STATUS_SHARED_IRQ_BUSY; ! 595: ! 596: } else { ! 597: ! 598: if (!currentExtension->PortOnAMultiportCard) { ! 599: ! 600: *status = STATUS_SHARED_IRQ_BUSY; ! 601: ! 602: } else { ! 603: ! 604: *status = STATUS_SUCCESS; ! 605: SerialMarkOpen(extensionToOpen); ! 606: ! 607: } ! 608: ! 609: } ! 610: ! 611: } ! 612: ! 613: return FALSE; ! 614: ! 615: } ! 616: ! 617: BOOLEAN ! 618: SerialMarkOpen( ! 619: IN PVOID Context ! 620: ) ! 621: ! 622: /*++ ! 623: ! 624: Routine Description: ! 625: ! 626: This routine merely sets a boolean to true to mark the fact that ! 627: somebody opened the device and its worthwhile to pay attention ! 628: to interrupts. ! 629: ! 630: Arguments: ! 631: ! 632: Context - Really a pointer to the device extension. ! 633: ! 634: Return Value: ! 635: ! 636: This routine always returns FALSE. ! 637: ! 638: --*/ ! 639: ! 640: { ! 641: ! 642: PSERIAL_DEVICE_EXTENSION extension = Context; ! 643: ! 644: SerialReset(extension); ! 645: ! 646: // ! 647: // Prepare for the opening by re-enabling interrupts. ! 648: // ! 649: // We do this my modifying the OUT2 line in the modem control. ! 650: // In PC's this bit is "anded" with the interrupt line. ! 651: // ! 652: // For the Jensen, we will ALWAYS leave the line high. That's ! 653: // the way the hardware engineers want it. ! 654: // ! 655: ! 656: WRITE_MODEM_CONTROL( ! 657: extension->Controller, ! 658: (UCHAR)(READ_MODEM_CONTROL(extension->Controller) | SERIAL_MCR_OUT2) ! 659: ); ! 660: ! 661: extension->DeviceIsOpened = TRUE; ! 662: extension->ErrorWord = 0; ! 663: ! 664: return FALSE; ! 665: ! 666: } ! 667: ! 668: BOOLEAN ! 669: SerialMarkClose( ! 670: IN PVOID Context ! 671: ) ! 672: ! 673: /*++ ! 674: ! 675: Routine Description: ! 676: ! 677: This routine merely sets a boolean to false to mark the fact that ! 678: somebody closed the device and it's no longer worthwhile to pay attention ! 679: to interrupts. ! 680: ! 681: Arguments: ! 682: ! 683: Context - Really a pointer to the device extension. ! 684: ! 685: Return Value: ! 686: ! 687: This routine always returns FALSE. ! 688: ! 689: --*/ ! 690: ! 691: { ! 692: ! 693: PSERIAL_DEVICE_EXTENSION extension = Context; ! 694: ! 695: // ! 696: // Prepare for the closing by stopping interrupts. ! 697: // ! 698: // We do this by adjusting the OUT2 line in the modem control. ! 699: // In PC's this bit is "anded" with the interrupt line. ! 700: // ! 701: // The line should stay high on the Jensen because that's the ! 702: // way the hardware engineers did it. ! 703: // ! 704: ! 705: if (!extension->Jensen) { ! 706: ! 707: WRITE_MODEM_CONTROL( ! 708: extension->Controller, ! 709: (UCHAR)(READ_MODEM_CONTROL(extension->Controller) & ~SERIAL_MCR_OUT2) ! 710: ); ! 711: ! 712: } ! 713: ! 714: if (extension->FifoPresent) { ! 715: ! 716: WRITE_FIFO_CONTROL( ! 717: extension->Controller, ! 718: (UCHAR)0 ! 719: ); ! 720: ! 721: } ! 722: ! 723: extension->DeviceIsOpened = FALSE; ! 724: ! 725: return FALSE; ! 726: ! 727: } ! 728: ! 729: NTSTATUS ! 730: SerialCleanup( ! 731: IN PDEVICE_OBJECT DeviceObject, ! 732: IN PIRP Irp ! 733: ) ! 734: ! 735: /*++ ! 736: ! 737: Routine Description: ! 738: ! 739: This function is used to kill all longstanding IO operations. ! 740: ! 741: Arguments: ! 742: ! 743: DeviceObject - Pointer to the device object for this device ! 744: ! 745: Irp - Pointer to the IRP for the current request ! 746: ! 747: Return Value: ! 748: ! 749: The function value is the final status of the call ! 750: ! 751: --*/ ! 752: ! 753: { ! 754: ! 755: PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension; ! 756: KIRQL oldIrql; ! 757: ! 758: SerialDump( ! 759: SERIRPPATH, ! 760: ("SERIAL: Dispatch entry for: %x\n",Irp) ! 761: ); ! 762: // ! 763: // First kill all the reads and writes. ! 764: // ! 765: ! 766: SerialKillAllReadsOrWrites( ! 767: DeviceObject, ! 768: &extension->WriteQueue, ! 769: &extension->CurrentWriteIrp ! 770: ); ! 771: ! 772: SerialKillAllReadsOrWrites( ! 773: DeviceObject, ! 774: &extension->ReadQueue, ! 775: &extension->CurrentReadIrp ! 776: ); ! 777: ! 778: // ! 779: // Next get rid of purges. ! 780: // ! 781: ! 782: SerialKillAllReadsOrWrites( ! 783: DeviceObject, ! 784: &extension->PurgeQueue, ! 785: &extension->CurrentPurgeIrp ! 786: ); ! 787: ! 788: // ! 789: // Get rid of any mask operations. ! 790: // ! 791: ! 792: SerialKillAllReadsOrWrites( ! 793: DeviceObject, ! 794: &extension->MaskQueue, ! 795: &extension->CurrentMaskIrp ! 796: ); ! 797: ! 798: // ! 799: // Now get rid a pending wait mask irp. ! 800: // ! 801: ! 802: IoAcquireCancelSpinLock(&oldIrql); ! 803: ! 804: if (extension->CurrentWaitIrp) { ! 805: ! 806: PDRIVER_CANCEL cancelRoutine; ! 807: ! 808: cancelRoutine = extension->CurrentWaitIrp->CancelRoutine; ! 809: extension->CurrentWaitIrp->Cancel = TRUE; ! 810: ! 811: if (cancelRoutine) { ! 812: ! 813: extension->CurrentWaitIrp->CancelIrql = oldIrql; ! 814: extension->CurrentWaitIrp->CancelRoutine = NULL; ! 815: ! 816: cancelRoutine( ! 817: DeviceObject, ! 818: extension->CurrentWaitIrp ! 819: ); ! 820: ! 821: } ! 822: ! 823: } else { ! 824: ! 825: IoReleaseCancelSpinLock(oldIrql); ! 826: ! 827: } ! 828: ! 829: Irp->IoStatus.Status = STATUS_SUCCESS; ! 830: Irp->IoStatus.Information=0L; ! 831: ! 832: SerialDump( ! 833: SERIRPPATH, ! 834: ("SERIAL: Complete Irp: %x\n",Irp) ! 835: ); ! 836: IoCompleteRequest( ! 837: Irp, ! 838: IO_NO_INCREMENT ! 839: ); ! 840: ! 841: return STATUS_SUCCESS; ! 842: ! 843: } ! 844: ! 845: LARGE_INTEGER ! 846: SerialGetCharTime( ! 847: IN PSERIAL_DEVICE_EXTENSION Extension ! 848: ) ! 849: ! 850: /*++ ! 851: ! 852: Routine Description: ! 853: ! 854: This function will return the number of 100 nanosecond intervals ! 855: there are in one character time (based on the present form ! 856: of flow control. ! 857: ! 858: Arguments: ! 859: ! 860: Extension - Just what it says. ! 861: ! 862: Return Value: ! 863: ! 864: 100 nanosecond intervals in a character time. ! 865: ! 866: --*/ ! 867: ! 868: { ! 869: ! 870: ULONG dataSize; ! 871: ULONG paritySize; ! 872: ULONG stopSize; ! 873: ULONG charTime; ! 874: ULONG bitTime; ! 875: ! 876: ! 877: if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) { ! 878: dataSize = 5; ! 879: } else if ((Extension->LineControl & SERIAL_DATA_MASK) ! 880: == SERIAL_6_DATA) { ! 881: dataSize = 6; ! 882: } else if ((Extension->LineControl & SERIAL_DATA_MASK) ! 883: == SERIAL_7_DATA) { ! 884: dataSize = 7; ! 885: } else if ((Extension->LineControl & SERIAL_DATA_MASK) ! 886: == SERIAL_8_DATA) { ! 887: dataSize = 8; ! 888: } ! 889: ! 890: paritySize = 1; ! 891: if ((Extension->LineControl & SERIAL_PARITY_MASK) ! 892: == SERIAL_NONE_PARITY) { ! 893: ! 894: paritySize = 0; ! 895: ! 896: } ! 897: ! 898: if (Extension->LineControl & SERIAL_2_STOP) { ! 899: ! 900: // ! 901: // Even if it is 1.5, for sanities sake were going ! 902: // to say 2. ! 903: // ! 904: ! 905: stopSize = 2; ! 906: ! 907: } else { ! 908: ! 909: stopSize = 1; ! 910: ! 911: } ! 912: ! 913: // ! 914: // First we calculate the number of 100 nanosecond intervals ! 915: // are in a single bit time (Approximately). ! 916: // ! 917: ! 918: bitTime = (10000000+(Extension->CurrentBaud-1))/Extension->CurrentBaud; ! 919: charTime = bitTime + ((dataSize+paritySize+stopSize)*bitTime); ! 920: ! 921: return RtlConvertUlongToLargeInteger(charTime); ! 922: ! 923: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.