diff options
-rw-r--r-- | hw/ide/atapi.c | 26 | ||||
-rw-r--r-- | hw/ide/core.c | 39 | ||||
-rw-r--r-- | hw/ide/internal.h | 35 | ||||
-rw-r--r-- | hw/ide/macio.c | 2 | ||||
-rw-r--r-- | hw/ide/pci.c | 4 | ||||
-rw-r--r-- | hw/ide/piix.c | 1 | ||||
-rw-r--r-- | hw/input/virtio-input-hid.c | 6 | ||||
-rw-r--r-- | hw/input/virtio-input-host.c | 70 | ||||
-rw-r--r-- | hw/input/virtio-input.c | 46 | ||||
-rw-r--r-- | hw/misc/ivshmem.c | 30 | ||||
-rw-r--r-- | include/hw/virtio/virtio-input.h | 17 | ||||
-rw-r--r-- | include/qemu/bswap.h | 19 | ||||
-rw-r--r-- | ui/input-linux.c | 30 |
13 files changed, 262 insertions, 63 deletions
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 1fe58ab..2bb606c 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -375,15 +375,18 @@ static void ide_atapi_cmd_check_status(IDEState *s) } /* ATAPI DMA support */ -/* XXX: handle read errors */ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) { IDEState *s = opaque; int data_offset, n; if (ret < 0) { - ide_atapi_io_error(s, ret); - goto eot; + if (ide_handle_rw_error(s, -ret, ide_dma_cmd_to_retry(s->dma_cmd))) { + if (s->bus->error_status) { + return; + } + goto eot; + } } if (s->io_buffer_size > 0) { @@ -481,21 +484,16 @@ static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, } } - -/* Called by *_restart_bh when the transfer function points - * to ide_atapi_cmd - */ void ide_atapi_dma_restart(IDEState *s) { /* - * I'm not sure we have enough stored to restart the command - * safely, so give the guest an error it should recover from. - * I'm assuming most guests will try to recover from something - * listed as a medium error on a CD; it seems to work on Linux. - * This would be more of a problem if we did any other type of - * DMA operation. + * At this point we can just re-evaluate the packet command and start over. + * The presence of ->dma_cb callback in the pre_save ensures that the packet + * command has been completely sent and we can safely restart command. */ - ide_atapi_cmd_error(s, MEDIUM_ERROR, ASC_NO_SEEK_COMPLETE); + s->unit = s->bus->retry_unit; + s->bus->dma->ops->restart_dma(s->bus->dma); + ide_atapi_cmd(s); } static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index, diff --git a/hw/ide/core.c b/hw/ide/core.c index 90524d5..41e6a2d 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -57,7 +57,6 @@ static const int smart_attributes[][12] = { { 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32}, }; -static int ide_handle_rw_error(IDEState *s, int error, int op); static void ide_dummy_transfer_stop(IDEState *s); static void padstr(char *str, const char *src, int len) @@ -773,7 +772,7 @@ void ide_dma_error(IDEState *s) ide_set_irq(s->bus); } -static int ide_handle_rw_error(IDEState *s, int error, int op) +int ide_handle_rw_error(IDEState *s, int error, int op) { bool is_read = (op & IDE_RETRY_READ) != 0; BlockErrorAction action = blk_get_error_action(s->blk, is_read, error); @@ -783,8 +782,10 @@ static int ide_handle_rw_error(IDEState *s, int error, int op) s->bus->error_status = op; } else if (action == BLOCK_ERROR_ACTION_REPORT) { block_acct_failed(blk_get_stats(s->blk), &s->acct); - if (op & IDE_RETRY_DMA) { + if (IS_IDE_RETRY_DMA(op)) { ide_dma_error(s); + } else if (IS_IDE_RETRY_ATAPI(op)) { + ide_atapi_io_error(s, -error); } else { ide_rw_error(s); } @@ -804,14 +805,7 @@ static void ide_dma_cb(void *opaque, int ret) return; } if (ret < 0) { - int op = IDE_RETRY_DMA; - - if (s->dma_cmd == IDE_DMA_READ) - op |= IDE_RETRY_READ; - else if (s->dma_cmd == IDE_DMA_TRIM) - op |= IDE_RETRY_TRIM; - - if (ide_handle_rw_error(s, -ret, op)) { + if (ide_handle_rw_error(s, -ret, ide_dma_cmd_to_retry(s->dma_cmd))) { return; } } @@ -879,6 +873,8 @@ static void ide_dma_cb(void *opaque, int ret) ide_issue_trim, ide_dma_cb, s, DMA_DIRECTION_TO_DEVICE); break; + default: + abort(); } return; @@ -1641,6 +1637,9 @@ static bool cmd_packet(IDEState *s, uint8_t cmd) s->status = READY_STAT | SEEK_STAT; s->atapi_dma = s->feature & 1; + if (s->atapi_dma) { + s->dma_cmd = IDE_DMA_ATAPI; + } s->nsector = 1; ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, ide_atapi_cmd); @@ -2525,15 +2524,13 @@ static void ide_restart_bh(void *opaque) if (s->bus->dma->ops->restart) { s->bus->dma->ops->restart(s->bus->dma); } - } - - if (error_status & IDE_RETRY_DMA) { + } else if (IS_IDE_RETRY_DMA(error_status)) { if (error_status & IDE_RETRY_TRIM) { ide_restart_dma(s, IDE_DMA_TRIM); } else { ide_restart_dma(s, is_read ? IDE_DMA_READ : IDE_DMA_WRITE); } - } else if (error_status & IDE_RETRY_PIO) { + } else if (IS_IDE_RETRY_PIO(error_status)) { if (is_read) { ide_sector_read(s); } else { @@ -2541,15 +2538,11 @@ static void ide_restart_bh(void *opaque) } } else if (error_status & IDE_RETRY_FLUSH) { ide_flush_cache(s); + } else if (IS_IDE_RETRY_ATAPI(error_status)) { + assert(s->end_transfer_func == ide_atapi_cmd); + ide_atapi_dma_restart(s); } else { - /* - * We've not got any bits to tell us about ATAPI - but - * we do have the end_transfer_func that tells us what - * we're trying to do. - */ - if (s->end_transfer_func == ide_atapi_cmd) { - ide_atapi_dma_restart(s); - } + abort(); } } diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 86bde26..d2c458f 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -338,6 +338,7 @@ enum ide_dma_cmd { IDE_DMA_READ, IDE_DMA_WRITE, IDE_DMA_TRIM, + IDE_DMA_ATAPI, }; #define ide_cmd_is_read(s) \ @@ -506,13 +507,45 @@ struct IDEDevice { }; /* These are used for the error_status field of IDEBus */ +#define IDE_RETRY_MASK 0xf8 #define IDE_RETRY_DMA 0x08 #define IDE_RETRY_PIO 0x10 +#define IDE_RETRY_ATAPI 0x20 /* reused IDE_RETRY_READ bit */ #define IDE_RETRY_READ 0x20 #define IDE_RETRY_FLUSH 0x40 #define IDE_RETRY_TRIM 0x80 #define IDE_RETRY_HBA 0x100 +#define IS_IDE_RETRY_DMA(_status) \ + ((_status) & IDE_RETRY_DMA) + +#define IS_IDE_RETRY_PIO(_status) \ + ((_status) & IDE_RETRY_PIO) + +/* + * The method of the IDE_RETRY_ATAPI determination is to use a previously + * impossible bit combination as a new status value. + */ +#define IS_IDE_RETRY_ATAPI(_status) \ + (((_status) & IDE_RETRY_MASK) == IDE_RETRY_ATAPI) + +static inline uint8_t ide_dma_cmd_to_retry(uint8_t dma_cmd) +{ + switch (dma_cmd) { + case IDE_DMA_READ: + return IDE_RETRY_DMA | IDE_RETRY_READ; + case IDE_DMA_WRITE: + return IDE_RETRY_DMA; + case IDE_DMA_TRIM: + return IDE_RETRY_DMA | IDE_RETRY_TRIM; + case IDE_DMA_ATAPI: + return IDE_RETRY_ATAPI; + default: + break; + } + return 0; +} + static inline IDEState *idebus_active_if(IDEBus *bus) { return bus->ifs + bus->unit; @@ -597,4 +630,6 @@ void ide_bus_new(IDEBus *idebus, size_t idebus_size, DeviceState *dev, int bus_id, int max_units); IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive); +int ide_handle_rw_error(IDEState *s, int error, int op); + #endif /* HW_IDE_INTERNAL_H */ diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 1725e5b..76256eb 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -346,6 +346,8 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) case IDE_DMA_TRIM: pmac_dma_trim(s->blk, offset, io->len, pmac_ide_transfer_cb, io); break; + default: + abort(); } return; diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 92ffee7..8d56a00 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -308,6 +308,10 @@ static void ide_bmdma_pre_save(void *opaque) BMDMAState *bm = opaque; uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; + if (!(bm->status & BM_STATUS_DMAING) && bm->dma_cb) { + bm->bus->error_status = + ide_dma_cmd_to_retry(bmdma_active_if(bm)->dma_cmd); + } bm->migration_retry_unit = bm->bus->retry_unit; bm->migration_retry_sector_num = bm->bus->retry_sector_num; bm->migration_retry_nsector = bm->bus->retry_nsector; diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 0a4cbcb..6d76ce9 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -189,6 +189,7 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev) idedev = pci_ide->bus[di->bus].slave; } idedev->conf.blk = NULL; + monitor_remove_blk(blk); blk_unref(blk); } } diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c index 5d12157..3ee0c18 100644 --- a/hw/input/virtio-input-hid.c +++ b/hw/input/virtio-input-hid.c @@ -121,6 +121,8 @@ static const unsigned int keymap_qcode[Q_KEY_CODE__MAX] = { [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, @@ -482,12 +484,12 @@ static struct virtio_input_config virtio_tablet_config[] = { .select = VIRTIO_INPUT_CFG_ABS_INFO, .subsel = ABS_X, .size = sizeof(virtio_input_absinfo), - .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE), + .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), + .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1), }, { /* end of list */ }, }; diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c index 9e0f46d..cb79e80 100644 --- a/hw/input/virtio-input-host.c +++ b/hw/input/virtio-input-host.c @@ -70,13 +70,39 @@ static void virtio_input_bits_config(VirtIOInputHost *vih, 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; + virtio_input_config id, *abs; struct input_id ids; - int rc, ver; + int rc, ver, i, axis; + uint8_t byte; if (!vih->evdev) { error_setg(errp, "evdev property is required"); @@ -125,6 +151,23 @@ static void virtio_input_host_realize(DeviceState *dev, Error **errp) 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; @@ -145,6 +188,28 @@ static void virtio_input_host_unrealize(DeviceState *dev, Error **errp) } } +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, @@ -164,6 +229,7 @@ static void virtio_input_host_class_init(ObjectClass *klass, void *data) 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) diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index 672c207..f59749a 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -14,6 +14,8 @@ #include "standard-headers/linux/input.h" +#define VIRTIO_INPUT_VM_VERSION 1 + /* ----------------------------------------------------------------- */ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event) @@ -97,9 +99,9 @@ static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq) virtio_notify(vdev, vinput->sts); } -static virtio_input_config *virtio_input_find_config(VirtIOInput *vinput, - uint8_t select, - uint8_t subsel) +virtio_input_config *virtio_input_find_config(VirtIOInput *vinput, + uint8_t select, + uint8_t subsel) { VirtIOInputConfig *cfg; @@ -214,6 +216,38 @@ static void virtio_input_reset(VirtIODevice *vdev) } } +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); @@ -245,14 +279,20 @@ static void virtio_input_device_realize(DeviceState *dev, Error **errp) 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) { diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 2eb8668..e40f23b 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -872,6 +872,8 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem, &error_abort); } else { + assert(s->server_chr); + IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n", s->server_chr->filename); @@ -1051,10 +1053,24 @@ static void ivshmem_plain_init(Object *obj) &error_abort); } +static void ivshmem_plain_realize(PCIDevice *dev, Error **errp) +{ + IVShmemState *s = IVSHMEM_COMMON(dev); + + if (!s->hostmem) { + error_setg(errp, "You must specify a 'memdev'"); + return; + } + + ivshmem_common_realize(dev, errp); +} + static void ivshmem_plain_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + k->realize = ivshmem_plain_realize; dc->props = ivshmem_plain_properties; dc->vmsd = &ivshmem_plain_vmsd; } @@ -1099,10 +1115,24 @@ static void ivshmem_doorbell_init(Object *obj) s->legacy_size = SIZE_MAX; /* whatever the server sends */ } +static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp) +{ + IVShmemState *s = IVSHMEM_COMMON(dev); + + if (!s->server_chr) { + error_setg(errp, "You must specify a 'chardev'"); + return; + } + + ivshmem_common_realize(dev, errp); +} + static void ivshmem_doorbell_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + k->realize = ivshmem_doorbell_realize; dc->props = ivshmem_doorbell_properties; dc->vmsd = &ivshmem_doorbell_vmsd; } diff --git a/include/hw/virtio/virtio-input.h b/include/hw/virtio/virtio-input.h index af1c207..bddbd4b 100644 --- a/include/hw/virtio/virtio-input.h +++ b/include/hw/virtio/virtio-input.h @@ -13,20 +13,6 @@ typedef struct virtio_input_absinfo virtio_input_absinfo; typedef struct virtio_input_config virtio_input_config; typedef struct virtio_input_event virtio_input_event; -#if defined(HOST_WORDS_BIGENDIAN) -# define const_le32(_x) \ - (((_x & 0x000000ffU) << 24) | \ - ((_x & 0x0000ff00U) << 8) | \ - ((_x & 0x00ff0000U) >> 8) | \ - ((_x & 0xff000000U) >> 24)) -# define const_le16(_x) \ - (((_x & 0x00ff) << 8) | \ - ((_x & 0xff00) >> 8)) -#else -# define const_le32(_x) (_x) -# define const_le16(_x) (_x) -#endif - /* ----------------------------------------------------------------- */ /* qemu internals */ @@ -111,6 +97,9 @@ struct VirtIOInputHost { void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event); void virtio_input_init_config(VirtIOInput *vinput, virtio_input_config *config); +virtio_input_config *virtio_input_find_config(VirtIOInput *vinput, + uint8_t select, + uint8_t subsel); void virtio_input_add_config(VirtIOInput *vinput, virtio_input_config *config); void virtio_input_idstr_config(VirtIOInput *vinput, diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index fcedf0d..ce3c42e 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -125,6 +125,25 @@ static inline uint32_t qemu_bswap_len(uint32_t value, int len) return bswap32(value) >> (32 - 8 * len); } +/* + * Same as cpu_to_le{16,23}, except that gcc will figure the result is + * a compile-time constant if you pass in a constant. So this can be + * used to initialize static variables. + */ +#if defined(HOST_WORDS_BIGENDIAN) +# define const_le32(_x) \ + ((((_x) & 0x000000ffU) << 24) | \ + (((_x) & 0x0000ff00U) << 8) | \ + (((_x) & 0x00ff0000U) >> 8) | \ + (((_x) & 0xff000000U) >> 24)) +# define const_le16(_x) \ + ((((_x) & 0x00ff) << 8) | \ + (((_x) & 0xff00) >> 8)) +#else +# define const_le32(_x) (_x) +# define const_le16(_x) (_x) +#endif + /* Unions for reinterpreting between floats and integers. */ typedef union { diff --git a/ui/input-linux.c b/ui/input-linux.c index 9c921cc..1d33b5c 100644 --- a/ui/input-linux.c +++ b/ui/input-linux.c @@ -337,7 +337,7 @@ static void input_linux_event_mouse(void *opaque) static void input_linux_complete(UserCreatable *uc, Error **errp) { InputLinux *il = INPUT_LINUX(uc); - uint32_t evtmap; + uint32_t evtmap, relmap, absmap; int rc, ver; if (!il->evdev) { @@ -359,16 +359,36 @@ static void input_linux_complete(UserCreatable *uc, Error **errp) } rc = ioctl(il->fd, EVIOCGBIT(0, sizeof(evtmap)), &evtmap); + if (rc < 0) { + error_setg(errp, "%s: failed to read event bits", il->evdev); + goto err_close; + } if (evtmap & (1 << EV_REL)) { - /* has relative axis -> assume mouse */ + rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap); + if (rc < 0) { + relmap = 0; + } + } + + if (evtmap & (1 << EV_ABS)) { + ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap); + if (rc < 0) { + absmap = 0; + } + } + + if ((evtmap & (1 << EV_REL)) && + (relmap & (1 << REL_X))) { + /* has relative x axis -> assume mouse */ qemu_set_fd_handler(il->fd, input_linux_event_mouse, NULL, il); - } else if (evtmap & (1 << EV_ABS)) { - /* has absolute axis -> not supported */ + } else if ((evtmap & (1 << EV_ABS)) && + (absmap & (1 << ABS_X))) { + /* has absolute x axis -> not supported */ error_setg(errp, "tablet/touchscreen not supported"); goto err_close; } else if (evtmap & (1 << EV_KEY)) { - /* has keys/buttons (and no axis) -> assume keyboard */ + /* has keys/buttons (and no x axis) -> assume keyboard */ qemu_set_fd_handler(il->fd, input_linux_event_keyboard, NULL, il); } else { /* Huh? What is this? */ |