1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * digi00x-transaction.c - a part of driver for Digidesign Digi 002/003 family 4 * 5 * Copyright (c) 2014-2015 Takashi Sakamoto 6 */ 7 8 #include <sound/asound.h> 9 #include "digi00x.h" 10 11 static void handle_unknown_message(struct snd_dg00x *dg00x, 12 unsigned long long offset, __be32 *buf) 13 { 14 scoped_guard(spinlock_irqsave, &dg00x->lock) { 15 dg00x->msg = be32_to_cpu(*buf); 16 } 17 18 wake_up(&dg00x->hwdep_wait); 19 } 20 21 static void handle_message(struct fw_card *card, struct fw_request *request, 22 int tcode, int destination, int source, 23 int generation, unsigned long long offset, 24 void *data, size_t length, void *callback_data) 25 { 26 struct snd_dg00x *dg00x = callback_data; 27 __be32 *buf = (__be32 *)data; 28 29 fw_send_response(card, request, RCODE_COMPLETE); 30 31 if (offset == dg00x->async_handler.offset) 32 handle_unknown_message(dg00x, offset, buf); 33 } 34 35 int snd_dg00x_transaction_reregister(struct snd_dg00x *dg00x) 36 { 37 struct fw_device *device = fw_parent_device(dg00x->unit); 38 __be32 data[2]; 39 40 /* Unknown. 4bytes. */ 41 data[0] = cpu_to_be32((device->card->node_id << 16) | 42 (dg00x->async_handler.offset >> 32)); 43 data[1] = cpu_to_be32(dg00x->async_handler.offset); 44 return snd_fw_transaction(dg00x->unit, TCODE_WRITE_BLOCK_REQUEST, 45 DG00X_ADDR_BASE + DG00X_OFFSET_MESSAGE_ADDR, 46 &data, sizeof(data), 0); 47 } 48 49 void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x) 50 { 51 if (dg00x->async_handler.callback_data == NULL) 52 return; 53 54 fw_core_remove_address_handler(&dg00x->async_handler); 55 56 dg00x->async_handler.callback_data = NULL; 57 } 58 59 int snd_dg00x_transaction_register(struct snd_dg00x *dg00x) 60 { 61 static const struct fw_address_region resp_register_region = { 62 .start = 0xffffe0000000ull, 63 .end = 0xffffe000ffffull, 64 }; 65 int err; 66 67 dg00x->async_handler.length = 4; 68 dg00x->async_handler.address_callback = handle_message; 69 dg00x->async_handler.callback_data = dg00x; 70 71 err = fw_core_add_address_handler(&dg00x->async_handler, 72 &resp_register_region); 73 if (err < 0) 74 return err; 75 76 err = snd_dg00x_transaction_reregister(dg00x); 77 if (err < 0) 78 snd_dg00x_transaction_unregister(dg00x); 79 80 return err; 81 } 82