Merge branch 'for-linus' into for-next
[linux-2.6-block.git] / sound / firewire / fireface / ff-protocol-latter.c
index c8236ff89b7fb9decdc867770f8ce7f694e3f9dd..0e4c3a9ed5e4914c8ac4cf634dc21dab7e0a456a 100644 (file)
@@ -9,11 +9,11 @@
 
 #include "ff.h"
 
-#define LATTER_STF             0xffff00000004
-#define LATTER_ISOC_CHANNELS   0xffff00000008
-#define LATTER_ISOC_START      0xffff0000000c
-#define LATTER_FETCH_MODE      0xffff00000010
-#define LATTER_SYNC_STATUS     0x0000801c0000
+#define LATTER_STF             0xffff00000004ULL
+#define LATTER_ISOC_CHANNELS   0xffff00000008ULL
+#define LATTER_ISOC_START      0xffff0000000cULL
+#define LATTER_FETCH_MODE      0xffff00000010ULL
+#define LATTER_SYNC_STATUS     0x0000801c0000ULL
 
 static int parse_clock_bits(u32 data, unsigned int *rate,
                            enum snd_ff_clock_src *src)
@@ -97,25 +97,64 @@ static int latter_switch_fetching_mode(struct snd_ff *ff, bool enable)
                                  LATTER_FETCH_MODE, &reg, sizeof(reg), 0);
 }
 
-static int keep_resources(struct snd_ff *ff, unsigned int rate)
+static int latter_allocate_resources(struct snd_ff *ff, unsigned int rate)
 {
        enum snd_ff_stream_mode mode;
+       unsigned int code;
+       __le32 reg;
+       unsigned int count;
        int i;
        int err;
 
-       // Check whether the given value is supported or not.
-       for (i = 0; i < CIP_SFC_COUNT; i++) {
-               if (amdtp_rate_table[i] == rate)
+       // Set the number of data blocks transferred in a second.
+       if (rate % 32000 == 0)
+               code = 0x00;
+       else if (rate % 44100 == 0)
+               code = 0x02;
+       else if (rate % 48000 == 0)
+               code = 0x04;
+       else
+               return -EINVAL;
+
+       if (rate >= 64000 && rate < 128000)
+               code |= 0x08;
+       else if (rate >= 128000 && rate < 192000)
+               code |= 0x10;
+
+       reg = cpu_to_le32(code);
+       err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                LATTER_STF, &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       // Confirm to shift transmission clock.
+       count = 0;
+       while (count++ < 10) {
+               unsigned int curr_rate;
+               enum snd_ff_clock_src src;
+
+               err = latter_get_clock(ff, &curr_rate, &src);
+               if (err < 0)
+                       return err;
+
+               if (curr_rate == rate)
                        break;
        }
-       if (i >= CIP_SFC_COUNT)
+       if (count == 10)
+               return -ETIMEDOUT;
+
+       for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); ++i) {
+               if (rate == amdtp_rate_table[i])
+                       break;
+       }
+       if (i == ARRAY_SIZE(amdtp_rate_table))
                return -EINVAL;
 
        err = snd_ff_stream_get_multiplier_mode(i, &mode);
        if (err < 0)
                return err;
 
-       /* Keep resources for in-stream. */
+       // Keep resources for in-stream.
        ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
        err = fw_iso_resources_allocate(&ff->tx_resources,
                        amdtp_stream_get_max_payload(&ff->tx_stream),
@@ -123,7 +162,7 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
        if (err < 0)
                return err;
 
-       /* Keep resources for out-stream. */
+       // Keep resources for out-stream.
        ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
        err = fw_iso_resources_allocate(&ff->rx_resources,
                        amdtp_stream_get_max_payload(&ff->rx_stream),
@@ -136,60 +175,30 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
 
 static int latter_begin_session(struct snd_ff *ff, unsigned int rate)
 {
-       static const struct {
-               unsigned int stf;
-               unsigned int code;
-               unsigned int flag;
-       } *entry, rate_table[] = {
-               { 32000,  0x00, 0x92, },
-               { 44100,  0x02, 0x92, },
-               { 48000,  0x04, 0x92, },
-               { 64000,  0x08, 0x8e, },
-               { 88200,  0x0a, 0x8e, },
-               { 96000,  0x0c, 0x8e, },
-               { 128000, 0x10, 0x8c, },
-               { 176400, 0x12, 0x8c, },
-               { 192000, 0x14, 0x8c, },
-       };
+       unsigned int generation = ff->rx_resources.generation;
+       unsigned int flag;
        u32 data;
        __le32 reg;
-       unsigned int count;
-       int i;
        int err;
 
-       for (i = 0; i < ARRAY_SIZE(rate_table); ++i) {
-               entry = rate_table + i;
-               if (entry->stf == rate)
-                       break;
-       }
-       if (i == ARRAY_SIZE(rate_table))
+       if (rate >= 32000 && rate <= 48000)
+               flag = 0x92;
+       else if (rate >= 64000 && rate <= 96000)
+               flag = 0x8e;
+       else if (rate >= 128000 && rate <= 192000)
+               flag = 0x8c;
+       else
                return -EINVAL;
 
-       reg = cpu_to_le32(entry->code);
-       err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
-                                LATTER_STF, &reg, sizeof(reg), 0);
-       if (err < 0)
-               return err;
-
-       // Confirm to shift transmission clock.
-       count = 0;
-       while (count++ < 10) {
-               unsigned int curr_rate;
-               enum snd_ff_clock_src src;
-
-               err = latter_get_clock(ff, &curr_rate, &src);
+       if (generation != fw_parent_device(ff->unit)->card->generation) {
+               err = fw_iso_resources_update(&ff->tx_resources);
                if (err < 0)
                        return err;
 
-               if (curr_rate == rate)
-                       break;
+               err = fw_iso_resources_update(&ff->rx_resources);
+               if (err < 0)
+                       return err;
        }
-       if (count == 10)
-               return -ETIMEDOUT;
-
-       err = keep_resources(ff, rate);
-       if (err < 0)
-               return err;
 
        data = (ff->tx_resources.channel << 8) | ff->rx_resources.channel;
        reg = cpu_to_le32(data);
@@ -200,7 +209,7 @@ static int latter_begin_session(struct snd_ff *ff, unsigned int rate)
 
        // Always use the maximum number of data channels in data block of
        // packet.
-       reg = cpu_to_le32(entry->flag);
+       reg = cpu_to_le32(flag);
        return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
                                  LATTER_ISOC_START, &reg, sizeof(reg), 0);
 }
@@ -424,6 +433,7 @@ const struct snd_ff_protocol snd_ff_protocol_latter = {
        .fill_midi_msg          = latter_fill_midi_msg,
        .get_clock              = latter_get_clock,
        .switch_fetching_mode   = latter_switch_fetching_mode,
+       .allocate_resources     = latter_allocate_resources,
        .begin_session          = latter_begin_session,
        .finish_session         = latter_finish_session,
        .dump_status            = latter_dump_status,