Posts
127
Following
28
Followers
27
A maintainer of Linux FireWire subsystem and ALSA firewire stack.
http://ieee1394.docs.kernel.org/
https://github.com/takaswie/linux-firewire-dkms/
@wagi Actually I can see that some USB/FireWire hybrid products use ArchWave DM1500 (e.g. Behringer FCA610). I wish I would find such a product with DM1200 someday, but it already takes two decades since the ASIC was shipped. It seems to be hard, sigh...

By the way, I have a question about DM1000 configuration ROM. I can see some products have dependent info directory, containing two offsets. For example, this is an example of M-Audio FireWire Solo:

dependent info directory at 1104
-----------------------------------------------------------------
1104 000637c7 directory_length 6, crc 14279
1108 120007f5 specifier id
1112 13000001 version
1116 3affffc7 (immediate value)
1120 3b100000 (immediate value)
1124 3cffffc7 (immediate value)
1128 3d600000 (immediate value)

If you have any idea about what were 0xffffc73b100000 and 0xffffc73d600000, it really helps my interests.
0
0
0

Takashi Sakamoto (坂本 貴史)

Or retrieve buffer from descriptor list?
0
0
0

Takashi Sakamoto (坂本 貴史)

Hm.

$ git show
commit ba003f0c08ead39934425cb3a70e0e8f83ed7a5b (HEAD -> topic/cdev/iso-resource-once-rework)
Author: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Date:   Mon Aug 24 23:12:18 2026 +0900

    firewire: ohci: don't handle AT request/response packets in caller's context
    
    It is inconvenient to handle AT request/response packets in the context of
    __fw_send_request() call, since it could be any type of IRQ contexts. In
    the case, the address handler implementation should take care of the lock
    type.

diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index e947227e..1195eab1 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -1535,11 +1535,23 @@ static void handle_local_lock(struct fw_ohci *ohci,
        fw_core_handle_response(&ohci->card, &response);
 }
 
-static void handle_local_request(struct at_context *ctx, struct fw_packet *packet)
+struct local_at_packet {
+       struct work_struct work;
+       struct at_context *ctx;
+       struct fw_packet *p;
+};
+
+static void local_at_run(struct work_struct *work)
 {
+       struct local_at_packet *local_packet = from_work(local_packet, work, work);
+       struct fw_packet *packet = local_packet->p;
+       struct at_context *ctx = local_packet->ctx;
        struct fw_ohci *ohci = ctx->context.ohci;
        u64 offset, csr;
 
+       // Timestamping on behalf of the hardware.
+       packet->timestamp = cycle_time_to_ohci_tstamp(get_cycle_time(ohci));
+
        if (ctx == &ohci->at_request_ctx) {
                packet->ack = ACK_PENDING;
                packet->callback(packet, &ohci->card, packet->ack);
@@ -1570,6 +1582,8 @@ static void handle_local_request(struct at_context *ctx, struct fw_packet *packe
                packet->ack = ACK_COMPLETE;
                packet->callback(packet, &ohci->card, packet->ack);
        }
+
+       kfree(local_packet);
 }
 
 static void at_context_transmit(struct at_context *ctx, struct fw_packet *packet)
@@ -1584,10 +1598,18 @@ static void at_context_transmit(struct at_context *ctx, struct fw_packet *packet
            ohci->generation == packet->generation) {
                spin_unlock_irqrestore(&ohci->lock, flags);
 
-               // Timestamping on behalf of the hardware.
-               packet->timestamp = cycle_time_to_ohci_tstamp(get_cycle_time(ohci));
+               struct local_at_packet *local_packet = kmalloc_obj(*local_packet);
+
+               // TODO:
+               if (!local_packet)
+                       return;
+
+               INIT_WORK(&local_packet->work, local_at_run);
+               local_packet->ctx = ctx;
+               local_packet->p = packet;
+
+               queue_work(ohci->card.async_wq, &local_packet->work);
 
-               handle_local_request(ctx, packet);
                return;
        }
 
0
0
0

Takashi Sakamoto (坂本 貴史)

I sent:

[GIT PULL] firewire updates for v7.3
https://lore.kernel.org/lkml/20260822051606.GA299935@sakamocchi.jp
0
0
0
@wagi Oh, gone, additionally forever... That's a sort of bad dream for embedded engineers. I've opened so many boxes, but never seen DM1200, in my memory, as you said.

I can agree that the cost of software engineering is often underscoped... But the console via async transaction is enough interesting to me. I attempt to make my implementation, but in my opinion it looks one of bootloader functions. But is it available after the device starts running with its main firmware loaded by the bootloader?
1
0
0

Takashi Sakamoto (坂本 貴史)

I realized to write stub functions for KUnit tests. Great!

diff --git a/drivers/firewire/.kunitconfig b/drivers/firewire/.kunitconfig
index 7406acb00478..4f58bbb2ac5a 100644
--- a/drivers/firewire/.kunitconfig
+++ b/drivers/firewire/.kunitconfig
@@ -7,3 +7,4 @@ CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST=y
 CONFIG_FIREWIRE_KUNIT_SELF_ID_SEQUENCE_HELPER_TEST=y
 CONFIG_FIREWIRE_KUNIT_OHCI_SERDES_TEST=y
 CONFIG_FIREWIRE_KUNIT_NODE_TREE_TEST=y
+CONFIG_FIREWIRE_KUNIT_CONFIG_ROM_READER_TEST=y
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index b5abe00accc9..ccdaa0920bf6 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -96,6 +96,21 @@ config FIREWIRE_KUNIT_NODE_TREE_TEST
 	  For more information on KUnit and unit tests in general, refer
 	  to the KUnit documentation in Documentation/dev-tools/kunit/.
 
+config FIREWIRE_KUNIT_CONFIG_ROM_READER_TEST
+	tristate "KUnit tests for node tree" if !KUNIT_ALL_TESTS
+	depends on FIREWIRE && KUNIT
+	default KUNIT_ALL_TESTS
+	help
+	  This builds the KUnit tests for configuration ROM reader.
+
+	  KUnit tests run during boot and output the results to the debug
+	  log in TAP format (https://testanything.org/). Only useful for
+	  kernel devs running KUnit test harness and are not for inclusion
+	  into a production build.
+
+	  For more information on KUnit and unit tests in general, refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
 config FIREWIRE_OHCI
 	tristate "OHCI-1394 controllers"
 	depends on PCI && FIREWIRE
diff --git a/drivers/firewire/configuration-rom-reader-test.c b/drivers/firewire/configuration-rom-reader-test.c
new file mode 100644
index 000000000000..953d65edd717
--- /dev/null
+++ b/drivers/firewire/configuration-rom-reader-test.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// configuration-rom-reader-test.c - An application of Kunit to test configuration ROM reader.
+//
+// Copyright (c) 2026 Takashi Sakamoto
+//
+// This file can not be built independently since it is intentionally included in core-device.c.
+
+#include <kunit/test.h>
+#include <kunit/static_stub.h>
+
+static int stub_fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
+				   int generation, int speed, unsigned long long offset,
+				   void *payload, size_t length)
+{
+	return RCODE_CONFLICT_ERROR;
+}
+
+static void config_rom_reader_test(struct kunit *test)
+{
+	kunit_activate_static_stub(test, fw_run_transaction, stub_fw_run_transaction);
+
+	struct fw_device device;
+	int generation = 0;
+	int speed = SCODE_100;
+	int index = 0;
+	u32 data;
+	int err;
+
+	err = read_rom(&device, generation, speed, index, &data);
+	KUNIT_EXPECT_EQ(test, err, RCODE_CONFLICT_ERROR);
+
+	kunit_deactivate_static_stub(test, fw_run_transaction);
+}
+
+static struct kunit_case config_rom_reader_test_cases[] = {
+	{}
+};
+
+static struct kunit_suite config_rom_reader_test_suite = {
+	.name = "firewire-configuration-rom-reader",
+	.test_cases = config_rom_reader_test_cases,
+};
+kunit_test_suite(config_rom_reader_test_suite);
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index cbac66916240..3472b44a8501 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -1442,3 +1442,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
 #ifdef CONFIG_FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST
 #include "device-attribute-test.c"
 #endif
+
+#ifdef CONFIG_FIREWIRE_KUNIT_CONFIG_ROM_READER_TEST
+#include "configuration-rom-reader-test.c"
+#endif
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 22ae387ae03c..2162e1daa447 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -24,6 +24,7 @@
 #include <linux/timer.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
+#include <kunit/static_stub.h>
 
 #include <asm/byteorder.h>
 
@@ -481,6 +482,9 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
 		       int generation, int speed, unsigned long long offset,
 		       void *payload, size_t length)
 {
+        KUNIT_STATIC_STUB_REDIRECT(fw_run_transaction, card, tcode, destination_id, generation,
+				   speed, offset, payload, length);
+
 	struct transaction_callback_data d;
 	struct fw_transaction t;
 
0
0
1
@wagi Ah, a workaround. Does the switch matrix problem seem to be circuit level? If so, it is surprising that any change of clock for audio signal processing (or packet processing) affects the baud rate in UART...
1
0
0

Takashi Sakamoto (坂本 貴史)

I think @wagi can provide helpful information about it, don't you?
1
0
0

Takashi Sakamoto (坂本 貴史)

Edited 11 days ago
He found the way to operate with BeBoB console for M-Audio FW 1814, surprising!

https://bsky.app/profile/mrmidi.bsky.social/post/3mtc23zcaj222
1
0
0

Takashi Sakamoto (坂本 貴史)

Replied:

Re: [PATCH v3 00/16] mod_devicetable.h: Split into per subsystem headers
https://lore.kernel.org/lkml/20260629235804.GA414914@sakamocchi.jp/
0
0
0

Takashi Sakamoto (坂本 貴史)

I'm waiting for v3 patchset. It would be posted after -rc1 release:

[PATCH v2 00/17] mod_devicetable.h: Split into per subsystem headers
https://lore.kernel.org/lkml/cover.1782490566.git.u.kleine-koenig@baylibre.com/
1
0
1

Takashi Sakamoto (坂本 貴史)

Edited 3 months ago
Re: [PATCH] list: Add safe entry iterators without an explicit n cursor
https://lore.kernel.org/lkml/2B3BFA1E-08B8-42AB-87D6-A28BF15E5C58@linux.dev/

I've realized but not fix yet...:
https://social.kernel.org/notice/AyDqvLkpwUvI5eyokK
0
0
0

Takashi Sakamoto (坂本 貴史)

Edited 4 months ago
The pair of client_get() and queue_delayed_work() is called in queue_bus_reset_event() just for iso_resource_auto, so it is a simple solution to split iso_resource_once, then take care of the workqueue cancellation.
0
0
0

Takashi Sakamoto (坂本 貴史)

Edited 4 months ago
static void iso_resource_auto_work(struct work_struct *work)
{
        struct iso_resource_auto *r = from_work(r, work, work.work);
        struct client *client = r->client;
        unsigned long index = r->resource.handle;
        u64 reset_jiffies;
        struct iso_resource_event *e;
        int resource_generation, current_generation;
        int channel, bandwidth, todo;
        bool free = false;

        scoped_guard(spinlock_irq, &client->device->card->lock) {
                reset_jiffies = client->device->card->reset_jiffies;
                current_generation = client->device->generation;
        }

        scoped_guard(spinlock_irq, &client->lock) {
                resource_generation = r->generation;
                r->generation = current_generation;
                todo = r->todo;
        }

        switch (todo) {
        case ISO_RES_AUTO_ALLOC:
                // Allow 1000ms grace period for other reallocations.
                if (time_is_after_jiffies64(reset_jiffies + secs_to_jiffies(1))) {
                        scoped_guard(spinlock_irq, &client->lock)
                                schedule_iso_resource_auto(r, msecs_to_jiffies(333));
                        goto out;
                }
                break;
        case ISO_RES_AUTO_REALLOC:
                // We could be called twice within the same generation.
                if (resource_generation == current_generation)
                        goto out;
                break;
        case ISO_RES_AUTO_DEALLOC:
        default:
                break;
        }

        bandwidth = r->bandwidth;

        fw_iso_resource_manage(client->device->card, current_generation,
                        r->channels, &channel, &bandwidth,
                        todo == ISO_RES_AUTO_ALLOC ||
                        todo == ISO_RES_AUTO_REALLOC);

        if (todo == ISO_RES_AUTO_DEALLOC) {
                e = no_free_ptr(r->e_dealloc);
        } else {
                // Is this generation outdated already?  As long as this resource sticks in the
                // xarray, it will be scheduled again for a newer generation or at shutdown.
                if (channel == -EAGAIN)
                        goto out;

                // Finishes successfully.
                if (channel >= 0 || bandwidth > 0) {
                        // Generate no event at reallocation.
                        if (todo == ISO_RES_AUTO_REALLOC)
                                goto out;

                        scoped_guard(spinlock_irq, &client->lock) {
                                // Transit from allocation to reallocation, except if the client
                                // requested deallocation in the meantime.
                                r->todo = ISO_RES_AUTO_REALLOC;
                                r->channels = 1ULL << channel;
                        }
                } else {
                        // Allocation or reallocation failure?  Pull this resource out of the
                        // xarray and prepare for deletion, unless the client is shutting down.
                        scoped_guard(spinlock_irq, &client->lock) {
                                if (!client->in_shutdown && xa_erase(&client->resource_xa, index)) {
                                        client_put(client);
                                        free = true;
                                }
                        }
                }

                e = no_free_ptr(r->e_alloc);
        }

        e->iso_resource.handle    = r->resource.handle;
        e->iso_resource.channel   = channel;
        e->iso_resource.bandwidth = bandwidth;

        queue_event(client, &e->event,
                    &e->iso_resource, sizeof(e->iso_resource), NULL, 0);

        if (free) {
                cancel_delayed_work(&r->work);
                kfree(r->e_alloc);
                kfree(r->e_dealloc);
                kfree(r);
        }
 out:
        client_put(client);
}

static void iso_resource_once_work(struct work_struct *work)
{
        struct iso_resource_once *r = from_work(r, work, work.work);
        struct client *client = r->client;
        struct iso_resource_event *e;
        int generation, channel, bandwidth;

        generation = client->device->generation;

        bandwidth = r->bandwidth;
        r->generation = generation;

        fw_iso_resource_manage(client->device->card, generation, r->channels, &channel, &bandwidth,
                               r->todo == ISO_RES_ONCE_ALLOC);

        e = no_free_ptr(r->event);
        e->iso_resource.channel   = channel;
        e->iso_resource.bandwidth = bandwidth;

        queue_event(client, &e->event, &e->iso_resource, sizeof(e->iso_resource), NULL, 0);

        cancel_delayed_work(&r->work);
        client_put(r->client);
        kfree(r);
}
0
0
0

Takashi Sakamoto (坂本 貴史)

Oops, being uninitialized...

Re: firewire-ohci: 7.0.0-rc1 warnings+crash
https://lore.kernel.org/lkml/20260228031255.GA832746@workstation.local/
1
0
0

Takashi Sakamoto (坂本 貴史)

0
0
0

Takashi Sakamoto (坂本 貴史)

Re: Bug#1126090: Firewire-ohci module crashes: firewire_ohci 0000:02:00.0: failed to read phy reg 2
https://lore.kernel.org/lkml/20260205123722.GA303762@workstation.local/

Being messed up...
0
0
0

Takashi Sakamoto (坂本 貴史)

I sent:
[GIT PULL] firewire fixes for v6.19-rc8:
https://lore.kernel.org/lkml/20260130225427.GA88593@workstation.local/T/#u

firewire fixes for 6.19-rc8

Fix a race condition introduced in v6.18. Andreas Persson discovered this
issue while working with Focusrite Saffire Pro 40 (TCD33070). The fw_card
instance maintains a linked list of pending transactions, which must be
protected against concurrent access. However, a commit b5725cfa4120
("firewire: core: use spin lock specific to timer for split transaction")
unintentionally allowed concurrent accesses to this list. Fix this by
adjusting the relevant critical sections to properly serialize access.
0
0
0

Takashi Sakamoto (坂本 貴史)

I made an apparent regression, sigh...

[PATCH] firewire: core: fix race condition against transaction list
https://lore.kernel.org/lkml/20260127223413.22265-1-o-takashi@sakamocchi.jp/
0
0
0
Show older