Commit 9a02843c authored by Takashi Sakamoto's avatar Takashi Sakamoto Committed by Takashi Iwai

ALSA: dice: Add support for duplex streams with synchronization

This commit adds support for AMDTP in-stream. As a result, Dice driver
supports full duplex streams with synchronization.

AMDTP can transfer timestamps in its packets. By handling the timestamp,
devices can synchronize to the other devices or drivers on the same bus.

When Dice chipset is 'enabled', it starts streams with correct settings.
This 'enable' register is global, thus, when a stream is started to run,
an opposite stream can't start unless turning off 'enable'. Therefore
a pair of streams must be running. This causes a loss of CPU usage when
single stream is needed for neither playbacking or capturing.

This commit assumes that playback-only models also have a functionality
to transmit stream for delivering timestamps.

Currently, sampling clock source is restricted to SYT-Match mode. This is
improved in followed commit. I note that at SYT-Match mode, Dice can select
from 4 streams for synchronization but this driver uses the 1st stream only
for simplicity.
Signed-off-by: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
Acked-by: default avatarClemens Ladisch <clemens@ladisch.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 288a8d0c
...@@ -181,7 +181,7 @@ static int playback_hw_free(struct snd_pcm_substream *substream) ...@@ -181,7 +181,7 @@ static int playback_hw_free(struct snd_pcm_substream *substream)
struct snd_dice *dice = substream->private_data; struct snd_dice *dice = substream->private_data;
mutex_lock(&dice->mutex); mutex_lock(&dice->mutex);
snd_dice_stream_stop(dice); snd_dice_stream_stop_duplex(dice);
mutex_unlock(&dice->mutex); mutex_unlock(&dice->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream); return snd_pcm_lib_free_vmalloc_buffer(substream);
...@@ -193,7 +193,7 @@ static int playback_prepare(struct snd_pcm_substream *substream) ...@@ -193,7 +193,7 @@ static int playback_prepare(struct snd_pcm_substream *substream)
int err; int err;
mutex_lock(&dice->mutex); mutex_lock(&dice->mutex);
err = snd_dice_stream_start(dice, substream->runtime->rate); err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
mutex_unlock(&dice->mutex); mutex_unlock(&dice->mutex);
if (err >= 0) if (err >= 0)
amdtp_stream_pcm_prepare(&dice->rx_stream); amdtp_stream_pcm_prepare(&dice->rx_stream);
......
This diff is collapsed.
...@@ -30,7 +30,6 @@ static int dice_interface_check(struct fw_unit *unit) ...@@ -30,7 +30,6 @@ static int dice_interface_check(struct fw_unit *unit)
int key, val, vendor = -1, model = -1, err; int key, val, vendor = -1, model = -1, err;
unsigned int category, i; unsigned int category, i;
__be32 *pointers, value; __be32 *pointers, value;
__be32 tx_data[4];
__be32 version; __be32 version;
pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32), pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
...@@ -85,16 +84,6 @@ static int dice_interface_check(struct fw_unit *unit) ...@@ -85,16 +84,6 @@ static int dice_interface_check(struct fw_unit *unit)
} }
} }
/* We support playback only. Let capture devices be handled by FFADO. */
err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
DICE_PRIVATE_SPACE +
be32_to_cpu(pointers[2]) * 4,
tx_data, sizeof(tx_data), 0);
if (err < 0 || (tx_data[0] && tx_data[3])) {
err = -ENODEV;
goto end;
}
/* /*
* Check that the implemented DICE driver specification major version * Check that the implemented DICE driver specification major version
* number matches. * number matches.
...@@ -142,6 +131,8 @@ static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode) ...@@ -142,6 +131,8 @@ static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode)
int err; int err;
if (highest_supported_mode_rate(dice, mode, &rate) < 0) { if (highest_supported_mode_rate(dice, mode, &rate) < 0) {
dice->tx_channels[mode] = 0;
dice->tx_midi_ports[mode] = 0;
dice->rx_channels[mode] = 0; dice->rx_channels[mode] = 0;
dice->rx_midi_ports[mode] = 0; dice->rx_midi_ports[mode] = 0;
return 0; return 0;
...@@ -151,6 +142,14 @@ static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode) ...@@ -151,6 +142,14 @@ static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode)
if (err < 0) if (err < 0)
return err; return err;
err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
values, sizeof(values));
if (err < 0)
return err;
dice->tx_channels[mode] = be32_to_cpu(values[0]);
dice->tx_midi_ports[mode] = be32_to_cpu(values[1]);
err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO, err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
values, sizeof(values)); values, sizeof(values));
if (err < 0) if (err < 0)
...@@ -280,13 +279,13 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) ...@@ -280,13 +279,13 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
snd_dice_create_proc(dice); snd_dice_create_proc(dice);
err = snd_dice_stream_init(dice); err = snd_dice_stream_init_duplex(dice);
if (err < 0) if (err < 0)
goto error; goto error;
err = snd_card_register(card); err = snd_card_register(card);
if (err < 0) { if (err < 0) {
snd_dice_stream_destroy(dice); snd_dice_stream_destroy_duplex(dice);
goto error; goto error;
} }
...@@ -304,7 +303,7 @@ static void dice_remove(struct fw_unit *unit) ...@@ -304,7 +303,7 @@ static void dice_remove(struct fw_unit *unit)
snd_card_disconnect(dice->card); snd_card_disconnect(dice->card);
snd_dice_stream_destroy(dice); snd_dice_stream_destroy_duplex(dice);
snd_card_free_when_closed(dice->card); snd_card_free_when_closed(dice->card);
} }
...@@ -317,7 +316,7 @@ static void dice_bus_reset(struct fw_unit *unit) ...@@ -317,7 +316,7 @@ static void dice_bus_reset(struct fw_unit *unit)
snd_dice_transaction_reinit(dice); snd_dice_transaction_reinit(dice);
mutex_lock(&dice->mutex); mutex_lock(&dice->mutex);
snd_dice_stream_update(dice); snd_dice_stream_update_duplex(dice);
mutex_unlock(&dice->mutex); mutex_unlock(&dice->mutex);
} }
......
...@@ -52,18 +52,28 @@ struct snd_dice { ...@@ -52,18 +52,28 @@ struct snd_dice {
unsigned int rsrv_offset; unsigned int rsrv_offset;
unsigned int clock_caps; unsigned int clock_caps;
unsigned int tx_channels[3];
unsigned int rx_channels[3]; unsigned int rx_channels[3];
unsigned int tx_midi_ports[3];
unsigned int rx_midi_ports[3]; unsigned int rx_midi_ports[3];
struct fw_address_handler notification_handler; struct fw_address_handler notification_handler;
int owner_generation; int owner_generation;
u32 notification_bits;
/* For uapi */
int dev_lock_count; /* > 0 driver, < 0 userspace */ int dev_lock_count; /* > 0 driver, < 0 userspace */
bool dev_lock_changed; bool dev_lock_changed;
bool global_enabled;
struct completion clock_accepted;
wait_queue_head_t hwdep_wait; wait_queue_head_t hwdep_wait;
u32 notification_bits;
/* For streaming */
struct fw_iso_resources tx_resources;
struct fw_iso_resources rx_resources; struct fw_iso_resources rx_resources;
struct amdtp_stream tx_stream;
struct amdtp_stream rx_stream; struct amdtp_stream rx_stream;
bool global_enabled;
struct completion clock_accepted;
unsigned int substreams_counter;
}; };
enum snd_dice_addr_type { enum snd_dice_addr_type {
...@@ -160,11 +170,11 @@ extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT]; ...@@ -160,11 +170,11 @@ extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT];
int snd_dice_stream_get_rate_mode(struct snd_dice *dice, int snd_dice_stream_get_rate_mode(struct snd_dice *dice,
unsigned int rate, unsigned int *mode); unsigned int rate, unsigned int *mode);
int snd_dice_stream_start(struct snd_dice *dice, unsigned int rate); int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate);
void snd_dice_stream_stop(struct snd_dice *dice); void snd_dice_stream_stop_duplex(struct snd_dice *dice);
int snd_dice_stream_init(struct snd_dice *dice); int snd_dice_stream_init_duplex(struct snd_dice *dice);
void snd_dice_stream_destroy(struct snd_dice *dice); void snd_dice_stream_destroy_duplex(struct snd_dice *dice);
void snd_dice_stream_update(struct snd_dice *dice); void snd_dice_stream_update_duplex(struct snd_dice *dice);
int snd_dice_stream_lock_try(struct snd_dice *dice); int snd_dice_stream_lock_try(struct snd_dice *dice);
void snd_dice_stream_lock_release(struct snd_dice *dice); void snd_dice_stream_lock_release(struct snd_dice *dice);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment