soc/intel/xeon_sp/util: Enhance lock_pam0123
[coreboot2.git] / payloads / libpayload / drivers / i8042 / mouse.c
blob9b94eec5bc068a1b87cd65da037dba872739e1d0
1 /*
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
7 * are met:
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
26 * SUCH DAMAGE.
29 #include <libpayload-config.h>
30 #include <libpayload.h>
32 static int x_axis;
33 static int y_axis;
34 static int z_axis;
35 static u32 buttons;
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)
44 i8042_cmd(0xd4);
46 i8042_write_data(cmd);
48 return i8042_wait_read_aux() == 0xfa;
51 static u8 mouse_cmd_data(u8 cmd, u8 val)
53 if (!mouse_cmd(cmd))
54 return 0;
56 return mouse_cmd(val);
59 /** Try to detect Microsoft Intelli mouse */
60 static u8 mouse_is_intellimouse(void)
62 /* Silence mouse. */
63 if (!mouse_cmd(0xf5))
64 return 0;
66 /* Set standard. */
67 if (!mouse_cmd(0xf6))
68 return 0;
70 /* Magic sequence. */
71 if (!mouse_cmd_data(0xf3, 0xc8))
72 return 0;
73 if (!mouse_cmd_data(0xf3, 0x64))
74 return 0;
75 if (!mouse_cmd_data(0xf3, 0x50))
76 return 0;
78 /* Get mouse id */
79 if (!mouse_cmd(0xf2))
80 return 0;
82 if (i8042_wait_read_aux() != 0x03)
83 return 0;
85 return 1;
88 /** Try to detect Microsoft Explorer mouse */
89 static u8 mouse_is_intellimouse_explorer(void)
91 /* Silence mouse. */
92 if (!mouse_cmd(0xf5))
93 return 0;
95 /* Set standard. */
96 if (!mouse_cmd(0xf6))
97 return 0;
99 /* Magic sequence. */
100 if (!mouse_cmd_data(0xf3, 0xc8))
101 return 0;
102 if (!mouse_cmd_data(0xf3, 0xc8))
103 return 0;
104 if (!mouse_cmd_data(0xf3, 0x50))
105 return 0;
107 /* Get mouse id */
108 if (!mouse_cmd(0xf2))
109 return 0;
111 if (i8042_wait_read_aux() != 4)
112 return 0;
114 return 1;
117 /** Decode temporary buffer
118 * Sanity check to prevent out of order decode.
119 * Decode PS/2 data.
120 * Supported devices:
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)
130 return;
131 if ((mouse_buf[3] & 0x10) != (mouse_buf[3] & 0x08)) {
132 mouse_buf_idx = 0;
133 return;
135 } else if (is_explorer_intellimouse) {
136 if (mouse_buf_idx < 4)
137 return;
138 if (mouse_buf[3] & 0xc0) {
139 mouse_buf_idx = 0;
140 return;
142 } else {
143 if (mouse_buf_idx < 3)
144 return;
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;
160 mouse_buf_idx = 0;
163 /** Insert data into internal temporary buffer. */
164 static void insert_buf(unsigned char c)
166 /* Validate input:
167 * First byte shall have bit 3 set ! */
168 if (!mouse_buf_idx && !(c & 8))
169 return;
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)
177 if (!initialized)
178 return;
180 while (i8042_data_ready_aux()) {
181 insert_buf(i8042_read_data_aux());
182 mouse_decode();
186 /** Mouse cursor interface method
187 * Return and reset internal state.
189 static void mouse_state(int *x, int *y, int *z, u32 *b)
191 if (!initialized)
192 return;
194 mouse_sample();
196 if (x) {
197 *x = x_axis;
198 x_axis = 0;
200 if (y) {
201 *y = y_axis;
202 y_axis = 0;
204 if (z) {
205 *z = z_axis;
206 z_axis = 0;
208 if (b)
209 *b = buttons;
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)
220 int ret;
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())
227 return;
229 /* Empty mouse buffer. */
230 while (i8042_data_ready_aux())
231 i8042_read_data_aux();
233 /* Enable mouse.
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.
237 * Ignore it ... */
238 ret = i8042_cmd(0xa8);
239 if (ret == -1)
240 return;
242 /* Silence mouse. */
243 if (!mouse_cmd(0xf5))
244 return;
246 /* Read mouse id. */
247 if (!mouse_cmd(0xf2))
248 return;
250 ret = i8042_wait_read_aux();
251 if (ret)
252 return;
254 /* Get and enable features (scroll wheel and 5 buttons) */
255 is_intellimouse = mouse_is_intellimouse();
256 is_explorer_intellimouse = mouse_is_intellimouse_explorer();
258 /* Set defaults. */
259 if (!mouse_cmd(0xf6))
260 return;
262 /* Enable data transmission. */
263 if (!mouse_cmd(0xf4))
264 return;
266 initialized = 1;
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
276 * controller */
277 if (inb(0x64) == 0xFF || !initialized)
278 return;
280 /* Empty keyboard buffer */
281 while (i8042_data_ready_aux())
282 i8042_read_data_aux();
284 /* Disable mouse. */
285 i8042_cmd(0xa7);
287 initialized = 0;
289 /* Release keyboard controller driver */
290 i8042_close();