diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-05-22 10:04:45 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-05-22 10:04:45 -0400 |
commit | 181a152a09ccbf977ea69405cde4d87b5585de6c (patch) | |
tree | 7da9527a962994fb2c1202c7e63954c1f0e950f3 | |
parent | 6ab97f25ad1c3883f0dc20d2d5b7dae30acade74 (diff) | |
parent | 9203dd016a5d8ffb2eb6acdca60cd0b5dfe38c2b (diff) |
Merge branch 'topic/hdmi' into for-next
-rw-r--r-- | include/sound/pcm_drm_eld.h | 6 | ||||
-rw-r--r-- | include/sound/pcm_iec958.h | 9 | ||||
-rw-r--r-- | sound/core/Kconfig | 6 | ||||
-rw-r--r-- | sound/core/Makefile | 2 | ||||
-rw-r--r-- | sound/core/pcm_drm_eld.c | 99 | ||||
-rw-r--r-- | sound/core/pcm_iec958.c | 95 |
6 files changed, 217 insertions, 0 deletions
diff --git a/include/sound/pcm_drm_eld.h b/include/sound/pcm_drm_eld.h new file mode 100644 index 000000000000..93357b25d2e2 --- /dev/null +++ b/include/sound/pcm_drm_eld.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef __SOUND_PCM_DRM_ELD_H | ||
2 | #define __SOUND_PCM_DRM_ELD_H | ||
3 | |||
4 | int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime *runtime, void *eld); | ||
5 | |||
6 | #endif | ||
diff --git a/include/sound/pcm_iec958.h b/include/sound/pcm_iec958.h new file mode 100644 index 000000000000..0eed397aca8e --- /dev/null +++ b/include/sound/pcm_iec958.h | |||
@@ -0,0 +1,9 @@ | |||
1 | #ifndef __SOUND_PCM_IEC958_H | ||
2 | #define __SOUND_PCM_IEC958_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | |||
6 | int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, | ||
7 | size_t len); | ||
8 | |||
9 | #endif | ||
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 63cc2e967099..937f5c763899 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig | |||
@@ -6,6 +6,12 @@ config SND_PCM | |||
6 | tristate | 6 | tristate |
7 | select SND_TIMER | 7 | select SND_TIMER |
8 | 8 | ||
9 | config SND_PCM_ELD | ||
10 | bool | ||
11 | |||
12 | config SND_PCM_IEC958 | ||
13 | bool | ||
14 | |||
9 | config SND_DMAENGINE_PCM | 15 | config SND_DMAENGINE_PCM |
10 | tristate | 16 | tristate |
11 | 17 | ||
diff --git a/sound/core/Makefile b/sound/core/Makefile index 7dd17a365269..73871b63a092 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile | |||
@@ -16,6 +16,8 @@ snd-$(CONFIG_SND_JACK) += ctljack.o jack.o | |||
16 | snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ | 16 | snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ |
17 | pcm_memory.o memalloc.o | 17 | pcm_memory.o memalloc.o |
18 | snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o | 18 | snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o |
19 | snd-pcm-$(CONFIG_SND_PCM_ELD) += pcm_drm_eld.o | ||
20 | snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o | ||
19 | 21 | ||
20 | # for trace-points | 22 | # for trace-points |
21 | CFLAGS_pcm_lib.o := -I$(src) | 23 | CFLAGS_pcm_lib.o := -I$(src) |
diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c new file mode 100644 index 000000000000..e70379fb63d0 --- /dev/null +++ b/sound/core/pcm_drm_eld.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * PCM DRM helpers | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | #include <linux/export.h> | ||
9 | #include <drm/drm_edid.h> | ||
10 | #include <sound/pcm.h> | ||
11 | #include <sound/pcm_drm_eld.h> | ||
12 | |||
13 | static const unsigned int eld_rates[] = { | ||
14 | 32000, | ||
15 | 44100, | ||
16 | 48000, | ||
17 | 88200, | ||
18 | 96000, | ||
19 | 176400, | ||
20 | 192000, | ||
21 | }; | ||
22 | |||
23 | static unsigned int sad_max_channels(const u8 *sad) | ||
24 | { | ||
25 | return 1 + (sad[0] & 7); | ||
26 | } | ||
27 | |||
28 | static int eld_limit_rates(struct snd_pcm_hw_params *params, | ||
29 | struct snd_pcm_hw_rule *rule) | ||
30 | { | ||
31 | struct snd_interval *r = hw_param_interval(params, rule->var); | ||
32 | struct snd_interval *c; | ||
33 | unsigned int rate_mask = 7, i; | ||
34 | const u8 *sad, *eld = rule->private; | ||
35 | |||
36 | sad = drm_eld_sad(eld); | ||
37 | if (sad) { | ||
38 | c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
39 | |||
40 | for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) { | ||
41 | unsigned max_channels = sad_max_channels(sad); | ||
42 | |||
43 | /* | ||
44 | * Exclude SADs which do not include the | ||
45 | * requested number of channels. | ||
46 | */ | ||
47 | if (c->min <= max_channels) | ||
48 | rate_mask |= sad[1]; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | return snd_interval_list(r, ARRAY_SIZE(eld_rates), eld_rates, | ||
53 | rate_mask); | ||
54 | } | ||
55 | |||
56 | static int eld_limit_channels(struct snd_pcm_hw_params *params, | ||
57 | struct snd_pcm_hw_rule *rule) | ||
58 | { | ||
59 | struct snd_interval *c = hw_param_interval(params, rule->var); | ||
60 | struct snd_interval *r; | ||
61 | struct snd_interval t = { .min = 1, .max = 2, .integer = 1, }; | ||
62 | unsigned int i; | ||
63 | const u8 *sad, *eld = rule->private; | ||
64 | |||
65 | sad = drm_eld_sad(eld); | ||
66 | if (sad) { | ||
67 | unsigned int rate_mask = 0; | ||
68 | |||
69 | /* Convert the rate interval to a mask */ | ||
70 | r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
71 | for (i = 0; i < ARRAY_SIZE(eld_rates); i++) | ||
72 | if (r->min <= eld_rates[i] && r->max >= eld_rates[i]) | ||
73 | rate_mask |= BIT(i); | ||
74 | |||
75 | for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) | ||
76 | if (rate_mask & sad[1]) | ||
77 | t.max = max(t.max, sad_max_channels(sad)); | ||
78 | } | ||
79 | |||
80 | return snd_interval_refine(c, &t); | ||
81 | } | ||
82 | |||
83 | int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime *runtime, void *eld) | ||
84 | { | ||
85 | int ret; | ||
86 | |||
87 | ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
88 | eld_limit_rates, eld, | ||
89 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
90 | if (ret < 0) | ||
91 | return ret; | ||
92 | |||
93 | ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
94 | eld_limit_channels, eld, | ||
95 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
96 | |||
97 | return ret; | ||
98 | } | ||
99 | EXPORT_SYMBOL_GPL(snd_pcm_hw_constraint_eld); | ||
diff --git a/sound/core/pcm_iec958.c b/sound/core/pcm_iec958.c new file mode 100644 index 000000000000..36b2d7aca1bd --- /dev/null +++ b/sound/core/pcm_iec958.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * PCM DRM helpers | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | #include <linux/export.h> | ||
9 | #include <linux/types.h> | ||
10 | #include <sound/asoundef.h> | ||
11 | #include <sound/pcm.h> | ||
12 | #include <sound/pcm_iec958.h> | ||
13 | |||
14 | /** | ||
15 | * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status | ||
16 | * @runtime: pcm runtime structure with ->rate filled in | ||
17 | * @cs: channel status buffer, at least four bytes | ||
18 | * @len: length of channel status buffer | ||
19 | * | ||
20 | * Create the consumer format channel status data in @cs of maximum size | ||
21 | * @len corresponding to the parameters of the PCM runtime @runtime. | ||
22 | * | ||
23 | * Drivers may wish to tweak the contents of the buffer after creation. | ||
24 | * | ||
25 | * Returns: length of buffer, or negative error code if something failed. | ||
26 | */ | ||
27 | int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, | ||
28 | size_t len) | ||
29 | { | ||
30 | unsigned int fs, ws; | ||
31 | |||
32 | if (len < 4) | ||
33 | return -EINVAL; | ||
34 | |||
35 | switch (runtime->rate) { | ||
36 | case 32000: | ||
37 | fs = IEC958_AES3_CON_FS_32000; | ||
38 | break; | ||
39 | case 44100: | ||
40 | fs = IEC958_AES3_CON_FS_44100; | ||
41 | break; | ||
42 | case 48000: | ||
43 | fs = IEC958_AES3_CON_FS_48000; | ||
44 | break; | ||
45 | case 88200: | ||
46 | fs = IEC958_AES3_CON_FS_88200; | ||
47 | break; | ||
48 | case 96000: | ||
49 | fs = IEC958_AES3_CON_FS_96000; | ||
50 | break; | ||
51 | case 176400: | ||
52 | fs = IEC958_AES3_CON_FS_176400; | ||
53 | break; | ||
54 | case 192000: | ||
55 | fs = IEC958_AES3_CON_FS_192000; | ||
56 | break; | ||
57 | default: | ||
58 | return -EINVAL; | ||
59 | } | ||
60 | |||
61 | if (len > 4) { | ||
62 | switch (snd_pcm_format_width(runtime->format)) { | ||
63 | case 16: | ||
64 | ws = IEC958_AES4_CON_WORDLEN_20_16; | ||
65 | break; | ||
66 | case 18: | ||
67 | ws = IEC958_AES4_CON_WORDLEN_22_18; | ||
68 | break; | ||
69 | case 20: | ||
70 | ws = IEC958_AES4_CON_WORDLEN_20_16 | | ||
71 | IEC958_AES4_CON_MAX_WORDLEN_24; | ||
72 | break; | ||
73 | case 24: | ||
74 | ws = IEC958_AES4_CON_WORDLEN_24_20 | | ||
75 | IEC958_AES4_CON_MAX_WORDLEN_24; | ||
76 | break; | ||
77 | |||
78 | default: | ||
79 | return -EINVAL; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | memset(cs, 0, len); | ||
84 | |||
85 | cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; | ||
86 | cs[1] = IEC958_AES1_CON_GENERAL; | ||
87 | cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; | ||
88 | cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | fs; | ||
89 | |||
90 | if (len > 4) | ||
91 | cs[4] = ws; | ||
92 | |||
93 | return len; | ||
94 | } | ||
95 | EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); | ||