2011-09-05 04:04:49 +08:00
|
|
|
/*
|
|
|
|
* TC Applied Technologies Digital Interface Communications Engine driver
|
|
|
|
*
|
|
|
|
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
|
|
|
|
* Licensed under the terms of the GNU General Public License, version 2.
|
|
|
|
*/
|
|
|
|
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
#include "dice.h"
|
2011-09-05 04:04:49 +08:00
|
|
|
|
|
|
|
MODULE_DESCRIPTION("DICE driver");
|
|
|
|
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
|
|
|
2011-12-05 05:07:01 +08:00
|
|
|
static int dice_rate_constraint(struct snd_pcm_hw_params *params,
|
|
|
|
struct snd_pcm_hw_rule *rule)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = rule->private;
|
2014-11-28 23:59:14 +08:00
|
|
|
|
|
|
|
const struct snd_interval *c =
|
2011-12-05 05:07:01 +08:00
|
|
|
hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
|
2014-11-28 23:59:14 +08:00
|
|
|
struct snd_interval *r =
|
2011-12-05 05:07:01 +08:00
|
|
|
hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
2014-11-28 23:59:14 +08:00
|
|
|
struct snd_interval rates = {
|
2011-12-05 05:07:01 +08:00
|
|
|
.min = UINT_MAX, .max = 0, .integer = 1
|
|
|
|
};
|
2014-11-28 23:59:14 +08:00
|
|
|
unsigned int i, rate, mode, *pcm_channels = dice->rx_channels;
|
2011-12-05 05:07:01 +08:00
|
|
|
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
|
2014-11-28 23:59:14 +08:00
|
|
|
rate = snd_dice_rates[i];
|
|
|
|
if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!snd_interval_test(c, pcm_channels[mode]))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
rates.min = min(rates.min, rate);
|
|
|
|
rates.max = max(rates.max, rate);
|
2011-12-05 05:07:01 +08:00
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
return snd_interval_refine(r, &rates);
|
2011-12-05 05:07:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int dice_channels_constraint(struct snd_pcm_hw_params *params,
|
|
|
|
struct snd_pcm_hw_rule *rule)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = rule->private;
|
2014-11-28 23:59:14 +08:00
|
|
|
|
|
|
|
const struct snd_interval *r =
|
2011-12-05 05:07:01 +08:00
|
|
|
hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
|
2014-11-28 23:59:14 +08:00
|
|
|
struct snd_interval *c =
|
2011-12-05 05:07:01 +08:00
|
|
|
hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
|
2014-11-28 23:59:14 +08:00
|
|
|
struct snd_interval channels = {
|
2011-12-05 05:07:01 +08:00
|
|
|
.min = UINT_MAX, .max = 0, .integer = 1
|
|
|
|
};
|
2014-11-28 23:59:14 +08:00
|
|
|
unsigned int i, rate, mode, *pcm_channels = dice->rx_channels;
|
2011-12-05 05:07:01 +08:00
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
|
|
|
|
rate = snd_dice_rates[i];
|
|
|
|
if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
|
|
|
|
continue;
|
2011-12-05 05:07:01 +08:00
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
if (!snd_interval_test(r, rate))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
channels.min = min(channels.min, pcm_channels[mode]);
|
|
|
|
channels.max = max(channels.max, pcm_channels[mode]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return snd_interval_refine(c, &channels);
|
2011-12-05 05:07:01 +08:00
|
|
|
}
|
|
|
|
|
2011-09-05 04:04:49 +08:00
|
|
|
static int dice_open(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
static const struct snd_pcm_hardware hardware = {
|
|
|
|
.info = SNDRV_PCM_INFO_MMAP |
|
|
|
|
SNDRV_PCM_INFO_MMAP_VALID |
|
|
|
|
SNDRV_PCM_INFO_BATCH |
|
|
|
|
SNDRV_PCM_INFO_INTERLEAVED |
|
|
|
|
SNDRV_PCM_INFO_BLOCK_TRANSFER,
|
|
|
|
.formats = AMDTP_OUT_PCM_FORMAT_BITS,
|
2011-12-05 05:07:01 +08:00
|
|
|
.channels_min = UINT_MAX,
|
|
|
|
.channels_max = 0,
|
2011-09-05 04:04:49 +08:00
|
|
|
.buffer_bytes_max = 16 * 1024 * 1024,
|
|
|
|
.period_bytes_min = 1,
|
|
|
|
.period_bytes_max = UINT_MAX,
|
|
|
|
.periods_min = 1,
|
|
|
|
.periods_max = UINT_MAX,
|
|
|
|
};
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = substream->private_data;
|
2011-09-05 04:04:49 +08:00
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
2011-12-05 05:07:01 +08:00
|
|
|
unsigned int i;
|
2011-09-05 04:04:49 +08:00
|
|
|
int err;
|
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
err = snd_dice_stream_lock_try(dice);
|
2011-09-05 04:14:15 +08:00
|
|
|
if (err < 0)
|
|
|
|
goto error;
|
|
|
|
|
2011-09-05 04:04:49 +08:00
|
|
|
runtime->hw = hardware;
|
2011-09-05 04:12:06 +08:00
|
|
|
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i)
|
2011-12-05 05:07:01 +08:00
|
|
|
if (dice->clock_caps & (1 << i))
|
|
|
|
runtime->hw.rates |=
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
snd_pcm_rate_to_rate_bit(snd_dice_rates[i]);
|
2011-09-05 04:12:06 +08:00
|
|
|
snd_pcm_limit_hw_rates(runtime);
|
|
|
|
|
2011-12-05 05:07:01 +08:00
|
|
|
for (i = 0; i < 3; ++i)
|
|
|
|
if (dice->rx_channels[i]) {
|
|
|
|
runtime->hw.channels_min = min(runtime->hw.channels_min,
|
|
|
|
dice->rx_channels[i]);
|
|
|
|
runtime->hw.channels_max = max(runtime->hw.channels_max,
|
|
|
|
dice->rx_channels[i]);
|
|
|
|
}
|
2011-09-05 04:04:49 +08:00
|
|
|
|
2011-12-05 05:07:01 +08:00
|
|
|
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
|
|
|
dice_rate_constraint, dice,
|
|
|
|
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
|
|
|
|
if (err < 0)
|
|
|
|
goto err_lock;
|
|
|
|
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
|
|
|
dice_channels_constraint, dice,
|
|
|
|
SNDRV_PCM_HW_PARAM_RATE, -1);
|
|
|
|
if (err < 0)
|
|
|
|
goto err_lock;
|
2011-09-05 04:16:10 +08:00
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
err = amdtp_stream_add_pcm_hw_constraints(&dice->rx_stream, runtime);
|
2011-09-05 04:04:49 +08:00
|
|
|
if (err < 0)
|
2011-09-05 04:14:15 +08:00
|
|
|
goto err_lock;
|
2011-09-05 04:04:49 +08:00
|
|
|
|
|
|
|
return 0;
|
2011-09-05 04:14:15 +08:00
|
|
|
|
|
|
|
err_lock:
|
2014-11-28 23:59:14 +08:00
|
|
|
snd_dice_stream_lock_release(dice);
|
2011-09-05 04:14:15 +08:00
|
|
|
error:
|
|
|
|
return err;
|
2011-09-05 04:04:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int dice_close(struct snd_pcm_substream *substream)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = substream->private_data;
|
2011-09-05 04:14:15 +08:00
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
snd_dice_stream_lock_release(dice);
|
2011-09-05 04:14:15 +08:00
|
|
|
|
2011-09-05 04:04:49 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dice_hw_params(struct snd_pcm_substream *substream,
|
|
|
|
struct snd_pcm_hw_params *hw_params)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = substream->private_data;
|
2014-11-28 23:59:14 +08:00
|
|
|
unsigned int mode, rate, channels, i;
|
2011-09-05 04:04:49 +08:00
|
|
|
int err;
|
|
|
|
|
|
|
|
mutex_lock(&dice->mutex);
|
2014-11-28 23:59:14 +08:00
|
|
|
snd_dice_stream_stop(dice);
|
2011-09-05 04:04:49 +08:00
|
|
|
mutex_unlock(&dice->mutex);
|
|
|
|
|
|
|
|
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
|
|
|
|
params_buffer_bytes(hw_params));
|
|
|
|
if (err < 0)
|
2011-12-05 05:07:01 +08:00
|
|
|
return err;
|
|
|
|
|
2014-04-25 21:44:51 +08:00
|
|
|
rate = params_rate(hw_params);
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
err = snd_dice_transaction_set_rate(dice, rate);
|
2011-12-05 05:07:01 +08:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2011-09-05 04:04:49 +08:00
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2014-04-25 21:44:51 +08:00
|
|
|
/*
|
2014-08-29 12:40:45 +08:00
|
|
|
* 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.
|
2014-04-25 21:44:51 +08:00
|
|
|
*/
|
|
|
|
channels = params_channels(hw_params);
|
2014-11-28 23:59:14 +08:00
|
|
|
if (mode > 1) {
|
2014-04-25 21:44:51 +08:00
|
|
|
if (channels > AMDTP_MAX_CHANNELS_FOR_PCM / 2) {
|
|
|
|
err = -ENOSYS;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
rate /= 2;
|
|
|
|
channels *= 2;
|
2014-11-28 23:59:11 +08:00
|
|
|
dice->rx_stream.double_pcm_frames = true;
|
2014-08-29 12:40:45 +08:00
|
|
|
} else {
|
2014-11-28 23:59:11 +08:00
|
|
|
dice->rx_stream.double_pcm_frames = false;
|
2014-04-25 21:44:51 +08:00
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
amdtp_stream_set_parameters(&dice->rx_stream, rate, channels,
|
2014-04-25 21:44:42 +08:00
|
|
|
dice->rx_midi_ports[mode]);
|
2014-11-28 23:59:14 +08:00
|
|
|
if (mode > 4) {
|
2014-08-29 12:40:44 +08:00
|
|
|
channels /= 2;
|
|
|
|
|
|
|
|
for (i = 0; i < channels; i++) {
|
2014-11-28 23:59:11 +08:00
|
|
|
dice->rx_stream.pcm_positions[i] = i * 2;
|
|
|
|
dice->rx_stream.pcm_positions[i + channels] = i * 2 + 1;
|
2014-08-29 12:40:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
amdtp_stream_set_pcm_format(&dice->rx_stream,
|
2014-04-25 21:44:42 +08:00
|
|
|
params_format(hw_params));
|
2011-09-05 04:04:49 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dice_hw_free(struct snd_pcm_substream *substream)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = substream->private_data;
|
2011-09-05 04:04:49 +08:00
|
|
|
|
|
|
|
mutex_lock(&dice->mutex);
|
2014-11-28 23:59:14 +08:00
|
|
|
snd_dice_stream_stop(dice);
|
2011-09-05 04:04:49 +08:00
|
|
|
mutex_unlock(&dice->mutex);
|
|
|
|
|
|
|
|
return snd_pcm_lib_free_vmalloc_buffer(substream);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dice_prepare(struct snd_pcm_substream *substream)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = substream->private_data;
|
2011-09-05 04:04:49 +08:00
|
|
|
int err;
|
|
|
|
|
|
|
|
mutex_lock(&dice->mutex);
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
if (amdtp_streaming_error(&dice->rx_stream))
|
2014-11-28 23:59:14 +08:00
|
|
|
snd_dice_stream_stop_packets(dice);
|
2011-09-05 04:04:49 +08:00
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
err = snd_dice_stream_start(dice);
|
2011-09-05 04:11:14 +08:00
|
|
|
if (err < 0) {
|
|
|
|
mutex_unlock(&dice->mutex);
|
|
|
|
return err;
|
2011-09-05 04:04:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&dice->mutex);
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
amdtp_stream_pcm_prepare(&dice->rx_stream);
|
2011-09-05 04:04:49 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dice_trigger(struct snd_pcm_substream *substream, int cmd)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = substream->private_data;
|
2011-09-05 04:04:49 +08:00
|
|
|
struct snd_pcm_substream *pcm;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SNDRV_PCM_TRIGGER_START:
|
|
|
|
pcm = substream;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_TRIGGER_STOP:
|
|
|
|
pcm = NULL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2014-11-28 23:59:11 +08:00
|
|
|
amdtp_stream_pcm_trigger(&dice->rx_stream, pcm);
|
2011-09-05 04:04:49 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = substream->private_data;
|
2011-09-05 04:04:49 +08:00
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
return amdtp_stream_pcm_pointer(&dice->rx_stream);
|
2011-09-05 04:04:49 +08:00
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
static int dice_create_pcm(struct snd_dice *dice)
|
2011-09-05 04:04:49 +08:00
|
|
|
{
|
|
|
|
static struct snd_pcm_ops ops = {
|
|
|
|
.open = dice_open,
|
|
|
|
.close = dice_close,
|
|
|
|
.ioctl = snd_pcm_lib_ioctl,
|
|
|
|
.hw_params = dice_hw_params,
|
|
|
|
.hw_free = dice_hw_free,
|
|
|
|
.prepare = dice_prepare,
|
|
|
|
.trigger = dice_trigger,
|
|
|
|
.pointer = dice_pointer,
|
|
|
|
.page = snd_pcm_lib_get_vmalloc_page,
|
|
|
|
.mmap = snd_pcm_lib_mmap_vmalloc,
|
|
|
|
};
|
|
|
|
struct snd_pcm *pcm;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
pcm->private_data = dice;
|
|
|
|
strcpy(pcm->name, dice->card->shortname);
|
2011-10-11 23:51:16 +08:00
|
|
|
pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->ops = &ops;
|
2011-09-05 04:04:49 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf,
|
|
|
|
long count, loff_t *offset)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = hwdep->private_data;
|
2011-09-05 04:14:15 +08:00
|
|
|
DEFINE_WAIT(wait);
|
|
|
|
union snd_firewire_event event;
|
|
|
|
|
|
|
|
spin_lock_irq(&dice->lock);
|
|
|
|
|
|
|
|
while (!dice->dev_lock_changed && dice->notification_bits == 0) {
|
|
|
|
prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
|
|
|
|
spin_unlock_irq(&dice->lock);
|
|
|
|
schedule();
|
|
|
|
finish_wait(&dice->hwdep_wait, &wait);
|
|
|
|
if (signal_pending(current))
|
|
|
|
return -ERESTARTSYS;
|
|
|
|
spin_lock_irq(&dice->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&event, 0, sizeof(event));
|
|
|
|
if (dice->dev_lock_changed) {
|
|
|
|
event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
|
|
|
|
event.lock_status.status = dice->dev_lock_count > 0;
|
|
|
|
dice->dev_lock_changed = false;
|
|
|
|
|
2014-11-28 23:59:10 +08:00
|
|
|
count = min_t(long, count, sizeof(event.lock_status));
|
2011-09-05 04:14:15 +08:00
|
|
|
} else {
|
2014-11-28 23:59:10 +08:00
|
|
|
event.dice_notification.type =
|
|
|
|
SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION;
|
2011-09-05 04:14:15 +08:00
|
|
|
event.dice_notification.notification = dice->notification_bits;
|
|
|
|
dice->notification_bits = 0;
|
|
|
|
|
2014-11-28 23:59:10 +08:00
|
|
|
count = min_t(long, count, sizeof(event.dice_notification));
|
2011-09-05 04:14:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock_irq(&dice->lock);
|
|
|
|
|
|
|
|
if (copy_to_user(buf, &event, count))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return count;
|
2011-09-05 04:04:49 +08:00
|
|
|
}
|
|
|
|
|
2011-09-05 04:14:15 +08:00
|
|
|
static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
|
|
|
|
poll_table *wait)
|
2011-09-05 04:04:49 +08:00
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = hwdep->private_data;
|
2011-09-05 04:14:15 +08:00
|
|
|
unsigned int events;
|
|
|
|
|
|
|
|
poll_wait(file, &dice->hwdep_wait, wait);
|
|
|
|
|
|
|
|
spin_lock_irq(&dice->lock);
|
|
|
|
if (dice->dev_lock_changed || dice->notification_bits != 0)
|
|
|
|
events = POLLIN | POLLRDNORM;
|
|
|
|
else
|
|
|
|
events = 0;
|
|
|
|
spin_unlock_irq(&dice->lock);
|
|
|
|
|
|
|
|
return events;
|
2011-09-05 04:04:49 +08:00
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
static int dice_hwdep_get_info(struct snd_dice *dice, void __user *arg)
|
2011-09-05 04:04:49 +08:00
|
|
|
{
|
2011-09-05 04:14:15 +08:00
|
|
|
struct fw_device *dev = fw_parent_device(dice->unit);
|
|
|
|
struct snd_firewire_get_info info;
|
|
|
|
|
|
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
info.type = SNDRV_FIREWIRE_TYPE_DICE;
|
|
|
|
info.card = dev->card->index;
|
|
|
|
*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
|
|
|
|
*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
|
|
|
|
strlcpy(info.device_name, dev_name(&dev->device),
|
|
|
|
sizeof(info.device_name));
|
|
|
|
|
|
|
|
if (copy_to_user(arg, &info, sizeof(info)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
2011-09-05 04:04:49 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
static int dice_hwdep_lock(struct snd_dice *dice)
|
2011-09-05 04:14:15 +08:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
spin_lock_irq(&dice->lock);
|
|
|
|
|
|
|
|
if (dice->dev_lock_count == 0) {
|
|
|
|
dice->dev_lock_count = -1;
|
|
|
|
err = 0;
|
|
|
|
} else {
|
|
|
|
err = -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock_irq(&dice->lock);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
static int dice_hwdep_unlock(struct snd_dice *dice)
|
2011-09-05 04:04:49 +08:00
|
|
|
{
|
2011-09-05 04:14:15 +08:00
|
|
|
int err;
|
|
|
|
|
|
|
|
spin_lock_irq(&dice->lock);
|
|
|
|
|
|
|
|
if (dice->dev_lock_count == -1) {
|
|
|
|
dice->dev_lock_count = 0;
|
|
|
|
err = 0;
|
|
|
|
} else {
|
|
|
|
err = -EBADFD;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock_irq(&dice->lock);
|
|
|
|
|
|
|
|
return err;
|
2011-09-05 04:04:49 +08:00
|
|
|
}
|
|
|
|
|
2011-09-05 04:14:54 +08:00
|
|
|
static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = hwdep->private_data;
|
2011-09-05 04:14:54 +08:00
|
|
|
|
|
|
|
spin_lock_irq(&dice->lock);
|
|
|
|
if (dice->dev_lock_count == -1)
|
|
|
|
dice->dev_lock_count = 0;
|
|
|
|
spin_unlock_irq(&dice->lock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-05 04:04:49 +08:00
|
|
|
static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
|
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = hwdep->private_data;
|
2011-09-05 04:14:15 +08:00
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SNDRV_FIREWIRE_IOCTL_GET_INFO:
|
|
|
|
return dice_hwdep_get_info(dice, (void __user *)arg);
|
|
|
|
case SNDRV_FIREWIRE_IOCTL_LOCK:
|
|
|
|
return dice_hwdep_lock(dice);
|
|
|
|
case SNDRV_FIREWIRE_IOCTL_UNLOCK:
|
|
|
|
return dice_hwdep_unlock(dice);
|
|
|
|
default:
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
static int dice_hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
|
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
return dice_hwdep_ioctl(hwdep, file, cmd,
|
|
|
|
(unsigned long)compat_ptr(arg));
|
2011-09-05 04:04:49 +08:00
|
|
|
}
|
2011-09-05 04:14:15 +08:00
|
|
|
#else
|
|
|
|
#define dice_hwdep_compat_ioctl NULL
|
|
|
|
#endif
|
2011-09-05 04:04:49 +08:00
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
static int dice_create_hwdep(struct snd_dice *dice)
|
2011-09-05 04:04:49 +08:00
|
|
|
{
|
|
|
|
static const struct snd_hwdep_ops ops = {
|
|
|
|
.read = dice_hwdep_read,
|
2011-09-05 04:14:54 +08:00
|
|
|
.release = dice_hwdep_release,
|
2011-09-05 04:04:49 +08:00
|
|
|
.poll = dice_hwdep_poll,
|
|
|
|
.ioctl = dice_hwdep_ioctl,
|
2011-09-05 04:14:15 +08:00
|
|
|
.ioctl_compat = dice_hwdep_compat_ioctl,
|
2011-09-05 04:04:49 +08:00
|
|
|
};
|
|
|
|
struct snd_hwdep *hwdep;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
strcpy(hwdep->name, "DICE");
|
|
|
|
hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;
|
|
|
|
hwdep->ops = ops;
|
|
|
|
hwdep->private_data = dice;
|
|
|
|
hwdep->exclusive = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
static int dice_proc_read_mem(struct snd_dice *dice, void *buffer,
|
2012-01-06 05:36:08 +08:00
|
|
|
unsigned int offset_q, unsigned int quadlets)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
|
|
|
|
DICE_PRIVATE_SPACE + 4 * offset_q,
|
|
|
|
buffer, 4 * quadlets, 0);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
for (i = 0; i < quadlets; ++i)
|
|
|
|
be32_to_cpus(&((u32 *)buffer)[i]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *str_from_array(const char *const strs[], unsigned int count,
|
|
|
|
unsigned int i)
|
|
|
|
{
|
|
|
|
if (i < count)
|
|
|
|
return strs[i];
|
2014-11-28 23:59:11 +08:00
|
|
|
|
|
|
|
return "(unknown)";
|
2012-01-06 05:36:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void dice_proc_fixup_string(char *s, unsigned int size)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < size; i += 4)
|
|
|
|
cpu_to_le32s((u32 *)(s + i));
|
|
|
|
|
|
|
|
for (i = 0; i < size - 2; ++i) {
|
|
|
|
if (s[i] == '\0')
|
|
|
|
return;
|
|
|
|
if (s[i] == '\\' && s[i + 1] == '\\') {
|
|
|
|
s[i + 2] = '\0';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s[size - 1] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dice_proc_read(struct snd_info_entry *entry,
|
|
|
|
struct snd_info_buffer *buffer)
|
|
|
|
{
|
|
|
|
static const char *const section_names[5] = {
|
|
|
|
"global", "tx", "rx", "ext_sync", "unused2"
|
|
|
|
};
|
|
|
|
static const char *const clock_sources[] = {
|
|
|
|
"aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif",
|
|
|
|
"wc", "arx1", "arx2", "arx3", "arx4", "internal"
|
|
|
|
};
|
|
|
|
static const char *const rates[] = {
|
|
|
|
"32000", "44100", "48000", "88200", "96000", "176400", "192000",
|
|
|
|
"any low", "any mid", "any high", "none"
|
|
|
|
};
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = entry->private_data;
|
2012-01-06 05:36:08 +08:00
|
|
|
u32 sections[ARRAY_SIZE(section_names) * 2];
|
|
|
|
struct {
|
|
|
|
u32 number;
|
|
|
|
u32 size;
|
|
|
|
} tx_rx_header;
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
u32 owner_hi, owner_lo;
|
|
|
|
u32 notification;
|
|
|
|
char nick_name[NICK_NAME_SIZE];
|
|
|
|
u32 clock_select;
|
|
|
|
u32 enable;
|
|
|
|
u32 status;
|
|
|
|
u32 extended_status;
|
|
|
|
u32 sample_rate;
|
|
|
|
u32 version;
|
|
|
|
u32 clock_caps;
|
|
|
|
char clock_source_names[CLOCK_SOURCE_NAMES_SIZE];
|
|
|
|
} global;
|
|
|
|
struct {
|
|
|
|
u32 iso;
|
|
|
|
u32 number_audio;
|
|
|
|
u32 number_midi;
|
|
|
|
u32 speed;
|
|
|
|
char names[TX_NAMES_SIZE];
|
|
|
|
u32 ac3_caps;
|
|
|
|
u32 ac3_enable;
|
|
|
|
} tx;
|
|
|
|
struct {
|
|
|
|
u32 iso;
|
|
|
|
u32 seq_start;
|
|
|
|
u32 number_audio;
|
|
|
|
u32 number_midi;
|
|
|
|
char names[RX_NAMES_SIZE];
|
|
|
|
u32 ac3_caps;
|
|
|
|
u32 ac3_enable;
|
|
|
|
} rx;
|
|
|
|
struct {
|
|
|
|
u32 clock_source;
|
|
|
|
u32 locked;
|
|
|
|
u32 rate;
|
|
|
|
u32 adat_user_data;
|
|
|
|
} ext_sync;
|
|
|
|
} buf;
|
|
|
|
unsigned int quadlets, stream, i;
|
|
|
|
|
|
|
|
if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0)
|
|
|
|
return;
|
|
|
|
snd_iprintf(buffer, "sections:\n");
|
|
|
|
for (i = 0; i < ARRAY_SIZE(section_names); ++i)
|
|
|
|
snd_iprintf(buffer, " %s: offset %u, size %u\n",
|
|
|
|
section_names[i],
|
|
|
|
sections[i * 2], sections[i * 2 + 1]);
|
|
|
|
|
|
|
|
quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4);
|
|
|
|
if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0)
|
|
|
|
return;
|
|
|
|
snd_iprintf(buffer, "global:\n");
|
|
|
|
snd_iprintf(buffer, " owner: %04x:%04x%08x\n",
|
|
|
|
buf.global.owner_hi >> 16,
|
|
|
|
buf.global.owner_hi & 0xffff, buf.global.owner_lo);
|
|
|
|
snd_iprintf(buffer, " notification: %08x\n", buf.global.notification);
|
|
|
|
dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE);
|
|
|
|
snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name);
|
|
|
|
snd_iprintf(buffer, " clock select: %s %s\n",
|
|
|
|
str_from_array(clock_sources, ARRAY_SIZE(clock_sources),
|
|
|
|
buf.global.clock_select & CLOCK_SOURCE_MASK),
|
|
|
|
str_from_array(rates, ARRAY_SIZE(rates),
|
|
|
|
(buf.global.clock_select & CLOCK_RATE_MASK)
|
|
|
|
>> CLOCK_RATE_SHIFT));
|
|
|
|
snd_iprintf(buffer, " enable: %u\n", buf.global.enable);
|
|
|
|
snd_iprintf(buffer, " status: %slocked %s\n",
|
|
|
|
buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un",
|
|
|
|
str_from_array(rates, ARRAY_SIZE(rates),
|
|
|
|
(buf.global.status &
|
|
|
|
STATUS_NOMINAL_RATE_MASK)
|
|
|
|
>> CLOCK_RATE_SHIFT));
|
|
|
|
snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status);
|
|
|
|
snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate);
|
|
|
|
snd_iprintf(buffer, " version: %u.%u.%u.%u\n",
|
|
|
|
(buf.global.version >> 24) & 0xff,
|
|
|
|
(buf.global.version >> 16) & 0xff,
|
|
|
|
(buf.global.version >> 8) & 0xff,
|
|
|
|
(buf.global.version >> 0) & 0xff);
|
|
|
|
if (quadlets >= 90) {
|
|
|
|
snd_iprintf(buffer, " clock caps:");
|
|
|
|
for (i = 0; i <= 6; ++i)
|
|
|
|
if (buf.global.clock_caps & (1 << i))
|
|
|
|
snd_iprintf(buffer, " %s", rates[i]);
|
|
|
|
for (i = 0; i <= 12; ++i)
|
|
|
|
if (buf.global.clock_caps & (1 << (16 + i)))
|
|
|
|
snd_iprintf(buffer, " %s", clock_sources[i]);
|
|
|
|
snd_iprintf(buffer, "\n");
|
|
|
|
dice_proc_fixup_string(buf.global.clock_source_names,
|
|
|
|
CLOCK_SOURCE_NAMES_SIZE);
|
|
|
|
snd_iprintf(buffer, " clock source names: %s\n",
|
|
|
|
buf.global.clock_source_names);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0)
|
|
|
|
return;
|
2013-11-29 16:14:09 +08:00
|
|
|
quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4);
|
2012-01-06 05:36:08 +08:00
|
|
|
for (stream = 0; stream < tx_rx_header.number; ++stream) {
|
|
|
|
if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 +
|
|
|
|
stream * tx_rx_header.size,
|
|
|
|
quadlets) < 0)
|
|
|
|
break;
|
|
|
|
snd_iprintf(buffer, "tx %u:\n", stream);
|
|
|
|
snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso);
|
|
|
|
snd_iprintf(buffer, " audio channels: %u\n",
|
|
|
|
buf.tx.number_audio);
|
|
|
|
snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi);
|
|
|
|
snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed);
|
|
|
|
if (quadlets >= 68) {
|
|
|
|
dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE);
|
|
|
|
snd_iprintf(buffer, " names: %s\n", buf.tx.names);
|
|
|
|
}
|
|
|
|
if (quadlets >= 70) {
|
|
|
|
snd_iprintf(buffer, " ac3 caps: %08x\n",
|
|
|
|
buf.tx.ac3_caps);
|
|
|
|
snd_iprintf(buffer, " ac3 enable: %08x\n",
|
|
|
|
buf.tx.ac3_enable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0)
|
|
|
|
return;
|
2013-11-29 16:14:09 +08:00
|
|
|
quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4);
|
2012-01-06 05:36:08 +08:00
|
|
|
for (stream = 0; stream < tx_rx_header.number; ++stream) {
|
|
|
|
if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 +
|
|
|
|
stream * tx_rx_header.size,
|
|
|
|
quadlets) < 0)
|
|
|
|
break;
|
|
|
|
snd_iprintf(buffer, "rx %u:\n", stream);
|
|
|
|
snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso);
|
2012-01-22 23:46:23 +08:00
|
|
|
snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start);
|
2012-01-06 05:36:08 +08:00
|
|
|
snd_iprintf(buffer, " audio channels: %u\n",
|
|
|
|
buf.rx.number_audio);
|
|
|
|
snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi);
|
|
|
|
if (quadlets >= 68) {
|
|
|
|
dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE);
|
|
|
|
snd_iprintf(buffer, " names: %s\n", buf.rx.names);
|
|
|
|
}
|
|
|
|
if (quadlets >= 70) {
|
|
|
|
snd_iprintf(buffer, " ac3 caps: %08x\n",
|
|
|
|
buf.rx.ac3_caps);
|
|
|
|
snd_iprintf(buffer, " ac3 enable: %08x\n",
|
|
|
|
buf.rx.ac3_enable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4);
|
|
|
|
if (quadlets >= 4) {
|
|
|
|
if (dice_proc_read_mem(dice, &buf.ext_sync,
|
|
|
|
sections[6], 4) < 0)
|
|
|
|
return;
|
|
|
|
snd_iprintf(buffer, "ext status:\n");
|
|
|
|
snd_iprintf(buffer, " clock source: %s\n",
|
|
|
|
str_from_array(clock_sources,
|
|
|
|
ARRAY_SIZE(clock_sources),
|
|
|
|
buf.ext_sync.clock_source));
|
|
|
|
snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked);
|
|
|
|
snd_iprintf(buffer, " rate: %s\n",
|
|
|
|
str_from_array(rates, ARRAY_SIZE(rates),
|
|
|
|
buf.ext_sync.rate));
|
|
|
|
snd_iprintf(buffer, " adat user data: ");
|
|
|
|
if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA)
|
|
|
|
snd_iprintf(buffer, "-\n");
|
|
|
|
else
|
|
|
|
snd_iprintf(buffer, "%x\n",
|
|
|
|
buf.ext_sync.adat_user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
static void dice_create_proc(struct snd_dice *dice)
|
2012-01-06 05:36:08 +08:00
|
|
|
{
|
|
|
|
struct snd_info_entry *entry;
|
|
|
|
|
|
|
|
if (!snd_card_proc_new(dice->card, "dice", &entry))
|
|
|
|
snd_info_set_text_ops(entry, dice, dice_proc_read);
|
|
|
|
}
|
|
|
|
|
2012-02-14 04:55:13 +08:00
|
|
|
#define OUI_WEISS 0x001c6a
|
|
|
|
|
|
|
|
#define DICE_CATEGORY_ID 0x04
|
|
|
|
#define WEISS_CATEGORY_ID 0x00
|
2011-09-05 04:16:02 +08:00
|
|
|
|
|
|
|
static int dice_interface_check(struct fw_unit *unit)
|
|
|
|
{
|
|
|
|
static const int min_values[10] = {
|
|
|
|
10, 0x64 / 4,
|
|
|
|
10, 0x18 / 4,
|
|
|
|
10, 0x18 / 4,
|
|
|
|
0, 0,
|
|
|
|
0, 0,
|
|
|
|
};
|
|
|
|
struct fw_device *device = fw_parent_device(unit);
|
|
|
|
struct fw_csr_iterator it;
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
int key, val, vendor = -1, model = -1, err;
|
2012-02-14 04:55:13 +08:00
|
|
|
unsigned int category, i;
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
__be32 *pointers, value;
|
2013-10-16 02:26:05 +08:00
|
|
|
__be32 tx_data[4];
|
2011-09-05 04:16:02 +08:00
|
|
|
__be32 version;
|
|
|
|
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (pointers == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2011-09-05 04:16:02 +08:00
|
|
|
/*
|
|
|
|
* Check that GUID and unit directory are constructed according to DICE
|
|
|
|
* rules, i.e., that the specifier ID is the GUID's OUI, and that the
|
2012-02-14 04:55:13 +08:00
|
|
|
* GUID chip ID consists of the 8-bit category ID, the 10-bit product
|
|
|
|
* ID, and a 22-bit serial number.
|
2011-09-05 04:16:02 +08:00
|
|
|
*/
|
|
|
|
fw_csr_iterator_init(&it, unit->directory);
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
while (fw_csr_iterator_next(&it, &key, &val)) {
|
2011-09-05 04:16:02 +08:00
|
|
|
switch (key) {
|
|
|
|
case CSR_SPECIFIER_ID:
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
vendor = val;
|
2011-09-05 04:16:02 +08:00
|
|
|
break;
|
|
|
|
case CSR_MODEL:
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
model = val;
|
2011-09-05 04:16:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-02-14 04:55:13 +08:00
|
|
|
if (vendor == OUI_WEISS)
|
|
|
|
category = WEISS_CATEGORY_ID;
|
|
|
|
else
|
|
|
|
category = DICE_CATEGORY_ID;
|
|
|
|
if (device->config_rom[3] != ((vendor << 8) | category) ||
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
device->config_rom[4] >> 22 != model) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto end;
|
|
|
|
}
|
2011-09-05 04:16:02 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that the sub address spaces exist and are located inside the
|
|
|
|
* private address space. The minimum values are chosen so that all
|
|
|
|
* minimally required registers are included.
|
|
|
|
*/
|
|
|
|
err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
DICE_PRIVATE_SPACE, pointers,
|
|
|
|
sizeof(__be32) * ARRAY_SIZE(min_values), 0);
|
|
|
|
if (err < 0) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
|
2011-09-05 04:16:02 +08:00
|
|
|
value = be32_to_cpu(pointers[i]);
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
if (value < min_values[i] || value >= 0x40000) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto end;
|
|
|
|
}
|
2011-09-05 04:16:02 +08:00
|
|
|
}
|
|
|
|
|
2013-10-16 02:26:05 +08:00
|
|
|
/* 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);
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
if (err < 0 || (tx_data[0] && tx_data[3])) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto end;
|
|
|
|
}
|
2013-10-16 02:26:05 +08:00
|
|
|
|
2011-09-05 04:16:02 +08:00
|
|
|
/*
|
|
|
|
* Check that the implemented DICE driver specification major version
|
|
|
|
* number matches.
|
|
|
|
*/
|
|
|
|
err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
|
|
|
|
DICE_PRIVATE_SPACE +
|
|
|
|
be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
|
2011-09-05 04:17:38 +08:00
|
|
|
&version, 4, 0);
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
if (err < 0) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto end;
|
|
|
|
}
|
2011-09-05 04:16:02 +08:00
|
|
|
if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
|
|
|
|
dev_err(&unit->device,
|
|
|
|
"unknown DICE version: 0x%08x\n", be32_to_cpu(version));
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
err = -ENODEV;
|
|
|
|
goto end;
|
2011-09-05 04:16:02 +08:00
|
|
|
}
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
end:
|
|
|
|
return err;
|
2011-09-05 04:16:02 +08:00
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
static int highest_supported_mode_rate(struct snd_dice *dice,
|
|
|
|
unsigned int mode, unsigned int *rate)
|
2011-12-05 05:23:59 +08:00
|
|
|
{
|
2014-11-28 23:59:14 +08:00
|
|
|
unsigned int i, m;
|
2011-12-05 05:23:59 +08:00
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
for (i = ARRAY_SIZE(snd_dice_rates); i > 0; i--) {
|
|
|
|
*rate = snd_dice_rates[i - 1];
|
|
|
|
if (snd_dice_stream_get_rate_mode(dice, *rate, &m) < 0)
|
|
|
|
continue;
|
|
|
|
if (mode == m)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == 0)
|
|
|
|
return -EINVAL;
|
2011-12-05 05:23:59 +08:00
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
return 0;
|
2011-12-05 05:23:59 +08:00
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode)
|
2011-12-05 05:23:59 +08:00
|
|
|
{
|
|
|
|
__be32 values[2];
|
2014-11-28 23:59:14 +08:00
|
|
|
unsigned int rate;
|
|
|
|
int err;
|
2011-12-05 05:23:59 +08:00
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
if (highest_supported_mode_rate(dice, mode, &rate) < 0) {
|
2011-12-05 05:23:59 +08:00
|
|
|
dice->rx_channels[mode] = 0;
|
|
|
|
dice->rx_midi_ports[mode] = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
err = snd_dice_transaction_set_rate(dice, rate);
|
2011-12-05 05:23:59 +08:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
|
|
|
|
values, sizeof(values));
|
2011-12-05 05:23:59 +08:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
dice->rx_channels[mode] = be32_to_cpu(values[0]);
|
|
|
|
dice->rx_midi_ports[mode] = be32_to_cpu(values[1]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
static int dice_read_params(struct snd_dice *dice)
|
2011-09-05 04:04:49 +08:00
|
|
|
{
|
2011-12-05 04:47:00 +08:00
|
|
|
__be32 value;
|
2011-12-05 05:23:59 +08:00
|
|
|
int mode, err;
|
2011-09-05 04:04:49 +08:00
|
|
|
|
2011-12-05 04:47:00 +08:00
|
|
|
/* some very old firmwares don't tell about their clock support */
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
if (dice->clock_caps > 0) {
|
|
|
|
err = snd_dice_transaction_read_global(dice,
|
|
|
|
GLOBAL_CLOCK_CAPABILITIES,
|
|
|
|
&value, 4);
|
2011-12-05 04:47:00 +08:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
dice->clock_caps = be32_to_cpu(value);
|
|
|
|
} else {
|
|
|
|
/* this should be supported by any device */
|
|
|
|
dice->clock_caps = CLOCK_CAP_RATE_44100 |
|
|
|
|
CLOCK_CAP_RATE_48000 |
|
|
|
|
CLOCK_CAP_SOURCE_ARX1 |
|
|
|
|
CLOCK_CAP_SOURCE_INTERNAL;
|
|
|
|
}
|
|
|
|
|
2011-12-05 05:23:59 +08:00
|
|
|
for (mode = 2; mode >= 0; --mode) {
|
|
|
|
err = dice_read_mode_params(dice, mode);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2011-09-05 04:04:49 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-28 23:59:11 +08:00
|
|
|
static void dice_card_strings(struct snd_dice *dice)
|
2011-09-05 04:04:49 +08:00
|
|
|
{
|
|
|
|
struct snd_card *card = dice->card;
|
|
|
|
struct fw_device *dev = fw_parent_device(dice->unit);
|
|
|
|
char vendor[32], model[32];
|
|
|
|
unsigned int i;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
strcpy(card->driver, "DICE");
|
|
|
|
|
|
|
|
strcpy(card->shortname, "DICE");
|
|
|
|
BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname));
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
err = snd_dice_transaction_read_global(dice, GLOBAL_NICK_NAME,
|
|
|
|
card->shortname,
|
|
|
|
sizeof(card->shortname));
|
2011-09-05 04:04:49 +08:00
|
|
|
if (err >= 0) {
|
|
|
|
/* DICE strings are returned in "always-wrong" endianness */
|
|
|
|
BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0);
|
|
|
|
for (i = 0; i < sizeof(card->shortname); i += 4)
|
|
|
|
swab32s((u32 *)&card->shortname[i]);
|
|
|
|
card->shortname[sizeof(card->shortname) - 1] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(vendor, "?");
|
|
|
|
fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
|
|
|
|
strcpy(model, "?");
|
|
|
|
fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
|
|
|
|
snprintf(card->longname, sizeof(card->longname),
|
2011-09-05 04:16:02 +08:00
|
|
|
"%s %s (serial %u) at %s, S%d",
|
|
|
|
vendor, model, dev->config_rom[4] & 0x3fffff,
|
2011-09-05 04:04:49 +08:00
|
|
|
dev_name(&dice->unit->device), 100 << dev->max_speed);
|
|
|
|
|
|
|
|
strcpy(card->mixername, "DICE");
|
|
|
|
}
|
|
|
|
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
static void dice_card_free(struct snd_card *card)
|
|
|
|
{
|
|
|
|
struct snd_dice *dice = card->private_data;
|
|
|
|
|
|
|
|
snd_dice_transaction_destroy(dice);
|
|
|
|
mutex_destroy(&dice->mutex);
|
|
|
|
}
|
|
|
|
|
2011-09-05 04:04:49 +08:00
|
|
|
static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
|
|
|
|
{
|
|
|
|
struct snd_card *card;
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice;
|
2011-09-05 04:04:49 +08:00
|
|
|
int err;
|
|
|
|
|
2011-09-05 04:16:02 +08:00
|
|
|
err = dice_interface_check(unit);
|
|
|
|
if (err < 0)
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
goto end;
|
2011-09-05 04:16:02 +08:00
|
|
|
|
2014-01-29 21:23:55 +08:00
|
|
|
err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
|
|
|
|
sizeof(*dice), &card);
|
2011-09-05 04:04:49 +08:00
|
|
|
if (err < 0)
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
goto end;
|
2011-09-05 04:04:49 +08:00
|
|
|
|
|
|
|
dice = card->private_data;
|
|
|
|
dice->card = card;
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
dice->unit = unit;
|
|
|
|
card->private_free = dice_card_free;
|
|
|
|
|
2011-09-05 04:14:15 +08:00
|
|
|
spin_lock_init(&dice->lock);
|
2011-09-05 04:04:49 +08:00
|
|
|
mutex_init(&dice->mutex);
|
2011-12-05 05:23:59 +08:00
|
|
|
init_completion(&dice->clock_accepted);
|
2011-09-05 04:14:15 +08:00
|
|
|
init_waitqueue_head(&dice->hwdep_wait);
|
2011-09-05 04:04:49 +08:00
|
|
|
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
err = snd_dice_transaction_init(dice);
|
2011-09-05 04:04:49 +08:00
|
|
|
if (err < 0)
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
goto error;
|
2011-12-06 05:09:42 +08:00
|
|
|
|
|
|
|
err = dice_read_params(dice);
|
|
|
|
if (err < 0)
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
goto error;
|
2011-09-05 04:04:49 +08:00
|
|
|
|
|
|
|
dice_card_strings(dice);
|
|
|
|
|
|
|
|
err = dice_create_pcm(dice);
|
|
|
|
if (err < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
err = dice_create_hwdep(dice);
|
|
|
|
if (err < 0)
|
|
|
|
goto error;
|
|
|
|
|
2012-01-06 05:36:08 +08:00
|
|
|
dice_create_proc(dice);
|
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
err = snd_dice_stream_init(dice);
|
2011-09-05 04:04:49 +08:00
|
|
|
if (err < 0)
|
|
|
|
goto error;
|
|
|
|
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
err = snd_card_register(card);
|
|
|
|
if (err < 0) {
|
2014-11-28 23:59:14 +08:00
|
|
|
snd_dice_stream_destroy(dice);
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
goto error;
|
|
|
|
}
|
2011-09-05 04:04:49 +08:00
|
|
|
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
dev_set_drvdata(&unit->device, dice);
|
|
|
|
end:
|
|
|
|
return err;
|
2011-09-05 04:04:49 +08:00
|
|
|
error:
|
|
|
|
snd_card_free(card);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dice_remove(struct fw_unit *unit)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = dev_get_drvdata(&unit->device);
|
2011-09-05 04:04:49 +08:00
|
|
|
|
2011-09-05 04:13:09 +08:00
|
|
|
snd_card_disconnect(dice->card);
|
|
|
|
|
2011-08-28 02:05:15 +08:00
|
|
|
mutex_lock(&dice->mutex);
|
|
|
|
|
2014-11-28 23:59:14 +08:00
|
|
|
snd_dice_stream_destroy(dice);
|
2011-09-05 04:13:09 +08:00
|
|
|
|
2011-09-05 04:04:49 +08:00
|
|
|
mutex_unlock(&dice->mutex);
|
|
|
|
|
|
|
|
snd_card_free_when_closed(dice->card);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dice_bus_reset(struct fw_unit *unit)
|
|
|
|
{
|
2014-11-28 23:59:11 +08:00
|
|
|
struct snd_dice *dice = dev_get_drvdata(&unit->device);
|
2011-09-05 04:04:49 +08:00
|
|
|
|
ALSA: dice: Split transaction functionality into a file
This commit adds a file with some helper functions for transaction, and move
some codes into the file with some arrangements.
For Dice chipset, well-known FCP or AV/C commands are not used to control
devices. It's achieved by read/write transactions into specific addresses.
Dice's address area is split into 5 areas. Each area has its own role. The
offset for each area can be got by reading head of the address area. By
reading these areas, drivers can get to know device status. By writing these
areas, drivers can change device status.
Dice has a specific mechanism called as 'notification'. When device status is
changed, Dice devices tells the event by sending transaction. This notification
is sent to an address which drivers register in advance. But this causes an
issue to drivers.
To handle the notification, drivers need to allocate its own callback function
to the address region in host controller. This region is exclusive. For the
other applications, drivers must give a mechanism to read the received
notification. For this purpose, Dice driver already implements hwdep interface.
Dice chipset doesn't allow drivers to register several addresses. In this
reason, when this driver is applied to a device, the other drivers should
_not_ try to register its own address to the device.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2014-11-28 23:59:13 +08:00
|
|
|
/* The handler address register becomes initialized. */
|
|
|
|
snd_dice_transaction_reinit(dice);
|
|
|
|
|
2011-08-28 02:05:15 +08:00
|
|
|
mutex_lock(&dice->mutex);
|
2014-11-28 23:59:14 +08:00
|
|
|
snd_dice_stream_update(dice);
|
2011-09-05 04:04:49 +08:00
|
|
|
mutex_unlock(&dice->mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define DICE_INTERFACE 0x000001
|
|
|
|
|
|
|
|
static const struct ieee1394_device_id dice_id_table[] = {
|
|
|
|
{
|
2011-09-05 04:16:02 +08:00
|
|
|
.match_flags = IEEE1394_MATCH_VERSION,
|
|
|
|
.version = DICE_INTERFACE,
|
2011-09-05 04:04:49 +08:00
|
|
|
},
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(ieee1394, dice_id_table);
|
|
|
|
|
|
|
|
static struct fw_driver dice_driver = {
|
|
|
|
.driver = {
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.name = KBUILD_MODNAME,
|
|
|
|
.bus = &fw_bus_type,
|
|
|
|
},
|
|
|
|
.probe = dice_probe,
|
|
|
|
.update = dice_bus_reset,
|
|
|
|
.remove = dice_remove,
|
|
|
|
.id_table = dice_id_table,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init alsa_dice_init(void)
|
|
|
|
{
|
|
|
|
return driver_register(&dice_driver.driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit alsa_dice_exit(void)
|
|
|
|
{
|
|
|
|
driver_unregister(&dice_driver.driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(alsa_dice_init);
|
|
|
|
module_exit(alsa_dice_exit);
|