|
|
1.1 ! root 1: ! 2: /*++ ! 3: ! 4: Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation ! 5: ! 6: Module Name: ! 7: ! 8: kbdcmn.c ! 9: ! 10: Abstract: ! 11: ! 12: The common portions of the Intel i8042 port driver which ! 13: apply to the keyboard device. ! 14: ! 15: Environment: ! 16: ! 17: Kernel mode only. ! 18: ! 19: Notes: ! 20: ! 21: NOTES: (Future/outstanding issues) ! 22: ! 23: - Powerfail not implemented. ! 24: ! 25: - Consolidate duplicate code, where possible and appropriate. ! 26: ! 27: Revision History: ! 28: ! 29: --*/ ! 30: ! 31: #include "stdarg.h" ! 32: #include "stdio.h" ! 33: #include "string.h" ! 34: #include "ntddk.h" ! 35: #include "i8042prt.h" ! 36: ! 37: ! 38: VOID ! 39: I8042KeyboardIsrDpc( ! 40: IN PKDPC Dpc, ! 41: IN PDEVICE_OBJECT DeviceObject, ! 42: IN PIRP Irp, ! 43: IN PVOID Context ! 44: ) ! 45: ! 46: /*++ ! 47: ! 48: Routine Description: ! 49: ! 50: This routine runs at DISPATCH_LEVEL IRQL to finish processing ! 51: keyboard interrupts. It is queued in the keyboard ISR. The real ! 52: work is done via a callback to the connected keyboard class driver. ! 53: ! 54: Arguments: ! 55: ! 56: Dpc - Pointer to the DPC object. ! 57: ! 58: DeviceObject - Pointer to the device object. ! 59: ! 60: Irp - Pointer to the Irp. ! 61: ! 62: Context - Not used. ! 63: ! 64: Return Value: ! 65: ! 66: None. ! 67: ! 68: --*/ ! 69: ! 70: { ! 71: ! 72: PDEVICE_EXTENSION deviceExtension; ! 73: GET_DATA_POINTER_CONTEXT getPointerContext; ! 74: SET_DATA_POINTER_CONTEXT setPointerContext; ! 75: VARIABLE_OPERATION_CONTEXT operationContext; ! 76: PVOID classService; ! 77: PVOID classDeviceObject; ! 78: LONG interlockedResult; ! 79: BOOLEAN moreDpcProcessing; ! 80: ULONG dataNotConsumed = 0; ! 81: ULONG inputDataConsumed = 0; ! 82: LARGE_INTEGER deltaTime; ! 83: ! 84: UNREFERENCED_PARAMETER(Dpc); ! 85: UNREFERENCED_PARAMETER(Irp); ! 86: UNREFERENCED_PARAMETER(Context); ! 87: ! 88: I8xPrint((2, "I8042PRT-I8042KeyboardIsrDpc: enter\n")); ! 89: ! 90: deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; ! 91: ! 92: // ! 93: // Use DpcInterlockKeyboard to determine whether the DPC is running ! 94: // concurrently on another processor. We only want one instantiation ! 95: // of the DPC to actually do any work. DpcInterlockKeyboard is -1 ! 96: // when no DPC is executing. We increment it, and if the result is ! 97: // zero then the current instantiation is the only one executing, and it ! 98: // is okay to proceed. Otherwise, we just return. ! 99: // ! 100: // ! 101: ! 102: operationContext.VariableAddress = ! 103: &deviceExtension->DpcInterlockKeyboard; ! 104: operationContext.Operation = IncrementOperation; ! 105: operationContext.NewValue = &interlockedResult; ! 106: ! 107: KeSynchronizeExecution( ! 108: deviceExtension->KeyboardInterruptObject, ! 109: (PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation, ! 110: (PVOID) &operationContext ! 111: ); ! 112: ! 113: moreDpcProcessing = (interlockedResult == 0)? TRUE:FALSE; ! 114: ! 115: while (moreDpcProcessing) { ! 116: ! 117: dataNotConsumed = 0; ! 118: inputDataConsumed = 0; ! 119: ! 120: // ! 121: // Get the port InputData queue pointers synchronously. ! 122: // ! 123: ! 124: getPointerContext.DeviceExtension = deviceExtension; ! 125: setPointerContext.DeviceExtension = deviceExtension; ! 126: getPointerContext.DeviceType = (CCHAR) KeyboardDeviceType; ! 127: setPointerContext.DeviceType = (CCHAR) KeyboardDeviceType; ! 128: setPointerContext.InputCount = 0; ! 129: ! 130: KeSynchronizeExecution( ! 131: deviceExtension->KeyboardInterruptObject, ! 132: (PKSYNCHRONIZE_ROUTINE) I8xGetDataQueuePointer, ! 133: (PVOID) &getPointerContext ! 134: ); ! 135: ! 136: if (getPointerContext.InputCount != 0) { ! 137: ! 138: // ! 139: // Call the connected class driver's callback ISR with the ! 140: // port InputData queue pointers. If we have to wrap the queue, ! 141: // break the operation into two pieces, and call the class ! 142: // callback ISR once for each piece. ! 143: // ! 144: ! 145: classDeviceObject = ! 146: deviceExtension->KeyboardExtension.ConnectData.ClassDeviceObject; ! 147: classService = ! 148: deviceExtension->KeyboardExtension.ConnectData.ClassService; ! 149: ASSERT(classService != NULL); ! 150: ! 151: if (getPointerContext.DataOut >= getPointerContext.DataIn) { ! 152: ! 153: // ! 154: // We'll have to wrap the InputData circular buffer. Call ! 155: // the class callback ISR with the chunk of data starting at ! 156: // DataOut and ending at the end of the queue. ! 157: // ! 158: ! 159: I8xPrint(( ! 160: 2, ! 161: "I8042PRT-I8042KeyboardIsrDpc: calling class callback\n" ! 162: )); ! 163: I8xPrint(( ! 164: 2, ! 165: "I8042PRT-I8042KeyboardIsrDpc: with Start 0x%x and End 0x%x\n", ! 166: getPointerContext.DataOut, ! 167: deviceExtension->KeyboardExtension.DataEnd ! 168: )); ! 169: ! 170: (*(PSERVICE_CALLBACK_ROUTINE) classService)( ! 171: classDeviceObject, ! 172: getPointerContext.DataOut, ! 173: deviceExtension->KeyboardExtension.DataEnd, ! 174: &inputDataConsumed ! 175: ); ! 176: ! 177: dataNotConsumed = (((PUCHAR) ! 178: deviceExtension->KeyboardExtension.DataEnd - ! 179: (PUCHAR) getPointerContext.DataOut) ! 180: / sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed; ! 181: ! 182: I8xPrint(( ! 183: 2, ! 184: "I8042PRT-I8042KeyboardIsrDpc: (Wrap) Call callback consumed %d items, left %d\n", ! 185: inputDataConsumed, ! 186: dataNotConsumed ! 187: )); ! 188: ! 189: setPointerContext.InputCount += inputDataConsumed; ! 190: ! 191: if (dataNotConsumed) { ! 192: setPointerContext.DataOut = ! 193: ((PUCHAR)getPointerContext.DataOut) + ! 194: (inputDataConsumed * sizeof(KEYBOARD_INPUT_DATA)); ! 195: } else { ! 196: setPointerContext.DataOut = ! 197: deviceExtension->KeyboardExtension.InputData; ! 198: getPointerContext.DataOut = setPointerContext.DataOut; ! 199: } ! 200: } ! 201: ! 202: // ! 203: // Call the class callback ISR with data remaining in the queue. ! 204: // ! 205: ! 206: if ((dataNotConsumed == 0) && ! 207: (inputDataConsumed < getPointerContext.InputCount)){ ! 208: I8xPrint(( ! 209: 2, ! 210: "I8042PRT-I8042KeyboardIsrDpc: calling class callback\n" ! 211: )); ! 212: I8xPrint(( ! 213: 2, ! 214: "I8042PRT-I8042KeyboardIsrDpc: with Start 0x%x and End 0x%x\n", ! 215: getPointerContext.DataOut, ! 216: getPointerContext.DataIn ! 217: )); ! 218: ! 219: (*(PSERVICE_CALLBACK_ROUTINE) classService)( ! 220: classDeviceObject, ! 221: getPointerContext.DataOut, ! 222: getPointerContext.DataIn, ! 223: &inputDataConsumed ! 224: ); ! 225: ! 226: dataNotConsumed = (((PUCHAR) getPointerContext.DataIn - ! 227: (PUCHAR) getPointerContext.DataOut) ! 228: / sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed; ! 229: ! 230: I8xPrint(( ! 231: 2, ! 232: "I8042PRT-I8042KeyboardIsrDpc: Call callback consumed %d items, left %d\n", ! 233: inputDataConsumed, ! 234: dataNotConsumed ! 235: )); ! 236: ! 237: setPointerContext.DataOut = ! 238: ((PUCHAR)getPointerContext.DataOut) + ! 239: (inputDataConsumed * sizeof(KEYBOARD_INPUT_DATA)); ! 240: setPointerContext.InputCount += inputDataConsumed; ! 241: ! 242: } ! 243: ! 244: // ! 245: // Update the port InputData queue DataOut pointer and InputCount ! 246: // synchronously. ! 247: // ! 248: ! 249: KeSynchronizeExecution( ! 250: deviceExtension->KeyboardInterruptObject, ! 251: (PKSYNCHRONIZE_ROUTINE) I8xSetDataQueuePointer, ! 252: (PVOID) &setPointerContext ! 253: ); ! 254: ! 255: } ! 256: ! 257: if (dataNotConsumed) { ! 258: ! 259: // ! 260: // The class driver was unable to consume all the data. ! 261: // Reset the interlocked variable to -1. We do not want ! 262: // to attempt to move more data to the class driver at this ! 263: // point, because it is already overloaded. Need to wait a ! 264: // while to give the Raw Input Thread a chance to read some ! 265: // of the data out of the class driver's queue. We accomplish ! 266: // this "wait" via a timer. ! 267: // ! 268: ! 269: I8xPrint((2, "I8042PRT-I8042KeyboardIsrDpc: set timer in DPC\n")); ! 270: ! 271: operationContext.Operation = WriteOperation; ! 272: interlockedResult = -1; ! 273: operationContext.NewValue = &interlockedResult; ! 274: ! 275: KeSynchronizeExecution( ! 276: deviceExtension->KeyboardInterruptObject, ! 277: (PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation, ! 278: (PVOID) &operationContext ! 279: ); ! 280: ! 281: deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000); ! 282: deltaTime.HighPart = -1; ! 283: ! 284: (VOID) KeSetTimer( ! 285: &deviceExtension->KeyboardExtension.DataConsumptionTimer, ! 286: deltaTime, ! 287: &deviceExtension->KeyboardIsrDpcRetry ! 288: ); ! 289: ! 290: moreDpcProcessing = FALSE; ! 291: ! 292: } else { ! 293: ! 294: // ! 295: // Decrement DpcInterlockKeyboard. If the result goes negative, ! 296: // then we're all finished processing the DPC. Otherwise, either ! 297: // the ISR incremented DpcInterlockKeyboard because it has more ! 298: // work for the ISR DPC to do, or a concurrent DPC executed on ! 299: // some processor while the current DPC was running (the ! 300: // concurrent DPC wouldn't have done any work). Make sure that ! 301: // the current DPC handles any extra work that is ready to be ! 302: // done. ! 303: // ! 304: ! 305: operationContext.Operation = DecrementOperation; ! 306: operationContext.NewValue = &interlockedResult; ! 307: ! 308: KeSynchronizeExecution( ! 309: deviceExtension->KeyboardInterruptObject, ! 310: (PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation, ! 311: (PVOID) &operationContext ! 312: ); ! 313: ! 314: if (interlockedResult != -1) { ! 315: ! 316: // ! 317: // The interlocked variable is still greater than or equal to ! 318: // zero. Reset it to zero, so that we execute the loop one ! 319: // more time (assuming no more DPCs execute and bump the ! 320: // variable up again). ! 321: // ! 322: ! 323: operationContext.Operation = WriteOperation; ! 324: interlockedResult = 0; ! 325: operationContext.NewValue = &interlockedResult; ! 326: ! 327: KeSynchronizeExecution( ! 328: deviceExtension->KeyboardInterruptObject, ! 329: (PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation, ! 330: (PVOID) &operationContext ! 331: ); ! 332: ! 333: I8xPrint((2, "I8042PRT-I8042KeyboardIsrDpc: loop in DPC\n")); ! 334: } else { ! 335: moreDpcProcessing = FALSE; ! 336: } ! 337: } ! 338: ! 339: } ! 340: ! 341: I8xPrint((2, "I8042PRT-I8042KeyboardIsrDpc: exit\n")); ! 342: ! 343: } ! 344: ! 345: BOOLEAN ! 346: I8xWriteDataToKeyboardQueue( ! 347: PPORT_KEYBOARD_EXTENSION KeyboardExtension, ! 348: IN PKEYBOARD_INPUT_DATA InputData ! 349: ) ! 350: ! 351: /*++ ! 352: ! 353: Routine Description: ! 354: ! 355: This routine adds input data from the keyboard to the InputData queue. ! 356: ! 357: Arguments: ! 358: ! 359: KeyboardExtension - Pointer to the keyboard portion of the device extension. ! 360: ! 361: InputData - Pointer to the data to add to the InputData queue. ! 362: ! 363: Return Value: ! 364: ! 365: Returns TRUE if the data was added, otherwise FALSE. ! 366: ! 367: --*/ ! 368: ! 369: { ! 370: ! 371: PKEYBOARD_INPUT_DATA previousDataIn; ! 372: ! 373: I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: enter\n")); ! 374: I8xPrint(( ! 375: 3, ! 376: "I8042PRT-I8xWriteDataToKeyboardQueue: DataIn 0x%x, DataOut 0x%x\n", ! 377: KeyboardExtension->DataIn, ! 378: KeyboardExtension->DataOut ! 379: )); ! 380: I8xPrint(( ! 381: 3, ! 382: "I8042PRT-I8xWriteDataToKeyboardQueue: InputCount %d\n", ! 383: KeyboardExtension->InputCount ! 384: )); ! 385: ! 386: // ! 387: // Check for full input data queue. ! 388: // ! 389: ! 390: if ((KeyboardExtension->DataIn == KeyboardExtension->DataOut) && ! 391: (KeyboardExtension->InputCount != 0)) { ! 392: ! 393: // ! 394: // Queue overflow. Replace the previous input data packet ! 395: // with a keyboard overrun data packet, thus losing both the ! 396: // previous and the current input data packet. ! 397: // ! 398: ! 399: I8xPrint((1,"I8042PRT-I8xWriteDataToKeyboardQueue: OVERFLOW\n")); ! 400: ! 401: if (KeyboardExtension->DataIn == KeyboardExtension->InputData) { ! 402: I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: wrap buffer\n")); ! 403: previousDataIn = KeyboardExtension->DataEnd; ! 404: } else { ! 405: previousDataIn = KeyboardExtension->DataIn - 1; ! 406: } ! 407: ! 408: previousDataIn->MakeCode = KEYBOARD_OVERRUN_MAKE_CODE; ! 409: previousDataIn->Flags = 0; ! 410: ! 411: I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: exit\n")); ! 412: return(FALSE); ! 413: ! 414: } else { ! 415: *(KeyboardExtension->DataIn) = *InputData; ! 416: KeyboardExtension->InputCount += 1; ! 417: KeyboardExtension->DataIn++; ! 418: I8xPrint(( ! 419: 2, ! 420: "I8042PRT-I8xWriteDataToKeyboardQueue: new InputCount %d\n", ! 421: KeyboardExtension->InputCount ! 422: )); ! 423: if (KeyboardExtension->DataIn == ! 424: KeyboardExtension->DataEnd) { ! 425: I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: wrap buffer\n")); ! 426: KeyboardExtension->DataIn = KeyboardExtension->InputData; ! 427: } ! 428: } ! 429: ! 430: I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: exit\n")); ! 431: ! 432: return(TRUE); ! 433: } ! 434:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.