root/trunk/libffado/src/dice/focusrite/saffire_pro26.cpp

Revision 2606, 17.9 kB (checked in by jwoithe, 8 years ago)

From Hector Martin <marcan@marcan.st>

I got an ADAT device to test this input and it turns out I had botched
the input selection. The ADAT port goes into the second ADAT receiver,
not the first. This makes sense, as S/PDIF via ADAT is on the fourth
AES receiver, which shares the same physical pin on the DICE chip.

Signed-off-by: Hector Martin <marcan@marcan.st>

Line 
1 /*
2  * Copyright (C) 2009 by Pieter Palmers
3  * Copyright (C) 2009 by Arnold Krille
4  * Copyright (C) 2015 by Hector Martin
5  *
6  * This file is part of FFADO
7  * FFADO = Free Firewire (pro-)audio drivers for linux
8  *
9  * FFADO is based upon FreeBoB.
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 2 of the License, or
14  * (at your option) version 3 of the License.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  *
24  */
25
26 #include "saffire_pro26.h"
27 #include "focusrite_eap.h"
28
29 #include "libutil/ByteSwap.h"
30 #include <cstdio>
31
32 namespace Dice {
33 namespace Focusrite {
34
35 void SaffirePro26::SaffirePro26EAP::setupSources_low() {
36     addSource("SPDIF/In",  4,  4, eRS_AES, 1);
37     addSource("ADAT/In",   8,  8, eRS_ADAT, 1);
38     addSource("Anlg/In", 0,  6, eRS_InS0, 1);
39     addSource("Mixer/Out",  0, 16, eRS_Mixer, 1);
40     addSource("1394/In",   0,  8, eRS_ARX0, 1);
41     addSource("Mute",   0,  1, eRS_Muted);
42 }
43 void SaffirePro26::SaffirePro26EAP::setupDestinations_low() {
44     addDestination("SPDIF/Out",  6,  2, eRD_AES, 1);
45     addDestination("Line/Out", 0,  6, eRD_InS0, 1);
46     addDestination("Mixer/In",  0, 16, eRD_Mixer0, 1);
47     addDestination("Mixer/In",  0,  2, eRD_Mixer1, 17);
48     addDestination("1394/Out",   0, 10, eRD_ATX0, 1);
49     addDestination("1394/Out",   0, 8, eRD_ATX1, 11);
50 // Is a Mute destination useful ?
51 //    addDestination("Mute",   0,  1, eRD_Muted);
52 }
53
54 void SaffirePro26::SaffirePro26EAP::setupSources_mid() {
55     addSource("SPDIF/In",  4,  4, eRS_AES, 1);
56     addSource("ADAT/In",   0,  4, eRS_ADAT, 1);
57     addSource("Anlg/In", 0,  6, eRS_InS0, 1);
58     addSource("Mixer/Out",  0, 16, eRS_Mixer, 1);
59     addSource("1394/In",   0,  8, eRS_ARX0, 1);
60     addSource("Mute",   0,  1, eRS_Muted);
61 }
62 void SaffirePro26::SaffirePro26EAP::setupDestinations_mid() {
63     addDestination("SPDIF/Out",  6,  2, eRD_AES, 1);
64     addDestination("Line/Out", 0,  6, eRD_InS0, 1);
65     addDestination("Mixer/In",  0, 16, eRD_Mixer0, 1);
66     addDestination("Mixer/In",  0,  2, eRD_Mixer1, 17);
67     addDestination("1394/Out",   0, 10, eRD_ATX0, 1);
68     addDestination("1394/Out",   0, 4, eRD_ATX1, 11);
69 // Is a Mute destination useful ?
70 //    addDestination("Mute",   0,  1, eRD_Muted);
71 }
72
73 void SaffirePro26::SaffirePro26EAP::setupSources_high() {
74     printMessage("High (192 kHz) sample rate not supported by Saffire Pro 26\n");
75 }
76
77 void SaffirePro26::SaffirePro26EAP::setupDestinations_high() {
78     printMessage("High (192 kHz) sample rate not supported by Saffire Pro 26\n");
79 }
80
81 /**
82  * The default configurations for the Saffire Pro 26 router.
83  *  For coherence with hardware, destinations must follow a specific ordering
84  *  Front LEDs are connected to the first six eRD_ATX0 entries
85  */
86 void
87 SaffirePro26::SaffirePro26EAP::setupDefaultRouterConfig_low() {
88     unsigned int i;
89     // the 1394 stream receivers except the two "loops" one
90     for (i=0; i<6; i++) {
91         addRoute(eRS_InS0, i, eRD_ATX0, i);
92     }
93     for (i=0; i<2; i++) {
94         addRoute(eRS_AES, i+4, eRD_ATX0, i+6);
95     }
96     for (i=0; i<8; i++) {
97         addRoute(eRS_ADAT, i, eRD_ATX1, i);
98     }
99     // The audio ports
100     // Ensure that audio port are not muted
101     for (i=0; i<6; i++) {
102         addRoute(eRS_ARX0, i%2, eRD_InS0, i);
103     }
104     // the SPDIF receiver
105     for (i=0; i<2; i++) {
106         addRoute(eRS_Muted, 0, eRD_AES, i+6);
107     }
108     // the "loops" 1394 stream receivers
109     for (i=0; i<2; i++) {
110         addRoute(eRS_Muted, 0, eRD_ATX0, i+8);
111     }
112     // the Mixer inputs
113     for (i=0; i<6; i++) {
114         addRoute(eRS_InS0, i, eRD_Mixer0, i);
115     }
116     for (i=0; i<2; i++) {
117         addRoute(eRS_AES, i+4, eRD_Mixer0, i+6);
118     }
119     for (i=0; i<8; i++) {
120         addRoute(eRS_ADAT, i, eRD_Mixer0, i+8);
121     }
122     for (i=0; i<2; i++) {
123         addRoute(eRS_ARX0, i, eRD_Mixer1, i);
124     }
125     // The two mute destinations
126     // FIXME: does this do anything useful?
127     for (i=0; i<2; i++) {
128         addRoute(eRS_Mixer, i, eRD_Muted, 0);
129     }
130 }
131
132 /**
133  *  There must be 40 (?) destinations at mid samplerate
134  *  Front LEDs are connected to the first six eRD_ATX0 entries
135  */
136 void
137 SaffirePro26::SaffirePro26EAP::setupDefaultRouterConfig_mid() {
138     unsigned int i;
139     // the 1394 stream receivers except the two "loops" one
140     for (i=0; i<6; i++) {
141         addRoute(eRS_InS0, i, eRD_ATX0, i);
142     }
143     for (i=0; i<2; i++) {
144         addRoute(eRS_AES, i+4, eRD_ATX0, i+6);
145     }
146     for (i=0; i<4; i++) {
147         addRoute(eRS_ADAT, i, eRD_ATX1, i);
148     }
149     // The audio ports
150     // Ensure that audio port are not muted
151     for (i=0; i<6; i++) {
152         addRoute(eRS_ARX0, i%2, eRD_InS0, i);
153     }
154     // the SPDIF receiver
155     for (i=0; i<2; i++) {
156         addRoute(eRS_Muted, 0, eRD_AES, i+6);
157     }
158     // the "loops" 1394 stream receivers
159     for (i=0; i<2; i++) {
160         addRoute(eRS_Muted, 0, eRD_ATX0, i+8);
161     }
162     // the Mixer inputs
163     for (i=0; i<6; i++) {
164         addRoute(eRS_InS0, i, eRD_Mixer0, i);
165     }
166     for (i=0; i<2; i++) {
167         addRoute(eRS_AES, i+4, eRD_Mixer0, i+6);
168     }
169     for (i=0; i<4; i++) {
170         addRoute(eRS_ADAT, i, eRD_Mixer0, i+8);
171     }
172     for (i=0; i<4; i++) {
173         addRoute(eRS_Muted, i, eRD_Mixer0, i+12);
174     }
175     for (i=0; i<2; i++) {
176         addRoute(eRS_ARX0, i, eRD_Mixer1, i);
177     }
178     // The two mute destinations
179     // FIXME: does this do anything useful?
180     for (i=0; i<2; i++) {
181         addRoute(eRS_Mixer, i, eRD_Muted, 0);
182     }
183 }
184
185 /**
186  *  High rate not supported
187  */
188 void
189 SaffirePro26::SaffirePro26EAP::setupDefaultRouterConfig_high() {
190     printMessage("High (192 kHz) sample rate not supported by Saffire Pro 26\n");
191 }
192
193 /**
194  *  Pro 24 Monitor section
195  */
196 SaffirePro26::SaffirePro26EAP::MonitorSection::MonitorSection(Dice::Focusrite::FocusriteEAP* eap,
197     std::string name) : Control::Container(eap, name)
198     , m_eap(eap)
199 {
200     // Global Mute control
201     Control::Container* grp_globalmute = new Control::Container(m_eap, "GlobalMute");
202     addElement(grp_globalmute);
203     FocusriteEAP::Switch* mute =
204         new FocusriteEAP::Switch(m_eap, "State",
205                                  SAFFIRE_PRO26_REGISTER_APP_GLOBAL_MUTE_SWITCH,
206                                  FOCUSRITE_EAP_GLOBAL_MUTE_SWITCH_VALUE,
207                                  SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
208                                  SAFFIRE_PRO26_MESSAGE_SET_GLOBAL_DIM_MUTE_SWITCH);
209     grp_globalmute->addElement(mute);
210
211     // Global Dim control
212     Control::Container* grp_globaldim = new Control::Container(m_eap, "GlobalDim");
213     addElement(grp_globaldim);
214     FocusriteEAP::Switch* dim =
215         new FocusriteEAP::Switch(m_eap, "State",
216                                  SAFFIRE_PRO26_REGISTER_APP_GLOBAL_DIM_SWITCH,
217                                  FOCUSRITE_EAP_GLOBAL_DIM_SWITCH_VALUE,
218                                  SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
219                                  SAFFIRE_PRO26_MESSAGE_SET_GLOBAL_DIM_MUTE_SWITCH);
220     grp_globaldim->addElement(dim);
221     FocusriteEAP::Poti* dimlevel =
222         new FocusriteEAP::Poti(m_eap, "Level",
223                                SAFFIRE_PRO26_REGISTER_APP_GLOBAL_DIM_VOLUME,
224                                SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
225                                SAFFIRE_PRO26_MESSAGE_SET_LINEOUT_MONITOR_VOLUME);
226     grp_globaldim->addElement(dimlevel);
227
228     // The mono switches don't seem to do anything on this device (and are not
229     // implemented in MixControl)
230
231     // Independent control of each line/out
232     Control::Container* grp_perchannel = new Control::Container(m_eap, "LineOut");
233     addElement(grp_perchannel);
234     FocusriteEAP::VolumeControl* vol;
235
236     // per Line/Out monitoring
237     FocusriteEAP::Switch* s;
238     for (unsigned int i=0; i<SAFFIRE_PRO26_APP_STEREO_LINEOUT_SIZE; ++i) {
239         std::stringstream stream;
240
241         // Activate/Unactivate per Line/Out volume monitoring
242         stream.str(std::string());
243         stream << "UnActivate" << i*2+1;
244         s =
245           new FocusriteEAP::Switch(m_eap, stream.str(),
246                                    SAFFIRE_PRO26_REGISTER_APP_LINEOUT_MONITOR_SWITCH+i*sizeof(quadlet_t),
247                                    FOCUSRITE_EAP_SWITCH_BIT_1,
248                                    SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
249                                    SAFFIRE_PRO26_MESSAGE_SET_LINEOUT_MONITOR_VOLUME);
250         grp_perchannel->addElement(s);
251         stream.str(std::string());
252         stream << "UnActivate" << i*2+2;
253         s =
254           new FocusriteEAP::Switch(m_eap, stream.str(),
255                                    SAFFIRE_PRO26_REGISTER_APP_LINEOUT_MONITOR_SWITCH+i*sizeof(quadlet_t),
256                                    FOCUSRITE_EAP_SWITCH_BIT_2,
257                                    SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
258                                    SAFFIRE_PRO26_MESSAGE_SET_LINEOUT_MONITOR_VOLUME);
259         grp_perchannel->addElement(s);
260
261         // per Line/Out mute/unmute
262         stream.str(std::string());
263         stream << "Mute" << i*2+1;
264         s =
265           new FocusriteEAP::Switch(m_eap, stream.str(),
266                                    SAFFIRE_PRO26_REGISTER_APP_LINEOUT_MONITOR_SWITCH+i*sizeof(quadlet_t),
267                                    FOCUSRITE_EAP_SWITCH_BIT_3,
268                                    SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
269                                    SAFFIRE_PRO26_MESSAGE_SET_LINEOUT_MONITOR_VOLUME);
270         grp_perchannel->addElement(s);
271         stream.str(std::string());
272         stream << "Mute" << i*2+2;
273         s =
274           new FocusriteEAP::Switch(m_eap, stream.str(),
275                                    SAFFIRE_PRO26_REGISTER_APP_LINEOUT_MONITOR_SWITCH+i*sizeof(quadlet_t),
276                                    FOCUSRITE_EAP_SWITCH_BIT_4,
277                                    SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
278                                    SAFFIRE_PRO26_MESSAGE_SET_LINEOUT_MONITOR_VOLUME);
279         grp_perchannel->addElement(s);
280
281         // per Line/Out global mute activation/unactivation
282         stream.str(std::string());
283         stream << "GMute" << 2*i+1;
284         s =
285           new FocusriteEAP::Switch(m_eap, stream.str(),
286                                    SAFFIRE_PRO26_REGISTER_APP_LINEOUT_SWITCH_CONTROL,
287                                    FOCUSRITE_EAP_SWITCH_CONTROL_VALUE
288                                         <<(FOCUSRITE_EAP_SWITCH_CONTROL_MUTE_SHIFT+2*i),
289                                    SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
290                                    SAFFIRE_PRO26_MESSAGE_SET_LINEOUT_SWITCH_CONTROL);
291         grp_perchannel->addElement(s);
292
293         stream.str(std::string());
294         stream << "GMute" << 2*i+2;
295         s =
296           new FocusriteEAP::Switch(m_eap, stream.str(),
297                                    SAFFIRE_PRO26_REGISTER_APP_LINEOUT_SWITCH_CONTROL,
298                                    FOCUSRITE_EAP_SWITCH_CONTROL_VALUE
299                                         <<(FOCUSRITE_EAP_SWITCH_CONTROL_MUTE_SHIFT+2*i+1),
300                                    SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
301                                    SAFFIRE_PRO26_MESSAGE_SET_LINEOUT_SWITCH_CONTROL);
302         grp_perchannel->addElement(s);
303
304         // per Line/Out global dim activation/unactivation
305         stream.str(std::string());
306         stream << "GDim" << 2*i+1;
307         s =
308           new FocusriteEAP::Switch(m_eap, stream.str(),
309                                    SAFFIRE_PRO26_REGISTER_APP_LINEOUT_SWITCH_CONTROL,
310                                    FOCUSRITE_EAP_SWITCH_CONTROL_VALUE
311                                         <<(FOCUSRITE_EAP_SWITCH_CONTROL_DIM_SHIFT+2*i),
312                                    SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
313                                    SAFFIRE_PRO26_MESSAGE_SET_LINEOUT_SWITCH_CONTROL);
314         grp_perchannel->addElement(s);
315
316         stream.str(std::string());
317         stream << "GDim" << 2*i+2;
318         s =
319           new FocusriteEAP::Switch(m_eap, stream.str(),
320                                    SAFFIRE_PRO26_REGISTER_APP_LINEOUT_SWITCH_CONTROL,
321                                    FOCUSRITE_EAP_SWITCH_CONTROL_VALUE
322                                         <<(FOCUSRITE_EAP_SWITCH_CONTROL_DIM_SHIFT+2*i+1),
323                                    SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
324                                    SAFFIRE_PRO26_MESSAGE_SET_LINEOUT_SWITCH_CONTROL);
325         grp_perchannel->addElement(s);
326
327         // per Line/Out volume control
328         stream.str(std::string());
329         stream << "Volume" << i*2+1;
330         vol =
331           new FocusriteEAP::VolumeControl(m_eap, stream.str(),
332                                           SAFFIRE_PRO26_REGISTER_APP_LINEOUT_MONITOR_VOLUME
333                                               +i*sizeof(quadlet_t),
334                                           FOCUSRITE_EAP_LINEOUT_VOLUME_SET_1,
335                                           SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
336                                           SAFFIRE_PRO26_MESSAGE_SET_LINEOUT_MONITOR_VOLUME);
337         grp_perchannel->addElement(vol);
338         stream.str(std::string());
339         stream << "Volume" << i*2+2;
340         vol =
341           new FocusriteEAP::VolumeControl(m_eap, stream.str(),
342                                           SAFFIRE_PRO26_REGISTER_APP_LINEOUT_MONITOR_VOLUME
343                                               +i*sizeof(quadlet_t),
344                                           FOCUSRITE_EAP_LINEOUT_VOLUME_SET_2,
345                                           SAFFIRE_PRO26_REGISTER_APP_MESSAGE_SET,
346                                           SAFFIRE_PRO26_MESSAGE_SET_LINEOUT_MONITOR_VOLUME);
347         grp_perchannel->addElement(vol);
348     }
349
350     // The Saffire PRO 26 does not have line/inst/gain controls. Instead it has
351     // dedicated hardware switches for inputs 1/2, auto selection for inputs 3/4,
352     // and no controls for inputs 5/6.
353
354     // There is also support for ADAT-as-SPDIF, but no control is necessary.
355     // SPDIF inputs appear on their own dedicated routing source when present
356     // (labeled SPDIF 3/4).
357 }
358
359 SaffirePro26::SaffirePro26( DeviceManager& d,
360                             std::auto_ptr<ConfigRom>( configRom ))
361     : Dice::Device(d , configRom)
362 {
363     debugOutput(DEBUG_LEVEL_VERBOSE, "Created Dice::Focusrite::SaffirePro26 (NodeID %d)\n",
364                 getConfigRom().getNodeId());
365 }
366
367 SaffirePro26::~SaffirePro26()
368 {
369     //debugOutput(DEBUG_LEVEL_VERBOSE, "Deleting the saffirePro26\n");
370     /// I wonder whether we should really save only on clean exits or also each time a setting is
371     //  changed. Or should we provide a function (and thus gui-button) to save the state of the
372     //  device?
373     getEAP()->storeFlashConfig();
374 }
375
376 bool SaffirePro26::discover() {
377     if (Dice::Device::discover()) {
378         fb_quadlet_t* version = (fb_quadlet_t *)calloc(2, sizeof(fb_quadlet_t));
379         getEAP()->readRegBlock(Dice::EAP::eRT_Application, SAFFIRE_PRO26_REGISTER_APP_VERSION, version, 1*sizeof(fb_quadlet_t));
380         // Only known firmware for Saffire Pro 26 devices so far is 0x10000.
381         if (version[0] != 0x10000) {
382             fprintf(stderr, "This is a Focusrite Saffire Pro26 but not the right firmware. Better stop here before something goes wrong.\n");
383             fprintf(stderr, "This device has firmware 0x%x while we only know about version 0x%x.\n", version[0], 0x10000);
384             return false;
385         }
386
387         // FIXME: What is the purpose of the following commented lines at this point ?
388         //getEAP()->readRegBlock(Dice::EAP::eRT_Command, 0x00, tmp, 2*sizeof(fb_quadlet_t)); // DEBUG
389         //hexDumpQuadlets(tmp, 2); // DEBUG
390
391         FocusriteEAP* eap = dynamic_cast<FocusriteEAP*>(getEAP());
392         SaffirePro26EAP::MonitorSection* monitor = new SaffirePro26EAP::MonitorSection(eap, "Monitoring");
393         getEAP()->addElement(monitor);
394         return true;
395     }
396     return false;
397 }
398
399 void SaffirePro26::showDevice()
400 {
401     debugOutput(DEBUG_LEVEL_VERBOSE, "This is a Dice::Focusrite::SaffirePro26\n");
402     Dice::Device::showDevice();
403 }
404 Dice::EAP* SaffirePro26::createEAP() {
405     return new SaffirePro26EAP(*this);
406 }
407
408 bool SaffirePro26::setNickname( std::string name ) {
409     char nickname[SAFFIRE_PRO26_APP_NICK_NAME_SIZE+1];
410
411     // The device has room for SAFFIRE_PRO26_APP_NICK_NAME_SIZE characters.
412     // Erase supplementary characters or fill-in with NULL character if necessary
413     strncpy(nickname, name.c_str(), SAFFIRE_PRO26_APP_NICK_NAME_SIZE);
414
415     // Strings from the device are always little-endian,
416     // so byteswap for big-endian machines
417     #if __BYTE_ORDER == __BIG_ENDIAN
418     byteSwapBlock((quadlet_t *)nickname, SAFFIRE_PRO26_APP_NICK_NAME_SIZE/4);
419     #endif
420
421     if (!getEAP()->writeRegBlock(Dice::EAP::eRT_Application, SAFFIRE_PRO26_REGISTER_APP_NICK_NAME,
422                                  (quadlet_t*)nickname, SAFFIRE_PRO26_APP_NICK_NAME_SIZE)) {
423         debugError("Could not write nickname string \n");
424         return false;
425     }
426     return true;
427 }
428
429 std::string SaffirePro26::getNickname() {
430     char nickname[SAFFIRE_PRO26_APP_NICK_NAME_SIZE+1];
431     if (!getEAP()->readRegBlock(Dice::EAP::eRT_Application, SAFFIRE_PRO26_REGISTER_APP_NICK_NAME,
432                                 (quadlet_t*)nickname, SAFFIRE_PRO26_APP_NICK_NAME_SIZE)){
433         debugError("Could not read nickname string \n");
434         return std::string("(unknown)");
435     }
436
437     // Strings from the device are always little-endian,
438     // so byteswap for big-endian machines
439     #if __BYTE_ORDER == __BIG_ENDIAN
440     byteSwapBlock((quadlet_t *)nickname, SAFFIRE_PRO26_APP_NICK_NAME_SIZE/4);
441     #endif
442
443     // The device supplies at most SAFFIRE_PRO26_APP_NICK_NAME_SIZE characters.  Ensure the string is
444     // NULL terminated.
445     nickname[SAFFIRE_PRO26_APP_NICK_NAME_SIZE] = 0;
446     return std::string(nickname);
447 }
448
449 }
450 }
451
452 // vim: et
Note: See TracBrowser for help on using the browser.