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