File Index
Files and directories
Sign in
FILE

motu-command-dsp-message-parser.c

File preview with syntax highlighting.

linux-6.19.14/sound/firewire/motu/motu-command-dsp-message-parser.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2//
  3// motu-command-dsp-message-parser.c - a part of driver for MOTU FireWire series
  4//
  5// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>
  6
  7// Below models allow software to configure their DSP function by command transferred in
  8// 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 mk3
 13//  * Track 16
 14//
 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			6
 77#define MIDI_BYTE_POS			7
 78#define MIDI_FLAG_POS			8
 79// One value of hardware meter consists of 4 messages.
 80#define FRAGMENTS_PER_VALUE		4
 81#define VALUES_AT_IMAGE_END		0xffffffffffffffff
 82
 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	int i;
 91
 92	guard(spinlock_irqsave)(&parser->lock);
 93
 94	for (i = 0; i < count; ++i) {
 95		__be32 *buffer = desc->ctx_payload;
 96		unsigned int data_blocks = desc->data_blocks;
 97		int j;
 98
 99		desc = amdtp_stream_next_packet_desc(s, desc);
100
101		for (j = 0; j < data_blocks; ++j) {
102			u8 *b = (u8 *)buffer;
103			buffer += data_block_quadlets;
104
105			switch (parser->state) {
106			case INITIALIZED:
107			{
108				u8 fragment = b[FRAGMENT_POS];
109
110				if (fragment > 0) {
111					parser->value = fragment;
112					parser->message_count = 1;
113					parser->state = FRAGMENT_DETECTED;
114				}
115				break;
116			}
117			case FRAGMENT_DETECTED:
118			{
119				if (parser->message_count % interval == 0) {
120					u8 fragment = b[FRAGMENT_POS];
121
122					parser->value >>= 8;
123					parser->value |= (u64)fragment << 56;
124
125					if (parser->value == VALUES_AT_IMAGE_END) {
126						parser->state = AVAILABLE;
127						parser->fragment_pos = 0;
128						parser->value_index = 0;
129						parser->message_count = 0;
130					}
131				}
132				++parser->message_count;
133				break;
134			}
135			case AVAILABLE:
136			default:
137			{
138				if (parser->message_count % interval == 0) {
139					u8 fragment = b[FRAGMENT_POS];
140
141					parser->value >>= 8;
142					parser->value |= (u64)fragment << 56;
143					++parser->fragment_pos;
144
145					if (parser->fragment_pos == 4) {
146						// Skip the last two quadlets since they could be
147						// invalid value (0xffffffff) as floating point
148						// number.
149						if (parser->value_index <
150						    SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT - 2) {
151							u32 val = (u32)(parser->value >> 32);
152							parser->meter.data[parser->value_index] = val;
153						}
154						++parser->value_index;
155						parser->fragment_pos = 0;
156					}
157
158					if (parser->value == VALUES_AT_IMAGE_END) {
159						parser->value_index = 0;
160						parser->fragment_pos = 0;
161						parser->message_count = 0;
162					}
163				}
164				++parser->message_count;
165				break;
166			}
167			}
168		}
169	}
170}
171
172void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,
173					struct snd_firewire_motu_command_dsp_meter *meter)
174{
175	struct msg_parser *parser = motu->message_parser;
176
177	guard(spinlock_irqsave)(&parser->lock);
178	memcpy(meter, &parser->meter, sizeof(*meter));
179}
~/ Read-only file preview.