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 ******************************************************************/
17 /* FUNCTIONS *****************************************************************/
19 static DRIVER_STARTIO i8042StartIo
;
20 static DRIVER_DISPATCH IrpStub
;
21 static DRIVER_DISPATCH i8042DeviceControl
;
22 static DRIVER_DISPATCH i8042InternalDeviceControl
;
23 DRIVER_INITIALIZE DriverEntry
;
27 IN PDRIVER_OBJECT DriverObject
,
28 IN PDEVICE_OBJECT Pdo
)
30 PI8042_DRIVER_EXTENSION DriverExtension
;
31 PFDO_DEVICE_EXTENSION DeviceExtension
= NULL
;
32 PDEVICE_OBJECT Fdo
= NULL
;
33 ULONG DeviceExtensionSize
;
36 TRACE_(I8042PRT
, "i8042AddDevice(%p %p)\n", DriverObject
, Pdo
);
38 DriverExtension
= (PI8042_DRIVER_EXTENSION
)IoGetDriverObjectExtension(DriverObject
, DriverObject
);
42 /* We're getting a NULL Pdo at the first call as
43 * we are a legacy driver. Ignore it */
44 return STATUS_SUCCESS
;
47 /* Create new device object. As we don't know if the device would be a keyboard
48 * or a mouse, we have to allocate the biggest device extension. */
49 DeviceExtensionSize
= MAX(sizeof(I8042_KEYBOARD_EXTENSION
), sizeof(I8042_MOUSE_EXTENSION
));
50 Status
= IoCreateDevice(
55 FILE_DEVICE_SECURE_OPEN
,
58 if (!NT_SUCCESS(Status
))
60 WARN_(I8042PRT
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
64 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
65 RtlZeroMemory(DeviceExtension
, DeviceExtensionSize
);
66 DeviceExtension
->Type
= Unknown
;
67 DeviceExtension
->Fdo
= Fdo
;
68 DeviceExtension
->Pdo
= Pdo
;
69 DeviceExtension
->PortDeviceExtension
= &DriverExtension
->Port
;
70 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
71 if (!NT_SUCCESS(Status
))
73 WARN_(I8042PRT
, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
77 ExInterlockedInsertTailList(
78 &DriverExtension
->DeviceListHead
,
79 &DeviceExtension
->ListEntry
,
80 &DriverExtension
->DeviceListLock
);
82 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
83 return STATUS_SUCCESS
;
86 if (DeviceExtension
&& DeviceExtension
->LowerDevice
)
87 IoDetachDevice(DeviceExtension
->LowerDevice
);
94 i8042SendHookWorkItem(
95 IN PDEVICE_OBJECT DeviceObject
,
98 PI8042_HOOK_WORKITEM WorkItemData
;
99 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
100 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
101 PDEVICE_OBJECT TopOfStack
= NULL
;
104 ULONG InputBufferLength
;
105 IO_STATUS_BLOCK IoStatus
;
110 TRACE_(I8042PRT
, "i8042SendHookWorkItem(%p %p)\n", DeviceObject
, Context
);
112 WorkItemData
= (PI8042_HOOK_WORKITEM
)Context
;
113 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
114 PortDeviceExtension
= FdoDeviceExtension
->PortDeviceExtension
;
116 switch (FdoDeviceExtension
->Type
)
120 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
121 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)FdoDeviceExtension
;
122 IoControlCode
= IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
;
123 InputBuffer
= &DeviceExtension
->KeyboardHook
;
124 InputBufferLength
= sizeof(INTERNAL_I8042_HOOK_KEYBOARD
);
129 PI8042_MOUSE_EXTENSION DeviceExtension
;
130 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)FdoDeviceExtension
;
131 IoControlCode
= IOCTL_INTERNAL_I8042_HOOK_MOUSE
;
132 InputBuffer
= &DeviceExtension
->MouseHook
;
133 InputBufferLength
= sizeof(INTERNAL_I8042_HOOK_MOUSE
);
138 ERR_(I8042PRT
, "Unknown FDO type %u\n", FdoDeviceExtension
->Type
);
140 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_INTERNAL_ERROR
;
145 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
146 TopOfStack
= IoGetAttachedDeviceReference(DeviceObject
);
148 NewIrp
= IoBuildDeviceIoControlRequest(
161 WARN_(I8042PRT
, "IoBuildDeviceIoControlRequest() failed\n");
162 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
166 Status
= IoCallDriver(TopOfStack
, NewIrp
);
167 if (Status
== STATUS_PENDING
)
169 KeWaitForSingleObject(
175 Status
= IoStatus
.Status
;
177 if (!NT_SUCCESS(Status
))
179 WARN_(I8042PRT
, "IoCallDriver() failed with status 0x%08lx\n", Status
);
183 if (FdoDeviceExtension
->Type
== Keyboard
)
185 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
187 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)FdoDeviceExtension
;
188 /* Call the hooked initialization if it exists */
189 if (DeviceExtension
->KeyboardHook
.InitializationRoutine
)
191 Status
= DeviceExtension
->KeyboardHook
.InitializationRoutine(
192 DeviceExtension
->KeyboardHook
.Context
,
195 i8042SynchWritePortKbd
,
197 if (!NT_SUCCESS(Status
))
199 WARN_(I8042PRT
, "KeyboardHook.InitializationRoutine() failed with status 0x%08lx\n", Status
);
200 WorkItemData
->Irp
->IoStatus
.Status
= Status
;
206 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
209 if (TopOfStack
!= NULL
)
210 ObDereferenceObject(TopOfStack
);
211 WorkItemData
->Irp
->IoStatus
.Information
= 0;
212 IoCompleteRequest(WorkItemData
->Irp
, IO_NO_INCREMENT
);
214 IoFreeWorkItem(WorkItemData
->WorkItem
);
215 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
220 IN PDEVICE_OBJECT DeviceObject
,
223 PFDO_DEVICE_EXTENSION DeviceExtension
;
225 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
226 switch (DeviceExtension
->Type
)
229 i8042KbdStartIo(DeviceObject
, Irp
);
232 ERR_(I8042PRT
, "Unknown FDO type %u\n", DeviceExtension
->Type
);
238 /* Write the current byte of the packet. Returns FALSE in case
243 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
245 UCHAR Port
= DeviceExtension
->PacketPort
;
249 if (!i8042Write(DeviceExtension
,
250 DeviceExtension
->ControlPort
,
253 /* something is really wrong! */
254 WARN_(I8042PRT
, "Failed to send packet byte!\n");
259 return i8042Write(DeviceExtension
,
260 DeviceExtension
->DataPort
,
261 DeviceExtension
->Packet
.Bytes
[DeviceExtension
->Packet
.CurrentByte
]);
266 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
269 if (DeviceExtension
->Packet
.State
== Idle
)
275 DeviceExtension
->PacketResends
++;
276 if (DeviceExtension
->PacketResends
> DeviceExtension
->Settings
.ResendIterations
)
278 DeviceExtension
->Packet
.State
= Idle
;
279 DeviceExtension
->PacketComplete
= TRUE
;
280 DeviceExtension
->PacketResult
= STATUS_IO_TIMEOUT
;
281 DeviceExtension
->PacketResends
= 0;
284 DeviceExtension
->Packet
.CurrentByte
--;
288 DeviceExtension
->Packet
.State
= Idle
;
289 DeviceExtension
->PacketComplete
= TRUE
;
290 DeviceExtension
->PacketResult
= STATUS_UNEXPECTED_IO_ERROR
;
291 DeviceExtension
->PacketResends
= 0;
295 DeviceExtension
->PacketResends
= 0;
298 if (DeviceExtension
->Packet
.CurrentByte
>= DeviceExtension
->Packet
.ByteCount
)
300 DeviceExtension
->Packet
.State
= Idle
;
301 DeviceExtension
->PacketComplete
= TRUE
;
302 DeviceExtension
->PacketResult
= STATUS_SUCCESS
;
306 if (!i8042PacketWrite(DeviceExtension
))
308 DeviceExtension
->Packet
.State
= Idle
;
309 DeviceExtension
->PacketComplete
= TRUE
;
310 DeviceExtension
->PacketResult
= STATUS_IO_TIMEOUT
;
313 DeviceExtension
->Packet
.CurrentByte
++;
319 * This function starts a packet. It must be called with the
324 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
325 IN PFDO_DEVICE_EXTENSION FdoDeviceExtension
,
333 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
335 if (DeviceExtension
->Packet
.State
!= Idle
)
337 Status
= STATUS_DEVICE_BUSY
;
341 switch (FdoDeviceExtension
->Type
)
343 case Keyboard
: DeviceExtension
->PacketPort
= 0; break;
344 case Mouse
: DeviceExtension
->PacketPort
= CTRL_WRITE_MOUSE
; break;
346 ERR_(I8042PRT
, "Unknown FDO type %u\n", FdoDeviceExtension
->Type
);
348 Status
= STATUS_INTERNAL_ERROR
;
352 DeviceExtension
->Packet
.Bytes
= Bytes
;
353 DeviceExtension
->Packet
.CurrentByte
= 0;
354 DeviceExtension
->Packet
.ByteCount
= ByteCount
;
355 DeviceExtension
->Packet
.State
= SendingBytes
;
356 DeviceExtension
->PacketResult
= Status
= STATUS_PENDING
;
357 DeviceExtension
->CurrentIrp
= Irp
;
358 DeviceExtension
->CurrentIrpDevice
= FdoDeviceExtension
->Fdo
;
360 if (!i8042PacketWrite(DeviceExtension
))
362 Status
= STATUS_IO_TIMEOUT
;
363 DeviceExtension
->Packet
.State
= Idle
;
364 DeviceExtension
->PacketResult
= STATUS_ABANDONED
;
368 DeviceExtension
->Packet
.CurrentByte
++;
371 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
373 if (Status
!= STATUS_PENDING
)
375 DeviceExtension
->CurrentIrp
= NULL
;
376 DeviceExtension
->CurrentIrpDevice
= NULL
;
377 Irp
->IoStatus
.Status
= Status
;
378 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
383 static NTSTATUS NTAPI
385 IN PDEVICE_OBJECT DeviceObject
,
388 NTSTATUS Status
= Irp
->IoStatus
.Status
;
390 UNREFERENCED_PARAMETER(DeviceObject
);
394 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
398 static NTSTATUS NTAPI
400 IN PDEVICE_OBJECT DeviceObject
,
403 PFDO_DEVICE_EXTENSION DeviceExtension
;
405 TRACE_(I8042PRT
, "i8042DeviceControl(%p %p)\n", DeviceObject
, Irp
);
406 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
408 switch (DeviceExtension
->Type
)
411 return i8042KbdDeviceControl(DeviceObject
, Irp
);
414 return IrpStub(DeviceObject
, Irp
);
418 static NTSTATUS NTAPI
419 i8042InternalDeviceControl(
420 IN PDEVICE_OBJECT DeviceObject
,
423 PFDO_DEVICE_EXTENSION DeviceExtension
;
427 TRACE_(I8042PRT
, "i8042InternalDeviceControl(%p %p)\n", DeviceObject
, Irp
);
428 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
430 switch (DeviceExtension
->Type
)
434 ControlCode
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
;
437 case IOCTL_INTERNAL_KEYBOARD_CONNECT
:
438 Status
= i8042KbdInternalDeviceControl(DeviceObject
, Irp
);
440 case IOCTL_INTERNAL_MOUSE_CONNECT
:
441 Status
= i8042MouInternalDeviceControl(DeviceObject
, Irp
);
444 ERR_(I8042PRT
, "Unknown IO control code 0x%lx\n", ControlCode
);
446 Status
= STATUS_INVALID_DEVICE_REQUEST
;
452 Status
= i8042KbdInternalDeviceControl(DeviceObject
, Irp
);
455 Status
= i8042MouInternalDeviceControl(DeviceObject
, Irp
);
458 ERR_(I8042PRT
, "Unknown FDO type %u\n", DeviceExtension
->Type
);
460 Status
= STATUS_INTERNAL_ERROR
;
461 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
470 IN PDRIVER_OBJECT DriverObject
,
471 IN PUNICODE_STRING RegistryPath
)
473 PI8042_DRIVER_EXTENSION DriverExtension
;
477 /* ROS Hack: ideally, we shouldn't have to initialize debug level this way,
478 but since the only way is to change it via KDBG, it's better to leave
481 DbgSetDebugFilterState(
483 (1 << DPFLTR_ERROR_LEVEL
) | (1 << DPFLTR_WARNING_LEVEL
) |
484 (1 << DPFLTR_TRACE_LEVEL
) /*| (1 << DPFLTR_INFO_LEVEL)*/ | DPFLTR_MASK
,
488 Status
= IoAllocateDriverObjectExtension(
491 sizeof(I8042_DRIVER_EXTENSION
),
492 (PVOID
*)&DriverExtension
);
493 if (!NT_SUCCESS(Status
))
495 WARN_(I8042PRT
, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status
);
498 RtlZeroMemory(DriverExtension
, sizeof(I8042_DRIVER_EXTENSION
));
499 KeInitializeSpinLock(&DriverExtension
->Port
.SpinLock
);
500 InitializeListHead(&DriverExtension
->DeviceListHead
);
501 KeInitializeSpinLock(&DriverExtension
->DeviceListLock
);
503 Status
= DuplicateUnicodeString(
504 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
506 &DriverExtension
->RegistryPath
);
507 if (!NT_SUCCESS(Status
))
509 WARN_(I8042PRT
, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
513 Status
= ReadRegistryEntries(RegistryPath
, &DriverExtension
->Port
.Settings
);
514 if (!NT_SUCCESS(Status
))
516 WARN_(I8042PRT
, "ReadRegistryEntries() failed with status 0x%08lx\n", Status
);
520 DriverObject
->DriverExtension
->AddDevice
= i8042AddDevice
;
521 DriverObject
->DriverStartIo
= i8042StartIo
;
523 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
524 DriverObject
->MajorFunction
[i
] = IrpStub
;
526 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = i8042Create
;
527 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = i8042Cleanup
;
528 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = i8042Close
;
529 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = i8042DeviceControl
;
530 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = i8042InternalDeviceControl
;
531 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = i8042Pnp
;
533 return STATUS_SUCCESS
;