root/trunk/libffado/src/motu/motu_controls.cpp

Revision 1831, 29.6 kB (checked in by jwoithe, 14 years ago)

MOTU: make optical mode control API easier to use when support for devices with multiple optical ports is added.

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  * Copyright (C) 2008-2009 by Jonathan Woithe
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB.
9  *
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.
14  *
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.
19  *
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/>.
22  *
23  */
24
25 // This also includes motu_controls.h
26 #include "motu_avdevice.h"
27
28 namespace Motu {
29
30 MotuDiscreteCtrl::MotuDiscreteCtrl(MotuDevice &parent, unsigned int dev_reg)
31 : Control::Discrete(&parent)
32 , m_parent(parent)
33 , m_register(dev_reg)
34 {
35 }
36
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)
42 {
43     setName(name);
44     setLabel(label);
45     setDescription(descr);
46 }
47
48 MotuBinarySwitch::MotuBinarySwitch(MotuDevice &parent, unsigned int dev_reg,
49   unsigned int val_mask, unsigned int setenable_mask)
50 : MotuDiscreteCtrl(parent, dev_reg)
51 {
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.
55      */
56     m_setenable_mask = setenable_mask;
57 }
58
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)
63 {
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.
67      */
68     m_setenable_mask = setenable_mask;
69 }
70              
71 bool
72 MotuBinarySwitch::setValue(int v)
73 {
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);
77
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;
81     }
82
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;
97     }
98     m_parent.WriteRegister(m_register, val);
99
100     return true;
101 }
102
103 int
104 MotuBinarySwitch::getValue()
105 {
106     unsigned int val;
107     debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for switch %s (0x%04x)\n",
108       getName().c_str(), m_register);
109
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;
113     }
114
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;
119 }
120
121 ChannelFader::ChannelFader(MotuDevice &parent, unsigned int dev_reg)
122 : MotuDiscreteCtrl(parent, dev_reg)
123 {
124 }
125
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)
129 {
130 }
131              
132 bool
133 ChannelFader::setValue(int v)
134 {
135     unsigned int val;
136     debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for channel fader 0x%04x to %d\n", m_register, v);
137
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;
141     }
142
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);
149
150     return true;
151 }
152
153 int
154 ChannelFader::getValue()
155 {
156     unsigned int val;
157     debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for channel fader 0x%04x\n", m_register);
158
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;
163     }
164
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;
169 }
170
171 ChannelPan::ChannelPan(MotuDevice &parent, unsigned int dev_reg)
172 : MotuDiscreteCtrl(parent, dev_reg)
173 {
174 }
175
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)
179 {
180 }
181              
182 bool
183 ChannelPan::setValue(int v)
184 {
185     unsigned int val;
186     debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for channel pan 0x%04x to %d\n", m_register, v);
187
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;
191     }
192
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);
199
200     return true;
201 }
202
203 int
204 ChannelPan::getValue()
205 {
206     unsigned int val;
207     debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for channel pan 0x%04x\n", m_register);
208
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;
213     }
214
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;
219 }
220
221
222 MotuMatrixMixer::MotuMatrixMixer(MotuDevice &parent)
223 : Control::MatrixMixer(&parent, "MatrixMixer")
224 , m_parent(parent)
225 {
226 }
227
228 MotuMatrixMixer::MotuMatrixMixer(MotuDevice &parent, std::string name)
229 : Control::MatrixMixer(&parent, name)
230 , m_parent(parent)
231 {
232 }
233
234 void MotuMatrixMixer::addRowInfo(std::string name, unsigned int flags,
235   unsigned int address)
236 {
237     struct sSignalInfo s;
238     s.name = name;
239     s.flags = flags;
240     s.address = address;
241     m_RowInfo.push_back(s);
242 }
243
244 void MotuMatrixMixer::addColInfo(std::string name, unsigned int flags,
245   unsigned int address)
246 {
247     struct sSignalInfo s;
248     s.name = name;
249     s.flags = flags;
250     s.address = address;
251     m_ColInfo.push_back(s);
252 }
253
254 uint32_t MotuMatrixMixer::getCellRegister(const unsigned int row, const unsigned int col)
255 {
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;
260 }
261
262 void MotuMatrixMixer::show()
263 {
264     debugOutput(DEBUG_LEVEL_NORMAL, "MOTU matrix mixer\n");
265 }
266
267 std::string MotuMatrixMixer::getRowName(const int row)
268 {
269     return m_RowInfo.at(row).name;
270 }
271
272 std::string MotuMatrixMixer::getColName(const int col)
273 {
274     return m_ColInfo.at(col).name;
275 }
276
277 int MotuMatrixMixer::getRowCount()
278 {
279     return m_RowInfo.size();
280 }
281
282 int MotuMatrixMixer::getColCount()
283 {
284     return m_ColInfo.size();
285 }
286
287 ChannelFaderMatrixMixer::ChannelFaderMatrixMixer(MotuDevice &parent)
288 : MotuMatrixMixer(parent, "ChannelFaderMatrixMixer")
289 {
290 }
291
292 ChannelFaderMatrixMixer::ChannelFaderMatrixMixer(MotuDevice &parent, std::string name)
293 : MotuMatrixMixer(parent, name)
294 {
295 }
296
297 double ChannelFaderMatrixMixer::setValue(const int row, const int col, const double val)
298 {
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);
306
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;
311     }
312     // Bit 30 indicates that the channel fader is being set
313     v |= 0x40000000;
314     m_parent.WriteRegister(reg, v);
315
316     return true;
317 }
318
319 double ChannelFaderMatrixMixer::getValue(const int row, const int col)
320 {
321     uint32_t val, reg;
322     reg = getCellRegister(row,col);
323
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;
328     }
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;
332
333     debugOutput(DEBUG_LEVEL_VERBOSE, "ChannelFader getValue for row %d col %d = %u\n",
334       row, col, val);
335     return val;
336 }
337
338 ChannelPanMatrixMixer::ChannelPanMatrixMixer(MotuDevice &parent)
339 : MotuMatrixMixer(parent, "ChannelPanMatrixMixer")
340 {
341 }
342
343 ChannelPanMatrixMixer::ChannelPanMatrixMixer(MotuDevice &parent, std::string name)
344 : MotuMatrixMixer(parent, name)
345 {
346 }
347
348 double ChannelPanMatrixMixer::setValue(const int row, const int col, const double val)
349 {
350     uint32_t v, reg;
351     v = ((val<-64?-64:(int32_t)val)+64) & 0xff;
352     if (v > 0x80)
353       v = 0x80;
354
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);
358
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;
363     }
364
365     // Bit 31 indicates that pan is being set
366     v = (v << 8) | 0x80000000;
367     m_parent.WriteRegister(reg, v);
368
369     return true;
370 }
371
372 double ChannelPanMatrixMixer::getValue(const int row, const int col)
373 {
374     int32_t val;
375     uint32_t reg;
376     reg = getCellRegister(row,col);
377
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;
382     }
383
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;
388
389     debugOutput(DEBUG_LEVEL_VERBOSE, "ChannelPan getValue for row %d col %d = %u\n",
390       row, col, val);
391     return val;
392 }
393
394 ChannelBinSwMatrixMixer::ChannelBinSwMatrixMixer(MotuDevice &parent)
395 : MotuMatrixMixer(parent, "ChannelPanMatrixMixer")
396 , m_value_mask(0)
397 , m_setenable_mask(0)
398 {
399 }
400
401 /* If no "write enable" is implemented for a given switch it's safe to
402  * pass zero in to setenable_mask.
403  */
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)
409 {
410 }
411
412 double ChannelBinSwMatrixMixer::setValue(const int row, const int col, const double val)
413 {
414     uint32_t v, reg;
415
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);
419
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;
424     }
425
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;
440     }
441     m_parent.WriteRegister(reg, v);
442
443     return true;
444 }
445
446 double ChannelBinSwMatrixMixer::getValue(const int row, const int col)
447 {
448     uint32_t val, reg;
449     reg = getCellRegister(row,col);
450
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;
455     }
456
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;
461
462     debugOutput(DEBUG_LEVEL_VERBOSE, "BinSw getValue for row %d col %d = %u\n",
463       row, col, val);
464     return val;
465 }
466
467
468 MixFader::MixFader(MotuDevice &parent, unsigned int dev_reg)
469 : MotuDiscreteCtrl(parent, dev_reg)
470 {
471 }
472
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)
476 {
477 }
478              
479 bool
480 MixFader::setValue(int v)
481 {
482     unsigned int val;
483     debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for mix fader 0x%04x to %d\n", m_register, v);
484
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;
489     }
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);
496
497     return true;
498 }
499
500 int
501 MixFader::getValue()
502 {
503     unsigned int val;
504     debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for mix fader 0x%04x\n", m_register);
505
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;
510     }
511
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;
516 }
517
518 MixMute::MixMute(MotuDevice &parent, unsigned int dev_reg)
519 : MotuDiscreteCtrl(parent, dev_reg)
520 {
521 }
522
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)
526 {
527 }
528              
529 bool
530 MixMute::setValue(int v)
531 {
532     unsigned int val, dest;
533     debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for mix mute 0x%04x to %d\n", m_register, v);
534
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;
539     }
540
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);
550
551     return true;
552 }
553
554 int
555 MixMute::getValue()
556 {
557     unsigned int val;
558     debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for mix mute 0x%04x\n", m_register);
559
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;
564     }
565
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;
570 }
571
572 MixDest::MixDest(MotuDevice &parent, unsigned int dev_reg)
573 : MotuDiscreteCtrl(parent, dev_reg)
574 {
575 }
576
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)
580 {
581 }
582              
583 bool
584 MixDest::setValue(int v)
585 {
586     unsigned int val, mute;
587     debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for mix destination 0x%04x to %d\n", m_register, v);
588
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;
593     }
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.
599      */
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).
604      */
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);
609
610     return true;
611 }
612
613 int
614 MixDest::getValue()
615 {
616     unsigned int val;
617     debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for mix destination 0x%04x\n", m_register);
618
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;
623     }
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;
628 }
629
630 PhonesSrc::PhonesSrc(MotuDevice &parent)
631 : MotuDiscreteCtrl(parent, 0)
632 {
633 }
634
635 PhonesSrc::PhonesSrc(MotuDevice &parent,
636              std::string name, std::string label, std::string descr)
637 : MotuDiscreteCtrl(parent, 0, name, label, descr)
638 {
639 }
640              
641 bool
642 PhonesSrc::setValue(int v)
643 {
644     unsigned int val;
645     debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for phones destination to %d\n", v);
646
647     /* Currently destination values between 0 and 0x0b are accepted.
648      * Ultimately this will be device (and device configuration) dependent.
649      */
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);
657
658     return true;
659 }
660
661 int
662 PhonesSrc::getValue()
663 {
664     unsigned int val;
665     debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for phones destination\n");
666
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;
671 }
672
673 OpticalMode::OpticalMode(MotuDevice &parent, unsigned int dev_reg)
674 : MotuDiscreteCtrl(parent, dev_reg)
675 {
676 }
677
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)
681 {
682 }
683              
684 bool
685 OpticalMode::setValue(int v)
686 {
687     unsigned int val, dir;
688     debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for optical mode %d to %d\n", m_register, v);
689
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;
696     }
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;
700 }
701
702 int
703 OpticalMode::getValue()
704 {
705     unsigned int dir, omode_a;
706     debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for optical mode %d\n", m_register);
707
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;
717     }
718     return 0;
719 }
720
721 InputGainPadInv::InputGainPadInv(MotuDevice &parent, unsigned int channel, unsigned int mode)
722 : MotuDiscreteCtrl(parent, channel)
723 {
724     m_mode = mode;
725     validate();
726 }
727
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)
731 {
732     m_mode = mode;
733     validate();
734 }
735
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;
742     }
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;
748     }
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;
753     }
754 }
755
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.
760      */
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);
766        }
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);
776        }
777     }
778     return 0;
779 }
780              
781 bool
782 InputGainPadInv::setValue(int v)
783 {
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);
787
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;
791     }
792
793     reg = dev_register();
794     if (reg == 0)
795         return false;
796     reg_shift = (m_register & 0x03) * 8;
797
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);
803
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);
812             }
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;
826             }
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;
832     }
833
834     // Set the channel's write enable bit
835     val |= (0x80 << reg_shift);
836
837     m_parent.WriteRegister(reg, val);
838
839     return true;
840 }
841
842 int
843 InputGainPadInv::getValue()
844 {
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);
848
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;
852     }
853
854     reg = dev_register();
855     if (reg == 0)
856         return false;
857     reg_shift = (m_register & 0x03) * 8;
858
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);
863
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;
876     }
877
878     return val;
879 }
880
881 MeterControl::MeterControl(MotuDevice &parent, unsigned int ctrl_mask, unsigned int ctrl_shift)
882 : MotuDiscreteCtrl(parent, ctrl_mask)
883 {
884     m_shift = ctrl_shift;
885     validate();
886 }
887
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)
891 {
892     m_shift = ctrl_shift;
893     validate();
894 }
895
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);
899     }
900 }
901
902 bool
903 MeterControl::setValue(int v)
904 {
905     unsigned int val;
906     debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for meter control 0x%08x/%d: %d\n",
907         m_register, m_shift, v);
908
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;
914
915     m_parent.WriteRegister(MOTU_REG_896HD_METER_CONF, val);
916
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);
922
923     return true;
924 }
925
926 int
927 MeterControl::getValue()
928 {
929     unsigned int val;
930     debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for meter control 0x%08x/%d\n",
931         m_register, m_shift);
932
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;
935
936     return val;
937 }
938
939 InfoElement::InfoElement(MotuDevice &parent, unsigned infotype)
940 : MotuDiscreteCtrl(parent, infotype)
941 {
942 }
943
944 InfoElement::InfoElement(MotuDevice &parent, unsigned infotype,
945              std::string name, std::string label, std::string descr)
946 : MotuDiscreteCtrl(parent, infotype, name, label, descr)
947 {
948 }
949              
950 bool
951 InfoElement::setValue(int v)
952 {
953     /* This is a read-only field, so any call to setValue() is technically
954      * an error.
955      */
956     debugOutput(DEBUG_LEVEL_VERBOSE, "InfoElement (%d) is read-only\n", m_register);
957     return false;
958 }
959
960 int
961 InfoElement::getValue()
962 {
963     unsigned int val;
964     signed int res = 0;
965
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.
975              */
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;
983     }
984     return res;
985 }
986
987 }
Note: See TracBrowser for help on using the browser.