Skip to content

Commit 44b7308

Browse files
takaswietiwai
authored andcommitted
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. Signed-off-by: Takashi Sakamoto <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 660dd3d commit 44b7308

File tree

6 files changed

+114
-3
lines changed

6 files changed

+114
-3
lines changed

include/uapi/sound/firewire.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#define SNDRV_FIREWIRE_EVENT_LOCK_STATUS 0x000010cc
1010
#define SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION 0xd1ce004e
1111
#define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE 0x4e617475
12+
#define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE 0x746e736c
1213

1314
struct snd_firewire_event_common {
1415
unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */
@@ -40,11 +41,17 @@ struct snd_firewire_event_efw_response {
4041
__be32 response[0]; /* some responses */
4142
};
4243

44+
struct snd_firewire_event_digi00x_message {
45+
unsigned int type;
46+
__u32 message; /* Digi00x-specific message */
47+
};
48+
4349
union snd_firewire_event {
4450
struct snd_firewire_event_common common;
4551
struct snd_firewire_event_lock_status lock_status;
4652
struct snd_firewire_event_dice_notification dice_notification;
4753
struct snd_firewire_event_efw_response efw_response;
54+
struct snd_firewire_event_digi00x_message digi00x_message;
4855
};
4956

5057

sound/firewire/digi00x/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
snd-firewire-digi00x-objs := amdtp-dot.o digi00x-stream.o digi00x-proc.o \
2-
digi00x-pcm.o digi00x-hwdep.o digi00x.o
2+
digi00x-pcm.o digi00x-hwdep.o \
3+
digi00x-transaction.o digi00x.o
34
obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += snd-firewire-digi00x.o

sound/firewire/digi00x/digi00x-hwdep.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* 1.get firewire node information
1313
* 2.get notification about starting/stopping stream
1414
* 3.lock/unlock stream
15+
* 4.get asynchronous messaging
1516
*/
1617

1718
#include "digi00x.h"
@@ -25,7 +26,7 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
2526

2627
spin_lock_irq(&dg00x->lock);
2728

28-
while (!dg00x->dev_lock_changed) {
29+
while (!dg00x->dev_lock_changed && dg00x->msg == 0) {
2930
prepare_to_wait(&dg00x->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
3031
spin_unlock_irq(&dg00x->lock);
3132
schedule();
@@ -42,6 +43,13 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
4243
dg00x->dev_lock_changed = false;
4344

4445
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));
4553
}
4654

4755
spin_unlock_irq(&dg00x->lock);
@@ -61,7 +69,7 @@ static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
6169
poll_wait(file, &dg00x->hwdep_wait, wait);
6270

6371
spin_lock_irq(&dg00x->lock);
64-
if (dg00x->dev_lock_changed)
72+
if (dg00x->dev_lock_changed || dg00x->msg)
6573
events = POLLIN | POLLRDNORM;
6674
else
6775
events = 0;
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
12+
static 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+
24+
static 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+
38+
int 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+
52+
int 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+
78+
void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x)
79+
{
80+
fw_core_remove_address_handler(&dg00x->async_handler);
81+
}

sound/firewire/digi00x/digi00x.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ static void dg00x_card_free(struct snd_card *card)
4646
struct snd_dg00x *dg00x = card->private_data;
4747

4848
snd_dg00x_stream_destroy_duplex(dg00x);
49+
snd_dg00x_transaction_unregister(dg00x);
4950

5051
fw_unit_put(dg00x->unit);
5152

@@ -93,6 +94,10 @@ static int snd_dg00x_probe(struct fw_unit *unit,
9394
if (err < 0)
9495
goto error;
9596

97+
err = snd_dg00x_transaction_register(dg00x);
98+
if (err < 0)
99+
goto error;
100+
96101
err = snd_card_register(card);
97102
if (err < 0)
98103
goto error;
@@ -109,6 +114,8 @@ static void snd_dg00x_update(struct fw_unit *unit)
109114
{
110115
struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device);
111116

117+
snd_dg00x_transaction_reregister(dg00x);
118+
112119
mutex_lock(&dg00x->mutex);
113120
snd_dg00x_stream_update_duplex(dg00x);
114121
mutex_unlock(&dg00x->mutex);

sound/firewire/digi00x/digi00x.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ struct snd_dg00x {
4949
bool dev_lock_changed;
5050
wait_queue_head_t hwdep_wait;
5151

52+
/* For asynchronous messages. */
53+
struct fw_address_handler async_handler;
54+
u32 msg;
5255
};
5356

5457
#define DG00X_ADDR_BASE 0xffffe0000000ull
@@ -110,6 +113,10 @@ int amdtp_dot_add_pcm_hw_constraints(struct amdtp_stream *s,
110113
struct snd_pcm_runtime *runtime);
111114
void amdtp_dot_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format);
112115

116+
int snd_dg00x_transaction_register(struct snd_dg00x *dg00x);
117+
int snd_dg00x_transaction_reregister(struct snd_dg00x *dg00x);
118+
void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x);
119+
113120
extern const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT];
114121
extern const unsigned int snd_dg00x_stream_pcm_channels[SND_DG00X_RATE_COUNT];
115122
int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,

0 commit comments

Comments
 (0)