/*
* 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
#define OSS_DEBUG
#endif
-#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
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);
} 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:
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;
}
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) {
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;
}
}
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;
}
}
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;
}
}
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));
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);
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;
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);
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;
return err;
}
}
- snd_assert(asubstream != NULL, return -EIO);
+ if (!asubstream)
+ return -EIO;
if (r_substream)
*r_substream = asubstream;
return 0;
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);
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_LE |
+ AFMT_S24_PACKED;
params = kmalloc(sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
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);
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)
struct snd_pcm_substream *substream;
unsigned int 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)
}
file->private_data = pcm_oss_file;
- *rpcm_oss_file = pcm_oss_file;
+ if (rpcm_oss_file)
+ *rpcm_oss_file = pcm_oss_file;
return 0;
}
{
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';
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);
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