137 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * motu-transaction.c - a part of driver for MOTU FireWire series4 *5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>6 */7 8 9#include "motu.h"10 11#define SND_MOTU_ADDR_BASE 0xfffff0000000ULL12#define ASYNC_ADDR_HI 0x0b0413#define ASYNC_ADDR_LO 0x0b0814 15int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,16 size_t size)17{18 int tcode;19 20 if (size % sizeof(__be32) > 0 || size <= 0)21 return -EINVAL;22 if (size == sizeof(__be32))23 tcode = TCODE_READ_QUADLET_REQUEST;24 else25 tcode = TCODE_READ_BLOCK_REQUEST;26 27 return snd_fw_transaction(motu->unit, tcode,28 SND_MOTU_ADDR_BASE + offset, reg, size, 0);29}30 31int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,32 size_t size)33{34 int tcode;35 36 if (size % sizeof(__be32) > 0 || size <= 0)37 return -EINVAL;38 if (size == sizeof(__be32))39 tcode = TCODE_WRITE_QUADLET_REQUEST;40 else41 tcode = TCODE_WRITE_BLOCK_REQUEST;42 43 return snd_fw_transaction(motu->unit, tcode,44 SND_MOTU_ADDR_BASE + offset, reg, size, 0);45}46 47static void handle_message(struct fw_card *card, struct fw_request *request,48 int tcode, int destination, int source,49 int generation, unsigned long long offset,50 void *data, size_t length, void *callback_data)51{52 struct snd_motu *motu = callback_data;53 __be32 *buf = (__be32 *)data;54 unsigned long flags;55 56 if (tcode != TCODE_WRITE_QUADLET_REQUEST) {57 fw_send_response(card, request, RCODE_COMPLETE);58 return;59 }60 61 if (offset != motu->async_handler.offset || length != 4) {62 fw_send_response(card, request, RCODE_ADDRESS_ERROR);63 return;64 }65 66 spin_lock_irqsave(&motu->lock, flags);67 motu->msg = be32_to_cpu(*buf);68 spin_unlock_irqrestore(&motu->lock, flags);69 70 fw_send_response(card, request, RCODE_COMPLETE);71 72 wake_up(&motu->hwdep_wait);73}74 75int snd_motu_transaction_reregister(struct snd_motu *motu)76{77 struct fw_device *device = fw_parent_device(motu->unit);78 __be32 data;79 int err;80 81 if (motu->async_handler.callback_data == NULL)82 return -EINVAL;83 84 /* Register messaging address. Block transaction is not allowed. */85 data = cpu_to_be32((device->card->node_id << 16) |86 (motu->async_handler.offset >> 32));87 err = snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data,88 sizeof(data));89 if (err < 0)90 return err;91 92 data = cpu_to_be32(motu->async_handler.offset);93 return snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data,94 sizeof(data));95}96 97int snd_motu_transaction_register(struct snd_motu *motu)98{99 static const struct fw_address_region resp_register_region = {100 .start = 0xffffe0000000ull,101 .end = 0xffffe000ffffull,102 };103 int err;104 105 /* Perhaps, 4 byte messages are transferred. */106 motu->async_handler.length = 4;107 motu->async_handler.address_callback = handle_message;108 motu->async_handler.callback_data = motu;109 110 err = fw_core_add_address_handler(&motu->async_handler,111 &resp_register_region);112 if (err < 0)113 return err;114 115 err = snd_motu_transaction_reregister(motu);116 if (err < 0) {117 fw_core_remove_address_handler(&motu->async_handler);118 motu->async_handler.address_callback = NULL;119 }120 121 return err;122}123 124void snd_motu_transaction_unregister(struct snd_motu *motu)125{126 __be32 data;127 128 if (motu->async_handler.address_callback != NULL)129 fw_core_remove_address_handler(&motu->async_handler);130 motu->async_handler.address_callback = NULL;131 132 /* Unregister the address. */133 data = cpu_to_be32(0x00000000);134 snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data, sizeof(data));135 snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data, sizeof(data));136}137