|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: immediat.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains the code that is very specific to transmit ! 12: immediate character 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: VOID ! 33: SerialGetNextImmediate( ! 34: IN PIRP *CurrentOpIrp, ! 35: IN PLIST_ENTRY QueueToProcess, ! 36: IN PIRP *NewIrp, ! 37: IN BOOLEAN CompleteCurrent ! 38: ); ! 39: ! 40: VOID ! 41: SerialCancelImmediate( ! 42: IN PDEVICE_OBJECT DeviceObject, ! 43: IN PIRP Irp ! 44: ); ! 45: ! 46: BOOLEAN ! 47: SerialGiveImmediateToIsr( ! 48: IN PVOID Context ! 49: ); ! 50: ! 51: BOOLEAN ! 52: SerialGrabImmediateFromIsr( ! 53: IN PVOID Context ! 54: ); ! 55: ! 56: BOOLEAN ! 57: SerialGiveImmediateToIsr( ! 58: IN PVOID Context ! 59: ); ! 60: ! 61: BOOLEAN ! 62: SerialGrabImmediateFromIsr( ! 63: IN PVOID Context ! 64: ); ! 65: ! 66: ! 67: VOID ! 68: SerialStartImmediate( ! 69: IN PSERIAL_DEVICE_EXTENSION Extension ! 70: ) ! 71: ! 72: /*++ ! 73: ! 74: Routine Description: ! 75: ! 76: This routine will calculate the timeouts needed for the ! 77: write. It will then hand the irp off to the isr. It ! 78: will need to be careful incase the irp has been canceled. ! 79: ! 80: Arguments: ! 81: ! 82: Extension - A pointer to the serial device extension. ! 83: ! 84: Return Value: ! 85: ! 86: None. ! 87: ! 88: --*/ ! 89: ! 90: { ! 91: ! 92: KIRQL OldIrql; ! 93: LARGE_INTEGER TotalTime; ! 94: BOOLEAN UseATimer; ! 95: SERIAL_TIMEOUTS Timeouts; ! 96: ! 97: ! 98: UseATimer = FALSE; ! 99: Extension->CurrentImmediateIrp->IoStatus.Status = STATUS_PENDING; ! 100: IoMarkIrpPending(Extension->CurrentImmediateIrp); ! 101: ! 102: // ! 103: // Calculate the timeout value needed for the ! 104: // request. Note that the values stored in the ! 105: // timeout record are in milliseconds. Note that ! 106: // if the timeout values are zero then we won't start ! 107: // the timer. ! 108: // ! 109: ! 110: KeAcquireSpinLock( ! 111: &Extension->ControlLock, ! 112: &OldIrql ! 113: ); ! 114: ! 115: Timeouts = Extension->Timeouts; ! 116: ! 117: KeReleaseSpinLock( ! 118: &Extension->ControlLock, ! 119: OldIrql ! 120: ); ! 121: ! 122: if (Timeouts.WriteTotalTimeoutConstant || ! 123: Timeouts.WriteTotalTimeoutMultiplier) { ! 124: ! 125: UseATimer = TRUE; ! 126: ! 127: // ! 128: // We have some timer values to calculate. ! 129: // ! 130: ! 131: TotalTime = RtlEnlargedUnsignedMultiply( ! 132: 1, ! 133: Timeouts.WriteTotalTimeoutMultiplier ! 134: ); ! 135: ! 136: TotalTime = RtlLargeIntegerAdd( ! 137: TotalTime, ! 138: RtlConvertUlongToLargeInteger( ! 139: Timeouts.WriteTotalTimeoutConstant ! 140: ) ! 141: ); ! 142: ! 143: TotalTime = RtlExtendedIntegerMultiply( ! 144: TotalTime, ! 145: -10000 ! 146: ); ! 147: ! 148: } ! 149: ! 150: // ! 151: // As the irp might be going to the isr, this is a good time ! 152: // to initialize the reference count. ! 153: // ! 154: ! 155: SERIAL_INIT_REFERENCE(Extension->CurrentImmediateIrp); ! 156: ! 157: // ! 158: // We need to see if this irp should be canceled. ! 159: // ! 160: ! 161: IoAcquireCancelSpinLock(&OldIrql); ! 162: if (Extension->CurrentImmediateIrp->Cancel) { ! 163: ! 164: PIRP OldIrp = Extension->CurrentImmediateIrp; ! 165: ! 166: Extension->CurrentImmediateIrp = NULL; ! 167: IoReleaseCancelSpinLock(OldIrql); ! 168: ! 169: OldIrp->IoStatus.Status = STATUS_CANCELLED; ! 170: OldIrp->IoStatus.Information = 0; ! 171: ! 172: SerialDump( ! 173: SERIRPPATH, ! 174: ("SERIAL: Complete Irp: %x\n",OldIrp) ! 175: ); ! 176: IoCompleteRequest( ! 177: OldIrp, ! 178: 0 ! 179: ); ! 180: ! 181: } else { ! 182: ! 183: // ! 184: // We give the irp to to the isr to write out. ! 185: // We set a cancel routine that knows how to ! 186: // grab the current write away from the isr. ! 187: // ! 188: ! 189: IoSetCancelRoutine( ! 190: Extension->CurrentImmediateIrp, ! 191: SerialCancelImmediate ! 192: ); ! 193: ! 194: // ! 195: // Since the cancel routine knows about the irp we ! 196: // increment the reference count. ! 197: // ! 198: ! 199: SERIAL_INC_REFERENCE(Extension->CurrentImmediateIrp); ! 200: ! 201: if (UseATimer) { ! 202: ! 203: KeSetTimer( ! 204: &Extension->ImmediateTotalTimer, ! 205: TotalTime, ! 206: &Extension->TotalImmediateTimeoutDpc ! 207: ); ! 208: ! 209: // ! 210: // Since the timer knows about the irp we increment ! 211: // the reference count. ! 212: // ! 213: ! 214: SERIAL_INC_REFERENCE(Extension->CurrentImmediateIrp); ! 215: ! 216: } ! 217: ! 218: KeSynchronizeExecution( ! 219: Extension->Interrupt, ! 220: SerialGiveImmediateToIsr, ! 221: Extension ! 222: ); ! 223: ! 224: IoReleaseCancelSpinLock(OldIrql); ! 225: ! 226: } ! 227: ! 228: } ! 229: ! 230: VOID ! 231: SerialCompleteImmediate( ! 232: IN PKDPC Dpc, ! 233: IN PVOID DeferredContext, ! 234: IN PVOID SystemContext1, ! 235: IN PVOID SystemContext2 ! 236: ) ! 237: ! 238: { ! 239: ! 240: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext; ! 241: KIRQL OldIrql; ! 242: ! 243: UNREFERENCED_PARAMETER(Dpc); ! 244: UNREFERENCED_PARAMETER(SystemContext1); ! 245: UNREFERENCED_PARAMETER(SystemContext2); ! 246: ! 247: IoAcquireCancelSpinLock(&OldIrql); ! 248: ! 249: SerialTryToCompleteCurrent( ! 250: Extension, ! 251: NULL, ! 252: OldIrql, ! 253: STATUS_SUCCESS, ! 254: &Extension->CurrentImmediateIrp, ! 255: NULL, ! 256: NULL, ! 257: &Extension->ImmediateTotalTimer, ! 258: NULL, ! 259: SerialGetNextImmediate ! 260: ); ! 261: ! 262: } ! 263: ! 264: VOID ! 265: SerialTimeoutImmediate( ! 266: IN PKDPC Dpc, ! 267: IN PVOID DeferredContext, ! 268: IN PVOID SystemContext1, ! 269: IN PVOID SystemContext2 ! 270: ) ! 271: ! 272: { ! 273: ! 274: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext; ! 275: KIRQL OldIrql; ! 276: ! 277: UNREFERENCED_PARAMETER(Dpc); ! 278: UNREFERENCED_PARAMETER(SystemContext1); ! 279: UNREFERENCED_PARAMETER(SystemContext2); ! 280: ! 281: IoAcquireCancelSpinLock(&OldIrql); ! 282: ! 283: SerialTryToCompleteCurrent( ! 284: Extension, ! 285: SerialGrabImmediateFromIsr, ! 286: OldIrql, ! 287: STATUS_TIMEOUT, ! 288: &Extension->CurrentImmediateIrp, ! 289: NULL, ! 290: NULL, ! 291: &Extension->ImmediateTotalTimer, ! 292: NULL, ! 293: SerialGetNextImmediate ! 294: ); ! 295: ! 296: } ! 297: ! 298: VOID ! 299: SerialGetNextImmediate( ! 300: IN PIRP *CurrentOpIrp, ! 301: IN PLIST_ENTRY QueueToProcess, ! 302: IN PIRP *NewIrp, ! 303: IN BOOLEAN CompleteCurrent ! 304: ) ! 305: ! 306: /*++ ! 307: ! 308: Routine Description: ! 309: ! 310: This routine is used to complete the current immediate ! 311: irp. Even though the current immediate will always ! 312: be completed and there is no queue associated with it, ! 313: we use this routine so that we can try to satisfy ! 314: a wait for transmit queue empty event. ! 315: ! 316: Arguments: ! 317: ! 318: CurrentOpIrp - Pointer to the pointer that points to the ! 319: current write irp. This should point ! 320: to CurrentImmediateIrp. ! 321: ! 322: QueueToProcess - Always NULL. ! 323: ! 324: NewIrp - Always NULL on exit to this routine. ! 325: ! 326: CompleteCurrent - Should always be true for this routine. ! 327: ! 328: ! 329: Return Value: ! 330: ! 331: None. ! 332: ! 333: --*/ ! 334: ! 335: { ! 336: ! 337: KIRQL OldIrql; ! 338: PSERIAL_DEVICE_EXTENSION Extension = CONTAINING_RECORD( ! 339: CurrentOpIrp, ! 340: SERIAL_DEVICE_EXTENSION, ! 341: CurrentImmediateIrp ! 342: ); ! 343: PIRP OldIrp = *CurrentOpIrp; ! 344: ! 345: UNREFERENCED_PARAMETER(QueueToProcess); ! 346: UNREFERENCED_PARAMETER(CompleteCurrent); ! 347: ! 348: IoAcquireCancelSpinLock(&OldIrql); ! 349: ! 350: ASSERT(Extension->TotalCharsQueued >= 1); ! 351: Extension->TotalCharsQueued--; ! 352: ! 353: *CurrentOpIrp = NULL; ! 354: *NewIrp = NULL; ! 355: KeSynchronizeExecution( ! 356: Extension->Interrupt, ! 357: SerialProcessEmptyTransmit, ! 358: Extension ! 359: ); ! 360: IoReleaseCancelSpinLock(OldIrql); ! 361: ! 362: SerialDump( ! 363: SERIRPPATH, ! 364: ("SERIAL: Complete Irp: %x\n",OldIrp) ! 365: ); ! 366: IoCompleteRequest( ! 367: OldIrp, ! 368: IO_SERIAL_INCREMENT ! 369: ); ! 370: ! 371: } ! 372: ! 373: VOID ! 374: SerialCancelImmediate( ! 375: IN PDEVICE_OBJECT DeviceObject, ! 376: IN PIRP Irp ! 377: ) ! 378: ! 379: /*++ ! 380: ! 381: Routine Description: ! 382: ! 383: This routine is used to cancel a irp that is waiting on ! 384: a comm event. ! 385: ! 386: Arguments: ! 387: ! 388: DeviceObject - Pointer to the device object for this device ! 389: ! 390: Irp - Pointer to the IRP for the current request ! 391: ! 392: Return Value: ! 393: ! 394: None. ! 395: ! 396: --*/ ! 397: ! 398: { ! 399: ! 400: PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension; ! 401: ! 402: SerialTryToCompleteCurrent( ! 403: Extension, ! 404: SerialGrabImmediateFromIsr, ! 405: Irp->CancelIrql, ! 406: STATUS_CANCELLED, ! 407: &Extension->CurrentImmediateIrp, ! 408: NULL, ! 409: NULL, ! 410: &Extension->ImmediateTotalTimer, ! 411: NULL, ! 412: SerialGetNextImmediate ! 413: ); ! 414: ! 415: } ! 416: ! 417: BOOLEAN ! 418: SerialGiveImmediateToIsr( ! 419: IN PVOID Context ! 420: ) ! 421: ! 422: /*++ ! 423: ! 424: Routine Description: ! 425: ! 426: Try to start off the write by slipping it in behind ! 427: a transmit immediate char, or if that isn't available ! 428: and the transmit holding register is empty, "tickle" ! 429: the UART into interrupting with a transmit buffer ! 430: empty. ! 431: ! 432: NOTE: This routine is called by KeSynchronizeExecution. ! 433: ! 434: NOTE: This routine assumes that it is called with the ! 435: cancel spin lock held. ! 436: ! 437: Arguments: ! 438: ! 439: Context - Really a pointer to the device extension. ! 440: ! 441: Return Value: ! 442: ! 443: This routine always returns FALSE. ! 444: ! 445: --*/ ! 446: ! 447: { ! 448: ! 449: PSERIAL_DEVICE_EXTENSION Extension = Context; ! 450: ! 451: Extension->TransmitImmediate = TRUE; ! 452: Extension->ImmediateChar = ! 453: *((UCHAR *) ! 454: (Extension->CurrentImmediateIrp->AssociatedIrp.SystemBuffer)); ! 455: ! 456: // ! 457: // The isr now has a reference to the irp. ! 458: // ! 459: ! 460: SERIAL_INC_REFERENCE(Extension->CurrentImmediateIrp); ! 461: ! 462: // ! 463: // Check first to see if a write is going on. If ! 464: // there is then we'll just slip in during the write. ! 465: // ! 466: ! 467: if (!Extension->WriteLength) { ! 468: ! 469: // ! 470: // If there is no normal write transmitting then we ! 471: // will "re-enable" the transmit holding register empty ! 472: // interrupt. The 8250 family of devices will always ! 473: // signal a transmit holding register empty interrupt ! 474: // *ANY* time this bit is set to one. By doing things ! 475: // this way we can simply use the normal interrupt code ! 476: // to start off this write. ! 477: // ! 478: // We've been keeping track of whether the transmit holding ! 479: // register is empty so it we only need to do this ! 480: // if the register is empty. ! 481: // ! 482: ! 483: if (Extension->HoldingEmpty) { ! 484: ! 485: DISABLE_ALL_INTERRUPTS(Extension->Controller); ! 486: ENABLE_ALL_INTERRUPTS(Extension->Controller); ! 487: ! 488: } ! 489: ! 490: } ! 491: ! 492: return FALSE; ! 493: ! 494: } ! 495: ! 496: BOOLEAN ! 497: SerialGrabImmediateFromIsr( ! 498: IN PVOID Context ! 499: ) ! 500: ! 501: /*++ ! 502: ! 503: Routine Description: ! 504: ! 505: ! 506: This routine is used to grab the current irp, which could be timing ! 507: out or canceling, from the ISR ! 508: ! 509: NOTE: This routine is being called from KeSynchronizeExecution. ! 510: ! 511: NOTE: This routine assumes that the cancel spin lock is held ! 512: when this routine is called. ! 513: ! 514: Arguments: ! 515: ! 516: Context - Really a pointer to the device extension. ! 517: ! 518: Return Value: ! 519: ! 520: Always false. ! 521: ! 522: --*/ ! 523: ! 524: { ! 525: ! 526: PSERIAL_DEVICE_EXTENSION Extension = Context; ! 527: ! 528: if (Extension->TransmitImmediate) { ! 529: ! 530: Extension->TransmitImmediate = FALSE; ! 531: ! 532: // ! 533: // Since the isr no longer references this irp, we can ! 534: // decrement it's reference count. ! 535: // ! 536: ! 537: SERIAL_DEC_REFERENCE(Extension->CurrentImmediateIrp); ! 538: ! 539: } ! 540: ! 541: return FALSE; ! 542: ! 543: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.