--- /dev/null
+/*
+ * motu-transaction.c - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+
+#include "motu.h"
+
+#define SND_MOTU_ADDR_BASE     0xfffff0000000ULL
+#define ASYNC_ADDR_HI  0x0b04
+#define ASYNC_ADDR_LO  0x0b08
+
+int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
+                             size_t size)
+{
+       int tcode;
+
+       if (size % sizeof(__be32) > 0 || size <= 0)
+               return -EINVAL;
+       if (size == sizeof(__be32))
+               tcode = TCODE_READ_QUADLET_REQUEST;
+       else
+               tcode = TCODE_READ_BLOCK_REQUEST;
+
+       return snd_fw_transaction(motu->unit, tcode,
+                                 SND_MOTU_ADDR_BASE + offset, reg, size, 0);
+}
+
+int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
+                              size_t size)
+{
+       int tcode;
+
+       if (size % sizeof(__be32) > 0 || size <= 0)
+               return -EINVAL;
+       if (size == sizeof(__be32))
+               tcode = TCODE_WRITE_QUADLET_REQUEST;
+       else
+               tcode = TCODE_WRITE_BLOCK_REQUEST;
+
+       return snd_fw_transaction(motu->unit, tcode,
+                                 SND_MOTU_ADDR_BASE + offset, reg, size, 0);
+}
+
+static void handle_message(struct fw_card *card, struct fw_request *request,
+                          int tcode, int destination, int source,
+                          int generation, unsigned long long offset,
+                          void *data, size_t length, void *callback_data)
+{
+       fw_send_response(card, request, RCODE_COMPLETE);
+}
+
+int snd_motu_transaction_reregister(struct snd_motu *motu)
+{
+       struct fw_device *device = fw_parent_device(motu->unit);
+       __be32 data;
+       int err;
+
+       if (motu->async_handler.callback_data == NULL)
+               return -EINVAL;
+
+       /* Register messaging address. Block transaction is not allowed. */
+       data = cpu_to_be32((device->card->node_id << 16) |
+                          (motu->async_handler.offset >> 32));
+       err = snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data,
+                                        sizeof(data));
+       if (err < 0)
+               return err;
+
+       data = cpu_to_be32(motu->async_handler.offset);
+       return snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data,
+                                         sizeof(data));
+}
+
+int snd_motu_transaction_register(struct snd_motu *motu)
+{
+       static const struct fw_address_region resp_register_region = {
+               .start  = 0xffffe0000000ull,
+               .end    = 0xffffe000ffffull,
+       };
+       int err;
+
+       /* Perhaps, 4 byte messages are transferred. */
+       motu->async_handler.length = 4;
+       motu->async_handler.address_callback = handle_message;
+       motu->async_handler.callback_data = motu;
+
+       err = fw_core_add_address_handler(&motu->async_handler,
+                                         &resp_register_region);
+       if (err < 0)
+               return err;
+
+       err = snd_motu_transaction_reregister(motu);
+       if (err < 0) {
+               fw_core_remove_address_handler(&motu->async_handler);
+               motu->async_handler.address_callback = NULL;
+       }
+
+       return err;
+}
+
+void snd_motu_transaction_unregister(struct snd_motu *motu)
+{
+       __be32 data;
+
+       if (motu->async_handler.address_callback != NULL)
+               fw_core_remove_address_handler(&motu->async_handler);
+       motu->async_handler.address_callback = NULL;
+
+       /* Unregister the address. */
+       data = cpu_to_be32(0x00000000);
+       snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data, sizeof(data));
+       snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data, sizeof(data));
+}
 
 
 static void motu_free(struct snd_motu *motu)
 {
+       snd_motu_transaction_unregister(motu);
+
        fw_unit_put(motu->unit);
 
        mutex_destroy(&motu->mutex);
 
        name_card(motu);
 
+       err = snd_motu_transaction_register(motu);
+       if (err < 0)
+               goto error;
+
        err = snd_card_register(motu->card);
        if (err < 0)
                goto error;
 
        return;
 error:
+       snd_motu_transaction_unregister(motu);
        snd_card_free(motu->card);
        dev_info(&motu->unit->device,
                 "Sound card registration failed: %d\n", err);
        /* Postpone a workqueue for deferred registration. */
        if (!motu->registered)
                snd_fw_schedule_registration(unit, &motu->dwork);
+
+       /* The handler address register becomes initialized. */
+       snd_motu_transaction_reregister(motu);
 }
 
 #define SND_MOTU_DEV_ENTRY(model, data)                        \
 
        struct snd_motu_packet_format rx_packet_formats;
        struct amdtp_stream tx_stream;
        struct amdtp_stream rx_stream;
+
+       /* For notification. */
+       struct fw_address_handler async_handler;
+       u32 msg;
 };
 
 enum snd_motu_spec_flags {
                              struct snd_motu_packet_format *formats);
 int amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s,
                                      struct snd_pcm_runtime *runtime);
+
+int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
+                             size_t size);
+int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
+                              size_t size);
+int snd_motu_transaction_register(struct snd_motu *motu);
+int snd_motu_transaction_reregister(struct snd_motu *motu);
+void snd_motu_transaction_unregister(struct snd_motu *motu);
 #endif