qemu-sparc queue

-----BEGIN PGP SIGNATURE-----
 
 iQFSBAABCgA8FiEEzGIauY6CIA2RXMnEW8LFb64PMh8FAmK4moUeHG1hcmsuY2F2
 ZS1heWxhbmRAaWxhbmRlLmNvLnVrAAoJEFvCxW+uDzIfaXsH/0+FT9TbHXCplB8h
 gvOETq9r5UscYMqUIbRPv7eFIhhZUfq4mCzpthZHYfMA6Tag0jMqaP5ymATm6Jm/
 GgS/7Fx+14uO54Cu4NwIFylRuDt39cESrBHrVjmXmYzOXx7a040+TPxtHHwSRXiQ
 Vvx5Oo0P8qQfADQe/Y9iray3JBdFMg4yejO37yrdfP58Nh2dzr9dNKw6apY8dwcv
 eTVTqVbYY5AAKOjStpxb0x8dFq/WXttclbeaiSZsK1wnuqhJdUtiMY3UaAfYdMEW
 kputMhTZqV/oopUY0mHmBEUK843s8bSQs2aoCSXLamGTWcrm27XNOsX0f4AYwf/y
 jWBcSvg=
 =0MrK
 -----END PGP SIGNATURE-----

Merge tag 'qemu-sparc-20220626' of https://github.com/mcayland/qemu into staging

qemu-sparc queue

# -----BEGIN PGP SIGNATURE-----
#
# iQFSBAABCgA8FiEEzGIauY6CIA2RXMnEW8LFb64PMh8FAmK4moUeHG1hcmsuY2F2
# ZS1heWxhbmRAaWxhbmRlLmNvLnVrAAoJEFvCxW+uDzIfaXsH/0+FT9TbHXCplB8h
# gvOETq9r5UscYMqUIbRPv7eFIhhZUfq4mCzpthZHYfMA6Tag0jMqaP5ymATm6Jm/
# GgS/7Fx+14uO54Cu4NwIFylRuDt39cESrBHrVjmXmYzOXx7a040+TPxtHHwSRXiQ
# Vvx5Oo0P8qQfADQe/Y9iray3JBdFMg4yejO37yrdfP58Nh2dzr9dNKw6apY8dwcv
# eTVTqVbYY5AAKOjStpxb0x8dFq/WXttclbeaiSZsK1wnuqhJdUtiMY3UaAfYdMEW
# kputMhTZqV/oopUY0mHmBEUK843s8bSQs2aoCSXLamGTWcrm27XNOsX0f4AYwf/y
# jWBcSvg=
# =0MrK
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun 26 Jun 2022 11:12:29 PM +0530
# gpg:                using RSA key CC621AB98E82200D915CC9C45BC2C56FAE0F321F
# gpg:                issuer "mark.cave-ayland@ilande.co.uk"
# gpg: Good signature from "Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: CC62 1AB9 8E82 200D 915C  C9C4 5BC2 C56F AE0F 321F

* tag 'qemu-sparc-20220626' of https://github.com/mcayland/qemu: (55 commits)
  artist: set memory region owners for buffers to the artist device
  ps2: remove update_irq() function and update_arg parameter
  pckbd: add QEMU interface comment for I8042 device
  pckbd: switch I8042 device from update_irq() function to PS2 device gpio
  pckbd: add i8042_reset() function to I8042 device
  pckbd: add QEMU interface comment for I8042_MMIO device
  pckbd: switch I8042_MMIO device from update_irq() function to PS2 device gpio
  lasips2: add QEMU interface comment
  lasips2: switch over from update_irq() function to PS2 device gpio
  lasips2: use sysbus IRQ for output IRQ
  lasips2: implement lasips2_realize()
  lasips2: add base property
  lasips2: move initialisation of PS2 ports from lasi_initfn() to lasi_init()
  lasips2: move mapping of LASIPS2 registers to HPPA machine
  lasips2: implement lasips2_init() function
  lasips2: rename lasips2_init() to lasips2_initfn() and update it to return the LASIPS2 device
  lasips2: move lasips2 QOM types from lasips2.c to lasips2.h
  lasips2: QOMify LASIPS2State
  pl050: add QEMU interface comment
  pl050: switch over from update_irq() function to PS2 device gpio
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2022-06-27 05:21:05 +05:30
commit 097ccbbbaf
10 changed files with 850 additions and 393 deletions

View File

@ -1358,7 +1358,7 @@ static void artist_create_buffer(ARTISTState *s, const char *name,
{
struct vram_buffer *buf = s->vram_buffer + idx;
memory_region_init_ram(&buf->mr, NULL, name, width * height,
memory_region_init_ram(&buf->mr, OBJECT(s), name, width * height,
&error_fatal);
memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0);

View File

@ -280,8 +280,15 @@ static void machine_hppa_init(MachineState *machine)
}
/* PS/2 Keyboard/Mouse */
lasips2_init(addr_space, LASI_PS2KBD_HPA,
qdev_get_gpio_in(lasi_dev, LASI_IRQ_PS2KBD_HPA));
dev = DEVICE(lasips2_initfn(LASI_PS2KBD_HPA,
qdev_get_gpio_in(lasi_dev,
LASI_IRQ_PS2KBD_HPA)));
memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA,
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
0));
memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA + 0x100,
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
1));
/* register power switch emulation */
qemu_register_powerdown_notifier(&hppa_system_powerdown_notifier);

View File

@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "hw/input/ps2.h"
#include "hw/input/lasips2.h"
#include "exec/hwaddr.h"
@ -31,26 +32,9 @@
#include "exec/address-spaces.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
#include "qapi/error.h"
struct LASIPS2State;
typedef struct LASIPS2Port {
struct LASIPS2State *parent;
MemoryRegion reg;
void *dev;
uint8_t id;
uint8_t control;
uint8_t buf;
bool loopback_rbne;
bool irq;
} LASIPS2Port;
typedef struct LASIPS2State {
LASIPS2Port kbd;
LASIPS2Port mouse;
qemu_irq irq;
} LASIPS2State;
static const VMStateDescription vmstate_lasips2 = {
.name = "lasips2",
.version_id = 0,
@ -205,7 +189,6 @@ static uint64_t lasips2_reg_read(void *opaque, hwaddr addr, unsigned size)
break;
case REG_PS2_STATUS:
ret = LASIPS2_STATUS_DATSHD | LASIPS2_STATUS_CLKSHD;
if (port->control & LASIPS2_CONTROL_DIAG) {
@ -238,9 +221,9 @@ static uint64_t lasips2_reg_read(void *opaque, hwaddr addr, unsigned size)
__func__, addr);
break;
}
trace_lasips2_reg_read(size, port->id, addr,
lasips2_read_reg_name(addr), ret);
return ret;
}
@ -254,35 +237,103 @@ static const MemoryRegionOps lasips2_reg_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void ps2dev_update_irq(void *opaque, int level)
static void lasips2_set_kbd_irq(void *opaque, int n, int level)
{
LASIPS2Port *port = opaque;
LASIPS2State *s = LASIPS2(opaque);
LASIPS2Port *port = &s->kbd;
port->irq = level;
lasips2_update_irq(port->parent);
}
void lasips2_init(MemoryRegion *address_space,
hwaddr base, qemu_irq irq)
static void lasips2_set_mouse_irq(void *opaque, int n, int level)
{
LASIPS2State *s;
LASIPS2State *s = LASIPS2(opaque);
LASIPS2Port *port = &s->mouse;
s = g_new0(LASIPS2State, 1);
port->irq = level;
lasips2_update_irq(port->parent);
}
s->irq = irq;
LASIPS2State *lasips2_initfn(hwaddr base, qemu_irq irq)
{
DeviceState *dev;
dev = qdev_new(TYPE_LASIPS2);
qdev_prop_set_uint64(dev, "base", base);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
return LASIPS2(dev);
}
static void lasips2_realize(DeviceState *dev, Error **errp)
{
LASIPS2State *s = LASIPS2(dev);
vmstate_register(NULL, s->base, &vmstate_lasips2, s);
s->kbd.dev = ps2_kbd_init();
qdev_connect_gpio_out(DEVICE(s->kbd.dev), PS2_DEVICE_IRQ,
qdev_get_gpio_in_named(dev, "ps2-kbd-input-irq",
0));
s->mouse.dev = ps2_mouse_init();
qdev_connect_gpio_out(DEVICE(s->mouse.dev), PS2_DEVICE_IRQ,
qdev_get_gpio_in_named(dev, "ps2-mouse-input-irq",
0));
}
static void lasips2_init(Object *obj)
{
LASIPS2State *s = LASIPS2(obj);
s->kbd.id = 0;
s->mouse.id = 1;
s->kbd.parent = s;
s->mouse.parent = s;
vmstate_register(NULL, base, &vmstate_lasips2, s);
s->kbd.dev = ps2_kbd_init(ps2dev_update_irq, &s->kbd);
s->mouse.dev = ps2_mouse_init(ps2dev_update_irq, &s->mouse);
memory_region_init_io(&s->kbd.reg, NULL, &lasips2_reg_ops, &s->kbd,
memory_region_init_io(&s->kbd.reg, obj, &lasips2_reg_ops, &s->kbd,
"lasips2-kbd", 0x100);
memory_region_add_subregion(address_space, base, &s->kbd.reg);
memory_region_init_io(&s->mouse.reg, NULL, &lasips2_reg_ops, &s->mouse,
memory_region_init_io(&s->mouse.reg, obj, &lasips2_reg_ops, &s->mouse,
"lasips2-mouse", 0x100);
memory_region_add_subregion(address_space, base + 0x100, &s->mouse.reg);
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->kbd.reg);
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mouse.reg);
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
qdev_init_gpio_in_named(DEVICE(obj), lasips2_set_kbd_irq,
"ps2-kbd-input-irq", 1);
qdev_init_gpio_in_named(DEVICE(obj), lasips2_set_mouse_irq,
"ps2-mouse-input-irq", 1);
}
static Property lasips2_properties[] = {
DEFINE_PROP_UINT64("base", LASIPS2State, base, UINT64_MAX),
DEFINE_PROP_END_OF_LIST(),
};
static void lasips2_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = lasips2_realize;
device_class_set_props(dc, lasips2_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
static const TypeInfo lasips2_info = {
.name = TYPE_LASIPS2,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_init = lasips2_init,
.instance_size = sizeof(LASIPS2State),
.class_init = lasips2_class_init,
};
static void lasips2_register_types(void)
{
type_register_static(&lasips2_info);
}
type_init(lasips2_register_types)

View File

@ -39,49 +39,86 @@
#include "trace.h"
/* Keyboard Controller Commands */
#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
#define KBD_CCMD_WRITE_OBUF 0xD2
#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
initiated by the auxiliary device */
#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
#define KBD_CCMD_PULSE_BITS_3_0 0xF0 /* Pulse bits 3-0 of the output port P2. */
#define KBD_CCMD_RESET 0xFE /* Pulse bit 0 of the output port P2 = CPU reset. */
#define KBD_CCMD_NO_OP 0xFF /* Pulse no bits of the output port P2. */
/* Keyboard Controller Commands */
/* Read mode bits */
#define KBD_CCMD_READ_MODE 0x20
/* Write mode bits */
#define KBD_CCMD_WRITE_MODE 0x60
/* Get controller version */
#define KBD_CCMD_GET_VERSION 0xA1
/* Disable mouse interface */
#define KBD_CCMD_MOUSE_DISABLE 0xA7
/* Enable mouse interface */
#define KBD_CCMD_MOUSE_ENABLE 0xA8
/* Mouse interface test */
#define KBD_CCMD_TEST_MOUSE 0xA9
/* Controller self test */
#define KBD_CCMD_SELF_TEST 0xAA
/* Keyboard interface test */
#define KBD_CCMD_KBD_TEST 0xAB
/* Keyboard interface disable */
#define KBD_CCMD_KBD_DISABLE 0xAD
/* Keyboard interface enable */
#define KBD_CCMD_KBD_ENABLE 0xAE
/* read input port */
#define KBD_CCMD_READ_INPORT 0xC0
/* read output port */
#define KBD_CCMD_READ_OUTPORT 0xD0
/* write output port */
#define KBD_CCMD_WRITE_OUTPORT 0xD1
#define KBD_CCMD_WRITE_OBUF 0xD2
/* Write to output buffer as if initiated by the auxiliary device */
#define KBD_CCMD_WRITE_AUX_OBUF 0xD3
/* Write the following byte to the mouse */
#define KBD_CCMD_WRITE_MOUSE 0xD4
/* HP vectra only ? */
#define KBD_CCMD_DISABLE_A20 0xDD
/* HP vectra only ? */
#define KBD_CCMD_ENABLE_A20 0xDF
/* Pulse bits 3-0 of the output port P2. */
#define KBD_CCMD_PULSE_BITS_3_0 0xF0
/* Pulse bit 0 of the output port P2 = CPU reset. */
#define KBD_CCMD_RESET 0xFE
/* Pulse no bits of the output port P2. */
#define KBD_CCMD_NO_OP 0xFF
/* Status Register Bits */
#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
#define KBD_STAT_PERR 0x80 /* Parity error */
/* Keyboard output buffer full */
#define KBD_STAT_OBF 0x01
/* Keyboard input buffer full */
#define KBD_STAT_IBF 0x02
/* Self test successful */
#define KBD_STAT_SELFTEST 0x04
/* Last write was a command write (0=data) */
#define KBD_STAT_CMD 0x08
/* Zero if keyboard locked */
#define KBD_STAT_UNLOCKED 0x10
/* Mouse output buffer full */
#define KBD_STAT_MOUSE_OBF 0x20
/* General receive/xmit timeout */
#define KBD_STAT_GTO 0x40
/* Parity error */
#define KBD_STAT_PERR 0x80
/* Controller Mode Register Bits */
#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
#define KBD_MODE_SYS 0x04 /* The system flag (?) */
#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
#define KBD_MODE_RFU 0x80
/* Keyboard data generate IRQ1 */
#define KBD_MODE_KBD_INT 0x01
/* Mouse data generate IRQ12 */
#define KBD_MODE_MOUSE_INT 0x02
/* The system flag (?) */
#define KBD_MODE_SYS 0x04
/* The keylock doesn't affect the keyboard if set */
#define KBD_MODE_NO_KEYLOCK 0x08
/* Disable keyboard interface */
#define KBD_MODE_DISABLE_KBD 0x10
/* Disable mouse interface */
#define KBD_MODE_DISABLE_MOUSE 0x20
/* Scan code conversion to PC format */
#define KBD_MODE_KCC 0x40
#define KBD_MODE_RFU 0x80
/* Output Port Bits */
#define KBD_OUT_RESET 0x01 /* 1=normal mode, 0=reset */
@ -89,7 +126,8 @@
#define KBD_OUT_OBF 0x10 /* Keyboard output buffer full */
#define KBD_OUT_MOUSE_OBF 0x20 /* Mouse output buffer full */
/* OSes typically write 0xdd/0xdf to turn the A20 line off and on.
/*
* OSes typically write 0xdd/0xdf to turn the A20 line off and on.
* We make the default value of the outport include these four bits,
* so that the subsection is rarely necessary.
*/
@ -108,33 +146,11 @@
#define KBD_OBSRC_MOUSE 0x02
#define KBD_OBSRC_CTRL 0x04
typedef struct KBDState {
uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
uint8_t status;
uint8_t mode;
uint8_t outport;
uint32_t migration_flags;
uint32_t obsrc;
bool outport_present;
bool extended_state;
bool extended_state_loaded;
/* Bitmask of devices with data available. */
uint8_t pending;
uint8_t obdata;
uint8_t cbdata;
uint8_t pending_tmp;
void *kbd;
void *mouse;
QEMUTimer *throttle_timer;
qemu_irq irq_kbd;
qemu_irq irq_mouse;
qemu_irq a20_out;
hwaddr mask;
} KBDState;
/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
incorrect, but it avoids having to simulate exact delays */
/*
* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
* incorrect, but it avoids having to simulate exact delays
*/
static void kbd_update_irq_lines(KBDState *s)
{
int irq_kbd_level, irq_mouse_level;
@ -154,8 +170,8 @@ static void kbd_update_irq_lines(KBDState *s)
}
}
}
qemu_set_irq(s->irq_kbd, irq_kbd_level);
qemu_set_irq(s->irq_mouse, irq_mouse_level);
qemu_set_irq(s->irqs[I8042_KBD_IRQ], irq_kbd_level);
qemu_set_irq(s->irqs[I8042_MOUSE_IRQ], irq_mouse_level);
}
static void kbd_deassert_irq(KBDState *s)
@ -302,21 +318,23 @@ static void kbd_write_command(void *opaque, hwaddr addr,
trace_pckbd_kbd_write_command(val);
/* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
/*
* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
* low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
* command specify the output port bits to be pulsed.
* 0: Bit should be pulsed. 1: Bit should not be modified.
* The only useful version of this command is pulsing bit 0,
* which does a CPU reset.
*/
if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
if(!(val & 1))
if ((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
if (!(val & 1)) {
val = KBD_CCMD_RESET;
else
} else {
val = KBD_CCMD_NO_OP;
}
}
switch(val) {
switch (val) {
case KBD_CCMD_READ_MODE:
kbd_queue(s, s->mode, 0);
break;
@ -409,7 +427,7 @@ static void kbd_write_data(void *opaque, hwaddr addr,
trace_pckbd_kbd_write_data(val);
switch(s->write_cmd) {
switch (s->write_cmd) {
case 0:
ps2_write_keyboard(s->kbd, val);
/* sending data to the keyboard reenables PS/2 communication */
@ -607,7 +625,7 @@ static const VMStateDescription vmstate_kbd = {
VMSTATE_UINT8(pending_tmp, KBDState),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription*[]) {
.subsections = (const VMStateDescription * []) {
&vmstate_kbd_outport,
&vmstate_kbd_extended_state,
NULL
@ -619,10 +637,11 @@ static uint64_t kbd_mm_readfn(void *opaque, hwaddr addr, unsigned size)
{
KBDState *s = opaque;
if (addr & s->mask)
if (addr & s->mask) {
return kbd_read_status(s, 0, 1) & 0xff;
else
} else {
return kbd_read_data(s, 0, 1) & 0xff;
}
}
static void kbd_mm_writefn(void *opaque, hwaddr addr,
@ -630,10 +649,11 @@ static void kbd_mm_writefn(void *opaque, hwaddr addr,
{
KBDState *s = opaque;
if (addr & s->mask)
if (addr & s->mask) {
kbd_write_command(s, 0, value & 0xff, 1);
else
} else {
kbd_write_data(s, 0, value & 0xff, 1);
}
}
@ -645,35 +665,105 @@ static const MemoryRegionOps i8042_mmio_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
MemoryRegion *region, ram_addr_t size,
hwaddr mask)
static void i8042_mmio_set_kbd_irq(void *opaque, int n, int level)
{
KBDState *s = g_new0(KBDState, 1);
MMIOKBDState *s = I8042_MMIO(opaque);
KBDState *ks = &s->kbd;
s->irq_kbd = kbd_irq;
s->irq_mouse = mouse_irq;
s->mask = mask;
s->extended_state = true;
vmstate_register(NULL, 0, &vmstate_kbd, s);
memory_region_init_io(region, NULL, &i8042_mmio_ops, s, "i8042", size);
s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
qemu_register_reset(kbd_reset, s);
kbd_update_kbd_irq(ks, level);
}
struct ISAKBDState {
ISADevice parent_obj;
static void i8042_mmio_set_mouse_irq(void *opaque, int n, int level)
{
MMIOKBDState *s = I8042_MMIO(opaque);
KBDState *ks = &s->kbd;
KBDState kbd;
bool kbd_throttle;
MemoryRegion io[2];
uint8_t kbd_irq;
uint8_t mouse_irq;
kbd_update_aux_irq(ks, level);
}
static void i8042_mmio_reset(DeviceState *dev)
{
MMIOKBDState *s = I8042_MMIO(dev);
KBDState *ks = &s->kbd;
kbd_reset(ks);
}
static void i8042_mmio_realize(DeviceState *dev, Error **errp)
{
MMIOKBDState *s = I8042_MMIO(dev);
KBDState *ks = &s->kbd;
memory_region_init_io(&s->region, OBJECT(dev), &i8042_mmio_ops, ks,
"i8042", s->size);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->region);
/* Note we can't use dc->vmsd without breaking migration compatibility */
vmstate_register(NULL, 0, &vmstate_kbd, ks);
ks->kbd = ps2_kbd_init();
qdev_connect_gpio_out(DEVICE(ks->kbd), PS2_DEVICE_IRQ,
qdev_get_gpio_in_named(dev, "ps2-kbd-input-irq",
0));
ks->mouse = ps2_mouse_init();
qdev_connect_gpio_out(DEVICE(ks->mouse), PS2_DEVICE_IRQ,
qdev_get_gpio_in_named(dev, "ps2-mouse-input-irq",
0));
}
static void i8042_mmio_init(Object *obj)
{
MMIOKBDState *s = I8042_MMIO(obj);
KBDState *ks = &s->kbd;
ks->extended_state = true;
qdev_init_gpio_out(DEVICE(obj), ks->irqs, 2);
qdev_init_gpio_in_named(DEVICE(obj), i8042_mmio_set_kbd_irq,
"ps2-kbd-input-irq", 1);
qdev_init_gpio_in_named(DEVICE(obj), i8042_mmio_set_mouse_irq,
"ps2-mouse-input-irq", 1);
}
static Property i8042_mmio_properties[] = {
DEFINE_PROP_UINT64("mask", MMIOKBDState, kbd.mask, UINT64_MAX),
DEFINE_PROP_UINT32("size", MMIOKBDState, size, -1),
DEFINE_PROP_END_OF_LIST(),
};
static void i8042_mmio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = i8042_mmio_realize;
dc->reset = i8042_mmio_reset;
device_class_set_props(dc, i8042_mmio_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
MMIOKBDState *i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
ram_addr_t size, hwaddr mask)
{
DeviceState *dev;
dev = qdev_new(TYPE_I8042_MMIO);
qdev_prop_set_uint64(dev, "mask", mask);
qdev_prop_set_uint32(dev, "size", size);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
qdev_connect_gpio_out(dev, I8042_KBD_IRQ, kbd_irq);
qdev_connect_gpio_out(dev, I8042_MOUSE_IRQ, mouse_irq);
return I8042_MMIO(dev);
}
static const TypeInfo i8042_mmio_info = {
.name = TYPE_I8042_MMIO,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_init = i8042_mmio_init,
.instance_size = sizeof(MMIOKBDState),
.class_init = i8042_mmio_class_init
};
void i8042_isa_mouse_fake_event(ISAKBDState *isa)
@ -718,6 +808,31 @@ static const MemoryRegionOps i8042_cmd_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void i8042_set_kbd_irq(void *opaque, int n, int level)
{
ISAKBDState *s = I8042(opaque);
KBDState *ks = &s->kbd;
kbd_update_kbd_irq(ks, level);
}
static void i8042_set_mouse_irq(void *opaque, int n, int level)
{
ISAKBDState *s = I8042(opaque);
KBDState *ks = &s->kbd;
kbd_update_aux_irq(ks, level);
}
static void i8042_reset(DeviceState *dev)
{
ISAKBDState *s = I8042(dev);
KBDState *ks = &s->kbd;
kbd_reset(ks);
}
static void i8042_initfn(Object *obj)
{
ISAKBDState *isa_s = I8042(obj);
@ -729,6 +844,12 @@ static void i8042_initfn(Object *obj)
"i8042-cmd", 1);
qdev_init_gpio_out_named(DEVICE(obj), &s->a20_out, I8042_A20_LINE, 1);
qdev_init_gpio_out(DEVICE(obj), s->irqs, 2);
qdev_init_gpio_in_named(DEVICE(obj), i8042_set_kbd_irq,
"ps2-kbd-input-irq", 1);
qdev_init_gpio_in_named(DEVICE(obj), i8042_set_mouse_irq,
"ps2-mouse-input-irq", 1);
}
static void i8042_realizefn(DeviceState *dev, Error **errp)
@ -749,14 +870,20 @@ static void i8042_realizefn(DeviceState *dev, Error **errp)
return;
}
s->irq_kbd = isa_get_irq(isadev, isa_s->kbd_irq);
s->irq_mouse = isa_get_irq(isadev, isa_s->mouse_irq);
isa_connect_gpio_out(isadev, I8042_KBD_IRQ, isa_s->kbd_irq);
isa_connect_gpio_out(isadev, I8042_MOUSE_IRQ, isa_s->mouse_irq);
isa_register_ioport(isadev, isa_s->io + 0, 0x60);
isa_register_ioport(isadev, isa_s->io + 1, 0x64);
s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
s->kbd = ps2_kbd_init();
qdev_connect_gpio_out(DEVICE(s->kbd), PS2_DEVICE_IRQ,
qdev_get_gpio_in_named(dev, "ps2-kbd-input-irq",
0));
s->mouse = ps2_mouse_init();
qdev_connect_gpio_out(DEVICE(s->mouse), PS2_DEVICE_IRQ,
qdev_get_gpio_in_named(dev, "ps2-mouse-input-irq",
0));
if (isa_s->kbd_throttle && !isa_s->kbd.extended_state) {
warn_report(TYPE_I8042 ": can't enable kbd-throttle without"
" extended-state, disabling kbd-throttle");
@ -764,7 +891,6 @@ static void i8042_realizefn(DeviceState *dev, Error **errp)
s->throttle_timer = timer_new_us(QEMU_CLOCK_VIRTUAL,
kbd_throttle_timeout, s);
}
qemu_register_reset(kbd_reset, s);
}
static void i8042_build_aml(AcpiDevAmlIf *adev, Aml *scope)
@ -810,6 +936,7 @@ static void i8042_class_initfn(ObjectClass *klass, void *data)
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
device_class_set_props(dc, i8042_properties);
dc->reset = i8042_reset;
dc->realize = i8042_realizefn;
dc->vmsd = &vmstate_kbd_isa;
adevc->build_dev_aml = i8042_build_aml;
@ -831,6 +958,7 @@ static const TypeInfo i8042_info = {
static void i8042_register_types(void)
{
type_register_static(&i8042_info);
type_register_static(&i8042_mmio_info);
}
type_init(i8042_register_types)

View File

@ -7,6 +7,14 @@
* This code is licensed under the GPL.
*/
/*
* QEMU interface:
* + sysbus MMIO region 0: MemoryRegion defining the PL050 registers
* + Named GPIO input "ps2-input-irq": set to 1 if the downstream PS2 device
* has asserted its irq
* + sysbus IRQ 0: PL050 output irq
*/
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
@ -53,26 +61,34 @@ static const VMStateDescription vmstate_pl050 = {
#define PL050_KMIC (1 << 1)
#define PL050_KMID (1 << 0)
static const unsigned char pl050_id[] =
{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
static const unsigned char pl050_id[] = {
0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
};
static void pl050_update(void *opaque, int level)
static void pl050_update_irq(PL050State *s)
{
int level = (s->pending && (s->cr & 0x10) != 0)
|| (s->cr & 0x08) != 0;
qemu_set_irq(s->irq, level);
}
static void pl050_set_irq(void *opaque, int n, int level)
{
PL050State *s = (PL050State *)opaque;
int raise;
s->pending = level;
raise = (s->pending && (s->cr & 0x10) != 0)
|| (s->cr & 0x08) != 0;
qemu_set_irq(s->irq, raise);
pl050_update_irq(s);
}
static uint64_t pl050_read(void *opaque, hwaddr offset,
unsigned size)
{
PL050State *s = (PL050State *)opaque;
if (offset >= 0xfe0 && offset < 0x1000)
if (offset >= 0xfe0 && offset < 0x1000) {
return pl050_id[(offset - 0xfe0) >> 2];
}
switch (offset >> 2) {
case 0: /* KMICR */
@ -88,16 +104,19 @@ static uint64_t pl050_read(void *opaque, hwaddr offset,
val = (val ^ (val >> 1)) & 1;
stat = PL050_TXEMPTY;
if (val)
if (val) {
stat |= PL050_RXPARITY;
if (s->pending)
}
if (s->pending) {
stat |= PL050_RXFULL;
}
return stat;
}
case 2: /* KMIDATA */
if (s->pending)
if (s->pending) {
s->last = ps2_read_data(s->dev);
}
return s->last;
case 3: /* KMICLKDIV */
return s->clk;
@ -114,10 +133,11 @@ static void pl050_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
PL050State *s = (PL050State *)opaque;
switch (offset >> 2) {
case 0: /* KMICR */
s->cr = value;
pl050_update(s, s->pending);
pl050_update_irq(s);
/* ??? Need to implement the enable/disable bit. */
break;
case 2: /* KMIDATA */
@ -152,10 +172,12 @@ static void pl050_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
if (s->is_mouse) {
s->dev = ps2_mouse_init(pl050_update, s);
s->dev = ps2_mouse_init();
} else {
s->dev = ps2_kbd_init(pl050_update, s);
s->dev = ps2_kbd_init();
}
qdev_connect_gpio_out(DEVICE(s->dev), PS2_DEVICE_IRQ,
qdev_get_gpio_in_named(dev, "ps2-input-irq", 0));
}
static void pl050_keyboard_init(Object *obj)
@ -184,6 +206,11 @@ static const TypeInfo pl050_mouse_info = {
.instance_init = pl050_mouse_init,
};
static void pl050_init(Object *obj)
{
qdev_init_gpio_in_named(DEVICE(obj), pl050_set_irq, "ps2-input-irq", 1);
}
static void pl050_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@ -195,6 +222,7 @@ static void pl050_class_init(ObjectClass *oc, void *data)
static const TypeInfo pl050_type_info = {
.name = TYPE_PL050,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_init = pl050_init,
.instance_size = sizeof(PL050State),
.abstract = true,
.class_init = pl050_class_init,

View File

@ -24,61 +24,59 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/irq.h"
#include "hw/sysbus.h"
#include "hw/input/ps2.h"
#include "migration/vmstate.h"
#include "ui/console.h"
#include "ui/input.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
#include "qapi/error.h"
#include "trace.h"
/* Keyboard Commands */
#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
#define KBD_CMD_ECHO 0xEE
#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */
#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
#define KBD_CMD_RESET 0xFF /* Reset */
#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
#define KBD_CMD_ECHO 0xEE
#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */
#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
#define KBD_CMD_RESET 0xFF /* Reset */
#define KBD_CMD_SET_MAKE_BREAK 0xFC /* Set Make and Break mode */
#define KBD_CMD_SET_TYPEMATIC 0xFA /* Set Typematic Make and Break mode */
/* Keyboard Replies */
#define KBD_REPLY_POR 0xAA /* Power on reset */
#define KBD_REPLY_ID 0xAB /* Keyboard ID */
#define KBD_REPLY_ACK 0xFA /* Command ACK */
#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
#define KBD_REPLY_POR 0xAA /* Power on reset */
#define KBD_REPLY_ID 0xAB /* Keyboard ID */
#define KBD_REPLY_ACK 0xFA /* Command ACK */
#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
/* Mouse Commands */
#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
#define AUX_SET_RES 0xE8 /* Set resolution */
#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
#define AUX_SET_STREAM 0xEA /* Set stream mode */
#define AUX_POLL 0xEB /* Poll */
#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
#define AUX_SET_WRAP 0xEE /* Set wrap mode */
#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
#define AUX_GET_TYPE 0xF2 /* Get type */
#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
#define AUX_SET_DEFAULT 0xF6
#define AUX_RESET 0xFF /* Reset aux device */
#define AUX_ACK 0xFA /* Command byte ACK. */
#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
#define AUX_SET_RES 0xE8 /* Set resolution */
#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
#define AUX_SET_STREAM 0xEA /* Set stream mode */
#define AUX_POLL 0xEB /* Poll */
#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
#define AUX_SET_WRAP 0xEE /* Set wrap mode */
#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
#define AUX_GET_TYPE 0xF2 /* Get type */
#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
#define AUX_SET_DEFAULT 0xF6
#define AUX_RESET 0xFF /* Reset aux device */
#define AUX_ACK 0xFA /* Command byte ACK. */
#define MOUSE_STATUS_REMOTE 0x40
#define MOUSE_STATUS_ENABLED 0x20
#define MOUSE_STATUS_SCALE21 0x10
/*
* PS/2 buffer size. Keep 256 bytes for compatibility with
* older QEMU versions.
*/
#define PS2_BUFFER_SIZE 256
#define PS2_QUEUE_SIZE 16 /* Queue size required by PS/2 protocol */
#define PS2_QUEUE_HEADROOM 8 /* Queue size for keyboard command replies */
@ -90,43 +88,6 @@
#define MOD_SHIFT_R (1 << 4)
#define MOD_ALT_R (1 << 5)
typedef struct {
uint8_t data[PS2_BUFFER_SIZE];
int rptr, wptr, cwptr, count;
} PS2Queue;
struct PS2State {
PS2Queue queue;
int32_t write_cmd;
void (*update_irq)(void *, int);
void *update_arg;
};
typedef struct {
PS2State common;
int scan_enabled;
int translate;
int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
int ledstate;
bool need_high_bit;
unsigned int modifiers; /* bitmask of MOD_* constants above */
} PS2KbdState;
typedef struct {
PS2State common;
uint8_t mouse_status;
uint8_t mouse_resolution;
uint8_t mouse_sample_rate;
uint8_t mouse_wrap;
uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
uint8_t mouse_detect_state;
int mouse_dx; /* current values, needed for 'poll' mode */
int mouse_dy;
int mouse_dz;
int mouse_dw;
uint8_t mouse_buttons;
} PS2MouseState;
static uint8_t translate_table[256] = {
0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
@ -212,9 +173,14 @@ void ps2_queue_noirq(PS2State *s, int b)
q->count++;
}
void ps2_raise_irq(PS2State *s)
static void ps2_raise_irq(PS2State *s)
{
s->update_irq(s->update_arg, 1);
qemu_set_irq(s->irq, 1);
}
static void ps2_lower_irq(PS2State *s)
{
qemu_set_irq(s->irq, 0);
}
void ps2_queue(PS2State *s, int b)
@ -324,6 +290,7 @@ static void ps2_cqueue_reset(PS2State *s)
static void ps2_put_keycode(void *opaque, int keycode)
{
PS2KbdState *s = opaque;
PS2State *ps = PS2_DEVICE(s);
trace_ps2_put_keycode(opaque, keycode);
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
@ -332,13 +299,13 @@ static void ps2_put_keycode(void *opaque, int keycode)
if (keycode == 0xf0) {
s->need_high_bit = true;
} else if (s->need_high_bit) {
ps2_queue(&s->common, translate_table[keycode] | 0x80);
ps2_queue(ps, translate_table[keycode] | 0x80);
s->need_high_bit = false;
} else {
ps2_queue(&s->common, translate_table[keycode]);
ps2_queue(ps, translate_table[keycode]);
}
} else {
ps2_queue(&s->common, keycode);
ps2_queue(ps, keycode);
}
}
@ -436,8 +403,9 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
}
}
} else {
if (qcode < qemu_input_map_qcode_to_atset1_len)
if (qcode < qemu_input_map_qcode_to_atset1_len) {
keycode = qemu_input_map_qcode_to_atset1[qcode];
}
if (keycode) {
if (keycode & 0xff00) {
ps2_put_keycode(s, keycode >> 8);
@ -530,8 +498,9 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
}
}
} else {
if (qcode < qemu_input_map_qcode_to_atset2_len)
if (qcode < qemu_input_map_qcode_to_atset2_len) {
keycode = qemu_input_map_qcode_to_atset2[qcode];
}
if (keycode) {
if (keycode & 0xff00) {
ps2_put_keycode(s, keycode >> 8);
@ -546,8 +515,9 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
}
}
} else if (s->scancode_set == 3) {
if (qcode < qemu_input_map_qcode_to_atset3_len)
if (qcode < qemu_input_map_qcode_to_atset3_len) {
keycode = qemu_input_map_qcode_to_atset3[qcode];
}
if (keycode) {
/* FIXME: break code should be configured on a key by key basis */
if (!key->down) {
@ -569,8 +539,10 @@ uint32_t ps2_read_data(PS2State *s)
trace_ps2_read_data(s);
q = &s->queue;
if (q->count == 0) {
/* NOTE: if no data left, we return the last keyboard one
(needed for EMM386) */
/*
* NOTE: if no data left, we return the last keyboard one
* (needed for EMM386)
*/
/* XXX: need a timer to do things correctly */
index = q->rptr - 1;
if (index < 0) {
@ -588,10 +560,10 @@ uint32_t ps2_read_data(PS2State *s)
q->cwptr = -1;
}
/* reading deasserts IRQ */
s->update_irq(s->update_arg, 0);
ps2_lower_irq(s);
/* reassert IRQs if data left */
if (q->count) {
s->update_irq(s->update_arg, 1);
ps2_raise_irq(s);
}
}
return val;
@ -606,119 +578,123 @@ static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
static void ps2_reset_keyboard(PS2KbdState *s)
{
PS2State *ps2 = PS2_DEVICE(s);
trace_ps2_reset_keyboard(s);
s->scan_enabled = 1;
s->scancode_set = 2;
ps2_reset_queue(&s->common);
ps2_reset_queue(ps2);
ps2_set_ledstate(s, 0);
}
void ps2_write_keyboard(void *opaque, int val)
void ps2_write_keyboard(PS2KbdState *s, int val)
{
PS2KbdState *s = (PS2KbdState *)opaque;
PS2State *ps2 = PS2_DEVICE(s);
trace_ps2_write_keyboard(opaque, val);
ps2_cqueue_reset(&s->common);
switch(s->common.write_cmd) {
trace_ps2_write_keyboard(s, val);
ps2_cqueue_reset(ps2);
switch (ps2->write_cmd) {
default:
case -1:
switch(val) {
switch (val) {
case 0x00:
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
ps2_cqueue_1(ps2, KBD_REPLY_ACK);
break;
case 0x05:
ps2_cqueue_1(&s->common, KBD_REPLY_RESEND);
ps2_cqueue_1(ps2, KBD_REPLY_RESEND);
break;
case KBD_CMD_GET_ID:
/* We emulate a MF2 AT keyboard here */
ps2_cqueue_3(&s->common, KBD_REPLY_ACK, KBD_REPLY_ID,
s->translate ? 0x41 : 0x83);
ps2_cqueue_3(ps2, KBD_REPLY_ACK, KBD_REPLY_ID,
s->translate ? 0x41 : 0x83);
break;
case KBD_CMD_ECHO:
ps2_cqueue_1(&s->common, KBD_CMD_ECHO);
ps2_cqueue_1(ps2, KBD_CMD_ECHO);
break;
case KBD_CMD_ENABLE:
s->scan_enabled = 1;
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
ps2_cqueue_1(ps2, KBD_REPLY_ACK);
break;
case KBD_CMD_SCANCODE:
case KBD_CMD_SET_LEDS:
case KBD_CMD_SET_RATE:
case KBD_CMD_SET_MAKE_BREAK:
s->common.write_cmd = val;
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
ps2->write_cmd = val;
ps2_cqueue_1(ps2, KBD_REPLY_ACK);
break;
case KBD_CMD_RESET_DISABLE:
ps2_reset_keyboard(s);
s->scan_enabled = 0;
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
ps2_cqueue_1(ps2, KBD_REPLY_ACK);
break;
case KBD_CMD_RESET_ENABLE:
ps2_reset_keyboard(s);
s->scan_enabled = 1;
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
ps2_cqueue_1(ps2, KBD_REPLY_ACK);
break;
case KBD_CMD_RESET:
ps2_reset_keyboard(s);
ps2_cqueue_2(&s->common,
KBD_REPLY_ACK,
KBD_REPLY_POR);
ps2_cqueue_2(ps2,
KBD_REPLY_ACK,
KBD_REPLY_POR);
break;
case KBD_CMD_SET_TYPEMATIC:
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
ps2_cqueue_1(ps2, KBD_REPLY_ACK);
break;
default:
ps2_cqueue_1(&s->common, KBD_REPLY_RESEND);
ps2_cqueue_1(ps2, KBD_REPLY_RESEND);
break;
}
break;
case KBD_CMD_SET_MAKE_BREAK:
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
s->common.write_cmd = -1;
ps2_cqueue_1(ps2, KBD_REPLY_ACK);
ps2->write_cmd = -1;
break;
case KBD_CMD_SCANCODE:
if (val == 0) {
ps2_cqueue_2(&s->common, KBD_REPLY_ACK, s->translate ?
ps2_cqueue_2(ps2, KBD_REPLY_ACK, s->translate ?
translate_table[s->scancode_set] : s->scancode_set);
} else if (val >= 1 && val <= 3) {
s->scancode_set = val;
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
ps2_cqueue_1(ps2, KBD_REPLY_ACK);
} else {
ps2_cqueue_1(&s->common, KBD_REPLY_RESEND);
ps2_cqueue_1(ps2, KBD_REPLY_RESEND);
}
s->common.write_cmd = -1;
ps2->write_cmd = -1;
break;
case KBD_CMD_SET_LEDS:
ps2_set_ledstate(s, val);
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
s->common.write_cmd = -1;
ps2_cqueue_1(ps2, KBD_REPLY_ACK);
ps2->write_cmd = -1;
break;
case KBD_CMD_SET_RATE:
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
s->common.write_cmd = -1;
ps2_cqueue_1(ps2, KBD_REPLY_ACK);
ps2->write_cmd = -1;
break;
}
}
/* Set the scancode translation mode.
0 = raw scancodes.
1 = translated scancodes (used by qemu internally). */
/*
* Set the scancode translation mode.
* 0 = raw scancodes.
* 1 = translated scancodes (used by qemu internally).
*/
void ps2_keyboard_set_translation(void *opaque, int mode)
void ps2_keyboard_set_translation(PS2KbdState *s, int mode)
{
PS2KbdState *s = (PS2KbdState *)opaque;
trace_ps2_keyboard_set_translation(opaque, mode);
trace_ps2_keyboard_set_translation(s, mode);
s->translate = mode;
}
static int ps2_mouse_send_packet(PS2MouseState *s)
{
PS2State *ps2 = PS2_DEVICE(s);
/* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */
const int needed = s->mouse_type ? 4 : 3;
unsigned int b;
int dx1, dy1, dz1, dw1;
if (PS2_QUEUE_SIZE - s->common.queue.count < needed) {
if (PS2_QUEUE_SIZE - ps2->queue.count < needed) {
return 0;
}
@ -727,31 +703,34 @@ static int ps2_mouse_send_packet(PS2MouseState *s)
dz1 = s->mouse_dz;
dw1 = s->mouse_dw;
/* XXX: increase range to 8 bits ? */
if (dx1 > 127)
if (dx1 > 127) {
dx1 = 127;
else if (dx1 < -127)
} else if (dx1 < -127) {
dx1 = -127;
if (dy1 > 127)
}
if (dy1 > 127) {
dy1 = 127;
else if (dy1 < -127)
} else if (dy1 < -127) {
dy1 = -127;
}
b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
ps2_queue_noirq(&s->common, b);
ps2_queue_noirq(&s->common, dx1 & 0xff);
ps2_queue_noirq(&s->common, dy1 & 0xff);
ps2_queue_noirq(ps2, b);
ps2_queue_noirq(ps2, dx1 & 0xff);
ps2_queue_noirq(ps2, dy1 & 0xff);
/* extra byte for IMPS/2 or IMEX */
switch(s->mouse_type) {
switch (s->mouse_type) {
default:
/* Just ignore the wheels if not supported */
s->mouse_dz = 0;
s->mouse_dw = 0;
break;
case 3:
if (dz1 > 127)
if (dz1 > 127) {
dz1 = 127;
else if (dz1 < -127)
dz1 = -127;
ps2_queue_noirq(&s->common, dz1 & 0xff);
} else if (dz1 < -127) {
dz1 = -127;
}
ps2_queue_noirq(ps2, dz1 & 0xff);
s->mouse_dz -= dz1;
s->mouse_dw = 0;
break;
@ -787,11 +766,11 @@ static int ps2_mouse_send_packet(PS2MouseState *s)
b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
s->mouse_dz -= dz1;
}
ps2_queue_noirq(&s->common, b);
ps2_queue_noirq(ps2, b);
break;
}
ps2_raise_irq(&s->common);
ps2_raise_irq(ps2);
trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
/* update deltas */
@ -816,8 +795,9 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
InputBtnEvent *btn;
/* check if deltas are recorded when disabled */
if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) {
return;
}
switch (evt->type) {
case INPUT_EVENT_KIND_REL:
@ -868,8 +848,10 @@ static void ps2_mouse_sync(DeviceState *dev)
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
}
if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
/* if not remote, send event. Multiple events are sent if
too big deltas */
/*
* if not remote, send event. Multiple events are sent if
* too big deltas
*/
while (ps2_mouse_send_packet(s)) {
if (s->mouse_dx == 0 && s->mouse_dy == 0
&& s->mouse_dz == 0 && s->mouse_dw == 0) {
@ -879,96 +861,95 @@ static void ps2_mouse_sync(DeviceState *dev)
}
}
void ps2_mouse_fake_event(void *opaque)
void ps2_mouse_fake_event(PS2MouseState *s)
{
PS2MouseState *s = opaque;
trace_ps2_mouse_fake_event(opaque);
trace_ps2_mouse_fake_event(s);
s->mouse_dx++;
ps2_mouse_sync(opaque);
ps2_mouse_sync(DEVICE(s));
}
void ps2_write_mouse(void *opaque, int val)
void ps2_write_mouse(PS2MouseState *s, int val)
{
PS2MouseState *s = (PS2MouseState *)opaque;
PS2State *ps2 = PS2_DEVICE(s);
trace_ps2_write_mouse(opaque, val);
switch(s->common.write_cmd) {
trace_ps2_write_mouse(s, val);
switch (ps2->write_cmd) {
default:
case -1:
/* mouse command */
if (s->mouse_wrap) {
if (val == AUX_RESET_WRAP) {
s->mouse_wrap = 0;
ps2_queue(&s->common, AUX_ACK);
ps2_queue(ps2, AUX_ACK);
return;
} else if (val != AUX_RESET) {
ps2_queue(&s->common, val);
ps2_queue(ps2, val);
return;
}
}
switch(val) {
switch (val) {
case AUX_SET_SCALE11:
s->mouse_status &= ~MOUSE_STATUS_SCALE21;
ps2_queue(&s->common, AUX_ACK);
ps2_queue(ps2, AUX_ACK);
break;
case AUX_SET_SCALE21:
s->mouse_status |= MOUSE_STATUS_SCALE21;
ps2_queue(&s->common, AUX_ACK);
ps2_queue(ps2, AUX_ACK);
break;
case AUX_SET_STREAM:
s->mouse_status &= ~MOUSE_STATUS_REMOTE;
ps2_queue(&s->common, AUX_ACK);
ps2_queue(ps2, AUX_ACK);
break;
case AUX_SET_WRAP:
s->mouse_wrap = 1;
ps2_queue(&s->common, AUX_ACK);
ps2_queue(ps2, AUX_ACK);
break;
case AUX_SET_REMOTE:
s->mouse_status |= MOUSE_STATUS_REMOTE;
ps2_queue(&s->common, AUX_ACK);
ps2_queue(ps2, AUX_ACK);
break;
case AUX_GET_TYPE:
ps2_queue_2(&s->common,
ps2_queue_2(ps2,
AUX_ACK,
s->mouse_type);
break;
case AUX_SET_RES:
case AUX_SET_SAMPLE:
s->common.write_cmd = val;
ps2_queue(&s->common, AUX_ACK);
ps2->write_cmd = val;
ps2_queue(ps2, AUX_ACK);
break;
case AUX_GET_SCALE:
ps2_queue_4(&s->common,
ps2_queue_4(ps2,
AUX_ACK,
s->mouse_status,
s->mouse_resolution,
s->mouse_sample_rate);
break;
case AUX_POLL:
ps2_queue(&s->common, AUX_ACK);
ps2_queue(ps2, AUX_ACK);
ps2_mouse_send_packet(s);
break;
case AUX_ENABLE_DEV:
s->mouse_status |= MOUSE_STATUS_ENABLED;
ps2_queue(&s->common, AUX_ACK);
ps2_queue(ps2, AUX_ACK);
break;
case AUX_DISABLE_DEV:
s->mouse_status &= ~MOUSE_STATUS_ENABLED;
ps2_queue(&s->common, AUX_ACK);
ps2_queue(ps2, AUX_ACK);
break;
case AUX_SET_DEFAULT:
s->mouse_sample_rate = 100;
s->mouse_resolution = 2;
s->mouse_status = 0;
ps2_queue(&s->common, AUX_ACK);
ps2_queue(ps2, AUX_ACK);
break;
case AUX_RESET:
s->mouse_sample_rate = 100;
s->mouse_resolution = 2;
s->mouse_status = 0;
s->mouse_type = 0;
ps2_reset_queue(&s->common);
ps2_queue_3(&s->common,
ps2_reset_queue(ps2);
ps2_queue_3(ps2,
AUX_ACK,
0xaa,
s->mouse_type);
@ -980,47 +961,53 @@ void ps2_write_mouse(void *opaque, int val)
case AUX_SET_SAMPLE:
s->mouse_sample_rate = val;
/* detect IMPS/2 or IMEX */
switch(s->mouse_detect_state) {
switch (s->mouse_detect_state) {
default:
case 0:
if (val == 200)
if (val == 200) {
s->mouse_detect_state = 1;
}
break;
case 1:
if (val == 100)
if (val == 100) {
s->mouse_detect_state = 2;
else if (val == 200)
} else if (val == 200) {
s->mouse_detect_state = 3;
else
} else {
s->mouse_detect_state = 0;
}
break;
case 2:
if (val == 80)
if (val == 80) {
s->mouse_type = 3; /* IMPS/2 */
}
s->mouse_detect_state = 0;
break;
case 3:
if (val == 80)
if (val == 80) {
s->mouse_type = 4; /* IMEX */
}
s->mouse_detect_state = 0;
break;
}
ps2_queue(&s->common, AUX_ACK);
s->common.write_cmd = -1;
ps2_queue(ps2, AUX_ACK);
ps2->write_cmd = -1;
break;
case AUX_SET_RES:
s->mouse_resolution = val;
ps2_queue(&s->common, AUX_ACK);
s->common.write_cmd = -1;
ps2_queue(ps2, AUX_ACK);
ps2->write_cmd = -1;
break;
}
}
static void ps2_common_reset(PS2State *s)
static void ps2_reset(DeviceState *dev)
{
PS2State *s = PS2_DEVICE(dev);
s->write_cmd = -1;
ps2_reset_queue(s);
s->update_irq(s->update_arg, 0);
ps2_lower_irq(s);
}
static void ps2_common_post_load(PS2State *s)
@ -1049,24 +1036,28 @@ static void ps2_common_post_load(PS2State *s)
q->cwptr = ccount ? (q->rptr + ccount) & (PS2_BUFFER_SIZE - 1) : -1;
}
static void ps2_kbd_reset(void *opaque)
static void ps2_kbd_reset(DeviceState *dev)
{
PS2KbdState *s = (PS2KbdState *) opaque;
PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(dev);
PS2KbdState *s = PS2_KBD_DEVICE(dev);
trace_ps2_kbd_reset(s);
ps2dc->parent_reset(dev);
trace_ps2_kbd_reset(opaque);
ps2_common_reset(&s->common);
s->scan_enabled = 1;
s->translate = 0;
s->scancode_set = 2;
s->modifiers = 0;
}
static void ps2_mouse_reset(void *opaque)
static void ps2_mouse_reset(DeviceState *dev)
{
PS2MouseState *s = (PS2MouseState *) opaque;
PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(dev);
PS2MouseState *s = PS2_MOUSE_DEVICE(dev);
trace_ps2_mouse_reset(s);
ps2dc->parent_reset(dev);
trace_ps2_mouse_reset(opaque);
ps2_common_reset(&s->common);
s->mouse_status = 0;
s->mouse_resolution = 0;
s->mouse_sample_rate = 0;
@ -1141,26 +1132,28 @@ static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
static bool ps2_keyboard_cqueue_needed(void *opaque)
{
PS2KbdState *s = opaque;
PS2State *ps2 = PS2_DEVICE(s);
return s->common.queue.cwptr != -1; /* the queue is mostly empty */
return ps2->queue.cwptr != -1; /* the queue is mostly empty */
}
static const VMStateDescription vmstate_ps2_keyboard_cqueue = {
.name = "ps2kbd/command_reply_queue",
.needed = ps2_keyboard_cqueue_needed,
.fields = (VMStateField[]) {
VMSTATE_INT32(common.queue.cwptr, PS2KbdState),
VMSTATE_INT32(parent_obj.queue.cwptr, PS2KbdState),
VMSTATE_END_OF_LIST()
}
};
static int ps2_kbd_post_load(void* opaque, int version_id)
static int ps2_kbd_post_load(void *opaque, int version_id)
{
PS2KbdState *s = (PS2KbdState*)opaque;
PS2State *ps2 = &s->common;
PS2KbdState *s = (PS2KbdState *)opaque;
PS2State *ps2 = PS2_DEVICE(s);
if (version_id == 2)
s->scancode_set=2;
if (version_id == 2) {
s->scancode_set = 2;
}
ps2_common_post_load(ps2);
@ -1173,13 +1166,14 @@ static const VMStateDescription vmstate_ps2_keyboard = {
.minimum_version_id = 2,
.post_load = ps2_kbd_post_load,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
VMSTATE_STRUCT(parent_obj, PS2KbdState, 0, vmstate_ps2_common,
PS2State),
VMSTATE_INT32(scan_enabled, PS2KbdState),
VMSTATE_INT32(translate, PS2KbdState),
VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
VMSTATE_INT32_V(scancode_set, PS2KbdState, 3),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription*[]) {
.subsections = (const VMStateDescription * []) {
&vmstate_ps2_keyboard_ledstate,
&vmstate_ps2_keyboard_need_high_bit,
&vmstate_ps2_keyboard_cqueue,
@ -1190,7 +1184,7 @@ static const VMStateDescription vmstate_ps2_keyboard = {
static int ps2_mouse_post_load(void *opaque, int version_id)
{
PS2MouseState *s = (PS2MouseState *)opaque;
PS2State *ps2 = &s->common;
PS2State *ps2 = PS2_DEVICE(s);
ps2_common_post_load(ps2);
@ -1203,7 +1197,8 @@ static const VMStateDescription vmstate_ps2_mouse = {
.minimum_version_id = 2,
.post_load = ps2_mouse_post_load,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
VMSTATE_STRUCT(parent_obj, PS2MouseState, 0, vmstate_ps2_common,
PS2State),
VMSTATE_UINT8(mouse_status, PS2MouseState),
VMSTATE_UINT8(mouse_resolution, PS2MouseState),
VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
@ -1224,18 +1219,21 @@ static QemuInputHandler ps2_keyboard_handler = {
.event = ps2_keyboard_event,
};
void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
static void ps2_kbd_realize(DeviceState *dev, Error **errp)
{
PS2KbdState *s = g_new0(PS2KbdState, 1);
qemu_input_handler_register(dev, &ps2_keyboard_handler);
}
void *ps2_kbd_init(void)
{
DeviceState *dev;
PS2KbdState *s;
dev = qdev_new(TYPE_PS2_KBD_DEVICE);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
s = PS2_KBD_DEVICE(dev);
trace_ps2_kbd_init(s);
s->common.update_irq = update_irq;
s->common.update_arg = update_arg;
s->scancode_set = 2;
vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
qemu_input_handler_register((DeviceState *)s,
&ps2_keyboard_handler);
qemu_register_reset(ps2_kbd_reset, s);
return s;
}
@ -1246,16 +1244,89 @@ static QemuInputHandler ps2_mouse_handler = {
.sync = ps2_mouse_sync,
};
void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
static void ps2_mouse_realize(DeviceState *dev, Error **errp)
{
PS2MouseState *s = g_new0(PS2MouseState, 1);
qemu_input_handler_register(dev, &ps2_mouse_handler);
}
void *ps2_mouse_init(void)
{
DeviceState *dev;
PS2MouseState *s;
dev = qdev_new(TYPE_PS2_MOUSE_DEVICE);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
s = PS2_MOUSE_DEVICE(dev);
trace_ps2_mouse_init(s);
s->common.update_irq = update_irq;
s->common.update_arg = update_arg;
vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
qemu_input_handler_register((DeviceState *)s,
&ps2_mouse_handler);
qemu_register_reset(ps2_mouse_reset, s);
return s;
}
static void ps2_kbd_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PS2DeviceClass *ps2dc = PS2_DEVICE_CLASS(klass);
dc->realize = ps2_kbd_realize;
device_class_set_parent_reset(dc, ps2_kbd_reset, &ps2dc->parent_reset);
dc->vmsd = &vmstate_ps2_keyboard;
}
static const TypeInfo ps2_kbd_info = {
.name = TYPE_PS2_KBD_DEVICE,
.parent = TYPE_PS2_DEVICE,
.instance_size = sizeof(PS2KbdState),
.class_init = ps2_kbd_class_init
};
static void ps2_mouse_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PS2DeviceClass *ps2dc = PS2_DEVICE_CLASS(klass);
dc->realize = ps2_mouse_realize;
device_class_set_parent_reset(dc, ps2_mouse_reset,
&ps2dc->parent_reset);
dc->vmsd = &vmstate_ps2_mouse;
}
static const TypeInfo ps2_mouse_info = {
.name = TYPE_PS2_MOUSE_DEVICE,
.parent = TYPE_PS2_DEVICE,
.instance_size = sizeof(PS2MouseState),
.class_init = ps2_mouse_class_init
};
static void ps2_init(Object *obj)
{
PS2State *s = PS2_DEVICE(obj);
qdev_init_gpio_out(DEVICE(obj), &s->irq, 1);
}
static void ps2_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = ps2_reset;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
static const TypeInfo ps2_info = {
.name = TYPE_PS2_DEVICE,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_init = ps2_init,
.instance_size = sizeof(PS2State),
.class_init = ps2_class_init,
.class_size = sizeof(PS2DeviceClass),
.abstract = true
};
static void ps2_register_types(void)
{
type_register_static(&ps2_info);
type_register_static(&ps2_kbd_info);
type_register_static(&ps2_mouse_info);
}
type_init(ps2_register_types)

View File

@ -136,11 +136,11 @@ static void mips_jazz_init(MachineState *machine,
MemoryRegion *isa_mem = g_new(MemoryRegion, 1);
MemoryRegion *isa_io = g_new(MemoryRegion, 1);
MemoryRegion *rtc = g_new(MemoryRegion, 1);
MemoryRegion *i8042 = g_new(MemoryRegion, 1);
MemoryRegion *dma_dummy = g_new(MemoryRegion, 1);
MemoryRegion *dp8393x_prom = g_new(MemoryRegion, 1);
NICInfo *nd;
DeviceState *dev, *rc4030;
MMIOKBDState *i8042;
SysBusDevice *sysbus;
ISABus *isa_bus;
ISADevice *pit;
@ -361,9 +361,12 @@ static void mips_jazz_init(MachineState *machine,
memory_region_add_subregion(address_space, 0x80004000, rtc);
/* Keyboard (i8042) */
i8042_mm_init(qdev_get_gpio_in(rc4030, 6), qdev_get_gpio_in(rc4030, 7),
i8042, 0x1000, 0x1);
memory_region_add_subregion(address_space, 0x80005000, i8042);
i8042 = i8042_mm_init(qdev_get_gpio_in(rc4030, 6),
qdev_get_gpio_in(rc4030, 7),
0x1000, 0x1);
memory_region_add_subregion(address_space, 0x80005000,
sysbus_mmio_get_region(SYS_BUS_DEVICE(i8042),
0));
/* Serial ports */
serial_mm_init(address_space, 0x80006000, 0,

View File

@ -9,17 +9,86 @@
#define HW_INPUT_I8042_H
#include "hw/isa/isa.h"
#include "hw/sysbus.h"
#include "qom/object.h"
#define I8042_KBD_IRQ 0
#define I8042_MOUSE_IRQ 1
typedef struct KBDState {
uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
uint8_t status;
uint8_t mode;
uint8_t outport;
uint32_t migration_flags;
uint32_t obsrc;
bool outport_present;
bool extended_state;
bool extended_state_loaded;
/* Bitmask of devices with data available. */
uint8_t pending;
uint8_t obdata;
uint8_t cbdata;
uint8_t pending_tmp;
void *kbd;
void *mouse;
QEMUTimer *throttle_timer;
qemu_irq irqs[2];
qemu_irq a20_out;
hwaddr mask;
} KBDState;
/*
* QEMU interface:
* + Named GPIO input "ps2-kbd-input-irq": set to 1 if the downstream PS2
* keyboard device has asserted its irq
* + Named GPIO input "ps2-mouse-input-irq": set to 1 if the downstream PS2
* mouse device has asserted its irq
* + Named GPIO output "a20": A20 line for x86 PCs
* + Unnamed GPIO output 0-1: i8042 output irqs for keyboard (0) or mouse (1)
*/
#define TYPE_I8042 "i8042"
OBJECT_DECLARE_SIMPLE_TYPE(ISAKBDState, I8042)
struct ISAKBDState {
ISADevice parent_obj;
KBDState kbd;
bool kbd_throttle;
MemoryRegion io[2];
uint8_t kbd_irq;
uint8_t mouse_irq;
};
/*
* QEMU interface:
* + sysbus MMIO region 0: MemoryRegion defining the command/status/data
* registers (access determined by mask property and access type)
* + Named GPIO input "ps2-kbd-input-irq": set to 1 if the downstream PS2
* keyboard device has asserted its irq
* + Named GPIO input "ps2-mouse-input-irq": set to 1 if the downstream PS2
* mouse device has asserted its irq
* + Unnamed GPIO output 0-1: i8042 output irqs for keyboard (0) or mouse (1)
*/
#define TYPE_I8042_MMIO "i8042-mmio"
OBJECT_DECLARE_SIMPLE_TYPE(MMIOKBDState, I8042_MMIO)
struct MMIOKBDState {
SysBusDevice parent_obj;
KBDState kbd;
uint32_t size;
MemoryRegion region;
};
#define I8042_A20_LINE "a20"
void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
MemoryRegion *region, ram_addr_t size,
hwaddr mask);
MMIOKBDState *i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
ram_addr_t size, hwaddr mask);
void i8042_isa_mouse_fake_event(ISAKBDState *isa);
void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out);

View File

@ -4,13 +4,50 @@
* Copyright (c) 2019 Sven Schnelle
*
*/
/*
* QEMU interface:
* + sysbus MMIO region 0: MemoryRegion defining the LASI PS2 keyboard
* registers
* + sysbus MMIO region 1: MemoryRegion defining the LASI PS2 mouse
* registers
* + sysbus IRQ 0: LASI PS2 output irq
* + Named GPIO input "ps2-kbd-input-irq": set to 1 if the downstream PS2
* keyboard device has asserted its irq
* + Named GPIO input "ps2-mouse-input-irq": set to 1 if the downstream PS2
* mouse device has asserted its irq
*/
#ifndef HW_INPUT_LASIPS2_H
#define HW_INPUT_LASIPS2_H
#include "exec/hwaddr.h"
#include "hw/sysbus.h"
struct LASIPS2State;
typedef struct LASIPS2Port {
struct LASIPS2State *parent;
MemoryRegion reg;
void *dev;
uint8_t id;
uint8_t control;
uint8_t buf;
bool loopback_rbne;
bool irq;
} LASIPS2Port;
struct LASIPS2State {
SysBusDevice parent_obj;
hwaddr base;
LASIPS2Port kbd;
LASIPS2Port mouse;
qemu_irq irq;
};
#define TYPE_LASIPS2 "lasips2"
OBJECT_DECLARE_SIMPLE_TYPE(LASIPS2State, LASIPS2)
void lasips2_init(MemoryRegion *address_space, hwaddr base, qemu_irq irq);
LASIPS2State *lasips2_initfn(hwaddr base, qemu_irq irq);
#endif /* HW_INPUT_LASIPS2_H */

View File

@ -25,28 +25,91 @@
#ifndef HW_PS2_H
#define HW_PS2_H
#include "hw/sysbus.h"
#define PS2_MOUSE_BUTTON_LEFT 0x01
#define PS2_MOUSE_BUTTON_RIGHT 0x02
#define PS2_MOUSE_BUTTON_MIDDLE 0x04
#define PS2_MOUSE_BUTTON_SIDE 0x08
#define PS2_MOUSE_BUTTON_EXTRA 0x10
typedef struct PS2State PS2State;
struct PS2DeviceClass {
SysBusDeviceClass parent_class;
DeviceReset parent_reset;
};
/*
* PS/2 buffer size. Keep 256 bytes for compatibility with
* older QEMU versions.
*/
#define PS2_BUFFER_SIZE 256
typedef struct {
uint8_t data[PS2_BUFFER_SIZE];
int rptr, wptr, cwptr, count;
} PS2Queue;
/* Output IRQ */
#define PS2_DEVICE_IRQ 0
struct PS2State {
SysBusDevice parent_obj;
PS2Queue queue;
int32_t write_cmd;
qemu_irq irq;
};
#define TYPE_PS2_DEVICE "ps2-device"
OBJECT_DECLARE_TYPE(PS2State, PS2DeviceClass, PS2_DEVICE)
struct PS2KbdState {
PS2State parent_obj;
int scan_enabled;
int translate;
int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
int ledstate;
bool need_high_bit;
unsigned int modifiers; /* bitmask of MOD_* constants above */
};
#define TYPE_PS2_KBD_DEVICE "ps2-kbd"
OBJECT_DECLARE_SIMPLE_TYPE(PS2KbdState, PS2_KBD_DEVICE)
struct PS2MouseState {
PS2State parent_obj;
uint8_t mouse_status;
uint8_t mouse_resolution;
uint8_t mouse_sample_rate;
uint8_t mouse_wrap;
uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
uint8_t mouse_detect_state;
int mouse_dx; /* current values, needed for 'poll' mode */
int mouse_dy;
int mouse_dz;
int mouse_dw;
uint8_t mouse_buttons;
};
#define TYPE_PS2_MOUSE_DEVICE "ps2-mouse"
OBJECT_DECLARE_SIMPLE_TYPE(PS2MouseState, PS2_MOUSE_DEVICE)
/* ps2.c */
void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
void ps2_write_mouse(void *, int val);
void ps2_write_keyboard(void *, int val);
void *ps2_kbd_init(void);
void *ps2_mouse_init(void);
void ps2_write_mouse(PS2MouseState *s, int val);
void ps2_write_keyboard(PS2KbdState *s, int val);
uint32_t ps2_read_data(PS2State *s);
void ps2_queue_noirq(PS2State *s, int b);
void ps2_raise_irq(PS2State *s);
void ps2_queue(PS2State *s, int b);
void ps2_queue_2(PS2State *s, int b1, int b2);
void ps2_queue_3(PS2State *s, int b1, int b2, int b3);
void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4);
void ps2_keyboard_set_translation(void *opaque, int mode);
void ps2_mouse_fake_event(void *opaque);
void ps2_keyboard_set_translation(PS2KbdState *s, int mode);
void ps2_mouse_fake_event(PS2MouseState *s);
int ps2_queue_empty(PS2State *s);
#endif /* HW_PS2_H */