|  | /* | 
|  | *  PCM DRM helpers | 
|  | * | 
|  | *   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. | 
|  | */ | 
|  | #include <linux/export.h> | 
|  | #include <linux/types.h> | 
|  | #include <sound/asoundef.h> | 
|  | #include <sound/pcm.h> | 
|  | #include <sound/pcm_params.h> | 
|  | #include <sound/pcm_iec958.h> | 
|  |  | 
|  | static int create_iec958_consumer(uint rate, uint sample_width, | 
|  | u8 *cs, size_t len) | 
|  | { | 
|  | unsigned int fs, ws; | 
|  |  | 
|  | if (len < 4) | 
|  | return -EINVAL; | 
|  |  | 
|  | switch (rate) { | 
|  | case 32000: | 
|  | fs = IEC958_AES3_CON_FS_32000; | 
|  | break; | 
|  | case 44100: | 
|  | fs = IEC958_AES3_CON_FS_44100; | 
|  | break; | 
|  | case 48000: | 
|  | fs = IEC958_AES3_CON_FS_48000; | 
|  | break; | 
|  | case 88200: | 
|  | fs = IEC958_AES3_CON_FS_88200; | 
|  | break; | 
|  | case 96000: | 
|  | fs = IEC958_AES3_CON_FS_96000; | 
|  | break; | 
|  | case 176400: | 
|  | fs = IEC958_AES3_CON_FS_176400; | 
|  | break; | 
|  | case 192000: | 
|  | fs = IEC958_AES3_CON_FS_192000; | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | if (len > 4) { | 
|  | switch (sample_width) { | 
|  | case 16: | 
|  | ws = IEC958_AES4_CON_WORDLEN_20_16; | 
|  | break; | 
|  | case 18: | 
|  | ws = IEC958_AES4_CON_WORDLEN_22_18; | 
|  | break; | 
|  | case 20: | 
|  | ws = IEC958_AES4_CON_WORDLEN_20_16 | | 
|  | IEC958_AES4_CON_MAX_WORDLEN_24; | 
|  | break; | 
|  | case 24: | 
|  | case 32: /* Assume 24-bit width for 32-bit samples. */ | 
|  | ws = IEC958_AES4_CON_WORDLEN_24_20 | | 
|  | IEC958_AES4_CON_MAX_WORDLEN_24; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  | } | 
|  |  | 
|  | memset(cs, 0, len); | 
|  |  | 
|  | cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; | 
|  | cs[1] = IEC958_AES1_CON_GENERAL; | 
|  | cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; | 
|  | cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | fs; | 
|  |  | 
|  | if (len > 4) | 
|  | cs[4] = ws; | 
|  |  | 
|  | return len; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status | 
|  | * @runtime: pcm runtime structure with ->rate filled in | 
|  | * @cs: channel status buffer, at least four bytes | 
|  | * @len: length of channel status buffer | 
|  | * | 
|  | * Create the consumer format channel status data in @cs of maximum size | 
|  | * @len corresponding to the parameters of the PCM runtime @runtime. | 
|  | * | 
|  | * Drivers may wish to tweak the contents of the buffer after creation. | 
|  | * | 
|  | * Returns: length of buffer, or negative error code if something failed. | 
|  | */ | 
|  | int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, | 
|  | size_t len) | 
|  | { | 
|  | return create_iec958_consumer(runtime->rate, | 
|  | snd_pcm_format_width(runtime->format), | 
|  | cs, len); | 
|  | } | 
|  | EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); | 
|  |  | 
|  | /** | 
|  | * snd_pcm_create_iec958_consumer_hw_params - create IEC958 channel status | 
|  | * @hw_params: the hw_params instance for extracting rate and sample format | 
|  | * @cs: channel status buffer, at least four bytes | 
|  | * @len: length of channel status buffer | 
|  | * | 
|  | * Create the consumer format channel status data in @cs of maximum size | 
|  | * @len corresponding to the parameters of the PCM runtime @runtime. | 
|  | * | 
|  | * Drivers may wish to tweak the contents of the buffer after creation. | 
|  | * | 
|  | * Returns: length of buffer, or negative error code if something failed. | 
|  | */ | 
|  | int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, | 
|  | u8 *cs, size_t len) | 
|  | { | 
|  | return create_iec958_consumer(params_rate(params), params_width(params), | 
|  | cs, len); | 
|  | } | 
|  | EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params); |