Commit 35033d8c authored by Takashi Sakamoto's avatar Takashi Sakamoto Committed by Takashi Iwai

ALSA: firewire-motu: add support MOTU 8pre FireWire

This commit adds support for MOTU 8pre FireWire, which was shipped 2007
and nowadays already discontinued. Userspace applications can transmit
and receive PCM frames and MIDI messages for this model via ALSA PCM
interface and RawMidi/Sequencer interfaces.

Like the other models of MOTU FireWire series, this model has many
quirks in its CIP.

At first, data channels for two pairs of optical interfaces. At lower
sampling transmission frequency, i.e. 44.1 and 48.0 kHz, one pair is
available for ADAT data, thus 8 data chunks are transferred by CIP.
At middle sampling transmission frequency, i.e.  88.2 and 96.0 kHz,
two pairs are available to keep 8 chunks for ADAT data, thus CIP
still includes 8 data chunks.

Apart from data chunks for optical interface, CIP includes fixed number
of data chunks. In tx stream, two chunks for status message, eight
chunks for samples from analog 1-8 input, two chunks for mix-return.
In rx stream, two chunks for control message, two chunks for main 1-2
output, two chunks for phone 1-2 output, two chunks for dummy 1-2.

CIP header in tx stream includes quirks for its dbs and dbc fields.
The value of dbs field is fixed to 0x13, against its actual size.
The value of dbc field is firstly updated to 0x07 from zero, then
it's incremented continuously according to actual number of data h
blocks.

Finally, the model has own bits to disable frame fetch.

This commit uses several options to absorb the above quirks.

$ python2 crpp < /sys/bus/firewire/devices/fw1/config_rom
               ROM header and bus information block
               -----------------------------------------------------------------
400  0410b57d  bus_info_length 4, crc_length 16, crc 46461
404  31333934  bus_name "1394"
408  20001000  irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 0, max_rec 1 (4)
40c  0001f200  company_id 0001f2     |
410  00083dfb  device_id 0000083dfb  | EUI-64 0001f20000083dfb

               root directory
               -----------------------------------------------------------------
414  0004c65c  directory_length 4, crc 50780
418  030001f2  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  0003991c  directory_length 3, crc 39196
42c  120001f2  specifier id
430  1300000f  version
434  17103800  model

               eui-64 leaf at 438
               -----------------------------------------------------------------
438  00022681  leaf_length 2, crc 9857
43c  0001f200  company_id 0001f2     |
440  00083dfb  device_id 0000083dfb  | EUI-64 0001f20000083dfb
Signed-off-by: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent b3f5c0f3
...@@ -412,6 +412,12 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, ...@@ -412,6 +412,12 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
CIP_HEADER_WITHOUT_EOH; CIP_HEADER_WITHOUT_EOH;
fmt = CIP_FMT_MOTU_TX_V3; fmt = CIP_FMT_MOTU_TX_V3;
} }
if (protocol == &snd_motu_protocol_v2) {
// 8pre has some quirks.
flags |= CIP_WRONG_DBS |
CIP_SKIP_DBC_ZERO_CHECK;
}
} else { } else {
process_data_blocks = process_rx_data_blocks; process_data_blocks = process_rx_data_blocks;
flags |= CIP_DBC_IS_END_EVENT; flags |= CIP_DBC_IS_END_EVENT;
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#define V2_CLOCK_SRC_SHIFT 0 #define V2_CLOCK_SRC_SHIFT 0
#define V2_CLOCK_TRAVELER_FETCH_DISABLE 0x04000000 #define V2_CLOCK_TRAVELER_FETCH_DISABLE 0x04000000
#define V2_CLOCK_TRAVELER_FETCH_ENABLE 0x03000000 #define V2_CLOCK_TRAVELER_FETCH_ENABLE 0x03000000
#define V2_CLOCK_8PRE_FETCH_DISABLE 0x02000000
#define V2_CLOCK_8PRE_FETCH_ENABLE 0x00000000
#define V2_IN_OUT_CONF_OFFSET 0x0c04 #define V2_IN_OUT_CONF_OFFSET 0x0c04
#define V2_OPT_OUT_IFACE_MASK 0x00000c00 #define V2_OPT_OUT_IFACE_MASK 0x00000c00
...@@ -132,20 +134,31 @@ static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable) ...@@ -132,20 +134,31 @@ static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable)
u32 data; u32 data;
int err = 0; int err = 0;
if (motu->spec == &snd_motu_spec_traveler) { if (motu->spec == &snd_motu_spec_traveler ||
motu->spec == &snd_motu_spec_8pre) {
err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,
&reg, sizeof(reg)); &reg, sizeof(reg));
if (err < 0) if (err < 0)
return err; return err;
data = be32_to_cpu(reg); data = be32_to_cpu(reg);
data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE | if (motu->spec == &snd_motu_spec_traveler) {
V2_CLOCK_TRAVELER_FETCH_ENABLE); data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE |
V2_CLOCK_TRAVELER_FETCH_ENABLE);
if (enable)
data |= V2_CLOCK_TRAVELER_FETCH_ENABLE; if (enable)
else data |= V2_CLOCK_TRAVELER_FETCH_ENABLE;
data |= V2_CLOCK_TRAVELER_FETCH_DISABLE; else
data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
} else if (motu->spec == &snd_motu_spec_8pre) {
data &= ~(V2_CLOCK_8PRE_FETCH_DISABLE |
V2_CLOCK_8PRE_FETCH_ENABLE);
if (enable)
data |= V2_CLOCK_8PRE_FETCH_DISABLE;
else
data |= V2_CLOCK_8PRE_FETCH_ENABLE;
}
reg = cpu_to_be32(data); reg = cpu_to_be32(data);
err = snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, err = snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,
...@@ -220,10 +233,16 @@ static void calculate_differed_part(struct snd_motu_packet_format *formats, ...@@ -220,10 +233,16 @@ static void calculate_differed_part(struct snd_motu_packet_format *formats,
* interfaces. * interfaces.
*/ */
data = (data & mask) >> shift; data = (data & mask) >> shift;
if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) && if (data == V2_OPT_IFACE_MODE_ADAT) {
data == V2_OPT_IFACE_MODE_ADAT) { if (flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) {
pcm_chunks[0] += 8; pcm_chunks[0] += 8;
pcm_chunks[1] += 4; pcm_chunks[1] += 4;
}
// 8pre has two sets of optical interface and doesn't reduce
// chunks for ADAT signals.
if (flags & SND_MOTU_SPEC_HAS_OPT_IFACE_B) {
pcm_chunks[1] += 4;
}
} }
/* At mode x4, no data chunks are supported in this part. */ /* At mode x4, no data chunks are supported in this part. */
......
...@@ -203,6 +203,20 @@ const struct snd_motu_spec snd_motu_spec_traveler = { ...@@ -203,6 +203,20 @@ const struct snd_motu_spec snd_motu_spec_traveler = {
.analog_out_ports = 8, .analog_out_ports = 8,
}; };
const struct snd_motu_spec snd_motu_spec_8pre = {
.name = "8pre",
.protocol = &snd_motu_protocol_v2,
// In tx, use coax chunks for mix-return 1/2. In rx, use coax chunks for
// dummy 1/2.
.flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
SND_MOTU_SPEC_HAS_OPT_IFACE_A |
SND_MOTU_SPEC_HAS_OPT_IFACE_B |
SND_MOTU_SPEC_RX_MIDI_2ND_Q |
SND_MOTU_SPEC_TX_MIDI_2ND_Q,
.analog_in_ports = 8,
.analog_out_ports = 2,
};
static const struct snd_motu_spec motu_828mk3 = { static const struct snd_motu_spec motu_828mk3 = {
.name = "828mk3", .name = "828mk3",
.protocol = &snd_motu_protocol_v3, .protocol = &snd_motu_protocol_v3,
...@@ -248,6 +262,7 @@ static const struct snd_motu_spec motu_audio_express = { ...@@ -248,6 +262,7 @@ static const struct snd_motu_spec motu_audio_express = {
static const struct ieee1394_device_id motu_id_table[] = { static const struct ieee1394_device_id motu_id_table[] = {
SND_MOTU_DEV_ENTRY(0x000003, &motu_828mk2), SND_MOTU_DEV_ENTRY(0x000003, &motu_828mk2),
SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler), SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler),
SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre),
SND_MOTU_DEV_ENTRY(0x000015, &motu_828mk3), /* FireWire only. */ SND_MOTU_DEV_ENTRY(0x000015, &motu_828mk3), /* FireWire only. */
SND_MOTU_DEV_ENTRY(0x000035, &motu_828mk3), /* Hybrid. */ SND_MOTU_DEV_ENTRY(0x000035, &motu_828mk3), /* Hybrid. */
SND_MOTU_DEV_ENTRY(0x000033, &motu_audio_express), SND_MOTU_DEV_ENTRY(0x000033, &motu_audio_express),
......
...@@ -130,6 +130,7 @@ extern const struct snd_motu_protocol snd_motu_protocol_v2; ...@@ -130,6 +130,7 @@ extern const struct snd_motu_protocol snd_motu_protocol_v2;
extern const struct snd_motu_protocol snd_motu_protocol_v3; extern const struct snd_motu_protocol snd_motu_protocol_v3;
extern const struct snd_motu_spec snd_motu_spec_traveler; extern const struct snd_motu_spec snd_motu_spec_traveler;
extern const struct snd_motu_spec snd_motu_spec_8pre;
int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir, enum amdtp_stream_direction dir,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment