keyboard.c
来自「一个类似windows」· C语言 代码 · 共 777 行 · 第 1/2 页
C
777 行
Irp->IoStatus.Status =
STATUS_INSUFFICIENT_RESOURCES;
IoFreeWorkItem(WorkItem);
goto intcontfailure;
}
WorkItemData->WorkItem = WorkItem;
WorkItemData->Target =
DevExt->KeyboardData.ClassDeviceObject;
WorkItemData->Irp = Irp;
IoMarkIrpPending(Irp);
IoQueueWorkItem(WorkItem,
I8042SendHookWorkItem,
DelayedWorkQueue,
WorkItemData);
Irp->IoStatus.Status = STATUS_PENDING;
}
break;
case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
DPRINT("IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER\n");
if (Stk->Parameters.DeviceIoControl.InputBufferLength < 1) {
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
goto intcontfailure;
}
if (!DevExt->KeyboardInterruptObject) {
Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
goto intcontfailure;
}
IoMarkIrpPending(Irp);
IoStartPacket(DeviceObject, Irp, NULL, NULL);
Irp->IoStatus.Status = STATUS_PENDING;
break;
case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
DPRINT("IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(KEYBOARD_ATTRIBUTES)) {
DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_ATTRIBUTES "
"invalid buffer size\n");
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
goto intcontfailure;
}
memcpy(Irp->AssociatedIrp.SystemBuffer,
&DevExt->KeyboardAttributes,
sizeof(KEYBOARD_ATTRIBUTES));
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IOCTL_KEYBOARD_QUERY_INDICATORS:
DPRINT("IOCTL_KEYBOARD_QUERY_INDICATORS\n");
if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_INDICATORS "
"invalid buffer size\n");
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
goto intcontfailure;
}
memcpy(Irp->AssociatedIrp.SystemBuffer,
&DevExt->KeyboardIndicators,
sizeof(KEYBOARD_INDICATOR_PARAMETERS));
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
DPRINT("IOCTL_KEYBOARD_QUERY_TYPEMATIC\n");
if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_TYPEMATIC "
"invalid buffer size\n");
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
goto intcontfailure;
}
memcpy(Irp->AssociatedIrp.SystemBuffer,
&DevExt->KeyboardTypematic,
sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IOCTL_KEYBOARD_SET_INDICATORS:
DPRINT("IOCTL_KEYBOARD_SET_INDICATORS\n");
if (Stk->Parameters.DeviceIoControl.InputBufferLength <
sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
DPRINT("Keyboard IOCTL_KEYBOARD_SET_INDICTATORS "
"invalid buffer size\n");
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
goto intcontfailure;
}
memcpy(&DevExt->KeyboardIndicators,
Irp->AssociatedIrp.SystemBuffer,
sizeof(KEYBOARD_INDICATOR_PARAMETERS));
DPRINT("%x\n", DevExt->KeyboardIndicators.LedFlags);
IoMarkIrpPending(Irp);
IoStartPacket(DeviceObject, Irp, NULL, NULL);
Irp->IoStatus.Status = STATUS_PENDING;
break;
case IOCTL_KEYBOARD_SET_TYPEMATIC:
DPRINT("IOCTL_KEYBOARD_SET_TYPEMATIC\n");
if (Stk->Parameters.DeviceIoControl.InputBufferLength <
sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
DPRINT("Keyboard IOCTL_KEYBOARD_SET_TYPEMATIC "
"invalid buffer size\n");
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
goto intcontfailure;
}
memcpy(&DevExt->KeyboardTypematic,
Irp->AssociatedIrp.SystemBuffer,
sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
IoMarkIrpPending(Irp);
IoStartPacket(DeviceObject, Irp, NULL, NULL);
Irp->IoStatus.Status = STATUS_PENDING;
break;
case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
/* We should check the UnitID, but it's kind of pointless as
* all keyboards are supposed to have the same one
*/
if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION)) {
DPRINT("IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: "
"invalid buffer size (expected)\n");
/* It's to query the buffer size */
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
goto intcontfailure;
}
Irp->IoStatus.Information =
sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
memcpy(Irp->AssociatedIrp.SystemBuffer,
&IndicatorTranslation,
sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION));
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
/* Nothing to do here */
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
intcontfailure:
return Irp->IoStatus.Status;
}
/* This is all pretty confusing. There's more than one way to
* disable/enable the keyboard. You can send KBD_ENABLE to the
* keyboard, and it will start scanning keys. Sending KBD_DISABLE
* will disable the key scanning but also reset the parameters to
* defaults.
*
* You can also send 0xAE to the controller for enabling the
* keyboard clock line and 0xAD for disabling it. Then it'll
* automatically get turned on at the next command. The last
* way is by modifying the bit that drives the clock line in the
* 'command byte' of the controller. This is almost, but not quite,
* the same as the AE/AD thing. The difference can be used to detect
* some really old broken keyboard controllers which I hope won't be
* necessary.
*
* We change the command byte, sending KBD_ENABLE/DISABLE seems to confuse
* some kvm switches.
*/
BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt)
{
UCHAR Value;
NTSTATUS Status;
DPRINT("Enable keyboard\n");
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
DPRINT1("Can't read i8042 mode\n");
return FALSE;
}
Status = I8042ReadDataWait(DevExt, &Value);
if (!NT_SUCCESS(Status)) {
DPRINT1("No response after read i8042 mode\n");
return FALSE;
}
Value &= ~CCB_KBD_DISAB; // don't disable keyboard
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
DPRINT1("Can't set i8042 mode\n");
return FALSE;
}
if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
DPRINT1("Can't send i8042 mode\n");
return FALSE;
}
return TRUE;
}
static BOOLEAN STDCALL I8042KeyboardDefaultsAndDisable(PDEVICE_EXTENSION DevExt)
{
UCHAR Value;
NTSTATUS Status;
DPRINT("Disabling keyboard\n");
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
DPRINT1("Can't read i8042 mode\n");
return FALSE;
}
Status = I8042ReadDataWait(DevExt, &Value);
if (!NT_SUCCESS(Status)) {
DPRINT1("No response after read i8042 mode\n");
return FALSE;
}
Value |= CCB_KBD_DISAB; // disable keyboard
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
DPRINT1("Can't set i8042 mode\n");
return FALSE;
}
if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
DPRINT1("Can't send i8042 mode\n");
return FALSE;
}
return TRUE;
}
BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt)
{
UCHAR Value;
NTSTATUS Status;
DPRINT("Enabling keyboard interrupt\n");
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
DPRINT1("Can't read i8042 mode\n");
return FALSE;
}
Status = I8042ReadDataWait(DevExt, &Value);
if (!NT_SUCCESS(Status)) {
DPRINT1("No response after read i8042 mode\n");
return FALSE;
}
Value &= ~CCB_KBD_DISAB; // don't disable keyboard
Value |= CCB_KBD_INT_ENAB; // enable keyboard interrupts
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
DPRINT1("Can't set i8042 mode\n");
return FALSE;
}
if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
DPRINT1("Can't send i8042 mode\n");
return FALSE;
}
return TRUE;
}
BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt)
{
NTSTATUS Status;
UCHAR Value;
UCHAR Value2;
ULONG RetryCount = 10;
DPRINT("Detecting keyboard\n");
I8042KeyboardDefaultsAndDisable(DevExt);
do {
I8042Flush();
Status = I8042SynchWritePort(DevExt, 0, KBD_GET_ID, TRUE);
} while (STATUS_IO_TIMEOUT == Status && RetryCount--);
if (!NT_SUCCESS(Status)) {
DPRINT1("Can't write GET_ID (%x)\n", Status);
/* Could be an AT keyboard */
DevExt->KeyboardIsAT = TRUE;
goto detectsetleds;
}
Status = I8042ReadDataWait(DevExt, &Value);
if (!NT_SUCCESS(Status)) {
DPRINT1("No response after GET_ID\n");
/* Could be an AT keyboard */
DevExt->KeyboardIsAT = TRUE;
goto detectsetleds;
}
DevExt->KeyboardIsAT = FALSE;
if (Value != 0xAB && Value != 0xAC) {
DPRINT("Bad ID: %x\n", Value);
/* This is certainly not a keyboard */
return FALSE;
}
Status = I8042ReadDataWait(DevExt, &Value2);
if (!NT_SUCCESS(Status)) {
DPRINT("Partial ID\n");
return FALSE;
}
DPRINT("Keyboard ID: 0x%x 0x%x\n", Value, Value2);
detectsetleds:
I8042Flush(); /* Flush any bytes left over from GET_ID */
Status = I8042SynchWritePort(DevExt, 0, KBD_SET_LEDS, TRUE);
if (!NT_SUCCESS(Status)) {
DPRINT("Can't write SET_LEDS (%x)\n", Status);
return FALSE;
}
Status = I8042SynchWritePort(DevExt, 0, 0, TRUE);
if (!NT_SUCCESS(Status)) {
DPRINT("Can't finish SET_LEDS (%x)\n", Status);
return FALSE;
}
// Turn on translation
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
DPRINT1("Can't read i8042 mode\n");
return FALSE;
}
Status = I8042ReadDataWait(DevExt, &Value);
if (!NT_SUCCESS(Status)) {
DPRINT1("No response after read i8042 mode\n");
return FALSE;
}
Value |= 0x40; // enable keyboard translation
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
DPRINT1("Can't set i8042 mode\n");
return FALSE;
}
if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
DPRINT1("Can't send i8042 mode\n");
return FALSE;
}
return TRUE;
}
/* debug stuff */
VOID STDCALL
KdpServiceDispatcher(ULONG Code, PVOID Context1, PVOID Context2);
#define EnterDebugger ((PVOID)0x25)
static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
PVOID Context)
{
ULONG Key;
PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
Key = InterlockedExchange((PLONG)&DevExt->DebugKey, 0);
DPRINT("Debug key: %x\n", Key);
if (!Key)
return;
#ifdef __REACTOS__
/* We hope kernel would understand this. If
* that's not the case, nothing would happen.
*/
KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)Key, NULL);
#endif /* __REACTOS__ */
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?