ALSA: dice: allow all sample rates
authorClemens Ladisch <clemens@ladisch.de>
Sun, 4 Sep 2011 20:12:06 +0000 (22:12 +0200)
committerClemens Ladisch <clemens@ladisch.de>
Sun, 20 Oct 2013 20:07:57 +0000 (22:07 +0200)
Instead of forcing a constant 44.1 kHz, read the current sample rate
from the device when opening the PCM device.

Actually changing the sample rate requires some separate controller
application.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
sound/firewire/dice.c

index b081021064ed0b854d3b503377abcdcc3d27e110..d3f3eb7a546a83906f867b74d6c70f331b68f0f7 100644 (file)
@@ -75,6 +75,7 @@
 #define  CLOCK_RATE_ANY_MID            0x00000800
 #define  CLOCK_RATE_ANY_HIGH           0x00000900
 #define  CLOCK_RATE_NONE               0x00000a00
+#define  CLOCK_RATE_SHIFT              8
 #define GLOBAL_ENABLE                  0x050
 #define  ENABLE                                0x00000001
 #define GLOBAL_STATUS                  0x054
@@ -248,6 +249,16 @@ MODULE_DESCRIPTION("DICE driver");
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_LICENSE("GPL v2");
 
+static const unsigned int dice_rates[] = {
+       [0] =  32000,
+       [1] =  44100,
+       [2] =  48000,
+       [3] =  88200,
+       [4] =  96000,
+       [5] = 176400,
+       [6] = 192000,
+};
+
 static inline u64 global_address(struct dice *dice, unsigned int offset)
 {
        return DICE_PRIVATE_SPACE + dice->global_offset + offset;
@@ -508,9 +519,6 @@ static int dice_open(struct snd_pcm_substream *substream)
                        SNDRV_PCM_INFO_INTERLEAVED |
                        SNDRV_PCM_INFO_BLOCK_TRANSFER,
                .formats = AMDTP_OUT_PCM_FORMAT_BITS,
-               .rates = SNDRV_PCM_RATE_44100,
-               .rate_min = 44100,
-               .rate_max = 44100,
                .buffer_bytes_max = 16 * 1024 * 1024,
                .period_bytes_min = 1,
                .period_bytes_max = UINT_MAX,
@@ -519,9 +527,20 @@ static int dice_open(struct snd_pcm_substream *substream)
        };
        struct dice *dice = substream->private_data;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       __be32 number_audio, number_midi;
+       __be32 clock_sel, number_audio, number_midi;
+       unsigned int rate;
        int err;
 
+       err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST,
+                                global_address(dice, GLOBAL_CLOCK_SELECT),
+                                &clock_sel, 4);
+       if (err < 0)
+               return err;
+       rate = (be32_to_cpu(clock_sel) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT;
+       if (rate >= ARRAY_SIZE(dice_rates))
+               return -ENXIO;
+       rate = dice_rates[rate];
+
        err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST,
                                 rx_address(dice, RX_NUMBER_AUDIO),
                                 &number_audio, 4);
@@ -534,10 +553,14 @@ static int dice_open(struct snd_pcm_substream *substream)
                return err;
 
        runtime->hw = hardware;
+
+       runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate);
+       snd_pcm_limit_hw_rates(runtime);
+
        runtime->hw.channels_min = be32_to_cpu(number_audio);
        runtime->hw.channels_max = be32_to_cpu(number_audio);
 
-       amdtp_out_stream_set_rate(&dice->stream, 44100);
+       amdtp_out_stream_set_rate(&dice->stream, rate);
        amdtp_out_stream_set_pcm(&dice->stream, be32_to_cpu(number_audio));
        amdtp_out_stream_set_midi(&dice->stream, be32_to_cpu(number_midi));
 
@@ -746,17 +769,9 @@ static int dice_create_pcm(struct dice *dice)
                .page      = snd_pcm_lib_get_vmalloc_page,
                .mmap      = snd_pcm_lib_mmap_vmalloc,
        };
-       __be32 clock;
        struct snd_pcm *pcm;
        int err;
 
-       clock = cpu_to_be32(CLOCK_SOURCE_ARX1 | CLOCK_RATE_44100);
-       err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
-                                global_address(dice, GLOBAL_CLOCK_SELECT),
-                                &clock, 4);
-       if (err < 0)
-               return err;
-
        err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm);
        if (err < 0)
                return err;
@@ -897,6 +912,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 {
        struct snd_card *card;
        struct dice *dice;
+       __be32 clock_sel;
        int err;
 
        err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*dice), &card);
@@ -938,6 +954,19 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 
        dice_card_strings(dice);
 
+       err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
+                                global_address(dice, GLOBAL_CLOCK_SELECT),
+                                &clock_sel, 4);
+       if (err < 0)
+               goto error;
+       clock_sel &= cpu_to_be32(~CLOCK_SOURCE_MASK);
+       clock_sel |= cpu_to_be32(CLOCK_SOURCE_ARX1);
+       err = snd_fw_transaction(unit, TCODE_WRITE_QUADLET_REQUEST,
+                                global_address(dice, GLOBAL_CLOCK_SELECT),
+                                &clock_sel, 4);
+       if (err < 0)
+               goto error;
+
        err = dice_create_pcm(dice);
        if (err < 0)
                goto error;