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