⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 keyboard.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * COPYRIGHT:        See COPYING in the top level directory
 * PROJECT:          ReactOS kernel
 * FILE:             drivers/input/i8042prt/keyboard.c
 * PURPOSE:          i8042 (ps/2 keyboard-mouse controller) driver
 *                   keyboard specifics
 * PROGRAMMER:       Victor Kirhenshtein (sauros@iname.com)
 *                   Jason Filby (jasonfilby@yahoo.com)
 *                   Tinus
 */

/* INCLUDES ****************************************************************/

#include "i8042prt.h"

#ifdef __REACTOS__
#include "kdfuncs.h"
#endif

#ifndef NDEBUG
#define NDEBUG
#endif
#include <debug.h>

/* GLOBALS *******************************************************************/

static UCHAR TypematicTable[] = {
	0x00, 0x00, 0x00, 0x05, 0x08, 0x0B, 0x0D, 0x0F, 0x10, 0x12, /*  0-9 */
	0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1A, /* 10-19 */
	0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E };

typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION {
	USHORT NumberOfIndicatorKeys;
	INDICATOR_LIST IndicatorList[3];
} LOCAL_KEYBOARD_INDICATOR_TRANSLATION, *PLOCAL_KEYBOARD_INDICATOR_TRANSLATION;

static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation = { 3, {
	{0x3A, KEYBOARD_CAPS_LOCK_ON},
	{0x45, KEYBOARD_NUM_LOCK_ON},
	{0x46, KEYBOARD_SCROLL_LOCK_ON}}};

static IO_WORKITEM_ROUTINE  I8042DebugWorkItem;
static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
                                       PVOID Context);

/* FUNCTIONS *****************************************************************/

/*
 * These functions are callbacks for filter driver custom interrupt
 * service routines.
 */
VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
                                         UCHAR Value)
{
	I8042IsrWritePort(Context, Value, 0);
}

static VOID STDCALL I8042QueueKeyboardPacket(PVOID Context)
{
	PDEVICE_OBJECT DeviceObject = Context;
	PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
	PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;

	DevExt->KeyComplete = TRUE;
	DevExt->KeysInBuffer++;
	if (DevExt->KeysInBuffer >
	                 DevExt->KeyboardAttributes.InputDataQueueLength) {
		DPRINT1("Keyboard buffer overflow\n");
		DevExt->KeysInBuffer--;
	}

	DPRINT("Irq completes key\n");
	KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
}

/*
 * These functions are callbacks for filter driver custom
 * initialization routines.
 */
NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
                                        UCHAR Value,
                                        BOOLEAN WaitForAck)
{
	return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
	                           0,
	                           Value,
	                           WaitForAck);
}

BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
                                             VOID * Context)
{
	UCHAR Output;
	UCHAR PortStatus;
	NTSTATUS Status;
	PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
	BOOLEAN HookContinue = FALSE, HookReturn;
	ULONG Iterations = 0;

	KEYBOARD_INPUT_DATA *InputData =
	                         DevExt->KeyboardBuffer + DevExt->KeysInBuffer;

	do {
		Status = I8042ReadStatus(&PortStatus);
		DPRINT("PortStatus: %x\n", PortStatus);
		Status = I8042ReadData(&Output);
		Iterations++;
		if (STATUS_SUCCESS == Status)
			break;
		KeStallExecutionProcessor(1);
	} while (Iterations < DevExt->Settings.PollStatusIterations);

	if (STATUS_SUCCESS != Status) {
		DPRINT("Spurious I8042 interrupt\n");
		return FALSE;
	}

	DPRINT("Got: %x\n", Output);

	if (DevExt->KeyboardHook.IsrRoutine) {
		HookReturn = DevExt->KeyboardHook.IsrRoutine(
                                             DevExt->KeyboardHook.Context,
		                             InputData,
		                             &DevExt->Packet,
		                             PortStatus,
		                             &Output,
		                             &HookContinue,
		                             &DevExt->KeyboardScanState);

		if (!HookContinue)
			return HookReturn;
	}

	if (I8042PacketIsr(DevExt, Output)) {
		if (DevExt->PacketComplete) {
			DPRINT("Packet complete\n");
			KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
		}
		DPRINT("Irq eaten by packet\n");
		return TRUE;
	}

	DPRINT("Irq is keyboard input\n");

	if (Normal == DevExt->KeyboardScanState) {
		switch (Output) {
		case 0xe0:
			DevExt->KeyboardScanState = GotE0;
			return TRUE;
		case 0xe1:
			DevExt->KeyboardScanState = GotE1;
			return TRUE;
		default:
			;/* continue */
		}
	}

	InputData->Flags = 0;

	switch (DevExt->KeyboardScanState) {
	case GotE0:
		InputData->Flags |= KEY_E0;
		break;
	case GotE1:
		InputData->Flags |= KEY_E1;
		break;
	default:
		;
	}
	DevExt->KeyboardScanState = Normal;

	if (Output & 0x80)
		InputData->Flags |= KEY_BREAK;
	else
		InputData->Flags |= KEY_MAKE;

	InputData->MakeCode = Output & 0x7f;

	I8042QueueKeyboardPacket(DevExt->KeyboardObject);

	return TRUE;
}

VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
                                PVOID DeferredContext,
                                PVOID SystemArgument1,
                                PVOID SystemArgument2)
{
	PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
	ULONG KeysTransferred = 0;
	ULONG KeysInBufferCopy;
	KIRQL Irql;

	I8042PacketDpc(DevExt);

	if (!DevExt->KeyComplete)
		return;

	/* We got the interrupt as it was being enabled, too bad */
	if (!DevExt->HighestDIRQLInterrupt)
		return;

	Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);

	DevExt->KeyComplete = FALSE;
	KeysInBufferCopy = DevExt->KeysInBuffer;

	KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);

	/* Test for TAB (debugging) */
	if (DevExt->Settings.CrashSysRq) {
		PKEYBOARD_INPUT_DATA InputData = DevExt->KeyboardBuffer +
		                                          KeysInBufferCopy - 1;
		if (InputData->MakeCode == 0x0F) {
			DPRINT("Tab!\n");
			DevExt->TabPressed = !(InputData->Flags & KEY_BREAK);
		} else if (DevExt->TabPressed) {
			DPRINT ("Queueing work item %x\n", DevExt->DebugWorkItem);
			DevExt->DebugKey = InputData->MakeCode;
			DevExt->TabPressed = FALSE;

			IoQueueWorkItem(DevExt->DebugWorkItem,
			                &(I8042DebugWorkItem),
					DelayedWorkQueue,
					DevExt);
		}
	}

	DPRINT ("Send a key\n");

	if (!DevExt->KeyboardData.ClassService)
		return;

	((PSERVICE_CALLBACK_ROUTINE) DevExt->KeyboardData.ClassService)(
		                 DevExt->KeyboardData.ClassDeviceObject,
		                 DevExt->KeyboardBuffer,
		                 DevExt->KeyboardBuffer + KeysInBufferCopy,
		                 &KeysTransferred);

	Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
	DevExt->KeysInBuffer -= KeysTransferred;
	KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
}

/* You have to send the rate/delay in a somewhat awkward format */
static UCHAR I8042GetTypematicByte(USHORT Rate, USHORT Delay)
{
	UCHAR ret;

	if (Rate < 3) {
		ret = 0x0;
	} else if (Rate > 26) {
		ret = 0x1F;
	} else {
		ret = TypematicTable[Rate];
	}

	if (Delay < 375) {
		;
	} else if (Delay < 625) {
		ret |= 0x20;
	} else if (Delay < 875) {
		ret |= 0x40;
	} else {
		ret |= 0x60;
	}
	return ret;
}
/*
 * Process the keyboard internal device requests
 * returns FALSE if it doesn't understand the
 * call so someone else can handle it.
 */
BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	PIO_STACK_LOCATION Stk;
	PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
	PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;

	Stk = IoGetCurrentIrpStackLocation(Irp);

	switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
	case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
		I8042StartPacket(
		             DevExt,
			     DeviceObject,
		             Stk->Parameters.DeviceIoControl.Type3InputBuffer,
		             Stk->Parameters.DeviceIoControl.InputBufferLength,
			     Irp);
		break;

	case IOCTL_KEYBOARD_SET_INDICATORS:
		DevExt->PacketBuffer[0] = 0xED;
		DevExt->PacketBuffer[1] = 0;
		if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON)
			DevExt->PacketBuffer[1] |= 0x04;

		if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON)
			DevExt->PacketBuffer[1] |= 0x02;

		if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON)
			DevExt->PacketBuffer[1] |= 0x01;

		I8042StartPacket(DevExt,
		                 DeviceObject,
		                 DevExt->PacketBuffer,
		                 2,
		                 Irp);
		break;
	case IOCTL_KEYBOARD_SET_TYPEMATIC:
		DevExt->PacketBuffer[0] = 0xF3;
		DevExt->PacketBuffer[1] = I8042GetTypematicByte(
				         DevExt->KeyboardTypematic.Rate,
				         DevExt->KeyboardTypematic.Delay);

		I8042StartPacket(DevExt,
		                 DeviceObject,
		                 DevExt->PacketBuffer,
		                 2,
		                 Irp);
		break;
	default:
		return FALSE;
	}

	return TRUE;
}

/*
 * Runs the keyboard IOCTL_INTERNAL dispatch.
 * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
 * so someone else can have a try at it.
 */
NTSTATUS STDCALL I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	PIO_STACK_LOCATION Stk;
	PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
	PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;

	DPRINT("InternalDeviceControl\n");

	Irp->IoStatus.Information = 0;
	Stk = IoGetCurrentIrpStackLocation(Irp);

	switch (Stk->Parameters.DeviceIoControl.IoControlCode) {

	case IOCTL_INTERNAL_KEYBOARD_CONNECT:
		DPRINT("IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
		if (Stk->Parameters.DeviceIoControl.InputBufferLength <
		                                      sizeof(CONNECT_DATA)) {
			DPRINT1("Keyboard IOCTL_INTERNAL_KEYBOARD_CONNECT "
			       "invalid buffer size\n");
			Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
			goto intcontfailure;
		}

		if (!DevExt->KeyboardExists) {
			Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
			goto intcontfailure;
		}

		if (DevExt->KeyboardClaimed) {
			DPRINT1("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
			       "Keyboard is already claimed\n");
			Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
			goto intcontfailure;
		}

		memcpy(&DevExt->KeyboardData,
		       Stk->Parameters.DeviceIoControl.Type3InputBuffer,
		       sizeof(CONNECT_DATA));
		DevExt->KeyboardHook.IsrWritePort = I8042IsrWritePortKbd;
		DevExt->KeyboardHook.QueueKeyboardPacket =
		                                    I8042QueueKeyboardPacket;
		DevExt->KeyboardHook.CallContext = DevExt;

		{
			PIO_WORKITEM WorkItem;
			PI8042_HOOK_WORKITEM WorkItemData;

			WorkItem = IoAllocateWorkItem(DeviceObject);
			if (!WorkItem) {
				DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
				        "Can't allocate work item\n");
				Irp->IoStatus.Status =
				              STATUS_INSUFFICIENT_RESOURCES;
				goto intcontfailure;
			}

			WorkItemData = ExAllocatePoolWithTag(

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -