remove whitespace from end of lines
[reactos.git] / reactos / drivers / input / kbdclass / kbdclass.c
1 /*
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)
8 * Tinus_
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <string.h>
15 #include <ntos/keyboard.h>
16 #include <ntos/minmax.h>
17 #include <rosrtl/string.h>
18
19 #include <ddk/ntddkbd.h>
20 #include <ddk/ntdd8042.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 #include "kbdclass.h"
26
27 /* GLOBALS *******************************************************************/
28
29 /*
30 * Driver data
31 */
32
33 static BOOLEAN AlreadyOpened = FALSE;
34
35 static VOID STDCALL KbdCopyKeys(PDEVICE_OBJECT DeviceObject,
36 PIRP Irp)
37 {
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;
45
46 while (DevExt->KeysInBuffer &&
47 NrRead < NrToRead) {
48 memcpy(&Rec[NrRead],
49 &DevExt->KbdBuffer[DevExt->BufHead],
50 sizeof(KEYBOARD_INPUT_DATA));
51
52 if (++DevExt->BufHead >= KBD_BUFFER_SIZE)
53 DevExt->BufHead = 0;
54
55 DevExt->KeysInBuffer--;
56 NrRead++;
57 }
58 Irp->IoStatus.Information = NrRead * sizeof(KEYBOARD_INPUT_DATA);
59
60 if (NrRead < NrToRead) {
61 Irp->IoStatus.Status = STATUS_PENDING;
62 DPRINT("Pending... (NrRead %d, NrToRead %d\n", NrRead, NrToRead);
63 } else {
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);
68 DPRINT("Success!\n");
69 }
70 }
71
72 static VOID STDCALL KbdClassServiceCallback (
73 PDEVICE_OBJECT DeviceObject,
74 PKEYBOARD_INPUT_DATA InputDataStart,
75 PKEYBOARD_INPUT_DATA InputDataEnd,
76 PULONG InputDataConsumed)
77 {
78 PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
79 PKEYBOARD_INPUT_DATA CurrentInput = InputDataStart;
80
81 DPRINT("ServiceCallback called\n");
82
83 while (DevExt->KeysInBuffer < KBD_BUFFER_SIZE &&
84 CurrentInput < InputDataEnd) {
85 memcpy(&DevExt->KbdBuffer[DevExt->BufTail],
86 CurrentInput,
87 sizeof(KEYBOARD_INPUT_DATA));
88
89 if (++DevExt->BufTail >= KBD_BUFFER_SIZE)
90 DevExt->BufTail = 0;
91 DevExt->KeysInBuffer++;
92
93 CurrentInput++;
94 InputDataConsumed[0]++;
95 }
96
97 if (CurrentInput < InputDataStart)
98 /* Copy the rest to the beginning, perhaps the keyboard
99 * can buffer it for us */
100 memmove(InputDataStart,
101 CurrentInput,
102 ((char *)InputDataEnd - (char *)CurrentInput));
103
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);
109 }
110 }
111
112 VOID STDCALL KbdStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
113 {
114 /* We only do this for read irps */
115 DPRINT("KeyboardStartIo(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
116 KbdCopyKeys(DeviceObject, Irp);
117 }
118
119
120 /*
121 * These are just passed down the stack but we must change the IOCTL to be
122 * INTERNAL. MSDN says there might be more...
123 */
124 NTSTATUS STDCALL KbdDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
125 {
126 PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
127 PIO_STACK_LOCATION Stk = IoGetCurrentIrpStackLocation(Irp);
128 PIO_STACK_LOCATION NextStk = IoGetNextIrpStackLocation(Irp);
129
130 DPRINT ("KbdDeviceControl %x\n", Stk->Parameters.DeviceIoControl.IoControlCode);
131
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;
141
142 return IoCallDriver(DevExt->I8042Device, Irp);
143 default:
144 return STATUS_INVALID_DEVICE_REQUEST;
145 }
146 }
147
148 static NTSTATUS STDCALL KbdInternalDeviceControl(PDEVICE_OBJECT DeviceObject,
149 PIRP Irp)
150 {
151 PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
152
153 DPRINT ("KbdInternalDeviceControl\n");
154
155 IoSkipCurrentIrpStackLocation(Irp);
156 return IoCallDriver(DevExt->I8042Device, Irp);
157 }
158
159 static NTSTATUS STDCALL KbdDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
160 {
161 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
162 NTSTATUS Status;
163
164 DPRINT("DeviceObject %x\n",DeviceObject);
165 DPRINT("Irp %x\n",Irp);
166
167 DPRINT("Dispatch: stk->MajorFunction %d\n", stk->MajorFunction);
168 DPRINT("AlreadyOpened %d\n",AlreadyOpened);
169
170 switch (stk->MajorFunction) {
171 case IRP_MJ_CREATE:
172 if (AlreadyOpened == TRUE) {
173 CHECKPOINT;
174 Status = STATUS_UNSUCCESSFUL;
175 DPRINT1("Keyboard is already open\n");
176 } else {
177 CHECKPOINT;
178 Status = STATUS_SUCCESS;
179 AlreadyOpened = TRUE;
180 }
181 break;
182
183 case IRP_MJ_CLOSE:
184 Status = STATUS_SUCCESS;
185 AlreadyOpened = FALSE;
186 break;
187
188 case IRP_MJ_READ:
189 DPRINT("Queueing packet\n");
190 IoMarkIrpPending(Irp);
191 IoStartPacket(DeviceObject,Irp,NULL,NULL);
192 return(STATUS_PENDING);
193
194 default:
195 Status = STATUS_NOT_IMPLEMENTED;
196 break;
197 }
198
199 Irp->IoStatus.Status = Status;
200 Irp->IoStatus.Information = 0;
201 IoCompleteRequest(Irp,IO_NO_INCREMENT);
202 DPRINT("Status %d\n",Status);
203 return(Status);
204 }
205
206 static VOID STDCALL KbdClassSendConnect(PDEVICE_EXTENSION DevExt)
207 {
208 CONNECT_DATA ConnectData;
209 KEVENT Event;
210 IO_STATUS_BLOCK IoStatus;
211 NTSTATUS Status;
212 PIRP Irp;
213
214 KeInitializeEvent(&Event, NotificationEvent, FALSE);
215
216 ConnectData.ClassDeviceObject = DevExt->DeviceObject;
217 ConnectData.ClassService = KbdClassServiceCallback;
218
219 Irp = IoBuildDeviceIoControlRequest(
220 IOCTL_INTERNAL_KEYBOARD_CONNECT,
221 DevExt->I8042Device,
222 &ConnectData,
223 sizeof(CONNECT_DATA),
224 NULL,
225 0,
226 TRUE,
227 &Event,
228 &IoStatus);
229
230 if (!Irp)
231 return;
232
233 Status = IoCallDriver(
234 DevExt->I8042Device,
235 Irp);
236 DPRINT("SendConnect status: %x\n", Status);
237
238 if (STATUS_PENDING ==Status)
239 KeWaitForSingleObject(&Event,
240 Executive,
241 KernelMode,
242 FALSE,
243 NULL);
244 DPRINT("SendConnect done\n");
245 }
246
247 NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
248 PUNICODE_STRING RegistryPath)
249 /*
250 * FUNCTION: Module entry point
251 */
252 {
253 PDEVICE_OBJECT DeviceObject;
254 PDEVICE_EXTENSION DevExt;
255 PFILE_OBJECT I8042File;
256 NTSTATUS Status;
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");
260
261 DPRINT("Keyboard Class Driver 0.0.1\n");
262
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;
269
270 DriverObject->DriverStartIo = KbdStartIo;
271
272 IoCreateDevice(DriverObject,
273 sizeof(DEVICE_EXTENSION),
274 &DeviceName,
275 FILE_DEVICE_KEYBOARD,
276 0,
277 TRUE,
278 &DeviceObject);
279
280 RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION));
281 DevExt = DeviceObject->DeviceExtension;
282 DevExt->DeviceObject = DeviceObject;
283
284 Status = IoGetDeviceObjectPointer(&I8042Name,
285 FILE_READ_DATA,
286 &I8042File,
287 &DevExt->I8042Device);
288
289 if (STATUS_SUCCESS != Status) {
290 DPRINT("Failed to open device: %x\n", Status);
291 return Status;
292 }
293
294 ObReferenceObject(DevExt->I8042Device);
295 ObDereferenceObject(I8042File);
296
297 DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
298
299 DeviceObject->StackSize = 1 + DevExt->I8042Device->StackSize;
300
301 IoCreateSymbolicLink(&SymlinkName, &DeviceName);
302
303 KbdClassSendConnect(DevExt);
304
305 return(STATUS_SUCCESS);
306 }