motu: report the optical control register read from the device when obtaining the...
[ffado.git] / libffado / src / motu / motu_controls.cpp
blob2f435133b4f4a520660768f9cc7faf0178d6ab80
1 /*
2 * Copyright (C) 2005-2008 by Pieter Palmers
3 * Copyright (C) 2008-2009 by Jonathan Woithe
5 * This file is part of FFADO
6 * FFADO = Free Firewire (pro-)audio drivers for linux
8 * FFADO is based upon FreeBoB.
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) version 3 of the License.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 // This also includes motu_controls.h
26 #include "motu_avdevice.h"
28 namespace Motu {
30 MotuDiscreteCtrl::MotuDiscreteCtrl(MotuDevice &parent, unsigned int dev_reg)
31 : Control::Discrete(&parent)
32 , m_parent(parent)
33 , m_register(dev_reg)
37 MotuDiscreteCtrl::MotuDiscreteCtrl(MotuDevice &parent, unsigned int dev_reg,
38 std::string name, std::string label, std::string descr)
39 : Control::Discrete(&parent)
40 , m_parent(parent)
41 , m_register(dev_reg)
43 setName(name);
44 setLabel(label);
45 setDescription(descr);
48 MotuBinarySwitch::MotuBinarySwitch(MotuDevice &parent, unsigned int dev_reg,
49 unsigned int val_mask, unsigned int setenable_mask)
50 : MotuDiscreteCtrl(parent, dev_reg)
52 m_value_mask = val_mask;
53 /* If no "write enable" is implemented for a given switch it's safe to
54 * pass zero in to setenable_mask.
56 m_setenable_mask = setenable_mask;
59 MotuBinarySwitch::MotuBinarySwitch(MotuDevice &parent, unsigned int dev_reg,
60 unsigned int val_mask, unsigned int setenable_mask,
61 std::string name, std::string label, std::string descr)
62 : MotuDiscreteCtrl(parent, dev_reg, name, label, descr)
64 m_value_mask = val_mask;
65 /* If no "write enable" is implemented for a given switch it's safe to
66 * pass zero in to setenable_mask.
68 m_setenable_mask = setenable_mask;
71 bool
72 MotuBinarySwitch::setValue(int v)
74 unsigned int val;
75 debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for switch %s (0x%04x) to %d\n",
76 getName().c_str(), m_register, v);
78 if (m_register == MOTU_CTRL_NONE) {
79 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
80 return true;
83 // Set the value
84 if (m_setenable_mask) {
85 val = (v==0)?0:m_value_mask;
86 // Set the "write enable" bit for the value being set
87 val |= m_setenable_mask;
88 } else {
89 // It would be good to utilise the cached value from the receive
90 // processor (if running) later on. For now we'll just fetch the
91 // current register value directly when needed.
92 val = m_parent.ReadRegister(m_register);
93 if (v==0)
94 val &= ~m_value_mask;
95 else
96 val |= m_value_mask;
98 m_parent.WriteRegister(m_register, val);
100 return true;
104 MotuBinarySwitch::getValue()
106 unsigned int val;
107 debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for switch %s (0x%04x)\n",
108 getName().c_str(), m_register);
110 if (m_register == MOTU_CTRL_NONE) {
111 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
112 return 0;
115 // FIXME: we could just read the appropriate mixer status field from the
116 // receive stream processor once we work out an efficient way to do this.
117 val = m_parent.ReadRegister(m_register);
118 return (val & m_value_mask) != 0;
121 ChannelFader::ChannelFader(MotuDevice &parent, unsigned int dev_reg)
122 : MotuDiscreteCtrl(parent, dev_reg)
126 ChannelFader::ChannelFader(MotuDevice &parent, unsigned int dev_reg,
127 std::string name, std::string label, std::string descr)
128 : MotuDiscreteCtrl(parent, dev_reg, name, label, descr)
132 bool
133 ChannelFader::setValue(int v)
135 unsigned int val;
136 debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for channel fader 0x%04x to %d\n", m_register, v);
138 if (m_register == MOTU_CTRL_NONE) {
139 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
140 return true;
143 val = v<0?0:v;
144 if (val > 0x80)
145 val = 0x80;
146 // Bit 30 indicates that the channel fader is being set
147 val |= 0x40000000;
148 m_parent.WriteRegister(m_register, val);
150 return true;
154 ChannelFader::getValue()
156 unsigned int val;
157 debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for channel fader 0x%04x\n", m_register);
159 // Silently swallow attempts to read non-existent controls for now
160 if (m_register == MOTU_CTRL_NONE) {
161 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
162 return 0;
165 // FIXME: we could just read the appropriate mixer status field from the
166 // receive stream processor once we work out an efficient way to do this.
167 val = m_parent.ReadRegister(m_register);
168 return val & 0xff;
171 ChannelPan::ChannelPan(MotuDevice &parent, unsigned int dev_reg)
172 : MotuDiscreteCtrl(parent, dev_reg)
176 ChannelPan::ChannelPan(MotuDevice &parent, unsigned int dev_reg,
177 std::string name, std::string label, std::string descr)
178 : MotuDiscreteCtrl(parent, dev_reg, name, label, descr)
182 bool
183 ChannelPan::setValue(int v)
185 unsigned int val;
186 debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for channel pan 0x%04x to %d\n", m_register, v);
188 if (m_register == MOTU_CTRL_NONE) {
189 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
190 return true;
193 val = ((v<-64?-64:v)+64) & 0xff;
194 if (val > 0x80)
195 val = 0x80;
196 // Bit 31 indicates that pan is being set
197 val = (val << 8) | 0x80000000;
198 m_parent.WriteRegister(m_register, val);
200 return true;
204 ChannelPan::getValue()
206 unsigned int val;
207 debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for channel pan 0x%04x\n", m_register);
209 // Silently swallow attempts to read non-existent controls for now
210 if (m_register == MOTU_CTRL_NONE) {
211 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
212 return 0;
215 // FIXME: we could just read the appropriate mixer status field from the
216 // receive stream processor once we work out an efficient way to do this.
217 val = m_parent.ReadRegister(m_register);
218 return ((val >> 8) & 0xff) - 0x40;
222 MotuMatrixMixer::MotuMatrixMixer(MotuDevice &parent)
223 : Control::MatrixMixer(&parent, "MatrixMixer")
224 , m_parent(parent)
228 MotuMatrixMixer::MotuMatrixMixer(MotuDevice &parent, std::string name)
229 : Control::MatrixMixer(&parent, name)
230 , m_parent(parent)
234 void MotuMatrixMixer::addRowInfo(std::string name, unsigned int flags,
235 unsigned int address)
237 struct sSignalInfo s;
238 s.name = name;
239 s.flags = flags;
240 s.address = address;
241 m_RowInfo.push_back(s);
244 void MotuMatrixMixer::addColInfo(std::string name, unsigned int flags,
245 unsigned int address)
247 struct sSignalInfo s;
248 s.name = name;
249 s.flags = flags;
250 s.address = address;
251 m_ColInfo.push_back(s);
254 uint32_t MotuMatrixMixer::getCellRegister(const unsigned int row, const unsigned int col)
256 if (m_RowInfo.at(row).address==MOTU_CTRL_NONE ||
257 m_ColInfo.at(col).address==MOTU_CTRL_NONE)
258 return MOTU_CTRL_NONE;
259 return m_RowInfo.at(row).address + m_ColInfo.at(col).address;
262 void MotuMatrixMixer::show()
264 debugOutput(DEBUG_LEVEL_NORMAL, "MOTU matrix mixer\n");
267 std::string MotuMatrixMixer::getRowName(const int row)
269 return m_RowInfo.at(row).name;
272 std::string MotuMatrixMixer::getColName(const int col)
274 return m_ColInfo.at(col).name;
277 int MotuMatrixMixer::getRowCount()
279 return m_RowInfo.size();
282 int MotuMatrixMixer::getColCount()
284 return m_ColInfo.size();
287 ChannelFaderMatrixMixer::ChannelFaderMatrixMixer(MotuDevice &parent)
288 : MotuMatrixMixer(parent, "ChannelFaderMatrixMixer")
292 ChannelFaderMatrixMixer::ChannelFaderMatrixMixer(MotuDevice &parent, std::string name)
293 : MotuMatrixMixer(parent, name)
297 double ChannelFaderMatrixMixer::setValue(const int row, const int col, const double val)
299 uint32_t v, reg;
300 v = val<0?0:(uint32_t)val;
301 if (v > 0x80)
302 v = 0x80;
303 debugOutput(DEBUG_LEVEL_VERBOSE, "ChannelFader setValue for row %d col %d to %lf (%d)\n",
304 row, col, val, v);
305 reg = getCellRegister(row,col);
307 // Silently swallow attempts to set non-existent controls for now
308 if (reg == MOTU_CTRL_NONE) {
309 debugOutput(DEBUG_LEVEL_VERBOSE, "ignoring control marked as non-existent\n");
310 return true;
312 // Bit 30 indicates that the channel fader is being set
313 v |= 0x40000000;
314 m_parent.WriteRegister(reg, v);
316 return true;
319 double ChannelFaderMatrixMixer::getValue(const int row, const int col)
321 uint32_t val, reg;
322 reg = getCellRegister(row,col);
324 // Silently swallow attempts to read non-existent controls for now
325 if (reg == MOTU_CTRL_NONE) {
326 debugOutput(DEBUG_LEVEL_VERBOSE, "ignoring control marked as non-existent\n");
327 return 0;
329 // FIXME: we could just read the appropriate mixer status field from the
330 // receive stream processor once we work out an efficient way to do this.
331 val = m_parent.ReadRegister(reg) & 0xff;
333 debugOutput(DEBUG_LEVEL_VERBOSE, "ChannelFader getValue for row %d col %d = %u\n",
334 row, col, val);
335 return val;
338 ChannelPanMatrixMixer::ChannelPanMatrixMixer(MotuDevice &parent)
339 : MotuMatrixMixer(parent, "ChannelPanMatrixMixer")
343 ChannelPanMatrixMixer::ChannelPanMatrixMixer(MotuDevice &parent, std::string name)
344 : MotuMatrixMixer(parent, name)
348 double ChannelPanMatrixMixer::setValue(const int row, const int col, const double val)
350 uint32_t v, reg;
351 v = ((val<-64?-64:(int32_t)val)+64) & 0xff;
352 if (v > 0x80)
353 v = 0x80;
355 debugOutput(DEBUG_LEVEL_VERBOSE, "ChannelPan setValue for row %d col %d to %lf (%d)\n",
356 row, col, val, v);
357 reg = getCellRegister(row,col);
359 // Silently swallow attempts to set non-existent controls for now
360 if (reg == MOTU_CTRL_NONE) {
361 debugOutput(DEBUG_LEVEL_VERBOSE, "ignoring control marked as non-existent\n");
362 return true;
365 // Bit 31 indicates that pan is being set
366 v = (v << 8) | 0x80000000;
367 m_parent.WriteRegister(reg, v);
369 return true;
372 double ChannelPanMatrixMixer::getValue(const int row, const int col)
374 int32_t val;
375 uint32_t reg;
376 reg = getCellRegister(row,col);
378 // Silently swallow attempts to read non-existent controls for now
379 if (reg == MOTU_CTRL_NONE) {
380 debugOutput(DEBUG_LEVEL_VERBOSE, "ignoring control marked as non-existent\n");
381 return 0;
384 // FIXME: we could just read the appropriate mixer status field from the
385 // receive stream processor once we work out an efficient way to do this.
386 val = m_parent.ReadRegister(reg);
387 val = ((val >> 8) & 0xff) - 0x40;
389 debugOutput(DEBUG_LEVEL_VERBOSE, "ChannelPan getValue for row %d col %d = %u\n",
390 row, col, val);
391 return val;
394 ChannelBinSwMatrixMixer::ChannelBinSwMatrixMixer(MotuDevice &parent)
395 : MotuMatrixMixer(parent, "ChannelPanMatrixMixer")
396 , m_value_mask(0)
397 , m_setenable_mask(0)
401 /* If no "write enable" is implemented for a given switch it's safe to
402 * pass zero in to setenable_mask.
404 ChannelBinSwMatrixMixer::ChannelBinSwMatrixMixer(MotuDevice &parent, std::string name,
405 unsigned int val_mask, unsigned int setenable_mask)
406 : MotuMatrixMixer(parent, name)
407 , m_value_mask(val_mask)
408 , m_setenable_mask(setenable_mask)
412 double ChannelBinSwMatrixMixer::setValue(const int row, const int col, const double val)
414 uint32_t v, reg;
416 debugOutput(DEBUG_LEVEL_VERBOSE, "BinSw setValue for row %d col %d to %lf (%d)\n",
417 row, col, val, val==0?0:1);
418 reg = getCellRegister(row,col);
420 // Silently swallow attempts to set non-existent controls for now
421 if (reg == MOTU_CTRL_NONE) {
422 debugOutput(DEBUG_LEVEL_VERBOSE, "ignoring control marked as non-existent\n");
423 return true;
426 // Set the value
427 if (m_setenable_mask) {
428 v = (val==0)?0:m_value_mask;
429 // Set the "write enable" bit for the value being set
430 v |= m_setenable_mask;
431 } else {
432 // It would be good to utilise the cached value from the receive
433 // processor (if running) later on. For now we'll just fetch the
434 // current register value directly when needed.
435 v = m_parent.ReadRegister(reg);
436 if (v==0)
437 v &= ~m_value_mask;
438 else
439 v |= m_value_mask;
441 m_parent.WriteRegister(reg, v);
443 return true;
446 double ChannelBinSwMatrixMixer::getValue(const int row, const int col)
448 uint32_t val, reg;
449 reg = getCellRegister(row,col);
451 // Silently swallow attempts to read non-existent controls for now
452 if (reg == MOTU_CTRL_NONE) {
453 debugOutput(DEBUG_LEVEL_VERBOSE, "ignoring control marked as non-existent\n");
454 return 0;
457 // FIXME: we could just read the appropriate mixer status field from the
458 // receive stream processor once we work out an efficient way to do this.
459 val = m_parent.ReadRegister(reg);
460 val = (val & m_value_mask) != 0;
462 debugOutput(DEBUG_LEVEL_VERBOSE, "BinSw getValue for row %d col %d = %u\n",
463 row, col, val);
464 return val;
468 MixFader::MixFader(MotuDevice &parent, unsigned int dev_reg)
469 : MotuDiscreteCtrl(parent, dev_reg)
473 MixFader::MixFader(MotuDevice &parent, unsigned int dev_reg,
474 std::string name, std::string label, std::string descr)
475 : MotuDiscreteCtrl(parent, dev_reg, name, label, descr)
479 bool
480 MixFader::setValue(int v)
482 unsigned int val;
483 debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for mix fader 0x%04x to %d\n", m_register, v);
485 // Silently swallow attempts to set non-existent controls for now
486 if (m_register == MOTU_CTRL_NONE) {
487 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
488 return true;
490 val = v<0?0:v;
491 if (val > 0x80)
492 val = 0x80;
493 // Bit 24 indicates that the mix fader is being set
494 val |= 0x01000000;
495 m_parent.WriteRegister(m_register, val);
497 return true;
501 MixFader::getValue()
503 unsigned int val;
504 debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for mix fader 0x%04x\n", m_register);
506 // Silently swallow attempts to read non-existent controls for now
507 if (m_register == MOTU_CTRL_NONE) {
508 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
509 return 0;
512 // FIXME: we could just read the appropriate mixer status field from the
513 // receive stream processor once we work out an efficient way to do this.
514 val = m_parent.ReadRegister(m_register);
515 return val & 0xff;
518 MixMute::MixMute(MotuDevice &parent, unsigned int dev_reg)
519 : MotuDiscreteCtrl(parent, dev_reg)
523 MixMute::MixMute(MotuDevice &parent, unsigned int dev_reg,
524 std::string name, std::string label, std::string descr)
525 : MotuDiscreteCtrl(parent, dev_reg, name, label, descr)
529 bool
530 MixMute::setValue(int v)
532 unsigned int val, dest;
533 debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for mix mute 0x%04x to %d\n", m_register, v);
535 // Silently swallow attempts to set non-existent controls for now
536 if (m_register == MOTU_CTRL_NONE) {
537 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
538 return true;
541 // Need to read current destination so we can preserve that when setting
542 // mute status (mute and destination are always set together).
543 dest = m_parent.ReadRegister(m_register) & 0x00000f00;
544 // Mute status is bit 12
545 val = (v==0)?0:0x00001000;
546 // Bit 25 indicates that mute and destination are being set. Also
547 // preserve the current destination.
548 val |= 0x02000000 | dest;
549 m_parent.WriteRegister(m_register, val);
551 return true;
555 MixMute::getValue()
557 unsigned int val;
558 debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for mix mute 0x%04x\n", m_register);
560 // Silently swallow attempts to read non-existent controls for now
561 if (m_register == MOTU_CTRL_NONE) {
562 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
563 return 0;
566 // FIXME: we could just read the appropriate mixer status field from the
567 // receive stream processor once we work out an efficient way to do this.
568 val = m_parent.ReadRegister(m_register);
569 return (val & 0x00001000) != 0;
572 MixDest::MixDest(MotuDevice &parent, unsigned int dev_reg)
573 : MotuDiscreteCtrl(parent, dev_reg)
577 MixDest::MixDest(MotuDevice &parent, unsigned int dev_reg,
578 std::string name, std::string label, std::string descr)
579 : MotuDiscreteCtrl(parent, dev_reg, name, label, descr)
583 bool
584 MixDest::setValue(int v)
586 unsigned int val, mute;
587 debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for mix destination 0x%04x to %d\n", m_register, v);
589 // Silently swallow attempts to set non-existent controls for now
590 if (m_register == MOTU_CTRL_NONE) {
591 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
592 return true;
594 // Need to get current mute status so we can preserve it
595 mute = m_parent.ReadRegister(m_register) & 0x00001000;
596 val = v;
597 /* Currently destination values between 0 and 0x0b are accepted.
598 * Ultimately this will be device (and device configuration) dependent.
600 if (val<0 || val>0x0b)
601 val = 0;
602 /* Destination is given by bits 11-8. Add in the current mute status so
603 * it can be preserved (it's set concurrently with the destination).
605 val = (val << 8) | mute;
606 // Bit 25 indicates that mute and destination are being set
607 val |= 0x02000000;
608 m_parent.WriteRegister(m_register, val);
610 return true;
614 MixDest::getValue()
616 unsigned int val;
617 debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for mix destination 0x%04x\n", m_register);
619 // Silently swallow attempts to read non-existent controls for now
620 if (m_register == MOTU_CTRL_NONE) {
621 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
622 return true;
624 // FIXME: we could just read the appropriate mixer status field from the
625 // receive stream processor once we work out an efficient way to do this.
626 val = m_parent.ReadRegister(m_register);
627 return (val >> 8) & 0x0f;
630 PhonesSrc::PhonesSrc(MotuDevice &parent)
631 : MotuDiscreteCtrl(parent, 0)
635 PhonesSrc::PhonesSrc(MotuDevice &parent,
636 std::string name, std::string label, std::string descr)
637 : MotuDiscreteCtrl(parent, 0, name, label, descr)
641 bool
642 PhonesSrc::setValue(int v)
644 unsigned int val;
645 debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for phones destination to %d\n", v);
647 /* Currently destination values between 0 and 0x0b are accepted.
648 * Ultimately this will be device (and device configuration) dependent.
650 val = v;
651 if (val<0 || val>0x0b)
652 val = 0;
653 // Destination is given by bits 3-0.
654 // Bit 24 indicates that the phones source is being set.
655 val |= 0x01000000;
656 m_parent.WriteRegister(MOTU_REG_ROUTE_PORT_CONF, val);
658 return true;
662 PhonesSrc::getValue()
664 unsigned int val;
665 debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for phones destination\n");
667 // FIXME: we could just read the appropriate mixer status field from the
668 // receive stream processor once we work out an efficient way to do this.
669 val = m_parent.ReadRegister(MOTU_REG_ROUTE_PORT_CONF);
670 return val & 0x0f;
673 OpticalMode::OpticalMode(MotuDevice &parent, unsigned int dev_reg)
674 : MotuDiscreteCtrl(parent, dev_reg)
678 OpticalMode::OpticalMode(MotuDevice &parent, unsigned int dev_reg,
679 std::string name, std::string label, std::string descr)
680 : MotuDiscreteCtrl(parent, dev_reg, name, label, descr)
684 bool
685 OpticalMode::setValue(int v)
687 unsigned int val, dir;
688 debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for optical mode %d to %d\n", m_register, v);
690 /* Assume v is 0 for "off", 1 for "ADAT" and 2 for "Toslink" */
691 switch (v) {
692 case 0: val = MOTU_OPTICAL_MODE_OFF; break;
693 case 1: val = MOTU_OPTICAL_MODE_ADAT; break;
694 case 2: val = MOTU_OPTICAL_MODE_TOSLINK; break;
695 default: return true;
697 dir = (m_register==MOTU_CTRL_DIR_IN)?MOTU_DIR_IN:MOTU_DIR_OUT;
698 m_parent.setOpticalMode(dir, val, MOTU_OPTICAL_MODE_KEEP);
699 return true;
703 OpticalMode::getValue()
705 unsigned int dir, omode_a;
706 debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for optical mode %d\n", m_register);
708 // FIXME: we could just read the appropriate mixer status field from the
709 // receive stream processor once we work out an efficient way to do this.
710 dir = (m_register==MOTU_CTRL_DIR_IN)?MOTU_DIR_IN:MOTU_DIR_OUT;
711 m_parent.getOpticalMode(dir, &omode_a, NULL);
712 switch (omode_a) {
713 case MOTU_OPTICAL_MODE_OFF: return 0;
714 case MOTU_OPTICAL_MODE_ADAT: return 1;
715 case MOTU_OPTICAL_MODE_TOSLINK: return 2;
716 default: return 0;
718 return 0;
721 InputGainPadInv::InputGainPadInv(MotuDevice &parent, unsigned int channel, unsigned int mode)
722 : MotuDiscreteCtrl(parent, channel)
724 m_mode = mode;
725 validate();
728 InputGainPadInv::InputGainPadInv(MotuDevice &parent, unsigned int channel, unsigned int mode,
729 std::string name, std::string label, std::string descr)
730 : MotuDiscreteCtrl(parent, channel, name, label, descr)
732 m_mode = mode;
733 validate();
736 void InputGainPadInv::validate(void) {
737 if ((m_mode==MOTU_CTRL_MODE_PAD || m_mode==MOTU_CTRL_MODE_TRIMGAIN) &&
738 m_register>MOTU_CTRL_TRIMGAINPAD_MAX_CHANNEL) {
739 debugOutput(DEBUG_LEVEL_VERBOSE, "Invalid channel %d: max supported is %d, assuming 0\n",
740 m_register, MOTU_CTRL_TRIMGAINPAD_MAX_CHANNEL);
741 m_register = 0;
743 if ((m_mode==MOTU_CTRL_MODE_UL_GAIN || m_mode==MOTU_CTRL_MODE_PHASE_INV) &&
744 m_register>MOTU_CTRL_GAINPHASEINV_MAX_CHANNEL) {
745 debugOutput(DEBUG_LEVEL_VERBOSE, "Invalid ultralite channel %d: max supported is %d, assuming 0\n",
746 m_register, MOTU_CTRL_GAINPHASEINV_MAX_CHANNEL);
747 m_register = 0;
749 if (m_mode!=MOTU_CTRL_MODE_PAD && m_mode!=MOTU_CTRL_MODE_TRIMGAIN &&
750 m_mode!=MOTU_CTRL_MODE_UL_GAIN && m_mode!=MOTU_CTRL_MODE_PHASE_INV) {
751 debugOutput(DEBUG_LEVEL_VERBOSE, "Invalid mode %d, assuming %d\n", m_mode, MOTU_CTRL_MODE_PAD);
752 m_mode = MOTU_CTRL_MODE_PAD;
756 unsigned int InputGainPadInv::dev_register(void) {
757 /* Work out the device register to use for the associated channel */
758 /* Registers for gain/phase inversion controls on the Ultralite differ from those
759 * of other devices.
761 if (m_mode==MOTU_CTRL_MODE_PAD || m_mode==MOTU_CTRL_MODE_TRIMGAIN) {
762 if (m_register>=0 && m_register<=3) {
763 return MOTU_REG_INPUT_GAIN_PAD_0;
764 } else {
765 debugOutput(DEBUG_LEVEL_VERBOSE, "unsupported channel %d\n", m_register);
767 } else {
768 if (m_register>=0 && m_register<=3)
769 return MOTU_REG_INPUT_GAIN_PHINV0;
770 else if (m_register>=4 && m_register<=7)
771 return MOTU_REG_INPUT_GAIN_PHINV1;
772 else if (m_register>=8 && m_register<=11)
773 return MOTU_REG_INPUT_GAIN_PHINV2;
774 else {
775 debugOutput(DEBUG_LEVEL_VERBOSE, "unsupported ultralite channel %d\n", m_register);
778 return 0;
781 bool
782 InputGainPadInv::setValue(int v)
784 unsigned int val;
785 unsigned int reg, reg_shift;
786 debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for mode %d input pad/trim %d to %d\n", m_mode, m_register, v);
788 if (m_register == MOTU_CTRL_NONE) {
789 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
790 return true;
793 reg = dev_register();
794 if (reg == 0)
795 return false;
796 reg_shift = (m_register & 0x03) * 8;
798 // Need to get current gain trim / pad value so we can preserve one
799 // while setting the other. The pad status is in bit 6 of the channel's
800 // respective byte with the trim in bits 0-5. Bit 7 is the write enable
801 // bit for the channel.
802 val = m_parent.ReadRegister(reg) & (0xff << reg_shift);
804 switch (m_mode) {
805 case MOTU_CTRL_MODE_PAD:
806 case MOTU_CTRL_MODE_PHASE_INV:
807 // Set pad/phase inversion bit (bit 6 of relevant channel's byte)
808 if (v == 0) {
809 val &= ~(0x40 << reg_shift);
810 } else {
811 val |= (0x40 << reg_shift);
813 break;
814 case MOTU_CTRL_MODE_TRIMGAIN:
815 case MOTU_CTRL_MODE_UL_GAIN:
816 // Set the gain trim (bits 0-5 of the channel's byte). Maximum
817 // gain is 53 dB for trimgain on non-ultralite devices. For
818 // ultralites, mic inputs max out at 0x18, line inputs at 0x12
819 // and spdif inputs at 0x0c. We just clip at 0x18 for now.
820 if (m_mode==MOTU_CTRL_MODE_TRIMGAIN) {
821 if (v > 0x35)
822 v = 0x35;
823 } else {
824 if (v > 0x18)
825 v = 0x18;
827 val = (val & ~(0x3f << reg_shift)) | (v << reg_shift);
828 break;
829 default:
830 debugOutput(DEBUG_LEVEL_VERBOSE, "unsupported mode %d\n", m_mode);
831 return false;
834 // Set the channel's write enable bit
835 val |= (0x80 << reg_shift);
837 m_parent.WriteRegister(reg, val);
839 return true;
843 InputGainPadInv::getValue()
845 unsigned int val;
846 unsigned int reg, reg_shift;
847 debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for mode %d input pad/trim %d\n", m_mode, m_register);
849 if (m_register == MOTU_CTRL_NONE) {
850 debugOutput(DEBUG_LEVEL_WARNING, "use of MOTU_CTRL_NONE in non-matrix control\n");
851 return 0;
854 reg = dev_register();
855 if (reg == 0)
856 return false;
857 reg_shift = (m_register & 0x03) * 8;
859 // The pad/phase inversion status is in bit 6 of the channel's
860 // respective byte with the trim in bits 0-5. Bit 7 is the write enable
861 // bit for the channel.
862 val = m_parent.ReadRegister(reg);
864 switch (m_mode) {
865 case MOTU_CTRL_MODE_PAD:
866 case MOTU_CTRL_MODE_PHASE_INV:
867 val = ((val >> reg_shift) & 0x40) != 0;
868 break;
869 case MOTU_CTRL_MODE_TRIMGAIN:
870 case MOTU_CTRL_MODE_UL_GAIN:
871 val = ((val >> reg_shift) & 0x3f);
872 break;
873 default:
874 debugOutput(DEBUG_LEVEL_VERBOSE, "unsupported mode %d\n", m_mode);
875 return 0;
878 return val;
881 MeterControl::MeterControl(MotuDevice &parent, unsigned int ctrl_mask, unsigned int ctrl_shift)
882 : MotuDiscreteCtrl(parent, ctrl_mask)
884 m_shift = ctrl_shift;
885 validate();
888 MeterControl::MeterControl(MotuDevice &parent, unsigned int ctrl_mask, unsigned int ctrl_shift,
889 std::string name, std::string label, std::string descr)
890 : MotuDiscreteCtrl(parent, ctrl_mask, name, label, descr)
892 m_shift = ctrl_shift;
893 validate();
896 void MeterControl::validate(void) {
897 if ((m_register & (1<< m_shift)) == 0) {
898 debugOutput(DEBUG_LEVEL_VERBOSE, "Inconsistent mask/shift: 0x%08x/%d\n", m_register, m_shift);
902 bool
903 MeterControl::setValue(int v)
905 unsigned int val;
906 debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for meter control 0x%08x/%d: %d\n",
907 m_register, m_shift, v);
909 // Need to get current register setting so we can preserve the parts not
910 // being controlled by this object. m_register holds the mask for the
911 // parts we're changing.
912 val = m_parent.ReadRegister(MOTU_REG_896HD_METER_CONF) & ~m_register;
913 val |= (v << m_shift) & m_register;
915 m_parent.WriteRegister(MOTU_REG_896HD_METER_CONF, val);
917 // Drivers under other OSes set MOTU_REG_896HD_METER_REG (0x0b1c) to
918 // 0x0400 whenever MOTU_REG_896HD_METER_CONF (0x0b24) is changed.
919 // There's no obvious reason why they do this, but since it's no hassle
920 // we might as well do the same.
921 m_parent.WriteRegister(MOTU_REG_896HD_METER_REG, 0x0400);
923 return true;
927 MeterControl::getValue()
929 unsigned int val;
930 debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for meter control 0x%08x/%d\n",
931 m_register, m_shift);
933 // m_register holds the mask of the part of interest
934 val = (m_parent.ReadRegister(MOTU_REG_896HD_METER_CONF) & m_register) >> m_shift;
936 return val;
939 InfoElement::InfoElement(MotuDevice &parent, unsigned infotype)
940 : MotuDiscreteCtrl(parent, infotype)
944 InfoElement::InfoElement(MotuDevice &parent, unsigned infotype,
945 std::string name, std::string label, std::string descr)
946 : MotuDiscreteCtrl(parent, infotype, name, label, descr)
950 bool
951 InfoElement::setValue(int v)
953 /* This is a read-only field, so any call to setValue() is technically
954 * an error.
956 debugOutput(DEBUG_LEVEL_VERBOSE, "InfoElement (%d) is read-only\n", m_register);
957 return false;
961 InfoElement::getValue()
963 unsigned int val;
964 signed int res = 0;
966 switch (m_register) {
967 case MOTU_INFO_MODEL:
968 res = m_parent.m_motu_model;
969 debugOutput(DEBUG_LEVEL_VERBOSE, "Model: %d\n", res);
970 break;
971 case MOTU_INFO_IS_STREAMING:
972 val = m_parent.ReadRegister(MOTU_REG_ISOCTRL);
973 /* Streaming is active if either bit 22 (Motu->PC streaming
974 * enable) or bit 30 (PC->Motu streaming enable) is set.
976 res = (val & 0x40400000) != 0;
977 debugOutput(DEBUG_LEVEL_VERBOSE, "IsStreaming: %d (reg=%08x)\n", res, val);
978 break;
979 case MOTU_INFO_SAMPLE_RATE:
980 res = m_parent.getSamplingFrequency();
981 debugOutput(DEBUG_LEVEL_VERBOSE, "SampleRate: %d\n", res);
982 break;
984 return res;