1da607e19SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */ 2fd6f4b0dSTakashi Sakamoto /* 3fd6f4b0dSTakashi Sakamoto * bebob.h - a part of driver for BeBoB based devices 4fd6f4b0dSTakashi Sakamoto * 5fd6f4b0dSTakashi Sakamoto * Copyright (c) 2013-2014 Takashi Sakamoto 6fd6f4b0dSTakashi Sakamoto */ 7fd6f4b0dSTakashi Sakamoto 8fd6f4b0dSTakashi Sakamoto #ifndef SOUND_BEBOB_H_INCLUDED 9fd6f4b0dSTakashi Sakamoto #define SOUND_BEBOB_H_INCLUDED 10fd6f4b0dSTakashi Sakamoto 11fd6f4b0dSTakashi Sakamoto #include <linux/compat.h> 12fd6f4b0dSTakashi Sakamoto #include <linux/device.h> 13fd6f4b0dSTakashi Sakamoto #include <linux/firewire.h> 14fd6f4b0dSTakashi Sakamoto #include <linux/firewire-constants.h> 15fd6f4b0dSTakashi Sakamoto #include <linux/module.h> 16fd6f4b0dSTakashi Sakamoto #include <linux/mod_devicetable.h> 17fd6f4b0dSTakashi Sakamoto #include <linux/delay.h> 18fd6f4b0dSTakashi Sakamoto #include <linux/slab.h> 19174cd4b1SIngo Molnar #include <linux/sched/signal.h> 20fd6f4b0dSTakashi Sakamoto 21fd6f4b0dSTakashi Sakamoto #include <sound/core.h> 22fd6f4b0dSTakashi Sakamoto #include <sound/initval.h> 23ad9697baSTakashi Sakamoto #include <sound/info.h> 24248b7802STakashi Sakamoto #include <sound/rawmidi.h> 25fbbebd2cSTakashi Sakamoto #include <sound/pcm.h> 26fbbebd2cSTakashi Sakamoto #include <sound/pcm_params.h> 27618eabeaSTakashi Sakamoto #include <sound/firewire.h> 28618eabeaSTakashi Sakamoto #include <sound/hwdep.h> 29fd6f4b0dSTakashi Sakamoto 30fd6f4b0dSTakashi Sakamoto #include "../lib.h" 31fd6f4b0dSTakashi Sakamoto #include "../fcp.h" 32eb7b3a05STakashi Sakamoto #include "../packets-buffer.h" 33eb7b3a05STakashi Sakamoto #include "../iso-resources.h" 345955815eSTakashi Sakamoto #include "../amdtp-am824.h" 35eb7b3a05STakashi Sakamoto #include "../cmp.h" 36fd6f4b0dSTakashi Sakamoto 37fd6f4b0dSTakashi Sakamoto /* basic register addresses on DM1000/DM1100/DM1500 */ 389b5f0edfSTakashi Sakamoto #define BEBOB_ADDR_REG_INFO 0xffffc8020000ULL 399b5f0edfSTakashi Sakamoto #define BEBOB_ADDR_REG_REQ 0xffffc8021000ULL 40fd6f4b0dSTakashi Sakamoto 41eb7b3a05STakashi Sakamoto struct snd_bebob; 42eb7b3a05STakashi Sakamoto 43eb7b3a05STakashi Sakamoto #define SND_BEBOB_STRM_FMT_ENTRIES 7 44eb7b3a05STakashi Sakamoto struct snd_bebob_stream_formation { 45eb7b3a05STakashi Sakamoto unsigned int pcm; 46eb7b3a05STakashi Sakamoto unsigned int midi; 47eb7b3a05STakashi Sakamoto }; 48eb7b3a05STakashi Sakamoto /* this is a lookup table for index of stream formations */ 49eb7b3a05STakashi Sakamoto extern const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES]; 50eb7b3a05STakashi Sakamoto 511fc9522aSTakashi Sakamoto /* device specific operations */ 5213a4f420STakashi Sakamoto enum snd_bebob_clock_type { 5313a4f420STakashi Sakamoto SND_BEBOB_CLOCK_TYPE_INTERNAL = 0, 5413a4f420STakashi Sakamoto SND_BEBOB_CLOCK_TYPE_EXTERNAL, 5513a4f420STakashi Sakamoto SND_BEBOB_CLOCK_TYPE_SYT, 5613a4f420STakashi Sakamoto }; 571fc9522aSTakashi Sakamoto struct snd_bebob_clock_spec { 581fc9522aSTakashi Sakamoto unsigned int num; 59e7ced413STakashi Iwai const char *const *labels; 60782fbec7STakashi Sakamoto const enum snd_bebob_clock_type *types; 611fc9522aSTakashi Sakamoto int (*get)(struct snd_bebob *bebob, unsigned int *id); 621fc9522aSTakashi Sakamoto }; 631fc9522aSTakashi Sakamoto struct snd_bebob_rate_spec { 641fc9522aSTakashi Sakamoto int (*get)(struct snd_bebob *bebob, unsigned int *rate); 651fc9522aSTakashi Sakamoto int (*set)(struct snd_bebob *bebob, unsigned int rate); 661fc9522aSTakashi Sakamoto }; 671fc9522aSTakashi Sakamoto struct snd_bebob_meter_spec { 681fc9522aSTakashi Sakamoto unsigned int num; 69e7ced413STakashi Iwai const char *const *labels; 701fc9522aSTakashi Sakamoto int (*get)(struct snd_bebob *bebob, u32 *target, unsigned int size); 711fc9522aSTakashi Sakamoto }; 721fc9522aSTakashi Sakamoto struct snd_bebob_spec { 736b9866c8SJulia Lawall const struct snd_bebob_clock_spec *clock; 746b9866c8SJulia Lawall const struct snd_bebob_rate_spec *rate; 756b9866c8SJulia Lawall const struct snd_bebob_meter_spec *meter; 761fc9522aSTakashi Sakamoto }; 771fc9522aSTakashi Sakamoto 78fd6f4b0dSTakashi Sakamoto struct snd_bebob { 79fd6f4b0dSTakashi Sakamoto struct snd_card *card; 80fd6f4b0dSTakashi Sakamoto struct fw_unit *unit; 81fd6f4b0dSTakashi Sakamoto int card_index; 82fd6f4b0dSTakashi Sakamoto 83fd6f4b0dSTakashi Sakamoto struct mutex mutex; 84fd6f4b0dSTakashi Sakamoto spinlock_t lock; 85eb7b3a05STakashi Sakamoto 8604a2c73cSTakashi Sakamoto bool registered; 8704a2c73cSTakashi Sakamoto struct delayed_work dwork; 8804a2c73cSTakashi Sakamoto 8904a2c73cSTakashi Sakamoto const struct ieee1394_device_id *entry; 901fc9522aSTakashi Sakamoto const struct snd_bebob_spec *spec; 911fc9522aSTakashi Sakamoto 92eb7b3a05STakashi Sakamoto unsigned int midi_input_ports; 93eb7b3a05STakashi Sakamoto unsigned int midi_output_ports; 94eb7b3a05STakashi Sakamoto 95eb7b3a05STakashi Sakamoto struct amdtp_stream tx_stream; 96eb7b3a05STakashi Sakamoto struct amdtp_stream rx_stream; 97eb7b3a05STakashi Sakamoto struct cmp_connection out_conn; 98eb7b3a05STakashi Sakamoto struct cmp_connection in_conn; 994fd6c6c7STakashi Sakamoto unsigned int substreams_counter; 100eb7b3a05STakashi Sakamoto 101eb7b3a05STakashi Sakamoto struct snd_bebob_stream_formation 102eb7b3a05STakashi Sakamoto tx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES]; 103eb7b3a05STakashi Sakamoto struct snd_bebob_stream_formation 104eb7b3a05STakashi Sakamoto rx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES]; 105eb7b3a05STakashi Sakamoto 106eb7b3a05STakashi Sakamoto int sync_input_plug; 107618eabeaSTakashi Sakamoto 108618eabeaSTakashi Sakamoto /* for uapi */ 109618eabeaSTakashi Sakamoto int dev_lock_count; 110618eabeaSTakashi Sakamoto bool dev_lock_changed; 111618eabeaSTakashi Sakamoto wait_queue_head_t hwdep_wait; 1123149ac48STakashi Sakamoto 1133149ac48STakashi Sakamoto /* for M-Audio special devices */ 1143149ac48STakashi Sakamoto void *maudio_special_quirk; 1157b4d7dcfSTakashi Sakamoto 1167b4d7dcfSTakashi Sakamoto /* For BeBoB version quirk. */ 1177b4d7dcfSTakashi Sakamoto unsigned int version; 118b0db4d51STakashi Sakamoto 119b0db4d51STakashi Sakamoto struct amdtp_domain domain; 120fd6f4b0dSTakashi Sakamoto }; 121fd6f4b0dSTakashi Sakamoto 122fd6f4b0dSTakashi Sakamoto static inline int 123fd6f4b0dSTakashi Sakamoto snd_bebob_read_block(struct fw_unit *unit, u64 addr, void *buf, int size) 124fd6f4b0dSTakashi Sakamoto { 125fd6f4b0dSTakashi Sakamoto return snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST, 126fd6f4b0dSTakashi Sakamoto BEBOB_ADDR_REG_INFO + addr, 127fd6f4b0dSTakashi Sakamoto buf, size, 0); 128fd6f4b0dSTakashi Sakamoto } 129fd6f4b0dSTakashi Sakamoto 130fd6f4b0dSTakashi Sakamoto static inline int 131fd6f4b0dSTakashi Sakamoto snd_bebob_read_quad(struct fw_unit *unit, u64 addr, u32 *buf) 132fd6f4b0dSTakashi Sakamoto { 133fd6f4b0dSTakashi Sakamoto return snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, 134fd6f4b0dSTakashi Sakamoto BEBOB_ADDR_REG_INFO + addr, 135fd6f4b0dSTakashi Sakamoto (void *)buf, sizeof(u32), 0); 136fd6f4b0dSTakashi Sakamoto } 137fd6f4b0dSTakashi Sakamoto 1381fc9522aSTakashi Sakamoto /* AV/C Audio Subunit Specification 1.0 (Oct 2000, 1394TA) */ 1391fc9522aSTakashi Sakamoto int avc_audio_set_selector(struct fw_unit *unit, unsigned int subunit_id, 1401fc9522aSTakashi Sakamoto unsigned int fb_id, unsigned int num); 1411fc9522aSTakashi Sakamoto int avc_audio_get_selector(struct fw_unit *unit, unsigned int subunit_id, 1421fc9522aSTakashi Sakamoto unsigned int fb_id, unsigned int *num); 1431fc9522aSTakashi Sakamoto 144eb7b3a05STakashi Sakamoto /* 145eb7b3a05STakashi Sakamoto * AVC command extensions, AV/C Unit and Subunit, Revision 17 146eb7b3a05STakashi Sakamoto * (Nov 2003, BridgeCo) 147eb7b3a05STakashi Sakamoto */ 148eb7b3a05STakashi Sakamoto #define AVC_BRIDGECO_ADDR_BYTES 6 149eb7b3a05STakashi Sakamoto enum avc_bridgeco_plug_dir { 150eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_DIR_IN = 0x00, 151eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_DIR_OUT = 0x01 152eb7b3a05STakashi Sakamoto }; 153eb7b3a05STakashi Sakamoto enum avc_bridgeco_plug_mode { 154eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_MODE_UNIT = 0x00, 155eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_MODE_SUBUNIT = 0x01, 156eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_MODE_FUNCTION_BLOCK = 0x02 157eb7b3a05STakashi Sakamoto }; 158eb7b3a05STakashi Sakamoto enum avc_bridgeco_plug_unit { 159eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_UNIT_ISOC = 0x00, 160eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_UNIT_EXT = 0x01, 161eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_UNIT_ASYNC = 0x02 162eb7b3a05STakashi Sakamoto }; 163eb7b3a05STakashi Sakamoto enum avc_bridgeco_plug_type { 164eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_TYPE_ISOC = 0x00, 165eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_TYPE_ASYNC = 0x01, 166eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_TYPE_MIDI = 0x02, 167eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_TYPE_SYNC = 0x03, 168eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_TYPE_ANA = 0x04, 1695a668812STakashi Sakamoto AVC_BRIDGECO_PLUG_TYPE_DIG = 0x05, 1705a668812STakashi Sakamoto AVC_BRIDGECO_PLUG_TYPE_ADDITION = 0x06 171eb7b3a05STakashi Sakamoto }; 172eb7b3a05STakashi Sakamoto static inline void 173eb7b3a05STakashi Sakamoto avc_bridgeco_fill_unit_addr(u8 buf[AVC_BRIDGECO_ADDR_BYTES], 174eb7b3a05STakashi Sakamoto enum avc_bridgeco_plug_dir dir, 175eb7b3a05STakashi Sakamoto enum avc_bridgeco_plug_unit unit, 176eb7b3a05STakashi Sakamoto unsigned int pid) 177eb7b3a05STakashi Sakamoto { 178eb7b3a05STakashi Sakamoto buf[0] = 0xff; /* Unit */ 179eb7b3a05STakashi Sakamoto buf[1] = dir; 180eb7b3a05STakashi Sakamoto buf[2] = AVC_BRIDGECO_PLUG_MODE_UNIT; 181eb7b3a05STakashi Sakamoto buf[3] = unit; 182eb7b3a05STakashi Sakamoto buf[4] = 0xff & pid; 183eb7b3a05STakashi Sakamoto buf[5] = 0xff; /* reserved */ 184eb7b3a05STakashi Sakamoto } 185eb7b3a05STakashi Sakamoto static inline void 186eb7b3a05STakashi Sakamoto avc_bridgeco_fill_msu_addr(u8 buf[AVC_BRIDGECO_ADDR_BYTES], 187eb7b3a05STakashi Sakamoto enum avc_bridgeco_plug_dir dir, 188eb7b3a05STakashi Sakamoto unsigned int pid) 189eb7b3a05STakashi Sakamoto { 190eb7b3a05STakashi Sakamoto buf[0] = 0x60; /* Music subunit */ 191eb7b3a05STakashi Sakamoto buf[1] = dir; 192eb7b3a05STakashi Sakamoto buf[2] = AVC_BRIDGECO_PLUG_MODE_SUBUNIT; 193eb7b3a05STakashi Sakamoto buf[3] = 0xff & pid; 194eb7b3a05STakashi Sakamoto buf[4] = 0xff; /* reserved */ 195eb7b3a05STakashi Sakamoto buf[5] = 0xff; /* reserved */ 196eb7b3a05STakashi Sakamoto } 197eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit, 198eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES], 199eb7b3a05STakashi Sakamoto u8 *buf, unsigned int len); 200eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_type(struct fw_unit *unit, 201eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES], 202eb7b3a05STakashi Sakamoto enum avc_bridgeco_plug_type *type); 203eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_section_type(struct fw_unit *unit, 204eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES], 205eb7b3a05STakashi Sakamoto unsigned int id, u8 *type); 206eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_input(struct fw_unit *unit, 207eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES], 208eb7b3a05STakashi Sakamoto u8 input[7]); 209eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit, 210eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf, 211eb7b3a05STakashi Sakamoto unsigned int *len, unsigned int eid); 212eb7b3a05STakashi Sakamoto 213eb7b3a05STakashi Sakamoto /* for AMDTP streaming */ 214eb7b3a05STakashi Sakamoto int snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *rate); 215eb7b3a05STakashi Sakamoto int snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate); 2163e254b16STakashi Sakamoto int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob, 2173e254b16STakashi Sakamoto enum snd_bebob_clock_type *src); 218eb7b3a05STakashi Sakamoto int snd_bebob_stream_discover(struct snd_bebob *bebob); 219eb7b3a05STakashi Sakamoto int snd_bebob_stream_init_duplex(struct snd_bebob *bebob); 220ac2888b9STakashi Sakamoto int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate); 221ac2888b9STakashi Sakamoto int snd_bebob_stream_start_duplex(struct snd_bebob *bebob); 222eb7b3a05STakashi Sakamoto void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob); 223eb7b3a05STakashi Sakamoto void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob); 224eb7b3a05STakashi Sakamoto 225618eabeaSTakashi Sakamoto void snd_bebob_stream_lock_changed(struct snd_bebob *bebob); 226618eabeaSTakashi Sakamoto int snd_bebob_stream_lock_try(struct snd_bebob *bebob); 227618eabeaSTakashi Sakamoto void snd_bebob_stream_lock_release(struct snd_bebob *bebob); 228618eabeaSTakashi Sakamoto 229ad9697baSTakashi Sakamoto void snd_bebob_proc_init(struct snd_bebob *bebob); 230ad9697baSTakashi Sakamoto 231248b7802STakashi Sakamoto int snd_bebob_create_midi_devices(struct snd_bebob *bebob); 232248b7802STakashi Sakamoto 233fbbebd2cSTakashi Sakamoto int snd_bebob_create_pcm_devices(struct snd_bebob *bebob); 234fbbebd2cSTakashi Sakamoto 235618eabeaSTakashi Sakamoto int snd_bebob_create_hwdep_device(struct snd_bebob *bebob); 236618eabeaSTakashi Sakamoto 237326b9cacSTakashi Sakamoto /* model specific operations */ 2386b9866c8SJulia Lawall extern const struct snd_bebob_spec phase88_rack_spec; 239e15c282eSTakashi Sakamoto extern const struct snd_bebob_spec yamaha_terratec_spec; 2406b9866c8SJulia Lawall extern const struct snd_bebob_spec saffirepro_26_spec; 2416b9866c8SJulia Lawall extern const struct snd_bebob_spec saffirepro_10_spec; 2426b9866c8SJulia Lawall extern const struct snd_bebob_spec saffire_le_spec; 2436b9866c8SJulia Lawall extern const struct snd_bebob_spec saffire_spec; 2446b9866c8SJulia Lawall extern const struct snd_bebob_spec maudio_fw410_spec; 2456b9866c8SJulia Lawall extern const struct snd_bebob_spec maudio_audiophile_spec; 2466b9866c8SJulia Lawall extern const struct snd_bebob_spec maudio_solo_spec; 2476b9866c8SJulia Lawall extern const struct snd_bebob_spec maudio_ozonic_spec; 2486b9866c8SJulia Lawall extern const struct snd_bebob_spec maudio_nrv10_spec; 2496b9866c8SJulia Lawall extern const struct snd_bebob_spec maudio_special_spec; 2503149ac48STakashi Sakamoto int snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814); 251a2b2a779STakashi Sakamoto int snd_bebob_maudio_load_firmware(struct fw_unit *unit); 252326b9cacSTakashi Sakamoto 2531fc9522aSTakashi Sakamoto #define SND_BEBOB_DEV_ENTRY(vendor, model, data) \ 254fd6f4b0dSTakashi Sakamoto { \ 255fd6f4b0dSTakashi Sakamoto .match_flags = IEEE1394_MATCH_VENDOR_ID | \ 256fd6f4b0dSTakashi Sakamoto IEEE1394_MATCH_MODEL_ID, \ 257fd6f4b0dSTakashi Sakamoto .vendor_id = vendor, \ 258fd6f4b0dSTakashi Sakamoto .model_id = model, \ 2591fc9522aSTakashi Sakamoto .driver_data = (kernel_ulong_t)data \ 260fd6f4b0dSTakashi Sakamoto } 261fd6f4b0dSTakashi Sakamoto 262fd6f4b0dSTakashi Sakamoto #endif 263