Skip to content

Commit 76fdb3a

Browse files
takaswietiwai
authored andcommitted
ALSA: fireface: add support for Fireface 400
Fireface 400 is a second model of RME Fireface series, released in 2006. This commit adds support for this model. This model supports 8 analog channels, 2 S/PDIF channels and 8 ADAT channels in both of tx/rx packet. The number of ADAT channels differs depending on each mode of sampling transmission frequency. $ python2 linux-firewire-utils/src/crpp < /sys/bus/firewire/devices/fw1/config_rom ROM header and bus information block ----------------------------------------------------------------- 400 0410776 bus_info_length 4, crc_length 16, crc 30568 (should be 61311) 404 31333934 bus_name "1394" 408 20009002 irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 0, max_rec 9 (1024) 40c 000a3501 company_id 000a35 | 410 1bd0862a device_id 011bd0862a | EUI-64 000a35011bd0862a root directory ----------------------------------------------------------------- 414 000485ec directory_length 4, crc 34284 418 03000a35 vendor 41c 0c0083c0 node capabilities per IEEE 1394 420 8d000006 --> eui-64 leaf at 438 424 d1000001 --> unit directory at 428 unit directory at 428 ----------------------------------------------------------------- 428 000314c4 directory_length 3, crc 5316 42c 12000a35 specifier id 430 13000002 version 434 17101800 model eui-64 leaf at 438 ----------------------------------------------------------------- 438 000261a8 leaf_length 2, crc 25000 43c 000a3501 company_id 000a35 | 440 1bd0862a device_id 011bd0862a | EUI-64 000a35011bd0862a Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent f656edd commit 76fdb3a

File tree

5 files changed

+396
-1
lines changed

5 files changed

+396
-1
lines changed

sound/firewire/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,5 +158,6 @@ config SND_FIREFACE
158158
select SND_HWDEP
159159
help
160160
Say Y here to include support for RME fireface series.
161+
* Fireface 400
161162

162163
endif # SND_FIREWIRE

sound/firewire/fireface/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \
2-
ff-stream.o ff-pcm.o ff-hwdep.o
2+
ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o
33
obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o
Lines changed: 371 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,371 @@
1+
/*
2+
* ff-protocol-ff400.c - a part of driver for RME Fireface series
3+
*
4+
* Copyright (c) 2015-2017 Takashi Sakamoto
5+
*
6+
* Licensed under the terms of the GNU General Public License, version 2.
7+
*/
8+
9+
#include <linux/delay.h>
10+
#include "ff.h"
11+
12+
#define FF400_STF 0x000080100500ull
13+
#define FF400_RX_PACKET_FORMAT 0x000080100504ull
14+
#define FF400_ISOC_COMM_START 0x000080100508ull
15+
#define FF400_TX_PACKET_FORMAT 0x00008010050cull
16+
#define FF400_ISOC_COMM_STOP 0x000080100510ull
17+
#define FF400_SYNC_STATUS 0x0000801c0000ull
18+
#define FF400_FETCH_PCM_FRAMES 0x0000801c0000ull /* For block request. */
19+
#define FF400_CLOCK_CONFIG 0x0000801c0004ull
20+
21+
#define FF400_MIDI_HIGH_ADDR 0x0000801003f4ull
22+
#define FF400_MIDI_RX_PORT_0 0x000080180000ull
23+
#define FF400_MIDI_RX_PORT_1 0x000080190000ull
24+
25+
static int ff400_get_clock(struct snd_ff *ff, unsigned int *rate,
26+
enum snd_ff_clock_src *src)
27+
{
28+
__le32 reg;
29+
u32 data;
30+
int err;
31+
32+
err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
33+
FF400_SYNC_STATUS, &reg, sizeof(reg), 0);
34+
if (err < 0)
35+
return err;
36+
data = le32_to_cpu(reg);
37+
38+
/* Calculate sampling rate. */
39+
switch ((data >> 1) & 0x03) {
40+
case 0x01:
41+
*rate = 32000;
42+
break;
43+
case 0x00:
44+
*rate = 44100;
45+
break;
46+
case 0x03:
47+
*rate = 48000;
48+
break;
49+
case 0x02:
50+
default:
51+
return -EIO;
52+
}
53+
54+
if (data & 0x08)
55+
*rate *= 2;
56+
else if (data & 0x10)
57+
*rate *= 4;
58+
59+
/* Calculate source of clock. */
60+
if (data & 0x01) {
61+
*src = SND_FF_CLOCK_SRC_INTERNAL;
62+
} else {
63+
/* TODO: 0x00, 0x01, 0x02, 0x06, 0x07? */
64+
switch ((data >> 10) & 0x07) {
65+
case 0x03:
66+
*src = SND_FF_CLOCK_SRC_SPDIF;
67+
break;
68+
case 0x04:
69+
*src = SND_FF_CLOCK_SRC_WORD;
70+
break;
71+
case 0x05:
72+
*src = SND_FF_CLOCK_SRC_LTC;
73+
break;
74+
case 0x00:
75+
default:
76+
*src = SND_FF_CLOCK_SRC_ADAT;
77+
break;
78+
}
79+
}
80+
81+
return 0;
82+
}
83+
84+
static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
85+
{
86+
__le32 reg;
87+
int i, err;
88+
89+
/* Check whether the given value is supported or not. */
90+
for (i = 0; i < CIP_SFC_COUNT; i++) {
91+
if (amdtp_rate_table[i] == rate)
92+
break;
93+
}
94+
if (i == CIP_SFC_COUNT)
95+
return -EINVAL;
96+
97+
/* Set the number of data blocks transferred in a second. */
98+
reg = cpu_to_le32(rate);
99+
err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
100+
FF400_STF, &reg, sizeof(reg), 0);
101+
if (err < 0)
102+
return err;
103+
104+
msleep(100);
105+
106+
/*
107+
* Set isochronous channel and the number of quadlets of received
108+
* packets.
109+
*/
110+
reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) |
111+
ff->rx_resources.channel);
112+
err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
113+
FF400_RX_PACKET_FORMAT, &reg, sizeof(reg), 0);
114+
if (err < 0)
115+
return err;
116+
117+
/*
118+
* Set isochronous channel and the number of quadlets of transmitted
119+
* packet.
120+
*/
121+
/* TODO: investigate the purpose of this 0x80. */
122+
reg = cpu_to_le32((0x80 << 24) |
123+
(ff->tx_resources.channel << 5) |
124+
(ff->tx_stream.data_block_quadlets));
125+
err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
126+
FF400_TX_PACKET_FORMAT, &reg, sizeof(reg), 0);
127+
if (err < 0)
128+
return err;
129+
130+
/* Allow to transmit packets. */
131+
reg = cpu_to_le32(0x00000001);
132+
return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
133+
FF400_ISOC_COMM_START, &reg, sizeof(reg), 0);
134+
}
135+
136+
static void ff400_finish_session(struct snd_ff *ff)
137+
{
138+
__le32 reg;
139+
140+
reg = cpu_to_le32(0x80000000);
141+
snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
142+
FF400_ISOC_COMM_STOP, &reg, sizeof(reg), 0);
143+
}
144+
145+
static int ff400_switch_fetching_mode(struct snd_ff *ff, bool enable)
146+
{
147+
__le32 *reg;
148+
int i;
149+
150+
reg = kzalloc(sizeof(__le32) * 18, GFP_KERNEL);
151+
if (reg == NULL)
152+
return -ENOMEM;
153+
154+
if (enable) {
155+
/*
156+
* Each quadlet is corresponding to data channels in a data
157+
* blocks in reverse order. Precisely, quadlets for available
158+
* data channels should be enabled. Here, I take second best
159+
* to fetch PCM frames from all of data channels regardless of
160+
* stf.
161+
*/
162+
for (i = 0; i < 18; ++i)
163+
reg[i] = cpu_to_le32(0x00000001);
164+
}
165+
166+
return snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST,
167+
FF400_FETCH_PCM_FRAMES, reg,
168+
sizeof(__le32) * 18, 0);
169+
}
170+
171+
static void ff400_dump_sync_status(struct snd_ff *ff,
172+
struct snd_info_buffer *buffer)
173+
{
174+
__le32 reg;
175+
u32 data;
176+
int err;
177+
178+
err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
179+
FF400_SYNC_STATUS, &reg, sizeof(reg), 0);
180+
if (err < 0)
181+
return;
182+
183+
data = le32_to_cpu(reg);
184+
185+
snd_iprintf(buffer, "External source detection:\n");
186+
187+
snd_iprintf(buffer, "Word Clock:");
188+
if ((data >> 24) & 0x20) {
189+
if ((data >> 24) & 0x40)
190+
snd_iprintf(buffer, "sync\n");
191+
else
192+
snd_iprintf(buffer, "lock\n");
193+
} else {
194+
snd_iprintf(buffer, "none\n");
195+
}
196+
197+
snd_iprintf(buffer, "S/PDIF:");
198+
if ((data >> 16) & 0x10) {
199+
if ((data >> 16) & 0x04)
200+
snd_iprintf(buffer, "sync\n");
201+
else
202+
snd_iprintf(buffer, "lock\n");
203+
} else {
204+
snd_iprintf(buffer, "none\n");
205+
}
206+
207+
snd_iprintf(buffer, "ADAT:");
208+
if ((data >> 8) & 0x04) {
209+
if ((data >> 8) & 0x10)
210+
snd_iprintf(buffer, "sync\n");
211+
else
212+
snd_iprintf(buffer, "lock\n");
213+
} else {
214+
snd_iprintf(buffer, "none\n");
215+
}
216+
217+
snd_iprintf(buffer, "\nUsed external source:\n");
218+
219+
if (((data >> 22) & 0x07) == 0x07) {
220+
snd_iprintf(buffer, "None\n");
221+
} else {
222+
switch ((data >> 22) & 0x07) {
223+
case 0x00:
224+
snd_iprintf(buffer, "ADAT:");
225+
break;
226+
case 0x03:
227+
snd_iprintf(buffer, "S/PDIF:");
228+
break;
229+
case 0x04:
230+
snd_iprintf(buffer, "Word:");
231+
break;
232+
case 0x07:
233+
snd_iprintf(buffer, "Nothing:");
234+
break;
235+
case 0x01:
236+
case 0x02:
237+
case 0x05:
238+
case 0x06:
239+
default:
240+
snd_iprintf(buffer, "unknown:");
241+
break;
242+
}
243+
244+
if ((data >> 25) & 0x07) {
245+
switch ((data >> 25) & 0x07) {
246+
case 0x01:
247+
snd_iprintf(buffer, "32000\n");
248+
break;
249+
case 0x02:
250+
snd_iprintf(buffer, "44100\n");
251+
break;
252+
case 0x03:
253+
snd_iprintf(buffer, "48000\n");
254+
break;
255+
case 0x04:
256+
snd_iprintf(buffer, "64000\n");
257+
break;
258+
case 0x05:
259+
snd_iprintf(buffer, "88200\n");
260+
break;
261+
case 0x06:
262+
snd_iprintf(buffer, "96000\n");
263+
break;
264+
case 0x07:
265+
snd_iprintf(buffer, "128000\n");
266+
break;
267+
case 0x08:
268+
snd_iprintf(buffer, "176400\n");
269+
break;
270+
case 0x09:
271+
snd_iprintf(buffer, "192000\n");
272+
break;
273+
case 0x00:
274+
snd_iprintf(buffer, "unknown\n");
275+
break;
276+
}
277+
}
278+
}
279+
280+
snd_iprintf(buffer, "Multiplied:");
281+
snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
282+
}
283+
284+
static void ff400_dump_clock_config(struct snd_ff *ff,
285+
struct snd_info_buffer *buffer)
286+
{
287+
__le32 reg;
288+
u32 data;
289+
unsigned int rate;
290+
const char *src;
291+
int err;
292+
293+
err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
294+
FF400_CLOCK_CONFIG, &reg, sizeof(reg), 0);
295+
if (err < 0)
296+
return;
297+
298+
data = le32_to_cpu(reg);
299+
300+
snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
301+
(data & 0x20) ? "Professional" : "Consumer",
302+
(data & 0x40) ? "on" : "off");
303+
304+
snd_iprintf(buffer, "Optical output interface format: %s\n",
305+
((data >> 8) & 0x01) ? "S/PDIF" : "ADAT");
306+
307+
snd_iprintf(buffer, "Word output single speed: %s\n",
308+
((data >> 8) & 0x20) ? "on" : "off");
309+
310+
snd_iprintf(buffer, "S/PDIF input interface: %s\n",
311+
((data >> 8) & 0x02) ? "Optical" : "Coaxial");
312+
313+
switch ((data >> 1) & 0x03) {
314+
case 0x01:
315+
rate = 32000;
316+
break;
317+
case 0x00:
318+
rate = 44100;
319+
break;
320+
case 0x03:
321+
rate = 48000;
322+
break;
323+
case 0x02:
324+
default:
325+
return;
326+
}
327+
328+
if (data & 0x08)
329+
rate *= 2;
330+
else if (data & 0x10)
331+
rate *= 4;
332+
333+
snd_iprintf(buffer, "Sampling rate: %d\n", rate);
334+
335+
if (data & 0x01) {
336+
src = "Internal";
337+
} else {
338+
switch ((data >> 10) & 0x07) {
339+
case 0x00:
340+
src = "ADAT";
341+
break;
342+
case 0x03:
343+
src = "S/PDIF";
344+
break;
345+
case 0x04:
346+
src = "Word";
347+
break;
348+
case 0x05:
349+
src = "LTC";
350+
break;
351+
default:
352+
return;
353+
}
354+
}
355+
356+
snd_iprintf(buffer, "Sync to clock source: %s\n", src);
357+
}
358+
359+
struct snd_ff_protocol snd_ff_protocol_ff400 = {
360+
.get_clock = ff400_get_clock,
361+
.begin_session = ff400_begin_session,
362+
.finish_session = ff400_finish_session,
363+
.switch_fetching_mode = ff400_switch_fetching_mode,
364+
365+
.dump_sync_status = ff400_dump_sync_status,
366+
.dump_clock_config = ff400_dump_clock_config,
367+
368+
.midi_high_addr_reg = FF400_MIDI_HIGH_ADDR,
369+
.midi_rx_port_0_reg = FF400_MIDI_RX_PORT_0,
370+
.midi_rx_port_1_reg = FF400_MIDI_RX_PORT_1,
371+
};

0 commit comments

Comments
 (0)