Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/dice/dice-extension.c
26442 views
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
177