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