208916d187a9d2b0228076069c6be8759b98f459
[reactos.git] / reactos / drivers / input / i8042prt / i8042prt.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/input/i8042prt/i8042prt.c
5 * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
6 * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
7 * Jason Filby (jasonfilby@yahoo.com)
8 * Tinus
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #define NDEBUG
14 #include <debug.h>
15
16 #include "i8042prt.h"
17
18 /* GLOBALS *******************************************************************/
19
20 /*
21 * Driver data
22 */
23 #define I8042_TIMEOUT 500000
24
25 #define I8042_MAX_COMMAND_LENGTH 16
26 #define I8042_MAX_UPWARDS_STACK 5
27
28 UNICODE_STRING I8042RegistryPath;
29
30 /* FUNCTIONS *****************************************************************/
31
32 /*
33 * FUNCTION: Write data to a port, waiting first for it to become ready
34 */
35 BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, PUCHAR addr, UCHAR data)
36 {
37 ULONG ResendIterations = DevExt->Settings.PollingIterations;
38
39 while ((KBD_IBF & READ_PORT_UCHAR(I8042_CTRL_PORT)) &&
40 (ResendIterations--))
41 {
42 KeStallExecutionProcessor(50);
43 }
44
45 if (ResendIterations) {
46 WRITE_PORT_UCHAR(addr,data);
47 DPRINT("Sent %x to %x\n", data, addr);
48 return TRUE;
49 }
50 return FALSE;
51 }
52
53 #if 0 /* function is not needed */
54 /*
55 * FUNCTION: Write data to a port, without waiting first
56 */
57 static BOOLEAN I8042WriteNoWait(PDEVICE_EXTENSION DevExt, int addr, UCHAR data)
58 {
59 WRITE_PORT_UCHAR((PUCHAR)addr,data);
60 DPRINT("Sent %x to %x\n", data, addr);
61 return TRUE;
62 }
63 #endif
64
65 /*
66 * FUNCTION: Read data from port 0x60
67 */
68 NTSTATUS I8042ReadData(UCHAR *Data)
69 {
70 UCHAR Status;
71 Status=READ_PORT_UCHAR(I8042_CTRL_PORT);
72
73 // If data is available
74 if ((Status & KBD_OBF)) {
75 Data[0]=READ_PORT_UCHAR((PUCHAR)I8042_DATA_PORT);
76 DPRINT("Read: %x (status: %x)\n", Data[0], Status);
77
78 // If the data is valid (not timeout, not parity error)
79 if (0 == (Status & KBD_PERR))
80 return STATUS_SUCCESS;
81 }
82 return STATUS_UNSUCCESSFUL;
83 }
84
85 NTSTATUS I8042ReadStatus(UCHAR *Status)
86 {
87 Status[0]=READ_PORT_UCHAR(I8042_CTRL_PORT);
88 return STATUS_SUCCESS;
89 }
90
91 /*
92 * FUNCTION: Read data from port 0x60
93 */
94 NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, UCHAR *Data)
95 {
96 ULONG Counter = DevExt->Settings.PollingIterations;
97 NTSTATUS Status;
98
99 while (Counter--) {
100 Status = I8042ReadData(Data);
101
102 if (STATUS_SUCCESS == Status)
103 return Status;
104
105 KeStallExecutionProcessor(50);
106 }
107 // Timed out
108 return STATUS_IO_TIMEOUT;
109 }
110
111 VOID I8042Flush()
112 {
113 UCHAR Ignore;
114
115 while (STATUS_SUCCESS == I8042ReadData(&Ignore)) {
116 DPRINT("Data flushed\n"); /* drop */
117 }
118 }
119
120 VOID STDCALL I8042IsrWritePort(PDEVICE_EXTENSION DevExt,
121 UCHAR Value,
122 UCHAR SelectCmd)
123 {
124 if (SelectCmd)
125 if (!I8042Write(DevExt, I8042_CTRL_PORT, SelectCmd))
126 return;
127
128 I8042Write(DevExt, I8042_DATA_PORT, Value);
129 }
130
131 /*
132 * These functions are callbacks for filter driver custom
133 * initialization routines.
134 */
135 NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
136 UCHAR Port,
137 UCHAR Value,
138 BOOLEAN WaitForAck)
139 {
140 NTSTATUS Status;
141 UCHAR Ack;
142 ULONG ResendIterations = DevExt->Settings.ResendIterations + 1;
143
144 do {
145 if (Port)
146 if (!I8042Write(DevExt, I8042_DATA_PORT, Port))
147 {
148 DPRINT1("Failed to write Port\n");
149 return STATUS_IO_TIMEOUT;
150 }
151
152 if (!I8042Write(DevExt, I8042_DATA_PORT, Value))
153 {
154 DPRINT1("Failed to write Value\n");
155 return STATUS_IO_TIMEOUT;
156 }
157
158 if (WaitForAck) {
159 Status = I8042ReadDataWait(DevExt, &Ack);
160 if (!NT_SUCCESS(Status))
161 {
162 DPRINT1("Failed to read Ack\n");
163 return Status;
164 }
165 if (Ack == KBD_ACK)
166 return STATUS_SUCCESS;
167 if (Ack != KBD_RESEND)
168 {
169 DPRINT1("Unexpected Ack 0x%x\n", Ack);
170 return STATUS_UNEXPECTED_IO_ERROR;
171 }
172 } else {
173 return STATUS_SUCCESS;
174 }
175 DPRINT("Reiterating\n");
176 ResendIterations--;
177 } while (ResendIterations);
178 return STATUS_IO_TIMEOUT;
179 }
180
181 /*
182 * This one reads a value from the port; You don't have to specify
183 * which one, it'll always be from the one you talked to, so one function
184 * is enough this time. Note how MSDN specifies the
185 * WaitForAck parameter to be ignored.
186 */
187 static NTSTATUS STDCALL I8042SynchReadPort(PVOID Context,
188 PUCHAR Value,
189 BOOLEAN WaitForAck)
190 {
191 PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)Context;
192
193 return I8042ReadDataWait(DevExt, Value);
194 }
195
196 /* Write the current byte of the packet. Returns FALSE in case
197 * of problems.
198 */
199 static BOOLEAN STDCALL I8042PacketWrite(PDEVICE_EXTENSION DevExt)
200 {
201 UCHAR Port = DevExt->PacketPort;
202
203 if (Port) {
204 if (!I8042Write(DevExt,
205 I8042_CTRL_PORT,
206 Port)) {
207 /* something is really wrong! */
208 DPRINT1("Failed to send packet byte!\n");
209 return FALSE;
210 }
211 }
212
213 return I8042Write(DevExt,
214 I8042_DATA_PORT,
215 DevExt->Packet.Bytes[DevExt->Packet.CurrentByte]);
216 }
217
218
219 /*
220 * This function starts a packet. It must be called with the
221 * correct DIRQL.
222 */
223 NTSTATUS STDCALL I8042StartPacket(PDEVICE_EXTENSION DevExt,
224 PDEVICE_OBJECT Device,
225 PUCHAR Bytes,
226 ULONG ByteCount,
227 PIRP Irp)
228 {
229 KIRQL Irql;
230 NTSTATUS Status;
231 PFDO_DEVICE_EXTENSION FdoDevExt = Device->DeviceExtension;
232
233 Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
234
235 DevExt->CurrentIrp = Irp;
236 DevExt->CurrentIrpDevice = Device;
237
238 if (Idle != DevExt->Packet.State) {
239 Status = STATUS_DEVICE_BUSY;
240 goto startpacketdone;
241 }
242
243 DevExt->Packet.Bytes = Bytes;
244 DevExt->Packet.CurrentByte = 0;
245 DevExt->Packet.ByteCount = ByteCount;
246 DevExt->Packet.State = SendingBytes;
247 DevExt->PacketResult = Status = STATUS_PENDING;
248
249 if (Mouse == FdoDevExt->Type)
250 DevExt->PacketPort = 0xD4;
251 else
252 DevExt->PacketPort = 0;
253
254 if (!I8042PacketWrite(DevExt)) {
255 Status = STATUS_IO_TIMEOUT;
256 DevExt->Packet.State = Idle;
257 DevExt->PacketResult = STATUS_ABANDONED;
258 goto startpacketdone;
259 }
260
261 DevExt->Packet.CurrentByte++;
262
263 startpacketdone:
264 KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
265
266 if (STATUS_PENDING != Status) {
267 DevExt->CurrentIrp = NULL;
268 DevExt->CurrentIrpDevice = NULL;
269 Irp->IoStatus.Status = Status;
270 IoCompleteRequest(Irp, IO_NO_INCREMENT);
271 }
272 return Status;
273 }
274
275 BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
276 UCHAR Output)
277 {
278 if (Idle == DevExt->Packet.State)
279 return FALSE;
280
281 switch (Output) {
282 case KBD_RESEND:
283 DevExt->PacketResends++;
284 if (DevExt->PacketResends > DevExt->Settings.ResendIterations) {
285 DevExt->Packet.State = Idle;
286 DevExt->PacketComplete = TRUE;
287 DevExt->PacketResult = STATUS_IO_TIMEOUT;
288 DevExt->PacketResends = 0;
289 return TRUE;
290 }
291 DevExt->Packet.CurrentByte--;
292 break;
293
294 case KBD_NACK:
295 DevExt->Packet.State = Idle;
296 DevExt->PacketComplete = TRUE;
297 DevExt->PacketResult = STATUS_UNEXPECTED_IO_ERROR;
298 DevExt->PacketResends = 0;
299 return TRUE;
300
301 default:
302 DevExt->PacketResends = 0;
303 }
304
305 if (DevExt->Packet.CurrentByte >= DevExt->Packet.ByteCount) {
306 DevExt->Packet.State = Idle;
307 DevExt->PacketComplete = TRUE;
308 DevExt->PacketResult = STATUS_SUCCESS;
309 return TRUE;
310 }
311
312 if (!I8042PacketWrite(DevExt)) {
313 DevExt->Packet.State = Idle;
314 DevExt->PacketComplete = TRUE;
315 DevExt->PacketResult = STATUS_IO_TIMEOUT;
316 return TRUE;
317 }
318 DevExt->Packet.CurrentByte++;
319
320 return TRUE;
321 }
322
323 VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt)
324 {
325 BOOLEAN FinishIrp = FALSE;
326 NTSTATUS Result = STATUS_INTERNAL_ERROR; /* Shouldn't happen */
327 KIRQL Irql;
328
329 /* If the interrupt happens before this is setup, the key
330 * was already in the buffer. Too bad! */
331 if (!DevExt->HighestDIRQLInterrupt)
332 return;
333
334 Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
335
336 if (Idle == DevExt->Packet.State &&
337 DevExt->PacketComplete) {
338 FinishIrp = TRUE;
339 Result = DevExt->PacketResult;
340 DevExt->PacketComplete = FALSE;
341 }
342
343 KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt,
344 Irql);
345
346 if (!FinishIrp)
347 return;
348
349 if (DevExt->CurrentIrp) {
350 DevExt->CurrentIrp->IoStatus.Status = Result;
351 IoCompleteRequest(DevExt->CurrentIrp, IO_NO_INCREMENT);
352 IoStartNextPacket(DevExt->CurrentIrpDevice, FALSE);
353 DevExt->CurrentIrp = NULL;
354 DevExt->CurrentIrpDevice = NULL;
355 }
356 }
357
358 VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject,
359 PVOID Context)
360 {
361 KEVENT Event;
362 IO_STATUS_BLOCK IoStatus;
363 NTSTATUS Status;
364 PDEVICE_EXTENSION DevExt;
365 PFDO_DEVICE_EXTENSION FdoDevExt;
366 PIRP NewIrp;
367 PI8042_HOOK_WORKITEM WorkItemData = (PI8042_HOOK_WORKITEM)Context;
368
369 ULONG IoControlCode;
370 PVOID InputBuffer;
371 ULONG InputBufferLength;
372 BOOLEAN IsKbd;
373
374 DPRINT("HookWorkItem\n");
375
376 FdoDevExt = (PFDO_DEVICE_EXTENSION)
377 DeviceObject->DeviceExtension;
378
379 DevExt = FdoDevExt->PortDevExt;
380
381 if (WorkItemData->Target == DevExt->KeyboardData.ClassDeviceObject) {
382 IoControlCode = IOCTL_INTERNAL_I8042_HOOK_KEYBOARD;
383 InputBuffer = &DevExt->KeyboardHook;
384 InputBufferLength = sizeof(INTERNAL_I8042_HOOK_KEYBOARD);
385 IsKbd = TRUE;
386 DPRINT ("is for keyboard.\n");
387 } else if (WorkItemData->Target == DevExt->MouseData.ClassDeviceObject){
388 IoControlCode = IOCTL_INTERNAL_I8042_HOOK_MOUSE;
389 InputBuffer = &DevExt->MouseHook;
390 InputBufferLength = sizeof(INTERNAL_I8042_HOOK_MOUSE);
391 IsKbd = FALSE;
392 DPRINT ("is for mouse.\n");
393 } else {
394 DPRINT1("I8042SendHookWorkItem: Can't find DeviceObject\n");
395 WorkItemData->Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
396 goto hookworkitemdone;
397 }
398
399 KeInitializeEvent(&Event, NotificationEvent, FALSE);
400
401 NewIrp = IoBuildDeviceIoControlRequest(
402 IoControlCode,
403 WorkItemData->Target,
404 InputBuffer,
405 InputBufferLength,
406 NULL,
407 0,
408 TRUE,
409 &Event,
410 &IoStatus);
411
412 if (!NewIrp) {
413 DPRINT("IOCTL_INTERNAL_(device)_CONNECT: "
414 "Can't allocate IRP\n");
415 WorkItemData->Irp->IoStatus.Status =
416 STATUS_INSUFFICIENT_RESOURCES;
417 goto hookworkitemdone;
418 }
419
420 Status = IoCallDriver(
421 WorkItemData->Target,
422 NewIrp);
423
424 if (STATUS_PENDING == Status)
425 KeWaitForSingleObject(&Event,
426 Executive,
427 KernelMode,
428 FALSE,
429 NULL);
430
431 if (IsKbd) {
432 /* Call the hooked initialization if it exists */
433 if (DevExt->KeyboardHook.InitializationRoutine) {
434 Status = DevExt->KeyboardHook.InitializationRoutine(
435 DevExt->KeyboardHook.Context,
436 DevExt,
437 I8042SynchReadPort,
438 I8042SynchWritePortKbd,
439 FALSE);
440 if (!NT_SUCCESS(Status)) {
441 WorkItemData->Irp->IoStatus.Status = Status;
442 goto hookworkitemdone;
443 }
444 }
445 /* TODO: Now would be the right time to enable the interrupt */
446
447 DevExt->KeyboardClaimed = TRUE;
448 } else {
449 /* Mouse doesn't have this, but we need to send a
450 * reset to start the detection.
451 */
452 KIRQL Irql;
453
454 Irql = KeAcquireInterruptSpinLock(
455 DevExt->HighestDIRQLInterrupt);
456
457 I8042Write(DevExt, I8042_CTRL_PORT, 0xD4);
458 I8042Write(DevExt, I8042_DATA_PORT, 0xFF);
459
460 KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
461 }
462
463 WorkItemData->Irp->IoStatus.Status = STATUS_SUCCESS;
464
465 hookworkitemdone:
466 WorkItemData->Irp->IoStatus.Information = 0;
467 IoCompleteRequest(WorkItemData->Irp, IO_NO_INCREMENT);
468
469 IoFreeWorkItem(WorkItemData->WorkItem);
470 ExFreePool(WorkItemData);
471 DPRINT("HookWorkItem done\n");
472 }
473
474 static VOID STDCALL I8042StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
475 {
476 if (!I8042StartIoKbd(DeviceObject, Irp)) {
477 DPRINT1("Unhandled StartIo!\n");
478 }
479 }
480
481 static NTSTATUS STDCALL I8042InternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
482 {
483 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
484 PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
485
486 DPRINT("InternalDeviceControl\n");
487
488 switch (FdoDevExt->Type) {
489 case Keyboard:
490 Status = I8042InternalDeviceControlKbd(DeviceObject, Irp);
491 break;
492 case Mouse:
493 Status = I8042InternalDeviceControlMouse(DeviceObject, Irp);
494 break;
495 }
496
497 if (Status == STATUS_INVALID_DEVICE_REQUEST) {
498 DPRINT1("Invalid internal device request!\n");
499 }
500
501 if (Status != STATUS_PENDING)
502 IoCompleteRequest(Irp, IO_NO_INCREMENT);
503
504 return Status;
505 }
506
507 static NTSTATUS STDCALL I8042CreateDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
508 {
509 NTSTATUS Status;
510
511 DPRINT ("I8042CreateDispatch\n");
512
513 Status = STATUS_SUCCESS;
514
515 Irp->IoStatus.Status = Status;
516 Irp->IoStatus.Information = 0;
517 IoCompleteRequest(Irp, IO_NO_INCREMENT);
518
519 return Status;
520 }
521
522 static NTSTATUS STDCALL I8042BasicDetect(PDEVICE_EXTENSION DevExt)
523 {
524 NTSTATUS Status;
525 UCHAR Value = 0;
526 ULONG Counter;
527
528 DevExt->MouseExists = FALSE;
529 DevExt->KeyboardExists = FALSE;
530
531 I8042Flush();
532
533 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST)) {
534 DPRINT1("Writing KBD_SELF_TEST command failed\n");
535 return STATUS_IO_TIMEOUT;
536 }
537
538 // Wait longer?
539 Counter = 3;
540 do {
541 Status = I8042ReadDataWait(DevExt, &Value);
542 } while ((Counter--) && (STATUS_IO_TIMEOUT == Status));
543
544 if (!NT_SUCCESS(Status)) {
545 DPRINT1("Failed to read KBD_SELF_TEST response, status 0x%x\n",
546 Status);
547 return Status;
548 }
549
550 if (Value != 0x55) {
551 DPRINT1("Got %x instead of 55\n", Value);
552 return STATUS_IO_DEVICE_ERROR;
553 }
554
555 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
556 DPRINT1("Can't read i8042 mode\n");
557 return FALSE;
558 }
559
560 Status = I8042ReadDataWait(DevExt, &Value);
561 if (!NT_SUCCESS(Status)) {
562 DPRINT1("No response after read i8042 mode\n");
563 return FALSE;
564 }
565
566 Value |= CCB_KBD_DISAB | CCB_MOUSE_DISAB; /* disable keyboard/mouse */
567 Value &= ~(CCB_KBD_INT_ENAB | CCB_MOUSE_INT_ENAB);
568 /* don't enable keyboard and mouse interrupts */
569
570 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
571 DPRINT1("Can't set i8042 mode\n");
572 return FALSE;
573 }
574
575 if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
576 DPRINT1("Can't send i8042 mode\n");
577 return FALSE;
578 }
579
580 /*
581 * We used to send a KBD_LINE_TEST command here, but on at least HP
582 * Pavilion notebooks the response to that command was incorrect.
583 * So now we just assume that a keyboard is attached.
584 */
585 DevExt->KeyboardExists = TRUE;
586
587 if (I8042Write(DevExt, I8042_CTRL_PORT, MOUSE_LINE_TEST))
588 {
589 Status = I8042ReadDataWait(DevExt, &Value);
590 if (NT_SUCCESS(Status) && Value == 0)
591 DevExt->MouseExists = TRUE;
592 }
593
594 return STATUS_SUCCESS;
595 }
596
597 static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt)
598 {
599 NTSTATUS Status;
600
601 Status = I8042BasicDetect(DevExt);
602 if (!NT_SUCCESS(Status)) {
603 DPRINT1("Basic keyboard detection failed: %x\n", Status);
604 return Status;
605 }
606
607 if (DevExt->MouseExists) {
608 DPRINT("Aux port detected\n");
609 DevExt->MouseExists = I8042DetectMouse(DevExt);
610 }
611
612 if (!DevExt->KeyboardExists) {
613 DPRINT("Keyboard port not detected\n");
614 if (DevExt->Settings.Headless)
615 /* Act as if it exists regardless */
616 DevExt->KeyboardExists = TRUE;
617 } else {
618 DPRINT("Keyboard port detected\n");
619 DevExt->KeyboardExists = I8042DetectKeyboard(DevExt);
620 }
621
622 if (DevExt->KeyboardExists) {
623 DPRINT("Keyboard detected\n");
624 I8042KeyboardEnable(DevExt);
625 I8042KeyboardEnableInterrupt(DevExt);
626 }
627
628 if (DevExt->MouseExists) {
629 DPRINT("Mouse detected\n");
630 I8042MouseEnable(DevExt);
631 }
632
633 return STATUS_SUCCESS;
634 }
635
636 static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject,
637 PDEVICE_OBJECT Pdo)
638 {
639 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
640 UNICODE_STRING MouseName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0");
641 ULONG MappedIrqKeyboard = 0, MappedIrqMouse = 0;
642 KIRQL DirqlKeyboard = 0;
643 KIRQL DirqlMouse = 0;
644 KIRQL DirqlMax;
645 KAFFINITY Affinity;
646 NTSTATUS Status;
647 PDEVICE_EXTENSION DevExt;
648 PFDO_DEVICE_EXTENSION FdoDevExt;
649 PDEVICE_OBJECT Fdo;
650 static BOOLEAN AlreadyAdded = FALSE;
651
652 DPRINT("I8042AddDevice\n");
653
654 /* HACK! */
655 if (AlreadyAdded)
656 return STATUS_UNSUCCESSFUL;
657 AlreadyAdded = TRUE;
658
659 Status = IoCreateDevice(DriverObject,
660 sizeof(DEVICE_EXTENSION),
661 NULL,
662 FILE_DEVICE_8042_PORT,
663 FILE_DEVICE_SECURE_OPEN,
664 TRUE,
665 &Fdo);
666
667 if (!NT_SUCCESS(Status))
668 return Status;
669
670 IoAttachDeviceToDeviceStack(Fdo, Pdo);
671
672 DevExt = Fdo->DeviceExtension;
673
674 RtlZeroMemory(DevExt, sizeof(DEVICE_EXTENSION));
675
676 I8042ReadRegistry(DriverObject, DevExt);
677
678 KeInitializeSpinLock(&DevExt->SpinLock);
679 InitializeListHead(&DevExt->BusDevices);
680
681 KeInitializeDpc(&DevExt->DpcKbd,
682 I8042DpcRoutineKbd,
683 DevExt);
684
685 KeInitializeDpc(&DevExt->DpcMouse,
686 I8042DpcRoutineMouse,
687 DevExt);
688
689 KeInitializeDpc(&DevExt->DpcMouseTimeout,
690 I8042DpcRoutineMouseTimeout,
691 DevExt);
692
693 KeInitializeTimer(&DevExt->TimerMouseTimeout);
694
695 Status = I8042Initialize(DevExt);
696 if (!NT_SUCCESS(STATUS_SUCCESS)) {
697 DPRINT1("Initialization failure: %x\n", Status);
698 return Status;
699 }
700
701 if (DevExt->KeyboardExists) {
702 MappedIrqKeyboard = HalGetInterruptVector(Internal,
703 0,
704 0,
705 KEYBOARD_IRQ,
706 &DirqlKeyboard,
707 &Affinity);
708
709 Status = IoCreateDevice(DriverObject,
710 sizeof(FDO_DEVICE_EXTENSION),
711 &DeviceName,
712 FILE_DEVICE_8042_PORT,
713 FILE_DEVICE_SECURE_OPEN,
714 TRUE,
715 &Fdo);
716
717 if (NT_SUCCESS(Status))
718 {
719 FdoDevExt = Fdo->DeviceExtension;
720
721 RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
722
723 FdoDevExt->PortDevExt = DevExt;
724 FdoDevExt->Type = Keyboard;
725 FdoDevExt->DeviceObject = Fdo;
726
727 Fdo->Flags |= DO_BUFFERED_IO;
728
729 DevExt->DebugWorkItem = IoAllocateWorkItem(Fdo);
730 DevExt->KeyboardObject = Fdo;
731
732 DevExt->KeyboardBuffer = ExAllocatePoolWithTag(
733 NonPagedPool,
734 DevExt->KeyboardAttributes.InputDataQueueLength *
735 sizeof(KEYBOARD_INPUT_DATA),
736 TAG_I8042);
737
738 if (!DevExt->KeyboardBuffer) {
739 DPRINT1("No memory for keyboardbuffer\n");
740 return STATUS_INSUFFICIENT_RESOURCES;
741 }
742
743 InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
744 }
745 else
746 DevExt->KeyboardExists = FALSE;
747 }
748
749 if (DevExt->MouseExists) {
750 MappedIrqMouse = HalGetInterruptVector(Internal,
751 0,
752 0,
753 MOUSE_IRQ,
754 &DirqlMouse,
755 &Affinity);
756
757 Status = IoCreateDevice(DriverObject,
758 sizeof(FDO_DEVICE_EXTENSION),
759 &MouseName,
760 FILE_DEVICE_8042_PORT,
761 FILE_DEVICE_SECURE_OPEN,
762 TRUE,
763 &Fdo);
764
765 if (NT_SUCCESS(Status))
766 {
767 FdoDevExt = Fdo->DeviceExtension;
768
769 RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
770
771 FdoDevExt->PortDevExt = DevExt;
772 FdoDevExt->Type = Mouse;
773 FdoDevExt->DeviceObject = Fdo;
774
775 Fdo->Flags |= DO_BUFFERED_IO;
776 DevExt->MouseObject = Fdo;
777
778 DevExt->MouseBuffer = ExAllocatePoolWithTag(
779 NonPagedPool,
780 DevExt->MouseAttributes.InputDataQueueLength *
781 sizeof(MOUSE_INPUT_DATA),
782 TAG_I8042);
783
784 if (!DevExt->MouseBuffer) {
785 ExFreePoolWithTag(DevExt->KeyboardBuffer, TAG_I8042);
786 DPRINT1("No memory for mouse buffer\n");
787 return STATUS_INSUFFICIENT_RESOURCES;
788 }
789
790 InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
791 }
792 else
793 DevExt->MouseExists = FALSE;
794 }
795
796 if (DirqlKeyboard > DirqlMouse)
797 DirqlMax = DirqlKeyboard;
798 else
799 DirqlMax = DirqlMouse;
800
801 if (DevExt->KeyboardExists) {
802 Status = IoConnectInterrupt(&DevExt->KeyboardInterruptObject,
803 I8042InterruptServiceKbd,
804 (PVOID)DevExt,
805 &DevExt->SpinLock,
806 MappedIrqKeyboard,
807 DirqlKeyboard,
808 DirqlMax,
809 LevelSensitive,
810 FALSE,
811 Affinity,
812 FALSE);
813
814 DPRINT("Keyboard Irq Status: %x\n", Status);
815 }
816
817 if (DevExt->MouseExists) {
818 Status = IoConnectInterrupt(&DevExt->MouseInterruptObject,
819 I8042InterruptServiceMouse,
820 (PVOID)DevExt,
821 &DevExt->SpinLock,
822 MappedIrqMouse,
823 DirqlMouse,
824 DirqlMax,
825 LevelSensitive,
826 FALSE,
827 Affinity,
828 FALSE);
829
830 DPRINT("Mouse Irq Status: %x\n", Status);
831 }
832
833 if (DirqlKeyboard > DirqlMouse)
834 DevExt->HighestDIRQLInterrupt = DevExt->KeyboardInterruptObject;
835 else
836 DevExt->HighestDIRQLInterrupt = DevExt->MouseInterruptObject;
837
838 DPRINT("I8042AddDevice done\n");
839
840 return(STATUS_SUCCESS);
841 }
842
843 NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
844 PUNICODE_STRING RegistryPath)
845 /*
846 * FUNCTION: Module entry point
847 */
848 {
849 DPRINT("I8042 Driver 0.0.1\n");
850
851 I8042RegistryPath.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters");
852 I8042RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
853 I8042RegistryPath.MaximumLength,
854 TAG_I8042);
855 if (I8042RegistryPath.Buffer == NULL) {
856
857 return STATUS_INSUFFICIENT_RESOURCES;
858 }
859
860 RtlCopyUnicodeString(&I8042RegistryPath, RegistryPath);
861 RtlAppendUnicodeToString(&I8042RegistryPath, L"\\Parameters");
862 I8042RegistryPath.Buffer[I8042RegistryPath.Length / sizeof(WCHAR)] = 0;
863
864
865
866 DriverObject->MajorFunction[IRP_MJ_CREATE] = I8042CreateDispatch;
867 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
868 I8042InternalDeviceControl;
869
870 DriverObject->DriverStartIo = I8042StartIo;
871 DriverObject->DriverExtension->AddDevice = I8042AddDevice;
872
873 return(STATUS_SUCCESS);
874 }