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
TranslateCharToScanCodes(IN PUCHAR InputBuffer,IN ULONG InputBufferSize,OUT KEYBOARD_INPUT_DATA * OutputBuffer,OUT PULONG OutputBufferSize,OUT PULONG BytesConsumed)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
KeyboardAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT Pdo)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
KeyboardDpcSendData(IN PKDPC Dpc,IN PVOID pDeviceExtension,IN PVOID Unused1,IN PVOID Unused2)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
KeyboardDeviceWorker(PVOID Context)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 KeStallExecutionProcessor(10);
217 continue;
218 }
219
220 Status = IoCallDriver(LowerDevice, Irp);
221 if (Status == STATUS_PENDING)
222 {
223 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
224 Status = ioStatus.Status;
225 }
226 if (!NT_SUCCESS(Status))
227 continue;
228
229 /* Read all available data and process */
230 i = 0;
231 while (i < ioStatus.Information)
232 {
233 Queue = DeviceExtension->ActiveQueue % 2;
234
235 Input = &DeviceExtension->KeyboardInputData[Queue][DeviceExtension->InputDataCount[Queue]];
236
237 /* Translate current chars to scan codes */
238 SpaceInQueue = KEYBOARD_BUFFER_SIZE - DeviceExtension->InputDataCount[Queue];
239 if (TranslateCharToScanCodes(
240 &Buffer[i], /* input buffer */
241 ioStatus.Information - i, /* input buffer size */
242 Input, /* output buffer */
243 &SpaceInQueue, /* output buffer size */
244 &BytesConsumed)) /* bytes consumed in input buffer */
245 {
246 DPRINT("Got char 0x%02x (%c)\n", Buffer[i], Buffer[i] >= 32 ? Buffer[i] : ' ');
247 DeviceExtension->InputDataCount[Queue] += BytesConsumed;
248
249 /* Send the data to the keyboard class driver */
250 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
251 KeInsertQueueDpc(&DeviceExtension->KeyboardDpc, NULL, NULL);
252 KeLowerIrql(OldIrql);
253 i += BytesConsumed;
254 }
255 else
256 {
257 /* TranslateCharToScanCodes failed. Possible reasons:
258 * - not enough bytes in input buffer (escape control code; wait next received bytes)
259 * - not enough room in output buffer (wait for the Dpc to empty it)
260 *
261 * The best way to resolve this is to try later.
262 */
263 i++;
264 }
265 }
266 }
267
268 PsTerminateSystemThread(STATUS_SUCCESS);
269 }
270
271 NTSTATUS
KeyboardInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)272 KeyboardInternalDeviceControl(
273 IN PDEVICE_OBJECT DeviceObject,
274 IN PIRP Irp)
275 {
276 PIO_STACK_LOCATION Stack;
277 PKEYBOARD_DEVICE_EXTENSION DeviceExtension;
278 NTSTATUS Status;
279
280 Stack = IoGetCurrentIrpStackLocation(Irp);
281 Irp->IoStatus.Information = 0;
282 DeviceExtension = (PKEYBOARD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
283
284 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
285 {
286 case IOCTL_INTERNAL_KEYBOARD_CONNECT:
287 {
288 DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
289 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
290 {
291 Status = STATUS_INVALID_PARAMETER;
292 break;
293 }
294
295 DeviceExtension->ClassInformation =
296 *((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
297
298 /* Start read loop */
299 Status = PsCreateSystemThread(
300 &DeviceExtension->WorkerThreadHandle,
301 (ACCESS_MASK)0L,
302 NULL,
303 NULL,
304 NULL,
305 KeyboardDeviceWorker,
306 DeviceObject);
307 break;
308 }
309 default:
310 {
311 DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
312 Stack->Parameters.DeviceIoControl.IoControlCode);
313 Status = STATUS_INVALID_DEVICE_REQUEST;
314 }
315 }
316
317 Irp->IoStatus.Status = Status;
318 IoCompleteRequest (Irp, IO_NO_INCREMENT);
319 return Status;
320 }
321