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

unix.superglobalmegacorp.com

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