:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / input / sermouse / sermouse.c
1 /*
2
3  ** Mouse driver 0.0.4
4  ** Written by Jason Filby (jasonfilby@yahoo.com)
5  ** For ReactOS (www.sid-dis.com/reactos)
6
7  ** Note: The serial.o driver must be loaded before loading this driver
8
9  ** Known Limitations:
10  ** Only supports mice on COM port 1
11
12 */
13
14 #include <ddk/ntddk.h>
15 #include "../include/mouse.h"
16 #include "sermouse.h"
17 #include "mouse.h"
18
19 #define MOUSE_IRQ_COM1  4
20 #define MOUSE_IRQ_COM2  3
21
22 #define COM1_PORT       0x3f8
23 #define COM2_PORT       0x2f8
24
25 #define max_screen_x    79
26 #define max_screen_y    24
27
28 //static unsigned int MOUSE_IRQ=MOUSE_IRQ_COM1;
29 static unsigned int MOUSE_COM=COM1_PORT;
30
31 static unsigned int     bytepos=0, coordinate;
32 static unsigned char    mpacket[3];
33 static signed int       mouse_x=40, mouse_y=12;
34 static unsigned char    mouse_button1, mouse_button2;
35 static signed int       horiz_sensitivity, vert_sensitivity;
36
37 BOOLEAN microsoft_mouse_handler(PKINTERRUPT Interrupt, PVOID ServiceContext)
38 {
39   unsigned int mbyte=READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
40
41   // Synchronize
42   if((mbyte&64)==64) { bytepos=0; }
43
44   mpacket[bytepos]=mbyte;
45   bytepos++;
46
47   // Process packet
48   if(bytepos==3) {
49     // Retrieve change in x and y from packet
50     int change_x=((mpacket[0] & 3) << 6) + mpacket[1];
51     int change_y=((mpacket[0] & 12) << 4) + mpacket[2];
52
53     // Some mice need this
54     if(coordinate==1) {
55       change_x-=128;
56       change_y-=128;
57     }
58
59     // Change to signed
60     if(change_x>=128) { change_x=change_x-256; }
61     if(change_y>=128) { change_y=change_y-256; }
62
63     // Adjust mouse position according to sensitivity
64     mouse_x+=change_x/horiz_sensitivity;
65     mouse_y+=change_y/vert_sensitivity;
66
67     // Check that mouse is still in screen
68     if(mouse_x<0) { mouse_x=0; }
69     if(mouse_x>max_screen_x) { mouse_x=max_screen_x; }
70     if(mouse_y<0) { mouse_y=0; }
71     if(mouse_y>max_screen_y) { mouse_y=max_screen_y; }
72
73     // Retrieve mouse button status from packet
74     mouse_button1=mpacket[0] & 32;
75     mouse_button2=mpacket[0] & 16;
76
77     bytepos=0;
78   }
79
80 }
81
82 void InitializeMouseHardware(unsigned int mtype)
83 {
84   char clear_error_bits;
85
86   WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+3, 0x80); // set DLAB on
87   WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM, 0x60); // speed LO byte
88   WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+1, 0); // speed HI byte
89   WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+3, mtype); // 2=MS Mouse; 3=Mouse systems mouse
90   WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+1, 0); // set comm and DLAB to 0
91   WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+4, 1); // DR int enable
92  
93   clear_error_bits=READ_PORT_UCHAR((PUCHAR)MOUSE_COM+5); // clear error bits
94 }
95
96 int DetMicrosoft(void)
97 {
98   char tmp, ind;
99   int buttons=0, i, timeout=250;
100
101   WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+4, 0x0b);
102   tmp=READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
103
104   // Check the first four bytes for signs that this is an MS mouse
105   for(i=0; i<4; i++) {
106     while(((READ_PORT_UCHAR((PUCHAR)MOUSE_COM+5) & 1)==0) && (timeout>0))
107     {
108       KeDelayExecutionThread (KernelMode, FALSE, 1);
109       timeout--;
110     }
111     ind=READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
112     if(ind==0x33) buttons=3;
113     if(ind==0x4d) buttons=2;
114   }
115
116   return buttons;
117 }
118
119 int CheckMouseType(unsigned int mtype)
120 {
121   unsigned int retval=0;
122
123   InitializeMouseHardware(mtype);
124   if(mtype==2) retval=DetMicrosoft();
125   if(mtype==3) {
126     WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+4, 11);
127     retval=3;
128   }
129   WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+1, 1);
130
131   return retval;
132 }
133
134 void ClearMouse(void)
135 {
136   // Waits until the mouse calms down but also quits out after a while
137   // in case some destructive user wants to keep moving the mouse
138   // before we're done
139
140   unsigned int restarts=0, i;
141   for (i=0; i<60000; i++)
142   {
143     unsigned temp=READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
144     if(temp!=0) {
145       restarts++;
146       if(restarts<300000) {
147         i=0;
148       } else
149       {
150         i=60000;
151       }
152     }
153   }
154 }
155
156 BOOLEAN InitializeMouse(PDEVICE_OBJECT DeviceObject)
157 {
158   int mbuttons=0, gotmouse=0;
159   PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
160   ULONG MappedIrq;
161   KIRQL Dirql;
162   KAFFINITY Affinity;
163
164   horiz_sensitivity=2;
165   vert_sensitivity=3;
166
167   // Check for Microsoft mouse (2 buttons)
168   if(CheckMouseType(2)!=0)
169   {
170     gotmouse=1;
171     DbgPrint("Microsoft Mouse Detected\n");
172     ClearMouse();
173     coordinate=0;
174   }
175
176   // Check for Microsoft Systems mouse (3 buttons)
177   if(gotmouse==0) {
178     if(CheckMouseType(3)!=0)
179     {
180     gotmouse=1;
181     DbgPrint("Microsoft Mouse Detected\n");
182     ClearMouse();
183     coordinate=1;
184     }
185   }
186
187   if(gotmouse==0) return FALSE;
188
189   DeviceExtension->InputDataCount = 0;
190   DeviceExtension->MouseInputData = ExAllocatePool(NonPagedPool, sizeof(MOUSE_INPUT_DATA) * MOUSE_BUFFER_SIZE);
191
192   MappedIrq = HalGetInterruptVector(Internal, 0, 0, MOUSE_IRQ,
193             &Dirql, &Affinity);
194
195   IoConnectInterrupt(&DeviceExtension->MouseInterrupt, microsoft_mouse_handler, NULL,
196          NULL, MappedIrq, Dirql, Dirql, 0, FALSE,
197          Affinity, FALSE);
198
199   return TRUE;
200 }
201
202 VOID SerialMouseInitializeDataQueue(PVOID Context)
203 {
204   ;
205 /*   PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceExtension;
206
207    DeviceExtension->InputDataCount = 0;
208    DeviceExtension->MouseInputData = ExAllocatePool(NonPagedPool, sizeof(MOUSE_INPUT_DATA) * MOUSE_BUFFER_SIZE); */
209 }
210
211 BOOLEAN MouseSynchronizeRoutine(PVOID Context)
212 {
213    PIRP Irp = (PIRP)Context;
214    PMOUSE_INPUT_DATA rec  = (PMOUSE_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
215    PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
216    ULONG NrToRead         = stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA);
217    int i;
218
219    if ((stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA))==NrToRead)
220    {
221       return(TRUE);
222    }
223
224    MouseDataRequired=stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA);
225    MouseDataRead=NrToRead;
226    CurrentIrp=Irp;
227
228    return(FALSE);
229 }
230
231 VOID SerialMouseStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
232 {
233    PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
234
235    if (KeSynchronizeExecution(DeviceExtension->MouseInterrupt, MouseSynchronizeRoutine, Irp))
236      {
237         Irp->IoStatus.Status = STATUS_SUCCESS;
238         Irp->IoStatus.Information = 0;
239         IoCompleteRequest(Irp, IO_NO_INCREMENT);
240         IoStartNextPacket(DeviceObject, FALSE);
241      }
242 }
243
244 NTSTATUS SerialMouseInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
245 {
246    PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
247    PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
248    NTSTATUS status;
249
250    switch(Stack->Parameters.DeviceIoControl.IoControlCode)
251    {
252       case IOCTL_INTERNAL_MOUSE_CONNECT:
253
254          DeviceExtension->ClassInformation =
255             *((PCLASS_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
256
257          // Reinitialize the port input data queue synchronously
258          KeSynchronizeExecution(DeviceExtension->MouseInterrupt,
259             (PKSYNCHRONIZE_ROUTINE)SerialMouseInitializeDataQueue, DeviceExtension);
260
261          status = STATUS_SUCCESS;
262          break;
263
264       default:
265          status = STATUS_INVALID_DEVICE_REQUEST;
266          break;
267    }
268
269    Irp->IoStatus.Status = status;
270    if (status == STATUS_PENDING) {
271       IoMarkIrpPending(Irp);
272       IoStartPacket(DeviceObject, Irp, NULL, NULL);
273    } else {
274       IoCompleteRequest(Irp, IO_NO_INCREMENT);
275    }
276
277    return status;
278 }
279
280 NTSTATUS SerialMouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
281 {
282    PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
283    NTSTATUS Status;
284
285    switch (stk->MajorFunction)
286      {
287       case IRP_MJ_CREATE:
288         if (AlreadyOpened == TRUE)
289           {
290              Status = STATUS_SUCCESS;
291           }
292         else
293           {
294              Status = STATUS_SUCCESS;
295              AlreadyOpened = TRUE;
296           }
297         break;
298         
299       case IRP_MJ_CLOSE:
300         Status = STATUS_SUCCESS;
301         break;
302
303       default:
304         DbgPrint("NOT IMPLEMENTED\n");
305         Status = STATUS_NOT_IMPLEMENTED;
306         break;
307      }
308
309    if (Status==STATUS_PENDING)
310      {
311         IoMarkIrpPending(Irp);
312      }
313    else
314      {
315         Irp->IoStatus.Status = Status;
316         Irp->IoStatus.Information = 0;
317         IoCompleteRequest(Irp,IO_NO_INCREMENT);
318      }
319    return(Status);
320 }
321
322 VOID SerialMouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
323 {
324    PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
325
326    (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassInformation.CallBack)(
327                         DeviceExtension->ClassInformation.DeviceObject,
328                         DeviceExtension->MouseInputData,
329                         NULL,
330                         &DeviceExtension->InputDataCount);
331
332    DeviceExtension->InputDataCount = 0;
333 }
334
335 NTSTATUS STDCALL
336 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
337 {
338   PDEVICE_OBJECT DeviceObject;
339   UNICODE_STRING DeviceName;
340   UNICODE_STRING SymlinkName;
341   PDEVICE_EXTENSION DeviceExtension;
342
343   DbgPrint("Serial Mouse Driver 0.0.4\n");
344
345   if(InitializeMouse(DeviceObject) == FALSE)
346     return STATUS_UNSUCCESSFUL;
347
348   DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialMouseDispatch;
349   DriverObject->MajorFunction[IRP_MJ_CLOSE]  = SerialMouseDispatch;
350   DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = SerialMouseInternalDeviceControl;
351   DriverObject->DriverStartIo                = SerialMouseStartIo;
352
353   RtlInitUnicodeStringFromLiteral(&DeviceName,
354                                   L"\\Device\\Mouse"); // FIXME: find correct device name
355   IoCreateDevice(DriverObject,
356           sizeof(DEVICE_EXTENSION),
357           &DeviceName,
358           FILE_DEVICE_SERIAL_MOUSE_PORT,
359           0,
360           TRUE,
361           &DeviceObject);
362   DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
363
364   RtlInitUnicodeStringFromLiteral(&SymlinkName,
365                                   L"\\??\\Mouse"); // FIXME: find correct device name
366   IoCreateSymbolicLink(&SymlinkName, &DeviceName);
367
368   DeviceExtension = DeviceObject->DeviceExtension;
369   KeInitializeDpc(&DeviceExtension->IsrDpc, (PKDEFERRED_ROUTINE)SerialMouseIsrDpc, DeviceObject);
370   KeInitializeDpc(&DeviceExtension->IsrDpcRetry, (PKDEFERRED_ROUTINE)SerialMouseIsrDpc, DeviceObject);
371
372   return(STATUS_SUCCESS);
373 }