From 652983299b4b18cdf26414b0ba468c5dd166adc7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 21 Nov 2011 23:50:36 +0100 Subject: [PATCH 01/58] XXX dont dump core on sigabort --- linux-user/signal.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/signal.c b/linux-user/signal.c index 96e86c0a29..d422aebffc 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -443,6 +443,10 @@ static void QEMU_NORETURN force_sig(int target_sig) trace_user_force_sig(env, target_sig, host_sig); gdb_signalled(env, target_sig); + if (target_sig == 6) { + goto no_core; + } + /* dump core if supported by target binary format */ if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) { stop_all_tasks(); @@ -460,6 +464,8 @@ static void QEMU_NORETURN force_sig(int target_sig) target_sig, strsignal(host_sig), "core dumped" ); } +no_core: + /* The proper exit code for dying from an uncaught signal is * -. The kernel doesn't allow exit() or _exit() to pass * a negative value. To get the proper exit code we need to -- 2.51.1 From 611fe6b38bf118be59326f35fd3a066250328311 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Tue, 14 Apr 2009 16:18:44 +0200 Subject: [PATCH 02/58] qemu-0.9.0.cvs-binfmt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes binfmt_misc setup script: - x86_64 is i386-compatible - m68k signature fixed - path to QEMU Signed-off-by: Ulrich Hecht [AF: Update path for qemu-aarch64 for v2.0.0-rc1] Signed-off-by: Andreas Färber --- scripts/qemu-binfmt-conf.sh | 39 ++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index 289b1a3963..75e05268ff 100644 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -27,46 +27,49 @@ case "$cpu" in armv[4-9]*) cpu="arm" ;; + sparc*) + cpu="sparc" + ;; esac # register the interpreter for each cpu except for the native one if [ $cpu != "i386" ] ; then - echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register - echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register + echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register + echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "alpha" ] ; then - echo ':alpha:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-alpha:' > /proc/sys/fs/binfmt_misc/register + echo ':alpha:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-alpha:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "arm" ] ; then - echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register - echo ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register + echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register + echo ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "aarch64" ] ; then - echo ':aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-aarch64:' > /proc/sys/fs/binfmt_misc/register + echo ':aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "sparc" ] ; then - echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register + echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "ppc" ] ; then - echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register + echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "m68k" ] ; then echo 'Please check cpu value and header information for m68k!' - echo ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-m68k:' > /proc/sys/fs/binfmt_misc/register + echo ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-m68k:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "mips" ] ; then # FIXME: We could use the other endianness on a MIPS host. - echo ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsn32:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mipsn32:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsn32el:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsn32el:' > /proc/sys/fs/binfmt_misc/register - echo ':mips64:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips64:' > /proc/sys/fs/binfmt_misc/register - echo ':mips64el:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mips64el:' > /proc/sys/fs/binfmt_misc/register + echo ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register + echo ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register + echo ':mipsn32:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-mipsn32:' > /proc/sys/fs/binfmt_misc/register + echo ':mipsn32el:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mipsn32el:' > /proc/sys/fs/binfmt_misc/register + echo ':mips64:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-mips64:' > /proc/sys/fs/binfmt_misc/register + echo ':mips64el:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mips64el:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "sh" ] ; then - echo ':sh4:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-sh4:' > /proc/sys/fs/binfmt_misc/register - echo ':sh4eb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sh4eb:' > /proc/sys/fs/binfmt_misc/register + echo ':sh4:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-sh4:' > /proc/sys/fs/binfmt_misc/register + echo ':sh4eb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-sh4eb:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "s390x" ] ; then - echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-s390x:' > /proc/sys/fs/binfmt_misc/register + echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-s390x:' > /proc/sys/fs/binfmt_misc/register fi -- 2.51.1 From 6171d82516b151c7d2bac6484c801c45d8de796e Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 14 Apr 2009 16:20:50 +0200 Subject: [PATCH 03/58] qemu-cvs-alsa_bitfield Implements TYPE_INTBITFIELD partially. (required for ALSA support) Signed-off-by: Alexander Graf Signed-off-by: Ulrich Hecht --- include/exec/user/thunk.h | 3 +++ thunk.c | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h index ad1d60266e..4e082a75ba 100644 --- a/include/exec/user/thunk.h +++ b/include/exec/user/thunk.h @@ -37,6 +37,7 @@ typedef enum argtype { TYPE_ARRAY, TYPE_STRUCT, TYPE_OLDDEVT, + TYPE_INTBITFIELD, } argtype; #define MK_PTR(type) TYPE_PTR, type @@ -90,6 +91,7 @@ static inline int thunk_type_size(const argtype *type_ptr, int is_host) case TYPE_SHORT: return 2; case TYPE_INT: + case TYPE_INTBITFIELD: return 4; case TYPE_LONGLONG: case TYPE_ULONGLONG: @@ -152,6 +154,7 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host) case TYPE_SHORT: return 2; case TYPE_INT: + case TYPE_INTBITFIELD: return 4; case TYPE_LONGLONG: case TYPE_ULONGLONG: diff --git a/thunk.c b/thunk.c index f057d86d94..6db7874cdd 100644 --- a/thunk.c +++ b/thunk.c @@ -37,6 +37,7 @@ static inline const argtype *thunk_type_next(const argtype *type_ptr) case TYPE_CHAR: case TYPE_SHORT: case TYPE_INT: + case TYPE_INTBITFIELD: case TYPE_LONGLONG: case TYPE_ULONGLONG: case TYPE_LONG: @@ -139,6 +140,26 @@ const argtype *thunk_convert(void *dst, const void *src, case TYPE_INT: *(uint32_t *)dst = tswap32(*(uint32_t *)src); break; + case TYPE_INTBITFIELD: +#if defined(TARGET_I386) && defined(__powerpc__) + /* powerpc uses the MSB, whereas i386 uses the LSB + * to store the first bit in a field */ + { + unsigned char byte = *(uint8_t *)src; + *(uint8_t *)dst = ((byte >> 7) & 1) + | ((byte >> 5) & 2) + | ((byte >> 3) & 4) + | ((byte >> 1) & 8) + | ((byte << 1) & 16) + | ((byte << 3) & 32) + | ((byte << 5) & 64) + | ((byte << 7) & 128); + /* FIXME: implement for bitfields > 1 byte and other archs */ + } +#else + *(uint32_t *)dst = tswap32(*(uint32_t *)src); +#endif + break; case TYPE_LONGLONG: case TYPE_ULONGLONG: *(uint64_t *)dst = tswap64(*(uint64_t *)src); -- 2.51.1 From b89afe9048994b21e361d9eebe96825d80d1ef56 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 14 Apr 2009 16:23:27 +0200 Subject: [PATCH 04/58] qemu-cvs-alsa_ioctl Implements ALSA ioctls on PPC hosts. Signed-off-by: Alexander Graf Signed-off-by: Ulrich Hecht --- linux-user/ioctls.h | 5 + linux-user/ioctls_alsa.h | 467 ++++++++ linux-user/ioctls_alsa_structs.h | 1740 ++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 2 + linux-user/syscall_types.h | 5 + linux-user/syscall_types_alsa.h | 1336 +++++++++++++++++++++++ 6 files changed, 3555 insertions(+) create mode 100644 linux-user/ioctls_alsa.h create mode 100644 linux-user/ioctls_alsa_structs.h create mode 100644 linux-user/syscall_types_alsa.h diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index e672655100..921d482160 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -319,6 +319,11 @@ IOCTL(VFAT_IOCTL_READDIR_BOTH, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2))) IOCTL(VFAT_IOCTL_READDIR_SHORT, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2))) +/* FIXME: including these on x86 / x86_64 breaks qemu-i386 */ +#ifdef __powerpc__ +#include "ioctls_alsa.h" +#endif + IOCTL(LOOP_SET_FD, 0, TYPE_INT) IOCTL(LOOP_CLR_FD, 0, TYPE_INT) IOCTL(LOOP_SET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info))) diff --git a/linux-user/ioctls_alsa.h b/linux-user/ioctls_alsa.h new file mode 100644 index 0000000000..c2aa542c3b --- /dev/null +++ b/linux-user/ioctls_alsa.h @@ -0,0 +1,467 @@ +#define SNDRV_SEQ_IOCTL_PVERSION _IOR ('S', 0x00, int) +#define SNDRV_SEQ_IOCTL_CLIENT_ID _IOR ('S', 0x01, int) +#define SNDRV_SEQ_IOCTL_SYSTEM_INFO _IOWR('S', 0x02, struct sndrv_seq_system_info) +#define SNDRV_SEQ_IOCTL_RUNNING_MODE _IOWR('S', 0x03, struct sndrv_seq_running_info) +#define SNDRV_SEQ_IOCTL_GET_CLIENT_INFO _IOWR('S', 0x10, struct sndrv_seq_client_info) +#define SNDRV_SEQ_IOCTL_SET_CLIENT_INFO _IOW ('S', 0x11, struct sndrv_seq_client_info) +#define SNDRV_SEQ_IOCTL_CREATE_PORT _IOWR('S', 0x20, struct sndrv_seq_port_info) +#define SNDRV_SEQ_IOCTL_DELETE_PORT _IOW ('S', 0x21, struct sndrv_seq_port_info) +#define SNDRV_SEQ_IOCTL_GET_PORT_INFO _IOWR('S', 0x22, struct sndrv_seq_port_info) +#define SNDRV_SEQ_IOCTL_SET_PORT_INFO _IOW ('S', 0x23, struct sndrv_seq_port_info) +#define SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT _IOW ('S', 0x30, struct sndrv_seq_port_subscribe) +#define SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT _IOW ('S', 0x31, struct sndrv_seq_port_subscribe) +#define SNDRV_SEQ_IOCTL_CREATE_QUEUE _IOWR('S', 0x32, struct sndrv_seq_queue_info) +#define SNDRV_SEQ_IOCTL_DELETE_QUEUE _IOW ('S', 0x33, struct sndrv_seq_queue_info) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_INFO _IOWR('S', 0x34, struct sndrv_seq_queue_info) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_INFO _IOWR('S', 0x35, struct sndrv_seq_queue_info) +#define SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE _IOWR('S', 0x36, struct sndrv_seq_queue_info) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS _IOWR('S', 0x40, struct sndrv_seq_queue_status) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO _IOWR('S', 0x41, struct sndrv_seq_queue_tempo) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO _IOW ('S', 0x42, struct sndrv_seq_queue_tempo) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_OWNER _IOWR('S', 0x43, struct sndrv_seq_queue_owner) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_OWNER _IOW ('S', 0x44, struct sndrv_seq_queue_owner) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER _IOWR('S', 0x45, struct sndrv_seq_queue_timer) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER _IOW ('S', 0x46, struct sndrv_seq_queue_timer) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_SYNC _IOWR('S', 0x53, struct sndrv_seq_queue_sync) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_SYNC _IOW ('S', 0x54, struct sndrv_seq_queue_sync) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT _IOWR('S', 0x49, struct sndrv_seq_queue_client) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT _IOW ('S', 0x4a, struct sndrv_seq_queue_client) +#define SNDRV_SEQ_IOCTL_GET_CLIENT_POOL _IOWR('S', 0x4b, struct sndrv_seq_client_pool) +#define SNDRV_SEQ_IOCTL_SET_CLIENT_POOL _IOW ('S', 0x4c, struct sndrv_seq_client_pool) +#define SNDRV_SEQ_IOCTL_REMOVE_EVENTS _IOW ('S', 0x4e, struct sndrv_seq_remove_events) +#define SNDRV_SEQ_IOCTL_QUERY_SUBS _IOWR('S', 0x4f, struct sndrv_seq_query_subs) +#define SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION _IOWR('S', 0x50, struct sndrv_seq_port_subscribe) +#define SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT _IOWR('S', 0x51, struct sndrv_seq_client_info) +#define SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT _IOWR('S', 0x52, struct sndrv_seq_port_info) +#define SNDRV_DM_FM_IOCTL_INFO _IOR('H', 0x20, snd_dm_fm_info_t) +#define SNDRV_DM_FM_IOCTL_RESET _IO ('H', 0x21) +#define SNDRV_DM_FM_IOCTL_PLAY_NOTE _IOW('H', 0x22, snd_dm_fm_note_t) +#define SNDRV_DM_FM_IOCTL_SET_VOICE _IOW('H', 0x23, snd_dm_fm_voice_t) +#define SNDRV_DM_FM_IOCTL_SET_PARAMS _IOW('H', 0x24, snd_dm_fm_params_t) +#define SNDRV_DM_FM_IOCTL_SET_MODE _IOW('H', 0x25, int) +#define SNDRV_DM_FM_IOCTL_SET_CONNECTION _IOW('H', 0x26, int) +#define SNDRV_DM_FM_OSS_IOCTL_RESET 0x20 +#define SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE 0x21 +#define SNDRV_DM_FM_OSS_IOCTL_SET_VOICE 0x22 +#define SNDRV_DM_FM_OSS_IOCTL_SET_PARAMS 0x23 +#define SNDRV_DM_FM_OSS_IOCTL_SET_MODE 0x24 +#define SNDRV_DM_FM_OSS_IOCTL_SET_OPL 0x25 +#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int) +#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct sndrv_hwdep_info) +#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct sndrv_hwdep_dsp_status) +#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct sndrv_hwdep_dsp_image) +#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int) +#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct sndrv_pcm_info) +#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) +#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct sndrv_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct sndrv_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12) +#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct sndrv_pcm_sw_params) +#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct sndrv_pcm_status) +#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, sndrv_pcm_sframes_t) +#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) +#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct sndrv_pcm_sync_ptr) +#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct sndrv_pcm_channel_info) +#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40) +#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41) +#define SNDRV_PCM_IOCTL_START _IO('A', 0x42) +#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43) +#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44) +#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int) +#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, sndrv_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47) +#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48) +#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, sndrv_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct sndrv_xferi) +#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct sndrv_xferi) +#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct sndrv_xfern) +#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct sndrv_xfern) +#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int) +#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61) +#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int) +#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct sndrv_rawmidi_info) +#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct sndrv_rawmidi_params) +#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct sndrv_rawmidi_status) +#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int) +#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int) +#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int) +#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct sndrv_timer_id) +#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int) +#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct sndrv_timer_ginfo) +#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct sndrv_timer_gparams) +#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct sndrv_timer_gstatus) +#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct sndrv_timer_select) +#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct sndrv_timer_info) +#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct sndrv_timer_params) +#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct sndrv_timer_status) +#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0) +#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1) +#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2) +#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3) +#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int) +#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct sndrv_ctl_card_info) +#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct sndrv_ctl_elem_list) +#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct sndrv_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct sndrv_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct sndrv_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct sndrv_ctl_elem_id) +#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct sndrv_ctl_elem_id) +#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int) +#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct sndrv_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct sndrv_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct sndrv_ctl_elem_id) +#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct sndrv_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct sndrv_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct sndrv_ctl_tlv) +#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int) +#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct sndrv_hwdep_info) +#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int) +#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct sndrv_pcm_info) +#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct sndrv_rawmidi_info) +#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int) +#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int) +#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int) +#define SNDRV_IOCTL_READV _IOW('K', 0x00, struct sndrv_xferv) +#define SNDRV_IOCTL_WRITEV _IOW('K', 0x01, struct sndrv_xferv) +#define SNDRV_EMU10K1_IOCTL_INFO _IOR ('H', 0x10, emu10k1_fx8010_info_t) +#define SNDRV_EMU10K1_IOCTL_CODE_POKE _IOW ('H', 0x11, emu10k1_fx8010_code_t) +#define SNDRV_EMU10K1_IOCTL_CODE_PEEK _IOWR('H', 0x12, emu10k1_fx8010_code_t) +#define SNDRV_EMU10K1_IOCTL_TRAM_SETUP _IOW ('H', 0x20, int) +#define SNDRV_EMU10K1_IOCTL_TRAM_POKE _IOW ('H', 0x21, emu10k1_fx8010_tram_t) +#define SNDRV_EMU10K1_IOCTL_TRAM_PEEK _IOWR('H', 0x22, emu10k1_fx8010_tram_t) +#define SNDRV_EMU10K1_IOCTL_PCM_POKE _IOW ('H', 0x30, emu10k1_fx8010_pcm_t) +#define SNDRV_EMU10K1_IOCTL_PCM_PEEK _IOWR('H', 0x31, emu10k1_fx8010_pcm_t) +#define SNDRV_EMU10K1_IOCTL_PVERSION _IOR ('H', 0x40, int) +#define SNDRV_EMU10K1_IOCTL_STOP _IO ('H', 0x80) +#define SNDRV_EMU10K1_IOCTL_CONTINUE _IO ('H', 0x81) +#define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82) +#define SNDRV_EMU10K1_IOCTL_SINGLE_STEP _IOW ('H', 0x83, int) +#define SNDRV_EMU10K1_IOCTL_DBG_READ _IOR ('H', 0x84, int) +#define SNDRV_HDSP_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, hdsp_peak_rms_t) +#define SNDRV_HDSP_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, hdsp_config_info_t) +#define SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE _IOW('H', 0x42, hdsp_firmware_t) +#define SNDRV_HDSP_IOCTL_GET_VERSION _IOR('H', 0x43, hdsp_version_t) +#define SNDRV_HDSP_IOCTL_GET_MIXER _IOR('H', 0x44, hdsp_mixer_t) +#define SNDRV_HDSP_IOCTL_GET_9632_AEB _IOR('H', 0x45, hdsp_9632_aeb_t) +#define SNDRV_SB_CSP_IOCTL_INFO _IOR('H', 0x10, snd_sb_csp_info_t) +#define SNDRV_SB_CSP_IOCTL_LOAD_CODE _IOW('H', 0x11, snd_sb_csp_microcode_t) +#define SNDRV_SB_CSP_IOCTL_UNLOAD_CODE _IO('H', 0x12) +#define SNDRV_SB_CSP_IOCTL_START _IOW('H', 0x13, snd_sb_csp_start_t) +#define SNDRV_SB_CSP_IOCTL_STOP _IO('H', 0x14) +#define SNDRV_SB_CSP_IOCTL_PAUSE _IO('H', 0x15) +#define SNDRV_SB_CSP_IOCTL_RESTART _IO('H', 0x16) +#define SND_SSCAPE_LOAD_BOOTB _IOWR('P', 100, struct sscape_bootblock) +#define SND_SSCAPE_LOAD_MCODE _IOW ('P', 101, struct sscape_microcode) + + +#define TARGET_SNDRV_SEQ_IOCTL_PVERSION TARGET_IOR ('S', 0x00, int) +#define TARGET_SNDRV_SEQ_IOCTL_CLIENT_ID TARGET_IOR ('S', 0x01, int) +#define TARGET_SNDRV_SEQ_IOCTL_SYSTEM_INFO TARGET_IOWRU('S', 0x02) +#define TARGET_SNDRV_SEQ_IOCTL_RUNNING_MODE TARGET_IOWRU('S', 0x03) +#define TARGET_SNDRV_SEQ_IOCTL_GET_CLIENT_INFO TARGET_IOWRU('S', 0x10) +#define TARGET_SNDRV_SEQ_IOCTL_SET_CLIENT_INFO TARGET_IOWU ('S', 0x11) +#define TARGET_SNDRV_SEQ_IOCTL_CREATE_PORT TARGET_IOWRU('S', 0x20) +#define TARGET_SNDRV_SEQ_IOCTL_DELETE_PORT TARGET_IOWU ('S', 0x21) +#define TARGET_SNDRV_SEQ_IOCTL_GET_PORT_INFO TARGET_IOWRU('S', 0x22) +#define TARGET_SNDRV_SEQ_IOCTL_SET_PORT_INFO TARGET_IOWU ('S', 0x23) +#define TARGET_SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT TARGET_IOWU ('S', 0x30) +#define TARGET_SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT TARGET_IOWU ('S', 0x31) +#define TARGET_SNDRV_SEQ_IOCTL_CREATE_QUEUE TARGET_IOWRU('S', 0x32) +#define TARGET_SNDRV_SEQ_IOCTL_DELETE_QUEUE TARGET_IOWU ('S', 0x33) +#define TARGET_SNDRV_SEQ_IOCTL_GET_QUEUE_INFO TARGET_IOWRU('S', 0x34) +#define TARGET_SNDRV_SEQ_IOCTL_SET_QUEUE_INFO TARGET_IOWRU('S', 0x35) +#define TARGET_SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE TARGET_IOWRU('S', 0x36) +#define TARGET_SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS TARGET_IOWRU('S', 0x40) +#define TARGET_SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO TARGET_IOWRU('S', 0x41) +#define TARGET_SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO TARGET_IOWU ('S', 0x42) +#define TARGET_SNDRV_SEQ_IOCTL_GET_QUEUE_OWNER TARGET_IOWRU('S', 0x43) +#define TARGET_SNDRV_SEQ_IOCTL_SET_QUEUE_OWNER TARGET_IOWU ('S', 0x44) +#define TARGET_SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER TARGET_IOWRU('S', 0x45) +#define TARGET_SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER TARGET_IOWU ('S', 0x46) +#define TARGET_SNDRV_SEQ_IOCTL_GET_QUEUE_SYNC TARGET_IOWRU('S', 0x53) +#define TARGET_SNDRV_SEQ_IOCTL_SET_QUEUE_SYNC TARGET_IOWU ('S', 0x54) +#define TARGET_SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT TARGET_IOWRU('S', 0x49) +#define TARGET_SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT TARGET_IOWU ('S', 0x4a) +#define TARGET_SNDRV_SEQ_IOCTL_GET_CLIENT_POOL TARGET_IOWRU('S', 0x4b) +#define TARGET_SNDRV_SEQ_IOCTL_SET_CLIENT_POOL TARGET_IOWU ('S', 0x4c) +#define TARGET_SNDRV_SEQ_IOCTL_REMOVE_EVENTS TARGET_IOWU ('S', 0x4e) +#define TARGET_SNDRV_SEQ_IOCTL_QUERY_SUBS TARGET_IOWRU('S', 0x4f) +#define TARGET_SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION TARGET_IOWRU('S', 0x50) +#define TARGET_SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT TARGET_IOWRU('S', 0x51) +#define TARGET_SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT TARGET_IOWRU('S', 0x52) +#define TARGET_SNDRV_DM_FM_IOCTL_INFO TARGET_IORU('H', 0x20) +#define TARGET_SNDRV_DM_FM_IOCTL_RESET TARGET_IO ('H', 0x21) +#define TARGET_SNDRV_DM_FM_IOCTL_PLAY_NOTE TARGET_IOWU('H', 0x22) +#define TARGET_SNDRV_DM_FM_IOCTL_SET_VOICE TARGET_IOWU('H', 0x23) +#define TARGET_SNDRV_DM_FM_IOCTL_SET_PARAMS TARGET_IOWU('H', 0x24) +#define TARGET_SNDRV_DM_FM_IOCTL_SET_MODE TARGET_IOW('H', 0x25, int) +#define TARGET_SNDRV_DM_FM_IOCTL_SET_CONNECTION TARGET_IOW('H', 0x26, int) +#define TARGET_SNDRV_DM_FM_OSS_IOCTL_RESET 0x20 +#define TARGET_SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE 0x21 +#define TARGET_SNDRV_DM_FM_OSS_IOCTL_SET_VOICE 0x22 +#define TARGET_SNDRV_DM_FM_OSS_IOCTL_SET_PARAMS 0x23 +#define TARGET_SNDRV_DM_FM_OSS_IOCTL_SET_MODE 0x24 +#define TARGET_SNDRV_DM_FM_OSS_IOCTL_SET_OPL 0x25 +#define TARGET_SNDRV_HWDEP_IOCTL_PVERSION TARGET_IOR ('H', 0x00, int) +#define TARGET_SNDRV_HWDEP_IOCTL_INFO TARGET_IORU ('H', 0x01) +#define TARGET_SNDRV_HWDEP_IOCTL_DSP_STATUS TARGET_IORU('H', 0x02) +#define TARGET_SNDRV_HWDEP_IOCTL_DSP_LOAD TARGET_IOWU('H', 0x03) +#define TARGET_SNDRV_PCM_IOCTL_PVERSION TARGET_IOR('A', 0x00, int) +#define TARGET_SNDRV_PCM_IOCTL_INFO TARGET_IORU('A', 0x01) +#define TARGET_SNDRV_PCM_IOCTL_TSTAMP TARGET_IOW('A', 0x02, int) +#define TARGET_SNDRV_PCM_IOCTL_HW_REFINE TARGET_IOWRU('A', 0x10) +#define TARGET_SNDRV_PCM_IOCTL_HW_PARAMS TARGET_IOWRU('A', 0x11) +#define TARGET_SNDRV_PCM_IOCTL_HW_FREE TARGET_IO('A', 0x12) +#define TARGET_SNDRV_PCM_IOCTL_SW_PARAMS TARGET_IOWRU('A', 0x13) +#define TARGET_SNDRV_PCM_IOCTL_STATUS TARGET_IORU('A', 0x20) +#define TARGET_SNDRV_PCM_IOCTL_DELAY TARGET_IORU('A', 0x21) +#define TARGET_SNDRV_PCM_IOCTL_HWSYNC TARGET_IO('A', 0x22) +#define TARGET_SNDRV_PCM_IOCTL_SYNC_PTR TARGET_IOWRU('A', 0x23) +#define TARGET_SNDRV_PCM_IOCTL_CHANNEL_INFO TARGET_IORU('A', 0x32) +#define TARGET_SNDRV_PCM_IOCTL_PREPARE TARGET_IO('A', 0x40) +#define TARGET_SNDRV_PCM_IOCTL_RESET TARGET_IO('A', 0x41) +#define TARGET_SNDRV_PCM_IOCTL_START TARGET_IO('A', 0x42) +#define TARGET_SNDRV_PCM_IOCTL_DROP TARGET_IO('A', 0x43) +#define TARGET_SNDRV_PCM_IOCTL_DRAIN TARGET_IO('A', 0x44) +#define TARGET_SNDRV_PCM_IOCTL_PAUSE TARGET_IOW('A', 0x45, int) +#define TARGET_SNDRV_PCM_IOCTL_REWIND TARGET_IOWU('A', 0x46) +#define TARGET_SNDRV_PCM_IOCTL_RESUME TARGET_IO('A', 0x47) +#define TARGET_SNDRV_PCM_IOCTL_XRUN TARGET_IO('A', 0x48) +#define TARGET_SNDRV_PCM_IOCTL_FORWARD TARGET_IOWU('A', 0x49) +#define TARGET_SNDRV_PCM_IOCTL_WRITEI_FRAMES TARGET_IOWU('A', 0x50) +#define TARGET_SNDRV_PCM_IOCTL_READI_FRAMES TARGET_IORU('A', 0x51) +#define TARGET_SNDRV_PCM_IOCTL_WRITEN_FRAMES TARGET_IOWU('A', 0x52) +#define TARGET_SNDRV_PCM_IOCTL_READN_FRAMES TARGET_IORU('A', 0x53) +#define TARGET_SNDRV_PCM_IOCTL_LINK TARGET_IOW('A', 0x60, int) +#define TARGET_SNDRV_PCM_IOCTL_UNLINK TARGET_IO('A', 0x61) +#define TARGET_SNDRV_RAWMIDI_IOCTL_PVERSION TARGET_IOR('W', 0x00, int) +#define TARGET_SNDRV_RAWMIDI_IOCTL_INFO TARGET_IORU('W', 0x01) +#define TARGET_SNDRV_RAWMIDI_IOCTL_PARAMS TARGET_IOWRU('W', 0x10) +#define TARGET_SNDRV_RAWMIDI_IOCTL_STATUS TARGET_IOWRU('W', 0x20) +#define TARGET_SNDRV_RAWMIDI_IOCTL_DROP TARGET_IOW('W', 0x30, int) +#define TARGET_SNDRV_RAWMIDI_IOCTL_DRAIN TARGET_IOW('W', 0x31, int) +#define TARGET_SNDRV_TIMER_IOCTL_PVERSION TARGET_IOR('T', 0x00, int) +#define TARGET_SNDRV_TIMER_IOCTL_NEXT_DEVICE TARGET_IOWRU('T', 0x01) +#define TARGET_SNDRV_TIMER_IOCTL_TREAD TARGET_IOW('T', 0x02, int) +#define TARGET_SNDRV_TIMER_IOCTL_GINFO TARGET_IOWRU('T', 0x03) +#define TARGET_SNDRV_TIMER_IOCTL_GPARAMS TARGET_IOWU('T', 0x04) +#define TARGET_SNDRV_TIMER_IOCTL_GSTATUS TARGET_IOWRU('T', 0x05) +#define TARGET_SNDRV_TIMER_IOCTL_SELECT TARGET_IOWU('T', 0x10) +#define TARGET_SNDRV_TIMER_IOCTL_INFO TARGET_IORU('T', 0x11) +#define TARGET_SNDRV_TIMER_IOCTL_PARAMS TARGET_IOWU('T', 0x12) +#define TARGET_SNDRV_TIMER_IOCTL_STATUS TARGET_IORU('T', 0x14) +#define TARGET_SNDRV_TIMER_IOCTL_START TARGET_IO('T', 0xa0) +#define TARGET_SNDRV_TIMER_IOCTL_STOP TARGET_IO('T', 0xa1) +#define TARGET_SNDRV_TIMER_IOCTL_CONTINUE TARGET_IO('T', 0xa2) +#define TARGET_SNDRV_TIMER_IOCTL_PAUSE TARGET_IO('T', 0xa3) +#define TARGET_SNDRV_CTL_IOCTL_PVERSION TARGET_IOR('U', 0x00, int) +#define TARGET_SNDRV_CTL_IOCTL_CARD_INFO TARGET_IORU('U', 0x01) +#define TARGET_SNDRV_CTL_IOCTL_ELEM_LIST TARGET_IOWRU('U', 0x10) +#define TARGET_SNDRV_CTL_IOCTL_ELEM_INFO TARGET_IOWRU('U', 0x11) +#define TARGET_SNDRV_CTL_IOCTL_ELEM_READ TARGET_IOWRU('U', 0x12) +#define TARGET_SNDRV_CTL_IOCTL_ELEM_WRITE TARGET_IOWRU('U', 0x13) +#define TARGET_SNDRV_CTL_IOCTL_ELEM_LOCK TARGET_IOWU('U', 0x14) +#define TARGET_SNDRV_CTL_IOCTL_ELEM_UNLOCK TARGET_IOWU('U', 0x15) +#define TARGET_SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS TARGET_IOWR('U', 0x16, int) +#define TARGET_SNDRV_CTL_IOCTL_ELEM_ADD TARGET_IOWRU('U', 0x17) +#define TARGET_SNDRV_CTL_IOCTL_ELEM_REPLACE TARGET_IOWRU('U', 0x18) +#define TARGET_SNDRV_CTL_IOCTL_ELEM_REMOVE TARGET_IOWRU('U', 0x19) +#define TARGET_SNDRV_CTL_IOCTL_TLV_READ TARGET_IOWRU('U', 0x1a) +#define TARGET_SNDRV_CTL_IOCTL_TLV_WRITE TARGET_IOWRU('U', 0x1b) +#define TARGET_SNDRV_CTL_IOCTL_TLV_COMMAND TARGET_IOWRU('U', 0x1c) +#define TARGET_SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE TARGET_IOWR('U', 0x20, int) +#define TARGET_SNDRV_CTL_IOCTL_HWDEP_INFO TARGET_IORU('U', 0x21) +#define TARGET_SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE TARGET_IOR('U', 0x30, int) +#define TARGET_SNDRV_CTL_IOCTL_PCM_INFO TARGET_IOWRU('U', 0x31) +#define TARGET_SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE TARGET_IOW('U', 0x32, int) +#define TARGET_SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE TARGET_IOWR('U', 0x40, int) +#define TARGET_SNDRV_CTL_IOCTL_RAWMIDI_INFO TARGET_IOWRU('U', 0x41) +#define TARGET_SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE TARGET_IOW('U', 0x42, int) +#define TARGET_SNDRV_CTL_IOCTL_POWER TARGET_IOWR('U', 0xd0, int) +#define TARGET_SNDRV_CTL_IOCTL_POWER_STATE TARGET_IOR('U', 0xd1, int) +#define TARGET_SNDRV_IOCTL_READV TARGET_IOWU('K', 0x00) +#define TARGET_SNDRV_IOCTL_WRITEV TARGET_IOWU('K', 0x01) +#define TARGET_SNDRV_EMU10K1_IOCTL_INFO TARGET_IORU ('H', 0x10) +#define TARGET_SNDRV_EMU10K1_IOCTL_CODE_POKE TARGET_IOWU ('H', 0x11) +#define TARGET_SNDRV_EMU10K1_IOCTL_CODE_PEEK TARGET_IOWRU('H', 0x12) +#define TARGET_SNDRV_EMU10K1_IOCTL_TRAM_SETUP TARGET_IOW ('H', 0x20, int) +#define TARGET_SNDRV_EMU10K1_IOCTL_TRAM_POKE TARGET_IOWU ('H', 0x21) +#define TARGET_SNDRV_EMU10K1_IOCTL_TRAM_PEEK TARGET_IOWRU('H', 0x22) +#define TARGET_SNDRV_EMU10K1_IOCTL_PCM_POKE TARGET_IOWU ('H', 0x30) +#define TARGET_SNDRV_EMU10K1_IOCTL_PCM_PEEK TARGET_IOWRU('H', 0x31) +#define TARGET_SNDRV_EMU10K1_IOCTL_PVERSION TARGET_IOR ('H', 0x40, int) +#define TARGET_SNDRV_EMU10K1_IOCTL_STOP TARGET_IO ('H', 0x80) +#define TARGET_SNDRV_EMU10K1_IOCTL_CONTINUE TARGET_IO ('H', 0x81) +#define TARGET_SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER TARGET_IO ('H', 0x82) +#define TARGET_SNDRV_EMU10K1_IOCTL_SINGLE_STEP TARGET_IOW ('H', 0x83, int) +#define TARGET_SNDRV_EMU10K1_IOCTL_DBG_READ TARGET_IOR ('H', 0x84, int) +#define TARGET_SNDRV_HDSP_IOCTL_GET_PEAK_RMS TARGET_IORU('H', 0x40) +#define TARGET_SNDRV_HDSP_IOCTL_GET_CONFIG_INFO TARGET_IORU('H', 0x41) +#define TARGET_SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE TARGET_IOWU('H', 0x42) +#define TARGET_SNDRV_HDSP_IOCTL_GET_VERSION TARGET_IORU('H', 0x43) +#define TARGET_SNDRV_HDSP_IOCTL_GET_MIXER TARGET_IORU('H', 0x44) +#define TARGET_SNDRV_HDSP_IOCTL_GET_9632_AEB TARGET_IORU('H', 0x45) +#define TARGET_SNDRV_SB_CSP_IOCTL_INFO TARGET_IORU('H', 0x10) +#define TARGET_SNDRV_SB_CSP_IOCTL_LOAD_CODE TARGET_IOWU('H', 0x11) +#define TARGET_SNDRV_SB_CSP_IOCTL_UNLOAD_CODE TARGET_IO('H', 0x12) +#define TARGET_SNDRV_SB_CSP_IOCTL_START TARGET_IOWU('H', 0x13) +#define TARGET_SNDRV_SB_CSP_IOCTL_STOP TARGET_IO('H', 0x14) +#define TARGET_SNDRV_SB_CSP_IOCTL_PAUSE TARGET_IO('H', 0x15) +#define TARGET_SNDRV_SB_CSP_IOCTL_RESTART TARGET_IO('H', 0x16) +#define TARGET_SND_SSCAPE_LOAD_BOOTB TARGET_IOWRU('P', 100) +#define TARGET_SND_SSCAPE_LOAD_MCODE TARGET_IOWU ('P', 101) + +IOCTL( SNDRV_SEQ_IOCTL_PVERSION , IOC_R, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_SEQ_IOCTL_CLIENT_ID , IOC_R, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_SEQ_IOCTL_SYSTEM_INFO , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_system_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_RUNNING_MODE , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_running_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_GET_CLIENT_INFO , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_client_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_SET_CLIENT_INFO , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_client_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_CREATE_PORT , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_port_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_DELETE_PORT , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_port_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_GET_PORT_INFO , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_port_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_SET_PORT_INFO , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_port_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_port_subscribe)) ) +IOCTL( SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_port_subscribe)) ) +IOCTL( SNDRV_SEQ_IOCTL_CREATE_QUEUE , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_DELETE_QUEUE , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_GET_QUEUE_INFO , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_SET_QUEUE_INFO , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_status)) ) +IOCTL( SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_tempo)) ) +IOCTL( SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_tempo)) ) +//IOCTL( SNDRV_SEQ_IOCTL_GET_QUEUE_OWNER , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_owner)) ) +//IOCTL( SNDRV_SEQ_IOCTL_SET_QUEUE_OWNER , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_owner)) ) +IOCTL( SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_timer)) ) +IOCTL( SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_timer)) ) +//IOCTL( SNDRV_SEQ_IOCTL_GET_QUEUE_SYNC , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_sync)) ) +//IOCTL( SNDRV_SEQ_IOCTL_SET_QUEUE_SYNC , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_sync)) ) +IOCTL( SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_client)) ) +IOCTL( SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_queue_client)) ) +IOCTL( SNDRV_SEQ_IOCTL_GET_CLIENT_POOL , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_client_pool)) ) +IOCTL( SNDRV_SEQ_IOCTL_SET_CLIENT_POOL , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_client_pool)) ) +IOCTL( SNDRV_SEQ_IOCTL_REMOVE_EVENTS , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_remove_events)) ) +IOCTL( SNDRV_SEQ_IOCTL_QUERY_SUBS , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_query_subs)) ) +IOCTL( SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_port_subscribe)) ) +IOCTL( SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_client_info)) ) +IOCTL( SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_seq_port_info)) ) +IOCTL( SNDRV_DM_FM_IOCTL_INFO , IOC_R, MK_PTR(MK_STRUCT(STRUCT_snd_dm_fm_info)) ) +IOCTL( SNDRV_DM_FM_IOCTL_RESET , 0, TYPE_NULL ) +IOCTL( SNDRV_DM_FM_IOCTL_PLAY_NOTE , IOC_W, MK_PTR(MK_STRUCT(STRUCT_snd_dm_fm_note)) ) +IOCTL( SNDRV_DM_FM_IOCTL_SET_VOICE , IOC_W, MK_PTR(MK_STRUCT(STRUCT_snd_dm_fm_voice)) ) +IOCTL( SNDRV_DM_FM_IOCTL_SET_PARAMS , IOC_W, MK_PTR(MK_STRUCT(STRUCT_snd_dm_fm_params)) ) +IOCTL( SNDRV_DM_FM_IOCTL_SET_MODE , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_DM_FM_IOCTL_SET_CONNECTION , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_HWDEP_IOCTL_PVERSION , IOC_R, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_HWDEP_IOCTL_INFO , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_hwdep_info)) ) +IOCTL( SNDRV_HWDEP_IOCTL_DSP_STATUS , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_hwdep_dsp_status)) ) +IOCTL( SNDRV_HWDEP_IOCTL_DSP_LOAD , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_hwdep_dsp_image)) ) +IOCTL( SNDRV_PCM_IOCTL_PVERSION , IOC_R, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_PCM_IOCTL_INFO , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_pcm_info)) ) +IOCTL( SNDRV_PCM_IOCTL_TSTAMP , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_PCM_IOCTL_HW_REFINE , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_pcm_hw_params)) ) +IOCTL( SNDRV_PCM_IOCTL_HW_PARAMS , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_pcm_hw_params)) ) +IOCTL( SNDRV_PCM_IOCTL_HW_FREE , 0, TYPE_NULL ) +IOCTL( SNDRV_PCM_IOCTL_SW_PARAMS , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_pcm_sw_params)) ) +IOCTL( SNDRV_PCM_IOCTL_STATUS , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_pcm_status)) ) +IOCTL( SNDRV_PCM_IOCTL_DELAY , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_pcm_sframes)) ) +IOCTL( SNDRV_PCM_IOCTL_HWSYNC , 0, TYPE_NULL ) +IOCTL( SNDRV_PCM_IOCTL_SYNC_PTR , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_pcm_sync_ptr)) ) +IOCTL( SNDRV_PCM_IOCTL_CHANNEL_INFO , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_pcm_channel_info)) ) +IOCTL( SNDRV_PCM_IOCTL_PREPARE , 0, TYPE_NULL ) +IOCTL( SNDRV_PCM_IOCTL_RESET , 0, TYPE_NULL ) +IOCTL( SNDRV_PCM_IOCTL_START , 0, TYPE_NULL ) +IOCTL( SNDRV_PCM_IOCTL_DROP , 0, TYPE_NULL ) +IOCTL( SNDRV_PCM_IOCTL_DRAIN , 0, TYPE_NULL ) +IOCTL( SNDRV_PCM_IOCTL_PAUSE , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_PCM_IOCTL_REWIND , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_pcm_uframes)) ) +IOCTL( SNDRV_PCM_IOCTL_RESUME , 0, TYPE_NULL ) +IOCTL( SNDRV_PCM_IOCTL_XRUN , 0, TYPE_NULL ) +IOCTL( SNDRV_PCM_IOCTL_FORWARD , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_pcm_uframes)) ) +IOCTL( SNDRV_PCM_IOCTL_WRITEI_FRAMES , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_xferi)) ) +IOCTL( SNDRV_PCM_IOCTL_READI_FRAMES , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_xferi)) ) +IOCTL( SNDRV_PCM_IOCTL_WRITEN_FRAMES , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_xfern)) ) +IOCTL( SNDRV_PCM_IOCTL_READN_FRAMES , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_xfern)) ) +IOCTL( SNDRV_PCM_IOCTL_LINK , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_PCM_IOCTL_UNLINK , 0, TYPE_NULL ) +IOCTL( SNDRV_RAWMIDI_IOCTL_PVERSION , IOC_R, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_RAWMIDI_IOCTL_INFO , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_rawmidi_info)) ) +IOCTL( SNDRV_RAWMIDI_IOCTL_PARAMS , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_rawmidi_params)) ) +IOCTL( SNDRV_RAWMIDI_IOCTL_STATUS , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_rawmidi_status)) ) +IOCTL( SNDRV_RAWMIDI_IOCTL_DROP , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_RAWMIDI_IOCTL_DRAIN , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_TIMER_IOCTL_PVERSION , IOC_R, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_TIMER_IOCTL_NEXT_DEVICE , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_timer_id)) ) +IOCTL( SNDRV_TIMER_IOCTL_TREAD , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_TIMER_IOCTL_GINFO , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_timer_ginfo)) ) +IOCTL( SNDRV_TIMER_IOCTL_GPARAMS , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_timer_gparams)) ) +IOCTL( SNDRV_TIMER_IOCTL_GSTATUS , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_timer_gstatus)) ) +IOCTL( SNDRV_TIMER_IOCTL_SELECT , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_timer_select)) ) +IOCTL( SNDRV_TIMER_IOCTL_INFO , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_timer_info)) ) +IOCTL( SNDRV_TIMER_IOCTL_PARAMS , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_timer_params)) ) +IOCTL( SNDRV_TIMER_IOCTL_STATUS , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_timer_status)) ) +IOCTL( SNDRV_TIMER_IOCTL_START , 0, TYPE_NULL ) +IOCTL( SNDRV_TIMER_IOCTL_STOP , 0, TYPE_NULL ) +IOCTL( SNDRV_TIMER_IOCTL_CONTINUE , 0, TYPE_NULL ) +IOCTL( SNDRV_TIMER_IOCTL_PAUSE , 0, TYPE_NULL ) +IOCTL( SNDRV_CTL_IOCTL_PVERSION , IOC_R, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_CTL_IOCTL_CARD_INFO , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_card_info)) ) +IOCTL( SNDRV_CTL_IOCTL_ELEM_LIST , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_elem_list)) ) +IOCTL( SNDRV_CTL_IOCTL_ELEM_INFO , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_elem_info)) ) +IOCTL( SNDRV_CTL_IOCTL_ELEM_READ , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_elem_value)) ) +IOCTL( SNDRV_CTL_IOCTL_ELEM_WRITE , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_elem_value)) ) +IOCTL( SNDRV_CTL_IOCTL_ELEM_LOCK , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_elem_id)) ) +IOCTL( SNDRV_CTL_IOCTL_ELEM_UNLOCK , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_elem_id)) ) +IOCTL( SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS , IOC_RW, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_CTL_IOCTL_ELEM_ADD , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_elem_info)) ) +IOCTL( SNDRV_CTL_IOCTL_ELEM_REPLACE , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_elem_info)) ) +IOCTL( SNDRV_CTL_IOCTL_ELEM_REMOVE , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_elem_id)) ) +IOCTL( SNDRV_CTL_IOCTL_TLV_READ , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_tlv)) ) +IOCTL( SNDRV_CTL_IOCTL_TLV_WRITE , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_tlv)) ) +IOCTL( SNDRV_CTL_IOCTL_TLV_COMMAND , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_ctl_tlv)) ) +IOCTL( SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE , IOC_RW, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_CTL_IOCTL_HWDEP_INFO , IOC_R, MK_PTR(MK_STRUCT(STRUCT_sndrv_hwdep_info)) ) +IOCTL( SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE , IOC_R, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_CTL_IOCTL_PCM_INFO , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_pcm_info)) ) +IOCTL( SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE , IOC_RW, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_CTL_IOCTL_RAWMIDI_INFO , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sndrv_rawmidi_info)) ) +IOCTL( SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_CTL_IOCTL_POWER , IOC_RW, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_CTL_IOCTL_POWER_STATE , IOC_R, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_IOCTL_READV , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_xferv)) ) +IOCTL( SNDRV_IOCTL_WRITEV , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sndrv_xferv)) ) +IOCTL( SNDRV_EMU10K1_IOCTL_INFO , IOC_R, MK_PTR(MK_STRUCT(STRUCT_emu10k1_fx8010_info)) ) +IOCTL( SNDRV_EMU10K1_IOCTL_CODE_POKE , IOC_W, MK_PTR(MK_STRUCT(STRUCT_emu10k1_fx8010_code)) ) +IOCTL( SNDRV_EMU10K1_IOCTL_CODE_PEEK , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_emu10k1_fx8010_code)) ) +IOCTL( SNDRV_EMU10K1_IOCTL_TRAM_SETUP , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_EMU10K1_IOCTL_TRAM_POKE , IOC_W, MK_PTR(MK_STRUCT(STRUCT_emu10k1_fx8010_tram)) ) +IOCTL( SNDRV_EMU10K1_IOCTL_TRAM_PEEK , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_emu10k1_fx8010_tram)) ) +IOCTL( SNDRV_EMU10K1_IOCTL_PCM_POKE , IOC_W, MK_PTR(MK_STRUCT(STRUCT_emu10k1_fx8010_pcm)) ) +IOCTL( SNDRV_EMU10K1_IOCTL_PCM_PEEK , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_emu10k1_fx8010_pcm)) ) +IOCTL( SNDRV_EMU10K1_IOCTL_PVERSION , IOC_R, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_EMU10K1_IOCTL_STOP , 0, TYPE_NULL ) +IOCTL( SNDRV_EMU10K1_IOCTL_CONTINUE , 0, TYPE_NULL ) +IOCTL( SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER , 0, TYPE_NULL ) +IOCTL( SNDRV_EMU10K1_IOCTL_SINGLE_STEP , IOC_W, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_EMU10K1_IOCTL_DBG_READ , IOC_R, MK_PTR(TYPE_INT) ) +IOCTL( SNDRV_HDSP_IOCTL_GET_PEAK_RMS , IOC_R, MK_PTR(MK_STRUCT(STRUCT_hdsp_peak_rms)) ) +IOCTL( SNDRV_HDSP_IOCTL_GET_CONFIG_INFO , IOC_R, MK_PTR(MK_STRUCT(STRUCT_hdsp_config_info)) ) +IOCTL( SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE , IOC_W, MK_PTR(MK_STRUCT(STRUCT_hdsp_firmware)) ) +IOCTL( SNDRV_HDSP_IOCTL_GET_VERSION , IOC_R, MK_PTR(MK_STRUCT(STRUCT_hdsp_version)) ) +IOCTL( SNDRV_HDSP_IOCTL_GET_MIXER , IOC_R, MK_PTR(MK_STRUCT(STRUCT_hdsp_mixer)) ) +IOCTL( SNDRV_HDSP_IOCTL_GET_9632_AEB , IOC_R, MK_PTR(MK_STRUCT(STRUCT_hdsp_9632_aeb)) ) +IOCTL( SNDRV_SB_CSP_IOCTL_INFO , IOC_R, MK_PTR(MK_STRUCT(STRUCT_snd_sb_csp_info)) ) +#if _IOC_SIZEBITS > 13 +IOCTL( SNDRV_SB_CSP_IOCTL_LOAD_CODE , IOC_W, MK_PTR(MK_STRUCT(STRUCT_snd_sb_csp_microcode)) ) +#endif +IOCTL( SNDRV_SB_CSP_IOCTL_UNLOAD_CODE , 0, TYPE_NULL ) +IOCTL( SNDRV_SB_CSP_IOCTL_START , IOC_W, MK_PTR(MK_STRUCT(STRUCT_snd_sb_csp_start)) ) +IOCTL( SNDRV_SB_CSP_IOCTL_STOP , 0, TYPE_NULL ) +IOCTL( SNDRV_SB_CSP_IOCTL_PAUSE , 0, TYPE_NULL ) +IOCTL( SNDRV_SB_CSP_IOCTL_RESTART , 0, TYPE_NULL ) +IOCTL( SND_SSCAPE_LOAD_BOOTB , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sscape_bootblock)) ) +IOCTL( SND_SSCAPE_LOAD_MCODE , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sscape_microcode)) ) diff --git a/linux-user/ioctls_alsa_structs.h b/linux-user/ioctls_alsa_structs.h new file mode 100644 index 0000000000..e09a30defb --- /dev/null +++ b/linux-user/ioctls_alsa_structs.h @@ -0,0 +1,1740 @@ +/* + * Advanced Linux Sound Architecture + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __u8 +#define __u8 uint8_t +#define __u16 uint16_t +#define __u32 uint32_t +#define __s8 int8_t +#define __s16 int16_t +#define __s32 int32_t +#endif + +#define SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE 0x3000 +#define HDSP_MATRIX_MIXER_SIZE 2048 +#define SNDRV_MASK_MAX 256 + +typedef struct fm_operator { + unsigned char am_vib; + unsigned char ksl_level; + unsigned char attack_decay; + unsigned char sustain_release; + unsigned char wave_select; +} fm_operator_t; + +typedef struct { + unsigned int share_id[4]; /* share id - zero = no sharing */ + unsigned char type; /* instrument type */ + + fm_operator_t op[4]; + unsigned char feedback_connection[2]; + + unsigned char echo_delay; + unsigned char echo_atten; + unsigned char chorus_spread; + unsigned char trnsps; + unsigned char fix_dur; + unsigned char modes; + unsigned char fix_key; +} fm_instrument_t; + +typedef struct fm_xoperator { + __u8 am_vib; + __u8 ksl_level; + __u8 attack_decay; + __u8 sustain_release; + __u8 wave_select; +} fm_xoperator_t; + +typedef struct fm_xinstrument { + __u32 stype; /* structure type */ + + __u32 share_id[4]; /* share id - zero = no sharing */ + __u8 type; /* instrument type */ + + fm_xoperator_t op[4]; /* fm operators */ + __u8 feedback_connection[2]; + + __u8 echo_delay; + __u8 echo_atten; + __u8 chorus_spread; + __u8 trnsps; + __u8 fix_dur; + __u8 modes; + __u8 fix_key; +} fm_xinstrument_t; + +typedef struct gf1_wave { + unsigned int share_id[4]; /* share id - zero = no sharing */ + unsigned int format; /* wave format */ + + struct { + unsigned int number; /* some other ID for this instrument */ + unsigned int memory; /* begin of waveform in onboard memory */ + unsigned char *ptr; /* pointer to waveform in system memory */ + } address; + + unsigned int size; /* size of waveform in samples */ + unsigned int start; /* start offset in samples * 16 (lowest 4 bits - fraction) */ + unsigned int loop_start; /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */ + unsigned int loop_end; /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + unsigned short loop_repeat; /* loop repeat - 0 = forever */ + + unsigned char flags; /* GF1 patch flags */ + unsigned char pad; + unsigned int sample_rate; /* sample rate in Hz */ + unsigned int low_frequency; /* low frequency range */ + unsigned int high_frequency; /* high frequency range */ + unsigned int root_frequency; /* root frequency range */ + signed short tune; + unsigned char balance; + unsigned char envelope_rate[6]; + unsigned char envelope_offset[6]; + unsigned char tremolo_sweep; + unsigned char tremolo_rate; + unsigned char tremolo_depth; + unsigned char vibrato_sweep; + unsigned char vibrato_rate; + unsigned char vibrato_depth; + unsigned short scale_frequency; + unsigned short scale_factor; /* 0-2048 or 0-2 */ + + struct gf1_wave *next; +} gf1_wave_t; + +typedef struct { + unsigned short exclusion; + unsigned short exclusion_group; /* 0 - none, 1-65535 */ + + unsigned char effect1; /* effect 1 */ + unsigned char effect1_depth; /* 0-127 */ + unsigned char effect2; /* effect 2 */ + unsigned char effect2_depth; /* 0-127 */ + + gf1_wave_t *wave; /* first waveform */ +} gf1_instrument_t; + +typedef struct gf1_xwave { + __u32 stype; /* structure type */ + + __u32 share_id[4]; /* share id - zero = no sharing */ + __u32 format; /* wave format */ + + __u32 size; /* size of waveform in samples */ + __u32 start; /* start offset in samples * 16 (lowest 4 bits - fraction) */ + __u32 loop_start; /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */ + __u32 loop_end; /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + __u16 loop_repeat; /* loop repeat - 0 = forever */ + + __u8 flags; /* GF1 patch flags */ + __u8 pad; + __u32 sample_rate; /* sample rate in Hz */ + __u32 low_frequency; /* low frequency range */ + __u32 high_frequency; /* high frequency range */ + __u32 root_frequency; /* root frequency range */ + __s16 tune; + __u8 balance; + __u8 envelope_rate[6]; + __u8 envelope_offset[6]; + __u8 tremolo_sweep; + __u8 tremolo_rate; + __u8 tremolo_depth; + __u8 vibrato_sweep; + __u8 vibrato_rate; + __u8 vibrato_depth; + __u16 scale_frequency; + __u16 scale_factor; /* 0-2048 or 0-2 */ +} gf1_xwave_t; + +typedef struct gf1_xinstrument { + __u32 stype; + + __u16 exclusion; + __u16 exclusion_group; /* 0 - none, 1-65535 */ + + __u8 effect1; /* effect 1 */ + __u8 effect1_depth; /* 0-127 */ + __u8 effect2; /* effect 2 */ + __u8 effect2_depth; /* 0-127 */ +} gf1_xinstrument_t; + +typedef struct gf1_info { + unsigned char flags; /* supported wave flags */ + unsigned char pad[3]; + unsigned int features; /* supported features */ + unsigned int max8_len; /* maximum 8-bit wave length */ + unsigned int max16_len; /* maximum 16-bit wave length */ +} gf1_info_t; + +typedef struct iwffff_wave { + unsigned int share_id[4]; /* share id - zero = no sharing */ + unsigned int format; /* wave format */ + + struct { + unsigned int number; /* some other ID for this wave */ + unsigned int memory; /* begin of waveform in onboard memory */ + unsigned char *ptr; /* pointer to waveform in system memory */ + } address; + + unsigned int size; /* size of waveform in samples */ + unsigned int start; /* start offset in samples * 16 (lowest 4 bits - fraction) */ + unsigned int loop_start; /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */ + unsigned int loop_end; /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + unsigned short loop_repeat; /* loop repeat - 0 = forever */ + unsigned int sample_ratio; /* sample ratio (44100 * 1024 / rate) */ + unsigned char attenuation; /* 0 - 127 (no corresponding midi controller) */ + unsigned char low_note; /* lower frequency range for this waveform */ + unsigned char high_note; /* higher frequency range for this waveform */ + unsigned char pad; + + struct iwffff_wave *next; +} iwffff_wave_t; + +typedef struct iwffff_lfo { + unsigned short freq; /* (0-2047) 0.01Hz - 21.5Hz */ + signed short depth; /* volume +- (0-255) 0.48675dB/step */ + signed short sweep; /* 0 - 950 deciseconds */ + unsigned char shape; /* see to IWFFFF_LFO_SHAPE_XXXX */ + unsigned char delay; /* 0 - 255 deciseconds */ +} iwffff_lfo_t; + +typedef struct iwffff_env_point { + unsigned short offset; + unsigned short rate; +} iwffff_env_point_t; + +typedef struct iwffff_env_record { + unsigned short nattack; + unsigned short nrelease; + unsigned short sustain_offset; + unsigned short sustain_rate; + unsigned short release_rate; + unsigned char hirange; + unsigned char pad; + struct iwffff_env_record *next; + /* points are stored here */ + /* count of points = nattack + nrelease */ +} iwffff_env_record_t; + +typedef struct iwffff_env { + unsigned char flags; + unsigned char mode; + unsigned char index; + unsigned char pad; + struct iwffff_env_record *record; +} iwffff_env_t; + +typedef struct iwffff_layer { + unsigned char flags; + unsigned char velocity_mode; + unsigned char layer_event; + unsigned char low_range; /* range for layer based */ + unsigned char high_range; /* on either velocity or frequency */ + unsigned char pan; /* pan offset from CC1 (0 left - 127 right) */ + unsigned char pan_freq_scale; /* position based on frequency (0-127) */ + unsigned char attenuation; /* 0-127 (no corresponding midi controller) */ + iwffff_lfo_t tremolo; /* tremolo effect */ + iwffff_lfo_t vibrato; /* vibrato effect */ + unsigned short freq_scale; /* 0-2048, 1024 is equal to semitone scaling */ + unsigned char freq_center; /* center for keyboard frequency scaling */ + unsigned char pad; + iwffff_env_t penv; /* pitch envelope */ + iwffff_env_t venv; /* volume envelope */ + + iwffff_wave_t *wave; + struct iwffff_layer *next; +} iwffff_layer_t; + +typedef struct { + unsigned short exclusion; + unsigned short layer_type; + unsigned short exclusion_group; /* 0 - none, 1-65535 */ + + unsigned char effect1; /* effect 1 */ + unsigned char effect1_depth; /* 0-127 */ + unsigned char effect2; /* effect 2 */ + unsigned char effect2_depth; /* 0-127 */ + + iwffff_layer_t *layer; /* first layer */ +} iwffff_instrument_t; + +typedef struct iwffff_xwave { + __u32 stype; /* structure type */ + + __u32 share_id[4]; /* share id - zero = no sharing */ + + __u32 format; /* wave format */ + __u32 offset; /* offset to ROM (address) */ + + __u32 size; /* size of waveform in samples */ + __u32 start; /* start offset in samples * 16 (lowest 4 bits - fraction) */ + __u32 loop_start; /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */ + __u32 loop_end; /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + __u16 loop_repeat; /* loop repeat - 0 = forever */ + __u32 sample_ratio; /* sample ratio (44100 * 1024 / rate) */ + __u8 attenuation; /* 0 - 127 (no corresponding midi controller) */ + __u8 low_note; /* lower frequency range for this waveform */ + __u8 high_note; /* higher frequency range for this waveform */ + __u8 pad; +} iwffff_xwave_t; + +typedef struct iwffff_xlfo { + __u16 freq; /* (0-2047) 0.01Hz - 21.5Hz */ + __s16 depth; /* volume +- (0-255) 0.48675dB/step */ + __s16 sweep; /* 0 - 950 deciseconds */ + __u8 shape; /* see to ULTRA_IW_LFO_SHAPE_XXXX */ + __u8 delay; /* 0 - 255 deciseconds */ +} iwffff_xlfo_t; + +typedef struct iwffff_xenv_point { + __u16 offset; + __u16 rate; +} iwffff_xenv_point_t; + +typedef struct iwffff_xenv_record { + __u32 stype; + __u16 nattack; + __u16 nrelease; + __u16 sustain_offset; + __u16 sustain_rate; + __u16 release_rate; + __u8 hirange; + __u8 pad; + /* points are stored here.. */ + /* count of points = nattack + nrelease */ +} iwffff_xenv_record_t; + +typedef struct iwffff_xenv { + __u8 flags; + __u8 mode; + __u8 index; + __u8 pad; +} iwffff_xenv_t; + +typedef struct iwffff_xlayer { + __u32 stype; + __u8 flags; + __u8 velocity_mode; + __u8 layer_event; + __u8 low_range; /* range for layer based */ + __u8 high_range; /* on either velocity or frequency */ + __u8 pan; /* pan offset from CC1 (0 left - 127 right) */ + __u8 pan_freq_scale; /* position based on frequency (0-127) */ + __u8 attenuation; /* 0-127 (no corresponding midi controller) */ + iwffff_xlfo_t tremolo; /* tremolo effect */ + iwffff_xlfo_t vibrato; /* vibrato effect */ + __u16 freq_scale; /* 0-2048, 1024 is equal to semitone scaling */ + __u8 freq_center; /* center for keyboard frequency scaling */ + __u8 pad; + iwffff_xenv_t penv; /* pitch envelope */ + iwffff_xenv_t venv; /* volume envelope */ +} iwffff_xlayer_t; + +typedef struct iwffff_xinstrument { + __u32 stype; + + __u16 exclusion; + __u16 layer_type; + __u16 exclusion_group; /* 0 - none, 1-65535 */ + + __u8 effect1; /* effect 1 */ + __u8 effect1_depth; /* 0-127 */ + __u8 effect2; /* effect 2 */ + __u8 effect2_depth; /* 0-127 */ +} iwffff_xinstrument_t; + +typedef struct { + __u8 iwave[8]; + __u8 revision; + __u8 series_number; + __u8 series_name[16]; + __u8 date[10]; + __u16 vendor_revision_major; + __u16 vendor_revision_minor; + __u32 rom_size; + __u8 copyright[128]; + __u8 vendor_name[64]; + __u8 description[128]; +} iwffff_rom_header_t; + +typedef struct iwffff_info { + unsigned int format; /* supported format bits */ + unsigned int effects; /* supported effects (1 << IWFFFF_EFFECT*) */ + unsigned int lfos; /* LFO effects */ + unsigned int max8_len; /* maximum 8-bit wave length */ + unsigned int max16_len; /* maximum 16-bit wave length */ +} iwffff_info_t; + +typedef struct simple_instrument_info { + unsigned int format; /* supported format bits */ + unsigned int effects; /* supported effects (1 << SIMPLE_EFFECT_*) */ + unsigned int max8_len; /* maximum 8-bit wave length */ + unsigned int max16_len; /* maximum 16-bit wave length */ +} simple_instrument_info_t; + +typedef struct { + unsigned int share_id[4]; /* share id - zero = no sharing */ + unsigned int format; /* wave format */ + + struct { + unsigned int number; /* some other ID for this instrument */ + unsigned int memory; /* begin of waveform in onboard memory */ + unsigned char *ptr; /* pointer to waveform in system memory */ + } address; + + unsigned int size; /* size of waveform in samples */ + unsigned int start; /* start offset in samples * 16 (lowest 4 bits - fraction) */ + unsigned int loop_start; /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + unsigned int loop_end; /* loop end offset in samples * 16 (lowest 4 bits - fraction) */ + unsigned short loop_repeat; /* loop repeat - 0 = forever */ + + unsigned char effect1; /* effect 1 */ + unsigned char effect1_depth; /* 0-127 */ + unsigned char effect2; /* effect 2 */ + unsigned char effect2_depth; /* 0-127 */ +} simple_instrument_t; + +typedef struct simple_xinstrument { + __u32 stype; + + __u32 share_id[4]; /* share id - zero = no sharing */ + __u32 format; /* wave format */ + + __u32 size; /* size of waveform in samples */ + __u32 start; /* start offset in samples * 16 (lowest 4 bits - fraction) */ + __u32 loop_start; /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */ + __u32 loop_end; /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + __u16 loop_repeat; /* loop repeat - 0 = forever */ + + __u8 effect1; /* effect 1 */ + __u8 effect1_depth; /* 0-127 */ + __u8 effect2; /* effect 2 */ + __u8 effect2_depth; /* 0-127 */ +} simple_xinstrument_t; + +typedef unsigned char sndrv_seq_event_type_t; + +/** event address */ +struct sndrv_seq_addr { + unsigned char client; /**< Client number: 0..255, 255 = broadcast to all clients */ + unsigned char port; /**< Port within client: 0..255, 255 = broadcast to all ports */ +}; + +/** port connection */ +struct sndrv_seq_connect { + struct sndrv_seq_addr sender; + struct sndrv_seq_addr dest; +}; + +struct sndrv_seq_ev_note { + unsigned char channel; + unsigned char note; + unsigned char velocity; + unsigned char off_velocity; /* only for SNDRV_SEQ_EVENT_NOTE */ + unsigned int duration; /* only for SNDRV_SEQ_EVENT_NOTE */ +}; + + /* controller event */ +struct sndrv_seq_ev_ctrl { + unsigned char channel; + unsigned char unused1, unused2, unused3; /* pad */ + unsigned int param; + signed int value; +}; + + /* generic set of bytes (12x8 bit) */ +struct sndrv_seq_ev_raw8 { + unsigned char d[12]; /* 8 bit value */ +}; + + /* generic set of integers (3x32 bit) */ +struct sndrv_seq_ev_raw32 { + unsigned int d[3]; /* 32 bit value */ +}; + + /* external stored data */ +struct sndrv_seq_ev_ext { + unsigned int len; /* length of data */ + void *ptr; /* pointer to data (note: maybe 64-bit) */ +} __attribute__((packed)); + +/* Instrument cluster type */ +typedef unsigned int sndrv_seq_instr_cluster_t; + +/* Instrument type */ +struct sndrv_seq_instr { + sndrv_seq_instr_cluster_t cluster; + unsigned int std; /* the upper byte means a private instrument (owner - client #) */ + unsigned short bank; + unsigned short prg; +}; + + /* sample number */ +struct sndrv_seq_ev_sample { + unsigned int std; + unsigned short bank; + unsigned short prg; +}; + + /* sample cluster */ +struct sndrv_seq_ev_cluster { + sndrv_seq_instr_cluster_t cluster; +}; + + /* sample position */ +typedef unsigned int sndrv_seq_position_t; /* playback position (in samples) * 16 */ + + /* sample stop mode */ +enum sndrv_seq_stop_mode { + SAMPLE_STOP_IMMEDIATELY = 0, /* terminate playing immediately */ + SAMPLE_STOP_VENVELOPE = 1, /* finish volume envelope */ + SAMPLE_STOP_LOOP = 2 /* terminate loop and finish wave */ +}; + + /* sample frequency */ +typedef int sndrv_seq_frequency_t; /* playback frequency in HZ * 16 */ + + /* sample volume control; if any value is set to -1 == do not change */ +struct sndrv_seq_ev_volume { + signed short volume; /* range: 0-16383 */ + signed short lr; /* left-right balance; range: 0-16383 */ + signed short fr; /* front-rear balance; range: 0-16383 */ + signed short du; /* down-up balance; range: 0-16383 */ +}; + + /* simple loop redefinition */ +struct sndrv_seq_ev_loop { + unsigned int start; /* loop start (in samples) * 16 */ + unsigned int end; /* loop end (in samples) * 16 */ +}; + +struct sndrv_seq_ev_sample_control { + unsigned char channel; + unsigned char unused1, unused2, unused3; /* pad */ + union { + struct sndrv_seq_ev_sample sample; + struct sndrv_seq_ev_cluster cluster; + sndrv_seq_position_t position; + int stop_mode; + sndrv_seq_frequency_t frequency; + struct sndrv_seq_ev_volume volume; + struct sndrv_seq_ev_loop loop; + unsigned char raw8[8]; + } param; +}; + + + +/* INSTR_BEGIN event */ +struct sndrv_seq_ev_instr_begin { + int timeout; /* zero = forever, otherwise timeout in ms */ +}; + +struct sndrv_seq_result { + int event; /* processed event type */ + int result; +}; + + +struct sndrv_seq_real_time { + unsigned int tv_sec; /* seconds */ + unsigned int tv_nsec; /* nanoseconds */ +}; + +typedef unsigned int sndrv_seq_tick_time_t; /* midi ticks */ + +union sndrv_seq_timestamp { + sndrv_seq_tick_time_t tick; + struct sndrv_seq_real_time time; +}; + +struct sndrv_seq_queue_skew { + unsigned int value; + unsigned int base; +}; + + /* queue timer control */ +struct sndrv_seq_ev_queue_control { + unsigned char queue; /* affected queue */ + unsigned char pad[3]; /* reserved */ + union { + signed int value; /* affected value (e.g. tempo) */ + union sndrv_seq_timestamp time; /* time */ + unsigned int position; /* sync position */ + struct sndrv_seq_queue_skew skew; + unsigned int d32[2]; + unsigned char d8[8]; + } param; +}; + + /* quoted event - inside the kernel only */ +struct sndrv_seq_ev_quote { + struct sndrv_seq_addr origin; /* original sender */ + unsigned short value; /* optional data */ + struct sndrv_seq_event *event; /* quoted event */ +} __attribute__((packed)); + + + /* sequencer event */ +struct sndrv_seq_event { + sndrv_seq_event_type_t type; /* event type */ + unsigned char flags; /* event flags */ + char tag; + + unsigned char queue; /* schedule queue */ + union sndrv_seq_timestamp time; /* schedule time */ + + + struct sndrv_seq_addr source; /* source address */ + struct sndrv_seq_addr dest; /* destination address */ + + union { /* event data... */ + struct sndrv_seq_ev_note note; + struct sndrv_seq_ev_ctrl control; + struct sndrv_seq_ev_raw8 raw8; + struct sndrv_seq_ev_raw32 raw32; + struct sndrv_seq_ev_ext ext; + struct sndrv_seq_ev_queue_control queue; + union sndrv_seq_timestamp time; + struct sndrv_seq_addr addr; + struct sndrv_seq_connect connect; + struct sndrv_seq_result result; + struct sndrv_seq_ev_instr_begin instr_begin; + struct sndrv_seq_ev_sample_control sample; + struct sndrv_seq_ev_quote quote; + } data; +}; + + +/* + * bounce event - stored as variable size data + */ +struct sndrv_seq_event_bounce { + int err; + struct sndrv_seq_event event; + /* external data follows here. */ +}; + +struct sndrv_seq_system_info { + int queues; /* maximum queues count */ + int clients; /* maximum clients count */ + int ports; /* maximum ports per client */ + int channels; /* maximum channels per port */ + int cur_clients; /* current clients */ + int cur_queues; /* current queues */ + char reserved[24]; +}; + +struct sndrv_seq_running_info { + unsigned char client; /* client id */ + unsigned char big_endian; /* 1 = big-endian */ + unsigned char cpu_mode; /* 4 = 32bit, 8 = 64bit */ + unsigned char pad; /* reserved */ + unsigned char reserved[12]; +}; + +enum sndrv_seq_client_type { + NO_CLIENT = 0, + USER_CLIENT = 1, + KERNEL_CLIENT = 2 +}; + +struct sndrv_seq_client_info { + int client; /* client number to inquire */ + int type; /* client type */ + char name[64]; /* client name */ + unsigned int filter; /* filter flags */ + unsigned char multicast_filter[8]; /* multicast filter bitmap */ + unsigned char event_filter[32]; /* event filter bitmap */ + int num_ports; /* RO: number of ports */ + int event_lost; /* number of lost events */ + char reserved[64]; /* for future use */ +}; + +struct sndrv_seq_client_pool { + int client; /* client number to inquire */ + int output_pool; /* outgoing (write) pool size */ + int input_pool; /* incoming (read) pool size */ + int output_room; /* minimum free pool size for select/blocking mode */ + int output_free; /* unused size */ + int input_free; /* unused size */ + char reserved[64]; +}; + +struct sndrv_seq_remove_events { + unsigned int remove_mode; /* Flags that determine what gets removed */ + + union sndrv_seq_timestamp time; + + unsigned char queue; /* Queue for REMOVE_DEST */ + struct sndrv_seq_addr dest; /* Address for REMOVE_DEST */ + unsigned char channel; /* Channel for REMOVE_DEST */ + + int type; /* For REMOVE_EVENT_TYPE */ + char tag; /* Tag for REMOVE_TAG */ + + int reserved[10]; /* To allow for future binary compatibility */ + +}; + +struct sndrv_seq_port_info { + struct sndrv_seq_addr addr; /* client/port numbers */ + char name[64]; /* port name */ + + unsigned int capability; /* port capability bits */ + unsigned int type; /* port type bits */ + int midi_channels; /* channels per MIDI port */ + int midi_voices; /* voices per MIDI port */ + int synth_voices; /* voices per SYNTH port */ + + int read_use; /* R/O: subscribers for output (from this port) */ + int write_use; /* R/O: subscribers for input (to this port) */ + + void *kernel; /* reserved for kernel use (must be NULL) */ + unsigned int flags; /* misc. conditioning */ + unsigned char time_queue; /* queue # for timestamping */ + char reserved[59]; /* for future use */ +}; + +struct sndrv_seq_queue_info { + int queue; /* queue id */ + + /* + * security settings, only owner of this queue can start/stop timer + * etc. if the queue is locked for other clients + */ + int owner; /* client id for owner of the queue */ + int locked:1; /* timing queue locked for other queues */ + char name[64]; /* name of this queue */ + unsigned int flags; /* flags */ + char reserved[60]; /* for future use */ + +}; + +struct sndrv_seq_queue_status { + int queue; /* queue id */ + int events; /* read-only - queue size */ + sndrv_seq_tick_time_t tick; /* current tick */ + struct sndrv_seq_real_time time; /* current time */ + int running; /* running state of queue */ + int flags; /* various flags */ + char reserved[64]; /* for the future */ +}; + +struct sndrv_seq_queue_tempo { + int queue; /* sequencer queue */ + unsigned int tempo; /* current tempo, us/tick */ + int ppq; /* time resolution, ticks/quarter */ + unsigned int skew_value; /* queue skew */ + unsigned int skew_base; /* queue skew base */ + char reserved[24]; /* for the future */ +}; + +struct sndrv_timer_id { + int dev_class; + int dev_sclass; + int card; + int device; + int subdevice; +}; + +struct sndrv_seq_queue_timer { + int queue; /* sequencer queue */ + int type; /* source timer type */ + union { + struct { + struct sndrv_timer_id id; /* ALSA's timer ID */ + unsigned int resolution; /* resolution in Hz */ + } alsa; + } u; + char reserved[64]; /* for the future use */ +}; + +struct sndrv_seq_queue_client { + int queue; /* sequencer queue */ + int client; /* sequencer client */ + int used; /* queue is used with this client + (must be set for accepting events) */ + /* per client watermarks */ + char reserved[64]; /* for future use */ +}; + +struct sndrv_seq_port_subscribe { + struct sndrv_seq_addr sender; /* sender address */ + struct sndrv_seq_addr dest; /* destination address */ + unsigned int voices; /* number of voices to be allocated (0 = don't care) */ + unsigned int flags; /* modes */ + unsigned char queue; /* input time-stamp queue (optional) */ + unsigned char pad[3]; /* reserved */ + char reserved[64]; +}; + +struct sndrv_seq_query_subs { + struct sndrv_seq_addr root; /* client/port id to be searched */ + int type; /* READ or WRITE */ + int index; /* 0..N-1 */ + int num_subs; /* R/O: number of subscriptions on this port */ + struct sndrv_seq_addr addr; /* R/O: result */ + unsigned char queue; /* R/O: result */ + unsigned int flags; /* R/O: result */ + char reserved[64]; /* for future use */ +}; + +/* size of ROM/RAM */ +typedef unsigned int sndrv_seq_instr_size_t; + +struct sndrv_seq_instr_info { + int result; /* operation result */ + unsigned int formats[8]; /* bitmap of supported formats */ + int ram_count; /* count of RAM banks */ + sndrv_seq_instr_size_t ram_sizes[16]; /* size of RAM banks */ + int rom_count; /* count of ROM banks */ + sndrv_seq_instr_size_t rom_sizes[8]; /* size of ROM banks */ + char reserved[128]; +}; + +struct sndrv_seq_instr_status { + int result; /* operation result */ + sndrv_seq_instr_size_t free_ram[16]; /* free RAM in banks */ + int instrument_count; /* count of downloaded instruments */ + char reserved[128]; +}; + +struct sndrv_seq_instr_format_info { + char format[16]; /* format identifier - SNDRV_SEQ_INSTR_ID_* */ + unsigned int len; /* max data length (without this structure) */ +}; + +struct sndrv_seq_instr_format_info_result { + int result; /* operation result */ + char format[16]; /* format identifier */ + unsigned int len; /* filled data length (without this structure) */ +}; + +struct sndrv_seq_instr_data { + char name[32]; /* instrument name */ + char reserved[16]; /* for the future use */ + int type; /* instrument type */ + union { + char format[16]; /* format identifier */ + struct sndrv_seq_instr alias; + } data; +}; + +struct sndrv_seq_instr_header { + union { + struct sndrv_seq_instr instr; + sndrv_seq_instr_cluster_t cluster; + } id; /* instrument identifier */ + unsigned int cmd; /* get/put/free command */ + unsigned int flags; /* query flags (only for get) */ + unsigned int len; /* real instrument data length (without header) */ + int result; /* operation result */ + char reserved[16]; /* for the future */ + struct sndrv_seq_instr_data data; /* instrument data (for put/get result) */ +}; + +struct sndrv_seq_instr_cluster_set { + sndrv_seq_instr_cluster_t cluster; /* cluster identifier */ + char name[32]; /* cluster name */ + int priority; /* cluster priority */ + char reserved[64]; /* for the future use */ +}; + +struct sndrv_seq_instr_cluster_get { + sndrv_seq_instr_cluster_t cluster; /* cluster identifier */ + char name[32]; /* cluster name */ + int priority; /* cluster priority */ + char reserved[64]; /* for the future use */ +}; + +typedef struct snd_dm_fm_info { + unsigned char fm_mode; /* OPL mode, see SNDRV_DM_FM_MODE_XXX */ + unsigned char rhythm; /* percussion mode flag */ +} snd_dm_fm_info_t; + +typedef struct snd_dm_fm_voice { + unsigned char op; /* operator cell (0 or 1) */ + unsigned char voice; /* FM voice (0 to 17) */ + + unsigned char am; /* amplitude modulation */ + unsigned char vibrato; /* vibrato effect */ + unsigned char do_sustain; /* sustain phase */ + unsigned char kbd_scale; /* keyboard scaling */ + unsigned char harmonic; /* 4 bits: harmonic and multiplier */ + unsigned char scale_level; /* 2 bits: decrease output freq rises */ + unsigned char volume; /* 6 bits: volume */ + + unsigned char attack; /* 4 bits: attack rate */ + unsigned char decay; /* 4 bits: decay rate */ + unsigned char sustain; /* 4 bits: sustain level */ + unsigned char release; /* 4 bits: release rate */ + + unsigned char feedback; /* 3 bits: feedback for op0 */ + unsigned char connection; /* 0 for serial, 1 for parallel */ + unsigned char left; /* stereo left */ + unsigned char right; /* stereo right */ + unsigned char waveform; /* 3 bits: waveform shape */ +} snd_dm_fm_voice_t; + +typedef struct snd_dm_fm_note { + unsigned char voice; /* 0-17 voice channel */ + unsigned char octave; /* 3 bits: what octave to play */ + unsigned int fnum; /* 10 bits: frequency number */ + unsigned char key_on; /* set for active, clear for silent */ +} snd_dm_fm_note_t; + +typedef struct snd_dm_fm_params { + unsigned char am_depth; /* amplitude modulation depth (1=hi) */ + unsigned char vib_depth; /* vibrato depth (1=hi) */ + unsigned char kbd_split; /* keyboard split */ + unsigned char rhythm; /* percussion mode select */ + + /* This block is the percussion instrument data */ + unsigned char bass; + unsigned char snare; + unsigned char tomtom; + unsigned char cymbal; + unsigned char hihat; +} snd_dm_fm_params_t; + +#include +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define SNDRV_LITTLE_ENDIAN +#elif __BYTE_ORDER == __BIG_ENDIAN +#define SNDRV_BIG_ENDIAN +#else +#error "Unsupported endian..." +#endif + +#include +#include + +struct sndrv_aes_iec958 { + unsigned char status[24]; /* AES/IEC958 channel status bits */ + unsigned char subcode[147]; /* AES/IEC958 subcode bits */ + unsigned char pad; /* nothing */ + unsigned char dig_subframe[4]; /* AES/IEC958 subframe bits */ +}; + +enum sndrv_hwdep_iface { + SNDRV_HWDEP_IFACE_OPL2 = 0, + SNDRV_HWDEP_IFACE_OPL3, + SNDRV_HWDEP_IFACE_OPL4, + SNDRV_HWDEP_IFACE_SB16CSP, /* Creative Signal Processor */ + SNDRV_HWDEP_IFACE_EMU10K1, /* FX8010 processor in EMU10K1 chip */ + SNDRV_HWDEP_IFACE_YSS225, /* Yamaha FX processor */ + SNDRV_HWDEP_IFACE_ICS2115, /* Wavetable synth */ + SNDRV_HWDEP_IFACE_SSCAPE, /* Ensoniq SoundScape ISA card (MC68EC000) */ + SNDRV_HWDEP_IFACE_VX, /* Digigram VX cards */ + SNDRV_HWDEP_IFACE_MIXART, /* Digigram miXart cards */ + SNDRV_HWDEP_IFACE_USX2Y, /* Tascam US122, US224 & US428 usb */ + SNDRV_HWDEP_IFACE_EMUX_WAVETABLE, /* EmuX wavetable */ + SNDRV_HWDEP_IFACE_BLUETOOTH, /* Bluetooth audio */ + SNDRV_HWDEP_IFACE_USX2Y_PCM, /* Tascam US122, US224 & US428 rawusb pcm */ + SNDRV_HWDEP_IFACE_PCXHR, /* Digigram PCXHR */ + SNDRV_HWDEP_IFACE_SB_RC, /* SB Extigy/Audigy2NX remote control */ + + /* Don't forget to change the following: */ + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SB_RC +}; + +struct sndrv_hwdep_info { + unsigned int device; /* WR: device number */ + int card; /* R: card number */ + unsigned char id[64]; /* ID (user selectable) */ + unsigned char name[80]; /* hwdep name */ + int iface; /* hwdep interface */ + unsigned char reserved[64]; /* reserved for future */ +}; + +/* generic DSP loader */ +struct sndrv_hwdep_dsp_status { + unsigned int version; /* R: driver-specific version */ + unsigned char id[32]; /* R: driver-specific ID string */ + unsigned int num_dsps; /* R: number of DSP images to transfer */ + unsigned int dsp_loaded; /* R: bit flags indicating the loaded DSPs */ + unsigned int chip_ready; /* R: 1 = initialization finished */ + unsigned char reserved[16]; /* reserved for future use */ +}; + +struct sndrv_hwdep_dsp_image { + unsigned int index; /* W: DSP index */ + unsigned char name[64]; /* W: ID (e.g. file name) */ + unsigned char *image; /* W: binary image */ + size_t length; /* W: size of image in bytes */ + unsigned long driver_data; /* W: driver-specific data */ +}; + +typedef unsigned long sndrv_pcm_uframes_t; +typedef long sndrv_pcm_sframes_t; + +enum sndrv_pcm_class { + SNDRV_PCM_CLASS_GENERIC = 0, /* standard mono or stereo device */ + SNDRV_PCM_CLASS_MULTI, /* multichannel device */ + SNDRV_PCM_CLASS_MODEM, /* software modem class */ + SNDRV_PCM_CLASS_DIGITIZER, /* digitizer class */ + /* Don't forget to change the following: */ + SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER, +}; + +enum sndrv_pcm_subclass { + SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0, /* mono or stereo subdevices are mixed together */ + SNDRV_PCM_SUBCLASS_MULTI_MIX, /* multichannel subdevices are mixed together */ + /* Don't forget to change the following: */ + SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX, +}; + +enum sndrv_pcm_stream { + SNDRV_PCM_STREAM_PLAYBACK = 0, + SNDRV_PCM_STREAM_CAPTURE, + SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE, +}; + +enum sndrv_pcm_access { + SNDRV_PCM_ACCESS_MMAP_INTERLEAVED = 0, /* interleaved mmap */ + SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED, /* noninterleaved mmap */ + SNDRV_PCM_ACCESS_MMAP_COMPLEX, /* complex mmap */ + SNDRV_PCM_ACCESS_RW_INTERLEAVED, /* readi/writei */ + SNDRV_PCM_ACCESS_RW_NONINTERLEAVED, /* readn/writen */ + SNDRV_PCM_ACCESS_LAST = SNDRV_PCM_ACCESS_RW_NONINTERLEAVED, +}; + +enum sndrv_pcm_format { + SNDRV_PCM_FORMAT_S8 = 0, + SNDRV_PCM_FORMAT_U8, + SNDRV_PCM_FORMAT_S16_LE, + SNDRV_PCM_FORMAT_S16_BE, + SNDRV_PCM_FORMAT_U16_LE, + SNDRV_PCM_FORMAT_U16_BE, + SNDRV_PCM_FORMAT_S24_LE, /* low three bytes */ + SNDRV_PCM_FORMAT_S24_BE, /* low three bytes */ + SNDRV_PCM_FORMAT_U24_LE, /* low three bytes */ + SNDRV_PCM_FORMAT_U24_BE, /* low three bytes */ + SNDRV_PCM_FORMAT_S32_LE, + SNDRV_PCM_FORMAT_S32_BE, + SNDRV_PCM_FORMAT_U32_LE, + SNDRV_PCM_FORMAT_U32_BE, + SNDRV_PCM_FORMAT_FLOAT_LE, /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_FLOAT_BE, /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_FLOAT64_LE, /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_FLOAT64_BE, /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE, /* IEC-958 subframe, Little Endian */ + SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE, /* IEC-958 subframe, Big Endian */ + SNDRV_PCM_FORMAT_MU_LAW, + SNDRV_PCM_FORMAT_A_LAW, + SNDRV_PCM_FORMAT_IMA_ADPCM, + SNDRV_PCM_FORMAT_MPEG, + SNDRV_PCM_FORMAT_GSM, + SNDRV_PCM_FORMAT_SPECIAL = 31, + SNDRV_PCM_FORMAT_S24_3LE = 32, /* in three bytes */ + SNDRV_PCM_FORMAT_S24_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_U24_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_U24_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_S20_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_S20_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_U20_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_U20_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_S18_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_S18_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_U18_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_U18_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_LAST = SNDRV_PCM_FORMAT_U18_3BE, + +#ifdef SNDRV_LITTLE_ENDIAN + SNDRV_PCM_FORMAT_S16 = SNDRV_PCM_FORMAT_S16_LE, + SNDRV_PCM_FORMAT_U16 = SNDRV_PCM_FORMAT_U16_LE, + SNDRV_PCM_FORMAT_S24 = SNDRV_PCM_FORMAT_S24_LE, + SNDRV_PCM_FORMAT_U24 = SNDRV_PCM_FORMAT_U24_LE, + SNDRV_PCM_FORMAT_S32 = SNDRV_PCM_FORMAT_S32_LE, + SNDRV_PCM_FORMAT_U32 = SNDRV_PCM_FORMAT_U32_LE, + SNDRV_PCM_FORMAT_FLOAT = SNDRV_PCM_FORMAT_FLOAT_LE, + SNDRV_PCM_FORMAT_FLOAT64 = SNDRV_PCM_FORMAT_FLOAT64_LE, + SNDRV_PCM_FORMAT_IEC958_SUBFRAME = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE, +#endif +#ifdef SNDRV_BIG_ENDIAN + SNDRV_PCM_FORMAT_S16 = SNDRV_PCM_FORMAT_S16_BE, + SNDRV_PCM_FORMAT_U16 = SNDRV_PCM_FORMAT_U16_BE, + SNDRV_PCM_FORMAT_S24 = SNDRV_PCM_FORMAT_S24_BE, + SNDRV_PCM_FORMAT_U24 = SNDRV_PCM_FORMAT_U24_BE, + SNDRV_PCM_FORMAT_S32 = SNDRV_PCM_FORMAT_S32_BE, + SNDRV_PCM_FORMAT_U32 = SNDRV_PCM_FORMAT_U32_BE, + SNDRV_PCM_FORMAT_FLOAT = SNDRV_PCM_FORMAT_FLOAT_BE, + SNDRV_PCM_FORMAT_FLOAT64 = SNDRV_PCM_FORMAT_FLOAT64_BE, + SNDRV_PCM_FORMAT_IEC958_SUBFRAME = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE, +#endif +}; + +enum sndrv_pcm_subformat { + SNDRV_PCM_SUBFORMAT_STD = 0, + SNDRV_PCM_SUBFORMAT_LAST = SNDRV_PCM_SUBFORMAT_STD, +}; + +enum sndrv_pcm_state { + SNDRV_PCM_STATE_OPEN = 0, /* stream is open */ + SNDRV_PCM_STATE_SETUP, /* stream has a setup */ + SNDRV_PCM_STATE_PREPARED, /* stream is ready to start */ + SNDRV_PCM_STATE_RUNNING, /* stream is running */ + SNDRV_PCM_STATE_XRUN, /* stream reached an xrun */ + SNDRV_PCM_STATE_DRAINING, /* stream is draining */ + SNDRV_PCM_STATE_PAUSED, /* stream is paused */ + SNDRV_PCM_STATE_SUSPENDED, /* hardware is suspended */ + SNDRV_PCM_STATE_DISCONNECTED, /* hardware is disconnected */ + SNDRV_PCM_STATE_LAST = SNDRV_PCM_STATE_DISCONNECTED, +}; + +enum { + SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, + SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000, + SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000, +}; + +union sndrv_pcm_sync_id { + unsigned char id[16]; + unsigned short id16[8]; + unsigned int id32[4]; +}; + +struct sndrv_pcm_info { + unsigned int device; /* RO/WR (control): device number */ + unsigned int subdevice; /* RO/WR (control): subdevice number */ + int stream; /* RO/WR (control): stream number */ + int card; /* R: card number */ + unsigned char id[64]; /* ID (user selectable) */ + unsigned char name[80]; /* name of this device */ + unsigned char subname[32]; /* subdevice name */ + int dev_class; /* SNDRV_PCM_CLASS_* */ + int dev_subclass; /* SNDRV_PCM_SUBCLASS_* */ + unsigned int subdevices_count; + unsigned int subdevices_avail; + union sndrv_pcm_sync_id sync; /* hardware synchronization ID */ + unsigned char reserved[64]; /* reserved for future... */ +}; + +enum sndrv_pcm_hw_param { + SNDRV_PCM_HW_PARAM_ACCESS = 0, /* Access type */ + SNDRV_PCM_HW_PARAM_FIRST_MASK = SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_HW_PARAM_FORMAT, /* Format */ + SNDRV_PCM_HW_PARAM_SUBFORMAT, /* Subformat */ + SNDRV_PCM_HW_PARAM_LAST_MASK = SNDRV_PCM_HW_PARAM_SUBFORMAT, + + SNDRV_PCM_HW_PARAM_SAMPLE_BITS = 8, /* Bits per sample */ + SNDRV_PCM_HW_PARAM_FIRST_INTERVAL = SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + SNDRV_PCM_HW_PARAM_FRAME_BITS, /* Bits per frame */ + SNDRV_PCM_HW_PARAM_CHANNELS, /* Channels */ + SNDRV_PCM_HW_PARAM_RATE, /* Approx rate */ + SNDRV_PCM_HW_PARAM_PERIOD_TIME, /* Approx distance between interrupts + in us */ + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, /* Approx frames between interrupts */ + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, /* Approx bytes between interrupts */ + SNDRV_PCM_HW_PARAM_PERIODS, /* Approx interrupts per buffer */ + SNDRV_PCM_HW_PARAM_BUFFER_TIME, /* Approx duration of buffer in us */ + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, /* Size of buffer in frames */ + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, /* Size of buffer in bytes */ + SNDRV_PCM_HW_PARAM_TICK_TIME, /* Approx tick duration in us */ + SNDRV_PCM_HW_PARAM_LAST_INTERVAL = SNDRV_PCM_HW_PARAM_TICK_TIME +}; + +struct sndrv_interval { + unsigned int min, max; + unsigned int openmin:1, + openmax:1, + integer:1, + empty:1; +}; + +struct sndrv_mask { + u_int32_t bits[(SNDRV_MASK_MAX+31)/32]; +}; + +struct sndrv_pcm_hw_params { + unsigned int flags; + struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - + SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; + struct sndrv_mask mres[5]; /* reserved masks */ + struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - + SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; + struct sndrv_interval ires[9]; /* reserved intervals */ + unsigned int rmask; /* W: requested masks */ + unsigned int cmask; /* R: changed masks */ + unsigned int info; /* R: Info flags for returned setup */ + unsigned int msbits; /* R: used most significant bits */ + unsigned int rate_num; /* R: rate numerator */ + unsigned int rate_den; /* R: rate denominator */ + sndrv_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */ + unsigned char reserved[64]; /* reserved for future */ +}; + +enum sndrv_pcm_tstamp { + SNDRV_PCM_TSTAMP_NONE = 0, + SNDRV_PCM_TSTAMP_MMAP, + SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_MMAP, +}; + +struct sndrv_pcm_sw_params { + int tstamp_mode; /* timestamp mode */ + unsigned int period_step; + unsigned int sleep_min; /* min ticks to sleep */ + sndrv_pcm_uframes_t avail_min; /* min avail frames for wakeup */ + sndrv_pcm_uframes_t xfer_align; /* xfer size need to be a multiple */ + sndrv_pcm_uframes_t start_threshold; /* min hw_avail frames for automatic start */ + sndrv_pcm_uframes_t stop_threshold; /* min avail frames for automatic stop */ + sndrv_pcm_uframes_t silence_threshold; /* min distance from noise for silence filling */ + sndrv_pcm_uframes_t silence_size; /* silence block size */ + sndrv_pcm_uframes_t boundary; /* pointers wrap point */ + unsigned char reserved[64]; /* reserved for future */ +}; + +struct sndrv_pcm_channel_info { + unsigned int channel; + long int offset; /* mmap offset */ + unsigned int first; /* offset to first sample in bits */ + unsigned int step; /* samples distance in bits */ +}; + +struct sndrv_pcm_status { + int state; /* stream state */ + struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */ + struct timespec tstamp; /* reference timestamp */ + sndrv_pcm_uframes_t appl_ptr; /* appl ptr */ + sndrv_pcm_uframes_t hw_ptr; /* hw ptr */ + sndrv_pcm_sframes_t delay; /* current delay in frames */ + sndrv_pcm_uframes_t avail; /* number of frames available */ + sndrv_pcm_uframes_t avail_max; /* max frames available on hw since last status */ + sndrv_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */ + int suspended_state; /* suspended stream state */ + unsigned char reserved[60]; /* must be filled with zero */ +}; + +struct sndrv_pcm_mmap_status { + int state; /* RO: state - SNDRV_PCM_STATE_XXXX */ + int pad1; /* Needed for 64 bit alignment */ + sndrv_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */ + struct timespec tstamp; /* Timestamp */ + int suspended_state; /* RO: suspended stream state */ +}; + +struct sndrv_pcm_mmap_control { + sndrv_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ + sndrv_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ +}; + +struct sndrv_pcm_sync_ptr { + unsigned int flags; + union { + struct sndrv_pcm_mmap_status status; + unsigned char reserved[64]; + } s; + union { + struct sndrv_pcm_mmap_control control; + unsigned char reserved[64]; + } c; +}; + +struct sndrv_xferi { + sndrv_pcm_sframes_t result; + void *buf; + sndrv_pcm_uframes_t frames; +}; + +struct sndrv_xfern { + sndrv_pcm_sframes_t result; + void **bufs; + sndrv_pcm_uframes_t frames; +}; + +enum sndrv_rawmidi_stream { + SNDRV_RAWMIDI_STREAM_OUTPUT = 0, + SNDRV_RAWMIDI_STREAM_INPUT, + SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT, +}; + +struct sndrv_rawmidi_info { + unsigned int device; /* RO/WR (control): device number */ + unsigned int subdevice; /* RO/WR (control): subdevice number */ + int stream; /* WR: stream */ + int card; /* R: card number */ + unsigned int flags; /* SNDRV_RAWMIDI_INFO_XXXX */ + unsigned char id[64]; /* ID (user selectable) */ + unsigned char name[80]; /* name of device */ + unsigned char subname[32]; /* name of active or selected subdevice */ + unsigned int subdevices_count; + unsigned int subdevices_avail; + unsigned char reserved[64]; /* reserved for future use */ +}; + +struct sndrv_rawmidi_params { + int stream; + size_t buffer_size; /* queue size in bytes */ + size_t avail_min; /* minimum avail bytes for wakeup */ + unsigned int no_active_sensing: 1; /* do not send active sensing byte in close() */ + unsigned char reserved[16]; /* reserved for future use */ +}; + +struct sndrv_rawmidi_status { + int stream; + struct timespec tstamp; /* Timestamp */ + size_t avail; /* available bytes */ + size_t xruns; /* count of overruns since last status (in bytes) */ + unsigned char reserved[16]; /* reserved for future use */ +}; + +enum sndrv_timer_class { + SNDRV_TIMER_CLASS_NONE = -1, + SNDRV_TIMER_CLASS_SLAVE = 0, + SNDRV_TIMER_CLASS_GLOBAL, + SNDRV_TIMER_CLASS_CARD, + SNDRV_TIMER_CLASS_PCM, + SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM, +}; + +/* slave timer classes */ +enum sndrv_timer_slave_class { + SNDRV_TIMER_SCLASS_NONE = 0, + SNDRV_TIMER_SCLASS_APPLICATION, + SNDRV_TIMER_SCLASS_SEQUENCER, /* alias */ + SNDRV_TIMER_SCLASS_OSS_SEQUENCER, /* alias */ + SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER, +}; + +struct sndrv_timer_ginfo { + struct sndrv_timer_id tid; /* requested timer ID */ + unsigned int flags; /* timer flags - SNDRV_TIMER_FLG_* */ + int card; /* card number */ + unsigned char id[64]; /* timer identification */ + unsigned char name[80]; /* timer name */ + unsigned long reserved0; /* reserved for future use */ + unsigned long resolution; /* average period resolution in ns */ + unsigned long resolution_min; /* minimal period resolution in ns */ + unsigned long resolution_max; /* maximal period resolution in ns */ + unsigned int clients; /* active timer clients */ + unsigned char reserved[32]; +}; + +struct sndrv_timer_gparams { + struct sndrv_timer_id tid; /* requested timer ID */ + unsigned long period_num; /* requested precise period duration (in seconds) - numerator */ + unsigned long period_den; /* requested precise period duration (in seconds) - denominator */ + unsigned char reserved[32]; +}; + +struct sndrv_timer_gstatus { + struct sndrv_timer_id tid; /* requested timer ID */ + unsigned long resolution; /* current period resolution in ns */ + unsigned long resolution_num; /* precise current period resolution (in seconds) - numerator */ + unsigned long resolution_den; /* precise current period resolution (in seconds) - denominator */ + unsigned char reserved[32]; +}; + +struct sndrv_timer_select { + struct sndrv_timer_id id; /* bind to timer ID */ + unsigned char reserved[32]; /* reserved */ +}; + +struct sndrv_timer_info { + unsigned int flags; /* timer flags - SNDRV_TIMER_FLG_* */ + int card; /* card number */ + unsigned char id[64]; /* timer identificator */ + unsigned char name[80]; /* timer name */ + unsigned long reserved0; /* reserved for future use */ + unsigned long resolution; /* average period resolution in ns */ + unsigned char reserved[64]; /* reserved */ +}; + +struct sndrv_timer_params { + unsigned int flags; /* flags - SNDRV_MIXER_PSFLG_* */ + unsigned int ticks; /* requested resolution in ticks */ + unsigned int queue_size; /* total size of queue (32-1024) */ + unsigned int reserved0; /* reserved, was: failure locations */ + unsigned int filter; /* event filter (bitmask of SNDRV_TIMER_EVENT_*) */ + unsigned char reserved[60]; /* reserved */ +}; + +struct sndrv_timer_status { + struct timespec tstamp; /* Timestamp - last update */ + unsigned int resolution; /* current period resolution in ns */ + unsigned int lost; /* counter of master tick lost */ + unsigned int overrun; /* count of read queue overruns */ + unsigned int queue; /* used queue size */ + unsigned char reserved[64]; /* reserved */ +}; + +struct sndrv_timer_read { + unsigned int resolution; + unsigned int ticks; +}; + +enum sndrv_timer_event { + SNDRV_TIMER_EVENT_RESOLUTION = 0, /* val = resolution in ns */ + SNDRV_TIMER_EVENT_TICK, /* val = ticks */ + SNDRV_TIMER_EVENT_START, /* val = resolution in ns */ + SNDRV_TIMER_EVENT_STOP, /* val = 0 */ + SNDRV_TIMER_EVENT_CONTINUE, /* val = resolution in ns */ + SNDRV_TIMER_EVENT_PAUSE, /* val = 0 */ + SNDRV_TIMER_EVENT_EARLY, /* val = 0, early event */ + SNDRV_TIMER_EVENT_SUSPEND, /* val = 0 */ + SNDRV_TIMER_EVENT_RESUME, /* val = resolution in ns */ + /* master timer events for slave timer instances */ + SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10, + SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10, + SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10, + SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10, + SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10, + SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10, +}; + +struct sndrv_timer_tread { + int event; + struct timespec tstamp; + unsigned int val; +}; + +struct sndrv_ctl_card_info { + int card; /* card number */ + int pad; /* reserved for future (was type) */ + unsigned char id[16]; /* ID of card (user selectable) */ + unsigned char driver[16]; /* Driver name */ + unsigned char name[32]; /* Short name of soundcard */ + unsigned char longname[80]; /* name + info text about soundcard */ + unsigned char reserved_[16]; /* reserved for future (was ID of mixer) */ + unsigned char mixername[80]; /* visual mixer identification */ + unsigned char components[80]; /* card components / fine identification, delimited with one space (AC97 etc..) */ + unsigned char reserved[48]; /* reserved for future */ +}; + +enum sndrv_ctl_elem_type { + SNDRV_CTL_ELEM_TYPE_NONE = 0, /* invalid */ + SNDRV_CTL_ELEM_TYPE_BOOLEAN, /* boolean type */ + SNDRV_CTL_ELEM_TYPE_INTEGER, /* integer type */ + SNDRV_CTL_ELEM_TYPE_ENUMERATED, /* enumerated type */ + SNDRV_CTL_ELEM_TYPE_BYTES, /* byte array */ + SNDRV_CTL_ELEM_TYPE_IEC958, /* IEC958 (S/PDIF) setup */ + SNDRV_CTL_ELEM_TYPE_INTEGER64, /* 64-bit integer type */ + SNDRV_CTL_ELEM_TYPE_LAST = SNDRV_CTL_ELEM_TYPE_INTEGER64, +}; + +enum sndrv_ctl_elem_iface { + SNDRV_CTL_ELEM_IFACE_CARD = 0, /* global control */ + SNDRV_CTL_ELEM_IFACE_HWDEP, /* hardware dependent device */ + SNDRV_CTL_ELEM_IFACE_MIXER, /* virtual mixer device */ + SNDRV_CTL_ELEM_IFACE_PCM, /* PCM device */ + SNDRV_CTL_ELEM_IFACE_RAWMIDI, /* RawMidi device */ + SNDRV_CTL_ELEM_IFACE_TIMER, /* timer device */ + SNDRV_CTL_ELEM_IFACE_SEQUENCER, /* sequencer client */ + SNDRV_CTL_ELEM_IFACE_LAST = SNDRV_CTL_ELEM_IFACE_SEQUENCER, +}; + +struct sndrv_ctl_elem_id { + unsigned int numid; /* numeric identifier, zero = invalid */ + int iface; /* interface identifier */ + unsigned int device; /* device/client number */ + unsigned int subdevice; /* subdevice (substream) number */ + unsigned char name[44]; /* ASCII name of item */ + unsigned int index; /* index of item */ +}; + +struct sndrv_ctl_elem_list { + unsigned int offset; /* W: first element ID to get */ + unsigned int space; /* W: count of element IDs to get */ + unsigned int used; /* R: count of element IDs set */ + unsigned int count; /* R: count of all elements */ + struct sndrv_ctl_elem_id *pids; /* R: IDs */ + unsigned char reserved[50]; +}; + +struct sndrv_ctl_elem_info { + struct sndrv_ctl_elem_id id; /* W: element ID */ + int type; /* R: value type - SNDRV_CTL_ELEM_TYPE_* */ + unsigned int access; /* R: value access (bitmask) - SNDRV_CTL_ELEM_ACCESS_* */ + unsigned int count; /* count of values */ + pid_t owner; /* owner's PID of this control */ + union { + struct { + long min; /* R: minimum value */ + long max; /* R: maximum value */ + long step; /* R: step (0 variable) */ + } integer; + struct { + long long min; /* R: minimum value */ + long long max; /* R: maximum value */ + long long step; /* R: step (0 variable) */ + } integer64; + struct { + unsigned int items; /* R: number of items */ + unsigned int item; /* W: item number */ + char name[64]; /* R: value name */ + } enumerated; + unsigned char reserved[128]; + } value; + union { + unsigned short d[4]; /* dimensions */ + unsigned short *d_ptr; /* indirect */ + } dimen; + unsigned char reserved[64-4*sizeof(unsigned short)]; +}; + +struct sndrv_ctl_elem_value { + struct sndrv_ctl_elem_id id; /* W: element ID */ + unsigned int indirect: 1; /* W: use indirect pointer (xxx_ptr member) */ + union { + union { + long value[128]; + long *value_ptr; + } integer; + union { + long long value[64]; + long long *value_ptr; + } integer64; + union { + unsigned int item[128]; + unsigned int *item_ptr; + } enumerated; + union { + unsigned char data[512]; + unsigned char *data_ptr; + } bytes; + struct sndrv_aes_iec958 iec958; + } value; /* RO */ + struct timespec tstamp; + unsigned char reserved[128-sizeof(struct timespec)]; +}; + +struct sndrv_ctl_tlv { + unsigned int numid; /* control element numeric identification */ + unsigned int length; /* in bytes aligned to 4 */ + unsigned int tlv[0]; /* first TLV */ +}; + +enum sndrv_ctl_event_type { + SNDRV_CTL_EVENT_ELEM = 0, + SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM, +}; + +struct sndrv_ctl_event { + int type; /* event type - SNDRV_CTL_EVENT_* */ + union { + struct { + unsigned int mask; + struct sndrv_ctl_elem_id id; + } elem; + unsigned char data8[60]; + } data; +}; + +struct sndrv_xferv { + const struct iovec *vector; + unsigned long count; +}; + +typedef struct { + unsigned int internal_tram_size; /* in samples */ + unsigned int external_tram_size; /* in samples */ + char fxbus_names[16][32]; /* names of FXBUSes */ + char extin_names[16][32]; /* names of external inputs */ + char extout_names[32][32]; /* names of external outputs */ + unsigned int gpr_controls; /* count of GPR controls */ +} emu10k1_fx8010_info_t; + +enum emu10k1_ctl_elem_iface { + EMU10K1_CTL_ELEM_IFACE_MIXER = 2, /* virtual mixer device */ + EMU10K1_CTL_ELEM_IFACE_PCM = 3, /* PCM device */ +}; + +typedef struct { + unsigned int pad; /* don't use */ + int iface; /* interface identifier */ + unsigned int device; /* device/client number */ + unsigned int subdevice; /* subdevice (substream) number */ + unsigned char name[44]; /* ASCII name of item */ + unsigned int index; /* index of item */ +} emu10k1_ctl_elem_id_t; + +typedef struct { + emu10k1_ctl_elem_id_t id; /* full control ID definition */ + unsigned int vcount; /* visible count */ + unsigned int count; /* count of GPR (1..16) */ + unsigned short gpr[32]; /* GPR number(s) */ + unsigned int value[32]; /* initial values */ + unsigned int min; /* minimum range */ + unsigned int max; /* maximum range */ + unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */ + unsigned int *tlv; +} emu10k1_fx8010_control_gpr_t; + +typedef struct { + char name[128]; + + unsigned long gpr_valid[0x200/(sizeof(unsigned long)*8)]; /* bitmask of valid initializers */ + uint32_t *gpr_map; /* initializers */ + + unsigned int gpr_add_control_count; /* count of GPR controls to add/replace */ + emu10k1_fx8010_control_gpr_t *gpr_add_controls; /* GPR controls to add/replace */ + + unsigned int gpr_del_control_count; /* count of GPR controls to remove */ + emu10k1_ctl_elem_id_t *gpr_del_controls; /* IDs of GPR controls to remove */ + + unsigned int gpr_list_control_count; /* count of GPR controls to list */ + unsigned int gpr_list_control_total; /* total count of GPR controls */ + emu10k1_fx8010_control_gpr_t *gpr_list_controls; /* listed GPR controls */ + + unsigned long tram_valid[0x100/(sizeof(unsigned long)*8)]; /* bitmask of valid initializers */ + uint32_t *tram_data_map; /* data initializers */ + uint32_t *tram_addr_map; /* map initializers */ + + unsigned long code_valid[1024/(sizeof(unsigned long)*8)]; /* bitmask of valid instructions */ + uint32_t *code; /* one instruction - 64 bits */ +} emu10k1_fx8010_code_t; + +typedef struct { + unsigned int address; /* 31.bit == 1 -> external TRAM */ + unsigned int size; /* size in samples (4 bytes) */ + unsigned int *samples; /* pointer to samples (20-bit) */ + /* NULL->clear memory */ +} emu10k1_fx8010_tram_t; + +typedef struct { + unsigned int substream; /* substream number */ + unsigned int res1; /* reserved */ + unsigned int channels; /* 16-bit channels count, zero = remove this substream */ + unsigned int tram_start; /* ring buffer position in TRAM (in samples) */ + unsigned int buffer_size; /* count of buffered samples */ + unsigned short gpr_size; /* GPR containing size of ringbuffer in samples (host) */ + unsigned short gpr_ptr; /* GPR containing current pointer in the ring buffer (host = reset, FX8010) */ + unsigned short gpr_count; /* GPR containing count of samples between two interrupts (host) */ + unsigned short gpr_tmpcount; /* GPR containing current count of samples to interrupt (host = set, FX8010) */ + unsigned short gpr_trigger; /* GPR containing trigger (activate) information (host) */ + unsigned short gpr_running; /* GPR containing info if PCM is running (FX8010) */ + unsigned char pad; /* reserved */ + unsigned char etram[32]; /* external TRAM address & data (one per channel) */ + unsigned int res2; /* reserved */ +} emu10k1_fx8010_pcm_t; + +typedef enum { + Digiface, + Multiface, + H9652, + H9632, + Undefined, +} HDSP_IO_Type; + +typedef struct _snd_hdsp_peak_rms hdsp_peak_rms_t; + +struct _snd_hdsp_peak_rms { + uint32_t input_peaks[26]; + uint32_t playback_peaks[26]; + uint32_t output_peaks[28]; + uint64_t input_rms[26]; + uint64_t playback_rms[26]; + /* These are only used for H96xx cards */ + uint64_t output_rms[26]; +}; + +typedef struct _snd_hdsp_config_info hdsp_config_info_t; + +struct _snd_hdsp_config_info { + unsigned char pref_sync_ref; + unsigned char wordclock_sync_check; + unsigned char spdif_sync_check; + unsigned char adatsync_sync_check; + unsigned char adat_sync_check[3]; + unsigned char spdif_in; + unsigned char spdif_out; + unsigned char spdif_professional; + unsigned char spdif_emphasis; + unsigned char spdif_nonaudio; + unsigned int spdif_sample_rate; + unsigned int system_sample_rate; + unsigned int autosync_sample_rate; + unsigned char system_clock_mode; + unsigned char clock_source; + unsigned char autosync_ref; + unsigned char line_out; + unsigned char passthru; + unsigned char da_gain; + unsigned char ad_gain; + unsigned char phone_gain; + unsigned char xlr_breakout_cable; + unsigned char analog_extension_board; +}; + +typedef struct _snd_hdsp_firmware hdsp_firmware_t; + +struct _snd_hdsp_firmware { + void *firmware_data; /* 24413 x 4 bytes */ +}; + +typedef struct _snd_hdsp_version hdsp_version_t; + +struct _snd_hdsp_version { + HDSP_IO_Type io_type; + unsigned short firmware_rev; +}; + +typedef struct _snd_hdsp_mixer hdsp_mixer_t; + +struct _snd_hdsp_mixer { + unsigned short matrix[HDSP_MATRIX_MIXER_SIZE]; +}; + +typedef struct _snd_hdsp_9632_aeb hdsp_9632_aeb_t; + +struct _snd_hdsp_9632_aeb { + int aebi; + int aebo; +}; + +typedef struct snd_sb_csp_mc_header { + char codec_name[16]; /* id name of codec */ + unsigned short func_req; /* requested function */ +} snd_sb_csp_mc_header_t; + +typedef struct snd_sb_csp_microcode { + snd_sb_csp_mc_header_t info; + unsigned char data[SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE]; +} snd_sb_csp_microcode_t; + +typedef struct snd_sb_csp_start { + int sample_width; /* sample width, look above */ + int channels; /* channels, look above */ +} snd_sb_csp_start_t; + +typedef struct snd_sb_csp_info { + char codec_name[16]; /* id name of codec */ + unsigned short func_nr; /* function number */ + unsigned int acc_format; /* accepted PCM formats */ + unsigned short acc_channels; /* accepted channels */ + unsigned short acc_width; /* accepted sample width */ + unsigned short acc_rates; /* accepted sample rates */ + unsigned short csp_mode; /* CSP mode, see above */ + unsigned short run_channels; /* current channels */ + unsigned short run_width; /* current sample width */ + unsigned short version; /* version id: 0x10 - 0x1f */ + unsigned short state; /* state bits */ +} snd_sb_csp_info_t; + +struct sscape_bootblock +{ + unsigned char code[256]; + unsigned version; +}; + +struct sscape_microcode +{ + unsigned char *code; +}; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 9e2b3c200a..b090cdb466 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2545,6 +2545,8 @@ struct target_ucred { uint32_t gid; }; +#include "ioctls_alsa_structs.h" + #endif typedef int32_t target_timer_t; diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 1fd4ee0bfd..e5331b4495 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -83,6 +83,11 @@ STRUCT(buffmem_desc, STRUCT(mixer_info, MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10)) +/* FIXME: including these on x86 / x86_64 breaks qemu-i386 */ +#ifdef __powerpc__ +#include "syscall_types_alsa.h" +#endif + /* loop device ioctls */ STRUCT(loop_info, TYPE_INT, /* lo_number */ diff --git a/linux-user/syscall_types_alsa.h b/linux-user/syscall_types_alsa.h new file mode 100644 index 0000000000..72622ae9a2 --- /dev/null +++ b/linux-user/syscall_types_alsa.h @@ -0,0 +1,1336 @@ +/* + * Advanced Linux Sound Architecture + * + * This program is free software, you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * aTYPE_LONG, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +STRUCT (sndrv_pcm_sframes, TYPE_LONG) +STRUCT (sndrv_seq_event_type, TYPE_CHAR) +STRUCT (sndrv_seq_instr_cluster, TYPE_INT) +STRUCT (sndrv_seq_position, TYPE_INT) +STRUCT (sndrv_seq_frequency, TYPE_INT) +STRUCT (sndrv_seq_tick_time, TYPE_INT) +STRUCT (sndrv_seq_instr_size, TYPE_INT) +STRUCT (sndrv_pcm_uframes, TYPE_ULONG) + + +STRUCT (timespec, + TYPE_LONG, + TYPE_LONG + ) + +STRUCT( fm_operator, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR +) + +STRUCT(fm_instrument, + MK_ARRAY(TYPE_INT, 4), /* share id - zero = no sharing */ + TYPE_CHAR, /* instrument type */ + + MK_ARRAY(MK_STRUCT(STRUCT_fm_operator), 4), + MK_ARRAY(TYPE_CHAR, 2), + + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR +) + +STRUCT( fm_xoperator, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR +) + +STRUCT( fm_xinstrument, + TYPE_INT, /* structure type */ + + MK_ARRAY(TYPE_INT, 4), /* share id - zero = no sharing */ + TYPE_CHAR, /* instrument type */ + + MK_ARRAY(MK_STRUCT(STRUCT_fm_xoperator), 4), /* fm operators */ + MK_ARRAY(TYPE_CHAR, 2), + + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR +) + +STRUCT( gf1_wave, + MK_ARRAY(TYPE_INT, 4), /* share id - zero = no sharing */ + TYPE_INT, /* wave format */ + + TYPE_INT, /* some other ID for this instrument */ + TYPE_INT, /* begin of waveform in onboard memory */ + TYPE_PTRVOID, /* poTYPE_INTer to waveform in system memory */ + + TYPE_INT, /* size of waveform in samples */ + TYPE_INT, /* start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_SHORT, /* loop repeat - 0 = forever */ + + TYPE_CHAR, /* GF1 patch flags */ + TYPE_CHAR, + TYPE_INT, /* sample rate in Hz */ + TYPE_INT, /* low frequency range */ + TYPE_INT, /* high frequency range */ + TYPE_INT, /* root frequency range */ + TYPE_SHORT, + TYPE_CHAR, + MK_ARRAY(TYPE_CHAR, 6), + MK_ARRAY(TYPE_CHAR, 6), + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_SHORT, + TYPE_SHORT, /* 0-2048 or 0-2 */ + + TYPE_PTRVOID +) + +STRUCT(gf1_instrument, + TYPE_SHORT, + TYPE_SHORT, /* 0 - none, 1-65535 */ + + TYPE_CHAR, /* effect 1 */ + TYPE_CHAR, /* 0-127 */ + TYPE_CHAR, /* effect 2 */ + TYPE_CHAR, /* 0-127 */ + + TYPE_PTRVOID /* first waveform */ +) + +STRUCT( gf1_xwave, + TYPE_INT, /* structure type */ + + MK_ARRAY(TYPE_INT, 4), /* share id - zero = no sharing */ + TYPE_INT, /* wave format */ + + TYPE_INT, /* size of waveform in samples */ + TYPE_INT, /* start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_SHORT, /* loop repeat - 0 = forever */ + + TYPE_CHAR, /* GF1 patch flags */ + TYPE_CHAR, + TYPE_INT, /* sample rate in Hz */ + TYPE_INT, /* low frequency range */ + TYPE_INT, /* high frequency range */ + TYPE_INT, /* root frequency range */ + TYPE_SHORT, + TYPE_CHAR, + MK_ARRAY(TYPE_CHAR, 6), + MK_ARRAY(TYPE_CHAR, 6), + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_SHORT, + TYPE_SHORT /* 0-2048 or 0-2 */ +) + +STRUCT( gf1_xinstrument, + TYPE_INT, + + TYPE_SHORT, + TYPE_SHORT, /* 0 - none, 1-65535 */ + + TYPE_CHAR, /* effect 1 */ + TYPE_CHAR, /* 0-127 */ + TYPE_CHAR, /* effect 2 */ + TYPE_CHAR /* 0-127 */ +) + +STRUCT( gf1_info, + TYPE_CHAR, /* supported wave flags */ + MK_ARRAY(TYPE_CHAR, 3), + TYPE_INT, /* supported features */ + TYPE_INT, /* maximum 8-bit wave length */ + TYPE_INT /* maximum 16-bit wave length */ +) + +STRUCT( iwffff_wave, + MK_ARRAY(TYPE_INT, 4), /* share id - zero = no sharing */ + TYPE_INT, /* wave format */ + + TYPE_INT, /* some other ID for this wave */ + TYPE_INT, /* begin of waveform in onboard memory */ + TYPE_PTRVOID, /* poTYPE_INTer to waveform in system memory */ + + TYPE_INT, /* size of waveform in samples */ + TYPE_INT, /* start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_SHORT, /* loop repeat - 0 = forever */ + TYPE_INT, /* sample ratio (44100 * 1024 / rate) */ + TYPE_CHAR, /* 0 - 127 (no corresponding midi controller) */ + TYPE_CHAR, /* lower frequency range for this waveform */ + TYPE_CHAR, /* higher frequency range for this waveform */ + TYPE_CHAR, + + TYPE_PTRVOID +) + +STRUCT( iwffff_lfo, + TYPE_SHORT, /* (0-2047) 0.01Hz - 21.5Hz */ + TYPE_SHORT, /* volume +- (0-255) 0.48675dB/step */ + TYPE_SHORT, /* 0 - 950 deciseconds */ + TYPE_CHAR, /* see to IWFFFF_LFO_SHAPE_XXXX */ + TYPE_CHAR /* 0 - 255 deciseconds */ +) + +STRUCT( iwffff_env_point, + TYPE_SHORT, + TYPE_SHORT +) + +STRUCT( iwffff_env_record, + TYPE_SHORT, + TYPE_SHORT, + TYPE_SHORT, + TYPE_SHORT, + TYPE_SHORT, + TYPE_CHAR, + TYPE_CHAR, + TYPE_PTRVOID +) + +STRUCT( iwffff_env, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_PTRVOID // MK_STRUCT(STRUCT_iwffff_env_record) +) + +STRUCT( iwffff_layer, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, /* range for layer based */ + TYPE_CHAR, /* on either velocity or frequency */ + TYPE_CHAR, /* pan offset from CC1 (0 left - 127 right) */ + TYPE_CHAR, /* position based on frequency (0-127) */ + TYPE_CHAR, /* 0-127 (no corresponding midi controller) */ + MK_STRUCT(STRUCT_iwffff_lfo), /* tremolo effect */ + MK_STRUCT(STRUCT_iwffff_lfo), /* vibrato effect */ + TYPE_SHORT, /* 0-2048, 1024 is equal to semitone scaling */ + TYPE_CHAR, /* center for keyboard frequency scaling */ + TYPE_CHAR, + MK_STRUCT(STRUCT_iwffff_env), /* pitch envelope */ + MK_STRUCT(STRUCT_iwffff_env), /* volume envelope */ + + TYPE_PTRVOID, // iwffff_wave_t *wave, + TYPE_PTRVOID // MK_STRUCT(STRUCT_iwffff_layer) +) + +STRUCT(iwffff_instrument, + TYPE_SHORT, + TYPE_SHORT, + TYPE_SHORT, /* 0 - none, 1-65535 */ + + TYPE_CHAR, /* effect 1 */ + TYPE_CHAR, /* 0-127 */ + TYPE_CHAR, /* effect 2 */ + TYPE_CHAR, /* 0-127 */ + + TYPE_PTRVOID // iwffff_layer_t *layer, /* first layer */ +) + +STRUCT( iwffff_xwave, + TYPE_INT, /* structure type */ + + MK_ARRAY(TYPE_INT, 4), /* share id - zero = no sharing */ + + TYPE_INT, /* wave format */ + TYPE_INT, /* offset to ROM (address) */ + + TYPE_INT, /* size of waveform in samples */ + TYPE_INT, /* start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_SHORT, /* loop repeat - 0 = forever */ + TYPE_INT, /* sample ratio (44100 * 1024 / rate) */ + TYPE_CHAR, /* 0 - 127 (no corresponding midi controller) */ + TYPE_CHAR, /* lower frequency range for this waveform */ + TYPE_CHAR, /* higher frequency range for this waveform */ + TYPE_CHAR +) + +STRUCT( iwffff_xlfo, + TYPE_SHORT, /* (0-2047) 0.01Hz - 21.5Hz */ + TYPE_SHORT, /* volume +- (0-255) 0.48675dB/step */ + TYPE_SHORT, /* 0 - 950 deciseconds */ + TYPE_CHAR, /* see to ULTRA_IW_LFO_SHAPE_XXXX */ + TYPE_CHAR /* 0 - 255 deciseconds */ +) + +STRUCT( iwffff_xenv_point, + TYPE_SHORT, + TYPE_SHORT +) + +STRUCT( iwffff_xenv_record, + TYPE_INT, + TYPE_SHORT, + TYPE_SHORT, + TYPE_SHORT, + TYPE_SHORT, + TYPE_SHORT, + TYPE_CHAR, + TYPE_CHAR +) + +STRUCT( iwffff_xenv, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR +) + +STRUCT( iwffff_xlayer, + TYPE_INT, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, /* range for layer based */ + TYPE_CHAR, /* on either velocity or frequency */ + TYPE_CHAR, /* pan offset from CC1 (0 left - 127 right) */ + TYPE_CHAR, /* position based on frequency (0-127) */ + TYPE_CHAR, /* 0-127 (no corresponding midi controller) */ + MK_STRUCT(STRUCT_iwffff_xlfo), /* tremolo effect */ + MK_STRUCT(STRUCT_iwffff_xlfo), /* vibrato effect */ + TYPE_SHORT, /* 0-2048, 1024 is equal to semitone scaling */ + TYPE_CHAR, /* center for keyboard frequency scaling */ + TYPE_CHAR, + MK_STRUCT(STRUCT_iwffff_xenv), /* pitch envelope */ + MK_STRUCT(STRUCT_iwffff_xenv) /* volume envelope */ +) + +STRUCT( iwffff_xinstrument, + TYPE_INT, + + TYPE_SHORT, + TYPE_SHORT, + TYPE_SHORT, /* 0 - none, 1-65535 */ + + TYPE_CHAR, /* effect 1 */ + TYPE_CHAR, /* 0-127 */ + TYPE_CHAR, /* effect 2 */ + TYPE_CHAR /* 0-127 */ +) + +STRUCT(iwffff_rom_header, + MK_ARRAY(TYPE_CHAR, 8), + TYPE_CHAR, + TYPE_CHAR, + MK_ARRAY(TYPE_CHAR, 16), + MK_ARRAY(TYPE_CHAR, 10), + TYPE_SHORT, + TYPE_SHORT, + TYPE_INT, + MK_ARRAY(TYPE_CHAR, 128), + MK_ARRAY(TYPE_CHAR, 64), + MK_ARRAY(TYPE_CHAR, 128) +) + +STRUCT( iwffff_info, + TYPE_INT, /* supported format bits */ + TYPE_INT, /* supported effects (1 << IWFFFF_EFFECT*) */ + TYPE_INT, /* LFO effects */ + TYPE_INT, /* maximum 8-bit wave length */ + TYPE_INT /* maximum 16-bit wave length */ +) + +STRUCT( simple_instrument_info, + TYPE_INT, /* supported format bits */ + TYPE_INT, /* supported effects (1 << SIMPLE_EFFECT_*) */ + TYPE_INT, /* maximum 8-bit wave length */ + TYPE_INT /* maximum 16-bit wave length */ +) + +STRUCT(simple_instrument, + MK_ARRAY(TYPE_INT, 4), /* share id - zero = no sharing */ + TYPE_INT, /* wave format */ + + TYPE_INT, /* some other ID for this instrument */ + TYPE_INT, /* begin of waveform in onboard memory */ + TYPE_PTRVOID, /* poTYPE_INTer to waveform in system memory */ + + TYPE_INT, /* size of waveform in samples */ + TYPE_INT, /* start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* loop end offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_SHORT, /* loop repeat - 0 = forever */ + + TYPE_CHAR, /* effect 1 */ + TYPE_CHAR, /* 0-127 */ + TYPE_CHAR, /* effect 2 */ + TYPE_CHAR /* 0-127 */ +) + +STRUCT( simple_xinstrument, + TYPE_INT, + + MK_ARRAY(TYPE_INT, 4), /* share id - zero = no sharing */ + TYPE_INT, /* wave format */ + + TYPE_INT, /* size of waveform in samples */ + TYPE_INT, /* start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_INT, /* loop start offset in samples * 16 (lowest 4 bits - fraction) */ + TYPE_SHORT, /* loop repeat - 0 = forever */ + + TYPE_CHAR, /* effect 1 */ + TYPE_CHAR, /* 0-127 */ + TYPE_CHAR, /* effect 2 */ + TYPE_CHAR /* 0-127 */ +) + +/** event address */ +STRUCT( sndrv_seq_addr, + TYPE_CHAR, /**< Client number: 0..255, 255 = broadcast to all clients */ + TYPE_CHAR /**< Port within client: 0..255, 255 = broadcast to all ports */ +) + +/** port connection */ +STRUCT( sndrv_seq_connect, + MK_STRUCT(STRUCT_sndrv_seq_addr), + MK_STRUCT(STRUCT_sndrv_seq_addr) +) + +STRUCT( sndrv_seq_ev_note, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, /* only for SNDRV_SEQ_EVENT_NOTE */ + TYPE_INT /* only for SNDRV_SEQ_EVENT_NOTE */ +) + + /* controller event */ +STRUCT( sndrv_seq_ev_ctrl, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, /* pad */ + TYPE_INT, + TYPE_INT +) + + /* generic set of bytes (12x8 bit) */ +STRUCT( sndrv_seq_ev_raw8, + MK_ARRAY(TYPE_CHAR, 12) /* 8 bit value */ +) + + /* generic set of TYPE_INTegers (3x32 bit) */ +STRUCT( sndrv_seq_ev_raw32, + MK_ARRAY(TYPE_INT, 3) /* 32 bit value */ +) + + /* external stored data */ +STRUCT( sndrv_seq_ev_ext, + TYPE_INT, /* length of data */ + TYPE_PTRVOID /* poTYPE_INTer to data (note: maybe 64-bit) */ +) + +/* Instrument type */ +STRUCT( sndrv_seq_instr, + TYPE_INT, + TYPE_INT, /* the upper byte means a private instrument (owner - client #) */ + TYPE_SHORT, + TYPE_SHORT +) + + /* sample number */ +STRUCT( sndrv_seq_ev_sample, + TYPE_INT, + TYPE_SHORT, + TYPE_SHORT +) + + /* sample cluster */ +STRUCT( sndrv_seq_ev_cluster, + TYPE_INT +) + + /* sample volume control, if any value is set to -1 == do not change */ +STRUCT( sndrv_seq_ev_volume, + TYPE_SHORT, /* range: 0-16383 */ + TYPE_SHORT, /* left-right balance, range: 0-16383 */ + TYPE_SHORT, /* front-rear balance, range: 0-16383 */ + TYPE_SHORT /* down-up balance, range: 0-16383 */ +) + + /* simple loop redefinition */ +STRUCT( sndrv_seq_ev_loop, + TYPE_INT, /* loop start (in samples) * 16 */ + TYPE_INT /* loop end (in samples) * 16 */ +) + +STRUCT( sndrv_seq_ev_sample_control, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, /* pad */ + MK_ARRAY(TYPE_INT, 2) +) + + + +/* INSTR_BEGIN event */ +STRUCT( sndrv_seq_ev_instr_begin, + TYPE_INT +) + +STRUCT( sndrv_seq_result, + TYPE_INT, + TYPE_INT +) + + +STRUCT( sndrv_seq_real_time, + TYPE_INT, + TYPE_INT +) + +STRUCT( sndrv_seq_queue_skew, + TYPE_INT, + TYPE_INT +) + + /* queue timer control */ +STRUCT( sndrv_seq_ev_queue_control, + TYPE_CHAR, /* affected queue */ + MK_ARRAY(TYPE_CHAR, 3), /* reserved */ + MK_ARRAY(TYPE_INT, 2) +) + + /* quoted event - inside the kernel only */ +STRUCT( sndrv_seq_ev_quote, + MK_STRUCT(STRUCT_sndrv_seq_addr), /* original sender */ + TYPE_SHORT, /* optional data */ + MK_STRUCT(STRUCT_sndrv_seq_event) /* quoted event */ +) + + + /* sequencer event */ +STRUCT( sndrv_seq_event, + TYPE_CHAR, /* event type */ + TYPE_CHAR, /* event flags */ + TYPE_CHAR, + + TYPE_CHAR, /* schedule queue */ + MK_STRUCT(STRUCT_sndrv_seq_real_time), /* schedule time */ + + + MK_STRUCT(STRUCT_sndrv_seq_addr), /* source address */ + MK_STRUCT(STRUCT_sndrv_seq_addr), /* destination address */ + + MK_ARRAY(TYPE_INT,3) +) + + +/* + * bounce event - stored as variable size data + */ +STRUCT( sndrv_seq_event_bounce, + TYPE_INT, + MK_STRUCT(STRUCT_sndrv_seq_event) + /* external data follows here. */ +) + +STRUCT( sndrv_seq_system_info, + TYPE_INT, /* maximum queues count */ + TYPE_INT, /* maximum clients count */ + TYPE_INT, /* maximum ports per client */ + TYPE_INT, /* maximum channels per port */ + TYPE_INT, /* current clients */ + TYPE_INT, /* current queues */ + MK_ARRAY(TYPE_CHAR, 24) +) + +STRUCT( sndrv_seq_running_info, + TYPE_CHAR, /* client id */ + TYPE_CHAR, /* 1 = big-endian */ + TYPE_CHAR, + TYPE_CHAR, /* reserved */ + MK_ARRAY(TYPE_CHAR, 12) +) + +STRUCT( sndrv_seq_client_info, + TYPE_INT, /* client number to inquire */ + TYPE_INT, /* client type */ + MK_ARRAY(TYPE_CHAR, 64), /* client name */ + TYPE_INT, /* filter flags */ + MK_ARRAY(TYPE_CHAR, 8), /* multicast filter bitmap */ + MK_ARRAY(TYPE_CHAR, 32), /* event filter bitmap */ + TYPE_INT, /* RO: number of ports */ + TYPE_INT, /* number of lost events */ + MK_ARRAY(TYPE_CHAR, 64) /* for future use */ +) + +STRUCT( sndrv_seq_client_pool, + TYPE_INT, /* client number to inquire */ + TYPE_INT, /* outgoing (write) pool size */ + TYPE_INT, /* incoming (read) pool size */ + TYPE_INT, /* minimum free pool size for select/blocking mode */ + TYPE_INT, /* unused size */ + TYPE_INT, /* unused size */ + MK_ARRAY(TYPE_CHAR, 64) +) + +STRUCT( sndrv_seq_remove_events, + TYPE_INT, /* Flags that determine what gets removed */ + + MK_STRUCT(STRUCT_sndrv_seq_real_time), + + TYPE_CHAR, /* Queue for REMOVE_DEST */ + MK_STRUCT(STRUCT_sndrv_seq_addr), /* Address for REMOVE_DEST */ + TYPE_CHAR, /* Channel for REMOVE_DEST */ + + TYPE_INT, /* For REMOVE_EVENT_TYPE */ + TYPE_CHAR, /* Tag for REMOVE_TAG */ + + MK_ARRAY(TYPE_INT, 10) /* To allow for future binary compatibility */ + +) + +STRUCT( sndrv_seq_port_info, + MK_STRUCT(STRUCT_sndrv_seq_addr), /* client/port numbers */ + MK_ARRAY(TYPE_CHAR, 64), /* port name */ + + TYPE_INT, /* port capability bits */ + TYPE_INT, /* port type bits */ + TYPE_INT, /* channels per MIDI port */ + TYPE_INT, /* voices per MIDI port */ + TYPE_INT, /* voices per SYNTH port */ + + TYPE_INT, /* R/O: subscribers for output (from this port) */ + TYPE_INT, /* R/O: subscribers for input (to this port) */ + + TYPE_PTRVOID, /* reserved for kernel use (must be NULL) */ + TYPE_INT, /* misc. conditioning */ + TYPE_CHAR, /* queue # for timestamping */ + MK_ARRAY(TYPE_CHAR, 59) /* for future use */ +) + +STRUCT( sndrv_seq_queue_info, + TYPE_INT, /* queue id */ + + /* + * security settings, only owner of this queue can start/stop timer + * etc. if the queue is locked for other clients + */ + TYPE_INT, /* client id for owner of the queue */ + TYPE_INT, /* timing queue locked for other queues */ + MK_ARRAY(TYPE_CHAR, 64), /* name of this queue */ + TYPE_INT, /* flags */ + MK_ARRAY(TYPE_CHAR, 60) /* for future use */ + +) + +STRUCT( sndrv_seq_queue_status, + TYPE_INT, /* queue id */ + TYPE_INT, /* read-only - queue size */ + TYPE_INT, /* current tick */ + MK_STRUCT(STRUCT_sndrv_seq_real_time), /* current time */ + TYPE_INT, /* running state of queue */ + TYPE_INT, /* various flags */ + MK_ARRAY(TYPE_CHAR, 64) /* for the future */ +) + +STRUCT( sndrv_seq_queue_tempo, + TYPE_INT, /* sequencer queue */ + TYPE_INT, + TYPE_INT, + TYPE_INT, /* queue skew */ + TYPE_INT, /* queue skew base */ + MK_ARRAY(TYPE_CHAR, 24) /* for the future */ +) + +STRUCT( sndrv_timer_id, + TYPE_INT, + TYPE_INT, + TYPE_INT, + TYPE_INT, + TYPE_INT +) + +STRUCT( sndrv_seq_queue_timer, + TYPE_INT, /* sequencer queue */ + TYPE_INT, /* source timer type */ + MK_STRUCT(STRUCT_sndrv_timer_id), /* ALSA's timer ID */ + TYPE_INT, /* resolution in Hz */ + MK_ARRAY(TYPE_CHAR, 64) /* for the future use */ +) + +STRUCT( sndrv_seq_queue_client, + TYPE_INT, /* sequencer queue */ + TYPE_INT, /* sequencer client */ + TYPE_INT, /* queue is used with this client + (must be set for accepting events) */ + /* per client watermarks */ + MK_ARRAY(TYPE_CHAR, 64) /* for future use */ +) + +STRUCT( sndrv_seq_port_subscribe, + MK_STRUCT(STRUCT_sndrv_seq_addr), /* sender address */ + MK_STRUCT(STRUCT_sndrv_seq_addr), /* destination address */ + TYPE_INT, /* number of voices to be allocated (0 = don't care) */ + TYPE_INT, /* modes */ + TYPE_CHAR, /* input time-stamp queue (optional) */ + MK_ARRAY(TYPE_CHAR, 3), /* reserved */ + MK_ARRAY(TYPE_CHAR, 64) +) + +STRUCT( sndrv_seq_query_subs, + MK_STRUCT(STRUCT_sndrv_seq_addr), /* client/port id to be searched */ + TYPE_INT, /* READ or WRITE */ + TYPE_INT, /* 0..N-1 */ + TYPE_INT, /* R/O: number of subscriptions on this port */ + MK_STRUCT(STRUCT_sndrv_seq_addr), /* R/O: result */ + TYPE_CHAR, /* R/O: result */ + TYPE_INT, /* R/O: result */ + MK_ARRAY(TYPE_CHAR, 64) /* for future use */ +) + +STRUCT( sndrv_seq_instr_info, + TYPE_INT, /* operation result */ + MK_ARRAY(TYPE_INT, 8), /* bitmap of supported formats */ + TYPE_INT, /* count of RAM banks */ + MK_ARRAY(TYPE_INT, 16), /* size of RAM banks */ + TYPE_INT, /* count of ROM banks */ + MK_ARRAY(TYPE_INT, 8), /* size of ROM banks */ + MK_ARRAY(TYPE_CHAR, 128) +) + +STRUCT( sndrv_seq_instr_status, + TYPE_INT, /* operation result */ + MK_ARRAY(TYPE_INT, 16), /* free RAM in banks */ + TYPE_INT, /* count of downloaded instruments */ + MK_ARRAY(TYPE_CHAR, 128) +) + +STRUCT( sndrv_seq_instr_format_info, + MK_ARRAY(TYPE_CHAR, 16), /* format identifier - SNDRV_SEQ_INSTR_ID_* */ + TYPE_INT /* max data length (without this structure) */ +) + +STRUCT( sndrv_seq_instr_format_info_result, + TYPE_INT, /* operation result */ + MK_ARRAY(TYPE_CHAR, 16), /* format identifier */ + TYPE_INT /* filled data length (without this structure) */ +) + +STRUCT( sndrv_seq_instr_data, + MK_ARRAY(TYPE_CHAR, 32), /* instrument name */ + MK_ARRAY(TYPE_CHAR, 16), /* for the future use */ + TYPE_INT, /* instrument type */ + MK_STRUCT(STRUCT_sndrv_seq_instr), + MK_ARRAY(TYPE_CHAR, 4) /* fillup */ +) + +STRUCT( sndrv_seq_instr_header, + MK_STRUCT(STRUCT_sndrv_seq_instr), + TYPE_INT, /* get/put/free command */ + TYPE_INT, /* query flags (only for get) */ + TYPE_INT, /* real instrument data length (without header) */ + TYPE_INT, /* operation result */ + MK_ARRAY(TYPE_CHAR, 16), /* for the future */ + MK_STRUCT(STRUCT_sndrv_seq_instr_data) /* instrument data (for put/get result) */ +) + +STRUCT( sndrv_seq_instr_cluster_set, + TYPE_INT, /* cluster identifier */ + MK_ARRAY(TYPE_CHAR, 32), /* cluster name */ + TYPE_INT, /* cluster priority */ + MK_ARRAY(TYPE_CHAR, 64) /* for the future use */ +) + +STRUCT( sndrv_seq_instr_cluster_get, + TYPE_INT, /* cluster identifier */ + MK_ARRAY(TYPE_CHAR, 32), /* cluster name */ + TYPE_INT, /* cluster priority */ + MK_ARRAY(TYPE_CHAR, 64) /* for the future use */ +) + +STRUCT( snd_dm_fm_info, + TYPE_CHAR, + TYPE_CHAR +) + +STRUCT( snd_dm_fm_voice, + TYPE_CHAR, /* operator cell (0 or 1) */ + TYPE_CHAR, /* FM voice (0 to 17) */ + + TYPE_CHAR, /* amplitude modulation */ + TYPE_CHAR, /* vibrato effect */ + TYPE_CHAR, /* sustain phase */ + TYPE_CHAR, /* keyboard scaling */ + TYPE_CHAR, /* 4 bits: harmonic and multiplier */ + TYPE_CHAR, /* 2 bits: decrease output freq rises */ + TYPE_CHAR, /* 6 bits: volume */ + + TYPE_CHAR, /* 4 bits: attack rate */ + TYPE_CHAR, /* 4 bits: decay rate */ + TYPE_CHAR, /* 4 bits: sustain level */ + TYPE_CHAR, /* 4 bits: release rate */ + + TYPE_CHAR, /* 3 bits: feedback for op0 */ + TYPE_CHAR, + TYPE_CHAR, /* stereo left */ + TYPE_CHAR, /* stereo right */ + TYPE_CHAR /* 3 bits: waveform shape */ +) + +STRUCT( snd_dm_fm_note, + TYPE_CHAR, /* 0-17 voice channel */ + TYPE_CHAR, /* 3 bits: what octave to play */ + TYPE_INT, /* 10 bits: frequency number */ + TYPE_CHAR +) + +STRUCT( snd_dm_fm_params, + TYPE_CHAR, /* amplitude modulation depth (1=hi) */ + TYPE_CHAR, /* vibrato depth (1=hi) */ + TYPE_CHAR, /* keyboard split */ + TYPE_CHAR, /* percussion mode select */ + + /* This block is the percussion instrument data */ + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR +) + +STRUCT( sndrv_aes_iec958, + MK_ARRAY(TYPE_CHAR, 24), /* AES/IEC958 channel status bits */ + MK_ARRAY(TYPE_CHAR, 147), /* AES/IEC958 subcode bits */ + TYPE_CHAR, /* nothing */ + MK_ARRAY(TYPE_CHAR, 4) /* AES/IEC958 subframe bits */ +) + +STRUCT( sndrv_hwdep_info, + TYPE_INT, /* WR: device number */ + TYPE_INT, /* R: card number */ + MK_ARRAY(TYPE_CHAR, 64), /* ID (user selectable) */ + MK_ARRAY(TYPE_CHAR, 80), /* hwdep name */ + TYPE_INT, /* hwdep interface */ + MK_ARRAY(TYPE_CHAR, 64) /* reserved for future */ +) + +/* generic DSP loader */ +STRUCT( sndrv_hwdep_dsp_status, + TYPE_INT, /* R: driver-specific version */ + MK_ARRAY(TYPE_CHAR, 32), /* R: driver-specific ID string */ + TYPE_INT, /* R: number of DSP images to transfer */ + TYPE_INT, /* R: bit flags indicating the loaded DSPs */ + TYPE_INT, /* R: 1 = initialization finished */ + MK_ARRAY(TYPE_CHAR, 16) /* reserved for future use */ +) + +STRUCT( sndrv_hwdep_dsp_image, + TYPE_INT, /* W: DSP index */ + MK_ARRAY(TYPE_CHAR, 64), /* W: ID (e.g. file name) */ + TYPE_CHAR, /* W: binary image */ + TYPE_LONG, /* W: size of image in bytes */ + TYPE_LONG /* W: driver-specific data */ +) + +STRUCT( sndrv_pcm_info, + TYPE_INT, /* RO/WR (control): device number */ + TYPE_INT, /* RO/WR (control): subdevice number */ + TYPE_INT, /* RO/WR (control): stream number */ + TYPE_INT, /* R: card number */ + MK_ARRAY(TYPE_CHAR, 64), /* ID (user selectable) */ + MK_ARRAY(TYPE_CHAR, 80), /* name of this device */ + MK_ARRAY(TYPE_CHAR, 32), /* subdevice name */ + TYPE_INT, /* SNDRV_PCM_CLASS_* */ + TYPE_INT, /* SNDRV_PCM_SUBCLASS_* */ + TYPE_INT, + TYPE_INT, + MK_ARRAY(TYPE_INT, 4), + + MK_ARRAY(TYPE_CHAR, 64) /* reserved for future... */ +) + +STRUCT( sndrv_interval, + TYPE_INT, + TYPE_INT, + TYPE_INTBITFIELD +) + +STRUCT( sndrv_mask, + MK_ARRAY(TYPE_INT, (SNDRV_MASK_MAX+31)/32) +) + +STRUCT( sndrv_pcm_hw_params, + TYPE_INT, + MK_ARRAY(MK_STRUCT(STRUCT_sndrv_mask),SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1), + MK_ARRAY(MK_STRUCT(STRUCT_sndrv_mask), 5), /* reserved masks */ + MK_ARRAY(MK_STRUCT(STRUCT_sndrv_interval), SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1), + MK_ARRAY(MK_STRUCT(STRUCT_sndrv_interval), 9), /* reserved intervals */ + TYPE_INT, /* W: requested masks */ + TYPE_INT, /* R: changed masks */ + TYPE_INT, /* R: Info flags for returned setup */ + TYPE_INT, /* R: used most significant bits */ + TYPE_INT, /* R: rate numerator */ + TYPE_INT, /* R: rate denominator */ + TYPE_LONG, /* R: chip FIFO size in frames */ + MK_ARRAY(TYPE_CHAR, 64) /* reserved for future */ +) + +STRUCT( sndrv_pcm_sw_params, + TYPE_INT, /* timestamp mode */ + TYPE_INT, + TYPE_INT, /* min ticks to sleep */ + TYPE_LONG, /* min avail frames for wakeup */ + TYPE_LONG, /* xfer size need to be a multiple */ + TYPE_LONG, /* min hw_avail frames for automatic start */ + TYPE_LONG, /* min avail frames for automatic stop */ + TYPE_LONG, /* min distance from noise for silence filling */ + TYPE_LONG, /* silence block size */ + TYPE_LONG, /* poTYPE_INTers wrap point */ + MK_ARRAY(TYPE_CHAR, 64) /* reserved for future */ +) + +STRUCT( sndrv_pcm_channel_info, + TYPE_INT, + TYPE_LONG, /* mmap offset (FIXME) */ + TYPE_INT, /* offset to first sample in bits */ + TYPE_INT /* samples distance in bits */ +) + + +STRUCT( sndrv_pcm_status, + TYPE_INT, /* stream state */ + MK_STRUCT(STRUCT_timespec), /* time when stream was started/stopped/paused */ + MK_STRUCT(STRUCT_timespec), /* reference timestamp */ + TYPE_LONG, /* appl ptr */ + TYPE_LONG, /* hw ptr */ + TYPE_LONG, /* current delay in frames */ + TYPE_LONG, /* number of frames available */ + TYPE_LONG, /* max frames available on hw since last status */ + TYPE_LONG, /* count of ADC (capture) overrange detections from last status */ + TYPE_INT, /* suspended stream state */ + MK_ARRAY(TYPE_CHAR, 60) /* must be filled with zero */ +) + +STRUCT( sndrv_pcm_mmap_status, + TYPE_INT, /* RO: state - SNDRV_PCM_STATE_XXXX */ + TYPE_INT, /* Needed for 64 bit alignment */ + TYPE_LONG, /* RO: hw ptr (0...boundary-1) */ + MK_STRUCT(STRUCT_timespec), /* Timestamp */ + TYPE_INT /* RO: suspended stream state */ +) + +STRUCT( sndrv_pcm_mmap_control, + TYPE_LONG, /* RW: appl ptr (0...boundary-1) */ + TYPE_LONG /* RW: min available frames for wakeup */ +) + +STRUCT( sndrv_pcm_sync_ptr, + TYPE_INT, + // FIXME: does not work with 64-bit target + MK_STRUCT(STRUCT_sndrv_pcm_mmap_status), // 28 bytes on 32-bit target + MK_ARRAY(TYPE_CHAR, 64 - 24), // so we pad to 64 bytes (was a union) + + MK_STRUCT(STRUCT_sndrv_pcm_mmap_control), // 8 bytes on 32-bit target + MK_ARRAY(TYPE_CHAR, 64 - 8) // so we pad to 64 bytes (was a union)) +) + +STRUCT( sndrv_xferi, + TYPE_LONG, + TYPE_PTRVOID, + TYPE_LONG +) + +STRUCT( sndrv_xfern, + TYPE_LONG, + TYPE_PTRVOID, + TYPE_LONG +) + +STRUCT( sndrv_rawmidi_info, + TYPE_INT, /* RO/WR (control): device number */ + TYPE_INT, /* RO/WR (control): subdevice number */ + TYPE_INT, /* WR: stream */ + TYPE_INT, /* R: card number */ + TYPE_INT, /* SNDRV_RAWMIDI_INFO_XXXX */ + MK_ARRAY(TYPE_CHAR, 64), /* ID (user selectable) */ + MK_ARRAY(TYPE_CHAR, 80), /* name of device */ + MK_ARRAY(TYPE_CHAR, 32), /* name of active or selected subdevice */ + TYPE_INT, + TYPE_INT, + MK_ARRAY(TYPE_CHAR, 64) /* reserved for future use */ +) + +STRUCT( sndrv_rawmidi_params, + TYPE_INT, + TYPE_LONG, /* queue size in bytes */ + TYPE_LONG, /* minimum avail bytes for wakeup */ + TYPE_INT, /* do not send active sensing byte in close() */ + MK_ARRAY(TYPE_CHAR, 16) /* reserved for future use */ +) + +STRUCT( sndrv_rawmidi_status, + TYPE_INT, + MK_STRUCT(STRUCT_timespec), /* Timestamp */ + TYPE_LONG, /* available bytes */ + TYPE_LONG, /* count of overruns since last status (in bytes) */ + MK_ARRAY(TYPE_CHAR, 16) /* reserved for future use */ +) + +STRUCT( sndrv_timer_ginfo, + MK_STRUCT(STRUCT_sndrv_timer_id), /* requested timer ID */ + TYPE_INT, /* timer flags - SNDRV_TIMER_FLG_* */ + TYPE_INT, /* card number */ + MK_ARRAY(TYPE_CHAR, 64), /* timer identification */ + MK_ARRAY(TYPE_CHAR, 80), /* timer name */ + TYPE_LONG, /* reserved for future use */ + TYPE_LONG, /* average period resolution in ns */ + TYPE_LONG, /* minimal period resolution in ns */ + TYPE_LONG, /* maximal period resolution in ns */ + TYPE_INT, /* active timer clients */ + MK_ARRAY(TYPE_CHAR, 32) +) + +STRUCT( sndrv_timer_gparams, + MK_STRUCT(STRUCT_sndrv_timer_id), /* requested timer ID */ + TYPE_LONG, /* requested precise period duration (in seconds) - numerator */ + TYPE_LONG, /* requested precise period duration (in seconds) - denominator */ + MK_ARRAY(TYPE_CHAR, 32) +) + +STRUCT( sndrv_timer_gstatus, + MK_STRUCT(STRUCT_sndrv_timer_id), /* requested timer ID */ + TYPE_LONG, /* current period resolution in ns */ + TYPE_LONG, /* precise current period resolution (in seconds) - numerator */ + TYPE_LONG, /* precise current period resolution (in seconds) - denominator */ + MK_ARRAY(TYPE_CHAR, 32) +) + +STRUCT( sndrv_timer_select, + MK_STRUCT(STRUCT_sndrv_timer_id), /* bind to timer ID */ + MK_ARRAY(TYPE_CHAR, 32) /* reserved */ +) + +STRUCT( sndrv_timer_info, + TYPE_INT, /* timer flags - SNDRV_TIMER_FLG_* */ + TYPE_INT, /* card number */ + MK_ARRAY(TYPE_CHAR, 64), /* timer identificator */ + MK_ARRAY(TYPE_CHAR, 80), /* timer name */ + TYPE_LONG, /* reserved for future use */ + TYPE_LONG, /* average period resolution in ns */ + MK_ARRAY(TYPE_CHAR, 64) /* reserved */ +) + +STRUCT( sndrv_timer_params, + TYPE_INT, /* flags - SNDRV_MIXER_PSFLG_* */ + TYPE_INT, /* requested resolution in ticks */ + TYPE_INT, /* total size of queue (32-1024) */ + TYPE_INT, + TYPE_INT, /* event filter (bitmask of SNDRV_TIMER_EVENT_*) */ + MK_ARRAY(TYPE_CHAR, 60) /* reserved */ +) + +STRUCT( sndrv_timer_status, + MK_STRUCT(STRUCT_timespec), /* Timestamp - last update */ + TYPE_INT, /* current period resolution in ns */ + TYPE_INT, /* counter of master tick lost */ + TYPE_INT, /* count of read queue overruns */ + TYPE_INT, /* used queue size */ + MK_ARRAY(TYPE_CHAR, 64) /* reserved */ +) + +STRUCT( sndrv_timer_read, + TYPE_INT, + TYPE_INT +) + +STRUCT( sndrv_timer_tread, + TYPE_INT, + MK_STRUCT(STRUCT_timespec), + TYPE_INT +) + +STRUCT( sndrv_ctl_card_info, + TYPE_INT, /* card number */ + TYPE_INT, /* reserved for future (was type) */ + MK_ARRAY(TYPE_CHAR, 16), /* ID of card (user selectable) */ + MK_ARRAY(TYPE_CHAR, 16), /* Driver name */ + MK_ARRAY(TYPE_CHAR, 32), /* Short name of soundcard */ + MK_ARRAY(TYPE_CHAR, 80), /* name + info text about soundcard */ + MK_ARRAY(TYPE_CHAR, 16), /* reserved for future (was ID of mixer) */ + MK_ARRAY(TYPE_CHAR, 80), /* visual mixer identification */ + MK_ARRAY(TYPE_CHAR, 80), /* card components / fine identification, delimited with one space (AC97 etc..) */ + MK_ARRAY(TYPE_CHAR, 48) /* reserved for future */ +) + +STRUCT( sndrv_ctl_elem_id, + TYPE_INT, + TYPE_INT, /* interface identifier */ + TYPE_INT, /* device/client number */ + TYPE_INT, /* subdevice (substream) number */ + MK_ARRAY(TYPE_CHAR, 44), /* ASCII name of item */ + TYPE_INT /* index of item */ +) + +STRUCT( sndrv_ctl_elem_list, + TYPE_INT, /* W: first element ID to get */ + TYPE_INT, /* W: count of element IDs to get */ + TYPE_INT, /* R: count of element IDs set */ + TYPE_INT, /* R: count of all elements */ + MK_STRUCT(STRUCT_sndrv_ctl_elem_id), /* R: IDs */ + MK_ARRAY(TYPE_CHAR, 50) +) + +STRUCT( sndrv_ctl_elem_info, + MK_STRUCT(STRUCT_sndrv_ctl_elem_id), /* W: element ID */ + TYPE_INT, /* R: value type - SNDRV_CTL_ELEM_TYPE_* */ + TYPE_INT, /* R: value access (bitmask) - SNDRV_CTL_ELEM_ACCESS_* */ + TYPE_INT, /* count of values */ + TYPE_INT, /* owner's PID of this control */ + MK_ARRAY(TYPE_CHAR, 128), // FIXME: prone to break (was union) + MK_ARRAY(TYPE_SHORT, 4), /* dimensions */ + MK_ARRAY(TYPE_CHAR, 64-4*sizeof(unsigned short)) +) + +STRUCT( sndrv_ctl_elem_value, + MK_STRUCT(STRUCT_sndrv_ctl_elem_id), /* W: element ID */ + TYPE_INT, /* W: use indirect pointer (xxx_ptr member) */ + MK_ARRAY(TYPE_INT, 128), + MK_STRUCT(STRUCT_timespec), + MK_ARRAY(TYPE_CHAR, 128-sizeof(struct timespec)) // FIXME: breaks on 64-bit host +) + +STRUCT( sndrv_ctl_tlv, + TYPE_INT, /* control element numeric identification */ + TYPE_INT, /* in bytes aligned to 4 */ + MK_ARRAY(TYPE_INT, 0) /* first TLV */ // FIXME: what is this supposed to become? +) + +STRUCT( sndrv_ctl_event, + TYPE_INT, /* event type - SNDRV_CTL_EVENT_* */ + TYPE_INT, + MK_STRUCT(STRUCT_sndrv_ctl_elem_id) // 64 bytes +) + +STRUCT( iovec, + TYPE_PTRVOID, + TYPE_LONG + ) + + +STRUCT( sndrv_xferv, + MK_STRUCT(STRUCT_iovec), + TYPE_LONG +) + +STRUCT(emu10k1_fx8010_info, + TYPE_INT, /* in samples */ + TYPE_INT, /* in samples */ + MK_ARRAY(MK_ARRAY(TYPE_CHAR, 32), 16), /* names of FXBUSes */ + MK_ARRAY(MK_ARRAY(TYPE_CHAR, 32), 16), /* names of external inputs */ + MK_ARRAY(MK_ARRAY(TYPE_CHAR, 32), 32), /* names of external outputs */ + TYPE_INT /* count of GPR controls */ +) + +STRUCT(emu10k1_ctl_elem_id, + TYPE_INT, /* don't use */ + TYPE_INT, /* interface identifier */ + TYPE_INT, /* device/client number */ + TYPE_INT, /* subdevice (substream) number */ + MK_ARRAY(TYPE_CHAR, 44), /* ASCII name of item */ + TYPE_INT /* index of item */ +) + +STRUCT(emu10k1_fx8010_control_gpr, + MK_STRUCT(STRUCT_emu10k1_ctl_elem_id), /* full control ID definition */ + TYPE_INT, /* visible count */ + TYPE_INT, /* count of GPR (1..16) */ + MK_ARRAY(TYPE_SHORT, 32), /* GPR number(s) */ + MK_ARRAY(TYPE_INT, 32), /* initial values */ + TYPE_INT, /* minimum range */ + TYPE_INT, /* maximum range */ + TYPE_INT, /* translation type (EMU10K1_GPR_TRANSLATION*) */ + TYPE_INT +) + +#ifndef TARGET_LONG_SIZE +#define TARGET_LONG_SIZE 4 +#endif + +STRUCT(emu10k1_fx8010_code, + MK_ARRAY(TYPE_CHAR, 128), + + MK_ARRAY(TYPE_LONG, 0x200/(TARGET_LONG_SIZE*8)), /* bitmask of valid initializers */ + TYPE_PTRVOID, /* initializers */ + + TYPE_INT, /* count of GPR controls to add/replace */ + MK_STRUCT(STRUCT_emu10k1_fx8010_control_gpr), /* GPR controls to add/replace */ + + TYPE_INT, /* count of GPR controls to remove */ + MK_STRUCT(STRUCT_emu10k1_ctl_elem_id), /* IDs of GPR controls to remove */ + + TYPE_INT, /* count of GPR controls to list */ + TYPE_INT, /* total count of GPR controls */ + MK_STRUCT(STRUCT_emu10k1_fx8010_control_gpr), /* listed GPR controls */ + + MK_ARRAY(TYPE_LONG, 0x100/(TARGET_LONG_SIZE*8)), /* bitmask of valid initializers */ + TYPE_PTRVOID, /* data initializers */ + TYPE_PTRVOID, /* map initializers */ + + MK_ARRAY(TYPE_LONG, 1024/(TARGET_LONG_SIZE*8)), /* bitmask of valid instructions */ + TYPE_PTRVOID /* one instruction - 64 bits */ +) + +STRUCT(emu10k1_fx8010_tram, + TYPE_INT, /* 31.bit == 1 -> external TRAM */ + TYPE_INT, /* size in samples (4 bytes) */ + TYPE_INT /* pointer to samples (20-bit) */ + /* NULL->clear memory */ +) + +STRUCT(emu10k1_fx8010_pcm, + TYPE_INT, /* substream number */ + TYPE_INT, /* reserved */ + TYPE_INT, + TYPE_INT, /* ring buffer position in TRAM (in samples) */ + TYPE_INT, /* count of buffered samples */ + TYPE_SHORT, /* GPR containing size of ringbuffer in samples (host) */ + TYPE_SHORT, + TYPE_SHORT, /* GPR containing count of samples between two TYPE_INTerrupts (host) */ + TYPE_SHORT, + TYPE_SHORT, /* GPR containing trigger (activate) information (host) */ + TYPE_SHORT, /* GPR containing info if PCM is running (FX8010) */ + TYPE_CHAR, /* reserved */ + MK_ARRAY(TYPE_CHAR, 32), /* external TRAM address & data (one per channel) */ + TYPE_INT /* reserved */ +) + +STRUCT( hdsp_peak_rms, + MK_ARRAY(TYPE_INT, 26), + MK_ARRAY(TYPE_INT, 26), + MK_ARRAY(TYPE_INT, 28), + MK_ARRAY(TYPE_LONGLONG, 26), + MK_ARRAY(TYPE_LONGLONG, 26), + /* These are only used for H96xx cards */ + MK_ARRAY(TYPE_LONGLONG, 26) +) + +STRUCT( hdsp_config_info, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + MK_ARRAY(TYPE_CHAR, 3), + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_INT, + TYPE_INT, + TYPE_INT, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR, + TYPE_CHAR +) + +STRUCT( hdsp_firmware, + TYPE_PTRVOID /* 24413 x 4 bytes */ +) + +STRUCT( hdsp_version, + TYPE_INT, + TYPE_SHORT +) + +STRUCT( hdsp_mixer, + MK_ARRAY(TYPE_SHORT, HDSP_MATRIX_MIXER_SIZE) +) + +STRUCT( hdsp_9632_aeb, + TYPE_INT, + TYPE_INT +) + +STRUCT( snd_sb_csp_mc_header, + MK_ARRAY(TYPE_CHAR, 16), /* id name of codec */ + TYPE_SHORT /* requested function */ +) + +STRUCT( snd_sb_csp_microcode, + MK_STRUCT(STRUCT_snd_sb_csp_mc_header), + MK_ARRAY(TYPE_CHAR, SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE) +) + +STRUCT( snd_sb_csp_start, + TYPE_INT, + TYPE_INT +) + +STRUCT( snd_sb_csp_info, + MK_ARRAY(TYPE_CHAR, 16), /* id name of codec */ + TYPE_SHORT, /* function number */ + TYPE_INT, /* accepted PCM formats */ + TYPE_SHORT, /* accepted channels */ + TYPE_SHORT, /* accepted sample width */ + TYPE_SHORT, /* accepted sample rates */ + TYPE_SHORT, + TYPE_SHORT, /* current channels */ + TYPE_SHORT, /* current sample width */ + TYPE_SHORT, /* version id: 0x10 - 0x1f */ + TYPE_SHORT /* state bits */ +) + +STRUCT( sscape_bootblock, + MK_ARRAY(TYPE_CHAR, 256), + TYPE_INT +) + +STRUCT( sscape_microcode, + TYPE_PTRVOID +) -- 2.51.1 From 9c9cfb248223f4da2ea2333164ea7e6a6091c03a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 14 Apr 2009 16:24:15 +0200 Subject: [PATCH 05/58] qemu-cvs-alsa_mmap Hack to prevent ALSA from using mmap() interface to simplify emulation. Signed-off-by: Alexander Graf Signed-off-by: Ulrich Hecht --- linux-user/mmap.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 3519147bce..671889b00f 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -358,6 +358,9 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) } } +#define SNDRV_PCM_MMAP_OFFSET_STATUS 0x80000000 +#define SNDRV_PCM_MMAP_OFFSET_CONTROL 0x81000000 + /* NOTE: all the constants are the HOST ones */ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, int flags, int fd, abi_ulong offset) @@ -392,6 +395,17 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, } #endif + /* Alsa tries to communcate with the kernel via mmap. This usually + * is a good idea when user- and kernelspace are running on the + * same architecture but does not work out when not. To make alsa + * not to use mmap, we can just have it fail on the mmap calls that + * would initiate this. + */ + if(offset == SNDRV_PCM_MMAP_OFFSET_STATUS || offset == SNDRV_PCM_MMAP_OFFSET_CONTROL) { + errno = EINVAL; + return -1; + } + if (offset & ~TARGET_PAGE_MASK) { errno = EINVAL; goto fail; -- 2.51.1 From 2dc4a9d135ce472a59da891af09ba9529c57b61b Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Tue, 14 Apr 2009 16:25:41 +0200 Subject: [PATCH 06/58] qemu-cvs-gettimeofday No clue what this is for. --- linux-user/syscall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 032d338869..d2317582c1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6985,6 +6985,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_gettimeofday: { struct timeval tv; + if(copy_from_user_timeval(&tv, arg1)) + goto efault; ret = get_errno(gettimeofday(&tv, NULL)); if (!is_error(ret)) { if (copy_to_user_timeval(arg1, &tv)) -- 2.51.1 From d2a4cedd351ff7e09843bb5cbb76038af2303df7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 14 Apr 2009 16:26:33 +0200 Subject: [PATCH 07/58] qemu-cvs-ioctl_debug Extends unsupported ioctl debug output. Signed-off-by: Alexander Graf Signed-off-by: Ulrich Hecht --- linux-user/syscall.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index d2317582c1..d693f9dcf7 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4022,7 +4022,12 @@ static abi_long do_ioctl(int fd, int cmd, abi_long arg) ie = ioctl_entries; for(;;) { if (ie->target_cmd == 0) { - gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd); + int i; + gemu_log("Unsupported ioctl: cmd=0x%04lx (%x)\n", (unsigned long)cmd, (unsigned int)(cmd & (TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) >> TARGET_IOC_SIZESHIFT); + for (i = 0; ioctl_entries[i].target_cmd; i++) { + if ((ioctl_entries[i].target_cmd & ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) == (cmd & ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT))) + gemu_log("%p\t->\t%s (%x)\n", (void *)(unsigned long)ioctl_entries[i].host_cmd, ioctl_entries[i].name, (ioctl_entries[i].target_cmd & (TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) >> TARGET_IOC_SIZESHIFT); + } return -TARGET_ENOSYS; } if (ie->target_cmd == cmd) -- 2.51.1 From 43f2593e07e0de12dddf72c3205e6a0fb851dc2d Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 14 Apr 2009 16:27:36 +0200 Subject: [PATCH 08/58] qemu-cvs-ioctl_nodirection the direction given in the ioctl should be correct so we can assume the communication is uni-directional. The alsa developers did not like this concept though and declared ioctls IOC_R and IOC_W even though they were IOC_RW. Signed-off-by: Alexander Graf Signed-off-by: Ulrich Hecht --- linux-user/syscall.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index d693f9dcf7..0858920a2d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4055,6 +4055,11 @@ static abi_long do_ioctl(int fd, int cmd, abi_long arg) arg_type++; target_size = thunk_type_size(arg_type, 0); switch(ie->access) { + /* FIXME: actually the direction given in the ioctl should be + * correct so we can assume the communication is uni-directional. + * The alsa developers did not like this concept though and + * declared ioctls IOC_R and IOC_W even though they were IOC_RW.*/ +/* case IOC_R: ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { @@ -4073,6 +4078,7 @@ static abi_long do_ioctl(int fd, int cmd, abi_long arg) unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); break; +*/ default: case IOC_RW: argptr = lock_user(VERIFY_READ, arg, target_size, 1); -- 2.51.1 From d367bff9f8b514a0beacac3d21426d787dcef77f Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Tue, 14 Apr 2009 16:37:42 +0200 Subject: [PATCH 09/58] block/vmdk: Support creation of SCSI VMDK images in qemu-img MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ulrich Hecht [AF: Changed BLOCK_FLAG_SCSI from 8 to 16 for v1.2] [AF: Rebased onto upstream VMDK SCSI support] [AF: Rebased onto skipping of image creation in v1.7] [AF: Simplified in preparation for v1.7.1/v2.0] [AF: Rebased onto QemuOpts conversion for v2.1] Signed-off-by: Andreas Färber --- block.c | 3 +++ block/vmdk.c | 10 +++++++++- include/block/block_int.h | 2 ++ qemu-img.c | 7 +++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index d4939b49bf..b10e0fe849 100644 --- a/block.c +++ b/block.c @@ -3588,6 +3588,9 @@ void bdrv_img_create(const char *filename, const char *fmt, if (!quiet) { printf("Formatting '%s', fmt=%s ", filename, fmt); qemu_opts_print(opts, " "); + if (qemu_opt_get_bool(opts, BLOCK_OPT_SCSI, false)) { + printf(", SCSI"); + } puts(""); } diff --git a/block/vmdk.c b/block/vmdk.c index 45f9d3c5b9..f5c68e08ba 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1885,9 +1885,12 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false)) { zeroed_grain = true; } + if (qemu_opt_get_bool_del(opts, BLOCK_OPT_SCSI, false)) { + flags |= BLOCK_FLAG_SCSI; + } if (!adapter_type) { - adapter_type = g_strdup("ide"); + adapter_type = g_strdup(flags & BLOCK_FLAG_SCSI ? "lsilogic" : "ide"); } else if (strcmp(adapter_type, "ide") && strcmp(adapter_type, "buslogic") && strcmp(adapter_type, "lsilogic") && @@ -2310,6 +2313,11 @@ static QemuOptsList vmdk_create_opts = { .help = "Enable efficient zero writes " "using the zeroed-grain GTE feature" }, + { + .name = BLOCK_OPT_SCSI, + .type = QEMU_OPT_BOOL, + .help = "SCSI image" + }, { /* end of list */ } } }; diff --git a/include/block/block_int.h b/include/block/block_int.h index 10d87595be..7c0b99c8af 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -40,10 +40,12 @@ #define BLOCK_FLAG_ENCRYPT 1 #define BLOCK_FLAG_COMPAT6 4 #define BLOCK_FLAG_LAZY_REFCOUNTS 8 +#define BLOCK_FLAG_SCSI 16 #define BLOCK_OPT_SIZE "size" #define BLOCK_OPT_ENCRYPT "encryption" #define BLOCK_OPT_COMPAT6 "compat6" +#define BLOCK_OPT_SCSI "scsi" #define BLOCK_OPT_BACKING_FILE "backing_file" #define BLOCK_OPT_BACKING_FMT "backing_fmt" #define BLOCK_OPT_CLUSTER_SIZE "cluster_size" diff --git a/qemu-img.c b/qemu-img.c index 46f2a6def4..01e6f4a622 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2027,6 +2027,13 @@ static int img_convert(int argc, char **argv) } } + if (qemu_opt_get_bool(opts, BLOCK_OPT_SCSI, false) + && strcmp(drv->format_name, "vmdk")) { + error_report("SCSI devices not supported for this file format"); + ret = -1; + goto out; + } + if (!skip_create) { /* Create the new image */ ret = bdrv_create(drv, out_filename, opts, &local_err); -- 2.51.1 From 4234d2b99790fd33e82bee633f48d773e0c7c43e Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 30 Sep 2011 19:40:36 +0200 Subject: [PATCH 10/58] linux-user: add binfmt wrapper for argv[0] handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using qemu's linux-user binaries through binfmt, argv[0] gets lost along the execution because qemu only gets passed in the full file name to the executable while argv[0] can be something completely different. This breaks in some subtile situations, such as the grep and make test suites. This patch adds a wrapper binary called qemu-$TARGET-binfmt that can be used with binfmt's P flag which passes the full path _and_ argv[0] to the binfmt handler. The binary would be smart enough to be versatile and only exist in the system once, creating the qemu binary path names from its own argv[0]. However, this seemed like it didn't fit the make system too well, so we're currently creating a new binary for each target archictecture. CC: Reinhard Max Signed-off-by: Alexander Graf [AF: Rebased onto new Makefile infrastructure, twice] [AF: Updated for aarch64 for v2.0.0-rc1] [AF: Rebased onto Makefile changes for v2.1.0-rc0] Signed-off-by: Andreas Färber --- Makefile.target | 13 ++++++++++++ linux-user/Makefile.objs | 2 ++ linux-user/binfmt.c | 42 +++++++++++++++++++++++++++++++++++++ scripts/qemu-binfmt-conf.sh | 36 +++++++++++++++---------------- 4 files changed, 75 insertions(+), 18 deletions(-) create mode 100644 linux-user/binfmt.c diff --git a/Makefile.target b/Makefile.target index 34ddb7e762..cba107898b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -36,6 +36,10 @@ endif PROGS=$(QEMU_PROG) $(QEMU_PROGW) STPFILES= +ifdef CONFIG_LINUX_USER +PROGS+=$(QEMU_PROG)-binfmt +endif + config-target.h: config-target.h-timestamp config-target.h-timestamp: config-target.mak @@ -113,6 +117,8 @@ QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user obj-y += linux-user/ obj-y += gdbstub.o thunk.o user-exec.o +obj-binfmt-y += linux-user/ + endif #CONFIG_LINUX_USER ######################################################### @@ -161,7 +167,11 @@ endif # CONFIG_SOFTMMU # Workaround for http://gcc.gnu.org/PR55489, see configure. %/translate.o: QEMU_CFLAGS += $(TRANSLATE_OPT_CFLAGS) +ifdef CONFIG_LINUX_USER +dummy := $(call unnest-vars,,obj-y obj-binfmt-y) +else dummy := $(call unnest-vars,,obj-y) +endif all-obj-y := $(obj-y) target-obj-y := @@ -198,6 +208,9 @@ ifdef CONFIG_DARWIN $(call quiet-command,SetFile -a C $@," SETFILE $(TARGET_DIR)$@") endif +$(QEMU_PROG)-binfmt: $(obj-binfmt-y) + $(call LINK,$^) + gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@") diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs index fd5021788f..446aca7f11 100644 --- a/linux-user/Makefile.objs +++ b/linux-user/Makefile.objs @@ -5,3 +5,5 @@ obj-$(TARGET_HAS_BFLT) += flatload.o obj-$(TARGET_I386) += vm86.o obj-$(TARGET_ARM) += arm/nwfpe/ obj-$(TARGET_M68K) += m68k-sim.o + +obj-binfmt-y = binfmt.o diff --git a/linux-user/binfmt.c b/linux-user/binfmt.c new file mode 100644 index 0000000000..cd1f513b33 --- /dev/null +++ b/linux-user/binfmt.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include + + +int main(int argc, char **argv, char **envp) +{ + char *binfmt; + char **new_argv; + + /* + * Check if our file name ends with -binfmt + */ + binfmt = argv[0] + strlen(argv[0]) - strlen("-binfmt"); + if (strcmp(binfmt, "-binfmt")) { + fprintf(stderr, "%s: Invalid executable name\n", argv[0]); + exit(1); + } + if (argc < 3) { + fprintf(stderr, "%s: Please use me through binfmt with P flag\n", + argv[0]); + exit(1); + } + + binfmt[0] = '\0'; + /* Now argv[0] is the real qemu binary name */ + + new_argv = (char **)malloc((argc + 2) * sizeof(*new_argv)); + if (argc > 3) { + memcpy(&new_argv[4], &argv[3], (argc - 3) * sizeof(*new_argv)); + } + new_argv[0] = argv[0]; + new_argv[1] = (char *)"-0"; + new_argv[2] = argv[2]; + new_argv[3] = argv[1]; + new_argv[argc + 1] = NULL; + + return execve(new_argv[0], new_argv, envp); +} diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index 75e05268ff..557dd2cc54 100644 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -34,42 +34,42 @@ esac # register the interpreter for each cpu except for the native one if [ $cpu != "i386" ] ; then - echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register - echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register + echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-i386-binfmt:P' > /proc/sys/fs/binfmt_misc/register + echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-i386-binfmt:P' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "alpha" ] ; then - echo ':alpha:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-alpha:' > /proc/sys/fs/binfmt_misc/register + echo ':alpha:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-alpha-binfmt:P' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "arm" ] ; then - echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register - echo ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register + echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-binfmt:P' > /proc/sys/fs/binfmt_misc/register + echo ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-armeb-binfmt:P' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "aarch64" ] ; then - echo ':aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64:' > /proc/sys/fs/binfmt_misc/register + echo ':aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64-binfmt:P' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "sparc" ] ; then - echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register + echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-sparc-binfmt:P' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "ppc" ] ; then - echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register + echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-ppc-binfmt:P' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "m68k" ] ; then echo 'Please check cpu value and header information for m68k!' - echo ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-m68k:' > /proc/sys/fs/binfmt_misc/register + echo ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-m68k-binfmt:P' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "mips" ] ; then # FIXME: We could use the other endianness on a MIPS host. - echo ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsn32:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-mipsn32:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsn32el:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mipsn32el:' > /proc/sys/fs/binfmt_misc/register - echo ':mips64:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-mips64:' > /proc/sys/fs/binfmt_misc/register - echo ':mips64el:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mips64el:' > /proc/sys/fs/binfmt_misc/register + echo ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-mips-binfmt:P' > /proc/sys/fs/binfmt_misc/register + echo ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mipsel-binfmt:P' > /proc/sys/fs/binfmt_misc/register + echo ':mipsn32:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-mipsn32-binfmt:P' > /proc/sys/fs/binfmt_misc/register + echo ':mipsn32el:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mipsn32el-binfmt:P' > /proc/sys/fs/binfmt_misc/register + echo ':mips64:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-mips64-binfmt:P' > /proc/sys/fs/binfmt_misc/register + echo ':mips64el:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mips64el-binfmt:P' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "sh" ] ; then - echo ':sh4:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-sh4:' > /proc/sys/fs/binfmt_misc/register - echo ':sh4eb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-sh4eb:' > /proc/sys/fs/binfmt_misc/register + echo ':sh4:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-sh4-binfmt:P' > /proc/sys/fs/binfmt_misc/register + echo ':sh4eb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-sh4eb-binfmt:P' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "s390x" ] ; then - echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-s390x:' > /proc/sys/fs/binfmt_misc/register + echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-s390x-binfmt:P' > /proc/sys/fs/binfmt_misc/register fi -- 2.51.1 From 312bb9ff5f1448e2aebcccc4f124cf8f7fa1e0a0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 6 Jan 2012 01:05:55 +0100 Subject: [PATCH 11/58] PPC: KVM: Disable mmu notifier check When using hugetlbfs (which is required for HV mode KVM on 970), we check for MMU notifiers that on 970 can not be implemented properly. So disable the check for mmu notifiers on PowerPC guests, making KVM guests work there, even if possibly racy in some odd circumstances. --- exec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exec.c b/exec.c index fc7526666f..a50e1488ce 100644 --- a/exec.c +++ b/exec.c @@ -1242,11 +1242,13 @@ static void *file_ram_alloc(RAMBlock *block, int fd = -1; int64_t page_size; +#ifndef TARGET_PPC if (kvm_enabled() && !kvm_has_sync_mmu()) { error_setg(errp, "host lacks kvm mmu notifiers, -mem-path unsupported"); return NULL; } +#endif for (;;) { fd = open(path, O_RDWR); -- 2.51.1 From 48e23620ccc1efef237996fcc102215619a5ba7d Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 13 Jan 2012 17:05:41 +0100 Subject: [PATCH 12/58] linux-user: fix segfault deadlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When entering the guest we take a lock to ensure that nobody else messes with our TB chaining while we're doing it. If we get a segfault inside that code, we manage to work on, but will not unlock the lock. This patch forces unlocking of that lock in the segv handler. I'm not sure this is the right approach though. Maybe we should rather make sure we don't segfault in the code? I would greatly appreciate someone more intelligible than me to look at this :). Example code to trigger this is at: http://csgraf.de/tmp/conftest.c Reported-by: Fabio Erculiani Signed-off-by: Alexander Graf [AF: Drop spinlock_safe_unlock() and switch to tb_lock_reset() (bonzini)] Signed-off-by: Andreas Färber --- user-exec.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user-exec.c b/user-exec.c index d8d597bafe..f8b7752671 100644 --- a/user-exec.c +++ b/user-exec.c @@ -94,6 +94,10 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address, printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", pc, address, is_write, *(unsigned long *)old_set); #endif + + /* Maybe we're still holding the TB fiddling lock? */ + tb_lock_reset(); + /* XXX: locking issue */ if (is_write && h2g_valid(address) && page_unprotect(h2g(address), pc, puc)) { -- 2.51.1 From 7ada3e29b37a639129e36a7ed2f2f07a0efc3334 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 2 Feb 2012 18:02:33 +0100 Subject: [PATCH 13/58] linux-user: binfmt: support host binaries When we have a working host binary equivalent for the guest binary we're trying to run, let's just use that instead as it will be a lot faster. Signed-off-by: Alexander Graf --- linux-user/binfmt.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/linux-user/binfmt.c b/linux-user/binfmt.c index cd1f513b33..458f136fb4 100644 --- a/linux-user/binfmt.c +++ b/linux-user/binfmt.c @@ -5,6 +5,9 @@ #include #include +#ifdef __x86_64__ +#define ARCH_NAME "x86_64" +#endif int main(int argc, char **argv, char **envp) { @@ -28,6 +31,29 @@ int main(int argc, char **argv, char **envp) binfmt[0] = '\0'; /* Now argv[0] is the real qemu binary name */ +#ifdef ARCH_NAME + { + char *hostbin; + char *guestarch; + int r; + + guestarch = strrchr(argv[0], '-') ; + if (!guestarch) { + goto skip; + } + guestarch++; + r = asprintf(&hostbin, "/emul/" ARCH_NAME "-for-%s/%s", guestarch, argv[1]); + if ((r > 0) && !access(hostbin, X_OK)) { + /* + * We found a host binary replacement for the non-host binary. Let's + * use that instead! + */ + return execve(hostbin, &argv[2], envp); + } + } +skip: +#endif + new_argv = (char **)malloc((argc + 2) * sizeof(*new_argv)); if (argc > 3) { memcpy(&new_argv[4], &argv[3], (argc - 3) * sizeof(*new_argv)); -- 2.51.1 From f3041527d08d4547ca88843c3be991569bca5152 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 12 Jun 2012 04:41:10 +0200 Subject: [PATCH 14/58] linux-user: Ignore broken loop ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During invocations of losetup, we run into an ioctl that doesn't exist. However, because of that we output an error, which then screws up the kiwi logic around that call. So let's silently ignore that bogus ioctl. Signed-off-by: Alexander Graf [AF: Rebased for v2.1.0-rc0] Signed-off-by: Andreas Färber --- linux-user/ioctls.h | 1 + linux-user/linux_loop.h | 1 + linux-user/syscall.c | 7 +++++++ linux-user/syscall_defs.h | 1 + 4 files changed, 10 insertions(+) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 921d482160..c180fafb15 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -331,6 +331,7 @@ IOCTL(LOOP_SET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) IOCTL(LOOP_GET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) IOCTL(LOOP_CHANGE_FD, 0, TYPE_INT) + IOCTL_SPECIAL(LOOP_BOGUS_CMD, 0, do_ioctl_fail, TYPE_INT) IOCTL(MTIOCTOP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_mtop))) IOCTL(MTIOCGET, IOC_R, MK_PTR(MK_STRUCT(STRUCT_mtget))) diff --git a/linux-user/linux_loop.h b/linux-user/linux_loop.h index 8974caa9d0..810ae616ed 100644 --- a/linux-user/linux_loop.h +++ b/linux-user/linux_loop.h @@ -91,5 +91,6 @@ struct loop_info64 { #define LOOP_SET_STATUS64 0x4C04 #define LOOP_GET_STATUS64 0x4C05 #define LOOP_CHANGE_FD 0x4C06 +#define LOOP_BOGUS_CMD 0x4C82 #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0858920a2d..758f747cc6 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3999,6 +3999,13 @@ static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp, return get_errno(ioctl(fd, ie->host_cmd, sig)); } +static abi_long do_ioctl_fail(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, + abi_long cmd, abi_long arg) +{ + /* Fail silently */ + return -EINVAL; +} + static IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index b090cdb466..f820b0bb77 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1087,6 +1087,7 @@ struct target_pollfd { #define TARGET_LOOP_SET_STATUS64 0x4C04 #define TARGET_LOOP_GET_STATUS64 0x4C05 #define TARGET_LOOP_CHANGE_FD 0x4C06 +#define TARGET_LOOP_BOGUS_CMD 0x4C82 /* fb ioctls */ #define TARGET_FBIOGET_VSCREENINFO 0x4600 -- 2.51.1 From 3c784b6969e0379542cf4661847effa17eacd27f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 5 Jul 2012 17:31:39 +0200 Subject: [PATCH 15/58] linux-user: lock tcg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tcg code generator is not thread safe. Lock its generation between different threads. Signed-off-by: Alexander Graf [AF: Rebased onto exec.c/translate-all.c split for 1.4] [AF: Rebased for v2.1.0-rc0] [AF: Rebased onto tcg_gen_code_common() drop for v2.5.0-rc0] Signed-off-by: Andreas Färber --- linux-user/mmap.c | 3 +++ tcg/tcg.c | 31 ++++++++++++++++++++++++++++++- tcg/tcg.h | 6 ++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 671889b00f..b85905c0c1 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -23,6 +23,7 @@ #include "qemu.h" #include "qemu-common.h" +#include "tcg.h" #include "translate-all.h" //#define DEBUG_MMAP @@ -34,6 +35,7 @@ void mmap_lock(void) { if (mmap_lock_count++ == 0) { pthread_mutex_lock(&mmap_mutex); + tcg_lock(); } } @@ -41,6 +43,7 @@ void mmap_unlock(void) { if (--mmap_lock_count == 0) { pthread_mutex_unlock(&mmap_mutex); + tcg_unlock(); } } diff --git a/tcg/tcg.c b/tcg/tcg.c index 796addd1fc..8c511bf2cb 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -34,6 +34,8 @@ #include "qemu/cutils.h" #include "qemu/host-utils.h" #include "qemu/timer.h" +#include "config-host.h" +#include "qemu/thread.h" /* Note: the long term plan is to reduce the dependencies on the QEMU CPU definitions. Currently they are used for qemu_ld/st @@ -114,6 +116,29 @@ static bool tcg_out_tb_finalize(TCGContext *s); static TCGRegSet tcg_target_available_regs[2]; static TCGRegSet tcg_target_call_clobber_regs; +#ifdef CONFIG_USER_ONLY +static __thread int tcg_lock_count; +#endif +void tcg_lock(void) +{ +#ifdef CONFIG_USER_ONLY + TCGContext *s = &tcg_ctx; + if (tcg_lock_count++ == 0) { + qemu_mutex_lock(&s->lock); + } +#endif +} + +void tcg_unlock(void) +{ +#ifdef CONFIG_USER_ONLY + TCGContext *s = &tcg_ctx; + if (--tcg_lock_count == 0) { + qemu_mutex_unlock(&s->lock); + } +#endif +} + #if TCG_TARGET_INSN_UNIT_SIZE == 1 static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) { @@ -326,7 +351,8 @@ void tcg_context_init(TCGContext *s) memset(s, 0, sizeof(*s)); s->nb_globals = 0; - + qemu_mutex_init(&s->lock); + /* Count total number of arguments and allocate the corresponding space */ total_args = 0; @@ -2353,6 +2379,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) qemu_log("\n"); } #endif + tcg_lock(); #ifdef CONFIG_PROFILER s->opt_time -= profile_getclock(); @@ -2457,6 +2484,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) the buffer completely. Thus we can test for overflow after generating code without having to check during generation. */ if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { + tcg_unlock(); return -1; } } @@ -2470,6 +2498,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) /* flush instruction cache */ flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); + tcg_unlock(); return tcg_current_code_size(s); } diff --git a/tcg/tcg.h b/tcg/tcg.h index 40c8fbe2ae..6b826af200 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -27,6 +27,7 @@ #include "qemu-common.h" #include "qemu/bitops.h" +#include "qemu/thread.h" #include "tcg-target.h" #define CPU_TEMP_BUF_NLONGS 128 @@ -591,6 +592,8 @@ struct TCGContext { uint16_t gen_insn_end_off[TCG_MAX_INSNS]; target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS]; + + QemuMutex lock; }; extern TCGContext tcg_ctx; @@ -798,6 +801,9 @@ void tcg_gen_callN(TCGContext *s, void *func, void tcg_op_remove(TCGContext *s, TCGOp *op); void tcg_optimize(TCGContext *s); +extern void tcg_lock(void); +extern void tcg_unlock(void); + /* only used for debugging purposes */ void tcg_dump_ops(TCGContext *s); -- 2.51.1 From 0922a98683629c491b15b282d35cba46c225549f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 10 Jul 2012 20:40:55 +0200 Subject: [PATCH 16/58] linux-user: Run multi-threaded code on a single core Running multi-threaded code can easily expose some of the fundamental breakages in QEMU's design. It's just not a well supported scenario. So if we pin the whole process to a single host CPU, we guarantee that we will never have concurrent memory access actually happen. We can still get scheduled away at any time, so it's no complete guarantee, but apparently it reduces the odds well enough to get my test cases to pass. This gets Java 1.7 working for me again on my test box. Signed-off-by: Alexander Graf --- linux-user/syscall.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 758f747cc6..b36273de54 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4704,6 +4704,15 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, if (nptl_flags & CLONE_SETTLS) cpu_set_tls (new_env, newtls); + /* agraf: Pin ourselves to a single CPU when running multi-threaded. + This turned out to improve stability for me. */ + { + cpu_set_t mask; + CPU_ZERO(&mask); + CPU_SET(0, &mask); + sched_setaffinity(0, sizeof(mask), &mask); + } + /* Grab a mutex so that thread setup appears atomic. */ pthread_mutex_lock(&clone_lock); -- 2.51.1 From 598cc6f427821cbaf6b6a8eeadf90176ecf9b9d5 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 11 Jul 2012 16:47:42 +0200 Subject: [PATCH 17/58] linux-user: lock tb flushing too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexander Graf [AF: Rebased onto exec.c/translate-all.c split for 1.4] [AF: Rebased onto tb_alloc() changes for v2.5.0-rc0] Signed-off-by: Andreas Färber --- translate-all.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/translate-all.c b/translate-all.c index 8329ea60ee..12a48c2aca 100644 --- a/translate-all.c +++ b/translate-all.c @@ -761,17 +761,21 @@ static TranslationBlock *tb_alloc(target_ulong pc) { TranslationBlock *tb; + tcg_lock(); if (tcg_ctx.tb_ctx.nb_tbs >= tcg_ctx.code_gen_max_blocks) { + tcg_unlock(); return NULL; } tb = &tcg_ctx.tb_ctx.tbs[tcg_ctx.tb_ctx.nb_tbs++]; tb->pc = pc; tb->cflags = 0; + tcg_unlock(); return tb; } void tb_free(TranslationBlock *tb) { + tcg_lock(); /* In practice this is mostly used for single use temporary TB Ignore the hard cases and just back up if this TB happens to be the last one generated. */ @@ -780,6 +784,7 @@ void tb_free(TranslationBlock *tb) tcg_ctx.code_gen_ptr = tb->tc_ptr; tcg_ctx.tb_ctx.nb_tbs--; } + tcg_unlock(); } static inline void invalidate_page_bitmap(PageDesc *p) @@ -833,6 +838,7 @@ void tb_flush(CPUState *cpu) ((unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer)) / tcg_ctx.tb_ctx.nb_tbs : 0); #endif + tcg_lock(); if ((unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer) > tcg_ctx.code_gen_buffer_size) { cpu_abort(cpu, "Internal error: code buffer overflow\n"); @@ -850,6 +856,7 @@ void tb_flush(CPUState *cpu) /* XXX: flush processor icache at this point if cache flush is expensive */ tcg_ctx.tb_ctx.tb_flush_count++; + tcg_unlock(); } #ifdef DEBUG_TB_CHECK @@ -1208,8 +1215,10 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, int current_flags = 0; #endif /* TARGET_HAS_PRECISE_SMC */ + tcg_lock(); p = page_find(start >> TARGET_PAGE_BITS); if (!p) { + tcg_unlock(); return; } #if defined(TARGET_HAS_PRECISE_SMC) @@ -1294,6 +1303,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, cpu_resume_from_signal(cpu, NULL); } #endif + tcg_unlock(); } /* len must be <= 8 and start must be a multiple of len */ @@ -1511,13 +1521,16 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr) { int m_min, m_max, m; uintptr_t v; - TranslationBlock *tb; + TranslationBlock *tb, *r; + tcg_lock(); if (tcg_ctx.tb_ctx.nb_tbs <= 0) { + tcg_unlock(); return NULL; } if (tc_ptr < (uintptr_t)tcg_ctx.code_gen_buffer || tc_ptr >= (uintptr_t)tcg_ctx.code_gen_ptr) { + tcg_unlock(); return NULL; } /* binary search (cf Knuth) */ @@ -1528,6 +1541,7 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr) tb = &tcg_ctx.tb_ctx.tbs[m]; v = (uintptr_t)tb->tc_ptr; if (v == tc_ptr) { + tcg_unlock(); return tb; } else if (tc_ptr < v) { m_max = m - 1; @@ -1535,7 +1549,9 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr) m_min = m + 1; } } - return &tcg_ctx.tb_ctx.tbs[m_max]; + r = &tcg_ctx.tb_ctx.tbs[m_max]; + tcg_unlock(); + return r; } #if !defined(CONFIG_USER_ONLY) -- 2.51.1 From 39ce1e900aba8b93e2296b3d4c613fd7af58f347 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 23 Jul 2012 10:24:14 +0200 Subject: [PATCH 18/58] linux-user: Fake /proc/cpuinfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fedora 17 for ARM reads /proc/cpuinfo and fails if it doesn't contain ARM related contents. This patch implements a quick hack to expose real /proc/cpuinfo data taken from a real world machine. The real fix would be to generate at least the flags automatically based on the selected CPU. Please do not submit this patch upstream until this has happened. Signed-off-by: Alexander Graf [AF: Rebased for v1.6 and v1.7] Signed-off-by: Andreas Färber --- linux-user/syscall.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b36273de54..7476689460 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5697,6 +5697,25 @@ static int open_self_stat(void *cpu_env, int fd) return 0; } +static int open_cpuinfo(void *cpu_env, int fd) +{ + dprintf(fd, +"Processor : ARMv7 Processor rev 5 (v7l)\n" +"BogoMIPS : 799.53\n" +"Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3\n" +"CPU implementer : 0x41\n" +"CPU architecture: 7\n" +"CPU variant : 0x2\n" +"CPU part : 0xc08\n" +"CPU revision : 5\n" +"\n" +"Hardware : Genesi Efika MX (Smarttop)\n" +"Revision : 51030\n" +"Serial : 0000000000000000\n"); + + return 0; +} + static int open_self_auxv(void *cpu_env, int fd) { CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); @@ -5811,6 +5830,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) { "/proc/net/route", open_net_route, is_proc }, #endif + { "cpuinfo", open_cpuinfo, is_proc_myself }, { NULL, NULL, NULL } }; -- 2.51.1 From 2783b7f3c20040aaa53b59a9a716364f04562126 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 20 Aug 2012 00:02:52 +0200 Subject: [PATCH 19/58] linux-user: implement FS_IOC_GETFLAGS ioctl Signed-off-by: Alexander Graf --- v1 -> v2: - use TYPE_LONG instead of TYPE_INT --- linux-user/ioctls.h | 1 + linux-user/syscall_defs.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index c180fafb15..8650a70235 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -90,6 +90,7 @@ IOCTL_SPECIAL(FS_IOC_FIEMAP, IOC_W | IOC_R, do_ioctl_fs_ioc_fiemap, MK_PTR(MK_STRUCT(STRUCT_fiemap))) #endif + IOCTL(FS_IOC_GETFLAGS, IOC_R, MK_PTR(TYPE_LONG)) IOCTL(SIOCATMARK, 0, TYPE_NULL) IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT)) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index f820b0bb77..5152e897b7 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2457,6 +2457,8 @@ struct target_f_owner_ex { #define TARGET_MTIOCGET TARGET_IOR('m', 2, struct mtget) #define TARGET_MTIOCPOS TARGET_IOR('m', 3, struct mtpos) +#define TARGET_FS_IOC_GETFLAGS TARGET_IORU('f', 1) + struct target_sysinfo { abi_long uptime; /* Seconds since boot */ abi_ulong loads[3]; /* 1, 5, and 15 minute load averages */ -- 2.51.1 From fe937a73ac633b34380ac53c9057a0664c3b77cc Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 20 Aug 2012 00:07:13 +0200 Subject: [PATCH 20/58] linux-user: implement FS_IOC_SETFLAGS ioctl Signed-off-by: Alexander Graf --- v1 -> v2 - use TYPE_LONG instead of TYPE_INT --- linux-user/ioctls.h | 1 + linux-user/syscall_defs.h | 1 + 2 files changed, 2 insertions(+) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 8650a70235..f9f7c83787 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -91,6 +91,7 @@ MK_PTR(MK_STRUCT(STRUCT_fiemap))) #endif IOCTL(FS_IOC_GETFLAGS, IOC_R, MK_PTR(TYPE_LONG)) + IOCTL(FS_IOC_SETFLAGS, IOC_W, MK_PTR(TYPE_LONG)) IOCTL(SIOCATMARK, 0, TYPE_NULL) IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT)) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 5152e897b7..77be1817fc 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2458,6 +2458,7 @@ struct target_f_owner_ex { #define TARGET_MTIOCPOS TARGET_IOR('m', 3, struct mtpos) #define TARGET_FS_IOC_GETFLAGS TARGET_IORU('f', 1) +#define TARGET_FS_IOC_SETFLAGS TARGET_IOWU('f', 2) struct target_sysinfo { abi_long uptime; /* Seconds since boot */ -- 2.51.1 From 11b56fbe40bf880945a0563044b58b03d9d0baa7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 21 Aug 2012 14:20:40 +0200 Subject: [PATCH 21/58] linux-user: XXX disable fiemap agraf: fiemap breaks in libarchive. Disable it for now. --- linux-user/syscall.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7476689460..7b7278461c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3494,6 +3494,11 @@ static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp, uint32_t outbufsz; int free_fm = 0; + if (1) { + /* XXX agraf: fiemap breaks for me */ + return -TARGET_EINVAL; + } + assert(arg_type[0] == TYPE_PTR); assert(ie->access == IOC_RW); arg_type++; -- 2.51.1 From bd75d0195aef3af7392ce38952e018936da303ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 29 Aug 2012 18:42:56 +0200 Subject: [PATCH 22/58] slirp: -nooutgoing TBD (from SUSE Studio team) --- qemu-options.hx | 10 ++++++++++ slirp/socket.c | 8 ++++++++ slirp/tcp_subr.c | 12 ++++++++++++ vl.c | 9 +++++++++ 4 files changed, 39 insertions(+) diff --git a/qemu-options.hx b/qemu-options.hx index 6106520c56..32b25a5a4d 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3102,6 +3102,16 @@ Store the QEMU process PID in @var{file}. It is useful if you launch QEMU from a script. ETEXI +DEF("nooutgoing", HAS_ARG, QEMU_OPTION_nooutgoing, \ + "-nooutgoing \n" \ + " incoming traffic only from IP, no outgoing\n", \ + QEMU_ARCH_ALL) +STEXI +@item -nooutgoing +Forbid userspace networking to make outgoing connections. Only accept incoming +connections from ip address IP. +ETEXI + DEF("singlestep", 0, QEMU_OPTION_singlestep, \ "-singlestep always run in singlestep mode\n", QEMU_ARCH_ALL) STEXI diff --git a/slirp/socket.c b/slirp/socket.c index b336586c7b..8e5bdc37f9 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -608,6 +608,8 @@ sorecvfrom(struct socket *so) } /* if ping packet */ } +extern int slirp_nooutgoing; + /* * sendto() a socket */ @@ -625,6 +627,12 @@ sosendto(struct socket *so, struct mbuf *m) DEBUG_CALL(" sendto()ing)"); sotranslate_out(so, &addr); + /* Only allow DNS requests */ + if (slirp_nooutgoing && ntohs(((struct sockaddr_in *)&addr)->sin_port) != 53) { + errno = EHOSTUNREACH; + return -1; + } + /* Don't care what port we get */ ret = sendto(so->s, m->m_data, m->m_len, 0, (struct sockaddr *)&addr, sockaddr_size(&addr)); diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 6b9fef2008..e712e21581 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -391,6 +391,8 @@ tcp_sockclosed(struct tcpcb *tp) * nonblocking. Connect returns after the SYN is sent, and does * not wait for ACK+SYN. */ +extern int slirp_nooutgoing; + int tcp_fconnect(struct socket *so, unsigned short af) { int ret=0; @@ -398,6 +400,11 @@ int tcp_fconnect(struct socket *so, unsigned short af) DEBUG_CALL("tcp_fconnect"); DEBUG_ARG("so = %p", so); + if (slirp_nooutgoing) { + errno = EHOSTUNREACH; + return -1; + } + ret = so->s = qemu_socket(af, SOCK_STREAM, 0); if (ret >= 0) { int opt, s=so->s; @@ -478,6 +485,11 @@ void tcp_connect(struct socket *inso) tcp_close(sototcpcb(so)); /* This will sofree() as well */ return; } + if (slirp_nooutgoing && ((struct sockaddr_in *)&addr)->sin_addr.s_addr != slirp_nooutgoing) { + tcp_close(sototcpcb(so)); /* This will sofree() as well */ + closesocket(s); + return; + } qemu_set_nonblock(s); socket_set_fast_reuse(s); opt = 1; diff --git a/vl.c b/vl.c index 5db5dc2881..c08278920d 100644 --- a/vl.c +++ b/vl.c @@ -162,6 +162,7 @@ int smp_threads = 1; int acpi_enabled = 1; int no_hpet = 0; int fd_bootchk = 1; +int slirp_nooutgoing = 0; static int no_reboot; int no_shutdown = 0; int cursor_hide = 1; @@ -3386,6 +3387,14 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_singlestep: singlestep = 1; break; + case QEMU_OPTION_nooutgoing: + slirp_nooutgoing = inet_addr(optarg); + if (slirp_nooutgoing == INADDR_NONE) { + printf("Invalid address: %s.\nOnly addresses of the format " + "xxx.xxx.xxx.xxx are supported.\n", optarg); + exit(1); + } + break; case QEMU_OPTION_S: autostart = 0; break; -- 2.51.1 From aa0933c1b541cc1b7efae51d7a0cc3978e127c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 29 Aug 2012 20:06:01 +0200 Subject: [PATCH 23/58] vnc: password-file= and incoming-connections= TBD (from SUSE Studio team) --- ui/vnc.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/ui/vnc.c b/ui/vnc.c index 3e89dad8fa..e7946ba7e1 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -58,6 +58,8 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 }; static QTAILQ_HEAD(, VncDisplay) vnc_displays = QTAILQ_HEAD_INITIALIZER(vnc_displays); +static int allowed_connections = 0; + static int vnc_cursor_define(VncState *vs); static void vnc_release_modifiers(VncState *vs); @@ -1185,6 +1187,7 @@ static void vnc_disconnect_start(VncState *vs) void vnc_disconnect_finish(VncState *vs) { int i; + static int num_disconnects = 0; vnc_jobs_join(vs); /* Wait encoding jobs */ @@ -1235,6 +1238,13 @@ void vnc_disconnect_finish(VncState *vs) object_unref(OBJECT(vs->sioc)); vs->sioc = NULL; g_free(vs); + + num_disconnects++; + if (allowed_connections > 0 && allowed_connections <= num_disconnects) { + VNC_DEBUG("Maximum number of disconnects (%d) reached:" + " Session terminating\n", allowed_connections); + exit(0); + } } ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, Error **errp) @@ -3200,6 +3210,39 @@ char *vnc_display_local_addr(const char *id) return ret; } +static void read_file_password(const char *id, const char *filename) +{ + FILE *pfile = NULL; + char *passwd = NULL; + int start = 0, length = 0, rc = 0; + + if (strlen(filename) == 0) { + printf("No file supplied\n"); + return; + } + + pfile = fopen(filename, "r"); + if (pfile == NULL) { + printf("Could not read from %s\n", filename); + return; + } + + start = ftell(pfile); + fseek(pfile, 0L, SEEK_END); + length = ftell(pfile); + fseek(pfile, 0L, start); + + passwd = g_malloc(length + 1); + rc = fread(passwd, 1, length, pfile); + fclose(pfile); + + if (rc == length && rc > 0) { + vnc_display_password(id, passwd); + } + + g_free(passwd); +} + static QemuOptsList qemu_vnc_opts = { .name = "vnc", .head = QTAILQ_HEAD_INITIALIZER(qemu_vnc_opts.head), @@ -3230,6 +3273,9 @@ static QemuOptsList qemu_vnc_opts = { },{ .name = "connections", .type = QEMU_OPT_NUMBER, + },{ + .name = "allowed-connections", + .type = QEMU_OPT_NUMBER, },{ .name = "to", .type = QEMU_OPT_NUMBER, @@ -3242,6 +3288,9 @@ static QemuOptsList qemu_vnc_opts = { },{ .name = "password", .type = QEMU_OPT_BOOL, + },{ + .name = "password-file", + .type = QEMU_OPT_STRING, },{ .name = "reverse", .type = QEMU_OPT_BOOL, @@ -3476,6 +3525,7 @@ void vnc_display_open(const char *id, Error **errp) const char *share, *device_id; QemuConsole *con; bool password = false; + const char *password_file; bool reverse = false; const char *vnc; char *h; @@ -3601,6 +3651,10 @@ void vnc_display_open(const char *id, Error **errp) goto fail; } } + password_file = qemu_opt_get(opts, "password-file"); + if (password_file) { + read_file_password(id, password_file); + } reverse = qemu_opt_get_bool(opts, "reverse", false); lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true); @@ -3689,6 +3743,7 @@ void vnc_display_open(const char *id, Error **errp) vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; } vs->connections_limit = qemu_opt_get_number(opts, "connections", 32); + allowed_connections = qemu_opt_get_number(opts, "allowed-connections", 0); #ifdef CONFIG_VNC_JPEG vs->lossy = qemu_opt_get_bool(opts, "lossy", false); -- 2.51.1 From 32cee35bd3c2f98dc645350021de3d9e23be731d Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 10 Oct 2012 10:21:20 +0200 Subject: [PATCH 24/58] linux-user: add more blk ioctls Implement a few more ioctls that operate on block devices. Signed-off-by: Alexander Graf --- linux-user/ioctls.h | 18 ++++++++++++++++++ linux-user/syscall_defs.h | 6 ++++++ linux-user/syscall_types.h | 3 +++ 3 files changed, 27 insertions(+) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index f9f7c83787..8eb44468a9 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -72,6 +72,24 @@ IOCTL(BLKGETSIZE, IOC_R, MK_PTR(TYPE_ULONG)) #ifdef BLKGETSIZE64 IOCTL(BLKGETSIZE64, IOC_R, MK_PTR(TYPE_ULONGLONG)) +#endif +#ifdef BLKDISCARD + IOCTL(BLKDISCARD, IOC_W, MK_PTR(MK_STRUCT(STRUCT_blkdiscard))) +#endif +#ifdef BLKIOMIN + IOCTL(BLKIOMIN, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef BLKIOOPT + IOCTL(BLKIOOPT, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef BLKALIGNOFF + IOCTL(BLKALIGNOFF, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef BLKPBSZGET + IOCTL(BLKPBSZGET, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef BLKDISCARDZEROES + IOCTL(BLKDISCARDZEROES, IOC_R, MK_PTR(TYPE_INT)) #endif IOCTL(BLKFLSBUF, 0, TYPE_NULL) IOCTL(BLKRASET, 0, TYPE_INT) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 77be1817fc..787ba857b7 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -956,6 +956,12 @@ struct target_pollfd { #define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,abi_ulong) /* return device size in bytes (u64 *arg) */ +#define TARGET_BLKDISCARD TARGET_IO(0x12,119) +#define TARGET_BLKIOMIN TARGET_IO(0x12,120) +#define TARGET_BLKIOOPT TARGET_IO(0x12,121) +#define TARGET_BLKALIGNOFF TARGET_IO(0x12,122) +#define TARGET_BLKPBSZGET TARGET_IO(0x12,123) +#define TARGET_BLKDISCARDZEROES TARGET_IO(0x12,124) #define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */ #define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */ #define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap) diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index e5331b4495..a730c87baf 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -71,6 +71,9 @@ STRUCT(kbentry, STRUCT(kbsentry, TYPE_CHAR, MK_ARRAY(TYPE_CHAR, 512)) +STRUCT(blkdiscard, + MK_ARRAY(TYPE_LONGLONG, 2)) + STRUCT(audio_buf_info, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT) -- 2.51.1 From 232612b32aa306574282a98dafdef5772c99ea24 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 9 Oct 2012 09:06:49 +0200 Subject: [PATCH 25/58] linux-user: use target_ulong Linux syscalls pass pointers or data length or other information of that sort to the kernel. This is all stuff you don't want to have sign extended. Otherwise a host 64bit variable parameter with a size parameter will extend it to a negative number, breaking lseek for example. Pass syscall arguments as ulong always. Signed-off-by: Alexander Graf --- linux-user/qemu.h | 8 ++++---- linux-user/syscall.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 26b0ba2736..b9a712342f 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -176,10 +176,10 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src, void target_set_brk(abi_ulong new_brk); abi_long do_brk(abi_ulong new_brk); void syscall_init(void); -abi_long do_syscall(void *cpu_env, int num, abi_long arg1, - abi_long arg2, abi_long arg3, abi_long arg4, - abi_long arg5, abi_long arg6, abi_long arg7, - abi_long arg8); +abi_long do_syscall(void *cpu_env, int num, abi_ulong arg1, + abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, + abi_ulong arg5, abi_ulong arg6, abi_ulong arg7, + abi_ulong arg8); void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2); extern THREAD CPUState *thread_cpu; void cpu_loop(CPUArchState *env); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7b7278461c..ebeab57f9e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5902,10 +5902,10 @@ static target_timer_t get_timer_id(abi_long arg) /* do_syscall() should always have a single exit point at the end so that actions, such as logging of syscall results, can be performed. All errnos that do_syscall() returns must be -TARGET_. */ -abi_long do_syscall(void *cpu_env, int num, abi_long arg1, - abi_long arg2, abi_long arg3, abi_long arg4, - abi_long arg5, abi_long arg6, abi_long arg7, - abi_long arg8) +abi_long do_syscall(void *cpu_env, int num, abi_ulong arg1, + abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, + abi_ulong arg5, abi_ulong arg6, abi_ulong arg7, + abi_ulong arg8) { CPUState *cpu = ENV_GET_CPU(cpu_env); abi_long ret; -- 2.51.1 From 171c8acfae279756c43f0265e1cfc7d984ab5464 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 5 Aug 2009 09:49:37 +0200 Subject: [PATCH 26/58] block: Add support for DictZip enabled gzip files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DictZip is an extension to the gzip format that allows random seeks in gzip compressed files by cutting the file into pieces and storing the piece offsets in the "extra" header of the gzip format. Thanks to that extension, we can use gzip compressed files as block backend, though only in read mode. This makes a lot of sense when stacked with tar files that can then be shipped to VM users. If a VM image is inside a tar file that is inside a DictZip enabled gzip file, the user can run the tar.gz file as is without having to extract the image first. Tar patch follows. Signed-off-by: Alexander Graf Signed-off-by: Bruce Rogers Signed-off-by: Andreas Färber [TH: Use bdrv_open options instead of filename] Signed-off-by: Tim Hardeck [AF: Error **errp added for bdrv_file_open, bdrv_delete -> bdrv_unref] [AF: qemu_opts_create_nofail() -> qemu_opts_create(), bdrv_file_open() -> bdrv_open(), based on work by brogers] [AF: error_is_set() dropped for v2.1.0-rc0] [AF: BlockDriverAIOCB -> BlockAIOCB, BlockDriverCompletionFunc -> BlockCompletionFunc, qemu_aio_release() -> qemu_aio_unref(), drop dictzip_aio_cancel()] [AF: common-obj-y -> block-obj-y, drop probe hook (bsc#945778)] [AF: Drop bdrv_open() drv parameter for 2.5] Signed-off-by: Andreas Färber Signed-off-by: Bruce Rogers --- block/Makefile.objs | 1 + block/dictzip.c | 580 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 581 insertions(+) create mode 100644 block/dictzip.c diff --git a/block/Makefile.objs b/block/Makefile.objs index 44a5416225..12e0cca043 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -21,6 +21,7 @@ block-obj-$(CONFIG_GLUSTERFS) += gluster.o block-obj-$(CONFIG_ARCHIPELAGO) += archipelago.o block-obj-$(CONFIG_LIBSSH2) += ssh.o block-obj-y += accounting.o dirty-bitmap.o +block-obj-y += dictzip.o block-obj-y += write-threshold.o block-obj-y += crypto.o diff --git a/block/dictzip.c b/block/dictzip.c new file mode 100644 index 0000000000..717a7d3eda --- /dev/null +++ b/block/dictzip.c @@ -0,0 +1,580 @@ +/* + * DictZip Block driver for dictzip enabled gzip files + * + * Use the "dictzip" tool from the "dictd" package to create gzip files that + * contain the extra DictZip headers. + * + * dictzip(1) is a compression program which creates compressed files in the + * gzip format (see RFC 1952). However, unlike gzip(1), dictzip(1) compresses + * the file in pieces and stores an index to the pieces in the gzip header. + * This allows random access to the file at the granularity of the compressed + * pieces (currently about 64kB) while maintaining good compression ratios + * (within 5% of the expected ratio for dictionary data). + * dictd(8) uses files stored in this format. + * + * For details on DictZip see http://dict.org/. + * + * Copyright (c) 2009 Alexander Graf + * + * 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 "qemu-common.h" +#include "block/block_int.h" +#include + +// #define DEBUG + +#ifdef DEBUG +#define dprintf(fmt, ...) do { printf("dzip: " fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) do { } while (0) +#endif + +#define SECTOR_SIZE 512 +#define Z_STREAM_COUNT 4 +#define CACHE_COUNT 20 + +/* magic values */ + +#define GZ_MAGIC1 0x1f +#define GZ_MAGIC2 0x8b +#define DZ_MAGIC1 'R' +#define DZ_MAGIC2 'A' + +#define GZ_FEXTRA 0x04 /* Optional field (random access index) */ +#define GZ_FNAME 0x08 /* Original name */ +#define GZ_COMMENT 0x10 /* Zero-terminated, human-readable comment */ +#define GZ_FHCRC 0x02 /* Header CRC16 */ + +/* offsets */ + +#define GZ_ID 0 /* GZ_MAGIC (16bit) */ +#define GZ_FLG 3 /* FLaGs (see above) */ +#define GZ_XLEN 10 /* eXtra LENgth (16bit) */ +#define GZ_SI 12 /* Subfield ID (16bit) */ +#define GZ_VERSION 16 /* Version for subfield format */ +#define GZ_CHUNKSIZE 18 /* Chunk size (16bit) */ +#define GZ_CHUNKCNT 20 /* Number of chunks (16bit) */ +#define GZ_RNDDATA 22 /* Random access data (16bit) */ + +#define GZ_99_CHUNKSIZE 18 /* Chunk size (32bit) */ +#define GZ_99_CHUNKCNT 22 /* Number of chunks (32bit) */ +#define GZ_99_FILESIZE 26 /* Size of unpacked file (64bit) */ +#define GZ_99_RNDDATA 34 /* Random access data (32bit) */ + +struct BDRVDictZipState; + +typedef struct DictZipAIOCB { + BlockAIOCB common; + struct BDRVDictZipState *s; + QEMUIOVector *qiov; /* QIOV of the original request */ + QEMUIOVector *qiov_gz; /* QIOV of the gz subrequest */ + QEMUBH *bh; /* BH for cache */ + z_stream *zStream; /* stream to use for decoding */ + int zStream_id; /* stream id of the above pointer */ + size_t start; /* offset into the uncompressed file */ + size_t len; /* uncompressed bytes to read */ + uint8_t *gzipped; /* the gzipped data */ + uint8_t *buf; /* cached result */ + size_t gz_len; /* amount of gzip data */ + size_t gz_start; /* uncompressed starting point of gzip data */ + uint64_t offset; /* offset for "start" into the uncompressed chunk */ + int chunks_len; /* amount of uncompressed data in all gzip data */ +} DictZipAIOCB; + +typedef struct dict_cache { + size_t start; + size_t len; + uint8_t *buf; +} DictCache; + +typedef struct BDRVDictZipState { + BlockDriverState *hd; + z_stream zStream[Z_STREAM_COUNT]; + DictCache cache[CACHE_COUNT]; + int cache_index; + uint8_t stream_in_use; + uint64_t chunk_len; + uint32_t chunk_cnt; + uint16_t *chunks; + uint32_t *chunks32; + uint64_t *offsets; + int64_t file_len; +} BDRVDictZipState; + +static int start_zStream(z_stream *zStream) +{ + zStream->zalloc = NULL; + zStream->zfree = NULL; + zStream->opaque = NULL; + zStream->next_in = 0; + zStream->avail_in = 0; + zStream->next_out = NULL; + zStream->avail_out = 0; + + return inflateInit2( zStream, -15 ); +} + +static QemuOptsList runtime_opts = { + .name = "dzip", + .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), + .desc = { + { + .name = "filename", + .type = QEMU_OPT_STRING, + .help = "URL to the dictzip file", + }, + { /* end of list */ } + }, +}; + +static int dictzip_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) +{ + BDRVDictZipState *s = bs->opaque; + const char *err = "Unknown (read error?)"; + uint8_t magic[2]; + char buf[100]; + uint8_t header_flags; + uint16_t chunk_len16; + uint16_t chunk_cnt16; + uint16_t header_ver; + uint16_t tmp_short; + uint64_t offset; + int chunks_len; + int headerLength = GZ_XLEN - 1; + int rnd_offs; + int ret; + int i; + QemuOpts *opts; + Error *local_err = NULL; + const char *filename; + + opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); + qemu_opts_absorb_qdict(opts, options, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto fail; + } + + filename = qemu_opt_get(opts, "filename"); + + if (!strncmp(filename, "dzip://", 7)) + filename += 7; + else if (!strncmp(filename, "dzip:", 5)) + filename += 5; + + ret = bdrv_open(&s->hd, filename, NULL, NULL, flags | BDRV_O_PROTOCOL, &local_err); + if (ret < 0) { + error_propagate(errp, local_err); + qemu_opts_del(opts); + return ret; + } + + /* initialize zlib streams */ + for (i = 0; i < Z_STREAM_COUNT; i++) { + if (start_zStream( &s->zStream[i] ) != Z_OK) { + err = s->zStream[i].msg; + goto fail; + } + } + + /* gzip header */ + if (bdrv_pread(s->hd, GZ_ID, &magic, sizeof(magic)) != sizeof(magic)) + goto fail; + + if (!((magic[0] == GZ_MAGIC1) && (magic[1] == GZ_MAGIC2))) { + err = "No gzip file"; + goto fail; + } + + /* dzip header */ + if (bdrv_pread(s->hd, GZ_FLG, &header_flags, 1) != 1) + goto fail; + + if (!(header_flags & GZ_FEXTRA)) { + err = "Not a dictzip file (wrong flags)"; + goto fail; + } + + /* extra length */ + if (bdrv_pread(s->hd, GZ_XLEN, &tmp_short, 2) != 2) + goto fail; + + headerLength += le16_to_cpu(tmp_short) + 2; + + /* DictZip magic */ + if (bdrv_pread(s->hd, GZ_SI, &magic, 2) != 2) + goto fail; + + if (magic[0] != DZ_MAGIC1 || magic[1] != DZ_MAGIC2) { + err = "Not a dictzip file (missing extra magic)"; + goto fail; + } + + /* DictZip version */ + if (bdrv_pread(s->hd, GZ_VERSION, &header_ver, 2) != 2) + goto fail; + + header_ver = le16_to_cpu(header_ver); + + switch (header_ver) { + case 1: /* Normal DictZip */ + /* number of chunks */ + if (bdrv_pread(s->hd, GZ_CHUNKSIZE, &chunk_len16, 2) != 2) + goto fail; + + s->chunk_len = le16_to_cpu(chunk_len16); + + /* chunk count */ + if (bdrv_pread(s->hd, GZ_CHUNKCNT, &chunk_cnt16, 2) != 2) + goto fail; + + s->chunk_cnt = le16_to_cpu(chunk_cnt16); + chunks_len = sizeof(short) * s->chunk_cnt; + rnd_offs = GZ_RNDDATA; + break; + case 99: /* Special Alex pigz version */ + /* number of chunks */ + if (bdrv_pread(s->hd, GZ_99_CHUNKSIZE, &s->chunk_len, 4) != 4) + goto fail; + + dprintf("chunk len [%#x] = %d\n", GZ_99_CHUNKSIZE, s->chunk_len); + s->chunk_len = le32_to_cpu(s->chunk_len); + + /* chunk count */ + if (bdrv_pread(s->hd, GZ_99_CHUNKCNT, &s->chunk_cnt, 4) != 4) + goto fail; + + s->chunk_cnt = le32_to_cpu(s->chunk_cnt); + + dprintf("chunk len | count = %d | %d\n", s->chunk_len, s->chunk_cnt); + + /* file size */ + if (bdrv_pread(s->hd, GZ_99_FILESIZE, &s->file_len, 8) != 8) + goto fail; + + s->file_len = le64_to_cpu(s->file_len); + chunks_len = sizeof(int) * s->chunk_cnt; + rnd_offs = GZ_99_RNDDATA; + break; + default: + err = "Invalid DictZip version"; + goto fail; + } + + /* random access data */ + s->chunks = g_malloc(chunks_len); + if (header_ver == 99) + s->chunks32 = (uint32_t *)s->chunks; + + if (bdrv_pread(s->hd, rnd_offs, s->chunks, chunks_len) != chunks_len) + goto fail; + + /* orig filename */ + if (header_flags & GZ_FNAME) { + if (bdrv_pread(s->hd, headerLength + 1, buf, sizeof(buf)) != sizeof(buf)) + goto fail; + + buf[sizeof(buf) - 1] = '\0'; + headerLength += strlen(buf) + 1; + + if (strlen(buf) == sizeof(buf)) + goto fail; + + dprintf("filename: %s\n", buf); + } + + /* comment field */ + if (header_flags & GZ_COMMENT) { + if (bdrv_pread(s->hd, headerLength, buf, sizeof(buf)) != sizeof(buf)) + goto fail; + + buf[sizeof(buf) - 1] = '\0'; + headerLength += strlen(buf) + 1; + + if (strlen(buf) == sizeof(buf)) + goto fail; + + dprintf("comment: %s\n", buf); + } + + if (header_flags & GZ_FHCRC) + headerLength += 2; + + /* uncompressed file length*/ + if (!s->file_len) { + uint32_t file_len; + + if (bdrv_pread(s->hd, bdrv_getlength(s->hd) - 4, &file_len, 4) != 4) + goto fail; + + s->file_len = le32_to_cpu(file_len); + } + + /* compute offsets */ + s->offsets = g_malloc(sizeof( *s->offsets ) * s->chunk_cnt); + + for (offset = headerLength + 1, i = 0; i < s->chunk_cnt; i++) { + s->offsets[i] = offset; + switch (header_ver) { + case 1: + offset += s->chunks[i]; + break; + case 99: + offset += s->chunks32[i]; + break; + } + + dprintf("chunk %#x - %#x = offset %#x -> %#x\n", i * s->chunk_len, (i+1) * s->chunk_len, s->offsets[i], offset); + } + qemu_opts_del(opts); + + return 0; + +fail: + fprintf(stderr, "DictZip: Error opening file: %s\n", err); + bdrv_unref(s->hd); + if (s->chunks) + g_free(s->chunks); + qemu_opts_del(opts); + return -EINVAL; +} + +/* This callback gets invoked when we have the result in cache already */ +static void dictzip_cache_cb(void *opaque) +{ + DictZipAIOCB *acb = (DictZipAIOCB *)opaque; + + qemu_iovec_from_buf(acb->qiov, 0, acb->buf, acb->len); + acb->common.cb(acb->common.opaque, 0); + qemu_bh_delete(acb->bh); + qemu_aio_unref(acb); +} + +/* This callback gets invoked by the underlying block reader when we have + * all compressed data. We uncompress in here. */ +static void dictzip_read_cb(void *opaque, int ret) +{ + DictZipAIOCB *acb = (DictZipAIOCB *)opaque; + struct BDRVDictZipState *s = acb->s; + uint8_t *buf; + DictCache *cache; + int r; + + buf = g_malloc(acb->chunks_len); + + /* uncompress the chunk */ + acb->zStream->next_in = acb->gzipped; + acb->zStream->avail_in = acb->gz_len; + acb->zStream->next_out = buf; + acb->zStream->avail_out = acb->chunks_len; + + r = inflate( acb->zStream, Z_PARTIAL_FLUSH ); + if ( (r != Z_OK) && (r != Z_STREAM_END) ) + fprintf(stderr, "Error inflating: [%d] %s\n", r, acb->zStream->msg); + + if ( r == Z_STREAM_END ) + inflateReset(acb->zStream); + + dprintf("inflating [%d] left: %d | %d bytes\n", r, acb->zStream->avail_in, acb->zStream->avail_out); + s->stream_in_use &= ~(1 << acb->zStream_id); + + /* nofity the caller */ + qemu_iovec_from_buf(acb->qiov, 0, buf + acb->offset, acb->len); + acb->common.cb(acb->common.opaque, 0); + + /* fill the cache */ + cache = &s->cache[s->cache_index]; + s->cache_index++; + if (s->cache_index == CACHE_COUNT) + s->cache_index = 0; + + cache->len = 0; + if (cache->buf) + g_free(cache->buf); + cache->start = acb->gz_start; + cache->buf = buf; + cache->len = acb->chunks_len; + + /* free occupied ressources */ + g_free(acb->qiov_gz); + qemu_aio_unref(acb); +} + +static const AIOCBInfo dictzip_aiocb_info = { + .aiocb_size = sizeof(DictZipAIOCB), +}; + +/* This is where we get a request from a caller to read something */ +static BlockAIOCB *dictzip_aio_readv(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockCompletionFunc *cb, void *opaque) +{ + BDRVDictZipState *s = bs->opaque; + DictZipAIOCB *acb; + QEMUIOVector *qiov_gz; + struct iovec *iov; + uint8_t *buf; + size_t start = sector_num * SECTOR_SIZE; + size_t len = nb_sectors * SECTOR_SIZE; + size_t end = start + len; + size_t gz_start; + size_t gz_len; + int64_t gz_sector_num; + int gz_nb_sectors; + int first_chunk, last_chunk; + int first_offset; + int i; + + acb = qemu_aio_get(&dictzip_aiocb_info, bs, cb, opaque); + if (!acb) + return NULL; + + /* Search Cache */ + for (i = 0; i < CACHE_COUNT; i++) { + if (!s->cache[i].len) + continue; + + if ((start >= s->cache[i].start) && + (end <= (s->cache[i].start + s->cache[i].len))) { + acb->buf = s->cache[i].buf + (start - s->cache[i].start); + acb->len = len; + acb->qiov = qiov; + acb->bh = qemu_bh_new(dictzip_cache_cb, acb); + qemu_bh_schedule(acb->bh); + + return &acb->common; + } + } + + /* No cache, so let's decode */ + do { + for (i = 0; i < Z_STREAM_COUNT; i++) { + if (!(s->stream_in_use & (1 << i))) { + s->stream_in_use |= (1 << i); + acb->zStream_id = i; + acb->zStream = &s->zStream[i]; + break; + } + } + } while(!acb->zStream); + + /* We need to read these chunks */ + first_chunk = start / s->chunk_len; + first_offset = start - first_chunk * s->chunk_len; + last_chunk = end / s->chunk_len; + + gz_start = s->offsets[first_chunk]; + gz_len = 0; + for (i = first_chunk; i <= last_chunk; i++) { + if (s->chunks32) + gz_len += s->chunks32[i]; + else + gz_len += s->chunks[i]; + } + + gz_sector_num = gz_start / SECTOR_SIZE; + gz_nb_sectors = (gz_len / SECTOR_SIZE); + + /* account for tail and heads */ + while ((gz_start + gz_len) > ((gz_sector_num + gz_nb_sectors) * SECTOR_SIZE)) + gz_nb_sectors++; + + /* Allocate qiov, iov and buf in one chunk so we only need to free qiov */ + qiov_gz = g_malloc0(sizeof(QEMUIOVector) + sizeof(struct iovec) + + (gz_nb_sectors * SECTOR_SIZE)); + iov = (struct iovec *)(((char *)qiov_gz) + sizeof(QEMUIOVector)); + buf = ((uint8_t *)iov) + sizeof(struct iovec *); + + /* Kick off the read by the backing file, so we can start decompressing */ + iov->iov_base = (void *)buf; + iov->iov_len = gz_nb_sectors * 512; + qemu_iovec_init_external(qiov_gz, iov, 1); + + dprintf("read %d - %d => %d - %d\n", start, end, gz_start, gz_start + gz_len); + + acb->s = s; + acb->qiov = qiov; + acb->qiov_gz = qiov_gz; + acb->start = start; + acb->len = len; + acb->gzipped = buf + (gz_start % SECTOR_SIZE); + acb->gz_len = gz_len; + acb->gz_start = first_chunk * s->chunk_len; + acb->offset = first_offset; + acb->chunks_len = (last_chunk - first_chunk + 1) * s->chunk_len; + + return bdrv_aio_readv(s->hd, gz_sector_num, qiov_gz, gz_nb_sectors, + dictzip_read_cb, acb); +} + +static void dictzip_close(BlockDriverState *bs) +{ + BDRVDictZipState *s = bs->opaque; + int i; + + for (i = 0; i < CACHE_COUNT; i++) { + if (!s->cache[i].len) + continue; + + g_free(s->cache[i].buf); + } + + for (i = 0; i < Z_STREAM_COUNT; i++) { + inflateEnd(&s->zStream[i]); + } + + if (s->chunks) + g_free(s->chunks); + + if (s->offsets) + g_free(s->offsets); + + dprintf("Close\n"); +} + +static int64_t dictzip_getlength(BlockDriverState *bs) +{ + BDRVDictZipState *s = bs->opaque; + dprintf("getlength -> %ld\n", s->file_len); + return s->file_len; +} + +static BlockDriver bdrv_dictzip = { + .format_name = "dzip", + .protocol_name = "dzip", + + .instance_size = sizeof(BDRVDictZipState), + .bdrv_file_open = dictzip_open, + .bdrv_close = dictzip_close, + .bdrv_getlength = dictzip_getlength, + + .bdrv_aio_readv = dictzip_aio_readv, +}; + +static void dictzip_block_init(void) +{ + bdrv_register(&bdrv_dictzip); +} + +block_init(dictzip_block_init); -- 2.51.1 From e05a6cfd83e972bf46ca8e8ce7a00d83c882e2d8 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 5 Aug 2009 17:28:38 +0200 Subject: [PATCH 27/58] block: Add tar container format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tar is a very widely used format to store data in. Sometimes people even put virtual machine images in there. So it makes sense for qemu to be able to read from tar files. I implemented a written from scratch reader that also knows about the GNU sparse format, which is what pigz creates. This version checks for filenames that end on well-known extensions. The logic could be changed to search for filenames given on the command line, but that would require changes to more parts of qemu. The tar reader in conjunctiuon with dzip gives us the chance to download tar'ed up virtual machine images (even via http) and instantly make use of them. Signed-off-by: Alexander Graf Signed-off-by: Bruce Rogers Signed-off-by: Andreas Färber [TH: Use bdrv_open options instead of filename] Signed-off-by: Tim Hardeck [AF: bdrv_file_open got an Error **errp argument, bdrv_delete -> brd_unref] [AF: qemu_opts_create_nofail() -> qemu_opts_create(), bdrv_file_open() -> bdrv_open(), based on work by brogers] [AF: error_is_set() dropped for v2.1.0-rc0] [AF: BlockDriverAIOCB -> BlockAIOCB, BlockDriverCompletionFunc -> BlockCompletionFunc, qemu_aio_release() -> qemu_aio_unref(), drop tar_aio_cancel()] [AF: common-obj-y -> block-obj-y, drop probe hook (bsc#945778)] [AF: Drop bdrv_open() drv parameter for 2.5] Signed-off-by: Andreas Färber Signed-off-by: Bruce Rogers --- block/Makefile.objs | 1 + block/tar.c | 370 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 371 insertions(+) create mode 100644 block/tar.c diff --git a/block/Makefile.objs b/block/Makefile.objs index 12e0cca043..34a6fba482 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -22,6 +22,7 @@ block-obj-$(CONFIG_ARCHIPELAGO) += archipelago.o block-obj-$(CONFIG_LIBSSH2) += ssh.o block-obj-y += accounting.o dirty-bitmap.o block-obj-y += dictzip.o +block-obj-y += tar.o block-obj-y += write-threshold.o block-obj-y += crypto.o diff --git a/block/tar.c b/block/tar.c new file mode 100644 index 0000000000..31da8b93b7 --- /dev/null +++ b/block/tar.c @@ -0,0 +1,370 @@ +/* + * Tar block driver + * + * Copyright (c) 2009 Alexander Graf + * + * 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 "qemu-common.h" +#include "block/block_int.h" + +// #define DEBUG + +#ifdef DEBUG +#define dprintf(fmt, ...) do { printf("tar: " fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) do { } while (0) +#endif + +#define SECTOR_SIZE 512 + +#define POSIX_TAR_MAGIC "ustar" +#define OFFS_LENGTH 0x7c +#define OFFS_TYPE 0x9c +#define OFFS_MAGIC 0x101 + +#define OFFS_S_SP 0x182 +#define OFFS_S_EXT 0x1e2 +#define OFFS_S_LENGTH 0x1e3 +#define OFFS_SX_EXT 0x1f8 + +typedef struct SparseCache { + uint64_t start; + uint64_t end; +} SparseCache; + +typedef struct BDRVTarState { + BlockDriverState *hd; + size_t file_sec; + uint64_t file_len; + SparseCache *sparse; + int sparse_num; + uint64_t last_end; + char longfile[2048]; +} BDRVTarState; + +static int str_ends(char *str, const char *end) +{ + int end_len = strlen(end); + int str_len = strlen(str); + + if (str_len < end_len) + return 0; + + return !strncmp(str + str_len - end_len, end, end_len); +} + +static int is_target_file(BlockDriverState *bs, char *filename) +{ + int retval = 0; + + if (str_ends(filename, ".raw")) + retval = 1; + + if (str_ends(filename, ".qcow")) + retval = 1; + + if (str_ends(filename, ".qcow2")) + retval = 1; + + if (str_ends(filename, ".vmdk")) + retval = 1; + + dprintf("does filename %s match? %s\n", filename, retval ? "yes" : "no"); + + /* make sure we're not using this name again */ + filename[0] = '\0'; + return retval; +} + +static uint64_t tar2u64(char *ptr) +{ + uint64_t retval; + char oldend = ptr[12]; + + ptr[12] = '\0'; + if (*ptr & 0x80) { + /* XXX we only support files up to 64 bit length */ + retval = be64_to_cpu(*(uint64_t *)(ptr+4)); + dprintf("Convert %lx -> %#lx\n", *(uint64_t*)(ptr+4), retval); + } else { + retval = strtol(ptr, NULL, 8); + dprintf("Convert %s -> %#lx\n", ptr, retval); + } + + ptr[12] = oldend; + + return retval; +} + +static void tar_sparse(BDRVTarState *s, uint64_t offs, uint64_t len) +{ + SparseCache *sparse; + + if (!len) + return; + if (!(offs - s->last_end)) { + s->last_end += len; + return; + } + if (s->last_end > offs) + return; + + dprintf("Last chunk until %lx new chunk at %lx\n", s->last_end, offs); + + s->sparse = g_realloc(s->sparse, (s->sparse_num + 1) * sizeof(SparseCache)); + sparse = &s->sparse[s->sparse_num]; + sparse->start = s->last_end; + sparse->end = offs; + s->last_end = offs + len; + s->sparse_num++; + dprintf("Sparse at %lx end=%lx\n", sparse->start, + sparse->end); +} + +static QemuOptsList runtime_opts = { + .name = "tar", + .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), + .desc = { + { + .name = "filename", + .type = QEMU_OPT_STRING, + .help = "URL to the tar file", + }, + { /* end of list */ } + }, +}; + +static int tar_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) +{ + BDRVTarState *s = bs->opaque; + char header[SECTOR_SIZE]; + char *real_file = header; + char *magic; + size_t header_offs = 0; + int ret; + QemuOpts *opts; + Error *local_err = NULL; + const char *filename; + + opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); + qemu_opts_absorb_qdict(opts, options, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto fail; + } + + filename = qemu_opt_get(opts, "filename"); + + if (!strncmp(filename, "tar://", 6)) + filename += 6; + else if (!strncmp(filename, "tar:", 4)) + filename += 4; + + ret = bdrv_open(&s->hd, filename, NULL, NULL, flags | BDRV_O_PROTOCOL, &local_err); + if (ret < 0) { + error_propagate(errp, local_err); + qemu_opts_del(opts); + return ret; + } + + /* Search the file for an image */ + + do { + /* tar header */ + if (bdrv_pread(s->hd, header_offs, header, SECTOR_SIZE) != SECTOR_SIZE) + goto fail; + + if ((header_offs > 1) && !header[0]) { + fprintf(stderr, "Tar: No image file found in archive\n"); + goto fail; + } + + magic = &header[OFFS_MAGIC]; + if (strncmp(magic, POSIX_TAR_MAGIC, 5)) { + fprintf(stderr, "Tar: Invalid magic: %s\n", magic); + goto fail; + } + + dprintf("file type: %c\n", header[OFFS_TYPE]); + + /* file length*/ + s->file_len = (tar2u64(&header[OFFS_LENGTH]) + (SECTOR_SIZE - 1)) & + ~(SECTOR_SIZE - 1); + s->file_sec = (header_offs / SECTOR_SIZE) + 1; + + header_offs += s->file_len + SECTOR_SIZE; + + if (header[OFFS_TYPE] == 'L') { + bdrv_pread(s->hd, header_offs - s->file_len, s->longfile, + sizeof(s->longfile)); + s->longfile[sizeof(s->longfile)-1] = '\0'; + } else if (s->longfile[0]) { + real_file = s->longfile; + } else { + real_file = header; + } + } while(!is_target_file(bs, real_file)); + + /* We found an image! */ + + if (header[OFFS_TYPE] == 'S') { + uint8_t isextended; + int i; + + for (i = OFFS_S_SP; i < (OFFS_S_SP + (4 * 24)); i += 24) + tar_sparse(s, tar2u64(&header[i]), tar2u64(&header[i+12])); + + s->file_len = tar2u64(&header[OFFS_S_LENGTH]); + isextended = header[OFFS_S_EXT]; + + while (isextended) { + if (bdrv_pread(s->hd, s->file_sec * SECTOR_SIZE, header, + SECTOR_SIZE) != SECTOR_SIZE) + goto fail; + + for (i = 0; i < (21 * 24); i += 24) + tar_sparse(s, tar2u64(&header[i]), tar2u64(&header[i+12])); + isextended = header[OFFS_SX_EXT]; + s->file_sec++; + } + tar_sparse(s, s->file_len, 1); + } + qemu_opts_del(opts); + + return 0; + +fail: + fprintf(stderr, "Tar: Error opening file\n"); + bdrv_unref(s->hd); + qemu_opts_del(opts); + return -EINVAL; +} + +typedef struct TarAIOCB { + BlockAIOCB common; + QEMUBH *bh; +} TarAIOCB; + +/* This callback gets invoked when we have pure sparseness */ +static void tar_sparse_cb(void *opaque) +{ + TarAIOCB *acb = (TarAIOCB *)opaque; + + acb->common.cb(acb->common.opaque, 0); + qemu_bh_delete(acb->bh); + qemu_aio_unref(acb); +} + +static AIOCBInfo tar_aiocb_info = { + .aiocb_size = sizeof(TarAIOCB), +}; + +/* This is where we get a request from a caller to read something */ +static BlockAIOCB *tar_aio_readv(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockCompletionFunc *cb, void *opaque) +{ + BDRVTarState *s = bs->opaque; + SparseCache *sparse; + int64_t sec_file = sector_num + s->file_sec; + int64_t start = sector_num * SECTOR_SIZE; + int64_t end = start + (nb_sectors * SECTOR_SIZE); + int i; + TarAIOCB *acb; + + for (i = 0; i < s->sparse_num; i++) { + sparse = &s->sparse[i]; + if (sparse->start > end) { + /* We expect the cache to be start increasing */ + break; + } else if ((sparse->start < start) && (sparse->end <= start)) { + /* sparse before our offset */ + sec_file -= (sparse->end - sparse->start) / SECTOR_SIZE; + } else if ((sparse->start <= start) && (sparse->end >= end)) { + /* all our sectors are sparse */ + char *buf = g_malloc0(nb_sectors * SECTOR_SIZE); + + acb = qemu_aio_get(&tar_aiocb_info, bs, cb, opaque); + qemu_iovec_from_buf(qiov, 0, buf, nb_sectors * SECTOR_SIZE); + g_free(buf); + acb->bh = qemu_bh_new(tar_sparse_cb, acb); + qemu_bh_schedule(acb->bh); + + return &acb->common; + } else if (((sparse->start >= start) && (sparse->start < end)) || + ((sparse->end >= start) && (sparse->end < end))) { + /* we're semi-sparse (worst case) */ + /* let's go synchronous and read all sectors individually */ + char *buf = g_malloc(nb_sectors * SECTOR_SIZE); + uint64_t offs; + + for (offs = 0; offs < (nb_sectors * SECTOR_SIZE); + offs += SECTOR_SIZE) { + bdrv_pread(bs, (sector_num * SECTOR_SIZE) + offs, + buf + offs, SECTOR_SIZE); + } + + qemu_iovec_from_buf(qiov, 0, buf, nb_sectors * SECTOR_SIZE); + acb = qemu_aio_get(&tar_aiocb_info, bs, cb, opaque); + acb->bh = qemu_bh_new(tar_sparse_cb, acb); + qemu_bh_schedule(acb->bh); + + return &acb->common; + } + } + + return bdrv_aio_readv(s->hd, sec_file, qiov, nb_sectors, + cb, opaque); +} + +static void tar_close(BlockDriverState *bs) +{ + dprintf("Close\n"); +} + +static int64_t tar_getlength(BlockDriverState *bs) +{ + BDRVTarState *s = bs->opaque; + dprintf("getlength -> %ld\n", s->file_len); + return s->file_len; +} + +static BlockDriver bdrv_tar = { + .format_name = "tar", + .protocol_name = "tar", + + .instance_size = sizeof(BDRVTarState), + .bdrv_file_open = tar_open, + .bdrv_close = tar_close, + .bdrv_getlength = tar_getlength, + + .bdrv_aio_readv = tar_aio_readv, +}; + +static void tar_block_init(void) +{ + bdrv_register(&bdrv_tar); +} + +block_init(tar_block_init); -- 2.51.1 From e04e97093af3fc593a7db57be40e7334f9776330 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 12 Dec 2012 19:11:30 +0100 Subject: [PATCH 28/58] Legacy Patch kvm-qemu-preXX-dictzip3.patch --- block/tar.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/block/tar.c b/block/tar.c index 31da8b93b7..41620fd919 100644 --- a/block/tar.c +++ b/block/tar.c @@ -73,7 +73,8 @@ static int str_ends(char *str, const char *end) return !strncmp(str + str_len - end_len, end, end_len); } -static int is_target_file(BlockDriverState *bs, char *filename) +static int is_target_file(BlockDriverState *bs, char *filename, + char *header) { int retval = 0; @@ -89,10 +90,17 @@ static int is_target_file(BlockDriverState *bs, char *filename) if (str_ends(filename, ".vmdk")) retval = 1; + if (retval && + (header[OFFS_TYPE] != '0') && + (header[OFFS_TYPE] != 'S')) { + retval = 0; + } + dprintf("does filename %s match? %s\n", filename, retval ? "yes" : "no"); /* make sure we're not using this name again */ filename[0] = '\0'; + return retval; } @@ -219,12 +227,13 @@ static int tar_open(BlockDriverState *bs, QDict *options, int flags, Error **err bdrv_pread(s->hd, header_offs - s->file_len, s->longfile, sizeof(s->longfile)); s->longfile[sizeof(s->longfile)-1] = '\0'; + real_file = header; } else if (s->longfile[0]) { real_file = s->longfile; } else { real_file = header; } - } while(!is_target_file(bs, real_file)); + } while(!is_target_file(bs, real_file, header)); /* We found an image! */ -- 2.51.1 From 36f007f4de748aff064604637383a23cbebe813e Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 6 Jun 2011 06:53:52 +0200 Subject: [PATCH 29/58] console: add question-mark escape operator Some termcaps (found using SLES11SP1) use [? sequences. According to man console_codes (http://linux.die.net/man/4/console_codes) the question mark is a nop and should simply be ignored. This patch does exactly that, rendering screen output readable when outputting guest serial consoles to the graphical console emulator. Signed-off-by: Alexander Graf --- ui/console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/console.c b/ui/console.c index bf385790b5..0c1b4a3f77 100644 --- a/ui/console.c +++ b/ui/console.c @@ -868,7 +868,7 @@ static void console_putchar(QemuConsole *s, int ch) } else { if (s->nb_esc_params < MAX_ESC_PARAMS) s->nb_esc_params++; - if (ch == ';') + if (ch == ';' || ch == '?') break; trace_console_putchar_csi(s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params); -- 2.51.1 From f745251506bedd96fb153b838dbf8a399eb8e275 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 1 Apr 2010 17:36:23 +0200 Subject: [PATCH 30/58] Make char muxer more robust wrt small FIFOs Virtio-Console can only process one character at a time. Using it on S390 gave me strage "lags" where I got the character I pressed before when pressing one. So I typed in "abc" and only received "a", then pressed "d" but the guest received "b" and so on. While the stdio driver calls a poll function that just processes on its queue in case virtio-console can't take multiple characters at once, the muxer does not have such callbacks, so it can't empty its queue. To work around that limitation, I introduced a new timer that only gets active when the guest can not receive any more characters. In that case it polls again after a while to check if the guest is now receiving input. This patch fixes input when using -nographic on s390 for me. --- qemu-char.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/qemu-char.c b/qemu-char.c index b597ee19ca..eedae4f614 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -512,6 +512,9 @@ typedef struct { IOEventHandler *chr_event[MAX_MUX]; void *ext_opaque[MAX_MUX]; CharDriverState *drv; +#if defined(TARGET_S390X) + QEMUTimer *accept_timer; +#endif int focus; int mux_cnt; int term_got_escape; @@ -671,6 +674,15 @@ static void mux_chr_accept_input(CharDriverState *chr) d->chr_read[m](d->ext_opaque[m], &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1); } + +#if defined(TARGET_S390X) + /* We're still not able to sync producer and consumer, so let's wait a bit + and try again by then. */ + if (d->prod[m] != d->cons[m]) { + qemu_mod_timer(d->accept_timer, qemu_get_clock_ns(vm_clock) + + (int64_t)100000); + } +#endif } static int mux_chr_can_read(void *opaque) @@ -812,6 +824,10 @@ static CharDriverState *qemu_chr_open_mux(const char *id, chr->opaque = d; d->drv = drv; d->focus = -1; +#if defined(TARGET_S390X) + d->accept_timer = qemu_new_timer_ns(vm_clock, + (QEMUTimerCB*)mux_chr_accept_input, chr); +#endif chr->chr_write = mux_chr_write; chr->chr_update_read_handler = mux_chr_update_read_handler; chr->chr_accept_input = mux_chr_accept_input; -- 2.51.1 From e7c736a9bfa10f1acb5e6b02c73fd8662d5c6a6c Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 13 Dec 2012 14:29:22 +0100 Subject: [PATCH 31/58] linux-user: lseek: explicitly cast non-set offsets to signed When doing lseek, SEEK_SET indicates that the offset is an unsigned variable. Other seek types have parameters that can be negative. When converting from 32bit to 64bit parameters, we need to take this into account and enable SEEK_END and SEEK_CUR to be negative, while SEEK_SET stays absolute positioned which we need to maintain as unsigned. Signed-off-by: Alexander Graf --- linux-user/syscall.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ebeab57f9e..c084f38490 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6233,9 +6233,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_ulong arg1, case TARGET_NR_oldstat: goto unimplemented; #endif - case TARGET_NR_lseek: - ret = get_errno(lseek(arg1, arg2, arg3)); + case TARGET_NR_lseek: { + off_t off = arg2; + if (arg3 != SEEK_SET) { + off = (abi_long)arg2; + } + ret = get_errno(lseek(arg1, off, arg3)); break; + } #if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA) /* Alpha specific */ case TARGET_NR_getxpid: -- 2.51.1 From 96ff92eb1a6402f0b90e4394990eda7f5e457d13 Mon Sep 17 00:00:00 2001 From: Bruce Rogers Date: Thu, 16 May 2013 12:39:10 +0200 Subject: [PATCH 32/58] virtfs-proxy-helper: Provide __u64 for broken sys/capability.h Fixes the build on SLE 11 SP2. [AF: Extend to ppc64] --- fsdev/virtfs-proxy-helper.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c index 54f7ad1c48..b4bf2f40c9 100644 --- a/fsdev/virtfs-proxy-helper.c +++ b/fsdev/virtfs-proxy-helper.c @@ -9,6 +9,13 @@ * the COPYING file in the top-level directory. */ +/* work around a broken sys/capability.h */ +#if defined(__i386__) +typedef unsigned long long __u64; +#endif +#if defined(__powerpc64__) +#include +#endif #include "qemu/osdep.h" #include #include -- 2.51.1 From 2181064a8a8f7a22285ae767affb23dc684d7d10 Mon Sep 17 00:00:00 2001 From: Dinar Valeev Date: Wed, 2 Oct 2013 17:56:03 +0200 Subject: [PATCH 33/58] configure: Enable PIE for ppc and ppc64 hosts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Dinar Valeev [AF: Rebased for v1.7] Signed-off-by: Andreas Färber --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 60e3c0dd6d..65232affbb 100755 --- a/configure +++ b/configure @@ -1537,7 +1537,7 @@ fi if test "$pie" = ""; then case "$cpu-$targetos" in - i386-Linux|x86_64-Linux|x32-Linux|i386-OpenBSD|x86_64-OpenBSD) + i386-Linux|x86_64-Linux|x32-Linux|ppc*-Linux|i386-OpenBSD|x86_64-OpenBSD) ;; *) pie="no" -- 2.51.1 From bc88332e8bf07bf413f32131cd20f4e2ba9aeb6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 17 Apr 2014 18:39:10 +0200 Subject: [PATCH 34/58] qtest: Increase socket timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change from 5 to 15 seconds. Signed-off-by: Andreas Färber --- tests/libqtest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libqtest.c b/tests/libqtest.c index b12a9e4ca9..8de01c07e9 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -27,7 +27,7 @@ #include "qapi/qmp/qjson.h" #define MAX_IRQ 256 -#define SOCKET_TIMEOUT 5 +#define SOCKET_TIMEOUT 15 QTestState *global_qtest; -- 2.51.1 From e69780e5f390f491fae554f1a0b0649c9187869e Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 14 Jan 2015 01:32:11 +0100 Subject: [PATCH 35/58] AIO: Reduce number of threads for 32bit hosts On hosts with limited virtual address space (32bit pointers), we can very easily run out of virtual memory with big thread pools. Instead, we should limit ourselves to small pools to keep memory footprint low on those systems. This patch fixes random VM stalls like (process:25114): GLib-ERROR **: gmem.c:103: failed to allocate 1048576 bytes on 32bit ARM systems for me. Signed-off-by: Alexander Graf --- thread-pool.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/thread-pool.c b/thread-pool.c index 03ba0b02a4..b5b4fd3a7b 100644 --- a/thread-pool.c +++ b/thread-pool.c @@ -297,7 +297,12 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) qemu_mutex_init(&pool->lock); qemu_cond_init(&pool->worker_stopped); qemu_sem_init(&pool->sem, 0); - pool->max_threads = 64; + if (sizeof(pool) == 4) { + /* 32bit systems run out of virtual memory quickly */ + pool->max_threads = 4; + } else { + pool->max_threads = 64; + } pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool); QLIST_INIT(&pool->head); -- 2.51.1 From 6bfa8a2b720bb6cc36a933870a2a1c0a239b3e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 14 Apr 2015 18:42:06 +0200 Subject: [PATCH 36/58] configure: Enable libseccomp for ppc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our Factory libseccomp is patched to support ppc, ppc64 and ppc64le. Signed-off-by: Andreas Färber --- configure | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure b/configure index 65232affbb..bf74354139 100755 --- a/configure +++ b/configure @@ -1879,6 +1879,9 @@ if test "$seccomp" != "no" ; then arm|aarch64) libseccomp_minver="2.2.3" ;; + ppc|ppc64) + libseccomp_minver="2.2.0" + ;; *) libseccomp_minver="" ;; -- 2.51.1 From bd33e933cbde5f822a0db069e7d368d0cb406249 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 15 Jun 2015 17:36:32 +0200 Subject: [PATCH 37/58] dictzip: Fix on big endian systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dictzip code in SLE11 received some treatment over time to support running on big endian hosts. Somewhere in the transition to SLE12 this support got lost. Add it back in again from the SLE11 code base. Furthermore while at it, fix up the debug prints to not emit warnings. [AG: BSC#937572] Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber --- block/dictzip.c | 50 +++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/block/dictzip.c b/block/dictzip.c index 717a7d3eda..1a104ac538 100644 --- a/block/dictzip.c +++ b/block/dictzip.c @@ -156,6 +156,7 @@ static int dictzip_open(BlockDriverState *bs, QDict *options, int flags, Error * uint8_t header_flags; uint16_t chunk_len16; uint16_t chunk_cnt16; + uint32_t chunk_len32; uint16_t header_ver; uint16_t tmp_short; uint64_t offset; @@ -255,11 +256,11 @@ static int dictzip_open(BlockDriverState *bs, QDict *options, int flags, Error * break; case 99: /* Special Alex pigz version */ /* number of chunks */ - if (bdrv_pread(s->hd, GZ_99_CHUNKSIZE, &s->chunk_len, 4) != 4) + if (bdrv_pread(s->hd, GZ_99_CHUNKSIZE, &chunk_len32, 4) != 4) goto fail; - dprintf("chunk len [%#x] = %d\n", GZ_99_CHUNKSIZE, s->chunk_len); - s->chunk_len = le32_to_cpu(s->chunk_len); + dprintf("chunk len [%#x] = %d\n", GZ_99_CHUNKSIZE, chunk_len32); + s->chunk_len = le32_to_cpu(chunk_len32); /* chunk count */ if (bdrv_pread(s->hd, GZ_99_CHUNKCNT, &s->chunk_cnt, 4) != 4) @@ -267,7 +268,7 @@ static int dictzip_open(BlockDriverState *bs, QDict *options, int flags, Error * s->chunk_cnt = le32_to_cpu(s->chunk_cnt); - dprintf("chunk len | count = %d | %d\n", s->chunk_len, s->chunk_cnt); + dprintf("chunk len | count = %"PRId64" | %d\n", s->chunk_len, s->chunk_cnt); /* file size */ if (bdrv_pread(s->hd, GZ_99_FILESIZE, &s->file_len, 8) != 8) @@ -338,14 +339,14 @@ static int dictzip_open(BlockDriverState *bs, QDict *options, int flags, Error * s->offsets[i] = offset; switch (header_ver) { case 1: - offset += s->chunks[i]; + offset += le16_to_cpu(s->chunks[i]); break; case 99: - offset += s->chunks32[i]; + offset += le32_to_cpu(s->chunks32[i]); break; } - dprintf("chunk %#x - %#x = offset %#x -> %#x\n", i * s->chunk_len, (i+1) * s->chunk_len, s->offsets[i], offset); + dprintf("chunk %#"PRIx64" - %#"PRIx64" = offset %#"PRIx64" -> %#"PRIx64"\n", i * s->chunk_len, (i+1) * s->chunk_len, s->offsets[i], offset); } qemu_opts_del(opts); @@ -379,10 +380,26 @@ static void dictzip_read_cb(void *opaque, int ret) struct BDRVDictZipState *s = acb->s; uint8_t *buf; DictCache *cache; - int r; + int r, i; buf = g_malloc(acb->chunks_len); + /* try to find zlib stream for decoding */ + do { + for (i = 0; i < Z_STREAM_COUNT; i++) { + if (!(s->stream_in_use & (1 << i))) { + s->stream_in_use |= (1 << i); + acb->zStream_id = i; + acb->zStream = &s->zStream[i]; + break; + } + } + } while(!acb->zStream); + + /* sure, we could handle more streams, but this callback should be single + threaded and when it's not, we really want to know! */ + assert(i == 0); + /* uncompress the chunk */ acb->zStream->next_in = acb->gzipped; acb->zStream->avail_in = acb->gz_len; @@ -468,17 +485,6 @@ static BlockAIOCB *dictzip_aio_readv(BlockDriverState *bs, } /* No cache, so let's decode */ - do { - for (i = 0; i < Z_STREAM_COUNT; i++) { - if (!(s->stream_in_use & (1 << i))) { - s->stream_in_use |= (1 << i); - acb->zStream_id = i; - acb->zStream = &s->zStream[i]; - break; - } - } - } while(!acb->zStream); - /* We need to read these chunks */ first_chunk = start / s->chunk_len; first_offset = start - first_chunk * s->chunk_len; @@ -488,9 +494,9 @@ static BlockAIOCB *dictzip_aio_readv(BlockDriverState *bs, gz_len = 0; for (i = first_chunk; i <= last_chunk; i++) { if (s->chunks32) - gz_len += s->chunks32[i]; + gz_len += le32_to_cpu(s->chunks32[i]); else - gz_len += s->chunks[i]; + gz_len += le16_to_cpu(s->chunks[i]); } gz_sector_num = gz_start / SECTOR_SIZE; @@ -511,7 +517,7 @@ static BlockAIOCB *dictzip_aio_readv(BlockDriverState *bs, iov->iov_len = gz_nb_sectors * 512; qemu_iovec_init_external(qiov_gz, iov, 1); - dprintf("read %d - %d => %d - %d\n", start, end, gz_start, gz_start + gz_len); + dprintf("read %zd - %zd => %zd - %zd\n", start, end, gz_start, gz_start + gz_len); acb->s = s; acb->qiov = qiov; -- 2.51.1 From 2cee6af27f7e7579c8690edfda4159a66406d2cd Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Thu, 24 Mar 2016 14:32:39 +0100 Subject: [PATCH 38/58] block: split large discard requests from block frontend Large discard requests lead to sign expansion errors in qemu. Since there is no API to tell a guest about the limitations qmeu has to split a large request itself. [bsc#964427] Signed-off-by: Olaf Hering --- block/io.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/block/io.c b/block/io.c index d02e0d5765..511bc75c42 100644 --- a/block/io.c +++ b/block/io.c @@ -2487,7 +2487,7 @@ static void coroutine_fn bdrv_discard_co_entry(void *opaque) rwco->ret = bdrv_co_discard(rwco->bs, rwco->sector_num, rwco->nb_sectors); } -int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, +static int __bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) { BdrvTrackedRequest req; @@ -2569,6 +2569,26 @@ out: return ret; } +int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, + int nb_sectors) +{ + int num, ret; + int limit = BDRV_REQUEST_MAX_SECTORS; + int remaining = nb_sectors; + int64_t sector_offset = sector_num; + + do { + num = remaining > limit ? limit : remaining; + ret = __bdrv_co_discard(bs, sector_offset, num); + if (ret < 0) + break; + remaining -= num; + sector_offset += num; + } while (remaining > 0); + + return ret; +} + int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) { Coroutine *co; -- 2.51.1 From 2d38805131dee693fd9bd931239793514e36d3e0 Mon Sep 17 00:00:00 2001 From: Bruce Rogers Date: Wed, 9 Mar 2016 15:18:11 -0700 Subject: [PATCH 39/58] xen_disk: Add suse specific flush disable handling and map to QEMU equiv Add code to read the suse specific suse-diskcache-disable-flush flag out of xenstore, and set the equivalent flag within QEMU. Patch taken from Xen's patch queue, Olaf Hering being the original author. [bsc#879425] Signed-off-by: Bruce Rogers Signed-off-by: Olaf Hering --- hw/block/xen_disk.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index d4ce380fee..91008625fe 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -112,6 +112,7 @@ struct XenBlkDev { int requests_inflight; int requests_finished; + gboolean cache_unsafe; /* Persistent grants extension */ gboolean feature_discard; gboolean feature_persistent; @@ -793,6 +794,16 @@ static void blk_parse_discard(struct XenBlkDev *blkdev) } } +static void blk_parse_cache_unsafe(struct XenBlkDev *blkdev) +{ + int enable; + + blkdev->cache_unsafe = false; + + if (xenstore_read_be_int(&blkdev->xendev, "suse-diskcache-disable-flush", &enable) == 0) + blkdev->cache_unsafe = !!enable; +} + static int blk_init(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); @@ -864,6 +875,7 @@ static int blk_init(struct XenDevice *xendev) xenstore_write_be_int(&blkdev->xendev, "info", info); blk_parse_discard(blkdev); + blk_parse_cache_unsafe(blkdev); g_free(directiosafe); return 0; @@ -906,6 +918,9 @@ static int blk_connect(struct XenDevice *xendev) qflags |= BDRV_O_UNMAP; } + if (blkdev->cache_unsafe) + qflags |= BDRV_O_NO_FLUSH; + /* init qemu block driver */ index = (blkdev->xendev.dev - 202 * 256) / 16; blkdev->dinfo = drive_get(IF_XEN, 0, index); -- 2.51.1 From f210e8f540cb261c11bffa4ed8e9918ad1731a9b Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 1 Apr 2016 12:27:16 +0200 Subject: [PATCH 40/58] build: link with libatomic on powerpc-linux Building on powerpc-linux fails with undefined reference to __atomic_load_8 in icount_warp_rt(). Force linking to -latomic. Fixes a0aa44b ("include/qemu/atomic.h: default to __atomic functions") Signed-off-by: Olaf Hering --- configure | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/configure b/configure index bf74354139..8892b36dfd 100755 --- a/configure +++ b/configure @@ -4033,6 +4033,33 @@ if test "$usb_redir" != "no" ; then fi fi +if test "$linux_user" = "no" -a "$cpu" = "ppc" -a "$targetos" = "Linux" ; then + # Do we need libm + cat > $TMPC << EOF + #include + #include + #include + int64_t val; + int main(int argc, char **argv) + { + val = (int64_t)read(0, NULL, 0); + if (atomic_read(&val) == -1) { + return 0; + } + return 1; + } +EOF + if compile_prog "-Iinclude" "" ; then + : + echo "No need to link with -latomic on powerpc-linux" + elif compile_prog "-Iinclude" "-latomic" ; then + echo "Link with -latomic on powerpc-linux" + libs_softmmu="$libs_softmmu -latomic" + else + error_exit "libatomic check failed" + fi +fi + ########################################## # check if we have VSS SDK headers for win -- 2.51.1 From 24b0afe9e7869a5a398cb5d04f6e7c5efbac65da Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Thu, 12 May 2016 16:13:39 +0200 Subject: [PATCH 41/58] xen: introduce dummy system device Introduce a new dummy system device serving as parent for virtual buses. This will enable new pv backends to introduce virtual buses which are removable again opposed to system buses which are meant to stay once added. Signed-off-by: Juergen Gross Acked-by: Anthony PERARD Reviewed-by: Wei Liu Message-id: 1463062421-613-2-git-send-email-jgross@suse.com Signed-off-by: Gerd Hoffmann (cherry picked from commit 9432e53a5bc88681b2d3aec4dac9db07c5476d1b) [BR: FATE#316612] Signed-off-by: Bruce Rogers --- hw/xenpv/xen_machine_pv.c | 40 ++++++++++++++++++++++++++++++++++++ include/hw/xen/xen_backend.h | 1 + 2 files changed, 41 insertions(+) diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index fc13535992..48d5bc6047 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -25,10 +25,15 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/boards.h" +#include "hw/sysbus.h" #include "hw/xen/xen_backend.h" #include "xen_domainbuild.h" #include "sysemu/block-backend.h" +#define TYPE_XENSYSDEV "xensysdev" + +DeviceState *xen_sysdev; + static void xen_init_pv(MachineState *machine) { DriveInfo *dinfo; @@ -67,6 +72,9 @@ static void xen_init_pv(MachineState *machine) break; } + xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV); + qdev_init_nofail(xen_sysdev); + xen_be_register("console", &xen_console_ops); xen_be_register("vkbd", &xen_kbdmouse_ops); xen_be_register("vfb", &xen_framebuffer_ops); @@ -101,6 +109,38 @@ static void xen_init_pv(MachineState *machine) xen_init_display(xen_domid); } +static int xen_sysdev_init(SysBusDevice *dev) +{ + return 0; +} + +static Property xen_sysdev_properties[] = { + {/* end of property list */}, +}; + +static void xen_sysdev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xen_sysdev_init; + dc->props = xen_sysdev_properties; +} + +static const TypeInfo xensysdev_info = { + .name = TYPE_XENSYSDEV, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = xen_sysdev_class_init, +}; + +static void xenpv_register_types(void) +{ + type_register_static(&xensysdev_info); +} + +type_init(xenpv_register_types); + static void xenpv_machine_init(MachineClass *mc) { mc->desc = "Xen Para-virtualized PC"; diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h index c839eeb489..b4b4ff0af2 100644 --- a/include/hw/xen/xen_backend.h +++ b/include/hw/xen/xen_backend.h @@ -60,6 +60,7 @@ extern xc_interface *xen_xc; extern xenforeignmemory_handle *xen_fmem; extern struct xs_handle *xenstore; extern const char *xen_protocol; +extern DeviceState *xen_sysdev; /* xenstore helper functions */ int xenstore_write_str(const char *base, const char *node, const char *val); -- 2.51.1 From 06bc1cf8722a7a5ad5cf7e0ad3adf9279516d77d Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Thu, 12 May 2016 16:13:40 +0200 Subject: [PATCH 42/58] xen: write information about supported backends Add a Xenstore directory for each supported pv backend. This will allow Xen tools to decide which backend type to use in case there are multiple possibilities. The information is added under /local/domain//device-model//backends before the "running" state is written to Xenstore. Using a directory for each backend enables us to add parameters for specific backends in the future. This interface is documented in the Xen source repository in the file docs/misc/qemu-backends.txt In order to reuse the Xenstore directory creation already present in hw/xen/xen_devconfig.c move the related functions to hw/xen/xen_backend.c where they fit better. Signed-off-by: Juergen Gross Acked-by: Anthony PERARD Reviewed-by: Wei Liu Message-id: 1463062421-613-3-git-send-email-jgross@suse.com Signed-off-by: Gerd Hoffmann (cherry picked from commit 637c53ffcb891ce8876183e6b593b8f0c3763ab1) [BR: FATE#316612] Signed-off-by: Bruce Rogers --- hw/xen/xen_backend.c | 63 ++++++++++++++++++++++++++++++++++++ hw/xen/xen_devconfig.c | 52 ++--------------------------- include/hw/xen/xen_backend.h | 2 ++ 3 files changed, 67 insertions(+), 50 deletions(-) diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c index 60575ad38d..c63f9df38b 100644 --- a/hw/xen/xen_backend.c +++ b/hw/xen/xen_backend.c @@ -42,11 +42,36 @@ struct xs_handle *xenstore = NULL; const char *xen_protocol; /* private */ +struct xs_dirs { + char *xs_dir; + QTAILQ_ENTRY(xs_dirs) list; +}; +static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = + QTAILQ_HEAD_INITIALIZER(xs_cleanup); + static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs); static int debug = 0; /* ------------------------------------------------------------- */ +static void xenstore_cleanup_dir(char *dir) +{ + struct xs_dirs *d; + + d = g_malloc(sizeof(*d)); + d->xs_dir = dir; + QTAILQ_INSERT_TAIL(&xs_cleanup, d, list); +} + +void xen_config_cleanup(void) +{ + struct xs_dirs *d; + + QTAILQ_FOREACH(d, &xs_cleanup, list) { + xs_rm(xenstore, 0, d->xs_dir); + } +} + int xenstore_write_str(const char *base, const char *node, const char *val) { char abspath[XEN_BUFSIZE]; @@ -75,6 +100,30 @@ char *xenstore_read_str(const char *base, const char *node) return ret; } +int xenstore_mkdir(char *path, int p) +{ + struct xs_permissions perms[2] = { + { + .id = 0, /* set owner: dom0 */ + }, { + .id = xen_domid, + .perms = p, + } + }; + + if (!xs_mkdir(xenstore, 0, path)) { + xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", path); + return -1; + } + xenstore_cleanup_dir(g_strdup(path)); + + if (!xs_set_permissions(xenstore, 0, path, perms, 2)) { + xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", path); + return -1; + } + return 0; +} + int xenstore_write_int(const char *base, const char *node, int ival) { char val[12]; @@ -726,6 +775,20 @@ err: int xen_be_register(const char *type, struct XenDevOps *ops) { + char path[50]; + int rc; + + if (ops->backend_register) { + rc = ops->backend_register(); + if (rc) { + return rc; + } + } + + snprintf(path, sizeof(path), "device-model/%u/backends/%s", xen_domid, + type); + xenstore_mkdir(path, XS_PERM_NONE); + return xenstore_scan(type, xen_domid, ops); } diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c index 1f30fe4f5a..b7d290df6c 100644 --- a/hw/xen/xen_devconfig.c +++ b/hw/xen/xen_devconfig.c @@ -5,54 +5,6 @@ /* ------------------------------------------------------------- */ -struct xs_dirs { - char *xs_dir; - QTAILQ_ENTRY(xs_dirs) list; -}; -static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = QTAILQ_HEAD_INITIALIZER(xs_cleanup); - -static void xen_config_cleanup_dir(char *dir) -{ - struct xs_dirs *d; - - d = g_malloc(sizeof(*d)); - d->xs_dir = dir; - QTAILQ_INSERT_TAIL(&xs_cleanup, d, list); -} - -void xen_config_cleanup(void) -{ - struct xs_dirs *d; - - QTAILQ_FOREACH(d, &xs_cleanup, list) { - xs_rm(xenstore, 0, d->xs_dir); - } -} - -/* ------------------------------------------------------------- */ - -static int xen_config_dev_mkdir(char *dev, int p) -{ - struct xs_permissions perms[2] = {{ - .id = 0, /* set owner: dom0 */ - },{ - .id = xen_domid, - .perms = p, - }}; - - if (!xs_mkdir(xenstore, 0, dev)) { - xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", dev); - return -1; - } - xen_config_cleanup_dir(g_strdup(dev)); - - if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) { - xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", dev); - return -1; - } - return 0; -} - static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev, char *fe, char *be, int len) { @@ -66,8 +18,8 @@ static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev, snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev); free(dom); - xen_config_dev_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE); - xen_config_dev_mkdir(be, XS_PERM_READ); + xenstore_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE); + xenstore_mkdir(be, XS_PERM_READ); return 0; } diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h index b4b4ff0af2..63364f71d0 100644 --- a/include/hw/xen/xen_backend.h +++ b/include/hw/xen/xen_backend.h @@ -28,6 +28,7 @@ struct XenDevOps { int (*free)(struct XenDevice *xendev); void (*backend_changed)(struct XenDevice *xendev, const char *node); void (*frontend_changed)(struct XenDevice *xendev, const char *node); + int (*backend_register)(void); }; struct XenDevice { @@ -63,6 +64,7 @@ extern const char *xen_protocol; extern DeviceState *xen_sysdev; /* xenstore helper functions */ +int xenstore_mkdir(char *path, int p); int xenstore_write_str(const char *base, const char *node, const char *val); int xenstore_write_int(const char *base, const char *node, int ival); int xenstore_write_int64(const char *base, const char *node, int64_t ival); -- 2.51.1 From 013c67849bbe9688491b85483bce6e8fc81fa90f Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Thu, 12 May 2016 16:13:41 +0200 Subject: [PATCH 43/58] xen: add pvUSB backend Add a backend for para-virtualized USB devices for xen domains. The backend is using host-libusb to forward USB requests from a domain via libusb to the real device(s) passed through. Signed-off-by: Juergen Gross Acked-by: Anthony PERARD Message-id: 1463062421-613-4-git-send-email-jgross@suse.com Signed-off-by: Gerd Hoffmann (cherry picked from commit 816ac92ef769f9ffc534e49a1bb6177bddce7aa2) [BR: FATE#316612] Signed-off-by: Bruce Rogers --- hw/usb/Makefile.objs | 4 + hw/usb/xen-usb.c | 1080 ++++++++++++++++++++++++++++++++++ hw/xenpv/xen_machine_pv.c | 3 + include/hw/xen/xen_backend.h | 3 + include/hw/xen/xen_common.h | 2 + 5 files changed, 1092 insertions(+) create mode 100644 hw/usb/xen-usb.c diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 2717027d34..98b5c9d273 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -38,3 +38,7 @@ common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o # usb pass-through common-obj-y += $(patsubst %,host-%.o,$(HOST_USB)) + +ifeq ($(CONFIG_USB_LIBUSB),y) +common-obj-$(CONFIG_XEN_BACKEND) += xen-usb.o +endif diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c new file mode 100644 index 0000000000..664df04181 --- /dev/null +++ b/hw/usb/xen-usb.c @@ -0,0 +1,1080 @@ +/* + * xen paravirt usb device backend + * + * (c) Juergen Gross + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/config-file.h" +#include "hw/sysbus.h" +#include "hw/usb.h" +#include "hw/xen/xen_backend.h" +#include "monitor/qdev.h" +#include "qapi/qmp/qbool.h" +#include "qapi/qmp/qint.h" +#include "qapi/qmp/qstring.h" +#include "sys/user.h" + +#include +#include + +/* + * Check for required support of usbif.h: USBIF_SHORT_NOT_OK was the last + * macro added we rely on. + */ +#ifdef USBIF_SHORT_NOT_OK + +#define TR(xendev, lvl, fmt, args...) \ + { \ + struct timeval tv; \ + \ + gettimeofday(&tv, NULL); \ + xen_be_printf(xendev, lvl, "%8ld.%06ld xen-usb(%s):" fmt, \ + tv.tv_sec, tv.tv_usec, __func__, ##args); \ + } +#define TR_BUS(xendev, fmt, args...) TR(xendev, 2, fmt, ##args) +#define TR_REQ(xendev, fmt, args...) TR(xendev, 3, fmt, ##args) + +#define USBBACK_MAXPORTS USBIF_PIPE_PORT_MASK +#define USB_DEV_ADDR_SIZE (USBIF_PIPE_DEV_MASK + 1) + +/* USB wire protocol: structure describing control request parameter. */ +struct usbif_ctrlrequest { + uint8_t bRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +}; + +struct usbback_info; +struct usbback_req; + +struct usbback_stub { + USBDevice *dev; + USBPort port; + unsigned int speed; + bool attached; + QTAILQ_HEAD(submit_q_head, usbback_req) submit_q; +}; + +struct usbback_req { + struct usbback_info *usbif; + struct usbback_stub *stub; + struct usbif_urb_request req; + USBPacket packet; + + unsigned int nr_buffer_segs; /* # of transfer_buffer segments */ + unsigned int nr_extra_segs; /* # of iso_frame_desc segments */ + + QTAILQ_ENTRY(usbback_req) q; + + void *buffer; + void *isoc_buffer; + struct libusb_transfer *xfer; +}; + +struct usbback_hotplug { + QSIMPLEQ_ENTRY(usbback_hotplug) q; + unsigned port; +}; + +struct usbback_info { + struct XenDevice xendev; /* must be first */ + USBBus bus; + void *urb_sring; + void *conn_sring; + struct usbif_urb_back_ring urb_ring; + struct usbif_conn_back_ring conn_ring; + int num_ports; + int usb_ver; + bool ring_error; + QTAILQ_HEAD(req_free_q_head, usbback_req) req_free_q; + QSIMPLEQ_HEAD(hotplug_q_head, usbback_hotplug) hotplug_q; + struct usbback_stub ports[USBBACK_MAXPORTS]; + struct usbback_stub *addr_table[USB_DEV_ADDR_SIZE]; + QEMUBH *bh; +}; + +static struct usbback_req *usbback_get_req(struct usbback_info *usbif) +{ + struct usbback_req *usbback_req; + + if (QTAILQ_EMPTY(&usbif->req_free_q)) { + usbback_req = g_new0(struct usbback_req, 1); + } else { + usbback_req = QTAILQ_FIRST(&usbif->req_free_q); + QTAILQ_REMOVE(&usbif->req_free_q, usbback_req, q); + } + return usbback_req; +} + +static void usbback_put_req(struct usbback_req *usbback_req) +{ + struct usbback_info *usbif; + + usbif = usbback_req->usbif; + memset(usbback_req, 0, sizeof(*usbback_req)); + QTAILQ_INSERT_HEAD(&usbif->req_free_q, usbback_req, q); +} + +static int usbback_gnttab_map(struct usbback_req *usbback_req) +{ + unsigned int nr_segs, i, prot; + uint32_t ref[USBIF_MAX_SEGMENTS_PER_REQUEST]; + struct usbback_info *usbif = usbback_req->usbif; + struct XenDevice *xendev = &usbif->xendev; + struct usbif_request_segment *seg; + void *addr; + + nr_segs = usbback_req->nr_buffer_segs + usbback_req->nr_extra_segs; + if (!nr_segs) { + return 0; + } + + if (nr_segs > USBIF_MAX_SEGMENTS_PER_REQUEST) { + xen_be_printf(xendev, 0, "bad number of segments in request (%d)\n", + nr_segs); + return -EINVAL; + } + + for (i = 0; i < nr_segs; i++) { + if ((unsigned)usbback_req->req.seg[i].offset + + (unsigned)usbback_req->req.seg[i].length > PAGE_SIZE) { + xen_be_printf(xendev, 0, "segment crosses page boundary\n"); + return -EINVAL; + } + } + + if (usbback_req->nr_buffer_segs) { + prot = PROT_READ; + if (usbif_pipein(usbback_req->req.pipe)) { + prot |= PROT_WRITE; + } + for (i = 0; i < usbback_req->nr_buffer_segs; i++) { + ref[i] = usbback_req->req.seg[i].gref; + } + usbback_req->buffer = xengnttab_map_domain_grant_refs(xendev->gnttabdev, + usbback_req->nr_buffer_segs, xendev->dom, ref, prot); + + if (!usbback_req->buffer) { + return -ENOMEM; + } + + for (i = 0; i < usbback_req->nr_buffer_segs; i++) { + seg = usbback_req->req.seg + i; + addr = usbback_req->buffer + i * PAGE_SIZE + seg->offset; + qemu_iovec_add(&usbback_req->packet.iov, addr, seg->length); + } + } + + if (!usbif_pipeisoc(usbback_req->req.pipe)) { + return 0; + } + + /* + * Right now isoc requests are not supported. + * Prepare supporting those by doing the work needed on the guest + * interface side. + */ + + if (!usbback_req->nr_extra_segs) { + xen_be_printf(xendev, 0, "iso request without descriptor segments\n"); + return -EINVAL; + } + + prot = PROT_READ | PROT_WRITE; + for (i = 0; i < usbback_req->nr_extra_segs; i++) { + ref[i] = usbback_req->req.seg[i + usbback_req->req.nr_buffer_segs].gref; + } + usbback_req->isoc_buffer = xengnttab_map_domain_grant_refs( + xendev->gnttabdev, usbback_req->nr_extra_segs, xendev->dom, ref, prot); + + if (!usbback_req->isoc_buffer) { + return -ENOMEM; + } + + return 0; +} + +static int usbback_init_packet(struct usbback_req *usbback_req) +{ + struct XenDevice *xendev = &usbback_req->usbif->xendev; + USBPacket *packet = &usbback_req->packet; + USBDevice *dev = usbback_req->stub->dev; + USBEndpoint *ep; + unsigned int pid, ep_nr; + bool sok; + int ret = 0; + + qemu_iovec_init(&packet->iov, USBIF_MAX_SEGMENTS_PER_REQUEST); + pid = usbif_pipein(usbback_req->req.pipe) ? USB_TOKEN_IN : USB_TOKEN_OUT; + ep_nr = usbif_pipeendpoint(usbback_req->req.pipe); + sok = !!(usbback_req->req.transfer_flags & USBIF_SHORT_NOT_OK); + if (usbif_pipectrl(usbback_req->req.pipe)) { + ep_nr = 0; + sok = false; + } + ep = usb_ep_get(dev, pid, ep_nr); + usb_packet_setup(packet, pid, ep, 0, 1, sok, true); + + switch (usbif_pipetype(usbback_req->req.pipe)) { + case USBIF_PIPE_TYPE_ISOC: + TR_REQ(xendev, "iso transfer %s: buflen: %x, %d frames\n", + (pid == USB_TOKEN_IN) ? "in" : "out", + usbback_req->req.buffer_length, + usbback_req->req.u.isoc.nr_frame_desc_segs); + ret = -EINVAL; /* isoc not implemented yet */ + break; + + case USBIF_PIPE_TYPE_INT: + TR_REQ(xendev, "int transfer %s: buflen: %x\n", + (pid == USB_TOKEN_IN) ? "in" : "out", + usbback_req->req.buffer_length); + break; + + case USBIF_PIPE_TYPE_CTRL: + packet->parameter = *(uint64_t *)usbback_req->req.u.ctrl; + TR_REQ(xendev, "ctrl parameter: %lx, buflen: %x\n", packet->parameter, + usbback_req->req.buffer_length); + break; + + case USBIF_PIPE_TYPE_BULK: + TR_REQ(xendev, "bulk transfer %s: buflen: %x\n", + (pid == USB_TOKEN_IN) ? "in" : "out", + usbback_req->req.buffer_length); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static void usbback_do_response(struct usbback_req *usbback_req, int32_t status, + int32_t actual_length, int32_t error_count) +{ + struct usbback_info *usbif; + struct usbif_urb_response *res; + struct XenDevice *xendev; + unsigned int notify; + + usbif = usbback_req->usbif; + xendev = &usbif->xendev; + + TR_REQ(xendev, "id %d, status %d, length %d, errcnt %d\n", + usbback_req->req.id, status, actual_length, error_count); + + if (usbback_req->packet.iov.iov) { + qemu_iovec_destroy(&usbback_req->packet.iov); + } + + if (usbback_req->buffer) { + xengnttab_unmap(xendev->gnttabdev, usbback_req->buffer, + usbback_req->nr_buffer_segs); + usbback_req->buffer = NULL; + } + + if (usbback_req->isoc_buffer) { + xengnttab_unmap(xendev->gnttabdev, usbback_req->isoc_buffer, + usbback_req->nr_extra_segs); + usbback_req->isoc_buffer = NULL; + } + + res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt); + res->id = usbback_req->req.id; + res->status = status; + res->actual_length = actual_length; + res->error_count = error_count; + res->start_frame = 0; + usbif->urb_ring.rsp_prod_pvt++; + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify); + + if (notify) { + xen_be_send_notify(xendev); + } + + usbback_put_req(usbback_req); +} + +static void usbback_do_response_ret(struct usbback_req *usbback_req, + int32_t status) +{ + usbback_do_response(usbback_req, status, 0, 0); +} + +static int32_t usbback_xlat_status(int status) +{ + switch (status) { + case USB_RET_SUCCESS: + return 0; + case USB_RET_NODEV: + return -ENODEV; + case USB_RET_STALL: + return -EPIPE; + case USB_RET_BABBLE: + return -EOVERFLOW; + case USB_RET_IOERROR: + return -EPROTO; + } + + return -ESHUTDOWN; +} + +static void usbback_packet_complete(USBPacket *packet) +{ + struct usbback_req *usbback_req; + int32_t status; + + usbback_req = container_of(packet, struct usbback_req, packet); + + QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q); + + status = usbback_xlat_status(packet->status); + usbback_do_response(usbback_req, status, packet->actual_length, 0); +} + +static void usbback_set_address(struct usbback_info *usbif, + struct usbback_stub *stub, + unsigned int cur_addr, unsigned int new_addr) +{ + if (cur_addr) { + usbif->addr_table[cur_addr] = NULL; + } + if (new_addr) { + usbif->addr_table[new_addr] = stub; + } +} + +static bool usbback_cancel_req(struct usbback_req *usbback_req) +{ + bool ret = false; + + if (usb_packet_is_inflight(&usbback_req->packet)) { + usb_cancel_packet(&usbback_req->packet); + ret = true; + } + return ret; +} + +static void usbback_process_unlink_req(struct usbback_req *usbback_req) +{ + struct usbback_info *usbif; + struct usbback_req *unlink_req; + unsigned int id, devnum; + int ret; + + usbif = usbback_req->usbif; + ret = 0; + id = usbback_req->req.u.unlink.unlink_id; + TR_REQ(&usbif->xendev, "unlink id %d\n", id); + devnum = usbif_pipedevice(usbback_req->req.pipe); + if (unlikely(devnum == 0)) { + usbback_req->stub = usbif->ports + + usbif_pipeportnum(usbback_req->req.pipe); + if (unlikely(!usbback_req->stub)) { + ret = -ENODEV; + goto fail_response; + } + } else { + if (unlikely(!usbif->addr_table[devnum])) { + ret = -ENODEV; + goto fail_response; + } + usbback_req->stub = usbif->addr_table[devnum]; + } + + QTAILQ_FOREACH(unlink_req, &usbback_req->stub->submit_q, q) { + if (unlink_req->req.id == id) { + if (usbback_cancel_req(unlink_req)) { + usbback_do_response_ret(unlink_req, -EPROTO); + } + break; + } + } + +fail_response: + usbback_do_response_ret(usbback_req, ret); +} + +/* + * Checks whether a request can be handled at once or should be forwarded + * to the usb framework. + * Return value is: + * 0 in case of usb framework is needed + * 1 in case of local handling (no error) + * The request response has been queued already if return value not 0. + */ +static int usbback_check_and_submit(struct usbback_req *usbback_req) +{ + struct usbback_info *usbif; + unsigned int devnum; + struct usbback_stub *stub; + struct usbif_ctrlrequest *ctrl; + int ret; + uint16_t wValue; + + usbif = usbback_req->usbif; + stub = NULL; + devnum = usbif_pipedevice(usbback_req->req.pipe); + ctrl = (struct usbif_ctrlrequest *)usbback_req->req.u.ctrl; + wValue = le16_to_cpu(ctrl->wValue); + + /* + * When the device is first connected or resetted, USB device has no + * address. In this initial state, following requests are sent to device + * address (#0), + * + * 1. GET_DESCRIPTOR (with Descriptor Type is "DEVICE") is sent, + * and OS knows what device is connected to. + * + * 2. SET_ADDRESS is sent, and then device has its address. + * + * In the next step, SET_CONFIGURATION is sent to addressed device, and + * then the device is finally ready to use. + */ + if (unlikely(devnum == 0)) { + stub = usbif->ports + usbif_pipeportnum(usbback_req->req.pipe) - 1; + if (!stub->dev || !stub->attached) { + ret = -ENODEV; + goto do_response; + } + + switch (ctrl->bRequest) { + case USB_REQ_GET_DESCRIPTOR: + /* + * GET_DESCRIPTOR request to device #0. + * through normal transfer. + */ + TR_REQ(&usbif->xendev, "devnum 0 GET_DESCRIPTOR\n"); + usbback_req->stub = stub; + return 0; + case USB_REQ_SET_ADDRESS: + /* + * SET_ADDRESS request to device #0. + * add attached device to addr_table. + */ + TR_REQ(&usbif->xendev, "devnum 0 SET_ADDRESS\n"); + usbback_set_address(usbif, stub, 0, wValue); + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + goto do_response; + } + + if (unlikely(!usbif->addr_table[devnum])) { + ret = -ENODEV; + goto do_response; + } + usbback_req->stub = usbif->addr_table[devnum]; + + /* + * Check special request + */ + if (ctrl->bRequest != USB_REQ_SET_ADDRESS) { + return 0; + } + + /* + * SET_ADDRESS request to addressed device. + * change addr or remove from addr_table. + */ + usbback_set_address(usbif, usbback_req->stub, devnum, wValue); + ret = 0; + +do_response: + usbback_do_response_ret(usbback_req, ret); + return 1; +} + +static void usbback_dispatch(struct usbback_req *usbback_req) +{ + int ret; + unsigned int devnum; + struct usbback_info *usbif; + + usbif = usbback_req->usbif; + + TR_REQ(&usbif->xendev, "start req_id %d pipe %08x\n", usbback_req->req.id, + usbback_req->req.pipe); + + /* unlink request */ + if (unlikely(usbif_pipeunlink(usbback_req->req.pipe))) { + usbback_process_unlink_req(usbback_req); + return; + } + + if (usbif_pipectrl(usbback_req->req.pipe)) { + if (usbback_check_and_submit(usbback_req)) { + return; + } + } else { + devnum = usbif_pipedevice(usbback_req->req.pipe); + usbback_req->stub = usbif->addr_table[devnum]; + + if (!usbback_req->stub || !usbback_req->stub->attached) { + ret = -ENODEV; + goto fail_response; + } + } + + QTAILQ_INSERT_TAIL(&usbback_req->stub->submit_q, usbback_req, q); + + usbback_req->nr_buffer_segs = usbback_req->req.nr_buffer_segs; + usbback_req->nr_extra_segs = usbif_pipeisoc(usbback_req->req.pipe) ? + usbback_req->req.u.isoc.nr_frame_desc_segs : 0; + + ret = usbback_init_packet(usbback_req); + if (ret) { + xen_be_printf(&usbif->xendev, 0, "invalid request\n"); + ret = -ESHUTDOWN; + goto fail_free_urb; + } + + ret = usbback_gnttab_map(usbback_req); + if (ret) { + xen_be_printf(&usbif->xendev, 0, "invalid buffer, ret=%d\n", ret); + ret = -ESHUTDOWN; + goto fail_free_urb; + } + + usb_handle_packet(usbback_req->stub->dev, &usbback_req->packet); + if (usbback_req->packet.status != USB_RET_ASYNC) { + usbback_packet_complete(&usbback_req->packet); + } + return; + +fail_free_urb: + QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q); + +fail_response: + usbback_do_response_ret(usbback_req, ret); +} + +static void usbback_hotplug_notify(struct usbback_info *usbif) +{ + struct usbif_conn_back_ring *ring = &usbif->conn_ring; + struct usbif_conn_request req; + struct usbif_conn_response *res; + struct usbback_hotplug *usb_hp; + unsigned int notify; + + if (!usbif->conn_sring) { + return; + } + + /* Check for full ring. */ + if ((RING_SIZE(ring) - ring->rsp_prod_pvt - ring->req_cons) == 0) { + xen_be_send_notify(&usbif->xendev); + return; + } + + usb_hp = QSIMPLEQ_FIRST(&usbif->hotplug_q); + QSIMPLEQ_REMOVE_HEAD(&usbif->hotplug_q, q); + + RING_COPY_REQUEST(ring, ring->req_cons, &req); + ring->req_cons++; + ring->sring->req_event = ring->req_cons + 1; + + res = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt); + res->id = req.id; + res->portnum = usb_hp->port; + res->speed = usbif->ports[usb_hp->port - 1].speed; + ring->rsp_prod_pvt++; + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify); + + if (notify) { + xen_be_send_notify(&usbif->xendev); + } + + TR_BUS(&usbif->xendev, "hotplug port %d speed %d\n", usb_hp->port, + res->speed); + + g_free(usb_hp); + + if (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) { + qemu_bh_schedule(usbif->bh); + } +} + +static void usbback_bh(void *opaque) +{ + struct usbback_info *usbif; + struct usbif_urb_back_ring *urb_ring; + struct usbback_req *usbback_req; + RING_IDX rc, rp; + unsigned int more_to_do; + + usbif = opaque; + if (usbif->ring_error) { + return; + } + + if (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) { + usbback_hotplug_notify(usbif); + } + + urb_ring = &usbif->urb_ring; + rc = urb_ring->req_cons; + rp = urb_ring->sring->req_prod; + xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ + + if (RING_REQUEST_PROD_OVERFLOW(urb_ring, rp)) { + rc = urb_ring->rsp_prod_pvt; + xen_be_printf(&usbif->xendev, 0, "domU provided bogus ring requests " + "(%#x - %#x = %u). Halting ring processing.\n", + rp, rc, rp - rc); + usbif->ring_error = true; + return; + } + + while (rc != rp) { + if (RING_REQUEST_CONS_OVERFLOW(urb_ring, rc)) { + break; + } + usbback_req = usbback_get_req(usbif); + + RING_COPY_REQUEST(urb_ring, rc, &usbback_req->req); + usbback_req->usbif = usbif; + + usbback_dispatch(usbback_req); + + urb_ring->req_cons = ++rc; + } + + RING_FINAL_CHECK_FOR_REQUESTS(urb_ring, more_to_do); + if (more_to_do) { + qemu_bh_schedule(usbif->bh); + } +} + +static void usbback_hotplug_enq(struct usbback_info *usbif, unsigned port) +{ + struct usbback_hotplug *usb_hp; + + usb_hp = g_new0(struct usbback_hotplug, 1); + usb_hp->port = port; + QSIMPLEQ_INSERT_TAIL(&usbif->hotplug_q, usb_hp, q); + usbback_hotplug_notify(usbif); +} + +static void usbback_portid_remove(struct usbback_info *usbif, unsigned port) +{ + USBPort *p; + + if (!usbif->ports[port - 1].dev) { + return; + } + + p = &(usbif->ports[port - 1].port); + snprintf(p->path, sizeof(p->path), "%d", 99); + + object_unparent(OBJECT(usbif->ports[port - 1].dev)); + usbif->ports[port - 1].dev = NULL; + usbif->ports[port - 1].speed = USBIF_SPEED_NONE; + usbif->ports[port - 1].attached = false; + usbback_hotplug_enq(usbif, port); + + TR_BUS(&usbif->xendev, "port %d removed\n", port); +} + +static void usbback_portid_add(struct usbback_info *usbif, unsigned port, + char *busid) +{ + unsigned speed; + char *portname; + USBPort *p; + Error *local_err = NULL; + QDict *qdict; + QemuOpts *opts; + + if (usbif->ports[port - 1].dev) { + return; + } + + portname = strchr(busid, '-'); + if (!portname) { + xen_be_printf(&usbif->xendev, 0, "device %s illegal specification\n", + busid); + return; + } + portname++; + p = &(usbif->ports[port - 1].port); + snprintf(p->path, sizeof(p->path), "%s", portname); + + qdict = qdict_new(); + qdict_put(qdict, "driver", qstring_from_str("usb-host")); + qdict_put(qdict, "hostbus", qint_from_int(atoi(busid))); + qdict_put(qdict, "hostport", qstring_from_str(portname)); + opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err); + if (local_err) { + goto err; + } + usbif->ports[port - 1].dev = USB_DEVICE(qdev_device_add(opts, &local_err)); + if (!usbif->ports[port - 1].dev) { + goto err; + } + QDECREF(qdict); + snprintf(p->path, sizeof(p->path), "%d", port); + speed = usbif->ports[port - 1].dev->speed; + switch (speed) { + case USB_SPEED_LOW: + speed = USBIF_SPEED_LOW; + break; + case USB_SPEED_FULL: + speed = USBIF_SPEED_FULL; + break; + case USB_SPEED_HIGH: + speed = (usbif->usb_ver < USB_VER_USB20) ? + USBIF_SPEED_NONE : USBIF_SPEED_HIGH; + break; + default: + speed = USBIF_SPEED_NONE; + break; + } + if (speed == USBIF_SPEED_NONE) { + xen_be_printf(&usbif->xendev, 0, "device %s wrong speed\n", busid); + object_unparent(OBJECT(usbif->ports[port - 1].dev)); + usbif->ports[port - 1].dev = NULL; + return; + } + usb_device_reset(usbif->ports[port - 1].dev); + usbif->ports[port - 1].speed = speed; + usbif->ports[port - 1].attached = true; + QTAILQ_INIT(&usbif->ports[port - 1].submit_q); + usbback_hotplug_enq(usbif, port); + + TR_BUS(&usbif->xendev, "port %d attached\n", port); + return; + +err: + QDECREF(qdict); + snprintf(p->path, sizeof(p->path), "%d", 99); + xen_be_printf(&usbif->xendev, 0, "device %s could not be opened\n", busid); +} + +static void usbback_process_port(struct usbback_info *usbif, unsigned port) +{ + char node[8]; + char *busid; + + snprintf(node, sizeof(node), "port/%d", port); + busid = xenstore_read_be_str(&usbif->xendev, node); + if (busid == NULL) { + xen_be_printf(&usbif->xendev, 0, "xenstore_read %s failed\n", node); + return; + } + + /* Remove portid, if the port is not connected. */ + if (strlen(busid) == 0) { + usbback_portid_remove(usbif, port); + } else { + usbback_portid_add(usbif, port, busid); + } + + g_free(busid); +} + +static void usbback_disconnect(struct XenDevice *xendev) +{ + struct usbback_info *usbif; + struct usbback_req *req, *tmp; + unsigned int i; + + TR_BUS(xendev, "start\n"); + + usbif = container_of(xendev, struct usbback_info, xendev); + + xen_be_unbind_evtchn(xendev); + + if (usbif->urb_sring) { + xengnttab_unmap(xendev->gnttabdev, usbif->urb_sring, 1); + usbif->urb_sring = NULL; + } + if (usbif->conn_sring) { + xengnttab_unmap(xendev->gnttabdev, usbif->conn_sring, 1); + usbif->conn_sring = NULL; + } + + for (i = 0; i < usbif->num_ports; i++) { + if (!usbif->ports[i].dev) { + continue; + } + QTAILQ_FOREACH_SAFE(req, &usbif->ports[i].submit_q, q, tmp) { + usbback_cancel_req(req); + } + } + + TR_BUS(xendev, "finished\n"); +} + +static int usbback_connect(struct XenDevice *xendev) +{ + struct usbback_info *usbif; + struct usbif_urb_sring *urb_sring; + struct usbif_conn_sring *conn_sring; + int urb_ring_ref; + int conn_ring_ref; + unsigned int i; + + TR_BUS(xendev, "start\n"); + + usbif = container_of(xendev, struct usbback_info, xendev); + + if (xenstore_read_fe_int(xendev, "urb-ring-ref", &urb_ring_ref)) { + xen_be_printf(xendev, 0, "error reading urb-ring-ref\n"); + return -1; + } + if (xenstore_read_fe_int(xendev, "conn-ring-ref", &conn_ring_ref)) { + xen_be_printf(xendev, 0, "error reading conn-ring-ref\n"); + return -1; + } + if (xenstore_read_fe_int(xendev, "event-channel", &xendev->remote_port)) { + xen_be_printf(xendev, 0, "error reading event-channel\n"); + return -1; + } + + usbif->urb_sring = xengnttab_map_grant_ref(xendev->gnttabdev, xendev->dom, + urb_ring_ref, + PROT_READ | PROT_WRITE); + usbif->conn_sring = xengnttab_map_grant_ref(xendev->gnttabdev, xendev->dom, + conn_ring_ref, + PROT_READ | PROT_WRITE); + if (!usbif->urb_sring || !usbif->conn_sring) { + xen_be_printf(xendev, 0, "error mapping rings\n"); + usbback_disconnect(xendev); + return -1; + } + + urb_sring = usbif->urb_sring; + conn_sring = usbif->conn_sring; + BACK_RING_INIT(&usbif->urb_ring, urb_sring, XC_PAGE_SIZE); + BACK_RING_INIT(&usbif->conn_ring, conn_sring, XC_PAGE_SIZE); + + xen_be_bind_evtchn(xendev); + + xen_be_printf(xendev, 1, "urb-ring-ref %d, conn-ring-ref %d, " + "remote port %d, local port %d\n", urb_ring_ref, + conn_ring_ref, xendev->remote_port, xendev->local_port); + + for (i = 1; i <= usbif->num_ports; i++) { + if (usbif->ports[i - 1].dev) { + usbback_hotplug_enq(usbif, i); + } + } + + return 0; +} + +static void usbback_backend_changed(struct XenDevice *xendev, const char *node) +{ + struct usbback_info *usbif; + unsigned int i; + + TR_BUS(xendev, "path %s\n", node); + + usbif = container_of(xendev, struct usbback_info, xendev); + for (i = 1; i <= usbif->num_ports; i++) { + usbback_process_port(usbif, i); + } +} + +static int usbback_init(struct XenDevice *xendev) +{ + struct usbback_info *usbif; + + TR_BUS(xendev, "start\n"); + + usbif = container_of(xendev, struct usbback_info, xendev); + + if (xenstore_read_be_int(xendev, "num-ports", &usbif->num_ports) || + usbif->num_ports < 1 || usbif->num_ports > USBBACK_MAXPORTS) { + xen_be_printf(xendev, 0, "num-ports not readable or out of bounds\n"); + return -1; + } + if (xenstore_read_be_int(xendev, "usb-ver", &usbif->usb_ver) || + (usbif->usb_ver != USB_VER_USB11 && usbif->usb_ver != USB_VER_USB20)) { + xen_be_printf(xendev, 0, "usb-ver not readable or out of bounds\n"); + return -1; + } + + usbback_backend_changed(xendev, "port"); + + TR_BUS(xendev, "finished\n"); + + return 0; +} + +static void xen_bus_attach(USBPort *port) +{ + struct usbback_info *usbif; + + usbif = port->opaque; + TR_BUS(&usbif->xendev, "\n"); + usbif->ports[port->index].attached = true; + usbback_hotplug_enq(usbif, port->index + 1); +} + +static void xen_bus_detach(USBPort *port) +{ + struct usbback_info *usbif; + + usbif = port->opaque; + TR_BUS(&usbif->xendev, "\n"); + usbif->ports[port->index].attached = false; + usbback_hotplug_enq(usbif, port->index + 1); +} + +static void xen_bus_child_detach(USBPort *port, USBDevice *child) +{ + struct usbback_info *usbif; + + usbif = port->opaque; + TR_BUS(&usbif->xendev, "\n"); +} + +static void xen_bus_complete(USBPort *port, USBPacket *packet) +{ + struct usbback_info *usbif; + + usbif = port->opaque; + TR_REQ(&usbif->xendev, "\n"); + usbback_packet_complete(packet); +} + +static USBPortOps xen_usb_port_ops = { + .attach = xen_bus_attach, + .detach = xen_bus_detach, + .child_detach = xen_bus_child_detach, + .complete = xen_bus_complete, +}; + +static USBBusOps xen_usb_bus_ops = { +}; + +static void usbback_alloc(struct XenDevice *xendev) +{ + struct usbback_info *usbif; + USBPort *p; + unsigned int i, max_grants; + + usbif = container_of(xendev, struct usbback_info, xendev); + + usb_bus_new(&usbif->bus, sizeof(usbif->bus), &xen_usb_bus_ops, xen_sysdev); + for (i = 0; i < USBBACK_MAXPORTS; i++) { + p = &(usbif->ports[i].port); + usb_register_port(&usbif->bus, p, usbif, i, &xen_usb_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL | + USB_SPEED_MASK_HIGH); + snprintf(p->path, sizeof(p->path), "%d", 99); + } + + QTAILQ_INIT(&usbif->req_free_q); + QSIMPLEQ_INIT(&usbif->hotplug_q); + usbif->bh = qemu_bh_new(usbback_bh, usbif); + + /* max_grants: for each request and for the rings (request and connect). */ + max_grants = USBIF_MAX_SEGMENTS_PER_REQUEST * USB_URB_RING_SIZE + 2; + if (xengnttab_set_max_grants(xendev->gnttabdev, max_grants) < 0) { + xen_be_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n", + strerror(errno)); + } +} + +static int usbback_free(struct XenDevice *xendev) +{ + struct usbback_info *usbif; + struct usbback_req *usbback_req; + struct usbback_hotplug *usb_hp; + unsigned int i; + + TR_BUS(xendev, "start\n"); + + usbback_disconnect(xendev); + usbif = container_of(xendev, struct usbback_info, xendev); + for (i = 1; i <= usbif->num_ports; i++) { + usbback_portid_remove(usbif, i); + } + + while (!QTAILQ_EMPTY(&usbif->req_free_q)) { + usbback_req = QTAILQ_FIRST(&usbif->req_free_q); + QTAILQ_REMOVE(&usbif->req_free_q, usbback_req, q); + g_free(usbback_req); + } + while (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) { + usb_hp = QSIMPLEQ_FIRST(&usbif->hotplug_q); + QSIMPLEQ_REMOVE_HEAD(&usbif->hotplug_q, q); + g_free(usb_hp); + } + + qemu_bh_delete(usbif->bh); + + for (i = 0; i < USBBACK_MAXPORTS; i++) { + usb_unregister_port(&usbif->bus, &(usbif->ports[i].port)); + } + + usb_bus_release(&usbif->bus); + + TR_BUS(xendev, "finished\n"); + + return 0; +} + +static void usbback_event(struct XenDevice *xendev) +{ + struct usbback_info *usbif; + + usbif = container_of(xendev, struct usbback_info, xendev); + qemu_bh_schedule(usbif->bh); +} + +struct XenDevOps xen_usb_ops = { + .size = sizeof(struct usbback_info), + .flags = DEVOPS_FLAG_NEED_GNTDEV, + .init = usbback_init, + .alloc = usbback_alloc, + .free = usbback_free, + .backend_changed = usbback_backend_changed, + .initialise = usbback_connect, + .disconnect = usbback_disconnect, + .event = usbback_event, +}; + +#else /* USBIF_SHORT_NOT_OK */ + +static int usbback_not_supported(void) +{ + return -EINVAL; +} + +struct XenDevOps xen_usb_ops = { + .backend_register = usbback_not_supported, +}; + +#endif diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 48d5bc6047..f68cf48a29 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -80,6 +80,9 @@ static void xen_init_pv(MachineState *machine) xen_be_register("vfb", &xen_framebuffer_ops); xen_be_register("qdisk", &xen_blkdev_ops); xen_be_register("qnic", &xen_netdev_ops); +#ifdef CONFIG_USB_LIBUSB + xen_be_register("qusb", &xen_usb_ops); +#endif /* configure framebuffer */ if (xenfb_enabled) { diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h index 63364f71d0..6e18a46a97 100644 --- a/include/hw/xen/xen_backend.h +++ b/include/hw/xen/xen_backend.h @@ -101,6 +101,9 @@ extern struct XenDevOps xen_kbdmouse_ops; /* xen_framebuffer.c */ extern struct XenDevOps xen_framebuffer_ops; /* xen_framebuffer.c */ extern struct XenDevOps xen_blkdev_ops; /* xen_disk.c */ extern struct XenDevOps xen_netdev_ops; /* xen_nic.c */ +#ifdef CONFIG_USB_LIBUSB +extern struct XenDevOps xen_usb_ops; /* xen-usb.c */ +#endif void xen_init_display(int domid); diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index 7b52e8ffc1..5eabf37328 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -49,6 +49,8 @@ typedef xc_gnttab xengnttab_handle; #define xengnttab_unmap(h, a, n) xc_gnttab_munmap(h, a, n) #define xengnttab_map_grant_refs(h, c, d, r, p) \ xc_gnttab_map_grant_refs(h, c, d, r, p) +#define xengnttab_map_domain_grant_refs(h, c, d, r, p) \ + xc_gnttab_map_domain_grant_refs(h, c, d, r, p) #define xenforeignmemory_open(l, f) xen_xc -- 2.51.1 From 87e73bcc23fedcaa89776810dfcf4c6ef8ad39b1 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 13 Jun 2016 11:12:21 +0200 Subject: [PATCH 44/58] xen: move xen_sysdev to xen_backend.c Commit 9432e53a5bc88681b2d3aec4dac9db07c5476d1b added xen_sysdev as a system device to serve as an anchor for removable virtual buses. This introduced a build failure for non-x86 builds with CONFIG_XEN_BACKEND set, as xen_sysdev was defined in a x86 specific file while being consumed in an architecture independent source. Move the xen_sysdev definition and initialization to xen_backend.c to avoid the build failure. Signed-off-by: Juergen Gross Reviewed-by: Anthony PERARD Acked-by: Stefano Stabellini Signed-off-by: Stefano Stabellini --- hw/xen/xen_backend.c | 41 +++++++++++++++++++++++++++++++++++++++ hw/xenpv/xen_machine_pv.c | 40 -------------------------------------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c index c63f9df38b..6e52474217 100644 --- a/hw/xen/xen_backend.c +++ b/hw/xen/xen_backend.c @@ -27,12 +27,17 @@ #include #include "hw/hw.h" +#include "hw/sysbus.h" #include "sysemu/char.h" #include "qemu/log.h" #include "hw/xen/xen_backend.h" #include +#define TYPE_XENSYSDEV "xensysdev" + +DeviceState *xen_sysdev; + /* ------------------------------------------------------------- */ /* public */ @@ -763,6 +768,10 @@ int xen_be_init(void) /* Check if xen_init() have been called */ goto err; } + + xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV); + qdev_init_nofail(xen_sysdev); + return 0; err: @@ -863,3 +872,35 @@ void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ... } qemu_log_flush(); } + +static int xen_sysdev_init(SysBusDevice *dev) +{ + return 0; +} + +static Property xen_sysdev_properties[] = { + {/* end of property list */}, +}; + +static void xen_sysdev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xen_sysdev_init; + dc->props = xen_sysdev_properties; +} + +static const TypeInfo xensysdev_info = { + .name = TYPE_XENSYSDEV, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = xen_sysdev_class_init, +}; + +static void xenbe_register_types(void) +{ + type_register_static(&xensysdev_info); +} + +type_init(xenbe_register_types); diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index f68cf48a29..48f725c9cd 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -25,15 +25,10 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/boards.h" -#include "hw/sysbus.h" #include "hw/xen/xen_backend.h" #include "xen_domainbuild.h" #include "sysemu/block-backend.h" -#define TYPE_XENSYSDEV "xensysdev" - -DeviceState *xen_sysdev; - static void xen_init_pv(MachineState *machine) { DriveInfo *dinfo; @@ -72,9 +67,6 @@ static void xen_init_pv(MachineState *machine) break; } - xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV); - qdev_init_nofail(xen_sysdev); - xen_be_register("console", &xen_console_ops); xen_be_register("vkbd", &xen_kbdmouse_ops); xen_be_register("vfb", &xen_framebuffer_ops); @@ -112,38 +104,6 @@ static void xen_init_pv(MachineState *machine) xen_init_display(xen_domid); } -static int xen_sysdev_init(SysBusDevice *dev) -{ - return 0; -} - -static Property xen_sysdev_properties[] = { - {/* end of property list */}, -}; - -static void xen_sysdev_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = xen_sysdev_init; - dc->props = xen_sysdev_properties; -} - -static const TypeInfo xensysdev_info = { - .name = TYPE_XENSYSDEV, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SysBusDevice), - .class_init = xen_sysdev_class_init, -}; - -static void xenpv_register_types(void) -{ - type_register_static(&xensysdev_info); -} - -type_init(xenpv_register_types); - static void xenpv_machine_init(MachineClass *mc) { mc->desc = "Xen Para-virtualized PC"; -- 2.51.1 From a77aa218a1ae490d8b4594a77492353c4ebf235f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 1 Jun 2016 08:22:30 +0200 Subject: [PATCH 45/58] vnc: add configurable keyboard delay Limits the rate kbd events from the vnc server are forwarded to the guest, so input devices which are typically low-bandwidth can keep up even on bulky input. v2: update documentation too. v3: spell fixes. Signed-off-by: Gerd Hoffmann Tested-by: Yang Hongyang Message-id: 1464762150-25817-1-git-send-email-kraxel@redhat.com (cherry picked from commit c5ce83334465ee5acb6789a2f22d125273761c9e) [BR: BSC#974914] Signed-off-by: Bruce Rogers --- qemu-options.hx | 8 ++++++++ ui/vnc.c | 13 +++++++++++-- ui/vnc.h | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 32b25a5a4d..3bcd98f637 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1410,6 +1410,14 @@ everybody else. 'ignore' completely ignores the shared flag and allows everybody connect unconditionally. Doesn't conform to the rfb spec but is traditional QEMU behavior. +@item key-delay-ms + +Set keyboard delay, for key down and key up events, in milliseconds. +Default is 1. Keyboards are low-bandwidth devices, so this slowdown +can help the device and guest to keep up and not lose events in case +events are arriving in bulk. Possible causes for the latter are flaky +network connections, or scripts for automated testing. + @end table ETEXI diff --git a/ui/vnc.c b/ui/vnc.c index e7946ba7e1..f78c8c3563 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1639,6 +1639,7 @@ static void reset_keys(VncState *vs) for(i = 0; i < 256; i++) { if (vs->modifiers_state[i]) { qemu_input_event_send_key_number(vs->vd->dcl.con, i, false); + qemu_input_event_send_key_delay(vs->vd->key_delay_ms); vs->modifiers_state[i] = 0; } } @@ -1648,9 +1649,9 @@ static void press_key(VncState *vs, int keysym) { int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK; qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true); - qemu_input_event_send_key_delay(0); + qemu_input_event_send_key_delay(vs->vd->key_delay_ms); qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false); - qemu_input_event_send_key_delay(0); + qemu_input_event_send_key_delay(vs->vd->key_delay_ms); } static int current_led_state(VncState *vs) @@ -1802,6 +1803,7 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) if (qemu_console_is_graphic(NULL)) { qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down); + qemu_input_event_send_key_delay(vs->vd->key_delay_ms); } else { bool numlock = vs->modifiers_state[0x45]; bool control = (vs->modifiers_state[0x1d] || @@ -1923,6 +1925,7 @@ static void vnc_release_modifiers(VncState *vs) continue; } qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false); + qemu_input_event_send_key_delay(vs->vd->key_delay_ms); } } @@ -3297,6 +3300,9 @@ static QemuOptsList qemu_vnc_opts = { },{ .name = "lock-key-sync", .type = QEMU_OPT_BOOL, + },{ + .name = "key-delay-ms", + .type = QEMU_OPT_NUMBER, },{ .name = "sasl", .type = QEMU_OPT_BOOL, @@ -3536,6 +3542,7 @@ void vnc_display_open(const char *id, Error **errp) #endif int acl = 0; int lock_key_sync = 1; + int key_delay_ms; if (!vs) { error_setg(errp, "VNC display not active"); @@ -3658,6 +3665,7 @@ void vnc_display_open(const char *id, Error **errp) reverse = qemu_opt_get_bool(opts, "reverse", false); lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true); + key_delay_ms = qemu_opt_get_number(opts, "key-delay-ms", 1); sasl = qemu_opt_get_bool(opts, "sasl", false); #ifndef CONFIG_VNC_SASL if (sasl) { @@ -3790,6 +3798,7 @@ void vnc_display_open(const char *id, Error **errp) } #endif vs->lock_key_sync = lock_key_sync; + vs->key_delay_ms = key_delay_ms; device_id = qemu_opt_get(opts, "display"); if (device_id) { diff --git a/ui/vnc.h b/ui/vnc.h index 81a326116b..6568bca520 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -155,6 +155,7 @@ struct VncDisplay DisplayChangeListener dcl; kbd_layout_t *kbd_layout; int lock_key_sync; + int key_delay_ms; QemuMutex mutex; QEMUCursor *cursor; -- 2.51.1 From c4fc507e8d321e3ad3df335b6c4ab84d8fd6bae7 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Fri, 6 May 2016 14:03:09 -0400 Subject: [PATCH 46/58] configure: add echo_version helper Simplifies printing library versions, dependent on if the library was even found Signed-off-by: Cole Robinson Message-id: 3c9ab16123e06bb4109771ef6ee8acd82d449ba0.1462557436.git.crobinso@redhat.com Signed-off-by: Gerd Hoffmann (cherry picked from commit 02d34f62fdecb54637e5a66d254bd68fcbfa397f) [BR: BSC#988855] Signed-off-by: Bruce Rogers --- configure | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/configure b/configure index 8892b36dfd..51dc704277 100755 --- a/configure +++ b/configure @@ -4749,6 +4749,12 @@ EOF fi fi +echo_version() { + if test "$1" = "yes" ; then + echo "($2)" + fi +} + # prepend pixman and ftd flags after all config tests are done QEMU_CFLAGS="$pixman_cflags $fdt_cflags $QEMU_CFLAGS" libs_softmmu="$pixman_libs $libs_softmmu" @@ -4806,11 +4812,7 @@ echo "GNUTLS hash $gnutls_hash" echo "GNUTLS rnd $gnutls_rnd" echo "libgcrypt $gcrypt" echo "libgcrypt kdf $gcrypt_kdf" -if test "$nettle" = "yes"; then - echo "nettle $nettle ($nettle_version)" -else - echo "nettle $nettle" -fi +echo "nettle $nettle `echo_version $nettle $nettle_version`" echo "nettle kdf $nettle_kdf" echo "libtasn1 $tasn1" echo "VTE support $vte" @@ -4862,11 +4864,7 @@ echo "Trace backends $trace_backends" if have_backend "simple"; then echo "Trace output file $trace_file-" fi -if test "$spice" = "yes"; then -echo "spice support $spice ($spice_protocol_version/$spice_server_version)" -else -echo "spice support $spice" -fi +echo "spice support $spice `echo_version $spice $spice_protocol_version/$spice_server_version`" echo "rbd support $rbd" echo "xfsctl support $xfs" echo "smartcard support $smartcard" -- 2.51.1 From eeb106a711b51266bf05f3895e01575357414ec6 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Fri, 6 May 2016 14:03:12 -0400 Subject: [PATCH 47/58] configure: support vte-2.91 vte >= 0.37 expores API version 2.91, which is where all the active development is. qemu builds and runs fine with that version, so use it if it's available. Signed-off-by: Cole Robinson Message-id: b4f0375647f7b368d3dbd3834aee58cb0253566a.1462557436.git.crobinso@redhat.com Signed-off-by: Gerd Hoffmann (cherry picked from commit c6feff9e09aa999b77a37f532adbb89682ecb1b6) [BR: BSC#988855] Signed-off-by: Bruce Rogers --- configure | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/configure b/configure index 51dc704277..8f1948c320 100755 --- a/configure +++ b/configure @@ -2396,20 +2396,25 @@ fi if test "$vte" != "no"; then if test "$gtkabi" = "3.0"; then - vtepackage="vte-2.90" - vteversion="0.32.0" + vteminversion="0.32.0" + if $pkg_config --exists "vte-2.91"; then + vtepackage="vte-2.91" + else + vtepackage="vte-2.90" + fi else vtepackage="vte" - vteversion="0.24.0" + vteminversion="0.24.0" fi - if $pkg_config --exists "$vtepackage >= $vteversion"; then + if $pkg_config --exists "$vtepackage >= $vteminversion"; then vte_cflags=`$pkg_config --cflags $vtepackage` vte_libs=`$pkg_config --libs $vtepackage` + vteversion=`$pkg_config --modversion $vtepackage` libs_softmmu="$vte_libs $libs_softmmu" vte="yes" elif test "$vte" = "yes"; then if test "$gtkabi" = "3.0"; then - feature_not_found "vte" "Install libvte-2.90 devel" + feature_not_found "vte" "Install libvte-2.90/2.91 devel" else feature_not_found "vte" "Install libvte devel" fi @@ -4807,6 +4812,7 @@ echo "pixman $pixman" echo "SDL support $sdl" echo "GTK support $gtk" echo "GTK GL support $gtk_gl" +echo "VTE support $vte `echo_version $vte $vteversion`" echo "GNUTLS support $gnutls" echo "GNUTLS hash $gnutls_hash" echo "GNUTLS rnd $gnutls_rnd" @@ -4815,7 +4821,6 @@ echo "libgcrypt kdf $gcrypt_kdf" echo "nettle $nettle `echo_version $nettle $nettle_version`" echo "nettle kdf $nettle_kdf" echo "libtasn1 $tasn1" -echo "VTE support $vte" echo "curses support $curses" echo "virgl support $virglrenderer" echo "curl support $curl" -- 2.51.1 From 8b1a852589b2693dd384680d761e617a34ba2f9e Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 4 Jul 2016 13:06:36 +0100 Subject: [PATCH 48/58] hw/arm/virt: mark the PCIe host controller as DMA coherent in the DT Since QEMU performs cacheable accesses to guest memory when doing DMA as part of the implementation of emulated PCI devices, guest drivers should use cacheable accesses as well when running under KVM. Since this essentially means that emulated PCI devices are DMA coherent, set the 'dma-coherent' DT property on the PCIe host controller DT node. This brings the DT description into line with the ACPI description, which already marks the PCI bridge as cache coherent (see commit bc64b96c984abf). Signed-off-by: Ard Biesheuvel Message-id: 1467134090-5099-1-git-send-email-ard.biesheuvel@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell (cherry picked from commit 5d636e21c44ecf982a22a7bc4ca89186079ac283) Signed-off-by: Alexander Graf --- hw/arm/virt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index a535285e4e..30841de7ad 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -950,6 +950,7 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2); qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, nr_pcie_buses - 1); + qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0); if (vbi->v2m_phandle) { qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", -- 2.51.1 From 6fc72ceb37357fb66b43b17a84b4b6fe128c5f4f Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Tue, 21 Jun 2016 18:42:45 +0200 Subject: [PATCH 49/58] xen: SUSE xenlinux unplug for emulated PCI Implement SUSE specific unplug protocol for emulated PCI devices in PVonHVM guests (bsc#953339, bsc#953362, bsc#953518, bsc#984981) Signed-off-by: Olaf Hering --- hw/i386/xen/xen_platform.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index aa7839324c..48800c122a 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -314,6 +314,28 @@ static void xen_platform_ioport_writeb(void *opaque, hwaddr addr, case 0: /* Platform flags */ platform_fixed_ioport_writeb(opaque, 0, (uint32_t)val); break; + case 4: + if (val == 1 && size == 1) { + /* + * SUSE unplug for Xenlinux + * xen-kmp used this since xen-3.0.4, instead the official protocol from xen-3.3+ + * It did an unconditional "outl(1, (ioaddr + 4));" + * This approach was used until openSUSE 12.3, up to SLE11SP3 and in SLE10. + * Starting with openSUSE 13.1, SLE11SP4 and SLE12 the official protocol is used. + * pre VMDP 1.7 made use of 4 and 8 depending on how vmdp was configured. + * If VMDP was to control both disk and LAN it would use 4. + * If it controlled just disk or just LAN, it would use 8 below. + */ + PCIDevice *pci_dev = PCI_DEVICE(s); + DPRINTF("unplug disks\n"); + blk_drain_all(); + blk_flush_all(); + pci_unplug_disks(pci_dev->bus); + DPRINTF("unplug nics\n"); + pci_unplug_nics(pci_dev->bus); + DPRINTF("done\n"); + } + break; case 8: log_writeb(s, (uint32_t)val); break; -- 2.51.1 From ef7fe72329d837ac78895a6b287bc6d7cb2a6889 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 20 Jun 2016 16:32:39 +0200 Subject: [PATCH 50/58] scsi: esp: fix migration Commit 926cde5 ("scsi: esp: make cmdbuf big enough for maximum CDB size", 2016-06-16) changed the size of a migrated field. Split it in two parts, and only migrate the second part in a new vmstate version. Signed-off-by: Paolo Bonzini (cherry picked from commit cc96677469388bad3d66479379735cf75db069e3) [BR: CVE-2016-6351 BSC#990835] Signed-off-by: Bruce Rogers --- hw/scsi/esp.c | 5 +++-- include/migration/vmstate.h | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index baa0a2cfdf..1f2f2d33dd 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -574,7 +574,7 @@ static bool esp_mem_accepts(void *opaque, hwaddr addr, const VMStateDescription vmstate_esp = { .name ="esp", - .version_id = 3, + .version_id = 4, .minimum_version_id = 3, .fields = (VMStateField[]) { VMSTATE_BUFFER(rregs, ESPState), @@ -585,7 +585,8 @@ const VMStateDescription vmstate_esp = { VMSTATE_BUFFER(ti_buf, ESPState), VMSTATE_UINT32(status, ESPState), VMSTATE_UINT32(dma, ESPState), - VMSTATE_BUFFER(cmdbuf, ESPState), + VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16), + VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4), VMSTATE_UINT32(cmdlen, ESPState), VMSTATE_UINT32(do_cmd, ESPState), VMSTATE_UINT32(dma_left, ESPState), diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 84ee355ceb..853a2bd6ba 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -888,8 +888,11 @@ extern const VMStateInfo vmstate_info_bitmap; #define VMSTATE_PARTIAL_BUFFER(_f, _s, _size) \ VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, 0, _size) +#define VMSTATE_BUFFER_START_MIDDLE_V(_f, _s, _start, _v) \ + VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, _start, sizeof(typeof_field(_s, _f))) + #define VMSTATE_BUFFER_START_MIDDLE(_f, _s, _start) \ - VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, _start, sizeof(typeof_field(_s, _f))) + VMSTATE_BUFFER_START_MIDDLE_V(_f, _s, _start, 0) #define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size) \ VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size) -- 2.51.1 From 57e6b7c9e33686c070e6b5bce203e1a4a01b821d Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Fri, 29 Jul 2016 12:51:53 +0200 Subject: [PATCH 51/58] xen: when removing a backend don't remove many of them When a Xenstore watch fires indicating a backend has to be removed don't remove all backends for that domain with the specified device index, but just the one which has the correct type. The easiest way to achieve this is to use the already determined xendev as parameter for xen_be_del_xendev() instead of only the domid and device index. This at once removes the open coded QTAILQ_FOREACH_SAVE() in xen_be_del_xendev() as there is no need to search for the correct xendev any longer. Signed-off-by: Juergen Gross Signed-off-by: Bruce Rogers --- hw/xen/xen_backend.c | 62 +++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c index 6e52474217..8f347dafd8 100644 --- a/hw/xen/xen_backend.c +++ b/hw/xen/xen_backend.c @@ -322,48 +322,28 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev, /* * release xen backend device. */ -static struct XenDevice *xen_be_del_xendev(int dom, int dev) +static void xen_be_del_xendev(struct XenDevice *xendev) { - struct XenDevice *xendev, *xnext; - - /* - * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but - * we save the next pointer in xnext because we might free xendev. - */ - xnext = xendevs.tqh_first; - while (xnext) { - xendev = xnext; - xnext = xendev->next.tqe_next; - - if (xendev->dom != dom) { - continue; - } - if (xendev->dev != dev && dev != -1) { - continue; - } - - if (xendev->ops->free) { - xendev->ops->free(xendev); - } - - if (xendev->fe) { - char token[XEN_BUFSIZE]; - snprintf(token, sizeof(token), "fe:%p", xendev); - xs_unwatch(xenstore, xendev->fe, token); - g_free(xendev->fe); - } - - if (xendev->evtchndev != NULL) { - xenevtchn_close(xendev->evtchndev); - } - if (xendev->gnttabdev != NULL) { - xengnttab_close(xendev->gnttabdev); - } - - QTAILQ_REMOVE(&xendevs, xendev, next); - g_free(xendev); + if (xendev->ops->free) { + xendev->ops->free(xendev); } - return NULL; + + if (xendev->fe) { + char token[XEN_BUFSIZE]; + snprintf(token, sizeof(token), "fe:%p", xendev); + xs_unwatch(xenstore, xendev->fe, token); + g_free(xendev->fe); + } + + if (xendev->evtchndev != NULL) { + xenevtchn_close(xendev->evtchndev); + } + if (xendev->gnttabdev != NULL) { + xengnttab_close(xendev->gnttabdev); + } + + QTAILQ_REMOVE(&xendevs, xendev, next); + g_free(xendev); } /* @@ -683,7 +663,7 @@ static void xenstore_update_be(char *watch, char *type, int dom, if (xendev != NULL) { bepath = xs_read(xenstore, 0, xendev->be, &len); if (bepath == NULL) { - xen_be_del_xendev(dom, dev); + xen_be_del_xendev(xendev); } else { free(bepath); xen_be_backend_changed(xendev, path); -- 2.51.1 From 559d8ccdb0a5e92b6a0a42f2850caa7a8c57ae76 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 27 Jul 2016 08:17:41 +0200 Subject: [PATCH 52/58] xen: drain submit queue in xen-usb before removing device When unplugging a device in the Xen pvusb backend drain the submit queue before deallocation of the control structures. Otherwise there will be bogus memory accesses when I/O contracts are finished. Correlated to this issue is the handling of cancel requests: a packet cancelled will still lead to the call of complete, so add a flag to the request indicating it should be just dropped on complete. Signed-off-by: Juergen Gross Signed-off-by: Bruce Rogers --- hw/usb/xen-usb.c | 93 +++++++++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 33 deletions(-) diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c index 664df04181..6f4b99d796 100644 --- a/hw/usb/xen-usb.c +++ b/hw/usb/xen-usb.c @@ -94,6 +94,8 @@ struct usbback_req { void *buffer; void *isoc_buffer; struct libusb_transfer *xfer; + + bool cancelled; }; struct usbback_hotplug { @@ -304,20 +306,23 @@ static void usbback_do_response(struct usbback_req *usbback_req, int32_t status, usbback_req->isoc_buffer = NULL; } - res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt); - res->id = usbback_req->req.id; - res->status = status; - res->actual_length = actual_length; - res->error_count = error_count; - res->start_frame = 0; - usbif->urb_ring.rsp_prod_pvt++; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify); + if (usbif->urb_sring) { + res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt); + res->id = usbback_req->req.id; + res->status = status; + res->actual_length = actual_length; + res->error_count = error_count; + res->start_frame = 0; + usbif->urb_ring.rsp_prod_pvt++; + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify); - if (notify) { - xen_be_send_notify(xendev); + if (notify) { + xen_be_send_notify(xendev); + } } - usbback_put_req(usbback_req); + if (!usbback_req->cancelled) + usbback_put_req(usbback_req); } static void usbback_do_response_ret(struct usbback_req *usbback_req, @@ -369,15 +374,14 @@ static void usbback_set_address(struct usbback_info *usbif, } } -static bool usbback_cancel_req(struct usbback_req *usbback_req) +static void usbback_cancel_req(struct usbback_req *usbback_req) { - bool ret = false; - if (usb_packet_is_inflight(&usbback_req->packet)) { usb_cancel_packet(&usbback_req->packet); - ret = true; + QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q); + usbback_req->cancelled = true; + usbback_do_response_ret(usbback_req, -EPROTO); } - return ret; } static void usbback_process_unlink_req(struct usbback_req *usbback_req) @@ -394,7 +398,7 @@ static void usbback_process_unlink_req(struct usbback_req *usbback_req) devnum = usbif_pipedevice(usbback_req->req.pipe); if (unlikely(devnum == 0)) { usbback_req->stub = usbif->ports + - usbif_pipeportnum(usbback_req->req.pipe); + usbif_pipeportnum(usbback_req->req.pipe) - 1; if (unlikely(!usbback_req->stub)) { ret = -ENODEV; goto fail_response; @@ -409,9 +413,7 @@ static void usbback_process_unlink_req(struct usbback_req *usbback_req) QTAILQ_FOREACH(unlink_req, &usbback_req->stub->submit_q, q) { if (unlink_req->req.id == id) { - if (usbback_cancel_req(unlink_req)) { - usbback_do_response_ret(unlink_req, -EPROTO); - } + usbback_cancel_req(unlink_req); break; } } @@ -684,6 +686,31 @@ static void usbback_hotplug_enq(struct usbback_info *usbif, unsigned port) usbback_hotplug_notify(usbif); } +static void usbback_portid_drain(struct usbback_info *usbif, unsigned port) +{ + struct usbback_req *req, *tmp; + bool sched = false; + + QTAILQ_FOREACH_SAFE(req, &usbif->ports[port - 1].submit_q, q, tmp) { + usbback_cancel_req(req); + sched = true; + } + + if (sched) + qemu_bh_schedule(usbif->bh); +} + +static void usbback_portid_detach(struct usbback_info *usbif, unsigned port) +{ + if (!usbif->ports[port - 1].attached) + return; + + usbif->ports[port - 1].speed = USBIF_SPEED_NONE; + usbif->ports[port - 1].attached = false; + usbback_portid_drain(usbif, port); + usbback_hotplug_enq(usbif, port); +} + static void usbback_portid_remove(struct usbback_info *usbif, unsigned port) { USBPort *p; @@ -697,9 +724,7 @@ static void usbback_portid_remove(struct usbback_info *usbif, unsigned port) object_unparent(OBJECT(usbif->ports[port - 1].dev)); usbif->ports[port - 1].dev = NULL; - usbif->ports[port - 1].speed = USBIF_SPEED_NONE; - usbif->ports[port - 1].attached = false; - usbback_hotplug_enq(usbif, port); + usbback_portid_detach(usbif, port); TR_BUS(&usbif->xendev, "port %d removed\n", port); } @@ -804,7 +829,6 @@ static void usbback_process_port(struct usbback_info *usbif, unsigned port) static void usbback_disconnect(struct XenDevice *xendev) { struct usbback_info *usbif; - struct usbback_req *req, *tmp; unsigned int i; TR_BUS(xendev, "start\n"); @@ -823,12 +847,8 @@ static void usbback_disconnect(struct XenDevice *xendev) } for (i = 0; i < usbif->num_ports; i++) { - if (!usbif->ports[i].dev) { - continue; - } - QTAILQ_FOREACH_SAFE(req, &usbif->ports[i].submit_q, q, tmp) { - usbback_cancel_req(req); - } + if (usbif->ports[i].dev) + usbback_portid_drain(usbif, i + 1); } TR_BUS(xendev, "finished\n"); @@ -947,8 +967,7 @@ static void xen_bus_detach(USBPort *port) usbif = port->opaque; TR_BUS(&usbif->xendev, "\n"); - usbif->ports[port->index].attached = false; - usbback_hotplug_enq(usbif, port->index + 1); + usbback_portid_detach(usbif, port->index + 1); } static void xen_bus_child_detach(USBPort *port, USBDevice *child) @@ -961,9 +980,16 @@ static void xen_bus_child_detach(USBPort *port, USBDevice *child) static void xen_bus_complete(USBPort *port, USBPacket *packet) { + struct usbback_req *usbback_req; struct usbback_info *usbif; - usbif = port->opaque; + usbback_req = container_of(packet, struct usbback_req, packet); + if (usbback_req->cancelled) { + g_free(usbback_req); + return; + } + + usbif = usbback_req->usbif; TR_REQ(&usbif->xendev, "\n"); usbback_packet_complete(packet); } @@ -1040,6 +1066,7 @@ static int usbback_free(struct XenDevice *xendev) } usb_bus_release(&usbif->bus); + object_unparent(OBJECT(&usbif->bus)); TR_BUS(xendev, "finished\n"); -- 2.51.1 From c9f5c5004b9fb97398c8dc0003303493904c986c Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 2 Jun 2016 18:58:15 +0300 Subject: [PATCH 53/58] qcow2: avoid extra flushes in qcow2 The problem with excessive flushing was found by a couple of performance tests: - parallel directory tree creation (from 2 processes) - 32 cached writes + fsync at the end in a loop For the first one results improved from 2.6 loops/sec to 3.5 loops/sec. Each loop creates 10^3 directories with 10 files in each. For the second one results improved from ~600 fsync/sec to ~1100 fsync/sec. Though, it was run on SSD so it probably won't show such performance gain on rotational media. qcow2_cache_flush() calls bdrv_flush() unconditionally after writing cache entries of a particular cache. This can lead to as many as 2 additional fdatasyncs inside bdrv_flush. We can simply skip all fdatasync calls inside qcow2_co_flush_to_os as bdrv_flush for sure will do the job. These flushes are necessary to keep the right order of writes to the different caches. Though this is not necessary in the current code base as this ordering is ensured through the flush in qcow2_cache_flush_dependency(). Signed-off-by: Denis V. Lunev CC: Pavel Borzenkov CC: Kevin Wolf CC: Max Reitz Signed-off-by: Kevin Wolf (cherry picked from commit f3c3b87dae44ac6c82246ceb3953793951800a9a) [BR: BSC#991296] Signed-off-by: Bruce Rogers --- block/qcow2-cache.c | 11 +++++++++-- block/qcow2.c | 4 ++-- block/qcow2.h | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index 0fe8edae41..208a060421 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -226,7 +226,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) return 0; } -int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c) +int qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c) { BDRVQcow2State *s = bs->opaque; int result = 0; @@ -242,8 +242,15 @@ int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c) } } + return result; +} + +int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c) +{ + int result = qcow2_cache_write(bs, c); + if (result == 0) { - ret = bdrv_flush(bs->file->bs); + int ret = bdrv_flush(bs->file->bs); if (ret < 0) { result = ret; } diff --git a/block/qcow2.c b/block/qcow2.c index 470734be9f..dc609a1aff 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2774,14 +2774,14 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs) int ret; qemu_co_mutex_lock(&s->lock); - ret = qcow2_cache_flush(bs, s->l2_table_cache); + ret = qcow2_cache_write(bs, s->l2_table_cache); if (ret < 0) { qemu_co_mutex_unlock(&s->lock); return ret; } if (qcow2_need_accurate_refcounts(s)) { - ret = qcow2_cache_flush(bs, s->refcount_block_cache); + ret = qcow2_cache_write(bs, s->refcount_block_cache); if (ret < 0) { qemu_co_mutex_unlock(&s->lock); return ret; diff --git a/block/qcow2.h b/block/qcow2.h index a063a3c1a1..7db9795d44 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -583,6 +583,7 @@ int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c); void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c, void *table); int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c); +int qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c); int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c, Qcow2Cache *dependency); void qcow2_cache_depends_on_flush(Qcow2Cache *c); -- 2.51.1 From 66d8c1e91cb8b11fad0ddc68c7398c5ff202525e Mon Sep 17 00:00:00 2001 From: Bruce Rogers Date: Tue, 2 Aug 2016 11:36:02 -0600 Subject: [PATCH 54/58] qemu-bridge-helper: reduce security profile Change from using glib alloc and free routines to those from libc. Also perform safety measure of dropping privs to user if configured no-caps. [BR: BOO#988279] Signed-off-by: Bruce Rogers --- qemu-bridge-helper.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c index 830fb9e269..73ac49ba66 100644 --- a/qemu-bridge-helper.c +++ b/qemu-bridge-helper.c @@ -15,8 +15,6 @@ #include "qemu/osdep.h" -#include - #include #include #include @@ -111,7 +109,12 @@ static int parse_acl_file(const char *filename, ACLList *acl_list) *argend = 0; if (strcmp(cmd, "deny") == 0) { - acl_rule = g_malloc(sizeof(*acl_rule)); + acl_rule = calloc(1, sizeof(*acl_rule)); + if (!acl_rule) { + fclose(f); + errno = ENOMEM; + return -1; + } if (strcmp(arg, "all") == 0) { acl_rule->type = ACL_DENY_ALL; } else { @@ -120,7 +123,12 @@ static int parse_acl_file(const char *filename, ACLList *acl_list) } QSIMPLEQ_INSERT_TAIL(acl_list, acl_rule, entry); } else if (strcmp(cmd, "allow") == 0) { - acl_rule = g_malloc(sizeof(*acl_rule)); + acl_rule = calloc(1, sizeof(*acl_rule)); + if (!acl_rule) { + fclose(f); + errno = ENOMEM; + return -1; + } if (strcmp(arg, "all") == 0) { acl_rule->type = ACL_ALLOW_ALL; } else { @@ -414,6 +422,17 @@ int main(int argc, char **argv) goto cleanup; } +#ifndef CONFIG_LIBCAP + /* avoid sending the fd as root user if running suid to not fool + * peer credentials to daemons that dont expect that + */ + if (setuid(getuid()) < 0) { + fprintf(stderr, "Failed to drop privileges.\n"); + ret = EXIT_FAILURE; + goto cleanup; + } +#endif + /* write fd to the domain socket */ if (send_fd(unixfd, fd) == -1) { fprintf(stderr, "failed to write fd to unix socket: %s\n", @@ -435,7 +454,7 @@ cleanup: } while ((acl_rule = QSIMPLEQ_FIRST(&acl_list)) != NULL) { QSIMPLEQ_REMOVE_HEAD(&acl_list, entry); - g_free(acl_rule); + free(acl_rule); } return ret; -- 2.51.1 From fceaaa771845a1fa7379539e77390b833dc9de3b Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Tue, 2 Aug 2016 08:32:32 +0200 Subject: [PATCH 55/58] xen: use a common function for pv and hvm guest backend register calls Instead of calling xen_be_register() for each supported backend type for hvm and pv guests in their machine init functions use a common function in order not to have to add new backends twice. This at once fixes the error that hvm domains couldn't use the qusb backend. Signed-off-by: Juergen Gross Acked-by: Anthony PERARD Message-id: 1470119552-16170-1-git-send-email-jgross@suse.com Signed-off-by: Gerd Hoffmann (cherry picked from commit 0e39bb022b5fa8c11964968885f3263c02ce42b0) [BR: BSC#991785] Signed-off-by: Bruce Rogers --- hw/xen/xen_backend.c | 10 ++++++++++ hw/xenpv/xen_machine_pv.c | 7 +------ include/hw/xen/xen_backend.h | 1 + xen-hvm.c | 4 +--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c index 8f347dafd8..f4d302d1d5 100644 --- a/hw/xen/xen_backend.c +++ b/hw/xen/xen_backend.c @@ -781,6 +781,16 @@ int xen_be_register(const char *type, struct XenDevOps *ops) return xenstore_scan(type, xen_domid, ops); } +void xen_be_register_common(void) +{ + xen_be_register("console", &xen_console_ops); + xen_be_register("vkbd", &xen_kbdmouse_ops); + xen_be_register("qdisk", &xen_blkdev_ops); +#ifdef CONFIG_USB_LIBUSB + xen_be_register("qusb", &xen_usb_ops); +#endif +} + int xen_be_bind_evtchn(struct XenDevice *xendev) { if (xendev->local_port != -1) { diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 48f725c9cd..79aef4ecc3 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -67,14 +67,9 @@ static void xen_init_pv(MachineState *machine) break; } - xen_be_register("console", &xen_console_ops); - xen_be_register("vkbd", &xen_kbdmouse_ops); + xen_be_register_common(); xen_be_register("vfb", &xen_framebuffer_ops); - xen_be_register("qdisk", &xen_blkdev_ops); xen_be_register("qnic", &xen_netdev_ops); -#ifdef CONFIG_USB_LIBUSB - xen_be_register("qusb", &xen_usb_ops); -#endif /* configure framebuffer */ if (xenfb_enabled) { diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h index 6e18a46a97..0e9af28417 100644 --- a/include/hw/xen/xen_backend.h +++ b/include/hw/xen/xen_backend.h @@ -87,6 +87,7 @@ void xen_be_check_state(struct XenDevice *xendev); /* xen backend driver bits */ int xen_be_init(void); +void xen_be_register_common(void); int xen_be_register(const char *type, struct XenDevOps *ops); int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state); int xen_be_bind_evtchn(struct XenDevice *xendev); diff --git a/xen-hvm.c b/xen-hvm.c index 039680a6d9..93c958a949 100644 --- a/xen-hvm.c +++ b/xen-hvm.c @@ -1305,9 +1305,7 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory) error_report("xen backend core setup failed"); goto err; } - xen_be_register("console", &xen_console_ops); - xen_be_register("vkbd", &xen_kbdmouse_ops); - xen_be_register("qdisk", &xen_blkdev_ops); + xen_be_register_common(); xen_read_physmap(state); return; -- 2.51.1 From 91d70a81877681df04c453bcb64bb67720973463 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Fri, 6 May 2016 14:03:13 -0400 Subject: [PATCH 56/58] ui: gtk: Fix a runtime warning on vte >= 0.37 inner-border was dropped in vte API 2.91, in favor of the standard padding style Signed-off-by: Cole Robinson Message-id: 60a6cdc337d611d902f53907e66a8f37ea374d65.1462557436.git.crobinso@redhat.com [ kraxel: Fix warning with old vte version. ] Signed-off-by: Gerd Hoffmann (cherry picked from commit 84e2dc4bf39f6ba90390b5f32aadcfcf18168e1d) [MS: BSC#1008519] Signed-off-by: Michal Suchanek --- ui/gtk.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ui/gtk.c b/ui/gtk.c index 9876d899aa..28e7d28fa8 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -330,6 +330,17 @@ static void gd_update_geometry_hints(VirtualConsole *vc) VteTerminal *term = VTE_TERMINAL(vc->vte.terminal); GtkBorder *ib; +#if VTE_CHECK_VERSION(0, 37, 0) + GtkBorder padding; + gtk_style_context_get_padding( + gtk_widget_get_style_context(vc->vte.terminal), + gtk_widget_get_state_flags(vc->vte.terminal), + &padding); + ib = &padding; +#else + gtk_widget_style_get(vc->vte.terminal, "inner-border", &ib, NULL); +#endif + geo.width_inc = vte_terminal_get_char_width(term); geo.height_inc = vte_terminal_get_char_height(term); mask |= GDK_HINT_RESIZE_INC; @@ -339,7 +350,7 @@ static void gd_update_geometry_hints(VirtualConsole *vc) geo.min_width = geo.width_inc * VC_TERM_X_MIN; geo.min_height = geo.height_inc * VC_TERM_Y_MIN; mask |= GDK_HINT_MIN_SIZE; - gtk_widget_style_get(vc->vte.terminal, "inner-border", &ib, NULL); + if (ib) { geo.base_width += ib->left + ib->right; geo.base_height += ib->top + ib->bottom; -- 2.51.1 From 2f19a90303db01e0d7f400ad569bd25b2a849dd3 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Fri, 13 May 2016 11:20:54 +0300 Subject: [PATCH 57/58] gtk: don't leak the GtkBorder with VTE 0.36 When gtk_widget_style_get() is used to get the "inner-border" style property, it returns a copy of the GtkBorder which must be freed by the caller. This patch also fixes a warning about the unused 'padding' structure with VTE 0.36. Signed-off-by: Alberto Garcia Message-id: 1463127654-5171-1-git-send-email-berto@igalia.com Cc: Cole Robinson Cc: Gerd Hoffmann [ kraxel: adapted to changes in ui patch queue ] Signed-off-by: Gerd Hoffmann (cherry picked from commit 6978dc4adcdf27722aa6f9e13f88a903b30a3f8d) [MS: BSC#1008519] Signed-off-by: Michal Suchanek --- ui/gtk.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 28e7d28fa8..633a89335f 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -328,17 +328,22 @@ static void gd_update_geometry_hints(VirtualConsole *vc) #if defined(CONFIG_VTE) } else if (vc->type == GD_VC_VTE) { VteTerminal *term = VTE_TERMINAL(vc->vte.terminal); - GtkBorder *ib; + GtkBorder padding = { 0 }; #if VTE_CHECK_VERSION(0, 37, 0) - GtkBorder padding; gtk_style_context_get_padding( gtk_widget_get_style_context(vc->vte.terminal), gtk_widget_get_state_flags(vc->vte.terminal), &padding); - ib = &padding; #else - gtk_widget_style_get(vc->vte.terminal, "inner-border", &ib, NULL); + { + GtkBorder *ib = NULL; + gtk_widget_style_get(vc->vte.terminal, "inner-border", &ib, NULL); + if (ib) { + padding = *ib; + gtk_border_free(ib); + } + } #endif geo.width_inc = vte_terminal_get_char_width(term); @@ -351,12 +356,10 @@ static void gd_update_geometry_hints(VirtualConsole *vc) geo.min_height = geo.height_inc * VC_TERM_Y_MIN; mask |= GDK_HINT_MIN_SIZE; - if (ib) { - geo.base_width += ib->left + ib->right; - geo.base_height += ib->top + ib->bottom; - geo.min_width += ib->left + ib->right; - geo.min_height += ib->top + ib->bottom; - } + geo.base_width += padding.left + padding.right; + geo.base_height += padding.top + padding.bottom; + geo.min_width += padding.left + padding.right; + geo.min_height += padding.top + padding.bottom; geo_widget = vc->vte.terminal; #endif } -- 2.51.1 From e8fa87acb58143d0c1f9e01e72903ff0929dd355 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Mon, 19 Dec 2016 17:59:48 +0100 Subject: [PATCH 58/58] Add QXL VGA support to some non-x86 archs. TODO: check if there are more archs where this makes sense. --- default-configs/arm-softmmu.mak | 2 ++ default-configs/mips-softmmu-common.mak | 2 ++ default-configs/ppc-softmmu.mak | 2 ++ default-configs/ppc64-softmmu.mak | 1 + 4 files changed, 7 insertions(+) diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index c63cdd073d..8386525dd8 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -2,8 +2,10 @@ include pci.mak include usb.mak +CONFIG_QXL=$(CONFIG_SPICE) CONFIG_VGA=y CONFIG_ISA_MMIO=y +CONFIG_VIRTIO_VGA=y CONFIG_NAND=y CONFIG_ECC=y CONFIG_SERIAL=y diff --git a/default-configs/mips-softmmu-common.mak b/default-configs/mips-softmmu-common.mak index 0394514b93..e228d6eea3 100644 --- a/default-configs/mips-softmmu-common.mak +++ b/default-configs/mips-softmmu-common.mak @@ -3,11 +3,13 @@ include pci.mak include sound.mak include usb.mak +CONFIG_QXL=$(CONFIG_SPICE) CONFIG_ESP=y CONFIG_VGA_ISA=y CONFIG_VGA_ISA_MM=y CONFIG_VGA_CIRRUS=y CONFIG_VMWARE_VGA=y +CONFIG_VIRTIO_VGA=y CONFIG_SERIAL=y CONFIG_PARALLEL=y CONFIG_I8254=y diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index 4befde3c7c..324319c0cf 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -3,6 +3,8 @@ include pci.mak include sound.mak include usb.mak +CONFIG_QXL=$(CONFIG_SPICE) +CONFIG_VIRTIO_VGA=y CONFIG_ISA_MMIO=y CONFIG_ESCC=y CONFIG_M48T59=y diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index bb71b23ee7..3d9dd54b94 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -3,6 +3,7 @@ include pci.mak include sound.mak include usb.mak +CONFIG_QXL=$(CONFIG_SPICE) CONFIG_VIRTIO_VGA=y CONFIG_ISA_MMIO=y CONFIG_ESCC=y -- 2.51.1