Path: blob/master/sound/firewire/motu/motu-command-dsp-message-parser.c
29266 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;89int i;9091guard(spinlock_irqsave)(&parser->lock);9293for (i = 0; i < count; ++i) {94__be32 *buffer = desc->ctx_payload;95unsigned int data_blocks = desc->data_blocks;96int j;9798desc = amdtp_stream_next_packet_desc(s, desc);99100for (j = 0; j < data_blocks; ++j) {101u8 *b = (u8 *)buffer;102buffer += data_block_quadlets;103104switch (parser->state) {105case INITIALIZED:106{107u8 fragment = b[FRAGMENT_POS];108109if (fragment > 0) {110parser->value = fragment;111parser->message_count = 1;112parser->state = FRAGMENT_DETECTED;113}114break;115}116case FRAGMENT_DETECTED:117{118if (parser->message_count % interval == 0) {119u8 fragment = b[FRAGMENT_POS];120121parser->value >>= 8;122parser->value |= (u64)fragment << 56;123124if (parser->value == VALUES_AT_IMAGE_END) {125parser->state = AVAILABLE;126parser->fragment_pos = 0;127parser->value_index = 0;128parser->message_count = 0;129}130}131++parser->message_count;132break;133}134case AVAILABLE:135default:136{137if (parser->message_count % interval == 0) {138u8 fragment = b[FRAGMENT_POS];139140parser->value >>= 8;141parser->value |= (u64)fragment << 56;142++parser->fragment_pos;143144if (parser->fragment_pos == 4) {145// Skip the last two quadlets since they could be146// invalid value (0xffffffff) as floating point147// number.148if (parser->value_index <149SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT - 2) {150u32 val = (u32)(parser->value >> 32);151parser->meter.data[parser->value_index] = val;152}153++parser->value_index;154parser->fragment_pos = 0;155}156157if (parser->value == VALUES_AT_IMAGE_END) {158parser->value_index = 0;159parser->fragment_pos = 0;160parser->message_count = 0;161}162}163++parser->message_count;164break;165}166}167}168}169}170171void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,172struct snd_firewire_motu_command_dsp_meter *meter)173{174struct msg_parser *parser = motu->message_parser;175176guard(spinlock_irqsave)(&parser->lock);177memcpy(meter, &parser->meter, sizeof(*meter));178}179180181