Path: blob/master/sound/firewire/motu/motu-transaction.c
29266 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* motu-transaction.c - a part of driver for MOTU FireWire series3*4* Copyright (c) 2015-2017 Takashi Sakamoto <[email protected]>5*/678#include "motu.h"910#define SND_MOTU_ADDR_BASE 0xfffff0000000ULL11#define ASYNC_ADDR_HI 0x0b0412#define ASYNC_ADDR_LO 0x0b081314int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,15size_t size)16{17int tcode;1819if (size % sizeof(__be32) > 0 || size <= 0)20return -EINVAL;21if (size == sizeof(__be32))22tcode = TCODE_READ_QUADLET_REQUEST;23else24tcode = TCODE_READ_BLOCK_REQUEST;2526return snd_fw_transaction(motu->unit, tcode,27SND_MOTU_ADDR_BASE + offset, reg, size, 0);28}2930int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,31size_t size)32{33int tcode;3435if (size % sizeof(__be32) > 0 || size <= 0)36return -EINVAL;37if (size == sizeof(__be32))38tcode = TCODE_WRITE_QUADLET_REQUEST;39else40tcode = TCODE_WRITE_BLOCK_REQUEST;4142return snd_fw_transaction(motu->unit, tcode,43SND_MOTU_ADDR_BASE + offset, reg, size, 0);44}4546static void handle_message(struct fw_card *card, struct fw_request *request,47int tcode, int destination, int source,48int generation, unsigned long long offset,49void *data, size_t length, void *callback_data)50{51struct snd_motu *motu = callback_data;52__be32 *buf = (__be32 *)data;5354if (tcode != TCODE_WRITE_QUADLET_REQUEST) {55fw_send_response(card, request, RCODE_COMPLETE);56return;57}5859if (offset != motu->async_handler.offset || length != 4) {60fw_send_response(card, request, RCODE_ADDRESS_ERROR);61return;62}6364scoped_guard(spinlock_irqsave, &motu->lock) {65motu->msg = be32_to_cpu(*buf);66}6768fw_send_response(card, request, RCODE_COMPLETE);6970wake_up(&motu->hwdep_wait);71}7273int snd_motu_transaction_reregister(struct snd_motu *motu)74{75struct fw_device *device = fw_parent_device(motu->unit);76__be32 data;77int err;7879if (motu->async_handler.callback_data == NULL)80return -EINVAL;8182/* Register messaging address. Block transaction is not allowed. */83data = cpu_to_be32((device->card->node_id << 16) |84(motu->async_handler.offset >> 32));85err = snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data,86sizeof(data));87if (err < 0)88return err;8990data = cpu_to_be32(motu->async_handler.offset);91return snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data,92sizeof(data));93}9495int snd_motu_transaction_register(struct snd_motu *motu)96{97static const struct fw_address_region resp_register_region = {98.start = 0xffffe0000000ull,99.end = 0xffffe000ffffull,100};101int err;102103/* Perhaps, 4 byte messages are transferred. */104motu->async_handler.length = 4;105motu->async_handler.address_callback = handle_message;106motu->async_handler.callback_data = motu;107108err = fw_core_add_address_handler(&motu->async_handler,109&resp_register_region);110if (err < 0)111return err;112113err = snd_motu_transaction_reregister(motu);114if (err < 0) {115fw_core_remove_address_handler(&motu->async_handler);116motu->async_handler.address_callback = NULL;117}118119return err;120}121122void snd_motu_transaction_unregister(struct snd_motu *motu)123{124__be32 data;125126if (motu->async_handler.address_callback != NULL)127fw_core_remove_address_handler(&motu->async_handler);128motu->async_handler.address_callback = NULL;129130/* Unregister the address. */131data = cpu_to_be32(0x00000000);132snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data, sizeof(data));133snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data, sizeof(data));134}135136137