diff --git a/emulators/qemu/Makefile b/emulators/qemu/Makefile index 34bbdf91f12..f02078c8fb4 100644 --- a/emulators/qemu/Makefile +++ b/emulators/qemu/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.183 2018/12/19 17:57:06 sthen Exp $ +# $OpenBSD: Makefile,v 1.184 2019/05/09 05:12:53 ratchov Exp $ USE_WXNEEDED= Yes @@ -7,6 +7,7 @@ ONLY_FOR_ARCHS= aarch64 amd64 arm i386 powerpc sparc64 COMMENT= multi system emulator DISTNAME= qemu-3.1.0 +REVISION= 0 CATEGORIES= emulators MASTER_SITES= https://download.qemu.org/ EXTRACT_SUFX= .tar.xz @@ -22,8 +23,8 @@ WANTLIB= SDL2 X11 atk-1.0 bz2 c cairo cairo-gobject capstone curl \ epoxy fdt gbm gdk-3 gdk_pixbuf-2.0 gio-2.0 glib-2.0 gnutls \ gobject-2.0 gthread-2.0 gtk-3 intl iscsi jpeg lzo2 m \ curses nettle nfs pango-1.0 pangocairo-1.0 pcre2-8 \ - pixman-1 png ssh2 usb-1.0 util vte-2.91 xkbcommon xml2 z \ - ${COMPILER_LIBCXX} + pixman-1 png sndio ssh2 usb-1.0 util vte-2.91 xkbcommon \ + xml2 z ${COMPILER_LIBCXX} # Using TLS emulation layer COMPILER = base-clang ports-gcc diff --git a/emulators/qemu/patches/patch-audio_Makefile_objs b/emulators/qemu/patches/patch-audio_Makefile_objs new file mode 100644 index 00000000000..355994e7263 --- /dev/null +++ b/emulators/qemu/patches/patch-audio_Makefile_objs @@ -0,0 +1,16 @@ +$OpenBSD: patch-audio_Makefile_objs,v 1.1 2019/05/09 05:12:53 ratchov Exp $ + +sndio module + +Index: audio/Makefile.objs +--- audio/Makefile.objs.orig ++++ audio/Makefile.objs +@@ -29,3 +29,8 @@ common-obj-$(CONFIG_AUDIO_SDL) += sdl.mo + sdl.mo-objs = sdlaudio.o + sdl.mo-cflags := $(SDL_CFLAGS) + sdl.mo-libs := $(SDL_LIBS) ++ ++# sndio module ++common-obj-$(CONFIG_AUDIO_SNDIO) += sndio.mo ++sndio.mo-objs = sndioaudio.o ++sndio.mo-libs := $(SNDIO_LIBS) diff --git a/emulators/qemu/patches/patch-audio_sndioaudio_c b/emulators/qemu/patches/patch-audio_sndioaudio_c new file mode 100644 index 00000000000..3d4f65e125f --- /dev/null +++ b/emulators/qemu/patches/patch-audio_sndioaudio_c @@ -0,0 +1,552 @@ +$OpenBSD: patch-audio_sndioaudio_c,v 1.1 2019/05/09 05:12:53 ratchov Exp $ + +sndio module + +Index: audio/sndioaudio.c +--- audio/sndioaudio.c.orig ++++ audio/sndioaudio.c +@@ -0,0 +1,544 @@ ++/* ++ * Copyright (c) 2019 Alexandre Ratchov ++ * ++ * Permission to use, copy, modify, and distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * TODO : ++ * ++ * - Store device handle in a global variable and open it in full-duplex ++ * rather than opening it twice. This is the only way to ensure ++ * playback doesn't drift with respect to recording, which ++ * is what guest systems expect. ++ * ++ * - Clarify whether hw->wpos can wrap, see sndio_run_in(). As we only ++ * transfer one block at a time, hw->hwpos can't wrap, unless upper ++ * layer skip samples. ++ */ ++ ++#include ++#include ++#include "qemu/osdep.h" ++#include "qemu-common.h" ++#include "qemu/main-loop.h" ++#include "audio.h" ++#include "trace.h" ++ ++#define AUDIO_CAP "sndio" ++#include "audio_int.h" ++ ++typedef struct SndioVoice { ++ union { ++ HWVoiceOut out; ++ HWVoiceIn in; ++ } hw; ++ struct sio_par par; ++ struct sio_hdl *hdl; ++ struct pollfd *pfds; ++ struct pollindex { ++ struct SndioVoice *self; ++ int index; ++ } *pindexes; ++ unsigned char *buf; ++ unsigned int bpf; ++ unsigned int sndio_pos; ++ unsigned int qemu_pos; ++ unsigned int mode; ++ unsigned int nfds; ++} SndioVoice; ++ ++typedef struct SndioConf { ++ const char *devname; ++ unsigned int latency; ++} SndioConf; ++ ++/* needed for forward reference */ ++static void sndio_poll_in(void *arg); ++static void sndio_poll_out(void *arg); ++ ++static SndioConf glob_conf = { ++ .devname = SIO_DEVANY, ++ .latency = 50 ++}; ++ ++static void sndio_poll_clear (SndioVoice *self) ++{ ++ struct pollfd *pfd; ++ int i; ++ ++ for (i = 0; i < self->nfds; i++) { ++ pfd = &self->pfds[i]; ++ qemu_set_fd_handler (pfd->fd, NULL, NULL, NULL); ++ } ++ ++ self->nfds = 0; ++} ++ ++static void sndio_poll_wait(SndioVoice *self, int events) ++{ ++ struct pollfd *pfd; ++ int i; ++ ++ /* ++ * fill the given array of descriptors with the events sndio ++ * wants, they are different from our 'event' variable because ++ * sndio may use descriptors internally. ++ */ ++ self->nfds = sio_pollfd (self->hdl, self->pfds, events); ++ ++ for (i = 0; i < self->nfds; i++) { ++ pfd = &self->pfds[i]; ++ if (pfd->fd < 0) ++ continue; ++ qemu_set_fd_handler (pfd->fd, ++ (pfd->events & POLLIN) ? sndio_poll_in : NULL, ++ (pfd->events & POLLOUT) ? sndio_poll_out : NULL, ++ &self->pindexes[i]); ++ pfd->revents = 0; ++ } ++} ++ ++static void sndio_write_do(SndioVoice *self) ++{ ++ int todo, n; ++ ++ todo = (self->qemu_pos * self->bpf) - self->sndio_pos; ++ ++ /* ++ * transfer data to device, until it blocks ++ */ ++ while (todo > 0) { ++ n = sio_write (self->hdl, self->buf + self->sndio_pos, todo); ++ if (n == 0) ++ break; ++ self->sndio_pos += n; ++ todo -= n; ++ } ++ ++ /* ++ * did we complete the block ? ++ */ ++ if (todo == 0 && self->qemu_pos == self->par.round) { ++ self->sndio_pos = 0; ++ self->qemu_pos = 0; ++ } ++ ++ audio_run ("sndio_out"); ++} ++ ++static void sndio_read_do(SndioVoice *self) ++{ ++ int todo, n; ++ ++ todo = (self->par.round * self->bpf) - self->sndio_pos; ++ ++ /* ++ * transfer data from the device, until it blocks ++ */ ++ while (todo > 0) { ++ n = sio_read (self->hdl, self->buf + self->sndio_pos, todo); ++ if (n == 0) ++ break; ++ self->sndio_pos += n; ++ todo -= n; ++ } ++ ++ audio_run ("sndio_in"); ++} ++ ++static void sndio_poll_event (SndioVoice *self, int index, int event) ++{ ++ int revents, todo; ++ ++ /* ++ * ensure we're not called twice this cycle ++ */ ++ sndio_poll_clear (self); ++ ++ /* ++ * make self->pfds[] look as we're returning from poll syscal, ++ * this is how sio_revents expects events to be. ++ */ ++ self->pfds[index].revents = event; ++ ++ /* ++ * tell sndio to handle events and return whether we can read or ++ * write without blocking. ++ */ ++ revents = sio_revents (self->hdl, self->pfds); ++ if (self->mode == SIO_PLAY) { ++ if (revents & POLLOUT) ++ sndio_write_do (self); ++ ++ todo = (self->qemu_pos * self->bpf) - self->sndio_pos; ++ sndio_poll_wait (self, todo > 0 ? POLLOUT : 0); ++ ++ } else { ++ if (revents & POLLIN) ++ sndio_read_do (self); ++ ++ todo = (self->par.round * self->bpf) - self->sndio_pos; ++ sndio_poll_wait (self, todo > 0 ? POLLIN : 0); ++ } ++} ++ ++static void sndio_poll_in(void *arg) ++{ ++ struct pollindex *pindex = (struct pollindex *) arg; ++ ++ sndio_poll_event (pindex->self, pindex->index, POLLIN); ++} ++ ++static void sndio_poll_out(void *arg) ++{ ++ struct pollindex *pindex = (struct pollindex *) arg; ++ ++ sndio_poll_event (pindex->self, pindex->index, POLLOUT); ++} ++ ++static void sndio_fini (SndioVoice *self) ++{ ++ if (self->hdl) { ++ sio_close (self->hdl); ++ self->hdl = NULL; ++ } ++ ++ if (self->pfds) { ++ g_free (self->pfds); ++ self->pfds = NULL; ++ } ++ ++ if (self->pindexes) { ++ g_free (self->pindexes); ++ self->pindexes = NULL; ++ } ++ ++ if (self->buf) { ++ g_free (self->buf); ++ self->buf = NULL; ++ } ++} ++ ++static int sndio_init (SndioVoice *self, ++ struct audsettings *as, int mode, SndioConf *cf) ++{ ++ struct sio_par req; ++ unsigned int nch; ++ int i, nfds; ++ ++ self->hdl = sio_open (cf->devname, mode, 1); ++ if (self->hdl == NULL) { ++ dolog ("failed to open device\n"); ++ return -1; ++ } ++ ++ self->mode = mode; ++ ++ sio_initpar(&req); ++ ++ switch (as->fmt) { ++ case AUD_FMT_S8: ++ req.bits = 8; ++ req.sig = 1; ++ break; ++ case AUD_FMT_U8: ++ req.bits = 8; ++ req.sig = 0; ++ break; ++ case AUD_FMT_S16: ++ req.bits = 16; ++ req.sig = 1; ++ break; ++ case AUD_FMT_U16: ++ req.bits = 16; ++ req.sig = 0; ++ break; ++ case AUD_FMT_S32: ++ req.bits = 32; ++ req.sig = 1; ++ break; ++ case AUD_FMT_U32: ++ req.bits = 32; ++ req.sig = 0; ++ } ++ ++ if (req.bits > 8) ++ req.le = as->endianness ? 0 : 1; ++ ++ req.rate = as->freq; ++ if (mode == SIO_PLAY) ++ req.pchan = as->nchannels; ++ else ++ req.rchan = as->nchannels; ++ ++ /* set on-device buffer size */ ++ req.appbufsz = req.rate * cf->latency / 1000; ++ ++ if (!sio_setpar (self->hdl, &req)) { ++ dolog ("failed set audio params\n"); ++ goto fail; ++ } ++ ++ if (!sio_getpar (self->hdl, &self->par)) { ++ dolog ("failed get audio params\n"); ++ goto fail; ++ } ++ ++ nch = (mode == SIO_PLAY) ? self->par.pchan : self->par.rchan; ++ ++ if (self->par.bits != req.bits || self->par.bps != req.bits / 8 || ++ self->par.sig != req.sig || (req.bits > 8 && self->par.le != req.le) || ++ self->par.rate != as->freq || nch != as->nchannels) { ++ dolog ("unsupported audio params\n"); ++ goto fail; ++ } ++ ++ self->bpf = self->par.bps * nch; ++ ++ self->buf = audio_calloc (__func__, self->par.round, self->bpf); ++ if (self->buf == NULL) { ++ dolog ("failed to allocate audio buffer\n"); ++ goto fail; ++ } ++ ++ nfds = sio_nfds (self->hdl); ++ ++ self->pfds = g_malloc_n (nfds, sizeof(struct pollfd)); ++ if (self->pfds == NULL) { ++ dolog ("failed to allocate pollfd structures\n"); ++ goto fail; ++ } ++ ++ self->pindexes = g_malloc_n (nfds, sizeof(struct pollindex)); ++ if (self->pindexes == NULL) { ++ dolog ("failed to allocate pollindex structures\n"); ++ goto fail; ++ } ++ ++ for (i = 0; i < nfds; i++) { ++ self->pindexes[i].self = self; ++ self->pindexes[i].index = i; ++ } ++ ++ return 0; ++fail: ++ sndio_fini (self); ++ return -1; ++} ++ ++static int sndio_run_out (HWVoiceOut *hw, int live) ++{ ++ SndioVoice *self = (SndioVoice *) hw; ++ int decr, todo; ++ ++ decr = hw->samples - self->qemu_pos; ++ if (decr > live) ++ decr = live; ++ ++ decr = audio_pcm_hw_clip_out (hw, self->buf, decr, self->qemu_pos); ++ ++ self->qemu_pos += decr; ++ ++ todo = (self->qemu_pos * self->bpf) - self->sndio_pos; ++ sndio_poll_wait (self, todo > 0 ? POLLOUT : 0); ++ ++ return decr; ++} ++ ++static int sndio_run_in (HWVoiceIn *hw) ++{ ++ SndioVoice *self = (SndioVoice *) hw; ++ int decr, todo, avail; ++ ++ avail = (self->sndio_pos / self->bpf) - self->qemu_pos; ++ ++ decr = hw->samples - audio_pcm_hw_get_live_in (hw); ++ if (decr > avail) ++ decr = avail; ++ ++ if (hw->wpos + decr > hw->samples) { ++ dolog ("%s: overrun: wpos = %d, decr = %d\n", __func__, hw->wpos, decr); ++ abort(); ++ } ++ ++ hw->conv (hw->conv_buf + hw->wpos, ++ self->buf + (hw->wpos * self->bpf), ++ decr); ++ ++ self->qemu_pos += decr; ++ ++ /* did we complete the block ? */ ++ if (self->qemu_pos == self->par.round) { ++ self->qemu_pos = 0; ++ self->sndio_pos = 0; ++ } ++ ++ todo = (self->par.round * self->bpf) - self->sndio_pos; ++ sndio_poll_wait (self, todo > 0 ? POLLIN : 0); ++ ++ hw->wpos += decr; ++ if (hw->wpos == hw->samples) ++ hw->wpos = 0; ++ ++ return decr; ++} ++ ++static int sndio_ctl (SndioVoice *self, int cmd) ++{ ++ switch (cmd) { ++ case VOICE_ENABLE: ++ sio_start (self->hdl); ++ sndio_poll_wait (self, 0); ++ return 0; ++ ++ case VOICE_DISABLE: ++ sndio_poll_clear (self); ++ sio_stop (self->hdl); ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static int sndio_write (SWVoiceOut *sw, void *buf, int len) ++{ ++ return audio_pcm_sw_write (sw, buf, len); ++} ++ ++static int sndio_read (SWVoiceIn *sw, void *buf, int len) ++{ ++ return audio_pcm_sw_read (sw, buf, len); ++} ++ ++static int sndio_ctl_out (HWVoiceOut *hw, int cmd, ...) ++{ ++ SndioVoice *self = (SndioVoice *) hw; ++ ++ return sndio_ctl (self, cmd); ++} ++ ++static int sndio_ctl_in (HWVoiceIn *hw, int cmd, ...) ++{ ++ SndioVoice *self = (SndioVoice *) hw; ++ ++ return sndio_ctl (self, cmd); ++} ++ ++static int sndio_init_out (HWVoiceOut *hw, struct audsettings *as, void *opaque) ++{ ++ SndioVoice *self = (SndioVoice *) hw; ++ ++ if (sndio_init (self, as, SIO_PLAY, opaque) == -1) ++ return -1; ++ ++ audio_pcm_init_info (&hw->info, as); ++ hw->samples = self->par.round; ++ ++ return 0; ++} ++ ++static int sndio_init_in (HWVoiceIn *hw, struct audsettings *as, void *opaque) ++{ ++ SndioVoice *self = (SndioVoice *) hw; ++ ++ if (sndio_init (self, as, SIO_REC, opaque) == -1) ++ return -1; ++ ++ audio_pcm_init_info (&hw->info, as); ++ hw->samples = self->par.round; ++ ++ return 0; ++} ++ ++static void sndio_fini_out (HWVoiceOut *hw) ++{ ++ SndioVoice *self = (SndioVoice *) hw; ++ ++ return sndio_fini(self); ++} ++ ++static void sndio_fini_in (HWVoiceIn *hw) ++{ ++ SndioVoice *self = (SndioVoice *) hw; ++ ++ return sndio_fini(self); ++} ++ ++static void *sndio_audio_init (void) ++{ ++ SndioConf *conf; ++ ++ conf = g_malloc(sizeof(SndioConf)); ++ if (conf == NULL) ++ return NULL; ++ ++ *conf = glob_conf; ++ ++ return conf; ++} ++ ++static void sndio_audio_fini (void *opaque) ++{ ++ g_free(opaque); ++} ++ ++static struct audio_option sndio_options[] = { ++ { ++ .name = "LATENCY", ++ .tag = AUD_OPT_INT, ++ .valp = &glob_conf.latency, ++ .descr = "Desired latency in milliseconds" ++ }, ++ { ++ .name = "DEVICE", ++ .tag = AUD_OPT_STR, ++ .valp = &glob_conf.devname, ++ .descr = "Device name" ++ }, ++ { /* End of list */ } ++}; ++ ++static struct audio_pcm_ops sndio_pcm_ops = { ++ .init_out = sndio_init_out, ++ .fini_out = sndio_fini_out, ++ .run_out = sndio_run_out, ++ .write = sndio_write, ++ .ctl_out = sndio_ctl_out, ++ .init_in = sndio_init_in, ++ .fini_in = sndio_fini_in, ++ .run_in = sndio_run_in, ++ .read = sndio_read, ++ .ctl_in = sndio_ctl_in, ++}; ++ ++static struct audio_driver sndio_audio_driver = { ++ .name = "sndio", ++ .descr = "https://man.openbsd.org/sndio", ++ .options = sndio_options, ++ .init = sndio_audio_init, ++ .fini = sndio_audio_fini, ++ .pcm_ops = &sndio_pcm_ops, ++ .can_be_default = 1, ++ .max_voices_out = INT_MAX, ++ .max_voices_in = INT_MAX, ++ .voice_size_out = sizeof (SndioVoice), ++ .voice_size_in = sizeof (SndioVoice) ++}; ++ ++static void register_audio_sndio(void) ++{ ++ audio_driver_register(&sndio_audio_driver); ++} ++ ++type_init(register_audio_sndio); diff --git a/emulators/qemu/patches/patch-configure b/emulators/qemu/patches/patch-configure index e502e3af1b0..ddae4025ebd 100644 --- a/emulators/qemu/patches/patch-configure +++ b/emulators/qemu/patches/patch-configure @@ -1,11 +1,36 @@ -$OpenBSD: patch-configure,v 1.59 2018/12/19 17:57:06 sthen Exp $ +$OpenBSD: patch-configure,v 1.60 2019/05/09 05:12:53 ratchov Exp $ -Fix curses test to work on OpenBSD +- sndio module +- Fix curses test to work on OpenBSD Index: configure --- configure.orig +++ configure -@@ -3370,6 +3370,7 @@ if test "$curses" != "no" ; then +@@ -819,8 +819,8 @@ NetBSD) + OpenBSD) + bsd="yes" + make="${MAKE-gmake}" +- audio_drv_list="sdl" +- audio_possible_drivers="sdl" ++ audio_drv_list="sndio" ++ audio_possible_drivers="sndio" + HOST_VARIANT_DIR="openbsd" + supported_os="yes" + ;; +@@ -3312,6 +3312,12 @@ for drv in $audio_drv_list; do + fi + ;; + ++ sndio) ++ audio_drv_probe $drv sndio.h "-lsndio" \ ++ "sio_open(0, SIO_PLAY, 0); return 0;" ++ sndio_libs="-lsndio" ++ ;; ++ + coreaudio) + coreaudio_libs="-framework CoreAudio" + ;; +@@ -3370,6 +3376,7 @@ if test "$curses" != "no" ; then fi curses_found=no cat > $TMPC << EOF @@ -13,7 +38,7 @@ Index: configure #include #include #include -@@ -5631,10 +5632,6 @@ write_c_skeleton +@@ -5631,10 +5638,6 @@ write_c_skeleton if test "$gcov" = "yes" ; then CFLAGS="-fprofile-arcs -ftest-coverage -g $CFLAGS" LDFLAGS="-fprofile-arcs -ftest-coverage $LDFLAGS" @@ -24,3 +49,20 @@ Index: configure fi if test "$have_asan" = "yes"; then +@@ -6261,7 +6264,7 @@ echo "CONFIG_AUDIO_DRIVERS=$audio_drv_list" >> $config + for drv in $audio_drv_list; do + def=CONFIG_AUDIO_$(echo $drv | LC_ALL=C tr '[a-z]' '[A-Z]') + case "$drv" in +- alsa | oss | pa | sdl) ++ alsa | oss | pa | sdl | sndio) + echo "$def=m" >> $config_host_mak ;; + *) + echo "$def=y" >> $config_host_mak ;; +@@ -6275,6 +6278,7 @@ echo "OSS_LIBS=$oss_libs" >> $config_host_mak + if test "$audio_pt_int" = "yes" ; then + echo "CONFIG_AUDIO_PT_INT=y" >> $config_host_mak + fi ++echo "SNDIO_LIBS=$sndio_libs" >> $config_host_mak + if test "$audio_win_int" = "yes" ; then + echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak + fi