blob: 59d5ca4438b26fbcca68fb0b917454ada4f65c14 [file] [log] [blame]
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001/*
2 * TC Applied Technologies Digital Interface Communications Engine driver
3 *
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 * Licensed under the terms of the GNU General Public License, version 2.
6 */
7
Clemens Ladisch0c29c912011-09-04 22:14:15 +02008#include <linux/compat.h>
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02009#include <linux/delay.h>
10#include <linux/device.h>
11#include <linux/firewire.h>
12#include <linux/firewire-constants.h>
13#include <linux/module.h>
14#include <linux/mod_devicetable.h>
15#include <linux/mutex.h>
16#include <linux/slab.h>
Clemens Ladisch0c29c912011-09-04 22:14:15 +020017#include <linux/spinlock.h>
18#include <linux/wait.h>
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +020019#include <sound/control.h>
20#include <sound/core.h>
Clemens Ladisch0c29c912011-09-04 22:14:15 +020021#include <sound/firewire.h>
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +020022#include <sound/hwdep.h>
23#include <sound/initval.h>
24#include <sound/pcm.h>
25#include <sound/pcm_params.h>
26#include "amdtp.h"
27#include "iso-resources.h"
28#include "lib.h"
Clemens Ladisch54e72f02011-09-04 22:15:54 +020029#include "dice-interface.h"
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +020030
31
32struct dice {
33 struct snd_card *card;
34 struct fw_unit *unit;
Clemens Ladisch0c29c912011-09-04 22:14:15 +020035 spinlock_t lock;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +020036 struct mutex mutex;
37 unsigned int global_offset;
38 unsigned int rx_offset;
39 struct fw_address_handler notification_handler;
40 int owner_generation;
Clemens Ladisch0c29c912011-09-04 22:14:15 +020041 int dev_lock_count; /* > 0 driver, < 0 userspace */
42 bool dev_lock_changed;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +020043 bool global_enabled;
Clemens Ladisch0c29c912011-09-04 22:14:15 +020044 wait_queue_head_t hwdep_wait;
45 u32 notification_bits;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +020046 struct snd_pcm_substream *pcm;
47 struct fw_iso_resources resources;
48 struct amdtp_out_stream stream;
49};
50
51MODULE_DESCRIPTION("DICE driver");
52MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
53MODULE_LICENSE("GPL v2");
54
Clemens Ladisch341682c2011-09-04 22:12:06 +020055static const unsigned int dice_rates[] = {
56 [0] = 32000,
57 [1] = 44100,
58 [2] = 48000,
59 [3] = 88200,
60 [4] = 96000,
61 [5] = 176400,
62 [6] = 192000,
63};
64
Clemens Ladisch0c29c912011-09-04 22:14:15 +020065static void dice_lock_changed(struct dice *dice)
66{
67 dice->dev_lock_changed = true;
68 wake_up(&dice->hwdep_wait);
69}
70
71static int dice_try_lock(struct dice *dice)
72{
73 int err;
74
75 spin_lock_irq(&dice->lock);
76
77 if (dice->dev_lock_count < 0) {
78 err = -EBUSY;
79 goto out;
80 }
81
82 if (dice->dev_lock_count++ == 0)
83 dice_lock_changed(dice);
84 err = 0;
85
86out:
87 spin_unlock_irq(&dice->lock);
88
89 return err;
90}
91
92static void dice_unlock(struct dice *dice)
93{
94 spin_lock_irq(&dice->lock);
95
96 if (WARN_ON(dice->dev_lock_count <= 0))
97 goto out;
98
99 if (--dice->dev_lock_count == 0)
100 dice_lock_changed(dice);
101
102out:
103 spin_unlock_irq(&dice->lock);
104}
105
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200106static inline u64 global_address(struct dice *dice, unsigned int offset)
107{
108 return DICE_PRIVATE_SPACE + dice->global_offset + offset;
109}
110
111// TODO: rx index
112static inline u64 rx_address(struct dice *dice, unsigned int offset)
113{
114 return DICE_PRIVATE_SPACE + dice->rx_offset + offset;
115}
116
117static int dice_owner_set(struct dice *dice)
118{
119 struct fw_device *device = fw_parent_device(dice->unit);
120 __be64 *buffer;
Clemens Ladisch1b704852011-09-04 22:17:38 +0200121 int err, errors = 0;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200122
123 buffer = kmalloc(2 * 8, GFP_KERNEL);
124 if (!buffer)
125 return -ENOMEM;
126
127 for (;;) {
128 buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
129 buffer[1] = cpu_to_be64(
130 ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
131 dice->notification_handler.offset);
132
133 dice->owner_generation = device->generation;
134 smp_rmb(); /* node_id vs. generation */
Clemens Ladisch1b704852011-09-04 22:17:38 +0200135 err = snd_fw_transaction(dice->unit,
136 TCODE_LOCK_COMPARE_SWAP,
137 global_address(dice, GLOBAL_OWNER),
138 buffer, 2 * 8,
139 FW_FIXED_GENERATION |
140 dice->owner_generation);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200141
Clemens Ladisch1b704852011-09-04 22:17:38 +0200142 if (err == 0) {
143 if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) {
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200144 dev_err(&dice->unit->device,
145 "device is already in use\n");
146 err = -EBUSY;
147 }
148 break;
149 }
Clemens Ladisch1b704852011-09-04 22:17:38 +0200150 if (err != -EAGAIN || ++errors >= 3)
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200151 break;
Clemens Ladisch1b704852011-09-04 22:17:38 +0200152
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200153 msleep(20);
154 }
155
156 kfree(buffer);
157
158 return err;
159}
160
161static int dice_owner_update(struct dice *dice)
162{
163 struct fw_device *device = fw_parent_device(dice->unit);
164 __be64 *buffer;
Clemens Ladisch1b704852011-09-04 22:17:38 +0200165 int err;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200166
167 if (dice->owner_generation == -1)
168 return 0;
169
170 buffer = kmalloc(2 * 8, GFP_KERNEL);
171 if (!buffer)
172 return -ENOMEM;
173
Clemens Ladisch1b704852011-09-04 22:17:38 +0200174 buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
175 buffer[1] = cpu_to_be64(
176 ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
177 dice->notification_handler.offset);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200178
Clemens Ladisch1b704852011-09-04 22:17:38 +0200179 dice->owner_generation = device->generation;
180 smp_rmb(); /* node_id vs. generation */
181 err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
182 global_address(dice, GLOBAL_OWNER),
183 buffer, 2 * 8,
184 FW_FIXED_GENERATION | dice->owner_generation);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200185
Clemens Ladisch1b704852011-09-04 22:17:38 +0200186 if (err == 0) {
187 if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) {
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200188 dev_err(&dice->unit->device,
Clemens Ladisch1b704852011-09-04 22:17:38 +0200189 "device is already in use\n");
190 err = -EBUSY;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200191 }
Clemens Ladisch1b704852011-09-04 22:17:38 +0200192 } else if (err == -EAGAIN) {
193 err = 0; /* try again later */
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200194 }
195
196 kfree(buffer);
197
198 if (err < 0)
199 dice->owner_generation = -1;
200
201 return err;
202}
203
204static void dice_owner_clear(struct dice *dice)
205{
206 struct fw_device *device = fw_parent_device(dice->unit);
207 __be64 *buffer;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200208
209 buffer = kmalloc(2 * 8, GFP_KERNEL);
210 if (!buffer)
211 return;
212
Clemens Ladisch1b704852011-09-04 22:17:38 +0200213 buffer[0] = cpu_to_be64(
214 ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
215 dice->notification_handler.offset);
216 buffer[1] = cpu_to_be64(OWNER_NO_OWNER);
217 snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
218 global_address(dice, GLOBAL_OWNER),
219 buffer, 2 * 8, FW_QUIET |
220 FW_FIXED_GENERATION | dice->owner_generation);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200221
222 kfree(buffer);
223
224 dice->owner_generation = -1;
225}
226
227static int dice_enable_set(struct dice *dice)
228{
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200229 __be32 value;
Clemens Ladisch1b704852011-09-04 22:17:38 +0200230 int err;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200231
Clemens Ladisch54e72f02011-09-04 22:15:54 +0200232 value = cpu_to_be32(1);
Clemens Ladisch1b704852011-09-04 22:17:38 +0200233 err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
234 global_address(dice, GLOBAL_ENABLE),
235 &value, 4,
236 FW_FIXED_GENERATION | dice->owner_generation);
237 if (err < 0)
238 return err;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200239
Clemens Ladisch1b704852011-09-04 22:17:38 +0200240 dice->global_enabled = true;
241
242 return 0;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200243}
244
245static void dice_enable_clear(struct dice *dice)
246{
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200247 __be32 value;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200248
249 value = 0;
Clemens Ladisch1b704852011-09-04 22:17:38 +0200250 snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
251 global_address(dice, GLOBAL_ENABLE),
252 &value, 4, FW_QUIET |
253 FW_FIXED_GENERATION | dice->owner_generation);
254
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200255 dice->global_enabled = false;
256}
257
258static void dice_notification(struct fw_card *card, struct fw_request *request,
259 int tcode, int destination, int source,
260 int generation, unsigned long long offset,
261 void *data, size_t length, void *callback_data)
262{
263 struct dice *dice = callback_data;
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200264 unsigned long flags;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200265
266 if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
267 fw_send_response(card, request, RCODE_TYPE_ERROR);
268 return;
269 }
270 if ((offset & 3) != 0) {
271 fw_send_response(card, request, RCODE_ADDRESS_ERROR);
272 return;
273 }
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200274 spin_lock_irqsave(&dice->lock, flags);
275 dice->notification_bits |= be32_to_cpup(data);
276 spin_unlock_irqrestore(&dice->lock, flags);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200277 fw_send_response(card, request, RCODE_COMPLETE);
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200278 wake_up(&dice->hwdep_wait);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200279}
280
281static int dice_open(struct snd_pcm_substream *substream)
282{
283 static const struct snd_pcm_hardware hardware = {
284 .info = SNDRV_PCM_INFO_MMAP |
285 SNDRV_PCM_INFO_MMAP_VALID |
286 SNDRV_PCM_INFO_BATCH |
287 SNDRV_PCM_INFO_INTERLEAVED |
288 SNDRV_PCM_INFO_BLOCK_TRANSFER,
289 .formats = AMDTP_OUT_PCM_FORMAT_BITS,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200290 .buffer_bytes_max = 16 * 1024 * 1024,
291 .period_bytes_min = 1,
292 .period_bytes_max = UINT_MAX,
293 .periods_min = 1,
294 .periods_max = UINT_MAX,
295 };
296 struct dice *dice = substream->private_data;
297 struct snd_pcm_runtime *runtime = substream->runtime;
Clemens Ladischa644a942011-09-04 22:17:31 +0200298 __be32 clock_sel, data[2];
299 unsigned int rate_index, number_audio, number_midi;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200300 int err;
301
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200302 err = dice_try_lock(dice);
303 if (err < 0)
304 goto error;
305
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200306 err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST,
Clemens Ladisch341682c2011-09-04 22:12:06 +0200307 global_address(dice, GLOBAL_CLOCK_SELECT),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200308 &clock_sel, 4, 0);
Clemens Ladisch341682c2011-09-04 22:12:06 +0200309 if (err < 0)
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200310 goto err_lock;
Clemens Ladischa7304e32011-09-04 22:16:10 +0200311 rate_index = (be32_to_cpu(clock_sel) & CLOCK_RATE_MASK)
312 >> CLOCK_RATE_SHIFT;
313 if (rate_index >= ARRAY_SIZE(dice_rates)) {
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200314 err = -ENXIO;
315 goto err_lock;
316 }
Clemens Ladisch341682c2011-09-04 22:12:06 +0200317
Clemens Ladischa644a942011-09-04 22:17:31 +0200318 err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200319 rx_address(dice, RX_NUMBER_AUDIO),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200320 data, 2 * 4, 0);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200321 if (err < 0)
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200322 goto err_lock;
Clemens Ladischa644a942011-09-04 22:17:31 +0200323 number_audio = be32_to_cpu(data[0]);
324 number_midi = be32_to_cpu(data[1]);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200325
326 runtime->hw = hardware;
Clemens Ladisch341682c2011-09-04 22:12:06 +0200327
Clemens Ladischa644a942011-09-04 22:17:31 +0200328 runtime->hw.rates = snd_pcm_rate_to_rate_bit(dice_rates[rate_index]);
Clemens Ladisch341682c2011-09-04 22:12:06 +0200329 snd_pcm_limit_hw_rates(runtime);
330
Clemens Ladischa644a942011-09-04 22:17:31 +0200331 runtime->hw.channels_min = number_audio;
332 runtime->hw.channels_max = number_audio;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200333
Clemens Ladischa644a942011-09-04 22:17:31 +0200334 amdtp_out_stream_set_parameters(&dice->stream, dice_rates[rate_index],
335 number_audio, number_midi);
Clemens Ladischa7304e32011-09-04 22:16:10 +0200336
337 err = snd_pcm_hw_constraint_step(runtime, 0,
338 SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
339 amdtp_syt_intervals[rate_index]);
340 if (err < 0)
341 goto err_lock;
342 err = snd_pcm_hw_constraint_step(runtime, 0,
343 SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
344 amdtp_syt_intervals[rate_index]);
345 if (err < 0)
346 goto err_lock;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200347
348 err = snd_pcm_hw_constraint_minmax(runtime,
349 SNDRV_PCM_HW_PARAM_PERIOD_TIME,
350 5000, 8192000);
351 if (err < 0)
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200352 goto err_lock;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200353
354 err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
355 if (err < 0)
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200356 goto err_lock;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200357
358 return 0;
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200359
360err_lock:
361 dice_unlock(dice);
362error:
363 return err;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200364}
365
366static int dice_close(struct snd_pcm_substream *substream)
367{
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200368 struct dice *dice = substream->private_data;
369
370 dice_unlock(dice);
371
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200372 return 0;
373}
374
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200375static int dice_stream_start_packets(struct dice *dice)
376{
377 int err;
378
Clemens Ladisch20b65dd2011-09-04 22:15:44 +0200379 if (amdtp_out_stream_running(&dice->stream))
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200380 return 0;
381
382 err = amdtp_out_stream_start(&dice->stream, dice->resources.channel,
383 fw_parent_device(dice->unit)->max_speed);
384 if (err < 0)
385 return err;
386
387 err = dice_enable_set(dice);
388 if (err < 0) {
389 amdtp_out_stream_stop(&dice->stream);
390 return err;
391 }
392
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200393 return 0;
394}
395
396static int dice_stream_start(struct dice *dice)
397{
398 __be32 channel;
399 int err;
400
401 if (!dice->resources.allocated) {
402 err = fw_iso_resources_allocate(&dice->resources,
403 amdtp_out_stream_get_max_payload(&dice->stream),
404 fw_parent_device(dice->unit)->max_speed);
405 if (err < 0)
406 goto error;
407
408 channel = cpu_to_be32(dice->resources.channel);
409 err = snd_fw_transaction(dice->unit,
410 TCODE_WRITE_QUADLET_REQUEST,
411 rx_address(dice, RX_ISOCHRONOUS),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200412 &channel, 4, 0);
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200413 if (err < 0)
414 goto err_resources;
415 }
416
417 err = dice_stream_start_packets(dice);
418 if (err < 0)
419 goto err_rx_channel;
420
421 return 0;
422
423err_rx_channel:
424 channel = cpu_to_be32((u32)-1);
425 snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
Clemens Ladisch1b704852011-09-04 22:17:38 +0200426 rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0);
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200427err_resources:
428 fw_iso_resources_free(&dice->resources);
429error:
430 return err;
431}
432
433static void dice_stream_stop_packets(struct dice *dice)
434{
Clemens Ladisch20b65dd2011-09-04 22:15:44 +0200435 if (amdtp_out_stream_running(&dice->stream)) {
436 dice_enable_clear(dice);
437 amdtp_out_stream_stop(&dice->stream);
438 }
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200439}
440
441static void dice_stream_stop(struct dice *dice)
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200442{
443 __be32 channel;
444
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200445 dice_stream_stop_packets(dice);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200446
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200447 if (!dice->resources.allocated)
448 return;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200449
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200450 channel = cpu_to_be32((u32)-1);
451 snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
Clemens Ladisch1b704852011-09-04 22:17:38 +0200452 rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200453
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200454 fw_iso_resources_free(&dice->resources);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200455}
456
457static int dice_hw_params(struct snd_pcm_substream *substream,
458 struct snd_pcm_hw_params *hw_params)
459{
460 struct dice *dice = substream->private_data;
461 int err;
462
463 mutex_lock(&dice->mutex);
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200464 dice_stream_stop(dice);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200465 mutex_unlock(&dice->mutex);
466
467 err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
468 params_buffer_bytes(hw_params));
469 if (err < 0)
470 goto error;
471
472 amdtp_out_stream_set_pcm_format(&dice->stream,
473 params_format(hw_params));
474
475 return 0;
476
477error:
478 return err;
479}
480
481static int dice_hw_free(struct snd_pcm_substream *substream)
482{
483 struct dice *dice = substream->private_data;
484
485 mutex_lock(&dice->mutex);
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200486 dice_stream_stop(dice);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200487 mutex_unlock(&dice->mutex);
488
489 return snd_pcm_lib_free_vmalloc_buffer(substream);
490}
491
492static int dice_prepare(struct snd_pcm_substream *substream)
493{
494 struct dice *dice = substream->private_data;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200495 int err;
496
497 mutex_lock(&dice->mutex);
498
499 if (amdtp_out_streaming_error(&dice->stream))
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200500 dice_stream_stop_packets(dice);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200501
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200502 err = dice_stream_start(dice);
503 if (err < 0) {
504 mutex_unlock(&dice->mutex);
505 return err;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200506 }
507
508 mutex_unlock(&dice->mutex);
509
510 amdtp_out_stream_pcm_prepare(&dice->stream);
511
512 return 0;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200513}
514
515static int dice_trigger(struct snd_pcm_substream *substream, int cmd)
516{
517 struct dice *dice = substream->private_data;
518 struct snd_pcm_substream *pcm;
519
520 switch (cmd) {
521 case SNDRV_PCM_TRIGGER_START:
522 pcm = substream;
523 break;
524 case SNDRV_PCM_TRIGGER_STOP:
525 pcm = NULL;
526 break;
527 default:
528 return -EINVAL;
529 }
530 amdtp_out_stream_pcm_trigger(&dice->stream, pcm);
531
532 return 0;
533}
534
535static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream)
536{
537 struct dice *dice = substream->private_data;
538
539 return amdtp_out_stream_pcm_pointer(&dice->stream);
540}
541
542static int dice_create_pcm(struct dice *dice)
543{
544 static struct snd_pcm_ops ops = {
545 .open = dice_open,
546 .close = dice_close,
547 .ioctl = snd_pcm_lib_ioctl,
548 .hw_params = dice_hw_params,
549 .hw_free = dice_hw_free,
550 .prepare = dice_prepare,
551 .trigger = dice_trigger,
552 .pointer = dice_pointer,
553 .page = snd_pcm_lib_get_vmalloc_page,
554 .mmap = snd_pcm_lib_mmap_vmalloc,
555 };
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200556 struct snd_pcm *pcm;
557 int err;
558
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200559 err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm);
560 if (err < 0)
561 return err;
562 pcm->private_data = dice;
563 strcpy(pcm->name, dice->card->shortname);
564 dice->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
565 dice->pcm->ops = &ops;
566
567 return 0;
568}
569
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200570static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf,
571 long count, loff_t *offset)
572{
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200573 struct dice *dice = hwdep->private_data;
574 DEFINE_WAIT(wait);
575 union snd_firewire_event event;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200576
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200577 spin_lock_irq(&dice->lock);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200578
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200579 while (!dice->dev_lock_changed && dice->notification_bits == 0) {
580 prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
581 spin_unlock_irq(&dice->lock);
582 schedule();
583 finish_wait(&dice->hwdep_wait, &wait);
584 if (signal_pending(current))
585 return -ERESTARTSYS;
586 spin_lock_irq(&dice->lock);
587 }
588
589 memset(&event, 0, sizeof(event));
590 if (dice->dev_lock_changed) {
591 event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
592 event.lock_status.status = dice->dev_lock_count > 0;
593 dice->dev_lock_changed = false;
594
595 count = min(count, (long)sizeof(event.lock_status));
596 } else {
597 event.dice_notification.type = SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION;
598 event.dice_notification.notification = dice->notification_bits;
599 dice->notification_bits = 0;
600
601 count = min(count, (long)sizeof(event.dice_notification));
602 }
603
604 spin_unlock_irq(&dice->lock);
605
606 if (copy_to_user(buf, &event, count))
607 return -EFAULT;
608
609 return count;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200610}
611
612static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
613 poll_table *wait)
614{
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200615 struct dice *dice = hwdep->private_data;
616 unsigned int events;
617
618 poll_wait(file, &dice->hwdep_wait, wait);
619
620 spin_lock_irq(&dice->lock);
621 if (dice->dev_lock_changed || dice->notification_bits != 0)
622 events = POLLIN | POLLRDNORM;
623 else
624 events = 0;
625 spin_unlock_irq(&dice->lock);
626
627 return events;
628}
629
630static int dice_hwdep_get_info(struct dice *dice, void __user *arg)
631{
632 struct fw_device *dev = fw_parent_device(dice->unit);
633 struct snd_firewire_get_info info;
634
635 memset(&info, 0, sizeof(info));
636 info.type = SNDRV_FIREWIRE_TYPE_DICE;
637 info.card = dev->card->index;
638 *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
639 *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
640 strlcpy(info.device_name, dev_name(&dev->device),
641 sizeof(info.device_name));
642
643 if (copy_to_user(arg, &info, sizeof(info)))
644 return -EFAULT;
645
646 return 0;
647}
648
649static int dice_hwdep_lock(struct dice *dice)
650{
651 int err;
652
653 spin_lock_irq(&dice->lock);
654
655 if (dice->dev_lock_count == 0) {
656 dice->dev_lock_count = -1;
657 err = 0;
658 } else {
659 err = -EBUSY;
660 }
661
662 spin_unlock_irq(&dice->lock);
663
664 return err;
665}
666
667static int dice_hwdep_unlock(struct dice *dice)
668{
669 int err;
670
671 spin_lock_irq(&dice->lock);
672
673 if (dice->dev_lock_count == -1) {
674 dice->dev_lock_count = 0;
675 err = 0;
676 } else {
677 err = -EBADFD;
678 }
679
680 spin_unlock_irq(&dice->lock);
681
682 return err;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200683}
684
Clemens Ladisch9dd81e32011-09-04 22:14:54 +0200685static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file)
686{
687 struct dice *dice = hwdep->private_data;
688
689 spin_lock_irq(&dice->lock);
690 if (dice->dev_lock_count == -1)
691 dice->dev_lock_count = 0;
692 spin_unlock_irq(&dice->lock);
693
694 return 0;
695}
696
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200697static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
698 unsigned int cmd, unsigned long arg)
699{
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200700 struct dice *dice = hwdep->private_data;
701
702 switch (cmd) {
703 case SNDRV_FIREWIRE_IOCTL_GET_INFO:
704 return dice_hwdep_get_info(dice, (void __user *)arg);
705 case SNDRV_FIREWIRE_IOCTL_LOCK:
706 return dice_hwdep_lock(dice);
707 case SNDRV_FIREWIRE_IOCTL_UNLOCK:
708 return dice_hwdep_unlock(dice);
709 default:
710 return -ENOIOCTLCMD;
711 }
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200712}
713
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200714#ifdef CONFIG_COMPAT
715static int dice_hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
716 unsigned int cmd, unsigned long arg)
717{
718 return dice_hwdep_ioctl(hwdep, file, cmd,
719 (unsigned long)compat_ptr(arg));
720}
721#else
722#define dice_hwdep_compat_ioctl NULL
723#endif
724
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200725static int dice_create_hwdep(struct dice *dice)
726{
727 static const struct snd_hwdep_ops ops = {
728 .read = dice_hwdep_read,
Clemens Ladisch9dd81e32011-09-04 22:14:54 +0200729 .release = dice_hwdep_release,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200730 .poll = dice_hwdep_poll,
731 .ioctl = dice_hwdep_ioctl,
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200732 .ioctl_compat = dice_hwdep_compat_ioctl,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200733 };
734 struct snd_hwdep *hwdep;
735 int err;
736
737 err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);
738 if (err < 0)
739 return err;
740 strcpy(hwdep->name, "DICE");
741 hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;
742 hwdep->ops = ops;
743 hwdep->private_data = dice;
744 hwdep->exclusive = true;
745
746 return 0;
747}
748
749static void dice_card_free(struct snd_card *card)
750{
751 struct dice *dice = card->private_data;
752
753 amdtp_out_stream_destroy(&dice->stream);
754 fw_core_remove_address_handler(&dice->notification_handler);
755 mutex_destroy(&dice->mutex);
756}
757
Clemens Ladischcbab3282011-09-04 22:16:02 +0200758#define DICE_CATEGORY_ID 0x04
759
760static int dice_interface_check(struct fw_unit *unit)
761{
762 static const int min_values[10] = {
763 10, 0x64 / 4,
764 10, 0x18 / 4,
765 10, 0x18 / 4,
766 0, 0,
767 0, 0,
768 };
769 struct fw_device *device = fw_parent_device(unit);
770 struct fw_csr_iterator it;
771 int key, value, vendor = -1, model = -1, err;
772 unsigned int i;
773 __be32 pointers[ARRAY_SIZE(min_values)];
774 __be32 version;
775
776 /*
777 * Check that GUID and unit directory are constructed according to DICE
778 * rules, i.e., that the specifier ID is the GUID's OUI, and that the
779 * GUID chip ID consists of the 8-bit DICE category ID, the 10-bit
780 * product ID, and a 22-bit serial number.
781 */
782 fw_csr_iterator_init(&it, unit->directory);
783 while (fw_csr_iterator_next(&it, &key, &value)) {
784 switch (key) {
785 case CSR_SPECIFIER_ID:
786 vendor = value;
787 break;
788 case CSR_MODEL:
789 model = value;
790 break;
791 }
792 }
793 if (device->config_rom[3] != ((vendor << 8) | DICE_CATEGORY_ID) ||
794 device->config_rom[4] >> 22 != model)
795 return -ENODEV;
796
797 /*
798 * Check that the sub address spaces exist and are located inside the
799 * private address space. The minimum values are chosen so that all
800 * minimally required registers are included.
801 */
802 err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
803 DICE_PRIVATE_SPACE,
Clemens Ladisch1b704852011-09-04 22:17:38 +0200804 pointers, sizeof(pointers), 0);
Clemens Ladischcbab3282011-09-04 22:16:02 +0200805 if (err < 0)
806 return -ENODEV;
807 for (i = 0; i < ARRAY_SIZE(pointers); ++i) {
808 value = be32_to_cpu(pointers[i]);
809 if (value < min_values[i] || value >= 0x40000)
810 return -ENODEV;
811 }
812
813 /*
814 * Check that the implemented DICE driver specification major version
815 * number matches.
816 */
817 err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
818 DICE_PRIVATE_SPACE +
819 be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
Clemens Ladisch1b704852011-09-04 22:17:38 +0200820 &version, 4, 0);
Clemens Ladischcbab3282011-09-04 22:16:02 +0200821 if (err < 0)
822 return -ENODEV;
823 if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
824 dev_err(&unit->device,
825 "unknown DICE version: 0x%08x\n", be32_to_cpu(version));
826 return -ENODEV;
827 }
828
829 return 0;
830}
831
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200832static int dice_init_offsets(struct dice *dice)
833{
834 __be32 pointers[6];
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200835 int err;
836
837 err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
Clemens Ladischcbab3282011-09-04 22:16:02 +0200838 DICE_PRIVATE_SPACE,
Clemens Ladisch1b704852011-09-04 22:17:38 +0200839 pointers, sizeof(pointers), 0);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200840 if (err < 0)
841 return err;
842
843 dice->global_offset = be32_to_cpu(pointers[0]) * 4;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200844 dice->rx_offset = be32_to_cpu(pointers[4]) * 4;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200845
846 return 0;
847}
848
849static void dice_card_strings(struct dice *dice)
850{
851 struct snd_card *card = dice->card;
852 struct fw_device *dev = fw_parent_device(dice->unit);
853 char vendor[32], model[32];
854 unsigned int i;
855 int err;
856
857 strcpy(card->driver, "DICE");
858
859 strcpy(card->shortname, "DICE");
860 BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname));
861 err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
862 global_address(dice, GLOBAL_NICK_NAME),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200863 card->shortname, sizeof(card->shortname), 0);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200864 if (err >= 0) {
865 /* DICE strings are returned in "always-wrong" endianness */
866 BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0);
867 for (i = 0; i < sizeof(card->shortname); i += 4)
868 swab32s((u32 *)&card->shortname[i]);
869 card->shortname[sizeof(card->shortname) - 1] = '\0';
870 }
871
872 strcpy(vendor, "?");
873 fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
874 strcpy(model, "?");
875 fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
876 snprintf(card->longname, sizeof(card->longname),
Clemens Ladischcbab3282011-09-04 22:16:02 +0200877 "%s %s (serial %u) at %s, S%d",
878 vendor, model, dev->config_rom[4] & 0x3fffff,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200879 dev_name(&dice->unit->device), 100 << dev->max_speed);
880
881 strcpy(card->mixername, "DICE");
882}
883
884static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
885{
886 struct snd_card *card;
887 struct dice *dice;
Clemens Ladisch341682c2011-09-04 22:12:06 +0200888 __be32 clock_sel;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200889 int err;
890
Clemens Ladischcbab3282011-09-04 22:16:02 +0200891 err = dice_interface_check(unit);
892 if (err < 0)
893 return err;
894
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200895 err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*dice), &card);
896 if (err < 0)
897 return err;
898 snd_card_set_dev(card, &unit->device);
899
900 dice = card->private_data;
901 dice->card = card;
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200902 spin_lock_init(&dice->lock);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200903 mutex_init(&dice->mutex);
904 dice->unit = unit;
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200905 init_waitqueue_head(&dice->hwdep_wait);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200906
907 err = dice_init_offsets(dice);
908 if (err < 0)
909 goto err_mutex;
910
911 dice->notification_handler.length = 4;
912 dice->notification_handler.address_callback = dice_notification;
913 dice->notification_handler.callback_data = dice;
914 err = fw_core_add_address_handler(&dice->notification_handler,
915 &fw_high_memory_region);
916 if (err < 0)
917 goto err_mutex;
918
919 err = fw_iso_resources_init(&dice->resources, unit);
920 if (err < 0)
921 goto err_notification_handler;
922 dice->resources.channels_mask = 0x00000000ffffffffuLL;
923
Clemens Ladischa7304e32011-09-04 22:16:10 +0200924 err = amdtp_out_stream_init(&dice->stream, unit,
925 CIP_BLOCKING | CIP_HI_DUALWIRE);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200926 if (err < 0)
927 goto err_resources;
928
929 err = dice_owner_set(dice);
930 if (err < 0)
931 goto err_stream;
932
933 card->private_free = dice_card_free;
934
935 dice_card_strings(dice);
936
Clemens Ladisch341682c2011-09-04 22:12:06 +0200937 err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
938 global_address(dice, GLOBAL_CLOCK_SELECT),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200939 &clock_sel, 4, 0);
Clemens Ladisch341682c2011-09-04 22:12:06 +0200940 if (err < 0)
941 goto error;
942 clock_sel &= cpu_to_be32(~CLOCK_SOURCE_MASK);
943 clock_sel |= cpu_to_be32(CLOCK_SOURCE_ARX1);
944 err = snd_fw_transaction(unit, TCODE_WRITE_QUADLET_REQUEST,
945 global_address(dice, GLOBAL_CLOCK_SELECT),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200946 &clock_sel, 4, 0);
Clemens Ladisch341682c2011-09-04 22:12:06 +0200947 if (err < 0)
948 goto error;
949
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200950 err = dice_create_pcm(dice);
951 if (err < 0)
952 goto error;
953
954 err = dice_create_hwdep(dice);
955 if (err < 0)
956 goto error;
957
958 err = snd_card_register(card);
959 if (err < 0)
960 goto error;
961
962 dev_set_drvdata(&unit->device, dice);
963
964 return 0;
965
966err_stream:
967 amdtp_out_stream_destroy(&dice->stream);
968err_resources:
969 fw_iso_resources_destroy(&dice->resources);
970err_notification_handler:
971 fw_core_remove_address_handler(&dice->notification_handler);
972err_mutex:
973 mutex_destroy(&dice->mutex);
974error:
975 snd_card_free(card);
976 return err;
977}
978
979static void dice_remove(struct fw_unit *unit)
980{
981 struct dice *dice = dev_get_drvdata(&unit->device);
982
Clemens Ladisch4ed31f202011-09-04 22:13:09 +0200983 mutex_lock(&dice->mutex);
984
985 amdtp_out_stream_pcm_abort(&dice->stream);
986
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200987 snd_card_disconnect(dice->card);
988
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200989 dice_stream_stop(dice);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200990 dice_owner_clear(dice);
Clemens Ladisch4ed31f202011-09-04 22:13:09 +0200991
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200992 mutex_unlock(&dice->mutex);
993
994 snd_card_free_when_closed(dice->card);
995}
996
997static void dice_bus_reset(struct fw_unit *unit)
998{
999 struct dice *dice = dev_get_drvdata(&unit->device);
1000
1001 mutex_lock(&dice->mutex);
Clemens Ladisch6abce9e2011-09-04 22:11:14 +02001002
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001003 /*
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001004 * On a bus reset, the DICE firmware disables streaming and then goes
1005 * off contemplating its own navel for hundreds of milliseconds before
1006 * it can react to any of our attempts to reenable streaming. This
1007 * means that we lose synchronization anyway, so we force our streams
1008 * to stop so that the application can restart them in an orderly
1009 * manner.
1010 */
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001011 amdtp_out_stream_pcm_abort(&dice->stream);
Clemens Ladisch6abce9e2011-09-04 22:11:14 +02001012 dice_stream_stop_packets(dice);
1013
1014 dice_owner_update(dice);
1015
1016 fw_iso_resources_update(&dice->resources);
1017
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001018 mutex_unlock(&dice->mutex);
1019}
1020
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001021#define DICE_INTERFACE 0x000001
1022
1023static const struct ieee1394_device_id dice_id_table[] = {
1024 {
Clemens Ladischcbab3282011-09-04 22:16:02 +02001025 .match_flags = IEEE1394_MATCH_VERSION,
1026 .version = DICE_INTERFACE,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001027 },
1028 { }
1029};
1030MODULE_DEVICE_TABLE(ieee1394, dice_id_table);
1031
1032static struct fw_driver dice_driver = {
1033 .driver = {
1034 .owner = THIS_MODULE,
1035 .name = KBUILD_MODNAME,
1036 .bus = &fw_bus_type,
1037 },
1038 .probe = dice_probe,
1039 .update = dice_bus_reset,
1040 .remove = dice_remove,
1041 .id_table = dice_id_table,
1042};
1043
1044static int __init alsa_dice_init(void)
1045{
1046 return driver_register(&dice_driver.driver);
1047}
1048
1049static void __exit alsa_dice_exit(void)
1050{
1051 driver_unregister(&dice_driver.driver);
1052}
1053
1054module_init(alsa_dice_init);
1055module_exit(alsa_dice_exit);