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 static DRIVER_DISPATCH i8042DeviceControl
;
23 static DRIVER_DISPATCH i8042InternalDeviceControl
;
24 DRIVER_INITIALIZE DriverEntry
;
28 IN PDRIVER_OBJECT DriverObject
,
29 IN PDEVICE_OBJECT Pdo
)
31 PI8042_DRIVER_EXTENSION DriverExtension
;
32 PFDO_DEVICE_EXTENSION DeviceExtension
= NULL
;
33 PDEVICE_OBJECT Fdo
= NULL
;
34 ULONG DeviceExtensionSize
;
37 TRACE_(I8042PRT
, "i8042AddDevice(%p %p)\n", DriverObject
, Pdo
);
39 DriverExtension
= (PI8042_DRIVER_EXTENSION
)IoGetDriverObjectExtension(DriverObject
, DriverObject
);
43 /* We're getting a NULL Pdo at the first call as
44 * we are a legacy driver. Ignore it */
45 return STATUS_SUCCESS
;
48 /* Create new device object. As we don't know if the device would be a keyboard
49 * or a mouse, we have to allocate the biggest device extension. */
50 DeviceExtensionSize
= MAX(sizeof(I8042_KEYBOARD_EXTENSION
), sizeof(I8042_MOUSE_EXTENSION
));
51 Status
= IoCreateDevice(
56 FILE_DEVICE_SECURE_OPEN
,
59 if (!NT_SUCCESS(Status
))
61 WARN_(I8042PRT
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
65 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
66 RtlZeroMemory(DeviceExtension
, DeviceExtensionSize
);
67 DeviceExtension
->Type
= Unknown
;
68 DeviceExtension
->Fdo
= Fdo
;
69 DeviceExtension
->Pdo
= Pdo
;
70 DeviceExtension
->PortDeviceExtension
= &DriverExtension
->Port
;
71 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
72 if (!NT_SUCCESS(Status
))
74 WARN_(I8042PRT
, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
78 ExInterlockedInsertTailList(
79 &DriverExtension
->DeviceListHead
,
80 &DeviceExtension
->ListEntry
,
81 &DriverExtension
->DeviceListLock
);
83 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
84 return STATUS_SUCCESS
;
87 if (DeviceExtension
&& DeviceExtension
->LowerDevice
)
88 IoDetachDevice(DeviceExtension
->LowerDevice
);
95 i8042SendHookWorkItem(
96 IN PDEVICE_OBJECT DeviceObject
,
99 PI8042_HOOK_WORKITEM WorkItemData
;
100 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
101 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
102 PDEVICE_OBJECT TopOfStack
= NULL
;
105 ULONG InputBufferLength
;
106 IO_STATUS_BLOCK IoStatus
;
111 TRACE_(I8042PRT
, "i8042SendHookWorkItem(%p %p)\n", DeviceObject
, Context
);
113 WorkItemData
= (PI8042_HOOK_WORKITEM
)Context
;
114 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
115 PortDeviceExtension
= FdoDeviceExtension
->PortDeviceExtension
;
117 switch (FdoDeviceExtension
->Type
)
121 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
122 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)FdoDeviceExtension
;
123 IoControlCode
= IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
;
124 InputBuffer
= &DeviceExtension
->KeyboardHook
;
125 InputBufferLength
= sizeof(INTERNAL_I8042_HOOK_KEYBOARD
);
130 PI8042_MOUSE_EXTENSION DeviceExtension
;
131 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)FdoDeviceExtension
;
132 IoControlCode
= IOCTL_INTERNAL_I8042_HOOK_MOUSE
;
133 InputBuffer
= &DeviceExtension
->MouseHook
;
134 InputBufferLength
= sizeof(INTERNAL_I8042_HOOK_MOUSE
);
139 ERR_(I8042PRT
, "Unknown FDO type %u\n", FdoDeviceExtension
->Type
);
141 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_INTERNAL_ERROR
;
146 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
147 TopOfStack
= IoGetAttachedDeviceReference(DeviceObject
);
149 NewIrp
= IoBuildDeviceIoControlRequest(
162 WARN_(I8042PRT
, "IoBuildDeviceIoControlRequest() failed\n");
163 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
167 Status
= IoCallDriver(TopOfStack
, NewIrp
);
168 if (Status
== STATUS_PENDING
)
170 KeWaitForSingleObject(
176 Status
= IoStatus
.Status
;
178 if (!NT_SUCCESS(Status
))
180 WARN_(I8042PRT
, "IoCallDriver() failed with status 0x%08lx\n", Status
);
184 if (FdoDeviceExtension
->Type
== Keyboard
)
186 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
188 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)FdoDeviceExtension
;
189 /* Call the hooked initialization if it exists */
190 if (DeviceExtension
->KeyboardHook
.InitializationRoutine
)
192 Status
= DeviceExtension
->KeyboardHook
.InitializationRoutine(
193 DeviceExtension
->KeyboardHook
.Context
,
196 i8042SynchWritePortKbd
,
198 if (!NT_SUCCESS(Status
))
200 WARN_(I8042PRT
, "KeyboardHook.InitializationRoutine() failed with status 0x%08lx\n", Status
);
201 WorkItemData
->Irp
->IoStatus
.Status
= Status
;
207 WorkItemData
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
210 if (TopOfStack
!= NULL
)
211 ObDereferenceObject(TopOfStack
);
212 WorkItemData
->Irp
->IoStatus
.Information
= 0;
213 IoCompleteRequest(WorkItemData
->Irp
, IO_NO_INCREMENT
);
215 IoFreeWorkItem(WorkItemData
->WorkItem
);
216 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
221 IN PDEVICE_OBJECT DeviceObject
,
224 PFDO_DEVICE_EXTENSION DeviceExtension
;
226 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
227 switch (DeviceExtension
->Type
)
230 i8042KbdStartIo(DeviceObject
, Irp
);
233 ERR_(I8042PRT
, "Unknown FDO type %u\n", DeviceExtension
->Type
);
239 /* Write the current byte of the packet. Returns FALSE in case
244 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
246 UCHAR Port
= DeviceExtension
->PacketPort
;
250 if (!i8042Write(DeviceExtension
,
251 DeviceExtension
->ControlPort
,
254 /* something is really wrong! */
255 WARN_(I8042PRT
, "Failed to send packet byte!\n");
260 return i8042Write(DeviceExtension
,
261 DeviceExtension
->DataPort
,
262 DeviceExtension
->Packet
.Bytes
[DeviceExtension
->Packet
.CurrentByte
]);
267 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
270 if (DeviceExtension
->Packet
.State
== Idle
)
276 DeviceExtension
->PacketResends
++;
277 if (DeviceExtension
->PacketResends
> DeviceExtension
->Settings
.ResendIterations
)
279 DeviceExtension
->Packet
.State
= Idle
;
280 DeviceExtension
->PacketComplete
= TRUE
;
281 DeviceExtension
->PacketResult
= STATUS_IO_TIMEOUT
;
282 DeviceExtension
->PacketResends
= 0;
285 DeviceExtension
->Packet
.CurrentByte
--;
289 DeviceExtension
->Packet
.State
= Idle
;
290 DeviceExtension
->PacketComplete
= TRUE
;
291 DeviceExtension
->PacketResult
= STATUS_UNEXPECTED_IO_ERROR
;
292 DeviceExtension
->PacketResends
= 0;
296 DeviceExtension
->PacketResends
= 0;
299 if (DeviceExtension
->Packet
.CurrentByte
>= DeviceExtension
->Packet
.ByteCount
)
301 DeviceExtension
->Packet
.State
= Idle
;
302 DeviceExtension
->PacketComplete
= TRUE
;
303 DeviceExtension
->PacketResult
= STATUS_SUCCESS
;
307 if (!i8042PacketWrite(DeviceExtension
))
309 DeviceExtension
->Packet
.State
= Idle
;
310 DeviceExtension
->PacketComplete
= TRUE
;
311 DeviceExtension
->PacketResult
= STATUS_IO_TIMEOUT
;
314 DeviceExtension
->Packet
.CurrentByte
++;
320 * This function starts a packet. It must be called with the
325 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
326 IN PFDO_DEVICE_EXTENSION FdoDeviceExtension
,
334 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
336 if (DeviceExtension
->Packet
.State
!= Idle
)
338 Status
= STATUS_DEVICE_BUSY
;
342 switch (FdoDeviceExtension
->Type
)
344 case Keyboard
: DeviceExtension
->PacketPort
= 0; break;
345 case Mouse
: DeviceExtension
->PacketPort
= CTRL_WRITE_MOUSE
; break;
347 ERR_(I8042PRT
, "Unknown FDO type %u\n", FdoDeviceExtension
->Type
);
349 Status
= STATUS_INTERNAL_ERROR
;
353 DeviceExtension
->Packet
.Bytes
= Bytes
;
354 DeviceExtension
->Packet
.CurrentByte
= 0;
355 DeviceExtension
->Packet
.ByteCount
= ByteCount
;
356 DeviceExtension
->Packet
.State
= SendingBytes
;
357 DeviceExtension
->PacketResult
= Status
= STATUS_PENDING
;
358 DeviceExtension
->CurrentIrp
= Irp
;
359 DeviceExtension
->CurrentIrpDevice
= FdoDeviceExtension
->Fdo
;
361 if (!i8042PacketWrite(DeviceExtension
))
363 Status
= STATUS_IO_TIMEOUT
;
364 DeviceExtension
->Packet
.State
= Idle
;
365 DeviceExtension
->PacketResult
= STATUS_ABANDONED
;
369 DeviceExtension
->Packet
.CurrentByte
++;
372 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
374 if (Status
!= STATUS_PENDING
)
376 DeviceExtension
->CurrentIrp
= NULL
;
377 DeviceExtension
->CurrentIrpDevice
= NULL
;
378 Irp
->IoStatus
.Status
= Status
;
379 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
384 static NTSTATUS NTAPI
386 IN PDEVICE_OBJECT DeviceObject
,
389 NTSTATUS Status
= Irp
->IoStatus
.Status
;
391 UNREFERENCED_PARAMETER(DeviceObject
);
395 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
399 static NTSTATUS NTAPI
401 IN PDEVICE_OBJECT DeviceObject
,
404 PFDO_DEVICE_EXTENSION DeviceExtension
;
406 TRACE_(I8042PRT
, "i8042DeviceControl(%p %p)\n", DeviceObject
, Irp
);
407 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
409 switch (DeviceExtension
->Type
)
412 return i8042KbdDeviceControl(DeviceObject
, Irp
);
415 return IrpStub(DeviceObject
, Irp
);
419 static NTSTATUS NTAPI
420 i8042InternalDeviceControl(
421 IN PDEVICE_OBJECT DeviceObject
,
424 PFDO_DEVICE_EXTENSION DeviceExtension
;
428 TRACE_(I8042PRT
, "i8042InternalDeviceControl(%p %p)\n", DeviceObject
, Irp
);
429 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
431 switch (DeviceExtension
->Type
)
435 ControlCode
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
;
438 case IOCTL_INTERNAL_KEYBOARD_CONNECT
:
439 Status
= i8042KbdInternalDeviceControl(DeviceObject
, Irp
);
441 case IOCTL_INTERNAL_MOUSE_CONNECT
:
442 Status
= i8042MouInternalDeviceControl(DeviceObject
, Irp
);
445 ERR_(I8042PRT
, "Unknown IO control code 0x%lx\n", ControlCode
);
447 Status
= STATUS_INVALID_DEVICE_REQUEST
;
453 Status
= i8042KbdInternalDeviceControl(DeviceObject
, Irp
);
456 Status
= i8042MouInternalDeviceControl(DeviceObject
, Irp
);
459 ERR_(I8042PRT
, "Unknown FDO type %u\n", DeviceExtension
->Type
);
461 Status
= STATUS_INTERNAL_ERROR
;
462 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
471 IN PDRIVER_OBJECT DriverObject
,
472 IN PUNICODE_STRING RegistryPath
)
474 PI8042_DRIVER_EXTENSION DriverExtension
;
478 /* ROS Hack: ideally, we shouldn't have to initialize debug level this way,
479 but since the only way is to change it via KDBG, it's better to leave
482 DbgSetDebugFilterState(
484 (1 << DPFLTR_ERROR_LEVEL
) | (1 << DPFLTR_WARNING_LEVEL
) |
485 (1 << DPFLTR_TRACE_LEVEL
) /*| (1 << DPFLTR_INFO_LEVEL)*/ | DPFLTR_MASK
,
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(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 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
525 DriverObject
->MajorFunction
[i
] = IrpStub
;
527 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = i8042Create
;
528 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = i8042Cleanup
;
529 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = i8042Close
;
530 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = i8042DeviceControl
;
531 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = i8042InternalDeviceControl
;
532 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = i8042Pnp
;
534 return STATUS_SUCCESS
;