* [PATCH 1/4] firewire: core: code refactoring to compute transaction speed
2025-10-18 3:55 [PATCH 0/4] firewire: core: handle TASCAM FW-1884/FW-1804/FW-1082 quirk Takashi Sakamoto
@ 2025-10-18 3:55 ` Takashi Sakamoto
2025-10-18 3:55 ` [PATCH 2/4] firewire: core: determine transaction speed after detecting quirks Takashi Sakamoto
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Takashi Sakamoto @ 2025-10-18 3:55 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel, linux-sound
This commit refactors the helper function to read the content of
configuration ROM with the passed speed.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-device.c | 35 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 18 deletions(-)
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 33ce4cd357ed..c698d4ced7d7 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -605,8 +605,7 @@ static int detect_quirks_by_root_directory(const u32 *root_directory, unsigned i
return quirks;
}
-static int read_rom(struct fw_device *device,
- int generation, int index, u32 *data)
+static int read_rom(struct fw_device *device, int generation, int speed, int index, u32 *data)
{
u64 offset = (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4;
int i, rcode;
@@ -617,7 +616,7 @@ static int read_rom(struct fw_device *device,
for (i = 10; i < 100; i += 10) {
rcode = fw_run_transaction(device->card,
TCODE_READ_QUADLET_REQUEST, device->node_id,
- generation, device->max_speed, offset, data, 4);
+ generation, speed, offset, data, 4);
if (rcode != RCODE_BUSY)
break;
msleep(i);
@@ -644,7 +643,7 @@ static int read_config_rom(struct fw_device *device, int generation)
const u32 *old_rom, *new_rom;
u32 *rom, *stack;
u32 sp, key;
- int i, end, length, ret;
+ int i, end, length, ret, speed;
int quirks;
rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE +
@@ -655,11 +654,11 @@ static int read_config_rom(struct fw_device *device, int generation)
stack = &rom[MAX_CONFIG_ROM_SIZE];
memset(rom, 0, sizeof(*rom) * MAX_CONFIG_ROM_SIZE);
- device->max_speed = SCODE_100;
+ speed = SCODE_100;
/* First read the bus info block. */
for (i = 0; i < 5; i++) {
- ret = read_rom(device, generation, i, &rom[i]);
+ ret = read_rom(device, generation, speed, i, &rom[i]);
if (ret != RCODE_COMPLETE)
goto out;
/*
@@ -681,7 +680,7 @@ static int read_config_rom(struct fw_device *device, int generation)
// Just prevent from torn writing/reading.
WRITE_ONCE(device->quirks, quirks);
- device->max_speed = device->node->max_speed;
+ speed = device->node->max_speed;
/*
* Determine the speed of
@@ -692,20 +691,18 @@ static int read_config_rom(struct fw_device *device, int generation)
* because some buggy firmwares set it lower than necessary and because
* 1394-1995 nodes do not have the field.
*/
- if ((rom[2] & 0x7) < device->max_speed ||
- device->max_speed == SCODE_BETA ||
- card->beta_repeaters_present) {
+ if ((rom[2] & 0x7) < speed || speed == SCODE_BETA || card->beta_repeaters_present) {
u32 dummy;
/* for S1600 and S3200 */
- if (device->max_speed == SCODE_BETA)
- device->max_speed = card->link_speed;
+ if (speed == SCODE_BETA)
+ speed = card->link_speed;
- while (device->max_speed > SCODE_100) {
- if (read_rom(device, generation, 0, &dummy) ==
+ while (speed > SCODE_100) {
+ if (read_rom(device, generation, speed, 0, &dummy) ==
RCODE_COMPLETE)
break;
- device->max_speed--;
+ --speed;
}
}
@@ -734,7 +731,7 @@ static int read_config_rom(struct fw_device *device, int generation)
}
/* Read header quadlet for the block to get the length. */
- ret = read_rom(device, generation, i, &rom[i]);
+ ret = read_rom(device, generation, speed, i, &rom[i]);
if (ret != RCODE_COMPLETE)
goto out;
end = i + (rom[i] >> 16) + 1;
@@ -758,7 +755,7 @@ static int read_config_rom(struct fw_device *device, int generation)
* it references another block, and push it in that case.
*/
for (; i < end; i++) {
- ret = read_rom(device, generation, i, &rom[i]);
+ ret = read_rom(device, generation, speed, i, &rom[i]);
if (ret != RCODE_COMPLETE)
goto out;
@@ -785,6 +782,8 @@ static int read_config_rom(struct fw_device *device, int generation)
length = i;
}
+ device->max_speed = speed;
+
quirks |= detect_quirks_by_root_directory(rom + ROOT_DIR_OFFSET, length - ROOT_DIR_OFFSET);
// Just prevent from torn writing/reading.
@@ -1234,7 +1233,7 @@ static int reread_config_rom(struct fw_device *device, int generation,
int i, rcode;
for (i = 0; i < 6; i++) {
- rcode = read_rom(device, generation, i, &q);
+ rcode = read_rom(device, generation, device->max_speed, i, &q);
if (rcode != RCODE_COMPLETE)
return rcode;
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/4] firewire: core: determine transaction speed after detecting quirks
2025-10-18 3:55 [PATCH 0/4] firewire: core: handle TASCAM FW-1884/FW-1804/FW-1082 quirk Takashi Sakamoto
2025-10-18 3:55 ` [PATCH 1/4] firewire: core: code refactoring to compute transaction speed Takashi Sakamoto
@ 2025-10-18 3:55 ` Takashi Sakamoto
2025-10-18 3:55 ` [PATCH 3/4] firewire: core: handle device quirk of TASCAM FW-1884/FW-1804/FW-1082 Takashi Sakamoto
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Takashi Sakamoto @ 2025-10-18 3:55 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel, linux-sound
Current implementation determines the maximum transaction speed supported
by the target device after reading bus information block of configuration
ROM. The read operations for root directory block are then performed at
the determined speed. However, some devices have quirks that cause issues
when transactions are performed at the determined speed.
In the first place, all devices are required to support the lowest speed
(S100) and must respond successfully to any read request within the
configuration ROM space. Therefore it is safe to postpone speed
determination until the entire configuration ROM has been read.
This commit moves the speed determination after reading root directory.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-device.c | 53 ++++++++++++++++------------------
1 file changed, 25 insertions(+), 28 deletions(-)
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index c698d4ced7d7..6a5740ed4934 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -680,32 +680,6 @@ static int read_config_rom(struct fw_device *device, int generation)
// Just prevent from torn writing/reading.
WRITE_ONCE(device->quirks, quirks);
- speed = device->node->max_speed;
-
- /*
- * Determine the speed of
- * - devices with link speed less than PHY speed,
- * - devices with 1394b PHY (unless only connected to 1394a PHYs),
- * - all devices if there are 1394b repeaters.
- * Note, we cannot use the bus info block's link_spd as starting point
- * because some buggy firmwares set it lower than necessary and because
- * 1394-1995 nodes do not have the field.
- */
- if ((rom[2] & 0x7) < speed || speed == SCODE_BETA || card->beta_repeaters_present) {
- u32 dummy;
-
- /* for S1600 and S3200 */
- if (speed == SCODE_BETA)
- speed = card->link_speed;
-
- while (speed > SCODE_100) {
- if (read_rom(device, generation, speed, 0, &dummy) ==
- RCODE_COMPLETE)
- break;
- --speed;
- }
- }
-
/*
* Now parse the config rom. The config rom is a recursive
* directory structure so we parse it using a stack of
@@ -782,13 +756,36 @@ static int read_config_rom(struct fw_device *device, int generation)
length = i;
}
- device->max_speed = speed;
-
quirks |= detect_quirks_by_root_directory(rom + ROOT_DIR_OFFSET, length - ROOT_DIR_OFFSET);
// Just prevent from torn writing/reading.
WRITE_ONCE(device->quirks, quirks);
+ speed = device->node->max_speed;
+
+ // Determine the speed of
+ // - devices with link speed less than PHY speed,
+ // - devices with 1394b PHY (unless only connected to 1394a PHYs),
+ // - all devices if there are 1394b repeaters.
+ // Note, we cannot use the bus info block's link_spd as starting point because some buggy
+ // firmwares set it lower than necessary and because 1394-1995 nodes do not have the field.
+ if ((rom[2] & 0x7) < speed || speed == SCODE_BETA || card->beta_repeaters_present) {
+ u32 dummy;
+
+ // for S1600 and S3200.
+ if (speed == SCODE_BETA)
+ speed = card->link_speed;
+
+ while (speed > SCODE_100) {
+ if (read_rom(device, generation, speed, 0, &dummy) ==
+ RCODE_COMPLETE)
+ break;
+ --speed;
+ }
+ }
+
+ device->max_speed = speed;
+
old_rom = device->config_rom;
new_rom = kmemdup(rom, length * 4, GFP_KERNEL);
if (new_rom == NULL) {
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/4] firewire: core: handle device quirk of TASCAM FW-1884/FW-1804/FW-1082
2025-10-18 3:55 [PATCH 0/4] firewire: core: handle TASCAM FW-1884/FW-1804/FW-1082 quirk Takashi Sakamoto
2025-10-18 3:55 ` [PATCH 1/4] firewire: core: code refactoring to compute transaction speed Takashi Sakamoto
2025-10-18 3:55 ` [PATCH 2/4] firewire: core: determine transaction speed after detecting quirks Takashi Sakamoto
@ 2025-10-18 3:55 ` Takashi Sakamoto
2025-10-18 3:55 ` [PATCH 4/4] ALSA: firewire-tascam: reserve resources for transferred isochronous packets at S400 Takashi Sakamoto
2025-10-20 0:19 ` [PATCH 0/4] firewire: core: handle TASCAM FW-1884/FW-1804/FW-1082 quirk Takashi Sakamoto
4 siblings, 0 replies; 6+ messages in thread
From: Takashi Sakamoto @ 2025-10-18 3:55 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel, linux-sound
TASCAM FW-1884/FW-1804/FW-1082 is too lazy to repspond to asynchronous
request at S400. The asynchronous transaction often results in timeout.
This is a problematic quirk.
This commit adds support for the quirk. When identifying the new quirk
flag, then the transaction speed is configured at S200.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-device.c | 18 +++++++++++++++++-
include/linux/firewire.h | 3 +++
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 6a5740ed4934..1674de477852 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -571,6 +571,14 @@ static const struct entry_match motu_audio_express_matches[] = {
{ 8, 0x17104800 },
};
+static const struct entry_match tascam_fw_series_matches[] = {
+ { 1, 0x0300022e },
+ { 3, 0x8d000006 },
+ { 4, 0xd1000001 },
+ { 6, 0x1200022e },
+ { 8, 0xd4000004 },
+};
+
static int detect_quirks_by_root_directory(const u32 *root_directory, unsigned int length)
{
static const struct {
@@ -583,6 +591,11 @@ static int detect_quirks_by_root_directory(const u32 *root_directory, unsigned i
.matches = motu_audio_express_matches,
.match_count = ARRAY_SIZE(motu_audio_express_matches),
},
+ {
+ .quirk = FW_DEVICE_QUIRK_UNSTABLE_AT_S400,
+ .matches = tascam_fw_series_matches,
+ .match_count = ARRAY_SIZE(tascam_fw_series_matches),
+ },
};
int quirks = 0;
int i;
@@ -761,7 +774,10 @@ static int read_config_rom(struct fw_device *device, int generation)
// Just prevent from torn writing/reading.
WRITE_ONCE(device->quirks, quirks);
- speed = device->node->max_speed;
+ if (unlikely(quirks & FW_DEVICE_QUIRK_UNSTABLE_AT_S400))
+ speed = SCODE_200;
+ else
+ speed = device->node->max_speed;
// Determine the speed of
// - devices with link speed less than PHY speed,
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index f1d8734c0ec6..6143b7d28eac 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -179,6 +179,9 @@ enum fw_device_quirk {
// MOTU Audio Express transfers acknowledge packet with 0x10 for pending state.
FW_DEVICE_QUIRK_ACK_PACKET_WITH_INVALID_PENDING_CODE = BIT(2),
+
+ // TASCAM FW-1082/FW-1804/FW-1884 often freezes when receiving S400 packets.
+ FW_DEVICE_QUIRK_UNSTABLE_AT_S400 = BIT(3),
};
enum fw_device_state {
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 4/4] ALSA: firewire-tascam: reserve resources for transferred isochronous packets at S400
2025-10-18 3:55 [PATCH 0/4] firewire: core: handle TASCAM FW-1884/FW-1804/FW-1082 quirk Takashi Sakamoto
` (2 preceding siblings ...)
2025-10-18 3:55 ` [PATCH 3/4] firewire: core: handle device quirk of TASCAM FW-1884/FW-1804/FW-1082 Takashi Sakamoto
@ 2025-10-18 3:55 ` Takashi Sakamoto
2025-10-20 0:19 ` [PATCH 0/4] firewire: core: handle TASCAM FW-1884/FW-1804/FW-1082 quirk Takashi Sakamoto
4 siblings, 0 replies; 6+ messages in thread
From: Takashi Sakamoto @ 2025-10-18 3:55 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel, linux-sound
TASCAM FW-1884/FW-1804/FW-1082 have a quirk that they often freeze when
receiving isochronous packets at S400. This behaviour is suppressed by a
new quirk flag added in Linux FireWire core to restrict maximum speed.
Consequently both of the asynchronous transactions and isochronous
transmissions are done at S200. However, the device still transfers
isochronous packet at S400, and the way to indicate the transmission
speed is not cleared yet.
This commit correctly reserves isochronous resources for the transferred
packet stream at S400. As a beneficial side effect, the pair of
isochronous transmissions for FW-1884 fits within the bandwidth capacity
of the bus.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
sound/firewire/tascam/tascam-stream.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c
index 9c8fddd7dee1..4ecd151a46c1 100644
--- a/sound/firewire/tascam/tascam-stream.c
+++ b/sound/firewire/tascam/tascam-stream.c
@@ -282,20 +282,22 @@ static int keep_resources(struct snd_tscm *tscm, unsigned int rate,
struct amdtp_stream *stream)
{
struct fw_iso_resources *resources;
+ int speed;
int err;
- if (stream == &tscm->tx_stream)
+ if (stream == &tscm->tx_stream) {
resources = &tscm->tx_resources;
- else
+ speed = fw_parent_device(tscm->unit)->max_speed;
+ } else {
resources = &tscm->rx_resources;
+ speed = SCODE_400;
+ }
err = amdtp_tscm_set_parameters(stream, rate);
if (err < 0)
return err;
- return fw_iso_resources_allocate(resources,
- amdtp_stream_get_max_payload(stream),
- fw_parent_device(tscm->unit)->max_speed);
+ return fw_iso_resources_allocate(resources, amdtp_stream_get_max_payload(stream), speed);
}
static int init_stream(struct snd_tscm *tscm, struct amdtp_stream *s)
@@ -455,7 +457,6 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
}
if (!amdtp_stream_running(&tscm->rx_stream)) {
- int spd = fw_parent_device(tscm->unit)->max_speed;
unsigned int tx_init_skip_cycles;
err = set_stream_formats(tscm, rate);
@@ -466,13 +467,13 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
if (err < 0)
goto error;
- err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream,
- tscm->rx_resources.channel, spd);
+ err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream, tscm->rx_resources.channel,
+ fw_parent_device(tscm->unit)->max_speed);
if (err < 0)
goto error;
- err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream,
- tscm->tx_resources.channel, spd);
+ err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream, tscm->tx_resources.channel,
+ SCODE_400);
if (err < 0)
goto error;
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 0/4] firewire: core: handle TASCAM FW-1884/FW-1804/FW-1082 quirk
2025-10-18 3:55 [PATCH 0/4] firewire: core: handle TASCAM FW-1884/FW-1804/FW-1082 quirk Takashi Sakamoto
` (3 preceding siblings ...)
2025-10-18 3:55 ` [PATCH 4/4] ALSA: firewire-tascam: reserve resources for transferred isochronous packets at S400 Takashi Sakamoto
@ 2025-10-20 0:19 ` Takashi Sakamoto
4 siblings, 0 replies; 6+ messages in thread
From: Takashi Sakamoto @ 2025-10-20 0:19 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel, linux-sound
On Sat, Oct 18, 2025 at 12:55:28PM +0900, Takashi Sakamoto wrote:
> Hi,
>
> In 2003, TEAC Corporation had released FW-1884/FW-1804/FW-1082 in its
> TASCAM brand. These devices are already supported by a driver in ALSA
> firewire stack, but they have an interoperability issue related to
> the speed of asynchronous transactions and isochronous transmissions.
> When operating at the speed described in configuration ROM, they are
> too lazy to respond, and eventually frozen.
>
> The most likely cause of this issue is a mismatch in the gap count
> between the initiators and receivers. Theoretically, this can be
> resolved by transmitting phy configuration packets to optimize gap count.
> Nevertheless, this approach has proven ineffective, suggesting that the
> device firmware may contain a bug causing the issue.
>
> From my experience, these devices operate more reliably at lower
> transaction and transmission speeds, which provides a practical
> mitigation.
>
> This patch series addresses the interoperability issue. The core function
> of Linux FireWire subsystem is changed to read the entire configuration
> ROM at the lowest speed (S100), and to identify these devices based on its
> contents. Once identified, their maximum speed is limited to S200. The
> ALSA driver then performs asynchronous requests and isochronous
> transmission at that speed to prevent device freezes.
>
> Takashi Sakamoto (4):
> firewire: core: code refactoring to compute transaction speed
> firewire: core: determine transaction speed after detecting quirks
> firewire: core: handle device quirk of TASCAM FW-1884/FW-1804/FW-1082
> ALSA: firewire-tascam: reserve resources for transferred isochronous
> packets at S400
>
> drivers/firewire/core-device.c | 86 +++++++++++++++------------
> include/linux/firewire.h | 3 +
> sound/firewire/tascam/tascam-stream.c | 21 +++----
> 3 files changed, 63 insertions(+), 47 deletions(-)
>
>
> base-commit: 15f9610fc96ac6fd2844e63f7bf5a0b08e1c31c8
Applied to for-next branch.
To sound subsystem maintainer, I'll send the 4th patch to mainline as a
part of firewire subsystem updates in next merge window.
Regards
Takashi Sakamoto
`
^ permalink raw reply [flat|nested] 6+ messages in thread