mirror of
https://github.com/reactos/reactos.git
synced 2025-05-16 15:50:24 +00:00

- Totally dynamic based on the principle of Native Providers built-in the Kernel (like Screen, FileLog and Serial) and a pluggable Wrapper which is optionally compiled (Bochs, GDB) - Nothing changed in KDBG, except for that its settings (KDSERIAL/KDNOECHO) are now stored in KdbDebugState instead. - Wrappers are currently built uncondtionally. With rbuild, I'll make them easily removable. - Debug Log code simplified greatly, sped up and now supports printing even the first boot messages, which wasn't supported before. - Removed most of KDBG compile-time settings, ones which are needed are in include/dbg as macros now. - Left in some kdbg init code and break code, but it could be made to be used as a 'wrapper' for those functions. I will do it later. - Made a hack for KdpEnterDebuggerException..it seems to be called differently and at different times for GDB vs KDBG and I couldn't unite them. - KdpServiceDispatcher now does both the documented and ros-internal debug functions and will eventually be called through INT2D from keyboard.sys instead of as an API. All in all, this patch makes KD separated from KDBG and creates a pluggable architecture for creating future wrappers that don't require changing tons of code in the future. It improves the debug log by printing even the earliest debug messages to it and it removes many of the manual ifdef(KDBG) but making them automatic though a single macro file. It makes extra debugging functionality optional and it allows removal of a private API from our exports. svn path=/trunk/; revision=14799
907 lines
23 KiB
C
907 lines
23 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: services/dd/keyboard/keyboard.c
|
|
* PURPOSE: Keyboard driver
|
|
* PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
|
|
* Jason Filby (jasonfilby@yahoo.com)
|
|
*/
|
|
|
|
/* INCLUDES ****************************************************************/
|
|
|
|
#include <ddk/ntddk.h>
|
|
#include <string.h>
|
|
#include <ntos/keyboard.h>
|
|
#include <ntos/minmax.h>
|
|
#include <rosrtl/string.h>
|
|
|
|
#include <ddk/ntddkbd.h>
|
|
#include <ddk/ntdd8042.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#include "keyboard.h"
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
/*
|
|
* Driver data
|
|
*/
|
|
|
|
static KEY_EVENT_RECORD kbdBuffer[KBD_BUFFER_SIZE];
|
|
static int bufHead,bufTail;
|
|
static int keysInBuffer;
|
|
static int extKey;
|
|
static BYTE ledStatus;
|
|
static BYTE capsDown,numDown,scrollDown;
|
|
static DWORD ctrlKeyState;
|
|
static PKINTERRUPT KbdInterrupt;
|
|
static KDPC KbdDpc;
|
|
static PIO_WORKITEM KbdWorkItem = NULL;
|
|
static BOOLEAN AlreadyOpened = FALSE;
|
|
|
|
/*
|
|
* PURPOSE: Current irp being processed
|
|
*/
|
|
static PIRP CurrentIrp;
|
|
|
|
/*
|
|
* PURPOSE: Number of keys that have been read into the current irp's buffer
|
|
*/
|
|
static ULONG KeysRead;
|
|
static ULONG KeysRequired;
|
|
|
|
/*
|
|
* Virtual key codes table
|
|
*
|
|
* Comments:
|
|
* * PrtSc = VK_PRINT
|
|
* * Alt+PrtSc (SysRq) = VK_EXECUTE
|
|
* * Alt = VK_MENU
|
|
*/
|
|
|
|
static const WORD vkTable[128]=
|
|
{
|
|
/* 00 - 07 */ 0, VK_ESCAPE, VK_1, VK_2, VK_3, VK_4, VK_5, VK_6,
|
|
/* 08 - 0F */ VK_7, VK_8, VK_9, VK_0, 189, 187, VK_BACK, VK_TAB,
|
|
/* 10 - 17 */ VK_Q, VK_W, VK_E, VK_R, VK_T, VK_Y, VK_U, VK_I,
|
|
/* 18 - 1F */ VK_O, VK_P, 219, 221, VK_RETURN, VK_CONTROL, VK_A, VK_S,
|
|
/* 20 - 27 */ VK_D, VK_F, VK_G, VK_H, VK_J, VK_K, VK_L, 186,
|
|
/* 28 - 2F */ 222, 192, VK_SHIFT, 220, VK_Z, VK_X, VK_C, VK_V,
|
|
/* 30 - 37 */ VK_B, VK_N, VK_M, 188, 190, 191, VK_SHIFT, VK_MULTIPLY,
|
|
/* 38 - 3F */ VK_MENU, VK_SPACE, VK_CAPITAL, VK_F1, VK_F2, VK_F3, VK_F4, VK_F5,
|
|
/* 40 - 47 */ VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, VK_NUMLOCK, VK_SCROLL, VK_HOME,
|
|
/* 48 - 4F */ VK_UP, VK_PRIOR, VK_SUBTRACT, VK_LEFT, VK_CLEAR, VK_RIGHT, VK_ADD, VK_END,
|
|
/* 50 - 57 */ VK_DOWN, VK_NEXT, VK_INSERT, VK_DELETE, VK_EXECUTE, 0, 0, VK_F11,
|
|
/* 58 - 5F */ VK_F12, 0, 0, 91, 92, 93, 0, 0,
|
|
/* 60 - 67 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 68 - 6F */ 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 70 - 77 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 78 - 7F */ 0, 0, 0, 0, 0, 0, 0, VK_PAUSE
|
|
};
|
|
static const WORD vkKeypadTable[13]= /* 47 - 53 */
|
|
{
|
|
VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9, VK_SUBTRACT,
|
|
VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_ADD,
|
|
VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD0, VK_DECIMAL
|
|
};
|
|
|
|
|
|
/*
|
|
* ASCII translation tables
|
|
*/
|
|
|
|
static const BYTE asciiTable1[10]=
|
|
{
|
|
')','!','@','#','$','%','^','&','*','('
|
|
};
|
|
static const BYTE asciiTable2[16]=
|
|
{
|
|
'0','1','2','3','4','5','6','7','8','9','*','+',0,'-','.','/'
|
|
};
|
|
static const BYTE asciiTable3[37]=
|
|
{
|
|
';','=',',','-','.','/','`', 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
'[', '\\', ']', '\''
|
|
};
|
|
static const BYTE asciiTable4[37]=
|
|
{
|
|
':','+','<','_','>','?','~', 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
'{', '|', '}', '"'
|
|
};
|
|
|
|
VOID STDCALL
|
|
KdpServiceDispatcher(ULONG Code, PVOID Context1, PVOID Context2);
|
|
|
|
static LONG DoSystemDebug = -1;
|
|
static BOOLEAN InSysRq = FALSE;
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
static void KbdWrite(int addr,BYTE data)
|
|
/*
|
|
* FUNCTION: Write data to keyboard
|
|
*/
|
|
{
|
|
BYTE status;
|
|
|
|
do
|
|
{
|
|
status=READ_PORT_UCHAR((PUCHAR)KBD_CTRL_PORT); // Wait until input buffer empty
|
|
} while(status & KBD_IBF);
|
|
WRITE_PORT_UCHAR((PUCHAR)addr,data);
|
|
}
|
|
|
|
static int KbdReadData(void)
|
|
/*
|
|
* FUNCTION: Read data from port 0x60
|
|
*/
|
|
{
|
|
int i;
|
|
BYTE status,data;
|
|
|
|
i=500000;
|
|
do
|
|
{
|
|
status=READ_PORT_UCHAR((PUCHAR)KBD_CTRL_PORT);
|
|
if (!(status & KBD_OBF)) // Check if data available
|
|
continue;
|
|
data=READ_PORT_UCHAR((PUCHAR)KBD_DATA_PORT);
|
|
if (status & (KBD_GTO | KBD_PERR)) // Check for timeout error
|
|
continue;
|
|
return data;
|
|
} while(--i);
|
|
return -1; // Timed out
|
|
}
|
|
|
|
|
|
/*
|
|
* Set keyboard LED's
|
|
*/
|
|
|
|
static void SetKeyboardLEDs(BYTE status)
|
|
{
|
|
KbdWrite(KBD_DATA_PORT,0xED);
|
|
if (KbdReadData()!=KBD_ACK) // Error
|
|
return;
|
|
KbdWrite(KBD_DATA_PORT,status);
|
|
KbdReadData();
|
|
}
|
|
|
|
|
|
/*
|
|
* Process scan code
|
|
*/
|
|
|
|
static void ProcessScanCode(BYTE scanCode,BOOL isDown)
|
|
{
|
|
switch(scanCode)
|
|
{
|
|
case 0x1D: // Ctrl
|
|
if (extKey)
|
|
{
|
|
if (isDown)
|
|
ctrlKeyState|=RIGHT_CTRL_PRESSED;
|
|
else
|
|
ctrlKeyState&=~RIGHT_CTRL_PRESSED;
|
|
}
|
|
else
|
|
{
|
|
if (isDown)
|
|
ctrlKeyState|=LEFT_CTRL_PRESSED;
|
|
else
|
|
ctrlKeyState&=~LEFT_CTRL_PRESSED;
|
|
}
|
|
break;
|
|
case 0x2A: // Left shift
|
|
case 0x36: // Right shift
|
|
if (isDown)
|
|
ctrlKeyState|=SHIFT_PRESSED;
|
|
else
|
|
ctrlKeyState&=~SHIFT_PRESSED;
|
|
break;
|
|
case 0x38: // Alt
|
|
if (extKey)
|
|
{
|
|
if (isDown)
|
|
ctrlKeyState|=RIGHT_ALT_PRESSED;
|
|
else
|
|
ctrlKeyState&=~RIGHT_ALT_PRESSED;
|
|
}
|
|
else
|
|
{
|
|
if (isDown)
|
|
ctrlKeyState|=LEFT_ALT_PRESSED;
|
|
else
|
|
ctrlKeyState&=~LEFT_ALT_PRESSED;
|
|
}
|
|
break;
|
|
case 0x3A: // CapsLock
|
|
if (ctrlKeyState & CTRL_PRESSED)
|
|
break;
|
|
if (isDown)
|
|
{
|
|
if (!capsDown)
|
|
{
|
|
capsDown=1;
|
|
if (ctrlKeyState & CAPSLOCK_ON)
|
|
{
|
|
ledStatus&=~KBD_LED_CAPS;
|
|
ctrlKeyState&=~CAPSLOCK_ON;
|
|
}
|
|
else
|
|
{
|
|
ledStatus|=KBD_LED_CAPS;
|
|
ctrlKeyState|=CAPSLOCK_ON;
|
|
}
|
|
SetKeyboardLEDs(ledStatus);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
capsDown=0;
|
|
}
|
|
break;
|
|
case 0x45: // NumLock
|
|
if (ctrlKeyState & CTRL_PRESSED)
|
|
break;
|
|
if (isDown)
|
|
{
|
|
if (!numDown)
|
|
{
|
|
numDown=1;
|
|
if (ctrlKeyState & NUMLOCK_ON)
|
|
{
|
|
ledStatus&=~KBD_LED_NUM;
|
|
ctrlKeyState&=~NUMLOCK_ON;
|
|
}
|
|
else
|
|
{
|
|
ledStatus|=KBD_LED_NUM;
|
|
ctrlKeyState|=NUMLOCK_ON;
|
|
}
|
|
SetKeyboardLEDs(ledStatus);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
numDown=0;
|
|
}
|
|
break;
|
|
case 0x46: // ScrollLock
|
|
if (ctrlKeyState & CTRL_PRESSED)
|
|
break;
|
|
if (isDown)
|
|
{
|
|
if (!scrollDown)
|
|
{
|
|
scrollDown=1;
|
|
if (ctrlKeyState & SCROLLLOCK_ON)
|
|
{
|
|
ledStatus&=~KBD_LED_SCROLL;
|
|
ctrlKeyState&=~SCROLLLOCK_ON;
|
|
}
|
|
else
|
|
{
|
|
ledStatus|=KBD_LED_SCROLL;
|
|
ctrlKeyState|=SCROLLLOCK_ON;
|
|
}
|
|
SetKeyboardLEDs(ledStatus);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
scrollDown=0;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Translate virtual key code to ASCII
|
|
*/
|
|
|
|
static BYTE VirtualToAscii(WORD keyCode,BOOL isDown)
|
|
{
|
|
if ((ctrlKeyState & ALT_PRESSED)&&(ctrlKeyState & CTRL_PRESSED))
|
|
return 0; // Ctrl+Alt+char always 0
|
|
if ((!isDown)&&(ctrlKeyState & ALT_PRESSED))
|
|
return 0; // Alt+char is 0 when key is released
|
|
|
|
if (ctrlKeyState & CTRL_PRESSED)
|
|
{
|
|
if ((keyCode>=VK_A)&&(keyCode<=VK_Z))
|
|
return keyCode-VK_A+1;
|
|
switch(keyCode)
|
|
{
|
|
case VK_SPACE:
|
|
return ' ';
|
|
case VK_BACK:
|
|
return 127;
|
|
case VK_RETURN:
|
|
return '\r';
|
|
case 219: /* [ */
|
|
if (ctrlKeyState & SHIFT_PRESSED)
|
|
return 0;
|
|
return 27;
|
|
case 220: /* \ */
|
|
if (ctrlKeyState & SHIFT_PRESSED)
|
|
return 0;
|
|
return 28;
|
|
case 221: /* ] */
|
|
if (ctrlKeyState & SHIFT_PRESSED)
|
|
return 0;
|
|
return 29;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ((keyCode>=VK_A)&&(keyCode<=VK_Z))
|
|
{
|
|
if (ctrlKeyState & CAPSLOCK_ON)
|
|
if (ctrlKeyState & SHIFT_PRESSED)
|
|
return keyCode-VK_A+'a';
|
|
else
|
|
return keyCode-VK_A+'A';
|
|
else
|
|
if (ctrlKeyState & SHIFT_PRESSED)
|
|
return keyCode-VK_A+'A';
|
|
else
|
|
return keyCode-VK_A+'a';
|
|
}
|
|
|
|
if ((keyCode>=VK_0)&&(keyCode<=VK_9))
|
|
{
|
|
if (ctrlKeyState & SHIFT_PRESSED)
|
|
return asciiTable1[keyCode-VK_0];
|
|
else
|
|
return keyCode-VK_0+'0';
|
|
}
|
|
|
|
if ((keyCode>=VK_NUMPAD0)&&(keyCode<=VK_DIVIDE))
|
|
return asciiTable2[keyCode-VK_NUMPAD0];
|
|
|
|
if ((keyCode>=186)&&(keyCode<=222))
|
|
{
|
|
if (ctrlKeyState & SHIFT_PRESSED)
|
|
return asciiTable4[keyCode-186];
|
|
else
|
|
return asciiTable3[keyCode-186];
|
|
}
|
|
|
|
switch(keyCode)
|
|
{
|
|
case VK_SPACE:
|
|
return ' ';
|
|
case VK_RETURN:
|
|
return '\r';
|
|
case VK_BACK:
|
|
return 8;
|
|
case VK_TAB:
|
|
return 9;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Translate scan code to virtual key code
|
|
*/
|
|
|
|
static WORD ScanToVirtual(BYTE scanCode)
|
|
{
|
|
if ((scanCode>=0x47)&&(scanCode<=0x53)&&(ctrlKeyState & NUMLOCK_ON)&&
|
|
(!extKey)&&(!(ctrlKeyState & SHIFT_PRESSED)))
|
|
return vkKeypadTable[scanCode-0x47];
|
|
if ((scanCode==0x35)&&(extKey)) // Gray divide
|
|
return VK_DIVIDE;
|
|
if ((scanCode==0x37)&&(extKey)) // Print screen
|
|
return VK_PRINT;
|
|
return vkTable[scanCode];
|
|
}
|
|
|
|
|
|
/*
|
|
* Debug request handler
|
|
*/
|
|
|
|
static VOID STDCALL
|
|
KbdWorkItemRoutine(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Context)
|
|
{
|
|
LONG Debug;
|
|
|
|
Debug = InterlockedExchange(&DoSystemDebug, -1);
|
|
if (Debug != -1)
|
|
{
|
|
KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)Debug, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Keyboard IRQ handler
|
|
*/
|
|
|
|
static VOID STDCALL
|
|
KbdDpcRoutine(PKDPC Dpc,
|
|
PVOID DeferredContext,
|
|
PVOID SystemArgument1,
|
|
PVOID SystemArgument2)
|
|
{
|
|
PIRP Irp = (PIRP)SystemArgument2;
|
|
PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)SystemArgument1;
|
|
|
|
if (SystemArgument1 == NULL && DoSystemDebug != -1)
|
|
{
|
|
if (KbdWorkItem != NULL && DoSystemDebug == 10) /* 10 is Tab + K (enter kernel debugger) */
|
|
{
|
|
IoQueueWorkItem(KbdWorkItem, (PIO_WORKITEM_ROUTINE)KbdWorkItemRoutine, DelayedWorkQueue, NULL);
|
|
}
|
|
else
|
|
{
|
|
KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)DoSystemDebug, NULL);
|
|
DoSystemDebug = -1;
|
|
}
|
|
return;
|
|
}
|
|
|
|
CHECKPOINT;
|
|
DPRINT("KbdDpcRoutine(DeviceObject %x, Irp %x)\n",
|
|
DeviceObject,Irp);
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
IoStartNextPacket(DeviceObject,FALSE);
|
|
}
|
|
|
|
|
|
static BOOLEAN STDCALL
|
|
KeyboardHandler(PKINTERRUPT Interrupt,
|
|
PVOID Context)
|
|
{
|
|
BYTE thisKey;
|
|
BOOL isDown;
|
|
static BYTE lastKey;
|
|
CHAR Status;
|
|
PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) Context;
|
|
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
|
|
|
|
CHECKPOINT;
|
|
|
|
/*
|
|
* Check status
|
|
*/
|
|
Status = READ_PORT_UCHAR((PUCHAR)KBD_CTRL_PORT);
|
|
if (!(Status & KBD_OBF))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
// Read scan code
|
|
thisKey=READ_PORT_UCHAR((PUCHAR)KBD_DATA_PORT);
|
|
|
|
// Call hook routine. May change scancode value.
|
|
if (deviceExtension->IsrHookCallback) {
|
|
BOOLEAN cont = FALSE, ret;
|
|
//BUG BUG: rewrite to have valid CurrentScanState!!!
|
|
ret = (*deviceExtension->IsrHookCallback)(
|
|
deviceObject,
|
|
NULL,//&deviceExtension->CurrentInput,
|
|
NULL,//&deviceExtension->CurrentOutput,
|
|
Status,
|
|
&thisKey, //&scanCode,
|
|
&cont,
|
|
NULL //&deviceExtension->CurrentScanState
|
|
);
|
|
|
|
if (!cont) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
if ((thisKey==0xE0)||(thisKey==0xE1)) // Extended key
|
|
{
|
|
extKey=1; // Wait for next byte
|
|
lastKey=thisKey;
|
|
return FALSE;
|
|
}
|
|
|
|
isDown=!(thisKey & 0x80);
|
|
thisKey&=0x7F;
|
|
|
|
// The keyboard maintains its own internal caps lock and num lock
|
|
// statuses. In caps lock mode E0 AA precedes make code and
|
|
// E0 2A follow break code. In num lock mode, E0 2A precedes
|
|
// make code and E0 AA follow break code. We maintain our own caps lock
|
|
// and num lock statuses, so we will just ignore these.
|
|
// Some keyboards have L-Shift/R-Shift modes instead of caps lock
|
|
// mode. If right shift pressed, E0 B6 / E0 36 pairs generated.
|
|
if (extKey & ((thisKey==0x2A)||(thisKey==0x36)))
|
|
{
|
|
extKey=0;
|
|
return FALSE;
|
|
}
|
|
|
|
// Check for PAUSE sequence
|
|
if (extKey && (lastKey==0xE1))
|
|
{
|
|
if (thisKey==0x1D)
|
|
lastKey=0xFF; // Sequence is OK
|
|
else
|
|
extKey=0;
|
|
return FALSE;
|
|
}
|
|
if (extKey && (lastKey==0xFF))
|
|
{
|
|
if (thisKey!=0x45)
|
|
{
|
|
extKey=0; // Bad sequence
|
|
return FALSE;
|
|
}
|
|
thisKey=0x7F; // Pseudo-code for PAUSE
|
|
}
|
|
|
|
ProcessScanCode(thisKey,isDown);
|
|
|
|
// DbgPrint("Key: %c\n",VirtualToAscii(ScanToVirtual(thisKey),isDown));
|
|
// DbgPrint("Key: %x\n",ScanToVirtual(thisKey));
|
|
if (ScanToVirtual(thisKey) == VK_TAB && isDown)
|
|
{
|
|
InSysRq = TRUE;
|
|
}
|
|
else if (ScanToVirtual(thisKey) == VK_TAB && !isDown)
|
|
{
|
|
InSysRq = FALSE;
|
|
}
|
|
else if (InSysRq == TRUE && ScanToVirtual(thisKey) >= VK_A &&
|
|
ScanToVirtual(thisKey) <= VK_Z && isDown)
|
|
{
|
|
InterlockedExchange(&DoSystemDebug, ScanToVirtual(thisKey) - VK_A);
|
|
KeInsertQueueDpc(&KbdDpc, NULL, NULL);
|
|
return(TRUE);
|
|
}
|
|
|
|
if (CurrentIrp!=NULL)
|
|
{
|
|
KEY_EVENT_RECORD* rec = (KEY_EVENT_RECORD *)
|
|
CurrentIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
CHECKPOINT;
|
|
|
|
rec[KeysRead].bKeyDown=isDown;
|
|
rec[KeysRead].wRepeatCount=1;
|
|
rec[KeysRead].wVirtualKeyCode=ScanToVirtual(thisKey);
|
|
rec[KeysRead].wVirtualScanCode=thisKey;
|
|
rec[KeysRead].uChar.AsciiChar=VirtualToAscii(rec->wVirtualKeyCode,isDown);
|
|
rec[KeysRead].dwControlKeyState=ctrlKeyState;
|
|
if (extKey)
|
|
{
|
|
rec[KeysRead].dwControlKeyState|=ENHANCED_KEY;
|
|
extKey = 0;
|
|
}
|
|
KeysRead++;
|
|
DPRINT("KeysRequired %d KeysRead %x\n",KeysRequired,KeysRead);
|
|
if (KeysRead==KeysRequired)
|
|
{
|
|
PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT) Context;
|
|
KeInsertQueueDpc(&KbdDpc,DeviceObject,CurrentIrp);
|
|
CurrentIrp=NULL;
|
|
}
|
|
CHECKPOINT;
|
|
return TRUE;
|
|
}
|
|
|
|
// Buffer is full ?
|
|
if (keysInBuffer==KBD_BUFFER_SIZE) // Buffer is full
|
|
{
|
|
extKey=0;
|
|
return(TRUE);
|
|
}
|
|
kbdBuffer[bufHead].bKeyDown=isDown;
|
|
kbdBuffer[bufHead].wRepeatCount=1;
|
|
kbdBuffer[bufHead].wVirtualKeyCode=ScanToVirtual(thisKey);
|
|
kbdBuffer[bufHead].wVirtualScanCode=thisKey;
|
|
kbdBuffer[bufHead].uChar.UnicodeChar=0;
|
|
// kbdBuffer[bufHead].uChar.AsciiChar=TranslateScanCode(thisKey);
|
|
kbdBuffer[bufHead].uChar.AsciiChar=VirtualToAscii(kbdBuffer[bufHead].wVirtualKeyCode,isDown);
|
|
kbdBuffer[bufHead].dwControlKeyState=ctrlKeyState;
|
|
if (extKey)
|
|
kbdBuffer[bufHead].dwControlKeyState|=ENHANCED_KEY;
|
|
bufHead++;
|
|
bufHead&=KBD_WRAP_MASK; // Modulo KBD_BUFFER_SIZE
|
|
keysInBuffer++;
|
|
extKey=0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize keyboard
|
|
//
|
|
static void KeyboardConnectInterrupt(PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
ULONG MappedIrq;
|
|
KIRQL Dirql;
|
|
KAFFINITY Affinity;
|
|
NTSTATUS Status;
|
|
|
|
MappedIrq = HalGetInterruptVector(Internal,
|
|
0,
|
|
0,
|
|
KEYBOARD_IRQ,
|
|
&Dirql,
|
|
&Affinity);
|
|
Status = IoConnectInterrupt(&KbdInterrupt,
|
|
KeyboardHandler,
|
|
(PVOID)DeviceObject,
|
|
NULL,
|
|
MappedIrq,
|
|
Dirql,
|
|
Dirql,
|
|
0,
|
|
FALSE,
|
|
Affinity,
|
|
FALSE);
|
|
}
|
|
|
|
VOID
|
|
KbdClearInput(VOID)
|
|
{
|
|
ULONG i;
|
|
CHAR Status;
|
|
|
|
for (i = 0; i < 100; i++)
|
|
{
|
|
Status = READ_PORT_UCHAR((PUCHAR)KBD_CTRL_PORT);
|
|
if (!(Status & KBD_OBF))
|
|
{
|
|
return;
|
|
}
|
|
(VOID)READ_PORT_UCHAR((PUCHAR)KBD_DATA_PORT);
|
|
}
|
|
}
|
|
|
|
static int InitializeKeyboard(PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
// Initialize variables
|
|
bufHead=0;
|
|
bufTail=0;
|
|
keysInBuffer=0;
|
|
ledStatus=0;
|
|
capsDown=0;
|
|
numDown=0;
|
|
scrollDown=0;
|
|
ctrlKeyState=0;
|
|
extKey=0;
|
|
|
|
KbdClearInput();
|
|
KeyboardConnectInterrupt(DeviceObject);
|
|
KeInitializeDpc(&KbdDpc,KbdDpcRoutine,NULL);
|
|
KbdWorkItem = IoAllocateWorkItem(DeviceObject);
|
|
if (KbdWorkItem == NULL)
|
|
{
|
|
DPRINT("Warning: Couldn't allocate work item!\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read data from keyboard buffer
|
|
*/
|
|
BOOLEAN STDCALL
|
|
KbdSynchronizeRoutine(PVOID Context)
|
|
{
|
|
PIRP Irp = (PIRP)Context;
|
|
KEY_EVENT_RECORD* rec = (KEY_EVENT_RECORD *)Irp->AssociatedIrp.SystemBuffer;
|
|
PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
|
|
ULONG NrToRead = stk->Parameters.Read.Length/sizeof(KEY_EVENT_RECORD);
|
|
int i;
|
|
|
|
DPRINT("NrToRead %d keysInBuffer %d\n",NrToRead,keysInBuffer);
|
|
NrToRead = min(NrToRead,keysInBuffer);
|
|
|
|
DPRINT("NrToRead %d stk->Parameters.Read.Length %d\n",
|
|
NrToRead,stk->Parameters.Read.Length);
|
|
DPRINT("sizeof(KEY_EVENT_RECORD) %d\n",sizeof(KEY_EVENT_RECORD));
|
|
for (i=0;i<NrToRead;i++)
|
|
{
|
|
memcpy(&rec[i],&kbdBuffer[bufTail],sizeof(KEY_EVENT_RECORD));
|
|
bufTail++;
|
|
bufTail&=KBD_WRAP_MASK;
|
|
keysInBuffer--;
|
|
}
|
|
if ((stk->Parameters.Read.Length/sizeof(KEY_EVENT_RECORD))==NrToRead)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
KeysRequired=stk->Parameters.Read.Length/sizeof(KEY_EVENT_RECORD);
|
|
KeysRead=NrToRead;
|
|
CurrentIrp=Irp;
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
VOID STDCALL KbdStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
#ifndef NDEBUG
|
|
PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
|
|
#endif
|
|
|
|
DPRINT("KeyboardStartIo(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
|
|
|
|
if (KeSynchronizeExecution(KbdInterrupt, KbdSynchronizeRoutine, Irp))
|
|
{
|
|
KIRQL oldIrql;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
oldIrql = KeGetCurrentIrql();
|
|
if (oldIrql < DISPATCH_LEVEL)
|
|
{
|
|
KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
|
|
IoStartNextPacket (DeviceObject, FALSE);
|
|
KeLowerIrql(oldIrql);
|
|
}
|
|
else
|
|
{
|
|
IoStartNextPacket (DeviceObject, FALSE);
|
|
}
|
|
}
|
|
|
|
DPRINT("stk->Parameters.Read.Length %d\n",stk->Parameters.Read.Length);
|
|
DPRINT("KeysRequired %d\n",KeysRequired);
|
|
}
|
|
|
|
NTSTATUS STDCALL KbdInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION stk;
|
|
PINTERNAL_I8042_HOOK_KEYBOARD hookKeyboard;
|
|
PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
stk = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
switch (stk->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
/*-----------------11/29/2001 4:12PM----------------
|
|
* This internal ioctrl belongs in i8042 driver. Should be
|
|
* moved to the appropriate driver later.
|
|
* --------------------------------------------------*/
|
|
case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
|
|
|
|
if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(INTERNAL_I8042_HOOK_KEYBOARD))
|
|
{
|
|
DPRINT(("Keyboard IOCTL_INTERNAL_I8042_HOOK_KEYBOARD invalid buffer size\n"));
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
//
|
|
// Copy the values if they are filled in
|
|
//
|
|
hookKeyboard = (PINTERNAL_I8042_HOOK_KEYBOARD)
|
|
stk->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
DevExt->HookContext = hookKeyboard->Context;
|
|
if (hookKeyboard->InitializationRoutine) {
|
|
DbgPrint("Keyboard: InitializationHookCallback NOT IMPLEMENTED\n");
|
|
DevExt->InitializationHookCallback =
|
|
hookKeyboard->InitializationRoutine;
|
|
}
|
|
|
|
if (hookKeyboard->IsrRoutine) {
|
|
DevExt->IsrHookCallback = hookKeyboard->IsrRoutine;
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
default:
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS STDCALL KbdDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("DeviceObject %x\n",DeviceObject);
|
|
DPRINT("Irp %x\n",Irp);
|
|
|
|
DPRINT("IRP_MJ_CREATE %d stk->MajorFunction %d\n",
|
|
IRP_MJ_CREATE, stk->MajorFunction);
|
|
DPRINT("AlreadyOpened %d\n",AlreadyOpened);
|
|
|
|
switch (stk->MajorFunction)
|
|
{
|
|
case IRP_MJ_CREATE:
|
|
if (AlreadyOpened == TRUE)
|
|
{
|
|
CHECKPOINT;
|
|
// Status = STATUS_UNSUCCESSFUL;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
CHECKPOINT;
|
|
Status = STATUS_SUCCESS;
|
|
AlreadyOpened = TRUE;
|
|
}
|
|
break;
|
|
|
|
case IRP_MJ_CLOSE:
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MJ_READ:
|
|
DPRINT("Handling Read request\n");
|
|
DPRINT("Queueing packet\n");
|
|
IoMarkIrpPending(Irp);
|
|
IoStartPacket(DeviceObject,Irp,NULL,NULL);
|
|
return(STATUS_PENDING);
|
|
|
|
default:
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
DPRINT("Status %d\n",Status);
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
|
|
PUNICODE_STRING RegistryPath)
|
|
/*
|
|
* FUNCTION: Module entry point
|
|
*/
|
|
{
|
|
PDEVICE_OBJECT DeviceObject;
|
|
UNICODE_STRING DeviceName = ROS_STRING_INITIALIZER(L"\\Device\\Keyboard");
|
|
UNICODE_STRING SymlinkName = ROS_STRING_INITIALIZER(L"\\??\\Keyboard");
|
|
|
|
DPRINT("Keyboard Driver 0.0.4\n");
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_READ] = KbdDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
|
|
KbdInternalDeviceControl;
|
|
|
|
DriverObject->DriverStartIo = KbdStartIo;
|
|
|
|
IoCreateDevice(DriverObject,
|
|
sizeof(DEVICE_EXTENSION),
|
|
&DeviceName,
|
|
FILE_DEVICE_KEYBOARD,
|
|
0,
|
|
TRUE,
|
|
&DeviceObject);
|
|
|
|
RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION));
|
|
|
|
DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
|
|
InitializeKeyboard( DeviceObject );
|
|
|
|
IoCreateSymbolicLink(&SymlinkName, &DeviceName);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|