Home | History | Annotate | Download | only in hw
      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 "hw.h"
     25 #include "isa.h"
     26 #include "pc.h"
     27 #include "ps2.h"
     28 #include "sysemu.h"
     29 
     30 /* debug PC keyboard */
     31 //#define DEBUG_KBD
     32 
     33 /*	Keyboard Controller Commands */
     34 #define KBD_CCMD_READ_MODE	0x20	/* Read mode bits */
     35 #define KBD_CCMD_WRITE_MODE	0x60	/* Write mode bits */
     36 #define KBD_CCMD_GET_VERSION	0xA1	/* Get controller version */
     37 #define KBD_CCMD_MOUSE_DISABLE	0xA7	/* Disable mouse interface */
     38 #define KBD_CCMD_MOUSE_ENABLE	0xA8	/* Enable mouse interface */
     39 #define KBD_CCMD_TEST_MOUSE	0xA9	/* Mouse interface test */
     40 #define KBD_CCMD_SELF_TEST	0xAA	/* Controller self test */
     41 #define KBD_CCMD_KBD_TEST	0xAB	/* Keyboard interface test */
     42 #define KBD_CCMD_KBD_DISABLE	0xAD	/* Keyboard interface disable */
     43 #define KBD_CCMD_KBD_ENABLE	0xAE	/* Keyboard interface enable */
     44 #define KBD_CCMD_READ_INPORT    0xC0    /* read input port */
     45 #define KBD_CCMD_READ_OUTPORT	0xD0    /* read output port */
     46 #define KBD_CCMD_WRITE_OUTPORT	0xD1    /* write output port */
     47 #define KBD_CCMD_WRITE_OBUF	0xD2
     48 #define KBD_CCMD_WRITE_AUX_OBUF	0xD3    /* Write to output buffer as if
     49 					   initiated by the auxiliary device */
     50 #define KBD_CCMD_WRITE_MOUSE	0xD4	/* Write the following byte to the mouse */
     51 #define KBD_CCMD_DISABLE_A20    0xDD    /* HP vectra only ? */
     52 #define KBD_CCMD_ENABLE_A20     0xDF    /* HP vectra only ? */
     53 #define KBD_CCMD_RESET	        0xFE
     54 
     55 /* Keyboard Commands */
     56 #define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
     57 #define KBD_CMD_ECHO     	0xEE
     58 #define KBD_CMD_GET_ID 	        0xF2	/* get keyboard ID */
     59 #define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
     60 #define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
     61 #define KBD_CMD_RESET_DISABLE	0xF5	/* reset and disable scanning */
     62 #define KBD_CMD_RESET_ENABLE   	0xF6    /* reset and enable scanning */
     63 #define KBD_CMD_RESET		0xFF	/* Reset */
     64 
     65 /* Keyboard Replies */
     66 #define KBD_REPLY_POR		0xAA	/* Power on reset */
     67 #define KBD_REPLY_ACK		0xFA	/* Command ACK */
     68 #define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
     69 
     70 /* Status Register Bits */
     71 #define KBD_STAT_OBF 		0x01	/* Keyboard output buffer full */
     72 #define KBD_STAT_IBF 		0x02	/* Keyboard input buffer full */
     73 #define KBD_STAT_SELFTEST	0x04	/* Self test successful */
     74 #define KBD_STAT_CMD		0x08	/* Last write was a command write (0=data) */
     75 #define KBD_STAT_UNLOCKED	0x10	/* Zero if keyboard locked */
     76 #define KBD_STAT_MOUSE_OBF	0x20	/* Mouse output buffer full */
     77 #define KBD_STAT_GTO 		0x40	/* General receive/xmit timeout */
     78 #define KBD_STAT_PERR 		0x80	/* Parity error */
     79 
     80 /* Controller Mode Register Bits */
     81 #define KBD_MODE_KBD_INT	0x01	/* Keyboard data generate IRQ1 */
     82 #define KBD_MODE_MOUSE_INT	0x02	/* Mouse data generate IRQ12 */
     83 #define KBD_MODE_SYS 		0x04	/* The system flag (?) */
     84 #define KBD_MODE_NO_KEYLOCK	0x08	/* The keylock doesn't affect the keyboard if set */
     85 #define KBD_MODE_DISABLE_KBD	0x10	/* Disable keyboard interface */
     86 #define KBD_MODE_DISABLE_MOUSE	0x20	/* Disable mouse interface */
     87 #define KBD_MODE_KCC 		0x40	/* Scan code conversion to PC format */
     88 #define KBD_MODE_RFU		0x80
     89 
     90 /* Mouse Commands */
     91 #define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
     92 #define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
     93 #define AUX_SET_RES		0xE8	/* Set resolution */
     94 #define AUX_GET_SCALE		0xE9	/* Get scaling factor */
     95 #define AUX_SET_STREAM		0xEA	/* Set stream mode */
     96 #define AUX_POLL		0xEB	/* Poll */
     97 #define AUX_RESET_WRAP		0xEC	/* Reset wrap mode */
     98 #define AUX_SET_WRAP		0xEE	/* Set wrap mode */
     99 #define AUX_SET_REMOTE		0xF0	/* Set remote mode */
    100 #define AUX_GET_TYPE		0xF2	/* Get type */
    101 #define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
    102 #define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
    103 #define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
    104 #define AUX_SET_DEFAULT		0xF6
    105 #define AUX_RESET		0xFF	/* Reset aux device */
    106 #define AUX_ACK			0xFA	/* Command byte ACK. */
    107 
    108 #define MOUSE_STATUS_REMOTE     0x40
    109 #define MOUSE_STATUS_ENABLED    0x20
    110 #define MOUSE_STATUS_SCALE21    0x10
    111 
    112 #define KBD_PENDING_KBD         1
    113 #define KBD_PENDING_AUX         2
    114 
    115 typedef struct KBDState {
    116     uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
    117     uint8_t status;
    118     uint8_t mode;
    119     /* Bitmask of devices with data available.  */
    120     uint8_t pending;
    121     void *kbd;
    122     void *mouse;
    123 
    124     qemu_irq irq_kbd;
    125     qemu_irq irq_mouse;
    126     target_phys_addr_t mask;
    127 } KBDState;
    128 
    129 static KBDState kbd_state;
    130 
    131 /* update irq and KBD_STAT_[MOUSE_]OBF */
    132 /* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
    133    incorrect, but it avoids having to simulate exact delays */
    134 static void kbd_update_irq(KBDState *s)
    135 {
    136     int irq_kbd_level, irq_mouse_level;
    137 
    138     irq_kbd_level = 0;
    139     irq_mouse_level = 0;
    140     s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
    141     if (s->pending) {
    142         s->status |= KBD_STAT_OBF;
    143         /* kbd data takes priority over aux data.  */
    144         if (s->pending == KBD_PENDING_AUX) {
    145             s->status |= KBD_STAT_MOUSE_OBF;
    146             if (s->mode & KBD_MODE_MOUSE_INT)
    147                 irq_mouse_level = 1;
    148         } else {
    149             if ((s->mode & KBD_MODE_KBD_INT) &&
    150                 !(s->mode & KBD_MODE_DISABLE_KBD))
    151                 irq_kbd_level = 1;
    152         }
    153     }
    154     qemu_set_irq(s->irq_kbd, irq_kbd_level);
    155     qemu_set_irq(s->irq_mouse, irq_mouse_level);
    156 }
    157 
    158 static void kbd_update_kbd_irq(void *opaque, int level)
    159 {
    160     KBDState *s = (KBDState *)opaque;
    161 
    162     if (level)
    163         s->pending |= KBD_PENDING_KBD;
    164     else
    165         s->pending &= ~KBD_PENDING_KBD;
    166     kbd_update_irq(s);
    167 }
    168 
    169 static void kbd_update_aux_irq(void *opaque, int level)
    170 {
    171     KBDState *s = (KBDState *)opaque;
    172 
    173     if (level)
    174         s->pending |= KBD_PENDING_AUX;
    175     else
    176         s->pending &= ~KBD_PENDING_AUX;
    177     kbd_update_irq(s);
    178 }
    179 
    180 static uint32_t kbd_read_status(void *opaque, uint32_t addr)
    181 {
    182     KBDState *s = opaque;
    183     int val;
    184     val = s->status;
    185 #if defined(DEBUG_KBD)
    186     printf("kbd: read status=0x%02x\n", val);
    187 #endif
    188     return val;
    189 }
    190 
    191 static void kbd_queue(KBDState *s, int b, int aux)
    192 {
    193     if (aux)
    194         ps2_queue(s->mouse, b);
    195     else
    196         ps2_queue(s->kbd, b);
    197 }
    198 
    199 static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
    200 {
    201     KBDState *s = opaque;
    202 
    203 #ifdef DEBUG_KBD
    204     printf("kbd: write cmd=0x%02x\n", val);
    205 #endif
    206     switch(val) {
    207     case KBD_CCMD_READ_MODE:
    208         kbd_queue(s, s->mode, 0);
    209         break;
    210     case KBD_CCMD_WRITE_MODE:
    211     case KBD_CCMD_WRITE_OBUF:
    212     case KBD_CCMD_WRITE_AUX_OBUF:
    213     case KBD_CCMD_WRITE_MOUSE:
    214     case KBD_CCMD_WRITE_OUTPORT:
    215         s->write_cmd = val;
    216         break;
    217     case KBD_CCMD_MOUSE_DISABLE:
    218         s->mode |= KBD_MODE_DISABLE_MOUSE;
    219         break;
    220     case KBD_CCMD_MOUSE_ENABLE:
    221         s->mode &= ~KBD_MODE_DISABLE_MOUSE;
    222         break;
    223     case KBD_CCMD_TEST_MOUSE:
    224         kbd_queue(s, 0x00, 0);
    225         break;
    226     case KBD_CCMD_SELF_TEST:
    227         s->status |= KBD_STAT_SELFTEST;
    228         kbd_queue(s, 0x55, 0);
    229         break;
    230     case KBD_CCMD_KBD_TEST:
    231         kbd_queue(s, 0x00, 0);
    232         break;
    233     case KBD_CCMD_KBD_DISABLE:
    234         s->mode |= KBD_MODE_DISABLE_KBD;
    235         kbd_update_irq(s);
    236         break;
    237     case KBD_CCMD_KBD_ENABLE:
    238         s->mode &= ~KBD_MODE_DISABLE_KBD;
    239         kbd_update_irq(s);
    240         break;
    241     case KBD_CCMD_READ_INPORT:
    242         kbd_queue(s, 0x00, 0);
    243         break;
    244     case KBD_CCMD_READ_OUTPORT:
    245         /* XXX: check that */
    246 #ifdef TARGET_I386
    247         val = 0x01 | (ioport_get_a20() << 1);
    248 #else
    249         val = 0x01;
    250 #endif
    251         if (s->status & KBD_STAT_OBF)
    252             val |= 0x10;
    253         if (s->status & KBD_STAT_MOUSE_OBF)
    254             val |= 0x20;
    255         kbd_queue(s, val, 0);
    256         break;
    257 #ifdef TARGET_I386
    258     case KBD_CCMD_ENABLE_A20:
    259         ioport_set_a20(1);
    260         break;
    261     case KBD_CCMD_DISABLE_A20:
    262         ioport_set_a20(0);
    263         break;
    264 #endif
    265     case KBD_CCMD_RESET:
    266         qemu_system_reset_request();
    267         break;
    268     case 0xff:
    269         /* ignore that - I don't know what is its use */
    270         break;
    271     default:
    272         fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
    273         break;
    274     }
    275 }
    276 
    277 static uint32_t kbd_read_data(void *opaque, uint32_t addr)
    278 {
    279     KBDState *s = opaque;
    280     uint32_t val;
    281 
    282     if (s->pending == KBD_PENDING_AUX)
    283         val = ps2_read_data(s->mouse);
    284     else
    285         val = ps2_read_data(s->kbd);
    286 
    287 #if defined(DEBUG_KBD)
    288     printf("kbd: read data=0x%02x\n", val);
    289 #endif
    290     return val;
    291 }
    292 
    293 static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
    294 {
    295     KBDState *s = opaque;
    296 
    297 #ifdef DEBUG_KBD
    298     printf("kbd: write data=0x%02x\n", val);
    299 #endif
    300 
    301     switch(s->write_cmd) {
    302     case 0:
    303         ps2_write_keyboard(s->kbd, val);
    304         break;
    305     case KBD_CCMD_WRITE_MODE:
    306         s->mode = val;
    307         ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
    308         /* ??? */
    309         kbd_update_irq(s);
    310         break;
    311     case KBD_CCMD_WRITE_OBUF:
    312         kbd_queue(s, val, 0);
    313         break;
    314     case KBD_CCMD_WRITE_AUX_OBUF:
    315         kbd_queue(s, val, 1);
    316         break;
    317     case KBD_CCMD_WRITE_OUTPORT:
    318 #ifdef TARGET_I386
    319         ioport_set_a20((val >> 1) & 1);
    320 #endif
    321         if (!(val & 1)) {
    322             qemu_system_reset_request();
    323         }
    324         break;
    325     case KBD_CCMD_WRITE_MOUSE:
    326         ps2_write_mouse(s->mouse, val);
    327         break;
    328     default:
    329         break;
    330     }
    331     s->write_cmd = 0;
    332 }
    333 
    334 static void kbd_reset(void *opaque)
    335 {
    336     KBDState *s = opaque;
    337 
    338     s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
    339     s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
    340 }
    341 
    342 static void kbd_save(QEMUFile* f, void* opaque)
    343 {
    344     KBDState *s = (KBDState*)opaque;
    345 
    346     qemu_put_8s(f, &s->write_cmd);
    347     qemu_put_8s(f, &s->status);
    348     qemu_put_8s(f, &s->mode);
    349     qemu_put_8s(f, &s->pending);
    350 }
    351 
    352 static int kbd_load(QEMUFile* f, void* opaque, int version_id)
    353 {
    354     KBDState *s = (KBDState*)opaque;
    355 
    356     if (version_id != 3)
    357         return -EINVAL;
    358     qemu_get_8s(f, &s->write_cmd);
    359     qemu_get_8s(f, &s->status);
    360     qemu_get_8s(f, &s->mode);
    361     qemu_get_8s(f, &s->pending);
    362     return 0;
    363 }
    364 
    365 void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base)
    366 {
    367     KBDState *s = &kbd_state;
    368 
    369     s->irq_kbd = kbd_irq;
    370     s->irq_mouse = mouse_irq;
    371 
    372     kbd_reset(s);
    373     register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
    374     register_ioport_read(io_base, 1, 1, kbd_read_data, s);
    375     register_ioport_write(io_base, 1, 1, kbd_write_data, s);
    376     register_ioport_read(io_base + 4, 1, 1, kbd_read_status, s);
    377     register_ioport_write(io_base + 4, 1, 1, kbd_write_command, s);
    378 
    379     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
    380     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
    381 #ifndef CONFIG_ANDROID
    382 #ifdef TARGET_I386
    383     vmmouse_init(s->mouse);
    384 #endif
    385 #endif
    386     qemu_register_reset(kbd_reset, 0, s);
    387 }
    388 
    389 /* Memory mapped interface */
    390 static uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr)
    391 {
    392     KBDState *s = opaque;
    393 
    394     if (addr & s->mask)
    395         return kbd_read_status(s, 0) & 0xff;
    396     else
    397         return kbd_read_data(s, 0) & 0xff;
    398 }
    399 
    400 static void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
    401 {
    402     KBDState *s = opaque;
    403 
    404     if (addr & s->mask)
    405         kbd_write_command(s, 0, value & 0xff);
    406     else
    407         kbd_write_data(s, 0, value & 0xff);
    408 }
    409 
    410 static CPUReadMemoryFunc *kbd_mm_read[] = {
    411     &kbd_mm_readb,
    412     &kbd_mm_readb,
    413     &kbd_mm_readb,
    414 };
    415 
    416 static CPUWriteMemoryFunc *kbd_mm_write[] = {
    417     &kbd_mm_writeb,
    418     &kbd_mm_writeb,
    419     &kbd_mm_writeb,
    420 };
    421 
    422 void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
    423                    target_phys_addr_t base, ram_addr_t size,
    424                    target_phys_addr_t mask)
    425 {
    426     KBDState *s = &kbd_state;
    427     int s_io_memory;
    428 
    429     s->irq_kbd = kbd_irq;
    430     s->irq_mouse = mouse_irq;
    431     s->mask = mask;
    432 
    433     kbd_reset(s);
    434     register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
    435     s_io_memory = cpu_register_io_memory(kbd_mm_read, kbd_mm_write, s);
    436     cpu_register_physical_memory(base, size, s_io_memory);
    437 
    438     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
    439     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
    440 #ifndef CONFIG_ANDROID
    441 #ifdef TARGET_I386
    442     vmmouse_init(s->mouse);
    443 #endif
    444 #endif
    445     qemu_register_reset(kbd_reset, 0, s);
    446 }
    447