From 34996e42f82bfd60bc2c191e5cae3c6ab233ec6c Mon Sep 17 00:00:00 2001
From: Daniel Baumann <daniel.baumann@progress-linux.org>
Date: Wed, 7 Aug 2024 15:11:27 +0200
Subject: Merging upstream version 6.9.7.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
---
 sound/firewire/oxfw/oxfw-stream.c | 100 +++++++++++++++++++++++++++++---------
 sound/firewire/oxfw/oxfw.c        |  10 +++-
 sound/firewire/oxfw/oxfw.h        |   7 ++-
 3 files changed, 91 insertions(+), 26 deletions(-)

(limited to 'sound/firewire/oxfw')

diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
index f4a702def3..00f7feb91f 100644
--- a/sound/firewire/oxfw/oxfw-stream.c
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -177,6 +177,8 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
 			flags |= CIP_JUMBO_PAYLOAD;
 		if (oxfw->quirks & SND_OXFW_QUIRK_WRONG_DBS)
 			flags |= CIP_WRONG_DBS;
+		if (oxfw->quirks & SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS)
+			flags |= CIP_DBC_IS_END_EVENT | CIP_DBC_IS_PAYLOAD_QUADLETS;
 	} else {
 		conn = &oxfw->in_conn;
 		c_dir = CMP_INPUT;
@@ -486,26 +488,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;
 }
 
@@ -515,7 +548,7 @@ end:
  * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
  * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
  */
-int snd_oxfw_stream_parse_format(u8 *format,
+int snd_oxfw_stream_parse_format(const u8 *format,
 				 struct snd_oxfw_stream_formation *formation)
 {
 	unsigned int i, e, channels, type;
@@ -600,14 +633,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.c b/sound/firewire/oxfw/oxfw.c
index 241a697ce2..98ae0e8cba 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -21,6 +21,7 @@
 #define VENDOR_TASCAM		0x00022e
 #define OUI_STANTON		0x001260
 #define OUI_APOGEE		0x0003db
+#define OUI_OXFORD		0x0030e0
 
 #define MODEL_SATELLITE		0x00200f
 #define MODEL_SCS1M		0x001000
@@ -232,6 +233,11 @@ static int oxfw_probe(struct fw_unit *unit, const struct ieee1394_device_id *ent
 	if (err < 0)
 		goto error;
 
+	if (entry->vendor_id == OUI_OXFORD && entry->model_id == 0x00f970) {
+		oxfw->quirks |= SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED |
+				SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS;
+	}
+
 	err = snd_oxfw_stream_discover(oxfw);
 	if (err < 0)
 		goto error;
@@ -330,6 +336,9 @@ static const struct ieee1394_device_id oxfw_id_table[] = {
 	//
 	OXFW_DEV_ENTRY(VENDOR_GRIFFIN, 0x00f970, &griffin_firewave),
 	OXFW_DEV_ENTRY(VENDOR_LACIE, 0x00f970, &lacie_speakers),
+	// Miglia HarmonyAudio (HA02). The numeric vendor ID is ASIC vendor and the model ID is the
+	// default value of ASIC.
+	OXFW_DEV_ENTRY(OUI_OXFORD, 0x00f970, NULL),
 	// Behringer,F-Control Audio 202. The value of SYT field is not reliable at all.
 	OXFW_DEV_ENTRY(VENDOR_BEHRINGER, 0x00fc22, NULL),
 	// Loud Technologies, Tapco Link.FireWire 4x6. The value of SYT field is always 0xffff.
@@ -337,7 +346,6 @@ static const struct ieee1394_device_id oxfw_id_table[] = {
 	// Loud Technologies, Mackie Onyx Satellite. Although revised version of firmware is
 	// installed to avoid the postpone, the value of SYT field is always 0xffff.
 	OXFW_DEV_ENTRY(VENDOR_LOUD, MODEL_SATELLITE, NULL),
-	// Miglia HarmonyAudio. Not yet identified.
 
 	//
 	// OXFW971 devices:
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index d728e451a2..39ea9a6dde 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -52,6 +52,11 @@ 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,
+	// Miglia Harmony Audio transmits CIP in which the value of dbc field expresses the number
+	// of accumulated payload quadlets including the packet.
+	SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS = 0x80,
 };
 
 /* This is an arbitrary number for convinience. */
@@ -136,7 +141,7 @@ struct snd_oxfw_stream_formation {
 	unsigned int pcm;
 	unsigned int midi;
 };
-int snd_oxfw_stream_parse_format(u8 *format,
+int snd_oxfw_stream_parse_format(const u8 *format,
 				 struct snd_oxfw_stream_formation *formation);
 int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
 				enum avc_general_plug_dir dir,
-- 
cgit v1.2.3