162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * motu.h - a part of driver for MOTU FireWire series
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifndef SOUND_FIREWIRE_MOTU_H_INCLUDED
962306a36Sopenharmony_ci#define SOUND_FIREWIRE_MOTU_H_INCLUDED
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/device.h>
1262306a36Sopenharmony_ci#include <linux/firewire.h>
1362306a36Sopenharmony_ci#include <linux/firewire-constants.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1662306a36Sopenharmony_ci#include <linux/mutex.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/compat.h>
1962306a36Sopenharmony_ci#include <linux/sched/signal.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <sound/control.h>
2262306a36Sopenharmony_ci#include <sound/core.h>
2362306a36Sopenharmony_ci#include <sound/pcm.h>
2462306a36Sopenharmony_ci#include <sound/info.h>
2562306a36Sopenharmony_ci#include <sound/rawmidi.h>
2662306a36Sopenharmony_ci#include <sound/firewire.h>
2762306a36Sopenharmony_ci#include <sound/hwdep.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "../lib.h"
3062306a36Sopenharmony_ci#include "../amdtp-stream.h"
3162306a36Sopenharmony_ci#include "../iso-resources.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistruct snd_motu_packet_format {
3462306a36Sopenharmony_ci	unsigned char midi_flag_offset;
3562306a36Sopenharmony_ci	unsigned char midi_byte_offset;
3662306a36Sopenharmony_ci	unsigned char pcm_byte_offset;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	unsigned char msg_chunks;
3962306a36Sopenharmony_ci	unsigned char pcm_chunks[3];
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistruct amdtp_motu_cache {
4362306a36Sopenharmony_ci	unsigned int *event_offsets;
4462306a36Sopenharmony_ci	unsigned int size;
4562306a36Sopenharmony_ci	unsigned int tail;
4662306a36Sopenharmony_ci	unsigned int tx_cycle_count;
4762306a36Sopenharmony_ci	unsigned int head;
4862306a36Sopenharmony_ci	unsigned int rx_cycle_count;
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistruct snd_motu {
5262306a36Sopenharmony_ci	struct snd_card *card;
5362306a36Sopenharmony_ci	struct fw_unit *unit;
5462306a36Sopenharmony_ci	struct mutex mutex;
5562306a36Sopenharmony_ci	spinlock_t lock;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	/* Model dependent information. */
5862306a36Sopenharmony_ci	const struct snd_motu_spec *spec;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/* For packet streaming */
6162306a36Sopenharmony_ci	struct snd_motu_packet_format tx_packet_formats;
6262306a36Sopenharmony_ci	struct snd_motu_packet_format rx_packet_formats;
6362306a36Sopenharmony_ci	struct amdtp_stream tx_stream;
6462306a36Sopenharmony_ci	struct amdtp_stream rx_stream;
6562306a36Sopenharmony_ci	struct fw_iso_resources tx_resources;
6662306a36Sopenharmony_ci	struct fw_iso_resources rx_resources;
6762306a36Sopenharmony_ci	unsigned int substreams_counter;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* For notification. */
7062306a36Sopenharmony_ci	struct fw_address_handler async_handler;
7162306a36Sopenharmony_ci	u32 msg;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	/* For uapi */
7462306a36Sopenharmony_ci	int dev_lock_count;
7562306a36Sopenharmony_ci	bool dev_lock_changed;
7662306a36Sopenharmony_ci	wait_queue_head_t hwdep_wait;
7762306a36Sopenharmony_ci	struct snd_hwdep *hwdep;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	struct amdtp_domain domain;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	struct amdtp_motu_cache cache;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	void *message_parser;
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cienum snd_motu_spec_flags {
8762306a36Sopenharmony_ci	SND_MOTU_SPEC_RX_MIDI_2ND_Q	= 0x0001,
8862306a36Sopenharmony_ci	SND_MOTU_SPEC_RX_MIDI_3RD_Q	= 0x0002,
8962306a36Sopenharmony_ci	SND_MOTU_SPEC_TX_MIDI_2ND_Q	= 0x0004,
9062306a36Sopenharmony_ci	SND_MOTU_SPEC_TX_MIDI_3RD_Q	= 0x0008,
9162306a36Sopenharmony_ci	SND_MOTU_SPEC_REGISTER_DSP	= 0x0010,
9262306a36Sopenharmony_ci	SND_MOTU_SPEC_COMMAND_DSP	= 0x0020,
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define SND_MOTU_CLOCK_RATE_COUNT	6
9662306a36Sopenharmony_ciextern const unsigned int snd_motu_clock_rates[SND_MOTU_CLOCK_RATE_COUNT];
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cienum snd_motu_clock_source {
9962306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_INTERNAL,
10062306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB,
10162306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT,
10262306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A,
10362306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B,
10462306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT,
10562306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A,
10662306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B,
10762306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX,
10862306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR,
10962306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC,
11062306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_SPH,
11162306a36Sopenharmony_ci	SND_MOTU_CLOCK_SOURCE_UNKNOWN,
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cienum snd_motu_protocol_version {
11562306a36Sopenharmony_ci	SND_MOTU_PROTOCOL_V1,
11662306a36Sopenharmony_ci	SND_MOTU_PROTOCOL_V2,
11762306a36Sopenharmony_ci	SND_MOTU_PROTOCOL_V3,
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistruct snd_motu_spec {
12162306a36Sopenharmony_ci	const char *const name;
12262306a36Sopenharmony_ci	enum snd_motu_protocol_version protocol_version;
12362306a36Sopenharmony_ci	// The combination of snd_motu_spec_flags enumeration-constants.
12462306a36Sopenharmony_ci	unsigned int flags;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	unsigned char tx_fixed_pcm_chunks[3];
12762306a36Sopenharmony_ci	unsigned char rx_fixed_pcm_chunks[3];
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_828;
13162306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_896;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_828mk2;
13462306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_896hd;
13562306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_traveler;
13662306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_ultralite;
13762306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_8pre;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_828mk3_fw;
14062306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_828mk3_hybrid;
14162306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_traveler_mk3;
14262306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_ultralite_mk3;
14362306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_audio_express;
14462306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_track16;
14562306a36Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_4pre;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ciint amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
14862306a36Sopenharmony_ci		    enum amdtp_stream_direction dir,
14962306a36Sopenharmony_ci		    const struct snd_motu_spec *spec,
15062306a36Sopenharmony_ci		    struct amdtp_motu_cache *cache);
15162306a36Sopenharmony_ciint amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate,
15262306a36Sopenharmony_ci			      unsigned int midi_ports,
15362306a36Sopenharmony_ci			      struct snd_motu_packet_format *formats);
15462306a36Sopenharmony_ciint amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s,
15562306a36Sopenharmony_ci				      struct snd_pcm_runtime *runtime);
15662306a36Sopenharmony_civoid amdtp_motu_midi_trigger(struct amdtp_stream *s, unsigned int port,
15762306a36Sopenharmony_ci			     struct snd_rawmidi_substream *midi);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ciint snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
16062306a36Sopenharmony_ci			      size_t size);
16162306a36Sopenharmony_ciint snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
16262306a36Sopenharmony_ci			       size_t size);
16362306a36Sopenharmony_ciint snd_motu_transaction_register(struct snd_motu *motu);
16462306a36Sopenharmony_ciint snd_motu_transaction_reregister(struct snd_motu *motu);
16562306a36Sopenharmony_civoid snd_motu_transaction_unregister(struct snd_motu *motu);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ciint snd_motu_stream_init_duplex(struct snd_motu *motu);
16862306a36Sopenharmony_civoid snd_motu_stream_destroy_duplex(struct snd_motu *motu);
16962306a36Sopenharmony_ciint snd_motu_stream_cache_packet_formats(struct snd_motu *motu);
17062306a36Sopenharmony_ciint snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
17162306a36Sopenharmony_ci				   unsigned int frames_per_period,
17262306a36Sopenharmony_ci				   unsigned int frames_per_buffer);
17362306a36Sopenharmony_ciint snd_motu_stream_start_duplex(struct snd_motu *motu);
17462306a36Sopenharmony_civoid snd_motu_stream_stop_duplex(struct snd_motu *motu);
17562306a36Sopenharmony_ciint snd_motu_stream_lock_try(struct snd_motu *motu);
17662306a36Sopenharmony_civoid snd_motu_stream_lock_release(struct snd_motu *motu);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_civoid snd_motu_proc_init(struct snd_motu *motu);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ciint snd_motu_create_pcm_devices(struct snd_motu *motu);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ciint snd_motu_create_midi_devices(struct snd_motu *motu);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ciint snd_motu_create_hwdep_device(struct snd_motu *motu);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ciint snd_motu_protocol_v1_get_clock_rate(struct snd_motu *motu,
18762306a36Sopenharmony_ci					unsigned int *rate);
18862306a36Sopenharmony_ciint snd_motu_protocol_v1_set_clock_rate(struct snd_motu *motu,
18962306a36Sopenharmony_ci					unsigned int rate);
19062306a36Sopenharmony_ciint snd_motu_protocol_v1_get_clock_source(struct snd_motu *motu,
19162306a36Sopenharmony_ci					  enum snd_motu_clock_source *src);
19262306a36Sopenharmony_ciint snd_motu_protocol_v1_switch_fetching_mode(struct snd_motu *motu,
19362306a36Sopenharmony_ci					      bool enable);
19462306a36Sopenharmony_ciint snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ciint snd_motu_protocol_v2_get_clock_rate(struct snd_motu *motu,
19762306a36Sopenharmony_ci					unsigned int *rate);
19862306a36Sopenharmony_ciint snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu,
19962306a36Sopenharmony_ci					unsigned int rate);
20062306a36Sopenharmony_ciint snd_motu_protocol_v2_get_clock_source(struct snd_motu *motu,
20162306a36Sopenharmony_ci					  enum snd_motu_clock_source *src);
20262306a36Sopenharmony_ciint snd_motu_protocol_v2_switch_fetching_mode(struct snd_motu *motu,
20362306a36Sopenharmony_ci					      bool enable);
20462306a36Sopenharmony_ciint snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ciint snd_motu_protocol_v3_get_clock_rate(struct snd_motu *motu,
20762306a36Sopenharmony_ci					unsigned int *rate);
20862306a36Sopenharmony_ciint snd_motu_protocol_v3_set_clock_rate(struct snd_motu *motu,
20962306a36Sopenharmony_ci					unsigned int rate);
21062306a36Sopenharmony_ciint snd_motu_protocol_v3_get_clock_source(struct snd_motu *motu,
21162306a36Sopenharmony_ci					  enum snd_motu_clock_source *src);
21262306a36Sopenharmony_ciint snd_motu_protocol_v3_switch_fetching_mode(struct snd_motu *motu,
21362306a36Sopenharmony_ci					      bool enable);
21462306a36Sopenharmony_ciint snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic inline int snd_motu_protocol_get_clock_rate(struct snd_motu *motu,
21762306a36Sopenharmony_ci						   unsigned int *rate)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V2)
22062306a36Sopenharmony_ci		return snd_motu_protocol_v2_get_clock_rate(motu, rate);
22162306a36Sopenharmony_ci	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
22262306a36Sopenharmony_ci		return snd_motu_protocol_v3_get_clock_rate(motu, rate);
22362306a36Sopenharmony_ci	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
22462306a36Sopenharmony_ci		return snd_motu_protocol_v1_get_clock_rate(motu, rate);
22562306a36Sopenharmony_ci	else
22662306a36Sopenharmony_ci		return -ENXIO;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic inline int snd_motu_protocol_set_clock_rate(struct snd_motu *motu,
23062306a36Sopenharmony_ci						   unsigned int rate)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V2)
23362306a36Sopenharmony_ci		return snd_motu_protocol_v2_set_clock_rate(motu, rate);
23462306a36Sopenharmony_ci	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
23562306a36Sopenharmony_ci		return snd_motu_protocol_v3_set_clock_rate(motu, rate);
23662306a36Sopenharmony_ci	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
23762306a36Sopenharmony_ci		return snd_motu_protocol_v1_set_clock_rate(motu, rate);
23862306a36Sopenharmony_ci	else
23962306a36Sopenharmony_ci		return -ENXIO;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic inline int snd_motu_protocol_get_clock_source(struct snd_motu *motu,
24362306a36Sopenharmony_ci					enum snd_motu_clock_source *source)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V2)
24662306a36Sopenharmony_ci		return snd_motu_protocol_v2_get_clock_source(motu, source);
24762306a36Sopenharmony_ci	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
24862306a36Sopenharmony_ci		return snd_motu_protocol_v3_get_clock_source(motu, source);
24962306a36Sopenharmony_ci	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
25062306a36Sopenharmony_ci		return snd_motu_protocol_v1_get_clock_source(motu, source);
25162306a36Sopenharmony_ci	else
25262306a36Sopenharmony_ci		return -ENXIO;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic inline int snd_motu_protocol_switch_fetching_mode(struct snd_motu *motu,
25662306a36Sopenharmony_ci							 bool enable)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V2)
25962306a36Sopenharmony_ci		return snd_motu_protocol_v2_switch_fetching_mode(motu, enable);
26062306a36Sopenharmony_ci	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
26162306a36Sopenharmony_ci		return snd_motu_protocol_v3_switch_fetching_mode(motu, enable);
26262306a36Sopenharmony_ci	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
26362306a36Sopenharmony_ci		return snd_motu_protocol_v1_switch_fetching_mode(motu, enable);
26462306a36Sopenharmony_ci	else
26562306a36Sopenharmony_ci		return -ENXIO;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic inline int snd_motu_protocol_cache_packet_formats(struct snd_motu *motu)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V2)
27162306a36Sopenharmony_ci		return snd_motu_protocol_v2_cache_packet_formats(motu);
27262306a36Sopenharmony_ci	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
27362306a36Sopenharmony_ci		return snd_motu_protocol_v3_cache_packet_formats(motu);
27462306a36Sopenharmony_ci	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
27562306a36Sopenharmony_ci		return snd_motu_protocol_v1_cache_packet_formats(motu);
27662306a36Sopenharmony_ci	else
27762306a36Sopenharmony_ci		return -ENXIO;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ciint snd_motu_register_dsp_message_parser_new(struct snd_motu *motu);
28162306a36Sopenharmony_ciint snd_motu_register_dsp_message_parser_init(struct snd_motu *motu);
28262306a36Sopenharmony_civoid snd_motu_register_dsp_message_parser_parse(const struct amdtp_stream *s,
28362306a36Sopenharmony_ci					const struct pkt_desc *descs, unsigned int count);
28462306a36Sopenharmony_civoid snd_motu_register_dsp_message_parser_copy_meter(struct snd_motu *motu,
28562306a36Sopenharmony_ci					struct snd_firewire_motu_register_dsp_meter *meter);
28662306a36Sopenharmony_civoid snd_motu_register_dsp_message_parser_copy_parameter(struct snd_motu *motu,
28762306a36Sopenharmony_ci					struct snd_firewire_motu_register_dsp_parameter *params);
28862306a36Sopenharmony_ciunsigned int snd_motu_register_dsp_message_parser_count_event(struct snd_motu *motu);
28962306a36Sopenharmony_cibool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32 *event);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ciint snd_motu_command_dsp_message_parser_new(struct snd_motu *motu);
29262306a36Sopenharmony_ciint snd_motu_command_dsp_message_parser_init(struct snd_motu *motu, enum cip_sfc sfc);
29362306a36Sopenharmony_civoid snd_motu_command_dsp_message_parser_parse(const struct amdtp_stream *s,
29462306a36Sopenharmony_ci					const struct pkt_desc *descs, unsigned int count);
29562306a36Sopenharmony_civoid snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,
29662306a36Sopenharmony_ci					struct snd_firewire_motu_command_dsp_meter *meter);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci#endif
299