A previous commit adds serializer/deserializer of 'snd_ctl_elem_value' structure for System V ABIs to modern 32 bit architectures. However, i386 is an exception because it has 4 bytes alignment for double-word machine type. This brings different 'internal padding' to the structure from the one on ABIs for modern 32 bit architectures.
This commit adds a pair of serializer and deserializer to convert data between different layout of the structure on the ABIs. To describe layout of the structure for i386 ABI on LP64 ABI, bitfield is used for the internal padding, and 'packed' attribute is used as a hint for compilers to native padding convention.
The serializer/deserializer are useless on non-Intel architectures. For this case, '__maybe_unused' is added as a hint to compilers for optimization.
Reference: System V application binary interface Intel386 architecture processor supplenent, draft copy of forth edition (1997, The Santa Cruz Operation, Inc. and AT&T) Reference: System V application binary interface AMD64 architecture processor supplement (with LP64 and ILP32 programming models) draft version 0.99.8 (2017, H.J. Lu, Michael Matz, Milind Girkar, Jan Hubicka, Andreas Jaeger and Mark Mitchell) Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/core/control_compat.c | 89 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+)
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 5c0e82afe400..5dfb31a22470 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -308,6 +308,95 @@ static int __maybe_unused serialize_to_elem_value_32( return 0; }
+/* + * Unlikw any System V ABI for 32 bit architecture, ABI for i386 architecture has + * different alignment (4 bytes) for double-word type. Thus offset of '.value' + * member is multiples of 4 bytes. + */ +struct snd_ctl_elem_value_i386 { + struct snd_ctl_elem_id id; + u32 indirect:1; + u32 padding:31; /* For 4 bytes alignment of '.value'. */ + union { + s32 integer[128]; /* long on ILP32. */ + u8 data[512]; + s64 integer64[64]; + } value; + struct { + s32 tv_sec; /* long on ILP32. */ + s32 tv_nsec; /* long on ILP32. */ + } tstamp; + u8 reserved[128 - sizeof(s32) - sizeof(s32)]; +} __packed; + +static int __maybe_unused deserialize_from_elem_value_i386( + struct snd_ctl_file *ctl_file, void *dst, void *src) +{ + struct snd_ctl_elem_value *data = dst; + struct snd_ctl_elem_value_i386 *datai386 = src; + snd_ctl_elem_type_t type; + int err; + + err = get_type(ctl_file, &datai386->id, &type); + if (err < 0) + return err; + + data->id = datai386->id; + data->indirect = datai386->indirect; + + if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || + type == SNDRV_CTL_ELEM_TYPE_INTEGER) { + int i; + for (i = 0; i < 128; ++i) { + data->value.integer.value[i] = + (s64)datai386->value.integer[i]; + } + /* Drop rest of this field. */ + } else { + /* Copy whole space of this field. */ + memcpy(&data->value, &datai386->value, sizeof(data->value)); + } + + data->tstamp.tv_sec = (s64)datai386->tstamp.tv_sec; + data->tstamp.tv_nsec = (s64)datai386->tstamp.tv_nsec; + + return 0; +} + +static int __maybe_unused serialize_to_elem_value_i386( + struct snd_ctl_file *ctl_file, void *dst, void *src) +{ + struct snd_ctl_elem_value_i386 *datai386 = dst; + struct snd_ctl_elem_value *data = src; + snd_ctl_elem_type_t type; + int err; + + err = get_type(ctl_file, &data->id, &type); + if (err < 0) + return err; + + datai386->id = data->id; + datai386->indirect = data->indirect; + + if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || + type == SNDRV_CTL_ELEM_TYPE_INTEGER) { + int i; + for (i = 0; i < 128; ++i) { + datai386->value.integer[i] = + (s32)data->value.integer.value[i]; + } + /* Drop rest of this field. */ + } else { + /* Copy whole space of this field. */ + memcpy(&datai386->value, &data->value, sizeof(datai386->value)); + } + + datai386->tstamp.tv_sec = (s32)data->tstamp.tv_sec; + datai386->tstamp.tv_nsec = (s32)data->tstamp.tv_nsec; + + return 0; +} + struct snd_ctl_elem_list32 { u32 offset; u32 space;