From 6117f9abfcd680742e90ff6d2b885cff1b9ec32733be6554ec58c4522a8388b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismail=20D=C3=B6nmez?= Date: Tue, 29 Nov 2016 18:09:28 +0000 Subject: [PATCH] Accepting request 442719 from home:tiwai:branches:multimedia:libs - Backport upstream fixes (bsc#1012594): - A few PCM bugs have been fixed: * Stall of dmix and others in a wrong PCM state * Refactoring of PCM locking scheme * SHM initialization race fix * plug PCM memory leaks * Improvement of dshare/dmix delay calculation * Fix endless dshare draining * Fix semaphore discard race fix of direct plugins - UCM fixes and updates for DB410c and skylake-r5286 - Mixer code cleanup not to install bogus plugin codes - Documentation fixes / updates 0001-ucm-Add-ucm-files-for-DB410c-board.patch 0002-mixer-Fix-rounding-mode-documentation.patch 0003-pcm-Fix-shm-initialization-race-condition.patch 0004-pcm-Better-understandable-locking-code.patch 0005-ucm-fix-crash-when-calling-snd_use_case_geti-with-no.patch 0006-ucm-docs-typeset-lists-of-identifiers-explicitly.patch 0007-Update-include-sound-tlv.h-from-4.9-pre-kernel-uapi.patch 0008-test-use-actual-information-for-TLV-operation.patch 0009-ctl-improve-API-documentation-for-TLV-operation.patch 0010-ctl-improve-documentation-about-TLV-related-APIs.patch 0011-ctl-correct-documentation-about-TLV-feature.patch 0012-conf-ucm-skylake-add-skylake-rt286-conf-files.patch 0013-pcm_plug-Clear-plugins-on-all-error-conditions.patch 0014-mixer-Don-t-install-smixer-modules-unless-python-is-.patch 0015-pcm_dshare-Do-not-discard-slave-reported-delay-in-st.patch 0016-pcm-direct-Protect-from-freeing-semaphore-when-alrea.patch 0017-pcm-dshare-Fix-endless-playback-of-buffer.patch 0018-pcm-Add-the-PCM-state-checks-to-plugins.patch OBS-URL: https://build.opensuse.org/request/show/442719 OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa?expand=0&rev=202 --- 0001-ucm-Add-ucm-files-for-DB410c-board.patch | 310 ++++++++++++++ ...ixer-Fix-rounding-mode-documentation.patch | 76 ++++ ...ix-shm-initialization-race-condition.patch | 39 ++ ...m-Better-understandable-locking-code.patch | 130 ++++++ ...en-calling-snd_use_case_geti-with-no.patch | 52 +++ ...eset-lists-of-identifiers-explicitly.patch | 108 +++++ ...sound-tlv.h-from-4.9-pre-kernel-uapi.patch | 105 +++++ ...actual-information-for-TLV-operation.patch | 386 ++++++++++++++++++ ...-API-documentation-for-TLV-operation.patch | 52 +++ ...documentation-about-TLV-related-APIs.patch | 64 +++ ...rect-documentation-about-TLV-feature.patch | 59 +++ ...skylake-add-skylake-rt286-conf-files.patch | 313 ++++++++++++++ ...lear-plugins-on-all-error-conditions.patch | 34 ++ ...all-smixer-modules-unless-python-is-.patch | 47 +++ ...t-discard-slave-reported-delay-in-st.patch | 109 +++++ ...ct-from-freeing-semaphore-when-alrea.patch | 82 ++++ ...share-Fix-endless-playback-of-buffer.patch | 30 ++ ...-Add-the-PCM-state-checks-to-plugins.patch | 220 ++++++++++ ...discard-slave-reported-delay-in-stat.patch | 103 +++++ alsa.changes | 38 ++ alsa.spec | 41 +- 21 files changed, 2396 insertions(+), 2 deletions(-) create mode 100644 0001-ucm-Add-ucm-files-for-DB410c-board.patch create mode 100644 0002-mixer-Fix-rounding-mode-documentation.patch create mode 100644 0003-pcm-Fix-shm-initialization-race-condition.patch create mode 100644 0004-pcm-Better-understandable-locking-code.patch create mode 100644 0005-ucm-fix-crash-when-calling-snd_use_case_geti-with-no.patch create mode 100644 0006-ucm-docs-typeset-lists-of-identifiers-explicitly.patch create mode 100644 0007-Update-include-sound-tlv.h-from-4.9-pre-kernel-uapi.patch create mode 100644 0008-test-use-actual-information-for-TLV-operation.patch create mode 100644 0009-ctl-improve-API-documentation-for-TLV-operation.patch create mode 100644 0010-ctl-improve-documentation-about-TLV-related-APIs.patch create mode 100644 0011-ctl-correct-documentation-about-TLV-feature.patch create mode 100644 0012-conf-ucm-skylake-add-skylake-rt286-conf-files.patch create mode 100644 0013-pcm_plug-Clear-plugins-on-all-error-conditions.patch create mode 100644 0014-mixer-Don-t-install-smixer-modules-unless-python-is-.patch create mode 100644 0015-pcm_dshare-Do-not-discard-slave-reported-delay-in-st.patch create mode 100644 0016-pcm-direct-Protect-from-freeing-semaphore-when-alrea.patch create mode 100644 0017-pcm-dshare-Fix-endless-playback-of-buffer.patch create mode 100644 0018-pcm-Add-the-PCM-state-checks-to-plugins.patch create mode 100644 0019-pcm-dmix-Do-not-discard-slave-reported-delay-in-stat.patch diff --git a/0001-ucm-Add-ucm-files-for-DB410c-board.patch b/0001-ucm-Add-ucm-files-for-DB410c-board.patch new file mode 100644 index 0000000..104071c --- /dev/null +++ b/0001-ucm-Add-ucm-files-for-DB410c-board.patch @@ -0,0 +1,310 @@ +From daafa451587b9e1d018f147885f38290a344a65a Mon Sep 17 00:00:00 2001 +From: Srinivas Kandagatla +Date: Mon, 8 Aug 2016 16:23:10 +0300 +Subject: [PATCH] ucm: Add ucm files for DB410c board. + +DB410c board has support for both Digital and Analog audio. Digital +audio is over HDMI and analog is over codec chip integrated inside the +APQ8016 SOC. + +It can support: + - 3 Microphones: Primary Mic(Handset mic), Headset Mic and Secondary + - 2 Digital Microphones. + - Earpiece. + - Headset. + - Loud Speaker. + - HDMI. + +[Riku: squashed Srinivas's patches together and converted spaces to tabs] + +Signed-off-by: Srinivas Kandagatla +Signed-off-by: Riku Voipio +Cc: nicolas.dechesne@linaro.org +Signed-off-by: Takashi Iwai +--- + configure.ac | 1 + + src/conf/ucm/DB410c/DB410c.conf | 8 ++ + src/conf/ucm/DB410c/HDMI | 31 +++++++ + src/conf/ucm/DB410c/HiFi | 185 ++++++++++++++++++++++++++++++++++++++++ + src/conf/ucm/DB410c/Makefile.am | 4 + + src/conf/ucm/Makefile.am | 2 +- + 6 files changed, 230 insertions(+), 1 deletion(-) + create mode 100644 src/conf/ucm/DB410c/DB410c.conf + create mode 100644 src/conf/ucm/DB410c/HDMI + create mode 100644 src/conf/ucm/DB410c/HiFi + create mode 100644 src/conf/ucm/DB410c/Makefile.am + +diff --git a/configure.ac b/configure.ac +index f592e8b74360..014af5f3d27b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -675,6 +675,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \ + src/conf/ucm/broadwell-rt286/Makefile \ + src/conf/ucm/VEYRON-I2S/Makefile \ + src/conf/ucm/chtrt5645/Makefile \ ++ src/conf/ucm/DB410c/Makefile \ + src/conf/topology/Makefile \ + src/conf/topology/broadwell/Makefile \ + modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \ +diff --git a/src/conf/ucm/DB410c/DB410c.conf b/src/conf/ucm/DB410c/DB410c.conf +new file mode 100644 +index 000000000000..590278fa7bdd +--- /dev/null ++++ b/src/conf/ucm/DB410c/DB410c.conf +@@ -0,0 +1,8 @@ ++SectionUseCase."HiFi" { ++ File "HiFi" ++ Comment "Play HiFi quality Music." ++} ++SectionUseCase."HDMI" { ++ File "HDMI" ++ Comment "HDMI output." ++} +diff --git a/src/conf/ucm/DB410c/HDMI b/src/conf/ucm/DB410c/HDMI +new file mode 100644 +index 000000000000..8112bc0a7110 +--- /dev/null ++++ b/src/conf/ucm/DB410c/HDMI +@@ -0,0 +1,31 @@ ++# Use case configuration for DB410c board. ++# Author: Srinivas Kandagatla ++ ++SectionVerb { ++ EnableSequence [ ++ ] ++ ++ DisableSequence [ ++ ] ++ Value { ++ TQ "HiFi" ++ PlaybackPCM "plughw:0,0" ++ } ++} ++ ++SectionDevice."HDMI-stereo" { ++ #Name "HDMI-stereo" ++ Comment "HDMI Digital Stereo Output" ++ ++ EnableSequence [ ++ cdev "hw:0" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:0" ++ ] ++ ++ Value { ++ PlaybackChannels "2" ++ } ++} +diff --git a/src/conf/ucm/DB410c/HiFi b/src/conf/ucm/DB410c/HiFi +new file mode 100644 +index 000000000000..f9cbcf053e84 +--- /dev/null ++++ b/src/conf/ucm/DB410c/HiFi +@@ -0,0 +1,185 @@ ++# Use case configuration for DB410c board. ++# Author: Srinivas Kandagatla ++ ++SectionVerb { ++ ++ EnableSequence [ ++ ] ++ ++ DisableSequence [ ++ ] ++ ++ # ALSA PCM ++ Value { ++ # ALSA PCM device for HiFi ++ PlaybackPCM "plughw:0,1" ++ CapturePCM "plughw:0,2" ++ } ++} ++ ++ ++SectionDevice."Speaker" { ++ Comment "Speaker playback" ++ ++ ConflictingDevice [ ++ "Headphones" ++ "Earpiece" ++ ] ++ ++ EnableSequence [ ++ cdev "hw:0" ++ cset "name='SPK DAC Switch' 1" ++ cset "name='RX3 MIX1 INP1' RX1" ++ ## gain to 0dB ++ cset "name='RX3 Digital Volume' 128" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:0" ++ cset "name='SPK DAC Switch' 0" ++ cset "name='RX3 MIX1 INP1' ZERO" ++ ] ++ ++ Value { ++ PlaybackChannels "2" ++ } ++} ++ ++ ++SectionDevice."Headphones" { ++ Comment "Headphones playback" ++ ++ ConflictingDevice [ ++ "Speaker" ++ "Earpiece" ++ ] ++ EnableSequence [ ++ cdev "hw:0" ++ cset "name='RX1 MIX1 INP1' RX1" ++ cset "name='RX2 MIX1 INP1' RX2" ++ cset "name='RDAC2 MUX' RX2" ++ cset "name='HPHL' 1" ++ cset "name='HPHR' 1" ++ ## gain to 0dB ++ cset "name='RX1 Digital Volume' 128" ++ ## gain to 0dB ++ cset "name='RX2 Digital Volume' 128" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:0" ++ cset "name='RX1 Digital Volume' 0" ++ cset "name='RX2 Digital Volume' 0" ++ cset "name='HPHL' 0" ++ cset "name='HPHR' 0" ++ cset "name='RDAC2 MUX' ZERO" ++ cset "name='RX1 MIX1 INP1' ZERO" ++ cset "name='RX2 MIX1 INP1' ZERO" ++ ] ++ ++ Value { ++ PlaybackChannels "2" ++ } ++} ++ ++SectionDevice."Earpiece" { ++ Comment "Earpiece playback" ++ ++ ConflictingDevice [ ++ "Speaker" ++ "Headphones" ++ ] ++ EnableSequence [ ++ cdev "hw:0" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:0" ++ ] ++ ++ Value { ++ PlaybackChannels "2" ++ } ++} ++ ++SectionDevice."Handset" { ++ Comment "Headset Microphone" ++ ++ EnableSequence [ ++ cdev "hw:0" ++ cset "name='DEC1 MUX' ADC2" ++ cset "name='ADC2 Volume' 8" ++ cset "name='ADC2 MUX' INP2" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:0" ++ cset "name='ADC2 MUX' ZERO" ++ cset "name='ADC2 Volume' 0" ++ cset "name='DEC1 MUX' ZERO" ++ ] ++ ++ Value { ++ CaptureChannels "2" ++ } ++} ++ ++SectionDevice."Primarymic" { ++ Comment "Primary Microphone" ++ ++ EnableSequence [ ++ cdev "hw:0" ++ cset "name='DEC1 MUX' ADC1" ++ cset "name='ADC1 Volume' 8" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:0" ++ cset "name='DEC1 MUX' ZERO" ++ cset "name='ADC1 Volume' 0" ++ ] ++ ++ Value { ++ CaptureChannels "2" ++ } ++} ++ ++SectionDevice."Secondarymic" { ++ Comment "Secondary Microphone" ++ ++ EnableSequence [ ++ cdev "hw:0" ++ cset "name='DEC1 MUX' ADC2" ++ cset "name='ADC2 Volume' 8" ++ cset "name='ADC2 MUX' INP2" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:0" ++ cset "name='DEC1 MUX' ZERO" ++ cset "name='ADC2 Volume' 0" ++ cset "name='ADC2 MUX' ZERO" ++ ] ++ ++ Value { ++ CaptureChannels "2" ++ } ++} ++ ++SectionDevice."DMIC" { ++ Comment "Digital Microphone" ++ ++ EnableSequence [ ++ cdev "hw:0" ++ cset "name='DEC1 MUX' DMIC1" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:0" ++ cset "name='DEC1 MUX' ZERO" ++ ] ++ ++ Value { ++ CaptureChannels "2" ++ } ++} +diff --git a/src/conf/ucm/DB410c/Makefile.am b/src/conf/ucm/DB410c/Makefile.am +new file mode 100644 +index 000000000000..e10a1363dc32 +--- /dev/null ++++ b/src/conf/ucm/DB410c/Makefile.am +@@ -0,0 +1,4 @@ ++alsaconfigdir = @ALSA_CONFIG_DIR@ ++ucmdir = $(alsaconfigdir)/ucm/DB410c ++ucm_DATA = DB410c.conf HDMI HiFi ++EXTRA_DIST = $(ucm_DATA) +diff --git a/src/conf/ucm/Makefile.am b/src/conf/ucm/Makefile.am +index 88657708fc68..7bf432e70e26 100644 +--- a/src/conf/ucm/Makefile.am ++++ b/src/conf/ucm/Makefile.am +@@ -1 +1 @@ +-SUBDIRS=DAISY-I2S PandaBoard PandaBoardES SDP4430 tegraalc5632 PAZ00 GoogleNyan broadwell-rt286 VEYRON-I2S chtrt5645 ++SUBDIRS=DAISY-I2S PandaBoard PandaBoardES SDP4430 tegraalc5632 PAZ00 GoogleNyan broadwell-rt286 VEYRON-I2S chtrt5645 DB410c +-- +2.10.2 + diff --git a/0002-mixer-Fix-rounding-mode-documentation.patch b/0002-mixer-Fix-rounding-mode-documentation.patch new file mode 100644 index 0000000..54ef1c2 --- /dev/null +++ b/0002-mixer-Fix-rounding-mode-documentation.patch @@ -0,0 +1,76 @@ +From e2cfe3c6c8483c27b60d9b64e760ba3e8c8a1d43 Mon Sep 17 00:00:00 2001 +From: David Henningsson +Date: Sun, 14 Aug 2016 09:31:25 +0200 +Subject: [PATCH] mixer: Fix rounding mode documentation + +The documentation specifies three different rounding modes, but this +is wrong, because they all end up calling snd_tlv_convert_from_dB, +which only has two rounding modes. + +Signed-off-by: David Henningsson +Signed-off-by: Takashi Iwai +--- + src/mixer/simple.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/mixer/simple.c b/src/mixer/simple.c +index fd9ba93ee791..82476d5ca0f2 100644 +--- a/src/mixer/simple.c ++++ b/src/mixer/simple.c +@@ -376,7 +376,7 @@ int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long + * \brief Return corresponding integer playback volume for given dB value for a mixer simple element + * \param elem Mixer simple element handle + * \param value value to be converted to dB range +- * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) ++ * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down + * \param dBvalue pointer to returned dB value + * \return 0 on success otherwise a negative error code + */ +@@ -454,7 +454,7 @@ int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_ + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value in dB * 100 +- * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) ++ * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down + * \return 0 on success otherwise a negative error code + */ + int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir) +@@ -491,7 +491,7 @@ int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value) + * \brief Set value in dB of playback volume control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value in dB * 100 +- * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) ++ * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down + * \return 0 on success otherwise a negative error code + */ + int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir) +@@ -706,7 +706,7 @@ int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long + * \param elem Mixer simple element handle + * \param dBvalue dB value to be converted to integer range + * \param value pointer to returned integer value +- * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) ++ * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down + * \return 0 on success otherwise a negative error code + */ + int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value) +@@ -777,7 +777,7 @@ int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_c + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value in dB * 100 +- * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) ++ * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down + * \return 0 on success otherwise a negative error code + */ + int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir) +@@ -814,7 +814,7 @@ int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value) + * \brief Set value in dB of capture volume control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value in dB * 100 +- * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) ++ * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down + * \return 0 on success otherwise a negative error code + */ + int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir) +-- +2.10.2 + diff --git a/0003-pcm-Fix-shm-initialization-race-condition.patch b/0003-pcm-Fix-shm-initialization-race-condition.patch new file mode 100644 index 0000000..26d51f6 --- /dev/null +++ b/0003-pcm-Fix-shm-initialization-race-condition.patch @@ -0,0 +1,39 @@ +From 7640856769d2d687877df720af5ef1ecd8938888 Mon Sep 17 00:00:00 2001 +From: Ismael Luceno +Date: Mon, 22 Aug 2016 13:04:33 -0300 +Subject: [PATCH] pcm: Fix shm initialization race-condition + +Easily seen when two threads try at the same time, one of them will fail. + +The bug was identified by using apulse with Skype. + +Fixes: dec428c35221 ("pcm: fix 'unable to create IPC shm instance' caused by fork from a thread") +Fixes: https://github.com/i-rinat/apulse/issues/38 +Signed-off-by: Ismael Luceno +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_direct.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index c3925cc20fd3..643498375b34 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -96,11 +96,12 @@ int snd_pcm_direct_shm_create_or_connect(snd_pcm_direct_t *dmix) + retryget: + dmix->shmid = shmget(dmix->ipc_key, sizeof(snd_pcm_direct_share_t), + dmix->ipc_perm); +- if (dmix->shmid < 0) { +- if (errno == ENOENT) ++ if (dmix->shmid < 0 && errno == ENOENT) { + if ((dmix->shmid = shmget(dmix->ipc_key, sizeof(snd_pcm_direct_share_t), + IPC_CREAT | IPC_EXCL | dmix->ipc_perm)) != -1) + first_instance = 1; ++ else if (errno == EEXIST) ++ goto retryget; + } + err = -errno; + if (dmix->shmid < 0) { +-- +2.10.2 + diff --git a/0004-pcm-Better-understandable-locking-code.patch b/0004-pcm-Better-understandable-locking-code.patch new file mode 100644 index 0000000..0bf9589 --- /dev/null +++ b/0004-pcm-Better-understandable-locking-code.patch @@ -0,0 +1,130 @@ +From 0fc4b4d17bfd0ce44394f6040e1d5f9dfa97a5ad Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 1 Sep 2016 14:05:00 +0200 +Subject: [PATCH] pcm: Better understandable locking code + +The newly added locking code seems to have confused quite a few +people, as "thread_safe=1" may be considered as if the thread-safety +lock has to be turned on. (It meant that the plugin _is_ thread-safe, +i.e. it needs no extra locking.) + +For avoiding such a misunderstanding, this commit renames the relevant +pcm fields and give more comments to explain what is for what. +The former single pcm->thread_safe flag is now split to two boolean +flags, pcm->need_lock and pcm->lock_enabled. It consumes a few more +bytes, but this would be (hopefully) better understandable. + +No functional change by this commit. + +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm.c | 16 +++++++++++----- + src/pcm/pcm_hw.c | 2 +- + src/pcm/pcm_local.h | 27 ++++++++++++++++++++++----- + 3 files changed, 34 insertions(+), 11 deletions(-) + +diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c +index f8323999343e..cd87bc759ded 100644 +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -2545,14 +2545,20 @@ int snd_pcm_new(snd_pcm_t **pcmp, snd_pcm_type_t type, const char *name, + INIT_LIST_HEAD(&pcm->async_handlers); + #ifdef THREAD_SAFE_API + pthread_mutex_init(&pcm->lock, NULL); ++ /* use locking as default; ++ * each plugin may suppress this in its open call ++ */ ++ pcm->need_lock = 1; + { +- static int default_thread_safe = -1; +- if (default_thread_safe < 0) { ++ /* set lock_enabled field depending on $LIBASOUND_THREAD_SAFE */ ++ static int do_lock_enable = -1; /* uninitialized */ ++ ++ /* evaluate env var only once at the first open for consistency */ ++ if (do_lock_enable == -1) { + char *p = getenv("LIBASOUND_THREAD_SAFE"); +- default_thread_safe = !p || *p != '0'; ++ do_lock_enable = !p || *p != '0'; + } +- if (!default_thread_safe) +- pcm->thread_safe = -1; /* force to disable */ ++ pcm->lock_enabled = do_lock_enable; + } + #endif + *pcmp = pcm; +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 3a5634c1d39a..56e88b6bf6c0 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -1514,7 +1514,7 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, + pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; + pcm->tstamp_type = tstamp_type; + #ifdef THREAD_SAFE_API +- pcm->thread_safe = 1; ++ pcm->need_lock = 0; /* hw plugin is thread-safe */ + #endif + + ret = snd_pcm_hw_mmap_status(pcm); +diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h +index bb7964d7833e..bba2f15ac463 100644 +--- a/src/pcm/pcm_local.h ++++ b/src/pcm/pcm_local.h +@@ -244,7 +244,12 @@ struct _snd_pcm { + void *private_data; + struct list_head async_handlers; + #ifdef THREAD_SAFE_API +- int thread_safe; ++ int need_lock; /* true = this PCM (plugin) is thread-unsafe, ++ * thus it needs a lock. ++ */ ++ int lock_enabled; /* thread-safety lock is enabled on the system; ++ * it's set depending on $LIBASOUND_THREAD_SAFE. ++ */ + pthread_mutex_t lock; + #endif + }; +@@ -1085,24 +1090,36 @@ static inline void sw_set_period_event(snd_pcm_sw_params_t *params, int val) + #define PCMINABORT(pcm) (((pcm)->mode & SND_PCM_ABORT) != 0) + + #ifdef THREAD_SAFE_API ++/* ++ * __snd_pcm_lock() and __snd_pcm_unlock() are used to lock/unlock the plugin ++ * forcibly even if it's declared as thread-safe. It's needed only for some ++ * codes that are thread-unsafe per design (e.g. snd_pcm_nonblock()). ++ * ++ * OTOH, snd_pcm_lock() and snd_pcm_unlock() are used to lock/unlock the plugin ++ * in normal situations. They do lock/unlock only when the plugin is ++ * thread-unsafe. ++ * ++ * Both __snd_pcm_lock() and snd_pcm_lock() (and their unlocks) wouldn't do ++ * any action when the whole locking is disabled via $LIBASOUND_THREAD_SAFE=0. ++ */ + static inline void __snd_pcm_lock(snd_pcm_t *pcm) + { +- if (pcm->thread_safe >= 0) ++ if (pcm->lock_enabled) + pthread_mutex_lock(&pcm->lock); + } + static inline void __snd_pcm_unlock(snd_pcm_t *pcm) + { +- if (pcm->thread_safe >= 0) ++ if (pcm->lock_enabled) + pthread_mutex_unlock(&pcm->lock); + } + static inline void snd_pcm_lock(snd_pcm_t *pcm) + { +- if (!pcm->thread_safe) ++ if (pcm->lock_enabled && pcm->need_lock) + pthread_mutex_lock(&pcm->lock); + } + static inline void snd_pcm_unlock(snd_pcm_t *pcm) + { +- if (!pcm->thread_safe) ++ if (pcm->lock_enabled && pcm->need_lock) + pthread_mutex_unlock(&pcm->lock); + } + #else /* THREAD_SAFE_API */ +-- +2.10.2 + diff --git a/0005-ucm-fix-crash-when-calling-snd_use_case_geti-with-no.patch b/0005-ucm-fix-crash-when-calling-snd_use_case_geti-with-no.patch new file mode 100644 index 0000000..96421e9 --- /dev/null +++ b/0005-ucm-fix-crash-when-calling-snd_use_case_geti-with-no.patch @@ -0,0 +1,52 @@ +From 4ec907c773a807d58b17f909522c27d05878b5b5 Mon Sep 17 00:00:00 2001 +From: Antonio Ospite +Date: Fri, 23 Sep 2016 18:11:16 +0200 +Subject: [PATCH] ucm: fix crash when calling snd_use_case_geti() with no + device or modifier + +When calling snd_use_case_geti(uc_mgr, "_devstatus", &lvalue) the code +ends up calling device_status(uc_mgr, NULL), which result in a crash in +strcmp(dev->name, NULL), when there are enabled devices. + +This happens because snd_use_case_geti() allows a "_devstatus" +identifier even if it's only supposed to allow the form +"_devstatus/{device}". + +So check that the device name is not null. + +The same issue occurs with "_modstatus", this change fixes that as well. + +Signed-off-by: Antonio Ospite +Signed-off-by: Takashi Iwai +--- + src/ucm/main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/ucm/main.c b/src/ucm/main.c +index 24d9510ecfec..8cc92089a326 100644 +--- a/src/ucm/main.c ++++ b/src/ucm/main.c +@@ -1528,12 +1528,20 @@ int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr, + str = NULL; + } + if (check_identifier(identifier, "_devstatus")) { ++ if (!str) { ++ err = -EINVAL; ++ goto __end; ++ } + err = device_status(uc_mgr, str); + if (err >= 0) { + *value = err; + err = 0; + } + } else if (check_identifier(identifier, "_modstatus")) { ++ if (!str) { ++ err = -EINVAL; ++ goto __end; ++ } + err = modifier_status(uc_mgr, str); + if (err >= 0) { + *value = err; +-- +2.10.2 + diff --git a/0006-ucm-docs-typeset-lists-of-identifiers-explicitly.patch b/0006-ucm-docs-typeset-lists-of-identifiers-explicitly.patch new file mode 100644 index 0000000..91c5d25 --- /dev/null +++ b/0006-ucm-docs-typeset-lists-of-identifiers-explicitly.patch @@ -0,0 +1,108 @@ +From 64481b3c72d758e8330e742aac95c7b66b863020 Mon Sep 17 00:00:00 2001 +From: Antonio Ospite +Date: Fri, 23 Sep 2016 18:18:57 +0200 +Subject: [PATCH] ucm: docs: typeset lists of identifiers explicitly + +Doxygen doesn't preserve formatting that relies only on indentation, +typeset lists of identifiers explicitly. + +This makes the HTML docs a lot more readable. + +This change comes along the lines of commit 72aa0f8332fb ("ucm: reformat +snd_use_case_get() doc"). + +Some TABs has been added too in order to preserve the aligned look when +reading the source code. + +Signed-off-by: Antonio Ospite +Signed-off-by: Takashi Iwai +--- + include/use-case.h | 57 +++++++++++++++++++++++++++--------------------------- + 1 file changed, 29 insertions(+), 28 deletions(-) + +diff --git a/include/use-case.h b/include/use-case.h +index 9aac6e2fb51d..8911645b5c4d 100644 +--- a/include/use-case.h ++++ b/include/use-case.h +@@ -192,20 +192,21 @@ int snd_use_case_free_list(const char *list[], int items); + * \return Number of list entries if success, otherwise a negative error code + * + * Defined identifiers: +- * NULL - get card list +- * (in pair cardname+comment) +- * _verbs - get verb list +- * (in pair verb+comment) +- * _devices[/{verb}] - get list of supported devices +- * (in pair device+comment) +- * _modifiers[/{verb}]- get list of supported modifiers +- * (in pair modifier+comment) +- * TQ[/{verb}] - get list of TQ identifiers +- * _enadevs - get list of enabled devices +- * _enamods - get list of enabled modifiers ++ * - NULL - get card list ++ * (in pair cardname+comment) ++ * - _verbs - get verb list ++ * (in pair verb+comment) ++ * - _devices[/{verb}] - get list of supported devices ++ * (in pair device+comment) ++ * - _modifiers[/{verb}] - get list of supported modifiers ++ * (in pair modifier+comment) ++ * - TQ[/{verb}] - get list of TQ identifiers ++ * - _enadevs - get list of enabled devices ++ * - _enamods - get list of enabled modifiers ++ * ++ * - _supporteddevs/{modifier}|{device}[/{verb}] - list of supported devices ++ * - _conflictingdevs/{modifier}|{device}[/{verb}] - list of conflicting devices + * +- * _supporteddevs/{modifier}|{device}[/{verb}] - list of supported devices +- * _conflictingdevs/{modifier}|{device}[/{verb}] - list of conflicting devices + * Note that at most one of the supported/conflicting devs lists has + * any entries, and when neither is present, all devices are supported. + * +@@ -331,8 +332,8 @@ int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, + * \return Zero if success, otherwise a negative error code + * + * Known identifiers: +- * _devstatus/{device} - return status for given device +- * _modstatus/{modifier} - return status for given modifier ++ * - _devstatus/{device} - return status for given device ++ * - _modstatus/{modifier} - return status for given modifier + */ + int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr, + const char *identifier, +@@ -346,19 +347,19 @@ int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr, + * \return Zero if success, otherwise a negative error code + * + * Known identifiers: +- * _verb - set current verb = value +- * _enadev - enable given device = value +- * _disdev - disable given device = value +- * _swdev/{old_device} - new_device = value +- * - disable old_device and then enable new_device +- * - if old_device is not enabled just return +- * - check transmit sequence firstly +- * _enamod - enable given modifier = value +- * _dismod - disable given modifier = value +- * _swmod/{old_modifier} - new_modifier = value +- * - disable old_modifier and then enable new_modifier +- * - if old_modifier is not enabled just return +- * - check transmit sequence firstly ++ * - _verb - set current verb = value ++ * - _enadev - enable given device = value ++ * - _disdev - disable given device = value ++ * - _swdev/{old_device} - new_device = value ++ * - disable old_device and then enable new_device ++ * - if old_device is not enabled just return ++ * - check transmit sequence firstly ++ * - _enamod - enable given modifier = value ++ * - _dismod - disable given modifier = value ++ * - _swmod/{old_modifier} - new_modifier = value ++ * - disable old_modifier and then enable new_modifier ++ * - if old_modifier is not enabled just return ++ * - check transmit sequence firstly + */ + int snd_use_case_set(snd_use_case_mgr_t *uc_mgr, + const char *identifier, +-- +2.10.2 + diff --git a/0007-Update-include-sound-tlv.h-from-4.9-pre-kernel-uapi.patch b/0007-Update-include-sound-tlv.h-from-4.9-pre-kernel-uapi.patch new file mode 100644 index 0000000..081a488 --- /dev/null +++ b/0007-Update-include-sound-tlv.h-from-4.9-pre-kernel-uapi.patch @@ -0,0 +1,105 @@ +From 21dcb000c8cfe38d3120419e0bd5360855318e55 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Thu, 29 Sep 2016 08:57:20 +0900 +Subject: [PATCH] Update include/sound/tlv.h from 4.9-pre kernel uapi + +The UAPI header in 4.9-pre kernel newly includes existent macros related +to tlv operation, mainly for layout of TLV packet payload. + +This commit updates corresponding backport header in this library. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + include/sound/tlv.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 77 insertions(+) + +diff --git a/include/sound/tlv.h b/include/sound/tlv.h +index 33d747df1410..b4df440c015b 100644 +--- a/include/sound/tlv.h ++++ b/include/sound/tlv.h +@@ -20,4 +20,81 @@ + #define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */ + #define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */ + ++/* ++ * channel-mapping TLV items ++ * TLV length must match with num_channels ++ */ ++#define SNDRV_CTL_TLVT_CHMAP_FIXED 0x101 /* fixed channel position */ ++#define SNDRV_CTL_TLVT_CHMAP_VAR 0x102 /* channels freely swappable */ ++#define SNDRV_CTL_TLVT_CHMAP_PAIRED 0x103 /* pair-wise swappable */ ++ ++/* ++ * TLV structure is right behind the struct snd_ctl_tlv: ++ * unsigned int type - see SNDRV_CTL_TLVT_* ++ * unsigned int length ++ * .... data aligned to sizeof(unsigned int), use ++ * block_length = (length + (sizeof(unsigned int) - 1)) & ++ * ~(sizeof(unsigned int) - 1)) .... ++ */ ++#define SNDRV_CTL_TLVD_ITEM(type, ...) \ ++ (type), SNDRV_CTL_TLVD_LENGTH(__VA_ARGS__), __VA_ARGS__ ++#define SNDRV_CTL_TLVD_LENGTH(...) \ ++ ((unsigned int)sizeof((const unsigned int[]) { __VA_ARGS__ })) ++ ++#define SNDRV_CTL_TLVD_CONTAINER_ITEM(...) \ ++ SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_CONTAINER, __VA_ARGS__) ++#define SNDRV_CTL_TLVD_DECLARE_CONTAINER(name, ...) \ ++ unsigned int name[] = { \ ++ SNDRV_CTL_TLVD_CONTAINER_ITEM(__VA_ARGS__) \ ++ } ++ ++#define SNDRV_CTL_TLVD_DB_SCALE_MASK 0xffff ++#define SNDRV_CTL_TLVD_DB_SCALE_MUTE 0x10000 ++#define SNDRV_CTL_TLVD_DB_SCALE_ITEM(min, step, mute) \ ++ SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_SCALE, \ ++ (min), \ ++ ((step) & SNDRV_CTL_TLVD_DB_SCALE_MASK) | \ ++ ((mute) ? SNDRV_CTL_TLVD_DB_SCALE_MUTE : 0)) ++#define SNDRV_CTL_TLVD_DECLARE_DB_SCALE(name, min, step, mute) \ ++ unsigned int name[] = { \ ++ SNDRV_CTL_TLVD_DB_SCALE_ITEM(min, step, mute) \ ++ } ++ ++/* dB scale specified with min/max values instead of step */ ++#define SNDRV_CTL_TLVD_DB_MINMAX_ITEM(min_dB, max_dB) \ ++ SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_MINMAX, (min_dB), (max_dB)) ++#define SNDRV_CTL_TLVD_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \ ++ SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_MINMAX_MUTE, (min_dB), (max_dB)) ++#define SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(name, min_dB, max_dB) \ ++ unsigned int name[] = { \ ++ SNDRV_CTL_TLVD_DB_MINMAX_ITEM(min_dB, max_dB) \ ++ } ++#define SNDRV_CTL_TLVD_DECLARE_DB_MINMAX_MUTE(name, min_dB, max_dB) \ ++ unsigned int name[] = { \ ++ SNDRV_CTL_TLVD_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \ ++ } ++ ++/* linear volume between min_dB and max_dB (.01dB unit) */ ++#define SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \ ++ SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_LINEAR, (min_dB), (max_dB)) ++#define SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(name, min_dB, max_dB) \ ++ unsigned int name[] = { \ ++ SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \ ++ } ++ ++/* dB range container: ++ * Items in dB range container must be ordered by their values and by their ++ * dB values. This implies that larger values must correspond with larger ++ * dB values (which is also required for all other mixer controls). ++ */ ++/* Each item is: */ ++#define SNDRV_CTL_TLVD_DB_RANGE_ITEM(...) \ ++ SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_RANGE, __VA_ARGS__) ++#define SNDRV_CTL_TLVD_DECLARE_DB_RANGE(name, ...) \ ++ unsigned int name[] = { \ ++ SNDRV_CTL_TLVD_DB_RANGE_ITEM(__VA_ARGS__) \ ++ } ++ ++#define SNDRV_CTL_TLVD_DB_GAIN_MUTE -9999999 ++ + #endif +-- +2.10.2 + diff --git a/0008-test-use-actual-information-for-TLV-operation.patch b/0008-test-use-actual-information-for-TLV-operation.patch new file mode 100644 index 0000000..ba48674 --- /dev/null +++ b/0008-test-use-actual-information-for-TLV-operation.patch @@ -0,0 +1,386 @@ +From ee1182d2cbb4930ca1166bc03f3b0fcfbb594145 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Thu, 29 Sep 2016 08:57:21 +0900 +Subject: [PATCH] test: use actual information for TLV operation + +Currently, this test program uses undefined type of TLV data. This can +bring confusions to userspace applications. + +This commit replaces the array with valid information, constructed by newly +exported TLV macros from kernel land. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + test/user-ctl-element-set.c | 214 ++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 178 insertions(+), 36 deletions(-) + +diff --git a/test/user-ctl-element-set.c b/test/user-ctl-element-set.c +index 9b9dc598f0af..75083d219fe6 100644 +--- a/test/user-ctl-element-set.c ++++ b/test/user-ctl-element-set.c +@@ -8,6 +8,7 @@ + */ + + #include "../include/asoundlib.h" ++#include + + struct elem_set_trial { + snd_ctl_t *handle; +@@ -25,8 +26,30 @@ struct elem_set_trial { + snd_ctl_elem_info_t *info); + void (*change_elem_members)(struct elem_set_trial *trial, + snd_ctl_elem_value_t *elem_data); ++ int (*allocate_elem_set_tlv)(struct elem_set_trial *trial, ++ unsigned int **tlv); + }; + ++struct chmap_entry { ++ unsigned int type; ++ unsigned int length; ++ unsigned int maps[0]; ++}; ++ ++/* ++ * History of TLV feature: ++ * ++ * 2016/09/15: 398fa4db6c69 ("ALSA: control: move layout of TLV payload to UAPI ++ * header") ++ * 2012/07/21: 2d3391ec0ecc ("ALSA: PCM: channel mapping API implementation") ++ * 2011/11/20: bf1d1c9b6179 ("ALSA: tlv: add DECLARE_TLV_DB_RANGE()") ++ * 2009/07/16: 085f30654175 ("ALSA: Add new TLV types for dBwith min/max") ++ * 2006/09/06: 55a29af5ed5d ("[ALSA] Add definition of TLV dB range compound") ++ * 2006/08/28: 063a40d9111c ("Add the definition of linear volume TLV") ++ * 2006/08/28: 42750b04c5ba ("[ALSA] Control API - TLV implementation for ++ * additional information like dB scale") ++ */ ++ + /* Operations for elements in an element set with boolean type. */ + static int add_bool_elem_set(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) +@@ -47,13 +70,30 @@ static void change_bool_elem_members(struct elem_set_trial *trial, + } + } + ++static int allocate_bool_elem_set_tlv(struct elem_set_trial *trial, ++ unsigned int **tlv) ++{ ++ /* ++ * Performs like a toggle switch for attenuation, because they're bool ++ * elements. ++ */ ++ static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(range, -10000, 0); ++ ++ *tlv = malloc(sizeof(range)); ++ if (*tlv == NULL) ++ return -ENOMEM; ++ memcpy(*tlv, range, sizeof(range)); ++ ++ return 0; ++} ++ + /* Operations for elements in an element set with integer type. */ + static int add_int_elem_set(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) + { + return snd_ctl_add_integer_elem_set(trial->handle, info, + trial->element_count, trial->member_count, +- 0, 99, 1); ++ 0, 25, 1); + } + + static int check_int_elem_props(struct elem_set_trial *trial, +@@ -61,7 +101,7 @@ static int check_int_elem_props(struct elem_set_trial *trial, + { + if (snd_ctl_elem_info_get_min(info) != 0) + return -EIO; +- if (snd_ctl_elem_info_get_max(info) != 99) ++ if (snd_ctl_elem_info_get_max(info) != 25) + return -EIO; + if (snd_ctl_elem_info_get_step(info) != 1) + return -EIO; +@@ -81,6 +121,41 @@ static void change_int_elem_members(struct elem_set_trial *trial, + } + } + ++static int allocate_int_elem_set_tlv(struct elem_set_trial *trial, ++ unsigned int **tlv) ++{ ++ unsigned int len, pos; ++ unsigned int i, j; ++ struct chmap_entry *entry; ++ ++ /* Calculate size of TLV packet for channel-mapping information. */ ++ len = 0; ++ for (i = 1; i <= 25; ++i) { ++ len += sizeof(struct chmap_entry); ++ len += i * sizeof(unsigned int); ++ } ++ ++ *tlv = malloc(len); ++ if (*tlv == NULL) ++ return -ENOMEM; ++ ++ /* ++ * Emulate channel-mapping information in in-kernel implementation. ++ * Here, 25 entries are for each different channel. ++ */ ++ pos = 0; ++ for (i = 1; i <= 25 && pos < len; ++i) { ++ entry = (struct chmap_entry *)&(*tlv)[pos]; ++ entry->type = SNDRV_CTL_TLVT_CHMAP_FIXED; ++ entry->length = i * sizeof(unsigned int); ++ for (j = 0; j < i; ++j) ++ entry->maps[j] = SND_CHMAP_MONO + j; ++ pos += sizeof(struct chmap_entry) + i * sizeof(unsigned int); ++ } ++ ++ return 0; ++} ++ + /* Operations for elements in an element set with enumerated type. */ + static const char *const labels[] = { + "trusty", +@@ -158,6 +233,24 @@ static void change_bytes_elem_members(struct elem_set_trial *trial, + } + } + ++static int allocate_bytes_elem_set_tlv(struct elem_set_trial *trial, ++ unsigned int **tlv) ++{ ++ /* ++ * Emulate AK4396. ++ * 20 * log10(x/255) (dB) ++ * Here, x is written value. ++ */ ++ static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(range, -4813, 0); ++ ++ *tlv = malloc(sizeof(range)); ++ if (*tlv == NULL) ++ return -ENOMEM; ++ memcpy(*tlv, range, sizeof(range)); ++ ++ return 0; ++} ++ + /* Operations for elements in an element set with iec958 type. */ + static int add_iec958_elem_set(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) +@@ -197,17 +290,17 @@ static int add_int64_elem_set(struct elem_set_trial *trial, + { + return snd_ctl_add_integer64_elem_set(trial->handle, info, + trial->element_count, trial->member_count, +- 100, 10000, 30); ++ 0, 10000, 1); + } + + static int check_int64_elem_props(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) + { +- if (snd_ctl_elem_info_get_min64(info) != 100) ++ if (snd_ctl_elem_info_get_min64(info) != 0) + return -EIO; + if (snd_ctl_elem_info_get_max64(info) != 10000) + return -EIO; +- if (snd_ctl_elem_info_get_step64(info) != 30) ++ if (snd_ctl_elem_info_get_step64(info) != 1) + return -EIO; + + return 0; +@@ -225,6 +318,45 @@ static void change_int64_elem_members(struct elem_set_trial *trial, + } + } + ++static int allocate_int64_elem_set_tlv(struct elem_set_trial *trial, ++ unsigned int **tlv) ++{ ++ /* ++ * Use this fomula between linear/dB value: ++ * ++ * Linear: dB range (coeff) ++ * 0<-> 4: -59.40<->-56.36 (44) ++ * 4<->22: -56.36<->-45.56 (60) ++ * 22<->33: -45.56<->-40.72 (76) ++ * 33<->37: -40.72<->-38.32 (44) ++ * 37<->48: -38.32<->-29.96 (76) ++ * 48<->66: -29.96<->-22.04 (60) ++ * 66<->84: -22.04<-> -8.36 (44) ++ * 84<->95: -8.36<-> -1.76 (60) ++ * 95<->99: -1.76<-> 0.00 (76) ++ * 100<->..: 0.0 ++ */ ++ static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(range, ++ 0, 4, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-5940, 44, 1), ++ 4, 22, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-5636, 60, 0), ++ 22, 33, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-4556, 76, 0), ++ 33, 37, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-4072, 44, 0), ++ 37, 48, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-3832, 76, 0), ++ 48, 66, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-2996, 60, 0), ++ 66, 84, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-2204, 44, 0), ++ 84, 95, SNDRV_CTL_TLVD_DB_SCALE_ITEM( -836, 60, 0), ++ 95, 99, SNDRV_CTL_TLVD_DB_SCALE_ITEM( -176, 76, 0), ++ 100, 10000, SNDRV_CTL_TLVD_DB_SCALE_ITEM(0, 0, 0), ++ ); ++ ++ *tlv = malloc(sizeof(range)); ++ if (*tlv == NULL) ++ return -ENOMEM; ++ memcpy(*tlv, range, sizeof(range)); ++ ++ return 0; ++} ++ + /* Common operations. */ + static int add_elem_set(struct elem_set_trial *trial) + { +@@ -414,41 +546,41 @@ static int check_elems(struct elem_set_trial *trial) + + static int check_tlv(struct elem_set_trial *trial) + { +- unsigned int orig[8], curr[8]; ++ unsigned int *tlv; ++ unsigned int len; ++ unsigned int *curr; + int err; + +- /* +- * See a layout of 'struct snd_ctl_tlv'. I don't know the reason to +- * construct this buffer with the same layout. It should be abstracted +- * inner userspace library... +- */ +- orig[0] = snd_ctl_elem_id_get_numid(trial->id); +- orig[1] = 6 * sizeof(orig[0]); +- orig[2] = 'a'; +- orig[3] = 'b'; +- orig[4] = 'c'; +- orig[5] = 'd'; +- orig[6] = 'e'; +- orig[7] = 'f'; ++ err = trial->allocate_elem_set_tlv(trial, &tlv); ++ if (err < 0) ++ return err; ++ ++ len = tlv[1] + sizeof(unsigned int) * 2; ++ curr = malloc(len); ++ if (curr == NULL) { ++ free(tlv); ++ return -ENOMEM; ++ } + + /* + * In in-kernel implementation, write and command operations are the +- * same for an element set added by userspace applications. Here, I ++ * same for an element set added by userspace applications. Here, I + * use write. + */ + err = snd_ctl_elem_tlv_write(trial->handle, trial->id, +- (const unsigned int *)orig); ++ (const unsigned int *)tlv); + if (err < 0) +- return err; ++ goto end; + +- err = snd_ctl_elem_tlv_read(trial->handle, trial->id, curr, +- sizeof(curr)); ++ err = snd_ctl_elem_tlv_read(trial->handle, trial->id, curr, len); + if (err < 0) +- return err; +- +- if (memcmp(curr, orig, sizeof(orig)) != 0) +- return -EIO; ++ goto end; + ++ if (memcmp(curr, tlv, len) != 0) ++ err = -EIO; ++end: ++ free(tlv); ++ free(curr); + return 0; + } + +@@ -484,6 +616,8 @@ int main(void) + trial.add_elem_set = add_bool_elem_set; + trial.check_elem_props = NULL; + trial.change_elem_members = change_bool_elem_members; ++ trial.allocate_elem_set_tlv = ++ allocate_bool_elem_set_tlv; + break; + case SND_CTL_ELEM_TYPE_INTEGER: + trial.element_count = 900; +@@ -495,6 +629,8 @@ int main(void) + trial.add_elem_set = add_int_elem_set; + trial.check_elem_props = check_int_elem_props; + trial.change_elem_members = change_int_elem_members; ++ trial.allocate_elem_set_tlv = ++ allocate_int_elem_set_tlv; + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + trial.element_count = 900; +@@ -506,6 +642,7 @@ int main(void) + trial.add_elem_set = add_enum_elem_set; + trial.check_elem_props = check_enum_elem_props; + trial.change_elem_members = change_enum_elem_members; ++ trial.allocate_elem_set_tlv = NULL; + break; + case SND_CTL_ELEM_TYPE_BYTES: + trial.element_count = 900; +@@ -517,6 +654,8 @@ int main(void) + trial.add_elem_set = add_bytes_elem_set; + trial.check_elem_props = NULL; + trial.change_elem_members = change_bytes_elem_members; ++ trial.allocate_elem_set_tlv = ++ allocate_bytes_elem_set_tlv; + break; + case SND_CTL_ELEM_TYPE_IEC958: + trial.element_count = 1; +@@ -528,6 +667,7 @@ int main(void) + trial.add_elem_set = add_iec958_elem_set; + trial.check_elem_props = NULL; + trial.change_elem_members = change_iec958_elem_members; ++ trial.allocate_elem_set_tlv = NULL; + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + default: +@@ -540,6 +680,8 @@ int main(void) + trial.add_elem_set = add_int64_elem_set; + trial.check_elem_props = check_int64_elem_props; + trial.change_elem_members = change_int64_elem_members; ++ trial.allocate_elem_set_tlv = ++ allocate_int64_elem_set_tlv; + break; + } + +@@ -589,22 +731,22 @@ int main(void) + } + + /* +- * Test an operation to change threshold data of this element set, +- * except for IEC958 type. ++ * Test an operation to change TLV data of this element set, ++ * except for enumerated and IEC958 type. + */ +- if (trial.type != SND_CTL_ELEM_TYPE_IEC958) { ++ if (trial.allocate_elem_set_tlv != NULL) { + err = check_tlv(&trial); + if (err < 0) { +- printf("Fail to change threshold level of an " +- "element set with %s type.\n", ++ printf("Fail to change TLV data of an element " ++ "set with %s type.\n", + 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 " +- "threshold level of an an element set " +- "with %s type.\n", ++ 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; + } +-- +2.10.2 + diff --git a/0009-ctl-improve-API-documentation-for-TLV-operation.patch b/0009-ctl-improve-API-documentation-for-TLV-operation.patch new file mode 100644 index 0000000..0b11314 --- /dev/null +++ b/0009-ctl-improve-API-documentation-for-TLV-operation.patch @@ -0,0 +1,52 @@ +From d31e37d12c58ca3be72e404a222289a896029ef1 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Thu, 29 Sep 2016 08:57:22 +0900 +Subject: [PATCH] ctl: improve API documentation for TLV operation + +A commit fe1b08803db6 ("ctl: improve API documentation for threshold level +operations") changes documentations for some TLV-related APIs with wrong +explanations. + +This commit fix it with better explanations. + +Fixes: fe1b08803db6 ("ctl: improve API documentation for threshold level operations") +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/control/control.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/control/control.c b/src/control/control.c +index 6c00b8e50d2b..422582d40600 100644 +--- a/src/control/control.c ++++ b/src/control/control.c +@@ -912,7 +912,7 @@ static int snd_ctl_tlv_do(snd_ctl_t *ctl, int op_flag, + } + + /** +- * \brief Set given data to an element as threshold level. ++ * \brief Read structured data from an element set to given buffer. + * \param ctl A handle of backend module for control interface. + * \param id ID of an element. + * \param tlv An array with members of unsigned int type. +@@ -940,7 +940,7 @@ int snd_ctl_elem_tlv_read(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + } + + /** +- * \brief Set given data to an element as threshold level. ++ * \brief Write structured data from given buffer to an element set. + * \param ctl A handle of backend module for control interface. + * \param id ID of an element. + * \param tlv An array with members of unsigned int type. The second member +@@ -957,7 +957,7 @@ int snd_ctl_elem_tlv_write(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + } + + /** +- * \brief Set given data to an element as threshold level. ++ * \brief Process structured data from given buffer for an element set. + * \param ctl A handle of backend module for control interface. + * \param id ID of an element. + * \param tlv An array with members of unsigned int type. The second member +-- +2.10.2 + diff --git a/0010-ctl-improve-documentation-about-TLV-related-APIs.patch b/0010-ctl-improve-documentation-about-TLV-related-APIs.patch new file mode 100644 index 0000000..197f421 --- /dev/null +++ b/0010-ctl-improve-documentation-about-TLV-related-APIs.patch @@ -0,0 +1,64 @@ +From e55d735f84364d3b7d38104cee37c968e3797ea4 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Thu, 29 Sep 2016 08:57:23 +0900 +Subject: [PATCH] ctl: improve documentation about TLV-related APIs + +The documentation gives no hints to users about format of TLV data. + +This commit add hints to construct/parse the information. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/control/control.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/src/control/control.c b/src/control/control.c +index 422582d40600..40ee9b7516a2 100644 +--- a/src/control/control.c ++++ b/src/control/control.c +@@ -918,6 +918,13 @@ static int snd_ctl_tlv_do(snd_ctl_t *ctl, int op_flag, + * \param tlv An array with members of unsigned int type. + * \param tlv_size The length of the array. + * \return 0 on success otherwise a negative error code ++ * ++ * The format of an array of \a tlv argument is: ++ * tlv[0]: Type. One of SND_CTL_TLVT_XXX. ++ * tlv[1]: Length. The length of value in units of byte. ++ * tlv[2..]: Value. Depending on the type. ++ * ++ * Details are described in . + */ + int snd_ctl_elem_tlv_read(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int *tlv, unsigned int tlv_size) +@@ -948,6 +955,13 @@ int snd_ctl_elem_tlv_read(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + * \retval 0 on success + * \retval >0 on success when value was changed + * \retval <0 a negative error code ++ * ++ * The format of an array of \a tlv argument is: ++ * tlv[0]: Type. One of SND_CTL_TLVT_XXX. ++ * tlv[1]: Length. The length of value in units of byte. ++ * tlv[2..]: Value. Depending on the type. ++ * ++ * Details are described in . + */ + int snd_ctl_elem_tlv_write(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + const unsigned int *tlv) +@@ -965,6 +979,13 @@ int snd_ctl_elem_tlv_write(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + * \retval 0 on success + * \retval >0 on success when value was changed + * \retval <0 a negative error code ++ * ++ * The format of an array of \a tlv argument is: ++ * tlv[0]: Type. One of SND_CTL_TLVT_XXX. ++ * tlv[1]: Length. The length of value in units of byte. ++ * tlv[2..]: Value. Depending on the type. ++ * ++ * Details are described in . + */ + int snd_ctl_elem_tlv_command(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + const unsigned int *tlv) +-- +2.10.2 + diff --git a/0011-ctl-correct-documentation-about-TLV-feature.patch b/0011-ctl-correct-documentation-about-TLV-feature.patch new file mode 100644 index 0000000..c52451a --- /dev/null +++ b/0011-ctl-correct-documentation-about-TLV-feature.patch @@ -0,0 +1,59 @@ +From 4298736ddad3e61dee2d379c8042f304317a6f3c Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Thu, 29 Sep 2016 08:57:24 +0900 +Subject: [PATCH] ctl: correct documentation about TLV feature + +From my misunderstanding, some explanations are wrong. This commit +corrects them. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/control/control.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/src/control/control.c b/src/control/control.c +index 40ee9b7516a2..134ba4c8ebea 100644 +--- a/src/control/control.c ++++ b/src/control/control.c +@@ -59,27 +59,27 @@ elements included in the element set. + When the value of member is changed, corresponding events are transferred to + userspace applications. The applications should subscribe any events in advance. + +-\section tlv_blob Thredshold level and arbitrary data ++\section tlv_blob Supplemental data for elements in an element set + +-TLV feature is designed to transfer data about threshold level between a driver +-and any userspace applications. The data is for an element set. ++TLV feature is designed to transfer data in a shape of Type/Length/Value, ++between a driver and any userspace applications. The main purpose is to attach ++supplement information for elements to an element set; e.g. dB range. + + At first, this feature was implemented to add pre-defined data readable to + userspace applications. Soon, it was extended to handle several operations; + read, write and command. The original implementation remains as the read + operation. The command operation allows drivers to have own implementations +-against requests from userspace applications. As of 2016, simple write operation +-is not supported yet. ++against requests from userspace applications. + + This feature was introduced to ALSA control feature in 2006, at commit + c7a0708a2362, corresponding to a series of work for Linux kernel (42750b04c5ba + and 8aa9b586e420). + +-This feature can transfer arbitrary data in a shape of an array with members of +-unsigned int type, therefore it can be used to deliver quite large arbitrary +-data from userspace to in-kernel drivers via ALSA control character device. +-Focusing on this nature, some in-kernel implementations utilize this feature for +-I/O operations. ++There's no limitation about maximum size of the data, therefore it can be used ++to deliver quite large arbitrary data from userspace to in-kernel drivers via ++ALSA control character device. Focusing on this nature, as of 2016, some ++in-kernel implementations utilize this feature for I/O operations. This is ++against the original design. + */ + + #include +-- +2.10.2 + diff --git a/0012-conf-ucm-skylake-add-skylake-rt286-conf-files.patch b/0012-conf-ucm-skylake-add-skylake-rt286-conf-files.patch new file mode 100644 index 0000000..6002edc --- /dev/null +++ b/0012-conf-ucm-skylake-add-skylake-rt286-conf-files.patch @@ -0,0 +1,313 @@ +From 4dfae1adb31440a37e2183626518f1373eb38b15 Mon Sep 17 00:00:00 2001 +From: Vinod Koul +Date: Fri, 7 Oct 2016 16:28:23 +0530 +Subject: [PATCH] conf/ucm: skylake: add skylake-rt286 conf files + +This add the UCM conf files for skylake enabling I2S audio, HDMI and DMIC +ports. + +Signed-off-by: Karthik D M +Signed-off-by: Nishit Sharma +Signed-off-by: Jeeja KP +Signed-off-by: Vinod Koul +Signed-off-by: Takashi Iwai +--- + configure.ac | 1 + + src/conf/ucm/Makefile.am | 2 +- + src/conf/ucm/skylake-rt286/Hdmi1 | 20 ++++ + src/conf/ucm/skylake-rt286/Hdmi2 | 20 ++++ + src/conf/ucm/skylake-rt286/HiFi | 129 ++++++++++++++++++++++++++ + src/conf/ucm/skylake-rt286/Makefile.am | 4 + + src/conf/ucm/skylake-rt286/skylake-rt286.conf | 60 ++++++++++++ + 7 files changed, 235 insertions(+), 1 deletion(-) + create mode 100644 src/conf/ucm/skylake-rt286/Hdmi1 + create mode 100644 src/conf/ucm/skylake-rt286/Hdmi2 + create mode 100644 src/conf/ucm/skylake-rt286/HiFi + create mode 100644 src/conf/ucm/skylake-rt286/Makefile.am + create mode 100644 src/conf/ucm/skylake-rt286/skylake-rt286.conf + +diff --git a/configure.ac b/configure.ac +index a1de230e588c..0dfbe81c6595 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -673,6 +673,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \ + src/conf/ucm/PAZ00/Makefile \ + src/conf/ucm/GoogleNyan/Makefile \ + src/conf/ucm/broadwell-rt286/Makefile \ ++ src/conf/ucm/skylake-rt286/Makefile \ + src/conf/ucm/VEYRON-I2S/Makefile \ + src/conf/ucm/chtrt5645/Makefile \ + src/conf/ucm/DB410c/Makefile \ +diff --git a/src/conf/ucm/Makefile.am b/src/conf/ucm/Makefile.am +index 7bf432e70e26..a11d324e785b 100644 +--- a/src/conf/ucm/Makefile.am ++++ b/src/conf/ucm/Makefile.am +@@ -1 +1 @@ +-SUBDIRS=DAISY-I2S PandaBoard PandaBoardES SDP4430 tegraalc5632 PAZ00 GoogleNyan broadwell-rt286 VEYRON-I2S chtrt5645 DB410c ++SUBDIRS=DAISY-I2S PandaBoard PandaBoardES SDP4430 tegraalc5632 PAZ00 GoogleNyan broadwell-rt286 skylake-rt286 VEYRON-I2S chtrt5645 DB410c +diff --git a/src/conf/ucm/skylake-rt286/Hdmi1 b/src/conf/ucm/skylake-rt286/Hdmi1 +new file mode 100644 +index 000000000000..0e00fc844301 +--- /dev/null ++++ b/src/conf/ucm/skylake-rt286/Hdmi1 +@@ -0,0 +1,20 @@ ++# Usecase for device HDMI1/Display Port stereo playback on Intel SKYLAKE/KABYLAKE platforms ++# For Audio in I2S mode ++ ++SectionDevice."Hdmi1" { ++ Comment "HDMI/Display Port 1 Stereo" ++ ++ EnableSequence [ ++ ] ++ ++ DisableSequence [ ++ ] ++ ++ Value { ++ PlaybackPCM "hw:skylakert286,4" ++ PlaybackChannels "2" ++ PlaybackPriority "3" ++ JackControl "HDMI/DP, pcm=4 Jack" ++ } ++} ++ +diff --git a/src/conf/ucm/skylake-rt286/Hdmi2 b/src/conf/ucm/skylake-rt286/Hdmi2 +new file mode 100644 +index 000000000000..89b31aa4b8f9 +--- /dev/null ++++ b/src/conf/ucm/skylake-rt286/Hdmi2 +@@ -0,0 +1,20 @@ ++# Usecase for device HDMI2/Display Port stereo playback on Intel SKYLAKE/KABYLAKE platforms ++# For Audio in I2S mode ++ ++SectionDevice."Hdmi2" { ++ Comment "HDMI/Display Port 2 Stereo" ++ ++ EnableSequence [ ++ ] ++ ++ DisableSequence [ ++ ] ++ ++ Value { ++ PlaybackPCM "hw:skylakert286,5" ++ PlaybackChannels "2" ++ PlaybackPriority "4" ++ JackControl "HDMI/DP, pcm=5 Jack" ++ } ++} ++ +diff --git a/src/conf/ucm/skylake-rt286/HiFi b/src/conf/ucm/skylake-rt286/HiFi +new file mode 100644 +index 000000000000..41638f4cb9c8 +--- /dev/null ++++ b/src/conf/ucm/skylake-rt286/HiFi +@@ -0,0 +1,129 @@ ++# Usecase for stereo playback Speaker and Headset, Recording on DMIC and Headset MIC. ++# For Audio in I2S mode on Intel SKYLAKE/KABYLAKE platforms ++ ++SectionVerb { ++ ++ EnableSequence [ ++ cdev "hw:skylakert286" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:skylakert286" ++ ] ++ ++ Value { ++ TQ "HiFi" ++ CapturePCM "hw:skylakert286,1" ++ PlaybackPCM "hw:skylakert286,0" ++ } ++} ++ ++SectionDevice."Headphones" { ++ Comment "Headphones" ++ ++ ConflictingDevice [ ++ "Speaker" ++ ] ++ EnableSequence [ ++ cdev "hw:skylakert286" ++ cset "name='HPO L Switch' 1" ++ cset "name='HPO R Switch' 1" ++ cset "name='Headphone Jack Switch' 1" ++ cset "name='Speaker Playback Switch' 0,0" ++ ] ++ ++ DisableSequence [ ++ ] ++ Value { ++ PlaybackChannels "2" ++ PlaybackPriority "1" ++ JackControl "Headphone Jack" ++ JackHWMute "Speaker" ++ } ++} ++ ++SectionDevice."Speaker" { ++ Comment "Speaker" ++ ++ ConflictingDevice [ ++ "Headphones" ++ ] ++ EnableSequence [ ++ cdev "hw:skylakert286" ++ cset "name='SPO Switch' 1" ++ cset "name='Speaker Playback Switch' 1,1" ++ cset "name='Speaker Switch' 1" ++ cset "name='HPO L Switch' 0" ++ cset "name='HPO R Switch' 0" ++ ] ++ ++ DisableSequence [ ++ ] ++ Value { ++ PlaybackChannels "2" ++ PlaybackPriority "1" ++ JackHWMute "Headphones" ++ } ++} ++ ++SectionDevice."Headset" { ++ Comment "Headset Mic" ++ ++ ConflictingDevice [ ++ "dmiccap" ++ ] ++ EnableSequence [ ++ cdev "hw:skylakert286" ++ cset "name='media0_out mo codec0_in mi Switch' 1" ++ cset "name='ADC0 Capture Switch' 1,1" ++ cset "name='ADC 0 Mux' 0" ++ cset "name='Mic Jack Switch' 1" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 0" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:skylakert286" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" ++ cset "name='media0_out mo codec0_in mi Switch' 0" ++ ] ++ Value { ++ CaptureChannels "2" ++ CapturePriority "2" ++ JackControl "Mic Jack" ++ } ++} ++ ++ ++SectionDevice."dmiccap" { ++ Comment "DMIC Stereo" ++ ++ ConflictingDevice [ ++ "Headpset" ++ ] ++ ++ EnableSequence [ ++ ++ cdev "hw:skylakert286" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" ++ cset "name='media0_out mo codec0_in mi Switch' 0" ++ cset "name='ADC0 Capture Switch' 0,0" ++ cset "name='Mic Jack Switch' 0" ++ cset "name='ADC 0 Mux' 0" ++ ++ ] ++ ++ DisableSequence [ ++ cdev "hw:skylakert286" ++ cset "name='media0_out mo codec0_in mi Switch' 1" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 0" ++ cset "name='ADC0 Capture Switch' 1,1" ++ cset "name='Mic Jack Switch' 1" ++ cset "name='ADC 0 Mux' 2" ++ ] ++ Value { ++ CaptureChannels "2" ++ CapturePriority "2" ++ } ++} ++ +diff --git a/src/conf/ucm/skylake-rt286/Makefile.am b/src/conf/ucm/skylake-rt286/Makefile.am +new file mode 100644 +index 000000000000..9d6a85a5bdcf +--- /dev/null ++++ b/src/conf/ucm/skylake-rt286/Makefile.am +@@ -0,0 +1,4 @@ ++alsaconfigdir = @ALSA_CONFIG_DIR@ ++ucmdir = $(alsaconfigdir)/ucm/skylake-rt286 ++ucm_DATA = skylake-rt286.conf HiFi Hdmi1 Hdmi2 ++EXTRA_DIST = $(ucm_DATA) +diff --git a/src/conf/ucm/skylake-rt286/skylake-rt286.conf b/src/conf/ucm/skylake-rt286/skylake-rt286.conf +new file mode 100644 +index 000000000000..3e4322864728 +--- /dev/null ++++ b/src/conf/ucm/skylake-rt286/skylake-rt286.conf +@@ -0,0 +1,60 @@ ++# UCM for Intel SKYLAKE/KABYLAKE platforms ++# For Audio in I2S mode ++ ++SectionUseCase."HiFi" { ++ File "HiFi" ++ Comment "Play and record HiFi quality Music" ++} ++ ++SectionUseCase."Hdmi1" { ++ File "Hdmi1" ++ Comment "Play on Hdmi/DP 1" ++} ++ ++SectionUseCase."Hdmi2" { ++ File "Hdmi2" ++ Comment "Play on Hdmi/DP 2" ++} ++ ++ValueDefaults { ++ PlaybackCTL "hw:skylakert286" ++ CaptureCTL "hw:skylakert286" ++ CaptureChannels "2" ++ CapturePriority "2" ++} ++ ++SectionDefaults [ ++ cdev "hw:skylakert286" ++ cset "name='Headphone Jack Switch' 1" ++ cset "name='Speaker Switch' 1" ++ cset "name='Speaker Playback Switch' 0,0" ++ cset "name='Front DAC Switch' 1" ++ cset "name='Front RECMIX Switch' 0" ++ cset "name='Mic Jack Switch' 1" ++ cset "name='ADC 0 Mux' 2" ++ cset "name='ADC 1 Mux' 0" ++ cset "name='ADC0 Capture Volume' 105,105" ++ cset "name='ADC0 Capture Switch' 1,1" ++ cset "name='AMIC Volume' 3" ++ cset "name='DAC0 Playback Volume' 100,100" ++ cset "name='HPO L Switch' 0" ++ cset "name='HPO Mux' 0" ++ cset "name='HPO R Switch' 0" ++ cset "name='Pin 5 Mux' 1" ++ cset "name='Pin 6 Mux' 2" ++ cset "name='Pin 7 Mux' 3" ++ cset "name='RECMIX Beep Switch' 0" ++ cset "name='RECMIX Line1 Switch' 0" ++ cset "name='RECMIX Mic1 Switch' 0" ++ cset "name='SPK Mux' 0" ++ cset "name='SPO Switch' 1" ++ cset "name='codec0_out mo codec0_in mi Switch' 0" ++ cset "name='codec0_out mo dmic01_hifi_in mi Switch' 0" ++ cset "name='codec0_out mo media0_in mi Switch' 1" ++ cset "name='codec1_out mo codec0_in mi Switch' 0" ++ cset "name='codec1_out mo dmic01_hifi_in mi Switch' 0" ++ cset "name='codec1_out mo media0_in mi Switch' 0" ++ cset "name='media0_out mo codec0_in mi Switch' 1" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" ++ cset "name='media0_out mo media0_in mi Switch' 0" ++] +-- +2.10.2 + diff --git a/0013-pcm_plug-Clear-plugins-on-all-error-conditions.patch b/0013-pcm_plug-Clear-plugins-on-all-error-conditions.patch new file mode 100644 index 0000000..26b5714 --- /dev/null +++ b/0013-pcm_plug-Clear-plugins-on-all-error-conditions.patch @@ -0,0 +1,34 @@ +From ced8722f7d98c946d1429e46252ccc061272d0db Mon Sep 17 00:00:00 2001 +From: Michael Forney +Date: Wed, 19 Oct 2016 18:22:56 -0700 +Subject: [PATCH] pcm_plug: Clear plugins on all error conditions + +Otherwise, they will linger after the error is returned (but pcm->setup == 0). +Then, if the caller tries to clean up and call snd_pcm_close(), the assertion +plug->gen.slave == plug->req_slave will fail. + +Signed-off-by: Michael Forney +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_plug.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c +index 5639b9ea8044..266707b425c1 100644 +--- a/src/pcm/pcm_plug.c ++++ b/src/pcm/pcm_plug.c +@@ -652,8 +652,10 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm, + (plug->ttable && !plug->ttable_ok)) { + snd_pcm_t *new; + int err; +- if (k >= sizeof(funcs)/sizeof(*funcs)) ++ if (k >= sizeof(funcs)/sizeof(*funcs)) { ++ snd_pcm_plug_clear(pcm); + return -EINVAL; ++ } + err = funcs[k](pcm, &new, client, &p); + if (err < 0) { + snd_pcm_plug_clear(pcm); +-- +2.10.2 + diff --git a/0014-mixer-Don-t-install-smixer-modules-unless-python-is-.patch b/0014-mixer-Don-t-install-smixer-modules-unless-python-is-.patch new file mode 100644 index 0000000..9ba53c4 --- /dev/null +++ b/0014-mixer-Don-t-install-smixer-modules-unless-python-is-.patch @@ -0,0 +1,47 @@ +From a668a94238dc67b19ae187b52a161e027d79ee5d Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 14 Nov 2016 11:46:05 +0100 +Subject: [PATCH] mixer: Don't install smixer modules unless python is enabled + +Currently the whole smixer stuff depends on python, so it doesn't make +sense to install plugins partially when the python support is +disabled. + +This patch changes Makefile.am not to install the smixer stuff at all +when the python support is disabled via configure script. + +Signed-off-by: Takashi Iwai +--- + modules/mixer/simple/Makefile.am | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/modules/mixer/simple/Makefile.am b/modules/mixer/simple/Makefile.am +index cb64ee8ca665..c21dd07d5180 100644 +--- a/modules/mixer/simple/Makefile.am ++++ b/modules/mixer/simple/Makefile.am +@@ -1,3 +1,4 @@ ++if BUILD_PYTHON + alsaplugindir = @ALSA_PLUGIN_DIR@ + pkglibdir = $(alsaplugindir)/smixer + +@@ -9,9 +10,7 @@ pkglib_LTLIBRARIES = smixer-sbase.la \ + smixer-ac97.la \ + smixer-hda.la + +-if BUILD_PYTHON + pkglib_LTLIBRARIES += smixer-python.la +-endif + + noinst_HEADERS = sbase.h + +@@ -27,7 +26,6 @@ smixer_hda_la_SOURCES = hda.c sbasedl.c + smixer_hda_la_LDFLAGS = -module -avoid-version $(LDFLAGS_NOUNDEFINED) + smixer_hda_la_LIBADD = ../../../src/libasound.la -ldl + +-if BUILD_PYTHON + smixer_python_la_SOURCES = python.c + smixer_python_la_LDFLAGS = -module -avoid-version $(LDFLAGS_NOUNDEFINED) + smixer_python_la_CFLAGS = $(PYTHON_INCLUDES) +-- +2.10.2 + diff --git a/0015-pcm_dshare-Do-not-discard-slave-reported-delay-in-st.patch b/0015-pcm_dshare-Do-not-discard-slave-reported-delay-in-st.patch new file mode 100644 index 0000000..dfc6904 --- /dev/null +++ b/0015-pcm_dshare-Do-not-discard-slave-reported-delay-in-st.patch @@ -0,0 +1,109 @@ +From faf53c197cabeb1eb0fd1f66cd001d1469ebac09 Mon Sep 17 00:00:00 2001 +From: Alan Young +Date: Wed, 2 Nov 2016 17:40:32 +0000 +Subject: [PATCH] pcm_dshare: Do not discard slave reported delay in status + result. + +snd_pcm_dshare_status() gets the underlying status from the slave PCM. +This may contain a delay value that includes elements such as codec and +other transfer delays. Use this as the base for the returned delay +value, adjusted for any frames buffered locally (within the dshare +plugin). + +Note: snd_pcm_dshare_delay() is not updated. + +Signed-off-by: Alan Young +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_dshare.c | 45 ++++++++++++++++++++++++++++----------------- + 1 file changed, 28 insertions(+), 17 deletions(-) + +diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c +index c5b3178a4990..9b478a714468 100644 +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -157,23 +157,14 @@ static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm) + /* + * synchronize hardware pointer (hw_ptr) with ours + */ +-static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) ++static int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr) + { + snd_pcm_direct_t *dshare = pcm->private_data; +- snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail; ++ snd_pcm_uframes_t old_slave_hw_ptr, avail; + snd_pcm_sframes_t diff; + +- switch (snd_pcm_state(dshare->spcm)) { +- case SND_PCM_STATE_DISCONNECTED: +- dshare->state = SNDRV_PCM_STATE_DISCONNECTED; +- return -ENODEV; +- default: +- break; +- } +- if (dshare->slowptr) +- snd_pcm_hwsync(dshare->spcm); + old_slave_hw_ptr = dshare->slave_hw_ptr; +- slave_hw_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr; ++ dshare->slave_hw_ptr = slave_hw_ptr; + diff = slave_hw_ptr - old_slave_hw_ptr; + if (diff == 0) /* fast path */ + return 0; +@@ -207,6 +198,24 @@ static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) + return 0; + } + ++static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) ++{ ++ snd_pcm_direct_t *dshare = pcm->private_data; ++ ++ switch (snd_pcm_state(dshare->spcm)) { ++ case SND_PCM_STATE_DISCONNECTED: ++ dshare->state = SNDRV_PCM_STATE_DISCONNECTED; ++ return -ENODEV; ++ default: ++ break; ++ } ++ ++ if (dshare->slowptr) ++ snd_pcm_hwsync(dshare->spcm); ++ ++ return snd_pcm_dshare_sync_ptr0(pcm, *dshare->spcm->hw.ptr); ++} ++ + /* + * plugin implementation + */ +@@ -215,22 +224,24 @@ static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + { + snd_pcm_direct_t *dshare = pcm->private_data; + ++ memset(status, 0, sizeof(*status)); ++ snd_pcm_status(dshare->spcm, status); ++ + switch (dshare->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: +- snd_pcm_dshare_sync_ptr(pcm); ++ snd_pcm_dshare_sync_ptr0(pcm, status->hw_ptr); ++ status->delay += snd_pcm_mmap_playback_delay(pcm) ++ + status->avail - dshare->spcm->buffer_size; + break; + default: + break; + } +- memset(status, 0, sizeof(*status)); +- snd_pcm_status(dshare->spcm, status); +- status->state = snd_pcm_state(dshare->spcm); ++ + status->trigger_tstamp = dshare->trigger_tstamp; + status->avail = snd_pcm_mmap_playback_avail(pcm); + status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max; + dshare->avail_max = 0; +- status->delay = snd_pcm_mmap_playback_delay(pcm); + return 0; + } + +-- +2.10.2 + diff --git a/0016-pcm-direct-Protect-from-freeing-semaphore-when-alrea.patch b/0016-pcm-direct-Protect-from-freeing-semaphore-when-alrea.patch new file mode 100644 index 0000000..4f47c4c --- /dev/null +++ b/0016-pcm-direct-Protect-from-freeing-semaphore-when-alrea.patch @@ -0,0 +1,82 @@ +From 2dd78251ff0c4009b478574cca7aef2eb05c2279 Mon Sep 17 00:00:00 2001 +From: Joshua Frkuska +Date: Fri, 25 Nov 2016 15:43:40 +0530 +Subject: [PATCH] pcm: direct: Protect from freeing semaphore when already in + use + +In the case of dshare, dsnoop, and dmix when a device is opened twice +and fails the second time, the semaphore is completely discarded. This +creates dangling semaphore data. + +This patch removes the possibility for the semaphore to be destroyed during +a typical open failure by first checking if the shared memory can be destroyed +or not. If the shared memory cannot be released it means both it and the +semaphore are still in use and therefore the semaphore is just released. + +Signed-off-by: Joshua Frkuska +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_dmix.c | 7 ++++--- + src/pcm/pcm_dshare.c | 7 ++++--- + src/pcm/pcm_dsnoop.c | 8 +++++--- + 3 files changed, 13 insertions(+), 9 deletions(-) + +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index 2714fb93c758..2fedb1c14a3b 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -1154,9 +1154,10 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_close(spcm); + if (dmix->u.dmix.shmid_sum >= 0) + shm_sum_discard(dmix); +- if (dmix->shmid >= 0) +- snd_pcm_direct_shm_discard(dmix); +- if (snd_pcm_direct_semaphore_discard(dmix) < 0) ++ if ((dmix->shmid >= 0) && (snd_pcm_direct_shm_discard(dmix))) { ++ if (snd_pcm_direct_semaphore_discard(dmix)) ++ snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT); ++ } else + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + _err_nosem: + if (dmix) { +diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c +index 9b478a714468..01f5eed8f97a 100644 +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -846,9 +846,10 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_direct_client_discard(dshare); + if (spcm) + snd_pcm_close(spcm); +- if (dshare->shmid >= 0) +- snd_pcm_direct_shm_discard(dshare); +- if (snd_pcm_direct_semaphore_discard(dshare) < 0) ++ if ((dshare->shmid >= 0) && (snd_pcm_direct_shm_discard(dshare))) { ++ if (snd_pcm_direct_semaphore_discard(dshare)) ++ snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT); ++ } else + snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); + _err_nosem: + if (dshare) { +diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c +index 4efbc53d177e..1aedf3cb73d2 100644 +--- a/src/pcm/pcm_dsnoop.c ++++ b/src/pcm/pcm_dsnoop.c +@@ -719,10 +719,12 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_direct_client_discard(dsnoop); + if (spcm) + snd_pcm_close(spcm); +- if (dsnoop->shmid >= 0) +- snd_pcm_direct_shm_discard(dsnoop); +- if (snd_pcm_direct_semaphore_discard(dsnoop) < 0) ++ if ((dsnoop->shmid >= 0) && (snd_pcm_direct_shm_discard(dsnoop))) { ++ if (snd_pcm_direct_semaphore_discard(dsnoop)) ++ snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT); ++ } else + snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); ++ + _err_nosem: + if (dsnoop) { + free(dsnoop->bindings); +-- +2.10.2 + diff --git a/0017-pcm-dshare-Fix-endless-playback-of-buffer.patch b/0017-pcm-dshare-Fix-endless-playback-of-buffer.patch new file mode 100644 index 0000000..ae4522a --- /dev/null +++ b/0017-pcm-dshare-Fix-endless-playback-of-buffer.patch @@ -0,0 +1,30 @@ +From 876563c824bdecbf771a0e7bda472b0a1c19d900 Mon Sep 17 00:00:00 2001 +From: Anant Agrawal +Date: Fri, 25 Nov 2016 16:43:34 +0530 +Subject: [PATCH] pcm: dshare: Fix endless playback of buffer + +On snd_pcm_drain() the slave PCM driven via plugin DSHARE is not filled with +silence. Result is endless playback of buffer content until pcm is closed. +In ALSA pcm dshare plugin, called do_silence method to fix the issue. + +Signed-off-by: Anant Agrawal +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_dshare.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c +index 01f5eed8f97a..29cd6c6da1d0 100644 +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -186,6 +186,7 @@ static int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_p + dshare->avail_max = avail; + if (avail >= pcm->stop_threshold) { + snd_timer_stop(dshare->timer); ++ do_silence(pcm); + gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type); + if (dshare->state == SND_PCM_STATE_RUNNING) { + dshare->state = SND_PCM_STATE_XRUN; +-- +2.10.2 + diff --git a/0018-pcm-Add-the-PCM-state-checks-to-plugins.patch b/0018-pcm-Add-the-PCM-state-checks-to-plugins.patch new file mode 100644 index 0000000..b4c87b8 --- /dev/null +++ b/0018-pcm-Add-the-PCM-state-checks-to-plugins.patch @@ -0,0 +1,220 @@ +From ea74ebbe4db81aeaedcff11bc5eb6ce139db1118 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 29 Nov 2016 14:31:20 +0100 +Subject: [PATCH] pcm: Add the PCM state checks to plugins + +I noticed that some plugin codes have no proper PCM state checks and +it results in expected outcomes. For example, when snd_pcm_drain() is +called for a dmix PCM after calling snd_pcm_drop(), it stalls +unexpectedly. It's just because its drain callback doesn't expect the +SND_PCM_SETUP state. + +We can fix such a bug in each place one by one, but a safer way would +be to filter out all such cases commonly in the PCM API functions +themselves. This patch adds the PCM state sanity checks to major API +functions so that they return -EBADFD when called in the unexpected +PCM states. + +As well as for the thread-safety extension, it'd be a question of the +performance; again at this time, the hw PCM is considered as an +exception, and it has pcm->own_state_check flag set, which means that +the common PCM state checks are skipped. + +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ + src/pcm/pcm_hw.c | 1 + + src/pcm/pcm_local.h | 1 + + 3 files changed, 50 insertions(+) + +diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c +index cd87bc759ded..f2ca02b55973 100644 +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -655,6 +655,23 @@ playback devices. + #include + #include "pcm_local.h" + ++#ifndef DOC_HIDDEN ++#define P_STATE(x) (1U << SND_PCM_STATE_ ## x) ++#define P_STATE_RUNNABLE (P_STATE(PREPARED) | \ ++ P_STATE(RUNNING) | \ ++ P_STATE(XRUN) | \ ++ P_STATE(PAUSED) | \ ++ P_STATE(DRAINING)) ++ ++/* check whether the PCM is in the unexpected state */ ++static int bad_pcm_state(snd_pcm_t *pcm, unsigned int supported_states) ++{ ++ if (pcm->own_state_check) ++ return 0; /* don't care, the plugin checks by itself */ ++ return !(supported_states & (1U << snd_pcm_state(pcm))); ++} ++#endif ++ + /** + * \brief get identifier of PCM handle + * \param pcm PCM handle +@@ -1120,6 +1137,8 @@ int snd_pcm_prepare(snd_pcm_t *pcm) + SNDMSG("PCM not set up"); + return -EIO; + } ++ if (bad_pcm_state(pcm, ~P_STATE(DISCONNECTED))) ++ return -EBADFD; + snd_pcm_lock(pcm); + err = pcm->fast_ops->prepare(pcm->fast_op_arg); + snd_pcm_unlock(pcm); +@@ -1166,6 +1185,8 @@ int snd_pcm_start(snd_pcm_t *pcm) + SNDMSG("PCM not set up"); + return -EIO; + } ++ if (bad_pcm_state(pcm, P_STATE(PREPARED))) ++ return -EBADFD; + snd_pcm_lock(pcm); + err = __snd_pcm_start(pcm); + snd_pcm_unlock(pcm); +@@ -1194,6 +1215,9 @@ int snd_pcm_drop(snd_pcm_t *pcm) + SNDMSG("PCM not set up"); + return -EIO; + } ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE | P_STATE(SETUP) | ++ P_STATE(SUSPENDED))) ++ return -EBADFD; + snd_pcm_lock(pcm); + err = pcm->fast_ops->drop(pcm->fast_op_arg); + snd_pcm_unlock(pcm); +@@ -1222,6 +1246,8 @@ int snd_pcm_drain(snd_pcm_t *pcm) + SNDMSG("PCM not set up"); + return -EIO; + } ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + /* lock handled in the callback */ + return pcm->fast_ops->drain(pcm->fast_op_arg); + } +@@ -1247,6 +1273,8 @@ int snd_pcm_pause(snd_pcm_t *pcm, int enable) + SNDMSG("PCM not set up"); + return -EIO; + } ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + snd_pcm_lock(pcm); + err = pcm->fast_ops->pause(pcm->fast_op_arg, enable); + snd_pcm_unlock(pcm); +@@ -1273,6 +1301,8 @@ snd_pcm_sframes_t snd_pcm_rewindable(snd_pcm_t *pcm) + SNDMSG("PCM not set up"); + return -EIO; + } ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + snd_pcm_lock(pcm); + result = pcm->fast_ops->rewindable(pcm->fast_op_arg); + snd_pcm_unlock(pcm); +@@ -1299,6 +1329,8 @@ snd_pcm_sframes_t snd_pcm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) + } + if (frames == 0) + return 0; ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + snd_pcm_lock(pcm); + result = pcm->fast_ops->rewind(pcm->fast_op_arg, frames); + snd_pcm_unlock(pcm); +@@ -1325,6 +1357,8 @@ snd_pcm_sframes_t snd_pcm_forwardable(snd_pcm_t *pcm) + SNDMSG("PCM not set up"); + return -EIO; + } ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + snd_pcm_lock(pcm); + result = pcm->fast_ops->forwardable(pcm->fast_op_arg); + snd_pcm_unlock(pcm); +@@ -1355,6 +1389,8 @@ snd_pcm_sframes_t snd_pcm_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) + } + if (frames == 0) + return 0; ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + snd_pcm_lock(pcm); + result = pcm->fast_ops->forward(pcm->fast_op_arg, frames); + snd_pcm_unlock(pcm); +@@ -1393,6 +1429,8 @@ snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_ufr + SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); + return -EINVAL; + } ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + return _snd_pcm_writei(pcm, buffer, size); + } + +@@ -1427,6 +1465,8 @@ snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t + SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); + return -EINVAL; + } ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + return _snd_pcm_writen(pcm, bufs, size); + } + +@@ -1461,6 +1501,8 @@ snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t + SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); + return -EINVAL; + } ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + return _snd_pcm_readi(pcm, buffer, size); + } + +@@ -1495,6 +1537,8 @@ snd_pcm_sframes_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t s + SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); + return -EINVAL; + } ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + return _snd_pcm_readn(pcm, bufs, size); + } + +@@ -6938,6 +6982,8 @@ int snd_pcm_mmap_begin(snd_pcm_t *pcm, + { + int err; + ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + snd_pcm_lock(pcm); + err = __snd_pcm_mmap_begin(pcm, areas, offset, frames); + snd_pcm_unlock(pcm); +@@ -7033,6 +7079,8 @@ snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm, + { + snd_pcm_sframes_t result; + ++ if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) ++ return -EBADFD; + snd_pcm_lock(pcm); + result = __snd_pcm_mmap_commit(pcm, offset, frames); + snd_pcm_unlock(pcm); +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 56e88b6bf6c0..30cd5d0f6503 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -1516,6 +1516,7 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, + #ifdef THREAD_SAFE_API + pcm->need_lock = 0; /* hw plugin is thread-safe */ + #endif ++ pcm->own_state_check = 1; /* skip the common state check */ + + ret = snd_pcm_hw_mmap_status(pcm); + if (ret < 0) { +diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h +index bba2f15ac463..32e6dcdf6fcd 100644 +--- a/src/pcm/pcm_local.h ++++ b/src/pcm/pcm_local.h +@@ -234,6 +234,7 @@ struct _snd_pcm { + * use the mmaped buffer of the slave + */ + unsigned int donot_close: 1; /* don't close this PCM */ ++ unsigned int own_state_check:1; /* plugin has own PCM state check */ + snd_pcm_channel_info_t *mmap_channels; + snd_pcm_channel_area_t *running_areas; + snd_pcm_channel_area_t *stopped_areas; +-- +2.10.2 + diff --git a/0019-pcm-dmix-Do-not-discard-slave-reported-delay-in-stat.patch b/0019-pcm-dmix-Do-not-discard-slave-reported-delay-in-stat.patch new file mode 100644 index 0000000..14fc9a3 --- /dev/null +++ b/0019-pcm-dmix-Do-not-discard-slave-reported-delay-in-stat.patch @@ -0,0 +1,103 @@ +From 38a2d2eda880fda9ed5a4a219db498d9c0856d71 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 29 Nov 2016 14:53:53 +0100 +Subject: [PATCH] pcm: dmix: Do not discard slave reported delay in status + result + +Like the change done for dshare plugin, we can calculate the delay +more precisely from the slave PCM. + +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_dmix.c | 45 ++++++++++++++++++++++++++++----------------- + 1 file changed, 28 insertions(+), 17 deletions(-) + +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index 2fedb1c14a3b..825677ffeb3f 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -391,23 +391,14 @@ static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm) + /* + * synchronize hardware pointer (hw_ptr) with ours + */ +-static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) ++static int snd_pcm_dmix_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr) + { + snd_pcm_direct_t *dmix = pcm->private_data; +- snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail; ++ snd_pcm_uframes_t old_slave_hw_ptr, avail; + snd_pcm_sframes_t diff; + +- switch (snd_pcm_state(dmix->spcm)) { +- case SND_PCM_STATE_DISCONNECTED: +- dmix->state = SND_PCM_STATE_DISCONNECTED; +- return -ENODEV; +- default: +- break; +- } +- if (dmix->slowptr) +- snd_pcm_hwsync(dmix->spcm); + old_slave_hw_ptr = dmix->slave_hw_ptr; +- slave_hw_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr; ++ dmix->slave_hw_ptr = *dmix->spcm->hw.ptr; + diff = slave_hw_ptr - old_slave_hw_ptr; + if (diff == 0) /* fast path */ + return 0; +@@ -440,6 +431,24 @@ static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) + return 0; + } + ++static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) ++{ ++ snd_pcm_direct_t *dmix = pcm->private_data; ++ ++ switch (snd_pcm_state(dmix->spcm)) { ++ case SND_PCM_STATE_DISCONNECTED: ++ dmix->state = SND_PCM_STATE_DISCONNECTED; ++ return -ENODEV; ++ default: ++ break; ++ } ++ ++ if (dmix->slowptr) ++ snd_pcm_hwsync(dmix->spcm); ++ ++ return snd_pcm_dmix_sync_ptr0(pcm, *dmix->spcm->hw.ptr); ++} ++ + /* + * plugin implementation + */ +@@ -467,22 +476,24 @@ static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + { + snd_pcm_direct_t *dmix = pcm->private_data; + ++ memset(status, 0, sizeof(*status)); ++ snd_pcm_status(dmix->spcm, status); ++ + switch (dmix->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: +- snd_pcm_dmix_sync_ptr(pcm); ++ snd_pcm_dmix_sync_ptr0(pcm, status->hw_ptr); ++ status->delay += snd_pcm_mmap_playback_delay(pcm) ++ + status->avail - dmix->spcm->buffer_size; + break; + default: + break; + } +- memset(status, 0, sizeof(*status)); +- snd_pcm_status(dmix->spcm, status); +- status->state = snd_pcm_dmix_state(pcm); ++ + status->trigger_tstamp = dmix->trigger_tstamp; + status->avail = snd_pcm_mmap_playback_avail(pcm); + status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max; + dmix->avail_max = 0; +- status->delay = snd_pcm_mmap_playback_delay(pcm); + return 0; + } + +-- +2.10.2 + diff --git a/alsa.changes b/alsa.changes index 8f2e613..b598937 100644 --- a/alsa.changes +++ b/alsa.changes @@ -1,3 +1,41 @@ +------------------------------------------------------------------- +Tue Nov 29 15:01:05 CET 2016 - tiwai@suse.de + +- Backport upstream fixes (bsc#1012594): + - A few PCM bugs have been fixed: + * Stall of dmix and others in a wrong PCM state + * Refactoring of PCM locking scheme + * SHM initialization race fix + * plug PCM memory leaks + * Improvement of dshare/dmix delay calculation + * Fix endless dshare draining + * Fix semaphore discard race fix of direct plugins + - UCM fixes and updates for DB410c and skylake-r5286 + - Mixer code cleanup not to install bogus plugin codes + - Documentation fixes / updates + + 0001-ucm-Add-ucm-files-for-DB410c-board.patch + 0002-mixer-Fix-rounding-mode-documentation.patch + 0003-pcm-Fix-shm-initialization-race-condition.patch + 0004-pcm-Better-understandable-locking-code.patch + 0005-ucm-fix-crash-when-calling-snd_use_case_geti-with-no.patch + 0006-ucm-docs-typeset-lists-of-identifiers-explicitly.patch + 0007-Update-include-sound-tlv.h-from-4.9-pre-kernel-uapi.patch + 0008-test-use-actual-information-for-TLV-operation.patch + 0009-ctl-improve-API-documentation-for-TLV-operation.patch + 0010-ctl-improve-documentation-about-TLV-related-APIs.patch + 0011-ctl-correct-documentation-about-TLV-feature.patch + 0012-conf-ucm-skylake-add-skylake-rt286-conf-files.patch + 0013-pcm_plug-Clear-plugins-on-all-error-conditions.patch + 0014-mixer-Don-t-install-smixer-modules-unless-python-is-.patch + 0015-pcm_dshare-Do-not-discard-slave-reported-delay-in-st.patch + 0016-pcm-direct-Protect-from-freeing-semaphore-when-alrea.patch + 0017-pcm-dshare-Fix-endless-playback-of-buffer.patch + 0018-pcm-Add-the-PCM-state-checks-to-plugins.patch + 0019-pcm-dmix-Do-not-discard-slave-reported-delay-in-stat.patch + +- smixer module files got removed from the file list as well + ------------------------------------------------------------------- Wed Aug 3 11:22:16 CEST 2016 - tiwai@suse.de diff --git a/alsa.spec b/alsa.spec index 98f3500..49764a1 100644 --- a/alsa.spec +++ b/alsa.spec @@ -48,6 +48,25 @@ Source40: 50-alsa.conf Source41: install-snd-module # Patch: alsa-lib-git-fixes.diff # upstream fixes +Patch1: 0001-ucm-Add-ucm-files-for-DB410c-board.patch +Patch2: 0002-mixer-Fix-rounding-mode-documentation.patch +Patch3: 0003-pcm-Fix-shm-initialization-race-condition.patch +Patch4: 0004-pcm-Better-understandable-locking-code.patch +Patch5: 0005-ucm-fix-crash-when-calling-snd_use_case_geti-with-no.patch +Patch6: 0006-ucm-docs-typeset-lists-of-identifiers-explicitly.patch +Patch7: 0007-Update-include-sound-tlv.h-from-4.9-pre-kernel-uapi.patch +Patch8: 0008-test-use-actual-information-for-TLV-operation.patch +Patch9: 0009-ctl-improve-API-documentation-for-TLV-operation.patch +Patch10: 0010-ctl-improve-documentation-about-TLV-related-APIs.patch +Patch11: 0011-ctl-correct-documentation-about-TLV-feature.patch +Patch12: 0012-conf-ucm-skylake-add-skylake-rt286-conf-files.patch +Patch13: 0013-pcm_plug-Clear-plugins-on-all-error-conditions.patch +Patch14: 0014-mixer-Don-t-install-smixer-modules-unless-python-is-.patch +Patch15: 0015-pcm_dshare-Do-not-discard-slave-reported-delay-in-st.patch +Patch16: 0016-pcm-direct-Protect-from-freeing-semaphore-when-alrea.patch +Patch17: 0017-pcm-dshare-Fix-endless-playback-of-buffer.patch +Patch18: 0018-pcm-Add-the-PCM-state-checks-to-plugins.patch +Patch19: 0019-pcm-dmix-Do-not-discard-slave-reported-delay-in-stat.patch # rest suse patches Patch99: alsa-lib-doxygen-avoid-crash-for-11.3.diff BuildRequires: doxygen @@ -116,6 +135,25 @@ Architecture. %prep %setup -q -n alsa-lib-%{package_version} # %patch -p1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 %if 0%{?suse_version} == 1130 %patch99 -p1 %endif @@ -146,7 +184,7 @@ make -C doc doc %{?_smp_mflags} make DESTDIR=%{buildroot} install %{?_smp_mflags} # clean up unneeded files rm -f %{buildroot}%{_libdir}/*.*a -rm -f %{buildroot}%{_libdir}/alsa-lib/smixer/*.*a +# rm -f %{buildroot}%{_libdir}/alsa-lib/smixer/*.*a rm -f %{buildroot}%{_bindir}/aserver # # install helper scripts @@ -274,7 +312,6 @@ exit 0 %files -n libasound2 %defattr(-, root, root) %{_libdir}/libasound.so.* -%{_libdir}/alsa-lib %{_datadir}/alsa %changelog