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 unsigned long flags; 15 16 spin_lock_irqsave(&dg00x->lock, flags); 17 dg00x->msg = be32_to_cpu(*buf); 18 spin_unlock_irqrestore(&dg00x->lock, flags); 19 20 wake_up(&dg00x->hwdep_wait); 21 } 22 23 static void handle_message(struct fw_card *card, struct fw_request *request, 24 int tcode, int destination, int source, 25 int generation, unsigned long long offset, 26 void *data, size_t length, void *callback_data) 27 { 28 struct snd_dg00x *dg00x = callback_data; 29 __be32 *buf = (__be32 *)data; 30 31 fw_send_response(card, request, RCODE_COMPLETE); 32 33 if (offset == dg00x->async_handler.offset) 34 handle_unknown_message(dg00x, offset, buf); 35 } 36 37 int snd_dg00x_transaction_reregister(struct snd_dg00x *dg00x) 38 { 39 struct fw_device *device = fw_parent_device(dg00x->unit); 40 __be32 data[2]; 41 42 /* Unknown. 4bytes. */ 43 data[0] = cpu_to_be32((device->card->node_id << 16) | 44 (dg00x->async_handler.offset >> 32)); 45 data[1] = cpu_to_be32(dg00x->async_handler.offset); 46 return snd_fw_transaction(dg00x->unit, TCODE_WRITE_BLOCK_REQUEST, 47 DG00X_ADDR_BASE + DG00X_OFFSET_MESSAGE_ADDR, 48 &data, sizeof(data), 0); 49 } 50 51 void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x) 52 { 53 if (dg00x->async_handler.callback_data == NULL) 54 return; 55 56 fw_core_remove_address_handler(&dg00x->async_handler); 57 58 dg00x->async_handler.callback_data = NULL; 59 } 60 61 int snd_dg00x_transaction_register(struct snd_dg00x *dg00x) 62 { 63 static const struct fw_address_region resp_register_region = { 64 .start = 0xffffe0000000ull, 65 .end = 0xffffe000ffffull, 66 }; 67 int err; 68 69 dg00x->async_handler.length = 4; 70 dg00x->async_handler.address_callback = handle_message; 71 dg00x->async_handler.callback_data = dg00x; 72 73 err = fw_core_add_address_handler(&dg00x->async_handler, 74 &resp_register_region); 75 if (err < 0) 76 return err; 77 78 err = snd_dg00x_transaction_reregister(dg00x); 79 if (err < 0) 80 snd_dg00x_transaction_unregister(dg00x); 81 82 return err; 83 } 84