2019-05-30 07:57:59 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2014-04-25 21:45:02 +08:00
|
|
|
/*
|
|
|
|
* fireworks_stream.c - a part of driver for Fireworks based devices
|
|
|
|
*
|
|
|
|
* Copyright (c) 2013-2014 Takashi Sakamoto
|
|
|
|
*/
|
|
|
|
#include "./fireworks.h"
|
|
|
|
|
2021-05-31 10:50:59 +08:00
|
|
|
#define READY_TIMEOUT_MS 1000
|
2014-04-25 21:45:02 +08:00
|
|
|
|
2019-08-04 14:21:24 +08:00
|
|
|
static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream)
|
2014-04-25 21:45:02 +08:00
|
|
|
{
|
|
|
|
struct cmp_connection *conn;
|
|
|
|
enum cmp_direction c_dir;
|
|
|
|
enum amdtp_stream_direction s_dir;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (stream == &efw->tx_stream) {
|
|
|
|
conn = &efw->out_conn;
|
|
|
|
c_dir = CMP_OUTPUT;
|
|
|
|
s_dir = AMDTP_IN_STREAM;
|
|
|
|
} else {
|
|
|
|
conn = &efw->in_conn;
|
|
|
|
c_dir = CMP_INPUT;
|
|
|
|
s_dir = AMDTP_OUT_STREAM;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = cmp_connection_init(conn, efw->unit, c_dir, 0);
|
|
|
|
if (err < 0)
|
2019-08-04 14:21:24 +08:00
|
|
|
return err;
|
2014-04-25 21:45:02 +08:00
|
|
|
|
2021-05-31 10:50:59 +08:00
|
|
|
err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING | CIP_UNAWARE_SYT);
|
2014-04-25 21:45:02 +08:00
|
|
|
if (err < 0) {
|
|
|
|
amdtp_stream_destroy(stream);
|
|
|
|
cmp_connection_destroy(conn);
|
2019-08-04 14:21:24 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stream == &efw->tx_stream) {
|
|
|
|
// Fireworks transmits NODATA packets with TAG0.
|
|
|
|
efw->tx_stream.flags |= CIP_EMPTY_WITH_TAG0;
|
|
|
|
// Fireworks has its own meaning for dbc.
|
|
|
|
efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT;
|
|
|
|
// Fireworks reset dbc at bus reset.
|
|
|
|
efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK;
|
|
|
|
// But Recent firmwares starts packets with non-zero dbc.
|
|
|
|
// Driver version 5.7.6 installs firmware version 5.7.3.
|
|
|
|
if (efw->is_fireworks3 &&
|
|
|
|
(efw->firmware_version == 0x5070000 ||
|
|
|
|
efw->firmware_version == 0x5070300 ||
|
|
|
|
efw->firmware_version == 0x5080000))
|
|
|
|
efw->tx_stream.flags |= CIP_UNALIGHED_DBC;
|
ALSA: fireworks: add support for Loud Onyx 1200f quirk
Loud Technologies shipped Onyx 1200f 2008 in its Mackie brand and
already discontinued. The model uses component of Fireworks board
module as its communication and DSP function.
The latest firmware (v4.6.0) has a quirk that tx packet includes wrong
value (0x1f) in its dbs field at middle and higher sampling transfer
frequency. It brings ALSA fireworks driver discontinuity of data block
counter.
This commit fixes it by assuming it as a quirk of firmware version
4.6.0.
$ cd linux-firewire-tools/src
$ python crpp < /sys/bus/firewire/devices/fw1/config_rom
ROM header and bus information block
-----------------------------------------------------------------
400 0404b9ef bus_info_length 4, crc_length 4, crc 47599
404 31333934 bus_name "1394"
408 e064a212 irmc 1, cmc 1, isc 1, bmc 0, pmc 0, cyc_clk_acc 100,
max_rec 10 (2048), max_rom 2, gen 1, spd 2 (S400)
40c 000ff209 company_id 000ff2 |
410 62550ce0 device_id 0962550ce0 | EUI-64 000ff20962550ce0
root directory
-----------------------------------------------------------------
414 0008088e directory_length 8, crc 2190
418 03000ff2 vendor
41c 8100000f --> descriptor leaf at 458
420 1701200f model
424 81000018 --> descriptor leaf at 484
428 0c008380 node capabilities
42c 8d000003 --> eui-64 leaf at 438
430 d1000005 --> unit directory at 444
434 08000ff2 (immediate value)
eui-64 leaf at 438
-----------------------------------------------------------------
438 000281ae leaf_length 2, crc 33198
43c 000ff209 company_id 000ff2 |
440 62550ce0 device_id 0962550ce0 | EUI-64 000ff20962550ce0
unit directory at 444
-----------------------------------------------------------------
444 00045d94 directory_length 4, crc 23956
448 1200a02d specifier id: 1394 TA
44c 13010000 version
450 1701200f model
454 8100000c --> descriptor leaf at 484
descriptor leaf at 458
-----------------------------------------------------------------
458 000a199d leaf_length 10, crc 6557
45c 00000000 textual descriptor
460 00000000 minimal ASCII
464 4d61636b "Mack"
468 69650000 "ie"
46c 00000000
470 00000000
474 00000000
478 00000000
47c 00000000
480 00000000
descriptor leaf at 484
-----------------------------------------------------------------
484 000a0964 leaf_length 10, crc 2404
488 00000000 textual descriptor
48c 00000000 minimal ASCII
490 4f6e7978 "Onyx"
494 20313230 " 120"
498 30460000 "0F"
49c 00000000
4a0 00000000
4a4 00000000
4a8 00000000
4ac 00000000
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20211111103015.7498-1-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-11-11 18:30:15 +08:00
|
|
|
// AudioFire9 always reports wrong dbs. Onyx 1200F with the latest firmware (v4.6.0)
|
|
|
|
// also report wrong dbs at 88.2 kHz or greater.
|
|
|
|
if (efw->is_af9 || efw->firmware_version == 0x4060000)
|
2019-08-04 14:21:24 +08:00
|
|
|
efw->tx_stream.flags |= CIP_WRONG_DBS;
|
|
|
|
// Firmware version 5.5 reports fixed interval for dbc.
|
|
|
|
if (efw->firmware_version == 0x5050000)
|
|
|
|
efw->tx_stream.ctx_data.tx.dbc_interval = 8;
|
2014-04-25 21:45:02 +08:00
|
|
|
}
|
2019-08-04 14:21:24 +08:00
|
|
|
|
2014-04-25 21:45:02 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-06-12 16:44:12 +08:00
|
|
|
static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
|
|
|
|
unsigned int rate)
|
2014-04-25 21:45:02 +08:00
|
|
|
{
|
|
|
|
struct cmp_connection *conn;
|
|
|
|
int err;
|
|
|
|
|
2019-06-12 16:44:12 +08:00
|
|
|
if (stream == &efw->tx_stream)
|
2014-04-25 21:45:02 +08:00
|
|
|
conn = &efw->out_conn;
|
2019-06-12 16:44:12 +08:00
|
|
|
else
|
2014-04-25 21:45:02 +08:00
|
|
|
conn = &efw->in_conn;
|
|
|
|
|
2019-06-12 16:44:12 +08:00
|
|
|
// Establish connection via CMP.
|
2019-06-15 17:11:01 +08:00
|
|
|
err = cmp_connection_establish(conn);
|
2014-04-25 21:45:02 +08:00
|
|
|
if (err < 0)
|
2019-06-12 16:44:12 +08:00
|
|
|
return err;
|
2014-04-25 21:45:02 +08:00
|
|
|
|
2019-06-12 16:44:12 +08:00
|
|
|
// Start amdtp stream.
|
2019-08-04 14:21:31 +08:00
|
|
|
err = amdtp_domain_add_stream(&efw->domain, stream,
|
|
|
|
conn->resources.channel, conn->speed);
|
2014-04-25 21:45:02 +08:00
|
|
|
if (err < 0) {
|
2019-06-12 16:44:12 +08:00
|
|
|
cmp_connection_break(conn);
|
|
|
|
return err;
|
2014-04-25 21:45:02 +08:00
|
|
|
}
|
|
|
|
|
2019-06-12 16:44:12 +08:00
|
|
|
return 0;
|
2014-04-25 21:45:02 +08:00
|
|
|
}
|
|
|
|
|
2019-08-04 14:21:24 +08:00
|
|
|
// This function should be called before starting the stream or after stopping
|
|
|
|
// the streams.
|
|
|
|
static void destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
|
2014-04-25 21:45:02 +08:00
|
|
|
{
|
2019-08-04 14:21:24 +08:00
|
|
|
amdtp_stream_destroy(stream);
|
2014-04-25 21:45:02 +08:00
|
|
|
|
|
|
|
if (stream == &efw->tx_stream)
|
2019-08-04 14:21:24 +08:00
|
|
|
cmp_connection_destroy(&efw->out_conn);
|
2014-04-25 21:45:02 +08:00
|
|
|
else
|
2019-08-04 14:21:24 +08:00
|
|
|
cmp_connection_destroy(&efw->in_conn);
|
2014-04-25 21:45:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
check_connection_used_by_others(struct snd_efw *efw, struct amdtp_stream *s)
|
|
|
|
{
|
|
|
|
struct cmp_connection *conn;
|
|
|
|
bool used;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (s == &efw->tx_stream)
|
|
|
|
conn = &efw->out_conn;
|
|
|
|
else
|
|
|
|
conn = &efw->in_conn;
|
|
|
|
|
|
|
|
err = cmp_connection_check_used(conn, &used);
|
|
|
|
if ((err >= 0) && used && !amdtp_stream_running(s)) {
|
|
|
|
dev_err(&efw->unit->device,
|
|
|
|
"Connection established by others: %cPCR[%d]\n",
|
|
|
|
(conn->direction == CMP_OUTPUT) ? 'o' : 'i',
|
|
|
|
conn->pcr_index);
|
|
|
|
err = -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int snd_efw_stream_init_duplex(struct snd_efw *efw)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = init_stream(efw, &efw->tx_stream);
|
|
|
|
if (err < 0)
|
2019-08-04 14:21:24 +08:00
|
|
|
return err;
|
2014-04-25 21:45:02 +08:00
|
|
|
|
|
|
|
err = init_stream(efw, &efw->rx_stream);
|
|
|
|
if (err < 0) {
|
|
|
|
destroy_stream(efw, &efw->tx_stream);
|
2019-08-04 14:21:24 +08:00
|
|
|
return err;
|
2014-04-25 21:45:02 +08:00
|
|
|
}
|
|
|
|
|
2019-08-04 14:21:31 +08:00
|
|
|
err = amdtp_domain_init(&efw->domain);
|
|
|
|
if (err < 0) {
|
|
|
|
destroy_stream(efw, &efw->tx_stream);
|
|
|
|
destroy_stream(efw, &efw->rx_stream);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-08-04 14:21:24 +08:00
|
|
|
// set IEC61883 compliant mode (actually not fully compliant...).
|
2014-04-25 21:45:02 +08:00
|
|
|
err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883);
|
|
|
|
if (err < 0) {
|
|
|
|
destroy_stream(efw, &efw->tx_stream);
|
|
|
|
destroy_stream(efw, &efw->rx_stream);
|
|
|
|
}
|
2019-08-04 14:21:24 +08:00
|
|
|
|
2014-04-25 21:45:02 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-06-12 16:44:12 +08:00
|
|
|
static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream,
|
|
|
|
unsigned int rate, unsigned int mode)
|
|
|
|
{
|
|
|
|
unsigned int pcm_channels;
|
|
|
|
unsigned int midi_ports;
|
2019-06-15 17:11:01 +08:00
|
|
|
struct cmp_connection *conn;
|
|
|
|
int err;
|
2019-06-12 16:44:12 +08:00
|
|
|
|
|
|
|
if (stream == &efw->tx_stream) {
|
|
|
|
pcm_channels = efw->pcm_capture_channels[mode];
|
|
|
|
midi_ports = efw->midi_out_ports;
|
2019-06-15 17:11:01 +08:00
|
|
|
conn = &efw->out_conn;
|
2019-06-12 16:44:12 +08:00
|
|
|
} else {
|
|
|
|
pcm_channels = efw->pcm_playback_channels[mode];
|
|
|
|
midi_ports = efw->midi_in_ports;
|
2019-06-15 17:11:01 +08:00
|
|
|
conn = &efw->in_conn;
|
2019-06-12 16:44:12 +08:00
|
|
|
}
|
|
|
|
|
2019-06-15 17:11:01 +08:00
|
|
|
err = amdtp_am824_set_parameters(stream, rate, pcm_channels,
|
|
|
|
midi_ports, false);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
|
2019-06-12 16:44:12 +08:00
|
|
|
}
|
|
|
|
|
2019-10-07 19:05:18 +08:00
|
|
|
int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate,
|
2019-10-17 23:54:15 +08:00
|
|
|
unsigned int frames_per_period,
|
|
|
|
unsigned int frames_per_buffer)
|
2014-04-25 21:45:02 +08:00
|
|
|
{
|
|
|
|
unsigned int curr_rate;
|
2019-06-12 16:44:11 +08:00
|
|
|
int err;
|
2014-04-25 21:45:02 +08:00
|
|
|
|
2019-06-12 16:44:11 +08:00
|
|
|
// Considering JACK/FFADO streaming:
|
|
|
|
// TODO: This can be removed hwdep functionality becomes popular.
|
ALSA: fireworks: drop reuse of incoming packet parameter for ougoing packet parameter
On Fireworks board module of Echo Audio, TSB43Cx43A (IceLynx Micro, iCEM)
is used to process payload of isochronous packets. There's an public
document of this chip[1]. This document is for firmware programmers to
transfer/receive AMDTP with IEC60958 data format, however in clause 2.5,
2.6 and 2.7, we can see system design to utilize the sequence of value in
SYT field of CIP header. In clause 2.3, we can see the specification of
Audio Master Clock (MCLK) from iCEM.
Well, this clock is actually not used for sampling clock. This can be
confirmed when corresponding driver transfer random value as the sequence
of SYT field. Even if in this case, the unit generates proper sound.
Additionally, in unique command set for this board module, the format
of CIP is changed; for IEC 61883-6 mode which we use, and for Windows
Operating System. In the latter mode, the whole 32 bit field in second CIP
header from Windows driver is used to represent counter of packets (NO-DATA
code is still used for packets without data blocks). If the master clock
was physically used by DSP on the board module, the Windows driver must
have transferred correct sequence of SYT field.
Furthermore, as long as seeing capacities of AudioFire2, AudioFire4,
AudioFire8, AudioFirePre8 and AudioFire12, these models don't support
SYT-Match clock source.
Summary, we have no need to relate incoming/outgoing packets. This commit
drops reusing SYT sequence of incoming packets for outgoing packets.
[1] Using TSB43Cx43A: S/PDIF over 1394 (2003, Texus Instruments
Incorporated)
http://www.ti.com/analog/docs/litabsmultiplefilelist.tsp?literatureNumber=slla148&docCategoryId=1&familyId=361
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2016-05-09 22:15:51 +08:00
|
|
|
err = check_connection_used_by_others(efw, &efw->rx_stream);
|
2014-04-25 21:45:02 +08:00
|
|
|
if (err < 0)
|
2019-06-12 16:44:11 +08:00
|
|
|
return err;
|
2014-04-25 21:45:02 +08:00
|
|
|
|
2019-06-12 16:44:11 +08:00
|
|
|
// stop streams if rate is different.
|
2014-04-25 21:45:02 +08:00
|
|
|
err = snd_efw_command_get_sampling_rate(efw, &curr_rate);
|
|
|
|
if (err < 0)
|
2019-06-12 16:44:11 +08:00
|
|
|
return err;
|
2014-04-25 21:45:02 +08:00
|
|
|
if (rate == 0)
|
|
|
|
rate = curr_rate;
|
2019-06-12 16:44:11 +08:00
|
|
|
if (rate != curr_rate) {
|
2019-08-04 14:21:31 +08:00
|
|
|
amdtp_domain_stop(&efw->domain);
|
|
|
|
|
|
|
|
cmp_connection_break(&efw->out_conn);
|
|
|
|
cmp_connection_break(&efw->in_conn);
|
2019-06-18 21:26:21 +08:00
|
|
|
|
|
|
|
cmp_connection_release(&efw->out_conn);
|
|
|
|
cmp_connection_release(&efw->in_conn);
|
2014-04-25 21:45:02 +08:00
|
|
|
}
|
|
|
|
|
2019-06-12 16:44:11 +08:00
|
|
|
if (efw->substreams_counter == 0 || rate != curr_rate) {
|
2019-06-12 16:44:12 +08:00
|
|
|
unsigned int mode;
|
|
|
|
|
2014-04-25 21:45:02 +08:00
|
|
|
err = snd_efw_command_set_sampling_rate(efw, rate);
|
|
|
|
if (err < 0)
|
2019-06-12 16:44:11 +08:00
|
|
|
return err;
|
2019-06-12 16:44:12 +08:00
|
|
|
|
|
|
|
err = snd_efw_get_multiplier_mode(rate, &mode);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = keep_resources(efw, &efw->tx_stream, rate, mode);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = keep_resources(efw, &efw->rx_stream, rate, mode);
|
2019-06-15 17:11:01 +08:00
|
|
|
if (err < 0) {
|
|
|
|
cmp_connection_release(&efw->in_conn);
|
2019-06-12 16:44:12 +08:00
|
|
|
return err;
|
2019-06-15 17:11:01 +08:00
|
|
|
}
|
2019-10-07 19:05:18 +08:00
|
|
|
|
|
|
|
err = amdtp_domain_set_events_per_period(&efw->domain,
|
2019-10-17 23:54:15 +08:00
|
|
|
frames_per_period, frames_per_buffer);
|
2019-10-07 19:05:18 +08:00
|
|
|
if (err < 0) {
|
|
|
|
cmp_connection_release(&efw->in_conn);
|
|
|
|
cmp_connection_release(&efw->out_conn);
|
|
|
|
return err;
|
|
|
|
}
|
2019-06-12 16:44:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int snd_efw_stream_start_duplex(struct snd_efw *efw)
|
|
|
|
{
|
|
|
|
unsigned int rate;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
// Need no substreams.
|
|
|
|
if (efw->substreams_counter == 0)
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
if (amdtp_streaming_error(&efw->rx_stream) ||
|
|
|
|
amdtp_streaming_error(&efw->tx_stream)) {
|
2019-08-04 14:21:31 +08:00
|
|
|
amdtp_domain_stop(&efw->domain);
|
|
|
|
cmp_connection_break(&efw->out_conn);
|
|
|
|
cmp_connection_break(&efw->in_conn);
|
2019-06-12 16:44:11 +08:00
|
|
|
}
|
|
|
|
|
2019-08-04 14:21:31 +08:00
|
|
|
err = snd_efw_command_get_sampling_rate(efw, &rate);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2019-06-12 16:44:11 +08:00
|
|
|
if (!amdtp_stream_running(&efw->rx_stream)) {
|
2021-05-31 10:50:59 +08:00
|
|
|
unsigned int tx_init_skip_cycles;
|
|
|
|
|
|
|
|
// Audiofire 2/4 skip an isochronous cycle several thousands after starting
|
|
|
|
// packet transmission.
|
|
|
|
if (efw->is_fireworks3 && !efw->is_af9)
|
|
|
|
tx_init_skip_cycles = 6000;
|
|
|
|
else
|
|
|
|
tx_init_skip_cycles = 0;
|
|
|
|
|
ALSA: fireworks: drop reuse of incoming packet parameter for ougoing packet parameter
On Fireworks board module of Echo Audio, TSB43Cx43A (IceLynx Micro, iCEM)
is used to process payload of isochronous packets. There's an public
document of this chip[1]. This document is for firmware programmers to
transfer/receive AMDTP with IEC60958 data format, however in clause 2.5,
2.6 and 2.7, we can see system design to utilize the sequence of value in
SYT field of CIP header. In clause 2.3, we can see the specification of
Audio Master Clock (MCLK) from iCEM.
Well, this clock is actually not used for sampling clock. This can be
confirmed when corresponding driver transfer random value as the sequence
of SYT field. Even if in this case, the unit generates proper sound.
Additionally, in unique command set for this board module, the format
of CIP is changed; for IEC 61883-6 mode which we use, and for Windows
Operating System. In the latter mode, the whole 32 bit field in second CIP
header from Windows driver is used to represent counter of packets (NO-DATA
code is still used for packets without data blocks). If the master clock
was physically used by DSP on the board module, the Windows driver must
have transferred correct sequence of SYT field.
Furthermore, as long as seeing capacities of AudioFire2, AudioFire4,
AudioFire8, AudioFirePre8 and AudioFire12, these models don't support
SYT-Match clock source.
Summary, we have no need to relate incoming/outgoing packets. This commit
drops reusing SYT sequence of incoming packets for outgoing packets.
[1] Using TSB43Cx43A: S/PDIF over 1394 (2003, Texus Instruments
Incorporated)
http://www.ti.com/analog/docs/litabsmultiplefilelist.tsp?literatureNumber=slla148&docCategoryId=1&familyId=361
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2016-05-09 22:15:51 +08:00
|
|
|
err = start_stream(efw, &efw->rx_stream, rate);
|
2019-08-04 14:21:31 +08:00
|
|
|
if (err < 0)
|
2019-06-12 16:44:11 +08:00
|
|
|
goto error;
|
2014-04-25 21:45:02 +08:00
|
|
|
|
ALSA: fireworks: drop reuse of incoming packet parameter for ougoing packet parameter
On Fireworks board module of Echo Audio, TSB43Cx43A (IceLynx Micro, iCEM)
is used to process payload of isochronous packets. There's an public
document of this chip[1]. This document is for firmware programmers to
transfer/receive AMDTP with IEC60958 data format, however in clause 2.5,
2.6 and 2.7, we can see system design to utilize the sequence of value in
SYT field of CIP header. In clause 2.3, we can see the specification of
Audio Master Clock (MCLK) from iCEM.
Well, this clock is actually not used for sampling clock. This can be
confirmed when corresponding driver transfer random value as the sequence
of SYT field. Even if in this case, the unit generates proper sound.
Additionally, in unique command set for this board module, the format
of CIP is changed; for IEC 61883-6 mode which we use, and for Windows
Operating System. In the latter mode, the whole 32 bit field in second CIP
header from Windows driver is used to represent counter of packets (NO-DATA
code is still used for packets without data blocks). If the master clock
was physically used by DSP on the board module, the Windows driver must
have transferred correct sequence of SYT field.
Furthermore, as long as seeing capacities of AudioFire2, AudioFire4,
AudioFire8, AudioFirePre8 and AudioFire12, these models don't support
SYT-Match clock source.
Summary, we have no need to relate incoming/outgoing packets. This commit
drops reusing SYT sequence of incoming packets for outgoing packets.
[1] Using TSB43Cx43A: S/PDIF over 1394 (2003, Texus Instruments
Incorporated)
http://www.ti.com/analog/docs/litabsmultiplefilelist.tsp?literatureNumber=slla148&docCategoryId=1&familyId=361
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2016-05-09 22:15:51 +08:00
|
|
|
err = start_stream(efw, &efw->tx_stream, rate);
|
2019-08-04 14:21:31 +08:00
|
|
|
if (err < 0)
|
|
|
|
goto error;
|
|
|
|
|
2021-05-31 10:50:59 +08:00
|
|
|
// NOTE: The device ignores presentation time expressed by the value of syt field
|
|
|
|
// of CIP header in received packets. The sequence of the number of data blocks per
|
|
|
|
// packet is important for media clock recovery.
|
|
|
|
err = amdtp_domain_start(&efw->domain, tx_init_skip_cycles, true, false);
|
2019-08-04 14:21:31 +08:00
|
|
|
if (err < 0)
|
|
|
|
goto error;
|
|
|
|
|
2021-05-20 12:01:54 +08:00
|
|
|
if (!amdtp_domain_wait_ready(&efw->domain, READY_TIMEOUT_MS)) {
|
2019-08-04 14:21:31 +08:00
|
|
|
err = -ETIMEDOUT;
|
2019-06-12 16:44:11 +08:00
|
|
|
goto error;
|
2014-04-25 21:45:02 +08:00
|
|
|
}
|
|
|
|
}
|
2019-06-12 16:44:11 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
error:
|
2019-08-04 14:21:31 +08:00
|
|
|
amdtp_domain_stop(&efw->domain);
|
|
|
|
|
|
|
|
cmp_connection_break(&efw->out_conn);
|
|
|
|
cmp_connection_break(&efw->in_conn);
|
|
|
|
|
2014-04-25 21:45:02 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
void snd_efw_stream_stop_duplex(struct snd_efw *efw)
|
|
|
|
{
|
2019-06-12 16:44:08 +08:00
|
|
|
if (efw->substreams_counter == 0) {
|
2019-08-04 14:21:31 +08:00
|
|
|
amdtp_domain_stop(&efw->domain);
|
|
|
|
|
|
|
|
cmp_connection_break(&efw->out_conn);
|
|
|
|
cmp_connection_break(&efw->in_conn);
|
2019-06-15 17:11:01 +08:00
|
|
|
|
|
|
|
cmp_connection_release(&efw->out_conn);
|
|
|
|
cmp_connection_release(&efw->in_conn);
|
2014-04-25 21:45:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void snd_efw_stream_update_duplex(struct snd_efw *efw)
|
|
|
|
{
|
2019-08-04 14:21:31 +08:00
|
|
|
amdtp_domain_stop(&efw->domain);
|
|
|
|
|
|
|
|
cmp_connection_break(&efw->out_conn);
|
|
|
|
cmp_connection_break(&efw->in_conn);
|
2019-08-04 14:21:25 +08:00
|
|
|
|
|
|
|
amdtp_stream_pcm_abort(&efw->rx_stream);
|
|
|
|
amdtp_stream_pcm_abort(&efw->tx_stream);
|
2014-04-25 21:45:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void snd_efw_stream_destroy_duplex(struct snd_efw *efw)
|
|
|
|
{
|
2019-08-04 14:21:31 +08:00
|
|
|
amdtp_domain_destroy(&efw->domain);
|
|
|
|
|
2014-04-25 21:45:02 +08:00
|
|
|
destroy_stream(efw, &efw->rx_stream);
|
|
|
|
destroy_stream(efw, &efw->tx_stream);
|
|
|
|
}
|
2014-04-25 21:45:12 +08:00
|
|
|
|
|
|
|
void snd_efw_stream_lock_changed(struct snd_efw *efw)
|
|
|
|
{
|
|
|
|
efw->dev_lock_changed = true;
|
|
|
|
wake_up(&efw->hwdep_wait);
|
|
|
|
}
|
|
|
|
|
|
|
|
int snd_efw_stream_lock_try(struct snd_efw *efw)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
spin_lock_irq(&efw->lock);
|
|
|
|
|
|
|
|
/* user land lock this */
|
|
|
|
if (efw->dev_lock_count < 0) {
|
|
|
|
err = -EBUSY;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this is the first time */
|
|
|
|
if (efw->dev_lock_count++ == 0)
|
|
|
|
snd_efw_stream_lock_changed(efw);
|
|
|
|
err = 0;
|
|
|
|
end:
|
|
|
|
spin_unlock_irq(&efw->lock);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
void snd_efw_stream_lock_release(struct snd_efw *efw)
|
|
|
|
{
|
|
|
|
spin_lock_irq(&efw->lock);
|
|
|
|
|
|
|
|
if (WARN_ON(efw->dev_lock_count <= 0))
|
|
|
|
goto end;
|
|
|
|
if (--efw->dev_lock_count == 0)
|
|
|
|
snd_efw_stream_lock_changed(efw);
|
|
|
|
end:
|
|
|
|
spin_unlock_irq(&efw->lock);
|
|
|
|
}
|