From 6d843ba5d377961f6765466ba0cc362dd10f7557 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 14 Jun 2017 12:37:39 +0100 Subject: [PATCH 01/39] topology: Add support for missing fields parser. The alsa-lib topology parser is missing some fields for certain objects that are part of the ABI. This patch adds the missing fields to the parser. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai --- src/topology/pcm.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/src/topology/pcm.c b/src/topology/pcm.c index daef20e4..0f4deb4f 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -383,6 +383,49 @@ int tplg_parse_stream_caps(snd_tplg_t *tplg, tplg_dbg("\t\t%s: %d\n", id, sc->channels_max); continue; } + + if (strcmp(id, "periods_min") == 0) { + sc->periods_min = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->periods_min); + continue; + } + + if (strcmp(id, "periods_max") == 0) { + sc->periods_max = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->periods_max); + continue; + } + + if (strcmp(id, "period_size_min") == 0) { + sc->period_size_min = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->period_size_min); + continue; + } + + if (strcmp(id, "period_size_max") == 0) { + sc->period_size_max = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->period_size_max); + continue; + } + + if (strcmp(id, "buffer_size_min") == 0) { + sc->buffer_size_min = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->buffer_size_min); + continue; + } + + if (strcmp(id, "buffer_size_max") == 0) { + sc->buffer_size_max = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->buffer_size_max); + continue; + } + + if (strcmp(id, "sig_bits") == 0) { + sc->sig_bits = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->sig_bits); + continue; + } + } return 0; @@ -572,6 +615,17 @@ int tplg_parse_pcm(snd_tplg_t *tplg, continue; } + if (strcmp(id, "compress") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (strcmp(val, "true") == 0) + pcm->compress = 1; + + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + if (strcmp(id, "dai") == 0) { err = tplg_parse_compound(tplg, n, tplg_parse_fe_dai, elem); @@ -655,6 +709,26 @@ int tplg_parse_dai(snd_tplg_t *tplg, continue; } + if (strcmp(id, "playback") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + dai->playback = atoi(val); + tplg_dbg("\t%s: %d\n", id, dai->playback); + continue; + } + + + if (strcmp(id, "capture") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + dai->capture = atoi(val); + tplg_dbg("\t%s: %d\n", id, dai->capture); + continue; + } + + /* stream capabilities */ if (strcmp(id, "pcm") == 0) { err = tplg_parse_compound(tplg, n, @@ -997,6 +1071,23 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, continue; } + if (strcmp(id, "bclk_freq") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->bclk_rate = atoi(val); + continue; + } + + if (strcmp(id, "bclk_invert") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "true")) + hw_cfg->invert_bclk = true; + continue; + } + if (strcmp(id, "fsync") == 0) { if (snd_config_get_string(n, &val) < 0) return -EINVAL; @@ -1005,6 +1096,98 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, hw_cfg->fsync_master = true; continue; } + + if (strcmp(id, "fsync_invert") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "true")) + hw_cfg->invert_fsync = true; + continue; + } + + if (strcmp(id, "fsync_freq") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->fsync_rate = atoi(val); + continue; + } + + if (strcmp(id, "mclk_freq") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->mclk_rate = atoi(val); + continue; + } + + if (strcmp(id, "mclk") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "master")) + hw_cfg->mclk_direction = true; + continue; + } + + if (strcmp(id, "pm_gate_clocks") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "true")) + hw_cfg->clock_gated = true; + continue; + } + + if (strcmp(id, "tdm_slots") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->tdm_slots = atoi(val); + continue; + } + + if (strcmp(id, "tdm_slot_width") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->tdm_slot_width = atoi(val); + continue; + } + + if (strcmp(id, "tx_slots") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->tx_slots = atoi(val); + continue; + } + + if (strcmp(id, "rx_slots") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->rx_slots = atoi(val); + continue; + } + + if (strcmp(id, "tx_channels") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->tx_channels = atoi(val); + continue; + } + + if (strcmp(id, "rx_channels") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->rx_channels = atoi(val); + continue; + } + } return 0; -- 2.13.5 From 89c96ad7fb0168411260196560892835d0adeddf Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 14 Jun 2017 12:37:40 +0100 Subject: [PATCH 02/39] topology: disable alsa-lib topology debug output by default. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai --- src/topology/tplg_local.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 42e3201d..60af0177 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -22,7 +22,6 @@ #include #include -#define TPLG_DEBUG #ifdef TPLG_DEBUG #define tplg_dbg SNDERR #else -- 2.13.5 From c550a421a3ff5b11ccd4a506ae04fdc6c5347ae3 Mon Sep 17 00:00:00 2001 From: Guneshwor Singh Date: Tue, 20 Jun 2017 09:45:45 +0530 Subject: [PATCH 03/39] topology: Add parsing for rates from conf In alsa-lib topology parser, rate_min and rate_max are parsed currently. Add support to parse rates also. Signed-off-by: Guneshwor Singh Signed-off-by: Takashi Iwai --- include/topology.h | 1 + src/topology/pcm.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++ src/topology/tplg_local.h | 20 +++++++++++++ 3 files changed, 92 insertions(+) diff --git a/include/topology.h b/include/topology.h index ccb3a004..42d23762 100644 --- a/include/topology.h +++ b/include/topology.h @@ -534,6 +534,7 @@ extern "C" { * SectionPCMCapabilities."name" { * * formats "S24_LE,S16_LE" # Supported formats + * rates "48000" # Supported rates * rate_min "48000" # Max supported sample rate * rate_max "48000" # Min supported sample rate * channels_min "2" # Min number of channels diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 0f4deb4f..bb63142e 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -20,6 +20,26 @@ #include "list.h" #include "tplg_local.h" +#define RATE(v) [SND_PCM_RATE_##v] = #v + +static const char *const snd_pcm_rate_names[] = { + RATE(5512), + RATE(8000), + RATE(11025), + RATE(16000), + RATE(22050), + RATE(32000), + RATE(44100), + RATE(48000), + RATE(64000), + RATE(88200), + RATE(96000), + RATE(176400), + RATE(192000), + RATE(CONTINUOUS), + RATE(KNOT), +}; + struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id) { struct list_head *pos; @@ -309,6 +329,42 @@ static int split_format(struct snd_soc_tplg_stream_caps *caps, char *str) return 0; } +static int get_rate_value(const char* name) +{ + int rate; + for (rate = 0; rate <= SND_PCM_RATE_LAST; rate++) { + if (snd_pcm_rate_names[rate] && + strcasecmp(name, snd_pcm_rate_names[rate]) == 0) { + return rate; + } + } + + return SND_PCM_RATE_UNKNOWN; +} + +static int split_rate(struct snd_soc_tplg_stream_caps *caps, char *str) +{ + char *s = NULL; + snd_pcm_rates_t rate; + int i = 0; + + s = strtok(str, ","); + while (s) { + rate = get_rate_value(s); + + if (rate == SND_PCM_RATE_UNKNOWN) { + SNDERR("error: unsupported stream rate %s\n", s); + return -EINVAL; + } + + caps->rates |= 1 << rate; + s = strtok(NULL, ", "); + i++; + } + + return 0; +} + /* Parse pcm stream capabilities */ int tplg_parse_stream_caps(snd_tplg_t *tplg, snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) @@ -360,6 +416,21 @@ int tplg_parse_stream_caps(snd_tplg_t *tplg, continue; } + if (strcmp(id, "rates") == 0) { + s = strdup(val); + if (!s) + return -ENOMEM; + + err = split_rate(sc, s); + free(s); + + if (err < 0) + return err; + + tplg_dbg("\t\t%s: %s\n", id, val); + continue; + } + if (strcmp(id, "rate_min") == 0) { sc->rate_min = atoi(val); tplg_dbg("\t\t%s: %d\n", id, sc->rate_min); diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 60af0177..af599145 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -37,6 +37,26 @@ struct tplg_ref; struct tplg_elem; +typedef enum _snd_pcm_rates { + SND_PCM_RATE_UNKNOWN = -1, + SND_PCM_RATE_5512 = 0, + SND_PCM_RATE_8000, + SND_PCM_RATE_11025, + SND_PCM_RATE_16000, + SND_PCM_RATE_22050, + SND_PCM_RATE_32000, + SND_PCM_RATE_44100, + SND_PCM_RATE_48000, + SND_PCM_RATE_64000, + SND_PCM_RATE_88200, + SND_PCM_RATE_96000, + SND_PCM_RATE_176400, + SND_PCM_RATE_192000, + SND_PCM_RATE_CONTINUOUS = 30, + SND_PCM_RATE_KNOT = 31, + SND_PCM_RATE_LAST = SND_PCM_RATE_KNOT, +} snd_pcm_rates_t; + struct snd_tplg { /* opaque vendor data */ -- 2.13.5 From 6c535573008e474c471c100c5bfa5383308020f3 Mon Sep 17 00:00:00 2001 From: Alexander Tsoy Date: Sun, 18 Jun 2017 23:23:02 +0300 Subject: [PATCH 04/39] conf: USB-Audio: fix dsnoop args for Audiophile USB card Fixes: a9b129955659 ("USB-Audio.conf: fix definition for M-Audio AudioP...") Signed-off-by: Alexander Tsoy Signed-off-by: Takashi Iwai --- src/conf/cards/USB-Audio.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf index e365f297..f72ef121 100644 --- a/src/conf/cards/USB-Audio.conf +++ b/src/conf/cards/USB-Audio.conf @@ -90,7 +90,7 @@ USB-Audio."Audiophile USB (tm)".pcm.default { type plug slave.pcm { @func concat - strings [ "dsnoop:DEVICE=1,CARD=" $CARD ] + strings [ "dsnoop:DEV=1,CARD=" $CARD ] } } } -- 2.13.5 From c09e3b2d5b7fe893b99df3c87577936a3f386d99 Mon Sep 17 00:00:00 2001 From: Alexander Tsoy Date: Sun, 18 Jun 2017 23:23:03 +0300 Subject: [PATCH 05/39] conf: USB-Audio: allow custom definitions for "default" devices Fixes: a9b129955659 ("USB-Audio.conf: fix definition for M-Audio AudioP...") Signed-off-by: Alexander Tsoy Signed-off-by: Takashi Iwai --- src/conf/cards/USB-Audio.conf | 77 ++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf index f72ef121..cc8c718c 100644 --- a/src/conf/cards/USB-Audio.conf +++ b/src/conf/cards/USB-Audio.conf @@ -67,7 +67,7 @@ USB-Audio.pcm.iec958_2_device { } -# If a device requires non-standard definitions for front, surround40, +# If a device requires non-standard definitions for front, default, surround40, # surround51, surround71 or iec958, they can be defined here. # M-Audio AudioPhile USB: @@ -125,13 +125,13 @@ USB-Audio."Audio Advantage MicroII".pcm.iec958 { @args.AES2 { type integer } @args.AES3 { type integer } - type hooks - slave.pcm { + type hooks + slave.pcm { type hw card $CARD - } + } - hooks.0 { + hooks.0 { type ctl_elems hook_args [ { @@ -174,41 +174,52 @@ USB-Audio.pcm.front.0 { card $CARD device 0 } -} +} USB-Audio.pcm.default { @args [ CARD ] @args.CARD { type string } - type asym - playback.pcm { - type plug - slave.pcm { - @func refer - name { - @func concat - strings [ - "cards.USB-Audio.pcm.default_playback_dmix_" - { - @func refer - name { - @func concat - strings [ - "cards.USB-Audio.pcm.use_dmix." - { @func card_name card $CARD } - ] + @func refer + name { + @func concat + strings [ + "cards.USB-Audio." + { @func card_name card $CARD } + ".pcm.default:CARD=" $CARD + ] + } + default { + type asym + playback.pcm { + type plug + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards.USB-Audio.pcm.default_playback_dmix_" + { + @func refer + name { + @func concat + strings [ + "cards.USB-Audio.pcm.use_dmix." + { @func card_name card $CARD } + ] + } + default yes } - default yes - } - ":CARD=" $CARD - ] + ":CARD=" $CARD + ] + } } } - } - capture.pcm { - type plug - slave.pcm { - @func concat - strings [ "dsnoop:" $CARD ] + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } } } } -- 2.13.5 From f10bc243e42142c568d90f540e806aefb45d8bac Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 23 Jun 2017 22:09:23 +0900 Subject: [PATCH 06/39] pcm: obsolete 'mmap_emulation' parameter of snd_pcm_hw_open_fd() A function, snd_pcm_hw_open_fd(), is just for internal use. This function has an obsoleted parameter and we can remove it without any compatibility issue. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_direct.c | 2 +- src/pcm/pcm_hw.c | 6 ++---- src/pcm/pcm_local.h | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index 43702601..9fd376d8 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -1523,7 +1523,7 @@ int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dm int ret; snd_pcm_t *spcm; - ret = snd_pcm_hw_open_fd(spcmp, client_name, dmix->hw_fd, 0, 0); + ret = snd_pcm_hw_open_fd(spcmp, client_name, dmix->hw_fd, 0); if (ret < 0) { SNDERR("unable to open hardware"); return ret; diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 30cd5d0f..f0efcde3 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -1410,15 +1410,13 @@ static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer = { * \param pcmp Returns created PCM handle * \param name Name of PCM * \param fd File descriptor - * \param mmap_emulation Obsoleted parameter * \param sync_ptr_ioctl Boolean flag for sync_ptr ioctl * \retval zero on success otherwise a negative error code * \warning Using of this function might be dangerous in the sense * of compatibility reasons. The prototype might be freely * changed in future. */ -int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, - int fd, int mmap_emulation ATTRIBUTE_UNUSED, +int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, int sync_ptr_ioctl) { int ver, mode; @@ -1615,7 +1613,7 @@ int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, } } snd_ctl_close(ctl); - return snd_pcm_hw_open_fd(pcmp, name, fd, 0, sync_ptr_ioctl); + return snd_pcm_hw_open_fd(pcmp, name, fd, sync_ptr_ioctl); _err: snd_ctl_close(ctl); return ret; diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index e4f65218..7600daa3 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -935,7 +935,8 @@ snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root, #define snd_pcm_conf_generic_id(id) _snd_conf_generic_id(id) -int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, int mmap_emulation, int sync_ptr_ioctl); +int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, + int sync_ptr_ioctl); int __snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int close_slave); -- 2.13.5 From 8beab3eb8a4346f823cb42c507122f0abbf9025f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 23 Jun 2017 22:09:24 +0900 Subject: [PATCH 07/39] pcm: minor code cleanup for ioctl call When error occurs, return value from ioctl(2) is -1 and error code can be got thread local variable, errno. It's OK just to check the return value without any assignment. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index f0efcde3..de6fd1af 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -132,8 +132,7 @@ static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags) { int err; hw->sync_ptr->flags = flags; - err = ioctl((hw)->fd, SNDRV_PCM_IOCTL_SYNC_PTR, (hw)->sync_ptr); - if (err < 0) { + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { err = -errno; SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); return err; -- 2.13.5 From 987788dbfe65ae7811868654ba11c05b4582955f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Jun 2017 12:39:23 +0200 Subject: [PATCH 08/39] pcm: hw: Remove superfluous call of snd_pcm_set_appl_ptr() There is a call of snd_pcm_set_appl_ptr() in snd_pcm_hw_hw_params() only for the capture direction. This must be a leftover from the ancient code. Although it's harmless for now, it's superfluous and confusing. Let's kill it. Reviewed-by: Takashi Sakamoto Tested-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index de6fd1af..a648d12c 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -329,14 +329,7 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) params->info &= ~0xf0000000; if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) params->info |= SND_PCM_INFO_MONOTONIC; - err = sync_ptr(hw, 0); - if (err < 0) - return err; - if (pcm->stream == SND_PCM_STREAM_CAPTURE) { - snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, - SNDRV_PCM_MMAP_OFFSET_CONTROL); - } - return 0; + return sync_ptr(hw, 0); } static void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw) -- 2.13.5 From 2fbad9bc4ead7ea0c19529c4496080af9b8ab275 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 25 Jun 2017 13:41:19 +0900 Subject: [PATCH 09/39] pcm: hw: add helper functions to map/unmap status/control data for runtime of PCM substream Handling mapping operation for status/control data includes some supplemental operations for fallback mode. It's better to have helper functions for this purpose. This commit adds the helper functions. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index a648d12c..abf4afe0 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -866,7 +867,7 @@ static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_u return xfern.result; } -static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm) +static int map_status_data(snd_pcm_t *pcm) { snd_pcm_hw_t *hw = pcm->private_data; struct snd_pcm_sync_ptr sync_ptr; @@ -900,7 +901,7 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm) return 0; } -static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm) +static int map_control_data(snd_pcm_t *pcm) { snd_pcm_hw_t *hw = pcm->private_data; void *ptr; @@ -922,10 +923,28 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm) return 0; } -static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm) +static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) { snd_pcm_hw_t *hw = pcm->private_data; int err; + + hw->sync_ptr_ioctl = (int)force_fallback; + + err = map_status_data(pcm); + if (err < 0) + return err; + + err = map_control_data(pcm); + if (err < 0) + return err; + + return 0; +} + +static int unmap_status_data(snd_pcm_hw_t *hw) +{ + int err; + if (hw->sync_ptr_ioctl) { free(hw->sync_ptr); hw->sync_ptr = NULL; @@ -939,10 +958,10 @@ static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm) return 0; } -static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm) +static int unmap_control_data(snd_pcm_hw_t *hw) { - snd_pcm_hw_t *hw = pcm->private_data; int err; + if (hw->sync_ptr_ioctl) { free(hw->sync_ptr); hw->sync_ptr = NULL; @@ -956,6 +975,12 @@ static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm) return 0; } +static void unmap_status_and_control_data(snd_pcm_hw_t *hw) +{ + unmap_status_data(hw); + unmap_control_data(hw); +} + static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) { return 0; @@ -974,8 +999,9 @@ static int snd_pcm_hw_close(snd_pcm_t *pcm) err = -errno; SYSMSG("close failed (%i)\n", err); } - snd_pcm_hw_munmap_status(pcm); - snd_pcm_hw_munmap_control(pcm); + + unmap_status_and_control_data(hw); + free(hw); return err; } @@ -1484,7 +1510,6 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, hw->device = info.device; hw->subdevice = info.subdevice; hw->fd = fd; - hw->sync_ptr_ioctl = sync_ptr_ioctl; /* no restriction */ hw->format = SND_PCM_FORMAT_UNKNOWN; hw->rate = 0; @@ -1508,12 +1533,7 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, #endif pcm->own_state_check = 1; /* skip the common state check */ - ret = snd_pcm_hw_mmap_status(pcm); - if (ret < 0) { - snd_pcm_close(pcm); - return ret; - } - ret = snd_pcm_hw_mmap_control(pcm); + ret = map_status_and_control_data(pcm, !!sync_ptr_ioctl); if (ret < 0) { snd_pcm_close(pcm); return ret; -- 2.13.5 From 812654881a370691fba3ecbd4c175c74c32b9eae Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 25 Jun 2017 13:41:20 +0900 Subject: [PATCH 10/39] pcm: hw: add an arrangement for initialization of appl_ptr/avail_min Regardless of success/failure mapping of control/status data for runtime of PCM substream, appl_ptr/avail_min parameters are initialized. In current implementation, they are initialized in case-dependent, different places. It's possible to collect them to one place. This commit unifies relevant code in a place after all of trials for the mappings are finished. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index abf4afe0..c60a521b 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -867,10 +867,8 @@ static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_u return xfern.result; } -static int map_status_data(snd_pcm_t *pcm) +static int map_status_data(snd_pcm_hw_t *hw) { - snd_pcm_hw_t *hw = pcm->private_data; - struct snd_pcm_sync_ptr sync_ptr; void *ptr; int err; ptr = MAP_FAILED; @@ -879,15 +877,6 @@ static int map_status_data(snd_pcm_t *pcm) PROT_READ, MAP_FILE|MAP_SHARED, hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); if (ptr == MAP_FAILED || ptr == NULL) { - memset(&sync_ptr, 0, sizeof(sync_ptr)); - sync_ptr.c.control.appl_ptr = 0; - sync_ptr.c.control.avail_min = 1; - err = ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, &sync_ptr); - if (err < 0) { - err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); - return err; - } hw->sync_ptr = calloc(1, sizeof(struct snd_pcm_sync_ptr)); if (hw->sync_ptr == NULL) return -ENOMEM; @@ -897,13 +886,12 @@ static int map_status_data(snd_pcm_t *pcm) } else { hw->mmap_status = ptr; } - snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS + offsetof(struct snd_pcm_mmap_status, hw_ptr)); + return 0; } -static int map_control_data(snd_pcm_t *pcm) +static int map_control_data(snd_pcm_hw_t *hw) { - snd_pcm_hw_t *hw = pcm->private_data; void *ptr; int err; if (hw->sync_ptr == NULL) { @@ -916,10 +904,8 @@ static int map_control_data(snd_pcm_t *pcm) return err; } hw->mmap_control = ptr; - } else { - hw->mmap_control->avail_min = 1; } - snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); + return 0; } @@ -930,14 +916,30 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) hw->sync_ptr_ioctl = (int)force_fallback; - err = map_status_data(pcm); + err = map_status_data(hw); if (err < 0) return err; - err = map_control_data(pcm); + err = map_control_data(hw); if (err < 0) return err; + /* Initialize the data. */ + hw->mmap_control->appl_ptr = 0; + hw->mmap_control->avail_min = 1; + snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd, + SNDRV_PCM_MMAP_OFFSET_STATUS + + offsetof(struct snd_pcm_mmap_status, hw_ptr)); + snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, + SNDRV_PCM_MMAP_OFFSET_CONTROL); + if (hw->sync_ptr_ioctl) { + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); + return err; + } + } + return 0; } -- 2.13.5 From cb7503eba15714c40630d9e26bf7e5905ee3da50 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 25 Jun 2017 13:41:21 +0900 Subject: [PATCH 11/39] pcm: hw: deallocate fallback buffer when trials of unmapping finished In current implementation, deallocation of fallback buffer is done at several places. This commit unifies these deallocations in one place. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index c60a521b..1d34956c 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -943,44 +943,35 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) return 0; } -static int unmap_status_data(snd_pcm_hw_t *hw) +static void unmap_status_data(snd_pcm_hw_t *hw) { - int err; - - if (hw->sync_ptr_ioctl) { - free(hw->sync_ptr); - hw->sync_ptr = NULL; - } else { - if (munmap((void*)hw->mmap_status, page_align(sizeof(*hw->mmap_status))) < 0) { - err = -errno; - SYSMSG("status munmap failed (%i)", err); - return err; - } + if (!hw->sync_ptr) { + if (munmap((void *)hw->mmap_status, + page_align(sizeof(*hw->mmap_status))) < 0) + SYSMSG("status munmap failed (%u)", errno); } - return 0; } -static int unmap_control_data(snd_pcm_hw_t *hw) +static void unmap_control_data(snd_pcm_hw_t *hw) { - int err; - - if (hw->sync_ptr_ioctl) { - free(hw->sync_ptr); - hw->sync_ptr = NULL; - } else { - if (munmap(hw->mmap_control, page_align(sizeof(*hw->mmap_control))) < 0) { - err = -errno; - SYSMSG("control munmap failed (%i)", err); - return err; - } + if (!hw->sync_ptr) { + if (munmap((void *)hw->mmap_control, + page_align(sizeof(*hw->mmap_control))) < 0) + SYSMSG("control munmap failed (%u)", errno); } - return 0; } static void unmap_status_and_control_data(snd_pcm_hw_t *hw) { unmap_status_data(hw); unmap_control_data(hw); + + if (hw->sync_ptr) + free(hw->sync_ptr); + + hw->mmap_status = NULL; + hw->mmap_control = NULL; + hw->sync_ptr = NULL; } static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -- 2.13.5 From afadf61e44706880c32a854648645409c82dc0a2 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 25 Jun 2017 13:41:22 +0900 Subject: [PATCH 12/39] pcm: hw: allocate fallback buffer in advance of trials of mapping When allowing failure of map operation for both of status/control data for runtime of PCM substream, applications need to use fallback buffer for an alternative ioctl. However, in current implementation, status mapping is dominant to the allocation. This commit moves code for the allocation outside of the mapping operation for status data. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 1d34956c..a3d1f137 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -867,21 +867,18 @@ static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_u return xfern.result; } -static int map_status_data(snd_pcm_hw_t *hw) +static int map_status_data(snd_pcm_hw_t *hw, struct snd_pcm_sync_ptr *sync_ptr) { void *ptr; - int err; + ptr = MAP_FAILED; if (hw->sync_ptr_ioctl == 0) ptr = mmap(NULL, page_align(sizeof(struct snd_pcm_mmap_status)), PROT_READ, MAP_FILE|MAP_SHARED, hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); if (ptr == MAP_FAILED || ptr == NULL) { - hw->sync_ptr = calloc(1, sizeof(struct snd_pcm_sync_ptr)); - if (hw->sync_ptr == NULL) - return -ENOMEM; - hw->mmap_status = &hw->sync_ptr->s.status; - hw->mmap_control = &hw->sync_ptr->c.control; + hw->mmap_status = &sync_ptr->s.status; + hw->mmap_control = &sync_ptr->c.control; hw->sync_ptr_ioctl = 1; } else { hw->mmap_status = ptr; @@ -894,7 +891,7 @@ static int map_control_data(snd_pcm_hw_t *hw) { void *ptr; int err; - if (hw->sync_ptr == NULL) { + if (hw->sync_ptr_ioctl == 0) { ptr = mmap(NULL, page_align(sizeof(struct snd_pcm_mmap_control)), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); @@ -912,11 +909,18 @@ static int map_control_data(snd_pcm_hw_t *hw) static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) { snd_pcm_hw_t *hw = pcm->private_data; + struct snd_pcm_sync_ptr *sync_ptr; int err; + /* Preparation for fallback to failure of mmap(2). */ + sync_ptr = malloc(sizeof(*sync_ptr)); + if (sync_ptr == NULL) + return -ENOMEM; + memset(sync_ptr, 0, sizeof(*sync_ptr)); + hw->sync_ptr_ioctl = (int)force_fallback; - err = map_status_data(hw); + err = map_status_data(hw, sync_ptr); if (err < 0) return err; @@ -924,6 +928,14 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) if (err < 0) return err; + /* Any fallback mode needs to keep the buffer. */ + if (hw->sync_ptr_ioctl == 0) { + hw->sync_ptr = sync_ptr; + } else { + free(sync_ptr); + hw->sync_ptr = NULL; + } + /* Initialize the data. */ hw->mmap_control->appl_ptr = 0; hw->mmap_control->avail_min = 1; -- 2.13.5 From 9c9e3d0822777b36d7c8cae21550b180d108a160 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 25 Jun 2017 13:41:23 +0900 Subject: [PATCH 13/39] pcm: hw: maintain fallback mode for status data mapping In current implementation, results to map status/control data are not maintained separately. It's handled as a fatal error that mapping of status data is successful and mapping of control data is failed. However, it's possible to handle this case by utilizing fallback buffer. This commit adds a member into a local structure to maintain fallback mode just for the mapping of status data as a preparation of later commit, in which mapping results are maintained separately for each of status/control data. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 78 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index a3d1f137..78857941 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -91,10 +91,12 @@ typedef struct { int version; int fd; int card, device, subdevice; - int sync_ptr_ioctl; + volatile struct snd_pcm_mmap_status * mmap_status; struct snd_pcm_mmap_control *mmap_control; + bool mmap_status_fallbacked; struct snd_pcm_sync_ptr *sync_ptr; + int period_event; snd_timer_t *period_timer; struct pollfd period_timer_pfd; @@ -867,42 +869,53 @@ static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_u return xfern.result; } -static int map_status_data(snd_pcm_hw_t *hw, struct snd_pcm_sync_ptr *sync_ptr) +static bool map_status_data(snd_pcm_hw_t *hw, struct snd_pcm_sync_ptr *sync_ptr, + bool force_fallback) { - void *ptr; + struct snd_pcm_mmap_status *mmap_status; + bool fallbacked; + + mmap_status = MAP_FAILED; + if (!force_fallback) { + mmap_status = mmap(NULL, page_align(sizeof(*mmap_status)), + PROT_READ, MAP_FILE|MAP_SHARED, + hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); + } - ptr = MAP_FAILED; - if (hw->sync_ptr_ioctl == 0) - ptr = mmap(NULL, page_align(sizeof(struct snd_pcm_mmap_status)), - PROT_READ, MAP_FILE|MAP_SHARED, - hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); - if (ptr == MAP_FAILED || ptr == NULL) { - hw->mmap_status = &sync_ptr->s.status; - hw->mmap_control = &sync_ptr->c.control; - hw->sync_ptr_ioctl = 1; + if (mmap_status == MAP_FAILED || mmap_status == NULL) { + mmap_status = &sync_ptr->s.status; + fallbacked = true; } else { - hw->mmap_status = ptr; + fallbacked = false; } - return 0; + hw->mmap_status = mmap_status; + + return fallbacked; } -static int map_control_data(snd_pcm_hw_t *hw) +static bool map_control_data(snd_pcm_hw_t *hw, + struct snd_pcm_sync_ptr *sync_ptr, + bool force_fallback) { - void *ptr; + struct snd_pcm_mmap_control *mmap_control; int err; - if (hw->sync_ptr_ioctl == 0) { - ptr = mmap(NULL, page_align(sizeof(struct snd_pcm_mmap_control)), - PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, - hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); - if (ptr == MAP_FAILED || ptr == NULL) { + + if (!force_fallback) { + mmap_control = mmap(NULL, page_align(sizeof(*mmap_control)), + PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, + hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); + if (mmap_control == MAP_FAILED || mmap_control == NULL) { err = -errno; SYSMSG("control mmap failed (%i)", err); return err; } - hw->mmap_control = ptr; + } else { + mmap_control = &sync_ptr->c.control; } + hw->mmap_control = mmap_control; + return 0; } @@ -918,18 +931,14 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) return -ENOMEM; memset(sync_ptr, 0, sizeof(*sync_ptr)); - hw->sync_ptr_ioctl = (int)force_fallback; - - err = map_status_data(hw, sync_ptr); - if (err < 0) - return err; - - err = map_control_data(hw); + hw->mmap_status_fallbacked = + map_status_data(hw, sync_ptr, force_fallback); + err = map_control_data(hw, sync_ptr, hw->mmap_status_fallbacked); if (err < 0) return err; /* Any fallback mode needs to keep the buffer. */ - if (hw->sync_ptr_ioctl == 0) { + if (hw->mmap_status_fallbacked == 0) { hw->sync_ptr = sync_ptr; } else { free(sync_ptr); @@ -944,7 +953,7 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) offsetof(struct snd_pcm_mmap_status, hw_ptr)); snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); - if (hw->sync_ptr_ioctl) { + if (hw->mmap_status_fallbacked) { if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { err = -errno; SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); @@ -957,7 +966,7 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) static void unmap_status_data(snd_pcm_hw_t *hw) { - if (!hw->sync_ptr) { + if (!hw->mmap_status_fallbacked) { if (munmap((void *)hw->mmap_status, page_align(sizeof(*hw->mmap_status))) < 0) SYSMSG("status munmap failed (%u)", errno); @@ -966,7 +975,7 @@ static void unmap_status_data(snd_pcm_hw_t *hw) static void unmap_control_data(snd_pcm_hw_t *hw) { - if (!hw->sync_ptr) { + if (!hw->mmap_status_fallbacked) { if (munmap((void *)hw->mmap_control, page_align(sizeof(*hw->mmap_control))) < 0) SYSMSG("control munmap failed (%u)", errno); @@ -978,11 +987,12 @@ static void unmap_status_and_control_data(snd_pcm_hw_t *hw) unmap_status_data(hw); unmap_control_data(hw); - if (hw->sync_ptr) + if (hw->mmap_status_fallbacked) free(hw->sync_ptr); hw->mmap_status = NULL; hw->mmap_control = NULL; + hw->mmap_status_fallbacked = false; hw->sync_ptr = NULL; } -- 2.13.5 From 48bf3d3e964fbd34afd430632e8f2f5ca395d24c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 25 Jun 2017 13:41:24 +0900 Subject: [PATCH 14/39] pcm: hw: maintain fallback mode for control data mapping independently Currently, failures of status/control data mapping are handled dependently. However, it's not sure that one of the operations is failed when another is failed. This commit adds a member into private data structure to maintain fallback mode for control data mapping, independently of status data mapping. As a result, we have four cases to handle status/control data: 1. both of status/control data are mapped. Nothing changed. A structure with alias of 'snd_pcm_hw_t' already has two members to point the mapped area and in application runtime they're used to refer/set status/control data. No need to call ioctl(2) with SNDRV_PCM_IOCTL_SYNC_PTR to issue/query the data. 2. both of status/control data are unmapped. The two members point to allocated memory for fallback buffer. In application runtime, the buffer is given as an argument for ioctl(2) with SNDRV_PCM_IOCTL_SYNC_PTR to issue/query the data. 3. status data is mapped only. One of the two members is used to point the mapped area. Another points to allocated memory for fallback buffer. In application runtime, the buffer is used as an argument to execute ioctl(2) with SNDRV_PCM_IOCTL_SYNC_PTR for the latter data, but the former data is already synchronized. 4. control data is mapped only. The same as the above. In design of ALSA PCM interface, userspace applications are not expected to map the status data as writable. On the other hand, expected to map the control data as writable. In a focus on the differences, we could achieve to reduce calls of the ioctl(2) in a case that one of the status/control data is successfully mapped and another is failed (case 3 and 4). Especially, in current alsa-lib implementation, application runtime queries state of runtime of PCM substream so often. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 78857941..5573fce2 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -95,6 +95,7 @@ typedef struct { volatile struct snd_pcm_mmap_status * mmap_status; struct snd_pcm_mmap_control *mmap_control; bool mmap_status_fallbacked; + bool mmap_control_fallbacked; struct snd_pcm_sync_ptr *sync_ptr; int period_event; @@ -143,9 +144,11 @@ static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags) return 0; } -static inline int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) +static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) { - return hw->sync_ptr ? sync_ptr1(hw, flags) : 0; + if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) + return sync_ptr1(hw, flags); + return 0; } static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw) @@ -899,24 +902,24 @@ static bool map_control_data(snd_pcm_hw_t *hw, bool force_fallback) { struct snd_pcm_mmap_control *mmap_control; - int err; + bool fallbacked; if (!force_fallback) { mmap_control = mmap(NULL, page_align(sizeof(*mmap_control)), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); - if (mmap_control == MAP_FAILED || mmap_control == NULL) { - err = -errno; - SYSMSG("control mmap failed (%i)", err); - return err; - } - } else { + } + + if (mmap_control == MAP_FAILED || mmap_control == NULL) { mmap_control = &sync_ptr->c.control; + fallbacked = true; + } else { + fallbacked = false; } hw->mmap_control = mmap_control; - return 0; + return fallbacked; } static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) @@ -933,12 +936,11 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) hw->mmap_status_fallbacked = map_status_data(hw, sync_ptr, force_fallback); - err = map_control_data(hw, sync_ptr, hw->mmap_status_fallbacked); - if (err < 0) - return err; + hw->mmap_control_fallbacked = + map_control_data(hw, sync_ptr, force_fallback); /* Any fallback mode needs to keep the buffer. */ - if (hw->mmap_status_fallbacked == 0) { + if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) { hw->sync_ptr = sync_ptr; } else { free(sync_ptr); @@ -953,7 +955,7 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) offsetof(struct snd_pcm_mmap_status, hw_ptr)); snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); - if (hw->mmap_status_fallbacked) { + if (hw->mmap_control_fallbacked) { if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { err = -errno; SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); @@ -975,7 +977,7 @@ static void unmap_status_data(snd_pcm_hw_t *hw) static void unmap_control_data(snd_pcm_hw_t *hw) { - if (!hw->mmap_status_fallbacked) { + if (!hw->mmap_control_fallbacked) { if (munmap((void *)hw->mmap_control, page_align(sizeof(*hw->mmap_control))) < 0) SYSMSG("control munmap failed (%u)", errno); @@ -987,12 +989,13 @@ static void unmap_status_and_control_data(snd_pcm_hw_t *hw) unmap_status_data(hw); unmap_control_data(hw); - if (hw->mmap_status_fallbacked) + if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) free(hw->sync_ptr); hw->mmap_status = NULL; hw->mmap_control = NULL; hw->mmap_status_fallbacked = false; + hw->mmap_control_fallbacked = false; hw->sync_ptr = NULL; } -- 2.13.5 From 8ef3805f1b80a6c6059e0d9efd404fe32697db15 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Jun 2017 14:21:20 +0200 Subject: [PATCH 15/39] pcm: hw: Call USER_PVERSION ioctl at open Up from the new PCM protocol 2.0.14, user-space can inform the protocol version it supports to kernel, so that the kernel may switch its behavior depending on it. Add this ioctl call in the PCM hw plugin at opening. The patch contains also the addition of SNDRV_PCM_INFO_SYNC_APPLPTR carried from the upstream kernel commit 42f945970af9 ("ALSA: pcm: Add the explicit appl_ptr sync support"), as well as the trivial change (an addition of comma) to sync with the kernel asound.h. Reviewed-by: Takashi Sakamoto Tested-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/asound.h | 6 ++++-- src/pcm/pcm_hw.c | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/sound/asound.h b/include/sound/asound.h index fb8d7d7e..1949923a 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -111,7 +111,7 @@ enum { SNDRV_HWDEP_IFACE_FW_FIREFACE, /* RME Fireface series */ /* Don't forget to change the following: */ - SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_FIREFACE, + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_FIREFACE }; struct snd_hwdep_info { @@ -152,7 +152,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 13) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 14) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; @@ -268,6 +268,7 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */ #define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */ #define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */ +#define SNDRV_PCM_INFO_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */ #define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */ #define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */ #define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */ @@ -563,6 +564,7 @@ enum { #define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) #define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) #define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int) +#define SNDRV_PCM_IOCTL_USER_PVERSION _IOW('A', 0x04, int) #define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params) #define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params) #define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 5573fce2..64188b22 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -1494,6 +1494,16 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_PCM_VERSION_MAX)) return -SND_ERROR_INCOMPATIBLE_VERSION; + if (SNDRV_PROTOCOL_VERSION(2, 0, 14) <= ver) { + /* inform the protocol version we're supporting */ + unsigned int user_ver = SNDRV_PCM_VERSION; + if (ioctl(fd, SNDRV_PCM_IOCTL_USER_PVERSION, &user_ver) < 0) { + ret = -errno; + SNDMSG("USER_PVERSION failed\n"); + return ret; + } + } + #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) if (SNDRV_PROTOCOL_VERSION(2, 0, 9) <= ver) { struct timespec timespec; -- 2.13.5 From ec16d21f86abbc23a56abeed0419a5a863ee5400 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 30 Jun 2017 19:50:00 +0900 Subject: [PATCH 16/39] pcm: hw: fix to initialize function local variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit is to fix below warning. pcm_hw.c: In function ‘snd1_pcm_hw_open_fd’: pcm_hw.c:955:33: warning: ‘mmap_control’ may be used uninitialized in this function [-Wmaybe-uninitialized] if (mmap_control == MAP_FAILED || mmap_control == NULL) { ^ pcm_hw.c:946:31: note: ‘mmap_control’ was declared here struct snd_pcm_mmap_control *mmap_control; ^~~~~~~~~~~~ Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 64188b22..e0931577 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -904,6 +904,7 @@ static bool map_control_data(snd_pcm_hw_t *hw, struct snd_pcm_mmap_control *mmap_control; bool fallbacked; + mmap_control = MAP_FAILED; if (!force_fallback) { mmap_control = mmap(NULL, page_align(sizeof(*mmap_control)), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, -- 2.13.5 From 84beecc71ec508feb32bdf3fd1655dc7d0badfac Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 30 Jun 2017 14:14:55 +0100 Subject: [PATCH 17/39] topology: Add support for new widget types Add topology support for new DSP widget types. This allows the new widgets to be added to the driver and firmware DAPM graphs. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai --- include/sound/asoc.h | 10 +++++++++- src/topology/dapm.c | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/sound/asoc.h b/include/sound/asoc.h index 082c5429..0f5d9f9a 100644 --- a/include/sound/asoc.h +++ b/include/sound/asoc.h @@ -70,7 +70,15 @@ #define SND_SOC_TPLG_DAPM_DAI_IN 13 #define SND_SOC_TPLG_DAPM_DAI_OUT 14 #define SND_SOC_TPLG_DAPM_DAI_LINK 15 -#define SND_SOC_TPLG_DAPM_LAST SND_SOC_TPLG_DAPM_DAI_LINK +#define SND_SOC_TPLG_DAPM_BUFFER 16 +#define SND_SOC_TPLG_DAPM_SCHEDULER 17 +#define SND_SOC_TPLG_DAPM_EFFECT 18 +#define SND_SOC_TPLG_DAPM_SIGGEN 19 +#define SND_SOC_TPLG_DAPM_SRC 20 +#define SND_SOC_TPLG_DAPM_ASRC 21 +#define SND_SOC_TPLG_DAPM_ENCODER 22 +#define SND_SOC_TPLG_DAPM_DECODER 23 +#define SND_SOC_TPLG_DAPM_LAST SND_SOC_TPLG_DAPM_DECODER /* Header magic number and string sizes */ #define SND_SOC_TPLG_MAGIC 0x41536F43 /* ASoC */ diff --git a/src/topology/dapm.c b/src/topology/dapm.c index 6af750b9..66892a66 100644 --- a/src/topology/dapm.c +++ b/src/topology/dapm.c @@ -38,6 +38,14 @@ static const struct map_elem widget_map[] = { {"dai_in", SND_SOC_TPLG_DAPM_DAI_IN}, {"dai_out", SND_SOC_TPLG_DAPM_DAI_OUT}, {"dai_link", SND_SOC_TPLG_DAPM_DAI_LINK}, + {"buffer", SND_SOC_TPLG_DAPM_BUFFER}, + {"scheduler", SND_SOC_TPLG_DAPM_SCHEDULER}, + {"effect", SND_SOC_TPLG_DAPM_EFFECT}, + {"siggen", SND_SOC_TPLG_DAPM_SIGGEN}, + {"src", SND_SOC_TPLG_DAPM_SRC}, + {"asrc", SND_SOC_TPLG_DAPM_ASRC}, + {"encoder", SND_SOC_TPLG_DAPM_ENCODER}, + {"decoder", SND_SOC_TPLG_DAPM_DECODER}, }; static int lookup_widget(const char *w) -- 2.13.5 From 5c9582b8b428f3dbacb9e2fc32924f55c38efe8d Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 30 Jun 2017 14:14:56 +0100 Subject: [PATCH 18/39] topology: improve verbose output for block output. Show index and full DAPm route in verbose output. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai --- src/topology/builder.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/topology/builder.c b/src/topology/builder.c index ca5cbe1a..997df0c7 100644 --- a/src/topology/builder.c +++ b/src/topology/builder.c @@ -67,9 +67,10 @@ static int write_block_header(snd_tplg_t *tplg, unsigned int type, exit(-EINVAL); } - verbose(tplg, " header type %d size 0x%lx/%ld vendor %d " - "version %d\n", type, (long unsigned int)payload_size, - (long int)payload_size, vendor_type, version); + verbose(tplg, " header index %d type %d count %d size 0x%lx/%ld vendor %d " + "version %d\n", index, type, count, + (long unsigned int)payload_size, (long int)payload_size, + vendor_type, version); tplg->next_hdr_pos += hdr.payload_size + sizeof(hdr); @@ -119,8 +120,10 @@ static int write_elem_block(snd_tplg_t *tplg, verbose(tplg, " %s '%s': write %d bytes\n", obj_name, elem->id, elem->size); else - verbose(tplg, " %s '%s': write %d bytes\n", - obj_name, elem->route->source, elem->size); + verbose(tplg, " %s '%s -> %s -> %s': write %d bytes\n", + obj_name, elem->route->source, + elem->route->control, + elem->route->sink, elem->size); wsize = write(tplg->out_fd, elem->obj, elem->size); if (wsize < 0) { -- 2.13.5 From 4396c83a4d572c32e88a6eb9d3f48240bf89da8e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 30 Jun 2017 20:00:26 +0900 Subject: [PATCH 19/39] pcm: hw: minor refactoring for initialization of control data At failure of control data mapping, alsa-lib goes to fallback mode. In this mode, a buffer is kept in user space and executes ioctl(2) with SNDRV_PCM_IOCTL_SYNC_PTR for the buffer to synchronize the control data. In current implementation, no helper function is used for initialize the control data. This commit use an proper helper function instead of a direct call of ioctl(2). Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index e0931577..f03bc589 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -957,11 +957,9 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); if (hw->mmap_control_fallbacked) { - if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { - err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); + err = sync_ptr1(hw, 0); + if (err < 0) return err; - } } return 0; -- 2.13.5 From ce0905c3ca50e143cadf7b0b70f3049ef8024dab Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 30 Jun 2017 20:37:24 +0900 Subject: [PATCH 20/39] pcm: hw: add a helper function to query status/control data When executing ioctl(2) with some commands, applications can request ALSA PCM core to change appl_ptr in kernel space. Below is a list of such operations: - SNDRV_PCM_IOCTL_PREPARE - SNDRV_PCM_IOCTL_RESET - SNDRV_PCM_IOCTL_REWIND - SNDRV_PCM_IOCTL_FORWARD - SNDRV_PCM_IOCTL_WRITEI_FRAMES - SNDRV_PCM_IOCTL_WRITEN_FRAMES - SNDRV_PCM_IOCTL_READI_FRAMES - SNDRV_PCM_IOCTL_READN_FRAMES After these operations, the value of appl_ptr should be synchronized between kernel/user spaces. This commit adds a helper function to query status and control data without issuing the control data just in fallback from failure of control mapping. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index f03bc589..9963523c 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -151,6 +151,20 @@ static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) return 0; } +static int query_status_and_control_data(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_control_fallbacked) + return 0; + + /* + * Query both of control/status data to avoid unexpected change of + * control data in kernel space. + */ + return sync_ptr1(hw, + SNDRV_PCM_SYNC_PTR_APPL | + SNDRV_PCM_SYNC_PTR_AVAIL_MIN); +} + static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw) { if (hw->period_timer_need_poll) { @@ -601,7 +615,7 @@ static int snd_pcm_hw_prepare(snd_pcm_t *pcm) SYSMSG("SNDRV_PCM_IOCTL_PREPARE failed (%i)", err); return err; } - return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); + return query_status_and_control_data(hw); } static int snd_pcm_hw_reset(snd_pcm_t *pcm) @@ -613,7 +627,7 @@ static int snd_pcm_hw_reset(snd_pcm_t *pcm) SYSMSG("SNDRV_PCM_IOCTL_RESET failed (%i)", err); return err; } - return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); + return query_status_and_control_data(hw); } static int snd_pcm_hw_start(snd_pcm_t *pcm) @@ -688,7 +702,7 @@ static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t fra SYSMSG("SNDRV_PCM_IOCTL_REWIND failed (%i)", err); return err; } - err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); + err = query_status_and_control_data(hw); if (err < 0) return err; return frames; @@ -709,7 +723,7 @@ static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t fr SYSMSG("SNDRV_PCM_IOCTL_FORWARD failed (%i)", err); return err; } - err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); + err = query_status_and_control_data(hw); if (err < 0) return err; return frames; @@ -805,8 +819,10 @@ static snd_pcm_sframes_t snd_pcm_hw_writei(snd_pcm_t *pcm, const void *buffer, s xferi.buf = (char*) buffer; xferi.frames = size; xferi.result = 0; /* make valgrind happy */ - err = ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xferi); - err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; + if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xferi) < 0) + err = -errno; + else + err = query_status_and_control_data(hw); #ifdef DEBUG_RW fprintf(stderr, "hw_writei: frames = %li, xferi.result = %li, err = %i\n", size, xferi.result, err); #endif @@ -824,8 +840,10 @@ static snd_pcm_sframes_t snd_pcm_hw_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_ memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */ xfern.bufs = bufs; xfern.frames = size; - err = ioctl(fd, SNDRV_PCM_IOCTL_WRITEN_FRAMES, &xfern); - err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; + if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEN_FRAMES, &xfern) < 0) + err = -errno; + else + err = query_status_and_control_data(hw); #ifdef DEBUG_RW fprintf(stderr, "hw_writen: frames = %li, result = %li, err = %i\n", size, xfern.result, err); #endif @@ -843,8 +861,10 @@ static snd_pcm_sframes_t snd_pcm_hw_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_ xferi.buf = buffer; xferi.frames = size; xferi.result = 0; /* make valgrind happy */ - err = ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi); - err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; + if (ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi) < 0) + err = -errno; + else + err = query_status_and_control_data(hw); #ifdef DEBUG_RW fprintf(stderr, "hw_readi: frames = %li, result = %li, err = %i\n", size, xferi.result, err); #endif @@ -862,8 +882,10 @@ static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_u memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */ xfern.bufs = bufs; xfern.frames = size; - err = ioctl(fd, SNDRV_PCM_IOCTL_READN_FRAMES, &xfern); - err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; + if (ioctl(fd, SNDRV_PCM_IOCTL_READN_FRAMES, &xfern) < 0) + err = -errno; + else + err = query_status_and_control_data(hw); #ifdef DEBUG_RW fprintf(stderr, "hw_readn: frames = %li, result = %li, err = %i\n", size, xfern.result, err); #endif -- 2.13.5 From 78f3165a9e82d6f5e83e0e7075cdd96b49f9f401 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 30 Jun 2017 20:37:25 +0900 Subject: [PATCH 21/39] pcm: hw: add a helper function just to query status data When mapping status data successfully, mapped page includes status data for applications. In this case, applications have no need to call ioctl(2) with SNDRV_PCM_IOCTL_SYNC_PTR. However, in current implementation, when map of control data is unavailable, applications execute the ioctl(2). This is inconvenient for some cases that applications require to query status only. This commit adds a helper function to query status data without issuing the control in fallback mode from failure of status mmap. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 9963523c..38d975af 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -165,6 +165,20 @@ static int query_status_and_control_data(snd_pcm_hw_t *hw) SNDRV_PCM_SYNC_PTR_AVAIL_MIN); } +static int query_status_data(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_status_fallbacked) + return 0; + + /* + * Query both of control/status data to avoid unexpected change of + * control data in kernel space. + */ + return sync_ptr1(hw, + SNDRV_PCM_SYNC_PTR_APPL | + SNDRV_PCM_SYNC_PTR_AVAIL_MIN); +} + static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw) { if (hw->period_timer_need_poll) { @@ -349,7 +363,7 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) params->info &= ~0xf0000000; if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) params->info |= SND_PCM_INFO_MONOTONIC; - return sync_ptr(hw, 0); + return query_status_data(hw); } static void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw) @@ -556,7 +570,7 @@ static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status) static snd_pcm_state_t snd_pcm_hw_state(snd_pcm_t *pcm) { snd_pcm_hw_t *hw = pcm->private_data; - int err = sync_ptr(hw, 0); + int err = query_status_data(hw); if (err < 0) return err; return (snd_pcm_state_t) hw->mmap_status->state; @@ -1064,7 +1078,7 @@ static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm) snd_pcm_hw_t *hw = pcm->private_data; snd_pcm_uframes_t avail; - sync_ptr(hw, 0); + query_status_data(hw); avail = snd_pcm_mmap_avail(pcm); switch (FAST_PCM_STATE(hw)) { case SNDRV_PCM_STATE_RUNNING: -- 2.13.5 From 8a3df40bce2ae3fd9e9dfdf979b2c672754e0b93 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 30 Jun 2017 20:37:26 +0900 Subject: [PATCH 22/39] pcm: hw: add a helper function to request hwsync without side-effects SNDRV_PCM_IOCTL_SYNC_PTR command for ioctl(2) with SNDRV_PCM_SYNC_PTR_HWSYNC flag has an effect to update hw_ptr. This is an alternative of SNDRV_PCM_IOCTL_HWSYNC but caller can get current status simultaneously. This commit adds a helper function just to issue hwsync. To avoid side-effect to change appl_ptr and avail_min, this commit uses SNDRV_PCM_SYNC_PTR_APPL and SNDRV_PCM_SYNC_PTR_AVAIL_MIN flags. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 38d975af..8455baaf 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -151,6 +151,21 @@ static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) return 0; } +static int request_hwsync(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_status_fallbacked) + return 0; + + /* + * Query both of control/status data to avoid unexpected change of + * control data in kernel space. + */ + return sync_ptr1(hw, + SNDRV_PCM_SYNC_PTR_HWSYNC | + SNDRV_PCM_SYNC_PTR_APPL | + SNDRV_PCM_SYNC_PTR_AVAIL_MIN); +} + static int query_status_and_control_data(snd_pcm_hw_t *hw) { if (!hw->mmap_control_fallbacked) @@ -593,8 +608,8 @@ static int snd_pcm_hw_hwsync(snd_pcm_t *pcm) snd_pcm_hw_t *hw = pcm->private_data; int fd = hw->fd, err; if (SNDRV_PROTOCOL_VERSION(2, 0, 3) <= hw->version) { - if (hw->sync_ptr) { - err = sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_HWSYNC); + if (hw->mmap_status_fallbacked) { + err = request_hwsync(hw); if (err < 0) return err; } else { -- 2.13.5 From de9fe69e40e6b705aeae9aa8d1408736d4a1e563 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 30 Jun 2017 20:37:27 +0900 Subject: [PATCH 23/39] pcm: hw: add a helper function to issue appl_ptr without side-effects After starting, PCM substream shift its state to running and applications can move appl_ptr by several ways. When status and control data of runtime of the PCM substream is not mapped, the applications should issue appl_ptr to kernel land. In this case, when any PCM frames is handled by mmap operation, the applications should issue appl_ptr to update. This commit adds a helper function for this purpose. To avoid unexpected change of avail_min, this commit uses a flag just to update appl_ptr. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 8455baaf..51512306 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -151,6 +151,15 @@ static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) return 0; } +static int issue_applptr(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_control_fallbacked) + return 0; + + /* Avoid unexpected change of avail_min in kernel space. */ + return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_AVAIL_MIN); +} + static int request_hwsync(snd_pcm_hw_t *hw) { if (!hw->mmap_status_fallbacked) @@ -667,7 +676,7 @@ static int snd_pcm_hw_start(snd_pcm_t *pcm) assert(pcm->stream != SND_PCM_STREAM_PLAYBACK || snd_pcm_mmap_playback_hw_avail(pcm) > 0); #endif - sync_ptr(hw, 0); + issue_applptr(hw); if (ioctl(hw->fd, SNDRV_PCM_IOCTL_START) < 0) { err = -errno; SYSMSG("SNDRV_PCM_IOCTL_START failed (%i)", err); @@ -1081,7 +1090,7 @@ static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm, snd_pcm_hw_t *hw = pcm->private_data; snd_pcm_mmap_appl_forward(pcm, size); - sync_ptr(hw, 0); + issue_applptr(hw); #ifdef DEBUG_MMAP fprintf(stderr, "appl_forward: hw_ptr = %li, appl_ptr = %li, size = %li\n", *pcm->hw.ptr, *pcm->appl.ptr, size); #endif -- 2.13.5 From cea81cbdc2e7be344a34992ad6adef451a759840 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 30 Jun 2017 20:37:28 +0900 Subject: [PATCH 24/39] pcm: hw: add a helper function to issue avail_min without side-effects At present, applications can change avail_min parameter of PCM substream by two ways; via mapped control data, and by executing ioctl(2) with SNDRV_PCM_IOCTL_SYNC_PTR. The former is available in a case that the applications map the data successfully. When utilizing alsa-lib API, the above is done by a call of 'snd_pcm_sw_params()' to hw PCM plugin. In current implementation, this call has an side-effect to issue appl_ptr unexpectedly. This commit adds a helper function to issue avail_min without the side-effect. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 51512306..9c8fc3f6 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -151,6 +151,15 @@ static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) return 0; } +static int issue_avail_min(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_control_fallbacked) + return 0; + + /* Avoid unexpected change of applptr in kernel space. */ + return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_APPL); +} + static int issue_applptr(snd_pcm_hw_t *hw) { if (!hw->mmap_control_fallbacked) @@ -506,7 +515,7 @@ static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) params->silence_size == pcm->silence_size && old_period_event == hw->period_event) { hw->mmap_control->avail_min = params->avail_min; - return sync_ptr(hw, 0); + return issue_avail_min(hw); } if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW && hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) { -- 2.13.5 From a9ec1a6f687a6cb4f14d3f093c2ee020b610e12d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 30 Jun 2017 20:37:29 +0900 Subject: [PATCH 25/39] pcm: hw: remove superfluous code to call of SNDRV_PCM_IOCTL_SYNC_PTR in snd_pcm_hw_forward() SNDRV_PCM_IOCTL_SYNC_PTR command was introduced to PCM protocol/interface in its version 2.0.7, however this command is used in a branch for the newer version protocol/interface in snd_pcm_hw_forward(). This commit removes the superfluous code as a part of work for code refactoring. Fixes: eafb4925124b ("- added SYNC_PTR ioctl support for pcm_hw plugin") Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- src/pcm/pcm_hw.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 9c8fc3f6..16d45e74 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -144,13 +144,6 @@ static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags) return 0; } -static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) -{ - if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) - return sync_ptr1(hw, flags); - return 0; -} - static int issue_avail_min(snd_pcm_hw_t *hw) { if (!hw->mmap_control_fallbacked) @@ -777,9 +770,6 @@ static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t fr } else { snd_pcm_sframes_t avail; - err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_HWSYNC); - if (err < 0) - return err; switch (FAST_PCM_STATE(hw)) { case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_DRAINING: @@ -797,9 +787,6 @@ static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t fr if (frames > (snd_pcm_uframes_t)avail) frames = avail; snd_pcm_mmap_appl_forward(pcm, frames); - err = sync_ptr(hw, 0); - if (err < 0) - return err; return frames; } } -- 2.13.5 From 885c64bcc48f5734da964d2da2b9a5603d7b2c8b Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Wed, 12 Jul 2017 10:45:18 +0200 Subject: [PATCH 26/39] cleanup: fix poll.h includes According POSIX[1] and linux manpage[2] the include is poll.h, not sys/poll.h. This fixes the he following compiler warning when build with musl libc: /usr/include/sys/poll.h:1:2: warning: #warning redirecting incorrect #include to [-Wcpp] #warning redirecting incorrect #include to ^~~~~~~ Signed-off-by: Natanael Copa Signed-off-by: Takashi Iwai --- aserver/aserver.c | 2 +- include/asoundlib-head.h | 2 +- include/local.h | 2 +- src/control/control.c | 2 +- src/control/control_shm.c | 2 +- src/pcm/pcm.c | 2 +- src/pcm/pcm_direct.c | 2 +- src/pcm/pcm_mmap.c | 2 +- src/pcm/pcm_share.c | 2 +- src/pcm/pcm_shm.c | 2 +- src/seq/seq.c | 2 +- src/shmarea.c | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/aserver/aserver.c b/aserver/aserver.c index ac20706b..46f731a4 100644 --- a/aserver/aserver.c +++ b/aserver/aserver.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/asoundlib-head.h b/include/asoundlib-head.h index 1ec611e5..21e32c6b 100644 --- a/include/asoundlib-head.h +++ b/include/asoundlib-head.h @@ -35,6 +35,6 @@ #include #include #include -#include +#include #include #include diff --git a/include/local.h b/include/local.h index 317f2e32..6a43a473 100644 --- a/include/local.h +++ b/include/local.h @@ -47,7 +47,7 @@ #error Header defining endianness not defined #endif #include -#include +#include #include #include #if defined(__linux__) diff --git a/src/control/control.c b/src/control/control.c index 134ba4c8..6439b294 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -90,7 +90,7 @@ against the original design. #include #include #include -#include +#include #include #include "control_local.h" diff --git a/src/control/control_shm.c b/src/control/control_shm.c index bd07d4af..9a2e268b 100644 --- a/src/control/control_shm.c +++ b/src/control/control_shm.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 200b10c2..2b4ce8ec 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -651,7 +651,7 @@ playback devices. #include #include #include -#include +#include #include #include #include "pcm_local.h" diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index 9fd376d8..393083f5 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c index 1948289c..4cf220a4 100644 --- a/src/pcm/pcm_mmap.c +++ b/src/pcm/pcm_mmap.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #ifdef HAVE_SYS_SHM_H #include diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index 5d8aaf21..21a57fc6 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include "pcm_local.h" diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c index a815ac6b..4ee958c1 100644 --- a/src/pcm/pcm_shm.c +++ b/src/pcm/pcm_shm.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/seq/seq.c b/src/seq/seq.c index b206e2f8..d5ed1c6a 100644 --- a/src/seq/seq.c +++ b/src/seq/seq.c @@ -777,7 +777,7 @@ void event_filter(snd_seq_t *seq, snd_seq_event_t *ev) */ -#include +#include #include "seq_local.h" /**************************************************************************** diff --git a/src/shmarea.c b/src/shmarea.c index 9843aa8b..eaa71f00 100644 --- a/src/shmarea.c +++ b/src/shmarea.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include "list.h" -- 2.13.5 From adab355f35c8fcb424b1336043634cf9a6856515 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Fri, 14 Jul 2017 16:18:11 +0200 Subject: [PATCH 27/39] cleanup: Use uint*_t instead of u_int*_t everythwere Use the standard uint{8,16,32,64}_t everywhere instead of the non-standard u_int{8,16,32,64}_t. This changes the types in the public headers and removes the u_int*_t defines. This may break things. However, indentifiers ending with _t are reserved by POSIX[1]; defining those can lead to undefined behavior. So if you rely on alsa-lib defining those for you, then you want the compiler to error so things can be fixed properly. [1]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_02_02 Signed-off-by: Natanael Copa Signed-off-by: Takashi Iwai --- include/pcm.h | 10 ++- include/type_compat.h | 12 --- src/pcm/interval.c | 4 +- src/pcm/mask_inline.h | 6 +- src/pcm/pcm.c | 26 +++---- src/pcm/pcm_iec958.c | 12 +-- src/pcm/pcm_linear.c | 2 +- src/pcm/pcm_misc.c | 42 +++++------ src/pcm/pcm_rate_linear.c | 4 +- src/pcm/pcm_route.c | 2 +- src/pcm/plugin_ops.h | 182 +++++++++++++++++++++++----------------------- 11 files changed, 146 insertions(+), 156 deletions(-) diff --git a/include/pcm.h b/include/pcm.h index 0be1a321..d44de54b 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -33,6 +33,8 @@ extern "C" { #endif +#include + /** * \defgroup PCM PCM Interface * See the \ref pcm page for more details. @@ -1108,10 +1110,10 @@ int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */ int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */ snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian); ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples); -u_int8_t snd_pcm_format_silence(snd_pcm_format_t format); -u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format); -u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format); -u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format); +uint8_t snd_pcm_format_silence(snd_pcm_format_t format); +uint16_t snd_pcm_format_silence_16(snd_pcm_format_t format); +uint32_t snd_pcm_format_silence_32(snd_pcm_format_t format); +uint64_t snd_pcm_format_silence_64(snd_pcm_format_t format); int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int samples); snd_pcm_sframes_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes); diff --git a/include/type_compat.h b/include/type_compat.h index 0c10aed7..35973b1e 100644 --- a/include/type_compat.h +++ b/include/type_compat.h @@ -47,18 +47,6 @@ #ifndef __le64 #define __le64 uint64_t #endif -#ifndef u_int8_t -#define u_int8_t uint8_t -#endif -#ifndef u_int16_t -#define u_int16_t uint16_t -#endif -#ifndef u_int32_t -#define u_int32_t uint32_t -#endif -#ifndef u_int32_t -#define u_int32_t uint64_t -#endif #ifndef __kernel_pid_t #define __kernel_pid_t pid_t #endif diff --git a/src/pcm/interval.c b/src/pcm/interval.c index 6e398084..74ec3204 100644 --- a/src/pcm/interval.c +++ b/src/pcm/interval.c @@ -26,7 +26,7 @@ #include #include "pcm_local.h" -static inline void div64_32(u_int64_t *n, u_int32_t d, u_int32_t *rem) +static inline void div64_32(uint64_t *n, uint32_t d, uint32_t *rem) { *rem = *n % d; *n /= d; @@ -88,7 +88,7 @@ static inline unsigned int sub(unsigned int a, unsigned int b) static inline unsigned int muldiv32(unsigned int a, unsigned int b, unsigned int c, unsigned int *r) { - u_int64_t n = (u_int64_t) a * b; + uint64_t n = (uint64_t) a * b; if (c == 0) { assert(n > 0); *r = 0; diff --git a/src/pcm/mask_inline.h b/src/pcm/mask_inline.h index f656568d..04c7ee6e 100644 --- a/src/pcm/mask_inline.h +++ b/src/pcm/mask_inline.h @@ -29,7 +29,7 @@ #define MASK_OFS(i) ((i) >> 5) #define MASK_BIT(i) (1U << ((i) & 31)) -MASK_INLINE unsigned int ld2(u_int32_t v) +MASK_INLINE unsigned int ld2(uint32_t v) { unsigned r = 0; @@ -54,7 +54,7 @@ MASK_INLINE unsigned int ld2(u_int32_t v) return r; } -MASK_INLINE unsigned int hweight32(u_int32_t v) +MASK_INLINE unsigned int hweight32(uint32_t v) { v = (v & 0x55555555) + ((v >> 1) & 0x55555555); v = (v & 0x33333333) + ((v >> 2) & 0x33333333); @@ -75,7 +75,7 @@ MASK_INLINE void snd_mask_none(snd_mask_t *mask) MASK_INLINE void snd_mask_any(snd_mask_t *mask) { - memset(mask, 0xff, MASK_SIZE * sizeof(u_int32_t)); + memset(mask, 0xff, MASK_SIZE * sizeof(uint32_t)); } MASK_INLINE int snd_mask_empty(const snd_mask_t *mask) diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 2b4ce8ec..fc7bd52c 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -2894,7 +2894,7 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes char *dst; unsigned int dst_step; int width; - u_int64_t silence; + uint64_t silence; if (!dst_area->addr) return 0; dst = snd_pcm_channel_area_addr(dst_area, dst_offset); @@ -2902,7 +2902,7 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes silence = snd_pcm_format_silence_64(format); if (dst_area->step == (unsigned int) width) { unsigned int dwords = samples * width / 64; - u_int64_t *dstp = (u_int64_t *)dst; + uint64_t *dstp = (uint64_t *)dst; samples -= dwords * 64 / width; while (dwords-- > 0) *dstp++ = silence; @@ -2912,8 +2912,8 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes dst_step = dst_area->step / 8; switch (width) { case 4: { - u_int8_t s0 = silence & 0xf0; - u_int8_t s1 = silence & 0x0f; + uint8_t s0 = silence & 0xf0; + uint8_t s1 = silence & 0x0f; int dstbit = dst_area->first % 8; int dstbit_step = dst_area->step % 8; while (samples-- > 0) { @@ -2934,7 +2934,7 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes break; } case 8: { - u_int8_t sil = silence; + uint8_t sil = silence; while (samples-- > 0) { *dst = sil; dst += dst_step; @@ -2942,9 +2942,9 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes break; } case 16: { - u_int16_t sil = silence; + uint16_t sil = silence; while (samples-- > 0) { - *(u_int16_t*)dst = sil; + *(uint16_t*)dst = sil; dst += dst_step; } break; @@ -2961,16 +2961,16 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes #endif break; case 32: { - u_int32_t sil = silence; + uint32_t sil = silence; while (samples-- > 0) { - *(u_int32_t*)dst = sil; + *(uint32_t*)dst = sil; dst += dst_step; } break; } case 64: { while (samples-- > 0) { - *(u_int64_t*)dst = silence; + *(uint64_t*)dst = silence; dst += dst_step; } break; @@ -3114,7 +3114,7 @@ int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t } case 16: { while (samples-- > 0) { - *(u_int16_t*)dst = *(const u_int16_t*)src; + *(uint16_t*)dst = *(const uint16_t*)src; src += src_step; dst += dst_step; } @@ -3131,7 +3131,7 @@ int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t break; case 32: { while (samples-- > 0) { - *(u_int32_t*)dst = *(const u_int32_t*)src; + *(uint32_t*)dst = *(const uint32_t*)src; src += src_step; dst += dst_step; } @@ -3139,7 +3139,7 @@ int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t } case 64: { while (samples-- > 0) { - *(u_int64_t*)dst = *(const u_int64_t*)src; + *(uint64_t*)dst = *(const uint64_t*)src; src += src_step; dst += dst_step; } diff --git a/src/pcm/pcm_iec958.c b/src/pcm/pcm_iec958.c index 86ac9cfd..115092de 100644 --- a/src/pcm/pcm_iec958.c +++ b/src/pcm/pcm_iec958.c @@ -102,7 +102,7 @@ static unsigned int iec958_parity(unsigned int data) * 31 = parity */ -static inline u_int32_t iec958_subframe(snd_pcm_iec958_t *iec, u_int32_t data, int channel) +static inline uint32_t iec958_subframe(snd_pcm_iec958_t *iec, uint32_t data, int channel) { unsigned int byte = iec->counter >> 3; unsigned int mask = 1 << (iec->counter - (byte << 3)); @@ -132,7 +132,7 @@ static inline u_int32_t iec958_subframe(snd_pcm_iec958_t *iec, u_int32_t data, i return data; } -static inline int32_t iec958_to_s32(snd_pcm_iec958_t *iec, u_int32_t data) +static inline int32_t iec958_to_s32(snd_pcm_iec958_t *iec, uint32_t data) { if (iec->byteswap) data = bswap_32(data); @@ -155,7 +155,7 @@ static void snd_pcm_iec958_decode(snd_pcm_iec958_t *iec, void *put = put32_labels[iec->getput_idx]; unsigned int channel; for (channel = 0; channel < channels; ++channel) { - const u_int32_t *src; + const uint32_t *src; char *dst; int src_step, dst_step; snd_pcm_uframes_t frames1; @@ -163,7 +163,7 @@ static void snd_pcm_iec958_decode(snd_pcm_iec958_t *iec, const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; src = snd_pcm_channel_area_addr(src_area, src_offset); dst = snd_pcm_channel_area_addr(dst_area, dst_offset); - src_step = snd_pcm_channel_area_step(src_area) / sizeof(u_int32_t); + src_step = snd_pcm_channel_area_step(src_area) / sizeof(uint32_t); dst_step = snd_pcm_channel_area_step(dst_area); frames1 = frames; while (frames1-- > 0) { @@ -195,7 +195,7 @@ static void snd_pcm_iec958_encode(snd_pcm_iec958_t *iec, int counter = iec->counter; for (channel = 0; channel < channels; ++channel) { const char *src; - u_int32_t *dst; + uint32_t *dst; int src_step, dst_step; snd_pcm_uframes_t frames1; const snd_pcm_channel_area_t *src_area = &src_areas[channel]; @@ -203,7 +203,7 @@ static void snd_pcm_iec958_encode(snd_pcm_iec958_t *iec, src = snd_pcm_channel_area_addr(src_area, src_offset); dst = snd_pcm_channel_area_addr(dst_area, dst_offset); src_step = snd_pcm_channel_area_step(src_area); - dst_step = snd_pcm_channel_area_step(dst_area) / sizeof(u_int32_t); + dst_step = snd_pcm_channel_area_step(dst_area) / sizeof(uint32_t); frames1 = frames; iec->counter = counter; while (frames1-- > 0) { diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c index 50df7794..9b1d9638 100644 --- a/src/pcm/pcm_linear.c +++ b/src/pcm/pcm_linear.c @@ -183,7 +183,7 @@ void snd_pcm_linear_getput(const snd_pcm_channel_area_t *dst_areas, snd_pcm_ufra void *get = get32_labels[get_idx]; void *put = put32_labels[put_idx]; unsigned int channel; - u_int32_t sample = 0; + uint32_t sample = 0; for (channel = 0; channel < channels; ++channel) { const char *src; char *dst; diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c index 7d2b05db..a321c87e 100644 --- a/src/pcm/pcm_misc.c +++ b/src/pcm/pcm_misc.c @@ -387,7 +387,7 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) * \param format Sample format * \return silence 64 bit word */ -u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) +uint64_t snd_pcm_format_silence_64(snd_pcm_format_t format) { switch (format) { case SNDRV_PCM_FORMAT_S8: @@ -467,7 +467,7 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) { union { float f[2]; - u_int64_t i; + uint64_t i; } u; u.f[0] = u.f[1] = 0.0; #ifdef SNDRV_LITTLE_ENDIAN @@ -480,7 +480,7 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) { union { double f; - u_int64_t i; + uint64_t i; } u; u.f = 0.0; #ifdef SNDRV_LITTLE_ENDIAN @@ -493,7 +493,7 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) { union { float f[2]; - u_int64_t i; + uint64_t i; } u; u.f[0] = u.f[1] = 0.0; #ifdef SNDRV_LITTLE_ENDIAN @@ -506,7 +506,7 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) { union { double f; - u_int64_t i; + uint64_t i; } u; u.f = 0.0; #ifdef SNDRV_LITTLE_ENDIAN @@ -539,10 +539,10 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) * \param format Sample format * \return silence 32 bit word */ -u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format) +uint32_t snd_pcm_format_silence_32(snd_pcm_format_t format) { assert(snd_pcm_format_physical_width(format) <= 32); - return (u_int32_t)snd_pcm_format_silence_64(format); + return (uint32_t)snd_pcm_format_silence_64(format); } /** @@ -550,10 +550,10 @@ u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format) * \param format Sample format * \return silence 16 bit word */ -u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format) +uint16_t snd_pcm_format_silence_16(snd_pcm_format_t format) { assert(snd_pcm_format_physical_width(format) <= 16); - return (u_int16_t)snd_pcm_format_silence_64(format); + return (uint16_t)snd_pcm_format_silence_64(format); } /** @@ -561,10 +561,10 @@ u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format) * \param format Sample format * \return silence 8 bit word */ -u_int8_t snd_pcm_format_silence(snd_pcm_format_t format) +uint8_t snd_pcm_format_silence(snd_pcm_format_t format) { assert(snd_pcm_format_physical_width(format) <= 8); - return (u_int8_t)snd_pcm_format_silence_64(format); + return (uint8_t)snd_pcm_format_silence_64(format); } /** @@ -580,7 +580,7 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int return 0; switch (snd_pcm_format_physical_width(format)) { case 4: { - u_int8_t silence = snd_pcm_format_silence_64(format); + uint8_t silence = snd_pcm_format_silence_64(format); unsigned int samples1; if (samples % 2 != 0) return -EINVAL; @@ -589,13 +589,13 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int break; } case 8: { - u_int8_t silence = snd_pcm_format_silence_64(format); + uint8_t silence = snd_pcm_format_silence_64(format); memset(data, silence, samples); break; } case 16: { - u_int16_t silence = snd_pcm_format_silence_64(format); - u_int16_t *pdata = (u_int16_t *)data; + uint16_t silence = snd_pcm_format_silence_64(format); + uint16_t *pdata = (uint16_t *)data; if (! silence) memset(data, 0, samples * 2); else { @@ -605,8 +605,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int break; } case 24: { - u_int32_t silence = snd_pcm_format_silence_64(format); - u_int8_t *pdata = (u_int8_t *)data; + uint32_t silence = snd_pcm_format_silence_64(format); + uint8_t *pdata = (uint8_t *)data; if (! silence) memset(data, 0, samples * 3); else { @@ -625,8 +625,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int break; } case 32: { - u_int32_t silence = snd_pcm_format_silence_64(format); - u_int32_t *pdata = (u_int32_t *)data; + uint32_t silence = snd_pcm_format_silence_64(format); + uint32_t *pdata = (uint32_t *)data; if (! silence) memset(data, 0, samples * 4); else { @@ -636,8 +636,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int break; } case 64: { - u_int64_t silence = snd_pcm_format_silence_64(format); - u_int64_t *pdata = (u_int64_t *)data; + uint64_t silence = snd_pcm_format_silence_64(format); + uint64_t *pdata = (uint64_t *)data; if (! silence) memset(data, 0, samples * 8); else { diff --git a/src/pcm/pcm_rate_linear.c b/src/pcm/pcm_rate_linear.c index 70399e0d..b20c715a 100644 --- a/src/pcm/pcm_rate_linear.c +++ b/src/pcm/pcm_rate_linear.c @@ -346,7 +346,7 @@ static int linear_init(void *obj, snd_pcm_rate_info_t *info) rate->func = linear_shrink; /* pitch is get_increment */ } - rate->pitch = (((u_int64_t)info->out.rate * LINEAR_DIV) + + rate->pitch = (((uint64_t)info->out.rate * LINEAR_DIV) + (info->in.rate / 2)) / info->in.rate; rate->channels = info->channels; @@ -363,7 +363,7 @@ static int linear_adjust_pitch(void *obj, snd_pcm_rate_info_t *info) struct rate_linear *rate = obj; snd_pcm_uframes_t cframes; - rate->pitch = (((u_int64_t)info->out.period_size * LINEAR_DIV) + + rate->pitch = (((uint64_t)info->out.period_size * LINEAR_DIV) + (info->in.period_size/2) ) / info->in.period_size; cframes = input_frames(rate, info->out.period_size); diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c index 508d5b0f..1bb83d2f 100644 --- a/src/pcm/pcm_route.c +++ b/src/pcm/pcm_route.c @@ -190,7 +190,7 @@ static void snd_pcm_route_convert1_one_getput(const snd_pcm_channel_area_t *dst_ const char *src; char *dst; int src_step, dst_step; - u_int32_t sample = 0; + uint32_t sample = 0; for (srcidx = 0; srcidx < ttable->nsrcs && srcidx < src_channels; ++srcidx) { unsigned int channel = ttable->srcs[srcidx].channel; if (channel >= src_channels) diff --git a/src/pcm/plugin_ops.h b/src/pcm/plugin_ops.h index eb8c2c4f..69e7f2cf 100644 --- a/src/pcm/plugin_ops.h +++ b/src/pcm/plugin_ops.h @@ -21,13 +21,13 @@ #ifndef SX_INLINES #define SX_INLINES -static inline u_int32_t sx24(u_int32_t x) +static inline uint32_t sx24(uint32_t x) { if(x&0x00800000) return x|0xFF000000; return x&0x00FFFFFF; } -static inline u_int32_t sx24s(u_int32_t x) +static inline uint32_t sx24s(uint32_t x) { if(x&0x00008000) return x|0x000000FF; @@ -35,10 +35,10 @@ static inline u_int32_t sx24s(u_int32_t x) } #endif -#define as_u8(ptr) (*(u_int8_t*)(ptr)) -#define as_u16(ptr) (*(u_int16_t*)(ptr)) -#define as_u32(ptr) (*(u_int32_t*)(ptr)) -#define as_u64(ptr) (*(u_int64_t*)(ptr)) +#define as_u8(ptr) (*(uint8_t*)(ptr)) +#define as_u16(ptr) (*(uint16_t*)(ptr)) +#define as_u32(ptr) (*(uint32_t*)(ptr)) +#define as_u64(ptr) (*(uint64_t*)(ptr)) #define as_s8(ptr) (*(int8_t*)(ptr)) #define as_s16(ptr) (*(int16_t*)(ptr)) #define as_s32(ptr) (*(int32_t*)(ptr)) @@ -46,10 +46,10 @@ static inline u_int32_t sx24s(u_int32_t x) #define as_float(ptr) (*(float_t*)(ptr)) #define as_double(ptr) (*(double_t*)(ptr)) -#define as_u8c(ptr) (*(const u_int8_t*)(ptr)) -#define as_u16c(ptr) (*(const u_int16_t*)(ptr)) -#define as_u32c(ptr) (*(const u_int32_t*)(ptr)) -#define as_u64c(ptr) (*(const u_int64_t*)(ptr)) +#define as_u8c(ptr) (*(const uint8_t*)(ptr)) +#define as_u16c(ptr) (*(const uint16_t*)(ptr)) +#define as_u32c(ptr) (*(const uint32_t*)(ptr)) +#define as_u64c(ptr) (*(const uint64_t*)(ptr)) #define as_s8c(ptr) (*(const int8_t*)(ptr)) #define as_s16c(ptr) (*(const int16_t*)(ptr)) #define as_s32c(ptr) (*(const int32_t*)(ptr)) @@ -57,18 +57,18 @@ static inline u_int32_t sx24s(u_int32_t x) #define as_floatc(ptr) (*(const float_t*)(ptr)) #define as_doublec(ptr) (*(const double_t*)(ptr)) -#define _get_triple_le(ptr) (*(u_int8_t*)(ptr) | (u_int32_t)*((u_int8_t*)(ptr) + 1) << 8 | (u_int32_t)*((u_int8_t*)(ptr) + 2) << 16) -#define _get_triple_be(ptr) ((u_int32_t)*(u_int8_t*)(ptr) << 16 | (u_int32_t)*((u_int8_t*)(ptr) + 1) << 8 | *((u_int8_t*)(ptr) + 2)) +#define _get_triple_le(ptr) (*(uint8_t*)(ptr) | (uint32_t)*((uint8_t*)(ptr) + 1) << 8 | (uint32_t)*((uint8_t*)(ptr) + 2) << 16) +#define _get_triple_be(ptr) ((uint32_t)*(uint8_t*)(ptr) << 16 | (uint32_t)*((uint8_t*)(ptr) + 1) << 8 | *((uint8_t*)(ptr) + 2)) #define _put_triple_le(ptr,val) do { \ - u_int8_t *_tmp = (u_int8_t *)(ptr); \ - u_int32_t _val = (val); \ + uint8_t *_tmp = (uint8_t *)(ptr); \ + uint32_t _val = (val); \ _tmp[0] = _val; \ _tmp[1] = _val >> 8; \ _tmp[2] = _val >> 16; \ } while(0) #define _put_triple_be(ptr,val) do { \ - u_int8_t *_tmp = (u_int8_t *)(ptr); \ - u_int32_t _val = (val); \ + uint8_t *_tmp = (uint8_t *)(ptr); \ + uint32_t _val = (val); \ _tmp[0] = _val >> 16; \ _tmp[1] = _val >> 8; \ _tmp[2] = _val; \ @@ -243,45 +243,45 @@ static void *const conv_labels[4 * 2 * 2 * 4 * 2] = { #ifdef CONV_END while(0) { conv_xxx1_xxx1: as_u8(dst) = as_u8c(src); goto CONV_END; -conv_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8c(src) << 8; goto CONV_END; -conv_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8c(src); goto CONV_END; -conv_xxx1_x100: as_u32(dst) = sx24((u_int32_t)as_u8c(src) << 16); goto CONV_END; -conv_xxx1_001x: as_u32(dst) = sx24s((u_int32_t)as_u8c(src) << 8); goto CONV_END; -conv_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8c(src) << 24; goto CONV_END; -conv_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8c(src); goto CONV_END; +conv_xxx1_xx10: as_u16(dst) = (uint16_t)as_u8c(src) << 8; goto CONV_END; +conv_xxx1_xx01: as_u16(dst) = (uint16_t)as_u8c(src); goto CONV_END; +conv_xxx1_x100: as_u32(dst) = sx24((uint32_t)as_u8c(src) << 16); goto CONV_END; +conv_xxx1_001x: as_u32(dst) = sx24s((uint32_t)as_u8c(src) << 8); goto CONV_END; +conv_xxx1_1000: as_u32(dst) = (uint32_t)as_u8c(src) << 24; goto CONV_END; +conv_xxx1_0001: as_u32(dst) = (uint32_t)as_u8c(src); goto CONV_END; conv_xxx1_xxx9: as_u8(dst) = as_u8c(src) ^ 0x80; goto CONV_END; -conv_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8c(src) ^ 0x80) << 8; goto CONV_END; -conv_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8c(src) ^ 0x80); goto CONV_END; -conv_xxx1_x900: as_u32(dst) = sx24((u_int32_t)(as_u8c(src) ^ 0x80) << 16); goto CONV_END; -conv_xxx1_009x: as_u32(dst) = sx24s((u_int32_t)(as_u8c(src) ^ 0x80) << 8); goto CONV_END; -conv_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8c(src) ^ 0x80) << 24; goto CONV_END; -conv_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8c(src) ^ 0x80); goto CONV_END; +conv_xxx1_xx90: as_u16(dst) = (uint16_t)(as_u8c(src) ^ 0x80) << 8; goto CONV_END; +conv_xxx1_xx09: as_u16(dst) = (uint16_t)(as_u8c(src) ^ 0x80); goto CONV_END; +conv_xxx1_x900: as_u32(dst) = sx24((uint32_t)(as_u8c(src) ^ 0x80) << 16); goto CONV_END; +conv_xxx1_009x: as_u32(dst) = sx24s((uint32_t)(as_u8c(src) ^ 0x80) << 8); goto CONV_END; +conv_xxx1_9000: as_u32(dst) = (uint32_t)(as_u8c(src) ^ 0x80) << 24; goto CONV_END; +conv_xxx1_0009: as_u32(dst) = (uint32_t)(as_u8c(src) ^ 0x80); goto CONV_END; conv_xx12_xxx1: as_u8(dst) = as_u16c(src) >> 8; goto CONV_END; conv_xx12_xx12: as_u16(dst) = as_u16c(src); goto CONV_END; conv_xx12_xx21: as_u16(dst) = bswap_16(as_u16c(src)); goto CONV_END; -conv_xx12_x120: as_u32(dst) = sx24((u_int32_t)as_u16c(src) << 8); goto CONV_END; -conv_xx12_021x: as_u32(dst) = sx24s((u_int32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; -conv_xx12_1200: as_u32(dst) = (u_int32_t)as_u16c(src) << 16; goto CONV_END; -conv_xx12_0021: as_u32(dst) = (u_int32_t)bswap_16(as_u16c(src)); goto CONV_END; +conv_xx12_x120: as_u32(dst) = sx24((uint32_t)as_u16c(src) << 8); goto CONV_END; +conv_xx12_021x: as_u32(dst) = sx24s((uint32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; +conv_xx12_1200: as_u32(dst) = (uint32_t)as_u16c(src) << 16; goto CONV_END; +conv_xx12_0021: as_u32(dst) = (uint32_t)bswap_16(as_u16c(src)); goto CONV_END; conv_xx12_xxx9: as_u8(dst) = (as_u16c(src) >> 8) ^ 0x80; goto CONV_END; conv_xx12_xx92: as_u16(dst) = as_u16c(src) ^ 0x8000; goto CONV_END; conv_xx12_xx29: as_u16(dst) = bswap_16(as_u16c(src)) ^ 0x80; goto CONV_END; -conv_xx12_x920: as_u32(dst) = sx24((u_int32_t)(as_u16c(src) ^ 0x8000) << 8); goto CONV_END; -conv_xx12_029x: as_u32(dst) = sx24s((u_int32_t)(bswap_16(as_u16c(src)) ^ 0x80) << 8); goto CONV_END; -conv_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16c(src) ^ 0x8000) << 16; goto CONV_END; -conv_xx12_0029: as_u32(dst) = (u_int32_t)(bswap_16(as_u16c(src)) ^ 0x80); goto CONV_END; +conv_xx12_x920: as_u32(dst) = sx24((uint32_t)(as_u16c(src) ^ 0x8000) << 8); goto CONV_END; +conv_xx12_029x: as_u32(dst) = sx24s((uint32_t)(bswap_16(as_u16c(src)) ^ 0x80) << 8); goto CONV_END; +conv_xx12_9200: as_u32(dst) = (uint32_t)(as_u16c(src) ^ 0x8000) << 16; goto CONV_END; +conv_xx12_0029: as_u32(dst) = (uint32_t)(bswap_16(as_u16c(src)) ^ 0x80); goto CONV_END; conv_xx12_xxx2: as_u8(dst) = as_u16c(src) & 0xff; goto CONV_END; -conv_xx12_x210: as_u32(dst) = sx24((u_int32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; -conv_xx12_012x: as_u32(dst) = sx24s((u_int32_t)as_u16c(src) << 8); goto CONV_END; -conv_xx12_2100: as_u32(dst) = (u_int32_t)bswap_16(as_u16c(src)) << 16; goto CONV_END; -conv_xx12_0012: as_u32(dst) = (u_int32_t)as_u16c(src); goto CONV_END; +conv_xx12_x210: as_u32(dst) = sx24((uint32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; +conv_xx12_012x: as_u32(dst) = sx24s((uint32_t)as_u16c(src) << 8); goto CONV_END; +conv_xx12_2100: as_u32(dst) = (uint32_t)bswap_16(as_u16c(src)) << 16; goto CONV_END; +conv_xx12_0012: as_u32(dst) = (uint32_t)as_u16c(src); goto CONV_END; conv_xx12_xxxA: as_u8(dst) = (as_u16c(src) ^ 0x80) & 0xff; goto CONV_END; conv_xx12_xxA1: as_u16(dst) = bswap_16(as_u16c(src) ^ 0x80); goto CONV_END; conv_xx12_xx1A: as_u16(dst) = as_u16c(src) ^ 0x80; goto CONV_END; -conv_xx12_xA10: as_u32(dst) = sx24((u_int32_t)bswap_16(as_u16c(src) ^ 0x80) << 8); goto CONV_END; -conv_xx12_01Ax: as_u32(dst) = sx24s((u_int32_t)(as_u16c(src) ^ 0x80) << 8); goto CONV_END; -conv_xx12_A100: as_u32(dst) = (u_int32_t)bswap_16(as_u16c(src) ^ 0x80) << 16; goto CONV_END; -conv_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16c(src) ^ 0x80); goto CONV_END; +conv_xx12_xA10: as_u32(dst) = sx24((uint32_t)bswap_16(as_u16c(src) ^ 0x80) << 8); goto CONV_END; +conv_xx12_01Ax: as_u32(dst) = sx24s((uint32_t)(as_u16c(src) ^ 0x80) << 8); goto CONV_END; +conv_xx12_A100: as_u32(dst) = (uint32_t)bswap_16(as_u16c(src) ^ 0x80) << 16; goto CONV_END; +conv_xx12_001A: as_u32(dst) = (uint32_t)(as_u16c(src) ^ 0x80); goto CONV_END; conv_x123_xxx1: as_u8(dst) = as_u32c(src) >> 16; goto CONV_END; conv_x123_xx12: as_u16(dst) = as_u32c(src) >> 8; goto CONV_END; conv_x123_xx21: as_u16(dst) = bswap_16(as_u32c(src) >> 8); goto CONV_END; @@ -376,8 +376,8 @@ static void *const get16_labels[4 * 2 * 2 + 4 * 3] = { #ifdef GET16_END while(0) { -get16_1_10: sample = (u_int16_t)as_u8c(src) << 8; goto GET16_END; -get16_1_90: sample = (u_int16_t)(as_u8c(src) ^ 0x80) << 8; goto GET16_END; +get16_1_10: sample = (uint16_t)as_u8c(src) << 8; goto GET16_END; +get16_1_90: sample = (uint16_t)(as_u8c(src) ^ 0x80) << 8; goto GET16_END; get16_12_12: sample = as_u16c(src); goto GET16_END; get16_12_92: sample = as_u16c(src) ^ 0x8000; goto GET16_END; get16_12_21: sample = bswap_16(as_u16c(src)); goto GET16_END; @@ -448,26 +448,26 @@ put16_12_12: as_u16(dst) = sample; goto PUT16_END; put16_12_92: as_u16(dst) = sample ^ 0x8000; goto PUT16_END; put16_12_21: as_u16(dst) = bswap_16(sample); goto PUT16_END; put16_12_29: as_u16(dst) = bswap_16(sample) ^ 0x80; goto PUT16_END; -put16_12_0120: as_u32(dst) = sx24((u_int32_t)sample << 8); goto PUT16_END; -put16_12_0920: as_u32(dst) = sx24((u_int32_t)(sample ^ 0x8000) << 8); goto PUT16_END; -put16_12_0210: as_u32(dst) = sx24s((u_int32_t)bswap_16(sample) << 8); goto PUT16_END; -put16_12_0290: as_u32(dst) = sx24s((u_int32_t)(bswap_16(sample) ^ 0x80) << 8); goto PUT16_END; -put16_12_1200: as_u32(dst) = (u_int32_t)sample << 16; goto PUT16_END; -put16_12_9200: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 16; goto PUT16_END; -put16_12_0021: as_u32(dst) = (u_int32_t)bswap_16(sample); goto PUT16_END; -put16_12_0029: as_u32(dst) = (u_int32_t)bswap_16(sample) ^ 0x80; goto PUT16_END; -put16_12_120: _put_triple(dst, (u_int32_t)sample << 8); goto PUT16_END; -put16_12_920: _put_triple(dst, (u_int32_t)(sample ^ 0x8000) << 8); goto PUT16_END; -put16_12_021: _put_triple_s(dst, (u_int32_t)sample << 8); goto PUT16_END; -put16_12_029: _put_triple_s(dst, (u_int32_t)(sample ^ 0x8000) << 8); goto PUT16_END; -put16_12_120_20: _put_triple(dst, (u_int32_t)sample << 4); goto PUT16_END; -put16_12_920_20: _put_triple(dst, (u_int32_t)(sample ^ 0x8000) << 4); goto PUT16_END; -put16_12_021_20: _put_triple_s(dst, (u_int32_t)sample << 4); goto PUT16_END; -put16_12_029_20: _put_triple_s(dst, (u_int32_t)(sample ^ 0x8000) << 4); goto PUT16_END; -put16_12_120_18: _put_triple(dst, (u_int32_t)sample << 2); goto PUT16_END; -put16_12_920_18: _put_triple(dst, (u_int32_t)(sample ^ 0x8000) << 2); goto PUT16_END; -put16_12_021_18: _put_triple_s(dst, (u_int32_t)sample << 2); goto PUT16_END; -put16_12_029_18: _put_triple_s(dst, (u_int32_t)(sample ^ 0x8000) << 2); goto PUT16_END; +put16_12_0120: as_u32(dst) = sx24((uint32_t)sample << 8); goto PUT16_END; +put16_12_0920: as_u32(dst) = sx24((uint32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +put16_12_0210: as_u32(dst) = sx24s((uint32_t)bswap_16(sample) << 8); goto PUT16_END; +put16_12_0290: as_u32(dst) = sx24s((uint32_t)(bswap_16(sample) ^ 0x80) << 8); goto PUT16_END; +put16_12_1200: as_u32(dst) = (uint32_t)sample << 16; goto PUT16_END; +put16_12_9200: as_u32(dst) = (uint32_t)(sample ^ 0x8000) << 16; goto PUT16_END; +put16_12_0021: as_u32(dst) = (uint32_t)bswap_16(sample); goto PUT16_END; +put16_12_0029: as_u32(dst) = (uint32_t)bswap_16(sample) ^ 0x80; goto PUT16_END; +put16_12_120: _put_triple(dst, (uint32_t)sample << 8); goto PUT16_END; +put16_12_920: _put_triple(dst, (uint32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +put16_12_021: _put_triple_s(dst, (uint32_t)sample << 8); goto PUT16_END; +put16_12_029: _put_triple_s(dst, (uint32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +put16_12_120_20: _put_triple(dst, (uint32_t)sample << 4); goto PUT16_END; +put16_12_920_20: _put_triple(dst, (uint32_t)(sample ^ 0x8000) << 4); goto PUT16_END; +put16_12_021_20: _put_triple_s(dst, (uint32_t)sample << 4); goto PUT16_END; +put16_12_029_20: _put_triple_s(dst, (uint32_t)(sample ^ 0x8000) << 4); goto PUT16_END; +put16_12_120_18: _put_triple(dst, (uint32_t)sample << 2); goto PUT16_END; +put16_12_920_18: _put_triple(dst, (uint32_t)(sample ^ 0x8000) << 2); goto PUT16_END; +put16_12_021_18: _put_triple_s(dst, (uint32_t)sample << 2); goto PUT16_END; +put16_12_029_18: _put_triple_s(dst, (uint32_t)(sample ^ 0x8000) << 2); goto PUT16_END; } #endif @@ -517,12 +517,12 @@ static void *const get32_labels[4 * 2 * 2 + 4 * 3] = { #ifdef GET32_END while (0) { -get32_1_1000: sample = (u_int32_t)as_u8c(src) << 24; goto GET32_END; -get32_1_9000: sample = (u_int32_t)(as_u8c(src) ^ 0x80) << 24; goto GET32_END; -get32_12_1200: sample = (u_int32_t)as_u16c(src) << 16; goto GET32_END; -get32_12_9200: sample = (u_int32_t)(as_u16c(src) ^ 0x8000) << 16; goto GET32_END; -get32_12_2100: sample = (u_int32_t)bswap_16(as_u16c(src)) << 16; goto GET32_END; -get32_12_A100: sample = (u_int32_t)bswap_16(as_u16c(src) ^ 0x80) << 16; goto GET32_END; +get32_1_1000: sample = (uint32_t)as_u8c(src) << 24; goto GET32_END; +get32_1_9000: sample = (uint32_t)(as_u8c(src) ^ 0x80) << 24; goto GET32_END; +get32_12_1200: sample = (uint32_t)as_u16c(src) << 16; goto GET32_END; +get32_12_9200: sample = (uint32_t)(as_u16c(src) ^ 0x8000) << 16; goto GET32_END; +get32_12_2100: sample = (uint32_t)bswap_16(as_u16c(src)) << 16; goto GET32_END; +get32_12_A100: sample = (uint32_t)bswap_16(as_u16c(src) ^ 0x80) << 16; goto GET32_END; get32_0123_1230: sample = as_u32c(src) << 8; goto GET32_END; get32_0123_9230: sample = (as_u32c(src) << 8) ^ 0x80000000; goto GET32_END; get32_1230_3210: sample = bswap_32(as_u32c(src) >> 8); goto GET32_END; @@ -786,18 +786,18 @@ static inline void _norms(const void *src, void *dst, s += (1U << (dst_wid - 1)); switch (dst_wid) { case 8: - *(u_int8_t*)dst = s; + *(uint8_t*)dst = s; break; case 16: if (dst_end) s = bswap_16(s); - *(u_int16_t*)dst = s; + *(uint16_t*)dst = s; break; case 24: case 32: if (dst_end) s = bswap_32(s); - *(u_int32_t*)dst = s; + *(uint32_t*)dst = s; break; } return; @@ -806,27 +806,27 @@ static inline void _norms(const void *src, void *dst, switch (dst_wid) { case 8: if (dst_sign) - *(u_int8_t*)dst = 0x80; + *(uint8_t*)dst = 0x80; else - *(u_int8_t*)dst = 0; + *(uint8_t*)dst = 0; break; case 16: if (dst_sign) - *(u_int16_t*)dst = dst_end ? 0x0080 : 0x8000; + *(uint16_t*)dst = dst_end ? 0x0080 : 0x8000; else - *(u_int16_t*)dst = 0; + *(uint16_t*)dst = 0; break; case 24: if (dst_sign) - *(u_int32_t*)dst = dst_end ? 0x00008000 : 0x00800000; + *(uint32_t*)dst = dst_end ? 0x00008000 : 0x00800000; else - *(u_int32_t*)dst = 0; + *(uint32_t*)dst = 0; break; case 32: if (dst_sign) - *(u_int32_t*)dst = dst_end ? 0x00000080 : 0x80000000; + *(uint32_t*)dst = dst_end ? 0x00000080 : 0x80000000; else - *(u_int32_t*)dst = 0; + *(uint32_t*)dst = 0; break; default: assert(0); @@ -838,27 +838,27 @@ static inline void _norms(const void *src, void *dst, switch (dst_wid) { case 8: if (dst_sign) - *(u_int8_t*)dst = 0x7f; + *(uint8_t*)dst = 0x7f; else - *(u_int8_t*)dst = 0xff; + *(uint8_t*)dst = 0xff; break; case 16: if (dst_sign) - *(u_int16_t*)dst = dst_end ? 0xff7f : 0x7fff; + *(uint16_t*)dst = dst_end ? 0xff7f : 0x7fff; else - *(u_int16_t*)dst = 0; + *(uint16_t*)dst = 0; break; case 24: if (dst_sign) - *(u_int32_t*)dst = dst_end ? 0xffff7f00 : 0x007fffff; + *(uint32_t*)dst = dst_end ? 0xffff7f00 : 0x007fffff; else - *(u_int32_t*)dst = 0; + *(uint32_t*)dst = 0; break; case 32: if (dst_sign) - *(u_int32_t*)dst = dst_end ? 0xffffff7f : 0x7fffffff; + *(uint32_t*)dst = dst_end ? 0xffffff7f : 0x7fffffff; else - *(u_int32_t*)dst = 0; + *(uint32_t*)dst = 0; break; default: assert(0); -- 2.13.5 From cb34cee0d8da2fb131986d5782ddf5cec985c532 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Fri, 14 Jul 2017 18:47:05 +0200 Subject: [PATCH 28/39] snd_user_file: avoid use wordexp As suggested in POSIX[1], wordexp might execute the shell. If the libc implementation does so, it will break the firefox sandbox which does not allow exec. This happened on Alpine Linux with musl libc[2]. Since we cannot guarantee that the system wordexp implementation does not execute shell, we cannot really use it, and need to implement the ~/ expansion ourselves. We provide a configure option --with-wordexp for users that still may need it, but we leave this off by default because wordexp is a large attack vector and it is better to avoid it. [1]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/wordexp.html#tag_16_684_08 [2]: http://bugs.alpinelinux.org/issues/7454#note-2 Signed-off-by: Natanael Copa Signed-off-by: Takashi Iwai --- configure.ac | 19 ++++++++++++++++- src/userfile.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index 26e5d125..fbcfa829 100644 --- a/configure.ac +++ b/configure.ac @@ -303,8 +303,25 @@ fi AC_SUBST(ALSA_DEPLIBS) +dnl Check for use of wordexp... +AC_MSG_CHECKING(for use of wordexp) +AC_ARG_WITH(wordexp, + AS_HELP_STRING([--with-wordexp], + [Use wordexp when expanding configs (default = no)]), + [case "$withval" in + y|yes) wordexp=yes ;; + *) wordexp=no ;; + esac],) +if test "$wordexp" = "yes" ; then + AC_DEFINE(HAVE_WORDEXP, "1", [Enable use of wordexp]) + AC_MSG_RESULT(yes) + AC_CHECK_HEADER([wordexp.h],[], [AC_MSG_ERROR([Couldn't find wordexp.h])]) +else + AC_MSG_RESULT(no) +fi + dnl Check for headers -AC_CHECK_HEADERS([wordexp.h endian.h sys/endian.h sys/shm.h]) +AC_CHECK_HEADERS([endian.h sys/endian.h sys/shm.h]) dnl Check for resmgr support... AC_MSG_CHECKING(for resmgr support) diff --git a/src/userfile.c b/src/userfile.c index 72779da4..f2145470 100644 --- a/src/userfile.c +++ b/src/userfile.c @@ -21,6 +21,7 @@ #include #include #include +#include /** * \brief Get the full file name @@ -32,14 +33,13 @@ * stores the first matchine one. The returned string is strdup'ed. */ -#ifdef HAVE_WORDEXP_H +#ifdef HAVE_WORDEXP #include -#include int snd_user_file(const char *file, char **result) { wordexp_t we; int err; - + assert(file && result); err = wordexp(file, &we, WRDE_NOCMD); switch (err) { @@ -61,13 +61,62 @@ int snd_user_file(const char *file, char **result) return 0; } -#else /* !HAVE_WORDEXP_H */ -/* just copy the string - would be nicer to expand by ourselves, though... */ +#else /* !HAVE_WORDEX */ + +#include +#include +#include +#include +#include + int snd_user_file(const char *file, char **result) { - *result = strdup(file); - if (! *result) + int err; + size_t len; + char *buf = NULL; + + assert(file && result); + *result = NULL; + + /* expand ~/ if needed */ + if (file[0] == '~' && file[1] == '/') { + const char *home = getenv("HOME"); + if (home == NULL) { + struct passwd pwent, *p = NULL; + uid_t id = getuid(); + size_t bufsize = 1024; + + buf = malloc(bufsize); + if (buf == NULL) + goto out; + + while ((err = getpwuid_r(id, &pwent, buf, bufsize, &p)) == ERANGE) { + char *newbuf; + bufsize += 1024; + if (bufsize < 1024) + break; + newbuf = realloc(buf, bufsize); + if (newbuf == NULL) + goto out; + buf = newbuf; + } + home = err ? "" : pwent.pw_dir; + } + len = strlen(home) + strlen(&file[2]) + 2; + *result = malloc(len); + if (*result) + snprintf(*result, len, "%s/%s", home, &file[2]); + } else { + *result = strdup(file); + } + +out: + if (buf) + free(buf); + + if (*result == NULL) return -ENOMEM; return 0; } -#endif /* HAVE_WORDEXP_H */ + +#endif /* HAVE_WORDEXP */ -- 2.13.5 From c01dc3fa4899a9b9948629c103c0bc435d4f1574 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 10 Aug 2017 13:36:16 +0200 Subject: [PATCH 29/39] conf/ucm: DB410c-HiFi: add CIC selection This patch adds CIC selection controls which have been added recently to the kernel to select mic source. Without this patch user has to manually select the control to record from DMIC or AMIC. Signed-off-by: Srinivas Kandagatla Signed-off-by: Takashi Iwai --- src/conf/ucm/DB410c/HiFi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/conf/ucm/DB410c/HiFi b/src/conf/ucm/DB410c/HiFi index f9cbcf05..dcb7ac98 100644 --- a/src/conf/ucm/DB410c/HiFi +++ b/src/conf/ucm/DB410c/HiFi @@ -108,6 +108,7 @@ SectionDevice."Handset" { EnableSequence [ cdev "hw:0" cset "name='DEC1 MUX' ADC2" + cset "name='CIC1 MUX' AMIC" cset "name='ADC2 Volume' 8" cset "name='ADC2 MUX' INP2" ] @@ -130,6 +131,7 @@ SectionDevice."Primarymic" { EnableSequence [ cdev "hw:0" cset "name='DEC1 MUX' ADC1" + cset "name='CIC1 MUX' AMIC" cset "name='ADC1 Volume' 8" ] @@ -150,6 +152,7 @@ SectionDevice."Secondarymic" { EnableSequence [ cdev "hw:0" cset "name='DEC1 MUX' ADC2" + cset "name='CIC1 MUX' AMIC" cset "name='ADC2 Volume' 8" cset "name='ADC2 MUX' INP2" ] @@ -172,6 +175,7 @@ SectionDevice."DMIC" { EnableSequence [ cdev "hw:0" cset "name='DEC1 MUX' DMIC1" + cset "name='CIC1 MUX' DMIC" ] DisableSequence [ -- 2.13.5 From 97da58213a7f56850468fc74726f255a5739cb49 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 11 Aug 2017 23:24:03 +0200 Subject: [PATCH 30/39] rawmidi: symbols: use rawmidi_virt only when available src/rawmidi/Makefile.am only brings rawmidi_virt.c into the build when BUILD_SEQ is defined (i.e when --enable-seq is passed). However, rawmidi_symbols.c unconditionally refers to _snd_module_rawmidi_virt, defined in rawmidi_virt.c. This causes a link failure when BUILD_SEQ is disabled. For example when linking ffmpeg against alsa-lib: /home/thomas/projets/buildroot/output/host/arm-buildroot-linux-uclibcgnueabi/sysroot/usr/lib/libasound.a(pcm_dmix.o): In function `snd_pcm_dmix_sync_ptr': pcm_dmix.c:(.text+0x83c): warning: /home/thomas/projets/buildroot/output/host/arm-buildroot-linux-uclibcgnueabi/sysroot/usr/lib/libasound.a(rawmidi_symbols.o):(.data+0x4): undefined reference to `_snd_module_rawmidi_virt' collect2: error: ld returned 1 exit status To fix this, we make sure that rawmidi_symbols.c only uses _snd_module_rawmidi_virt when available. Signed-off-by: Thomas Petazzoni Signed-off-by: Takashi Iwai --- src/rawmidi/rawmidi_symbols.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/rawmidi/rawmidi_symbols.c b/src/rawmidi/rawmidi_symbols.c index cdc06d7f..64734334 100644 --- a/src/rawmidi/rawmidi_symbols.c +++ b/src/rawmidi/rawmidi_symbols.c @@ -21,11 +21,15 @@ #ifndef PIC extern const char *_snd_module_rawmidi_hw; +#ifdef BUILD_SEQ extern const char *_snd_module_rawmidi_virt; +#endif static const char **snd_rawmidi_open_objects[] = { &_snd_module_rawmidi_hw, +#ifdef BUILD_SEQ &_snd_module_rawmidi_virt +#endif }; void *snd_rawmidi_open_symbols(void) -- 2.13.5 From 80bd4ce1478efdc08189c82a74da183da591c0fb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 16 Aug 2017 11:08:48 -0500 Subject: [PATCH 31/39] conf: HdmiLpeAudio: add support for 3 devices The LPE Audio mode on BYT/CHT supports up to 3 devices, and also supports IEC61937 passthrough. Add missing alsa-lib configurations so that apps can use the usual -D'hdmi:CARD=X,DEV=Y,AES0=0x[4|6]' syntax, e.g. aplay -D'hdmi:CARD=0,DEV=2,AES0=0x6' -c2 -r48000 -fs16_le ac3_surround_test.spdif Tested on Zotac PI330 with Onkyo receiver Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- src/conf/cards/HdmiLpeAudio.conf | 77 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/conf/cards/HdmiLpeAudio.conf b/src/conf/cards/HdmiLpeAudio.conf index dae71fac..9fa30da0 100644 --- a/src/conf/cards/HdmiLpeAudio.conf +++ b/src/conf/cards/HdmiLpeAudio.conf @@ -56,6 +56,83 @@ HdmiLpeAudio.pcm.hdmi.0 { { interface PCM name "IEC958 Playback Default" + device 0 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} + +HdmiLpeAudio.pcm.hdmi.1 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback Default" + device 1 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} + +HdmiLpeAudio.pcm.hdmi.2 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device 2 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback Default" + device 2 lock true preserve true value [ $AES0 $AES1 $AES2 $AES3 ] -- 2.13.5 From 52826d4655fac9fa86600d5238391eb2c8ca8092 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 22 Aug 2017 10:16:05 +0100 Subject: [PATCH 32/39] topology: Fix private data for BEs Private data was not being added to BEs. Fix this. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai --- src/topology/data.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/topology/data.c b/src/topology/data.c index 5b83b9fc..f96ff9bb 100644 --- a/src/topology/data.c +++ b/src/topology/data.c @@ -50,7 +50,9 @@ struct snd_soc_tplg_private *get_priv_data(struct tplg_elem *elem) case SND_TPLG_TYPE_DAI: priv = &elem->dai->priv; break; - + case SND_TPLG_TYPE_BE: + priv = &elem->link->priv; + break; default: SNDERR("error: '%s': no support for private data for type %d\n", elem->id, elem->type); -- 2.13.5 From 5efdabc1ab60f443f7183e50fea99510d0e3fe77 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 24 Aug 2017 10:48:35 +0900 Subject: [PATCH 33/39] test: apply optimization for v4.14 kernel about changes for TLV data handling on user-defined element set At kernel v4.14, in initial state, elements on user-defined sets have write-only flag. When applications write TLV data, then the elements get readable flag and the TLV data is available. Originally TLV data is shared by elements in the same set, thus events are generated for all of elements in the set by the write operation. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- test/user-ctl-element-set.c | 84 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 11 deletions(-) diff --git a/test/user-ctl-element-set.c b/test/user-ctl-element-set.c index 8635c156..f3710732 100644 --- a/test/user-ctl-element-set.c +++ b/test/user-ctl-element-set.c @@ -9,6 +9,7 @@ #include "../include/asoundlib.h" #include +#include struct elem_set_trial { snd_ctl_t *handle; @@ -28,6 +29,8 @@ struct elem_set_trial { snd_ctl_elem_value_t *elem_data); int (*allocate_elem_set_tlv)(struct elem_set_trial *trial, unsigned int **tlv); + + bool tlv_readable; }; struct chmap_entry { @@ -420,9 +423,9 @@ static int check_event(struct elem_set_trial *trial, unsigned int mask, continue; /* * I expect each event is generated separately to the same - * element. + * element or several events are generated at once. */ - if (!(snd_ctl_event_elem_get_mask(event) & mask)) + if ((snd_ctl_event_elem_get_mask(event) & mask) != mask) continue; --expected_count; } @@ -561,6 +564,16 @@ static int check_elem_set_props(struct elem_set_trial *trial) if (!snd_ctl_elem_info_is_locked(info)) return -EIO; + /* + * In initial state, any application can register TLV data for + * user-defined element set except for IEC 958 type, thus + * elements in any user-defined set should allow any write + * operation. + */ + if (trial->type != SND_CTL_ELEM_TYPE_IEC958 && + !snd_ctl_elem_info_is_tlv_writable(info)) + return -EIO; + /* Check type-specific properties. */ if (trial->check_elem_props != NULL) { err = trial->check_elem_props(trial, info); @@ -572,6 +585,25 @@ static int check_elem_set_props(struct elem_set_trial *trial) err = snd_ctl_elem_unlock(trial->handle, id); if (err < 0) return err; + + /* + * Till kernel v4.14, ALSA control core allows elements in any + * user-defined set to have TLV_READ flag even if they have no + * TLV data in their initial state. In this case, any read + * operation for TLV data should return -ENXIO. + */ + if (snd_ctl_elem_info_is_tlv_readable(info)) { + unsigned int data[32]; + err = snd_ctl_elem_tlv_read(trial->handle, trial->id, + data, sizeof(data)); + if (err >= 0) + return -EIO; + if (err != -ENXIO) + return err; + + trial->tlv_readable = true; + } + } return 0; @@ -619,6 +651,8 @@ static int check_elems(struct elem_set_trial *trial) static int check_tlv(struct elem_set_trial *trial) { unsigned int *tlv; + int mask; + unsigned int count; unsigned int len; unsigned int *curr; int err; @@ -644,6 +678,36 @@ static int check_tlv(struct elem_set_trial *trial) if (err < 0) goto end; + /* + * Since kernel v4.14, any write operation to an element in user-defined + * set can change state of the other elements in the same set. In this + * case, any TLV data is firstly available after the operation. + */ + if (!trial->tlv_readable) { + mask = SND_CTL_EVENT_MASK_INFO | SND_CTL_EVENT_MASK_TLV; + count = trial->element_count; + } else { + mask = SND_CTL_EVENT_MASK_TLV; + count = 1; + } + err = check_event(trial, mask, count); + if (err < 0) + goto end; + if (!trial->tlv_readable) { + snd_ctl_elem_info_t *info; + snd_ctl_elem_info_alloca(&info); + + snd_ctl_elem_info_set_id(info, trial->id); + err = snd_ctl_elem_info(trial->handle, info); + if (err < 0) + return err; + if (!snd_ctl_elem_info_is_tlv_readable(info)) + return -EIO; + + /* Now TLV data is available for this element set. */ + trial->tlv_readable = true; + } + err = snd_ctl_elem_tlv_read(trial->handle, trial->id, curr, len); if (err < 0) goto end; @@ -690,6 +754,7 @@ int main(void) trial.change_elem_members = change_bool_elem_members; trial.allocate_elem_set_tlv = allocate_bool_elem_set_tlv; + trial.tlv_readable = false; break; case SND_CTL_ELEM_TYPE_INTEGER: trial.element_count = 900; @@ -703,6 +768,7 @@ int main(void) trial.change_elem_members = change_int_elem_members; trial.allocate_elem_set_tlv = allocate_int_elem_set_tlv; + trial.tlv_readable = false; break; case SND_CTL_ELEM_TYPE_ENUMERATED: trial.element_count = 900; @@ -715,6 +781,7 @@ int main(void) trial.check_elem_props = check_enum_elem_props; trial.change_elem_members = change_enum_elem_members; trial.allocate_elem_set_tlv = NULL; + trial.tlv_readable = false; break; case SND_CTL_ELEM_TYPE_BYTES: trial.element_count = 900; @@ -728,6 +795,7 @@ int main(void) trial.change_elem_members = change_bytes_elem_members; trial.allocate_elem_set_tlv = allocate_bytes_elem_set_tlv; + trial.tlv_readable = false; break; case SND_CTL_ELEM_TYPE_IEC958: trial.element_count = 1; @@ -740,6 +808,7 @@ int main(void) trial.check_elem_props = NULL; trial.change_elem_members = change_iec958_elem_members; trial.allocate_elem_set_tlv = NULL; + trial.tlv_readable = false; break; case SND_CTL_ELEM_TYPE_INTEGER64: default: @@ -754,6 +823,7 @@ int main(void) trial.change_elem_members = change_int64_elem_members; trial.allocate_elem_set_tlv = allocate_int64_elem_set_tlv; + trial.tlv_readable = false; break; } @@ -784,7 +854,7 @@ int main(void) /* Check properties of each element in this element set. */ err = check_elem_set_props(&trial); if (err < 0) { - printf("Fail to check propetries of each element with " + printf("Fail to check properties of each element with " "%s type.\n", snd_ctl_elem_type_name(trial.type)); break; @@ -822,14 +892,6 @@ int main(void) snd_ctl_elem_type_name(trial.type)); break; } - err = check_event(&trial, SND_CTL_EVENT_MASK_TLV, 1); - if (err < 0) { - printf("Fail to check an event to change TLV" - "data of an an element set with %s " - "type.\n", - snd_ctl_elem_type_name(trial.type)); - break; - } } /* Test an operation to remove elements in this element set. */ -- 2.13.5 From 8d6169514519a3f3246ad09dd1281e3a7d854d42 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 12 Sep 2017 21:47:42 +0100 Subject: [PATCH 34/39] topology: fix usage of SND_TPLG_INDEX_ALL when checking routes Make sure SND_TPLG_INDEX_ALL is used correctly when checking routes so that connecting routes of different indexes does not emit any warnings. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai --- src/topology/dapm.c | 4 ++-- src/topology/elem.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/topology/dapm.c b/src/topology/dapm.c index 66892a66..0ddbf965 100644 --- a/src/topology/dapm.c +++ b/src/topology/dapm.c @@ -279,7 +279,7 @@ int tplg_build_routes(snd_tplg_t *tplg) } if (!tplg_elem_lookup(&tplg->widget_list, route->sink, - SND_TPLG_TYPE_DAPM_WIDGET, elem->index)) { + SND_TPLG_TYPE_DAPM_WIDGET, SND_TPLG_INDEX_ALL)) { SNDERR("warning: undefined sink widget/stream '%s'\n", route->sink); } @@ -302,7 +302,7 @@ int tplg_build_routes(snd_tplg_t *tplg) } if (!tplg_elem_lookup(&tplg->widget_list, route->source, - SND_TPLG_TYPE_DAPM_WIDGET, elem->index)) { + SND_TPLG_TYPE_DAPM_WIDGET, SND_TPLG_INDEX_ALL)) { SNDERR("warning: Undefined source widget/stream '%s'\n", route->source); } diff --git a/src/topology/elem.c b/src/topology/elem.c index 89a4ac9f..9a7c7b75 100644 --- a/src/topology/elem.c +++ b/src/topology/elem.c @@ -123,7 +123,7 @@ struct tplg_elem *tplg_elem_lookup(struct list_head *base, const char* id, return elem; /* SND_TPLG_INDEX_ALL is the default value "0" and applicable for all use cases */ - if ((elem->index != SND_TPLG_INDEX_ALL) + if ((index != SND_TPLG_INDEX_ALL) && (elem->index > index)) break; } -- 2.13.5 From 6a617cc719d553ad8eb96308b7f3b94f5a53d243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Krause?= Date: Wed, 13 Sep 2017 16:21:10 +0200 Subject: [PATCH 35/39] pcm: softvol: add support for S24_LE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested with the Wolfson WM8524 DAC on a i.MX6UL board and the following ALSA configuration file using the pcm test utility from alsa-lib: """ $ cat /etc/asound.conf pcm.!default { type plug slave.pcm "softvol" } pcm.softvol { type softvol slave { pcm "hw:0" } control { name "Master" card 0 } } ctl.!default { type hw card 0 } ctl.softvol { type hw card 0 } $ pcm -D softvol -o S24_LE -c 2 -r 48000 """ The data in the Synchronous Audio Interface (SAI) of the i.MX6UL is aligned the following way: """ 31 30 29 28 | 27 26 25 24 | 23 22 21 20 | .. | 3 2 1 0 ## ## ## ## ## ## ## ## [ DATA[23:0] ] """ Signed-off-by: Jörg Krause Signed-off-by: Takashi Iwai --- src/pcm/pcm_softvol.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c index 1fe5784d..68a35b56 100644 --- a/src/pcm/pcm_softvol.c +++ b/src/pcm/pcm_softvol.c @@ -251,6 +251,44 @@ static inline short MULTI_DIV_short(short a, unsigned int b, int swap) } \ } \ } while (0) + +#define CONVERT_AREA_S24_LE() do { \ + unsigned int ch, fr; \ + int *src, *dst; \ + int tmp; \ + for (ch = 0; ch < channels; ch++) { \ + src_area = &src_areas[ch]; \ + dst_area = &dst_areas[ch]; \ + src = snd_pcm_channel_area_addr(src_area, src_offset); \ + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); \ + src_step = snd_pcm_channel_area_step(src_area) \ + / sizeof(int); \ + dst_step = snd_pcm_channel_area_step(dst_area) \ + / sizeof(int); \ + GET_VOL_SCALE; \ + fr = frames; \ + if (! vol_scale) { \ + while (fr--) { \ + *dst = 0; \ + dst += dst_step; \ + } \ + } else if (vol_scale == 0xffff) { \ + while (fr--) { \ + *dst = *src; \ + src += dst_step; \ + dst += src_step; \ + } \ + } else { \ + while (fr--) { \ + tmp = *src << 8; \ + tmp = (signed int) tmp >> 8; \ + *dst = MULTI_DIV_24(tmp, vol_scale); \ + src += dst_step; \ + dst += src_step; \ + } \ + } \ + } \ +} while (0) #define GET_VOL_SCALE \ switch (ch) { \ @@ -315,6 +353,10 @@ static void softvol_convert_stereo_vol(snd_pcm_softvol_t *svol, CONVERT_AREA(int, !snd_pcm_format_cpu_endian(svol->sformat)); break; + case SND_PCM_FORMAT_S24_LE: + /* 24bit samples */ + CONVERT_AREA_S24_LE(); + break; case SND_PCM_FORMAT_S24_3LE: CONVERT_AREA_S24_3LE(); break; @@ -366,6 +408,10 @@ static void softvol_convert_mono_vol(snd_pcm_softvol_t *svol, CONVERT_AREA(int, !snd_pcm_format_cpu_endian(svol->sformat)); break; + case SND_PCM_FORMAT_S24_LE: + /* 24bit samples */ + CONVERT_AREA_S24_LE(); + break; case SND_PCM_FORMAT_S24_3LE: CONVERT_AREA_S24_3LE(); break; @@ -422,6 +468,7 @@ static int snd_pcm_softvol_hw_refine_cprepare(snd_pcm_t *pcm, { (1ULL << SND_PCM_FORMAT_S16_LE) | (1ULL << SND_PCM_FORMAT_S16_BE) | + (1ULL << SND_PCM_FORMAT_S24_LE) | (1ULL << SND_PCM_FORMAT_S32_LE) | (1ULL << SND_PCM_FORMAT_S32_BE), (1ULL << (SND_PCM_FORMAT_S24_3LE - 32)) @@ -577,10 +624,11 @@ static int snd_pcm_softvol_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * param if (slave->format != SND_PCM_FORMAT_S16_LE && slave->format != SND_PCM_FORMAT_S16_BE && slave->format != SND_PCM_FORMAT_S24_3LE && + slave->format != SND_PCM_FORMAT_S24_LE && slave->format != SND_PCM_FORMAT_S32_LE && slave->format != SND_PCM_FORMAT_S32_BE) { - SNDERR("softvol supports only S16_LE, S16_BE, S24_3LE, S32_LE " - " or S32_BE"); + SNDERR("softvol supports only S16_LE, S16_BE, S24_LE, S24_3LE, " + "S32_LE or S32_BE"); return -EINVAL; } svol->sformat = slave->format; @@ -863,6 +911,7 @@ int snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, sformat != SND_PCM_FORMAT_S16_LE && sformat != SND_PCM_FORMAT_S16_BE && sformat != SND_PCM_FORMAT_S24_3LE && + sformat != SND_PCM_FORMAT_S24_LE && sformat != SND_PCM_FORMAT_S32_LE && sformat != SND_PCM_FORMAT_S32_BE) return -EINVAL; @@ -1082,9 +1131,10 @@ int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, sformat != SND_PCM_FORMAT_S16_LE && sformat != SND_PCM_FORMAT_S16_BE && sformat != SND_PCM_FORMAT_S24_3LE && + sformat != SND_PCM_FORMAT_S24_LE && sformat != SND_PCM_FORMAT_S32_LE && sformat != SND_PCM_FORMAT_S32_BE) { - SNDERR("only S16_LE, S16_BE, S24_3LE, S32_LE or S32_BE format is supported"); + SNDERR("only S16_LE, S16_BE, S24_LE, S24_3LE, S32_LE or S32_BE format is supported"); snd_config_delete(sconf); return -EINVAL; } -- 2.13.5 From baed295faafb076d380392fa938234a7ec426dfc Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Thu, 28 Sep 2017 15:46:15 +0200 Subject: [PATCH 36/39] seq: fix snd_seq_set_queue_tempo() usage example in the documentation snd_seq_set_queue_tempo() requires a queue id as the second argument, fix the example in documentation to reflect that. Also add the queue id as an argument of the set_tempo() function, just to keep the whole example compilable. Signed-off-by: Antonio Ospite Signed-off-by: Takashi Iwai --- src/seq/seq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/seq/seq.c b/src/seq/seq.c index d5ed1c6a..808c7915 100644 --- a/src/seq/seq.c +++ b/src/seq/seq.c @@ -452,13 +452,13 @@ For setting these tempo parameters, use #snd_seq_queue_tempo_t record. For example, to set the tempo of the queue q to 48 PPQ, 60 BPM, \code -void set_tempo(snd_seq_t *handle) +void set_tempo(snd_seq_t *handle, int queue) { snd_seq_queue_tempo_t *tempo; snd_seq_queue_tempo_alloca(&tempo); snd_seq_queue_tempo_set_tempo(tempo, 1000000); // 60 BPM snd_seq_queue_tempo_set_ppq(tempo, 48); // 48 PPQ - snd_seq_set_queue_tempo(handle, tempo); + snd_seq_set_queue_tempo(handle, queue, tempo); } \endcode -- 2.13.5 From 8c0b17bca3d641dc86d35eb1b97fae5fe4080984 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Tue, 26 Sep 2017 16:44:49 +0200 Subject: [PATCH 37/39] test/seq-decoder: enable timestamping for external subscribers Events sent by external clients subscribed to the input port are not timestamped. This inconsistent behavior may surprise newbies who look at seq-decoder as a reference example. See the example below using "vkeybd --addr 128:0" to connect to seq-decoder, the events sent by vkeybd are on a different queue with no timestamps: ... EVENT>>> Type = 66, flags = 0x0, time = 0 ticks Source = 0.1, dest = 128.0, queue = 253 Event = Port Subscribed; 129:0 -> 128:0 EVENT>>> Type = 66, flags = 0x1, time = 4.829712627 Source = 0.1, dest = 128.0, queue = 0 Event = Port Subscribed; 129:0 -> 128:0 EVENT>>> Type = 10, flags = 0x0, time = 0 ticks Source = 129.0, dest = 128.0, queue = 253 Event = Controller; ch=0, param=0, value=0 EVENT>>> Type = 11, flags = 0x0, time = 0 ticks Source = 129.0, dest = 128.0, queue = 253 Event = Program Change; ch=0, program=0 ... After the change events are on the main queue and are timestamped: ... EVENT>>> Type = 66, flags = 0x1, time = 4.280907223 Source = 0.1, dest = 128.0, queue = 0 Event = Port Subscribed; 129:0 -> 128:0 EVENT>>> Type = 66, flags = 0x1, time = 4.280912063 Source = 0.1, dest = 128.0, queue = 0 Event = Port Subscribed; 129:0 -> 128:0 EVENT>>> Type = 10, flags = 0x1, time = 4.280990702 Source = 129.0, dest = 128.0, queue = 0 Event = Controller; ch=0, param=0, value=0 EVENT>>> Type = 11, flags = 0x1, time = 4.280994862 Source = 129.0, dest = 128.0, queue = 0 Event = Program Change; ch=0, program=0 ... Signed-off-by: Antonio Ospite Signed-off-by: Takashi Iwai --- test/seq-decoder.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/seq-decoder.c b/test/seq-decoder.c index b110e98d..38755553 100644 --- a/test/seq-decoder.c +++ b/test/seq-decoder.c @@ -283,6 +283,12 @@ void event_decoder(snd_seq_t *handle, int argc, char *argv[]) snd_seq_port_info_set_name(pinfo, "Input"); snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC); snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_WRITE); + + /* Enable timestamping for events sent by external subscribers. */ + snd_seq_port_info_set_timestamping(pinfo, 1); + snd_seq_port_info_set_timestamp_real(pinfo, 1); + snd_seq_port_info_set_timestamp_queue(pinfo, queue); + if ((err = snd_seq_create_port(handle, pinfo)) < 0) { fprintf(stderr, "Cannot create input port: %s\n", snd_strerror(err)); return; -- 2.13.5 From 98d2c12ac2f8dc7e92790e927f472e26459d3852 Mon Sep 17 00:00:00 2001 From: Timo Wischer Date: Thu, 5 Oct 2017 16:25:23 +0200 Subject: [PATCH 38/39] ctl: ext: Fail with error code if snd_ctl_ext_callback::read_event() callback is not defined The snd_ctl_ext_callback::read_event() callback is only optional if no poll descriptor was given via snd_ctl_ext_t::poll_fd or snd_ctl_ext_callback::snd_ctl_ext_poll_descriptors(). If a poll descriptor is given the snd_ctl_ext_callback::read_event() callback has also to be defined because there is no minigful default behavior. This callback will be called when ever the poll() on the file descriptor indicates that there is an event pending. Therefore returning a 0 which indicates that there is no event makes no sense. Signed-off-by: Timo Wischer Signed-off-by: Takashi Iwai --- src/control/control_ext.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/control/control_ext.c b/src/control/control_ext.c index 56552fa1..d7de8e84 100644 --- a/src/control/control_ext.c +++ b/src/control/control_ext.c @@ -415,8 +415,12 @@ static int snd_ctl_ext_read(snd_ctl_t *handle, snd_ctl_event_t *event) { snd_ctl_ext_t *ext = handle->private_data; - memset(event, 0, sizeof(*event)); - return ext->callback->read_event(ext, &event->data.elem.id, &event->data.elem.mask); + if (ext->callback->read_event) { + memset(event, 0, sizeof(*event)); + return ext->callback->read_event(ext, &event->data.elem.id, &event->data.elem.mask); + } + + return -EINVAL; } static int snd_ctl_ext_poll_descriptors_count(snd_ctl_t *handle) -- 2.13.5 From 996dd33b5f0df06d0b1fdd8f43b7a212c26e2a27 Mon Sep 17 00:00:00 2001 From: Tanu Kaskinen Date: Wed, 4 Oct 2017 22:44:00 +0300 Subject: [PATCH 39/39] conf: HdmiLpeAudio: remove the "front" pcm definition PulseAudio assumes that the "front" pcm device always refers to an analog device, not HDMI. While that assumption is not really valid, the reality is that without that assumption PulseAudio can't know whether "front" and "hdmi" refer to a different or the same device. The HDMI LPE driver doesn't allow audio streaming while the HDMI cable is unplugged, so PulseAudio has to know when it's plugged in and when it's not. If both "front" and "hdmi" devices exist, PulseAudio will notice that HDMI is unplugged, but it doesn't know that "front" refers to the same device, and PulseAudio will try to use the "front" device with bad consequences. The kernel driver's refusal to stream any audio makes PulseAudio enter an infinite loop and then the kernel kills PulseAudio, because it consumes too much CPU time in a realtime thread. While the looping in PulseAudio could probably be fixed, that wouldn't change the fact that PulseAudio thinks that there is an analog device. I believe it's best to avoid having the same device as both "front" and "hdmi" in alsa-lib. I removed also the surround configuration includes. I don't think they had any effect anyway, so I wonder why they were there in the first place. BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=100488 Signed-off-by: Takashi Iwai --- src/conf/cards/HdmiLpeAudio.conf | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/conf/cards/HdmiLpeAudio.conf b/src/conf/cards/HdmiLpeAudio.conf index 9fa30da0..a1e493da 100644 --- a/src/conf/cards/HdmiLpeAudio.conf +++ b/src/conf/cards/HdmiLpeAudio.conf @@ -2,30 +2,6 @@ # Configuration for the Intel HDMI/DP LPE audio # - - -HdmiLpeAudio.pcm.front.0 { - @args [ CARD ] - @args.CARD { - type string - } - type softvol - slave.pcm { - type hw - card $CARD - } - control { - name "PCM Playback Volume" - card $CARD - } -} - - - - - - - HdmiLpeAudio.pcm.hdmi.0 { -- 2.13.5 From 7f3ad37fd7e9327542be7f467ad337dd7398e2b7 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 22 Oct 2017 15:02:19 +0200 Subject: [PATCH] topology: fix coverity issues --- src/topology/ctl.c | 6 +++--- src/topology/dapm.c | 7 ++++++- src/topology/data.c | 7 +++---- src/topology/elem.c | 4 +++- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/topology/ctl.c b/src/topology/ctl.c index e73d9eb7..9dd88db6 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -130,7 +130,7 @@ static int tplg_build_mixer_control(snd_tplg_t *tplg, list_for_each(pos, base) { ref = list_entry(pos, struct tplg_ref, list); - if (ref->id == NULL || ref->elem) + if (ref->elem) continue; if (ref->type == SND_TPLG_TYPE_TLV) { @@ -180,7 +180,7 @@ static int tplg_build_enum_control(snd_tplg_t *tplg, list_for_each(pos, base) { ref = list_entry(pos, struct tplg_ref, list); - if (ref->id == NULL || ref->elem) + if (ref->elem) continue; if (ref->type == SND_TPLG_TYPE_TEXT) { @@ -216,7 +216,7 @@ static int tplg_build_bytes_control(snd_tplg_t *tplg, struct tplg_elem *elem) list_for_each(pos, base) { ref = list_entry(pos, struct tplg_ref, list); - if (ref->id == NULL || ref->elem) + if (ref->elem) continue; if (ref->type == SND_TPLG_TYPE_DATA) { diff --git a/src/topology/dapm.c b/src/topology/dapm.c index 0ddbf965..e5d473a8 100644 --- a/src/topology/dapm.c +++ b/src/topology/dapm.c @@ -428,7 +428,7 @@ int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg, snd_config_t *n; int err; const char *graph_id, *val = NULL; - int index; + int index = -1; if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { SNDERR("error: compound is expected for dapm graph definition\n"); @@ -452,6 +452,11 @@ int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg, } if (strcmp(id, "lines") == 0) { + if (index < 0) { + SNDERR("error: failed to parse dapm graph %s, missing index\n", + graph_id); + return -EINVAL; + } err = tplg_parse_routes(tplg, n, index); if (err < 0) { SNDERR("error: failed to parse dapm graph %s\n", diff --git a/src/topology/data.c b/src/topology/data.c index f96ff9bb..6b7c3f6c 100644 --- a/src/topology/data.c +++ b/src/topology/data.c @@ -132,7 +132,6 @@ err: static void dump_priv_data(struct tplg_elem *elem) { struct snd_soc_tplg_private *priv = elem->data; - unsigned char *p = (unsigned char *)priv->data; unsigned int i, j = 0; tplg_dbg(" elem size = %d, priv data size = %d\n", @@ -366,7 +365,7 @@ static struct tplg_elem *get_tokens(snd_tplg_t *tplg, struct tplg_elem *elem) ref = list_entry(pos, struct tplg_ref, list); - if (!ref->id || ref->type != SND_TPLG_TYPE_TOKEN) + if (ref->type != SND_TPLG_TYPE_TOKEN) continue; if (!ref->elem) { @@ -390,7 +389,7 @@ static bool has_tuples(struct tplg_elem *elem) list_for_each(pos, base) { ref = list_entry(pos, struct tplg_ref, list); - if (ref->id && ref->type == SND_TPLG_TYPE_TUPLE) + if (ref->type == SND_TPLG_TYPE_TUPLE) return true; } @@ -504,7 +503,7 @@ static int build_tuples(snd_tplg_t *tplg, struct tplg_elem *elem) ref = list_entry(pos, struct tplg_ref, list); - if (!ref->id || ref->type != SND_TPLG_TYPE_TUPLE) + if (ref->type != SND_TPLG_TYPE_TUPLE) continue; tplg_dbg("tuples '%s' used by data '%s'\n", ref->id, elem->id); diff --git a/src/topology/elem.c b/src/topology/elem.c index 9a7c7b75..16ad4423 100644 --- a/src/topology/elem.c +++ b/src/topology/elem.c @@ -178,8 +178,10 @@ struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg, if (snd_config_get_id(n, &id)) continue; if (strcmp(id, "index") == 0) { - if (snd_config_get_string(n, &val) < 0) + if (snd_config_get_string(n, &val) < 0) { + free(elem); return NULL; + } elem->index = atoi(val); } } -- 2.13.5