root/sound/firewire/dice/dice-extension.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_transaction
  2. read_stream_entries
  3. detect_stream_formats
  4. snd_dice_detect_extension_formats

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * dice-extension.c - a part of driver for DICE based devices
   4  *
   5  * Copyright (c) 2018 Takashi Sakamoto
   6  */
   7 
   8 #include "dice.h"
   9 
  10 /* For TCD2210/2220, TCAT defines extension of application protocol. */
  11 
  12 #define DICE_EXT_APP_SPACE              0xffffe0200000uLL
  13 
  14 #define DICE_EXT_APP_CAPS_OFFSET        0x00
  15 #define DICE_EXT_APP_CAPS_SIZE          0x04
  16 #define DICE_EXT_APP_CMD_OFFSET         0x08
  17 #define DICE_EXT_APP_CMD_SIZE           0x0c
  18 #define DICE_EXT_APP_MIXER_OFFSET       0x10
  19 #define DICE_EXT_APP_MIXER_SIZE         0x14
  20 #define DICE_EXT_APP_PEAK_OFFSET        0x18
  21 #define DICE_EXT_APP_PEAK_SIZE          0x1c
  22 #define DICE_EXT_APP_ROUTER_OFFSET      0x20
  23 #define DICE_EXT_APP_ROUTER_SIZE        0x24
  24 #define DICE_EXT_APP_STREAM_OFFSET      0x28
  25 #define DICE_EXT_APP_STREAM_SIZE        0x2c
  26 #define DICE_EXT_APP_CURRENT_OFFSET     0x30
  27 #define DICE_EXT_APP_CURRENT_SIZE       0x34
  28 #define DICE_EXT_APP_STANDALONE_OFFSET  0x38
  29 #define DICE_EXT_APP_STANDALONE_SIZE    0x3c
  30 #define DICE_EXT_APP_APPLICATION_OFFSET 0x40
  31 #define DICE_EXT_APP_APPLICATION_SIZE   0x44
  32 
  33 #define EXT_APP_STREAM_TX_NUMBER        0x0000
  34 #define EXT_APP_STREAM_RX_NUMBER        0x0004
  35 #define EXT_APP_STREAM_ENTRIES          0x0008
  36 #define EXT_APP_STREAM_ENTRY_SIZE       0x010c
  37 #define  EXT_APP_NUMBER_AUDIO           0x0000
  38 #define  EXT_APP_NUMBER_MIDI            0x0004
  39 #define  EXT_APP_NAMES                  0x0008
  40 #define   EXT_APP_NAMES_SIZE            256
  41 #define  EXT_APP_AC3                    0x0108
  42 
  43 #define EXT_APP_CONFIG_LOW_ROUTER       0x0000
  44 #define EXT_APP_CONFIG_LOW_STREAM       0x1000
  45 #define EXT_APP_CONFIG_MIDDLE_ROUTER    0x2000
  46 #define EXT_APP_CONFIG_MIDDLE_STREAM    0x3000
  47 #define EXT_APP_CONFIG_HIGH_ROUTER      0x4000
  48 #define EXT_APP_CONFIG_HIGH_STREAM      0x5000
  49 
  50 static inline int read_transaction(struct snd_dice *dice, u64 section_addr,
  51                                    u32 offset, void *buf, size_t len)
  52 {
  53         return snd_fw_transaction(dice->unit,
  54                                   len == 4 ? TCODE_READ_QUADLET_REQUEST :
  55                                              TCODE_READ_BLOCK_REQUEST,
  56                                   section_addr + offset, buf, len, 0);
  57 }
  58 
  59 static int read_stream_entries(struct snd_dice *dice, u64 section_addr,
  60                                u32 base_offset, unsigned int stream_count,
  61                                unsigned int mode,
  62                                unsigned int pcm_channels[MAX_STREAMS][3],
  63                                unsigned int midi_ports[MAX_STREAMS])
  64 {
  65         u32 entry_offset;
  66         __be32 reg[2];
  67         int err;
  68         int i;
  69 
  70         for (i = 0; i < stream_count; ++i) {
  71                 entry_offset = base_offset + i * EXT_APP_STREAM_ENTRY_SIZE;
  72                 err = read_transaction(dice, section_addr,
  73                                     entry_offset + EXT_APP_NUMBER_AUDIO,
  74                                     reg, sizeof(reg));
  75                 if (err < 0)
  76                         return err;
  77                 pcm_channels[i][mode] = be32_to_cpu(reg[0]);
  78                 midi_ports[i] = max(midi_ports[i], be32_to_cpu(reg[1]));
  79         }
  80 
  81         return 0;
  82 }
  83 
  84 static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)
  85 {
  86         u32 base_offset;
  87         __be32 reg[2];
  88         unsigned int stream_count;
  89         int mode;
  90         int err = 0;
  91 
  92         for (mode = 0; mode < SND_DICE_RATE_MODE_COUNT; ++mode) {
  93                 unsigned int cap;
  94 
  95                 /*
  96                  * Some models report stream formats at highest mode, however
  97                  * they don't support the mode. Check clock capabilities.
  98                  */
  99                 if (mode == 2) {
 100                         cap = CLOCK_CAP_RATE_176400 | CLOCK_CAP_RATE_192000;
 101                 } else if (mode == 1) {
 102                         cap = CLOCK_CAP_RATE_88200 | CLOCK_CAP_RATE_96000;
 103                 } else {
 104                         cap = CLOCK_CAP_RATE_32000 | CLOCK_CAP_RATE_44100 |
 105                               CLOCK_CAP_RATE_48000;
 106                 }
 107                 if (!(cap & dice->clock_caps))
 108                         continue;
 109 
 110                 base_offset = 0x2000 * mode + 0x1000;
 111 
 112                 err = read_transaction(dice, section_addr,
 113                                        base_offset + EXT_APP_STREAM_TX_NUMBER,
 114                                        &reg, sizeof(reg));
 115                 if (err < 0)
 116                         break;
 117 
 118                 base_offset += EXT_APP_STREAM_ENTRIES;
 119                 stream_count = be32_to_cpu(reg[0]);
 120                 err = read_stream_entries(dice, section_addr, base_offset,
 121                                           stream_count, mode,
 122                                           dice->tx_pcm_chs,
 123                                           dice->tx_midi_ports);
 124                 if (err < 0)
 125                         break;
 126 
 127                 base_offset += stream_count * EXT_APP_STREAM_ENTRY_SIZE;
 128                 stream_count = be32_to_cpu(reg[1]);
 129                 err = read_stream_entries(dice, section_addr, base_offset,
 130                                           stream_count,
 131                                           mode, dice->rx_pcm_chs,
 132                                           dice->rx_midi_ports);
 133                 if (err < 0)
 134                         break;
 135         }
 136 
 137         return err;
 138 }
 139 
 140 int snd_dice_detect_extension_formats(struct snd_dice *dice)
 141 {
 142         __be32 *pointers;
 143         unsigned int i;
 144         u64 section_addr;
 145         int err;
 146 
 147         pointers = kmalloc_array(9, sizeof(__be32) * 2, GFP_KERNEL);
 148         if (pointers == NULL)
 149                 return -ENOMEM;
 150 
 151         err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
 152                                  DICE_EXT_APP_SPACE, pointers,
 153                                  9 * sizeof(__be32) * 2, 0);
 154         if (err < 0)
 155                 goto end;
 156 
 157         /* Check two of them for offset have the same value or not. */
 158         for (i = 0; i < 9; ++i) {
 159                 int j;
 160 
 161                 for (j = i + 1; j < 9; ++j) {
 162                         if (pointers[i * 2] == pointers[j * 2]) {
 163                                 // Fallback to limited functionality.
 164                                 err = -ENXIO;
 165                                 goto end;
 166                         }
 167                 }
 168         }
 169 
 170         section_addr = DICE_EXT_APP_SPACE + be32_to_cpu(pointers[12]) * 4;
 171         err = detect_stream_formats(dice, section_addr);
 172 end:
 173         kfree(pointers);
 174         return err;
 175 }

/* [<][>][^][v][top][bottom][index][help] */