mb/google/brya/var/uldrenite: Generate RAM ID and SPD file
[coreboot2.git] / payloads / libpayload / drivers / i8042 / i8042.c
bloba89b9d9717e0becc65bad279add8b3a0ed72fa40
1 /*
3 * Patrick Rudolph 2017 <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>
31 #include <stdbool.h>
32 #include <stddef.h>
34 #include "i8042.h"
36 /* Overflowing FIFO implementation */
38 struct fifo {
39 u8 *buf;
40 size_t tx;
41 size_t rx;
42 size_t len;
45 /** Initialize a new fifo queue.
46 * Initialize a new fifo with length @len.
47 * @len: Length of new fifo
48 * Returns NULL on error.
50 static struct fifo *fifo_init(size_t len)
52 struct fifo *ret;
54 ret = malloc(sizeof(*ret));
55 if (!ret)
56 return NULL;
58 memset(ret, 0, sizeof(*ret));
60 ret->buf = malloc(len);
61 if (!ret->buf) {
62 free(ret);
63 return NULL;
66 ret->len = len;
68 return ret;
71 /** Push object onto fifo queue.
72 * Pushes a new object onto the fifo. In case the fifo
73 * is full the oldest object is overwritten.
74 * @fifo: Fifo to use
75 * @c: Element to push
77 static void fifo_push(struct fifo *fifo, u8 c)
79 fifo->buf[fifo->tx++] = c;
80 fifo->tx = fifo->tx % fifo->len;
81 if (fifo->tx == fifo->rx)
82 fifo->rx++;
83 fifo->rx = fifo->rx % fifo->len;
86 /** Test fifo queue element count.
87 * Returns 1 if fifo is empty.
88 * @fifo: Fifo to use
90 static int fifo_is_empty(struct fifo *fifo)
92 if (!fifo)
93 return 1;
94 return fifo->tx == fifo->rx;
97 /** Pop element from fifo queue.
98 * Returns the oldest object from queue if any.
99 * In case the queue is empty 0 is returned.
100 * @fifo: Fifo to use
102 static u8 fifo_pop(struct fifo *fifo)
104 u8 ret;
106 if (fifo_is_empty(fifo))
107 return 0;
109 ret = fifo->buf[fifo->rx++];
110 fifo->rx = fifo->rx % fifo->len;
112 return ret;
115 /** Peek on the head of fifo queue.
116 * Returns the oldest object on the queue if any.
117 * In case the queue is empty 0 is returned.
118 * @fifo: Fifo to use
120 static u8 fifo_peek(struct fifo *fifo)
122 if (fifo_is_empty(fifo))
123 return 0;
125 return fifo->buf[fifo->rx];
128 /** Destroys a fifo queue.
129 * @fifo: Fifo to use
131 static void fifo_destroy(struct fifo *fifo)
133 if (fifo && fifo->buf)
134 free(fifo->buf);
135 if (fifo)
136 free(fifo);
139 /* i8042 keyboard controller implementation */
141 static inline u8 read_status(void) { return inb(0x64); }
142 static inline u8 read_data(void) { return inb(0x60); }
143 static inline void write_cmd(u8 cmd) { outb(cmd, 0x64); }
144 static inline void write_data(u8 data) { outb(data, 0x60); }
146 #define OBF 1
147 #define IBF 2
149 /* Keyboard controller methods */
150 static int initialized = 0;
151 static int kbc_init = 0;
152 static struct fifo *aux_fifo = NULL;
153 static struct fifo *ps2_fifo = NULL;
155 static int i8042_cmd_with_response(u8 cmd);
157 /** Wait for command ready.
158 * Wait for the keyboard controller to accept a new command.
159 * Returns: 0 on timeout
161 static u8 i8042_wait_cmd_rdy(void)
163 int retries = 10000;
164 while (retries-- && (read_status() & IBF))
165 udelay(50);
167 return retries > 0;
170 /** Wait for data ready.
171 * Wait for the keyboard controller to accept new data.
172 * Returns: 0 on timeout
174 static u8 i8042_wait_data_rdy(void)
176 int retries = 30000;
177 while (retries-- && !(read_status() & OBF))
178 udelay(50);
180 return retries > 0;
183 /** Keyboard controller has a ps2 port.
184 * Returns if ps2 port is available.
186 size_t i8042_has_ps2(void)
188 return !!ps2_fifo;
191 /** Keyboard controller has an aux port.
192 * Returns if aux port is available.
194 size_t i8042_has_aux(void)
196 return !!aux_fifo;
200 * Probe for keyboard controller
201 * Returns: 1 for success, 0 for failure
203 u8 i8042_probe(void)
205 if (initialized)
206 return 1;
208 aux_fifo = NULL;
209 ps2_fifo = NULL;
211 /* If 0x64 returns 0xff, then we have no keyboard
212 * controller */
213 if (read_status() == 0xFF) {
214 printf("ERROR: No keyboard controller found!\n");
215 return 0;
218 if (!i8042_wait_cmd_rdy()) {
219 printf("ERROR: i8042_wait_cmd_rdy failed!\n");
220 return 0;
223 kbc_init = 1;
225 /* Disable first device */
226 if (i8042_cmd(I8042_CMD_DIS_KB) != 0) {
227 kbc_init = 0;
228 printf("ERROR: i8042_cmd I8042_CMD_DIS_KB failed!\n");
229 return 0;
232 /* Disable second device */
233 if (i8042_cmd(I8042_CMD_DIS_AUX) != 0) {
234 kbc_init = 0;
235 printf("ERROR: i8042_cmd I8042_CMD_DIS_AUX failed!\n");
236 return 0;
239 /* Flush buffer */
240 while (read_status() & OBF)
241 read_data();
243 /* Self test. */
244 if (i8042_cmd_with_response(I8042_CMD_SELF_TEST)
245 != I8042_SELF_TEST_RSP) {
246 kbc_init = 0;
247 printf("ERROR: i8042_cmd I8042_CMD_SELF_TEST failed!\n");
248 return 0;
251 /* Test secondary port */
252 if (CONFIG(LP_PC_MOUSE)) {
253 if (i8042_cmd_with_response(I8042_CMD_AUX_TEST) == 0)
254 aux_fifo = fifo_init(4 * 32);
257 /* Test first PS/2 port */
258 if (i8042_cmd_with_response(I8042_CMD_KB_TEST) == 0)
259 ps2_fifo = fifo_init(2 * 16);
261 kbc_init = 0;
263 initialized = aux_fifo || ps2_fifo;
265 return initialized;
268 /* Close the keyboard controller */
269 void i8042_close(void)
271 if (!initialized)
272 return;
274 fifo_destroy(aux_fifo);
275 fifo_destroy(ps2_fifo);
277 initialized = 0;
278 aux_fifo = NULL;
279 ps2_fifo = NULL;
282 /** Send command to keyboard controller.
283 * @param cmd: The command to be send.
284 * returns: 0 on success, -1 on failure.
286 int i8042_cmd(u8 cmd)
288 if (!initialized && !kbc_init)
289 return -1;
291 if (!i8042_wait_cmd_rdy())
292 return -1;
294 write_cmd(cmd);
296 if (!i8042_wait_cmd_rdy())
297 return -1;
299 return 0;
302 /** Send command to keyboard controller.
303 * @param cmd: The command to be send.
304 * returns: Response on success, -1 on failure.
306 static int i8042_cmd_with_response(u8 cmd)
308 const int ret = i8042_cmd(cmd);
309 if (ret != 0)
310 return ret;
312 if (!i8042_wait_data_rdy())
313 return -1;
315 return read_data();
318 /** Send additional data to keyboard controller.
319 * @param data The data to be send.
321 void i8042_write_data(u8 data)
323 if (!initialized)
324 return;
326 if (!i8042_wait_cmd_rdy())
327 return;
329 write_data(data);
331 if (!i8042_wait_cmd_rdy())
332 return;
336 * Send command & data to keyboard controller.
338 * @param cmd: The command to be sent.
339 * @param data: The data to be sent.
340 * Returns 0 on success, -1 on failure.
342 static int i8042_cmd_with_data(const u8 cmd, const u8 data)
344 const int ret = i8042_cmd(cmd);
345 if (ret != 0)
346 return ret;
348 i8042_write_data(data);
350 return ret;
354 * Probe for keyboard controller data and queue it.
356 static void i8042_data_poll(void)
358 u8 c;
360 if (!initialized)
361 return;
363 c = read_status();
364 while ((c != 0xFF) && (c & OBF)) {
365 const u8 in = read_data();
366 /* Assume "second PS/2 port output buffer full" flag works */
367 struct fifo *const fifo = (c & 0x20) ? aux_fifo : ps2_fifo;
368 if (fifo)
369 fifo_push(fifo, in);
371 c = read_status();
375 /** Keyboard controller data ready status.
376 * Signals that keyboard data is ready for reading.
378 u8 i8042_data_ready_ps2(void)
380 if (!initialized)
381 return 0;
382 i8042_data_poll();
383 return !fifo_is_empty(ps2_fifo);
386 /** Keyboard controller data ready status.
387 * Signals that mouse data is ready for reading.
389 u8 i8042_data_ready_aux(void)
391 if (!initialized)
392 return 0;
393 i8042_data_poll();
394 return !fifo_is_empty(aux_fifo);
398 * Returns available keyboard data, if any.
400 u8 i8042_read_data_ps2(void)
402 i8042_data_poll();
403 return fifo_pop(ps2_fifo);
407 * Returns available keyboard data without advancing the queue.
409 u8 i8042_peek_data_ps2(void)
411 return fifo_peek(ps2_fifo);
415 * Returns available mouse data, if any.
417 u8 i8042_read_data_aux(void)
419 i8042_data_poll();
420 return fifo_pop(aux_fifo);
424 * Waits for keyboard data.
425 * Waits for up to 500msec to receive data.
426 * Returns: -1 on timeout, data received otherwise
428 int i8042_wait_read_ps2(void)
430 int retries = 10000;
432 while (retries-- && !i8042_data_ready_ps2())
433 udelay(50);
435 return (retries <= 0) ? -1 : i8042_read_data_ps2();
438 /** Waits for mouse data.
439 * Waits for up to 500msec to receive data.
440 * Returns: -1 on timeout, data received otherwise
442 int i8042_wait_read_aux(void)
444 int retries = 10000;
446 while (retries-- && !i8042_data_ready_aux())
447 udelay(50);
449 return (retries <= 0) ? -1 : i8042_read_data_aux();
453 * Get the keyboard scancode translation state.
455 * Returns: -1 on timeout, 1 if the controller translates
456 * scancode set #2 to #1, and 0 if not.
458 int i8042_get_kbd_translation(void)
460 const int cfg = i8042_cmd_with_response(I8042_CMD_RD_CMD_BYTE);
461 if (cfg < 0)
462 return cfg;
464 return !!(cfg & I8042_CMD_BYTE_XLATE);
468 * Sets the keyboard scancode translation state.
470 * Returns: -1 on timeout, 0 otherwise.
472 int i8042_set_kbd_translation(const bool xlate)
474 int cfg = i8042_cmd_with_response(I8042_CMD_RD_CMD_BYTE);
475 if (cfg < 0)
476 return cfg;
478 if (xlate)
479 cfg |= I8042_CMD_BYTE_XLATE;
480 else
481 cfg &= ~I8042_CMD_BYTE_XLATE;
482 return i8042_cmd_with_data(I8042_CMD_WR_CMD_BYTE, cfg);