ALSA: dice: code refactoring to keep isochronous resources

This commit is a part of preparation to perform allocation/release
of isochronous resources in pcm.hw_params/hw_free callbacks.

This commit adds a helper function to allocate isochronous resources,
separated from operations to start packet streaming, I note that some
dice-based devices have two pair of endpoints for isochronous packet
straeming.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Sakamoto 2019-06-11 22:21:15 +09:00 committed by Takashi Iwai
parent b3480638a5
commit c738aed136
1 changed files with 90 additions and 75 deletions

View File

@ -175,35 +175,22 @@ static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
}
}
static int keep_resources(struct snd_dice *dice,
enum amdtp_stream_direction dir, unsigned int index,
unsigned int rate, unsigned int pcm_chs,
unsigned int midi_ports)
static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,
struct fw_iso_resources *resources, unsigned int rate,
unsigned int pcm_chs, unsigned int midi_ports)
{
struct amdtp_stream *stream;
struct fw_iso_resources *resources;
bool double_pcm_frames;
unsigned int i;
int err;
if (dir == AMDTP_IN_STREAM) {
stream = &dice->tx_stream[index];
resources = &dice->tx_resources[index];
} else {
stream = &dice->rx_stream[index];
resources = &dice->rx_resources[index];
}
/*
* At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
* one data block of AMDTP packet. Thus sampling transfer frequency is
* a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
* transferred on AMDTP packets at 96 kHz. Two successive samples of a
* channel are stored consecutively in the packet. This quirk is called
* as 'Dual Wire'.
* For this quirk, blocking mode is required and PCM buffer size should
* be aligned to SYT_INTERVAL.
*/
// At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
// one data block of AMDTP packet. Thus sampling transfer frequency is
// a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
// transferred on AMDTP packets at 96 kHz. Two successive samples of a
// channel are stored consecutively in the packet. This quirk is called
// as 'Dual Wire'.
// For this quirk, blocking mode is required and PCM buffer size should
// be aligned to SYT_INTERVAL.
double_pcm_frames = rate > 96000;
if (double_pcm_frames) {
rate /= 2;
@ -230,6 +217,68 @@ static int keep_resources(struct snd_dice *dice,
fw_parent_device(dice->unit)->max_speed);
}
static int keep_dual_resources(struct snd_dice *dice, unsigned int rate,
enum amdtp_stream_direction dir,
struct reg_params *params)
{
enum snd_dice_rate_mode mode;
int i;
int err;
err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
if (err < 0)
return err;
for (i = 0; i < params->count; ++i) {
__be32 reg[2];
struct amdtp_stream *stream;
struct fw_iso_resources *resources;
unsigned int pcm_cache;
unsigned int midi_cache;
unsigned int pcm_chs;
unsigned int midi_ports;
if (dir == AMDTP_IN_STREAM) {
stream = &dice->tx_stream[i];
resources = &dice->tx_resources[i];
pcm_cache = dice->tx_pcm_chs[i][mode];
midi_cache = dice->tx_midi_ports[i];
err = snd_dice_transaction_read_tx(dice,
params->size * i + TX_NUMBER_AUDIO,
reg, sizeof(reg));
} else {
stream = &dice->rx_stream[i];
resources = &dice->rx_resources[i];
pcm_cache = dice->rx_pcm_chs[i][mode];
midi_cache = dice->rx_midi_ports[i];
err = snd_dice_transaction_read_rx(dice,
params->size * i + RX_NUMBER_AUDIO,
reg, sizeof(reg));
}
if (err < 0)
return err;
pcm_chs = be32_to_cpu(reg[0]);
midi_ports = be32_to_cpu(reg[1]);
// These are important for developer of this driver.
if (pcm_chs != pcm_cache || midi_ports != midi_cache) {
dev_info(&dice->unit->device,
"cache mismatch: pcm: %u:%u, midi: %u:%u\n",
pcm_chs, pcm_cache, midi_ports, midi_cache);
return -EPROTO;
}
err = keep_resources(dice, stream, resources, rate, pcm_chs,
midi_ports);
if (err < 0)
return err;
}
return 0;
}
static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
struct reg_params *rx_params)
{
@ -242,84 +291,50 @@ static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
unsigned int rate, struct reg_params *params)
{
__be32 reg[2];
enum snd_dice_rate_mode mode;
unsigned int i, pcm_chs, midi_ports;
struct amdtp_stream *streams;
struct fw_iso_resources *resources;
struct fw_device *fw_dev = fw_parent_device(dice->unit);
int err = 0;
unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;
int i;
int err;
if (dir == AMDTP_IN_STREAM) {
streams = dice->tx_stream;
resources = dice->tx_resources;
} else {
streams = dice->rx_stream;
resources = dice->rx_resources;
}
err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
err = keep_dual_resources(dice, rate, dir, params);
if (err < 0)
return err;
for (i = 0; i < params->count; i++) {
unsigned int pcm_cache;
unsigned int midi_cache;
struct amdtp_stream *stream;
struct fw_iso_resources *resources;
__be32 reg;
if (dir == AMDTP_IN_STREAM) {
pcm_cache = dice->tx_pcm_chs[i][mode];
midi_cache = dice->tx_midi_ports[i];
err = snd_dice_transaction_read_tx(dice,
params->size * i + TX_NUMBER_AUDIO,
reg, sizeof(reg));
stream = dice->tx_stream + i;
resources = dice->tx_resources + i;
} else {
pcm_cache = dice->rx_pcm_chs[i][mode];
midi_cache = dice->rx_midi_ports[i];
err = snd_dice_transaction_read_rx(dice,
params->size * i + RX_NUMBER_AUDIO,
reg, sizeof(reg));
}
if (err < 0)
return err;
pcm_chs = be32_to_cpu(reg[0]);
midi_ports = be32_to_cpu(reg[1]);
/* These are important for developer of this driver. */
if (pcm_chs != pcm_cache || midi_ports != midi_cache) {
dev_info(&dice->unit->device,
"cache mismatch: pcm: %u:%u, midi: %u:%u\n",
pcm_chs, pcm_cache, midi_ports, midi_cache);
return -EPROTO;
stream = dice->rx_stream + i;
resources = dice->rx_resources + i;
}
err = keep_resources(dice, dir, i, rate, pcm_chs, midi_ports);
if (err < 0)
return err;
reg[0] = cpu_to_be32(resources[i].channel);
reg = cpu_to_be32(resources->channel);
if (dir == AMDTP_IN_STREAM) {
err = snd_dice_transaction_write_tx(dice,
params->size * i + TX_ISOCHRONOUS,
reg, sizeof(reg[0]));
&reg, sizeof(reg));
} else {
err = snd_dice_transaction_write_rx(dice,
params->size * i + RX_ISOCHRONOUS,
reg, sizeof(reg[0]));
&reg, sizeof(reg));
}
if (err < 0)
return err;
if (dir == AMDTP_IN_STREAM) {
reg[0] = cpu_to_be32(fw_dev->max_speed);
reg = cpu_to_be32(max_speed);
err = snd_dice_transaction_write_tx(dice,
params->size * i + TX_SPEED,
reg, sizeof(reg[0]));
&reg, sizeof(reg));
if (err < 0)
return err;
}
err = amdtp_stream_start(&streams[i], resources[i].channel,
fw_dev->max_speed);
err = amdtp_stream_start(stream, resources->channel, max_speed);
if (err < 0)
return err;
}