18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * motu.h - a part of driver for MOTU FireWire series 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifndef SOUND_FIREWIRE_MOTU_H_INCLUDED 98c2ecf20Sopenharmony_ci#define SOUND_FIREWIRE_MOTU_H_INCLUDED 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/firewire.h> 138c2ecf20Sopenharmony_ci#include <linux/firewire-constants.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 168c2ecf20Sopenharmony_ci#include <linux/mutex.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/compat.h> 198c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <sound/control.h> 228c2ecf20Sopenharmony_ci#include <sound/core.h> 238c2ecf20Sopenharmony_ci#include <sound/pcm.h> 248c2ecf20Sopenharmony_ci#include <sound/info.h> 258c2ecf20Sopenharmony_ci#include <sound/rawmidi.h> 268c2ecf20Sopenharmony_ci#include <sound/firewire.h> 278c2ecf20Sopenharmony_ci#include <sound/hwdep.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "../lib.h" 308c2ecf20Sopenharmony_ci#include "../amdtp-stream.h" 318c2ecf20Sopenharmony_ci#include "../iso-resources.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct snd_motu_packet_format { 348c2ecf20Sopenharmony_ci unsigned char midi_flag_offset; 358c2ecf20Sopenharmony_ci unsigned char midi_byte_offset; 368c2ecf20Sopenharmony_ci unsigned char pcm_byte_offset; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci unsigned char msg_chunks; 398c2ecf20Sopenharmony_ci unsigned char pcm_chunks[3]; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct snd_motu { 438c2ecf20Sopenharmony_ci struct snd_card *card; 448c2ecf20Sopenharmony_ci struct fw_unit *unit; 458c2ecf20Sopenharmony_ci struct mutex mutex; 468c2ecf20Sopenharmony_ci spinlock_t lock; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci bool registered; 498c2ecf20Sopenharmony_ci struct delayed_work dwork; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* Model dependent information. */ 528c2ecf20Sopenharmony_ci const struct snd_motu_spec *spec; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* For packet streaming */ 558c2ecf20Sopenharmony_ci struct snd_motu_packet_format tx_packet_formats; 568c2ecf20Sopenharmony_ci struct snd_motu_packet_format rx_packet_formats; 578c2ecf20Sopenharmony_ci struct amdtp_stream tx_stream; 588c2ecf20Sopenharmony_ci struct amdtp_stream rx_stream; 598c2ecf20Sopenharmony_ci struct fw_iso_resources tx_resources; 608c2ecf20Sopenharmony_ci struct fw_iso_resources rx_resources; 618c2ecf20Sopenharmony_ci unsigned int substreams_counter; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* For notification. */ 648c2ecf20Sopenharmony_ci struct fw_address_handler async_handler; 658c2ecf20Sopenharmony_ci u32 msg; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* For uapi */ 688c2ecf20Sopenharmony_ci int dev_lock_count; 698c2ecf20Sopenharmony_ci bool dev_lock_changed; 708c2ecf20Sopenharmony_ci wait_queue_head_t hwdep_wait; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci struct amdtp_domain domain; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cienum snd_motu_spec_flags { 768c2ecf20Sopenharmony_ci SND_MOTU_SPEC_RX_MIDI_2ND_Q = 0x0001, 778c2ecf20Sopenharmony_ci SND_MOTU_SPEC_RX_MIDI_3RD_Q = 0x0002, 788c2ecf20Sopenharmony_ci SND_MOTU_SPEC_TX_MIDI_2ND_Q = 0x0004, 798c2ecf20Sopenharmony_ci SND_MOTU_SPEC_TX_MIDI_3RD_Q = 0x0008, 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define SND_MOTU_CLOCK_RATE_COUNT 6 838c2ecf20Sopenharmony_ciextern const unsigned int snd_motu_clock_rates[SND_MOTU_CLOCK_RATE_COUNT]; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cienum snd_motu_clock_source { 868c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_INTERNAL, 878c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB, 888c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT, 898c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A, 908c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B, 918c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT, 928c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A, 938c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B, 948c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX, 958c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR, 968c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC, 978c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_SPH, 988c2ecf20Sopenharmony_ci SND_MOTU_CLOCK_SOURCE_UNKNOWN, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cienum snd_motu_protocol_version { 1028c2ecf20Sopenharmony_ci SND_MOTU_PROTOCOL_V2, 1038c2ecf20Sopenharmony_ci SND_MOTU_PROTOCOL_V3, 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistruct snd_motu_spec { 1078c2ecf20Sopenharmony_ci const char *const name; 1088c2ecf20Sopenharmony_ci enum snd_motu_protocol_version protocol_version; 1098c2ecf20Sopenharmony_ci enum snd_motu_spec_flags flags; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci unsigned char tx_fixed_pcm_chunks[3]; 1128c2ecf20Sopenharmony_ci unsigned char rx_fixed_pcm_chunks[3]; 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_828mk2; 1168c2ecf20Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_traveler; 1178c2ecf20Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_ultralite; 1188c2ecf20Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_8pre; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_828mk3; 1218c2ecf20Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_ultralite_mk3; 1228c2ecf20Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_audio_express; 1238c2ecf20Sopenharmony_ciextern const struct snd_motu_spec snd_motu_spec_4pre; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciint amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, 1268c2ecf20Sopenharmony_ci enum amdtp_stream_direction dir, 1278c2ecf20Sopenharmony_ci const struct snd_motu_spec *spec); 1288c2ecf20Sopenharmony_ciint amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate, 1298c2ecf20Sopenharmony_ci unsigned int midi_ports, 1308c2ecf20Sopenharmony_ci struct snd_motu_packet_format *formats); 1318c2ecf20Sopenharmony_ciint amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s, 1328c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime); 1338c2ecf20Sopenharmony_civoid amdtp_motu_midi_trigger(struct amdtp_stream *s, unsigned int port, 1348c2ecf20Sopenharmony_ci struct snd_rawmidi_substream *midi); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciint snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg, 1378c2ecf20Sopenharmony_ci size_t size); 1388c2ecf20Sopenharmony_ciint snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg, 1398c2ecf20Sopenharmony_ci size_t size); 1408c2ecf20Sopenharmony_ciint snd_motu_transaction_register(struct snd_motu *motu); 1418c2ecf20Sopenharmony_ciint snd_motu_transaction_reregister(struct snd_motu *motu); 1428c2ecf20Sopenharmony_civoid snd_motu_transaction_unregister(struct snd_motu *motu); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ciint snd_motu_stream_init_duplex(struct snd_motu *motu); 1458c2ecf20Sopenharmony_civoid snd_motu_stream_destroy_duplex(struct snd_motu *motu); 1468c2ecf20Sopenharmony_ciint snd_motu_stream_cache_packet_formats(struct snd_motu *motu); 1478c2ecf20Sopenharmony_ciint snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate, 1488c2ecf20Sopenharmony_ci unsigned int frames_per_period, 1498c2ecf20Sopenharmony_ci unsigned int frames_per_buffer); 1508c2ecf20Sopenharmony_ciint snd_motu_stream_start_duplex(struct snd_motu *motu); 1518c2ecf20Sopenharmony_civoid snd_motu_stream_stop_duplex(struct snd_motu *motu); 1528c2ecf20Sopenharmony_ciint snd_motu_stream_lock_try(struct snd_motu *motu); 1538c2ecf20Sopenharmony_civoid snd_motu_stream_lock_release(struct snd_motu *motu); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_civoid snd_motu_proc_init(struct snd_motu *motu); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ciint snd_motu_create_pcm_devices(struct snd_motu *motu); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ciint snd_motu_create_midi_devices(struct snd_motu *motu); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ciint snd_motu_create_hwdep_device(struct snd_motu *motu); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ciint snd_motu_protocol_v2_get_clock_rate(struct snd_motu *motu, 1648c2ecf20Sopenharmony_ci unsigned int *rate); 1658c2ecf20Sopenharmony_ciint snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu, 1668c2ecf20Sopenharmony_ci unsigned int rate); 1678c2ecf20Sopenharmony_ciint snd_motu_protocol_v2_get_clock_source(struct snd_motu *motu, 1688c2ecf20Sopenharmony_ci enum snd_motu_clock_source *src); 1698c2ecf20Sopenharmony_ciint snd_motu_protocol_v2_switch_fetching_mode(struct snd_motu *motu, 1708c2ecf20Sopenharmony_ci bool enable); 1718c2ecf20Sopenharmony_ciint snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ciint snd_motu_protocol_v3_get_clock_rate(struct snd_motu *motu, 1748c2ecf20Sopenharmony_ci unsigned int *rate); 1758c2ecf20Sopenharmony_ciint snd_motu_protocol_v3_set_clock_rate(struct snd_motu *motu, 1768c2ecf20Sopenharmony_ci unsigned int rate); 1778c2ecf20Sopenharmony_ciint snd_motu_protocol_v3_get_clock_source(struct snd_motu *motu, 1788c2ecf20Sopenharmony_ci enum snd_motu_clock_source *src); 1798c2ecf20Sopenharmony_ciint snd_motu_protocol_v3_switch_fetching_mode(struct snd_motu *motu, 1808c2ecf20Sopenharmony_ci bool enable); 1818c2ecf20Sopenharmony_ciint snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic inline int snd_motu_protocol_get_clock_rate(struct snd_motu *motu, 1848c2ecf20Sopenharmony_ci unsigned int *rate) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V2) 1878c2ecf20Sopenharmony_ci return snd_motu_protocol_v2_get_clock_rate(motu, rate); 1888c2ecf20Sopenharmony_ci else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3) 1898c2ecf20Sopenharmony_ci return snd_motu_protocol_v3_get_clock_rate(motu, rate); 1908c2ecf20Sopenharmony_ci else 1918c2ecf20Sopenharmony_ci return -ENXIO; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic inline int snd_motu_protocol_set_clock_rate(struct snd_motu *motu, 1958c2ecf20Sopenharmony_ci unsigned int rate) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V2) 1988c2ecf20Sopenharmony_ci return snd_motu_protocol_v2_set_clock_rate(motu, rate); 1998c2ecf20Sopenharmony_ci else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3) 2008c2ecf20Sopenharmony_ci return snd_motu_protocol_v3_set_clock_rate(motu, rate); 2018c2ecf20Sopenharmony_ci else 2028c2ecf20Sopenharmony_ci return -ENXIO; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic inline int snd_motu_protocol_get_clock_source(struct snd_motu *motu, 2068c2ecf20Sopenharmony_ci enum snd_motu_clock_source *source) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V2) 2098c2ecf20Sopenharmony_ci return snd_motu_protocol_v2_get_clock_source(motu, source); 2108c2ecf20Sopenharmony_ci else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3) 2118c2ecf20Sopenharmony_ci return snd_motu_protocol_v3_get_clock_source(motu, source); 2128c2ecf20Sopenharmony_ci else 2138c2ecf20Sopenharmony_ci return -ENXIO; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic inline int snd_motu_protocol_switch_fetching_mode(struct snd_motu *motu, 2178c2ecf20Sopenharmony_ci bool enable) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V2) 2208c2ecf20Sopenharmony_ci return snd_motu_protocol_v2_switch_fetching_mode(motu, enable); 2218c2ecf20Sopenharmony_ci else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3) 2228c2ecf20Sopenharmony_ci return snd_motu_protocol_v3_switch_fetching_mode(motu, enable); 2238c2ecf20Sopenharmony_ci else 2248c2ecf20Sopenharmony_ci return -ENXIO; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic inline int snd_motu_protocol_cache_packet_formats(struct snd_motu *motu) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V2) 2308c2ecf20Sopenharmony_ci return snd_motu_protocol_v2_cache_packet_formats(motu); 2318c2ecf20Sopenharmony_ci else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3) 2328c2ecf20Sopenharmony_ci return snd_motu_protocol_v3_cache_packet_formats(motu); 2338c2ecf20Sopenharmony_ci else 2348c2ecf20Sopenharmony_ci return -ENXIO; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#endif 238