1 #include "kvm/read-write.h"
2 #include "kvm/ioport.h"
8 #include "kvm/kvm-cpu.h"
21 #define I8042_DATA_REG 0x60
22 #define I8042_COMMAND_REG 0x64
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)
66 char kq
[QUEUE_SIZE
]; /* Keyboard queue */
67 int kread
, kwrite
; /* Indexes into the queue */
68 int kcount
; /* number of elements in queue */
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
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)
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
;
105 /* Keyboard has higher priority than mouse */
106 if (klevel
== 0 && state
.mcount
!= 0) {
107 state
.status
|= I8042_STR_OBF
| I8042_STR_AUXDATA
;
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
)
123 state
.mq
[state
.mwrite
++ % QUEUE_SIZE
] = c
;
130 * Add a byte to the keyboard queue, then set IRQs
134 if (state
.kcount
>= QUEUE_SIZE
)
137 state
.kq
[state
.kwrite
++ % QUEUE_SIZE
] = c
;
143 static void kbd_write_command(struct kvm
*kvm
, u8 val
)
146 case I8042_CMD_CTL_RCTR
:
147 kbd_queue(state
.mode
);
149 case I8042_CMD_CTL_WCTR
:
150 case I8042_CMD_AUX_SEND
:
151 case I8042_CMD_AUX_LOOP
:
152 state
.write_cmd
= val
;
154 case I8042_CMD_AUX_TEST
:
155 /* 0 means we're a normal PS/2 mouse */
158 case I8042_CMD_AUX_DISABLE
:
159 state
.mode
|= MODE_DISABLE_AUX
;
161 case I8042_CMD_AUX_ENABLE
:
162 state
.mode
&= ~MODE_DISABLE_AUX
;
164 case I8042_CMD_SYSTEM_RESET
:
173 * Called when the OS reads from port 0x60 (PS/2 data)
175 static u32
kbd_read_data(void)
180 if (state
.kcount
!= 0) {
181 /* Keyboard data gets read first */
182 ret
= state
.kq
[state
.kread
++ % QUEUE_SIZE
];
184 kvm__irq_line(state
.kvm
, KBD_IRQ
, 0);
186 } else if (state
.mcount
> 0) {
187 /* Followed by the mouse */
188 ret
= state
.mq
[state
.mread
++ % QUEUE_SIZE
];
190 kvm__irq_line(state
.kvm
, AUX_IRQ
, 0);
192 } else if (state
.kcount
== 0) {
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
:
221 case I8042_CMD_AUX_LOOP
:
223 mouse_queue(RESPONSE_ACK
);
225 case I8042_CMD_AUX_SEND
:
226 /* The OS wants to send a command to the mouse */
227 mouse_queue(RESPONSE_ACK
);
230 /* set scaling = 1:1 */
231 state
.mstatus
&= ~AUX_SCALING_FLAG
;
238 /* Report mouse status/config */
239 mouse_queue(state
.mstatus
);
240 mouse_queue(state
.mres
);
241 mouse_queue(state
.msample
);
245 mouse_queue(0); /* normal mouse */
248 /* set sample rate */
252 /* enable reporting */
253 state
.mstatus
|= AUX_ENABLE_REPORTING
;
256 state
.mstatus
&= ~AUX_ENABLE_REPORTING
;
259 /* set defaults, just fall through to reset */
263 state
.mres
= AUX_DEFAULT_RESOLUTION
;
264 state
.msample
= AUX_DEFAULT_SAMPLE
;
271 /* Just send the ID */
272 kbd_queue(RESPONSE_ACK
);
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
)
300 case I8042_COMMAND_REG
: {
301 u8 value
= kbd_read_status();
302 ioport__write8(data
, value
);
305 case I8042_DATA_REG
: {
306 u32 value
= kbd_read_data();
307 ioport__write32(data
, value
);
317 static bool kbd_out(struct ioport
*ioport
, struct kvm
*kvm
, u16 port
, void *data
, int size
)
320 case I8042_COMMAND_REG
: {
321 u8 value
= ioport__read8(data
);
322 kbd_write_command(kvm
, value
);
325 case I8042_DATA_REG
: {
326 u32 value
= ioport__read32(data
);
327 kbd_write_data(value
);
337 static struct ioport_operations kbd_ops
= {
342 void kbd__init(struct kvm
*kvm
)
346 ioport__register(I8042_DATA_REG
, &kbd_ops
, 2, NULL
);
347 ioport__register(I8042_COMMAND_REG
, &kbd_ops
, 2, NULL
);