Annotation of ntddk/src/comm/serial/write.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.