diff options
Diffstat (limited to 'sound/firewire/fireface/ff-protocol-former.c')
-rw-r--r-- | sound/firewire/fireface/ff-protocol-former.c | 112 |
1 files changed, 60 insertions, 52 deletions
diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index 8d1c2c6e907b..bf44cad7985e 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -293,27 +293,6 @@ static int former_fill_midi_msg(struct snd_ff *ff, #define FF800_TX_PACKET_ISOC_CH 0x0000801c0008 -static int allocate_rx_resources(struct snd_ff *ff) -{ - u32 data; - __le32 reg; - int err; - - // Controllers should allocate isochronous resources for rx stream. - err = fw_iso_resources_allocate(&ff->rx_resources, - amdtp_stream_get_max_payload(&ff->rx_stream), - fw_parent_device(ff->unit)->max_speed); - if (err < 0) - return err; - - // Set isochronous channel and the number of quadlets of rx packets. - data = ff->rx_stream.data_block_quadlets << 3; - data = (data << 8) | ff->rx_resources.channel; - reg = cpu_to_le32(data); - return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF800_RX_PACKET_FORMAT, ®, sizeof(reg), 0); -} - static int allocate_tx_resources(struct snd_ff *ff) { __le32 reg; @@ -355,8 +334,9 @@ static int allocate_tx_resources(struct snd_ff *ff) return 0; } -static int ff800_begin_session(struct snd_ff *ff, unsigned int rate) +static int ff800_allocate_resources(struct snd_ff *ff, unsigned int rate) { + u32 data; __le32 reg; int err; @@ -371,14 +351,38 @@ static int ff800_begin_session(struct snd_ff *ff, unsigned int rate) // Let's sleep for a bit. msleep(100); - err = allocate_rx_resources(ff); + // Controllers should allocate isochronous resources for rx stream. + err = fw_iso_resources_allocate(&ff->rx_resources, + amdtp_stream_get_max_payload(&ff->rx_stream), + fw_parent_device(ff->unit)->max_speed); if (err < 0) return err; - err = allocate_tx_resources(ff); + // Set isochronous channel and the number of quadlets of rx packets. + // This should be done before the allocation of tx resources to avoid + // periodical noise. + data = ff->rx_stream.data_block_quadlets << 3; + data = (data << 8) | ff->rx_resources.channel; + reg = cpu_to_le32(data); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF800_RX_PACKET_FORMAT, ®, sizeof(reg), 0); if (err < 0) return err; + return allocate_tx_resources(ff); +} + +static int ff800_begin_session(struct snd_ff *ff, unsigned int rate) +{ + unsigned int generation = ff->rx_resources.generation; + __le32 reg; + + if (generation != fw_parent_device(ff->unit)->card->generation) { + int err = fw_iso_resources_update(&ff->rx_resources); + if (err < 0) + return err; + } + reg = cpu_to_le32(0x80000000); reg |= cpu_to_le32(ff->tx_stream.data_block_quadlets); if (fw_parent_device(ff->unit)->max_speed == SCODE_800) @@ -420,6 +424,7 @@ const struct snd_ff_protocol snd_ff_protocol_ff800 = { .fill_midi_msg = former_fill_midi_msg, .get_clock = former_get_clock, .switch_fetching_mode = former_switch_fetching_mode, + .allocate_resources = ff800_allocate_resources, .begin_session = ff800_begin_session, .finish_session = ff800_finish_session, .dump_status = former_dump_status, @@ -431,12 +436,11 @@ const struct snd_ff_protocol snd_ff_protocol_ff800 = { #define FF400_TX_PACKET_FORMAT 0x00008010050cull #define FF400_ISOC_COMM_STOP 0x000080100510ull -/* - * Fireface 400 manages isochronous channel number in 3 bit field. Therefore, - * we can allocate between 0 and 7 channel. - */ -static int keep_resources(struct snd_ff *ff, unsigned int rate) +// Fireface 400 manages isochronous channel number in 3 bit field. Therefore, +// we can allocate between 0 and 7 channel. +static int ff400_allocate_resources(struct snd_ff *ff, unsigned int rate) { + __le32 reg; enum snd_ff_stream_mode mode; int i; int err; @@ -449,11 +453,20 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate) if (i >= CIP_SFC_COUNT) return -EINVAL; + // Set the number of data blocks transferred in a second. + reg = cpu_to_le32(rate); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF400_STF, ®, sizeof(reg), 0); + if (err < 0) + return err; + + msleep(100); + 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), @@ -461,7 +474,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), @@ -474,26 +487,22 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate) static int ff400_begin_session(struct snd_ff *ff, unsigned int rate) { + unsigned int generation = ff->rx_resources.generation; __le32 reg; int err; - err = keep_resources(ff, rate); - if (err < 0) - return err; - - /* Set the number of data blocks transferred in a second. */ - reg = cpu_to_le32(rate); - err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF400_STF, ®, sizeof(reg), 0); - if (err < 0) - return err; + if (generation != fw_parent_device(ff->unit)->card->generation) { + err = fw_iso_resources_update(&ff->tx_resources); + if (err < 0) + return err; - msleep(100); + err = fw_iso_resources_update(&ff->rx_resources); + if (err < 0) + return err; + } - /* - * Set isochronous channel and the number of quadlets of received - * packets. - */ + // Set isochronous channel and the number of quadlets of received + // packets. reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) | ff->rx_resources.channel); err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, @@ -501,11 +510,9 @@ static int ff400_begin_session(struct snd_ff *ff, unsigned int rate) if (err < 0) return err; - /* - * Set isochronous channel and the number of quadlets of transmitted - * packet. - */ - /* TODO: investigate the purpose of this 0x80. */ + // Set isochronous channel and the number of quadlets of transmitted + // packet. + // TODO: investigate the purpose of this 0x80. reg = cpu_to_le32((0x80 << 24) | (ff->tx_resources.channel << 5) | (ff->tx_stream.data_block_quadlets)); @@ -514,7 +521,7 @@ static int ff400_begin_session(struct snd_ff *ff, unsigned int rate) if (err < 0) return err; - /* Allow to transmit packets. */ + // Allow to transmit packets. reg = cpu_to_le32(0x00000001); return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, FF400_ISOC_COMM_START, ®, sizeof(reg), 0); @@ -591,6 +598,7 @@ const struct snd_ff_protocol snd_ff_protocol_ff400 = { .fill_midi_msg = former_fill_midi_msg, .get_clock = former_get_clock, .switch_fetching_mode = former_switch_fetching_mode, + .allocate_resources = ff400_allocate_resources, .begin_session = ff400_begin_session, .finish_session = ff400_finish_session, .dump_status = former_dump_status, |