1

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,9 +486,11 @@ int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
enum avc_general_plug_dir dir, enum avc_general_plug_dir dir,
struct snd_oxfw_stream_formation *formation) struct snd_oxfw_stream_formation *formation)
{ {
int err;
if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) {
u8 *format; u8 *format;
unsigned int len; unsigned int len;
int err;
len = AVC_GENERIC_FRAME_MAXIMUM_BYTES; len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
format = kmalloc(len, GFP_KERNEL); format = kmalloc(len, GFP_KERNEL);
@ -496,16 +498,45 @@ int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
return -ENOMEM; return -ENOMEM;
err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len); err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
if (err < 0) if (err >= 0) {
goto end; if (len < 3)
if (len < 3) {
err = -EIO; err = -EIO;
goto end; else
err = snd_oxfw_stream_parse_format(format, formation);
} }
err = snd_oxfw_stream_parse_format(format, formation);
end:
kfree(format); 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;
}
return err; return err;
} }
@ -600,7 +631,8 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
unsigned int i, eid; unsigned int i, eid;
int err; int err;
/* get format at current sampling rate */ // 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); err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
if (err < 0) { if (err < 0) {
dev_err(&oxfw->unit->device, dev_err(&oxfw->unit->device,
@ -609,6 +641,24 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
pid, err); pid, err);
goto end; 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 */ /* parse and set stream format */
eid = 0; eid = 0;

View File

@ -52,6 +52,8 @@ enum snd_oxfw_quirk {
// performs media clock recovery voluntarily. In the recovery, the packets with NO_INFO // performs media clock recovery voluntarily. In the recovery, the packets with NO_INFO
// are ignored, thus driver should transfer packets with timestamp. // are ignored, thus driver should transfer packets with timestamp.
SND_OXFW_QUIRK_VOLUNTARY_RECOVERY = 0x20, 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. */ /* This is an arbitrary number for convinience. */