prevent buffer overflow, LoadString accepts the size of the buffer in TCHARs, not...
[reactos.git] / reactos / drivers / input / i8042prt / keyboard.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/input/i8042prt/keyboard.c
5 * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
6 * keyboard specifics
7 * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
8 * Jason Filby (jasonfilby@yahoo.com)
9 * Tinus
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <string.h>
16 #include <ntos/keyboard.h>
17 #include <ntos/minmax.h>
18 #include <rosrtl/string.h>
19
20 #include <ddk/ntddkbd.h>
21 #include <ddk/ntdd8042.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 #include "i8042prt.h"
27
28 /* GLOBALS *******************************************************************/
29
30 static BYTE TypematicTable[] = {
31 0x00, 0x00, 0x00, 0x05, 0x08, 0x0B, 0x0D, 0x0F, 0x10, 0x12, /* 0-9 */
32 0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1A, /* 10-19 */
33 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E };
34
35 typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION {
36 USHORT NumberOfIndicatorKeys;
37 INDICATOR_LIST IndicatorList[3];
38 } LOCAL_KEYBOARD_INDICATOR_TRANSLATION, *PLOCAL_KEYBOARD_INDICATOR_TRANSLATION;
39
40 static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation = { 3, {
41 {0x3A, KEYBOARD_CAPS_LOCK_ON},
42 {0x45, KEYBOARD_NUM_LOCK_ON},
43 {0x46, KEYBOARD_SCROLL_LOCK_ON}}};
44
45 static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
46 PVOID Context);
47
48 /* FUNCTIONS *****************************************************************/
49
50 /*
51 * These functions are callbacks for filter driver custom interrupt
52 * service routines.
53 */
54 VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
55 UCHAR Value)
56 {
57 I8042IsrWritePort(Context, Value, 0);
58 }
59
60 static VOID STDCALL I8042QueueKeyboardPacket(PVOID Context)
61 {
62 PDEVICE_OBJECT DeviceObject = Context;
63 PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
64 PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
65
66 DevExt->KeyComplete = TRUE;
67 DevExt->KeysInBuffer++;
68 if (DevExt->KeysInBuffer >
69 DevExt->KeyboardAttributes.InputDataQueueLength) {
70 DPRINT1("Keyboard buffer overflow\n");
71 DevExt->KeysInBuffer--;
72 }
73
74 DPRINT("Irq completes key\n");
75 KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
76 }
77
78 /*
79 * These functions are callbacks for filter driver custom
80 * initialization routines.
81 */
82 NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
83 UCHAR Value,
84 BOOLEAN WaitForAck)
85 {
86 return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
87 0,
88 Value,
89 WaitForAck);
90 }
91
92 BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
93 VOID * Context)
94 {
95 BYTE Output;
96 BYTE PortStatus;
97 NTSTATUS Status;
98 PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
99 BOOLEAN HookContinue = FALSE, HookReturn;
100 UINT Iterations = 0;
101
102 KEYBOARD_INPUT_DATA *InputData =
103 DevExt->KeyboardBuffer + DevExt->KeysInBuffer;
104
105 do {
106 Status = I8042ReadStatus(&PortStatus);
107 DPRINT("PortStatus: %x\n", PortStatus);
108 Status = I8042ReadData(&Output);
109 Iterations++;
110 if (STATUS_SUCCESS == Status)
111 break;
112 KeStallExecutionProcessor(1);
113 } while (Iterations < DevExt->Settings.PollStatusIterations);
114
115 if (STATUS_SUCCESS != Status) {
116 DPRINT1("Spurious I8042 interrupt\n");
117 return FALSE;
118 }
119
120 DPRINT("Got: %x\n", Output);
121
122 if (DevExt->KeyboardHook.IsrRoutine) {
123 HookReturn = DevExt->KeyboardHook.IsrRoutine(
124 DevExt->KeyboardHook.Context,
125 InputData,
126 &DevExt->Packet,
127 PortStatus,
128 &Output,
129 &HookContinue,
130 &DevExt->KeyboardScanState);
131
132 if (!HookContinue)
133 return HookReturn;
134 }
135
136 if (I8042PacketIsr(DevExt, Output)) {
137 if (DevExt->PacketComplete) {
138 DPRINT("Packet complete\n");
139 KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
140 }
141 DPRINT("Irq eaten by packet\n");
142 return TRUE;
143 }
144
145 DPRINT("Irq is keyboard input\n");
146
147 if (Normal == DevExt->KeyboardScanState) {
148 switch (Output) {
149 case 0xe0:
150 DevExt->KeyboardScanState = GotE0;
151 return TRUE;
152 case 0xe1:
153 DevExt->KeyboardScanState = GotE1;
154 return TRUE;
155 default:
156 ;/* continue */
157 }
158 }
159
160 InputData->Flags = 0;
161
162 switch (DevExt->KeyboardScanState) {
163 case GotE0:
164 InputData->Flags |= KEY_E0;
165 break;
166 case GotE1:
167 InputData->Flags |= KEY_E1;
168 break;
169 default:
170 ;
171 }
172 DevExt->KeyboardScanState = Normal;
173
174 if (Output & 0x80)
175 InputData->Flags |= KEY_BREAK;
176 else
177 InputData->Flags |= KEY_MAKE;
178
179 InputData->MakeCode = Output & 0x7f;
180
181 I8042QueueKeyboardPacket(DevExt->KeyboardObject);
182
183 return TRUE;
184 }
185
186 VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
187 PVOID DeferredContext,
188 PVOID SystemArgument1,
189 PVOID SystemArgument2)
190 {
191 PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
192 ULONG KeysTransferred = 0;
193 ULONG KeysInBufferCopy;
194 KIRQL Irql;
195
196 I8042PacketDpc(DevExt);
197
198 if (!DevExt->KeyComplete)
199 return;
200
201 /* We got the interrupt as it was being enabled, too bad */
202 if (!DevExt->HighestDIRQLInterrupt)
203 return;
204
205 Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
206
207 DevExt->KeyComplete = FALSE;
208 KeysInBufferCopy = DevExt->KeysInBuffer;
209
210 KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
211
212 /* Test for TAB (debugging) */
213 if (DevExt->Settings.CrashSysRq) {
214 PKEYBOARD_INPUT_DATA InputData = DevExt->KeyboardBuffer +
215 KeysInBufferCopy - 1;
216 if (InputData->MakeCode == 0x0F) {
217 DPRINT("Tab!\n");
218 DevExt->TabPressed = !(InputData->Flags & KEY_BREAK);
219 } else if (DevExt->TabPressed) {
220 DPRINT ("Queueing work item %x\n", DevExt->DebugWorkItem);
221 DevExt->DebugKey = InputData->MakeCode;
222 DevExt->TabPressed = FALSE;
223
224 IoQueueWorkItem(DevExt->DebugWorkItem,
225 &(I8042DebugWorkItem),
226 DelayedWorkQueue,
227 DevExt);
228 }
229 }
230
231 DPRINT ("Send a key\n");
232
233 if (!DevExt->KeyboardData.ClassService)
234 return;
235
236 ((KEYBOARD_CLASS_SERVICE_CALLBACK) DevExt->KeyboardData.ClassService)(
237 DevExt->KeyboardData.ClassDeviceObject,
238 DevExt->KeyboardBuffer,
239 DevExt->KeyboardBuffer + KeysInBufferCopy,
240 &KeysTransferred);
241
242 Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
243 DevExt->KeysInBuffer -= KeysTransferred;
244 KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
245 }
246
247 /* You have to send the rate/delay in a somewhat awkward format */
248 static USHORT I8042GetTypematicByte(USHORT Rate, USHORT Delay)
249 {
250 USHORT ret;
251
252 if (Rate < 3) {
253 ret = 0x0;
254 } else if (Rate > 26) {
255 ret = 0x1F;
256 } else {
257 ret = TypematicTable[Rate];
258 }
259
260 if (Delay < 375) {
261 ;
262 } else if (Delay < 625) {
263 ret |= 0x20;
264 } else if (Delay < 875) {
265 ret |= 0x40;
266 } else {
267 ret |= 0x60;
268 }
269 return ret;
270 }
271 /*
272 * Process the keyboard internal device requests
273 * returns FALSE if it doesn't understand the
274 * call so someone else can handle it.
275 */
276 BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
277 {
278 PIO_STACK_LOCATION Stk;
279 PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
280 PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
281
282 Stk = IoGetCurrentIrpStackLocation(Irp);
283
284 switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
285 case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
286 I8042StartPacket(
287 DevExt,
288 DeviceObject,
289 Stk->Parameters.DeviceIoControl.Type3InputBuffer,
290 Stk->Parameters.DeviceIoControl.InputBufferLength,
291 Irp);
292 break;
293
294 case IOCTL_KEYBOARD_SET_INDICATORS:
295 DevExt->PacketBuffer[0] = 0xED;
296 DevExt->PacketBuffer[1] = 0;
297 if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON)
298 DevExt->PacketBuffer[1] |= 0x04;
299
300 if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON)
301 DevExt->PacketBuffer[1] |= 0x02;
302
303 if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON)
304 DevExt->PacketBuffer[1] |= 0x01;
305
306 I8042StartPacket(DevExt,
307 DeviceObject,
308 DevExt->PacketBuffer,
309 2,
310 Irp);
311 break;
312 case IOCTL_KEYBOARD_SET_TYPEMATIC:
313 DevExt->PacketBuffer[0] = 0xF3;
314 DevExt->PacketBuffer[1] = I8042GetTypematicByte(
315 DevExt->KeyboardTypematic.Rate,
316 DevExt->KeyboardTypematic.Delay);
317
318 I8042StartPacket(DevExt,
319 DeviceObject,
320 DevExt->PacketBuffer,
321 2,
322 Irp);
323 break;
324 default:
325 return FALSE;
326 }
327
328 return TRUE;
329 }
330
331 /*
332 * Runs the keyboard IOCTL_INTERNAL dispatch.
333 * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
334 * so someone else can have a try at it.
335 */
336 NTSTATUS STDCALL I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
337 {
338 PIO_STACK_LOCATION Stk;
339 PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
340 PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
341
342 DPRINT("InternalDeviceControl\n");
343
344 Irp->IoStatus.Information = 0;
345 Stk = IoGetCurrentIrpStackLocation(Irp);
346
347 switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
348
349 case IOCTL_INTERNAL_KEYBOARD_CONNECT:
350 DPRINT("IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
351 if (Stk->Parameters.DeviceIoControl.InputBufferLength <
352 sizeof(CONNECT_DATA)) {
353 DPRINT1("Keyboard IOCTL_INTERNAL_KEYBOARD_CONNECT "
354 "invalid buffer size\n");
355 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
356 goto intcontfailure;
357 }
358
359 if (!DevExt->KeyboardExists) {
360 Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
361 goto intcontfailure;
362 }
363
364 if (DevExt->KeyboardClaimed) {
365 DPRINT1("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
366 "Keyboard is already claimed\n");
367 Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
368 goto intcontfailure;
369 }
370
371 memcpy(&DevExt->KeyboardData,
372 Stk->Parameters.DeviceIoControl.Type3InputBuffer,
373 sizeof(CONNECT_DATA));
374 DevExt->KeyboardHook.IsrWritePort = I8042IsrWritePortKbd;
375 DevExt->KeyboardHook.QueueKeyboardPacket =
376 I8042QueueKeyboardPacket;
377 DevExt->KeyboardHook.CallContext = DevExt;
378
379 {
380 PIO_WORKITEM WorkItem;
381 PI8042_HOOK_WORKITEM WorkItemData;
382
383 WorkItem = IoAllocateWorkItem(DeviceObject);
384 if (!WorkItem) {
385 DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
386 "Can't allocate work item\n");
387 Irp->IoStatus.Status =
388 STATUS_INSUFFICIENT_RESOURCES;
389 goto intcontfailure;
390 }
391
392 WorkItemData = ExAllocatePoolWithTag(
393 NonPagedPool,
394 sizeof(I8042_HOOK_WORKITEM),
395 TAG_I8042);
396 if (!WorkItemData) {
397 DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
398 "Can't allocate work item data\n");
399 Irp->IoStatus.Status =
400 STATUS_INSUFFICIENT_RESOURCES;
401 IoFreeWorkItem(WorkItem);
402 goto intcontfailure;
403 }
404 WorkItemData->WorkItem = WorkItem;
405 WorkItemData->Target =
406 DevExt->KeyboardData.ClassDeviceObject;
407 WorkItemData->Irp = Irp;
408
409 IoMarkIrpPending(Irp);
410 IoQueueWorkItem(WorkItem,
411 I8042SendHookWorkItem,
412 DelayedWorkQueue,
413 WorkItemData);
414
415 Irp->IoStatus.Status = STATUS_PENDING;
416 }
417
418 break;
419 case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
420 DPRINT("IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER\n");
421 if (Stk->Parameters.DeviceIoControl.InputBufferLength < 1) {
422 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
423 goto intcontfailure;
424 }
425 if (!DevExt->KeyboardInterruptObject) {
426 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
427 goto intcontfailure;
428 }
429
430 IoMarkIrpPending(Irp);
431 IoStartPacket(DeviceObject, Irp, NULL, NULL);
432 Irp->IoStatus.Status = STATUS_PENDING;
433
434 break;
435 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
436 DPRINT("IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
437 if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
438 sizeof(KEYBOARD_ATTRIBUTES)) {
439 DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_ATTRIBUTES "
440 "invalid buffer size\n");
441 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
442 goto intcontfailure;
443 }
444 memcpy(Irp->AssociatedIrp.SystemBuffer,
445 &DevExt->KeyboardAttributes,
446 sizeof(KEYBOARD_ATTRIBUTES));
447
448 Irp->IoStatus.Status = STATUS_SUCCESS;
449 break;
450 case IOCTL_KEYBOARD_QUERY_INDICATORS:
451 DPRINT("IOCTL_KEYBOARD_QUERY_INDICATORS\n");
452 if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
453 sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
454 DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_INDICATORS "
455 "invalid buffer size\n");
456 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
457 goto intcontfailure;
458 }
459 memcpy(Irp->AssociatedIrp.SystemBuffer,
460 &DevExt->KeyboardIndicators,
461 sizeof(KEYBOARD_INDICATOR_PARAMETERS));
462
463 Irp->IoStatus.Status = STATUS_SUCCESS;
464 break;
465 case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
466 DPRINT("IOCTL_KEYBOARD_QUERY_TYPEMATIC\n");
467 if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
468 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
469 DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_TYPEMATIC "
470 "invalid buffer size\n");
471 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
472 goto intcontfailure;
473 }
474 memcpy(Irp->AssociatedIrp.SystemBuffer,
475 &DevExt->KeyboardTypematic,
476 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
477
478 Irp->IoStatus.Status = STATUS_SUCCESS;
479 break;
480 case IOCTL_KEYBOARD_SET_INDICATORS:
481 DPRINT("IOCTL_KEYBOARD_SET_INDICATORS\n");
482 if (Stk->Parameters.DeviceIoControl.InputBufferLength <
483 sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
484 DPRINT("Keyboard IOCTL_KEYBOARD_SET_INDICTATORS "
485 "invalid buffer size\n");
486 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
487 goto intcontfailure;
488 }
489
490 memcpy(&DevExt->KeyboardIndicators,
491 Irp->AssociatedIrp.SystemBuffer,
492 sizeof(KEYBOARD_INDICATOR_PARAMETERS));
493
494 DPRINT("%x\n", DevExt->KeyboardIndicators.LedFlags);
495
496 IoMarkIrpPending(Irp);
497 IoStartPacket(DeviceObject, Irp, NULL, NULL);
498 Irp->IoStatus.Status = STATUS_PENDING;
499
500 break;
501 case IOCTL_KEYBOARD_SET_TYPEMATIC:
502 DPRINT("IOCTL_KEYBOARD_SET_TYPEMATIC\n");
503 if (Stk->Parameters.DeviceIoControl.InputBufferLength <
504 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
505 DPRINT("Keyboard IOCTL_KEYBOARD_SET_TYPEMATIC "
506 "invalid buffer size\n");
507 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
508 goto intcontfailure;
509 }
510
511 memcpy(&DevExt->KeyboardTypematic,
512 Irp->AssociatedIrp.SystemBuffer,
513 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
514
515 IoMarkIrpPending(Irp);
516 IoStartPacket(DeviceObject, Irp, NULL, NULL);
517 Irp->IoStatus.Status = STATUS_PENDING;
518
519 break;
520 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
521 /* We should check the UnitID, but it's kind of pointless as
522 * all keyboards are supposed to have the same one
523 */
524 if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
525 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION)) {
526 DPRINT("IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: "
527 "invalid buffer size (expected)\n");
528 /* It's to query the buffer size */
529 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
530 goto intcontfailure;
531 }
532 Irp->IoStatus.Information =
533 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
534
535 memcpy(Irp->AssociatedIrp.SystemBuffer,
536 &IndicatorTranslation,
537 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION));
538
539 Irp->IoStatus.Status = STATUS_SUCCESS;
540 break;
541 case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
542 /* Nothing to do here */
543 Irp->IoStatus.Status = STATUS_SUCCESS;
544 break;
545 default:
546 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
547 break;
548 }
549
550 intcontfailure:
551 return Irp->IoStatus.Status;
552 }
553
554 BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt)
555 {
556 DPRINT("Enabling keyboard\n");
557 if (STATUS_SUCCESS != I8042SynchWritePort(DevExt,
558 0,
559 KBD_ENABLE,
560 TRUE)) {
561 DPRINT("Can't enable keyboard\n");
562 return FALSE;
563 }
564 return TRUE;
565 }
566
567 BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt)
568 {
569 UCHAR Value;
570 NTSTATUS Status;
571
572 DPRINT("Enabling keyboard interrupt\n");
573
574 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
575 DPRINT1("Can't read i8042 mode\n");
576 return FALSE;
577 }
578
579 Status = I8042ReadDataWait(DevExt, &Value);
580 if (Status != STATUS_SUCCESS) {
581 DPRINT1("No response after read i8042 mode\n");
582 return FALSE;
583 }
584
585 Value &= ~(0x10); // don't disable keyboard
586 Value |= 0x01; // enable keyboard interrupts
587
588 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
589 DPRINT1("Can't set i8042 mode\n");
590 return FALSE;
591 }
592
593 if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
594 DPRINT1("Can't send i8042 mode\n");
595 return FALSE;
596 }
597
598 return TRUE;
599 }
600
601 BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt)
602 {
603 NTSTATUS Status;
604 UCHAR Value;
605 UINT RetryCount = 10;
606
607 DPRINT("Detecting keyboard\n");
608
609 do {
610 Status = I8042SynchWritePort(DevExt, 0, KBD_GET_ID, TRUE);
611 } while (STATUS_TIMEOUT == Status && RetryCount--);
612
613 if (Status != STATUS_SUCCESS) {
614 DPRINT("Can't write GET_ID (%x)\n", Status);
615 return FALSE;
616 }
617
618 Status = I8042ReadDataWait(DevExt, &Value);
619 if (Status != STATUS_SUCCESS) {
620 DPRINT1("No response after GET_ID\n");
621 /* Could be an AT keyboard */
622 DevExt->KeyboardIsAT = TRUE;
623 goto detectsetleds;
624 }
625 DevExt->KeyboardIsAT = FALSE;
626
627 if (Value != 0xAB && Value != 0xAC) {
628 DPRINT("Bad ID: %x\n", Value);
629 /* This is certainly not a keyboard */
630 return FALSE;
631 }
632
633 DPRINT("Keyboard ID: %x", Value);
634
635 Status = I8042ReadDataWait(DevExt, &Value);
636 if (Status != STATUS_SUCCESS) {
637 DPRINT("Partial ID\n");
638 return FALSE;
639 }
640
641 DPRINT ("%x\n", Value);
642
643 detectsetleds:
644 Status = I8042SynchWritePort(DevExt, 0, KBD_SET_LEDS, TRUE);
645 if (Status != STATUS_SUCCESS) {
646 DPRINT("Can't write SET_LEDS (%x)\n", Status);
647 return FALSE;
648 }
649 Status = I8042SynchWritePort(DevExt, 0, 0, TRUE);
650 if (Status != STATUS_SUCCESS) {
651 DPRINT("Can't finish SET_LEDS (%x)\n", Status);
652 return FALSE;
653 }
654
655 // Turn on translation
656
657 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
658 DPRINT1("Can't read i8042 mode\n");
659 return FALSE;
660 }
661
662 Status = I8042ReadDataWait(DevExt, &Value);
663 if (Status != STATUS_SUCCESS) {
664 DPRINT1("No response after read i8042 mode\n");
665 return FALSE;
666 }
667
668 Value |= 0x40; // enable keyboard translation
669
670 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
671 DPRINT1("Can't set i8042 mode\n");
672 return FALSE;
673 }
674
675 if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
676 DPRINT1("Can't send i8042 mode\n");
677 return FALSE;
678 }
679
680 return TRUE;
681 }
682
683 /* debug stuff */
684 VOID STDCALL
685 KdpServiceDispatcher(ULONG Code, PVOID Context1, PVOID Context2);
686
687 static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
688 PVOID Context)
689 {
690 ULONG Key;
691 PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
692 PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
693
694 Key = InterlockedExchange(&DevExt->DebugKey, 0);
695 DPRINT("Debug key: %x\n", Key);
696
697 if (!Key)
698 return;
699
700 KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)Key, NULL);
701 }