mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 02:39:48 +00:00
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:
parent
b3480638a5
commit
c738aed136
1 changed files with 90 additions and 75 deletions
|
@ -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]));
|
||||
®, sizeof(reg));
|
||||
} else {
|
||||
err = snd_dice_transaction_write_rx(dice,
|
||||
params->size * i + RX_ISOCHRONOUS,
|
||||
reg, sizeof(reg[0]));
|
||||
®, 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]));
|
||||
®, 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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue