Linux 6.9-rc4
[sfrench/cifs-2.6.git] / sound / firewire / oxfw / oxfw-stream.c
index 80c9dc13f1b50b1bd3c75274ac45a6056fcf6d85..00f7feb91f929515254ddf80c918e2dd93db2884 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/delay.h>
 
 #define AVC_GENERIC_FRAME_MAXIMUM_BYTES        512
-#define CALLBACK_TIMEOUT       200
+#define READY_TIMEOUT_MS       600
 
 /*
  * According to datasheet of Oxford Semiconductor:
@@ -153,12 +153,32 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
        struct cmp_connection *conn;
        enum cmp_direction c_dir;
        enum amdtp_stream_direction s_dir;
+       unsigned int flags = 0;
        int err;
 
+       if (!(oxfw->quirks & SND_OXFW_QUIRK_BLOCKING_TRANSMISSION))
+               flags |= CIP_NONBLOCKING;
+       else
+               flags |= CIP_BLOCKING;
+
+       // OXFW 970/971 has no function to generate playback timing according to the sequence
+       // of value in syt field, thus the packet should include NO_INFO value in the field.
+       // However, some models just ignore data blocks in packet with NO_INFO for audio data
+       // processing.
+       if (!(oxfw->quirks & SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET))
+               flags |= CIP_UNAWARE_SYT;
+
        if (stream == &oxfw->tx_stream) {
                conn = &oxfw->out_conn;
                c_dir = CMP_OUTPUT;
                s_dir = AMDTP_IN_STREAM;
+
+               if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD)
+                       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;
@@ -169,24 +189,12 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
        if (err < 0)
                return err;
 
-       err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
+       err = amdtp_am824_init(stream, oxfw->unit, s_dir, flags);
        if (err < 0) {
                cmp_connection_destroy(conn);
                return err;
        }
 
-       /*
-        * OXFW starts to transmit packets with non-zero dbc.
-        * OXFW postpone transferring packets till handling any asynchronous
-        * packets. As a result, next isochronous packet includes more data
-        * blocks than IEC 61883-6 defines.
-        */
-       if (stream == &oxfw->tx_stream) {
-               oxfw->tx_stream.flags |= CIP_JUMBO_PAYLOAD;
-               if (oxfw->wrong_dbs)
-                       oxfw->tx_stream.flags |= CIP_WRONG_DBS;
-       }
-
        return 0;
 }
 
@@ -338,6 +346,9 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
        }
 
        if (!amdtp_stream_running(&oxfw->rx_stream)) {
+               unsigned int tx_init_skip_cycles = 0;
+               bool replay_seq = false;
+
                err = start_stream(oxfw, &oxfw->rx_stream);
                if (err < 0) {
                        dev_err(&oxfw->unit->device,
@@ -353,26 +364,32 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
                                        "fail to prepare tx stream: %d\n", err);
                                goto error;
                        }
+
+                       if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD) {
+                               // Just after changing sampling transfer frequency, many cycles are
+                               // skipped for packet transmission.
+                               tx_init_skip_cycles = 400;
+                       } else if (oxfw->quirks & SND_OXFW_QUIRK_VOLUNTARY_RECOVERY) {
+                               // It takes a bit time for target device to adjust event frequency
+                               // according to nominal event frequency in isochronous packets from
+                               // ALSA oxfw driver.
+                               tx_init_skip_cycles = 4000;
+                       } else {
+                               replay_seq = true;
+                       }
                }
 
-               err = amdtp_domain_start(&oxfw->domain, 0);
+               // NOTE: The device ignores presentation time expressed by the value of syt field
+               // of CIP header in received packets. The sequence of the number of data blocks per
+               // packet is important for media clock recovery.
+               err = amdtp_domain_start(&oxfw->domain, tx_init_skip_cycles, replay_seq, false);
                if (err < 0)
                        goto error;
 
-               // Wait first packet.
-               if (!amdtp_stream_wait_callback(&oxfw->rx_stream,
-                                               CALLBACK_TIMEOUT)) {
+               if (!amdtp_domain_wait_ready(&oxfw->domain, READY_TIMEOUT_MS)) {
                        err = -ETIMEDOUT;
                        goto error;
                }
-
-               if (oxfw->has_output) {
-                       if (!amdtp_stream_wait_callback(&oxfw->tx_stream,
-                                                       CALLBACK_TIMEOUT)) {
-                               err = -ETIMEDOUT;
-                               goto error;
-                       }
-               }
        }
 
        return 0;
@@ -471,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;
 }
 
@@ -500,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;
@@ -585,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 */