motu: the 4pre channel layout within packets is now believed to be correct. Thanks...
[ffado.git] / libffado / src / motu / motu_avdevice.cpp
blob5ce648493a995b853c4be2861cd153522c4e3d72
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"},
93 {FW_VENDORID_MOTU, 0, 0x00000045, 0x000001f2, MOTU_MODEL_4PRE, "MOTU", "4pre"},
96 // Ports declarations
97 const PortEntry Ports_828MKI[] =
99 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4},
100 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 7},
101 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
102 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
103 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
104 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
105 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
106 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
107 {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 52},
108 {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 55},
109 {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 28},
110 {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 31},
111 {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 34},
112 {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 37},
113 {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 40},
114 {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 43},
115 {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 46},
116 {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 49},
119 const PortEntry Ports_896HD[] =
121 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
122 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
123 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
124 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
125 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 16},
126 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 10},
127 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 19},
128 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 13},
129 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 22},
130 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 16},
131 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 25},
132 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 19},
133 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 28},
134 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 22},
135 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 31},
136 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 25},
137 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 34},
138 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 28},
139 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 37},
140 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 31},
141 {"MainOut-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
142 {"MainOut-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
143 {"unknown-1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
144 {"unknown-2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
145 {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 46},
146 {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 49},
147 {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 52},
148 {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 55},
149 {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 58},
150 {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 61},
151 {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
152 {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
153 // AES/EBU location with ADAT active
154 {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
155 {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
156 {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, 58},
157 {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, 61},
158 // AES/EBU location with no ADAT active
159 {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF, 46},
160 {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF, 49},
163 const PortEntry Ports_828MKII[] =
165 {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
166 {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
167 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
168 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
169 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
170 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
171 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
172 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
173 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
174 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
175 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
176 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
177 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
178 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
179 {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
180 {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
181 {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 46},
182 {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 49},
183 {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 52},
184 {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 55},
185 {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 58},
186 {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 61},
187 {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
188 {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
189 {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
190 {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
193 const PortEntry Ports_TRAVELER[] =
195 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
196 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
197 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
198 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
199 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 16},
200 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 10},
201 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 19},
202 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 13},
203 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 22},
204 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 16},
205 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 25},
206 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 19},
207 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 28},
208 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 22},
209 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 31},
210 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 25},
211 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 34},
212 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 28},
213 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 37},
214 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 31},
215 {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
216 {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
217 {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_OPTICAL_ADAT, 46},
218 {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_OPTICAL_ADAT, 49},
219 {"Toslink1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 46},
220 {"Toslink2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 49},
221 {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 52},
222 {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 55},
223 {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 58},
224 {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 61},
225 {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
226 {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
227 {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
228 {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
231 const PortEntry Ports_ULTRALITE[] =
233 {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
234 {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
235 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
236 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
237 {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
238 {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
239 {"Analog1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
240 {"Analog2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
241 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
242 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
243 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
244 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
245 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
246 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
247 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
248 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
249 {"SPDIF1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
250 {"SPDIF2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
251 {"Padding1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 46},
252 {"Padding2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 49},
253 {"SPDIF1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 46},
254 {"SPDIF2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 49},
257 const PortEntry Ports_8PRE[] =
259 {"Analog1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
260 {"Analog2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
261 {"Analog3", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
262 {"Analog4", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
263 {"Analog5", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
264 {"Analog6", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
265 {"Analog7", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
266 {"Analog8", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
267 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
268 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
269 {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
270 {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
271 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
272 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
273 {"Padding1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_OFF|MOTU_PA_PADDING, 22},
274 {"Padding2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_OFF|MOTU_PA_PADDING, 25},
275 {"ADAT1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 40},
276 {"ADAT1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 22},
277 {"ADAT2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 43},
278 {"ADAT2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 25},
279 {"ADAT3", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 46},
280 {"ADAT3", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 28},
281 {"ADAT4", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 49},
282 {"ADAT4", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 31},
283 {"ADAT5", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 52},
284 {"ADAT5", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 34},
285 {"ADAT6", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 55},
286 {"ADAT6", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 37},
287 {"ADAT7", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 58},
288 {"ADAT7", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 40},
289 {"ADAT8", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 61},
290 {"ADAT8", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 43},
293 const PortEntry Ports_828mk3[] =
295 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 10},
296 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 13},
297 {"Unknown-L", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 10},
298 {"Unknown-R", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 13},
299 {"Mic-1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 10},
300 {"Mic-2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 13},
301 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 16},
302 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 19},
303 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 22},
304 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 25},
305 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 28},
306 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 31},
307 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 34},
308 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 37},
309 {"MainOut-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 40},
310 {"MainOut-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 43},
311 {"Return-1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 40},
312 {"Return-2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 43},
313 {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 46},
314 {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 49},
315 {"Unknown-1", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 46},
316 {"Unknown-2", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 49},
317 {"Reverb-1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 52},
318 {"Reverb-2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 55},
320 // Optical port locations are a bit messy with the Mark 3 devices since
321 // there are two optical ports whose modes can be independently set.
322 // First take care of the output direction.
324 {"Toslink-A1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 52},
325 {"Toslink-A2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 55},
326 {"ADAT-A1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 52},
327 {"ADAT-A2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 55},
328 {"ADAT-A3", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 58},
329 {"ADAT-A4", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 61},
330 {"ADAT-A5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 64},
331 {"ADAT-A6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 67},
332 {"ADAT-A7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 70},
333 {"ADAT-A8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 73},
335 {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 52},
336 {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 55},
337 {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 58},
338 {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 61},
339 {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 76},
340 {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 79},
341 {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 64},
342 {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 67},
343 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 76},
344 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 79},
345 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 82},
346 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 85},
347 {"ADAT-B5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 88},
348 {"ADAT-B6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 91},
349 {"ADAT-B7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 94},
350 {"ADAT-B8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 97},
351 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 64},
352 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 67},
353 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 70},
354 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 73},
356 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 58},
357 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 61},
358 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 64},
359 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 67},
360 {"ADAT-B5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 70},
361 {"ADAT-B6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 73},
362 {"ADAT-B7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 76},
363 {"ADAT-B8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 79},
364 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 58},
365 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 61},
366 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 64},
367 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 67},
369 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 52},
370 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 55},
371 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 58},
372 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 61},
373 {"ADAT-B5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 64},
374 {"ADAT-B6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 67},
375 {"ADAT-B7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 70},
376 {"ADAT-B8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 73},
377 {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 52},
378 {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 55},
379 {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 58},
380 {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 61},
382 // Now deal with the input side of things. Firstly comes two channels
383 // which are yet to be identified at 1x rates.
384 {"Unknown-1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 58},
385 {"Unknown-2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 61},
387 // Follow up with the optical input port details.
389 {"Toslink-A1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 64},
390 {"Toslink-A2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 67},
391 {"Toslink-A1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 58},
392 {"Toslink-A2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 61},
393 {"ADAT-A1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 64},
394 {"ADAT-A2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 67},
395 {"ADAT-A3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 70},
396 {"ADAT-A4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 73},
397 {"ADAT-A5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 76},
398 {"ADAT-A6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 79},
399 {"ADAT-A7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 82},
400 {"ADAT-A8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 85},
401 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 88},
402 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 91},
403 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 94},
404 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 97},
405 {"ADAT-B5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 100},
406 {"ADAT-B6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 103},
407 {"ADAT-B7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 106},
408 {"ADAT-B8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 109},
409 {"ADAT-A1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 58},
410 {"ADAT-A2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 61},
411 {"ADAT-A3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 64},
412 {"ADAT-A4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 67},
413 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 70},
414 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 73},
415 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 76},
416 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 79},
417 {"Unknown-3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 82},
418 {"Unknown-4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 85},
420 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 64},
421 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 67},
422 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 58},
423 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 61},
424 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 70},
425 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 73},
426 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 64},
427 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 67},
428 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 88},
429 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 91},
430 {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 70},
431 {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 73},
432 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 64},
433 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 67},
434 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 70},
435 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 73},
436 {"ADAT-B5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 76},
437 {"ADAT-B6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 79},
438 {"ADAT-B7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 82},
439 {"ADAT-B8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 85},
440 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 58},
441 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 61},
442 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 64},
443 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 67},
444 {"Unknown-3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 70},
445 {"Unknown-4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 73},
447 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 70},
448 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 73},
449 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 76},
450 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 79},
451 {"ADAT-B5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 82},
452 {"ADAT-B6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 85},
453 {"ADAT-B7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 88},
454 {"ADAT-B8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 91},
455 {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 64},
456 {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 67},
457 {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 70},
458 {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 73},
459 {"Unknown-3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 76},
460 {"Unknown-4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 79},
464 const PortEntry Ports_ULTRALITEmk3[] =
466 {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
467 {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
468 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
469 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
470 {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
471 {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
472 {"Analog1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
473 {"Analog2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
474 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
475 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
476 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
477 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
478 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
479 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
480 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
481 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
482 {"SPDIF1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
483 {"SPDIF2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
484 {"Padding1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 46},
485 {"Padding2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 49},
486 {"SPDIF1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 46},
487 {"SPDIF2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 49},
490 const PortEntry Ports_ULTRALITEmk3_hybrid[] =
492 {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
493 {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
494 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
495 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
496 {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
497 {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
498 {"Analog1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
499 {"Analog2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
500 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
501 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
502 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
503 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
504 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
505 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
506 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
507 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
508 {"SPDIF1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
509 {"SPDIF2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
510 {"Reverb1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 46},
511 {"Reverb2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 49},
512 {"Unknown1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 52},
513 {"Unknown2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 55},
514 {"Unknown3", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 58},
515 {"Unknown4", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 61},
517 {"SPDIF1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 46},
518 {"SPDIF2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 49},
521 /* FIXME: as of 5 Aug 2010 this is still under development */
522 const PortEntry Ports_TRAVELERmk3[] =
524 {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 10},
525 {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 13},
526 {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 10},
527 {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 13},
528 {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 16},
529 {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 19},
530 {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 22},
531 {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 25},
532 {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 28},
533 {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 31},
534 {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 34},
535 {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 37},
536 {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 40},
537 {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 43},
538 {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 46},
539 {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 49},
540 {"Reverb1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 52},
541 {"Reverb2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 55},
542 {"Unknown1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 58},
543 {"Unknown2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 61},
545 // FIXME: optical port details to be filled in later.
546 #if 0
547 {"Toslink1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 46},
548 {"Toslink2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 49},
549 {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 52},
550 {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 55},
551 {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 58},
552 {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 61},
553 {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
554 {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
555 {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
556 {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
557 #endif
560 // FIXME: The following tables relate to the new PortGroupEntry mechanism,
561 // used to convey the same information as the old PortEntry tables but in a
562 // more compact and maintainable form. These aren't actually used yet since
563 // the functionality of addDirPortGroups() still needs to be tested. Once
564 // this is done, all calls to addDirPorts() will be replaced with calls to
565 // addDirPortGroups(). After this is working the old PortEntry tables can
566 // be removed.
568 PortGroupEntry PortGroups_828MKI[] =
570 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, -1, },
571 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
572 {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, },
573 {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, },
576 PortGroupEntry PortGroups_896HD[] =
578 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, -1, },
579 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
580 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
581 {"MainOut-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
582 {"unknown-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
583 {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, },
584 {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, },
585 {"AES/EBU%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
588 PortGroupEntry PortGroups_828MKII[] =
590 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, -1},
591 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
592 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
593 {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
594 {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
595 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
596 {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, },
597 {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, },
600 PortGroupEntry PortGroups_TRAVELER[] =
602 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, -1, },
603 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
604 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
605 {"AES/EBU%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
606 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_OPTICAL_ADAT, },
607 {"Toslink%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, },
608 {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, },
609 {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, },
612 PortGroupEntry PortGroups_ULTRALITE[] =
614 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
615 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
616 {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, },
617 {"Analog%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4, },
618 {"Analog%d", 6, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 5, 2},
619 {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
620 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 6, },
621 {"Padding%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 7, },
624 PortGroupEntry PortGroups_8PRE[] =
626 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
627 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, },
628 {"Analog%d", 8, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
629 {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
630 {"Padding%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 4, },
631 {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 5, },
632 {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, 6, },
635 PortGroupEntry PortGroups_828mk3[] =
637 {"Mic-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, -1, },
638 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
639 {"Unknown-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, },
640 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
641 {"Return-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
642 {"MainOut-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
643 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
644 {"Unknown-%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, },
645 {"Reverb-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
647 // For input at 1x rates there are an additional 2 channel slots which
648 // are yet to be identified.
650 {"UnknownA-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
652 // Optical ports. Note: UnknownB is flagged as being always present at
653 // 2x rates in the input stream. This is yet to be verified. In the
654 // case of the old PortEntry definition UnknownB's equivalent was only
655 // flagged as present if optical B was set to ADAT; this seems wrong on
656 // reflection.
658 // The purpose of the Toslink-{A,B}-extra-* ports is not yet known,
659 // beyond the observed fact that allowance must be made for them in the
660 // packet format whenever the corresponding optical port is set to
661 // Toslink mode. They may be padding, but for now connect them with
662 // audio ports so users can experiment to see if they correspond to
663 // anything interesting.
665 {"Toslink-A%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, },
666 {"Toslink-A-extra-%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, },
667 {"ADAT-A%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
668 {"ADAT-A%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
669 {"Toslink-B%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_TOSLINK, },
670 {"Toslink-B-extra-%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_TOSLINK, },
671 {"ADAT-B%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
672 {"ADAT-B%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
673 {"UnknownB-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ANY, },
676 PortGroupEntry PortGroups_ULTRALITEmk3[] =
678 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 6, },
679 {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
680 {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
681 {"Analog%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
682 {"Analog%d", 6, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, 2},
683 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4, },
684 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 5, },
685 {"Reverb-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 7, },
686 {"Padding%d", 4, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 8, },
687 {"Pad out%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 9, },
690 PortGroupEntry PortGroups_ULTRALITEmk3_hybrid[] =
692 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
693 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
694 {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, },
695 {"Analog%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4, },
696 {"Analog%d", 6, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 5, 2, },
697 {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
698 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 6, },
699 {"Reverb%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 7, },
700 {"Unknown%d", 4, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 8, },
703 /* FIXME: as of 5 Aug 2010 this is still under development */
704 PortGroupEntry PortGroups_TRAVELERmk3[] =
706 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, -1, },
707 {"Phones-%s",2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
708 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
709 {"AES/EBU%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
710 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
711 {"Reverb%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
712 {"Unknown%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
714 // FIXME: optical port details still being determined.
716 // The purpose of the Toslink-{A,B}-extra-* ports is not yet known,
717 // beyond the observed fact that allowance must be made for them in the
718 // packet format whenever the corresponding optical port is set to
719 // Toslink mode. They may be padding, but for now connect them with
720 // audio ports so users can experiment to see if they correspond to
721 // anything interesting.
723 {"Toslink-A%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, },
724 {"Toslink-A-extra-%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, },
725 {"ADAT-A%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
726 {"ADAT-A%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
727 {"Toslink-B%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_TOSLINK, },
728 {"Toslink-B-extra-%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_TOSLINK, },
729 {"ADAT-B%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
730 {"ADAT-B%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
731 {"UnknownB-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, },
734 /* FIXME: as of 8 Oct 2010 this is still under development. Presently this
735 * layout is nothing more than an educated guess. The presence of the
736 * Toslink-{A,B}-extra-* ports is even more of a guess, and is based on
737 * the observation that they have so far proved necessary on the mk3
738 * devices which we have been able to explicitly verify.
740 PortGroupEntry PortGroups_896mk3[] =
742 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, -1, },
743 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
744 {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
745 {"MainOut-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
746 {"UnknownIn-%d", 4, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
747 {"AES/EBU%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
748 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
749 {"UnknownOut-%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
750 {"Toslink-A%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, },
751 {"ADAT-A%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
752 {"Toslink-A-extra-%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, },
753 {"ADAT-A%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
754 {"Toslink-B%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_TOSLINK, },
755 {"Toslink-B-extra-%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_TOSLINK, },
756 {"ADAT-B%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
757 {"ADAT-B%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
760 /* Believed correct as of 24 Feb 2014. Thanks to Tim Radvan for testing. */
761 PortGroupEntry PortGroups_4PRE[] =
763 {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
764 {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
765 {"Mic/Line-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, },
766 {"Mic/Guitar-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4, },
767 {"Analog%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 5, },
768 {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
769 {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 6, },
770 {"Extra-%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 7, },
773 #define PORTGROUPS(__model) PortGroups_ ## __model, N_ELEMENTS(PortGroups_ ## __model)
775 /* The order of DevicesProperty entries must match the numeric order of the
776 * MOTU model enumeration (EMotuModel).
778 const DevicePropertyEntry DevicesProperty[] = {
779 // { PortGroups_map, N_ELEMENTS( PortGroups_map ),
780 // Ports_map, N_ELEMENTS( Ports_map ), MaxSR, MixerDescrPtr, Mark3MixerDescrPtr },
781 { PORTGROUPS(828MKII),
782 Ports_828MKII, N_ELEMENTS( Ports_828MKII ), 96000, &Mixer_828Mk2, NULL, },
783 { PORTGROUPS(TRAVELER),
784 Ports_TRAVELER, N_ELEMENTS( Ports_TRAVELER ), 192000, &Mixer_Traveler, NULL, },
785 { PORTGROUPS(ULTRALITE),
786 Ports_ULTRALITE, N_ELEMENTS( Ports_ULTRALITE ), 96000, &Mixer_Ultralite, NULL, },
787 { PORTGROUPS(8PRE),
788 Ports_8PRE, N_ELEMENTS( Ports_8PRE ), 96000, &Mixer_8pre, NULL, },
789 { PORTGROUPS(828MKI),
790 Ports_828MKI, N_ELEMENTS( Ports_828MKI ), 48000, &Mixer_828Mk1, NULL, },
791 { PORTGROUPS(896HD),
792 Ports_896HD, N_ELEMENTS( Ports_896HD ), 192000, &Mixer_896HD, NULL, },
793 { PORTGROUPS(828mk3),
794 Ports_828mk3, N_ELEMENTS( Ports_828mk3 ), 192000 },
795 { PORTGROUPS(ULTRALITEmk3),
796 Ports_ULTRALITEmk3, N_ELEMENTS( Ports_ULTRALITEmk3 ), 192000 }, // Ultralite mk3
797 { PORTGROUPS(ULTRALITEmk3_hybrid),
798 Ports_ULTRALITEmk3_hybrid, N_ELEMENTS( Ports_ULTRALITEmk3_hybrid ), 192000 }, // Ultralite mk3 hybrid
799 { PORTGROUPS(TRAVELERmk3),
800 Ports_TRAVELERmk3, N_ELEMENTS( Ports_TRAVELERmk3 ), 192000 },
801 { PORTGROUPS(896mk3),
802 NULL, 0, 192000 }, // 896 Mk 3
803 { PORTGROUPS(4PRE),
804 NULL, 0, 96000, },
807 MotuDevice::MotuDevice( DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
808 : FFADODevice( d, configRom )
809 , m_motu_model( MOTU_MODEL_NONE )
810 , m_iso_recv_channel ( -1 )
811 , m_iso_send_channel ( -1 )
812 , m_rx_bandwidth ( -1 )
813 , m_tx_bandwidth ( -1 )
814 , m_rx_event_size ( 0 )
815 , m_tx_event_size ( 0 )
816 , m_receiveProcessor ( 0 )
817 , m_transmitProcessor ( 0 )
818 , m_MixerContainer ( NULL )
819 , m_ControlContainer ( NULL )
821 debugOutput( DEBUG_LEVEL_VERBOSE, "Created Motu::MotuDevice (NodeID %d)\n",
822 getConfigRom().getNodeId() );
825 MotuDevice::~MotuDevice()
827 delete m_receiveProcessor;
828 delete m_transmitProcessor;
830 // Free ieee1394 bus resources if they have been allocated
831 if (m_iso_recv_channel>=0 && !get1394Service().freeIsoChannel(m_iso_recv_channel)) {
832 debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free recv iso channel %d\n", m_iso_recv_channel);
834 if (m_iso_send_channel>=0 && !get1394Service().freeIsoChannel(m_iso_send_channel)) {
835 debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free send iso channel %d\n", m_iso_send_channel);
838 destroyMixer();
841 bool
842 MotuDevice::probe( Util::Configuration& c, ConfigRom& configRom, bool generic)
844 if(generic) return false;
846 unsigned int vendorId = configRom.getNodeVendorId();
847 unsigned int unitVersion = configRom.getUnitVersion();
848 unsigned int unitSpecifierId = configRom.getUnitSpecifierId();
850 for ( unsigned int i = 0;
851 i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
852 ++i )
854 if ( ( supportedDeviceList[i].vendor_id == vendorId )
855 && ( supportedDeviceList[i].unit_version == unitVersion )
856 && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
859 if (supportedDeviceList[i].model == MOTU_MODEL_NONE) {
860 debugOutput( DEBUG_LEVEL_VERBOSE, "%s %s found but is not currently supported by FFADO\n",
861 supportedDeviceList[i].vendor_name, supportedDeviceList[i].model_name);
862 debugOutput( DEBUG_LEVEL_VERBOSE, " unitVersion=0x%08x\n", unitVersion);
863 return false;
866 return true;
870 return false;
873 FFADODevice *
874 MotuDevice::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
876 return new MotuDevice(d, configRom);
879 bool
880 MotuDevice::discover()
882 unsigned int vendorId = getConfigRom().getNodeVendorId();
883 unsigned int unitVersion = getConfigRom().getUnitVersion();
884 unsigned int unitSpecifierId = getConfigRom().getUnitSpecifierId();
886 for ( unsigned int i = 0;
887 i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
888 ++i )
890 if ( ( supportedDeviceList[i].vendor_id == vendorId )
891 && ( supportedDeviceList[i].unit_version == unitVersion )
892 && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
895 m_model = &(supportedDeviceList[i]);
896 m_motu_model=supportedDeviceList[i].model;
900 if (m_model == NULL) {
901 return false;
904 debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
905 m_model->vendor_name, m_model->model_name);
907 if (m_motu_model == MOTU_MODEL_NONE) {
908 debugOutput( DEBUG_LEVEL_VERBOSE, "This MOTU device is not currently supported by FFADO\n");
909 return false;
912 // The MOTU 8pre seems to power up in "converter" mode. To toggle it
913 // into "interface" mode it is necessary to do a write to the clock
914 // control register. Since setClockCtrlRegister() will only do a write
915 // if something is explicitly set it isn't sufficient to do something like
916 // setClockCtrlRegister(-1, MOTU_CLKSRC_UNCHANGED)
917 // Instead, we request that the clock source be set to its present value;
918 // effectively this preserves the interface's current clock settings.
919 if (m_motu_model == MOTU_MODEL_8PRE) {
920 setClockCtrlRegister(-1, getHwClockSource());
923 // The MOTU 828mk1 device seems to power up without a valid clock source
924 // configured (the relevant bits don't seem to map to anything sensible).
925 // Deal with this if necessary.
926 if (m_motu_model == MOTU_MODEL_828MkI) {
927 signed int csrc = getHwClockSource();
928 if (csrc == MOTU_CLKSRC_NONE)
929 csrc = MOTU_CLKSRC_INTERNAL;
930 setClockCtrlRegister(-1, csrc);
933 if (!buildMixer()) {
934 debugWarning("Could not build mixer\n");
937 return true;
940 enum FFADODevice::eStreamingState
941 MotuDevice::getStreamingState()
943 unsigned int val = ReadRegister(MOTU_REG_ISOCTRL);
944 /* Streaming is active if either bit 22 (Motu->PC streaming
945 * enable) or bit 30 (PC->Motu streaming enable) is set.
947 debugOutput(DEBUG_LEVEL_VERBOSE, "MOTU_REG_ISOCTRL: %08x\n", val);
949 if((val & 0x40400000) != 0) {
950 return eSS_Both;
951 } else if ((val & 0x40000000) != 0) {
952 return eSS_Receiving;
953 } else if ((val & 0x00400000) != 0) {
954 return eSS_Sending;
955 } else {
956 return eSS_Idle;
961 MotuDevice::getSamplingFrequency( ) {
963 * Retrieve the current sample rate from the MOTU device.
965 quadlet_t q = 0;
966 int rate = 0;
967 unsigned int rate_base_mask, rate_base48k;
968 unsigned int rate_mult_mask, rate_mult2, rate_mult4;
970 if (m_motu_model == MOTU_MODEL_828MkI) {
971 /* The original MOTU interfaces did things rather differently */
972 q = ReadRegister(MOTU_G1_REG_CONFIG);
973 if ((q & MOTU_G1_RATE_MASK) == MOTU_G1_RATE_44100)
974 rate = 44100;
975 else
976 rate = 48000;
977 return rate;
980 /* The way the rate is managed is the same across G2 and G3 devices,
981 * but the actual bits used in the clock control register is different.
983 if (getDeviceGeneration() == MOTU_DEVICE_G2) {
984 rate_base_mask = MOTU_RATE_BASE_MASK;
985 rate_base48k = MOTU_RATE_BASE_48000;
986 rate_mult_mask = MOTU_RATE_MULTIPLIER_MASK;
987 rate_mult2 = MOTU_RATE_MULTIPLIER_2X;
988 rate_mult4 = MOTU_RATE_MULTIPLIER_4X;
989 } else {
990 rate_base_mask = MOTU_G3_RATE_BASE_MASK;
991 rate_base48k = MOTU_G3_RATE_BASE_48000;
992 rate_mult_mask = MOTU_G3_RATE_MULTIPLIER_MASK;
993 rate_mult2 = MOTU_G3_RATE_MULTIPLIER_2X;
994 rate_mult4 = MOTU_G3_RATE_MULTIPLIER_4X;
997 q = ReadRegister(MOTU_REG_CLK_CTRL);
998 if ((q & rate_base_mask) == rate_base48k)
999 rate = 48000;
1000 else
1001 rate = 44100;
1002 if ((q & rate_mult_mask) == rate_mult4)
1003 rate *= 4;
1004 else
1005 if ((q & rate_mult_mask) == rate_mult2)
1006 rate *= 2;
1008 return rate;
1012 MotuDevice::getConfigurationId()
1014 return 0;
1017 unsigned int
1018 MotuDevice::getHwClockSource()
1020 unsigned int reg;
1022 if (m_motu_model == MOTU_MODEL_828MkI) {
1023 reg = ReadRegister(MOTU_G1_REG_CONFIG);
1024 switch (reg & MOTU_G1_CLKSRC_MASK) {
1025 case MOTU_G1_CLKSRC_INTERNAL: return MOTU_CLKSRC_INTERNAL;
1026 case MOTU_G1_CLKSRC_ADAT_9PIN: return MOTU_CLKSRC_ADAT_9PIN;
1027 case MOTU_G1_CLKSRC_SPDIF: return MOTU_CLKSRC_SPDIF_TOSLINK;
1028 case MOTU_G1_CLKSRC_ADAT_OPTICAL: return MOTU_CLKSRC_ADAT_OPTICAL;
1030 return MOTU_CLKSRC_NONE;
1033 reg = ReadRegister(MOTU_REG_CLK_CTRL);
1034 if (getDeviceGeneration() == MOTU_DEVICE_G2) {
1035 switch (reg & MOTU_G2_CLKSRC_MASK) {
1036 case MOTU_G2_CLKSRC_INTERNAL: return MOTU_CLKSRC_INTERNAL;
1037 case MOTU_G2_CLKSRC_ADAT_OPTICAL: return MOTU_CLKSRC_ADAT_OPTICAL;
1038 case MOTU_G2_CLKSRC_SPDIF_TOSLINK: return MOTU_CLKSRC_SPDIF_TOSLINK;
1039 case MOTU_G2_CLKSRC_SMPTE: return MOTU_CLKSRC_SMPTE;
1040 case MOTU_G2_CLKSRC_WORDCLOCK: return MOTU_CLKSRC_WORDCLOCK;
1041 case MOTU_G2_CLKSRC_ADAT_9PIN: return MOTU_CLKSRC_ADAT_9PIN;
1042 case MOTU_G2_CLKSRC_AES_EBU: return MOTU_CLKSRC_AES_EBU;
1044 } else {
1045 /* Handle G3 devices */
1046 switch (reg & MOTU_G3_CLKSRC_MASK) {
1047 case MOTU_G3_CLKSRC_INTERNAL: return MOTU_CLKSRC_INTERNAL;
1048 case MOTU_G3_CLKSRC_SPDIF: return MOTU_CLKSRC_SPDIF_TOSLINK;
1049 case MOTU_G3_CLKSRC_SMPTE: return MOTU_CLKSRC_SMPTE;
1050 case MOTU_G3_CLKSRC_WORDCLOCK: return MOTU_CLKSRC_WORDCLOCK;
1051 case MOTU_G3_CLKSRC_OPTICAL_A: return MOTU_CLKSRC_OPTICAL_A;
1052 case MOTU_G3_CLKSRC_OPTICAL_B: return MOTU_CLKSRC_OPTICAL_B;
1055 return MOTU_CLKSRC_NONE;
1058 bool
1059 MotuDevice::setClockCtrlRegister(signed int samplingFrequency, unsigned int clock_source)
1062 * Set the MOTU device's samplerate and/or clock source via the clock
1063 * control register. If samplingFrequency <= 0 it remains unchanged. If
1064 * clock_source is MOTU_CLKSRC_UNCHANGED the clock source remains unchanged.
1066 const char *src_name;
1067 quadlet_t q, new_rate=0xffffffff;
1068 signed int i, supported=true, cancel_adat=false;
1069 quadlet_t reg;
1070 unsigned int rate_mask = 0;
1071 unsigned int old_clock_src = getHwClockSource();
1072 signed int device_gen = getDeviceGeneration();
1074 /* Don't touch anything if there's nothing to do */
1075 if (samplingFrequency<=0 && clock_source==MOTU_CLKSRC_NONE)
1076 return true;
1078 if ( samplingFrequency > DevicesProperty[m_motu_model-1].MaxSampleRate )
1079 return false;
1081 /* The original MOTU devices do things differently; they are much
1082 * simpler than the later interfaces.
1084 if (m_motu_model == MOTU_MODEL_828MkI) {
1085 reg = ReadRegister(MOTU_G1_REG_CONFIG);
1086 if (samplingFrequency > 0) {
1087 reg &= ~MOTU_G1_RATE_MASK;
1088 switch (samplingFrequency) {
1089 case 44100:
1090 reg |= MOTU_G1_RATE_44100;
1091 break;
1092 case 48000:
1093 reg |= MOTU_G1_RATE_48000;
1094 break;
1095 default:
1096 // Unsupported rate
1097 return false;
1100 if (clock_source != MOTU_CLKSRC_UNCHANGED) {
1101 switch (clock_source) {
1102 case MOTU_CLKSRC_INTERNAL:
1103 clock_source = MOTU_G1_CLKSRC_INTERNAL; break;
1104 case MOTU_CLKSRC_SPDIF_TOSLINK:
1105 clock_source = MOTU_G1_CLKSRC_SPDIF; break;
1106 case MOTU_CLKSRC_ADAT_9PIN:
1107 clock_source = MOTU_G1_CLKSRC_ADAT_9PIN; break;
1108 case MOTU_CLKSRC_ADAT_OPTICAL:
1109 clock_source = MOTU_G1_CLKSRC_ADAT_OPTICAL; break;
1110 default:
1111 // Unsupported clock source
1112 return false;
1114 reg &= ~MOTU_G1_CLKSRC_MASK;
1115 reg |= clock_source;
1117 if (WriteRegister(MOTU_G1_REG_CONFIG, reg) != 0)
1118 return false;
1119 return true;
1122 /* The rest of this function deals with later generation devices */
1124 reg = ReadRegister(MOTU_REG_CLK_CTRL);
1126 /* The method of controlling the sampling rate is the same for G2/G3
1127 * devices but the actual bits used in the rate control register differ.
1129 if (device_gen == MOTU_DEVICE_G2) {
1130 rate_mask = MOTU_RATE_BASE_MASK | MOTU_RATE_MULTIPLIER_MASK;
1131 switch ( samplingFrequency ) {
1132 case -1: break;
1133 case 44100: new_rate = MOTU_RATE_BASE_44100 | MOTU_RATE_MULTIPLIER_1X; break;
1134 case 48000: new_rate = MOTU_RATE_BASE_48000 | MOTU_RATE_MULTIPLIER_1X; break;
1135 case 88200: new_rate = MOTU_RATE_BASE_44100 | MOTU_RATE_MULTIPLIER_2X; break;
1136 case 96000: new_rate = MOTU_RATE_BASE_48000 | MOTU_RATE_MULTIPLIER_2X; break;
1137 case 176400: new_rate = MOTU_RATE_BASE_44100 | MOTU_RATE_MULTIPLIER_4X; break;
1138 case 192000: new_rate = MOTU_RATE_BASE_48000 | MOTU_RATE_MULTIPLIER_4X; break;
1139 default:
1140 supported=false;
1142 } else
1143 if (device_gen == MOTU_DEVICE_G3) {
1144 rate_mask = MOTU_G3_RATE_BASE_MASK | MOTU_G3_RATE_MULTIPLIER_MASK;
1145 switch ( samplingFrequency ) {
1146 case -1: break;
1147 case 44100: new_rate = MOTU_G3_RATE_BASE_44100 | MOTU_G3_RATE_MULTIPLIER_1X; break;
1148 case 48000: new_rate = MOTU_G3_RATE_BASE_48000 | MOTU_G3_RATE_MULTIPLIER_1X; break;
1149 case 88200: new_rate = MOTU_G3_RATE_BASE_44100 | MOTU_G3_RATE_MULTIPLIER_2X; break;
1150 case 96000: new_rate = MOTU_G3_RATE_BASE_48000 | MOTU_G3_RATE_MULTIPLIER_2X; break;
1151 case 176400: new_rate = MOTU_G3_RATE_BASE_44100 | MOTU_G3_RATE_MULTIPLIER_4X; break;
1152 case 192000: new_rate = MOTU_G3_RATE_BASE_48000 | MOTU_G3_RATE_MULTIPLIER_4X; break;
1153 default:
1154 supported=false;
1157 /* ADAT output is only possible for sample rates up to 96 kHz. For
1158 * anything higher, force the ADAT channels off.
1160 if (samplingFrequency > 96000) {
1161 cancel_adat = true;
1164 // Sanity check the clock source
1165 if (clock_source>MOTU_CLKSRC_LAST && clock_source!=MOTU_CLKSRC_UNCHANGED)
1166 supported = false;
1168 // Update the clock control register. FIXME: while this is now rather
1169 // comprehensive there may still be a need to manipulate MOTU_REG_CLK_CTRL
1170 // a little more than we do.
1171 if (supported) {
1173 // If optical port must be disabled (because a 4x sample rate has
1174 // been selected) then do so before changing the sample rate. At
1175 // this stage it will be up to the user to re-enable the optical
1176 // port if the sample rate is set to a 1x or 2x rate later.
1177 if (cancel_adat) {
1178 setOpticalMode(MOTU_CTRL_DIR_INOUT, MOTU_OPTICAL_MODE_OFF, MOTU_OPTICAL_MODE_OFF);
1181 // Set up new frequency if requested
1182 if (new_rate != 0xffffffff) {
1183 reg &= ~rate_mask;
1184 reg |= new_rate;
1187 // Set up new clock source if required
1188 if (clock_source != MOTU_CLKSRC_UNCHANGED) {
1189 if (device_gen == MOTU_DEVICE_G2) {
1190 reg &= ~MOTU_G2_CLKSRC_MASK;
1191 switch (clock_source) {
1192 case MOTU_CLKSRC_INTERNAL: reg |= MOTU_G2_CLKSRC_INTERNAL; break;
1193 case MOTU_CLKSRC_ADAT_OPTICAL: reg |= MOTU_G2_CLKSRC_ADAT_OPTICAL; break;
1194 case MOTU_CLKSRC_SPDIF_TOSLINK: reg |= MOTU_G2_CLKSRC_SPDIF_TOSLINK; break;
1195 case MOTU_CLKSRC_SMPTE: reg |= MOTU_G2_CLKSRC_SMPTE; break;
1196 case MOTU_CLKSRC_WORDCLOCK: reg |= MOTU_G2_CLKSRC_WORDCLOCK; break;
1197 case MOTU_CLKSRC_ADAT_9PIN: reg |= MOTU_G2_CLKSRC_ADAT_9PIN; break;
1198 case MOTU_CLKSRC_AES_EBU: reg |= MOTU_G2_CLKSRC_AES_EBU; break;
1200 } else {
1201 reg &= ~MOTU_G3_CLKSRC_MASK;
1202 switch (clock_source) {
1203 case MOTU_CLKSRC_INTERNAL: reg |= MOTU_G3_CLKSRC_INTERNAL; break;
1204 case MOTU_CLKSRC_SPDIF_TOSLINK: reg |= MOTU_G3_CLKSRC_SPDIF; break;
1205 case MOTU_CLKSRC_SMPTE: reg |= MOTU_G3_CLKSRC_SMPTE; break;
1206 case MOTU_CLKSRC_WORDCLOCK: reg |= MOTU_G3_CLKSRC_WORDCLOCK; break;
1207 case MOTU_CLKSRC_OPTICAL_A: reg |= MOTU_G3_CLKSRC_OPTICAL_A; break;
1208 case MOTU_CLKSRC_OPTICAL_B: reg |= MOTU_G3_CLKSRC_OPTICAL_B; break;
1211 } else {
1212 /* Use the device's current clock source to set the clock
1213 * source name registers, which must be done even if we aren't
1214 * changing the clock source.
1216 clock_source = old_clock_src;
1219 // Bits 24-26 of MOTU_REG_CLK_CTRL behave a little differently
1220 // depending on the model. In addition, different bit patterns are
1221 // written depending on whether streaming is enabled, disabled or is
1222 // changing state. For now we go with the combination used when
1223 // streaming is enabled since it seems to work for the other states
1224 // as well. Since device muting can be effected by these bits, we
1225 // may utilise this in future during streaming startup to prevent
1226 // noises during stabilisation.
1228 // For most models (possibly all except the Ultralite) all 3 bits
1229 // can be zero and audio is still output.
1231 // For the Traveler, if bit 26 is set (as it is under other OSes),
1232 // bit 25 functions as a device mute bit: if set, audio is output
1233 // while if 0 the entire device is muted. If bit 26 is unset,
1234 // setting bit 25 doesn't appear to be detrimental.
1236 // For the Ultralite, other OSes leave bit 26 unset. However, unlike
1237 // other devices bit 25 seems to function as a mute bit in this case.
1239 // The function of bit 24 is currently unknown. Other OSes set it
1240 // for all devices so we will too.
1241 reg &= 0xf8ffffff;
1242 if (m_motu_model == MOTU_MODEL_TRAVELER)
1243 reg |= 0x04000000;
1244 reg |= 0x03000000;
1245 if (WriteRegister(MOTU_REG_CLK_CTRL, reg) == 0) {
1246 supported=true;
1247 } else {
1248 supported=false;
1250 // A write to the rate/clock control register requires the
1251 // textual name of the current clock source be sent to the
1252 // clock source name registers. This appears to be the same for
1253 // both G2 and G3 devices.
1254 switch (clock_source) {
1255 case MOTU_CLKSRC_INTERNAL:
1256 src_name = "Internal ";
1257 break;
1258 case MOTU_CLKSRC_ADAT_OPTICAL:
1259 src_name = "ADAT Optical ";
1260 break;
1261 case MOTU_CLKSRC_SPDIF_TOSLINK: {
1262 unsigned int p0_mode;
1263 if (device_gen < MOTU_DEVICE_G3) {
1264 getOpticalMode(MOTU_DIR_IN, &p0_mode, NULL);
1265 } else
1266 p0_mode = MOTU_OPTICAL_MODE_OFF;
1267 if (p0_mode == MOTU_OPTICAL_MODE_TOSLINK)
1268 src_name = "TOSLink ";
1269 else
1270 src_name = "SPDIF ";
1271 break;
1273 case MOTU_CLKSRC_SMPTE:
1274 src_name = "SMPTE ";
1275 break;
1276 case MOTU_CLKSRC_WORDCLOCK:
1277 src_name = "Word Clock In ";
1278 break;
1279 case MOTU_CLKSRC_ADAT_9PIN:
1280 src_name = "ADAT 9-pin ";
1281 break;
1282 case MOTU_CLKSRC_AES_EBU:
1283 src_name = "AES-EBU ";
1284 break;
1285 case MOTU_CLKSRC_OPTICAL_A: {
1286 unsigned int p0_mode;
1287 getOpticalMode(MOTU_DIR_IN, &p0_mode, NULL);
1288 if (p0_mode == MOTU_OPTICAL_MODE_TOSLINK)
1289 src_name = "Toslink-A ";
1290 else
1291 src_name = "ADAT-A Optical ";
1292 break;
1294 case MOTU_CLKSRC_OPTICAL_B: {
1295 unsigned int p1_mode;
1296 getOpticalMode(MOTU_DIR_IN, NULL, &p1_mode);
1297 if (p1_mode == MOTU_OPTICAL_MODE_TOSLINK)
1298 src_name = "Toslink-B ";
1299 else
1300 src_name = "ADAT-B Optical ";
1301 break;
1303 default:
1304 src_name = "Unknown ";
1306 for (i=0; i<16; i+=4) {
1307 q = (src_name[i]<<24) | (src_name[i+1]<<16) |
1308 (src_name[i+2]<<8) | src_name[i+3];
1309 WriteRegister(MOTU_REG_CLKSRC_NAME0+i, q);
1312 return supported;
1315 bool
1316 MotuDevice::setSamplingFrequency( int samplingFrequency )
1319 * Set the MOTU device's samplerate.
1321 return setClockCtrlRegister(samplingFrequency, MOTU_CLKSRC_UNCHANGED);
1324 std::vector<int>
1325 MotuDevice::getSupportedSamplingFrequencies()
1327 std::vector<int> frequencies;
1328 signed int max_freq = DevicesProperty[m_motu_model-1].MaxSampleRate;
1330 /* All MOTUs support 1x rates. All others must be conditional. */
1331 frequencies.push_back(44100);
1332 frequencies.push_back(48000);
1334 if (88200 <= max_freq)
1335 frequencies.push_back(88200);
1336 if (96000 <= max_freq)
1337 frequencies.push_back(96000);
1338 if (176400 <= max_freq)
1339 frequencies.push_back(176400);
1340 if (192000 <= max_freq)
1341 frequencies.push_back(192000);
1342 return frequencies;
1345 FFADODevice::ClockSource
1346 MotuDevice::clockIdToClockSource(unsigned int id) {
1347 ClockSource s;
1348 signed int device_gen = getDeviceGeneration();
1349 s.id = id;
1351 // Assume a clock source is valid/active unless otherwise overridden.
1352 s.valid = true;
1353 s.locked = true;
1354 s.active = true;
1356 switch (id) {
1357 case MOTU_CLKSRC_INTERNAL:
1358 s.type = eCT_Internal;
1359 s.description = "Internal sync";
1360 break;
1361 case MOTU_CLKSRC_ADAT_OPTICAL:
1362 s.type = eCT_ADAT;
1363 s.description = "ADAT optical";
1364 s.valid = s.active = s.locked = (device_gen!=MOTU_DEVICE_G1);
1365 break;
1366 case MOTU_CLKSRC_SPDIF_TOSLINK:
1367 s.type = eCT_SPDIF;
1368 if (device_gen < MOTU_DEVICE_G3)
1369 s.description = "SPDIF/Toslink";
1370 else
1371 s.description = "SPDIF";
1372 break;
1373 case MOTU_CLKSRC_SMPTE:
1374 s.type = eCT_SMPTE;
1375 s.description = "SMPTE";
1376 // Since we don't currently know how to deal with SMPTE on these
1377 // devices make sure the SMPTE clock source is disabled.
1378 s.valid = false;
1379 s.active = false;
1380 s.locked = false;
1381 break;
1382 case MOTU_CLKSRC_WORDCLOCK:
1383 s.type = eCT_WordClock;
1384 s.description = "Wordclock";
1385 s.valid = s.active = s.locked = (device_gen!=MOTU_DEVICE_G1);
1386 break;
1387 case MOTU_CLKSRC_ADAT_9PIN:
1388 s.type = eCT_ADAT;
1389 s.description = "ADAT 9-pin";
1390 break;
1391 case MOTU_CLKSRC_AES_EBU:
1392 s.type = eCT_AES;
1393 s.description = "AES/EBU";
1394 s.valid = s.active = s.locked = (device_gen!=MOTU_DEVICE_G1);
1395 break;
1396 case MOTU_CLKSRC_OPTICAL_A:
1397 s.type = eCT_ADAT;
1398 s.description = "ADAT/Toslink port A";
1399 break;
1400 case MOTU_CLKSRC_OPTICAL_B:
1401 s.type = eCT_ADAT;
1402 s.description = "ADAT/Toslink port B";
1403 break;
1404 default:
1405 s.type = eCT_Invalid;
1408 s.slipping = false;
1409 return s;
1412 FFADODevice::ClockSourceVector
1413 MotuDevice::getSupportedClockSources() {
1414 FFADODevice::ClockSourceVector r;
1415 ClockSource s;
1416 signed int device_gen = getDeviceGeneration();
1418 /* Form a list of clocks supported by MOTU interfaces */
1420 /* All interfaces support an internal clock */
1421 s = clockIdToClockSource(MOTU_CLKSRC_INTERNAL);
1422 r.push_back(s);
1424 if (device_gen==MOTU_DEVICE_G2 || device_gen==MOTU_DEVICE_G1) {
1425 s = clockIdToClockSource(MOTU_CLKSRC_ADAT_OPTICAL);
1426 r.push_back(s);
1429 s = clockIdToClockSource(MOTU_CLKSRC_SPDIF_TOSLINK);
1430 r.push_back(s);
1431 s = clockIdToClockSource(MOTU_CLKSRC_SMPTE);
1432 r.push_back(s);
1434 /* The 828mk1 didn't have a wordclock sync option */
1435 if (device_gen != MOTU_DEVICE_G1) {
1436 s = clockIdToClockSource(MOTU_CLKSRC_WORDCLOCK);
1437 r.push_back(s);
1440 /* The 9-pin ADAT sync was only present on selected G2
1441 * devices. The 828mk1 also offered this.
1443 if (m_motu_model==MOTU_MODEL_828mkII || m_motu_model==MOTU_MODEL_TRAVELER ||
1444 m_motu_model==MOTU_MODEL_896HD || m_motu_model==MOTU_MODEL_828MkI) {
1445 s = clockIdToClockSource(MOTU_CLKSRC_ADAT_9PIN);
1446 r.push_back(s);
1448 /* AES/EBU is present on the G2/G3 Travelers and 896HDs */
1449 if (m_motu_model==MOTU_MODEL_TRAVELER || m_motu_model==MOTU_MODEL_TRAVELERmk3 ||
1450 m_motu_model==MOTU_MODEL_896HD || m_motu_model==MOTU_MODEL_896mk3) {
1451 s = clockIdToClockSource(MOTU_CLKSRC_AES_EBU);
1452 r.push_back(s);
1455 /* Dual-port ADAT is a feature of the G3 devices, and then only some */
1456 if (m_motu_model==MOTU_MODEL_828mk3 || m_motu_model==MOTU_MODEL_TRAVELERmk3 ||
1457 m_motu_model==MOTU_MODEL_896mk3) {
1458 s = clockIdToClockSource(MOTU_CLKSRC_OPTICAL_A);
1459 r.push_back(s);
1460 s = clockIdToClockSource(MOTU_CLKSRC_OPTICAL_B);
1461 r.push_back(s);
1464 return r;
1467 bool
1468 MotuDevice::setActiveClockSource(ClockSource s) {
1469 debugOutput(DEBUG_LEVEL_VERBOSE, "setting clock source to id: %d\n",s.id);
1471 // FIXME: this could do with some error checking
1472 return setClockCtrlRegister(-1, s.id);
1475 FFADODevice::ClockSource
1476 MotuDevice::getActiveClockSource() {
1477 ClockSource s;
1478 quadlet_t clock_id = getHwClockSource();
1479 s = clockIdToClockSource(clock_id);
1480 s.active = true;
1481 return s;
1484 bool
1485 MotuDevice::lock() {
1487 return true;
1491 bool
1492 MotuDevice::unlock() {
1494 return true;
1497 void
1498 MotuDevice::showDevice()
1500 debugOutput(DEBUG_LEVEL_VERBOSE,
1501 "%s %s at node %d\n", m_model->vendor_name, m_model->model_name,
1502 getNodeId());
1505 bool
1506 MotuDevice::prepare() {
1508 int samp_freq = getSamplingFrequency();
1509 unsigned int optical_in_mode_a, optical_out_mode_a;
1510 unsigned int optical_in_mode_b, optical_out_mode_b;
1511 unsigned int event_size_in;
1512 unsigned int event_size_out;
1514 debugOutput(DEBUG_LEVEL_NORMAL, "Preparing MotuDevice...\n" );
1516 /* The 828mk1 powers up without the optical mode register fields set
1517 * to anything in particular. For this interface, hardcode a default
1518 * optical mode if it appears that the interface is uninitialised.
1519 * On powerup, the unknown-2 register is 0xffffffff and this is reset
1520 * by software to 0; this provides a convenient test for the status
1521 * of the interface.
1523 if (m_motu_model==MOTU_MODEL_828MkI && ReadRegister(MOTU_G1_REG_UNKNOWN_2)!=0) {
1524 optical_in_mode_a = optical_out_mode_a = MOTU_OPTICAL_MODE_OFF;
1525 optical_in_mode_b = optical_out_mode_b = MOTU_OPTICAL_MODE_NONE;
1526 } else {
1527 getOpticalMode(MOTU_DIR_IN, &optical_in_mode_a, &optical_in_mode_b);
1528 getOpticalMode(MOTU_DIR_OUT, &optical_out_mode_a, &optical_out_mode_b);
1531 // Initialise port groups and determine the event sizes based on the
1532 // current device mode and sample rate.
1533 initDirPortGroups(Streaming::Port::E_Capture, samp_freq, optical_in_mode_a, optical_in_mode_b);
1534 initDirPortGroups(Streaming::Port::E_Playback, samp_freq, optical_out_mode_a, optical_out_mode_b);
1536 event_size_in = getEventSize(MOTU_DIR_IN);
1537 event_size_out= getEventSize(MOTU_DIR_OUT);
1539 // Explicitly set the optical mode, primarily to ensure that the
1540 // MOTU_REG_OPTICAL_CTRL register is initialised. We need to do this to
1541 // because some interfaces (the Ultralite for example) appear to power
1542 // up without this set to anything sensible. In this case, writes to
1543 // MOTU_REG_ISOCTRL fail more often than not, which is bad.
1544 setOpticalMode(MOTU_DIR_IN, optical_in_mode_a, optical_in_mode_b);
1545 setOpticalMode(MOTU_DIR_OUT, optical_out_mode_a, optical_out_mode_b);
1547 // The original 828 (aka 828mk1) was seen to write to these two
1548 // registers as part of its startup routine. It's not entirely clear
1549 // what these registers control. The inclusion of the local node ID is
1550 // an educated guess on experiments with bus topology when using other
1551 // systems.
1552 if (m_motu_model == MOTU_MODEL_828MkI) {
1553 WriteRegister(MOTU_G1_REG_UNKNOWN_1,
1554 0xffc00001 | ((get1394Service().getLocalNodeId()&0x3f)<<16));
1555 WriteRegister(MOTU_G1_REG_UNKNOWN_2, 0x00000000);
1558 // Allocate bandwidth if not previously done.
1559 // FIXME: The bandwidth allocation calculation can probably be
1560 // refined somewhat since this is currently based on a rudimentary
1561 // understanding of the ieee1394 iso protocol.
1562 // Currently we assume the following.
1563 // * Ack/iso gap = 0.05 us
1564 // * DATA_PREFIX = 0.16 us
1565 // * DATA_END = 0.26 us
1566 // These numbers are the worst-case figures given in the ieee1394
1567 // standard. This gives approximately 0.5 us of overheads per packet -
1568 // around 25 bandwidth allocation units (from the ieee1394 standard 1
1569 // bandwidth allocation unit is 125/6144 us). We further assume the
1570 // MOTU is running at S400 (which it should be) so one allocation unit
1571 // is equivalent to 1 transmitted byte; thus the bandwidth allocation
1572 // required for the packets themselves is just the size of the packet.
1573 // We used to allocate based on the maximum packet size (1160 bytes at
1574 // 192 kHz for the traveler) but now do this based on the actual device
1575 // state by utilising the result from getEventSize() and remembering
1576 // that each packet has an 8 byte CIP header. Note that bandwidth is
1577 // allocated on a *per stream* basis - it must be allocated for both the
1578 // transmit and receive streams. While most MOTU modules are close to
1579 // symmetric in terms of the number of in/out channels there are
1580 // exceptions, so we deal with receive and transmit bandwidth separately.
1581 signed int n_events_per_packet = samp_freq<=48000?8:(samp_freq<=96000?16:32);
1582 m_rx_bandwidth = 25 + (n_events_per_packet*event_size_in);
1583 m_tx_bandwidth = 25 + (n_events_per_packet*event_size_out);
1585 // Assign iso channels if not already done
1586 if (m_iso_send_channel < 0)
1587 m_iso_send_channel = get1394Service().allocateIsoChannelGeneric(m_tx_bandwidth);
1589 if (m_iso_recv_channel < 0)
1590 m_iso_recv_channel = get1394Service().allocateIsoChannelGeneric(m_rx_bandwidth);
1592 debugOutput(DEBUG_LEVEL_VERBOSE, "recv channel = %d, send channel = %d\n",
1593 m_iso_recv_channel, m_iso_send_channel);
1595 if (m_iso_recv_channel<0 || m_iso_send_channel<0) {
1596 // be nice and deallocate
1597 if (m_iso_recv_channel >= 0)
1598 get1394Service().freeIsoChannel(m_iso_recv_channel);
1599 if (m_iso_send_channel >= 0)
1600 get1394Service().freeIsoChannel(m_iso_send_channel);
1602 debugFatal("Could not allocate iso channels!\n");
1603 return false;
1606 // get the device specific and/or global SP configuration
1607 Util::Configuration &config = getDeviceManager().getConfiguration();
1608 // base value is the config.h value
1609 float recv_sp_dll_bw = STREAMPROCESSOR_DLL_BW_HZ;
1610 float xmit_sp_dll_bw = STREAMPROCESSOR_DLL_BW_HZ;
1612 // we can override that globally
1613 config.getValueForSetting("streaming.spm.recv_sp_dll_bw", recv_sp_dll_bw);
1614 config.getValueForSetting("streaming.spm.xmit_sp_dll_bw", xmit_sp_dll_bw);
1616 // or override in the device section
1617 config.getValueForDeviceSetting(getConfigRom().getNodeVendorId(), getConfigRom().getModelId(), "recv_sp_dll_bw", recv_sp_dll_bw);
1618 config.getValueForDeviceSetting(getConfigRom().getNodeVendorId(), getConfigRom().getModelId(), "xmit_sp_dll_bw", xmit_sp_dll_bw);
1620 m_receiveProcessor=new Streaming::MotuReceiveStreamProcessor(*this, event_size_in);
1621 m_receiveProcessor->setVerboseLevel(getDebugLevel());
1623 // The first thing is to initialize the processor. This creates the
1624 // data structures.
1625 if(!m_receiveProcessor->init()) {
1626 debugFatal("Could not initialize receive processor!\n");
1627 return false;
1630 if(!m_receiveProcessor->setDllBandwidth(recv_sp_dll_bw)) {
1631 debugFatal("Could not set DLL bandwidth\n");
1632 delete m_receiveProcessor;
1633 m_receiveProcessor = NULL;
1634 return false;
1637 // Now we add ports to the processor
1638 debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to receive processor\n");
1640 char *buff;
1641 Streaming::Port *p=NULL;
1643 // retrieve the ID
1644 std::string id=std::string("dev?");
1645 if(!getOption("id", id)) {
1646 debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n");
1649 // Add audio capture ports
1650 #ifndef USE_PORTGROUPS
1651 if (!addDirPorts(Streaming::Port::E_Capture, samp_freq, optical_in_mode_a, optical_in_mode_b)) {
1652 return false;
1654 #else
1655 if (!addDirPortGroups(Streaming::Port::E_Capture, samp_freq, optical_in_mode_a, optical_in_mode_b)) {
1656 return false;
1658 #endif
1659 // Add MIDI port. Every MOTU interface except the original 828 has
1660 // exactly one MIDI input port, with each MIDI byte sent using a 3 byte
1661 // sequence starting at byte 4 of the event data.
1662 if (m_motu_model != MOTU_MODEL_828MkI) {
1663 asprintf(&buff,"%s_cap_MIDI0",id.c_str());
1664 p = new Streaming::MotuMidiPort(*m_receiveProcessor, buff,
1665 Streaming::Port::E_Capture, 4);
1666 if (!p) {
1667 debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n", buff);
1669 free(buff);
1672 // example of adding an control port:
1673 // asprintf(&buff,"%s_cap_%s",id.c_str(),"myportnamehere");
1674 // p=new Streaming::MotuControlPort(
1675 // buff,
1676 // Streaming::Port::E_Capture,
1677 // 0 // you can add all other port specific stuff you
1678 // // need to pass by extending MotuXXXPort and MotuPortInfo
1679 // );
1680 // free(buff);
1682 // if (!p) {
1683 // debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
1684 // } else {
1686 // if (!m_receiveProcessor->addPort(p)) {
1687 // debugWarning("Could not register port with stream processor\n");
1688 // return false;
1689 // } else {
1690 // debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
1691 // }
1692 // }
1694 // Do the same for the transmit processor
1695 m_transmitProcessor=new Streaming::MotuTransmitStreamProcessor(*this, event_size_out);
1697 m_transmitProcessor->setVerboseLevel(getDebugLevel());
1699 if(!m_transmitProcessor->init()) {
1700 debugFatal("Could not initialize transmit processor!\n");
1701 return false;
1704 if(!m_transmitProcessor->setDllBandwidth(xmit_sp_dll_bw)) {
1705 debugFatal("Could not set DLL bandwidth\n");
1706 delete m_transmitProcessor;
1707 m_transmitProcessor = NULL;
1708 return false;
1711 // Now we add ports to the processor
1712 debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to transmit processor\n");
1714 // Add audio playback ports
1715 #ifndef USE_PORTGROUPS
1716 if (!addDirPorts(Streaming::Port::E_Playback, samp_freq, optical_out_mode_a, optical_out_mode_b)) {
1717 return false;
1719 #else
1720 if (!addDirPortGroups(Streaming::Port::E_Playback, samp_freq, optical_out_mode_a, optical_out_mode_b)) {
1721 return false;
1723 #endif
1725 // Add MIDI port. Every MOTU interface except the original 828 has
1726 // exactly one MIDI input port, with each MIDI byte sent using a 3 byte
1727 // sequence starting at byte 4 of the event data.
1728 if (m_motu_model != MOTU_MODEL_828MkI) {
1729 asprintf(&buff,"%s_pbk_MIDI0",id.c_str());
1730 p = new Streaming::MotuMidiPort(*m_transmitProcessor, buff,
1731 Streaming::Port::E_Playback, 4);
1732 if (!p) {
1733 debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n", buff);
1735 free(buff);
1738 // example of adding an control port:
1739 // asprintf(&buff,"%s_pbk_%s",id.c_str(),"myportnamehere");
1741 // p=new Streaming::MotuControlPort(
1742 // buff,
1743 // Streaming::Port::E_Playback,
1744 // 0 // you can add all other port specific stuff you
1745 // // need to pass by extending MotuXXXPort and MotuPortInfo
1746 // );
1747 // free(buff);
1749 // if (!p) {
1750 // debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
1751 // } else {
1752 // if (!m_transmitProcessor->addPort(p)) {
1753 // debugWarning("Could not register port with stream processor\n");
1754 // return false;
1755 // } else {
1756 // debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
1757 // }
1758 // }
1760 return true;
1764 MotuDevice::getStreamCount() {
1765 return 2; // one receive, one transmit
1768 Streaming::StreamProcessor *
1769 MotuDevice::getStreamProcessorByIndex(int i) {
1770 switch (i) {
1771 case 0:
1772 return m_receiveProcessor;
1773 case 1:
1774 return m_transmitProcessor;
1775 default:
1776 return NULL;
1778 return 0;
1781 bool
1782 MotuDevice::startStreamByIndex(int i) {
1784 quadlet_t isoctrl = ReadRegister(MOTU_REG_ISOCTRL);
1785 quadlet_t config2_reg = ReadRegister(MOTU_G1_REG_CONFIG_2);
1787 if (m_motu_model == MOTU_MODEL_828MkI) {
1788 // The 828MkI device does this differently. In particular it does
1789 // not appear possible to enable tx and rx separately since they
1790 // share a global enable (MOTU_G1_C1_ISO_ENABLE). Therefore we
1791 // enable both when the 0th index is requested and ignore any
1792 // request for index 1. Also note that on the G1 devices,
1793 // MOTU_REG_ISOCTRL and MOTU_G1_REG_CONFIG are one and the same.
1794 if (i == 1)
1795 return true;
1796 m_receiveProcessor->setChannel(m_iso_recv_channel);
1797 m_transmitProcessor->setChannel(m_iso_send_channel);
1799 /* Start with a setting of the config2 register. The purpose of
1800 * doing this is unclear, but it's done by other drivers so we
1801 * should too, at least until we have something working.
1803 WriteRegister(MOTU_G1_REG_CONFIG_2, config2_reg);
1805 /* Send the iso details to the control register. Note that as for
1806 * other MOTU devices bit 24 enables changes to the MOTU's iso tx
1807 * settings while bit 31 enables iso rx changes.
1809 debugOutput(DEBUG_LEVEL_VERBOSE, "MOTU g1: read isoctl: %x\n", isoctrl);
1810 debugOutput(DEBUG_LEVEL_VERBOSE, "MOTU g1: read config2: %x\n", config2_reg);
1811 isoctrl &= ~MOTU_G1_C1_ISO_INFO_MASK;
1812 isoctrl |= (MOTU_G1_C1_ISO_TX_WREN | MOTU_G1_C1_ISO_RX_WREN);
1813 isoctrl |= (m_iso_recv_channel << MOTU_G1_C1_ISO_TX_CH_BIT0);
1814 isoctrl |= (m_iso_send_channel << MOTU_G1_C1_ISO_RX_CH_BIT0);
1815 isoctrl |= (MOTU_G1_C1_ISO_TX_ACTIVE | MOTU_G1_C1_ISO_RX_ACTIVE);
1816 isoctrl |= (MOTU_G1_IO_ENABLE_0);
1817 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1818 debugOutput(DEBUG_LEVEL_VERBOSE, "MOTU g1: isoctrl 1: %08x\n", isoctrl);
1820 /* Streaming should be started with the conclusion of the above
1821 * register writes. There's one final bit that's set afterwards
1822 * by other systems, so we'll do the same until its demonstrated
1823 * that this write can be merged with the previous one without ill
1824 * effects.
1826 isoctrl &= ~MOTU_G1_C1_ISO_INFO_MASK;
1827 isoctrl |= MOTU_G1_C1_ISO_ENABLE;
1828 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1830 debugOutput(DEBUG_LEVEL_VERBOSE, "MOTU g1: isoctrl 2: %08x\n", isoctrl);
1832 return true;
1835 // NOTE: this assumes that you have two streams
1836 switch (i) {
1837 case 0:
1838 // TODO: do the stuff that is nescessary to make the device
1839 // receive a stream
1841 // Set the streamprocessor channel to the one obtained by
1842 // the connection management
1843 m_receiveProcessor->setChannel(m_iso_recv_channel);
1845 // Mask out current transmit settings of the MOTU and replace with
1846 // new ones (which correspond to our receive channel). Turn bit 24
1847 // on to enable changes to the MOTU's iso transmit settings when the
1848 // iso control register is written. Bit 23 enables iso transmit
1849 // from the MOTU.
1850 isoctrl &= 0xff00ffff;
1851 isoctrl |= (m_iso_recv_channel << 16);
1852 isoctrl |= 0x00c00000;
1853 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1854 break;
1855 case 1:
1856 // TODO: do the stuff that is nescessary to make the device
1857 // transmit a stream
1859 // Set the streamprocessor channel to the one obtained by
1860 // the connection management
1861 m_transmitProcessor->setChannel(m_iso_send_channel);
1863 // Mask out current receive settings of the MOTU and replace with
1864 // new ones (which correspond to our transmit channel). Turn bit 31
1865 // on to enable changes to the MOTU's iso receive settings when the
1866 // iso control register is written. Bit 30 enables iso receive by
1867 // the MOTU.
1868 isoctrl &= 0x00ffffff;
1869 isoctrl |= (m_iso_send_channel << 24);
1870 isoctrl |= 0xc0000000;
1871 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1872 break;
1874 default: // Invalid stream index
1875 return false;
1878 return true;
1881 bool
1882 MotuDevice::stopStreamByIndex(int i) {
1884 quadlet_t isoctrl = ReadRegister(MOTU_REG_ISOCTRL);
1886 // Shut down streaming. Essentially the opposite of the start function.
1888 if (m_motu_model == MOTU_MODEL_828MkI) {
1889 quadlet_t reg = isoctrl;
1890 // The 828MkI device does this differently. In particular it does
1891 // not appear possible to disable tx and rx separately since they
1892 // share a global enable (MOTU_G1_C1_ISO_ENABLE). Therefore we
1893 // disable both when the 0th index is requested and ignore any
1894 // request for index 1.
1895 if (i == 1)
1896 return true;
1898 /* First disable the streaming */
1899 reg &= ~MOTU_G1_C1_ISO_INFO_MASK;
1900 reg &= ~MOTU_G1_C1_ISO_ENABLE;
1901 WriteRegister(MOTU_REG_ISOCTRL, reg);
1903 /* Next, turn off individual stream enable flags. As for the stream
1904 * start case, this is separated from the first write because that's
1905 * what other systems do.
1907 reg |= (isoctrl & MOTU_G1_C1_ISO_INFO_MASK);
1908 reg &= ~(MOTU_G1_C1_ISO_TX_ACTIVE | MOTU_G1_C1_ISO_RX_ACTIVE);
1909 WriteRegister(MOTU_REG_ISOCTRL, reg);
1911 return true;
1914 // NOTE: this assumes that you have two streams
1915 switch (i) {
1916 case 0:
1917 // Turn bit 22 off to disable iso send by the MOTU. Turn
1918 // bit 23 on to enable changes to the MOTU's iso transmit
1919 // settings when the iso control register is written.
1920 isoctrl &= 0xffbfffff;
1921 isoctrl |= 0x00800000;
1922 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1923 break;
1924 case 1:
1925 // Turn bit 30 off to disable iso receive by the MOTU. Turn
1926 // bit 31 on to enable changes to the MOTU's iso receive
1927 // settings when the iso control register is written.
1928 isoctrl &= 0xbfffffff;
1929 isoctrl |= 0x80000000;
1930 WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1931 break;
1933 default: // Invalid stream index
1934 return false;
1937 return true;
1940 signed int MotuDevice::getIsoRecvChannel(void) {
1941 return m_iso_recv_channel;
1944 signed int MotuDevice::getIsoSendChannel(void) {
1945 return m_iso_send_channel;
1948 signed int MotuDevice::getDeviceGeneration(void) {
1949 if (m_motu_model == MOTU_MODEL_828MkI)
1950 return MOTU_DEVICE_G1;
1951 if (m_motu_model==MOTU_MODEL_828mk3 ||
1952 m_motu_model==MOTU_MODEL_ULTRALITEmk3 ||
1953 m_motu_model==MOTU_MODEL_ULTRALITEmk3_HYB ||
1954 m_motu_model==MOTU_MODEL_TRAVELERmk3 ||
1955 m_motu_model==MOTU_MODEL_896mk3)
1956 return MOTU_DEVICE_G3;
1957 return MOTU_DEVICE_G2;
1960 unsigned int MotuDevice::getOpticalMode(unsigned int dir,
1961 unsigned int *port_a_mode, unsigned int *port_b_mode) {
1962 // Only the "Mark 3" (aka G3) MOTU devices had more than one optical
1963 // port. Therefore the "port_b_mode" parameter is unused by all
1964 // devices other than the Mark 3 devices.
1966 // If a mode parameter pointer is NULL it will not be returned.
1967 unsigned int reg, reg2;
1968 unsigned int mask, shift;
1970 if (port_b_mode != NULL)
1971 *port_b_mode = MOTU_OPTICAL_MODE_NONE;
1972 if (getDeviceGeneration()!=MOTU_DEVICE_G3 && port_a_mode==NULL)
1973 return 0;
1975 if (m_motu_model == MOTU_MODEL_828MkI) {
1976 // The early devices used a different register layout.
1977 unsigned int mask2;
1978 reg = ReadRegister(MOTU_G1_REG_CONFIG);
1979 reg2 = ReadRegister(MOTU_G1_REG_CONFIG_2);
1981 mask = (dir==MOTU_DIR_IN)?MOTU_G1_C1_OPT_TOSLINK_IN:MOTU_G1_C1_OPT_TOSLINK_OUT;
1982 mask2 = (dir==MOTU_DIR_IN)?MOTU_G1_C2_OPT_nADAT_IN:MOTU_G1_C2_OPT_nADAT_OUT;
1984 if ((reg & mask) && (reg2 & mask2)) {
1985 /* Toslink bit set, nADAT bit set -> Toslink mode */
1986 *port_a_mode = MOTU_OPTICAL_MODE_TOSLINK;
1987 } else
1988 if ((reg & mask)==0 && (reg2 & mask2)==0) {
1989 /* Toslink bit clear, nADAT bit clear -> ADAT mode */
1990 *port_a_mode = MOTU_OPTICAL_MODE_ADAT;
1991 } else {
1992 /* All other combinations are unexpected except toslink clear/
1993 * nADAT set, so just assume the optical port is off if we get
1994 * here.
1996 *port_a_mode = MOTU_OPTICAL_MODE_OFF;
1998 return 0;
2001 if (getDeviceGeneration() == MOTU_DEVICE_G3) {
2002 unsigned int enable, toslink;
2003 /* The Ultralite Mk3s don't have any optical ports. All others have 2. */
2004 if (m_motu_model==MOTU_MODEL_ULTRALITEmk3 || m_motu_model==MOTU_MODEL_ULTRALITEmk3_HYB) {
2005 if (port_a_mode != NULL)
2006 *port_a_mode = MOTU_OPTICAL_MODE_NONE;
2007 if (port_b_mode != NULL)
2008 *port_b_mode = MOTU_OPTICAL_MODE_NONE;
2009 return 0;
2011 reg = ReadRegister(MOTU_G3_REG_OPTICAL_CTRL);
2012 debugOutput(DEBUG_LEVEL_VERBOSE, "mark3 optical control register = 0x%08x\n", reg);
2013 if (port_a_mode != NULL) {
2014 enable = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_A_IN_ENABLE:MOTU_G3_OPT_A_OUT_ENABLE;
2015 toslink = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_A_IN_TOSLINK:MOTU_G3_OPT_A_OUT_TOSLINK;
2016 if ((reg & enable) == 0)
2017 *port_a_mode = MOTU_OPTICAL_MODE_OFF;
2018 else
2019 if ((reg & toslink) != 0)
2020 *port_a_mode = MOTU_OPTICAL_MODE_TOSLINK;
2021 else
2022 *port_a_mode = MOTU_OPTICAL_MODE_ADAT;
2024 if (port_b_mode != NULL) {
2025 enable = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_B_IN_ENABLE:MOTU_G3_OPT_B_OUT_ENABLE;
2026 toslink = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_B_IN_TOSLINK:MOTU_G3_OPT_B_OUT_TOSLINK;
2027 if ((reg & enable) == 0)
2028 *port_b_mode = MOTU_OPTICAL_MODE_OFF;
2029 else
2030 if ((reg & toslink) != 0)
2031 *port_b_mode = MOTU_OPTICAL_MODE_TOSLINK;
2032 else
2033 *port_b_mode = MOTU_OPTICAL_MODE_ADAT;
2035 return 0;
2038 reg = ReadRegister(MOTU_REG_ROUTE_PORT_CONF);
2039 mask = (dir==MOTU_DIR_IN)?MOTU_G2_OPTICAL_IN_MODE_MASK:MOTU_G2_OPTICAL_OUT_MODE_MASK;
2040 shift = (dir==MOTU_DIR_IN)?MOTU_G2_OPTICAL_IN_MODE_BIT0:MOTU_G2_OPTICAL_OUT_MODE_BIT0;
2041 switch ((reg & mask) >> shift) {
2042 case MOTU_G2_OPTICAL_MODE_OFF: *port_a_mode = MOTU_OPTICAL_MODE_OFF; break;
2043 case MOTU_G2_OPTICAL_MODE_ADAT: *port_a_mode = MOTU_OPTICAL_MODE_ADAT; break;
2044 case MOTU_G2_OPTICAL_MODE_TOSLINK: *port_a_mode = MOTU_OPTICAL_MODE_TOSLINK; break;
2046 return 0;
2049 signed int MotuDevice::setOpticalMode(unsigned int dir,
2050 unsigned int port_a_mode, unsigned int port_b_mode) {
2051 // Only the "Mark 3" (aka G3) MOTU devices had more than one optical port.
2052 // Therefore the "port B" mode is ignored for all devices other than
2053 // the Mark 3 devices.
2054 unsigned int reg, g2mode;
2055 unsigned int opt_ctrl = 0x0000002;
2057 /* THe 896HD doesn't have an SPDIF/TOSLINK optical mode, so don't try to
2058 * set it
2060 if (m_motu_model==MOTU_MODEL_896HD && port_a_mode==MOTU_OPTICAL_MODE_TOSLINK)
2061 return -1;
2063 if (getDeviceGeneration()!=MOTU_DEVICE_G3 && port_a_mode==MOTU_OPTICAL_MODE_KEEP)
2064 return 0;
2066 if (m_motu_model == MOTU_MODEL_828MkI) {
2067 // The earlier MOTUs handle this differently.
2068 unsigned int g1_conf1_ref, g1_conf2_ref;
2069 unsigned int g1_conf1, g1_conf2;
2070 unsigned int toslink, n_adat;
2071 signed int err = 0;
2072 g1_conf1 = ReadRegister(MOTU_G1_REG_CONFIG);
2073 g1_conf2 = ReadRegister(MOTU_G1_REG_CONFIG_2);
2074 toslink = (dir==MOTU_DIR_IN)?MOTU_G1_C1_OPT_TOSLINK_IN:MOTU_G1_C1_OPT_TOSLINK_OUT;
2075 n_adat = (dir==MOTU_DIR_IN)?MOTU_G1_C2_OPT_nADAT_IN:MOTU_G1_C2_OPT_nADAT_OUT;
2077 // Don't send ISO information
2078 g1_conf1 &= ~MOTU_G1_C1_ISO_INFO_MASK;
2080 // This bit seems to always be set
2081 g1_conf1 |= (MOTU_G1_IO_ENABLE_0);
2083 /* This bit seems to always be set when this register is set.
2084 * It may be a write enable bit.
2086 g1_conf2 |= MOTU_G1_C2_OPT_nADAT_WREN;
2088 g1_conf1_ref = g1_conf1;
2089 g1_conf2_ref = g1_conf2;
2091 /* Set registers as needed by the requested mode */
2093 if (port_a_mode == MOTU_OPTICAL_MODE_TOSLINK) {
2094 g1_conf1 |= toslink;
2095 } else {
2096 g1_conf1 &= ~toslink;
2098 if (port_a_mode == MOTU_OPTICAL_MODE_ADAT) {
2099 g1_conf2 &= ~n_adat;
2100 } else {
2101 g1_conf2 |= n_adat;
2104 // Under other systems, MOTU_G1_REG_CONFIG is always written
2105 // first, but only if its value has been changed. Similarly,
2106 // MOTU_G1_REG_CONFIG_2 is only written if its value has been
2107 // altered.
2108 if (!err && g1_conf1!=g1_conf1_ref)
2109 err = WriteRegister(MOTU_G1_REG_CONFIG, g1_conf1) != 0;
2110 if (!err && g1_conf2!=g1_conf2_ref)
2111 err = WriteRegister(MOTU_G1_REG_CONFIG_2, g1_conf2) != 0;
2112 if (err)
2113 return -1;
2114 return 0;
2117 /* The G3 devices are also quite a bit different to the G2 units */
2118 if (getDeviceGeneration() == MOTU_DEVICE_G3) {
2119 unsigned int mask, enable, toslink;
2120 reg = ReadRegister(MOTU_G3_REG_OPTICAL_CTRL);
2121 if (port_a_mode != MOTU_OPTICAL_MODE_KEEP) {
2122 mask = enable = toslink = 0;
2123 if (dir & MOTU_DIR_IN) {
2124 mask |= MOTU_G3_OPT_A_IN_MASK;
2125 enable |= MOTU_G3_OPT_A_IN_ENABLE;
2126 toslink |= MOTU_G3_OPT_A_IN_TOSLINK;
2128 if (dir & MOTU_DIR_OUT) {
2129 mask |= MOTU_G3_OPT_A_OUT_MASK;
2130 enable |= MOTU_G3_OPT_A_OUT_ENABLE;
2131 toslink |= MOTU_G3_OPT_A_OUT_TOSLINK;
2133 reg = (reg & ~mask) | enable;
2134 switch (port_a_mode) {
2135 case MOTU_OPTICAL_MODE_OFF: reg &= ~enable; break;
2136 case MOTU_OPTICAL_MODE_TOSLINK: reg |= toslink; break;
2139 if (port_b_mode != MOTU_OPTICAL_MODE_KEEP) {
2140 mask = enable = toslink = 0;
2141 if (dir & MOTU_DIR_IN) {
2142 mask |= MOTU_G3_OPT_B_IN_MASK;
2143 enable |= MOTU_G3_OPT_B_IN_ENABLE;
2144 toslink |= MOTU_G3_OPT_B_IN_TOSLINK;
2146 if (dir & MOTU_DIR_OUT) {
2147 mask |= MOTU_G3_OPT_B_OUT_MASK;
2148 enable |= MOTU_G3_OPT_B_OUT_ENABLE;
2149 toslink |= MOTU_G3_OPT_B_OUT_TOSLINK;
2151 reg = (reg & ~mask) | enable;
2152 switch (port_a_mode) {
2153 case MOTU_OPTICAL_MODE_OFF: reg &= ~enable; break;
2154 case MOTU_OPTICAL_MODE_TOSLINK: reg |= toslink; break;
2156 reg = (reg & ~mask) | enable;
2157 switch (port_b_mode) {
2158 case MOTU_OPTICAL_MODE_OFF: reg &= ~enable; break;
2159 case MOTU_OPTICAL_MODE_TOSLINK: reg |= toslink; break;
2162 return WriteRegister(MOTU_G3_REG_OPTICAL_CTRL, reg);
2165 reg = ReadRegister(MOTU_REG_ROUTE_PORT_CONF);
2167 // Map from user mode to values sent to the device registers.
2168 g2mode = 0;
2169 switch (port_a_mode) {
2170 case MOTU_OPTICAL_MODE_OFF: g2mode = MOTU_G2_OPTICAL_MODE_OFF; break;
2171 case MOTU_OPTICAL_MODE_ADAT: g2mode = MOTU_G2_OPTICAL_MODE_ADAT; break;
2172 case MOTU_OPTICAL_MODE_TOSLINK: g2mode = MOTU_G2_OPTICAL_MODE_TOSLINK; break;
2175 // Set up the optical control register value according to the current
2176 // optical port modes. At this stage it's not completely understood
2177 // what the "Optical control" register does, so the values it's set to
2178 // are more or less "magic" numbers.
2179 if ((reg & MOTU_G2_OPTICAL_IN_MODE_MASK) != (MOTU_G2_OPTICAL_MODE_ADAT<<MOTU_G2_OPTICAL_IN_MODE_BIT0))
2180 opt_ctrl |= 0x00000080;
2181 if ((reg & MOTU_G2_OPTICAL_OUT_MODE_MASK) != (MOTU_G2_OPTICAL_MODE_ADAT<<MOTU_G2_OPTICAL_OUT_MODE_BIT0))
2182 opt_ctrl |= 0x00000040;
2184 if (dir & MOTU_DIR_IN) {
2185 reg &= ~MOTU_G2_OPTICAL_IN_MODE_MASK;
2186 reg |= (g2mode << MOTU_G2_OPTICAL_IN_MODE_BIT0) & MOTU_G2_OPTICAL_IN_MODE_MASK;
2187 if (g2mode != MOTU_G2_OPTICAL_MODE_ADAT)
2188 opt_ctrl |= 0x00000080;
2189 else
2190 opt_ctrl &= ~0x00000080;
2192 if (dir & MOTU_DIR_OUT) {
2193 reg &= ~MOTU_G2_OPTICAL_OUT_MODE_MASK;
2194 reg |= (g2mode << MOTU_G2_OPTICAL_OUT_MODE_BIT0) & MOTU_G2_OPTICAL_OUT_MODE_MASK;
2195 if (g2mode != MOTU_G2_OPTICAL_MODE_ADAT)
2196 opt_ctrl |= 0x00000040;
2197 else
2198 opt_ctrl &= ~0x00000040;
2201 /* Setting bit 25 in the route/port configuration register enables the
2202 * setting of the optical mode. Bit 24 allows the phones assign to be
2203 * set using the lower 8 bits of the register. This function has no
2204 * business setting that, so make sure bit 24 is masked off.
2206 reg |= 0x02000000;
2207 reg &= ~0x01000000;
2209 // FIXME: there seems to be more to it than this, but for
2210 // the moment at least this seems to work.
2211 WriteRegister(MOTU_REG_ROUTE_PORT_CONF, reg);
2212 return WriteRegister(MOTU_REG_OPTICAL_CTRL, opt_ctrl);
2215 signed int MotuDevice::getEventSize(unsigned int direction) {
2217 // Return the size in bytes of a single event sent to (dir==MOTU_OUT) or
2218 // from (dir==MOTU_IN) the MOTU as part of an iso data packet.
2220 // FIXME: for performance it may turn out best to calculate the event
2221 // size in setOpticalMode and cache the result in a data field. However,
2222 // as it stands this will not adapt to dynamic changes in sample rate - we'd
2223 // need a setFrameRate() for that.
2225 // Note that all audio channels are sent using 3 bytes.
2226 signed int size = 0;
2228 #ifndef USE_PORTGROUPS
2229 const DevicePropertyEntry *devprop = &DevicesProperty[m_motu_model-1];
2230 signed int sample_rate = getSamplingFrequency();
2231 unsigned int optical_mode_a, optical_mode_b;
2233 unsigned int i;
2234 unsigned int dir = direction==MOTU_DIR_IN?MOTU_PA_IN:MOTU_PA_OUT;
2235 unsigned int flags = 0;
2236 unsigned int port_flags;
2238 // At the very least an event consists of the SPH (4 bytes). On all
2239 // interfaces except the 828Mk1 there are also 6 bytes of control/MIDI
2240 // data at the start.
2241 size = 4;
2242 if (m_motu_model != MOTU_MODEL_828MkI)
2243 size += 6;
2244 getOpticalMode(direction, &optical_mode_a, &optical_mode_b);
2246 if ( sample_rate > 96000 )
2247 flags |= MOTU_PA_RATE_4x;
2248 else if ( sample_rate > 48000 )
2249 flags |= MOTU_PA_RATE_2x;
2250 else
2251 flags |= MOTU_PA_RATE_1x;
2253 switch (optical_mode_a) {
2254 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_OPTICAL_ANY; break;
2255 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_OPTICAL_OFF; break;
2256 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_OPTICAL_ADAT; break;
2257 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_OPTICAL_TOSLINK; break;
2259 switch (optical_mode_b) {
2260 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_MK3_OPT_B_ANY; break;
2261 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_MK3_OPT_B_OFF; break;
2262 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_MK3_OPT_B_ADAT; break;
2263 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_MK3_OPT_B_TOSLINK; break;
2266 // Don't test for padding port flag here since we need to include such
2267 // pseudo-ports when calculating the event size.
2268 for (i=0; i < devprop->n_port_entries; i++) {
2269 port_flags = devprop->port_entry[i].port_flags;
2270 /* Make sure the optical port tests return true for devices without
2271 * one or both optical ports.
2273 if (optical_mode_a == MOTU_OPTICAL_MODE_NONE) {
2274 port_flags |= MOTU_PA_OPTICAL_ANY;
2276 if (optical_mode_b == MOTU_OPTICAL_MODE_NONE) {
2277 port_flags |= MOTU_PA_MK3_OPT_B_ANY;
2279 if (( port_flags & dir ) &&
2280 ( port_flags & MOTU_PA_RATE_MASK & flags ) &&
2281 ( port_flags & MOTU_PA_MK3_OPT_B_MASK & flags ) &&
2282 ( port_flags & MOTU_PA_OPTICAL_MASK & flags )) {
2283 size += 3;
2287 // The 828Mk1 includes an additional 6 bytes at the end of the packet.
2288 // The purpose of these is unknown at this stage, but we need to allow
2289 // for them in the event size calculation.
2290 if (m_motu_model == MOTU_MODEL_828MkI)
2291 size += 6;
2293 #else
2294 if (direction==MOTU_DIR_IN)
2295 size = m_rx_event_size;
2296 else
2297 size = m_tx_event_size;
2298 #endif
2300 // Finally round size up to the next quadlet boundary
2301 return ((size+3)/4)*4;
2303 /* ======================================================================= */
2305 bool MotuDevice::addPort(Streaming::StreamProcessor *s_processor,
2306 char *name, enum Streaming::Port::E_Direction direction,
2307 int position, int size) {
2309 * Internal helper function to add a MOTU port to a given stream processor.
2310 * This just saves the unnecessary replication of what is essentially
2311 * boilerplate code. Note that the port name is freed by this function
2312 * prior to exit.
2314 Streaming::Port *p=NULL;
2316 p = new Streaming::MotuAudioPort(*s_processor, name, direction, position, size);
2318 if (!p) {
2319 debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",name);
2321 free(name);
2322 return true;
2324 /* ======================================================================= */
2326 bool MotuDevice::addDirPorts(
2327 enum Streaming::Port::E_Direction direction, unsigned int sample_rate,
2328 unsigned int optical_a_mode, unsigned int optical_b_mode) {
2330 * Internal helper method: adds all required ports for the given direction
2331 * based on the indicated sample rate and optical mode.
2333 * Notes: currently ports are not created if they are disabled due to sample
2334 * rate or optical mode. However, it might be better to unconditionally
2335 * create all ports and just disable those which are not active.
2337 const char *mode_str = direction==Streaming::Port::E_Capture?"cap":"pbk";
2338 Streaming::StreamProcessor *s_processor;
2339 unsigned int i;
2340 char *buff;
2341 unsigned int dir = direction==Streaming::Port::E_Capture?MOTU_PA_IN:MOTU_PA_OUT;
2342 unsigned int flags = 0;
2343 unsigned int port_flags;
2346 if ( sample_rate > 96000 )
2347 flags |= MOTU_PA_RATE_4x;
2348 else if ( sample_rate > 48000 )
2349 flags |= MOTU_PA_RATE_2x;
2350 else
2351 flags |= MOTU_PA_RATE_1x;
2353 switch (optical_a_mode) {
2354 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_OPTICAL_ANY; break;
2355 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_OPTICAL_OFF; break;
2356 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_OPTICAL_ADAT; break;
2357 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_OPTICAL_TOSLINK; break;
2359 switch (optical_b_mode) {
2360 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_MK3_OPT_B_ANY; break;
2361 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_MK3_OPT_B_OFF; break;
2362 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_MK3_OPT_B_ADAT; break;
2363 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_MK3_OPT_B_TOSLINK; break;
2366 // retrieve the ID
2367 std::string id=std::string("dev?");
2368 if(!getOption("id", id)) {
2369 debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n");
2372 if (direction == Streaming::Port::E_Capture) {
2373 s_processor = m_receiveProcessor;
2374 } else {
2375 s_processor = m_transmitProcessor;
2378 for (i=0; i < DevicesProperty[m_motu_model-1].n_port_entries; i++) {
2379 port_flags = DevicesProperty[m_motu_model-1].port_entry[i].port_flags;
2380 /* For devices without one or more optical ports, ensure the tests
2381 * on the optical ports always returns "true".
2383 if (optical_a_mode == MOTU_OPTICAL_MODE_NONE)
2384 port_flags |= MOTU_PA_OPTICAL_ANY;
2385 if (optical_b_mode == MOTU_OPTICAL_MODE_NONE)
2386 port_flags |= MOTU_PA_MK3_OPT_B_ANY;
2388 if (( port_flags & dir ) &&
2389 ( port_flags & MOTU_PA_RATE_MASK & flags ) &&
2390 ( port_flags & MOTU_PA_OPTICAL_MASK & flags ) &&
2391 ( port_flags & MOTU_PA_MK3_OPT_B_MASK & flags ) &&
2392 !( port_flags & MOTU_PA_PADDING )) {
2393 asprintf(&buff,"%s_%s_%s" , id.c_str(), mode_str,
2394 DevicesProperty[m_motu_model-1].port_entry[i].port_name);
2395 if (!addPort(s_processor, buff, direction, DevicesProperty[m_motu_model-1].port_entry[i].port_offset, 0))
2396 return false;
2400 return true;
2402 /* ======================================================================= */
2404 bool MotuDevice::initDirPortGroups(
2405 enum Streaming::Port::E_Direction direction, unsigned int sample_rate,
2406 unsigned int optical_a_mode, unsigned int optical_b_mode) {
2408 * Internal helper method. Using a PortGroupEntry array the locations of
2409 * channels within a packet is deduced based on the given sample rate and
2410 * optical port modes, and stored back into the PortGroupEntry. Locations
2411 * within the packet start at 10 and are incremented by 3 for each
2412 * subsequent channel. Channels are assumed to be ordered in the packet as
2413 * they are in the port group array. Port groups which are not to be
2414 * created have their packet offset set to -1.
2416 * Notes:
2417 * - When the ports are created by addDirPortGroups() the port_order field
2418 * is used to order the additions. This way the first ports created do
2419 * not necessarily have to be those which appear in the packets first.
2421 * - Currently ports are not flagged for creation if they are disabled due
2422 * to sample rate or optical mode. However, it might be better to
2423 * unconditionally create all ports and just disable those which are not
2424 * active.
2426 signed int i;
2427 unsigned int dir = direction==Streaming::Port::E_Capture?MOTU_PA_IN:MOTU_PA_OUT;
2428 const signed int mode_idx = direction==Streaming::Port::E_Capture?1:0;
2429 unsigned int flags = 0;
2430 unsigned int portgroup_flags;
2431 signed int pkt_ofs;
2432 const DevicePropertyEntry *devprop = &DevicesProperty[m_motu_model-1];
2433 signed int n_groups = devprop->n_portgroup_entries;
2435 if (n_groups <= 0)
2436 return true;
2438 /* Port data starts at offset 10 on most models, and 4 on the 828mk1 */
2439 if (m_motu_model == MOTU_MODEL_828MkI)
2440 pkt_ofs = 4;
2441 else
2442 pkt_ofs = 10;
2444 if ( sample_rate > 96000 )
2445 flags |= MOTU_PA_RATE_4x;
2446 else if ( sample_rate > 48000 )
2447 flags |= MOTU_PA_RATE_2x;
2448 else
2449 flags |= MOTU_PA_RATE_1x;
2451 switch (optical_a_mode) {
2452 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_OPTICAL_ANY; break;
2453 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_OPTICAL_OFF; break;
2454 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_OPTICAL_ADAT; break;
2455 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_OPTICAL_TOSLINK; break;
2457 switch (optical_b_mode) {
2458 case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_MK3_OPT_B_ANY; break;
2459 case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_MK3_OPT_B_OFF; break;
2460 case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_MK3_OPT_B_ADAT; break;
2461 case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_MK3_OPT_B_TOSLINK; break;
2464 fprintf(stderr, "initDirPortGroups(): flags=0x%08x, opta=0x%x, optb=0x%x\n",
2465 flags, optical_a_mode, optical_b_mode);
2467 /* Scan through the port groups, allocating packet offsets for all
2468 * port groups which are found to be active in the device's current state.
2470 for (i=0; i<n_groups; i++) {
2471 portgroup_flags = devprop->portgroup_entry[i].flags;
2472 /* For devices without one or more optical ports, ensure the tests
2473 * on the optical ports always returns "true".
2475 if (optical_a_mode == MOTU_OPTICAL_MODE_NONE)
2476 portgroup_flags |= MOTU_PA_OPTICAL_ANY;
2477 if (optical_b_mode == MOTU_OPTICAL_MODE_NONE)
2478 portgroup_flags |= MOTU_PA_MK3_OPT_B_ANY;
2480 devprop->portgroup_entry[i].group_pkt_offset[mode_idx] = -1;
2481 if (( portgroup_flags & dir ) &&
2482 ( portgroup_flags & MOTU_PA_RATE_MASK & flags ) &&
2483 ( portgroup_flags & MOTU_PA_OPTICAL_MASK & flags ) &&
2484 ( portgroup_flags & MOTU_PA_MK3_OPT_B_MASK & flags )) {
2485 if ((portgroup_flags & MOTU_PA_PADDING) == 0) {
2486 devprop->portgroup_entry[i].group_pkt_offset[mode_idx] = pkt_ofs;
2488 pkt_ofs += 3*devprop->portgroup_entry[i].n_channels;
2492 /* The 828mk1 has an additional 6 bytes tacked onto the end of the
2493 * packet sent by it, which we must account for when using pkt_ofs as a
2494 * proxy for size.
2496 if (direction==Streaming::Port::E_Capture && m_motu_model==MOTU_MODEL_828MkI)
2497 pkt_ofs += 6;
2499 if (direction == Streaming::Port::E_Capture)
2500 m_rx_event_size = pkt_ofs;
2501 else
2502 m_tx_event_size = pkt_ofs;
2504 fprintf(stderr, "initDirPortGroups(): rxsize=%d, txsize=%d\n",
2505 m_rx_event_size, m_tx_event_size);
2507 return true;
2509 /* ======================================================================= */
2511 bool MotuDevice::addDirPortGroups(
2512 enum Streaming::Port::E_Direction direction, unsigned int sample_rate,
2513 unsigned int optical_a_mode, unsigned int optical_b_mode) {
2515 * Internal helper method. Using a PortGroupEntry array previously
2516 * initialised with a call to initPortGroups(), ports are created for each
2517 * active channel of the interface. The locations of channels within a
2518 * packet are obtained from the group_pkt_offset field which was set by
2519 * initPortGroups() and the order they should be created in is specifed by
2520 * the port_order field of a port group.
2522 * The port_order functionality is helpful if it's more convenient to have a
2523 * particular port show up first in jackd even through it's located in the
2524 * middle of the packet. If the port_order field of the first port group is
2525 * -1 it is assumed that the port creation is to happen in the order
2526 * specified in the port group list.
2528 * A port group is taken to be inactive if its group_pkt_offset is set to -1.
2530 const char *mode_str = direction==Streaming::Port::E_Capture?"cap":"pbk";
2531 const signed int mode_idx = direction==Streaming::Port::E_Capture?1:0;
2532 Streaming::StreamProcessor *s_processor;
2533 signed int i;
2534 char *buff;
2535 const DevicePropertyEntry *devprop = &DevicesProperty[m_motu_model-1];
2536 signed int n_groups = devprop->n_portgroup_entries;
2537 signed int creation_indices[n_groups];
2538 signed int create_in_order;
2540 if (n_groups <= 0)
2541 return true;
2543 // retrieve the ID
2544 std::string id=std::string("dev?");
2545 if(!getOption("id", id)) {
2546 debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n");
2549 if (direction == Streaming::Port::E_Capture) {
2550 s_processor = m_receiveProcessor;
2551 } else {
2552 s_processor = m_transmitProcessor;
2555 for (i=0; i<n_groups; i++) {
2556 creation_indices[i] = -1;
2558 create_in_order = devprop->portgroup_entry[0].port_order<0;
2560 /* First scan through the port groups to determine the creation order */
2561 for (i=0; i<n_groups; i++) {
2562 if (devprop->portgroup_entry[i].group_pkt_offset[mode_idx] >= 0) {
2563 if (create_in_order)
2564 creation_indices[i] = i;
2565 else
2566 creation_indices[devprop->portgroup_entry[i].port_order] = i;
2570 /* Now run through the portgroup list again, this time in creation order,
2571 * to make the ports.
2573 for (i=0; i<n_groups; i++) {
2574 char namestr[64];
2575 signed int ch;
2576 signed int entry;
2577 if (creation_indices[i] < 0)
2578 continue;
2579 entry = creation_indices[i];
2580 for (ch=0; ch<devprop->portgroup_entry[entry].n_channels; ch++) {
2581 /* Deduce the full channel name */
2582 if (strstr(devprop->portgroup_entry[entry].group_name_format, "%d") != NULL)
2583 snprintf(namestr, sizeof(namestr), devprop->portgroup_entry[entry].group_name_format,
2584 ch+1+devprop->portgroup_entry[entry].port_num_offset);
2585 else
2586 if (strstr(devprop->portgroup_entry[entry].group_name_format, "%s") != NULL)
2587 snprintf(namestr, sizeof(namestr), devprop->portgroup_entry[entry].group_name_format,
2588 (ch & 0x1)?"R":"L");
2589 else
2590 snprintf(namestr, sizeof(namestr), "%s", devprop->portgroup_entry[entry].group_name_format);
2591 asprintf(&buff,"%s_%s_%s" , id.c_str(), mode_str, namestr);
2592 if (!addPort(s_processor, buff, direction,
2593 devprop->portgroup_entry[entry].group_pkt_offset[mode_idx]+3*ch, 0))
2594 return false;
2598 return true;
2600 /* ======================================================================== */
2602 unsigned int MotuDevice::ReadRegister(fb_nodeaddr_t reg) {
2604 * Attempts to read the requested register from the MOTU.
2607 quadlet_t quadlet = 0;
2609 /* If the supplied register has no upper bits set assume it's a G1/G2
2610 * register which is assumed to be relative to MOTU_REG_BASE_ADDR.
2612 if ((reg & MOTU_REG_BASE_ADDR) == 0)
2613 reg |= MOTU_REG_BASE_ADDR;
2615 // Note: 1394Service::read() expects a physical ID, not the node id
2616 if (get1394Service().read(0xffc0 | getNodeId(), reg, 1, &quadlet) <= 0) {
2617 debugError("Error doing motu read from register 0x%012llx\n",reg);
2620 return CondSwapFromBus32(quadlet);
2623 signed int
2624 MotuDevice::readBlock(fb_nodeaddr_t reg, quadlet_t *buf, signed int n_quads) {
2626 // Read "n_quads" quadlets from the device starting at register "reg" into
2627 // the buffer pointed to by "buf". "buf" is assumed to have been
2628 // preallocated and be large enough for the requested data.
2630 signed int i;
2632 if (get1394Service().read(0xffc0 | getNodeId(), reg, n_quads, buf) <= 0) {
2633 debugError("Error doing motu block read of %d quadlets from register 0x%llx\n", n_quads, reg);
2634 return -1;
2636 for (i=0; i<n_quads; i++) {
2637 buf[i] = CondSwapFromBus32(buf[i]);
2639 return 0;
2642 signed int MotuDevice::WriteRegister(fb_nodeaddr_t reg, quadlet_t data) {
2644 * Attempts to write the given data to the requested MOTU register.
2647 unsigned int err = 0;
2648 data = CondSwapToBus32(data);
2650 /* If the supplied register has no upper bits set assume it's a G1/G2
2651 * register which is assumed to be relative to MOTU_REG_BASE_ADDR.
2653 if ((reg & MOTU_REG_BASE_ADDR) == 0)
2654 reg |= MOTU_REG_BASE_ADDR;
2656 // Note: 1394Service::write() expects a physical ID, not the node id
2657 if (get1394Service().write(0xffc0 | getNodeId(), reg, 1, &data) <= 0) {
2658 err = 1;
2659 debugError("Error doing motu write to register 0x%012llx\n",reg);
2662 SleepRelativeUsec(100);
2663 return (err==0)?0:-1;
2666 signed int
2667 MotuDevice::writeBlock(fb_nodeaddr_t reg, quadlet_t *data, signed int n_quads) {
2669 // Write n_quads quadlets from "data" to the device register "reg". Note that
2670 // any necessary byte swapping is done in place, so the contents of "data"
2671 // may be altered by this function.
2673 signed int ret = 0;
2674 signed int i;
2675 for (i=0; i<n_quads; i++) {
2676 data[i] = CondSwapToBus32(data[i]);
2678 if (get1394Service().write(0xffc0 | getNodeId(), reg, n_quads, data) <= 0) {
2679 ret = -1;
2680 debugError("Error doing motu block write of %d quadlets to register 0x%llx\n", n_quads, reg);
2682 return ret;