2 * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/input/i8042prt/i8042prt.c
5 * PURPOSE: Driver entry function
6 * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
7 Copyright Jason Filby (jasonfilby@yahoo.com)
8 Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
9 Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
12 /* INCLUDES ******************************************************************/
18 /* FUNCTIONS *****************************************************************/
20 static DRIVER_STARTIO i8042StartIo
;
21 static DRIVER_DISPATCH IrpStub
;
22 _Dispatch_type_(IRP_MJ_DEVICE_CONTROL
)
23 static DRIVER_DISPATCH i8042DeviceControl
;
24 _Dispatch_type_(IRP_MJ_INTERNAL_DEVICE_CONTROL
)
25 static DRIVER_DISPATCH i8042InternalDeviceControl
;
26 _Dispatch_type_(IRP_MJ_SYSTEM_CONTROL
)
27 static DRIVER_DISPATCH i8042SystemControl
;
28 _Dispatch_type_(IRP_MJ_POWER
)
29 static DRIVER_DISPATCH i8042Power
;
30 DRIVER_INITIALIZE DriverEntry
;
34 IN PDRIVER_OBJECT DriverObject
,
35 IN PDEVICE_OBJECT Pdo
)
37 PI8042_DRIVER_EXTENSION DriverExtension
;
38 PFDO_DEVICE_EXTENSION DeviceExtension
= NULL
;
39 PDEVICE_OBJECT Fdo
= NULL
;
40 ULONG DeviceExtensionSize
;
43 TRACE_(I8042PRT
, "i8042AddDevice(%p %p)\n", DriverObject
, Pdo
);
45 DriverExtension
= (PI8042_DRIVER_EXTENSION
)IoGetDriverObjectExtension(DriverObject
, DriverObject
);
49 /* We're getting a NULL Pdo at the first call as
50 * we are a legacy driver. Ignore it */
51 return STATUS_SUCCESS
;
54 /* Create new device object. As we don't know if the device would be a keyboard
55 * or a mouse, we have to allocate the biggest device extension. */
56 DeviceExtensionSize
= MAX(sizeof(I8042_KEYBOARD_EXTENSION
), sizeof(I8042_MOUSE_EXTENSION
));
57 Status
= IoCreateDevice(
62 FILE_DEVICE_SECURE_OPEN
,
65 if (!NT_SUCCESS(Status
))
67 WARN_(I8042PRT
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
71 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
72 RtlZeroMemory(DeviceExtension
, DeviceExtensionSize
);
73 DeviceExtension
->Type
= Unknown
;
74 DeviceExtension
->Fdo
= Fdo
;
75 DeviceExtension
->Pdo
= Pdo
;
76 DeviceExtension
->PortDeviceExtension
= &DriverExtension
->Port
;
77 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
78 if (!NT_SUCCESS(Status
))
80 WARN_(I8042PRT
, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
84 ExInterlockedInsertTailList(
85 &DriverExtension
->DeviceListHead
,
86 &DeviceExtension
->ListEntry
,
87 &DriverExtension
->DeviceListLock
);
89 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
90 return STATUS_SUCCESS
;
93 if (DeviceExtension
&& DeviceExtension
->LowerDevice
)
94 IoDetachDevice(DeviceExtension
->LowerDevice
);
101 i8042SendHookWorkItem(
102 IN PDEVICE_OBJECT DeviceObject
,
105 PI8042_HOOK_WORKITEM WorkItemData
;
106 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
107 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
108 PDEVICE_OBJECT TopOfStack
= NULL
;
111 ULONG InputBufferLength
;
112 IO_STATUS_BLOCK IoStatus
;
117 TRACE_(I8042PRT
, "i8042SendHookWorkItem(%p %p)\n", DeviceObject
, Context
);
119 WorkItemData
= (PI8042_HOOK_WORKITEM
)Context
;
120 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
121 PortDeviceExtension
= FdoDeviceExtension
->PortDeviceExtension
;
123 switch (FdoDeviceExtension
->Type
)
127 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
128 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)FdoDeviceExtension
;
129 IoControlCode
= IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
;
130 InputBuffer
= &DeviceExtension
->KeyboardHook
;
131 InputBufferLength
= sizeof(INTERNAL_I8042_HOOK_KEYBOARD
);
136 PI8042_MOUSE_EXTENSION DeviceExtension
;
137 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)FdoDeviceExtension
;
138 IoControlCode
= IOCTL_INTERNAL_I8042_HOOK_MOUSE
;
139 InputBuffer
= &DeviceExtension
->MouseHook
;
140 InputBufferLength
= sizeof(INTERNAL_I8042_HOOK_MOUSE
);
145 ERR_(I8042PRT
, "Unknown FDO type %u\n", FdoDeviceExtension
->Type
);
147 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_INTERNAL_ERROR
;
152 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
153 TopOfStack
= IoGetAttachedDeviceReference(DeviceObject
);
155 NewIrp
= IoBuildDeviceIoControlRequest(
168 WARN_(I8042PRT
, "IoBuildDeviceIoControlRequest() failed\n");
169 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
173 Status
= IoCallDriver(TopOfStack
, NewIrp
);
174 if (Status
== STATUS_PENDING
)
176 KeWaitForSingleObject(
182 Status
= IoStatus
.Status
;
184 if (!NT_SUCCESS(Status
))
186 WARN_(I8042PRT
, "IoCallDriver() failed with status 0x%08lx\n", Status
);
190 if (FdoDeviceExtension
->Type
== Keyboard
)
192 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
194 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)FdoDeviceExtension
;
195 /* Call the hooked initialization if it exists */
196 if (DeviceExtension
->KeyboardHook
.InitializationRoutine
)
198 Status
= DeviceExtension
->KeyboardHook
.InitializationRoutine(
199 DeviceExtension
->KeyboardHook
.Context
,
202 i8042SynchWritePortKbd
,
204 if (!NT_SUCCESS(Status
))
206 WARN_(I8042PRT
, "KeyboardHook.InitializationRoutine() failed with status 0x%08lx\n", Status
);
207 WorkItemData
->Irp
->IoStatus
.Status
= Status
;
213 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
216 if (TopOfStack
!= NULL
)
217 ObDereferenceObject(TopOfStack
);
218 WorkItemData
->Irp
->IoStatus
.Information
= 0;
219 IoCompleteRequest(WorkItemData
->Irp
, IO_NO_INCREMENT
);
221 IoFreeWorkItem(WorkItemData
->WorkItem
);
222 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
227 IN PDEVICE_OBJECT DeviceObject
,
230 PFDO_DEVICE_EXTENSION DeviceExtension
;
232 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
233 switch (DeviceExtension
->Type
)
236 i8042KbdStartIo(DeviceObject
, Irp
);
239 ERR_(I8042PRT
, "Unknown FDO type %u\n", DeviceExtension
->Type
);
245 /* Write the current byte of the packet. Returns FALSE in case
250 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
252 UCHAR Port
= DeviceExtension
->PacketPort
;
256 if (!i8042Write(DeviceExtension
,
257 DeviceExtension
->ControlPort
,
260 /* something is really wrong! */
261 WARN_(I8042PRT
, "Failed to send packet byte!\n");
266 return i8042Write(DeviceExtension
,
267 DeviceExtension
->DataPort
,
268 DeviceExtension
->Packet
.Bytes
[DeviceExtension
->Packet
.CurrentByte
]);
273 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
276 if (DeviceExtension
->Packet
.State
== Idle
)
282 DeviceExtension
->PacketResends
++;
283 if (DeviceExtension
->PacketResends
> DeviceExtension
->Settings
.ResendIterations
)
285 DeviceExtension
->Packet
.State
= Idle
;
286 DeviceExtension
->PacketComplete
= TRUE
;
287 DeviceExtension
->PacketResult
= STATUS_IO_TIMEOUT
;
288 DeviceExtension
->PacketResends
= 0;
291 DeviceExtension
->Packet
.CurrentByte
--;
295 DeviceExtension
->Packet
.State
= Idle
;
296 DeviceExtension
->PacketComplete
= TRUE
;
297 DeviceExtension
->PacketResult
= STATUS_UNEXPECTED_IO_ERROR
;
298 DeviceExtension
->PacketResends
= 0;
302 DeviceExtension
->PacketResends
= 0;
305 if (DeviceExtension
->Packet
.CurrentByte
>= DeviceExtension
->Packet
.ByteCount
)
307 DeviceExtension
->Packet
.State
= Idle
;
308 DeviceExtension
->PacketComplete
= TRUE
;
309 DeviceExtension
->PacketResult
= STATUS_SUCCESS
;
313 if (!i8042PacketWrite(DeviceExtension
))
315 DeviceExtension
->Packet
.State
= Idle
;
316 DeviceExtension
->PacketComplete
= TRUE
;
317 DeviceExtension
->PacketResult
= STATUS_IO_TIMEOUT
;
320 DeviceExtension
->Packet
.CurrentByte
++;
326 * This function starts a packet. It must be called with the
331 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
332 IN PFDO_DEVICE_EXTENSION FdoDeviceExtension
,
340 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
342 if (DeviceExtension
->Packet
.State
!= Idle
)
344 Status
= STATUS_DEVICE_BUSY
;
348 switch (FdoDeviceExtension
->Type
)
350 case Keyboard
: DeviceExtension
->PacketPort
= 0; break;
351 case Mouse
: DeviceExtension
->PacketPort
= CTRL_WRITE_MOUSE
; break;
353 ERR_(I8042PRT
, "Unknown FDO type %u\n", FdoDeviceExtension
->Type
);
355 Status
= STATUS_INTERNAL_ERROR
;
359 DeviceExtension
->Packet
.Bytes
= Bytes
;
360 DeviceExtension
->Packet
.CurrentByte
= 0;
361 DeviceExtension
->Packet
.ByteCount
= ByteCount
;
362 DeviceExtension
->Packet
.State
= SendingBytes
;
363 DeviceExtension
->PacketResult
= Status
= STATUS_PENDING
;
364 DeviceExtension
->CurrentIrp
= Irp
;
365 DeviceExtension
->CurrentIrpDevice
= FdoDeviceExtension
->Fdo
;
367 if (!i8042PacketWrite(DeviceExtension
))
369 Status
= STATUS_IO_TIMEOUT
;
370 DeviceExtension
->Packet
.State
= Idle
;
371 DeviceExtension
->PacketResult
= STATUS_ABANDONED
;
375 DeviceExtension
->Packet
.CurrentByte
++;
378 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
380 if (Status
!= STATUS_PENDING
)
382 DeviceExtension
->CurrentIrp
= NULL
;
383 DeviceExtension
->CurrentIrpDevice
= NULL
;
384 Irp
->IoStatus
.Status
= Status
;
385 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
390 static NTSTATUS NTAPI
392 IN PDEVICE_OBJECT DeviceObject
,
395 NTSTATUS Status
= Irp
->IoStatus
.Status
;
397 UNREFERENCED_PARAMETER(DeviceObject
);
401 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
405 static NTSTATUS NTAPI
407 IN PDEVICE_OBJECT DeviceObject
,
410 PFDO_DEVICE_EXTENSION DeviceExtension
;
412 TRACE_(I8042PRT
, "i8042DeviceControl(%p %p)\n", DeviceObject
, Irp
);
413 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
415 switch (DeviceExtension
->Type
)
418 return i8042KbdDeviceControl(DeviceObject
, Irp
);
421 return IrpStub(DeviceObject
, Irp
);
425 static NTSTATUS NTAPI
426 i8042InternalDeviceControl(
427 IN PDEVICE_OBJECT DeviceObject
,
430 PFDO_DEVICE_EXTENSION DeviceExtension
;
434 TRACE_(I8042PRT
, "i8042InternalDeviceControl(%p %p)\n", DeviceObject
, Irp
);
435 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
437 switch (DeviceExtension
->Type
)
441 ControlCode
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
;
444 case IOCTL_INTERNAL_KEYBOARD_CONNECT
:
445 Status
= i8042KbdInternalDeviceControl(DeviceObject
, Irp
);
447 case IOCTL_INTERNAL_MOUSE_CONNECT
:
448 Status
= i8042MouInternalDeviceControl(DeviceObject
, Irp
);
451 ERR_(I8042PRT
, "Unknown IO control code 0x%lx\n", ControlCode
);
453 Status
= STATUS_INVALID_DEVICE_REQUEST
;
459 Status
= i8042KbdInternalDeviceControl(DeviceObject
, Irp
);
462 Status
= i8042MouInternalDeviceControl(DeviceObject
, Irp
);
465 ERR_(I8042PRT
, "Unknown FDO type %u\n", DeviceExtension
->Type
);
467 Status
= STATUS_INTERNAL_ERROR
;
468 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
475 static NTSTATUS NTAPI
477 IN PDEVICE_OBJECT DeviceObject
,
480 PFDO_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
481 PDEVICE_OBJECT LowerDevice
= DeviceExtension
->LowerDevice
;
483 PoStartNextPowerIrp(Irp
);
484 IoSkipCurrentIrpStackLocation(Irp
);
485 return PoCallDriver(LowerDevice
, Irp
);
488 static NTSTATUS NTAPI
490 IN PDEVICE_OBJECT DeviceObject
,
493 return ForwardIrpAndForget(DeviceObject
, Irp
);
498 IN PDRIVER_OBJECT DriverObject
,
499 IN PUNICODE_STRING RegistryPath
)
501 PI8042_DRIVER_EXTENSION DriverExtension
;
505 /* ROS Hack: ideally, we shouldn't have to initialize debug level this way,
506 but since the only way is to change it via KDBG, it's better to leave
509 DbgSetDebugFilterState(
511 (1 << DPFLTR_ERROR_LEVEL
) | (1 << DPFLTR_WARNING_LEVEL
) |
512 (1 << DPFLTR_TRACE_LEVEL
) /*| (1 << DPFLTR_INFO_LEVEL)*/ | DPFLTR_MASK
,
516 Status
= IoAllocateDriverObjectExtension(
519 sizeof(I8042_DRIVER_EXTENSION
),
520 (PVOID
*)&DriverExtension
);
521 if (!NT_SUCCESS(Status
))
523 WARN_(I8042PRT
, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status
);
526 RtlZeroMemory(DriverExtension
, sizeof(I8042_DRIVER_EXTENSION
));
527 KeInitializeSpinLock(&DriverExtension
->Port
.SpinLock
);
528 InitializeListHead(&DriverExtension
->DeviceListHead
);
529 KeInitializeSpinLock(&DriverExtension
->DeviceListLock
);
531 Status
= DuplicateUnicodeString(
532 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
534 &DriverExtension
->RegistryPath
);
535 if (!NT_SUCCESS(Status
))
537 WARN_(I8042PRT
, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
541 Status
= ReadRegistryEntries(RegistryPath
, &DriverExtension
->Port
.Settings
);
542 if (!NT_SUCCESS(Status
))
544 WARN_(I8042PRT
, "ReadRegistryEntries() failed with status 0x%08lx\n", Status
);
548 DriverObject
->DriverExtension
->AddDevice
= i8042AddDevice
;
549 DriverObject
->DriverStartIo
= i8042StartIo
;
551 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
552 DriverObject
->MajorFunction
[i
] = IrpStub
;
554 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = i8042Create
;
555 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = i8042Cleanup
;
556 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = i8042Close
;
557 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = i8042DeviceControl
;
558 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = i8042InternalDeviceControl
;
559 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = i8042Power
;
560 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = i8042SystemControl
;
561 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = i8042Pnp
;
563 return STATUS_SUCCESS
;