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