Path: blob/master/sound/firewire/motu/motu-command-dsp-message-parser.c
26424 views
// SPDX-License-Identifier: GPL-2.0-only1//2// motu-command-dsp-message-parser.c - a part of driver for MOTU FireWire series3//4// Copyright (c) 2021 Takashi Sakamoto <[email protected]>56// Below models allow software to configure their DSP function by command transferred in7// asynchronous transaction:8// * 828 mk3 (FireWire only and Hybrid)9// * 896 mk3 (FireWire only and Hybrid)10// * Ultralite mk3 (FireWire only and Hybrid)11// * Traveler mk312// * Track 1613//14// Isochronous packets from the above models includes messages to report state of hardware meter.1516#include "motu.h"1718enum msg_parser_state {19INITIALIZED,20FRAGMENT_DETECTED,21AVAILABLE,22};2324struct msg_parser {25spinlock_t lock;26enum msg_parser_state state;27unsigned int interval;28unsigned int message_count;29unsigned int fragment_pos;30unsigned int value_index;31u64 value;32struct snd_firewire_motu_command_dsp_meter meter;33};3435int snd_motu_command_dsp_message_parser_new(struct snd_motu *motu)36{37struct msg_parser *parser;3839parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);40if (!parser)41return -ENOMEM;42spin_lock_init(&parser->lock);43motu->message_parser = parser;4445return 0;46}4748int snd_motu_command_dsp_message_parser_init(struct snd_motu *motu, enum cip_sfc sfc)49{50struct msg_parser *parser = motu->message_parser;5152parser->state = INITIALIZED;5354// All of data blocks don't have messages with meaningful information.55switch (sfc) {56case CIP_SFC_176400:57case CIP_SFC_192000:58parser->interval = 4;59break;60case CIP_SFC_88200:61case CIP_SFC_96000:62parser->interval = 2;63break;64case CIP_SFC_32000:65case CIP_SFC_44100:66case CIP_SFC_48000:67default:68parser->interval = 1;69break;70}7172return 0;73}7475#define FRAGMENT_POS 676#define MIDI_BYTE_POS 777#define MIDI_FLAG_POS 878// One value of hardware meter consists of 4 messages.79#define FRAGMENTS_PER_VALUE 480#define VALUES_AT_IMAGE_END 0xffffffffffffffff8182void snd_motu_command_dsp_message_parser_parse(const struct amdtp_stream *s,83const struct pkt_desc *desc, unsigned int count)84{85struct snd_motu *motu = container_of(s, struct snd_motu, tx_stream);86unsigned int data_block_quadlets = s->data_block_quadlets;87struct msg_parser *parser = motu->message_parser;88unsigned int interval = parser->interval;89unsigned long flags;90int i;9192spin_lock_irqsave(&parser->lock, flags);9394for (i = 0; i < count; ++i) {95__be32 *buffer = desc->ctx_payload;96unsigned int data_blocks = desc->data_blocks;97int j;9899desc = amdtp_stream_next_packet_desc(s, desc);100101for (j = 0; j < data_blocks; ++j) {102u8 *b = (u8 *)buffer;103buffer += data_block_quadlets;104105switch (parser->state) {106case INITIALIZED:107{108u8 fragment = b[FRAGMENT_POS];109110if (fragment > 0) {111parser->value = fragment;112parser->message_count = 1;113parser->state = FRAGMENT_DETECTED;114}115break;116}117case FRAGMENT_DETECTED:118{119if (parser->message_count % interval == 0) {120u8 fragment = b[FRAGMENT_POS];121122parser->value >>= 8;123parser->value |= (u64)fragment << 56;124125if (parser->value == VALUES_AT_IMAGE_END) {126parser->state = AVAILABLE;127parser->fragment_pos = 0;128parser->value_index = 0;129parser->message_count = 0;130}131}132++parser->message_count;133break;134}135case AVAILABLE:136default:137{138if (parser->message_count % interval == 0) {139u8 fragment = b[FRAGMENT_POS];140141parser->value >>= 8;142parser->value |= (u64)fragment << 56;143++parser->fragment_pos;144145if (parser->fragment_pos == 4) {146// Skip the last two quadlets since they could be147// invalid value (0xffffffff) as floating point148// number.149if (parser->value_index <150SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT - 2) {151u32 val = (u32)(parser->value >> 32);152parser->meter.data[parser->value_index] = val;153}154++parser->value_index;155parser->fragment_pos = 0;156}157158if (parser->value == VALUES_AT_IMAGE_END) {159parser->value_index = 0;160parser->fragment_pos = 0;161parser->message_count = 0;162}163}164++parser->message_count;165break;166}167}168}169}170171spin_unlock_irqrestore(&parser->lock, flags);172}173174void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,175struct snd_firewire_motu_command_dsp_meter *meter)176{177struct msg_parser *parser = motu->message_parser;178unsigned long flags;179180spin_lock_irqsave(&parser->lock, flags);181memcpy(meter, &parser->meter, sizeof(*meter));182spin_unlock_irqrestore(&parser->lock, flags);183}184185186