1 /*
2  * motu-transaction.c - a part of driver for MOTU FireWire series
3  *
4  * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
5  *
6  * Licensed under the terms of the GNU General Public License, version 2.
7  */
8 
9 
10 #include "motu.h"
11 
12 #define SND_MOTU_ADDR_BASE	0xfffff0000000ULL
13 #define ASYNC_ADDR_HI  0x0b04
14 #define ASYNC_ADDR_LO  0x0b08
15 
16 int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
17 			      size_t size)
18 {
19 	int tcode;
20 
21 	if (size % sizeof(__be32) > 0 || size <= 0)
22 		return -EINVAL;
23 	if (size == sizeof(__be32))
24 		tcode = TCODE_READ_QUADLET_REQUEST;
25 	else
26 		tcode = TCODE_READ_BLOCK_REQUEST;
27 
28 	return snd_fw_transaction(motu->unit, tcode,
29 				  SND_MOTU_ADDR_BASE + offset, reg, size, 0);
30 }
31 
32 int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
33 			       size_t size)
34 {
35 	int tcode;
36 
37 	if (size % sizeof(__be32) > 0 || size <= 0)
38 		return -EINVAL;
39 	if (size == sizeof(__be32))
40 		tcode = TCODE_WRITE_QUADLET_REQUEST;
41 	else
42 		tcode = TCODE_WRITE_BLOCK_REQUEST;
43 
44 	return snd_fw_transaction(motu->unit, tcode,
45 				  SND_MOTU_ADDR_BASE + offset, reg, size, 0);
46 }
47 
48 static void handle_message(struct fw_card *card, struct fw_request *request,
49 			   int tcode, int destination, int source,
50 			   int generation, unsigned long long offset,
51 			   void *data, size_t length, void *callback_data)
52 {
53 	struct snd_motu *motu = callback_data;
54 	__be32 *buf = (__be32 *)data;
55 	unsigned long flags;
56 
57 	if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
58 		fw_send_response(card, request, RCODE_COMPLETE);
59 		return;
60 	}
61 
62 	if (offset != motu->async_handler.offset || length != 4) {
63 		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
64 		return;
65 	}
66 
67 	spin_lock_irqsave(&motu->lock, flags);
68 	motu->msg = be32_to_cpu(*buf);
69 	spin_unlock_irqrestore(&motu->lock, flags);
70 
71 	fw_send_response(card, request, RCODE_COMPLETE);
72 
73 	wake_up(&motu->hwdep_wait);
74 }
75 
76 int snd_motu_transaction_reregister(struct snd_motu *motu)
77 {
78 	struct fw_device *device = fw_parent_device(motu->unit);
79 	__be32 data;
80 	int err;
81 
82 	if (motu->async_handler.callback_data == NULL)
83 		return -EINVAL;
84 
85 	/* Register messaging address. Block transaction is not allowed. */
86 	data = cpu_to_be32((device->card->node_id << 16) |
87 			   (motu->async_handler.offset >> 32));
88 	err = snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data,
89 					 sizeof(data));
90 	if (err < 0)
91 		return err;
92 
93 	data = cpu_to_be32(motu->async_handler.offset);
94 	return snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data,
95 					  sizeof(data));
96 }
97 
98 int snd_motu_transaction_register(struct snd_motu *motu)
99 {
100 	static const struct fw_address_region resp_register_region = {
101 		.start	= 0xffffe0000000ull,
102 		.end	= 0xffffe000ffffull,
103 	};
104 	int err;
105 
106 	/* Perhaps, 4 byte messages are transferred. */
107 	motu->async_handler.length = 4;
108 	motu->async_handler.address_callback = handle_message;
109 	motu->async_handler.callback_data = motu;
110 
111 	err = fw_core_add_address_handler(&motu->async_handler,
112 					  &resp_register_region);
113 	if (err < 0)
114 		return err;
115 
116 	err = snd_motu_transaction_reregister(motu);
117 	if (err < 0) {
118 		fw_core_remove_address_handler(&motu->async_handler);
119 		motu->async_handler.address_callback = NULL;
120 	}
121 
122 	return err;
123 }
124 
125 void snd_motu_transaction_unregister(struct snd_motu *motu)
126 {
127 	__be32 data;
128 
129 	if (motu->async_handler.address_callback != NULL)
130 		fw_core_remove_address_handler(&motu->async_handler);
131 	motu->async_handler.address_callback = NULL;
132 
133 	/* Unregister the address. */
134 	data = cpu_to_be32(0x00000000);
135 	snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data, sizeof(data));
136 	snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data, sizeof(data));
137 }
138