// SPDX-License-Identifier: GPL-2.0-only1/*2* PCM DRM helpers3*/4#include <linux/export.h>5#include <linux/types.h>6#include <sound/asoundef.h>7#include <sound/pcm.h>8#include <sound/pcm_params.h>9#include <sound/pcm_iec958.h>1011/**12* snd_pcm_create_iec958_consumer_default - create default consumer format IEC958 channel status13* @cs: channel status buffer, at least four bytes14* @len: length of channel status buffer15*16* Create the consumer format channel status data in @cs of maximum size17* @len. When relevant, the configuration-dependant bits will be set as18* unspecified.19*20* Drivers should then call einter snd_pcm_fill_iec958_consumer() or21* snd_pcm_fill_iec958_consumer_hw_params() to replace these unspecified22* bits by their actual values.23*24* Drivers may wish to tweak the contents of the buffer after creation.25*26* Returns: length of buffer, or negative error code if something failed.27*/28int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len)29{30if (len < 4)31return -EINVAL;3233memset(cs, 0, len);3435cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;36cs[1] = IEC958_AES1_CON_GENERAL;37cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;38cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID;3940if (len > 4)41cs[4] = IEC958_AES4_CON_WORDLEN_NOTID;4243return len;44}45EXPORT_SYMBOL_GPL(snd_pcm_create_iec958_consumer_default);4647static int fill_iec958_consumer(uint rate, uint sample_width,48u8 *cs, size_t len)49{50if (len < 4)51return -EINVAL;5253if ((cs[3] & IEC958_AES3_CON_FS) == IEC958_AES3_CON_FS_NOTID) {54unsigned int fs;5556switch (rate) {57case 32000:58fs = IEC958_AES3_CON_FS_32000;59break;60case 44100:61fs = IEC958_AES3_CON_FS_44100;62break;63case 48000:64fs = IEC958_AES3_CON_FS_48000;65break;66case 88200:67fs = IEC958_AES3_CON_FS_88200;68break;69case 96000:70fs = IEC958_AES3_CON_FS_96000;71break;72case 176400:73fs = IEC958_AES3_CON_FS_176400;74break;75case 192000:76fs = IEC958_AES3_CON_FS_192000;77break;78default:79return -EINVAL;80}8182cs[3] &= ~IEC958_AES3_CON_FS;83cs[3] |= fs;84}8586if (len > 4 &&87(cs[4] & IEC958_AES4_CON_WORDLEN) == IEC958_AES4_CON_WORDLEN_NOTID) {88unsigned int ws;8990switch (sample_width) {91case 16:92ws = IEC958_AES4_CON_WORDLEN_20_16;93break;94case 18:95ws = IEC958_AES4_CON_WORDLEN_22_18;96break;97case 20:98ws = IEC958_AES4_CON_WORDLEN_20_16 |99IEC958_AES4_CON_MAX_WORDLEN_24;100break;101case 24:102case 32: /* Assume 24-bit width for 32-bit samples. */103ws = IEC958_AES4_CON_WORDLEN_24_20 |104IEC958_AES4_CON_MAX_WORDLEN_24;105break;106107default:108return -EINVAL;109}110111cs[4] &= ~IEC958_AES4_CON_WORDLEN;112cs[4] |= ws;113}114115return len;116}117118/**119* snd_pcm_fill_iec958_consumer - Fill consumer format IEC958 channel status120* @runtime: pcm runtime structure with ->rate filled in121* @cs: channel status buffer, at least four bytes122* @len: length of channel status buffer123*124* Fill the unspecified bits in an IEC958 status bits array using the125* parameters of the PCM runtime @runtime.126*127* Drivers may wish to tweak the contents of the buffer after its been128* filled.129*130* Returns: length of buffer, or negative error code if something failed.131*/132int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime,133u8 *cs, size_t len)134{135return fill_iec958_consumer(runtime->rate,136snd_pcm_format_width(runtime->format),137cs, len);138}139EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer);140141/**142* snd_pcm_fill_iec958_consumer_hw_params - Fill consumer format IEC958 channel status143* @params: the hw_params instance for extracting rate and sample format144* @cs: channel status buffer, at least four bytes145* @len: length of channel status buffer146*147* Fill the unspecified bits in an IEC958 status bits array using the148* parameters of the PCM hardware parameters @params.149*150* Drivers may wish to tweak the contents of the buffer after its been151* filled..152*153* Returns: length of buffer, or negative error code if something failed.154*/155int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,156u8 *cs, size_t len)157{158return fill_iec958_consumer(params_rate(params), params_width(params), cs, len);159}160EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer_hw_params);161162/**163* snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status164* @runtime: pcm runtime structure with ->rate filled in165* @cs: channel status buffer, at least four bytes166* @len: length of channel status buffer167*168* Create the consumer format channel status data in @cs of maximum size169* @len corresponding to the parameters of the PCM runtime @runtime.170*171* Drivers may wish to tweak the contents of the buffer after creation.172*173* Returns: length of buffer, or negative error code if something failed.174*/175int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,176size_t len)177{178int ret;179180ret = snd_pcm_create_iec958_consumer_default(cs, len);181if (ret < 0)182return ret;183184return snd_pcm_fill_iec958_consumer(runtime, cs, len);185}186EXPORT_SYMBOL(snd_pcm_create_iec958_consumer);187188/**189* snd_pcm_create_iec958_consumer_hw_params - create IEC958 channel status190* @params: the hw_params instance for extracting rate and sample format191* @cs: channel status buffer, at least four bytes192* @len: length of channel status buffer193*194* Create the consumer format channel status data in @cs of maximum size195* @len corresponding to the parameters of the PCM runtime @runtime.196*197* Drivers may wish to tweak the contents of the buffer after creation.198*199* Returns: length of buffer, or negative error code if something failed.200*/201int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,202u8 *cs, size_t len)203{204int ret;205206ret = snd_pcm_create_iec958_consumer_default(cs, len);207if (ret < 0)208return ret;209210return fill_iec958_consumer(params_rate(params), params_width(params), cs, len);211}212EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params);213214215