Accepting request 320497 from multimedia:libs
1 OBS-URL: https://build.opensuse.org/request/show/320497 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/alsa?expand=0&rev=163
This commit is contained in:
commit
ec58dcef52
@ -0,0 +1,63 @@
|
||||
From bbe9248e6788e7a852af15f2110dbaeace4d1907 Mon Sep 17 00:00:00 2001
|
||||
From: David Henningsson <david.henningsson@canonical.com>
|
||||
Date: Thu, 18 Jun 2015 10:47:59 +0200
|
||||
Subject: [PATCH] surround41/50.conf: Use chmap syntax for better flexibility
|
||||
|
||||
In case the hardware only supports a specific channel map,
|
||||
this change would allow surround41/50 to select the correct
|
||||
channel map and channel count in this situation.
|
||||
|
||||
Signed-off-by: David Henningsson <david.henningsson@canonical.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/conf/pcm/surround41.conf | 11 +++++------
|
||||
src/conf/pcm/surround50.conf | 11 +++++------
|
||||
2 files changed, 10 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/src/conf/pcm/surround41.conf b/src/conf/pcm/surround41.conf
|
||||
index 10e486e21528..2f823815821a 100644
|
||||
--- a/src/conf/pcm/surround41.conf
|
||||
+++ b/src/conf/pcm/surround41.conf
|
||||
@@ -53,12 +53,11 @@ pcm.!surround41 {
|
||||
]
|
||||
}
|
||||
}
|
||||
- slave.channels 6
|
||||
- ttable.0.0 1
|
||||
- ttable.1.1 1
|
||||
- ttable.2.2 1
|
||||
- ttable.3.3 1
|
||||
- ttable.4.5 1
|
||||
+ ttable.0.FL 1
|
||||
+ ttable.1.FR 1
|
||||
+ ttable.2.RL 1
|
||||
+ ttable.3.RR 1
|
||||
+ ttable.4.LFE 1
|
||||
hint {
|
||||
description "4.1 Surround output to Front, Rear and Subwoofer speakers"
|
||||
device $DEV
|
||||
diff --git a/src/conf/pcm/surround50.conf b/src/conf/pcm/surround50.conf
|
||||
index 7b7b17e10246..dc95c179da68 100644
|
||||
--- a/src/conf/pcm/surround50.conf
|
||||
+++ b/src/conf/pcm/surround50.conf
|
||||
@@ -53,12 +53,11 @@ pcm.!surround50 {
|
||||
]
|
||||
}
|
||||
}
|
||||
- slave.channels 6
|
||||
- ttable.0.0 1
|
||||
- ttable.1.1 1
|
||||
- ttable.2.2 1
|
||||
- ttable.3.3 1
|
||||
- ttable.4.4 1
|
||||
+ ttable.0.FL 1
|
||||
+ ttable.1.FR 1
|
||||
+ ttable.2.RL 1
|
||||
+ ttable.3.RR 1
|
||||
+ ttable.4.FC 1
|
||||
hint {
|
||||
description "5.0 Surround output to Front, Center and Rear speakers"
|
||||
device $DEV
|
||||
--
|
||||
2.5.0
|
||||
|
@ -0,0 +1,28 @@
|
||||
From f66c7cc293b13765ffd67f530008e836f8354b13 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Mon, 29 Jun 2015 16:25:57 +0100
|
||||
Subject: [PATCH 24/49] ucm: docs: fix doxygen exclude patch for UCM local
|
||||
header
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
doc/doxygen.cfg.in | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in
|
||||
index f4499d610290..043e75b2d7eb 100644
|
||||
--- a/doc/doxygen.cfg.in
|
||||
+++ b/doc/doxygen.cfg.in
|
||||
@@ -94,7 +94,7 @@ EXCLUDE = @top_srcdir@/src/control/control_local.h \
|
||||
@top_srcdir@/src/mixer/mixer_local.h \
|
||||
@top_srcdir@/src/rawmidi/rawmidi_local.h \
|
||||
@top_srcdir@/src/seq/seq_local.h \
|
||||
- @top_srcdir@/src/seq/ucm_local.h
|
||||
+ @top_srcdir@/src/ucm/ucm_local.h
|
||||
RECURSIVE = YES
|
||||
FILE_PATTERNS = *.c *.h
|
||||
EXAMPLE_PATH = @top_srcdir@/test
|
||||
--
|
||||
2.5.0
|
||||
|
69
0025-ucm-docs-Fix-doxygen-formatting-for-UCM-main-page.patch
Normal file
69
0025-ucm-docs-Fix-doxygen-formatting-for-UCM-main-page.patch
Normal file
@ -0,0 +1,69 @@
|
||||
From bb92545e064c3e2549878a328277eebe343aae61 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Mon, 29 Jun 2015 16:25:58 +0100
|
||||
Subject: [PATCH 25/49] ucm: docs: Fix doxygen formatting for UCM main page.
|
||||
|
||||
Make sure group is defined and lists dipplayed correctly.
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
include/use-case.h | 20 +++++++++-----------
|
||||
1 file changed, 9 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/include/use-case.h b/include/use-case.h
|
||||
index c7789c03c4e8..9aac6e2fb51d 100644
|
||||
--- a/include/use-case.h
|
||||
+++ b/include/use-case.h
|
||||
@@ -43,15 +43,13 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
- * \defgroup Use Case Interface
|
||||
+ * \defgroup ucm Use Case Interface
|
||||
* The ALSA Use Case manager interface.
|
||||
* See \ref Usecase page for more details.
|
||||
* \{
|
||||
*/
|
||||
|
||||
/*! \page Usecase ALSA Use Case Interface
|
||||
- *
|
||||
- * ALSA Use Case Interface
|
||||
*
|
||||
* The use case manager works by configuring the sound card ALSA kcontrols to
|
||||
* change the hardware digital and analog audio routing to match the requested
|
||||
@@ -69,9 +67,9 @@ extern "C" {
|
||||
*
|
||||
* However there are times when a use case has to be modified at runtime. e.g.
|
||||
*
|
||||
- * o Incoming phone call when the device is playing music
|
||||
- * o Recording sections of a phone call
|
||||
- * o Playing tones during a call.
|
||||
+ * + Incoming phone call when the device is playing music
|
||||
+ * + Recording sections of a phone call
|
||||
+ * + Playing tones during a call.
|
||||
*
|
||||
* In order to allow asynchronous runtime use case adaptations, we have a third
|
||||
* optional modifier parameter that can be used to further configure
|
||||
@@ -79,13 +77,13 @@ extern "C" {
|
||||
*
|
||||
* This interface allows clients to :-
|
||||
*
|
||||
- * o Query the supported use case verbs, devices and modifiers for the machine.
|
||||
- * o Set and Get use case verbs, devices and modifiers for the machine.
|
||||
- * o Get the ALSA PCM playback and capture device PCMs for use case verb,
|
||||
+ * + Query the supported use case verbs, devices and modifiers for the machine.
|
||||
+ * + Set and Get use case verbs, devices and modifiers for the machine.
|
||||
+ * + Get the ALSA PCM playback and capture device PCMs for use case verb,
|
||||
* use case device and modifier.
|
||||
- * o Get the TQ parameter for each use case verb, use case device and
|
||||
+ * + Get the TQ parameter for each use case verb, use case device and
|
||||
* modifier.
|
||||
- * o Get the ALSA master playback and capture volume/switch kcontrols
|
||||
+ * + Get the ALSA master playback and capture volume/switch kcontrols
|
||||
* for each use case.
|
||||
*/
|
||||
|
||||
--
|
||||
2.5.0
|
||||
|
26
0026-docs-Add-UCM-link-to-main-doxygen-page.patch
Normal file
26
0026-docs-Add-UCM-link-to-main-doxygen-page.patch
Normal file
@ -0,0 +1,26 @@
|
||||
From c6df8273746645b2c5109537b07af6ed33d268d1 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Mon, 29 Jun 2015 16:25:59 +0100
|
||||
Subject: [PATCH 26/49] docs: Add UCM link to main doxygen page.
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
doc/index.doxygen | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/doc/index.doxygen b/doc/index.doxygen
|
||||
index 45aa68a11caa..7d049fe5c32a 100644
|
||||
--- a/doc/index.doxygen
|
||||
+++ b/doc/index.doxygen
|
||||
@@ -40,6 +40,7 @@ may be placed in the library code instead of the kernel driver.</P>
|
||||
<LI>Page \ref rawmidi explains the design of the RawMidi API.
|
||||
<LI>Page \ref timer explains the design of the Timer API.
|
||||
<LI>Page \ref seq explains the design of the Sequencer API.
|
||||
+ <LI>Page \ref ucm explains the use case API.
|
||||
</UL>
|
||||
|
||||
<H2>Configuration</H2>
|
||||
--
|
||||
2.5.0
|
||||
|
105
0027-Replace-unsafe-characters-with-_-in-card-name.patch
Normal file
105
0027-Replace-unsafe-characters-with-_-in-card-name.patch
Normal file
@ -0,0 +1,105 @@
|
||||
From 4dc44bb34aab2b23ab45c8e61e4b17bf2cf58959 Mon Sep 17 00:00:00 2001
|
||||
From: "Alexander E. Patrakov" <patrakov@gmail.com>
|
||||
Date: Mon, 29 Jun 2015 22:53:53 +0500
|
||||
Subject: [PATCH 27/49] Replace unsafe characters with _ in card name
|
||||
|
||||
Otherwise, they get misinterpreted as argument separators
|
||||
in USB-Audio PCM definitions, and thus prevent SPDIF blacklist entries
|
||||
from working.
|
||||
|
||||
While at it, add my Logitec C910 webcam to the SPDIF blacklist.
|
||||
|
||||
Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
include/conf.h | 1 +
|
||||
src/conf.c | 32 ++++++++++++++++++++++++++++++++
|
||||
src/conf/cards/USB-Audio.conf | 3 ++-
|
||||
src/confmisc.c | 2 +-
|
||||
4 files changed, 36 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/include/conf.h b/include/conf.h
|
||||
index ff270f617383..087c05dc6bcf 100644
|
||||
--- a/include/conf.h
|
||||
+++ b/include/conf.h
|
||||
@@ -126,6 +126,7 @@ int snd_config_imake_integer(snd_config_t **config, const char *key, const long
|
||||
int snd_config_imake_integer64(snd_config_t **config, const char *key, const long long value);
|
||||
int snd_config_imake_real(snd_config_t **config, const char *key, const double value);
|
||||
int snd_config_imake_string(snd_config_t **config, const char *key, const char *ascii);
|
||||
+int snd_config_imake_safe_string(snd_config_t **config, const char *key, const char *ascii);
|
||||
int snd_config_imake_pointer(snd_config_t **config, const char *key, const void *ptr);
|
||||
|
||||
snd_config_type_t snd_config_get_type(const snd_config_t *config);
|
||||
diff --git a/src/conf.c b/src/conf.c
|
||||
index bb256e7ae443..c6a83eef7d2f 100644
|
||||
--- a/src/conf.c
|
||||
+++ b/src/conf.c
|
||||
@@ -2228,6 +2228,38 @@ int snd_config_imake_string(snd_config_t **config, const char *id, const char *v
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int snd_config_imake_safe_string(snd_config_t **config, const char *id, const char *value)
|
||||
+{
|
||||
+ int err;
|
||||
+ snd_config_t *tmp;
|
||||
+ char *c;
|
||||
+
|
||||
+ err = snd_config_make(&tmp, id, SND_CONFIG_TYPE_STRING);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ if (value) {
|
||||
+ tmp->u.string = strdup(value);
|
||||
+ if (!tmp->u.string) {
|
||||
+ snd_config_delete(tmp);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ for (c = tmp->u.string; *c; c++) {
|
||||
+ if (*c == ' ' || *c == '-' || *c == '_' ||
|
||||
+ (*c >= '0' && *c <= '9') ||
|
||||
+ (*c >= 'a' && *c <= 'z') ||
|
||||
+ (*c >= 'A' && *c <= 'Z'))
|
||||
+ continue;
|
||||
+ *c = '_';
|
||||
+ }
|
||||
+ } else {
|
||||
+ tmp->u.string = NULL;
|
||||
+ }
|
||||
+ *config = tmp;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/**
|
||||
* \brief Creates a pointer configuration node with the given initial value.
|
||||
* \param[out] config The function puts the handle to the new node at
|
||||
diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf
|
||||
index 031bee0d86fd..e365f2979e6a 100644
|
||||
--- a/src/conf/cards/USB-Audio.conf
|
||||
+++ b/src/conf/cards/USB-Audio.conf
|
||||
@@ -57,7 +57,8 @@ USB-Audio.pcm.iec958_device {
|
||||
"Scarlett 2i4 USB" 999
|
||||
"Sennheiser USB headset" 999
|
||||
"SWTOR Gaming Headset by Razer" 999
|
||||
- "USB Device 0x46d:0x992" 999
|
||||
+ "USB Device 0x46d_0x821" 999
|
||||
+ "USB Device 0x46d_0x992" 999
|
||||
}
|
||||
|
||||
# Second iec958 device number, if any.
|
||||
diff --git a/src/confmisc.c b/src/confmisc.c
|
||||
index 1fb4f282217e..ae0275ff4de3 100644
|
||||
--- a/src/confmisc.c
|
||||
+++ b/src/confmisc.c
|
||||
@@ -935,7 +935,7 @@ int snd_func_card_name(snd_config_t **dst, snd_config_t *root,
|
||||
}
|
||||
err = snd_config_get_id(src, &id);
|
||||
if (err >= 0)
|
||||
- err = snd_config_imake_string(dst, id,
|
||||
+ err = snd_config_imake_safe_string(dst, id,
|
||||
snd_ctl_card_info_get_name(info));
|
||||
__error:
|
||||
if (ctl)
|
||||
--
|
||||
2.5.0
|
||||
|
@ -0,0 +1,84 @@
|
||||
From 6cb31b444442f8ebca939cd78b80993f2ac85350 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Date: Wed, 1 Jul 2015 15:40:54 -0500
|
||||
Subject: [PATCH 28/49] pcm: add helper functions to query timestamping
|
||||
capabilities
|
||||
|
||||
extend support to link, link_estimated and link_synchronized
|
||||
timestamp. wall-clock is deprecated
|
||||
|
||||
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
include/pcm.h | 3 ++-
|
||||
src/pcm/pcm.c | 35 ++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 36 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/include/pcm.h b/include/pcm.h
|
||||
index 0655e7f43ef6..2aa1eff36be3 100644
|
||||
--- a/include/pcm.h
|
||||
+++ b/include/pcm.h
|
||||
@@ -668,7 +668,8 @@ int snd_pcm_hw_params_is_half_duplex(const snd_pcm_hw_params_t *params);
|
||||
int snd_pcm_hw_params_is_joint_duplex(const snd_pcm_hw_params_t *params);
|
||||
int snd_pcm_hw_params_can_sync_start(const snd_pcm_hw_params_t *params);
|
||||
int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *params);
|
||||
-int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params);
|
||||
+int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params); /* deprecated, use audio_ts_type */
|
||||
+int snd_pcm_hw_params_supports_audio_ts_type(const snd_pcm_hw_params_t *params, int type);
|
||||
int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params,
|
||||
unsigned int *rate_num,
|
||||
unsigned int *rate_den);
|
||||
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
|
||||
index bc18954b92da..846d502a6cb1 100644
|
||||
--- a/src/pcm/pcm.c
|
||||
+++ b/src/pcm/pcm.c
|
||||
@@ -3190,12 +3190,45 @@ int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *param
|
||||
*/
|
||||
int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params)
|
||||
{
|
||||
+ /* deprecated */
|
||||
+ return snd_pcm_hw_params_supports_audio_ts_type(params,
|
||||
+ SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * \brief Check if hardware supports type of audio timestamps
|
||||
+ * \param params Configuration space
|
||||
+ * \param type Audio timestamp type
|
||||
+ * \retval 0 Hardware doesn't support type of audio timestamps
|
||||
+ * \retval 1 Hardware supports type of audio timestamps
|
||||
+ *
|
||||
+ * This function should only be called when the configuration space
|
||||
+ * contains a single configuration. Call #snd_pcm_hw_params to choose
|
||||
+ * a single configuration from the configuration space.
|
||||
+ */
|
||||
+int snd_pcm_hw_params_supports_audio_ts_type(const snd_pcm_hw_params_t *params, int type)
|
||||
+{
|
||||
assert(params);
|
||||
if (CHECK_SANITY(params->info == ~0U)) {
|
||||
SNDMSG("invalid PCM info field");
|
||||
return 0; /* FIXME: should be a negative error? */
|
||||
}
|
||||
- return !!(params->info & SNDRV_PCM_INFO_HAS_WALL_CLOCK);
|
||||
+ switch (type) {
|
||||
+ case SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT:
|
||||
+ return !!(params->info & SNDRV_PCM_INFO_HAS_WALL_CLOCK); /* deprecated */
|
||||
+ case SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT:
|
||||
+ return 1; /* always supported, based on hw_ptr */
|
||||
+ case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK:
|
||||
+ return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_ATIME);
|
||||
+ case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE:
|
||||
+ return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME);
|
||||
+ case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED:
|
||||
+ return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME);
|
||||
+ case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED:
|
||||
+ return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME);
|
||||
+ default:
|
||||
+ return 0;
|
||||
+ }
|
||||
}
|
||||
|
||||
/**
|
||||
--
|
||||
2.5.0
|
||||
|
129
0029-pcm-add-support-for-get-set_audio_htstamp_config.patch
Normal file
129
0029-pcm-add-support-for-get-set_audio_htstamp_config.patch
Normal file
@ -0,0 +1,129 @@
|
||||
From 6ec2464f397ff401c251057499abea77fd80b60b Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Date: Wed, 1 Jul 2015 15:40:55 -0500
|
||||
Subject: [PATCH 29/49] pcm: add support for get/set_audio_htstamp_config
|
||||
|
||||
Enable kernel-side functionality by letting user select what sort of
|
||||
timestamp it desires
|
||||
|
||||
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
include/pcm.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
src/pcm/pcm.c | 38 ++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 82 insertions(+)
|
||||
|
||||
diff --git a/include/pcm.h b/include/pcm.h
|
||||
index 2aa1eff36be3..a1d14a989a47 100644
|
||||
--- a/include/pcm.h
|
||||
+++ b/include/pcm.h
|
||||
@@ -330,6 +330,26 @@ typedef enum _snd_pcm_tstamp_type {
|
||||
SND_PCM_TSTAMP_TYPE_LAST = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW,
|
||||
} snd_pcm_tstamp_type_t;
|
||||
|
||||
+typedef struct _snd_pcm_audio_tstamp_config {
|
||||
+ /* 5 of max 16 bits used */
|
||||
+ unsigned int type_requested:4;
|
||||
+ unsigned int report_delay:1; /* add total delay to A/D or D/A */
|
||||
+} snd_pcm_audio_tstamp_config_t;
|
||||
+
|
||||
+typedef struct _snd_pcm_audio_tstamp_report {
|
||||
+ /* 6 of max 16 bits used for bit-fields */
|
||||
+
|
||||
+ /* for backwards compatibility */
|
||||
+ unsigned int valid:1;
|
||||
+
|
||||
+ /* actual type if hardware could not support requested timestamp */
|
||||
+ unsigned int actual_type:4;
|
||||
+
|
||||
+ /* accuracy represented in ns units */
|
||||
+ unsigned int accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */
|
||||
+ unsigned int accuracy; /* up to 4.29s, will be packed in separate field */
|
||||
+} snd_pcm_audio_tstamp_report_t;
|
||||
+
|
||||
/** Unsigned frames quantity */
|
||||
typedef unsigned long snd_pcm_uframes_t;
|
||||
/** Signed frames quantity */
|
||||
@@ -981,6 +1001,30 @@ void snd_pcm_status_get_trigger_htstamp(const snd_pcm_status_t *obj, snd_htimest
|
||||
void snd_pcm_status_get_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t *ptr);
|
||||
void snd_pcm_status_get_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr);
|
||||
void snd_pcm_status_get_audio_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr);
|
||||
+void snd_pcm_status_get_driver_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr);
|
||||
+void snd_pcm_status_get_audio_htstamp_report(const snd_pcm_status_t *obj,
|
||||
+ snd_pcm_audio_tstamp_report_t *audio_tstamp_report);
|
||||
+void snd_pcm_status_set_audio_htstamp_config(snd_pcm_status_t *obj,
|
||||
+ snd_pcm_audio_tstamp_config_t *audio_tstamp_config);
|
||||
+
|
||||
+static inline void snd_pcm_pack_audio_tstamp_config(unsigned int *data,
|
||||
+ snd_pcm_audio_tstamp_config_t *config)
|
||||
+{
|
||||
+ *data = config->report_delay;
|
||||
+ *data <<= 4;
|
||||
+ *data |= config->type_requested;
|
||||
+}
|
||||
+
|
||||
+static inline void snd_pcm_unpack_audio_tstamp_report(unsigned int data, unsigned int accuracy,
|
||||
+ snd_pcm_audio_tstamp_report_t *report)
|
||||
+{
|
||||
+ data >>= 16;
|
||||
+ report->valid = data & 1;
|
||||
+ report->actual_type = (data >> 1) & 0xF;
|
||||
+ report->accuracy_report = (data >> 5) & 1;
|
||||
+ report->accuracy = accuracy;
|
||||
+}
|
||||
+
|
||||
snd_pcm_sframes_t snd_pcm_status_get_delay(const snd_pcm_status_t *obj);
|
||||
snd_pcm_uframes_t snd_pcm_status_get_avail(const snd_pcm_status_t *obj);
|
||||
snd_pcm_uframes_t snd_pcm_status_get_avail_max(const snd_pcm_status_t *obj);
|
||||
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
|
||||
index 846d502a6cb1..bae1d1653904 100644
|
||||
--- a/src/pcm/pcm.c
|
||||
+++ b/src/pcm/pcm.c
|
||||
@@ -6367,6 +6367,44 @@ void snd_pcm_status_get_audio_htstamp(const snd_pcm_status_t *obj, snd_htimestam
|
||||
}
|
||||
|
||||
/**
|
||||
+ * \brief Get "now" hi-res driver timestamp from a PCM status container. Defines when the status
|
||||
+ * was generated by driver, may differ from normal timestamp.
|
||||
+ * \param obj pointer to #snd_pcm_status_t
|
||||
+ * \param ptr Pointer to returned timestamp
|
||||
+ */
|
||||
+void snd_pcm_status_get_driver_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr)
|
||||
+{
|
||||
+ assert(obj && ptr);
|
||||
+ *ptr = obj->driver_tstamp;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * \brief Get audio_tstamp_report from a PCM status container
|
||||
+ * \param obj pointer to #snd_pcm_status_t
|
||||
+ * \param ptr Pointer to returned report (valid fields are accuracy and type)
|
||||
+ */
|
||||
+void snd_pcm_status_get_audio_htstamp_report(const snd_pcm_status_t *obj,
|
||||
+ snd_pcm_audio_tstamp_report_t *audio_tstamp_report)
|
||||
+{
|
||||
+ assert(obj && audio_tstamp_report);
|
||||
+ snd_pcm_unpack_audio_tstamp_report(obj->audio_tstamp_data,
|
||||
+ obj->audio_tstamp_accuracy,
|
||||
+ audio_tstamp_report);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * \brief set audio_tstamp_config from a PCM status container
|
||||
+ * \param obj pointer to #snd_pcm_status_t
|
||||
+ * \param ptr Pointer to config (valid fields are type and report_analog_delay)
|
||||
+ */
|
||||
+void snd_pcm_status_set_audio_htstamp_config(snd_pcm_status_t *obj,
|
||||
+ snd_pcm_audio_tstamp_config_t *audio_tstamp_config)
|
||||
+{
|
||||
+ assert(obj && audio_tstamp_config);
|
||||
+ snd_pcm_pack_audio_tstamp_config(&obj->audio_tstamp_data, audio_tstamp_config);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* \brief Get delay from a PCM status container (see #snd_pcm_delay)
|
||||
* \return Delay in frames
|
||||
*
|
||||
--
|
||||
2.5.0
|
||||
|
45
0030-pcm-add-support-for-new-STATUS_EXT-ioctl.patch
Normal file
45
0030-pcm-add-support-for-new-STATUS_EXT-ioctl.patch
Normal file
@ -0,0 +1,45 @@
|
||||
From cc8b73436a90c35beda64bfa13b2196df20cfd81 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Date: Wed, 1 Jul 2015 15:40:56 -0500
|
||||
Subject: [PATCH 30/49] pcm: add support for new STATUS_EXT ioctl
|
||||
|
||||
use STATUS_EXT ioctl if PCM protocol is > 2.0.12
|
||||
All audio timestamp configuration will be ignored with an
|
||||
older protocol.
|
||||
|
||||
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/pcm/pcm_hw.c | 16 ++++++++++++----
|
||||
1 file changed, 12 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
|
||||
index c34b766ee035..232b19736db9 100644
|
||||
--- a/src/pcm/pcm_hw.c
|
||||
+++ b/src/pcm/pcm_hw.c
|
||||
@@ -510,10 +510,18 @@ static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private_data;
|
||||
int fd = hw->fd, err;
|
||||
- if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) {
|
||||
- err = -errno;
|
||||
- SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err);
|
||||
- return err;
|
||||
+ if (SNDRV_PROTOCOL_VERSION(2, 0, 13) > hw->version) {
|
||||
+ if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) {
|
||||
+ err = -errno;
|
||||
+ SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS_EXT, status) < 0) {
|
||||
+ err = -errno;
|
||||
+ SYSMSG("SNDRV_PCM_IOCTL_STATUS_EXT failed (%i)", err);
|
||||
+ return err;
|
||||
+ }
|
||||
}
|
||||
if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) {
|
||||
status->tstamp.tv_nsec *= 1000L;
|
||||
--
|
||||
2.5.0
|
||||
|
596
0031-test-fix-audio_time-with-new-get-set-audio_tstamp_co.patch
Normal file
596
0031-test-fix-audio_time-with-new-get-set-audio_tstamp_co.patch
Normal file
@ -0,0 +1,596 @@
|
||||
From 7bb3a74c4dbcfb01b0b91d94452d994b845b4ff3 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Date: Wed, 1 Jul 2015 15:40:57 -0500
|
||||
Subject: [PATCH 31/49] test: fix audio_time with new get/set
|
||||
audio_tstamp_config
|
||||
|
||||
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
test/audio_time.c | 491 ++++++++++++++++++++++++++++++++++--------------------
|
||||
1 file changed, 313 insertions(+), 178 deletions(-)
|
||||
|
||||
diff --git a/test/audio_time.c b/test/audio_time.c
|
||||
index 7435db6a7fd8..e369e59b4ff2 100644
|
||||
--- a/test/audio_time.c
|
||||
+++ b/test/audio_time.c
|
||||
@@ -4,13 +4,39 @@
|
||||
* helpful to verify the information reported by drivers.
|
||||
*/
|
||||
|
||||
-#include "../include/asoundlib.h"
|
||||
+#include <stdio.h>
|
||||
+#include <malloc.h>
|
||||
+#include <unistd.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <getopt.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <ctype.h>
|
||||
+#include <errno.h>
|
||||
+#include <limits.h>
|
||||
+#include <time.h>
|
||||
+#include <locale.h>
|
||||
#include <math.h>
|
||||
+#include "../include/asoundlib.h"
|
||||
|
||||
-static char *device = "hw:0,0";
|
||||
-
|
||||
+static char *command;
|
||||
+static char *pcm_name = "hw:0";
|
||||
snd_output_t *output = NULL;
|
||||
|
||||
+static void usage(char *command)
|
||||
+{
|
||||
+ printf("Usage: %s [OPTION]... \n"
|
||||
+ "\n"
|
||||
+ "-h, --help help\n"
|
||||
+ "-c, --capture capture tstamps \n"
|
||||
+ "-d, --delay add delay \n"
|
||||
+ "-D, --device=NAME select PCM by name \n"
|
||||
+ "-p, --playback playback tstamps \n"
|
||||
+ "-t, --ts_type=TYPE Default(0),link(1),link_estimated(2),synchronized(3) \n"
|
||||
+ , command);
|
||||
+}
|
||||
+
|
||||
+
|
||||
long long timestamp2ns(snd_htimestamp_t t)
|
||||
{
|
||||
long long nsec;
|
||||
@@ -31,15 +57,20 @@ long long timediff(snd_htimestamp_t t1, snd_htimestamp_t t2)
|
||||
return nsec1 - nsec2;
|
||||
}
|
||||
|
||||
-void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
|
||||
- snd_htimestamp_t *trigger_timestamp,
|
||||
- snd_htimestamp_t *audio_timestamp,
|
||||
- snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
|
||||
+void _gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
|
||||
+ snd_htimestamp_t *trigger_timestamp,
|
||||
+ snd_htimestamp_t *audio_timestamp,
|
||||
+ snd_pcm_audio_tstamp_config_t *audio_tstamp_config,
|
||||
+ snd_pcm_audio_tstamp_report_t *audio_tstamp_report,
|
||||
+ snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
|
||||
{
|
||||
int err;
|
||||
snd_pcm_status_t *status;
|
||||
|
||||
snd_pcm_status_alloca(&status);
|
||||
+
|
||||
+ snd_pcm_status_set_audio_htstamp_config(status, audio_tstamp_config);
|
||||
+
|
||||
if ((err = snd_pcm_status(handle, status)) < 0) {
|
||||
printf("Stream status error: %s\n", snd_strerror(err));
|
||||
exit(0);
|
||||
@@ -47,26 +78,30 @@ void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
|
||||
snd_pcm_status_get_trigger_htstamp(status, trigger_timestamp);
|
||||
snd_pcm_status_get_htstamp(status, timestamp);
|
||||
snd_pcm_status_get_audio_htstamp(status, audio_timestamp);
|
||||
+ snd_pcm_status_get_audio_htstamp_report(status, audio_tstamp_report);
|
||||
*avail = snd_pcm_status_get_avail(status);
|
||||
*delay = snd_pcm_status_get_delay(status);
|
||||
}
|
||||
|
||||
-#define PERIOD 6000
|
||||
+#define TIMESTAMP_FREQ 8 /* Hz */
|
||||
+#define SAMPLE_FREQ 48000
|
||||
+#define PERIOD (SAMPLE_FREQ/TIMESTAMP_FREQ)
|
||||
#define PCM_LINK /* sync start for playback and capture */
|
||||
#define TRACK_CAPTURE /* dump capture timing info */
|
||||
#define TRACK_PLAYBACK /* dump playback timing info */
|
||||
-#define TRACK_SAMPLE_COUNTS /* show difference between sample counters and audiotimestamps returned by driver */
|
||||
+/*#define TRACK_SAMPLE_COUNTS */ /* show difference between sample counters and audiotimestamps returned by driver */
|
||||
#define PLAYBACK_BUFFERS 4
|
||||
-#define TSTAMP_TYPE SND_PCM_TSTAMP_TYPE_MONOTONIC
|
||||
+#define TSTAMP_TYPE SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW
|
||||
|
||||
|
||||
-int main(void)
|
||||
+int main(int argc, char *argv[])
|
||||
{
|
||||
- int err;
|
||||
- unsigned int i;
|
||||
- snd_pcm_t *handle_p = NULL;
|
||||
- snd_pcm_t *handle_c = NULL;
|
||||
- snd_pcm_sframes_t frames;
|
||||
+ int c;
|
||||
+ int err;
|
||||
+ unsigned int i;
|
||||
+ snd_pcm_t *handle_p = NULL;
|
||||
+ snd_pcm_t *handle_c = NULL;
|
||||
+ snd_pcm_sframes_t frames;
|
||||
snd_htimestamp_t tstamp_c, tstamp_p;
|
||||
snd_htimestamp_t trigger_tstamp_c, trigger_tstamp_p;
|
||||
snd_htimestamp_t audio_tstamp_c, audio_tstamp_p;
|
||||
@@ -87,206 +122,306 @@ int main(void)
|
||||
snd_pcm_sframes_t delay_p, delay_c;
|
||||
snd_pcm_uframes_t avail_p, avail_c;
|
||||
|
||||
- if ((err = snd_pcm_open(&handle_p, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
||||
- printf("Playback open error: %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
- }
|
||||
- if ((err = snd_pcm_set_params(handle_p,
|
||||
- SND_PCM_FORMAT_S16,
|
||||
- SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||
- 2,
|
||||
- 48000,
|
||||
- 0,
|
||||
- 500000)) < 0) { /* 0.5sec */
|
||||
- printf("Playback open error: %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
+ snd_pcm_audio_tstamp_config_t audio_tstamp_config_p;
|
||||
+ snd_pcm_audio_tstamp_config_t audio_tstamp_config_c;
|
||||
+ snd_pcm_audio_tstamp_report_t audio_tstamp_report_p;
|
||||
+ snd_pcm_audio_tstamp_report_t audio_tstamp_report_c;
|
||||
+
|
||||
+ int option_index;
|
||||
+ static const char short_options[] = "hcpdD:t:";
|
||||
+
|
||||
+ static const struct option long_options[] = {
|
||||
+ {"capture", 0, 0, 'c'},
|
||||
+ {"delay", 0, 0, 'd'},
|
||||
+ {"device", required_argument, 0, 'D'},
|
||||
+ {"help", no_argument, 0, 'h'},
|
||||
+ {"playback", 0, 0, 'p'},
|
||||
+ {"ts_type", required_argument, 0, 't'},
|
||||
+ {0, 0, 0, 0}
|
||||
+ };
|
||||
+
|
||||
+ int do_delay = 0;
|
||||
+ int do_playback = 0;
|
||||
+ int do_capture = 0;
|
||||
+ int type = 0;
|
||||
+
|
||||
+ while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
|
||||
+ switch (c) {
|
||||
+ case 'h':
|
||||
+ usage(command);
|
||||
+ return 0;
|
||||
+ case 'p':
|
||||
+ do_playback = 1;
|
||||
+ break;
|
||||
+ case 'c':
|
||||
+ do_capture = 1;
|
||||
+ break;
|
||||
+ case 'd':
|
||||
+ do_delay = 1;
|
||||
+ break;
|
||||
+ case 'D':
|
||||
+ pcm_name = optarg;
|
||||
+ break;
|
||||
+ case 't':
|
||||
+ type = atoi(optarg);
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
|
||||
- snd_pcm_hw_params_alloca(&hwparams_p);
|
||||
- /* get the current hwparams */
|
||||
- err = snd_pcm_hw_params_current(handle_p, hwparams_p);
|
||||
- if (err < 0) {
|
||||
- printf("Unable to determine current hwparams_p: %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
- }
|
||||
- if (snd_pcm_hw_params_supports_audio_wallclock_ts(hwparams_p))
|
||||
- printf("Playback relies on audio wallclock timestamps\n");
|
||||
- else
|
||||
- printf("Playback relies on audio sample counter timestamps\n");
|
||||
-
|
||||
- snd_pcm_sw_params_alloca(&swparams_p);
|
||||
- /* get the current swparams */
|
||||
- err = snd_pcm_sw_params_current(handle_p, swparams_p);
|
||||
- if (err < 0) {
|
||||
- printf("Unable to determine current swparams_p: %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
- }
|
||||
+ memset(&audio_tstamp_config_p, 0, sizeof(snd_pcm_audio_tstamp_config_t));
|
||||
+ memset(&audio_tstamp_config_c, 0, sizeof(snd_pcm_audio_tstamp_config_t));
|
||||
+ memset(&audio_tstamp_report_p, 0, sizeof(snd_pcm_audio_tstamp_report_t));
|
||||
+ memset(&audio_tstamp_report_c, 0, sizeof(snd_pcm_audio_tstamp_report_t));
|
||||
|
||||
- /* enable tstamp */
|
||||
- err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, SND_PCM_TSTAMP_ENABLE);
|
||||
- if (err < 0) {
|
||||
- printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
- }
|
||||
+ if (do_playback) {
|
||||
+ if ((err = snd_pcm_open(&handle_p, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
||||
+ printf("Playback open error: %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
|
||||
- err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, TSTAMP_TYPE);
|
||||
- if (err < 0) {
|
||||
- printf("Unable to set tstamp type : %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
- }
|
||||
+ if ((err = snd_pcm_set_params(handle_p,
|
||||
+ SND_PCM_FORMAT_S16,
|
||||
+ SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||
+ 2,
|
||||
+ SAMPLE_FREQ,
|
||||
+ 0,
|
||||
+ 4*1000000/TIMESTAMP_FREQ)) < 0) {
|
||||
+ printf("Playback open error: %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
|
||||
- /* write the sw parameters */
|
||||
- err = snd_pcm_sw_params(handle_p, swparams_p);
|
||||
- if (err < 0) {
|
||||
- printf("Unable to set swparams_p : %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
- }
|
||||
+ snd_pcm_hw_params_alloca(&hwparams_p);
|
||||
+/* get the current hwparams */
|
||||
+ err = snd_pcm_hw_params_current(handle_p, hwparams_p);
|
||||
+ if (err < 0) {
|
||||
+ printf("Unable to determine current hwparams_p: %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
|
||||
- if ((err = snd_pcm_open(&handle_c, device, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
|
||||
- printf("Capture open error: %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
- }
|
||||
- if ((err = snd_pcm_set_params(handle_c,
|
||||
- SND_PCM_FORMAT_S16,
|
||||
- SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||
- 2,
|
||||
- 48000,
|
||||
- 0,
|
||||
- 500000)) < 0) { /* 0.5sec */
|
||||
- printf("Capture open error: %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
- }
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 0))
|
||||
+ printf("Playback supports audio compat timestamps\n");
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 1))
|
||||
+ printf("Playback supports audio default timestamps\n");
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 2))
|
||||
+ printf("Playback supports audio link timestamps\n");
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 3))
|
||||
+ printf("Playback supports audio link absolute timestamps\n");
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 4))
|
||||
+ printf("Playback supports audio link estimated timestamps\n");
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 5))
|
||||
+ printf("Playback supports audio link synchronized timestamps\n");
|
||||
+
|
||||
+ snd_pcm_sw_params_alloca(&swparams_p);
|
||||
+ /* get the current swparams */
|
||||
+ err = snd_pcm_sw_params_current(handle_p, swparams_p);
|
||||
+ if (err < 0) {
|
||||
+ printf("Unable to determine current swparams_p: %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
|
||||
- snd_pcm_hw_params_alloca(&hwparams_c);
|
||||
- /* get the current hwparams */
|
||||
- err = snd_pcm_hw_params_current(handle_c, hwparams_c);
|
||||
- if (err < 0) {
|
||||
- printf("Unable to determine current hwparams_c: %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
- }
|
||||
- if (snd_pcm_hw_params_supports_audio_wallclock_ts(hwparams_c))
|
||||
- printf("Capture relies on audio wallclock timestamps\n");
|
||||
- else
|
||||
- printf("Capture relies on audio sample counter timestamps\n");
|
||||
-
|
||||
- snd_pcm_sw_params_alloca(&swparams_c);
|
||||
- /* get the current swparams */
|
||||
- err = snd_pcm_sw_params_current(handle_c, swparams_c);
|
||||
- if (err < 0) {
|
||||
- printf("Unable to determine current swparams_c: %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
- }
|
||||
+ /* enable tstamp */
|
||||
+ err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, SND_PCM_TSTAMP_ENABLE);
|
||||
+ if (err < 0) {
|
||||
+ printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
|
||||
- /* enable tstamp */
|
||||
- err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, SND_PCM_TSTAMP_ENABLE);
|
||||
- if (err < 0) {
|
||||
- printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
- }
|
||||
+ err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, TSTAMP_TYPE);
|
||||
+ if (err < 0) {
|
||||
+ printf("Unable to set tstamp type : %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
+
|
||||
+ /* write the sw parameters */
|
||||
+ err = snd_pcm_sw_params(handle_p, swparams_p);
|
||||
+ if (err < 0) {
|
||||
+ printf("Unable to set swparams_p : %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
|
||||
- err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, TSTAMP_TYPE);
|
||||
- if (err < 0) {
|
||||
- printf("Unable to set tstamp type : %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
}
|
||||
|
||||
- /* write the sw parameters */
|
||||
- err = snd_pcm_sw_params(handle_c, swparams_c);
|
||||
- if (err < 0) {
|
||||
- printf("Unable to set swparams_c : %s\n", snd_strerror(err));
|
||||
- goto _exit;
|
||||
+ if (do_capture) {
|
||||
+
|
||||
+ if ((err = snd_pcm_open(&handle_c, pcm_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
|
||||
+ printf("Capture open error: %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
+ if ((err = snd_pcm_set_params(handle_c,
|
||||
+ SND_PCM_FORMAT_S16,
|
||||
+ SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||
+ 2,
|
||||
+ SAMPLE_FREQ,
|
||||
+ 0,
|
||||
+ 4*1000000/TIMESTAMP_FREQ)) < 0) {
|
||||
+ printf("Capture open error: %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
+
|
||||
+ snd_pcm_hw_params_alloca(&hwparams_c);
|
||||
+ /* get the current hwparams */
|
||||
+ err = snd_pcm_hw_params_current(handle_c, hwparams_c);
|
||||
+ if (err < 0) {
|
||||
+ printf("Unable to determine current hwparams_c: %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
+
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 0))
|
||||
+ printf("Capture supports audio compat timestamps\n");
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 1))
|
||||
+ printf("Capture supports audio default timestamps\n");
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 2))
|
||||
+ printf("Capture supports audio link timestamps\n");
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 3))
|
||||
+ printf("Capture supports audio link absolute timestamps\n");
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 4))
|
||||
+ printf("Capture supports audio link estimated timestamps\n");
|
||||
+ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 5))
|
||||
+ printf("Capture supports audio link synchronized timestamps\n");
|
||||
+
|
||||
+ snd_pcm_sw_params_alloca(&swparams_c);
|
||||
+ /* get the current swparams */
|
||||
+ err = snd_pcm_sw_params_current(handle_c, swparams_c);
|
||||
+ if (err < 0) {
|
||||
+ printf("Unable to determine current swparams_c: %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
+
|
||||
+ /* enable tstamp */
|
||||
+ err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, SND_PCM_TSTAMP_ENABLE);
|
||||
+ if (err < 0) {
|
||||
+ printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
+
|
||||
+ err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, TSTAMP_TYPE);
|
||||
+ if (err < 0) {
|
||||
+ printf("Unable to set tstamp type : %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
+
|
||||
+ /* write the sw parameters */
|
||||
+ err = snd_pcm_sw_params(handle_c, swparams_c);
|
||||
+ if (err < 0) {
|
||||
+ printf("Unable to set swparams_c : %s\n", snd_strerror(err));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
}
|
||||
|
||||
+ if (do_playback && do_capture) {
|
||||
#ifdef PCM_LINK
|
||||
- if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
|
||||
- printf("Streams link error: %s\n", snd_strerror(err));
|
||||
- exit(0);
|
||||
- }
|
||||
+ if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
|
||||
+ printf("Streams link error: %s\n", snd_strerror(err));
|
||||
+ exit(0);
|
||||
+ }
|
||||
#endif
|
||||
-
|
||||
- i = PLAYBACK_BUFFERS;
|
||||
- while (i--) {
|
||||
- frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
|
||||
- if (frames < 0) {
|
||||
- printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
|
||||
- goto _exit;
|
||||
- }
|
||||
- frame_count_p += frames;
|
||||
}
|
||||
|
||||
- if (PLAYBACK_BUFFERS != 4)
|
||||
- snd_pcm_start(handle_p);
|
||||
+ if (do_playback) {
|
||||
+ i = PLAYBACK_BUFFERS;
|
||||
+ while (i--) {
|
||||
+ frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
|
||||
+ if (frames < 0) {
|
||||
+ printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
+ frame_count_p += frames;
|
||||
+ }
|
||||
+
|
||||
+ if (PLAYBACK_BUFFERS != 4)
|
||||
+ snd_pcm_start(handle_p);
|
||||
+ }
|
||||
|
||||
+ if (do_capture) {
|
||||
#ifndef PCM_LINK
|
||||
- /* need to start capture explicitly */
|
||||
- snd_pcm_start(handle_c);
|
||||
+ /* need to start capture explicitly */
|
||||
+ snd_pcm_start(handle_c);
|
||||
+#else
|
||||
+ if (!do_playback)
|
||||
+ /* need to start capture explicitly */
|
||||
+ snd_pcm_start(handle_c);
|
||||
#endif
|
||||
+ }
|
||||
|
||||
- while (1) {
|
||||
-
|
||||
- frames = snd_pcm_wait(handle_c, -1);
|
||||
- if (frames < 0) {
|
||||
- printf("snd_pcm_wait failed: %s\n", snd_strerror(frames));
|
||||
- goto _exit;
|
||||
- }
|
||||
-
|
||||
- frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
|
||||
- if (frames < 0) {
|
||||
- printf("snd_pcm_readi failed: %s\n", snd_strerror(frames));
|
||||
- goto _exit;
|
||||
- }
|
||||
- frame_count_c += frames;
|
||||
+ while (1) {
|
||||
|
||||
- frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
|
||||
- if (frames < 0) {
|
||||
- printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
|
||||
- goto _exit;
|
||||
- }
|
||||
+ if (do_capture) {
|
||||
|
||||
- frame_count_p += frames;
|
||||
+ frames = snd_pcm_wait(handle_c, -1);
|
||||
+ if (frames < 0) {
|
||||
+ printf("snd_pcm_wait failed: %s\n", snd_strerror(frames));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
|
||||
-#if defined(TRACK_PLAYBACK)
|
||||
- gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p, &audio_tstamp_p, &avail_p, &delay_p);
|
||||
+ frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
|
||||
+ if (frames < 0) {
|
||||
+ printf("snd_pcm_readi failed: %s\n", snd_strerror(frames));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
+ frame_count_c += frames;
|
||||
|
||||
+#if defined(TRACK_CAPTURE)
|
||||
+ audio_tstamp_config_c.type_requested = type;
|
||||
+ audio_tstamp_config_c.report_delay = do_delay;
|
||||
+ _gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c,
|
||||
+ &audio_tstamp_c, &audio_tstamp_config_c, &audio_tstamp_report_c,
|
||||
+ &avail_c, &delay_c);
|
||||
#if defined(TRACK_SAMPLE_COUNTS)
|
||||
- curr_count_p = frame_count_p - delay_p; /* written minus queued */
|
||||
+ curr_count_c = frame_count_c + delay_c; /* read plus queued */
|
||||
|
||||
- printf("playback: curr_count %lli driver count %lli, delta %lli\n",
|
||||
- (long long)curr_count_p * 1000000000LL / 48000 ,
|
||||
- timestamp2ns(audio_tstamp_p),
|
||||
- (long long)curr_count_p * 1000000000LL / 48000 - timestamp2ns(audio_tstamp_p)
|
||||
- );
|
||||
+
|
||||
+ printf("capture: curr_count %lli driver count %lli, delta %lli\n",
|
||||
+ (long long)curr_count_c * 1000000000LL / SAMPLE_FREQ ,
|
||||
+ timestamp2ns(audio_tstamp_c),
|
||||
+ (long long)curr_count_c * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_c)
|
||||
+ );
|
||||
#endif
|
||||
|
||||
- printf("playback: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
|
||||
- timediff(tstamp_p, trigger_tstamp_p),
|
||||
- timestamp2ns(audio_tstamp_p),
|
||||
- timediff(tstamp_p, trigger_tstamp_p) - timestamp2ns(audio_tstamp_p)
|
||||
- );
|
||||
+ printf("\t capture: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
|
||||
+ timediff(tstamp_c, trigger_tstamp_c),
|
||||
+ timestamp2ns(audio_tstamp_c),
|
||||
+ timediff(tstamp_c, trigger_tstamp_c) - timestamp2ns(audio_tstamp_c)
|
||||
+ );
|
||||
#endif
|
||||
+ }
|
||||
|
||||
-#if defined(TRACK_CAPTURE)
|
||||
- gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c, &audio_tstamp_c, &avail_c, &delay_c);
|
||||
+ if (do_playback) {
|
||||
+ frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
|
||||
+ if (frames < 0) {
|
||||
+ printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
|
||||
+ goto _exit;
|
||||
+ }
|
||||
|
||||
-#if defined(TRACK_SAMPLE_COUNTS)
|
||||
- curr_count_c = frame_count_c + delay_c; /* read plus queued */
|
||||
+ frame_count_p += frames;
|
||||
+
|
||||
+#if defined(TRACK_PLAYBACK)
|
||||
|
||||
+ audio_tstamp_config_p.type_requested = type;
|
||||
+ audio_tstamp_config_p.report_delay = do_delay;
|
||||
+ _gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p,
|
||||
+ &audio_tstamp_p, &audio_tstamp_config_p, &audio_tstamp_report_p,
|
||||
+ &avail_p, &delay_p);
|
||||
|
||||
- printf("capture: curr_count %lli driver count %lli, delta %lli\n",
|
||||
- (long long)curr_count_c * 1000000000LL / 48000 ,
|
||||
- timestamp2ns(audio_tstamp_c),
|
||||
- (long long)curr_count_c * 1000000000LL / 48000 - timestamp2ns(audio_tstamp_c)
|
||||
- );
|
||||
+#if defined(TRACK_SAMPLE_COUNTS)
|
||||
+ curr_count_p = frame_count_p - delay_p; /* written minus queued */
|
||||
+
|
||||
+ printf("playback: curr_count %lli driver count %lli, delta %lli\n",
|
||||
+ (long long)curr_count_p * 1000000000LL / SAMPLE_FREQ ,
|
||||
+ timestamp2ns(audio_tstamp_p),
|
||||
+ (long long)curr_count_p * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_p)
|
||||
+ );
|
||||
#endif
|
||||
|
||||
- printf("\t capture: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
|
||||
- timediff(tstamp_c, trigger_tstamp_c),
|
||||
- timestamp2ns(audio_tstamp_c),
|
||||
- timediff(tstamp_c, trigger_tstamp_c) - timestamp2ns(audio_tstamp_c)
|
||||
- );
|
||||
+ printf("playback: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
|
||||
+ timediff(tstamp_p, trigger_tstamp_p),
|
||||
+ timestamp2ns(audio_tstamp_p),
|
||||
+ timediff(tstamp_p, trigger_tstamp_p) - timestamp2ns(audio_tstamp_p)
|
||||
+ );
|
||||
#endif
|
||||
+ }
|
||||
+
|
||||
|
||||
- }
|
||||
+ } /* while(1) */
|
||||
|
||||
_exit:
|
||||
if (handle_p)
|
||||
--
|
||||
2.5.0
|
||||
|
106
0032-test-audio_time-show-report-validity-and-accuracy.patch
Normal file
106
0032-test-audio_time-show-report-validity-and-accuracy.patch
Normal file
@ -0,0 +1,106 @@
|
||||
From 6849d7dc88e0fe22cddb6b2d06ddc967ad4c3a6c Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Date: Wed, 1 Jul 2015 15:40:58 -0500
|
||||
Subject: [PATCH 32/49] test: audio_time: show report validity and accuracy
|
||||
|
||||
Add checks to show if driver reports valid report and resolution
|
||||
information. disabled by default
|
||||
|
||||
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
test/audio_time.c | 30 +++++++++++++++++++++++++-----
|
||||
1 file changed, 25 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/test/audio_time.c b/test/audio_time.c
|
||||
index e369e59b4ff2..a54c10dc9ebd 100644
|
||||
--- a/test/audio_time.c
|
||||
+++ b/test/audio_time.c
|
||||
@@ -33,6 +33,7 @@ static void usage(char *command)
|
||||
"-D, --device=NAME select PCM by name \n"
|
||||
"-p, --playback playback tstamps \n"
|
||||
"-t, --ts_type=TYPE Default(0),link(1),link_estimated(2),synchronized(3) \n"
|
||||
+ "-r, --report show audio timestamp and accuracy validity\n"
|
||||
, command);
|
||||
}
|
||||
|
||||
@@ -128,7 +129,7 @@ int main(int argc, char *argv[])
|
||||
snd_pcm_audio_tstamp_report_t audio_tstamp_report_c;
|
||||
|
||||
int option_index;
|
||||
- static const char short_options[] = "hcpdD:t:";
|
||||
+ static const char short_options[] = "hcpdrD:t:";
|
||||
|
||||
static const struct option long_options[] = {
|
||||
{"capture", 0, 0, 'c'},
|
||||
@@ -137,6 +138,7 @@ int main(int argc, char *argv[])
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"playback", 0, 0, 'p'},
|
||||
{"ts_type", required_argument, 0, 't'},
|
||||
+ {"report", 0, 0, 'r'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -144,6 +146,7 @@ int main(int argc, char *argv[])
|
||||
int do_playback = 0;
|
||||
int do_capture = 0;
|
||||
int type = 0;
|
||||
+ int do_report = 0;
|
||||
|
||||
while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
|
||||
switch (c) {
|
||||
@@ -165,6 +168,8 @@ int main(int argc, char *argv[])
|
||||
case 't':
|
||||
type = atoi(optarg);
|
||||
break;
|
||||
+ case 'r':
|
||||
+ do_report = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,11 +381,19 @@ int main(int argc, char *argv[])
|
||||
(long long)curr_count_c * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_c)
|
||||
);
|
||||
#endif
|
||||
+ if (do_report) {
|
||||
+ if (audio_tstamp_report_c.valid == 0)
|
||||
+ printf("Audio capture timestamp report invalid - ");
|
||||
+ if (audio_tstamp_report_c.accuracy_report == 0)
|
||||
+ printf("Audio capture timestamp accuracy report invalid");
|
||||
+ printf("\n");
|
||||
+ }
|
||||
+
|
||||
|
||||
- printf("\t capture: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
|
||||
+ printf("\t capture: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli \t resolution %d ns \n",
|
||||
timediff(tstamp_c, trigger_tstamp_c),
|
||||
timestamp2ns(audio_tstamp_c),
|
||||
- timediff(tstamp_c, trigger_tstamp_c) - timestamp2ns(audio_tstamp_c)
|
||||
+ timediff(tstamp_c, trigger_tstamp_c) - timestamp2ns(audio_tstamp_c), audio_tstamp_report_c.accuracy
|
||||
);
|
||||
#endif
|
||||
}
|
||||
@@ -411,11 +424,18 @@ int main(int argc, char *argv[])
|
||||
(long long)curr_count_p * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_p)
|
||||
);
|
||||
#endif
|
||||
+ if (do_report) {
|
||||
+ if (audio_tstamp_report_p.valid == 0)
|
||||
+ printf("Audio playback timestamp report invalid - ");
|
||||
+ if (audio_tstamp_report_p.accuracy_report == 0)
|
||||
+ printf("Audio playback timestamp accuracy report invalid");
|
||||
+ printf("\n");
|
||||
+ }
|
||||
|
||||
- printf("playback: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
|
||||
+ printf("playback: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli resolution %d ns\n",
|
||||
timediff(tstamp_p, trigger_tstamp_p),
|
||||
timestamp2ns(audio_tstamp_p),
|
||||
- timediff(tstamp_p, trigger_tstamp_p) - timestamp2ns(audio_tstamp_p)
|
||||
+ timediff(tstamp_p, trigger_tstamp_p) - timestamp2ns(audio_tstamp_p), audio_tstamp_report_p.accuracy
|
||||
);
|
||||
#endif
|
||||
}
|
||||
--
|
||||
2.5.0
|
||||
|
44
0033-pcm-restore-hw-params-on-set-latency-failed.patch
Normal file
44
0033-pcm-restore-hw-params-on-set-latency-failed.patch
Normal file
@ -0,0 +1,44 @@
|
||||
From 77b6be63876ee46a95320e77735d977edeedd44a Mon Sep 17 00:00:00 2001
|
||||
From: Martin Geier <martin.geier@streamunlimited.com>
|
||||
Date: Fri, 24 Jul 2015 09:30:57 +0200
|
||||
Subject: [PATCH 33/49] pcm: restore hw params on set latency failed
|
||||
|
||||
When method snd_pcm_set_params sets sample rate to 22050 and latency to 50000
|
||||
to davinci soc driver method snd_pcm_hw_params_set_buffer_time_near fails
|
||||
and variable params is already changed in the method so the next method
|
||||
snd_pcm_hw_params_set_period_time_near fails also.
|
||||
|
||||
Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/pcm/pcm.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
|
||||
index bae1d1653904..f5fc728518d8 100644
|
||||
--- a/src/pcm/pcm.c
|
||||
+++ b/src/pcm/pcm.c
|
||||
@@ -8004,7 +8004,7 @@ int snd_pcm_set_params(snd_pcm_t *pcm,
|
||||
int soft_resample,
|
||||
unsigned int latency)
|
||||
{
|
||||
- snd_pcm_hw_params_t *params;
|
||||
+ snd_pcm_hw_params_t *params, params_saved;
|
||||
snd_pcm_sw_params_t *swparams;
|
||||
const char *s = snd_pcm_stream_name(snd_pcm_stream(pcm));
|
||||
snd_pcm_uframes_t buffer_size, period_size;
|
||||
@@ -8057,9 +8057,11 @@ int snd_pcm_set_params(snd_pcm_t *pcm,
|
||||
return -EINVAL;
|
||||
}
|
||||
/* set the buffer time */
|
||||
+ params_saved = *params;
|
||||
err = INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(pcm, params, &latency, NULL);
|
||||
if (err < 0) {
|
||||
/* error path -> set period size as first */
|
||||
+ *params = params_saved;
|
||||
/* set the period time */
|
||||
period_time = latency / 4;
|
||||
err = INTERNAL(snd_pcm_hw_params_set_period_time_near)(pcm, params, &period_time, NULL);
|
||||
--
|
||||
2.5.0
|
||||
|
274
0034-Replace-list.h-with-its-own-version.patch
Normal file
274
0034-Replace-list.h-with-its-own-version.patch
Normal file
@ -0,0 +1,274 @@
|
||||
From d0e13f87742e923edfb638d4b16b69b8dc2136d8 Mon Sep 17 00:00:00 2001
|
||||
From: Takashi Iwai <tiwai@suse.de>
|
||||
Date: Mon, 27 Jul 2015 12:32:37 +0200
|
||||
Subject: [PATCH 34/49] Replace list.h with its own version
|
||||
|
||||
We copied include/list.h from Linux kernel, and it's of course in
|
||||
GPLv2. This has raised concerns to many people, as it's not clear
|
||||
whether such a code is considered to be completely trivial, thus it
|
||||
might be seen as a derivative work, which takes effect in GPL, as
|
||||
suggested by Clemens.
|
||||
|
||||
For clearing the situation, this patch replaces the existing list.h
|
||||
implementation from a new version. The API is kept to be compatible,
|
||||
but the codes were written from full scratch under LGPL, to be aligned
|
||||
with other alsa-lib codes.
|
||||
|
||||
Reported-by: Clemens Lang <clemens.lang@bmw-carit.de>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
include/list.h | 212 +++++++++++++++++++--------------------------------------
|
||||
1 file changed, 70 insertions(+), 142 deletions(-)
|
||||
|
||||
diff --git a/include/list.h b/include/list.h
|
||||
index 4d9895feba05..947c1f8411e2 100644
|
||||
--- a/include/list.h
|
||||
+++ b/include/list.h
|
||||
@@ -1,174 +1,102 @@
|
||||
+/* Doubly linked list macros compatible with Linux kernel's version
|
||||
+ * Copyright (c) 2015 by Takashi Iwai <tiwai@suse.de>
|
||||
+ *
|
||||
+ * This library is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU Lesser General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2.1 of
|
||||
+ * the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU Lesser General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
#ifndef _LIST_H
|
||||
#define _LIST_H
|
||||
|
||||
-/*
|
||||
- * This code was taken from the Linux 2.4.0 kernel. [jaroslav]
|
||||
- */
|
||||
+#include <stddef.h>
|
||||
|
||||
-/*
|
||||
- * Simple doubly linked list implementation.
|
||||
- *
|
||||
- * Some of the internal functions ("__xxx") are useful when
|
||||
- * manipulating whole lists rather than single entries, as
|
||||
- * sometimes we already know the next/prev entries and we can
|
||||
- * generate better code by using them directly rather than
|
||||
- * using the generic single-entry routines.
|
||||
- */
|
||||
-
|
||||
-#ifndef LIST_HEAD_IS_DEFINED
|
||||
struct list_head {
|
||||
- struct list_head *next, *prev;
|
||||
+ struct list_head *next;
|
||||
+ struct list_head *prev;
|
||||
};
|
||||
-#endif
|
||||
-
|
||||
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
-#define LIST_HEAD(name) \
|
||||
- struct list_head name = LIST_HEAD_INIT(name)
|
||||
+/* one-shot definition of a list head */
|
||||
+#define LIST_HEAD(x) \
|
||||
+ struct list_head x = { &x, &x }
|
||||
|
||||
-#define INIT_LIST_HEAD(ptr) do { \
|
||||
- (ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
-} while (0)
|
||||
-
|
||||
-/*
|
||||
- * Insert a new entry between two known consecutive entries.
|
||||
- *
|
||||
- * This is only for internal list manipulation where we know
|
||||
- * the prev/next entries already!
|
||||
- */
|
||||
-static __inline__ void __list_add(struct list_head * _new,
|
||||
- struct list_head * prev,
|
||||
- struct list_head * next)
|
||||
+/* initialize a list head explicitly */
|
||||
+static inline void INIT_LIST_HEAD(struct list_head *p)
|
||||
{
|
||||
- next->prev = _new;
|
||||
- _new->next = next;
|
||||
- _new->prev = prev;
|
||||
- prev->next = _new;
|
||||
+ p->next = p->prev = p;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * list_add - add a new entry
|
||||
- * @new: new entry to be added
|
||||
- * @head: list head to add it after
|
||||
- *
|
||||
- * Insert a new entry after the specified head.
|
||||
- * This is good for implementing stacks.
|
||||
+#define list_entry_offset(p, type, offset) \
|
||||
+ ((type *)((char *)(p) - (offset)))
|
||||
+
|
||||
+/* list_entry - retrieve the original struct from list_head
|
||||
+ * @p: list_head pointer
|
||||
+ * @type: struct type
|
||||
+ * @member: struct field member containing the list_head
|
||||
*/
|
||||
-static __inline__ void list_add(struct list_head *_new, struct list_head *head)
|
||||
-{
|
||||
- __list_add(_new, head, head->next);
|
||||
-}
|
||||
+#define list_entry(p, type, member) \
|
||||
+ list_entry_offset(p, type, offsetof(type, member))
|
||||
|
||||
-/**
|
||||
- * list_add_tail - add a new entry
|
||||
- * @new: new entry to be added
|
||||
- * @head: list head to add it before
|
||||
- *
|
||||
- * Insert a new entry before the specified head.
|
||||
- * This is useful for implementing queues.
|
||||
+/* list_for_each - iterate over the linked list
|
||||
+ * @p: iterator, a list_head pointer variable
|
||||
+ * @list: list_head pointer containing the list
|
||||
*/
|
||||
-static __inline__ void list_add_tail(struct list_head *_new, struct list_head *head)
|
||||
-{
|
||||
- __list_add(_new, head->prev, head);
|
||||
-}
|
||||
+#define list_for_each(p, list) \
|
||||
+ for (p = (list)->next; p != (list); p = p->next)
|
||||
|
||||
-/*
|
||||
- * Delete a list entry by making the prev/next entries
|
||||
- * point to each other.
|
||||
- *
|
||||
- * This is only for internal list manipulation where we know
|
||||
- * the prev/next entries already!
|
||||
+/* list_for_each_safe - iterate over the linked list, safe to delete
|
||||
+ * @p: iterator, a list_head pointer variable
|
||||
+ * @s: a temporary variable to keep the next, a list_head pointer, too
|
||||
+ * @list: list_head pointer containing the list
|
||||
*/
|
||||
-static __inline__ void __list_del(struct list_head * prev,
|
||||
- struct list_head * next)
|
||||
-{
|
||||
- next->prev = prev;
|
||||
- prev->next = next;
|
||||
-}
|
||||
+#define list_for_each_safe(p, s, list) \
|
||||
+ for (p = (list)->next; s = p->next, p != (list); p = s)
|
||||
|
||||
-/**
|
||||
- * list_del - deletes entry from list.
|
||||
- * @entry: the element to delete from the list.
|
||||
- * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
|
||||
+/* list_add - prepend a list entry at the head
|
||||
+ * @p: the new list entry to add
|
||||
+ * @list: the list head
|
||||
*/
|
||||
-static __inline__ void list_del(struct list_head *entry)
|
||||
+static inline void list_add(struct list_head *p, struct list_head *list)
|
||||
{
|
||||
- __list_del(entry->prev, entry->next);
|
||||
+ struct list_head *first = list->next;
|
||||
+
|
||||
+ p->next = first;
|
||||
+ first->prev = p;
|
||||
+ list->next = p;
|
||||
+ p->prev = list;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * list_del_init - deletes entry from list and reinitialize it.
|
||||
- * @entry: the element to delete from the list.n
|
||||
+/* list_add_tail - append a list entry at the tail
|
||||
+ * @p: the new list entry to add
|
||||
+ * @list: the list head
|
||||
*/
|
||||
-static __inline__ void list_del_init(struct list_head *entry)
|
||||
+static inline void list_add_tail(struct list_head *p, struct list_head *list)
|
||||
{
|
||||
- __list_del(entry->prev, entry->next);
|
||||
- INIT_LIST_HEAD(entry);
|
||||
+ struct list_head *last = list->prev;
|
||||
+
|
||||
+ last->next = p;
|
||||
+ p->prev = last;
|
||||
+ p->next = list;
|
||||
+ list->prev = p;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * list_empty - tests whether a list is empty
|
||||
- * @head: the list to test.
|
||||
- */
|
||||
-static __inline__ int list_empty(struct list_head *head)
|
||||
+/* list_del - delete the given list entry */
|
||||
+static inline void list_del(struct list_head *p)
|
||||
{
|
||||
- return head->next == head;
|
||||
+ p->prev->next = p->next;
|
||||
+ p->next->prev = p->prev;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * list_splice - join two lists
|
||||
- * @list: the new list to add.
|
||||
- * @head: the place to add it in the first list.
|
||||
- */
|
||||
-static __inline__ void list_splice(struct list_head *list, struct list_head *head)
|
||||
+/* list_empty - returns 1 if the given list is empty */
|
||||
+static inline int list_empty(const struct list_head *p)
|
||||
{
|
||||
- struct list_head *first = list->next;
|
||||
-
|
||||
- if (first != list) {
|
||||
- struct list_head *last = list->prev;
|
||||
- struct list_head *at = head->next;
|
||||
-
|
||||
- first->prev = head;
|
||||
- head->next = first;
|
||||
-
|
||||
- last->next = at;
|
||||
- at->prev = last;
|
||||
- }
|
||||
+ return p->next == p;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * list_for_each - iterate over a list
|
||||
- * @pos: the &struct list_head to use as a loop counter.
|
||||
- * @head: the head for your list.
|
||||
- */
|
||||
-#define list_for_each(pos, head) \
|
||||
- for (pos = (head)->next ; pos != (head); pos = pos->next)
|
||||
-
|
||||
-/**
|
||||
- * list_for_each_safe - iterate over a list safely (actual pointer can be invalidated)
|
||||
- * @pos: the &struct list_head to use as a loop counter.
|
||||
- * @next: the &struct list_head to use to save next.
|
||||
- * @head: the head for your list.
|
||||
- */
|
||||
-#define list_for_each_safe(pos, npos, head) \
|
||||
- for (pos = (head)->next, npos = pos->next ; pos != (head); pos = npos, npos = pos->next)
|
||||
-
|
||||
-/**
|
||||
- * list_entry - get the struct for this entry
|
||||
- * @ptr: the &struct list_head pointer.
|
||||
- * @type: the type of the struct this is embedded in.
|
||||
- * @member: the name of the list_struct within the struct.
|
||||
- */
|
||||
-#define list_entry(ptr, type, member) \
|
||||
- ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
-
|
||||
-/**
|
||||
- * list_entry - get the struct for this entry
|
||||
- * @ptr: the &struct list_head pointer.
|
||||
- * @type: the type of the struct this is embedded in.
|
||||
- * @offset: offset of entry inside a struct
|
||||
- */
|
||||
-#define list_entry_offset(ptr, type, offset) \
|
||||
- ((type *)((char *)(ptr)-(offset)))
|
||||
-
|
||||
#endif /* _LIST_H */
|
||||
--
|
||||
2.5.0
|
||||
|
454
0035-topology-uapi-Add-UAPI-headers-for-topology-ABI.patch
Normal file
454
0035-topology-uapi-Add-UAPI-headers-for-topology-ABI.patch
Normal file
@ -0,0 +1,454 @@
|
||||
From 227c790c16db17a986df06c9a3ad79edade78db7 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:13 +0100
|
||||
Subject: [PATCH 35/49] topology: uapi: Add UAPI headers for topology ABI
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
include/sound/Makefile.am | 3 +-
|
||||
include/sound/asoc.h | 388 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
include/sound/tlv.h | 23 +++
|
||||
3 files changed, 413 insertions(+), 1 deletion(-)
|
||||
create mode 100644 include/sound/asoc.h
|
||||
create mode 100644 include/sound/tlv.h
|
||||
|
||||
diff --git a/include/sound/Makefile.am b/include/sound/Makefile.am
|
||||
index 31aa2db43d27..b659985e7e36 100644
|
||||
--- a/include/sound/Makefile.am
|
||||
+++ b/include/sound/Makefile.am
|
||||
@@ -1,6 +1,7 @@
|
||||
alsasoundincludedir = ${includedir}/alsa/sound
|
||||
|
||||
alsasoundinclude_HEADERS = asound_fm.h hdsp.h hdspm.h sb16_csp.h \
|
||||
- sscape_ioctl.h emu10k1.h type_compat.h
|
||||
+ sscape_ioctl.h emu10k1.h type_compat.h \
|
||||
+ asoc.h tlv.h
|
||||
|
||||
noinst_HEADERS = asound.h asoundef.h asequencer.h
|
||||
diff --git a/include/sound/asoc.h b/include/sound/asoc.h
|
||||
new file mode 100644
|
||||
index 000000000000..bb6dcf3ff7b4
|
||||
--- /dev/null
|
||||
+++ b/include/sound/asoc.h
|
||||
@@ -0,0 +1,388 @@
|
||||
+/*
|
||||
+ * uapi/sound/asoc.h -- ALSA SoC Firmware Controls and DAPM
|
||||
+ *
|
||||
+ * Copyright (C) 2012 Texas Instruments Inc.
|
||||
+ * Copyright (C) 2015 Intel Corporation.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * Simple file API to load FW that includes mixers, coefficients, DAPM graphs,
|
||||
+ * algorithms, equalisers, DAIs, widgets etc.
|
||||
+*/
|
||||
+
|
||||
+#ifndef __LINUX_UAPI_SND_ASOC_H
|
||||
+#define __LINUX_UAPI_SND_ASOC_H
|
||||
+
|
||||
+/*
|
||||
+ * Maximum number of channels topology kcontrol can represent.
|
||||
+ */
|
||||
+#define SND_SOC_TPLG_MAX_CHAN 8
|
||||
+
|
||||
+/*
|
||||
+ * Maximum number of PCM formats capability
|
||||
+ */
|
||||
+#define SND_SOC_TPLG_MAX_FORMATS 16
|
||||
+
|
||||
+/*
|
||||
+ * Maximum number of PCM stream configs
|
||||
+ */
|
||||
+#define SND_SOC_TPLG_STREAM_CONFIG_MAX 8
|
||||
+
|
||||
+/* individual kcontrol info types - can be mixed with other types */
|
||||
+#define SND_SOC_TPLG_CTL_VOLSW 1
|
||||
+#define SND_SOC_TPLG_CTL_VOLSW_SX 2
|
||||
+#define SND_SOC_TPLG_CTL_VOLSW_XR_SX 3
|
||||
+#define SND_SOC_TPLG_CTL_ENUM 4
|
||||
+#define SND_SOC_TPLG_CTL_BYTES 5
|
||||
+#define SND_SOC_TPLG_CTL_ENUM_VALUE 6
|
||||
+#define SND_SOC_TPLG_CTL_RANGE 7
|
||||
+#define SND_SOC_TPLG_CTL_STROBE 8
|
||||
+
|
||||
+
|
||||
+/* individual widget kcontrol info types - can be mixed with other types */
|
||||
+#define SND_SOC_TPLG_DAPM_CTL_VOLSW 64
|
||||
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE 65
|
||||
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT 66
|
||||
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE 67
|
||||
+#define SND_SOC_TPLG_DAPM_CTL_PIN 68
|
||||
+
|
||||
+/* DAPM widget types - add new items to the end */
|
||||
+#define SND_SOC_TPLG_DAPM_INPUT 0
|
||||
+#define SND_SOC_TPLG_DAPM_OUTPUT 1
|
||||
+#define SND_SOC_TPLG_DAPM_MUX 2
|
||||
+#define SND_SOC_TPLG_DAPM_MIXER 3
|
||||
+#define SND_SOC_TPLG_DAPM_PGA 4
|
||||
+#define SND_SOC_TPLG_DAPM_OUT_DRV 5
|
||||
+#define SND_SOC_TPLG_DAPM_ADC 6
|
||||
+#define SND_SOC_TPLG_DAPM_DAC 7
|
||||
+#define SND_SOC_TPLG_DAPM_SWITCH 8
|
||||
+#define SND_SOC_TPLG_DAPM_PRE 9
|
||||
+#define SND_SOC_TPLG_DAPM_POST 10
|
||||
+#define SND_SOC_TPLG_DAPM_AIF_IN 11
|
||||
+#define SND_SOC_TPLG_DAPM_AIF_OUT 12
|
||||
+#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
|
||||
+
|
||||
+/* Header magic number and string sizes */
|
||||
+#define SND_SOC_TPLG_MAGIC 0x41536F43 /* ASoC */
|
||||
+
|
||||
+/* string sizes */
|
||||
+#define SND_SOC_TPLG_NUM_TEXTS 16
|
||||
+
|
||||
+/* ABI version */
|
||||
+#define SND_SOC_TPLG_ABI_VERSION 0x3
|
||||
+
|
||||
+/* Max size of TLV data */
|
||||
+#define SND_SOC_TPLG_TLV_SIZE 32
|
||||
+
|
||||
+/*
|
||||
+ * File and Block header data types.
|
||||
+ * Add new generic and vendor types to end of list.
|
||||
+ * Generic types are handled by the core whilst vendors types are passed
|
||||
+ * to the component drivers for handling.
|
||||
+ */
|
||||
+#define SND_SOC_TPLG_TYPE_MIXER 1
|
||||
+#define SND_SOC_TPLG_TYPE_BYTES 2
|
||||
+#define SND_SOC_TPLG_TYPE_ENUM 3
|
||||
+#define SND_SOC_TPLG_TYPE_DAPM_GRAPH 4
|
||||
+#define SND_SOC_TPLG_TYPE_DAPM_WIDGET 5
|
||||
+#define SND_SOC_TPLG_TYPE_DAI_LINK 6
|
||||
+#define SND_SOC_TPLG_TYPE_PCM 7
|
||||
+#define SND_SOC_TPLG_TYPE_MANIFEST 8
|
||||
+#define SND_SOC_TPLG_TYPE_CODEC_LINK 9
|
||||
+#define SND_SOC_TPLG_TYPE_PDATA 10
|
||||
+#define SND_SOC_TPLG_TYPE_MAX SND_SOC_TPLG_TYPE_PDATA
|
||||
+
|
||||
+/* vendor block IDs - please add new vendor types to end */
|
||||
+#define SND_SOC_TPLG_TYPE_VENDOR_FW 1000
|
||||
+#define SND_SOC_TPLG_TYPE_VENDOR_CONFIG 1001
|
||||
+#define SND_SOC_TPLG_TYPE_VENDOR_COEFF 1002
|
||||
+#define SND_SOC_TPLG_TYPEVENDOR_CODEC 1003
|
||||
+
|
||||
+#define SND_SOC_TPLG_STREAM_PLAYBACK 0
|
||||
+#define SND_SOC_TPLG_STREAM_CAPTURE 1
|
||||
+
|
||||
+/*
|
||||
+ * Block Header.
|
||||
+ * This header precedes all object and object arrays below.
|
||||
+ */
|
||||
+struct snd_soc_tplg_hdr {
|
||||
+ __le32 magic; /* magic number */
|
||||
+ __le32 abi; /* ABI version */
|
||||
+ __le32 version; /* optional vendor specific version details */
|
||||
+ __le32 type; /* SND_SOC_TPLG_TYPE_ */
|
||||
+ __le32 size; /* size of this structure */
|
||||
+ __le32 vendor_type; /* optional vendor specific type info */
|
||||
+ __le32 payload_size; /* data bytes, excluding this header */
|
||||
+ __le32 index; /* identifier for block */
|
||||
+ __le32 count; /* number of elements in block */
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * Private data.
|
||||
+ * All topology objects may have private data that can be used by the driver or
|
||||
+ * firmware. Core will ignore this data.
|
||||
+ */
|
||||
+struct snd_soc_tplg_private {
|
||||
+ __le32 size; /* in bytes of private data */
|
||||
+ char data[0];
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * Kcontrol TLV data.
|
||||
+ */
|
||||
+struct snd_soc_tplg_ctl_tlv {
|
||||
+ __le32 size; /* in bytes aligned to 4 */
|
||||
+ __le32 numid; /* control element numeric identification */
|
||||
+ __le32 count; /* number of elem in data array */
|
||||
+ __le32 data[SND_SOC_TPLG_TLV_SIZE];
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * Kcontrol channel data
|
||||
+ */
|
||||
+struct snd_soc_tplg_channel {
|
||||
+ __le32 size; /* in bytes of this structure */
|
||||
+ __le32 reg;
|
||||
+ __le32 shift;
|
||||
+ __le32 id; /* ID maps to Left, Right, LFE etc */
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * Kcontrol Operations IDs
|
||||
+ */
|
||||
+struct snd_soc_tplg_kcontrol_ops_id {
|
||||
+ __le32 get;
|
||||
+ __le32 put;
|
||||
+ __le32 info;
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * kcontrol header
|
||||
+ */
|
||||
+struct snd_soc_tplg_ctl_hdr {
|
||||
+ __le32 size; /* in bytes of this structure */
|
||||
+ __le32 type;
|
||||
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
+ __le32 access;
|
||||
+ struct snd_soc_tplg_kcontrol_ops_id ops;
|
||||
+ __le32 tlv_size; /* non zero means control has TLV data */
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * Stream Capabilities
|
||||
+ */
|
||||
+struct snd_soc_tplg_stream_caps {
|
||||
+ __le32 size; /* in bytes of this structure */
|
||||
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
+ __le64 formats[SND_SOC_TPLG_MAX_FORMATS]; /* supported formats SNDRV_PCM_FMTBIT_* */
|
||||
+ __le32 rates; /* supported rates SNDRV_PCM_RATE_* */
|
||||
+ __le32 rate_min; /* min rate */
|
||||
+ __le32 rate_max; /* max rate */
|
||||
+ __le32 channels_min; /* min channels */
|
||||
+ __le32 channels_max; /* max channels */
|
||||
+ __le32 periods_min; /* min number of periods */
|
||||
+ __le32 periods_max; /* max number of periods */
|
||||
+ __le32 period_size_min; /* min period size bytes */
|
||||
+ __le32 period_size_max; /* max period size bytes */
|
||||
+ __le32 buffer_size_min; /* min buffer size bytes */
|
||||
+ __le32 buffer_size_max; /* max buffer size bytes */
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * FE or BE Stream configuration supported by SW/FW
|
||||
+ */
|
||||
+struct snd_soc_tplg_stream {
|
||||
+ __le32 size; /* in bytes of this structure */
|
||||
+ __le64 format; /* SNDRV_PCM_FMTBIT_* */
|
||||
+ __le32 rate; /* SNDRV_PCM_RATE_* */
|
||||
+ __le32 period_bytes; /* size of period in bytes */
|
||||
+ __le32 buffer_bytes; /* size of buffer in bytes */
|
||||
+ __le32 channels; /* channels */
|
||||
+ __le32 tdm_slot; /* optional BE bitmask of supported TDM slots */
|
||||
+ __le32 dai_fmt; /* SND_SOC_DAIFMT_ */
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * Duplex stream configuration supported by SW/FW.
|
||||
+ */
|
||||
+struct snd_soc_tplg_stream_config {
|
||||
+ __le32 size; /* in bytes of this structure */
|
||||
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
+ struct snd_soc_tplg_stream playback;
|
||||
+ struct snd_soc_tplg_stream capture;
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * Manifest. List totals for each payload type. Not used in parsing, but will
|
||||
+ * be passed to the component driver before any other objects in order for any
|
||||
+ * global component resource allocations.
|
||||
+ *
|
||||
+ * File block representation for manifest :-
|
||||
+ * +-----------------------------------+----+
|
||||
+ * | struct snd_soc_tplg_hdr | 1 |
|
||||
+ * +-----------------------------------+----+
|
||||
+ * | struct snd_soc_tplg_manifest | 1 |
|
||||
+ * +-----------------------------------+----+
|
||||
+ */
|
||||
+struct snd_soc_tplg_manifest {
|
||||
+ __le32 size; /* in bytes of this structure */
|
||||
+ __le32 control_elems; /* number of control elements */
|
||||
+ __le32 widget_elems; /* number of widget elements */
|
||||
+ __le32 graph_elems; /* number of graph elements */
|
||||
+ __le32 dai_elems; /* number of DAI elements */
|
||||
+ __le32 dai_link_elems; /* number of DAI link elements */
|
||||
+ struct snd_soc_tplg_private priv;
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * Mixer kcontrol.
|
||||
+ *
|
||||
+ * File block representation for mixer kcontrol :-
|
||||
+ * +-----------------------------------+----+
|
||||
+ * | struct snd_soc_tplg_hdr | 1 |
|
||||
+ * +-----------------------------------+----+
|
||||
+ * | struct snd_soc_tplg_mixer_control | N |
|
||||
+ * +-----------------------------------+----+
|
||||
+ */
|
||||
+struct snd_soc_tplg_mixer_control {
|
||||
+ struct snd_soc_tplg_ctl_hdr hdr;
|
||||
+ __le32 size; /* in bytes of this structure */
|
||||
+ __le32 min;
|
||||
+ __le32 max;
|
||||
+ __le32 platform_max;
|
||||
+ __le32 invert;
|
||||
+ __le32 num_channels;
|
||||
+ struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
|
||||
+ struct snd_soc_tplg_ctl_tlv tlv;
|
||||
+ struct snd_soc_tplg_private priv;
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * Enumerated kcontrol
|
||||
+ *
|
||||
+ * File block representation for enum kcontrol :-
|
||||
+ * +-----------------------------------+----+
|
||||
+ * | struct snd_soc_tplg_hdr | 1 |
|
||||
+ * +-----------------------------------+----+
|
||||
+ * | struct snd_soc_tplg_enum_control | N |
|
||||
+ * +-----------------------------------+----+
|
||||
+ */
|
||||
+struct snd_soc_tplg_enum_control {
|
||||
+ struct snd_soc_tplg_ctl_hdr hdr;
|
||||
+ __le32 size; /* in bytes of this structure */
|
||||
+ __le32 num_channels;
|
||||
+ struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
|
||||
+ __le32 items;
|
||||
+ __le32 mask;
|
||||
+ __le32 count;
|
||||
+ char texts[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
+ __le32 values[SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN / 4];
|
||||
+ struct snd_soc_tplg_private priv;
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * Bytes kcontrol
|
||||
+ *
|
||||
+ * File block representation for bytes kcontrol :-
|
||||
+ * +-----------------------------------+----+
|
||||
+ * | struct snd_soc_tplg_hdr | 1 |
|
||||
+ * +-----------------------------------+----+
|
||||
+ * | struct snd_soc_tplg_bytes_control | N |
|
||||
+ * +-----------------------------------+----+
|
||||
+ */
|
||||
+struct snd_soc_tplg_bytes_control {
|
||||
+ struct snd_soc_tplg_ctl_hdr hdr;
|
||||
+ __le32 size; /* in bytes of this structure */
|
||||
+ __le32 max;
|
||||
+ __le32 mask;
|
||||
+ __le32 base;
|
||||
+ __le32 num_regs;
|
||||
+ struct snd_soc_tplg_private priv;
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * DAPM Graph Element
|
||||
+ *
|
||||
+ * File block representation for DAPM graph elements :-
|
||||
+ * +-------------------------------------+----+
|
||||
+ * | struct snd_soc_tplg_hdr | 1 |
|
||||
+ * +-------------------------------------+----+
|
||||
+ * | struct snd_soc_tplg_dapm_graph_elem | N |
|
||||
+ * +-------------------------------------+----+
|
||||
+ */
|
||||
+struct snd_soc_tplg_dapm_graph_elem {
|
||||
+ char sink[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
+ char control[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
+ char source[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * DAPM Widget.
|
||||
+ *
|
||||
+ * File block representation for DAPM widget :-
|
||||
+ * +-------------------------------------+-----+
|
||||
+ * | struct snd_soc_tplg_hdr | 1 |
|
||||
+ * +-------------------------------------+-----+
|
||||
+ * | struct snd_soc_tplg_dapm_widget | N |
|
||||
+ * +-------------------------------------+-----+
|
||||
+ * | struct snd_soc_tplg_enum_control | 0|1 |
|
||||
+ * | struct snd_soc_tplg_mixer_control | 0|N |
|
||||
+ * +-------------------------------------+-----+
|
||||
+ *
|
||||
+ * Optional enum or mixer control can be appended to the end of each widget
|
||||
+ * in the block.
|
||||
+ */
|
||||
+struct snd_soc_tplg_dapm_widget {
|
||||
+ __le32 size; /* in bytes of this structure */
|
||||
+ __le32 id; /* SND_SOC_DAPM_CTL */
|
||||
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
+ char sname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
+
|
||||
+ __le32 reg; /* negative reg = no direct dapm */
|
||||
+ __le32 shift; /* bits to shift */
|
||||
+ __le32 mask; /* non-shifted mask */
|
||||
+ __le32 subseq; /* sort within widget type */
|
||||
+ __u32 invert; /* invert the power bit */
|
||||
+ __u32 ignore_suspend; /* kept enabled over suspend */
|
||||
+ __u16 event_flags;
|
||||
+ __u16 event_type;
|
||||
+ __u16 num_kcontrols;
|
||||
+ struct snd_soc_tplg_private priv;
|
||||
+ /*
|
||||
+ * kcontrols that relate to this widget
|
||||
+ * follow here after widget private data
|
||||
+ */
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+struct snd_soc_tplg_pcm_cfg_caps {
|
||||
+ struct snd_soc_tplg_stream_caps caps;
|
||||
+ struct snd_soc_tplg_stream_config configs[SND_SOC_TPLG_STREAM_CONFIG_MAX];
|
||||
+ __le32 num_configs; /* number of configs */
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+/*
|
||||
+ * Describes SW/FW specific features of PCM or DAI link.
|
||||
+ *
|
||||
+ * File block representation for PCM/DAI-Link :-
|
||||
+ * +-----------------------------------+-----+
|
||||
+ * | struct snd_soc_tplg_hdr | 1 |
|
||||
+ * +-----------------------------------+-----+
|
||||
+ * | struct snd_soc_tplg_dapm_pcm_dai | N |
|
||||
+ * +-----------------------------------+-----+
|
||||
+ */
|
||||
+struct snd_soc_tplg_pcm_dai {
|
||||
+ __le32 size; /* in bytes of this structure */
|
||||
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
+ __le32 id; /* unique ID - used to match */
|
||||
+ __le32 playback; /* supports playback mode */
|
||||
+ __le32 capture; /* supports capture mode */
|
||||
+ __le32 compress; /* 1 = compressed; 0 = PCM */
|
||||
+ struct snd_soc_tplg_pcm_cfg_caps capconf[2]; /* capabilities and configs */
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+#endif
|
||||
diff --git a/include/sound/tlv.h b/include/sound/tlv.h
|
||||
new file mode 100644
|
||||
index 000000000000..33d747df1410
|
||||
--- /dev/null
|
||||
+++ b/include/sound/tlv.h
|
||||
@@ -0,0 +1,23 @@
|
||||
+/*
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __UAPI_SOUND_TLV_H
|
||||
+#define __UAPI_SOUND_TLV_H
|
||||
+
|
||||
+#define SNDRV_CTL_TLVT_CONTAINER 0 /* one level down - group of TLVs */
|
||||
+#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */
|
||||
+#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */
|
||||
+#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */
|
||||
+#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 */
|
||||
+
|
||||
+#endif
|
||||
--
|
||||
2.5.0
|
||||
|
1326
0036-topology-Add-topology-core-parser.patch
Normal file
1326
0036-topology-Add-topology-core-parser.patch
Normal file
File diff suppressed because it is too large
Load Diff
112
0037-topology-Add-text-section-parser.patch
Normal file
112
0037-topology-Add-text-section-parser.patch
Normal file
@ -0,0 +1,112 @@
|
||||
From 408396a8ca092846c840baa79c04b5f7dbe5da69 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:15 +0100
|
||||
Subject: [PATCH 37/49] topology: Add text section parser.
|
||||
|
||||
Parse text lists (like enum values) and store for later attachment
|
||||
to other objects.
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/topology/text.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 88 insertions(+)
|
||||
create mode 100644 src/topology/text.c
|
||||
|
||||
diff --git a/src/topology/text.c b/src/topology/text.c
|
||||
new file mode 100644
|
||||
index 000000000000..ebb6e3840d62
|
||||
--- /dev/null
|
||||
+++ b/src/topology/text.c
|
||||
@@ -0,0 +1,88 @@
|
||||
+/*
|
||||
+ Copyright(c) 2014-2015 Intel Corporation
|
||||
+ All rights reserved.
|
||||
+
|
||||
+ This program is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of version 2 of the GNU General Public License as
|
||||
+ published by the Free Software Foundation.
|
||||
+
|
||||
+ This program is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ Authors: Mengdong Lin <mengdong.lin@intel.com>
|
||||
+ Yao Jin <yao.jin@intel.com>
|
||||
+ Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
+
|
||||
+*/
|
||||
+
|
||||
+#include "list.h"
|
||||
+#include "tplg_local.h"
|
||||
+
|
||||
+#define TEXT_SIZE_MAX \
|
||||
+ (SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
|
||||
+
|
||||
+static int parse_text_values(snd_config_t *cfg, struct tplg_elem *elem)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *value = NULL;
|
||||
+ int j = 0;
|
||||
+
|
||||
+ tplg_dbg(" Text Values: %s\n", elem->id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+
|
||||
+ if (j == SND_SOC_TPLG_NUM_TEXTS) {
|
||||
+ tplg_dbg("error: text string number exceeds %d\n", j);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ /* get value */
|
||||
+ if (snd_config_get_string(n, &value) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ elem_copy_text(&elem->texts[j][0], value,
|
||||
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
||||
+ tplg_dbg("\t%s\n", &elem->texts[j][0]);
|
||||
+
|
||||
+ j++;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Parse Text data */
|
||||
+int tplg_parse_text(snd_tplg_t *tplg, snd_config_t *cfg,
|
||||
+ void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id;
|
||||
+ int err = 0;
|
||||
+ struct tplg_elem *elem;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_TEXT);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "values") == 0) {
|
||||
+ err = parse_text_values(n, elem);
|
||||
+ if (err < 0) {
|
||||
+ SNDERR("error: failed to parse text values");
|
||||
+ return err;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
--
|
||||
2.5.0
|
||||
|
664
0038-topology-Add-PCM-parser.patch
Normal file
664
0038-topology-Add-PCM-parser.patch
Normal file
@ -0,0 +1,664 @@
|
||||
From 4db19506c3e7a68a0d0be40422172f22605c58d8 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:16 +0100
|
||||
Subject: [PATCH 38/49] topology: Add PCM parser.
|
||||
|
||||
Parse PCM configurations and capabilities. These can then be used to define
|
||||
the capabilities and config for FE DAI links, PCM devices and
|
||||
codec <-> codec style links.
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/topology/pcm.c | 639 +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 639 insertions(+)
|
||||
create mode 100644 src/topology/pcm.c
|
||||
|
||||
diff --git a/src/topology/pcm.c b/src/topology/pcm.c
|
||||
new file mode 100644
|
||||
index 000000000000..8f23a6f12ec4
|
||||
--- /dev/null
|
||||
+++ b/src/topology/pcm.c
|
||||
@@ -0,0 +1,639 @@
|
||||
+/*
|
||||
+ Copyright(c) 2014-2015 Intel Corporation
|
||||
+ All rights reserved.
|
||||
+
|
||||
+ This program is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of version 2 of the GNU General Public License as
|
||||
+ published by the Free Software Foundation.
|
||||
+
|
||||
+ This program is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ Authors: Mengdong Lin <mengdong.lin@intel.com>
|
||||
+ Yao Jin <yao.jin@intel.com>
|
||||
+ Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
+*/
|
||||
+
|
||||
+#include "list.h"
|
||||
+#include "tplg_local.h"
|
||||
+
|
||||
+struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id)
|
||||
+{
|
||||
+ struct list_head *pos;
|
||||
+ struct tplg_elem *elem;
|
||||
+ struct snd_soc_tplg_pcm_dai *pcm_dai;
|
||||
+
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ elem = list_entry(pos, struct tplg_elem, list);
|
||||
+ if (elem->type != OBJECT_TYPE_PCM)
|
||||
+ return NULL;
|
||||
+
|
||||
+ pcm_dai = elem->pcm;
|
||||
+
|
||||
+ if (pcm_dai && (!strcmp(pcm_dai->capconf[0].caps.name, id)
|
||||
+ || !strcmp(pcm_dai->capconf[1].caps.name, id)))
|
||||
+ return elem;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+/* copy referenced caps to the pcm */
|
||||
+static void copy_pcm_caps(const char *id, struct snd_soc_tplg_stream_caps *caps,
|
||||
+ struct tplg_elem *ref_elem)
|
||||
+{
|
||||
+ struct snd_soc_tplg_stream_caps *ref_caps = ref_elem->stream_caps;
|
||||
+
|
||||
+ tplg_dbg("Copy pcm caps (%ld bytes) from '%s' to '%s' \n",
|
||||
+ sizeof(*caps), ref_elem->id, id);
|
||||
+
|
||||
+ *caps = *ref_caps;
|
||||
+}
|
||||
+
|
||||
+/* copy referenced config to the pcm */
|
||||
+static void copy_pcm_config(const char *id,
|
||||
+ struct snd_soc_tplg_stream_config *cfg, struct tplg_elem *ref_elem)
|
||||
+{
|
||||
+ struct snd_soc_tplg_stream_config *ref_cfg = ref_elem->stream_cfg;
|
||||
+
|
||||
+ tplg_dbg("Copy pcm config (%ld bytes) from '%s' to '%s' \n",
|
||||
+ sizeof(*cfg), ref_elem->id, id);
|
||||
+
|
||||
+ *cfg = *ref_cfg;
|
||||
+}
|
||||
+
|
||||
+/* check referenced config and caps for a pcm */
|
||||
+static int tplg_build_pcm_cfg_caps(snd_tplg_t *tplg, struct tplg_elem *elem)
|
||||
+{
|
||||
+ struct tplg_elem *ref_elem = NULL;
|
||||
+ struct snd_soc_tplg_pcm_cfg_caps *capconf;
|
||||
+ struct snd_soc_tplg_pcm_dai *pcm_dai;
|
||||
+ unsigned int i, j;
|
||||
+
|
||||
+ switch (elem->type) {
|
||||
+ case OBJECT_TYPE_PCM:
|
||||
+ pcm_dai = elem->pcm;
|
||||
+ break;
|
||||
+ case OBJECT_TYPE_BE:
|
||||
+ pcm_dai = elem->be;
|
||||
+ break;
|
||||
+ case OBJECT_TYPE_CC:
|
||||
+ pcm_dai = elem->cc;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < 2; i++) {
|
||||
+ capconf = &pcm_dai->capconf[i];
|
||||
+
|
||||
+ ref_elem = tplg_elem_lookup(&tplg->pcm_caps_list,
|
||||
+ capconf->caps.name, OBJECT_TYPE_STREAM_CAPS);
|
||||
+
|
||||
+ if (ref_elem != NULL)
|
||||
+ copy_pcm_caps(elem->id, &capconf->caps, ref_elem);
|
||||
+
|
||||
+ for (j = 0; j < capconf->num_configs; j++) {
|
||||
+ ref_elem = tplg_elem_lookup(&tplg->pcm_config_list,
|
||||
+ capconf->configs[j].name,
|
||||
+ OBJECT_TYPE_STREAM_CONFIG);
|
||||
+
|
||||
+ if (ref_elem != NULL)
|
||||
+ copy_pcm_config(elem->id,
|
||||
+ &capconf->configs[j],
|
||||
+ ref_elem);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int tplg_build_pcm_dai(snd_tplg_t *tplg, unsigned int type)
|
||||
+{
|
||||
+ struct list_head *base, *pos;
|
||||
+ struct tplg_elem *elem;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ switch (type) {
|
||||
+ case OBJECT_TYPE_PCM:
|
||||
+ base = &tplg->pcm_list;
|
||||
+ break;
|
||||
+ case OBJECT_TYPE_BE:
|
||||
+ base = &tplg->be_list;
|
||||
+ break;
|
||||
+ case OBJECT_TYPE_CC:
|
||||
+ base = &tplg->cc_list;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ elem = list_entry(pos, struct tplg_elem, list);
|
||||
+ if (elem->type != type) {
|
||||
+ SNDERR("error: invalid elem '%s'\n", elem->id);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ err = tplg_build_pcm_cfg_caps(tplg, elem);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* PCM stream configuration */
|
||||
+static int tplg_parse_stream_cfg(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
||||
+ snd_config_t *cfg, void *private)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ struct snd_soc_tplg_stream_config *sc = private;
|
||||
+ struct snd_soc_tplg_stream *stream;
|
||||
+ const char *id, *val;
|
||||
+ snd_pcm_format_t format;
|
||||
+ int ret;
|
||||
+
|
||||
+ snd_config_get_id(cfg, &id);
|
||||
+
|
||||
+ if (strcmp(id, "playback") == 0)
|
||||
+ stream = &sc->playback;
|
||||
+ else if (strcmp(id, "capture") == 0)
|
||||
+ stream = &sc->capture;
|
||||
+ else
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ tplg_dbg("\t%s:\n", id);
|
||||
+
|
||||
+ stream->size = sizeof(*stream);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (strcmp(id, "format") == 0) {
|
||||
+ format = snd_pcm_format_value(val);
|
||||
+ if (format == SND_PCM_FORMAT_UNKNOWN) {
|
||||
+ SNDERR("error: unsupported stream format %s\n",
|
||||
+ val);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ stream->format = format;
|
||||
+ tplg_dbg("\t\t%s: %s\n", id, val);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "rate") == 0) {
|
||||
+ stream->rate = atoi(val);
|
||||
+ tplg_dbg("\t\t%s: %d\n", id, stream->rate);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "channels") == 0) {
|
||||
+ stream->channels = atoi(val);
|
||||
+ tplg_dbg("\t\t%s: %d\n", id, stream->channels);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "tdm_slot") == 0) {
|
||||
+ stream->tdm_slot = strtol(val, NULL, 16);
|
||||
+ tplg_dbg("\t\t%s: 0x%x\n", id, stream->tdm_slot);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Parse pcm configuration */
|
||||
+int tplg_parse_pcm_config(snd_tplg_t *tplg,
|
||||
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ struct snd_soc_tplg_stream_config *sc;
|
||||
+ struct tplg_elem *elem;
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id;
|
||||
+ int err;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_STREAM_CONFIG);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ sc = elem->stream_cfg;
|
||||
+ sc->size = elem->size;
|
||||
+
|
||||
+ tplg_dbg(" PCM Config: %s\n", elem->id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* skip comments */
|
||||
+ if (strcmp(id, "comment") == 0)
|
||||
+ continue;
|
||||
+ if (id[0] == '#')
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "config") == 0) {
|
||||
+ err = tplg_parse_compound(tplg, n,
|
||||
+ tplg_parse_stream_cfg, sc);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int split_format(struct snd_soc_tplg_stream_caps *caps, char *str)
|
||||
+{
|
||||
+ char *s = NULL;
|
||||
+ snd_pcm_format_t format;
|
||||
+ int i = 0, ret;
|
||||
+
|
||||
+ s = strtok(str, ",");
|
||||
+ while ((s != NULL) && (i < SND_SOC_TPLG_MAX_FORMATS)) {
|
||||
+ format = snd_pcm_format_value(s);
|
||||
+ if (format == SND_PCM_FORMAT_UNKNOWN) {
|
||||
+ SNDERR("error: unsupported stream format %s\n", s);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ caps->formats[i] = format;
|
||||
+ s = strtok(NULL, ", ");
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Parse pcm Capabilities */
|
||||
+int tplg_parse_pcm_caps(snd_tplg_t *tplg,
|
||||
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ struct snd_soc_tplg_stream_caps *sc;
|
||||
+ struct tplg_elem *elem;
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id, *val;
|
||||
+ char *s;
|
||||
+ int err;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_STREAM_CAPS);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ sc = elem->stream_caps;
|
||||
+ sc->size = elem->size;
|
||||
+ elem_copy_text(sc->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
||||
+
|
||||
+ tplg_dbg(" PCM Capabilities: %s\n", elem->id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* skip comments */
|
||||
+ if (strcmp(id, "comment") == 0)
|
||||
+ continue;
|
||||
+ if (id[0] == '#')
|
||||
+ continue;
|
||||
+
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (strcmp(id, "formats") == 0) {
|
||||
+ s = strdup(val);
|
||||
+ if (s == NULL)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ err = split_format(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);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "rate_max") == 0) {
|
||||
+ sc->rate_max = atoi(val);
|
||||
+ tplg_dbg("\t\t%s: %d\n", id, sc->rate_max);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "channels_min") == 0) {
|
||||
+ sc->channels_min = atoi(val);
|
||||
+ tplg_dbg("\t\t%s: %d\n", id, sc->channels_min);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "channels_max") == 0) {
|
||||
+ sc->channels_max = atoi(val);
|
||||
+ tplg_dbg("\t\t%s: %d\n", id, sc->channels_max);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int tplg_parse_pcm_cfg(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
||||
+ snd_config_t *cfg, void *private)
|
||||
+{
|
||||
+ struct snd_soc_tplg_pcm_cfg_caps *capconf = private;
|
||||
+ struct snd_soc_tplg_stream_config *configs = capconf->configs;
|
||||
+ unsigned int *num_configs = &capconf->num_configs;
|
||||
+ const char *value;
|
||||
+
|
||||
+ if (*num_configs == SND_SOC_TPLG_STREAM_CONFIG_MAX)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (snd_config_get_string(cfg, &value) < 0)
|
||||
+ return EINVAL;
|
||||
+
|
||||
+ elem_copy_text(configs[*num_configs].name, value,
|
||||
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
||||
+
|
||||
+ *num_configs += 1;
|
||||
+
|
||||
+ tplg_dbg("\t\t\t%s\n", value);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Parse the cap and config of a pcm */
|
||||
+int tplg_parse_pcm_cap_cfg(snd_tplg_t *tplg, snd_config_t *cfg,
|
||||
+ void *private)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ struct tplg_elem *elem = private;
|
||||
+ struct snd_soc_tplg_pcm_dai *pcm_dai;
|
||||
+ const char *id, *value;
|
||||
+ int err, stream;
|
||||
+
|
||||
+ if (elem->type == OBJECT_TYPE_PCM)
|
||||
+ pcm_dai = elem->pcm;
|
||||
+ else if (elem->type == OBJECT_TYPE_BE)
|
||||
+ pcm_dai = elem->be;
|
||||
+ else if (elem->type == OBJECT_TYPE_CC)
|
||||
+ pcm_dai = elem->cc;
|
||||
+ else
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ snd_config_get_id(cfg, &id);
|
||||
+
|
||||
+ tplg_dbg("\t%s:\n", id);
|
||||
+
|
||||
+ if (strcmp(id, "playback") == 0) {
|
||||
+ stream = SND_SOC_TPLG_STREAM_PLAYBACK;
|
||||
+ pcm_dai->playback = 1;
|
||||
+ } else if (strcmp(id, "capture") == 0) {
|
||||
+ stream = SND_SOC_TPLG_STREAM_CAPTURE;
|
||||
+ pcm_dai->capture = 1;
|
||||
+ } else
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+
|
||||
+ /* get id */
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "capabilities") == 0) {
|
||||
+ if (snd_config_get_string(n, &value) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ elem_copy_text(pcm_dai->capconf[stream].caps.name, value,
|
||||
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
||||
+
|
||||
+ tplg_dbg("\t\t%s\n\t\t\t%s\n", id, value);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "configs") == 0) {
|
||||
+ tplg_dbg("\t\tconfigs:\n");
|
||||
+ err = tplg_parse_compound(tplg, n, tplg_parse_pcm_cfg,
|
||||
+ &pcm_dai->capconf[stream]);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Parse pcm */
|
||||
+int tplg_parse_pcm(snd_tplg_t *tplg,
|
||||
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ struct snd_soc_tplg_pcm_dai *pcm_dai;
|
||||
+ struct tplg_elem *elem;
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id, *val = NULL;
|
||||
+ int err;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_PCM);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pcm_dai = elem->pcm;
|
||||
+ pcm_dai->size = elem->size;
|
||||
+ elem_copy_text(pcm_dai->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
||||
+
|
||||
+ tplg_dbg(" PCM: %s\n", elem->id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* skip comments */
|
||||
+ if (strcmp(id, "comment") == 0)
|
||||
+ continue;
|
||||
+ if (id[0] == '#')
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "index") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ elem->index = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, elem->index);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "id") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ pcm_dai->id = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, pcm_dai->id);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "pcm") == 0) {
|
||||
+ err = tplg_parse_compound(tplg, n,
|
||||
+ tplg_parse_pcm_cap_cfg, elem);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Parse be */
|
||||
+int tplg_parse_be(snd_tplg_t *tplg,
|
||||
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ struct snd_soc_tplg_pcm_dai *pcm_dai;
|
||||
+ struct tplg_elem *elem;
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id, *val = NULL;
|
||||
+ int err;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_BE);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pcm_dai = elem->be;
|
||||
+ pcm_dai->size = elem->size;
|
||||
+ elem_copy_text(pcm_dai->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
||||
+
|
||||
+ tplg_dbg(" BE: %s\n", elem->id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* skip comments */
|
||||
+ if (strcmp(id, "comment") == 0)
|
||||
+ continue;
|
||||
+ if (id[0] == '#')
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "index") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ elem->index = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, elem->index);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "id") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ pcm_dai->id = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, pcm_dai->id);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "be") == 0) {
|
||||
+ err = tplg_parse_compound(tplg, n,
|
||||
+ tplg_parse_pcm_cap_cfg, elem);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Parse cc */
|
||||
+int tplg_parse_cc(snd_tplg_t *tplg,
|
||||
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ struct snd_soc_tplg_pcm_dai *pcm_dai;
|
||||
+ struct tplg_elem *elem;
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id, *val = NULL;
|
||||
+ int err;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_CC);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pcm_dai = elem->cc;
|
||||
+ pcm_dai->size = elem->size;
|
||||
+
|
||||
+ tplg_dbg(" CC: %s\n", elem->id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* skip comments */
|
||||
+ if (strcmp(id, "comment") == 0)
|
||||
+ continue;
|
||||
+ if (id[0] == '#')
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "index") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ elem->index = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, elem->index);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "id") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ pcm_dai->id = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, pcm_dai->id);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "cc") == 0) {
|
||||
+ err = tplg_parse_compound(tplg, n,
|
||||
+ tplg_parse_pcm_cap_cfg, elem);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--
|
||||
2.5.0
|
||||
|
107
0039-topology-Add-operations-parser.patch
Normal file
107
0039-topology-Add-operations-parser.patch
Normal file
@ -0,0 +1,107 @@
|
||||
From 353f1eddb608a837157342155fc061f85bf0a5f8 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:17 +0100
|
||||
Subject: [PATCH 39/49] topology: Add operations parser
|
||||
|
||||
Parse operations so we can bind them to kcontrols in the kernel.
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/topology/ops.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 84 insertions(+)
|
||||
create mode 100644 src/topology/ops.c
|
||||
|
||||
diff --git a/src/topology/ops.c b/src/topology/ops.c
|
||||
new file mode 100644
|
||||
index 000000000000..243d8c5e2bbc
|
||||
--- /dev/null
|
||||
+++ b/src/topology/ops.c
|
||||
@@ -0,0 +1,84 @@
|
||||
+/*
|
||||
+ Copyright(c) 2014-2015 Intel Corporation
|
||||
+ All rights reserved.
|
||||
+
|
||||
+ This program is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of version 2 of the GNU General Public License as
|
||||
+ published by the Free Software Foundation.
|
||||
+
|
||||
+ This program is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ Authors: Mengdong Lin <mengdong.lin@intel.com>
|
||||
+ Yao Jin <yao.jin@intel.com>
|
||||
+ Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
+*/
|
||||
+
|
||||
+#include "list.h"
|
||||
+#include "tplg_local.h"
|
||||
+
|
||||
+/* mapping of kcontrol text names to types */
|
||||
+static const struct map_elem control_map[] = {
|
||||
+ {"volsw", SND_SOC_TPLG_CTL_VOLSW},
|
||||
+ {"volsw_sx", SND_SOC_TPLG_CTL_VOLSW_SX},
|
||||
+ {"volsw_xr_sx", SND_SOC_TPLG_CTL_VOLSW_XR_SX},
|
||||
+ {"enum", SND_SOC_TPLG_CTL_ENUM},
|
||||
+ {"bytes", SND_SOC_TPLG_CTL_BYTES},
|
||||
+ {"enum_value", SND_SOC_TPLG_CTL_ENUM_VALUE},
|
||||
+ {"range", SND_SOC_TPLG_CTL_RANGE},
|
||||
+ {"strobe", SND_SOC_TPLG_CTL_STROBE},
|
||||
+};
|
||||
+
|
||||
+static int lookup_ops(const char *c)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(control_map); i++) {
|
||||
+ if (strcmp(control_map[i].name, c) == 0)
|
||||
+ return control_map[i].id;
|
||||
+ }
|
||||
+
|
||||
+ /* cant find string name in our table so we use its ID number */
|
||||
+ return atoi(c);
|
||||
+}
|
||||
+
|
||||
+/* Parse Control operations. Ops can come from standard names above or
|
||||
+ * bespoke driver controls with numbers >= 256
|
||||
+ */
|
||||
+int tplg_parse_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
||||
+ snd_config_t *cfg, void *private)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ struct snd_soc_tplg_ctl_hdr *hdr = private;
|
||||
+ const char *id, *value;
|
||||
+
|
||||
+ tplg_dbg("\tOps\n");
|
||||
+ hdr->size = sizeof(*hdr);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+
|
||||
+ /* get id */
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* get value - try strings then ints */
|
||||
+ if (snd_config_get_string(n, &value) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "info") == 0)
|
||||
+ hdr->ops.info = lookup_ops(value);
|
||||
+ else if (strcmp(id, "put") == 0)
|
||||
+ hdr->ops.put = lookup_ops(value);
|
||||
+ else if (strcmp(id, "get") == 0)
|
||||
+ hdr->ops.get = lookup_ops(value);
|
||||
+
|
||||
+ tplg_dbg("\t\t%s = %s\n", id, value);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--
|
||||
2.5.0
|
||||
|
420
0040-topology-Add-private-data-parser.patch
Normal file
420
0040-topology-Add-private-data-parser.patch
Normal file
@ -0,0 +1,420 @@
|
||||
From 5b379da2a0a1084349e918a52f471c03e37af703 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:18 +0100
|
||||
Subject: [PATCH 40/49] topology: Add private data parser
|
||||
|
||||
Parse private data and store for attachment to other objects. Data can come
|
||||
file or be locally defined as bytes, shorts or words.
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/topology/data.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 396 insertions(+)
|
||||
create mode 100644 src/topology/data.c
|
||||
|
||||
diff --git a/src/topology/data.c b/src/topology/data.c
|
||||
new file mode 100644
|
||||
index 000000000000..ae664721935d
|
||||
--- /dev/null
|
||||
+++ b/src/topology/data.c
|
||||
@@ -0,0 +1,396 @@
|
||||
+/*
|
||||
+ Copyright(c) 2014-2015 Intel Corporation
|
||||
+ All rights reserved.
|
||||
+
|
||||
+ This program is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of version 2 of the GNU General Public License as
|
||||
+ published by the Free Software Foundation.
|
||||
+
|
||||
+ This program is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ Authors: Mengdong Lin <mengdong.lin@intel.com>
|
||||
+ Yao Jin <yao.jin@intel.com>
|
||||
+ Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
+*/
|
||||
+
|
||||
+#include "list.h"
|
||||
+#include "tplg_local.h"
|
||||
+
|
||||
+/* Get Private data from a file. */
|
||||
+static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
|
||||
+{
|
||||
+ struct snd_soc_tplg_private *priv = NULL;
|
||||
+ const char *value = NULL;
|
||||
+ char filename[MAX_FILE];
|
||||
+ char *env = getenv(ALSA_CONFIG_TPLG_VAR);
|
||||
+ FILE *fp;
|
||||
+ size_t size, bytes_read;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ tplg_dbg("data DataFile: %s\n", elem->id);
|
||||
+
|
||||
+ if (snd_config_get_string(cfg, &value) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* prepend alsa config directory to path */
|
||||
+ snprintf(filename, sizeof(filename), "%s/%s",
|
||||
+ env ? env : ALSA_TPLG_DIR, value);
|
||||
+
|
||||
+ fp = fopen(filename, "r");
|
||||
+ if (fp == NULL) {
|
||||
+ SNDERR("error: invalid data file path '%s'\n",
|
||||
+ filename);
|
||||
+ ret = -errno;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ fseek(fp, 0L, SEEK_END);
|
||||
+ size = ftell(fp);
|
||||
+ fseek(fp, 0L, SEEK_SET);
|
||||
+ if (size <= 0) {
|
||||
+ SNDERR("error: invalid data file size %zu\n", size);
|
||||
+ ret = -EINVAL;
|
||||
+ goto err;
|
||||
+ }
|
||||
+ if (size > TPLG_MAX_PRIV_SIZE) {
|
||||
+ SNDERR("error: data file too big %zu\n", size);
|
||||
+ ret = -EINVAL;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ priv = calloc(1, sizeof(*priv) + size);
|
||||
+ if (!priv) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ bytes_read = fread(&priv->data, 1, size, fp);
|
||||
+ if (bytes_read != size) {
|
||||
+ ret = -errno;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ elem->data = priv;
|
||||
+ priv->size = size;
|
||||
+ elem->size = sizeof(*priv) + size;
|
||||
+ return 0;
|
||||
+
|
||||
+err:
|
||||
+ if (priv)
|
||||
+ free(priv);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+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",
|
||||
+ elem->size, priv->size);
|
||||
+
|
||||
+ for (i = 0; i < priv->size; i++) {
|
||||
+ if (j++ % 8 == 0)
|
||||
+ tplg_dbg("\n");
|
||||
+
|
||||
+ tplg_dbg(" 0x%x", *p++);
|
||||
+ }
|
||||
+
|
||||
+ tplg_dbg("\n\n");
|
||||
+}
|
||||
+
|
||||
+/* get number of hex value elements in CSV list */
|
||||
+static int get_hex_num(const char *str)
|
||||
+{
|
||||
+ int commas = 0, values = 0, len = strlen(str);
|
||||
+ const char *end = str + len;
|
||||
+
|
||||
+ /* we expect "0x0, 0x0, 0x0" */
|
||||
+ while (str < end) {
|
||||
+
|
||||
+ /* skip white space */
|
||||
+ if (isspace(*str)) {
|
||||
+ str++;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* find delimeters */
|
||||
+ if (*str == ',') {
|
||||
+ commas++;
|
||||
+ str++;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* find 0x[0-9] values */
|
||||
+ if (*str == '0' && str + 2 <= end) {
|
||||
+ if (str[1] == 'x' && str[2] >= '0' && str[2] <= 'f') {
|
||||
+ values++;
|
||||
+ str += 3;
|
||||
+ } else {
|
||||
+ str++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ str++;
|
||||
+ }
|
||||
+
|
||||
+ /* there should always be one less comma than value */
|
||||
+ if (values -1 != commas)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return values;
|
||||
+}
|
||||
+
|
||||
+static int write_hex(char *buf, char *str, int width)
|
||||
+{
|
||||
+ long val;
|
||||
+ void *p = &val;
|
||||
+
|
||||
+ errno = 0;
|
||||
+ val = strtol(str, NULL, 16);
|
||||
+
|
||||
+ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
|
||||
+ || (errno != 0 && val == 0)) {
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ switch (width) {
|
||||
+ case 1:
|
||||
+ *(unsigned char *)buf = *(unsigned char *)p;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ *(unsigned short *)buf = *(unsigned short *)p;
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ *(unsigned int *)buf = *(unsigned int *)p;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int copy_data_hex(char *data, int off, const char *str, int width)
|
||||
+{
|
||||
+ char *tmp, *s = NULL, *p = data;
|
||||
+ int ret;
|
||||
+
|
||||
+ tmp = strdup(str);
|
||||
+ if (tmp == NULL)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ p += off;
|
||||
+ s = strtok(tmp, ",");
|
||||
+
|
||||
+ while (s != NULL) {
|
||||
+ ret = write_hex(p, s, width);
|
||||
+ if (ret < 0) {
|
||||
+ free(tmp);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ s = strtok(NULL, ",");
|
||||
+ p += width;
|
||||
+ }
|
||||
+
|
||||
+ free(tmp);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem,
|
||||
+ int width)
|
||||
+{
|
||||
+ struct snd_soc_tplg_private *priv;
|
||||
+ const char *value = NULL;
|
||||
+ int size, esize, off, num;
|
||||
+ int ret;
|
||||
+
|
||||
+ tplg_dbg(" data: %s\n", elem->id);
|
||||
+
|
||||
+ if (snd_config_get_string(cfg, &value) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ num = get_hex_num(value);
|
||||
+ if (num <= 0) {
|
||||
+ SNDERR("error: malformed hex variable list %s\n", value);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ size = num * width;
|
||||
+ priv = elem->data;
|
||||
+
|
||||
+ if (esize > TPLG_MAX_PRIV_SIZE) {
|
||||
+ SNDERR("error: data too big %d\n", esize);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (priv != NULL) {
|
||||
+ off = priv->size;
|
||||
+ esize = elem->size + size;
|
||||
+ priv = realloc(priv, esize);
|
||||
+ } else {
|
||||
+ off = 0;
|
||||
+ esize = sizeof(*priv) + size;
|
||||
+ priv = calloc(1, esize);
|
||||
+ }
|
||||
+
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ elem->data = priv;
|
||||
+ priv->size += size;
|
||||
+ elem->size = esize;
|
||||
+
|
||||
+ ret = copy_data_hex(priv->data, off, value, width);
|
||||
+
|
||||
+ dump_priv_data(elem);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* Parse Private data.
|
||||
+ *
|
||||
+ * Object private data can either be from file or defined as bytes, shorts,
|
||||
+ * words.
|
||||
+ */
|
||||
+int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
|
||||
+ void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id, *val = NULL;
|
||||
+ int err = 0;
|
||||
+ struct tplg_elem *elem;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_DATA);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "file") == 0) {
|
||||
+ err = tplg_parse_data_file(n, elem);
|
||||
+ if (err < 0) {
|
||||
+ SNDERR("error: failed to parse data file\n");
|
||||
+ return err;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "bytes") == 0) {
|
||||
+ err = tplg_parse_data_hex(n, elem, 1);
|
||||
+ if (err < 0) {
|
||||
+ SNDERR("error: failed to parse data bytes\n");
|
||||
+ return err;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "shorts") == 0) {
|
||||
+ err = tplg_parse_data_hex(n, elem, 2);
|
||||
+ if (err < 0) {
|
||||
+ SNDERR("error: failed to parse data shorts\n");
|
||||
+ return err;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "words") == 0) {
|
||||
+ err = tplg_parse_data_hex(n, elem, 4);
|
||||
+ if (err < 0) {
|
||||
+ SNDERR("error: failed to parse data words\n");
|
||||
+ return err;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "index") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ elem->index = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, elem->index);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "type") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ elem->vendor_type = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, elem->index);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+/* copy private data into the bytes extended control */
|
||||
+int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref)
|
||||
+{
|
||||
+ struct snd_soc_tplg_private *priv;
|
||||
+ int priv_data_size;
|
||||
+
|
||||
+ if (!ref)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ tplg_dbg("Data '%s' used by '%s'\n", ref->id, elem->id);
|
||||
+ priv_data_size = ref->data->size;
|
||||
+
|
||||
+ switch (elem->type) {
|
||||
+ case OBJECT_TYPE_MIXER:
|
||||
+ elem->mixer_ctrl = realloc(elem->mixer_ctrl,
|
||||
+ elem->size + priv_data_size);
|
||||
+ if (!elem->mixer_ctrl)
|
||||
+ return -ENOMEM;
|
||||
+ priv = &elem->mixer_ctrl->priv;
|
||||
+ break;
|
||||
+
|
||||
+ case OBJECT_TYPE_ENUM:
|
||||
+ elem->enum_ctrl = realloc(elem->enum_ctrl,
|
||||
+ elem->size + priv_data_size);
|
||||
+ if (!elem->enum_ctrl)
|
||||
+ return -ENOMEM;
|
||||
+ priv = &elem->enum_ctrl->priv;
|
||||
+ break;
|
||||
+
|
||||
+ case OBJECT_TYPE_BYTES:
|
||||
+ elem->bytes_ext = realloc(elem->bytes_ext,
|
||||
+ elem->size + priv_data_size);
|
||||
+ if (!elem->bytes_ext)
|
||||
+ return -ENOMEM;
|
||||
+ priv = &elem->bytes_ext->priv;
|
||||
+ break;
|
||||
+
|
||||
+
|
||||
+ case OBJECT_TYPE_DAPM_WIDGET:
|
||||
+ elem->widget = realloc(elem->widget,
|
||||
+ elem->size + priv_data_size);
|
||||
+ if (!elem->widget)
|
||||
+ return -ENOMEM;
|
||||
+ priv = &elem->widget->priv;
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ SNDERR("elem '%s': type %d private data not supported \n",
|
||||
+ elem->id, elem->type);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ elem->size += priv_data_size;
|
||||
+ priv->size = priv_data_size;
|
||||
+ ref->compound_elem = 1;
|
||||
+ memcpy(priv->data, ref->data->data, priv_data_size);
|
||||
+ return 0;
|
||||
+}
|
||||
--
|
||||
2.5.0
|
||||
|
585
0041-topology-Add-DAPM-object-parser.patch
Normal file
585
0041-topology-Add-DAPM-object-parser.patch
Normal file
@ -0,0 +1,585 @@
|
||||
From 01a0e1a1c2196967d2522092ca993098a7c66613 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:19 +0100
|
||||
Subject: [PATCH 41/49] topology: Add DAPM object parser
|
||||
|
||||
Parse DAPM objects including widgets and graph elements.
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/topology/dapm.c | 562 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 562 insertions(+)
|
||||
create mode 100644 src/topology/dapm.c
|
||||
|
||||
diff --git a/src/topology/dapm.c b/src/topology/dapm.c
|
||||
new file mode 100644
|
||||
index 000000000000..1da82adea470
|
||||
--- /dev/null
|
||||
+++ b/src/topology/dapm.c
|
||||
@@ -0,0 +1,562 @@
|
||||
+/*
|
||||
+ Copyright(c) 2014-2015 Intel Corporation
|
||||
+ All rights reserved.
|
||||
+
|
||||
+ This program is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of version 2 of the GNU General Public License as
|
||||
+ published by the Free Software Foundation.
|
||||
+
|
||||
+ This program is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ Authors: Mengdong Lin <mengdong.lin@intel.com>
|
||||
+ Yao Jin <yao.jin@intel.com>
|
||||
+ Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
+*/
|
||||
+
|
||||
+#include "list.h"
|
||||
+#include "tplg_local.h"
|
||||
+
|
||||
+/* mapping of widget text names to types */
|
||||
+static const struct map_elem widget_map[] = {
|
||||
+ {"input", SND_SOC_TPLG_DAPM_INPUT},
|
||||
+ {"output", SND_SOC_TPLG_DAPM_OUTPUT},
|
||||
+ {"mux", SND_SOC_TPLG_DAPM_MUX},
|
||||
+ {"mixer", SND_SOC_TPLG_DAPM_MIXER},
|
||||
+ {"pga", SND_SOC_TPLG_DAPM_PGA},
|
||||
+ {"out_drv", SND_SOC_TPLG_DAPM_OUT_DRV},
|
||||
+ {"adc", SND_SOC_TPLG_DAPM_ADC},
|
||||
+ {"dac", SND_SOC_TPLG_DAPM_DAC},
|
||||
+ {"switch", SND_SOC_TPLG_DAPM_SWITCH},
|
||||
+ {"pre", SND_SOC_TPLG_DAPM_PRE},
|
||||
+ {"post", SND_SOC_TPLG_DAPM_POST},
|
||||
+ {"aif_in", SND_SOC_TPLG_DAPM_AIF_IN},
|
||||
+ {"aif_out", SND_SOC_TPLG_DAPM_AIF_OUT},
|
||||
+ {"dai_in", SND_SOC_TPLG_DAPM_DAI_IN},
|
||||
+ {"dai_out", SND_SOC_TPLG_DAPM_DAI_OUT},
|
||||
+ {"dai_link", SND_SOC_TPLG_DAPM_DAI_LINK},
|
||||
+};
|
||||
+
|
||||
+/* mapping of widget kcontrol text names to types */
|
||||
+static const struct map_elem widget_control_map[] = {
|
||||
+ {"volsw", SND_SOC_TPLG_DAPM_CTL_VOLSW},
|
||||
+ {"enum_double", SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE},
|
||||
+ {"enum_virt", SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT},
|
||||
+ {"enum_value", SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE},
|
||||
+};
|
||||
+
|
||||
+static int lookup_widget(const char *w)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(widget_map); i++) {
|
||||
+ if (strcmp(widget_map[i].name, w) == 0)
|
||||
+ return widget_map[i].id;
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static int tplg_parse_dapm_mixers(snd_config_t *cfg, struct tplg_elem *elem)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *value = NULL;
|
||||
+
|
||||
+ tplg_dbg(" DAPM Mixer Controls: %s\n", elem->id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+
|
||||
+ /* get value */
|
||||
+ if (snd_config_get_string(n, &value) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ tplg_ref_add(elem, OBJECT_TYPE_MIXER, value);
|
||||
+ tplg_dbg("\t\t %s\n", value);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int tplg_parse_dapm_enums(snd_config_t *cfg, struct tplg_elem *elem)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *value = NULL;
|
||||
+
|
||||
+ tplg_dbg(" DAPM Enum Controls: %s\n", elem->id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+
|
||||
+ /* get value */
|
||||
+ if (snd_config_get_string(n, &value) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ tplg_ref_add(elem, OBJECT_TYPE_ENUM, value);
|
||||
+ tplg_dbg("\t\t %s\n", value);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* move referenced controls to the widget */
|
||||
+static int copy_dapm_control(struct tplg_elem *elem, struct tplg_elem *ref)
|
||||
+{
|
||||
+ struct snd_soc_tplg_dapm_widget *widget = elem->widget;
|
||||
+ struct snd_soc_tplg_mixer_control *mixer_ctrl = ref->mixer_ctrl;
|
||||
+ struct snd_soc_tplg_enum_control *enum_ctrl = ref->enum_ctrl;
|
||||
+
|
||||
+ tplg_dbg("Control '%s' used by '%s'\n", ref->id, elem->id);
|
||||
+ tplg_dbg("\tparent size: %d + %d -> %d, priv size -> %d\n",
|
||||
+ elem->size, ref->size, elem->size + ref->size,
|
||||
+ widget->priv.size);
|
||||
+
|
||||
+ widget = realloc(widget, elem->size + ref->size);
|
||||
+ if (!widget)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ elem->widget = widget;
|
||||
+
|
||||
+ /* copy new widget at the end */
|
||||
+ if (ref->type == OBJECT_TYPE_MIXER)
|
||||
+ memcpy((void*)widget + elem->size, mixer_ctrl, ref->size);
|
||||
+ else if (ref->type == OBJECT_TYPE_ENUM)
|
||||
+ memcpy((void*)widget + elem->size, enum_ctrl, ref->size);
|
||||
+
|
||||
+ elem->size += ref->size;
|
||||
+ widget->num_kcontrols++;
|
||||
+ ref->compound_elem = 1;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* check referenced controls for a widget */
|
||||
+static int tplg_build_widget(snd_tplg_t *tplg,
|
||||
+ struct tplg_elem *elem)
|
||||
+{
|
||||
+ struct tplg_ref *ref;
|
||||
+ struct list_head *base, *pos;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ base = &elem->ref_list;
|
||||
+
|
||||
+ /* for each ref in this control elem */
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ ref = list_entry(pos, struct tplg_ref, list);
|
||||
+ if (ref->id == NULL || ref->elem)
|
||||
+ continue;
|
||||
+
|
||||
+ switch (ref->type) {
|
||||
+ case OBJECT_TYPE_MIXER:
|
||||
+ ref->elem = tplg_elem_lookup(&tplg->mixer_list,
|
||||
+ ref->id, OBJECT_TYPE_MIXER);
|
||||
+ if (ref->elem)
|
||||
+ err = copy_dapm_control(elem, ref->elem);
|
||||
+ break;
|
||||
+
|
||||
+ case OBJECT_TYPE_ENUM:
|
||||
+ ref->elem = tplg_elem_lookup(&tplg->enum_list,
|
||||
+ ref->id, OBJECT_TYPE_ENUM);
|
||||
+ if (ref->elem)
|
||||
+ err = copy_dapm_control(elem, ref->elem);
|
||||
+ break;
|
||||
+
|
||||
+ case OBJECT_TYPE_DATA:
|
||||
+ ref->elem = tplg_elem_lookup(&tplg->pdata_list,
|
||||
+ ref->id, OBJECT_TYPE_DATA);
|
||||
+ if (ref->elem)
|
||||
+ err = tplg_copy_data(elem, ref->elem);
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (!ref->elem) {
|
||||
+ SNDERR("error: cannot find control '%s'"
|
||||
+ " referenced by widget '%s'\n",
|
||||
+ ref->id, elem->id);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int tplg_build_widgets(snd_tplg_t *tplg)
|
||||
+{
|
||||
+
|
||||
+ struct list_head *base, *pos;
|
||||
+ struct tplg_elem *elem;
|
||||
+ int err;
|
||||
+
|
||||
+ base = &tplg->widget_list;
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ elem = list_entry(pos, struct tplg_elem, list);
|
||||
+ if (!elem->widget || elem->type != OBJECT_TYPE_DAPM_WIDGET) {
|
||||
+ SNDERR("error: invalid widget '%s'\n",
|
||||
+ elem->id);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ err = tplg_build_widget(tplg, elem);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ /* add widget to manifest */
|
||||
+ tplg->manifest.widget_elems++;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int tplg_build_routes(snd_tplg_t *tplg)
|
||||
+{
|
||||
+ struct list_head *base, *pos;
|
||||
+ struct tplg_elem *elem;
|
||||
+ struct snd_soc_tplg_dapm_graph_elem *route;
|
||||
+
|
||||
+ base = &tplg->route_list;
|
||||
+
|
||||
+ list_for_each(pos, base) {
|
||||
+ elem = list_entry(pos, struct tplg_elem, list);
|
||||
+
|
||||
+ if (!elem->route || elem->type != OBJECT_TYPE_DAPM_GRAPH) {
|
||||
+ SNDERR("error: invalid route '%s'\n",
|
||||
+ elem->id);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ route = elem->route;
|
||||
+ tplg_dbg("\nCheck route: sink '%s', control '%s', source '%s'\n",
|
||||
+ route->sink, route->control, route->source);
|
||||
+
|
||||
+ /* validate sink */
|
||||
+ if (strlen(route->sink) <= 0) {
|
||||
+ SNDERR("error: no sink\n");
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ }
|
||||
+ if (!tplg_elem_lookup(&tplg->widget_list, route->sink,
|
||||
+ OBJECT_TYPE_DAPM_WIDGET)) {
|
||||
+ SNDERR("warning: undefined sink widget/stream '%s'\n",
|
||||
+ route->sink);
|
||||
+ }
|
||||
+
|
||||
+ /* validate control name */
|
||||
+ if (strlen(route->control)) {
|
||||
+ if (!tplg_elem_lookup(&tplg->mixer_list,
|
||||
+ route->control, OBJECT_TYPE_MIXER) &&
|
||||
+ !tplg_elem_lookup(&tplg->enum_list,
|
||||
+ route->control, OBJECT_TYPE_ENUM)) {
|
||||
+ SNDERR("warning: Undefined mixer/enum control '%s'\n",
|
||||
+ route->control);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* validate source */
|
||||
+ if (strlen(route->source) <= 0) {
|
||||
+ SNDERR("error: no source\n");
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ }
|
||||
+ if (!tplg_elem_lookup(&tplg->widget_list, route->source,
|
||||
+ OBJECT_TYPE_DAPM_WIDGET)) {
|
||||
+ SNDERR("warning: Undefined source widget/stream '%s'\n",
|
||||
+ route->source);
|
||||
+ }
|
||||
+
|
||||
+ /* add graph to manifest */
|
||||
+ tplg->manifest.graph_elems++;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#define LINE_SIZE 1024
|
||||
+
|
||||
+/* line is defined as '"source, control, sink"' */
|
||||
+static int tplg_parse_line(const char *text,
|
||||
+ struct snd_soc_tplg_dapm_graph_elem *line)
|
||||
+{
|
||||
+ char buf[LINE_SIZE];
|
||||
+ unsigned int len, i;
|
||||
+ const char *source = NULL, *sink = NULL, *control = NULL;
|
||||
+
|
||||
+ elem_copy_text(buf, text, LINE_SIZE);
|
||||
+
|
||||
+ len = strlen(buf);
|
||||
+ if (len <= 2) {
|
||||
+ SNDERR("error: invalid route \"%s\"\n", buf);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* find first , */
|
||||
+ for (i = 1; i < len; i++) {
|
||||
+ if (buf[i] == ',')
|
||||
+ goto second;
|
||||
+ }
|
||||
+ SNDERR("error: invalid route \"%s\"\n", buf);
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+second:
|
||||
+ /* find second , */
|
||||
+ sink = buf;
|
||||
+ control = &buf[i + 2];
|
||||
+ buf[i] = 0;
|
||||
+
|
||||
+ for (; i < len; i++) {
|
||||
+ if (buf[i] == ',')
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ SNDERR("error: invalid route \"%s\"\n", buf);
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+done:
|
||||
+ buf[i] = 0;
|
||||
+ source = &buf[i + 2];
|
||||
+
|
||||
+ strcpy(line->source, source);
|
||||
+ strcpy(line->control, control);
|
||||
+ strcpy(line->sink, sink);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int tplg_parse_routes(snd_tplg_t *tplg, snd_config_t *cfg)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ struct tplg_elem *elem;
|
||||
+ struct snd_soc_tplg_dapm_graph_elem *line = NULL;
|
||||
+ int err;
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+ const char *val;
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ elem = tplg_elem_new();
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ list_add_tail(&elem->list, &tplg->route_list);
|
||||
+ strcpy(elem->id, "line");
|
||||
+ elem->type = OBJECT_TYPE_DAPM_GRAPH;
|
||||
+ elem->size = sizeof(*line);
|
||||
+
|
||||
+ line = calloc(1, sizeof(*line));
|
||||
+ if (!line)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ elem->route = line;
|
||||
+
|
||||
+ err = tplg_parse_line(val, line);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ tplg_dbg("route: sink '%s', control '%s', source '%s'\n",
|
||||
+ line->sink, line->control, line->source);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg,
|
||||
+ void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ int err;
|
||||
+ const char *graph_id;
|
||||
+
|
||||
+ if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
|
||||
+ SNDERR("error: compound is expected for dapm graph definition\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ snd_config_get_id(cfg, &graph_id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+ const char *id;
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "lines") == 0) {
|
||||
+ err = tplg_parse_routes(tplg, n);
|
||||
+ if (err < 0) {
|
||||
+ SNDERR("error: failed to parse dapm graph %s\n",
|
||||
+ graph_id);
|
||||
+ return err;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* DAPM Widget */
|
||||
+int tplg_parse_dapm_widget(snd_tplg_t *tplg,
|
||||
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ struct snd_soc_tplg_dapm_widget *widget;
|
||||
+ struct tplg_elem *elem;
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id, *val = NULL;
|
||||
+ int widget_type, err;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_DAPM_WIDGET);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ tplg_dbg(" Widget: %s\n", elem->id);
|
||||
+
|
||||
+ widget = elem->widget;
|
||||
+ elem_copy_text(widget->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
||||
+ widget->size = elem->size;
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* skip comments */
|
||||
+ if (strcmp(id, "comment") == 0)
|
||||
+ continue;
|
||||
+ if (id[0] == '#')
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "index") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ elem->index = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, elem->index);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "type") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ widget_type = lookup_widget(val);
|
||||
+ if (widget_type < 0){
|
||||
+ SNDERR("Widget '%s': Unsupported widget type %s\n",
|
||||
+ elem->id, val);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ widget->id = widget_type;
|
||||
+ tplg_dbg("\t%s: %s\n", id, val);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "no_pm") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (strcmp(val, "true") == 0)
|
||||
+ widget->reg = -1;
|
||||
+
|
||||
+ tplg_dbg("\t%s: %s\n", id, val);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "shift") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ widget->shift = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, widget->shift);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "reg") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ widget->reg = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, widget->reg);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "invert") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ widget->invert = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, widget->invert);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "subseq") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ widget->subseq= atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, widget->subseq);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "event_type") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ widget->event_type = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, widget->event_type);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "event_flags") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ widget->event_flags = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, widget->event_flags);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "enum") == 0) {
|
||||
+ err = tplg_parse_dapm_enums(n, elem);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "mixer") == 0) {
|
||||
+ err = tplg_parse_dapm_mixers(n, elem);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "data") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ tplg_ref_add(elem, OBJECT_TYPE_DATA, val);
|
||||
+ tplg_dbg("\t%s: %s\n", id, val);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--
|
||||
2.5.0
|
||||
|
636
0042-topology-Add-CTL-parser.patch
Normal file
636
0042-topology-Add-CTL-parser.patch
Normal file
@ -0,0 +1,636 @@
|
||||
From 694b857ce7b44a333c4f5e8b12f1b6cdf1c12388 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:20 +0100
|
||||
Subject: [PATCH 42/49] topology: Add CTL parser
|
||||
|
||||
Add support to parse mixers, enums and byte controls.
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/topology/ctl.c | 613 +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 613 insertions(+)
|
||||
create mode 100644 src/topology/ctl.c
|
||||
|
||||
diff --git a/src/topology/ctl.c b/src/topology/ctl.c
|
||||
new file mode 100644
|
||||
index 000000000000..9c1333c1fc88
|
||||
--- /dev/null
|
||||
+++ b/src/topology/ctl.c
|
||||
@@ -0,0 +1,613 @@
|
||||
+/*
|
||||
+ Copyright(c) 2014-2015 Intel Corporation
|
||||
+ All rights reserved.
|
||||
+
|
||||
+ This program is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of version 2 of the GNU General Public License as
|
||||
+ published by the Free Software Foundation.
|
||||
+
|
||||
+ This program is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ Authors: Mengdong Lin <mengdong.lin@intel.com>
|
||||
+ Yao Jin <yao.jin@intel.com>
|
||||
+ Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
+*/
|
||||
+
|
||||
+#include "list.h"
|
||||
+#include "tplg_local.h"
|
||||
+
|
||||
+/* copy referenced TLV to the mixer control */
|
||||
+static int copy_tlv(struct tplg_elem *elem, struct tplg_elem *ref)
|
||||
+{
|
||||
+ struct snd_soc_tplg_mixer_control *mixer_ctrl = elem->mixer_ctrl;
|
||||
+ struct snd_soc_tplg_ctl_tlv *tlv = ref->tlv;
|
||||
+
|
||||
+ tplg_dbg("TLV '%s' used by '%s\n", ref->id, elem->id);
|
||||
+
|
||||
+ /* TLV has a fixed size */
|
||||
+ mixer_ctrl->tlv = *tlv;
|
||||
+
|
||||
+ /* set size of TLV data */
|
||||
+ mixer_ctrl->hdr.tlv_size = tlv->count * sizeof(uint32_t);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* check referenced TLV for a mixer control */
|
||||
+static int tplg_build_mixer_control(snd_tplg_t *tplg,
|
||||
+ struct tplg_elem *elem)
|
||||
+{
|
||||
+ struct tplg_ref *ref;
|
||||
+ struct list_head *base, *pos;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ base = &elem->ref_list;
|
||||
+
|
||||
+ /* for each ref in this control elem */
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ ref = list_entry(pos, struct tplg_ref, list);
|
||||
+ if (ref->id == NULL || ref->elem)
|
||||
+ continue;
|
||||
+
|
||||
+ if (ref->type == OBJECT_TYPE_TLV) {
|
||||
+ ref->elem = tplg_elem_lookup(&tplg->tlv_list,
|
||||
+ ref->id, OBJECT_TYPE_TLV);
|
||||
+ if (ref->elem)
|
||||
+ err = copy_tlv(elem, ref->elem);
|
||||
+
|
||||
+ } else if (ref->type == OBJECT_TYPE_DATA) {
|
||||
+ ref->elem = tplg_elem_lookup(&tplg->pdata_list,
|
||||
+ ref->id, OBJECT_TYPE_DATA);
|
||||
+ err = tplg_copy_data(elem, ref->elem);
|
||||
+ }
|
||||
+
|
||||
+ if (!ref->elem) {
|
||||
+ SNDERR("error: cannot find '%s' referenced by"
|
||||
+ " control '%s'\n", ref->id, elem->id);
|
||||
+ return -EINVAL;
|
||||
+ } else if (err < 0)
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void copy_enum_texts(struct tplg_elem *enum_elem,
|
||||
+ struct tplg_elem *ref_elem)
|
||||
+{
|
||||
+ struct snd_soc_tplg_enum_control *ec = enum_elem->enum_ctrl;
|
||||
+
|
||||
+ memcpy(ec->texts, ref_elem->texts,
|
||||
+ SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
||||
+}
|
||||
+
|
||||
+/* check referenced text for a enum control */
|
||||
+static int tplg_build_enum_control(snd_tplg_t *tplg,
|
||||
+ struct tplg_elem *elem)
|
||||
+{
|
||||
+ struct tplg_ref *ref;
|
||||
+ struct list_head *base, *pos;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ base = &elem->ref_list;
|
||||
+
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ ref = list_entry(pos, struct tplg_ref, list);
|
||||
+ if (ref->id == NULL || ref->elem)
|
||||
+ continue;
|
||||
+
|
||||
+ if (ref->type == OBJECT_TYPE_TEXT) {
|
||||
+ ref->elem = tplg_elem_lookup(&tplg->text_list,
|
||||
+ ref->id, OBJECT_TYPE_TEXT);
|
||||
+ if (ref->elem)
|
||||
+ copy_enum_texts(elem, ref->elem);
|
||||
+
|
||||
+ } else if (ref->type == OBJECT_TYPE_DATA) {
|
||||
+ ref->elem = tplg_elem_lookup(&tplg->pdata_list,
|
||||
+ ref->id, OBJECT_TYPE_DATA);
|
||||
+ err = tplg_copy_data(elem, ref->elem);
|
||||
+ }
|
||||
+ if (!ref->elem) {
|
||||
+ SNDERR("error: cannot find '%s' referenced by"
|
||||
+ " control '%s'\n", ref->id, elem->id);
|
||||
+ return -EINVAL;
|
||||
+ } else if (err < 0)
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* check referenced private data for a byte control */
|
||||
+static int tplg_build_bytes_control(snd_tplg_t *tplg, struct tplg_elem *elem)
|
||||
+{
|
||||
+ struct tplg_ref *ref;
|
||||
+ struct list_head *base, *pos;
|
||||
+
|
||||
+ base = &elem->ref_list;
|
||||
+
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ ref = list_entry(pos, struct tplg_ref, list);
|
||||
+ if (ref->id == NULL || ref->elem)
|
||||
+ continue;
|
||||
+
|
||||
+ /* bytes control only reference one private data section */
|
||||
+ ref->elem = tplg_elem_lookup(&tplg->pdata_list,
|
||||
+ ref->id, OBJECT_TYPE_DATA);
|
||||
+ if (!ref->elem) {
|
||||
+ SNDERR("error: cannot find data '%s'"
|
||||
+ " referenced by control '%s'\n",
|
||||
+ ref->id, elem->id);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* copy texts to enum elem */
|
||||
+ return tplg_copy_data(elem, ref->elem);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int tplg_build_controls(snd_tplg_t *tplg)
|
||||
+{
|
||||
+ struct list_head *base, *pos;
|
||||
+ struct tplg_elem *elem;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ base = &tplg->mixer_list;
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ elem = list_entry(pos, struct tplg_elem, list);
|
||||
+ err = tplg_build_mixer_control(tplg, elem);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ /* add control to manifest */
|
||||
+ tplg->manifest.control_elems++;
|
||||
+ }
|
||||
+
|
||||
+ base = &tplg->enum_list;
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ elem = list_entry(pos, struct tplg_elem, list);
|
||||
+ err = tplg_build_enum_control(tplg, elem);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ /* add control to manifest */
|
||||
+ tplg->manifest.control_elems++;
|
||||
+ }
|
||||
+
|
||||
+ base = &tplg->bytes_ext_list;
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ elem = list_entry(pos, struct tplg_elem, list);
|
||||
+ err = tplg_build_bytes_control(tplg, elem);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ /* add control to manifest */
|
||||
+ tplg->manifest.control_elems++;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Parse TLV of DBScale type.
|
||||
+ *
|
||||
+ * Parse DBScale describing min, step, mute in DB.
|
||||
+ */
|
||||
+static int tplg_parse_tlv_dbscale(snd_config_t *cfg, struct tplg_elem *elem)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ struct snd_soc_tplg_ctl_tlv *tplg_tlv;
|
||||
+ const char *id = NULL, *value = NULL;
|
||||
+ int *data;
|
||||
+
|
||||
+ tplg_dbg(" scale: %s\n", elem->id);
|
||||
+
|
||||
+ tplg_tlv = calloc(1, sizeof(*tplg_tlv));
|
||||
+ if (!tplg_tlv)
|
||||
+ return -ENOMEM;
|
||||
+ data = (int*)(tplg_tlv->data);
|
||||
+
|
||||
+ elem->tlv = tplg_tlv;
|
||||
+ tplg_tlv->numid = SNDRV_CTL_TLVT_DB_SCALE;
|
||||
+ tplg_tlv->count = 8;
|
||||
+ tplg_tlv->size = sizeof(*tplg_tlv);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+
|
||||
+ /* get ID */
|
||||
+ if (snd_config_get_id(n, &id) < 0) {
|
||||
+ SNDERR("error: cant get ID\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* get value */
|
||||
+ if (snd_config_get_string(n, &value) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ tplg_dbg("\t%s = %s\n", id, value);
|
||||
+
|
||||
+ /* get TLV data */
|
||||
+ if (strcmp(id, "min") == 0)
|
||||
+ data[0] = atoi(value);
|
||||
+ else if (strcmp(id, "step") == 0)
|
||||
+ data[1] = atoi(value);
|
||||
+ else if (strcmp(id, "mute") == 0)
|
||||
+ data[2] = atoi(value);
|
||||
+ else
|
||||
+ SNDERR("error: unknown key %s\n", id);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Parse TLV */
|
||||
+int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg,
|
||||
+ void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id;
|
||||
+ int err = 0;
|
||||
+ struct tplg_elem *elem;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_TLV);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "scale") == 0) {
|
||||
+ err = tplg_parse_tlv_dbscale(n, elem);
|
||||
+ if (err < 0) {
|
||||
+ SNDERR("error: failed to DBScale");
|
||||
+ return err;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+/* Parse Control Bytes */
|
||||
+int tplg_parse_control_bytes(snd_tplg_t *tplg,
|
||||
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ struct snd_soc_tplg_bytes_control *be;
|
||||
+ struct tplg_elem *elem;
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id, *val = NULL;
|
||||
+ int err;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_BYTES);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ be = elem->bytes_ext;
|
||||
+ be->size = elem->size;
|
||||
+ elem_copy_text(be->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
||||
+ be->hdr.type = SND_SOC_TPLG_TYPE_BYTES;
|
||||
+
|
||||
+ tplg_dbg(" Control Bytes: %s\n", elem->id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* skip comments */
|
||||
+ if (strcmp(id, "comment") == 0)
|
||||
+ continue;
|
||||
+ if (id[0] == '#')
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "index") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ elem->index = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, elem->index);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "base") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ be->base = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, be->base);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "num_regs") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ be->num_regs = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, be->num_regs);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "max") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ be->max = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, be->num_regs);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "mask") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ be->mask = strtol(val, NULL, 16);
|
||||
+ tplg_dbg("\t%s: %d\n", id, be->mask);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "data") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ tplg_ref_add(elem, OBJECT_TYPE_DATA, val);
|
||||
+ tplg_dbg("\t%s: %s\n", id, val);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "tlv") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ err = tplg_ref_add(elem, OBJECT_TYPE_TLV, val);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ be->hdr.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
|
||||
+ SNDRV_CTL_ELEM_ACCESS_READWRITE;
|
||||
+ tplg_dbg("\t%s: %s\n", id, val);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Parse Control Enums. */
|
||||
+int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
|
||||
+ void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ struct snd_soc_tplg_enum_control *ec;
|
||||
+ struct tplg_elem *elem;
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id, *val = NULL;
|
||||
+ int err, j;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_ENUM);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ /* init new mixer */
|
||||
+ ec = elem->enum_ctrl;
|
||||
+ elem_copy_text(ec->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
||||
+ ec->hdr.type = SND_SOC_TPLG_TYPE_ENUM;
|
||||
+ ec->size = elem->size;
|
||||
+ tplg->channel_idx = 0;
|
||||
+
|
||||
+ /* set channel reg to default state */
|
||||
+ for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
|
||||
+ ec->channel[j].reg = -1;
|
||||
+
|
||||
+ tplg_dbg(" Control Enum: %s\n", elem->id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* skip comments */
|
||||
+ if (strcmp(id, "comment") == 0)
|
||||
+ continue;
|
||||
+ if (id[0] == '#')
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "index") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ elem->index = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, elem->index);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "texts") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ tplg_ref_add(elem, OBJECT_TYPE_TEXT, val);
|
||||
+ tplg_dbg("\t%s: %s\n", id, val);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "channel") == 0) {
|
||||
+ if (ec->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
|
||||
+ SNDERR("error: too many channels %s\n",
|
||||
+ elem->id);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ err = tplg_parse_compound(tplg, n, tplg_parse_channel,
|
||||
+ ec->channel);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ ec->num_channels = tplg->channel_idx;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "ops") == 0) {
|
||||
+ err = tplg_parse_compound(tplg, n, tplg_parse_ops,
|
||||
+ &ec->hdr);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "data") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ tplg_ref_add(elem, OBJECT_TYPE_DATA, val);
|
||||
+ tplg_dbg("\t%s: %s\n", id, val);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Parse Controls.
|
||||
+ *
|
||||
+ * Mixer control. Supports multiple channels.
|
||||
+ */
|
||||
+int tplg_parse_control_mixer(snd_tplg_t *tplg,
|
||||
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ struct snd_soc_tplg_mixer_control *mc;
|
||||
+ struct tplg_elem *elem;
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ const char *id, *val = NULL;
|
||||
+ int err, j;
|
||||
+
|
||||
+ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_MIXER);
|
||||
+ if (!elem)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ /* init new mixer */
|
||||
+ mc = elem->mixer_ctrl;
|
||||
+ elem_copy_text(mc->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
||||
+ mc->hdr.type = SND_SOC_TPLG_TYPE_MIXER;
|
||||
+ mc->size = elem->size;
|
||||
+ tplg->channel_idx = 0;
|
||||
+
|
||||
+ /* set channel reg to default state */
|
||||
+ for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
|
||||
+ mc->channel[j].reg = -1;
|
||||
+
|
||||
+ tplg_dbg(" Control Mixer: %s\n", elem->id);
|
||||
+
|
||||
+ /* giterate trough each mixer elment */
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* skip comments */
|
||||
+ if (strcmp(id, "comment") == 0)
|
||||
+ continue;
|
||||
+ if (id[0] == '#')
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "index") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ elem->index = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, elem->index);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "channel") == 0) {
|
||||
+ if (mc->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
|
||||
+ SNDERR("error: too many channels %s\n",
|
||||
+ elem->id);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ err = tplg_parse_compound(tplg, n, tplg_parse_channel,
|
||||
+ mc->channel);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ mc->num_channels = tplg->channel_idx;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "max") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ mc->max = atoi(val);
|
||||
+ tplg_dbg("\t%s: %d\n", id, mc->max);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "invert") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (strcmp(val, "true") == 0)
|
||||
+ mc->invert = 1;
|
||||
+ else if (strcmp(val, "false") == 0)
|
||||
+ mc->invert = 0;
|
||||
+
|
||||
+ tplg_dbg("\t%s: %d\n", id, mc->invert);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "ops") == 0) {
|
||||
+ err = tplg_parse_compound(tplg, n, tplg_parse_ops,
|
||||
+ &mc->hdr);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "tlv") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ err = tplg_ref_add(elem, OBJECT_TYPE_TLV, val);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ mc->hdr.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
|
||||
+ SNDRV_CTL_ELEM_ACCESS_READWRITE;
|
||||
+ tplg_dbg("\t%s: %s\n", id, val);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(id, "data") == 0) {
|
||||
+ if (snd_config_get_string(n, &val) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ tplg_ref_add(elem, OBJECT_TYPE_DATA, val);
|
||||
+ tplg_dbg("\t%s: %s\n", id, val);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--
|
||||
2.5.0
|
||||
|
145
0043-topology-Add-Channel-map-parser.patch
Normal file
145
0043-topology-Add-Channel-map-parser.patch
Normal file
@ -0,0 +1,145 @@
|
||||
From 9764a4b891737e6b4363c09b5e5ce8384acecc11 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:21 +0100
|
||||
Subject: [PATCH 43/49] topology: Add Channel map parser.
|
||||
|
||||
Add support for parsing channel map to control registers.
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/topology/channel.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 122 insertions(+)
|
||||
create mode 100644 src/topology/channel.c
|
||||
|
||||
diff --git a/src/topology/channel.c b/src/topology/channel.c
|
||||
new file mode 100644
|
||||
index 000000000000..9bc5d5a77c57
|
||||
--- /dev/null
|
||||
+++ b/src/topology/channel.c
|
||||
@@ -0,0 +1,122 @@
|
||||
+/*
|
||||
+ Copyright(c) 2014-2015 Intel Corporation
|
||||
+ All rights reserved.
|
||||
+
|
||||
+ This program is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of version 2 of the GNU General Public License as
|
||||
+ published by the Free Software Foundation.
|
||||
+
|
||||
+ This program is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ Authors: Mengdong Lin <mengdong.lin@intel.com>
|
||||
+ Yao Jin <yao.jin@intel.com>
|
||||
+ Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
+*/
|
||||
+
|
||||
+#include "list.h"
|
||||
+#include "tplg_local.h"
|
||||
+
|
||||
+/* mapping of channel text names to types */
|
||||
+static const struct map_elem channel_map[] = {
|
||||
+ {"mono", SNDRV_CHMAP_MONO}, /* mono stream */
|
||||
+ {"fl", SNDRV_CHMAP_FL}, /* front left */
|
||||
+ {"fr", SNDRV_CHMAP_FR}, /* front right */
|
||||
+ {"rl", SNDRV_CHMAP_RL}, /* rear left */
|
||||
+ {"rr", SNDRV_CHMAP_RR}, /* rear right */
|
||||
+ {"fc", SNDRV_CHMAP_FC}, /* front center */
|
||||
+ {"lfe", SNDRV_CHMAP_LFE}, /* LFE */
|
||||
+ {"sl", SNDRV_CHMAP_SL}, /* side left */
|
||||
+ {"sr", SNDRV_CHMAP_SR}, /* side right */
|
||||
+ {"rc", SNDRV_CHMAP_RC}, /* rear center */
|
||||
+ {"flc", SNDRV_CHMAP_FLC}, /* front left center */
|
||||
+ {"frc", SNDRV_CHMAP_FRC}, /* front right center */
|
||||
+ {"rlc", SNDRV_CHMAP_RLC}, /* rear left center */
|
||||
+ {"rrc", SNDRV_CHMAP_RRC}, /* rear right center */
|
||||
+ {"flw", SNDRV_CHMAP_FLW}, /* front left wide */
|
||||
+ {"frw", SNDRV_CHMAP_FRW}, /* front right wide */
|
||||
+ {"flh", SNDRV_CHMAP_FLH}, /* front left high */
|
||||
+ {"fch", SNDRV_CHMAP_FCH}, /* front center high */
|
||||
+ {"frh", SNDRV_CHMAP_FRH}, /* front right high */
|
||||
+ {"tc", SNDRV_CHMAP_TC}, /* top center */
|
||||
+ {"tfl", SNDRV_CHMAP_TFL}, /* top front left */
|
||||
+ {"tfr", SNDRV_CHMAP_TFR}, /* top front right */
|
||||
+ {"tfc", SNDRV_CHMAP_TFC}, /* top front center */
|
||||
+ {"trl", SNDRV_CHMAP_TRL}, /* top rear left */
|
||||
+ {"trr", SNDRV_CHMAP_TRR}, /* top rear right */
|
||||
+ {"trc", SNDRV_CHMAP_TRC}, /* top rear center */
|
||||
+ {"tflc", SNDRV_CHMAP_TFLC}, /* top front left center */
|
||||
+ {"tfrc", SNDRV_CHMAP_TFRC}, /* top front right center */
|
||||
+ {"tsl", SNDRV_CHMAP_TSL}, /* top side left */
|
||||
+ {"tsr", SNDRV_CHMAP_TSR}, /* top side right */
|
||||
+ {"llfe", SNDRV_CHMAP_LLFE}, /* left LFE */
|
||||
+ {"rlfe", SNDRV_CHMAP_RLFE}, /* right LFE */
|
||||
+ {"bc", SNDRV_CHMAP_BC}, /* bottom center */
|
||||
+ {"blc", SNDRV_CHMAP_BLC}, /* bottom left center */
|
||||
+ {"brc", SNDRV_CHMAP_BRC}, /* bottom right center */
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static int lookup_channel(const char *c)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(channel_map); i++) {
|
||||
+ if (strcasecmp(channel_map[i].name, c) == 0) {
|
||||
+ return channel_map[i].id;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+/* Parse a channel mapping. */
|
||||
+int tplg_parse_channel(snd_tplg_t *tplg,
|
||||
+ snd_config_t *cfg, void *private)
|
||||
+{
|
||||
+ snd_config_iterator_t i, next;
|
||||
+ snd_config_t *n;
|
||||
+ struct snd_soc_tplg_channel *channel = private;
|
||||
+ const char *id, *value;
|
||||
+
|
||||
+ if (tplg->channel_idx >= SND_SOC_TPLG_MAX_CHAN)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ channel += tplg->channel_idx;
|
||||
+ snd_config_get_id(cfg, &id);
|
||||
+ tplg_dbg("\tChannel %s at index %d\n", id, tplg->channel_idx);
|
||||
+
|
||||
+ channel->id = lookup_channel(id);
|
||||
+ if (channel->id < 0) {
|
||||
+ SNDERR("error: invalid channel %s\n", id);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ channel->size = sizeof(*channel);
|
||||
+ tplg_dbg("\tChan %s = %d\n", id, channel->id);
|
||||
+
|
||||
+ snd_config_for_each(i, next, cfg) {
|
||||
+
|
||||
+ n = snd_config_iterator_entry(i);
|
||||
+
|
||||
+ /* get id */
|
||||
+ if (snd_config_get_id(n, &id) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* get value */
|
||||
+ if (snd_config_get_string(n, &value) < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ if (strcmp(id, "reg") == 0)
|
||||
+ channel->reg = atoi(value);
|
||||
+ else if (strcmp(id, "shift") == 0)
|
||||
+ channel->shift = atoi(value);
|
||||
+
|
||||
+ tplg_dbg("\t\t%s = %s\n", id, value);
|
||||
+ }
|
||||
+
|
||||
+ tplg->channel_idx++;
|
||||
+ return 0;
|
||||
+}
|
||||
--
|
||||
2.5.0
|
||||
|
350
0044-topology-Add-binary-file-builder.patch
Normal file
350
0044-topology-Add-binary-file-builder.patch
Normal file
@ -0,0 +1,350 @@
|
||||
From 1d1dff56767842a99d2e06a6997079c0516dec68 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:22 +0100
|
||||
Subject: [PATCH 44/49] topology: Add binary file builder.
|
||||
|
||||
Build the binary output file from all the locally parsed objects and elements.
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/topology/builder.c | 327 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 327 insertions(+)
|
||||
create mode 100644 src/topology/builder.c
|
||||
|
||||
diff --git a/src/topology/builder.c b/src/topology/builder.c
|
||||
new file mode 100644
|
||||
index 000000000000..0066b220353c
|
||||
--- /dev/null
|
||||
+++ b/src/topology/builder.c
|
||||
@@ -0,0 +1,327 @@
|
||||
+/*
|
||||
+ Copyright(c) 2014-2015 Intel Corporation
|
||||
+ All rights reserved.
|
||||
+
|
||||
+ This program is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of version 2 of the GNU General Public License as
|
||||
+ published by the Free Software Foundation.
|
||||
+
|
||||
+ This program is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ Authors: Mengdong Lin <mengdong.lin@intel.com>
|
||||
+ Yao Jin <yao.jin@intel.com>
|
||||
+ Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
+*/
|
||||
+
|
||||
+#include "list.h"
|
||||
+#include "tplg_local.h"
|
||||
+
|
||||
+/* verbose output detailing each object size and file position */
|
||||
+static void verbose(snd_tplg_t *tplg, const char *fmt, ...)
|
||||
+{
|
||||
+ int offset;
|
||||
+ va_list va;
|
||||
+
|
||||
+ if (!tplg->verbose)
|
||||
+ return;
|
||||
+
|
||||
+ offset = lseek(tplg->out_fd, 0, SEEK_CUR);
|
||||
+
|
||||
+ va_start(va, fmt);
|
||||
+ fprintf(stdout, "0x%6.6x/%6.6d -", offset, offset);
|
||||
+ vfprintf(stdout, fmt, va);
|
||||
+ va_end(va);
|
||||
+}
|
||||
+
|
||||
+/* write out block header to output file */
|
||||
+static int write_block_header(snd_tplg_t *tplg, unsigned int type,
|
||||
+ unsigned int vendor_type, unsigned int version, unsigned int index,
|
||||
+ size_t payload_size, int count)
|
||||
+{
|
||||
+ struct snd_soc_tplg_hdr hdr;
|
||||
+ size_t bytes;
|
||||
+ int offset = lseek(tplg->out_fd, 0, SEEK_CUR);
|
||||
+
|
||||
+ memset(&hdr, 0, sizeof(hdr));
|
||||
+ hdr.magic = SND_SOC_TPLG_MAGIC;
|
||||
+ hdr.abi = SND_SOC_TPLG_ABI_VERSION;
|
||||
+ hdr.type = type;
|
||||
+ hdr.vendor_type = vendor_type;
|
||||
+ hdr.version = version;
|
||||
+ hdr.payload_size = payload_size;
|
||||
+ hdr.index = index;
|
||||
+ hdr.size = sizeof(hdr);
|
||||
+ hdr.count = count;
|
||||
+
|
||||
+ /* make sure file offset is aligned with the calculated HDR offset */
|
||||
+ if ((unsigned int)offset != tplg->next_hdr_pos) {
|
||||
+ SNDERR("error: New header is at offset 0x%x but file"
|
||||
+ " offset 0x%x is %s by %d bytes\n",
|
||||
+ tplg->next_hdr_pos, offset,
|
||||
+ (unsigned int)offset > tplg->next_hdr_pos ? "ahead" : "behind",
|
||||
+ abs(offset - tplg->next_hdr_pos));
|
||||
+ 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);
|
||||
+
|
||||
+ tplg->next_hdr_pos += hdr.payload_size + sizeof(hdr);
|
||||
+
|
||||
+ bytes = write(tplg->out_fd, &hdr, sizeof(hdr));
|
||||
+ if (bytes != sizeof(hdr)) {
|
||||
+ SNDERR("error: can't write section header %lu\n",
|
||||
+ (long unsigned int)bytes);
|
||||
+ return bytes;
|
||||
+ }
|
||||
+
|
||||
+ return bytes;
|
||||
+}
|
||||
+
|
||||
+static int write_data_block(snd_tplg_t *tplg, int size, int tplg_type,
|
||||
+ const char *obj_name, void *data)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ /* write the header for this block */
|
||||
+ ret = write_block_header(tplg, tplg_type, 0,
|
||||
+ SND_SOC_TPLG_ABI_VERSION, 0, size, 1);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("error: failed to write %s block %d\n", obj_name, ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ verbose(tplg, " %s : write %d bytes\n", obj_name, size);
|
||||
+
|
||||
+ ret = write(tplg->out_fd, data, size);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("error: failed to write %s %d\n", obj_name, ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int write_elem_block(snd_tplg_t *tplg,
|
||||
+ struct list_head *base, int size, int tplg_type, const char *obj_name)
|
||||
+{
|
||||
+ struct list_head *pos;
|
||||
+ struct tplg_elem *elem;
|
||||
+ int ret, wsize = 0, count = 0, vendor_type;
|
||||
+
|
||||
+ /* count number of elements */
|
||||
+ list_for_each(pos, base)
|
||||
+ count++;
|
||||
+
|
||||
+ /* write the header for this block */
|
||||
+ list_for_each(pos, base) {
|
||||
+ elem = list_entry(pos, struct tplg_elem, list);
|
||||
+ vendor_type = elem->vendor_type;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ ret = write_block_header(tplg, tplg_type, vendor_type,
|
||||
+ SND_SOC_TPLG_ABI_VERSION, 0, size, count);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("error: failed to write %s block %d\n",
|
||||
+ obj_name, ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* write each elem to block */
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ elem = list_entry(pos, struct tplg_elem, list);
|
||||
+
|
||||
+ /* compound elems have already been copied to other elems */
|
||||
+ if (elem->compound_elem)
|
||||
+ continue;
|
||||
+
|
||||
+ if (elem->type != OBJECT_TYPE_DAPM_GRAPH)
|
||||
+ 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);
|
||||
+
|
||||
+ count = write(tplg->out_fd, elem->obj, elem->size);
|
||||
+ if (count < 0) {
|
||||
+ SNDERR("error: failed to write %s %d\n",
|
||||
+ obj_name, ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ wsize += count;
|
||||
+ }
|
||||
+
|
||||
+ /* make sure we have written the correct size */
|
||||
+ if (wsize != size) {
|
||||
+ SNDERR("error: size mismatch. Expected %d wrote %d\n",
|
||||
+ size, wsize);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int calc_block_size(struct list_head *base)
|
||||
+{
|
||||
+ struct list_head *pos;
|
||||
+ struct tplg_elem *elem;
|
||||
+ int size = 0;
|
||||
+
|
||||
+ list_for_each(pos, base) {
|
||||
+
|
||||
+ elem = list_entry(pos, struct tplg_elem, list);
|
||||
+
|
||||
+ /* compound elems have already been copied to other elems */
|
||||
+ if (elem->compound_elem)
|
||||
+ continue;
|
||||
+
|
||||
+ size += elem->size;
|
||||
+ }
|
||||
+
|
||||
+ return size;
|
||||
+}
|
||||
+
|
||||
+static int write_block(snd_tplg_t *tplg, struct list_head *base,
|
||||
+ int type)
|
||||
+{
|
||||
+ int size;
|
||||
+
|
||||
+ /* calculate the block size in bytes for all elems in this list */
|
||||
+ size = calc_block_size(base);
|
||||
+ if (size <= 0)
|
||||
+ return size;
|
||||
+
|
||||
+ verbose(tplg, " block size for type %d is %d\n", type, size);
|
||||
+
|
||||
+ /* write each elem for this block */
|
||||
+ switch (type) {
|
||||
+ case OBJECT_TYPE_MIXER:
|
||||
+ return write_elem_block(tplg, base, size,
|
||||
+ SND_SOC_TPLG_TYPE_MIXER, "mixer");
|
||||
+ case OBJECT_TYPE_BYTES:
|
||||
+ return write_elem_block(tplg, base, size,
|
||||
+ SND_SOC_TPLG_TYPE_BYTES, "bytes");
|
||||
+ case OBJECT_TYPE_ENUM:
|
||||
+ return write_elem_block(tplg, base, size,
|
||||
+ SND_SOC_TPLG_TYPE_ENUM, "enum");
|
||||
+ case OBJECT_TYPE_DAPM_GRAPH:
|
||||
+ return write_elem_block(tplg, base, size,
|
||||
+ SND_SOC_TPLG_TYPE_DAPM_GRAPH, "route");
|
||||
+ case OBJECT_TYPE_DAPM_WIDGET:
|
||||
+ return write_elem_block(tplg, base, size,
|
||||
+ SND_SOC_TPLG_TYPE_DAPM_WIDGET, "widget");
|
||||
+ case OBJECT_TYPE_PCM:
|
||||
+ return write_elem_block(tplg, base, size,
|
||||
+ SND_SOC_TPLG_TYPE_PCM, "pcm");
|
||||
+ case OBJECT_TYPE_BE:
|
||||
+ return write_elem_block(tplg, base, size,
|
||||
+ SND_SOC_TPLG_TYPE_DAI_LINK, "be");
|
||||
+ case OBJECT_TYPE_CC:
|
||||
+ return write_elem_block(tplg, base, size,
|
||||
+ SND_SOC_TPLG_TYPE_DAI_LINK, "cc");
|
||||
+ case OBJECT_TYPE_MANIFEST:
|
||||
+ return write_data_block(tplg, size, SND_SOC_TPLG_TYPE_MANIFEST,
|
||||
+ "manifest", &tplg->manifest);
|
||||
+ case OBJECT_TYPE_DATA:
|
||||
+ return write_elem_block(tplg, base, size,
|
||||
+ SND_SOC_TPLG_TYPE_PDATA, "data");
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int tplg_write_data(snd_tplg_t *tplg)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ /* write manifest */
|
||||
+ ret = write_data_block(tplg, sizeof(tplg->manifest),
|
||||
+ OBJECT_TYPE_MANIFEST, "manifest", &tplg->manifest);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("failed to write manifest %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* write mixer elems. */
|
||||
+ ret = write_block(tplg, &tplg->mixer_list,
|
||||
+ OBJECT_TYPE_MIXER);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("failed to write control elems %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* write enum control elems. */
|
||||
+ ret = write_block(tplg, &tplg->enum_list,
|
||||
+ OBJECT_TYPE_ENUM);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("failed to write control elems %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* write bytes extended control elems. */
|
||||
+ ret = write_block(tplg, &tplg->bytes_ext_list,
|
||||
+ OBJECT_TYPE_BYTES);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("failed to write control elems %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* write widget elems */
|
||||
+ ret = write_block(tplg, &tplg->widget_list,
|
||||
+ OBJECT_TYPE_DAPM_WIDGET);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("failed to write widget elems %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* write pcm elems */
|
||||
+ ret = write_block(tplg, &tplg->pcm_list,
|
||||
+ OBJECT_TYPE_PCM);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("failed to write pcm elems %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* write be elems */
|
||||
+ ret = write_block(tplg, &tplg->be_list,
|
||||
+ OBJECT_TYPE_BE);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("failed to write be elems %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* write cc elems */
|
||||
+ ret = write_block(tplg, &tplg->cc_list,
|
||||
+ OBJECT_TYPE_CC);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("failed to write cc elems %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* write route elems */
|
||||
+ ret = write_block(tplg, &tplg->route_list,
|
||||
+ OBJECT_TYPE_DAPM_GRAPH);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("failed to write graph elems %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* write private data */
|
||||
+ ret = write_block(tplg, &tplg->pdata_list,
|
||||
+ OBJECT_TYPE_DATA);
|
||||
+ if (ret < 0) {
|
||||
+ SNDERR("failed to write private data %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--
|
||||
2.5.0
|
||||
|
125
0045-topology-autotools-Add-build-support-for-topology-co.patch
Normal file
125
0045-topology-autotools-Add-build-support-for-topology-co.patch
Normal file
@ -0,0 +1,125 @@
|
||||
From fec1e8f25374ec8eb4d57ee43e94e9689a748678 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:23 +0100
|
||||
Subject: [PATCH 45/49] topology: autotools: Add build support for topology
|
||||
core
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
configure.ac | 9 ++++++++-
|
||||
include/Makefile.am | 4 ++++
|
||||
src/Makefile.am | 7 +++++++
|
||||
src/topology/Makefile.am | 19 +++++++++++++++++++
|
||||
4 files changed, 38 insertions(+), 1 deletion(-)
|
||||
create mode 100644 src/topology/Makefile.am
|
||||
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 9621d4e9ec2b..b6bea2dca434 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -380,6 +380,9 @@ AC_ARG_ENABLE(seq,
|
||||
AC_ARG_ENABLE(ucm,
|
||||
AS_HELP_STRING([--disable-ucm], [disable the use-case-manager component]),
|
||||
[build_ucm="$enableval"], [build_ucm="yes"])
|
||||
+AC_ARG_ENABLE(topology,
|
||||
+ AS_HELP_STRING([--disable-topology], [disable the DSP topology component]),
|
||||
+ [build_topology="$enableval"], [build_topology="yes"])
|
||||
AC_ARG_ENABLE(alisp,
|
||||
AS_HELP_STRING([--disable-alisp], [disable the alisp component]),
|
||||
[build_alisp="$enableval"], [build_alisp="yes"])
|
||||
@@ -422,6 +425,7 @@ AM_CONDITIONAL([BUILD_RAWMIDI], [test x$build_rawmidi = xyes])
|
||||
AM_CONDITIONAL([BUILD_HWDEP], [test x$build_hwdep = xyes])
|
||||
AM_CONDITIONAL([BUILD_SEQ], [test x$build_seq = xyes])
|
||||
AM_CONDITIONAL([BUILD_UCM], [test x$build_ucm = xyes])
|
||||
+AM_CONDITIONAL([BUILD_TOPOLOGY], [test x$build_topology = xyes])
|
||||
AM_CONDITIONAL([BUILD_ALISP], [test x$build_alisp = xyes])
|
||||
AM_CONDITIONAL([BUILD_PYTHON], [test x$build_python = xyes])
|
||||
|
||||
@@ -443,6 +447,9 @@ fi
|
||||
if test "$build_ucm" = "yes"; then
|
||||
AC_DEFINE([BUILD_UCM], "1", [Build UCM component])
|
||||
fi
|
||||
+if test "$build_topology" = "yes"; then
|
||||
+ AC_DEFINE([BUILD_TOPOLOGY], "1", [Build DSP Topology component])
|
||||
+fi
|
||||
|
||||
dnl PCM Plugins
|
||||
|
||||
@@ -643,7 +650,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
|
||||
src/pcm/Makefile src/pcm/scopes/Makefile \
|
||||
src/rawmidi/Makefile src/timer/Makefile \
|
||||
src/hwdep/Makefile src/seq/Makefile src/ucm/Makefile \
|
||||
- src/alisp/Makefile \
|
||||
+ src/alisp/Makefile src/topology/Makefile \
|
||||
src/conf/Makefile src/conf/alsa.conf.d/Makefile \
|
||||
src/conf/cards/Makefile \
|
||||
src/conf/pcm/Makefile \
|
||||
diff --git a/include/Makefile.am b/include/Makefile.am
|
||||
index 4baa03af69e1..ff931fda24d5 100644
|
||||
--- a/include/Makefile.am
|
||||
+++ b/include/Makefile.am
|
||||
@@ -50,6 +50,10 @@ if BUILD_UCM
|
||||
alsainclude_HEADERS += use-case.h
|
||||
endif
|
||||
|
||||
+if BUILD_TOPOLOGY
|
||||
+alsainclude_HEADERS += topology.h
|
||||
+endif
|
||||
+
|
||||
if BUILD_ALISP
|
||||
alsainclude_HEADERS += alisp.h
|
||||
endif
|
||||
diff --git a/src/Makefile.am b/src/Makefile.am
|
||||
index fa255ff43ee0..57686a612fd8 100644
|
||||
--- a/src/Makefile.am
|
||||
+++ b/src/Makefile.am
|
||||
@@ -42,6 +42,10 @@ if BUILD_UCM
|
||||
SUBDIRS += ucm
|
||||
libasound_la_LIBADD += ucm/libucm.la
|
||||
endif
|
||||
+if BUILD_TOPOLOGY
|
||||
+SUBDIRS += topology
|
||||
+libasound_la_LIBADD += topology/libtopology.la
|
||||
+endif
|
||||
if BUILD_ALISP
|
||||
SUBDIRS += alisp
|
||||
libasound_la_LIBADD += alisp/libalisp.la
|
||||
@@ -81,6 +85,9 @@ seq/libseq.la:
|
||||
ucm/libucm.la:
|
||||
$(MAKE) -C ucm libucm.la
|
||||
|
||||
+topology/libtopology.la:
|
||||
+ $(MAKE) -C topology libtopology.la
|
||||
+
|
||||
instr/libinstr.la:
|
||||
$(MAKE) -C instr libinstr.la
|
||||
|
||||
diff --git a/src/topology/Makefile.am b/src/topology/Makefile.am
|
||||
new file mode 100644
|
||||
index 000000000000..3fb8bf7a9290
|
||||
--- /dev/null
|
||||
+++ b/src/topology/Makefile.am
|
||||
@@ -0,0 +1,19 @@
|
||||
+EXTRA_LTLIBRARIES = libtopology.la
|
||||
+
|
||||
+libtopology_la_SOURCES =\
|
||||
+ parser.c \
|
||||
+ builder.c \
|
||||
+ ctl.c \
|
||||
+ dapm.c \
|
||||
+ pcm.c \
|
||||
+ data.c \
|
||||
+ text.c \
|
||||
+ channel.c \
|
||||
+ ops.c \
|
||||
+ elem.c
|
||||
+
|
||||
+noinst_HEADERS = tplg_local.h
|
||||
+
|
||||
+all: libtopology.la
|
||||
+
|
||||
+AM_CPPFLAGS=-I$(top_srcdir)/include
|
||||
--
|
||||
2.5.0
|
||||
|
@ -0,0 +1,60 @@
|
||||
From 22603237b09ed50744030f550248ade135d4f73b Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:24 +0100
|
||||
Subject: [PATCH 46/49] topology: doxygen: Add doxygen support for topology
|
||||
core.
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
doc/doxygen.cfg.in | 7 +++++--
|
||||
doc/index.doxygen | 1 +
|
||||
2 files changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in
|
||||
index 043e75b2d7eb..92bd52ba67a2 100644
|
||||
--- a/doc/doxygen.cfg.in
|
||||
+++ b/doc/doxygen.cfg.in
|
||||
@@ -29,6 +29,7 @@ INPUT = @top_srcdir@/doc/index.doxygen \
|
||||
@top_srcdir@/include/control_external.h \
|
||||
@top_srcdir@/include/mixer.h \
|
||||
@top_srcdir@/include/use-case.h \
|
||||
+ @top_srcdir@/include/topology.h \
|
||||
@top_srcdir@/src/error.c \
|
||||
@top_srcdir@/src/dlmisc.c \
|
||||
@top_srcdir@/src/async.c \
|
||||
@@ -78,7 +79,8 @@ INPUT = @top_srcdir@/doc/index.doxygen \
|
||||
@top_srcdir@/src/timer \
|
||||
@top_srcdir@/src/hwdep \
|
||||
@top_srcdir@/src/seq \
|
||||
- @top_srcdir@/src/ucm
|
||||
+ @top_srcdir@/src/ucm \
|
||||
+ @top_srcdir@/src/topology
|
||||
EXCLUDE = @top_srcdir@/src/control/control_local.h \
|
||||
@top_srcdir@/src/pcm/atomic.h \
|
||||
@top_srcdir@/src/pcm/interval.h \
|
||||
@@ -94,7 +96,8 @@ EXCLUDE = @top_srcdir@/src/control/control_local.h \
|
||||
@top_srcdir@/src/mixer/mixer_local.h \
|
||||
@top_srcdir@/src/rawmidi/rawmidi_local.h \
|
||||
@top_srcdir@/src/seq/seq_local.h \
|
||||
- @top_srcdir@/src/ucm/ucm_local.h
|
||||
+ @top_srcdir@/src/ucm/ucm_local.h \
|
||||
+ @top_srcdir@/src/topology/tplg_local.h
|
||||
RECURSIVE = YES
|
||||
FILE_PATTERNS = *.c *.h
|
||||
EXAMPLE_PATH = @top_srcdir@/test
|
||||
diff --git a/doc/index.doxygen b/doc/index.doxygen
|
||||
index 7d049fe5c32a..b40c75a5239b 100644
|
||||
--- a/doc/index.doxygen
|
||||
+++ b/doc/index.doxygen
|
||||
@@ -41,6 +41,7 @@ may be placed in the library code instead of the kernel driver.</P>
|
||||
<LI>Page \ref timer explains the design of the Timer API.
|
||||
<LI>Page \ref seq explains the design of the Sequencer API.
|
||||
<LI>Page \ref ucm explains the use case API.
|
||||
+ <LI>Page \ref topology explains the DSP topology API.
|
||||
</UL>
|
||||
|
||||
<H2>Configuration</H2>
|
||||
--
|
||||
2.5.0
|
||||
|
443
0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch
Normal file
443
0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch
Normal file
@ -0,0 +1,443 @@
|
||||
From 00a51b5bacb0f966d0e323bd9d3057c0eb0e6f23 Mon Sep 17 00:00:00 2001
|
||||
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Date: Wed, 29 Jul 2015 17:45:25 +0100
|
||||
Subject: [PATCH 47/49] conf: topology: Add topology file for broadwell audio
|
||||
DSP
|
||||
|
||||
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
configure.ac | 2 +
|
||||
src/conf/Makefile.am | 2 +-
|
||||
src/conf/topology/Makefile.am | 1 +
|
||||
src/conf/topology/broadwell/Makefile.am | 4 +
|
||||
src/conf/topology/broadwell/broadwell.conf | 375 +++++++++++++++++++++++++++++
|
||||
5 files changed, 383 insertions(+), 1 deletion(-)
|
||||
create mode 100644 src/conf/topology/Makefile.am
|
||||
create mode 100644 src/conf/topology/broadwell/Makefile.am
|
||||
create mode 100644 src/conf/topology/broadwell/broadwell.conf
|
||||
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index b6bea2dca434..a482b3e7f6ca 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -663,6 +663,8 @@ 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/topology/Makefile \
|
||||
+ src/conf/topology/broadwell/Makefile \
|
||||
modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \
|
||||
alsalisp/Makefile aserver/Makefile \
|
||||
test/Makefile test/lsb/Makefile \
|
||||
diff --git a/src/conf/Makefile.am b/src/conf/Makefile.am
|
||||
index 948d5a1c822e..a04f73fddc65 100644
|
||||
--- a/src/conf/Makefile.am
|
||||
+++ b/src/conf/Makefile.am
|
||||
@@ -1,4 +1,4 @@
|
||||
-SUBDIRS=cards pcm alsa.conf.d ucm
|
||||
+SUBDIRS=cards pcm alsa.conf.d ucm topology
|
||||
|
||||
cfg_files = alsa.conf
|
||||
if BUILD_ALISP
|
||||
diff --git a/src/conf/topology/Makefile.am b/src/conf/topology/Makefile.am
|
||||
new file mode 100644
|
||||
index 000000000000..f56a96c651e5
|
||||
--- /dev/null
|
||||
+++ b/src/conf/topology/Makefile.am
|
||||
@@ -0,0 +1 @@
|
||||
+SUBDIRS=broadwell
|
||||
diff --git a/src/conf/topology/broadwell/Makefile.am b/src/conf/topology/broadwell/Makefile.am
|
||||
new file mode 100644
|
||||
index 000000000000..35d1e83cb645
|
||||
--- /dev/null
|
||||
+++ b/src/conf/topology/broadwell/Makefile.am
|
||||
@@ -0,0 +1,4 @@
|
||||
+alsaconfigdir = @ALSA_CONFIG_DIR@
|
||||
+topologydir = $(alsaconfigdir)/topology/broadwell
|
||||
+topology_DATA = broadwell.conf
|
||||
+EXTRA_DIST = $(topology_DATA)
|
||||
diff --git a/src/conf/topology/broadwell/broadwell.conf b/src/conf/topology/broadwell/broadwell.conf
|
||||
new file mode 100644
|
||||
index 000000000000..05b3889bec58
|
||||
--- /dev/null
|
||||
+++ b/src/conf/topology/broadwell/broadwell.conf
|
||||
@@ -0,0 +1,375 @@
|
||||
+# Dynamic Firmware Configuration for Broadwell
|
||||
+
|
||||
+# TLV
|
||||
+SectionTLV."hsw_vol_tlv" {
|
||||
+ Comment "TLV used by both global and stream volumes"
|
||||
+
|
||||
+ scale {
|
||||
+ min "-9000"
|
||||
+ step "300"
|
||||
+ mute "1"
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+# Controls
|
||||
+SectionControlMixer."Master Playback Volume" {
|
||||
+ Comment "Global DSP volume"
|
||||
+
|
||||
+ # control belongs to this index group
|
||||
+ index "1"
|
||||
+
|
||||
+ # Channel register and shift for Front Left/Right
|
||||
+ channel."FL" {
|
||||
+ reg "0"
|
||||
+ shift "0"
|
||||
+ }
|
||||
+ channel."FR" {
|
||||
+ reg "0"
|
||||
+ shift "8"
|
||||
+ }
|
||||
+
|
||||
+ # max control value and whether value is inverted
|
||||
+ max "31"
|
||||
+ invert "false"
|
||||
+
|
||||
+ # control uses bespoke driver get/put/info ID 0
|
||||
+ ops."ctl" {
|
||||
+ info "volsw"
|
||||
+ get "256"
|
||||
+ put "256"
|
||||
+ }
|
||||
+
|
||||
+ # uses TLV data above
|
||||
+ tlv "hsw_vol_tlv"
|
||||
+}
|
||||
+
|
||||
+SectionControlMixer."Media0 Playback Volume" {
|
||||
+ Comment "Offload 0 volume"
|
||||
+
|
||||
+ # control belongs to this index group
|
||||
+ index "1"
|
||||
+
|
||||
+ # Channel register and shift for Front Left/Right
|
||||
+ channel."FL" {
|
||||
+ reg "1"
|
||||
+ shift "0"
|
||||
+ }
|
||||
+ channel."FR" {
|
||||
+ reg "1"
|
||||
+ shift "8"
|
||||
+ }
|
||||
+
|
||||
+ # max control value and whether value is inverted
|
||||
+ max "31"
|
||||
+ invert "false"
|
||||
+
|
||||
+ # control uses bespoke driver get/put/info ID 0
|
||||
+ ops."ctl" {
|
||||
+ info "volsw"
|
||||
+ get "257"
|
||||
+ put "257"
|
||||
+ }
|
||||
+
|
||||
+ # uses TLV data above
|
||||
+ tlv "hsw_vol_tlv"
|
||||
+}
|
||||
+
|
||||
+SectionControlMixer."Media1 Playback Volume" {
|
||||
+ Comment "Offload 1 volume"
|
||||
+
|
||||
+ # control belongs to this index group
|
||||
+ index "1"
|
||||
+
|
||||
+ # Channel register and shift for Front Left/Right
|
||||
+ channel."FL" {
|
||||
+ reg "2"
|
||||
+ shift "0"
|
||||
+ }
|
||||
+ channel."FR" {
|
||||
+ reg "2"
|
||||
+ shift "8"
|
||||
+ }
|
||||
+
|
||||
+ # max control value and whether value is inverted
|
||||
+ max "31"
|
||||
+ invert "false"
|
||||
+
|
||||
+ # control uses bespoke driver get/put/info ID 0
|
||||
+ ops."ctl" {
|
||||
+ info "volsw"
|
||||
+ get "257"
|
||||
+ put "257"
|
||||
+ }
|
||||
+
|
||||
+ # uses TLV data above
|
||||
+ tlv "hsw_vol_tlv"
|
||||
+}
|
||||
+
|
||||
+SectionControlMixer."Mic Capture Volume" {
|
||||
+ Comment "Mic Capture volume"
|
||||
+
|
||||
+ # control belongs to this index group
|
||||
+ index "1"
|
||||
+
|
||||
+ # Channel register and shift for Front Left/Right
|
||||
+ channel."FL" {
|
||||
+ reg "0"
|
||||
+ shift "0"
|
||||
+ }
|
||||
+ channel."FR" {
|
||||
+ reg "0"
|
||||
+ shift "8"
|
||||
+ }
|
||||
+
|
||||
+ # max control value and whether value is inverted
|
||||
+ max "31"
|
||||
+ invert "false"
|
||||
+
|
||||
+ # control uses bespoke driver get/put/info ID 0
|
||||
+ ops."ctl" {
|
||||
+ info "volsw"
|
||||
+ get "257"
|
||||
+ put "257"
|
||||
+ }
|
||||
+
|
||||
+ # uses TLV data above
|
||||
+ tlv "hsw_vol_tlv"
|
||||
+}
|
||||
+
|
||||
+SectionWidget."SSP0 CODEC IN" {
|
||||
+
|
||||
+ index "1"
|
||||
+ type "aif_in"
|
||||
+ no_pm "true"
|
||||
+ shift "0"
|
||||
+ invert "0"
|
||||
+}
|
||||
+
|
||||
+SectionWidget."SSP0 CODEC OUT" {
|
||||
+
|
||||
+ index "1"
|
||||
+ type "aif_out"
|
||||
+ no_pm "true"
|
||||
+ shift "0"
|
||||
+ invert "0"
|
||||
+}
|
||||
+
|
||||
+SectionWidget."SSP1 BT IN" {
|
||||
+
|
||||
+ index "1"
|
||||
+ type "aif_in"
|
||||
+ no_pm "true"
|
||||
+ shift "0"
|
||||
+ invert "0"
|
||||
+}
|
||||
+
|
||||
+SectionWidget."SSP1 BT OUT" {
|
||||
+
|
||||
+ index "1"
|
||||
+ type "aif_out"
|
||||
+ no_pm "true"
|
||||
+ shift "0"
|
||||
+ invert "0"
|
||||
+}
|
||||
+
|
||||
+SectionWidget."Playback VMixer" {
|
||||
+
|
||||
+ index "1"
|
||||
+ type "mixer"
|
||||
+ no_pm "true"
|
||||
+ shift "0"
|
||||
+ invert "0"
|
||||
+}
|
||||
+
|
||||
+# PCM Configurations supported by FW
|
||||
+SectionPCMConfig."PCM 48k Stereo 24bit" {
|
||||
+
|
||||
+ config."playback" {
|
||||
+ format "S24_LE"
|
||||
+ rate "48000"
|
||||
+ channels "2"
|
||||
+ tdm_slot "0xf"
|
||||
+ }
|
||||
+
|
||||
+ config."capture" {
|
||||
+ format "S24_LE"
|
||||
+ rate "48000"
|
||||
+ channels "2"
|
||||
+ tdm_slot "0xf"
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+SectionPCMConfig."PCM 48k Stereo 16bit" {
|
||||
+
|
||||
+ config."playback" {
|
||||
+ format "S16_LE"
|
||||
+ rate "48000"
|
||||
+ channels "2"
|
||||
+ tdm_slot "0xf"
|
||||
+ }
|
||||
+
|
||||
+ config."capture" {
|
||||
+ format "S16_LE"
|
||||
+ rate "48000"
|
||||
+ channels "2"
|
||||
+ tdm_slot "0xf"
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+SectionPCMConfig."PCM 48k 2P/4C 16bit" {
|
||||
+
|
||||
+ config."playback" {
|
||||
+ format "S16_LE"
|
||||
+ rate "48000"
|
||||
+ channels "2"
|
||||
+ tdm_slot "0xf"
|
||||
+ }
|
||||
+
|
||||
+ config."capture" {
|
||||
+ format "S16_LE"
|
||||
+ rate "48000"
|
||||
+ channels "4"
|
||||
+ tdm_slot "0xf"
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+# PCM capabilities supported by FW
|
||||
+SectionPCMCapabilities."System Playback" {
|
||||
+
|
||||
+ formats "S24_LE,S16_LE"
|
||||
+ rate_min "48000"
|
||||
+ rate_max "48000"
|
||||
+ channels_min "2"
|
||||
+ channels_max "2"
|
||||
+}
|
||||
+
|
||||
+SectionPCMCapabilities."Analog Capture" {
|
||||
+
|
||||
+ formats "S24_LE,S16_LE"
|
||||
+ rate_min "48000"
|
||||
+ rate_max "48000"
|
||||
+ channels_min "2"
|
||||
+ channels_max "4"
|
||||
+}
|
||||
+
|
||||
+SectionPCMCapabilities."Loopback Capture" {
|
||||
+
|
||||
+ formats "S24_LE,S16_LE"
|
||||
+ rate_min "48000"
|
||||
+ rate_max "48000"
|
||||
+ channels_min "2"
|
||||
+ channels_max "2"
|
||||
+}
|
||||
+
|
||||
+SectionPCMCapabilities."Offload0 Playback" {
|
||||
+ formats "S24_LE,S16_LE"
|
||||
+ rate_min "8000"
|
||||
+ rate_max "192000"
|
||||
+ channels_min "2"
|
||||
+ channels_max "2"
|
||||
+}
|
||||
+
|
||||
+SectionPCMCapabilities."Offload1 Playback" {
|
||||
+ formats "S24_LE,S16_LE"
|
||||
+ rate_min "8000"
|
||||
+ rate_max "48000"
|
||||
+ channels_min "2"
|
||||
+ channels_max "2"
|
||||
+}
|
||||
+
|
||||
+# PCM devices exported by Firmware
|
||||
+SectionPCM."System Pin" {
|
||||
+
|
||||
+ index "1"
|
||||
+
|
||||
+ # used for binding to the PCM
|
||||
+ ID "0"
|
||||
+
|
||||
+ pcm."playback" {
|
||||
+
|
||||
+ capabilities "System Playback"
|
||||
+
|
||||
+ configs [
|
||||
+ "PCM 48k Stereo 24bit"
|
||||
+ "PCM 48k Stereo 16bit"
|
||||
+ ]
|
||||
+ }
|
||||
+
|
||||
+ pcm."capture" {
|
||||
+
|
||||
+ capabilities "Analog Capture"
|
||||
+
|
||||
+ configs [
|
||||
+ "PCM 48k Stereo 24bit"
|
||||
+ "PCM 48k Stereo 16bit"
|
||||
+ "PCM 48k 2P/4C 16bit"
|
||||
+ ]
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+SectionPCM."Offload0 Pin" {
|
||||
+
|
||||
+ index "1"
|
||||
+
|
||||
+ # used for binding to the PCM
|
||||
+ ID "1"
|
||||
+
|
||||
+ pcm."playback" {
|
||||
+
|
||||
+ capabilities "Offload0 Playback"
|
||||
+
|
||||
+ configs [
|
||||
+ "PCM 48k Stereo 24bit"
|
||||
+ "PCM 48k Stereo 16bit"
|
||||
+ ]
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+SectionPCM."Offload1 Pin" {
|
||||
+
|
||||
+ index "1"
|
||||
+
|
||||
+ # used for binding to the PCM
|
||||
+ ID "2"
|
||||
+
|
||||
+ pcm."playback" {
|
||||
+
|
||||
+ capabilities "Offload1 Playback"
|
||||
+
|
||||
+ configs [
|
||||
+ "PCM 48k Stereo 24bit"
|
||||
+ "PCM 48k Stereo 16bit"
|
||||
+ ]
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+SectionPCM."Loopback Pin" {
|
||||
+
|
||||
+ index "1"
|
||||
+
|
||||
+ # used for binding to the PCM
|
||||
+ ID "3"
|
||||
+
|
||||
+ pcm."capture" {
|
||||
+
|
||||
+ capabilities "Loopback Capture"
|
||||
+
|
||||
+ configs [
|
||||
+ "PCM 48k Stereo 24bit"
|
||||
+ "PCM 48k Stereo 16bit"
|
||||
+ ]
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+SectionGraph."dsp" {
|
||||
+ index "1"
|
||||
+
|
||||
+ lines [
|
||||
+ "Playback VMixer, , System Playback"
|
||||
+ "Playback VMixer, , Offload0 Playback"
|
||||
+ "Playback VMixer, , Offload1 Playback"
|
||||
+ "SSP0 CODEC OUT, , Playback VMixer"
|
||||
+ "Loopback Capture, , Playback VMixer"
|
||||
+ "Analog Capture, , SSP0 CODEC IN"
|
||||
+ ]
|
||||
+}
|
||||
--
|
||||
2.5.0
|
||||
|
28
0048-topology-Fix-missing-inclusion-of-ctype.h.patch
Normal file
28
0048-topology-Fix-missing-inclusion-of-ctype.h.patch
Normal file
@ -0,0 +1,28 @@
|
||||
From 907e464593a2acf51c2e2be4c3d4e098efdd95ff Mon Sep 17 00:00:00 2001
|
||||
From: Takashi Iwai <tiwai@suse.de>
|
||||
Date: Thu, 30 Jul 2015 16:34:50 +0200
|
||||
Subject: [PATCH 48/49] topology: Fix missing inclusion of ctype.h
|
||||
|
||||
Fix a compile warning:
|
||||
data.c:116:7: warning: implicit declaration of function 'isspace' [-Wimplicit-function-declaration]
|
||||
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
src/topology/data.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/src/topology/data.c b/src/topology/data.c
|
||||
index ae664721935d..13e1e2bb60fb 100644
|
||||
--- a/src/topology/data.c
|
||||
+++ b/src/topology/data.c
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "list.h"
|
||||
#include "tplg_local.h"
|
||||
+#include <ctype.h>
|
||||
|
||||
/* Get Private data from a file. */
|
||||
static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
|
||||
--
|
||||
2.5.0
|
||||
|
96
0049-topology-Fix-typos.patch
Normal file
96
0049-topology-Fix-typos.patch
Normal file
@ -0,0 +1,96 @@
|
||||
From 66ce9f9a1177de3b8e8304323b4d3a16d78ead32 Mon Sep 17 00:00:00 2001
|
||||
From: Takashi Iwai <tiwai@suse.de>
|
||||
Date: Thu, 30 Jul 2015 16:43:19 +0200
|
||||
Subject: [PATCH 49/49] topology: Fix typos
|
||||
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
include/topology.h | 18 +++++++++---------
|
||||
1 file changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/include/topology.h b/include/topology.h
|
||||
index f604ed1450d3..0cb2d79e5574 100644
|
||||
--- a/include/topology.h
|
||||
+++ b/include/topology.h
|
||||
@@ -48,7 +48,7 @@ extern "C" {
|
||||
*
|
||||
* The topology text format uses the standard ALSA configuration file format to
|
||||
* describe each topology object type. This allows topology objects to include
|
||||
- * other topology objects as part of thier definition. i.e. a TLV data object
|
||||
+ * other topology objects as part of their definition. i.e. a TLV data object
|
||||
* can be shared amongst many control objects that use the same TLV data.
|
||||
*
|
||||
*
|
||||
@@ -174,7 +174,7 @@ extern "C" {
|
||||
* words "0xaabbccdd,0x11223344,0x66aa77bb,0xefef1234"
|
||||
* };
|
||||
* </pre>
|
||||
- * The file, bytes, shorts and words keywords are all mutulally exclusive as
|
||||
+ * The file, bytes, shorts and words keywords are all mutually exclusive as
|
||||
* the private data should only be taken from one source. The private data can
|
||||
* either be read from a separate file or defined in the topology file using
|
||||
* the bytes, shorts or words keywords.
|
||||
@@ -247,7 +247,7 @@ extern "C" {
|
||||
* can include channel mapping, callback operations, private data and
|
||||
* text strings to represent the enumerated control options.<br>
|
||||
*
|
||||
- * The text strings for the enumerated controls are defined in a seperate
|
||||
+ * The text strings for the enumerated controls are defined in a separate
|
||||
* section as follows :-
|
||||
*
|
||||
* <pre>
|
||||
@@ -306,7 +306,7 @@ extern "C" {
|
||||
* graph with other graphs, it's not used by the kernel atm.
|
||||
*
|
||||
* <h4>DAPM Widgets</h4>
|
||||
- * DAPM wigets are similar to controls in that they can include many other
|
||||
+ * DAPM widgets are similar to controls in that they can include many other
|
||||
* objects. Widgets can contain private data, mixer controls and enum controls.
|
||||
*
|
||||
* The following widget types are supported and match the driver types :-
|
||||
@@ -367,13 +367,13 @@ extern "C" {
|
||||
*
|
||||
* formats "S24_LE,S16_LE" # Supported formats
|
||||
* rate_min "48000" # Max supported sample rate
|
||||
- * rate_max "48000" # Min suppoprted sample rate
|
||||
+ * rate_max "48000" # Min supported sample rate
|
||||
* channels_min "2" # Min number of channels
|
||||
* channels_max "2" # max number of channels
|
||||
* }
|
||||
* </pre>
|
||||
* The supported formats use the same naming convention as the driver macros.
|
||||
- * The PCM capabilities name can be reffered to and included by BE, PCM and
|
||||
+ * The PCM capabilities name can be referred to and included by BE, PCM and
|
||||
* Codec <-> codec topology sections.
|
||||
*
|
||||
* <h4>PCM Configurations</h4>
|
||||
@@ -400,7 +400,7 @@ extern "C" {
|
||||
* </pre>
|
||||
*
|
||||
* The supported formats use the same naming convention as the driver macros.
|
||||
- * The PCM configuration name can be reffered to and included by BE, PCM and
|
||||
+ * The PCM configuration name can be referred to and included by BE, PCM and
|
||||
* Codec <-> codec topology sections.
|
||||
*
|
||||
* <h4>PCM Configurations</h4>
|
||||
@@ -434,7 +434,7 @@ extern "C" {
|
||||
* id "0" # used for binding to the PCM
|
||||
*
|
||||
* pcm."playback" {
|
||||
- * capabilities "capabilities1" # capbilities for playback
|
||||
+ * capabilities "capabilities1" # capabilities for playback
|
||||
*
|
||||
* configs [ # supported configs for playback
|
||||
* "config1"
|
||||
@@ -476,7 +476,7 @@ void snd_tplg_free(snd_tplg_t *tplg);
|
||||
* \param tplg Topology instance.
|
||||
* \param infile Topology text input file to be parsed
|
||||
* \param outfile Binary topology output file.
|
||||
- * \return Zero on sucess, otherwise a negative error code
|
||||
+ * \return Zero on success, otherwise a negative error code
|
||||
*/
|
||||
int snd_tplg_build_file(snd_tplg_t *tplg, const char *infile,
|
||||
const char *outfile);
|
||||
--
|
||||
2.5.0
|
||||
|
43
alsa.changes
43
alsa.changes
@ -1,3 +1,46 @@
|
||||
-------------------------------------------------------------------
|
||||
Tue Aug 4 17:41:39 CEST 2015 - tiwai@suse.de
|
||||
|
||||
- Backport upstream fixes: surround41/50 chmap fix, UCM documents,
|
||||
config string fix, PCM timestamp query API, replacement of list.h
|
||||
with LGPL:
|
||||
0023-surround41-50.conf-Use-chmap-syntax-for-better-flexi.patch
|
||||
0024-ucm-docs-fix-doxygen-exclude-patch-for-UCM-local-hea.patch
|
||||
0025-ucm-docs-Fix-doxygen-formatting-for-UCM-main-page.patch
|
||||
0026-docs-Add-UCM-link-to-main-doxygen-page.patch
|
||||
0027-Replace-unsafe-characters-with-_-in-card-name.patch
|
||||
0028-pcm-add-helper-functions-to-query-timestamping-capab.patch
|
||||
0029-pcm-add-support-for-get-set_audio_htstamp_config.patch
|
||||
0030-pcm-add-support-for-new-STATUS_EXT-ioctl.patch
|
||||
0031-test-fix-audio_time-with-new-get-set-audio_tstamp_co.patch
|
||||
0032-test-audio_time-show-report-validity-and-accuracy.patch
|
||||
0033-pcm-restore-hw-params-on-set-latency-failed.patch
|
||||
0034-Replace-list.h-with-its-own-version.patch
|
||||
- Backport topology API addition patches:
|
||||
0035-topology-uapi-Add-UAPI-headers-for-topology-ABI.patch
|
||||
0036-topology-Add-topology-core-parser.patch
|
||||
0037-topology-Add-text-section-parser.patch
|
||||
0038-topology-Add-PCM-parser.patch
|
||||
0039-topology-Add-operations-parser.patch
|
||||
0040-topology-Add-private-data-parser.patch
|
||||
0041-topology-Add-DAPM-object-parser.patch
|
||||
0042-topology-Add-CTL-parser.patch
|
||||
0043-topology-Add-Channel-map-parser.patch
|
||||
0044-topology-Add-binary-file-builder.patch
|
||||
0045-topology-autotools-Add-build-support-for-topology-co.patch
|
||||
0046-topology-doxygen-Add-doxygen-support-for-topology-co.patch
|
||||
0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch
|
||||
0048-topology-Fix-missing-inclusion-of-ctype.h.patch
|
||||
0049-topology-Fix-typos.patch
|
||||
- Enable autoreconf call to regenerate after patching
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Fri Jul 31 07:35:12 UTC 2015 - dimstar@opensuse.org
|
||||
|
||||
- Change libudev-devel BuildRequires to pkgconfig(udev): makes us
|
||||
less prone to packaging changes, and in the end udev.pc is
|
||||
exactly what we need to define _udevdir.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Jun 18 09:32:07 CEST 2015 - tiwai@suse.de
|
||||
|
||||
|
58
alsa.spec
58
alsa.spec
@ -71,6 +71,33 @@ Patch19: 0019-pcm-Don-t-assert-in-_snd_pcm_hw_params_internal.patch
|
||||
Patch20: 0020-pcm-Fix-snd_pcm_status-for-dmix-co.patch
|
||||
Patch21: 0021-control-Allow-cset-ing-specific-values-in-the-multi-.patch
|
||||
Patch22: 0022-PCM-snd_pcm_xxxx_drain-maybe-blocked-after-suspend-a.patch
|
||||
Patch23: 0023-surround41-50.conf-Use-chmap-syntax-for-better-flexi.patch
|
||||
Patch24: 0024-ucm-docs-fix-doxygen-exclude-patch-for-UCM-local-hea.patch
|
||||
Patch25: 0025-ucm-docs-Fix-doxygen-formatting-for-UCM-main-page.patch
|
||||
Patch26: 0026-docs-Add-UCM-link-to-main-doxygen-page.patch
|
||||
Patch27: 0027-Replace-unsafe-characters-with-_-in-card-name.patch
|
||||
Patch28: 0028-pcm-add-helper-functions-to-query-timestamping-capab.patch
|
||||
Patch29: 0029-pcm-add-support-for-get-set_audio_htstamp_config.patch
|
||||
Patch30: 0030-pcm-add-support-for-new-STATUS_EXT-ioctl.patch
|
||||
Patch31: 0031-test-fix-audio_time-with-new-get-set-audio_tstamp_co.patch
|
||||
Patch32: 0032-test-audio_time-show-report-validity-and-accuracy.patch
|
||||
Patch33: 0033-pcm-restore-hw-params-on-set-latency-failed.patch
|
||||
Patch34: 0034-Replace-list.h-with-its-own-version.patch
|
||||
Patch35: 0035-topology-uapi-Add-UAPI-headers-for-topology-ABI.patch
|
||||
Patch36: 0036-topology-Add-topology-core-parser.patch
|
||||
Patch37: 0037-topology-Add-text-section-parser.patch
|
||||
Patch38: 0038-topology-Add-PCM-parser.patch
|
||||
Patch39: 0039-topology-Add-operations-parser.patch
|
||||
Patch40: 0040-topology-Add-private-data-parser.patch
|
||||
Patch41: 0041-topology-Add-DAPM-object-parser.patch
|
||||
Patch42: 0042-topology-Add-CTL-parser.patch
|
||||
Patch43: 0043-topology-Add-Channel-map-parser.patch
|
||||
Patch44: 0044-topology-Add-binary-file-builder.patch
|
||||
Patch45: 0045-topology-autotools-Add-build-support-for-topology-co.patch
|
||||
Patch46: 0046-topology-doxygen-Add-doxygen-support-for-topology-co.patch
|
||||
Patch47: 0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch
|
||||
Patch48: 0048-topology-Fix-missing-inclusion-of-ctype.h.patch
|
||||
Patch49: 0049-topology-Fix-typos.patch
|
||||
# rest suse patches
|
||||
Patch99: alsa-lib-doxygen-avoid-crash-for-11.3.diff
|
||||
# suppress timestamp in documents
|
||||
@ -86,7 +113,7 @@ Recommends: alsa-oss
|
||||
Recommends: alsa-plugins
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
%if 0%{?suse_version} > 1200
|
||||
BuildRequires: libudev-devel
|
||||
BuildRequires: pkgconfig(udev)
|
||||
%else
|
||||
BuildRequires: udev
|
||||
%endif
|
||||
@ -163,6 +190,33 @@ Architecture.
|
||||
%patch20 -p1
|
||||
%patch21 -p1
|
||||
%patch22 -p1
|
||||
%patch23 -p1
|
||||
%patch24 -p1
|
||||
%patch25 -p1
|
||||
%patch26 -p1
|
||||
%patch27 -p1
|
||||
%patch28 -p1
|
||||
%patch29 -p1
|
||||
%patch30 -p1
|
||||
%patch31 -p1
|
||||
%patch32 -p1
|
||||
%patch33 -p1
|
||||
%patch34 -p1
|
||||
%patch35 -p1
|
||||
%patch36 -p1
|
||||
%patch37 -p1
|
||||
%patch38 -p1
|
||||
%patch39 -p1
|
||||
%patch40 -p1
|
||||
%patch41 -p1
|
||||
%patch42 -p1
|
||||
%patch43 -p1
|
||||
%patch44 -p1
|
||||
%patch45 -p1
|
||||
%patch46 -p1
|
||||
%patch47 -p1
|
||||
%patch48 -p1
|
||||
%patch49 -p1
|
||||
%if 0%{?suse_version} == 1130
|
||||
%patch99 -p1
|
||||
%endif
|
||||
@ -178,7 +232,7 @@ sed -i -e'/recommends.*alsa-oss/d' $RPM_SOURCE_DIR/baselibs.conf
|
||||
%build
|
||||
export AUTOMAKE_JOBS="%{?_smp_mflags}"
|
||||
# build alsa-lib
|
||||
# autoreconf -fi
|
||||
autoreconf -fi
|
||||
%configure \
|
||||
--disable-static \
|
||||
--enable-symbolic-functions \
|
||||
|
Loading…
Reference in New Issue
Block a user