X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=sound%2Fcore%2Foss%2Fpcm_oss.c;h=699d2890535ccb9a5280ce6173980308602d6c26;hb=85bff8857c62ab2bc3ed204de3fcde74781bbdb2;hp=a92b93e5ebd58215ca648736d4e510f2c4ca09a3;hpb=746d4a02e68499fc6c1f8d0c43d2271853ade181;p=safe%2Fjmp%2Flinux-2.6 diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index a92b93e..699d289 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1,6 +1,6 @@ /* * Digital Audio (PCM) abstract layer / OSS compatible - * Copyright (c) by Jaroslav Kysela + * Copyright (c) by Jaroslav Kysela * * * This program is free software; you can redistribute it and/or modify @@ -26,9 +26,7 @@ #define OSS_DEBUG #endif -#include #include -#include #include #include #include @@ -49,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 , Abramo Bagnara "); +MODULE_AUTHOR("Jaroslav Kysela , Abramo Bagnara "); MODULE_DESCRIPTION("PCM OSS emulation for ALSA."); MODULE_LICENSE("GPL"); module_param_array(dsp_map, int, NULL, 0444); @@ -454,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: @@ -463,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; } @@ -634,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) { @@ -647,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; } } @@ -664,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; } } @@ -750,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; @@ -810,6 +840,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) struct snd_mask sformat_mask; struct snd_mask mask; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -EINTR; sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL); params = kmalloc(sizeof(*params), GFP_KERNEL); sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); @@ -865,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)); @@ -928,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); @@ -954,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; @@ -978,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); @@ -989,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; @@ -1020,6 +1059,7 @@ failure: kfree(sw_params); kfree(params); kfree(sparams); + mutex_unlock(&runtime->oss.params_lock); return err; } @@ -1040,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; @@ -1307,14 +1348,17 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) return tmp; + mutex_lock(&runtime->oss.params_lock); while (bytes > 0) { if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { tmp = bytes; if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes) tmp = runtime->oss.period_bytes - runtime->oss.buffer_used; if (tmp > 0) { - if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp)) - return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT; + if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp)) { + tmp = -EFAULT; + goto err; + } } runtime->oss.buffer_used += tmp; buf += tmp; @@ -1325,22 +1369,24 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr, runtime->oss.buffer_used - runtime->oss.period_ptr, 1); if (tmp <= 0) - return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; + goto err; runtime->oss.bytes += tmp; runtime->oss.period_ptr += tmp; runtime->oss.period_ptr %= runtime->oss.period_bytes; if (runtime->oss.period_ptr == 0 || runtime->oss.period_ptr == runtime->oss.buffer_used) runtime->oss.buffer_used = 0; - else if ((substream->f_flags & O_NONBLOCK) != 0) - return xfer > 0 ? xfer : -EAGAIN; + else if ((substream->f_flags & O_NONBLOCK) != 0) { + tmp = -EAGAIN; + goto err; + } } } else { tmp = snd_pcm_oss_write2(substream, (const char __force *)buf, runtime->oss.period_bytes, 0); if (tmp <= 0) - return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; + goto err; runtime->oss.bytes += tmp; buf += tmp; bytes -= tmp; @@ -1350,7 +1396,12 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha break; } } + mutex_unlock(&runtime->oss.params_lock); return xfer; + + err: + mutex_unlock(&runtime->oss.params_lock); + return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; } static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf, size_t bytes, int in_kernel) @@ -1397,12 +1448,13 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) return tmp; + mutex_lock(&runtime->oss.params_lock); while (bytes > 0) { if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { if (runtime->oss.buffer_used == 0) { tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); if (tmp <= 0) - return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; + goto err; runtime->oss.bytes += tmp; runtime->oss.period_ptr = tmp; runtime->oss.buffer_used = tmp; @@ -1410,8 +1462,10 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use tmp = bytes; if ((size_t) tmp > runtime->oss.buffer_used) tmp = runtime->oss.buffer_used; - if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp)) - return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT; + if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp)) { + tmp = -EFAULT; + goto err; + } buf += tmp; bytes -= tmp; xfer += tmp; @@ -1420,14 +1474,19 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use tmp = snd_pcm_oss_read2(substream, (char __force *)buf, runtime->oss.period_bytes, 0); if (tmp <= 0) - return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; + goto err; runtime->oss.bytes += tmp; buf += tmp; bytes -= tmp; xfer += tmp; } } + mutex_unlock(&runtime->oss.params_lock); return xfer; + + err: + mutex_unlock(&runtime->oss.params_lock); + return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; } static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file) @@ -1528,6 +1587,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) return err; format = snd_pcm_oss_format_from(runtime->oss.format); width = snd_pcm_format_physical_width(format); + mutex_lock(&runtime->oss.params_lock); if (runtime->oss.buffer_used > 0) { #ifdef OSS_DEBUG printk("sync: buffer_used\n"); @@ -1537,8 +1597,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) runtime->oss.buffer + runtime->oss.buffer_used, size); err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes); - if (err < 0) + if (err < 0) { + mutex_unlock(&runtime->oss.params_lock); return err; + } } else if (runtime->oss.period_ptr > 0) { #ifdef OSS_DEBUG printk("sync: period_ptr\n"); @@ -1548,8 +1610,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) runtime->oss.buffer, size * 8 / width); err = snd_pcm_oss_sync1(substream, size); - if (err < 0) + if (err < 0) { + mutex_unlock(&runtime->oss.params_lock); return err; + } } /* * The ALSA's period might be a bit large than OSS one. @@ -1569,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); @@ -1579,6 +1644,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) snd_pcm_lib_writev(substream, buffers, size); } } + mutex_unlock(&runtime->oss.params_lock); /* * finish sync: drain the buffer */ @@ -1699,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; @@ -1707,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); @@ -2172,6 +2242,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream, runtime->oss.params = 1; runtime->oss.trigger = 1; runtime->oss.rate = 8000; + mutex_init(&runtime->oss.params_lock); switch (SNDRV_MINOR_OSS_DEVICE(minor)) { case SNDRV_MINOR_OSS_PCM_8: runtime->oss.format = AFMT_U8; @@ -2192,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) @@ -2211,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) @@ -2254,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; } @@ -2263,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'; @@ -2357,9 +2431,11 @@ 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; - snd_pcm_oss_sync(pcm_oss_file); + if (!pcm->card->shutdown) + snd_pcm_oss_sync(pcm_oss_file); mutex_lock(&pcm->open_mutex); snd_pcm_oss_release_file(pcm_oss_file); mutex_unlock(&pcm->open_mutex); @@ -2389,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 @@ -2795,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) @@ -2809,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; } } @@ -2860,7 +2937,7 @@ static void snd_pcm_oss_proc_done(struct snd_pcm *pcm) * ENTRY functions */ -static struct file_operations snd_pcm_oss_f_reg = +static const struct file_operations snd_pcm_oss_f_reg = { .owner = THIS_MODULE, .read = snd_pcm_oss_read, @@ -2929,25 +3006,23 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm) snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, pcm->card, 1); } - } - return 0; -} - -static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm) -{ - snd_pcm_oss_disconnect_minor(pcm); - if (pcm->oss.reg) { if (dsp_map[pcm->card->number] == (int)pcm->device) { #ifdef SNDRV_OSS_INFO_DEV_AUDIO snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number); #endif } pcm->oss.reg = 0; - snd_pcm_oss_proc_done(pcm); } return 0; } +static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm) +{ + snd_pcm_oss_disconnect_minor(pcm); + snd_pcm_oss_proc_done(pcm); + return 0; +} + static struct snd_pcm_notify snd_pcm_oss_notify = { .n_register = snd_pcm_oss_register_minor,