err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
FORMER_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); if (err < 0) return err;
data = le32_to_cpu(reg);
return parse_clock_bits(data, rate, src);
}
staticint former_switch_fetching_mode(struct snd_ff *ff, bool enable)
{ unsignedint count;
__le32 *reg; int i; int err;
count = 0; for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i)
count = max(count, ff->spec->pcm_playback_channels[i]);
reg = kcalloc(count, sizeof(__le32), GFP_KERNEL); if (!reg) return -ENOMEM;
if (!enable) { /* * Each quadlet is corresponding to data channels in a data * blocks in reverse order. Precisely, quadlets for available * data channels should be enabled. Here, I take second best * to fetch PCM frames from all of data channels regardless of * stf.
*/ for (i = 0; i < count; ++i)
reg[i] = cpu_to_le32(0x00000001);
}
// Wait till the format of tx packet is available.
count = 0; while (count++ < 10) {
u32 data;
err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
FF800_TX_PACKET_ISOC_CH, ®, sizeof(reg), 0); if (err < 0) return err;
data = le32_to_cpu(reg); if (data != 0xffffffff) {
tx_isoc_channel = data; break;
}
msleep(50);
} if (count >= 10) return -ETIMEDOUT;
// NOTE: this is a makeshift to start OHCI 1394 IR context in the // channel. On the other hand, 'struct fw_iso_resources.allocated' is // not true and it's not deallocated at stop.
ff->tx_resources.channel = tx_isoc_channel;
// If starting isochronous communication immediately, change of STF has // no effect. In this case, the communication runs based on former STF. // Let's sleep for a bit.
msleep(100);
// 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. // 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;
// Fireface 400 manages isochronous channel number in 3 bit field. Therefore, // we can allocate between 0 and 7 channel. staticint ff400_allocate_resources(struct snd_ff *ff, unsignedint rate)
{
__le32 reg; enum snd_ff_stream_mode mode; 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) break;
} 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.
ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
err = fw_iso_resources_allocate(&ff->tx_resources,
amdtp_stream_get_max_payload(&ff->tx_stream),
fw_parent_device(ff->unit)->max_speed); if (err < 0) return err;
// 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),
fw_parent_device(ff->unit)->max_speed); if (err < 0)
fw_iso_resources_free(&ff->tx_resources);
if (generation != fw_parent_device(ff->unit)->card->generation) {
err = fw_iso_resources_update(&ff->tx_resources); if (err < 0) return err;
err = fw_iso_resources_update(&ff->rx_resources); if (err < 0) return err;
}
// 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,
FF400_RX_PACKET_FORMAT, ®, sizeof(reg), 0); if (err < 0) return err;
// 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));
err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
FF400_TX_PACKET_FORMAT, ®, sizeof(reg), 0); if (err < 0) return err;
// For Fireface 400, lower 4 bytes of destination address is configured by bit // flag in quadlet register (little endian) at 0x'0000'801'0051c. Drivers can // select one of 4 options: // // bit flags: offset of destination address // - 0x04000000: 0x'....'....'0000'0000 // - 0x08000000: 0x'....'....'0000'0080 // - 0x10000000: 0x'....'....'0000'0100 // - 0x20000000: 0x'....'....'0000'0180 // // Drivers can suppress the device to transfer asynchronous transactions by // using below 2 bits. // - 0x01000000: suppress transmission // - 0x02000000: suppress transmission // // Actually, the register is write-only and includes the other options such as // input attenuation. This driver allocates destination address with '0000'0000 // in its lower offset and expects userspace application to configure the // register for it.
// When the message is for signal level operation, the upper 4 bits in MSB expresses the pair of // stereo physical port. // - 0: Microphone input 0/1 // - 1: Line input 0/1 // - [2-4]: Line output 0-5 // - 5: Headphone output 0/1 // - 6: S/PDIF output 0/1 // - [7-10]: ADAT output 0-7 // // The value of signal level can be detected by mask of 0x00fffc00. For signal level of microphone // input: // // - 0: 0.0 dB // - 10: +10.0 dB // - 11: +11.0 dB // - 12: +12.0 dB // - ... // - 63: +63.0 dB: // - 64: +64.0 dB: // - 65: +65.0 dB: // // For signal level of line input: // // - 0: 0.0 dB // - 1: +0.5 dB // - 2: +1.0 dB // - 3: +1.5 dB // - ... // - 34: +17.0 dB: // - 35: +17.5 dB: // - 36: +18.0 dB: // // For signal level of any type of output: // // - 63: -infinite // - 62: -58.0 dB // - 61: -56.0 dB // - 60: -54.0 dB // - 59: -53.0 dB // - 58: -52.0 dB // - ... // - 7: -1.0 dB // - 6: 0.0 dB // - 5: +1.0 dB // - ... // - 2: +4.0 dB // - 1: +5.0 dB // - 0: +6.0 dB // // When the message is not for signal level operation, it's for MIDI bytes. When matching to // FF400_MSG_FLAG_IS_MIDI_PORT_0, one MIDI byte can be detected by mask of 0x000000ff. When // matching to FF400_MSG_FLAG_IS_MIDI_PORT_1, one MIDI byte can be detected by mask of 0x00ff0000. #define FF400_MSG_FLAG_IS_SIGNAL_LEVEL 0x04000000 #define FF400_MSG_FLAG_IS_RIGHT_CHANNEL 0x08000000 #define FF400_MSG_FLAG_IS_STEREO_PAIRED 0x02000000 #define FF400_MSG_MASK_STEREO_PAIR 0xf0000000 #define FF400_MSG_MASK_SIGNAL_LEVEL 0x00fffc00 #define FF400_MSG_FLAG_IS_MIDI_PORT_0 0x00000100 #define FF400_MSG_MASK_MIDI_PORT_0 0x000000ff #define FF400_MSG_FLAG_IS_MIDI_PORT_1 0x01000000 #define FF400_MSG_MASK_MIDI_PORT_1 0x00ff0000
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.