]> git.alsa-project.org Git - alsa-oss.git/commitdiff
First public version of OSS emulation library
authorAbramo Bagnara <abramo@alsa-project.org>
Sat, 9 Dec 2000 10:43:21 +0000 (10:43 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Sat, 9 Dec 2000 10:43:21 +0000 (10:43 +0000)
Makefile.am [new file with mode: 0644]
alsa-oss.c [new file with mode: 0644]
configure.in [new file with mode: 0644]
cvscompile [new file with mode: 0644]

diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..782e321
--- /dev/null
@@ -0,0 +1,7 @@
+
+CFLAGS = -g -O2 -W -Wall
+
+lib_LTLIBRARIES = libaoss.la
+
+libaoss_la_SOURCES = alsa-oss.c
+libaoss_la_LIBADD = -ldl -lasound
diff --git a/alsa-oss.c b/alsa-oss.c
new file mode 100644 (file)
index 0000000..3b6dcb3
--- /dev/null
@@ -0,0 +1,1394 @@
+/*
+ *  OSS -> ALSA compatibility layer
+ *  Copyright (c) by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#include <sys/select.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include <linux/soundcard.h>
+#include <sys/asoundlib.h>
+
+#if 0
+#define DEBUG_POLL
+#define DEBUG_SELECT
+#define debug(...) fprintf(stderr, __VA_ARGS__);
+#else
+#define debug(...)
+#endif
+
+int (*_select)(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
+int (*_poll)(struct pollfd *ufds, unsigned int nfds, int timeout);
+
+/* Note that to do a fool proof job we need also to trap:
+   fopen, fdopen, freopen, fclose, fwrite, fread, etc.
+   I hope that no applications use stdio to access OSS devices */
+
+int (*_open)(const char *file, int oflag, ...);
+int (*_close)(int fd);
+ssize_t (*_write)(int fd, const void *buf, size_t n);
+ssize_t (*_read)(int fd, void *buf, size_t n);
+int (*_ioctl)(int fd, unsigned long request, ...);
+int (*_fcntl)(int fd, int cmd, ...);
+void *(*_mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
+int (*_munmap)(void* addr, size_t len);
+
+typedef struct ops {
+       int (*open)(const char *file, int oflag, ...);
+       int (*close)(int fd);
+       ssize_t (*write)(int fd, const void *buf, size_t n);
+       ssize_t (*read)(int fd, void *buf, size_t n);
+       int (*ioctl)(int fd, unsigned long request, ...);
+       int (*fcntl)(int fd, int cmd, ...);
+       void *(*mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
+       int (*munmap)(int fd, void* addr, size_t len);
+} ops_t;
+
+
+#define FD_CLASSES 1
+static ops_t ops[FD_CLASSES];
+
+typedef struct {
+       snd_pcm_t *pcm;
+       size_t frame_bytes;
+       size_t fragment_size;
+       size_t fragments;
+       size_t buffer_size;
+       size_t bytes;
+       size_t boundary;
+       size_t old_hw_ptr;
+       unsigned int mmap:1,
+                    disabled:1;
+} oss_dsp_stream_t;
+
+typedef struct {
+       int channels;
+       int rate;
+       int format;
+       int fragshift;
+       int maxfrags;
+       int subdivision;
+       oss_dsp_stream_t streams[2];
+} oss_dsp_t;
+
+typedef enum { FD_OSS_DSP = 0, FD_DEFAULT = -1, FD_CLOSED = -2 } fd_class_t;
+
+typedef struct {
+       fd_class_t class;
+       void *private;
+       void *mmap_area;
+} fd_t;
+
+static fd_t fds[OPEN_MAX];
+
+#define RETRY OPEN_MAX
+#define OSS_MAJOR 14
+#define OSS_DEVICE_MIXER 0
+#define OSS_DEVICE_SEQUENCER 1
+#define OSS_DEVICE_MIDI 2
+#define OSS_DEVICE_DSP 3
+#define OSS_DEVICE_AUDIO 4
+#define OSS_DEVICE_DSPW 5
+#define OSS_DEVICE_SNDSTAT 6
+#define OSS_DEVICE_MUSIC 8
+#define OSS_DEVICE_DMMIDI 9
+#define OSS_DEVICE_DMFM 10
+#define OSS_DEVICE_AMIXER 11
+#define OSS_DEVICE_ADSP 12
+#define OSS_DEVICE_AMIDI 13
+#define OSS_DEVICE_ADMMIDI 14
+
+static int oss_format_to_alsa(int format)
+{
+       switch (format) {
+       case AFMT_MU_LAW:       return SND_PCM_FORMAT_MU_LAW;
+       case AFMT_A_LAW:        return SND_PCM_FORMAT_A_LAW;
+       case AFMT_IMA_ADPCM:    return SND_PCM_FORMAT_IMA_ADPCM;
+       case AFMT_U8:           return SND_PCM_FORMAT_U8;
+       case AFMT_S16_LE:       return SND_PCM_FORMAT_S16_LE;
+       case AFMT_S16_BE:       return SND_PCM_FORMAT_S16_BE;
+       case AFMT_S8:           return SND_PCM_FORMAT_S8;
+       case AFMT_U16_LE:       return SND_PCM_FORMAT_U16_LE;
+       case AFMT_U16_BE:       return SND_PCM_FORMAT_U16_BE;
+       case AFMT_MPEG:         return SND_PCM_FORMAT_MPEG;
+       default:                return SND_PCM_FORMAT_U8;
+       }
+}
+
+static int alsa_format_to_oss(int format)
+{
+       switch (format) {
+       case SND_PCM_FORMAT_MU_LAW:     return AFMT_MU_LAW;
+       case SND_PCM_FORMAT_A_LAW:      return AFMT_A_LAW;
+       case SND_PCM_FORMAT_IMA_ADPCM:  return AFMT_IMA_ADPCM;
+       case SND_PCM_FORMAT_U8:         return AFMT_U8;
+       case SND_PCM_FORMAT_S16_LE:     return AFMT_S16_LE;
+       case SND_PCM_FORMAT_S16_BE:     return AFMT_S16_BE;
+       case SND_PCM_FORMAT_S8:         return AFMT_S8;
+       case SND_PCM_FORMAT_U16_LE:     return AFMT_U16_LE;
+       case SND_PCM_FORMAT_U16_BE:     return AFMT_U16_BE;
+       case SND_PCM_FORMAT_MPEG:       return AFMT_MPEG;
+       default:                        return -EINVAL;
+       }
+}
+
+static int oss_dsp_params(oss_dsp_t *dsp)
+{
+       int k;
+       for (k = 1; k >= 0; --k) {
+               oss_dsp_stream_t *str = &dsp->streams[k];
+               snd_pcm_t *pcm = str->pcm;
+               snd_pcm_hw_params_t hw;
+               snd_pcm_sw_params_t sw;
+               snd_pcm_hw_info_t info;
+               snd_pcm_strategy_t *strategy;
+               int format;
+               int frag_length;
+               int err;
+               if (!pcm)
+                       continue;
+               snd_pcm_hw_info_any(&info);
+               if (str->mmap)
+                       info.access_mask = SND_PCM_ACCBIT_MMAP_INTERLEAVED;
+               else
+                       info.access_mask = SND_PCM_ACCBIT_RW_INTERLEAVED;
+               format = oss_format_to_alsa(dsp->format);
+               info.format_mask = 1 << format;
+               info.channels_min = info.channels_max = dsp->channels;
+
+               if (dsp->maxfrags > 0)
+                       info.fragments_max = dsp->maxfrags;
+               if (dsp->fragshift > 0) {
+                       frag_length = 1 << dsp->fragshift;
+                       frag_length /= snd_pcm_format_physical_width(format) / 8;
+                       frag_length = (u_int64_t) frag_length * 1000000 / dsp->rate;
+               } else
+                       frag_length = 250000;
+               err = snd_pcm_strategy_simple(&strategy, 1000000, 2000000);
+               assert(err >= 0);
+               err = snd_pcm_strategy_simple_near(strategy, 0, SND_PCM_HW_INFO_RATE,
+                                                  dsp->rate, 1);
+               assert(err >= 0);
+               err = snd_pcm_strategy_simple_near(strategy, 1, SND_PCM_HW_INFO_FRAGMENT_LENGTH,
+                                                  frag_length, 1);
+               assert(err >= 0);
+               err = snd_pcm_strategy_simple_near(strategy, 2, SND_PCM_HW_INFO_BUFFER_LENGTH,
+                                                  1000000, 1);
+               err = snd_pcm_hw_info_strategy(pcm, &info, strategy);
+               snd_pcm_strategy_free(strategy);
+               if (err < 0)
+                       return err;
+               err = snd_pcm_hw_params_info(pcm, &hw, &info);
+               if (err < 0)
+                       return err;
+               dsp->rate = hw.rate;
+               dsp->format = alsa_format_to_oss(hw.format);
+               str->frame_bytes = snd_pcm_format_physical_width(hw.format) * hw.channels / 8;
+               str->fragment_size = hw.fragment_size;
+               str->fragments = hw.fragments;
+               str->buffer_size = hw.fragments * hw.fragment_size;
+               if (str->disabled)
+                       sw.start_mode = SND_PCM_START_EXPLICIT;
+               else
+                       sw.start_mode = SND_PCM_START_DATA;
+               if (str->mmap)
+                       sw.xrun_mode = SND_PCM_XRUN_NONE;
+               else
+                       sw.xrun_mode = SND_PCM_XRUN_FRAGMENT;
+               sw.ready_mode = SND_PCM_READY_FRAGMENT;
+               sw.avail_min = hw.fragment_size;
+               sw.xfer_min = 1;
+               sw.xfer_align = 1;
+               sw.time = 0;
+               err = snd_pcm_sw_params(pcm, &sw);
+               if (err < 0)
+                       return err;
+               str->boundary = sw.boundary;
+               err = snd_pcm_prepare(pcm);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static int oss_dsp_close(int fd)
+{
+       int result = 0;
+       int k;
+       oss_dsp_t *dsp = fds[fd].private;
+       for (k = 0; k < 2; ++k) {
+               int err;
+               oss_dsp_stream_t *str = &dsp->streams[k];
+               if (!str->pcm)
+                       continue;
+               err = snd_pcm_close(str->pcm);
+               if (err < 0)
+                       result = err;
+       }
+       _close(fd);
+       free(dsp);
+       if (result < 0) {
+               errno = -result;
+               return -1;
+       }
+       return 0;
+}
+
+static int oss_dsp_open(int card, int device, int oflag, mode_t mode)
+{
+       oss_dsp_t *dsp;
+       unsigned int pcm_mode = 0;
+       unsigned int streams, k;
+       int format = AFMT_MU_LAW;
+       int fd = -1;
+       int result;
+       char name[64];
+
+       switch (device) {
+       case OSS_DEVICE_DSP:
+               format = AFMT_U8;
+               sprintf(name, "dsp%d", card);
+               break;
+       case OSS_DEVICE_DSPW:
+               format = AFMT_S16_LE;
+               sprintf(name, "dspW%d", card);
+               break;
+       case OSS_DEVICE_AUDIO:
+               sprintf(name, "audio%d", card);
+               break;
+       case OSS_DEVICE_ADSP:
+               sprintf(name, "adsp%d", card);
+               break;
+       default:
+               return RETRY;
+       }
+       if (mode & O_NONBLOCK)
+               pcm_mode = SND_PCM_NONBLOCK;
+       switch (oflag & O_ACCMODE) {
+       case O_RDONLY:
+               streams = 1 << SND_PCM_STREAM_CAPTURE;
+               break;
+       case O_WRONLY:
+               streams = 1 << SND_PCM_STREAM_PLAYBACK;
+               break;
+       case O_RDWR:
+               streams = ((1 << SND_PCM_STREAM_PLAYBACK) | 
+                          (1 << SND_PCM_STREAM_CAPTURE));
+               break;
+       default:
+               errno = EINVAL;
+               return -1;
+       }
+       fd = _open("/dev/null", oflag & O_ACCMODE);
+       assert(fd >= 0);
+       fds[fd].class = FD_OSS_DSP;
+       dsp = calloc(1, sizeof(oss_dsp_t));
+       if (!dsp) {
+               errno = -ENOMEM;
+               return -1;
+       }
+       fds[fd].private = dsp;
+       dsp->channels = 1;
+       dsp->rate = 8000;
+       dsp->format = format;
+       for (k = 0; k < 2; ++k) {
+               if (!(streams & (1 << k)))
+                       continue;
+               result = snd_pcm_open(&dsp->streams[k].pcm, name, k, pcm_mode);
+               if (result < 0)
+                       goto _error;
+       }
+       result = oss_dsp_params(dsp);
+       if (result < 0)
+               goto _error;
+       return fd;
+
+ _error:
+       close(fd);
+       errno = -result;
+       return -1;
+}
+
+static int oss_open(const char *file, int oflag, ...)
+{
+       int result;
+       int minor, card, device;
+       struct stat s;
+       mode_t mode;
+       va_list args;
+       va_start(args, oflag);
+       mode = va_arg(args, mode_t);
+       va_end(args);
+       result = stat(file, &s);
+       if (result < 0)
+               return RETRY;
+       if (!S_ISCHR(s.st_mode) || ((s.st_rdev >> 8) & 0xff) != OSS_MAJOR)
+               return RETRY;
+       minor = s.st_rdev & 0xff;
+       card = minor >> 4;
+       device = minor & 0x0f;
+       switch (device) {
+       case OSS_DEVICE_DSP:
+       case OSS_DEVICE_DSPW:
+       case OSS_DEVICE_AUDIO:
+       case OSS_DEVICE_ADSP:
+               return oss_dsp_open(card, device, oflag, mode);
+       default:
+               return RETRY;
+       }
+}
+
+static ssize_t oss_dsp_write(int fd, const void *buf, size_t n)
+{
+       ssize_t result;
+       oss_dsp_t *dsp = fds[fd].private;
+       oss_dsp_stream_t *str = &dsp->streams[SND_PCM_STREAM_PLAYBACK];
+       snd_pcm_t *pcm = str->pcm;
+       size_t frames;
+       if (!pcm) {
+               errno = EBADFD;
+               return -1;
+       }
+       frames = n / str->frame_bytes;
+ _again:
+       result = snd_pcm_writei(pcm, buf, frames);
+       if (result == -EPIPE && 
+           snd_pcm_state(pcm) == SND_PCM_STATE_XRUN &&
+           (result = snd_pcm_prepare(pcm)) == 0)
+               goto _again;
+       if (result < 0) {
+               errno = -result;
+               return -1;
+       }
+       result *= str->frame_bytes;
+       str->bytes += result;
+       debug("WRITE %ld %ld\n", (long)n, (long)result);
+       return result;
+}
+
+static ssize_t oss_dsp_read(int fd, void *buf, size_t n)
+{
+       ssize_t result;
+       oss_dsp_t *dsp = fds[fd].private;
+       oss_dsp_stream_t *str = &dsp->streams[SND_PCM_STREAM_CAPTURE];
+       snd_pcm_t *pcm = str->pcm;
+       size_t frames;
+       if (!pcm) {
+               errno = EBADFD;
+               return -1;
+       }
+       frames = n / str->frame_bytes;
+ _again:
+       result = snd_pcm_readi(pcm, buf, n);
+       if (result == -EPIPE && 
+           snd_pcm_state(pcm) == SND_PCM_STATE_XRUN &&
+           (result = snd_pcm_prepare(pcm)) == 0)
+               goto _again;
+       if (result < 0) {
+               errno = -result;
+               return -1;
+       }
+       result *= str->frame_bytes;
+       str->bytes += result;
+       return result;
+}
+
+static int oss_dsp_ioctl(int fd, unsigned long request, ...)
+{
+       int result, err;
+       va_list args;
+       void *arg;
+       oss_dsp_t *dsp = fds[fd].private;
+       oss_dsp_stream_t *str;
+       snd_pcm_t *pcm;
+
+       va_start(args, request);
+       arg = va_arg(args, void *);
+       va_end(args);
+       switch (request) {
+       case OSS_GETVERSION:
+               debug("OSS_GETVERSION\n");
+               *(int*)arg = SOUND_VERSION;
+               return 0;
+       case SNDCTL_DSP_RESET:
+       {
+               int k;
+               debug("SNDCTL_DSP_RESET\n");
+               result = 0;
+               for (k = 0; k < 2; ++k) {
+                       str = &dsp->streams[k];
+                       pcm = str->pcm;
+                       if (!pcm)
+                               continue;
+                       err = snd_pcm_drop(pcm);
+                       if (err >= 0)
+                               err = snd_pcm_prepare(pcm);
+                       if (err < 0)
+                               result = err;
+                       str->bytes = 0;
+               }
+               if (result < 0) {
+                       errno = -result;
+                       return -1;
+               }
+               return 0;
+       }
+       case SNDCTL_DSP_SYNC:
+       {
+               int k;
+               debug("SNDCTL_DSP_SYNC\n");
+               result = 0;
+               for (k = 0; k < 2; ++k) {
+                       str = &dsp->streams[k];
+                       pcm = str->pcm;
+                       if (!pcm)
+                               continue;
+                       err = snd_pcm_drain(pcm);
+                       if (err >= 0)
+                               err = snd_pcm_prepare(pcm);
+                       if (err < 0)
+                               result = err;
+                       
+               }
+               if (result < 0) {
+                       errno = -result;
+                       return -1;
+               }
+               return 0;
+       }
+       case SNDCTL_DSP_SPEED:
+               debug("SNDCTL_DSP_SPEED %d\n", *(int *)arg);
+               dsp->rate = *(int *)arg;
+               err = oss_dsp_params(dsp);
+               if (err < 0) {
+                       errno = -err;
+                       return -1;
+               }
+               *(int *)arg = dsp->rate;
+               return 0;
+       case SNDCTL_DSP_STEREO:
+               debug("SNDCTL_DSP_STEREO %d\n", *(int *)arg);
+               if (*(int *)arg)
+                       dsp->channels = 2;
+               else
+                       dsp->channels = 1;
+               err = oss_dsp_params(dsp);
+               if (err < 0) {
+                       errno = -err;
+                       return -1;
+               }
+               *(int *)arg = dsp->channels - 1;
+               return 0;
+       case SNDCTL_DSP_CHANNELS:
+               debug("SNDCTL_DSP_CHANNELS %d\n", *(int *)arg);
+               dsp->channels = (*(int *)arg);
+               err = oss_dsp_params(dsp);
+               if (err < 0) {
+                       errno = -err;
+                       return -1;
+               }
+               *(int *)arg = dsp->channels;
+               return 0;
+       case SNDCTL_DSP_SETFMT:
+               debug("SNDCTL_DSP_SETFMT %d\n", *(int *)arg);
+               if (*(int *)arg != AFMT_QUERY) {
+                       dsp->format = *(int *)arg;
+                       err = oss_dsp_params(dsp);
+                       if (err < 0) {
+                               errno = -err;
+                               return -1;
+                       }
+               }
+               *(int *) arg = dsp->format;
+               return 0;
+       case SNDCTL_DSP_GETBLKSIZE:
+               str = &dsp->streams[SND_PCM_STREAM_PLAYBACK];
+               if (!str->pcm)
+                       str = &dsp->streams[SND_PCM_STREAM_CAPTURE];
+               pcm = str->pcm;
+               *(int *) arg = str->fragment_size * str->frame_bytes;
+               debug("SNDCTL_DSP_GETBLKSIZE %d\n", *(int *)arg);
+               return 0;
+       case SNDCTL_DSP_POST:
+               debug("SNDCTL_DSP_POST\n");
+               return 0;
+       case SNDCTL_DSP_SUBDIVIDE:
+               debug("SNDCTL_DSP_SUBDIVIDE %d\n", *(int *)arg);
+               dsp->subdivision = *(int *)arg;
+               if (dsp->subdivision < 1)
+                       dsp->subdivision = 1;
+               err = oss_dsp_params(dsp);
+               if (err < 0) {
+                       errno = -err;
+                       return -1;
+               }
+               return 0;
+       case SNDCTL_DSP_SETFRAGMENT:
+       {
+               debug("SNDCTL_DSP_SETFRAGMENT %x\n", *(int *)arg);
+               dsp->fragshift = *(int *)arg & 0xffff;
+               if (dsp->fragshift < 4)
+                       dsp->fragshift = 4;
+               dsp->maxfrags = ((*(int *)arg) >> 16) & 0xffff;
+               if (dsp->maxfrags < 2)
+                       dsp->maxfrags = 2;
+               err = oss_dsp_params(dsp);
+               if (err < 0) {
+                       errno = -err;
+                       return -1;
+               }
+               return 0;
+       }
+       case SNDCTL_DSP_GETFMTS:
+       {
+               debug("SNDCTL_DSP_GETFMTS\n");
+               *(int *)arg = (AFMT_MU_LAW | AFMT_A_LAW | AFMT_IMA_ADPCM | 
+                              AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE | 
+                              AFMT_S8 | AFMT_U16_LE | AFMT_U16_BE);
+               return 0;
+       }
+       case SNDCTL_DSP_NONBLOCK:
+       {
+               int k;
+               debug("SNDCTL_DSP_NONBLOCK\n");
+               result = 0;
+               for (k = 0; k < 2; ++k) {
+                       pcm = dsp->streams[k].pcm;
+                       if (!pcm)
+                               continue;
+                       err = snd_pcm_nonblock(pcm, 1);
+                       if (err < 0)
+                               result = err;
+               }
+               if (result < 0) {
+                       errno = -result;
+                       return -1;
+               }
+               return 0;
+       }
+       case SNDCTL_DSP_GETCAPS:
+       {
+               debug("SNDCTL_DSP_GETCAPS\n");
+               result = DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP;
+               if (dsp->streams[SND_PCM_STREAM_PLAYBACK].pcm && 
+                   dsp->streams[SND_PCM_STREAM_CAPTURE].pcm)
+                       result |= DSP_CAP_DUPLEX;
+               *(int*)arg = result;
+               return 0;
+       }
+       case SNDCTL_DSP_GETTRIGGER:
+       {
+               int s = 0;
+               pcm = dsp->streams[SND_PCM_STREAM_PLAYBACK].pcm;
+               if (pcm) {
+                       err = snd_pcm_state(pcm);
+                       if (err == SND_PCM_STATE_RUNNING)
+                               s |= PCM_ENABLE_OUTPUT;
+               }
+               pcm = dsp->streams[SND_PCM_STREAM_CAPTURE].pcm;
+               if (pcm) {
+                       err = snd_pcm_state(pcm);
+                       if (err == SND_PCM_STATE_RUNNING)
+                               s |= PCM_ENABLE_INPUT;
+               }
+               *(int*)arg = s;
+               debug("SNDCTL_DSP_GETTRIGGER %d\n", *(int*)arg);
+               return 0;
+       }               
+       case SNDCTL_DSP_SETTRIGGER:
+       {
+               debug("SNDCTL_DSP_SETTRIGGER %d\n", *(int*)arg);
+               result = *(int*) arg;
+               str = &dsp->streams[SND_PCM_STREAM_CAPTURE];
+               pcm = str->pcm;
+               if (pcm) {
+                       if (result & PCM_ENABLE_INPUT) {
+                               str->disabled = 0;
+                               if (oss_dsp_params(dsp) >= 0 &&
+                                   snd_pcm_prepare(pcm) >= 0)
+                                       snd_pcm_start(pcm);
+                       } else {
+                               str->disabled = 1;
+                               if (snd_pcm_drop(pcm) >= 0)
+                                       oss_dsp_params(dsp);                            
+                       }
+               }
+               str = &dsp->streams[SND_PCM_STREAM_PLAYBACK];
+               pcm = str->pcm;
+               if (pcm) {
+                       if (result & PCM_ENABLE_OUTPUT) {
+                               str->disabled = 0;
+                               if (oss_dsp_params(dsp) >= 0 &&
+                                   snd_pcm_prepare(pcm) >= 0)
+                                       snd_pcm_start(pcm);
+                       } else {
+                               str->disabled = 1;
+                               if (snd_pcm_drop(pcm) >= 0)
+                                       oss_dsp_params(dsp);                            
+                       }
+               }
+               return 0;
+       }
+       case SNDCTL_DSP_GETISPACE:
+       {
+               ssize_t avail, delay;
+               audio_buf_info *info = arg;
+               str = &dsp->streams[SND_PCM_STREAM_CAPTURE];
+               pcm = str->pcm;
+               if (!pcm) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               if (snd_pcm_state(pcm) == SND_PCM_STATE_RUNNING) {
+                       err = snd_pcm_delay(pcm, &delay);
+               }
+               avail = snd_pcm_avail_update(pcm);
+               if (avail < 0)
+                       avail = 0;
+               info->fragsize = str->fragment_size * str->frame_bytes;
+               info->fragstotal = str->fragments;
+               info->bytes = avail * str->frame_bytes;
+               info->fragments = avail / str->fragment_size;
+               return 0;
+       }
+       case SNDCTL_DSP_GETOSPACE:
+       {
+               ssize_t avail, delay;
+               audio_buf_info *info = arg;
+               fprintf(stderr, "OSPACE\n");
+               str = &dsp->streams[SND_PCM_STREAM_PLAYBACK];
+               pcm = str->pcm;
+               if (!pcm) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               if (snd_pcm_state(pcm) == SND_PCM_STATE_RUNNING) {
+                       err = snd_pcm_delay(pcm, &delay);
+               }
+               avail = snd_pcm_avail_update(pcm);
+               if (avail < 0)
+                       avail = str->buffer_size;
+               info->fragsize = str->fragment_size * str->frame_bytes;
+               info->fragstotal = str->fragments;
+               info->bytes = avail * str->frame_bytes;
+               info->fragments = avail / str->fragment_size;
+               return 0;
+       }
+       case SNDCTL_DSP_GETIPTR:
+       {
+               ssize_t avail, delay;
+               size_t hw_ptr;
+               count_info *info = arg;
+               str = &dsp->streams[SND_PCM_STREAM_CAPTURE];
+               pcm = str->pcm;
+               if (!pcm) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               if (snd_pcm_state(pcm) == SND_PCM_STATE_RUNNING) {
+                       err = snd_pcm_delay(pcm, &delay);
+                       if (err < 0) {
+                               errno = -err;
+                               return -1;
+                       }
+               } else
+                       delay = 0;
+               avail = snd_pcm_avail_update(pcm);
+               if (avail < 0) {
+                       errno = -avail;
+                       return -1;
+               }
+               hw_ptr = _snd_pcm_mmap_hw_ptr(pcm);
+               /* FIXME */
+               info->bytes = hw_ptr;
+               info->bytes *= str->frame_bytes;
+               info->ptr = hw_ptr % str->buffer_size;
+               info->ptr *= str->frame_bytes;
+               if (str->mmap) {
+                       ssize_t n = (hw_ptr / str->fragment_size) - (str->old_hw_ptr / str->fragment_size);
+                       if (n < 0)
+                               n += str->boundary / str->fragment_size;
+                       info->blocks = n;
+                       str->old_hw_ptr = hw_ptr;
+               } else
+                       info->blocks = delay / str->fragment_size;
+               return 0;
+       }
+       case SNDCTL_DSP_GETOPTR:
+       {
+               ssize_t avail, delay;
+               size_t hw_ptr;
+               count_info *info = arg;
+               fprintf(stderr, "OPTR\n");
+               str = &dsp->streams[SND_PCM_STREAM_PLAYBACK];
+               pcm = str->pcm;
+               if (!pcm) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               err = snd_pcm_delay(pcm, &delay);
+               if (snd_pcm_state(pcm) == SND_PCM_STATE_RUNNING) {
+                       if (err < 0) {
+                               errno = -err;
+                               return -1;
+                       }
+               } else
+                       delay = 0;
+               avail = snd_pcm_avail_update(pcm);
+               if (avail < 0) {
+                       errno = -avail;
+                       return -1;
+               }
+               /* FIXME */
+               hw_ptr = _snd_pcm_mmap_hw_ptr(pcm);
+               info->bytes = hw_ptr;
+               info->bytes *= str->frame_bytes;
+               info->ptr = hw_ptr % str->buffer_size;
+               info->ptr *= str->frame_bytes;
+               if (str->mmap) {
+                       ssize_t n = (hw_ptr / str->fragment_size) - (str->old_hw_ptr / str->fragment_size);
+                       if (n < 0)
+                               n += str->boundary / str->fragment_size;
+                       info->blocks = n;
+                       str->old_hw_ptr = hw_ptr;
+               } else
+                       info->blocks = delay / str->fragment_size;
+               return 0;
+       }
+       case SNDCTL_DSP_GETODELAY:
+       {
+               ssize_t delay;
+               fprintf(stderr, "ODELAY\n");
+               str = &dsp->streams[SND_PCM_STREAM_PLAYBACK];
+               pcm = str->pcm;
+               if (!pcm) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               if (snd_pcm_state(pcm) != SND_PCM_STATE_RUNNING ||
+                   snd_pcm_delay(pcm, &delay) < 0)
+                       delay = 0;
+               *(int *)arg = delay * str->frame_bytes;
+               return 0;
+       }
+       case SNDCTL_DSP_SETDUPLEX:
+               return 0;
+       case SOUND_PCM_READ_RATE:
+       {
+               *(int *)arg = dsp->rate;
+               return 0;
+       }
+       case SOUND_PCM_READ_CHANNELS:
+       {
+               *(int *)arg = dsp->channels;
+               return 0;
+       }
+       case SOUND_PCM_READ_BITS:
+       {
+               *(int *)arg = snd_pcm_format_width(oss_format_to_alsa(dsp->format));
+               return 0;
+       }
+       case SNDCTL_DSP_MAPINBUF:
+       case SNDCTL_DSP_MAPOUTBUF:
+       case SNDCTL_DSP_SETSYNCRO:
+       case SOUND_PCM_READ_FILTER:
+       case SOUND_PCM_WRITE_FILTER:
+               errno = EINVAL;
+               return -1;
+       default:
+               // return oss_mixer_ioctl(...);
+               errno = ENXIO;
+               return -1;
+       }
+}
+
+static int oss_dsp_fcntl(int fd, int cmd, ...)
+{
+       int result;
+       va_list args;
+       long arg;
+
+       va_start(args, cmd);
+       arg = va_arg(args, long);
+       va_end(args);
+       result = _fcntl(fd, cmd, arg);
+       if (result < 0)
+               return result;
+       switch (cmd) {
+       case F_DUPFD:
+               fds[arg] = fds[fd];
+               return result;
+       case F_SETFL:
+               if (arg & O_NONBLOCK) {
+                       int k;
+                       int err;
+                       snd_pcm_t *pcm;
+                       oss_dsp_t *dsp = fds[fd].private;
+                       for (k = 0; k < 2; ++k) {
+                               pcm = dsp->streams[k].pcm;
+                               if (!pcm)
+                                       continue;
+                               err = snd_pcm_nonblock(pcm, 1);
+                               if (err < 0)
+                                       result = err;
+                       }
+                       if (result < 0) {
+                               errno = -result;
+                               return -1;
+                       }
+               }
+               return 0;
+       default:
+               return result;
+       }
+       return -1;
+}
+
+static void *oss_dsp_mmap(void *addr ATTRIBUTE_UNUSED, size_t len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, int fd, off_t offset ATTRIBUTE_UNUSED)
+{
+       int err;
+       const snd_pcm_channel_area_t *areas;
+       oss_dsp_t *dsp = fds[fd].private;
+       oss_dsp_stream_t *str;
+       str = &dsp->streams[SND_PCM_STREAM_PLAYBACK];
+       if (!str->pcm)
+               str = &dsp->streams[SND_PCM_STREAM_CAPTURE];
+       str->mmap = 1;
+       err = oss_dsp_params(dsp);
+       if (err < 0) {
+               errno = -err;
+               return MAP_FAILED;
+       }
+       areas = snd_pcm_mmap_areas(str->pcm);
+       return areas->addr;
+}
+
+static int oss_dsp_munmap(int fd, void *addr ATTRIBUTE_UNUSED, size_t len ATTRIBUTE_UNUSED)
+{
+       int err;
+       oss_dsp_t *dsp = fds[fd].private;
+       oss_dsp_stream_t *str;
+       str = &dsp->streams[SND_PCM_STREAM_PLAYBACK];
+       if (!str->pcm)
+               str = &dsp->streams[SND_PCM_STREAM_CAPTURE];
+       str->mmap = 0;
+       err = oss_dsp_params(dsp);
+       if (err < 0) {
+               errno = -err;
+               return -1;
+       }
+       return 0;
+}
+
+static ops_t ops[FD_CLASSES] = {
+       {
+               open: oss_open,
+               close: oss_dsp_close,
+               write: oss_dsp_write,
+               read: oss_dsp_read,
+               ioctl: oss_dsp_ioctl,
+               fcntl: oss_dsp_fcntl,
+               mmap: oss_dsp_mmap,
+               munmap: oss_dsp_munmap,
+       }
+};
+
+int open(const char *file, int oflag, ...)
+{
+       va_list args;
+       mode_t mode = 0;
+       int k;
+       int fd;
+
+       if (oflag & O_CREAT) {
+               va_start(args, oflag);
+               mode = va_arg(args, mode_t);
+               va_end(args);
+       }
+       for (k = 0; k < FD_CLASSES; ++k) {
+               if (!ops[k].open)
+                       continue;
+               fd = ops[k].open(file, oflag, mode);
+               if (fd != RETRY)
+                       goto _end;
+       }
+       fd = _open(file, oflag, mode);
+       if (fd >= 0) {
+               if (fds[fd].class != FD_CLOSED) {
+                       _close(fd);
+                       errno = EMFILE;
+                       return -1;
+               }
+               fds[fd].class = FD_DEFAULT;
+       }
+ _end:
+       return fd;
+}
+
+int close(int fd)
+{
+       int result;
+       if (fd < 0 || fd >= OPEN_MAX || fds[fd].class < 0)
+               result = _close(fd);
+       else
+               result = ops[fds[fd].class].close(fd);
+       if (result >= 0)
+               fds[fd].class = FD_CLOSED;
+       return result;
+}
+
+ssize_t write(int fd, const void *buf, size_t n)
+{
+       if (fd < 0 || fd >= OPEN_MAX || fds[fd].class < 0)
+               return _write(fd, buf, n);
+       else
+               return ops[fds[fd].class].write(fd, buf, n);
+}
+
+ssize_t read(int fd, void *buf, size_t n)
+{
+       if (fd < 0 || fd >= OPEN_MAX || fds[fd].class < 0)
+               return _read(fd, buf, n);
+       else
+               return ops[fds[fd].class].read(fd, buf, n);
+}
+
+int ioctl(int fd, unsigned long request, ...)
+{
+       va_list args;
+       void *arg;
+
+       va_start(args, request);
+       arg = va_arg(args, void *);
+       va_end(args);
+       if (fd < 0 || fd >= OPEN_MAX || fds[fd].class < 0)
+               return _ioctl(fd, request, arg);
+       else 
+               return ops[fds[fd].class].ioctl(fd, request, arg);
+}
+
+int fcntl(int fd, int cmd, ...)
+{
+       va_list args;
+       void *arg;
+
+       va_start(args, cmd);
+       arg = va_arg(args, void *);
+       va_end(args);
+       if (fd < 0 || fd >= OPEN_MAX || fds[fd].class < 0)
+               return _fcntl(fd, cmd, arg);
+       else
+               return ops[fds[fd].class].fcntl(fd, cmd, arg);
+}
+
+void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+       void *result;
+       if (fd < 0 || fd >= OPEN_MAX || fds[fd].class < 0)
+               return _mmap(addr, len, prot, flags, fd, offset);
+       result = ops[fds[fd].class].mmap(addr, len, prot, flags, fd, offset);
+       if (result != NULL && result != MAP_FAILED)
+               fds[fd].mmap_area = result;
+       return result;
+}
+
+int munmap(void *addr, size_t len)
+{
+       int fd;
+       for (fd = 0; fd < OPEN_MAX; ++fd) {
+               if (fds[fd].mmap_area == addr)
+                       break;
+       }
+       if (fd >= OPEN_MAX || fds[fd].class < 0)
+               return _munmap(addr, len);
+       else
+               return ops[fds[fd].class].munmap(fd, addr, len);
+}
+
+#ifdef DEBUG_POLL
+void dump_poll(struct pollfd *pfds, unsigned long nfds, int timeout)
+{
+       unsigned int k;
+       printf("POLL nfds: %ld, timeout: %d\n", nfds, timeout);
+       for (k = 0; k < nfds; ++k) {
+               printf("fd=%d, events=%x, revents=%x\n", 
+                      pfds[k].fd, pfds[k].events, pfds[k].revents);
+       }
+}
+#endif
+
+#ifdef DEBUG_SELECT
+void dump_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds,
+                struct timeval *timeout)
+{
+       int k;
+       printf("SELECT nfds: %d, ", nfds);
+       if (timeout)
+               printf("timeout: %ld.%06ld\n", timeout->tv_sec, timeout->tv_usec);
+       else
+               printf("no timeout\n");
+       if (rfds) {
+               printf("rfds: ");
+               for (k = 0; k < nfds; ++k) {
+                       if (FD_ISSET(k, rfds))
+                               putchar('1');
+                       else
+                               putchar('0');
+               }
+               putchar('\n');
+       }
+       if (wfds) {
+               printf("wfds: ");
+               for (k = 0; k < nfds; ++k) {
+                       if (FD_ISSET(k, wfds))
+                               putchar('1');
+                       else
+                               putchar('0');
+               }
+               putchar('\n');
+       }
+       if (efds) {
+               printf("efds: ");
+               for (k = 0; k < nfds; ++k) {
+                       if (FD_ISSET(k, efds))
+                               putchar('1');
+                       else
+                               putchar('0');
+               }
+               putchar('\n');
+       }
+}
+#endif
+
+int poll(struct pollfd *pfds, unsigned long nfds, int timeout)
+{
+       unsigned int k;
+       unsigned int nfds1;
+       int count, count1;
+       int direct = 1;
+       struct pollfd pfds1[nfds * 2];
+       nfds1 = 0;
+       for (k = 0; k < nfds; ++k) {
+               int fd = pfds[k].fd;
+               pfds[k].revents = 0;
+               if (fd >= OPEN_MAX)
+                       goto _std1;
+               switch (fds[fd].class) {
+               case FD_OSS_DSP:
+               {
+                       oss_dsp_t *dsp = fds[fd].private;
+                       oss_dsp_stream_t *str;
+                       int j;
+                       for (j = 0; j < 2; ++j) {
+                               str = &dsp->streams[j];
+                               if (str->pcm) {
+                                       pfds1[nfds1].fd = snd_pcm_poll_descriptor(str->pcm);
+                                       pfds1[nfds1].events = pfds[k].events;
+                                       pfds1[nfds1].revents = 0;
+                                       nfds1++;
+                               }
+                       }
+                       direct = 0;
+                       break;
+               }
+               default:
+               _std1:
+                       pfds1[nfds1].fd = pfds[k].fd;
+                       pfds1[nfds1].events = pfds[k].events;
+                       pfds1[nfds1].revents = 0;
+                       nfds1++;
+                       break;
+               }
+       }
+       if (direct)
+               return _poll(pfds, nfds, timeout);
+#ifdef DEBUG_POLL
+       printf("Orig enter ");
+       dump_poll(pfds, nfds, timeout);
+       printf("Changed enter ");
+       dump_poll(pfds1, nfds1, timeout);
+#endif
+       count = _poll(pfds1, nfds1, timeout);
+       if (count <= 0)
+               return count;
+       nfds1 = 0;
+       count1 = 0;
+       for (k = 0; k < nfds; ++k) {
+               int fd = pfds[k].fd;
+               unsigned int revents;
+               if (fd >= OPEN_MAX)
+                       goto _std2;
+               switch (fds[fd].class) {
+               case FD_OSS_DSP:
+               {
+                       oss_dsp_t *dsp = fds[fd].private;
+                       oss_dsp_stream_t *str;
+                       int j;
+                       revents = 0;
+                       for (j = 0; j < 2; ++j) {
+                               str = &dsp->streams[j];
+                               if (str->pcm) {
+                                       revents |= pfds1[nfds1].revents;
+                                       nfds1++;
+                               }
+                       }
+                       break;
+               }
+               default:
+               _std2:
+                       revents = pfds1[nfds1].revents;
+                       nfds1++;
+                       break;
+               }
+               pfds[k].revents = revents;
+               if (revents)
+                       count1++;
+       }
+#ifdef DEBUG_POLL
+       printf("Changed exit ");
+       dump_poll(pfds1, nfds1, timeout);
+       printf("Orig exit ");
+       dump_poll(pfds, nfds, timeout);
+#endif
+       return count1;
+}
+
+int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds,
+          struct timeval *timeout)
+{
+       fd_set _rfds1, _wfds1, _efds1;
+       fd_set *rfds1, *wfds1, *efds1;
+       int nfds1 = nfds;
+       int count, count1;
+       int fd;
+       int direct = 1;
+       if (rfds) {
+               _rfds1 = *rfds;
+               rfds1 = &_rfds1;
+       } else
+               rfds1 = NULL;
+       if (wfds) {
+               _wfds1 = *wfds;
+               wfds1 = &_wfds1;
+       } else
+               wfds1 = NULL;
+       if (efds) {
+               _efds1 = *efds;
+               efds1 = &_efds1;
+       } else
+               efds1 = NULL;
+       for (fd = 0; fd < nfds; ++fd) {
+               int r = (rfds && FD_ISSET(fd, rfds));
+               int w = (wfds && FD_ISSET(fd, wfds));
+               int e = (efds && FD_ISSET(fd, efds));
+               if (!(r || w || e))
+                       continue;
+               switch (fds[fd].class) {
+               case FD_OSS_DSP:
+               {
+                       oss_dsp_t *dsp = fds[fd].private;
+                       oss_dsp_stream_t *str;
+                       int j;
+                       if (r)
+                               FD_CLR(fd, rfds1);
+                       if (w)
+                               FD_CLR(fd, wfds1);
+                       if (e)
+                               FD_CLR(fd, efds1);
+                       for (j = 0; j < 2; ++j) {
+                               str = &dsp->streams[j];
+                               if (str->pcm) {
+                                       int fd1 = snd_pcm_poll_descriptor(str->pcm);
+                                       if (fd1 >= nfds1)
+                                               nfds1 = fd1 + 1;
+                                       if (r)
+                                               FD_SET(fd1, rfds1);
+                                       if (w)
+                                               FD_SET(fd1, wfds1);
+                                       if (e)
+                                               FD_SET(fd1, efds1);
+                               }
+                       }
+                       direct = 0;
+                       break;
+               }
+               default:
+                       break;
+               }
+       }
+       if (direct)
+               return _select(nfds, rfds, wfds, efds, timeout);
+#ifdef DEBUG_SELECT
+       printf("Orig enter ");
+       dump_select(nfds, rfds, wfds, efds, timeout);
+       printf("Changed enter ");
+       dump_select(nfds1, rfds1, wfds1, efds1, timeout);
+#endif
+       count = _select(nfds1, rfds1, wfds1, efds1, timeout);
+       if (count < 0)
+               return count;
+       if (count == 0) {
+               if (rfds)
+                       FD_ZERO(rfds);
+               if (wfds)
+                       FD_ZERO(wfds);
+               if (efds)
+                       FD_ZERO(efds);
+               return 0;
+       }
+       count1 = 0;
+       for (fd = 0; fd < nfds; ++fd) {
+               int r = (rfds && FD_ISSET(fd, rfds));
+               int w = (wfds && FD_ISSET(fd, wfds));
+               int e = (efds && FD_ISSET(fd, efds));
+               int r1, w1, e1;
+               if (!(r || w || e))
+                       continue;
+               switch (fds[fd].class) {
+               case FD_OSS_DSP:
+               {
+                       oss_dsp_t *dsp = fds[fd].private;
+                       oss_dsp_stream_t *str;
+                       int j;
+                       r1 = w1 = e1 = 0;
+                       for (j = 0; j < 2; ++j) {
+                               str = &dsp->streams[j];
+                               if (str->pcm) {
+                                       int fd1 = snd_pcm_poll_descriptor(str->pcm);
+                                       if (r && FD_ISSET(fd1, rfds1))
+                                               r1++;
+                                       if (w && FD_ISSET(fd1, wfds1))
+                                               w1++;
+                                       if (e && FD_ISSET(fd1, efds1))
+                                               e1++;
+#if 1
+                               {
+                                 size_t delay;
+                                 snd_pcm_delay(str->pcm, &delay);
+                                 fprintf(stderr, "%d %d %d\n", delay, str->buffer_size, str->fragment_size);
+                               }
+#endif
+                               }
+                       }
+                       break;
+               }
+               default:
+                       r1 = (r && FD_ISSET(fd, rfds1));
+                       w1 = (w && FD_ISSET(fd, wfds1));
+                       e1 = (e && FD_ISSET(fd, efds1));
+                       break;
+               }
+               if (r && !r1)
+                       FD_CLR(fd, rfds);
+               if (w && !w1)
+                       FD_CLR(fd, wfds);
+               if (e && !e1)
+                       FD_CLR(fd, efds);
+               if (r1 || w1 || e1)
+                       count1++;
+       }
+#ifdef DEBUG_SELECT
+       printf("Changed exit ");
+       dump_select(nfds1, rfds1, wfds1, efds1, timeout);
+       printf("Orig exit ");
+       dump_select(nfds, rfds, wfds, efds, timeout);
+#endif
+       return count1;
+}
+
+
+int dup(int fd)
+{
+       return fcntl(fd, F_DUPFD, 0);
+}
+
+int dup2(int fd, int fd2)
+{
+       int save;
+
+       if (fd2 < 0 || fd2 >= OPEN_MAX) {
+               errno = EBADF;
+               return -1;
+       }
+       
+       if (fcntl(fd, F_GETFL) < 0)
+               return -1;
+       
+       if (fd == fd2)
+               return fd2;
+       
+       save = errno;
+       close(fd2);
+       errno = save;
+       
+       return fcntl(fd, F_DUPFD, fd2);
+}
+
+#ifndef O_LARGEFILE
+#define O_LARGEFILE 0100000
+#endif
+
+int open64(const char *file, int oflag, ...)
+{
+       va_list args;
+       mode_t mode = 0;
+
+       if (oflag & O_CREAT) {
+               va_start(args, oflag);
+               mode = va_arg(args, mode_t);
+               va_end(args);
+       }
+       return open(file, oflag | O_LARGEFILE, mode);
+}
+
+static void initialize() __attribute__ ((constructor));
+
+static void initialize()
+{
+       int k;
+       _open = dlsym(RTLD_NEXT, "open");
+       _close = dlsym(RTLD_NEXT, "close");
+       _write = dlsym(RTLD_NEXT, "write");
+       _read = dlsym(RTLD_NEXT, "read");
+       _ioctl = dlsym(RTLD_NEXT, "ioctl");
+       _fcntl = dlsym(RTLD_NEXT, "fcntl");
+       _mmap = dlsym(RTLD_NEXT, "mmap");
+       _munmap = dlsym(RTLD_NEXT, "munmap");
+       _select = dlsym(RTLD_NEXT, "select");
+       _poll = dlsym(RTLD_NEXT, "poll");
+       for (k = 0; k < OPEN_MAX; ++k) {
+               fds[k].private = 0;
+               if (_fcntl(k, F_GETFL) < 0)
+                       fds[k].class = FD_CLOSED;
+               else
+                       fds[k].class = FD_DEFAULT;
+       }
+}
+
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..3ed9bb4
--- /dev/null
@@ -0,0 +1,9 @@
+AC_INIT(alsa-oss.c)
+AM_INIT_AUTOMAKE(alsa-oss, 0.6)
+
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S 
+AM_PROG_LIBTOOL
+
+AC_OUTPUT(Makefile)
diff --git a/cvscompile b/cvscompile
new file mode 100644 (file)
index 0000000..aa130d4
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+aclocal $ACLOCAL_FLAGS
+automake --foreign --add-missing
+autoconf
+export CFLAGS='-O2 -Wall -W -pipe -g'
+echo "CFLAGS=$CFLAGS"
+echo "./configure $@"
+./configure $@
+unset CFLAGS
+make