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

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, static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,
enum amdtp_stream_direction dir, unsigned int index, struct fw_iso_resources *resources, unsigned int rate,
unsigned int rate, unsigned int pcm_chs, unsigned int pcm_chs, unsigned int midi_ports)
unsigned int midi_ports)
{ {
struct amdtp_stream *stream;
struct fw_iso_resources *resources;
bool double_pcm_frames; bool double_pcm_frames;
unsigned int i; unsigned int i;
int err; int err;
if (dir == AMDTP_IN_STREAM) { // At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
stream = &dice->tx_stream[index]; // one data block of AMDTP packet. Thus sampling transfer frequency is
resources = &dice->tx_resources[index]; // a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
} else { // transferred on AMDTP packets at 96 kHz. Two successive samples of a
stream = &dice->rx_stream[index]; // channel are stored consecutively in the packet. This quirk is called
resources = &dice->rx_resources[index]; // 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; double_pcm_frames = rate > 96000;
if (double_pcm_frames) { if (double_pcm_frames) {
rate /= 2; rate /= 2;
@ -230,6 +217,68 @@ static int keep_resources(struct snd_dice *dice,
fw_parent_device(dice->unit)->max_speed); 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, static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
struct reg_params *rx_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, static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
unsigned int rate, struct reg_params *params) unsigned int rate, struct reg_params *params)
{ {
__be32 reg[2]; unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;
enum snd_dice_rate_mode mode; int i;
unsigned int i, pcm_chs, midi_ports; int err;
struct amdtp_stream *streams;
struct fw_iso_resources *resources;
struct fw_device *fw_dev = fw_parent_device(dice->unit);
int err = 0;
if (dir == AMDTP_IN_STREAM) { err = keep_dual_resources(dice, rate, dir, params);
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);
if (err < 0) if (err < 0)
return err; return err;
for (i = 0; i < params->count; i++) { for (i = 0; i < params->count; i++) {
unsigned int pcm_cache; struct amdtp_stream *stream;
unsigned int midi_cache; struct fw_iso_resources *resources;
__be32 reg;
if (dir == AMDTP_IN_STREAM) { if (dir == AMDTP_IN_STREAM) {
pcm_cache = dice->tx_pcm_chs[i][mode]; stream = dice->tx_stream + i;
midi_cache = dice->tx_midi_ports[i]; resources = dice->tx_resources + i;
err = snd_dice_transaction_read_tx(dice,
params->size * i + TX_NUMBER_AUDIO,
reg, sizeof(reg));
} else { } else {
pcm_cache = dice->rx_pcm_chs[i][mode]; stream = dice->rx_stream + i;
midi_cache = dice->rx_midi_ports[i]; resources = dice->rx_resources + 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, dir, i, rate, pcm_chs, midi_ports); reg = cpu_to_be32(resources->channel);
if (err < 0)
return err;
reg[0] = cpu_to_be32(resources[i].channel);
if (dir == AMDTP_IN_STREAM) { if (dir == AMDTP_IN_STREAM) {
err = snd_dice_transaction_write_tx(dice, err = snd_dice_transaction_write_tx(dice,
params->size * i + TX_ISOCHRONOUS, params->size * i + TX_ISOCHRONOUS,
reg, sizeof(reg[0])); &reg, sizeof(reg));
} else { } else {
err = snd_dice_transaction_write_rx(dice, err = snd_dice_transaction_write_rx(dice,
params->size * i + RX_ISOCHRONOUS, params->size * i + RX_ISOCHRONOUS,
reg, sizeof(reg[0])); &reg, sizeof(reg));
} }
if (err < 0) if (err < 0)
return err; return err;
if (dir == AMDTP_IN_STREAM) { 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, err = snd_dice_transaction_write_tx(dice,
params->size * i + TX_SPEED, params->size * i + TX_SPEED,
reg, sizeof(reg[0])); &reg, sizeof(reg));
if (err < 0) if (err < 0)
return err; return err;
} }
err = amdtp_stream_start(&streams[i], resources[i].channel, err = amdtp_stream_start(stream, resources->channel, max_speed);
fw_dev->max_speed);
if (err < 0) if (err < 0)
return err; return err;
} }