motu: report the optical control register read from the device when obtaining the...
[ffado.git] / libffado / src / motu / motu_avdevice.cpp
blobd065f17f9db5e2448e0e6a27c010cf1aebbf7e7f
1 /*
2 * Copyright (C) 2005-2008 by Pieter Palmers
3 * Copyright (C) 2005-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 #include "config.h"
27 #include "motu/motu_avdevice.h"
28 #include "motu/motu_mixerdefs.h"
29 #include "motu/motu_mark3_mixerdefs.h"
31 #include "devicemanager.h"
33 #include "libieee1394/configrom.h"
34 #include "libieee1394/ieee1394service.h"
36 #include "libavc/avc_definitions.h"
38 #include "debugmodule/debugmodule.h"
40 #include "libstreaming/motu/MotuReceiveStreamProcessor.h"
41 #include "libstreaming/motu/MotuTransmitStreamProcessor.h"
42 #include "libstreaming/motu/MotuPort.h"
44 #include "libutil/Time.h"
45 #include "libutil/Configuration.h"
47 #include "libcontrol/BasicElements.h"
49 #include <string>
50 #include <stdint.h>
51 #include <assert.h>
52 #include "libutil/ByteSwap.h"
53 #include <iostream>
54 #include <sstream>
56 #include <libraw1394/csr.h>
58 // FIXME: this allows for easy switching between the old PortEntry and
59 // new PortEntryGroup methods of identifying audio streams in the iso
60 // packets sent to/from the MOTU interfaces. Leave undefined to use
61 // the old method.
63 #define USE_PORTGROUPS
66 namespace Motu {
68 // Define the supported devices. Device ordering is arbitary here. To include a MOTU
69 // device which cannot yet be used (for identification purposes only), set the model
70 // field to MOTU_MODEL_NONE.
72 // The V4HD device includes 4 sub-devices. Include all in the definition as a way
73 // of documenting it. It's likely that only one of these is of interest for audio
74 // but that's still to be determined.
75 static VendorModelEntry supportedDeviceList[] =
77 // {vendor_id, model_id, unit_version, unit_specifier_id, model, vendor_name,model_name}
78 {FW_VENDORID_MOTU, 0, 0x00000003, 0x000001f2, MOTU_MODEL_828mkII, "MOTU", "828MkII"},
79 {FW_VENDORID_MOTU, 0, 0x00000009, 0x000001f2, MOTU_MODEL_TRAVELER, "MOTU", "Traveler"},
80 {FW_VENDORID_MOTU, 0, 0x0000000d, 0x000001f2, MOTU_MODEL_ULTRALITE, "MOTU", "UltraLite"},
81 {FW_VENDORID_MOTU, 0, 0x0000000f, 0x000001f2, MOTU_MODEL_8PRE, "MOTU", "8pre"},
82 {FW_VENDORID_MOTU, 0, 0x00000001, 0x000001f2, MOTU_MODEL_828MkI, "MOTU", "828MkI"},
83 {FW_VENDORID_MOTU, 0, 0x00000005, 0x000001f2, MOTU_MODEL_896HD, "MOTU", "896HD"},
84 {FW_VENDORID_MOTU, 0, 0x00000015, 0x000001f2, MOTU_MODEL_828mk3, "MOTU", "828Mk3"},
85 {FW_VENDORID_MOTU, 0, 0x00000017, 0x000001f2, MOTU_MODEL_896mk3, "MOTU", "896Mk3"},
86 {FW_VENDORID_MOTU, 0, 0x00000019, 0x000001f2, MOTU_MODEL_ULTRALITEmk3, "MOTU", "UltraLiteMk3"},
87 {FW_VENDORID_MOTU, 0, 0x0000001b, 0x000001f2, MOTU_MODEL_TRAVELERmk3, "MOTU", "TravelerMk3"},
88 {FW_VENDORID_MOTU, 0, 0x00000021, 0x000001f2, MOTU_MODEL_NONE, "MOTU", "V4HD subdevice 0"},
89 {FW_VENDORID_MOTU, 0, 0x00000022, 0x000001f2, MOTU_MODEL_NONE, "MOTU", "V4HD subdevice 1"},
90 {FW_VENDORID_MOTU, 0, 0x00000023, 0x000001f2, MOTU_MODEL_NONE, "MOTU", "V4HD subdevice 2"},
91 {FW_VENDORID_MOTU, 0, 0x00000024, 0x000001f2, MOTU_MODEL_NONE, "MOTU", "V4HD subdevice 3"},
92 {FW_VENDORID_MOTU, 0, 0x00000030, 0x000001f2, MOTU_MODEL_ULTRALITEmk3_HYB, "MOTU", "UltraLiteMk3-hybrid"},
95 // Ports declarations
96 const PortEntry Ports_828MKI[] =
98 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4},
99 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 7},
100 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
101 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
102 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
103 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
104 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
105 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
106 {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 52},
107 {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 55},
108 {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 28},
109 {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 31},
110 {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 34},
111 {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 37},
112 {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 40},
113 {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 43},
114 {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 46},
115 {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 49},
118 const PortEntry Ports_896HD[] =
120 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
121 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
122 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
123 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
124 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 16},
125 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 10},
126 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 19},
127 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 13},
128 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 22},
129 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 16},
130 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 25},
131 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 19},
132 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 28},
133 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 22},
134 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 31},
135 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 25},
136 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 34},
137 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 28},
138 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 37},
139 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 31},
140 {"MainOut-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
141 {"MainOut-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
142 {"unknown-1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
143 {"unknown-2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
144 {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 46},
145 {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 49},
146 {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 52},
147 {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 55},
148 {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 58},
149 {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 61},
150 {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
151 {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
152 // AES/EBU location with ADAT active
153 {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
154 {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
155 {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, 58},
156 {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, 61},
157 // AES/EBU location with no ADAT active
158 {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF, 46},
159 {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF, 49},
162 const PortEntry Ports_828MKII[] =
164 {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
165 {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
166 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
167 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
168 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
169 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
170 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
171 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
172 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
173 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
174 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
175 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
176 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
177 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
178 {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
179 {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
180 {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 46},
181 {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 49},
182 {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 52},
183 {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 55},
184 {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 58},
185 {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 61},
186 {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
187 {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
188 {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
189 {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
192 const PortEntry Ports_TRAVELER[] =
194 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
195 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
196 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
197 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
198 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 16},
199 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 10},
200 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 19},
201 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 13},
202 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 22},
203 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 16},
204 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 25},
205 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 19},
206 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 28},
207 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 22},
208 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 31},
209 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 25},
210 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 34},
211 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 28},
212 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 37},
213 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 31},
214 {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
215 {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
216 {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_OPTICAL_ADAT, 46},
217 {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_OPTICAL_ADAT, 49},
218 {"Toslink1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 46},
219 {"Toslink2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 49},
220 {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 52},
221 {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 55},
222 {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 58},
223 {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 61},
224 {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
225 {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
226 {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
227 {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
230 const PortEntry Ports_ULTRALITE[] =
232 {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
233 {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
234 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
235 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
236 {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
237 {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
238 {"Analog1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
239 {"Analog2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
240 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
241 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
242 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
243 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
244 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
245 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
246 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
247 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
248 {"SPDIF1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
249 {"SPDIF2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
250 {"Padding1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 46},
251 {"Padding2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 49},
252 {"SPDIF1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 46},
253 {"SPDIF2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 49},
256 const PortEntry Ports_8PRE[] =
258 {"Analog1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
259 {"Analog2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
260 {"Analog3", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
261 {"Analog4", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
262 {"Analog5", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
263 {"Analog6", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
264 {"Analog7", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
265 {"Analog8", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
266 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
267 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
268 {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
269 {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
270 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
271 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
272 {"Padding1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_OFF|MOTU_PA_PADDING, 22},
273 {"Padding2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_OFF|MOTU_PA_PADDING, 25},
274 {"ADAT1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 40},
275 {"ADAT1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 22},
276 {"ADAT2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 43},
277 {"ADAT2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 25},
278 {"ADAT3", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 46},
279 {"ADAT3", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 28},
280 {"ADAT4", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 49},
281 {"ADAT4", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 31},
282 {"ADAT5", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 52},
283 {"ADAT5", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 34},
284 {"ADAT6", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 55},
285 {"ADAT6", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 37},
286 {"ADAT7", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 58},
287 {"ADAT7", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 40},
288 {"ADAT8", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 61},
289 {"ADAT8", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 43},
292 const PortEntry Ports_828mk3[] =
294 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 10},
295 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 13},
296 {"Unknown-L", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 10},
297 {"Unknown-R", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 13},
298 {"Mic-1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 10},
299 {"Mic-2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 13},
300 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 16},
301 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 19},
302 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 22},
303 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 25},
304 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 28},
305 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 31},
306 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 34},
307 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 37},
308 {"MainOut-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 40},
309 {"MainOut-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 43},
310 {"Return-1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 40},
311 {"Return-2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 43},
312 {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 46},
313 {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 49},
314 {"Unknown-1", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 46},
315 {"Unknown-2", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 49},
316 {"Reverb-1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 52},
317 {"Reverb-2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 55},
319 // Optical port locations are a bit messy with the Mark 3 devices since
320 // there are two optical ports whose modes can be independently set.
321 // First take care of the output direction.
323 {"Toslink-A1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 52},
324 {"Toslink-A2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 55},
325 {"ADAT-A1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 52},
326 {"ADAT-A2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 55},
327 {"ADAT-A3", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 58},
328 {"ADAT-A4", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 61},
329 {"ADAT-A5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 64},
330 {"ADAT-A6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 67},
331 {"ADAT-A7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 70},
332 {"ADAT-A8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 73},
334 {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 52},
335 {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 55},
336 {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 58},
337 {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 61},
338 {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 76},
339 {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 79},
340 {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 64},
341 {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 67},
342 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 76},
343 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 79},
344 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 82},
345 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 85},
346 {"ADAT-B5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 88},
347 {"ADAT-B6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 91},
348 {"ADAT-B7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 94},
349 {"ADAT-B8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 97},
350 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 64},
351 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 67},
352 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 70},
353 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 73},
355 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 58},
356 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 61},
357 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 64},
358 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 67},
359 {"ADAT-B5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 70},
360 {"ADAT-B6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 73},
361 {"ADAT-B7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 76},
362 {"ADAT-B8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 79},
363 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 58},
364 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 61},
365 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 64},
366 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 67},
368 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 52},
369 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 55},
370 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 58},
371 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 61},
372 {"ADAT-B5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 64},
373 {"ADAT-B6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 67},
374 {"ADAT-B7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 70},
375 {"ADAT-B8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 73},
376 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 52},
377 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 55},
378 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 58},
379 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 61},
381 // Now deal with the input side of things. Firstly comes two channels
382 // which are yet to be identified at 1x rates.
383 {"Unknown-1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 58},
384 {"Unknown-2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 61},
386 // Follow up with the optical input port details.
388 {"Toslink-A1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 64},
389 {"Toslink-A2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 67},
390 {"Toslink-A1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 58},
391 {"Toslink-A2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 61},
392 {"ADAT-A1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 64},
393 {"ADAT-A2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 67},
394 {"ADAT-A3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 70},
395 {"ADAT-A4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 73},
396 {"ADAT-A5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 76},
397 {"ADAT-A6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 79},
398 {"ADAT-A7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 82},
399 {"ADAT-A8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 85},
400 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 88},
401 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 91},
402 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 94},
403 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 97},
404 {"ADAT-B5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 100},
405 {"ADAT-B6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 103},
406 {"ADAT-B7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 106},
407 {"ADAT-B8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 109},
408 {"ADAT-A1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 58},
409 {"ADAT-A2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 61},
410 {"ADAT-A3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 64},
411 {"ADAT-A4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 67},
412 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 70},
413 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 73},
414 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 76},
415 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 79},
416 {"Unknown-3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 82},
417 {"Unknown-4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 85},
419 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 64},
420 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 67},
421 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 58},
422 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 61},
423 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 70},
424 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 73},
425 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 64},
426 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 67},
427 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 88},
428 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 91},
429 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 70},
430 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 73},
431 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 64},
432 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 67},
433 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 70},
434 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 73},
435 {"ADAT-B5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 76},
436 {"ADAT-B6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 79},
437 {"ADAT-B7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 82},
438 {"ADAT-B8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 85},
439 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 58},
440 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 61},
441 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 64},
442 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 67},
443 {"Unknown-3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 70},
444 {"Unknown-4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 73},
446 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 70},
447 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 73},
448 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 76},
449 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 79},
450 {"ADAT-B5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 82},
451 {"ADAT-B6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 85},
452 {"ADAT-B7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 88},
453 {"ADAT-B8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 91},
454 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 64},
455 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 67},
456 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 70},
457 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 73},
458 {"Unknown-3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 76},
459 {"Unknown-4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 79},
463 const PortEntry Ports_ULTRALITEmk3[] =
465 {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
466 {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
467 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
468 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
469 {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
470 {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
471 {"Analog1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
472 {"Analog2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
473 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
474 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
475 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
476 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
477 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
478 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
479 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
480 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
481 {"SPDIF1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
482 {"SPDIF2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
483 {"Padding1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 46},
484 {"Padding2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 49},
485 {"SPDIF1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 46},
486 {"SPDIF2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 49},
489 const PortEntry Ports_ULTRALITEmk3_hybrid[] =
491 {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
492 {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
493 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
494 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
495 {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
496 {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
497 {"Analog1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
498 {"Analog2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
499 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
500 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
501 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
502 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
503 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
504 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
505 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
506 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
507 {"SPDIF1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
508 {"SPDIF2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
509 {"Reverb1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 46},
510 {"Reverb2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 49},
511 {"Unknown1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 52},
512 {"Unknown2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 55},
513 {"Unknown3", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 58},
514 {"Unknown4", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 61},
516 {"SPDIF1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 46},
517 {"SPDIF2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 49},
520 /* FIXME: as of 5 Aug 2010 this is still under development */
521 const PortEntry Ports_TRAVELERmk3[] =
523 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 10},
524 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 13},
525 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 10},
526 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 13},
527 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 16},
528 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 19},
529 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 22},
530 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 25},
531 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 28},
532 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 31},
533 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 34},
534 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 37},
535 {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 40},
536 {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 43},
537 {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 46},
538 {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 49},
539 {"Reverb1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 52},
540 {"Reverb2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 55},
541 {"Unknown1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 58},
542 {"Unknown2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 61},
544 // FIXME: optical port details to be filled in later.
545 #if 0
546 {"Toslink1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 46},
547 {"Toslink2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 49},
548 {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 52},
549 {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 55},
550 {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 58},
551 {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 61},
552 {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
553 {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
554 {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
555 {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
556 #endif
559 // FIXME: The following tables relate to the new PortGroupEntry mechanism,
560 // used to convey the same information as the old PortEntry tables but in a
561 // more compact and maintainable form. These aren't actually used yet since
562 // the functionality of addDirPortGroups() still needs to be tested. Once
563 // this is done, all calls to addDirPorts() will be replaced with calls to
564 // addDirPortGroups(). After this is working the old PortEntry tables can
565 // be removed.
567 PortGroupEntry PortGroups_828MKI[] =
569 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, -1, },
570 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
571 {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, },
572 {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, },
575 PortGroupEntry PortGroups_896HD[] =
577 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, -1, },
578 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
579 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
580 {"MainOut-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
581 {"unknown-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
582 {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, },
583 {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, },
584 {"AES/EBU%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
587 PortGroupEntry PortGroups_828MKII[] =
589 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, -1},
590 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
591 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
592 {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
593 {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
594 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
595 {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, },
596 {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, },
599 PortGroupEntry PortGroups_TRAVELER[] =
601 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, -1, },
602 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
603 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
604 {"AES/EBU%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
605 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_OPTICAL_ADAT, },
606 {"Toslink%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, },
607 {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, },
608 {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, },
611 PortGroupEntry PortGroups_ULTRALITE[] =
613 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
614 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
615 {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, },
616 {"Analog%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4, },
617 {"Analog%d", 6, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 5, 2},
618 {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
619 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 6, },
620 {"Padding%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 7, },
623 PortGroupEntry PortGroups_8PRE[] =
625 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
626 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, },
627 {"Analog%d", 8, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
628 {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
629 {"Padding%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 4, },
630 {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 5, },
631 {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, 6, },
634 PortGroupEntry PortGroups_828mk3[] =
636 {"Mic-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, -1, },
637 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
638 {"Unknown-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, },
639 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
640 {"Return-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
641 {"MainOut-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
642 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
643 {"Unknown-%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, },
644 {"Reverb-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
646 // For input at 1x rates there are an additional 2 channel slots which
647 // are yet to be identified.
649 {"UnknownA-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
651 // Optical ports. Note: UnknownB is flagged as being always present at
652 // 2x rates in the input stream. This is yet to be verified. In the
653 // case of the old PortEntry definition UnknownB's equivalent was only
654 // flagged as present if optical B was set to ADAT; this seems wrong on
655 // reflection.
657 {"Toslink-A%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, },
658 {"ADAT-A%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
659 {"ADAT-A%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
660 {"Toslink-B%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_TOSLINK, },
661 {"ADAT-B%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
662 {"ADAT-B%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
663 {"UnknownB-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ANY, },
666 PortGroupEntry PortGroups_ULTRALITEmk3[] =
668 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 6, },
669 {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
670 {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
671 {"Analog%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
672 {"Analog%d", 6, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, 2},
673 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4, },
674 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 5, },
675 {"Reverb-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 7, },
676 {"Padding%d", 4, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 8, },
677 {"Pad out%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 9, },
680 PortGroupEntry PortGroups_ULTRALITEmk3_hybrid[] =
682 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
683 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
684 {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, },
685 {"Analog%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4, },
686 {"Analog%d", 6, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 5, 2, },
687 {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
688 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 6, },
689 {"Reverb%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 7, },
690 {"Unknown%d", 4, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 8, },
693 /* FIXME: as of 5 Aug 2010 this is still under development */
694 PortGroupEntry PortGroups_TRAVELERmk3[] =
696 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, -1, },
697 {"Phones-%s",2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
698 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
699 {"AES/EBU%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
700 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
701 {"Reverb%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
702 {"Unknown%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
704 // FIXME: optical port details to be filled in later.
708 /* FIXME: as of 8 Oct 2010 this is still under development. Presently this
709 * layout is nothing more than an educated guess.
711 PortGroupEntry PortGroups_896mk3[] =
713 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, -1, },
714 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
715 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
716 {"MainOut-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
717 {"UnknownIn-%d", 4, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
718 {"AES/EBU%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
719 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
720 {"UnknownOut-%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
721 {"Toslink-A%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, },
722 {"ADAT-A%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
723 {"ADAT-A%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
724 {"Toslink-B%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_TOSLINK, },
725 {"ADAT-B%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
726 {"ADAT-B%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
730 #define PORTGROUPS(__model) PortGroups_ ## __model, N_ELEMENTS(PortGroups_ ## __model)
732 /* The order of DevicesProperty entries must match the numeric order of the
733 * MOTU model enumeration (EMotuModel).
735 const DevicePropertyEntry DevicesProperty[] = {
736 // { PortGroups_map, N_ELEMENTS( PortGroups_map ),
737 // Ports_map, N_ELEMENTS( Ports_map ), MaxSR, MixerDescrPtr, Mark3MixerDescrPtr },
738 { PORTGROUPS(828MKII),
739 Ports_828MKII, N_ELEMENTS( Ports_828MKII ), 96000, &Mixer_828Mk2, NULL, },
740 { PORTGROUPS(TRAVELER),
741 Ports_TRAVELER, N_ELEMENTS( Ports_TRAVELER ), 192000, &Mixer_Traveler, NULL, },
742 { PORTGROUPS(ULTRALITE),
743 Ports_ULTRALITE, N_ELEMENTS( Ports_ULTRALITE ), 96000, &Mixer_Ultralite, NULL, },
744 { PORTGROUPS(8PRE),
745 Ports_8PRE, N_ELEMENTS( Ports_8PRE ), 96000, &Mixer_8pre, NULL, },
746 { PORTGROUPS(828MKI),
747 Ports_828MKI, N_ELEMENTS( Ports_828MKI ), 48000, &Mixer_828Mk1, NULL, },
748 { PORTGROUPS(896HD),
749 Ports_896HD, N_ELEMENTS( Ports_896HD ), 192000, &Mixer_896HD, NULL, },
750 { PORTGROUPS(828mk3),
751 Ports_828mk3, N_ELEMENTS( Ports_828mk3 ), 192000 },
752 { PORTGROUPS(ULTRALITEmk3),
753 Ports_ULTRALITEmk3, N_ELEMENTS( Ports_ULTRALITEmk3 ), 192000 }, // Ultralite mk3
754 { PORTGROUPS(ULTRALITEmk3_hybrid),
755 Ports_ULTRALITEmk3_hybrid, N_ELEMENTS( Ports_ULTRALITEmk3_hybrid ), 192000 }, // Ultralite mk3 hybrid
756 { PORTGROUPS(TRAVELERmk3),
757 Ports_TRAVELERmk3, N_ELEMENTS( Ports_TRAVELERmk3 ), 192000 },
758 { PORTGROUPS(896mk3),
759 NULL, 0, 192000 }, // 896 Mk 3
762 MotuDevice::MotuDevice( DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
763 : FFADODevice( d, configRom )
764 , m_motu_model( MOTU_MODEL_NONE )
765 , m_iso_recv_channel ( -1 )
766 , m_iso_send_channel ( -1 )
767 , m_rx_bandwidth ( -1 )
768 , m_tx_bandwidth ( -1 )
769 , m_rx_event_size ( 0 )
770 , m_tx_event_size ( 0 )
771 , m_receiveProcessor ( 0 )
772 , m_transmitProcessor ( 0 )
773 , m_MixerContainer ( NULL )
774 , m_ControlContainer ( NULL )
776 debugOutput( DEBUG_LEVEL_VERBOSE, "Created Motu::MotuDevice (NodeID %d)\n",
777 getConfigRom().getNodeId() );
780 MotuDevice::~MotuDevice()
782 delete m_receiveProcessor;
783 delete m_transmitProcessor;
785 // Free ieee1394 bus resources if they have been allocated
786 if (m_iso_recv_channel>=0 && !get1394Service().freeIsoChannel(m_iso_recv_channel)) {
787 debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free recv iso channel %d\n", m_iso_recv_channel);
789 if (m_iso_send_channel>=0 && !get1394Service().freeIsoChannel(m_iso_send_channel)) {
790 debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free send iso channel %d\n", m_iso_send_channel);
793 destroyMixer();
796 bool
797 MotuDevice::probe( Util::Configuration& c, ConfigRom& configRom, bool generic)
799 if(generic) return false;
801 unsigned int vendorId = configRom.getNodeVendorId();
802 unsigned int unitVersion = configRom.getUnitVersion();
803 unsigned int unitSpecifierId = configRom.getUnitSpecifierId();
805 for ( unsigned int i = 0;
806 i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
807 ++i )
809 if ( ( supportedDeviceList[i].vendor_id == vendorId )
810 && ( supportedDeviceList[i].unit_version == unitVersion )
811 && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
814 if (supportedDeviceList[i].model == MOTU_MODEL_NONE) {
815 debugOutput( DEBUG_LEVEL_VERBOSE, "%s %s found but is not currently supported by FFADO\n",
816 supportedDeviceList[i].vendor_name, supportedDeviceList[i].model_name);
817 debugOutput( DEBUG_LEVEL_VERBOSE, " unitVersion=0x%08x\n", unitVersion);
818 return false;
821 return true;
825 return false;
828 FFADODevice *
829 MotuDevice::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
831 return new MotuDevice(d, configRom);
834 bool
835 MotuDevice::discover()
837 unsigned int vendorId = getConfigRom().getNodeVendorId();
838 unsigned int unitVersion = getConfigRom().getUnitVersion();
839 unsigned int unitSpecifierId = getConfigRom().getUnitSpecifierId();
841 for ( unsigned int i = 0;
842 i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
843 ++i )
845 if ( ( supportedDeviceList[i].vendor_id == vendorId )
846 && ( supportedDeviceList[i].unit_version == unitVersion )
847 && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
850 m_model = &(supportedDeviceList[i]);
851 m_motu_model=supportedDeviceList[i].model;
855 if (m_model == NULL) {
856 return false;
859 debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
860 m_model->vendor_name, m_model->model_name);
862 if (m_motu_model == MOTU_MODEL_NONE) {
863 debugOutput( DEBUG_LEVEL_VERBOSE, "This MOTU device is not currently supported by FFADO\n");
864 return false;
867 // The MOTU 8pre seems to power up in "converter" mode. To toggle it
868 // into "interface" mode it is necessary to do a write to the clock
869 // control register. Since setClockCtrlRegister() will only do a write
870 // if something is explicitly set it isn't sufficient to do something like
871 // setClockCtrlRegister(-1, MOTU_CLKSRC_UNCHANGED)
872 // Instead, we request that the clock source be set to its present value;
873 // effectively this preserves the interface's current clock settings.
874 if (m_motu_model == MOTU_MODEL_8PRE) {
875 setClockCtrlRegister(-1, getHwClockSource());
878 // The MOTU 828mk1 device seems to power up without a valid clock source
879 // configured (the relevant bits don't seem to map to anything sensible).
880 // Deal with this if necessary.
881 if (m_motu_model == MOTU_MODEL_828MkI) {
882 signed int csrc = getHwClockSource();
883 if (csrc == MOTU_CLKSRC_NONE)
884 csrc = MOTU_CLKSRC_INTERNAL;
885 setClockCtrlRegister(-1, csrc);
888 if (!buildMixer()) {
889 debugWarning("Could not build mixer\n");
892 return true;
895 enum FFADODevice::eStreamingState
896 MotuDevice::getStreamingState()
898 unsigned int val = ReadRegister(MOTU_REG_ISOCTRL);
899 /* Streaming is active if either bit 22 (Motu->PC streaming
900 * enable) or bit 30 (PC->Motu streaming enable) is set.
902 debugOutput(DEBUG_LEVEL_VERBOSE, "MOTU_REG_ISOCTRL: %08x\n", val);
904 if((val & 0x40400000) != 0) {
905 return eSS_Both;
906 } else if ((val & 0x40000000) != 0) {
907 return eSS_Receiving;
908 } else if ((val & 0x00400000) != 0) {
909 return eSS_Sending;
910 } else {
911 return eSS_Idle;
916 MotuDevice::getSamplingFrequency( ) {
918 * Retrieve the current sample rate from the MOTU device.
920 quadlet_t q = 0;
921 int rate = 0;
922 unsigned int rate_base_mask, rate_base48k;
923 unsigned int rate_mult_mask, rate_mult2, rate_mult4;
925 if (m_motu_model == MOTU_MODEL_828MkI) {
926 /* The original MOTU interfaces did things rather differently */
927 q = ReadRegister(MOTU_G1_REG_CONFIG);
928 if ((q & MOTU_G1_RATE_MASK) == MOTU_G1_RATE_44100)
929 rate = 44100;
930 else
931 rate = 48000;
932 return rate;
935 /* The way the rate is managed is the same across G2 and G3 devices,
936 * but the actual bits used in the clock control register is different.
938 if (getDeviceGeneration() == MOTU_DEVICE_G2) {
939 rate_base_mask = MOTU_RATE_BASE_MASK;
940 rate_base48k = MOTU_RATE_BASE_48000;
941 rate_mult_mask = MOTU_RATE_MULTIPLIER_MASK;
942 rate_mult2 = MOTU_RATE_MULTIPLIER_2X;
943 rate_mult4 = MOTU_RATE_MULTIPLIER_4X;
944 } else {
945 rate_base_mask = MOTU_G3_RATE_BASE_MASK;
946 rate_base48k = MOTU_G3_RATE_BASE_48000;
947 rate_mult_mask = MOTU_G3_RATE_MULTIPLIER_MASK;
948 rate_mult2 = MOTU_G3_RATE_MULTIPLIER_2X;
949 rate_mult4 = MOTU_G3_RATE_MULTIPLIER_4X;
952 q = ReadRegister(MOTU_REG_CLK_CTRL);
953 if ((q & rate_base_mask) == rate_base48k)
954 rate = 48000;
955 else
956 rate = 44100;
957 if ((q & rate_mult_mask) == rate_mult4)
958 rate *= 4;
959 else
960 if ((q & rate_mult_mask) == rate_mult2)
961 rate *= 2;
963 return rate;
967 MotuDevice::getConfigurationId()
969 return 0;
972 unsigned int
973 MotuDevice::getHwClockSource()
975 unsigned int reg;
977 if (m_motu_model == MOTU_MODEL_828MkI) {
978 reg = ReadRegister(MOTU_G1_REG_CONFIG);
979 switch (reg & MOTU_G1_CLKSRC_MASK) {
980 case MOTU_G1_CLKSRC_INTERNAL: return MOTU_CLKSRC_INTERNAL;
981 case MOTU_G1_CLKSRC_ADAT_9PIN: return MOTU_CLKSRC_ADAT_9PIN;
982 case MOTU_G1_CLKSRC_SPDIF: return MOTU_CLKSRC_SPDIF_TOSLINK;
983 case MOTU_G1_CLKSRC_ADAT_OPTICAL: return MOTU_CLKSRC_ADAT_OPTICAL;
985 return MOTU_CLKSRC_NONE;
988 reg = ReadRegister(MOTU_REG_CLK_CTRL);
989 if (getDeviceGeneration() == MOTU_DEVICE_G2) {
990 switch (reg & MOTU_G2_CLKSRC_MASK) {
991 case MOTU_G2_CLKSRC_INTERNAL: return MOTU_CLKSRC_INTERNAL;
992 case MOTU_G2_CLKSRC_ADAT_OPTICAL: return MOTU_CLKSRC_ADAT_OPTICAL;
993 case MOTU_G2_CLKSRC_SPDIF_TOSLINK: return MOTU_CLKSRC_SPDIF_TOSLINK;
994 case MOTU_G2_CLKSRC_SMPTE: return MOTU_CLKSRC_SMPTE;
995 case MOTU_G2_CLKSRC_WORDCLOCK: return MOTU_CLKSRC_WORDCLOCK;
996 case MOTU_G2_CLKSRC_ADAT_9PIN: return MOTU_CLKSRC_ADAT_9PIN;
997 case MOTU_G2_CLKSRC_AES_EBU: return MOTU_CLKSRC_AES_EBU;
999 } else {
1000 /* Handle G3 devices */
1001 switch (reg & MOTU_G3_CLKSRC_MASK) {
1002 case MOTU_G3_CLKSRC_INTERNAL: return MOTU_CLKSRC_INTERNAL;
1003 case MOTU_G3_CLKSRC_SPDIF: return MOTU_CLKSRC_SPDIF_TOSLINK;
1004 case MOTU_G3_CLKSRC_SMPTE: return MOTU_CLKSRC_SMPTE;
1005 case MOTU_G3_CLKSRC_WORDCLOCK: return MOTU_CLKSRC_WORDCLOCK;
1006 case MOTU_G3_CLKSRC_OPTICAL_A: return MOTU_CLKSRC_OPTICAL_A;
1007 case MOTU_G3_CLKSRC_OPTICAL_B: return MOTU_CLKSRC_OPTICAL_B;
1010 return MOTU_CLKSRC_NONE;
1013 bool
1014 MotuDevice::setClockCtrlRegister(signed int samplingFrequency, unsigned int clock_source)
1017 * Set the MOTU device's samplerate and/or clock source via the clock
1018 * control register. If samplingFrequency <= 0 it remains unchanged. If
1019 * clock_source is MOTU_CLKSRC_UNCHANGED the clock source remains unchanged.
1021 const char *src_name;
1022 quadlet_t q, new_rate=0xffffffff;
1023 signed int i, supported=true, cancel_adat=false;
1024 quadlet_t reg;
1025 unsigned int rate_mask = 0;
1026 unsigned int old_clock_src = getHwClockSource();
1027 signed int device_gen = getDeviceGeneration();
1029 /* Don't touch anything if there's nothing to do */
1030 if (samplingFrequency<=0 && clock_source==MOTU_CLKSRC_NONE)
1031 return true;
1033 if ( samplingFrequency > DevicesProperty[m_motu_model-1].MaxSampleRate )
1034 return false;
1036 /* The original MOTU devices do things differently; they are much
1037 * simpler than the later interfaces.
1039 if (m_motu_model == MOTU_MODEL_828MkI) {
1040 reg = ReadRegister(MOTU_G1_REG_CONFIG);
1041 if (samplingFrequency > 0) {
1042 reg &= ~MOTU_G1_RATE_MASK;
1043 switch (samplingFrequency) {
1044 case 44100:
1045 reg |= MOTU_G1_RATE_44100;
1046 break;
1047 case 48000:
1048 reg |= MOTU_G1_RATE_48000;
1049 break;
1050 default:
1051 // Unsupported rate
1052 return false;
1055 if (clock_source != MOTU_CLKSRC_UNCHANGED) {
1056 switch (clock_source) {
1057 case MOTU_CLKSRC_INTERNAL:
1058 clock_source = MOTU_G1_CLKSRC_INTERNAL; break;
1059 case MOTU_CLKSRC_SPDIF_TOSLINK:
1060 clock_source = MOTU_G1_CLKSRC_SPDIF; break;
1061 case MOTU_CLKSRC_ADAT_9PIN:
1062 clock_source = MOTU_G1_CLKSRC_ADAT_9PIN; break;
1063 case MOTU_CLKSRC_ADAT_OPTICAL:
1064 clock_source = MOTU_G1_CLKSRC_ADAT_OPTICAL; break;
1065 default:
1066 // Unsupported clock source
1067 return false;
1069 reg &= ~MOTU_G1_CLKSRC_MASK;
1070 reg |= clock_source;
1072 if (WriteRegister(MOTU_G1_REG_CONFIG, reg) != 0)
1073 return false;
1074 return true;
1077 /* The rest of this function deals with later generation devices */
1079 reg = ReadRegister(MOTU_REG_CLK_CTRL);
1081 /* The method of controlling the sampling rate is the same for G2/G3
1082 * devices but the actual bits used in the rate control register differ.
1084 if (device_gen == MOTU_DEVICE_G2) {
1085 rate_mask = MOTU_RATE_BASE_MASK | MOTU_RATE_MULTIPLIER_MASK;
1086 switch ( samplingFrequency ) {
1087 case -1: break;
1088 case 44100: new_rate = MOTU_RATE_BASE_44100 | MOTU_RATE_MULTIPLIER_1X; break;
1089 case 48000: new_rate = MOTU_RATE_BASE_48000 | MOTU_RATE_MULTIPLIER_1X; break;
1090 case 88200: new_rate = MOTU_RATE_BASE_44100 | MOTU_RATE_MULTIPLIER_2X; break;
1091 case 96000: new_rate = MOTU_RATE_BASE_48000 | MOTU_RATE_MULTIPLIER_2X; break;
1092 case 176400: new_rate = MOTU_RATE_BASE_44100 | MOTU_RATE_MULTIPLIER_4X; break;
1093 case 192000: new_rate = MOTU_RATE_BASE_48000 | MOTU_RATE_MULTIPLIER_4X; break;
1094 default:
1095 supported=false;
1097 } else
1098 if (device_gen == MOTU_DEVICE_G3) {
1099 rate_mask = MOTU_G3_RATE_BASE_MASK | MOTU_G3_RATE_MULTIPLIER_MASK;
1100 switch ( samplingFrequency ) {
1101 case -1: break;
1102 case 44100: new_rate = MOTU_G3_RATE_BASE_44100 | MOTU_G3_RATE_MULTIPLIER_1X; break;
1103 case 48000: new_rate = MOTU_G3_RATE_BASE_48000 | MOTU_G3_RATE_MULTIPLIER_1X; break;
1104 case 88200: new_rate = MOTU_G3_RATE_BASE_44100 | MOTU_G3_RATE_MULTIPLIER_2X; break;
1105 case 96000: new_rate = MOTU_G3_RATE_BASE_48000 | MOTU_G3_RATE_MULTIPLIER_2X; break;
1106 case 176400: new_rate = MOTU_G3_RATE_BASE_44100 | MOTU_G3_RATE_MULTIPLIER_4X; break;
1107 case 192000: new_rate = MOTU_G3_RATE_BASE_48000 | MOTU_G3_RATE_MULTIPLIER_4X; break;
1108 default:
1109 supported=false;
1112 /* ADAT output is only possible for sample rates up to 96 kHz. For
1113 * anything higher, force the ADAT channels off.
1115 if (samplingFrequency > 96000) {
1116 cancel_adat = true;
1119 // Sanity check the clock source
1120 if (clock_source>MOTU_CLKSRC_LAST && clock_source!=MOTU_CLKSRC_UNCHANGED)
1121 supported = false;
1123 // Update the clock control register. FIXME: while this is now rather
1124 // comprehensive there may still be a need to manipulate MOTU_REG_CLK_CTRL
1125 // a little more than we do.
1126 if (supported) {
1128 // If optical port must be disabled (because a 4x sample rate has
1129 // been selected) then do so before changing the sample rate. At
1130 // this stage it will be up to the user to re-enable the optical
1131 // port if the sample rate is set to a 1x or 2x rate later.
1132 if (cancel_adat) {
1133 setOpticalMode(MOTU_CTRL_DIR_INOUT, MOTU_OPTICAL_MODE_OFF, MOTU_OPTICAL_MODE_OFF);
1136 // Set up new frequency if requested
1137 if (new_rate != 0xffffffff) {
1138 reg &= ~rate_mask;
1139 reg |= new_rate;
1142 // Set up new clock source if required
1143 if (clock_source != MOTU_CLKSRC_UNCHANGED) {
1144 if (device_gen == MOTU_DEVICE_G2) {
1145 reg &= ~MOTU_G2_CLKSRC_MASK;
1146 switch (clock_source) {
1147 case MOTU_CLKSRC_INTERNAL: reg |= MOTU_G2_CLKSRC_INTERNAL; break;
1148 case MOTU_CLKSRC_ADAT_OPTICAL: reg |= MOTU_G2_CLKSRC_ADAT_OPTICAL; break;
1149 case MOTU_CLKSRC_SPDIF_TOSLINK: reg |= MOTU_G2_CLKSRC_SPDIF_TOSLINK; break;
1150 case MOTU_CLKSRC_SMPTE: reg |= MOTU_G2_CLKSRC_SMPTE; break;
1151 case MOTU_CLKSRC_WORDCLOCK: reg |= MOTU_G2_CLKSRC_WORDCLOCK; break;
1152 case MOTU_CLKSRC_ADAT_9PIN: reg |= MOTU_G2_CLKSRC_ADAT_9PIN; break;
1153 case MOTU_CLKSRC_AES_EBU: reg |= MOTU_G2_CLKSRC_AES_EBU; break;
1155 } else {
1156 reg &= ~MOTU_G3_CLKSRC_MASK;
1157 switch (clock_source) {
1158 case MOTU_CLKSRC_INTERNAL: reg |= MOTU_G3_CLKSRC_INTERNAL; break;
1159 case MOTU_CLKSRC_SPDIF_TOSLINK: reg |= MOTU_G3_CLKSRC_SPDIF; break;
1160 case MOTU_CLKSRC_SMPTE: reg |= MOTU_G3_CLKSRC_SMPTE; break;
1161 case MOTU_CLKSRC_WORDCLOCK: reg |= MOTU_G3_CLKSRC_WORDCLOCK; break;
1162 case MOTU_CLKSRC_OPTICAL_A: reg |= MOTU_G3_CLKSRC_OPTICAL_A; break;
1163 case MOTU_CLKSRC_OPTICAL_B: reg |= MOTU_G3_CLKSRC_OPTICAL_B; break;
1166 } else {
1167 /* Use the device's current clock source to set the clock
1168 * source name registers, which must be done even if we aren't
1169 * changing the clock source.
1171 clock_source = old_clock_src;
1174 // Bits 24-26 of MOTU_REG_CLK_CTRL behave a little differently
1175 // depending on the model. In addition, different bit patterns are
1176 // written depending on whether streaming is enabled, disabled or is
1177 // changing state. For now we go with the combination used when
1178 // streaming is enabled since it seems to work for the other states
1179 // as well. Since device muting can be effected by these bits, we
1180 // may utilise this in future during streaming startup to prevent
1181 // noises during stabilisation.
1183 // For most models (possibly all except the Ultralite) all 3 bits
1184 // can be zero and audio is still output.
1186 // For the Traveler, if bit 26 is set (as it is under other OSes),
1187 // bit 25 functions as a device mute bit: if set, audio is output
1188 // while if 0 the entire device is muted. If bit 26 is unset,
1189 // setting bit 25 doesn't appear to be detrimental.
1191 // For the Ultralite, other OSes leave bit 26 unset. However, unlike
1192 // other devices bit 25 seems to function as a mute bit in this case.
1194 // The function of bit 24 is currently unknown. Other OSes set it
1195 // for all devices so we will too.
1196 reg &= 0xf8ffffff;
1197 if (m_motu_model == MOTU_MODEL_TRAVELER)
1198 reg |= 0x04000000;
1199 reg |= 0x03000000;
1200 if (WriteRegister(MOTU_REG_CLK_CTRL, reg) == 0) {
1201 supported=true;
1202 } else {
1203 supported=false;
1205 // A write to the rate/clock control register requires the
1206 // textual name of the current clock source be sent to the
1207 // clock source name registers. This appears to be the same for
1208 // both G2 and G3 devices.
1209 switch (clock_source) {
1210 case MOTU_CLKSRC_INTERNAL:
1211 src_name = "Internal ";
1212 break;
1213 case MOTU_CLKSRC_ADAT_OPTICAL:
1214 src_name = "ADAT Optical ";
1215 break;
1216 case MOTU_CLKSRC_SPDIF_TOSLINK: {
1217 unsigned int p0_mode;
1218 if (device_gen < MOTU_DEVICE_G3) {
1219 getOpticalMode(MOTU_DIR_IN, &p0_mode, NULL);
1220 } else
1221 p0_mode = MOTU_OPTICAL_MODE_OFF;
1222 if (p0_mode == MOTU_OPTICAL_MODE_TOSLINK)
1223 src_name = "TOSLink ";
1224 else
1225 src_name = "SPDIF ";
1226 break;
1228 case MOTU_CLKSRC_SMPTE:
1229 src_name = "SMPTE ";
1230 break;
1231 case MOTU_CLKSRC_WORDCLOCK:
1232 src_name = "Word Clock In ";
1233 break;
1234 case MOTU_CLKSRC_ADAT_9PIN:
1235 src_name = "ADAT 9-pin ";
1236 break;
1237 case MOTU_CLKSRC_AES_EBU:
1238 src_name = "AES-EBU ";
1239 break;
1240 case MOTU_CLKSRC_OPTICAL_A: {
1241 unsigned int p0_mode;
1242 getOpticalMode(MOTU_DIR_IN, &p0_mode, NULL);
1243 if (p0_mode == MOTU_OPTICAL_MODE_TOSLINK)
1244 src_name = "Toslink-A ";
1245 else
1246 src_name = "ADAT-A Optical ";
1247 break;
1249 case MOTU_CLKSRC_OPTICAL_B: {
1250 unsigned int p1_mode;
1251 getOpticalMode(MOTU_DIR_IN, NULL, &p1_mode);
1252 if (p1_mode == MOTU_OPTICAL_MODE_TOSLINK)
1253 src_name = "Toslink-B ";
1254 else
1255 src_name = "ADAT-B Optical ";
1256 break;
1258 default:
1259 src_name = "Unknown ";
1261 for (i=0; i<16; i+=4) {
1262 q = (src_name[i]<<24) | (src_name[i+1]<<16) |
1263 (src_name[i+2]<<8) | src_name[i+3];
1264 WriteRegister(MOTU_REG_CLKSRC_NAME0+i, q);
1267 return supported;
1270 bool
1271 MotuDevice::setSamplingFrequency( int samplingFrequency )
1274 * Set the MOTU device's samplerate.
1276 return setClockCtrlRegister(samplingFrequency, MOTU_CLKSRC_UNCHANGED);
1279 std::vector<int>
1280 MotuDevice::getSupportedSamplingFrequencies()
1282 std::vector<int> frequencies;
1283 signed int max_freq = DevicesProperty[m_motu_model-1].MaxSampleRate;
1285 /* All MOTUs support 1x rates. All others must be conditional. */
1286 frequencies.push_back(44100);
1287 frequencies.push_back(48000);
1289 if (88200 <= max_freq)
1290 frequencies.push_back(88200);
1291 if (96000 <= max_freq)
1292 frequencies.push_back(96000);
1293 if (176400 <= max_freq)
1294 frequencies.push_back(176400);
1295 if (192000 <= max_freq)
1296 frequencies.push_back(192000);
1297 return frequencies;
1300 FFADODevice::ClockSource
1301 MotuDevice::clockIdToClockSource(unsigned int id) {
1302 ClockSource s;
1303 signed int device_gen = getDeviceGeneration();
1304 s.id = id;
1306 // Assume a clock source is valid/active unless otherwise overridden.
1307 s.valid = true;
1308 s.locked = true;
1309 s.active = true;
1311 switch (id) {
1312 case MOTU_CLKSRC_INTERNAL:
1313 s.type = eCT_Internal;
1314 s.description = "Internal sync";
1315 break;
1316 case MOTU_CLKSRC_ADAT_OPTICAL:
1317 s.type = eCT_ADAT;
1318 s.description = "ADAT optical";
1319 s.valid = s.active = s.locked = (device_gen!=MOTU_DEVICE_G1);
1320 break;
1321 case MOTU_CLKSRC_SPDIF_TOSLINK:
1322 s.type = eCT_SPDIF;
1323 if (device_gen < MOTU_DEVICE_G3)
1324 s.description = "SPDIF/Toslink";
1325 else
1326 s.description = "SPDIF";
1327 break;
1328 case MOTU_CLKSRC_SMPTE:
1329 s.type = eCT_SMPTE;
1330 s.description = "SMPTE";
1331 // Since we don't currently know how to deal with SMPTE on these
1332 // devices make sure the SMPTE clock source is disabled.
1333 s.valid = false;
1334 s.active = false;
1335 s.locked = false;
1336 break;
1337 case MOTU_CLKSRC_WORDCLOCK:
1338 s.type = eCT_WordClock;
1339 s.description = "Wordclock";
1340 s.valid = s.active = s.locked = (device_gen!=MOTU_DEVICE_G1);
1341 break;
1342 case MOTU_CLKSRC_ADAT_9PIN:
1343 s.type = eCT_ADAT;
1344 s.description = "ADAT 9-pin";
1345 break;
1346 case MOTU_CLKSRC_AES_EBU:
1347 s.type = eCT_AES;
1348 s.description = "AES/EBU";
1349 s.valid = s.active = s.locked = (device_gen!=MOTU_DEVICE_G1);
1350 break;
1351 case MOTU_CLKSRC_OPTICAL_A:
1352 s.type = eCT_ADAT;
1353 s.description = "ADAT/Toslink port A";
1354 break;
1355 case MOTU_CLKSRC_OPTICAL_B:
1356 s.type = eCT_ADAT;
1357 s.description = "ADAT/Toslink port B";
1358 break;
1359 default:
1360 s.type = eCT_Invalid;
1363 s.slipping = false;
1364 return s;
1367 FFADODevice::ClockSourceVector
1368 MotuDevice::getSupportedClockSources() {
1369 FFADODevice::ClockSourceVector r;
1370 ClockSource s;
1371 signed int device_gen = getDeviceGeneration();
1373 /* Form a list of clocks supported by MOTU interfaces */
1375 /* All interfaces support an internal clock */
1376 s = clockIdToClockSource(MOTU_CLKSRC_INTERNAL);
1377 r.push_back(s);
1379 if (device_gen==MOTU_DEVICE_G2 || device_gen==MOTU_DEVICE_G1) {
1380 s = clockIdToClockSource(MOTU_CLKSRC_ADAT_OPTICAL);
1381 r.push_back(s);
1384 s = clockIdToClockSource(MOTU_CLKSRC_SPDIF_TOSLINK);
1385 r.push_back(s);
1386 s = clockIdToClockSource(MOTU_CLKSRC_SMPTE);
1387 r.push_back(s);
1389 /* The 828mk1 didn't have a wordclock sync option */
1390 if (device_gen != MOTU_DEVICE_G1) {
1391 s = clockIdToClockSource(MOTU_CLKSRC_WORDCLOCK);
1392 r.push_back(s);
1395 /* The 9-pin ADAT sync was only present on selected G2
1396 * devices. The 828mk1 also offered this.
1398 if (m_motu_model==MOTU_MODEL_828mkII || m_motu_model==MOTU_MODEL_TRAVELER ||
1399 m_motu_model==MOTU_MODEL_896HD || m_motu_model==MOTU_MODEL_828MkI) {
1400 s = clockIdToClockSource(MOTU_CLKSRC_ADAT_9PIN);
1401 r.push_back(s);
1403 /* AES/EBU is present on the G2/G3 Travelers and 896HDs */
1404 if (m_motu_model==MOTU_MODEL_TRAVELER || m_motu_model==MOTU_MODEL_TRAVELERmk3 ||
1405 m_motu_model==MOTU_MODEL_896HD || m_motu_model==MOTU_MODEL_896mk3) {
1406 s = clockIdToClockSource(MOTU_CLKSRC_AES_EBU);
1407 r.push_back(s);
1410 /* Dual-port ADAT is a feature of the G3 devices, and then only some */
1411 if (m_motu_model==MOTU_MODEL_828mk3 || m_motu_model==MOTU_MODEL_TRAVELERmk3 ||
1412 m_motu_model==MOTU_MODEL_896mk3) {
1413 s = clockIdToClockSource(MOTU_CLKSRC_OPTICAL_A);
1414 r.push_back(s);
1415 s = clockIdToClockSource(MOTU_CLKSRC_OPTICAL_B);
1416 r.push_back(s);
1419 return r;
1422 bool
1423 MotuDevice::setActiveClockSource(ClockSource s) {
1424 debugOutput(DEBUG_LEVEL_VERBOSE, "setting clock source to id: %d\n",s.id);
1426 // FIXME: this could do with some error checking
1427 return setClockCtrlRegister(-1, s.id);
1430 FFADODevice::ClockSource
1431 MotuDevice::getActiveClockSource() {
1432 ClockSource s;
1433 quadlet_t clock_id = getHwClockSource();
1434 s = clockIdToClockSource(clock_id);
1435 s.active = true;
1436 return s;
1439 bool
1440 MotuDevice::lock() {
1442 return true;
1446 bool
1447 MotuDevice::unlock() {
1449 return true;
1452 void
1453 MotuDevice::showDevice()
1455 debugOutput(DEBUG_LEVEL_VERBOSE,
1456 "%s %s at node %d\n", m_model->vendor_name, m_model->model_name,
1457 getNodeId());
1460 bool
1461 MotuDevice::prepare() {
1463 int samp_freq = getSamplingFrequency();
1464 unsigned int optical_in_mode_a, optical_out_mode_a;
1465 unsigned int optical_in_mode_b, optical_out_mode_b;
1466 unsigned int event_size_in;
1467 unsigned int event_size_out;
1469 debugOutput(DEBUG_LEVEL_NORMAL, "Preparing MotuDevice...\n" );
1471 /* The 828mk1 powers up without the optical mode register fields set
1472 * to anything in particular. For this interface, hardcode a default
1473 * optical mode if it appears that the interface is uninitialised.
1474 * On powerup, the unknown-2 register is 0xffffffff and this is reset
1475 * by software to 0; this provides a convenient test for the status
1476 * of the interface.
1478 if (m_motu_model==MOTU_MODEL_828MkI && ReadRegister(MOTU_G1_REG_UNKNOWN_2)!=0) {
1479 optical_in_mode_a = optical_out_mode_a = MOTU_OPTICAL_MODE_OFF;
1480 optical_in_mode_b = optical_out_mode_b = MOTU_OPTICAL_MODE_NONE;
1481 } else {
1482 getOpticalMode(MOTU_DIR_IN, &optical_in_mode_a, &optical_in_mode_b);
1483 getOpticalMode(MOTU_DIR_OUT, &optical_out_mode_a, &optical_out_mode_b);
1486 // Initialise port groups and determine the event sizes based on the
1487 // current device mode and sample rate.
1488 initDirPortGroups(Streaming::Port::E_Capture, samp_freq, optical_in_mode_a, optical_in_mode_b);
1489 initDirPortGroups(Streaming::Port::E_Playback, samp_freq, optical_out_mode_a, optical_out_mode_b);
1491 event_size_in = getEventSize(MOTU_DIR_IN);
1492 event_size_out= getEventSize(MOTU_DIR_OUT);
1494 // Explicitly set the optical mode, primarily to ensure that the
1495 // MOTU_REG_OPTICAL_CTRL register is initialised. We need to do this to
1496 // because some interfaces (the Ultralite for example) appear to power
1497 // up without this set to anything sensible. In this case, writes to
1498 // MOTU_REG_ISOCTRL fail more often than not, which is bad.
1499 setOpticalMode(MOTU_DIR_IN, optical_in_mode_a, optical_in_mode_b);
1500 setOpticalMode(MOTU_DIR_OUT, optical_out_mode_a, optical_out_mode_b);
1502 // The original 828 (aka 828mk1) was seen to write to these two
1503 // registers as part of its startup routine. It's not entirely clear
1504 // what these registers control. The inclusion of the local node ID is
1505 // an educated guess on experiments with bus topology when using other
1506 // systems.
1507 if (m_motu_model == MOTU_MODEL_828MkI) {
1508 WriteRegister(MOTU_G1_REG_UNKNOWN_1,
1509 0xffc00001 | ((get1394Service().getLocalNodeId()&0x3f)<<16));
1510 WriteRegister(MOTU_G1_REG_UNKNOWN_2, 0x00000000);
1513 // Allocate bandwidth if not previously done.
1514 // FIXME: The bandwidth allocation calculation can probably be
1515 // refined somewhat since this is currently based on a rudimentary
1516 // understanding of the ieee1394 iso protocol.
1517 // Currently we assume the following.
1518 // * Ack/iso gap = 0.05 us
1519 // * DATA_PREFIX = 0.16 us
1520 // * DATA_END = 0.26 us
1521 // These numbers are the worst-case figures given in the ieee1394
1522 // standard. This gives approximately 0.5 us of overheads per packet -
1523 // around 25 bandwidth allocation units (from the ieee1394 standard 1
1524 // bandwidth allocation unit is 125/6144 us). We further assume the
1525 // MOTU is running at S400 (which it should be) so one allocation unit
1526 // is equivalent to 1 transmitted byte; thus the bandwidth allocation
1527 // required for the packets themselves is just the size of the packet.
1528 // We used to allocate based on the maximum packet size (1160 bytes at
1529 // 192 kHz for the traveler) but now do this based on the actual device
1530 // state by utilising the result from getEventSize() and remembering
1531 // that each packet has an 8 byte CIP header. Note that bandwidth is
1532 // allocated on a *per stream* basis - it must be allocated for both the
1533 // transmit and receive streams. While most MOTU modules are close to
1534 // symmetric in terms of the number of in/out channels there are
1535 // exceptions, so we deal with receive and transmit bandwidth separately.
1536 signed int n_events_per_packet = samp_freq<=48000?8:(samp_freq<=96000?16:32);
1537 m_rx_bandwidth = 25 + (n_events_per_packet*event_size_in);
1538 m_tx_bandwidth = 25 + (n_events_per_packet*event_size_out);
1540 // Assign iso channels if not already done
1541 if (m_iso_send_channel < 0)
1542 m_iso_send_channel = get1394Service().allocateIsoChannelGeneric(m_tx_bandwidth);
1544 if (m_iso_recv_channel < 0)
1545 m_iso_recv_channel = get1394Service().allocateIsoChannelGeneric(m_rx_bandwidth);
1547 debugOutput(DEBUG_LEVEL_VERBOSE, "recv channel = %d, send channel = %d\n",
1548 m_iso_recv_channel, m_iso_send_channel);
1550 if (m_iso_recv_channel<0 || m_iso_send_channel<0) {
1551 // be nice and deallocate
1552 if (m_iso_recv_channel >= 0)
1553 get1394Service().freeIsoChannel(m_iso_recv_channel);
1554 if (m_iso_send_channel >= 0)
1555 get1394Service().freeIsoChannel(m_iso_send_channel);
1557 debugFatal("Could not allocate iso channels!\n");
1558 return false;
1561 // get the device specific and/or global SP configuration
1562 Util::Configuration &config = getDeviceManager().getConfiguration();
1563 // base value is the config.h value
1564 float recv_sp_dll_bw = STREAMPROCESSOR_DLL_BW_HZ;
1565 float xmit_sp_dll_bw = STREAMPROCESSOR_DLL_BW_HZ;
1567 // we can override that globally
1568 config.getValueForSetting("streaming.spm.recv_sp_dll_bw", recv_sp_dll_bw);
1569 config.getValueForSetting("streaming.spm.xmit_sp_dll_bw", xmit_sp_dll_bw);
1571 // or override in the device section
1572 config.getValueForDeviceSetting(getConfigRom().getNodeVendorId(), getConfigRom().getModelId(), "recv_sp_dll_bw", recv_sp_dll_bw);
1573 config.getValueForDeviceSetting(getConfigRom().getNodeVendorId(), getConfigRom().getModelId(), "xmit_sp_dll_bw", xmit_sp_dll_bw);
1575 m_receiveProcessor=new Streaming::MotuReceiveStreamProcessor(*this, event_size_in);
1576 m_receiveProcessor->setVerboseLevel(getDebugLevel());
1578 // The first thing is to initialize the processor. This creates the
1579 // data structures.
1580 if(!m_receiveProcessor->init()) {
1581 debugFatal("Could not initialize receive processor!\n");
1582 return false;
1585 if(!m_receiveProcessor->setDllBandwidth(recv_sp_dll_bw)) {
1586 debugFatal("Could not set DLL bandwidth\n");
1587 delete m_receiveProcessor;
1588 m_receiveProcessor = NULL;
1589 return false;
1592 // Now we add ports to the processor
1593 debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to receive processor\n");
1595 char *buff;
1596 Streaming::Port *p=NULL;
1598 // retrieve the ID
1599 std::string id=std::string("dev?");
1600 if(!getOption("id", id)) {
1601 debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n");
1604 // Add audio capture ports
1605 #ifndef USE_PORTGROUPS
1606 if (!addDirPorts(Streaming::Port::E_Capture, samp_freq, optical_in_mode_a, optical_in_mode_b)) {
1607 return false;
1609 #else
1610 if (!addDirPortGroups(Streaming::Port::E_Capture, samp_freq, optical_in_mode_a, optical_in_mode_b)) {
1611 return false;
1613 #endif
1614 // Add MIDI port. Every MOTU interface except the original 828 has
1615 // exactly one MIDI input port, with each MIDI byte sent using a 3 byte
1616 // sequence starting at byte 4 of the event data.
1617 if (m_motu_model != MOTU_MODEL_828MkI) {
1618 asprintf(&buff,"%s_cap_MIDI0",id.c_str());
1619 p = new Streaming::MotuMidiPort(*m_receiveProcessor, buff,
1620 Streaming::Port::E_Capture, 4);
1621 if (!p) {
1622 debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n", buff);
1624 free(buff);
1627 // example of adding an control port:
1628 // asprintf(&buff,"%s_cap_%s",id.c_str(),"myportnamehere");
1629 // p=new Streaming::MotuControlPort(
1630 // buff,
1631 // Streaming::Port::E_Capture,
1632 // 0 // you can add all other port specific stuff you
1633 // // need to pass by extending MotuXXXPort and MotuPortInfo
1634 // );
1635 // free(buff);
1637 // if (!p) {
1638 // debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
1639 // } else {
1641 // if (!m_receiveProcessor->addPort(p)) {
1642 // debugWarning("Could not register port with stream processor\n");
1643 // return false;
1644 // } else {
1645 // debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
1646 // }
1647 // }
1649 // Do the same for the transmit processor
1650 m_transmitProcessor=new Streaming::MotuTransmitStreamProcessor(*this, event_size_out);
1652 m_transmitProcessor->setVerboseLevel(getDebugLevel());
1654 if(!m_transmitProcessor->init()) {
1655 debugFatal("Could not initialize transmit processor!\n");
1656 return false;
1659 if(!m_transmitProcessor->setDllBandwidth(xmit_sp_dll_bw)) {
1660 debugFatal("Could not set DLL bandwidth\n");
1661 delete m_transmitProcessor;
1662 m_transmitProcessor = NULL;
1663 return false;
1666 // Now we add ports to the processor
1667 debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to transmit processor\n");
1669 // Add audio playback ports
1670 #ifndef USE_PORTGROUPS
1671 if (!addDirPorts(Streaming::Port::E_Playback, samp_freq, optical_out_mode_a, optical_out_mode_b)) {
1672 return false;
1674 #else
1675 if (!addDirPortGroups(Streaming::Port::E_Playback, samp_freq, optical_out_mode_a, optical_out_mode_b)) {
1676 return false;
1678 #endif
1680 // Add MIDI port. Every MOTU interface except the original 828 has
1681 // exactly one MIDI input port, with each MIDI byte sent using a 3 byte
1682 // sequence starting at byte 4 of the event data.
1683 if (m_motu_model != MOTU_MODEL_828MkI) {
1684 asprintf(&buff,"%s_pbk_MIDI0",id.c_str());
1685 p = new Streaming::MotuMidiPort(*m_transmitProcessor, buff,
1686 Streaming::Port::E_Playback, 4);
1687 if (!p) {
1688 debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n", buff);
1690 free(buff);
1693 // example of adding an control port:
1694 // asprintf(&buff,"%s_pbk_%s",id.c_str(),"myportnamehere");
1696 // p=new Streaming::MotuControlPort(
1697 // buff,
1698 // Streaming::Port::E_Playback,
1699 // 0 // you can add all other port specific stuff you
1700 // // need to pass by extending MotuXXXPort and MotuPortInfo
1701 // );
1702 // free(buff);
1704 // if (!p) {
1705 // debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
1706 // } else {
1707 // if (!m_transmitProcessor->addPort(p)) {
1708 // debugWarning("Could not register port with stream processor\n");
1709 // return false;
1710 // } else {
1711 // debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
1712 // }
1713 // }
1715 return true;
1719 MotuDevice::getStreamCount() {
1720 return 2; // one receive, one transmit
1723 Streaming::StreamProcessor *
1724 MotuDevice::getStreamProcessorByIndex(int i) {
1725 switch (i) {
1726 case 0:
1727 return m_receiveProcessor;
1728 case 1:
1729 return m_transmitProcessor;
1730 default:
1731 return NULL;
1733 return 0;
1736 bool
1737 MotuDevice::startStreamByIndex(int i) {
1739 quadlet_t isoctrl = ReadRegister(MOTU_REG_ISOCTRL);
1740 quadlet_t config2_reg = ReadRegister(MOTU_G1_REG_CONFIG_2);
1742 if (m_motu_model == MOTU_MODEL_828MkI) {
1743 // The 828MkI device does this differently. In particular it does
1744 // not appear possible to enable tx and rx separately since they
1745 // share a global enable (MOTU_G1_C1_ISO_ENABLE). Therefore we
1746 // enable both when the 0th index is requested and ignore any
1747 // request for index 1. Also note that on the G1 devices,
1748 // MOTU_REG_ISOCTRL and MOTU_G1_REG_CONFIG are one and the same.
1749 if (i == 1)
1750 return true;
1751 m_receiveProcessor->setChannel(m_iso_recv_channel);
1752 m_transmitProcessor->setChannel(m_iso_send_channel);
1754 /* Start with a setting of the config2 register. The purpose of
1755 * doing this is unclear, but it's done by other drivers so we
1756 * should too, at least until we have something working.
1758 WriteRegister(MOTU_G1_REG_CONFIG_2, config2_reg);
1760 /* Send the iso details to the control register. Note that as for
1761 * other MOTU devices bit 24 enables changes to the MOTU's iso tx
1762 * settings while bit 31 enables iso rx changes.
1764 debugOutput(DEBUG_LEVEL_VERBOSE, "MOTU g1: read isoctl: %x\n", isoctrl);
1765 debugOutput(DEBUG_LEVEL_VERBOSE, "MOTU g1: read config2: %x\n", config2_reg);
1766 isoctrl &= ~MOTU_G1_C1_ISO_INFO_MASK;
1767 isoctrl |= (MOTU_G1_C1_ISO_TX_WREN | MOTU_G1_C1_ISO_RX_WREN);
1768 isoctrl |= (m_iso_recv_channel << MOTU_G1_C1_ISO_TX_CH_BIT0);
1769 isoctrl |= (m_iso_send_channel << MOTU_G1_C1_ISO_RX_CH_BIT0);
1770 isoctrl |= (MOTU_G1_C1_ISO_TX_ACTIVE | MOTU_G1_C1_ISO_RX_ACTIVE);
1771 isoctrl |= (MOTU_G1_IO_ENABLE_0);
1772 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1773 debugOutput(DEBUG_LEVEL_VERBOSE, "MOTU g1: isoctrl 1: %08x\n", isoctrl);
1775 /* Streaming should be started with the conclusion of the above
1776 * register writes. There's one final bit that's set afterwards
1777 * by other systems, so we'll do the same until its demonstrated
1778 * that this write can be merged with the previous one without ill
1779 * effects.
1781 isoctrl &= ~MOTU_G1_C1_ISO_INFO_MASK;
1782 isoctrl |= MOTU_G1_C1_ISO_ENABLE;
1783 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1785 debugOutput(DEBUG_LEVEL_VERBOSE, "MOTU g1: isoctrl 2: %08x\n", isoctrl);
1787 return true;
1790 // NOTE: this assumes that you have two streams
1791 switch (i) {
1792 case 0:
1793 // TODO: do the stuff that is nescessary to make the device
1794 // receive a stream
1796 // Set the streamprocessor channel to the one obtained by
1797 // the connection management
1798 m_receiveProcessor->setChannel(m_iso_recv_channel);
1800 // Mask out current transmit settings of the MOTU and replace with
1801 // new ones (which correspond to our receive channel). Turn bit 24
1802 // on to enable changes to the MOTU's iso transmit settings when the
1803 // iso control register is written. Bit 23 enables iso transmit
1804 // from the MOTU.
1805 isoctrl &= 0xff00ffff;
1806 isoctrl |= (m_iso_recv_channel << 16);
1807 isoctrl |= 0x00c00000;
1808 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1809 break;
1810 case 1:
1811 // TODO: do the stuff that is nescessary to make the device
1812 // transmit a stream
1814 // Set the streamprocessor channel to the one obtained by
1815 // the connection management
1816 m_transmitProcessor->setChannel(m_iso_send_channel);
1818 // Mask out current receive settings of the MOTU and replace with
1819 // new ones (which correspond to our transmit channel). Turn bit 31
1820 // on to enable changes to the MOTU's iso receive settings when the
1821 // iso control register is written. Bit 30 enables iso receive by
1822 // the MOTU.
1823 isoctrl &= 0x00ffffff;
1824 isoctrl |= (m_iso_send_channel << 24);
1825 isoctrl |= 0xc0000000;
1826 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1827 break;
1829 default: // Invalid stream index
1830 return false;
1833 return true;
1836 bool
1837 MotuDevice::stopStreamByIndex(int i) {
1839 quadlet_t isoctrl = ReadRegister(MOTU_REG_ISOCTRL);
1841 // Shut down streaming. Essentially the opposite of the start function.
1843 if (m_motu_model == MOTU_MODEL_828MkI) {
1844 quadlet_t reg = isoctrl;
1845 // The 828MkI device does this differently. In particular it does
1846 // not appear possible to disable tx and rx separately since they
1847 // share a global enable (MOTU_G1_C1_ISO_ENABLE). Therefore we
1848 // disable both when the 0th index is requested and ignore any
1849 // request for index 1.
1850 if (i == 1)
1851 return true;
1853 /* First disable the streaming */
1854 reg &= ~MOTU_G1_C1_ISO_INFO_MASK;
1855 reg &= ~MOTU_G1_C1_ISO_ENABLE;
1856 WriteRegister(MOTU_REG_ISOCTRL, reg);
1858 /* Next, turn off individual stream enable flags. As for the stream
1859 * start case, this is separated from the first write because that's
1860 * what other systems do.
1862 reg |= (isoctrl & MOTU_G1_C1_ISO_INFO_MASK);
1863 reg &= ~(MOTU_G1_C1_ISO_TX_ACTIVE | MOTU_G1_C1_ISO_RX_ACTIVE);
1864 WriteRegister(MOTU_REG_ISOCTRL, reg);
1866 return true;
1869 // NOTE: this assumes that you have two streams
1870 switch (i) {
1871 case 0:
1872 // Turn bit 22 off to disable iso send by the MOTU. Turn
1873 // bit 23 on to enable changes to the MOTU's iso transmit
1874 // settings when the iso control register is written.
1875 isoctrl &= 0xffbfffff;
1876 isoctrl |= 0x00800000;
1877 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1878 break;
1879 case 1:
1880 // Turn bit 30 off to disable iso receive by the MOTU. Turn
1881 // bit 31 on to enable changes to the MOTU's iso receive
1882 // settings when the iso control register is written.
1883 isoctrl &= 0xbfffffff;
1884 isoctrl |= 0x80000000;
1885 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1886 break;
1888 default: // Invalid stream index
1889 return false;
1892 return true;
1895 signed int MotuDevice::getIsoRecvChannel(void) {
1896 return m_iso_recv_channel;
1899 signed int MotuDevice::getIsoSendChannel(void) {
1900 return m_iso_send_channel;
1903 signed int MotuDevice::getDeviceGeneration(void) {
1904 if (m_motu_model == MOTU_MODEL_828MkI)
1905 return MOTU_DEVICE_G1;
1906 if (m_motu_model==MOTU_MODEL_828mk3 ||
1907 m_motu_model==MOTU_MODEL_ULTRALITEmk3 ||
1908 m_motu_model==MOTU_MODEL_ULTRALITEmk3_HYB ||
1909 m_motu_model==MOTU_MODEL_TRAVELERmk3 ||
1910 m_motu_model==MOTU_MODEL_896mk3)
1911 return MOTU_DEVICE_G3;
1912 return MOTU_DEVICE_G2;
1915 unsigned int MotuDevice::getOpticalMode(unsigned int dir,
1916 unsigned int *port_a_mode, unsigned int *port_b_mode) {
1917 // Only the "Mark 3" (aka G3) MOTU devices had more than one optical
1918 // port. Therefore the "port_b_mode" parameter is unused by all
1919 // devices other than the Mark 3 devices.
1921 // If a mode parameter pointer is NULL it will not be returned.
1922 unsigned int reg, reg2;
1923 unsigned int mask, shift;
1925 if (port_b_mode != NULL)
1926 *port_b_mode = MOTU_OPTICAL_MODE_NONE;
1927 if (getDeviceGeneration()!=MOTU_DEVICE_G3 && port_a_mode==NULL)
1928 return 0;
1930 if (m_motu_model == MOTU_MODEL_828MkI) {
1931 // The early devices used a different register layout.
1932 unsigned int mask2;
1933 reg = ReadRegister(MOTU_G1_REG_CONFIG);
1934 reg2 = ReadRegister(MOTU_G1_REG_CONFIG_2);
1936 mask = (dir==MOTU_DIR_IN)?MOTU_G1_C1_OPT_TOSLINK_IN:MOTU_G1_C1_OPT_TOSLINK_OUT;
1937 mask2 = (dir==MOTU_DIR_IN)?MOTU_G1_C2_OPT_nADAT_IN:MOTU_G1_C2_OPT_nADAT_OUT;
1939 if ((reg & mask) && (reg2 & mask2)) {
1940 /* Toslink bit set, nADAT bit set -> Toslink mode */
1941 *port_a_mode = MOTU_OPTICAL_MODE_TOSLINK;
1942 } else
1943 if ((reg & mask)==0 && (reg2 & mask2)==0) {
1944 /* Toslink bit clear, nADAT bit clear -> ADAT mode */
1945 *port_a_mode = MOTU_OPTICAL_MODE_ADAT;
1946 } else {
1947 /* All other combinations are unexpected except toslink clear/
1948 * nADAT set, so just assume the optical port is off if we get
1949 * here.
1951 *port_a_mode = MOTU_OPTICAL_MODE_OFF;
1953 return 0;
1956 if (getDeviceGeneration() == MOTU_DEVICE_G3) {
1957 unsigned int enable, toslink;
1958 /* The Ultralite Mk3s don't have any optical ports. All others have 2. */
1959 if (m_motu_model==MOTU_MODEL_ULTRALITEmk3 || m_motu_model==MOTU_MODEL_ULTRALITEmk3_HYB) {
1960 if (port_a_mode != NULL)
1961 *port_a_mode = MOTU_OPTICAL_MODE_NONE;
1962 if (port_b_mode != NULL)
1963 *port_b_mode = MOTU_OPTICAL_MODE_NONE;
1964 return 0;
1966 reg = ReadRegister(MOTU_G3_REG_OPTICAL_CTRL);
1967 debugOutput(DEBUG_LEVEL_VERBOSE, "mark3 optical control register = 0x%08x\n", reg);
1968 if (port_a_mode != NULL) {
1969 enable = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_A_IN_ENABLE:MOTU_G3_OPT_A_OUT_ENABLE;
1970 toslink = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_A_IN_TOSLINK:MOTU_G3_OPT_A_OUT_TOSLINK;
1971 if ((reg & enable) == 0)
1972 *port_a_mode = MOTU_OPTICAL_MODE_OFF;
1973 else
1974 if ((reg & toslink) == 0)
1975 *port_a_mode = MOTU_OPTICAL_MODE_TOSLINK;
1976 else
1977 *port_a_mode = MOTU_OPTICAL_MODE_ADAT;
1979 if (port_b_mode != NULL) {
1980 enable = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_B_IN_ENABLE:MOTU_G3_OPT_B_OUT_ENABLE;
1981 toslink = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_B_IN_TOSLINK:MOTU_G3_OPT_B_OUT_TOSLINK;
1982 if ((reg & enable) == 0)
1983 *port_b_mode = MOTU_OPTICAL_MODE_OFF;
1984 else
1985 if ((reg & toslink) == 0)
1986 *port_b_mode = MOTU_OPTICAL_MODE_TOSLINK;
1987 else
1988 *port_b_mode = MOTU_OPTICAL_MODE_ADAT;
1990 return 0;
1993 reg = ReadRegister(MOTU_REG_ROUTE_PORT_CONF);
1994 mask = (dir==MOTU_DIR_IN)?MOTU_G2_OPTICAL_IN_MODE_MASK:MOTU_G2_OPTICAL_OUT_MODE_MASK;
1995 shift = (dir==MOTU_DIR_IN)?MOTU_G2_OPTICAL_IN_MODE_BIT0:MOTU_G2_OPTICAL_OUT_MODE_BIT0;
1996 switch ((reg & mask) >> shift) {
1997 case MOTU_G2_OPTICAL_MODE_OFF: *port_a_mode = MOTU_OPTICAL_MODE_OFF; break;
1998 case MOTU_G2_OPTICAL_MODE_ADAT: *port_a_mode = MOTU_OPTICAL_MODE_ADAT; break;
1999 case MOTU_G2_OPTICAL_MODE_TOSLINK: *port_a_mode = MOTU_OPTICAL_MODE_TOSLINK; break;
2001 return 0;
2004 signed int MotuDevice::setOpticalMode(unsigned int dir,
2005 unsigned int port_a_mode, unsigned int port_b_mode) {
2006 // Only the "Mark 3" (aka G3) MOTU devices had more than one optical port.
2007 // Therefore the "port B" mode is ignored for all devices other than
2008 // the Mark 3 devices.
2009 unsigned int reg, g2mode;
2010 unsigned int opt_ctrl = 0x0000002;
2012 /* THe 896HD doesn't have an SPDIF/TOSLINK optical mode, so don't try to
2013 * set it
2015 if (m_motu_model==MOTU_MODEL_896HD && port_a_mode==MOTU_OPTICAL_MODE_TOSLINK)
2016 return -1;
2018 if (getDeviceGeneration()!=MOTU_DEVICE_G3 && port_a_mode==MOTU_OPTICAL_MODE_KEEP)
2019 return 0;
2021 if (m_motu_model == MOTU_MODEL_828MkI) {
2022 // The earlier MOTUs handle this differently.
2023 unsigned int g1_conf1_ref, g1_conf2_ref;
2024 unsigned int g1_conf1, g1_conf2;
2025 unsigned int toslink, n_adat;
2026 signed int err = 0;
2027 g1_conf1 = ReadRegister(MOTU_G1_REG_CONFIG);
2028 g1_conf2 = ReadRegister(MOTU_G1_REG_CONFIG_2);
2029 toslink = (dir==MOTU_DIR_IN)?MOTU_G1_C1_OPT_TOSLINK_IN:MOTU_G1_C1_OPT_TOSLINK_OUT;
2030 n_adat = (dir==MOTU_DIR_IN)?MOTU_G1_C2_OPT_nADAT_IN:MOTU_G1_C2_OPT_nADAT_OUT;
2032 // Don't send ISO information
2033 g1_conf1 &= ~MOTU_G1_C1_ISO_INFO_MASK;
2035 // This bit seems to always be set
2036 g1_conf1 |= (MOTU_G1_IO_ENABLE_0);
2038 /* This bit seems to always be set when this register is set.
2039 * It may be a write enable bit.
2041 g1_conf2 |= MOTU_G1_C2_OPT_nADAT_WREN;
2043 g1_conf1_ref = g1_conf1;
2044 g1_conf2_ref = g1_conf2;
2046 /* Set registers as needed by the requested mode */
2048 if (port_a_mode == MOTU_OPTICAL_MODE_TOSLINK) {
2049 g1_conf1 |= toslink;
2050 } else {
2051 g1_conf1 &= ~toslink;
2053 if (port_a_mode == MOTU_OPTICAL_MODE_ADAT) {
2054 g1_conf2 &= ~n_adat;
2055 } else {
2056 g1_conf2 |= n_adat;
2059 // Under other systems, MOTU_G1_REG_CONFIG is always written
2060 // first, but only if its value has been changed. Similarly,
2061 // MOTU_G1_REG_CONFIG_2 is only written if its value has been
2062 // altered.
2063 if (!err && g1_conf1!=g1_conf1_ref)
2064 err = WriteRegister(MOTU_G1_REG_CONFIG, g1_conf1) != 0;
2065 if (!err && g1_conf2!=g1_conf2_ref)
2066 err = WriteRegister(MOTU_G1_REG_CONFIG_2, g1_conf2) != 0;
2067 if (err)
2068 return -1;
2069 return 0;
2072 /* The G3 devices are also quite a bit different to the G2 units */
2073 if (getDeviceGeneration() == MOTU_DEVICE_G3) {
2074 unsigned int mask, enable, toslink;
2075 reg = ReadRegister(MOTU_G3_REG_OPTICAL_CTRL);
2076 if (port_a_mode != MOTU_OPTICAL_MODE_KEEP) {
2077 mask = enable = toslink = 0;
2078 if (dir & MOTU_DIR_IN) {
2079 mask |= MOTU_G3_OPT_A_IN_MASK;
2080 enable |= MOTU_G3_OPT_A_IN_ENABLE;
2081 toslink |= MOTU_G3_OPT_A_IN_TOSLINK;
2083 if (dir & MOTU_DIR_OUT) {
2084 mask |= MOTU_G3_OPT_A_OUT_MASK;
2085 enable |= MOTU_G3_OPT_A_OUT_ENABLE;
2086 toslink |= MOTU_G3_OPT_A_OUT_TOSLINK;
2088 reg = (reg & ~mask) | enable;
2089 switch (port_a_mode) {
2090 case MOTU_OPTICAL_MODE_OFF: reg &= ~enable; break;
2091 case MOTU_OPTICAL_MODE_TOSLINK: reg |= toslink; break;
2094 if (port_b_mode != MOTU_OPTICAL_MODE_KEEP) {
2095 mask = enable = toslink = 0;
2096 if (dir & MOTU_DIR_IN) {
2097 mask |= MOTU_G3_OPT_B_IN_MASK;
2098 enable |= MOTU_G3_OPT_B_IN_ENABLE;
2099 toslink |= MOTU_G3_OPT_B_IN_TOSLINK;
2101 if (dir & MOTU_DIR_OUT) {
2102 mask |= MOTU_G3_OPT_B_OUT_MASK;
2103 enable |= MOTU_G3_OPT_B_OUT_ENABLE;
2104 toslink |= MOTU_G3_OPT_B_OUT_TOSLINK;
2106 reg = (reg & ~mask) | enable;
2107 switch (port_a_mode) {
2108 case MOTU_OPTICAL_MODE_OFF: reg &= ~enable; break;
2109 case MOTU_OPTICAL_MODE_TOSLINK: reg |= toslink; break;
2111 reg = (reg & ~mask) | enable;
2112 switch (port_b_mode) {
2113 case MOTU_OPTICAL_MODE_OFF: reg &= ~enable; break;
2114 case MOTU_OPTICAL_MODE_TOSLINK: reg |= toslink; break;
2117 return WriteRegister(MOTU_G3_REG_OPTICAL_CTRL, reg);
2120 reg = ReadRegister(MOTU_REG_ROUTE_PORT_CONF);
2122 // Map from user mode to values sent to the device registers.
2123 g2mode = 0;
2124 switch (port_a_mode) {
2125 case MOTU_OPTICAL_MODE_OFF: g2mode = MOTU_G2_OPTICAL_MODE_OFF; break;
2126 case MOTU_OPTICAL_MODE_ADAT: g2mode = MOTU_G2_OPTICAL_MODE_ADAT; break;
2127 case MOTU_OPTICAL_MODE_TOSLINK: g2mode = MOTU_G2_OPTICAL_MODE_TOSLINK; break;
2130 // Set up the optical control register value according to the current
2131 // optical port modes. At this stage it's not completely understood
2132 // what the "Optical control" register does, so the values it's set to
2133 // are more or less "magic" numbers.
2134 if ((reg & MOTU_G2_OPTICAL_IN_MODE_MASK) != (MOTU_G2_OPTICAL_MODE_ADAT<<MOTU_G2_OPTICAL_IN_MODE_BIT0))
2135 opt_ctrl |= 0x00000080;
2136 if ((reg & MOTU_G2_OPTICAL_OUT_MODE_MASK) != (MOTU_G2_OPTICAL_MODE_ADAT<<MOTU_G2_OPTICAL_OUT_MODE_BIT0))
2137 opt_ctrl |= 0x00000040;
2139 if (dir & MOTU_DIR_IN) {
2140 reg &= ~MOTU_G2_OPTICAL_IN_MODE_MASK;
2141 reg |= (g2mode << MOTU_G2_OPTICAL_IN_MODE_BIT0) & MOTU_G2_OPTICAL_IN_MODE_MASK;
2142 if (g2mode != MOTU_G2_OPTICAL_MODE_ADAT)
2143 opt_ctrl |= 0x00000080;
2144 else
2145 opt_ctrl &= ~0x00000080;
2147 if (dir & MOTU_DIR_OUT) {
2148 reg &= ~MOTU_G2_OPTICAL_OUT_MODE_MASK;
2149 reg |= (g2mode << MOTU_G2_OPTICAL_OUT_MODE_BIT0) & MOTU_G2_OPTICAL_OUT_MODE_MASK;
2150 if (g2mode != MOTU_G2_OPTICAL_MODE_ADAT)
2151 opt_ctrl |= 0x00000040;
2152 else
2153 opt_ctrl &= ~0x00000040;
2156 /* Setting bit 25 in the route/port configuration register enables the
2157 * setting of the optical mode. Bit 24 allows the phones assign to be
2158 * set using the lower 8 bits of the register. This function has no
2159 * business setting that, so make sure bit 24 is masked off.
2161 reg |= 0x02000000;
2162 reg &= ~0x01000000;
2164 // FIXME: there seems to be more to it than this, but for
2165 // the moment at least this seems to work.
2166 WriteRegister(MOTU_REG_ROUTE_PORT_CONF, reg);
2167 return WriteRegister(MOTU_REG_OPTICAL_CTRL, opt_ctrl);
2170 signed int MotuDevice::getEventSize(unsigned int direction) {
2172 // Return the size in bytes of a single event sent to (dir==MOTU_OUT) or
2173 // from (dir==MOTU_IN) the MOTU as part of an iso data packet.
2175 // FIXME: for performance it may turn out best to calculate the event
2176 // size in setOpticalMode and cache the result in a data field. However,
2177 // as it stands this will not adapt to dynamic changes in sample rate - we'd
2178 // need a setFrameRate() for that.
2180 // Note that all audio channels are sent using 3 bytes.
2181 signed int size = 0;
2183 #ifndef USE_PORTGROUPS
2184 const DevicePropertyEntry *devprop = &DevicesProperty[m_motu_model-1];
2185 signed int sample_rate = getSamplingFrequency();
2186 unsigned int optical_mode_a, optical_mode_b;
2188 unsigned int i;
2189 unsigned int dir = direction==MOTU_DIR_IN?MOTU_PA_IN:MOTU_PA_OUT;
2190 unsigned int flags = 0;
2191 unsigned int port_flags;
2193 // At the very least an event consists of the SPH (4 bytes). On all
2194 // interfaces except the 828Mk1 there are also 6 bytes of control/MIDI
2195 // data at the start.
2196 size = 4;
2197 if (m_motu_model != MOTU_MODEL_828MkI)
2198 size += 6;
2199 getOpticalMode(direction, &optical_mode_a, &optical_mode_b);
2201 if ( sample_rate > 96000 )
2202 flags |= MOTU_PA_RATE_4x;
2203 else if ( sample_rate > 48000 )
2204 flags |= MOTU_PA_RATE_2x;
2205 else
2206 flags |= MOTU_PA_RATE_1x;
2208 switch (optical_mode_a) {
2209 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_OPTICAL_ANY; break;
2210 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_OPTICAL_OFF; break;
2211 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_OPTICAL_ADAT; break;
2212 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_OPTICAL_TOSLINK; break;
2214 switch (optical_mode_b) {
2215 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_MK3_OPT_B_ANY; break;
2216 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_MK3_OPT_B_OFF; break;
2217 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_MK3_OPT_B_ADAT; break;
2218 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_MK3_OPT_B_TOSLINK; break;
2221 // Don't test for padding port flag here since we need to include such
2222 // pseudo-ports when calculating the event size.
2223 for (i=0; i < devprop->n_port_entries; i++) {
2224 port_flags = devprop->port_entry[i].port_flags;
2225 /* Make sure the optical port tests return true for devices without
2226 * one or both optical ports.
2228 if (optical_mode_a == MOTU_OPTICAL_MODE_NONE) {
2229 port_flags |= MOTU_PA_OPTICAL_ANY;
2231 if (optical_mode_b == MOTU_OPTICAL_MODE_NONE) {
2232 port_flags |= MOTU_PA_MK3_OPT_B_ANY;
2234 if (( port_flags & dir ) &&
2235 ( port_flags & MOTU_PA_RATE_MASK & flags ) &&
2236 ( port_flags & MOTU_PA_MK3_OPT_B_MASK & flags ) &&
2237 ( port_flags & MOTU_PA_OPTICAL_MASK & flags )) {
2238 size += 3;
2242 // The 828Mk1 includes an additional 6 bytes at the end of the packet.
2243 // The purpose of these is unknown at this stage, but we need to allow
2244 // for them in the event size calculation.
2245 if (m_motu_model == MOTU_MODEL_828MkI)
2246 size += 6;
2248 #else
2249 if (direction==MOTU_DIR_IN)
2250 size = m_rx_event_size;
2251 else
2252 size = m_tx_event_size;
2253 #endif
2255 // Finally round size up to the next quadlet boundary
2256 return ((size+3)/4)*4;
2258 /* ======================================================================= */
2260 bool MotuDevice::addPort(Streaming::StreamProcessor *s_processor,
2261 char *name, enum Streaming::Port::E_Direction direction,
2262 int position, int size) {
2264 * Internal helper function to add a MOTU port to a given stream processor.
2265 * This just saves the unnecessary replication of what is essentially
2266 * boilerplate code. Note that the port name is freed by this function
2267 * prior to exit.
2269 Streaming::Port *p=NULL;
2271 p = new Streaming::MotuAudioPort(*s_processor, name, direction, position, size);
2273 if (!p) {
2274 debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",name);
2276 free(name);
2277 return true;
2279 /* ======================================================================= */
2281 bool MotuDevice::addDirPorts(
2282 enum Streaming::Port::E_Direction direction, unsigned int sample_rate,
2283 unsigned int optical_a_mode, unsigned int optical_b_mode) {
2285 * Internal helper method: adds all required ports for the given direction
2286 * based on the indicated sample rate and optical mode.
2288 * Notes: currently ports are not created if they are disabled due to sample
2289 * rate or optical mode. However, it might be better to unconditionally
2290 * create all ports and just disable those which are not active.
2292 const char *mode_str = direction==Streaming::Port::E_Capture?"cap":"pbk";
2293 Streaming::StreamProcessor *s_processor;
2294 unsigned int i;
2295 char *buff;
2296 unsigned int dir = direction==Streaming::Port::E_Capture?MOTU_PA_IN:MOTU_PA_OUT;
2297 unsigned int flags = 0;
2298 unsigned int port_flags;
2301 if ( sample_rate > 96000 )
2302 flags |= MOTU_PA_RATE_4x;
2303 else if ( sample_rate > 48000 )
2304 flags |= MOTU_PA_RATE_2x;
2305 else
2306 flags |= MOTU_PA_RATE_1x;
2308 switch (optical_a_mode) {
2309 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_OPTICAL_ANY; break;
2310 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_OPTICAL_OFF; break;
2311 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_OPTICAL_ADAT; break;
2312 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_OPTICAL_TOSLINK; break;
2314 switch (optical_b_mode) {
2315 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_MK3_OPT_B_ANY; break;
2316 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_MK3_OPT_B_OFF; break;
2317 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_MK3_OPT_B_ADAT; break;
2318 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_MK3_OPT_B_TOSLINK; break;
2321 // retrieve the ID
2322 std::string id=std::string("dev?");
2323 if(!getOption("id", id)) {
2324 debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n");
2327 if (direction == Streaming::Port::E_Capture) {
2328 s_processor = m_receiveProcessor;
2329 } else {
2330 s_processor = m_transmitProcessor;
2333 for (i=0; i < DevicesProperty[m_motu_model-1].n_port_entries; i++) {
2334 port_flags = DevicesProperty[m_motu_model-1].port_entry[i].port_flags;
2335 /* For devices without one or more optical ports, ensure the tests
2336 * on the optical ports always returns "true".
2338 if (optical_a_mode == MOTU_OPTICAL_MODE_NONE)
2339 port_flags |= MOTU_PA_OPTICAL_ANY;
2340 if (optical_b_mode == MOTU_OPTICAL_MODE_NONE)
2341 port_flags |= MOTU_PA_MK3_OPT_B_ANY;
2343 if (( port_flags & dir ) &&
2344 ( port_flags & MOTU_PA_RATE_MASK & flags ) &&
2345 ( port_flags & MOTU_PA_OPTICAL_MASK & flags ) &&
2346 ( port_flags & MOTU_PA_MK3_OPT_B_MASK & flags ) &&
2347 !( port_flags & MOTU_PA_PADDING )) {
2348 asprintf(&buff,"%s_%s_%s" , id.c_str(), mode_str,
2349 DevicesProperty[m_motu_model-1].port_entry[i].port_name);
2350 if (!addPort(s_processor, buff, direction, DevicesProperty[m_motu_model-1].port_entry[i].port_offset, 0))
2351 return false;
2355 return true;
2357 /* ======================================================================= */
2359 bool MotuDevice::initDirPortGroups(
2360 enum Streaming::Port::E_Direction direction, unsigned int sample_rate,
2361 unsigned int optical_a_mode, unsigned int optical_b_mode) {
2363 * Internal helper method. Using a PortGroupEntry array the locations of
2364 * channels within a packet is deduced based on the given sample rate and
2365 * optical port modes, and stored back into the PortGroupEntry. Locations
2366 * within the packet start at 10 and are incremented by 3 for each
2367 * subsequent channel. Channels are assumed to be ordered in the packet as
2368 * they are in the port group array. Port groups which are not to be
2369 * created have their packet offset set to -1.
2371 * Notes:
2372 * - When the ports are created by addDirPortGroups() the port_order field
2373 * is used to order the additions. This way the first ports created do
2374 * not necessarily have to be those which appear in the packets first.
2376 * - Currently ports are not flagged for creation if they are disabled due
2377 * to sample rate or optical mode. However, it might be better to
2378 * unconditionally create all ports and just disable those which are not
2379 * active.
2381 signed int i;
2382 unsigned int dir = direction==Streaming::Port::E_Capture?MOTU_PA_IN:MOTU_PA_OUT;
2383 const signed int mode_idx = direction==Streaming::Port::E_Capture?1:0;
2384 unsigned int flags = 0;
2385 unsigned int portgroup_flags;
2386 signed int pkt_ofs;
2387 const DevicePropertyEntry *devprop = &DevicesProperty[m_motu_model-1];
2388 signed int n_groups = devprop->n_portgroup_entries;
2390 if (n_groups <= 0)
2391 return true;
2393 /* Port data starts at offset 10 on most models, and 4 on the 828mk1 */
2394 if (m_motu_model == MOTU_MODEL_828MkI)
2395 pkt_ofs = 4;
2396 else
2397 pkt_ofs = 10;
2399 if ( sample_rate > 96000 )
2400 flags |= MOTU_PA_RATE_4x;
2401 else if ( sample_rate > 48000 )
2402 flags |= MOTU_PA_RATE_2x;
2403 else
2404 flags |= MOTU_PA_RATE_1x;
2406 switch (optical_a_mode) {
2407 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_OPTICAL_ANY; break;
2408 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_OPTICAL_OFF; break;
2409 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_OPTICAL_ADAT; break;
2410 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_OPTICAL_TOSLINK; break;
2412 switch (optical_b_mode) {
2413 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_MK3_OPT_B_ANY; break;
2414 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_MK3_OPT_B_OFF; break;
2415 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_MK3_OPT_B_ADAT; break;
2416 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_MK3_OPT_B_TOSLINK; break;
2419 fprintf(stderr, "initDirPortGroups(): flags=0x%08x, opta=0x%x, optb=0x%x\n",
2420 flags, optical_a_mode, optical_b_mode);
2422 /* Scan through the port groups, allocating packet offsets for all
2423 * port groups which are found to be active in the device's current state.
2425 for (i=0; i<n_groups; i++) {
2426 portgroup_flags = devprop->portgroup_entry[i].flags;
2427 /* For devices without one or more optical ports, ensure the tests
2428 * on the optical ports always returns "true".
2430 if (optical_a_mode == MOTU_OPTICAL_MODE_NONE)
2431 portgroup_flags |= MOTU_PA_OPTICAL_ANY;
2432 if (optical_b_mode == MOTU_OPTICAL_MODE_NONE)
2433 portgroup_flags |= MOTU_PA_MK3_OPT_B_ANY;
2435 devprop->portgroup_entry[i].group_pkt_offset[mode_idx] = -1;
2436 if (( portgroup_flags & dir ) &&
2437 ( portgroup_flags & MOTU_PA_RATE_MASK & flags ) &&
2438 ( portgroup_flags & MOTU_PA_OPTICAL_MASK & flags ) &&
2439 ( portgroup_flags & MOTU_PA_MK3_OPT_B_MASK & flags )) {
2440 if ((portgroup_flags & MOTU_PA_PADDING) == 0) {
2441 devprop->portgroup_entry[i].group_pkt_offset[mode_idx] = pkt_ofs;
2443 pkt_ofs += 3*devprop->portgroup_entry[i].n_channels;
2447 /* The 828mk1 has an additional 6 bytes tacked onto the end of the
2448 * packet sent by it, which we must account for when using pkt_ofs as a
2449 * proxy for size.
2451 if (direction==Streaming::Port::E_Capture && m_motu_model==MOTU_MODEL_828MkI)
2452 pkt_ofs += 6;
2454 if (direction == Streaming::Port::E_Capture)
2455 m_rx_event_size = pkt_ofs;
2456 else
2457 m_tx_event_size = pkt_ofs;
2459 fprintf(stderr, "initDirPortGroups(): rxsize=%d, txsize=%d\n",
2460 m_rx_event_size, m_tx_event_size);
2462 return true;
2464 /* ======================================================================= */
2466 bool MotuDevice::addDirPortGroups(
2467 enum Streaming::Port::E_Direction direction, unsigned int sample_rate,
2468 unsigned int optical_a_mode, unsigned int optical_b_mode) {
2470 * Internal helper method. Using a PortGroupEntry array previously
2471 * initialised with a call to initPortGroups(), ports are created for each
2472 * active channel of the interface. The locations of channels within a
2473 * packet are obtained from the group_pkt_offset field which was set by
2474 * initPortGroups() and the order they should be created in is specifed by
2475 * the port_order field of a port group.
2477 * The port_order functionality is helpful if it's more convenient to have a
2478 * particular port show up first in jackd even through it's located in the
2479 * middle of the packet. If the port_order field of the first port group is
2480 * -1 it is assumed that the port creation is to happen in the order
2481 * specified in the port group list.
2483 * A port group is taken to be inactive if its group_pkt_offset is set to -1.
2485 const char *mode_str = direction==Streaming::Port::E_Capture?"cap":"pbk";
2486 const signed int mode_idx = direction==Streaming::Port::E_Capture?1:0;
2487 Streaming::StreamProcessor *s_processor;
2488 signed int i;
2489 char *buff;
2490 const DevicePropertyEntry *devprop = &DevicesProperty[m_motu_model-1];
2491 signed int n_groups = devprop->n_portgroup_entries;
2492 signed int creation_indices[n_groups];
2493 signed int create_in_order;
2495 if (n_groups <= 0)
2496 return true;
2498 // retrieve the ID
2499 std::string id=std::string("dev?");
2500 if(!getOption("id", id)) {
2501 debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n");
2504 if (direction == Streaming::Port::E_Capture) {
2505 s_processor = m_receiveProcessor;
2506 } else {
2507 s_processor = m_transmitProcessor;
2510 for (i=0; i<n_groups; i++) {
2511 creation_indices[i] = -1;
2513 create_in_order = devprop->portgroup_entry[0].port_order<0;
2515 /* First scan through the port groups to determine the creation order */
2516 for (i=0; i<n_groups; i++) {
2517 if (devprop->portgroup_entry[i].group_pkt_offset[mode_idx] >= 0) {
2518 if (create_in_order)
2519 creation_indices[i] = i;
2520 else
2521 creation_indices[devprop->portgroup_entry[i].port_order] = i;
2525 /* Now run through the portgroup list again, this time in creation order,
2526 * to make the ports.
2528 for (i=0; i<n_groups; i++) {
2529 char namestr[64];
2530 signed int ch;
2531 signed int entry;
2532 if (creation_indices[i] < 0)
2533 continue;
2534 entry = creation_indices[i];
2535 for (ch=0; ch<devprop->portgroup_entry[entry].n_channels; ch++) {
2536 /* Deduce the full channel name */
2537 if (strstr(devprop->portgroup_entry[entry].group_name_format, "%d") != NULL)
2538 snprintf(namestr, sizeof(namestr), devprop->portgroup_entry[entry].group_name_format,
2539 ch+1+devprop->portgroup_entry[entry].port_num_offset);
2540 else
2541 if (strstr(devprop->portgroup_entry[entry].group_name_format, "%s") != NULL)
2542 snprintf(namestr, sizeof(namestr), devprop->portgroup_entry[entry].group_name_format,
2543 (ch & 0x1)?"R":"L");
2544 else
2545 snprintf(namestr, sizeof(namestr), "%s", devprop->portgroup_entry[entry].group_name_format);
2546 asprintf(&buff,"%s_%s_%s" , id.c_str(), mode_str, namestr);
2547 if (!addPort(s_processor, buff, direction,
2548 devprop->portgroup_entry[entry].group_pkt_offset[mode_idx]+3*ch, 0))
2549 return false;
2553 return true;
2555 /* ======================================================================== */
2557 unsigned int MotuDevice::ReadRegister(fb_nodeaddr_t reg) {
2559 * Attempts to read the requested register from the MOTU.
2562 quadlet_t quadlet = 0;
2564 /* If the supplied register has no upper bits set assume it's a G1/G2
2565 * register which is assumed to be relative to MOTU_REG_BASE_ADDR.
2567 if ((reg & MOTU_REG_BASE_ADDR) == 0)
2568 reg |= MOTU_REG_BASE_ADDR;
2570 // Note: 1394Service::read() expects a physical ID, not the node id
2571 if (get1394Service().read(0xffc0 | getNodeId(), reg, 1, &quadlet) <= 0) {
2572 debugError("Error doing motu read from register 0x%012llx\n",reg);
2575 return CondSwapFromBus32(quadlet);
2578 signed int
2579 MotuDevice::readBlock(fb_nodeaddr_t reg, quadlet_t *buf, signed int n_quads) {
2581 // Read "n_quads" quadlets from the device starting at register "reg" into
2582 // the buffer pointed to by "buf". "buf" is assumed to have been
2583 // preallocated and be large enough for the requested data.
2585 signed int i;
2587 if (get1394Service().read(0xffc0 | getNodeId(), reg, n_quads, buf) <= 0) {
2588 debugError("Error doing motu block read of %d quadlets from register 0x%llx\n", n_quads, reg);
2589 return -1;
2591 for (i=0; i<n_quads; i++) {
2592 buf[i] = CondSwapFromBus32(buf[i]);
2594 return 0;
2597 signed int MotuDevice::WriteRegister(fb_nodeaddr_t reg, quadlet_t data) {
2599 * Attempts to write the given data to the requested MOTU register.
2602 unsigned int err = 0;
2603 data = CondSwapToBus32(data);
2605 /* If the supplied register has no upper bits set assume it's a G1/G2
2606 * register which is assumed to be relative to MOTU_REG_BASE_ADDR.
2608 if ((reg & MOTU_REG_BASE_ADDR) == 0)
2609 reg |= MOTU_REG_BASE_ADDR;
2611 // Note: 1394Service::write() expects a physical ID, not the node id
2612 if (get1394Service().write(0xffc0 | getNodeId(), reg, 1, &data) <= 0) {
2613 err = 1;
2614 debugError("Error doing motu write to register 0x%012llx\n",reg);
2617 SleepRelativeUsec(100);
2618 return (err==0)?0:-1;
2621 signed int
2622 MotuDevice::writeBlock(fb_nodeaddr_t reg, quadlet_t *data, signed int n_quads) {
2624 // Write n_quads quadlets from "data" to the device register "reg". Note that
2625 // any necessary byte swapping is done in place, so the contents of "data"
2626 // may be altered by this function.
2628 signed int ret = 0;
2629 signed int i;
2630 for (i=0; i<n_quads; i++) {
2631 data[i] = CondSwapToBus32(data[i]);
2633 if (get1394Service().write(0xffc0 | getNodeId(), reg, n_quads, data) <= 0) {
2634 ret = -1;
2635 debugError("Error doing motu block write of %d quadlets to register 0x%llx\n", n_quads, reg);
2637 return ret;