blob: 58bef78ddf5d468aa29cb0aaa27f539b6f58b00f [file] [log] [blame]
/*
* Goldfish 'events' device model, used for a rotary encoder device.
*
* Copyright (C) 2007-2008 The Android Open Source Project
* Copyright (c) 2014 Linaro Limited
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/sysbus.h"
#include "ui/input.h"
#include "ui/console.h"
#include "hw/input/android_keycodes.h"
#include "hw/input/linux_keycodes.h"
#include "hw/input/goldfish_events_common.h"
/* NOTE: The ev_bits arrays are used to indicate to the kernel
* which events can be sent by the emulated hardware.
*/
#define TYPE_ROTARYEVDEV "goldfish_rotary"
/* Pointer to the global device instance. Also serves as an initialization
* flag in goldfish_rotary_send_rotate() to filter-out events that are sent from
* the UI before the device was properly realized.
*/
static GoldfishEvDevState* s_evdev = NULL;
static const VMStateDescription vmstate_rotary_evdev =
GOLDFISHEVDEV_VM_STATE_DESCRIPTION("goldfish_rotary");
int goldfish_rotary_send_rotate(int value)
{
GoldfishEvDevState *dev = s_evdev;
if (dev) {
goldfish_enqueue_event(dev, EV_REL, REL_WHEEL, value);
goldfish_enqueue_event(dev, 0, 0, value);
}
return 0;
}
static const MemoryRegionOps rotary_evdev_ops = {
.read = goldfish_events_read,
.write = goldfish_events_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void rotary_evdev_init(Object *obj)
{
GoldfishEvDevState *s = GOLDFISHEVDEV(obj, TYPE_ROTARYEVDEV);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, obj, &rotary_evdev_ops, s,
"goldfish_rotary", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
}
static void rotary_evdev_realize(DeviceState *dev, Error **errp)
{
GoldfishEvDevState *s = GOLDFISHEVDEV(dev, TYPE_ROTARYEVDEV);
/* Initialize the device ID so the event dev can be looked up during
* monitor commands.
*/
dev->id = g_strdup(TYPE_ROTARYEVDEV);
/* now set the events capability bits depending on hardware configuration */
/* apparently, the EV_SYN array is used to indicate which other
* event classes to consider.
*/
s->name = "goldfish_rotary";
/* configure EV_KEY array */
goldfish_events_set_bit(s, EV_SYN, EV_KEY);
/* configure EV_REL array */
goldfish_events_set_bit(s, EV_SYN, EV_REL);
goldfish_events_set_bit(s, EV_REL, REL_WHEEL);
/* Register global variable. */
assert(s_evdev == NULL);
assert(s->state == 0);
s_evdev = s;
}
static void rotary_evdev_reset(DeviceState *dev)
{
GoldfishEvDevState *s = GOLDFISHEVDEV(dev, TYPE_ROTARYEVDEV);
s->first = 0;
s->last = 0;
}
static void rotary_evdev_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = rotary_evdev_realize;
dc->reset = rotary_evdev_reset;
dc->vmsd = &vmstate_rotary_evdev;
}
static const TypeInfo rotary_evdev_info = {
.name = TYPE_ROTARYEVDEV,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(GoldfishEvDevState),
.instance_init = rotary_evdev_init,
.class_init = rotary_evdev_class_init,
};
static void rotary_evdev_register_types(void)
{
type_register_static(&rotary_evdev_info);
}
type_init(rotary_evdev_register_types)