185 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// motu-command-dsp-message-parser.c - a part of driver for MOTU FireWire series4//5// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>6 7// Below models allow software to configure their DSP function by command transferred in8// asynchronous transaction:9// * 828 mk3 (FireWire only and Hybrid)10// * 896 mk3 (FireWire only and Hybrid)11// * Ultralite mk3 (FireWire only and Hybrid)12// * Traveler mk313// * Track 1614//15// Isochronous packets from the above models includes messages to report state of hardware meter.16 17#include "motu.h"18 19enum msg_parser_state {20 INITIALIZED,21 FRAGMENT_DETECTED,22 AVAILABLE,23};24 25struct msg_parser {26 spinlock_t lock;27 enum msg_parser_state state;28 unsigned int interval;29 unsigned int message_count;30 unsigned int fragment_pos;31 unsigned int value_index;32 u64 value;33 struct snd_firewire_motu_command_dsp_meter meter;34};35 36int snd_motu_command_dsp_message_parser_new(struct snd_motu *motu)37{38 struct msg_parser *parser;39 40 parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);41 if (!parser)42 return -ENOMEM;43 spin_lock_init(&parser->lock);44 motu->message_parser = parser;45 46 return 0;47}48 49int snd_motu_command_dsp_message_parser_init(struct snd_motu *motu, enum cip_sfc sfc)50{51 struct msg_parser *parser = motu->message_parser;52 53 parser->state = INITIALIZED;54 55 // All of data blocks don't have messages with meaningful information.56 switch (sfc) {57 case CIP_SFC_176400:58 case CIP_SFC_192000:59 parser->interval = 4;60 break;61 case CIP_SFC_88200:62 case CIP_SFC_96000:63 parser->interval = 2;64 break;65 case CIP_SFC_32000:66 case CIP_SFC_44100:67 case CIP_SFC_48000:68 default:69 parser->interval = 1;70 break;71 }72 73 return 0;74}75 76#define FRAGMENT_POS 677#define MIDI_BYTE_POS 778#define MIDI_FLAG_POS 879// One value of hardware meter consists of 4 messages.80#define FRAGMENTS_PER_VALUE 481#define VALUES_AT_IMAGE_END 0xffffffffffffffff82 83void snd_motu_command_dsp_message_parser_parse(const struct amdtp_stream *s,84 const struct pkt_desc *desc, unsigned int count)85{86 struct snd_motu *motu = container_of(s, struct snd_motu, tx_stream);87 unsigned int data_block_quadlets = s->data_block_quadlets;88 struct msg_parser *parser = motu->message_parser;89 unsigned int interval = parser->interval;90 unsigned long flags;91 int i;92 93 spin_lock_irqsave(&parser->lock, flags);94 95 for (i = 0; i < count; ++i) {96 __be32 *buffer = desc->ctx_payload;97 unsigned int data_blocks = desc->data_blocks;98 int j;99 100 desc = amdtp_stream_next_packet_desc(s, desc);101 102 for (j = 0; j < data_blocks; ++j) {103 u8 *b = (u8 *)buffer;104 buffer += data_block_quadlets;105 106 switch (parser->state) {107 case INITIALIZED:108 {109 u8 fragment = b[FRAGMENT_POS];110 111 if (fragment > 0) {112 parser->value = fragment;113 parser->message_count = 1;114 parser->state = FRAGMENT_DETECTED;115 }116 break;117 }118 case FRAGMENT_DETECTED:119 {120 if (parser->message_count % interval == 0) {121 u8 fragment = b[FRAGMENT_POS];122 123 parser->value >>= 8;124 parser->value |= (u64)fragment << 56;125 126 if (parser->value == VALUES_AT_IMAGE_END) {127 parser->state = AVAILABLE;128 parser->fragment_pos = 0;129 parser->value_index = 0;130 parser->message_count = 0;131 }132 }133 ++parser->message_count;134 break;135 }136 case AVAILABLE:137 default:138 {139 if (parser->message_count % interval == 0) {140 u8 fragment = b[FRAGMENT_POS];141 142 parser->value >>= 8;143 parser->value |= (u64)fragment << 56;144 ++parser->fragment_pos;145 146 if (parser->fragment_pos == 4) {147 // Skip the last two quadlets since they could be148 // invalid value (0xffffffff) as floating point149 // number.150 if (parser->value_index <151 SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT - 2) {152 u32 val = (u32)(parser->value >> 32);153 parser->meter.data[parser->value_index] = val;154 }155 ++parser->value_index;156 parser->fragment_pos = 0;157 }158 159 if (parser->value == VALUES_AT_IMAGE_END) {160 parser->value_index = 0;161 parser->fragment_pos = 0;162 parser->message_count = 0;163 }164 }165 ++parser->message_count;166 break;167 }168 }169 }170 }171 172 spin_unlock_irqrestore(&parser->lock, flags);173}174 175void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,176 struct snd_firewire_motu_command_dsp_meter *meter)177{178 struct msg_parser *parser = motu->message_parser;179 unsigned long flags;180 181 spin_lock_irqsave(&parser->lock, flags);182 memcpy(meter, &parser->meter, sizeof(*meter));183 spin_unlock_irqrestore(&parser->lock, flags);184}185