ALSA: oxfw: support the case that AV/C Stream Format Information command is not available

Miglia Harmony Audio does neither support AV/C Stream Format Information
command nor AV/C Extended Stream Format Information command.

This commit adds a workaround for the case and uses the hard-coded formats.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20240218074128.95210-3-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Sakamoto 2024-02-18 16:41:26 +09:00 committed by Takashi Iwai
parent 5c0a35b26f
commit 25ab2b2f6a
2 changed files with 75 additions and 23 deletions

View file

@ -486,26 +486,57 @@ int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
enum avc_general_plug_dir dir,
struct snd_oxfw_stream_formation *formation)
{
u8 *format;
unsigned int len;
int err;
len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
format = kmalloc(len, GFP_KERNEL);
if (format == NULL)
return -ENOMEM;
if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) {
u8 *format;
unsigned int len;
err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
if (err < 0)
goto end;
if (len < 3) {
err = -EIO;
goto end;
len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
format = kmalloc(len, GFP_KERNEL);
if (format == NULL)
return -ENOMEM;
err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
if (err >= 0) {
if (len < 3)
err = -EIO;
else
err = snd_oxfw_stream_parse_format(format, formation);
}
kfree(format);
} else {
// Miglia Harmony Audio does not support Extended Stream Format Information
// command. Use the duplicated hard-coded format, instead.
unsigned int rate;
u8 *const *formats;
int i;
err = avc_general_get_sig_fmt(oxfw->unit, &rate, dir, 0);
if (err < 0)
return err;
if (dir == AVC_GENERAL_PLUG_DIR_IN)
formats = oxfw->rx_stream_formats;
else
formats = oxfw->tx_stream_formats;
for (i = 0; (i < SND_OXFW_STREAM_FORMAT_ENTRIES); ++i) {
if (!formats[i])
continue;
err = snd_oxfw_stream_parse_format(formats[i], formation);
if (err < 0)
continue;
if (formation->rate == rate)
break;
}
if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
return -EIO;
}
err = snd_oxfw_stream_parse_format(format, formation);
end:
kfree(format);
return err;
}
@ -600,14 +631,33 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
unsigned int i, eid;
int err;
/* get format at current sampling rate */
err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
if (err < 0) {
dev_err(&oxfw->unit->device,
"fail to get current stream format for isoc %s plug %d:%d\n",
(dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
pid, err);
goto end;
// get format at current sampling rate.
if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) {
err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
if (err < 0) {
dev_err(&oxfw->unit->device,
"fail to get current stream format for isoc %s plug %d:%d\n",
(dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
pid, err);
goto end;
}
} else {
// Miglia Harmony Audio does not support Extended Stream Format Information
// command. Use the hard-coded format, instead.
buf[0] = 0x90;
buf[1] = 0x40;
buf[2] = avc_stream_rate_table[0];
buf[3] = 0x00;
buf[4] = 0x01;
if (dir == AVC_GENERAL_PLUG_DIR_IN)
buf[5] = 0x08;
else
buf[5] = 0x02;
buf[6] = 0x06;
*len = 7;
}
/* parse and set stream format */

View file

@ -52,6 +52,8 @@ enum snd_oxfw_quirk {
// performs media clock recovery voluntarily. In the recovery, the packets with NO_INFO
// are ignored, thus driver should transfer packets with timestamp.
SND_OXFW_QUIRK_VOLUNTARY_RECOVERY = 0x20,
// Miglia Harmony Audio does not support AV/C Stream Format Information command.
SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED = 0x40,
};
/* This is an arbitrary number for convinience. */