2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/input/kbdclass/kbdclass.c
5 * PURPOSE: Keyboard class driver
6 * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
7 * Jason Filby (jasonfilby@yahoo.com)
11 /* INCLUDES ****************************************************************/
13 #include <ddk/ntddk.h>
15 #include <ntos/keyboard.h>
16 #include <ntos/minmax.h>
17 #include <rosrtl/string.h>
19 #include <ddk/ntddkbd.h>
20 #include <ddk/ntdd8042.h>
27 /* GLOBALS *******************************************************************/
33 static BOOLEAN AlreadyOpened
= FALSE
;
35 static VOID STDCALL
KbdCopyKeys(PDEVICE_OBJECT DeviceObject
,
38 PDEVICE_EXTENSION DevExt
= DeviceObject
->DeviceExtension
;
39 PIO_STACK_LOCATION stk
= IoGetCurrentIrpStackLocation(Irp
);
40 ULONG NrToRead
= stk
->Parameters
.Read
.Length
/
41 sizeof(KEYBOARD_INPUT_DATA
);
42 ULONG NrRead
= Irp
->IoStatus
.Information
/sizeof(KEYBOARD_INPUT_DATA
);
43 KEYBOARD_INPUT_DATA
*Rec
=
44 (KEYBOARD_INPUT_DATA
*)Irp
->AssociatedIrp
.SystemBuffer
;
46 while (DevExt
->KeysInBuffer
&&
49 &DevExt
->KbdBuffer
[DevExt
->BufHead
],
50 sizeof(KEYBOARD_INPUT_DATA
));
52 if (++DevExt
->BufHead
>= KBD_BUFFER_SIZE
)
55 DevExt
->KeysInBuffer
--;
58 Irp
->IoStatus
.Information
= NrRead
* sizeof(KEYBOARD_INPUT_DATA
);
60 if (NrRead
< NrToRead
) {
61 Irp
->IoStatus
.Status
= STATUS_PENDING
;
62 DPRINT("Pending... (NrRead %d, NrToRead %d\n", NrRead
, NrToRead
);
64 DPRINT("Send scancode: %x\n", ((KEYBOARD_INPUT_DATA
*)Irp
->AssociatedIrp
.SystemBuffer
)->MakeCode
);
65 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
66 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
67 IoStartNextPacket (DeviceObject
, FALSE
);
72 static VOID STDCALL
KbdClassServiceCallback (
73 PDEVICE_OBJECT DeviceObject
,
74 PKEYBOARD_INPUT_DATA InputDataStart
,
75 PKEYBOARD_INPUT_DATA InputDataEnd
,
76 PULONG InputDataConsumed
)
78 PDEVICE_EXTENSION DevExt
= DeviceObject
->DeviceExtension
;
79 PKEYBOARD_INPUT_DATA CurrentInput
= InputDataStart
;
81 DPRINT("ServiceCallback called\n");
83 while (DevExt
->KeysInBuffer
< KBD_BUFFER_SIZE
&&
84 CurrentInput
< InputDataEnd
) {
85 memcpy(&DevExt
->KbdBuffer
[DevExt
->BufTail
],
87 sizeof(KEYBOARD_INPUT_DATA
));
89 if (++DevExt
->BufTail
>= KBD_BUFFER_SIZE
)
91 DevExt
->KeysInBuffer
++;
94 InputDataConsumed
[0]++;
97 if (CurrentInput
< InputDataStart
)
98 /* Copy the rest to the beginning, perhaps the keyboard
99 * can buffer it for us */
100 memmove(InputDataStart
,
102 ((char *)InputDataEnd
- (char *)CurrentInput
));
104 if (DeviceObject
->CurrentIrp
) {
105 PIRP Irp
= DeviceObject
->CurrentIrp
;
106 PIO_STACK_LOCATION stk
= IoGetCurrentIrpStackLocation(Irp
);
107 if (stk
->MajorFunction
== IRP_MJ_READ
)
108 KbdCopyKeys(DeviceObject
, Irp
);
112 VOID STDCALL
KbdStartIo(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
114 /* We only do this for read irps */
115 DPRINT("KeyboardStartIo(DeviceObject %x Irp %x)\n",DeviceObject
,Irp
);
116 KbdCopyKeys(DeviceObject
, Irp
);
121 * These are just passed down the stack but we must change the IOCTL to be
122 * INTERNAL. MSDN says there might be more...
124 NTSTATUS STDCALL
KbdDeviceControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
126 PDEVICE_EXTENSION DevExt
= DeviceObject
->DeviceExtension
;
127 PIO_STACK_LOCATION Stk
= IoGetCurrentIrpStackLocation(Irp
);
128 PIO_STACK_LOCATION NextStk
= IoGetNextIrpStackLocation(Irp
);
130 DPRINT ("KbdDeviceControl %x\n", Stk
->Parameters
.DeviceIoControl
.IoControlCode
);
132 switch (Stk
->Parameters
.DeviceIoControl
.IoControlCode
) {
133 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES
:
134 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
135 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
136 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
137 case IOCTL_KEYBOARD_SET_INDICATORS
:
138 case IOCTL_KEYBOARD_SET_TYPEMATIC
: /* not in MSDN, would seem logical */
139 IoCopyCurrentIrpStackLocationToNext(Irp
);
140 NextStk
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
142 return IoCallDriver(DevExt
->I8042Device
, Irp
);
144 return STATUS_INVALID_DEVICE_REQUEST
;
148 static NTSTATUS STDCALL
KbdInternalDeviceControl(PDEVICE_OBJECT DeviceObject
,
151 PDEVICE_EXTENSION DevExt
= DeviceObject
->DeviceExtension
;
153 DPRINT ("KbdInternalDeviceControl\n");
155 IoSkipCurrentIrpStackLocation(Irp
);
156 return IoCallDriver(DevExt
->I8042Device
, Irp
);
159 static NTSTATUS STDCALL
KbdDispatch(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
161 PIO_STACK_LOCATION stk
= IoGetCurrentIrpStackLocation(Irp
);
164 DPRINT("DeviceObject %x\n",DeviceObject
);
165 DPRINT("Irp %x\n",Irp
);
167 DPRINT("Dispatch: stk->MajorFunction %d\n", stk
->MajorFunction
);
168 DPRINT("AlreadyOpened %d\n",AlreadyOpened
);
170 switch (stk
->MajorFunction
) {
172 if (AlreadyOpened
== TRUE
) {
174 Status
= STATUS_UNSUCCESSFUL
;
175 DPRINT1("Keyboard is already open\n");
178 Status
= STATUS_SUCCESS
;
179 AlreadyOpened
= TRUE
;
184 Status
= STATUS_SUCCESS
;
185 AlreadyOpened
= FALSE
;
189 DPRINT("Queueing packet\n");
190 IoMarkIrpPending(Irp
);
191 IoStartPacket(DeviceObject
,Irp
,NULL
,NULL
);
192 return(STATUS_PENDING
);
195 Status
= STATUS_NOT_IMPLEMENTED
;
199 Irp
->IoStatus
.Status
= Status
;
200 Irp
->IoStatus
.Information
= 0;
201 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
202 DPRINT("Status %d\n",Status
);
206 static VOID STDCALL
KbdClassSendConnect(PDEVICE_EXTENSION DevExt
)
208 CONNECT_DATA ConnectData
;
210 IO_STATUS_BLOCK IoStatus
;
214 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
216 ConnectData
.ClassDeviceObject
= DevExt
->DeviceObject
;
217 ConnectData
.ClassService
= KbdClassServiceCallback
;
219 Irp
= IoBuildDeviceIoControlRequest(
220 IOCTL_INTERNAL_KEYBOARD_CONNECT
,
223 sizeof(CONNECT_DATA
),
233 Status
= IoCallDriver(
236 DPRINT("SendConnect status: %x\n", Status
);
238 if (STATUS_PENDING
==Status
)
239 KeWaitForSingleObject(&Event
,
244 DPRINT("SendConnect done\n");
247 NTSTATUS STDCALL
DriverEntry(PDRIVER_OBJECT DriverObject
,
248 PUNICODE_STRING RegistryPath
)
250 * FUNCTION: Module entry point
253 PDEVICE_OBJECT DeviceObject
;
254 PDEVICE_EXTENSION DevExt
;
255 PFILE_OBJECT I8042File
;
257 UNICODE_STRING DeviceName
= ROS_STRING_INITIALIZER(L
"\\Device\\Keyboard");
258 UNICODE_STRING SymlinkName
= ROS_STRING_INITIALIZER(L
"\\??\\Keyboard");
259 UNICODE_STRING I8042Name
= ROS_STRING_INITIALIZER(L
"\\Device\\KeyboardClass0");
261 DPRINT("Keyboard Class Driver 0.0.1\n");
263 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = KbdDispatch
;
264 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = KbdDispatch
;
265 DriverObject
->MajorFunction
[IRP_MJ_READ
] = KbdDispatch
;
266 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] =
267 KbdInternalDeviceControl
;
268 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = KbdDeviceControl
;
270 DriverObject
->DriverStartIo
= KbdStartIo
;
272 IoCreateDevice(DriverObject
,
273 sizeof(DEVICE_EXTENSION
),
275 FILE_DEVICE_KEYBOARD
,
280 RtlZeroMemory(DeviceObject
->DeviceExtension
, sizeof(DEVICE_EXTENSION
));
281 DevExt
= DeviceObject
->DeviceExtension
;
282 DevExt
->DeviceObject
= DeviceObject
;
284 Status
= IoGetDeviceObjectPointer(&I8042Name
,
287 &DevExt
->I8042Device
);
289 if (STATUS_SUCCESS
!= Status
) {
290 DPRINT("Failed to open device: %x\n", Status
);
294 ObReferenceObject(DevExt
->I8042Device
);
295 ObDereferenceObject(I8042File
);
297 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_BUFFERED_IO
;
299 DeviceObject
->StackSize
= 1 + DevExt
->I8042Device
->StackSize
;
301 IoCreateSymbolicLink(&SymlinkName
, &DeviceName
);
303 KbdClassSendConnect(DevExt
);
305 return(STATUS_SUCCESS
);