VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/i8042prt/i8042dep.c@ 2981

Last change on this file since 2981 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 101.8 KB
Line 
1/*++
2
3Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
4
5Module Name:
6
7 i8042dep.c
8
9Abstract:
10
11 The initialization and hardware-dependent portions of
12 the Intel i8042 port driver which are common to both
13 the keyboard and the auxiliary (PS/2 mouse) device.
14
15Environment:
16
17 Kernel mode only.
18
19Notes:
20
21 NOTES: (Future/outstanding issues)
22
23 - Powerfail not implemented.
24
25 - Consolidate duplicate code, where possible and appropriate.
26
27 - There is code ifdef'ed out (#if 0). This code was intended to
28 disable the device by setting the correct disable bit in the CCB.
29 It is supposedly correct to disable the device prior to sending a
30 command that will cause output to end up in the 8042 output buffer
31 (thereby possibly trashing something that was already in the output
32 buffer). Unfortunately, on rev K8 of the AMI 8042, disabling the
33 device where we do caused some commands to timeout, because
34 the keyboard was unable to return the expected bytes. Interestingly,
35 AMI claim that the device is only really disabled until the next ACK
36 comes back.
37
38Revision History:
39
40--*/
41
42// VBOX begin
43// VBOX backdoor logging
44//#define LOG_ENABLED
45#include <VBox/err.h>
46// VBOX end
47
48#include "stdarg.h"
49#include "stdio.h"
50#include "string.h"
51#include "ntddk.h"
52#include "i8042prt.h"
53#include "i8042log.h"
54
55//
56// Use the alloc_text pragma to specify the driver initialization routines
57// (they can be paged out).
58//
59
60#ifdef ALLOC_PRAGMA
61#pragma alloc_text(INIT,DriverEntry)
62#pragma alloc_text(INIT,I8xServiceParameters)
63#pragma alloc_text(INIT,I8xBuildResourceList)
64#pragma alloc_text(INIT,I8xInitializeHardware)
65#if defined(JAPAN) && defined(i386)
66// Fujitsu Sep.08.1994
67// We want to write debugging information to the file except stop error.
68#pragma alloc_text(INIT,I8xServiceCrashDump)
69#endif
70#endif
71
72
73
74
75NTSTATUS
76DriverEntry(
77 IN PDRIVER_OBJECT DriverObject,
78 IN PUNICODE_STRING RegistryPath
79 )
80
81/*++
82
83Routine Description:
84
85 This routine initializes the i8042 keyboard/mouse port driver.
86
87Arguments:
88
89 DriverObject - Pointer to driver object created by system.
90
91 RegistryPath - Pointer to the Unicode name of the registry path
92 for this driver.
93
94Return Value:
95
96 The function value is the final status from the initialization operation.
97
98--*/
99
100{
101 PDEVICE_OBJECT portDeviceObject = NULL;
102 PINIT_EXTENSION initializationData = NULL;
103 PDEVICE_EXTENSION deviceExtension = NULL;
104 NTSTATUS status = STATUS_SUCCESS;
105 KIRQL coordinatorIrql = 0;
106 I8042_INITIALIZE_DATA_CONTEXT initializeDataContext;
107 ULONG keyboardInterruptVector;
108 ULONG mouseInterruptVector;
109 KIRQL keyboardInterruptLevel;
110 KIRQL mouseInterruptLevel;
111 KAFFINITY keyboardAffinity;
112 KAFFINITY mouseAffinity;
113 ULONG addressSpace;
114 PHYSICAL_ADDRESS cardAddress;
115 PIO_ERROR_LOG_PACKET errorLogEntry;
116 ULONG uniqueErrorValue;
117 NTSTATUS errorCode = STATUS_SUCCESS;
118 ULONG dumpCount = 0;
119 PCM_RESOURCE_LIST resources = NULL;
120 ULONG resourceListSize = 0;
121 BOOLEAN conflictDetected;
122 ULONG i;
123
124 UNICODE_STRING fullKeyboardName;
125 UNICODE_STRING fullPointerName;
126 UNICODE_STRING baseKeyboardName;
127 UNICODE_STRING basePointerName;
128 UNICODE_STRING deviceNameSuffix;
129 UNICODE_STRING resourceDeviceClass;
130 UNICODE_STRING registryPath;
131
132#define NAME_MAX 256
133 WCHAR keyboardBuffer[NAME_MAX];
134 WCHAR pointerBuffer[NAME_MAX];
135
136#define DUMP_COUNT 4
137 ULONG dumpData[DUMP_COUNT];
138
139// VBOX start
140 int vboxRC = VINF_SUCCESS;
141// VBOX end
142
143 dprintf(("I8042PRT-I8042Initialize: enter\n"));
144 I8xPrint((1,"\n\nI8042PRT-I8042Initialize: enter\n"));
145
146 //
147 // Allocate the temporary device extension
148 //
149
150 initializationData = ExAllocatePool(
151 NonPagedPool,
152 sizeof(INIT_EXTENSION)
153 );
154
155 if (initializationData == NULL) {
156 I8xPrint((
157 1,
158 "I8042PRT-I8042Initialize: Couldn't allocate pool for init extension\n"
159 ));
160
161 status = STATUS_UNSUCCESSFUL;
162 errorCode = I8042_INSUFFICIENT_RESOURCES;
163 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 2;
164 dumpData[0] = (ULONG) sizeof(INIT_EXTENSION);
165 dumpCount = 1;
166 goto I8042InitializeExit;
167 }
168
169 //
170 // Zero-initialize various structures.
171 //
172
173 RtlZeroMemory(initializationData, sizeof(INIT_EXTENSION));
174
175 for (i = 0; i < DUMP_COUNT; i++)
176 dumpData[i] = 0;
177
178 fullKeyboardName.MaximumLength = 0;
179 fullKeyboardName.Length = 0;
180 fullPointerName.MaximumLength = 0;
181 fullPointerName.Length = 0;
182 deviceNameSuffix.MaximumLength = 0;
183 deviceNameSuffix.Length = 0;
184 resourceDeviceClass.MaximumLength = 0;
185 resourceDeviceClass.Length = 0;
186 registryPath.MaximumLength = 0;
187
188 RtlZeroMemory(keyboardBuffer, NAME_MAX * sizeof(WCHAR));
189 baseKeyboardName.Buffer = keyboardBuffer;
190 baseKeyboardName.Length = 0;
191 baseKeyboardName.MaximumLength = NAME_MAX * sizeof(WCHAR);
192
193 RtlZeroMemory(pointerBuffer, NAME_MAX * sizeof(WCHAR));
194 basePointerName.Buffer = pointerBuffer;
195 basePointerName.Length = 0;
196 basePointerName.MaximumLength = NAME_MAX * sizeof(WCHAR);
197
198 //
199 // Need to ensure that the registry path is null-terminated.
200 // Allocate pool to hold a null-terminated copy of the path.
201 //
202
203 registryPath.Buffer = ExAllocatePool(
204 PagedPool,
205 RegistryPath->Length + sizeof(UNICODE_NULL)
206 );
207
208 if (!registryPath.Buffer) {
209 I8xPrint((
210 1,
211 "I8042PRT-I8042Initialize: Couldn't allocate pool for registry path\n"
212 ));
213
214 status = STATUS_UNSUCCESSFUL;
215 errorCode = I8042_INSUFFICIENT_RESOURCES;
216 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 2;
217 dumpData[0] = (ULONG) RegistryPath->Length + sizeof(UNICODE_NULL);
218 dumpCount = 1;
219 goto I8042InitializeExit;
220
221 } else {
222
223 registryPath.Length = RegistryPath->Length + sizeof(UNICODE_NULL);
224 registryPath.MaximumLength = registryPath.Length;
225
226 RtlZeroMemory(
227 registryPath.Buffer,
228 registryPath.Length
229 );
230
231 RtlMoveMemory(
232 registryPath.Buffer,
233 RegistryPath->Buffer,
234 RegistryPath->Length
235 );
236
237 }
238
239 //
240 // Get the configuration information for this driver.
241 //
242
243 I8xKeyboardConfiguration(
244 initializationData,
245 &registryPath,
246 &baseKeyboardName,
247 &basePointerName
248 );
249
250 I8xMouseConfiguration(
251 initializationData,
252 &registryPath,
253 &baseKeyboardName,
254 &basePointerName
255 );
256
257 if (initializationData->DeviceExtension.HardwarePresent == 0) {
258
259 //
260 // There is neither a keyboard nor a mouse attached. Free
261 // resources and return with unsuccessful status.
262 //
263
264 I8xPrint((1,"I8042PRT-I8042Initialize: No keyboard/mouse attached.\n"));
265 status = STATUS_NO_SUCH_DEVICE;
266 errorCode = I8042_NO_SUCH_DEVICE;
267 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 4;
268 goto I8042InitializeExit;
269
270 } else if (!(initializationData->DeviceExtension.HardwarePresent &
271 KEYBOARD_HARDWARE_PRESENT)) {
272 //
273 // Log a warning about the missing keyboard later on, but
274 // continue processing.
275 //
276
277 I8xPrint((1,"I8042PRT-I8042Initialize: No keyboard attached.\n"));
278 status = STATUS_NO_SUCH_DEVICE;
279 errorCode = I8042_NO_KBD_DEVICE;
280 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 5;
281 dumpCount = 0;
282
283 }
284#if 0
285 //
286 // This code was removed so that we don't log an error when the mouse
287 // is not present. It was annoying to those who did not have
288 // PS/2 compatible mice to get the informational message on every boot.
289 //
290
291 else if (!(initializationData->DeviceExtension.HardwarePresent &
292 MOUSE_HARDWARE_PRESENT)) {
293
294 //
295 // Log a warning about the missing mouse later on, but
296 // continue processing.
297 //
298
299 I8xPrint((1,"I8042PRT-I8042Initialize: No mouse attached.\n"));
300 status = STATUS_NO_SUCH_DEVICE;
301 errorCode = I8042_NO_MOU_DEVICE;
302 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 6;
303 dumpCount = 0;
304 }
305#endif
306
307 //
308 // Set up space for the port's device object suffix. Note that
309 // we overallocate space for the suffix string because it is much
310 // easier than figuring out exactly how much space is required.
311 // The storage gets freed at the end of driver initialization, so
312 // who cares...
313 //
314
315 RtlInitUnicodeString(
316 &deviceNameSuffix,
317 NULL
318 );
319
320 deviceNameSuffix.MaximumLength =
321 (KEYBOARD_PORTS_MAXIMUM > POINTER_PORTS_MAXIMUM)?
322 KEYBOARD_PORTS_MAXIMUM * sizeof(WCHAR):
323 POINTER_PORTS_MAXIMUM * sizeof(WCHAR);
324 deviceNameSuffix.MaximumLength += sizeof(UNICODE_NULL);
325
326 deviceNameSuffix.Buffer = ExAllocatePool(
327 PagedPool,
328 deviceNameSuffix.MaximumLength
329 );
330
331 if (!deviceNameSuffix.Buffer) {
332
333 I8xPrint((
334 1,
335 "I8042PRT-I8042Initialize: Couldn't allocate string for device object suffix\n"
336 ));
337
338 status = STATUS_UNSUCCESSFUL;
339 errorCode = I8042_INSUFFICIENT_RESOURCES;
340 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 8;
341 dumpData[0] = (ULONG) deviceNameSuffix.MaximumLength;
342 dumpCount = 1;
343 goto I8042InitializeExit;
344
345 }
346
347 RtlZeroMemory(
348 deviceNameSuffix.Buffer,
349 deviceNameSuffix.MaximumLength
350 );
351
352 //
353 // Set up space for the port's full keyboard device object name.
354 //
355
356 RtlInitUnicodeString(
357 &fullKeyboardName,
358 NULL
359 );
360
361 fullKeyboardName.MaximumLength = sizeof(L"\\Device\\") +
362 baseKeyboardName.Length +
363 deviceNameSuffix.MaximumLength;
364
365
366 fullKeyboardName.Buffer = ExAllocatePool(
367 PagedPool,
368 fullKeyboardName.MaximumLength
369 );
370
371 if (!fullKeyboardName.Buffer) {
372
373 I8xPrint((
374 1,
375 "I8042PRT-I8042Initialize: Couldn't allocate string for keyboard device object name\n"
376 ));
377
378 status = STATUS_UNSUCCESSFUL;
379 errorCode = I8042_INSUFFICIENT_RESOURCES;
380 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 10;
381 dumpData[0] = (ULONG) fullKeyboardName.MaximumLength;
382 dumpCount = 1;
383 goto I8042InitializeExit;
384
385 }
386
387 RtlZeroMemory(
388 fullKeyboardName.Buffer,
389 fullKeyboardName.MaximumLength
390 );
391 RtlAppendUnicodeToString(
392 &fullKeyboardName,
393 L"\\Device\\"
394 );
395 RtlAppendUnicodeToString(
396 &fullKeyboardName,
397 baseKeyboardName.Buffer
398 );
399
400 for (i = 0; i < KEYBOARD_PORTS_MAXIMUM; i++) {
401
402 //
403 // Append the suffix to the device object name string. E.g., turn
404 // \Device\KeyboardPort into \Device\KeyboardPort0. Then we attempt
405 // to create the device object. If the device object already
406 // exists (because it was already created by another port driver),
407 // increment the suffix and try again.
408 //
409
410 status = RtlIntegerToUnicodeString(
411 i,
412 10,
413 &deviceNameSuffix
414 );
415
416 if (!NT_SUCCESS(status)) {
417 break;
418 }
419
420 RtlAppendUnicodeStringToString(
421 &fullKeyboardName,
422 &deviceNameSuffix
423 );
424
425 dprintf(("I8042PRT-I8042Initialize: Creating device object named %S\n", fullKeyboardName.Buffer));
426 I8xPrint((
427 1,
428 "I8042PRT-I8042Initialize: Creating device object named %ws\n",
429 fullKeyboardName.Buffer
430 ));
431
432 //
433 // Create device object for the i8042 keyboard port device.
434 // Note that we specify that this is a non-exclusive device.
435 // User code will be able to open this device, but they cannot
436 // do any real harm because all the device controls are internal
437 // device controls (and thus not accessible from user code).
438 //
439
440 status = IoCreateDevice(
441 DriverObject,
442 sizeof(DEVICE_EXTENSION),
443 &fullKeyboardName,
444 FILE_DEVICE_8042_PORT,
445 0,
446 FALSE,
447 &portDeviceObject
448 );
449
450 if (NT_SUCCESS(status)) {
451
452 //
453 // We've successfully created a device object.
454 //
455#ifdef JAPAN
456 status = I8xCreateSymbolicLink(L"\\DosDevices\\KEYBOARD", i, &fullKeyboardName);
457 if (!NT_SUCCESS(status)) {
458 errorCode = I8042_INSUFFICIENT_RESOURCES;
459 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 12;
460 dumpData[0] = (ULONG) i;
461 dumpCount = 1;
462 goto I8042InitializeExit;
463 }
464#endif
465
466 break;
467 } else {
468
469 //
470 // We'll increment the suffix and try again. Note that we reset
471 // the length of the string here to get back to the beginning
472 // of the suffix portion of the name. Do not bother to
473 // zero the suffix, though, because the string for the
474 // incremented suffix will be at least as long as the previous
475 // one.
476 //
477
478 fullKeyboardName.Length -= deviceNameSuffix.Length;
479 }
480 }
481
482 if (!NT_SUCCESS(status)) {
483 I8xPrint((
484 1,
485 "I8042PRT-I8042Initialize: Could not create port device object = %ws\n",
486 fullKeyboardName.Buffer
487 ));
488 errorCode = I8042_INSUFFICIENT_RESOURCES;
489 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 12;
490 dumpData[0] = (ULONG) i;
491 dumpCount = 1;
492 goto I8042InitializeExit;
493 }
494
495 //
496 // Set up the device extension.
497 //
498
499 deviceExtension =
500 (PDEVICE_EXTENSION)portDeviceObject->DeviceExtension;
501 *deviceExtension = initializationData->DeviceExtension;
502 deviceExtension->DeviceObject = portDeviceObject;
503
504#if defined(JAPAN) && defined(i386)
505// Fujitsu Sep.08.1994
506// We want to write debugging information to the file except stop error.
507
508 deviceExtension->Dump1Keys = 0;
509 deviceExtension->Dump2Key = 0;
510 deviceExtension->DumpFlags = 0;
511
512 //
513 // Get the crashdump information.
514 //
515
516 I8xServiceCrashDump(
517 deviceExtension,
518 &registryPath,
519 &baseKeyboardName,
520 &basePointerName
521 );
522
523#endif
524
525 //
526 // Set up the resource list prior to reporting resource usage.
527 //
528
529 I8xBuildResourceList(deviceExtension, &resources, &resourceListSize);
530
531 //
532 // Set up space for the resource device class name.
533 //
534
535 RtlInitUnicodeString(
536 &resourceDeviceClass,
537 NULL
538 );
539
540 resourceDeviceClass.MaximumLength = baseKeyboardName.Length +
541 sizeof(L"/") +
542 basePointerName.Length;
543
544 resourceDeviceClass.Buffer = ExAllocatePool(
545 PagedPool,
546 resourceDeviceClass.MaximumLength
547 );
548
549 if (!resourceDeviceClass.Buffer) {
550
551 I8xPrint((
552 1,
553 "I8042PRT-I8042Initialize: Couldn't allocate string for resource device class name\n"
554 ));
555
556 status = STATUS_UNSUCCESSFUL;
557 errorCode = I8042_INSUFFICIENT_RESOURCES;
558 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 15;
559 dumpData[0] = (ULONG) resourceDeviceClass.MaximumLength;
560 dumpCount = 1;
561 goto I8042InitializeExit;
562
563 }
564
565 //
566 // Form the resource device class name from both the keyboard and
567 // the pointer base device names.
568 //
569
570 RtlZeroMemory(
571 resourceDeviceClass.Buffer,
572 resourceDeviceClass.MaximumLength
573 );
574 RtlAppendUnicodeStringToString(
575 &resourceDeviceClass,
576 &baseKeyboardName
577 );
578 RtlAppendUnicodeToString(
579 &resourceDeviceClass,
580 L"/"
581 );
582 RtlAppendUnicodeStringToString(
583 &resourceDeviceClass,
584 &basePointerName
585 );
586
587 //
588 // Report resource usage for the registry.
589 //
590
591
592 IoReportResourceUsage(
593 &resourceDeviceClass,
594 DriverObject,
595 NULL,
596 0,
597 portDeviceObject,
598 resources,
599 resourceListSize,
600 FALSE,
601 &conflictDetected
602 );
603
604 if (conflictDetected) {
605
606 //
607 // Some other device already owns the i8042 ports or interrupts.
608 // Fatal error.
609 //
610
611 I8xPrint((
612 1,
613 "I8042PRT-I8042Initialize: Resource usage conflict\n"
614 ));
615
616 //
617 // Set up error log info.
618 //
619
620 status = STATUS_INSUFFICIENT_RESOURCES;
621 errorCode = I8042_RESOURCE_CONFLICT;
622 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 20;
623 dumpData[0] = (ULONG)
624 resources->List[0].PartialResourceList.PartialDescriptors[0].u.Interrupt.Level;
625 dumpData[1] = (ULONG)
626 resources->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Level;
627 dumpData[2] = (ULONG)
628 resources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Level;
629 dumpData[3] = (ULONG)
630 resources->List[0].PartialResourceList.PartialDescriptors[3].u.Interrupt.Level;
631 dumpCount = 4;
632
633 goto I8042InitializeExit;
634
635 }
636
637 //
638 // Map the i8042 controller registers.
639 //
640
641 for (i = 0; i < deviceExtension->Configuration.PortListCount; i++) {
642
643 addressSpace = (deviceExtension->Configuration.PortList[i].Flags
644 & CM_RESOURCE_PORT_IO) == CM_RESOURCE_PORT_IO? 1:0;
645
646 if (!HalTranslateBusAddress(
647 deviceExtension->Configuration.InterfaceType,
648 deviceExtension->Configuration.BusNumber,
649 deviceExtension->Configuration.PortList[i].u.Port.Start,
650 &addressSpace,
651 &cardAddress
652 )) {
653
654 addressSpace = 1;
655 cardAddress.QuadPart = 0;
656 }
657
658 if (!addressSpace) {
659
660 deviceExtension->UnmapRegistersRequired = TRUE;
661 deviceExtension->DeviceRegisters[i] =
662 MmMapIoSpace(
663 cardAddress,
664 deviceExtension->Configuration.PortList[i].u.Port.Length,
665 FALSE
666 );
667
668 } else {
669
670 deviceExtension->UnmapRegistersRequired = FALSE;
671 deviceExtension->DeviceRegisters[i] = (PVOID)cardAddress.LowPart;
672
673 }
674
675 if (!deviceExtension->DeviceRegisters[i]) {
676
677 I8xPrint((
678 1,
679 "I8042PRT-I8042Initialize: Couldn't map the device registers.\n"
680 ));
681 status = STATUS_NONE_MAPPED;
682
683 //
684 // Set up error log info.
685 //
686
687 errorCode = I8042_REGISTERS_NOT_MAPPED;
688 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 30;
689 dumpData[0] = cardAddress.LowPart;
690 dumpCount = 1;
691
692 goto I8042InitializeExit;
693
694 }
695 }
696
697 //
698 // Do buffered I/O.
699 //
700
701 portDeviceObject->Flags |= DO_BUFFERED_IO;
702
703 //
704 // Initialize the 8042 hardware to default values for the keyboard and
705 // mouse.
706 //
707
708 I8xInitializeHardware(portDeviceObject);
709
710 //
711 // Initialize shared spinlock used to synchronize access to the
712 // i8042 controller, keyboard, and mouse.
713 //
714
715 KeInitializeSpinLock(&(deviceExtension->SharedInterruptSpinLock));
716
717 //
718 // Allocate ring buffers for the keyboard and/or mouse input data.
719 //
720
721 if (deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) {
722
723 //
724 // Allocate memory for the keyboard data queue.
725 //
726
727 deviceExtension->KeyboardExtension.InputData =
728 ExAllocatePool(
729 NonPagedPool,
730 deviceExtension->Configuration.KeyboardAttributes.InputDataQueueLength
731 );
732
733 if (!deviceExtension->KeyboardExtension.InputData) {
734
735 //
736 // Could not allocate memory for the keyboard data queue.
737 //
738
739
740 I8xPrint((
741 1,
742 "I8042PRT-I8042Initialize: Could not allocate keyboard input data queue\n"
743 ));
744
745 status = STATUS_INSUFFICIENT_RESOURCES;
746
747 //
748 // Set up error log info.
749 //
750
751 errorCode = I8042_NO_BUFFER_ALLOCATED;
752 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 50;
753 dumpData[0] =
754 deviceExtension->Configuration.KeyboardAttributes.InputDataQueueLength;
755 dumpCount = 1;
756
757 goto I8042InitializeExit;
758 }
759
760 deviceExtension->KeyboardExtension.DataEnd =
761 (PKEYBOARD_INPUT_DATA)
762 ((PCHAR) (deviceExtension->KeyboardExtension.InputData)
763 + deviceExtension->Configuration.KeyboardAttributes.InputDataQueueLength);
764
765 //
766 // Zero the keyboard input data ring buffer.
767 //
768
769 RtlZeroMemory(
770 deviceExtension->KeyboardExtension.InputData,
771 deviceExtension->Configuration.KeyboardAttributes.InputDataQueueLength
772 );
773
774 }
775
776 if (deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT) {
777
778 //
779 // Set up space for the port's full pointer device object name.
780 //
781
782 RtlInitUnicodeString(
783 &fullPointerName,
784 NULL
785 );
786
787 fullPointerName.MaximumLength = sizeof(L"\\Device\\") +
788 basePointerName.Length +
789 deviceNameSuffix.MaximumLength;
790
791
792 fullPointerName.Buffer = ExAllocatePool(
793 PagedPool,
794 fullPointerName.MaximumLength
795 );
796
797 if (!fullPointerName.Buffer) {
798
799 I8xPrint((
800 1,
801 "I8042PRT-I8042Initialize: Couldn't allocate string for pointer device object name\n"
802 ));
803
804 status = STATUS_UNSUCCESSFUL;
805 goto I8042InitializeExit;
806
807 }
808
809 RtlZeroMemory(
810 fullPointerName.Buffer,
811 fullPointerName.MaximumLength
812 );
813 RtlAppendUnicodeToString(
814 &fullPointerName,
815 L"\\Device\\"
816 );
817 RtlAppendUnicodeToString(
818 &fullPointerName,
819 basePointerName.Buffer
820 );
821
822 RtlZeroMemory(
823 deviceNameSuffix.Buffer,
824 deviceNameSuffix.MaximumLength
825 );
826 deviceNameSuffix.Length = 0;
827
828 for (i = 0; i < POINTER_PORTS_MAXIMUM; i++) {
829
830 //
831 // Append the suffix to the device object name string. E.g., turn
832 // \Device\PointerPort into \Device\PointerPort0. Then we attempt
833 // to create a symbolic link to the keyboard device object. If
834 // a device object with the symbolic link name already
835 // exists (because it was created by another port driver),
836 // increment the suffix and try again.
837 //
838
839 status = RtlIntegerToUnicodeString(
840 i,
841 10,
842 &deviceNameSuffix
843 );
844
845 if (!NT_SUCCESS(status)) {
846 break;
847 }
848
849 RtlAppendUnicodeStringToString(
850 &fullPointerName,
851 &deviceNameSuffix
852 );
853
854 dprintf(("I8042PRT-I8042Initialize: pointer port name (symbolic link) = %S\n", fullPointerName.Buffer));
855 I8xPrint((
856 1,
857 "I8042PRT-I8042Initialize: pointer port name (symbolic link) = %ws\n",
858 fullPointerName.Buffer
859 ));
860
861 //
862 // Set up a symbolic link so that the keyboard and mouse class
863 // drivers can access the port device object by different names.
864 //
865
866#ifdef JAPAN
867 status = I8xCreateSymbolicLink(L"\\DosDevices\\POINTER", i, &fullPointerName);
868 if (!NT_SUCCESS(status)) {
869 errorCode = I8042_INSUFFICIENT_RESOURCES;
870 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 12;
871 dumpData[0] = (ULONG) i;
872 dumpCount = 1;
873 goto I8042InitializeExit;
874 }
875#endif
876 status = IoCreateSymbolicLink(
877 &fullPointerName,
878 &fullKeyboardName
879 );
880
881 if (NT_SUCCESS(status)) {
882
883 //
884 // We've successfully created a symbolic link.
885 //
886
887 break;
888
889 } else {
890
891 //
892 // We'll increment the suffix and try again. Note that we reset
893 // the length of the string here to get back to the beginning
894 // of the suffix portion of the name. Do not bother to
895 // zero the suffix, though, because the string for the
896 // incremented suffix will be at least as long as the previous
897 // one.
898 //
899
900 fullPointerName.Length -= deviceNameSuffix.Length;
901 }
902 }
903
904 if (!NT_SUCCESS(status)) {
905 I8xPrint((
906 1,
907 "I8042PRT-I8042Initialize: Could not create symbolic link = %ws\n",
908 fullPointerName.Buffer
909 ));
910 goto I8042InitializeExit;
911 }
912
913 //
914 // Allocate memory for the mouse data queue.
915 //
916
917 deviceExtension->MouseExtension.InputData =
918 ExAllocatePool(
919 NonPagedPool,
920 deviceExtension->Configuration.MouseAttributes.InputDataQueueLength
921 );
922
923 if (!deviceExtension->MouseExtension.InputData) {
924
925 //
926 // Could not allocate memory for the mouse data queue.
927 //
928
929 I8xPrint((
930 1,
931 "I8042PRT-I8042Initialize: Could not allocate mouse input data queue\n"
932 ));
933
934 status = STATUS_INSUFFICIENT_RESOURCES;
935
936 //
937 // Set up error log info.
938 //
939
940 errorCode = I8042_NO_BUFFER_ALLOCATED;
941 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 60;
942 dumpData[0] =
943 deviceExtension->Configuration.MouseAttributes.InputDataQueueLength;
944 dumpCount = 1;
945
946 goto I8042InitializeExit;
947 }
948
949 deviceExtension->MouseExtension.DataEnd =
950 (PMOUSE_INPUT_DATA)
951 ((PCHAR) (deviceExtension->MouseExtension.InputData)
952 + deviceExtension->Configuration.MouseAttributes.InputDataQueueLength);
953
954 //
955 // Zero the mouse input data ring buffer.
956 //
957
958 RtlZeroMemory(
959 deviceExtension->MouseExtension.InputData,
960 deviceExtension->Configuration.MouseAttributes.InputDataQueueLength
961 );
962
963 }
964
965 //
966 // Initialize the connection data.
967 //
968
969 deviceExtension->KeyboardExtension.ConnectData.ClassDeviceObject = NULL;
970 deviceExtension->KeyboardExtension.ConnectData.ClassService = NULL;
971 deviceExtension->MouseExtension.ConnectData.ClassDeviceObject = NULL;
972 deviceExtension->MouseExtension.ConnectData.ClassService = NULL;
973
974 //
975 // Initialize the input data queues.
976 //
977
978 initializeDataContext.DeviceExtension = deviceExtension;
979 initializeDataContext.DeviceType = KeyboardDeviceType;
980 I8xInitializeDataQueue((PVOID) &initializeDataContext);
981
982 initializeDataContext.DeviceType = MouseDeviceType;
983 I8xInitializeDataQueue((PVOID) &initializeDataContext);
984
985 //
986 // Initialize the port completion DPC object in the device extension.
987 // This DPC routine handles the completion of successful set requests.
988 //
989
990 deviceExtension->DpcInterlockKeyboard = -1;
991 deviceExtension->DpcInterlockMouse = -1;
992 IoInitializeDpcRequest(portDeviceObject, I8042CompletionDpc);
993
994 //
995 // Initialize the port completion DPC for requests that exceed the
996 // maximum number of retries.
997 //
998
999 KeInitializeDpc(
1000 &deviceExtension->RetriesExceededDpc,
1001 (PKDEFERRED_ROUTINE) I8042RetriesExceededDpc,
1002 portDeviceObject
1003 );
1004
1005 //
1006 // Initialize the port DPC queue to log overrun and internal
1007 // driver errors.
1008 //
1009
1010 KeInitializeDpc(
1011 &deviceExtension->ErrorLogDpc,
1012 (PKDEFERRED_ROUTINE) I8042ErrorLogDpc,
1013 portDeviceObject
1014 );
1015
1016 //
1017 // Initialize the port keyboard ISR DPC and mouse ISR DPC. The ISR DPC
1018 // is responsible for calling the connected class driver's callback
1019 // routine to process the input data queue.
1020 //
1021
1022 KeInitializeDpc(
1023 &deviceExtension->KeyboardIsrDpc,
1024 (PKDEFERRED_ROUTINE) I8042KeyboardIsrDpc,
1025 portDeviceObject
1026 );
1027
1028 KeInitializeDpc(
1029 &deviceExtension->KeyboardIsrDpcRetry,
1030 (PKDEFERRED_ROUTINE) I8042KeyboardIsrDpc,
1031 portDeviceObject
1032 );
1033
1034 KeInitializeDpc(
1035 &deviceExtension->MouseIsrDpc,
1036 (PKDEFERRED_ROUTINE) I8042MouseIsrDpc,
1037 portDeviceObject
1038 );
1039
1040 KeInitializeDpc(
1041 &deviceExtension->MouseIsrDpcRetry,
1042 (PKDEFERRED_ROUTINE) I8042MouseIsrDpc,
1043 portDeviceObject
1044 );
1045
1046 //
1047 // Initialize the port DPC queue for timeouts.
1048 //
1049
1050 KeInitializeDpc(
1051 &deviceExtension->TimeOutDpc,
1052 (PKDEFERRED_ROUTINE) I8042TimeOutDpc,
1053 portDeviceObject
1054 );
1055
1056 //
1057 // Initialize the i8042 command timer.
1058 //
1059
1060 KeInitializeTimer(&deviceExtension->CommandTimer);
1061 deviceExtension->TimerCount = I8042_ASYNC_NO_TIMEOUT;
1062
1063 //
1064 // Initialize the keyboard and mouse data consumption timers.
1065 //
1066
1067 KeInitializeTimer(&deviceExtension->KeyboardExtension.DataConsumptionTimer);
1068 KeInitializeTimer(&deviceExtension->MouseExtension.DataConsumptionTimer);
1069
1070 //
1071 // From the Hal, get the keyboard and mouse interrupt vectors and levels.
1072 //
1073
1074 keyboardInterruptVector = HalGetInterruptVector(
1075 deviceExtension->Configuration.InterfaceType,
1076 deviceExtension->Configuration.BusNumber,
1077 deviceExtension->Configuration.KeyboardInterrupt.u.Interrupt.Level,
1078 deviceExtension->Configuration.KeyboardInterrupt.u.Interrupt.Vector,
1079 &keyboardInterruptLevel,
1080 &keyboardAffinity
1081 );
1082
1083 mouseInterruptVector = HalGetInterruptVector(
1084 deviceExtension->Configuration.InterfaceType,
1085 deviceExtension->Configuration.BusNumber,
1086 deviceExtension->Configuration.MouseInterrupt.u.Interrupt.Level,
1087 deviceExtension->Configuration.MouseInterrupt.u.Interrupt.Vector,
1088 &mouseInterruptLevel,
1089 &mouseAffinity
1090 );
1091
1092 //
1093 // Determine the coordinator interrupt object
1094 // based on which device has the highest IRQL.
1095 //
1096
1097 if ((deviceExtension->HardwarePresent &
1098 (KEYBOARD_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT)) ==
1099 (KEYBOARD_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT)) {
1100
1101 coordinatorIrql = (keyboardInterruptLevel > mouseInterruptLevel) ?
1102 keyboardInterruptLevel: mouseInterruptLevel;
1103 }
1104
1105 //
1106 // Initialize and connect the interrupt object for the mouse.
1107 // Determine the coordinator interrupt object based on which device
1108 // has the highest IRQL.
1109 //
1110
1111 if (deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT) {
1112
1113 status = IoConnectInterrupt(
1114 &(deviceExtension->MouseInterruptObject),
1115 (PKSERVICE_ROUTINE) I8042MouseInterruptService,
1116 (PVOID) portDeviceObject,
1117 &(deviceExtension->SharedInterruptSpinLock),
1118 mouseInterruptVector,
1119 mouseInterruptLevel,
1120 (KIRQL) ((coordinatorIrql == (KIRQL)0) ?
1121 mouseInterruptLevel : coordinatorIrql),
1122 deviceExtension->Configuration.MouseInterrupt.Flags
1123 == CM_RESOURCE_INTERRUPT_LATCHED ?
1124 Latched : LevelSensitive,
1125 deviceExtension->Configuration.MouseInterrupt.ShareDisposition,
1126 mouseAffinity,
1127 deviceExtension->Configuration.FloatingSave
1128 );
1129
1130 if (!NT_SUCCESS(status)) {
1131
1132 //
1133 // Failed to install. Free up resources before exiting.
1134 //
1135
1136 I8xPrint((
1137 1,
1138 "I8042PRT-I8042Initialize: Could not connect mouse interrupt\n"
1139 ));
1140
1141 //
1142 // Set up error log info.
1143 //
1144
1145 errorCode = I8042_NO_INTERRUPT_CONNECTED;
1146 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 70;
1147 dumpData[0] = mouseInterruptLevel;
1148 dumpCount = 1;
1149
1150 goto I8042InitializeExit;
1151
1152 }
1153
1154 //
1155 // Enable mouse transmissions, now that the interrupts are enabled.
1156 // We've held off transmissions until now, in an attempt to
1157 // keep the driver's notion of mouse input data state in sync
1158 // with the mouse hardware.
1159 //
1160
1161 status = I8xMouseEnableTransmission(portDeviceObject);
1162
1163 if (!NT_SUCCESS(status)) {
1164
1165 //
1166 // Couldn't enable mouse transmissions. Continue on, anyway.
1167 //
1168
1169 I8xPrint((
1170 1,
1171 "I8042PRT-I8042Initialize: Could not enable mouse transmission\n"
1172 ));
1173
1174 status = STATUS_SUCCESS;
1175 }
1176
1177 }
1178
1179 //
1180 // Initialize and connect the interrupt object for the keyboard.
1181 // Determine the coordinator interrupt object based on which device
1182 // has the highest IRQL.
1183 //
1184
1185 if (deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) {
1186
1187 status = IoConnectInterrupt(
1188 &(deviceExtension->KeyboardInterruptObject),
1189 (PKSERVICE_ROUTINE) I8042KeyboardInterruptService,
1190 (PVOID) portDeviceObject,
1191 &(deviceExtension->SharedInterruptSpinLock),
1192 keyboardInterruptVector,
1193 keyboardInterruptLevel,
1194 (KIRQL) ((coordinatorIrql == (KIRQL)0) ?
1195 keyboardInterruptLevel : coordinatorIrql),
1196 deviceExtension->Configuration.KeyboardInterrupt.Flags
1197 == CM_RESOURCE_INTERRUPT_LATCHED ?
1198 Latched : LevelSensitive,
1199 deviceExtension->Configuration.KeyboardInterrupt.ShareDisposition,
1200 keyboardAffinity,
1201 deviceExtension->Configuration.FloatingSave
1202 );
1203
1204 if (!NT_SUCCESS(status)) {
1205
1206 //
1207 // Failed to install. Free up resources before exiting.
1208 //
1209
1210 I8xPrint((
1211 1,
1212 "I8042PRT-I8042Initialize: Could not connect keyboard interrupt\n"
1213 ));
1214
1215 //
1216 // Set up error log info.
1217 //
1218
1219 errorCode = I8042_NO_INTERRUPT_CONNECTED;
1220 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 80;
1221 dumpData[0] = keyboardInterruptLevel;
1222 dumpCount = 1;
1223
1224 goto I8042InitializeExit;
1225
1226 }
1227
1228 }
1229
1230 //
1231 // Once initialization is finished, load the device map information
1232 // into the registry so that setup can determine which pointer port
1233 // and keyboard port are active.
1234 //
1235
1236 if (deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) {
1237
1238 status = RtlWriteRegistryValue(
1239 RTL_REGISTRY_DEVICEMAP,
1240 baseKeyboardName.Buffer,
1241 fullKeyboardName.Buffer,
1242 REG_SZ,
1243 registryPath.Buffer,
1244 registryPath.Length
1245 );
1246
1247 if (!NT_SUCCESS(status)) {
1248
1249 I8xPrint((
1250 1,
1251 "I8042PRT-I8042Initialize: Could not store keyboard name in DeviceMap\n"
1252 ));
1253
1254 errorCode = I8042_NO_DEVICEMAP_CREATED;
1255 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 90;
1256 dumpCount = 0;
1257
1258 goto I8042InitializeExit;
1259
1260 } else {
1261
1262 I8xPrint((
1263 1,
1264 "I8042PRT-I8042Initialize: Stored keyboard name in DeviceMap\n"
1265 ));
1266
1267 }
1268
1269 }
1270
1271 if (deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT) {
1272
1273 status = RtlWriteRegistryValue(
1274 RTL_REGISTRY_DEVICEMAP,
1275 basePointerName.Buffer,
1276 fullPointerName.Buffer,
1277 REG_SZ,
1278 registryPath.Buffer,
1279 registryPath.Length
1280 );
1281
1282 if (!NT_SUCCESS(status)) {
1283
1284 I8xPrint((
1285 1,
1286 "I8042PRT-I8042Initialize: Could not store pointer name in DeviceMap\n"
1287 ));
1288
1289 errorCode = I8042_NO_DEVICEMAP_CREATED;
1290 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 95;
1291 dumpCount = 0;
1292
1293 goto I8042InitializeExit;
1294
1295 } else {
1296
1297 I8xPrint((
1298 1,
1299 "I8042PRT-I8042Initialize: Stored pointer name in DeviceMap\n"
1300 ));
1301 }
1302
1303 }
1304
1305 ASSERT(status == STATUS_SUCCESS);
1306
1307#ifdef PNP_IDENTIFY
1308 //
1309 // Log information about our resources & device object in the registry
1310 // so that the user mode PnP stuff can determine which driver/device goes
1311 // with which set of arcdetect resources
1312 //
1313
1314 LinkDeviceToDescription(
1315 RegistryPath,
1316 &fullKeyboardName,
1317 initializationData->KeyboardConfig.InterfaceType,
1318 initializationData->KeyboardConfig.InterfaceNumber,
1319 initializationData->KeyboardConfig.ControllerType,
1320 initializationData->KeyboardConfig.ControllerNumber,
1321 initializationData->KeyboardConfig.PeripheralType,
1322 initializationData->KeyboardConfig.PeripheralNumber
1323 );
1324
1325 LinkDeviceToDescription(
1326 RegistryPath,
1327 &fullPointerName,
1328 initializationData->MouseConfig.InterfaceType,
1329 initializationData->MouseConfig.InterfaceNumber,
1330 initializationData->MouseConfig.ControllerType,
1331 initializationData->MouseConfig.ControllerNumber,
1332 initializationData->MouseConfig.PeripheralType,
1333 initializationData->MouseConfig.PeripheralNumber
1334 );
1335#endif
1336
1337// VBOX start
1338 vboxRC = VbglInit ();
1339
1340 if (VBOX_FAILURE(vboxRC))
1341 {
1342 dprintf(("i8042prt::DriverEntry: could not initialize guest library, rc = %Vrc\n", vboxRC));
1343 status = STATUS_UNSUCCESSFUL;
1344 goto I8042InitializeExit;
1345 }
1346 else
1347 {
1348 VMMDevReqMouseStatus *req = NULL;
1349
1350 vboxRC = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
1351
1352 if (VBOX_SUCCESS(vboxRC))
1353 {
1354 /* Inform host that we support absolute */
1355 req->mouseFeatures = VBOXGUEST_MOUSE_GUEST_CAN_ABSOLUTE;
1356 req->pointerXPos = 0;
1357 req->pointerYPos = 0;
1358
1359 vboxRC = VbglGRPerform (&req->header);
1360
1361 if (VBOX_FAILURE(vboxRC) || VBOX_FAILURE(req->header.rc))
1362 {
1363 dprintf(("i8042prt::DriverEntry: ERROR communicating new mouse capabilities to VMMDev."
1364 "rc = %d, VMMDev rc = %Vrc\n", vboxRC, req->header.rc));
1365 }
1366 else
1367 {
1368 /* We will use the allocated request buffer in the ServiceCallback to GET mouse status. */
1369 req->header.requestType = VMMDevReq_GetMouseStatus;
1370 deviceExtension->reqIS = req;
1371 }
1372 }
1373 else
1374 {
1375 VbglTerminate ();
1376
1377 dprintf(("i8042prt::DriverEntry: could not allocate request buffer, rc = %Vrc\n", vboxRC));
1378 status = STATUS_UNSUCCESSFUL;
1379 goto I8042InitializeExit;
1380 }
1381 }
1382// VBOX end
1383
1384 //
1385 // Set up the device driver entry points.
1386 //
1387
1388 DriverObject->DriverStartIo = I8042StartIo;
1389 DriverObject->MajorFunction[IRP_MJ_CREATE] = I8042OpenCloseDispatch;
1390 DriverObject->MajorFunction[IRP_MJ_CLOSE] = I8042OpenCloseDispatch;
1391 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] =
1392 I8042Flush;
1393 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
1394 I8042InternalDeviceControl;
1395 //
1396 // NOTE: Don't allow this driver to unload. Otherwise, we would set
1397 // DriverObject->DriverUnload = I8042Unload.
1398 //
1399
1400I8042InitializeExit:
1401
1402 if (errorCode != STATUS_SUCCESS) {
1403
1404 //
1405 // Log an error/warning message.
1406 //
1407
1408 errorLogEntry = (PIO_ERROR_LOG_PACKET)
1409 IoAllocateErrorLogEntry(
1410 (portDeviceObject == NULL) ?
1411 (PVOID) DriverObject : (PVOID) portDeviceObject,
1412 (UCHAR) (sizeof(IO_ERROR_LOG_PACKET)
1413 + (dumpCount * sizeof(ULONG)))
1414 );
1415
1416 if (errorLogEntry != NULL) {
1417
1418 errorLogEntry->ErrorCode = errorCode;
1419 errorLogEntry->DumpDataSize = (USHORT) dumpCount * sizeof(ULONG);
1420 errorLogEntry->SequenceNumber = 0;
1421 errorLogEntry->MajorFunctionCode = 0;
1422 errorLogEntry->IoControlCode = 0;
1423 errorLogEntry->RetryCount = 0;
1424 errorLogEntry->UniqueErrorValue = uniqueErrorValue;
1425 errorLogEntry->FinalStatus = status;
1426 for (i = 0; i < dumpCount; i++)
1427 errorLogEntry->DumpData[i] = dumpData[i];
1428
1429 IoWriteErrorLogEntry(errorLogEntry);
1430 }
1431 }
1432
1433 if (!NT_SUCCESS(status)) {
1434
1435 //
1436 // The initialization failed. Cleanup resources before exiting.
1437 //
1438 // N.B. It is okay to disconnect the interrupt even if it never
1439 // got connected.
1440 //
1441
1442 //
1443 // Note: No need/way to undo the KeInitializeDpc or
1444 // KeInitializeTimer calls.
1445 //
1446
1447 //
1448 // The initialization failed. Cleanup resources before exiting.
1449 //
1450
1451 if (resources) {
1452
1453 //
1454 // Call IoReportResourceUsage to remove the resources from
1455 // the map.
1456 //
1457
1458 resources->Count = 0;
1459
1460 IoReportResourceUsage(
1461 &resourceDeviceClass,
1462 DriverObject,
1463 NULL,
1464 0,
1465 portDeviceObject,
1466 resources,
1467 resourceListSize,
1468 FALSE,
1469 &conflictDetected
1470 );
1471
1472 }
1473
1474 if (deviceExtension) {
1475 if (deviceExtension->KeyboardInterruptObject != NULL)
1476 IoDisconnectInterrupt(deviceExtension->KeyboardInterruptObject);
1477 if (deviceExtension->MouseInterruptObject != NULL)
1478 IoDisconnectInterrupt(deviceExtension->MouseInterruptObject);
1479 if (deviceExtension->KeyboardExtension.InputData)
1480 ExFreePool(deviceExtension->KeyboardExtension.InputData);
1481 if (deviceExtension->MouseExtension.InputData)
1482 ExFreePool(deviceExtension->MouseExtension.InputData);
1483
1484 if (deviceExtension->UnmapRegistersRequired) {
1485 for (i = 0;
1486 i < deviceExtension->Configuration.PortListCount; i++){
1487 if (deviceExtension->DeviceRegisters[i]) {
1488 MmUnmapIoSpace(
1489 deviceExtension->DeviceRegisters[i],
1490 deviceExtension->Configuration.PortList[i].u.Port.Length);
1491 }
1492 }
1493 }
1494 }
1495
1496
1497 if (portDeviceObject) {
1498 if (fullPointerName.Length > 0) {
1499 IoDeleteSymbolicLink(&fullPointerName);
1500 }
1501 IoDeleteDevice(portDeviceObject);
1502 }
1503 }
1504
1505 //
1506 // Free the resource list.
1507 //
1508 // N.B. If we ever decide to hang on to the resource list instead,
1509 // we need to allocate it from non-paged pool (it is now paged pool).
1510 //
1511
1512 if (resources) {
1513 ExFreePool(resources);
1514 }
1515
1516 //
1517 // Free the temporary device extension
1518 //
1519
1520 if (initializationData != NULL) {
1521 ExFreePool(initializationData);
1522 }
1523
1524 //
1525 // Free the unicode strings for device names.
1526 //
1527
1528 if (deviceNameSuffix.MaximumLength != 0)
1529 ExFreePool(deviceNameSuffix.Buffer);
1530 if (fullKeyboardName.MaximumLength != 0)
1531 ExFreePool(fullKeyboardName.Buffer);
1532 if (fullPointerName.MaximumLength != 0)
1533 ExFreePool(fullPointerName.Buffer);
1534 if (resourceDeviceClass.MaximumLength != 0)
1535 ExFreePool(resourceDeviceClass.Buffer);
1536 if (registryPath.MaximumLength != 0)
1537 ExFreePool(registryPath.Buffer);
1538
1539 I8xPrint((1,"I8042PRT-I8042Initialize: exit\n"));
1540
1541 return(status);
1542
1543}
1544
1545
1546VOID
1547I8042Unload(
1548 IN PDRIVER_OBJECT DriverObject
1549 )
1550{
1551 UNREFERENCED_PARAMETER(DriverObject);
1552
1553 I8xPrint((2, "I8042PRT-I8042Unload: enter\n"));
1554 I8xPrint((2, "I8042PRT-I8042Unload: exit\n"));
1555}
1556
1557
1558VOID
1559I8xBuildResourceList(
1560 IN PDEVICE_EXTENSION DeviceExtension,
1561 OUT PCM_RESOURCE_LIST *ResourceList,
1562 OUT PULONG ResourceListSize
1563 )
1564
1565/*++
1566
1567Routine Description:
1568
1569 Creates a resource list that is used to query or report resource usage.
1570
1571Arguments:
1572
1573 DeviceExtension - Pointer to the port's device extension.
1574
1575 ResourceList - Pointer to a pointer to the resource list to be allocated
1576 and filled.
1577
1578 ResourceListSize - Pointer to the returned size of the resource
1579 list (in bytes).
1580
1581Return Value:
1582
1583 None. If the call succeeded, *ResourceList points to the built
1584 resource list and *ResourceListSize is set to the size (in bytes)
1585 of the resource list; otherwise, *ResourceList is NULL.
1586
1587Note:
1588
1589 Memory may be allocated here for *ResourceList. It must be
1590 freed up by the caller, by calling ExFreePool();
1591
1592--*/
1593
1594{
1595 ULONG count = 0;
1596 ULONG i = 0;
1597 ULONG j = 0;
1598#define DUMP_COUNT 4
1599 ULONG dumpData[DUMP_COUNT];
1600
1601 count += DeviceExtension->Configuration.PortListCount;
1602 if (DeviceExtension->Configuration.KeyboardInterrupt.Type
1603 == CmResourceTypeInterrupt)
1604 count += 1;
1605 if (DeviceExtension->Configuration.MouseInterrupt.Type
1606 == CmResourceTypeInterrupt)
1607 count += 1;
1608
1609 *ResourceListSize = sizeof(CM_RESOURCE_LIST) +
1610 ((count - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
1611
1612 *ResourceList = (PCM_RESOURCE_LIST) ExAllocatePool(
1613 PagedPool,
1614 *ResourceListSize
1615 );
1616
1617 //
1618 // Return NULL if the structure could not be allocated.
1619 // Otherwise, fill in the resource list.
1620 //
1621
1622 if (!*ResourceList) {
1623
1624 //
1625 // Could not allocate memory for the resource list.
1626 //
1627
1628 I8xPrint((
1629 1,
1630 "I8042PRT-I8xBuildResourceList: Could not allocate resource list\n"
1631 ));
1632
1633 //
1634 // Log an error.
1635 //
1636
1637 dumpData[0] = *ResourceListSize;
1638 *ResourceListSize = 0;
1639
1640 I8xLogError(
1641 DeviceExtension->DeviceObject,
1642 I8042_INSUFFICIENT_RESOURCES,
1643 I8042_ERROR_VALUE_BASE + 110,
1644 STATUS_INSUFFICIENT_RESOURCES,
1645 dumpData,
1646 1
1647 );
1648
1649 return;
1650 }
1651
1652 RtlZeroMemory(
1653 *ResourceList,
1654 *ResourceListSize
1655 );
1656
1657 //
1658 // Concoct one full resource descriptor.
1659 //
1660
1661 (*ResourceList)->Count = 1;
1662
1663 (*ResourceList)->List[0].InterfaceType =
1664 DeviceExtension->Configuration.InterfaceType;
1665 (*ResourceList)->List[0].BusNumber =
1666 DeviceExtension->Configuration.BusNumber;
1667
1668 //
1669 // Build the partial resource descriptors for interrupt and port
1670 // resources from the saved values.
1671 //
1672
1673 (*ResourceList)->List[0].PartialResourceList.Count = count;
1674 if (DeviceExtension->Configuration.KeyboardInterrupt.Type
1675 == CmResourceTypeInterrupt)
1676 (*ResourceList)->List[0].PartialResourceList.PartialDescriptors[i++] =
1677 DeviceExtension->Configuration.KeyboardInterrupt;
1678 if (DeviceExtension->Configuration.MouseInterrupt.Type
1679 == CmResourceTypeInterrupt)
1680 (*ResourceList)->List[0].PartialResourceList.PartialDescriptors[i++] =
1681 DeviceExtension->Configuration.MouseInterrupt;
1682
1683 for (j = 0; j < DeviceExtension->Configuration.PortListCount; j++) {
1684 (*ResourceList)->List[0].PartialResourceList.PartialDescriptors[i++] =
1685 DeviceExtension->Configuration.PortList[j];
1686 }
1687
1688}
1689
1690
1691VOID
1692I8xDrainOutputBuffer(
1693 IN PUCHAR DataAddress,
1694 IN PUCHAR CommandAddress
1695 )
1696
1697/*++
1698
1699Routine Description:
1700
1701 This routine drains the i8042 controller's output buffer. This gets
1702 rid of stale data that may have resulted from the user hitting a key
1703 or moving the mouse, prior to the execution of I8042Initialize.
1704
1705Arguments:
1706
1707 DataAddress - Pointer to the data address to read/write from/to.
1708
1709 CommandAddress - Pointer to the command/status address to
1710 read/write from/to.
1711
1712
1713Return Value:
1714
1715 None.
1716
1717--*/
1718
1719{
1720 UCHAR byte;
1721 ULONG i;
1722
1723 I8xPrint((3, "I8042PRT-I8xDrainOutputBuffer: enter\n"));
1724
1725 //
1726 // Wait till the input buffer is processed by keyboard
1727 // then go and read the data from keyboard. Don't wait longer
1728 // than 1 second in case hardware is broken. This fix is
1729 // necessary for some DEC hardware so that the keyboard doesn't
1730 // lock up.
1731 //
1732 for (i = 0; i < 2000; i++) {
1733 if (!(I8X_GET_STATUS_BYTE(CommandAddress)&INPUT_BUFFER_FULL)) {
1734 break;
1735 }
1736 KeStallExecutionProcessor(500);
1737 }
1738
1739 while (I8X_GET_STATUS_BYTE(CommandAddress) & OUTPUT_BUFFER_FULL) {
1740
1741 //
1742 // Eat the output buffer byte.
1743 //
1744
1745 byte = I8X_GET_DATA_BYTE(DataAddress);
1746 }
1747
1748 I8xPrint((3, "I8042PRT-I8xDrainOutputBuffer: exit\n"));
1749}
1750
1751
1752VOID
1753I8xGetByteAsynchronous(
1754 IN CCHAR DeviceType,
1755 IN PDEVICE_EXTENSION DeviceExtension,
1756 OUT PUCHAR Byte
1757 )
1758
1759/*++
1760
1761Routine Description:
1762
1763 This routine reads a data byte from the controller or keyboard
1764 or mouse, asynchronously.
1765
1766Arguments:
1767
1768 DeviceType - Specifies which device (i8042 controller, keyboard, or
1769 mouse) to read the byte from.
1770
1771 DeviceExtension - Pointer to the device extension.
1772
1773 Byte - Pointer to the location to store the byte read from the hardware.
1774
1775Return Value:
1776
1777 None.
1778
1779 As a side-effect, the byte value read is stored. If the hardware was not
1780 ready for output or did not respond, the byte value is not stored.
1781
1782--*/
1783
1784{
1785 ULONG i;
1786 UCHAR response;
1787 UCHAR desiredMask;
1788
1789 I8xPrint((3, "I8042PRT-I8xGetByteAsynchronous: enter\n"));
1790
1791 if (DeviceType == KeyboardDeviceType) {
1792 I8xPrint((3, "I8042PRT-I8xGetByteAsynchronous: keyboard\n"));
1793 } else if (DeviceType == MouseDeviceType) {
1794 I8xPrint((3, "I8042PRT-I8xGetByteAsynchronous: mouse\n"));
1795 } else {
1796 I8xPrint((3, "I8042PRT-I8xGetByteAsynchronous: 8042 controller\n"));
1797 }
1798
1799 i = 0;
1800 desiredMask = (DeviceType == MouseDeviceType)?
1801 (UCHAR) (OUTPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL):
1802 (UCHAR) OUTPUT_BUFFER_FULL;
1803
1804 //
1805 // Poll until we get back a controller status value that indicates
1806 // the output buffer is full. If we want to read a byte from the mouse,
1807 // further ensure that the auxiliary device output buffer full bit is
1808 // set.
1809 //
1810
1811 while ((i < (ULONG)DeviceExtension->Configuration.PollingIterations) &&
1812 ((UCHAR)((response =
1813 I8X_GET_STATUS_BYTE(DeviceExtension->DeviceRegisters[CommandPort]))
1814 & desiredMask) != desiredMask)) {
1815
1816 if (response & OUTPUT_BUFFER_FULL) {
1817
1818 //
1819 // There is something in the i8042 output buffer, but it
1820 // isn't from the device we want to get a byte from. Eat
1821 // the byte and try again.
1822 //
1823
1824 *Byte = I8X_GET_DATA_BYTE(DeviceExtension->DeviceRegisters[DataPort]);
1825 I8xPrint((2, "I8042PRT-I8xGetByteAsynchronous: ate 0x%x\n", *Byte));
1826 } else {
1827
1828 //
1829 // Try again.
1830 //
1831
1832 i += 1;
1833
1834 I8xPrint((
1835 2,
1836 "I8042PRT-I8xGetByteAsynchronous: wait for correct status\n"
1837 ));
1838 }
1839
1840 }
1841 if (i >= (ULONG)DeviceExtension->Configuration.PollingIterations) {
1842 I8xPrint((2, "I8042PRT-I8xGetByteAsynchronous: timing out\n"));
1843 return;
1844 }
1845
1846 //
1847 // Grab the byte from the hardware.
1848 //
1849
1850 *Byte = I8X_GET_DATA_BYTE(DeviceExtension->DeviceRegisters[DataPort]);
1851
1852 I8xPrint((
1853 3,
1854 "I8042PRT-I8xGetByteAsynchronous: exit with Byte 0x%x\n", *Byte
1855 ));
1856
1857}
1858
1859
1860NTSTATUS
1861I8xGetBytePolled(
1862 IN CCHAR DeviceType,
1863 IN PDEVICE_EXTENSION DeviceExtension,
1864 OUT PUCHAR Byte
1865 )
1866
1867/*++
1868
1869Routine Description:
1870
1871 This routine reads a data byte from the controller or keyboard
1872 or mouse, in polling mode.
1873
1874Arguments:
1875
1876 DeviceType - Specifies which device (i8042 controller, keyboard, or
1877 mouse) to read the byte from.
1878
1879 DeviceExtension - Pointer to the device extension.
1880
1881 Byte - Pointer to the location to store the byte read from the hardware.
1882
1883Return Value:
1884
1885 STATUS_IO_TIMEOUT - The hardware was not ready for output or did not
1886 respond.
1887
1888 STATUS_SUCCESS - The byte was successfully read from the hardware.
1889
1890 As a side-effect, the byte value read is stored.
1891
1892--*/
1893
1894{
1895 ULONG i;
1896 UCHAR response;
1897 UCHAR desiredMask;
1898
1899 I8xPrint((3, "I8042PRT-I8xGetBytePolled: enter\n"));
1900
1901 if (DeviceType == KeyboardDeviceType) {
1902 I8xPrint((3, "I8042PRT-I8xGetBytePolled: keyboard\n"));
1903 } else if (DeviceType == MouseDeviceType) {
1904 I8xPrint((3, "I8042PRT-I8xGetBytePolled: mouse\n"));
1905 } else {
1906 I8xPrint((3, "I8042PRT-I8xGetBytePolled: 8042 controller\n"));
1907 }
1908
1909 i = 0;
1910 desiredMask = (DeviceType == MouseDeviceType)?
1911 (UCHAR) (OUTPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL):
1912 (UCHAR) OUTPUT_BUFFER_FULL;
1913
1914
1915 //
1916 // Poll until we get back a controller status value that indicates
1917 // the output buffer is full. If we want to read a byte from the mouse,
1918 // further ensure that the auxiliary device output buffer full bit is
1919 // set.
1920 //
1921
1922 while ((i < (ULONG)DeviceExtension->Configuration.PollingIterations) &&
1923 ((UCHAR)((response =
1924 I8X_GET_STATUS_BYTE(DeviceExtension->DeviceRegisters[CommandPort]))
1925 & desiredMask) != desiredMask)) {
1926 if (response & OUTPUT_BUFFER_FULL) {
1927
1928 //
1929 // There is something in the i8042 output buffer, but it
1930 // isn't from the device we want to get a byte from. Eat
1931 // the byte and try again.
1932 //
1933
1934 *Byte = I8X_GET_DATA_BYTE(DeviceExtension->DeviceRegisters[DataPort]);
1935 I8xPrint((2, "I8042PRT-I8xGetBytePolled: ate 0x%x\n", *Byte));
1936 } else {
1937 I8xPrint((2, "I8042PRT-I8xGetBytePolled: stalling\n"));
1938 KeStallExecutionProcessor(
1939 DeviceExtension->Configuration.StallMicroseconds
1940 );
1941 i += 1;
1942 }
1943 }
1944 if (i >= (ULONG)DeviceExtension->Configuration.PollingIterations) {
1945 I8xPrint((2, "I8042PRT-I8xGetBytePolled: timing out\n"));
1946 return(STATUS_IO_TIMEOUT);
1947 }
1948
1949 //
1950 // Grab the byte from the hardware, and return success.
1951 //
1952
1953 *Byte = I8X_GET_DATA_BYTE(DeviceExtension->DeviceRegisters[DataPort]);
1954
1955 I8xPrint((3, "I8042PRT-I8xGetBytePolled: exit with Byte 0x%x\n", *Byte));
1956
1957 return(STATUS_SUCCESS);
1958
1959}
1960
1961
1962NTSTATUS
1963I8xGetControllerCommand(
1964 IN ULONG HardwareDisableEnableMask,
1965 IN PDEVICE_EXTENSION DeviceExtension,
1966 OUT PUCHAR Byte
1967 )
1968
1969/*++
1970
1971Routine Description:
1972
1973 This routine reads the 8042 Controller Command Byte.
1974
1975Arguments:
1976
1977 HardwareDisableEnableMask - Specifies which hardware devices, if any,
1978 need to be disabled/enable around the operation.
1979
1980 DeviceExtension - Pointer to the device extension.
1981
1982 Byte - Pointer to the location into which the Controller Command Byte is
1983 read.
1984
1985Return Value:
1986
1987 Status is returned.
1988
1989--*/
1990
1991{
1992 NTSTATUS status;
1993 NTSTATUS secondStatus;
1994 ULONG retryCount;
1995
1996 I8xPrint((3, "I8042PRT-I8xGetControllerCommand: enter\n"));
1997
1998 //
1999 // Disable the specified devices before sending the command to
2000 // read the Controller Command Byte (otherwise data in the output
2001 // buffer might get trashed).
2002 //
2003
2004 if (HardwareDisableEnableMask & KEYBOARD_HARDWARE_PRESENT) {
2005 status = I8xPutBytePolled(
2006 (CCHAR) CommandPort,
2007 NO_WAIT_FOR_ACKNOWLEDGE,
2008 (CCHAR) UndefinedDeviceType,
2009 DeviceExtension,
2010 (UCHAR) I8042_DISABLE_KEYBOARD_DEVICE
2011 );
2012 if (!NT_SUCCESS(status)) {
2013 return(status);
2014 }
2015 }
2016
2017 if (HardwareDisableEnableMask & MOUSE_HARDWARE_PRESENT) {
2018 status = I8xPutBytePolled(
2019 (CCHAR) CommandPort,
2020 NO_WAIT_FOR_ACKNOWLEDGE,
2021 (CCHAR) UndefinedDeviceType,
2022 DeviceExtension,
2023 (UCHAR) I8042_DISABLE_MOUSE_DEVICE
2024 );
2025 if (!NT_SUCCESS(status)) {
2026
2027 //
2028 // Re-enable the keyboard device, if necessary, before returning.
2029 //
2030
2031 if (HardwareDisableEnableMask & KEYBOARD_HARDWARE_PRESENT) {
2032 secondStatus = I8xPutBytePolled(
2033 (CCHAR) CommandPort,
2034 NO_WAIT_FOR_ACKNOWLEDGE,
2035 (CCHAR) UndefinedDeviceType,
2036 DeviceExtension,
2037 (UCHAR) I8042_ENABLE_KEYBOARD_DEVICE
2038 );
2039 }
2040 return(status);
2041 }
2042 }
2043
2044 //
2045 // Send a command to the i8042 controller to read the Controller
2046 // Command Byte.
2047 //
2048
2049 status = I8xPutBytePolled(
2050 (CCHAR) CommandPort,
2051 NO_WAIT_FOR_ACKNOWLEDGE,
2052 (CCHAR) UndefinedDeviceType,
2053 DeviceExtension,
2054 (UCHAR) I8042_READ_CONTROLLER_COMMAND_BYTE
2055 );
2056
2057 //
2058 // Read the byte from the i8042 data port.
2059 //
2060
2061 if (NT_SUCCESS(status)) {
2062 for (retryCount = 0; retryCount < 5; retryCount++) {
2063 status = I8xGetBytePolled(
2064 (CCHAR) ControllerDeviceType,
2065 DeviceExtension,
2066 Byte
2067 );
2068 if (NT_SUCCESS(status)) {
2069 break;
2070 }
2071 if (status == STATUS_IO_TIMEOUT) {
2072 KeStallExecutionProcessor(50);
2073 } else {
2074 break;
2075 }
2076 }
2077 }
2078
2079 //
2080 // Re-enable the specified devices. Clear the device disable
2081 // bits in the Controller Command Byte by hand (they got set when
2082 // we disabled the devices, so the CCB we read lacked the real
2083 // device disable bit information).
2084 //
2085
2086 if (HardwareDisableEnableMask & KEYBOARD_HARDWARE_PRESENT) {
2087 secondStatus = I8xPutBytePolled(
2088 (CCHAR) CommandPort,
2089 NO_WAIT_FOR_ACKNOWLEDGE,
2090 (CCHAR) UndefinedDeviceType,
2091 DeviceExtension,
2092 (UCHAR) I8042_ENABLE_KEYBOARD_DEVICE
2093 );
2094 if (!NT_SUCCESS(secondStatus)) {
2095 if (NT_SUCCESS(status))
2096 status = secondStatus;
2097 } else if (status == STATUS_SUCCESS) {
2098 *Byte &= (UCHAR) ~CCB_DISABLE_KEYBOARD_DEVICE;
2099 }
2100
2101 }
2102
2103 if (HardwareDisableEnableMask & MOUSE_HARDWARE_PRESENT) {
2104 secondStatus = I8xPutBytePolled(
2105 (CCHAR) CommandPort,
2106 NO_WAIT_FOR_ACKNOWLEDGE,
2107 (CCHAR) UndefinedDeviceType,
2108 DeviceExtension,
2109 (UCHAR) I8042_ENABLE_MOUSE_DEVICE
2110 );
2111 if (!NT_SUCCESS(secondStatus)) {
2112 if (NT_SUCCESS(status))
2113 status = secondStatus;
2114 } else if (NT_SUCCESS(status)) {
2115 *Byte &= (UCHAR) ~CCB_DISABLE_MOUSE_DEVICE;
2116 }
2117 }
2118
2119 I8xPrint((3, "I8042PRT-I8xGetControllerCommand: exit\n"));
2120
2121 return(status);
2122
2123}
2124
2125
2126VOID
2127I8xInitializeHardware(
2128 IN PDEVICE_OBJECT DeviceObject
2129 )
2130
2131/*++
2132
2133Routine Description:
2134
2135 This routine initializes the i8042 controller, keyboard, and mouse.
2136 Note that it is only called at initialization time. This routine
2137 does not need to synchronize access to the hardware, or synchronize
2138 with the ISRs (they aren't connected yet).
2139
2140Arguments:
2141
2142 DeviceObject - Pointer to the device object.
2143
2144Return Value:
2145
2146 None. As a side-effect, however, DeviceExtension->HardwarePresent is set.
2147
2148--*/
2149
2150{
2151 PDEVICE_EXTENSION deviceExtension;
2152 NTSTATUS status;
2153 I8042_TRANSMIT_CCB_CONTEXT transmitCCBContext;
2154 PUCHAR dataAddress, commandAddress;
2155
2156 I8xPrint((2, "I8042PRT-I8xInitializeHardware: enter\n"));
2157
2158 //
2159 // Grab useful configuration parameters from the device extension.
2160 //
2161
2162 deviceExtension = DeviceObject->DeviceExtension;
2163 dataAddress = deviceExtension->DeviceRegisters[DataPort];
2164 commandAddress = deviceExtension->DeviceRegisters[CommandPort];
2165
2166 //
2167 // Drain the i8042 output buffer to get rid of stale data.
2168 //
2169
2170 I8xDrainOutputBuffer(dataAddress, commandAddress);
2171
2172 //
2173 // Disable interrupts from the keyboard and mouse. Read the Controller
2174 // Command Byte, turn off the keyboard and auxiliary interrupt enable
2175 // bits, and rewrite the Controller Command Byte.
2176 //
2177
2178 transmitCCBContext.HardwareDisableEnableMask = 0;
2179 transmitCCBContext.AndOperation = AND_OPERATION;
2180 transmitCCBContext.ByteMask = (UCHAR)
2181 ~((UCHAR) CCB_ENABLE_KEYBOARD_INTERRUPT |
2182 (UCHAR) CCB_ENABLE_MOUSE_INTERRUPT);
2183
2184 I8xTransmitControllerCommand(deviceExtension, (PVOID) &transmitCCBContext);
2185
2186 if (!NT_SUCCESS(transmitCCBContext.Status)) {
2187 I8xPrint((
2188 1,
2189 "I8042PRT-I8xInitializeHardware: failed to disable interrupts, status 0x%x\n",
2190 transmitCCBContext.Status
2191 ));
2192
2193 return;
2194 }
2195
2196 if ((deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT) == 0) {
2197 I8xPrint((
2198 1,
2199 "I8042PRT-I8xInitializeHardware: no mouse present\n"
2200 ));
2201 }
2202
2203 if ((deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) == 0) {
2204 I8xPrint((
2205 1,
2206 "I8042PRT-I8xInitializeHardware: no keyboard present\n"
2207 ));
2208 }
2209
2210
2211 //
2212 // Disable the keyboard and mouse devices.
2213 //
2214
2215#if 0
2216 //
2217 // NOTE: This is supposedly the "correct" thing to do. However,
2218 // disabling the keyboard device here causes the AMI rev K8 machines
2219 // (e.g., some Northgates) to fail some commands (e.g., the READID
2220 // command).
2221 //
2222
2223 status = I8xPutBytePolled(
2224 (CCHAR) CommandPort,
2225 NO_WAIT_FOR_ACKNOWLEDGE,
2226 (CCHAR) UndefinedDeviceType,
2227 deviceExtension,
2228 (UCHAR) I8042_DISABLE_KEYBOARD_DEVICE
2229 );
2230 if (!NT_SUCCESS(status)) {
2231 I8xPrint((
2232 1,
2233 "I8042PRT-I8xInitializeHardware: failed kbd disable, status 0x%x\n",
2234 status
2235 ));
2236 deviceExtension->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2237 }
2238#endif
2239
2240
2241#if 0
2242 //
2243 // NOTE: This is supposedly the "correct thing to do. However,
2244 // disabling the mouse on RadiSys EPC-24 which uses VLSI part number
2245 // VL82C144 (3751E) causes the part to shut down keyboard interrupts.
2246 //
2247
2248 status = I8xPutBytePolled(
2249 (CCHAR) CommandPort,
2250 NO_WAIT_FOR_ACKNOWLEDGE,
2251 (CCHAR) UndefinedDeviceType,
2252 deviceExtension,
2253 (UCHAR) I8042_DISABLE_MOUSE_DEVICE
2254 );
2255 if (!NT_SUCCESS(status)) {
2256 I8xPrint((
2257 1,
2258 "I8042PRT-I8xInitializeHardware: failed mou disable, status 0x%x\n",
2259 status
2260 ));
2261
2262 deviceExtension->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
2263 }
2264#endif
2265
2266 //
2267 // Drain the i8042 output buffer to get rid of stale data that could
2268 // come in sometime between the previous drain and the time the devices
2269 // are disabled.
2270 //
2271
2272 I8xDrainOutputBuffer(dataAddress, commandAddress);
2273
2274 //
2275 // Setup the mouse hardware. This consists of resetting the mouse and
2276 // then setting the mouse sample rate.
2277 //
2278
2279 if (deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT) {
2280 status = I8xInitializeMouse(DeviceObject);
2281 if (!NT_SUCCESS(status)) {
2282 I8xPrint((
2283 1,
2284 "I8042PRT-I8xInitializeHardware: failed mou init, status 0x%x\n",
2285 status
2286 ));
2287 deviceExtension->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
2288 }
2289 }
2290
2291 //
2292 // Setup the keyboard hardware.
2293 //
2294
2295 if (deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) {
2296 status = I8xInitializeKeyboard(DeviceObject);
2297 if (!NT_SUCCESS(status)) {
2298 I8xPrint((
2299 0,
2300 "I8042PRT-I8xInitializeHardware: failed kbd init, status 0x%x\n",
2301 status
2302 ));
2303
2304#if defined(JAPAN) && defined(i386)
2305//Fujitsu Aug.23.1994
2306// To realize "keyboard-less system" needs to make look like connecting
2307// keybaord hardware, as this routine, if not connect.
2308
2309 if ( status == STATUS_IO_TIMEOUT ) {
2310 deviceExtension->HardwarePresent |= KEYBOARD_HARDWARE_PRESENT;
2311 }else{
2312 deviceExtension->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2313 }
2314#else
2315 deviceExtension->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2316#endif
2317 }
2318 }
2319
2320 //
2321 // Enable the keyboard and mouse devices and their interrupts. Note
2322 // that it is required that this operation happen during intialization
2323 // time, because the i8042 Output Buffer Full bit gets set in the
2324 // Controller Command Byte when the keyboard/mouse is used, even if
2325 // the device is disabled. Hence, we cannot successfully perform
2326 // the enable operation later (e.g., when processing
2327 // IOCTL_INTERNAL_*_ENABLE), because we can't guarantee that
2328 // I8xPutBytePolled() won't time out waiting for the Output Buffer Full
2329 // bit to clear, even if we drain the output buffer (because the user
2330 // could be playing with the mouse/keyboard, and continuing to set the
2331 // OBF bit). KeyboardEnableCount and MouseEnableCount remain zero until
2332 // their respective IOCTL_INTERNAL_*_ENABLE call succeeds, so the ISR
2333 // ignores the unexpected interrupts.
2334 //
2335
2336 //
2337 // Re-enable the keyboard device in the Controller Command Byte.
2338 // Note that some of the keyboards will send an ACK back, while
2339 // others don't. Don't wait for an ACK, but do drain the output
2340 // buffer afterwards so that an unexpected ACK doesn't screw up
2341 // successive PutByte operations.
2342
2343 if (deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) {
2344 status = I8xPutBytePolled(
2345 (CCHAR) CommandPort,
2346 NO_WAIT_FOR_ACKNOWLEDGE,
2347 (CCHAR) UndefinedDeviceType,
2348 deviceExtension,
2349 (UCHAR) I8042_ENABLE_KEYBOARD_DEVICE
2350 );
2351 if (!NT_SUCCESS(status)) {
2352 I8xPrint((
2353 1,
2354 "I8042PRT-I8xInitializeHardware: failed kbd re-enable, status 0x%x\n",
2355 status
2356 ));
2357 deviceExtension->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2358 }
2359
2360 I8xDrainOutputBuffer(dataAddress, commandAddress);
2361 }
2362
2363
2364 //
2365 // Re-enable the mouse device in the Controller Command Byte.
2366 //
2367
2368 if (deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT) {
2369 status = I8xPutBytePolled(
2370 (CCHAR) CommandPort,
2371 NO_WAIT_FOR_ACKNOWLEDGE,
2372 (CCHAR) UndefinedDeviceType,
2373 deviceExtension,
2374 (UCHAR) I8042_ENABLE_MOUSE_DEVICE
2375 );
2376 if (!NT_SUCCESS(status)) {
2377 I8xPrint((
2378 1,
2379 "I8042PRT-I8xInitializeHardware: failed mou re-enable, status 0x%x\n",
2380 status
2381 ));
2382 deviceExtension->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
2383 }
2384 I8xDrainOutputBuffer(dataAddress, commandAddress);
2385 }
2386
2387 //
2388 // Re-enable interrupts in the Controller Command Byte.
2389 //
2390
2391 if (deviceExtension->HardwarePresent) {
2392 transmitCCBContext.HardwareDisableEnableMask =
2393 deviceExtension->HardwarePresent;
2394 transmitCCBContext.AndOperation = OR_OPERATION;
2395 transmitCCBContext.ByteMask =
2396 (deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) ?
2397 CCB_ENABLE_KEYBOARD_INTERRUPT : 0;
2398 transmitCCBContext.ByteMask |= (UCHAR)
2399 (deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT) ?
2400 CCB_ENABLE_MOUSE_INTERRUPT : 0;
2401
2402 I8xTransmitControllerCommand(
2403 deviceExtension,
2404 (PVOID) &transmitCCBContext
2405 );
2406
2407 if (!NT_SUCCESS(transmitCCBContext.Status)) {
2408 I8xPrint((
2409 1,
2410 "I8042PRT-I8xInitializeHardware: failed to re-enable interrupts, status 0x%x\n",
2411 transmitCCBContext.Status
2412 ));
2413
2414 //
2415 // We have the option here of resetting HardwarePresent to zero,
2416 // which will cause the driver to fail its initialization and
2417 // unload. Instead, we allow initialization to continue in
2418 // the hope that the command to re-enable interrupts was
2419 // successful at the hardware level (i.e., things will work),
2420 // even though the hardware response indicates otherwise.
2421 //
2422 }
2423 }
2424
2425 I8xPrint((2, "I8042PRT-I8xInitializeHardware: exit\n"));
2426
2427 return;
2428
2429}
2430
2431
2432VOID
2433I8xPutByteAsynchronous(
2434 IN CCHAR PortType,
2435 IN PDEVICE_EXTENSION DeviceExtension,
2436 IN UCHAR Byte
2437 )
2438
2439/*++
2440
2441Routine Description:
2442
2443 This routine sends a command or data byte to the controller or keyboard
2444 or mouse, asynchronously. It does not wait for acknowledgment.
2445 If the hardware was not ready for input, the byte is not sent.
2446
2447Arguments:
2448
2449 PortType - If CommandPort, send the byte to the command register,
2450 otherwise send it to the data register.
2451
2452 DeviceExtension - Pointer to the device extension.
2453
2454 Byte - The byte to send to the hardware.
2455
2456Return Value:
2457
2458 None.
2459
2460--*/
2461
2462{
2463 ULONG i;
2464
2465 I8xPrint((3, "I8042PRT-I8xPutByteAsynchronous: enter\n"));
2466
2467 //
2468 // Make sure the Input Buffer Full controller status bit is clear.
2469 // Time out if necessary.
2470 //
2471
2472 i = 0;
2473 while ((i++ < (ULONG)DeviceExtension->Configuration.PollingIterations) &&
2474 (I8X_GET_STATUS_BYTE(DeviceExtension->DeviceRegisters[CommandPort])
2475 & INPUT_BUFFER_FULL)) {
2476
2477 //
2478 // Do nothing.
2479 //
2480
2481 I8xPrint((
2482 3,
2483 "I8042PRT-I8xPutByteAsynchronous: wait for IBF and OBF to clear\n"
2484 ));
2485
2486 }
2487 if (i >= (ULONG)DeviceExtension->Configuration.PollingIterations) {
2488 I8xPrint((
2489 3,
2490 "I8042PRT-I8xPutByteAsynchronous: exceeded number of retries\n"
2491 ));
2492 return;
2493 }
2494
2495 //
2496 // Send the byte to the appropriate (command/data) hardware register.
2497 //
2498
2499 if (PortType == CommandPort) {
2500 I8xPrint((
2501 3,
2502 "I8042PRT-I8xPutByteAsynchronous: sending 0x%x to command port\n",
2503 Byte
2504 ));
2505 I8X_PUT_COMMAND_BYTE(DeviceExtension->DeviceRegisters[CommandPort], Byte);
2506 } else {
2507 I8xPrint((
2508 3,
2509 "I8042PRT-I8xPutByteAsynchronous: sending 0x%x to data port\n",
2510 Byte
2511 ));
2512 I8X_PUT_DATA_BYTE(DeviceExtension->DeviceRegisters[DataPort], Byte);
2513 }
2514
2515 I8xPrint((3, "I8042PRT-I8xPutByteAsynchronous: exit\n"));
2516
2517}
2518
2519
2520NTSTATUS
2521I8xPutBytePolled(
2522 IN CCHAR PortType,
2523 IN BOOLEAN WaitForAcknowledge,
2524 IN CCHAR AckDeviceType,
2525 IN PDEVICE_EXTENSION DeviceExtension,
2526 IN UCHAR Byte
2527 )
2528
2529/*++
2530
2531Routine Description:
2532
2533 This routine sends a command or data byte to the controller or keyboard
2534 or mouse, in polling mode. It waits for acknowledgment and resends
2535 the command/data if necessary.
2536
2537Arguments:
2538
2539 PortType - If CommandPort, send the byte to the command register,
2540 otherwise send it to the data register.
2541
2542 WaitForAcknowledge - If true, wait for an ACK back from the hardware.
2543
2544 AckDeviceType - Indicates which device we expect to get the ACK back
2545 from.
2546
2547 DeviceExtension - Pointer to the device extension.
2548
2549 Byte - The byte to send to the hardware.
2550
2551Return Value:
2552
2553 STATUS_IO_TIMEOUT - The hardware was not ready for input or did not
2554 respond.
2555
2556 STATUS_SUCCESS - The byte was successfully sent to the hardware.
2557
2558--*/
2559
2560{
2561 ULONG i,j;
2562 UCHAR response;
2563 NTSTATUS status;
2564 BOOLEAN keepTrying;
2565 PUCHAR dataAddress, commandAddress;
2566
2567 I8xPrint((3, "I8042PRT-I8xPutBytePolled: enter\n"));
2568
2569 if (AckDeviceType == MouseDeviceType) {
2570
2571 //
2572 // We need to precede a PutByte for the mouse device with
2573 // a PutByte that tells the controller that the next byte
2574 // sent to the controller should go to the auxiliary device
2575 // (by default it would go to the keyboard device). We
2576 // do this by calling I8xPutBytePolled recursively to send
2577 // the "send next byte to auxiliary device" command
2578 // before sending the intended byte to the mouse. Note that
2579 // there is only one level of recursion, since the AckDeviceType
2580 // for the recursive call is guaranteed to be UndefinedDeviceType,
2581 // and hence this IF statement will evaluate to FALSE.
2582 //
2583
2584 I8xPutBytePolled(
2585 (CCHAR) CommandPort,
2586 NO_WAIT_FOR_ACKNOWLEDGE,
2587 (CCHAR) UndefinedDeviceType,
2588 DeviceExtension,
2589 (UCHAR) I8042_WRITE_TO_AUXILIARY_DEVICE
2590 );
2591 }
2592
2593 dataAddress = DeviceExtension->DeviceRegisters[DataPort];
2594 commandAddress = DeviceExtension->DeviceRegisters[CommandPort];
2595
2596 for (j=0;j < (ULONG)DeviceExtension->Configuration.ResendIterations;j++) {
2597
2598 //
2599 // Make sure the Input Buffer Full controller status bit is clear.
2600 // Time out if necessary.
2601 //
2602
2603 i = 0;
2604 while ((i++ < (ULONG)DeviceExtension->Configuration.PollingIterations)
2605 && (I8X_GET_STATUS_BYTE(commandAddress) & INPUT_BUFFER_FULL)) {
2606 I8xPrint((2, "I8042PRT-I8xPutBytePolled: stalling\n"));
2607 KeStallExecutionProcessor(
2608 DeviceExtension->Configuration.StallMicroseconds
2609 );
2610 }
2611 if (i >= (ULONG)DeviceExtension->Configuration.PollingIterations) {
2612 I8xPrint((2, "I8042PRT-I8xPutBytePolled: timing out\n"));
2613 status = STATUS_IO_TIMEOUT;
2614 break;
2615 }
2616
2617 //
2618 // Drain the i8042 output buffer to get rid of stale data.
2619 //
2620
2621 I8xDrainOutputBuffer(dataAddress, commandAddress);
2622
2623 //
2624 // Send the byte to the appropriate (command/data) hardware register.
2625 //
2626
2627 if (PortType == CommandPort) {
2628 I8xPrint((
2629 3,
2630 "I8042PRT-I8xPutBytePolled: sending 0x%x to command port\n",
2631 Byte
2632 ));
2633 I8X_PUT_COMMAND_BYTE(commandAddress, Byte);
2634 } else {
2635 I8xPrint((
2636 3,
2637 "I8042PRT-I8xPutBytePolled: sending 0x%x to data port\n",
2638 Byte
2639 ));
2640 I8X_PUT_DATA_BYTE(dataAddress, Byte);
2641 }
2642
2643 //
2644 // If we don't need to wait for an ACK back from the controller,
2645 // set the status and break out of the for loop.
2646 //
2647 //
2648
2649 if (WaitForAcknowledge == NO_WAIT_FOR_ACKNOWLEDGE) {
2650 status = STATUS_SUCCESS;
2651 break;
2652 }
2653
2654 //
2655 // Wait for an ACK back from the controller. If we get an ACK,
2656 // the operation was successful. If we get a RESEND, break out to
2657 // the for loop and try the operation again. Ignore anything other
2658 // than ACK or RESEND.
2659 //
2660
2661 I8xPrint((3, "I8042PRT-I8xPutBytePolled: waiting for ACK\n"));
2662 keepTrying = FALSE;
2663 while ((status = I8xGetBytePolled(
2664 AckDeviceType,
2665 DeviceExtension,
2666 &response
2667 )
2668 ) == STATUS_SUCCESS) {
2669
2670 if (response == ACKNOWLEDGE) {
2671 I8xPrint((3, "I8042PRT-I8xPutBytePolled: got ACK\n"));
2672 break;
2673 } else if (response == RESEND) {
2674 I8xPrint((3, "I8042PRT-I8xPutBytePolled: got RESEND\n"));
2675
2676 if (AckDeviceType == MouseDeviceType) {
2677
2678 //
2679 // We need to precede the "resent" PutByte for the
2680 // mouse device with a PutByte that tells the controller
2681 // that the next byte sent to the controller should go
2682 // to the auxiliary device (by default it would go to
2683 // the keyboard device). We do this by calling
2684 // I8xPutBytePolled recursively to send the "send next
2685 // byte to auxiliary device" command before resending
2686 // the byte to the mouse. Note that there is only one
2687 // level of recursion, since the AckDeviceType for the
2688 // recursive call is guaranteed to be UndefinedDeviceType.
2689 //
2690
2691 I8xPutBytePolled(
2692 (CCHAR) CommandPort,
2693 NO_WAIT_FOR_ACKNOWLEDGE,
2694 (CCHAR) UndefinedDeviceType,
2695 DeviceExtension,
2696 (UCHAR) I8042_WRITE_TO_AUXILIARY_DEVICE
2697 );
2698 }
2699
2700 keepTrying = TRUE;
2701 break;
2702 }
2703
2704 //
2705 // Ignore any other response, and keep trying.
2706 //
2707
2708 }
2709
2710 if (!keepTrying)
2711 break;
2712 }
2713
2714 //
2715 // Check to see if the number of allowable retries was exceeded.
2716 //
2717
2718 if (j >= (ULONG)DeviceExtension->Configuration.ResendIterations) {
2719 I8xPrint((
2720 2,
2721 "I8042PRT-I8xPutBytePolled: exceeded number of retries\n"
2722 ));
2723 status = STATUS_IO_TIMEOUT;
2724 }
2725
2726 I8xPrint((3, "I8042PRT-I8xPutBytePolled: exit\n"));
2727
2728 return(status);
2729}
2730
2731
2732NTSTATUS
2733I8xPutControllerCommand(
2734 IN PDEVICE_EXTENSION DeviceExtension,
2735 IN UCHAR Byte
2736 )
2737
2738/*++
2739
2740Routine Description:
2741
2742 This routine writes the 8042 Controller Command Byte.
2743
2744Arguments:
2745
2746 DeviceExtension - Pointer to the device extension.
2747
2748 Byte - The byte to store in the Controller Command Byte.
2749
2750Return Value:
2751
2752 Status is returned.
2753
2754--*/
2755
2756{
2757 NTSTATUS status;
2758
2759 I8xPrint((3, "I8042PRT-I8xPutControllerCommand: enter\n"));
2760
2761 //
2762 // Send a command to the i8042 controller to write the Controller
2763 // Command Byte.
2764 //
2765
2766 status = I8xPutBytePolled(
2767 (CCHAR) CommandPort,
2768 NO_WAIT_FOR_ACKNOWLEDGE,
2769 (CCHAR) UndefinedDeviceType,
2770 DeviceExtension,
2771 (UCHAR) I8042_WRITE_CONTROLLER_COMMAND_BYTE
2772 );
2773
2774 if (!NT_SUCCESS(status)) {
2775 return(status);
2776 }
2777
2778 //
2779 // Write the byte through the i8042 data port.
2780 //
2781
2782 I8xPrint((3, "I8042PRT-I8xPutControllerCommand: exit\n"));
2783
2784 return(I8xPutBytePolled(
2785 (CCHAR) DataPort,
2786 NO_WAIT_FOR_ACKNOWLEDGE,
2787 (CCHAR) UndefinedDeviceType,
2788 DeviceExtension,
2789 (UCHAR) Byte
2790 )
2791 );
2792}
2793
2794
2795VOID
2796I8xServiceParameters(
2797 IN PINIT_EXTENSION InitializationData,
2798 IN PUNICODE_STRING RegistryPath,
2799 IN PUNICODE_STRING KeyboardDeviceName,
2800 IN PUNICODE_STRING PointerDeviceName
2801 )
2802
2803/*++
2804
2805Routine Description:
2806
2807 This routine retrieves this driver's service parameters information
2808 from the registry.
2809
2810Arguments:
2811
2812 InitializationData - Pointer to the initialization data, including the
2813 the device extension.
2814
2815 RegistryPath - Pointer to the null-terminated Unicode name of the
2816 registry path for this driver.
2817
2818 KeyboardDeviceName - Pointer to the Unicode string that will receive
2819 the keyboard port device name.
2820
2821 PointerDeviceName - Pointer to the Unicode string that will receive
2822 the pointer port device name.
2823
2824Return Value:
2825
2826 None. As a side-effect, sets fields in DeviceExtension->Configuration.
2827
2828--*/
2829
2830{
2831 PI8042_CONFIGURATION_INFORMATION configuration;
2832 PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
2833 UNICODE_STRING parametersPath;
2834 USHORT defaultResendIterations = I8042_RESEND_DEFAULT;
2835 ULONG resendIterations = 0;
2836 USHORT defaultPollingIterations = I8042_POLLING_DEFAULT;
2837 ULONG pollingIterations = 0;
2838 USHORT defaultPollingIterationsMaximum = I8042_POLLING_MAXIMUM;
2839 ULONG pollingIterationsMaximum = 0;
2840 USHORT defaultPollStatusIterations = I8042_POLLING_DEFAULT;
2841 ULONG pollStatusIterations = 0;
2842 ULONG defaultDataQueueSize = DATA_QUEUE_SIZE;
2843 ULONG numberOfButtons = MOUSE_NUMBER_OF_BUTTONS;
2844 USHORT defaultNumberOfButtons = MOUSE_NUMBER_OF_BUTTONS;
2845 ULONG sampleRate = MOUSE_SAMPLE_RATE;
2846 USHORT defaultSampleRate = MOUSE_SAMPLE_RATE;
2847 ULONG mouseResolution = MOUSE_RESOLUTION;
2848 USHORT defaultMouseResolution = MOUSE_RESOLUTION;
2849 ULONG overrideKeyboardType = 0;
2850 ULONG invalidKeyboardType = 0;
2851 ULONG overrideKeyboardSubtype = (ULONG) -1;
2852 ULONG invalidKeyboardSubtype = (ULONG) -1;
2853 ULONG defaultSynchPacket100ns = MOUSE_SYNCH_PACKET_100NS;
2854 ULONG enableWheelDetection = 0;
2855 ULONG defaultEnableWheelDetection = 1;
2856 UNICODE_STRING defaultPointerName;
2857 UNICODE_STRING defaultKeyboardName;
2858 NTSTATUS status = STATUS_SUCCESS;
2859 PWSTR path = NULL;
2860 USHORT queries = 15;
2861
2862 configuration = &(InitializationData->DeviceExtension.Configuration);
2863 configuration->StallMicroseconds = I8042_STALL_DEFAULT;
2864 parametersPath.Buffer = NULL;
2865
2866 //
2867 // Registry path is already null-terminated, so just use it.
2868 //
2869
2870 path = RegistryPath->Buffer;
2871
2872 if (NT_SUCCESS(status)) {
2873
2874 //
2875 // Allocate the Rtl query table.
2876 //
2877
2878 parameters = ExAllocatePool(
2879 PagedPool,
2880 sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
2881 );
2882
2883 if (!parameters) {
2884
2885 I8xPrint((
2886 1,
2887 "I8042PRT-I8xServiceParameters: Couldn't allocate table for Rtl query to parameters for %ws\n",
2888 path
2889 ));
2890
2891 status = STATUS_UNSUCCESSFUL;
2892
2893 } else {
2894
2895 RtlZeroMemory(
2896 parameters,
2897 sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
2898 );
2899
2900 //
2901 // Form a path to this driver's Parameters subkey.
2902 //
2903
2904 RtlInitUnicodeString(
2905 &parametersPath,
2906 NULL
2907 );
2908
2909 parametersPath.MaximumLength = RegistryPath->Length +
2910 sizeof(L"\\Parameters");
2911
2912 parametersPath.Buffer = ExAllocatePool(
2913 PagedPool,
2914 parametersPath.MaximumLength
2915 );
2916
2917 if (!parametersPath.Buffer) {
2918
2919 I8xPrint((
2920 1,
2921 "I8042PRT-I8xServiceParameters: Couldn't allocate string for path to parameters for %ws\n",
2922 path
2923 ));
2924
2925 status = STATUS_UNSUCCESSFUL;
2926
2927 }
2928 }
2929 }
2930
2931 if (NT_SUCCESS(status)) {
2932
2933 //
2934 // Form the parameters path.
2935 //
2936
2937 RtlZeroMemory(
2938 parametersPath.Buffer,
2939 parametersPath.MaximumLength
2940 );
2941 RtlAppendUnicodeToString(
2942 &parametersPath,
2943 path
2944 );
2945 RtlAppendUnicodeToString(
2946 &parametersPath,
2947 L"\\Parameters"
2948 );
2949
2950 I8xPrint((
2951 1,
2952 "I8042PRT-I8xServiceParameters: parameters path is %ws\n",
2953 parametersPath.Buffer
2954 ));
2955
2956 //
2957 // Form the default port device names, in case they are not
2958 // specified in the registry.
2959 //
2960
2961 RtlInitUnicodeString(
2962 &defaultKeyboardName,
2963 DD_KEYBOARD_PORT_BASE_NAME_U
2964 );
2965 RtlInitUnicodeString(
2966 &defaultPointerName,
2967 DD_POINTER_PORT_BASE_NAME_U
2968 );
2969
2970 //
2971 // Gather all of the "user specified" information from
2972 // the registry.
2973 //
2974
2975 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2976 parameters[0].Name = L"ResendIterations";
2977 parameters[0].EntryContext = &resendIterations;
2978 parameters[0].DefaultType = REG_DWORD;
2979 parameters[0].DefaultData = &defaultResendIterations;
2980 parameters[0].DefaultLength = sizeof(USHORT);
2981
2982 parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2983 parameters[1].Name = L"PollingIterations";
2984 parameters[1].EntryContext = &pollingIterations;
2985 parameters[1].DefaultType = REG_DWORD;
2986 parameters[1].DefaultData = &defaultPollingIterations;
2987 parameters[1].DefaultLength = sizeof(USHORT);
2988
2989 parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
2990 parameters[2].Name = L"PollingIterationsMaximum";
2991 parameters[2].EntryContext = &pollingIterationsMaximum;
2992 parameters[2].DefaultType = REG_DWORD;
2993 parameters[2].DefaultData = &defaultPollingIterationsMaximum;
2994 parameters[2].DefaultLength = sizeof(USHORT);
2995
2996 parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
2997 parameters[3].Name = L"KeyboardDataQueueSize";
2998 parameters[3].EntryContext =
2999 &configuration->KeyboardAttributes.InputDataQueueLength;
3000 parameters[3].DefaultType = REG_DWORD;
3001 parameters[3].DefaultData = &defaultDataQueueSize;
3002 parameters[3].DefaultLength = sizeof(ULONG);
3003
3004 parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
3005 parameters[4].Name = L"MouseDataQueueSize";
3006 parameters[4].EntryContext =
3007 &configuration->MouseAttributes.InputDataQueueLength;
3008 parameters[4].DefaultType = REG_DWORD;
3009 parameters[4].DefaultData = &defaultDataQueueSize;
3010 parameters[4].DefaultLength = sizeof(ULONG);
3011
3012 parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
3013 parameters[5].Name = L"NumberOfButtons";
3014 parameters[5].EntryContext = &numberOfButtons;
3015 parameters[5].DefaultType = REG_DWORD;
3016 parameters[5].DefaultData = &defaultNumberOfButtons;
3017 parameters[5].DefaultLength = sizeof(USHORT);
3018
3019 parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
3020 parameters[6].Name = L"SampleRate";
3021 parameters[6].EntryContext = &sampleRate;
3022 parameters[6].DefaultType = REG_DWORD;
3023 parameters[6].DefaultData = &defaultSampleRate;
3024 parameters[6].DefaultLength = sizeof(USHORT);
3025
3026 parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
3027 parameters[7].Name = L"MouseResolution";
3028 parameters[7].EntryContext = &mouseResolution;
3029 parameters[7].DefaultType = REG_DWORD;
3030 parameters[7].DefaultData = &defaultMouseResolution;
3031 parameters[7].DefaultLength = sizeof(USHORT);
3032
3033 parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
3034 parameters[8].Name = L"OverrideKeyboardType";
3035 parameters[8].EntryContext = &overrideKeyboardType;
3036 parameters[8].DefaultType = REG_DWORD;
3037 parameters[8].DefaultData = &invalidKeyboardType;
3038 parameters[8].DefaultLength = sizeof(ULONG);
3039
3040 parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
3041 parameters[9].Name = L"OverrideKeyboardSubtype";
3042 parameters[9].EntryContext = &overrideKeyboardSubtype;
3043 parameters[9].DefaultType = REG_DWORD;
3044 parameters[9].DefaultData = &invalidKeyboardSubtype;
3045 parameters[9].DefaultLength = sizeof(ULONG);
3046
3047 parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT;
3048 parameters[10].Name = L"KeyboardDeviceBaseName";
3049 parameters[10].EntryContext = KeyboardDeviceName;
3050 parameters[10].DefaultType = REG_SZ;
3051 parameters[10].DefaultData = defaultKeyboardName.Buffer;
3052 parameters[10].DefaultLength = 0;
3053
3054 parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT;
3055 parameters[11].Name = L"PointerDeviceBaseName";
3056 parameters[11].EntryContext = PointerDeviceName;
3057 parameters[11].DefaultType = REG_SZ;
3058 parameters[11].DefaultData = defaultPointerName.Buffer;
3059 parameters[11].DefaultLength = 0;
3060
3061 parameters[12].Flags = RTL_QUERY_REGISTRY_DIRECT;
3062 parameters[12].Name = L"MouseSynchIn100ns";
3063 parameters[12].EntryContext =
3064 &(InitializationData->DeviceExtension.MouseExtension.SynchTickCount);
3065 parameters[12].DefaultType = REG_DWORD;
3066 parameters[12].DefaultData = &defaultSynchPacket100ns;
3067 parameters[12].DefaultLength = sizeof(ULONG);
3068
3069 parameters[13].Flags = RTL_QUERY_REGISTRY_DIRECT;
3070 parameters[13].Name = L"PollStatusIterations";
3071 parameters[13].EntryContext = &pollStatusIterations;
3072 parameters[13].DefaultType = REG_DWORD;
3073 parameters[13].DefaultData = &defaultPollStatusIterations;
3074 parameters[13].DefaultLength = sizeof(USHORT);
3075
3076 parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
3077 parameters[14].Name = L"EnableWheelDetection";
3078 parameters[14].EntryContext = &enableWheelDetection;
3079 parameters[14].DefaultType = REG_DWORD;
3080 parameters[14].DefaultData = &defaultEnableWheelDetection;
3081 parameters[14].DefaultLength = sizeof(ULONG);
3082
3083 status = RtlQueryRegistryValues(
3084 RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
3085 parametersPath.Buffer,
3086 parameters,
3087 NULL,
3088 NULL
3089 );
3090
3091 if (!NT_SUCCESS(status)) {
3092 I8xPrint((
3093 1,
3094 "I8042PRT-I8xServiceParameters: RtlQueryRegistryValues failed with 0x%x\n",
3095 status
3096 ));
3097 }
3098 }
3099
3100 if (!NT_SUCCESS(status)) {
3101
3102 //
3103 // Go ahead and assign driver defaults.
3104 //
3105
3106 configuration->ResendIterations = defaultResendIterations;
3107 configuration->PollingIterations = defaultPollingIterations;
3108 configuration->PollingIterationsMaximum =
3109 defaultPollingIterationsMaximum;
3110 configuration->PollStatusIterations = defaultPollStatusIterations;
3111 configuration->KeyboardAttributes.InputDataQueueLength =
3112 defaultDataQueueSize;
3113 configuration->MouseAttributes.InputDataQueueLength =
3114 defaultDataQueueSize;
3115 configuration->EnableWheelDetection =
3116 defaultEnableWheelDetection;
3117 InitializationData->DeviceExtension.MouseExtension.SynchTickCount =
3118 defaultSynchPacket100ns;
3119 RtlCopyUnicodeString(KeyboardDeviceName, &defaultKeyboardName);
3120 RtlCopyUnicodeString(PointerDeviceName, &defaultPointerName);
3121 } else {
3122 configuration->ResendIterations = (USHORT) resendIterations;
3123 configuration->PollingIterations = (USHORT) pollingIterations;
3124 configuration->PollingIterationsMaximum =
3125 (USHORT) pollingIterationsMaximum;
3126 configuration->PollStatusIterations = (USHORT) pollStatusIterations;
3127 configuration->EnableWheelDetection = (ULONG) ((enableWheelDetection) ? 1 : 0);
3128 }
3129
3130 I8xPrint((
3131 1,
3132 "I8042PRT-I8xServiceParameters: Keyboard port base name = %ws\n",
3133 KeyboardDeviceName->Buffer
3134 ));
3135
3136 I8xPrint((
3137 1,
3138 "I8042PRT-I8xServiceParameters: Pointer port base name = %ws\n",
3139 PointerDeviceName->Buffer
3140 ));
3141
3142 I8xPrint((
3143 1,
3144 "I8042PRT-I8xServiceParameters: StallMicroseconds = %d\n",
3145 configuration->StallMicroseconds
3146 ));
3147 I8xPrint((
3148 1,
3149 "I8042PRT-I8xServiceParameters: ResendIterations = %d\n",
3150 configuration->ResendIterations
3151 ));
3152 I8xPrint((
3153 1,
3154 "I8042PRT-I8xServiceParameters: PollingIterations = %d\n",
3155 configuration->PollingIterations
3156 ));
3157 I8xPrint((
3158 1,
3159 "I8042PRT-I8xServiceParameters: PollingIterationsMaximum = %d\n",
3160 configuration->PollingIterationsMaximum
3161 ));
3162 I8xPrint((
3163 1,
3164 "I8042PRT-I8xServiceParameters: PollStatusIterations = %d\n",
3165 configuration->PollStatusIterations
3166 ));
3167
3168 if (configuration->KeyboardAttributes.InputDataQueueLength == 0) {
3169
3170 I8xPrint((
3171 1,
3172 "I8042PRT-I8xServiceParameters: overriding KeyboardInputDataQueueLength = 0x%x\n",
3173 configuration->KeyboardAttributes.InputDataQueueLength
3174 ));
3175
3176 configuration->KeyboardAttributes.InputDataQueueLength =
3177 defaultDataQueueSize;
3178 }
3179
3180 configuration->KeyboardAttributes.InputDataQueueLength *=
3181 sizeof(KEYBOARD_INPUT_DATA);
3182
3183 I8xPrint((
3184 1,
3185 "I8042PRT-I8xServiceParameters: KeyboardInputDataQueueLength = 0x%x\n",
3186 configuration->KeyboardAttributes.InputDataQueueLength
3187 ));
3188
3189 if (configuration->MouseAttributes.InputDataQueueLength == 0) {
3190
3191 I8xPrint((
3192 1,
3193 "I8042PRT-I8xServiceParameters: overriding MouseInputDataQueueLength = 0x%x\n",
3194 configuration->MouseAttributes.InputDataQueueLength
3195 ));
3196
3197 configuration->MouseAttributes.InputDataQueueLength =
3198 defaultDataQueueSize;
3199 }
3200
3201 configuration->MouseAttributes.InputDataQueueLength *=
3202 sizeof(MOUSE_INPUT_DATA);
3203
3204 I8xPrint((
3205 1,
3206 "I8042PRT-I8xServiceParameters: MouseInputDataQueueLength = 0x%x\n",
3207 configuration->MouseAttributes.InputDataQueueLength
3208 ));
3209
3210 configuration->MouseAttributes.NumberOfButtons = (USHORT) numberOfButtons;
3211 I8xPrint((
3212 1,
3213 "I8042PRT-I8xServiceParameters: NumberOfButtons = %d\n",
3214 configuration->MouseAttributes.NumberOfButtons
3215 ));
3216
3217 configuration->MouseAttributes.SampleRate = (USHORT) sampleRate;
3218 I8xPrint((
3219 1,
3220 "I8042PRT-I8xServiceParameters: SampleRate = %d\n",
3221 configuration->MouseAttributes.SampleRate
3222 ));
3223
3224 configuration->MouseResolution = (USHORT) mouseResolution;
3225 I8xPrint((
3226 1,
3227 "I8042PRT-I8xServiceParameters: MouseResolution = %d\n",
3228 configuration->MouseResolution
3229 ));
3230
3231 if (overrideKeyboardType != invalidKeyboardType) {
3232 if (overrideKeyboardType <= NUM_KNOWN_KEYBOARD_TYPES) {
3233 I8xPrint((
3234 1,
3235 "I8042PRT-I8xServiceParameters: Override KeyboardType = %d\n",
3236 overrideKeyboardType
3237 ));
3238 configuration->KeyboardAttributes.KeyboardIdentifier.Type =
3239 (UCHAR) overrideKeyboardType;
3240 } else {
3241 I8xPrint((
3242 1,
3243 "I8042PRT-I8xServiceParameters: Invalid OverrideKeyboardType = %d\n",
3244 overrideKeyboardType
3245 ));
3246 }
3247 }
3248
3249 if (overrideKeyboardSubtype != invalidKeyboardSubtype) {
3250 I8xPrint((
3251 1,
3252 "I8042PRT-I8xServiceParameters: Override KeyboardSubtype = %d\n",
3253 overrideKeyboardSubtype
3254 ));
3255 configuration->KeyboardAttributes.KeyboardIdentifier.Subtype =
3256 (UCHAR) overrideKeyboardSubtype;
3257 }
3258
3259 if (InitializationData->DeviceExtension.MouseExtension.SynchTickCount == 0) {
3260
3261 I8xPrint((
3262 1,
3263 "I8042PRT-I8xServiceParameters: overriding MouseSynchIn100ns\n"
3264 ));
3265
3266 InitializationData->DeviceExtension.MouseExtension.SynchTickCount =
3267 defaultSynchPacket100ns;
3268 }
3269
3270 //
3271 // Convert SynchTickCount to be the number of interval timer
3272 // interrupts that occur during the time specified by MouseSynchIn100ns.
3273 // Note that KeQueryTimeIncrement returns the number of 100ns units that
3274 // are added to the system time each time the interval clock interrupts.
3275 //
3276
3277 InitializationData->DeviceExtension.MouseExtension.SynchTickCount /=
3278 KeQueryTimeIncrement();
3279
3280 I8xPrint((
3281 1,
3282 "I8042PRT-I8xServiceParameters: SynchTickCount = 0x%x\n",
3283 InitializationData->DeviceExtension.MouseExtension.SynchTickCount
3284 ));
3285
3286 I8xPrint((
3287 1,
3288 "I8042PRT-I8xServiceParameters: DisableWheelMouse = %#x\n",
3289 configuration->EnableWheelDetection
3290 ));
3291
3292 //
3293 // Free the allocated memory before returning.
3294 //
3295
3296 if (parametersPath.Buffer)
3297 ExFreePool(parametersPath.Buffer);
3298 if (parameters)
3299 ExFreePool(parameters);
3300
3301}
3302
3303
3304VOID
3305I8xTransmitControllerCommand(
3306 IN PDEVICE_EXTENSION DeviceExtension,
3307 IN PVOID Context
3308 )
3309
3310/*++
3311
3312Routine Description:
3313
3314 This routine reads the 8042 Controller Command Byte, performs an AND
3315 or OR operation using the specified ByteMask, and writes the resulting
3316 ControllerCommandByte.
3317
3318Arguments:
3319
3320 DeviceExtension - Pointer to the device extension.
3321
3322 Context - Pointer to a structure containing the HardwareDisableEnableMask,
3323 the AndOperation boolean, and the ByteMask to apply to the Controller
3324 Command Byte before it is rewritten.
3325
3326Return Value:
3327
3328 None. Status is returned in the Context structure.
3329
3330--*/
3331
3332{
3333 UCHAR controllerCommandByte;
3334 UCHAR verifyCommandByte;
3335 PI8042_TRANSMIT_CCB_CONTEXT transmitCCBContext;
3336 PIO_ERROR_LOG_PACKET errorLogEntry;
3337
3338 I8xPrint((3, "I8042PRT-I8xTransmitControllerCommand: enter\n"));
3339
3340 //
3341 // Grab the parameters from the Context structure.
3342 //
3343
3344 transmitCCBContext = (PI8042_TRANSMIT_CCB_CONTEXT) Context;
3345
3346 //
3347 // Get the current Controller Command Byte.
3348 //
3349
3350 transmitCCBContext->Status =
3351 I8xGetControllerCommand(
3352 transmitCCBContext->HardwareDisableEnableMask,
3353 DeviceExtension,
3354 &controllerCommandByte
3355 );
3356
3357 if (!NT_SUCCESS(transmitCCBContext->Status)) {
3358 return;
3359 }
3360
3361 I8xPrint((
3362 3,
3363 "I8042PRT-I8xTransmitControllerCommand: current CCB 0x%x\n",
3364 controllerCommandByte
3365 ));
3366
3367 //
3368 // Diddle the desired bits in the Controller Command Byte.
3369 //
3370
3371 if (transmitCCBContext->AndOperation)
3372 controllerCommandByte &= transmitCCBContext->ByteMask;
3373 else
3374 controllerCommandByte |= transmitCCBContext->ByteMask;
3375
3376 //
3377 // Write the new Controller Command Byte.
3378 //
3379
3380 transmitCCBContext->Status =
3381 I8xPutControllerCommand(DeviceExtension, controllerCommandByte);
3382
3383 I8xPrint((
3384 3,
3385 "I8042PRT-I8xTransmitControllerCommand: new CCB 0x%x\n",
3386 controllerCommandByte
3387 ));
3388
3389 //
3390 // Verify that the new Controller Command Byte really got written.
3391 //
3392
3393 transmitCCBContext->Status =
3394 I8xGetControllerCommand(
3395 transmitCCBContext->HardwareDisableEnableMask,
3396 DeviceExtension,
3397 &verifyCommandByte
3398 );
3399
3400 if (NT_SUCCESS(transmitCCBContext->Status)
3401 && (verifyCommandByte != controllerCommandByte)) {
3402 transmitCCBContext->Status = STATUS_DEVICE_DATA_ERROR;
3403
3404 //
3405 // Log an error.
3406 //
3407
3408 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
3409 DeviceExtension->DeviceObject,
3410 sizeof(IO_ERROR_LOG_PACKET)
3411 + (4 * sizeof(ULONG))
3412 );
3413 if (errorLogEntry != NULL) {
3414
3415 errorLogEntry->ErrorCode = I8042_CCB_WRITE_FAILED;
3416 errorLogEntry->DumpDataSize = 4 * sizeof(ULONG);
3417 errorLogEntry->SequenceNumber = 0;
3418 errorLogEntry->MajorFunctionCode = 0;
3419 errorLogEntry->IoControlCode = 0;
3420 errorLogEntry->RetryCount = 0;
3421 errorLogEntry->UniqueErrorValue = 80;
3422 errorLogEntry->FinalStatus = transmitCCBContext->Status;
3423 errorLogEntry->DumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
3424 errorLogEntry->DumpData[1] = DataPort;
3425 errorLogEntry->DumpData[2] = I8042_WRITE_CONTROLLER_COMMAND_BYTE;
3426 errorLogEntry->DumpData[3] = controllerCommandByte;
3427
3428 IoWriteErrorLogEntry(errorLogEntry);
3429 }
3430
3431 }
3432
3433 I8xPrint((3, "I8042PRT-I8xTransmitControllerCommand: exit\n"));
3434
3435 return;
3436
3437}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette