brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · 5d8a86a Raw
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