Annotation of ntddk/src/input/mouclass/mouclass.c, revision 1.1

1.1     ! root        1: 
        !             2: /*++
        !             3: 
        !             4: Copyright (c) 1990, 1991, 1992, 1993  Microsoft Corporation
        !             5: 
        !             6: Module Name:
        !             7: 
        !             8:     mouclass.c
        !             9: 
        !            10: Abstract:
        !            11: 
        !            12:     Mouse class driver.
        !            13: 
        !            14: Environment:
        !            15: 
        !            16:     Kernel mode only.
        !            17: 
        !            18: Notes:
        !            19: 
        !            20:     NOTES:  (Future/outstanding issues)
        !            21: 
        !            22:     - Powerfail not implemented.
        !            23: 
        !            24:     - Consolidate duplicate code, where possible and appropriate.
        !            25: 
        !            26:     - Unload not implemented.  We don't want to allow this driver
        !            27:       to unload.
        !            28: 
        !            29: Revision History:
        !            30: 
        !            31: --*/
        !            32: 
        !            33: #include "stdarg.h"
        !            34: #include "stdio.h"
        !            35: #include "ntddk.h"
        !            36: #include "mouclass.h"
        !            37: #include "kbdmou.h"
        !            38: #include "moulog.h"
        !            39: 
        !            40: 
        !            41: NTSTATUS
        !            42: DriverEntry(
        !            43:     IN PDRIVER_OBJECT DriverObject,
        !            44:     IN PUNICODE_STRING RegistryPath
        !            45:     );
        !            46: 
        !            47: VOID
        !            48: MouseClassCancel(
        !            49:     IN PDEVICE_OBJECT DeviceObject,
        !            50:     IN PIRP Irp
        !            51:     );
        !            52: 
        !            53: NTSTATUS
        !            54: MouseClassCleanup(
        !            55:     IN PDEVICE_OBJECT DeviceObject,
        !            56:     IN PIRP Irp
        !            57:     );
        !            58: 
        !            59: NTSTATUS
        !            60: MouseClassDeviceControl(
        !            61:     IN PDEVICE_OBJECT DeviceObject,
        !            62:     IN PIRP Irp
        !            63:     );
        !            64: 
        !            65: NTSTATUS
        !            66: MouseClassFlush(
        !            67:     IN PDEVICE_OBJECT DeviceObject,
        !            68:     IN PIRP Irp
        !            69:     );
        !            70: 
        !            71: NTSTATUS
        !            72: MouseClassOpenClose(
        !            73:     IN PDEVICE_OBJECT DeviceObject,
        !            74:     IN PIRP Irp
        !            75:     );
        !            76: 
        !            77: NTSTATUS
        !            78: MouseClassRead(
        !            79:     IN PDEVICE_OBJECT DeviceObject,
        !            80:     IN PIRP Irp
        !            81:     );
        !            82: 
        !            83: VOID
        !            84: MouseClassServiceCallback(
        !            85:     IN PDEVICE_OBJECT DeviceObject,
        !            86:     IN PMOUSE_INPUT_DATA InputDataStart,
        !            87:     IN PMOUSE_INPUT_DATA InputDataEnd,
        !            88:     IN OUT PULONG InputDataConsumed
        !            89:     );
        !            90: 
        !            91: VOID
        !            92: MouseClassStartIo(
        !            93:     IN PDEVICE_OBJECT DeviceObject,
        !            94:     IN PIRP Irp
        !            95:     );
        !            96: 
        !            97: VOID
        !            98: MouseClassUnload(
        !            99:     IN PDRIVER_OBJECT DriverObject
        !           100:     );
        !           101: 
        !           102: BOOLEAN
        !           103: MouCancelRequest(
        !           104:     IN PVOID Context
        !           105:     );
        !           106: 
        !           107: VOID
        !           108: MouConfiguration(
        !           109:     IN PDEVICE_EXTENSION DeviceExtension,
        !           110:     IN PUNICODE_STRING RegistryPath,
        !           111:     IN PUNICODE_STRING DeviceName
        !           112:     );
        !           113: 
        !           114: NTSTATUS
        !           115: MouConnectToPort(
        !           116:     IN PDEVICE_OBJECT ClassDeviceObject,
        !           117:     IN PUNICODE_STRING FullPortName,
        !           118:     IN ULONG PortIndex
        !           119:     );
        !           120: 
        !           121: NTSTATUS
        !           122: MouCreateClassObject(
        !           123:     IN PDRIVER_OBJECT DriverObject,
        !           124:     IN PDEVICE_EXTENSION TmpDeviceExtension,
        !           125:     IN PUNICODE_STRING RegistryPath,
        !           126:     IN PUNICODE_STRING FullDeviceName,
        !           127:     IN PUNICODE_STRING BaseDeviceName,
        !           128:     IN PDEVICE_OBJECT *ClassDeviceObject
        !           129:     );
        !           130: 
        !           131: #if DBG
        !           132: 
        !           133: VOID
        !           134: MouDebugPrint(
        !           135:     ULONG DebugPrintLevel,
        !           136:     PCCHAR DebugMessage,
        !           137:     ...
        !           138:     );
        !           139: 
        !           140: //
        !           141: // Declare the global debug flag for this driver.
        !           142: //
        !           143: 
        !           144: ULONG MouseDebug = 0;
        !           145: #define MouPrint(x) MouDebugPrint x
        !           146: #else
        !           147: #define MouPrint(x)
        !           148: #endif
        !           149: 
        !           150: NTSTATUS
        !           151: MouDeterminePortsServiced(
        !           152:     IN PUNICODE_STRING BasePortName,
        !           153:     IN OUT PULONG NumberPortsServiced
        !           154:     );
        !           155: 
        !           156: NTSTATUS 
        !           157: MouDeviceMapQueryCallback(
        !           158:     IN PWSTR ValueName,
        !           159:     IN ULONG ValueType,
        !           160:     IN PVOID ValueData,
        !           161:     IN ULONG ValueLength,
        !           162:     IN PVOID Context,
        !           163:     IN PVOID EntryContext
        !           164:     );
        !           165: 
        !           166: NTSTATUS
        !           167: MouEnableDisablePort(
        !           168:     IN PDEVICE_OBJECT DeviceObject,
        !           169:     IN BOOLEAN EnableFlag,
        !           170:     IN ULONG PortIndex
        !           171:     );
        !           172: 
        !           173: VOID
        !           174: MouInitializeDataQueue(
        !           175:     IN PVOID Context
        !           176:     );
        !           177: 
        !           178: NTSTATUS
        !           179: MouSendConnectRequest(
        !           180:     IN PDEVICE_OBJECT DeviceObject,
        !           181:     IN PVOID ServiceCallback,
        !           182:     IN ULONG PortIndex
        !           183:     );
        !           184: 
        !           185: //
        !           186: // Use the alloc_text pragma to specify the driver initialization routines
        !           187: // (they can be paged out).
        !           188: //
        !           189: 
        !           190: #ifdef ALLOC_PRAGMA
        !           191: #pragma alloc_text(init,DriverEntry)
        !           192: #pragma alloc_text(init,MouConfiguration)
        !           193: #pragma alloc_text(init,MouCreateClassObject)
        !           194: #pragma alloc_text(init,MouDeterminePortsServiced)
        !           195: #pragma alloc_text(init,MouDeviceMapQueryCallback)
        !           196: #pragma alloc_text(init,MouConnectToPort)
        !           197: #pragma alloc_text(init,MouSendConnectRequest)
        !           198: #endif
        !           199: 
        !           200: 
        !           201: NTSTATUS
        !           202: DriverEntry(
        !           203:     IN PDRIVER_OBJECT DriverObject,
        !           204:     IN PUNICODE_STRING RegistryPath
        !           205:     )
        !           206: 
        !           207: /*++
        !           208: 
        !           209: Routine Description:
        !           210: 
        !           211:     This routine initializes the mouse class driver.
        !           212: 
        !           213: Arguments:
        !           214: 
        !           215:     DriverObject - Pointer to driver object created by system.
        !           216: 
        !           217:     RegistryPath - Pointer to the Unicode name of the registry path
        !           218:         for this driver.
        !           219: 
        !           220: Return Value:
        !           221: 
        !           222:     The function value is the final status from the initialization operation.
        !           223: 
        !           224: --*/
        !           225: 
        !           226: {
        !           227:     DEVICE_EXTENSION tmpDeviceExtension;
        !           228:     PDEVICE_OBJECT classDeviceObject = NULL;
        !           229:     PDEVICE_EXTENSION deviceExtension = NULL;
        !           230:     NTSTATUS status;
        !           231:     ULONG i;
        !           232:     ULONG portConnectionSuccessful;
        !           233:     UNICODE_STRING fullClassName;
        !           234:     UNICODE_STRING fullPortName;
        !           235:     UNICODE_STRING baseClassName;
        !           236:     UNICODE_STRING basePortName;
        !           237:     UNICODE_STRING deviceNameSuffix;
        !           238:     UNICODE_STRING registryPath;
        !           239:     PIO_ERROR_LOG_PACKET errorLogEntry;
        !           240:     ULONG uniqueErrorValue;
        !           241:     ULONG dumpCount = 0;
        !           242:     NTSTATUS errorCode = STATUS_SUCCESS;
        !           243: 
        !           244: #define NAME_MAX 256
        !           245:     WCHAR baseClassBuffer[NAME_MAX];
        !           246:     WCHAR basePortBuffer[NAME_MAX];
        !           247: 
        !           248: #define DUMP_COUNT 4
        !           249:     ULONG dumpData[DUMP_COUNT];
        !           250: 
        !           251:     MouPrint((1,"\n\nMOUCLASS-MouseClassInitialize: enter\n"));
        !           252: 
        !           253:     //
        !           254:     // Zero-initialize various structures.
        !           255:     //
        !           256: 
        !           257:     RtlZeroMemory(&tmpDeviceExtension, sizeof(DEVICE_EXTENSION));
        !           258: 
        !           259:     fullClassName.MaximumLength = 0;
        !           260:     fullPortName.MaximumLength = 0;
        !           261:     deviceNameSuffix.MaximumLength = 0;
        !           262:     registryPath.MaximumLength = 0;
        !           263: 
        !           264:     RtlZeroMemory(baseClassBuffer, NAME_MAX * sizeof(WCHAR));
        !           265:     baseClassName.Buffer = baseClassBuffer;
        !           266:     baseClassName.Length = 0;
        !           267:     baseClassName.MaximumLength = NAME_MAX * sizeof(WCHAR);
        !           268: 
        !           269:     RtlZeroMemory(basePortBuffer, NAME_MAX * sizeof(WCHAR));
        !           270:     basePortName.Buffer = basePortBuffer;
        !           271:     basePortName.Length = 0;
        !           272:     basePortName.MaximumLength = NAME_MAX * sizeof(WCHAR);
        !           273: 
        !           274:     //
        !           275:     // Need to ensure that the registry path is null-terminated.
        !           276:     // Allocate pool to hold a null-terminated copy of the path.
        !           277:     //
        !           278: 
        !           279:     registryPath.Buffer = ExAllocatePool(
        !           280:                               PagedPool,
        !           281:                               RegistryPath->Length + sizeof(UNICODE_NULL)
        !           282:                               );
        !           283: 
        !           284:     if (!registryPath.Buffer) {
        !           285:         MouPrint((
        !           286:             1,
        !           287:             "MOUCLASS-MouseClassInitialize: Couldn't allocate pool for registry path\n"
        !           288:             ));
        !           289: 
        !           290:         status = STATUS_UNSUCCESSFUL;
        !           291:         errorCode = MOUCLASS_INSUFFICIENT_RESOURCES;
        !           292:         uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 2;
        !           293:         dumpData[0] = (ULONG) RegistryPath->Length + sizeof(UNICODE_NULL);
        !           294:         dumpCount = 1;
        !           295:         goto MouseClassInitializeExit;
        !           296: 
        !           297:     } else {
        !           298: 
        !           299:         registryPath.Length = RegistryPath->Length;
        !           300:         registryPath.MaximumLength = 
        !           301:             registryPath.Length + sizeof(UNICODE_NULL);
        !           302: 
        !           303:         RtlZeroMemory(
        !           304:             registryPath.Buffer,
        !           305:             registryPath.MaximumLength
        !           306:                 );
        !           307: 
        !           308:         RtlMoveMemory(
        !           309:             registryPath.Buffer,
        !           310:             RegistryPath->Buffer,
        !           311:             RegistryPath->Length
        !           312:             );
        !           313: 
        !           314:     }
        !           315: 
        !           316:     //
        !           317:     // Get the configuration information for this driver.
        !           318:     //
        !           319: 
        !           320:     MouConfiguration(&tmpDeviceExtension, &registryPath, &baseClassName);
        !           321: 
        !           322:     //
        !           323:     // Set up space for the class's device object suffix.  Note that
        !           324:     // we overallocate space for the suffix string because it is much
        !           325:     // easier than figuring out exactly how much space is required.
        !           326:     // The storage gets freed at the end of driver initialization, so
        !           327:     // who cares...
        !           328:     //
        !           329: 
        !           330:     RtlInitUnicodeString(&deviceNameSuffix, NULL);
        !           331:     
        !           332:     deviceNameSuffix.MaximumLength = POINTER_PORTS_MAXIMUM * sizeof(WCHAR);
        !           333:     deviceNameSuffix.MaximumLength += sizeof(UNICODE_NULL);
        !           334:     
        !           335:     deviceNameSuffix.Buffer = ExAllocatePool(
        !           336:                                   PagedPool,
        !           337:                                   deviceNameSuffix.MaximumLength
        !           338:                                   );
        !           339:     
        !           340:     if (!deviceNameSuffix.Buffer) {
        !           341:     
        !           342:         MouPrint((
        !           343:             1,
        !           344:             "MOUCLASS-MouseClassInitialize: Couldn't allocate string for device object suffix\n"
        !           345:             ));
        !           346:     
        !           347:         status = STATUS_UNSUCCESSFUL;
        !           348:         errorCode = MOUCLASS_INSUFFICIENT_RESOURCES;
        !           349:         uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 4;
        !           350:         dumpData[0] = (ULONG) deviceNameSuffix.MaximumLength;
        !           351:         dumpCount = 1;
        !           352:         goto MouseClassInitializeExit;
        !           353:     
        !           354:     }
        !           355: 
        !           356:     RtlZeroMemory(deviceNameSuffix.Buffer, deviceNameSuffix.MaximumLength);
        !           357: 
        !           358:     //
        !           359:     // Set up space for the class's full device object name.  
        !           360:     //
        !           361: 
        !           362:     RtlInitUnicodeString(&fullClassName, NULL);
        !           363:     
        !           364:     fullClassName.MaximumLength = sizeof(L"\\Device\\") +
        !           365:                                       baseClassName.Length +
        !           366:                                       deviceNameSuffix.MaximumLength;
        !           367:                                       
        !           368:     
        !           369:     fullClassName.Buffer = ExAllocatePool(
        !           370:                                    PagedPool,
        !           371:                                    fullClassName.MaximumLength
        !           372:                                    );
        !           373:     
        !           374:     if (!fullClassName.Buffer) {
        !           375:     
        !           376:         MouPrint((
        !           377:             1,
        !           378:             "MOUCLASS-MouseClassInitialize: Couldn't allocate string for device object name\n"
        !           379:             ));
        !           380:     
        !           381:         status = STATUS_UNSUCCESSFUL;
        !           382:         errorCode = MOUCLASS_INSUFFICIENT_RESOURCES;
        !           383:         uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 6;
        !           384:         dumpData[0] = (ULONG) fullClassName.MaximumLength;
        !           385:         dumpCount = 1;
        !           386:         goto MouseClassInitializeExit;
        !           387:     
        !           388:     }
        !           389: 
        !           390:     RtlZeroMemory(fullClassName.Buffer, fullClassName.MaximumLength);
        !           391:     RtlAppendUnicodeToString(&fullClassName, L"\\Device\\");
        !           392:     RtlAppendUnicodeToString(&fullClassName, baseClassName.Buffer);
        !           393: 
        !           394:     //
        !           395:     // Set up the base device name for the associated port device.
        !           396:     // It is the same as the base class name, with "Class" replaced
        !           397:     // by "Port".
        !           398:     //
        !           399: 
        !           400:     RtlCopyUnicodeString(&basePortName, &baseClassName);
        !           401: 
        !           402:     basePortName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
        !           403: 
        !           404:     RtlAppendUnicodeToString(&basePortName, L"Port");
        !           405: 
        !           406:     //
        !           407:     // Determine how many ports this class driver is to service.
        !           408:     //
        !           409: 
        !           410:     status = MouDeterminePortsServiced(&basePortName, &i);
        !           411: 
        !           412:     if (NT_SUCCESS(status)) {
        !           413:         if (i < tmpDeviceExtension.MaximumPortsServiced)
        !           414:             tmpDeviceExtension.MaximumPortsServiced = i;
        !           415:     }
        !           416: 
        !           417:     status = STATUS_SUCCESS;
        !           418: 
        !           419:     MouPrint((
        !           420:         1,
        !           421:         "MOUCLASS-MouseClassInitialize: Will service %d port devices\n",
        !           422:         tmpDeviceExtension.MaximumPortsServiced
        !           423:         ));
        !           424: 
        !           425:     //
        !           426:     // Set up space for the full device object name for the ports.  
        !           427:     //
        !           428: 
        !           429:     RtlInitUnicodeString(&fullPortName, NULL);
        !           430:     
        !           431:     fullPortName.MaximumLength = sizeof(L"\\Device\\") +
        !           432:                                      basePortName.Length +
        !           433:                                      deviceNameSuffix.MaximumLength;
        !           434:                                       
        !           435:     fullPortName.Buffer = ExAllocatePool(
        !           436:                                   PagedPool,
        !           437:                                   fullPortName.MaximumLength
        !           438:                                   );
        !           439:     
        !           440:     if (!fullPortName.Buffer) {
        !           441:     
        !           442:         MouPrint((
        !           443:             1,
        !           444:             "MOUCLASS-MouseClassInitialize: Couldn't allocate string for port device object name\n"
        !           445:             ));
        !           446:     
        !           447:         status = STATUS_UNSUCCESSFUL;
        !           448:         errorCode = MOUCLASS_INSUFFICIENT_RESOURCES;
        !           449:         uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 8;
        !           450:         dumpData[0] = (ULONG) fullPortName.MaximumLength;
        !           451:         dumpCount = 1;
        !           452:         goto MouseClassInitializeExit;
        !           453:     
        !           454:     }
        !           455: 
        !           456:     RtlZeroMemory(fullPortName.Buffer, fullPortName.MaximumLength);
        !           457:     RtlAppendUnicodeToString(&fullPortName, L"\\Device\\");
        !           458:     RtlAppendUnicodeToString(&fullPortName, basePortName.Buffer);
        !           459: 
        !           460:     //
        !           461:     // Allocate memory for the port device object pointer list.
        !           462:     //
        !           463: 
        !           464:     (PDEVICE_OBJECT *) tmpDeviceExtension.PortDeviceObjectList = 
        !           465:         ExAllocatePool(
        !           466:             NonPagedPool,
        !           467:             sizeof(PDEVICE_OBJECT) * tmpDeviceExtension.MaximumPortsServiced
        !           468:             );
        !           469: 
        !           470:     if (!tmpDeviceExtension.PortDeviceObjectList) {
        !           471:    
        !           472:         //
        !           473:         // Could not allocate memory for the port device object pointers.
        !           474:         //
        !           475: 
        !           476:         MouPrint((
        !           477:             1,
        !           478:             "MOUCLASS-MouseClassInitialize: Could not allocate PortDeviceObjectList for %ws\n",
        !           479:             fullClassName.Buffer
        !           480:             ));
        !           481: 
        !           482:         status = STATUS_INSUFFICIENT_RESOURCES;
        !           483:         errorCode = MOUCLASS_INSUFFICIENT_RESOURCES;
        !           484:         uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 10;
        !           485:         dumpData[0] = (ULONG) (sizeof(PDEVICE_OBJECT) * tmpDeviceExtension.MaximumPortsServiced);
        !           486:         dumpData[1] = (ULONG) tmpDeviceExtension.MaximumPortsServiced;
        !           487:         dumpCount = 2;
        !           488: 
        !           489:         goto MouseClassInitializeExit;
        !           490:     }
        !           491: 
        !           492:     //
        !           493:     // Set up the class device object(s) to handle the associated 
        !           494:     // port devices.
        !           495:     //
        !           496: 
        !           497:     portConnectionSuccessful = 0;
        !           498: 
        !           499: 
        !           500:     for (i = 0; i < tmpDeviceExtension.MaximumPortsServiced; i++) {
        !           501:     
        !           502:         //
        !           503:         // Append the suffix to the device object name string.  E.g., turn
        !           504:         // \Device\PointerClass into \Device\PointerClass0.  Then attempt
        !           505:         // to create the device object.  If the device object already
        !           506:         // exists increment the suffix and try again.
        !           507:         //
        !           508: 
        !           509:         status = RtlIntegerToUnicodeString(
        !           510:                      i,
        !           511:                      10,
        !           512:                      &deviceNameSuffix
        !           513:                      );
        !           514: 
        !           515:         if (!NT_SUCCESS(status)) {
        !           516:             continue;
        !           517:         }
        !           518: 
        !           519:         RtlAppendUnicodeStringToString(
        !           520:             &fullClassName,
        !           521:             &deviceNameSuffix
        !           522:         );
        !           523: 
        !           524:         RtlAppendUnicodeStringToString(
        !           525:             &fullPortName,
        !           526:             &deviceNameSuffix
        !           527:         );
        !           528: 
        !           529:         //
        !           530:         // Create the class device object.
        !           531:         //
        !           532: 
        !           533:         if (tmpDeviceExtension.ConnectOneClassToOnePort 
        !           534:                 || (classDeviceObject == NULL)) {
        !           535:             classDeviceObject = NULL;
        !           536:             status = MouCreateClassObject(
        !           537:                          DriverObject,
        !           538:                          &tmpDeviceExtension,
        !           539:                          &registryPath,
        !           540:                          &fullClassName,
        !           541:                          &baseClassName,
        !           542:                          &classDeviceObject
        !           543:                          );
        !           544:         }
        !           545: 
        !           546:         //
        !           547:         // Connect to the port device.
        !           548:         //
        !           549: 
        !           550:         if (NT_SUCCESS(status)) {
        !           551:             status = MouConnectToPort(
        !           552:                          classDeviceObject,
        !           553:                          &fullPortName,
        !           554:                          i
        !           555:                          );
        !           556:         }
        !           557: 
        !           558:         if (NT_SUCCESS(status)) {
        !           559: 
        !           560:             portConnectionSuccessful += 1;
        !           561: 
        !           562:             if (tmpDeviceExtension.ConnectOneClassToOnePort 
        !           563:                     || (portConnectionSuccessful == 1)) {
        !           564: 
        !           565:                 //
        !           566:                 // Load the device map information into the registry so 
        !           567:                 // that setup can determine which mouse class driver is active.  
        !           568:                 //
        !           569:             
        !           570:                 status = RtlWriteRegistryValue(
        !           571:                              RTL_REGISTRY_DEVICEMAP,
        !           572:                              baseClassName.Buffer,
        !           573:                              fullClassName.Buffer,
        !           574:                              REG_SZ,
        !           575:                              registryPath.Buffer,
        !           576:                              registryPath.Length + sizeof(UNICODE_NULL)
        !           577:                              );
        !           578:                 
        !           579:                 if (!NT_SUCCESS(status)) {
        !           580:                 
        !           581:                     MouPrint((
        !           582:                         1, 
        !           583:                         "MOUCLASS-MouseClassInitialize: Could not store %ws in DeviceMap\n",
        !           584:                         fullClassName.Buffer
        !           585:                             ));
        !           586:                 
        !           587:                 
        !           588:                     //
        !           589:                     // Stop making connections, and log an error.
        !           590:                     //
        !           591:     
        !           592:                     errorCode = MOUCLASS_NO_DEVICEMAP_CREATED;
        !           593:                     uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 14;
        !           594:                     dumpCount = 0;
        !           595: 
        !           596:                     //
        !           597:                     // N.B. 'break' should cause execution to
        !           598:                     // go to KeyboardClassInitializeExit (otherwise
        !           599:                     // do an explicit 'goto').
        !           600:                     //
        !           601: 
        !           602:                     break;
        !           603:             
        !           604:                 } else {
        !           605:                 
        !           606:                     MouPrint((
        !           607:                         1, 
        !           608:                         "MOUCLASS-MouseClassInitialize: Stored %ws in DeviceMap\n",
        !           609:                         fullClassName.Buffer
        !           610:                         ));
        !           611:                 }
        !           612:             }
        !           613: 
        !           614:             //
        !           615:             // Try the next one.
        !           616:             //
        !           617: 
        !           618:             fullClassName.Length -= deviceNameSuffix.Length;
        !           619:             fullPortName.Length -= deviceNameSuffix.Length;
        !           620: 
        !           621:         } else if (tmpDeviceExtension.ConnectOneClassToOnePort) {
        !           622: 
        !           623:             //
        !           624:             // Stop doing 1:1 class-port connections if there is
        !           625:             // a failure.
        !           626:             //
        !           627:             // Note that if we are doing 1:many class-port connections
        !           628:             // and we encounter an error, we continue to try to connect 
        !           629:             // to port devices. 
        !           630:             //
        !           631: 
        !           632:             break;
        !           633:         }
        !           634: 
        !           635:     }
        !           636: 
        !           637:     if (!portConnectionSuccessful) {
        !           638: 
        !           639:         //
        !           640:         // The class driver was unable to connect to any port devices.
        !           641:         // Log a warning message.
        !           642:         //
        !           643: 
        !           644:         errorCode = MOUCLASS_NO_PORT_DEVICE_OBJECT;
        !           645:         uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 18;
        !           646: 
        !           647:     }
        !           648: 
        !           649: MouseClassInitializeExit:
        !           650: 
        !           651:     if (errorCode != STATUS_SUCCESS) {
        !           652: 
        !           653:         //
        !           654:         // The initialization failed in some way.  Log an error.
        !           655:         //
        !           656: 
        !           657:         errorLogEntry = (PIO_ERROR_LOG_PACKET)
        !           658:             IoAllocateErrorLogEntry(
        !           659:                 (classDeviceObject == NULL) ? 
        !           660:                     (PVOID) DriverObject : (PVOID) classDeviceObject,
        !           661:                 (UCHAR) (sizeof(IO_ERROR_LOG_PACKET)
        !           662:                          + (dumpCount * sizeof(ULONG)))
        !           663:                 );
        !           664: 
        !           665:         if (errorLogEntry != NULL) {
        !           666: 
        !           667:             errorLogEntry->ErrorCode = errorCode;
        !           668:             errorLogEntry->DumpDataSize = dumpCount * sizeof(ULONG);
        !           669:             errorLogEntry->SequenceNumber = 0;
        !           670:             errorLogEntry->MajorFunctionCode = 0;
        !           671:             errorLogEntry->IoControlCode = 0;
        !           672:             errorLogEntry->RetryCount = 0;
        !           673:             errorLogEntry->UniqueErrorValue = uniqueErrorValue;
        !           674:             errorLogEntry->FinalStatus = status;
        !           675:             for (i = 0; i < dumpCount; i++)
        !           676:                 errorLogEntry->DumpData[i] = dumpData[i];
        !           677: 
        !           678:             IoWriteErrorLogEntry(errorLogEntry);
        !           679:         }
        !           680:     }
        !           681: 
        !           682:     //
        !           683:     // Free the unicode strings.
        !           684:     //
        !           685: 
        !           686:     if (deviceNameSuffix.MaximumLength != 0)
        !           687:         ExFreePool(deviceNameSuffix.Buffer);
        !           688:     if (fullClassName.MaximumLength != 0)
        !           689:         ExFreePool(fullClassName.Buffer);
        !           690:     if (fullPortName.MaximumLength != 0)
        !           691:         ExFreePool(fullPortName.Buffer);
        !           692:     if (registryPath.MaximumLength != 0)
        !           693:         ExFreePool(registryPath.Buffer);
        !           694: 
        !           695:     if ((tmpDeviceExtension.ConnectOneClassToOnePort 
        !           696:              && (!NT_SUCCESS(status))) ||
        !           697:          !portConnectionSuccessful) {
        !           698: 
        !           699:         //
        !           700:         // Clean up leftover resources.  If we're doing 1:1 class-port
        !           701:         // connections, then we may have created a class device object
        !           702:         // for which the connect failed.  If we're doing 1:many
        !           703:         // connections, we may have created a class device object but
        !           704:         // failed to make ANY connections.  In either case, we
        !           705:         // free the ring buffer and delete the class device object.
        !           706:         //
        !           707: 
        !           708:         if (classDeviceObject) {
        !           709:             deviceExtension =
        !           710:                 (PDEVICE_EXTENSION) classDeviceObject->DeviceExtension;
        !           711:             if ((deviceExtension) && (deviceExtension->InputData))
        !           712:                 ExFreePool(deviceExtension->InputData);
        !           713:             IoDeleteDevice(classDeviceObject);
        !           714:         }
        !           715:     }
        !           716: 
        !           717:     //
        !           718:     // If we successfully connected to at least one pointer port device,
        !           719:     // this driver's initialization was successful.
        !           720:     //
        !           721: 
        !           722:     if (portConnectionSuccessful) {
        !           723: 
        !           724:         //
        !           725:         // Set up the device driver entry points.
        !           726:         //
        !           727: 
        !           728:         DriverObject->DriverStartIo = MouseClassStartIo;
        !           729:         DriverObject->MajorFunction[IRP_MJ_CREATE] = MouseClassOpenClose;
        !           730:         DriverObject->MajorFunction[IRP_MJ_CLOSE]  = MouseClassOpenClose;
        !           731:         DriverObject->MajorFunction[IRP_MJ_READ]   = MouseClassRead;
        !           732:         DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]  =
        !           733:                                                  MouseClassFlush;
        !           734:         DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
        !           735:                                                  MouseClassDeviceControl;
        !           736:         DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MouseClassCleanup;
        !           737: 
        !           738:         //
        !           739:         // NOTE: Don't allow this driver to unload.  Otherwise, we would set
        !           740:         // DriverObject->DriverUnload = MouseClassUnload.
        !           741:         //
        !           742: 
        !           743:         status = STATUS_SUCCESS;
        !           744:     }
        !           745: 
        !           746:     MouPrint((1,"MOUCLASS-MouseClassInitialize: exit\n"));
        !           747: 
        !           748:     return(status);
        !           749: 
        !           750: }
        !           751: 
        !           752: VOID
        !           753: MouseClassCancel(
        !           754:     IN PDEVICE_OBJECT DeviceObject,
        !           755:     IN PIRP Irp
        !           756:     )
        !           757: 
        !           758: /*++
        !           759: 
        !           760: Routine Description:
        !           761: 
        !           762:     This routine is the class cancellation routine.  It is
        !           763:     called from the I/O system when a request is cancelled.  Read requests
        !           764:     are currently the only cancellable requests.
        !           765: 
        !           766:     N.B.  The cancel spinlock is already held upon entry to this routine.
        !           767: 
        !           768: Arguments:
        !           769: 
        !           770:     DeviceObject - Pointer to class device object.
        !           771: 
        !           772:     Irp - Pointer to the request packet to be cancelled.
        !           773: 
        !           774: Return Value:
        !           775: 
        !           776:     None.
        !           777: 
        !           778: --*/
        !           779: 
        !           780: {
        !           781:     PDEVICE_EXTENSION deviceExtension;
        !           782:     KIRQL currentIrql;
        !           783:     KIRQL cancelIrql;
        !           784: 
        !           785:     MouPrint((2,"MOUCLASS-MouseClassCancel: enter\n"));
        !           786: 
        !           787:     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
        !           788: 
        !           789:     //
        !           790:     // Release the cancel spinlock and grab the mouse class spinlock (it
        !           791:     // protects the RequestIsPending flag).
        !           792:     //
        !           793: 
        !           794:     IoReleaseCancelSpinLock(Irp->CancelIrql);
        !           795:     KeAcquireSpinLock(&deviceExtension->SpinLock, &currentIrql);
        !           796:     
        !           797:     if ((deviceExtension->RequestIsPending) 
        !           798:         && (Irp == DeviceObject->CurrentIrp)) {
        !           799: 
        !           800:         //
        !           801:         // The current request is being cancelled.  Set the CurrentIrp to
        !           802:         // null, clear the RequestIsPending flag, and release the mouse class 
        !           803:         // spinlock before starting the next packet.
        !           804:         //
        !           805: 
        !           806:         DeviceObject->CurrentIrp = NULL;
        !           807:         deviceExtension->RequestIsPending = FALSE;
        !           808:         KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
        !           809:         IoStartNextPacket(DeviceObject, TRUE);
        !           810:     } else {
        !           811: 
        !           812:         //
        !           813:         // Cancel a request in the device queue.  Reacquire the cancel
        !           814:         // spinlock, remove the request from the queue, and release the 
        !           815:         // cancel spinlock.  Release the mouse class spinlock.
        !           816:         //
        !           817: 
        !           818:         IoAcquireCancelSpinLock(&cancelIrql);
        !           819:         if (TRUE != KeRemoveEntryDeviceQueue(
        !           820:                         &DeviceObject->DeviceQueue,
        !           821:                         &Irp->Tail.Overlay.DeviceQueueEntry
        !           822:                         )) {
        !           823:             MouPrint((
        !           824:                 1, 
        !           825:                 "MOUCLASS-MouseClassCancel: Irp 0x%x not in device queue?!?\n",
        !           826:                 Irp
        !           827:                 ));
        !           828:         }
        !           829:         IoReleaseCancelSpinLock(cancelIrql);
        !           830:         KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
        !           831:     }
        !           832: 
        !           833:     //
        !           834:     // Complete the request with STATUS_CANCELLED.
        !           835:     //
        !           836: 
        !           837:     Irp->IoStatus.Status = STATUS_CANCELLED;
        !           838:     Irp->IoStatus.Information = 0;
        !           839:     IoCompleteRequest (Irp, IO_MOUSE_INCREMENT);
        !           840: 
        !           841:     MouPrint((2,"MOUCLASS-MouseClassCancel: exit\n"));
        !           842: 
        !           843:     return;
        !           844: }
        !           845: 
        !           846: NTSTATUS
        !           847: MouseClassCleanup(
        !           848:     IN PDEVICE_OBJECT DeviceObject,
        !           849:     IN PIRP Irp
        !           850:     )
        !           851: 
        !           852: /*++
        !           853: 
        !           854: Routine Description:
        !           855: 
        !           856:     This routine is the dispatch routine for cleanup requests.
        !           857:     All requests queued to the mouse class device (on behalf of
        !           858:     the thread for whom the cleanup request was generated) are 
        !           859:     completed with STATUS_CANCELLED.
        !           860: 
        !           861: Arguments:
        !           862: 
        !           863:     DeviceObject - Pointer to class device object.
        !           864: 
        !           865:     Irp - Pointer to the request packet.
        !           866: 
        !           867: Return Value:
        !           868: 
        !           869:     Status is returned.
        !           870: 
        !           871: --*/
        !           872: 
        !           873: {
        !           874:     KIRQL spinlockIrql;
        !           875:     KIRQL cancelIrql;
        !           876:     PDEVICE_EXTENSION deviceExtension;
        !           877:     PKDEVICE_QUEUE_ENTRY packet;
        !           878:     PIRP  currentIrp = NULL;
        !           879:     PIO_STACK_LOCATION irpSp;
        !           880: 
        !           881:     MouPrint((2,"MOUCLASS-MouseClassCleanup: enter\n"));
        !           882: 
        !           883:     deviceExtension = DeviceObject->DeviceExtension;
        !           884: 
        !           885:     //
        !           886:     // Acquire the mouse class spinlock and the cancel spinlock.
        !           887:     //
        !           888: 
        !           889:     KeAcquireSpinLock(&deviceExtension->SpinLock, &spinlockIrql);
        !           890:     IoAcquireCancelSpinLock(&cancelIrql);
        !           891: 
        !           892:     //
        !           893:     // Get a pointer to the current stack location for this request.  
        !           894:     //
        !           895: 
        !           896:     irpSp = IoGetCurrentIrpStackLocation(Irp);
        !           897: 
        !           898:     //
        !           899:     // If the file object's FsContext is non-null, then the cleanup 
        !           900:     // request is being executed by the trusted subsystem.  Since the 
        !           901:     // trusted subsystem is the only one with sufficient privilege to make 
        !           902:     // Read requests to the driver, and since only Read requests get queued 
        !           903:     // to the device queue, a cleanup request from the trusted subsystem is 
        !           904:     // handled by cancelling all queued requests.
        !           905:     // 
        !           906:     // If the FsContext is null, there is no cleanup work to perform
        !           907:     // (only read requests can be cancelled).
        !           908:     // 
        !           909:     // NOTE:  If this driver is to allow more than one trusted subsystem 
        !           910:     //        to make read requests to the same device object some day in
        !           911:     //        the future, then there needs to be a mechanism that
        !           912:     //        allows Cleanup to remove only those queued requests that
        !           913:     //        were made by threads using the same FileObject as the
        !           914:     //        file object in the Cleanup request.
        !           915:     //
        !           916: 
        !           917:     if (irpSp->FileObject->FsContext) {
        !           918: 
        !           919:         //
        !           920:         // Indicate that the cleanup routine has been called (StartIo cares
        !           921:         // about this).
        !           922:         //
        !           923: 
        !           924:         deviceExtension->CleanupWasInitiated = TRUE;
        !           925: 
        !           926:         //
        !           927:         // Complete all requests queued by this thread with STATUS_CANCELLED.
        !           928:         // Start with the real CurrentIrp, and run down the list of requests 
        !           929:         // in the device queue.  Be sure to set the real CurrentIrp to NULL 
        !           930:         // and the RequestIsPending flag to FALSE, so that the class
        !           931:         // service callback routine won't attempt to complete CurrentIrp.  
        !           932:         // Note that we can really only trust CurrentIrp when RequestIsPending.
        !           933:         //
        !           934: 
        !           935:         currentIrp = DeviceObject->CurrentIrp;
        !           936:         DeviceObject->CurrentIrp = NULL;
        !           937:         deviceExtension->RequestIsPending = FALSE;
        !           938:     
        !           939:         while (currentIrp != NULL) {
        !           940:     
        !           941:             //
        !           942:             // Remove the CurrentIrp from the cancellable state.
        !           943:             //
        !           944:             //
        !           945:     
        !           946:             IoSetCancelRoutine(currentIrp, NULL);
        !           947:     
        !           948:             //
        !           949:             // Set Status to CANCELLED, release the spinlocks,
        !           950:             // and complete the request.  Note that the IRQL is reset to
        !           951:             // DISPATCH_LEVEL when we release the spinlocks.
        !           952:             //
        !           953:     
        !           954:             currentIrp->IoStatus.Status = STATUS_CANCELLED;
        !           955:             currentIrp->IoStatus.Information = 0;
        !           956:     
        !           957:             IoReleaseCancelSpinLock(cancelIrql);
        !           958:             KeReleaseSpinLock(&deviceExtension->SpinLock, spinlockIrql);
        !           959:             IoCompleteRequest(currentIrp, IO_MOUSE_INCREMENT);
        !           960:     
        !           961:             //
        !           962:             // Reacquire the spinlocks.
        !           963:             //
        !           964:     
        !           965:             KeAcquireSpinLock(&deviceExtension->SpinLock, &spinlockIrql);
        !           966:             IoAcquireCancelSpinLock(&cancelIrql);
        !           967:     
        !           968:             //
        !           969:             // Dequeue the next packet (IRP) from the device work queue.
        !           970:             //
        !           971:     
        !           972:             packet = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue);
        !           973:             if (packet != NULL) {
        !           974:                 currentIrp =
        !           975:                     CONTAINING_RECORD(packet, IRP, Tail.Overlay.DeviceQueueEntry);
        !           976:             } else {
        !           977:                 currentIrp = (PIRP) NULL;
        !           978:             }
        !           979:     
        !           980:         } // end while
        !           981:     }
        !           982: 
        !           983:     //
        !           984:     // Release the spinlocks and lower IRQL.
        !           985:     //
        !           986: 
        !           987:     IoReleaseCancelSpinLock(cancelIrql);
        !           988:     KeReleaseSpinLock(&deviceExtension->SpinLock, spinlockIrql);
        !           989: 
        !           990:     //
        !           991:     // Complete the cleanup request with STATUS_SUCCESS.
        !           992:     //
        !           993: 
        !           994:     Irp->IoStatus.Status = STATUS_SUCCESS;
        !           995:     Irp->IoStatus.Information = 0;
        !           996:     IoCompleteRequest (Irp, IO_NO_INCREMENT);
        !           997: 
        !           998:     MouPrint((2,"MOUCLASS-MouseClassCleanup: exit\n"));
        !           999: 
        !          1000:     return(STATUS_SUCCESS);
        !          1001: 
        !          1002: }
        !          1003: 
        !          1004: NTSTATUS
        !          1005: MouseClassDeviceControl(
        !          1006:     IN PDEVICE_OBJECT DeviceObject,
        !          1007:     IN PIRP Irp
        !          1008:     )
        !          1009: 
        !          1010: /*++
        !          1011: 
        !          1012: Routine Description:
        !          1013: 
        !          1014:     This routine is the dispatch routine for device control requests.
        !          1015:     All device control subfunctions are passed, asynchronously, to the 
        !          1016:     connected port driver for processing and completion.
        !          1017: 
        !          1018: Arguments:
        !          1019: 
        !          1020:     DeviceObject - Pointer to class device object.
        !          1021: 
        !          1022:     Irp - Pointer to the request packet.
        !          1023: 
        !          1024: Return Value:
        !          1025: 
        !          1026:     Status is returned.
        !          1027: 
        !          1028: --*/
        !          1029: 
        !          1030: {
        !          1031:     PIO_STACK_LOCATION irpSp;
        !          1032:     PIO_STACK_LOCATION nextSp;
        !          1033:     PDEVICE_EXTENSION deviceExtension;
        !          1034:     NTSTATUS status = STATUS_SUCCESS;
        !          1035:     ULONG unitId;
        !          1036: 
        !          1037:     MouPrint((2,"MOUCLASS-MouseClassDeviceControl: enter\n"));
        !          1038: 
        !          1039:     //
        !          1040:     // Get a pointer to the device extension.
        !          1041:     //
        !          1042: 
        !          1043:     deviceExtension = DeviceObject->DeviceExtension;
        !          1044: 
        !          1045:     //
        !          1046:     // Get a pointer to the current parameters for this request.  The
        !          1047:     // information is contained in the current stack location.
        !          1048:     //
        !          1049: 
        !          1050:     irpSp = IoGetCurrentIrpStackLocation(Irp);
        !          1051: 
        !          1052:     //
        !          1053:     // Check for adequate input buffer length.  The input buffer
        !          1054:     // should, at a minimum, contain the unit ID specifying one of
        !          1055:     // the connected port devices.  If there is no input buffer (i.e.,
        !          1056:     // the input buffer length is zero), then we assume the unit ID 
        !          1057:     // is zero (for backwards compatibility).
        !          1058:     //
        !          1059: 
        !          1060:     if (irpSp->Parameters.DeviceIoControl.InputBufferLength == 0) {
        !          1061:         unitId = 0;
        !          1062:     } else if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
        !          1063:                   sizeof(MOUSE_UNIT_ID_PARAMETER)) {
        !          1064:         status = STATUS_BUFFER_TOO_SMALL;
        !          1065:         
        !          1066:     } else {
        !          1067:         unitId = ((PMOUSE_UNIT_ID_PARAMETER)
        !          1068:                      Irp->AssociatedIrp.SystemBuffer)->UnitId;
        !          1069:         if (unitId >= deviceExtension->MaximumPortsServiced) {
        !          1070:             status = STATUS_INVALID_PARAMETER; 
        !          1071:         }
        !          1072:     }
        !          1073: 
        !          1074:     if (NT_SUCCESS(status)) {
        !          1075: 
        !          1076:         //
        !          1077:         // Pass the device control request on to the port driver,
        !          1078:         // asynchronously.  Get the next IRP stack location and copy the 
        !          1079:         // input parameters to the next stack location.  Change the major 
        !          1080:         // function to internal device control.
        !          1081:         //
        !          1082:     
        !          1083:         nextSp = IoGetNextIrpStackLocation(Irp);
        !          1084:         ASSERT(nextSp != NULL);
        !          1085:         nextSp->Parameters.DeviceIoControl = 
        !          1086:             irpSp->Parameters.DeviceIoControl;
        !          1087:         nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
        !          1088:     
        !          1089:         //
        !          1090:         // Mark the packet pending.
        !          1091:         //
        !          1092:     
        !          1093:         IoMarkIrpPending(Irp);
        !          1094:     
        !          1095:         //
        !          1096:         // Pass the IRP on to the connected port device (specified by 
        !          1097:         // the unit ID).  The port device driver will process the request.
        !          1098:         //
        !          1099:     
        !          1100:         status = IoCallDriver(
        !          1101:                      deviceExtension->PortDeviceObjectList[unitId], 
        !          1102:                      Irp
        !          1103:                      );
        !          1104:     } else {
        !          1105: 
        !          1106:         //
        !          1107:         // Complete the request.
        !          1108:         //
        !          1109: 
        !          1110:         Irp->IoStatus.Status = status;
        !          1111:         Irp->IoStatus.Information = 0;
        !          1112:         IoCompleteRequest(Irp, IO_NO_INCREMENT);
        !          1113:     } 
        !          1114: 
        !          1115:     MouPrint((2,"MOUCLASS-MouseClassDeviceControl: exit\n"));
        !          1116: 
        !          1117:     return(status);
        !          1118: 
        !          1119: }
        !          1120: 
        !          1121: NTSTATUS
        !          1122: MouseClassFlush(
        !          1123:     IN PDEVICE_OBJECT DeviceObject,
        !          1124:     IN PIRP Irp
        !          1125:     )
        !          1126: 
        !          1127: /*++
        !          1128: 
        !          1129: Routine Description:
        !          1130: 
        !          1131:     This routine is the dispatch routine for flush requests.  The class
        !          1132:     input data queue is reinitialized.
        !          1133: 
        !          1134: Arguments:
        !          1135: 
        !          1136:     DeviceObject - Pointer to class device object.
        !          1137: 
        !          1138:     Irp - Pointer to the request packet.
        !          1139: 
        !          1140: Return Value:
        !          1141: 
        !          1142:     Status is returned.
        !          1143: 
        !          1144: --*/
        !          1145: 
        !          1146: {
        !          1147:     PDEVICE_EXTENSION deviceExtension;
        !          1148:     NTSTATUS status = STATUS_SUCCESS;
        !          1149: 
        !          1150:     MouPrint((2,"MOUCLASS-MouseClassFlush: enter\n"));
        !          1151: 
        !          1152:     //
        !          1153:     // Get a pointer to the device extension.
        !          1154:     //
        !          1155: 
        !          1156:     deviceExtension = DeviceObject->DeviceExtension;
        !          1157: 
        !          1158:     //
        !          1159:     // Initialize mouse class input data queue.
        !          1160:     //
        !          1161: 
        !          1162:     MouInitializeDataQueue((PVOID)deviceExtension);
        !          1163: 
        !          1164:     //
        !          1165:     // Complete the request and return status.
        !          1166:     //
        !          1167: 
        !          1168:     Irp->IoStatus.Status = status;
        !          1169:     Irp->IoStatus.Information = 0;
        !          1170:     IoCompleteRequest(Irp, IO_NO_INCREMENT);
        !          1171: 
        !          1172:     MouPrint((2,"MOUCLASS-MouseClassFlush: exit\n"));
        !          1173: 
        !          1174:     return(status);
        !          1175: 
        !          1176: } // end MouseClassFlush
        !          1177: 
        !          1178: NTSTATUS
        !          1179: MouseClassOpenClose(
        !          1180:     IN PDEVICE_OBJECT DeviceObject,
        !          1181:     IN PIRP Irp
        !          1182:     )
        !          1183: 
        !          1184: /*++
        !          1185: 
        !          1186: Routine Description:
        !          1187: 
        !          1188:     This routine is the dispatch routine for create/open and close requests.
        !          1189:     Open/close requests are completed here.
        !          1190: 
        !          1191: Arguments:
        !          1192: 
        !          1193:     DeviceObject - Pointer to class device object.
        !          1194: 
        !          1195:     Irp - Pointer to the request packet.
        !          1196: 
        !          1197: Return Value:
        !          1198: 
        !          1199:     Status is returned.
        !          1200: 
        !          1201: --*/
        !          1202: 
        !          1203: {
        !          1204:     PIO_STACK_LOCATION irpSp;
        !          1205:     PDEVICE_EXTENSION deviceExtension;
        !          1206:     KIRQL oldIrql;
        !          1207:     BOOLEAN enableFlag = FALSE;
        !          1208:     NTSTATUS status = STATUS_SUCCESS;
        !          1209:     PIO_ERROR_LOG_PACKET errorLogEntry;
        !          1210:     BOOLEAN SomeEnableDisableSucceeded = FALSE;
        !          1211:     ULONG i;
        !          1212: 
        !          1213:     MouPrint((2,"MOUCLASS-MouseClassOpenClose: enter\n"));
        !          1214: 
        !          1215:     //
        !          1216:     // Get a pointer to the device extension.
        !          1217:     //
        !          1218: 
        !          1219:     deviceExtension = DeviceObject->DeviceExtension;
        !          1220: 
        !          1221:     //
        !          1222:     // Get a pointer to the current parameters for this request.  The
        !          1223:     // information is contained in the current stack location.
        !          1224:     //
        !          1225: 
        !          1226:     irpSp = IoGetCurrentIrpStackLocation(Irp);
        !          1227: 
        !          1228:     //
        !          1229:     // Case on the function that is being performed by the requestor.
        !          1230:     //
        !          1231: 
        !          1232:     switch (irpSp->MajorFunction) {
        !          1233: 
        !          1234:         //
        !          1235:         // For the create/open operation, send a MOUSE_ENABLE internal 
        !          1236:         // device control request to the port driver to enable interrupts.
        !          1237:         //
        !          1238: 
        !          1239:         case IRP_MJ_CREATE:
        !          1240: 
        !          1241:             //
        !          1242:             // First, if the requestor is the trusted subsystem (the single
        !          1243:             // reader), reset the the cleanup indicator and set the file
        !          1244:             // object's FsContext to non-null (MouseClassRead uses
        !          1245:             // FsContext to determine if the requestor has sufficient
        !          1246:             // privilege to perform the read operation).
        !          1247:             //
        !          1248: 
        !          1249:             if (SeSinglePrivilegeCheck(RtlConvertLongToLargeInteger(
        !          1250:                                                  SE_TCB_PRIVILEGE),
        !          1251:                                                  Irp->RequestorMode 
        !          1252:                                                  )) {
        !          1253: 
        !          1254:                 KeAcquireSpinLock(&deviceExtension->SpinLock, &oldIrql);
        !          1255:                 deviceExtension->CleanupWasInitiated = FALSE;
        !          1256:                 irpSp->FileObject->FsContext = (PVOID) 1;
        !          1257:                 KeReleaseSpinLock(&deviceExtension->SpinLock, oldIrql);
        !          1258:             }
        !          1259: 
        !          1260:             enableFlag = TRUE;
        !          1261: 
        !          1262:             break;
        !          1263: 
        !          1264:         //
        !          1265:         // For the close operation, send a MOUSE_DISABLE internal device
        !          1266:         // control request to the port driver to disable interrupts.
        !          1267:         //
        !          1268: 
        !          1269:         case IRP_MJ_CLOSE:
        !          1270: 
        !          1271:             break;
        !          1272:     }
        !          1273: 
        !          1274:     //
        !          1275:     // Enable/disable interrupts via port driver.
        !          1276:     //
        !          1277: 
        !          1278:     for (i = 0; i < deviceExtension->MaximumPortsServiced; i++) {
        !          1279: 
        !          1280:         status = MouEnableDisablePort(DeviceObject, enableFlag, i);
        !          1281: 
        !          1282:         if (status != STATUS_SUCCESS) {
        !          1283: 
        !          1284:             MouPrint((
        !          1285:                 0,
        !          1286:                 "MOUCLASS-MouseClassOpenClose: Could not enable/disable interrupts for port device object @ 0x%x\n",
        !          1287:                 deviceExtension->PortDeviceObjectList[i]
        !          1288:                 ));
        !          1289: 
        !          1290:             //
        !          1291:             // Log an error.
        !          1292:             //
        !          1293: 
        !          1294:             errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
        !          1295:                                                      DeviceObject,
        !          1296:                                                      sizeof(IO_ERROR_LOG_PACKET)
        !          1297:                                                      );
        !          1298: 
        !          1299:             if (errorLogEntry != NULL) {
        !          1300: 
        !          1301:                 errorLogEntry->ErrorCode = 
        !          1302:                     enableFlag? MOUCLASS_PORT_INTERRUPTS_NOT_ENABLED:
        !          1303:                                 MOUCLASS_PORT_INTERRUPTS_NOT_DISABLED;
        !          1304:                 errorLogEntry->SequenceNumber = 0;
        !          1305:                 errorLogEntry->MajorFunctionCode = irpSp->MajorFunction;
        !          1306:                 errorLogEntry->IoControlCode = 0;
        !          1307:                 errorLogEntry->RetryCount = 0;
        !          1308:                 errorLogEntry->UniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 120;
        !          1309:                 errorLogEntry->FinalStatus = status;
        !          1310: 
        !          1311:                 IoWriteErrorLogEntry(errorLogEntry);
        !          1312:             }
        !          1313: 
        !          1314:         } else {
        !          1315:             SomeEnableDisableSucceeded = TRUE;
        !          1316:         }
        !          1317:     }
        !          1318: 
        !          1319:     //
        !          1320:     // Complete the request and return status.
        !          1321:     //
        !          1322:     // NOTE: We complete the request successfully if any one of the
        !          1323:     //       connected port devices successfully handled the request.
        !          1324:     //       The RIT only knows about one pointing device.
        !          1325:     //
        !          1326: 
        !          1327:     if (SomeEnableDisableSucceeded) {
        !          1328:         status = STATUS_SUCCESS;
        !          1329:     }
        !          1330: 
        !          1331:     Irp->IoStatus.Status = status;
        !          1332:     Irp->IoStatus.Information = 0;
        !          1333:     IoCompleteRequest(Irp, IO_NO_INCREMENT);
        !          1334: 
        !          1335:     MouPrint((2,"MOUCLASS-MouseClassOpenClose: exit\n"));
        !          1336: 
        !          1337:     return(status);
        !          1338: }
        !          1339: 
        !          1340: NTSTATUS
        !          1341: MouseClassRead(
        !          1342:     IN PDEVICE_OBJECT DeviceObject,
        !          1343:     IN PIRP Irp
        !          1344:     )
        !          1345: 
        !          1346: /*++
        !          1347: 
        !          1348: Routine Description:
        !          1349: 
        !          1350:     This routine is the dispatch routine for read requests.  Valid read
        !          1351:     requests are marked pending, and started via IoStartPacket.
        !          1352: 
        !          1353: Arguments:
        !          1354: 
        !          1355:     DeviceObject - Pointer to class device object.
        !          1356: 
        !          1357:     Irp - Pointer to the request packet.
        !          1358: 
        !          1359: Return Value:
        !          1360: 
        !          1361:     Status is returned.
        !          1362: 
        !          1363: --*/
        !          1364: 
        !          1365: {
        !          1366:     NTSTATUS status;
        !          1367:     PIO_STACK_LOCATION irpSp;
        !          1368: 
        !          1369:     MouPrint((2,"MOUCLASS-MouseClassRead: enter\n"));
        !          1370: 
        !          1371:     irpSp = IoGetCurrentIrpStackLocation(Irp);
        !          1372: 
        !          1373:     //
        !          1374:     // Validate the read request parameters.  The read length should be an
        !          1375:     // integral number of MOUSE_INPUT_DATA structures.
        !          1376:     //
        !          1377: 
        !          1378: 
        !          1379:     if (irpSp->Parameters.Read.Length == 0) {
        !          1380:         status = STATUS_SUCCESS;
        !          1381:     }
        !          1382:     else if (irpSp->Parameters.Read.Length % sizeof(MOUSE_INPUT_DATA)) {
        !          1383:         status = STATUS_BUFFER_TOO_SMALL;
        !          1384:     } 
        !          1385:     else if (irpSp->FileObject->FsContext) {
        !          1386: 
        !          1387:         //
        !          1388:         // If the file object's FsContext is non-null, then we've already 
        !          1389:         // done the Read privilege check once before for this thread.  Skip 
        !          1390:         // the privilege check.
        !          1391:         //
        !          1392: 
        !          1393:         status = STATUS_PENDING;
        !          1394:     }
        !          1395:     else {
        !          1396: 
        !          1397:         //
        !          1398:         // We only allow a trusted subsystem with the appropriate privilege 
        !          1399:         // level to execute a Read call.
        !          1400:         //
        !          1401: 
        !          1402:         status = STATUS_PRIVILEGE_NOT_HELD;
        !          1403: 
        !          1404: 
        !          1405:     }
        !          1406: 
        !          1407:     //
        !          1408:     // If status is pending, mark the packet pending and start the packet
        !          1409:     // in a cancellable state.  Otherwise, complete the request.
        !          1410:     //
        !          1411: 
        !          1412:     Irp->IoStatus.Status = status;
        !          1413:     Irp->IoStatus.Information = 0;
        !          1414:     if (status == STATUS_PENDING) {
        !          1415:         IoMarkIrpPending(Irp);
        !          1416:         IoStartPacket(DeviceObject, Irp, (PULONG)NULL, MouseClassCancel);
        !          1417:     } else {
        !          1418:         IoCompleteRequest(Irp, IO_NO_INCREMENT);
        !          1419:     }
        !          1420: 
        !          1421:     MouPrint((2,"MOUCLASS-MouseClassRead: exit\n"));
        !          1422: 
        !          1423:     return(status);
        !          1424: 
        !          1425: }
        !          1426: 
        !          1427: VOID
        !          1428: MouseClassServiceCallback(
        !          1429:     IN PDEVICE_OBJECT DeviceObject,
        !          1430:     IN PMOUSE_INPUT_DATA InputDataStart,
        !          1431:     IN PMOUSE_INPUT_DATA InputDataEnd,
        !          1432:     IN OUT PULONG InputDataConsumed
        !          1433:     )
        !          1434: 
        !          1435: /*++
        !          1436: 
        !          1437: Routine Description:
        !          1438: 
        !          1439:     This routine is the class service callback routine.  It is
        !          1440:     called from the port driver's interrupt service DPC.  If there is an
        !          1441:     outstanding read request, the request is satisfied from the port input
        !          1442:     data queue.  Unsolicited mouse input is moved from the port input
        !          1443:     data queue to the class input data queue.
        !          1444: 
        !          1445:     N.B.  This routine is entered at DISPATCH_LEVEL IRQL from the port
        !          1446:           driver's ISR DPC routine.
        !          1447: 
        !          1448: Arguments:
        !          1449: 
        !          1450:     DeviceObject - Pointer to class device object.
        !          1451: 
        !          1452:     InputDataStart - Pointer to the start of the data in the port input
        !          1453:         data queue.
        !          1454: 
        !          1455:     InputDataEnd - Points one input data structure past the end of the
        !          1456:         valid port input data.
        !          1457: 
        !          1458:     InputDataConsumed - Pointer to storage in which the number of input
        !          1459:         data structures consumed by this call is returned.
        !          1460: 
        !          1461:     NOTE:  Could pull the duplicate code out into a called procedure.
        !          1462: 
        !          1463: Return Value:
        !          1464: 
        !          1465:     None.
        !          1466: 
        !          1467: --*/
        !          1468: 
        !          1469: {
        !          1470:     PDEVICE_EXTENSION deviceExtension;
        !          1471:     PIO_STACK_LOCATION irpSp;
        !          1472:     PIRP  irp;
        !          1473:     KIRQL cancelIrql;
        !          1474:     ULONG bytesInQueue;
        !          1475:     ULONG bytesToMove;
        !          1476:     ULONG moveSize;
        !          1477:     BOOLEAN satisfiedPendingReadRequest = FALSE;
        !          1478:     PIO_ERROR_LOG_PACKET errorLogEntry;
        !          1479: 
        !          1480:     MouPrint((2,"MOUCLASS-MouseClassServiceCallback: enter\n"));
        !          1481: 
        !          1482:     deviceExtension = DeviceObject->DeviceExtension;
        !          1483:     bytesInQueue = (PCHAR) InputDataEnd - (PCHAR) InputDataStart;
        !          1484:     moveSize = 0;
        !          1485:     *InputDataConsumed = 0;
        !          1486: 
        !          1487:     //
        !          1488:     // Acquire the spinlock that  protects the class device extension 
        !          1489:     // (so we can look at RequestIsPending synchronously).  If there is
        !          1490:     // a pending read request, satisfy it.
        !          1491:     //
        !          1492:     // N.B. We can use KeAcquireSpinLockAtDpcLevel, instead of
        !          1493:     //      KeAcquireSpinLock, because this routine is already running
        !          1494:     //      at DISPATCH_IRQL.
        !          1495:     //
        !          1496: 
        !          1497:     KeAcquireSpinLockAtDpcLevel(&deviceExtension->SpinLock);
        !          1498: 
        !          1499:     if (deviceExtension->RequestIsPending) {
        !          1500: 
        !          1501:         //
        !          1502:         // Acquire the cancel spinlock, remove the request from the 
        !          1503:         // cancellable state, and free the cancel spinlock.
        !          1504:         //
        !          1505: 
        !          1506:         IoAcquireCancelSpinLock(&cancelIrql);
        !          1507:         irp = DeviceObject->CurrentIrp;
        !          1508:         IoSetCancelRoutine(irp, NULL);
        !          1509:         DeviceObject->CurrentIrp = NULL;
        !          1510:         IoReleaseCancelSpinLock(cancelIrql);
        !          1511: 
        !          1512:         //
        !          1513:         // An outstanding read request exists.   Clear the RequestIsPending 
        !          1514:         // flag to indicate there is no longer an outstanding read request 
        !          1515:         // pending.
        !          1516:         //
        !          1517: 
        !          1518:         deviceExtension->RequestIsPending = FALSE;
        !          1519: 
        !          1520:         //
        !          1521:         // Copy as much of the input data possible from the port input
        !          1522:         // data queue to the SystemBuffer to satisfy the read.
        !          1523:         //
        !          1524: 
        !          1525:         irpSp = IoGetCurrentIrpStackLocation(irp);
        !          1526:         bytesToMove = irpSp->Parameters.Read.Length;
        !          1527:         moveSize = (bytesInQueue < bytesToMove) ?
        !          1528:                                    bytesInQueue:bytesToMove;
        !          1529:         *InputDataConsumed += (moveSize / sizeof(MOUSE_INPUT_DATA));
        !          1530: 
        !          1531:         MouPrint((
        !          1532:             3,
        !          1533:             "MOUCLASS-MouseClassServiceCallback: port queue length 0x%lx, read length 0x%lx\n",
        !          1534:             bytesInQueue,
        !          1535:             bytesToMove
        !          1536:             ));
        !          1537:         MouPrint((
        !          1538:             3,
        !          1539:             "MOUCLASS-MouseClassServiceCallback: number of bytes to move from port to SystemBuffer 0x%lx\n",
        !          1540:             moveSize
        !          1541:             ));
        !          1542:         MouPrint((
        !          1543:             3,
        !          1544:             "MOUCLASS-MouseClassServiceCallback: move bytes from 0x%lx to 0x%lx\n",
        !          1545:             (PCHAR) InputDataStart,
        !          1546:             irp->AssociatedIrp.SystemBuffer
        !          1547:             ));
        !          1548: 
        !          1549:         RtlMoveMemory(
        !          1550:             irp->AssociatedIrp.SystemBuffer,
        !          1551:             (PCHAR) InputDataStart,
        !          1552:             moveSize
        !          1553:             );
        !          1554: 
        !          1555:         //
        !          1556:         // Set the flag so that we start the next packet and complete 
        !          1557:         // this read request (with STATUS_SUCCESS) prior to return.
        !          1558:         //
        !          1559: 
        !          1560:         irp->IoStatus.Status = STATUS_SUCCESS;
        !          1561:         irp->IoStatus.Information = moveSize;
        !          1562:         irpSp->Parameters.Read.Length = moveSize;
        !          1563:         satisfiedPendingReadRequest = TRUE;
        !          1564: 
        !          1565:     }
        !          1566: 
        !          1567:     //
        !          1568:     // If there is still data in the port input data queue, move it to the class
        !          1569:     // input data queue.
        !          1570:     //
        !          1571: 
        !          1572:     InputDataStart = (PMOUSE_INPUT_DATA) ((PCHAR) InputDataStart + moveSize);
        !          1573:     moveSize = bytesInQueue - moveSize;
        !          1574: 
        !          1575:     MouPrint((
        !          1576:         3,
        !          1577:         "MOUCLASS-MouseClassServiceCallback: bytes remaining after move to SystemBuffer 0x%lx\n",
        !          1578:         moveSize
        !          1579:         ));
        !          1580: 
        !          1581:     if (moveSize > 0) {
        !          1582: 
        !          1583:         //
        !          1584:         // Move the remaining data from the port input data queue to
        !          1585:         // the class input data queue.  The move will happen in two
        !          1586:         // parts in the case where the class input data buffer wraps.
        !          1587:         //
        !          1588: 
        !          1589:         bytesInQueue =
        !          1590:             deviceExtension->MouseAttributes.InputDataQueueLength -
        !          1591:             (deviceExtension->InputCount * sizeof(MOUSE_INPUT_DATA));
        !          1592:         bytesToMove = moveSize;
        !          1593: 
        !          1594:         MouPrint((
        !          1595:             3,
        !          1596:             "MOUCLASS-MouseClassServiceCallback: unused bytes in class queue 0x%lx, remaining bytes in port queue 0x%lx\n",
        !          1597:             bytesInQueue,
        !          1598:             bytesToMove
        !          1599:             ));
        !          1600: 
        !          1601:         if (bytesInQueue == 0) {
        !          1602: 
        !          1603:             //
        !          1604:             // Refuse to move any bytes that would cause a class input data 
        !          1605:             // queue overflow.  Just drop the bytes on the floor, and
        !          1606:             // log an overrun error.
        !          1607:             //
        !          1608: 
        !          1609:             MouPrint((
        !          1610:                 1,
        !          1611:                 "MOUCLASS-MouseClassServiceCallback: Class input data queue OVERRUN\n"
        !          1612:                 ));
        !          1613: 
        !          1614:             if (deviceExtension->OkayToLogOverflow) {
        !          1615: 
        !          1616:                 //
        !          1617:                 // Log an error.
        !          1618:                 //
        !          1619:         
        !          1620:                 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
        !          1621:                                                          DeviceObject,
        !          1622:                                                          sizeof(IO_ERROR_LOG_PACKET)
        !          1623:                                                          + (2 * sizeof(ULONG))
        !          1624:                                                          );
        !          1625:         
        !          1626:                 if (errorLogEntry != NULL) {
        !          1627:         
        !          1628:                     errorLogEntry->ErrorCode = MOUCLASS_MOU_BUFFER_OVERFLOW;
        !          1629:                     errorLogEntry->DumpDataSize = 2 * sizeof(ULONG);
        !          1630:                     errorLogEntry->SequenceNumber = 0;
        !          1631:                     errorLogEntry->MajorFunctionCode = 0;
        !          1632:                     errorLogEntry->IoControlCode = 0;
        !          1633:                     errorLogEntry->RetryCount = 0;
        !          1634:                     errorLogEntry->UniqueErrorValue = 
        !          1635:                         MOUSE_ERROR_VALUE_BASE + 210;
        !          1636:                     errorLogEntry->FinalStatus = 0;
        !          1637:                     errorLogEntry->DumpData[0] = bytesToMove;
        !          1638:                     errorLogEntry->DumpData[1] = 
        !          1639:                         deviceExtension->MouseAttributes.InputDataQueueLength;
        !          1640:         
        !          1641:                     IoWriteErrorLogEntry(errorLogEntry);
        !          1642:                 }
        !          1643: 
        !          1644:                 deviceExtension->OkayToLogOverflow = FALSE;
        !          1645:             }
        !          1646: 
        !          1647:         } else {
        !          1648: 
        !          1649:             //
        !          1650:             // There is room in the class input data queue, so move
        !          1651:             // the remaining port input data to it.
        !          1652:             //
        !          1653:             // bytesToMove <- MIN(Number of unused bytes in class input data 
        !          1654:             //                    queue, Number of bytes remaining in port 
        !          1655:             //                    input queue).
        !          1656:             // This is the total number of bytes that actually will move from 
        !          1657:             // the port input data queue to the class input data queue.
        !          1658:             //
        !          1659: 
        !          1660: 
        !          1661:             bytesToMove = (bytesInQueue < bytesToMove) ?
        !          1662:                                           bytesInQueue:bytesToMove;
        !          1663: 
        !          1664:             //
        !          1665:             // bytesInQueue <- Number of unused bytes from insertion pointer to
        !          1666:             // the end of the class input data queue (i.e., until the buffer
        !          1667:             // wraps).
        !          1668:             //
        !          1669:     
        !          1670:             bytesInQueue = ((PCHAR) deviceExtension->InputData +
        !          1671:                         deviceExtension->MouseAttributes.InputDataQueueLength) -
        !          1672:                         (PCHAR) deviceExtension->DataIn;
        !          1673:             MouPrint((
        !          1674:                 3,
        !          1675:                 "MOUCLASS-MouseClassServiceCallback: total number of bytes to move to class queue 0x%lx\n",
        !          1676:                 bytesToMove
        !          1677:                 ));
        !          1678:     
        !          1679:             MouPrint((
        !          1680:                 3,
        !          1681:                 "MOUCLASS-MouseClassServiceCallback: number of bytes to end of class buffer 0x%lx\n",
        !          1682:                 bytesInQueue
        !          1683:                 ));
        !          1684:     
        !          1685:             //
        !          1686:             // moveSize <- Number of bytes to handle in the first move.
        !          1687:             //
        !          1688:     
        !          1689:             moveSize = (bytesToMove < bytesInQueue) ?
        !          1690:                                       bytesToMove:bytesInQueue;
        !          1691:             MouPrint((
        !          1692:                 3,
        !          1693:                 "MOUCLASS-MouseClassServiceCallback: number of bytes in first move to class 0x%lx\n",
        !          1694:                 moveSize
        !          1695:                 ));
        !          1696:     
        !          1697:             //
        !          1698:             // Do the move from the port data queue to the class data queue.
        !          1699:             //
        !          1700:     
        !          1701:             MouPrint((
        !          1702:                 3,
        !          1703:                 "MOUCLASS-MouseClassServiceCallback: move bytes from 0x%lx to 0x%lx\n",
        !          1704:                 (PCHAR) InputDataStart,
        !          1705:                 (PCHAR) deviceExtension->DataIn
        !          1706:                 ));
        !          1707: 
        !          1708:             RtlMoveMemory(
        !          1709:                 (PCHAR) deviceExtension->DataIn,
        !          1710:                 (PCHAR) InputDataStart,
        !          1711:                 moveSize
        !          1712:                 );
        !          1713:     
        !          1714:             //
        !          1715:             // Increment the port data queue pointer and the class input
        !          1716:             // data queue insertion pointer.  Wrap the insertion pointer,
        !          1717:             // if necessary.
        !          1718:             //
        !          1719:     
        !          1720:             InputDataStart = (PMOUSE_INPUT_DATA)
        !          1721:                              (((PCHAR) InputDataStart) + moveSize);
        !          1722:             deviceExtension->DataIn = (PMOUSE_INPUT_DATA)
        !          1723:                                  (((PCHAR) deviceExtension->DataIn) + moveSize);
        !          1724:             if ((PCHAR) deviceExtension->DataIn >=
        !          1725:                 ((PCHAR) deviceExtension->InputData +
        !          1726:                  deviceExtension->MouseAttributes.InputDataQueueLength)) {
        !          1727:                 deviceExtension->DataIn = deviceExtension->InputData;
        !          1728:             }
        !          1729:     
        !          1730:             if ((bytesToMove - moveSize) > 0) {
        !          1731:     
        !          1732:                 //
        !          1733:                 // Special case.  The data must wrap in the class input data buffer.
        !          1734:                 // Copy the rest of the port input data into the beginning of the
        !          1735:                 // class input data queue.
        !          1736:                 //
        !          1737:     
        !          1738:                 //
        !          1739:                 // moveSize <- Number of bytes to handle in the second move.
        !          1740:                 //
        !          1741:     
        !          1742:                 moveSize = bytesToMove - moveSize;
        !          1743:     
        !          1744:                 //
        !          1745:                 // Do the move from the port data queue to the class data queue.
        !          1746:                 //
        !          1747:     
        !          1748:                 MouPrint((
        !          1749:                     3,
        !          1750:                     "MOUCLASS-MouseClassServiceCallback: number of bytes in second move to class 0x%lx\n",
        !          1751:                     moveSize
        !          1752:                     ));
        !          1753:                 MouPrint((
        !          1754:                     3,
        !          1755:                     "MOUCLASS-MouseClassServiceCallback: move bytes from 0x%lx to 0x%lx\n",
        !          1756:                     (PCHAR) InputDataStart,
        !          1757:                     (PCHAR) deviceExtension->DataIn
        !          1758:                     ));
        !          1759:     
        !          1760:                 RtlMoveMemory(
        !          1761:                     (PCHAR) deviceExtension->DataIn,
        !          1762:                     (PCHAR) InputDataStart,
        !          1763:                     moveSize
        !          1764:                     );
        !          1765:     
        !          1766:                 //
        !          1767:                 // Update the class input data queue insertion pointer.
        !          1768:                 //
        !          1769:     
        !          1770:                 deviceExtension->DataIn = (PMOUSE_INPUT_DATA)
        !          1771:                                  (((PCHAR) deviceExtension->DataIn) + moveSize);
        !          1772:             }
        !          1773:     
        !          1774:             //
        !          1775:             // Update the input data queue counter.
        !          1776:             //
        !          1777:     
        !          1778:             deviceExtension->InputCount +=
        !          1779:                     (bytesToMove / sizeof(MOUSE_INPUT_DATA));
        !          1780:             *InputDataConsumed += (bytesToMove / sizeof(MOUSE_INPUT_DATA));
        !          1781: 
        !          1782:             MouPrint((
        !          1783:                 3,
        !          1784:                 "MOUCLASS-MouseClassServiceCallback: changed InputCount to %ld entries in the class queue\n",
        !          1785:                 deviceExtension->InputCount
        !          1786:                 ));
        !          1787:             MouPrint((
        !          1788:                 3,
        !          1789:                 "MOUCLASS-MouseClassServiceCallback: DataIn 0x%lx, DataOut 0x%lx\n",
        !          1790:                 deviceExtension->DataIn,
        !          1791:                 deviceExtension->DataOut
        !          1792:                 ));
        !          1793:             MouPrint((
        !          1794:                 3,
        !          1795:                 "MOUCLASS-MouseClassServiceCallback: Input data items consumed = %d\n",
        !          1796:                 *InputDataConsumed
        !          1797:                 ));
        !          1798:         }
        !          1799:     }
        !          1800: 
        !          1801:     //
        !          1802:     // Release the class input data queue spinlock.
        !          1803:     //
        !          1804: 
        !          1805:     KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
        !          1806: 
        !          1807:     // 
        !          1808:     // If we satisfied an outstanding read request, start the next
        !          1809:     // packet and complete the request.
        !          1810:     // 
        !          1811: 
        !          1812:     if (satisfiedPendingReadRequest) {
        !          1813: 
        !          1814:         IoStartNextPacket(DeviceObject, TRUE);
        !          1815:         IoCompleteRequest(irp, IO_MOUSE_INCREMENT);
        !          1816:     }
        !          1817: 
        !          1818:     MouPrint((2,"MOUCLASS-MouseClassServiceCallback: exit\n"));
        !          1819: 
        !          1820:     return;
        !          1821: 
        !          1822: }
        !          1823: 
        !          1824: VOID
        !          1825: MouseClassStartIo(
        !          1826:     IN PDEVICE_OBJECT DeviceObject,
        !          1827:     IN PIRP Irp
        !          1828:     )
        !          1829: 
        !          1830: /*++
        !          1831: 
        !          1832: Routine Description:
        !          1833: 
        !          1834:     This routine is the StartIo routine.  It is invoked to start a Read
        !          1835:     request.  If the class input data queue contains input data, the input
        !          1836:     data is copied to the SystemBuffer to satisfy the read.
        !          1837: 
        !          1838:     N.B.  Requests enter MouseClassStartIo in a cancellable state.  Also,
        !          1839:           there is an implicit assumption that only read requests are
        !          1840:           queued to the device queue (and handled by StartIo).  If this
        !          1841:           changes in the future, the MouseClassCleanup routine will
        !          1842:           be impacted.
        !          1843: 
        !          1844:     NOTE:  Could pull the duplicate code out into a called procedure.
        !          1845: 
        !          1846: Arguments:
        !          1847: 
        !          1848:     DeviceObject - Pointer to class device object.
        !          1849: 
        !          1850:     Irp - Pointer to the request packet.
        !          1851: 
        !          1852: Return Value:
        !          1853: 
        !          1854:     None.
        !          1855: 
        !          1856: --*/
        !          1857: 
        !          1858: {
        !          1859:     PDEVICE_EXTENSION deviceExtension;
        !          1860:     PIO_STACK_LOCATION irpSp;
        !          1861:     KIRQL cancelIrql;
        !          1862:     PCHAR destination;
        !          1863:     ULONG bytesInQueue;
        !          1864:     ULONG bytesToMove;
        !          1865:     ULONG moveSize;
        !          1866: 
        !          1867:     MouPrint((2,"MOUCLASS-MouseClassStartIo: enter\n"));
        !          1868: 
        !          1869:     deviceExtension = DeviceObject->DeviceExtension;
        !          1870: 
        !          1871:     //
        !          1872:     // Bump the error log sequence number.
        !          1873:     //
        !          1874: 
        !          1875:     deviceExtension->SequenceNumber += 1;
        !          1876: 
        !          1877:     //
        !          1878:     // Acquire the spinlock to protect the input data queue and associated
        !          1879:     // pointers.  Note that StartIo is already running at DISPATCH_LEVEL
        !          1880:     // IRQL, so we can use KeAcquireSpinLockAtDpcLevel instead of
        !          1881:     // KeAcquireSpinLock.
        !          1882:     //
        !          1883: 
        !          1884:     KeAcquireSpinLockAtDpcLevel(&deviceExtension->SpinLock);
        !          1885: 
        !          1886:     //
        !          1887:     // Acquire the cancel spinlock and verify that the Irp has not been
        !          1888:     // cancelled and that cleanup is not in progress.
        !          1889:     //
        !          1890: 
        !          1891:     IoAcquireCancelSpinLock(&cancelIrql);
        !          1892:     if (Irp->Cancel || deviceExtension->CleanupWasInitiated) {
        !          1893:         IoReleaseCancelSpinLock(cancelIrql);
        !          1894:         KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
        !          1895:         return;
        !          1896:     }
        !          1897: 
        !          1898:     MouPrint((
        !          1899:         3,
        !          1900:         "MOUCLASS-MouseClassStartIo: DataIn 0x%lx, DataOut 0x%lx\n",
        !          1901:         deviceExtension->DataIn, deviceExtension->DataOut
        !          1902:         ));
        !          1903: 
        !          1904:     MouPrint((
        !          1905:         3,
        !          1906:         "MOUCLASS-MouseClassStartIo: entries in queue %ld\n",
        !          1907:         deviceExtension->InputCount
        !          1908:         ));
        !          1909: 
        !          1910:     //
        !          1911:     // If the input data queue is non-empty, satisfy the read request.
        !          1912:     // Otherwise, hold the request pending.
        !          1913:     //
        !          1914: 
        !          1915:     if (deviceExtension->InputCount != 0) {
        !          1916: 
        !          1917:         //
        !          1918:         // Copy as much of the input data as possible from the class input
        !          1919:         // data queue to the SystemBuffer to satisfy the read.  It may be
        !          1920:         // necessary to copy the data in two chunks (i.e., if the circular
        !          1921:         // queue wraps).
        !          1922:         // First, remove the request from the cancellable state, and free the
        !          1923:         // cancel spinlock.
        !          1924:         //
        !          1925: 
        !          1926:         IoSetCancelRoutine(Irp, NULL);
        !          1927:         DeviceObject->CurrentIrp = NULL;
        !          1928:         IoReleaseCancelSpinLock(cancelIrql);
        !          1929: 
        !          1930:         irpSp = IoGetCurrentIrpStackLocation(Irp);
        !          1931: 
        !          1932:         //
        !          1933:         // bytesToMove <- MIN(Number of filled bytes in class input data queue,
        !          1934:         //                    Requested read length).
        !          1935:         //
        !          1936: 
        !          1937:         bytesInQueue = deviceExtension->InputCount *
        !          1938:                            sizeof(MOUSE_INPUT_DATA);
        !          1939:         bytesToMove = irpSp->Parameters.Read.Length;
        !          1940:         MouPrint((
        !          1941:             3,
        !          1942:             "MOUCLASS-MouseClassStartIo: queue size 0x%lx, read length 0x%lx\n",
        !          1943:             bytesInQueue,
        !          1944:             bytesToMove
        !          1945:             ));
        !          1946:         bytesToMove = (bytesInQueue < bytesToMove) ?
        !          1947:                                       bytesInQueue:bytesToMove;
        !          1948: 
        !          1949:         //
        !          1950:         // moveSize <- MIN(Number of bytes to be moved from the class queue,
        !          1951:         //                 Number of bytes to end of class input data queue).
        !          1952:         //
        !          1953: 
        !          1954:         bytesInQueue = ((PCHAR) deviceExtension->InputData +
        !          1955:                     deviceExtension->MouseAttributes.InputDataQueueLength) -
        !          1956:                     (PCHAR) deviceExtension->DataOut;
        !          1957:         moveSize = (bytesToMove < bytesInQueue) ?
        !          1958:                                   bytesToMove:bytesInQueue;
        !          1959:         MouPrint((
        !          1960:             3,
        !          1961:             "MOUCLASS-MouseClassStartIo: bytes to end of queue 0x%lx\n",
        !          1962:             bytesInQueue
        !          1963:             ));
        !          1964: 
        !          1965:         //
        !          1966:         // Move bytes from the class input data queue to SystemBuffer, until
        !          1967:         // the request is satisfied or we wrap the class input data buffer.
        !          1968:         //
        !          1969: 
        !          1970:         destination = Irp->AssociatedIrp.SystemBuffer;
        !          1971:         MouPrint((
        !          1972:             3,
        !          1973:             "MOUCLASS-MouseClassStartIo: number of bytes in first move 0x%lx\n",
        !          1974:             moveSize
        !          1975:             ));
        !          1976:         MouPrint((
        !          1977:             3,
        !          1978:             "MOUCLASS-MouseClassStartIo: move bytes from 0x%lx to 0x%lx\n",
        !          1979:             (PCHAR) deviceExtension->DataOut,
        !          1980:             destination
        !          1981:             ));
        !          1982: 
        !          1983:         RtlMoveMemory(
        !          1984:             destination,
        !          1985:             (PCHAR) deviceExtension->DataOut,
        !          1986:             moveSize
        !          1987:             );
        !          1988:         destination += moveSize;
        !          1989: 
        !          1990:         //
        !          1991:         // If the data wraps in the class input data buffer, copy the rest
        !          1992:         // of the data from the start of the input data queue
        !          1993:         // buffer through the end of the queued data.
        !          1994:         //
        !          1995: 
        !          1996:         if ((bytesToMove - moveSize) > 0) {
        !          1997: 
        !          1998:             //
        !          1999:             // moveSize <- Remaining number bytes to move.
        !          2000:             //
        !          2001: 
        !          2002:             moveSize = bytesToMove - moveSize;
        !          2003: 
        !          2004:             //
        !          2005:             // Move the bytes from the class input data queue to SystemBuffer.
        !          2006:             //
        !          2007: 
        !          2008:             MouPrint((
        !          2009:                 3,
        !          2010:                 "MOUCLASS-MouseClassStartIo: number of bytes in second move 0x%lx\n",
        !          2011:                 moveSize
        !          2012:                 ));
        !          2013:             MouPrint((
        !          2014:                 3,
        !          2015:                 "MOUCLASS-MouseClassStartIo: move bytes from 0x%lx to 0x%lx\n",
        !          2016:                 (PCHAR) deviceExtension->InputData,
        !          2017:                 destination
        !          2018:                 ));
        !          2019: 
        !          2020:             RtlMoveMemory(
        !          2021:                 destination,
        !          2022:                 (PCHAR) deviceExtension->InputData,
        !          2023:                 moveSize
        !          2024:                 );
        !          2025: 
        !          2026:             //
        !          2027:             // Update the class input data queue removal pointer.
        !          2028:             //
        !          2029: 
        !          2030:             deviceExtension->DataOut = (PMOUSE_INPUT_DATA)
        !          2031:                              (((PCHAR) deviceExtension->InputData) + moveSize);
        !          2032:         } else {
        !          2033: 
        !          2034:             //
        !          2035:             // Update the input data queue removal pointer.
        !          2036:             //
        !          2037: 
        !          2038:             deviceExtension->DataOut = (PMOUSE_INPUT_DATA)
        !          2039:                              (((PCHAR) deviceExtension->DataOut) + moveSize);
        !          2040:         }
        !          2041: 
        !          2042:         //
        !          2043:         // Update the class input data queue InputCount.
        !          2044:         //
        !          2045: 
        !          2046:         deviceExtension->InputCount -=
        !          2047:             (bytesToMove / sizeof(MOUSE_INPUT_DATA));
        !          2048: 
        !          2049:         if (deviceExtension->InputCount == 0) {
        !          2050: 
        !          2051:             //
        !          2052:             // Reset the flag that determines whether it is time to log
        !          2053:             // queue overflow errors.  We don't want to log errors too often.
        !          2054:             // Instead, log an error on the first overflow that occurs after
        !          2055:             // the ring buffer has been emptied, and then stop logging errors
        !          2056:             // until it gets cleared out and overflows again.
        !          2057:             //
        !          2058:     
        !          2059:             MouPrint((
        !          2060:                 1,
        !          2061:                 "MOUCLASS-MouseClassStartIo: Okay to log overflow\n"
        !          2062:                 ));
        !          2063:             deviceExtension->OkayToLogOverflow = TRUE;
        !          2064:         }
        !          2065: 
        !          2066:         MouPrint((
        !          2067:             3,
        !          2068:             "MOUCLASS-MouseClassStartIo: new DataIn 0x%lx, DataOut 0x%lx\n",
        !          2069:             deviceExtension->DataIn,
        !          2070:             deviceExtension->DataOut
        !          2071:             ));
        !          2072:         MouPrint((
        !          2073:             3,
        !          2074:             "MOUCLASS-MouseClassStartIo: new InputCount %ld\n",
        !          2075:             deviceExtension->InputCount
        !          2076:             ));
        !          2077: 
        !          2078:         //
        !          2079:         // Clear the RequestIsPending flag to indicate this request is
        !          2080:         // not held pending.
        !          2081:         //
        !          2082: 
        !          2083:         deviceExtension->RequestIsPending = FALSE;
        !          2084: 
        !          2085:         //
        !          2086:         // Release the class input data queue spinlock.
        !          2087:         //
        !          2088: 
        !          2089:         KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
        !          2090: 
        !          2091:         //
        !          2092:         // Start the next packet, and complete this read request
        !          2093:         // with STATUS_SUCCESS.
        !          2094:         //
        !          2095: 
        !          2096:         Irp->IoStatus.Status = STATUS_SUCCESS;
        !          2097:         Irp->IoStatus.Information = bytesToMove;
        !          2098:         irpSp->Parameters.Read.Length = bytesToMove;
        !          2099: 
        !          2100:         IoStartNextPacket(DeviceObject, TRUE);
        !          2101:         IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
        !          2102: 
        !          2103:     } else {
        !          2104: 
        !          2105:         //
        !          2106:         // Set the RequestIsPending flag to indicate this request is
        !          2107:         // held pending for the callback routine to complete.
        !          2108:         //
        !          2109: 
        !          2110:         deviceExtension->RequestIsPending = TRUE;
        !          2111: 
        !          2112:         //
        !          2113:         // Hold the read request pending.  It remains in the cancellable
        !          2114:         // state.  When new input is received, the class service
        !          2115:         // callback routine will eventually complete the request.  For now,
        !          2116:         // merely free the cancel spinlock and the class input data queue
        !          2117:         // spinlock.
        !          2118:         //
        !          2119: 
        !          2120:         IoReleaseCancelSpinLock(cancelIrql);
        !          2121:         KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
        !          2122:     }
        !          2123: 
        !          2124:     MouPrint((2,"MOUCLASS-MouseClassStartIo: exit\n"));
        !          2125: 
        !          2126:     return;
        !          2127: 
        !          2128: }
        !          2129: 
        !          2130: VOID
        !          2131: MouseClassUnload(
        !          2132:     IN PDRIVER_OBJECT DriverObject
        !          2133:     )
        !          2134: 
        !          2135: /*++
        !          2136: 
        !          2137: Routine Description:
        !          2138: 
        !          2139:     This routine is the class driver unload routine.
        !          2140: 
        !          2141:     NOTE:  Not currently implemented.
        !          2142: 
        !          2143: Arguments:
        !          2144: 
        !          2145:     DeviceObject - Pointer to class device object.
        !          2146: 
        !          2147: Return Value:
        !          2148: 
        !          2149:     None.
        !          2150: 
        !          2151: --*/
        !          2152: 
        !          2153: {
        !          2154:     UNREFERENCED_PARAMETER(DriverObject);
        !          2155: 
        !          2156:     MouPrint((2,"MOUCLASS-MouseClassUnload: enter\n"));
        !          2157:     MouPrint((2,"MOUCLASS-MouseClassUnload: exit\n"));
        !          2158: 
        !          2159:     return;
        !          2160: }
        !          2161: 
        !          2162: VOID
        !          2163: MouConfiguration(
        !          2164:     IN PDEVICE_EXTENSION DeviceExtension,
        !          2165:     IN PUNICODE_STRING RegistryPath,
        !          2166:     IN PUNICODE_STRING DeviceName
        !          2167: )
        !          2168: 
        !          2169: /*++
        !          2170: 
        !          2171: Routine Description:
        !          2172: 
        !          2173:     This routine stores the configuration information for this device.
        !          2174: 
        !          2175: Arguments:
        !          2176: 
        !          2177:     DeviceExtension - Pointer to the device extension.
        !          2178: 
        !          2179:     RegistryPath - Pointer to the null-terminated Unicode name of the 
        !          2180:         registry path for this driver.
        !          2181: 
        !          2182:     DeviceName - Pointer to the Unicode string that will receive
        !          2183:         the port device name.
        !          2184: 
        !          2185: Return Value:
        !          2186: 
        !          2187:     None.  As a side-effect, sets fields in DeviceExtension->MouseAttributes.
        !          2188: 
        !          2189: --*/
        !          2190: 
        !          2191: {
        !          2192:     PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
        !          2193:     UNICODE_STRING parametersPath;
        !          2194:     ULONG defaultDataQueueSize = DATA_QUEUE_SIZE;
        !          2195:     ULONG defaultMaximumPortsServiced = 1;
        !          2196:     ULONG defaultConnectMultiplePorts = 0;
        !          2197:     NTSTATUS status = STATUS_SUCCESS;
        !          2198:     UNICODE_STRING defaultUnicodeName;
        !          2199:     PWSTR path = NULL;
        !          2200:     USHORT queriesPlusOne = 5;
        !          2201: 
        !          2202:     parametersPath.Buffer = NULL;
        !          2203: 
        !          2204:     //
        !          2205:     // Registry path is already null-terminated, so just use it.
        !          2206:     //
        !          2207: 
        !          2208:     path = RegistryPath->Buffer;
        !          2209: 
        !          2210:     if (NT_SUCCESS(status)) {
        !          2211: 
        !          2212:         //
        !          2213:         // Allocate the Rtl query table.
        !          2214:         //
        !          2215:     
        !          2216:         parameters = ExAllocatePool(
        !          2217:                          PagedPool,
        !          2218:                          sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
        !          2219:                          );
        !          2220:     
        !          2221:         if (!parameters) {
        !          2222:     
        !          2223:             MouPrint((
        !          2224:                 1,
        !          2225:                 "MOUCLASS-MouConfiguration: Couldn't allocate table for Rtl query to parameters for %ws\n",
        !          2226:                  path
        !          2227:                  ));
        !          2228:     
        !          2229:             status = STATUS_UNSUCCESSFUL;
        !          2230:     
        !          2231:         } else {
        !          2232:     
        !          2233:             RtlZeroMemory(
        !          2234:                 parameters,
        !          2235:                 sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
        !          2236:                 );
        !          2237:     
        !          2238:             //
        !          2239:             // Form a path to this driver's Parameters subkey.
        !          2240:             //
        !          2241:     
        !          2242:             RtlInitUnicodeString(
        !          2243:                 &parametersPath,
        !          2244:                 NULL
        !          2245:                 );
        !          2246:     
        !          2247:             parametersPath.MaximumLength = RegistryPath->Length +
        !          2248:                                            sizeof(L"\\Parameters");
        !          2249:     
        !          2250:             parametersPath.Buffer = ExAllocatePool(
        !          2251:                                         PagedPool,
        !          2252:                                         parametersPath.MaximumLength
        !          2253:                                         );
        !          2254:     
        !          2255:             if (!parametersPath.Buffer) {
        !          2256:     
        !          2257:                 MouPrint((
        !          2258:                     1,
        !          2259:                     "MOUCLASS-MouConfiguration: Couldn't allocate string for path to parameters for %ws\n",
        !          2260:                      path
        !          2261:                     ));
        !          2262:     
        !          2263:                 status = STATUS_UNSUCCESSFUL;
        !          2264:     
        !          2265:             }
        !          2266:         }
        !          2267:     }
        !          2268: 
        !          2269:     if (NT_SUCCESS(status)) {
        !          2270: 
        !          2271:         //
        !          2272:         // Form the parameters path.
        !          2273:         //
        !          2274:     
        !          2275:         RtlZeroMemory(
        !          2276:             parametersPath.Buffer,
        !          2277:             parametersPath.MaximumLength
        !          2278:             );
        !          2279:         RtlAppendUnicodeToString(
        !          2280:             &parametersPath,
        !          2281:             path
        !          2282:             );
        !          2283:         RtlAppendUnicodeToString(
        !          2284:             &parametersPath,
        !          2285:             L"\\Parameters"
        !          2286:             );
        !          2287:     
        !          2288:         MouPrint((
        !          2289:             1,
        !          2290:             "MOUCLASS-MouConfiguration: parameters path is %ws\n",
        !          2291:              parametersPath.Buffer
        !          2292:             ));
        !          2293: 
        !          2294:         //
        !          2295:         // Form the default pointer class device name, in case it is not
        !          2296:         // specified in the registry.
        !          2297:         //
        !          2298: 
        !          2299:         RtlInitUnicodeString(
        !          2300:             &defaultUnicodeName, 
        !          2301:             DD_POINTER_CLASS_BASE_NAME_U
        !          2302:             );
        !          2303:     
        !          2304:         //
        !          2305:         // Gather all of the "user specified" information from
        !          2306:         // the registry.
        !          2307:         //
        !          2308:     
        !          2309:         parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
        !          2310:         parameters[0].Name = L"MouseDataQueueSize";
        !          2311:         parameters[0].EntryContext = 
        !          2312:             &DeviceExtension->MouseAttributes.InputDataQueueLength;
        !          2313:         parameters[0].DefaultType = REG_DWORD;
        !          2314:         parameters[0].DefaultData = &defaultDataQueueSize;
        !          2315:         parameters[0].DefaultLength = sizeof(ULONG);
        !          2316: 
        !          2317:         parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
        !          2318:         parameters[1].Name = L"MaximumPortsServiced";
        !          2319:         parameters[1].EntryContext = 
        !          2320:             &DeviceExtension->MaximumPortsServiced;
        !          2321:         parameters[1].DefaultType = REG_DWORD;
        !          2322:         parameters[1].DefaultData = &defaultMaximumPortsServiced;
        !          2323:         parameters[1].DefaultLength = sizeof(ULONG);
        !          2324: 
        !          2325:         parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
        !          2326:         parameters[2].Name = L"PointerDeviceBaseName";
        !          2327:         parameters[2].EntryContext = DeviceName;
        !          2328:         parameters[2].DefaultType = REG_SZ;
        !          2329:         parameters[2].DefaultData = defaultUnicodeName.Buffer;
        !          2330:         parameters[2].DefaultLength = 0;
        !          2331: 
        !          2332:         parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
        !          2333:         parameters[3].Name = L"ConnectMultiplePorts";
        !          2334:         parameters[3].EntryContext = 
        !          2335:             &DeviceExtension->ConnectOneClassToOnePort;
        !          2336:         parameters[3].DefaultType = REG_DWORD;
        !          2337:         parameters[3].DefaultData = &defaultConnectMultiplePorts;
        !          2338:         parameters[3].DefaultLength = sizeof(ULONG);
        !          2339: 
        !          2340:         status = RtlQueryRegistryValues(
        !          2341:                      RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
        !          2342:                      parametersPath.Buffer,
        !          2343:                      parameters,
        !          2344:                      NULL,
        !          2345:                      NULL
        !          2346:                      );
        !          2347: 
        !          2348:         if (!NT_SUCCESS(status)) {
        !          2349:             MouPrint((
        !          2350:                 1,
        !          2351:                 "MOUCLASS-MouConfiguration: RtlQueryRegistryValues failed with 0x%x\n",
        !          2352:                 status
        !          2353:                 ));
        !          2354:         }
        !          2355:     }
        !          2356: 
        !          2357:     if (!NT_SUCCESS(status)) {
        !          2358: 
        !          2359:         //
        !          2360:         // Go ahead and assign driver defaults.
        !          2361:         //
        !          2362: 
        !          2363:         DeviceExtension->MouseAttributes.InputDataQueueLength = 
        !          2364:             defaultDataQueueSize;
        !          2365:         DeviceExtension->MaximumPortsServiced = defaultMaximumPortsServiced;
        !          2366:         DeviceExtension->ConnectOneClassToOnePort = 
        !          2367:             !defaultConnectMultiplePorts;
        !          2368:         RtlCopyUnicodeString(DeviceName, &defaultUnicodeName);
        !          2369:     }
        !          2370: 
        !          2371:     MouPrint((
        !          2372:         1,
        !          2373:         "MOUCLASS-MouConfiguration: Mouse class base name = %ws\n",
        !          2374:         DeviceName->Buffer
        !          2375:         ));
        !          2376: 
        !          2377:     if (DeviceExtension->MouseAttributes.InputDataQueueLength == 0) {
        !          2378: 
        !          2379:         MouPrint((
        !          2380:             1,
        !          2381:             "MOUCLASS-MouConfiguration: overriding MouseInputDataQueueLength = 0x%x\n",
        !          2382:             DeviceExtension->MouseAttributes.InputDataQueueLength
        !          2383:             ));
        !          2384: 
        !          2385:         DeviceExtension->MouseAttributes.InputDataQueueLength = 
        !          2386:             defaultDataQueueSize;
        !          2387:     }
        !          2388: 
        !          2389:     DeviceExtension->MouseAttributes.InputDataQueueLength *= 
        !          2390:         sizeof(MOUSE_INPUT_DATA);
        !          2391: 
        !          2392:     MouPrint((
        !          2393:         1,
        !          2394:         "MOUCLASS-MouConfiguration: MouseInputDataQueueLength = 0x%x\n",
        !          2395:         DeviceExtension->MouseAttributes.InputDataQueueLength
        !          2396:         ));
        !          2397: 
        !          2398:     MouPrint((
        !          2399:         1,
        !          2400:         "MOUCLASS-MouConfiguration: MaximumPortsServiced = %d\n",
        !          2401:         DeviceExtension->MaximumPortsServiced
        !          2402:         ));
        !          2403: 
        !          2404:     //
        !          2405:     // Invert the flag that specifies the type of class/port connections.
        !          2406:     // We used it in the RtlQuery call in an inverted fashion.
        !          2407:     //
        !          2408: 
        !          2409:     DeviceExtension->ConnectOneClassToOnePort = 
        !          2410:         !DeviceExtension->ConnectOneClassToOnePort;
        !          2411: 
        !          2412:     MouPrint((
        !          2413:         1,
        !          2414:         "MOUCLASS-MouConfiguration: Connection Type = %d\n",
        !          2415:         DeviceExtension->ConnectOneClassToOnePort
        !          2416:         ));
        !          2417: 
        !          2418:     //
        !          2419:     // Free the allocated memory before returning.
        !          2420:     //
        !          2421: 
        !          2422:     if (parametersPath.Buffer)
        !          2423:         ExFreePool(parametersPath.Buffer);
        !          2424:     if (parameters)
        !          2425:         ExFreePool(parameters);
        !          2426: 
        !          2427: }
        !          2428: 
        !          2429: NTSTATUS
        !          2430: MouConnectToPort(
        !          2431:     IN PDEVICE_OBJECT ClassDeviceObject,
        !          2432:     IN PUNICODE_STRING FullPortName,
        !          2433:     IN ULONG PortIndex
        !          2434:     )
        !          2435: 
        !          2436: /*++
        !          2437: 
        !          2438: Routine Description:
        !          2439: 
        !          2440:     This routine creates the mouse class device object and connects
        !          2441:     to the port device.  
        !          2442:     
        !          2443: 
        !          2444: Arguments:
        !          2445: 
        !          2446:     ClassDeviceObject - Pointer to the device object for the class device.
        !          2447: 
        !          2448:     FullPortName - Pointer to the Unicode string that is the full path name
        !          2449:         for the port device object.
        !          2450: 
        !          2451:     PortIndex - The index into the PortDeviceObjectList[] for the 
        !          2452:         current connection.
        !          2453: 
        !          2454: Return Value:
        !          2455: 
        !          2456:     The function value is the final status from the operation.
        !          2457: 
        !          2458: --*/
        !          2459: 
        !          2460: {
        !          2461:     PDEVICE_EXTENSION deviceExtension = NULL;
        !          2462:     NTSTATUS status;
        !          2463:     PFILE_OBJECT fileObject = NULL;
        !          2464:     PDEVICE_OBJECT portDeviceObject = NULL;
        !          2465:     PIO_ERROR_LOG_PACKET errorLogEntry;
        !          2466:     ULONG uniqueErrorValue;
        !          2467:     NTSTATUS errorCode = STATUS_SUCCESS;
        !          2468: 
        !          2469:     MouPrint((1,"\n\nMOUCLASS-MouConnectToPort: enter\n"));
        !          2470: 
        !          2471:     //
        !          2472:     // Get a pointer to the port device object.
        !          2473:     //
        !          2474: 
        !          2475:     MouPrint((
        !          2476:         2,
        !          2477:         "MOUCLASS-MouConnectToPort: Pointer port name %ws\n", 
        !          2478:         FullPortName->Buffer
        !          2479:         ));
        !          2480: 
        !          2481:     status = IoGetDeviceObjectPointer(
        !          2482:                  FullPortName,
        !          2483:                  FILE_READ_ATTRIBUTES,
        !          2484:                  &fileObject,
        !          2485:                  &portDeviceObject
        !          2486:                  );
        !          2487: 
        !          2488:     if (status != STATUS_SUCCESS) {
        !          2489:         MouPrint((
        !          2490:             1,
        !          2491:             "MOUCLASS-MouConnectToPort: Could not get port device object %ws\n",
        !          2492:             FullPortName->Buffer
        !          2493:             ));
        !          2494: 
        !          2495:         goto MouConnectToPortExit;
        !          2496:     }
        !          2497: 
        !          2498:     deviceExtension =
        !          2499:         (PDEVICE_EXTENSION) ClassDeviceObject->DeviceExtension;
        !          2500:     deviceExtension->PortDeviceObjectList[PortIndex] = portDeviceObject;
        !          2501: 
        !          2502:     //
        !          2503:     // Set the IRP stack size (add 1 for the class layer).
        !          2504:     //
        !          2505:     // NOTE:  This is a bit funky for 1:many connections (we end up setting
        !          2506:     //        StackSize each time through this routine). Note also that 
        !          2507:     //        there is an assumption that the number of layers in the 
        !          2508:     //        class/port driver model is always the same (i.e., if there is 
        !          2509:     //        a layer between the class and the port driver for one device, 
        !          2510:     //        that is true for every device).
        !          2511:     //
        !          2512: 
        !          2513:     ClassDeviceObject->StackSize =
        !          2514:         (CCHAR) deviceExtension->PortDeviceObjectList[PortIndex]->StackSize + 1;
        !          2515: 
        !          2516:     //
        !          2517:     // Connect to port device.
        !          2518:     //
        !          2519: 
        !          2520:     status = MouSendConnectRequest(
        !          2521:                 ClassDeviceObject,
        !          2522:                 (PVOID)MouseClassServiceCallback,
        !          2523:                 PortIndex
        !          2524:                 );
        !          2525: 
        !          2526:     if (status != STATUS_SUCCESS) {
        !          2527:         MouPrint((
        !          2528:             1,
        !          2529:             "MOUCLASS-MouConnectToPort: Could not connect to port device %ws\n",
        !          2530:             FullPortName->Buffer
        !          2531:             ));
        !          2532: 
        !          2533:         //
        !          2534:         // Log an error.
        !          2535:         //
        !          2536: 
        !          2537:         errorCode = MOUCLASS_NO_PORT_CONNECT;
        !          2538:         uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 30;
        !          2539:         goto MouConnectToPortExit;
        !          2540:     }
        !          2541: 
        !          2542: MouConnectToPortExit:
        !          2543: 
        !          2544:     if (status != STATUS_SUCCESS) {
        !          2545: 
        !          2546:         //
        !          2547:         // Some part of the initialization failed.  Log an error, and 
        !          2548:         // clean up the resources for the failed part of the initialization.
        !          2549:         //
        !          2550: 
        !          2551:         if (errorCode != STATUS_SUCCESS) {
        !          2552:             errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
        !          2553:                                                      ClassDeviceObject,
        !          2554:                                                      sizeof(IO_ERROR_LOG_PACKET)
        !          2555:                                                      );
        !          2556: 
        !          2557:             if (errorLogEntry != NULL) {
        !          2558:     
        !          2559:                 errorLogEntry->ErrorCode = errorCode;
        !          2560:                 errorLogEntry->SequenceNumber = 0;
        !          2561:                 errorLogEntry->MajorFunctionCode = 0;
        !          2562:                 errorLogEntry->IoControlCode = 0;
        !          2563:                 errorLogEntry->RetryCount = 0;
        !          2564:                 errorLogEntry->UniqueErrorValue = uniqueErrorValue;
        !          2565:                 errorLogEntry->FinalStatus = status;
        !          2566:     
        !          2567:                 IoWriteErrorLogEntry(errorLogEntry);
        !          2568:             }
        !          2569:         }
        !          2570:     
        !          2571:         if (fileObject) {
        !          2572:             ObDereferenceObject(fileObject);
        !          2573:         }
        !          2574: 
        !          2575:         //
        !          2576:         // We count on the caller to free the ring buffer and delete
        !          2577:         // the class device object.
        !          2578:         //
        !          2579:     }
        !          2580:     
        !          2581:     MouPrint((1,"MOUCLASS-MouConnectToPort: exit\n"));
        !          2582:     
        !          2583:     return(status);
        !          2584: 
        !          2585: }
        !          2586: 
        !          2587: NTSTATUS
        !          2588: MouCreateClassObject(
        !          2589:     IN PDRIVER_OBJECT DriverObject,
        !          2590:     IN PDEVICE_EXTENSION TmpDeviceExtension,
        !          2591:     IN PUNICODE_STRING RegistryPath,
        !          2592:     IN PUNICODE_STRING FullDeviceName,
        !          2593:     IN PUNICODE_STRING BaseDeviceName,
        !          2594:     IN PDEVICE_OBJECT *ClassDeviceObject
        !          2595:     )
        !          2596: 
        !          2597: /*++
        !          2598: 
        !          2599: Routine Description:
        !          2600: 
        !          2601:     This routine creates the mouse class device object.
        !          2602:     
        !          2603: 
        !          2604: Arguments:
        !          2605: 
        !          2606:     DriverObject - Pointer to driver object created by system.
        !          2607: 
        !          2608:     TmpDeviceExtension - Pointer to the template device extension.
        !          2609:         
        !          2610:     RegistryPath - Pointer to the null-terminated Unicode name of the 
        !          2611:         registry path for this driver.
        !          2612: 
        !          2613:     FullDeviceName - Pointer to the Unicode string that is the full path name
        !          2614:         for the class device object.
        !          2615: 
        !          2616:     BaseDeviceName - Pointer to the Unicode string that is the base path name
        !          2617:         for the class device.
        !          2618: 
        !          2619:     ClassDeviceObject - Pointer to a pointer to the class device object.
        !          2620: 
        !          2621: Return Value:
        !          2622: 
        !          2623:     The function value is the final status from the operation.
        !          2624: 
        !          2625: --*/
        !          2626: 
        !          2627: {
        !          2628:     PDEVICE_EXTENSION deviceExtension = NULL;
        !          2629:     NTSTATUS status;
        !          2630:     PIO_ERROR_LOG_PACKET errorLogEntry;
        !          2631:     ULONG uniqueErrorValue;
        !          2632:     NTSTATUS errorCode = STATUS_SUCCESS;
        !          2633: 
        !          2634:     MouPrint((1,"\n\nMOUCLASS-MouCreateClassObject: enter\n"));
        !          2635: 
        !          2636:     //
        !          2637:     // Create a non-exclusive device object for the mouse class device.
        !          2638:     //
        !          2639: 
        !          2640:     MouPrint((
        !          2641:         1,
        !          2642:         "MOUCLASS-MouCreateClassObject: Creating device object named %ws\n",
        !          2643:         FullDeviceName->Buffer
        !          2644:         ));
        !          2645: 
        !          2646:     status = IoCreateDevice(
        !          2647:                  DriverObject,
        !          2648:                  sizeof(DEVICE_EXTENSION),
        !          2649:                  FullDeviceName,
        !          2650:                  FILE_DEVICE_MOUSE,
        !          2651:                  0,
        !          2652:                  FALSE,
        !          2653:                  ClassDeviceObject
        !          2654:                  );
        !          2655: 
        !          2656:     if (!NT_SUCCESS(status)) {
        !          2657:         MouPrint((
        !          2658:             1,
        !          2659:             "MOUCLASS-MouCreateClassObject: Could not create class device object = %ws\n",
        !          2660:             FullDeviceName->Buffer
        !          2661:             ));
        !          2662:         goto MouCreateClassObjectExit;
        !          2663:       
        !          2664:     } 
        !          2665: 
        !          2666:     //
        !          2667:     // Do buffered I/O.  I.e., the I/O system will copy to/from user data
        !          2668:     // from/to a system buffer.
        !          2669:     //
        !          2670: 
        !          2671:     (*ClassDeviceObject)->Flags |= DO_BUFFERED_IO;
        !          2672:     deviceExtension =
        !          2673:         (PDEVICE_EXTENSION)(*ClassDeviceObject)->DeviceExtension;
        !          2674:     *deviceExtension = *TmpDeviceExtension;
        !          2675: 
        !          2676:     //
        !          2677:     // Initialize spin lock for critical sections.
        !          2678:     //
        !          2679: 
        !          2680:     KeInitializeSpinLock(&deviceExtension->SpinLock);
        !          2681: 
        !          2682:     //
        !          2683:     // Initialize mouse class flags to indicate there is no outstanding 
        !          2684:     // read request pending and cleanup has not been initiated.
        !          2685:     //
        !          2686: 
        !          2687:     deviceExtension->RequestIsPending = FALSE;
        !          2688:     deviceExtension->CleanupWasInitiated = FALSE;
        !          2689: 
        !          2690:     //
        !          2691:     // Allocate the ring buffer for the mouse class input data.
        !          2692:     //
        !          2693: 
        !          2694:     deviceExtension->InputData = 
        !          2695:         ExAllocatePool(
        !          2696:             NonPagedPool,
        !          2697:             deviceExtension->MouseAttributes.InputDataQueueLength
        !          2698:             );
        !          2699: 
        !          2700:     if (!deviceExtension->InputData) {
        !          2701:    
        !          2702:         //
        !          2703:         // Could not allocate memory for the mouse class data queue.
        !          2704:         //
        !          2705: 
        !          2706:         MouPrint((
        !          2707:             1,
        !          2708:             "MOUCLASS-MouCreateClassObject: Could not allocate input data queue for %ws\n",
        !          2709:             FullDeviceName->Buffer
        !          2710:             ));
        !          2711: 
        !          2712:         status = STATUS_INSUFFICIENT_RESOURCES;
        !          2713: 
        !          2714:         //
        !          2715:         // Log an error.
        !          2716:         //
        !          2717: 
        !          2718:         errorCode = MOUCLASS_NO_BUFFER_ALLOCATED;
        !          2719:         uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 20;
        !          2720:         goto MouCreateClassObjectExit;
        !          2721:     }
        !          2722: 
        !          2723:     //
        !          2724:     // Initialize mouse class input data queue.
        !          2725:     //
        !          2726: 
        !          2727:     MouInitializeDataQueue((PVOID)deviceExtension);
        !          2728: 
        !          2729: MouCreateClassObjectExit:
        !          2730: 
        !          2731:     if (status != STATUS_SUCCESS) {
        !          2732: 
        !          2733:         //
        !          2734:         // Some part of the initialization failed.  Log an error, and 
        !          2735:         // clean up the resources for the failed part of the initialization.
        !          2736:         //
        !          2737: 
        !          2738:         if (errorCode != STATUS_SUCCESS) {
        !          2739:             errorLogEntry = (PIO_ERROR_LOG_PACKET)
        !          2740:                 IoAllocateErrorLogEntry(
        !          2741:                     (*ClassDeviceObject == NULL) ? 
        !          2742:                         (PVOID) DriverObject : (PVOID) *ClassDeviceObject,
        !          2743:                     sizeof(IO_ERROR_LOG_PACKET)
        !          2744:                     );
        !          2745: 
        !          2746:             if (errorLogEntry != NULL) {
        !          2747:     
        !          2748:                 errorLogEntry->ErrorCode = errorCode;
        !          2749:                 errorLogEntry->SequenceNumber = 0;
        !          2750:                 errorLogEntry->MajorFunctionCode = 0;
        !          2751:                 errorLogEntry->IoControlCode = 0;
        !          2752:                 errorLogEntry->RetryCount = 0;
        !          2753:                 errorLogEntry->UniqueErrorValue = uniqueErrorValue;
        !          2754:                 errorLogEntry->FinalStatus = status;
        !          2755:     
        !          2756:                 IoWriteErrorLogEntry(errorLogEntry);
        !          2757:             }
        !          2758:         }
        !          2759:     
        !          2760:         if ((deviceExtension) && (deviceExtension->InputData))
        !          2761:             ExFreePool(deviceExtension->InputData);
        !          2762:         if (*ClassDeviceObject) {
        !          2763:             IoDeleteDevice(*ClassDeviceObject);
        !          2764:             *ClassDeviceObject = NULL;
        !          2765:         }
        !          2766:     }
        !          2767:     
        !          2768:     MouPrint((1,"MOUCLASS-MouCreateClassObject: exit\n"));
        !          2769:     
        !          2770:     return(status);
        !          2771: 
        !          2772: }
        !          2773: 
        !          2774: #if DBG
        !          2775: 
        !          2776: VOID
        !          2777: MouDebugPrint(
        !          2778:     ULONG DebugPrintLevel,
        !          2779:     PCCHAR DebugMessage,
        !          2780:     ...
        !          2781:     )
        !          2782: 
        !          2783: /*++
        !          2784: 
        !          2785: Routine Description:
        !          2786: 
        !          2787:     Debug print routine.
        !          2788: 
        !          2789: Arguments:
        !          2790: 
        !          2791:     Debug print level between 0 and 3, with 3 being the most verbose.
        !          2792: 
        !          2793: Return Value:
        !          2794: 
        !          2795:     None.
        !          2796: 
        !          2797: --*/
        !          2798: 
        !          2799: {
        !          2800:     va_list ap;
        !          2801: 
        !          2802:     va_start(ap, DebugMessage);
        !          2803: 
        !          2804:     if (DebugPrintLevel <= MouseDebug) {
        !          2805: 
        !          2806:         char buffer[256];
        !          2807: 
        !          2808:         (VOID) vsprintf(buffer, DebugMessage, ap);
        !          2809: 
        !          2810:         DbgPrint(buffer);
        !          2811:     }
        !          2812: 
        !          2813:     va_end(ap);
        !          2814: 
        !          2815: } 
        !          2816: #endif
        !          2817: 
        !          2818: NTSTATUS
        !          2819: MouDeterminePortsServiced(
        !          2820:     IN PUNICODE_STRING BasePortName,
        !          2821:     IN OUT PULONG NumberPortsServiced
        !          2822:     )
        !          2823: 
        !          2824: /*++
        !          2825: 
        !          2826: Routine Description:
        !          2827: 
        !          2828:     This routine reads the DEVICEMAP portion of the registry to determine
        !          2829:     how many ports the class driver is to service.  Depending on the
        !          2830:     value of DeviceExtension->ConnectOneClassToOnePort, the class driver 
        !          2831:     will eventually create one device object per port device serviced, or
        !          2832:     one class device object that connects to multiple port device objects. 
        !          2833:     
        !          2834:     Assumptions:
        !          2835: 
        !          2836:         1.  If the base device name for the class driver is "PointerClass",
        !          2837:                                                                     ^^^^^
        !          2838:             then the port drivers it can service are found under the
        !          2839:             "PointerPort" subkey in the DEVICEMAP portion of the registry.
        !          2840:                     ^^^^
        !          2841: 
        !          2842:         2.  The port device objects are created with suffixes in strictly
        !          2843:             ascending order, starting with suffix 0.  E.g., 
        !          2844:             \Device\PointerPort0 indicates the first pointer port device, 
        !          2845:             \Device\PointerPort1 the second, and so on.  There are no gaps 
        !          2846:             in the list.
        !          2847: 
        !          2848:         3.  If ConnectOneClassToOnePort is non-zero, there is a 1:1 
        !          2849:             correspondence between class device objects and port device 
        !          2850:             objects.  I.e., \Device\PointerClass0 will connect to 
        !          2851:             \Device\PointerPort0, \Device\PointerClass1 to
        !          2852:             \Device\PointerPort1, and so on.
        !          2853: 
        !          2854:         4.  If ConnectOneClassToOnePort is zero, there is a 1:many
        !          2855:             correspondence between class device objects and port device 
        !          2856:             objects.  I.e., \Device\PointerClass0 will connect to 
        !          2857:             \Device\PointerPort0, and \Device\PointerPort1, and so on.
        !          2858: 
        !          2859: 
        !          2860:     Note that for Product 1, the Raw Input Thread (Windows USER) will
        !          2861:     only deign to open and read from one pointing device.  Hence, it is 
        !          2862:     safe to make simplifying assumptions because the driver is basically 
        !          2863:     providing  much more functionality than the RIT will use.
        !          2864:             
        !          2865: Arguments:
        !          2866: 
        !          2867:     BasePortName - Pointer to the Unicode string that is the base path name
        !          2868:         for the port device.
        !          2869: 
        !          2870:     NumberPortsServiced - Pointer to storage that will receive the
        !          2871:         number of ports this class driver should service.
        !          2872: 
        !          2873: Return Value:
        !          2874: 
        !          2875:     The function value is the final status from the operation.  
        !          2876: 
        !          2877: --*/
        !          2878: 
        !          2879: {
        !          2880: 
        !          2881:     NTSTATUS status;
        !          2882:     PRTL_QUERY_REGISTRY_TABLE registryTable = NULL;
        !          2883:     USHORT queriesPlusOne = 2;
        !          2884:     
        !          2885:     //
        !          2886:     // Initialize the result.
        !          2887:     //
        !          2888: 
        !          2889:     *NumberPortsServiced = 0;
        !          2890: 
        !          2891:     //
        !          2892:     // Allocate the Rtl query table.
        !          2893:     //
        !          2894:     
        !          2895:     registryTable = ExAllocatePool(
        !          2896:                         PagedPool,
        !          2897:                         sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
        !          2898:                      );
        !          2899:     
        !          2900:     if (!registryTable) {
        !          2901:     
        !          2902:         MouPrint((
        !          2903:             1,
        !          2904:             "MOUCLASS-MouDeterminePortsServiced: Couldn't allocate table for Rtl query\n"
        !          2905:             ));
        !          2906:     
        !          2907:         status = STATUS_UNSUCCESSFUL;
        !          2908:     
        !          2909:     } else {
        !          2910:     
        !          2911:         RtlZeroMemory(
        !          2912:             registryTable,
        !          2913:             sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
        !          2914:             );
        !          2915: 
        !          2916:         //
        !          2917:         // Set things up so that MouDeviceMapQueryCallback will be
        !          2918:         // called once for every value in the pointer port section
        !          2919:         // of the registry's hardware devicemap.
        !          2920:         //
        !          2921:     
        !          2922:         registryTable[0].QueryRoutine = MouDeviceMapQueryCallback;
        !          2923:         registryTable[0].Name = NULL;
        !          2924: 
        !          2925:         status = RtlQueryRegistryValues(
        !          2926:                      RTL_REGISTRY_DEVICEMAP | RTL_REGISTRY_OPTIONAL,
        !          2927:                      BasePortName->Buffer, 
        !          2928:                      registryTable,
        !          2929:                      NumberPortsServiced,
        !          2930:                      NULL
        !          2931:                      );
        !          2932: 
        !          2933:         if (!NT_SUCCESS(status)) {
        !          2934:             MouPrint((
        !          2935:                 1,
        !          2936:                 "MOUCLASS-MouDeterminePortsServiced: RtlQueryRegistryValues failed with 0x%x\n",
        !          2937:                 status
        !          2938:                 ));
        !          2939:         }
        !          2940: 
        !          2941:         ExFreePool(registryTable);
        !          2942:     }
        !          2943: 
        !          2944:     return(status);
        !          2945: }
        !          2946: 
        !          2947: NTSTATUS 
        !          2948: MouDeviceMapQueryCallback(
        !          2949:     IN PWSTR ValueName,
        !          2950:     IN ULONG ValueType,
        !          2951:     IN PVOID ValueData,
        !          2952:     IN ULONG ValueLength,
        !          2953:     IN PVOID Context,
        !          2954:     IN PVOID EntryContext
        !          2955:     )
        !          2956: 
        !          2957: /*++
        !          2958: 
        !          2959: Routine Description:
        !          2960: 
        !          2961:     This is the callout routine specified in a call to
        !          2962:     RtlQueryRegistryValues.  It increments the value pointed
        !          2963:     to by the Context parameter.
        !          2964:             
        !          2965: Arguments:
        !          2966: 
        !          2967:     ValueName - Unused.
        !          2968: 
        !          2969:     ValueType - Unused.
        !          2970: 
        !          2971:     ValueData - Unused.
        !          2972: 
        !          2973:     ValueLength - Unused.
        !          2974: 
        !          2975:     Context - Pointer to a count of the number of times this
        !          2976:         routine has been called.  This is the number of ports
        !          2977:         the class driver needs to service.
        !          2978: 
        !          2979:     EntryContext - Unused.
        !          2980: 
        !          2981: Return Value:
        !          2982: 
        !          2983:     The function value is the final status from the operation.  
        !          2984: 
        !          2985: --*/
        !          2986: 
        !          2987: {
        !          2988:     *(PULONG)Context += 1;
        !          2989: 
        !          2990:     return(STATUS_SUCCESS);
        !          2991: }
        !          2992: 
        !          2993: NTSTATUS
        !          2994: MouEnableDisablePort(
        !          2995:     IN PDEVICE_OBJECT DeviceObject,
        !          2996:     IN BOOLEAN EnableFlag,
        !          2997:     IN ULONG PortIndex
        !          2998:     )
        !          2999: 
        !          3000: /*++
        !          3001: 
        !          3002: Routine Description:
        !          3003: 
        !          3004:     This routine sends an enable or a disable request to the port driver.
        !          3005: 
        !          3006: Arguments:
        !          3007: 
        !          3008:     DeviceObject - Pointer to class device object.
        !          3009: 
        !          3010:     EnableFlag - If TRUE, send an ENABLE request; otherwise, send DISABLE.
        !          3011: 
        !          3012:     PortIndex - Index into the PortDeviceObjectList[] for the current
        !          3013:         enable/disable request.
        !          3014: 
        !          3015: Return Value:
        !          3016: 
        !          3017:     Status is returned.
        !          3018: 
        !          3019: --*/
        !          3020: 
        !          3021: {
        !          3022:     PIRP irp;
        !          3023:     IO_STATUS_BLOCK ioStatus;
        !          3024:     NTSTATUS status;
        !          3025:     KEVENT event;
        !          3026:     PDEVICE_EXTENSION deviceExtension;
        !          3027: 
        !          3028:     MouPrint((2,"MOUCLASS-MouEnableDisablePort: enter\n"));
        !          3029: 
        !          3030:     //
        !          3031:     // Get a pointer to the device extension.
        !          3032:     //
        !          3033: 
        !          3034:     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
        !          3035: 
        !          3036:     //
        !          3037:     // Create notification event object to be used to signal the
        !          3038:     // request completion.
        !          3039:     //
        !          3040: 
        !          3041:     KeInitializeEvent(&event, NotificationEvent, FALSE);
        !          3042: 
        !          3043:     //
        !          3044:     // Build the synchronous request to be sent to the port driver
        !          3045:     // to perform the request.  Allocate an IRP to issue the port internal
        !          3046:     // device control Enable/Disable call.  
        !          3047:     //
        !          3048: 
        !          3049:     irp = IoBuildDeviceIoControlRequest(
        !          3050:             EnableFlag? IOCTL_INTERNAL_MOUSE_ENABLE:
        !          3051:                         IOCTL_INTERNAL_MOUSE_DISABLE,
        !          3052:             deviceExtension->PortDeviceObjectList[PortIndex],
        !          3053:             NULL,
        !          3054:             0,
        !          3055:             NULL,
        !          3056:             0,
        !          3057:             TRUE,
        !          3058:             &event,
        !          3059:             &ioStatus
        !          3060:             );
        !          3061: 
        !          3062:     //
        !          3063:     // Call the port driver to perform the operation.  If the returned status
        !          3064:     // is PENDING, wait for the request to complete.
        !          3065:     //
        !          3066: 
        !          3067:     status = IoCallDriver(
        !          3068:                  deviceExtension->PortDeviceObjectList[PortIndex],
        !          3069:                  irp
        !          3070:                  );
        !          3071: 
        !          3072:     if (status == STATUS_PENDING) {
        !          3073:         (VOID) KeWaitForSingleObject(
        !          3074:                    &event,
        !          3075:                    Suspended,
        !          3076:                    KernelMode,
        !          3077:                    FALSE,
        !          3078:                    NULL
        !          3079:                    );
        !          3080:     } else {
        !          3081: 
        !          3082:         //
        !          3083:         // Ensure that the proper status value gets picked up.
        !          3084:         //
        !          3085: 
        !          3086:         ioStatus.Status = status;
        !          3087:     }
        !          3088: 
        !          3089:     MouPrint((2,"MOUCLASS-MouEnableDisablePort: exit\n"));
        !          3090: 
        !          3091:     return(ioStatus.Status);
        !          3092: 
        !          3093: }
        !          3094: 
        !          3095: VOID
        !          3096: MouInitializeDataQueue (
        !          3097:     IN PVOID Context
        !          3098:     )
        !          3099: 
        !          3100: /*++
        !          3101: 
        !          3102: Routine Description:
        !          3103: 
        !          3104:     This routine initializes the input data queue.  IRQL is raised to
        !          3105:     DISPATCH_LEVEL to synchronize with StartIo, and the device object
        !          3106:     spinlock is acquired.
        !          3107: 
        !          3108: Arguments:
        !          3109: 
        !          3110:     Context - Supplies a pointer to the device extension.
        !          3111: 
        !          3112: Return Value:
        !          3113: 
        !          3114:     None.
        !          3115: 
        !          3116: --*/
        !          3117: 
        !          3118: {
        !          3119: 
        !          3120:     KIRQL oldIrql;
        !          3121:     PDEVICE_EXTENSION deviceExtension;
        !          3122: 
        !          3123:     MouPrint((3,"MOUCLASS-MouInitializeDataQueue: enter\n"));
        !          3124: 
        !          3125:     //
        !          3126:     // Get address of device extension.
        !          3127:     //
        !          3128: 
        !          3129:     deviceExtension = (PDEVICE_EXTENSION)Context;
        !          3130: 
        !          3131:     //
        !          3132:     // Acquire the spinlock to protect the input data 
        !          3133:     // queue and associated pointers.
        !          3134:     //
        !          3135: 
        !          3136:     KeAcquireSpinLock(&deviceExtension->SpinLock, &oldIrql);
        !          3137: 
        !          3138:     //
        !          3139:     // Initialize the input data queue.
        !          3140:     //
        !          3141: 
        !          3142:     deviceExtension->InputCount = 0;
        !          3143:     deviceExtension->DataIn = deviceExtension->InputData;
        !          3144:     deviceExtension->DataOut = deviceExtension->InputData;
        !          3145: 
        !          3146:     deviceExtension->OkayToLogOverflow = TRUE;
        !          3147: 
        !          3148:     //
        !          3149:     // Release the spinlock and return to the old IRQL.
        !          3150:     //
        !          3151: 
        !          3152:     KeReleaseSpinLock(&deviceExtension->SpinLock, oldIrql);
        !          3153: 
        !          3154:     MouPrint((3,"MOUCLASS-MouInitializeDataQueue: exit\n"));
        !          3155: 
        !          3156: } // end MouInitializeDataQueue
        !          3157: 
        !          3158: NTSTATUS
        !          3159: MouSendConnectRequest(
        !          3160:     IN PDEVICE_OBJECT DeviceObject,
        !          3161:     IN PVOID ServiceCallback,
        !          3162:     IN ULONG PortIndex
        !          3163:     )
        !          3164: 
        !          3165: /*++
        !          3166: 
        !          3167: Routine Description:
        !          3168: 
        !          3169:     This routine sends a connect request to the port driver.
        !          3170: 
        !          3171: Arguments:
        !          3172: 
        !          3173:     DeviceObject - Pointer to class device object.
        !          3174: 
        !          3175:     ServiceCallback - Pointer to the class service callback routine.
        !          3176: 
        !          3177:     PortIndex - The index into the PortDeviceObjectList[] for the current
        !          3178:         connect request.
        !          3179: 
        !          3180: Return Value:
        !          3181: 
        !          3182:     Status is returned.
        !          3183: 
        !          3184: --*/
        !          3185: 
        !          3186: {
        !          3187:     PIRP irp;
        !          3188:     IO_STATUS_BLOCK ioStatus;
        !          3189:     NTSTATUS status;
        !          3190:     KEVENT event;
        !          3191:     PDEVICE_EXTENSION deviceExtension;
        !          3192:     CONNECT_DATA connectData;
        !          3193: 
        !          3194:     MouPrint((2,"MOUCLASS-MouSendConnectRequest: enter\n"));
        !          3195: 
        !          3196:     //
        !          3197:     // Get a pointer to the device extension.
        !          3198:     //
        !          3199: 
        !          3200:     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
        !          3201: 
        !          3202:     //
        !          3203:     // Create notification event object to be used to signal the
        !          3204:     // request completion.
        !          3205:     //
        !          3206: 
        !          3207:     KeInitializeEvent(&event, NotificationEvent, FALSE);
        !          3208: 
        !          3209:     //
        !          3210:     // Build the synchronous request to be sent to the port driver
        !          3211:     // to perform the request.  Allocate an IRP to issue the port internal
        !          3212:     // device control connect call.  The connect parameters are passed in
        !          3213:     // the input buffer.
        !          3214:     //
        !          3215: 
        !          3216:     connectData.ClassDeviceObject = DeviceObject;
        !          3217:     connectData.ClassService = ServiceCallback;
        !          3218: 
        !          3219:     irp = IoBuildDeviceIoControlRequest(
        !          3220:             IOCTL_INTERNAL_MOUSE_CONNECT,
        !          3221:             deviceExtension->PortDeviceObjectList[PortIndex],
        !          3222:             &connectData,
        !          3223:             sizeof(CONNECT_DATA),
        !          3224:             NULL,
        !          3225:             0,
        !          3226:             TRUE,
        !          3227:             &event,
        !          3228:             &ioStatus
        !          3229:             );
        !          3230: 
        !          3231:     //
        !          3232:     // Call the port driver to perform the operation.  If the returned status
        !          3233:     // is PENDING, wait for the request to complete.
        !          3234:     //
        !          3235: 
        !          3236:     status = IoCallDriver(
        !          3237:                  deviceExtension->PortDeviceObjectList[PortIndex],
        !          3238:                  irp
        !          3239:                  );
        !          3240: 
        !          3241:     if (status == STATUS_PENDING) {
        !          3242:         (VOID) KeWaitForSingleObject(
        !          3243:                    &event,
        !          3244:                    Suspended,
        !          3245:                    KernelMode,
        !          3246:                    FALSE,
        !          3247:                    NULL
        !          3248:                    );
        !          3249:     } else {
        !          3250: 
        !          3251:         //
        !          3252:         // Ensure that the proper status value gets picked up.
        !          3253:         //
        !          3254: 
        !          3255:         ioStatus.Status = status;
        !          3256:     }
        !          3257: 
        !          3258:     MouPrint((2,"MOUCLASS-MouSendConnectRequest: exit\n"));
        !          3259: 
        !          3260:     return(ioStatus.Status);
        !          3261: 
        !          3262: } // end MouSendConnectRequest()

unix.superglobalmegacorp.com

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