usb: make usbnet work with xhci.

audio: add sndio backend.
 misc bugfixes for console, xhci, audio, ati-vga and virtio-gpu.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEoDKM/7k6F6eZAf59TLbY7tPocTgFAmMyse8ACgkQTLbY7tPo
 cTiLrRAAltoyd++jsmhg2wXuJsfekfec3kOro7T+eSznDWfBRvm7VxJ+gswYBYga
 HbEkHjII0yPbOP9WDMhhHx33g2nYdbhDLPKXHdK8MjHTTPxtYP7XmsWkEVpuuzTx
 WqeYvGSmUri6QOUz7fd07IhiBT1aQvUQ/vWQ6OhyRVPy41bR8kIbGx3iV0JDxWvz
 n3xUZALGLz3QAM0lXRzXPYT9JB/RqdbpMM35HNTpN9/xaZmgFWsyuQXSSm61pTtb
 PS+lILDPjgZeYsfsZRyhZaSZrp2f6WOGm1ZdtSM0rvmRKezOzYnG8fm4fqZQLYSj
 nrAqUs38sKaM71a3QbpXhDjbv4cpj0K3iSNLmlUq4pgvPiMgwPlgSwwCGlkNDaRo
 IA1KON1pMH2A5vvtXEUt5RTkbXxHAAKPdpl5sS6kgbs7dgoKDqzaIPFQELam259Z
 9nbMBqz/d6gm2CFT5ogrY0q511IC5hWtsmbQZkOZeBd5SvhvyJ59DIabFDcw05fG
 ixZVapewXYtzFUde2lb8X5qyneUVeGY5D2OJ2uUykHgR2Qz4d3CjXlhnRkLIkMcd
 Uu6N1LTkjyuuB86BoTSZxk0iz94OvmyDiXpqwmRaCGcdnTOTj0dKrbRrtHdC2vCo
 cBpUAIdyJvDJSm0X8ZWvvv1sMJCAJ7lofFf/P/jUKlacC2ipgXQ=
 =QBLK
 -----END PGP SIGNATURE-----

Merge tag 'kraxel-20220927-pull-request' of https://gitlab.com/kraxel/qemu into staging

usb: make usbnet work with xhci.
audio: add sndio backend.
misc bugfixes for console, xhci, audio, ati-vga and virtio-gpu.

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCgAdFiEEoDKM/7k6F6eZAf59TLbY7tPocTgFAmMyse8ACgkQTLbY7tPo
# cTiLrRAAltoyd++jsmhg2wXuJsfekfec3kOro7T+eSznDWfBRvm7VxJ+gswYBYga
# HbEkHjII0yPbOP9WDMhhHx33g2nYdbhDLPKXHdK8MjHTTPxtYP7XmsWkEVpuuzTx
# WqeYvGSmUri6QOUz7fd07IhiBT1aQvUQ/vWQ6OhyRVPy41bR8kIbGx3iV0JDxWvz
# n3xUZALGLz3QAM0lXRzXPYT9JB/RqdbpMM35HNTpN9/xaZmgFWsyuQXSSm61pTtb
# PS+lILDPjgZeYsfsZRyhZaSZrp2f6WOGm1ZdtSM0rvmRKezOzYnG8fm4fqZQLYSj
# nrAqUs38sKaM71a3QbpXhDjbv4cpj0K3iSNLmlUq4pgvPiMgwPlgSwwCGlkNDaRo
# IA1KON1pMH2A5vvtXEUt5RTkbXxHAAKPdpl5sS6kgbs7dgoKDqzaIPFQELam259Z
# 9nbMBqz/d6gm2CFT5ogrY0q511IC5hWtsmbQZkOZeBd5SvhvyJ59DIabFDcw05fG
# ixZVapewXYtzFUde2lb8X5qyneUVeGY5D2OJ2uUykHgR2Qz4d3CjXlhnRkLIkMcd
# Uu6N1LTkjyuuB86BoTSZxk0iz94OvmyDiXpqwmRaCGcdnTOTj0dKrbRrtHdC2vCo
# cBpUAIdyJvDJSm0X8ZWvvv1sMJCAJ7lofFf/P/jUKlacC2ipgXQ=
# =QBLK
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 27 Sep 2022 04:18:55 EDT
# gpg:                using RSA key A0328CFFB93A17A79901FE7D4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* tag 'kraxel-20220927-pull-request' of https://gitlab.com/kraxel/qemu: (24 commits)
  virtio-gpu: update scanout if there is any area covered by the rect
  hw/display/ati_2d: Fix buffer overflow in ati_2d_blt (CVE-2021-3638)
  audio: remove abort() in audio_bug()
  Revert "audio: Log context for audio bug"
  audio: Add sndio backend
  usbnet: Report link-up via interrupt endpoint in CDC-ECM mode
  usbnet: Detect short packets as sent by the xHCI controller
  usbnet: Accept mandatory USB_CDC_SET_ETHERNET_PACKET_FILTER request
  usbnet: Add missing usb_wakeup() call in usbnet_receive()
  hcd-xhci: drop operation with secondary stream arrays enabled
  usb/msd: add usb_msd_fatal_error() and fix guest-triggerable assert
  usb/msd: move usb_msd_packet_complete()
  hcd-ohci: Drop ohci_service_iso_td() if ed->head & OHCI_DPTR_MASK is zero
  hw/usb/hcd-xhci: Check whether DMA accesses fail
  ui/console: fix three double frees in png_save()
  ui/vdagent: fix serial reset of guest agent
  ui/clipboard: reset the serial state on reset
  ui/vdagent: always reset the clipboard serial on caps
  ui/clipboard: fix serial priority
  ui: add some vdagent related traces
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
master
Stefan Hajnoczi 2022-09-27 07:59:26 -04:00
commit c48c9c6b33
31 changed files with 903 additions and 205 deletions

View File

@ -2438,6 +2438,7 @@ X: audio/jackaudio.c
X: audio/ossaudio.c
X: audio/paaudio.c
X: audio/sdlaudio.c
X: audio/sndioaudio.c
X: audio/spiceaudio.c
F: qapi/audio.json
@ -2482,6 +2483,12 @@ R: Thomas Huth <huth@tuxfamily.org>
S: Odd Fixes
F: audio/sdlaudio.c
Sndio Audio backend
M: Gerd Hoffmann <kraxel@redhat.com>
R: Alexandre Ratchov <alex@caoua.org>
S: Odd Fixes
F: audio/sndioaudio.c
Block layer core
M: Kevin Wolf <kwolf@redhat.com>
M: Hanna Reitz <hreitz@redhat.com>

View File

@ -138,7 +138,7 @@ static inline int audio_bits_to_index (int bits)
default:
audio_bug ("bits_to_index", 1);
AUD_log (NULL, "invalid bits %d\n", bits);
abort();
return 0;
}
}
@ -156,7 +156,7 @@ void *audio_calloc (const char *funcname, int nmemb, size_t size)
AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n",
funcname);
AUD_log (NULL, "nmemb=%d size=%zu (len=%zu)\n", nmemb, size, len);
abort();
return NULL;
}
return g_malloc0 (len);
@ -543,7 +543,7 @@ static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
if (audio_bug(__func__, live > hw->conv_buf->size)) {
dolog("live=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
abort();
return 0;
}
return live;
}
@ -581,7 +581,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
}
if (audio_bug(__func__, live > hw->conv_buf->size)) {
dolog("live_in=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
abort();
return 0;
}
rpos = audio_ring_posb(hw->conv_buf->pos, live, hw->conv_buf->size);
@ -656,7 +656,7 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
if (audio_bug(__func__, live > hw->mix_buf->size)) {
dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
abort();
return 0;
}
return live;
}
@ -706,7 +706,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
live = sw->total_hw_samples_mixed;
if (audio_bug(__func__, live > hwsamples)) {
dolog("live=%zu hw->mix_buf->size=%zu\n", live, hwsamples);
abort();
return 0;
}
if (live == hwsamples) {
@ -998,7 +998,7 @@ static size_t audio_get_avail (SWVoiceIn *sw)
if (audio_bug(__func__, live > sw->hw->conv_buf->size)) {
dolog("live=%zu sw->hw->conv_buf->size=%zu\n", live,
sw->hw->conv_buf->size);
abort();
return 0;
}
ldebug (
@ -1028,7 +1028,7 @@ static size_t audio_get_free(SWVoiceOut *sw)
if (audio_bug(__func__, live > sw->hw->mix_buf->size)) {
dolog("live=%zu sw->hw->mix_buf->size=%zu\n", live,
sw->hw->mix_buf->size);
abort();
return 0;
}
dead = sw->hw->mix_buf->size - live;
@ -1170,7 +1170,7 @@ static void audio_run_out (AudioState *s)
if (audio_bug(__func__, live > hw->mix_buf->size)) {
dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
abort();
continue;
}
if (hw->pending_disable && !nb_live) {
@ -1203,7 +1203,7 @@ static void audio_run_out (AudioState *s)
if (audio_bug(__func__, hw->mix_buf->pos >= hw->mix_buf->size)) {
dolog("hw->mix_buf->pos=%zu hw->mix_buf->size=%zu played=%zu\n",
hw->mix_buf->pos, hw->mix_buf->size, played);
abort();
hw->mix_buf->pos = 0;
}
#ifdef DEBUG_OUT
@ -1223,7 +1223,7 @@ static void audio_run_out (AudioState *s)
if (audio_bug(__func__, played > sw->total_hw_samples_mixed)) {
dolog("played=%zu sw->total_hw_samples_mixed=%zu\n",
played, sw->total_hw_samples_mixed);
abort();
played = sw->total_hw_samples_mixed;
}
sw->total_hw_samples_mixed -= played;
@ -1346,7 +1346,7 @@ static void audio_run_capture (AudioState *s)
if (audio_bug(__func__, captured > sw->total_hw_samples_mixed)) {
dolog("captured=%zu sw->total_hw_samples_mixed=%zu\n",
captured, sw->total_hw_samples_mixed);
abort();
captured = sw->total_hw_samples_mixed;
}
sw->total_hw_samples_mixed -= captured;
@ -2030,6 +2030,7 @@ void audio_create_pdos(Audiodev *dev)
CASE(OSS, oss, Oss);
CASE(PA, pa, Pa);
CASE(SDL, sdl, Sdl);
CASE(SNDIO, sndio, );
CASE(SPICE, spice, );
CASE(WAV, wav, );

View File

@ -59,13 +59,12 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
if (audio_bug(__func__, !voice_size && max_voices)) {
dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
drv->name, max_voices);
abort();
glue (s->nb_hw_voices_, TYPE) = 0;
}
if (audio_bug(__func__, voice_size && !max_voices)) {
dolog ("drv=`%s' voice_size=%d max_voices=0\n",
drv->name, voice_size);
abort();
}
}
@ -82,7 +81,6 @@ static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
size_t samples = hw->samples;
if (audio_bug(__func__, samples == 0)) {
dolog("Attempted to allocate empty buffer\n");
abort();
}
HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples);
@ -254,12 +252,12 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
if (audio_bug(__func__, !drv)) {
dolog ("No host audio driver\n");
abort();
return NULL;
}
if (audio_bug(__func__, !drv->pcm_ops)) {
dolog ("Host audio driver without pcm_ops\n");
abort();
return NULL;
}
hw = audio_calloc(__func__, 1, glue(drv->voice_size_, TYPE));
@ -277,13 +275,12 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
QLIST_INIT (&hw->cap_head);
#endif
if (glue (hw->pcm_ops->init_, TYPE) (hw, as, s->drv_opaque)) {
g_free(hw);
return NULL;
goto err0;
}
if (audio_bug(__func__, hw->samples <= 0)) {
dolog("hw->samples=%zd\n", hw->samples);
abort();
goto err1;
}
if (hw->info.is_float) {
@ -312,6 +309,12 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
audio_attach_capture (hw);
#endif
return hw;
err1:
glue (hw->pcm_ops->fini_, TYPE) (hw);
err0:
g_free (hw);
return NULL;
}
AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
@ -336,6 +339,8 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE);
case AUDIODEV_DRIVER_SDL:
return qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.TYPE);
case AUDIODEV_DRIVER_SNDIO:
return dev->u.sndio.TYPE;
case AUDIODEV_DRIVER_SPICE:
return dev->u.spice.TYPE;
case AUDIODEV_DRIVER_WAV:
@ -432,7 +437,7 @@ void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
if (sw) {
if (audio_bug(__func__, !card)) {
dolog ("card=%p\n", card);
abort();
return;
}
glue (audio_close_, TYPE) (sw);
@ -454,7 +459,7 @@ SW *glue (AUD_open_, TYPE) (
if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
dolog ("card=%p name=%p callback_fn=%p as=%p\n",
card, name, callback_fn, as);
abort();
goto fail;
}
s = card->state;
@ -465,12 +470,12 @@ SW *glue (AUD_open_, TYPE) (
if (audio_bug(__func__, audio_validate_settings(as))) {
audio_print_settings (as);
abort();
goto fail;
}
if (audio_bug(__func__, !s->drv)) {
dolog ("Can not open `%s' (no host audio driver)\n", name);
abort();
goto fail;
}
if (sw && audio_pcm_info_eq (&sw->info, as)) {

View File

@ -17,6 +17,7 @@ foreach m : [
['pa', pulse, files('paaudio.c')],
['sdl', sdl, files('sdlaudio.c')],
['jack', jack, files('jackaudio.c')],
['sndio', sndio, files('sndioaudio.c')],
['spice', spice, files('spiceaudio.c')]
]
if m[1].found()

565
audio/sndioaudio.c Normal file
View File

@ -0,0 +1,565 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2019 Alexandre Ratchov <alex@caoua.org>
*/
/*
* TODO :
*
* Use a single device and open it in full-duplex rather than
* opening it twice (once for playback once for recording).
*
* This is the only way to ensure that playback doesn't drift with respect
* to recording, which is what guest systems expect.
*/
#include <poll.h>
#include <sndio.h>
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "audio.h"
#include "trace.h"
#define AUDIO_CAP "sndio"
#include "audio_int.h"
/* default latency in microseconds if no option is set */
#define SNDIO_LATENCY_US 50000
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;
size_t buf_size;
size_t sndio_pos;
size_t qemu_pos;
unsigned int mode;
unsigned int nfds;
bool enabled;
} 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);
/*
* stop polling descriptors
*/
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;
}
/*
* write data to the device until it blocks or
* all of our buffered data is written
*/
static void sndio_write(SndioVoice *self)
{
size_t todo, n;
todo = self->qemu_pos - 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;
}
if (self->sndio_pos == self->buf_size) {
/*
* we complete the block
*/
self->sndio_pos = 0;
self->qemu_pos = 0;
}
}
/*
* read data from the device until it blocks or
* there no room any longer
*/
static void sndio_read(SndioVoice *self)
{
size_t todo, n;
todo = self->buf_size - 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;
}
}
/*
* Set handlers for all descriptors libsndio needs to
* poll
*/
static void sndio_poll_wait(SndioVoice *self)
{
struct pollfd *pfd;
int events, i;
events = 0;
if (self->mode == SIO_PLAY) {
if (self->sndio_pos < self->qemu_pos) {
events |= POLLOUT;
}
} else {
if (self->sndio_pos < self->buf_size) {
events |= POLLIN;
}
}
/*
* 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;
}
}
/*
* call-back called when one of the descriptors
* became readable or writable
*/
static void sndio_poll_event(SndioVoice *self, int index, int event)
{
int revents;
/*
* 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(self);
}
if (self->qemu_pos < self->buf_size) {
audio_run(self->hw.out.s, "sndio_out");
}
} else {
if (revents & POLLIN) {
sndio_read(self);
}
if (self->qemu_pos < self->sndio_pos) {
audio_run(self->hw.in.s, "sndio_in");
}
}
/*
* audio_run() may have changed state
*/
if (self->enabled) {
sndio_poll_wait(self);
}
}
/*
* return the upper limit of the amount of free play buffer space
*/
static size_t sndio_buffer_get_free(HWVoiceOut *hw)
{
SndioVoice *self = (SndioVoice *) hw;
return self->buf_size - self->qemu_pos;
}
/*
* return a buffer where data to play can be stored,
* its size is stored in the location pointed by the size argument.
*/
static void *sndio_get_buffer_out(HWVoiceOut *hw, size_t *size)
{
SndioVoice *self = (SndioVoice *) hw;
*size = self->buf_size - self->qemu_pos;
return self->buf + self->qemu_pos;
}
/*
* put back to sndio back-end a buffer returned by sndio_get_buffer_out()
*/
static size_t sndio_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
{
SndioVoice *self = (SndioVoice *) hw;
self->qemu_pos += size;
sndio_poll_wait(self);
return size;
}
/*
* return a buffer from where recorded data is available,
* its size is stored in the location pointed by the size argument.
* it may not exceed the initial value of "*size".
*/
static void *sndio_get_buffer_in(HWVoiceIn *hw, size_t *size)
{
SndioVoice *self = (SndioVoice *) hw;
size_t todo, max_todo;
/*
* unlike the get_buffer_out() method, get_buffer_in()
* must return a buffer of at most the given size, see audio.c
*/
max_todo = *size;
todo = self->sndio_pos - self->qemu_pos;
if (todo > max_todo) {
todo = max_todo;
}
*size = todo;
return self->buf + self->qemu_pos;
}
/*
* discard the given amount of recorded data
*/
static void sndio_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
{
SndioVoice *self = (SndioVoice *) hw;
self->qemu_pos += size;
if (self->qemu_pos == self->buf_size) {
self->qemu_pos = 0;
self->sndio_pos = 0;
}
sndio_poll_wait(self);
}
/*
* call-back called when one of our descriptors becomes writable
*/
static void sndio_poll_out(void *arg)
{
struct pollindex *pindex = (struct pollindex *) arg;
sndio_poll_event(pindex->self, pindex->index, POLLOUT);
}
/*
* call-back called when one of our descriptors becomes readable
*/
static void sndio_poll_in(void *arg)
{
struct pollindex *pindex = (struct pollindex *) arg;
sndio_poll_event(pindex->self, pindex->index, POLLIN);
}
static void sndio_fini(SndioVoice *self)
{
if (self->hdl) {
sio_close(self->hdl);
self->hdl = NULL;
}
g_free(self->pfds);
g_free(self->pindexes);
g_free(self->buf);
}
static int sndio_init(SndioVoice *self,
struct audsettings *as, int mode, Audiodev *dev)
{
AudiodevSndioOptions *opts = &dev->u.sndio;
unsigned long long latency;
const char *dev_name;
struct sio_par req;
unsigned int nch;
int i, nfds;
dev_name = opts->has_dev ? opts->dev : SIO_DEVANY;
latency = opts->has_latency ? opts->latency : SNDIO_LATENCY_US;
/* open the device in non-blocking mode */
self->hdl = sio_open(dev_name, mode, 1);
if (self->hdl == NULL) {
dolog("failed to open device\n");
return -1;
}
self->mode = mode;
sio_initpar(&req);
switch (as->fmt) {
case AUDIO_FORMAT_S8:
req.bits = 8;
req.sig = 1;
break;
case AUDIO_FORMAT_U8:
req.bits = 8;
req.sig = 0;
break;
case AUDIO_FORMAT_S16:
req.bits = 16;
req.sig = 1;
break;
case AUDIO_FORMAT_U16:
req.bits = 16;
req.sig = 0;
break;
case AUDIO_FORMAT_S32:
req.bits = 32;
req.sig = 1;
break;
case AUDIO_FORMAT_U32:
req.bits = 32;
req.sig = 0;
break;
default:
dolog("unknown audio sample format\n");
return -1;
}
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 * latency / 1000000;
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;
/*
* With the default setup, sndio supports any combination of parameters
* so these checks are mostly to catch configuration errors.
*/
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;
}
/*
* we use one block as buffer size; this is how
* transfers get well aligned
*/
self->buf_size = self->par.round * self->par.bps * nch;
self->buf = g_malloc(self->buf_size);
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 void sndio_enable(SndioVoice *self, bool enable)
{
if (enable) {
sio_start(self->hdl);
self->enabled = true;
sndio_poll_wait(self);
} else {
self->enabled = false;
sndio_poll_clear(self);
sio_stop(self->hdl);
}
}
static void sndio_enable_out(HWVoiceOut *hw, bool enable)
{
SndioVoice *self = (SndioVoice *) hw;
sndio_enable(self, enable);
}
static void sndio_enable_in(HWVoiceIn *hw, bool enable)
{
SndioVoice *self = (SndioVoice *) hw;
sndio_enable(self, enable);
}
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;
sndio_fini(self);
}
static void sndio_fini_in(HWVoiceIn *hw)
{
SndioVoice *self = (SndioVoice *) hw;
sndio_fini(self);
}
static void *sndio_audio_init(Audiodev *dev)
{
assert(dev->driver == AUDIODEV_DRIVER_SNDIO);
return dev;
}
static void sndio_audio_fini(void *opaque)
{
}
static struct audio_pcm_ops sndio_pcm_ops = {
.init_out = sndio_init_out,
.fini_out = sndio_fini_out,
.enable_out = sndio_enable_out,
.write = audio_generic_write,
.buffer_get_free = sndio_buffer_get_free,
.get_buffer_out = sndio_get_buffer_out,
.put_buffer_out = sndio_put_buffer_out,
.init_in = sndio_init_in,
.fini_in = sndio_fini_in,
.read = audio_generic_read,
.enable_in = sndio_enable_in,
.get_buffer_in = sndio_get_buffer_in,
.put_buffer_in = sndio_put_buffer_in,
};
static struct audio_driver sndio_audio_driver = {
.name = "sndio",
.descr = "sndio https://sndio.org",
.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);

View File

@ -287,8 +287,8 @@ select the fuzz target. Then, the qtest client is initialized. If the target
requires qos, qgraph is set up and the QOM/LIBQOS modules are initialized.
Then the QGraph is walked and the QEMU cmd_line is determined and saved.
After this, the ``vl.c:qemu_main`` is called to set up the guest. There are
target-specific hooks that can be called before and after qemu_main, for
After this, the ``vl.c:main`` is called to set up the guest. There are
target-specific hooks that can be called before and after main, for
additional setup(e.g. PCI setup, or VM snapshotting).
``LLVMFuzzerTestOneInput``: Uses qtest/qos functions to act based on the fuzz

View File

@ -84,7 +84,7 @@ void ati_2d_blt(ATIVGAState *s)
DPRINTF("%d %d %d, %d %d %d, (%d,%d) -> (%d,%d) %dx%d %c %c\n",
s->regs.src_offset, s->regs.dst_offset, s->regs.default_offset,
s->regs.src_pitch, s->regs.dst_pitch, s->regs.default_pitch,
s->regs.src_x, s->regs.src_y, s->regs.dst_x, s->regs.dst_y,
s->regs.src_x, s->regs.src_y, dst_x, dst_y,
s->regs.dst_width, s->regs.dst_height,
(s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? '>' : '<'),
(s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? 'v' : '^'));
@ -180,11 +180,11 @@ void ati_2d_blt(ATIVGAState *s)
dst_stride /= sizeof(uint32_t);
DPRINTF("pixman_fill(%p, %d, %d, %d, %d, %d, %d, %x)\n",
dst_bits, dst_stride, bpp,
s->regs.dst_x, s->regs.dst_y,
dst_x, dst_y,
s->regs.dst_width, s->regs.dst_height,
filler);
pixman_fill((uint32_t *)dst_bits, dst_stride, bpp,
s->regs.dst_x, s->regs.dst_y,
dst_x, dst_y,
s->regs.dst_width, s->regs.dst_height,
filler);
if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr &&

View File

@ -515,9 +515,10 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
scanout = &g->parent_obj.scanout[i];
if (scanout->resource_id == res->resource_id &&
rf.r.x >= scanout->x && rf.r.y >= scanout->y &&
rf.r.x + rf.r.width <= scanout->x + scanout->width &&
rf.r.y + rf.r.height <= scanout->y + scanout->height &&
rf.r.x < scanout->x + scanout->width &&
rf.r.x + rf.r.width >= scanout->x &&
rf.r.y < scanout->y + scanout->height &&
rf.r.y + rf.r.height >= scanout->y &&
console_has_gl(scanout->con)) {
dpy_gl_update(scanout->con, 0, 0, scanout->width,
scanout->height);

View File

@ -91,6 +91,8 @@ enum usbstring_idx {
#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43
#define USB_CDC_GET_ETHERNET_STATISTIC 0x44
#define USB_CDC_NETWORK_CONNECTION 0x00
#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
#define STATUS_BYTECOUNT 16 /* 8 byte header + data */
@ -640,6 +642,8 @@ struct USBNetState {
uint16_t filter;
uint32_t vendorid;
uint16_t connection;
unsigned int out_ptr;
uint8_t out_buf[2048];
@ -647,6 +651,7 @@ struct USBNetState {
uint8_t in_buf[2048];
USBEndpoint *intr;
USBEndpoint *bulk_in;
char usbstring_mac[13];
NICState *nic;
@ -1121,6 +1126,12 @@ static void usb_net_handle_control(USBDevice *dev, USBPacket *p,
#endif
break;
case ClassInterfaceOutRequest | USB_CDC_SET_ETHERNET_PACKET_FILTER:
if (is_rndis(s)) {
goto fail;
}
break;
default:
fail:
fprintf(stderr, "usbnet: failed control transaction: "
@ -1133,18 +1144,28 @@ static void usb_net_handle_control(USBDevice *dev, USBPacket *p,
static void usb_net_handle_statusin(USBNetState *s, USBPacket *p)
{
le32 buf[2];
le32 rbuf[2];
uint16_t ebuf[4];
if (p->iov.size < 8) {
p->status = USB_RET_STALL;
return;
}
buf[0] = cpu_to_le32(1);
buf[1] = cpu_to_le32(0);
usb_packet_copy(p, buf, 8);
if (!s->rndis_resp.tqh_first) {
p->status = USB_RET_NAK;
if (is_rndis(s)) {
rbuf[0] = cpu_to_le32(1);
rbuf[1] = cpu_to_le32(0);
usb_packet_copy(p, rbuf, 8);
if (!s->rndis_resp.tqh_first) {
p->status = USB_RET_NAK;
}
} else {
ebuf[0] =
cpu_to_be16(ClassInterfaceRequest | USB_CDC_NETWORK_CONNECTION);
ebuf[1] = cpu_to_le16(s->connection);
ebuf[2] = cpu_to_le16(1);
ebuf[3] = cpu_to_le16(0);
usb_packet_copy(p, ebuf, 8);
}
#ifdef TRAFFIC_DEBUG
@ -1204,7 +1225,7 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
s->out_ptr += sz;
if (!is_rndis(s)) {
if (p->iov.size < 64) {
if (p->iov.size % 64 || p->iov.size == 0) {
qemu_send_packet(qemu_get_queue(s->nic), s->out_buf, s->out_ptr);
s->out_ptr = 0;
}
@ -1317,6 +1338,7 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz
memcpy(in_buf, buf, size);
s->in_len = total_size;
s->in_ptr = 0;
usb_wakeup(s->bulk_in, 0);
return size;
}
@ -1358,7 +1380,9 @@ static void usb_net_realize(USBDevice *dev, Error **errp)
s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */;
s->filter = 0;
s->vendorid = 0x1234;
s->connection = 1; /* Connected */
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
s->bulk_in = usb_ep_get(dev, USB_TOKEN_IN, 2);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,

View File

@ -177,6 +177,37 @@ static const USBDesc desc = {
.str = desc_strings,
};
static void usb_msd_packet_complete(MSDState *s)
{
USBPacket *p = s->packet;
/*
* Set s->packet to NULL before calling usb_packet_complete
* because another request may be issued before
* usb_packet_complete returns.
*/
trace_usb_msd_packet_complete();
s->packet = NULL;
usb_packet_complete(&s->dev, p);
}
static void usb_msd_fatal_error(MSDState *s)
{
trace_usb_msd_fatal_error();
if (s->packet) {
s->packet->status = USB_RET_STALL;
usb_msd_packet_complete(s);
}
/*
* Guest messed up up device state with illegal requests. Go
* ignore any requests until the guests resets the device (and
* brings it into a known state that way).
*/
s->needs_reset = true;
}
static void usb_msd_copy_data(MSDState *s, USBPacket *p)
{
uint32_t len;
@ -208,24 +239,16 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p)
memset(&s->csw, 0, sizeof(s->csw));
}
static void usb_msd_packet_complete(MSDState *s)
{
USBPacket *p = s->packet;
/* Set s->packet to NULL before calling usb_packet_complete
because another request may be issued before
usb_packet_complete returns. */
trace_usb_msd_packet_complete();
s->packet = NULL;
usb_packet_complete(&s->dev, p);
}
void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
{
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet;
assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
if ((s->mode == USB_MSDM_DATAOUT) != (req->cmd.mode == SCSI_XFER_TO_DEV)) {
usb_msd_fatal_error(s);
return;
}
s->scsi_len = len;
s->scsi_off = 0;
if (p) {
@ -315,6 +338,8 @@ void usb_msd_handle_reset(USBDevice *dev)
memset(&s->csw, 0, sizeof(s->csw));
s->mode = USB_MSDM_CBW;
s->needs_reset = false;
}
static void usb_msd_handle_control(USBDevice *dev, USBPacket *p,
@ -380,6 +405,11 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
SCSIDevice *scsi_dev;
uint32_t len;
if (s->needs_reset) {
p->status = USB_RET_STALL;
return;
}
switch (p->pid) {
case USB_TOKEN_OUT:
if (devep != 2)

View File

@ -571,6 +571,11 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed)
addr = ed->head & OHCI_DPTR_MASK;
if (addr == 0) {
ohci_die(ohci);
return 1;
}
if (ohci_read_iso_td(ohci, addr, &iso_td)) {
trace_usb_ohci_iso_td_read_failed(addr);
ohci_die(ohci);
@ -859,6 +864,11 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
int completion;
addr = ed->head & OHCI_DPTR_MASK;
if (addr == 0) {
ohci_die(ohci);
return 1;
}
/* See if this TD has already been submitted to the device. */
completion = (addr == ohci->async_td);
if (completion && !ohci->async_complete) {

View File

@ -463,6 +463,12 @@ static void xhci_mfwrap_timer(void *opaque)
xhci_mfwrap_update(xhci);
}
static void xhci_die(XHCIState *xhci)
{
xhci->usbsts |= USBSTS_HCE;
DPRINTF("xhci: asserted controller error\n");
}
static inline dma_addr_t xhci_addr64(uint32_t low, uint32_t high)
{
if (sizeof(dma_addr_t) == 4) {
@ -488,7 +494,14 @@ static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr,
assert((len % sizeof(uint32_t)) == 0);
dma_memory_read(xhci->as, addr, buf, len, MEMTXATTRS_UNSPECIFIED);
if (dma_memory_read(xhci->as, addr, buf, len,
MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n",
__func__);
memset(buf, 0xff, len);
xhci_die(xhci);
return;
}
for (i = 0; i < (len / sizeof(uint32_t)); i++) {
buf[i] = le32_to_cpu(buf[i]);
@ -496,7 +509,7 @@ static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr,
}
static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr,
uint32_t *buf, size_t len)
const uint32_t *buf, size_t len)
{
int i;
uint32_t tmp[5];
@ -508,7 +521,13 @@ static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr,
for (i = 0; i < n; i++) {
tmp[i] = cpu_to_le32(buf[i]);
}
dma_memory_write(xhci->as, addr, tmp, len, MEMTXATTRS_UNSPECIFIED);
if (dma_memory_write(xhci->as, addr, tmp, len,
MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n",
__func__);
xhci_die(xhci);
return;
}
}
static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
@ -593,12 +612,6 @@ static inline int xhci_running(XHCIState *xhci)
return !(xhci->usbsts & USBSTS_HCH);
}
static void xhci_die(XHCIState *xhci)
{
xhci->usbsts |= USBSTS_HCE;
DPRINTF("xhci: asserted controller error\n");
}
static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v)
{
XHCIInterrupter *intr = &xhci->intr[v];
@ -619,7 +632,12 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v)
ev_trb.status, ev_trb.control);
addr = intr->er_start + TRB_SIZE*intr->er_ep_idx;
dma_memory_write(xhci->as, addr, &ev_trb, TRB_SIZE, MEMTXATTRS_UNSPECIFIED);
if (dma_memory_write(xhci->as, addr, &ev_trb, TRB_SIZE,
MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n",
__func__);
xhci_die(xhci);
}
intr->er_ep_idx++;
if (intr->er_ep_idx >= intr->er_size) {
@ -680,8 +698,12 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
while (1) {
TRBType type;
dma_memory_read(xhci->as, ring->dequeue, trb, TRB_SIZE,
MEMTXATTRS_UNSPECIFIED);
if (dma_memory_read(xhci->as, ring->dequeue, trb, TRB_SIZE,
MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n",
__func__);
return 0;
}
trb->addr = ring->dequeue;
trb->ccs = ring->ccs;
le64_to_cpus(&trb->parameter);
@ -798,8 +820,14 @@ static void xhci_er_reset(XHCIState *xhci, int v)
xhci_die(xhci);
return;
}
dma_memory_read(xhci->as, erstba, &seg, sizeof(seg),
MEMTXATTRS_UNSPECIFIED);
if (dma_memory_read(xhci->as, erstba, &seg, sizeof(seg),
MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n",
__func__);
xhci_die(xhci);
return;
}
le32_to_cpus(&seg.addr_low);
le32_to_cpus(&seg.addr_high);
le32_to_cpus(&seg.size);
@ -992,7 +1020,9 @@ static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx,
}
sctx = epctx->pstreams + streamid;
} else {
FIXME("secondary streams not implemented yet");
fprintf(stderr, "xhci: FIXME: secondary streams not implemented yet");
*cc_error = CC_INVALID_STREAM_TYPE_ERROR;
return NULL;
}
if (sctx->sct == -1) {
@ -2415,8 +2445,12 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
/* TODO: actually implement real values here */
bw_ctx[0] = 0;
memset(&bw_ctx[1], 80, xhci->numports); /* 80% */
dma_memory_write(xhci->as, ctx, bw_ctx, sizeof(bw_ctx),
MEMTXATTRS_UNSPECIFIED);
if (dma_memory_write(xhci->as, ctx, bw_ctx, sizeof(bw_ctx),
MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory write failed!\n",
__func__);
return CC_TRB_ERROR;
}
return CC_SUCCESS;
}

View File

@ -263,6 +263,7 @@ usb_msd_packet_complete(void) ""
usb_msd_cmd_submit(unsigned lun, unsigned tag, unsigned flags, unsigned len, unsigned data_len) "lun %u, tag 0x%x, flags 0x%08x, len %d, data-len %d"
usb_msd_cmd_complete(unsigned status, unsigned tag) "status %d, tag 0x%x"
usb_msd_cmd_cancel(unsigned tag) "tag 0x%x"
usb_msd_fatal_error(void) ""
# dev-uas.c
usb_uas_reset(int addr) "dev %d"

View File

@ -40,6 +40,7 @@ struct MSDState {
bool removable;
bool commandlog;
SCSIDevice *scsi_dev;
bool needs_reset;
};
typedef struct MSDState MSDState;

View File

@ -5,6 +5,7 @@
#ifndef QEMU_MAIN_H
#define QEMU_MAIN_H
int qemu_main(int argc, char **argv, char **envp);
int qemu_default_main(void);
extern int (*qemu_main)(void);
#endif /* QEMU_MAIN_H */

View File

@ -284,23 +284,10 @@ bool qemu_in_main_thread(void);
* Please refer to include/block/block-global-state.h for more
* information about GS API.
*/
#ifdef CONFIG_COCOA
/*
* When using the Cocoa UI, addRemovableDevicesMenuItems() is called from
* a thread different from the QEMU main thread and can not take the BQL,
* triggering this assertions in the block layer (commit 0439c5a462).
* As the Cocoa fix is not trivial, disable this assertion for the v7.0.0
* release (when using Cocoa); we will restore it immediately after the
* release.
* This issue is tracked as https://gitlab.com/qemu-project/qemu/-/issues/926
*/
#define GLOBAL_STATE_CODE()
#else
#define GLOBAL_STATE_CODE() \
do { \
assert(qemu_in_main_thread()); \
} while (0)
#endif /* CONFIG_COCOA */
/*
* Mark and check that the function is part of the I/O API.

View File

@ -102,7 +102,7 @@ void qemu_boot_set(const char *boot_order, Error **errp);
bool defaults_enabled(void);
void qemu_init(int argc, char **argv, char **envp);
void qemu_init(int argc, char **argv);
int qemu_main_loop(void);
void qemu_cleanup(void);

View File

@ -70,6 +70,7 @@ void hmp_mouse_set(Monitor *mon, const QDict *qdict);
/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
constants) */
#define QEMU_KEY_ESC1(c) ((c) | 0xe100)
#define QEMU_KEY_TAB 0x0009
#define QEMU_KEY_BACKSPACE 0x007f
#define QEMU_KEY_UP QEMU_KEY_ESC1('A')
#define QEMU_KEY_DOWN QEMU_KEY_ESC1('B')

View File

@ -589,12 +589,6 @@ endif
cocoa = dependency('appleframeworks', modules: ['Cocoa', 'CoreVideo'],
required: get_option('cocoa'))
if cocoa.found() and get_option('sdl').enabled()
error('Cocoa and SDL cannot be enabled at the same time')
endif
if cocoa.found() and get_option('gtk').enabled()
error('Cocoa and GTK+ cannot be enabled at the same time')
endif
vmnet = dependency('appleframeworks', modules: 'vmnet', required: get_option('vmnet'))
if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
@ -681,6 +675,11 @@ if not get_option('jack').auto() or have_system
jack = dependency('jack', required: get_option('jack'),
method: 'pkg-config', kwargs: static_kwargs)
endif
sndio = not_found
if not get_option('sndio').auto() or have_system
sndio = dependency('sndio', required: get_option('sndio'),
method: 'pkg-config', kwargs: static_kwargs)
endif
spice_protocol = not_found
if not get_option('spice_protocol').auto() or have_system
@ -921,7 +920,7 @@ if not get_option('brlapi').auto() or have_system
endif
sdl = not_found
if not get_option('sdl').auto() or (have_system and not cocoa.found())
if not get_option('sdl').auto() or have_system
sdl = dependency('sdl2', required: get_option('sdl'), kwargs: static_kwargs)
sdl_image = not_found
endif
@ -1187,7 +1186,7 @@ endif
gtk = not_found
gtkx11 = not_found
vte = not_found
if not get_option('gtk').auto() or (have_system and not cocoa.found())
if not get_option('gtk').auto() or have_system
gtk = dependency('gtk+-3.0', version: '>=3.22.0',
method: 'pkg-config',
required: get_option('gtk'),
@ -1597,6 +1596,7 @@ if have_system
'oss': oss.found(),
'pa': pulse.found(),
'sdl': sdl.found(),
'sndio': sndio.found(),
}
foreach k, v: audio_drivers_available
config_host_data.set('CONFIG_AUDIO_' + k.to_upper(), v)
@ -1604,7 +1604,7 @@ if have_system
# Default to native drivers first, OSS second, SDL third
audio_drivers_priority = \
[ 'pa', 'coreaudio', 'dsound', 'oss' ] + \
[ 'pa', 'coreaudio', 'dsound', 'sndio', 'oss' ] + \
(targetos == 'linux' ? [] : [ 'sdl' ])
audio_drivers_default = []
foreach k: audio_drivers_priority
@ -3928,6 +3928,7 @@ if vnc.found()
endif
if targetos not in ['darwin', 'haiku', 'windows']
summary_info += {'OSS support': oss}
summary_info += {'sndio support': sndio}
elif targetos == 'darwin'
summary_info += {'CoreAudio support': coreaudio}
elif targetos == 'windows'

View File

@ -21,7 +21,7 @@ option('tls_priority', type : 'string', value : 'NORMAL',
option('default_devices', type : 'boolean', value : true,
description: 'Include a default selection of devices in emulators')
option('audio_drv_list', type: 'array', value: ['default'],
choices: ['alsa', 'coreaudio', 'default', 'dsound', 'jack', 'oss', 'pa', 'sdl'],
choices: ['alsa', 'coreaudio', 'default', 'dsound', 'jack', 'oss', 'pa', 'sdl', 'sndio'],
description: 'Set audio driver list')
option('block_drv_rw_whitelist', type : 'string', value : '',
description: 'set block driver read-write whitelist (by default affects only QEMU, not tools like qemu-img)')
@ -240,6 +240,8 @@ option('oss', type: 'feature', value: 'auto',
description: 'OSS sound support')
option('pa', type: 'feature', value: 'auto',
description: 'PulseAudio sound support')
option('sndio', type: 'feature', value: 'auto',
description: 'sndio sound support')
option('vhost_kernel', type: 'feature', value: 'auto',
description: 'vhost kernel backend support')

View File

@ -106,6 +106,28 @@
'*out': 'AudiodevAlsaPerDirectionOptions',
'*threshold': 'uint32' } }
##
# @AudiodevSndioOptions:
#
# Options of the sndio audio backend.
#
# @in: options of the capture stream
#
# @out: options of the playback stream
#
# @dev: the name of the sndio device to use (default 'default')
#
# @latency: play buffer size (in microseconds)
#
# Since: 7.2
##
{ 'struct': 'AudiodevSndioOptions',
'data': {
'*in': 'AudiodevPerDirectionOptions',
'*out': 'AudiodevPerDirectionOptions',
'*dev': 'str',
'*latency': 'uint32'} }
##
# @AudiodevCoreaudioPerDirectionOptions:
#
@ -387,7 +409,7 @@
##
{ 'enum': 'AudiodevDriver',
'data': [ 'none', 'alsa', 'coreaudio', 'dbus', 'dsound', 'jack', 'oss', 'pa',
'sdl', 'spice', 'wav' ] }
'sdl', 'sndio', 'spice', 'wav' ] }
##
# @Audiodev:
@ -418,5 +440,6 @@
'oss': 'AudiodevOssOptions',
'pa': 'AudiodevPaOptions',
'sdl': 'AudiodevSdlOptions',
'sndio': 'AudiodevSndioOptions',
'spice': 'AudiodevGenericOptions',
'wav': 'AudiodevWavOptions' } }

View File

@ -769,6 +769,9 @@ DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev,
"-audiodev sdl,id=id[,prop[=value][,...]]\n"
" in|out.buffer-count= number of buffers\n"
#endif
#ifdef CONFIG_AUDIO_SNDIO
"-audiodev sndio,id=id[,prop[=value][,...]]\n"
#endif
#ifdef CONFIG_SPICE
"-audiodev spice,id=id[,prop[=value][,...]]\n"
#endif
@ -935,6 +938,19 @@ SRST
``in|out.buffer-count=count``
Sets the count of the buffers.
``-audiodev sndio,id=id[,prop[=value][,...]]``
Creates a backend using SNDIO. This backend is available on
OpenBSD and most other Unix-like systems.
Sndio specific options are:
``in|out.dev=device``
Specify the sndio device to use for input and/or output. Default
is ``default``.
``in|out.latency=usecs``
Sets the desired period length in microseconds.
``-audiodev spice,id=id[,prop[=value][,...]]``
Creates a backend that sends audio through SPICE. This backend
requires ``-spice`` and automatically selected in that case, so

View File

@ -1,7 +1,7 @@
# This file is generated by meson-buildoptions.py, do not edit!
meson_options_help() {
printf "%s\n" ' --audio-drv-list=CHOICES Set audio driver list [default] (choices:'
printf "%s\n" ' alsa/coreaudio/default/dsound/jack/oss/pa/sdl)'
printf "%s\n" ' --audio-drv-list=CHOICES Set audio driver list [default] (choices: alsa/co'
printf "%s\n" ' reaudio/default/dsound/jack/oss/pa/sdl/sndio)'
printf "%s\n" ' --block-drv-ro-whitelist=VALUE'
printf "%s\n" ' set block driver read-only whitelist (by default'
printf "%s\n" ' affects only QEMU, not tools like qemu-img)'
@ -144,6 +144,7 @@ meson_options_help() {
printf "%s\n" ' slirp-smbd use smbd (at path --smbd=*) in slirp networking'
printf "%s\n" ' smartcard CA smartcard emulation support'
printf "%s\n" ' snappy snappy compression support'
printf "%s\n" ' sndio sndio sound support'
printf "%s\n" ' sparse sparse checker'
printf "%s\n" ' spice Spice server support'
printf "%s\n" ' spice-protocol Spice protocol support'
@ -393,6 +394,8 @@ _meson_option_parse() {
--disable-smartcard) printf "%s" -Dsmartcard=disabled ;;
--enable-snappy) printf "%s" -Dsnappy=enabled ;;
--disable-snappy) printf "%s" -Dsnappy=disabled ;;
--enable-sndio) printf "%s" -Dsndio=enabled ;;
--disable-sndio) printf "%s" -Dsndio=disabled ;;
--enable-sparse) printf "%s" -Dsparse=enabled ;;
--disable-sparse) printf "%s" -Dsparse=disabled ;;
--sphinx-build=*) quote_sh "-Dsphinx_build=$2" ;;

View File

@ -30,20 +30,20 @@
#include <SDL.h>
#endif
int qemu_main(int argc, char **argv, char **envp)
int qemu_default_main(void)
{
int status;
qemu_init(argc, argv, envp);
status = qemu_main_loop();
qemu_cleanup();
return status;
}
#ifndef CONFIG_COCOA
int (*qemu_main)(void) = qemu_default_main;
int main(int argc, char **argv)
{
return qemu_main(argc, argv, NULL);
qemu_init(argc, argv);
return qemu_main();
}
#endif

View File

@ -2605,7 +2605,7 @@ void qmp_x_exit_preconfig(Error **errp)
}
}
void qemu_init(int argc, char **argv, char **envp)
void qemu_init(int argc, char **argv)
{
QemuOpts *opts;
QemuOpts *icount_opts = NULL, *accel_opts = NULL;

View File

@ -218,7 +218,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
g_free(pretty_cmd_line);
}
qemu_init(result.we_wordc, result.we_wordv, NULL);
qemu_init(result.we_wordc, result.we_wordv);
/* re-enable the rcu atfork, which was previously disabled in qemu_init */
rcu_enable_atfork();

View File

@ -1,5 +1,6 @@
#include "qemu/osdep.h"
#include "ui/clipboard.h"
#include "trace.h"
static NotifierList clipboard_notifiers =
NOTIFIER_LIST_INITIALIZER(clipboard_notifiers);
@ -43,17 +44,23 @@ void qemu_clipboard_peer_release(QemuClipboardPeer *peer,
bool qemu_clipboard_check_serial(QemuClipboardInfo *info, bool client)
{
bool ok;
if (!info->has_serial ||
!cbinfo[info->selection] ||
!cbinfo[info->selection]->has_serial) {
trace_clipboard_check_serial(-1, -1, true);
return true;
}
if (client) {
return cbinfo[info->selection]->serial >= info->serial;
ok = info->serial >= cbinfo[info->selection]->serial;
} else {
return cbinfo[info->selection]->serial > info->serial;
ok = info->serial > cbinfo[info->selection]->serial;
}
trace_clipboard_check_serial(cbinfo[info->selection]->serial, info->serial, ok);
return ok;
}
void qemu_clipboard_update(QemuClipboardInfo *info)
@ -132,7 +139,14 @@ void qemu_clipboard_request(QemuClipboardInfo *info,
void qemu_clipboard_reset_serial(void)
{
QemuClipboardNotify notify = { .type = QEMU_CLIPBOARD_RESET_SERIAL };
int i;
for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
QemuClipboardInfo *info = qemu_clipboard_info(i);
if (info) {
info->serial = 0;
}
}
notifier_list_notify(&clipboard_notifiers, &notify);
}

View File

@ -100,13 +100,9 @@ static int cursor_hide = 1;
static int left_command_key_enabled = 1;
static bool swap_opt_cmd;
static int gArgc;
static char **gArgv;
static bool stretch_video;
static NSTextField *pauseLabel;
static QemuSemaphore display_init_sem;
static QemuSemaphore app_started_sem;
static bool allow_events;
static NSInteger cbchangecount = -1;
@ -597,7 +593,7 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
/*
* Don't try to tell QEMU about UI information in the application
* startup phase -- we haven't yet registered dcl with the QEMU UI
* layer, and also trying to take the iothread lock would deadlock.
* layer.
* When cocoa_display_init() does register the dcl, the UI layer
* will call cocoa_switch(), which will call updateUIInfo, so
* we don't lose any information here.
@ -790,16 +786,6 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
- (bool) handleEvent:(NSEvent *)event
{
if(!allow_events) {
/*
* Just let OSX have all events that arrive before
* applicationDidFinishLaunching.
* This avoids a deadlock on the iothread lock, which cocoa_display_init()
* will not drop until after the app_started_sem is posted. (In theory
* there should not be any such events, but OSX Catalina now emits some.)
*/
return false;
}
return bool_with_iothread_lock(^{
return [self handleEventLocked:event];
});
@ -1287,8 +1273,6 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
{
COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n");
allow_events = true;
/* Tell cocoa_display_init to proceed */
qemu_sem_post(&app_started_sem);
}
- (void)applicationWillTerminate:(NSNotification *)aNotification
@ -1919,92 +1903,45 @@ static void cocoa_clipboard_request(QemuClipboardInfo *info,
/*
* The startup process for the OSX/Cocoa UI is complicated, because
* OSX insists that the UI runs on the initial main thread, and so we
* need to start a second thread which runs the vl.c qemu_main():
*
* Initial thread: 2nd thread:
* need to start a second thread which runs the qemu_default_main():
* in main():
* create qemu-main thread
* wait on display_init semaphore
* call qemu_main()
* ...
* in cocoa_display_init():
* post the display_init semaphore
* wait on app_started semaphore
* create application, menus, etc
* enter OSX run loop
* in applicationDidFinishLaunching:
* post app_started semaphore
* tell main thread to fullscreen if needed
* [...]
* run qemu main-loop
*
* We do this in two stages so that we don't do the creation of the
* GUI application menus and so on for command line options like --help
* where we want to just print text to stdout and exit immediately.
* in cocoa_display_init():
* assign cocoa_main to qemu_main
* create application, menus, etc
* in cocoa_main():
* create qemu-main thread
* enter OSX run loop
*/
static void *call_qemu_main(void *opaque)
{
int status;
COCOA_DEBUG("Second thread: calling qemu_main()\n");
status = qemu_main(gArgc, gArgv, *_NSGetEnviron());
COCOA_DEBUG("Second thread: qemu_main() returned, exiting\n");
COCOA_DEBUG("Second thread: calling qemu_default_main()\n");
qemu_mutex_lock_iothread();
status = qemu_default_main();
qemu_mutex_unlock_iothread();
COCOA_DEBUG("Second thread: qemu_default_main() returned, exiting\n");
[cbowner release];
exit(status);
}
int main (int argc, char **argv) {
static int cocoa_main()
{
QemuThread thread;
COCOA_DEBUG("Entered main()\n");
gArgc = argc;
gArgv = argv;
qemu_sem_init(&display_init_sem, 0);
qemu_sem_init(&app_started_sem, 0);
COCOA_DEBUG("Entered %s()\n", __func__);
qemu_mutex_unlock_iothread();
qemu_thread_create(&thread, "qemu_main", call_qemu_main,
NULL, QEMU_THREAD_DETACHED);
COCOA_DEBUG("Main thread: waiting for display_init_sem\n");
qemu_sem_wait(&display_init_sem);
COCOA_DEBUG("Main thread: initializing app\n");
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// Pull this console process up to being a fully-fledged graphical
// app with a menubar and Dock icon
ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
[QemuApplication sharedApplication];
create_initial_menus();
/*
* Create the menu entries which depend on QEMU state (for consoles
* and removeable devices). These make calls back into QEMU functions,
* which is OK because at this point we know that the second thread
* holds the iothread lock and is synchronously waiting for us to
* finish.
*/
add_console_menu_entries();
addRemovableDevicesMenuItems();
// Create an Application controller
QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
[NSApp setDelegate:appController];
// Start the main event loop
COCOA_DEBUG("Main thread: entering OSX run loop\n");
[NSApp run];
COCOA_DEBUG("Main thread: left OSX run loop, exiting\n");
COCOA_DEBUG("Main thread: left OSX run loop, which should never happen\n");
[appController release];
[pool release];
return 0;
abort();
}
@ -2083,25 +2020,42 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
/* Tell main thread to go ahead and create the app and enter the run loop */
qemu_sem_post(&display_init_sem);
qemu_sem_wait(&app_started_sem);
COCOA_DEBUG("cocoa_display_init: app start completed\n");
qemu_main = cocoa_main;
// Pull this console process up to being a fully-fledged graphical
// app with a menubar and Dock icon
ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
[QemuApplication sharedApplication];
create_initial_menus();
/*
* Create the menu entries which depend on QEMU state (for consoles
* and removeable devices). These make calls back into QEMU functions,
* which is OK because at this point we know that the second thread
* holds the iothread lock and is synchronously waiting for us to
* finish.
*/
add_console_menu_entries();
addRemovableDevicesMenuItems();
// Create an Application controller
QemuCocoaAppController *controller = [[QemuCocoaAppController alloc] init];
[NSApp setDelegate:controller];
QemuCocoaAppController *controller = (QemuCocoaAppController *)[[NSApplication sharedApplication] delegate];
/* if fullscreen mode is to be used */
if (opts->has_full_screen && opts->full_screen) {
dispatch_async(dispatch_get_main_queue(), ^{
[NSApp activateIgnoringOtherApps: YES];
[controller toggleFullScreen: nil];
});
[NSApp activateIgnoringOtherApps: YES];
[controller toggleFullScreen: nil];
}
if (opts->u.cocoa.has_full_grab && opts->u.cocoa.full_grab) {
dispatch_async(dispatch_get_main_queue(), ^{
[controller setFullGrab: nil];
});
[controller setFullGrab: nil];
}
if (opts->has_show_cursor && opts->show_cursor) {
@ -2121,6 +2075,8 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
qemu_event_init(&cbevent, false);
cbowner = [[QemuCocoaPasteboardTypeOwner alloc] init];
qemu_clipboard_peer_register(&cbpeer);
[pool release];
}
static QemuDisplay qemu_display_cocoa = {

View File

@ -304,8 +304,8 @@ static bool png_save(int fd, pixman_image_t *image, Error **errp)
{
int width = pixman_image_get_width(image);
int height = pixman_image_get_height(image);
g_autofree png_struct *png_ptr = NULL;
g_autofree png_info *info_ptr = NULL;
png_struct *png_ptr;
png_info *info_ptr;
g_autoptr(pixman_image_t) linebuf =
qemu_pixman_linebuf_create(PIXMAN_a8r8g8b8, width);
uint8_t *buf = (uint8_t *)pixman_image_get_data(linebuf);
@ -346,7 +346,6 @@ static bool png_save(int fd, pixman_image_t *image, Error **errp)
qemu_pixman_linebuf_fill(linebuf, image, width, 0, y);
png_write_row(png_ptr, buf);
}
qemu_pixman_image_unref(linebuf);
png_write_end(png_ptr, NULL);
@ -1368,6 +1367,7 @@ static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
[Q_KEY_CODE_PGUP] = QEMU_KEY_PAGEUP,
[Q_KEY_CODE_PGDN] = QEMU_KEY_PAGEDOWN,
[Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
[Q_KEY_CODE_TAB] = QEMU_KEY_TAB,
[Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
};

View File

@ -127,15 +127,20 @@ xkeymap_vendor(const char *name) "vendor '%s'"
xkeymap_keycodes(const char *name) "keycodes '%s'"
xkeymap_keymap(const char *name) "keymap '%s'"
# clipboard.c
clipboard_check_serial(int cur, int recv, bool ok) "cur:%d recv:%d %d"
# vdagent.c
vdagent_open(void) ""
vdagent_close(void) ""
vdagent_disconnect(void) ""
vdagent_send(const char *name) "msg %s"
vdagent_send_empty_clipboard(void) ""
vdagent_recv_chunk(uint32_t size) "size %d"
vdagent_recv_msg(const char *name, uint32_t size) "msg %s, size %d"
vdagent_peer_cap(const char *name) "cap %s"
vdagent_cb_grab_selection(const char *name) "selection %s"
vdagent_cb_grab_discard(const char *name, int cur, int recv) "selection %s, cur:%d recv:%d"
vdagent_cb_grab_type(const char *name) "type %s"
vdagent_cb_serial_discard(uint32_t current, uint32_t received) "current=%u, received=%u"

View File

@ -471,7 +471,7 @@ static void vdagent_clipboard_reset_serial(VDAgentChardev *vd)
/* reopen the agent connection to reset the serial state */
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
/* OPENED again after the guest disconnected, see set_fe_open */
}
static void vdagent_clipboard_notify(Notifier *notifier, void *data)
@ -533,6 +533,8 @@ static void vdagent_clipboard_recv_grab(VDAgentChardev *vd, uint8_t s, uint32_t
info->has_serial = true;
info->serial = *(uint32_t *)data;
if (info->serial < vd->last_serial[s]) {
trace_vdagent_cb_grab_discard(GET_NAME(sel_name, s),
vd->last_serial[s], info->serial);
/* discard lower-ordering guest grab */
return;
}
@ -717,8 +719,10 @@ static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
if (have_mouse(vd) && vd->mouse_hs) {
qemu_input_handler_activate(vd->mouse_hs);
}
memset(vd->last_serial, 0, sizeof(vd->last_serial));
if (have_clipboard(vd) && vd->cbpeer.notifier.notify == NULL) {
memset(vd->last_serial, 0, sizeof(vd->last_serial));
vd->cbpeer.name = "vdagent";
vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
vd->cbpeer.request = vdagent_clipboard_request;
@ -853,6 +857,8 @@ static void vdagent_chr_accept_input(Chardev *chr)
static void vdagent_disconnect(VDAgentChardev *vd)
{
trace_vdagent_disconnect();
buffer_reset(&vd->outbuf);
vdagent_reset_bufs(vd);
vd->caps = 0;
@ -869,6 +875,9 @@ static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open)
{
if (!fe_open) {
trace_vdagent_close();
/* To reset_serial, we CLOSED our side. Make sure the other end knows we
* are ready again. */
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
return;
}