diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2014-04-25 09:45:24 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-05-26 08:31:50 -0400 |
commit | 25784ec2d0347b715e354d92151734afe1296f02 (patch) | |
tree | 6823c6edc1694370d2e0852d5a6cfdb32bea03c4 /sound/firewire | |
parent | 8ac98a3585ee7ad0c1bd03b098784a10e13bee21 (diff) |
ALSA: bebob: Add support for Focusrite Saffire/SaffirePro series
This commit allows this driver to support all of models which Focusrite
produces with DM1000/BeBoB. They are:
- Saffire
- Saffire LE
- SaffirePro 10 I/O
- SaffirePro 26 I/O
This commit adds Focusrite specific operations:
1. Get source of clock
2. Get/Set sampling frequency
3. Get metering information
The driver uses these functionalities to read/write specific address by async
transaction.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r-- | sound/firewire/Kconfig | 1 | ||||
-rw-r--r-- | sound/firewire/bebob/Makefile | 2 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob.c | 30 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob.h | 4 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob_focusrite.c | 279 |
5 files changed, 314 insertions, 2 deletions
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index f8e484586221..605e44b14f83 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig | |||
@@ -112,6 +112,7 @@ config SND_BEBOB | |||
112 | * Terratec EWS MIC2/EWS MIC4 | 112 | * Terratec EWS MIC2/EWS MIC4 |
113 | * Terratec Aureon 7.1 Firewire | 113 | * Terratec Aureon 7.1 Firewire |
114 | * Yamaha GO44/GO46 | 114 | * Yamaha GO44/GO46 |
115 | * Focusrite Saffire/Saffire LE/SaffirePro10 IO/SaffirePro26 IO | ||
115 | 116 | ||
116 | To compile this driver as a module, choose M here: the module | 117 | To compile this driver as a module, choose M here: the module |
117 | will be called snd-bebob. | 118 | will be called snd-bebob. |
diff --git a/sound/firewire/bebob/Makefile b/sound/firewire/bebob/Makefile index c35eee105135..656542077b12 100644 --- a/sound/firewire/bebob/Makefile +++ b/sound/firewire/bebob/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | snd-bebob-objs := bebob_command.o bebob_stream.o bebob_proc.o bebob_midi.o \ | 1 | snd-bebob-objs := bebob_command.o bebob_stream.o bebob_proc.o bebob_midi.o \ |
2 | bebob_pcm.o bebob_hwdep.o bebob_terratec.o bebob_yamaha.o \ | 2 | bebob_pcm.o bebob_hwdep.o bebob_terratec.o bebob_yamaha.o \ |
3 | bebob.o | 3 | bebob_focusrite.o bebob.o |
4 | obj-m += snd-bebob.o | 4 | obj-m += snd-bebob.o |
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 6a6350466fd4..6d23e44e635b 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c | |||
@@ -54,6 +54,9 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS); | |||
54 | #define VEN_PRISMSOUND 0x00001198 | 54 | #define VEN_PRISMSOUND 0x00001198 |
55 | #define VEN_TERRATEC 0x00000aac | 55 | #define VEN_TERRATEC 0x00000aac |
56 | #define VEN_YAMAHA 0x0000a0de | 56 | #define VEN_YAMAHA 0x0000a0de |
57 | #define VEN_FOCUSRITE 0x0000130e | ||
58 | |||
59 | #define MODEL_FOCUSRITE_SAFFIRE_BOTH 0x00000000 | ||
57 | 60 | ||
58 | static int | 61 | static int |
59 | name_device(struct snd_bebob *bebob, unsigned int vendor_id) | 62 | name_device(struct snd_bebob *bebob, unsigned int vendor_id) |
@@ -122,6 +125,20 @@ bebob_card_free(struct snd_card *card) | |||
122 | mutex_destroy(&bebob->mutex); | 125 | mutex_destroy(&bebob->mutex); |
123 | } | 126 | } |
124 | 127 | ||
128 | static const struct snd_bebob_spec * | ||
129 | get_saffire_spec(struct fw_unit *unit) | ||
130 | { | ||
131 | char name[24] = {0}; | ||
132 | |||
133 | if (fw_csr_string(unit->directory, CSR_MODEL, name, sizeof(name)) < 0) | ||
134 | return NULL; | ||
135 | |||
136 | if (strcmp(name, "SaffireLE") == 0) | ||
137 | return &saffire_le_spec; | ||
138 | else | ||
139 | return &saffire_spec; | ||
140 | } | ||
141 | |||
125 | static int | 142 | static int |
126 | bebob_probe(struct fw_unit *unit, | 143 | bebob_probe(struct fw_unit *unit, |
127 | const struct ieee1394_device_id *entry) | 144 | const struct ieee1394_device_id *entry) |
@@ -143,7 +160,11 @@ bebob_probe(struct fw_unit *unit, | |||
143 | goto end; | 160 | goto end; |
144 | } | 161 | } |
145 | 162 | ||
146 | spec = (const struct snd_bebob_spec *)entry->driver_data; | 163 | if ((entry->vendor_id == VEN_FOCUSRITE) && |
164 | (entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH)) | ||
165 | spec = get_saffire_spec(unit); | ||
166 | else | ||
167 | spec = (const struct snd_bebob_spec *)entry->driver_data; | ||
147 | if (spec == NULL) { | 168 | if (spec == NULL) { |
148 | err = -ENOSYS; | 169 | err = -ENOSYS; |
149 | goto end; | 170 | goto end; |
@@ -306,6 +327,13 @@ static const struct ieee1394_device_id bebob_id_table[] = { | |||
306 | SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000b, &yamaha_go_spec), | 327 | SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000b, &yamaha_go_spec), |
307 | /* YAMAHA, GO46 */ | 328 | /* YAMAHA, GO46 */ |
308 | SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000c, &yamaha_go_spec), | 329 | SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000c, &yamaha_go_spec), |
330 | /* Focusrite, SaffirePro 26 I/O */ | ||
331 | SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000003, &saffirepro_26_spec), | ||
332 | /* Focusrite, SaffirePro 10 I/O */ | ||
333 | SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000006, &saffirepro_10_spec), | ||
334 | /* Focusrite, Saffire(no label and LE) */ | ||
335 | SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, MODEL_FOCUSRITE_SAFFIRE_BOTH, | ||
336 | &saffire_spec), | ||
309 | /* IDs are unknown but able to be supported */ | 337 | /* IDs are unknown but able to be supported */ |
310 | /* Apogee, Mini-ME Firewire */ | 338 | /* Apogee, Mini-ME Firewire */ |
311 | /* Apogee, Mini-DAC Firewire */ | 339 | /* Apogee, Mini-DAC Firewire */ |
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index e92d356ce361..220b115785e2 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h | |||
@@ -228,6 +228,10 @@ int snd_bebob_create_hwdep_device(struct snd_bebob *bebob); | |||
228 | extern struct snd_bebob_spec phase88_rack_spec; | 228 | extern struct snd_bebob_spec phase88_rack_spec; |
229 | extern struct snd_bebob_spec phase24_series_spec; | 229 | extern struct snd_bebob_spec phase24_series_spec; |
230 | extern struct snd_bebob_spec yamaha_go_spec; | 230 | extern struct snd_bebob_spec yamaha_go_spec; |
231 | extern struct snd_bebob_spec saffirepro_26_spec; | ||
232 | extern struct snd_bebob_spec saffirepro_10_spec; | ||
233 | extern struct snd_bebob_spec saffire_le_spec; | ||
234 | extern struct snd_bebob_spec saffire_spec; | ||
231 | 235 | ||
232 | #define SND_BEBOB_DEV_ENTRY(vendor, model, data) \ | 236 | #define SND_BEBOB_DEV_ENTRY(vendor, model, data) \ |
233 | { \ | 237 | { \ |
diff --git a/sound/firewire/bebob/bebob_focusrite.c b/sound/firewire/bebob/bebob_focusrite.c new file mode 100644 index 000000000000..cd29dbc4b691 --- /dev/null +++ b/sound/firewire/bebob/bebob_focusrite.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* | ||
2 | * bebob_focusrite.c - a part of driver for BeBoB based devices | ||
3 | * | ||
4 | * Copyright (c) 2013-2014 Takashi Sakamoto | ||
5 | * | ||
6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
7 | */ | ||
8 | |||
9 | #include "./bebob.h" | ||
10 | |||
11 | #define ANA_IN "Analog In" | ||
12 | #define DIG_IN "Digital In" | ||
13 | #define ANA_OUT "Analog Out" | ||
14 | #define DIG_OUT "Digital Out" | ||
15 | #define STM_IN "Stream In" | ||
16 | |||
17 | #define SAFFIRE_ADDRESS_BASE 0x000100000000 | ||
18 | |||
19 | #define SAFFIRE_OFFSET_CLOCK_SOURCE 0x0000000000f8 | ||
20 | #define SAFFIREPRO_OFFSET_CLOCK_SOURCE 0x000000000174 | ||
21 | |||
22 | /* whether sync to external device or not */ | ||
23 | #define SAFFIRE_OFFSET_CLOCK_SYNC_EXT 0x00000000013c | ||
24 | #define SAFFIRE_LE_OFFSET_CLOCK_SYNC_EXT 0x000000000432 | ||
25 | #define SAFFIREPRO_OFFSET_CLOCK_SYNC_EXT 0x000000000164 | ||
26 | |||
27 | #define SAFFIRE_CLOCK_SOURCE_INTERNAL 0 | ||
28 | #define SAFFIRE_CLOCK_SOURCE_SPDIF 1 | ||
29 | |||
30 | /* '1' is absent, why... */ | ||
31 | #define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0 | ||
32 | #define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2 | ||
33 | #define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 | ||
34 | #define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 | ||
35 | #define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5 | ||
36 | |||
37 | /* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */ | ||
38 | #define SAFFIREPRO_ENABLE_DIG_IFACES 0x0000000001a4 | ||
39 | |||
40 | /* saffirepro has its own parameter for sampling frequency */ | ||
41 | #define SAFFIREPRO_RATE_NOREBOOT 0x0000000001cc | ||
42 | /* index is the value for this register */ | ||
43 | static const unsigned int rates[] = { | ||
44 | [0] = 0, | ||
45 | [1] = 44100, | ||
46 | [2] = 48000, | ||
47 | [3] = 88200, | ||
48 | [4] = 96000, | ||
49 | [5] = 176400, | ||
50 | [6] = 192000 | ||
51 | }; | ||
52 | |||
53 | /* saffire(no label)/saffire LE has metering */ | ||
54 | #define SAFFIRE_OFFSET_METER 0x000000000100 | ||
55 | #define SAFFIRE_LE_OFFSET_METER 0x000000000168 | ||
56 | |||
57 | static inline int | ||
58 | saffire_read_block(struct snd_bebob *bebob, u64 offset, | ||
59 | u32 *buf, unsigned int size) | ||
60 | { | ||
61 | unsigned int i; | ||
62 | int err; | ||
63 | __be32 *tmp = (__be32 *)buf; | ||
64 | |||
65 | err = snd_fw_transaction(bebob->unit, TCODE_READ_BLOCK_REQUEST, | ||
66 | SAFFIRE_ADDRESS_BASE + offset, | ||
67 | tmp, size, 0); | ||
68 | if (err < 0) | ||
69 | goto end; | ||
70 | |||
71 | for (i = 0; i < size / sizeof(u32); i++) | ||
72 | buf[i] = be32_to_cpu(tmp[i]); | ||
73 | end: | ||
74 | return err; | ||
75 | } | ||
76 | |||
77 | static inline int | ||
78 | saffire_read_quad(struct snd_bebob *bebob, u64 offset, u32 *value) | ||
79 | { | ||
80 | int err; | ||
81 | __be32 tmp; | ||
82 | |||
83 | err = snd_fw_transaction(bebob->unit, TCODE_READ_QUADLET_REQUEST, | ||
84 | SAFFIRE_ADDRESS_BASE + offset, | ||
85 | &tmp, sizeof(__be32), 0); | ||
86 | if (err < 0) | ||
87 | goto end; | ||
88 | |||
89 | *value = be32_to_cpu(tmp); | ||
90 | end: | ||
91 | return err; | ||
92 | } | ||
93 | |||
94 | static inline int | ||
95 | saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value) | ||
96 | { | ||
97 | __be32 data = cpu_to_be32(value); | ||
98 | |||
99 | return snd_fw_transaction(bebob->unit, TCODE_WRITE_QUADLET_REQUEST, | ||
100 | SAFFIRE_ADDRESS_BASE + offset, | ||
101 | &data, sizeof(__be32), 0); | ||
102 | } | ||
103 | |||
104 | static char *const saffirepro_26_clk_src_labels[] = { | ||
105 | SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock" | ||
106 | }; | ||
107 | |||
108 | static char *const saffirepro_10_clk_src_labels[] = { | ||
109 | SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock" | ||
110 | }; | ||
111 | static int | ||
112 | saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate) | ||
113 | { | ||
114 | u32 id; | ||
115 | int err; | ||
116 | |||
117 | err = saffire_read_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, &id); | ||
118 | if (err < 0) | ||
119 | goto end; | ||
120 | if (id >= ARRAY_SIZE(rates)) | ||
121 | err = -EIO; | ||
122 | else | ||
123 | *rate = rates[id]; | ||
124 | end: | ||
125 | return err; | ||
126 | } | ||
127 | static int | ||
128 | saffirepro_both_clk_freq_set(struct snd_bebob *bebob, unsigned int rate) | ||
129 | { | ||
130 | u32 id; | ||
131 | |||
132 | for (id = 0; id < ARRAY_SIZE(rates); id++) { | ||
133 | if (rates[id] == rate) | ||
134 | break; | ||
135 | } | ||
136 | if (id == ARRAY_SIZE(rates)) | ||
137 | return -EINVAL; | ||
138 | |||
139 | return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id); | ||
140 | } | ||
141 | static int | ||
142 | saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) | ||
143 | { | ||
144 | int err; | ||
145 | u32 value; | ||
146 | |||
147 | err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value); | ||
148 | if (err < 0) | ||
149 | goto end; | ||
150 | |||
151 | if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels) { | ||
152 | if (value == SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK) | ||
153 | *id = 2; | ||
154 | else if (value == SAFFIREPRO_CLOCK_SOURCE_SPDIF) | ||
155 | *id = 1; | ||
156 | } else if (value > 1) { | ||
157 | *id = value - 1; | ||
158 | } | ||
159 | end: | ||
160 | return err; | ||
161 | } | ||
162 | |||
163 | struct snd_bebob_spec saffire_le_spec; | ||
164 | static char *const saffire_both_clk_src_labels[] = { | ||
165 | SND_BEBOB_CLOCK_INTERNAL, "S/PDIF" | ||
166 | }; | ||
167 | static int | ||
168 | saffire_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) | ||
169 | { | ||
170 | int err; | ||
171 | u32 value; | ||
172 | |||
173 | err = saffire_read_quad(bebob, SAFFIRE_OFFSET_CLOCK_SOURCE, &value); | ||
174 | if (err >= 0) | ||
175 | *id = 0xff & value; | ||
176 | |||
177 | return err; | ||
178 | }; | ||
179 | static char *const saffire_le_meter_labels[] = { | ||
180 | ANA_IN, ANA_IN, DIG_IN, | ||
181 | ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, | ||
182 | STM_IN, STM_IN | ||
183 | }; | ||
184 | static char *const saffire_meter_labels[] = { | ||
185 | ANA_IN, ANA_IN, | ||
186 | STM_IN, STM_IN, STM_IN, STM_IN, STM_IN, | ||
187 | }; | ||
188 | static int | ||
189 | saffire_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size) | ||
190 | { | ||
191 | struct snd_bebob_meter_spec *spec = bebob->spec->meter; | ||
192 | unsigned int channels; | ||
193 | u64 offset; | ||
194 | int err; | ||
195 | |||
196 | if (spec->labels == saffire_le_meter_labels) | ||
197 | offset = SAFFIRE_LE_OFFSET_METER; | ||
198 | else | ||
199 | offset = SAFFIRE_OFFSET_METER; | ||
200 | |||
201 | channels = spec->num * 2; | ||
202 | if (size < channels * sizeof(u32)) | ||
203 | return -EIO; | ||
204 | |||
205 | err = saffire_read_block(bebob, offset, buf, size); | ||
206 | if (err >= 0 && spec->labels == saffire_le_meter_labels) { | ||
207 | swap(buf[1], buf[3]); | ||
208 | swap(buf[2], buf[3]); | ||
209 | swap(buf[3], buf[4]); | ||
210 | |||
211 | swap(buf[7], buf[10]); | ||
212 | swap(buf[8], buf[10]); | ||
213 | swap(buf[9], buf[11]); | ||
214 | swap(buf[11], buf[12]); | ||
215 | |||
216 | swap(buf[15], buf[16]); | ||
217 | } | ||
218 | |||
219 | return err; | ||
220 | } | ||
221 | |||
222 | static struct snd_bebob_rate_spec saffirepro_both_rate_spec = { | ||
223 | .get = &saffirepro_both_clk_freq_get, | ||
224 | .set = &saffirepro_both_clk_freq_set, | ||
225 | }; | ||
226 | /* Saffire Pro 26 I/O */ | ||
227 | static struct snd_bebob_clock_spec saffirepro_26_clk_spec = { | ||
228 | .num = ARRAY_SIZE(saffirepro_26_clk_src_labels), | ||
229 | .labels = saffirepro_26_clk_src_labels, | ||
230 | .get = &saffirepro_both_clk_src_get, | ||
231 | }; | ||
232 | struct snd_bebob_spec saffirepro_26_spec = { | ||
233 | .clock = &saffirepro_26_clk_spec, | ||
234 | .rate = &saffirepro_both_rate_spec, | ||
235 | .meter = NULL | ||
236 | }; | ||
237 | /* Saffire Pro 10 I/O */ | ||
238 | static struct snd_bebob_clock_spec saffirepro_10_clk_spec = { | ||
239 | .num = ARRAY_SIZE(saffirepro_10_clk_src_labels), | ||
240 | .labels = saffirepro_10_clk_src_labels, | ||
241 | .get = &saffirepro_both_clk_src_get, | ||
242 | }; | ||
243 | struct snd_bebob_spec saffirepro_10_spec = { | ||
244 | .clock = &saffirepro_10_clk_spec, | ||
245 | .rate = &saffirepro_both_rate_spec, | ||
246 | .meter = NULL | ||
247 | }; | ||
248 | |||
249 | static struct snd_bebob_rate_spec saffire_both_rate_spec = { | ||
250 | .get = &snd_bebob_stream_get_rate, | ||
251 | .set = &snd_bebob_stream_set_rate, | ||
252 | }; | ||
253 | static struct snd_bebob_clock_spec saffire_both_clk_spec = { | ||
254 | .num = ARRAY_SIZE(saffire_both_clk_src_labels), | ||
255 | .labels = saffire_both_clk_src_labels, | ||
256 | .get = &saffire_both_clk_src_get, | ||
257 | }; | ||
258 | /* Saffire LE */ | ||
259 | struct snd_bebob_meter_spec saffire_le_meter_spec = { | ||
260 | .num = ARRAY_SIZE(saffire_le_meter_labels), | ||
261 | .labels = saffire_le_meter_labels, | ||
262 | .get = &saffire_meter_get, | ||
263 | }; | ||
264 | struct snd_bebob_spec saffire_le_spec = { | ||
265 | .clock = &saffire_both_clk_spec, | ||
266 | .rate = &saffire_both_rate_spec, | ||
267 | .meter = &saffire_le_meter_spec | ||
268 | }; | ||
269 | /* Saffire */ | ||
270 | struct snd_bebob_meter_spec saffire_meter_spec = { | ||
271 | .num = ARRAY_SIZE(saffire_meter_labels), | ||
272 | .labels = saffire_meter_labels, | ||
273 | .get = &saffire_meter_get, | ||
274 | }; | ||
275 | struct snd_bebob_spec saffire_spec = { | ||
276 | .clock = &saffire_both_clk_spec, | ||
277 | .rate = &saffire_both_rate_spec, | ||
278 | .meter = &saffire_meter_spec | ||
279 | }; | ||