Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 //
0003 // motu-command-dsp-message-parser.c - a part of driver for MOTU FireWire series
0004 //
0005 // Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>
0006 
0007 // Below models allow software to configure their DSP function by command transferred in
0008 // asynchronous transaction:
0009 //  * 828 mk3 (FireWire only and Hybrid)
0010 //  * 896 mk3 (FireWire only and Hybrid)
0011 //  * Ultralite mk3 (FireWire only and Hybrid)
0012 //  * Traveler mk3
0013 //  * Track 16
0014 //
0015 // Isochronous packets from the above models includes messages to report state of hardware meter.
0016 
0017 #include "motu.h"
0018 
0019 enum msg_parser_state {
0020     INITIALIZED,
0021     FRAGMENT_DETECTED,
0022     AVAILABLE,
0023 };
0024 
0025 struct msg_parser {
0026     spinlock_t lock;
0027     enum msg_parser_state state;
0028     unsigned int interval;
0029     unsigned int message_count;
0030     unsigned int fragment_pos;
0031     unsigned int value_index;
0032     u64 value;
0033     struct snd_firewire_motu_command_dsp_meter meter;
0034 };
0035 
0036 int snd_motu_command_dsp_message_parser_new(struct snd_motu *motu)
0037 {
0038     struct msg_parser *parser;
0039 
0040     parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);
0041     if (!parser)
0042         return -ENOMEM;
0043     spin_lock_init(&parser->lock);
0044     motu->message_parser = parser;
0045 
0046     return 0;
0047 }
0048 
0049 int snd_motu_command_dsp_message_parser_init(struct snd_motu *motu, enum cip_sfc sfc)
0050 {
0051     struct msg_parser *parser = motu->message_parser;
0052 
0053     parser->state = INITIALIZED;
0054 
0055     // All of data blocks don't have messages with meaningful information.
0056     switch (sfc) {
0057     case CIP_SFC_176400:
0058     case CIP_SFC_192000:
0059         parser->interval = 4;
0060         break;
0061     case CIP_SFC_88200:
0062     case CIP_SFC_96000:
0063         parser->interval = 2;
0064         break;
0065     case CIP_SFC_32000:
0066     case CIP_SFC_44100:
0067     case CIP_SFC_48000:
0068     default:
0069         parser->interval = 1;
0070         break;
0071     }
0072 
0073     return 0;
0074 }
0075 
0076 #define FRAGMENT_POS            6
0077 #define MIDI_BYTE_POS           7
0078 #define MIDI_FLAG_POS           8
0079 // One value of hardware meter consists of 4 messages.
0080 #define FRAGMENTS_PER_VALUE     4
0081 #define VALUES_AT_IMAGE_END     0xffffffffffffffff
0082 
0083 void snd_motu_command_dsp_message_parser_parse(struct snd_motu *motu, const struct pkt_desc *descs,
0084                     unsigned int desc_count, unsigned int data_block_quadlets)
0085 {
0086     struct msg_parser *parser = motu->message_parser;
0087     unsigned int interval = parser->interval;
0088     unsigned long flags;
0089     int i;
0090 
0091     spin_lock_irqsave(&parser->lock, flags);
0092 
0093     for (i = 0; i < desc_count; ++i) {
0094         const struct pkt_desc *desc = descs + i;
0095         __be32 *buffer = desc->ctx_payload;
0096         unsigned int data_blocks = desc->data_blocks;
0097         int j;
0098 
0099         for (j = 0; j < data_blocks; ++j) {
0100             u8 *b = (u8 *)buffer;
0101             buffer += data_block_quadlets;
0102 
0103             switch (parser->state) {
0104             case INITIALIZED:
0105             {
0106                 u8 fragment = b[FRAGMENT_POS];
0107 
0108                 if (fragment > 0) {
0109                     parser->value = fragment;
0110                     parser->message_count = 1;
0111                     parser->state = FRAGMENT_DETECTED;
0112                 }
0113                 break;
0114             }
0115             case FRAGMENT_DETECTED:
0116             {
0117                 if (parser->message_count % interval == 0) {
0118                     u8 fragment = b[FRAGMENT_POS];
0119 
0120                     parser->value >>= 8;
0121                     parser->value |= (u64)fragment << 56;
0122 
0123                     if (parser->value == VALUES_AT_IMAGE_END) {
0124                         parser->state = AVAILABLE;
0125                         parser->fragment_pos = 0;
0126                         parser->value_index = 0;
0127                         parser->message_count = 0;
0128                     }
0129                 }
0130                 ++parser->message_count;
0131                 break;
0132             }
0133             case AVAILABLE:
0134             default:
0135             {
0136                 if (parser->message_count % interval == 0) {
0137                     u8 fragment = b[FRAGMENT_POS];
0138 
0139                     parser->value >>= 8;
0140                     parser->value |= (u64)fragment << 56;
0141                     ++parser->fragment_pos;
0142 
0143                     if (parser->fragment_pos == 4) {
0144                         // Skip the last two quadlets since they could be
0145                         // invalid value (0xffffffff) as floating point
0146                         // number.
0147                         if (parser->value_index <
0148                             SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT - 2) {
0149                             u32 val = (u32)(parser->value >> 32);
0150                             parser->meter.data[parser->value_index] = val;
0151                         }
0152                         ++parser->value_index;
0153                         parser->fragment_pos = 0;
0154                     }
0155 
0156                     if (parser->value == VALUES_AT_IMAGE_END) {
0157                         parser->value_index = 0;
0158                         parser->fragment_pos = 0;
0159                         parser->message_count = 0;
0160                     }
0161                 }
0162                 ++parser->message_count;
0163                 break;
0164             }
0165             }
0166         }
0167     }
0168 
0169     spin_unlock_irqrestore(&parser->lock, flags);
0170 }
0171 
0172 void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,
0173                     struct snd_firewire_motu_command_dsp_meter *meter)
0174 {
0175     struct msg_parser *parser = motu->message_parser;
0176     unsigned long flags;
0177 
0178     spin_lock_irqsave(&parser->lock, flags);
0179     memcpy(meter, &parser->meter, sizeof(*meter));
0180     spin_unlock_irqrestore(&parser->lock, flags);
0181 }