summaryrefslogtreecommitdiffstats
path: root/sound/firewire/motu
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2017-03-22 08:30:19 -0400
committerTakashi Iwai <tiwai@suse.de>2017-03-28 06:33:32 -0400
commit2e76701bbb1fbe55f7d8538ae7f6869070eb3446 (patch)
tree32857eb7553612105d0a9e96098b2897ae37bf9f /sound/firewire/motu
parent4641c939401076c0ab7faba024827069723f719c (diff)
ALSA: firewire-motu: handle transactions specific for MOTU FireWire models
All models of MOTU FireWire series can be controlled by write transaction to addresses in a range from 0x'ffff'f0000'0b00 to 0x'ffff'f000'0cff. The models support asynchronous notification. This notification has 32 bit field data, and is transferred when status of clock changes. Meaning of the value is not enough clear yet. Drivers can register its address to receive the notification. Write transaction to 0x'ffff'f000'0b04 registers higher 16 bits of the address. Write transaction to 0x'ffff'f0000'0b08 registers the rest of bits. The address includes node ID, thus it should be registered every time of bus reset. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/motu')
-rw-r--r--sound/firewire/motu/Makefile2
-rw-r--r--sound/firewire/motu/motu-transaction.c117
-rw-r--r--sound/firewire/motu/motu.c10
-rw-r--r--sound/firewire/motu/motu.h12
4 files changed, 140 insertions, 1 deletions
diff --git a/sound/firewire/motu/Makefile b/sound/firewire/motu/Makefile
index 37391f5c623d..03b07694df66 100644
--- a/sound/firewire/motu/Makefile
+++ b/sound/firewire/motu/Makefile
@@ -1,2 +1,2 @@
1snd-firewire-motu-objs := motu.o amdtp-motu.o 1snd-firewire-motu-objs := motu.o amdtp-motu.o motu-transaction.o
2obj-$(CONFIG_SND_FIREWIRE_MOTU) += snd-firewire-motu.o 2obj-$(CONFIG_SND_FIREWIRE_MOTU) += snd-firewire-motu.o
diff --git a/sound/firewire/motu/motu-transaction.c b/sound/firewire/motu/motu-transaction.c
new file mode 100644
index 000000000000..416dd9833896
--- /dev/null
+++ b/sound/firewire/motu/motu-transaction.c
@@ -0,0 +1,117 @@
1/*
2 * motu-transaction.c - a part of driver for MOTU FireWire series
3 *
4 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
5 *
6 * Licensed under the terms of the GNU General Public License, version 2.
7 */
8
9
10#include "motu.h"
11
12#define SND_MOTU_ADDR_BASE 0xfffff0000000ULL
13#define ASYNC_ADDR_HI 0x0b04
14#define ASYNC_ADDR_LO 0x0b08
15
16int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
17 size_t size)
18{
19 int tcode;
20
21 if (size % sizeof(__be32) > 0 || size <= 0)
22 return -EINVAL;
23 if (size == sizeof(__be32))
24 tcode = TCODE_READ_QUADLET_REQUEST;
25 else
26 tcode = TCODE_READ_BLOCK_REQUEST;
27
28 return snd_fw_transaction(motu->unit, tcode,
29 SND_MOTU_ADDR_BASE + offset, reg, size, 0);
30}
31
32int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
33 size_t size)
34{
35 int tcode;
36
37 if (size % sizeof(__be32) > 0 || size <= 0)
38 return -EINVAL;
39 if (size == sizeof(__be32))
40 tcode = TCODE_WRITE_QUADLET_REQUEST;
41 else
42 tcode = TCODE_WRITE_BLOCK_REQUEST;
43
44 return snd_fw_transaction(motu->unit, tcode,
45 SND_MOTU_ADDR_BASE + offset, reg, size, 0);
46}
47
48static void handle_message(struct fw_card *card, struct fw_request *request,
49 int tcode, int destination, int source,
50 int generation, unsigned long long offset,
51 void *data, size_t length, void *callback_data)
52{
53 fw_send_response(card, request, RCODE_COMPLETE);
54}
55
56int snd_motu_transaction_reregister(struct snd_motu *motu)
57{
58 struct fw_device *device = fw_parent_device(motu->unit);
59 __be32 data;
60 int err;
61
62 if (motu->async_handler.callback_data == NULL)
63 return -EINVAL;
64
65 /* Register messaging address. Block transaction is not allowed. */
66 data = cpu_to_be32((device->card->node_id << 16) |
67 (motu->async_handler.offset >> 32));
68 err = snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data,
69 sizeof(data));
70 if (err < 0)
71 return err;
72
73 data = cpu_to_be32(motu->async_handler.offset);
74 return snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data,
75 sizeof(data));
76}
77
78int snd_motu_transaction_register(struct snd_motu *motu)
79{
80 static const struct fw_address_region resp_register_region = {
81 .start = 0xffffe0000000ull,
82 .end = 0xffffe000ffffull,
83 };
84 int err;
85
86 /* Perhaps, 4 byte messages are transferred. */
87 motu->async_handler.length = 4;
88 motu->async_handler.address_callback = handle_message;
89 motu->async_handler.callback_data = motu;
90
91 err = fw_core_add_address_handler(&motu->async_handler,
92 &resp_register_region);
93 if (err < 0)
94 return err;
95
96 err = snd_motu_transaction_reregister(motu);
97 if (err < 0) {
98 fw_core_remove_address_handler(&motu->async_handler);
99 motu->async_handler.address_callback = NULL;
100 }
101
102 return err;
103}
104
105void snd_motu_transaction_unregister(struct snd_motu *motu)
106{
107 __be32 data;
108
109 if (motu->async_handler.address_callback != NULL)
110 fw_core_remove_address_handler(&motu->async_handler);
111 motu->async_handler.address_callback = NULL;
112
113 /* Unregister the address. */
114 data = cpu_to_be32(0x00000000);
115 snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data, sizeof(data));
116 snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data, sizeof(data));
117}
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c
index 1e6fc74a6458..db6014c2f16d 100644
--- a/sound/firewire/motu/motu.c
+++ b/sound/firewire/motu/motu.c
@@ -54,6 +54,8 @@ static void name_card(struct snd_motu *motu)
54 54
55static void motu_free(struct snd_motu *motu) 55static void motu_free(struct snd_motu *motu)
56{ 56{
57 snd_motu_transaction_unregister(motu);
58
57 fw_unit_put(motu->unit); 59 fw_unit_put(motu->unit);
58 60
59 mutex_destroy(&motu->mutex); 61 mutex_destroy(&motu->mutex);
@@ -86,6 +88,10 @@ static void do_registration(struct work_struct *work)
86 88
87 name_card(motu); 89 name_card(motu);
88 90
91 err = snd_motu_transaction_register(motu);
92 if (err < 0)
93 goto error;
94
89 err = snd_card_register(motu->card); 95 err = snd_card_register(motu->card);
90 if (err < 0) 96 if (err < 0)
91 goto error; 97 goto error;
@@ -100,6 +106,7 @@ static void do_registration(struct work_struct *work)
100 106
101 return; 107 return;
102error: 108error:
109 snd_motu_transaction_unregister(motu);
103 snd_card_free(motu->card); 110 snd_card_free(motu->card);
104 dev_info(&motu->unit->device, 111 dev_info(&motu->unit->device,
105 "Sound card registration failed: %d\n", err); 112 "Sound card registration failed: %d\n", err);
@@ -155,6 +162,9 @@ static void motu_bus_update(struct fw_unit *unit)
155 /* Postpone a workqueue for deferred registration. */ 162 /* Postpone a workqueue for deferred registration. */
156 if (!motu->registered) 163 if (!motu->registered)
157 snd_fw_schedule_registration(unit, &motu->dwork); 164 snd_fw_schedule_registration(unit, &motu->dwork);
165
166 /* The handler address register becomes initialized. */
167 snd_motu_transaction_reregister(motu);
158} 168}
159 169
160#define SND_MOTU_DEV_ENTRY(model, data) \ 170#define SND_MOTU_DEV_ENTRY(model, data) \
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h
index cd1b3dd3e371..ed1d779c0dcc 100644
--- a/sound/firewire/motu/motu.h
+++ b/sound/firewire/motu/motu.h
@@ -48,6 +48,10 @@ struct snd_motu {
48 struct snd_motu_packet_format rx_packet_formats; 48 struct snd_motu_packet_format rx_packet_formats;
49 struct amdtp_stream tx_stream; 49 struct amdtp_stream tx_stream;
50 struct amdtp_stream rx_stream; 50 struct amdtp_stream rx_stream;
51
52 /* For notification. */
53 struct fw_address_handler async_handler;
54 u32 msg;
51}; 55};
52 56
53enum snd_motu_spec_flags { 57enum snd_motu_spec_flags {
@@ -106,4 +110,12 @@ int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate,
106 struct snd_motu_packet_format *formats); 110 struct snd_motu_packet_format *formats);
107int amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s, 111int amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s,
108 struct snd_pcm_runtime *runtime); 112 struct snd_pcm_runtime *runtime);
113
114int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
115 size_t size);
116int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
117 size_t size);
118int snd_motu_transaction_register(struct snd_motu *motu);
119int snd_motu_transaction_reregister(struct snd_motu *motu);
120void snd_motu_transaction_unregister(struct snd_motu *motu);
109#endif 121#endif