diff options
Diffstat (limited to 'qemu/hw/input')
-rw-r--r-- | qemu/hw/input/Makefile.objs | 19 | ||||
-rw-r--r-- | qemu/hw/input/adb.c | 598 | ||||
-rw-r--r-- | qemu/hw/input/hid.c | 618 | ||||
-rw-r--r-- | qemu/hw/input/lm832x.c | 525 | ||||
-rw-r--r-- | qemu/hw/input/milkymist-softusb.c | 319 | ||||
-rw-r--r-- | qemu/hw/input/pckbd.c | 595 | ||||
-rw-r--r-- | qemu/hw/input/pl050.c | 206 | ||||
-rw-r--r-- | qemu/hw/input/ps2.c | 813 | ||||
-rw-r--r-- | qemu/hw/input/pxa2xx_keypad.c | 335 | ||||
-rw-r--r-- | qemu/hw/input/stellaris_input.c | 88 | ||||
-rw-r--r-- | qemu/hw/input/tsc2005.c | 595 | ||||
-rw-r--r-- | qemu/hw/input/tsc210x.c | 1273 | ||||
-rw-r--r-- | qemu/hw/input/virtio-input-hid.c | 525 | ||||
-rw-r--r-- | qemu/hw/input/virtio-input-host.c | 257 | ||||
-rw-r--r-- | qemu/hw/input/virtio-input.c | 343 | ||||
-rw-r--r-- | qemu/hw/input/vmmouse.c | 304 |
16 files changed, 0 insertions, 7413 deletions
diff --git a/qemu/hw/input/Makefile.objs b/qemu/hw/input/Makefile.objs deleted file mode 100644 index 7715d7230..000000000 --- a/qemu/hw/input/Makefile.objs +++ /dev/null @@ -1,19 +0,0 @@ -common-obj-$(CONFIG_ADB) += adb.o -common-obj-y += hid.o -common-obj-$(CONFIG_LM832X) += lm832x.o -common-obj-$(CONFIG_PCKBD) += pckbd.o -common-obj-$(CONFIG_PL050) += pl050.o -common-obj-y += ps2.o -common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o -common-obj-$(CONFIG_TSC2005) += tsc2005.o -common-obj-$(CONFIG_VMMOUSE) += vmmouse.o - -common-obj-$(CONFIG_VIRTIO) += virtio-input.o -common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o -ifeq ($(CONFIG_LINUX),y) -common-obj-$(CONFIG_VIRTIO) += virtio-input-host.o -endif - -obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o -obj-$(CONFIG_PXA2XX) += pxa2xx_keypad.o -obj-$(CONFIG_TSC210X) += tsc210x.o diff --git a/qemu/hw/input/adb.c b/qemu/hw/input/adb.c deleted file mode 100644 index f0ad0d447..000000000 --- a/qemu/hw/input/adb.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - * QEMU ADB support - * - * Copyright (c) 2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/input/adb.h" -#include "ui/console.h" - -/* debug ADB */ -//#define DEBUG_ADB - -#ifdef DEBUG_ADB -#define ADB_DPRINTF(fmt, ...) \ -do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0) -#else -#define ADB_DPRINTF(fmt, ...) -#endif - -/* ADB commands */ -#define ADB_BUSRESET 0x00 -#define ADB_FLUSH 0x01 -#define ADB_WRITEREG 0x08 -#define ADB_READREG 0x0c - -/* ADB device commands */ -#define ADB_CMD_SELF_TEST 0xff -#define ADB_CMD_CHANGE_ID 0xfe -#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd -#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00 - -/* ADB default device IDs (upper 4 bits of ADB command byte) */ -#define ADB_DEVID_DONGLE 1 -#define ADB_DEVID_KEYBOARD 2 -#define ADB_DEVID_MOUSE 3 -#define ADB_DEVID_TABLET 4 -#define ADB_DEVID_MODEM 5 -#define ADB_DEVID_MISC 7 - -/* error codes */ -#define ADB_RET_NOTPRESENT (-2) - -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) -{ - ADBDevice *d; - int devaddr, cmd, i; - - cmd = buf[0] & 0xf; - if (cmd == ADB_BUSRESET) { - for(i = 0; i < s->nb_devices; i++) { - d = s->devices[i]; - adb_device_reset(d); - } - return 0; - } - devaddr = buf[0] >> 4; - for(i = 0; i < s->nb_devices; i++) { - d = s->devices[i]; - if (d->devaddr == devaddr) { - ADBDeviceClass *adc = ADB_DEVICE_GET_CLASS(d); - return adc->devreq(d, obuf, buf, len); - } - } - return ADB_RET_NOTPRESENT; -} - -/* XXX: move that to cuda ? */ -int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask) -{ - ADBDevice *d; - int olen, i; - uint8_t buf[1]; - - olen = 0; - 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); - /* if there is data, we poll again the same device */ - if (olen > 0) { - obuf[0] = buf[0]; - olen++; - break; - } - } - s->poll_index++; - } - return olen; -} - -static const TypeInfo adb_bus_type_info = { - .name = TYPE_ADB_BUS, - .parent = TYPE_BUS, - .instance_size = sizeof(ADBBusState), -}; - -static const VMStateDescription vmstate_adb_device = { - .name = "adb_device", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_INT32(devaddr, ADBDevice), - VMSTATE_INT32(handler, ADBDevice), - VMSTATE_END_OF_LIST() - } -}; - -static void adb_device_realizefn(DeviceState *dev, Error **errp) -{ - ADBDevice *d = ADB_DEVICE(dev); - ADBBusState *bus = ADB_BUS(qdev_get_parent_bus(dev)); - - if (bus->nb_devices >= MAX_ADB_DEVICES) { - return; - } - - bus->devices[bus->nb_devices++] = d; -} - -static void adb_device_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = adb_device_realizefn; - dc->bus_type = TYPE_ADB_BUS; -} - -static const TypeInfo adb_device_type_info = { - .name = TYPE_ADB_DEVICE, - .parent = TYPE_DEVICE, - .instance_size = sizeof(ADBDevice), - .abstract = true, - .class_init = adb_device_class_init, -}; - -/***************************************************************/ -/* Keyboard ADB device */ - -#define ADB_KEYBOARD(obj) OBJECT_CHECK(KBDState, (obj), TYPE_ADB_KEYBOARD) - -typedef struct KBDState { - /*< private >*/ - ADBDevice parent_obj; - /*< public >*/ - - uint8_t data[128]; - int rptr, wptr, count; -} KBDState; - -#define ADB_KEYBOARD_CLASS(class) \ - OBJECT_CLASS_CHECK(ADBKeyboardClass, (class), TYPE_ADB_KEYBOARD) -#define ADB_KEYBOARD_GET_CLASS(obj) \ - OBJECT_GET_CLASS(ADBKeyboardClass, (obj), TYPE_ADB_KEYBOARD) - -typedef struct ADBKeyboardClass { - /*< private >*/ - ADBDeviceClass parent_class; - /*< public >*/ - - DeviceRealize parent_realize; -} ADBKeyboardClass; - -static const uint8_t pc_to_adb_keycode[256] = { - 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, - 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1, - 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, - 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, - 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, - 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0,110, 81, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,125, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 75, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,115, 62,116, 0, 59, 0, 60, 0,119, - 61,121,114,117, 0, 0, 0, 0, 0, 0, 0, 55,126, 0,127, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static void adb_kbd_put_keycode(void *opaque, int keycode) -{ - KBDState *s = opaque; - - if (s->count < sizeof(s->data)) { - s->data[s->wptr] = keycode; - if (++s->wptr == sizeof(s->data)) - s->wptr = 0; - s->count++; - } -} - -static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) -{ - static int ext_keycode; - KBDState *s = ADB_KEYBOARD(d); - int adb_keycode, keycode; - int olen; - - olen = 0; - for(;;) { - if (s->count == 0) - break; - keycode = s->data[s->rptr]; - if (++s->rptr == sizeof(s->data)) - s->rptr = 0; - s->count--; - - if (keycode == 0xe0) { - ext_keycode = 1; - } else { - if (ext_keycode) - adb_keycode = pc_to_adb_keycode[keycode | 0x80]; - else - adb_keycode = pc_to_adb_keycode[keycode & 0x7f]; - obuf[0] = adb_keycode | (keycode & 0x80); - /* NOTE: could put a second keycode if needed */ - obuf[1] = 0xff; - olen = 2; - ext_keycode = 0; - break; - } - } - return olen; -} - -static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, - const uint8_t *buf, int len) -{ - KBDState *s = ADB_KEYBOARD(d); - int cmd, reg, olen; - - if ((buf[0] & 0x0f) == ADB_FLUSH) { - /* flush keyboard fifo */ - s->wptr = s->rptr = s->count = 0; - return 0; - } - - cmd = buf[0] & 0xc; - reg = buf[0] & 0x3; - olen = 0; - switch(cmd) { - case ADB_WRITEREG: - switch(reg) { - case 2: - /* LED status */ - break; - case 3: - switch(buf[2]) { - case ADB_CMD_SELF_TEST: - break; - case ADB_CMD_CHANGE_ID: - case ADB_CMD_CHANGE_ID_AND_ACT: - case ADB_CMD_CHANGE_ID_AND_ENABLE: - d->devaddr = buf[1] & 0xf; - break; - default: - /* XXX: check this */ - d->devaddr = buf[1] & 0xf; - d->handler = buf[2]; - break; - } - } - break; - case ADB_READREG: - switch(reg) { - case 0: - olen = adb_kbd_poll(d, obuf); - break; - case 1: - break; - case 2: - obuf[0] = 0x00; /* XXX: check this */ - obuf[1] = 0x07; /* led status */ - olen = 2; - break; - case 3: - obuf[0] = d->handler; - obuf[1] = d->devaddr; - olen = 2; - break; - } - break; - } - return olen; -} - -static const VMStateDescription vmstate_adb_kbd = { - .name = "adb_kbd", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(parent_obj, KBDState, 0, vmstate_adb_device, ADBDevice), - VMSTATE_BUFFER(data, KBDState), - VMSTATE_INT32(rptr, KBDState), - VMSTATE_INT32(wptr, KBDState), - VMSTATE_INT32(count, KBDState), - VMSTATE_END_OF_LIST() - } -}; - -static void adb_kbd_reset(DeviceState *dev) -{ - ADBDevice *d = ADB_DEVICE(dev); - KBDState *s = ADB_KEYBOARD(dev); - - d->handler = 1; - d->devaddr = ADB_DEVID_KEYBOARD; - memset(s->data, 0, sizeof(s->data)); - s->rptr = 0; - s->wptr = 0; - s->count = 0; -} - -static void adb_kbd_realizefn(DeviceState *dev, Error **errp) -{ - ADBDevice *d = ADB_DEVICE(dev); - ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev); - - akc->parent_realize(dev, errp); - - qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); -} - -static void adb_kbd_initfn(Object *obj) -{ - ADBDevice *d = ADB_DEVICE(obj); - - d->devaddr = ADB_DEVID_KEYBOARD; -} - -static void adb_kbd_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); - ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc); - - akc->parent_realize = dc->realize; - dc->realize = adb_kbd_realizefn; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - - adc->devreq = adb_kbd_request; - dc->reset = adb_kbd_reset; - dc->vmsd = &vmstate_adb_kbd; -} - -static const TypeInfo adb_kbd_type_info = { - .name = TYPE_ADB_KEYBOARD, - .parent = TYPE_ADB_DEVICE, - .instance_size = sizeof(KBDState), - .instance_init = adb_kbd_initfn, - .class_init = adb_kbd_class_init, - .class_size = sizeof(ADBKeyboardClass), -}; - -/***************************************************************/ -/* Mouse ADB device */ - -#define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE) - -typedef struct MouseState { - /*< public >*/ - ADBDevice parent_obj; - /*< private >*/ - - int buttons_state, last_buttons_state; - int dx, dy, dz; -} MouseState; - -#define ADB_MOUSE_CLASS(class) \ - OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE) -#define ADB_MOUSE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE) - -typedef struct ADBMouseClass { - /*< public >*/ - ADBDeviceClass parent_class; - /*< private >*/ - - DeviceRealize parent_realize; -} ADBMouseClass; - -static void adb_mouse_event(void *opaque, - int dx1, int dy1, int dz1, int buttons_state) -{ - MouseState *s = opaque; - - s->dx += dx1; - s->dy += dy1; - s->dz += dz1; - s->buttons_state = buttons_state; -} - - -static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) -{ - MouseState *s = ADB_MOUSE(d); - int dx, dy; - - if (s->last_buttons_state == s->buttons_state && - s->dx == 0 && s->dy == 0) - return 0; - - dx = s->dx; - if (dx < -63) - dx = -63; - else if (dx > 63) - dx = 63; - - dy = s->dy; - if (dy < -63) - dy = -63; - else if (dy > 63) - dy = 63; - - s->dx -= dx; - s->dy -= dy; - s->last_buttons_state = s->buttons_state; - - dx &= 0x7f; - dy &= 0x7f; - - if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) - dy |= 0x80; - if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) - dx |= 0x80; - - obuf[0] = dy; - obuf[1] = dx; - return 2; -} - -static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, - const uint8_t *buf, int len) -{ - MouseState *s = ADB_MOUSE(d); - int cmd, reg, olen; - - if ((buf[0] & 0x0f) == ADB_FLUSH) { - /* flush mouse fifo */ - s->buttons_state = s->last_buttons_state; - s->dx = 0; - s->dy = 0; - s->dz = 0; - return 0; - } - - cmd = buf[0] & 0xc; - reg = buf[0] & 0x3; - olen = 0; - switch(cmd) { - case ADB_WRITEREG: - ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]); - switch(reg) { - case 2: - break; - case 3: - switch(buf[2]) { - case ADB_CMD_SELF_TEST: - break; - case ADB_CMD_CHANGE_ID: - case ADB_CMD_CHANGE_ID_AND_ACT: - case ADB_CMD_CHANGE_ID_AND_ENABLE: - d->devaddr = buf[1] & 0xf; - break; - default: - /* XXX: check this */ - d->devaddr = buf[1] & 0xf; - break; - } - } - break; - case ADB_READREG: - switch(reg) { - case 0: - olen = adb_mouse_poll(d, obuf); - break; - case 1: - break; - case 3: - obuf[0] = d->handler; - obuf[1] = d->devaddr; - olen = 2; - break; - } - ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg, - obuf[0], obuf[1]); - break; - } - return olen; -} - -static void adb_mouse_reset(DeviceState *dev) -{ - ADBDevice *d = ADB_DEVICE(dev); - MouseState *s = ADB_MOUSE(dev); - - d->handler = 2; - d->devaddr = ADB_DEVID_MOUSE; - s->last_buttons_state = s->buttons_state = 0; - s->dx = s->dy = s->dz = 0; -} - -static const VMStateDescription vmstate_adb_mouse = { - .name = "adb_mouse", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device, - ADBDevice), - VMSTATE_INT32(buttons_state, MouseState), - VMSTATE_INT32(last_buttons_state, MouseState), - VMSTATE_INT32(dx, MouseState), - VMSTATE_INT32(dy, MouseState), - VMSTATE_INT32(dz, MouseState), - VMSTATE_END_OF_LIST() - } -}; - -static void adb_mouse_realizefn(DeviceState *dev, Error **errp) -{ - MouseState *s = ADB_MOUSE(dev); - ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev); - - amc->parent_realize(dev, errp); - - qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse"); -} - -static void adb_mouse_initfn(Object *obj) -{ - ADBDevice *d = ADB_DEVICE(obj); - - d->devaddr = ADB_DEVID_MOUSE; -} - -static void adb_mouse_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); - ADBMouseClass *amc = ADB_MOUSE_CLASS(oc); - - amc->parent_realize = dc->realize; - dc->realize = adb_mouse_realizefn; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - - adc->devreq = adb_mouse_request; - dc->reset = adb_mouse_reset; - dc->vmsd = &vmstate_adb_mouse; -} - -static const TypeInfo adb_mouse_type_info = { - .name = TYPE_ADB_MOUSE, - .parent = TYPE_ADB_DEVICE, - .instance_size = sizeof(MouseState), - .instance_init = adb_mouse_initfn, - .class_init = adb_mouse_class_init, - .class_size = sizeof(ADBMouseClass), -}; - - -static void adb_register_types(void) -{ - type_register_static(&adb_bus_type_info); - type_register_static(&adb_device_type_info); - type_register_static(&adb_kbd_type_info); - type_register_static(&adb_mouse_type_info); -} - -type_init(adb_register_types) diff --git a/qemu/hw/input/hid.c b/qemu/hw/input/hid.c deleted file mode 100644 index d92c7463b..000000000 --- a/qemu/hw/input/hid.c +++ /dev/null @@ -1,618 +0,0 @@ -/* - * QEMU HID devices - * - * Copyright (c) 2005 Fabrice Bellard - * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "ui/console.h" -#include "qemu/timer.h" -#include "hw/input/hid.h" - -#define HID_USAGE_ERROR_ROLLOVER 0x01 -#define HID_USAGE_POSTFAIL 0x02 -#define HID_USAGE_ERROR_UNDEFINED 0x03 - -/* Indices are QEMU keycodes, values are from HID Usage Table. Indices - * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */ -static const uint8_t hid_usage_keys[0x100] = { - 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, - 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, - 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, - 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, - 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, - 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, - 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, - 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, - 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, - 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x64, 0x44, - 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, - 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, - 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a, - 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, - 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -bool hid_has_events(HIDState *hs) -{ - return hs->n > 0 || hs->idle_pending; -} - -static void hid_idle_timer(void *opaque) -{ - HIDState *hs = opaque; - - hs->idle_pending = true; - hs->event(hs); -} - -static void hid_del_idle_timer(HIDState *hs) -{ - if (hs->idle_timer) { - timer_del(hs->idle_timer); - timer_free(hs->idle_timer); - hs->idle_timer = NULL; - } -} - -void hid_set_next_idle(HIDState *hs) -{ - if (hs->idle) { - uint64_t expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - NANOSECONDS_PER_SECOND * hs->idle * 4 / 1000; - if (!hs->idle_timer) { - hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs); - } - timer_mod_ns(hs->idle_timer, expire_time); - } else { - hid_del_idle_timer(hs); - } -} - -static void hid_pointer_event(DeviceState *dev, QemuConsole *src, - InputEvent *evt) -{ - static const int bmap[INPUT_BUTTON__MAX] = { - [INPUT_BUTTON_LEFT] = 0x01, - [INPUT_BUTTON_RIGHT] = 0x02, - [INPUT_BUTTON_MIDDLE] = 0x04, - }; - HIDState *hs = (HIDState *)dev; - HIDPointerEvent *e; - InputMoveEvent *move; - InputBtnEvent *btn; - - assert(hs->n < QUEUE_LENGTH); - e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; - - switch (evt->type) { - case INPUT_EVENT_KIND_REL: - move = evt->u.rel.data; - if (move->axis == INPUT_AXIS_X) { - e->xdx += move->value; - } else if (move->axis == INPUT_AXIS_Y) { - e->ydy += move->value; - } - break; - - case INPUT_EVENT_KIND_ABS: - move = evt->u.abs.data; - if (move->axis == INPUT_AXIS_X) { - e->xdx = move->value; - } else if (move->axis == INPUT_AXIS_Y) { - e->ydy = move->value; - } - break; - - case INPUT_EVENT_KIND_BTN: - btn = evt->u.btn.data; - if (btn->down) { - e->buttons_state |= bmap[btn->button]; - if (btn->button == INPUT_BUTTON_WHEEL_UP) { - e->dz--; - } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { - e->dz++; - } - } else { - e->buttons_state &= ~bmap[btn->button]; - } - break; - - default: - /* keep gcc happy */ - break; - } - -} - -static void hid_pointer_sync(DeviceState *dev) -{ - HIDState *hs = (HIDState *)dev; - HIDPointerEvent *prev, *curr, *next; - bool event_compression = false; - - if (hs->n == QUEUE_LENGTH-1) { - /* - * Queue full. We are losing information, but we at least - * keep track of most recent button state. - */ - return; - } - - prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK]; - curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; - next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK]; - - if (hs->n > 0) { - /* - * No button state change between previous and current event - * (and previous wasn't seen by the guest yet), so there is - * motion information only and we can combine the two event - * into one. - */ - if (curr->buttons_state == prev->buttons_state) { - event_compression = true; - } - } - - if (event_compression) { - /* add current motion to previous, clear current */ - if (hs->kind == HID_MOUSE) { - prev->xdx += curr->xdx; - curr->xdx = 0; - prev->ydy += curr->ydy; - curr->ydy = 0; - } else { - prev->xdx = curr->xdx; - prev->ydy = curr->ydy; - } - prev->dz += curr->dz; - curr->dz = 0; - } else { - /* prepate next (clear rel, copy abs + btns) */ - if (hs->kind == HID_MOUSE) { - next->xdx = 0; - next->ydy = 0; - } else { - next->xdx = curr->xdx; - next->ydy = curr->ydy; - } - next->dz = 0; - next->buttons_state = curr->buttons_state; - /* make current guest visible, notify guest */ - hs->n++; - hs->event(hs); - } -} - -static void hid_keyboard_event(DeviceState *dev, QemuConsole *src, - InputEvent *evt) -{ - HIDState *hs = (HIDState *)dev; - int scancodes[3], i, count; - int slot; - InputKeyEvent *key = evt->u.key.data; - - count = qemu_input_key_value_to_scancode(key->key, - key->down, - scancodes); - if (hs->n + count > QUEUE_LENGTH) { - fprintf(stderr, "usb-kbd: warning: key event queue full\n"); - return; - } - for (i = 0; i < count; i++) { - slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; - hs->kbd.keycodes[slot] = scancodes[i]; - } - hs->event(hs); -} - -static void hid_keyboard_process_keycode(HIDState *hs) -{ - uint8_t hid_code, index, key; - int i, keycode, slot; - - if (hs->n == 0) { - return; - } - slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--; - keycode = hs->kbd.keycodes[slot]; - - key = keycode & 0x7f; - index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1); - hid_code = hid_usage_keys[index]; - hs->kbd.modifiers &= ~(1 << 8); - - switch (hid_code) { - case 0x00: - return; - - case 0xe0: - assert(key == 0x1d); - if (hs->kbd.modifiers & (1 << 9)) { - /* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0. - * Here we're processing the second hid_code. By dropping bit 9 - * and setting bit 8, the scancode after 0x1d will access the - * second half of the table. - */ - hs->kbd.modifiers ^= (1 << 8) | (1 << 9); - return; - } - /* fall through to process Ctrl_L */ - case 0xe1 ... 0xe7: - /* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R. - * Handle releases here, or fall through to process presses. - */ - if (keycode & (1 << 7)) { - hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f)); - return; - } - /* fall through */ - case 0xe8 ... 0xe9: - /* USB modifiers are just 1 byte long. Bits 8 and 9 of - * hs->kbd.modifiers implement a state machine that detects the - * 0xe0 and 0xe1/0x1d sequences. These bits do not follow the - * usual rules where bit 7 marks released keys; they are cleared - * elsewhere in the function as the state machine dictates. - */ - hs->kbd.modifiers |= 1 << (hid_code & 0x0f); - return; - - case 0xea ... 0xef: - abort(); - - default: - break; - } - - if (keycode & (1 << 7)) { - for (i = hs->kbd.keys - 1; i >= 0; i--) { - if (hs->kbd.key[i] == hid_code) { - hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys]; - hs->kbd.key[hs->kbd.keys] = 0x00; - break; - } - } - if (i < 0) { - return; - } - } else { - for (i = hs->kbd.keys - 1; i >= 0; i--) { - if (hs->kbd.key[i] == hid_code) { - break; - } - } - if (i < 0) { - if (hs->kbd.keys < sizeof(hs->kbd.key)) { - hs->kbd.key[hs->kbd.keys++] = hid_code; - } - } else { - return; - } - } -} - -static inline int int_clamp(int val, int vmin, int vmax) -{ - if (val < vmin) { - return vmin; - } else if (val > vmax) { - return vmax; - } else { - return val; - } -} - -void hid_pointer_activate(HIDState *hs) -{ - if (!hs->ptr.mouse_grabbed) { - qemu_input_handler_activate(hs->s); - hs->ptr.mouse_grabbed = 1; - } -} - -int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) -{ - int dx, dy, dz, l; - int index; - HIDPointerEvent *e; - - hs->idle_pending = false; - - hid_pointer_activate(hs); - - /* When the buffer is empty, return the last event. Relative - movements will all be zero. */ - index = (hs->n ? hs->head : hs->head - 1); - e = &hs->ptr.queue[index & QUEUE_MASK]; - - if (hs->kind == HID_MOUSE) { - dx = int_clamp(e->xdx, -127, 127); - dy = int_clamp(e->ydy, -127, 127); - e->xdx -= dx; - e->ydy -= dy; - } else { - dx = e->xdx; - dy = e->ydy; - } - dz = int_clamp(e->dz, -127, 127); - e->dz -= dz; - - if (hs->n && - !e->dz && - (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { - /* that deals with this event */ - QUEUE_INCR(hs->head); - hs->n--; - } - - /* Appears we have to invert the wheel direction */ - dz = 0 - dz; - l = 0; - switch (hs->kind) { - case HID_MOUSE: - if (len > l) { - buf[l++] = e->buttons_state; - } - if (len > l) { - buf[l++] = dx; - } - if (len > l) { - buf[l++] = dy; - } - if (len > l) { - buf[l++] = dz; - } - break; - - case HID_TABLET: - if (len > l) { - buf[l++] = e->buttons_state; - } - if (len > l) { - buf[l++] = dx & 0xff; - } - if (len > l) { - buf[l++] = dx >> 8; - } - if (len > l) { - buf[l++] = dy & 0xff; - } - if (len > l) { - buf[l++] = dy >> 8; - } - if (len > l) { - buf[l++] = dz; - } - break; - - default: - abort(); - } - - return l; -} - -int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) -{ - hs->idle_pending = false; - - if (len < 2) { - return 0; - } - - hid_keyboard_process_keycode(hs); - - buf[0] = hs->kbd.modifiers & 0xff; - buf[1] = 0; - if (hs->kbd.keys > 6) { - memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); - } else { - memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2); - } - - return MIN(8, len); -} - -int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len) -{ - if (len > 0) { - int ledstate = 0; - /* 0x01: Num Lock LED - * 0x02: Caps Lock LED - * 0x04: Scroll Lock LED - * 0x08: Compose LED - * 0x10: Kana LED */ - hs->kbd.leds = buf[0]; - if (hs->kbd.leds & 0x04) { - ledstate |= QEMU_SCROLL_LOCK_LED; - } - if (hs->kbd.leds & 0x01) { - ledstate |= QEMU_NUM_LOCK_LED; - } - if (hs->kbd.leds & 0x02) { - ledstate |= QEMU_CAPS_LOCK_LED; - } - kbd_put_ledstate(ledstate); - } - return 0; -} - -void hid_reset(HIDState *hs) -{ - switch (hs->kind) { - case HID_KEYBOARD: - memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes)); - memset(hs->kbd.key, 0, sizeof(hs->kbd.key)); - hs->kbd.keys = 0; - break; - case HID_MOUSE: - case HID_TABLET: - memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue)); - break; - } - hs->head = 0; - hs->n = 0; - hs->protocol = 1; - hs->idle = 0; - hs->idle_pending = false; - hid_del_idle_timer(hs); -} - -void hid_free(HIDState *hs) -{ - qemu_input_handler_unregister(hs->s); - hid_del_idle_timer(hs); -} - -static QemuInputHandler hid_keyboard_handler = { - .name = "QEMU HID Keyboard", - .mask = INPUT_EVENT_MASK_KEY, - .event = hid_keyboard_event, -}; - -static QemuInputHandler hid_mouse_handler = { - .name = "QEMU HID Mouse", - .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, - .event = hid_pointer_event, - .sync = hid_pointer_sync, -}; - -static QemuInputHandler hid_tablet_handler = { - .name = "QEMU HID Tablet", - .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, - .event = hid_pointer_event, - .sync = hid_pointer_sync, -}; - -void hid_init(HIDState *hs, int kind, HIDEventFunc event) -{ - hs->kind = kind; - hs->event = event; - - if (hs->kind == HID_KEYBOARD) { - hs->s = qemu_input_handler_register((DeviceState *)hs, - &hid_keyboard_handler); - qemu_input_handler_activate(hs->s); - } else if (hs->kind == HID_MOUSE) { - hs->s = qemu_input_handler_register((DeviceState *)hs, - &hid_mouse_handler); - } else if (hs->kind == HID_TABLET) { - hs->s = qemu_input_handler_register((DeviceState *)hs, - &hid_tablet_handler); - } -} - -static int hid_post_load(void *opaque, int version_id) -{ - HIDState *s = opaque; - - hid_set_next_idle(s); - - if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET || - s->kind == HID_MOUSE)) { - /* - * Handle ptr device migration from old qemu with full queue. - * - * Throw away everything but the last event, so we propagate - * at least the current button state to the guest. Also keep - * current position for the tablet, signal "no motion" for the - * mouse. - */ - HIDPointerEvent evt; - evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK]; - if (s->kind == HID_MOUSE) { - evt.xdx = 0; - evt.ydy = 0; - } - s->ptr.queue[0] = evt; - s->head = 0; - s->n = 1; - } - return 0; -} - -static const VMStateDescription vmstate_hid_ptr_queue = { - .name = "HIDPointerEventQueue", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(xdx, HIDPointerEvent), - VMSTATE_INT32(ydy, HIDPointerEvent), - VMSTATE_INT32(dz, HIDPointerEvent), - VMSTATE_INT32(buttons_state, HIDPointerEvent), - VMSTATE_END_OF_LIST() - } -}; - -const VMStateDescription vmstate_hid_ptr_device = { - .name = "HIDPointerDevice", - .version_id = 1, - .minimum_version_id = 1, - .post_load = hid_post_load, - .fields = (VMStateField[]) { - VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0, - vmstate_hid_ptr_queue, HIDPointerEvent), - VMSTATE_UINT32(head, HIDState), - VMSTATE_UINT32(n, HIDState), - VMSTATE_INT32(protocol, HIDState), - VMSTATE_UINT8(idle, HIDState), - VMSTATE_END_OF_LIST(), - } -}; - -const VMStateDescription vmstate_hid_keyboard_device = { - .name = "HIDKeyboardDevice", - .version_id = 1, - .minimum_version_id = 1, - .post_load = hid_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH), - VMSTATE_UINT32(head, HIDState), - VMSTATE_UINT32(n, HIDState), - VMSTATE_UINT16(kbd.modifiers, HIDState), - VMSTATE_UINT8(kbd.leds, HIDState), - VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16), - VMSTATE_INT32(kbd.keys, HIDState), - VMSTATE_INT32(protocol, HIDState), - VMSTATE_UINT8(idle, HIDState), - VMSTATE_END_OF_LIST(), - } -}; diff --git a/qemu/hw/input/lm832x.c b/qemu/hw/input/lm832x.c deleted file mode 100644 index 539682cac..000000000 --- a/qemu/hw/input/lm832x.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * National Semiconductor LM8322/8323 GPIO keyboard & PWM chips. - * - * Copyright (C) 2008 Nokia Corporation - * Written by Andrzej Zaborowski <andrew@openedhand.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i2c/i2c.h" -#include "qemu/timer.h" -#include "ui/console.h" - -#define TYPE_LM8323 "lm8323" -#define LM8323(obj) OBJECT_CHECK(LM823KbdState, (obj), TYPE_LM8323) - -typedef struct { - I2CSlave parent_obj; - - uint8_t i2c_dir; - uint8_t i2c_cycle; - uint8_t reg; - - qemu_irq nirq; - uint16_t model; - - struct { - qemu_irq out[2]; - int in[2][2]; - } mux; - - uint8_t config; - uint8_t status; - uint8_t acttime; - uint8_t error; - uint8_t clock; - - struct { - uint16_t pull; - uint16_t mask; - uint16_t dir; - uint16_t level; - qemu_irq out[16]; - } gpio; - - struct { - uint8_t dbnctime; - uint8_t size; - uint8_t start; - uint8_t len; - uint8_t fifo[16]; - } kbd; - - struct { - uint16_t file[256]; - uint8_t faddr; - uint8_t addr[3]; - QEMUTimer *tm[3]; - } pwm; -} LM823KbdState; - -#define INT_KEYPAD (1 << 0) -#define INT_ERROR (1 << 3) -#define INT_NOINIT (1 << 4) -#define INT_PWMEND(n) (1 << (5 + n)) - -#define ERR_BADPAR (1 << 0) -#define ERR_CMDUNK (1 << 1) -#define ERR_KEYOVR (1 << 2) -#define ERR_FIFOOVR (1 << 6) - -static void lm_kbd_irq_update(LM823KbdState *s) -{ - qemu_set_irq(s->nirq, !s->status); -} - -static void lm_kbd_gpio_update(LM823KbdState *s) -{ -} - -static void lm_kbd_reset(LM823KbdState *s) -{ - s->config = 0x80; - s->status = INT_NOINIT; - s->acttime = 125; - s->kbd.dbnctime = 3; - s->kbd.size = 0x33; - s->clock = 0x08; - - lm_kbd_irq_update(s); - lm_kbd_gpio_update(s); -} - -static void lm_kbd_error(LM823KbdState *s, int err) -{ - s->error |= err; - s->status |= INT_ERROR; - lm_kbd_irq_update(s); -} - -static void lm_kbd_pwm_tick(LM823KbdState *s, int line) -{ -} - -static void lm_kbd_pwm_start(LM823KbdState *s, int line) -{ - lm_kbd_pwm_tick(s, line); -} - -static void lm_kbd_pwm0_tick(void *opaque) -{ - lm_kbd_pwm_tick(opaque, 0); -} -static void lm_kbd_pwm1_tick(void *opaque) -{ - lm_kbd_pwm_tick(opaque, 1); -} -static void lm_kbd_pwm2_tick(void *opaque) -{ - lm_kbd_pwm_tick(opaque, 2); -} - -enum { - LM832x_CMD_READ_ID = 0x80, /* Read chip ID. */ - LM832x_CMD_WRITE_CFG = 0x81, /* Set configuration item. */ - LM832x_CMD_READ_INT = 0x82, /* Get interrupt status. */ - LM832x_CMD_RESET = 0x83, /* Reset, same as external one */ - LM823x_CMD_WRITE_PULL_DOWN = 0x84, /* Select GPIO pull-up/down. */ - LM832x_CMD_WRITE_PORT_SEL = 0x85, /* Select GPIO in/out. */ - LM832x_CMD_WRITE_PORT_STATE = 0x86, /* Set GPIO pull-up/down. */ - LM832x_CMD_READ_PORT_SEL = 0x87, /* Get GPIO in/out. */ - LM832x_CMD_READ_PORT_STATE = 0x88, /* Get GPIO pull-up/down. */ - LM832x_CMD_READ_FIFO = 0x89, /* Read byte from FIFO. */ - LM832x_CMD_RPT_READ_FIFO = 0x8a, /* Read FIFO (no increment). */ - LM832x_CMD_SET_ACTIVE = 0x8b, /* Set active time. */ - LM832x_CMD_READ_ERROR = 0x8c, /* Get error status. */ - LM832x_CMD_READ_ROTATOR = 0x8e, /* Read rotator status. */ - LM832x_CMD_SET_DEBOUNCE = 0x8f, /* Set debouncing time. */ - LM832x_CMD_SET_KEY_SIZE = 0x90, /* Set keypad size. */ - LM832x_CMD_READ_KEY_SIZE = 0x91, /* Get keypad size. */ - LM832x_CMD_READ_CFG = 0x92, /* Get configuration item. */ - LM832x_CMD_WRITE_CLOCK = 0x93, /* Set clock config. */ - LM832x_CMD_READ_CLOCK = 0x94, /* Get clock config. */ - LM832x_CMD_PWM_WRITE = 0x95, /* Write PWM script. */ - LM832x_CMD_PWM_START = 0x96, /* Start PWM engine. */ - LM832x_CMD_PWM_STOP = 0x97, /* Stop PWM engine. */ - LM832x_GENERAL_ERROR = 0xff, /* There was one error. - Previously was represented by -1 - This is not a command */ -}; - -#define LM832x_MAX_KPX 8 -#define LM832x_MAX_KPY 12 - -static uint8_t lm_kbd_read(LM823KbdState *s, int reg, int byte) -{ - int ret; - - switch (reg) { - case LM832x_CMD_READ_ID: - ret = 0x0400; - break; - - case LM832x_CMD_READ_INT: - ret = s->status; - if (!(s->status & INT_NOINIT)) { - s->status = 0; - lm_kbd_irq_update(s); - } - break; - - case LM832x_CMD_READ_PORT_SEL: - ret = s->gpio.dir; - break; - case LM832x_CMD_READ_PORT_STATE: - ret = s->gpio.mask; - break; - - case LM832x_CMD_READ_FIFO: - if (s->kbd.len <= 1) - return 0x00; - - /* Example response from the two commands after a INT_KEYPAD - * interrupt caused by the key 0x3c being pressed: - * RPT_READ_FIFO: 55 bc 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01 - * READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01 - * RPT_READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01 - * - * 55 is the code of the key release event serviced in the previous - * interrupt handling. - * - * TODO: find out whether the FIFO is advanced a single character - * before reading every byte or the whole size of the FIFO at the - * last LM832x_CMD_READ_FIFO. This affects LM832x_CMD_RPT_READ_FIFO - * output in cases where there are more than one event in the FIFO. - * Assume 0xbc and 0x3c events are in the FIFO: - * RPT_READ_FIFO: 55 bc 3c 00 4e ff 0a 50 08 00 29 d9 08 01 c9 - * READ_FIFO: bc 3c 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 - * Does RPT_READ_FIFO now return 0xbc and 0x3c or only 0x3c? - */ - s->kbd.start ++; - s->kbd.start &= sizeof(s->kbd.fifo) - 1; - s->kbd.len --; - - return s->kbd.fifo[s->kbd.start]; - case LM832x_CMD_RPT_READ_FIFO: - if (byte >= s->kbd.len) - return 0x00; - - return s->kbd.fifo[(s->kbd.start + byte) & (sizeof(s->kbd.fifo) - 1)]; - - case LM832x_CMD_READ_ERROR: - return s->error; - - case LM832x_CMD_READ_ROTATOR: - return 0; - - case LM832x_CMD_READ_KEY_SIZE: - return s->kbd.size; - - case LM832x_CMD_READ_CFG: - return s->config & 0xf; - - case LM832x_CMD_READ_CLOCK: - return (s->clock & 0xfc) | 2; - - default: - lm_kbd_error(s, ERR_CMDUNK); - fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg); - return 0x00; - } - - return ret >> (byte << 3); -} - -static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value) -{ - switch (reg) { - case LM832x_CMD_WRITE_CFG: - s->config = value; - /* This must be done whenever s->mux.in is updated (never). */ - if ((s->config >> 1) & 1) /* MUX1EN */ - qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 0) & 1]); - if ((s->config >> 3) & 1) /* MUX2EN */ - qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 2) & 1]); - /* TODO: check that this is issued only following the chip reset - * and not in the middle of operation and that it is followed by - * the GPIO ports re-resablishing through WRITE_PORT_SEL and - * WRITE_PORT_STATE (using a timer perhaps) and otherwise output - * warnings. */ - s->status = 0; - lm_kbd_irq_update(s); - s->kbd.len = 0; - s->kbd.start = 0; - s->reg = LM832x_GENERAL_ERROR; - break; - - case LM832x_CMD_RESET: - if (value == 0xaa) - lm_kbd_reset(s); - else - lm_kbd_error(s, ERR_BADPAR); - s->reg = LM832x_GENERAL_ERROR; - break; - - case LM823x_CMD_WRITE_PULL_DOWN: - if (!byte) - s->gpio.pull = value; - else { - s->gpio.pull |= value << 8; - lm_kbd_gpio_update(s); - s->reg = LM832x_GENERAL_ERROR; - } - break; - case LM832x_CMD_WRITE_PORT_SEL: - if (!byte) - s->gpio.dir = value; - else { - s->gpio.dir |= value << 8; - lm_kbd_gpio_update(s); - s->reg = LM832x_GENERAL_ERROR; - } - break; - case LM832x_CMD_WRITE_PORT_STATE: - if (!byte) - s->gpio.mask = value; - else { - s->gpio.mask |= value << 8; - lm_kbd_gpio_update(s); - s->reg = LM832x_GENERAL_ERROR; - } - break; - - case LM832x_CMD_SET_ACTIVE: - s->acttime = value; - s->reg = LM832x_GENERAL_ERROR; - break; - - case LM832x_CMD_SET_DEBOUNCE: - s->kbd.dbnctime = value; - s->reg = LM832x_GENERAL_ERROR; - if (!value) - lm_kbd_error(s, ERR_BADPAR); - break; - - case LM832x_CMD_SET_KEY_SIZE: - s->kbd.size = value; - s->reg = LM832x_GENERAL_ERROR; - if ( - (value & 0xf) < 3 || (value & 0xf) > LM832x_MAX_KPY || - (value >> 4) < 3 || (value >> 4) > LM832x_MAX_KPX) - lm_kbd_error(s, ERR_BADPAR); - break; - - case LM832x_CMD_WRITE_CLOCK: - s->clock = value; - s->reg = LM832x_GENERAL_ERROR; - if ((value & 3) && (value & 3) != 3) { - lm_kbd_error(s, ERR_BADPAR); - fprintf(stderr, "%s: invalid clock setting in RCPWM\n", - __FUNCTION__); - } - /* TODO: Validate that the command is only issued once */ - break; - - case LM832x_CMD_PWM_WRITE: - if (byte == 0) { - if (!(value & 3) || (value >> 2) > 59) { - lm_kbd_error(s, ERR_BADPAR); - s->reg = LM832x_GENERAL_ERROR; - break; - } - - s->pwm.faddr = value; - s->pwm.file[s->pwm.faddr] = 0; - } else if (byte == 1) { - s->pwm.file[s->pwm.faddr] |= value << 8; - } else if (byte == 2) { - s->pwm.file[s->pwm.faddr] |= value << 0; - s->reg = LM832x_GENERAL_ERROR; - } - break; - case LM832x_CMD_PWM_START: - s->reg = LM832x_GENERAL_ERROR; - if (!(value & 3) || (value >> 2) > 59) { - lm_kbd_error(s, ERR_BADPAR); - break; - } - - s->pwm.addr[(value & 3) - 1] = value >> 2; - lm_kbd_pwm_start(s, (value & 3) - 1); - break; - case LM832x_CMD_PWM_STOP: - s->reg = LM832x_GENERAL_ERROR; - if (!(value & 3)) { - lm_kbd_error(s, ERR_BADPAR); - break; - } - - timer_del(s->pwm.tm[(value & 3) - 1]); - break; - - case LM832x_GENERAL_ERROR: - lm_kbd_error(s, ERR_BADPAR); - break; - default: - lm_kbd_error(s, ERR_CMDUNK); - fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg); - break; - } -} - -static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event) -{ - LM823KbdState *s = LM8323(i2c); - - switch (event) { - case I2C_START_RECV: - case I2C_START_SEND: - s->i2c_cycle = 0; - s->i2c_dir = (event == I2C_START_SEND); - break; - - default: - break; - } -} - -static int lm_i2c_rx(I2CSlave *i2c) -{ - LM823KbdState *s = LM8323(i2c); - - return lm_kbd_read(s, s->reg, s->i2c_cycle ++); -} - -static int lm_i2c_tx(I2CSlave *i2c, uint8_t data) -{ - LM823KbdState *s = LM8323(i2c); - - if (!s->i2c_cycle) - s->reg = data; - else - lm_kbd_write(s, s->reg, s->i2c_cycle - 1, data); - s->i2c_cycle ++; - - return 0; -} - -static int lm_kbd_post_load(void *opaque, int version_id) -{ - LM823KbdState *s = opaque; - - lm_kbd_irq_update(s); - lm_kbd_gpio_update(s); - - return 0; -} - -static const VMStateDescription vmstate_lm_kbd = { - .name = "LM8323", - .version_id = 0, - .minimum_version_id = 0, - .post_load = lm_kbd_post_load, - .fields = (VMStateField[]) { - VMSTATE_I2C_SLAVE(parent_obj, LM823KbdState), - VMSTATE_UINT8(i2c_dir, LM823KbdState), - VMSTATE_UINT8(i2c_cycle, LM823KbdState), - VMSTATE_UINT8(reg, LM823KbdState), - VMSTATE_UINT8(config, LM823KbdState), - VMSTATE_UINT8(status, LM823KbdState), - VMSTATE_UINT8(acttime, LM823KbdState), - VMSTATE_UINT8(error, LM823KbdState), - VMSTATE_UINT8(clock, LM823KbdState), - VMSTATE_UINT16(gpio.pull, LM823KbdState), - VMSTATE_UINT16(gpio.mask, LM823KbdState), - VMSTATE_UINT16(gpio.dir, LM823KbdState), - VMSTATE_UINT16(gpio.level, LM823KbdState), - VMSTATE_UINT8(kbd.dbnctime, LM823KbdState), - VMSTATE_UINT8(kbd.size, LM823KbdState), - VMSTATE_UINT8(kbd.start, LM823KbdState), - VMSTATE_UINT8(kbd.len, LM823KbdState), - VMSTATE_BUFFER(kbd.fifo, LM823KbdState), - VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256), - VMSTATE_UINT8(pwm.faddr, LM823KbdState), - VMSTATE_BUFFER(pwm.addr, LM823KbdState), - VMSTATE_TIMER_PTR_ARRAY(pwm.tm, LM823KbdState, 3), - VMSTATE_END_OF_LIST() - } -}; - - -static int lm8323_init(I2CSlave *i2c) -{ - LM823KbdState *s = LM8323(i2c); - - s->model = 0x8323; - s->pwm.tm[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm0_tick, s); - s->pwm.tm[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm1_tick, s); - s->pwm.tm[2] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm2_tick, s); - qdev_init_gpio_out(DEVICE(i2c), &s->nirq, 1); - - lm_kbd_reset(s); - - qemu_register_reset((void *) lm_kbd_reset, s); - return 0; -} - -void lm832x_key_event(DeviceState *dev, int key, int state) -{ - LM823KbdState *s = LM8323(dev); - - if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR)) - return; - - if (s->kbd.len >= sizeof(s->kbd.fifo)) { - lm_kbd_error(s, ERR_FIFOOVR); - return; - } - - s->kbd.fifo[(s->kbd.start + s->kbd.len ++) & (sizeof(s->kbd.fifo) - 1)] = - key | (state << 7); - - /* We never set ERR_KEYOVR because we support multiple keys fine. */ - s->status |= INT_KEYPAD; - lm_kbd_irq_update(s); -} - -static void lm8323_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - - k->init = lm8323_init; - k->event = lm_i2c_event; - k->recv = lm_i2c_rx; - k->send = lm_i2c_tx; - dc->vmsd = &vmstate_lm_kbd; -} - -static const TypeInfo lm8323_info = { - .name = TYPE_LM8323, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(LM823KbdState), - .class_init = lm8323_class_init, -}; - -static void lm832x_register_types(void) -{ - type_register_static(&lm8323_info); -} - -type_init(lm832x_register_types) diff --git a/qemu/hw/input/milkymist-softusb.c b/qemu/hw/input/milkymist-softusb.c deleted file mode 100644 index 40dfca157..000000000 --- a/qemu/hw/input/milkymist-softusb.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * QEMU model of the Milkymist SoftUSB block. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * not available yet - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "ui/console.h" -#include "hw/input/hid.h" -#include "qemu/error-report.h" - -enum { - R_CTRL = 0, - R_MAX -}; - -enum { - CTRL_RESET = (1<<0), -}; - -#define COMLOC_DEBUG_PRODUCE 0x1000 -#define COMLOC_DEBUG_BASE 0x1001 -#define COMLOC_MEVT_PRODUCE 0x1101 -#define COMLOC_MEVT_BASE 0x1102 -#define COMLOC_KEVT_PRODUCE 0x1142 -#define COMLOC_KEVT_BASE 0x1143 - -#define TYPE_MILKYMIST_SOFTUSB "milkymist-softusb" -#define MILKYMIST_SOFTUSB(obj) \ - OBJECT_CHECK(MilkymistSoftUsbState, (obj), TYPE_MILKYMIST_SOFTUSB) - -struct MilkymistSoftUsbState { - SysBusDevice parent_obj; - - HIDState hid_kbd; - HIDState hid_mouse; - - MemoryRegion regs_region; - MemoryRegion pmem; - MemoryRegion dmem; - qemu_irq irq; - - void *pmem_ptr; - void *dmem_ptr; - - /* device properties */ - uint32_t pmem_size; - uint32_t dmem_size; - - /* device registers */ - uint32_t regs[R_MAX]; - - /* mouse state */ - uint8_t mouse_hid_buffer[4]; - - /* keyboard state */ - uint8_t kbd_hid_buffer[8]; -}; -typedef struct MilkymistSoftUsbState MilkymistSoftUsbState; - -static uint64_t softusb_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistSoftUsbState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CTRL: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_softusb: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_softusb_memory_read(addr << 2, r); - - return r; -} - -static void -softusb_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistSoftUsbState *s = opaque; - - trace_milkymist_softusb_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTRL: - s->regs[addr] = value; - break; - - default: - error_report("milkymist_softusb: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps softusb_mmio_ops = { - .read = softusb_read, - .write = softusb_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static inline void softusb_read_dmem(MilkymistSoftUsbState *s, - uint32_t offset, uint8_t *buf, uint32_t len) -{ - if (offset + len >= s->dmem_size) { - error_report("milkymist_softusb: read dmem out of bounds " - "at offset 0x%x, len %d", offset, len); - memset(buf, 0, len); - return; - } - - memcpy(buf, s->dmem_ptr + offset, len); -} - -static inline void softusb_write_dmem(MilkymistSoftUsbState *s, - uint32_t offset, uint8_t *buf, uint32_t len) -{ - if (offset + len >= s->dmem_size) { - error_report("milkymist_softusb: write dmem out of bounds " - "at offset 0x%x, len %d", offset, len); - return; - } - - memcpy(s->dmem_ptr + offset, buf, len); -} - -static void softusb_mouse_changed(MilkymistSoftUsbState *s) -{ - uint8_t m; - - softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1); - trace_milkymist_softusb_mevt(m); - softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4); - m = (m + 1) & 0xf; - softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1); - - trace_milkymist_softusb_pulse_irq(); - qemu_irq_pulse(s->irq); -} - -static void softusb_kbd_changed(MilkymistSoftUsbState *s) -{ - uint8_t m; - - softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1); - trace_milkymist_softusb_kevt(m); - softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8); - m = (m + 1) & 0x7; - softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1); - - trace_milkymist_softusb_pulse_irq(); - qemu_irq_pulse(s->irq); -} - -static void softusb_kbd_hid_datain(HIDState *hs) -{ - MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd); - int len; - - /* if device is in reset, do nothing */ - if (s->regs[R_CTRL] & CTRL_RESET) { - return; - } - - while (hid_has_events(hs)) { - len = hid_keyboard_poll(hs, s->kbd_hid_buffer, - sizeof(s->kbd_hid_buffer)); - - if (len == 8) { - softusb_kbd_changed(s); - } - } -} - -static void softusb_mouse_hid_datain(HIDState *hs) -{ - MilkymistSoftUsbState *s = - container_of(hs, MilkymistSoftUsbState, hid_mouse); - int len; - - /* if device is in reset, do nothing */ - if (s->regs[R_CTRL] & CTRL_RESET) { - return; - } - - while (hid_has_events(hs)) { - len = hid_pointer_poll(hs, s->mouse_hid_buffer, - sizeof(s->mouse_hid_buffer)); - - if (len == 4) { - softusb_mouse_changed(s); - } - } -} - -static void milkymist_softusb_reset(DeviceState *d) -{ - MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer)); - memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer)); - - hid_reset(&s->hid_kbd); - hid_reset(&s->hid_mouse); - - /* defaults */ - s->regs[R_CTRL] = CTRL_RESET; -} - -static int milkymist_softusb_init(SysBusDevice *dev) -{ - MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(dev); - - sysbus_init_irq(dev, &s->irq); - - memory_region_init_io(&s->regs_region, OBJECT(s), &softusb_mmio_ops, s, - "milkymist-softusb", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); - - /* register pmem and dmem */ - memory_region_init_ram(&s->pmem, OBJECT(s), "milkymist-softusb.pmem", - s->pmem_size, &error_fatal); - vmstate_register_ram_global(&s->pmem); - s->pmem_ptr = memory_region_get_ram_ptr(&s->pmem); - sysbus_init_mmio(dev, &s->pmem); - memory_region_init_ram(&s->dmem, OBJECT(s), "milkymist-softusb.dmem", - s->dmem_size, &error_fatal); - vmstate_register_ram_global(&s->dmem); - s->dmem_ptr = memory_region_get_ram_ptr(&s->dmem); - sysbus_init_mmio(dev, &s->dmem); - - hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain); - hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain); - - return 0; -} - -static const VMStateDescription vmstate_milkymist_softusb = { - .name = "milkymist-softusb", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX), - VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState), - VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState), - VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState), - VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_softusb_properties[] = { - DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000), - DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_softusb_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = milkymist_softusb_init; - dc->reset = milkymist_softusb_reset; - dc->vmsd = &vmstate_milkymist_softusb; - dc->props = milkymist_softusb_properties; -} - -static const TypeInfo milkymist_softusb_info = { - .name = TYPE_MILKYMIST_SOFTUSB, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistSoftUsbState), - .class_init = milkymist_softusb_class_init, -}; - -static void milkymist_softusb_register_types(void) -{ - type_register_static(&milkymist_softusb_info); -} - -type_init(milkymist_softusb_register_types) diff --git a/qemu/hw/input/pckbd.c b/qemu/hw/input/pckbd.c deleted file mode 100644 index 1d932ec19..000000000 --- a/qemu/hw/input/pckbd.c +++ /dev/null @@ -1,595 +0,0 @@ -/* - * QEMU PC keyboard emulation - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/isa/isa.h" -#include "hw/i386/pc.h" -#include "hw/input/ps2.h" -#include "sysemu/sysemu.h" - -/* debug PC keyboard */ -//#define DEBUG_KBD -#ifdef DEBUG_KBD -#define DPRINTF(fmt, ...) \ - do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) -#endif - -/* 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 Commands */ -#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ -#define KBD_CMD_ECHO 0xEE -#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 */ - -/* Keyboard Replies */ -#define KBD_REPLY_POR 0xAA /* Power on reset */ -#define KBD_REPLY_ACK 0xFA /* Command ACK */ -#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ - -/* 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 */ - -/* 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 - -/* Output Port Bits */ -#define KBD_OUT_RESET 0x01 /* 1=normal mode, 0=reset */ -#define KBD_OUT_A20 0x02 /* x86 only */ -#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. - * We make the default value of the outport include these four bits, - * so that the subsection is rarely necessary. - */ -#define KBD_OUT_ONES 0xcc - -/* 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 MOUSE_STATUS_REMOTE 0x40 -#define MOUSE_STATUS_ENABLED 0x20 -#define MOUSE_STATUS_SCALE21 0x10 - -#define KBD_PENDING_KBD 1 -#define KBD_PENDING_AUX 2 - -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; - bool outport_present; - /* Bitmask of devices with data available. */ - uint8_t pending; - void *kbd; - void *mouse; - - qemu_irq irq_kbd; - qemu_irq irq_mouse; - qemu_irq *a20_out; - hwaddr mask; -} KBDState; - -/* update irq and KBD_STAT_[MOUSE_]OBF */ -/* 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(KBDState *s) -{ - int irq_kbd_level, irq_mouse_level; - - irq_kbd_level = 0; - irq_mouse_level = 0; - s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); - s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF); - if (s->pending) { - s->status |= KBD_STAT_OBF; - s->outport |= KBD_OUT_OBF; - /* kbd data takes priority over aux data. */ - if (s->pending == KBD_PENDING_AUX) { - s->status |= KBD_STAT_MOUSE_OBF; - s->outport |= KBD_OUT_MOUSE_OBF; - if (s->mode & KBD_MODE_MOUSE_INT) - irq_mouse_level = 1; - } else { - if ((s->mode & KBD_MODE_KBD_INT) && - !(s->mode & KBD_MODE_DISABLE_KBD)) - irq_kbd_level = 1; - } - } - qemu_set_irq(s->irq_kbd, irq_kbd_level); - qemu_set_irq(s->irq_mouse, irq_mouse_level); -} - -static void kbd_update_kbd_irq(void *opaque, int level) -{ - KBDState *s = (KBDState *)opaque; - - if (level) - s->pending |= KBD_PENDING_KBD; - else - s->pending &= ~KBD_PENDING_KBD; - kbd_update_irq(s); -} - -static void kbd_update_aux_irq(void *opaque, int level) -{ - KBDState *s = (KBDState *)opaque; - - if (level) - s->pending |= KBD_PENDING_AUX; - else - s->pending &= ~KBD_PENDING_AUX; - kbd_update_irq(s); -} - -static uint64_t kbd_read_status(void *opaque, hwaddr addr, - unsigned size) -{ - KBDState *s = opaque; - int val; - val = s->status; - DPRINTF("kbd: read status=0x%02x\n", val); - return val; -} - -static void kbd_queue(KBDState *s, int b, int aux) -{ - if (aux) - ps2_queue(s->mouse, b); - else - ps2_queue(s->kbd, b); -} - -static void outport_write(KBDState *s, uint32_t val) -{ - DPRINTF("kbd: write outport=0x%02x\n", val); - s->outport = val; - if (s->a20_out) { - qemu_set_irq(*s->a20_out, (val >> 1) & 1); - } - if (!(val & 1)) { - qemu_system_reset_request(); - } -} - -static void kbd_write_command(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - KBDState *s = opaque; - - DPRINTF("kbd: write cmd=0x%02" PRIx64 "\n", val); - - /* 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)) - val = KBD_CCMD_RESET; - else - val = KBD_CCMD_NO_OP; - } - - switch(val) { - case KBD_CCMD_READ_MODE: - kbd_queue(s, s->mode, 0); - break; - case KBD_CCMD_WRITE_MODE: - case KBD_CCMD_WRITE_OBUF: - case KBD_CCMD_WRITE_AUX_OBUF: - case KBD_CCMD_WRITE_MOUSE: - case KBD_CCMD_WRITE_OUTPORT: - s->write_cmd = val; - break; - case KBD_CCMD_MOUSE_DISABLE: - s->mode |= KBD_MODE_DISABLE_MOUSE; - break; - case KBD_CCMD_MOUSE_ENABLE: - s->mode &= ~KBD_MODE_DISABLE_MOUSE; - break; - case KBD_CCMD_TEST_MOUSE: - kbd_queue(s, 0x00, 0); - break; - case KBD_CCMD_SELF_TEST: - s->status |= KBD_STAT_SELFTEST; - kbd_queue(s, 0x55, 0); - break; - case KBD_CCMD_KBD_TEST: - kbd_queue(s, 0x00, 0); - break; - case KBD_CCMD_KBD_DISABLE: - s->mode |= KBD_MODE_DISABLE_KBD; - kbd_update_irq(s); - break; - case KBD_CCMD_KBD_ENABLE: - s->mode &= ~KBD_MODE_DISABLE_KBD; - kbd_update_irq(s); - break; - case KBD_CCMD_READ_INPORT: - kbd_queue(s, 0x80, 0); - break; - case KBD_CCMD_READ_OUTPORT: - kbd_queue(s, s->outport, 0); - break; - case KBD_CCMD_ENABLE_A20: - if (s->a20_out) { - qemu_irq_raise(*s->a20_out); - } - s->outport |= KBD_OUT_A20; - break; - case KBD_CCMD_DISABLE_A20: - if (s->a20_out) { - qemu_irq_lower(*s->a20_out); - } - s->outport &= ~KBD_OUT_A20; - break; - case KBD_CCMD_RESET: - qemu_system_reset_request(); - break; - case KBD_CCMD_NO_OP: - /* ignore that */ - break; - default: - fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", (int)val); - break; - } -} - -static uint64_t kbd_read_data(void *opaque, hwaddr addr, - unsigned size) -{ - KBDState *s = opaque; - uint32_t val; - - if (s->pending == KBD_PENDING_AUX) - val = ps2_read_data(s->mouse); - else - val = ps2_read_data(s->kbd); - - DPRINTF("kbd: read data=0x%02x\n", val); - return val; -} - -static void kbd_write_data(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - KBDState *s = opaque; - - DPRINTF("kbd: write data=0x%02" PRIx64 "\n", val); - - switch(s->write_cmd) { - case 0: - ps2_write_keyboard(s->kbd, val); - break; - case KBD_CCMD_WRITE_MODE: - s->mode = val; - ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0); - /* ??? */ - kbd_update_irq(s); - break; - case KBD_CCMD_WRITE_OBUF: - kbd_queue(s, val, 0); - break; - case KBD_CCMD_WRITE_AUX_OBUF: - kbd_queue(s, val, 1); - break; - case KBD_CCMD_WRITE_OUTPORT: - outport_write(s, val); - break; - case KBD_CCMD_WRITE_MOUSE: - ps2_write_mouse(s->mouse, val); - break; - default: - break; - } - s->write_cmd = 0; -} - -static void kbd_reset(void *opaque) -{ - KBDState *s = opaque; - - s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; - s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; - s->outport = KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES; - s->outport_present = false; -} - -static uint8_t kbd_outport_default(KBDState *s) -{ - return KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES - | (s->status & KBD_STAT_OBF ? KBD_OUT_OBF : 0) - | (s->status & KBD_STAT_MOUSE_OBF ? KBD_OUT_MOUSE_OBF : 0); -} - -static int kbd_outport_post_load(void *opaque, int version_id) -{ - KBDState *s = opaque; - s->outport_present = true; - return 0; -} - -static bool kbd_outport_needed(void *opaque) -{ - KBDState *s = opaque; - return s->outport != kbd_outport_default(s); -} - -static const VMStateDescription vmstate_kbd_outport = { - .name = "pckbd_outport", - .version_id = 1, - .minimum_version_id = 1, - .post_load = kbd_outport_post_load, - .needed = kbd_outport_needed, - .fields = (VMStateField[]) { - VMSTATE_UINT8(outport, KBDState), - VMSTATE_END_OF_LIST() - } -}; - -static int kbd_post_load(void *opaque, int version_id) -{ - KBDState *s = opaque; - if (!s->outport_present) { - s->outport = kbd_outport_default(s); - } - s->outport_present = false; - return 0; -} - -static const VMStateDescription vmstate_kbd = { - .name = "pckbd", - .version_id = 3, - .minimum_version_id = 3, - .post_load = kbd_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT8(write_cmd, KBDState), - VMSTATE_UINT8(status, KBDState), - VMSTATE_UINT8(mode, KBDState), - VMSTATE_UINT8(pending, KBDState), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &vmstate_kbd_outport, - NULL - } -}; - -/* Memory mapped interface */ -static uint32_t kbd_mm_readb (void *opaque, hwaddr addr) -{ - KBDState *s = opaque; - - if (addr & s->mask) - return kbd_read_status(s, 0, 1) & 0xff; - else - return kbd_read_data(s, 0, 1) & 0xff; -} - -static void kbd_mm_writeb (void *opaque, hwaddr addr, uint32_t value) -{ - KBDState *s = opaque; - - if (addr & s->mask) - kbd_write_command(s, 0, value & 0xff, 1); - else - kbd_write_data(s, 0, value & 0xff, 1); -} - -static const MemoryRegionOps i8042_mmio_ops = { - .endianness = DEVICE_NATIVE_ENDIAN, - .old_mmio = { - .read = { kbd_mm_readb, kbd_mm_readb, kbd_mm_readb }, - .write = { kbd_mm_writeb, kbd_mm_writeb, kbd_mm_writeb }, - }, -}; - -void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, - MemoryRegion *region, ram_addr_t size, - hwaddr mask) -{ - KBDState *s = g_malloc0(sizeof(KBDState)); - - s->irq_kbd = kbd_irq; - s->irq_mouse = mouse_irq; - s->mask = mask; - - 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); -} - -#define TYPE_I8042 "i8042" -#define I8042(obj) OBJECT_CHECK(ISAKBDState, (obj), TYPE_I8042) - -typedef struct ISAKBDState { - ISADevice parent_obj; - - KBDState kbd; - MemoryRegion io[2]; -} ISAKBDState; - -void i8042_isa_mouse_fake_event(void *opaque) -{ - ISADevice *dev = opaque; - ISAKBDState *isa = I8042(dev); - KBDState *s = &isa->kbd; - - ps2_mouse_fake_event(s->mouse); -} - -void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out) -{ - ISAKBDState *isa = I8042(dev); - KBDState *s = &isa->kbd; - - s->a20_out = a20_out; -} - -static const VMStateDescription vmstate_kbd_isa = { - .name = "pckbd", - .version_id = 3, - .minimum_version_id = 3, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState), - VMSTATE_END_OF_LIST() - } -}; - -static const MemoryRegionOps i8042_data_ops = { - .read = kbd_read_data, - .write = kbd_write_data, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static const MemoryRegionOps i8042_cmd_ops = { - .read = kbd_read_status, - .write = kbd_write_command, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void i8042_initfn(Object *obj) -{ - ISAKBDState *isa_s = I8042(obj); - KBDState *s = &isa_s->kbd; - - memory_region_init_io(isa_s->io + 0, obj, &i8042_data_ops, s, - "i8042-data", 1); - memory_region_init_io(isa_s->io + 1, obj, &i8042_cmd_ops, s, - "i8042-cmd", 1); -} - -static void i8042_realizefn(DeviceState *dev, Error **errp) -{ - ISADevice *isadev = ISA_DEVICE(dev); - ISAKBDState *isa_s = I8042(dev); - KBDState *s = &isa_s->kbd; - - isa_init_irq(isadev, &s->irq_kbd, 1); - isa_init_irq(isadev, &s->irq_mouse, 12); - - 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); - qemu_register_reset(kbd_reset, s); -} - -static void i8042_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = i8042_realizefn; - dc->vmsd = &vmstate_kbd_isa; -} - -static const TypeInfo i8042_info = { - .name = TYPE_I8042, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(ISAKBDState), - .instance_init = i8042_initfn, - .class_init = i8042_class_initfn, -}; - -static void i8042_register_types(void) -{ - type_register_static(&i8042_info); -} - -type_init(i8042_register_types) diff --git a/qemu/hw/input/pl050.c b/qemu/hw/input/pl050.c deleted file mode 100644 index 3092b0fe3..000000000 --- a/qemu/hw/input/pl050.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Arm PrimeCell PL050 Keyboard / Mouse Interface - * - * Copyright (c) 2006-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "hw/input/ps2.h" - -#define TYPE_PL050 "pl050" -#define PL050(obj) OBJECT_CHECK(PL050State, (obj), TYPE_PL050) - -typedef struct PL050State { - SysBusDevice parent_obj; - - MemoryRegion iomem; - void *dev; - uint32_t cr; - uint32_t clk; - uint32_t last; - int pending; - qemu_irq irq; - bool is_mouse; -} PL050State; - -static const VMStateDescription vmstate_pl050 = { - .name = "pl050", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_UINT32(cr, PL050State), - VMSTATE_UINT32(clk, PL050State), - VMSTATE_UINT32(last, PL050State), - VMSTATE_INT32(pending, PL050State), - VMSTATE_END_OF_LIST() - } -}; - -#define PL050_TXEMPTY (1 << 6) -#define PL050_TXBUSY (1 << 5) -#define PL050_RXFULL (1 << 4) -#define PL050_RXBUSY (1 << 3) -#define PL050_RXPARITY (1 << 2) -#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 void pl050_update(void *opaque, 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); -} - -static uint64_t pl050_read(void *opaque, hwaddr offset, - unsigned size) -{ - PL050State *s = (PL050State *)opaque; - if (offset >= 0xfe0 && offset < 0x1000) - return pl050_id[(offset - 0xfe0) >> 2]; - - switch (offset >> 2) { - case 0: /* KMICR */ - return s->cr; - case 1: /* KMISTAT */ - { - uint8_t val; - uint32_t stat; - - val = s->last; - val = val ^ (val >> 4); - val = val ^ (val >> 2); - val = (val ^ (val >> 1)) & 1; - - stat = PL050_TXEMPTY; - if (val) - stat |= PL050_RXPARITY; - if (s->pending) - stat |= PL050_RXFULL; - - return stat; - } - case 2: /* KMIDATA */ - if (s->pending) - s->last = ps2_read_data(s->dev); - return s->last; - case 3: /* KMICLKDIV */ - return s->clk; - case 4: /* KMIIR */ - return s->pending | 2; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl050_read: Bad offset %x\n", (int)offset); - return 0; - } -} - -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); - /* ??? Need to implement the enable/disable bit. */ - break; - case 2: /* KMIDATA */ - /* ??? This should toggle the TX interrupt line. */ - /* ??? This means kbd/mouse can block each other. */ - if (s->is_mouse) { - ps2_write_mouse(s->dev, value); - } else { - ps2_write_keyboard(s->dev, value); - } - break; - case 3: /* KMICLKDIV */ - s->clk = value; - return; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl050_write: Bad offset %x\n", (int)offset); - } -} -static const MemoryRegionOps pl050_ops = { - .read = pl050_read, - .write = pl050_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int pl050_initfn(SysBusDevice *dev) -{ - PL050State *s = PL050(dev); - - memory_region_init_io(&s->iomem, OBJECT(s), &pl050_ops, s, "pl050", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - if (s->is_mouse) { - s->dev = ps2_mouse_init(pl050_update, s); - } else { - s->dev = ps2_kbd_init(pl050_update, s); - } - return 0; -} - -static void pl050_keyboard_init(Object *obj) -{ - PL050State *s = PL050(obj); - - s->is_mouse = false; -} - -static void pl050_mouse_init(Object *obj) -{ - PL050State *s = PL050(obj); - - s->is_mouse = true; -} - -static const TypeInfo pl050_kbd_info = { - .name = "pl050_keyboard", - .parent = TYPE_PL050, - .instance_init = pl050_keyboard_init, -}; - -static const TypeInfo pl050_mouse_info = { - .name = "pl050_mouse", - .parent = TYPE_PL050, - .instance_init = pl050_mouse_init, -}; - -static void pl050_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(oc); - - sdc->init = pl050_initfn; - dc->vmsd = &vmstate_pl050; -} - -static const TypeInfo pl050_type_info = { - .name = TYPE_PL050, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PL050State), - .abstract = true, - .class_init = pl050_class_init, -}; - -static void pl050_register_types(void) -{ - type_register_static(&pl050_type_info); - type_register_static(&pl050_kbd_info); - type_register_static(&pl050_mouse_info); -} - -type_init(pl050_register_types) diff --git a/qemu/hw/input/ps2.c b/qemu/hw/input/ps2.c deleted file mode 100644 index a8aa36f5c..000000000 --- a/qemu/hw/input/ps2.c +++ /dev/null @@ -1,813 +0,0 @@ -/* - * QEMU PS/2 keyboard/mouse emulation - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/input/ps2.h" -#include "ui/console.h" -#include "ui/input.h" -#include "sysemu/sysemu.h" - -#include "trace.h" - -/* debug PC keyboard */ -//#define DEBUG_KBD - -/* debug PC keyboard : only mouse */ -//#define DEBUG_MOUSE - -/* 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 */ - -/* 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 */ - -/* 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 MOUSE_STATUS_REMOTE 0x40 -#define MOUSE_STATUS_ENABLED 0x20 -#define MOUSE_STATUS_SCALE21 0x10 - -#define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */ - -typedef struct { - /* Keep the data array 256 bytes long, which compatibility - with older qemu versions. */ - uint8_t data[256]; - int rptr, wptr, count; -} PS2Queue; - -typedef struct { - PS2Queue queue; - int32_t write_cmd; - void (*update_irq)(void *, int); - void *update_arg; -} PS2State; - -typedef struct { - PS2State common; - int scan_enabled; - /* QEMU uses translated PC scancodes internally. To avoid multiple - conversions we do the translation (if any) in the PS/2 emulation - not the keyboard controller. */ - int translate; - int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ - int ledstate; -} 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; - uint8_t mouse_buttons; -} PS2MouseState; - -/* Table to convert from PC scancodes to raw scancodes. */ -static const unsigned char ps2_raw_keycode[128] = { - 0, 118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13, - 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, - 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, - 50, 49, 58, 65, 73, 74, 89, 124, 17, 41, 88, 5, 6, 4, 12, 3, - 11, 2, 10, 1, 9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105, -114, 122, 112, 113, 127, 96, 97, 120, 7, 15, 23, 31, 39, 47, 55, 63, - 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111, - 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110 -}; -static const unsigned char ps2_raw_keycode_set3[128] = { - 0, 8, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13, - 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 17, 28, 27, - 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 92, 26, 34, 33, 42, - 50, 49, 58, 65, 73, 74, 89, 126, 25, 41, 20, 7, 15, 23, 31, 39, - 47, 2, 63, 71, 79, 118, 95, 108, 117, 125, 132, 107, 115, 116, 124, 105, -114, 122, 112, 113, 127, 96, 97, 86, 94, 15, 23, 31, 39, 47, 55, 63, - 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111, - 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110 -}; - -void ps2_queue(void *opaque, int b) -{ - PS2State *s = (PS2State *)opaque; - PS2Queue *q = &s->queue; - - if (q->count >= PS2_QUEUE_SIZE - 1) - return; - q->data[q->wptr] = b; - if (++q->wptr == PS2_QUEUE_SIZE) - q->wptr = 0; - q->count++; - s->update_irq(s->update_arg, 1); -} - -/* - keycode is expressed as follow: - bit 7 - 0 key pressed, 1 = key released - bits 6-0 - translated scancode set 2 - */ -static void ps2_put_keycode(void *opaque, int keycode) -{ - PS2KbdState *s = opaque; - - trace_ps2_put_keycode(opaque, keycode); - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - /* XXX: add support for scancode set 1 */ - if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) { - if (keycode & 0x80) { - ps2_queue(&s->common, 0xf0); - } - if (s->scancode_set == 2) { - keycode = ps2_raw_keycode[keycode & 0x7f]; - } else if (s->scancode_set == 3) { - keycode = ps2_raw_keycode_set3[keycode & 0x7f]; - } - } - ps2_queue(&s->common, keycode); -} - -static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, - InputEvent *evt) -{ - PS2KbdState *s = (PS2KbdState *)dev; - int scancodes[3], i, count; - InputKeyEvent *key = evt->u.key.data; - - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - count = qemu_input_key_value_to_scancode(key->key, - key->down, - scancodes); - for (i = 0; i < count; i++) { - ps2_put_keycode(s, scancodes[i]); - } -} - -uint32_t ps2_read_data(void *opaque) -{ - PS2State *s = (PS2State *)opaque; - PS2Queue *q; - int val, index; - - trace_ps2_read_data(opaque); - q = &s->queue; - if (q->count == 0) { - /* 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) - index = PS2_QUEUE_SIZE - 1; - val = q->data[index]; - } else { - val = q->data[q->rptr]; - if (++q->rptr == PS2_QUEUE_SIZE) - q->rptr = 0; - q->count--; - /* reading deasserts IRQ */ - s->update_irq(s->update_arg, 0); - /* reassert IRQs if data left */ - s->update_irq(s->update_arg, q->count != 0); - } - return val; -} - -static void ps2_set_ledstate(PS2KbdState *s, int ledstate) -{ - trace_ps2_set_ledstate(s, ledstate); - s->ledstate = ledstate; - kbd_put_ledstate(ledstate); -} - -static void ps2_reset_keyboard(PS2KbdState *s) -{ - trace_ps2_reset_keyboard(s); - s->scan_enabled = 1; - s->scancode_set = 2; - ps2_set_ledstate(s, 0); -} - -void ps2_write_keyboard(void *opaque, int val) -{ - PS2KbdState *s = (PS2KbdState *)opaque; - - trace_ps2_write_keyboard(opaque, val); - switch(s->common.write_cmd) { - default: - case -1: - switch(val) { - case 0x00: - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - case 0x05: - ps2_queue(&s->common, KBD_REPLY_RESEND); - break; - case KBD_CMD_GET_ID: - ps2_queue(&s->common, KBD_REPLY_ACK); - /* We emulate a MF2 AT keyboard here */ - ps2_queue(&s->common, KBD_REPLY_ID); - if (s->translate) - ps2_queue(&s->common, 0x41); - else - ps2_queue(&s->common, 0x83); - break; - case KBD_CMD_ECHO: - ps2_queue(&s->common, KBD_CMD_ECHO); - break; - case KBD_CMD_ENABLE: - s->scan_enabled = 1; - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - case KBD_CMD_SCANCODE: - case KBD_CMD_SET_LEDS: - case KBD_CMD_SET_RATE: - s->common.write_cmd = val; - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - case KBD_CMD_RESET_DISABLE: - ps2_reset_keyboard(s); - s->scan_enabled = 0; - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - case KBD_CMD_RESET_ENABLE: - ps2_reset_keyboard(s); - s->scan_enabled = 1; - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - case KBD_CMD_RESET: - ps2_reset_keyboard(s); - ps2_queue(&s->common, KBD_REPLY_ACK); - ps2_queue(&s->common, KBD_REPLY_POR); - break; - default: - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - } - break; - case KBD_CMD_SCANCODE: - if (val == 0) { - if (s->scancode_set == 1) - ps2_put_keycode(s, 0x43); - else if (s->scancode_set == 2) - ps2_put_keycode(s, 0x41); - else if (s->scancode_set == 3) - ps2_put_keycode(s, 0x3f); - } else { - if (val >= 1 && val <= 3) - s->scancode_set = val; - ps2_queue(&s->common, KBD_REPLY_ACK); - } - s->common.write_cmd = -1; - break; - case KBD_CMD_SET_LEDS: - ps2_set_ledstate(s, val); - ps2_queue(&s->common, KBD_REPLY_ACK); - s->common.write_cmd = -1; - break; - case KBD_CMD_SET_RATE: - ps2_queue(&s->common, KBD_REPLY_ACK); - s->common.write_cmd = -1; - break; - } -} - -/* Set the scancode translation mode. - 0 = raw scancodes. - 1 = translated scancodes (used by qemu internally). */ - -void ps2_keyboard_set_translation(void *opaque, int mode) -{ - PS2KbdState *s = (PS2KbdState *)opaque; - trace_ps2_keyboard_set_translation(opaque, mode); - s->translate = mode; -} - -static void ps2_mouse_send_packet(PS2MouseState *s) -{ - unsigned int b; - int dx1, dy1, dz1; - - dx1 = s->mouse_dx; - dy1 = s->mouse_dy; - dz1 = s->mouse_dz; - /* XXX: increase range to 8 bits ? */ - if (dx1 > 127) - dx1 = 127; - else if (dx1 < -127) - dx1 = -127; - if (dy1 > 127) - dy1 = 127; - else if (dy1 < -127) - dy1 = -127; - b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); - ps2_queue(&s->common, b); - ps2_queue(&s->common, dx1 & 0xff); - ps2_queue(&s->common, dy1 & 0xff); - /* extra byte for IMPS/2 or IMEX */ - switch(s->mouse_type) { - default: - break; - case 3: - if (dz1 > 127) - dz1 = 127; - else if (dz1 < -127) - dz1 = -127; - ps2_queue(&s->common, dz1 & 0xff); - break; - case 4: - if (dz1 > 7) - dz1 = 7; - else if (dz1 < -7) - dz1 = -7; - b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); - ps2_queue(&s->common, b); - break; - } - - trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); - /* update deltas */ - s->mouse_dx -= dx1; - s->mouse_dy -= dy1; - s->mouse_dz -= dz1; -} - -static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, - InputEvent *evt) -{ - static const int bmap[INPUT_BUTTON__MAX] = { - [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, - [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, - [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, - }; - PS2MouseState *s = (PS2MouseState *)dev; - InputMoveEvent *move; - InputBtnEvent *btn; - - /* check if deltas are recorded when disabled */ - if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) - return; - - switch (evt->type) { - case INPUT_EVENT_KIND_REL: - move = evt->u.rel.data; - if (move->axis == INPUT_AXIS_X) { - s->mouse_dx += move->value; - } else if (move->axis == INPUT_AXIS_Y) { - s->mouse_dy -= move->value; - } - break; - - case INPUT_EVENT_KIND_BTN: - btn = evt->u.btn.data; - if (btn->down) { - s->mouse_buttons |= bmap[btn->button]; - if (btn->button == INPUT_BUTTON_WHEEL_UP) { - s->mouse_dz--; - } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { - s->mouse_dz++; - } - } else { - s->mouse_buttons &= ~bmap[btn->button]; - } - break; - - default: - /* keep gcc happy */ - break; - } -} - -static void ps2_mouse_sync(DeviceState *dev) -{ - PS2MouseState *s = (PS2MouseState *)dev; - - if (s->mouse_buttons) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - } - if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { - while (s->common.queue.count < PS2_QUEUE_SIZE - 4) { - /* if not remote, send event. Multiple events are sent if - too big deltas */ - ps2_mouse_send_packet(s); - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) - break; - } - } -} - -void ps2_mouse_fake_event(void *opaque) -{ - PS2MouseState *s = opaque; - trace_ps2_mouse_fake_event(opaque); - s->mouse_dx++; - ps2_mouse_sync(opaque); -} - -void ps2_write_mouse(void *opaque, int val) -{ - PS2MouseState *s = (PS2MouseState *)opaque; - - trace_ps2_write_mouse(opaque, val); -#ifdef DEBUG_MOUSE - printf("kbd: write mouse 0x%02x\n", val); -#endif - switch(s->common.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); - return; - } else if (val != AUX_RESET) { - ps2_queue(&s->common, val); - return; - } - } - switch(val) { - case AUX_SET_SCALE11: - s->mouse_status &= ~MOUSE_STATUS_SCALE21; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_SET_SCALE21: - s->mouse_status |= MOUSE_STATUS_SCALE21; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_SET_STREAM: - s->mouse_status &= ~MOUSE_STATUS_REMOTE; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_SET_WRAP: - s->mouse_wrap = 1; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_SET_REMOTE: - s->mouse_status |= MOUSE_STATUS_REMOTE; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_GET_TYPE: - ps2_queue(&s->common, AUX_ACK); - ps2_queue(&s->common, s->mouse_type); - break; - case AUX_SET_RES: - case AUX_SET_SAMPLE: - s->common.write_cmd = val; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_GET_SCALE: - ps2_queue(&s->common, AUX_ACK); - ps2_queue(&s->common, s->mouse_status); - ps2_queue(&s->common, s->mouse_resolution); - ps2_queue(&s->common, s->mouse_sample_rate); - break; - case AUX_POLL: - ps2_queue(&s->common, AUX_ACK); - ps2_mouse_send_packet(s); - break; - case AUX_ENABLE_DEV: - s->mouse_status |= MOUSE_STATUS_ENABLED; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_DISABLE_DEV: - s->mouse_status &= ~MOUSE_STATUS_ENABLED; - ps2_queue(&s->common, 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); - break; - case AUX_RESET: - s->mouse_sample_rate = 100; - s->mouse_resolution = 2; - s->mouse_status = 0; - s->mouse_type = 0; - ps2_queue(&s->common, AUX_ACK); - ps2_queue(&s->common, 0xaa); - ps2_queue(&s->common, s->mouse_type); - break; - default: - break; - } - break; - case AUX_SET_SAMPLE: - s->mouse_sample_rate = val; - /* detect IMPS/2 or IMEX */ - switch(s->mouse_detect_state) { - default: - case 0: - if (val == 200) - s->mouse_detect_state = 1; - break; - case 1: - if (val == 100) - s->mouse_detect_state = 2; - else if (val == 200) - s->mouse_detect_state = 3; - else - s->mouse_detect_state = 0; - break; - case 2: - if (val == 80) - s->mouse_type = 3; /* IMPS/2 */ - s->mouse_detect_state = 0; - break; - case 3: - 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; - break; - case AUX_SET_RES: - s->mouse_resolution = val; - ps2_queue(&s->common, AUX_ACK); - s->common.write_cmd = -1; - break; - } -} - -static void ps2_common_reset(PS2State *s) -{ - PS2Queue *q; - s->write_cmd = -1; - q = &s->queue; - q->rptr = 0; - q->wptr = 0; - q->count = 0; - s->update_irq(s->update_arg, 0); -} - -static void ps2_common_post_load(PS2State *s) -{ - PS2Queue *q = &s->queue; - int size; - int i; - int tmp_data[PS2_QUEUE_SIZE]; - - /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */ - size = q->count > PS2_QUEUE_SIZE ? 0 : q->count; - - /* move the queue elements to the start of data array */ - if (size > 0) { - for (i = 0; i < size; i++) { - /* move the queue elements to the temporary buffer */ - tmp_data[i] = q->data[q->rptr]; - if (++q->rptr == 256) { - q->rptr = 0; - } - } - memcpy(q->data, tmp_data, size); - } - /* reset rptr/wptr/count */ - q->rptr = 0; - q->wptr = size; - q->count = size; - s->update_irq(s->update_arg, q->count != 0); -} - -static void ps2_kbd_reset(void *opaque) -{ - PS2KbdState *s = (PS2KbdState *) opaque; - - trace_ps2_kbd_reset(opaque); - ps2_common_reset(&s->common); - s->scan_enabled = 0; - s->translate = 0; - s->scancode_set = 2; -} - -static void ps2_mouse_reset(void *opaque) -{ - PS2MouseState *s = (PS2MouseState *) opaque; - - trace_ps2_mouse_reset(opaque); - ps2_common_reset(&s->common); - s->mouse_status = 0; - s->mouse_resolution = 0; - s->mouse_sample_rate = 0; - s->mouse_wrap = 0; - s->mouse_type = 0; - s->mouse_detect_state = 0; - s->mouse_dx = 0; - s->mouse_dy = 0; - s->mouse_dz = 0; - s->mouse_buttons = 0; -} - -static const VMStateDescription vmstate_ps2_common = { - .name = "PS2 Common State", - .version_id = 3, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_INT32(write_cmd, PS2State), - VMSTATE_INT32(queue.rptr, PS2State), - VMSTATE_INT32(queue.wptr, PS2State), - VMSTATE_INT32(queue.count, PS2State), - VMSTATE_BUFFER(queue.data, PS2State), - VMSTATE_END_OF_LIST() - } -}; - -static bool ps2_keyboard_ledstate_needed(void *opaque) -{ - PS2KbdState *s = opaque; - - return s->ledstate != 0; /* 0 is default state */ -} - -static int ps2_kbd_ledstate_post_load(void *opaque, int version_id) -{ - PS2KbdState *s = opaque; - - kbd_put_ledstate(s->ledstate); - return 0; -} - -static const VMStateDescription vmstate_ps2_keyboard_ledstate = { - .name = "ps2kbd/ledstate", - .version_id = 3, - .minimum_version_id = 2, - .post_load = ps2_kbd_ledstate_post_load, - .needed = ps2_keyboard_ledstate_needed, - .fields = (VMStateField[]) { - VMSTATE_INT32(ledstate, PS2KbdState), - VMSTATE_END_OF_LIST() - } -}; - -static int ps2_kbd_post_load(void* opaque, int version_id) -{ - PS2KbdState *s = (PS2KbdState*)opaque; - PS2State *ps2 = &s->common; - - if (version_id == 2) - s->scancode_set=2; - - ps2_common_post_load(ps2); - - return 0; -} - -static void ps2_kbd_pre_save(void *opaque) -{ - PS2KbdState *s = (PS2KbdState *)opaque; - PS2State *ps2 = &s->common; - - ps2_common_post_load(ps2); -} - -static const VMStateDescription vmstate_ps2_keyboard = { - .name = "ps2kbd", - .version_id = 3, - .minimum_version_id = 2, - .post_load = ps2_kbd_post_load, - .pre_save = ps2_kbd_pre_save, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), - VMSTATE_INT32(scan_enabled, PS2KbdState), - VMSTATE_INT32(translate, PS2KbdState), - VMSTATE_INT32_V(scancode_set, PS2KbdState,3), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &vmstate_ps2_keyboard_ledstate, - NULL - } -}; - -static int ps2_mouse_post_load(void *opaque, int version_id) -{ - PS2MouseState *s = (PS2MouseState *)opaque; - PS2State *ps2 = &s->common; - - ps2_common_post_load(ps2); - - return 0; -} - -static void ps2_mouse_pre_save(void *opaque) -{ - PS2MouseState *s = (PS2MouseState *)opaque; - PS2State *ps2 = &s->common; - - ps2_common_post_load(ps2); -} - -static const VMStateDescription vmstate_ps2_mouse = { - .name = "ps2mouse", - .version_id = 2, - .minimum_version_id = 2, - .post_load = ps2_mouse_post_load, - .pre_save = ps2_mouse_pre_save, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), - VMSTATE_UINT8(mouse_status, PS2MouseState), - VMSTATE_UINT8(mouse_resolution, PS2MouseState), - VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), - VMSTATE_UINT8(mouse_wrap, PS2MouseState), - VMSTATE_UINT8(mouse_type, PS2MouseState), - VMSTATE_UINT8(mouse_detect_state, PS2MouseState), - VMSTATE_INT32(mouse_dx, PS2MouseState), - VMSTATE_INT32(mouse_dy, PS2MouseState), - VMSTATE_INT32(mouse_dz, PS2MouseState), - VMSTATE_UINT8(mouse_buttons, PS2MouseState), - VMSTATE_END_OF_LIST() - } -}; - -static QemuInputHandler ps2_keyboard_handler = { - .name = "QEMU PS/2 Keyboard", - .mask = INPUT_EVENT_MASK_KEY, - .event = ps2_keyboard_event, -}; - -void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) -{ - PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState)); - - 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; -} - -static QemuInputHandler ps2_mouse_handler = { - .name = "QEMU PS/2 Mouse", - .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, - .event = ps2_mouse_event, - .sync = ps2_mouse_sync, -}; - -void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) -{ - PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState)); - - 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; -} diff --git a/qemu/hw/input/pxa2xx_keypad.c b/qemu/hw/input/pxa2xx_keypad.c deleted file mode 100644 index 2b70bbb95..000000000 --- a/qemu/hw/input/pxa2xx_keypad.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Intel PXA27X Keypad Controller emulation. - * - * Copyright (c) 2007 MontaVista Software, Inc - * Written by Armin Kuster <akuster@kama-aina.net> - * or <Akuster@mvista.com> - * - * This code is licensed under the GPLv2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/arm/pxa.h" -#include "ui/console.h" - -/* - * Keypad - */ -#define KPC 0x00 /* Keypad Interface Control register */ -#define KPDK 0x08 /* Keypad Interface Direct Key register */ -#define KPREC 0x10 /* Keypad Interface Rotary Encoder register */ -#define KPMK 0x18 /* Keypad Interface Matrix Key register */ -#define KPAS 0x20 /* Keypad Interface Automatic Scan register */ -#define KPASMKP0 0x28 /* Keypad Interface Automatic Scan Multiple - Key Presser register 0 */ -#define KPASMKP1 0x30 /* Keypad Interface Automatic Scan Multiple - Key Presser register 1 */ -#define KPASMKP2 0x38 /* Keypad Interface Automatic Scan Multiple - Key Presser register 2 */ -#define KPASMKP3 0x40 /* Keypad Interface Automatic Scan Multiple - Key Presser register 3 */ -#define KPKDI 0x48 /* Keypad Interface Key Debounce Interval - register */ - -/* Keypad defines */ -#define KPC_AS (0x1 << 30) /* Automatic Scan bit */ -#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */ -#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */ -#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */ -#define KPC_MS7 (0x1 << 20) /* Matrix scan line 7 */ -#define KPC_MS6 (0x1 << 19) /* Matrix scan line 6 */ -#define KPC_MS5 (0x1 << 18) /* Matrix scan line 5 */ -#define KPC_MS4 (0x1 << 17) /* Matrix scan line 4 */ -#define KPC_MS3 (0x1 << 16) /* Matrix scan line 3 */ -#define KPC_MS2 (0x1 << 15) /* Matrix scan line 2 */ -#define KPC_MS1 (0x1 << 14) /* Matrix scan line 1 */ -#define KPC_MS0 (0x1 << 13) /* Matrix scan line 0 */ -#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */ -#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */ -#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */ -#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */ -#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */ -#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */ -#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */ -#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */ -#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */ - -#define KPDK_DKP (0x1 << 31) -#define KPDK_DK7 (0x1 << 7) -#define KPDK_DK6 (0x1 << 6) -#define KPDK_DK5 (0x1 << 5) -#define KPDK_DK4 (0x1 << 4) -#define KPDK_DK3 (0x1 << 3) -#define KPDK_DK2 (0x1 << 2) -#define KPDK_DK1 (0x1 << 1) -#define KPDK_DK0 (0x1 << 0) - -#define KPREC_OF1 (0x1 << 31) -#define KPREC_UF1 (0x1 << 30) -#define KPREC_OF0 (0x1 << 15) -#define KPREC_UF0 (0x1 << 14) - -#define KPMK_MKP (0x1 << 31) -#define KPAS_SO (0x1 << 31) -#define KPASMKPx_SO (0x1 << 31) - - -#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2))) - -#define PXAKBD_MAXROW 8 -#define PXAKBD_MAXCOL 8 - -struct PXA2xxKeyPadState { - MemoryRegion iomem; - qemu_irq irq; - const struct keymap *map; - int pressed_cnt; - int alt_code; - - uint32_t kpc; - uint32_t kpdk; - uint32_t kprec; - uint32_t kpmk; - uint32_t kpas; - uint32_t kpasmkp[4]; - uint32_t kpkdi; -}; - -static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col) -{ - int i; - for (i = 0; i < 4; i++) - { - *col = i * 2; - for (*row = 0; *row < 8; (*row)++) { - if (kp->kpasmkp[i] & (1 << *row)) - return; - } - *col = i * 2 + 1; - for (*row = 0; *row < 8; (*row)++) { - if (kp->kpasmkp[i] & (1 << (*row + 16))) - return; - } - } -} - -static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode) -{ - int row, col, rel, assert_irq = 0; - uint32_t val; - - if (keycode == 0xe0) { - kp->alt_code = 1; - return; - } - - if(!(kp->kpc & KPC_ME)) /* skip if not enabled */ - return; - - rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */ - keycode &= ~0x80; /* strip qemu key release bit */ - if (kp->alt_code) { - keycode |= 0x80; - kp->alt_code = 0; - } - - row = kp->map[keycode].row; - col = kp->map[keycode].column; - if (row == -1 || col == -1) { - return; - } - - val = KPASMKPx_MKC(row, col); - if (rel) { - if (kp->kpasmkp[col / 2] & val) { - kp->kpasmkp[col / 2] &= ~val; - kp->pressed_cnt--; - assert_irq = 1; - } - } else { - if (!(kp->kpasmkp[col / 2] & val)) { - kp->kpasmkp[col / 2] |= val; - kp->pressed_cnt++; - assert_irq = 1; - } - } - kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf; - if (kp->pressed_cnt == 1) { - kp->kpas &= ~((0xf << 4) | 0xf); - if (rel) { - pxa27x_keypad_find_pressed_key(kp, &row, &col); - } - kp->kpas |= ((row & 0xf) << 4) | (col & 0xf); - } - - if (!(kp->kpc & (KPC_AS | KPC_ASACT))) - assert_irq = 0; - - if (assert_irq && (kp->kpc & KPC_MIE)) { - kp->kpc |= KPC_MI; - qemu_irq_raise(kp->irq); - } -} - -static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset, - unsigned size) -{ - PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque; - uint32_t tmp; - - switch (offset) { - case KPC: - tmp = s->kpc; - if(tmp & KPC_MI) - s->kpc &= ~(KPC_MI); - if(tmp & KPC_DI) - s->kpc &= ~(KPC_DI); - qemu_irq_lower(s->irq); - return tmp; - break; - case KPDK: - return s->kpdk; - break; - case KPREC: - tmp = s->kprec; - if(tmp & KPREC_OF1) - s->kprec &= ~(KPREC_OF1); - if(tmp & KPREC_UF1) - s->kprec &= ~(KPREC_UF1); - if(tmp & KPREC_OF0) - s->kprec &= ~(KPREC_OF0); - if(tmp & KPREC_UF0) - s->kprec &= ~(KPREC_UF0); - return tmp; - break; - case KPMK: - tmp = s->kpmk; - if(tmp & KPMK_MKP) - s->kpmk &= ~(KPMK_MKP); - return tmp; - break; - case KPAS: - return s->kpas; - break; - case KPASMKP0: - return s->kpasmkp[0]; - break; - case KPASMKP1: - return s->kpasmkp[1]; - break; - case KPASMKP2: - return s->kpasmkp[2]; - break; - case KPASMKP3: - return s->kpasmkp[3]; - break; - case KPKDI: - return s->kpkdi; - break; - default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); - } - - return 0; -} - -static void pxa2xx_keypad_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque; - - switch (offset) { - case KPC: - s->kpc = value; - if (s->kpc & KPC_AS) { - s->kpc &= ~(KPC_AS); - } - break; - case KPDK: - s->kpdk = value; - break; - case KPREC: - s->kprec = value; - break; - case KPMK: - s->kpmk = value; - break; - case KPAS: - s->kpas = value; - break; - case KPASMKP0: - s->kpasmkp[0] = value; - break; - case KPASMKP1: - s->kpasmkp[1] = value; - break; - case KPASMKP2: - s->kpasmkp[2] = value; - break; - case KPASMKP3: - s->kpasmkp[3] = value; - break; - case KPKDI: - s->kpkdi = value; - break; - - default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); - } -} - -static const MemoryRegionOps pxa2xx_keypad_ops = { - .read = pxa2xx_keypad_read, - .write = pxa2xx_keypad_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pxa2xx_keypad = { - .name = "pxa2xx_keypad", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32(kpc, PXA2xxKeyPadState), - VMSTATE_UINT32(kpdk, PXA2xxKeyPadState), - VMSTATE_UINT32(kprec, PXA2xxKeyPadState), - VMSTATE_UINT32(kpmk, PXA2xxKeyPadState), - VMSTATE_UINT32(kpas, PXA2xxKeyPadState), - VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4), - VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState), - VMSTATE_END_OF_LIST() - } -}; - -PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem, - hwaddr base, - qemu_irq irq) -{ - PXA2xxKeyPadState *s; - - s = (PXA2xxKeyPadState *) g_malloc0(sizeof(PXA2xxKeyPadState)); - s->irq = irq; - - memory_region_init_io(&s->iomem, NULL, &pxa2xx_keypad_ops, s, - "pxa2xx-keypad", 0x00100000); - memory_region_add_subregion(sysmem, base, &s->iomem); - - vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s); - - return s; -} - -void pxa27x_register_keypad(PXA2xxKeyPadState *kp, - const struct keymap *map, int size) -{ - if(!map || size < 0x80) { - fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__); - exit(-1); - } - - kp->map = map; - qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp); -} diff --git a/qemu/hw/input/stellaris_input.c b/qemu/hw/input/stellaris_input.c deleted file mode 100644 index 99168bfee..000000000 --- a/qemu/hw/input/stellaris_input.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Gamepad style buttons connected to IRQ/GPIO lines - * - * Copyright (c) 2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/devices.h" -#include "ui/console.h" - -typedef struct { - qemu_irq irq; - int keycode; - uint8_t pressed; -} gamepad_button; - -typedef struct { - gamepad_button *buttons; - int num_buttons; - int extension; -} gamepad_state; - -static void stellaris_gamepad_put_key(void * opaque, int keycode) -{ - gamepad_state *s = (gamepad_state *)opaque; - int i; - int down; - - if (keycode == 0xe0 && !s->extension) { - s->extension = 0x80; - return; - } - - down = (keycode & 0x80) == 0; - keycode = (keycode & 0x7f) | s->extension; - - for (i = 0; i < s->num_buttons; i++) { - if (s->buttons[i].keycode == keycode - && s->buttons[i].pressed != down) { - s->buttons[i].pressed = down; - qemu_set_irq(s->buttons[i].irq, down); - } - } - - s->extension = 0; -} - -static const VMStateDescription vmstate_stellaris_button = { - .name = "stellaris_button", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT8(pressed, gamepad_button), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_stellaris_gamepad = { - .name = "stellaris_gamepad", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(extension, gamepad_state), - VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0, - vmstate_stellaris_button, gamepad_button), - VMSTATE_END_OF_LIST() - } -}; - -/* Returns an array of 5 output slots. */ -void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode) -{ - gamepad_state *s; - int i; - - s = g_new0(gamepad_state, 1); - s->buttons = g_new0(gamepad_button, n); - for (i = 0; i < n; i++) { - s->buttons[i].irq = irq[i]; - s->buttons[i].keycode = keycode[i]; - } - s->num_buttons = n; - qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s); - vmstate_register(NULL, -1, &vmstate_stellaris_gamepad, s); -} diff --git a/qemu/hw/input/tsc2005.c b/qemu/hw/input/tsc2005.c deleted file mode 100644 index 9b359aaec..000000000 --- a/qemu/hw/input/tsc2005.c +++ /dev/null @@ -1,595 +0,0 @@ -/* - * TI TSC2005 emulator. - * - * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org> - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "qemu/timer.h" -#include "ui/console.h" -#include "hw/devices.h" - -#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10))) - -typedef struct { - qemu_irq pint; /* Combination of the nPENIRQ and DAV signals */ - QEMUTimer *timer; - uint16_t model; - - int x, y; - int pressure; - - int state, reg, irq, command; - uint16_t data, dav; - - int busy; - int enabled; - int host_mode; - int function; - int nextfunction; - int precision; - int nextprecision; - int filter; - int pin_func; - int timing[2]; - int noise; - int reset; - int pdst; - int pnd0; - uint16_t temp_thr[2]; - uint16_t aux_thr[2]; - - int tr[8]; -} TSC2005State; - -enum { - TSC_MODE_XYZ_SCAN = 0x0, - TSC_MODE_XY_SCAN, - TSC_MODE_X, - TSC_MODE_Y, - TSC_MODE_Z, - TSC_MODE_AUX, - TSC_MODE_TEMP1, - TSC_MODE_TEMP2, - TSC_MODE_AUX_SCAN, - TSC_MODE_X_TEST, - TSC_MODE_Y_TEST, - TSC_MODE_TS_TEST, - TSC_MODE_RESERVED, - TSC_MODE_XX_DRV, - TSC_MODE_YY_DRV, - TSC_MODE_YX_DRV, -}; - -static const uint16_t mode_regs[16] = { - 0xf000, /* X, Y, Z scan */ - 0xc000, /* X, Y scan */ - 0x8000, /* X */ - 0x4000, /* Y */ - 0x3000, /* Z */ - 0x0800, /* AUX */ - 0x0400, /* TEMP1 */ - 0x0200, /* TEMP2 */ - 0x0800, /* AUX scan */ - 0x0040, /* X test */ - 0x0020, /* Y test */ - 0x0080, /* Short-circuit test */ - 0x0000, /* Reserved */ - 0x0000, /* X+, X- drivers */ - 0x0000, /* Y+, Y- drivers */ - 0x0000, /* Y+, X- drivers */ -}; - -#define X_TRANSFORM(s) \ - ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3]) -#define Y_TRANSFORM(s) \ - ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7]) -#define Z1_TRANSFORM(s) \ - ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4) -#define Z2_TRANSFORM(s) \ - ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4) - -#define AUX_VAL (700 << 4) /* +/- 3 at 12-bit */ -#define TEMP1_VAL (1264 << 4) /* +/- 5 at 12-bit */ -#define TEMP2_VAL (1531 << 4) /* +/- 5 at 12-bit */ - -static uint16_t tsc2005_read(TSC2005State *s, int reg) -{ - uint16_t ret; - - switch (reg) { - case 0x0: /* X */ - s->dav &= ~mode_regs[TSC_MODE_X]; - return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) + - (s->noise & 3); - case 0x1: /* Y */ - s->dav &= ~mode_regs[TSC_MODE_Y]; - s->noise ++; - return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^ - (s->noise & 3); - case 0x2: /* Z1 */ - s->dav &= 0xdfff; - return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) - - (s->noise & 3); - case 0x3: /* Z2 */ - s->dav &= 0xefff; - return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) | - (s->noise & 3); - - case 0x4: /* AUX */ - s->dav &= ~mode_regs[TSC_MODE_AUX]; - return TSC_CUT_RESOLUTION(AUX_VAL, s->precision); - - case 0x5: /* TEMP1 */ - s->dav &= ~mode_regs[TSC_MODE_TEMP1]; - return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) - - (s->noise & 5); - case 0x6: /* TEMP2 */ - s->dav &= 0xdfff; - s->dav &= ~mode_regs[TSC_MODE_TEMP2]; - return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^ - (s->noise & 3); - - case 0x7: /* Status */ - ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0; - s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] | - mode_regs[TSC_MODE_TS_TEST]); - s->reset = 1; - return ret; - - case 0x8: /* AUX high treshold */ - return s->aux_thr[1]; - case 0x9: /* AUX low treshold */ - return s->aux_thr[0]; - - case 0xa: /* TEMP high treshold */ - return s->temp_thr[1]; - case 0xb: /* TEMP low treshold */ - return s->temp_thr[0]; - - case 0xc: /* CFR0 */ - return (s->pressure << 15) | ((!s->busy) << 14) | - (s->nextprecision << 13) | s->timing[0]; - case 0xd: /* CFR1 */ - return s->timing[1]; - case 0xe: /* CFR2 */ - return (s->pin_func << 14) | s->filter; - - case 0xf: /* Function select status */ - return s->function >= 0 ? 1 << s->function : 0; - } - - /* Never gets here */ - return 0xffff; -} - -static void tsc2005_write(TSC2005State *s, int reg, uint16_t data) -{ - switch (reg) { - case 0x8: /* AUX high treshold */ - s->aux_thr[1] = data; - break; - case 0x9: /* AUX low treshold */ - s->aux_thr[0] = data; - break; - - case 0xa: /* TEMP high treshold */ - s->temp_thr[1] = data; - break; - case 0xb: /* TEMP low treshold */ - s->temp_thr[0] = data; - break; - - case 0xc: /* CFR0 */ - s->host_mode = data >> 15; - if (s->enabled != !(data & 0x4000)) { - s->enabled = !(data & 0x4000); - fprintf(stderr, "%s: touchscreen sense %sabled\n", - __FUNCTION__, s->enabled ? "en" : "dis"); - if (s->busy && !s->enabled) - timer_del(s->timer); - s->busy &= s->enabled; - } - s->nextprecision = (data >> 13) & 1; - s->timing[0] = data & 0x1fff; - if ((s->timing[0] >> 11) == 3) - fprintf(stderr, "%s: illegal conversion clock setting\n", - __FUNCTION__); - break; - case 0xd: /* CFR1 */ - s->timing[1] = data & 0xf07; - break; - case 0xe: /* CFR2 */ - s->pin_func = (data >> 14) & 3; - s->filter = data & 0x3fff; - break; - - default: - fprintf(stderr, "%s: write into read-only register %x\n", - __FUNCTION__, reg); - } -} - -/* This handles most of the chip's logic. */ -static void tsc2005_pin_update(TSC2005State *s) -{ - int64_t expires; - int pin_state; - - switch (s->pin_func) { - case 0: - pin_state = !s->pressure && !!s->dav; - break; - case 1: - case 3: - default: - pin_state = !s->dav; - break; - case 2: - pin_state = !s->pressure; - } - - if (pin_state != s->irq) { - s->irq = pin_state; - qemu_set_irq(s->pint, s->irq); - } - - switch (s->nextfunction) { - case TSC_MODE_XYZ_SCAN: - case TSC_MODE_XY_SCAN: - if (!s->host_mode && s->dav) - s->enabled = 0; - if (!s->pressure) - return; - /* Fall through */ - case TSC_MODE_AUX_SCAN: - break; - - case TSC_MODE_X: - case TSC_MODE_Y: - case TSC_MODE_Z: - if (!s->pressure) - return; - /* Fall through */ - case TSC_MODE_AUX: - case TSC_MODE_TEMP1: - case TSC_MODE_TEMP2: - case TSC_MODE_X_TEST: - case TSC_MODE_Y_TEST: - case TSC_MODE_TS_TEST: - if (s->dav) - s->enabled = 0; - break; - - case TSC_MODE_RESERVED: - case TSC_MODE_XX_DRV: - case TSC_MODE_YY_DRV: - case TSC_MODE_YX_DRV: - default: - return; - } - - if (!s->enabled || s->busy) - return; - - s->busy = 1; - s->precision = s->nextprecision; - s->function = s->nextfunction; - s->pdst = !s->pnd0; /* Synchronised on internal clock */ - expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - (NANOSECONDS_PER_SECOND >> 7); - timer_mod(s->timer, expires); -} - -static void tsc2005_reset(TSC2005State *s) -{ - s->state = 0; - s->pin_func = 0; - s->enabled = 0; - s->busy = 0; - s->nextprecision = 0; - s->nextfunction = 0; - s->timing[0] = 0; - s->timing[1] = 0; - s->irq = 0; - s->dav = 0; - s->reset = 0; - s->pdst = 1; - s->pnd0 = 0; - s->function = -1; - s->temp_thr[0] = 0x000; - s->temp_thr[1] = 0xfff; - s->aux_thr[0] = 0x000; - s->aux_thr[1] = 0xfff; - - tsc2005_pin_update(s); -} - -static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value) -{ - TSC2005State *s = opaque; - uint32_t ret = 0; - - switch (s->state ++) { - case 0: - if (value & 0x80) { - /* Command */ - if (value & (1 << 1)) - tsc2005_reset(s); - else { - s->nextfunction = (value >> 3) & 0xf; - s->nextprecision = (value >> 2) & 1; - if (s->enabled != !(value & 1)) { - s->enabled = !(value & 1); - fprintf(stderr, "%s: touchscreen sense %sabled\n", - __FUNCTION__, s->enabled ? "en" : "dis"); - if (s->busy && !s->enabled) - timer_del(s->timer); - s->busy &= s->enabled; - } - tsc2005_pin_update(s); - } - - s->state = 0; - } else if (value) { - /* Data transfer */ - s->reg = (value >> 3) & 0xf; - s->pnd0 = (value >> 1) & 1; - s->command = value & 1; - - if (s->command) { - /* Read */ - s->data = tsc2005_read(s, s->reg); - tsc2005_pin_update(s); - } else - s->data = 0; - } else - s->state = 0; - break; - - case 1: - if (s->command) - ret = (s->data >> 8) & 0xff; - else - s->data |= value << 8; - break; - - case 2: - if (s->command) - ret = s->data & 0xff; - else { - s->data |= value; - tsc2005_write(s, s->reg, s->data); - tsc2005_pin_update(s); - } - - s->state = 0; - break; - } - - return ret; -} - -uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len) -{ - uint32_t ret = 0; - - len &= ~7; - while (len > 0) { - len -= 8; - ret |= tsc2005_txrx_word(opaque, (value >> len) & 0xff) << len; - } - - return ret; -} - -static void tsc2005_timer_tick(void *opaque) -{ - TSC2005State *s = opaque; - - /* Timer ticked -- a set of conversions has been finished. */ - - if (!s->busy) - return; - - s->busy = 0; - s->dav |= mode_regs[s->function]; - s->function = -1; - tsc2005_pin_update(s); -} - -static void tsc2005_touchscreen_event(void *opaque, - int x, int y, int z, int buttons_state) -{ - TSC2005State *s = opaque; - int p = s->pressure; - - if (buttons_state) { - s->x = x; - s->y = y; - } - s->pressure = !!buttons_state; - - /* - * Note: We would get better responsiveness in the guest by - * signaling TS events immediately, but for now we simulate - * the first conversion delay for sake of correctness. - */ - if (p != s->pressure) - tsc2005_pin_update(s); -} - -static void tsc2005_save(QEMUFile *f, void *opaque) -{ - TSC2005State *s = (TSC2005State *) opaque; - int i; - - qemu_put_be16(f, s->x); - qemu_put_be16(f, s->y); - qemu_put_byte(f, s->pressure); - - qemu_put_byte(f, s->state); - qemu_put_byte(f, s->reg); - qemu_put_byte(f, s->command); - - qemu_put_byte(f, s->irq); - qemu_put_be16s(f, &s->dav); - qemu_put_be16s(f, &s->data); - - timer_put(f, s->timer); - qemu_put_byte(f, s->enabled); - qemu_put_byte(f, s->host_mode); - qemu_put_byte(f, s->function); - qemu_put_byte(f, s->nextfunction); - qemu_put_byte(f, s->precision); - qemu_put_byte(f, s->nextprecision); - qemu_put_be16(f, s->filter); - qemu_put_byte(f, s->pin_func); - qemu_put_be16(f, s->timing[0]); - qemu_put_be16(f, s->timing[1]); - qemu_put_be16s(f, &s->temp_thr[0]); - qemu_put_be16s(f, &s->temp_thr[1]); - qemu_put_be16s(f, &s->aux_thr[0]); - qemu_put_be16s(f, &s->aux_thr[1]); - qemu_put_be32(f, s->noise); - qemu_put_byte(f, s->reset); - qemu_put_byte(f, s->pdst); - qemu_put_byte(f, s->pnd0); - - for (i = 0; i < 8; i ++) - qemu_put_be32(f, s->tr[i]); -} - -static int tsc2005_load(QEMUFile *f, void *opaque, int version_id) -{ - TSC2005State *s = (TSC2005State *) opaque; - int i; - - s->x = qemu_get_be16(f); - s->y = qemu_get_be16(f); - s->pressure = qemu_get_byte(f); - - s->state = qemu_get_byte(f); - s->reg = qemu_get_byte(f); - s->command = qemu_get_byte(f); - - s->irq = qemu_get_byte(f); - qemu_get_be16s(f, &s->dav); - qemu_get_be16s(f, &s->data); - - timer_get(f, s->timer); - s->enabled = qemu_get_byte(f); - s->host_mode = qemu_get_byte(f); - s->function = qemu_get_byte(f); - s->nextfunction = qemu_get_byte(f); - s->precision = qemu_get_byte(f); - s->nextprecision = qemu_get_byte(f); - s->filter = qemu_get_be16(f); - s->pin_func = qemu_get_byte(f); - s->timing[0] = qemu_get_be16(f); - s->timing[1] = qemu_get_be16(f); - qemu_get_be16s(f, &s->temp_thr[0]); - qemu_get_be16s(f, &s->temp_thr[1]); - qemu_get_be16s(f, &s->aux_thr[0]); - qemu_get_be16s(f, &s->aux_thr[1]); - s->noise = qemu_get_be32(f); - s->reset = qemu_get_byte(f); - s->pdst = qemu_get_byte(f); - s->pnd0 = qemu_get_byte(f); - - for (i = 0; i < 8; i ++) - s->tr[i] = qemu_get_be32(f); - - s->busy = timer_pending(s->timer); - tsc2005_pin_update(s); - - return 0; -} - -void *tsc2005_init(qemu_irq pintdav) -{ - TSC2005State *s; - - s = (TSC2005State *) - g_malloc0(sizeof(TSC2005State)); - s->x = 400; - s->y = 240; - s->pressure = 0; - s->precision = s->nextprecision = 0; - s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s); - s->pint = pintdav; - s->model = 0x2005; - - s->tr[0] = 0; - s->tr[1] = 1; - s->tr[2] = 1; - s->tr[3] = 0; - s->tr[4] = 1; - s->tr[5] = 0; - s->tr[6] = 1; - s->tr[7] = 0; - - tsc2005_reset(s); - - qemu_add_mouse_event_handler(tsc2005_touchscreen_event, s, 1, - "QEMU TSC2005-driven Touchscreen"); - - qemu_register_reset((void *) tsc2005_reset, s); - register_savevm(NULL, "tsc2005", -1, 0, tsc2005_save, tsc2005_load, s); - - return s; -} - -/* - * Use tslib generated calibration data to generate ADC input values - * from the touchscreen. Assuming 12-bit precision was used during - * tslib calibration. - */ -void tsc2005_set_transform(void *opaque, MouseTransformInfo *info) -{ - TSC2005State *s = (TSC2005State *) opaque; - - /* This version assumes touchscreen X & Y axis are parallel or - * perpendicular to LCD's X & Y axis in some way. */ - if (abs(info->a[0]) > abs(info->a[1])) { - s->tr[0] = 0; - s->tr[1] = -info->a[6] * info->x; - s->tr[2] = info->a[0]; - s->tr[3] = -info->a[2] / info->a[0]; - s->tr[4] = info->a[6] * info->y; - s->tr[5] = 0; - s->tr[6] = info->a[4]; - s->tr[7] = -info->a[5] / info->a[4]; - } else { - s->tr[0] = info->a[6] * info->y; - s->tr[1] = 0; - s->tr[2] = info->a[1]; - s->tr[3] = -info->a[2] / info->a[1]; - s->tr[4] = 0; - s->tr[5] = -info->a[6] * info->x; - s->tr[6] = info->a[3]; - s->tr[7] = -info->a[5] / info->a[3]; - } - - s->tr[0] >>= 11; - s->tr[1] >>= 11; - s->tr[3] <<= 4; - s->tr[4] >>= 11; - s->tr[5] >>= 11; - s->tr[7] <<= 4; -} diff --git a/qemu/hw/input/tsc210x.c b/qemu/hw/input/tsc210x.c deleted file mode 100644 index 93ca374fc..000000000 --- a/qemu/hw/input/tsc210x.c +++ /dev/null @@ -1,1273 +0,0 @@ -/* - * TI TSC2102 (touchscreen/sensors/audio controller) emulator. - * TI TSC2301 (touchscreen/sensors/keypad). - * - * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org> - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "audio/audio.h" -#include "qemu/timer.h" -#include "ui/console.h" -#include "hw/arm/omap.h" /* For I2SCodec and uWireSlave */ -#include "hw/devices.h" - -#define TSC_DATA_REGISTERS_PAGE 0x0 -#define TSC_CONTROL_REGISTERS_PAGE 0x1 -#define TSC_AUDIO_REGISTERS_PAGE 0x2 - -#define TSC_VERBOSE - -#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - resolution[p])) - -typedef struct { - qemu_irq pint; - qemu_irq kbint; - qemu_irq davint; - QEMUTimer *timer; - QEMUSoundCard card; - uWireSlave chip; - I2SCodec codec; - uint8_t in_fifo[16384]; - uint8_t out_fifo[16384]; - uint16_t model; - - int x, y; - int pressure; - - int state, page, offset, irq; - uint16_t command, dav; - - int busy; - int enabled; - int host_mode; - int function; - int nextfunction; - int precision; - int nextprecision; - int filter; - int pin_func; - int ref; - int timing; - int noise; - - uint16_t audio_ctrl1; - uint16_t audio_ctrl2; - uint16_t audio_ctrl3; - uint16_t pll[3]; - uint16_t volume; - int64_t volume_change; - int softstep; - uint16_t dac_power; - int64_t powerdown; - uint16_t filter_data[0x14]; - - const char *name; - SWVoiceIn *adc_voice[1]; - SWVoiceOut *dac_voice[1]; - int i2s_rx_rate; - int i2s_tx_rate; - - int tr[8]; - - struct { - uint16_t down; - uint16_t mask; - int scan; - int debounce; - int mode; - int intr; - } kb; -} TSC210xState; - -static const int resolution[4] = { 12, 8, 10, 12 }; - -#define TSC_MODE_NO_SCAN 0x0 -#define TSC_MODE_XY_SCAN 0x1 -#define TSC_MODE_XYZ_SCAN 0x2 -#define TSC_MODE_X 0x3 -#define TSC_MODE_Y 0x4 -#define TSC_MODE_Z 0x5 -#define TSC_MODE_BAT1 0x6 -#define TSC_MODE_BAT2 0x7 -#define TSC_MODE_AUX 0x8 -#define TSC_MODE_AUX_SCAN 0x9 -#define TSC_MODE_TEMP1 0xa -#define TSC_MODE_PORT_SCAN 0xb -#define TSC_MODE_TEMP2 0xc -#define TSC_MODE_XX_DRV 0xd -#define TSC_MODE_YY_DRV 0xe -#define TSC_MODE_YX_DRV 0xf - -static const uint16_t mode_regs[16] = { - 0x0000, /* No scan */ - 0x0600, /* X, Y scan */ - 0x0780, /* X, Y, Z scan */ - 0x0400, /* X */ - 0x0200, /* Y */ - 0x0180, /* Z */ - 0x0040, /* BAT1 */ - 0x0030, /* BAT2 */ - 0x0010, /* AUX */ - 0x0010, /* AUX scan */ - 0x0004, /* TEMP1 */ - 0x0070, /* Port scan */ - 0x0002, /* TEMP2 */ - 0x0000, /* X+, X- drivers */ - 0x0000, /* Y+, Y- drivers */ - 0x0000, /* Y+, X- drivers */ -}; - -#define X_TRANSFORM(s) \ - ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3]) -#define Y_TRANSFORM(s) \ - ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7]) -#define Z1_TRANSFORM(s) \ - ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4) -#define Z2_TRANSFORM(s) \ - ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4) - -#define BAT1_VAL 0x8660 -#define BAT2_VAL 0x0000 -#define AUX1_VAL 0x35c0 -#define AUX2_VAL 0xffff -#define TEMP1_VAL 0x8c70 -#define TEMP2_VAL 0xa5b0 - -#define TSC_POWEROFF_DELAY 50 -#define TSC_SOFTSTEP_DELAY 50 - -static void tsc210x_reset(TSC210xState *s) -{ - s->state = 0; - s->pin_func = 2; - s->enabled = 0; - s->busy = 0; - s->nextfunction = 0; - s->ref = 0; - s->timing = 0; - s->irq = 0; - s->dav = 0; - - s->audio_ctrl1 = 0x0000; - s->audio_ctrl2 = 0x4410; - s->audio_ctrl3 = 0x0000; - s->pll[0] = 0x1004; - s->pll[1] = 0x0000; - s->pll[2] = 0x1fff; - s->volume = 0xffff; - s->dac_power = 0x8540; - s->softstep = 1; - s->volume_change = 0; - s->powerdown = 0; - s->filter_data[0x00] = 0x6be3; - s->filter_data[0x01] = 0x9666; - s->filter_data[0x02] = 0x675d; - s->filter_data[0x03] = 0x6be3; - s->filter_data[0x04] = 0x9666; - s->filter_data[0x05] = 0x675d; - s->filter_data[0x06] = 0x7d83; - s->filter_data[0x07] = 0x84ee; - s->filter_data[0x08] = 0x7d83; - s->filter_data[0x09] = 0x84ee; - s->filter_data[0x0a] = 0x6be3; - s->filter_data[0x0b] = 0x9666; - s->filter_data[0x0c] = 0x675d; - s->filter_data[0x0d] = 0x6be3; - s->filter_data[0x0e] = 0x9666; - s->filter_data[0x0f] = 0x675d; - s->filter_data[0x10] = 0x7d83; - s->filter_data[0x11] = 0x84ee; - s->filter_data[0x12] = 0x7d83; - s->filter_data[0x13] = 0x84ee; - - s->i2s_tx_rate = 0; - s->i2s_rx_rate = 0; - - s->kb.scan = 1; - s->kb.debounce = 0; - s->kb.mask = 0x0000; - s->kb.mode = 3; - s->kb.intr = 0; - - qemu_set_irq(s->pint, !s->irq); - qemu_set_irq(s->davint, !s->dav); - qemu_irq_raise(s->kbint); -} - -typedef struct { - int rate; - int dsor; - int fsref; -} TSC210xRateInfo; - -/* { rate, dsor, fsref } */ -static const TSC210xRateInfo tsc2102_rates[] = { - /* Fsref / 6.0 */ - { 7350, 63, 1 }, - { 8000, 63, 0 }, - /* Fsref / 6.0 */ - { 7350, 54, 1 }, - { 8000, 54, 0 }, - /* Fsref / 5.0 */ - { 8820, 45, 1 }, - { 9600, 45, 0 }, - /* Fsref / 4.0 */ - { 11025, 36, 1 }, - { 12000, 36, 0 }, - /* Fsref / 3.0 */ - { 14700, 27, 1 }, - { 16000, 27, 0 }, - /* Fsref / 2.0 */ - { 22050, 18, 1 }, - { 24000, 18, 0 }, - /* Fsref / 1.5 */ - { 29400, 9, 1 }, - { 32000, 9, 0 }, - /* Fsref */ - { 44100, 0, 1 }, - { 48000, 0, 0 }, - - { 0, 0, 0 }, -}; - -static inline void tsc210x_out_flush(TSC210xState *s, int len) -{ - uint8_t *data = s->codec.out.fifo + s->codec.out.start; - uint8_t *end = data + len; - - while (data < end) - data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data); - - s->codec.out.len -= len; - if (s->codec.out.len) - memmove(s->codec.out.fifo, end, s->codec.out.len); - s->codec.out.start = 0; -} - -static void tsc210x_audio_out_cb(TSC210xState *s, int free_b) -{ - if (s->codec.out.len >= free_b) { - tsc210x_out_flush(s, free_b); - return; - } - - s->codec.out.size = MIN(free_b, 16384); - qemu_irq_raise(s->codec.tx_start); -} - -static void tsc2102_audio_rate_update(TSC210xState *s) -{ - const TSC210xRateInfo *rate; - - s->codec.tx_rate = 0; - s->codec.rx_rate = 0; - if (s->dac_power & (1 << 15)) /* PWDNC */ - return; - - for (rate = tsc2102_rates; rate->rate; rate ++) - if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */ - rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */ - break; - if (!rate->rate) { - printf("%s: unknown sampling rate configured\n", __FUNCTION__); - return; - } - - s->codec.tx_rate = rate->rate; -} - -static void tsc2102_audio_output_update(TSC210xState *s) -{ - int enable; - struct audsettings fmt; - - if (s->dac_voice[0]) { - tsc210x_out_flush(s, s->codec.out.len); - s->codec.out.size = 0; - AUD_set_active_out(s->dac_voice[0], 0); - AUD_close_out(&s->card, s->dac_voice[0]); - s->dac_voice[0] = NULL; - } - s->codec.cts = 0; - - enable = - (~s->dac_power & (1 << 15)) && /* PWDNC */ - (~s->dac_power & (1 << 10)); /* DAPWDN */ - if (!enable || !s->codec.tx_rate) - return; - - /* Force our own sampling rate even in slave DAC mode */ - fmt.endianness = 0; - fmt.nchannels = 2; - fmt.freq = s->codec.tx_rate; - fmt.fmt = AUD_FMT_S16; - - s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0], - "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt); - if (s->dac_voice[0]) { - s->codec.cts = 1; - AUD_set_active_out(s->dac_voice[0], 1); - } -} - -static uint16_t tsc2102_data_register_read(TSC210xState *s, int reg) -{ - switch (reg) { - case 0x00: /* X */ - s->dav &= 0xfbff; - return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) + - (s->noise & 3); - - case 0x01: /* Y */ - s->noise ++; - s->dav &= 0xfdff; - return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^ - (s->noise & 3); - - case 0x02: /* Z1 */ - s->dav &= 0xfeff; - return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) - - (s->noise & 3); - - case 0x03: /* Z2 */ - s->dav &= 0xff7f; - return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) | - (s->noise & 3); - - case 0x04: /* KPData */ - if ((s->model & 0xff00) == 0x2300) { - if (s->kb.intr && (s->kb.mode & 2)) { - s->kb.intr = 0; - qemu_irq_raise(s->kbint); - } - return s->kb.down; - } - - return 0xffff; - - case 0x05: /* BAT1 */ - s->dav &= 0xffbf; - return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision) + - (s->noise & 6); - - case 0x06: /* BAT2 */ - s->dav &= 0xffdf; - return TSC_CUT_RESOLUTION(BAT2_VAL, s->precision); - - case 0x07: /* AUX1 */ - s->dav &= 0xffef; - return TSC_CUT_RESOLUTION(AUX1_VAL, s->precision); - - case 0x08: /* AUX2 */ - s->dav &= 0xfff7; - return 0xffff; - - case 0x09: /* TEMP1 */ - s->dav &= 0xfffb; - return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) - - (s->noise & 5); - - case 0x0a: /* TEMP2 */ - s->dav &= 0xfffd; - return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^ - (s->noise & 3); - - case 0x0b: /* DAC */ - s->dav &= 0xfffe; - return 0xffff; - - default: -#ifdef TSC_VERBOSE - fprintf(stderr, "tsc2102_data_register_read: " - "no such register: 0x%02x\n", reg); -#endif - return 0xffff; - } -} - -static uint16_t tsc2102_control_register_read( - TSC210xState *s, int reg) -{ - switch (reg) { - case 0x00: /* TSC ADC */ - return (s->pressure << 15) | ((!s->busy) << 14) | - (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter; - - case 0x01: /* Status / Keypad Control */ - if ((s->model & 0xff00) == 0x2100) - return (s->pin_func << 14) | ((!s->enabled) << 13) | - (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav; - else - return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) | - (s->kb.debounce << 11); - - case 0x02: /* DAC Control */ - if ((s->model & 0xff00) == 0x2300) - return s->dac_power & 0x8000; - else - goto bad_reg; - - case 0x03: /* Reference */ - return s->ref; - - case 0x04: /* Reset */ - return 0xffff; - - case 0x05: /* Configuration */ - return s->timing; - - case 0x06: /* Secondary configuration */ - if ((s->model & 0xff00) == 0x2100) - goto bad_reg; - return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2]; - - case 0x10: /* Keypad Mask */ - if ((s->model & 0xff00) == 0x2100) - goto bad_reg; - return s->kb.mask; - - default: - bad_reg: -#ifdef TSC_VERBOSE - fprintf(stderr, "tsc2102_control_register_read: " - "no such register: 0x%02x\n", reg); -#endif - return 0xffff; - } -} - -static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg) -{ - int l_ch, r_ch; - uint16_t val; - - switch (reg) { - case 0x00: /* Audio Control 1 */ - return s->audio_ctrl1; - - case 0x01: - return 0xff00; - - case 0x02: /* DAC Volume Control */ - return s->volume; - - case 0x03: - return 0x8b00; - - case 0x04: /* Audio Control 2 */ - l_ch = 1; - r_ch = 1; - if (s->softstep && !(s->dac_power & (1 << 10))) { - l_ch = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) > - s->volume_change + TSC_SOFTSTEP_DELAY); - r_ch = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) > - s->volume_change + TSC_SOFTSTEP_DELAY); - } - - return s->audio_ctrl2 | (l_ch << 3) | (r_ch << 2); - - case 0x05: /* Stereo DAC Power Control */ - return 0x2aa0 | s->dac_power | - (((s->dac_power & (1 << 10)) && - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) > - s->powerdown + TSC_POWEROFF_DELAY)) << 6); - - case 0x06: /* Audio Control 3 */ - val = s->audio_ctrl3 | 0x0001; - s->audio_ctrl3 &= 0xff3f; - return val; - - case 0x07: /* LCH_BASS_BOOST_N0 */ - case 0x08: /* LCH_BASS_BOOST_N1 */ - case 0x09: /* LCH_BASS_BOOST_N2 */ - case 0x0a: /* LCH_BASS_BOOST_N3 */ - case 0x0b: /* LCH_BASS_BOOST_N4 */ - case 0x0c: /* LCH_BASS_BOOST_N5 */ - case 0x0d: /* LCH_BASS_BOOST_D1 */ - case 0x0e: /* LCH_BASS_BOOST_D2 */ - case 0x0f: /* LCH_BASS_BOOST_D4 */ - case 0x10: /* LCH_BASS_BOOST_D5 */ - case 0x11: /* RCH_BASS_BOOST_N0 */ - case 0x12: /* RCH_BASS_BOOST_N1 */ - case 0x13: /* RCH_BASS_BOOST_N2 */ - case 0x14: /* RCH_BASS_BOOST_N3 */ - case 0x15: /* RCH_BASS_BOOST_N4 */ - case 0x16: /* RCH_BASS_BOOST_N5 */ - case 0x17: /* RCH_BASS_BOOST_D1 */ - case 0x18: /* RCH_BASS_BOOST_D2 */ - case 0x19: /* RCH_BASS_BOOST_D4 */ - case 0x1a: /* RCH_BASS_BOOST_D5 */ - return s->filter_data[reg - 0x07]; - - case 0x1b: /* PLL Programmability 1 */ - return s->pll[0]; - - case 0x1c: /* PLL Programmability 2 */ - return s->pll[1]; - - case 0x1d: /* Audio Control 4 */ - return (!s->softstep) << 14; - - default: -#ifdef TSC_VERBOSE - fprintf(stderr, "tsc2102_audio_register_read: " - "no such register: 0x%02x\n", reg); -#endif - return 0xffff; - } -} - -static void tsc2102_data_register_write( - TSC210xState *s, int reg, uint16_t value) -{ - switch (reg) { - case 0x00: /* X */ - case 0x01: /* Y */ - case 0x02: /* Z1 */ - case 0x03: /* Z2 */ - case 0x05: /* BAT1 */ - case 0x06: /* BAT2 */ - case 0x07: /* AUX1 */ - case 0x08: /* AUX2 */ - case 0x09: /* TEMP1 */ - case 0x0a: /* TEMP2 */ - return; - - default: -#ifdef TSC_VERBOSE - fprintf(stderr, "tsc2102_data_register_write: " - "no such register: 0x%02x\n", reg); -#endif - } -} - -static void tsc2102_control_register_write( - TSC210xState *s, int reg, uint16_t value) -{ - switch (reg) { - case 0x00: /* TSC ADC */ - s->host_mode = value >> 15; - s->enabled = !(value & 0x4000); - if (s->busy && !s->enabled) - timer_del(s->timer); - s->busy &= s->enabled; - s->nextfunction = (value >> 10) & 0xf; - s->nextprecision = (value >> 8) & 3; - s->filter = value & 0xff; - return; - - case 0x01: /* Status / Keypad Control */ - if ((s->model & 0xff00) == 0x2100) - s->pin_func = value >> 14; - else { - s->kb.scan = (value >> 14) & 1; - s->kb.debounce = (value >> 11) & 7; - if (s->kb.intr && s->kb.scan) { - s->kb.intr = 0; - qemu_irq_raise(s->kbint); - } - } - return; - - case 0x02: /* DAC Control */ - if ((s->model & 0xff00) == 0x2300) { - s->dac_power &= 0x7fff; - s->dac_power |= 0x8000 & value; - } else - goto bad_reg; - break; - - case 0x03: /* Reference */ - s->ref = value & 0x1f; - return; - - case 0x04: /* Reset */ - if (value == 0xbb00) { - if (s->busy) - timer_del(s->timer); - tsc210x_reset(s); -#ifdef TSC_VERBOSE - } else { - fprintf(stderr, "tsc2102_control_register_write: " - "wrong value written into RESET\n"); -#endif - } - return; - - case 0x05: /* Configuration */ - s->timing = value & 0x3f; -#ifdef TSC_VERBOSE - if (value & ~0x3f) - fprintf(stderr, "tsc2102_control_register_write: " - "wrong value written into CONFIG\n"); -#endif - return; - - case 0x06: /* Secondary configuration */ - if ((s->model & 0xff00) == 0x2100) - goto bad_reg; - s->kb.mode = value >> 14; - s->pll[2] = value & 0x3ffff; - return; - - case 0x10: /* Keypad Mask */ - if ((s->model & 0xff00) == 0x2100) - goto bad_reg; - s->kb.mask = value; - return; - - default: - bad_reg: -#ifdef TSC_VERBOSE - fprintf(stderr, "tsc2102_control_register_write: " - "no such register: 0x%02x\n", reg); -#endif - } -} - -static void tsc2102_audio_register_write( - TSC210xState *s, int reg, uint16_t value) -{ - switch (reg) { - case 0x00: /* Audio Control 1 */ - s->audio_ctrl1 = value & 0x0f3f; -#ifdef TSC_VERBOSE - if ((value & ~0x0f3f) || ((value & 7) != ((value >> 3) & 7))) - fprintf(stderr, "tsc2102_audio_register_write: " - "wrong value written into Audio 1\n"); -#endif - tsc2102_audio_rate_update(s); - tsc2102_audio_output_update(s); - return; - - case 0x01: -#ifdef TSC_VERBOSE - if (value != 0xff00) - fprintf(stderr, "tsc2102_audio_register_write: " - "wrong value written into reg 0x01\n"); -#endif - return; - - case 0x02: /* DAC Volume Control */ - s->volume = value; - s->volume_change = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - return; - - case 0x03: -#ifdef TSC_VERBOSE - if (value != 0x8b00) - fprintf(stderr, "tsc2102_audio_register_write: " - "wrong value written into reg 0x03\n"); -#endif - return; - - case 0x04: /* Audio Control 2 */ - s->audio_ctrl2 = value & 0xf7f2; -#ifdef TSC_VERBOSE - if (value & ~0xf7fd) - fprintf(stderr, "tsc2102_audio_register_write: " - "wrong value written into Audio 2\n"); -#endif - return; - - case 0x05: /* Stereo DAC Power Control */ - if ((value & ~s->dac_power) & (1 << 10)) - s->powerdown = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - - s->dac_power = value & 0x9543; -#ifdef TSC_VERBOSE - if ((value & ~0x9543) != 0x2aa0) - fprintf(stderr, "tsc2102_audio_register_write: " - "wrong value written into Power\n"); -#endif - tsc2102_audio_rate_update(s); - tsc2102_audio_output_update(s); - return; - - case 0x06: /* Audio Control 3 */ - s->audio_ctrl3 &= 0x00c0; - s->audio_ctrl3 |= value & 0xf800; -#ifdef TSC_VERBOSE - if (value & ~0xf8c7) - fprintf(stderr, "tsc2102_audio_register_write: " - "wrong value written into Audio 3\n"); -#endif - tsc2102_audio_output_update(s); - return; - - case 0x07: /* LCH_BASS_BOOST_N0 */ - case 0x08: /* LCH_BASS_BOOST_N1 */ - case 0x09: /* LCH_BASS_BOOST_N2 */ - case 0x0a: /* LCH_BASS_BOOST_N3 */ - case 0x0b: /* LCH_BASS_BOOST_N4 */ - case 0x0c: /* LCH_BASS_BOOST_N5 */ - case 0x0d: /* LCH_BASS_BOOST_D1 */ - case 0x0e: /* LCH_BASS_BOOST_D2 */ - case 0x0f: /* LCH_BASS_BOOST_D4 */ - case 0x10: /* LCH_BASS_BOOST_D5 */ - case 0x11: /* RCH_BASS_BOOST_N0 */ - case 0x12: /* RCH_BASS_BOOST_N1 */ - case 0x13: /* RCH_BASS_BOOST_N2 */ - case 0x14: /* RCH_BASS_BOOST_N3 */ - case 0x15: /* RCH_BASS_BOOST_N4 */ - case 0x16: /* RCH_BASS_BOOST_N5 */ - case 0x17: /* RCH_BASS_BOOST_D1 */ - case 0x18: /* RCH_BASS_BOOST_D2 */ - case 0x19: /* RCH_BASS_BOOST_D4 */ - case 0x1a: /* RCH_BASS_BOOST_D5 */ - s->filter_data[reg - 0x07] = value; - return; - - case 0x1b: /* PLL Programmability 1 */ - s->pll[0] = value & 0xfffc; -#ifdef TSC_VERBOSE - if (value & ~0xfffc) - fprintf(stderr, "tsc2102_audio_register_write: " - "wrong value written into PLL 1\n"); -#endif - return; - - case 0x1c: /* PLL Programmability 2 */ - s->pll[1] = value & 0xfffc; -#ifdef TSC_VERBOSE - if (value & ~0xfffc) - fprintf(stderr, "tsc2102_audio_register_write: " - "wrong value written into PLL 2\n"); -#endif - return; - - case 0x1d: /* Audio Control 4 */ - s->softstep = !(value & 0x4000); -#ifdef TSC_VERBOSE - if (value & ~0x4000) - fprintf(stderr, "tsc2102_audio_register_write: " - "wrong value written into Audio 4\n"); -#endif - return; - - default: -#ifdef TSC_VERBOSE - fprintf(stderr, "tsc2102_audio_register_write: " - "no such register: 0x%02x\n", reg); -#endif - } -} - -/* This handles most of the chip logic. */ -static void tsc210x_pin_update(TSC210xState *s) -{ - int64_t expires; - int pin_state; - - switch (s->pin_func) { - case 0: - pin_state = s->pressure; - break; - case 1: - pin_state = !!s->dav; - break; - case 2: - default: - pin_state = s->pressure && !s->dav; - } - - if (!s->enabled) - pin_state = 0; - - if (pin_state != s->irq) { - s->irq = pin_state; - qemu_set_irq(s->pint, !s->irq); - } - - switch (s->nextfunction) { - case TSC_MODE_XY_SCAN: - case TSC_MODE_XYZ_SCAN: - if (!s->pressure) - return; - break; - - case TSC_MODE_X: - case TSC_MODE_Y: - case TSC_MODE_Z: - if (!s->pressure) - return; - /* Fall through */ - case TSC_MODE_BAT1: - case TSC_MODE_BAT2: - case TSC_MODE_AUX: - case TSC_MODE_TEMP1: - case TSC_MODE_TEMP2: - if (s->dav) - s->enabled = 0; - break; - - case TSC_MODE_AUX_SCAN: - case TSC_MODE_PORT_SCAN: - break; - - case TSC_MODE_NO_SCAN: - case TSC_MODE_XX_DRV: - case TSC_MODE_YY_DRV: - case TSC_MODE_YX_DRV: - default: - return; - } - - if (!s->enabled || s->busy || s->dav) - return; - - s->busy = 1; - s->precision = s->nextprecision; - s->function = s->nextfunction; - expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - (NANOSECONDS_PER_SECOND >> 10); - timer_mod(s->timer, expires); -} - -static uint16_t tsc210x_read(TSC210xState *s) -{ - uint16_t ret = 0x0000; - - if (!s->command) - fprintf(stderr, "tsc210x_read: SPI underrun!\n"); - - switch (s->page) { - case TSC_DATA_REGISTERS_PAGE: - ret = tsc2102_data_register_read(s, s->offset); - if (!s->dav) - qemu_irq_raise(s->davint); - break; - case TSC_CONTROL_REGISTERS_PAGE: - ret = tsc2102_control_register_read(s, s->offset); - break; - case TSC_AUDIO_REGISTERS_PAGE: - ret = tsc2102_audio_register_read(s, s->offset); - break; - default: - hw_error("tsc210x_read: wrong memory page\n"); - } - - tsc210x_pin_update(s); - - /* Allow sequential reads. */ - s->offset ++; - s->state = 0; - return ret; -} - -static void tsc210x_write(TSC210xState *s, uint16_t value) -{ - /* - * This is a two-state state machine for reading - * command and data every second time. - */ - if (!s->state) { - s->command = value >> 15; - s->page = (value >> 11) & 0x0f; - s->offset = (value >> 5) & 0x3f; - s->state = 1; - } else { - if (s->command) - fprintf(stderr, "tsc210x_write: SPI overrun!\n"); - else - switch (s->page) { - case TSC_DATA_REGISTERS_PAGE: - tsc2102_data_register_write(s, s->offset, value); - break; - case TSC_CONTROL_REGISTERS_PAGE: - tsc2102_control_register_write(s, s->offset, value); - break; - case TSC_AUDIO_REGISTERS_PAGE: - tsc2102_audio_register_write(s, s->offset, value); - break; - default: - hw_error("tsc210x_write: wrong memory page\n"); - } - - tsc210x_pin_update(s); - s->state = 0; - } -} - -uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len) -{ - TSC210xState *s = opaque; - uint32_t ret = 0; - - if (len != 16) - hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len); - - /* TODO: sequential reads etc - how do we make sure the host doesn't - * unintentionally read out a conversion result from a register while - * transmitting the command word of the next command? */ - if (!value || (s->state && s->command)) - ret = tsc210x_read(s); - if (value || (s->state && !s->command)) - tsc210x_write(s, value); - - return ret; -} - -static void tsc210x_timer_tick(void *opaque) -{ - TSC210xState *s = opaque; - - /* Timer ticked -- a set of conversions has been finished. */ - - if (!s->busy) - return; - - s->busy = 0; - s->dav |= mode_regs[s->function]; - tsc210x_pin_update(s); - qemu_irq_lower(s->davint); -} - -static void tsc210x_touchscreen_event(void *opaque, - int x, int y, int z, int buttons_state) -{ - TSC210xState *s = opaque; - int p = s->pressure; - - if (buttons_state) { - s->x = x; - s->y = y; - } - s->pressure = !!buttons_state; - - /* - * Note: We would get better responsiveness in the guest by - * signaling TS events immediately, but for now we simulate - * the first conversion delay for sake of correctness. - */ - if (p != s->pressure) - tsc210x_pin_update(s); -} - -static void tsc210x_i2s_swallow(TSC210xState *s) -{ - if (s->dac_voice[0]) - tsc210x_out_flush(s, s->codec.out.len); - else - s->codec.out.len = 0; -} - -static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out) -{ - s->i2s_tx_rate = out; - s->i2s_rx_rate = in; -} - -static void tsc210x_save(QEMUFile *f, void *opaque) -{ - TSC210xState *s = (TSC210xState *) opaque; - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int i; - - qemu_put_be16(f, s->x); - qemu_put_be16(f, s->y); - qemu_put_byte(f, s->pressure); - - qemu_put_byte(f, s->state); - qemu_put_byte(f, s->page); - qemu_put_byte(f, s->offset); - qemu_put_byte(f, s->command); - - qemu_put_byte(f, s->irq); - qemu_put_be16s(f, &s->dav); - - timer_put(f, s->timer); - qemu_put_byte(f, s->enabled); - qemu_put_byte(f, s->host_mode); - qemu_put_byte(f, s->function); - qemu_put_byte(f, s->nextfunction); - qemu_put_byte(f, s->precision); - qemu_put_byte(f, s->nextprecision); - qemu_put_byte(f, s->filter); - qemu_put_byte(f, s->pin_func); - qemu_put_byte(f, s->ref); - qemu_put_byte(f, s->timing); - qemu_put_be32(f, s->noise); - - qemu_put_be16s(f, &s->audio_ctrl1); - qemu_put_be16s(f, &s->audio_ctrl2); - qemu_put_be16s(f, &s->audio_ctrl3); - qemu_put_be16s(f, &s->pll[0]); - qemu_put_be16s(f, &s->pll[1]); - qemu_put_be16s(f, &s->volume); - qemu_put_sbe64(f, (s->volume_change - now)); - qemu_put_sbe64(f, (s->powerdown - now)); - qemu_put_byte(f, s->softstep); - qemu_put_be16s(f, &s->dac_power); - - for (i = 0; i < 0x14; i ++) - qemu_put_be16s(f, &s->filter_data[i]); -} - -static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) -{ - TSC210xState *s = (TSC210xState *) opaque; - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int i; - - s->x = qemu_get_be16(f); - s->y = qemu_get_be16(f); - s->pressure = qemu_get_byte(f); - - s->state = qemu_get_byte(f); - s->page = qemu_get_byte(f); - s->offset = qemu_get_byte(f); - s->command = qemu_get_byte(f); - - s->irq = qemu_get_byte(f); - qemu_get_be16s(f, &s->dav); - - timer_get(f, s->timer); - s->enabled = qemu_get_byte(f); - s->host_mode = qemu_get_byte(f); - s->function = qemu_get_byte(f); - if (s->function < 0 || s->function >= ARRAY_SIZE(mode_regs)) { - return -EINVAL; - } - s->nextfunction = qemu_get_byte(f); - if (s->nextfunction < 0 || s->nextfunction >= ARRAY_SIZE(mode_regs)) { - return -EINVAL; - } - s->precision = qemu_get_byte(f); - if (s->precision < 0 || s->precision >= ARRAY_SIZE(resolution)) { - return -EINVAL; - } - s->nextprecision = qemu_get_byte(f); - if (s->nextprecision < 0 || s->nextprecision >= ARRAY_SIZE(resolution)) { - return -EINVAL; - } - s->filter = qemu_get_byte(f); - s->pin_func = qemu_get_byte(f); - s->ref = qemu_get_byte(f); - s->timing = qemu_get_byte(f); - s->noise = qemu_get_be32(f); - - qemu_get_be16s(f, &s->audio_ctrl1); - qemu_get_be16s(f, &s->audio_ctrl2); - qemu_get_be16s(f, &s->audio_ctrl3); - qemu_get_be16s(f, &s->pll[0]); - qemu_get_be16s(f, &s->pll[1]); - qemu_get_be16s(f, &s->volume); - s->volume_change = qemu_get_sbe64(f) + now; - s->powerdown = qemu_get_sbe64(f) + now; - s->softstep = qemu_get_byte(f); - qemu_get_be16s(f, &s->dac_power); - - for (i = 0; i < 0x14; i ++) - qemu_get_be16s(f, &s->filter_data[i]); - - s->busy = timer_pending(s->timer); - qemu_set_irq(s->pint, !s->irq); - qemu_set_irq(s->davint, !s->dav); - - return 0; -} - -uWireSlave *tsc2102_init(qemu_irq pint) -{ - TSC210xState *s; - - s = g_new0(TSC210xState, 1); - s->x = 160; - s->y = 160; - s->pressure = 0; - s->precision = s->nextprecision = 0; - s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc210x_timer_tick, s); - s->pint = pint; - s->model = 0x2102; - s->name = "tsc2102"; - - s->tr[0] = 0; - s->tr[1] = 1; - s->tr[2] = 1; - s->tr[3] = 0; - s->tr[4] = 1; - s->tr[5] = 0; - s->tr[6] = 1; - s->tr[7] = 0; - - s->chip.opaque = s; - s->chip.send = (void *) tsc210x_write; - s->chip.receive = (void *) tsc210x_read; - - s->codec.opaque = s; - s->codec.tx_swallow = (void *) tsc210x_i2s_swallow; - s->codec.set_rate = (void *) tsc210x_i2s_set_rate; - s->codec.in.fifo = s->in_fifo; - s->codec.out.fifo = s->out_fifo; - - tsc210x_reset(s); - - qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, - "QEMU TSC2102-driven Touchscreen"); - - AUD_register_card(s->name, &s->card); - - qemu_register_reset((void *) tsc210x_reset, s); - register_savevm(NULL, s->name, -1, 0, - tsc210x_save, tsc210x_load, s); - - return &s->chip; -} - -uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav) -{ - TSC210xState *s; - - s = g_new0(TSC210xState, 1); - s->x = 400; - s->y = 240; - s->pressure = 0; - s->precision = s->nextprecision = 0; - s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc210x_timer_tick, s); - s->pint = penirq; - s->kbint = kbirq; - s->davint = dav; - s->model = 0x2301; - s->name = "tsc2301"; - - s->tr[0] = 0; - s->tr[1] = 1; - s->tr[2] = 1; - s->tr[3] = 0; - s->tr[4] = 1; - s->tr[5] = 0; - s->tr[6] = 1; - s->tr[7] = 0; - - s->chip.opaque = s; - s->chip.send = (void *) tsc210x_write; - s->chip.receive = (void *) tsc210x_read; - - s->codec.opaque = s; - s->codec.tx_swallow = (void *) tsc210x_i2s_swallow; - s->codec.set_rate = (void *) tsc210x_i2s_set_rate; - s->codec.in.fifo = s->in_fifo; - s->codec.out.fifo = s->out_fifo; - - tsc210x_reset(s); - - qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, - "QEMU TSC2301-driven Touchscreen"); - - AUD_register_card(s->name, &s->card); - - qemu_register_reset((void *) tsc210x_reset, s); - register_savevm(NULL, s->name, -1, 0, tsc210x_save, tsc210x_load, s); - - return &s->chip; -} - -I2SCodec *tsc210x_codec(uWireSlave *chip) -{ - TSC210xState *s = (TSC210xState *) chip->opaque; - - return &s->codec; -} - -/* - * Use tslib generated calibration data to generate ADC input values - * from the touchscreen. Assuming 12-bit precision was used during - * tslib calibration. - */ -void tsc210x_set_transform(uWireSlave *chip, - MouseTransformInfo *info) -{ - TSC210xState *s = (TSC210xState *) chip->opaque; -#if 0 - int64_t ltr[8]; - - ltr[0] = (int64_t) info->a[1] * info->y; - ltr[1] = (int64_t) info->a[4] * info->x; - ltr[2] = (int64_t) info->a[1] * info->a[3] - - (int64_t) info->a[4] * info->a[0]; - ltr[3] = (int64_t) info->a[2] * info->a[4] - - (int64_t) info->a[5] * info->a[1]; - ltr[4] = (int64_t) info->a[0] * info->y; - ltr[5] = (int64_t) info->a[3] * info->x; - ltr[6] = (int64_t) info->a[4] * info->a[0] - - (int64_t) info->a[1] * info->a[3]; - ltr[7] = (int64_t) info->a[2] * info->a[3] - - (int64_t) info->a[5] * info->a[0]; - - /* Avoid integer overflow */ - s->tr[0] = ltr[0] >> 11; - s->tr[1] = ltr[1] >> 11; - s->tr[2] = muldiv64(ltr[2], 1, info->a[6]); - s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]); - s->tr[4] = ltr[4] >> 11; - s->tr[5] = ltr[5] >> 11; - s->tr[6] = muldiv64(ltr[6], 1, info->a[6]); - s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]); -#else - - /* This version assumes touchscreen X & Y axis are parallel or - * perpendicular to LCD's X & Y axis in some way. */ - if (abs(info->a[0]) > abs(info->a[1])) { - s->tr[0] = 0; - s->tr[1] = -info->a[6] * info->x; - s->tr[2] = info->a[0]; - s->tr[3] = -info->a[2] / info->a[0]; - s->tr[4] = info->a[6] * info->y; - s->tr[5] = 0; - s->tr[6] = info->a[4]; - s->tr[7] = -info->a[5] / info->a[4]; - } else { - s->tr[0] = info->a[6] * info->y; - s->tr[1] = 0; - s->tr[2] = info->a[1]; - s->tr[3] = -info->a[2] / info->a[1]; - s->tr[4] = 0; - s->tr[5] = -info->a[6] * info->x; - s->tr[6] = info->a[3]; - s->tr[7] = -info->a[5] / info->a[3]; - } - - s->tr[0] >>= 11; - s->tr[1] >>= 11; - s->tr[3] <<= 4; - s->tr[4] >>= 11; - s->tr[5] >>= 11; - s->tr[7] <<= 4; -#endif -} - -void tsc210x_key_event(uWireSlave *chip, int key, int down) -{ - TSC210xState *s = (TSC210xState *) chip->opaque; - - if (down) - s->kb.down |= 1 << key; - else - s->kb.down &= ~(1 << key); - - if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) { - s->kb.intr = 1; - qemu_irq_lower(s->kbint); - } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) && - !(s->kb.mode & 1)) { - s->kb.intr = 0; - qemu_irq_raise(s->kbint); - } -} diff --git a/qemu/hw/input/virtio-input-hid.c b/qemu/hw/input/virtio-input-hid.c deleted file mode 100644 index 3ee0c1814..000000000 --- a/qemu/hw/input/virtio-input-hid.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * This work is licensed under the terms of the GNU GPL, version 2 or - * (at your option) any later version. See the COPYING file in the - * top-level directory. - */ - -#include "qemu/osdep.h" -#include "qemu/iov.h" - -#include "hw/qdev.h" -#include "hw/virtio/virtio.h" -#include "hw/virtio/virtio-input.h" - -#undef CONFIG_CURSES -#include "ui/console.h" - -#include "standard-headers/linux/input.h" - -#define VIRTIO_ID_NAME_KEYBOARD "QEMU Virtio Keyboard" -#define VIRTIO_ID_NAME_MOUSE "QEMU Virtio Mouse" -#define VIRTIO_ID_NAME_TABLET "QEMU Virtio Tablet" - -/* ----------------------------------------------------------------- */ - -static const unsigned int keymap_qcode[Q_KEY_CODE__MAX] = { - [Q_KEY_CODE_ESC] = KEY_ESC, - [Q_KEY_CODE_1] = KEY_1, - [Q_KEY_CODE_2] = KEY_2, - [Q_KEY_CODE_3] = KEY_3, - [Q_KEY_CODE_4] = KEY_4, - [Q_KEY_CODE_5] = KEY_5, - [Q_KEY_CODE_6] = KEY_6, - [Q_KEY_CODE_7] = KEY_7, - [Q_KEY_CODE_8] = KEY_8, - [Q_KEY_CODE_9] = KEY_9, - [Q_KEY_CODE_0] = KEY_0, - [Q_KEY_CODE_MINUS] = KEY_MINUS, - [Q_KEY_CODE_EQUAL] = KEY_EQUAL, - [Q_KEY_CODE_BACKSPACE] = KEY_BACKSPACE, - - [Q_KEY_CODE_TAB] = KEY_TAB, - [Q_KEY_CODE_Q] = KEY_Q, - [Q_KEY_CODE_W] = KEY_W, - [Q_KEY_CODE_E] = KEY_E, - [Q_KEY_CODE_R] = KEY_R, - [Q_KEY_CODE_T] = KEY_T, - [Q_KEY_CODE_Y] = KEY_Y, - [Q_KEY_CODE_U] = KEY_U, - [Q_KEY_CODE_I] = KEY_I, - [Q_KEY_CODE_O] = KEY_O, - [Q_KEY_CODE_P] = KEY_P, - [Q_KEY_CODE_BRACKET_LEFT] = KEY_LEFTBRACE, - [Q_KEY_CODE_BRACKET_RIGHT] = KEY_RIGHTBRACE, - [Q_KEY_CODE_RET] = KEY_ENTER, - - [Q_KEY_CODE_CTRL] = KEY_LEFTCTRL, - [Q_KEY_CODE_A] = KEY_A, - [Q_KEY_CODE_S] = KEY_S, - [Q_KEY_CODE_D] = KEY_D, - [Q_KEY_CODE_F] = KEY_F, - [Q_KEY_CODE_G] = KEY_G, - [Q_KEY_CODE_H] = KEY_H, - [Q_KEY_CODE_J] = KEY_J, - [Q_KEY_CODE_K] = KEY_K, - [Q_KEY_CODE_L] = KEY_L, - [Q_KEY_CODE_SEMICOLON] = KEY_SEMICOLON, - [Q_KEY_CODE_APOSTROPHE] = KEY_APOSTROPHE, - [Q_KEY_CODE_GRAVE_ACCENT] = KEY_GRAVE, - - [Q_KEY_CODE_SHIFT] = KEY_LEFTSHIFT, - [Q_KEY_CODE_BACKSLASH] = KEY_BACKSLASH, - [Q_KEY_CODE_LESS] = KEY_102ND, - [Q_KEY_CODE_Z] = KEY_Z, - [Q_KEY_CODE_X] = KEY_X, - [Q_KEY_CODE_C] = KEY_C, - [Q_KEY_CODE_V] = KEY_V, - [Q_KEY_CODE_B] = KEY_B, - [Q_KEY_CODE_N] = KEY_N, - [Q_KEY_CODE_M] = KEY_M, - [Q_KEY_CODE_COMMA] = KEY_COMMA, - [Q_KEY_CODE_DOT] = KEY_DOT, - [Q_KEY_CODE_SLASH] = KEY_SLASH, - [Q_KEY_CODE_SHIFT_R] = KEY_RIGHTSHIFT, - - [Q_KEY_CODE_ALT] = KEY_LEFTALT, - [Q_KEY_CODE_SPC] = KEY_SPACE, - [Q_KEY_CODE_CAPS_LOCK] = KEY_CAPSLOCK, - - [Q_KEY_CODE_F1] = KEY_F1, - [Q_KEY_CODE_F2] = KEY_F2, - [Q_KEY_CODE_F3] = KEY_F3, - [Q_KEY_CODE_F4] = KEY_F4, - [Q_KEY_CODE_F5] = KEY_F5, - [Q_KEY_CODE_F6] = KEY_F6, - [Q_KEY_CODE_F7] = KEY_F7, - [Q_KEY_CODE_F8] = KEY_F8, - [Q_KEY_CODE_F9] = KEY_F9, - [Q_KEY_CODE_F10] = KEY_F10, - [Q_KEY_CODE_NUM_LOCK] = KEY_NUMLOCK, - [Q_KEY_CODE_SCROLL_LOCK] = KEY_SCROLLLOCK, - - [Q_KEY_CODE_KP_0] = KEY_KP0, - [Q_KEY_CODE_KP_1] = KEY_KP1, - [Q_KEY_CODE_KP_2] = KEY_KP2, - [Q_KEY_CODE_KP_3] = KEY_KP3, - [Q_KEY_CODE_KP_4] = KEY_KP4, - [Q_KEY_CODE_KP_5] = KEY_KP5, - [Q_KEY_CODE_KP_6] = KEY_KP6, - [Q_KEY_CODE_KP_7] = KEY_KP7, - [Q_KEY_CODE_KP_8] = KEY_KP8, - [Q_KEY_CODE_KP_9] = KEY_KP9, - [Q_KEY_CODE_KP_SUBTRACT] = KEY_KPMINUS, - [Q_KEY_CODE_KP_ADD] = KEY_KPPLUS, - [Q_KEY_CODE_KP_DECIMAL] = KEY_KPDOT, - [Q_KEY_CODE_KP_ENTER] = KEY_KPENTER, - [Q_KEY_CODE_KP_DIVIDE] = KEY_KPSLASH, - [Q_KEY_CODE_KP_MULTIPLY] = KEY_KPASTERISK, - - [Q_KEY_CODE_F11] = KEY_F11, - [Q_KEY_CODE_F12] = KEY_F12, - - [Q_KEY_CODE_CTRL_R] = KEY_RIGHTCTRL, - [Q_KEY_CODE_SYSRQ] = KEY_SYSRQ, - [Q_KEY_CODE_PRINT] = KEY_SYSRQ, - [Q_KEY_CODE_PAUSE] = KEY_PAUSE, - [Q_KEY_CODE_ALT_R] = KEY_RIGHTALT, - - [Q_KEY_CODE_HOME] = KEY_HOME, - [Q_KEY_CODE_UP] = KEY_UP, - [Q_KEY_CODE_PGUP] = KEY_PAGEUP, - [Q_KEY_CODE_LEFT] = KEY_LEFT, - [Q_KEY_CODE_RIGHT] = KEY_RIGHT, - [Q_KEY_CODE_END] = KEY_END, - [Q_KEY_CODE_DOWN] = KEY_DOWN, - [Q_KEY_CODE_PGDN] = KEY_PAGEDOWN, - [Q_KEY_CODE_INSERT] = KEY_INSERT, - [Q_KEY_CODE_DELETE] = KEY_DELETE, - - [Q_KEY_CODE_META_L] = KEY_LEFTMETA, - [Q_KEY_CODE_META_R] = KEY_RIGHTMETA, - [Q_KEY_CODE_MENU] = KEY_MENU, -}; - -static const unsigned int keymap_button[INPUT_BUTTON__MAX] = { - [INPUT_BUTTON_LEFT] = BTN_LEFT, - [INPUT_BUTTON_RIGHT] = BTN_RIGHT, - [INPUT_BUTTON_MIDDLE] = BTN_MIDDLE, - [INPUT_BUTTON_WHEEL_UP] = BTN_GEAR_UP, - [INPUT_BUTTON_WHEEL_DOWN] = BTN_GEAR_DOWN, -}; - -static const unsigned int axismap_rel[INPUT_AXIS__MAX] = { - [INPUT_AXIS_X] = REL_X, - [INPUT_AXIS_Y] = REL_Y, -}; - -static const unsigned int axismap_abs[INPUT_AXIS__MAX] = { - [INPUT_AXIS_X] = ABS_X, - [INPUT_AXIS_Y] = ABS_Y, -}; - -/* ----------------------------------------------------------------- */ - -static void virtio_input_key_config(VirtIOInput *vinput, - const unsigned int *keymap, - size_t mapsize) -{ - virtio_input_config keys; - int i, bit, byte, bmax = 0; - - memset(&keys, 0, sizeof(keys)); - for (i = 0; i < mapsize; i++) { - bit = keymap[i]; - if (!bit) { - continue; - } - byte = bit / 8; - bit = bit % 8; - keys.u.bitmap[byte] |= (1 << bit); - if (bmax < byte+1) { - bmax = byte+1; - } - } - keys.select = VIRTIO_INPUT_CFG_EV_BITS; - keys.subsel = EV_KEY; - keys.size = bmax; - virtio_input_add_config(vinput, &keys); -} - -static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src, - InputEvent *evt) -{ - VirtIOInput *vinput = VIRTIO_INPUT(dev); - virtio_input_event event; - int qcode; - InputKeyEvent *key; - InputMoveEvent *move; - InputBtnEvent *btn; - - switch (evt->type) { - case INPUT_EVENT_KIND_KEY: - key = evt->u.key.data; - qcode = qemu_input_key_value_to_qcode(key->key); - if (qcode && keymap_qcode[qcode]) { - event.type = cpu_to_le16(EV_KEY); - event.code = cpu_to_le16(keymap_qcode[qcode]); - event.value = cpu_to_le32(key->down ? 1 : 0); - virtio_input_send(vinput, &event); - } else { - if (key->down) { - fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__, - qcode, QKeyCode_lookup[qcode]); - } - } - break; - case INPUT_EVENT_KIND_BTN: - btn = evt->u.btn.data; - if (keymap_button[btn->button]) { - event.type = cpu_to_le16(EV_KEY); - event.code = cpu_to_le16(keymap_button[btn->button]); - event.value = cpu_to_le32(btn->down ? 1 : 0); - virtio_input_send(vinput, &event); - } else { - if (btn->down) { - fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__, - btn->button, - InputButton_lookup[btn->button]); - } - } - break; - case INPUT_EVENT_KIND_REL: - move = evt->u.rel.data; - event.type = cpu_to_le16(EV_REL); - event.code = cpu_to_le16(axismap_rel[move->axis]); - event.value = cpu_to_le32(move->value); - virtio_input_send(vinput, &event); - break; - case INPUT_EVENT_KIND_ABS: - move = evt->u.abs.data; - event.type = cpu_to_le16(EV_ABS); - event.code = cpu_to_le16(axismap_abs[move->axis]); - event.value = cpu_to_le32(move->value); - virtio_input_send(vinput, &event); - break; - default: - /* keep gcc happy */ - break; - } -} - -static void virtio_input_handle_sync(DeviceState *dev) -{ - VirtIOInput *vinput = VIRTIO_INPUT(dev); - virtio_input_event event = { - .type = cpu_to_le16(EV_SYN), - .code = cpu_to_le16(SYN_REPORT), - .value = 0, - }; - - virtio_input_send(vinput, &event); -} - -static void virtio_input_hid_realize(DeviceState *dev, Error **errp) -{ - VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev); - - vhid->hs = qemu_input_handler_register(dev, vhid->handler); - if (vhid->display && vhid->hs) { - qemu_input_handler_bind(vhid->hs, vhid->display, vhid->head, NULL); - } -} - -static void virtio_input_hid_unrealize(DeviceState *dev, Error **errp) -{ - VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev); - qemu_input_handler_unregister(vhid->hs); -} - -static void virtio_input_hid_change_active(VirtIOInput *vinput) -{ - VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput); - - if (vinput->active) { - qemu_input_handler_activate(vhid->hs); - } else { - qemu_input_handler_deactivate(vhid->hs); - } -} - -static void virtio_input_hid_handle_status(VirtIOInput *vinput, - virtio_input_event *event) -{ - VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput); - int ledbit = 0; - - switch (le16_to_cpu(event->type)) { - case EV_LED: - if (event->code == LED_NUML) { - ledbit = QEMU_NUM_LOCK_LED; - } else if (event->code == LED_CAPSL) { - ledbit = QEMU_CAPS_LOCK_LED; - } else if (event->code == LED_SCROLLL) { - ledbit = QEMU_SCROLL_LOCK_LED; - } - if (event->value) { - vhid->ledstate |= ledbit; - } else { - vhid->ledstate &= ~ledbit; - } - kbd_put_ledstate(vhid->ledstate); - break; - default: - fprintf(stderr, "%s: unknown type %d\n", __func__, - le16_to_cpu(event->type)); - break; - } -} - -static Property virtio_input_hid_properties[] = { - DEFINE_PROP_STRING("display", VirtIOInputHID, display), - DEFINE_PROP_UINT32("head", VirtIOInputHID, head, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_input_hid_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass); - - dc->props = virtio_input_hid_properties; - vic->realize = virtio_input_hid_realize; - vic->unrealize = virtio_input_hid_unrealize; - vic->change_active = virtio_input_hid_change_active; - vic->handle_status = virtio_input_hid_handle_status; -} - -static const TypeInfo virtio_input_hid_info = { - .name = TYPE_VIRTIO_INPUT_HID, - .parent = TYPE_VIRTIO_INPUT, - .instance_size = sizeof(VirtIOInputHID), - .class_init = virtio_input_hid_class_init, - .abstract = true, -}; - -/* ----------------------------------------------------------------- */ - -static QemuInputHandler virtio_keyboard_handler = { - .name = VIRTIO_ID_NAME_KEYBOARD, - .mask = INPUT_EVENT_MASK_KEY, - .event = virtio_input_handle_event, - .sync = virtio_input_handle_sync, -}; - -static struct virtio_input_config virtio_keyboard_config[] = { - { - .select = VIRTIO_INPUT_CFG_ID_NAME, - .size = sizeof(VIRTIO_ID_NAME_KEYBOARD), - .u.string = VIRTIO_ID_NAME_KEYBOARD, - },{ - .select = VIRTIO_INPUT_CFG_ID_DEVIDS, - .size = sizeof(struct virtio_input_devids), - .u.ids = { - .bustype = const_le16(BUS_VIRTUAL), - .vendor = const_le16(0x0627), /* same we use for usb hid devices */ - .product = const_le16(0x0001), - .version = const_le16(0x0001), - }, - },{ - .select = VIRTIO_INPUT_CFG_EV_BITS, - .subsel = EV_REP, - .size = 1, - },{ - .select = VIRTIO_INPUT_CFG_EV_BITS, - .subsel = EV_LED, - .size = 1, - .u.bitmap = { - (1 << LED_NUML) | (1 << LED_CAPSL) | (1 << LED_SCROLLL), - }, - }, - { /* end of list */ }, -}; - -static void virtio_keyboard_init(Object *obj) -{ - VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj); - VirtIOInput *vinput = VIRTIO_INPUT(obj); - - vhid->handler = &virtio_keyboard_handler; - virtio_input_init_config(vinput, virtio_keyboard_config); - virtio_input_key_config(vinput, keymap_qcode, - ARRAY_SIZE(keymap_qcode)); -} - -static const TypeInfo virtio_keyboard_info = { - .name = TYPE_VIRTIO_KEYBOARD, - .parent = TYPE_VIRTIO_INPUT_HID, - .instance_size = sizeof(VirtIOInputHID), - .instance_init = virtio_keyboard_init, -}; - -/* ----------------------------------------------------------------- */ - -static QemuInputHandler virtio_mouse_handler = { - .name = VIRTIO_ID_NAME_MOUSE, - .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, - .event = virtio_input_handle_event, - .sync = virtio_input_handle_sync, -}; - -static struct virtio_input_config virtio_mouse_config[] = { - { - .select = VIRTIO_INPUT_CFG_ID_NAME, - .size = sizeof(VIRTIO_ID_NAME_MOUSE), - .u.string = VIRTIO_ID_NAME_MOUSE, - },{ - .select = VIRTIO_INPUT_CFG_ID_DEVIDS, - .size = sizeof(struct virtio_input_devids), - .u.ids = { - .bustype = const_le16(BUS_VIRTUAL), - .vendor = const_le16(0x0627), /* same we use for usb hid devices */ - .product = const_le16(0x0002), - .version = const_le16(0x0001), - }, - },{ - .select = VIRTIO_INPUT_CFG_EV_BITS, - .subsel = EV_REL, - .size = 1, - .u.bitmap = { - (1 << REL_X) | (1 << REL_Y), - }, - }, - { /* end of list */ }, -}; - -static void virtio_mouse_init(Object *obj) -{ - VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj); - VirtIOInput *vinput = VIRTIO_INPUT(obj); - - vhid->handler = &virtio_mouse_handler; - virtio_input_init_config(vinput, virtio_mouse_config); - virtio_input_key_config(vinput, keymap_button, - ARRAY_SIZE(keymap_button)); -} - -static const TypeInfo virtio_mouse_info = { - .name = TYPE_VIRTIO_MOUSE, - .parent = TYPE_VIRTIO_INPUT_HID, - .instance_size = sizeof(VirtIOInputHID), - .instance_init = virtio_mouse_init, -}; - -/* ----------------------------------------------------------------- */ - -static QemuInputHandler virtio_tablet_handler = { - .name = VIRTIO_ID_NAME_TABLET, - .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, - .event = virtio_input_handle_event, - .sync = virtio_input_handle_sync, -}; - -static struct virtio_input_config virtio_tablet_config[] = { - { - .select = VIRTIO_INPUT_CFG_ID_NAME, - .size = sizeof(VIRTIO_ID_NAME_TABLET), - .u.string = VIRTIO_ID_NAME_TABLET, - },{ - .select = VIRTIO_INPUT_CFG_ID_DEVIDS, - .size = sizeof(struct virtio_input_devids), - .u.ids = { - .bustype = const_le16(BUS_VIRTUAL), - .vendor = const_le16(0x0627), /* same we use for usb hid devices */ - .product = const_le16(0x0003), - .version = const_le16(0x0001), - }, - },{ - .select = VIRTIO_INPUT_CFG_EV_BITS, - .subsel = EV_ABS, - .size = 1, - .u.bitmap = { - (1 << ABS_X) | (1 << ABS_Y), - }, - },{ - .select = VIRTIO_INPUT_CFG_ABS_INFO, - .subsel = ABS_X, - .size = sizeof(virtio_input_absinfo), - .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1), - },{ - .select = VIRTIO_INPUT_CFG_ABS_INFO, - .subsel = ABS_Y, - .size = sizeof(virtio_input_absinfo), - .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1), - }, - { /* end of list */ }, -}; - -static void virtio_tablet_init(Object *obj) -{ - VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj); - VirtIOInput *vinput = VIRTIO_INPUT(obj); - - vhid->handler = &virtio_tablet_handler; - virtio_input_init_config(vinput, virtio_tablet_config); - virtio_input_key_config(vinput, keymap_button, - ARRAY_SIZE(keymap_button)); -} - -static const TypeInfo virtio_tablet_info = { - .name = TYPE_VIRTIO_TABLET, - .parent = TYPE_VIRTIO_INPUT_HID, - .instance_size = sizeof(VirtIOInputHID), - .instance_init = virtio_tablet_init, -}; - -/* ----------------------------------------------------------------- */ - -static void virtio_register_types(void) -{ - type_register_static(&virtio_input_hid_info); - type_register_static(&virtio_keyboard_info); - type_register_static(&virtio_mouse_info); - type_register_static(&virtio_tablet_info); -} - -type_init(virtio_register_types) diff --git a/qemu/hw/input/virtio-input-host.c b/qemu/hw/input/virtio-input-host.c deleted file mode 100644 index cb79e8002..000000000 --- a/qemu/hw/input/virtio-input-host.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * This work is licensed under the terms of the GNU GPL, version 2 or - * (at your option) any later version. See the COPYING file in the - * top-level directory. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "qemu/sockets.h" - -#include "hw/qdev.h" -#include "hw/virtio/virtio.h" -#include "hw/virtio/virtio-input.h" - -#include <sys/ioctl.h> -#include "standard-headers/linux/input.h" - -/* ----------------------------------------------------------------- */ - -static struct virtio_input_config virtio_input_host_config[] = { - { /* empty list */ }, -}; - -static void virtio_input_host_event(void *opaque) -{ - VirtIOInputHost *vih = opaque; - VirtIOInput *vinput = VIRTIO_INPUT(vih); - struct virtio_input_event virtio; - struct input_event evdev; - int rc; - - for (;;) { - rc = read(vih->fd, &evdev, sizeof(evdev)); - if (rc != sizeof(evdev)) { - break; - } - - virtio.type = cpu_to_le16(evdev.type); - virtio.code = cpu_to_le16(evdev.code); - virtio.value = cpu_to_le32(evdev.value); - virtio_input_send(vinput, &virtio); - } -} - -static void virtio_input_bits_config(VirtIOInputHost *vih, - int type, int count) -{ - virtio_input_config bits; - int rc, i, size = 0; - - memset(&bits, 0, sizeof(bits)); - rc = ioctl(vih->fd, EVIOCGBIT(type, count/8), bits.u.bitmap); - if (rc < 0) { - return; - } - - for (i = 0; i < count/8; i++) { - if (bits.u.bitmap[i]) { - size = i+1; - } - } - if (size == 0) { - return; - } - - bits.select = VIRTIO_INPUT_CFG_EV_BITS; - bits.subsel = type; - bits.size = size; - virtio_input_add_config(VIRTIO_INPUT(vih), &bits); -} - -static void virtio_input_abs_config(VirtIOInputHost *vih, int axis) -{ - virtio_input_config config; - struct input_absinfo absinfo; - int rc; - - rc = ioctl(vih->fd, EVIOCGABS(axis), &absinfo); - if (rc < 0) { - return; - } - - memset(&config, 0, sizeof(config)); - config.select = VIRTIO_INPUT_CFG_ABS_INFO; - config.subsel = axis; - config.size = sizeof(virtio_input_absinfo); - - config.u.abs.min = cpu_to_le32(absinfo.minimum); - config.u.abs.max = cpu_to_le32(absinfo.maximum); - config.u.abs.fuzz = cpu_to_le32(absinfo.fuzz); - config.u.abs.flat = cpu_to_le32(absinfo.flat); - config.u.abs.res = cpu_to_le32(absinfo.resolution); - - virtio_input_add_config(VIRTIO_INPUT(vih), &config); -} - -static void virtio_input_host_realize(DeviceState *dev, Error **errp) -{ - VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev); - VirtIOInput *vinput = VIRTIO_INPUT(dev); - virtio_input_config id, *abs; - struct input_id ids; - int rc, ver, i, axis; - uint8_t byte; - - if (!vih->evdev) { - error_setg(errp, "evdev property is required"); - return; - } - - vih->fd = open(vih->evdev, O_RDWR); - if (vih->fd < 0) { - error_setg_file_open(errp, errno, vih->evdev); - return; - } - qemu_set_nonblock(vih->fd); - - rc = ioctl(vih->fd, EVIOCGVERSION, &ver); - if (rc < 0) { - error_setg(errp, "%s: is not an evdev device", vih->evdev); - goto err_close; - } - - rc = ioctl(vih->fd, EVIOCGRAB, 1); - if (rc < 0) { - error_setg_errno(errp, errno, "%s: failed to get exclusive access", - vih->evdev); - goto err_close; - } - - memset(&id, 0, sizeof(id)); - ioctl(vih->fd, EVIOCGNAME(sizeof(id.u.string)-1), id.u.string); - id.select = VIRTIO_INPUT_CFG_ID_NAME; - id.size = strlen(id.u.string); - virtio_input_add_config(vinput, &id); - - if (ioctl(vih->fd, EVIOCGID, &ids) == 0) { - memset(&id, 0, sizeof(id)); - id.select = VIRTIO_INPUT_CFG_ID_DEVIDS; - id.size = sizeof(struct virtio_input_devids); - id.u.ids.bustype = cpu_to_le16(ids.bustype); - id.u.ids.vendor = cpu_to_le16(ids.vendor); - id.u.ids.product = cpu_to_le16(ids.product); - id.u.ids.version = cpu_to_le16(ids.version); - virtio_input_add_config(vinput, &id); - } - - virtio_input_bits_config(vih, EV_KEY, KEY_CNT); - virtio_input_bits_config(vih, EV_REL, REL_CNT); - virtio_input_bits_config(vih, EV_ABS, ABS_CNT); - virtio_input_bits_config(vih, EV_MSC, MSC_CNT); - virtio_input_bits_config(vih, EV_SW, SW_CNT); - virtio_input_bits_config(vih, EV_LED, LED_CNT); - - abs = virtio_input_find_config(VIRTIO_INPUT(vih), - VIRTIO_INPUT_CFG_EV_BITS, EV_ABS); - if (abs) { - for (i = 0; i < abs->size; i++) { - byte = abs->u.bitmap[i]; - axis = 8 * i; - while (byte) { - if (byte & 1) { - virtio_input_abs_config(vih, axis); - } - axis++; - byte >>= 1; - } - } - } - - qemu_set_fd_handler(vih->fd, virtio_input_host_event, NULL, vih); - return; - -err_close: - close(vih->fd); - vih->fd = -1; - return; -} - -static void virtio_input_host_unrealize(DeviceState *dev, Error **errp) -{ - VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev); - - if (vih->fd > 0) { - qemu_set_fd_handler(vih->fd, NULL, NULL, NULL); - close(vih->fd); - } -} - -static void virtio_input_host_handle_status(VirtIOInput *vinput, - virtio_input_event *event) -{ - VirtIOInputHost *vih = VIRTIO_INPUT_HOST(vinput); - struct input_event evdev; - int rc; - - if (gettimeofday(&evdev.time, NULL)) { - perror("virtio_input_host_handle_status: gettimeofday"); - return; - } - - evdev.type = le16_to_cpu(event->type); - evdev.code = le16_to_cpu(event->code); - evdev.value = le32_to_cpu(event->value); - - rc = write(vih->fd, &evdev, sizeof(evdev)); - if (rc == -1) { - perror("virtio_input_host_handle_status: write"); - } -} - -static const VMStateDescription vmstate_virtio_input_host = { - .name = "virtio-input-host", - .unmigratable = 1, -}; - -static Property virtio_input_host_properties[] = { - DEFINE_PROP_STRING("evdev", VirtIOInputHost, evdev), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_input_host_class_init(ObjectClass *klass, void *data) -{ - VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->vmsd = &vmstate_virtio_input_host; - dc->props = virtio_input_host_properties; - vic->realize = virtio_input_host_realize; - vic->unrealize = virtio_input_host_unrealize; - vic->handle_status = virtio_input_host_handle_status; -} - -static void virtio_input_host_init(Object *obj) -{ - VirtIOInput *vinput = VIRTIO_INPUT(obj); - - virtio_input_init_config(vinput, virtio_input_host_config); -} - -static const TypeInfo virtio_input_host_info = { - .name = TYPE_VIRTIO_INPUT_HOST, - .parent = TYPE_VIRTIO_INPUT, - .instance_size = sizeof(VirtIOInputHost), - .instance_init = virtio_input_host_init, - .class_init = virtio_input_host_class_init, -}; - -/* ----------------------------------------------------------------- */ - -static void virtio_register_types(void) -{ - type_register_static(&virtio_input_host_info); -} - -type_init(virtio_register_types) diff --git a/qemu/hw/input/virtio-input.c b/qemu/hw/input/virtio-input.c deleted file mode 100644 index f59749a94..000000000 --- a/qemu/hw/input/virtio-input.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * This work is licensed under the terms of the GNU GPL, version 2 or - * (at your option) any later version. See the COPYING file in the - * top-level directory. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu/iov.h" - -#include "hw/qdev.h" -#include "hw/virtio/virtio.h" -#include "hw/virtio/virtio-input.h" - -#include "standard-headers/linux/input.h" - -#define VIRTIO_INPUT_VM_VERSION 1 - -/* ----------------------------------------------------------------- */ - -void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event) -{ - VirtQueueElement *elem; - unsigned have, need; - int i, len; - - if (!vinput->active) { - return; - } - - /* queue up events ... */ - if (vinput->qindex == vinput->qsize) { - vinput->qsize++; - vinput->queue = realloc(vinput->queue, vinput->qsize * - sizeof(virtio_input_event)); - } - vinput->queue[vinput->qindex++] = *event; - - /* ... until we see a report sync ... */ - if (event->type != cpu_to_le16(EV_SYN) || - event->code != cpu_to_le16(SYN_REPORT)) { - return; - } - - /* ... then check available space ... */ - need = sizeof(virtio_input_event) * vinput->qindex; - virtqueue_get_avail_bytes(vinput->evt, &have, NULL, need, 0); - if (have < need) { - vinput->qindex = 0; - fprintf(stderr, "%s: ENOSPC in vq, dropping events\n", __func__); - return; - } - - /* ... and finally pass them to the guest */ - for (i = 0; i < vinput->qindex; i++) { - elem = virtqueue_pop(vinput->evt, sizeof(VirtQueueElement)); - if (!elem) { - /* should not happen, we've checked for space beforehand */ - fprintf(stderr, "%s: Huh? No vq elem available ...\n", __func__); - return; - } - len = iov_from_buf(elem->in_sg, elem->in_num, - 0, vinput->queue+i, sizeof(virtio_input_event)); - virtqueue_push(vinput->evt, elem, len); - g_free(elem); - } - virtio_notify(VIRTIO_DEVICE(vinput), vinput->evt); - vinput->qindex = 0; -} - -static void virtio_input_handle_evt(VirtIODevice *vdev, VirtQueue *vq) -{ - /* nothing */ -} - -static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq) -{ - VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev); - VirtIOInput *vinput = VIRTIO_INPUT(vdev); - virtio_input_event event; - VirtQueueElement *elem; - int len; - - for (;;) { - elem = virtqueue_pop(vinput->sts, sizeof(VirtQueueElement)); - if (!elem) { - break; - } - - memset(&event, 0, sizeof(event)); - len = iov_to_buf(elem->out_sg, elem->out_num, - 0, &event, sizeof(event)); - if (vic->handle_status) { - vic->handle_status(vinput, &event); - } - virtqueue_push(vinput->sts, elem, len); - g_free(elem); - } - virtio_notify(vdev, vinput->sts); -} - -virtio_input_config *virtio_input_find_config(VirtIOInput *vinput, - uint8_t select, - uint8_t subsel) -{ - VirtIOInputConfig *cfg; - - QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) { - if (select == cfg->config.select && - subsel == cfg->config.subsel) { - return &cfg->config; - } - } - return NULL; -} - -void virtio_input_add_config(VirtIOInput *vinput, - virtio_input_config *config) -{ - VirtIOInputConfig *cfg; - - if (virtio_input_find_config(vinput, config->select, config->subsel)) { - /* should not happen */ - fprintf(stderr, "%s: duplicate config: %d/%d\n", - __func__, config->select, config->subsel); - abort(); - } - - cfg = g_new0(VirtIOInputConfig, 1); - cfg->config = *config; - QTAILQ_INSERT_TAIL(&vinput->cfg_list, cfg, node); -} - -void virtio_input_init_config(VirtIOInput *vinput, - virtio_input_config *config) -{ - int i = 0; - - QTAILQ_INIT(&vinput->cfg_list); - while (config[i].select) { - virtio_input_add_config(vinput, config + i); - i++; - } -} - -void virtio_input_idstr_config(VirtIOInput *vinput, - uint8_t select, const char *string) -{ - virtio_input_config id; - - if (!string) { - return; - } - memset(&id, 0, sizeof(id)); - id.select = select; - id.size = snprintf(id.u.string, sizeof(id.u.string), "%s", string); - virtio_input_add_config(vinput, &id); -} - -static void virtio_input_get_config(VirtIODevice *vdev, uint8_t *config_data) -{ - VirtIOInput *vinput = VIRTIO_INPUT(vdev); - virtio_input_config *config; - - config = virtio_input_find_config(vinput, vinput->cfg_select, - vinput->cfg_subsel); - if (config) { - memcpy(config_data, config, vinput->cfg_size); - } else { - memset(config_data, 0, vinput->cfg_size); - } -} - -static void virtio_input_set_config(VirtIODevice *vdev, - const uint8_t *config_data) -{ - VirtIOInput *vinput = VIRTIO_INPUT(vdev); - virtio_input_config *config = (virtio_input_config *)config_data; - - vinput->cfg_select = config->select; - vinput->cfg_subsel = config->subsel; - virtio_notify_config(vdev); -} - -static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f, - Error **errp) -{ - return f; -} - -static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val) -{ - VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev); - VirtIOInput *vinput = VIRTIO_INPUT(vdev); - - if (val & VIRTIO_CONFIG_S_DRIVER_OK) { - if (!vinput->active) { - vinput->active = true; - if (vic->change_active) { - vic->change_active(vinput); - } - } - } -} - -static void virtio_input_reset(VirtIODevice *vdev) -{ - VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev); - VirtIOInput *vinput = VIRTIO_INPUT(vdev); - - if (vinput->active) { - vinput->active = false; - if (vic->change_active) { - vic->change_active(vinput); - } - } -} - -static void virtio_input_save(QEMUFile *f, void *opaque) -{ - VirtIOInput *vinput = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(vinput); - - virtio_save(vdev, f); -} - -static int virtio_input_load(QEMUFile *f, void *opaque, int version_id) -{ - VirtIOInput *vinput = opaque; - VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vinput); - VirtIODevice *vdev = VIRTIO_DEVICE(vinput); - int ret; - - if (version_id != VIRTIO_INPUT_VM_VERSION) { - return -EINVAL; - } - - ret = virtio_load(vdev, f, version_id); - if (ret) { - return ret; - } - - /* post_load() */ - vinput->active = vdev->status & VIRTIO_CONFIG_S_DRIVER_OK; - if (vic->change_active) { - vic->change_active(vinput); - } - return 0; -} - -static void virtio_input_device_realize(DeviceState *dev, Error **errp) -{ - VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev); - VirtIODevice *vdev = VIRTIO_DEVICE(dev); - VirtIOInput *vinput = VIRTIO_INPUT(dev); - VirtIOInputConfig *cfg; - Error *local_err = NULL; - - if (vic->realize) { - vic->realize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } - - virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SERIAL, - vinput->serial); - - QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) { - if (vinput->cfg_size < cfg->config.size) { - vinput->cfg_size = cfg->config.size; - } - } - vinput->cfg_size += 8; - assert(vinput->cfg_size <= sizeof(virtio_input_config)); - - virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT, - vinput->cfg_size); - vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt); - vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts); - - register_savevm(dev, "virtio-input", -1, VIRTIO_INPUT_VM_VERSION, - virtio_input_save, virtio_input_load, vinput); -} - -static void virtio_input_device_unrealize(DeviceState *dev, Error **errp) -{ - VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev); - VirtIODevice *vdev = VIRTIO_DEVICE(dev); - VirtIOInput *vinput = VIRTIO_INPUT(dev); - Error *local_err = NULL; - - unregister_savevm(dev, "virtio-input", vinput); - - if (vic->unrealize) { - vic->unrealize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } - virtio_cleanup(vdev); -} - -static Property virtio_input_properties[] = { - DEFINE_PROP_STRING("serial", VirtIOInput, serial), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_input_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - - dc->props = virtio_input_properties; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - vdc->realize = virtio_input_device_realize; - vdc->unrealize = virtio_input_device_unrealize; - vdc->get_config = virtio_input_get_config; - vdc->set_config = virtio_input_set_config; - vdc->get_features = virtio_input_get_features; - vdc->set_status = virtio_input_set_status; - vdc->reset = virtio_input_reset; -} - -static const TypeInfo virtio_input_info = { - .name = TYPE_VIRTIO_INPUT, - .parent = TYPE_VIRTIO_DEVICE, - .instance_size = sizeof(VirtIOInput), - .class_size = sizeof(VirtIOInputClass), - .class_init = virtio_input_class_init, - .abstract = true, -}; - -/* ----------------------------------------------------------------- */ - -static void virtio_register_types(void) -{ - type_register_static(&virtio_input_info); -} - -type_init(virtio_register_types) diff --git a/qemu/hw/input/vmmouse.c b/qemu/hw/input/vmmouse.c deleted file mode 100644 index 6d15a887c..000000000 --- a/qemu/hw/input/vmmouse.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * QEMU VMMouse emulation - * - * Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "ui/console.h" -#include "hw/input/ps2.h" -#include "hw/i386/pc.h" -#include "hw/qdev.h" - -/* debug only vmmouse */ -//#define DEBUG_VMMOUSE - -/* VMMouse Commands */ -#define VMMOUSE_GETVERSION 10 -#define VMMOUSE_DATA 39 -#define VMMOUSE_STATUS 40 -#define VMMOUSE_COMMAND 41 - -#define VMMOUSE_READ_ID 0x45414552 -#define VMMOUSE_DISABLE 0x000000f5 -#define VMMOUSE_REQUEST_RELATIVE 0x4c455252 -#define VMMOUSE_REQUEST_ABSOLUTE 0x53424152 - -#define VMMOUSE_QUEUE_SIZE 1024 - -#define VMMOUSE_VERSION 0x3442554a - -#ifdef DEBUG_VMMOUSE -#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else -#define DPRINTF(fmt, ...) do { } while (0) -#endif - -#define TYPE_VMMOUSE "vmmouse" -#define VMMOUSE(obj) OBJECT_CHECK(VMMouseState, (obj), TYPE_VMMOUSE) - -typedef struct VMMouseState -{ - ISADevice parent_obj; - - uint32_t queue[VMMOUSE_QUEUE_SIZE]; - int32_t queue_size; - uint16_t nb_queue; - uint16_t status; - uint8_t absolute; - QEMUPutMouseEntry *entry; - void *ps2_mouse; -} VMMouseState; - -static uint32_t vmmouse_get_status(VMMouseState *s) -{ - DPRINTF("vmmouse_get_status()\n"); - return (s->status << 16) | s->nb_queue; -} - -static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_state) -{ - VMMouseState *s = opaque; - int buttons = 0; - - if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4)) - return; - - DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n", - x, y, dz, buttons_state); - - if ((buttons_state & MOUSE_EVENT_LBUTTON)) - buttons |= 0x20; - if ((buttons_state & MOUSE_EVENT_RBUTTON)) - buttons |= 0x10; - if ((buttons_state & MOUSE_EVENT_MBUTTON)) - buttons |= 0x08; - - if (s->absolute) { - x <<= 1; - y <<= 1; - } - - s->queue[s->nb_queue++] = buttons; - s->queue[s->nb_queue++] = x; - s->queue[s->nb_queue++] = y; - s->queue[s->nb_queue++] = dz; - - /* need to still generate PS2 events to notify driver to - read from queue */ - i8042_isa_mouse_fake_event(s->ps2_mouse); -} - -static void vmmouse_remove_handler(VMMouseState *s) -{ - if (s->entry) { - qemu_remove_mouse_event_handler(s->entry); - s->entry = NULL; - } -} - -static void vmmouse_update_handler(VMMouseState *s, int absolute) -{ - if (s->status != 0) { - return; - } - if (s->absolute != absolute) { - s->absolute = absolute; - vmmouse_remove_handler(s); - } - if (s->entry == NULL) { - s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event, - s, s->absolute, - "vmmouse"); - qemu_activate_mouse_event_handler(s->entry); - } -} - -static void vmmouse_read_id(VMMouseState *s) -{ - DPRINTF("vmmouse_read_id()\n"); - - if (s->nb_queue == VMMOUSE_QUEUE_SIZE) - return; - - s->queue[s->nb_queue++] = VMMOUSE_VERSION; - s->status = 0; -} - -static void vmmouse_request_relative(VMMouseState *s) -{ - DPRINTF("vmmouse_request_relative()\n"); - vmmouse_update_handler(s, 0); -} - -static void vmmouse_request_absolute(VMMouseState *s) -{ - DPRINTF("vmmouse_request_absolute()\n"); - vmmouse_update_handler(s, 1); -} - -static void vmmouse_disable(VMMouseState *s) -{ - DPRINTF("vmmouse_disable()\n"); - s->status = 0xffff; - vmmouse_remove_handler(s); -} - -static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size) -{ - int i; - - DPRINTF("vmmouse_data(%d)\n", size); - - if (size == 0 || size > 6 || size > s->nb_queue) { - printf("vmmouse: driver requested too much data %d\n", size); - s->status = 0xffff; - vmmouse_remove_handler(s); - return; - } - - for (i = 0; i < size; i++) - data[i] = s->queue[i]; - - s->nb_queue -= size; - if (s->nb_queue) - memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue); -} - -static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr) -{ - VMMouseState *s = opaque; - uint32_t data[6]; - uint16_t command; - - vmmouse_get_data(data); - - command = data[2] & 0xFFFF; - - switch (command) { - case VMMOUSE_STATUS: - data[0] = vmmouse_get_status(s); - break; - case VMMOUSE_COMMAND: - switch (data[1]) { - case VMMOUSE_DISABLE: - vmmouse_disable(s); - break; - case VMMOUSE_READ_ID: - vmmouse_read_id(s); - break; - case VMMOUSE_REQUEST_RELATIVE: - vmmouse_request_relative(s); - break; - case VMMOUSE_REQUEST_ABSOLUTE: - vmmouse_request_absolute(s); - break; - default: - printf("vmmouse: unknown command %x\n", data[1]); - break; - } - break; - case VMMOUSE_DATA: - vmmouse_data(s, data, data[1]); - break; - default: - printf("vmmouse: unknown command %x\n", command); - break; - } - - vmmouse_set_data(data); - return data[0]; -} - -static int vmmouse_post_load(void *opaque, int version_id) -{ - VMMouseState *s = opaque; - - vmmouse_remove_handler(s); - vmmouse_update_handler(s, s->absolute); - return 0; -} - -static const VMStateDescription vmstate_vmmouse = { - .name = "vmmouse", - .version_id = 0, - .minimum_version_id = 0, - .post_load = vmmouse_post_load, - .fields = (VMStateField[]) { - VMSTATE_INT32_EQUAL(queue_size, VMMouseState), - VMSTATE_UINT32_ARRAY(queue, VMMouseState, VMMOUSE_QUEUE_SIZE), - VMSTATE_UINT16(nb_queue, VMMouseState), - VMSTATE_UINT16(status, VMMouseState), - VMSTATE_UINT8(absolute, VMMouseState), - VMSTATE_END_OF_LIST() - } -}; - -static void vmmouse_reset(DeviceState *d) -{ - VMMouseState *s = VMMOUSE(d); - - s->queue_size = VMMOUSE_QUEUE_SIZE; - - vmmouse_disable(s); -} - -static void vmmouse_realizefn(DeviceState *dev, Error **errp) -{ - VMMouseState *s = VMMOUSE(dev); - - DPRINTF("vmmouse_init\n"); - - vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s); - vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s); - vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s); -} - -static Property vmmouse_properties[] = { - DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse), - DEFINE_PROP_END_OF_LIST(), -}; - -static void vmmouse_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = vmmouse_realizefn; - dc->reset = vmmouse_reset; - dc->vmsd = &vmstate_vmmouse; - dc->props = vmmouse_properties; - /* Reason: pointer property "ps2_mouse" */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo vmmouse_info = { - .name = TYPE_VMMOUSE, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(VMMouseState), - .class_init = vmmouse_class_initfn, -}; - -static void vmmouse_register_types(void) -{ - type_register_static(&vmmouse_info); -} - -type_init(vmmouse_register_types) |