blob: 06fef4752d500d27e95f46a850ff3cf764287ad5 [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;
Clemens Ladischa0301992011-12-04 21:47:00 +010039 unsigned int clock_caps;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +020040 struct fw_address_handler notification_handler;
41 int owner_generation;
Clemens Ladisch0c29c912011-09-04 22:14:15 +020042 int dev_lock_count; /* > 0 driver, < 0 userspace */
43 bool dev_lock_changed;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +020044 bool global_enabled;
Clemens Ladisch0c29c912011-09-04 22:14:15 +020045 wait_queue_head_t hwdep_wait;
46 u32 notification_bits;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +020047 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
Clemens Ladischeadce072011-09-04 22:17:45 +0200249 if (!dice->global_enabled)
250 return;
251
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200252 value = 0;
Clemens Ladisch1b704852011-09-04 22:17:38 +0200253 snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
254 global_address(dice, GLOBAL_ENABLE),
255 &value, 4, FW_QUIET |
256 FW_FIXED_GENERATION | dice->owner_generation);
257
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200258 dice->global_enabled = false;
259}
260
261static void dice_notification(struct fw_card *card, struct fw_request *request,
262 int tcode, int destination, int source,
263 int generation, unsigned long long offset,
264 void *data, size_t length, void *callback_data)
265{
266 struct dice *dice = callback_data;
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200267 unsigned long flags;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200268
269 if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
270 fw_send_response(card, request, RCODE_TYPE_ERROR);
271 return;
272 }
273 if ((offset & 3) != 0) {
274 fw_send_response(card, request, RCODE_ADDRESS_ERROR);
275 return;
276 }
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200277 spin_lock_irqsave(&dice->lock, flags);
278 dice->notification_bits |= be32_to_cpup(data);
279 spin_unlock_irqrestore(&dice->lock, flags);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200280 fw_send_response(card, request, RCODE_COMPLETE);
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200281 wake_up(&dice->hwdep_wait);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200282}
283
284static int dice_open(struct snd_pcm_substream *substream)
285{
286 static const struct snd_pcm_hardware hardware = {
287 .info = SNDRV_PCM_INFO_MMAP |
288 SNDRV_PCM_INFO_MMAP_VALID |
289 SNDRV_PCM_INFO_BATCH |
290 SNDRV_PCM_INFO_INTERLEAVED |
291 SNDRV_PCM_INFO_BLOCK_TRANSFER,
292 .formats = AMDTP_OUT_PCM_FORMAT_BITS,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200293 .buffer_bytes_max = 16 * 1024 * 1024,
294 .period_bytes_min = 1,
295 .period_bytes_max = UINT_MAX,
296 .periods_min = 1,
297 .periods_max = UINT_MAX,
298 };
299 struct dice *dice = substream->private_data;
300 struct snd_pcm_runtime *runtime = substream->runtime;
Clemens Ladischa644a942011-09-04 22:17:31 +0200301 __be32 clock_sel, data[2];
302 unsigned int rate_index, number_audio, number_midi;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200303 int err;
304
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200305 err = dice_try_lock(dice);
306 if (err < 0)
307 goto error;
308
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200309 err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST,
Clemens Ladisch341682c2011-09-04 22:12:06 +0200310 global_address(dice, GLOBAL_CLOCK_SELECT),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200311 &clock_sel, 4, 0);
Clemens Ladisch341682c2011-09-04 22:12:06 +0200312 if (err < 0)
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200313 goto err_lock;
Clemens Ladischa7304e32011-09-04 22:16:10 +0200314 rate_index = (be32_to_cpu(clock_sel) & CLOCK_RATE_MASK)
315 >> CLOCK_RATE_SHIFT;
316 if (rate_index >= ARRAY_SIZE(dice_rates)) {
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200317 err = -ENXIO;
318 goto err_lock;
319 }
Clemens Ladisch341682c2011-09-04 22:12:06 +0200320
Clemens Ladischa644a942011-09-04 22:17:31 +0200321 err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200322 rx_address(dice, RX_NUMBER_AUDIO),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200323 data, 2 * 4, 0);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200324 if (err < 0)
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200325 goto err_lock;
Clemens Ladischa644a942011-09-04 22:17:31 +0200326 number_audio = be32_to_cpu(data[0]);
327 number_midi = be32_to_cpu(data[1]);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200328
329 runtime->hw = hardware;
Clemens Ladisch341682c2011-09-04 22:12:06 +0200330
Clemens Ladischa644a942011-09-04 22:17:31 +0200331 runtime->hw.rates = snd_pcm_rate_to_rate_bit(dice_rates[rate_index]);
Clemens Ladisch341682c2011-09-04 22:12:06 +0200332 snd_pcm_limit_hw_rates(runtime);
333
Clemens Ladischa644a942011-09-04 22:17:31 +0200334 runtime->hw.channels_min = number_audio;
335 runtime->hw.channels_max = number_audio;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200336
Clemens Ladischa644a942011-09-04 22:17:31 +0200337 amdtp_out_stream_set_parameters(&dice->stream, dice_rates[rate_index],
338 number_audio, number_midi);
Clemens Ladischa7304e32011-09-04 22:16:10 +0200339
340 err = snd_pcm_hw_constraint_step(runtime, 0,
341 SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
342 amdtp_syt_intervals[rate_index]);
343 if (err < 0)
344 goto err_lock;
345 err = snd_pcm_hw_constraint_step(runtime, 0,
346 SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
347 amdtp_syt_intervals[rate_index]);
348 if (err < 0)
349 goto err_lock;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200350
351 err = snd_pcm_hw_constraint_minmax(runtime,
352 SNDRV_PCM_HW_PARAM_PERIOD_TIME,
Clemens Ladisch435a9be2011-09-04 22:17:51 +0200353 5000, UINT_MAX);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200354 if (err < 0)
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200355 goto err_lock;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200356
357 err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
358 if (err < 0)
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200359 goto err_lock;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200360
361 return 0;
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200362
363err_lock:
364 dice_unlock(dice);
365error:
366 return err;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200367}
368
369static int dice_close(struct snd_pcm_substream *substream)
370{
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200371 struct dice *dice = substream->private_data;
372
373 dice_unlock(dice);
374
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200375 return 0;
376}
377
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200378static int dice_stream_start_packets(struct dice *dice)
379{
380 int err;
381
Clemens Ladisch20b65dd2011-09-04 22:15:44 +0200382 if (amdtp_out_stream_running(&dice->stream))
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200383 return 0;
384
385 err = amdtp_out_stream_start(&dice->stream, dice->resources.channel,
386 fw_parent_device(dice->unit)->max_speed);
387 if (err < 0)
388 return err;
389
390 err = dice_enable_set(dice);
391 if (err < 0) {
392 amdtp_out_stream_stop(&dice->stream);
393 return err;
394 }
395
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200396 return 0;
397}
398
399static int dice_stream_start(struct dice *dice)
400{
401 __be32 channel;
402 int err;
403
404 if (!dice->resources.allocated) {
405 err = fw_iso_resources_allocate(&dice->resources,
406 amdtp_out_stream_get_max_payload(&dice->stream),
407 fw_parent_device(dice->unit)->max_speed);
408 if (err < 0)
409 goto error;
410
411 channel = cpu_to_be32(dice->resources.channel);
412 err = snd_fw_transaction(dice->unit,
413 TCODE_WRITE_QUADLET_REQUEST,
414 rx_address(dice, RX_ISOCHRONOUS),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200415 &channel, 4, 0);
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200416 if (err < 0)
417 goto err_resources;
418 }
419
420 err = dice_stream_start_packets(dice);
421 if (err < 0)
422 goto err_rx_channel;
423
424 return 0;
425
426err_rx_channel:
427 channel = cpu_to_be32((u32)-1);
428 snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
Clemens Ladisch1b704852011-09-04 22:17:38 +0200429 rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0);
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200430err_resources:
431 fw_iso_resources_free(&dice->resources);
432error:
433 return err;
434}
435
436static void dice_stream_stop_packets(struct dice *dice)
437{
Clemens Ladisch20b65dd2011-09-04 22:15:44 +0200438 if (amdtp_out_stream_running(&dice->stream)) {
439 dice_enable_clear(dice);
440 amdtp_out_stream_stop(&dice->stream);
441 }
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200442}
443
444static void dice_stream_stop(struct dice *dice)
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200445{
446 __be32 channel;
447
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200448 dice_stream_stop_packets(dice);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200449
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200450 if (!dice->resources.allocated)
451 return;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200452
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200453 channel = cpu_to_be32((u32)-1);
454 snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
Clemens Ladisch1b704852011-09-04 22:17:38 +0200455 rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200456
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200457 fw_iso_resources_free(&dice->resources);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200458}
459
460static int dice_hw_params(struct snd_pcm_substream *substream,
461 struct snd_pcm_hw_params *hw_params)
462{
463 struct dice *dice = substream->private_data;
464 int err;
465
466 mutex_lock(&dice->mutex);
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200467 dice_stream_stop(dice);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200468 mutex_unlock(&dice->mutex);
469
470 err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
471 params_buffer_bytes(hw_params));
472 if (err < 0)
473 goto error;
474
475 amdtp_out_stream_set_pcm_format(&dice->stream,
476 params_format(hw_params));
477
478 return 0;
479
480error:
481 return err;
482}
483
484static int dice_hw_free(struct snd_pcm_substream *substream)
485{
486 struct dice *dice = substream->private_data;
487
488 mutex_lock(&dice->mutex);
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200489 dice_stream_stop(dice);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200490 mutex_unlock(&dice->mutex);
491
492 return snd_pcm_lib_free_vmalloc_buffer(substream);
493}
494
495static int dice_prepare(struct snd_pcm_substream *substream)
496{
497 struct dice *dice = substream->private_data;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200498 int err;
499
500 mutex_lock(&dice->mutex);
501
502 if (amdtp_out_streaming_error(&dice->stream))
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200503 dice_stream_stop_packets(dice);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200504
Clemens Ladisch6abce9e2011-09-04 22:11:14 +0200505 err = dice_stream_start(dice);
506 if (err < 0) {
507 mutex_unlock(&dice->mutex);
508 return err;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200509 }
510
511 mutex_unlock(&dice->mutex);
512
513 amdtp_out_stream_pcm_prepare(&dice->stream);
514
515 return 0;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200516}
517
518static int dice_trigger(struct snd_pcm_substream *substream, int cmd)
519{
520 struct dice *dice = substream->private_data;
521 struct snd_pcm_substream *pcm;
522
523 switch (cmd) {
524 case SNDRV_PCM_TRIGGER_START:
525 pcm = substream;
526 break;
527 case SNDRV_PCM_TRIGGER_STOP:
528 pcm = NULL;
529 break;
530 default:
531 return -EINVAL;
532 }
533 amdtp_out_stream_pcm_trigger(&dice->stream, pcm);
534
535 return 0;
536}
537
538static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream)
539{
540 struct dice *dice = substream->private_data;
541
542 return amdtp_out_stream_pcm_pointer(&dice->stream);
543}
544
545static int dice_create_pcm(struct dice *dice)
546{
547 static struct snd_pcm_ops ops = {
548 .open = dice_open,
549 .close = dice_close,
550 .ioctl = snd_pcm_lib_ioctl,
551 .hw_params = dice_hw_params,
552 .hw_free = dice_hw_free,
553 .prepare = dice_prepare,
554 .trigger = dice_trigger,
555 .pointer = dice_pointer,
556 .page = snd_pcm_lib_get_vmalloc_page,
557 .mmap = snd_pcm_lib_mmap_vmalloc,
558 };
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200559 struct snd_pcm *pcm;
560 int err;
561
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200562 err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm);
563 if (err < 0)
564 return err;
565 pcm->private_data = dice;
566 strcpy(pcm->name, dice->card->shortname);
Clemens Ladisch8709f1e2011-10-11 17:51:16 +0200567 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->ops = &ops;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200568
569 return 0;
570}
571
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200572static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf,
573 long count, loff_t *offset)
574{
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200575 struct dice *dice = hwdep->private_data;
576 DEFINE_WAIT(wait);
577 union snd_firewire_event event;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200578
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200579 spin_lock_irq(&dice->lock);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200580
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200581 while (!dice->dev_lock_changed && dice->notification_bits == 0) {
582 prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
583 spin_unlock_irq(&dice->lock);
584 schedule();
585 finish_wait(&dice->hwdep_wait, &wait);
586 if (signal_pending(current))
587 return -ERESTARTSYS;
588 spin_lock_irq(&dice->lock);
589 }
590
591 memset(&event, 0, sizeof(event));
592 if (dice->dev_lock_changed) {
593 event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
594 event.lock_status.status = dice->dev_lock_count > 0;
595 dice->dev_lock_changed = false;
596
597 count = min(count, (long)sizeof(event.lock_status));
598 } else {
599 event.dice_notification.type = SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION;
600 event.dice_notification.notification = dice->notification_bits;
601 dice->notification_bits = 0;
602
603 count = min(count, (long)sizeof(event.dice_notification));
604 }
605
606 spin_unlock_irq(&dice->lock);
607
608 if (copy_to_user(buf, &event, count))
609 return -EFAULT;
610
611 return count;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200612}
613
614static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
615 poll_table *wait)
616{
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200617 struct dice *dice = hwdep->private_data;
618 unsigned int events;
619
620 poll_wait(file, &dice->hwdep_wait, wait);
621
622 spin_lock_irq(&dice->lock);
623 if (dice->dev_lock_changed || dice->notification_bits != 0)
624 events = POLLIN | POLLRDNORM;
625 else
626 events = 0;
627 spin_unlock_irq(&dice->lock);
628
629 return events;
630}
631
632static int dice_hwdep_get_info(struct dice *dice, void __user *arg)
633{
634 struct fw_device *dev = fw_parent_device(dice->unit);
635 struct snd_firewire_get_info info;
636
637 memset(&info, 0, sizeof(info));
638 info.type = SNDRV_FIREWIRE_TYPE_DICE;
639 info.card = dev->card->index;
640 *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
641 *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
642 strlcpy(info.device_name, dev_name(&dev->device),
643 sizeof(info.device_name));
644
645 if (copy_to_user(arg, &info, sizeof(info)))
646 return -EFAULT;
647
648 return 0;
649}
650
651static int dice_hwdep_lock(struct dice *dice)
652{
653 int err;
654
655 spin_lock_irq(&dice->lock);
656
657 if (dice->dev_lock_count == 0) {
658 dice->dev_lock_count = -1;
659 err = 0;
660 } else {
661 err = -EBUSY;
662 }
663
664 spin_unlock_irq(&dice->lock);
665
666 return err;
667}
668
669static int dice_hwdep_unlock(struct dice *dice)
670{
671 int err;
672
673 spin_lock_irq(&dice->lock);
674
675 if (dice->dev_lock_count == -1) {
676 dice->dev_lock_count = 0;
677 err = 0;
678 } else {
679 err = -EBADFD;
680 }
681
682 spin_unlock_irq(&dice->lock);
683
684 return err;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200685}
686
Clemens Ladisch9dd81e32011-09-04 22:14:54 +0200687static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file)
688{
689 struct dice *dice = hwdep->private_data;
690
691 spin_lock_irq(&dice->lock);
692 if (dice->dev_lock_count == -1)
693 dice->dev_lock_count = 0;
694 spin_unlock_irq(&dice->lock);
695
696 return 0;
697}
698
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200699static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
700 unsigned int cmd, unsigned long arg)
701{
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200702 struct dice *dice = hwdep->private_data;
703
704 switch (cmd) {
705 case SNDRV_FIREWIRE_IOCTL_GET_INFO:
706 return dice_hwdep_get_info(dice, (void __user *)arg);
707 case SNDRV_FIREWIRE_IOCTL_LOCK:
708 return dice_hwdep_lock(dice);
709 case SNDRV_FIREWIRE_IOCTL_UNLOCK:
710 return dice_hwdep_unlock(dice);
711 default:
712 return -ENOIOCTLCMD;
713 }
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200714}
715
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200716#ifdef CONFIG_COMPAT
717static int dice_hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
718 unsigned int cmd, unsigned long arg)
719{
720 return dice_hwdep_ioctl(hwdep, file, cmd,
721 (unsigned long)compat_ptr(arg));
722}
723#else
724#define dice_hwdep_compat_ioctl NULL
725#endif
726
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200727static int dice_create_hwdep(struct dice *dice)
728{
729 static const struct snd_hwdep_ops ops = {
730 .read = dice_hwdep_read,
Clemens Ladisch9dd81e32011-09-04 22:14:54 +0200731 .release = dice_hwdep_release,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200732 .poll = dice_hwdep_poll,
733 .ioctl = dice_hwdep_ioctl,
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200734 .ioctl_compat = dice_hwdep_compat_ioctl,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200735 };
736 struct snd_hwdep *hwdep;
737 int err;
738
739 err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);
740 if (err < 0)
741 return err;
742 strcpy(hwdep->name, "DICE");
743 hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;
744 hwdep->ops = ops;
745 hwdep->private_data = dice;
746 hwdep->exclusive = true;
747
748 return 0;
749}
750
751static void dice_card_free(struct snd_card *card)
752{
753 struct dice *dice = card->private_data;
754
755 amdtp_out_stream_destroy(&dice->stream);
756 fw_core_remove_address_handler(&dice->notification_handler);
757 mutex_destroy(&dice->mutex);
758}
759
Clemens Ladischcbab3282011-09-04 22:16:02 +0200760#define DICE_CATEGORY_ID 0x04
761
762static int dice_interface_check(struct fw_unit *unit)
763{
764 static const int min_values[10] = {
765 10, 0x64 / 4,
766 10, 0x18 / 4,
767 10, 0x18 / 4,
768 0, 0,
769 0, 0,
770 };
771 struct fw_device *device = fw_parent_device(unit);
772 struct fw_csr_iterator it;
773 int key, value, vendor = -1, model = -1, err;
774 unsigned int i;
775 __be32 pointers[ARRAY_SIZE(min_values)];
776 __be32 version;
777
778 /*
779 * Check that GUID and unit directory are constructed according to DICE
780 * rules, i.e., that the specifier ID is the GUID's OUI, and that the
781 * GUID chip ID consists of the 8-bit DICE category ID, the 10-bit
782 * product ID, and a 22-bit serial number.
783 */
784 fw_csr_iterator_init(&it, unit->directory);
785 while (fw_csr_iterator_next(&it, &key, &value)) {
786 switch (key) {
787 case CSR_SPECIFIER_ID:
788 vendor = value;
789 break;
790 case CSR_MODEL:
791 model = value;
792 break;
793 }
794 }
795 if (device->config_rom[3] != ((vendor << 8) | DICE_CATEGORY_ID) ||
796 device->config_rom[4] >> 22 != model)
797 return -ENODEV;
798
799 /*
800 * Check that the sub address spaces exist and are located inside the
801 * private address space. The minimum values are chosen so that all
802 * minimally required registers are included.
803 */
804 err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
805 DICE_PRIVATE_SPACE,
Clemens Ladisch1b704852011-09-04 22:17:38 +0200806 pointers, sizeof(pointers), 0);
Clemens Ladischcbab3282011-09-04 22:16:02 +0200807 if (err < 0)
808 return -ENODEV;
809 for (i = 0; i < ARRAY_SIZE(pointers); ++i) {
810 value = be32_to_cpu(pointers[i]);
811 if (value < min_values[i] || value >= 0x40000)
812 return -ENODEV;
813 }
814
815 /*
816 * Check that the implemented DICE driver specification major version
817 * number matches.
818 */
819 err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
820 DICE_PRIVATE_SPACE +
821 be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
Clemens Ladisch1b704852011-09-04 22:17:38 +0200822 &version, 4, 0);
Clemens Ladischcbab3282011-09-04 22:16:02 +0200823 if (err < 0)
824 return -ENODEV;
825 if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
826 dev_err(&unit->device,
827 "unknown DICE version: 0x%08x\n", be32_to_cpu(version));
828 return -ENODEV;
829 }
830
831 return 0;
832}
833
Clemens Ladischa0301992011-12-04 21:47:00 +0100834static int dice_read_params(struct dice *dice)
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200835{
836 __be32 pointers[6];
Clemens Ladischa0301992011-12-04 21:47:00 +0100837 __be32 value;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200838 int err;
839
840 err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
Clemens Ladischcbab3282011-09-04 22:16:02 +0200841 DICE_PRIVATE_SPACE,
Clemens Ladisch1b704852011-09-04 22:17:38 +0200842 pointers, sizeof(pointers), 0);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200843 if (err < 0)
844 return err;
845
846 dice->global_offset = be32_to_cpu(pointers[0]) * 4;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200847 dice->rx_offset = be32_to_cpu(pointers[4]) * 4;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200848
Clemens Ladischa0301992011-12-04 21:47:00 +0100849 /* some very old firmwares don't tell about their clock support */
850 if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4) {
851 err = snd_fw_transaction(
852 dice->unit, TCODE_READ_QUADLET_REQUEST,
853 global_address(dice, GLOBAL_CLOCK_CAPABILITIES),
854 &value, 4, 0);
855 if (err < 0)
856 return err;
857 dice->clock_caps = be32_to_cpu(value);
858 } else {
859 /* this should be supported by any device */
860 dice->clock_caps = CLOCK_CAP_RATE_44100 |
861 CLOCK_CAP_RATE_48000 |
862 CLOCK_CAP_SOURCE_ARX1 |
863 CLOCK_CAP_SOURCE_INTERNAL;
864 }
865
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200866 return 0;
867}
868
869static void dice_card_strings(struct dice *dice)
870{
871 struct snd_card *card = dice->card;
872 struct fw_device *dev = fw_parent_device(dice->unit);
873 char vendor[32], model[32];
874 unsigned int i;
875 int err;
876
877 strcpy(card->driver, "DICE");
878
879 strcpy(card->shortname, "DICE");
880 BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname));
881 err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
882 global_address(dice, GLOBAL_NICK_NAME),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200883 card->shortname, sizeof(card->shortname), 0);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200884 if (err >= 0) {
885 /* DICE strings are returned in "always-wrong" endianness */
886 BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0);
887 for (i = 0; i < sizeof(card->shortname); i += 4)
888 swab32s((u32 *)&card->shortname[i]);
889 card->shortname[sizeof(card->shortname) - 1] = '\0';
890 }
891
892 strcpy(vendor, "?");
893 fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
894 strcpy(model, "?");
895 fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
896 snprintf(card->longname, sizeof(card->longname),
Clemens Ladischcbab3282011-09-04 22:16:02 +0200897 "%s %s (serial %u) at %s, S%d",
898 vendor, model, dev->config_rom[4] & 0x3fffff,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200899 dev_name(&dice->unit->device), 100 << dev->max_speed);
900
901 strcpy(card->mixername, "DICE");
902}
903
904static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
905{
906 struct snd_card *card;
907 struct dice *dice;
Clemens Ladisch341682c2011-09-04 22:12:06 +0200908 __be32 clock_sel;
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200909 int err;
910
Clemens Ladischcbab3282011-09-04 22:16:02 +0200911 err = dice_interface_check(unit);
912 if (err < 0)
913 return err;
914
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200915 err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*dice), &card);
916 if (err < 0)
917 return err;
918 snd_card_set_dev(card, &unit->device);
919
920 dice = card->private_data;
921 dice->card = card;
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200922 spin_lock_init(&dice->lock);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200923 mutex_init(&dice->mutex);
924 dice->unit = unit;
Clemens Ladisch0c29c912011-09-04 22:14:15 +0200925 init_waitqueue_head(&dice->hwdep_wait);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200926
Clemens Ladischa0301992011-12-04 21:47:00 +0100927 err = dice_read_params(dice);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200928 if (err < 0)
929 goto err_mutex;
930
931 dice->notification_handler.length = 4;
932 dice->notification_handler.address_callback = dice_notification;
933 dice->notification_handler.callback_data = dice;
934 err = fw_core_add_address_handler(&dice->notification_handler,
935 &fw_high_memory_region);
936 if (err < 0)
937 goto err_mutex;
938
939 err = fw_iso_resources_init(&dice->resources, unit);
940 if (err < 0)
941 goto err_notification_handler;
942 dice->resources.channels_mask = 0x00000000ffffffffuLL;
943
Clemens Ladischa7304e32011-09-04 22:16:10 +0200944 err = amdtp_out_stream_init(&dice->stream, unit,
945 CIP_BLOCKING | CIP_HI_DUALWIRE);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200946 if (err < 0)
947 goto err_resources;
948
949 err = dice_owner_set(dice);
950 if (err < 0)
951 goto err_stream;
952
953 card->private_free = dice_card_free;
954
955 dice_card_strings(dice);
956
Clemens Ladisch341682c2011-09-04 22:12:06 +0200957 err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
958 global_address(dice, GLOBAL_CLOCK_SELECT),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200959 &clock_sel, 4, 0);
Clemens Ladisch341682c2011-09-04 22:12:06 +0200960 if (err < 0)
961 goto error;
962 clock_sel &= cpu_to_be32(~CLOCK_SOURCE_MASK);
963 clock_sel |= cpu_to_be32(CLOCK_SOURCE_ARX1);
964 err = snd_fw_transaction(unit, TCODE_WRITE_QUADLET_REQUEST,
965 global_address(dice, GLOBAL_CLOCK_SELECT),
Clemens Ladisch1b704852011-09-04 22:17:38 +0200966 &clock_sel, 4, 0);
Clemens Ladisch341682c2011-09-04 22:12:06 +0200967 if (err < 0)
968 goto error;
969
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +0200970 err = dice_create_pcm(dice);
971 if (err < 0)
972 goto error;
973
974 err = dice_create_hwdep(dice);
975 if (err < 0)
976 goto error;
977
978 err = snd_card_register(card);
979 if (err < 0)
980 goto error;
981
982 dev_set_drvdata(&unit->device, dice);
983
984 return 0;
985
986err_stream:
987 amdtp_out_stream_destroy(&dice->stream);
988err_resources:
989 fw_iso_resources_destroy(&dice->resources);
990err_notification_handler:
991 fw_core_remove_address_handler(&dice->notification_handler);
992err_mutex:
993 mutex_destroy(&dice->mutex);
994error:
995 snd_card_free(card);
996 return err;
997}
998
999static void dice_remove(struct fw_unit *unit)
1000{
1001 struct dice *dice = dev_get_drvdata(&unit->device);
1002
Clemens Ladisch4ed31f202011-09-04 22:13:09 +02001003 amdtp_out_stream_pcm_abort(&dice->stream);
1004
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001005 snd_card_disconnect(dice->card);
1006
Stefan Richtera8c558f2011-08-27 20:05:15 +02001007 mutex_lock(&dice->mutex);
1008
Clemens Ladisch6abce9e2011-09-04 22:11:14 +02001009 dice_stream_stop(dice);
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001010 dice_owner_clear(dice);
Clemens Ladisch4ed31f202011-09-04 22:13:09 +02001011
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001012 mutex_unlock(&dice->mutex);
1013
1014 snd_card_free_when_closed(dice->card);
1015}
1016
1017static void dice_bus_reset(struct fw_unit *unit)
1018{
1019 struct dice *dice = dev_get_drvdata(&unit->device);
1020
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001021 /*
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001022 * On a bus reset, the DICE firmware disables streaming and then goes
1023 * off contemplating its own navel for hundreds of milliseconds before
1024 * it can react to any of our attempts to reenable streaming. This
1025 * means that we lose synchronization anyway, so we force our streams
1026 * to stop so that the application can restart them in an orderly
1027 * manner.
1028 */
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001029 amdtp_out_stream_pcm_abort(&dice->stream);
Clemens Ladischeadce072011-09-04 22:17:45 +02001030
Stefan Richtera8c558f2011-08-27 20:05:15 +02001031 mutex_lock(&dice->mutex);
1032
Clemens Ladischeadce072011-09-04 22:17:45 +02001033 dice->global_enabled = false;
Clemens Ladisch6abce9e2011-09-04 22:11:14 +02001034 dice_stream_stop_packets(dice);
1035
1036 dice_owner_update(dice);
1037
1038 fw_iso_resources_update(&dice->resources);
1039
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001040 mutex_unlock(&dice->mutex);
1041}
1042
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001043#define DICE_INTERFACE 0x000001
1044
1045static const struct ieee1394_device_id dice_id_table[] = {
1046 {
Clemens Ladischcbab3282011-09-04 22:16:02 +02001047 .match_flags = IEEE1394_MATCH_VERSION,
1048 .version = DICE_INTERFACE,
Clemens Ladisch82fbb4f2011-09-04 22:04:49 +02001049 },
1050 { }
1051};
1052MODULE_DEVICE_TABLE(ieee1394, dice_id_table);
1053
1054static struct fw_driver dice_driver = {
1055 .driver = {
1056 .owner = THIS_MODULE,
1057 .name = KBUILD_MODNAME,
1058 .bus = &fw_bus_type,
1059 },
1060 .probe = dice_probe,
1061 .update = dice_bus_reset,
1062 .remove = dice_remove,
1063 .id_table = dice_id_table,
1064};
1065
1066static int __init alsa_dice_init(void)
1067{
1068 return driver_register(&dice_driver.driver);
1069}
1070
1071static void __exit alsa_dice_exit(void)
1072{
1073 driver_unregister(&dice_driver.driver);
1074}
1075
1076module_init(alsa_dice_init);
1077module_exit(alsa_dice_exit);