162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * bebob.h - a part of driver for BeBoB based devices
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2013-2014 Takashi Sakamoto
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifndef SOUND_BEBOB_H_INCLUDED
962306a36Sopenharmony_ci#define SOUND_BEBOB_H_INCLUDED
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/compat.h>
1262306a36Sopenharmony_ci#include <linux/device.h>
1362306a36Sopenharmony_ci#include <linux/firewire.h>
1462306a36Sopenharmony_ci#include <linux/firewire-constants.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/sched/signal.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <sound/core.h>
2262306a36Sopenharmony_ci#include <sound/initval.h>
2362306a36Sopenharmony_ci#include <sound/info.h>
2462306a36Sopenharmony_ci#include <sound/rawmidi.h>
2562306a36Sopenharmony_ci#include <sound/pcm.h>
2662306a36Sopenharmony_ci#include <sound/pcm_params.h>
2762306a36Sopenharmony_ci#include <sound/firewire.h>
2862306a36Sopenharmony_ci#include <sound/hwdep.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include "../lib.h"
3162306a36Sopenharmony_ci#include "../fcp.h"
3262306a36Sopenharmony_ci#include "../packets-buffer.h"
3362306a36Sopenharmony_ci#include "../iso-resources.h"
3462306a36Sopenharmony_ci#include "../amdtp-am824.h"
3562306a36Sopenharmony_ci#include "../cmp.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* basic register addresses on DM1000/DM1100/DM1500 */
3862306a36Sopenharmony_ci#define BEBOB_ADDR_REG_INFO	0xffffc8020000ULL
3962306a36Sopenharmony_ci#define BEBOB_ADDR_REG_REQ	0xffffc8021000ULL
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistruct snd_bebob;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define SND_BEBOB_STRM_FMT_ENTRIES	7
4462306a36Sopenharmony_cistruct snd_bebob_stream_formation {
4562306a36Sopenharmony_ci	unsigned int pcm;
4662306a36Sopenharmony_ci	unsigned int midi;
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci/* this is a lookup table for index of stream formations */
4962306a36Sopenharmony_ciextern const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES];
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* device specific operations */
5262306a36Sopenharmony_cienum snd_bebob_clock_type {
5362306a36Sopenharmony_ci	SND_BEBOB_CLOCK_TYPE_INTERNAL = 0,
5462306a36Sopenharmony_ci	SND_BEBOB_CLOCK_TYPE_EXTERNAL,
5562306a36Sopenharmony_ci	SND_BEBOB_CLOCK_TYPE_SYT,
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_cistruct snd_bebob_clock_spec {
5862306a36Sopenharmony_ci	unsigned int num;
5962306a36Sopenharmony_ci	const char *const *labels;
6062306a36Sopenharmony_ci	const enum snd_bebob_clock_type *types;
6162306a36Sopenharmony_ci	int (*get)(struct snd_bebob *bebob, unsigned int *id);
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_cistruct snd_bebob_rate_spec {
6462306a36Sopenharmony_ci	int (*get)(struct snd_bebob *bebob, unsigned int *rate);
6562306a36Sopenharmony_ci	int (*set)(struct snd_bebob *bebob, unsigned int rate);
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_cistruct snd_bebob_meter_spec {
6862306a36Sopenharmony_ci	unsigned int num;
6962306a36Sopenharmony_ci	const char *const *labels;
7062306a36Sopenharmony_ci	int (*get)(struct snd_bebob *bebob, u32 *target, unsigned int size);
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_cistruct snd_bebob_spec {
7362306a36Sopenharmony_ci	const struct snd_bebob_clock_spec *clock;
7462306a36Sopenharmony_ci	const struct snd_bebob_rate_spec *rate;
7562306a36Sopenharmony_ci	const struct snd_bebob_meter_spec *meter;
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cienum snd_bebob_quirk {
7962306a36Sopenharmony_ci	SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC = (1 << 0),
8062306a36Sopenharmony_ci	SND_BEBOB_QUIRK_WRONG_DBC		  = (1 << 1),
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct snd_bebob {
8462306a36Sopenharmony_ci	struct snd_card *card;
8562306a36Sopenharmony_ci	struct fw_unit *unit;
8662306a36Sopenharmony_ci	int card_index;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	struct mutex mutex;
8962306a36Sopenharmony_ci	spinlock_t lock;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	const struct snd_bebob_spec *spec;
9262306a36Sopenharmony_ci	unsigned int quirks;	// Combination of snd_bebob_quirk enumerations.
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	unsigned int midi_input_ports;
9562306a36Sopenharmony_ci	unsigned int midi_output_ports;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	struct amdtp_stream tx_stream;
9862306a36Sopenharmony_ci	struct amdtp_stream rx_stream;
9962306a36Sopenharmony_ci	struct cmp_connection out_conn;
10062306a36Sopenharmony_ci	struct cmp_connection in_conn;
10162306a36Sopenharmony_ci	unsigned int substreams_counter;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	struct snd_bebob_stream_formation
10462306a36Sopenharmony_ci		tx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES];
10562306a36Sopenharmony_ci	struct snd_bebob_stream_formation
10662306a36Sopenharmony_ci		rx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES];
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	int sync_input_plug;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* for uapi */
11162306a36Sopenharmony_ci	int dev_lock_count;
11262306a36Sopenharmony_ci	bool dev_lock_changed;
11362306a36Sopenharmony_ci	wait_queue_head_t hwdep_wait;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* for M-Audio special devices */
11662306a36Sopenharmony_ci	void *maudio_special_quirk;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	struct amdtp_domain domain;
11962306a36Sopenharmony_ci};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic inline int
12262306a36Sopenharmony_cisnd_bebob_read_block(struct fw_unit *unit, u64 addr, void *buf, int size)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	return snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
12562306a36Sopenharmony_ci				  BEBOB_ADDR_REG_INFO + addr,
12662306a36Sopenharmony_ci				  buf, size, 0);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic inline int
13062306a36Sopenharmony_cisnd_bebob_read_quad(struct fw_unit *unit, u64 addr, u32 *buf)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	return snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
13362306a36Sopenharmony_ci				  BEBOB_ADDR_REG_INFO + addr,
13462306a36Sopenharmony_ci				  (void *)buf, sizeof(u32), 0);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/* AV/C Audio Subunit Specification 1.0 (Oct 2000, 1394TA) */
13862306a36Sopenharmony_ciint avc_audio_set_selector(struct fw_unit *unit, unsigned int subunit_id,
13962306a36Sopenharmony_ci			   unsigned int fb_id, unsigned int num);
14062306a36Sopenharmony_ciint avc_audio_get_selector(struct fw_unit *unit, unsigned  int subunit_id,
14162306a36Sopenharmony_ci			   unsigned int fb_id, unsigned int *num);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci/*
14462306a36Sopenharmony_ci * AVC command extensions, AV/C Unit and Subunit, Revision 17
14562306a36Sopenharmony_ci * (Nov 2003, BridgeCo)
14662306a36Sopenharmony_ci */
14762306a36Sopenharmony_ci#define	AVC_BRIDGECO_ADDR_BYTES	6
14862306a36Sopenharmony_cienum avc_bridgeco_plug_dir {
14962306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_DIR_IN	= 0x00,
15062306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_DIR_OUT	= 0x01
15162306a36Sopenharmony_ci};
15262306a36Sopenharmony_cienum avc_bridgeco_plug_mode {
15362306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_MODE_UNIT		= 0x00,
15462306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_MODE_SUBUNIT		= 0x01,
15562306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_MODE_FUNCTION_BLOCK	= 0x02
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_cienum avc_bridgeco_plug_unit {
15862306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_UNIT_ISOC	= 0x00,
15962306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_UNIT_EXT	= 0x01,
16062306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_UNIT_ASYNC	= 0x02
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_cienum avc_bridgeco_plug_type {
16362306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_TYPE_ISOC	= 0x00,
16462306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_TYPE_ASYNC	= 0x01,
16562306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_TYPE_MIDI	= 0x02,
16662306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_TYPE_SYNC	= 0x03,
16762306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_TYPE_ANA	= 0x04,
16862306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_TYPE_DIG	= 0x05,
16962306a36Sopenharmony_ci	AVC_BRIDGECO_PLUG_TYPE_ADDITION	= 0x06
17062306a36Sopenharmony_ci};
17162306a36Sopenharmony_cistatic inline void
17262306a36Sopenharmony_ciavc_bridgeco_fill_unit_addr(u8 buf[AVC_BRIDGECO_ADDR_BYTES],
17362306a36Sopenharmony_ci			    enum avc_bridgeco_plug_dir dir,
17462306a36Sopenharmony_ci			    enum avc_bridgeco_plug_unit unit,
17562306a36Sopenharmony_ci			    unsigned int pid)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	buf[0] = 0xff;	/* Unit */
17862306a36Sopenharmony_ci	buf[1] = dir;
17962306a36Sopenharmony_ci	buf[2] = AVC_BRIDGECO_PLUG_MODE_UNIT;
18062306a36Sopenharmony_ci	buf[3] = unit;
18162306a36Sopenharmony_ci	buf[4] = 0xff & pid;
18262306a36Sopenharmony_ci	buf[5] = 0xff;	/* reserved */
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_cistatic inline void
18562306a36Sopenharmony_ciavc_bridgeco_fill_msu_addr(u8 buf[AVC_BRIDGECO_ADDR_BYTES],
18662306a36Sopenharmony_ci			   enum avc_bridgeco_plug_dir dir,
18762306a36Sopenharmony_ci			   unsigned int pid)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	buf[0] = 0x60;	/* Music subunit */
19062306a36Sopenharmony_ci	buf[1] = dir;
19162306a36Sopenharmony_ci	buf[2] = AVC_BRIDGECO_PLUG_MODE_SUBUNIT;
19262306a36Sopenharmony_ci	buf[3] = 0xff & pid;
19362306a36Sopenharmony_ci	buf[4] = 0xff;	/* reserved */
19462306a36Sopenharmony_ci	buf[5] = 0xff;	/* reserved */
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ciint avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
19762306a36Sopenharmony_ci				 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
19862306a36Sopenharmony_ci				 u8 *buf, unsigned int len);
19962306a36Sopenharmony_ciint avc_bridgeco_get_plug_type(struct fw_unit *unit,
20062306a36Sopenharmony_ci			       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
20162306a36Sopenharmony_ci			       enum avc_bridgeco_plug_type *type);
20262306a36Sopenharmony_ciint avc_bridgeco_get_plug_ch_count(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES],
20362306a36Sopenharmony_ci				   unsigned int *ch_count);
20462306a36Sopenharmony_ciint avc_bridgeco_get_plug_section_type(struct fw_unit *unit,
20562306a36Sopenharmony_ci				       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
20662306a36Sopenharmony_ci				       unsigned int id, u8 *type);
20762306a36Sopenharmony_ciint avc_bridgeco_get_plug_input(struct fw_unit *unit,
20862306a36Sopenharmony_ci				u8 addr[AVC_BRIDGECO_ADDR_BYTES],
20962306a36Sopenharmony_ci				u8 input[7]);
21062306a36Sopenharmony_ciint avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit,
21162306a36Sopenharmony_ci				   u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf,
21262306a36Sopenharmony_ci				   unsigned int *len, unsigned int eid);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/* for AMDTP streaming */
21562306a36Sopenharmony_ciint snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *rate);
21662306a36Sopenharmony_ciint snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate);
21762306a36Sopenharmony_ciint snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
21862306a36Sopenharmony_ci				   enum snd_bebob_clock_type *src);
21962306a36Sopenharmony_ciint snd_bebob_stream_discover(struct snd_bebob *bebob);
22062306a36Sopenharmony_ciint snd_bebob_stream_init_duplex(struct snd_bebob *bebob);
22162306a36Sopenharmony_ciint snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate,
22262306a36Sopenharmony_ci				    unsigned int frames_per_period,
22362306a36Sopenharmony_ci				    unsigned int frames_per_buffer);
22462306a36Sopenharmony_ciint snd_bebob_stream_start_duplex(struct snd_bebob *bebob);
22562306a36Sopenharmony_civoid snd_bebob_stream_stop_duplex(struct snd_bebob *bebob);
22662306a36Sopenharmony_civoid snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_civoid snd_bebob_stream_lock_changed(struct snd_bebob *bebob);
22962306a36Sopenharmony_ciint snd_bebob_stream_lock_try(struct snd_bebob *bebob);
23062306a36Sopenharmony_civoid snd_bebob_stream_lock_release(struct snd_bebob *bebob);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_civoid snd_bebob_proc_init(struct snd_bebob *bebob);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ciint snd_bebob_create_midi_devices(struct snd_bebob *bebob);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ciint snd_bebob_create_pcm_devices(struct snd_bebob *bebob);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ciint snd_bebob_create_hwdep_device(struct snd_bebob *bebob);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/* model specific operations */
24162306a36Sopenharmony_ciextern const struct snd_bebob_spec phase88_rack_spec;
24262306a36Sopenharmony_ciextern const struct snd_bebob_spec yamaha_terratec_spec;
24362306a36Sopenharmony_ciextern const struct snd_bebob_spec saffirepro_26_spec;
24462306a36Sopenharmony_ciextern const struct snd_bebob_spec saffirepro_10_spec;
24562306a36Sopenharmony_ciextern const struct snd_bebob_spec saffire_le_spec;
24662306a36Sopenharmony_ciextern const struct snd_bebob_spec saffire_spec;
24762306a36Sopenharmony_ciextern const struct snd_bebob_spec maudio_fw410_spec;
24862306a36Sopenharmony_ciextern const struct snd_bebob_spec maudio_audiophile_spec;
24962306a36Sopenharmony_ciextern const struct snd_bebob_spec maudio_solo_spec;
25062306a36Sopenharmony_ciextern const struct snd_bebob_spec maudio_ozonic_spec;
25162306a36Sopenharmony_ciextern const struct snd_bebob_spec maudio_nrv10_spec;
25262306a36Sopenharmony_ciextern const struct snd_bebob_spec maudio_special_spec;
25362306a36Sopenharmony_ciint snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814);
25462306a36Sopenharmony_ciint snd_bebob_maudio_load_firmware(struct fw_unit *unit);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci#endif
257