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
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 /* Overflowing FIFO implementation */
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
)
54 ret
= malloc(sizeof(*ret
));
58 memset(ret
, 0, sizeof(*ret
));
60 ret
->buf
= malloc(len
);
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.
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
)
83 fifo
->rx
= fifo
->rx
% fifo
->len
;
86 /** Test fifo queue element count.
87 * Returns 1 if fifo is empty.
90 static int fifo_is_empty(struct fifo
*fifo
)
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.
102 static u8
fifo_pop(struct fifo
*fifo
)
106 if (fifo_is_empty(fifo
))
109 ret
= fifo
->buf
[fifo
->rx
++];
110 fifo
->rx
= fifo
->rx
% fifo
->len
;
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.
120 static u8
fifo_peek(struct fifo
*fifo
)
122 if (fifo_is_empty(fifo
))
125 return fifo
->buf
[fifo
->rx
];
128 /** Destroys a fifo queue.
131 static void fifo_destroy(struct fifo
*fifo
)
133 if (fifo
&& fifo
->buf
)
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); }
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)
164 while (retries
-- && (read_status() & IBF
))
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)
177 while (retries
-- && !(read_status() & OBF
))
183 /** Keyboard controller has a ps2 port.
184 * Returns if ps2 port is available.
186 size_t i8042_has_ps2(void)
191 /** Keyboard controller has an aux port.
192 * Returns if aux port is available.
194 size_t i8042_has_aux(void)
200 * Probe for keyboard controller
201 * Returns: 1 for success, 0 for failure
211 /* If 0x64 returns 0xff, then we have no keyboard
213 if (read_status() == 0xFF) {
214 printf("ERROR: No keyboard controller found!\n");
218 if (!i8042_wait_cmd_rdy()) {
219 printf("ERROR: i8042_wait_cmd_rdy failed!\n");
225 /* Disable first device */
226 if (i8042_cmd(I8042_CMD_DIS_KB
) != 0) {
228 printf("ERROR: i8042_cmd I8042_CMD_DIS_KB failed!\n");
232 /* Disable second device */
233 if (i8042_cmd(I8042_CMD_DIS_AUX
) != 0) {
235 printf("ERROR: i8042_cmd I8042_CMD_DIS_AUX failed!\n");
240 while (read_status() & OBF
)
244 if (i8042_cmd_with_response(I8042_CMD_SELF_TEST
)
245 != I8042_SELF_TEST_RSP
) {
247 printf("ERROR: i8042_cmd I8042_CMD_SELF_TEST failed!\n");
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);
263 initialized
= aux_fifo
|| ps2_fifo
;
268 /* Close the keyboard controller */
269 void i8042_close(void)
274 fifo_destroy(aux_fifo
);
275 fifo_destroy(ps2_fifo
);
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
)
291 if (!i8042_wait_cmd_rdy())
296 if (!i8042_wait_cmd_rdy())
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
);
312 if (!i8042_wait_data_rdy())
318 /** Send additional data to keyboard controller.
319 * @param data The data to be send.
321 void i8042_write_data(u8 data
)
326 if (!i8042_wait_cmd_rdy())
331 if (!i8042_wait_cmd_rdy())
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
);
348 i8042_write_data(data
);
354 * Probe for keyboard controller data and queue it.
356 static void i8042_data_poll(void)
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
;
375 /** Keyboard controller data ready status.
376 * Signals that keyboard data is ready for reading.
378 u8
i8042_data_ready_ps2(void)
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)
394 return !fifo_is_empty(aux_fifo
);
398 * Returns available keyboard data, if any.
400 u8
i8042_read_data_ps2(void)
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)
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)
432 while (retries
-- && !i8042_data_ready_ps2())
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)
446 while (retries
-- && !i8042_data_ready_aux())
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
);
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
);
479 cfg
|= I8042_CMD_BYTE_XLATE
;
481 cfg
&= ~I8042_CMD_BYTE_XLATE
;
482 return i8042_cmd_with_data(I8042_CMD_WR_CMD_BYTE
, cfg
);