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}