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/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/Makefile.objs b/block/Makefile.objs index 44a5416225..34a6fba482 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -21,6 +21,8 @@ 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 += tar.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..1a104ac538 --- /dev/null +++ b/block/dictzip.c @@ -0,0 +1,586 @@ +/* + * 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; + uint32_t chunk_len32; + 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, &chunk_len32, 4) != 4) + goto fail; + + 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) + goto fail; + + s->chunk_cnt = le32_to_cpu(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) + 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 += le16_to_cpu(s->chunks[i]); + break; + case 99: + offset += le32_to_cpu(s->chunks32[i]); + break; + } + + 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); + + 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, 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; + 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 */ + /* 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 += le32_to_cpu(s->chunks32[i]); + else + gz_len += le16_to_cpu(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 %zd - %zd => %zd - %zd\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); 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; 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); diff --git a/block/tar.c b/block/tar.c new file mode 100644 index 0000000000..41620fd919 --- /dev/null +++ b/block/tar.c @@ -0,0 +1,379 @@ +/* + * 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, + char *header) +{ + 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; + + 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; +} + +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'; + real_file = header; + } else if (s->longfile[0]) { + real_file = s->longfile; + } else { + real_file = header; + } + } while(!is_target_file(bs, real_file, header)); + + /* 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); 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/configure b/configure index 60e3c0dd6d..8f1948c320 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" @@ -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="" ;; @@ -2393,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 @@ -4030,6 +4038,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 @@ -4719,6 +4754,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" @@ -4771,19 +4812,15 @@ 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" 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" echo "curses support $curses" echo "virgl support $virglrenderer" echo "curl support $curl" @@ -4832,11 +4869,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" 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 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); 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 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", 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); 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; 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/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..6f4b99d796 --- /dev/null +++ b/hw/usb/xen-usb.c @@ -0,0 +1,1107 @@ +/* + * 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; + + bool cancelled; +}; + +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; + } + + 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 (!usbback_req->cancelled) + 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 void usbback_cancel_req(struct usbback_req *usbback_req) +{ + if (usb_packet_is_inflight(&usbback_req->packet)) { + usb_cancel_packet(&usbback_req->packet); + QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q); + usbback_req->cancelled = true; + usbback_do_response_ret(usbback_req, -EPROTO); + } +} + +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) - 1; + 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) { + usbback_cancel_req(unlink_req); + 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_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; + + 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; + usbback_portid_detach(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; + 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) + usbback_portid_drain(usbif, i + 1); + } + + 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"); + usbback_portid_detach(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_req *usbback_req; + struct usbback_info *usbif; + + 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); +} + +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); + object_unparent(OBJECT(&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/xen/xen_backend.c b/hw/xen/xen_backend.c index 60575ad38d..f4d302d1d5 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 */ @@ -42,11 +47,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 +105,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]; @@ -268,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); } /* @@ -629,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); @@ -714,6 +748,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: @@ -726,9 +764,33 @@ 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); } +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) { @@ -800,3 +862,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/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/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index fc13535992..79aef4ecc3 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -67,10 +67,8 @@ 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); /* configure framebuffer */ 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/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/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h index c839eeb489..0e9af28417 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 { @@ -60,8 +61,10 @@ 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_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); @@ -84,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); @@ -98,6 +102,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 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) 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..458f136fb4 --- /dev/null +++ b/linux-user/binfmt.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include + +#ifdef __x86_64__ +#define ARCH_NAME "x86_64" +#endif + +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 */ + +#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)); + } + 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/linux-user/ioctls.h b/linux-user/ioctls.h index e672655100..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) @@ -90,6 +108,8 @@ 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(FS_IOC_SETFLAGS, IOC_W, MK_PTR(TYPE_LONG)) IOCTL(SIOCATMARK, 0, TYPE_NULL) IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT)) @@ -319,6 +339,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))) @@ -326,6 +351,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/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/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/mmap.c b/linux-user/mmap.c index 3519147bce..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(); } } @@ -358,6 +361,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 +398,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; 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/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 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 032d338869..c084f38490 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++; @@ -3999,6 +4004,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__ } }, @@ -4022,7 +4034,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) @@ -4050,6 +4067,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)) { @@ -4068,6 +4090,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); @@ -4686,6 +4709,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); @@ -5670,6 +5702,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); @@ -5784,6 +5835,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 } }; @@ -5850,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; @@ -6181,9 +6233,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long 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: @@ -6985,6 +7042,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)) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 9e2b3c200a..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) @@ -1087,6 +1093,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 @@ -2456,6 +2463,9 @@ 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) +#define TARGET_FS_IOC_SETFLAGS TARGET_IOWU('f', 2) + struct target_sysinfo { abi_long uptime; /* Seconds since boot */ abi_ulong loads[3]; /* 1, 5, and 15 minute load averages */ @@ -2545,6 +2555,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..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) @@ -83,6 +86,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 +) 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; 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; 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); diff --git a/qemu-options.hx b/qemu-options.hx index 6106520c56..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 @@ -3102,6 +3110,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/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index 289b1a3963..557dd2cc54 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-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/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-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/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-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/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-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/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-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/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-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/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-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/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-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/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-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/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-binfmt:P' > /proc/sys/fs/binfmt_misc/register fi 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/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); 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; 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); 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); 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) 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); diff --git a/ui/gtk.c b/ui/gtk.c index 9876d899aa..633a89335f 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -328,7 +328,23 @@ 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) + gtk_style_context_get_padding( + gtk_widget_get_style_context(vc->vte.terminal), + gtk_widget_get_state_flags(vc->vte.terminal), + &padding); +#else + { + 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); geo.height_inc = vte_terminal_get_char_height(term); @@ -339,13 +355,11 @@ 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; - 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 } diff --git a/ui/vnc.c b/ui/vnc.c index 3e89dad8fa..f78c8c3563 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) @@ -1629,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; } } @@ -1638,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) @@ -1792,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] || @@ -1913,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); } } @@ -3200,6 +3213,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 +3276,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,12 +3291,18 @@ static QemuOptsList qemu_vnc_opts = { },{ .name = "password", .type = QEMU_OPT_BOOL, + },{ + .name = "password-file", + .type = QEMU_OPT_STRING, },{ .name = "reverse", .type = QEMU_OPT_BOOL, },{ .name = "lock-key-sync", .type = QEMU_OPT_BOOL, + },{ + .name = "key-delay-ms", + .type = QEMU_OPT_NUMBER, },{ .name = "sasl", .type = QEMU_OPT_BOOL, @@ -3476,6 +3531,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; @@ -3486,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"); @@ -3601,9 +3658,14 @@ 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); + 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) { @@ -3689,6 +3751,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); @@ -3735,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; 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)) { 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; 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;