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