Path: blob/master/sound/firewire/fireface/ff-protocol-former.c
26451 views
// SPDX-License-Identifier: GPL-2.01// ff-protocol-former.c - a part of driver for RME Fireface series2//3// Copyright (c) 2019 Takashi Sakamoto45#include <linux/delay.h>67#include "ff.h"89#define FORMER_REG_SYNC_STATUS 0x0000801c0000ull10/* For block write request. */11#define FORMER_REG_FETCH_PCM_FRAMES 0x0000801c0000ull12#define FORMER_REG_CLOCK_CONFIG 0x0000801c0004ull1314static int parse_clock_bits(u32 data, unsigned int *rate,15enum snd_ff_clock_src *src)16{17static const struct {18unsigned int rate;19u32 mask;20} *rate_entry, rate_entries[] = {21{ 32000, 0x00000002, },22{ 44100, 0x00000000, },23{ 48000, 0x00000006, },24{ 64000, 0x0000000a, },25{ 88200, 0x00000008, },26{ 96000, 0x0000000e, },27{ 128000, 0x00000012, },28{ 176400, 0x00000010, },29{ 192000, 0x00000016, },30};31static const struct {32enum snd_ff_clock_src src;33u32 mask;34} *clk_entry, clk_entries[] = {35{ SND_FF_CLOCK_SRC_ADAT1, 0x00000000, },36{ SND_FF_CLOCK_SRC_ADAT2, 0x00000400, },37{ SND_FF_CLOCK_SRC_SPDIF, 0x00000c00, },38{ SND_FF_CLOCK_SRC_WORD, 0x00001000, },39{ SND_FF_CLOCK_SRC_LTC, 0x00001800, },40};41int i;4243for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) {44rate_entry = rate_entries + i;45if ((data & 0x0000001e) == rate_entry->mask) {46*rate = rate_entry->rate;47break;48}49}50if (i == ARRAY_SIZE(rate_entries))51return -EIO;5253if (data & 0x00000001) {54*src = SND_FF_CLOCK_SRC_INTERNAL;55} else {56for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) {57clk_entry = clk_entries + i;58if ((data & 0x00001c00) == clk_entry->mask) {59*src = clk_entry->src;60break;61}62}63if (i == ARRAY_SIZE(clk_entries))64return -EIO;65}6667return 0;68}6970static int former_get_clock(struct snd_ff *ff, unsigned int *rate,71enum snd_ff_clock_src *src)72{73__le32 reg;74u32 data;75int err;7677err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,78FORMER_REG_CLOCK_CONFIG, ®, sizeof(reg), 0);79if (err < 0)80return err;81data = le32_to_cpu(reg);8283return parse_clock_bits(data, rate, src);84}8586static int former_switch_fetching_mode(struct snd_ff *ff, bool enable)87{88unsigned int count;89__le32 *reg;90int i;91int err;9293count = 0;94for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i)95count = max(count, ff->spec->pcm_playback_channels[i]);9697reg = kcalloc(count, sizeof(__le32), GFP_KERNEL);98if (!reg)99return -ENOMEM;100101if (!enable) {102/*103* Each quadlet is corresponding to data channels in a data104* blocks in reverse order. Precisely, quadlets for available105* data channels should be enabled. Here, I take second best106* to fetch PCM frames from all of data channels regardless of107* stf.108*/109for (i = 0; i < count; ++i)110reg[i] = cpu_to_le32(0x00000001);111}112113err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST,114FORMER_REG_FETCH_PCM_FRAMES, reg,115sizeof(__le32) * count, 0);116kfree(reg);117return err;118}119120static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer)121{122__le32 reg;123u32 data;124unsigned int rate;125enum snd_ff_clock_src src;126const char *label;127int err;128129err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,130FORMER_REG_CLOCK_CONFIG, ®, sizeof(reg), 0);131if (err < 0)132return;133data = le32_to_cpu(reg);134135snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",136(data & 0x00000020) ? "Professional" : "Consumer",137str_on_off(data & 0x00000040));138139snd_iprintf(buffer, "Optical output interface format: %s\n",140(data & 0x00000100) ? "S/PDIF" : "ADAT");141142snd_iprintf(buffer, "Word output single speed: %s\n",143str_on_off(data & 0x00002000));144145snd_iprintf(buffer, "S/PDIF input interface: %s\n",146(data & 0x00000200) ? "Optical" : "Coaxial");147148err = parse_clock_bits(data, &rate, &src);149if (err < 0)150return;151label = snd_ff_proc_get_clk_label(src);152if (!label)153return;154155snd_iprintf(buffer, "Clock configuration: %d %s\n", rate, label);156}157158static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer)159{160static const struct {161char *const label;162u32 locked_mask;163u32 synced_mask;164} *clk_entry, clk_entries[] = {165{ "WDClk", 0x40000000, 0x20000000, },166{ "S/PDIF", 0x00080000, 0x00040000, },167{ "ADAT1", 0x00000400, 0x00001000, },168{ "ADAT2", 0x00000800, 0x00002000, },169};170static const struct {171char *const label;172u32 mask;173} *referred_entry, referred_entries[] = {174{ "ADAT1", 0x00000000, },175{ "ADAT2", 0x00400000, },176{ "S/PDIF", 0x00c00000, },177{ "WDclk", 0x01000000, },178{ "TCO", 0x01400000, },179};180static const struct {181unsigned int rate;182u32 mask;183} *rate_entry, rate_entries[] = {184{ 32000, 0x02000000, },185{ 44100, 0x04000000, },186{ 48000, 0x06000000, },187{ 64000, 0x08000000, },188{ 88200, 0x0a000000, },189{ 96000, 0x0c000000, },190{ 128000, 0x0e000000, },191{ 176400, 0x10000000, },192{ 192000, 0x12000000, },193};194__le32 reg[2];195u32 data[2];196int i;197int err;198199err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,200FORMER_REG_SYNC_STATUS, reg, sizeof(reg), 0);201if (err < 0)202return;203data[0] = le32_to_cpu(reg[0]);204data[1] = le32_to_cpu(reg[1]);205206snd_iprintf(buffer, "External source detection:\n");207208for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) {209const char *state;210211clk_entry = clk_entries + i;212if (data[0] & clk_entry->locked_mask) {213if (data[0] & clk_entry->synced_mask)214state = "sync";215else216state = "lock";217} else {218state = "none";219}220221snd_iprintf(buffer, "%s: %s\n", clk_entry->label, state);222}223224snd_iprintf(buffer, "Referred clock:\n");225226if (data[1] & 0x00000001) {227snd_iprintf(buffer, "Internal\n");228} else {229unsigned int rate;230const char *label;231232for (i = 0; i < ARRAY_SIZE(referred_entries); ++i) {233referred_entry = referred_entries + i;234if ((data[0] & 0x1e0000) == referred_entry->mask) {235label = referred_entry->label;236break;237}238}239if (i == ARRAY_SIZE(referred_entries))240label = "none";241242for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) {243rate_entry = rate_entries + i;244if ((data[0] & 0x1e000000) == rate_entry->mask) {245rate = rate_entry->rate;246break;247}248}249if (i == ARRAY_SIZE(rate_entries))250rate = 0;251252snd_iprintf(buffer, "%s %d\n", label, rate);253}254}255256static void former_dump_status(struct snd_ff *ff,257struct snd_info_buffer *buffer)258{259dump_clock_config(ff, buffer);260dump_sync_status(ff, buffer);261}262263static int former_fill_midi_msg(struct snd_ff *ff,264struct snd_rawmidi_substream *substream,265unsigned int port)266{267u8 *buf = (u8 *)ff->msg_buf[port];268int len;269int i;270271len = snd_rawmidi_transmit_peek(substream, buf,272SND_FF_MAXIMIM_MIDI_QUADS);273if (len <= 0)274return len;275276// One quadlet includes one byte.277for (i = len - 1; i >= 0; --i)278ff->msg_buf[port][i] = cpu_to_le32(buf[i]);279ff->rx_bytes[port] = len;280281return len;282}283284#define FF800_STF 0x0000fc88f000285#define FF800_RX_PACKET_FORMAT 0x0000fc88f004286#define FF800_ALLOC_TX_STREAM 0x0000fc88f008287#define FF800_ISOC_COMM_START 0x0000fc88f00c288#define FF800_TX_S800_FLAG 0x00000800289#define FF800_ISOC_COMM_STOP 0x0000fc88f010290291#define FF800_TX_PACKET_ISOC_CH 0x0000801c0008292293static int allocate_tx_resources(struct snd_ff *ff)294{295__le32 reg;296unsigned int count;297unsigned int tx_isoc_channel;298int err;299300reg = cpu_to_le32(ff->tx_stream.data_block_quadlets);301err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,302FF800_ALLOC_TX_STREAM, ®, sizeof(reg), 0);303if (err < 0)304return err;305306// Wait till the format of tx packet is available.307count = 0;308while (count++ < 10) {309u32 data;310err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,311FF800_TX_PACKET_ISOC_CH, ®, sizeof(reg), 0);312if (err < 0)313return err;314315data = le32_to_cpu(reg);316if (data != 0xffffffff) {317tx_isoc_channel = data;318break;319}320321msleep(50);322}323if (count >= 10)324return -ETIMEDOUT;325326// NOTE: this is a makeshift to start OHCI 1394 IR context in the327// channel. On the other hand, 'struct fw_iso_resources.allocated' is328// not true and it's not deallocated at stop.329ff->tx_resources.channel = tx_isoc_channel;330331return 0;332}333334static int ff800_allocate_resources(struct snd_ff *ff, unsigned int rate)335{336u32 data;337__le32 reg;338int err;339340reg = cpu_to_le32(rate);341err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,342FF800_STF, ®, sizeof(reg), 0);343if (err < 0)344return err;345346// If starting isochronous communication immediately, change of STF has347// no effect. In this case, the communication runs based on former STF.348// Let's sleep for a bit.349msleep(100);350351// Controllers should allocate isochronous resources for rx stream.352err = fw_iso_resources_allocate(&ff->rx_resources,353amdtp_stream_get_max_payload(&ff->rx_stream),354fw_parent_device(ff->unit)->max_speed);355if (err < 0)356return err;357358// Set isochronous channel and the number of quadlets of rx packets.359// This should be done before the allocation of tx resources to avoid360// periodical noise.361data = ff->rx_stream.data_block_quadlets << 3;362data = (data << 8) | ff->rx_resources.channel;363reg = cpu_to_le32(data);364err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,365FF800_RX_PACKET_FORMAT, ®, sizeof(reg), 0);366if (err < 0)367return err;368369return allocate_tx_resources(ff);370}371372static int ff800_begin_session(struct snd_ff *ff, unsigned int rate)373{374unsigned int generation = ff->rx_resources.generation;375__le32 reg;376377if (generation != fw_parent_device(ff->unit)->card->generation) {378int err = fw_iso_resources_update(&ff->rx_resources);379if (err < 0)380return err;381}382383reg = cpu_to_le32(0x80000000);384reg |= cpu_to_le32(ff->tx_stream.data_block_quadlets);385if (fw_parent_device(ff->unit)->max_speed == SCODE_800)386reg |= cpu_to_le32(FF800_TX_S800_FLAG);387return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,388FF800_ISOC_COMM_START, ®, sizeof(reg), 0);389}390391static void ff800_finish_session(struct snd_ff *ff)392{393__le32 reg;394395reg = cpu_to_le32(0x80000000);396snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,397FF800_ISOC_COMM_STOP, ®, sizeof(reg), 0);398}399400// Fireface 800 doesn't allow drivers to register lower 4 bytes of destination401// address.402// A write transaction to clear registered higher 4 bytes of destination address403// has an effect to suppress asynchronous transaction from device.404static void ff800_handle_midi_msg(struct snd_ff *ff, unsigned int offset, const __le32 *buf,405size_t length, u32 tstamp)406{407int i;408409for (i = 0; i < length / 4; i++) {410u8 byte = le32_to_cpu(buf[i]) & 0xff;411struct snd_rawmidi_substream *substream;412413substream = READ_ONCE(ff->tx_midi_substreams[0]);414if (substream)415snd_rawmidi_receive(substream, &byte, 1);416}417}418419const struct snd_ff_protocol snd_ff_protocol_ff800 = {420.handle_msg = ff800_handle_midi_msg,421.fill_midi_msg = former_fill_midi_msg,422.get_clock = former_get_clock,423.switch_fetching_mode = former_switch_fetching_mode,424.allocate_resources = ff800_allocate_resources,425.begin_session = ff800_begin_session,426.finish_session = ff800_finish_session,427.dump_status = former_dump_status,428};429430#define FF400_STF 0x000080100500ull431#define FF400_RX_PACKET_FORMAT 0x000080100504ull432#define FF400_ISOC_COMM_START 0x000080100508ull433#define FF400_TX_PACKET_FORMAT 0x00008010050cull434#define FF400_ISOC_COMM_STOP 0x000080100510ull435436// Fireface 400 manages isochronous channel number in 3 bit field. Therefore,437// we can allocate between 0 and 7 channel.438static int ff400_allocate_resources(struct snd_ff *ff, unsigned int rate)439{440__le32 reg;441enum snd_ff_stream_mode mode;442int i;443int err;444445// Check whether the given value is supported or not.446for (i = 0; i < CIP_SFC_COUNT; i++) {447if (amdtp_rate_table[i] == rate)448break;449}450if (i >= CIP_SFC_COUNT)451return -EINVAL;452453// Set the number of data blocks transferred in a second.454reg = cpu_to_le32(rate);455err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,456FF400_STF, ®, sizeof(reg), 0);457if (err < 0)458return err;459460msleep(100);461462err = snd_ff_stream_get_multiplier_mode(i, &mode);463if (err < 0)464return err;465466// Keep resources for in-stream.467ff->tx_resources.channels_mask = 0x00000000000000ffuLL;468err = fw_iso_resources_allocate(&ff->tx_resources,469amdtp_stream_get_max_payload(&ff->tx_stream),470fw_parent_device(ff->unit)->max_speed);471if (err < 0)472return err;473474// Keep resources for out-stream.475ff->rx_resources.channels_mask = 0x00000000000000ffuLL;476err = fw_iso_resources_allocate(&ff->rx_resources,477amdtp_stream_get_max_payload(&ff->rx_stream),478fw_parent_device(ff->unit)->max_speed);479if (err < 0)480fw_iso_resources_free(&ff->tx_resources);481482return err;483}484485static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)486{487unsigned int generation = ff->rx_resources.generation;488__le32 reg;489int err;490491if (generation != fw_parent_device(ff->unit)->card->generation) {492err = fw_iso_resources_update(&ff->tx_resources);493if (err < 0)494return err;495496err = fw_iso_resources_update(&ff->rx_resources);497if (err < 0)498return err;499}500501// Set isochronous channel and the number of quadlets of received502// packets.503reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) |504ff->rx_resources.channel);505err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,506FF400_RX_PACKET_FORMAT, ®, sizeof(reg), 0);507if (err < 0)508return err;509510// Set isochronous channel and the number of quadlets of transmitted511// packet.512// TODO: investigate the purpose of this 0x80.513reg = cpu_to_le32((0x80 << 24) |514(ff->tx_resources.channel << 5) |515(ff->tx_stream.data_block_quadlets));516err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,517FF400_TX_PACKET_FORMAT, ®, sizeof(reg), 0);518if (err < 0)519return err;520521// Allow to transmit packets.522reg = cpu_to_le32(0x00000001);523return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,524FF400_ISOC_COMM_START, ®, sizeof(reg), 0);525}526527static void ff400_finish_session(struct snd_ff *ff)528{529__le32 reg;530531reg = cpu_to_le32(0x80000000);532snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,533FF400_ISOC_COMM_STOP, ®, sizeof(reg), 0);534}535536static void parse_midi_msg(struct snd_ff *ff, u32 quad, unsigned int port)537{538struct snd_rawmidi_substream *substream = READ_ONCE(ff->tx_midi_substreams[port]);539540if (substream != NULL) {541u8 byte = (quad >> (16 * port)) & 0x000000ff;542543snd_rawmidi_receive(substream, &byte, 1);544}545}546547#define FF400_QUEUE_SIZE 32548549struct ff400_msg_parser {550struct {551u32 msg;552u32 tstamp;553} msgs[FF400_QUEUE_SIZE];554size_t push_pos;555size_t pull_pos;556};557558static bool ff400_has_msg(struct snd_ff *ff)559{560struct ff400_msg_parser *parser = ff->msg_parser;561562return (parser->push_pos != parser->pull_pos);563}564565// For Fireface 400, lower 4 bytes of destination address is configured by bit566// flag in quadlet register (little endian) at 0x'0000'801'0051c. Drivers can567// select one of 4 options:568//569// bit flags: offset of destination address570// - 0x04000000: 0x'....'....'0000'0000571// - 0x08000000: 0x'....'....'0000'0080572// - 0x10000000: 0x'....'....'0000'0100573// - 0x20000000: 0x'....'....'0000'0180574//575// Drivers can suppress the device to transfer asynchronous transactions by576// using below 2 bits.577// - 0x01000000: suppress transmission578// - 0x02000000: suppress transmission579//580// Actually, the register is write-only and includes the other options such as581// input attenuation. This driver allocates destination address with '0000'0000582// in its lower offset and expects userspace application to configure the583// register for it.584585// When the message is for signal level operation, the upper 4 bits in MSB expresses the pair of586// stereo physical port.587// - 0: Microphone input 0/1588// - 1: Line input 0/1589// - [2-4]: Line output 0-5590// - 5: Headphone output 0/1591// - 6: S/PDIF output 0/1592// - [7-10]: ADAT output 0-7593//594// The value of signal level can be detected by mask of 0x00fffc00. For signal level of microphone595// input:596//597// - 0: 0.0 dB598// - 10: +10.0 dB599// - 11: +11.0 dB600// - 12: +12.0 dB601// - ...602// - 63: +63.0 dB:603// - 64: +64.0 dB:604// - 65: +65.0 dB:605//606// For signal level of line input:607//608// - 0: 0.0 dB609// - 1: +0.5 dB610// - 2: +1.0 dB611// - 3: +1.5 dB612// - ...613// - 34: +17.0 dB:614// - 35: +17.5 dB:615// - 36: +18.0 dB:616//617// For signal level of any type of output:618//619// - 63: -infinite620// - 62: -58.0 dB621// - 61: -56.0 dB622// - 60: -54.0 dB623// - 59: -53.0 dB624// - 58: -52.0 dB625// - ...626// - 7: -1.0 dB627// - 6: 0.0 dB628// - 5: +1.0 dB629// - ...630// - 2: +4.0 dB631// - 1: +5.0 dB632// - 0: +6.0 dB633//634// When the message is not for signal level operation, it's for MIDI bytes. When matching to635// FF400_MSG_FLAG_IS_MIDI_PORT_0, one MIDI byte can be detected by mask of 0x000000ff. When636// matching to FF400_MSG_FLAG_IS_MIDI_PORT_1, one MIDI byte can be detected by mask of 0x00ff0000.637#define FF400_MSG_FLAG_IS_SIGNAL_LEVEL 0x04000000638#define FF400_MSG_FLAG_IS_RIGHT_CHANNEL 0x08000000639#define FF400_MSG_FLAG_IS_STEREO_PAIRED 0x02000000640#define FF400_MSG_MASK_STEREO_PAIR 0xf0000000641#define FF400_MSG_MASK_SIGNAL_LEVEL 0x00fffc00642#define FF400_MSG_FLAG_IS_MIDI_PORT_0 0x00000100643#define FF400_MSG_MASK_MIDI_PORT_0 0x000000ff644#define FF400_MSG_FLAG_IS_MIDI_PORT_1 0x01000000645#define FF400_MSG_MASK_MIDI_PORT_1 0x00ff0000646647static void ff400_handle_msg(struct snd_ff *ff, unsigned int offset, const __le32 *buf,648size_t length, u32 tstamp)649{650bool need_hwdep_wake_up = false;651int i;652653for (i = 0; i < length / 4; i++) {654u32 quad = le32_to_cpu(buf[i]);655656if (quad & FF400_MSG_FLAG_IS_SIGNAL_LEVEL) {657struct ff400_msg_parser *parser = ff->msg_parser;658659parser->msgs[parser->push_pos].msg = quad;660parser->msgs[parser->push_pos].tstamp = tstamp;661++parser->push_pos;662if (parser->push_pos >= FF400_QUEUE_SIZE)663parser->push_pos = 0;664665need_hwdep_wake_up = true;666} else if (quad & FF400_MSG_FLAG_IS_MIDI_PORT_0) {667parse_midi_msg(ff, quad, 0);668} else if (quad & FF400_MSG_FLAG_IS_MIDI_PORT_1) {669parse_midi_msg(ff, quad, 1);670}671}672673if (need_hwdep_wake_up)674wake_up(&ff->hwdep_wait);675}676677static long ff400_copy_msg_to_user(struct snd_ff *ff, char __user *buf, long count)678{679struct snd_firewire_event_ff400_message ev = {680.type = SNDRV_FIREWIRE_EVENT_FF400_MESSAGE,681.message_count = 0,682};683struct ff400_msg_parser *parser = ff->msg_parser;684long consumed = 0;685long ret = 0;686687if (count < sizeof(ev) || parser->pull_pos == parser->push_pos)688return 0;689690count -= sizeof(ev);691consumed += sizeof(ev);692693while (count >= sizeof(*parser->msgs) && parser->pull_pos != parser->push_pos) {694spin_unlock_irq(&ff->lock);695if (copy_to_user(buf + consumed, parser->msgs + parser->pull_pos,696sizeof(*parser->msgs)))697ret = -EFAULT;698spin_lock_irq(&ff->lock);699if (ret)700return ret;701702++parser->pull_pos;703if (parser->pull_pos >= FF400_QUEUE_SIZE)704parser->pull_pos = 0;705++ev.message_count;706count -= sizeof(*parser->msgs);707consumed += sizeof(*parser->msgs);708}709710spin_unlock_irq(&ff->lock);711if (copy_to_user(buf, &ev, sizeof(ev)))712ret = -EFAULT;713spin_lock_irq(&ff->lock);714if (ret)715return ret;716717return consumed;718}719720const struct snd_ff_protocol snd_ff_protocol_ff400 = {721.msg_parser_size = sizeof(struct ff400_msg_parser),722.has_msg = ff400_has_msg,723.copy_msg_to_user = ff400_copy_msg_to_user,724.handle_msg = ff400_handle_msg,725.fill_midi_msg = former_fill_midi_msg,726.get_clock = former_get_clock,727.switch_fetching_mode = former_switch_fetching_mode,728.allocate_resources = ff400_allocate_resources,729.begin_session = ff400_begin_session,730.finish_session = ff400_finish_session,731.dump_status = former_dump_status,732};733734735