diff options
Diffstat (limited to 'sound/core')
37 files changed, 1005 insertions, 507 deletions
diff --git a/sound/core/control.c b/sound/core/control.c index 498e3701514a..a25c0d64d104 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -995,7 +995,10 @@ static int __snd_ctl_elem_info(struct snd_card *card, #ifdef CONFIG_SND_DEBUG info->access = 0; #endif - result = kctl->info(kctl, info); + result = snd_power_ref_and_wait(card); + if (!result) + result = kctl->info(kctl, info); + snd_power_unref(card); if (result >= 0) { snd_BUG_ON(info->access); index_offset = snd_ctl_get_ioff(kctl, &info->id); @@ -1042,9 +1045,6 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, if (copy_from_user(&info, _info, sizeof(info))) return -EFAULT; - result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); - if (result < 0) - return result; result = snd_ctl_elem_info(ctl, &info); if (result < 0) return result; @@ -1088,7 +1088,10 @@ static int snd_ctl_elem_read(struct snd_card *card, if (!snd_ctl_skip_validation(&info)) fill_remaining_elem_value(control, &info, pattern); - ret = kctl->get(kctl, control); + ret = snd_power_ref_and_wait(card); + if (!ret) + ret = kctl->get(kctl, control); + snd_power_unref(card); if (ret < 0) return ret; if (!snd_ctl_skip_validation(&info) && @@ -1113,10 +1116,6 @@ static int snd_ctl_elem_read_user(struct snd_card *card, if (IS_ERR(control)) return PTR_ERR(control); - result = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (result < 0) - goto error; - down_read(&card->controls_rwsem); result = snd_ctl_elem_read(card, control); up_read(&card->controls_rwsem); @@ -1154,7 +1153,10 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, } snd_ctl_build_ioff(&control->id, kctl, index_offset); - result = kctl->put(kctl, control); + result = snd_power_ref_and_wait(card); + if (!result) + result = kctl->put(kctl, control); + snd_power_unref(card); if (result < 0) { up_write(&card->controls_rwsem); return result; @@ -1183,10 +1185,6 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file, return PTR_ERR(control); card = file->card; - result = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (result < 0) - goto error; - result = snd_ctl_elem_write(card, file, control); if (result < 0) goto error; @@ -1669,7 +1667,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, {SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND}, }; struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)]; - int i; + int i, ret; /* Check support of the request for this element. */ for (i = 0; i < ARRAY_SIZE(pairs); ++i) { @@ -1687,7 +1685,11 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, vd->owner != NULL && vd->owner != file) return -EPERM; - return kctl->tlv.c(kctl, op_flag, size, buf); + ret = snd_power_ref_and_wait(file->card); + if (!ret) + ret = kctl->tlv.c(kctl, op_flag, size, buf); + snd_power_unref(file->card); + return ret; } static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id, @@ -1815,11 +1817,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg case SNDRV_CTL_IOCTL_POWER: return -ENOPROTOOPT; case SNDRV_CTL_IOCTL_POWER_STATE: -#ifdef CONFIG_PM - return put_user(card->power_state, ip) ? -EFAULT : 0; -#else return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0; -#endif } down_read(&snd_ioctl_rwsem); list_for_each_entry(p, &snd_control_ioctls, list) { diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 1d708aab9c98..470dabc60aa0 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -96,9 +96,6 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) goto error; - err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); - if (err < 0) - goto error; err = snd_ctl_elem_info(ctl, data); if (err < 0) goto error; @@ -187,7 +184,10 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, return -ENOMEM; } info->id = *id; - err = kctl->info(kctl, info); + err = snd_power_ref_and_wait(card); + if (!err) + err = kctl->info(kctl, info); + snd_power_unref(card); up_read(&card->controls_rwsem); if (err >= 0) { err = info->type; @@ -298,9 +298,6 @@ static int ctl_elem_read_user(struct snd_card *card, if (err < 0) goto error; - err = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (err < 0) - goto error; err = snd_ctl_elem_read(card, data); if (err < 0) goto error; @@ -326,9 +323,6 @@ static int ctl_elem_write_user(struct snd_ctl_file *file, if (err < 0) goto error; - err = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (err < 0) - goto error; err = snd_ctl_elem_write(card, file, data); if (err < 0) goto error; diff --git a/sound/core/control_led.c b/sound/core/control_led.c index a90e31dbde61..764058cc345d 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -393,11 +393,11 @@ static void snd_ctl_led_dev_release(struct device *dev) * sysfs */ -static ssize_t show_mode(struct device *dev, +static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); - const char *str; + const char *str = NULL; switch (led->mode) { case MODE_FOLLOW_MUTE: str = "follow-mute"; break; @@ -408,7 +408,8 @@ static ssize_t show_mode(struct device *dev, return sprintf(buf, "%s\n", str); } -static ssize_t store_mode(struct device *dev, struct device_attribute *attr, +static ssize_t mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); @@ -437,7 +438,7 @@ static ssize_t store_mode(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_brightness(struct device *dev, +static ssize_t brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); @@ -445,8 +446,8 @@ static ssize_t show_brightness(struct device *dev, return sprintf(buf, "%u\n", ledtrig_audio_get(led->trigger_type)); } -static DEVICE_ATTR(mode, 0644, show_mode, store_mode); -static DEVICE_ATTR(brightness, 0444, show_brightness, NULL); +static DEVICE_ATTR_RW(mode); +static DEVICE_ATTR_RO(brightness); static struct attribute *snd_ctl_led_dev_attrs[] = { &dev_attr_mode.attr, @@ -580,22 +581,25 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si return count; } -static ssize_t parse_attach(struct device *dev, struct device_attribute *attr, +static ssize_t attach_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); return set_led_id(led_card, buf, count, true); } -static ssize_t parse_detach(struct device *dev, struct device_attribute *attr, +static ssize_t detach_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); return set_led_id(led_card, buf, count, false); } -static ssize_t ctl_reset(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t reset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); int err; @@ -608,8 +612,8 @@ static ssize_t ctl_reset(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t ctl_list(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t list_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); struct snd_card *card; @@ -642,10 +646,10 @@ static ssize_t ctl_list(struct device *dev, return buf2 - buf; } -static DEVICE_ATTR(attach, 0200, NULL, parse_attach); -static DEVICE_ATTR(detach, 0200, NULL, parse_detach); -static DEVICE_ATTR(reset, 0200, NULL, ctl_reset); -static DEVICE_ATTR(list, 0444, ctl_list, NULL); +static DEVICE_ATTR_WO(attach); +static DEVICE_ATTR_WO(detach); +static DEVICE_ATTR_WO(reset); +static DEVICE_ATTR_RO(list); static struct attribute *snd_ctl_led_card_attrs[] = { &dev_attr_attach.attr, diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 264b8ea64bc2..e95fa275c289 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -195,7 +195,8 @@ static int snd_hwdep_dsp_status(struct snd_hwdep *hw, return -ENXIO; memset(&info, 0, sizeof(info)); info.dsp_loaded = hw->dsp_loaded; - if ((err = hw->ops.dsp_status(hw, &info)) < 0) + err = hw->ops.dsp_status(hw, &info); + if (err < 0) return err; if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; @@ -500,7 +501,8 @@ static void __init snd_hwdep_proc_init(void) { struct snd_info_entry *entry; - if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) { + entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL); + if (entry) { entry->c.text.read = snd_hwdep_proc_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index 83900485dd8c..1ba887c7954e 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c @@ -31,7 +31,8 @@ int snd_oss_info_register(int dev, int num, char *string) return -ENXIO; mutex_lock(&strings); if (string == NULL) { - if ((x = snd_sndstat_strings[num][dev]) != NULL) { + x = snd_sndstat_strings[num][dev]; + if (x) { kfree(x); x = NULL; } diff --git a/sound/core/init.c b/sound/core/init.c index ef41f5b3a240..1490568efdb0 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -220,6 +220,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid, mutex_init(&card->memory_mutex); #ifdef CONFIG_PM init_waitqueue_head(&card->power_sleep); + init_waitqueue_head(&card->power_ref_sleep); + atomic_set(&card->power_ref, 0); #endif init_waitqueue_head(&card->remove_sleep); card->sync_irq = -1; @@ -442,6 +444,7 @@ int snd_card_disconnect(struct snd_card *card) #ifdef CONFIG_PM wake_up(&card->power_sleep); + snd_power_sync_ref(card); #endif return 0; } @@ -662,17 +665,15 @@ void snd_card_set_id(struct snd_card *card, const char *nid) } EXPORT_SYMBOL(snd_card_set_id); -static ssize_t -card_id_show_attr(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t id_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct snd_card *card = container_of(dev, struct snd_card, card_dev); return scnprintf(buf, PAGE_SIZE, "%s\n", card->id); } -static ssize_t -card_id_store_attr(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t id_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct snd_card *card = container_of(dev, struct snd_card, card_dev); char buf1[sizeof(card->id)]; @@ -700,17 +701,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(id, 0644, card_id_show_attr, card_id_store_attr); +static DEVICE_ATTR_RW(id); -static ssize_t -card_number_show_attr(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t number_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct snd_card *card = container_of(dev, struct snd_card, card_dev); return scnprintf(buf, PAGE_SIZE, "%i\n", card->number); } -static DEVICE_ATTR(number, 0444, card_number_show_attr, NULL); +static DEVICE_ATTR_RO(number); static struct attribute *card_dev_attrs[] = { &dev_attr_id.attr, @@ -770,7 +770,8 @@ int snd_card_register(struct snd_card *card) card->registered = true; } - if ((err = snd_device_register_all(card)) < 0) + err = snd_device_register_all(card); + if (err < 0) return err; mutex_lock(&snd_card_mutex); if (snd_cards[card->number]) { @@ -813,7 +814,8 @@ static void snd_card_info_read(struct snd_info_entry *entry, for (idx = count = 0; idx < SNDRV_CARDS; idx++) { mutex_lock(&snd_card_mutex); - if ((card = snd_cards[idx]) != NULL) { + card = snd_cards[idx]; + if (card) { count++; snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n", idx, @@ -837,7 +839,8 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer) for (idx = count = 0; idx < SNDRV_CARDS; idx++) { mutex_lock(&snd_card_mutex); - if ((card = snd_cards[idx]) != NULL) { + card = snd_cards[idx]; + if (card) { count++; snd_iprintf(buffer, "%s\n", card->longname); } @@ -859,7 +862,8 @@ static void snd_card_module_info_read(struct snd_info_entry *entry, for (idx = 0; idx < SNDRV_CARDS; idx++) { mutex_lock(&snd_card_mutex); - if ((card = snd_cards[idx]) != NULL) + card = snd_cards[idx]; + if (card) snd_iprintf(buffer, "%2i %s\n", idx, card->module->name); mutex_unlock(&snd_card_mutex); @@ -1002,21 +1006,28 @@ EXPORT_SYMBOL(snd_card_file_remove); #ifdef CONFIG_PM /** - * snd_power_wait - wait until the power-state is changed. - * @card: soundcard structure - * @power_state: expected power state + * snd_power_ref_and_wait - wait until the card gets powered up + * @card: soundcard structure + * + * Take the power_ref reference count of the given card, and + * wait until the card gets powered up to SNDRV_CTL_POWER_D0 state. + * The refcount is down again while sleeping until power-up, hence this + * function can be used for syncing the floating control ops accesses, + * typically around calling control ops. * - * Waits until the power-state is changed. + * The caller needs to pull down the refcount via snd_power_unref() later + * no matter whether the error is returned from this function or not. * - * Return: Zero if successful, or a negative error code. + * Return: Zero if successful, or a negative error code. */ -int snd_power_wait(struct snd_card *card, unsigned int power_state) +int snd_power_ref_and_wait(struct snd_card *card) { wait_queue_entry_t wait; int result = 0; + snd_power_ref(card); /* fastpath */ - if (snd_power_get_state(card) == power_state) + if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0) return 0; init_waitqueue_entry(&wait, current); add_wait_queue(&card->power_sleep, &wait); @@ -1025,13 +1036,33 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state) result = -ENODEV; break; } - if (snd_power_get_state(card) == power_state) + if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0) break; + snd_power_unref(card); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(30 * HZ); + snd_power_ref(card); } remove_wait_queue(&card->power_sleep, &wait); return result; } +EXPORT_SYMBOL_GPL(snd_power_ref_and_wait); + +/** + * snd_power_wait - wait until the card gets powered up (old form) + * @card: soundcard structure + * + * Wait until the card gets powered up to SNDRV_CTL_POWER_D0 state. + * + * Return: Zero if successful, or a negative error code. + */ +int snd_power_wait(struct snd_card *card) +{ + int ret; + + ret = snd_power_ref_and_wait(card); + snd_power_unref(card); + return ret; +} EXPORT_SYMBOL(snd_power_wait); #endif /* CONFIG_PM */ diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 966bef5acc75..83b79edfa52d 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -15,99 +15,27 @@ #include <asm/set_memory.h> #endif #include <sound/memalloc.h> +#include "memalloc_local.h" -/* - * - * Bus-specific memory allocators - * - */ - -#ifdef CONFIG_HAS_DMA -/* allocate the coherent DMA pages */ -static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size) -{ - gfp_t gfp_flags; +static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab); - gfp_flags = GFP_KERNEL - | __GFP_COMP /* compound page lets parts be mapped */ - | __GFP_NORETRY /* don't trigger OOM-killer */ - | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ - dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, - gfp_flags); -#ifdef CONFIG_X86 - if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) - set_memory_wc((unsigned long)dmab->area, - PAGE_ALIGN(size) >> PAGE_SHIFT); -#endif -} - -/* free the coherent DMA pages */ -static void snd_free_dev_pages(struct snd_dma_buffer *dmab) -{ -#ifdef CONFIG_X86 - if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) - set_memory_wb((unsigned long)dmab->area, - PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT); -#endif - dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); -} - -#ifdef CONFIG_GENERIC_ALLOCATOR -/** - * snd_malloc_dev_iram - allocate memory from on-chip internal ram - * @dmab: buffer allocation record to store the allocated data - * @size: number of bytes to allocate from the iram - * - * This function requires iram phandle provided via of_node - */ -static void snd_malloc_dev_iram(struct snd_dma_buffer *dmab, size_t size) +/* a cast to gfp flag from the dev pointer; for CONTINUOUS and VMALLOC types */ +static inline gfp_t snd_mem_get_gfp_flags(const struct snd_dma_buffer *dmab, + gfp_t default_gfp) { - struct device *dev = dmab->dev.dev; - struct gen_pool *pool = NULL; - - dmab->area = NULL; - dmab->addr = 0; - - if (dev->of_node) - pool = of_gen_pool_get(dev->of_node, "iram", 0); - - if (!pool) - return; - - /* Assign the pool into private_data field */ - dmab->private_data = pool; - - dmab->area = gen_pool_dma_alloc_align(pool, size, &dmab->addr, - PAGE_SIZE); + if (!dmab->dev.dev) + return default_gfp; + else + return (__force gfp_t)(unsigned long)dmab->dev.dev; } -/** - * snd_free_dev_iram - free allocated specific memory from on-chip internal ram - * @dmab: buffer allocation record to store the allocated data - */ -static void snd_free_dev_iram(struct snd_dma_buffer *dmab) +static int __snd_dma_alloc_pages(struct snd_dma_buffer *dmab, size_t size) { - struct gen_pool *pool = dmab->private_data; - - if (pool && dmab->area) - gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes); -} -#endif /* CONFIG_GENERIC_ALLOCATOR */ -#endif /* CONFIG_HAS_DMA */ - -/* - * - * ALSA generic memory management - * - */ + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); -static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev, - gfp_t default_gfp) -{ - if (!dev) - return default_gfp; - else - return (__force gfp_t)(unsigned long)dev; + if (WARN_ON_ONCE(!ops || !ops->alloc)) + return -EINVAL; + return ops->alloc(dmab, size); } /** @@ -126,7 +54,7 @@ static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev, int snd_dma_alloc_pages(int type, struct device *device, size_t size, struct snd_dma_buffer *dmab) { - gfp_t gfp; + int err; if (WARN_ON(!size)) return -ENXIO; @@ -140,43 +68,10 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->area = NULL; dmab->addr = 0; dmab->private_data = NULL; - switch (type) { - case SNDRV_DMA_TYPE_CONTINUOUS: - gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL); - dmab->area = alloc_pages_exact(size, gfp); - break; - case SNDRV_DMA_TYPE_VMALLOC: - gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL | __GFP_HIGHMEM); - dmab->area = __vmalloc(size, gfp); - break; -#ifdef CONFIG_HAS_DMA -#ifdef CONFIG_GENERIC_ALLOCATOR - case SNDRV_DMA_TYPE_DEV_IRAM: - snd_malloc_dev_iram(dmab, size); - if (dmab->area) - break; - /* Internal memory might have limited size and no enough space, - * so if we fail to malloc, try to fetch memory traditionally. - */ - dmab->dev.type = SNDRV_DMA_TYPE_DEV; - fallthrough; -#endif /* CONFIG_GENERIC_ALLOCATOR */ - case SNDRV_DMA_TYPE_DEV: - case SNDRV_DMA_TYPE_DEV_UC: - snd_malloc_dev_pages(dmab, size); - break; -#endif -#ifdef CONFIG_SND_DMA_SGBUF - case SNDRV_DMA_TYPE_DEV_SG: - case SNDRV_DMA_TYPE_DEV_UC_SG: - snd_malloc_sgbuf_pages(device, size, dmab, NULL); - break; -#endif - default: - pr_err("snd-malloc: invalid device type %d\n", type); - return -ENXIO; - } - if (! dmab->area) + err = __snd_dma_alloc_pages(dmab, size); + if (err < 0) + return err; + if (!dmab->area) return -ENOMEM; dmab->bytes = size; return 0; @@ -217,7 +112,6 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, } EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); - /** * snd_dma_free_pages - release the allocated buffer * @dmab: the buffer allocation record to release @@ -226,32 +120,288 @@ EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); */ void snd_dma_free_pages(struct snd_dma_buffer *dmab) { - switch (dmab->dev.type) { - case SNDRV_DMA_TYPE_CONTINUOUS: - free_pages_exact(dmab->area, dmab->bytes); - break; - case SNDRV_DMA_TYPE_VMALLOC: - vfree(dmab->area); - break; + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); + + if (ops && ops->free) + ops->free(dmab); +} +EXPORT_SYMBOL(snd_dma_free_pages); + +/** + * snd_dma_buffer_mmap - perform mmap of the given DMA buffer + * @dmab: buffer allocation information + * @area: VM area information + */ +int snd_dma_buffer_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); + + if (ops && ops->mmap) + return ops->mmap(dmab, area); + else + return -ENOENT; +} +EXPORT_SYMBOL(snd_dma_buffer_mmap); + +/** + * snd_sgbuf_get_addr - return the physical address at the corresponding offset + * @dmab: buffer allocation information + * @offset: offset in the ring buffer + */ +dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab, size_t offset) +{ + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); + + if (ops && ops->get_addr) + return ops->get_addr(dmab, offset); + else + return dmab->addr + offset; +} +EXPORT_SYMBOL(snd_sgbuf_get_addr); + +/** + * snd_sgbuf_get_page - return the physical page at the corresponding offset + * @dmab: buffer allocation information + * @offset: offset in the ring buffer + */ +struct page *snd_sgbuf_get_page(struct snd_dma_buffer *dmab, size_t offset) +{ + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); + + if (ops && ops->get_page) + return ops->get_page(dmab, offset); + else + return virt_to_page(dmab->area + offset); +} +EXPORT_SYMBOL(snd_sgbuf_get_page); + +/** + * snd_sgbuf_get_chunk_size - compute the max chunk size with continuous pages + * on sg-buffer + * @dmab: buffer allocation information + * @ofs: offset in the ring buffer + * @size: the requested size + */ +unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab, + unsigned int ofs, unsigned int size) +{ + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); + + if (ops && ops->get_chunk_size) + return ops->get_chunk_size(dmab, ofs, size); + else + return size; +} +EXPORT_SYMBOL(snd_sgbuf_get_chunk_size); + +/* + * Continuous pages allocator + */ +static int snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL); + + dmab->area = alloc_pages_exact(size, gfp); + return 0; +} + +static void snd_dma_continuous_free(struct snd_dma_buffer *dmab) +{ + free_pages_exact(dmab->area, dmab->bytes); +} + +static int snd_dma_continuous_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + return remap_pfn_range(area, area->vm_start, + dmab->addr >> PAGE_SHIFT, + area->vm_end - area->vm_start, + area->vm_page_prot); +} + +static const struct snd_malloc_ops snd_dma_continuous_ops = { + .alloc = snd_dma_continuous_alloc, + .free = snd_dma_continuous_free, + .mmap = snd_dma_continuous_mmap, +}; + +/* + * VMALLOC allocator + */ +static int snd_dma_vmalloc_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL | __GFP_HIGHMEM); + + dmab->area = __vmalloc(size, gfp); + return 0; +} + +static void snd_dma_vmalloc_free(struct snd_dma_buffer *dmab) +{ + vfree(dmab->area); +} + +static int snd_dma_vmalloc_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + return remap_vmalloc_range(area, dmab->area, 0); +} + +static dma_addr_t snd_dma_vmalloc_get_addr(struct snd_dma_buffer *dmab, + size_t offset) +{ + return page_to_phys(vmalloc_to_page(dmab->area + offset)) + + offset % PAGE_SIZE; +} + +static struct page *snd_dma_vmalloc_get_page(struct snd_dma_buffer *dmab, + size_t offset) +{ + return vmalloc_to_page(dmab->area + offset); +} + +static unsigned int +snd_dma_vmalloc_get_chunk_size(struct snd_dma_buffer *dmab, + unsigned int ofs, unsigned int size) +{ + ofs %= PAGE_SIZE; + size += ofs; + if (size > PAGE_SIZE) + size = PAGE_SIZE; + return size - ofs; +} + +static const struct snd_malloc_ops snd_dma_vmalloc_ops = { + .alloc = snd_dma_vmalloc_alloc, + .free = snd_dma_vmalloc_free, + .mmap = snd_dma_vmalloc_mmap, + .get_addr = snd_dma_vmalloc_get_addr, + .get_page = snd_dma_vmalloc_get_page, + .get_chunk_size = snd_dma_vmalloc_get_chunk_size, +}; + #ifdef CONFIG_HAS_DMA +/* + * IRAM allocator + */ #ifdef CONFIG_GENERIC_ALLOCATOR - case SNDRV_DMA_TYPE_DEV_IRAM: - snd_free_dev_iram(dmab); - break; +static int snd_dma_iram_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + struct device *dev = dmab->dev.dev; + struct gen_pool *pool; + + if (dev->of_node) { + pool = of_gen_pool_get(dev->of_node, "iram", 0); + /* Assign the pool into private_data field */ + dmab->private_data = pool; + + dmab->area = gen_pool_dma_alloc_align(pool, size, &dmab->addr, + PAGE_SIZE); + if (dmab->area) + return 0; + } + + /* Internal memory might have limited size and no enough space, + * so if we fail to malloc, try to fetch memory traditionally. + */ + dmab->dev.type = SNDRV_DMA_TYPE_DEV; + return __snd_dma_alloc_pages(dmab, size); +} + +static void snd_dma_iram_free(struct snd_dma_buffer *dmab) +{ + struct gen_pool *pool = dmab->private_data; + + if (pool && dmab->area) + gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes); +} + +static int snd_dma_iram_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); + return remap_pfn_range(area, area->vm_start, + dmab->addr >> PAGE_SHIFT, + area->vm_end - area->vm_start, + area->vm_page_prot); +} + +static const struct snd_malloc_ops snd_dma_iram_ops = { + .alloc = snd_dma_iram_alloc, + .free = snd_dma_iram_free, + .mmap = snd_dma_iram_mmap, +}; #endif /* CONFIG_GENERIC_ALLOCATOR */ - case SNDRV_DMA_TYPE_DEV: - case SNDRV_DMA_TYPE_DEV_UC: - snd_free_dev_pages(dmab); - break; + +/* + * Coherent device pages allocator + */ +static int snd_dma_dev_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + gfp_t gfp_flags; + + gfp_flags = GFP_KERNEL + | __GFP_COMP /* compound page lets parts be mapped */ + | __GFP_NORETRY /* don't trigger OOM-killer */ + | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ + dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, + gfp_flags); +#ifdef CONFIG_X86 + if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) + set_memory_wc((unsigned long)dmab->area, + PAGE_ALIGN(size) >> PAGE_SHIFT); #endif + return 0; +} + +static void snd_dma_dev_free(struct snd_dma_buffer *dmab) +{ +#ifdef CONFIG_X86 + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) + set_memory_wb((unsigned long)dmab->area, + PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT); +#endif + dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); +} + +static int snd_dma_dev_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + return dma_mmap_coherent(dmab->dev.dev, area, + dmab->area, dmab->addr, dmab->bytes); +} + +static const struct snd_malloc_ops snd_dma_dev_ops = { + .alloc = snd_dma_dev_alloc, + .free = snd_dma_dev_free, + .mmap = snd_dma_dev_mmap, +}; +#endif /* CONFIG_HAS_DMA */ + +/* + * Entry points + */ +static const struct snd_malloc_ops *dma_ops[] = { + [SNDRV_DMA_TYPE_CONTINUOUS] = &snd_dma_continuous_ops, + [SNDRV_DMA_TYPE_VMALLOC] = &snd_dma_vmalloc_ops, +#ifdef CONFIG_HAS_DMA + [SNDRV_DMA_TYPE_DEV] = &snd_dma_dev_ops, + [SNDRV_DMA_TYPE_DEV_UC] = &snd_dma_dev_ops, +#ifdef CONFIG_GENERIC_ALLOCATOR + [SNDRV_DMA_TYPE_DEV_IRAM] = &snd_dma_iram_ops, +#endif /* CONFIG_GENERIC_ALLOCATOR */ +#endif /* CONFIG_HAS_DMA */ #ifdef CONFIG_SND_DMA_SGBUF - case SNDRV_DMA_TYPE_DEV_SG: - case SNDRV_DMA_TYPE_DEV_UC_SG: - snd_free_sgbuf_pages(dmab); - break; + [SNDRV_DMA_TYPE_DEV_SG] = &snd_dma_sg_ops, + [SNDRV_DMA_TYPE_DEV_UC_SG] = &snd_dma_sg_ops, #endif - default: - pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type); - } +}; + +static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab) +{ + if (WARN_ON_ONCE(dmab->dev.type <= SNDRV_DMA_TYPE_UNKNOWN || + dmab->dev.type >= ARRAY_SIZE(dma_ops))) + return NULL; + return dma_ops[dmab->dev.type]; } -EXPORT_SYMBOL(snd_dma_free_pages); diff --git a/sound/core/memalloc_local.h b/sound/core/memalloc_local.h new file mode 100644 index 000000000000..dbea7f2aed07 --- /dev/null +++ b/sound/core/memalloc_local.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-only +#ifndef __MEMALLOC_LOCAL_H +#define __MEMALLOC_LOCAL_H + +struct snd_malloc_ops { + int (*alloc)(struct snd_dma_buffer *dmab, size_t size); + void (*free)(struct snd_dma_buffer *dmab); + dma_addr_t (*get_addr)(struct snd_dma_buffer *dmab, size_t offset); + struct page *(*get_page)(struct snd_dma_buffer *dmab, size_t offset); + unsigned int (*get_chunk_size)(struct snd_dma_buffer *dmab, + unsigned int ofs, unsigned int size); + int (*mmap)(struct snd_dma_buffer *dmab, struct vm_area_struct *area); +}; + +#ifdef CONFIG_SND_DMA_SGBUF +extern const struct snd_malloc_ops snd_dma_sg_ops; +#endif + +#endif /* __MEMALLOC_LOCAL_H */ diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index bec928327478..6a5abdd4271b 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -185,7 +185,8 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer) if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */ int err; unsigned int index; - if ((err = mixer->get_recsrc(fmixer, &index)) < 0) + err = mixer->get_recsrc(fmixer, &index); + if (err < 0) return err; result = 1 << index; } else { @@ -517,7 +518,8 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) { up_read(&card->controls_rwsem); return; } @@ -555,7 +557,8 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) { up_read(&card->controls_rwsem); return; } @@ -620,7 +623,8 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) { up_read(&card->controls_rwsem); return; } @@ -636,7 +640,8 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max); if (uinfo->count > 1) uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max); - if ((res = kctl->put(kctl, uctl)) < 0) + res = kctl->put(kctl, uctl); + if (res < 0) goto __unalloc; if (res > 0) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); @@ -661,7 +666,8 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) { up_read(&card->controls_rwsem); return; } @@ -681,7 +687,8 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, } else { uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0; } - if ((res = kctl->put(kctl, uctl)) < 0) + res = kctl->put(kctl, uctl); + if (res < 0) goto __unalloc; if (res > 0) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); @@ -809,9 +816,11 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned err = -ENOENT; goto __unlock; } - if ((err = kctl->info(kctl, uinfo)) < 0) + err = kctl->info(kctl, uinfo); + if (err < 0) goto __unlock; - if ((err = kctl->get(kctl, uctl)) < 0) + err = kctl->get(kctl, uctl); + if (err < 0) goto __unlock; for (idx = 0; idx < 32; idx++) { if (!(mixer->mask_recsrc & (1 << idx))) @@ -860,7 +869,8 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned err = -ENOENT; goto __unlock; } - if ((err = kctl->info(kctl, uinfo)) < 0) + err = kctl->info(kctl, uinfo); + if (err < 0) goto __unlock; for (idx = 0; idx < 32; idx++) { if (!(mixer->mask_recsrc & (1 << idx))) @@ -915,7 +925,8 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl up_read(&card->controls_rwsem); return -ENOMEM; } - if ((err = kcontrol->info(kcontrol, info)) < 0) { + err = kcontrol->info(kcontrol, info); + if (err < 0) { up_read(&card->controls_rwsem); kfree(info); return err; @@ -1036,7 +1047,10 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, if (snd_mixer_oss_build_test_all(mixer, ptr, &slot)) return 0; down_read(&mixer->card->controls_rwsem); - if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) { + kctl = NULL; + if (!ptr->index) + kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); + if (kctl) { struct snd_ctl_elem_info *uinfo; uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); @@ -1343,9 +1357,10 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd) if (mixer == NULL) return -ENOMEM; mutex_init(&mixer->reg_mutex); - if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, - card, 0, - &snd_mixer_oss_f_ops, card)) < 0) { + err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, + card, 0, + &snd_mixer_oss_f_ops, card); + if (err < 0) { dev_err(card->dev, "unable to register OSS mixer device %i:%i\n", card->number, 0); diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 86c39ee01aaa..82a818734a5f 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -955,9 +955,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) if (!direct) { /* add necessary plugins */ snd_pcm_oss_plugin_clear(substream); - if ((err = snd_pcm_plug_format_plugins(substream, - params, - sparams)) < 0) { + err = snd_pcm_plug_format_plugins(substream, params, sparams); + if (err < 0) { pcm_dbg(substream->pcm, "snd_pcm_plug_format_plugins failed: %i\n", err); snd_pcm_oss_plugin_clear(substream); @@ -965,7 +964,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) } if (runtime->oss.plugin_first) { struct snd_pcm_plugin *plugin; - if ((err = snd_pcm_plugin_build_io(substream, sparams, &plugin)) < 0) { + err = snd_pcm_plugin_build_io(substream, sparams, &plugin); + if (err < 0) { pcm_dbg(substream->pcm, "snd_pcm_plugin_build_io failed: %i\n", err); snd_pcm_oss_plugin_clear(substream); @@ -1011,7 +1011,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) sw_params->silence_size = frames; } - if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) { + err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params); + if (err < 0) { pcm_dbg(substream->pcm, "SW_PARAMS failed: %i\n", err); goto failure; } @@ -1573,7 +1574,8 @@ static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file) substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream != NULL) { - if ((err = snd_pcm_oss_make_ready(substream)) < 0) + err = snd_pcm_oss_make_ready(substream); + if (err < 0) return err; snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL); } @@ -1645,7 +1647,8 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) runtime = substream->runtime; if (atomic_read(&substream->mmap_count)) goto __direct; - if ((err = snd_pcm_oss_make_ready(substream)) < 0) + err = snd_pcm_oss_make_ready(substream); + if (err < 0) return err; atomic_inc(&runtime->oss.rw_ref); if (mutex_lock_interruptible(&runtime->oss.params_lock)) { @@ -1711,7 +1714,8 @@ unlock: substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (substream != NULL) { - if ((err = snd_pcm_oss_make_ready(substream)) < 0) + err = snd_pcm_oss_make_ready(substream); + if (err < 0) return err; runtime = substream->runtime; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); @@ -1758,7 +1762,8 @@ static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) + err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream); + if (err < 0) return err; return substream->runtime->oss.rate; } @@ -1795,7 +1800,8 @@ static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) + err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream); + if (err < 0) return err; return substream->runtime->oss.channels; } @@ -1805,7 +1811,8 @@ static int snd_pcm_oss_get_block_size(struct snd_pcm_oss_file *pcm_oss_file) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) + err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream); + if (err < 0) return err; return substream->runtime->oss.period_bytes; } @@ -1820,7 +1827,8 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) const struct snd_mask *format_mask; int fmt; - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) + err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream); + if (err < 0) return err; if (atomic_read(&substream->mmap_count)) direct = 1; @@ -1890,7 +1898,8 @@ static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) + err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream); + if (err < 0) return err; return substream->runtime->oss.format; } @@ -2050,11 +2059,13 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (psubstream) { - if ((err = snd_pcm_oss_make_ready(psubstream)) < 0) + err = snd_pcm_oss_make_ready(psubstream); + if (err < 0) return err; } if (csubstream) { - if ((err = snd_pcm_oss_make_ready(csubstream)) < 0) + err = snd_pcm_oss_make_ready(csubstream); + if (err < 0) return err; } if (psubstream) { @@ -2141,7 +2152,8 @@ static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file) substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream == NULL) return -EINVAL; - if ((err = snd_pcm_oss_make_ready(substream)) < 0) + err = snd_pcm_oss_make_ready(substream); + if (err < 0) return err; runtime = substream->runtime; if (runtime->oss.params || runtime->oss.prepare) @@ -2168,7 +2180,8 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream substream = pcm_oss_file->streams[stream]; if (substream == NULL) return -EINVAL; - if ((err = snd_pcm_oss_make_ready(substream)) < 0) + err = snd_pcm_oss_make_ready(substream); + if (err < 0) return err; runtime = substream->runtime; if (runtime->oss.params || runtime->oss.prepare) { @@ -2239,9 +2252,11 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre return -EINVAL; runtime = substream->runtime; - if (runtime->oss.params && - (err = snd_pcm_oss_change_params(substream, false)) < 0) - return err; + if (runtime->oss.params) { + err = snd_pcm_oss_change_params(substream, false); + if (err < 0) + return err; + } info.fragsize = runtime->oss.period_bytes; info.fragstotal = runtime->periods; @@ -2601,7 +2616,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long case SNDCTL_DSP_SPEED: if (get_user(res, p)) return -EFAULT; - if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0) + 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: @@ -2613,7 +2629,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long if (get_user(res, p)) return -EFAULT; res = res > 0 ? 2 : 1; - if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0) + res = snd_pcm_oss_set_channels(pcm_oss_file, res); + if (res < 0) return res; return put_user(--res, p); case SNDCTL_DSP_GETBLKSIZE: @@ -2829,7 +2846,8 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait) snd_pcm_state_t ostate; poll_wait(file, &runtime->sleep, wait); snd_pcm_stream_lock_irq(csubstream); - if ((ostate = runtime->status->state) != SNDRV_PCM_STATE_RUNNING || + ostate = runtime->status->state; + if (ostate != SNDRV_PCM_STATE_RUNNING || snd_pcm_oss_capture_ready(csubstream)) mask |= EPOLLIN | EPOLLRDNORM; snd_pcm_stream_unlock_irq(csubstream); @@ -3043,7 +3061,8 @@ static void snd_pcm_oss_proc_init(struct snd_pcm *pcm) struct snd_pcm_str *pstr = &pcm->streams[stream]; if (pstr->substream_count == 0) continue; - if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) { + entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root); + if (entry) { entry->content = SNDRV_INFO_CONTENT_TEXT; entry->mode = S_IFREG | 0644; entry->c.text.read = snd_pcm_oss_proc_read; @@ -3191,7 +3210,8 @@ static int __init alsa_pcm_oss_init(void) adsp_map[i] = 1; } } - if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0) + err = snd_pcm_notify(&snd_pcm_oss_notify, 0); + if (err < 0) return err; return 0; } diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index d5ca161d588c..061ba06bc926 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -59,7 +59,8 @@ static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t } else { format = &plugin->dst_format; } - if ((width = snd_pcm_format_physical_width(format->format)) < 0) + width = snd_pcm_format_physical_width(format->format); + if (width < 0) return width; size = frames * format->channels * width; if (snd_BUG_ON(size % 8)) @@ -572,7 +573,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plu } v = plugin->buf_channels; *channels = v; - if ((width = snd_pcm_format_physical_width(format->format)) < 0) + width = snd_pcm_format_physical_width(format->format); + if (width < 0) return width; nchannels = format->channels; if (snd_BUG_ON(plugin->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && @@ -600,16 +602,17 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st while (plugin) { if (frames <= 0) return frames; - if ((next = plugin->next) != NULL) { + next = plugin->next; + if (next) { snd_pcm_sframes_t frames1 = frames; if (plugin->dst_frames) { frames1 = plugin->dst_frames(plugin, frames); if (frames1 <= 0) return frames1; } - if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) { + err = next->client_channels(next, frames1, &dst_channels); + if (err < 0) return err; - } if (err != frames1) { frames = err; if (plugin->src_frames) { @@ -621,7 +624,8 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st } else dst_channels = NULL; pdprintf("write plugin: %s, %li\n", plugin->name, frames); - if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) + frames = plugin->transfer(plugin, src_channels, dst_channels, frames); + if (frames < 0) return frames; src_channels = dst_channels; plugin = next; @@ -643,16 +647,18 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str src_channels = NULL; plugin = snd_pcm_plug_first(plug); while (plugin && frames > 0) { - if ((next = plugin->next) != NULL) { - if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) { + next = plugin->next; + if (next) { + err = plugin->client_channels(plugin, frames, &dst_channels); + if (err < 0) return err; - } frames = err; } else { dst_channels = dst_channels_final; } pdprintf("read plugin: %s, %li\n", plugin->name, frames); - if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) + frames = plugin->transfer(plugin, src_channels, dst_channels, frames); + if (frames < 0) return frames; plugin = next; src_channels = dst_channels; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index b163164a83ec..6fd3677685d7 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1004,7 +1004,7 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) substream->pstr->substream_opened--; } -static ssize_t show_pcm_class(struct device *dev, +static ssize_t pcm_class_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev); @@ -1024,7 +1024,7 @@ static ssize_t show_pcm_class(struct device *dev, return sprintf(buf, "%s\n", str); } -static DEVICE_ATTR(pcm_class, 0444, show_pcm_class, NULL); +static DEVICE_ATTR_RO(pcm_class); static struct attribute *pcm_dev_attrs[] = { &dev_attr_pcm_class.attr, NULL diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 590a46a9e78d..a59de24695ec 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -239,7 +239,8 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime; int err; - if (! (runtime = substream->runtime)) + runtime = substream->runtime; + if (!runtime) return -ENOTTY; data = kmalloc(sizeof(*data), GFP_KERNEL); @@ -343,7 +344,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; - if ((ch = substream->runtime->channels) > 128) + ch = substream->runtime->channels; + if (ch > 128) return -EINVAL; if (get_user(buf, &data32->bufs) || get_user(frames, &data32->frames)) diff --git a/sound/core/pcm_iec958.c b/sound/core/pcm_iec958.c index f9a211cc1f2c..7a1b816f67cc 100644 --- a/sound/core/pcm_iec958.c +++ b/sound/core/pcm_iec958.c @@ -9,41 +9,85 @@ #include <sound/pcm_params.h> #include <sound/pcm_iec958.h> -static int create_iec958_consumer(uint rate, uint sample_width, - u8 *cs, size_t len) +/** + * snd_pcm_create_iec958_consumer_default - create default consumer format IEC958 channel status + * @cs: channel status buffer, at least four bytes + * @len: length of channel status buffer + * + * Create the consumer format channel status data in @cs of maximum size + * @len. When relevant, the configuration-dependant bits will be set as + * unspecified. + * + * Drivers should then call einter snd_pcm_fill_iec958_consumer() or + * snd_pcm_fill_iec958_consumer_hw_params() to replace these unspecified + * bits by their actual values. + * + * Drivers may wish to tweak the contents of the buffer after creation. + * + * Returns: length of buffer, or negative error code if something failed. + */ +int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len) { - unsigned int fs, ws; - if (len < 4) return -EINVAL; - switch (rate) { - case 32000: - fs = IEC958_AES3_CON_FS_32000; - break; - case 44100: - fs = IEC958_AES3_CON_FS_44100; - break; - case 48000: - fs = IEC958_AES3_CON_FS_48000; - break; - case 88200: - fs = IEC958_AES3_CON_FS_88200; - break; - case 96000: - fs = IEC958_AES3_CON_FS_96000; - break; - case 176400: - fs = IEC958_AES3_CON_FS_176400; - break; - case 192000: - fs = IEC958_AES3_CON_FS_192000; - break; - default: + memset(cs, 0, len); + + cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; + cs[1] = IEC958_AES1_CON_GENERAL; + cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; + cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID; + + if (len > 4) + cs[4] = IEC958_AES4_CON_WORDLEN_NOTID; + + return len; +} +EXPORT_SYMBOL_GPL(snd_pcm_create_iec958_consumer_default); + +static int fill_iec958_consumer(uint rate, uint sample_width, + u8 *cs, size_t len) +{ + if (len < 4) return -EINVAL; + + if ((cs[3] & IEC958_AES3_CON_FS) == IEC958_AES3_CON_FS_NOTID) { + unsigned int fs; + + switch (rate) { + case 32000: + fs = IEC958_AES3_CON_FS_32000; + break; + case 44100: + fs = IEC958_AES3_CON_FS_44100; + break; + case 48000: + fs = IEC958_AES3_CON_FS_48000; + break; + case 88200: + fs = IEC958_AES3_CON_FS_88200; + break; + case 96000: + fs = IEC958_AES3_CON_FS_96000; + break; + case 176400: + fs = IEC958_AES3_CON_FS_176400; + break; + case 192000: + fs = IEC958_AES3_CON_FS_192000; + break; + default: + return -EINVAL; + } + + cs[3] &= ~IEC958_AES3_CON_FS; + cs[3] |= fs; } - if (len > 4) { + if (len > 4 && + (cs[4] & IEC958_AES4_CON_WORDLEN) == IEC958_AES4_CON_WORDLEN_NOTID) { + unsigned int ws; + switch (sample_width) { case 16: ws = IEC958_AES4_CON_WORDLEN_20_16; @@ -64,20 +108,57 @@ static int create_iec958_consumer(uint rate, uint sample_width, default: return -EINVAL; } - } - memset(cs, 0, len); + cs[4] &= ~IEC958_AES4_CON_WORDLEN; + cs[4] |= ws; + } - cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; - cs[1] = IEC958_AES1_CON_GENERAL; - cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; - cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | fs; + return len; +} - if (len > 4) - cs[4] = ws; +/** + * snd_pcm_fill_iec958_consumer - Fill consumer format IEC958 channel status + * @runtime: pcm runtime structure with ->rate filled in + * @cs: channel status buffer, at least four bytes + * @len: length of channel status buffer + * + * Fill the unspecified bits in an IEC958 status bits array using the + * parameters of the PCM runtime @runtime. + * + * Drivers may wish to tweak the contents of the buffer after its been + * filled. + * + * Returns: length of buffer, or negative error code if something failed. + */ +int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime, + u8 *cs, size_t len) +{ + return fill_iec958_consumer(runtime->rate, + snd_pcm_format_width(runtime->format), + cs, len); +} +EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer); - return len; +/** + * snd_pcm_fill_iec958_consumer_hw_params - Fill consumer format IEC958 channel status + * @params: the hw_params instance for extracting rate and sample format + * @cs: channel status buffer, at least four bytes + * @len: length of channel status buffer + * + * Fill the unspecified bits in an IEC958 status bits array using the + * parameters of the PCM hardware parameters @params. + * + * Drivers may wish to tweak the contents of the buffer after its been + * filled.. + * + * Returns: length of buffer, or negative error code if something failed. + */ +int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, + u8 *cs, size_t len) +{ + return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); } +EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer_hw_params); /** * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status @@ -95,9 +176,13 @@ static int create_iec958_consumer(uint rate, uint sample_width, int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, size_t len) { - return create_iec958_consumer(runtime->rate, - snd_pcm_format_width(runtime->format), - cs, len); + int ret; + + ret = snd_pcm_create_iec958_consumer_default(cs, len); + if (ret < 0) + return ret; + + return snd_pcm_fill_iec958_consumer(runtime, cs, len); } EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); @@ -117,7 +202,12 @@ EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, u8 *cs, size_t len) { - return create_iec958_consumer(params_rate(params), params_width(params), - cs, len); + int ret; + + ret = snd_pcm_create_iec958_consumer_default(cs, len); + if (ret < 0) + return ret; + + return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); } EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b7e3d8f44511..7d5883432085 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1778,27 +1778,38 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, EXPORT_SYMBOL(snd_pcm_lib_ioctl); /** - * snd_pcm_period_elapsed - update the pcm status for the next period - * @substream: the pcm substream instance + * snd_pcm_period_elapsed_under_stream_lock() - update the status of runtime for the next period + * under acquired lock of PCM substream. + * @substream: the instance of pcm substream. + * + * This function is called when the batch of audio data frames as the same size as the period of + * buffer is already processed in audio data transmission. + * + * The call of function updates the status of runtime with the latest position of audio data + * transmission, checks overrun and underrun over buffer, awaken user processes from waiting for + * available audio data frames, sampling audio timestamp, and performs stop or drain the PCM + * substream according to configured threshold. + * + * The function is intended to use for the case that PCM driver operates audio data frames under + * acquired lock of PCM substream; e.g. in callback of any operation of &snd_pcm_ops in process + * context. In any interrupt context, it's preferrable to use ``snd_pcm_period_elapsed()`` instead + * since lock of PCM substream should be acquired in advance. * - * This function is called from the interrupt handler when the - * PCM has processed the period size. It will update the current - * pointer, wake up sleepers, etc. + * Developer should pay enough attention that some callbacks in &snd_pcm_ops are done by the call of + * function: * - * Even if more than one periods have elapsed since the last call, you - * have to call this only once. + * - .pointer - to retrieve current position of audio data transmission by frame count or XRUN state. + * - .trigger - with SNDRV_PCM_TRIGGER_STOP at XRUN or DRAINING state. + * - .get_time_info - to retrieve audio time stamp if needed. + * + * Even if more than one periods have elapsed since the last call, you have to call this only once. */ -void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) +void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime; - unsigned long flags; - if (snd_BUG_ON(!substream)) - return; - - snd_pcm_stream_lock_irqsave(substream, flags); if (PCM_RUNTIME_CHECK(substream)) - goto _unlock; + return; runtime = substream->runtime; if (!snd_pcm_running(substream) || @@ -1811,7 +1822,30 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) #endif _end: kill_fasync(&runtime->fasync, SIGIO, POLL_IN); - _unlock: +} +EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock); + +/** + * snd_pcm_period_elapsed() - update the status of runtime for the next period by acquiring lock of + * PCM substream. + * @substream: the instance of PCM substream. + * + * This function is mostly similar to ``snd_pcm_period_elapsed_under_stream_lock()`` except for + * acquiring lock of PCM substream voluntarily. + * + * It's typically called by any type of IRQ handler when hardware IRQ occurs to notify event that + * the batch of audio data frames as the same size as the period of buffer is already processed in + * audio data transmission. + */ +void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) +{ + unsigned long flags; + + if (snd_BUG_ON(!substream)) + return; + + snd_pcm_stream_lock_irqsave(substream, flags); + snd_pcm_period_elapsed_under_stream_lock(substream); snd_pcm_stream_unlock_irqrestore(substream, flags); } EXPORT_SYMBOL(snd_pcm_period_elapsed); diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h index e3b3558aeab6..fe9689b8a6a6 100644 --- a/sound/core/pcm_local.h +++ b/sound/core/pcm_local.h @@ -65,11 +65,6 @@ void __snd_pcm_xrun(struct snd_pcm_substream *substream); void snd_pcm_group_init(struct snd_pcm_group *group); void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq); -#ifdef CONFIG_SND_DMA_SGBUF -struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, - unsigned long offset); -#endif - #define PCM_RUNTIME_CHECK(sub) snd_BUG_ON(!(sub) || !(sub)->runtime) /* loop over all PCM substreams */ diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 542a75babdee..d7621ed105bd 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -337,27 +337,6 @@ void snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type, } EXPORT_SYMBOL(snd_pcm_set_managed_buffer_all); -#ifdef CONFIG_SND_DMA_SGBUF -/* - * snd_pcm_sgbuf_ops_page - get the page struct at the given offset - * @substream: the pcm substream instance - * @offset: the buffer offset - * - * Used as the page callback of PCM ops. - * - * Return: The page struct at the given buffer offset. %NULL on failure. - */ -struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset) -{ - struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); - - unsigned int idx = offset >> PAGE_SHIFT; - if (idx >= (unsigned int)sgbuf->pages) - return NULL; - return sgbuf->page_table[idx]; -} -#endif /* CONFIG_SND_DMA_SGBUF */ - /** * snd_pcm_lib_malloc_pages - allocate the DMA buffer * @substream: the substream to allocate the DMA buffer to diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 257d412eac5d..4866aed97aac 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -266,7 +266,8 @@ int snd_pcm_format_signed(snd_pcm_format_t format) int val; if (!valid_format(format)) return -EINVAL; - if ((val = pcm_formats[(INT)format].signd) < 0) + val = pcm_formats[(INT)format].signd; + if (val < 0) return -EINVAL; return val; } @@ -314,7 +315,8 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format) int val; if (!valid_format(format)) return -EINVAL; - if ((val = pcm_formats[(INT)format].le) < 0) + val = pcm_formats[(INT)format].le; + if (val < 0) return -EINVAL; return val; } @@ -350,7 +352,8 @@ int snd_pcm_format_width(snd_pcm_format_t format) int val; if (!valid_format(format)) return -EINVAL; - if ((val = pcm_formats[(INT)format].width) == 0) + val = pcm_formats[(INT)format].width; + if (!val) return -EINVAL; return val; } @@ -368,7 +371,8 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format) int val; if (!valid_format(format)) return -EINVAL; - if ((val = pcm_formats[(INT)format].phys) == 0) + val = pcm_formats[(INT)format].phys; + if (!val) return -EINVAL; return val; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8dbe86cf2e4f..14e32825c339 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -768,7 +768,8 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, if (cpu_latency_qos_request_active(&substream->latency_pm_qos_req)) cpu_latency_qos_remove_request(&substream->latency_pm_qos_req); - if ((usecs = period_to_usecs(runtime)) >= 0) + usecs = period_to_usecs(runtime); + if (usecs >= 0) cpu_latency_qos_add_request(&substream->latency_pm_qos_req, usecs); return 0; @@ -2658,7 +2659,8 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, goto error; } - if ((err = substream->ops->open(substream)) < 0) + err = substream->ops->open(substream); + if (err < 0) goto error; substream->hw_opened = 1; @@ -2799,6 +2801,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file) if (snd_BUG_ON(!substream)) return -ENXIO; pcm = substream->pcm; + + /* block until the device gets woken up as it may touch the hardware */ + snd_power_wait(pcm->card); + mutex_lock(&pcm->open_mutex); snd_pcm_release_substream(substream); kfree(pcm_file); @@ -3193,7 +3199,7 @@ static int snd_pcm_common_ioctl(struct file *file, if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; - res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0); + res = snd_power_wait(substream->pcm->card); if (res < 0) return res; @@ -3638,24 +3644,6 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file } #endif /* coherent mmap */ -static inline struct page * -snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) -{ - void *vaddr = substream->runtime->dma_area + ofs; - - switch (substream->dma_buffer.dev.type) { -#ifdef CONFIG_SND_DMA_SGBUF - case SNDRV_DMA_TYPE_DEV_SG: - case SNDRV_DMA_TYPE_DEV_UC_SG: - return snd_pcm_sgbuf_ops_page(substream, ofs); -#endif /* CONFIG_SND_DMA_SGBUF */ - case SNDRV_DMA_TYPE_VMALLOC: - return vmalloc_to_page(vaddr); - default: - return virt_to_page(vaddr); - } -} - /* * fault callback for mmapping a RAM page */ @@ -3677,7 +3665,7 @@ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf) if (substream->ops->page) page = substream->ops->page(substream, offset); else - page = snd_pcm_default_page_ops(substream, offset); + page = snd_sgbuf_get_page(snd_pcm_get_dma_buf(substream), offset); if (!page) return VM_FAULT_SIGBUS; get_page(page); @@ -3712,22 +3700,9 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *area) { area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; -#ifdef CONFIG_GENERIC_ALLOCATOR - if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_IRAM) { - area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); - return remap_pfn_range(area, area->vm_start, - substream->dma_buffer.addr >> PAGE_SHIFT, - area->vm_end - area->vm_start, area->vm_page_prot); - } -#endif /* CONFIG_GENERIC_ALLOCATOR */ - if (IS_ENABLED(CONFIG_HAS_DMA) && !substream->ops->page && - (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV || - substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_UC)) - return dma_mmap_coherent(substream->dma_buffer.dev.dev, - area, - substream->runtime->dma_area, - substream->runtime->dma_addr, - substream->runtime->dma_bytes); + if (!substream->ops->page && + !snd_dma_buffer_mmap(snd_pcm_get_dma_buf(substream), area)) + return 0; /* mmap with fault handler */ area->vm_ops = &snd_pcm_vm_ops_data_fault; return 0; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index aca00af93afe..6c0a4a67ad2e 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -680,9 +680,12 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, bool is_input) { char *newbuf, *oldbuf; + unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK; if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) return -EINVAL; + if (framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP && (params->buffer_size & 0x1f) != 0) + return -EINVAL; if (params->avail_min < 1 || params->avail_min > params->buffer_size) return -EINVAL; if (params->buffer_size != runtime->buffer_size) { @@ -720,8 +723,24 @@ EXPORT_SYMBOL(snd_rawmidi_output_params); int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params *params) { + unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK; + unsigned int clock_type = params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK; + int err; + + if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE) + return -EINVAL; + else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW) + return -EINVAL; + if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) + return -EINVAL; snd_rawmidi_drain_input(substream); - return resize_runtime_buffer(substream->runtime, params, true); + err = resize_runtime_buffer(substream->runtime, params, true); + if (err < 0) + return err; + + substream->framing = framing; + substream->clock_type = clock_type; + return 0; } EXPORT_SYMBOL(snd_rawmidi_input_params); @@ -963,6 +982,62 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, return -ENOIOCTLCMD; } +static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream, + const unsigned char *buffer, int src_count, const struct timespec64 *tstamp) +{ + struct snd_rawmidi_runtime *runtime = substream->runtime; + struct snd_rawmidi_framing_tstamp *dest_ptr; + struct snd_rawmidi_framing_tstamp frame = { .tv_sec = tstamp->tv_sec, .tv_nsec = tstamp->tv_nsec }; + int dest_frames = 0; + int orig_count = src_count; + int frame_size = sizeof(struct snd_rawmidi_framing_tstamp); + + BUILD_BUG_ON(frame_size != 0x20); + if (snd_BUG_ON((runtime->hw_ptr & 0x1f) != 0)) + return -EINVAL; + + while (src_count > 0) { + if ((int)(runtime->buffer_size - runtime->avail) < frame_size) { + runtime->xruns += src_count; + break; + } + if (src_count >= SNDRV_RAWMIDI_FRAMING_DATA_LENGTH) + frame.length = SNDRV_RAWMIDI_FRAMING_DATA_LENGTH; + else { + frame.length = src_count; + memset(frame.data, 0, SNDRV_RAWMIDI_FRAMING_DATA_LENGTH); + } + memcpy(frame.data, buffer, frame.length); + buffer += frame.length; + src_count -= frame.length; + dest_ptr = (struct snd_rawmidi_framing_tstamp *) (runtime->buffer + runtime->hw_ptr); + *dest_ptr = frame; + runtime->avail += frame_size; + runtime->hw_ptr += frame_size; + runtime->hw_ptr %= runtime->buffer_size; + dest_frames++; + } + return orig_count - src_count; +} + +static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substream) +{ + struct timespec64 ts64 = {0, 0}; + + switch (substream->clock_type) { + case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW: + ktime_get_raw_ts64(&ts64); + break; + case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC: + ktime_get_ts64(&ts64); + break; + case SNDRV_RAWMIDI_MODE_CLOCK_REALTIME: + ktime_get_real_ts64(&ts64); + break; + } + return ts64; +} + /** * snd_rawmidi_receive - receive the input data from the device * @substream: the rawmidi substream @@ -977,6 +1052,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, const unsigned char *buffer, int count) { unsigned long flags; + struct timespec64 ts64 = get_framing_tstamp(substream); int result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -987,8 +1063,11 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, "snd_rawmidi_receive: input is not active!!!\n"); return -EINVAL; } + spin_lock_irqsave(&runtime->lock, flags); - if (count == 1) { /* special case, faster code */ + if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { + result = receive_with_tstamp_framing(substream, buffer, count, &ts64); + } else if (count == 1) { /* special case, faster code */ substream->bytes++; if (runtime->avail < runtime->buffer_size) { runtime->buffer[runtime->hw_ptr++] = buffer[0]; @@ -1541,6 +1620,8 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, struct snd_rawmidi_substream *substream; struct snd_rawmidi_runtime *runtime; unsigned long buffer_size, avail, xruns; + unsigned int clock_type; + static const char *clock_names[4] = { "none", "realtime", "monotonic", "monotonic raw" }; rmidi = entry->private_data; snd_iprintf(buffer, "%s\n\n", rmidi->name); @@ -1596,6 +1677,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Avail : %lu\n" " Overruns : %lu\n", buffer_size, avail, xruns); + if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { + clock_type = substream->clock_type >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT; + if (!snd_BUG_ON(clock_type >= ARRAY_SIZE(clock_names))) + snd_iprintf(buffer, + " Framing : tstamp\n" + " Clock type : %s\n", + clock_names[clock_type]); + } } } } diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c index 7397130976d0..68a93443583c 100644 --- a/sound/core/rawmidi_compat.c +++ b/sound/core/rawmidi_compat.c @@ -13,7 +13,8 @@ struct snd_rawmidi_params32 { u32 buffer_size; u32 avail_min; unsigned int no_active_sensing; /* avoid bit-field */ - unsigned char reserved[16]; + unsigned int mode; + unsigned char reserved[12]; } __attribute__((packed)); static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, @@ -25,6 +26,7 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, if (get_user(params.stream, &src->stream) || get_user(params.buffer_size, &src->buffer_size) || get_user(params.avail_min, &src->avail_min) || + get_user(params.mode, &src->mode) || get_user(val, &src->no_active_sensing)) return -EFAULT; params.no_active_sensing = val; diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 250a92b18726..77c1214acd90 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -67,13 +67,16 @@ static int __init alsa_seq_oss_init(void) { int rc; - if ((rc = register_device()) < 0) + rc = register_device(); + if (rc < 0) goto error; - if ((rc = register_proc()) < 0) { + rc = register_proc(); + if (rc < 0) { unregister_device(); goto error; } - if ((rc = snd_seq_oss_create_client()) < 0) { + rc = snd_seq_oss_create_client(); + if (rc < 0) { unregister_proc(); unregister_device(); goto error; @@ -133,7 +136,8 @@ odev_release(struct inode *inode, struct file *file) { struct seq_oss_devinfo *dp; - if ((dp = file->private_data) == NULL) + dp = file->private_data; + if (!dp) return 0; mutex_lock(®ister_mutex); @@ -226,16 +230,18 @@ register_device(void) int rc; mutex_lock(®ister_mutex); - if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, - NULL, 0, - &seq_oss_f_ops, NULL)) < 0) { + rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, + NULL, 0, + &seq_oss_f_ops, NULL); + if (rc < 0) { pr_err("ALSA: seq_oss: can't register device seq\n"); mutex_unlock(®ister_mutex); return rc; } - if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, - NULL, 0, - &seq_oss_f_ops, NULL)) < 0) { + rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, + NULL, 0, + &seq_oss_f_ops, NULL); + if (rc < 0) { pr_err("ALSA: seq_oss: can't register device music\n"); snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0); mutex_unlock(®ister_mutex); diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index 4534a154b8c8..0ee4a5081fd6 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -94,10 +94,10 @@ snd_seq_oss_create_client(void) port_callback.event_input = receive_announce; port->kernel = &port_callback; - call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port); - if ((system_port = port->addr.port) >= 0) { + if (call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port) >= 0) { struct snd_seq_port_subscribe subs; + system_port = port->addr.port; memset(&subs, 0, sizeof(subs)); subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM; subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; @@ -354,7 +354,8 @@ alloc_seq_queue(struct seq_oss_devinfo *dp) qinfo.owner = system_client; qinfo.locked = 1; strcpy(qinfo.name, "OSS Sequencer Emulation"); - if ((rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo)) < 0) + rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo); + if (rc < 0) return rc; dp->queue = qinfo.queue; return 0; @@ -485,7 +486,8 @@ snd_seq_oss_system_info_read(struct snd_info_buffer *buf) snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients); for (i = 0; i < num_clients; i++) { snd_iprintf(buf, "\nApplication %d: ", i); - if ((dp = client_table[i]) == NULL) { + dp = client_table[i]; + if (!dp) { snd_iprintf(buf, "*empty*\n"); continue; } diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 3f82c196de46..1e3bf086f867 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -152,7 +152,8 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo) /* * look for the identical slot */ - if ((mdev = find_slot(pinfo->addr.client, pinfo->addr.port)) != NULL) { + mdev = find_slot(pinfo->addr.client, pinfo->addr.port); + if (mdev) { /* already exists */ snd_use_lock_free(&mdev->use_lock); return 0; @@ -218,7 +219,8 @@ snd_seq_oss_midi_check_exit_port(int client, int port) unsigned long flags; int index; - if ((mdev = find_slot(client, port)) != NULL) { + mdev = find_slot(client, port); + if (mdev) { spin_lock_irqsave(®ister_lock, flags); midi_devs[mdev->seq_device] = NULL; spin_unlock_irqrestore(®ister_lock, flags); @@ -250,7 +252,8 @@ snd_seq_oss_midi_clear_all(void) spin_lock_irqsave(®ister_lock, flags); for (i = 0; i < max_midi_devs; i++) { - if ((mdev = midi_devs[i]) != NULL) { + mdev = midi_devs[i]; + if (mdev) { snd_midi_event_free(mdev->coder); kfree(mdev); midi_devs[i] = NULL; @@ -318,7 +321,8 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode) struct seq_oss_midi *mdev; struct snd_seq_port_subscribe subs; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return -ENODEV; /* already used? */ @@ -384,7 +388,8 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev) struct seq_oss_midi *mdev; struct snd_seq_port_subscribe subs; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return -ENODEV; if (! mdev->opened || mdev->devinfo != dp) { snd_use_lock_free(&mdev->use_lock); @@ -421,7 +426,8 @@ snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev) struct seq_oss_midi *mdev; int mode; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return 0; mode = 0; @@ -443,7 +449,8 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev) { struct seq_oss_midi *mdev; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return; if (! mdev->opened) { snd_use_lock_free(&mdev->use_lock); @@ -491,7 +498,8 @@ snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_ad { struct seq_oss_midi *mdev; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return; addr->client = mdev->client; addr->port = mdev->port; @@ -511,7 +519,8 @@ snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data) if (dp->readq == NULL) return 0; - if ((mdev = find_slot(ev->source.client, ev->source.port)) == NULL) + mdev = find_slot(ev->source.client, ev->source.port); + if (!mdev) return 0; if (! (mdev->opened & PERM_READ)) { snd_use_lock_free(&mdev->use_lock); @@ -623,7 +632,8 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru { struct seq_oss_midi *mdev; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return -ENODEV; if (snd_midi_event_encode_byte(mdev->coder, c, ev)) { snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port); @@ -642,7 +652,8 @@ snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info { struct seq_oss_midi *mdev; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return -ENXIO; inf->device = dev; inf->dev_type = 0; /* FIXME: ?? */ diff --git a/sound/core/seq/oss/seq_oss_rw.c b/sound/core/seq/oss/seq_oss_rw.c index 537d5f423e20..8a142fd54a19 100644 --- a/sound/core/seq/oss/seq_oss_rw.c +++ b/sound/core/seq/oss/seq_oss_rw.c @@ -132,7 +132,8 @@ snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int count, } /* insert queue */ - if ((err = insert_queue(dp, &rec, opt)) < 0) + err = insert_queue(dp, &rec, opt); + if (err < 0) break; result += ev_size; diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 722f5059b300..e3394919daa0 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -451,7 +451,8 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, if (info->is_midi) return 0; - if ((rec = get_synthdev(dp, dev)) == NULL) + rec = get_synthdev(dp, dev); + if (!rec) return -ENXIO; if (rec->oper.load_patch == NULL) @@ -569,7 +570,8 @@ snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, u info = get_synthinfo_nospec(dp, dev); if (!info || info->is_midi) return -ENXIO; - if ((rec = get_synthdev(dp, dev)) == NULL) + rec = get_synthdev(dp, dev); + if (!rec) return -ENXIO; if (rec->oper.ioctl == NULL) rc = -ENXIO; @@ -619,7 +621,8 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in inf->device = dev; strscpy(inf->name, minf.name, sizeof(inf->name)); } else { - if ((rec = get_synthdev(dp, dev)) == NULL) + rec = get_synthdev(dp, dev); + if (!rec) return -ENXIO; inf->synth_type = rec->synth_type; inf->synth_subtype = rec->synth_subtype; diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c index 0a02a59103b4..3e3209ce53b1 100644 --- a/sound/core/seq/oss/seq_oss_writeq.c +++ b/sound/core/seq/oss/seq_oss_writeq.c @@ -27,7 +27,8 @@ snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen) struct seq_oss_writeq *q; struct snd_seq_client_pool pool; - if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) + q = kzalloc(sizeof(*q), GFP_KERNEL); + if (!q) return NULL; q->dp = dp; q->maxlen = maxlen; diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index b6a24fb5e76b..2e9d695d336c 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -416,7 +416,10 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, if (snd_BUG_ON(!client)) return -ENXIO; - if (!client->accept_input || (fifo = client->data.user.fifo) == NULL) + if (!client->accept_input) + return -ENXIO; + fifo = client->data.user.fifo; + if (!fifo) return -ENXIO; if (atomic_read(&fifo->overflow) > 0) { @@ -435,9 +438,9 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, int nonblock; nonblock = (file->f_flags & O_NONBLOCK) || result > 0; - if ((err = snd_seq_fifo_cell_out(fifo, &cell, nonblock)) < 0) { + err = snd_seq_fifo_cell_out(fifo, &cell, nonblock); + if (err < 0) break; - } if (snd_seq_ev_is_variable(&cell->event)) { struct snd_seq_event tmpev; tmpev = cell->event; @@ -970,7 +973,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client, return err; /* we got a cell. enqueue it. */ - if ((err = snd_seq_enqueue_event(cell, atomic, hop)) < 0) { + err = snd_seq_enqueue_event(cell, atomic, hop); + if (err < 0) { snd_seq_cell_free(cell); return err; } @@ -1312,7 +1316,8 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg) return -EINVAL; } if (client->type == KERNEL_CLIENT) { - if ((callback = info->kernel) != NULL) { + callback = info->kernel; + if (callback) { if (callback->owner) port->owner = callback->owner; port->private_data = callback->private_data; @@ -1466,13 +1471,17 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client, struct snd_seq_client *receiver = NULL, *sender = NULL; struct snd_seq_client_port *sport = NULL, *dport = NULL; - if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL) + receiver = snd_seq_client_use_ptr(subs->dest.client); + if (!receiver) goto __end; - if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL) + sender = snd_seq_client_use_ptr(subs->sender.client); + if (!sender) goto __end; - if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL) + sport = snd_seq_port_use_ptr(sender, subs->sender.port); + if (!sport) goto __end; - if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL) + dport = snd_seq_port_use_ptr(receiver, subs->dest.port); + if (!dport) goto __end; result = check_subscription_permission(client, sport, dport, subs); @@ -1508,13 +1517,17 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client, struct snd_seq_client *receiver = NULL, *sender = NULL; struct snd_seq_client_port *sport = NULL, *dport = NULL; - if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL) + receiver = snd_seq_client_use_ptr(subs->dest.client); + if (!receiver) goto __end; - if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL) + sender = snd_seq_client_use_ptr(subs->sender.client); + if (!sender) goto __end; - if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL) + sport = snd_seq_port_use_ptr(sender, subs->sender.port); + if (!sport) goto __end; - if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL) + dport = snd_seq_port_use_ptr(receiver, subs->dest.port); + if (!dport) goto __end; result = check_subscription_permission(client, sport, dport, subs); @@ -1926,9 +1939,11 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client, struct snd_seq_client_port *sport = NULL; result = -EINVAL; - if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL) + sender = snd_seq_client_use_ptr(subs->sender.client); + if (!sender) goto __end; - if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL) + sport = snd_seq_port_use_ptr(sender, subs->sender.port); + if (!sport) goto __end; result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest, subs); @@ -1955,9 +1970,11 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg) struct list_head *p; int i; - if ((cptr = snd_seq_client_use_ptr(subs->root.client)) == NULL) + cptr = snd_seq_client_use_ptr(subs->root.client); + if (!cptr) goto __end; - if ((port = snd_seq_port_use_ptr(cptr, subs->root.port)) == NULL) + port = snd_seq_port_use_ptr(cptr, subs->root.port); + if (!port) goto __end; switch (subs->type) { diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index cd5a4cad8881..ac760b1e3d12 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -109,7 +109,8 @@ create_port(int idx, int type) struct snd_seq_port_callback pcb; struct snd_seq_dummy_port *rec; - if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) + rec = kzalloc(sizeof(*rec), GFP_KERNEL); + if (!rec) return NULL; rec->client = my_client; diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index eaaa8b5830bb..f8e02e98709a 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -143,7 +143,8 @@ static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f) { struct snd_seq_event_cell *cell; - if ((cell = f->head) != NULL) { + cell = f->head; + if (cell) { f->head = cell->next; /* reset tail if this was the last element */ diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index e245bb6ba533..b7aee23fc387 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -69,7 +69,8 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, int len, err; struct snd_seq_event_cell *cell; - if ((len = get_var_len(event)) <= 0) + len = get_var_len(event); + if (len <= 0) return len; if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) { @@ -133,7 +134,8 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char int len, newlen; int err; - if ((len = get_var_len(event)) < 0) + len = get_var_len(event); + if (len < 0) return len; newlen = len; if (size_aligned > 0) diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 6825940ea2cf..4589aac09154 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -101,7 +101,8 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i if (snd_BUG_ON(!substream || !buf)) return -EINVAL; runtime = substream->runtime; - if ((tmp = runtime->avail) < count) { + tmp = runtime->avail; + if (tmp < count) { if (printk_ratelimit()) pr_err("ALSA: seq_midi: MIDI output buffer overrun\n"); return -ENOMEM; @@ -167,10 +168,11 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe struct snd_rawmidi_params params; /* open midi port */ - if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device, - msynth->subdevice, - SNDRV_RAWMIDI_LFLG_INPUT, - &msynth->input_rfile)) < 0) { + err = snd_rawmidi_kernel_open(msynth->card, msynth->device, + msynth->subdevice, + SNDRV_RAWMIDI_LFLG_INPUT, + &msynth->input_rfile); + if (err < 0) { pr_debug("ALSA: seq_midi: midi input open failed!!!\n"); return err; } @@ -178,7 +180,8 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe memset(¶ms, 0, sizeof(params)); params.avail_min = 1; params.buffer_size = input_buffer_size; - if ((err = snd_rawmidi_input_params(msynth->input_rfile.input, ¶ms)) < 0) { + err = snd_rawmidi_input_params(msynth->input_rfile.input, ¶ms); + if (err < 0) { snd_rawmidi_kernel_release(&msynth->input_rfile); return err; } @@ -209,10 +212,11 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info struct snd_rawmidi_params params; /* open midi port */ - if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device, - msynth->subdevice, - SNDRV_RAWMIDI_LFLG_OUTPUT, - &msynth->output_rfile)) < 0) { + err = snd_rawmidi_kernel_open(msynth->card, msynth->device, + msynth->subdevice, + SNDRV_RAWMIDI_LFLG_OUTPUT, + &msynth->output_rfile); + if (err < 0) { pr_debug("ALSA: seq_midi: midi output open failed!!!\n"); return err; } @@ -220,7 +224,8 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info params.avail_min = 1; params.buffer_size = output_buffer_size; params.no_active_sensing = 1; - if ((err = snd_rawmidi_output_params(msynth->output_rfile.output, ¶ms)) < 0) { + err = snd_rawmidi_output_params(msynth->output_rfile.output, ¶ms); + if (err < 0) { snd_rawmidi_kernel_release(&msynth->output_rfile); return err; } diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 13cfc2d47fa7..d6c02dea976c 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -222,7 +222,8 @@ struct snd_seq_queue *snd_seq_queue_find_name(char *name) struct snd_seq_queue *q; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) != NULL) { + q = queueptr(i); + if (q) { if (strncmp(q->name, name, sizeof(q->name)) == 0) return q; queuefree(q); @@ -432,7 +433,8 @@ int snd_seq_queue_timer_open(int queueid) if (queue == NULL) return -EINVAL; tmr = queue->timer; - if ((result = snd_seq_timer_open(queue)) < 0) { + result = snd_seq_timer_open(queue); + if (result < 0) { snd_seq_timer_defaults(tmr); result = snd_seq_timer_open(queue); } @@ -548,7 +550,8 @@ void snd_seq_queue_client_leave(int client) /* delete own queues from queue list */ for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queue_list_remove(i, client)) != NULL) + q = queue_list_remove(i, client); + if (q) queue_delete(q); } @@ -556,7 +559,8 @@ void snd_seq_queue_client_leave(int client) * they are not owned by this client */ for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) + q = queueptr(i); + if (!q) continue; if (test_bit(client, q->clients_bitmap)) { snd_seq_prioq_leave(q->tickq, client, 0); @@ -578,7 +582,8 @@ void snd_seq_queue_client_leave_cells(int client) struct snd_seq_queue *q; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) + q = queueptr(i); + if (!q) continue; snd_seq_prioq_leave(q->tickq, client, 0); snd_seq_prioq_leave(q->timeq, client, 0); @@ -593,7 +598,8 @@ void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info) struct snd_seq_queue *q; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) + q = queueptr(i); + if (!q) continue; if (test_bit(client, q->clients_bitmap) && (! (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) || @@ -724,7 +730,8 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, int owner; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) + q = queueptr(i); + if (!q) continue; tmr = q->timer; diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 77d7037d1476..4abc38c70cae 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -482,10 +482,11 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi int err; *rrmidi = NULL; - if ((err = snd_rawmidi_new(card, "VirMidi", device, - 16, /* may be configurable */ - 16, /* may be configurable */ - &rmidi)) < 0) + err = snd_rawmidi_new(card, "VirMidi", device, + 16, /* may be configurable */ + 16, /* may be configurable */ + &rmidi); + if (err < 0) return err; strcpy(rmidi->name, rmidi->id); rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c index 29ddb76187e5..232cf3f1bcb3 100644 --- a/sound/core/sgbuf.c +++ b/sound/core/sgbuf.c @@ -10,20 +10,34 @@ #include <linux/vmalloc.h> #include <linux/export.h> #include <sound/memalloc.h> - +#include "memalloc_local.h" + +struct snd_sg_page { + void *buf; + dma_addr_t addr; +}; + +struct snd_sg_buf { + int size; /* allocated byte size */ + int pages; /* allocated pages */ + int tblsize; /* allocated table size */ + struct snd_sg_page *table; /* address table */ + struct page **page_table; /* page table (for vmap/vunmap) */ + struct device *dev; +}; /* table entries are align to 32 */ #define SGBUF_TBL_ALIGN 32 #define sgbuf_align_table(tbl) ALIGN((tbl), SGBUF_TBL_ALIGN) -int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) +static void snd_dma_sg_free(struct snd_dma_buffer *dmab) { struct snd_sg_buf *sgbuf = dmab->private_data; struct snd_dma_buffer tmpb; int i; - if (! sgbuf) - return -EINVAL; + if (!sgbuf) + return; vunmap(dmab->area); dmab->area = NULL; @@ -45,15 +59,11 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) kfree(sgbuf->page_table); kfree(sgbuf); dmab->private_data = NULL; - - return 0; } #define MAX_ALLOC_PAGES 32 -void *snd_malloc_sgbuf_pages(struct device *device, - size_t size, struct snd_dma_buffer *dmab, - size_t *res_size) +static int snd_dma_sg_alloc(struct snd_dma_buffer *dmab, size_t size) { struct snd_sg_buf *sgbuf; unsigned int i, pages, chunk, maxpages; @@ -63,18 +73,16 @@ void *snd_malloc_sgbuf_pages(struct device *device, int type = SNDRV_DMA_TYPE_DEV; pgprot_t prot = PAGE_KERNEL; - dmab->area = NULL; - dmab->addr = 0; dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL); - if (! sgbuf) - return NULL; + if (!sgbuf) + return -ENOMEM; if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) { type = SNDRV_DMA_TYPE_DEV_UC; #ifdef pgprot_noncached prot = pgprot_noncached(PAGE_KERNEL); #endif } - sgbuf->dev = device; + sgbuf->dev = dmab->dev.dev; pages = snd_sgbuf_aligned_pages(size); sgbuf->tblsize = sgbuf_align_table(pages); table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL); @@ -94,12 +102,10 @@ void *snd_malloc_sgbuf_pages(struct device *device, if (chunk > maxpages) chunk = maxpages; chunk <<= PAGE_SHIFT; - if (snd_dma_alloc_pages_fallback(type, device, + if (snd_dma_alloc_pages_fallback(type, dmab->dev.dev, chunk, &tmpb) < 0) { if (!sgbuf->pages) goto _failed; - if (!res_size) - goto _failed; size = sgbuf->pages * PAGE_SIZE; break; } @@ -124,27 +130,42 @@ void *snd_malloc_sgbuf_pages(struct device *device, dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot); if (! dmab->area) goto _failed; - if (res_size) - *res_size = sgbuf->size; - return dmab->area; + return 0; _failed: - snd_free_sgbuf_pages(dmab); /* free the table */ - return NULL; + snd_dma_sg_free(dmab); /* free the table */ + return -ENOMEM; } -/* - * compute the max chunk size with continuous pages on sg-buffer - */ -unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab, - unsigned int ofs, unsigned int size) +static dma_addr_t snd_dma_sg_get_addr(struct snd_dma_buffer *dmab, + size_t offset) +{ + struct snd_sg_buf *sgbuf = dmab->private_data; + dma_addr_t addr; + + addr = sgbuf->table[offset >> PAGE_SHIFT].addr; + addr &= ~((dma_addr_t)PAGE_SIZE - 1); + return addr + offset % PAGE_SIZE; +} + +static struct page *snd_dma_sg_get_page(struct snd_dma_buffer *dmab, + size_t offset) +{ + struct snd_sg_buf *sgbuf = dmab->private_data; + unsigned int idx = offset >> PAGE_SHIFT; + + if (idx >= (unsigned int)sgbuf->pages) + return NULL; + return sgbuf->page_table[idx]; +} + +static unsigned int snd_dma_sg_get_chunk_size(struct snd_dma_buffer *dmab, + unsigned int ofs, + unsigned int size) { struct snd_sg_buf *sg = dmab->private_data; unsigned int start, end, pg; - if (!sg) - return size; - start = ofs >> PAGE_SHIFT; end = (ofs + size - 1) >> PAGE_SHIFT; /* check page continuity */ @@ -160,4 +181,11 @@ unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab, /* ok, all on continuous pages */ return size; } -EXPORT_SYMBOL(snd_sgbuf_get_chunk_size); + +const struct snd_malloc_ops snd_dma_sg_ops = { + .alloc = snd_dma_sg_alloc, + .free = snd_dma_sg_free, + .get_addr = snd_dma_sg_get_addr, + .get_page = snd_dma_sg_get_page, + .get_chunk_size = snd_dma_sg_get_chunk_size, +}; diff --git a/sound/core/sound.c b/sound/core/sound.c index af89e51dd44a..df5571d98629 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -357,7 +357,8 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu mutex_lock(&sound_mutex); for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) { - if (!(mptr = snd_minors[minor])) + mptr = snd_minors[minor]; + if (!mptr) continue; if (mptr->card >= 0) { if (mptr->device >= 0) diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 610f317bea9d..7ed0a2a91035 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -217,7 +217,8 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry, mutex_lock(&sound_oss_mutex); for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) { - if (!(mptr = snd_oss_minors[minor])) + mptr = snd_oss_minors[minor]; + if (!mptr) continue; if (mptr->card >= 0) snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", minor, |