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