remarkable-linux/sound/firewire/motu/motu.h
Takashi Sakamoto 5992e30034 ALSA: firewire-motu: add support for MOTU 828mk3 (FireWire/Hybrid) as a model with protocol version 3
MOTU 828mk3 (FireWire/Hybrid) is one of third generation in MOTU FireWire
series, produced in 2008/2014. This model consists of three chips for
functionality on IEEE 1394 bus:

 * TI TSB41AB2 (Physical layer for IEEE 1394 bus)
 * Xilinx Spartan-3E FPGA Family (Link layer for IEEE 1394 bus, packet
   processing and data block processing layer)
 * TI TMS320C6722 (Digital signal processing)

This commit adds a support for this model, with its unique protocol as
version 3. This protocol has some additional features to protocol
version 2.

 * Support several optical interfaces.
 * Support a data chunk for return of reverb effect.
 * Have a quirk of tx packets.
 * Support heartbeat asynchronous transaction.

In this protocol, series of transferred packets has some quirks. Below
fields in CIP headers of the packets are out of IEC 61883-1:
 - SID (source node id): always 0x0d
 - DBS (data block size): always 0x04
 - DBC (data block counter): always 0x00
 - EOH (End of header): always 0x00

Below is an actual sample of transferred packets.

quads CIP1       CIP2
520   0x0D040400 0x22FFFFFF
  8   0x0D040400 0x22FFFFFF
520   0x0D040400 0x22FFFFFF
520   0x0D040400 0x22FFFFFF
  8   0x0D040400 0x22FFFFFF

Status of clock is configured by write transactions to 0x'ffff'f000'0b14,
as well as version 2, while meanings of fields are different from the
former protocols. Modes of optical interfaces are configured by write
transactions to 0x'ffff'f000'0c94.

Drivers can register its address to receive heatbeat transactions from the
unit. 0x'ffff'f000'0b0c is for the higher part and 0x'ffff'f000'0b10 is
for the lower part. Nevertheless, this feature is not useless for this
driver and this commit omits it.

Each data block consists of two parts in a point of the number of included
data chunks. In both of 'fixed' and 'differed' parts, the number of
included data blocks are a multiple of 4, thus depending on models there's
some empty data chunks. For example, 828mk3 includes one pair of empty
data chunks in its fixed part. When optical interface is configured to
S/PDIF, 828mk3 includes one pair of empty data chunks in its differed part.
To reduce consumption of CPU cycles with additional conditions/loops, this
commit just exposes these empty chunks to user space as PCM channels.

Additionally, 828mk3 has a non-negligible overhead to change its sampling
transfer frequency. When softwares send asynchronous transaction to
perform it, LED on the unit starts to blink. In a worst case, it continues
blink during several seconds; e.g. 10 seconds. When stopping blinking,
the unit seems to be prepared for the requested sampling transfer
frequency. To wait for the preparation, this commit forces the driver
to call task scheduler and applications sleeps for 4 seconds.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2017-03-28 12:34:13 +02:00

162 lines
4.9 KiB
C

/*
* motu.h - a part of driver for MOTU FireWire series
*
* Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
*
* Licensed under the terms of the GNU General Public License, version 2.
*/
#ifndef SOUND_FIREWIRE_MOTU_H_INCLUDED
#define SOUND_FIREWIRE_MOTU_H_INCLUDED
#include <linux/device.h>
#include <linux/firewire.h>
#include <linux/firewire-constants.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/sched/signal.h>
#include <sound/control.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/info.h>
#include <sound/rawmidi.h>
#include <sound/firewire.h>
#include <sound/hwdep.h>
#include "../lib.h"
#include "../amdtp-stream.h"
#include "../iso-resources.h"
struct snd_motu_packet_format {
unsigned char midi_flag_offset;
unsigned char midi_byte_offset;
unsigned char pcm_byte_offset;
unsigned char msg_chunks;
unsigned char fixed_part_pcm_chunks[3];
unsigned char differed_part_pcm_chunks[3];
};
struct snd_motu {
struct snd_card *card;
struct fw_unit *unit;
struct mutex mutex;
spinlock_t lock;
bool registered;
struct delayed_work dwork;
/* Model dependent information. */
const struct snd_motu_spec *spec;
/* For packet streaming */
struct snd_motu_packet_format tx_packet_formats;
struct snd_motu_packet_format rx_packet_formats;
struct amdtp_stream tx_stream;
struct amdtp_stream rx_stream;
struct fw_iso_resources tx_resources;
struct fw_iso_resources rx_resources;
unsigned int capture_substreams;
unsigned int playback_substreams;
/* For notification. */
struct fw_address_handler async_handler;
u32 msg;
/* For uapi */
int dev_lock_count;
bool dev_lock_changed;
wait_queue_head_t hwdep_wait;
};
enum snd_motu_spec_flags {
SND_MOTU_SPEC_SUPPORT_CLOCK_X2 = 0x0001,
SND_MOTU_SPEC_SUPPORT_CLOCK_X4 = 0x0002,
SND_MOTU_SPEC_TX_MICINST_CHUNK = 0x0004,
SND_MOTU_SPEC_TX_RETURN_CHUNK = 0x0008,
SND_MOTU_SPEC_TX_REVERB_CHUNK = 0x0010,
SND_MOTU_SPEC_TX_AESEBU_CHUNK = 0x0020,
SND_MOTU_SPEC_HAS_OPT_IFACE_A = 0x0040,
SND_MOTU_SPEC_HAS_OPT_IFACE_B = 0x0080,
SND_MOTU_SPEC_HAS_MIDI = 0x0100,
};
#define SND_MOTU_CLOCK_RATE_COUNT 6
extern const unsigned int snd_motu_clock_rates[SND_MOTU_CLOCK_RATE_COUNT];
enum snd_motu_clock_source {
SND_MOTU_CLOCK_SOURCE_INTERNAL,
SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB,
SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT,
SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A,
SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B,
SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT,
SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A,
SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B,
SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX,
SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR,
SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC,
SND_MOTU_CLOCK_SOURCE_UNKNOWN,
};
struct snd_motu_protocol {
int (*get_clock_rate)(struct snd_motu *motu, unsigned int *rate);
int (*set_clock_rate)(struct snd_motu *motu, unsigned int rate);
int (*get_clock_source)(struct snd_motu *motu,
enum snd_motu_clock_source *source);
int (*switch_fetching_mode)(struct snd_motu *motu, bool enable);
int (*cache_packet_formats)(struct snd_motu *motu);
};
struct snd_motu_spec {
const char *const name;
enum snd_motu_spec_flags flags;
unsigned char analog_in_ports;
unsigned char analog_out_ports;
const struct snd_motu_protocol *const protocol;
};
extern const struct snd_motu_protocol snd_motu_protocol_v2;
extern const struct snd_motu_protocol snd_motu_protocol_v3;
int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir,
const struct snd_motu_protocol *const protocol);
int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate,
unsigned int midi_ports,
struct snd_motu_packet_format *formats);
int amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s,
struct snd_pcm_runtime *runtime);
void amdtp_motu_midi_trigger(struct amdtp_stream *s, unsigned int port,
struct snd_rawmidi_substream *midi);
int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
size_t size);
int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
size_t size);
int snd_motu_transaction_register(struct snd_motu *motu);
int snd_motu_transaction_reregister(struct snd_motu *motu);
void snd_motu_transaction_unregister(struct snd_motu *motu);
int snd_motu_stream_init_duplex(struct snd_motu *motu);
void snd_motu_stream_destroy_duplex(struct snd_motu *motu);
int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate);
void snd_motu_stream_stop_duplex(struct snd_motu *motu);
int snd_motu_stream_lock_try(struct snd_motu *motu);
void snd_motu_stream_lock_release(struct snd_motu *motu);
void snd_motu_proc_init(struct snd_motu *motu);
int snd_motu_create_pcm_devices(struct snd_motu *motu);
int snd_motu_create_midi_devices(struct snd_motu *motu);
int snd_motu_create_hwdep_device(struct snd_motu *motu);
#endif