162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * digi00x-transaction.c - a part of driver for Digidesign Digi 002/003 family 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2014-2015 Takashi Sakamoto 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <sound/asound.h> 962306a36Sopenharmony_ci#include "digi00x.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic void handle_unknown_message(struct snd_dg00x *dg00x, 1262306a36Sopenharmony_ci unsigned long long offset, __be32 *buf) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci unsigned long flags; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci spin_lock_irqsave(&dg00x->lock, flags); 1762306a36Sopenharmony_ci dg00x->msg = be32_to_cpu(*buf); 1862306a36Sopenharmony_ci spin_unlock_irqrestore(&dg00x->lock, flags); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci wake_up(&dg00x->hwdep_wait); 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void handle_message(struct fw_card *card, struct fw_request *request, 2462306a36Sopenharmony_ci int tcode, int destination, int source, 2562306a36Sopenharmony_ci int generation, unsigned long long offset, 2662306a36Sopenharmony_ci void *data, size_t length, void *callback_data) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct snd_dg00x *dg00x = callback_data; 2962306a36Sopenharmony_ci __be32 *buf = (__be32 *)data; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci fw_send_response(card, request, RCODE_COMPLETE); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (offset == dg00x->async_handler.offset) 3462306a36Sopenharmony_ci handle_unknown_message(dg00x, offset, buf); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ciint snd_dg00x_transaction_reregister(struct snd_dg00x *dg00x) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct fw_device *device = fw_parent_device(dg00x->unit); 4062306a36Sopenharmony_ci __be32 data[2]; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci /* Unknown. 4bytes. */ 4362306a36Sopenharmony_ci data[0] = cpu_to_be32((device->card->node_id << 16) | 4462306a36Sopenharmony_ci (dg00x->async_handler.offset >> 32)); 4562306a36Sopenharmony_ci data[1] = cpu_to_be32(dg00x->async_handler.offset); 4662306a36Sopenharmony_ci return snd_fw_transaction(dg00x->unit, TCODE_WRITE_BLOCK_REQUEST, 4762306a36Sopenharmony_ci DG00X_ADDR_BASE + DG00X_OFFSET_MESSAGE_ADDR, 4862306a36Sopenharmony_ci &data, sizeof(data), 0); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_civoid snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci if (dg00x->async_handler.callback_data == NULL) 5462306a36Sopenharmony_ci return; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci fw_core_remove_address_handler(&dg00x->async_handler); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci dg00x->async_handler.callback_data = NULL; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciint snd_dg00x_transaction_register(struct snd_dg00x *dg00x) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci static const struct fw_address_region resp_register_region = { 6462306a36Sopenharmony_ci .start = 0xffffe0000000ull, 6562306a36Sopenharmony_ci .end = 0xffffe000ffffull, 6662306a36Sopenharmony_ci }; 6762306a36Sopenharmony_ci int err; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci dg00x->async_handler.length = 4; 7062306a36Sopenharmony_ci dg00x->async_handler.address_callback = handle_message; 7162306a36Sopenharmony_ci dg00x->async_handler.callback_data = dg00x; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci err = fw_core_add_address_handler(&dg00x->async_handler, 7462306a36Sopenharmony_ci &resp_register_region); 7562306a36Sopenharmony_ci if (err < 0) 7662306a36Sopenharmony_ci return err; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci err = snd_dg00x_transaction_reregister(dg00x); 7962306a36Sopenharmony_ci if (err < 0) 8062306a36Sopenharmony_ci snd_dg00x_transaction_unregister(dg00x); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return err; 8362306a36Sopenharmony_ci} 84