kvm tools, setup: Create private directory
[linux-2.6/next.git] / tools / kvm / hw / i8042.c
blob3a3642596b49a026854e02fd6b35575378a5c4cd
1 #include "kvm/read-write.h"
2 #include "kvm/ioport.h"
3 #include "kvm/mutex.h"
4 #include "kvm/util.h"
5 #include "kvm/term.h"
6 #include "kvm/kvm.h"
7 #include "kvm/i8042.h"
8 #include "kvm/kvm-cpu.h"
10 #include <stdint.h>
13 * IRQs
15 #define KBD_IRQ 1
16 #define AUX_IRQ 12
19 * Registers
21 #define I8042_DATA_REG 0x60
22 #define I8042_COMMAND_REG 0x64
25 * Commands
27 #define I8042_CMD_CTL_RCTR 0x20
28 #define I8042_CMD_CTL_WCTR 0x60
29 #define I8042_CMD_AUX_LOOP 0xD3
30 #define I8042_CMD_AUX_SEND 0xD4
31 #define I8042_CMD_AUX_TEST 0xA9
32 #define I8042_CMD_AUX_DISABLE 0xA7
33 #define I8042_CMD_AUX_ENABLE 0xA8
34 #define I8042_CMD_SYSTEM_RESET 0xFE
36 #define RESPONSE_ACK 0xFA
38 #define MODE_DISABLE_AUX 0x20
40 #define AUX_ENABLE_REPORTING 0x20
41 #define AUX_SCALING_FLAG 0x10
42 #define AUX_DEFAULT_RESOLUTION 0x2
43 #define AUX_DEFAULT_SAMPLE 100
46 * Status register bits
48 #define I8042_STR_AUXDATA 0x20
49 #define I8042_STR_KEYLOCK 0x10
50 #define I8042_STR_CMDDAT 0x08
51 #define I8042_STR_MUXERR 0x04
52 #define I8042_STR_OBF 0x01
54 #define KBD_MODE_KBD_INT 0x01
55 #define KBD_MODE_SYS 0x02
57 #define QUEUE_SIZE 128
60 * This represents the current state of the PS/2 keyboard system,
61 * including the AUX device (the mouse)
63 struct kbd_state {
64 struct kvm *kvm;
66 char kq[QUEUE_SIZE]; /* Keyboard queue */
67 int kread, kwrite; /* Indexes into the queue */
68 int kcount; /* number of elements in queue */
70 char mq[QUEUE_SIZE];
71 int mread, mwrite;
72 int mcount;
74 u8 mstatus; /* Mouse status byte */
75 u8 mres; /* Current mouse resolution */
76 u8 msample; /* Current mouse samples/second */
78 u8 mode; /* i8042 mode register */
79 u8 status; /* i8042 status register */
81 * Some commands (on port 0x64) have arguments;
82 * we store the command here while we wait for the argument
84 u32 write_cmd;
87 static struct kbd_state state;
90 * If there are packets to be read, set the appropriate IRQs high
92 static void kbd_update_irq(void)
94 u8 klevel = 0;
95 u8 mlevel = 0;
97 /* First, clear the kbd and aux output buffer full bits */
98 state.status &= ~(I8042_STR_OBF | I8042_STR_AUXDATA);
100 if (state.kcount > 0) {
101 state.status |= I8042_STR_OBF;
102 klevel = 1;
105 /* Keyboard has higher priority than mouse */
106 if (klevel == 0 && state.mcount != 0) {
107 state.status |= I8042_STR_OBF | I8042_STR_AUXDATA;
108 mlevel = 1;
111 kvm__irq_line(state.kvm, KBD_IRQ, klevel);
112 kvm__irq_line(state.kvm, AUX_IRQ, mlevel);
116 * Add a byte to the mouse queue, then set IRQs
118 void mouse_queue(u8 c)
120 if (state.mcount >= QUEUE_SIZE)
121 return;
123 state.mq[state.mwrite++ % QUEUE_SIZE] = c;
125 state.mcount++;
126 kbd_update_irq();
130 * Add a byte to the keyboard queue, then set IRQs
132 void kbd_queue(u8 c)
134 if (state.kcount >= QUEUE_SIZE)
135 return;
137 state.kq[state.kwrite++ % QUEUE_SIZE] = c;
139 state.kcount++;
140 kbd_update_irq();
143 static void kbd_write_command(struct kvm *kvm, u8 val)
145 switch (val) {
146 case I8042_CMD_CTL_RCTR:
147 kbd_queue(state.mode);
148 break;
149 case I8042_CMD_CTL_WCTR:
150 case I8042_CMD_AUX_SEND:
151 case I8042_CMD_AUX_LOOP:
152 state.write_cmd = val;
153 break;
154 case I8042_CMD_AUX_TEST:
155 /* 0 means we're a normal PS/2 mouse */
156 mouse_queue(0);
157 break;
158 case I8042_CMD_AUX_DISABLE:
159 state.mode |= MODE_DISABLE_AUX;
160 break;
161 case I8042_CMD_AUX_ENABLE:
162 state.mode &= ~MODE_DISABLE_AUX;
163 break;
164 case I8042_CMD_SYSTEM_RESET:
165 kvm_cpu__reboot();
166 break;
167 default:
168 break;
173 * Called when the OS reads from port 0x60 (PS/2 data)
175 static u32 kbd_read_data(void)
177 u32 ret;
178 int i;
180 if (state.kcount != 0) {
181 /* Keyboard data gets read first */
182 ret = state.kq[state.kread++ % QUEUE_SIZE];
183 state.kcount--;
184 kvm__irq_line(state.kvm, KBD_IRQ, 0);
185 kbd_update_irq();
186 } else if (state.mcount > 0) {
187 /* Followed by the mouse */
188 ret = state.mq[state.mread++ % QUEUE_SIZE];
189 state.mcount--;
190 kvm__irq_line(state.kvm, AUX_IRQ, 0);
191 kbd_update_irq();
192 } else if (state.kcount == 0) {
193 i = state.kread - 1;
194 if (i < 0)
195 i = QUEUE_SIZE;
196 ret = state.kq[i];
198 return ret;
202 * Called when the OS read from port 0x64, the command port
204 static u32 kbd_read_status(void)
206 return (u32)state.status;
210 * Called when the OS writes to port 0x60 (data port)
211 * Things written here are generally arguments to commands previously
212 * written to port 0x64 and stored in state.write_cmd
214 static void kbd_write_data(u32 val)
216 switch (state.write_cmd) {
217 case I8042_CMD_CTL_WCTR:
218 state.mode = val;
219 kbd_update_irq();
220 break;
221 case I8042_CMD_AUX_LOOP:
222 mouse_queue(val);
223 mouse_queue(RESPONSE_ACK);
224 break;
225 case I8042_CMD_AUX_SEND:
226 /* The OS wants to send a command to the mouse */
227 mouse_queue(RESPONSE_ACK);
228 switch (val) {
229 case 0xe6:
230 /* set scaling = 1:1 */
231 state.mstatus &= ~AUX_SCALING_FLAG;
232 break;
233 case 0xe8:
234 /* set resolution */
235 state.mres = val;
236 break;
237 case 0xe9:
238 /* Report mouse status/config */
239 mouse_queue(state.mstatus);
240 mouse_queue(state.mres);
241 mouse_queue(state.msample);
242 break;
243 case 0xf2:
244 /* send ID */
245 mouse_queue(0); /* normal mouse */
246 break;
247 case 0xf3:
248 /* set sample rate */
249 state.msample = val;
250 break;
251 case 0xf4:
252 /* enable reporting */
253 state.mstatus |= AUX_ENABLE_REPORTING;
254 break;
255 case 0xf5:
256 state.mstatus &= ~AUX_ENABLE_REPORTING;
257 break;
258 case 0xf6:
259 /* set defaults, just fall through to reset */
260 case 0xff:
261 /* reset */
262 state.mstatus = 0x0;
263 state.mres = AUX_DEFAULT_RESOLUTION;
264 state.msample = AUX_DEFAULT_SAMPLE;
265 break;
266 default:
267 break;
269 break;
270 case 0:
271 /* Just send the ID */
272 kbd_queue(RESPONSE_ACK);
273 kbd_queue(0xab);
274 kbd_queue(0x41);
275 kbd_update_irq();
276 break;
277 default:
278 /* Yeah whatever */
279 break;
281 state.write_cmd = 0;
284 static void kbd_reset(void)
286 state = (struct kbd_state) {
287 .status = I8042_STR_MUXERR | I8042_STR_CMDDAT | I8042_STR_KEYLOCK, /* 0x1c */
288 .mode = KBD_MODE_KBD_INT | KBD_MODE_SYS, /* 0x3 */
289 .mres = AUX_DEFAULT_RESOLUTION,
290 .msample = AUX_DEFAULT_SAMPLE,
295 * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
297 static bool kbd_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
299 switch (port) {
300 case I8042_COMMAND_REG: {
301 u8 value = kbd_read_status();
302 ioport__write8(data, value);
303 break;
305 case I8042_DATA_REG: {
306 u32 value = kbd_read_data();
307 ioport__write32(data, value);
308 break;
310 default:
311 return false;
314 return true;
317 static bool kbd_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
319 switch (port) {
320 case I8042_COMMAND_REG: {
321 u8 value = ioport__read8(data);
322 kbd_write_command(kvm, value);
323 break;
325 case I8042_DATA_REG: {
326 u32 value = ioport__read32(data);
327 kbd_write_data(value);
328 break;
330 default:
331 return false;
334 return true;
337 static struct ioport_operations kbd_ops = {
338 .io_in = kbd_in,
339 .io_out = kbd_out,
342 void kbd__init(struct kvm *kvm)
344 kbd_reset();
345 state.kvm = kvm;
346 ioport__register(I8042_DATA_REG, &kbd_ops, 2, NULL);
347 ioport__register(I8042_COMMAND_REG, &kbd_ops, 2, NULL);