1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * ff-transaction.c - a part of driver for RME Fireface series |
4 | * |
5 | * Copyright (c) 2015-2017 Takashi Sakamoto |
6 | */ |
7 | |
8 | #include "ff.h" |
9 | |
10 | static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port, |
11 | int rcode) |
12 | { |
13 | struct snd_rawmidi_substream *substream = |
14 | READ_ONCE(ff->rx_midi_substreams[port]); |
15 | |
16 | if (rcode_is_permanent_error(rcode)) { |
17 | ff->rx_midi_error[port] = true; |
18 | return; |
19 | } |
20 | |
21 | if (rcode != RCODE_COMPLETE) { |
22 | /* Transfer the message again, immediately. */ |
23 | ff->next_ktime[port] = 0; |
24 | schedule_work(work: &ff->rx_midi_work[port]); |
25 | return; |
26 | } |
27 | |
28 | snd_rawmidi_transmit_ack(substream, count: ff->rx_bytes[port]); |
29 | ff->rx_bytes[port] = 0; |
30 | |
31 | if (!snd_rawmidi_transmit_empty(substream)) |
32 | schedule_work(work: &ff->rx_midi_work[port]); |
33 | } |
34 | |
35 | static void finish_transmit_midi0_msg(struct fw_card *card, int rcode, |
36 | void *data, size_t length, |
37 | void *callback_data) |
38 | { |
39 | struct snd_ff *ff = |
40 | container_of(callback_data, struct snd_ff, transactions[0]); |
41 | finish_transmit_midi_msg(ff, port: 0, rcode); |
42 | } |
43 | |
44 | static void finish_transmit_midi1_msg(struct fw_card *card, int rcode, |
45 | void *data, size_t length, |
46 | void *callback_data) |
47 | { |
48 | struct snd_ff *ff = |
49 | container_of(callback_data, struct snd_ff, transactions[1]); |
50 | finish_transmit_midi_msg(ff, port: 1, rcode); |
51 | } |
52 | |
53 | static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) |
54 | { |
55 | struct snd_rawmidi_substream *substream = |
56 | READ_ONCE(ff->rx_midi_substreams[port]); |
57 | int quad_count; |
58 | |
59 | struct fw_device *fw_dev = fw_parent_device(ff->unit); |
60 | unsigned long long addr; |
61 | int generation; |
62 | fw_transaction_callback_t callback; |
63 | int tcode; |
64 | |
65 | if (substream == NULL || snd_rawmidi_transmit_empty(substream)) |
66 | return; |
67 | |
68 | if (ff->rx_bytes[port] > 0 || ff->rx_midi_error[port]) |
69 | return; |
70 | |
71 | /* Do it in next chance. */ |
72 | if (ktime_after(cmp1: ff->next_ktime[port], cmp2: ktime_get())) { |
73 | schedule_work(work: &ff->rx_midi_work[port]); |
74 | return; |
75 | } |
76 | |
77 | quad_count = ff->spec->protocol->fill_midi_msg(ff, substream, port); |
78 | if (quad_count <= 0) |
79 | return; |
80 | |
81 | if (port == 0) { |
82 | addr = ff->spec->midi_rx_addrs[0]; |
83 | callback = finish_transmit_midi0_msg; |
84 | } else { |
85 | addr = ff->spec->midi_rx_addrs[1]; |
86 | callback = finish_transmit_midi1_msg; |
87 | } |
88 | |
89 | /* Set interval to next transaction. */ |
90 | ff->next_ktime[port] = ktime_add_ns(ktime_get(), |
91 | ff->rx_bytes[port] * 8 * (NSEC_PER_SEC / 31250)); |
92 | |
93 | if (quad_count == 1) |
94 | tcode = TCODE_WRITE_QUADLET_REQUEST; |
95 | else |
96 | tcode = TCODE_WRITE_BLOCK_REQUEST; |
97 | |
98 | /* |
99 | * In Linux FireWire core, when generation is updated with memory |
100 | * barrier, node id has already been updated. In this module, After |
101 | * this smp_rmb(), load/store instructions to memory are completed. |
102 | * Thus, both of generation and node id are available with recent |
103 | * values. This is a light-serialization solution to handle bus reset |
104 | * events on IEEE 1394 bus. |
105 | */ |
106 | generation = fw_dev->generation; |
107 | smp_rmb(); |
108 | fw_send_request(card: fw_dev->card, t: &ff->transactions[port], tcode, |
109 | destination_id: fw_dev->node_id, generation, speed: fw_dev->max_speed, |
110 | offset: addr, payload: &ff->msg_buf[port], length: quad_count * 4, |
111 | callback, callback_data: &ff->transactions[port]); |
112 | } |
113 | |
114 | static void transmit_midi0_msg(struct work_struct *work) |
115 | { |
116 | struct snd_ff *ff = container_of(work, struct snd_ff, rx_midi_work[0]); |
117 | |
118 | transmit_midi_msg(ff, port: 0); |
119 | } |
120 | |
121 | static void transmit_midi1_msg(struct work_struct *work) |
122 | { |
123 | struct snd_ff *ff = container_of(work, struct snd_ff, rx_midi_work[1]); |
124 | |
125 | transmit_midi_msg(ff, port: 1); |
126 | } |
127 | |
128 | static void handle_msg(struct fw_card *card, struct fw_request *request, int tcode, |
129 | int destination, int source, int generation, unsigned long long offset, |
130 | void *data, size_t length, void *callback_data) |
131 | { |
132 | struct snd_ff *ff = callback_data; |
133 | __le32 *buf = data; |
134 | u32 tstamp = fw_request_get_timestamp(request); |
135 | unsigned long flag; |
136 | |
137 | fw_send_response(card, request, RCODE_COMPLETE); |
138 | |
139 | offset -= ff->async_handler.offset; |
140 | |
141 | spin_lock_irqsave(&ff->lock, flag); |
142 | ff->spec->protocol->handle_msg(ff, (unsigned int)offset, buf, length, tstamp); |
143 | spin_unlock_irqrestore(lock: &ff->lock, flags: flag); |
144 | } |
145 | |
146 | static int allocate_own_address(struct snd_ff *ff, int i) |
147 | { |
148 | struct fw_address_region midi_msg_region; |
149 | int err; |
150 | |
151 | ff->async_handler.length = ff->spec->midi_addr_range; |
152 | ff->async_handler.address_callback = handle_msg; |
153 | ff->async_handler.callback_data = ff; |
154 | |
155 | midi_msg_region.start = 0x000100000000ull * i; |
156 | midi_msg_region.end = midi_msg_region.start + ff->async_handler.length; |
157 | |
158 | err = fw_core_add_address_handler(handler: &ff->async_handler, region: &midi_msg_region); |
159 | if (err >= 0) { |
160 | /* Controllers are allowed to register this region. */ |
161 | if (ff->async_handler.offset & 0x0000ffffffff) { |
162 | fw_core_remove_address_handler(handler: &ff->async_handler); |
163 | err = -EAGAIN; |
164 | } |
165 | } |
166 | |
167 | return err; |
168 | } |
169 | |
170 | // Controllers are allowed to register higher 4 bytes of destination address to |
171 | // receive asynchronous transactions for MIDI messages, while the way to |
172 | // register lower 4 bytes of address is different depending on protocols. For |
173 | // details, please refer to comments in protocol implementations. |
174 | // |
175 | // This driver expects userspace applications to configure registers for the |
176 | // lower address because in most cases such registers has the other settings. |
177 | int snd_ff_transaction_reregister(struct snd_ff *ff) |
178 | { |
179 | struct fw_card *fw_card = fw_parent_device(ff->unit)->card; |
180 | u32 addr; |
181 | __le32 reg; |
182 | |
183 | /* |
184 | * Controllers are allowed to register its node ID and upper 2 byte of |
185 | * local address to listen asynchronous transactions. |
186 | */ |
187 | addr = (fw_card->node_id << 16) | (ff->async_handler.offset >> 32); |
188 | reg = cpu_to_le32(addr); |
189 | return snd_fw_transaction(unit: ff->unit, TCODE_WRITE_QUADLET_REQUEST, |
190 | offset: ff->spec->midi_high_addr, |
191 | buffer: ®, length: sizeof(reg), flags: 0); |
192 | } |
193 | |
194 | int snd_ff_transaction_register(struct snd_ff *ff) |
195 | { |
196 | int i, err; |
197 | |
198 | /* |
199 | * Allocate in Memory Space of IEC 13213, but lower 4 byte in LSB should |
200 | * be zero due to device specification. |
201 | */ |
202 | for (i = 0; i < 0xffff; i++) { |
203 | err = allocate_own_address(ff, i); |
204 | if (err != -EBUSY && err != -EAGAIN) |
205 | break; |
206 | } |
207 | if (err < 0) |
208 | return err; |
209 | |
210 | err = snd_ff_transaction_reregister(ff); |
211 | if (err < 0) |
212 | return err; |
213 | |
214 | INIT_WORK(&ff->rx_midi_work[0], transmit_midi0_msg); |
215 | INIT_WORK(&ff->rx_midi_work[1], transmit_midi1_msg); |
216 | |
217 | return 0; |
218 | } |
219 | |
220 | void snd_ff_transaction_unregister(struct snd_ff *ff) |
221 | { |
222 | __le32 reg; |
223 | |
224 | if (ff->async_handler.callback_data == NULL) |
225 | return; |
226 | ff->async_handler.callback_data = NULL; |
227 | |
228 | /* Release higher 4 bytes of address. */ |
229 | reg = cpu_to_le32(0x00000000); |
230 | snd_fw_transaction(unit: ff->unit, TCODE_WRITE_QUADLET_REQUEST, |
231 | offset: ff->spec->midi_high_addr, |
232 | buffer: ®, length: sizeof(reg), flags: 0); |
233 | |
234 | fw_core_remove_address_handler(handler: &ff->async_handler); |
235 | } |
236 | |