For anyone interested, you want to compile this code (courtesy of cesium) and then LD_PRELOAD the resulting library:
Code: Select all
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include "/usr/lib/oss/include/sys/soundcard.h"
static int (*next_ioctl)(int fd, int request, void *data) = NULL;
static char buf[PATH_MAX], x[65535] = { 0 }, s[255];
static pid_t pid;
#define IOCTL(x) case x: fprintf(stderr, #x " ioctl")
#define PRINTINT() \
do { \
if (data != NULL) fprintf(stderr, " with %d arg.", *(int *)data); \
else fprintf(stderr, " with arg == NULL.\n"); \
fflush(stderr); \
ret = next_ioctl(fd, request, data); \
if (data != NULL) fprintf(stderr, " Returned with %d arg\n", *(int *)data); \
fflush(stderr); \
} while(0); \
break
#define PRINTFRAG() \
do { \
if (data == NULL) goto cont; \
fprintf(stderr, "maxfrags: %d, fragsize : %d. Overriden to inf/16384.", *(int *)data & 0xFFFF0000, 1 << (*(int *)data & 0xFFFF)); \
fflush(stderr); \
*(int *)data = (0x7fff << 16) | 14; \
ret = next_ioctl(fd, request, data); \
fprintf(stderr, " Returned: maxfrags: %d, fragsize : %d.\n", *(int *)data & 0xFFFF0000, 1 << (*(int *)data & 0xFFFF)); \
fflush(stderr); \
} while(0); \
break
#define FORMAT(f) case f: fprintf(stderr, " with " #f " format\n"); break
#define PRINTFORMAT() \
do { \
if (data != NULL) \
switch (*(int *)data) { \
FORMAT(AFMT_QUERY); \
FORMAT(AFMT_MU_LAW); \
FORMAT(AFMT_A_LAW); \
FORMAT(AFMT_IMA_ADPCM); \
FORMAT(AFMT_U8); \
FORMAT(AFMT_S16_LE); \
FORMAT(AFMT_S16_BE); \
FORMAT(AFMT_S8); \
FORMAT(AFMT_U16_LE); \
FORMAT(AFMT_U16_BE); \
FORMAT(AFMT_MPEG); \
FORMAT(AFMT_AC3); \
FORMAT(AFMT_VORBIS); \
FORMAT(AFMT_S32_LE); \
FORMAT(AFMT_S32_BE); \
FORMAT(AFMT_FLOAT); \
FORMAT(AFMT_S24_LE); \
FORMAT(AFMT_S24_BE); \
FORMAT(AFMT_SPDIF_RAW); \
FORMAT(AFMT_S24_PACKED); \
default: fprintf(stderr, "with format == %d\n", *(int *)data); \
} \
else fprintf(stderr, "with format == NULL??\n"); \
fflush(stderr); \
} while(0); \
break
int ioctl(int fd, int request, void *data) {
int ret;
if (next_ioctl == NULL) {
char *msg;
next_ioctl = dlsym(RTLD_NEXT, "ioctl");
if ((msg = dlerror()) != NULL) {
fprintf(stderr, "ioctl: dlopen failed : %s\n", msg);
fflush(stderr);
exit(1);
} else {
fprintf(stderr, "ioctl: wrapping done\n");
fflush(stderr);
}
pid = getpid();
}
if (x[fd % 65535] == 2) goto cont;
else if (x[fd % 65535] == 1) goto found;
snprintf(s, sizeof(s), "/proc/%d/fd/%d", pid, fd);
readlink(s, buf, sizeof(buf)-1);
if (strstr(buf, "/dev/oss/") != NULL) x[fd % 65535] = 1;
else if (strstr(buf, "/dev/dsp") != NULL) x[fd % 65535] = 1;
else {
x[fd % 65535] = 2;
goto cont;
}
found:
switch (request) {
IOCTL(SNDCTL_DSP_BIND_CHANNEL); PRINTINT();
IOCTL(SNDCTL_DSP_CHANNELS); PRINTINT();
IOCTL(SNDCTL_DSP_COOKEDMODE); PRINTINT();
IOCTL(SNDCTL_DSP_CURRENT_IPTR); PRINTINT();
IOCTL(SNDCTL_DSP_CURRENT_OPTR); PRINTINT();
IOCTL(SNDCTL_DSP_GETBLKSIZE); PRINTINT();
IOCTL(SNDCTL_DSP_GETCAPS); PRINTINT();
IOCTL(SNDCTL_DSP_GETCHANNELMASK); PRINTINT();
IOCTL(SNDCTL_DSP_GET_CHNORDER); PRINTINT();
IOCTL(SNDCTL_DSP_GETERROR); PRINTINT();
IOCTL(SNDCTL_DSP_GETFMTS); PRINTINT();
IOCTL(SNDCTL_DSP_GETIPEAKS); PRINTINT();
IOCTL(SNDCTL_DSP_GETIPTR); PRINTINT();
IOCTL(SNDCTL_DSP_GETISPACE); PRINTINT();
IOCTL(SNDCTL_DSP_GETODELAY); PRINTINT();
IOCTL(SNDCTL_DSP_GETOPEAKS); PRINTINT();
IOCTL(SNDCTL_DSP_GETOPTR); PRINTINT();
IOCTL(SNDCTL_DSP_GETOSPACE); PRINTINT();
IOCTL(SNDCTL_DSP_GET_PLAYTGT_NAMES); PRINTINT();
IOCTL(SNDCTL_DSP_GET_PLAYTGT); PRINTINT();
IOCTL(SNDCTL_DSP_GETPLAYVOL); PRINTINT();
IOCTL(SNDCTL_DSP_GET_RECSRC_NAMES); PRINTINT();
IOCTL(SNDCTL_DSP_GET_RECSRC); PRINTINT();
IOCTL(SNDCTL_DSP_GETRECVOL); PRINTINT();
IOCTL(SNDCTL_DSP_GETTRIGGER); PRINTINT();
IOCTL(SNDCTL_DSP_LOW_WATER); PRINTINT();
IOCTL(SNDCTL_DSP_NONBLOCK); PRINTINT();
IOCTL(SNDCTL_DSP_POLICY); PRINTINT();
IOCTL(SNDCTL_DSP_POST); PRINTINT();
IOCTL(SNDCTL_DSP_PROFILE); PRINTINT();
IOCTL(SNDCTL_DSP_READCTL); PRINTINT();
IOCTL(SNDCTL_DSP_RESET_INPUT); PRINTINT();
IOCTL(SNDCTL_DSP_RESET_OUTPUT); PRINTINT();
IOCTL(SNDCTL_DSP_RESET); PRINTINT();
IOCTL(SNDCTL_DSP_SET_CHNORDER); PRINTINT();
IOCTL(SNDCTL_DSP_SETDUPLEX); PRINTINT();
IOCTL(SNDCTL_DSP_SETFMT); PRINTFORMAT();
IOCTL(SNDCTL_DSP_SETFRAGMENT); PRINTFRAG();
IOCTL(SNDCTL_DSP_SET_PLAYTGT); PRINTINT();
IOCTL(SNDCTL_DSP_SETPLAYVOL); PRINTINT();
IOCTL(SNDCTL_DSP_SET_RECSRC); PRINTINT();
IOCTL(SNDCTL_DSP_SETRECVOL); PRINTINT();
IOCTL(SNDCTL_DSP_SETSYNCRO); PRINTINT();
IOCTL(SNDCTL_DSP_SILENCE); PRINTINT();
IOCTL(SNDCTL_DSP_SKIP); PRINTINT();
IOCTL(SNDCTL_DSP_SPEED); PRINTINT();
IOCTL(SNDCTL_DSP_STEREO); PRINTINT();
IOCTL(SNDCTL_DSP_SUBDIVIDE); PRINTINT();
IOCTL(SNDCTL_DSP_SYNCGROUP); PRINTINT();
IOCTL(SNDCTL_DSP_SYNC); PRINTINT();
IOCTL(SNDCTL_DSP_SYNCSTART); PRINTINT();
IOCTL(SNDCTL_DSP_WRITECTL); PRINTINT();
default:
if (data != NULL)
fprintf(stderr, "unknown ioctl with arg == %d\n", *(int *)data);
else fprintf(stderr, "unknown ioctl with arg == NULL\n");
fflush(stderr);
goto cont;
}
cont:
return next_ioctl(fd, request, data);
}
Marbleblast works great, though vmware still experiences problems, so I assume that's a different issue.
Adam