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
@ -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]));
|
®, 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]));
|
®, 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]));
|
®, 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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user