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

unix.superglobalmegacorp.com

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