/** * snd_pcm_hw_param_value_min * @params: the hw_params instance * @var: parameter to retrieve * @dir: pointer to the direction (-1,0,1) or NULL * * Return the minimum value for field PAR.
*/ staticunsignedint
snd_pcm_hw_param_value_min(conststruct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, int *dir)
{ if (hw_is_mask(var)) { if (dir)
*dir = 0; return snd_mask_min(hw_param_mask_c(params, var));
} if (hw_is_interval(var)) { conststruct snd_interval *i = hw_param_interval_c(params, var); if (dir)
*dir = i->openmin; return snd_interval_min(i);
} return -EINVAL;
}
/** * snd_pcm_hw_param_value_max * @params: the hw_params instance * @var: parameter to retrieve * @dir: pointer to the direction (-1,0,1) or NULL * * Return the maximum value for field PAR.
*/ staticint
snd_pcm_hw_param_value_max(conststruct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, int *dir)
{ if (hw_is_mask(var)) { if (dir)
*dir = 0; return snd_mask_max(hw_param_mask_c(params, var));
} if (hw_is_interval(var)) { conststruct snd_interval *i = hw_param_interval_c(params, var); if (dir)
*dir = - (int) i->openmax; return snd_interval_max(i);
} return -EINVAL;
}
staticint snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, conststruct snd_mask *val)
{ int changed = _snd_pcm_hw_param_mask(params, var, val); if (changed < 0) return changed; if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); if (err < 0) return err;
} return 0;
}
staticint _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, unsignedint val, int dir)
{ int changed; int open = 0; if (dir) { if (dir > 0) {
open = 1;
} elseif (dir < 0) { if (val > 0) {
open = 1;
val--;
}
}
} if (hw_is_mask(var))
changed = snd_mask_refine_min(hw_param_mask(params, var),
val + !!open); elseif (hw_is_interval(var))
changed = snd_interval_refine_min(hw_param_interval(params, var),
val, open); else return -EINVAL; if (changed > 0) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
} return changed;
}
/** * snd_pcm_hw_param_min * @pcm: PCM instance * @params: the hw_params instance * @var: parameter to retrieve * @val: minimal value * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS remove from PAR all * values < VAL. Reduce configuration space accordingly. * Return new minimum or -EINVAL if the configuration space is empty
*/ staticint snd_pcm_hw_param_min(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, unsignedint val, int *dir)
{ int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0); if (changed < 0) return changed; if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); if (err < 0) return err;
} return snd_pcm_hw_param_value_min(params, var, dir);
}
staticint _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, unsignedint val, int dir)
{ int changed; int open = 0; if (dir) { if (dir < 0) {
open = 1;
} elseif (dir > 0) {
open = 1;
val++;
}
} if (hw_is_mask(var)) { if (val == 0 && open) {
snd_mask_none(hw_param_mask(params, var));
changed = -EINVAL;
} else
changed = snd_mask_refine_max(hw_param_mask(params, var),
val - !!open);
} elseif (hw_is_interval(var))
changed = snd_interval_refine_max(hw_param_interval(params, var),
val, open); else return -EINVAL; if (changed > 0) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
} return changed;
}
/** * snd_pcm_hw_param_max * @pcm: PCM instance * @params: the hw_params instance * @var: parameter to retrieve * @val: maximal value * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS remove from PAR all * values >= VAL + 1. Reduce configuration space accordingly. * Return new maximum or -EINVAL if the configuration space is empty
*/ staticint snd_pcm_hw_param_max(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, unsignedint val, int *dir)
{ int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0); if (changed < 0) return changed; if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); if (err < 0) return err;
} return snd_pcm_hw_param_value_max(params, var, dir);
}
staticint boundary_sub(int a, int adir, int b, int bdir, int *c, int *cdir)
{
adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
*c = a - b;
*cdir = adir - bdir; if (*cdir == -2) {
(*c)--;
} elseif (*cdir == 2) {
(*c)++;
} return 0;
}
staticint boundary_lt(unsignedint a, int adir, unsignedint b, int bdir)
{ if (adir < 0) {
a--;
adir = 1;
} elseif (adir > 0)
adir = 1; if (bdir < 0) {
b--;
bdir = 1;
} elseif (bdir > 0)
bdir = 1; return a < b || (a == b && adir < bdir);
}
/* Return 1 if min is nearer to best than max */ staticint boundary_nearer(int min, int mindir, int best, int bestdir, int max, int maxdir)
{ int dmin, dmindir; int dmax, dmaxdir;
boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir); return boundary_lt(dmin, dmindir, dmax, dmaxdir);
}
/** * snd_pcm_hw_param_near * @pcm: PCM instance * @params: the hw_params instance * @var: parameter to retrieve * @best: value to set * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS set PAR to the available value * nearest to VAL. Reduce configuration space accordingly. * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS, * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT. * Return the value found.
*/ staticint snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, unsignedint best, int *dir)
{ struct snd_pcm_hw_params *save __free(kfree) = NULL; int v; unsignedint saved_min; int last = 0; int min, max; int mindir, maxdir; int valdir = dir ? *dir : 0; /* FIXME */ if (best > INT_MAX)
best = INT_MAX;
min = max = best;
mindir = maxdir = valdir; if (maxdir > 0)
maxdir = 0; elseif (maxdir == 0)
maxdir = -1; else {
maxdir = 1;
max--;
}
save = kmalloc(sizeof(*save), GFP_KERNEL); if (save == NULL) return -ENOMEM;
*save = *params;
saved_min = min;
min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir); if (min >= 0) { struct snd_pcm_hw_params *params1 __free(kfree) = NULL; if (max < 0) goto _end; if ((unsignedint)min == saved_min && mindir == valdir) goto _end;
params1 = kmalloc(sizeof(*params1), GFP_KERNEL); if (params1 == NULL) return -ENOMEM;
*params1 = *save;
max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir); if (max < 0) goto _end; if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
*params = *params1;
last = 1;
}
} else {
*params = *save;
max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir); if (max < 0) return max;
last = 1;
}
_end: if (last)
v = snd_pcm_hw_param_last(pcm, params, var, dir); else
v = snd_pcm_hw_param_first(pcm, params, var, dir); return v;
}
/** * snd_pcm_hw_param_set * @pcm: PCM instance * @params: the hw_params instance * @var: parameter to retrieve * @val: value to set * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS remove from PAR all * values != VAL. Reduce configuration space accordingly. * Return VAL or -EINVAL if the configuration space is empty
*/ staticint snd_pcm_hw_param_set(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, unsignedint val, int dir)
{ int changed = _snd_pcm_hw_param_set(params, var, val, dir); if (changed < 0) return changed; if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); if (err < 0) return err;
} return snd_pcm_hw_param_value(params, var, NULL);
}
static snd_pcm_format_t snd_pcm_oss_format_from(int format)
{ switch (format) { case AFMT_MU_LAW: return SNDRV_PCM_FORMAT_MU_LAW; case AFMT_A_LAW: return SNDRV_PCM_FORMAT_A_LAW; case AFMT_IMA_ADPCM: return SNDRV_PCM_FORMAT_IMA_ADPCM; case AFMT_U8: return SNDRV_PCM_FORMAT_U8; case AFMT_S16_LE: return SNDRV_PCM_FORMAT_S16_LE; case AFMT_S16_BE: return SNDRV_PCM_FORMAT_S16_BE; case AFMT_S8: return SNDRV_PCM_FORMAT_S8; 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;
}
}
staticint snd_pcm_oss_format_to(snd_pcm_format_t format)
{ switch (format) { case SNDRV_PCM_FORMAT_MU_LAW: return AFMT_MU_LAW; case SNDRV_PCM_FORMAT_A_LAW: return AFMT_A_LAW; case SNDRV_PCM_FORMAT_IMA_ADPCM: return AFMT_IMA_ADPCM; case SNDRV_PCM_FORMAT_U8: return AFMT_U8; case SNDRV_PCM_FORMAT_S16_LE: return AFMT_S16_LE; case SNDRV_PCM_FORMAT_S16_BE: return AFMT_S16_BE; case SNDRV_PCM_FORMAT_S8: return AFMT_S8; 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;
}
}
if (substream->oss.setup.periods > 1)
oss_periods = substream->oss.setup.periods;
s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL); if (s > 0 && runtime->oss.maxfrags && s > runtime->oss.maxfrags)
s = runtime->oss.maxfrags; if (oss_periods > s)
oss_periods = s;
s = snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL); if (s < 2)
s = 2; if (oss_periods < s)
oss_periods = s;
while (oss_period_size * oss_periods > oss_buffer_size)
oss_period_size /= 2;
if (oss_period_size < 16) return -EINVAL;
/* don't allocate too large period; 1MB period must be enough */ if (oss_period_size > 1024 * 1024) return -ENOMEM;
/* this one takes the lock by itself */ staticint snd_pcm_oss_change_params(struct snd_pcm_substream *substream, bool trylock)
{ struct snd_pcm_runtime *runtime = substream->runtime; int err;
if (trylock) { if (!(mutex_trylock(&runtime->oss.params_lock))) return -EAGAIN;
} elseif (mutex_lock_interruptible(&runtime->oss.params_lock)) return -ERESTARTSYS;
for (idx = 0; idx < 2; idx++) {
substream = pcm_oss_file->streams[idx]; if (substream == NULL) continue; if (asubstream == NULL)
asubstream = substream; if (substream->runtime->oss.params) {
err = snd_pcm_oss_change_params(substream, false); if (err < 0) return err;
}
} if (!asubstream) return -EIO; if (r_substream)
*r_substream = asubstream; return 0;
}
/* call with params_lock held */ /* NOTE: this always call PREPARE unconditionally no matter whether * runtime->oss.prepare is set or not
*/ staticint snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
{ int err; struct snd_pcm_runtime *runtime = substream->runtime;
while (1) {
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, delay); if (err < 0) break;
runtime = substream->runtime; if (*delay <= (snd_pcm_sframes_t)runtime->buffer_size) break; /* in case of overrun, skip whole periods like OSS/Linux driver does */ /* until avail(delay) <= buffer_size */
frames = (*delay - runtime->buffer_size) + runtime->period_size - 1;
frames /= runtime->period_size;
frames *= runtime->period_size;
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_FORWARD, &frames); if (err < 0) break;
} return err;
}
snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, constchar *ptr, snd_pcm_uframes_t frames, int in_kernel)
{ struct snd_pcm_runtime *runtime = substream->runtime; int ret; while (1) { if (runtime->state == SNDRV_PCM_STATE_XRUN ||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) { #ifdef OSS_DEBUG
pcm_dbg(substream->pcm, "pcm_oss: write: recovering from %s\n",
runtime->state == SNDRV_PCM_STATE_XRUN ? "XRUN" : "SUSPEND"); #endif
ret = snd_pcm_oss_prepare(substream); if (ret < 0) break;
}
mutex_unlock(&runtime->oss.params_lock);
ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true,
frames, in_kernel);
mutex_lock(&runtime->oss.params_lock); if (ret != -EPIPE && ret != -ESTRPIPE) break; /* test, if we can't store new data, because the stream */ /* has not been started */ if (runtime->state == SNDRV_PCM_STATE_PREPARED) return -EAGAIN;
} return ret;
}
snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
{ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t delay; int ret; while (1) { if (runtime->state == SNDRV_PCM_STATE_XRUN ||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) { #ifdef OSS_DEBUG
pcm_dbg(substream->pcm, "pcm_oss: read: recovering from %s\n",
runtime->state == SNDRV_PCM_STATE_XRUN ? "XRUN" : "SUSPEND"); #endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); if (ret < 0) break;
} elseif (runtime->state == SNDRV_PCM_STATE_SETUP) {
ret = snd_pcm_oss_prepare(substream); if (ret < 0) break;
}
ret = snd_pcm_oss_capture_position_fixup(substream, &delay); if (ret < 0) break;
mutex_unlock(&runtime->oss.params_lock);
ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true,
frames, in_kernel);
mutex_lock(&runtime->oss.params_lock); if (ret == -EPIPE) { if (runtime->state == SNDRV_PCM_STATE_DRAINING) {
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if (ret < 0) break;
} continue;
} if (ret != -ESTRPIPE) break;
} return ret;
}
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
{ struct snd_pcm_runtime *runtime = substream->runtime; int ret; while (1) { if (runtime->state == SNDRV_PCM_STATE_XRUN ||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) { #ifdef OSS_DEBUG
pcm_dbg(substream->pcm, "pcm_oss: writev: recovering from %s\n",
runtime->state == SNDRV_PCM_STATE_XRUN ? "XRUN" : "SUSPEND"); #endif
ret = snd_pcm_oss_prepare(substream); if (ret < 0) break;
}
ret = snd_pcm_kernel_writev(substream, bufs, frames); if (ret != -EPIPE && ret != -ESTRPIPE) break;
/* test, if we can't store new data, because the stream */ /* has not been started */ if (runtime->state == SNDRV_PCM_STATE_PREPARED) return -EAGAIN;
} return ret;
}
snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
{ struct snd_pcm_runtime *runtime = substream->runtime; int ret; while (1) { if (runtime->state == SNDRV_PCM_STATE_XRUN ||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) { #ifdef OSS_DEBUG
pcm_dbg(substream->pcm, "pcm_oss: readv: recovering from %s\n",
runtime->state == SNDRV_PCM_STATE_XRUN ? "XRUN" : "SUSPEND"); #endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); if (ret < 0) break;
} elseif (runtime->state == SNDRV_PCM_STATE_SETUP) {
ret = snd_pcm_oss_prepare(substream); if (ret < 0) break;
}
ret = snd_pcm_kernel_readv(substream, bufs, frames); if (ret != -EPIPE && ret != -ESTRPIPE) break;
} return ret;
} #endif/* CONFIG_SND_PCM_OSS_PLUGINS */
for (i = 0; i < 2; i++) {
substream = pcm_oss_file->streams[i]; if (!substream) continue;
runtime = substream->runtime;
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
mutex_lock(&runtime->oss.params_lock);
runtime->oss.prepare = 1;
runtime->oss.buffer_used = 0;
runtime->oss.prev_hw_ptr_period = 0;
runtime->oss.period_ptr = 0;
mutex_unlock(&runtime->oss.params_lock);
} return 0;
}
staticint snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file)
{ struct snd_pcm_substream *substream; int err;
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream != NULL) {
err = snd_pcm_oss_make_ready(substream); if (err < 0) return err;
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
} /* note: all errors from the start action are ignored */ /* OSS apps do not know, how to handle them */ return 0;
}
staticint snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
{ struct snd_pcm_runtime *runtime;
ssize_t result = 0;
snd_pcm_state_t state; long res;
wait_queue_entry_t wait;
runtime = substream->runtime;
init_waitqueue_entry(&wait, current);
add_wait_queue(&runtime->sleep, &wait); #ifdef OSS_DEBUG
pcm_dbg(substream->pcm, "sync1: size = %li\n", size); #endif while (1) {
result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1); if (result > 0) {
runtime->oss.buffer_used = 0;
result = 0; break;
} if (result != 0 && result != -EAGAIN) break;
result = 0;
set_current_state(TASK_INTERRUPTIBLE);
scoped_guard(pcm_stream_lock_irq, substream)
state = runtime->state; if (state != SNDRV_PCM_STATE_RUNNING) {
set_current_state(TASK_RUNNING); break;
}
res = schedule_timeout(10 * HZ); if (signal_pending(current)) {
result = -ERESTARTSYS; break;
} if (res == 0) {
pcm_err(substream->pcm, "OSS sync error - DMA timeout\n");
result = -EIO; break;
}
}
remove_wait_queue(&runtime->sleep, &wait); return result;
}
staticint snd_pcm_oss_get_caps1(struct snd_pcm_substream *substream, int res)
{
if (substream == NULL) {
res &= ~DSP_CAP_DUPLEX; return res;
} #ifdef DSP_CAP_MULTI if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->pstr->substream_count > 1)
res |= DSP_CAP_MULTI; #endif /* DSP_CAP_REALTIME is set all times: */ /* all ALSA drivers can return actual pointer in ring buffer */ #ifdefined(DSP_CAP_REALTIME) && 0
{ struct snd_pcm_runtime *runtime = substream->runtime; if (runtime->info & (SNDRV_PCM_INFO_BLOCK_TRANSFER|SNDRV_PCM_INFO_BATCH))
res &= ~DSP_CAP_REALTIME;
} #endif return res;
}
staticint snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file)
{ int result, idx;
result = DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_DUPLEX | DSP_CAP_REALTIME; for (idx = 0; idx < 2; idx++) { struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
result = snd_pcm_oss_get_caps1(substream, result);
}
result |= 0x0001; /* revision - same as SB AWE 64 */ return result;
}
pcm_oss_file = file->private_data; if (cmd == OSS_GETVERSION) return put_user(SNDRV_OSS_VERSION, p); if (cmd == OSS_ALSAEMULVER) return put_user(1, p); #if IS_REACHABLE(CONFIG_SND_MIXER_OSS) if (((cmd >> 8) & 0xff) == 'M') { /* mixer ioctl - for OSS compatibility */ struct snd_pcm_substream *substream; int idx; for (idx = 0; idx < 2; ++idx) {
substream = pcm_oss_file->streams[idx]; if (substream != NULL) break;
} if (snd_BUG_ON(idx >= 2)) return -ENXIO; return snd_mixer_oss_ioctl_card(substream->pcm->card, cmd, arg);
} #endif if (((cmd >> 8) & 0xff) != 'P') return -EINVAL; #ifdef OSS_DEBUG
pr_debug("pcm_oss: ioctl = 0x%x\n", cmd); #endif switch (cmd) { case SNDCTL_DSP_RESET: return snd_pcm_oss_reset(pcm_oss_file); case SNDCTL_DSP_SYNC: return snd_pcm_oss_sync(pcm_oss_file); case SNDCTL_DSP_SPEED: if (get_user(res, p)) return -EFAULT;
res = snd_pcm_oss_set_rate(pcm_oss_file, res); if (res < 0) return res; return put_user(res, p); case SOUND_PCM_READ_RATE:
res = snd_pcm_oss_get_rate(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_STEREO: if (get_user(res, p)) return -EFAULT;
res = res > 0 ? 2 : 1;
res = snd_pcm_oss_set_channels(pcm_oss_file, res); if (res < 0) return res; return put_user(--res, p); case SNDCTL_DSP_GETBLKSIZE:
res = snd_pcm_oss_get_block_size(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_SETFMT: if (get_user(res, p)) return -EFAULT;
res = snd_pcm_oss_set_format(pcm_oss_file, res); if (res < 0) return res; return put_user(res, p); case SOUND_PCM_READ_BITS:
res = snd_pcm_oss_get_format(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_CHANNELS: if (get_user(res, p)) return -EFAULT;
res = snd_pcm_oss_set_channels(pcm_oss_file, res); if (res < 0) return res; return put_user(res, p); case SOUND_PCM_READ_CHANNELS:
res = snd_pcm_oss_get_channels(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: return -EIO; case SNDCTL_DSP_POST: return snd_pcm_oss_post(pcm_oss_file); case SNDCTL_DSP_SUBDIVIDE: if (get_user(res, p)) return -EFAULT;
res = snd_pcm_oss_set_subdivide(pcm_oss_file, res); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_SETFRAGMENT: if (get_user(res, p)) return -EFAULT; return snd_pcm_oss_set_fragment(pcm_oss_file, res); case SNDCTL_DSP_GETFMTS:
res = snd_pcm_oss_get_formats(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_GETOSPACE: case SNDCTL_DSP_GETISPACE: return snd_pcm_oss_get_space(pcm_oss_file,
cmd == SNDCTL_DSP_GETISPACE ?
SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
(struct audio_buf_info __user *) arg); case SNDCTL_DSP_NONBLOCK: return snd_pcm_oss_nonblock(file); case SNDCTL_DSP_GETCAPS:
res = snd_pcm_oss_get_caps(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_GETTRIGGER:
res = snd_pcm_oss_get_trigger(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_SETTRIGGER: if (get_user(res, p)) return -EFAULT; return snd_pcm_oss_set_trigger(pcm_oss_file, res); case SNDCTL_DSP_GETIPTR: case SNDCTL_DSP_GETOPTR: return snd_pcm_oss_get_ptr(pcm_oss_file,
cmd == SNDCTL_DSP_GETIPTR ?
SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
(struct count_info __user *) arg); case SNDCTL_DSP_MAPINBUF: case SNDCTL_DSP_MAPOUTBUF: return snd_pcm_oss_get_mapbuf(pcm_oss_file,
cmd == SNDCTL_DSP_MAPINBUF ?
SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
(struct buffmem_desc __user *) arg); case SNDCTL_DSP_SETSYNCRO: /* stop DMA now.. */ return 0; case SNDCTL_DSP_SETDUPLEX: if (snd_pcm_oss_get_caps(pcm_oss_file) & DSP_CAP_DUPLEX) return 0; return -EIO; case SNDCTL_DSP_GETODELAY:
res = snd_pcm_oss_get_odelay(pcm_oss_file); if (res < 0) { /* it's for sure, some broken apps don't check for error codes */
put_user(0, p); return res;
} return put_user(res, p); case SNDCTL_DSP_PROFILE: return 0; /* silently ignore */ default:
pr_debug("pcm_oss: unknown command = 0x%x\n", cmd);
} return -EINVAL;
}
#ifdef CONFIG_COMPAT /* all compatible */ staticlong snd_pcm_oss_ioctl_compat(struct file *file, unsignedint cmd, unsignedlong arg)
{ /* * Everything is compatbile except SNDCTL_DSP_MAPINBUF/SNDCTL_DSP_MAPOUTBUF, * which are not implemented for the native case either
*/ return snd_pcm_oss_ioctl(file, cmd, (unsignedlong)compat_ptr(arg));
} #else #define snd_pcm_oss_ioctl_compat NULL #endif
#ifdef OSS_DEBUG
pr_debug("pcm_oss: mmap begin\n"); #endif
pcm_oss_file = file->private_data; switch ((area->vm_flags & (VM_READ | VM_WRITE))) { case VM_READ | VM_WRITE:
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream) break;
fallthrough; case VM_READ:
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; break; case VM_WRITE:
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; break; default: return -EINVAL;
} /* set VM_READ access as well to fix memset() routines that do
reads before writes (to improve performance) */
vm_flags_set(area, VM_READ); if (substream == NULL) return -ENXIO;
runtime = substream->runtime; if (!(runtime->info & SNDRV_PCM_INFO_MMAP_VALID)) return -EIO; if (runtime->info & SNDRV_PCM_INFO_INTERLEAVED)
runtime->access = SNDRV_PCM_ACCESS_MMAP_INTERLEAVED; else return -EIO;
if (runtime->oss.params) { /* use mutex_trylock() for params_lock for avoiding a deadlock * between mmap_lock and params_lock taken by * copy_from/to_user() in snd_pcm_oss_write/read()
*/
err = snd_pcm_oss_change_params(substream, true); if (err < 0) return err;
} #ifdef CONFIG_SND_PCM_OSS_PLUGINS if (runtime->oss.plugin_first != NULL) return -EIO; #endif
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.71Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.