brintos

brintos / linux-shallow public Read only

0
0
Text · 3.5 KiB · 2dc1d6e Raw
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