3 * Copyright (C) 2017 Patrick Rudolph <siro@das-labor.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <libpayload-config.h>
30 #include <libpayload.h>
36 static u8 is_intellimouse
;
37 static u8 is_explorer_intellimouse
;
38 static u8 initialized
;
39 static unsigned char mouse_buf
[4];
40 static unsigned char mouse_buf_idx
;
42 static u8
mouse_cmd(unsigned char cmd
)
46 i8042_write_data(cmd
);
48 return i8042_wait_read_aux() == 0xfa;
51 static u8
mouse_cmd_data(u8 cmd
, u8 val
)
56 return mouse_cmd(val
);
59 /** Try to detect Microsoft Intelli mouse */
60 static u8
mouse_is_intellimouse(void)
71 if (!mouse_cmd_data(0xf3, 0xc8))
73 if (!mouse_cmd_data(0xf3, 0x64))
75 if (!mouse_cmd_data(0xf3, 0x50))
82 if (i8042_wait_read_aux() != 0x03)
88 /** Try to detect Microsoft Explorer mouse */
89 static u8
mouse_is_intellimouse_explorer(void)
100 if (!mouse_cmd_data(0xf3, 0xc8))
102 if (!mouse_cmd_data(0xf3, 0xc8))
104 if (!mouse_cmd_data(0xf3, 0x50))
108 if (!mouse_cmd(0xf2))
111 if (i8042_wait_read_aux() != 4)
117 /** Decode temporary buffer
118 * Sanity check to prevent out of order decode.
121 * Generic 3 button mouse
122 * Microsoft Intelli mouse
123 * Microsoft Explorer mouse
125 static void mouse_decode(void)
127 /* Buffer full check and sanity check */
128 if (is_intellimouse
) {
129 if (mouse_buf_idx
< 4)
131 if ((mouse_buf
[3] & 0x10) != (mouse_buf
[3] & 0x08)) {
135 } else if (is_explorer_intellimouse
) {
136 if (mouse_buf_idx
< 4)
138 if (mouse_buf
[3] & 0xc0) {
143 if (mouse_buf_idx
< 3)
147 /* Common protocol */
148 x_axis
+= mouse_buf
[1] ? mouse_buf
[1] - ((mouse_buf
[0] << 4) & 0x100) : 0;
149 y_axis
+= mouse_buf
[2] ? ((mouse_buf
[0] << 3) & 0x100) - mouse_buf
[2] : 0;
150 buttons
= mouse_buf
[0] & 0x7;
152 /* Extended protocol */
153 if (is_intellimouse
) {
154 z_axis
+= (mouse_buf
[3] & 0x7) - (mouse_buf
[3] & 0x08) ? 8 : 0;
155 } else if (is_explorer_intellimouse
) {
156 z_axis
+= (mouse_buf
[3] & 0x7) - (mouse_buf
[3] & 0x08) ? 8 : 0;
157 buttons
= (mouse_buf
[0] & 0x7) | (mouse_buf
[3] & 0x30) >> 1;
163 /** Insert data into internal temporary buffer. */
164 static void insert_buf(unsigned char c
)
167 * First byte shall have bit 3 set ! */
168 if (!mouse_buf_idx
&& !(c
& 8))
171 mouse_buf
[mouse_buf_idx
++] = c
;
174 /** Probe i8042 for new aux data and try to decode it. */
175 static void mouse_sample(void)
180 while (i8042_data_ready_aux()) {
181 insert_buf(i8042_read_data_aux());
186 /** Mouse cursor interface method
187 * Return and reset internal state.
189 static void mouse_state(int *x
, int *y
, int *z
, u32
*b
)
212 static struct mouse_cursor_input_driver curs
= {
213 .get_state
= mouse_state
,
214 .input_type
= CURSOR_INPUT_TYPE_PS2
,
217 /** Probe for PS/2 mouse */
218 void i8042_mouse_init(void)
223 * Initialize keyboard controller.
224 * Might fail in case no AUX port or firmware disabled the AUX port.
226 if (!i8042_probe() || !i8042_has_aux())
229 /* Empty mouse buffer. */
230 while (i8042_data_ready_aux())
231 i8042_read_data_aux();
234 * Documentation is unclear at this point.
235 * Some recommend to wait for response, some claim there's none.
236 * No response on Lenovo H8 EC.
238 ret
= i8042_cmd(0xa8);
243 if (!mouse_cmd(0xf5))
247 if (!mouse_cmd(0xf2))
250 ret
= i8042_wait_read_aux();
254 /* Get and enable features (scroll wheel and 5 buttons) */
255 is_intellimouse
= mouse_is_intellimouse();
256 is_explorer_intellimouse
= mouse_is_intellimouse_explorer();
259 if (!mouse_cmd(0xf6))
262 /* Enable data transmission. */
263 if (!mouse_cmd(0xf4))
268 /* Register mouse cursor driver */
269 mouse_cursor_add_input_driver(&curs
);
272 /* Disable PS/2 mouse. */
273 void i8042_mouse_disconnect(void)
275 /* If 0x64 returns 0xff, then we have no keyboard
277 if (inb(0x64) == 0xFF || !initialized
)
280 /* Empty keyboard buffer */
281 while (i8042_data_ready_aux())
282 i8042_read_data_aux();
289 /* Release keyboard controller driver */