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)
22 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
23 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
24 int state_dx, state_dy, state_buttons;
26 unsigned status = controller_read_status();
27 scancode = controller_read_input();
30 * Don't handle the mouse event if we aren't connected to the mouse class
33 if (DeviceExtension->ClassInformation.CallBack == NULL)
38 if ((status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) != 0)
40 // mouse_handle_event(scancode); proceed to handle it
44 return FALSE; // keyboard_handle_event(scancode);
47 if (mouse_replies_expected > 0)
49 if (scancode == MOUSE_ACK)
51 mouse_replies_expected--;
55 mouse_replies_expected = 0;
58 /* Add this scancode to the mouse event queue. */
59 mouse_buffer[mouse_buffer_position] = scancode;
60 mouse_buffer_position++;
62 /* If the buffer is full, parse this event */
63 if (mouse_buffer_position == 3)
65 mouse_buffer_position = 0;
67 state_buttons = (mouse_buffer[0] & 1) * GPM_B_LEFT +
68 (mouse_buffer[0] & 2) * GPM_B_RIGHT +
69 (mouse_buffer[0] & 4) * GPM_B_MIDDLE;
72 * Some PS/2 mice send reports with negative bit set in data[0] and zero
73 * for movement. I think this is a bug in the mouse, but working around
74 * it only causes artifacts when the actual report is -256; they'll
75 * be treated as zero. This should be rare if the mouse sampling rate is
76 * set to a reasonable value; the default of 100 Hz is plenty.
79 if (mouse_buffer[1] == 0)
85 state_dx = (mouse_buffer[0] & 0x10) ?
86 mouse_buffer[1] - 256 :
90 if (mouse_buffer[2] == 0)
96 state_dy = -((mouse_buffer[0] & 0x20) ?
97 mouse_buffer[2] - 256 :
101 if (((state_dx!=0) || (state_dy!=0) || (state_buttons!=0)))
104 PMOUSE_INPUT_DATA Input;
106 /* FIXME: Implement button state, see /include/ntddmous.h */
108 DeviceObject = (PDEVICE_OBJECT)ServiceContext;
109 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
110 Queue = DeviceExtension->ActiveQueue % 2;
112 if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE)
117 Input = &DeviceExtension->MouseInputData[Queue]
118 [DeviceExtension->InputDataCount[Queue]];
119 Input->RawButtons = state_buttons;
120 Input->ButtonData = state_buttons;
121 Input->LastX = state_dx;
122 Input->LastY = state_dy;
123 DeviceExtension->InputDataCount[Queue]++;
125 KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp,
132 /* Write a PS/2 mouse command. */
134 static void mouse_write_command (int command)
137 controller_write_command (CONTROLLER_COMMAND_WRITE_MODE);
139 controller_write_output (command);
142 /* Send a byte to the PS/2 mouse & handle returned ACK. */
144 static void mouse_write_ack (int value)
147 controller_write_command (CONTROLLER_COMMAND_WRITE_MOUSE);
149 controller_write_output (value);
151 /* We expect an ACK in response. */
153 mouse_replies_expected++;
157 /* Check if this is a dual port controller. */
159 BOOLEAN detect_ps2_port(void)
162 BOOLEAN return_value = FALSE;
163 LARGE_INTEGER Millisecond_Timeout;
165 Millisecond_Timeout.QuadPart = 1;
167 return TRUE; // The rest of this code fails under BOCHs
169 /* Put the value 0x5A in the output buffer using the "WriteAuxiliary Device Output Buffer" command (0xD3).
170 Poll the Status Register for a while to see if the value really turns up in the Data Register. If the
171 KEYBOARD_STATUS_MOUSE_OBF bit is also set to 1 in the Status Register, we assume this controller has an
172 Auxiliary Port (a.k.a. Mouse Port). */
175 controller_write_command (CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER);
178 // 0x5A is a random dummy value
179 controller_write_output (0x5A);
181 for (loops = 0; loops < 10; loops++)
183 unsigned char status = controller_read_status();
185 if((status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
187 controller_read_input();
188 if ((status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) != 0)
195 KeDelayExecutionThread (KernelMode, FALSE, &Millisecond_Timeout);
201 // Initialize the PS/2 mouse support
203 BOOLEAN mouse_init (PDEVICE_OBJECT DeviceObject)
205 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
210 if (!detect_ps2_port ()) return FALSE;
214 DeviceExtension->InputDataCount[0] = 0;
215 DeviceExtension->InputDataCount[1] = 0;
216 DeviceExtension->ActiveQueue = 0;
218 // Enable the PS/2 mouse port
219 controller_write_command_word (CONTROLLER_COMMAND_MOUSE_ENABLE);
222 mouse_write_ack (MOUSE_SET_SAMPLE_RATE);
223 mouse_write_ack (200);
226 mouse_write_ack (MOUSE_SET_RESOLUTION);
230 mouse_write_ack (MOUSE_SET_SCALE21);
232 // Enable the PS/2 device
233 mouse_write_ack (MOUSE_ENABLE_DEVICE);
235 // Enable controller interrupts
236 mouse_write_command (MOUSE_INTERRUPTS_ON);
238 // Connect the interrupt for the mouse irq
239 MappedIrq = HalGetInterruptVector(Internal, 0, 0, MOUSE_IRQ, &Dirql, &Affinity);
241 IoConnectInterrupt(&DeviceExtension->MouseInterrupt, ps2_mouse_handler, DeviceObject, NULL, MappedIrq,
242 Dirql, Dirql, 0, FALSE, Affinity, FALSE);