* [PATCH 0/2] firewire: core: add device quirk detection
@ 2025-10-13 14:03 Takashi Sakamoto
2025-10-13 14:03 ` [PATCH 1/2] firewire: core: detect device quirk when reading configuration ROM Takashi Sakamoto
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Takashi Sakamoto @ 2025-10-13 14:03 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel
Hi,
In the history of this subsystem, we have experienced some device-specific
quirks. For example:
* afa1282a35d3 ("firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder").
* a509e43ff338 ("firewire: core: fix unstable I/O with Canon camcorder").
* 3a93d082bacf ("ALSA: firewire-motu: add support for MOTU Audio Express")
However, there is no common mechanism to handle such quirks. This patchset
adds a consistent approach for detecting and managing device-specific
quirks within the subsystem.
Takashi Sakamoto (2):
firewire: core: detect device quirk when reading configuration ROM
firewire: core: handle device quirk of MOTu Audio Express
drivers/firewire/core-card.c | 21 +++------
drivers/firewire/core-device.c | 78 +++++++++++++++++++++++++++++++++-
drivers/firewire/ohci.c | 29 +++++++++++++
include/linux/firewire.h | 14 ++++++
4 files changed, 126 insertions(+), 16 deletions(-)
base-commit: 3a8660878839faadb4f1a6dd72c3179c1df56787
--
2.51.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/2] firewire: core: detect device quirk when reading configuration ROM
2025-10-13 14:03 [PATCH 0/2] firewire: core: add device quirk detection Takashi Sakamoto
@ 2025-10-13 14:03 ` Takashi Sakamoto
2025-10-13 14:03 ` [PATCH 2/2] firewire: core: handle device quirk of MOTU Audio Express Takashi Sakamoto
2025-10-16 0:06 ` [PATCH 0/2] firewire: core: add device quirk detection Takashi Sakamoto
2 siblings, 0 replies; 4+ messages in thread
From: Takashi Sakamoto @ 2025-10-13 14:03 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel
Every time the bus manager runs, the cached configuration ROM content of
the IRM device is investigated to detect device-specific quirks. This
detection can be performed in advance when reading the configuration ROM.
This commit adds device quirk flags to the fw_device structure, and
initializes them after reading the bus information block of the
configuration ROM. The quirk flags are immutable once the configuration
ROM has been read. Although they are likely accessed concurrently only by
the bus manager, this commit ensures safe access by preventing torn writes
and reads using the WRITE_ONCE()/READ_ONCE() macros.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-card.c | 21 +++++++--------------
drivers/firewire/core-device.c | 25 +++++++++++++++++++++++--
include/linux/firewire.h | 11 +++++++++++
3 files changed, 41 insertions(+), 16 deletions(-)
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index e5e0174a0335..6979d6a88ae2 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -86,8 +86,6 @@ static size_t config_rom_length = 1 + 4 + 1 + 1;
*/
#define DEFAULT_SPLIT_TIMEOUT (2 * 8000)
-#define CANON_OUI 0x000085
-
static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
{
struct fw_descriptor *desc;
@@ -308,11 +306,9 @@ __must_hold(&card->lock)
cpu_to_be32(local_id),
};
bool grace = time_is_before_jiffies64(card->reset_jiffies + msecs_to_jiffies(125));
- bool irm_is_1394_1995_only = false;
- bool keep_this_irm = false;
struct fw_node *irm_node;
struct fw_device *irm_device;
- int irm_node_id;
+ int irm_node_id, irm_device_quirks = 0;
int rcode;
lockdep_assert_held(&card->lock);
@@ -328,15 +324,12 @@ __must_hold(&card->lock)
return BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF;
}
+ // NOTE: It is likely that the quirk detection for IRM device has not done yet.
irm_device = fw_node_get_device(irm_node);
- if (irm_device && irm_device->config_rom) {
- irm_is_1394_1995_only = (irm_device->config_rom[2] & 0x000000f0) == 0;
-
- // Canon MV5i works unreliably if it is not root node.
- keep_this_irm = irm_device->config_rom[3] >> 8 == CANON_OUI;
- }
-
- if (irm_is_1394_1995_only && !keep_this_irm) {
+ if (irm_device)
+ irm_device_quirks = READ_ONCE(irm_device->quirks);
+ if ((irm_device_quirks & FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY) &&
+ !(irm_device_quirks & FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER)) {
fw_notice(card, "IRM is not 1394a compliant, making local node (%02x) root\n",
local_id);
return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY;
@@ -373,7 +366,7 @@ __must_hold(&card->lock)
return BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM;
}
default:
- if (!keep_this_irm) {
+ if (!(irm_device_quirks & FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER)) {
fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n",
fw_rcode_string(rcode), local_id);
return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY;
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 457a0da024a7..9bab2d594b89 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -542,6 +542,21 @@ static struct device_attribute fw_device_attributes[] = {
__ATTR_NULL,
};
+#define CANON_OUI 0x000085
+
+static int detect_quirks_by_bus_information_block(const u32 *bus_information_block)
+{
+ int quirks = 0;
+
+ if ((bus_information_block[2] & 0x000000f0) == 0)
+ quirks |= FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY;
+
+ if ((bus_information_block[3] >> 8) == CANON_OUI)
+ quirks |= FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER;
+
+ return quirks;
+}
+
static int read_rom(struct fw_device *device,
int generation, int index, u32 *data)
{
@@ -582,6 +597,7 @@ static int read_config_rom(struct fw_device *device, int generation)
u32 *rom, *stack;
u32 sp, key;
int i, end, length, ret;
+ int quirks;
rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE +
sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL);
@@ -612,6 +628,11 @@ static int read_config_rom(struct fw_device *device, int generation)
}
}
+ quirks = detect_quirks_by_bus_information_block(rom);
+
+ // Just prevent from torn writing/reading.
+ WRITE_ONCE(device->quirks, quirks);
+
device->max_speed = device->node->max_speed;
/*
@@ -1122,10 +1143,10 @@ static void fw_device_init(struct work_struct *work)
device->workfn = fw_device_shutdown;
fw_schedule_device_work(device, SHUTDOWN_DELAY);
} else {
- fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n",
+ fw_notice(card, "created device %s: GUID %08x%08x, S%d00, quirks %08x\n",
dev_name(&device->device),
device->config_rom[3], device->config_rom[4],
- 1 << device->max_speed);
+ 1 << device->max_speed, device->quirks);
device->config_rom_retries = 0;
set_broadcast_channel(device, device->generation);
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 6d208769d456..161829cfcc00 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -170,6 +170,14 @@ struct fw_attribute_group {
struct attribute *attrs[13];
};
+enum fw_device_quirk {
+ // See afa1282a35d3 ("firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder").
+ FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY = BIT(0),
+
+ // See a509e43ff338 ("firewire: core: fix unstable I/O with Canon camcorder").
+ FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER = BIT(1),
+};
+
enum fw_device_state {
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING,
@@ -203,6 +211,9 @@ struct fw_device {
struct fw_card *card;
struct device device;
+ // A set of enum fw_device_quirk.
+ int quirks;
+
struct mutex client_list_mutex;
struct list_head client_list;
--
2.51.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 2/2] firewire: core: handle device quirk of MOTU Audio Express
2025-10-13 14:03 [PATCH 0/2] firewire: core: add device quirk detection Takashi Sakamoto
2025-10-13 14:03 ` [PATCH 1/2] firewire: core: detect device quirk when reading configuration ROM Takashi Sakamoto
@ 2025-10-13 14:03 ` Takashi Sakamoto
2025-10-16 0:06 ` [PATCH 0/2] firewire: core: add device quirk detection Takashi Sakamoto
2 siblings, 0 replies; 4+ messages in thread
From: Takashi Sakamoto @ 2025-10-13 14:03 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel
A commit 3a93d082bacf ("ALSA: firewire-motu: add support for MOTU Audio
Express") describes a quirk of MOTU Audio Express. The device returns
acknowledge packet with 0x10 as the pending state of any types of
asynchronous request transaction. It is completely out of specification.
This commit implements handling for that device-specific quirk. The quirk
is detected after reading the root directory of configuration ROM. When
processing the acknowledge code in 1394 OHCI AT context event handler,
firewire-ohci module seeks the device instance of destination node by
traversing device hierarchy. If the device has the quirk, the acknowledge
code is replaced with the standard code.
The 1394 OHCI AT context events occur for outgoing asynchronous request
packets. The device traversal is safe since no new request initiators
exist after the fw_card_instance has been invalidated.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-device.c | 53 ++++++++++++++++++++++++++++++++++
drivers/firewire/ohci.c | 29 +++++++++++++++++++
include/linux/firewire.h | 3 ++
3 files changed, 85 insertions(+)
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 9bab2d594b89..33ce4cd357ed 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -557,6 +557,54 @@ static int detect_quirks_by_bus_information_block(const u32 *bus_information_blo
return quirks;
}
+struct entry_match {
+ unsigned int index;
+ u32 value;
+};
+
+static const struct entry_match motu_audio_express_matches[] = {
+ { 1, 0x030001f2 },
+ { 3, 0xd1000002 },
+ { 4, 0x8d000005 },
+ { 6, 0x120001f2 },
+ { 7, 0x13000033 },
+ { 8, 0x17104800 },
+};
+
+static int detect_quirks_by_root_directory(const u32 *root_directory, unsigned int length)
+{
+ static const struct {
+ enum fw_device_quirk quirk;
+ const struct entry_match *matches;
+ unsigned int match_count;
+ } *entry, entries[] = {
+ {
+ .quirk = FW_DEVICE_QUIRK_ACK_PACKET_WITH_INVALID_PENDING_CODE,
+ .matches = motu_audio_express_matches,
+ .match_count = ARRAY_SIZE(motu_audio_express_matches),
+ },
+ };
+ int quirks = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(entries); ++i) {
+ int j;
+
+ entry = entries + i;
+ for (j = 0; j < entry->match_count; ++j) {
+ unsigned int index = entry->matches[j].index;
+ unsigned int value = entry->matches[j].value;
+
+ if ((length < index) || (root_directory[index] != value))
+ break;
+ }
+ if (j == entry->match_count)
+ quirks |= entry->quirk;
+ }
+
+ return quirks;
+}
+
static int read_rom(struct fw_device *device,
int generation, int index, u32 *data)
{
@@ -737,6 +785,11 @@ static int read_config_rom(struct fw_device *device, int generation)
length = i;
}
+ 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);
+
old_rom = device->config_rom;
new_rom = kmemdup(rom, length * 4, GFP_KERNEL);
if (new_rom == NULL) {
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 030aed5453a1..757dd9c64b1c 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -1319,6 +1319,14 @@ static void at_context_flush(struct at_context *ctx)
enable_work(&ctx->work);
}
+static int find_fw_device(struct device *dev, const void *data)
+{
+ struct fw_device *device = fw_device(dev);
+ const u32 *params = data;
+
+ return (device->generation == params[0]) && (device->node_id == params[1]);
+}
+
static int handle_at_packet(struct context *context,
struct descriptor *d,
struct descriptor *last)
@@ -1390,6 +1398,27 @@ static int handle_at_packet(struct context *context,
fallthrough;
default:
+ if (unlikely(evt == 0x10)) {
+ u32 params[2] = {
+ packet->generation,
+ async_header_get_destination(packet->header),
+ };
+ struct device *dev;
+
+ fw_card_get(&ohci->card);
+ dev = device_find_child(ohci->card.device, (const void *)params, find_fw_device);
+ fw_card_put(&ohci->card);
+ if (dev) {
+ struct fw_device *device = fw_device(dev);
+ int quirks = READ_ONCE(device->quirks);
+
+ put_device(dev);
+ if (quirks & FW_DEVICE_QUIRK_ACK_PACKET_WITH_INVALID_PENDING_CODE) {
+ packet->ack = ACK_PENDING;
+ break;
+ }
+ }
+ }
packet->ack = RCODE_SEND_ERROR;
break;
}
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 161829cfcc00..f1d8734c0ec6 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -176,6 +176,9 @@ enum fw_device_quirk {
// See a509e43ff338 ("firewire: core: fix unstable I/O with Canon camcorder").
FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER = BIT(1),
+
+ // MOTU Audio Express transfers acknowledge packet with 0x10 for pending state.
+ FW_DEVICE_QUIRK_ACK_PACKET_WITH_INVALID_PENDING_CODE = BIT(2),
};
enum fw_device_state {
--
2.51.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 0/2] firewire: core: add device quirk detection
2025-10-13 14:03 [PATCH 0/2] firewire: core: add device quirk detection Takashi Sakamoto
2025-10-13 14:03 ` [PATCH 1/2] firewire: core: detect device quirk when reading configuration ROM Takashi Sakamoto
2025-10-13 14:03 ` [PATCH 2/2] firewire: core: handle device quirk of MOTU Audio Express Takashi Sakamoto
@ 2025-10-16 0:06 ` Takashi Sakamoto
2 siblings, 0 replies; 4+ messages in thread
From: Takashi Sakamoto @ 2025-10-16 0:06 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel
On Mon, Oct 13, 2025 at 11:03:09PM +0900, Takashi Sakamoto wrote:
> Hi,
>
> In the history of this subsystem, we have experienced some device-specific
> quirks. For example:
>
> * afa1282a35d3 ("firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder").
> * a509e43ff338 ("firewire: core: fix unstable I/O with Canon camcorder").
> * 3a93d082bacf ("ALSA: firewire-motu: add support for MOTU Audio Express")
>
> However, there is no common mechanism to handle such quirks. This patchset
> adds a consistent approach for detecting and managing device-specific
> quirks within the subsystem.
>
> Takashi Sakamoto (2):
> firewire: core: detect device quirk when reading configuration ROM
> firewire: core: handle device quirk of MOTu Audio Express
>
> drivers/firewire/core-card.c | 21 +++------
> drivers/firewire/core-device.c | 78 +++++++++++++++++++++++++++++++++-
> drivers/firewire/ohci.c | 29 +++++++++++++
> include/linux/firewire.h | 14 ++++++
> 4 files changed, 126 insertions(+), 16 deletions(-)
Applied to for-next branch.
Regards
Takashi Sakamoto
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-10-16 0:06 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-13 14:03 [PATCH 0/2] firewire: core: add device quirk detection Takashi Sakamoto
2025-10-13 14:03 ` [PATCH 1/2] firewire: core: detect device quirk when reading configuration ROM Takashi Sakamoto
2025-10-13 14:03 ` [PATCH 2/2] firewire: core: handle device quirk of MOTU Audio Express Takashi Sakamoto
2025-10-16 0:06 ` [PATCH 0/2] firewire: core: add device quirk detection Takashi Sakamoto
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®