cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

motu-command-dsp-message-parser.c (4482B)


      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(struct snd_motu *motu, const struct pkt_desc *descs,
     84					unsigned int desc_count, unsigned int data_block_quadlets)
     85{
     86	struct msg_parser *parser = motu->message_parser;
     87	unsigned int interval = parser->interval;
     88	unsigned long flags;
     89	int i;
     90
     91	spin_lock_irqsave(&parser->lock, flags);
     92
     93	for (i = 0; i < desc_count; ++i) {
     94		const struct pkt_desc *desc = descs + i;
     95		__be32 *buffer = desc->ctx_payload;
     96		unsigned int data_blocks = desc->data_blocks;
     97		int j;
     98
     99		for (j = 0; j < data_blocks; ++j) {
    100			u8 *b = (u8 *)buffer;
    101			buffer += data_block_quadlets;
    102
    103			switch (parser->state) {
    104			case INITIALIZED:
    105			{
    106				u8 fragment = b[FRAGMENT_POS];
    107
    108				if (fragment > 0) {
    109					parser->value = fragment;
    110					parser->message_count = 1;
    111					parser->state = FRAGMENT_DETECTED;
    112				}
    113				break;
    114			}
    115			case FRAGMENT_DETECTED:
    116			{
    117				if (parser->message_count % interval == 0) {
    118					u8 fragment = b[FRAGMENT_POS];
    119
    120					parser->value >>= 8;
    121					parser->value |= (u64)fragment << 56;
    122
    123					if (parser->value == VALUES_AT_IMAGE_END) {
    124						parser->state = AVAILABLE;
    125						parser->fragment_pos = 0;
    126						parser->value_index = 0;
    127						parser->message_count = 0;
    128					}
    129				}
    130				++parser->message_count;
    131				break;
    132			}
    133			case AVAILABLE:
    134			default:
    135			{
    136				if (parser->message_count % interval == 0) {
    137					u8 fragment = b[FRAGMENT_POS];
    138
    139					parser->value >>= 8;
    140					parser->value |= (u64)fragment << 56;
    141					++parser->fragment_pos;
    142
    143					if (parser->fragment_pos == 4) {
    144						// Skip the last two quadlets since they could be
    145						// invalid value (0xffffffff) as floating point
    146						// number.
    147						if (parser->value_index <
    148						    SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT - 2) {
    149							u32 val = (u32)(parser->value >> 32);
    150							parser->meter.data[parser->value_index] = val;
    151						}
    152						++parser->value_index;
    153						parser->fragment_pos = 0;
    154					}
    155
    156					if (parser->value == VALUES_AT_IMAGE_END) {
    157						parser->value_index = 0;
    158						parser->fragment_pos = 0;
    159						parser->message_count = 0;
    160					}
    161				}
    162				++parser->message_count;
    163				break;
    164			}
    165			}
    166		}
    167	}
    168
    169	spin_unlock_irqrestore(&parser->lock, flags);
    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	unsigned long flags;
    177
    178	spin_lock_irqsave(&parser->lock, flags);
    179	memcpy(meter, &parser->meter, sizeof(*meter));
    180	spin_unlock_irqrestore(&parser->lock, flags);
    181}