History

ALSA: firewire-digi00x: add support for asynchronous messaging

Digi 002/003 family uses asynchronous transaction for messaging. The address to transmit this message is stored on a certain register. This commit allocates a range of address on OHCI 1394 host controller to handle the messaging. As long as I know, the purpose of this message seems to notify lost of synchronization. While, the meaning of content of the message is not clear. Actual examples of this messaging: * When clock source is set as internal: - 0x00007051 - 0x00007052 - 0x00007054 - 0x00007057 - 0x00007058 * When clock source is set as somewhat external: - 0x00009000 - 0x00009010 - 0x00009020 - 0x00009021 - 0x00009022 The lost often occurs when using internal clock source. In this case, users hear sounds with quite short gap every several minutes. In fact, the lost is recovered temporarily. When using with external clock source, the lost seems not to occur. The mechanism is not clear yet.

Takashi Sakamoto committed 11 years ago

Commit 44b73081 parent 660dd3d6 files · +114 −3Browse files

Unified · Split

6 files
  1. include/uapi/sound/firewire.h +7 −0
  2. sound/firewire/digi00x/Makefile +2 −1
  3. sound/firewire/digi00x/digi00x-hwdep.c +10 −2
  4. sound/firewire/digi00x/digi00x-transaction.c +81 −0
  5. sound/firewire/digi00x/digi00x.c +7 −0
  6. sound/firewire/digi00x/digi00x.h +7 −0
include/uapi/sound/firewire.h+7−0
@@ -9,6 +9,7 @@ · 8 unmodified lines
9#define SNDRV_FIREWIRE_EVENT_LOCK_STATUS 0x000010cc9#define SNDRV_FIREWIRE_EVENT_LOCK_STATUS 0x000010cc
10#define SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION 0xd1ce004e10#define SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION 0xd1ce004e
11#define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE 0x4e61747511#define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE 0x4e617475
12#define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE 0x746e736c
12 13
13struct snd_firewire_event_common {14struct snd_firewire_event_common {
14 unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */15 unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */
@@ -40,11 +41,17 @@ struct snd_firewire_event_efw_response { · 25 unmodified lines
40 __be32 response[0]; /* some responses */41 __be32 response[0]; /* some responses */
41};42};
42 43
44struct snd_firewire_event_digi00x_message {
45 unsigned int type;
46 __u32 message; /* Digi00x-specific message */
47};
48
43union snd_firewire_event {49union snd_firewire_event {
44 struct snd_firewire_event_common common;50 struct snd_firewire_event_common common;
45 struct snd_firewire_event_lock_status lock_status;51 struct snd_firewire_event_lock_status lock_status;
46 struct snd_firewire_event_dice_notification dice_notification;52 struct snd_firewire_event_dice_notification dice_notification;
47 struct snd_firewire_event_efw_response efw_response;53 struct snd_firewire_event_efw_response efw_response;
54 struct snd_firewire_event_digi00x_message digi00x_message;
48};55};
49 56
50 57
sound/firewire/digi00x/Makefile+2−1
@@ -1,3 +1,4 @@
1snd-firewire-digi00x-objs := amdtp-dot.o digi00x-stream.o digi00x-proc.o \1snd-firewire-digi00x-objs := amdtp-dot.o digi00x-stream.o digi00x-proc.o \
2 digi00x-pcm.o digi00x-hwdep.o digi00x.o2 digi00x-pcm.o digi00x-hwdep.o \
3 digi00x-transaction.o digi00x.o
3obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += snd-firewire-digi00x.o4obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += snd-firewire-digi00x.o
sound/firewire/digi00x/digi00x-hwdep.c+10−2
@@ -12,6 +12,7 @@ · 11 unmodified lines
12 * 1.get firewire node information12 * 1.get firewire node information
13 * 2.get notification about starting/stopping stream13 * 2.get notification about starting/stopping stream
14 * 3.lock/unlock stream14 * 3.lock/unlock stream
15 * 4.get asynchronous messaging
15 */16 */
16 17
17#include "digi00x.h"18#include "digi00x.h"
@@ -25,7 +26,7 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, · 7 unmodified lines
25 26
26 spin_lock_irq(&dg00x->lock);27 spin_lock_irq(&dg00x->lock);
27 28
28 while (!dg00x->dev_lock_changed) {29 while (!dg00x->dev_lock_changed && dg00x->msg == 0) {
29 prepare_to_wait(&dg00x->hwdep_wait, &wait, TASK_INTERRUPTIBLE);30 prepare_to_wait(&dg00x->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
30 spin_unlock_irq(&dg00x->lock);31 spin_unlock_irq(&dg00x->lock);
31 schedule();32 schedule();
@@ -42,6 +43,13 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, · 10 unmodified lines
42 dg00x->dev_lock_changed = false;43 dg00x->dev_lock_changed = false;
43 44
44 count = min_t(long, count, sizeof(event.lock_status));45 count = min_t(long, count, sizeof(event.lock_status));
46 } else {
47 event.digi00x_message.type =
48 SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE;
49 event.digi00x_message.message = dg00x->msg;
50 dg00x->msg = 0;
51
52 count = min_t(long, count, sizeof(event.digi00x_message));
45 }53 }
46 54
47 spin_unlock_irq(&dg00x->lock);55 spin_unlock_irq(&dg00x->lock);
@@ -61,7 +69,7 @@ static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file, · 13 unmodified lines
61 poll_wait(file, &dg00x->hwdep_wait, wait);69 poll_wait(file, &dg00x->hwdep_wait, wait);
62 70
63 spin_lock_irq(&dg00x->lock);71 spin_lock_irq(&dg00x->lock);
64 if (dg00x->dev_lock_changed)72 if (dg00x->dev_lock_changed || dg00x->msg)
65 events = POLLIN | POLLRDNORM;73 events = POLLIN | POLLRDNORM;
66 else74 else
67 events = 0;75 events = 0;
sound/firewire/digi00x/digi00x-transaction.c+81−0
@@ -0,0 +1,81 @@
1/*
2 * digi00x-transaction.c - a part of driver for Digidesign Digi 002/003 family
3 *
4 * Copyright (c) 2014-2015 Takashi Sakamoto
5 *
6 * Licensed under the terms of the GNU General Public License, version 2.
7 */
8
9#include <sound/asound.h>
10#include "digi00x.h"
11
12static void handle_unknown_message(struct snd_dg00x *dg00x,
13 unsigned long long offset, __be32 *buf)
14{
15 unsigned long flags;
16
17 spin_lock_irqsave(&dg00x->lock, flags);
18 dg00x->msg = be32_to_cpu(*buf);
19 spin_unlock_irqrestore(&dg00x->lock, flags);
20
21 wake_up(&dg00x->hwdep_wait);
22}
23
24static void handle_message(struct fw_card *card, struct fw_request *request,
25 int tcode, int destination, int source,
26 int generation, unsigned long long offset,
27 void *data, size_t length, void *callback_data)
28{
29 struct snd_dg00x *dg00x = callback_data;
30 __be32 *buf = (__be32 *)data;
31
32 if (offset == dg00x->async_handler.offset)
33 handle_unknown_message(dg00x, offset, buf);
34
35 fw_send_response(card, request, RCODE_COMPLETE);
36}
37
38int snd_dg00x_transaction_reregister(struct snd_dg00x *dg00x)
39{
40 struct fw_device *device = fw_parent_device(dg00x->unit);
41 __be32 data[2];
42
43 /* Unknown. 4bytes. */
44 data[0] = cpu_to_be32((device->card->node_id << 16) |
45 (dg00x->async_handler.offset >> 32));
46 data[1] = cpu_to_be32(dg00x->async_handler.offset);
47 return snd_fw_transaction(dg00x->unit, TCODE_WRITE_BLOCK_REQUEST,
48 DG00X_ADDR_BASE + DG00X_OFFSET_MESSAGE_ADDR,
49 &data, sizeof(data), 0);
50}
51
52int snd_dg00x_transaction_register(struct snd_dg00x *dg00x)
53{
54 static const struct fw_address_region resp_register_region = {
55 .start = 0xffffe0000000ull,
56 .end = 0xffffe000ffffull,
57 };
58 int err;
59
60 dg00x->async_handler.length = 4;
61 dg00x->async_handler.address_callback = handle_message;
62 dg00x->async_handler.callback_data = dg00x;
63
64 err = fw_core_add_address_handler(&dg00x->async_handler,
65 &resp_register_region);
66 if (err < 0)
67 return err;
68
69 err = snd_dg00x_transaction_reregister(dg00x);
70 if (err < 0) {
71 fw_core_remove_address_handler(&dg00x->async_handler);
72 dg00x->async_handler.address_callback = NULL;
73 }
74
75 return err;
76}
77
78void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x)
79{
80 fw_core_remove_address_handler(&dg00x->async_handler);
81}
sound/firewire/digi00x/digi00x.c+7−0
@@ -46,6 +46,7 @@ static void dg00x_card_free(struct snd_card *card) · 45 unmodified lines
46 struct snd_dg00x *dg00x = card->private_data;46 struct snd_dg00x *dg00x = card->private_data;
47 47
48 snd_dg00x_stream_destroy_duplex(dg00x);48 snd_dg00x_stream_destroy_duplex(dg00x);
49 snd_dg00x_transaction_unregister(dg00x);
49 50
50 fw_unit_put(dg00x->unit);51 fw_unit_put(dg00x->unit);
51 52
@@ -93,6 +94,10 @@ static int snd_dg00x_probe(struct fw_unit *unit, · 41 unmodified lines
93 if (err < 0)94 if (err < 0)
94 goto error;95 goto error;
95 96
97 err = snd_dg00x_transaction_register(dg00x);
98 if (err < 0)
99 goto error;
100
96 err = snd_card_register(card);101 err = snd_card_register(card);
97 if (err < 0)102 if (err < 0)
98 goto error;103 goto error;
@@ -109,6 +114,8 @@ static void snd_dg00x_update(struct fw_unit *unit) · 10 unmodified lines
109{114{
110 struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device);115 struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device);
111 116
117 snd_dg00x_transaction_reregister(dg00x);
118
112 mutex_lock(&dg00x->mutex);119 mutex_lock(&dg00x->mutex);
113 snd_dg00x_stream_update_duplex(dg00x);120 snd_dg00x_stream_update_duplex(dg00x);
114 mutex_unlock(&dg00x->mutex);121 mutex_unlock(&dg00x->mutex);
sound/firewire/digi00x/digi00x.h+7−0
@@ -49,6 +49,9 @@ struct snd_dg00x { · 48 unmodified lines
49 bool dev_lock_changed;49 bool dev_lock_changed;
50 wait_queue_head_t hwdep_wait;50 wait_queue_head_t hwdep_wait;
51 51
52 /* For asynchronous messages. */
53 struct fw_address_handler async_handler;
54 u32 msg;
52};55};
53 56
54#define DG00X_ADDR_BASE 0xffffe0000000ull57#define DG00X_ADDR_BASE 0xffffe0000000ull
@@ -110,6 +113,10 @@ int amdtp_dot_add_pcm_hw_constraints(struct amdtp_stream *s, · 55 unmodified lines
110 struct snd_pcm_runtime *runtime);113 struct snd_pcm_runtime *runtime);
111void amdtp_dot_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format);114void amdtp_dot_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format);
112 115
116int snd_dg00x_transaction_register(struct snd_dg00x *dg00x);
117int snd_dg00x_transaction_reregister(struct snd_dg00x *dg00x);
118void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x);
119
113extern const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT];120extern const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT];
114extern const unsigned int snd_dg00x_stream_pcm_channels[SND_DG00X_RATE_COUNT];121extern const unsigned int snd_dg00x_stream_pcm_channels[SND_DG00X_RATE_COUNT];
115int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,122int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t