2 #include "../include/mouse.h"
3 #include "controller.h"
7 // Have we got a PS/2 mouse port?
8 BOOLEAN has_mouse = FALSE;
10 // This buffer holds the mouse scan codes. The PS/2 protocol sends three characters for each event.
11 unsigned mouse_buffer[3];
12 int mouse_buffer_position = 0;
14 // The number of mouse replies expected
15 int mouse_replies_expected = 0;
17 // Handle a mouse event
20 ps2_mouse_handler(PKINTERRUPT Interrupt, PVOID ServiceContext)
23 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
24 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
26 int state_dx, state_dy, state_buttons;
28 unsigned status = controller_read_status();
29 scancode = controller_read_input();
31 // Don't handle the mouse event if we aren't connected to the mouse class driver
32 if(DeviceExtension->ClassInformation.CallBack == NULL) return FALSE;
34 if((status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) != 0)
36 // mouse_handle_event(scancode); proceed to handle it
40 return FALSE; // keyboard_handle_event(scancode);
43 if (mouse_replies_expected > 0)
45 if (scancode == MOUSE_ACK)
47 mouse_replies_expected--;
51 mouse_replies_expected = 0;
54 /* Add this scancode to the mouse event queue. */
56 mouse_buffer[mouse_buffer_position] = scancode;
57 mouse_buffer_position++;
59 // If the buffer is full, parse this event
60 if (mouse_buffer_position == 3)
62 mouse_buffer_position = 0;
63 // system_call_debug_print_simple ("We got a mouse event");
65 state_buttons = (mouse_buffer[0] & 1) * GPM_B_LEFT +
66 (mouse_buffer[0] & 2) * GPM_B_RIGHT +
67 (mouse_buffer[0] & 4) * GPM_B_MIDDLE;
69 /* Some PS/2 mice send reports with negative bit set in data[0] and zero for movement. I think this is a
70 bug in the mouse, but working around it only causes artifacts when the actual report is -256; they'll
71 be treated as zero. This should be rare if the mouse sampling rate is set to a reasonable value; the
72 default of 100 Hz is plenty. (Stephen Tell) */
74 if (mouse_buffer[1] == 0)
80 state_dx = (mouse_buffer[0] & 0x10) ?
81 mouse_buffer[1] - 256 :
85 if (mouse_buffer[2] == 0)
91 state_dy = -((mouse_buffer[0] & 0x20) ?
92 mouse_buffer[2] - 256 :
96 if (((state_dx!=0) || (state_dy!=0) || (state_buttons!=0)))
98 // FIXME: Implement button state, see /include/ntddmous.h
100 DeviceObject = (PDEVICE_OBJECT)ServiceContext;
101 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
103 if (DeviceExtension->InputDataCount == MOUSE_BUFFER_SIZE)
108 DeviceExtension->MouseInputData[DeviceExtension->InputDataCount].RawButtons = state_buttons;
109 DeviceExtension->MouseInputData[DeviceExtension->InputDataCount].ButtonData = state_buttons;
110 DeviceExtension->MouseInputData[DeviceExtension->InputDataCount].LastX = state_dx;
111 DeviceExtension->MouseInputData[DeviceExtension->InputDataCount].LastY = state_dy;
112 DeviceExtension->InputDataCount++;
114 KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL);
121 /* Write a PS/2 mouse command. */
123 static void mouse_write_command (int command)
126 controller_write_command (CONTROLLER_COMMAND_WRITE_MODE);
128 controller_write_output (command);
131 /* Send a byte to the PS/2 mouse & handle returned ACK. */
133 static void mouse_write_ack (int value)
136 controller_write_command (CONTROLLER_COMMAND_WRITE_MOUSE);
138 controller_write_output (value);
140 /* We expect an ACK in response. */
142 mouse_replies_expected++;
146 /* Check if this is a dual port controller. */
148 BOOLEAN detect_ps2_port(void)
151 BOOLEAN return_value = FALSE;
152 LARGE_INTEGER Millisecond_Timeout;
154 Millisecond_Timeout.QuadPart = 1;
156 return TRUE; // The rest of this code fails under BOCHs
158 /* Put the value 0x5A in the output buffer using the "WriteAuxiliary Device Output Buffer" command (0xD3).
159 Poll the Status Register for a while to see if the value really turns up in the Data Register. If the
160 KEYBOARD_STATUS_MOUSE_OBF bit is also set to 1 in the Status Register, we assume this controller has an
161 Auxiliary Port (a.k.a. Mouse Port). */
164 controller_write_command (CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER);
167 // 0x5A is a random dummy value
168 controller_write_output (0x5A);
170 for (loops = 0; loops < 10; loops++)
172 unsigned char status = controller_read_status();
174 if((status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
176 controller_read_input();
177 if ((status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) != 0)
184 KeDelayExecutionThread (KernelMode, FALSE, &Millisecond_Timeout);
190 // Initialize the PS/2 mouse support
192 BOOLEAN mouse_init (PDEVICE_OBJECT DeviceObject)
194 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
199 if (!detect_ps2_port ()) return FALSE;
203 DeviceExtension->InputDataCount = 0;
204 DeviceExtension->MouseInputData = ExAllocatePool(NonPagedPool, sizeof(MOUSE_INPUT_DATA) * MOUSE_BUFFER_SIZE);
206 // Enable the PS/2 mouse port
207 controller_write_command_word (CONTROLLER_COMMAND_MOUSE_ENABLE);
210 mouse_write_ack (MOUSE_SET_SAMPLE_RATE);
211 mouse_write_ack (200);
214 mouse_write_ack (MOUSE_SET_RESOLUTION);
218 mouse_write_ack (MOUSE_SET_SCALE21);
220 // Enable the PS/2 device
221 mouse_write_ack (MOUSE_ENABLE_DEVICE);
223 // Enable controller interrupts
224 mouse_write_command (MOUSE_INTERRUPTS_ON);
226 // Connect the interrupt for the mouse irq
227 MappedIrq = HalGetInterruptVector(Internal, 0, 0, MOUSE_IRQ, &Dirql, &Affinity);
229 IoConnectInterrupt(&DeviceExtension->MouseInterrupt, ps2_mouse_handler, DeviceObject, NULL, MappedIrq,
230 Dirql, Dirql, 0, FALSE, Affinity, FALSE);