diff mbox series

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

Message ID 20240218074128.95210-3-o-takashi@sakamocchi.jp
State Accepted
Commit 25ab2b2f6ac209a3746eec42210a98fe047a7453
Headers show
Series ALSA: oxfw: add support for Miglia Harmony Audio | expand

Commit Message

Takashi Sakamoto Feb. 18, 2024, 7:41 a.m. UTC
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>
---
 sound/firewire/oxfw/oxfw-stream.c | 96 +++++++++++++++++++++++--------
 sound/firewire/oxfw/oxfw.h        |  2 +
 2 files changed, 75 insertions(+), 23 deletions(-)
diff mbox series

Patch

diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
index 6d8722f9d3a5..40716bb989c7 100644
--- a/sound/firewire/oxfw/oxfw-stream.c
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -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 */
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index 39316aeafeaa..3bf8d7bec636 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -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. */