mirror of
https://github.com/reactos/reactos.git
synced 2024-08-19 01:48:11 +00:00
321 lines
9.8 KiB
C
321 lines
9.8 KiB
C
![]() |
/*
|
|||
|
* PROJECT: ReactOS VT100 emulator
|
|||
|
* LICENSE: GPL - See COPYING in the top level directory
|
|||
|
* FILE: drivers/dd/green/keyboard.c
|
|||
|
* PURPOSE: Keyboard part of green management
|
|||
|
* PROGRAMMERS: Copyright 2005-2006 Herv<EFBFBD> Poussineau (hpoussin@reactos.org)
|
|||
|
*/
|
|||
|
|
|||
|
#include "green.h"
|
|||
|
|
|||
|
#define NDEBUG
|
|||
|
#include <debug.h>
|
|||
|
|
|||
|
static BOOLEAN
|
|||
|
TranslateCharToScanCodes(
|
|||
|
IN PUCHAR InputBuffer,
|
|||
|
IN ULONG InputBufferSize,
|
|||
|
OUT KEYBOARD_INPUT_DATA* OutputBuffer,
|
|||
|
OUT PULONG OutputBufferSize,
|
|||
|
OUT PULONG BytesConsumed)
|
|||
|
{
|
|||
|
BOOLEAN NormalKey = FALSE;
|
|||
|
USHORT MakeCode;
|
|||
|
|
|||
|
if (InputBufferSize == 0)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
switch (*InputBuffer)
|
|||
|
{
|
|||
|
case 0x1b: MakeCode = 0x01; NormalKey = TRUE; break; /* ESC */
|
|||
|
|
|||
|
case '1': MakeCode = 0x02; NormalKey = TRUE; break;
|
|||
|
case '2': MakeCode = 0x03; NormalKey = TRUE; break;
|
|||
|
case '3': MakeCode = 0x04; NormalKey = TRUE; break;
|
|||
|
case '4': MakeCode = 0x05; NormalKey = TRUE; break;
|
|||
|
case '5': MakeCode = 0x06; NormalKey = TRUE; break;
|
|||
|
case '6': MakeCode = 0x07; NormalKey = TRUE; break;
|
|||
|
case '7': MakeCode = 0x08; NormalKey = TRUE; break;
|
|||
|
case '8': MakeCode = 0x09; NormalKey = TRUE; break;
|
|||
|
case '9': MakeCode = 0x0a; NormalKey = TRUE; break;
|
|||
|
case '0': MakeCode = 0x0b; NormalKey = TRUE; break;
|
|||
|
case '-': MakeCode = 0x0c; NormalKey = TRUE; break;
|
|||
|
case '=': MakeCode = 0x0d; NormalKey = TRUE; break;
|
|||
|
case '\b': MakeCode = 0x0e; NormalKey = TRUE; break;
|
|||
|
|
|||
|
case '\t': MakeCode = 0x0f; NormalKey = TRUE; break;
|
|||
|
case 'q': MakeCode = 0x10; NormalKey = TRUE; break;
|
|||
|
case 'w': MakeCode = 0x11; NormalKey = TRUE; break;
|
|||
|
case 'e': MakeCode = 0x12; NormalKey = TRUE; break;
|
|||
|
case 'r': MakeCode = 0x13; NormalKey = TRUE; break;
|
|||
|
case 't': MakeCode = 0x14; NormalKey = TRUE; break;
|
|||
|
case 'y': MakeCode = 0x15; NormalKey = TRUE; break;
|
|||
|
case 'u': MakeCode = 0x16; NormalKey = TRUE; break;
|
|||
|
case 'i': MakeCode = 0x17; NormalKey = TRUE; break;
|
|||
|
case 'o': MakeCode = 0x18; NormalKey = TRUE; break;
|
|||
|
case 'p': MakeCode = 0x19; NormalKey = TRUE; break;
|
|||
|
case '[': MakeCode = 0x1a; NormalKey = TRUE; break;
|
|||
|
case ']': MakeCode = 0x1b; NormalKey = TRUE; break;
|
|||
|
|
|||
|
case '\r': MakeCode = 0x1c; NormalKey = TRUE; break;
|
|||
|
|
|||
|
case 'a': MakeCode = 0x1e; NormalKey = TRUE; break;
|
|||
|
case 's': MakeCode = 0x1f; NormalKey = TRUE; break;
|
|||
|
case 'd': MakeCode = 0x20; NormalKey = TRUE; break;
|
|||
|
case 'f': MakeCode = 0x21; NormalKey = TRUE; break;
|
|||
|
case 'g': MakeCode = 0x22; NormalKey = TRUE; break;
|
|||
|
case 'h': MakeCode = 0x23; NormalKey = TRUE; break;
|
|||
|
case 'j': MakeCode = 0x24; NormalKey = TRUE; break;
|
|||
|
case 'k': MakeCode = 0x25; NormalKey = TRUE; break;
|
|||
|
case 'l': MakeCode = 0x26; NormalKey = TRUE; break;
|
|||
|
case ';': MakeCode = 0x27; NormalKey = TRUE; break;
|
|||
|
case '\'': MakeCode = 0x28; NormalKey = TRUE; break;
|
|||
|
|
|||
|
case '`': MakeCode = 0x29; NormalKey = TRUE; break;
|
|||
|
|
|||
|
case '\\': MakeCode = 0x2b; NormalKey = TRUE; break;
|
|||
|
|
|||
|
case 'z': MakeCode = 0x2c; NormalKey = TRUE; break;
|
|||
|
case 'x': MakeCode = 0x2d; NormalKey = TRUE; break;
|
|||
|
case 'c': MakeCode = 0x2e; NormalKey = TRUE; break;
|
|||
|
case 'v': MakeCode = 0x2f; NormalKey = TRUE; break;
|
|||
|
case 'b': MakeCode = 0x30; NormalKey = TRUE; break;
|
|||
|
case 'n': MakeCode = 0x31; NormalKey = TRUE; break;
|
|||
|
case 'm': MakeCode = 0x32; NormalKey = TRUE; break;
|
|||
|
case ',': MakeCode = 0x33; NormalKey = TRUE; break;
|
|||
|
case '.': MakeCode = 0x34; NormalKey = TRUE; break;
|
|||
|
case '/': MakeCode = 0x35; NormalKey = TRUE; break;
|
|||
|
|
|||
|
case ' ': MakeCode = 0x39; NormalKey = TRUE; break;
|
|||
|
}
|
|||
|
if (NormalKey && *OutputBufferSize >= 2)
|
|||
|
{
|
|||
|
OutputBuffer[0].MakeCode = MakeCode;
|
|||
|
OutputBuffer[0].Flags = KEY_MAKE;
|
|||
|
OutputBuffer[1].MakeCode = MakeCode;
|
|||
|
OutputBuffer[1].Flags = KEY_BREAK;
|
|||
|
*BytesConsumed = 2;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
/* Consume strange character by ignoring it */
|
|||
|
DPRINT1("Strange byte received 0x%02x ('%c')\n",
|
|||
|
*InputBuffer, *InputBuffer >= 32 ? *InputBuffer : '.');
|
|||
|
*BytesConsumed = 1;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
KeyboardAddDevice(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT Pdo)
|
|||
|
{
|
|||
|
PDEVICE_OBJECT Fdo;
|
|||
|
PKEYBOARD_DEVICE_EXTENSION DeviceExtension;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
DPRINT("KeyboardInitialize() called\n");
|
|||
|
|
|||
|
Status = IoCreateDevice(DriverObject,
|
|||
|
sizeof(KEYBOARD_DEVICE_EXTENSION),
|
|||
|
NULL,
|
|||
|
FILE_DEVICE_KEYBOARD,
|
|||
|
FILE_DEVICE_SECURE_OPEN,
|
|||
|
TRUE,
|
|||
|
&Fdo);
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
return Status;
|
|||
|
|
|||
|
DeviceExtension = (PKEYBOARD_DEVICE_EXTENSION)Fdo->DeviceExtension;
|
|||
|
RtlZeroMemory(DeviceExtension, sizeof(KEYBOARD_DEVICE_EXTENSION));
|
|||
|
DeviceExtension->Common.Type = KeyboardFDO;
|
|||
|
DeviceExtension->Common.LowerDevice = IoAttachDeviceToDeviceStack(Fdo, Pdo);
|
|||
|
DeviceExtension->Green = ((PGREEN_DRIVER_EXTENSION)IoGetDriverObjectExtension(DriverObject, DriverObject))->GreenMainDO;
|
|||
|
((PGREEN_DEVICE_EXTENSION)DeviceExtension->Green->DeviceExtension)->KeyboardFdo = Fdo;
|
|||
|
Fdo->Flags |= DO_POWER_PAGABLE | DO_BUFFERED_IO;
|
|||
|
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
static VOID NTAPI
|
|||
|
KeyboardDpcSendData(
|
|||
|
IN PKDPC Dpc,
|
|||
|
IN PVOID pDeviceExtension, /* real type PKEYBOARD_DEVICE_EXTENSION */
|
|||
|
IN PVOID Unused1,
|
|||
|
IN PVOID Unused2)
|
|||
|
{
|
|||
|
PKEYBOARD_DEVICE_EXTENSION DeviceExtension;
|
|||
|
ULONG Queue;
|
|||
|
ULONG InputDataConsumed;
|
|||
|
|
|||
|
DeviceExtension = (PKEYBOARD_DEVICE_EXTENSION)pDeviceExtension;
|
|||
|
|
|||
|
Queue = DeviceExtension->ActiveQueue % 2;
|
|||
|
InterlockedIncrement((PLONG)&DeviceExtension->ActiveQueue);
|
|||
|
(*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassInformation.ClassService)(
|
|||
|
DeviceExtension->ClassInformation.ClassDeviceObject,
|
|||
|
DeviceExtension->KeyboardInputData[Queue],
|
|||
|
DeviceExtension->KeyboardInputData[Queue] + DeviceExtension->InputDataCount[Queue],
|
|||
|
&InputDataConsumed);
|
|||
|
|
|||
|
DeviceExtension->InputDataCount[Queue] = 0;
|
|||
|
}
|
|||
|
|
|||
|
static VOID NTAPI
|
|||
|
KeyboardDeviceWorker(
|
|||
|
PVOID Context)
|
|||
|
{
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
PKEYBOARD_DEVICE_EXTENSION DeviceExtension;
|
|||
|
PGREEN_DEVICE_EXTENSION GreenDeviceExtension;
|
|||
|
PDEVICE_OBJECT LowerDevice;
|
|||
|
UCHAR Buffer[16]; /* Arbitrary size */
|
|||
|
ULONG BufferSize;
|
|||
|
LARGE_INTEGER Zero;
|
|||
|
PIRP Irp;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
KEVENT event;
|
|||
|
KIRQL OldIrql;
|
|||
|
ULONG i, Queue;
|
|||
|
ULONG SpaceInQueue;
|
|||
|
ULONG BytesConsumed = 0;
|
|||
|
PKEYBOARD_INPUT_DATA Input;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
DPRINT("KeyboardDeviceWorker() called\n");
|
|||
|
|
|||
|
DeviceObject = (PDEVICE_OBJECT)Context;
|
|||
|
DeviceExtension = (PKEYBOARD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|||
|
GreenDeviceExtension = (PGREEN_DEVICE_EXTENSION)DeviceExtension->Green->DeviceExtension;
|
|||
|
LowerDevice = GreenDeviceExtension->Serial;
|
|||
|
BufferSize = sizeof(Buffer);
|
|||
|
Zero.QuadPart = 0;
|
|||
|
|
|||
|
/* Initialize device extension */
|
|||
|
DeviceExtension->ActiveQueue = 0;
|
|||
|
DeviceExtension->InputDataCount[0] = 0;
|
|||
|
DeviceExtension->InputDataCount[1] = 0;
|
|||
|
KeInitializeDpc(&DeviceExtension->KeyboardDpc, KeyboardDpcSendData, DeviceExtension);
|
|||
|
RtlZeroMemory(&DeviceExtension->KeyboardInputData, sizeof(DeviceExtension->KeyboardInputData));
|
|||
|
|
|||
|
/* main read loop */
|
|||
|
while (TRUE)
|
|||
|
{
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
Irp = IoBuildSynchronousFsdRequest(
|
|||
|
IRP_MJ_READ,
|
|||
|
LowerDevice,
|
|||
|
Buffer, BufferSize,
|
|||
|
&Zero,
|
|||
|
&event,
|
|||
|
&ioStatus);
|
|||
|
if (!Irp)
|
|||
|
{
|
|||
|
/* no memory actually, try later */
|
|||
|
KeStallExecutionProcessor(10);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
Status = IoCallDriver(LowerDevice, Irp);
|
|||
|
if (Status == STATUS_PENDING)
|
|||
|
{
|
|||
|
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
|
|||
|
Status = ioStatus.Status;
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
continue;
|
|||
|
|
|||
|
/* Read all available data and process */
|
|||
|
i = 0;
|
|||
|
while (i < ioStatus.Information)
|
|||
|
{
|
|||
|
Queue = DeviceExtension->ActiveQueue % 2;
|
|||
|
|
|||
|
Input = &DeviceExtension->KeyboardInputData[Queue][DeviceExtension->InputDataCount[Queue]];
|
|||
|
|
|||
|
/* Translate current chars to scan codes */
|
|||
|
SpaceInQueue = KEYBOARD_BUFFER_SIZE - DeviceExtension->InputDataCount[Queue];
|
|||
|
if (TranslateCharToScanCodes(
|
|||
|
&Buffer[i], /* input buffer */
|
|||
|
ioStatus.Information - i, /* input buffer size */
|
|||
|
Input, /* output buffer */
|
|||
|
&SpaceInQueue, /* output buffer size */
|
|||
|
&BytesConsumed)) /* bytes consumed in input buffer */
|
|||
|
{
|
|||
|
DPRINT("Got char 0x%02x (%c)\n", Buffer[i], Buffer[i] >= 32 ? Buffer[i] : ' ');
|
|||
|
DeviceExtension->InputDataCount[Queue] += BytesConsumed;
|
|||
|
|
|||
|
/* Send the data to the keyboard class driver */
|
|||
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
|||
|
KeInsertQueueDpc(&DeviceExtension->KeyboardDpc, NULL, NULL);
|
|||
|
KeLowerIrql(OldIrql);
|
|||
|
i += BytesConsumed;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* TranslateCharToScanCodes failed. Possible reasons:
|
|||
|
* - not enough bytes in input buffer (escape control code; wait next received bytes)
|
|||
|
* - not enough room in output buffer (wait for the Dpc to empty it)
|
|||
|
*
|
|||
|
* The best way to resolve this is to try later.
|
|||
|
*/
|
|||
|
i++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PsTerminateSystemThread(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
KeyboardInternalDeviceControl(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp)
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION Stack;
|
|||
|
PKEYBOARD_DEVICE_EXTENSION DeviceExtension;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
DeviceExtension = (PKEYBOARD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
|
|||
|
{
|
|||
|
case IOCTL_INTERNAL_KEYBOARD_CONNECT:
|
|||
|
{
|
|||
|
DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
|
|||
|
if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
|
|||
|
{
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
DeviceExtension->ClassInformation =
|
|||
|
*((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
|
|||
|
|
|||
|
/* Start read loop */
|
|||
|
Status = PsCreateSystemThread(
|
|||
|
&DeviceExtension->WorkerThreadHandle,
|
|||
|
(ACCESS_MASK)0L,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
KeyboardDeviceWorker,
|
|||
|
DeviceObject);
|
|||
|
break;
|
|||
|
}
|
|||
|
default:
|
|||
|
{
|
|||
|
DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
|
|||
|
Stack->Parameters.DeviceIoControl.IoControlCode);
|
|||
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Status = Status;
|
|||
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|||
|
return Status;
|
|||
|
}
|