summaryrefslogtreecommitdiffstats
path: root/hw/input
diff options
context:
space:
mode:
Diffstat (limited to 'hw/input')
-rw-r--r--hw/input/adb-kbd.c42
-rw-r--r--hw/input/adb-mouse.c65
-rw-r--r--hw/input/adb.c210
-rw-r--r--hw/input/pckbd.c31
-rw-r--r--hw/input/trace-events27
5 files changed, 305 insertions, 70 deletions
diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index a6d5c9b7c9..3cfb6a7a20 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -243,7 +243,7 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
olen = 0;
switch (cmd) {
case ADB_WRITEREG:
- trace_adb_kbd_writereg(reg, buf[1]);
+ trace_adb_device_kbd_writereg(reg, buf[1]);
switch (reg) {
case 2:
/* LED status */
@@ -256,24 +256,22 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
- trace_adb_kbd_request_change_addr(d->devaddr);
+ trace_adb_device_kbd_request_change_addr(d->devaddr);
break;
default:
- if (!d->disable_direct_reg3_writes) {
- d->devaddr = buf[1] & 0xf;
-
- /* we support handlers:
- * 1: Apple Standard Keyboard
- * 2: Apple Extended Keyboard (LShift = RShift)
- * 3: Apple Extended Keyboard (LShift != RShift)
- */
- if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) {
- d->handler = buf[2];
- }
-
- trace_adb_kbd_request_change_addr_and_handler(d->devaddr,
- d->handler);
+ d->devaddr = buf[1] & 0xf;
+ /*
+ * we support handlers:
+ * 1: Apple Standard Keyboard
+ * 2: Apple Extended Keyboard (LShift = RShift)
+ * 3: Apple Extended Keyboard (LShift != RShift)
+ */
+ if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) {
+ d->handler = buf[2];
}
+
+ trace_adb_device_kbd_request_change_addr_and_handler(
+ d->devaddr, d->handler);
break;
}
}
@@ -296,12 +294,19 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
olen = 2;
break;
}
- trace_adb_kbd_readreg(reg, obuf[0], obuf[1]);
+ trace_adb_device_kbd_readreg(reg, obuf[0], obuf[1]);
break;
}
return olen;
}
+static bool adb_kbd_has_data(ADBDevice *d)
+{
+ KBDState *s = ADB_KEYBOARD(d);
+
+ return s->count > 0;
+}
+
/* This is where keyboard events enter this file */
static void adb_keyboard_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
@@ -316,7 +321,7 @@ static void adb_keyboard_event(DeviceState *dev, QemuConsole *src,
/* FIXME: take handler into account when translating qcode */
keycode = qcode_to_adb_keycode[qcode];
if (keycode == NO_KEY) { /* We don't want to send this to the guest */
- trace_adb_kbd_no_key();
+ trace_adb_device_kbd_no_key();
return;
}
if (evt->u.key.data->down == false) { /* if key release event */
@@ -384,6 +389,7 @@ static void adb_kbd_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
adc->devreq = adb_kbd_request;
+ adc->devhasdata = adb_kbd_has_data;
dc->reset = adb_kbd_reset;
dc->vmsd = &vmstate_adb_kbd;
}
diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c
index aeba41bddd..577a38ff2e 100644
--- a/hw/input/adb-mouse.c
+++ b/hw/input/adb-mouse.c
@@ -121,7 +121,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
s->dx = 0;
s->dy = 0;
s->dz = 0;
- trace_adb_mouse_flush();
+ trace_adb_device_mouse_flush();
return 0;
}
@@ -130,11 +130,21 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
olen = 0;
switch (cmd) {
case ADB_WRITEREG:
- trace_adb_mouse_writereg(reg, buf[1]);
+ trace_adb_device_mouse_writereg(reg, buf[1]);
switch (reg) {
case 2:
break;
case 3:
+ /*
+ * MacOS 9 has a bug in its ADB driver whereby after configuring
+ * the ADB bus devices it sends another write of invalid length
+ * to reg 3. Make sure we ignore it to prevent an address clash
+ * with the previous device.
+ */
+ if (len != 3) {
+ return 0;
+ }
+
switch (buf[2]) {
case ADB_CMD_SELF_TEST:
break;
@@ -142,30 +152,28 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
- trace_adb_mouse_request_change_addr(d->devaddr);
+ trace_adb_device_mouse_request_change_addr(d->devaddr);
break;
default:
- if (!d->disable_direct_reg3_writes) {
- d->devaddr = buf[1] & 0xf;
-
- /* we support handlers:
- * 0x01: Classic Apple Mouse Protocol / 100 cpi operations
- * 0x02: Classic Apple Mouse Protocol / 200 cpi operations
- * we don't support handlers (at least):
- * 0x03: Mouse systems A3 trackball
- * 0x04: Extended Apple Mouse Protocol
- * 0x2f: Microspeed mouse
- * 0x42: Macally
- * 0x5f: Microspeed mouse
- * 0x66: Microspeed mouse
- */
- if (buf[2] == 1 || buf[2] == 2) {
- d->handler = buf[2];
- }
-
- trace_adb_mouse_request_change_addr_and_handler(
- d->devaddr, d->handler);
+ d->devaddr = buf[1] & 0xf;
+ /*
+ * we support handlers:
+ * 0x01: Classic Apple Mouse Protocol / 100 cpi operations
+ * 0x02: Classic Apple Mouse Protocol / 200 cpi operations
+ * we don't support handlers (at least):
+ * 0x03: Mouse systems A3 trackball
+ * 0x04: Extended Apple Mouse Protocol
+ * 0x2f: Microspeed mouse
+ * 0x42: Macally
+ * 0x5f: Microspeed mouse
+ * 0x66: Microspeed mouse
+ */
+ if (buf[2] == 1 || buf[2] == 2) {
+ d->handler = buf[2];
}
+
+ trace_adb_device_mouse_request_change_addr_and_handler(
+ d->devaddr, d->handler);
break;
}
}
@@ -183,12 +191,20 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
olen = 2;
break;
}
- trace_adb_mouse_readreg(reg, obuf[0], obuf[1]);
+ trace_adb_device_mouse_readreg(reg, obuf[0], obuf[1]);
break;
}
return olen;
}
+static bool adb_mouse_has_data(ADBDevice *d)
+{
+ MouseState *s = ADB_MOUSE(d);
+
+ return !(s->last_buttons_state == s->buttons_state &&
+ s->dx == 0 && s->dy == 0);
+}
+
static void adb_mouse_reset(DeviceState *dev)
{
ADBDevice *d = ADB_DEVICE(dev);
@@ -244,6 +260,7 @@ static void adb_mouse_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
adc->devreq = adb_mouse_request;
+ adc->devhasdata = adb_mouse_has_data;
dc->reset = adb_mouse_reset;
dc->vmsd = &vmstate_adb_mouse;
}
diff --git a/hw/input/adb.c b/hw/input/adb.c
index b1ac4a3852..013fcc9c54 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -27,41 +27,85 @@
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
+#include "qemu/timer.h"
#include "adb-internal.h"
+#include "trace.h"
/* error codes */
#define ADB_RET_NOTPRESENT (-2)
+static const char *adb_commands[] = {
+ "RESET", "FLUSH", "(Reserved 0x2)", "(Reserved 0x3)",
+ "Reserved (0x4)", "(Reserved 0x5)", "(Reserved 0x6)", "(Reserved 0x7)",
+ "LISTEN r0", "LISTEN r1", "LISTEN r2", "LISTEN r3",
+ "TALK r0", "TALK r1", "TALK r2", "TALK r3",
+};
+
static void adb_device_reset(ADBDevice *d)
{
qdev_reset_all(DEVICE(d));
}
-int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
+static int do_adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf,
+ int len)
{
ADBDevice *d;
- int devaddr, cmd, i;
+ ADBDeviceClass *adc;
+ int devaddr, cmd, olen, i;
cmd = buf[0] & 0xf;
if (cmd == ADB_BUSRESET) {
- for(i = 0; i < s->nb_devices; i++) {
+ for (i = 0; i < s->nb_devices; i++) {
d = s->devices[i];
adb_device_reset(d);
}
+ s->status = 0;
return 0;
}
+
+ s->pending = 0;
+ for (i = 0; i < s->nb_devices; i++) {
+ d = s->devices[i];
+ adc = ADB_DEVICE_GET_CLASS(d);
+
+ if (adc->devhasdata(d)) {
+ s->pending |= (1 << d->devaddr);
+ }
+ }
+
+ s->status = 0;
devaddr = buf[0] >> 4;
- for(i = 0; i < s->nb_devices; i++) {
+ for (i = 0; i < s->nb_devices; i++) {
d = s->devices[i];
+ adc = ADB_DEVICE_GET_CLASS(d);
+
if (d->devaddr == devaddr) {
- ADBDeviceClass *adc = ADB_DEVICE_GET_CLASS(d);
- return adc->devreq(d, obuf, buf, len);
+ olen = adc->devreq(d, obuf, buf, len);
+ if (!olen) {
+ s->status |= ADB_STATUS_BUSTIMEOUT;
+ }
+ return olen;
}
}
+
+ s->status |= ADB_STATUS_BUSTIMEOUT;
return ADB_RET_NOTPRESENT;
}
-/* XXX: move that to cuda ? */
+int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
+{
+ int ret;
+
+ trace_adb_bus_request(buf[0] >> 4, adb_commands[buf[0] & 0xf], len);
+
+ assert(s->autopoll_blocked);
+
+ ret = do_adb_request(s, obuf, buf, len);
+
+ trace_adb_bus_request_done(buf[0] >> 4, adb_commands[buf[0] & 0xf], ret);
+ return ret;
+}
+
int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
{
ADBDevice *d;
@@ -69,18 +113,20 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
uint8_t buf[1];
olen = 0;
- for(i = 0; i < s->nb_devices; i++) {
- if (s->poll_index >= s->nb_devices)
+ for (i = 0; i < s->nb_devices; i++) {
+ if (s->poll_index >= s->nb_devices) {
s->poll_index = 0;
+ }
d = s->devices[s->poll_index];
if ((1 << d->devaddr) & poll_mask) {
buf[0] = ADB_READREG | (d->devaddr << 4);
- olen = adb_request(s, obuf + 1, buf, 1);
+ olen = do_adb_request(s, obuf + 1, buf, 1);
/* if there is data, we poll again the same device */
if (olen > 0) {
+ s->status |= ADB_STATUS_POLLREPLY;
obuf[0] = buf[0];
olen++;
- break;
+ return olen;
}
}
s->poll_index++;
@@ -88,10 +134,145 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
return olen;
}
+void adb_set_autopoll_enabled(ADBBusState *s, bool enabled)
+{
+ if (s->autopoll_enabled != enabled) {
+ s->autopoll_enabled = enabled;
+ if (s->autopoll_enabled) {
+ timer_mod(s->autopoll_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ s->autopoll_rate_ms);
+ } else {
+ timer_del(s->autopoll_timer);
+ }
+ }
+}
+
+void adb_set_autopoll_rate_ms(ADBBusState *s, int rate_ms)
+{
+ s->autopoll_rate_ms = rate_ms;
+
+ if (s->autopoll_enabled) {
+ timer_mod(s->autopoll_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ s->autopoll_rate_ms);
+ }
+}
+
+void adb_set_autopoll_mask(ADBBusState *s, uint16_t mask)
+{
+ if (s->autopoll_mask != mask) {
+ s->autopoll_mask = mask;
+ if (s->autopoll_enabled && s->autopoll_mask) {
+ timer_mod(s->autopoll_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ s->autopoll_rate_ms);
+ } else {
+ timer_del(s->autopoll_timer);
+ }
+ }
+}
+
+void adb_autopoll_block(ADBBusState *s)
+{
+ s->autopoll_blocked = true;
+ trace_adb_bus_autopoll_block(s->autopoll_blocked);
+
+ if (s->autopoll_enabled) {
+ timer_del(s->autopoll_timer);
+ }
+}
+
+void adb_autopoll_unblock(ADBBusState *s)
+{
+ s->autopoll_blocked = false;
+ trace_adb_bus_autopoll_block(s->autopoll_blocked);
+
+ if (s->autopoll_enabled) {
+ timer_mod(s->autopoll_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ s->autopoll_rate_ms);
+ }
+}
+
+static void adb_autopoll(void *opaque)
+{
+ ADBBusState *s = opaque;
+
+ if (!s->autopoll_blocked) {
+ trace_adb_bus_autopoll_cb(s->autopoll_mask);
+ s->autopoll_cb(s->autopoll_cb_opaque);
+ trace_adb_bus_autopoll_cb_done(s->autopoll_mask);
+ }
+
+ timer_mod(s->autopoll_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ s->autopoll_rate_ms);
+}
+
+void adb_register_autopoll_callback(ADBBusState *s, void (*cb)(void *opaque),
+ void *opaque)
+{
+ s->autopoll_cb = cb;
+ s->autopoll_cb_opaque = opaque;
+}
+
+static const VMStateDescription vmstate_adb_bus = {
+ .name = "adb_bus",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_TIMER_PTR(autopoll_timer, ADBBusState),
+ VMSTATE_BOOL(autopoll_enabled, ADBBusState),
+ VMSTATE_UINT8(autopoll_rate_ms, ADBBusState),
+ VMSTATE_UINT16(autopoll_mask, ADBBusState),
+ VMSTATE_BOOL(autopoll_blocked, ADBBusState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void adb_bus_reset(BusState *qbus)
+{
+ ADBBusState *adb_bus = ADB_BUS(qbus);
+
+ adb_bus->autopoll_enabled = false;
+ adb_bus->autopoll_mask = 0xffff;
+ adb_bus->autopoll_rate_ms = 20;
+}
+
+static void adb_bus_realize(BusState *qbus, Error **errp)
+{
+ ADBBusState *adb_bus = ADB_BUS(qbus);
+
+ adb_bus->autopoll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, adb_autopoll,
+ adb_bus);
+
+ vmstate_register(NULL, -1, &vmstate_adb_bus, adb_bus);
+}
+
+static void adb_bus_unrealize(BusState *qbus)
+{
+ ADBBusState *adb_bus = ADB_BUS(qbus);
+
+ timer_del(adb_bus->autopoll_timer);
+
+ vmstate_unregister(NULL, &vmstate_adb_bus, adb_bus);
+}
+
+static void adb_bus_class_init(ObjectClass *klass, void *data)
+{
+ BusClass *k = BUS_CLASS(klass);
+
+ k->realize = adb_bus_realize;
+ k->unrealize = adb_bus_unrealize;
+ k->reset = adb_bus_reset;
+}
+
static const TypeInfo adb_bus_type_info = {
.name = TYPE_ADB_BUS,
.parent = TYPE_BUS,
.instance_size = sizeof(ADBBusState),
+ .class_init = adb_bus_class_init,
};
const VMStateDescription vmstate_adb_device = {
@@ -117,18 +298,11 @@ static void adb_device_realizefn(DeviceState *dev, Error **errp)
bus->devices[bus->nb_devices++] = d;
}
-static Property adb_device_properties[] = {
- DEFINE_PROP_BOOL("disable-direct-reg3-writes", ADBDevice,
- disable_direct_reg3_writes, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void adb_device_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = adb_device_realizefn;
- device_class_set_props(dc, adb_device_properties);
dc->bus_type = TYPE_ADB_BUS;
}
diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c
index 60a4130320..29d633ca94 100644
--- a/hw/input/pckbd.c
+++ b/hw/input/pckbd.c
@@ -26,6 +26,7 @@
#include "qemu/log.h"
#include "hw/isa/isa.h"
#include "migration/vmstate.h"
+#include "hw/acpi/aml-build.h"
#include "hw/input/ps2.h"
#include "hw/irq.h"
#include "hw/input/i8042.h"
@@ -561,12 +562,42 @@ static void i8042_realizefn(DeviceState *dev, Error **errp)
qemu_register_reset(kbd_reset, s);
}
+static void i8042_build_aml(ISADevice *isadev, Aml *scope)
+{
+ Aml *kbd;
+ Aml *mou;
+ Aml *crs;
+
+ crs = aml_resource_template();
+ aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01));
+ aml_append(crs, aml_io(AML_DECODE16, 0x0064, 0x0064, 0x01, 0x01));
+ aml_append(crs, aml_irq_no_flags(1));
+
+ kbd = aml_device("KBD");
+ aml_append(kbd, aml_name_decl("_HID", aml_eisaid("PNP0303")));
+ aml_append(kbd, aml_name_decl("_STA", aml_int(0xf)));
+ aml_append(kbd, aml_name_decl("_CRS", crs));
+
+ crs = aml_resource_template();
+ aml_append(crs, aml_irq_no_flags(12));
+
+ mou = aml_device("MOU");
+ aml_append(mou, aml_name_decl("_HID", aml_eisaid("PNP0F13")));
+ aml_append(mou, aml_name_decl("_STA", aml_int(0xf)));
+ aml_append(mou, aml_name_decl("_CRS", crs));
+
+ aml_append(scope, kbd);
+ aml_append(scope, mou);
+}
+
static void i8042_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
dc->realize = i8042_realizefn;
dc->vmsd = &vmstate_kbd_isa;
+ isa->build_aml = i8042_build_aml;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
diff --git a/hw/input/trace-events b/hw/input/trace-events
index a2888fd10c..1dd8ad6018 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -1,18 +1,25 @@
# See docs/devel/tracing.txt for syntax documentation.
# adb-kbd.c
-adb_kbd_no_key(void) "Ignoring NO_KEY"
-adb_kbd_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
-adb_kbd_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
-adb_kbd_request_change_addr(int devaddr) "change addr to 0x%x"
-adb_kbd_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
+adb_device_kbd_no_key(void) "Ignoring NO_KEY"
+adb_device_kbd_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
+adb_device_kbd_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
+adb_device_kbd_request_change_addr(int devaddr) "change addr to 0x%x"
+adb_device_kbd_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
# adb-mouse.c
-adb_mouse_flush(void) "flush"
-adb_mouse_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
-adb_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
-adb_mouse_request_change_addr(int devaddr) "change addr to 0x%x"
-adb_mouse_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
+adb_device_mouse_flush(void) "flush"
+adb_device_mouse_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
+adb_device_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
+adb_device_mouse_request_change_addr(int devaddr) "change addr to 0x%x"
+adb_device_mouse_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
+
+# adb.c
+adb_bus_request(uint8_t addr, const char *cmd, int size) "device 0x%x %s cmdsize=%d"
+adb_bus_request_done(uint8_t addr, const char *cmd, int size) "device 0x%x %s replysize=%d"
+adb_bus_autopoll_block(bool blocked) "blocked: %d"
+adb_bus_autopoll_cb(uint16_t mask) "executing autopoll_cb with autopoll mask 0x%x"
+adb_bus_autopoll_cb_done(uint16_t mask) "done executing autopoll_cb with autopoll mask 0x%x"
# pckbd.c
pckbd_kbd_read_data(uint32_t val) "0x%02x"