Merge trunk HEAD (r44067)
[reactos.git] / rosapps / drivers / green / keyboard.c
1 /*
2 * PROJECT: ReactOS VT100 emulator
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/dd/green/keyboard.c
5 * PURPOSE: Keyboard part of green management
6 * PROGRAMMERS: Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
7 */
8
9 #include "green.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 static BOOLEAN
15 TranslateCharToScanCodes(
16 IN PUCHAR InputBuffer,
17 IN ULONG InputBufferSize,
18 OUT KEYBOARD_INPUT_DATA* OutputBuffer,
19 OUT PULONG OutputBufferSize,
20 OUT PULONG BytesConsumed)
21 {
22 BOOLEAN NormalKey = FALSE;
23 USHORT MakeCode;
24
25 if (InputBufferSize == 0)
26 return FALSE;
27
28 switch (*InputBuffer)
29 {
30 case 0x1b: MakeCode = 0x01; NormalKey = TRUE; break; /* ESC */
31
32 case '1': MakeCode = 0x02; NormalKey = TRUE; break;
33 case '2': MakeCode = 0x03; NormalKey = TRUE; break;
34 case '3': MakeCode = 0x04; NormalKey = TRUE; break;
35 case '4': MakeCode = 0x05; NormalKey = TRUE; break;
36 case '5': MakeCode = 0x06; NormalKey = TRUE; break;
37 case '6': MakeCode = 0x07; NormalKey = TRUE; break;
38 case '7': MakeCode = 0x08; NormalKey = TRUE; break;
39 case '8': MakeCode = 0x09; NormalKey = TRUE; break;
40 case '9': MakeCode = 0x0a; NormalKey = TRUE; break;
41 case '0': MakeCode = 0x0b; NormalKey = TRUE; break;
42 case '-': MakeCode = 0x0c; NormalKey = TRUE; break;
43 case '=': MakeCode = 0x0d; NormalKey = TRUE; break;
44 case '\b': MakeCode = 0x0e; NormalKey = TRUE; break;
45
46 case '\t': MakeCode = 0x0f; NormalKey = TRUE; break;
47 case 'q': MakeCode = 0x10; NormalKey = TRUE; break;
48 case 'w': MakeCode = 0x11; NormalKey = TRUE; break;
49 case 'e': MakeCode = 0x12; NormalKey = TRUE; break;
50 case 'r': MakeCode = 0x13; NormalKey = TRUE; break;
51 case 't': MakeCode = 0x14; NormalKey = TRUE; break;
52 case 'y': MakeCode = 0x15; NormalKey = TRUE; break;
53 case 'u': MakeCode = 0x16; NormalKey = TRUE; break;
54 case 'i': MakeCode = 0x17; NormalKey = TRUE; break;
55 case 'o': MakeCode = 0x18; NormalKey = TRUE; break;
56 case 'p': MakeCode = 0x19; NormalKey = TRUE; break;
57 case '[': MakeCode = 0x1a; NormalKey = TRUE; break;
58 case ']': MakeCode = 0x1b; NormalKey = TRUE; break;
59
60 case '\r': MakeCode = 0x1c; NormalKey = TRUE; break;
61
62 case 'a': MakeCode = 0x1e; NormalKey = TRUE; break;
63 case 's': MakeCode = 0x1f; NormalKey = TRUE; break;
64 case 'd': MakeCode = 0x20; NormalKey = TRUE; break;
65 case 'f': MakeCode = 0x21; NormalKey = TRUE; break;
66 case 'g': MakeCode = 0x22; NormalKey = TRUE; break;
67 case 'h': MakeCode = 0x23; NormalKey = TRUE; break;
68 case 'j': MakeCode = 0x24; NormalKey = TRUE; break;
69 case 'k': MakeCode = 0x25; NormalKey = TRUE; break;
70 case 'l': MakeCode = 0x26; NormalKey = TRUE; break;
71 case ';': MakeCode = 0x27; NormalKey = TRUE; break;
72 case '\'': MakeCode = 0x28; NormalKey = TRUE; break;
73
74 case '`': MakeCode = 0x29; NormalKey = TRUE; break;
75
76 case '\\': MakeCode = 0x2b; NormalKey = TRUE; break;
77
78 case 'z': MakeCode = 0x2c; NormalKey = TRUE; break;
79 case 'x': MakeCode = 0x2d; NormalKey = TRUE; break;
80 case 'c': MakeCode = 0x2e; NormalKey = TRUE; break;
81 case 'v': MakeCode = 0x2f; NormalKey = TRUE; break;
82 case 'b': MakeCode = 0x30; NormalKey = TRUE; break;
83 case 'n': MakeCode = 0x31; NormalKey = TRUE; break;
84 case 'm': MakeCode = 0x32; NormalKey = TRUE; break;
85 case ',': MakeCode = 0x33; NormalKey = TRUE; break;
86 case '.': MakeCode = 0x34; NormalKey = TRUE; break;
87 case '/': MakeCode = 0x35; NormalKey = TRUE; break;
88
89 case ' ': MakeCode = 0x39; NormalKey = TRUE; break;
90 }
91 if (NormalKey && *OutputBufferSize >= 2)
92 {
93 OutputBuffer[0].MakeCode = MakeCode;
94 OutputBuffer[0].Flags = KEY_MAKE;
95 OutputBuffer[1].MakeCode = MakeCode;
96 OutputBuffer[1].Flags = KEY_BREAK;
97 *BytesConsumed = 2;
98 return TRUE;
99 }
100
101 /* Consume strange character by ignoring it */
102 DPRINT1("Strange byte received 0x%02x ('%c')\n",
103 *InputBuffer, *InputBuffer >= 32 ? *InputBuffer : '.');
104 *BytesConsumed = 1;
105 return TRUE;
106 }
107
108 NTSTATUS
109 KeyboardAddDevice(
110 IN PDRIVER_OBJECT DriverObject,
111 IN PDEVICE_OBJECT Pdo)
112 {
113 PDEVICE_OBJECT Fdo;
114 PKEYBOARD_DEVICE_EXTENSION DeviceExtension;
115 NTSTATUS Status;
116
117 DPRINT("KeyboardInitialize() called\n");
118
119 Status = IoCreateDevice(DriverObject,
120 sizeof(KEYBOARD_DEVICE_EXTENSION),
121 NULL,
122 FILE_DEVICE_KEYBOARD,
123 FILE_DEVICE_SECURE_OPEN,
124 TRUE,
125 &Fdo);
126 if (!NT_SUCCESS(Status))
127 return Status;
128
129 DeviceExtension = (PKEYBOARD_DEVICE_EXTENSION)Fdo->DeviceExtension;
130 RtlZeroMemory(DeviceExtension, sizeof(KEYBOARD_DEVICE_EXTENSION));
131 DeviceExtension->Common.Type = KeyboardFDO;
132 DeviceExtension->Common.LowerDevice = IoAttachDeviceToDeviceStack(Fdo, Pdo);
133 DeviceExtension->Green = ((PGREEN_DRIVER_EXTENSION)IoGetDriverObjectExtension(DriverObject, DriverObject))->GreenMainDO;
134 ((PGREEN_DEVICE_EXTENSION)DeviceExtension->Green->DeviceExtension)->KeyboardFdo = Fdo;
135 Fdo->Flags |= DO_POWER_PAGABLE | DO_BUFFERED_IO;
136 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
137
138 return STATUS_SUCCESS;
139 }
140
141 static VOID NTAPI
142 KeyboardDpcSendData(
143 IN PKDPC Dpc,
144 IN PVOID pDeviceExtension, /* real type PKEYBOARD_DEVICE_EXTENSION */
145 IN PVOID Unused1,
146 IN PVOID Unused2)
147 {
148 PKEYBOARD_DEVICE_EXTENSION DeviceExtension;
149 ULONG Queue;
150 ULONG InputDataConsumed;
151
152 DeviceExtension = (PKEYBOARD_DEVICE_EXTENSION)pDeviceExtension;
153
154 Queue = DeviceExtension->ActiveQueue % 2;
155 InterlockedIncrement((PLONG)&DeviceExtension->ActiveQueue);
156 (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassInformation.ClassService)(
157 DeviceExtension->ClassInformation.ClassDeviceObject,
158 DeviceExtension->KeyboardInputData[Queue],
159 DeviceExtension->KeyboardInputData[Queue] + DeviceExtension->InputDataCount[Queue],
160 &InputDataConsumed);
161
162 DeviceExtension->InputDataCount[Queue] = 0;
163 }
164
165 static VOID NTAPI
166 KeyboardDeviceWorker(
167 PVOID Context)
168 {
169 PDEVICE_OBJECT DeviceObject;
170 PKEYBOARD_DEVICE_EXTENSION DeviceExtension;
171 PGREEN_DEVICE_EXTENSION GreenDeviceExtension;
172 PDEVICE_OBJECT LowerDevice;
173 UCHAR Buffer[16]; /* Arbitrary size */
174 ULONG BufferSize;
175 LARGE_INTEGER Zero;
176 PIRP Irp;
177 IO_STATUS_BLOCK ioStatus;
178 KEVENT event;
179 KIRQL OldIrql;
180 ULONG i, Queue;
181 ULONG SpaceInQueue;
182 ULONG BytesConsumed = 0;
183 PKEYBOARD_INPUT_DATA Input;
184 NTSTATUS Status;
185
186 DPRINT("KeyboardDeviceWorker() called\n");
187
188 DeviceObject = (PDEVICE_OBJECT)Context;
189 DeviceExtension = (PKEYBOARD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
190 GreenDeviceExtension = (PGREEN_DEVICE_EXTENSION)DeviceExtension->Green->DeviceExtension;
191 LowerDevice = GreenDeviceExtension->Serial;
192 BufferSize = sizeof(Buffer);
193 Zero.QuadPart = 0;
194
195 /* Initialize device extension */
196 DeviceExtension->ActiveQueue = 0;
197 DeviceExtension->InputDataCount[0] = 0;
198 DeviceExtension->InputDataCount[1] = 0;
199 KeInitializeDpc(&DeviceExtension->KeyboardDpc, KeyboardDpcSendData, DeviceExtension);
200 RtlZeroMemory(&DeviceExtension->KeyboardInputData, sizeof(DeviceExtension->KeyboardInputData));
201
202 /* main read loop */
203 while (TRUE)
204 {
205 KeInitializeEvent(&event, NotificationEvent, FALSE);
206 Irp = IoBuildSynchronousFsdRequest(
207 IRP_MJ_READ,
208 LowerDevice,
209 Buffer, BufferSize,
210 &Zero,
211 &event,
212 &ioStatus);
213 if (!Irp)
214 {
215 /* no memory actually, try later */
216 CHECKPOINT;
217 KeStallExecutionProcessor(10);
218 continue;
219 }
220
221 Status = IoCallDriver(LowerDevice, Irp);
222 if (Status == STATUS_PENDING)
223 {
224 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
225 Status = ioStatus.Status;
226 }
227 if (!NT_SUCCESS(Status))
228 continue;
229
230 /* Read all available data and process */
231 i = 0;
232 while (i < ioStatus.Information)
233 {
234 Queue = DeviceExtension->ActiveQueue % 2;
235
236 Input = &DeviceExtension->KeyboardInputData[Queue][DeviceExtension->InputDataCount[Queue]];
237
238 /* Translate current chars to scan codes */
239 SpaceInQueue = KEYBOARD_BUFFER_SIZE - DeviceExtension->InputDataCount[Queue];
240 if (TranslateCharToScanCodes(
241 &Buffer[i], /* input buffer */
242 ioStatus.Information - i, /* input buffer size */
243 Input, /* output buffer */
244 &SpaceInQueue, /* output buffer size */
245 &BytesConsumed)) /* bytes consumed in input buffer */
246 {
247 DPRINT("Got char 0x%02x (%c)\n", Buffer[i], Buffer[i] >= 32 ? Buffer[i] : ' ');
248 DeviceExtension->InputDataCount[Queue] += BytesConsumed;
249
250 /* Send the data to the keyboard class driver */
251 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
252 KeInsertQueueDpc(&DeviceExtension->KeyboardDpc, NULL, NULL);
253 KeLowerIrql(OldIrql);
254 i += BytesConsumed;
255 }
256 else
257 {
258 /* TranslateCharToScanCodes failed. Possible reasons:
259 * - not enough bytes in input buffer (escape control code; wait next received bytes)
260 * - not enough room in output buffer (wait for the Dpc to empty it)
261 *
262 * The best way to resolve this is to try later.
263 */
264 i++;
265 }
266 }
267 }
268
269 PsTerminateSystemThread(STATUS_SUCCESS);
270 }
271
272 NTSTATUS
273 KeyboardInternalDeviceControl(
274 IN PDEVICE_OBJECT DeviceObject,
275 IN PIRP Irp)
276 {
277 PIO_STACK_LOCATION Stack;
278 PKEYBOARD_DEVICE_EXTENSION DeviceExtension;
279 NTSTATUS Status;
280
281 Stack = IoGetCurrentIrpStackLocation(Irp);
282 Irp->IoStatus.Information = 0;
283 DeviceExtension = (PKEYBOARD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
284
285 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
286 {
287 case IOCTL_INTERNAL_KEYBOARD_CONNECT:
288 {
289 DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
290 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
291 {
292 Status = STATUS_INVALID_PARAMETER;
293 break;
294 }
295
296 DeviceExtension->ClassInformation =
297 *((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
298
299 /* Start read loop */
300 Status = PsCreateSystemThread(
301 &DeviceExtension->WorkerThreadHandle,
302 (ACCESS_MASK)0L,
303 NULL,
304 NULL,
305 NULL,
306 KeyboardDeviceWorker,
307 DeviceObject);
308 break;
309 }
310 default:
311 {
312 DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
313 Stack->Parameters.DeviceIoControl.IoControlCode);
314 Status = STATUS_INVALID_DEVICE_REQUEST;
315 }
316 }
317
318 Irp->IoStatus.Status = Status;
319 IoCompleteRequest (Irp, IO_NO_INCREMENT);
320 return Status;
321 }