spin_lock_irqsave(&dice->lock, flags);
if (up)
- amdtp_am824_midi_trigger(&dice->tx_stream,
+ amdtp_am824_midi_trigger(&dice->tx_stream[0],
substrm->number, substrm);
else
- amdtp_am824_midi_trigger(&dice->tx_stream,
+ amdtp_am824_midi_trigger(&dice->tx_stream[0],
substrm->number, NULL);
spin_unlock_irqrestore(&dice->lock, flags);
spin_lock_irqsave(&dice->lock, flags);
if (up)
- amdtp_am824_midi_trigger(&dice->rx_stream,
+ amdtp_am824_midi_trigger(&dice->rx_stream[0],
substrm->number, substrm);
else
- amdtp_am824_midi_trigger(&dice->rx_stream,
+ amdtp_am824_midi_trigger(&dice->rx_stream[0],
substrm->number, NULL);
spin_unlock_irqrestore(&dice->lock, flags);
* Retrieve current Multi Bit Linear Audio data channel and limit to
* it.
*/
- if (stream == &dice->tx_stream) {
+ if (stream == &dice->tx_stream[0]) {
err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
reg, sizeof(reg));
} else {
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
hw->formats = AM824_IN_PCM_FORMAT_BITS;
- stream = &dice->tx_stream;
+ stream = &dice->tx_stream[0];
} else {
hw->formats = AM824_OUT_PCM_FORMAT_BITS;
- stream = &dice->rx_stream;
+ stream = &dice->rx_stream[0];
}
err = limit_channels_and_rates(dice, runtime, stream);
struct snd_pcm_hw_params *hw_params)
{
struct snd_dice *dice = substream->private_data;
+ struct amdtp_stream *stream = &dice->tx_stream[0];
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
mutex_unlock(&dice->mutex);
}
- amdtp_am824_set_pcm_format(&dice->tx_stream, params_format(hw_params));
+ amdtp_am824_set_pcm_format(stream, params_format(hw_params));
return 0;
}
struct snd_pcm_hw_params *hw_params)
{
struct snd_dice *dice = substream->private_data;
+ struct amdtp_stream *stream = &dice->rx_stream[0];
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
mutex_unlock(&dice->mutex);
}
- amdtp_am824_set_pcm_format(&dice->rx_stream, params_format(hw_params));
+ amdtp_am824_set_pcm_format(stream, params_format(hw_params));
return 0;
}
static int capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_dice *dice = substream->private_data;
+ struct amdtp_stream *stream = &dice->tx_stream[0];
int err;
mutex_lock(&dice->mutex);
err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
mutex_unlock(&dice->mutex);
if (err >= 0)
- amdtp_stream_pcm_prepare(&dice->tx_stream);
+ amdtp_stream_pcm_prepare(stream);
return 0;
}
static int playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_dice *dice = substream->private_data;
+ struct amdtp_stream *stream = &dice->rx_stream[0];
int err;
mutex_lock(&dice->mutex);
err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
mutex_unlock(&dice->mutex);
if (err >= 0)
- amdtp_stream_pcm_prepare(&dice->rx_stream);
+ amdtp_stream_pcm_prepare(stream);
return err;
}
static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_dice *dice = substream->private_data;
+ struct amdtp_stream *stream = &dice->tx_stream[0];
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- amdtp_stream_pcm_trigger(&dice->tx_stream, substream);
+ amdtp_stream_pcm_trigger(stream, substream);
break;
case SNDRV_PCM_TRIGGER_STOP:
- amdtp_stream_pcm_trigger(&dice->tx_stream, NULL);
+ amdtp_stream_pcm_trigger(stream, NULL);
break;
default:
return -EINVAL;
static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_dice *dice = substream->private_data;
+ struct amdtp_stream *stream = &dice->rx_stream[0];
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- amdtp_stream_pcm_trigger(&dice->rx_stream, substream);
+ amdtp_stream_pcm_trigger(stream, substream);
break;
case SNDRV_PCM_TRIGGER_STOP:
- amdtp_stream_pcm_trigger(&dice->rx_stream, NULL);
+ amdtp_stream_pcm_trigger(stream, NULL);
break;
default:
return -EINVAL;
static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
{
struct snd_dice *dice = substream->private_data;
+ struct amdtp_stream *stream = &dice->tx_stream[0];
- return amdtp_stream_pcm_pointer(&dice->tx_stream);
+ return amdtp_stream_pcm_pointer(stream);
}
static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
{
struct snd_dice *dice = substream->private_data;
+ struct amdtp_stream *stream = &dice->rx_stream[0];
- return amdtp_stream_pcm_pointer(&dice->rx_stream);
+ return amdtp_stream_pcm_pointer(stream);
}
int snd_dice_create_pcm(struct snd_dice *dice)
/* Reset channel number */
channel = cpu_to_be32((u32)-1);
- if (resources == &dice->tx_resources)
+ if (resources == &dice->tx_resources[0])
snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
&channel, sizeof(channel));
else
/* Set channel number */
channel = cpu_to_be32(resources->channel);
- if (resources == &dice->tx_resources)
+ if (resources == &dice->tx_resources[0])
err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
&channel, sizeof(channel));
else
amdtp_stream_pcm_abort(stream);
amdtp_stream_stop(stream);
- if (stream == &dice->tx_stream)
- release_resources(dice, &dice->tx_resources);
+ if (stream == &dice->tx_stream[0])
+ release_resources(dice, &dice->tx_resources[0]);
else
- release_resources(dice, &dice->rx_resources);
+ release_resources(dice, &dice->rx_resources[0]);
}
static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
bool double_pcm_frames;
int err;
- if (stream == &dice->tx_stream) {
- resources = &dice->tx_resources;
+ if (stream == &dice->tx_stream[0]) {
+ resources = &dice->tx_resources[0];
err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
reg, sizeof(reg));
} else {
- resources = &dice->rx_resources;
+ resources = &dice->rx_resources[0];
err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
reg, sizeof(reg));
}
if (dice->substreams_counter == 0)
goto end;
- master = &dice->rx_stream;
- slave = &dice->tx_stream;
+ master = &dice->rx_stream[0];
+ slave = &dice->tx_stream[0];
/* Some packet queueing errors. */
if (amdtp_streaming_error(master) || amdtp_streaming_error(slave))
snd_dice_transaction_clear_enable(dice);
- stop_stream(dice, &dice->tx_stream);
- stop_stream(dice, &dice->rx_stream);
+ stop_stream(dice, &dice->tx_stream[0]);
+ stop_stream(dice, &dice->rx_stream[0]);
}
static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream)
struct fw_iso_resources *resources;
enum amdtp_stream_direction dir;
- if (stream == &dice->tx_stream) {
- resources = &dice->tx_resources;
+ if (stream == &dice->tx_stream[0]) {
+ resources = &dice->tx_resources[0];
dir = AMDTP_IN_STREAM;
} else {
- resources = &dice->rx_resources;
+ resources = &dice->rx_resources[0];
dir = AMDTP_OUT_STREAM;
}
{
struct fw_iso_resources *resources;
- if (stream == &dice->tx_stream)
- resources = &dice->tx_resources;
+ if (stream == &dice->tx_stream[0])
+ resources = &dice->tx_resources[0];
else
- resources = &dice->rx_resources;
+ resources = &dice->rx_resources[0];
amdtp_stream_destroy(stream);
fw_iso_resources_destroy(resources);
dice->substreams_counter = 0;
- err = init_stream(dice, &dice->tx_stream);
+ err = init_stream(dice, &dice->tx_stream[0]);
if (err < 0)
goto end;
- err = init_stream(dice, &dice->rx_stream);
+ err = init_stream(dice, &dice->rx_stream[0]);
if (err < 0)
- destroy_stream(dice, &dice->tx_stream);
+ destroy_stream(dice, &dice->tx_stream[0]);
end:
return err;
}
{
snd_dice_transaction_clear_enable(dice);
- destroy_stream(dice, &dice->tx_stream);
- destroy_stream(dice, &dice->rx_stream);
+ destroy_stream(dice, &dice->tx_stream[0]);
+ destroy_stream(dice, &dice->rx_stream[0]);
dice->substreams_counter = 0;
}
*/
dice->global_enabled = false;
- stop_stream(dice, &dice->rx_stream);
- stop_stream(dice, &dice->tx_stream);
+ stop_stream(dice, &dice->rx_stream[0]);
+ stop_stream(dice, &dice->tx_stream[0]);
- fw_iso_resources_update(&dice->rx_resources);
- fw_iso_resources_update(&dice->tx_resources);
+ fw_iso_resources_update(&dice->rx_resources[0]);
+ fw_iso_resources_update(&dice->tx_resources[0]);
}
static void dice_lock_changed(struct snd_dice *dice)
#include "../lib.h"
#include "dice-interface.h"
+/*
+ * This module support maximum 2 pairs of tx/rx isochronous streams for
+ * our convinience.
+ *
+ * In documents for ASICs called with a name of 'DICE':
+ * - ASIC for DICE II:
+ * - Maximum 2 tx and 4 rx are supported.
+ * - A packet supports maximum 16 data channels.
+ * - TCD2210/2210-E (so-called 'Dice Mini'):
+ * - Maximum 2 tx and 2 rx are supported.
+ * - A packet supports maximum 16 data channels.
+ * - TCD2220/2220-E (so-called 'Dice Jr.')
+ * - 2 tx and 2 rx are supported.
+ * - A packet supports maximum 16 data channels.
+ * - TCD3070-CH (so-called 'Dice III')
+ * - Maximum 2 tx and 2 rx are supported.
+ * - A packet supports maximum 32 data channels.
+ *
+ * For the above, MIDI conformant data channel is just on the first isochronous
+ * stream.
+ */
+#define MAX_STREAMS 2
+
struct snd_dice {
struct snd_card *card;
struct fw_unit *unit;
wait_queue_head_t hwdep_wait;
/* For streaming */
- struct fw_iso_resources tx_resources;
- struct fw_iso_resources rx_resources;
- struct amdtp_stream tx_stream;
- struct amdtp_stream rx_stream;
+ struct fw_iso_resources tx_resources[MAX_STREAMS];
+ struct fw_iso_resources rx_resources[MAX_STREAMS];
+ struct amdtp_stream tx_stream[MAX_STREAMS];
+ struct amdtp_stream rx_stream[MAX_STREAMS];
bool global_enabled;
struct completion clock_accepted;
unsigned int substreams_counter;