Annotation of ntddk/src/input/kbdclass/kbdclass.c, revision 1.1.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.