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