diff options
Diffstat (limited to 'hw/input')
-rw-r--r-- | hw/input/adb-kbd.c | 42 | ||||
-rw-r--r-- | hw/input/adb-mouse.c | 65 | ||||
-rw-r--r-- | hw/input/adb.c | 210 | ||||
-rw-r--r-- | hw/input/pckbd.c | 31 | ||||
-rw-r--r-- | hw/input/trace-events | 27 |
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" |