diff options
58 files changed, 609 insertions, 414 deletions
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c index cfc79c129e..3dd2c4d4a6 100644 --- a/audio/dsoundaudio.c +++ b/audio/dsoundaudio.c @@ -536,13 +536,12 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size) DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer; HRESULT hr; - DWORD cpos, rpos, act_size; + DWORD rpos, act_size; size_t req_size; int err; void *ret; - hr = IDirectSoundCaptureBuffer_GetCurrentPosition( - dscb, &cpos, ds->first_time ? &rpos : NULL); + hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dscb, NULL, &rpos); if (FAILED(hr)) { dsound_logerr(hr, "Could not get capture buffer position\n"); *size = 0; @@ -554,7 +553,7 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size) ds->first_time = false; } - req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul); + req_size = audio_ring_dist(rpos, hw->pos_emul, hw->size_emul); req_size = MIN(*size, MIN(req_size, hw->size_emul - hw->pos_emul)); if (req_size == 0) { diff --git a/audio/jackaudio.c b/audio/jackaudio.c index e7de6d5433..317009e936 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -622,6 +622,7 @@ static void qjack_enable_in(HWVoiceIn *hw, bool enable) ji->c.enabled = enable; } +#if !defined(WIN32) && defined(CONFIG_PTHREAD_SETNAME_NP_W_TID) static int qjack_thread_creator(jack_native_thread_t *thread, const pthread_attr_t *attr, void *(*function)(void *), void *arg) { @@ -635,6 +636,7 @@ static int qjack_thread_creator(jack_native_thread_t *thread, return ret; } +#endif static void *qjack_init(Audiodev *dev) { @@ -687,7 +689,9 @@ static void register_audio_jack(void) { qemu_mutex_init(&qjack_shutdown_lock); audio_driver_register(&jack_driver); +#if !defined(WIN32) && defined(CONFIG_PTHREAD_SETNAME_NP_W_TID) jack_set_thread_creator(qjack_thread_creator); +#endif jack_set_error_function(qjack_error); jack_set_info_function(qjack_info); } diff --git a/block/curl.c b/block/curl.c index 4a8ae2b269..6a6cd72975 100644 --- a/block/curl.c +++ b/block/curl.c @@ -125,7 +125,7 @@ static gboolean curl_drop_socket(void *key, void *value, void *opaque) BDRVCURLState *s = socket->s; aio_set_fd_handler(s->aio_context, socket->fd, false, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); return true; } @@ -173,19 +173,20 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action, switch (action) { case CURL_POLL_IN: aio_set_fd_handler(s->aio_context, fd, false, - curl_multi_do, NULL, NULL, socket); + curl_multi_do, NULL, NULL, NULL, socket); break; case CURL_POLL_OUT: aio_set_fd_handler(s->aio_context, fd, false, - NULL, curl_multi_do, NULL, socket); + NULL, curl_multi_do, NULL, NULL, socket); break; case CURL_POLL_INOUT: aio_set_fd_handler(s->aio_context, fd, false, - curl_multi_do, curl_multi_do, NULL, socket); + curl_multi_do, curl_multi_do, + NULL, NULL, socket); break; case CURL_POLL_REMOVE: aio_set_fd_handler(s->aio_context, fd, false, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); break; } diff --git a/block/export/fuse.c b/block/export/fuse.c index 823c126d23..6710d8aed8 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -223,7 +223,7 @@ static int setup_fuse_export(FuseExport *exp, const char *mountpoint, aio_set_fd_handler(exp->common.ctx, fuse_session_fd(exp->fuse_session), true, - read_from_fuse_export, NULL, NULL, exp); + read_from_fuse_export, NULL, NULL, NULL, exp); exp->fd_handler_set_up = true; return 0; @@ -267,7 +267,7 @@ static void fuse_export_shutdown(BlockExport *blk_exp) if (exp->fd_handler_set_up) { aio_set_fd_handler(exp->common.ctx, fuse_session_fd(exp->fuse_session), true, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); exp->fd_handler_set_up = false; } } diff --git a/block/io_uring.c b/block/io_uring.c index dfa475cc87..782afdb433 100644 --- a/block/io_uring.c +++ b/block/io_uring.c @@ -292,12 +292,14 @@ static bool qemu_luring_poll_cb(void *opaque) { LuringState *s = opaque; - if (io_uring_cq_ready(&s->ring)) { - luring_process_completions_and_submit(s); - return true; - } + return io_uring_cq_ready(&s->ring); +} + +static void qemu_luring_poll_ready(void *opaque) +{ + LuringState *s = opaque; - return false; + luring_process_completions_and_submit(s); } static void ioq_init(LuringQueue *io_q) @@ -402,8 +404,8 @@ int coroutine_fn luring_co_submit(BlockDriverState *bs, LuringState *s, int fd, void luring_detach_aio_context(LuringState *s, AioContext *old_context) { - aio_set_fd_handler(old_context, s->ring.ring_fd, false, NULL, NULL, NULL, - s); + aio_set_fd_handler(old_context, s->ring.ring_fd, false, + NULL, NULL, NULL, NULL, s); qemu_bh_delete(s->completion_bh); s->aio_context = NULL; } @@ -413,7 +415,8 @@ void luring_attach_aio_context(LuringState *s, AioContext *new_context) s->aio_context = new_context; s->completion_bh = aio_bh_new(new_context, qemu_luring_completion_bh, s); aio_set_fd_handler(s->aio_context, s->ring.ring_fd, false, - qemu_luring_completion_cb, NULL, qemu_luring_poll_cb, s); + qemu_luring_completion_cb, NULL, + qemu_luring_poll_cb, qemu_luring_poll_ready, s); } LuringState *luring_init(Error **errp) diff --git a/block/iscsi.c b/block/iscsi.c index 57aa07a40d..51f2a5eeaa 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -363,7 +363,7 @@ iscsi_set_events(IscsiLun *iscsilun) false, (ev & POLLIN) ? iscsi_process_read : NULL, (ev & POLLOUT) ? iscsi_process_write : NULL, - NULL, + NULL, NULL, iscsilun); iscsilun->events = ev; } @@ -1534,7 +1534,7 @@ static void iscsi_detach_aio_context(BlockDriverState *bs) IscsiLun *iscsilun = bs->opaque; aio_set_fd_handler(iscsilun->aio_context, iscsi_get_fd(iscsilun->iscsi), - false, NULL, NULL, NULL, NULL); + false, NULL, NULL, NULL, NULL, NULL); iscsilun->events = 0; if (iscsilun->nop_timer) { diff --git a/block/linux-aio.c b/block/linux-aio.c index f53ae72e21..4c423fcccf 100644 --- a/block/linux-aio.c +++ b/block/linux-aio.c @@ -263,12 +263,15 @@ static bool qemu_laio_poll_cb(void *opaque) LinuxAioState *s = container_of(e, LinuxAioState, e); struct io_event *events; - if (!io_getevents_peek(s->ctx, &events)) { - return false; - } + return io_getevents_peek(s->ctx, &events); +} + +static void qemu_laio_poll_ready(EventNotifier *opaque) +{ + EventNotifier *e = opaque; + LinuxAioState *s = container_of(e, LinuxAioState, e); qemu_laio_process_completions_and_submit(s); - return true; } static void ioq_init(LaioQueue *io_q) @@ -427,7 +430,7 @@ int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd, void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context) { - aio_set_event_notifier(old_context, &s->e, false, NULL, NULL); + aio_set_event_notifier(old_context, &s->e, false, NULL, NULL, NULL); qemu_bh_delete(s->completion_bh); s->aio_context = NULL; } @@ -438,7 +441,8 @@ void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context) s->completion_bh = aio_bh_new(new_context, qemu_laio_completion_bh, s); aio_set_event_notifier(new_context, &s->e, false, qemu_laio_completion_cb, - qemu_laio_poll_cb); + qemu_laio_poll_cb, + qemu_laio_poll_ready); } LinuxAioState *laio_init(Error **errp) diff --git a/block/nfs.c b/block/nfs.c index 577aea1d22..444c40b458 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -197,7 +197,7 @@ static void nfs_set_events(NFSClient *client) false, (ev & POLLIN) ? nfs_process_read : NULL, (ev & POLLOUT) ? nfs_process_write : NULL, - NULL, client); + NULL, NULL, client); } client->events = ev; @@ -372,7 +372,7 @@ static void nfs_detach_aio_context(BlockDriverState *bs) NFSClient *client = bs->opaque; aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context), - false, NULL, NULL, NULL, NULL); + false, NULL, NULL, NULL, NULL, NULL); client->events = 0; } @@ -390,7 +390,7 @@ static void nfs_client_close(NFSClient *client) if (client->context) { qemu_mutex_lock(&client->mutex); aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context), - false, NULL, NULL, NULL, NULL); + false, NULL, NULL, NULL, NULL, NULL); qemu_mutex_unlock(&client->mutex); if (client->fh) { nfs_close(client->context, client->fh); diff --git a/block/nvme.c b/block/nvme.c index fa360b9b3c..dd20de3865 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -605,10 +605,8 @@ out: return ret; } -static bool nvme_poll_queue(NVMeQueuePair *q) +static void nvme_poll_queue(NVMeQueuePair *q) { - bool progress = false; - const size_t cqe_offset = q->cq.head * NVME_CQ_ENTRY_BYTES; NvmeCqe *cqe = (NvmeCqe *)&q->cq.queue[cqe_offset]; @@ -619,30 +617,23 @@ static bool nvme_poll_queue(NVMeQueuePair *q) * cannot race with itself. */ if ((le16_to_cpu(cqe->status) & 0x1) == q->cq_phase) { - return false; + return; } qemu_mutex_lock(&q->lock); while (nvme_process_completion(q)) { /* Keep polling */ - progress = true; } qemu_mutex_unlock(&q->lock); - - return progress; } -static bool nvme_poll_queues(BDRVNVMeState *s) +static void nvme_poll_queues(BDRVNVMeState *s) { - bool progress = false; int i; for (i = 0; i < s->queue_count; i++) { - if (nvme_poll_queue(s->queues[i])) { - progress = true; - } + nvme_poll_queue(s->queues[i]); } - return progress; } static void nvme_handle_event(EventNotifier *n) @@ -703,8 +694,30 @@ static bool nvme_poll_cb(void *opaque) EventNotifier *e = opaque; BDRVNVMeState *s = container_of(e, BDRVNVMeState, irq_notifier[MSIX_SHARED_IRQ_IDX]); + int i; - return nvme_poll_queues(s); + for (i = 0; i < s->queue_count; i++) { + NVMeQueuePair *q = s->queues[i]; + const size_t cqe_offset = q->cq.head * NVME_CQ_ENTRY_BYTES; + NvmeCqe *cqe = (NvmeCqe *)&q->cq.queue[cqe_offset]; + + /* + * q->lock isn't needed because nvme_process_completion() only runs in + * the event loop thread and cannot race with itself. + */ + if ((le16_to_cpu(cqe->status) & 0x1) != q->cq_phase) { + return true; + } + } + return false; +} + +static void nvme_poll_ready(EventNotifier *e) +{ + BDRVNVMeState *s = container_of(e, BDRVNVMeState, + irq_notifier[MSIX_SHARED_IRQ_IDX]); + + nvme_poll_queues(s); } static int nvme_init(BlockDriverState *bs, const char *device, int namespace, @@ -839,7 +852,8 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace, } aio_set_event_notifier(bdrv_get_aio_context(bs), &s->irq_notifier[MSIX_SHARED_IRQ_IDX], - false, nvme_handle_event, nvme_poll_cb); + false, nvme_handle_event, nvme_poll_cb, + nvme_poll_ready); if (!nvme_identify(bs, namespace, errp)) { ret = -EIO; @@ -924,7 +938,7 @@ static void nvme_close(BlockDriverState *bs) g_free(s->queues); aio_set_event_notifier(bdrv_get_aio_context(bs), &s->irq_notifier[MSIX_SHARED_IRQ_IDX], - false, NULL, NULL); + false, NULL, NULL, NULL); event_notifier_cleanup(&s->irq_notifier[MSIX_SHARED_IRQ_IDX]); qemu_vfio_pci_unmap_bar(s->vfio, 0, s->bar0_wo_map, 0, sizeof(NvmeBar) + NVME_DOORBELL_SIZE); @@ -1520,7 +1534,7 @@ static void nvme_detach_aio_context(BlockDriverState *bs) aio_set_event_notifier(bdrv_get_aio_context(bs), &s->irq_notifier[MSIX_SHARED_IRQ_IDX], - false, NULL, NULL); + false, NULL, NULL, NULL); } static void nvme_attach_aio_context(BlockDriverState *bs, @@ -1530,7 +1544,8 @@ static void nvme_attach_aio_context(BlockDriverState *bs, s->aio_context = new_context; aio_set_event_notifier(new_context, &s->irq_notifier[MSIX_SHARED_IRQ_IDX], - false, nvme_handle_event, nvme_poll_cb); + false, nvme_handle_event, nvme_poll_cb, + nvme_poll_ready); for (unsigned i = 0; i < s->queue_count; i++) { NVMeQueuePair *q = s->queues[i]; diff --git a/block/ssh.c b/block/ssh.c index e0fbb4934b..3b5bf34031 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -990,7 +990,7 @@ static void restart_coroutine(void *opaque) AioContext *ctx = bdrv_get_aio_context(bs); trace_ssh_restart_coroutine(restart->co); - aio_set_fd_handler(ctx, s->sock, false, NULL, NULL, NULL, NULL); + aio_set_fd_handler(ctx, s->sock, false, NULL, NULL, NULL, NULL, NULL); aio_co_wake(restart->co); } @@ -1020,7 +1020,7 @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs) trace_ssh_co_yield(s->sock, rd_handler, wr_handler); aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock, - false, rd_handler, wr_handler, NULL, &restart); + false, rd_handler, wr_handler, NULL, NULL, &restart); qemu_coroutine_yield(); trace_ssh_co_yield_back(s->sock); } diff --git a/block/win32-aio.c b/block/win32-aio.c index b7221a272f..c57e10c997 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -172,7 +172,7 @@ int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile) void win32_aio_detach_aio_context(QEMUWin32AIOState *aio, AioContext *old_context) { - aio_set_event_notifier(old_context, &aio->e, false, NULL, NULL); + aio_set_event_notifier(old_context, &aio->e, false, NULL, NULL, NULL); aio->aio_ctx = NULL; } @@ -181,7 +181,7 @@ void win32_aio_attach_aio_context(QEMUWin32AIOState *aio, { aio->aio_ctx = new_context; aio_set_event_notifier(new_context, &aio->e, false, - win32_aio_completion_cb, NULL); + win32_aio_completion_cb, NULL, NULL); } QEMUWin32AIOState *win32_aio_init(void) diff --git a/configs/devices/mips-softmmu/common.mak b/configs/devices/mips-softmmu/common.mak index 752b62b1e6..d2202c839e 100644 --- a/configs/devices/mips-softmmu/common.mak +++ b/configs/devices/mips-softmmu/common.mak @@ -7,7 +7,7 @@ CONFIG_ISA_BUS=y CONFIG_PCI=y CONFIG_PCI_DEVICES=y CONFIG_VGA_ISA=y -CONFIG_VGA_ISA_MM=y +CONFIG_VGA_MMIO=y CONFIG_VGA_CIRRUS=y CONFIG_VMWARE_VGA=y CONFIG_SERIAL=y diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 2b55d52150..5f8a878f20 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -581,7 +581,7 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3 if (st->ctl & 0x01) { /* reset */ dprint(d, 1, "st #%d: reset\n", reg->stream); - st->ctl = SD_STS_FIFO_READY << 24; + st->ctl = SD_STS_FIFO_READY << 24 | SD_CTL_STREAM_RESET; } if ((st->ctl & 0x02) != (old & 0x02)) { uint32_t stnr = (st->ctl >> 20) & 0x0f; diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index ee5a5352dc..49276e46f2 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -154,17 +154,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) g_free(s); } -static bool virtio_blk_data_plane_handle_output(VirtIODevice *vdev, - VirtQueue *vq) -{ - VirtIOBlock *s = (VirtIOBlock *)vdev; - - assert(s->dataplane); - assert(s->dataplane_started); - - return virtio_blk_handle_vq(s, vq); -} - /* Context: QEMU global mutex held */ int virtio_blk_data_plane_start(VirtIODevice *vdev) { @@ -258,8 +247,7 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) for (i = 0; i < nvqs; i++) { VirtQueue *vq = virtio_get_queue(s->vdev, i); - virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, - virtio_blk_data_plane_handle_output); + virtio_queue_aio_attach_host_notifier(vq, s->ctx); } aio_context_release(s->ctx); return 0; @@ -302,7 +290,7 @@ static void virtio_blk_data_plane_stop_bh(void *opaque) for (i = 0; i < s->conf->num_queues; i++) { VirtQueue *vq = virtio_get_queue(s->vdev, i); - virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, NULL); + virtio_queue_aio_detach_host_notifier(vq, s->ctx); } } diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index f139cd7cc9..82676cdd01 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -767,12 +767,11 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) return 0; } -bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) +void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) { VirtIOBlockReq *req; MultiReqBuffer mrb = {}; bool suppress_notifications = virtio_queue_get_notification(vq); - bool progress = false; aio_context_acquire(blk_get_aio_context(s->blk)); blk_io_plug(s->blk); @@ -783,7 +782,6 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) } while ((req = virtio_blk_get_request(s, vq))) { - progress = true; if (virtio_blk_handle_request(req, &mrb)) { virtqueue_detach_element(req->vq, &req->elem, 0); virtio_blk_free_request(req); @@ -802,19 +800,13 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) blk_io_unplug(s->blk); aio_context_release(blk_get_aio_context(s->blk)); - return progress; -} - -static void virtio_blk_handle_output_do(VirtIOBlock *s, VirtQueue *vq) -{ - virtio_blk_handle_vq(s, vq); } static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) { VirtIOBlock *s = (VirtIOBlock *)vdev; - if (s->dataplane) { + if (s->dataplane && !s->dataplane_started) { /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start * dataplane here instead of waiting for .set_status(). */ @@ -823,7 +815,7 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) return; } } - virtio_blk_handle_output_do(s, vq); + virtio_blk_handle_vq(s, vq); } void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh) diff --git a/hw/display/Kconfig b/hw/display/Kconfig index a2306b67d8..a1b159becd 100644 --- a/hw/display/Kconfig +++ b/hw/display/Kconfig @@ -49,7 +49,7 @@ config VGA_ISA depends on ISA_BUS select VGA -config VGA_ISA_MM +config VGA_MMIO bool select VGA diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index f2b874d5e3..bccf32af69 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -24,6 +24,9 @@ static const struct edid_mode { { .xres = 2048, .yres = 1152 }, { .xres = 1920, .yres = 1080, .dta = 31 }, + /* dea/dta extension timings (all @ 60 Hz) */ + { .xres = 3840, .yres = 2160, .dta = 97 }, + /* additional standard timings 3 (all @ 60Hz) */ { .xres = 1920, .yres = 1200, .xtra3 = 10, .bit = 0 }, { .xres = 1600, .yres = 1200, .xtra3 = 9, .bit = 2 }, @@ -401,10 +404,10 @@ void qemu_edid_generate(uint8_t *edid, size_t size, info->name = "QEMU Monitor"; } if (!info->prefx) { - info->prefx = 1024; + info->prefx = 1280; } if (!info->prefy) { - info->prefy = 768; + info->prefy = 800; } if (info->prefx >= 4096 || info->prefy >= 4096) { large_screen = 1; diff --git a/hw/display/meson.build b/hw/display/meson.build index 861c43ff98..adc53dd8b6 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -18,7 +18,7 @@ softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xenfb.c')) softmmu_ss.add(when: 'CONFIG_VGA_PCI', if_true: files('vga-pci.c')) softmmu_ss.add(when: 'CONFIG_VGA_ISA', if_true: files('vga-isa.c')) -softmmu_ss.add(when: 'CONFIG_VGA_ISA_MM', if_true: files('vga-isa-mm.c')) +softmmu_ss.add(when: 'CONFIG_VGA_MMIO', if_true: files('vga-mmio.c')) softmmu_ss.add(when: 'CONFIG_VMWARE_VGA', if_true: files('vmware_vga.c')) softmmu_ss.add(when: 'CONFIG_BOCHS_DISPLAY', if_true: files('bochs-display.c')) diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c deleted file mode 100644 index 7321b7a06d..0000000000 --- a/hw/display/vga-isa-mm.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * QEMU ISA MM VGA Emulator. - * - * 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 "qemu/bitops.h" -#include "qemu/units.h" -#include "migration/vmstate.h" -#include "hw/display/vga.h" -#include "vga_int.h" -#include "ui/pixel_ops.h" - -#define VGA_RAM_SIZE (8 * MiB) - -typedef struct ISAVGAMMState { - VGACommonState vga; - int it_shift; -} ISAVGAMMState; - -/* Memory mapped interface */ -static uint64_t vga_mm_read(void *opaque, hwaddr addr, unsigned size) -{ - ISAVGAMMState *s = opaque; - - return vga_ioport_read(&s->vga, addr >> s->it_shift) & - MAKE_64BIT_MASK(0, size * 8); -} - -static void vga_mm_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - ISAVGAMMState *s = opaque; - - vga_ioport_write(&s->vga, addr >> s->it_shift, - value & MAKE_64BIT_MASK(0, size * 8)); -} - -static const MemoryRegionOps vga_mm_ctrl_ops = { - .read = vga_mm_read, - .write = vga_mm_write, - .valid.min_access_size = 1, - .valid.max_access_size = 4, - .impl.min_access_size = 1, - .impl.max_access_size = 4, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void vga_mm_init(ISAVGAMMState *s, hwaddr vram_base, - hwaddr ctrl_base, int it_shift, - MemoryRegion *address_space) -{ - MemoryRegion *s_ioport_ctrl, *vga_io_memory; - - s->it_shift = it_shift; - s_ioport_ctrl = g_malloc(sizeof(*s_ioport_ctrl)); - memory_region_init_io(s_ioport_ctrl, NULL, &vga_mm_ctrl_ops, s, - "vga-mm-ctrl", 0x100000); - memory_region_set_flush_coalesced(s_ioport_ctrl); - - vga_io_memory = g_malloc(sizeof(*vga_io_memory)); - /* XXX: endianness? */ - memory_region_init_io(vga_io_memory, NULL, &vga_mem_ops, &s->vga, - "vga-mem", 0x20000); - - vmstate_register(NULL, 0, &vmstate_vga_common, s); - - memory_region_add_subregion(address_space, ctrl_base, s_ioport_ctrl); - s->vga.bank_offset = 0; - memory_region_add_subregion(address_space, - vram_base + 0x000a0000, vga_io_memory); - memory_region_set_coalescing(vga_io_memory); -} - -int isa_vga_mm_init(hwaddr vram_base, - hwaddr ctrl_base, int it_shift, - MemoryRegion *address_space) -{ - ISAVGAMMState *s; - - s = g_malloc0(sizeof(*s)); - - s->vga.vram_size_mb = VGA_RAM_SIZE / MiB; - s->vga.global_vmstate = true; - vga_common_init(&s->vga, NULL); - vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space); - - s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s); - - memory_region_add_subregion(address_space, - VBE_DISPI_LFB_PHYSICAL_ADDRESS, - &s->vga.vram); - - return 0; -} diff --git a/hw/display/vga-mmio.c b/hw/display/vga-mmio.c new file mode 100644 index 0000000000..4969368081 --- /dev/null +++ b/hw/display/vga-mmio.c @@ -0,0 +1,139 @@ +/* + * QEMU MMIO VGA Emulator. + * + * 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 "qapi/error.h" +#include "hw/sysbus.h" +#include "hw/display/vga.h" +#include "hw/qdev-properties.h" +#include "vga_int.h" + +/* + * QEMU interface: + * + sysbus MMIO region 0: VGA I/O registers + * + sysbus MMIO region 1: VGA MMIO registers + * + sysbus MMIO region 2: VGA memory + */ + +OBJECT_DECLARE_SIMPLE_TYPE(VGAMmioState, VGA_MMIO) + +struct VGAMmioState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + VGACommonState vga; + MemoryRegion iomem; + MemoryRegion lowmem; + + uint8_t it_shift; +}; + +static uint64_t vga_mm_read(void *opaque, hwaddr addr, unsigned size) +{ + VGAMmioState *s = opaque; + + return vga_ioport_read(&s->vga, addr >> s->it_shift) & + MAKE_64BIT_MASK(0, size * 8); +} + +static void vga_mm_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + VGAMmioState *s = opaque; + + vga_ioport_write(&s->vga, addr >> s->it_shift, + value & MAKE_64BIT_MASK(0, size * 8)); +} + +static const MemoryRegionOps vga_mm_ctrl_ops = { + .read = vga_mm_read, + .write = vga_mm_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 4, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void vga_mmio_reset(DeviceState *dev) +{ + VGAMmioState *s = VGA_MMIO(dev); + + vga_common_reset(&s->vga); +} + +static void vga_mmio_realizefn(DeviceState *dev, Error **errp) +{ + VGAMmioState *s = VGA_MMIO(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(dev), &vga_mm_ctrl_ops, s, + "vga-mmio", 0x100000); + memory_region_set_flush_coalesced(&s->iomem); + sysbus_init_mmio(sbd, &s->iomem); + + /* XXX: endianness? */ + memory_region_init_io(&s->lowmem, OBJECT(dev), &vga_mem_ops, &s->vga, + "vga-lowmem", 0x20000); + memory_region_set_coalescing(&s->lowmem); + sysbus_init_mmio(sbd, &s->lowmem); + + s->vga.bank_offset = 0; + s->vga.global_vmstate = true; + vga_common_init(&s->vga, OBJECT(dev)); + sysbus_init_mmio(sbd, &s->vga.vram); + s->vga.con = graphic_console_init(dev, 0, s->vga.hw_ops, &s->vga); +} + +static Property vga_mmio_properties[] = { + DEFINE_PROP_UINT8("it_shift", VGAMmioState, it_shift, 0), + DEFINE_PROP_UINT32("vgamem_mb", VGAMmioState, vga.vram_size_mb, 8), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vga_mmio_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = vga_mmio_realizefn; + dc->reset = vga_mmio_reset; + dc->vmsd = &vmstate_vga_common; + device_class_set_props(dc, vga_mmio_properties); + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); +} + +static const TypeInfo vga_mmio_info = { + .name = TYPE_VGA_MMIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(VGAMmioState), + .class_init = vga_mmio_class_initfn, +}; + +static void vga_mmio_register_types(void) +{ + type_register_static(&vga_mmio_info); +} + +type_init(vga_mmio_register_types) diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 9376a8f4ce..6236711e1b 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -123,6 +123,7 @@ typedef struct { int mouse_dx; /* current values, needed for 'poll' mode */ int mouse_dy; int mouse_dz; + int mouse_dw; uint8_t mouse_buttons; } PS2MouseState; @@ -715,7 +716,7 @@ static int ps2_mouse_send_packet(PS2MouseState *s) /* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */ const int needed = s->mouse_type ? 4 : 3; unsigned int b; - int dx1, dy1, dz1; + int dx1, dy1, dz1, dw1; if (PS2_QUEUE_SIZE - s->common.queue.count < needed) { return 0; @@ -724,6 +725,7 @@ static int ps2_mouse_send_packet(PS2MouseState *s) dx1 = s->mouse_dx; dy1 = s->mouse_dy; dz1 = s->mouse_dz; + dw1 = s->mouse_dw; /* XXX: increase range to 8 bits ? */ if (dx1 > 127) dx1 = 127; @@ -740,6 +742,9 @@ static int ps2_mouse_send_packet(PS2MouseState *s) /* extra byte for IMPS/2 or IMEX */ switch(s->mouse_type) { default: + /* Just ignore the wheels if not supported */ + s->mouse_dz = 0; + s->mouse_dw = 0; break; case 3: if (dz1 > 127) @@ -747,13 +752,41 @@ static int ps2_mouse_send_packet(PS2MouseState *s) else if (dz1 < -127) dz1 = -127; ps2_queue_noirq(&s->common, dz1 & 0xff); + s->mouse_dz -= dz1; + s->mouse_dw = 0; break; case 4: - if (dz1 > 7) - dz1 = 7; - else if (dz1 < -7) - dz1 = -7; - b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); + /* + * This matches what the Linux kernel expects for exps/2 in + * drivers/input/mouse/psmouse-base.c. Note, if you happen to + * press/release the 4th or 5th buttons at the same moment as a + * horizontal wheel scroll, those button presses will get lost. I'm not + * sure what to do about that, since by this point we don't know + * whether those buttons actually changed state. + */ + if (dw1 != 0) { + if (dw1 > 31) { + dw1 = 31; + } else if (dw1 < -31) { + dw1 = -31; + } + + /* + * linux kernel expects first 6 bits to represent the value + * for horizontal scroll + */ + b = (dw1 & 0x3f) | 0x40; + s->mouse_dw -= dw1; + } else { + if (dz1 > 7) { + dz1 = 7; + } else if (dz1 < -7) { + dz1 = -7; + } + + b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); + s->mouse_dz -= dz1; + } ps2_queue_noirq(&s->common, b); break; } @@ -764,7 +797,6 @@ static int ps2_mouse_send_packet(PS2MouseState *s) /* update deltas */ s->mouse_dx -= dx1; s->mouse_dy -= dy1; - s->mouse_dz -= dz1; return 1; } @@ -806,6 +838,12 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { s->mouse_dz++; } + + if (btn->button == INPUT_BUTTON_WHEEL_RIGHT) { + s->mouse_dw--; + } else if (btn->button == INPUT_BUTTON_WHEEL_LEFT) { + s->mouse_dw++; + } } else { s->mouse_buttons &= ~bmap[btn->button]; } @@ -833,8 +871,10 @@ static void ps2_mouse_sync(DeviceState *dev) /* if not remote, send event. Multiple events are sent if too big deltas */ while (ps2_mouse_send_packet(s)) { - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) + if (s->mouse_dx == 0 && s->mouse_dy == 0 + && s->mouse_dz == 0 && s->mouse_dw == 0) { break; + } } } } @@ -1036,6 +1076,7 @@ static void ps2_mouse_reset(void *opaque) s->mouse_dx = 0; s->mouse_dy = 0; s->mouse_dz = 0; + s->mouse_dw = 0; s->mouse_buttons = 0; } diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index b4c5549ce8..725525358d 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -16,7 +16,7 @@ config JAZZ select I8254 select I8257 select PCSPK - select VGA_ISA_MM + select VGA_MMIO select G364FB select DP8393X select ESP diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index f5a26e174d..44f0d48bfd 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -43,6 +43,7 @@ #include "hw/rtc/mc146818rtc.h" #include "hw/timer/i8254.h" #include "hw/display/vga.h" +#include "hw/display/bochs-vbe.h" #include "hw/audio/pcspk.h" #include "hw/input/i8042.h" #include "hw/sysbus.h" @@ -274,7 +275,13 @@ static void mips_jazz_init(MachineState *machine, } break; case JAZZ_PICA61: - isa_vga_mm_init(0x40000000, 0x60000000, 0, get_system_memory()); + dev = qdev_new(TYPE_VGA_MMIO); + qdev_prop_set_uint8(dev, "it_shift", 0); + sysbus = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sysbus, &error_fatal); + sysbus_mmio_map(sysbus, 0, 0x60000000); + sysbus_mmio_map(sysbus, 1, 0x400a0000); + sysbus_mmio_map(sysbus, 2, VBE_DISPI_LFB_PHYSICAL_ADDRESS); break; default: break; diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 18eb824c97..29575cbaf6 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -49,51 +49,6 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp) } } -static bool virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev, - VirtQueue *vq) -{ - bool progress = false; - VirtIOSCSI *s = VIRTIO_SCSI(vdev); - - virtio_scsi_acquire(s); - if (!s->dataplane_fenced) { - assert(s->ctx && s->dataplane_started); - progress = virtio_scsi_handle_cmd_vq(s, vq); - } - virtio_scsi_release(s); - return progress; -} - -static bool virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev, - VirtQueue *vq) -{ - bool progress = false; - VirtIOSCSI *s = VIRTIO_SCSI(vdev); - - virtio_scsi_acquire(s); - if (!s->dataplane_fenced) { - assert(s->ctx && s->dataplane_started); - progress = virtio_scsi_handle_ctrl_vq(s, vq); - } - virtio_scsi_release(s); - return progress; -} - -static bool virtio_scsi_data_plane_handle_event(VirtIODevice *vdev, - VirtQueue *vq) -{ - bool progress = false; - VirtIOSCSI *s = VIRTIO_SCSI(vdev); - - virtio_scsi_acquire(s); - if (!s->dataplane_fenced) { - assert(s->ctx && s->dataplane_started); - progress = virtio_scsi_handle_event_vq(s, vq); - } - virtio_scsi_release(s); - return progress; -} - static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); @@ -118,10 +73,10 @@ static void virtio_scsi_dataplane_stop_bh(void *opaque) VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); int i; - virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, NULL); - virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, NULL); + virtio_queue_aio_detach_host_notifier(vs->ctrl_vq, s->ctx); + virtio_queue_aio_detach_host_notifier(vs->event_vq, s->ctx); for (i = 0; i < vs->conf.num_queues; i++) { - virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, NULL); + virtio_queue_aio_detach_host_notifier(vs->cmd_vqs[i], s->ctx); } } @@ -182,14 +137,11 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev) memory_region_transaction_commit(); aio_context_acquire(s->ctx); - virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, - virtio_scsi_data_plane_handle_ctrl); - virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, - virtio_scsi_data_plane_handle_event); + virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx); + virtio_queue_aio_attach_host_notifier(vs->event_vq, s->ctx); for (i = 0; i < vs->conf.num_queues; i++) { - virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, - virtio_scsi_data_plane_handle_cmd); + virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx); } s->dataplane_starting = false; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 51fd09522a..34a968ecfb 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -720,7 +720,7 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) /* use non-QOM casts in the data path */ VirtIOSCSI *s = (VirtIOSCSI *)vdev; - if (s->ctx) { + if (s->ctx && !s->dataplane_started) { virtio_device_start_ioeventfd(vdev); if (!s->dataplane_fenced) { return; diff --git a/hw/usb/desc.c b/hw/usb/desc.c index 8b6eaea407..7f6cc2f99b 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -632,7 +632,8 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE)); const USBDesc *desc = usb_device_get_usb_desc(dev); const USBDescDevice *other_dev; - uint8_t buf[256]; + size_t buflen = USB_DESC_MAX_LEN; + g_autofree uint8_t *buf = g_malloc(buflen); uint8_t type = value >> 8; uint8_t index = value & 0xff; int flags, ret = -1; @@ -650,36 +651,36 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, switch(type) { case USB_DT_DEVICE: - ret = usb_desc_device(&desc->id, dev->device, msos, buf, sizeof(buf)); + ret = usb_desc_device(&desc->id, dev->device, msos, buf, buflen); trace_usb_desc_device(dev->addr, len, ret); break; case USB_DT_CONFIG: if (index < dev->device->bNumConfigurations) { ret = usb_desc_config(dev->device->confs + index, flags, - buf, sizeof(buf)); + buf, buflen); } trace_usb_desc_config(dev->addr, index, len, ret); break; case USB_DT_STRING: - ret = usb_desc_string(dev, index, buf, sizeof(buf)); + ret = usb_desc_string(dev, index, buf, buflen); trace_usb_desc_string(dev->addr, index, len, ret); break; case USB_DT_DEVICE_QUALIFIER: if (other_dev != NULL) { - ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); + ret = usb_desc_device_qualifier(other_dev, buf, buflen); } trace_usb_desc_device_qualifier(dev->addr, len, ret); break; case USB_DT_OTHER_SPEED_CONFIG: if (other_dev != NULL && index < other_dev->bNumConfigurations) { ret = usb_desc_config(other_dev->confs + index, flags, - buf, sizeof(buf)); + buf, buflen); buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; } trace_usb_desc_other_speed_config(dev->addr, index, len, ret); break; case USB_DT_BOS: - ret = usb_desc_bos(desc, buf, sizeof(buf)); + ret = usb_desc_bos(desc, buf, buflen); trace_usb_desc_bos(dev->addr, len, ret); break; diff --git a/hw/usb/desc.h b/hw/usb/desc.h index 3ac604ecfa..35babdeff6 100644 --- a/hw/usb/desc.h +++ b/hw/usb/desc.h @@ -199,6 +199,7 @@ struct USBDesc { const USBDescMSOS *msos; }; +#define USB_DESC_MAX_LEN 8192 #define USB_DESC_FLAG_SUPER (1 << 1) /* little helpers */ diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 599d6b52a0..c9f295e7e4 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -908,6 +908,7 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) p->status = USB_RET_STALL; break; } + return; err_stream: error_report("%s: invalid stream %d", __func__, p->stream); diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index ed687bc9f1..8323650c6a 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -69,6 +69,65 @@ static const USBDescStrings desc_strings = { [STR_SERIALNUMBER] = "1", }; +static const uint8_t qemu_wacom_hid_report_descriptor[] = { + 0x05, 0x01, /* Usage Page (Desktop) */ + 0x09, 0x02, /* Usage (Mouse) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x85, 0x01, /* Report ID (1) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x05, 0x09, /* Usage Page (Button) */ + 0x19, 0x01, /* Usage Minimum (01h) */ + 0x29, 0x03, /* Usage Maximum (03h) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x95, 0x03, /* Report Count (3) */ + 0x75, 0x01, /* Report Size (1) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x05, /* Report Size (5) */ + 0x81, 0x01, /* Input (Constant) */ + 0x05, 0x01, /* Usage Page (Desktop) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x09, 0x38, /* Usage (Wheel) */ + 0x15, 0x81, /* Logical Minimum (-127) */ + 0x25, 0x7f, /* Logical Maximum (127) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x03, /* Report Count (3) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0x95, 0x03, /* Report Count (3) */ + 0x81, 0x01, /* Input (Constant) */ + 0xc0, /* End Collection */ + 0xc0, /* End Collection */ + 0x05, 0x0d, /* Usage Page (Digitizer) */ + 0x09, 0x01, /* Usage (Digitizer) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x85, 0x02, /* Report ID (2) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x06, 0x00, 0xff,/* Usage Page (ff00h), vendor-defined */ + 0x09, 0x01, /* Usage (01h) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x26, 0xff, 0x00,/* Logical Maximum (255) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x07, /* Report Count (7) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0xc0, /* End Collection */ + 0x09, 0x01, /* Usage (01h) */ + 0x85, 0x63, /* Report ID (99) */ + 0x95, 0x07, /* Report Count (7) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x09, 0x01, /* Usage (01h) */ + 0x85, 0x02, /* Report ID (2) */ + 0x95, 0x01, /* Report Count (1) */ + 0xb1, 0x02, /* Feature (Variable) */ + 0x09, 0x01, /* Usage (01h) */ + 0x85, 0x03, /* Report ID (3) */ + 0x95, 0x01, /* Report Count (1) */ + 0xb1, 0x02, /* Feature (Variable) */ + 0xc0 /* End Collection */ +}; + static const USBDescIface desc_iface_wacom = { .bInterfaceNumber = 0, .bNumEndpoints = 1, @@ -86,7 +145,7 @@ static const USBDescIface desc_iface_wacom = { 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ USB_DT_REPORT, /* u8 type: Report */ - 0x6e, 0, /* u16 len */ + sizeof(qemu_wacom_hid_report_descriptor), 0, /* u16 len */ }, }, }, @@ -266,6 +325,17 @@ static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p, } switch (request) { + case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: + switch (value >> 8) { + case 0x22: + memcpy(data, qemu_wacom_hid_report_descriptor, + sizeof(qemu_wacom_hid_report_descriptor)); + p->actual_length = sizeof(qemu_wacom_hid_report_descriptor); + break; + default: + return; + } + break; case WACOM_SET_REPORT: if (s->mouse_grabbed) { qemu_remove_mouse_event_handler(s->eh_entry); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 5d18868d7d..aae72fb8b7 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -125,7 +125,6 @@ struct VirtQueue uint16_t vector; VirtIOHandleOutput handle_output; - VirtIOHandleAIOOutput handle_aio_output; VirtIODevice *vdev; EventNotifier guest_notifier; EventNotifier host_notifier; @@ -2303,24 +2302,6 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align) } } -static bool virtio_queue_notify_aio_vq(VirtQueue *vq) -{ - bool ret = false; - - if (vq->vring.desc && vq->handle_aio_output) { - VirtIODevice *vdev = vq->vdev; - - trace_virtio_queue_notify(vdev, vq - vdev->vq, vq); - ret = vq->handle_aio_output(vdev, vq); - - if (unlikely(vdev->start_on_kick)) { - virtio_set_started(vdev, true); - } - } - - return ret; -} - static void virtio_queue_notify_vq(VirtQueue *vq) { if (vq->vring.desc && vq->handle_output) { @@ -2399,7 +2380,6 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, vdev->vq[i].vring.num_default = queue_size; vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN; vdev->vq[i].handle_output = handle_output; - vdev->vq[i].handle_aio_output = NULL; vdev->vq[i].used_elems = g_malloc0(sizeof(VirtQueueElement) * queue_size); @@ -2411,7 +2391,6 @@ void virtio_delete_queue(VirtQueue *vq) vq->vring.num = 0; vq->vring.num_default = 0; vq->handle_output = NULL; - vq->handle_aio_output = NULL; g_free(vq->used_elems); vq->used_elems = NULL; virtio_virtqueue_reset_region_cache(vq); @@ -3516,14 +3495,6 @@ EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq) return &vq->guest_notifier; } -static void virtio_queue_host_notifier_aio_read(EventNotifier *n) -{ - VirtQueue *vq = container_of(n, VirtQueue, host_notifier); - if (event_notifier_test_and_clear(n)) { - virtio_queue_notify_aio_vq(vq); - } -} - static void virtio_queue_host_notifier_aio_poll_begin(EventNotifier *n) { VirtQueue *vq = container_of(n, VirtQueue, host_notifier); @@ -3536,11 +3507,14 @@ static bool virtio_queue_host_notifier_aio_poll(void *opaque) EventNotifier *n = opaque; VirtQueue *vq = container_of(n, VirtQueue, host_notifier); - if (!vq->vring.desc || virtio_queue_empty(vq)) { - return false; - } + return vq->vring.desc && !virtio_queue_empty(vq); +} + +static void virtio_queue_host_notifier_aio_poll_ready(EventNotifier *n) +{ + VirtQueue *vq = container_of(n, VirtQueue, host_notifier); - return virtio_queue_notify_aio_vq(vq); + virtio_queue_notify_vq(vq); } static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n) @@ -3551,24 +3525,23 @@ static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n) virtio_queue_set_notification(vq, 1); } -void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, - VirtIOHandleAIOOutput handle_output) +void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx) { - if (handle_output) { - vq->handle_aio_output = handle_output; - aio_set_event_notifier(ctx, &vq->host_notifier, true, - virtio_queue_host_notifier_aio_read, - virtio_queue_host_notifier_aio_poll); - aio_set_event_notifier_poll(ctx, &vq->host_notifier, - virtio_queue_host_notifier_aio_poll_begin, - virtio_queue_host_notifier_aio_poll_end); - } else { - aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL); - /* Test and clear notifier before after disabling event, - * in case poll callback didn't have time to run. */ - virtio_queue_host_notifier_aio_read(&vq->host_notifier); - vq->handle_aio_output = NULL; - } + aio_set_event_notifier(ctx, &vq->host_notifier, true, + virtio_queue_host_notifier_read, + virtio_queue_host_notifier_aio_poll, + virtio_queue_host_notifier_aio_poll_ready); + aio_set_event_notifier_poll(ctx, &vq->host_notifier, + virtio_queue_host_notifier_aio_poll_begin, + virtio_queue_host_notifier_aio_poll_end); +} + +void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx) +{ + aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL); + /* Test and clear notifier before after disabling event, + * in case poll callback didn't have time to run. */ + virtio_queue_host_notifier_read(&vq->host_notifier); } void virtio_queue_host_notifier_read(EventNotifier *n) diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index 416583f130..645a29a5a0 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -1115,11 +1115,11 @@ void xen_device_set_event_channel_context(XenDevice *xendev, if (channel->ctx) aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); channel->ctx = ctx; aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, - xen_device_event, NULL, xen_device_poll, channel); + xen_device_event, NULL, xen_device_poll, NULL, channel); } XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev, @@ -1193,7 +1193,7 @@ void xen_device_unbind_event_channel(XenDevice *xendev, QLIST_REMOVE(channel, list); aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); if (xenevtchn_unbind(channel->xeh, channel->local_port) < 0) { error_setg_errno(errp, errno, "xenevtchn_unbind failed"); diff --git a/include/block/aio.h b/include/block/aio.h index 47fbe9d81f..5634173b12 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -469,6 +469,7 @@ void aio_set_fd_handler(AioContext *ctx, IOHandler *io_read, IOHandler *io_write, AioPollFn *io_poll, + IOHandler *io_poll_ready, void *opaque); /* Set polling begin/end callbacks for a file descriptor that has already been @@ -490,7 +491,8 @@ void aio_set_event_notifier(AioContext *ctx, EventNotifier *notifier, bool is_external, EventNotifierHandler *io_read, - AioPollFn *io_poll); + AioPollFn *io_poll, + EventNotifierHandler *io_poll_ready); /* Set polling begin/end callbacks for an event notifier that has already been * registered with aio_set_event_notifier. Do nothing if the event notifier is diff --git a/include/hw/display/vga.h b/include/hw/display/vga.h index 5f7825e0e3..a79aa2909b 100644 --- a/include/hw/display/vga.h +++ b/include/hw/display/vga.h @@ -9,8 +9,6 @@ #ifndef QEMU_HW_DISPLAY_VGA_H #define QEMU_HW_DISPLAY_VGA_H -#include "exec/hwaddr.h" - /* * modules can reference this symbol to avoid being loaded * into system emulators without vga support @@ -24,8 +22,6 @@ enum vga_retrace_method { extern enum vga_retrace_method vga_retrace_method; -int isa_vga_mm_init(hwaddr vram_base, - hwaddr ctrl_base, int it_shift, - MemoryRegion *address_space); +#define TYPE_VGA_MMIO "vga-mmio" #endif diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 29655a406d..d311c57cca 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -90,7 +90,7 @@ typedef struct MultiReqBuffer { bool is_write; } MultiReqBuffer; -bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); +void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh); #endif diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index acfba7c76c..2179b75703 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -147,8 +147,8 @@ struct VirtIOGPUBaseClass { DEFINE_PROP_UINT32("max_outputs", _state, _conf.max_outputs, 1), \ DEFINE_PROP_BIT("edid", _state, _conf.flags, \ VIRTIO_GPU_FLAG_EDID_ENABLED, true), \ - DEFINE_PROP_UINT32("xres", _state, _conf.xres, 1024), \ - DEFINE_PROP_UINT32("yres", _state, _conf.yres, 768) + DEFINE_PROP_UINT32("xres", _state, _conf.xres, 1280), \ + DEFINE_PROP_UINT32("yres", _state, _conf.yres, 800) typedef struct VGPUDMABuf { QemuDmaBuf buf; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 8bab9cfb75..f095637058 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -175,7 +175,6 @@ void virtio_error(VirtIODevice *vdev, const char *fmt, ...) GCC_FMT_ATTR(2, 3); void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name); typedef void (*VirtIOHandleOutput)(VirtIODevice *, VirtQueue *); -typedef bool (*VirtIOHandleAIOOutput)(VirtIODevice *, VirtQueue *); VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, VirtIOHandleOutput handle_output); @@ -317,8 +316,8 @@ bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev); EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled); void virtio_queue_host_notifier_read(EventNotifier *n); -void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, - VirtIOHandleAIOOutput handle_output); +void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx); +void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx); VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector); VirtQueue *virtio_vector_next_queue(VirtQueue *vq); diff --git a/io/channel-command.c b/io/channel-command.c index b2a9e27138..338da73ade 100644 --- a/io/channel-command.c +++ b/io/channel-command.c @@ -346,8 +346,10 @@ static void qio_channel_command_set_aio_fd_handler(QIOChannel *ioc, void *opaque) { QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); - aio_set_fd_handler(ctx, cioc->readfd, false, io_read, NULL, NULL, opaque); - aio_set_fd_handler(ctx, cioc->writefd, false, NULL, io_write, NULL, opaque); + aio_set_fd_handler(ctx, cioc->readfd, false, + io_read, NULL, NULL, NULL, opaque); + aio_set_fd_handler(ctx, cioc->writefd, false, + NULL, io_write, NULL, NULL, opaque); } diff --git a/io/channel-file.c b/io/channel-file.c index c4bf799a80..d7cf6d278f 100644 --- a/io/channel-file.c +++ b/io/channel-file.c @@ -191,7 +191,8 @@ static void qio_channel_file_set_aio_fd_handler(QIOChannel *ioc, void *opaque) { QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc); - aio_set_fd_handler(ctx, fioc->fd, false, io_read, io_write, NULL, opaque); + aio_set_fd_handler(ctx, fioc->fd, false, io_read, io_write, + NULL, NULL, opaque); } static GSource *qio_channel_file_create_watch(QIOChannel *ioc, diff --git a/io/channel-socket.c b/io/channel-socket.c index 606ec97cf7..459922c874 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -761,7 +761,8 @@ static void qio_channel_socket_set_aio_fd_handler(QIOChannel *ioc, void *opaque) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); - aio_set_fd_handler(ctx, sioc->fd, false, io_read, io_write, NULL, opaque); + aio_set_fd_handler(ctx, sioc->fd, false, + io_read, io_write, NULL, NULL, opaque); } static GSource *qio_channel_socket_create_watch(QIOChannel *ioc, diff --git a/migration/rdma.c b/migration/rdma.c index f5d3bbe7e9..c7c7a38487 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3161,14 +3161,14 @@ static void qio_channel_rdma_set_aio_fd_handler(QIOChannel *ioc, QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc); if (io_read) { aio_set_fd_handler(ctx, rioc->rdmain->recv_comp_channel->fd, - false, io_read, io_write, NULL, opaque); + false, io_read, io_write, NULL, NULL, opaque); aio_set_fd_handler(ctx, rioc->rdmain->send_comp_channel->fd, - false, io_read, io_write, NULL, opaque); + false, io_read, io_write, NULL, NULL, opaque); } else { aio_set_fd_handler(ctx, rioc->rdmaout->recv_comp_channel->fd, - false, io_read, io_write, NULL, opaque); + false, io_read, io_write, NULL, NULL, opaque); aio_set_fd_handler(ctx, rioc->rdmaout->send_comp_channel->fd, - false, io_read, io_write, NULL, opaque); + false, io_read, io_write, NULL, NULL, opaque); } } diff --git a/qapi/ui.json b/qapi/ui.json index 2b4371da37..9354f4c467 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -905,7 +905,7 @@ ## { 'enum' : 'InputButton', 'data' : [ 'left', 'middle', 'right', 'wheel-up', 'wheel-down', 'side', - 'extra' ] } + 'extra', 'wheel-left', 'wheel-right' ] } ## # @InputAxis: diff --git a/qemu-edid.c b/qemu-edid.c index c3a9fba10d..20c958d9c7 100644 --- a/qemu-edid.c +++ b/qemu-edid.c @@ -10,8 +10,8 @@ #include "hw/display/edid.h" static qemu_edid_info info = { - .prefx = 1024, - .prefy = 768, + .prefx = 1280, + .prefy = 800, }; static void usage(FILE *out) diff --git a/tests/unit/test-aio.c b/tests/unit/test-aio.c index 6feeb9a4a9..178048d2f2 100644 --- a/tests/unit/test-aio.c +++ b/tests/unit/test-aio.c @@ -130,7 +130,7 @@ static void *test_acquire_thread(void *opaque) static void set_event_notifier(AioContext *ctx, EventNotifier *notifier, EventNotifierHandler *handler) { - aio_set_event_notifier(ctx, notifier, false, handler, NULL); + aio_set_event_notifier(ctx, notifier, false, handler, NULL, NULL); } static void dummy_notifier_read(EventNotifier *n) @@ -390,7 +390,7 @@ static void test_aio_external_client(void) for (i = 1; i < 3; i++) { EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, true, event_ready_cb, NULL); + aio_set_event_notifier(ctx, &data.e, true, event_ready_cb, NULL, NULL); event_notifier_set(&data.e); for (j = 0; j < i; j++) { aio_disable_external(ctx); diff --git a/tests/unit/test-fdmon-epoll.c b/tests/unit/test-fdmon-epoll.c index 11fd8a2fa9..ef5a856d09 100644 --- a/tests/unit/test-fdmon-epoll.c +++ b/tests/unit/test-fdmon-epoll.c @@ -22,14 +22,14 @@ static void add_event_notifiers(EventNotifier *notifiers, size_t n) for (size_t i = 0; i < n; i++) { event_notifier_init(¬ifiers[i], false); aio_set_event_notifier(ctx, ¬ifiers[i], false, - dummy_fd_handler, NULL); + dummy_fd_handler, NULL, NULL); } } static void remove_event_notifiers(EventNotifier *notifiers, size_t n) { for (size_t i = 0; i < n; i++) { - aio_set_event_notifier(ctx, ¬ifiers[i], false, NULL, NULL); + aio_set_event_notifier(ctx, ¬ifiers[i], false, NULL, NULL, NULL); event_notifier_cleanup(¬ifiers[i]); } } diff --git a/ui/cocoa.m b/ui/cocoa.m index 69745c483b..ac18e14ce0 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -970,21 +970,27 @@ QemuCocoaView *cocoaView; */ /* - * When deltaY is zero, it means that this scrolling event was - * either horizontal, or so fine that it only appears in - * scrollingDeltaY. So we drop the event. + * We shouldn't have got a scroll event when deltaY and delta Y + * are zero, hence no harm in dropping the event */ - if ([event deltaY] != 0) { + if ([event deltaY] != 0 || [event deltaX] != 0) { /* Determine if this is a scroll up or scroll down event */ - buttons = ([event deltaY] > 0) ? + if ([event deltaY] != 0) { + buttons = ([event deltaY] > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN; + } else if ([event deltaX] != 0) { + buttons = ([event deltaX] > 0) ? + INPUT_BUTTON_WHEEL_LEFT : INPUT_BUTTON_WHEEL_RIGHT; + } + qemu_input_queue_btn(dcl.con, buttons, true); qemu_input_event_sync(); qemu_input_queue_btn(dcl.con, buttons, false); qemu_input_event_sync(); } + /* - * Since deltaY also reports scroll wheel events we prevent mouse + * Since deltaX/deltaY also report scroll wheel events we prevent mouse * movement code from executing. */ mouse_event = false; @@ -405,6 +405,7 @@ dbus_vc_class_init(ObjectClass *oc, void *data) static const TypeInfo dbus_vc_type_info = { .name = TYPE_CHARDEV_VC, .parent = TYPE_CHARDEV_DBUS, + .class_size = sizeof(DBusVCClass), .class_init = dbus_vc_class_init, }; diff --git a/ui/gtk-clipboard.c b/ui/gtk-clipboard.c index e0b8b283fe..d58fd761ab 100644 --- a/ui/gtk-clipboard.c +++ b/ui/gtk-clipboard.c @@ -83,7 +83,7 @@ static void gd_clipboard_update_info(GtkDisplayState *gd, if (info != qemu_clipboard_info(s)) { gd->cbpending[s] = 0; if (!self_update) { - GtkTargetList *list; + g_autoptr(GtkTargetList) list = NULL; GtkTargetEntry *targets; gint n_targets; @@ -94,15 +94,16 @@ static void gd_clipboard_update_info(GtkDisplayState *gd, targets = gtk_target_table_new_from_list(list, &n_targets); gtk_clipboard_clear(gd->gtkcb[s]); - gd->cbowner[s] = true; - gtk_clipboard_set_with_data(gd->gtkcb[s], - targets, n_targets, - gd_clipboard_get_data, - gd_clipboard_clear, - gd); - - gtk_target_table_free(targets, n_targets); - gtk_target_list_unref(list); + if (targets) { + gd->cbowner[s] = true; + gtk_clipboard_set_with_data(gd->gtkcb[s], + targets, n_targets, + gd_clipboard_get_data, + gd_clipboard_clear, + gd); + + gtk_target_table_free(targets, n_targets); + } } return; } @@ -968,33 +968,63 @@ static gboolean gd_scroll_event(GtkWidget *widget, GdkEventScroll *scroll, void *opaque) { VirtualConsole *vc = opaque; - InputButton btn; + InputButton btn_vertical; + InputButton btn_horizontal; + bool has_vertical = false; + bool has_horizontal = false; if (scroll->direction == GDK_SCROLL_UP) { - btn = INPUT_BUTTON_WHEEL_UP; + btn_vertical = INPUT_BUTTON_WHEEL_UP; + has_vertical = true; } else if (scroll->direction == GDK_SCROLL_DOWN) { - btn = INPUT_BUTTON_WHEEL_DOWN; + btn_vertical = INPUT_BUTTON_WHEEL_DOWN; + has_vertical = true; + } else if (scroll->direction == GDK_SCROLL_LEFT) { + btn_horizontal = INPUT_BUTTON_WHEEL_LEFT; + has_horizontal = true; + } else if (scroll->direction == GDK_SCROLL_RIGHT) { + btn_horizontal = INPUT_BUTTON_WHEEL_RIGHT; + has_horizontal = true; } else if (scroll->direction == GDK_SCROLL_SMOOTH) { gdouble delta_x, delta_y; if (!gdk_event_get_scroll_deltas((GdkEvent *)scroll, &delta_x, &delta_y)) { return TRUE; } - if (delta_y == 0) { - return TRUE; - } else if (delta_y > 0) { - btn = INPUT_BUTTON_WHEEL_DOWN; + + if (delta_y > 0) { + btn_vertical = INPUT_BUTTON_WHEEL_DOWN; + has_vertical = true; + } else if (delta_y < 0) { + btn_vertical = INPUT_BUTTON_WHEEL_UP; + has_vertical = true; + } else if (delta_x > 0) { + btn_horizontal = INPUT_BUTTON_WHEEL_RIGHT; + has_horizontal = true; + } else if (delta_x < 0) { + btn_horizontal = INPUT_BUTTON_WHEEL_LEFT; + has_horizontal = true; } else { - btn = INPUT_BUTTON_WHEEL_UP; + return TRUE; } } else { return TRUE; } - qemu_input_queue_btn(vc->gfx.dcl.con, btn, true); - qemu_input_event_sync(); - qemu_input_queue_btn(vc->gfx.dcl.con, btn, false); - qemu_input_event_sync(); + if (has_vertical) { + qemu_input_queue_btn(vc->gfx.dcl.con, btn_vertical, true); + qemu_input_event_sync(); + qemu_input_queue_btn(vc->gfx.dcl.con, btn_vertical, false); + qemu_input_event_sync(); + } + + if (has_horizontal) { + qemu_input_queue_btn(vc->gfx.dcl.con, btn_horizontal, true); + qemu_input_event_sync(); + qemu_input_queue_btn(vc->gfx.dcl.con, btn_horizontal, false); + qemu_input_event_sync(); + } + return TRUE; } diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 9fc78a639b..46ea74e44d 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qapi/qapi-commands-ui.h" #include "ui/console.h" #include "keymaps.h" @@ -179,6 +180,20 @@ static void legacy_mouse_event(DeviceState *dev, QemuConsole *src, 1, s->buttons); } + if (btn->down && btn->button == INPUT_BUTTON_WHEEL_RIGHT) { + s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, + s->axis[INPUT_AXIS_X], + s->axis[INPUT_AXIS_Y], + -2, + s->buttons); + } + if (btn->down && btn->button == INPUT_BUTTON_WHEEL_LEFT) { + s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, + s->axis[INPUT_AXIS_X], + s->axis[INPUT_AXIS_Y], + 2, + s->buttons); + } break; case INPUT_EVENT_KIND_ABS: move = evt->u.abs.data; @@ -33,6 +33,7 @@ #include "sysemu/runstate-action.h" #include "sysemu/sysemu.h" #include "ui/win32-kbd-hook.h" +#include "qemu/log.h" static int sdl2_num_outputs; static struct sdl2_console *sdl2_console; @@ -535,6 +536,10 @@ static void handle_mousewheel(SDL_Event *ev) btn = INPUT_BUTTON_WHEEL_UP; } else if (wev->y < 0) { btn = INPUT_BUTTON_WHEEL_DOWN; + } else if (wev->x < 0) { + btn = INPUT_BUTTON_WHEEL_RIGHT; + } else if (wev->x > 0) { + btn = INPUT_BUTTON_WHEEL_LEFT; } else { return; } @@ -1354,12 +1354,12 @@ void vnc_disconnect_finish(VncState *vs) /* last client gone */ vnc_update_server_surface(vs->vd); } + vnc_unlock_output(vs); + if (vs->cbpeer.notifier.notify) { qemu_clipboard_peer_unregister(&vs->cbpeer); } - vnc_unlock_output(vs); - qemu_mutex_destroy(&vs->output_mutex); if (vs->bh != NULL) { qemu_bh_delete(vs->bh); diff --git a/util/aio-posix.c b/util/aio-posix.c index 2b86777e91..7b9f629218 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -23,6 +23,15 @@ #include "trace.h" #include "aio-posix.h" +/* + * G_IO_IN and G_IO_OUT are not appropriate revents values for polling, since + * the handler may not need to access the file descriptor. For example, the + * handler doesn't need to read from an EventNotifier if it polled a memory + * location and a read syscall would be slow. Define our own unique revents + * value to indicate that polling determined this AioHandler is ready. + */ +#define REVENTS_POLL_READY 0 + /* Stop userspace polling on a handler if it isn't active for some time */ #define POLL_IDLE_INTERVAL_NS (7 * NANOSECONDS_PER_SECOND) @@ -93,6 +102,7 @@ void aio_set_fd_handler(AioContext *ctx, IOHandler *io_read, IOHandler *io_write, AioPollFn *io_poll, + IOHandler *io_poll_ready, void *opaque) { AioHandler *node; @@ -101,6 +111,10 @@ void aio_set_fd_handler(AioContext *ctx, bool deleted = false; int poll_disable_change; + if (io_poll && !io_poll_ready) { + io_poll = NULL; /* polling only makes sense if there is a handler */ + } + qemu_lockcnt_lock(&ctx->list_lock); node = find_aio_handler(ctx, fd); @@ -127,6 +141,7 @@ void aio_set_fd_handler(AioContext *ctx, new_node->io_read = io_read; new_node->io_write = io_write; new_node->io_poll = io_poll; + new_node->io_poll_ready = io_poll_ready; new_node->opaque = opaque; new_node->is_external = is_external; @@ -182,10 +197,12 @@ void aio_set_event_notifier(AioContext *ctx, EventNotifier *notifier, bool is_external, EventNotifierHandler *io_read, - AioPollFn *io_poll) + AioPollFn *io_poll, + EventNotifierHandler *io_poll_ready) { aio_set_fd_handler(ctx, event_notifier_get_fd(notifier), is_external, - (IOHandler *)io_read, NULL, io_poll, notifier); + (IOHandler *)io_read, NULL, io_poll, + (IOHandler *)io_poll_ready, notifier); } void aio_set_event_notifier_poll(AioContext *ctx, @@ -198,7 +215,8 @@ void aio_set_event_notifier_poll(AioContext *ctx, (IOHandler *)io_poll_end); } -static bool poll_set_started(AioContext *ctx, bool started) +static bool poll_set_started(AioContext *ctx, AioHandlerList *ready_list, + bool started) { AioHandler *node; bool progress = false; @@ -228,8 +246,9 @@ static bool poll_set_started(AioContext *ctx, bool started) } /* Poll one last time in case ->io_poll_end() raced with the event */ - if (!started) { - progress = node->io_poll(node->opaque) || progress; + if (!started && node->io_poll(node->opaque)) { + aio_add_ready_handler(ready_list, node, REVENTS_POLL_READY); + progress = true; } } qemu_lockcnt_dec(&ctx->list_lock); @@ -240,8 +259,11 @@ static bool poll_set_started(AioContext *ctx, bool started) bool aio_prepare(AioContext *ctx) { + AioHandlerList ready_list = QLIST_HEAD_INITIALIZER(ready_list); + /* Poll mode cannot be used with glib's event loop, disable it. */ - poll_set_started(ctx, false); + poll_set_started(ctx, &ready_list, false); + /* TODO what to do with this list? */ return false; } @@ -321,6 +343,18 @@ static bool aio_dispatch_handler(AioContext *ctx, AioHandler *node) } QLIST_INSERT_HEAD(&ctx->poll_aio_handlers, node, node_poll); } + if (!QLIST_IS_INSERTED(node, node_deleted) && + revents == 0 && + aio_node_check(ctx, node->is_external) && + node->io_poll_ready) { + node->io_poll_ready(node->opaque); + + /* + * Return early since revents was zero. aio_notify() does not count as + * progress. + */ + return node->opaque != &ctx->notifier; + } if (!QLIST_IS_INSERTED(node, node_deleted) && (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) && @@ -387,6 +421,7 @@ void aio_dispatch(AioContext *ctx) } static bool run_poll_handlers_once(AioContext *ctx, + AioHandlerList *ready_list, int64_t now, int64_t *timeout) { @@ -397,6 +432,8 @@ static bool run_poll_handlers_once(AioContext *ctx, QLIST_FOREACH_SAFE(node, &ctx->poll_aio_handlers, node_poll, tmp) { if (aio_node_check(ctx, node->is_external) && node->io_poll(node->opaque)) { + aio_add_ready_handler(ready_list, node, REVENTS_POLL_READY); + node->poll_idle_timeout = now + POLL_IDLE_INTERVAL_NS; /* @@ -420,7 +457,9 @@ static bool fdmon_supports_polling(AioContext *ctx) return ctx->fdmon_ops->need_wait != aio_poll_disabled; } -static bool remove_idle_poll_handlers(AioContext *ctx, int64_t now) +static bool remove_idle_poll_handlers(AioContext *ctx, + AioHandlerList *ready_list, + int64_t now) { AioHandler *node; AioHandler *tmp; @@ -451,7 +490,11 @@ static bool remove_idle_poll_handlers(AioContext *ctx, int64_t now) * Nevermind about re-adding the handler in the rare case where * this causes progress. */ - progress = node->io_poll(node->opaque) || progress; + if (node->io_poll(node->opaque)) { + aio_add_ready_handler(ready_list, node, + REVENTS_POLL_READY); + progress = true; + } } } } @@ -461,6 +504,7 @@ static bool remove_idle_poll_handlers(AioContext *ctx, int64_t now) /* run_poll_handlers: * @ctx: the AioContext + * @ready_list: the list to place ready handlers on * @max_ns: maximum time to poll for, in nanoseconds * * Polls for a given time. @@ -469,7 +513,8 @@ static bool remove_idle_poll_handlers(AioContext *ctx, int64_t now) * * Returns: true if progress was made, false otherwise */ -static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout) +static bool run_poll_handlers(AioContext *ctx, AioHandlerList *ready_list, + int64_t max_ns, int64_t *timeout) { bool progress; int64_t start_time, elapsed_time; @@ -490,13 +535,15 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout) start_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); do { - progress = run_poll_handlers_once(ctx, start_time, timeout); + progress = run_poll_handlers_once(ctx, ready_list, + start_time, timeout); elapsed_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start_time; max_ns = qemu_soonest_timeout(*timeout, max_ns); assert(!(max_ns && progress)); } while (elapsed_time < max_ns && !ctx->fdmon_ops->need_wait(ctx)); - if (remove_idle_poll_handlers(ctx, start_time + elapsed_time)) { + if (remove_idle_poll_handlers(ctx, ready_list, + start_time + elapsed_time)) { *timeout = 0; progress = true; } @@ -514,6 +561,7 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout) /* try_poll_mode: * @ctx: the AioContext + * @ready_list: list to add handlers that need to be run * @timeout: timeout for blocking wait, computed by the caller and updated if * polling succeeds. * @@ -521,7 +569,8 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout) * * Returns: true if progress was made, false otherwise */ -static bool try_poll_mode(AioContext *ctx, int64_t *timeout) +static bool try_poll_mode(AioContext *ctx, AioHandlerList *ready_list, + int64_t *timeout) { int64_t max_ns; @@ -531,14 +580,14 @@ static bool try_poll_mode(AioContext *ctx, int64_t *timeout) max_ns = qemu_soonest_timeout(*timeout, ctx->poll_ns); if (max_ns && !ctx->fdmon_ops->need_wait(ctx)) { - poll_set_started(ctx, true); + poll_set_started(ctx, ready_list, true); - if (run_poll_handlers(ctx, max_ns, timeout)) { + if (run_poll_handlers(ctx, ready_list, max_ns, timeout)) { return true; } } - if (poll_set_started(ctx, false)) { + if (poll_set_started(ctx, ready_list, false)) { *timeout = 0; return true; } @@ -549,7 +598,6 @@ static bool try_poll_mode(AioContext *ctx, int64_t *timeout) bool aio_poll(AioContext *ctx, bool blocking) { AioHandlerList ready_list = QLIST_HEAD_INITIALIZER(ready_list); - int ret = 0; bool progress; bool use_notify_me; int64_t timeout; @@ -574,7 +622,7 @@ bool aio_poll(AioContext *ctx, bool blocking) } timeout = blocking ? aio_compute_timeout(ctx) : 0; - progress = try_poll_mode(ctx, &timeout); + progress = try_poll_mode(ctx, &ready_list, &timeout); assert(!(timeout && progress)); /* @@ -604,7 +652,7 @@ bool aio_poll(AioContext *ctx, bool blocking) * system call---a single round of run_poll_handlers_once suffices. */ if (timeout || ctx->fdmon_ops->need_wait(ctx)) { - ret = ctx->fdmon_ops->wait(ctx, &ready_list, timeout); + ctx->fdmon_ops->wait(ctx, &ready_list, timeout); } if (use_notify_me) { @@ -657,10 +705,7 @@ bool aio_poll(AioContext *ctx, bool blocking) } progress |= aio_bh_poll(ctx); - - if (ret > 0) { - progress |= aio_dispatch_ready_handlers(ctx, &ready_list); - } + progress |= aio_dispatch_ready_handlers(ctx, &ready_list); aio_free_deleted_handlers(ctx); diff --git a/util/aio-posix.h b/util/aio-posix.h index c80c04506a..7f2c37a684 100644 --- a/util/aio-posix.h +++ b/util/aio-posix.h @@ -24,6 +24,7 @@ struct AioHandler { IOHandler *io_read; IOHandler *io_write; AioPollFn *io_poll; + IOHandler *io_poll_ready; IOHandler *io_poll_begin; IOHandler *io_poll_end; void *opaque; diff --git a/util/aio-win32.c b/util/aio-win32.c index d5b09a1193..7aac89df3a 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -68,6 +68,7 @@ void aio_set_fd_handler(AioContext *ctx, IOHandler *io_read, IOHandler *io_write, AioPollFn *io_poll, + IOHandler *io_poll_ready, void *opaque) { /* fd is a SOCKET in our case */ @@ -136,7 +137,8 @@ void aio_set_event_notifier(AioContext *ctx, EventNotifier *e, bool is_external, EventNotifierHandler *io_notify, - AioPollFn *io_poll) + AioPollFn *io_poll, + EventNotifierHandler *io_poll_ready) { AioHandler *node; diff --git a/util/async.c b/util/async.c index 6f6717a34b..08d25feef5 100644 --- a/util/async.c +++ b/util/async.c @@ -362,7 +362,7 @@ aio_ctx_finalize(GSource *source) g_free(bh); } - aio_set_event_notifier(ctx, &ctx->notifier, false, NULL, NULL); + aio_set_event_notifier(ctx, &ctx->notifier, false, NULL, NULL, NULL); event_notifier_cleanup(&ctx->notifier); qemu_rec_mutex_destroy(&ctx->lock); qemu_lockcnt_destroy(&ctx->list_lock); @@ -485,6 +485,11 @@ static bool aio_context_notifier_poll(void *opaque) return qatomic_read(&ctx->notified); } +static void aio_context_notifier_poll_ready(EventNotifier *e) +{ + /* Do nothing, we just wanted to kick the event loop */ +} + static void co_schedule_bh_cb(void *opaque) { AioContext *ctx = opaque; @@ -536,7 +541,8 @@ AioContext *aio_context_new(Error **errp) aio_set_event_notifier(ctx, &ctx->notifier, false, aio_context_notifier_cb, - aio_context_notifier_poll); + aio_context_notifier_poll, + aio_context_notifier_poll_ready); #ifdef CONFIG_LINUX_AIO ctx->linux_aio = NULL; #endif diff --git a/util/main-loop.c b/util/main-loop.c index 06b18b195c..4d5a5b9943 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -582,7 +582,7 @@ void qemu_set_fd_handler(int fd, { iohandler_init(); aio_set_fd_handler(iohandler_ctx, fd, false, - fd_read, fd_write, NULL, opaque); + fd_read, fd_write, NULL, NULL, opaque); } void event_notifier_set_handler(EventNotifier *e, @@ -590,5 +590,5 @@ void event_notifier_set_handler(EventNotifier *e, { iohandler_init(); aio_set_event_notifier(iohandler_ctx, e, false, - handler, NULL); + handler, NULL, NULL); } diff --git a/util/qemu-coroutine-io.c b/util/qemu-coroutine-io.c index 5b80bb416f..7f5839cb76 100644 --- a/util/qemu-coroutine-io.c +++ b/util/qemu-coroutine-io.c @@ -75,7 +75,8 @@ typedef struct { static void fd_coroutine_enter(void *opaque) { FDYieldUntilData *data = opaque; - aio_set_fd_handler(data->ctx, data->fd, false, NULL, NULL, NULL, NULL); + aio_set_fd_handler(data->ctx, data->fd, false, + NULL, NULL, NULL, NULL, NULL); qemu_coroutine_enter(data->co); } @@ -88,6 +89,6 @@ void coroutine_fn yield_until_fd_readable(int fd) data.co = qemu_coroutine_self(); data.fd = fd; aio_set_fd_handler( - data.ctx, fd, false, fd_coroutine_enter, NULL, NULL, &data); + data.ctx, fd, false, fd_coroutine_enter, NULL, NULL, NULL, &data); qemu_coroutine_yield(); } diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c index 783d847a6d..f68287e811 100644 --- a/util/vhost-user-server.c +++ b/util/vhost-user-server.c @@ -250,7 +250,7 @@ set_watch(VuDev *vu_dev, int fd, int vu_evt, vu_fd_watch->cb = cb; qemu_set_nonblock(fd); aio_set_fd_handler(server->ioc->ctx, fd, true, kick_handler, - NULL, NULL, vu_fd_watch); + NULL, NULL, NULL, vu_fd_watch); vu_fd_watch->vu_dev = vu_dev; vu_fd_watch->pvt = pvt; } @@ -270,7 +270,8 @@ static void remove_watch(VuDev *vu_dev, int fd) if (!vu_fd_watch) { return; } - aio_set_fd_handler(server->ioc->ctx, fd, true, NULL, NULL, NULL, NULL); + aio_set_fd_handler(server->ioc->ctx, fd, true, + NULL, NULL, NULL, NULL, NULL); QTAILQ_REMOVE(&server->vu_fd_watches, vu_fd_watch, next); g_free(vu_fd_watch); @@ -334,7 +335,7 @@ void vhost_user_server_stop(VuServer *server) QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) { aio_set_fd_handler(server->ctx, vu_fd_watch->fd, true, - NULL, NULL, NULL, vu_fd_watch); + NULL, NULL, NULL, NULL, vu_fd_watch); } qio_channel_shutdown(server->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); @@ -377,7 +378,7 @@ void vhost_user_server_attach_aio_context(VuServer *server, AioContext *ctx) QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) { aio_set_fd_handler(ctx, vu_fd_watch->fd, true, kick_handler, NULL, - NULL, vu_fd_watch); + NULL, NULL, vu_fd_watch); } aio_co_schedule(ctx, server->co_trip); @@ -391,7 +392,7 @@ void vhost_user_server_detach_aio_context(VuServer *server) QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) { aio_set_fd_handler(server->ctx, vu_fd_watch->fd, true, - NULL, NULL, NULL, vu_fd_watch); + NULL, NULL, NULL, NULL, vu_fd_watch); } qio_channel_detach_aio_context(server->ioc); |