162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// motu-register-dsp-message-parser.c - a part of driver for MOTU FireWire series 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci// Below models allow software to configure their DSP functions by asynchronous transaction 862306a36Sopenharmony_ci// to access their internal registers. 962306a36Sopenharmony_ci// * 828 mk2 1062306a36Sopenharmony_ci// * 896hd 1162306a36Sopenharmony_ci// * Traveler 1262306a36Sopenharmony_ci// * 8 pre 1362306a36Sopenharmony_ci// * Ultralite 1462306a36Sopenharmony_ci// * 4 pre 1562306a36Sopenharmony_ci// * Audio Express 1662306a36Sopenharmony_ci// 1762306a36Sopenharmony_ci// Additionally, isochronous packets from the above models include messages to notify state of 1862306a36Sopenharmony_ci// DSP. The messages are two set of 3 byte data in 2nd and 3rd quadlet of data block. When user 1962306a36Sopenharmony_ci// operates hardware components such as dial and switch, corresponding messages are transferred. 2062306a36Sopenharmony_ci// The messages include Hardware metering and MIDI messages as well. 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "motu.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define MSG_FLAG_POS 4 2562306a36Sopenharmony_ci#define MSG_FLAG_TYPE_MASK 0xf8 2662306a36Sopenharmony_ci#define MSG_FLAG_MIDI_MASK 0x01 2762306a36Sopenharmony_ci#define MSG_FLAG_MODEL_SPECIFIC_MASK 0x06 2862306a36Sopenharmony_ci#define MSG_FLAG_8PRE 0x00 2962306a36Sopenharmony_ci#define MSG_FLAG_ULTRALITE 0x04 3062306a36Sopenharmony_ci#define MSG_FLAG_TRAVELER 0x04 3162306a36Sopenharmony_ci#define MSG_FLAG_828MK2 0x04 3262306a36Sopenharmony_ci#define MSG_FLAG_896HD 0x04 3362306a36Sopenharmony_ci#define MSG_FLAG_4PRE 0x05 // MIDI mask is in 8th byte. 3462306a36Sopenharmony_ci#define MSG_FLAG_AUDIOEXPRESS 0x05 // MIDI mask is in 8th byte. 3562306a36Sopenharmony_ci#define MSG_FLAG_TYPE_SHIFT 3 3662306a36Sopenharmony_ci#define MSG_VALUE_POS 5 3762306a36Sopenharmony_ci#define MSG_MIDI_BYTE_POS 6 3862306a36Sopenharmony_ci#define MSG_METER_IDX_POS 7 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci// In 4 pre and Audio express, meter index is in 6th byte. MIDI flag is in 8th byte and MIDI byte 4162306a36Sopenharmony_ci// is in 7th byte. 4262306a36Sopenharmony_ci#define MSG_METER_IDX_POS_4PRE_AE 6 4362306a36Sopenharmony_ci#define MSG_MIDI_BYTE_POS_4PRE_AE 7 4462306a36Sopenharmony_ci#define MSG_FLAG_MIDI_POS_4PRE_AE 8 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cienum register_dsp_msg_type { 4762306a36Sopenharmony_ci // Used for messages with no information. 4862306a36Sopenharmony_ci INVALID = 0x00, 4962306a36Sopenharmony_ci MIXER_SELECT = 0x01, 5062306a36Sopenharmony_ci MIXER_SRC_GAIN = 0x02, 5162306a36Sopenharmony_ci MIXER_SRC_PAN = 0x03, 5262306a36Sopenharmony_ci MIXER_SRC_FLAG = 0x04, 5362306a36Sopenharmony_ci MIXER_OUTPUT_PAIRED_VOLUME = 0x05, 5462306a36Sopenharmony_ci MIXER_OUTPUT_PAIRED_FLAG = 0x06, 5562306a36Sopenharmony_ci MAIN_OUTPUT_PAIRED_VOLUME = 0x07, 5662306a36Sopenharmony_ci HP_OUTPUT_PAIRED_VOLUME = 0x08, 5762306a36Sopenharmony_ci HP_OUTPUT_PAIRED_ASSIGNMENT = 0x09, 5862306a36Sopenharmony_ci // Transferred by all models but the purpose is still unknown. 5962306a36Sopenharmony_ci UNKNOWN_0 = 0x0a, 6062306a36Sopenharmony_ci // Specific to 828mk2, 896hd, Traveler. 6162306a36Sopenharmony_ci UNKNOWN_2 = 0x0c, 6262306a36Sopenharmony_ci // Specific to 828mk2, Traveler, and 896hd (not functional). 6362306a36Sopenharmony_ci LINE_INPUT_BOOST = 0x0d, 6462306a36Sopenharmony_ci // Specific to 828mk2, Traveler, and 896hd (not functional). 6562306a36Sopenharmony_ci LINE_INPUT_NOMINAL_LEVEL = 0x0e, 6662306a36Sopenharmony_ci // Specific to Ultralite, 4 pre, Audio express, and 8 pre (not functional). 6762306a36Sopenharmony_ci INPUT_GAIN_AND_INVERT = 0x15, 6862306a36Sopenharmony_ci // Specific to 4 pre, and Audio express. 6962306a36Sopenharmony_ci INPUT_FLAG = 0x16, 7062306a36Sopenharmony_ci // Specific to 4 pre, and Audio express. 7162306a36Sopenharmony_ci MIXER_SRC_PAIRED_BALANCE = 0x17, 7262306a36Sopenharmony_ci // Specific to 4 pre, and Audio express. 7362306a36Sopenharmony_ci MIXER_SRC_PAIRED_WIDTH = 0x18, 7462306a36Sopenharmony_ci // Transferred by all models. This type of message interposes the series of the other 7562306a36Sopenharmony_ci // messages. The message delivers signal level up to 96.0 kHz. In 828mk2, 896hd, and 7662306a36Sopenharmony_ci // Traveler, one of physical outputs is selected for the message. The selection is done 7762306a36Sopenharmony_ci // by LSB one byte in asynchronous write quadlet transaction to 0x'ffff'f000'0b2c. 7862306a36Sopenharmony_ci METER = 0x1f, 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define EVENT_QUEUE_SIZE 16 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistruct msg_parser { 8462306a36Sopenharmony_ci spinlock_t lock; 8562306a36Sopenharmony_ci struct snd_firewire_motu_register_dsp_meter meter; 8662306a36Sopenharmony_ci bool meter_pos_quirk; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci struct snd_firewire_motu_register_dsp_parameter param; 8962306a36Sopenharmony_ci u8 prev_mixer_src_type; 9062306a36Sopenharmony_ci u8 mixer_ch; 9162306a36Sopenharmony_ci u8 mixer_src_ch; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci u8 input_ch; 9462306a36Sopenharmony_ci u8 prev_msg_type; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci u32 event_queue[EVENT_QUEUE_SIZE]; 9762306a36Sopenharmony_ci unsigned int push_pos; 9862306a36Sopenharmony_ci unsigned int pull_pos; 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciint snd_motu_register_dsp_message_parser_new(struct snd_motu *motu) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct msg_parser *parser; 10462306a36Sopenharmony_ci parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL); 10562306a36Sopenharmony_ci if (!parser) 10662306a36Sopenharmony_ci return -ENOMEM; 10762306a36Sopenharmony_ci spin_lock_init(&parser->lock); 10862306a36Sopenharmony_ci if (motu->spec == &snd_motu_spec_4pre || motu->spec == &snd_motu_spec_audio_express) 10962306a36Sopenharmony_ci parser->meter_pos_quirk = true; 11062306a36Sopenharmony_ci motu->message_parser = parser; 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciint snd_motu_register_dsp_message_parser_init(struct snd_motu *motu) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct msg_parser *parser = motu->message_parser; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci parser->prev_mixer_src_type = INVALID; 11962306a36Sopenharmony_ci parser->mixer_ch = 0xff; 12062306a36Sopenharmony_ci parser->mixer_src_ch = 0xff; 12162306a36Sopenharmony_ci parser->prev_msg_type = INVALID; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci// Rough implementaion of queue without overrun check. 12762306a36Sopenharmony_cistatic void queue_event(struct snd_motu *motu, u8 msg_type, u8 identifier0, u8 identifier1, u8 val) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct msg_parser *parser = motu->message_parser; 13062306a36Sopenharmony_ci unsigned int pos = parser->push_pos; 13162306a36Sopenharmony_ci u32 entry; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (!motu->hwdep || motu->hwdep->used == 0) 13462306a36Sopenharmony_ci return; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci entry = (msg_type << 24) | (identifier0 << 16) | (identifier1 << 8) | val; 13762306a36Sopenharmony_ci parser->event_queue[pos] = entry; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci ++pos; 14062306a36Sopenharmony_ci if (pos >= EVENT_QUEUE_SIZE) 14162306a36Sopenharmony_ci pos = 0; 14262306a36Sopenharmony_ci parser->push_pos = pos; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_civoid snd_motu_register_dsp_message_parser_parse(const struct amdtp_stream *s, 14662306a36Sopenharmony_ci const struct pkt_desc *desc, unsigned int count) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct snd_motu *motu = container_of(s, struct snd_motu, tx_stream); 14962306a36Sopenharmony_ci unsigned int data_block_quadlets = s->data_block_quadlets; 15062306a36Sopenharmony_ci struct msg_parser *parser = motu->message_parser; 15162306a36Sopenharmony_ci bool meter_pos_quirk = parser->meter_pos_quirk; 15262306a36Sopenharmony_ci unsigned int pos = parser->push_pos; 15362306a36Sopenharmony_ci unsigned long flags; 15462306a36Sopenharmony_ci int i; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci spin_lock_irqsave(&parser->lock, flags); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci for (i = 0; i < count; ++i) { 15962306a36Sopenharmony_ci __be32 *buffer = desc->ctx_payload; 16062306a36Sopenharmony_ci unsigned int data_blocks = desc->data_blocks; 16162306a36Sopenharmony_ci int j; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci desc = amdtp_stream_next_packet_desc(s, desc); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci for (j = 0; j < data_blocks; ++j) { 16662306a36Sopenharmony_ci u8 *b = (u8 *)buffer; 16762306a36Sopenharmony_ci u8 msg_type = (b[MSG_FLAG_POS] & MSG_FLAG_TYPE_MASK) >> MSG_FLAG_TYPE_SHIFT; 16862306a36Sopenharmony_ci u8 val = b[MSG_VALUE_POS]; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci buffer += data_block_quadlets; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci switch (msg_type) { 17362306a36Sopenharmony_ci case MIXER_SELECT: 17462306a36Sopenharmony_ci { 17562306a36Sopenharmony_ci u8 mixer_ch = val / 0x20; 17662306a36Sopenharmony_ci if (mixer_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT) { 17762306a36Sopenharmony_ci parser->mixer_src_ch = 0; 17862306a36Sopenharmony_ci parser->mixer_ch = mixer_ch; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci break; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci case MIXER_SRC_GAIN: 18362306a36Sopenharmony_ci case MIXER_SRC_PAN: 18462306a36Sopenharmony_ci case MIXER_SRC_FLAG: 18562306a36Sopenharmony_ci case MIXER_SRC_PAIRED_BALANCE: 18662306a36Sopenharmony_ci case MIXER_SRC_PAIRED_WIDTH: 18762306a36Sopenharmony_ci { 18862306a36Sopenharmony_ci struct snd_firewire_motu_register_dsp_parameter *param = &parser->param; 18962306a36Sopenharmony_ci u8 mixer_ch = parser->mixer_ch; 19062306a36Sopenharmony_ci u8 mixer_src_ch = parser->mixer_src_ch; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (msg_type != parser->prev_mixer_src_type) 19362306a36Sopenharmony_ci mixer_src_ch = 0; 19462306a36Sopenharmony_ci else 19562306a36Sopenharmony_ci ++mixer_src_ch; 19662306a36Sopenharmony_ci parser->prev_mixer_src_type = msg_type; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (mixer_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT && 19962306a36Sopenharmony_ci mixer_src_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_SRC_COUNT) { 20062306a36Sopenharmony_ci u8 mixer_ch = parser->mixer_ch; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci switch (msg_type) { 20362306a36Sopenharmony_ci case MIXER_SRC_GAIN: 20462306a36Sopenharmony_ci if (param->mixer.source[mixer_ch].gain[mixer_src_ch] != val) { 20562306a36Sopenharmony_ci queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val); 20662306a36Sopenharmony_ci param->mixer.source[mixer_ch].gain[mixer_src_ch] = val; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci case MIXER_SRC_PAN: 21062306a36Sopenharmony_ci if (param->mixer.source[mixer_ch].pan[mixer_src_ch] != val) { 21162306a36Sopenharmony_ci queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val); 21262306a36Sopenharmony_ci param->mixer.source[mixer_ch].pan[mixer_src_ch] = val; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci break; 21562306a36Sopenharmony_ci case MIXER_SRC_FLAG: 21662306a36Sopenharmony_ci if (param->mixer.source[mixer_ch].flag[mixer_src_ch] != val) { 21762306a36Sopenharmony_ci queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val); 21862306a36Sopenharmony_ci param->mixer.source[mixer_ch].flag[mixer_src_ch] = val; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci break; 22162306a36Sopenharmony_ci case MIXER_SRC_PAIRED_BALANCE: 22262306a36Sopenharmony_ci if (param->mixer.source[mixer_ch].paired_balance[mixer_src_ch] != val) { 22362306a36Sopenharmony_ci queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val); 22462306a36Sopenharmony_ci param->mixer.source[mixer_ch].paired_balance[mixer_src_ch] = val; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci break; 22762306a36Sopenharmony_ci case MIXER_SRC_PAIRED_WIDTH: 22862306a36Sopenharmony_ci if (param->mixer.source[mixer_ch].paired_width[mixer_src_ch] != val) { 22962306a36Sopenharmony_ci queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val); 23062306a36Sopenharmony_ci param->mixer.source[mixer_ch].paired_width[mixer_src_ch] = val; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci break; 23362306a36Sopenharmony_ci default: 23462306a36Sopenharmony_ci break; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci parser->mixer_src_ch = mixer_src_ch; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci break; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci case MIXER_OUTPUT_PAIRED_VOLUME: 24262306a36Sopenharmony_ci case MIXER_OUTPUT_PAIRED_FLAG: 24362306a36Sopenharmony_ci { 24462306a36Sopenharmony_ci struct snd_firewire_motu_register_dsp_parameter *param = &parser->param; 24562306a36Sopenharmony_ci u8 mixer_ch = parser->mixer_ch; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (mixer_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT) { 24862306a36Sopenharmony_ci switch (msg_type) { 24962306a36Sopenharmony_ci case MIXER_OUTPUT_PAIRED_VOLUME: 25062306a36Sopenharmony_ci if (param->mixer.output.paired_volume[mixer_ch] != val) { 25162306a36Sopenharmony_ci queue_event(motu, msg_type, mixer_ch, 0, val); 25262306a36Sopenharmony_ci param->mixer.output.paired_volume[mixer_ch] = val; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci case MIXER_OUTPUT_PAIRED_FLAG: 25662306a36Sopenharmony_ci if (param->mixer.output.paired_flag[mixer_ch] != val) { 25762306a36Sopenharmony_ci queue_event(motu, msg_type, mixer_ch, 0, val); 25862306a36Sopenharmony_ci param->mixer.output.paired_flag[mixer_ch] = val; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci default: 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci case MAIN_OUTPUT_PAIRED_VOLUME: 26862306a36Sopenharmony_ci if (parser->param.output.main_paired_volume != val) { 26962306a36Sopenharmony_ci queue_event(motu, msg_type, 0, 0, val); 27062306a36Sopenharmony_ci parser->param.output.main_paired_volume = val; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci break; 27362306a36Sopenharmony_ci case HP_OUTPUT_PAIRED_VOLUME: 27462306a36Sopenharmony_ci if (parser->param.output.hp_paired_volume != val) { 27562306a36Sopenharmony_ci queue_event(motu, msg_type, 0, 0, val); 27662306a36Sopenharmony_ci parser->param.output.hp_paired_volume = val; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci case HP_OUTPUT_PAIRED_ASSIGNMENT: 28062306a36Sopenharmony_ci if (parser->param.output.hp_paired_assignment != val) { 28162306a36Sopenharmony_ci queue_event(motu, msg_type, 0, 0, val); 28262306a36Sopenharmony_ci parser->param.output.hp_paired_assignment = val; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case LINE_INPUT_BOOST: 28662306a36Sopenharmony_ci if (parser->param.line_input.boost_flag != val) { 28762306a36Sopenharmony_ci queue_event(motu, msg_type, 0, 0, val); 28862306a36Sopenharmony_ci parser->param.line_input.boost_flag = val; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci break; 29162306a36Sopenharmony_ci case LINE_INPUT_NOMINAL_LEVEL: 29262306a36Sopenharmony_ci if (parser->param.line_input.nominal_level_flag != val) { 29362306a36Sopenharmony_ci queue_event(motu, msg_type, 0, 0, val); 29462306a36Sopenharmony_ci parser->param.line_input.nominal_level_flag = val; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci case INPUT_GAIN_AND_INVERT: 29862306a36Sopenharmony_ci case INPUT_FLAG: 29962306a36Sopenharmony_ci { 30062306a36Sopenharmony_ci struct snd_firewire_motu_register_dsp_parameter *param = &parser->param; 30162306a36Sopenharmony_ci u8 input_ch = parser->input_ch; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (parser->prev_msg_type != msg_type) 30462306a36Sopenharmony_ci input_ch = 0; 30562306a36Sopenharmony_ci else 30662306a36Sopenharmony_ci ++input_ch; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (input_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_INPUT_COUNT) { 30962306a36Sopenharmony_ci switch (msg_type) { 31062306a36Sopenharmony_ci case INPUT_GAIN_AND_INVERT: 31162306a36Sopenharmony_ci if (param->input.gain_and_invert[input_ch] != val) { 31262306a36Sopenharmony_ci queue_event(motu, msg_type, input_ch, 0, val); 31362306a36Sopenharmony_ci param->input.gain_and_invert[input_ch] = val; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci case INPUT_FLAG: 31762306a36Sopenharmony_ci if (param->input.flag[input_ch] != val) { 31862306a36Sopenharmony_ci queue_event(motu, msg_type, input_ch, 0, val); 31962306a36Sopenharmony_ci param->input.flag[input_ch] = val; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci default: 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci parser->input_ch = input_ch; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci case UNKNOWN_0: 33062306a36Sopenharmony_ci case UNKNOWN_2: 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci case METER: 33362306a36Sopenharmony_ci { 33462306a36Sopenharmony_ci u8 pos; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (!meter_pos_quirk) 33762306a36Sopenharmony_ci pos = b[MSG_METER_IDX_POS]; 33862306a36Sopenharmony_ci else 33962306a36Sopenharmony_ci pos = b[MSG_METER_IDX_POS_4PRE_AE]; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (pos < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_INPUT_COUNT) { 34262306a36Sopenharmony_ci parser->meter.data[pos] = val; 34362306a36Sopenharmony_ci } else if (pos >= 0x80) { 34462306a36Sopenharmony_ci pos -= (0x80 - SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_INPUT_COUNT); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (pos < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_COUNT) 34762306a36Sopenharmony_ci parser->meter.data[pos] = val; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci // The message for meter is interruptible to the series of other 35162306a36Sopenharmony_ci // types of messages. Don't cache it. 35262306a36Sopenharmony_ci fallthrough; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci case INVALID: 35562306a36Sopenharmony_ci default: 35662306a36Sopenharmony_ci // Don't cache it. 35762306a36Sopenharmony_ci continue; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci parser->prev_msg_type = msg_type; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (pos != parser->push_pos) 36562306a36Sopenharmony_ci wake_up(&motu->hwdep_wait); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci spin_unlock_irqrestore(&parser->lock, flags); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_civoid snd_motu_register_dsp_message_parser_copy_meter(struct snd_motu *motu, 37162306a36Sopenharmony_ci struct snd_firewire_motu_register_dsp_meter *meter) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct msg_parser *parser = motu->message_parser; 37462306a36Sopenharmony_ci unsigned long flags; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci spin_lock_irqsave(&parser->lock, flags); 37762306a36Sopenharmony_ci memcpy(meter, &parser->meter, sizeof(*meter)); 37862306a36Sopenharmony_ci spin_unlock_irqrestore(&parser->lock, flags); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_civoid snd_motu_register_dsp_message_parser_copy_parameter(struct snd_motu *motu, 38262306a36Sopenharmony_ci struct snd_firewire_motu_register_dsp_parameter *param) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct msg_parser *parser = motu->message_parser; 38562306a36Sopenharmony_ci unsigned long flags; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci spin_lock_irqsave(&parser->lock, flags); 38862306a36Sopenharmony_ci memcpy(param, &parser->param, sizeof(*param)); 38962306a36Sopenharmony_ci spin_unlock_irqrestore(&parser->lock, flags); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ciunsigned int snd_motu_register_dsp_message_parser_count_event(struct snd_motu *motu) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct msg_parser *parser = motu->message_parser; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (parser->pull_pos > parser->push_pos) 39762306a36Sopenharmony_ci return EVENT_QUEUE_SIZE - parser->pull_pos + parser->push_pos; 39862306a36Sopenharmony_ci else 39962306a36Sopenharmony_ci return parser->push_pos - parser->pull_pos; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cibool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32 *event) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct msg_parser *parser = motu->message_parser; 40562306a36Sopenharmony_ci unsigned int pos = parser->pull_pos; 40662306a36Sopenharmony_ci unsigned long flags; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (pos == parser->push_pos) 40962306a36Sopenharmony_ci return false; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci spin_lock_irqsave(&parser->lock, flags); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci *event = parser->event_queue[pos]; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci ++pos; 41662306a36Sopenharmony_ci if (pos >= EVENT_QUEUE_SIZE) 41762306a36Sopenharmony_ci pos = 0; 41862306a36Sopenharmony_ci parser->pull_pos = pos; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci spin_unlock_irqrestore(&parser->lock, flags); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return true; 42362306a36Sopenharmony_ci} 424