1 // Support for handling the PS/2 mouse/keyboard ports.
3 // Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4 // Based on code Copyright (c) 1999-2004 Vojtech Pavlik
6 // This file may be distributed under the terms of the GNU GPLv3 license.
8 #include "ioport.h" // inb
9 #include "util.h" // dprintf
10 #include "biosvar.h" // GET_EBDA
11 #include "ps2port.h" // kbd_command
14 /****************************************************************
15 * Low level i8042 commands.
16 ****************************************************************/
19 #define I8042_CTL_TIMEOUT 10000
21 #define I8042_BUFFER_SIZE 16
26 // XXX - implement real udelay
27 outb(0x00, PORT_DIAG);
34 for (i=0; i<I8042_CTL_TIMEOUT; i++) {
35 u8 status = inb(PORT_PS2_STATUS);
36 if (status & I8042_STR_OBF)
40 dprintf(1, "i8042 timeout on wait read\n");
45 i8042_wait_write(void)
48 for (i=0; i<I8042_CTL_TIMEOUT; i++) {
49 u8 status = inb(PORT_PS2_STATUS);
50 if (! (status & I8042_STR_IBF))
54 dprintf(1, "i8042 timeout on wait write\n");
61 unsigned long flags = irq_save();
64 for (i=0; i<I8042_BUFFER_SIZE; i++) {
65 u8 status = inb(PORT_PS2_STATUS);
66 if (! (status & I8042_STR_OBF)) {
75 dprintf(1, "i8042 timeout on flush\n");
80 __i8042_command(int command, u8 *param)
82 int receive = (command >> 8) & 0xf;
83 int send = (command >> 12) & 0xf;
86 int ret = i8042_wait_write();
89 outb(command, PORT_PS2_STATUS);
91 // Send parameters (if any).
93 for (i = 0; i < send; i++) {
94 ret = i8042_wait_write();
97 outb(param[i], PORT_PS2_DATA);
100 // Receive parameters (if any).
101 for (i = 0; i < receive; i++) {
102 ret = i8042_wait_read();
105 param[i] = inb(PORT_PS2_DATA);
112 i8042_command(int command, u8 *param)
114 unsigned long flags = irq_save();
115 int ret = __i8042_command(command, param);
118 dprintf(2, "i8042 command %x failed\n", command);
123 i8042_kbd_write(u8 c)
125 unsigned long flags = irq_save();
127 int ret = i8042_wait_write();
129 outb(c, PORT_PS2_DATA);
137 i8042_aux_write(u8 c)
139 return i8042_command(I8042_CMD_AUX_SEND, &c);
143 /****************************************************************
145 ****************************************************************/
147 #define PS2_RET_ACK 0xfa
148 #define PS2_RET_NAK 0xfe
151 ps2_sendbyte(int aux, u8 command)
155 ret = i8042_aux_write(command);
157 ret = i8042_kbd_write(command);
162 ret = i8042_wait_read();
165 u8 ack = inb(PORT_PS2_DATA);
166 if (ack != PS2_RET_ACK) {
167 dprintf(1, "Missing ack (got %x not %x)\n", ack, PS2_RET_ACK);
175 ps2_command(int aux, int command, u8 *param)
178 int receive = (command >> 8) & 0xf;
179 int send = (command >> 12) & 0xf;
181 // Disable interrupts and keyboard/mouse.
182 u8 ps2ctr = GET_EBDA(ps2ctr);
185 newctr |= I8042_CTR_KBDDIS;
187 newctr |= I8042_CTR_AUXDIS;
188 newctr &= ~(I8042_CTR_KBDINT|I8042_CTR_AUXINT);
189 dprintf(6, "i8042 ctr old=%x new=%x\n", ps2ctr, newctr);
190 int ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr);
195 ret = ps2_sendbyte(aux, command);
199 // Send parameters (if any).
201 for (i = 0; i < send; i++) {
202 ret = ps2_sendbyte(aux, command);
207 // Receive parameters (if any).
208 for (i = 0; i < receive; i++) {
209 ret = i8042_wait_read();
211 // On a receive timeout, return the item number that the
212 // transfer failed on.
216 param[i] = inb(PORT_PS2_DATA);
220 // Restore interrupts and keyboard/mouse.
221 ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr);
229 kbd_command(int command, u8 *param)
231 int ret = ps2_command(0, command, param);
233 dprintf(2, "keyboard command %x failed (ret=%d)\n", command, ret);
238 aux_command(int command, u8 *param)
240 int ret = ps2_command(1, command, param);
242 dprintf(2, "mouse command %x failed (ret=%d)\n", command, ret);