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
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 { · 25 unmodified lines
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+2−1
@@ -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+10−2
@@ -12,6 +12,7 @@ · 11 unmodified lines
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, · 7 unmodified lines
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, · 10 unmodified lines
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, · 13 unmodified lines
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;
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+
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+7−0
@@ -46,6 +46,7 @@ static void dg00x_card_free(struct snd_card *card) · 45 unmodified lines
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, · 41 unmodified lines
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) · 10 unmodified lines
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+7−0
@@ -49,6 +49,9 @@ struct snd_dg00x { · 48 unmodified lines
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, · 55 unmodified lines
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,

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