Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / modules / rosapps / drivers / green / keyboard.c
diff --git a/modules/rosapps/drivers/green/keyboard.c b/modules/rosapps/drivers/green/keyboard.c
new file mode 100644 (file)
index 0000000..511b856
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * 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Ă© 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;
+}