symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/pckbd.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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_QUEUE_SIZE 256
       
   113 
       
   114 #define KBD_PENDING_KBD         1
       
   115 #define KBD_PENDING_AUX         2
       
   116 
       
   117 typedef struct KBDState {
       
   118     uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
       
   119     uint8_t status;
       
   120     uint8_t mode;
       
   121     /* Bitmask of devices with data available.  */
       
   122     uint8_t pending;
       
   123     void *kbd;
       
   124     void *mouse;
       
   125 
       
   126     qemu_irq irq_kbd;
       
   127     qemu_irq irq_mouse;
       
   128     target_phys_addr_t mask;
       
   129 } KBDState;
       
   130 
       
   131 static KBDState kbd_state;
       
   132 
       
   133 /* update irq and KBD_STAT_[MOUSE_]OBF */
       
   134 /* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
       
   135    incorrect, but it avoids having to simulate exact delays */
       
   136 static void kbd_update_irq(KBDState *s)
       
   137 {
       
   138     int irq_kbd_level, irq_mouse_level;
       
   139 
       
   140     irq_kbd_level = 0;
       
   141     irq_mouse_level = 0;
       
   142     s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
       
   143     if (s->pending) {
       
   144         s->status |= KBD_STAT_OBF;
       
   145         /* kbd data takes priority over aux data.  */
       
   146         if (s->pending == KBD_PENDING_AUX) {
       
   147             s->status |= KBD_STAT_MOUSE_OBF;
       
   148             if (s->mode & KBD_MODE_MOUSE_INT)
       
   149                 irq_mouse_level = 1;
       
   150         } else {
       
   151             if ((s->mode & KBD_MODE_KBD_INT) &&
       
   152                 !(s->mode & KBD_MODE_DISABLE_KBD))
       
   153                 irq_kbd_level = 1;
       
   154         }
       
   155     }
       
   156     qemu_set_irq(s->irq_kbd, irq_kbd_level);
       
   157     qemu_set_irq(s->irq_mouse, irq_mouse_level);
       
   158 }
       
   159 
       
   160 static void kbd_update_kbd_irq(void *opaque, int level)
       
   161 {
       
   162     KBDState *s = (KBDState *)opaque;
       
   163 
       
   164     if (level)
       
   165         s->pending |= KBD_PENDING_KBD;
       
   166     else
       
   167         s->pending &= ~KBD_PENDING_KBD;
       
   168     kbd_update_irq(s);
       
   169 }
       
   170 
       
   171 static void kbd_update_aux_irq(void *opaque, int level)
       
   172 {
       
   173     KBDState *s = (KBDState *)opaque;
       
   174 
       
   175     if (level)
       
   176         s->pending |= KBD_PENDING_AUX;
       
   177     else
       
   178         s->pending &= ~KBD_PENDING_AUX;
       
   179     kbd_update_irq(s);
       
   180 }
       
   181 
       
   182 static uint32_t kbd_read_status(void *opaque, uint32_t addr)
       
   183 {
       
   184     KBDState *s = opaque;
       
   185     int val;
       
   186     val = s->status;
       
   187 #if defined(DEBUG_KBD)
       
   188     printf("kbd: read status=0x%02x\n", val);
       
   189 #endif
       
   190     return val;
       
   191 }
       
   192 
       
   193 static void kbd_queue(KBDState *s, int b, int aux)
       
   194 {
       
   195     if (aux)
       
   196         ps2_queue(s->mouse, b);
       
   197     else
       
   198         ps2_queue(s->kbd, b);
       
   199 }
       
   200 
       
   201 static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
       
   202 {
       
   203     KBDState *s = opaque;
       
   204 
       
   205 #ifdef DEBUG_KBD
       
   206     printf("kbd: write cmd=0x%02x\n", val);
       
   207 #endif
       
   208     switch(val) {
       
   209     case KBD_CCMD_READ_MODE:
       
   210         kbd_queue(s, s->mode, 0);
       
   211         break;
       
   212     case KBD_CCMD_WRITE_MODE:
       
   213     case KBD_CCMD_WRITE_OBUF:
       
   214     case KBD_CCMD_WRITE_AUX_OBUF:
       
   215     case KBD_CCMD_WRITE_MOUSE:
       
   216     case KBD_CCMD_WRITE_OUTPORT:
       
   217         s->write_cmd = val;
       
   218         break;
       
   219     case KBD_CCMD_MOUSE_DISABLE:
       
   220         s->mode |= KBD_MODE_DISABLE_MOUSE;
       
   221         break;
       
   222     case KBD_CCMD_MOUSE_ENABLE:
       
   223         s->mode &= ~KBD_MODE_DISABLE_MOUSE;
       
   224         break;
       
   225     case KBD_CCMD_TEST_MOUSE:
       
   226         kbd_queue(s, 0x00, 0);
       
   227         break;
       
   228     case KBD_CCMD_SELF_TEST:
       
   229         s->status |= KBD_STAT_SELFTEST;
       
   230         kbd_queue(s, 0x55, 0);
       
   231         break;
       
   232     case KBD_CCMD_KBD_TEST:
       
   233         kbd_queue(s, 0x00, 0);
       
   234         break;
       
   235     case KBD_CCMD_KBD_DISABLE:
       
   236         s->mode |= KBD_MODE_DISABLE_KBD;
       
   237         kbd_update_irq(s);
       
   238         break;
       
   239     case KBD_CCMD_KBD_ENABLE:
       
   240         s->mode &= ~KBD_MODE_DISABLE_KBD;
       
   241         kbd_update_irq(s);
       
   242         break;
       
   243     case KBD_CCMD_READ_INPORT:
       
   244         kbd_queue(s, 0x00, 0);
       
   245         break;
       
   246     case KBD_CCMD_READ_OUTPORT:
       
   247         /* XXX: check that */
       
   248 #ifdef TARGET_I386
       
   249         val = 0x01 | (ioport_get_a20() << 1);
       
   250 #else
       
   251         val = 0x01;
       
   252 #endif
       
   253         if (s->status & KBD_STAT_OBF)
       
   254             val |= 0x10;
       
   255         if (s->status & KBD_STAT_MOUSE_OBF)
       
   256             val |= 0x20;
       
   257         kbd_queue(s, val, 0);
       
   258         break;
       
   259 #ifdef TARGET_I386
       
   260     case KBD_CCMD_ENABLE_A20:
       
   261         ioport_set_a20(1);
       
   262         break;
       
   263     case KBD_CCMD_DISABLE_A20:
       
   264         ioport_set_a20(0);
       
   265         break;
       
   266 #endif
       
   267     case KBD_CCMD_RESET:
       
   268         qemu_system_reset_request();
       
   269         break;
       
   270     case 0xff:
       
   271         /* ignore that - I don't know what is its use */
       
   272         break;
       
   273     default:
       
   274         fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
       
   275         break;
       
   276     }
       
   277 }
       
   278 
       
   279 static uint32_t kbd_read_data(void *opaque, uint32_t addr)
       
   280 {
       
   281     KBDState *s = opaque;
       
   282     uint32_t val;
       
   283 
       
   284     if (s->pending == KBD_PENDING_AUX)
       
   285         val = ps2_read_data(s->mouse);
       
   286     else
       
   287         val = ps2_read_data(s->kbd);
       
   288 
       
   289 #if defined(DEBUG_KBD)
       
   290     printf("kbd: read data=0x%02x\n", val);
       
   291 #endif
       
   292     return val;
       
   293 }
       
   294 
       
   295 static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
       
   296 {
       
   297     KBDState *s = opaque;
       
   298 
       
   299 #ifdef DEBUG_KBD
       
   300     printf("kbd: write data=0x%02x\n", val);
       
   301 #endif
       
   302 
       
   303     switch(s->write_cmd) {
       
   304     case 0:
       
   305         ps2_write_keyboard(s->kbd, val);
       
   306         break;
       
   307     case KBD_CCMD_WRITE_MODE:
       
   308         s->mode = val;
       
   309         ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
       
   310         /* ??? */
       
   311         kbd_update_irq(s);
       
   312         break;
       
   313     case KBD_CCMD_WRITE_OBUF:
       
   314         kbd_queue(s, val, 0);
       
   315         break;
       
   316     case KBD_CCMD_WRITE_AUX_OBUF:
       
   317         kbd_queue(s, val, 1);
       
   318         break;
       
   319     case KBD_CCMD_WRITE_OUTPORT:
       
   320 #ifdef TARGET_I386
       
   321         ioport_set_a20((val >> 1) & 1);
       
   322 #endif
       
   323         if (!(val & 1)) {
       
   324             qemu_system_reset_request();
       
   325         }
       
   326         break;
       
   327     case KBD_CCMD_WRITE_MOUSE:
       
   328         ps2_write_mouse(s->mouse, val);
       
   329         break;
       
   330     default:
       
   331         break;
       
   332     }
       
   333     s->write_cmd = 0;
       
   334 }
       
   335 
       
   336 static void kbd_reset(void *opaque)
       
   337 {
       
   338     KBDState *s = opaque;
       
   339 
       
   340     s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
       
   341     s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
       
   342 }
       
   343 
       
   344 static void kbd_save(QEMUFile* f, void* opaque)
       
   345 {
       
   346     KBDState *s = (KBDState*)opaque;
       
   347 
       
   348     qemu_put_8s(f, &s->write_cmd);
       
   349     qemu_put_8s(f, &s->status);
       
   350     qemu_put_8s(f, &s->mode);
       
   351     qemu_put_8s(f, &s->pending);
       
   352 }
       
   353 
       
   354 static int kbd_load(QEMUFile* f, void* opaque, int version_id)
       
   355 {
       
   356     KBDState *s = (KBDState*)opaque;
       
   357 
       
   358     if (version_id != 3)
       
   359         return -EINVAL;
       
   360     qemu_get_8s(f, &s->write_cmd);
       
   361     qemu_get_8s(f, &s->status);
       
   362     qemu_get_8s(f, &s->mode);
       
   363     qemu_get_8s(f, &s->pending);
       
   364     return 0;
       
   365 }
       
   366 
       
   367 void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base)
       
   368 {
       
   369     KBDState *s = &kbd_state;
       
   370 
       
   371     s->irq_kbd = kbd_irq;
       
   372     s->irq_mouse = mouse_irq;
       
   373 
       
   374     kbd_reset(s);
       
   375     register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
       
   376     register_ioport_read(io_base, 1, 1, kbd_read_data, s);
       
   377     register_ioport_write(io_base, 1, 1, kbd_write_data, s);
       
   378     register_ioport_read(io_base + 4, 1, 1, kbd_read_status, s);
       
   379     register_ioport_write(io_base + 4, 1, 1, kbd_write_command, s);
       
   380 
       
   381     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
       
   382     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
       
   383 #ifdef TARGET_I386
       
   384     vmmouse_init(s->mouse);
       
   385 #endif
       
   386     qemu_register_reset(kbd_reset, 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(0, 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 #ifdef TARGET_I386
       
   441     vmmouse_init(s->mouse);
       
   442 #endif
       
   443     qemu_register_reset(kbd_reset, s);
       
   444 }