Commit | Line | Data |
---|---|---|
82fbb4f7 CL |
1 | /* |
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 | ||
7c2d4c0c | 8 | #include "dice.h" |
82fbb4f7 CL |
9 | |
10 | MODULE_DESCRIPTION("DICE driver"); | |
11 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | |
12 | MODULE_LICENSE("GPL v2"); | |
13 | ||
4edeb831 CL |
14 | static int dice_rate_constraint(struct snd_pcm_hw_params *params, |
15 | struct snd_pcm_hw_rule *rule) | |
16 | { | |
732d153f | 17 | struct snd_dice *dice = rule->private; |
6eb6c81e TS |
18 | |
19 | const struct snd_interval *c = | |
4edeb831 | 20 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
6eb6c81e | 21 | struct snd_interval *r = |
4edeb831 | 22 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
6eb6c81e | 23 | struct snd_interval rates = { |
4edeb831 CL |
24 | .min = UINT_MAX, .max = 0, .integer = 1 |
25 | }; | |
6eb6c81e | 26 | unsigned int i, rate, mode, *pcm_channels = dice->rx_channels; |
4edeb831 | 27 | |
7c2d4c0c | 28 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { |
6eb6c81e TS |
29 | rate = snd_dice_rates[i]; |
30 | if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) | |
31 | continue; | |
32 | ||
33 | if (!snd_interval_test(c, pcm_channels[mode])) | |
34 | continue; | |
35 | ||
36 | rates.min = min(rates.min, rate); | |
37 | rates.max = max(rates.max, rate); | |
4edeb831 CL |
38 | } |
39 | ||
6eb6c81e | 40 | return snd_interval_refine(r, &rates); |
4edeb831 CL |
41 | } |
42 | ||
43 | static int dice_channels_constraint(struct snd_pcm_hw_params *params, | |
44 | struct snd_pcm_hw_rule *rule) | |
45 | { | |
732d153f | 46 | struct snd_dice *dice = rule->private; |
6eb6c81e TS |
47 | |
48 | const struct snd_interval *r = | |
4edeb831 | 49 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); |
6eb6c81e | 50 | struct snd_interval *c = |
4edeb831 | 51 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
6eb6c81e | 52 | struct snd_interval channels = { |
4edeb831 CL |
53 | .min = UINT_MAX, .max = 0, .integer = 1 |
54 | }; | |
6eb6c81e | 55 | unsigned int i, rate, mode, *pcm_channels = dice->rx_channels; |
4edeb831 | 56 | |
6eb6c81e TS |
57 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { |
58 | rate = snd_dice_rates[i]; | |
59 | if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) | |
60 | continue; | |
4edeb831 | 61 | |
6eb6c81e TS |
62 | if (!snd_interval_test(r, rate)) |
63 | continue; | |
64 | ||
65 | channels.min = min(channels.min, pcm_channels[mode]); | |
66 | channels.max = max(channels.max, pcm_channels[mode]); | |
67 | } | |
68 | ||
69 | return snd_interval_refine(c, &channels); | |
4edeb831 CL |
70 | } |
71 | ||
82fbb4f7 CL |
72 | static int dice_open(struct snd_pcm_substream *substream) |
73 | { | |
74 | static const struct snd_pcm_hardware hardware = { | |
75 | .info = SNDRV_PCM_INFO_MMAP | | |
76 | SNDRV_PCM_INFO_MMAP_VALID | | |
77 | SNDRV_PCM_INFO_BATCH | | |
78 | SNDRV_PCM_INFO_INTERLEAVED | | |
79 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | |
80 | .formats = AMDTP_OUT_PCM_FORMAT_BITS, | |
4edeb831 CL |
81 | .channels_min = UINT_MAX, |
82 | .channels_max = 0, | |
82fbb4f7 CL |
83 | .buffer_bytes_max = 16 * 1024 * 1024, |
84 | .period_bytes_min = 1, | |
85 | .period_bytes_max = UINT_MAX, | |
86 | .periods_min = 1, | |
87 | .periods_max = UINT_MAX, | |
88 | }; | |
732d153f | 89 | struct snd_dice *dice = substream->private_data; |
82fbb4f7 | 90 | struct snd_pcm_runtime *runtime = substream->runtime; |
4edeb831 | 91 | unsigned int i; |
82fbb4f7 CL |
92 | int err; |
93 | ||
6eb6c81e | 94 | err = snd_dice_stream_lock_try(dice); |
0c29c918 CL |
95 | if (err < 0) |
96 | goto error; | |
97 | ||
82fbb4f7 | 98 | runtime->hw = hardware; |
341682cd | 99 | |
7c2d4c0c | 100 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) |
4edeb831 CL |
101 | if (dice->clock_caps & (1 << i)) |
102 | runtime->hw.rates |= | |
7c2d4c0c | 103 | snd_pcm_rate_to_rate_bit(snd_dice_rates[i]); |
341682cd CL |
104 | snd_pcm_limit_hw_rates(runtime); |
105 | ||
4edeb831 CL |
106 | for (i = 0; i < 3; ++i) |
107 | if (dice->rx_channels[i]) { | |
108 | runtime->hw.channels_min = min(runtime->hw.channels_min, | |
109 | dice->rx_channels[i]); | |
110 | runtime->hw.channels_max = max(runtime->hw.channels_max, | |
111 | dice->rx_channels[i]); | |
112 | } | |
82fbb4f7 | 113 | |
4edeb831 CL |
114 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
115 | dice_rate_constraint, dice, | |
116 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | |
117 | if (err < 0) | |
118 | goto err_lock; | |
119 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | |
120 | dice_channels_constraint, dice, | |
121 | SNDRV_PCM_HW_PARAM_RATE, -1); | |
122 | if (err < 0) | |
123 | goto err_lock; | |
a7304e3b | 124 | |
732d153f | 125 | err = amdtp_stream_add_pcm_hw_constraints(&dice->rx_stream, runtime); |
82fbb4f7 | 126 | if (err < 0) |
0c29c918 | 127 | goto err_lock; |
82fbb4f7 CL |
128 | |
129 | return 0; | |
0c29c918 CL |
130 | |
131 | err_lock: | |
6eb6c81e | 132 | snd_dice_stream_lock_release(dice); |
0c29c918 CL |
133 | error: |
134 | return err; | |
82fbb4f7 CL |
135 | } |
136 | ||
137 | static int dice_close(struct snd_pcm_substream *substream) | |
138 | { | |
732d153f | 139 | struct snd_dice *dice = substream->private_data; |
0c29c918 | 140 | |
6eb6c81e | 141 | snd_dice_stream_lock_release(dice); |
0c29c918 | 142 | |
82fbb4f7 CL |
143 | return 0; |
144 | } | |
145 | ||
82fbb4f7 CL |
146 | static int dice_hw_params(struct snd_pcm_substream *substream, |
147 | struct snd_pcm_hw_params *hw_params) | |
148 | { | |
732d153f | 149 | struct snd_dice *dice = substream->private_data; |
6eb6c81e | 150 | unsigned int mode, rate, channels, i; |
82fbb4f7 CL |
151 | int err; |
152 | ||
153 | mutex_lock(&dice->mutex); | |
6eb6c81e | 154 | snd_dice_stream_stop(dice); |
82fbb4f7 CL |
155 | mutex_unlock(&dice->mutex); |
156 | ||
157 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, | |
158 | params_buffer_bytes(hw_params)); | |
159 | if (err < 0) | |
4edeb831 CL |
160 | return err; |
161 | ||
10550bea | 162 | rate = params_rate(hw_params); |
7c2d4c0c | 163 | err = snd_dice_transaction_set_rate(dice, rate); |
4edeb831 CL |
164 | if (err < 0) |
165 | return err; | |
82fbb4f7 | 166 | |
6eb6c81e TS |
167 | err = snd_dice_stream_get_rate_mode(dice, rate, &mode); |
168 | if (err < 0) | |
169 | return err; | |
170 | ||
10550bea | 171 | /* |
65845f29 TS |
172 | * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in |
173 | * one data block of AMDTP packet. Thus sampling transfer frequency is | |
174 | * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are | |
175 | * transferred on AMDTP packets at 96 kHz. Two successive samples of a | |
176 | * channel are stored consecutively in the packet. This quirk is called | |
177 | * as 'Dual Wire'. | |
178 | * For this quirk, blocking mode is required and PCM buffer size should | |
179 | * be aligned to SYT_INTERVAL. | |
10550bea TS |
180 | */ |
181 | channels = params_channels(hw_params); | |
6eb6c81e | 182 | if (mode > 1) { |
10550bea TS |
183 | if (channels > AMDTP_MAX_CHANNELS_FOR_PCM / 2) { |
184 | err = -ENOSYS; | |
185 | return err; | |
186 | } | |
187 | ||
10550bea TS |
188 | rate /= 2; |
189 | channels *= 2; | |
732d153f | 190 | dice->rx_stream.double_pcm_frames = true; |
65845f29 | 191 | } else { |
732d153f | 192 | dice->rx_stream.double_pcm_frames = false; |
10550bea TS |
193 | } |
194 | ||
732d153f | 195 | amdtp_stream_set_parameters(&dice->rx_stream, rate, channels, |
be4a2894 | 196 | dice->rx_midi_ports[mode]); |
6eb6c81e | 197 | if (mode > 4) { |
1033eb5b TS |
198 | channels /= 2; |
199 | ||
200 | for (i = 0; i < channels; i++) { | |
732d153f TS |
201 | dice->rx_stream.pcm_positions[i] = i * 2; |
202 | dice->rx_stream.pcm_positions[i + channels] = i * 2 + 1; | |
1033eb5b TS |
203 | } |
204 | } | |
205 | ||
732d153f | 206 | amdtp_stream_set_pcm_format(&dice->rx_stream, |
be4a2894 | 207 | params_format(hw_params)); |
82fbb4f7 CL |
208 | |
209 | return 0; | |
82fbb4f7 CL |
210 | } |
211 | ||
212 | static int dice_hw_free(struct snd_pcm_substream *substream) | |
213 | { | |
732d153f | 214 | struct snd_dice *dice = substream->private_data; |
82fbb4f7 CL |
215 | |
216 | mutex_lock(&dice->mutex); | |
6eb6c81e | 217 | snd_dice_stream_stop(dice); |
82fbb4f7 CL |
218 | mutex_unlock(&dice->mutex); |
219 | ||
220 | return snd_pcm_lib_free_vmalloc_buffer(substream); | |
221 | } | |
222 | ||
223 | static int dice_prepare(struct snd_pcm_substream *substream) | |
224 | { | |
732d153f | 225 | struct snd_dice *dice = substream->private_data; |
82fbb4f7 CL |
226 | int err; |
227 | ||
228 | mutex_lock(&dice->mutex); | |
229 | ||
732d153f | 230 | if (amdtp_streaming_error(&dice->rx_stream)) |
6eb6c81e | 231 | snd_dice_stream_stop_packets(dice); |
82fbb4f7 | 232 | |
6eb6c81e | 233 | err = snd_dice_stream_start(dice); |
6abce9e6 CL |
234 | if (err < 0) { |
235 | mutex_unlock(&dice->mutex); | |
236 | return err; | |
82fbb4f7 CL |
237 | } |
238 | ||
239 | mutex_unlock(&dice->mutex); | |
240 | ||
732d153f | 241 | amdtp_stream_pcm_prepare(&dice->rx_stream); |
82fbb4f7 CL |
242 | |
243 | return 0; | |
82fbb4f7 CL |
244 | } |
245 | ||
246 | static int dice_trigger(struct snd_pcm_substream *substream, int cmd) | |
247 | { | |
732d153f | 248 | struct snd_dice *dice = substream->private_data; |
82fbb4f7 CL |
249 | struct snd_pcm_substream *pcm; |
250 | ||
251 | switch (cmd) { | |
252 | case SNDRV_PCM_TRIGGER_START: | |
253 | pcm = substream; | |
254 | break; | |
255 | case SNDRV_PCM_TRIGGER_STOP: | |
256 | pcm = NULL; | |
257 | break; | |
258 | default: | |
259 | return -EINVAL; | |
260 | } | |
732d153f | 261 | amdtp_stream_pcm_trigger(&dice->rx_stream, pcm); |
82fbb4f7 CL |
262 | |
263 | return 0; | |
264 | } | |
265 | ||
266 | static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream) | |
267 | { | |
732d153f | 268 | struct snd_dice *dice = substream->private_data; |
82fbb4f7 | 269 | |
732d153f | 270 | return amdtp_stream_pcm_pointer(&dice->rx_stream); |
82fbb4f7 CL |
271 | } |
272 | ||
732d153f | 273 | static int dice_create_pcm(struct snd_dice *dice) |
82fbb4f7 CL |
274 | { |
275 | static struct snd_pcm_ops ops = { | |
276 | .open = dice_open, | |
277 | .close = dice_close, | |
278 | .ioctl = snd_pcm_lib_ioctl, | |
279 | .hw_params = dice_hw_params, | |
280 | .hw_free = dice_hw_free, | |
281 | .prepare = dice_prepare, | |
282 | .trigger = dice_trigger, | |
283 | .pointer = dice_pointer, | |
284 | .page = snd_pcm_lib_get_vmalloc_page, | |
285 | .mmap = snd_pcm_lib_mmap_vmalloc, | |
286 | }; | |
82fbb4f7 CL |
287 | struct snd_pcm *pcm; |
288 | int err; | |
289 | ||
82fbb4f7 CL |
290 | err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm); |
291 | if (err < 0) | |
292 | return err; | |
293 | pcm->private_data = dice; | |
294 | strcpy(pcm->name, dice->card->shortname); | |
8709f1e4 | 295 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->ops = &ops; |
82fbb4f7 CL |
296 | |
297 | return 0; | |
298 | } | |
299 | ||
82fbb4f7 CL |
300 | static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, |
301 | long count, loff_t *offset) | |
302 | { | |
732d153f | 303 | struct snd_dice *dice = hwdep->private_data; |
0c29c918 CL |
304 | DEFINE_WAIT(wait); |
305 | union snd_firewire_event event; | |
306 | ||
307 | spin_lock_irq(&dice->lock); | |
308 | ||
309 | while (!dice->dev_lock_changed && dice->notification_bits == 0) { | |
310 | prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE); | |
311 | spin_unlock_irq(&dice->lock); | |
312 | schedule(); | |
313 | finish_wait(&dice->hwdep_wait, &wait); | |
314 | if (signal_pending(current)) | |
315 | return -ERESTARTSYS; | |
316 | spin_lock_irq(&dice->lock); | |
317 | } | |
318 | ||
319 | memset(&event, 0, sizeof(event)); | |
320 | if (dice->dev_lock_changed) { | |
321 | event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; | |
322 | event.lock_status.status = dice->dev_lock_count > 0; | |
323 | dice->dev_lock_changed = false; | |
324 | ||
81fc5ad5 | 325 | count = min_t(long, count, sizeof(event.lock_status)); |
0c29c918 | 326 | } else { |
81fc5ad5 TS |
327 | event.dice_notification.type = |
328 | SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION; | |
0c29c918 CL |
329 | event.dice_notification.notification = dice->notification_bits; |
330 | dice->notification_bits = 0; | |
331 | ||
81fc5ad5 | 332 | count = min_t(long, count, sizeof(event.dice_notification)); |
0c29c918 CL |
333 | } |
334 | ||
335 | spin_unlock_irq(&dice->lock); | |
336 | ||
337 | if (copy_to_user(buf, &event, count)) | |
338 | return -EFAULT; | |
339 | ||
340 | return count; | |
82fbb4f7 CL |
341 | } |
342 | ||
0c29c918 CL |
343 | static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file, |
344 | poll_table *wait) | |
82fbb4f7 | 345 | { |
732d153f | 346 | struct snd_dice *dice = hwdep->private_data; |
0c29c918 CL |
347 | unsigned int events; |
348 | ||
349 | poll_wait(file, &dice->hwdep_wait, wait); | |
350 | ||
351 | spin_lock_irq(&dice->lock); | |
352 | if (dice->dev_lock_changed || dice->notification_bits != 0) | |
353 | events = POLLIN | POLLRDNORM; | |
354 | else | |
355 | events = 0; | |
356 | spin_unlock_irq(&dice->lock); | |
357 | ||
358 | return events; | |
82fbb4f7 CL |
359 | } |
360 | ||
732d153f | 361 | static int dice_hwdep_get_info(struct snd_dice *dice, void __user *arg) |
82fbb4f7 | 362 | { |
0c29c918 CL |
363 | struct fw_device *dev = fw_parent_device(dice->unit); |
364 | struct snd_firewire_get_info info; | |
365 | ||
366 | memset(&info, 0, sizeof(info)); | |
367 | info.type = SNDRV_FIREWIRE_TYPE_DICE; | |
368 | info.card = dev->card->index; | |
369 | *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); | |
370 | *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); | |
371 | strlcpy(info.device_name, dev_name(&dev->device), | |
372 | sizeof(info.device_name)); | |
373 | ||
374 | if (copy_to_user(arg, &info, sizeof(info))) | |
375 | return -EFAULT; | |
376 | ||
82fbb4f7 CL |
377 | return 0; |
378 | } | |
379 | ||
732d153f | 380 | static int dice_hwdep_lock(struct snd_dice *dice) |
0c29c918 CL |
381 | { |
382 | int err; | |
383 | ||
384 | spin_lock_irq(&dice->lock); | |
385 | ||
386 | if (dice->dev_lock_count == 0) { | |
387 | dice->dev_lock_count = -1; | |
388 | err = 0; | |
389 | } else { | |
390 | err = -EBUSY; | |
391 | } | |
392 | ||
393 | spin_unlock_irq(&dice->lock); | |
394 | ||
395 | return err; | |
396 | } | |
397 | ||
732d153f | 398 | static int dice_hwdep_unlock(struct snd_dice *dice) |
82fbb4f7 | 399 | { |
0c29c918 CL |
400 | int err; |
401 | ||
402 | spin_lock_irq(&dice->lock); | |
403 | ||
404 | if (dice->dev_lock_count == -1) { | |
405 | dice->dev_lock_count = 0; | |
406 | err = 0; | |
407 | } else { | |
408 | err = -EBADFD; | |
409 | } | |
410 | ||
411 | spin_unlock_irq(&dice->lock); | |
412 | ||
413 | return err; | |
82fbb4f7 CL |
414 | } |
415 | ||
9dd81e31 CL |
416 | static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file) |
417 | { | |
732d153f | 418 | struct snd_dice *dice = hwdep->private_data; |
9dd81e31 CL |
419 | |
420 | spin_lock_irq(&dice->lock); | |
421 | if (dice->dev_lock_count == -1) | |
422 | dice->dev_lock_count = 0; | |
423 | spin_unlock_irq(&dice->lock); | |
424 | ||
425 | return 0; | |
426 | } | |
427 | ||
82fbb4f7 CL |
428 | static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, |
429 | unsigned int cmd, unsigned long arg) | |
430 | { | |
732d153f | 431 | struct snd_dice *dice = hwdep->private_data; |
0c29c918 CL |
432 | |
433 | switch (cmd) { | |
434 | case SNDRV_FIREWIRE_IOCTL_GET_INFO: | |
435 | return dice_hwdep_get_info(dice, (void __user *)arg); | |
436 | case SNDRV_FIREWIRE_IOCTL_LOCK: | |
437 | return dice_hwdep_lock(dice); | |
438 | case SNDRV_FIREWIRE_IOCTL_UNLOCK: | |
439 | return dice_hwdep_unlock(dice); | |
440 | default: | |
441 | return -ENOIOCTLCMD; | |
442 | } | |
443 | } | |
444 | ||
445 | #ifdef CONFIG_COMPAT | |
446 | static int dice_hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, | |
447 | unsigned int cmd, unsigned long arg) | |
448 | { | |
449 | return dice_hwdep_ioctl(hwdep, file, cmd, | |
450 | (unsigned long)compat_ptr(arg)); | |
82fbb4f7 | 451 | } |
0c29c918 CL |
452 | #else |
453 | #define dice_hwdep_compat_ioctl NULL | |
454 | #endif | |
82fbb4f7 | 455 | |
732d153f | 456 | static int dice_create_hwdep(struct snd_dice *dice) |
82fbb4f7 CL |
457 | { |
458 | static const struct snd_hwdep_ops ops = { | |
459 | .read = dice_hwdep_read, | |
9dd81e31 | 460 | .release = dice_hwdep_release, |
82fbb4f7 CL |
461 | .poll = dice_hwdep_poll, |
462 | .ioctl = dice_hwdep_ioctl, | |
0c29c918 | 463 | .ioctl_compat = dice_hwdep_compat_ioctl, |
82fbb4f7 CL |
464 | }; |
465 | struct snd_hwdep *hwdep; | |
466 | int err; | |
467 | ||
468 | err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep); | |
469 | if (err < 0) | |
470 | return err; | |
471 | strcpy(hwdep->name, "DICE"); | |
472 | hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE; | |
473 | hwdep->ops = ops; | |
474 | hwdep->private_data = dice; | |
475 | hwdep->exclusive = true; | |
476 | ||
477 | return 0; | |
478 | } | |
479 | ||
732d153f | 480 | static int dice_proc_read_mem(struct snd_dice *dice, void *buffer, |
c614475b CL |
481 | unsigned int offset_q, unsigned int quadlets) |
482 | { | |
483 | unsigned int i; | |
484 | int err; | |
485 | ||
486 | err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, | |
487 | DICE_PRIVATE_SPACE + 4 * offset_q, | |
488 | buffer, 4 * quadlets, 0); | |
489 | if (err < 0) | |
490 | return err; | |
491 | ||
492 | for (i = 0; i < quadlets; ++i) | |
493 | be32_to_cpus(&((u32 *)buffer)[i]); | |
494 | ||
495 | return 0; | |
496 | } | |
497 | ||
498 | static const char *str_from_array(const char *const strs[], unsigned int count, | |
499 | unsigned int i) | |
500 | { | |
501 | if (i < count) | |
502 | return strs[i]; | |
732d153f TS |
503 | |
504 | return "(unknown)"; | |
c614475b CL |
505 | } |
506 | ||
507 | static void dice_proc_fixup_string(char *s, unsigned int size) | |
508 | { | |
509 | unsigned int i; | |
510 | ||
511 | for (i = 0; i < size; i += 4) | |
512 | cpu_to_le32s((u32 *)(s + i)); | |
513 | ||
514 | for (i = 0; i < size - 2; ++i) { | |
515 | if (s[i] == '\0') | |
516 | return; | |
517 | if (s[i] == '\\' && s[i + 1] == '\\') { | |
518 | s[i + 2] = '\0'; | |
519 | return; | |
520 | } | |
521 | } | |
522 | s[size - 1] = '\0'; | |
523 | } | |
524 | ||
525 | static void dice_proc_read(struct snd_info_entry *entry, | |
526 | struct snd_info_buffer *buffer) | |
527 | { | |
528 | static const char *const section_names[5] = { | |
529 | "global", "tx", "rx", "ext_sync", "unused2" | |
530 | }; | |
531 | static const char *const clock_sources[] = { | |
532 | "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif", | |
533 | "wc", "arx1", "arx2", "arx3", "arx4", "internal" | |
534 | }; | |
535 | static const char *const rates[] = { | |
536 | "32000", "44100", "48000", "88200", "96000", "176400", "192000", | |
537 | "any low", "any mid", "any high", "none" | |
538 | }; | |
732d153f | 539 | struct snd_dice *dice = entry->private_data; |
c614475b CL |
540 | u32 sections[ARRAY_SIZE(section_names) * 2]; |
541 | struct { | |
542 | u32 number; | |
543 | u32 size; | |
544 | } tx_rx_header; | |
545 | union { | |
546 | struct { | |
547 | u32 owner_hi, owner_lo; | |
548 | u32 notification; | |
549 | char nick_name[NICK_NAME_SIZE]; | |
550 | u32 clock_select; | |
551 | u32 enable; | |
552 | u32 status; | |
553 | u32 extended_status; | |
554 | u32 sample_rate; | |
555 | u32 version; | |
556 | u32 clock_caps; | |
557 | char clock_source_names[CLOCK_SOURCE_NAMES_SIZE]; | |
558 | } global; | |
559 | struct { | |
560 | u32 iso; | |
561 | u32 number_audio; | |
562 | u32 number_midi; | |
563 | u32 speed; | |
564 | char names[TX_NAMES_SIZE]; | |
565 | u32 ac3_caps; | |
566 | u32 ac3_enable; | |
567 | } tx; | |
568 | struct { | |
569 | u32 iso; | |
570 | u32 seq_start; | |
571 | u32 number_audio; | |
572 | u32 number_midi; | |
573 | char names[RX_NAMES_SIZE]; | |
574 | u32 ac3_caps; | |
575 | u32 ac3_enable; | |
576 | } rx; | |
577 | struct { | |
578 | u32 clock_source; | |
579 | u32 locked; | |
580 | u32 rate; | |
581 | u32 adat_user_data; | |
582 | } ext_sync; | |
583 | } buf; | |
584 | unsigned int quadlets, stream, i; | |
585 | ||
586 | if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0) | |
587 | return; | |
588 | snd_iprintf(buffer, "sections:\n"); | |
589 | for (i = 0; i < ARRAY_SIZE(section_names); ++i) | |
590 | snd_iprintf(buffer, " %s: offset %u, size %u\n", | |
591 | section_names[i], | |
592 | sections[i * 2], sections[i * 2 + 1]); | |
593 | ||
594 | quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4); | |
595 | if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0) | |
596 | return; | |
597 | snd_iprintf(buffer, "global:\n"); | |
598 | snd_iprintf(buffer, " owner: %04x:%04x%08x\n", | |
599 | buf.global.owner_hi >> 16, | |
600 | buf.global.owner_hi & 0xffff, buf.global.owner_lo); | |
601 | snd_iprintf(buffer, " notification: %08x\n", buf.global.notification); | |
602 | dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE); | |
603 | snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name); | |
604 | snd_iprintf(buffer, " clock select: %s %s\n", | |
605 | str_from_array(clock_sources, ARRAY_SIZE(clock_sources), | |
606 | buf.global.clock_select & CLOCK_SOURCE_MASK), | |
607 | str_from_array(rates, ARRAY_SIZE(rates), | |
608 | (buf.global.clock_select & CLOCK_RATE_MASK) | |
609 | >> CLOCK_RATE_SHIFT)); | |
610 | snd_iprintf(buffer, " enable: %u\n", buf.global.enable); | |
611 | snd_iprintf(buffer, " status: %slocked %s\n", | |
612 | buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un", | |
613 | str_from_array(rates, ARRAY_SIZE(rates), | |
614 | (buf.global.status & | |
615 | STATUS_NOMINAL_RATE_MASK) | |
616 | >> CLOCK_RATE_SHIFT)); | |
617 | snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status); | |
618 | snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate); | |
619 | snd_iprintf(buffer, " version: %u.%u.%u.%u\n", | |
620 | (buf.global.version >> 24) & 0xff, | |
621 | (buf.global.version >> 16) & 0xff, | |
622 | (buf.global.version >> 8) & 0xff, | |
623 | (buf.global.version >> 0) & 0xff); | |
624 | if (quadlets >= 90) { | |
625 | snd_iprintf(buffer, " clock caps:"); | |
626 | for (i = 0; i <= 6; ++i) | |
627 | if (buf.global.clock_caps & (1 << i)) | |
628 | snd_iprintf(buffer, " %s", rates[i]); | |
629 | for (i = 0; i <= 12; ++i) | |
630 | if (buf.global.clock_caps & (1 << (16 + i))) | |
631 | snd_iprintf(buffer, " %s", clock_sources[i]); | |
632 | snd_iprintf(buffer, "\n"); | |
633 | dice_proc_fixup_string(buf.global.clock_source_names, | |
634 | CLOCK_SOURCE_NAMES_SIZE); | |
635 | snd_iprintf(buffer, " clock source names: %s\n", | |
636 | buf.global.clock_source_names); | |
637 | } | |
638 | ||
639 | if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0) | |
640 | return; | |
4d6ff250 | 641 | quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4); |
c614475b CL |
642 | for (stream = 0; stream < tx_rx_header.number; ++stream) { |
643 | if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 + | |
644 | stream * tx_rx_header.size, | |
645 | quadlets) < 0) | |
646 | break; | |
647 | snd_iprintf(buffer, "tx %u:\n", stream); | |
648 | snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso); | |
649 | snd_iprintf(buffer, " audio channels: %u\n", | |
650 | buf.tx.number_audio); | |
651 | snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi); | |
652 | snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed); | |
653 | if (quadlets >= 68) { | |
654 | dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE); | |
655 | snd_iprintf(buffer, " names: %s\n", buf.tx.names); | |
656 | } | |
657 | if (quadlets >= 70) { | |
658 | snd_iprintf(buffer, " ac3 caps: %08x\n", | |
659 | buf.tx.ac3_caps); | |
660 | snd_iprintf(buffer, " ac3 enable: %08x\n", | |
661 | buf.tx.ac3_enable); | |
662 | } | |
663 | } | |
664 | ||
665 | if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0) | |
666 | return; | |
4d6ff250 | 667 | quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4); |
c614475b CL |
668 | for (stream = 0; stream < tx_rx_header.number; ++stream) { |
669 | if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 + | |
670 | stream * tx_rx_header.size, | |
671 | quadlets) < 0) | |
672 | break; | |
673 | snd_iprintf(buffer, "rx %u:\n", stream); | |
674 | snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso); | |
ed7e4826 | 675 | snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start); |
c614475b CL |
676 | snd_iprintf(buffer, " audio channels: %u\n", |
677 | buf.rx.number_audio); | |
678 | snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi); | |
679 | if (quadlets >= 68) { | |
680 | dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE); | |
681 | snd_iprintf(buffer, " names: %s\n", buf.rx.names); | |
682 | } | |
683 | if (quadlets >= 70) { | |
684 | snd_iprintf(buffer, " ac3 caps: %08x\n", | |
685 | buf.rx.ac3_caps); | |
686 | snd_iprintf(buffer, " ac3 enable: %08x\n", | |
687 | buf.rx.ac3_enable); | |
688 | } | |
689 | } | |
690 | ||
691 | quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4); | |
692 | if (quadlets >= 4) { | |
693 | if (dice_proc_read_mem(dice, &buf.ext_sync, | |
694 | sections[6], 4) < 0) | |
695 | return; | |
696 | snd_iprintf(buffer, "ext status:\n"); | |
697 | snd_iprintf(buffer, " clock source: %s\n", | |
698 | str_from_array(clock_sources, | |
699 | ARRAY_SIZE(clock_sources), | |
700 | buf.ext_sync.clock_source)); | |
701 | snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked); | |
702 | snd_iprintf(buffer, " rate: %s\n", | |
703 | str_from_array(rates, ARRAY_SIZE(rates), | |
704 | buf.ext_sync.rate)); | |
705 | snd_iprintf(buffer, " adat user data: "); | |
706 | if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA) | |
707 | snd_iprintf(buffer, "-\n"); | |
708 | else | |
709 | snd_iprintf(buffer, "%x\n", | |
710 | buf.ext_sync.adat_user_data); | |
711 | } | |
712 | } | |
713 | ||
732d153f | 714 | static void dice_create_proc(struct snd_dice *dice) |
c614475b CL |
715 | { |
716 | struct snd_info_entry *entry; | |
717 | ||
718 | if (!snd_card_proc_new(dice->card, "dice", &entry)) | |
719 | snd_info_set_text_ops(entry, dice, dice_proc_read); | |
720 | } | |
721 | ||
a471fcde CL |
722 | #define OUI_WEISS 0x001c6a |
723 | ||
724 | #define DICE_CATEGORY_ID 0x04 | |
725 | #define WEISS_CATEGORY_ID 0x00 | |
cbab328d CL |
726 | |
727 | static int dice_interface_check(struct fw_unit *unit) | |
728 | { | |
729 | static const int min_values[10] = { | |
730 | 10, 0x64 / 4, | |
731 | 10, 0x18 / 4, | |
732 | 10, 0x18 / 4, | |
733 | 0, 0, | |
734 | 0, 0, | |
735 | }; | |
736 | struct fw_device *device = fw_parent_device(unit); | |
737 | struct fw_csr_iterator it; | |
7c2d4c0c | 738 | int key, val, vendor = -1, model = -1, err; |
a471fcde | 739 | unsigned int category, i; |
7c2d4c0c | 740 | __be32 *pointers, value; |
b20be8de | 741 | __be32 tx_data[4]; |
cbab328d CL |
742 | __be32 version; |
743 | ||
7c2d4c0c TS |
744 | pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32), |
745 | GFP_KERNEL); | |
746 | if (pointers == NULL) | |
747 | return -ENOMEM; | |
748 | ||
cbab328d CL |
749 | /* |
750 | * Check that GUID and unit directory are constructed according to DICE | |
751 | * rules, i.e., that the specifier ID is the GUID's OUI, and that the | |
a471fcde CL |
752 | * GUID chip ID consists of the 8-bit category ID, the 10-bit product |
753 | * ID, and a 22-bit serial number. | |
cbab328d CL |
754 | */ |
755 | fw_csr_iterator_init(&it, unit->directory); | |
7c2d4c0c | 756 | while (fw_csr_iterator_next(&it, &key, &val)) { |
cbab328d CL |
757 | switch (key) { |
758 | case CSR_SPECIFIER_ID: | |
7c2d4c0c | 759 | vendor = val; |
cbab328d CL |
760 | break; |
761 | case CSR_MODEL: | |
7c2d4c0c | 762 | model = val; |
cbab328d CL |
763 | break; |
764 | } | |
765 | } | |
a471fcde CL |
766 | if (vendor == OUI_WEISS) |
767 | category = WEISS_CATEGORY_ID; | |
768 | else | |
769 | category = DICE_CATEGORY_ID; | |
770 | if (device->config_rom[3] != ((vendor << 8) | category) || | |
7c2d4c0c TS |
771 | device->config_rom[4] >> 22 != model) { |
772 | err = -ENODEV; | |
773 | goto end; | |
774 | } | |
cbab328d CL |
775 | |
776 | /* | |
777 | * Check that the sub address spaces exist and are located inside the | |
778 | * private address space. The minimum values are chosen so that all | |
779 | * minimally required registers are included. | |
780 | */ | |
781 | err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST, | |
7c2d4c0c TS |
782 | DICE_PRIVATE_SPACE, pointers, |
783 | sizeof(__be32) * ARRAY_SIZE(min_values), 0); | |
784 | if (err < 0) { | |
785 | err = -ENODEV; | |
786 | goto end; | |
787 | } | |
788 | for (i = 0; i < ARRAY_SIZE(min_values); ++i) { | |
cbab328d | 789 | value = be32_to_cpu(pointers[i]); |
7c2d4c0c TS |
790 | if (value < min_values[i] || value >= 0x40000) { |
791 | err = -ENODEV; | |
792 | goto end; | |
793 | } | |
cbab328d CL |
794 | } |
795 | ||
b20be8de CL |
796 | /* We support playback only. Let capture devices be handled by FFADO. */ |
797 | err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST, | |
798 | DICE_PRIVATE_SPACE + | |
799 | be32_to_cpu(pointers[2]) * 4, | |
800 | tx_data, sizeof(tx_data), 0); | |
7c2d4c0c TS |
801 | if (err < 0 || (tx_data[0] && tx_data[3])) { |
802 | err = -ENODEV; | |
803 | goto end; | |
804 | } | |
b20be8de | 805 | |
cbab328d CL |
806 | /* |
807 | * Check that the implemented DICE driver specification major version | |
808 | * number matches. | |
809 | */ | |
810 | err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, | |
811 | DICE_PRIVATE_SPACE + | |
812 | be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION, | |
1b70485f | 813 | &version, 4, 0); |
7c2d4c0c TS |
814 | if (err < 0) { |
815 | err = -ENODEV; | |
816 | goto end; | |
817 | } | |
cbab328d CL |
818 | if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) { |
819 | dev_err(&unit->device, | |
820 | "unknown DICE version: 0x%08x\n", be32_to_cpu(version)); | |
7c2d4c0c TS |
821 | err = -ENODEV; |
822 | goto end; | |
cbab328d | 823 | } |
7c2d4c0c TS |
824 | end: |
825 | return err; | |
cbab328d CL |
826 | } |
827 | ||
6eb6c81e TS |
828 | static int highest_supported_mode_rate(struct snd_dice *dice, |
829 | unsigned int mode, unsigned int *rate) | |
15a75c8b | 830 | { |
6eb6c81e | 831 | unsigned int i, m; |
15a75c8b | 832 | |
6eb6c81e TS |
833 | for (i = ARRAY_SIZE(snd_dice_rates); i > 0; i--) { |
834 | *rate = snd_dice_rates[i - 1]; | |
835 | if (snd_dice_stream_get_rate_mode(dice, *rate, &m) < 0) | |
836 | continue; | |
837 | if (mode == m) | |
838 | break; | |
839 | } | |
840 | if (i == 0) | |
841 | return -EINVAL; | |
15a75c8b | 842 | |
6eb6c81e | 843 | return 0; |
15a75c8b CL |
844 | } |
845 | ||
732d153f | 846 | static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode) |
15a75c8b CL |
847 | { |
848 | __be32 values[2]; | |
6eb6c81e TS |
849 | unsigned int rate; |
850 | int err; | |
15a75c8b | 851 | |
6eb6c81e | 852 | if (highest_supported_mode_rate(dice, mode, &rate) < 0) { |
15a75c8b CL |
853 | dice->rx_channels[mode] = 0; |
854 | dice->rx_midi_ports[mode] = 0; | |
855 | return 0; | |
856 | } | |
857 | ||
6eb6c81e | 858 | err = snd_dice_transaction_set_rate(dice, rate); |
15a75c8b CL |
859 | if (err < 0) |
860 | return err; | |
861 | ||
7c2d4c0c TS |
862 | err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO, |
863 | values, sizeof(values)); | |
15a75c8b CL |
864 | if (err < 0) |
865 | return err; | |
866 | ||
867 | dice->rx_channels[mode] = be32_to_cpu(values[0]); | |
868 | dice->rx_midi_ports[mode] = be32_to_cpu(values[1]); | |
869 | ||
870 | return 0; | |
871 | } | |
872 | ||
732d153f | 873 | static int dice_read_params(struct snd_dice *dice) |
82fbb4f7 | 874 | { |
a0301998 | 875 | __be32 value; |
15a75c8b | 876 | int mode, err; |
82fbb4f7 | 877 | |
a0301998 | 878 | /* some very old firmwares don't tell about their clock support */ |
7c2d4c0c TS |
879 | if (dice->clock_caps > 0) { |
880 | err = snd_dice_transaction_read_global(dice, | |
881 | GLOBAL_CLOCK_CAPABILITIES, | |
882 | &value, 4); | |
a0301998 CL |
883 | if (err < 0) |
884 | return err; | |
885 | dice->clock_caps = be32_to_cpu(value); | |
886 | } else { | |
887 | /* this should be supported by any device */ | |
888 | dice->clock_caps = CLOCK_CAP_RATE_44100 | | |
889 | CLOCK_CAP_RATE_48000 | | |
890 | CLOCK_CAP_SOURCE_ARX1 | | |
891 | CLOCK_CAP_SOURCE_INTERNAL; | |
892 | } | |
893 | ||
15a75c8b CL |
894 | for (mode = 2; mode >= 0; --mode) { |
895 | err = dice_read_mode_params(dice, mode); | |
896 | if (err < 0) | |
897 | return err; | |
898 | } | |
899 | ||
82fbb4f7 CL |
900 | return 0; |
901 | } | |
902 | ||
732d153f | 903 | static void dice_card_strings(struct snd_dice *dice) |
82fbb4f7 CL |
904 | { |
905 | struct snd_card *card = dice->card; | |
906 | struct fw_device *dev = fw_parent_device(dice->unit); | |
907 | char vendor[32], model[32]; | |
908 | unsigned int i; | |
909 | int err; | |
910 | ||
911 | strcpy(card->driver, "DICE"); | |
912 | ||
913 | strcpy(card->shortname, "DICE"); | |
914 | BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname)); | |
7c2d4c0c TS |
915 | err = snd_dice_transaction_read_global(dice, GLOBAL_NICK_NAME, |
916 | card->shortname, | |
917 | sizeof(card->shortname)); | |
82fbb4f7 CL |
918 | if (err >= 0) { |
919 | /* DICE strings are returned in "always-wrong" endianness */ | |
920 | BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0); | |
921 | for (i = 0; i < sizeof(card->shortname); i += 4) | |
922 | swab32s((u32 *)&card->shortname[i]); | |
923 | card->shortname[sizeof(card->shortname) - 1] = '\0'; | |
924 | } | |
925 | ||
926 | strcpy(vendor, "?"); | |
927 | fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor)); | |
928 | strcpy(model, "?"); | |
929 | fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model)); | |
930 | snprintf(card->longname, sizeof(card->longname), | |
cbab328d CL |
931 | "%s %s (serial %u) at %s, S%d", |
932 | vendor, model, dev->config_rom[4] & 0x3fffff, | |
82fbb4f7 CL |
933 | dev_name(&dice->unit->device), 100 << dev->max_speed); |
934 | ||
935 | strcpy(card->mixername, "DICE"); | |
936 | } | |
937 | ||
7c2d4c0c TS |
938 | static void dice_card_free(struct snd_card *card) |
939 | { | |
940 | struct snd_dice *dice = card->private_data; | |
941 | ||
942 | snd_dice_transaction_destroy(dice); | |
943 | mutex_destroy(&dice->mutex); | |
944 | } | |
945 | ||
82fbb4f7 CL |
946 | static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) |
947 | { | |
948 | struct snd_card *card; | |
732d153f | 949 | struct snd_dice *dice; |
82fbb4f7 CL |
950 | int err; |
951 | ||
cbab328d CL |
952 | err = dice_interface_check(unit); |
953 | if (err < 0) | |
7c2d4c0c | 954 | goto end; |
cbab328d | 955 | |
06b45f00 TI |
956 | err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, |
957 | sizeof(*dice), &card); | |
82fbb4f7 | 958 | if (err < 0) |
7c2d4c0c | 959 | goto end; |
82fbb4f7 CL |
960 | |
961 | dice = card->private_data; | |
962 | dice->card = card; | |
7c2d4c0c TS |
963 | dice->unit = unit; |
964 | card->private_free = dice_card_free; | |
965 | ||
0c29c918 | 966 | spin_lock_init(&dice->lock); |
82fbb4f7 | 967 | mutex_init(&dice->mutex); |
15a75c8b | 968 | init_completion(&dice->clock_accepted); |
0c29c918 | 969 | init_waitqueue_head(&dice->hwdep_wait); |
82fbb4f7 | 970 | |
7c2d4c0c | 971 | err = snd_dice_transaction_init(dice); |
82fbb4f7 | 972 | if (err < 0) |
7c2d4c0c | 973 | goto error; |
5ea4018e CL |
974 | |
975 | err = dice_read_params(dice); | |
976 | if (err < 0) | |
7c2d4c0c | 977 | goto error; |
82fbb4f7 CL |
978 | |
979 | dice_card_strings(dice); | |
980 | ||
981 | err = dice_create_pcm(dice); | |
982 | if (err < 0) | |
983 | goto error; | |
984 | ||
985 | err = dice_create_hwdep(dice); | |
986 | if (err < 0) | |
987 | goto error; | |
988 | ||
c614475b CL |
989 | dice_create_proc(dice); |
990 | ||
6eb6c81e | 991 | err = snd_dice_stream_init(dice); |
82fbb4f7 CL |
992 | if (err < 0) |
993 | goto error; | |
82fbb4f7 | 994 | |
7c2d4c0c TS |
995 | err = snd_card_register(card); |
996 | if (err < 0) { | |
6eb6c81e | 997 | snd_dice_stream_destroy(dice); |
7c2d4c0c TS |
998 | goto error; |
999 | } | |
82fbb4f7 | 1000 | |
7c2d4c0c TS |
1001 | dev_set_drvdata(&unit->device, dice); |
1002 | end: | |
1003 | return err; | |
82fbb4f7 CL |
1004 | error: |
1005 | snd_card_free(card); | |
1006 | return err; | |
1007 | } | |
1008 | ||
1009 | static void dice_remove(struct fw_unit *unit) | |
1010 | { | |
732d153f | 1011 | struct snd_dice *dice = dev_get_drvdata(&unit->device); |
82fbb4f7 | 1012 | |
4ed31f20 CL |
1013 | snd_card_disconnect(dice->card); |
1014 | ||
a8c558f6 SR |
1015 | mutex_lock(&dice->mutex); |
1016 | ||
6eb6c81e | 1017 | snd_dice_stream_destroy(dice); |
4ed31f20 | 1018 | |
82fbb4f7 CL |
1019 | mutex_unlock(&dice->mutex); |
1020 | ||
1021 | snd_card_free_when_closed(dice->card); | |
1022 | } | |
1023 | ||
1024 | static void dice_bus_reset(struct fw_unit *unit) | |
1025 | { | |
732d153f | 1026 | struct snd_dice *dice = dev_get_drvdata(&unit->device); |
82fbb4f7 | 1027 | |
7c2d4c0c TS |
1028 | /* The handler address register becomes initialized. */ |
1029 | snd_dice_transaction_reinit(dice); | |
1030 | ||
a8c558f6 | 1031 | mutex_lock(&dice->mutex); |
6eb6c81e | 1032 | snd_dice_stream_update(dice); |
82fbb4f7 CL |
1033 | mutex_unlock(&dice->mutex); |
1034 | } | |
1035 | ||
82fbb4f7 CL |
1036 | #define DICE_INTERFACE 0x000001 |
1037 | ||
1038 | static const struct ieee1394_device_id dice_id_table[] = { | |
1039 | { | |
cbab328d CL |
1040 | .match_flags = IEEE1394_MATCH_VERSION, |
1041 | .version = DICE_INTERFACE, | |
82fbb4f7 CL |
1042 | }, |
1043 | { } | |
1044 | }; | |
1045 | MODULE_DEVICE_TABLE(ieee1394, dice_id_table); | |
1046 | ||
1047 | static struct fw_driver dice_driver = { | |
1048 | .driver = { | |
1049 | .owner = THIS_MODULE, | |
1050 | .name = KBUILD_MODNAME, | |
1051 | .bus = &fw_bus_type, | |
1052 | }, | |
1053 | .probe = dice_probe, | |
1054 | .update = dice_bus_reset, | |
1055 | .remove = dice_remove, | |
1056 | .id_table = dice_id_table, | |
1057 | }; | |
1058 | ||
1059 | static int __init alsa_dice_init(void) | |
1060 | { | |
1061 | return driver_register(&dice_driver.driver); | |
1062 | } | |
1063 | ||
1064 | static void __exit alsa_dice_exit(void) | |
1065 | { | |
1066 | driver_unregister(&dice_driver.driver); | |
1067 | } | |
1068 | ||
1069 | module_init(alsa_dice_init); | |
1070 | module_exit(alsa_dice_exit); |