.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * 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 | 4 | */ |
---|
8 | 5 | #include <linux/export.h> |
---|
9 | 6 | #include <linux/types.h> |
---|
.. | .. |
---|
12 | 9 | #include <sound/pcm_params.h> |
---|
13 | 10 | #include <sound/pcm_iec958.h> |
---|
14 | 11 | |
---|
15 | | -static int create_iec958_consumer(uint rate, uint sample_width, |
---|
16 | | - u8 *cs, size_t len) |
---|
| 12 | +/** |
---|
| 13 | + * snd_pcm_create_iec958_consumer_default - create default consumer format IEC958 channel status |
---|
| 14 | + * @cs: channel status buffer, at least four bytes |
---|
| 15 | + * @len: length of channel status buffer |
---|
| 16 | + * |
---|
| 17 | + * Create the consumer format channel status data in @cs of maximum size |
---|
| 18 | + * @len. When relevant, the configuration-dependant bits will be set as |
---|
| 19 | + * unspecified. |
---|
| 20 | + * |
---|
| 21 | + * Drivers should then call einter snd_pcm_fill_iec958_consumer() or |
---|
| 22 | + * snd_pcm_fill_iec958_consumer_hw_params() to replace these unspecified |
---|
| 23 | + * bits by their actual values. |
---|
| 24 | + * |
---|
| 25 | + * Drivers may wish to tweak the contents of the buffer after creation. |
---|
| 26 | + * |
---|
| 27 | + * Returns: length of buffer, or negative error code if something failed. |
---|
| 28 | + */ |
---|
| 29 | +int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len) |
---|
17 | 30 | { |
---|
18 | | - unsigned int fs, ws; |
---|
19 | | - |
---|
20 | 31 | if (len < 4) |
---|
21 | 32 | return -EINVAL; |
---|
22 | 33 | |
---|
23 | | - switch (rate) { |
---|
24 | | - case 32000: |
---|
25 | | - fs = IEC958_AES3_CON_FS_32000; |
---|
26 | | - break; |
---|
27 | | - case 44100: |
---|
28 | | - fs = IEC958_AES3_CON_FS_44100; |
---|
29 | | - break; |
---|
30 | | - case 48000: |
---|
31 | | - fs = IEC958_AES3_CON_FS_48000; |
---|
32 | | - break; |
---|
33 | | - case 88200: |
---|
34 | | - fs = IEC958_AES3_CON_FS_88200; |
---|
35 | | - break; |
---|
36 | | - case 96000: |
---|
37 | | - fs = IEC958_AES3_CON_FS_96000; |
---|
38 | | - break; |
---|
39 | | - case 176400: |
---|
40 | | - fs = IEC958_AES3_CON_FS_176400; |
---|
41 | | - break; |
---|
42 | | - case 192000: |
---|
43 | | - fs = IEC958_AES3_CON_FS_192000; |
---|
44 | | - break; |
---|
45 | | - default: |
---|
| 34 | + memset(cs, 0, len); |
---|
| 35 | + |
---|
| 36 | + cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; |
---|
| 37 | + cs[1] = IEC958_AES1_CON_GENERAL; |
---|
| 38 | + cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; |
---|
| 39 | + cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID; |
---|
| 40 | + |
---|
| 41 | + if (len > 4) |
---|
| 42 | + cs[4] = IEC958_AES4_CON_WORDLEN_NOTID; |
---|
| 43 | + |
---|
| 44 | + return len; |
---|
| 45 | +} |
---|
| 46 | +EXPORT_SYMBOL_GPL(snd_pcm_create_iec958_consumer_default); |
---|
| 47 | + |
---|
| 48 | +static int fill_iec958_consumer(uint rate, uint sample_width, |
---|
| 49 | + u8 *cs, size_t len) |
---|
| 50 | +{ |
---|
| 51 | + if (len < 4) |
---|
46 | 52 | return -EINVAL; |
---|
| 53 | + |
---|
| 54 | + if ((cs[3] & IEC958_AES3_CON_FS) == IEC958_AES3_CON_FS_NOTID) { |
---|
| 55 | + unsigned int fs; |
---|
| 56 | + |
---|
| 57 | + switch (rate) { |
---|
| 58 | + case 32000: |
---|
| 59 | + fs = IEC958_AES3_CON_FS_32000; |
---|
| 60 | + break; |
---|
| 61 | + case 44100: |
---|
| 62 | + fs = IEC958_AES3_CON_FS_44100; |
---|
| 63 | + break; |
---|
| 64 | + case 48000: |
---|
| 65 | + fs = IEC958_AES3_CON_FS_48000; |
---|
| 66 | + break; |
---|
| 67 | + case 88200: |
---|
| 68 | + fs = IEC958_AES3_CON_FS_88200; |
---|
| 69 | + break; |
---|
| 70 | + case 96000: |
---|
| 71 | + fs = IEC958_AES3_CON_FS_96000; |
---|
| 72 | + break; |
---|
| 73 | + case 176400: |
---|
| 74 | + fs = IEC958_AES3_CON_FS_176400; |
---|
| 75 | + break; |
---|
| 76 | + case 192000: |
---|
| 77 | + fs = IEC958_AES3_CON_FS_192000; |
---|
| 78 | + break; |
---|
| 79 | + default: |
---|
| 80 | + return -EINVAL; |
---|
| 81 | + } |
---|
| 82 | + |
---|
| 83 | + cs[3] &= ~IEC958_AES3_CON_FS; |
---|
| 84 | + cs[3] |= fs; |
---|
47 | 85 | } |
---|
48 | 86 | |
---|
49 | | - if (len > 4) { |
---|
| 87 | + if (len > 4 && |
---|
| 88 | + (cs[4] & IEC958_AES4_CON_WORDLEN) == IEC958_AES4_CON_WORDLEN_NOTID) { |
---|
| 89 | + unsigned int ws; |
---|
| 90 | + |
---|
50 | 91 | switch (sample_width) { |
---|
51 | 92 | case 16: |
---|
52 | 93 | ws = IEC958_AES4_CON_WORDLEN_20_16; |
---|
.. | .. |
---|
67 | 108 | default: |
---|
68 | 109 | return -EINVAL; |
---|
69 | 110 | } |
---|
| 111 | + |
---|
| 112 | + cs[4] &= ~IEC958_AES4_CON_WORDLEN; |
---|
| 113 | + cs[4] |= ws; |
---|
70 | 114 | } |
---|
71 | | - |
---|
72 | | - memset(cs, 0, len); |
---|
73 | | - |
---|
74 | | - cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; |
---|
75 | | - cs[1] = IEC958_AES1_CON_GENERAL; |
---|
76 | | - cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; |
---|
77 | | - cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | fs; |
---|
78 | | - |
---|
79 | | - if (len > 4) |
---|
80 | | - cs[4] = ws; |
---|
81 | 115 | |
---|
82 | 116 | return len; |
---|
83 | 117 | } |
---|
| 118 | + |
---|
| 119 | +/** |
---|
| 120 | + * snd_pcm_fill_iec958_consumer - Fill consumer format IEC958 channel status |
---|
| 121 | + * @runtime: pcm runtime structure with ->rate filled in |
---|
| 122 | + * @cs: channel status buffer, at least four bytes |
---|
| 123 | + * @len: length of channel status buffer |
---|
| 124 | + * |
---|
| 125 | + * Fill the unspecified bits in an IEC958 status bits array using the |
---|
| 126 | + * parameters of the PCM runtime @runtime. |
---|
| 127 | + * |
---|
| 128 | + * Drivers may wish to tweak the contents of the buffer after its been |
---|
| 129 | + * filled. |
---|
| 130 | + * |
---|
| 131 | + * Returns: length of buffer, or negative error code if something failed. |
---|
| 132 | + */ |
---|
| 133 | +int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime, |
---|
| 134 | + u8 *cs, size_t len) |
---|
| 135 | +{ |
---|
| 136 | + return fill_iec958_consumer(runtime->rate, |
---|
| 137 | + snd_pcm_format_width(runtime->format), |
---|
| 138 | + cs, len); |
---|
| 139 | +} |
---|
| 140 | +EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer); |
---|
| 141 | + |
---|
| 142 | +/** |
---|
| 143 | + * snd_pcm_fill_iec958_consumer_hw_params - Fill consumer format IEC958 channel status |
---|
| 144 | + * @params: the hw_params instance for extracting rate and sample format |
---|
| 145 | + * @cs: channel status buffer, at least four bytes |
---|
| 146 | + * @len: length of channel status buffer |
---|
| 147 | + * |
---|
| 148 | + * Fill the unspecified bits in an IEC958 status bits array using the |
---|
| 149 | + * parameters of the PCM hardware parameters @params. |
---|
| 150 | + * |
---|
| 151 | + * Drivers may wish to tweak the contents of the buffer after its been |
---|
| 152 | + * filled.. |
---|
| 153 | + * |
---|
| 154 | + * Returns: length of buffer, or negative error code if something failed. |
---|
| 155 | + */ |
---|
| 156 | +int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, |
---|
| 157 | + u8 *cs, size_t len) |
---|
| 158 | +{ |
---|
| 159 | + return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); |
---|
| 160 | +} |
---|
| 161 | +EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer_hw_params); |
---|
84 | 162 | |
---|
85 | 163 | /** |
---|
86 | 164 | * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status |
---|
.. | .. |
---|
98 | 176 | int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, |
---|
99 | 177 | size_t len) |
---|
100 | 178 | { |
---|
101 | | - return create_iec958_consumer(runtime->rate, |
---|
102 | | - snd_pcm_format_width(runtime->format), |
---|
103 | | - cs, len); |
---|
| 179 | + int ret; |
---|
| 180 | + |
---|
| 181 | + ret = snd_pcm_create_iec958_consumer_default(cs, len); |
---|
| 182 | + if (ret < 0) |
---|
| 183 | + return ret; |
---|
| 184 | + |
---|
| 185 | + return snd_pcm_fill_iec958_consumer(runtime, cs, len); |
---|
104 | 186 | } |
---|
105 | 187 | EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); |
---|
106 | 188 | |
---|
107 | 189 | /** |
---|
108 | 190 | * snd_pcm_create_iec958_consumer_hw_params - create IEC958 channel status |
---|
109 | | - * @hw_params: the hw_params instance for extracting rate and sample format |
---|
| 191 | + * @params: the hw_params instance for extracting rate and sample format |
---|
110 | 192 | * @cs: channel status buffer, at least four bytes |
---|
111 | 193 | * @len: length of channel status buffer |
---|
112 | 194 | * |
---|
.. | .. |
---|
120 | 202 | int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, |
---|
121 | 203 | u8 *cs, size_t len) |
---|
122 | 204 | { |
---|
123 | | - return create_iec958_consumer(params_rate(params), params_width(params), |
---|
124 | | - cs, len); |
---|
| 205 | + int ret; |
---|
| 206 | + |
---|
| 207 | + ret = snd_pcm_create_iec958_consumer_default(cs, len); |
---|
| 208 | + if (ret < 0) |
---|
| 209 | + return ret; |
---|
| 210 | + |
---|
| 211 | + return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); |
---|
125 | 212 | } |
---|
126 | 213 | EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params); |
---|