VirtualBox

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

Last change on this file since 11822 was 4770, checked in by vboxsync, 17 years ago

Do not fail the i8042 guest driver init (NT guest), if VBoxGuest is not loaded.

  • 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 /* Continue working in non-VBox mode. */
1344 }
1345 else
1346 {
1347 VMMDevReqMouseStatus *req = NULL;
1348
1349 vboxRC = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
1350
1351 if (VBOX_SUCCESS(vboxRC))
1352 {
1353 /* Inform host that we support absolute */
1354 req->mouseFeatures = VBOXGUEST_MOUSE_GUEST_CAN_ABSOLUTE;
1355 req->pointerXPos = 0;
1356 req->pointerYPos = 0;
1357
1358 vboxRC = VbglGRPerform (&req->header);
1359
1360 if (VBOX_FAILURE(vboxRC) || VBOX_FAILURE(req->header.rc))
1361 {
1362 dprintf(("i8042prt::DriverEntry: ERROR communicating new mouse capabilities to VMMDev."
1363 "rc = %d, VMMDev rc = %Vrc\n", vboxRC, req->header.rc));
1364 }
1365 else
1366 {
1367 /* We will use the allocated request buffer in the ServiceCallback to GET mouse status. */
1368 req->header.requestType = VMMDevReq_GetMouseStatus;
1369 deviceExtension->reqIS = req;
1370 }
1371 }
1372 else
1373 {
1374 VbglTerminate ();
1375
1376 dprintf(("i8042prt::DriverEntry: could not allocate request buffer, rc = %Vrc\n", vboxRC));
1377 /* Continue working in non-VBox mode. */
1378 }
1379 }
1380// VBOX end
1381
1382 //
1383 // Set up the device driver entry points.
1384 //
1385
1386 DriverObject->DriverStartIo = I8042StartIo;
1387 DriverObject->MajorFunction[IRP_MJ_CREATE] = I8042OpenCloseDispatch;
1388 DriverObject->MajorFunction[IRP_MJ_CLOSE] = I8042OpenCloseDispatch;
1389 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] =
1390 I8042Flush;
1391 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
1392 I8042InternalDeviceControl;
1393 //
1394 // NOTE: Don't allow this driver to unload. Otherwise, we would set
1395 // DriverObject->DriverUnload = I8042Unload.
1396 //
1397
1398I8042InitializeExit:
1399
1400 if (errorCode != STATUS_SUCCESS) {
1401
1402 //
1403 // Log an error/warning message.
1404 //
1405
1406 errorLogEntry = (PIO_ERROR_LOG_PACKET)
1407 IoAllocateErrorLogEntry(
1408 (portDeviceObject == NULL) ?
1409 (PVOID) DriverObject : (PVOID) portDeviceObject,
1410 (UCHAR) (sizeof(IO_ERROR_LOG_PACKET)
1411 + (dumpCount * sizeof(ULONG)))
1412 );
1413
1414 if (errorLogEntry != NULL) {
1415
1416 errorLogEntry->ErrorCode = errorCode;
1417 errorLogEntry->DumpDataSize = (USHORT) dumpCount * sizeof(ULONG);
1418 errorLogEntry->SequenceNumber = 0;
1419 errorLogEntry->MajorFunctionCode = 0;
1420 errorLogEntry->IoControlCode = 0;
1421 errorLogEntry->RetryCount = 0;
1422 errorLogEntry->UniqueErrorValue = uniqueErrorValue;
1423 errorLogEntry->FinalStatus = status;
1424 for (i = 0; i < dumpCount; i++)
1425 errorLogEntry->DumpData[i] = dumpData[i];
1426
1427 IoWriteErrorLogEntry(errorLogEntry);
1428 }
1429 }
1430
1431 if (!NT_SUCCESS(status)) {
1432
1433 //
1434 // The initialization failed. Cleanup resources before exiting.
1435 //
1436 // N.B. It is okay to disconnect the interrupt even if it never
1437 // got connected.
1438 //
1439
1440 //
1441 // Note: No need/way to undo the KeInitializeDpc or
1442 // KeInitializeTimer calls.
1443 //
1444
1445 //
1446 // The initialization failed. Cleanup resources before exiting.
1447 //
1448
1449 if (resources) {
1450
1451 //
1452 // Call IoReportResourceUsage to remove the resources from
1453 // the map.
1454 //
1455
1456 resources->Count = 0;
1457
1458 IoReportResourceUsage(
1459 &resourceDeviceClass,
1460 DriverObject,
1461 NULL,
1462 0,
1463 portDeviceObject,
1464 resources,
1465 resourceListSize,
1466 FALSE,
1467 &conflictDetected
1468 );
1469
1470 }
1471
1472 if (deviceExtension) {
1473 if (deviceExtension->KeyboardInterruptObject != NULL)
1474 IoDisconnectInterrupt(deviceExtension->KeyboardInterruptObject);
1475 if (deviceExtension->MouseInterruptObject != NULL)
1476 IoDisconnectInterrupt(deviceExtension->MouseInterruptObject);
1477 if (deviceExtension->KeyboardExtension.InputData)
1478 ExFreePool(deviceExtension->KeyboardExtension.InputData);
1479 if (deviceExtension->MouseExtension.InputData)
1480 ExFreePool(deviceExtension->MouseExtension.InputData);
1481
1482 if (deviceExtension->UnmapRegistersRequired) {
1483 for (i = 0;
1484 i < deviceExtension->Configuration.PortListCount; i++){
1485 if (deviceExtension->DeviceRegisters[i]) {
1486 MmUnmapIoSpace(
1487 deviceExtension->DeviceRegisters[i],
1488 deviceExtension->Configuration.PortList[i].u.Port.Length);
1489 }
1490 }
1491 }
1492 }
1493
1494
1495 if (portDeviceObject) {
1496 if (fullPointerName.Length > 0) {
1497 IoDeleteSymbolicLink(&fullPointerName);
1498 }
1499 IoDeleteDevice(portDeviceObject);
1500 }
1501 }
1502
1503 //
1504 // Free the resource list.
1505 //
1506 // N.B. If we ever decide to hang on to the resource list instead,
1507 // we need to allocate it from non-paged pool (it is now paged pool).
1508 //
1509
1510 if (resources) {
1511 ExFreePool(resources);
1512 }
1513
1514 //
1515 // Free the temporary device extension
1516 //
1517
1518 if (initializationData != NULL) {
1519 ExFreePool(initializationData);
1520 }
1521
1522 //
1523 // Free the unicode strings for device names.
1524 //
1525
1526 if (deviceNameSuffix.MaximumLength != 0)
1527 ExFreePool(deviceNameSuffix.Buffer);
1528 if (fullKeyboardName.MaximumLength != 0)
1529 ExFreePool(fullKeyboardName.Buffer);
1530 if (fullPointerName.MaximumLength != 0)
1531 ExFreePool(fullPointerName.Buffer);
1532 if (resourceDeviceClass.MaximumLength != 0)
1533 ExFreePool(resourceDeviceClass.Buffer);
1534 if (registryPath.MaximumLength != 0)
1535 ExFreePool(registryPath.Buffer);
1536
1537 I8xPrint((1,"I8042PRT-I8042Initialize: exit\n"));
1538
1539 return(status);
1540
1541}
1542
1543
1544VOID
1545I8042Unload(
1546 IN PDRIVER_OBJECT DriverObject
1547 )
1548{
1549 UNREFERENCED_PARAMETER(DriverObject);
1550
1551 I8xPrint((2, "I8042PRT-I8042Unload: enter\n"));
1552 I8xPrint((2, "I8042PRT-I8042Unload: exit\n"));
1553}
1554
1555
1556VOID
1557I8xBuildResourceList(
1558 IN PDEVICE_EXTENSION DeviceExtension,
1559 OUT PCM_RESOURCE_LIST *ResourceList,
1560 OUT PULONG ResourceListSize
1561 )
1562
1563/*++
1564
1565Routine Description:
1566
1567 Creates a resource list that is used to query or report resource usage.
1568
1569Arguments:
1570
1571 DeviceExtension - Pointer to the port's device extension.
1572
1573 ResourceList - Pointer to a pointer to the resource list to be allocated
1574 and filled.
1575
1576 ResourceListSize - Pointer to the returned size of the resource
1577 list (in bytes).
1578
1579Return Value:
1580
1581 None. If the call succeeded, *ResourceList points to the built
1582 resource list and *ResourceListSize is set to the size (in bytes)
1583 of the resource list; otherwise, *ResourceList is NULL.
1584
1585Note:
1586
1587 Memory may be allocated here for *ResourceList. It must be
1588 freed up by the caller, by calling ExFreePool();
1589
1590--*/
1591
1592{
1593 ULONG count = 0;
1594 ULONG i = 0;
1595 ULONG j = 0;
1596#define DUMP_COUNT 4
1597 ULONG dumpData[DUMP_COUNT];
1598
1599 count += DeviceExtension->Configuration.PortListCount;
1600 if (DeviceExtension->Configuration.KeyboardInterrupt.Type
1601 == CmResourceTypeInterrupt)
1602 count += 1;
1603 if (DeviceExtension->Configuration.MouseInterrupt.Type
1604 == CmResourceTypeInterrupt)
1605 count += 1;
1606
1607 *ResourceListSize = sizeof(CM_RESOURCE_LIST) +
1608 ((count - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
1609
1610 *ResourceList = (PCM_RESOURCE_LIST) ExAllocatePool(
1611 PagedPool,
1612 *ResourceListSize
1613 );
1614
1615 //
1616 // Return NULL if the structure could not be allocated.
1617 // Otherwise, fill in the resource list.
1618 //
1619
1620 if (!*ResourceList) {
1621
1622 //
1623 // Could not allocate memory for the resource list.
1624 //
1625
1626 I8xPrint((
1627 1,
1628 "I8042PRT-I8xBuildResourceList: Could not allocate resource list\n"
1629 ));
1630
1631 //
1632 // Log an error.
1633 //
1634
1635 dumpData[0] = *ResourceListSize;
1636 *ResourceListSize = 0;
1637
1638 I8xLogError(
1639 DeviceExtension->DeviceObject,
1640 I8042_INSUFFICIENT_RESOURCES,
1641 I8042_ERROR_VALUE_BASE + 110,
1642 STATUS_INSUFFICIENT_RESOURCES,
1643 dumpData,
1644 1
1645 );
1646
1647 return;
1648 }
1649
1650 RtlZeroMemory(
1651 *ResourceList,
1652 *ResourceListSize
1653 );
1654
1655 //
1656 // Concoct one full resource descriptor.
1657 //
1658
1659 (*ResourceList)->Count = 1;
1660
1661 (*ResourceList)->List[0].InterfaceType =
1662 DeviceExtension->Configuration.InterfaceType;
1663 (*ResourceList)->List[0].BusNumber =
1664 DeviceExtension->Configuration.BusNumber;
1665
1666 //
1667 // Build the partial resource descriptors for interrupt and port
1668 // resources from the saved values.
1669 //
1670
1671 (*ResourceList)->List[0].PartialResourceList.Count = count;
1672 if (DeviceExtension->Configuration.KeyboardInterrupt.Type
1673 == CmResourceTypeInterrupt)
1674 (*ResourceList)->List[0].PartialResourceList.PartialDescriptors[i++] =
1675 DeviceExtension->Configuration.KeyboardInterrupt;
1676 if (DeviceExtension->Configuration.MouseInterrupt.Type
1677 == CmResourceTypeInterrupt)
1678 (*ResourceList)->List[0].PartialResourceList.PartialDescriptors[i++] =
1679 DeviceExtension->Configuration.MouseInterrupt;
1680
1681 for (j = 0; j < DeviceExtension->Configuration.PortListCount; j++) {
1682 (*ResourceList)->List[0].PartialResourceList.PartialDescriptors[i++] =
1683 DeviceExtension->Configuration.PortList[j];
1684 }
1685
1686}
1687
1688
1689VOID
1690I8xDrainOutputBuffer(
1691 IN PUCHAR DataAddress,
1692 IN PUCHAR CommandAddress
1693 )
1694
1695/*++
1696
1697Routine Description:
1698
1699 This routine drains the i8042 controller's output buffer. This gets
1700 rid of stale data that may have resulted from the user hitting a key
1701 or moving the mouse, prior to the execution of I8042Initialize.
1702
1703Arguments:
1704
1705 DataAddress - Pointer to the data address to read/write from/to.
1706
1707 CommandAddress - Pointer to the command/status address to
1708 read/write from/to.
1709
1710
1711Return Value:
1712
1713 None.
1714
1715--*/
1716
1717{
1718 UCHAR byte;
1719 ULONG i;
1720
1721 I8xPrint((3, "I8042PRT-I8xDrainOutputBuffer: enter\n"));
1722
1723 //
1724 // Wait till the input buffer is processed by keyboard
1725 // then go and read the data from keyboard. Don't wait longer
1726 // than 1 second in case hardware is broken. This fix is
1727 // necessary for some DEC hardware so that the keyboard doesn't
1728 // lock up.
1729 //
1730 for (i = 0; i < 2000; i++) {
1731 if (!(I8X_GET_STATUS_BYTE(CommandAddress)&INPUT_BUFFER_FULL)) {
1732 break;
1733 }
1734 KeStallExecutionProcessor(500);
1735 }
1736
1737 while (I8X_GET_STATUS_BYTE(CommandAddress) & OUTPUT_BUFFER_FULL) {
1738
1739 //
1740 // Eat the output buffer byte.
1741 //
1742
1743 byte = I8X_GET_DATA_BYTE(DataAddress);
1744 }
1745
1746 I8xPrint((3, "I8042PRT-I8xDrainOutputBuffer: exit\n"));
1747}
1748
1749
1750VOID
1751I8xGetByteAsynchronous(
1752 IN CCHAR DeviceType,
1753 IN PDEVICE_EXTENSION DeviceExtension,
1754 OUT PUCHAR Byte
1755 )
1756
1757/*++
1758
1759Routine Description:
1760
1761 This routine reads a data byte from the controller or keyboard
1762 or mouse, asynchronously.
1763
1764Arguments:
1765
1766 DeviceType - Specifies which device (i8042 controller, keyboard, or
1767 mouse) to read the byte from.
1768
1769 DeviceExtension - Pointer to the device extension.
1770
1771 Byte - Pointer to the location to store the byte read from the hardware.
1772
1773Return Value:
1774
1775 None.
1776
1777 As a side-effect, the byte value read is stored. If the hardware was not
1778 ready for output or did not respond, the byte value is not stored.
1779
1780--*/
1781
1782{
1783 ULONG i;
1784 UCHAR response;
1785 UCHAR desiredMask;
1786
1787 I8xPrint((3, "I8042PRT-I8xGetByteAsynchronous: enter\n"));
1788
1789 if (DeviceType == KeyboardDeviceType) {
1790 I8xPrint((3, "I8042PRT-I8xGetByteAsynchronous: keyboard\n"));
1791 } else if (DeviceType == MouseDeviceType) {
1792 I8xPrint((3, "I8042PRT-I8xGetByteAsynchronous: mouse\n"));
1793 } else {
1794 I8xPrint((3, "I8042PRT-I8xGetByteAsynchronous: 8042 controller\n"));
1795 }
1796
1797 i = 0;
1798 desiredMask = (DeviceType == MouseDeviceType)?
1799 (UCHAR) (OUTPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL):
1800 (UCHAR) OUTPUT_BUFFER_FULL;
1801
1802 //
1803 // Poll until we get back a controller status value that indicates
1804 // the output buffer is full. If we want to read a byte from the mouse,
1805 // further ensure that the auxiliary device output buffer full bit is
1806 // set.
1807 //
1808
1809 while ((i < (ULONG)DeviceExtension->Configuration.PollingIterations) &&
1810 ((UCHAR)((response =
1811 I8X_GET_STATUS_BYTE(DeviceExtension->DeviceRegisters[CommandPort]))
1812 & desiredMask) != desiredMask)) {
1813
1814 if (response & OUTPUT_BUFFER_FULL) {
1815
1816 //
1817 // There is something in the i8042 output buffer, but it
1818 // isn't from the device we want to get a byte from. Eat
1819 // the byte and try again.
1820 //
1821
1822 *Byte = I8X_GET_DATA_BYTE(DeviceExtension->DeviceRegisters[DataPort]);
1823 I8xPrint((2, "I8042PRT-I8xGetByteAsynchronous: ate 0x%x\n", *Byte));
1824 } else {
1825
1826 //
1827 // Try again.
1828 //
1829
1830 i += 1;
1831
1832 I8xPrint((
1833 2,
1834 "I8042PRT-I8xGetByteAsynchronous: wait for correct status\n"
1835 ));
1836 }
1837
1838 }
1839 if (i >= (ULONG)DeviceExtension->Configuration.PollingIterations) {
1840 I8xPrint((2, "I8042PRT-I8xGetByteAsynchronous: timing out\n"));
1841 return;
1842 }
1843
1844 //
1845 // Grab the byte from the hardware.
1846 //
1847
1848 *Byte = I8X_GET_DATA_BYTE(DeviceExtension->DeviceRegisters[DataPort]);
1849
1850 I8xPrint((
1851 3,
1852 "I8042PRT-I8xGetByteAsynchronous: exit with Byte 0x%x\n", *Byte
1853 ));
1854
1855}
1856
1857
1858NTSTATUS
1859I8xGetBytePolled(
1860 IN CCHAR DeviceType,
1861 IN PDEVICE_EXTENSION DeviceExtension,
1862 OUT PUCHAR Byte
1863 )
1864
1865/*++
1866
1867Routine Description:
1868
1869 This routine reads a data byte from the controller or keyboard
1870 or mouse, in polling mode.
1871
1872Arguments:
1873
1874 DeviceType - Specifies which device (i8042 controller, keyboard, or
1875 mouse) to read the byte from.
1876
1877 DeviceExtension - Pointer to the device extension.
1878
1879 Byte - Pointer to the location to store the byte read from the hardware.
1880
1881Return Value:
1882
1883 STATUS_IO_TIMEOUT - The hardware was not ready for output or did not
1884 respond.
1885
1886 STATUS_SUCCESS - The byte was successfully read from the hardware.
1887
1888 As a side-effect, the byte value read is stored.
1889
1890--*/
1891
1892{
1893 ULONG i;
1894 UCHAR response;
1895 UCHAR desiredMask;
1896
1897 I8xPrint((3, "I8042PRT-I8xGetBytePolled: enter\n"));
1898
1899 if (DeviceType == KeyboardDeviceType) {
1900 I8xPrint((3, "I8042PRT-I8xGetBytePolled: keyboard\n"));
1901 } else if (DeviceType == MouseDeviceType) {
1902 I8xPrint((3, "I8042PRT-I8xGetBytePolled: mouse\n"));
1903 } else {
1904 I8xPrint((3, "I8042PRT-I8xGetBytePolled: 8042 controller\n"));
1905 }
1906
1907 i = 0;
1908 desiredMask = (DeviceType == MouseDeviceType)?
1909 (UCHAR) (OUTPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL):
1910 (UCHAR) OUTPUT_BUFFER_FULL;
1911
1912
1913 //
1914 // Poll until we get back a controller status value that indicates
1915 // the output buffer is full. If we want to read a byte from the mouse,
1916 // further ensure that the auxiliary device output buffer full bit is
1917 // set.
1918 //
1919
1920 while ((i < (ULONG)DeviceExtension->Configuration.PollingIterations) &&
1921 ((UCHAR)((response =
1922 I8X_GET_STATUS_BYTE(DeviceExtension->DeviceRegisters[CommandPort]))
1923 & desiredMask) != desiredMask)) {
1924 if (response & OUTPUT_BUFFER_FULL) {
1925
1926 //
1927 // There is something in the i8042 output buffer, but it
1928 // isn't from the device we want to get a byte from. Eat
1929 // the byte and try again.
1930 //
1931
1932 *Byte = I8X_GET_DATA_BYTE(DeviceExtension->DeviceRegisters[DataPort]);
1933 I8xPrint((2, "I8042PRT-I8xGetBytePolled: ate 0x%x\n", *Byte));
1934 } else {
1935 I8xPrint((2, "I8042PRT-I8xGetBytePolled: stalling\n"));
1936 KeStallExecutionProcessor(
1937 DeviceExtension->Configuration.StallMicroseconds
1938 );
1939 i += 1;
1940 }
1941 }
1942 if (i >= (ULONG)DeviceExtension->Configuration.PollingIterations) {
1943 I8xPrint((2, "I8042PRT-I8xGetBytePolled: timing out\n"));
1944 return(STATUS_IO_TIMEOUT);
1945 }
1946
1947 //
1948 // Grab the byte from the hardware, and return success.
1949 //
1950
1951 *Byte = I8X_GET_DATA_BYTE(DeviceExtension->DeviceRegisters[DataPort]);
1952
1953 I8xPrint((3, "I8042PRT-I8xGetBytePolled: exit with Byte 0x%x\n", *Byte));
1954
1955 return(STATUS_SUCCESS);
1956
1957}
1958
1959
1960NTSTATUS
1961I8xGetControllerCommand(
1962 IN ULONG HardwareDisableEnableMask,
1963 IN PDEVICE_EXTENSION DeviceExtension,
1964 OUT PUCHAR Byte
1965 )
1966
1967/*++
1968
1969Routine Description:
1970
1971 This routine reads the 8042 Controller Command Byte.
1972
1973Arguments:
1974
1975 HardwareDisableEnableMask - Specifies which hardware devices, if any,
1976 need to be disabled/enable around the operation.
1977
1978 DeviceExtension - Pointer to the device extension.
1979
1980 Byte - Pointer to the location into which the Controller Command Byte is
1981 read.
1982
1983Return Value:
1984
1985 Status is returned.
1986
1987--*/
1988
1989{
1990 NTSTATUS status;
1991 NTSTATUS secondStatus;
1992 ULONG retryCount;
1993
1994 I8xPrint((3, "I8042PRT-I8xGetControllerCommand: enter\n"));
1995
1996 //
1997 // Disable the specified devices before sending the command to
1998 // read the Controller Command Byte (otherwise data in the output
1999 // buffer might get trashed).
2000 //
2001
2002 if (HardwareDisableEnableMask & KEYBOARD_HARDWARE_PRESENT) {
2003 status = I8xPutBytePolled(
2004 (CCHAR) CommandPort,
2005 NO_WAIT_FOR_ACKNOWLEDGE,
2006 (CCHAR) UndefinedDeviceType,
2007 DeviceExtension,
2008 (UCHAR) I8042_DISABLE_KEYBOARD_DEVICE
2009 );
2010 if (!NT_SUCCESS(status)) {
2011 return(status);
2012 }
2013 }
2014
2015 if (HardwareDisableEnableMask & MOUSE_HARDWARE_PRESENT) {
2016 status = I8xPutBytePolled(
2017 (CCHAR) CommandPort,
2018 NO_WAIT_FOR_ACKNOWLEDGE,
2019 (CCHAR) UndefinedDeviceType,
2020 DeviceExtension,
2021 (UCHAR) I8042_DISABLE_MOUSE_DEVICE
2022 );
2023 if (!NT_SUCCESS(status)) {
2024
2025 //
2026 // Re-enable the keyboard device, if necessary, before returning.
2027 //
2028
2029 if (HardwareDisableEnableMask & KEYBOARD_HARDWARE_PRESENT) {
2030 secondStatus = I8xPutBytePolled(
2031 (CCHAR) CommandPort,
2032 NO_WAIT_FOR_ACKNOWLEDGE,
2033 (CCHAR) UndefinedDeviceType,
2034 DeviceExtension,
2035 (UCHAR) I8042_ENABLE_KEYBOARD_DEVICE
2036 );
2037 }
2038 return(status);
2039 }
2040 }
2041
2042 //
2043 // Send a command to the i8042 controller to read the Controller
2044 // Command Byte.
2045 //
2046
2047 status = I8xPutBytePolled(
2048 (CCHAR) CommandPort,
2049 NO_WAIT_FOR_ACKNOWLEDGE,
2050 (CCHAR) UndefinedDeviceType,
2051 DeviceExtension,
2052 (UCHAR) I8042_READ_CONTROLLER_COMMAND_BYTE
2053 );
2054
2055 //
2056 // Read the byte from the i8042 data port.
2057 //
2058
2059 if (NT_SUCCESS(status)) {
2060 for (retryCount = 0; retryCount < 5; retryCount++) {
2061 status = I8xGetBytePolled(
2062 (CCHAR) ControllerDeviceType,
2063 DeviceExtension,
2064 Byte
2065 );
2066 if (NT_SUCCESS(status)) {
2067 break;
2068 }
2069 if (status == STATUS_IO_TIMEOUT) {
2070 KeStallExecutionProcessor(50);
2071 } else {
2072 break;
2073 }
2074 }
2075 }
2076
2077 //
2078 // Re-enable the specified devices. Clear the device disable
2079 // bits in the Controller Command Byte by hand (they got set when
2080 // we disabled the devices, so the CCB we read lacked the real
2081 // device disable bit information).
2082 //
2083
2084 if (HardwareDisableEnableMask & KEYBOARD_HARDWARE_PRESENT) {
2085 secondStatus = I8xPutBytePolled(
2086 (CCHAR) CommandPort,
2087 NO_WAIT_FOR_ACKNOWLEDGE,
2088 (CCHAR) UndefinedDeviceType,
2089 DeviceExtension,
2090 (UCHAR) I8042_ENABLE_KEYBOARD_DEVICE
2091 );
2092 if (!NT_SUCCESS(secondStatus)) {
2093 if (NT_SUCCESS(status))
2094 status = secondStatus;
2095 } else if (status == STATUS_SUCCESS) {
2096 *Byte &= (UCHAR) ~CCB_DISABLE_KEYBOARD_DEVICE;
2097 }
2098
2099 }
2100
2101 if (HardwareDisableEnableMask & MOUSE_HARDWARE_PRESENT) {
2102 secondStatus = I8xPutBytePolled(
2103 (CCHAR) CommandPort,
2104 NO_WAIT_FOR_ACKNOWLEDGE,
2105 (CCHAR) UndefinedDeviceType,
2106 DeviceExtension,
2107 (UCHAR) I8042_ENABLE_MOUSE_DEVICE
2108 );
2109 if (!NT_SUCCESS(secondStatus)) {
2110 if (NT_SUCCESS(status))
2111 status = secondStatus;
2112 } else if (NT_SUCCESS(status)) {
2113 *Byte &= (UCHAR) ~CCB_DISABLE_MOUSE_DEVICE;
2114 }
2115 }
2116
2117 I8xPrint((3, "I8042PRT-I8xGetControllerCommand: exit\n"));
2118
2119 return(status);
2120
2121}
2122
2123
2124VOID
2125I8xInitializeHardware(
2126 IN PDEVICE_OBJECT DeviceObject
2127 )
2128
2129/*++
2130
2131Routine Description:
2132
2133 This routine initializes the i8042 controller, keyboard, and mouse.
2134 Note that it is only called at initialization time. This routine
2135 does not need to synchronize access to the hardware, or synchronize
2136 with the ISRs (they aren't connected yet).
2137
2138Arguments:
2139
2140 DeviceObject - Pointer to the device object.
2141
2142Return Value:
2143
2144 None. As a side-effect, however, DeviceExtension->HardwarePresent is set.
2145
2146--*/
2147
2148{
2149 PDEVICE_EXTENSION deviceExtension;
2150 NTSTATUS status;
2151 I8042_TRANSMIT_CCB_CONTEXT transmitCCBContext;
2152 PUCHAR dataAddress, commandAddress;
2153
2154 I8xPrint((2, "I8042PRT-I8xInitializeHardware: enter\n"));
2155
2156 //
2157 // Grab useful configuration parameters from the device extension.
2158 //
2159
2160 deviceExtension = DeviceObject->DeviceExtension;
2161 dataAddress = deviceExtension->DeviceRegisters[DataPort];
2162 commandAddress = deviceExtension->DeviceRegisters[CommandPort];
2163
2164 //
2165 // Drain the i8042 output buffer to get rid of stale data.
2166 //
2167
2168 I8xDrainOutputBuffer(dataAddress, commandAddress);
2169
2170 //
2171 // Disable interrupts from the keyboard and mouse. Read the Controller
2172 // Command Byte, turn off the keyboard and auxiliary interrupt enable
2173 // bits, and rewrite the Controller Command Byte.
2174 //
2175
2176 transmitCCBContext.HardwareDisableEnableMask = 0;
2177 transmitCCBContext.AndOperation = AND_OPERATION;
2178 transmitCCBContext.ByteMask = (UCHAR)
2179 ~((UCHAR) CCB_ENABLE_KEYBOARD_INTERRUPT |
2180 (UCHAR) CCB_ENABLE_MOUSE_INTERRUPT);
2181
2182 I8xTransmitControllerCommand(deviceExtension, (PVOID) &transmitCCBContext);
2183
2184 if (!NT_SUCCESS(transmitCCBContext.Status)) {
2185 I8xPrint((
2186 1,
2187 "I8042PRT-I8xInitializeHardware: failed to disable interrupts, status 0x%x\n",
2188 transmitCCBContext.Status
2189 ));
2190
2191 return;
2192 }
2193
2194 if ((deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT) == 0) {
2195 I8xPrint((
2196 1,
2197 "I8042PRT-I8xInitializeHardware: no mouse present\n"
2198 ));
2199 }
2200
2201 if ((deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) == 0) {
2202 I8xPrint((
2203 1,
2204 "I8042PRT-I8xInitializeHardware: no keyboard present\n"
2205 ));
2206 }
2207
2208
2209 //
2210 // Disable the keyboard and mouse devices.
2211 //
2212
2213#if 0
2214 //
2215 // NOTE: This is supposedly the "correct" thing to do. However,
2216 // disabling the keyboard device here causes the AMI rev K8 machines
2217 // (e.g., some Northgates) to fail some commands (e.g., the READID
2218 // command).
2219 //
2220
2221 status = I8xPutBytePolled(
2222 (CCHAR) CommandPort,
2223 NO_WAIT_FOR_ACKNOWLEDGE,
2224 (CCHAR) UndefinedDeviceType,
2225 deviceExtension,
2226 (UCHAR) I8042_DISABLE_KEYBOARD_DEVICE
2227 );
2228 if (!NT_SUCCESS(status)) {
2229 I8xPrint((
2230 1,
2231 "I8042PRT-I8xInitializeHardware: failed kbd disable, status 0x%x\n",
2232 status
2233 ));
2234 deviceExtension->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2235 }
2236#endif
2237
2238
2239#if 0
2240 //
2241 // NOTE: This is supposedly the "correct thing to do. However,
2242 // disabling the mouse on RadiSys EPC-24 which uses VLSI part number
2243 // VL82C144 (3751E) causes the part to shut down keyboard interrupts.
2244 //
2245
2246 status = I8xPutBytePolled(
2247 (CCHAR) CommandPort,
2248 NO_WAIT_FOR_ACKNOWLEDGE,
2249 (CCHAR) UndefinedDeviceType,
2250 deviceExtension,
2251 (UCHAR) I8042_DISABLE_MOUSE_DEVICE
2252 );
2253 if (!NT_SUCCESS(status)) {
2254 I8xPrint((
2255 1,
2256 "I8042PRT-I8xInitializeHardware: failed mou disable, status 0x%x\n",
2257 status
2258 ));
2259
2260 deviceExtension->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
2261 }
2262#endif
2263
2264 //
2265 // Drain the i8042 output buffer to get rid of stale data that could
2266 // come in sometime between the previous drain and the time the devices
2267 // are disabled.
2268 //
2269
2270 I8xDrainOutputBuffer(dataAddress, commandAddress);
2271
2272 //
2273 // Setup the mouse hardware. This consists of resetting the mouse and
2274 // then setting the mouse sample rate.
2275 //
2276
2277 if (deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT) {
2278 status = I8xInitializeMouse(DeviceObject);
2279 if (!NT_SUCCESS(status)) {
2280 I8xPrint((
2281 1,
2282 "I8042PRT-I8xInitializeHardware: failed mou init, status 0x%x\n",
2283 status
2284 ));
2285 deviceExtension->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
2286 }
2287 }
2288
2289 //
2290 // Setup the keyboard hardware.
2291 //
2292
2293 if (deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) {
2294 status = I8xInitializeKeyboard(DeviceObject);
2295 if (!NT_SUCCESS(status)) {
2296 I8xPrint((
2297 0,
2298 "I8042PRT-I8xInitializeHardware: failed kbd init, status 0x%x\n",
2299 status
2300 ));
2301
2302#if defined(JAPAN) && defined(i386)
2303//Fujitsu Aug.23.1994
2304// To realize "keyboard-less system" needs to make look like connecting
2305// keybaord hardware, as this routine, if not connect.
2306
2307 if ( status == STATUS_IO_TIMEOUT ) {
2308 deviceExtension->HardwarePresent |= KEYBOARD_HARDWARE_PRESENT;
2309 }else{
2310 deviceExtension->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2311 }
2312#else
2313 deviceExtension->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2314#endif
2315 }
2316 }
2317
2318 //
2319 // Enable the keyboard and mouse devices and their interrupts. Note
2320 // that it is required that this operation happen during intialization
2321 // time, because the i8042 Output Buffer Full bit gets set in the
2322 // Controller Command Byte when the keyboard/mouse is used, even if
2323 // the device is disabled. Hence, we cannot successfully perform
2324 // the enable operation later (e.g., when processing
2325 // IOCTL_INTERNAL_*_ENABLE), because we can't guarantee that
2326 // I8xPutBytePolled() won't time out waiting for the Output Buffer Full
2327 // bit to clear, even if we drain the output buffer (because the user
2328 // could be playing with the mouse/keyboard, and continuing to set the
2329 // OBF bit). KeyboardEnableCount and MouseEnableCount remain zero until
2330 // their respective IOCTL_INTERNAL_*_ENABLE call succeeds, so the ISR
2331 // ignores the unexpected interrupts.
2332 //
2333
2334 //
2335 // Re-enable the keyboard device in the Controller Command Byte.
2336 // Note that some of the keyboards will send an ACK back, while
2337 // others don't. Don't wait for an ACK, but do drain the output
2338 // buffer afterwards so that an unexpected ACK doesn't screw up
2339 // successive PutByte operations.
2340
2341 if (deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) {
2342 status = I8xPutBytePolled(
2343 (CCHAR) CommandPort,
2344 NO_WAIT_FOR_ACKNOWLEDGE,
2345 (CCHAR) UndefinedDeviceType,
2346 deviceExtension,
2347 (UCHAR) I8042_ENABLE_KEYBOARD_DEVICE
2348 );
2349 if (!NT_SUCCESS(status)) {
2350 I8xPrint((
2351 1,
2352 "I8042PRT-I8xInitializeHardware: failed kbd re-enable, status 0x%x\n",
2353 status
2354 ));
2355 deviceExtension->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2356 }
2357
2358 I8xDrainOutputBuffer(dataAddress, commandAddress);
2359 }
2360
2361
2362 //
2363 // Re-enable the mouse device in the Controller Command Byte.
2364 //
2365
2366 if (deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT) {
2367 status = I8xPutBytePolled(
2368 (CCHAR) CommandPort,
2369 NO_WAIT_FOR_ACKNOWLEDGE,
2370 (CCHAR) UndefinedDeviceType,
2371 deviceExtension,
2372 (UCHAR) I8042_ENABLE_MOUSE_DEVICE
2373 );
2374 if (!NT_SUCCESS(status)) {
2375 I8xPrint((
2376 1,
2377 "I8042PRT-I8xInitializeHardware: failed mou re-enable, status 0x%x\n",
2378 status
2379 ));
2380 deviceExtension->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
2381 }
2382 I8xDrainOutputBuffer(dataAddress, commandAddress);
2383 }
2384
2385 //
2386 // Re-enable interrupts in the Controller Command Byte.
2387 //
2388
2389 if (deviceExtension->HardwarePresent) {
2390 transmitCCBContext.HardwareDisableEnableMask =
2391 deviceExtension->HardwarePresent;
2392 transmitCCBContext.AndOperation = OR_OPERATION;
2393 transmitCCBContext.ByteMask =
2394 (deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) ?
2395 CCB_ENABLE_KEYBOARD_INTERRUPT : 0;
2396 transmitCCBContext.ByteMask |= (UCHAR)
2397 (deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT) ?
2398 CCB_ENABLE_MOUSE_INTERRUPT : 0;
2399
2400 I8xTransmitControllerCommand(
2401 deviceExtension,
2402 (PVOID) &transmitCCBContext
2403 );
2404
2405 if (!NT_SUCCESS(transmitCCBContext.Status)) {
2406 I8xPrint((
2407 1,
2408 "I8042PRT-I8xInitializeHardware: failed to re-enable interrupts, status 0x%x\n",
2409 transmitCCBContext.Status
2410 ));
2411
2412 //
2413 // We have the option here of resetting HardwarePresent to zero,
2414 // which will cause the driver to fail its initialization and
2415 // unload. Instead, we allow initialization to continue in
2416 // the hope that the command to re-enable interrupts was
2417 // successful at the hardware level (i.e., things will work),
2418 // even though the hardware response indicates otherwise.
2419 //
2420 }
2421 }
2422
2423 I8xPrint((2, "I8042PRT-I8xInitializeHardware: exit\n"));
2424
2425 return;
2426
2427}
2428
2429
2430VOID
2431I8xPutByteAsynchronous(
2432 IN CCHAR PortType,
2433 IN PDEVICE_EXTENSION DeviceExtension,
2434 IN UCHAR Byte
2435 )
2436
2437/*++
2438
2439Routine Description:
2440
2441 This routine sends a command or data byte to the controller or keyboard
2442 or mouse, asynchronously. It does not wait for acknowledgment.
2443 If the hardware was not ready for input, the byte is not sent.
2444
2445Arguments:
2446
2447 PortType - If CommandPort, send the byte to the command register,
2448 otherwise send it to the data register.
2449
2450 DeviceExtension - Pointer to the device extension.
2451
2452 Byte - The byte to send to the hardware.
2453
2454Return Value:
2455
2456 None.
2457
2458--*/
2459
2460{
2461 ULONG i;
2462
2463 I8xPrint((3, "I8042PRT-I8xPutByteAsynchronous: enter\n"));
2464
2465 //
2466 // Make sure the Input Buffer Full controller status bit is clear.
2467 // Time out if necessary.
2468 //
2469
2470 i = 0;
2471 while ((i++ < (ULONG)DeviceExtension->Configuration.PollingIterations) &&
2472 (I8X_GET_STATUS_BYTE(DeviceExtension->DeviceRegisters[CommandPort])
2473 & INPUT_BUFFER_FULL)) {
2474
2475 //
2476 // Do nothing.
2477 //
2478
2479 I8xPrint((
2480 3,
2481 "I8042PRT-I8xPutByteAsynchronous: wait for IBF and OBF to clear\n"
2482 ));
2483
2484 }
2485 if (i >= (ULONG)DeviceExtension->Configuration.PollingIterations) {
2486 I8xPrint((
2487 3,
2488 "I8042PRT-I8xPutByteAsynchronous: exceeded number of retries\n"
2489 ));
2490 return;
2491 }
2492
2493 //
2494 // Send the byte to the appropriate (command/data) hardware register.
2495 //
2496
2497 if (PortType == CommandPort) {
2498 I8xPrint((
2499 3,
2500 "I8042PRT-I8xPutByteAsynchronous: sending 0x%x to command port\n",
2501 Byte
2502 ));
2503 I8X_PUT_COMMAND_BYTE(DeviceExtension->DeviceRegisters[CommandPort], Byte);
2504 } else {
2505 I8xPrint((
2506 3,
2507 "I8042PRT-I8xPutByteAsynchronous: sending 0x%x to data port\n",
2508 Byte
2509 ));
2510 I8X_PUT_DATA_BYTE(DeviceExtension->DeviceRegisters[DataPort], Byte);
2511 }
2512
2513 I8xPrint((3, "I8042PRT-I8xPutByteAsynchronous: exit\n"));
2514
2515}
2516
2517
2518NTSTATUS
2519I8xPutBytePolled(
2520 IN CCHAR PortType,
2521 IN BOOLEAN WaitForAcknowledge,
2522 IN CCHAR AckDeviceType,
2523 IN PDEVICE_EXTENSION DeviceExtension,
2524 IN UCHAR Byte
2525 )
2526
2527/*++
2528
2529Routine Description:
2530
2531 This routine sends a command or data byte to the controller or keyboard
2532 or mouse, in polling mode. It waits for acknowledgment and resends
2533 the command/data if necessary.
2534
2535Arguments:
2536
2537 PortType - If CommandPort, send the byte to the command register,
2538 otherwise send it to the data register.
2539
2540 WaitForAcknowledge - If true, wait for an ACK back from the hardware.
2541
2542 AckDeviceType - Indicates which device we expect to get the ACK back
2543 from.
2544
2545 DeviceExtension - Pointer to the device extension.
2546
2547 Byte - The byte to send to the hardware.
2548
2549Return Value:
2550
2551 STATUS_IO_TIMEOUT - The hardware was not ready for input or did not
2552 respond.
2553
2554 STATUS_SUCCESS - The byte was successfully sent to the hardware.
2555
2556--*/
2557
2558{
2559 ULONG i,j;
2560 UCHAR response;
2561 NTSTATUS status;
2562 BOOLEAN keepTrying;
2563 PUCHAR dataAddress, commandAddress;
2564
2565 I8xPrint((3, "I8042PRT-I8xPutBytePolled: enter\n"));
2566
2567 if (AckDeviceType == MouseDeviceType) {
2568
2569 //
2570 // We need to precede a PutByte for the mouse device with
2571 // a PutByte that tells the controller that the next byte
2572 // sent to the controller should go to the auxiliary device
2573 // (by default it would go to the keyboard device). We
2574 // do this by calling I8xPutBytePolled recursively to send
2575 // the "send next byte to auxiliary device" command
2576 // before sending the intended byte to the mouse. Note that
2577 // there is only one level of recursion, since the AckDeviceType
2578 // for the recursive call is guaranteed to be UndefinedDeviceType,
2579 // and hence this IF statement will evaluate to FALSE.
2580 //
2581
2582 I8xPutBytePolled(
2583 (CCHAR) CommandPort,
2584 NO_WAIT_FOR_ACKNOWLEDGE,
2585 (CCHAR) UndefinedDeviceType,
2586 DeviceExtension,
2587 (UCHAR) I8042_WRITE_TO_AUXILIARY_DEVICE
2588 );
2589 }
2590
2591 dataAddress = DeviceExtension->DeviceRegisters[DataPort];
2592 commandAddress = DeviceExtension->DeviceRegisters[CommandPort];
2593
2594 for (j=0;j < (ULONG)DeviceExtension->Configuration.ResendIterations;j++) {
2595
2596 //
2597 // Make sure the Input Buffer Full controller status bit is clear.
2598 // Time out if necessary.
2599 //
2600
2601 i = 0;
2602 while ((i++ < (ULONG)DeviceExtension->Configuration.PollingIterations)
2603 && (I8X_GET_STATUS_BYTE(commandAddress) & INPUT_BUFFER_FULL)) {
2604 I8xPrint((2, "I8042PRT-I8xPutBytePolled: stalling\n"));
2605 KeStallExecutionProcessor(
2606 DeviceExtension->Configuration.StallMicroseconds
2607 );
2608 }
2609 if (i >= (ULONG)DeviceExtension->Configuration.PollingIterations) {
2610 I8xPrint((2, "I8042PRT-I8xPutBytePolled: timing out\n"));
2611 status = STATUS_IO_TIMEOUT;
2612 break;
2613 }
2614
2615 //
2616 // Drain the i8042 output buffer to get rid of stale data.
2617 //
2618
2619 I8xDrainOutputBuffer(dataAddress, commandAddress);
2620
2621 //
2622 // Send the byte to the appropriate (command/data) hardware register.
2623 //
2624
2625 if (PortType == CommandPort) {
2626 I8xPrint((
2627 3,
2628 "I8042PRT-I8xPutBytePolled: sending 0x%x to command port\n",
2629 Byte
2630 ));
2631 I8X_PUT_COMMAND_BYTE(commandAddress, Byte);
2632 } else {
2633 I8xPrint((
2634 3,
2635 "I8042PRT-I8xPutBytePolled: sending 0x%x to data port\n",
2636 Byte
2637 ));
2638 I8X_PUT_DATA_BYTE(dataAddress, Byte);
2639 }
2640
2641 //
2642 // If we don't need to wait for an ACK back from the controller,
2643 // set the status and break out of the for loop.
2644 //
2645 //
2646
2647 if (WaitForAcknowledge == NO_WAIT_FOR_ACKNOWLEDGE) {
2648 status = STATUS_SUCCESS;
2649 break;
2650 }
2651
2652 //
2653 // Wait for an ACK back from the controller. If we get an ACK,
2654 // the operation was successful. If we get a RESEND, break out to
2655 // the for loop and try the operation again. Ignore anything other
2656 // than ACK or RESEND.
2657 //
2658
2659 I8xPrint((3, "I8042PRT-I8xPutBytePolled: waiting for ACK\n"));
2660 keepTrying = FALSE;
2661 while ((status = I8xGetBytePolled(
2662 AckDeviceType,
2663 DeviceExtension,
2664 &response
2665 )
2666 ) == STATUS_SUCCESS) {
2667
2668 if (response == ACKNOWLEDGE) {
2669 I8xPrint((3, "I8042PRT-I8xPutBytePolled: got ACK\n"));
2670 break;
2671 } else if (response == RESEND) {
2672 I8xPrint((3, "I8042PRT-I8xPutBytePolled: got RESEND\n"));
2673
2674 if (AckDeviceType == MouseDeviceType) {
2675
2676 //
2677 // We need to precede the "resent" PutByte for the
2678 // mouse device with a PutByte that tells the controller
2679 // that the next byte sent to the controller should go
2680 // to the auxiliary device (by default it would go to
2681 // the keyboard device). We do this by calling
2682 // I8xPutBytePolled recursively to send the "send next
2683 // byte to auxiliary device" command before resending
2684 // the byte to the mouse. Note that there is only one
2685 // level of recursion, since the AckDeviceType for the
2686 // recursive call is guaranteed to be UndefinedDeviceType.
2687 //
2688
2689 I8xPutBytePolled(
2690 (CCHAR) CommandPort,
2691 NO_WAIT_FOR_ACKNOWLEDGE,
2692 (CCHAR) UndefinedDeviceType,
2693 DeviceExtension,
2694 (UCHAR) I8042_WRITE_TO_AUXILIARY_DEVICE
2695 );
2696 }
2697
2698 keepTrying = TRUE;
2699 break;
2700 }
2701
2702 //
2703 // Ignore any other response, and keep trying.
2704 //
2705
2706 }
2707
2708 if (!keepTrying)
2709 break;
2710 }
2711
2712 //
2713 // Check to see if the number of allowable retries was exceeded.
2714 //
2715
2716 if (j >= (ULONG)DeviceExtension->Configuration.ResendIterations) {
2717 I8xPrint((
2718 2,
2719 "I8042PRT-I8xPutBytePolled: exceeded number of retries\n"
2720 ));
2721 status = STATUS_IO_TIMEOUT;
2722 }
2723
2724 I8xPrint((3, "I8042PRT-I8xPutBytePolled: exit\n"));
2725
2726 return(status);
2727}
2728
2729
2730NTSTATUS
2731I8xPutControllerCommand(
2732 IN PDEVICE_EXTENSION DeviceExtension,
2733 IN UCHAR Byte
2734 )
2735
2736/*++
2737
2738Routine Description:
2739
2740 This routine writes the 8042 Controller Command Byte.
2741
2742Arguments:
2743
2744 DeviceExtension - Pointer to the device extension.
2745
2746 Byte - The byte to store in the Controller Command Byte.
2747
2748Return Value:
2749
2750 Status is returned.
2751
2752--*/
2753
2754{
2755 NTSTATUS status;
2756
2757 I8xPrint((3, "I8042PRT-I8xPutControllerCommand: enter\n"));
2758
2759 //
2760 // Send a command to the i8042 controller to write the Controller
2761 // Command Byte.
2762 //
2763
2764 status = I8xPutBytePolled(
2765 (CCHAR) CommandPort,
2766 NO_WAIT_FOR_ACKNOWLEDGE,
2767 (CCHAR) UndefinedDeviceType,
2768 DeviceExtension,
2769 (UCHAR) I8042_WRITE_CONTROLLER_COMMAND_BYTE
2770 );
2771
2772 if (!NT_SUCCESS(status)) {
2773 return(status);
2774 }
2775
2776 //
2777 // Write the byte through the i8042 data port.
2778 //
2779
2780 I8xPrint((3, "I8042PRT-I8xPutControllerCommand: exit\n"));
2781
2782 return(I8xPutBytePolled(
2783 (CCHAR) DataPort,
2784 NO_WAIT_FOR_ACKNOWLEDGE,
2785 (CCHAR) UndefinedDeviceType,
2786 DeviceExtension,
2787 (UCHAR) Byte
2788 )
2789 );
2790}
2791
2792
2793VOID
2794I8xServiceParameters(
2795 IN PINIT_EXTENSION InitializationData,
2796 IN PUNICODE_STRING RegistryPath,
2797 IN PUNICODE_STRING KeyboardDeviceName,
2798 IN PUNICODE_STRING PointerDeviceName
2799 )
2800
2801/*++
2802
2803Routine Description:
2804
2805 This routine retrieves this driver's service parameters information
2806 from the registry.
2807
2808Arguments:
2809
2810 InitializationData - Pointer to the initialization data, including the
2811 the device extension.
2812
2813 RegistryPath - Pointer to the null-terminated Unicode name of the
2814 registry path for this driver.
2815
2816 KeyboardDeviceName - Pointer to the Unicode string that will receive
2817 the keyboard port device name.
2818
2819 PointerDeviceName - Pointer to the Unicode string that will receive
2820 the pointer port device name.
2821
2822Return Value:
2823
2824 None. As a side-effect, sets fields in DeviceExtension->Configuration.
2825
2826--*/
2827
2828{
2829 PI8042_CONFIGURATION_INFORMATION configuration;
2830 PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
2831 UNICODE_STRING parametersPath;
2832 USHORT defaultResendIterations = I8042_RESEND_DEFAULT;
2833 ULONG resendIterations = 0;
2834 USHORT defaultPollingIterations = I8042_POLLING_DEFAULT;
2835 ULONG pollingIterations = 0;
2836 USHORT defaultPollingIterationsMaximum = I8042_POLLING_MAXIMUM;
2837 ULONG pollingIterationsMaximum = 0;
2838 USHORT defaultPollStatusIterations = I8042_POLLING_DEFAULT;
2839 ULONG pollStatusIterations = 0;
2840 ULONG defaultDataQueueSize = DATA_QUEUE_SIZE;
2841 ULONG numberOfButtons = MOUSE_NUMBER_OF_BUTTONS;
2842 USHORT defaultNumberOfButtons = MOUSE_NUMBER_OF_BUTTONS;
2843 ULONG sampleRate = MOUSE_SAMPLE_RATE;
2844 USHORT defaultSampleRate = MOUSE_SAMPLE_RATE;
2845 ULONG mouseResolution = MOUSE_RESOLUTION;
2846 USHORT defaultMouseResolution = MOUSE_RESOLUTION;
2847 ULONG overrideKeyboardType = 0;
2848 ULONG invalidKeyboardType = 0;
2849 ULONG overrideKeyboardSubtype = (ULONG) -1;
2850 ULONG invalidKeyboardSubtype = (ULONG) -1;
2851 ULONG defaultSynchPacket100ns = MOUSE_SYNCH_PACKET_100NS;
2852 ULONG enableWheelDetection = 0;
2853 ULONG defaultEnableWheelDetection = 1;
2854 UNICODE_STRING defaultPointerName;
2855 UNICODE_STRING defaultKeyboardName;
2856 NTSTATUS status = STATUS_SUCCESS;
2857 PWSTR path = NULL;
2858 USHORT queries = 15;
2859
2860 configuration = &(InitializationData->DeviceExtension.Configuration);
2861 configuration->StallMicroseconds = I8042_STALL_DEFAULT;
2862 parametersPath.Buffer = NULL;
2863
2864 //
2865 // Registry path is already null-terminated, so just use it.
2866 //
2867
2868 path = RegistryPath->Buffer;
2869
2870 if (NT_SUCCESS(status)) {
2871
2872 //
2873 // Allocate the Rtl query table.
2874 //
2875
2876 parameters = ExAllocatePool(
2877 PagedPool,
2878 sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
2879 );
2880
2881 if (!parameters) {
2882
2883 I8xPrint((
2884 1,
2885 "I8042PRT-I8xServiceParameters: Couldn't allocate table for Rtl query to parameters for %ws\n",
2886 path
2887 ));
2888
2889 status = STATUS_UNSUCCESSFUL;
2890
2891 } else {
2892
2893 RtlZeroMemory(
2894 parameters,
2895 sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
2896 );
2897
2898 //
2899 // Form a path to this driver's Parameters subkey.
2900 //
2901
2902 RtlInitUnicodeString(
2903 &parametersPath,
2904 NULL
2905 );
2906
2907 parametersPath.MaximumLength = RegistryPath->Length +
2908 sizeof(L"\\Parameters");
2909
2910 parametersPath.Buffer = ExAllocatePool(
2911 PagedPool,
2912 parametersPath.MaximumLength
2913 );
2914
2915 if (!parametersPath.Buffer) {
2916
2917 I8xPrint((
2918 1,
2919 "I8042PRT-I8xServiceParameters: Couldn't allocate string for path to parameters for %ws\n",
2920 path
2921 ));
2922
2923 status = STATUS_UNSUCCESSFUL;
2924
2925 }
2926 }
2927 }
2928
2929 if (NT_SUCCESS(status)) {
2930
2931 //
2932 // Form the parameters path.
2933 //
2934
2935 RtlZeroMemory(
2936 parametersPath.Buffer,
2937 parametersPath.MaximumLength
2938 );
2939 RtlAppendUnicodeToString(
2940 &parametersPath,
2941 path
2942 );
2943 RtlAppendUnicodeToString(
2944 &parametersPath,
2945 L"\\Parameters"
2946 );
2947
2948 I8xPrint((
2949 1,
2950 "I8042PRT-I8xServiceParameters: parameters path is %ws\n",
2951 parametersPath.Buffer
2952 ));
2953
2954 //
2955 // Form the default port device names, in case they are not
2956 // specified in the registry.
2957 //
2958
2959 RtlInitUnicodeString(
2960 &defaultKeyboardName,
2961 DD_KEYBOARD_PORT_BASE_NAME_U
2962 );
2963 RtlInitUnicodeString(
2964 &defaultPointerName,
2965 DD_POINTER_PORT_BASE_NAME_U
2966 );
2967
2968 //
2969 // Gather all of the "user specified" information from
2970 // the registry.
2971 //
2972
2973 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2974 parameters[0].Name = L"ResendIterations";
2975 parameters[0].EntryContext = &resendIterations;
2976 parameters[0].DefaultType = REG_DWORD;
2977 parameters[0].DefaultData = &defaultResendIterations;
2978 parameters[0].DefaultLength = sizeof(USHORT);
2979
2980 parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2981 parameters[1].Name = L"PollingIterations";
2982 parameters[1].EntryContext = &pollingIterations;
2983 parameters[1].DefaultType = REG_DWORD;
2984 parameters[1].DefaultData = &defaultPollingIterations;
2985 parameters[1].DefaultLength = sizeof(USHORT);
2986
2987 parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
2988 parameters[2].Name = L"PollingIterationsMaximum";
2989 parameters[2].EntryContext = &pollingIterationsMaximum;
2990 parameters[2].DefaultType = REG_DWORD;
2991 parameters[2].DefaultData = &defaultPollingIterationsMaximum;
2992 parameters[2].DefaultLength = sizeof(USHORT);
2993
2994 parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
2995 parameters[3].Name = L"KeyboardDataQueueSize";
2996 parameters[3].EntryContext =
2997 &configuration->KeyboardAttributes.InputDataQueueLength;
2998 parameters[3].DefaultType = REG_DWORD;
2999 parameters[3].DefaultData = &defaultDataQueueSize;
3000 parameters[3].DefaultLength = sizeof(ULONG);
3001
3002 parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
3003 parameters[4].Name = L"MouseDataQueueSize";
3004 parameters[4].EntryContext =
3005 &configuration->MouseAttributes.InputDataQueueLength;
3006 parameters[4].DefaultType = REG_DWORD;
3007 parameters[4].DefaultData = &defaultDataQueueSize;
3008 parameters[4].DefaultLength = sizeof(ULONG);
3009
3010 parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
3011 parameters[5].Name = L"NumberOfButtons";
3012 parameters[5].EntryContext = &numberOfButtons;
3013 parameters[5].DefaultType = REG_DWORD;
3014 parameters[5].DefaultData = &defaultNumberOfButtons;
3015 parameters[5].DefaultLength = sizeof(USHORT);
3016
3017 parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
3018 parameters[6].Name = L"SampleRate";
3019 parameters[6].EntryContext = &sampleRate;
3020 parameters[6].DefaultType = REG_DWORD;
3021 parameters[6].DefaultData = &defaultSampleRate;
3022 parameters[6].DefaultLength = sizeof(USHORT);
3023
3024 parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
3025 parameters[7].Name = L"MouseResolution";
3026 parameters[7].EntryContext = &mouseResolution;
3027 parameters[7].DefaultType = REG_DWORD;
3028 parameters[7].DefaultData = &defaultMouseResolution;
3029 parameters[7].DefaultLength = sizeof(USHORT);
3030
3031 parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
3032 parameters[8].Name = L"OverrideKeyboardType";
3033 parameters[8].EntryContext = &overrideKeyboardType;
3034 parameters[8].DefaultType = REG_DWORD;
3035 parameters[8].DefaultData = &invalidKeyboardType;
3036 parameters[8].DefaultLength = sizeof(ULONG);
3037
3038 parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
3039 parameters[9].Name = L"OverrideKeyboardSubtype";
3040 parameters[9].EntryContext = &overrideKeyboardSubtype;
3041 parameters[9].DefaultType = REG_DWORD;
3042 parameters[9].DefaultData = &invalidKeyboardSubtype;
3043 parameters[9].DefaultLength = sizeof(ULONG);
3044
3045 parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT;
3046 parameters[10].Name = L"KeyboardDeviceBaseName";
3047 parameters[10].EntryContext = KeyboardDeviceName;
3048 parameters[10].DefaultType = REG_SZ;
3049 parameters[10].DefaultData = defaultKeyboardName.Buffer;
3050 parameters[10].DefaultLength = 0;
3051
3052 parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT;
3053 parameters[11].Name = L"PointerDeviceBaseName";
3054 parameters[11].EntryContext = PointerDeviceName;
3055 parameters[11].DefaultType = REG_SZ;
3056 parameters[11].DefaultData = defaultPointerName.Buffer;
3057 parameters[11].DefaultLength = 0;
3058
3059 parameters[12].Flags = RTL_QUERY_REGISTRY_DIRECT;
3060 parameters[12].Name = L"MouseSynchIn100ns";
3061 parameters[12].EntryContext =
3062 &(InitializationData->DeviceExtension.MouseExtension.SynchTickCount);
3063 parameters[12].DefaultType = REG_DWORD;
3064 parameters[12].DefaultData = &defaultSynchPacket100ns;
3065 parameters[12].DefaultLength = sizeof(ULONG);
3066
3067 parameters[13].Flags = RTL_QUERY_REGISTRY_DIRECT;
3068 parameters[13].Name = L"PollStatusIterations";
3069 parameters[13].EntryContext = &pollStatusIterations;
3070 parameters[13].DefaultType = REG_DWORD;
3071 parameters[13].DefaultData = &defaultPollStatusIterations;
3072 parameters[13].DefaultLength = sizeof(USHORT);
3073
3074 parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
3075 parameters[14].Name = L"EnableWheelDetection";
3076 parameters[14].EntryContext = &enableWheelDetection;
3077 parameters[14].DefaultType = REG_DWORD;
3078 parameters[14].DefaultData = &defaultEnableWheelDetection;
3079 parameters[14].DefaultLength = sizeof(ULONG);
3080
3081 status = RtlQueryRegistryValues(
3082 RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
3083 parametersPath.Buffer,
3084 parameters,
3085 NULL,
3086 NULL
3087 );
3088
3089 if (!NT_SUCCESS(status)) {
3090 I8xPrint((
3091 1,
3092 "I8042PRT-I8xServiceParameters: RtlQueryRegistryValues failed with 0x%x\n",
3093 status
3094 ));
3095 }
3096 }
3097
3098 if (!NT_SUCCESS(status)) {
3099
3100 //
3101 // Go ahead and assign driver defaults.
3102 //
3103
3104 configuration->ResendIterations = defaultResendIterations;
3105 configuration->PollingIterations = defaultPollingIterations;
3106 configuration->PollingIterationsMaximum =
3107 defaultPollingIterationsMaximum;
3108 configuration->PollStatusIterations = defaultPollStatusIterations;
3109 configuration->KeyboardAttributes.InputDataQueueLength =
3110 defaultDataQueueSize;
3111 configuration->MouseAttributes.InputDataQueueLength =
3112 defaultDataQueueSize;
3113 configuration->EnableWheelDetection =
3114 defaultEnableWheelDetection;
3115 InitializationData->DeviceExtension.MouseExtension.SynchTickCount =
3116 defaultSynchPacket100ns;
3117 RtlCopyUnicodeString(KeyboardDeviceName, &defaultKeyboardName);
3118 RtlCopyUnicodeString(PointerDeviceName, &defaultPointerName);
3119 } else {
3120 configuration->ResendIterations = (USHORT) resendIterations;
3121 configuration->PollingIterations = (USHORT) pollingIterations;
3122 configuration->PollingIterationsMaximum =
3123 (USHORT) pollingIterationsMaximum;
3124 configuration->PollStatusIterations = (USHORT) pollStatusIterations;
3125 configuration->EnableWheelDetection = (ULONG) ((enableWheelDetection) ? 1 : 0);
3126 }
3127
3128 I8xPrint((
3129 1,
3130 "I8042PRT-I8xServiceParameters: Keyboard port base name = %ws\n",
3131 KeyboardDeviceName->Buffer
3132 ));
3133
3134 I8xPrint((
3135 1,
3136 "I8042PRT-I8xServiceParameters: Pointer port base name = %ws\n",
3137 PointerDeviceName->Buffer
3138 ));
3139
3140 I8xPrint((
3141 1,
3142 "I8042PRT-I8xServiceParameters: StallMicroseconds = %d\n",
3143 configuration->StallMicroseconds
3144 ));
3145 I8xPrint((
3146 1,
3147 "I8042PRT-I8xServiceParameters: ResendIterations = %d\n",
3148 configuration->ResendIterations
3149 ));
3150 I8xPrint((
3151 1,
3152 "I8042PRT-I8xServiceParameters: PollingIterations = %d\n",
3153 configuration->PollingIterations
3154 ));
3155 I8xPrint((
3156 1,
3157 "I8042PRT-I8xServiceParameters: PollingIterationsMaximum = %d\n",
3158 configuration->PollingIterationsMaximum
3159 ));
3160 I8xPrint((
3161 1,
3162 "I8042PRT-I8xServiceParameters: PollStatusIterations = %d\n",
3163 configuration->PollStatusIterations
3164 ));
3165
3166 if (configuration->KeyboardAttributes.InputDataQueueLength == 0) {
3167
3168 I8xPrint((
3169 1,
3170 "I8042PRT-I8xServiceParameters: overriding KeyboardInputDataQueueLength = 0x%x\n",
3171 configuration->KeyboardAttributes.InputDataQueueLength
3172 ));
3173
3174 configuration->KeyboardAttributes.InputDataQueueLength =
3175 defaultDataQueueSize;
3176 }
3177
3178 configuration->KeyboardAttributes.InputDataQueueLength *=
3179 sizeof(KEYBOARD_INPUT_DATA);
3180
3181 I8xPrint((
3182 1,
3183 "I8042PRT-I8xServiceParameters: KeyboardInputDataQueueLength = 0x%x\n",
3184 configuration->KeyboardAttributes.InputDataQueueLength
3185 ));
3186
3187 if (configuration->MouseAttributes.InputDataQueueLength == 0) {
3188
3189 I8xPrint((
3190 1,
3191 "I8042PRT-I8xServiceParameters: overriding MouseInputDataQueueLength = 0x%x\n",
3192 configuration->MouseAttributes.InputDataQueueLength
3193 ));
3194
3195 configuration->MouseAttributes.InputDataQueueLength =
3196 defaultDataQueueSize;
3197 }
3198
3199 configuration->MouseAttributes.InputDataQueueLength *=
3200 sizeof(MOUSE_INPUT_DATA);
3201
3202 I8xPrint((
3203 1,
3204 "I8042PRT-I8xServiceParameters: MouseInputDataQueueLength = 0x%x\n",
3205 configuration->MouseAttributes.InputDataQueueLength
3206 ));
3207
3208 configuration->MouseAttributes.NumberOfButtons = (USHORT) numberOfButtons;
3209 I8xPrint((
3210 1,
3211 "I8042PRT-I8xServiceParameters: NumberOfButtons = %d\n",
3212 configuration->MouseAttributes.NumberOfButtons
3213 ));
3214
3215 configuration->MouseAttributes.SampleRate = (USHORT) sampleRate;
3216 I8xPrint((
3217 1,
3218 "I8042PRT-I8xServiceParameters: SampleRate = %d\n",
3219 configuration->MouseAttributes.SampleRate
3220 ));
3221
3222 configuration->MouseResolution = (USHORT) mouseResolution;
3223 I8xPrint((
3224 1,
3225 "I8042PRT-I8xServiceParameters: MouseResolution = %d\n",
3226 configuration->MouseResolution
3227 ));
3228
3229 if (overrideKeyboardType != invalidKeyboardType) {
3230 if (overrideKeyboardType <= NUM_KNOWN_KEYBOARD_TYPES) {
3231 I8xPrint((
3232 1,
3233 "I8042PRT-I8xServiceParameters: Override KeyboardType = %d\n",
3234 overrideKeyboardType
3235 ));
3236 configuration->KeyboardAttributes.KeyboardIdentifier.Type =
3237 (UCHAR) overrideKeyboardType;
3238 } else {
3239 I8xPrint((
3240 1,
3241 "I8042PRT-I8xServiceParameters: Invalid OverrideKeyboardType = %d\n",
3242 overrideKeyboardType
3243 ));
3244 }
3245 }
3246
3247 if (overrideKeyboardSubtype != invalidKeyboardSubtype) {
3248 I8xPrint((
3249 1,
3250 "I8042PRT-I8xServiceParameters: Override KeyboardSubtype = %d\n",
3251 overrideKeyboardSubtype
3252 ));
3253 configuration->KeyboardAttributes.KeyboardIdentifier.Subtype =
3254 (UCHAR) overrideKeyboardSubtype;
3255 }
3256
3257 if (InitializationData->DeviceExtension.MouseExtension.SynchTickCount == 0) {
3258
3259 I8xPrint((
3260 1,
3261 "I8042PRT-I8xServiceParameters: overriding MouseSynchIn100ns\n"
3262 ));
3263
3264 InitializationData->DeviceExtension.MouseExtension.SynchTickCount =
3265 defaultSynchPacket100ns;
3266 }
3267
3268 //
3269 // Convert SynchTickCount to be the number of interval timer
3270 // interrupts that occur during the time specified by MouseSynchIn100ns.
3271 // Note that KeQueryTimeIncrement returns the number of 100ns units that
3272 // are added to the system time each time the interval clock interrupts.
3273 //
3274
3275 InitializationData->DeviceExtension.MouseExtension.SynchTickCount /=
3276 KeQueryTimeIncrement();
3277
3278 I8xPrint((
3279 1,
3280 "I8042PRT-I8xServiceParameters: SynchTickCount = 0x%x\n",
3281 InitializationData->DeviceExtension.MouseExtension.SynchTickCount
3282 ));
3283
3284 I8xPrint((
3285 1,
3286 "I8042PRT-I8xServiceParameters: DisableWheelMouse = %#x\n",
3287 configuration->EnableWheelDetection
3288 ));
3289
3290 //
3291 // Free the allocated memory before returning.
3292 //
3293
3294 if (parametersPath.Buffer)
3295 ExFreePool(parametersPath.Buffer);
3296 if (parameters)
3297 ExFreePool(parameters);
3298
3299}
3300
3301
3302VOID
3303I8xTransmitControllerCommand(
3304 IN PDEVICE_EXTENSION DeviceExtension,
3305 IN PVOID Context
3306 )
3307
3308/*++
3309
3310Routine Description:
3311
3312 This routine reads the 8042 Controller Command Byte, performs an AND
3313 or OR operation using the specified ByteMask, and writes the resulting
3314 ControllerCommandByte.
3315
3316Arguments:
3317
3318 DeviceExtension - Pointer to the device extension.
3319
3320 Context - Pointer to a structure containing the HardwareDisableEnableMask,
3321 the AndOperation boolean, and the ByteMask to apply to the Controller
3322 Command Byte before it is rewritten.
3323
3324Return Value:
3325
3326 None. Status is returned in the Context structure.
3327
3328--*/
3329
3330{
3331 UCHAR controllerCommandByte;
3332 UCHAR verifyCommandByte;
3333 PI8042_TRANSMIT_CCB_CONTEXT transmitCCBContext;
3334 PIO_ERROR_LOG_PACKET errorLogEntry;
3335
3336 I8xPrint((3, "I8042PRT-I8xTransmitControllerCommand: enter\n"));
3337
3338 //
3339 // Grab the parameters from the Context structure.
3340 //
3341
3342 transmitCCBContext = (PI8042_TRANSMIT_CCB_CONTEXT) Context;
3343
3344 //
3345 // Get the current Controller Command Byte.
3346 //
3347
3348 transmitCCBContext->Status =
3349 I8xGetControllerCommand(
3350 transmitCCBContext->HardwareDisableEnableMask,
3351 DeviceExtension,
3352 &controllerCommandByte
3353 );
3354
3355 if (!NT_SUCCESS(transmitCCBContext->Status)) {
3356 return;
3357 }
3358
3359 I8xPrint((
3360 3,
3361 "I8042PRT-I8xTransmitControllerCommand: current CCB 0x%x\n",
3362 controllerCommandByte
3363 ));
3364
3365 //
3366 // Diddle the desired bits in the Controller Command Byte.
3367 //
3368
3369 if (transmitCCBContext->AndOperation)
3370 controllerCommandByte &= transmitCCBContext->ByteMask;
3371 else
3372 controllerCommandByte |= transmitCCBContext->ByteMask;
3373
3374 //
3375 // Write the new Controller Command Byte.
3376 //
3377
3378 transmitCCBContext->Status =
3379 I8xPutControllerCommand(DeviceExtension, controllerCommandByte);
3380
3381 I8xPrint((
3382 3,
3383 "I8042PRT-I8xTransmitControllerCommand: new CCB 0x%x\n",
3384 controllerCommandByte
3385 ));
3386
3387 //
3388 // Verify that the new Controller Command Byte really got written.
3389 //
3390
3391 transmitCCBContext->Status =
3392 I8xGetControllerCommand(
3393 transmitCCBContext->HardwareDisableEnableMask,
3394 DeviceExtension,
3395 &verifyCommandByte
3396 );
3397
3398 if (NT_SUCCESS(transmitCCBContext->Status)
3399 && (verifyCommandByte != controllerCommandByte)) {
3400 transmitCCBContext->Status = STATUS_DEVICE_DATA_ERROR;
3401
3402 //
3403 // Log an error.
3404 //
3405
3406 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
3407 DeviceExtension->DeviceObject,
3408 sizeof(IO_ERROR_LOG_PACKET)
3409 + (4 * sizeof(ULONG))
3410 );
3411 if (errorLogEntry != NULL) {
3412
3413 errorLogEntry->ErrorCode = I8042_CCB_WRITE_FAILED;
3414 errorLogEntry->DumpDataSize = 4 * sizeof(ULONG);
3415 errorLogEntry->SequenceNumber = 0;
3416 errorLogEntry->MajorFunctionCode = 0;
3417 errorLogEntry->IoControlCode = 0;
3418 errorLogEntry->RetryCount = 0;
3419 errorLogEntry->UniqueErrorValue = 80;
3420 errorLogEntry->FinalStatus = transmitCCBContext->Status;
3421 errorLogEntry->DumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
3422 errorLogEntry->DumpData[1] = DataPort;
3423 errorLogEntry->DumpData[2] = I8042_WRITE_CONTROLLER_COMMAND_BYTE;
3424 errorLogEntry->DumpData[3] = controllerCommandByte;
3425
3426 IoWriteErrorLogEntry(errorLogEntry);
3427 }
3428
3429 }
3430
3431 I8xPrint((3, "I8042PRT-I8xTransmitControllerCommand: exit\n"));
3432
3433 return;
3434
3435}
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