Merge branch 'for-2.6.29' of git://linux-nfs.org/~bfields/linux
[safe/jmp/linux-2.6] / sound / core / oss / pcm_oss.c
index fc11572..699d289 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Digital Audio (PCM) abstract layer / OSS compatible
- *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  *
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,6 @@
 #define OSS_DEBUG
 #endif
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
@@ -48,7 +47,7 @@ static int dsp_map[SNDRV_CARDS];
 static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
 static int nonblock_open = 1;
 
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Abramo Bagnara <abramo@alsa-project.org>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");
 MODULE_DESCRIPTION("PCM OSS emulation for ALSA.");
 MODULE_LICENSE("GPL");
 module_param_array(dsp_map, int, NULL, 0444);
@@ -453,7 +452,8 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
        } else {
                *params = *save;
                max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
-               snd_assert(max >= 0, return -EINVAL);
+               if (max < 0)
+                       return max;
                last = 1;
        }
  _end:
@@ -462,7 +462,7 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
                v = snd_pcm_hw_param_last(pcm, params, var, dir);
        else
                v = snd_pcm_hw_param_first(pcm, params, var, dir);
-       snd_assert(v >= 0, return -EINVAL);
+       snd_BUG_ON(v < 0);
        return v;
 }
 
@@ -633,6 +633,22 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes)
        return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
 }
 
+/* define extended formats in the recent OSS versions (if any) */
+/* linear formats */
+#define AFMT_S32_LE      0x00001000
+#define AFMT_S32_BE      0x00002000
+#define AFMT_S24_LE      0x00008000
+#define AFMT_S24_BE      0x00010000
+#define AFMT_S24_PACKED  0x00040000
+
+/* other supported formats */
+#define AFMT_FLOAT       0x00004000
+#define AFMT_SPDIF_RAW   0x00020000
+
+/* unsupported formats */
+#define AFMT_AC3         0x00000400
+#define AFMT_VORBIS      0x00000800
+
 static int snd_pcm_oss_format_from(int format)
 {
        switch (format) {
@@ -646,6 +662,13 @@ static int snd_pcm_oss_format_from(int format)
        case AFMT_U16_LE:       return SNDRV_PCM_FORMAT_U16_LE;
        case AFMT_U16_BE:       return SNDRV_PCM_FORMAT_U16_BE;
        case AFMT_MPEG:         return SNDRV_PCM_FORMAT_MPEG;
+       case AFMT_S32_LE:       return SNDRV_PCM_FORMAT_S32_LE;
+       case AFMT_S32_BE:       return SNDRV_PCM_FORMAT_S32_BE;
+       case AFMT_S24_LE:       return SNDRV_PCM_FORMAT_S24_LE;
+       case AFMT_S24_BE:       return SNDRV_PCM_FORMAT_S24_BE;
+       case AFMT_S24_PACKED:   return SNDRV_PCM_FORMAT_S24_3LE;
+       case AFMT_FLOAT:        return SNDRV_PCM_FORMAT_FLOAT;
+       case AFMT_SPDIF_RAW:    return SNDRV_PCM_FORMAT_IEC958_SUBFRAME;
        default:                return SNDRV_PCM_FORMAT_U8;
        }
 }
@@ -663,6 +686,13 @@ static int snd_pcm_oss_format_to(int format)
        case SNDRV_PCM_FORMAT_U16_LE:   return AFMT_U16_LE;
        case SNDRV_PCM_FORMAT_U16_BE:   return AFMT_U16_BE;
        case SNDRV_PCM_FORMAT_MPEG:             return AFMT_MPEG;
+       case SNDRV_PCM_FORMAT_S32_LE:   return AFMT_S32_LE;
+       case SNDRV_PCM_FORMAT_S32_BE:   return AFMT_S32_BE;
+       case SNDRV_PCM_FORMAT_S24_LE:   return AFMT_S24_LE;
+       case SNDRV_PCM_FORMAT_S24_BE:   return AFMT_S24_BE;
+       case SNDRV_PCM_FORMAT_S24_3LE:  return AFMT_S24_PACKED;
+       case SNDRV_PCM_FORMAT_FLOAT:    return AFMT_FLOAT;
+       case SNDRV_PCM_FORMAT_IEC958_SUBFRAME: return AFMT_SPDIF_RAW;
        default:                        return -EINVAL;
        }
 }
@@ -749,7 +779,8 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
        while (oss_period_size * oss_periods > oss_buffer_size)
                oss_period_size /= 2;
 
-       snd_assert(oss_period_size >= 16, return -EINVAL);
+       if (oss_period_size < 16)
+               return -EINVAL;
        runtime->oss.period_bytes = oss_period_size;
        runtime->oss.period_frames = 1;
        runtime->oss.periods = oss_periods;
@@ -866,7 +897,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
                }
        }
        err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);
-       snd_assert(err >= 0, goto failure);
+       if (err < 0)
+               goto failure;
 
        if (direct) {
                memcpy(params, sparams, sizeof(*params));
@@ -929,11 +961,13 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
 
        n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);
        err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL);
-       snd_assert(err >= 0, goto failure);
+       if (err < 0)
+               goto failure;
 
        err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,
                                     runtime->oss.periods, NULL);
-       snd_assert(err >= 0, goto failure);
+       if (err < 0)
+               goto failure;
 
        snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
 
@@ -955,10 +989,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
                sw_params->stop_threshold = runtime->buffer_size;
        sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
        sw_params->period_step = 1;
-       sw_params->sleep_min = 0;
        sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
                1 : runtime->period_size;
-       sw_params->xfer_align = 1;
        if (atomic_read(&substream->mmap_count) ||
            substream->oss.setup.nosilence) {
                sw_params->silence_threshold = 0;
@@ -979,7 +1011,10 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
 
        runtime->oss.periods = params_periods(sparams);
        oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
-       snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);
+       if (oss_period_size < 0) {
+               err = -EINVAL;
+               goto failure;
+       }
 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
        if (runtime->oss.plugin_first) {
                err = snd_pcm_plug_alloc(substream, oss_period_size);
@@ -990,7 +1025,10 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        oss_period_size *= oss_frame_size;
 
        oss_buffer_size = oss_period_size * runtime->oss.periods;
-       snd_assert(oss_buffer_size >= 0, err = -EINVAL; goto failure);
+       if (oss_buffer_size < 0) {
+               err = -EINVAL;
+               goto failure;
+       }
 
        runtime->oss.period_bytes = oss_period_size;
        runtime->oss.buffer_bytes = oss_buffer_size;
@@ -1042,7 +1080,8 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil
                                return err;
                }
        }
-       snd_assert(asubstream != NULL, return -EIO);
+       if (!asubstream)
+               return -EIO;
        if (r_substream)
                *r_substream = asubstream;
        return 0;
@@ -1594,6 +1633,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
                                        snd_pcm_format_set_silence(runtime->format,
                                                                   runtime->oss.buffer,
                                                                   size1);
+                                       size1 /= runtime->channels; /* frames */
                                        fs = snd_enter_user();
                                        snd_pcm_lib_write(substream, (void __user *)runtime->oss.buffer, size1);
                                        snd_leave_user(fs);
@@ -1725,7 +1765,10 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
                return AFMT_MU_LAW | AFMT_U8 |
                       AFMT_S16_LE | AFMT_S16_BE |
                       AFMT_S8 | AFMT_U16_LE |
-                      AFMT_U16_BE;
+                      AFMT_U16_BE |
+                       AFMT_S32_LE | AFMT_S32_BE |
+                       AFMT_S24_LE | AFMT_S24_BE |
+                       AFMT_S24_PACKED;
        params = kmalloc(sizeof(*params), GFP_KERNEL);
        if (!params)
                return -ENOMEM;
@@ -1733,7 +1776,8 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
        err = snd_pcm_hw_refine(substream, params);
        format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 
        kfree(params);
-       snd_assert(err >= 0, return err);
+       if (err < 0)
+               return err;
        for (fmt = 0; fmt < 32; ++fmt) {
                if (snd_mask_test(&format_mask, fmt)) {
                        int f = snd_pcm_oss_format_to(fmt);
@@ -2219,7 +2263,8 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
 static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
 {
        int cidx;
-       snd_assert(pcm_oss_file != NULL, return -ENXIO);
+       if (!pcm_oss_file)
+               return 0;
        for (cidx = 0; cidx < 2; ++cidx) {
                struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx];
                if (substream)
@@ -2238,10 +2283,10 @@ static int snd_pcm_oss_open_file(struct file *file,
        int idx, err;
        struct snd_pcm_oss_file *pcm_oss_file;
        struct snd_pcm_substream *substream;
-       unsigned int f_mode = file->f_mode;
+       fmode_t f_mode = file->f_mode;
 
-       snd_assert(rpcm_oss_file != NULL, return -EINVAL);
-       *rpcm_oss_file = NULL;
+       if (rpcm_oss_file)
+               *rpcm_oss_file = NULL;
 
        pcm_oss_file = kzalloc(sizeof(*pcm_oss_file), GFP_KERNEL);
        if (pcm_oss_file == NULL)
@@ -2281,7 +2326,8 @@ static int snd_pcm_oss_open_file(struct file *file,
        }
 
        file->private_data = pcm_oss_file;
-       *rpcm_oss_file = pcm_oss_file;
+       if (rpcm_oss_file)
+               *rpcm_oss_file = pcm_oss_file;
        return 0;
 }
 
@@ -2290,7 +2336,8 @@ static int snd_task_name(struct task_struct *task, char *name, size_t size)
 {
        unsigned int idx;
 
-       snd_assert(task != NULL && name != NULL && size >= 2, return -EINVAL);
+       if (snd_BUG_ON(!task || !name || size < 2))
+               return -EINVAL;
        for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++)
                name[idx] = task->comm[idx];
        name[idx] = '\0';
@@ -2384,7 +2431,8 @@ static int snd_pcm_oss_release(struct inode *inode, struct file *file)
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
        if (substream == NULL)
                substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
-       snd_assert(substream != NULL, return -ENXIO);
+       if (snd_BUG_ON(!substream))
+               return -ENXIO;
        pcm = substream->pcm;
        if (!pcm->card->shutdown)
                snd_pcm_oss_sync(pcm_oss_file);
@@ -2417,7 +2465,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
                        if (substream != NULL)
                                break;
                }
-               snd_assert(substream != NULL, return -ENXIO);
+               if (snd_BUG_ON(idx >= 2))
+                       return -ENXIO;
                return snd_mixer_oss_ioctl_card(substream->pcm->card, cmd, arg);
        }
 #endif
@@ -2823,7 +2872,7 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
                        setup = kmalloc(sizeof(*setup), GFP_KERNEL);
                        if (! setup) {
                                buffer->error = -ENOMEM;
-                               mutex_lock(&pstr->oss.setup_mutex);
+                               mutex_unlock(&pstr->oss.setup_mutex);
                                return;
                        }
                        if (pstr->oss.setup_list == NULL)
@@ -2837,7 +2886,7 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
                        if (! template.task_name) {
                                kfree(setup);
                                buffer->error = -ENOMEM;
-                               mutex_lock(&pstr->oss.setup_mutex);
+                               mutex_unlock(&pstr->oss.setup_mutex);
                                return;
                        }
                }