source: trunk/packages/xen-3.1/xen-3.1/tools/ioemu/hw/pckbd.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 11.2 KB
Line 
1/*
2 * QEMU PC keyboard emulation
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#include "vl.h"
25
26/* debug PC keyboard */
27//#define DEBUG_KBD
28
29/* debug PC keyboard : only mouse */
30//#define DEBUG_MOUSE
31
32/*      Keyboard Controller Commands */
33#define KBD_CCMD_READ_MODE      0x20    /* Read mode bits */
34#define KBD_CCMD_WRITE_MODE     0x60    /* Write mode bits */
35#define KBD_CCMD_GET_VERSION    0xA1    /* Get controller version */
36#define KBD_CCMD_MOUSE_DISABLE  0xA7    /* Disable mouse interface */
37#define KBD_CCMD_MOUSE_ENABLE   0xA8    /* Enable mouse interface */
38#define KBD_CCMD_TEST_MOUSE     0xA9    /* Mouse interface test */
39#define KBD_CCMD_SELF_TEST      0xAA    /* Controller self test */
40#define KBD_CCMD_KBD_TEST       0xAB    /* Keyboard interface test */
41#define KBD_CCMD_KBD_DISABLE    0xAD    /* Keyboard interface disable */
42#define KBD_CCMD_KBD_ENABLE     0xAE    /* Keyboard interface enable */
43#define KBD_CCMD_READ_INPORT    0xC0    /* read input port */
44#define KBD_CCMD_READ_OUTPORT   0xD0    /* read output port */
45#define KBD_CCMD_WRITE_OUTPORT  0xD1    /* write output port */
46#define KBD_CCMD_WRITE_OBUF     0xD2
47#define KBD_CCMD_WRITE_AUX_OBUF 0xD3    /* Write to output buffer as if
48                                           initiated by the auxiliary device */
49#define KBD_CCMD_WRITE_MOUSE    0xD4    /* Write the following byte to the mouse */
50#define KBD_CCMD_DISABLE_A20    0xDD    /* HP vectra only ? */
51#define KBD_CCMD_ENABLE_A20     0xDF    /* HP vectra only ? */
52#define KBD_CCMD_RESET          0xFE
53
54/* Keyboard Commands */
55#define KBD_CMD_SET_LEDS        0xED    /* Set keyboard leds */
56#define KBD_CMD_ECHO            0xEE
57#define KBD_CMD_GET_ID          0xF2    /* get keyboard ID */
58#define KBD_CMD_SET_RATE        0xF3    /* Set typematic rate */
59#define KBD_CMD_ENABLE          0xF4    /* Enable scanning */
60#define KBD_CMD_RESET_DISABLE   0xF5    /* reset and disable scanning */
61#define KBD_CMD_RESET_ENABLE    0xF6    /* reset and enable scanning */
62#define KBD_CMD_RESET           0xFF    /* Reset */
63
64/* Keyboard Replies */
65#define KBD_REPLY_POR           0xAA    /* Power on reset */
66#define KBD_REPLY_ACK           0xFA    /* Command ACK */
67#define KBD_REPLY_RESEND        0xFE    /* Command NACK, send the cmd again */
68
69/* Status Register Bits */
70#define KBD_STAT_OBF            0x01    /* Keyboard output buffer full */
71#define KBD_STAT_IBF            0x02    /* Keyboard input buffer full */
72#define KBD_STAT_SELFTEST       0x04    /* Self test successful */
73#define KBD_STAT_CMD            0x08    /* Last write was a command write (0=data) */
74#define KBD_STAT_UNLOCKED       0x10    /* Zero if keyboard locked */
75#define KBD_STAT_MOUSE_OBF      0x20    /* Mouse output buffer full */
76#define KBD_STAT_GTO            0x40    /* General receive/xmit timeout */
77#define KBD_STAT_PERR           0x80    /* Parity error */
78
79/* Controller Mode Register Bits */
80#define KBD_MODE_KBD_INT        0x01    /* Keyboard data generate IRQ1 */
81#define KBD_MODE_MOUSE_INT      0x02    /* Mouse data generate IRQ12 */
82#define KBD_MODE_SYS            0x04    /* The system flag (?) */
83#define KBD_MODE_NO_KEYLOCK     0x08    /* The keylock doesn't affect the keyboard if set */
84#define KBD_MODE_DISABLE_KBD    0x10    /* Disable keyboard interface */
85#define KBD_MODE_DISABLE_MOUSE  0x20    /* Disable mouse interface */
86#define KBD_MODE_KCC            0x40    /* Scan code conversion to PC format */
87#define KBD_MODE_RFU            0x80
88
89/* Mouse Commands */
90#define AUX_SET_SCALE11         0xE6    /* Set 1:1 scaling */
91#define AUX_SET_SCALE21         0xE7    /* Set 2:1 scaling */
92#define AUX_SET_RES             0xE8    /* Set resolution */
93#define AUX_GET_SCALE           0xE9    /* Get scaling factor */
94#define AUX_SET_STREAM          0xEA    /* Set stream mode */
95#define AUX_POLL                0xEB    /* Poll */
96#define AUX_RESET_WRAP          0xEC    /* Reset wrap mode */
97#define AUX_SET_WRAP            0xEE    /* Set wrap mode */
98#define AUX_SET_REMOTE          0xF0    /* Set remote mode */
99#define AUX_GET_TYPE            0xF2    /* Get type */
100#define AUX_SET_SAMPLE          0xF3    /* Set sample rate */
101#define AUX_ENABLE_DEV          0xF4    /* Enable aux device */
102#define AUX_DISABLE_DEV         0xF5    /* Disable aux device */
103#define AUX_SET_DEFAULT         0xF6
104#define AUX_RESET               0xFF    /* Reset aux device */
105#define AUX_ACK                 0xFA    /* Command byte ACK. */
106
107#define MOUSE_STATUS_REMOTE     0x40
108#define MOUSE_STATUS_ENABLED    0x20
109#define MOUSE_STATUS_SCALE21    0x10
110
111#define KBD_QUEUE_SIZE 256
112
113#define KBD_PENDING_KBD         1
114#define KBD_PENDING_AUX         2
115
116typedef struct KBDState {
117    uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
118    uint8_t status;
119    uint8_t mode;
120    /* Bitmask of devices with data available.  */
121    uint8_t pending;
122    void *kbd;
123    void *mouse;
124} KBDState;
125
126KBDState kbd_state;
127
128/* update irq and KBD_STAT_[MOUSE_]OBF */
129/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
130   incorrect, but it avoids having to simulate exact delays */
131static void kbd_update_irq(KBDState *s)
132{
133    int irq12_level, irq1_level;
134
135    irq1_level = 0;   
136    irq12_level = 0;   
137    s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
138    if (s->pending) {
139        s->status |= KBD_STAT_OBF;
140        /* kdb data takes priority over aux data.  */
141        if (s->pending == KBD_PENDING_AUX) {
142            s->status |= KBD_STAT_MOUSE_OBF;
143            if (s->mode & KBD_MODE_MOUSE_INT)
144                irq12_level = 1;
145        } else {
146            if ((s->mode & KBD_MODE_KBD_INT) && 
147                !(s->mode & KBD_MODE_DISABLE_KBD))
148                irq1_level = 1;
149        }
150    }
151    pic_set_irq(1, irq1_level);
152    pic_set_irq(12, irq12_level);
153}
154
155static void kbd_update_kbd_irq(void *opaque, int level)
156{
157    KBDState *s = (KBDState *)opaque;
158
159    if (level)
160        s->pending |= KBD_PENDING_KBD;
161    else
162        s->pending &= ~KBD_PENDING_KBD;
163    kbd_update_irq(s);
164}
165
166static void kbd_update_aux_irq(void *opaque, int level)
167{
168    KBDState *s = (KBDState *)opaque;
169
170    if (level)
171        s->pending |= KBD_PENDING_AUX;
172    else
173        s->pending &= ~KBD_PENDING_AUX;
174    kbd_update_irq(s);
175}
176
177static uint32_t kbd_read_status(void *opaque, uint32_t addr)
178{
179    KBDState *s = opaque;
180    int val;
181    val = s->status;
182#if defined(DEBUG_KBD)
183    printf("kbd: read status=0x%02x\n", val);
184#endif
185    return val;
186}
187
188static void kbd_queue(KBDState *s, int b, int aux)
189{
190    if (aux)
191        ps2_queue(s->mouse, b);
192    else
193        ps2_queue(s->kbd, b);
194}
195
196static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
197{
198    KBDState *s = opaque;
199
200#ifdef DEBUG_KBD
201    printf("kbd: write cmd=0x%02x\n", val);
202#endif
203    switch(val) {
204    case KBD_CCMD_READ_MODE:
205        kbd_queue(s, s->mode, 0);
206        break;
207    case KBD_CCMD_WRITE_MODE:
208    case KBD_CCMD_WRITE_OBUF:
209    case KBD_CCMD_WRITE_AUX_OBUF:
210    case KBD_CCMD_WRITE_MOUSE:
211    case KBD_CCMD_WRITE_OUTPORT:
212        s->write_cmd = val;
213        break;
214    case KBD_CCMD_MOUSE_DISABLE:
215        s->mode |= KBD_MODE_DISABLE_MOUSE;
216        break;
217    case KBD_CCMD_MOUSE_ENABLE:
218        s->mode &= ~KBD_MODE_DISABLE_MOUSE;
219        break;
220    case KBD_CCMD_TEST_MOUSE:
221        kbd_queue(s, 0x00, 0);
222        break;
223    case KBD_CCMD_SELF_TEST:
224        s->status |= KBD_STAT_SELFTEST;
225        kbd_queue(s, 0x55, 0);
226        break;
227    case KBD_CCMD_KBD_TEST:
228        kbd_queue(s, 0x00, 0);
229        break;
230    case KBD_CCMD_KBD_DISABLE:
231        s->mode |= KBD_MODE_DISABLE_KBD;
232        kbd_update_irq(s);
233        break;
234    case KBD_CCMD_KBD_ENABLE:
235        s->mode &= ~KBD_MODE_DISABLE_KBD;
236        kbd_update_irq(s);
237        break;
238    case KBD_CCMD_READ_INPORT:
239        kbd_queue(s, 0x00, 0);
240        break;
241    case KBD_CCMD_READ_OUTPORT:
242        /* XXX: check that */
243#ifdef TARGET_I386
244        val = 0x01 | (ioport_get_a20() << 1);
245#else
246        val = 0x01;
247#endif
248        if (s->status & KBD_STAT_OBF)
249            val |= 0x10;
250        if (s->status & KBD_STAT_MOUSE_OBF)
251            val |= 0x20;
252        kbd_queue(s, val, 0);
253        break;
254#ifdef TARGET_I386
255    case KBD_CCMD_ENABLE_A20:
256        ioport_set_a20(1);
257        break;
258    case KBD_CCMD_DISABLE_A20:
259        ioport_set_a20(0);
260        break;
261#endif
262    case KBD_CCMD_RESET:
263        qemu_system_reset_request();
264        break;
265    case 0xff:
266        /* ignore that - I don't know what is its use */
267        break;
268    default:
269        fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
270        break;
271    }
272}
273
274static uint32_t kbd_read_data(void *opaque, uint32_t addr)
275{
276    KBDState *s = opaque;
277
278    if (s->pending == KBD_PENDING_AUX)
279        return ps2_read_data(s->mouse);
280
281    return ps2_read_data(s->kbd);
282}
283
284void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
285{
286    KBDState *s = opaque;
287
288#ifdef DEBUG_KBD
289    printf("kbd: write data=0x%02x\n", val);
290#endif
291
292    switch(s->write_cmd) {
293    case 0:
294        ps2_write_keyboard(s->kbd, val);
295        break;
296    case KBD_CCMD_WRITE_MODE:
297        s->mode = val;
298        ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
299        /* ??? */
300        kbd_update_irq(s);
301        break;
302    case KBD_CCMD_WRITE_OBUF:
303        kbd_queue(s, val, 0);
304        break;
305    case KBD_CCMD_WRITE_AUX_OBUF:
306        kbd_queue(s, val, 1);
307        break;
308    case KBD_CCMD_WRITE_OUTPORT:
309#ifdef TARGET_I386
310        ioport_set_a20((val >> 1) & 1);
311#endif
312        if (!(val & 1)) {
313            qemu_system_reset_request();
314        }
315        break;
316    case KBD_CCMD_WRITE_MOUSE:
317        ps2_write_mouse(s->mouse, val);
318        break;
319    default:
320        break;
321    }
322    s->write_cmd = 0;
323}
324
325static void kbd_reset(void *opaque)
326{
327    KBDState *s = opaque;
328
329    s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
330    s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
331}
332
333static void kbd_save(QEMUFile* f, void* opaque)
334{
335    KBDState *s = (KBDState*)opaque;
336   
337    qemu_put_8s(f, &s->write_cmd);
338    qemu_put_8s(f, &s->status);
339    qemu_put_8s(f, &s->mode);
340    qemu_put_8s(f, &s->pending);
341}
342
343static int kbd_load(QEMUFile* f, void* opaque, int version_id)
344{
345    KBDState *s = (KBDState*)opaque;
346   
347    if (version_id != 3)
348        return -EINVAL;
349    qemu_get_8s(f, &s->write_cmd);
350    qemu_get_8s(f, &s->status);
351    qemu_get_8s(f, &s->mode);
352    qemu_get_8s(f, &s->pending);
353    return 0;
354}
355
356void kbd_init(void)
357{
358    KBDState *s = &kbd_state;
359   
360    kbd_reset(s);
361    register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
362    register_ioport_read(0x60, 1, 1, kbd_read_data, s);
363    register_ioport_write(0x60, 1, 1, kbd_write_data, s);
364    register_ioport_read(0x64, 1, 1, kbd_read_status, s);
365    register_ioport_write(0x64, 1, 1, kbd_write_command, s);
366
367    s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
368    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
369    qemu_register_reset(kbd_reset, s);
370}
Note: See TracBrowser for help on using the repository browser.