diff options
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/Kconfig | 2 | ||||
-rw-r--r-- | sound/core/control.c | 35 | ||||
-rw-r--r-- | sound/core/init.c | 61 | ||||
-rw-r--r-- | sound/core/jack.c | 3 | ||||
-rw-r--r-- | sound/core/oss/pcm_oss.c | 5 | ||||
-rw-r--r-- | sound/core/pcm_compat.c | 11 | ||||
-rw-r--r-- | sound/core/pcm_lib.c | 146 | ||||
-rw-r--r-- | sound/core/pcm_native.c | 122 | ||||
-rw-r--r-- | sound/core/seq/Kconfig | 16 | ||||
-rw-r--r-- | sound/core/seq/Makefile | 18 | ||||
-rw-r--r-- | sound/core/seq/seq_compat.c | 9 | ||||
-rw-r--r-- | sound/core/timer.c | 11 |
12 files changed, 271 insertions, 168 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 7bbdda041a99..6061fb5f4e1c 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -205,3 +205,5 @@ config SND_PCM_XRUN_DEBUG config SND_VMASTER bool + +source "sound/core/seq/Kconfig" diff --git a/sound/core/control.c b/sound/core/control.c index 4b20fa2b7e6d..17b8d47a5cd0 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -723,14 +723,11 @@ static int snd_ctl_elem_read_user(struct snd_card *card, { struct snd_ctl_elem_value *control; int result; - - control = kmalloc(sizeof(*control), GFP_KERNEL); - if (control == NULL) - return -ENOMEM; - if (copy_from_user(control, _control, sizeof(*control))) { - kfree(control); - return -EFAULT; - } + + control = memdup_user(_control, sizeof(*control)); + if (IS_ERR(control)) + return PTR_ERR(control); + snd_power_lock(card); result = snd_power_wait(card, SNDRV_CTL_POWER_D0); if (result >= 0) @@ -784,13 +781,10 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file, struct snd_card *card; int result; - control = kmalloc(sizeof(*control), GFP_KERNEL); - if (control == NULL) - return -ENOMEM; - if (copy_from_user(control, _control, sizeof(*control))) { - kfree(control); - return -EFAULT; - } + control = memdup_user(_control, sizeof(*control)); + if (IS_ERR(control)) + return PTR_ERR(control); + card = file->card; snd_power_lock(card); result = snd_power_wait(card, SNDRV_CTL_POWER_D0); @@ -916,13 +910,10 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, if (op_flag > 0) { if (size > 1024 * 128) /* sane value */ return -EINVAL; - new_data = kmalloc(size, GFP_KERNEL); - if (new_data == NULL) - return -ENOMEM; - if (copy_from_user(new_data, tlv, size)) { - kfree(new_data); - return -EFAULT; - } + + new_data = memdup_user(tlv, size); + if (IS_ERR(new_data)) + return PTR_ERR(new_data); change = ue->tlv_data_size != size; if (!change) change = memcmp(ue->tlv_data, new_data, size); diff --git a/sound/core/init.c b/sound/core/init.c index fd56afe846ed..d5d40d78c409 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -152,15 +152,8 @@ int snd_card_create(int idx, const char *xid, card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); if (!card) return -ENOMEM; - if (xid) { - if (!snd_info_check_reserved_words(xid)) { - snd_printk(KERN_ERR - "given id string '%s' is reserved.\n", xid); - err = -EBUSY; - goto __error; - } + if (xid) strlcpy(card->id, xid, sizeof(card->id)); - } err = 0; mutex_lock(&snd_card_mutex); if (idx < 0) { @@ -483,22 +476,28 @@ int snd_card_free(struct snd_card *card) EXPORT_SYMBOL(snd_card_free); -static void choose_default_id(struct snd_card *card) +static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid) { int i, len, idx_flag = 0, loops = SNDRV_CARDS; - char *id, *spos; + const char *spos, *src; + char *id; - id = spos = card->shortname; - while (*id != '\0') { - if (*id == ' ') - spos = id + 1; - id++; + if (nid == NULL) { + id = card->shortname; + spos = src = id; + while (*id != '\0') { + if (*id == ' ') + spos = id + 1; + id++; + } + } else { + spos = src = nid; } id = card->id; while (*spos != '\0' && !isalnum(*spos)) spos++; if (isdigit(*spos)) - *id++ = isalpha(card->shortname[0]) ? card->shortname[0] : 'D'; + *id++ = isalpha(src[0]) ? src[0] : 'D'; while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) { if (isalnum(*spos)) *id++ = *spos; @@ -513,7 +512,7 @@ static void choose_default_id(struct snd_card *card) while (1) { if (loops-- == 0) { - snd_printk(KERN_ERR "unable to choose default card id (%s)\n", id); + snd_printk(KERN_ERR "unable to set card id (%s)\n", id); strcpy(card->id, card->proc_root->name); return; } @@ -539,14 +538,33 @@ static void choose_default_id(struct snd_card *card) spos = id + len - 2; if ((size_t)len <= sizeof(card->id) - 2) spos++; - *spos++ = '_'; - *spos++ = '1'; - *spos++ = '\0'; + *(char *)spos++ = '_'; + *(char *)spos++ = '1'; + *(char *)spos++ = '\0'; idx_flag++; } } } +/** + * snd_card_set_id - set card identification name + * @card: soundcard structure + * @nid: new identification string + * + * This function sets the card identification and checks for name + * collisions. + */ +void snd_card_set_id(struct snd_card *card, const char *nid) +{ + /* check if user specified own card->id */ + if (card->id[0] != '\0') + return; + mutex_lock(&snd_card_mutex); + snd_card_set_id_no_lock(card, nid); + mutex_unlock(&snd_card_mutex); +} +EXPORT_SYMBOL(snd_card_set_id); + #ifndef CONFIG_SYSFS_DEPRECATED static ssize_t card_id_show_attr(struct device *dev, @@ -640,8 +658,7 @@ int snd_card_register(struct snd_card *card) mutex_unlock(&snd_card_mutex); return 0; } - if (card->id[0] == '\0') - choose_default_id(card); + snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id); snd_cards[card->number] = card; mutex_unlock(&snd_card_mutex); init_info_for_card(card); diff --git a/sound/core/jack.c b/sound/core/jack.c index c8254c667c62..d54d1a05fe65 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -35,6 +35,9 @@ static int snd_jack_dev_free(struct snd_device *device) { struct snd_jack *jack = device->device_data; + if (jack->private_free) + jack->private_free(jack); + /* If the input device is registered with the input subsystem * then we need to use a different deallocator. */ if (jack->registered) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index dda000b9684c..dbe406b82591 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -31,6 +31,7 @@ #include <linux/time.h> #include <linux/vmalloc.h> #include <linux/moduleparam.h> +#include <linux/math64.h> #include <linux/string.h> #include <sound/core.h> #include <sound/minors.h> @@ -617,9 +618,7 @@ static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames) #else { u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes; - u32 rem; - div64_32(&bsize, buffer_size, &rem); - return (long)bsize; + return div_u64(bsize, buffer_size); } #endif } diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 36d7a5998234..08bfed594a83 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -232,14 +232,11 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, if (! (runtime = substream->runtime)) return -ENOTTY; - data = kmalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; /* only fifo_size is different, so just copy all */ - if (copy_from_user(data, data32, sizeof(*data32))) { - err = -EFAULT; - goto error; - } + data = memdup_user(data32, sizeof(*data32)); + if (IS_ERR(data)) + return PTR_ERR(data); + if (refine) err = snd_pcm_hw_refine(substream, data); else diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index fbb2e391591e..333e4dd29450 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/time.h> +#include <linux/math64.h> #include <sound/core.h> #include <sound/control.h> #include <sound/info.h> @@ -126,24 +127,37 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram } #ifdef CONFIG_SND_PCM_XRUN_DEBUG -#define xrun_debug(substream) ((substream)->pstr->xrun_debug) +#define xrun_debug(substream, mask) ((substream)->pstr->xrun_debug & (mask)) #else -#define xrun_debug(substream) 0 +#define xrun_debug(substream, mask) 0 #endif -#define dump_stack_on_xrun(substream) do { \ - if (xrun_debug(substream) > 1) \ - dump_stack(); \ +#define dump_stack_on_xrun(substream) do { \ + if (xrun_debug(substream, 2)) \ + dump_stack(); \ } while (0) +static void pcm_debug_name(struct snd_pcm_substream *substream, + char *name, size_t len) +{ + snprintf(name, len, "pcmC%dD%d%c:%d", + substream->pcm->card->number, + substream->pcm->device, + substream->stream ? 'c' : 'p', + substream->number); +} + static void xrun(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; + + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - if (xrun_debug(substream)) { - snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n", - substream->pcm->card->number, - substream->pcm->device, - substream->stream ? 'c' : 'p'); + if (xrun_debug(substream, 1)) { + char name[16]; + pcm_debug_name(substream, name, sizeof(name)); + snd_printd(KERN_DEBUG "XRUN: %s\n", name); dump_stack_on_xrun(substream); } } @@ -154,16 +168,16 @@ snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, { snd_pcm_uframes_t pos; - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); pos = substream->ops->pointer(substream); if (pos == SNDRV_PCM_POS_XRUN) return pos; /* XRUN */ if (pos >= runtime->buffer_size) { if (printk_ratelimit()) { - snd_printd(KERN_ERR "BUG: stream = %i, pos = 0x%lx, " + char name[16]; + pcm_debug_name(substream, name, sizeof(name)); + snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, " "buffer size = 0x%lx, period size = 0x%lx\n", - substream->stream, pos, runtime->buffer_size, + name, pos, runtime->buffer_size, runtime->period_size); } pos = 0; @@ -197,7 +211,7 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, #define hw_ptr_error(substream, fmt, args...) \ do { \ - if (xrun_debug(substream)) { \ + if (xrun_debug(substream, 1)) { \ if (printk_ratelimit()) { \ snd_printd("PCM: " fmt, ##args); \ } \ @@ -209,9 +223,11 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t pos; - snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base; - snd_pcm_sframes_t delta; + snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base; + snd_pcm_sframes_t hdelta, delta; + unsigned long jdelta; + old_hw_ptr = runtime->status->hw_ptr; pos = snd_pcm_update_hw_ptr_pos(substream, runtime); if (pos == SNDRV_PCM_POS_XRUN) { xrun(substream); @@ -247,7 +263,45 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) new_hw_ptr = hw_base + pos; } } - if (delta > runtime->period_size) { + + /* Do jiffies check only in xrun_debug mode */ + if (!xrun_debug(substream, 4)) + goto no_jiffies_check; + + /* Skip the jiffies check for hardwares with BATCH flag. + * Such hardware usually just increases the position at each IRQ, + * thus it can't give any strange position. + */ + if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) + goto no_jiffies_check; + hdelta = new_hw_ptr - old_hw_ptr; + if (hdelta < runtime->delay) + goto no_jiffies_check; + hdelta -= runtime->delay; + jdelta = jiffies - runtime->hw_ptr_jiffies; + if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) { + delta = jdelta / + (((runtime->period_size * HZ) / runtime->rate) + + HZ/100); + hw_ptr_error(substream, + "hw_ptr skipping! [Q] " + "(pos=%ld, delta=%ld, period=%ld, " + "jdelta=%lu/%lu/%lu)\n", + (long)pos, (long)hdelta, + (long)runtime->period_size, jdelta, + ((hdelta * HZ) / runtime->rate), delta); + hw_ptr_interrupt = runtime->hw_ptr_interrupt + + runtime->period_size * delta; + if (hw_ptr_interrupt >= runtime->boundary) + hw_ptr_interrupt -= runtime->boundary; + /* rebase to interrupt position */ + hw_base = new_hw_ptr = hw_ptr_interrupt; + /* align hw_base to buffer_size */ + hw_base -= hw_base % runtime->buffer_size; + delta = 0; + } + no_jiffies_check: + if (delta > runtime->period_size + runtime->period_size / 2) { hw_ptr_error(substream, "Lost interrupts? " "(stream=%i, delta=%ld, intr_ptr=%ld)\n", @@ -257,13 +311,20 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size; } + runtime->hw_ptr_interrupt = hw_ptr_interrupt; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); + if (runtime->status->hw_ptr == new_hw_ptr) + return 0; + runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; - runtime->hw_ptr_interrupt = hw_ptr_interrupt; + runtime->hw_ptr_jiffies = jiffies; + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); return snd_pcm_update_hw_ptr_post(substream, runtime); } @@ -275,6 +336,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) snd_pcm_uframes_t pos; snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; snd_pcm_sframes_t delta; + unsigned long jdelta; old_hw_ptr = runtime->status->hw_ptr; pos = snd_pcm_update_hw_ptr_pos(substream, runtime); @@ -286,14 +348,15 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) new_hw_ptr = hw_base + pos; delta = new_hw_ptr - old_hw_ptr; + jdelta = jiffies - runtime->hw_ptr_jiffies; if (delta < 0) { delta += runtime->buffer_size; if (delta < 0) { hw_ptr_error(substream, "Unexpected hw_pointer value [2] " - "(stream=%i, pos=%ld, old_ptr=%ld)\n", + "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n", substream->stream, (long)pos, - (long)old_hw_ptr); + (long)old_hw_ptr, jdelta); return 0; } hw_base += runtime->buffer_size; @@ -301,20 +364,34 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) hw_base = 0; new_hw_ptr = hw_base + pos; } - if (delta > runtime->period_size && runtime->periods > 1) { + /* Do jiffies check only in xrun_debug mode */ + if (!xrun_debug(substream, 4)) + goto no_jiffies_check; + if (delta < runtime->delay) + goto no_jiffies_check; + delta -= runtime->delay; + if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) { hw_ptr_error(substream, "hw_ptr skipping! " - "(pos=%ld, delta=%ld, period=%ld)\n", + "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n", (long)pos, (long)delta, - (long)runtime->period_size); + (long)runtime->period_size, jdelta, + ((delta * HZ) / runtime->rate)); return 0; } + no_jiffies_check: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); + if (runtime->status->hw_ptr == new_hw_ptr) + return 0; + runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; + runtime->hw_ptr_jiffies = jiffies; + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); return snd_pcm_update_hw_ptr_post(substream, runtime); } @@ -408,7 +485,7 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b, *r = 0; return UINT_MAX; } - div64_32(&n, c, r); + n = div_u64_rem(n, c, r); if (n >= UINT_MAX) { *r = 0; return UINT_MAX; @@ -1480,6 +1557,23 @@ static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream, return 0; } +static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, + void *arg) +{ + struct snd_pcm_hw_params *params = arg; + snd_pcm_format_t format; + int channels, width; + + params->fifo_size = substream->runtime->hw.fifo_size; + if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) { + format = params_format(params); + channels = params_channels(params); + width = snd_pcm_format_physical_width(format); + params->fifo_size /= width * channels; + } + return 0; +} + /** * snd_pcm_lib_ioctl - a generic PCM ioctl callback * @substream: the pcm substream instance @@ -1501,6 +1595,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, return snd_pcm_lib_ioctl_reset(substream, arg); case SNDRV_PCM_IOCTL1_CHANNEL_INFO: return snd_pcm_lib_ioctl_channel_info(substream, arg); + case SNDRV_PCM_IOCTL1_FIFO_SIZE: + return snd_pcm_lib_ioctl_fifo_size(substream, arg); } return -ENXIO; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a151fb01ba82..84da3ba17c86 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -312,9 +312,18 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, hw = &substream->runtime->hw; if (!params->info) - params->info = hw->info; - if (!params->fifo_size) - params->fifo_size = hw->fifo_size; + params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES; + if (!params->fifo_size) { + if (snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) == + snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) && + snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) == + snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) { + changed = substream->ops->ioctl(substream, + SNDRV_PCM_IOCTL1_FIFO_SIZE, params); + if (params < 0) + return changed; + } + } params->rmask = 0; return 0; } @@ -327,21 +336,16 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params; int err; - params = kmalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - err = -ENOMEM; - goto out; - } - if (copy_from_user(params, _params, sizeof(*params))) { - err = -EFAULT; - goto out; - } + params = memdup_user(_params, sizeof(*params)); + if (IS_ERR(params)) + return PTR_ERR(params); + err = snd_pcm_hw_refine(substream, params); if (copy_to_user(_params, params, sizeof(*params))) { if (!err) err = -EFAULT; } -out: + kfree(params); return err; } @@ -465,21 +469,16 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params; int err; - params = kmalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - err = -ENOMEM; - goto out; - } - if (copy_from_user(params, _params, sizeof(*params))) { - err = -EFAULT; - goto out; - } + params = memdup_user(_params, sizeof(*params)); + if (IS_ERR(params)) + return PTR_ERR(params); + err = snd_pcm_hw_params(substream, params); if (copy_to_user(_params, params, sizeof(*params))) { if (!err) err = -EFAULT; } -out: + kfree(params); return err; } @@ -597,14 +596,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { status->avail = snd_pcm_playback_avail(runtime); if (runtime->status->state == SNDRV_PCM_STATE_RUNNING || - runtime->status->state == SNDRV_PCM_STATE_DRAINING) + runtime->status->state == SNDRV_PCM_STATE_DRAINING) { status->delay = runtime->buffer_size - status->avail; - else + status->delay += runtime->delay; + } else status->delay = 0; } else { status->avail = snd_pcm_capture_avail(runtime); if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - status->delay = status->avail; + status->delay = status->avail + runtime->delay; else status->delay = 0; } @@ -858,6 +858,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); + runtime->hw_ptr_jiffies = jiffies; runtime->status->state = state; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) @@ -971,6 +972,11 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push) { if (substream->runtime->trigger_master != substream) return 0; + /* The jiffies check in snd_pcm_update_hw_ptr*() is done by + * a delta betwen the current jiffies, this gives a large enough + * delta, effectively to skip the check once. + */ + substream->runtime->hw_ptr_jiffies = jiffies - HZ * 1000; return substream->ops->trigger(substream, push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH : SNDRV_PCM_TRIGGER_PAUSE_RELEASE); @@ -2414,6 +2420,7 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream, n = snd_pcm_playback_hw_avail(runtime); else n = snd_pcm_capture_avail(runtime); + n += runtime->delay; break; case SNDRV_PCM_STATE_XRUN: err = -EPIPE; @@ -2593,13 +2600,11 @@ static int snd_pcm_playback_ioctl1(struct file *file, return -EFAULT; if (copy_from_user(&xfern, _xfern, sizeof(xfern))) return -EFAULT; - bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL); - if (bufs == NULL) - return -ENOMEM; - if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) { - kfree(bufs); - return -EFAULT; - } + + bufs = memdup_user(xfern.bufs, + sizeof(void *) * runtime->channels); + if (IS_ERR(bufs)) + return PTR_ERR(bufs); result = snd_pcm_lib_writev(substream, bufs, xfern.frames); kfree(bufs); __put_user(result, &_xfern->result); @@ -2675,13 +2680,11 @@ static int snd_pcm_capture_ioctl1(struct file *file, return -EFAULT; if (copy_from_user(&xfern, _xfern, sizeof(xfern))) return -EFAULT; - bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL); - if (bufs == NULL) - return -ENOMEM; - if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) { - kfree(bufs); - return -EFAULT; - } + + bufs = memdup_user(xfern.bufs, + sizeof(void *) * runtime->channels); + if (IS_ERR(bufs)) + return PTR_ERR(bufs); result = snd_pcm_lib_readv(substream, bufs, xfern.frames); kfree(bufs); __put_user(result, &_xfern->result); @@ -3312,18 +3315,12 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, int err; params = kmalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - err = -ENOMEM; - goto out; - } - oparams = kmalloc(sizeof(*oparams), GFP_KERNEL); - if (!oparams) { - err = -ENOMEM; - goto out; - } + if (!params) + return -ENOMEM; - if (copy_from_user(oparams, _oparams, sizeof(*oparams))) { - err = -EFAULT; + oparams = memdup_user(_oparams, sizeof(*oparams)); + if (IS_ERR(oparams)) { + err = PTR_ERR(oparams); goto out; } snd_pcm_hw_convert_from_old_params(params, oparams); @@ -3333,9 +3330,10 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, if (!err) err = -EFAULT; } + + kfree(oparams); out: kfree(params); - kfree(oparams); return err; } @@ -3347,17 +3345,12 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, int err; params = kmalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - err = -ENOMEM; - goto out; - } - oparams = kmalloc(sizeof(*oparams), GFP_KERNEL); - if (!oparams) { - err = -ENOMEM; - goto out; - } - if (copy_from_user(oparams, _oparams, sizeof(*oparams))) { - err = -EFAULT; + if (!params) + return -ENOMEM; + + oparams = memdup_user(_oparams, sizeof(*oparams)); + if (IS_ERR(oparams)) { + err = PTR_ERR(oparams); goto out; } snd_pcm_hw_convert_from_old_params(params, oparams); @@ -3367,9 +3360,10 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, if (!err) err = -EFAULT; } + + kfree(oparams); out: kfree(params); - kfree(oparams); return err; } #endif /* CONFIG_SND_SUPPORT_OLD_API */ diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig new file mode 100644 index 000000000000..b851fd890a89 --- /dev/null +++ b/sound/core/seq/Kconfig @@ -0,0 +1,16 @@ +# define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX) + +config SND_RAWMIDI_SEQ + def_tristate SND_SEQUENCER && SND_RAWMIDI + +config SND_OPL3_LIB_SEQ + def_tristate SND_SEQUENCER && SND_OPL3_LIB + +config SND_OPL4_LIB_SEQ + def_tristate SND_SEQUENCER && SND_OPL4_LIB + +config SND_SBAWE_SEQ + def_tristate SND_SEQUENCER && SND_SBAWE + +config SND_EMU10K1_SEQ + def_tristate SND_SEQUENCER && SND_EMU10K1 diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index 069593717fba..1bcb360330e5 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile @@ -17,14 +17,6 @@ snd-seq-midi-event-objs := seq_midi_event.o snd-seq-dummy-objs := seq_dummy.o snd-seq-virmidi-objs := seq_virmidi.o -# -# this function returns: -# "m" - CONFIG_SND_SEQUENCER is m -# <empty string> - CONFIG_SND_SEQUENCER is undefined -# otherwise parameter #1 value -# -sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) - obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o @@ -33,8 +25,8 @@ obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o # Toplevel Module Dependency obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o -obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o -obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o -obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o -obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o -obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o +obj-$(CONFIG_SND_RAWMIDI_SEQ) += snd-seq-midi.o snd-seq-midi-event.o +obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o +obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o +obj-$(CONFIG_SND_SBAWE_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o +obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c index 38693f47c262..c956fe462569 100644 --- a/sound/core/seq/seq_compat.c +++ b/sound/core/seq/seq_compat.c @@ -48,12 +48,11 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned struct snd_seq_port_info *data; mm_segment_t fs; - data = kmalloc(sizeof(*data), GFP_KERNEL); - if (! data) - return -ENOMEM; + data = memdup_user(data32, sizeof(*data32)); + if (IS_ERR(data)) + return PTR_ERR(data); - if (copy_from_user(data, data32, sizeof(*data32)) || - get_user(data->flags, &data32->flags) || + if (get_user(data->flags, &data32->flags) || get_user(data->time_queue, &data32->time_queue)) goto error; data->kernel = NULL; diff --git a/sound/core/timer.c b/sound/core/timer.c index 3f0050d0b71e..8f8b17ac074d 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1395,13 +1395,10 @@ static int snd_timer_user_ginfo(struct file *file, struct list_head *p; int err = 0; - ginfo = kmalloc(sizeof(*ginfo), GFP_KERNEL); - if (! ginfo) - return -ENOMEM; - if (copy_from_user(ginfo, _ginfo, sizeof(*ginfo))) { - kfree(ginfo); - return -EFAULT; - } + ginfo = memdup_user(_ginfo, sizeof(*ginfo)); + if (IS_ERR(ginfo)) + return PTR_ERR(ginfo); + tid = ginfo->tid; memset(ginfo, 0, sizeof(*ginfo)); ginfo->tid = tid; |