ALSA: fireworks: fix an endianness bug for transaction length
[cascardo/linux.git] / sound / firewire / fireworks / fireworks_transaction.c
1 /*
2  * fireworks_transaction.c - a part of driver for Fireworks based devices
3  *
4  * Copyright (c) 2013-2014 Takashi Sakamoto
5  *
6  * Licensed under the terms of the GNU General Public License, version 2.
7  */
8
9 /*
10  * Fireworks have its own transaction. The transaction can be delivered by AV/C
11  * Vendor Specific command frame or usual asynchronous transaction. At least,
12  * Windows driver and firmware version 5.5 or later don't use AV/C command.
13  *
14  * Transaction substance:
15  *  At first, 6 data exist. Following to the data, parameters for each command
16  *  exist. All of the parameters are 32 bit alighed to big endian.
17  *   data[0]:   Length of transaction substance
18  *   data[1]:   Transaction version
19  *   data[2]:   Sequence number. This is incremented by the device
20  *   data[3]:   Transaction category
21  *   data[4]:   Transaction command
22  *   data[5]:   Return value in response.
23  *   data[6-]:  Parameters
24  *
25  * Transaction address:
26  *  command:    0xecc000000000
27  *  response:   0xecc080000000 (default)
28  *
29  * I note that the address for response can be changed by command. But this
30  * module uses the default address.
31  */
32 #include "./fireworks.h"
33
34 #define MEMORY_SPACE_EFW_COMMAND        0xecc000000000ULL
35 #define MEMORY_SPACE_EFW_RESPONSE       0xecc080000000ULL
36
37 #define ERROR_RETRIES 3
38 #define ERROR_DELAY_MS 5
39 #define EFC_TIMEOUT_MS 125
40
41 static DEFINE_SPINLOCK(instances_lock);
42 static struct snd_efw *instances[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
43
44 static DEFINE_SPINLOCK(transaction_queues_lock);
45 static LIST_HEAD(transaction_queues);
46
47 enum transaction_queue_state {
48         STATE_PENDING,
49         STATE_BUS_RESET,
50         STATE_COMPLETE
51 };
52
53 struct transaction_queue {
54         struct list_head list;
55         struct fw_unit *unit;
56         void *buf;
57         unsigned int size;
58         u32 seqnum;
59         enum transaction_queue_state state;
60         wait_queue_head_t wait;
61 };
62
63 int snd_efw_transaction_cmd(struct fw_unit *unit,
64                             const void *cmd, unsigned int size)
65 {
66         return snd_fw_transaction(unit, TCODE_WRITE_BLOCK_REQUEST,
67                                   MEMORY_SPACE_EFW_COMMAND,
68                                   (void *)cmd, size, 0);
69 }
70
71 int snd_efw_transaction_run(struct fw_unit *unit,
72                             const void *cmd, unsigned int cmd_size,
73                             void *resp, unsigned int resp_size)
74 {
75         struct transaction_queue t;
76         unsigned int tries;
77         int ret;
78
79         t.unit = unit;
80         t.buf = resp;
81         t.size = resp_size;
82         t.seqnum = be32_to_cpu(((struct snd_efw_transaction *)cmd)->seqnum) + 1;
83         t.state = STATE_PENDING;
84         init_waitqueue_head(&t.wait);
85
86         spin_lock_irq(&transaction_queues_lock);
87         list_add_tail(&t.list, &transaction_queues);
88         spin_unlock_irq(&transaction_queues_lock);
89
90         tries = 0;
91         do {
92                 ret = snd_efw_transaction_cmd(t.unit, (void *)cmd, cmd_size);
93                 if (ret < 0)
94                         break;
95
96                 wait_event_timeout(t.wait, t.state != STATE_PENDING,
97                                    msecs_to_jiffies(EFC_TIMEOUT_MS));
98
99                 if (t.state == STATE_COMPLETE) {
100                         ret = t.size;
101                         break;
102                 } else if (t.state == STATE_BUS_RESET) {
103                         msleep(ERROR_DELAY_MS);
104                 } else if (++tries >= ERROR_RETRIES) {
105                         dev_err(&t.unit->device, "EFW transaction timed out\n");
106                         ret = -EIO;
107                         break;
108                 }
109         } while (1);
110
111         spin_lock_irq(&transaction_queues_lock);
112         list_del(&t.list);
113         spin_unlock_irq(&transaction_queues_lock);
114
115         return ret;
116 }
117
118 static void
119 copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
120 {
121         size_t capacity, till_end;
122         struct snd_efw_transaction *t;
123
124         spin_lock_irq(&efw->lock);
125
126         t = (struct snd_efw_transaction *)data;
127         length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length);
128
129         if (efw->push_ptr < efw->pull_ptr)
130                 capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr);
131         else
132                 capacity = snd_efw_resp_buf_size -
133                            (unsigned int)(efw->push_ptr - efw->pull_ptr);
134
135         /* confirm enough space for this response */
136         if (capacity < length) {
137                 *rcode = RCODE_CONFLICT_ERROR;
138                 goto end;
139         }
140
141         /* copy to ring buffer */
142         while (length > 0) {
143                 till_end = snd_efw_resp_buf_size -
144                            (unsigned int)(efw->push_ptr - efw->resp_buf);
145                 till_end = min_t(unsigned int, length, till_end);
146
147                 memcpy(efw->push_ptr, data, till_end);
148
149                 efw->push_ptr += till_end;
150                 if (efw->push_ptr >= efw->resp_buf + snd_efw_resp_buf_size)
151                         efw->push_ptr -= snd_efw_resp_buf_size;
152
153                 length -= till_end;
154                 data += till_end;
155         }
156
157         /* for hwdep */
158         efw->resp_queues++;
159         wake_up(&efw->hwdep_wait);
160
161         *rcode = RCODE_COMPLETE;
162 end:
163         spin_unlock_irq(&efw->lock);
164 }
165
166 static void
167 handle_resp_for_user(struct fw_card *card, int generation, int source,
168                      void *data, size_t length, int *rcode)
169 {
170         struct fw_device *device;
171         struct snd_efw *efw;
172         unsigned int i;
173
174         spin_lock_irq(&instances_lock);
175
176         for (i = 0; i < SNDRV_CARDS; i++) {
177                 efw = instances[i];
178                 if (efw == NULL)
179                         continue;
180                 device = fw_parent_device(efw->unit);
181                 if ((device->card != card) ||
182                     (device->generation != generation))
183                         continue;
184                 smp_rmb();      /* node id vs. generation */
185                 if (device->node_id != source)
186                         continue;
187
188                 break;
189         }
190         if (i == SNDRV_CARDS)
191                 goto end;
192
193         copy_resp_to_buf(efw, data, length, rcode);
194 end:
195         spin_unlock_irq(&instances_lock);
196 }
197
198 static void
199 handle_resp_for_kernel(struct fw_card *card, int generation, int source,
200                        void *data, size_t length, int *rcode, u32 seqnum)
201 {
202         struct fw_device *device;
203         struct transaction_queue *t;
204         unsigned long flags;
205
206         spin_lock_irqsave(&transaction_queues_lock, flags);
207         list_for_each_entry(t, &transaction_queues, list) {
208                 device = fw_parent_device(t->unit);
209                 if ((device->card != card) ||
210                     (device->generation != generation))
211                         continue;
212                 smp_rmb();      /* node_id vs. generation */
213                 if (device->node_id != source)
214                         continue;
215
216                 if ((t->state == STATE_PENDING) && (t->seqnum == seqnum)) {
217                         t->state = STATE_COMPLETE;
218                         t->size = min_t(unsigned int, length, t->size);
219                         memcpy(t->buf, data, t->size);
220                         wake_up(&t->wait);
221                         *rcode = RCODE_COMPLETE;
222                 }
223         }
224         spin_unlock_irqrestore(&transaction_queues_lock, flags);
225 }
226
227 static void
228 efw_response(struct fw_card *card, struct fw_request *request,
229              int tcode, int destination, int source,
230              int generation, unsigned long long offset,
231              void *data, size_t length, void *callback_data)
232 {
233         int rcode, dummy;
234         u32 seqnum;
235
236         rcode = RCODE_TYPE_ERROR;
237         if (length < sizeof(struct snd_efw_transaction)) {
238                 rcode = RCODE_DATA_ERROR;
239                 goto end;
240         } else if (offset != MEMORY_SPACE_EFW_RESPONSE) {
241                 rcode = RCODE_ADDRESS_ERROR;
242                 goto end;
243         }
244
245         seqnum = be32_to_cpu(((struct snd_efw_transaction *)data)->seqnum);
246         if (seqnum > SND_EFW_TRANSACTION_USER_SEQNUM_MAX + 1) {
247                 handle_resp_for_kernel(card, generation, source,
248                                        data, length, &rcode, seqnum);
249                 if (snd_efw_resp_buf_debug)
250                         handle_resp_for_user(card, generation, source,
251                                              data, length, &dummy);
252         } else {
253                 handle_resp_for_user(card, generation, source,
254                                      data, length, &rcode);
255         }
256 end:
257         fw_send_response(card, request, rcode);
258 }
259
260 void snd_efw_transaction_add_instance(struct snd_efw *efw)
261 {
262         unsigned int i;
263
264         spin_lock_irq(&instances_lock);
265
266         for (i = 0; i < SNDRV_CARDS; i++) {
267                 if (instances[i] != NULL)
268                         continue;
269                 instances[i] = efw;
270                 break;
271         }
272
273         spin_unlock_irq(&instances_lock);
274 }
275
276 void snd_efw_transaction_remove_instance(struct snd_efw *efw)
277 {
278         unsigned int i;
279
280         spin_lock_irq(&instances_lock);
281
282         for (i = 0; i < SNDRV_CARDS; i++) {
283                 if (instances[i] != efw)
284                         continue;
285                 instances[i] = NULL;
286         }
287
288         spin_unlock_irq(&instances_lock);
289 }
290
291 void snd_efw_transaction_bus_reset(struct fw_unit *unit)
292 {
293         struct transaction_queue *t;
294
295         spin_lock_irq(&transaction_queues_lock);
296         list_for_each_entry(t, &transaction_queues, list) {
297                 if ((t->unit == unit) &&
298                     (t->state == STATE_PENDING)) {
299                         t->state = STATE_BUS_RESET;
300                         wake_up(&t->wait);
301                 }
302         }
303         spin_unlock_irq(&transaction_queues_lock);
304 }
305
306 static struct fw_address_handler resp_register_handler = {
307         .length = SND_EFW_RESPONSE_MAXIMUM_BYTES,
308         .address_callback = efw_response
309 };
310
311 int snd_efw_transaction_register(void)
312 {
313         static const struct fw_address_region resp_register_region = {
314                 .start  = MEMORY_SPACE_EFW_RESPONSE,
315                 .end    = MEMORY_SPACE_EFW_RESPONSE +
316                           SND_EFW_RESPONSE_MAXIMUM_BYTES
317         };
318         return fw_core_add_address_handler(&resp_register_handler,
319                                            &resp_register_region);
320 }
321
322 void snd_efw_transaction_unregister(void)
323 {
324         WARN_ON(!list_empty(&transaction_queues));
325         fw_core_remove_address_handler(&resp_register_handler);
326 }