~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/firewire/dice/dice-extension.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 }
176 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php