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 _Dispatch_type_(IRP_MJ_DEVICE_CONTROL
)
22 static DRIVER_DISPATCH i8042DeviceControl
;
23 _Dispatch_type_(IRP_MJ_INTERNAL_DEVICE_CONTROL
)
24 static DRIVER_DISPATCH i8042InternalDeviceControl
;
25 _Dispatch_type_(IRP_MJ_SYSTEM_CONTROL
)
26 static DRIVER_DISPATCH i8042SystemControl
;
27 _Dispatch_type_(IRP_MJ_POWER
)
28 static DRIVER_DISPATCH i8042Power
;
29 DRIVER_INITIALIZE DriverEntry
;
33 IN PDRIVER_OBJECT DriverObject
,
34 IN PDEVICE_OBJECT Pdo
)
36 PI8042_DRIVER_EXTENSION DriverExtension
;
37 PFDO_DEVICE_EXTENSION DeviceExtension
= NULL
;
38 PDEVICE_OBJECT Fdo
= NULL
;
39 ULONG DeviceExtensionSize
;
42 TRACE_(I8042PRT
, "i8042AddDevice(%p %p)\n", DriverObject
, Pdo
);
44 DriverExtension
= (PI8042_DRIVER_EXTENSION
)IoGetDriverObjectExtension(DriverObject
, DriverObject
);
48 /* We're getting a NULL Pdo at the first call as
49 * we are a legacy driver. Ignore it */
50 return STATUS_SUCCESS
;
53 /* Create new device object. As we don't know if the device would be a keyboard
54 * or a mouse, we have to allocate the biggest device extension. */
55 DeviceExtensionSize
= MAX(sizeof(I8042_KEYBOARD_EXTENSION
), sizeof(I8042_MOUSE_EXTENSION
));
56 Status
= IoCreateDevice(
61 FILE_DEVICE_SECURE_OPEN
,
64 if (!NT_SUCCESS(Status
))
66 WARN_(I8042PRT
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
70 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
71 RtlZeroMemory(DeviceExtension
, DeviceExtensionSize
);
72 DeviceExtension
->Type
= Unknown
;
73 DeviceExtension
->Fdo
= Fdo
;
74 DeviceExtension
->Pdo
= Pdo
;
75 DeviceExtension
->PortDeviceExtension
= &DriverExtension
->Port
;
76 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
77 if (!NT_SUCCESS(Status
))
79 WARN_(I8042PRT
, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
83 ExInterlockedInsertTailList(
84 &DriverExtension
->DeviceListHead
,
85 &DeviceExtension
->ListEntry
,
86 &DriverExtension
->DeviceListLock
);
88 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
89 return STATUS_SUCCESS
;
92 if (DeviceExtension
&& DeviceExtension
->LowerDevice
)
93 IoDetachDevice(DeviceExtension
->LowerDevice
);
100 i8042SendHookWorkItem(
101 IN PDEVICE_OBJECT DeviceObject
,
104 PI8042_HOOK_WORKITEM WorkItemData
;
105 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
106 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
107 PDEVICE_OBJECT TopOfStack
= NULL
;
110 ULONG InputBufferLength
;
111 IO_STATUS_BLOCK IoStatus
;
116 TRACE_(I8042PRT
, "i8042SendHookWorkItem(%p %p)\n", DeviceObject
, Context
);
118 WorkItemData
= (PI8042_HOOK_WORKITEM
)Context
;
119 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
120 PortDeviceExtension
= FdoDeviceExtension
->PortDeviceExtension
;
122 switch (FdoDeviceExtension
->Type
)
126 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
127 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)FdoDeviceExtension
;
128 IoControlCode
= IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
;
129 InputBuffer
= &DeviceExtension
->KeyboardHook
;
130 InputBufferLength
= sizeof(INTERNAL_I8042_HOOK_KEYBOARD
);
135 PI8042_MOUSE_EXTENSION DeviceExtension
;
136 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)FdoDeviceExtension
;
137 IoControlCode
= IOCTL_INTERNAL_I8042_HOOK_MOUSE
;
138 InputBuffer
= &DeviceExtension
->MouseHook
;
139 InputBufferLength
= sizeof(INTERNAL_I8042_HOOK_MOUSE
);
144 ERR_(I8042PRT
, "Unknown FDO type %u\n", FdoDeviceExtension
->Type
);
146 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_INTERNAL_ERROR
;
151 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
152 TopOfStack
= IoGetAttachedDeviceReference(DeviceObject
);
154 NewIrp
= IoBuildDeviceIoControlRequest(
167 WARN_(I8042PRT
, "IoBuildDeviceIoControlRequest() failed\n");
168 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
172 Status
= IoCallDriver(TopOfStack
, NewIrp
);
173 if (Status
== STATUS_PENDING
)
175 KeWaitForSingleObject(
181 Status
= IoStatus
.Status
;
183 if (!NT_SUCCESS(Status
))
185 WARN_(I8042PRT
, "IoCallDriver() failed with status 0x%08lx\n", Status
);
189 if (FdoDeviceExtension
->Type
== Keyboard
)
191 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
193 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)FdoDeviceExtension
;
194 /* Call the hooked initialization if it exists */
195 if (DeviceExtension
->KeyboardHook
.InitializationRoutine
)
197 Status
= DeviceExtension
->KeyboardHook
.InitializationRoutine(
198 DeviceExtension
->KeyboardHook
.Context
,
201 i8042SynchWritePortKbd
,
203 if (!NT_SUCCESS(Status
))
205 WARN_(I8042PRT
, "KeyboardHook.InitializationRoutine() failed with status 0x%08lx\n", Status
);
206 WorkItemData
->Irp
->IoStatus
.Status
= Status
;
212 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
215 if (TopOfStack
!= NULL
)
216 ObDereferenceObject(TopOfStack
);
217 WorkItemData
->Irp
->IoStatus
.Information
= 0;
218 IoCompleteRequest(WorkItemData
->Irp
, IO_NO_INCREMENT
);
220 IoFreeWorkItem(WorkItemData
->WorkItem
);
221 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
226 IN PDEVICE_OBJECT DeviceObject
,
229 PFDO_DEVICE_EXTENSION DeviceExtension
;
231 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
232 switch (DeviceExtension
->Type
)
235 i8042KbdStartIo(DeviceObject
, Irp
);
238 ERR_(I8042PRT
, "Unknown FDO type %u\n", DeviceExtension
->Type
);
244 /* Write the current byte of the packet. Returns FALSE in case
249 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
251 UCHAR Port
= DeviceExtension
->PacketPort
;
255 if (!i8042Write(DeviceExtension
,
256 DeviceExtension
->ControlPort
,
259 /* something is really wrong! */
260 WARN_(I8042PRT
, "Failed to send packet byte!\n");
265 return i8042Write(DeviceExtension
,
266 DeviceExtension
->DataPort
,
267 DeviceExtension
->Packet
.Bytes
[DeviceExtension
->Packet
.CurrentByte
]);
272 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
275 if (DeviceExtension
->Packet
.State
== Idle
)
281 DeviceExtension
->PacketResends
++;
282 if (DeviceExtension
->PacketResends
> DeviceExtension
->Settings
.ResendIterations
)
284 DeviceExtension
->Packet
.State
= Idle
;
285 DeviceExtension
->PacketComplete
= TRUE
;
286 DeviceExtension
->PacketResult
= STATUS_IO_TIMEOUT
;
287 DeviceExtension
->PacketResends
= 0;
290 DeviceExtension
->Packet
.CurrentByte
--;
294 DeviceExtension
->Packet
.State
= Idle
;
295 DeviceExtension
->PacketComplete
= TRUE
;
296 DeviceExtension
->PacketResult
= STATUS_UNEXPECTED_IO_ERROR
;
297 DeviceExtension
->PacketResends
= 0;
301 DeviceExtension
->PacketResends
= 0;
304 if (DeviceExtension
->Packet
.CurrentByte
>= DeviceExtension
->Packet
.ByteCount
)
306 DeviceExtension
->Packet
.State
= Idle
;
307 DeviceExtension
->PacketComplete
= TRUE
;
308 DeviceExtension
->PacketResult
= STATUS_SUCCESS
;
312 if (!i8042PacketWrite(DeviceExtension
))
314 DeviceExtension
->Packet
.State
= Idle
;
315 DeviceExtension
->PacketComplete
= TRUE
;
316 DeviceExtension
->PacketResult
= STATUS_IO_TIMEOUT
;
319 DeviceExtension
->Packet
.CurrentByte
++;
325 * This function starts a packet. It must be called with the
330 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
331 IN PFDO_DEVICE_EXTENSION FdoDeviceExtension
,
339 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
341 if (DeviceExtension
->Packet
.State
!= Idle
)
343 Status
= STATUS_DEVICE_BUSY
;
347 switch (FdoDeviceExtension
->Type
)
349 case Keyboard
: DeviceExtension
->PacketPort
= 0; break;
350 case Mouse
: DeviceExtension
->PacketPort
= CTRL_WRITE_MOUSE
; break;
352 ERR_(I8042PRT
, "Unknown FDO type %u\n", FdoDeviceExtension
->Type
);
354 Status
= STATUS_INTERNAL_ERROR
;
358 DeviceExtension
->Packet
.Bytes
= Bytes
;
359 DeviceExtension
->Packet
.CurrentByte
= 0;
360 DeviceExtension
->Packet
.ByteCount
= ByteCount
;
361 DeviceExtension
->Packet
.State
= SendingBytes
;
362 DeviceExtension
->PacketResult
= Status
= STATUS_PENDING
;
363 DeviceExtension
->CurrentIrp
= Irp
;
364 DeviceExtension
->CurrentIrpDevice
= FdoDeviceExtension
->Fdo
;
366 if (!i8042PacketWrite(DeviceExtension
))
368 Status
= STATUS_IO_TIMEOUT
;
369 DeviceExtension
->Packet
.State
= Idle
;
370 DeviceExtension
->PacketResult
= STATUS_ABANDONED
;
374 DeviceExtension
->Packet
.CurrentByte
++;
377 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
379 if (Status
!= STATUS_PENDING
)
381 DeviceExtension
->CurrentIrp
= NULL
;
382 DeviceExtension
->CurrentIrpDevice
= NULL
;
383 Irp
->IoStatus
.Status
= Status
;
384 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
389 static NTSTATUS NTAPI
391 IN PDEVICE_OBJECT DeviceObject
,
394 PFDO_DEVICE_EXTENSION DeviceExtension
;
396 TRACE_(I8042PRT
, "i8042DeviceControl(%p %p)\n", DeviceObject
, Irp
);
397 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
399 switch (DeviceExtension
->Type
)
402 return i8042KbdDeviceControl(DeviceObject
, Irp
);
404 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
405 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
406 return STATUS_INVALID_DEVICE_REQUEST
;
410 static NTSTATUS NTAPI
411 i8042InternalDeviceControl(
412 IN PDEVICE_OBJECT DeviceObject
,
415 PFDO_DEVICE_EXTENSION DeviceExtension
;
419 TRACE_(I8042PRT
, "i8042InternalDeviceControl(%p %p)\n", DeviceObject
, Irp
);
420 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
422 switch (DeviceExtension
->Type
)
426 ControlCode
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
;
429 case IOCTL_INTERNAL_KEYBOARD_CONNECT
:
430 Status
= i8042KbdInternalDeviceControl(DeviceObject
, Irp
);
432 case IOCTL_INTERNAL_MOUSE_CONNECT
:
433 Status
= i8042MouInternalDeviceControl(DeviceObject
, Irp
);
436 ERR_(I8042PRT
, "Unknown IO control code 0x%lx\n", ControlCode
);
438 Status
= STATUS_INVALID_DEVICE_REQUEST
;
444 Status
= i8042KbdInternalDeviceControl(DeviceObject
, Irp
);
447 Status
= i8042MouInternalDeviceControl(DeviceObject
, Irp
);
450 ERR_(I8042PRT
, "Unknown FDO type %u\n", DeviceExtension
->Type
);
452 Status
= STATUS_INTERNAL_ERROR
;
453 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
460 static NTSTATUS NTAPI
462 IN PDEVICE_OBJECT DeviceObject
,
465 PFDO_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
466 PDEVICE_OBJECT LowerDevice
= DeviceExtension
->LowerDevice
;
468 PoStartNextPowerIrp(Irp
);
469 IoSkipCurrentIrpStackLocation(Irp
);
470 return PoCallDriver(LowerDevice
, Irp
);
473 static NTSTATUS NTAPI
475 IN PDEVICE_OBJECT DeviceObject
,
478 return ForwardIrpAndForget(DeviceObject
, Irp
);
483 IN PDRIVER_OBJECT DriverObject
,
484 IN PUNICODE_STRING RegistryPath
)
486 PI8042_DRIVER_EXTENSION DriverExtension
;
489 Status
= IoAllocateDriverObjectExtension(
492 sizeof(I8042_DRIVER_EXTENSION
),
493 (PVOID
*)&DriverExtension
);
494 if (!NT_SUCCESS(Status
))
496 WARN_(I8042PRT
, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status
);
499 RtlZeroMemory(DriverExtension
, sizeof(I8042_DRIVER_EXTENSION
));
500 KeInitializeSpinLock(&DriverExtension
->Port
.SpinLock
);
501 InitializeListHead(&DriverExtension
->DeviceListHead
);
502 KeInitializeSpinLock(&DriverExtension
->DeviceListLock
);
504 Status
= DuplicateUnicodeString(
505 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
507 &DriverExtension
->RegistryPath
);
508 if (!NT_SUCCESS(Status
))
510 WARN_(I8042PRT
, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
514 Status
= ReadRegistryEntries(&DriverExtension
->RegistryPath
, &DriverExtension
->Port
.Settings
);
515 if (!NT_SUCCESS(Status
))
517 WARN_(I8042PRT
, "ReadRegistryEntries() failed with status 0x%08lx\n", Status
);
521 DriverObject
->DriverExtension
->AddDevice
= i8042AddDevice
;
522 DriverObject
->DriverStartIo
= i8042StartIo
;
524 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = i8042Create
;
525 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = i8042Cleanup
;
526 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = i8042Close
;
527 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = i8042DeviceControl
;
528 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = i8042InternalDeviceControl
;
529 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = i8042Power
;
530 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = i8042SystemControl
;
531 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = i8042Pnp
;
533 i8042InitializeHwHacks();
535 return STATUS_SUCCESS
;