update for HEAD-2003091401
[reactos.git] / drivers / input / psaux / psaux.c
1 /*
2  ** PS/2 driver 0.0.2
3  ** Written by Jason Filby (jasonfilby@yahoo.com)
4  ** For ReactOS (www.reactos.com)
5
6  ** Handles the keyboard and mouse on the PS/2 ports
7
8  ** TODO: Fix detect_ps2_port(void) so that it works under BOCHs
9 */
10
11 #include <ddk/ntddk.h>
12 #include <ddk/ntddmou.h>
13 #include "mouse.h"
14 #include "psaux.h"
15
16 BOOLEAN STDCALL
17 MouseSynchronizeRoutine(PVOID Context)
18 {
19    PIRP Irp = (PIRP)Context;
20    PMOUSE_INPUT_DATA rec  = (PMOUSE_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
21    PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
22    ULONG NrToRead         = stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA);
23    int i;
24
25    if ((stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA))==NrToRead)
26    {
27       return(TRUE);
28    }
29
30    MouseDataRequired=stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA);
31    MouseDataRead=NrToRead;
32    CurrentIrp=Irp;
33
34    return(FALSE);
35 }
36
37 VOID STDCALL
38 PS2MouseStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
39 {
40    PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
41
42    if (KeSynchronizeExecution(DeviceExtension->MouseInterrupt, MouseSynchronizeRoutine, Irp))
43      {
44         Irp->IoStatus.Status = STATUS_SUCCESS;
45         Irp->IoStatus.Information = 0;
46         IoCompleteRequest(Irp, IO_NO_INCREMENT);
47         IoStartNextPacket(DeviceObject, FALSE);
48      }
49 }
50
51 NTSTATUS STDCALL
52 PS2MouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
53 {
54    PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
55    NTSTATUS Status;
56
57    switch (stk->MajorFunction)
58      {
59       case IRP_MJ_CREATE:
60         if (AlreadyOpened == TRUE)
61           {
62              Status = STATUS_SUCCESS;
63           }
64         else
65           {
66              Status = STATUS_SUCCESS;
67              AlreadyOpened = TRUE;
68           }
69         break;
70         
71       case IRP_MJ_CLOSE:
72         Status = STATUS_SUCCESS;
73         break;
74
75       default:
76         DbgPrint("NOT IMPLEMENTED\n");
77         Status = STATUS_NOT_IMPLEMENTED;
78         break;
79      }
80
81    if (Status==STATUS_PENDING)
82      {
83         IoMarkIrpPending(Irp);
84      }
85    else
86      {
87         Irp->IoStatus.Status = Status;
88         Irp->IoStatus.Information = 0;
89         IoCompleteRequest(Irp,IO_NO_INCREMENT);
90      }
91    return(Status);
92 }
93
94 VOID PS2MouseInitializeDataQueue(PVOID Context)
95 {
96 }
97
98 NTSTATUS STDCALL
99 PS2MouseInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
100 {
101    PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
102    PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
103    NTSTATUS status;
104
105    switch(Stack->Parameters.DeviceIoControl.IoControlCode)
106    {
107       case IOCTL_INTERNAL_MOUSE_CONNECT:
108
109          DeviceExtension->ClassInformation =
110             *((PCLASS_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
111
112          // Reinitialize the port input data queue synchronously
113          KeSynchronizeExecution(DeviceExtension->MouseInterrupt,
114             (PKSYNCHRONIZE_ROUTINE)PS2MouseInitializeDataQueue, DeviceExtension);
115
116          status = STATUS_SUCCESS;
117          break;
118
119       default:
120          status = STATUS_INVALID_DEVICE_REQUEST;
121          break;
122    }
123
124    Irp->IoStatus.Status = status;
125    if (status == STATUS_PENDING) {
126       IoMarkIrpPending(Irp);
127       IoStartPacket(DeviceObject, Irp, NULL, NULL);
128    } else {
129       IoCompleteRequest(Irp, IO_NO_INCREMENT);
130    }
131
132    return status;
133 }
134
135 VOID PS2MouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
136 {
137    PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
138    ULONG Queue;
139
140    Queue = DeviceExtension->ActiveQueue % 2;
141    InterlockedIncrement(&DeviceExtension->ActiveQueue);
142    (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassInformation.CallBack)(
143                         DeviceExtension->ClassInformation.DeviceObject,
144                         DeviceExtension->MouseInputData[Queue],
145                         NULL,
146                         &DeviceExtension->InputDataCount[Queue]);
147    DeviceExtension->InputDataCount[Queue] = 0;
148 }
149
150 /* Maximum value plus one for \Device\PointerClass* device name */
151 #define POINTER_PORTS_MAXIMUM   8
152 /* Letter count for POINTER_PORTS_MAXIMUM variable * sizeof(WCHAR) */
153 #define SUFFIX_MAXIMUM_SIZE             (1 * sizeof(WCHAR))
154
155 /* This is almost the same routine as in sermouse.c. */
156 STATIC PDEVICE_OBJECT
157 AllocatePointerDevice(PDRIVER_OBJECT DriverObject)
158 {
159         PDEVICE_OBJECT DeviceObject;
160         UNICODE_STRING DeviceName;
161         UNICODE_STRING SuffixString;
162         UNICODE_STRING SymlinkName;
163         PDEVICE_EXTENSION DeviceExtension;
164         ULONG Suffix;
165         NTSTATUS Status;
166
167         /* Allocate buffer for full device name */   
168         RtlInitUnicodeString(&DeviceName, NULL);
169         DeviceName.MaximumLength = sizeof(DD_MOUSE_DEVICE_NAME_U) + SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
170         DeviceName.Buffer = ExAllocatePool(PagedPool, DeviceName.MaximumLength);
171         RtlAppendUnicodeToString(&DeviceName, DD_MOUSE_DEVICE_NAME_U);
172
173         /* Allocate buffer for device name suffix */
174         RtlInitUnicodeString(&SuffixString, NULL);
175         SuffixString.MaximumLength = SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
176         SuffixString.Buffer = ExAllocatePool(PagedPool, SuffixString.MaximumLength);
177
178         /* Generate full qualified name with suffix */
179         for (Suffix = 0; Suffix < POINTER_PORTS_MAXIMUM; ++Suffix)
180         {
181                 ANSI_STRING DebugString;
182
183                 RtlIntegerToUnicodeString(Suffix, 10, &SuffixString);
184                 RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer);
185                 // FIXME: this isn't really a serial mouse port driver
186                 Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
187                         &DeviceName, FILE_DEVICE_SERIAL_MOUSE_PORT, 0, TRUE, &DeviceObject);
188                 RtlUnicodeStringToAnsiString(&DebugString, &DeviceName, TRUE);
189                 DbgPrint(DebugString.Buffer);
190                 DbgPrint("\n");
191                 RtlFreeAnsiString(&DebugString);
192                 /* Device successfully created, leave the cyclus */
193                 if (NT_SUCCESS(Status))
194                         break;
195                 DeviceName.Length -= SuffixString.Length;
196         }
197  
198         ExFreePool(DeviceName.Buffer);
199
200         /* Couldn't create device */
201         if (!NT_SUCCESS(Status))
202         {
203                 ExFreePool(SuffixString.Buffer);
204                 return NULL;
205         }
206
207         DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
208
209         /* Create symlink */
210         RtlInitUnicodeString(&SymlinkName, NULL);
211         SymlinkName.MaximumLength = sizeof(L"\\??\\Mouse") + SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
212         SymlinkName.Buffer = ExAllocatePool(PagedPool, SymlinkName.MaximumLength);
213         RtlAppendUnicodeToString(&SymlinkName, L"\\??\\Mouse");
214         RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer);
215         IoCreateSymbolicLink(&SymlinkName, &DeviceName);
216         ExFreePool(SuffixString.Buffer);
217
218         DeviceExtension = DeviceObject->DeviceExtension;
219         KeInitializeDpc(&DeviceExtension->IsrDpc, (PKDEFERRED_ROUTINE)PS2MouseIsrDpc, DeviceObject);
220
221         return DeviceObject;
222 }
223
224 NTSTATUS STDCALL
225 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
226 {
227    PDEVICE_OBJECT DeviceObject;
228    UNICODE_STRING DeviceName;
229    UNICODE_STRING SymlinkName;
230    PDEVICE_EXTENSION DeviceExtension;
231
232    if (detect_ps2_port() == TRUE) {
233      DbgPrint("PS2 Port Driver version 0.0.2\n");
234    } else {
235      DbgPrint("PS2 port not found.\n");
236      return STATUS_UNSUCCESSFUL;
237    }
238
239    DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)PS2MouseDispatch;
240    DriverObject->MajorFunction[IRP_MJ_CLOSE]  = (PDRIVER_DISPATCH)PS2MouseDispatch;
241    DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)PS2MouseInternalDeviceControl;
242    DriverObject->DriverStartIo                = PS2MouseStartIo;
243
244    DeviceObject = AllocatePointerDevice(DriverObject);
245
246    mouse_init(DeviceObject);
247
248    return(STATUS_SUCCESS);
249 }