Annotation of ntddk/src/input/inport/i386/inpcmn.c, revision 1.1

1.1     ! root        1: #if defined(i386)
        !             2: 
        !             3: /*++
        !             4: 
        !             5: Copyright (c) 1989, 1990, 1991, 1992, 1993  Microsoft Corporation
        !             6: 
        !             7: Module Name:
        !             8: 
        !             9:     inpcmn.c
        !            10: 
        !            11: Abstract:
        !            12: 
        !            13:     The common portions of the Microsoft InPort mouse port driver.
        !            14:     This file should not require modification to support new mice 
        !            15:     that are similar to the InPort mouse.
        !            16: 
        !            17: Environment:
        !            18: 
        !            19:     Kernel mode only.
        !            20: 
        !            21: Notes:
        !            22: 
        !            23:     NOTES:  (Future/outstanding issues)
        !            24: 
        !            25:     - Powerfail not implemented.
        !            26: 
        !            27:     - IOCTL_INTERNAL_MOUSE_DISCONNECT has not been implemented.  It's not
        !            28:       needed until the class unload routine is implemented. Right now, 
        !            29:       we don't want to allow the mouse class driver to unload.
        !            30: 
        !            31:     - Consolidate duplicate code, where possible and appropriate.
        !            32: 
        !            33: Revision History:
        !            34: 
        !            35: --*/
        !            36: 
        !            37: #include "stdarg.h"
        !            38: #include "stdio.h"
        !            39: #include "string.h"
        !            40: #include "ntddk.h"
        !            41: #include "inport.h"
        !            42: #include "inplog.h"
        !            43: 
        !            44: //
        !            45: // Declare the global debug flag for this driver.
        !            46: //
        !            47: 
        !            48: #if DBG
        !            49: ULONG InportDebug = 0;
        !            50: #endif
        !            51: 
        !            52: 
        !            53: VOID
        !            54: InportErrorLogDpc(
        !            55:     IN PKDPC Dpc,
        !            56:     IN PDEVICE_OBJECT DeviceObject,
        !            57:     IN PIRP Irp,
        !            58:     IN PVOID Context
        !            59:     )
        !            60: 
        !            61: /*++
        !            62: 
        !            63: Routine Description:
        !            64: 
        !            65:     This routine runs at DISPATCH_LEVEL IRQL to log errors that are
        !            66:     discovered at IRQL > DISPATCH_LEVEL (e.g., in the ISR routine or
        !            67:     in a routine that is executed via KeSynchronizeExecution).  There
        !            68:     is not necessarily a current request associated with this condition.
        !            69: 
        !            70: Arguments:
        !            71: 
        !            72:     Dpc - Pointer to the DPC object.
        !            73: 
        !            74:     DeviceObject - Pointer to the device object.
        !            75: 
        !            76:     Irp - Not used.
        !            77: 
        !            78:     Context - Indicates type of error to log.
        !            79: 
        !            80: Return Value:
        !            81: 
        !            82:     None.
        !            83: 
        !            84: --*/
        !            85: 
        !            86: {
        !            87:     PDEVICE_EXTENSION deviceExtension;
        !            88:     PIO_ERROR_LOG_PACKET errorLogEntry;
        !            89: 
        !            90:     UNREFERENCED_PARAMETER(Dpc);
        !            91:     UNREFERENCED_PARAMETER(Irp);
        !            92: 
        !            93:     InpPrint((2, "INPORT-InportErrorLogDpc: enter\n"));
        !            94:    
        !            95:     deviceExtension = DeviceObject->DeviceExtension;
        !            96: 
        !            97:     //
        !            98:     // Log an error packet.
        !            99:     //
        !           100: 
        !           101:     errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
        !           102:                                               DeviceObject,
        !           103:                                               sizeof(IO_ERROR_LOG_PACKET)
        !           104:                                               + (2 * sizeof(ULONG))
        !           105:                                               );
        !           106:     if (errorLogEntry != NULL) {
        !           107: 
        !           108:         errorLogEntry->DumpDataSize = 2 * sizeof(ULONG);
        !           109: 
        !           110:         if ((ULONG) Context == INPORT_MOU_BUFFER_OVERFLOW) {
        !           111:             errorLogEntry->UniqueErrorValue = INPORT_ERROR_VALUE_BASE + 210;
        !           112:             errorLogEntry->DumpData[0] = sizeof(MOUSE_INPUT_DATA);
        !           113:             errorLogEntry->DumpData[1] = 
        !           114:                 deviceExtension->Configuration.MouseAttributes.InputDataQueueLength;
        !           115:         } else {
        !           116:             errorLogEntry->UniqueErrorValue = INPORT_ERROR_VALUE_BASE + 220;
        !           117:             errorLogEntry->DumpData[0] = 0;
        !           118:             errorLogEntry->DumpData[1] = 0;
        !           119:         }
        !           120: 
        !           121:         errorLogEntry->ErrorCode = (ULONG) Context;
        !           122:         errorLogEntry->SequenceNumber = 0;
        !           123:         errorLogEntry->MajorFunctionCode = 0;
        !           124:         errorLogEntry->IoControlCode = 0;
        !           125:         errorLogEntry->RetryCount = 0;
        !           126:         errorLogEntry->FinalStatus = 0;
        !           127: 
        !           128:         IoWriteErrorLogEntry(errorLogEntry);
        !           129:     }
        !           130: 
        !           131:     InpPrint((2, "INPORT-InportErrorLogDpc: exit\n"));
        !           132: 
        !           133: }
        !           134: 
        !           135: NTSTATUS
        !           136: InportFlush(
        !           137:     IN PDEVICE_OBJECT DeviceObject,
        !           138:     IN PIRP Irp
        !           139:     )
        !           140: {
        !           141:     UNREFERENCED_PARAMETER(DeviceObject);
        !           142:     UNREFERENCED_PARAMETER(Irp);
        !           143: 
        !           144:     InpPrint((2,"INPORT-InportFlush: enter\n"));
        !           145:     InpPrint((2,"INPORT-InportFlush: exit\n"));
        !           146: 
        !           147:     return(STATUS_NOT_IMPLEMENTED);
        !           148: }
        !           149: 
        !           150: NTSTATUS
        !           151: InportInternalDeviceControl(
        !           152:     IN PDEVICE_OBJECT DeviceObject,
        !           153:     IN PIRP Irp
        !           154:     )
        !           155: 
        !           156: /*++
        !           157: 
        !           158: Routine Description:
        !           159: 
        !           160:     This routine is the dispatch routine for internal device control requests.
        !           161: 
        !           162: Arguments:
        !           163: 
        !           164:     DeviceObject - Pointer to the device object.
        !           165: 
        !           166:     Irp - Pointer to the request packet.
        !           167: 
        !           168: Return Value:
        !           169: 
        !           170:     Status is returned.
        !           171: 
        !           172: --*/
        !           173: 
        !           174: {
        !           175: 
        !           176:     PIO_STACK_LOCATION irpSp;
        !           177:     PDEVICE_EXTENSION deviceExtension;
        !           178:     NTSTATUS status;
        !           179: 
        !           180:     InpPrint((2,"INPORT-InportInternalDeviceControl: enter\n"));
        !           181: 
        !           182:     //
        !           183:     // Get a pointer to the device extension.
        !           184:     //
        !           185: 
        !           186:     deviceExtension = DeviceObject->DeviceExtension;
        !           187: 
        !           188:     //
        !           189:     // Initialize the returned Information field.
        !           190:     //
        !           191: 
        !           192:     Irp->IoStatus.Information = 0;
        !           193: 
        !           194:     //
        !           195:     // Get a pointer to the current parameters for this request.  The
        !           196:     // information is contained in the current stack location.
        !           197:     //
        !           198: 
        !           199:     irpSp = IoGetCurrentIrpStackLocation(Irp);
        !           200: 
        !           201:     //
        !           202:     // Case on the device control subfunction that is being performed by the
        !           203:     // requestor.
        !           204:     //
        !           205: 
        !           206:     switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
        !           207: 
        !           208:         //
        !           209:         // Connect a mouse class device driver to the port driver.
        !           210:         //
        !           211: 
        !           212:         case IOCTL_INTERNAL_MOUSE_CONNECT:
        !           213: 
        !           214:             InpPrint((
        !           215:                 2,
        !           216:                 "INPORT-InportInternalDeviceControl: mouse connect\n"
        !           217:                 ));
        !           218: 
        !           219:             //
        !           220:             // Only allow one connection.
        !           221:             //
        !           222:             // FUTURE:  Consider allowing multiple connections, just for
        !           223:             // the sake of generality?
        !           224:             //
        !           225: 
        !           226:             if (deviceExtension->ConnectData.ClassService
        !           227:                 != NULL) {
        !           228: 
        !           229:                 InpPrint((
        !           230:                     2,
        !           231:                     "INPORT-InportInternalDeviceControl: error - already connected\n"
        !           232:                     ));
        !           233: 
        !           234:                 status = STATUS_SHARING_VIOLATION;
        !           235:                 break;
        !           236: 
        !           237:             } else 
        !           238:             if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
        !           239:                     sizeof(CONNECT_DATA)) {
        !           240: 
        !           241:                 InpPrint((
        !           242:                     2,
        !           243:                     "INPORT-InportInternalDeviceControl: error - invalid buffer length\n"
        !           244:                     ));
        !           245: 
        !           246:                 status = STATUS_INVALID_PARAMETER;
        !           247:                 break;
        !           248:             }
        !           249: 
        !           250:             //
        !           251:             // Copy the connection parameters to the device extension.
        !           252:             //
        !           253: 
        !           254:             deviceExtension->ConnectData =
        !           255:                 *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
        !           256: 
        !           257:             //
        !           258:             // Reinitialize the port input data queue synchronously.
        !           259:             //
        !           260: 
        !           261:             KeSynchronizeExecution(
        !           262:                 deviceExtension->InterruptObject,
        !           263:                 (PKSYNCHRONIZE_ROUTINE) InpInitializeDataQueue,
        !           264:                 (PVOID) deviceExtension
        !           265:                 );
        !           266: 
        !           267:             //
        !           268:             // Set the completion status.
        !           269:             //
        !           270: 
        !           271:             status = STATUS_SUCCESS;
        !           272:             break;
        !           273: 
        !           274:         //
        !           275:         // Disconnect a mouse class device driver from the port driver.
        !           276:         //
        !           277:         // NOTE: Not implemented.
        !           278:         //
        !           279: 
        !           280:         case IOCTL_INTERNAL_MOUSE_DISCONNECT:
        !           281: 
        !           282:             InpPrint((
        !           283:                 2,
        !           284:                 "INPORT-InportInternalDeviceControl: mouse disconnect\n"
        !           285:                 ));
        !           286: 
        !           287:             //
        !           288:             // Perform a mouse interrupt disable call.
        !           289:             //
        !           290: 
        !           291:             //
        !           292:             // Clear the connection parameters in the device extension.
        !           293:             // NOTE:  Must synchronize this with the mouse ISR.
        !           294:             //
        !           295:             //
        !           296:             //deviceExtension->ConnectData.ClassDeviceObject =
        !           297:             //    Null;
        !           298:             //deviceExtension->ConnectData.ClassService =
        !           299:             //    Null;
        !           300: 
        !           301:             //
        !           302:             // Set the completion status.
        !           303:             //
        !           304: 
        !           305:             status = STATUS_NOT_IMPLEMENTED;
        !           306:             break;
        !           307: 
        !           308:         //
        !           309:         // Enable mouse interrupts (mark the request pending and handle
        !           310:         // it in StartIo).
        !           311:         //
        !           312: 
        !           313:         case IOCTL_INTERNAL_MOUSE_ENABLE:
        !           314: 
        !           315:             InpPrint((
        !           316:                 2,
        !           317:                 "INPORT-InportInternalDeviceControl: mouse enable\n"
        !           318:                 ));
        !           319: 
        !           320:             status = STATUS_PENDING;
        !           321:             break;
        !           322: 
        !           323:         //
        !           324:         // Disable mouse interrupts (mark the request pending and handle
        !           325:         // it in StartIo).
        !           326:         //
        !           327: 
        !           328:         case IOCTL_INTERNAL_MOUSE_DISABLE:
        !           329: 
        !           330:             InpPrint((
        !           331:                 2,
        !           332:                 "INPORT-InportInternalDeviceControl: mouse disable\n"
        !           333:                 ));
        !           334: 
        !           335:             status = STATUS_PENDING;
        !           336:             break;
        !           337: 
        !           338:         //
        !           339:         // Query the mouse attributes.  First check for adequate buffer 
        !           340:         // length.  Then, copy the mouse attributes from the device 
        !           341:         // extension to the output buffer. 
        !           342:         //
        !           343: 
        !           344:         case IOCTL_MOUSE_QUERY_ATTRIBUTES:
        !           345: 
        !           346:             InpPrint((
        !           347:                 2,
        !           348:                 "INPORT-InportInternalDeviceControl: mouse query attributes\n"
        !           349:                 ));
        !           350: 
        !           351:             if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
        !           352:                 sizeof(MOUSE_ATTRIBUTES)) {
        !           353:                 status = STATUS_BUFFER_TOO_SMALL;
        !           354:             } else {
        !           355: 
        !           356:                 //
        !           357:                 // Copy the attributes from the DeviceExtension to the
        !           358:                 // buffer.
        !           359:                 //
        !           360: 
        !           361:                 *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
        !           362:                     deviceExtension->Configuration.MouseAttributes;
        !           363: 
        !           364:                 Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
        !           365:                 status = STATUS_SUCCESS;
        !           366:             }
        !           367: 
        !           368:             break;
        !           369: 
        !           370:         default:
        !           371: 
        !           372:             InpPrint((
        !           373:                 2,
        !           374:                 "INPORT-InportInternalDeviceControl: INVALID REQUEST\n"
        !           375:                 ));
        !           376: 
        !           377:             status = STATUS_INVALID_DEVICE_REQUEST;
        !           378:             break;
        !           379:     }
        !           380: 
        !           381:     Irp->IoStatus.Status = status;
        !           382:     if (status == STATUS_PENDING) {
        !           383:         IoMarkIrpPending(Irp);
        !           384:         IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
        !           385:     } else {
        !           386:         IoCompleteRequest(Irp, IO_NO_INCREMENT);
        !           387:     }
        !           388: 
        !           389:     InpPrint((2,"INPORT-InportInternalDeviceControl: exit\n"));
        !           390: 
        !           391:     return(status);
        !           392: 
        !           393: }
        !           394: 
        !           395: VOID
        !           396: InportIsrDpc(
        !           397:     IN PKDPC Dpc,
        !           398:     IN PDEVICE_OBJECT DeviceObject,
        !           399:     IN PIRP Irp,
        !           400:     IN PVOID Context
        !           401:     )
        !           402: 
        !           403: /*++
        !           404: 
        !           405: Routine Description:
        !           406: 
        !           407:     This routine runs at DISPATCH_LEVEL IRQL to finish processing
        !           408:     mouse interrupts.  It is queued in the mouse ISR.  The real
        !           409:     work is done via a callback to the connected mouse class driver.
        !           410: 
        !           411: Arguments:
        !           412: 
        !           413:     Dpc - Pointer to the DPC object.
        !           414: 
        !           415:     DeviceObject - Pointer to the device object.
        !           416: 
        !           417:     Irp - Pointer to the Irp.
        !           418: 
        !           419:     Context - Not used.
        !           420: 
        !           421: Return Value:
        !           422: 
        !           423:     None.
        !           424: 
        !           425: --*/
        !           426: 
        !           427: {
        !           428: 
        !           429:     PDEVICE_EXTENSION deviceExtension;
        !           430:     GET_DATA_POINTER_CONTEXT getPointerContext;
        !           431:     SET_DATA_POINTER_CONTEXT setPointerContext;
        !           432:     VARIABLE_OPERATION_CONTEXT operationContext;
        !           433:     PVOID classService;
        !           434:     PVOID classDeviceObject;
        !           435:     LONG interlockedResult;
        !           436:     BOOLEAN moreDpcProcessing;
        !           437:     ULONG dataNotConsumed = 0;
        !           438:     ULONG inputDataConsumed = 0; 
        !           439:     LARGE_INTEGER deltaTime;
        !           440: 
        !           441:     UNREFERENCED_PARAMETER(Dpc);
        !           442:     UNREFERENCED_PARAMETER(Irp);
        !           443:     UNREFERENCED_PARAMETER(Context);
        !           444: 
        !           445:     InpPrint((2, "INPORT-InportIsrDpc: enter\n"));
        !           446: 
        !           447:     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
        !           448: 
        !           449:     //
        !           450:     // Use DpcInterlockVariable to determine whether the DPC is running
        !           451:     // concurrently on another processor.  We only want one instantiation
        !           452:     // of the DPC to actually do any work.  DpcInterlockVariable is -1
        !           453:     // when no DPC is executing.  We increment it, and if the result is
        !           454:     // zero then the current instantiation is the only one executing, and it
        !           455:     // is okay to proceed.  Otherwise, we just return.
        !           456:     //
        !           457:     //
        !           458: 
        !           459:     operationContext.VariableAddress = 
        !           460:         &deviceExtension->DpcInterlockVariable;
        !           461:     operationContext.Operation = IncrementOperation;
        !           462:     operationContext.NewValue = &interlockedResult;
        !           463: 
        !           464:     KeSynchronizeExecution(
        !           465:             deviceExtension->InterruptObject,
        !           466:             (PKSYNCHRONIZE_ROUTINE) InpDpcVariableOperation,
        !           467:             (PVOID) &operationContext
        !           468:             );
        !           469: 
        !           470:     moreDpcProcessing = (interlockedResult == 0)? TRUE:FALSE;
        !           471: 
        !           472:     while (moreDpcProcessing) {
        !           473: 
        !           474:         dataNotConsumed = 0;
        !           475:         inputDataConsumed = 0;
        !           476: 
        !           477:         //
        !           478:         // Get the port InputData queue pointers synchronously.
        !           479:         //
        !           480:     
        !           481:         getPointerContext.DeviceExtension = deviceExtension;
        !           482:         setPointerContext.DeviceExtension = deviceExtension;
        !           483:         setPointerContext.InputCount = 0;
        !           484:     
        !           485:         KeSynchronizeExecution(
        !           486:             deviceExtension->InterruptObject,
        !           487:             (PKSYNCHRONIZE_ROUTINE) InpGetDataQueuePointer,
        !           488:             (PVOID) &getPointerContext
        !           489:             );
        !           490:     
        !           491:         if (getPointerContext.InputCount != 0) {
        !           492:         
        !           493:             //
        !           494:             // Call the connected class driver's callback ISR with the
        !           495:             // port InputData queue pointers.  If we have to wrap the queue,
        !           496:             // break the operation into two pieces, and call the class callback
        !           497:             // ISR once for each piece.
        !           498:             //
        !           499:         
        !           500:             classDeviceObject =
        !           501:                 deviceExtension->ConnectData.ClassDeviceObject;
        !           502:             classService =
        !           503:                 deviceExtension->ConnectData.ClassService;
        !           504:             ASSERT(classService != NULL);
        !           505:         
        !           506:             if (getPointerContext.DataOut >= getPointerContext.DataIn) {
        !           507:         
        !           508:                 //
        !           509:                 // We'll have to wrap the InputData circular buffer.  Call
        !           510:                 // the class callback ISR with the chunk of data starting at 
        !           511:                 // DataOut and ending at the end of the queue.
        !           512:                 //
        !           513:         
        !           514:                 InpPrint((
        !           515:                     2, 
        !           516:                     "INPORT-InportIsrDpc: calling class callback\n"
        !           517:                     ));
        !           518:                 InpPrint((
        !           519:                     2,
        !           520:                     "INPORT-InportIsrDpc: with Start 0x%x and End 0x%x\n",
        !           521:                     getPointerContext.DataOut,
        !           522:                     deviceExtension->DataEnd
        !           523:                     ));
        !           524:         
        !           525:                 (*(PSERVICE_CALLBACK_ROUTINE) classService)(
        !           526:                       classDeviceObject,
        !           527:                       getPointerContext.DataOut,
        !           528:                       deviceExtension->DataEnd,
        !           529:                       &inputDataConsumed
        !           530:                       );
        !           531:         
        !           532:                 dataNotConsumed = (((PUCHAR)
        !           533:                     deviceExtension->DataEnd -
        !           534:                     (PUCHAR) getPointerContext.DataOut) 
        !           535:                     / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
        !           536: 
        !           537:                 InpPrint((
        !           538:                     2,
        !           539:                     "INPORT-InportIsrDpc: (Wrap) Call callback consumed %d items, left %d\n",
        !           540:                     inputDataConsumed,
        !           541:                     dataNotConsumed
        !           542:                     ));
        !           543: 
        !           544:                 setPointerContext.InputCount += inputDataConsumed;
        !           545:         
        !           546:                 if (dataNotConsumed) {
        !           547:                     setPointerContext.DataOut = 
        !           548:                         ((PUCHAR)getPointerContext.DataOut) + 
        !           549:                         (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
        !           550:                 } else {
        !           551:                     setPointerContext.DataOut =
        !           552:                         deviceExtension->InputData;
        !           553:                     getPointerContext.DataOut = setPointerContext.DataOut;
        !           554:                 }
        !           555:             }
        !           556:         
        !           557:             //
        !           558:             // Call the class callback ISR with data remaining in the queue.
        !           559:             //
        !           560:         
        !           561:             if ((dataNotConsumed == 0) &&
        !           562:                 (inputDataConsumed < getPointerContext.InputCount)){
        !           563:                 InpPrint((
        !           564:                     2, 
        !           565:                     "INPORT-InportIsrDpc: calling class callback\n"
        !           566:                     ));
        !           567:                 InpPrint((
        !           568:                     2,
        !           569:                     "INPORT-InportIsrDpc: with Start 0x%x and End 0x%x\n",
        !           570:                     getPointerContext.DataOut,
        !           571:                     getPointerContext.DataIn
        !           572:                     ));
        !           573:         
        !           574:                 (*(PSERVICE_CALLBACK_ROUTINE) classService)(
        !           575:                       classDeviceObject,
        !           576:                       getPointerContext.DataOut,
        !           577:                       getPointerContext.DataIn,
        !           578:                       &inputDataConsumed
        !           579:                       );
        !           580: 
        !           581:                 dataNotConsumed = (((PUCHAR) getPointerContext.DataIn - 
        !           582:                       (PUCHAR) getPointerContext.DataOut)
        !           583:                       / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
        !           584:         
        !           585:                 InpPrint((
        !           586:                     2,
        !           587:                     "INPORT-InportIsrDpc: Call callback consumed %d items, left %d\n",
        !           588:                     inputDataConsumed,
        !           589:                     dataNotConsumed
        !           590:                     ));
        !           591: 
        !           592:                 setPointerContext.DataOut = 
        !           593:                     ((PUCHAR)getPointerContext.DataOut) +
        !           594:                     (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
        !           595:                 setPointerContext.InputCount += inputDataConsumed;
        !           596: 
        !           597:             }
        !           598:         
        !           599:             //
        !           600:             // Update the port InputData queue DataOut pointer and InputCount
        !           601:             // synchronously.
        !           602:             //
        !           603:         
        !           604:             KeSynchronizeExecution(
        !           605:                 deviceExtension->InterruptObject,
        !           606:                 (PKSYNCHRONIZE_ROUTINE) InpSetDataQueuePointer,
        !           607:                 (PVOID) &setPointerContext
        !           608:                 );
        !           609:         
        !           610:         }
        !           611:         
        !           612:         if (dataNotConsumed) {
        !           613: 
        !           614:             //
        !           615:             // The class driver was unable to consume all the data.  
        !           616:             // Reset the interlocked variable to -1.  We do not want
        !           617:             // to attempt to move more data to the class driver at this
        !           618:             // point, because it is already overloaded.  Need to wait a
        !           619:             // while to give the Raw Input Thread a chance to read some
        !           620:             // of the data out of the class driver's queue.  We accomplish
        !           621:             // this "wait" via a timer.
        !           622:             // 
        !           623: 
        !           624:             InpPrint((2, "INPORT-InportIsrDpc: set timer in DPC\n"));
        !           625: 
        !           626:             operationContext.Operation = WriteOperation;
        !           627:             interlockedResult = -1;
        !           628:             operationContext.NewValue = &interlockedResult;
        !           629:         
        !           630:             KeSynchronizeExecution(
        !           631:                     deviceExtension->InterruptObject,
        !           632:                     (PKSYNCHRONIZE_ROUTINE) InpDpcVariableOperation,
        !           633:                     (PVOID) &operationContext
        !           634:                     );
        !           635: 
        !           636:             deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
        !           637:             deltaTime.HighPart = -1;
        !           638: 
        !           639:             (VOID) KeSetTimer(
        !           640:                        &deviceExtension->DataConsumptionTimer,
        !           641:                        deltaTime,
        !           642:                        &deviceExtension->IsrDpcRetry
        !           643:                        );
        !           644: 
        !           645:             moreDpcProcessing = FALSE; 
        !           646: 
        !           647:         } else {
        !           648:     
        !           649:             //
        !           650:             // Decrement DpcInterlockVariable.  If the result goes negative,
        !           651:             // then we're all finished processing the DPC.  Otherwise, either
        !           652:             // the ISR incremented DpcInterlockVariable because it has more
        !           653:             // work for the ISR DPC to do, or a concurrent DPC executed on 
        !           654:             // some processor while the current DPC was running (the 
        !           655:             // concurrent DPC wouldn't have done any work).  Make sure that 
        !           656:             // the current DPC handles any extra work that is ready to be
        !           657:             // done.
        !           658:             //
        !           659: 
        !           660:             operationContext.Operation = DecrementOperation;
        !           661:             operationContext.NewValue = &interlockedResult;
        !           662:         
        !           663:             KeSynchronizeExecution(
        !           664:                     deviceExtension->InterruptObject,
        !           665:                     (PKSYNCHRONIZE_ROUTINE) InpDpcVariableOperation,
        !           666:                     (PVOID) &operationContext
        !           667:                     );
        !           668: 
        !           669:             if (interlockedResult != -1) {
        !           670: 
        !           671:                 //
        !           672:                 // The interlocked variable is still greater than or equal to
        !           673:                 // zero. Reset it to zero, so that we execute the loop one
        !           674:                 // more time (assuming no more DPCs execute and bump the
        !           675:                 // variable up again).
        !           676:                 //
        !           677: 
        !           678:                 operationContext.Operation = WriteOperation;
        !           679:                 interlockedResult = 0;
        !           680:                 operationContext.NewValue = &interlockedResult;
        !           681:         
        !           682:                 KeSynchronizeExecution(
        !           683:                     deviceExtension->InterruptObject,
        !           684:                     (PKSYNCHRONIZE_ROUTINE) InpDpcVariableOperation,
        !           685:                     (PVOID) &operationContext
        !           686:                     );
        !           687: 
        !           688:                 InpPrint((2, "INPORT-InportIsrDpc: loop in DPC\n"));
        !           689:             } else {
        !           690:                 moreDpcProcessing = FALSE;
        !           691:             }
        !           692:         }
        !           693:     }
        !           694: 
        !           695:     InpPrint((2, "INPORT-InportIsrDpc: exit\n"));
        !           696: 
        !           697: }
        !           698: 
        !           699: NTSTATUS
        !           700: InportOpenClose(
        !           701:     IN PDEVICE_OBJECT DeviceObject,
        !           702:     IN PIRP Irp
        !           703:     )
        !           704: 
        !           705: /*++
        !           706: 
        !           707: Routine Description:
        !           708: 
        !           709:     This is the dispatch routine for create/open and close requests.
        !           710:     These requests complete successfully.
        !           711: 
        !           712: Arguments:
        !           713: 
        !           714:     DeviceObject - Pointer to the device object.
        !           715: 
        !           716:     Irp - Pointer to the request packet.
        !           717: 
        !           718: Return Value:
        !           719: 
        !           720:     Status is returned.
        !           721: 
        !           722: --*/
        !           723: 
        !           724: {
        !           725: 
        !           726:     UNREFERENCED_PARAMETER(DeviceObject);
        !           727: 
        !           728:     InpPrint((3,"INPORT-InportOpenClose: enter\n"));
        !           729: 
        !           730:     //
        !           731:     // Complete the request with successful status.
        !           732:     //
        !           733: 
        !           734:     Irp->IoStatus.Status = STATUS_SUCCESS;
        !           735:     Irp->IoStatus.Information = 0;
        !           736:     IoCompleteRequest(Irp, IO_NO_INCREMENT);
        !           737: 
        !           738:     InpPrint((3,"INPORT-InportOpenClose: exit\n"));
        !           739: 
        !           740:     return(STATUS_SUCCESS);
        !           741: 
        !           742: } // end InportOpenClose
        !           743: 
        !           744: VOID
        !           745: InportStartIo(
        !           746:     IN PDEVICE_OBJECT DeviceObject,
        !           747:     IN PIRP Irp
        !           748:     )
        !           749: 
        !           750: /*++
        !           751: 
        !           752: Routine Description:
        !           753: 
        !           754:     This routine starts an I/O operation for the device.
        !           755: 
        !           756: Arguments:
        !           757: 
        !           758:     DeviceObject - Pointer to the device object.
        !           759: 
        !           760:     Irp - Pointer to the request packet.
        !           761: 
        !           762: Return Value:
        !           763: 
        !           764:     None.
        !           765: 
        !           766: --*/
        !           767: 
        !           768: {
        !           769:     PDEVICE_EXTENSION deviceExtension;
        !           770:     PIO_STACK_LOCATION irpSp;
        !           771: 
        !           772:     InpPrint((2, "INPORT-InportStartIo: enter\n"));
        !           773: 
        !           774:     deviceExtension = DeviceObject->DeviceExtension;
        !           775: 
        !           776:     //
        !           777:     // Bump the error log sequence number.
        !           778:     //
        !           779: 
        !           780:     deviceExtension->SequenceNumber += 1;
        !           781: 
        !           782:     //
        !           783:     // Get a pointer to the current parameters for this request.  The
        !           784:     // information is contained in the current stack location.
        !           785:     //
        !           786: 
        !           787:     irpSp = IoGetCurrentIrpStackLocation(Irp);
        !           788: 
        !           789:     //
        !           790:     // We know we got here with an internal device control request.  Switch
        !           791:     // on IoControlCode.
        !           792:     //
        !           793: 
        !           794:     switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
        !           795: 
        !           796:         //
        !           797:         // Enable mouse interrupts, by calling InpEnableInterrupts
        !           798:         // synchronously.
        !           799:         //
        !           800: 
        !           801:         case IOCTL_INTERNAL_MOUSE_ENABLE:
        !           802: 
        !           803:             KeSynchronizeExecution(
        !           804:                 deviceExtension->InterruptObject,
        !           805:                 (PKSYNCHRONIZE_ROUTINE) InpEnableInterrupts,
        !           806:                 (PVOID) deviceExtension
        !           807:                 );
        !           808: 
        !           809:             InpPrint((
        !           810:                 2, 
        !           811:                 "INPORT-InportStartIo: mouse enable (count %d)\n",
        !           812:                 deviceExtension->MouseEnableCount
        !           813:                 ));
        !           814: 
        !           815:             Irp->IoStatus.Status = STATUS_SUCCESS;
        !           816: 
        !           817:             //
        !           818:             // Complete the request.
        !           819:             //
        !           820: 
        !           821:             IoStartNextPacket(DeviceObject, FALSE);
        !           822:             IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
        !           823: 
        !           824:             break;
        !           825: 
        !           826:         //
        !           827:         // Disable mouse interrupts, by calling InpDisableInterrupts
        !           828:         // synchronously.
        !           829:         //
        !           830: 
        !           831:         case IOCTL_INTERNAL_MOUSE_DISABLE:
        !           832: 
        !           833:             InpPrint((2, "INPORT-InportStartIo: mouse disable"));
        !           834: 
        !           835:             if (deviceExtension->MouseEnableCount == 0) {
        !           836: 
        !           837:                 //
        !           838:                 // Mouse already disabled.
        !           839:                 //
        !           840: 
        !           841:                 InpPrint((2, " - error\n"));
        !           842: 
        !           843:                 Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
        !           844: 
        !           845:             } else {
        !           846: 
        !           847:                 //
        !           848:                 // Disable mouse by calling InpDisableInterrupts.
        !           849:                 //
        !           850: 
        !           851:                 KeSynchronizeExecution(
        !           852:                     deviceExtension->InterruptObject,
        !           853:                     (PKSYNCHRONIZE_ROUTINE) InpDisableInterrupts,
        !           854:                     (PVOID) deviceExtension
        !           855:                     );
        !           856: 
        !           857:                 InpPrint((
        !           858:                     2, 
        !           859:                     " (count %d)\n",
        !           860:                     deviceExtension->MouseEnableCount
        !           861:                     ));
        !           862: 
        !           863:                 Irp->IoStatus.Status = STATUS_SUCCESS;
        !           864:             }
        !           865: 
        !           866:             //
        !           867:             // Complete the request.
        !           868:             //
        !           869: 
        !           870:             IoStartNextPacket(DeviceObject, FALSE);
        !           871:             IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
        !           872: 
        !           873:             break;
        !           874: 
        !           875:         default:
        !           876: 
        !           877:             InpPrint((2, "INPORT-InportStartIo: INVALID REQUEST\n"));
        !           878: 
        !           879:             //
        !           880:             // Log an internal error.  Note that we're calling the
        !           881:             // error log DPC routine directly, rather than duplicating
        !           882:             // code.
        !           883:             //
        !           884: 
        !           885:             InportErrorLogDpc(
        !           886:                 (PKDPC) NULL,
        !           887:                 DeviceObject,
        !           888:                 Irp,
        !           889:                 (PVOID) (ULONG) INPORT_INVALID_STARTIO_REQUEST
        !           890:                 );
        !           891: 
        !           892:             ASSERT(FALSE);
        !           893:             break;
        !           894:     }
        !           895: 
        !           896:     InpPrint((2, "INPORT-InportStartIo: exit\n"));
        !           897: 
        !           898:     return;
        !           899: }
        !           900: 
        !           901: #if DBG
        !           902: VOID
        !           903: InpDebugPrint(
        !           904:     ULONG DebugPrintLevel,
        !           905:     PCCHAR DebugMessage,
        !           906:     ...
        !           907:     )
        !           908: 
        !           909: /*++
        !           910: 
        !           911: Routine Description:
        !           912: 
        !           913:     Debug print routine.
        !           914: 
        !           915: Arguments:
        !           916: 
        !           917:     Debug print level between 0 and 3, with 3 being the most verbose.
        !           918: 
        !           919: Return Value:
        !           920: 
        !           921:     None.
        !           922: 
        !           923: --*/
        !           924: 
        !           925: {
        !           926:     va_list ap;
        !           927: 
        !           928:     va_start(ap, DebugMessage);
        !           929: 
        !           930:     if (DebugPrintLevel <= InportDebug) {
        !           931: 
        !           932:         char buffer[128];
        !           933: 
        !           934:         (VOID) vsprintf(buffer, DebugMessage, ap);
        !           935: 
        !           936:         DbgPrint(buffer);
        !           937:     }
        !           938: 
        !           939:     va_end(ap);
        !           940: 
        !           941: }
        !           942: #endif
        !           943: 
        !           944: VOID
        !           945: InpDpcVariableOperation(
        !           946:     IN  PVOID Context
        !           947:     )
        !           948: 
        !           949: /*++
        !           950: 
        !           951: Routine Description:
        !           952: 
        !           953:     This routine is called synchronously by the ISR DPC to perform an 
        !           954:     operation on the InterlockedDpcVariable.  The operations that can be 
        !           955:     performed include increment, decrement, write, and read.  The ISR 
        !           956:     itself reads and writes the InterlockedDpcVariable without calling this 
        !           957:     routine.  
        !           958: 
        !           959: Arguments:
        !           960: 
        !           961:     Context - Pointer to a structure containing the address of the variable
        !           962:         to be operated on, the operation to perform, and the address at
        !           963:         which to copy the resulting value of the variable (the latter is also
        !           964:         used to pass in the value to write to the variable, on a write
        !           965:         operation).
        !           966: 
        !           967: Return Value:
        !           968: 
        !           969:     None.
        !           970: 
        !           971: --*/
        !           972: 
        !           973: {
        !           974:     PVARIABLE_OPERATION_CONTEXT operationContext = Context;
        !           975: 
        !           976:     InpPrint((3,"INPORT-InpDpcVariableOperation: enter\n"));
        !           977:     InpPrint((
        !           978:         3,
        !           979:         "\tPerforming %s at 0x%x (current value 0x%x)\n",
        !           980:         (operationContext->Operation == IncrementOperation)? "increment":
        !           981:         (operationContext->Operation == DecrementOperation)? "decrement":
        !           982:         (operationContext->Operation == WriteOperation)?     "write":
        !           983:         (operationContext->Operation == ReadOperation)?      "read":"",
        !           984:         operationContext->VariableAddress,
        !           985:         *(operationContext->VariableAddress)
        !           986:         ));
        !           987: 
        !           988:     //
        !           989:     // Perform the specified operation at the specified address.
        !           990:     //
        !           991: 
        !           992:     switch(operationContext->Operation) {
        !           993:         case IncrementOperation:
        !           994:             *(operationContext->VariableAddress) += 1;
        !           995:             break;
        !           996:         case DecrementOperation:
        !           997:             *(operationContext->VariableAddress) -= 1;
        !           998:             break;
        !           999:         case ReadOperation:
        !          1000:             break;
        !          1001:         case WriteOperation:
        !          1002:             InpPrint((
        !          1003:                 3,
        !          1004:                 "\tWriting 0x%x\n",
        !          1005:                 *(operationContext->NewValue)
        !          1006:                 ));
        !          1007:             *(operationContext->VariableAddress) = 
        !          1008:                 *(operationContext->NewValue);
        !          1009:             break;
        !          1010:         default:
        !          1011:             ASSERT(FALSE);
        !          1012:             break;
        !          1013:     }
        !          1014: 
        !          1015:     *(operationContext->NewValue) = *(operationContext->VariableAddress);
        !          1016: 
        !          1017:     InpPrint((
        !          1018:         3,
        !          1019:         "INPORT-InpDpcVariableOperation: exit with value 0x%x\n",
        !          1020:         *(operationContext->NewValue)
        !          1021:         ));
        !          1022: }
        !          1023: 
        !          1024: VOID
        !          1025: InpGetDataQueuePointer(
        !          1026:     IN  PVOID Context
        !          1027:     )
        !          1028: 
        !          1029: /*++
        !          1030: 
        !          1031: Routine Description:
        !          1032: 
        !          1033:     This routine is called synchronously to get the current DataIn and DataOut
        !          1034:     pointers for the port InputData queue.
        !          1035: 
        !          1036: Arguments:
        !          1037: 
        !          1038:     Context - Pointer to a structure containing the device extension,
        !          1039:         address at which to store the current DataIn pointer, and the
        !          1040:         address at which to store the current DataOut pointer.
        !          1041: 
        !          1042: Return Value:
        !          1043: 
        !          1044:     None.
        !          1045: 
        !          1046: --*/
        !          1047: 
        !          1048: {
        !          1049:     PDEVICE_EXTENSION deviceExtension;
        !          1050: 
        !          1051:     InpPrint((3,"INPORT-InpGetDataQueuePointer: enter\n"));
        !          1052: 
        !          1053:     //
        !          1054:     // Get address of device extension.
        !          1055:     //
        !          1056: 
        !          1057:     deviceExtension = (PDEVICE_EXTENSION)
        !          1058:                       ((PGET_DATA_POINTER_CONTEXT) Context)->DeviceExtension;
        !          1059: 
        !          1060:     //
        !          1061:     // Get the DataIn and DataOut pointers.
        !          1062:     //
        !          1063: 
        !          1064:     InpPrint((
        !          1065:         3,
        !          1066:         "INPORT-InpGetDataQueuePointer: DataIn 0x%x, DataOut 0x%x\n",
        !          1067:         deviceExtension->DataIn,
        !          1068:         deviceExtension->DataOut
        !          1069:         ));
        !          1070:     ((PGET_DATA_POINTER_CONTEXT) Context)->DataIn = deviceExtension->DataIn;
        !          1071:     ((PGET_DATA_POINTER_CONTEXT) Context)->DataOut = deviceExtension->DataOut;
        !          1072:     ((PGET_DATA_POINTER_CONTEXT) Context)->InputCount = 
        !          1073:         deviceExtension->InputCount;
        !          1074: 
        !          1075:     InpPrint((3,"INPORT-InpGetDataQueuePointer: exit\n"));
        !          1076: }
        !          1077: 
        !          1078: VOID
        !          1079: InpInitializeDataQueue (
        !          1080:     IN PVOID Context
        !          1081:     )
        !          1082: 
        !          1083: /*++
        !          1084: 
        !          1085: Routine Description:
        !          1086: 
        !          1087:     This routine initializes the input data queue.  It is called
        !          1088:     via KeSynchronization, except when called from the initialization routine.
        !          1089: 
        !          1090: Arguments:
        !          1091: 
        !          1092:     Context - Pointer to the device extension.
        !          1093: 
        !          1094: Return Value:
        !          1095: 
        !          1096:     None.
        !          1097: 
        !          1098: --*/
        !          1099: 
        !          1100: {
        !          1101: 
        !          1102:     PDEVICE_EXTENSION deviceExtension;
        !          1103: 
        !          1104:     InpPrint((3,"INPORT-InpInitializeDataQueue: enter\n"));
        !          1105: 
        !          1106:     //
        !          1107:     // Get address of device extension.
        !          1108:     //
        !          1109: 
        !          1110:     deviceExtension = (PDEVICE_EXTENSION) Context;
        !          1111: 
        !          1112:     //
        !          1113:     // Initialize the input data queue.
        !          1114:     //
        !          1115: 
        !          1116:     deviceExtension->InputCount = 0;
        !          1117:     deviceExtension->DataIn = deviceExtension->InputData;
        !          1118:     deviceExtension->DataOut = deviceExtension->InputData;
        !          1119: 
        !          1120:     deviceExtension->OkayToLogOverflow = TRUE;
        !          1121: 
        !          1122:     InpPrint((3,"INPORT-InpInitializeDataQueue: exit\n"));
        !          1123: 
        !          1124: }
        !          1125: 
        !          1126: VOID
        !          1127: InpSetDataQueuePointer(
        !          1128:     IN  PVOID Context
        !          1129:     )
        !          1130: 
        !          1131: /*++
        !          1132: 
        !          1133: Routine Description:
        !          1134: 
        !          1135:     This routine is called synchronously to set the DataOut pointer
        !          1136:     and InputCount for the port InputData queue.
        !          1137: 
        !          1138: Arguments:
        !          1139: 
        !          1140:     Context - Pointer to a structure containing the device extension
        !          1141:         and the new DataOut value for the port InputData queue.
        !          1142: 
        !          1143: Return Value:
        !          1144: 
        !          1145:     None.
        !          1146: 
        !          1147: --*/
        !          1148: 
        !          1149: {
        !          1150:     PDEVICE_EXTENSION deviceExtension;
        !          1151: 
        !          1152:     InpPrint((3,"INPORT-InpSetDataQueuePointer: enter\n"));
        !          1153: 
        !          1154:     //
        !          1155:     // Get address of device extension.
        !          1156:     //
        !          1157: 
        !          1158:     deviceExtension = (PDEVICE_EXTENSION)
        !          1159:                       ((PSET_DATA_POINTER_CONTEXT) Context)->DeviceExtension;
        !          1160: 
        !          1161:     //
        !          1162:     // Set the DataOut pointer.
        !          1163:     //
        !          1164: 
        !          1165:     InpPrint((
        !          1166:         3,
        !          1167:         "INPORT-InpSetDataQueuePointer: old mouse DataOut 0x%x, InputCount %d\n",
        !          1168:         deviceExtension->DataOut,
        !          1169:         deviceExtension->InputCount
        !          1170:         ));
        !          1171:     deviceExtension->DataOut = ((PSET_DATA_POINTER_CONTEXT) Context)->DataOut;
        !          1172:     deviceExtension->InputCount -=
        !          1173:         ((PSET_DATA_POINTER_CONTEXT) Context)->InputCount;
        !          1174: 
        !          1175:     if (deviceExtension->InputCount == 0) {
        !          1176: 
        !          1177:         //
        !          1178:         // Reset the flag that determines whether it is time to log
        !          1179:         // queue overflow errors.  We don't want to log errors too often.
        !          1180:         // Instead, log an error on the first overflow that occurs after
        !          1181:         // the ring buffer has been emptied, and then stop logging errors
        !          1182:         // until it gets cleared out and overflows again.
        !          1183:         //
        !          1184: 
        !          1185:         InpPrint((
        !          1186:             1,
        !          1187:             "INPORT-InpSetDataQueuePointer: Okay to log overflow\n"
        !          1188:             ));
        !          1189:         deviceExtension->OkayToLogOverflow = TRUE;
        !          1190:     }
        !          1191: 
        !          1192:     InpPrint((
        !          1193:         3,
        !          1194:         "INPORT-InpSetDataQueuePointer: new mouse DataOut 0x%x, InputCount %d\n",
        !          1195:         deviceExtension->DataOut,
        !          1196:         deviceExtension->InputCount
        !          1197:         ));
        !          1198: 
        !          1199:     InpPrint((3,"INPORT-InpSetDataQueuePointer: exit\n"));
        !          1200: }
        !          1201: 
        !          1202: BOOLEAN
        !          1203: InpWriteDataToQueue(
        !          1204:     PDEVICE_EXTENSION DeviceExtension,
        !          1205:     IN PMOUSE_INPUT_DATA InputData
        !          1206:     )
        !          1207: 
        !          1208: /*++
        !          1209: 
        !          1210: Routine Description:
        !          1211: 
        !          1212:     This routine adds input data from the mouse to the InputData queue.
        !          1213: 
        !          1214: Arguments:
        !          1215: 
        !          1216:     DeviceExtension - Pointer to the device extension.
        !          1217: 
        !          1218:     InputData - Pointer to the data to add to the InputData queue.
        !          1219: 
        !          1220: Return Value:
        !          1221: 
        !          1222:     Returns TRUE if the data was added, otherwise FALSE.
        !          1223: 
        !          1224: --*/
        !          1225: 
        !          1226: {
        !          1227: 
        !          1228:     InpPrint((2,"INPORT-InpWriteDataToQueue: enter\n"));
        !          1229:     InpPrint((
        !          1230:         3,
        !          1231:         "INPORT-InpWriteDataToQueue: DataIn 0x%x, DataOut 0x%x\n",
        !          1232:         DeviceExtension->DataIn,
        !          1233:         DeviceExtension->DataOut
        !          1234:         ));
        !          1235:     InpPrint((
        !          1236:         3,
        !          1237:         "INPORT-InpWriteDataToQueue: InputCount %d\n",
        !          1238:         DeviceExtension->InputCount
        !          1239:         ));
        !          1240: 
        !          1241:     //
        !          1242:     // Check for full input data queue.
        !          1243:     //
        !          1244: 
        !          1245:     if ((DeviceExtension->DataIn == DeviceExtension->DataOut) &&
        !          1246:         (DeviceExtension->InputCount != 0)) {
        !          1247: 
        !          1248:         //
        !          1249:         // The input data queue is full.  Intentionally ignore
        !          1250:         // the new data.
        !          1251:         //
        !          1252: 
        !          1253:         InpPrint((1,"INPORT-InpWriteDataToQueue: OVERFLOW\n"));
        !          1254:         return(FALSE);
        !          1255: 
        !          1256:     } else {
        !          1257:         *(DeviceExtension->DataIn) = *InputData;
        !          1258:         DeviceExtension->InputCount += 1;
        !          1259:         DeviceExtension->DataIn++;
        !          1260:         InpPrint((
        !          1261:             2,
        !          1262:             "INPORT-InpWriteDataToQueue: new InputCount %d\n",
        !          1263:             DeviceExtension->InputCount
        !          1264:             ));
        !          1265:         if (DeviceExtension->DataIn ==
        !          1266:             DeviceExtension->DataEnd) {
        !          1267:             InpPrint((2,"INPORT-InpWriteDataToQueue: wrap buffer\n"));
        !          1268:             DeviceExtension->DataIn = DeviceExtension->InputData;
        !          1269:         }
        !          1270:     }
        !          1271: 
        !          1272:     InpPrint((2,"INPORT-InpWriteDataToQueue: exit\n"));
        !          1273: 
        !          1274:     return(TRUE);
        !          1275: }
        !          1276: 
        !          1277: #endif

unix.superglobalmegacorp.com

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