Remove mouse device detection for now, since it fails on some i8042 clones.
[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 (!NT_SUCCESS(Status))
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 (!NT_SUCCESS(Status)) {
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 = 0;
515 UINT Counter;
516
517 DevExt->MouseExists = FALSE;
518 DevExt->KeyboardExists = FALSE;
519
520 if (!I8042Write(DevExt, I8042_DATA_PORT, 0x74))
521 return STATUS_TIMEOUT;
522
523 I8042Flush();
524
525 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST))
526 return STATUS_TIMEOUT;
527
528 // Wait longer?
529 Counter = 3;
530 do {
531 Status = I8042ReadDataWait(DevExt, &Value);
532 } while ((Counter--) && (STATUS_TIMEOUT == Status));
533
534 if (!NT_SUCCESS(Status))
535 return Status;
536
537 if (Value != 0x55) {
538 DPRINT1("Got %x instead of 55\n", Value);
539 return STATUS_IO_DEVICE_ERROR;
540 }
541
542 if (I8042Write(DevExt, I8042_CTRL_PORT, KBD_LINE_TEST))
543 {
544 Status = I8042ReadDataWait(DevExt, &Value);
545 if (NT_SUCCESS(Status) && Value == 0)
546 DevExt->KeyboardExists = TRUE;
547 }
548
549 if (I8042Write(DevExt, I8042_CTRL_PORT, MOUSE_LINE_TEST))
550 {
551 Status = I8042ReadDataWait(DevExt, &Value);
552 if (NT_SUCCESS(Status) && Value == 0)
553 DevExt->MouseExists = TRUE;
554 }
555
556 return STATUS_SUCCESS;
557 }
558
559 static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt)
560 {
561 NTSTATUS Status;
562
563 Status = I8042BasicDetect(DevExt);
564 if (!NT_SUCCESS(Status)) {
565 DPRINT1("Basic keyboard detection failed: %x\n", Status);
566 return Status;
567 }
568
569 if (!DevExt->KeyboardExists) {
570 DPRINT("Keyboard port not detected\n");
571 if (DevExt->Settings.Headless)
572 /* Act as if it exists regardless */
573 DevExt->KeyboardExists = TRUE;
574 } else {
575 DPRINT("Keyboard port detected\n");
576 DevExt->KeyboardExists = I8042DetectKeyboard(DevExt);
577 }
578
579 if (DevExt->KeyboardExists) {
580 DPRINT("Keyboard detected\n");
581 I8042KeyboardEnable(DevExt);
582 I8042KeyboardEnableInterrupt(DevExt);
583 }
584
585 if (DevExt->MouseExists) {
586 DPRINT("Mouse detected\n");
587 I8042MouseEnable(DevExt);
588 }
589
590 return STATUS_SUCCESS;
591 }
592
593 static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject,
594 PDEVICE_OBJECT Pdo)
595 {
596 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
597 UNICODE_STRING MouseName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0");
598 ULONG MappedIrqKeyboard = 0, MappedIrqMouse = 0;
599 KIRQL DirqlKeyboard = 0;
600 KIRQL DirqlMouse = 0;
601 KIRQL DirqlMax;
602 KAFFINITY Affinity;
603 NTSTATUS Status;
604 PDEVICE_EXTENSION DevExt;
605 PFDO_DEVICE_EXTENSION FdoDevExt;
606 PDEVICE_OBJECT Fdo;
607
608 DPRINT("I8042AddDevice\n");
609
610 Status = IoCreateDevice(DriverObject,
611 sizeof(DEVICE_EXTENSION),
612 NULL,
613 FILE_DEVICE_8042_PORT,
614 FILE_DEVICE_SECURE_OPEN,
615 TRUE,
616 &Fdo);
617
618 if (!NT_SUCCESS(Status))
619 return Status;
620
621 IoAttachDeviceToDeviceStack(Fdo, Pdo);
622
623 DevExt = Fdo->DeviceExtension;
624
625 RtlZeroMemory(DevExt, sizeof(DEVICE_EXTENSION));
626
627 I8042ReadRegistry(DriverObject, DevExt);
628
629 KeInitializeSpinLock(&DevExt->SpinLock);
630 InitializeListHead(&DevExt->BusDevices);
631
632 KeInitializeDpc(&DevExt->DpcKbd,
633 I8042DpcRoutineKbd,
634 DevExt);
635
636 KeInitializeDpc(&DevExt->DpcMouse,
637 I8042DpcRoutineMouse,
638 DevExt);
639
640 KeInitializeDpc(&DevExt->DpcMouseTimeout,
641 I8042DpcRoutineMouseTimeout,
642 DevExt);
643
644 KeInitializeTimer(&DevExt->TimerMouseTimeout);
645
646 Status = I8042Initialize(DevExt);
647 if (!NT_SUCCESS(STATUS_SUCCESS)) {
648 DPRINT1("Initialization failure: %x\n", Status);
649 return Status;
650 }
651
652 if (DevExt->KeyboardExists) {
653 MappedIrqKeyboard = HalGetInterruptVector(Internal,
654 0,
655 0,
656 KEYBOARD_IRQ,
657 &DirqlKeyboard,
658 &Affinity);
659
660 Status = IoCreateDevice(DriverObject,
661 sizeof(FDO_DEVICE_EXTENSION),
662 &DeviceName,
663 FILE_DEVICE_8042_PORT,
664 FILE_DEVICE_SECURE_OPEN,
665 TRUE,
666 &Fdo);
667
668 if (NT_SUCCESS(Status))
669 {
670 FdoDevExt = Fdo->DeviceExtension;
671
672 RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
673
674 FdoDevExt->PortDevExt = DevExt;
675 FdoDevExt->Type = Keyboard;
676 FdoDevExt->DeviceObject = Fdo;
677
678 Fdo->Flags |= DO_BUFFERED_IO;
679
680 DevExt->DebugWorkItem = IoAllocateWorkItem(Fdo);
681 DevExt->KeyboardObject = Fdo;
682
683 DevExt->KeyboardBuffer = ExAllocatePoolWithTag(
684 NonPagedPool,
685 DevExt->KeyboardAttributes.InputDataQueueLength *
686 sizeof(KEYBOARD_INPUT_DATA),
687 TAG_I8042);
688
689 if (!DevExt->KeyboardBuffer) {
690 DPRINT1("No memory for keyboardbuffer\n");
691 return STATUS_INSUFFICIENT_RESOURCES;
692 }
693
694 InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
695 }
696 else
697 DevExt->KeyboardExists = FALSE;
698 }
699
700 if (DevExt->MouseExists) {
701 MappedIrqMouse = HalGetInterruptVector(Internal,
702 0,
703 0,
704 MOUSE_IRQ,
705 &DirqlMouse,
706 &Affinity);
707
708 Status = IoCreateDevice(DriverObject,
709 sizeof(FDO_DEVICE_EXTENSION),
710 &MouseName,
711 FILE_DEVICE_8042_PORT,
712 FILE_DEVICE_SECURE_OPEN,
713 TRUE,
714 &Fdo);
715
716 if (NT_SUCCESS(Status))
717 {
718 FdoDevExt = Fdo->DeviceExtension;
719
720 RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
721
722 FdoDevExt->PortDevExt = DevExt;
723 FdoDevExt->Type = Mouse;
724 FdoDevExt->DeviceObject = Fdo;
725
726 Fdo->Flags |= DO_BUFFERED_IO;
727 DevExt->MouseObject = Fdo;
728
729 DevExt->MouseBuffer = ExAllocatePoolWithTag(
730 NonPagedPool,
731 DevExt->MouseAttributes.InputDataQueueLength *
732 sizeof(MOUSE_INPUT_DATA),
733 TAG_I8042);
734
735 if (!DevExt->MouseBuffer) {
736 ExFreePoolWithTag(DevExt->KeyboardBuffer, TAG_I8042);
737 DPRINT1("No memory for mouse buffer\n");
738 return STATUS_INSUFFICIENT_RESOURCES;
739 }
740
741 InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
742 }
743 else
744 DevExt->MouseExists = FALSE;
745 }
746
747 if (DirqlKeyboard > DirqlMouse)
748 DirqlMax = DirqlKeyboard;
749 else
750 DirqlMax = DirqlMouse;
751
752 if (DevExt->KeyboardExists) {
753 Status = IoConnectInterrupt(&DevExt->KeyboardInterruptObject,
754 I8042InterruptServiceKbd,
755 (PVOID)DevExt,
756 &DevExt->SpinLock,
757 MappedIrqKeyboard,
758 DirqlKeyboard,
759 DirqlMax,
760 LevelSensitive,
761 FALSE,
762 Affinity,
763 FALSE);
764
765 DPRINT("Keyboard Irq Status: %x\n", Status);
766 }
767
768 if (DevExt->MouseExists) {
769 Status = IoConnectInterrupt(&DevExt->MouseInterruptObject,
770 I8042InterruptServiceMouse,
771 (PVOID)DevExt,
772 &DevExt->SpinLock,
773 MappedIrqMouse,
774 DirqlMouse,
775 DirqlMax,
776 LevelSensitive,
777 FALSE,
778 Affinity,
779 FALSE);
780
781 DPRINT("Mouse Irq Status: %x\n", Status);
782 }
783
784 if (DirqlKeyboard > DirqlMouse)
785 DevExt->HighestDIRQLInterrupt = DevExt->KeyboardInterruptObject;
786 else
787 DevExt->HighestDIRQLInterrupt = DevExt->MouseInterruptObject;
788
789 DPRINT("I8042AddDevice done\n");
790
791 return(STATUS_SUCCESS);
792 }
793
794 NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
795 PUNICODE_STRING RegistryPath)
796 /*
797 * FUNCTION: Module entry point
798 */
799 {
800 DPRINT("I8042 Driver 0.0.1\n");
801
802 DriverObject->MajorFunction[IRP_MJ_CREATE] = I8042CreateDispatch;
803 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
804 I8042InternalDeviceControl;
805
806 DriverObject->DriverStartIo = I8042StartIo;
807 DriverObject->DriverExtension->AddDevice = I8042AddDevice;
808
809 return(STATUS_SUCCESS);
810 }
811