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

Revision 1902, 104.3 kB (checked in by jwoithe, 14 years ago)

MOTU: Create a define (USE_PORTGROUPS) which if defined will switch to the new PortGroups? methods of identifying audio streams in data packets. This is currently not defined, meaning the old PortEntry? method continues to be used by default.
MOTU: Make MotuDevice::getEventSize aware of the PortGroups? mechanism when necessary.

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  * Copyright (C) 2005-2009 by Jonathan Woithe
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB.
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 2 of the License, or
13  * (at your option) version 3 of the License.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include "config.h"
26
27 #include "motu/motu_avdevice.h"
28 #include "motu/motu_mixerdefs.h"
29 #include "motu/motu_mark3_mixerdefs.h"
30
31 #include "devicemanager.h"
32
33 #include "libieee1394/configrom.h"
34 #include "libieee1394/ieee1394service.h"
35
36 #include "libavc/avc_definitions.h"
37
38 #include "debugmodule/debugmodule.h"
39
40 #include "libstreaming/motu/MotuReceiveStreamProcessor.h"
41 #include "libstreaming/motu/MotuTransmitStreamProcessor.h"
42 #include "libstreaming/motu/MotuPort.h"
43
44 #include "libutil/Time.h"
45 #include "libutil/Configuration.h"
46
47 #include "libcontrol/BasicElements.h"
48
49 #include <string>
50 #include <stdint.h>
51 #include <assert.h>
52 #include "libutil/ByteSwap.h"
53 #include <iostream>
54 #include <sstream>
55
56 #include <libraw1394/csr.h>
57
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.
62 //
63 // #define USE_PORTGROUPS
64
65
66 namespace Motu {
67
68 // Define the supported devices.  Device ordering is arbitary here.
69 static VendorModelEntry supportedDeviceList[] =
70 {
71 //  {vendor_id, model_id, unit_version, unit_specifier_id, model, vendor_name,model_name}
72     {FW_VENDORID_MOTU, 0, 0x00000003, 0x000001f2, MOTU_MODEL_828mkII, "MOTU", "828MkII"},
73     {FW_VENDORID_MOTU, 0, 0x00000009, 0x000001f2, MOTU_MODEL_TRAVELER, "MOTU", "Traveler"},
74     {FW_VENDORID_MOTU, 0, 0x0000000d, 0x000001f2, MOTU_MODEL_ULTRALITE, "MOTU", "UltraLite"},
75     {FW_VENDORID_MOTU, 0, 0x0000000f, 0x000001f2, MOTU_MODEL_8PRE, "MOTU", "8pre"},
76     {FW_VENDORID_MOTU, 0, 0x00000001, 0x000001f2, MOTU_MODEL_828MkI, "MOTU", "828MkI"},
77     {FW_VENDORID_MOTU, 0, 0x00000005, 0x000001f2, MOTU_MODEL_896HD, "MOTU", "896HD"},
78     {FW_VENDORID_MOTU, 0, 0x00000015, 0x000001f2, MOTU_MODEL_828mk3, "MOTU", "828Mk3"},
79     {FW_VENDORID_MOTU, 0, 0x00000019, 0x000001f2, MOTU_MODEL_ULTRALITEmk3, "MOTU", "UltraLiteMk3"},
80     {FW_VENDORID_MOTU, 0, 0x0000001b, 0x000001f2, MOTU_MODEL_TRAVELERmk3, "MOTU", "TravelerMk3"},
81     {FW_VENDORID_MOTU, 0, 0x00000030, 0x000001f2, MOTU_MODEL_ULTRALITEmk3_HYB, "MOTU", "UltraLiteMk3-hybrid"},
82 };
83
84 // Ports declarations
85 const PortEntry Ports_828MKI[] =
86 {
87     {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
88     {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
89     {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
90     {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
91     {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
92     {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
93     {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
94     {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
95     {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
96     {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
97     {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 40},
98     {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 43},
99     {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 46},
100     {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 49},
101     {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 52},
102     {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 55},
103     {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 58},
104     {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 61},
105 };
106
107 const PortEntry Ports_896HD[] =
108 {
109     {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
110     {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
111     {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
112     {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
113     {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 16},
114     {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 10},
115     {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 19},
116     {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 13},
117     {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 22},
118     {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 16},
119     {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 25},
120     {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 19},
121     {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 28},
122     {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 22},
123     {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 31},
124     {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 25},
125     {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 34},
126     {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 28},
127     {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 37},
128     {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 31},
129     {"MainOut-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
130     {"MainOut-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
131     {"unknown-1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
132     {"unknown-2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
133     {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 46},
134     {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 49},
135     {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 52},
136     {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 55},
137     {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 58},
138     {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 61},
139     {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
140     {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
141     // AES/EBU location with ADAT active
142     {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
143     {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
144     {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, 58},
145     {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, 61},
146     // AES/EBU location with no ADAT active
147     {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF, 46},
148     {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF, 49},
149 };
150
151 const PortEntry Ports_828MKII[] =
152 {
153     {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
154     {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
155     {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
156     {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
157     {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
158     {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
159     {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
160     {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
161     {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
162     {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
163     {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
164     {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
165     {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
166     {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
167     {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
168     {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
169     {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 46},
170     {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 49},
171     {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 52},
172     {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 55},
173     {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 58},
174     {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 61},
175     {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
176     {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
177     {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
178     {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
179 };
180
181 const PortEntry Ports_TRAVELER[] =
182 {
183     {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
184     {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
185     {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 10},
186     {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 13},
187     {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 16},
188     {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 10},
189     {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 19},
190     {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 13},
191     {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 22},
192     {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 16},
193     {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 25},
194     {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 19},
195     {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 28},
196     {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 22},
197     {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 31},
198     {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 25},
199     {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 34},
200     {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 28},
201     {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 37},
202     {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_4x|MOTU_PA_OPTICAL_ANY, 31},
203     {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
204     {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
205     {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_OPTICAL_ADAT, 46},
206     {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_OPTICAL_ADAT, 49},
207     {"Toslink1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 46},
208     {"Toslink2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 49},
209     {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 52},
210     {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 55},
211     {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 58},
212     {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 61},
213     {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
214     {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
215     {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
216     {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
217 };
218
219 const PortEntry Ports_ULTRALITE[] =
220 {
221     {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
222     {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
223     {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
224     {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
225     {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
226     {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
227     {"Analog1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
228     {"Analog2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
229     {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
230     {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
231     {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
232     {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
233     {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
234     {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
235     {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
236     {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
237     {"SPDIF1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
238     {"SPDIF2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
239     {"Padding1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 46},
240     {"Padding2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 49},
241     {"SPDIF1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 46},
242     {"SPDIF2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 49},
243 };
244
245 const PortEntry Ports_8PRE[] =
246 {
247     {"Analog1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
248     {"Analog2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
249     {"Analog3", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
250     {"Analog4", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
251     {"Analog5", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
252     {"Analog6", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
253     {"Analog7", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
254     {"Analog8", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
255     {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
256     {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
257     {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
258     {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
259     {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
260     {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
261     {"Padding1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_OFF|MOTU_PA_PADDING, 22},
262     {"Padding2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_OFF|MOTU_PA_PADDING, 25},
263     {"ADAT1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 40},
264     {"ADAT1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 22},
265     {"ADAT2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 43},
266     {"ADAT2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 25},
267     {"ADAT3", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 46},
268     {"ADAT3", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 28},
269     {"ADAT4", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 49},
270     {"ADAT4", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 31},
271     {"ADAT5", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 52},
272     {"ADAT5", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 34},
273     {"ADAT6", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 55},
274     {"ADAT6", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 37},
275     {"ADAT7", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 58},
276     {"ADAT7", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 40},
277     {"ADAT8", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 61},
278     {"ADAT8", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ADAT, 43},
279 };
280
281 const PortEntry Ports_828mk3[] =
282 {
283     {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 10},
284     {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 13},
285     {"Unknown-L", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 10},
286     {"Unknown-R", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 13},
287     {"Mic-1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 10},
288     {"Mic-2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 13},
289     {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 16},
290     {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 19},
291     {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 22},
292     {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 25},
293     {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 28},
294     {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 31},
295     {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 34},
296     {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 37},
297     {"MainOut-L", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 40},
298     {"MainOut-R", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 43},
299     {"Return-1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 40},
300     {"Return-2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 43},
301     {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 46},
302     {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 49},
303     {"Unknown-1", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 46},
304     {"Unknown-2", MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, 49},
305     {"Reverb-1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 52},
306     {"Reverb-2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 55},
307     //
308     // Optical port locations are a bit messy with the Mark 3 devices since
309     // there are two optical ports whose modes can be independently set.
310     // First take care of the output direction.
311     //
312     {"Toslink-A1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 52},
313     {"Toslink-A2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 55},
314     {"ADAT-A1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 52},
315     {"ADAT-A2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 55},
316     {"ADAT-A3", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 58},
317     {"ADAT-A4", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 61},
318     {"ADAT-A5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 64},
319     {"ADAT-A6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 67},
320     {"ADAT-A7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 70},
321     {"ADAT-A8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, 73},
322     //
323     {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 52},
324     {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 55},
325     {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 58},
326     {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 61},
327     {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 76},
328     {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 79},
329     {"Toslink-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 64},
330     {"Toslink-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 67},
331     {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 76},
332     {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 79},
333     {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 82},
334     {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 85},
335     {"ADAT-B5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 88},
336     {"ADAT-B6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 91},
337     {"ADAT-B7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 94},
338     {"ADAT-B8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 97},
339     {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 64},
340     {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 67},
341     {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 70},
342     {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 73},
343     //
344     {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 58},
345     {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 61},
346     {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 64},
347     {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 67},
348     {"ADAT-B5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 70},
349     {"ADAT-B6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 73},
350     {"ADAT-B7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 76},
351     {"ADAT-B8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 79},
352     {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 58},
353     {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 61},
354     {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 64},
355     {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 67},
356     //
357     {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 52},
358     {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 55},
359     {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 58},
360     {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 61},
361     {"ADAT-B5", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 64},
362     {"ADAT-B6", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 67},
363     {"ADAT-B7", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 70},
364     {"ADAT-B8", MOTU_PA_OUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 73},
365     {"ADAT-B1", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 52},
366     {"ADAT-B2", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 55},
367     {"ADAT-B3", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 58},
368     {"ADAT-B4", MOTU_PA_OUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_ADAT, 61},
369
370     // Now deal with the input side of things.  Firstly comes two channels
371     // which are yet to be identified at 1x rates.
372     {"Unknown-1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 58},
373     {"Unknown-2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 61},
374
375     // Follow up with the optical input port details.
376     //
377     {"Toslink-A1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 64},
378     {"Toslink-A2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 67},
379     {"Toslink-A1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 58},
380     {"Toslink-A2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, 61},
381     {"ADAT-A1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 64},
382     {"ADAT-A2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 67},
383     {"ADAT-A3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 70},
384     {"ADAT-A4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 73},
385     {"ADAT-A5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 76},
386     {"ADAT-A6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 79},
387     {"ADAT-A7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 82},
388     {"ADAT-A8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 85},
389     {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 88},
390     {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 91},
391     {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 94},
392     {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 97},
393     {"ADAT-B5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 100},
394     {"ADAT-B6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 103},
395     {"ADAT-B7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 106},
396     {"ADAT-B8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 109},
397     {"ADAT-A1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 58},
398     {"ADAT-A2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 61},
399     {"ADAT-A3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 64},
400     {"ADAT-A4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ANY, 67},
401     {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 70},
402     {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 73},
403     {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 76},
404     {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 79},
405     {"Unknown-3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 82},
406     {"Unknown-4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT|MOTU_PA_MK3_OPT_B_ADAT, 85},
407     //
408     {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 64},
409     {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 67},
410     {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 58},
411     {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_OFF|MOTU_PA_MK3_OPT_B_TOSLINK, 61},
412     {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 70},
413     {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 73},
414     {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 64},
415     {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_TOSLINK, 67},
416     {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 88},
417     {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 91},
418     {"Toslink-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 70},
419     {"Toslink-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_TOSLINK, 73},
420     {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 64},
421     {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 67},
422     {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 70},
423     {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 73},
424     {"ADAT-B5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 76},
425     {"ADAT-B6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 79},
426     {"ADAT-B7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 82},
427     {"ADAT-B8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 85},
428     {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 58},
429     {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 61},
430     {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 64},
431     {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 67},
432     {"Unknown-3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 70},
433     {"Unknown-4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_MK3_OPT_B_ADAT, 73},
434     //
435     {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 70},
436     {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 73},
437     {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 76},
438     {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 79},
439     {"ADAT-B5", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 82},
440     {"ADAT-B6", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 85},
441     {"ADAT-B7", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 88},
442     {"ADAT-B8", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 91},
443     {"ADAT-B1", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 64},
444     {"ADAT-B2", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 67},
445     {"ADAT-B3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 70},
446     {"ADAT-B4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 73},
447     {"Unknown-3", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 76},
448     {"Unknown-4", MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_TOSLINK|MOTU_PA_MK3_OPT_B_ADAT, 79},
449
450 };
451
452 const PortEntry Ports_ULTRALITEmk3[] =
453 {
454     {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
455     {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
456     {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
457     {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
458     {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
459     {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
460     {"Analog1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
461     {"Analog2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
462     {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
463     {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
464     {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
465     {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
466     {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
467     {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
468     {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
469     {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
470     {"SPDIF1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
471     {"SPDIF2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
472     {"Padding1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 46},
473     {"Padding2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 49},
474     {"SPDIF1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 46},
475     {"SPDIF2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 49},
476 };
477
478 const PortEntry Ports_ULTRALITEmk3_hybrid[] =
479 {
480     {"Main-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 40},
481     {"Main-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 43},
482     {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
483     {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
484     {"Mic1", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
485     {"Mic2", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
486     {"Analog1", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 16},
487     {"Analog2", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 19},
488     {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 22},
489     {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 25},
490     {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 28},
491     {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 31},
492     {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 34},
493     {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 37},
494     {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 10},
495     {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 13},
496     {"SPDIF1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 40},
497     {"SPDIF2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 43},
498     {"Reverb1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 46},
499     {"Reverb2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 49},
500     {"Unknown1", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 52},
501     {"Unknown2", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 55},
502     {"Unknown3", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 58},
503     {"Unknown4", MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 61},
504
505     {"SPDIF1", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 46},
506     {"SPDIF2", MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 49},
507 };
508
509 /* FIXME: as of 5 Aug 2010 this is still under development */
510 const PortEntry Ports_TRAVELERmk3[] =
511 {
512     {"Mix-L", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 10},
513     {"Mix-R", MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 13},
514     {"Phones-L", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 10},
515     {"Phones-R", MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 13},
516     {"Analog1", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 16},
517     {"Analog2", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 19},
518     {"Analog3", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 22},
519     {"Analog4", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 25},
520     {"Analog5", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 28},
521     {"Analog6", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 31},
522     {"Analog7", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 34},
523     {"Analog8", MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, 37},
524     {"AES/EBU1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 40},
525     {"AES/EBU2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 43},
526     {"SPDIF1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 46},
527     {"SPDIF2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, 49},
528     {"Reverb1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 52},
529     {"Reverb2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 55},
530     {"Unknown1", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 58},
531     {"Unknown2", MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, 61},
532     //
533     // FIXME: optical port details to be filled in later.
534 #if 0
535     {"Toslink1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 46},
536     {"Toslink2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, 49},
537     {"ADAT1", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 52},
538     {"ADAT2", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 55},
539     {"ADAT3", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 58},
540     {"ADAT4", MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, 61},
541     {"ADAT5", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 64},
542     {"ADAT6", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 67},
543     {"ADAT7", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 70},
544     {"ADAT8", MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 73},
545 #endif
546 };
547
548 // FIXME: The following tables relate to the new PortGroupEntry mechanism,
549 // used to convey the same information as the old PortEntry tables but in a
550 // more compact and maintainable form.  These aren't actually used yet since
551 // the functionality of addDirPortGroups() still needs to be tested.  Once
552 // this is done, all calls to addDirPorts() will be replaced with calls to
553 // addDirPortGroups().  After this is working the old PortEntry tables can
554 // be removed.
555
556 PortGroupEntry PortGroups_828MKI[] =
557 {
558     {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, -1, },
559     {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
560     {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, },
561     {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, },
562 };
563
564 PortGroupEntry PortGroups_896HD[] =
565 {
566     {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, -1, },
567     {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
568     {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
569     {"MainOut-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
570     {"unknown-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
571     {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, },
572     {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, },
573     {"AES/EBU%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ADAT, },
574 };
575
576 PortGroupEntry PortGroups_828MKII[] =
577 {
578     {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, -1},
579     {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
580     {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
581     {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
582     {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
583     {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
584     {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, },
585     {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, },
586 };
587
588 PortGroupEntry PortGroups_TRAVELER[] =
589 {
590     {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, -1, },
591     {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
592     {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, },
593     {"AES/EBU%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, },
594     {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_OFF|MOTU_PA_OPTICAL_ADAT, },
595     {"Toslink%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_TOSLINK, },
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, },
598 };
599
600 PortGroupEntry PortGroups_ULTRALITE[] =
601 {
602     {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
603     {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
604     {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, },
605     {"Analog%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4, },
606     {"Analog%d", 6, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 5, 2},
607     {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
608     {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 6, },
609     {"Padding%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 7, },
610 };
611
612 PortGroupEntry PortGroups_8PRE[] =
613 {
614     {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
615     {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, },
616     {"Analog%d", 8, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
617     {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
618     {"Padding%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_OFF|MOTU_PA_PADDING, 4, },
619     {"ADAT%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_OPTICAL_ADAT, 5, },
620     {"ADAT%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_OPTICAL_ADAT, 6, },
621 };
622
623 PortGroupEntry PortGroups_828mk3[] =
624 {
625     {"Mic-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, -1, },
626     {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
627     {"Unknown-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, },
628     {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
629     {"Return-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
630     {"MainOut-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
631     {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
632     {"Unknown-%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_4x|MOTU_PA_MK3_OPT_ANY, },
633     {"Reverb-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
634     //
635     // For input at 1x rates there are an additional 2 channel slots which
636     // are yet to be identified.
637     //
638     {"UnknownA-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
639     //
640     // Optical ports.  Note: UnknownB is flagged as being always present at
641     // 2x rates in the input stream.  This is yet to be verified.  In the
642     // case of the old PortEntry definition UnknownB's equivalent was only
643     // flagged as present if optical B was set to ADAT; this seems wrong on
644     // reflection.
645     //
646     {"Toslink-A%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_TOSLINK|MOTU_PA_MK3_OPT_B_ANY, },
647     {"ADAT-A%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
648     {"ADAT-A%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ADAT|MOTU_PA_MK3_OPT_B_ANY, },
649     {"Toslink-B%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_TOSLINK, },
650     {"ADAT-B%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
651     {"ADAT-B%d", 4, MOTU_PA_INOUT | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ADAT, },
652     {"UnknownB-%d", 2, MOTU_PA_IN | MOTU_PA_RATE_2x|MOTU_PA_MK3_OPT_A_ANY|MOTU_PA_MK3_OPT_B_ANY, },
653 };
654
655 PortGroupEntry PortGroups_ULTRALITEmk3[] =
656 {
657     {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
658     {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
659     {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, },
660     {"Analog%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4, },
661     {"Analog%d", 6, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 5, 2},
662     {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
663     {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 6, },
664     {"Padding%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY|MOTU_PA_PADDING, 7, },
665 };
666
667 PortGroupEntry PortGroups_ULTRALITEmk3_hybrid[] =
668 {
669     {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 1, },
670     {"Phones-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 2, },
671     {"Mic%d", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 3, },
672     {"Analog%d", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 4, },
673     {"Analog%d", 6, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 5, 2, },
674     {"Main-%s", 2, MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_OPTICAL_ANY, 0, },
675     {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 6, },
676     {"Reverb%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 7, },
677     {"Unknown%d", 4, MOTU_PA_IN | MOTU_PA_RATE_1x2x|MOTU_PA_OPTICAL_ANY, 8, },
678 };
679
680 /* FIXME: as of 5 Aug 2010 this is still under development */
681 PortGroupEntry PortGroups_TRAVELERmk3[] =
682 {
683     {"Mix-%s", 2, MOTU_PA_IN | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, -1, },
684     {"Phones-%s",2,  MOTU_PA_OUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
685     {"Analog%d", 8, MOTU_PA_INOUT | MOTU_PA_RATE_ANY|MOTU_PA_MK3_OPT_ANY, },
686     {"AES/EBU%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
687     {"SPDIF%d", 2, MOTU_PA_INOUT | MOTU_PA_RATE_1x2x|MOTU_PA_MK3_OPT_ANY, },
688     {"Reverb%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
689     {"Unknown%d", 2, MOTU_PA_IN | MOTU_PA_RATE_1x|MOTU_PA_MK3_OPT_ANY, },
690     //
691     // FIXME: optical port details to be filled in later.
692     //
693 };
694
695
696 #define PORTGROUPS(__model) PortGroups_ ## __model, N_ELEMENTS(PortGroups_ ## __model)
697
698 /* The order of DevicesProperty entries must match the numeric order of the
699  * MOTU model enumeration (EMotuModel).
700  */
701 const DevicePropertyEntry DevicesProperty[] = {
702 //  { PortGroups_map,     N_ELEMENTS( PortGroups_map ),
703 //    Ports_map,          N_ELEMENTS( Ports_map ),      MaxSR, MixerDescrPtr, Mark3MixerDescrPtr },
704     { PORTGROUPS(828MKII),
705       Ports_828MKII,      N_ELEMENTS( Ports_828MKII ),       96000, &Mixer_828Mk2, NULL, },
706     { PORTGROUPS(TRAVELER),
707       Ports_TRAVELER,     N_ELEMENTS( Ports_TRAVELER ),     192000, &Mixer_Traveler, NULL, },
708     { PORTGROUPS(ULTRALITE),
709       Ports_ULTRALITE,    N_ELEMENTS( Ports_ULTRALITE ),     96000, &Mixer_Ultralite, NULL, },
710     { PORTGROUPS(8PRE),
711       Ports_8PRE,         N_ELEMENTS( Ports_8PRE ),          96000, &Mixer_8pre, NULL, },
712     { PORTGROUPS(828MKI),
713       Ports_828MKI,       N_ELEMENTS( Ports_828MKI ),        48000 },
714     { PORTGROUPS(896HD),
715       Ports_896HD,        N_ELEMENTS( Ports_896HD ),        192000, &Mixer_896HD, NULL, },
716     { PORTGROUPS(828mk3),
717       Ports_828mk3,       N_ELEMENTS( Ports_828mk3 ),       192000 },
718     { PORTGROUPS(ULTRALITEmk3),
719       Ports_ULTRALITEmk3, N_ELEMENTS( Ports_ULTRALITEmk3 ), 192000 }, // Ultralite mk3
720     { PORTGROUPS(ULTRALITEmk3_hybrid),
721       Ports_ULTRALITEmk3_hybrid, N_ELEMENTS( Ports_ULTRALITEmk3_hybrid ), 192000 }, // Ultralite mk3 hybrid
722     { PORTGROUPS(TRAVELERmk3),
723       Ports_TRAVELERmk3,  N_ELEMENTS( Ports_TRAVELERmk3 ),  192000 },
724 };
725
726 MotuDevice::MotuDevice( DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
727     : FFADODevice( d, configRom )
728     , m_motu_model( MOTU_MODEL_NONE )
729     , m_iso_recv_channel ( -1 )
730     , m_iso_send_channel ( -1 )
731     , m_rx_bandwidth ( -1 )
732     , m_tx_bandwidth ( -1 )
733     , m_receiveProcessor ( 0 )
734     , m_transmitProcessor ( 0 )
735     , m_MixerContainer ( NULL )
736     , m_ControlContainer ( NULL )
737 {
738     debugOutput( DEBUG_LEVEL_VERBOSE, "Created Motu::MotuDevice (NodeID %d)\n",
739                  getConfigRom().getNodeId() );
740 }
741
742 MotuDevice::~MotuDevice()
743 {
744     delete m_receiveProcessor;
745     delete m_transmitProcessor;
746
747     // Free ieee1394 bus resources if they have been allocated
748     if (m_iso_recv_channel>=0 && !get1394Service().freeIsoChannel(m_iso_recv_channel)) {
749         debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free recv iso channel %d\n", m_iso_recv_channel);
750     }
751     if (m_iso_send_channel>=0 && !get1394Service().freeIsoChannel(m_iso_send_channel)) {
752         debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free send iso channel %d\n", m_iso_send_channel);
753     }
754
755     destroyMixer();
756 }
757
758 bool
759 MotuDevice::probe( Util::Configuration& c, ConfigRom& configRom, bool generic)
760 {
761     if(generic) return false;
762
763     unsigned int vendorId = configRom.getNodeVendorId();
764     unsigned int unitVersion = configRom.getUnitVersion();
765     unsigned int unitSpecifierId = configRom.getUnitSpecifierId();
766
767     for ( unsigned int i = 0;
768           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
769           ++i )
770     {
771         if ( ( supportedDeviceList[i].vendor_id == vendorId )
772              && ( supportedDeviceList[i].unit_version == unitVersion )
773              && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
774            )
775         {
776             return true;
777         }
778     }
779
780     return false;
781 }
782
783 FFADODevice *
784 MotuDevice::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
785 {
786     return new MotuDevice(d, configRom);
787 }
788
789 bool
790 MotuDevice::discover()
791 {
792     unsigned int vendorId = getConfigRom().getNodeVendorId();
793     unsigned int unitVersion = getConfigRom().getUnitVersion();
794     unsigned int unitSpecifierId = getConfigRom().getUnitSpecifierId();
795
796     for ( unsigned int i = 0;
797           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
798           ++i )
799     {
800         if ( ( supportedDeviceList[i].vendor_id == vendorId )
801              && ( supportedDeviceList[i].unit_version == unitVersion )
802              && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
803            )
804         {
805             m_model = &(supportedDeviceList[i]);
806             m_motu_model=supportedDeviceList[i].model;
807         }
808     }
809
810     if (m_model == NULL) {
811         return false;
812     }
813
814     debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
815         m_model->vendor_name, m_model->model_name);
816
817     if (!buildMixer()) {
818         debugWarning("Could not build mixer\n");
819     }
820
821     return true;
822 }
823
824 enum FFADODevice::eStreamingState
825 MotuDevice::getStreamingState()
826 {
827     unsigned int val = ReadRegister(MOTU_REG_ISOCTRL);
828     /* Streaming is active if either bit 22 (Motu->PC streaming
829      * enable) or bit 30 (PC->Motu streaming enable) is set.
830      */
831     debugOutput(DEBUG_LEVEL_VERBOSE, "MOTU_REG_ISOCTRL: %08x\n", val);
832
833     if((val & 0x40400000) != 0) {
834         return eSS_Both;
835     } else if ((val & 0x40000000) != 0) {
836         return eSS_Receiving;
837     } else if ((val & 0x00400000) != 0) {
838         return eSS_Sending;
839     } else {
840         return eSS_Idle;
841     }
842 }
843
844 int
845 MotuDevice::getSamplingFrequency( ) {
846 /*
847  * Retrieve the current sample rate from the MOTU device.
848  */
849     quadlet_t q = 0;
850     int rate = 0;
851     unsigned int rate_base_mask, rate_base48k;
852     unsigned int rate_mult_mask, rate_mult2, rate_mult4;
853
854     if (m_motu_model == MOTU_MODEL_828MkI) {
855         /* The original MOTU interfaces did things rather differently */
856         q = ReadRegister(MOTU_G1_REG_CONFIG);
857         if ((q & MOTU_G1_RATE_MASK) == MOTU_G1_RATE_44100)
858             rate = 44100;
859         else
860             rate = 48000;
861         return rate;
862     }
863
864     /* The way the rate is managed is the same across G2 and G3 devices,
865      * but the actual bits used in the clock control register is different.
866      */
867     if (getDeviceGeneration() == MOTU_DEVICE_G2) {
868         rate_base_mask = MOTU_RATE_BASE_MASK;
869         rate_base48k = MOTU_RATE_BASE_48000;
870         rate_mult_mask = MOTU_RATE_MULTIPLIER_MASK;
871         rate_mult2 = MOTU_RATE_MULTIPLIER_2X;
872         rate_mult4 = MOTU_RATE_MULTIPLIER_4X;
873     } else {
874         rate_base_mask = MOTU_G3_RATE_BASE_MASK;
875         rate_base48k = MOTU_G3_RATE_BASE_48000;
876         rate_mult_mask = MOTU_G3_RATE_MULTIPLIER_MASK;
877         rate_mult2 = MOTU_G3_RATE_MULTIPLIER_2X;
878         rate_mult4 = MOTU_G3_RATE_MULTIPLIER_4X;
879     }
880
881     q = ReadRegister(MOTU_REG_CLK_CTRL);
882     if ((q & rate_base_mask) == rate_base48k)
883         rate = 48000;
884     else
885         rate = 44100;
886     if ((q & rate_mult_mask) == rate_mult4)
887         rate *= 4;
888     else
889     if ((q & rate_mult_mask) == rate_mult2)
890         rate *= 2;
891
892     return rate;
893 }
894
895 int
896 MotuDevice::getConfigurationId()
897 {
898     return 0;
899 }
900
901 unsigned int
902 MotuDevice::getHwClockSource()
903 {
904     unsigned int reg;
905
906     if (m_motu_model == MOTU_MODEL_828MkI) {
907         reg = ReadRegister(MOTU_G1_REG_CONFIG);
908         switch (reg & MOTU_G1_CLKSRC_MASK) {
909             case MOTU_G1_CLKSRC_INTERNAL: return MOTU_CLKSRC_INTERNAL;
910             case MOTU_G1_CLKSRC_ADAT_9PIN: return MOTU_CLKSRC_ADAT_9PIN;
911             case MOTU_G1_CLKSRC_SPDIF: return MOTU_CLKSRC_SPDIF_TOSLINK;
912         }
913         return MOTU_CLKSRC_NONE;
914     }
915
916     reg = ReadRegister(MOTU_REG_CLK_CTRL);
917     if (getDeviceGeneration() == MOTU_DEVICE_G2) {
918         switch (reg & MOTU_G2_CLKSRC_MASK) {
919             case MOTU_G2_CLKSRC_INTERNAL: return MOTU_CLKSRC_INTERNAL;
920             case MOTU_G2_CLKSRC_ADAT_OPTICAL: return MOTU_CLKSRC_ADAT_OPTICAL;
921             case MOTU_G2_CLKSRC_SPDIF_TOSLINK: return MOTU_CLKSRC_SPDIF_TOSLINK;
922             case MOTU_G2_CLKSRC_SMPTE: return MOTU_CLKSRC_SMPTE;
923             case MOTU_G2_CLKSRC_WORDCLOCK: return MOTU_CLKSRC_WORDCLOCK;
924             case MOTU_G2_CLKSRC_ADAT_9PIN: return MOTU_CLKSRC_ADAT_9PIN;
925             case MOTU_G2_CLKSRC_AES_EBU: return MOTU_CLKSRC_AES_EBU;
926         }
927     } else {
928         /* Handle G3 devices */
929         switch (reg & MOTU_G3_CLKSRC_MASK) {
930             case MOTU_G3_CLKSRC_INTERNAL: return MOTU_CLKSRC_INTERNAL;
931             case MOTU_G3_CLKSRC_SPDIF: return MOTU_CLKSRC_SPDIF_TOSLINK;
932             case MOTU_G3_CLKSRC_SMPTE: return MOTU_CLKSRC_SMPTE;
933             case MOTU_G3_CLKSRC_WORDCLOCK: return MOTU_CLKSRC_WORDCLOCK;
934             case MOTU_G3_CLKSRC_OPTICAL_A: return MOTU_CLKSRC_OPTICAL_A;
935             case MOTU_G3_CLKSRC_OPTICAL_B: return MOTU_CLKSRC_OPTICAL_B;
936         }
937     }
938     return MOTU_CLKSRC_NONE;
939 }
940
941 bool
942 MotuDevice::setClockCtrlRegister(signed int samplingFrequency, unsigned int clock_source)
943 {
944 /*
945  * Set the MOTU device's samplerate and/or clock source via the clock
946  * control register.  If samplingFrequency <= 0 it remains unchanged.  If
947  * clock_source is MOTU_CLKSRC_UNCHANGED the clock source remains unchanged.
948  */
949     const char *src_name;
950     quadlet_t q, new_rate=0xffffffff;
951     signed int i, supported=true, cancel_adat=false;
952     quadlet_t reg;
953     unsigned int rate_mask = 0;
954     unsigned int old_clock_src = getHwClockSource();
955     signed int device_gen = getDeviceGeneration();
956
957     /* Don't touch anything if there's nothing to do */
958     if (samplingFrequency<=0 && clock_source==MOTU_CLKSRC_NONE)
959         return true;
960
961     if ( samplingFrequency > DevicesProperty[m_motu_model-1].MaxSampleRate )
962        return false;
963
964     /* The original MOTU devices do things differently; they are much
965      * simpler than the later interfaces.
966      */
967     if (m_motu_model == MOTU_MODEL_828MkI) {
968         reg = ReadRegister(MOTU_G1_REG_CONFIG);
969         if (samplingFrequency > 0) {
970             reg &= ~MOTU_G1_RATE_MASK;
971             switch (samplingFrequency) {
972                 case 44100:
973                     reg |= MOTU_G1_RATE_44100;
974                     break;
975                 case 48000:
976                     reg |= MOTU_G1_RATE_48000;
977                 default:
978                     // Unsupported rate
979                     return false;
980             }
981         }
982         if (clock_source != MOTU_CLKSRC_UNCHANGED) {
983             switch (clock_source) {
984                 case MOTU_CLKSRC_INTERNAL:
985                     clock_source = MOTU_G1_CLKSRC_INTERNAL; break;
986                 case MOTU_CLKSRC_SPDIF_TOSLINK:
987                     clock_source = MOTU_G1_CLKSRC_SPDIF; break;
988                 case MOTU_CLKSRC_ADAT_9PIN:
989                     clock_source = MOTU_G1_CLKSRC_ADAT_9PIN; break;
990                 default:
991                     // Unsupported clock source
992                     return false;
993             }
994             reg &= ~MOTU_G1_CLKSRC_MASK;
995             reg |= clock_source;
996         }
997         if (WriteRegister(MOTU_G1_REG_CONFIG, reg) != 0)
998             return false;
999         return true;
1000     }
1001
1002     /* The rest of this function deals with later generation devices */
1003
1004     reg = ReadRegister(MOTU_REG_CLK_CTRL);
1005
1006     /* The method of controlling the sampling rate is the same for G2/G3
1007      * devices but the actual bits used in the rate control register differ.
1008      */
1009     if (device_gen == MOTU_DEVICE_G2) {
1010         rate_mask = MOTU_RATE_BASE_MASK | MOTU_RATE_MULTIPLIER_MASK;
1011         switch ( samplingFrequency ) {
1012             case -1: break;
1013             case 44100: new_rate = MOTU_RATE_BASE_44100 | MOTU_RATE_MULTIPLIER_1X; break;
1014             case 48000: new_rate = MOTU_RATE_BASE_48000 | MOTU_RATE_MULTIPLIER_1X; break;
1015             case 88200: new_rate = MOTU_RATE_BASE_44100 | MOTU_RATE_MULTIPLIER_2X; break;
1016             case 96000: new_rate = MOTU_RATE_BASE_48000 | MOTU_RATE_MULTIPLIER_2X; break;
1017             case 176400: new_rate = MOTU_RATE_BASE_44100 | MOTU_RATE_MULTIPLIER_4X; break;
1018             case 192000: new_rate = MOTU_RATE_BASE_48000 | MOTU_RATE_MULTIPLIER_4X; break;
1019             default:
1020                 supported=false;
1021         }
1022     } else
1023     if (device_gen == MOTU_DEVICE_G3) {
1024         rate_mask = MOTU_G3_RATE_BASE_MASK | MOTU_G3_RATE_MULTIPLIER_MASK;
1025         switch ( samplingFrequency ) {
1026             case -1: break;
1027             case 44100: new_rate = MOTU_G3_RATE_BASE_44100 | MOTU_G3_RATE_MULTIPLIER_1X; break;
1028             case 48000: new_rate = MOTU_G3_RATE_BASE_48000 | MOTU_G3_RATE_MULTIPLIER_1X; break;
1029             case 88200: new_rate = MOTU_G3_RATE_BASE_44100 | MOTU_G3_RATE_MULTIPLIER_2X; break;
1030             case 96000: new_rate = MOTU_G3_RATE_BASE_48000 | MOTU_G3_RATE_MULTIPLIER_2X; break;
1031             case 176400: new_rate = MOTU_G3_RATE_BASE_44100 | MOTU_G3_RATE_MULTIPLIER_4X; break;
1032             case 192000: new_rate = MOTU_G3_RATE_BASE_48000 | MOTU_G3_RATE_MULTIPLIER_4X; break;
1033             default:
1034                 supported=false;
1035         }
1036     }
1037     /* ADAT output is only possible for sample rates up to 96 kHz.  For
1038      * anything higher, force the ADAT channels off.
1039      */
1040     if (samplingFrequency > 96000) {
1041       cancel_adat = true;
1042     }
1043
1044     // Sanity check the clock source
1045     if (clock_source>MOTU_CLKSRC_LAST && clock_source!=MOTU_CLKSRC_UNCHANGED)
1046         supported = false;
1047
1048     // Update the clock control register.  FIXME: while this is now rather
1049     // comprehensive there may still be a need to manipulate MOTU_REG_CLK_CTRL
1050     // a little more than we do.
1051     if (supported) {
1052
1053         // If optical port must be disabled (because a 4x sample rate has
1054         // been selected) then do so before changing the sample rate.  At
1055         // this stage it will be up to the user to re-enable the optical
1056         // port if the sample rate is set to a 1x or 2x rate later.
1057         if (cancel_adat) {
1058             setOpticalMode(MOTU_CTRL_DIR_INOUT, MOTU_OPTICAL_MODE_OFF, MOTU_OPTICAL_MODE_OFF);
1059         }
1060
1061         // Set up new frequency if requested
1062         if (new_rate != 0xffffffff) {
1063             reg &= ~rate_mask;
1064             reg |= new_rate;
1065         }
1066
1067         // Set up new clock source if required
1068         if (clock_source != MOTU_CLKSRC_UNCHANGED) {
1069             if (device_gen == MOTU_DEVICE_G2) {
1070                 reg &= ~MOTU_G2_CLKSRC_MASK;
1071                 switch (clock_source) {
1072                     case MOTU_CLKSRC_INTERNAL: reg |= MOTU_G2_CLKSRC_INTERNAL; break;
1073                     case MOTU_CLKSRC_ADAT_OPTICAL: reg |= MOTU_G2_CLKSRC_ADAT_OPTICAL; break;
1074                     case MOTU_CLKSRC_SPDIF_TOSLINK: reg |= MOTU_G2_CLKSRC_SPDIF_TOSLINK; break;
1075                     case MOTU_CLKSRC_SMPTE: reg |= MOTU_G2_CLKSRC_SMPTE; break;
1076                     case MOTU_CLKSRC_WORDCLOCK: reg |= MOTU_G2_CLKSRC_WORDCLOCK; break;
1077                     case MOTU_CLKSRC_ADAT_9PIN: reg |= MOTU_G2_CLKSRC_ADAT_9PIN; break;
1078                     case MOTU_CLKSRC_AES_EBU: reg |= MOTU_G2_CLKSRC_AES_EBU; break;
1079                 }
1080             } else {
1081                 reg &= ~MOTU_G3_CLKSRC_MASK;
1082                 switch (clock_source) {
1083                     case MOTU_CLKSRC_INTERNAL: reg |= MOTU_G3_CLKSRC_INTERNAL; break;
1084                     case MOTU_CLKSRC_SPDIF_TOSLINK: reg |= MOTU_G3_CLKSRC_SPDIF; break;
1085                     case MOTU_CLKSRC_SMPTE: reg |= MOTU_G3_CLKSRC_SMPTE; break;
1086                     case MOTU_CLKSRC_WORDCLOCK: reg |= MOTU_G3_CLKSRC_WORDCLOCK; break;
1087                     case MOTU_CLKSRC_OPTICAL_A: reg |= MOTU_G3_CLKSRC_OPTICAL_A; break;
1088                     case MOTU_CLKSRC_OPTICAL_B: reg |= MOTU_G3_CLKSRC_OPTICAL_B; break;
1089                 }
1090             }
1091         } else {
1092             /* Use the device's current clock source to set the clock
1093              * source name registers, which must be done even if we aren't
1094              * changing the clock source.
1095              */
1096             clock_source = old_clock_src;
1097         }
1098
1099         // Bits 24-26 of MOTU_REG_CLK_CTRL behave a little differently
1100         // depending on the model.  In addition, different bit patterns are
1101         // written depending on whether streaming is enabled, disabled or is
1102         // changing state.  For now we go with the combination used when
1103         // streaming is enabled since it seems to work for the other states
1104         // as well.  Since device muting can be effected by these bits, we
1105         // may utilise this in future during streaming startup to prevent
1106         // noises during stabilisation.
1107         //
1108         // For most models (possibly all except the Ultralite) all 3 bits
1109         // can be zero and audio is still output.
1110         //
1111         // For the Traveler, if bit 26 is set (as it is under other OSes),
1112         // bit 25 functions as a device mute bit: if set, audio is output
1113         // while if 0 the entire device is muted.  If bit 26 is unset,
1114         // setting bit 25 doesn't appear to be detrimental.
1115         //
1116         // For the Ultralite, other OSes leave bit 26 unset.  However, unlike
1117         // other devices bit 25 seems to function as a mute bit in this case.
1118         //
1119         // The function of bit 24 is currently unknown.  Other OSes set it
1120         // for all devices so we will too.
1121         reg &= 0xf8ffffff;
1122         if (m_motu_model == MOTU_MODEL_TRAVELER)
1123             reg |= 0x04000000;
1124         reg |= 0x03000000;
1125         if (WriteRegister(MOTU_REG_CLK_CTRL, reg) == 0) {
1126             supported=true;
1127         } else {
1128             supported=false;
1129         }
1130         // A write to the rate/clock control register requires the
1131         // textual name of the current clock source be sent to the
1132         // clock source name registers.  This appears to be the same for
1133         // both G2 and G3 devices.
1134         switch (clock_source) {
1135             case MOTU_CLKSRC_INTERNAL:
1136                 src_name = "Internal        ";
1137                 break;
1138             case MOTU_CLKSRC_ADAT_OPTICAL:
1139                 src_name = "ADAT Optical    ";
1140                 break;
1141             case MOTU_CLKSRC_SPDIF_TOSLINK: {
1142                 unsigned int p0_mode;
1143                 if (device_gen < MOTU_DEVICE_G3) {
1144                     getOpticalMode(MOTU_DIR_IN, &p0_mode, NULL);
1145                 } else
1146                     p0_mode = MOTU_OPTICAL_MODE_OFF;
1147                 if (p0_mode == MOTU_OPTICAL_MODE_TOSLINK)
1148                     src_name = "TOSLink         ";
1149                 else
1150                     src_name = "SPDIF           ";
1151                 break;
1152             }
1153             case MOTU_CLKSRC_SMPTE:
1154                 src_name = "SMPTE           ";
1155                 break;
1156             case MOTU_CLKSRC_WORDCLOCK:
1157                 src_name = "Word Clock In   ";
1158                 break;
1159             case MOTU_CLKSRC_ADAT_9PIN:
1160                 src_name = "ADAT 9-pin      ";
1161                 break;
1162             case MOTU_CLKSRC_AES_EBU:
1163                 src_name = "AES-EBU         ";
1164                 break;
1165             case MOTU_CLKSRC_OPTICAL_A: {
1166                 unsigned int p0_mode;
1167                 getOpticalMode(MOTU_DIR_IN, &p0_mode, NULL);
1168                 if (p0_mode == MOTU_OPTICAL_MODE_TOSLINK)
1169                     src_name = "Toslink-A       ";
1170                 else
1171                     src_name = "ADAT-A Optical  ";
1172                 break;
1173             }
1174             case MOTU_CLKSRC_OPTICAL_B: {
1175                 unsigned int p1_mode;
1176                 getOpticalMode(MOTU_DIR_IN, NULL, &p1_mode);
1177                 if (p1_mode == MOTU_OPTICAL_MODE_TOSLINK)
1178                     src_name = "Toslink-B       ";
1179                 else
1180                     src_name = "ADAT-B Optical  ";
1181                 break;
1182             }
1183             default:
1184                 src_name = "Unknown         ";
1185         }
1186         for (i=0; i<16; i+=4) {
1187             q = (src_name[i]<<24) | (src_name[i+1]<<16) |
1188                 (src_name[i+2]<<8) | src_name[i+3];
1189             WriteRegister(MOTU_REG_CLKSRC_NAME0+i, q);
1190         }
1191     }
1192     return supported;
1193 }
1194
1195 bool
1196 MotuDevice::setSamplingFrequency( int samplingFrequency )
1197 {
1198 /*
1199  * Set the MOTU device's samplerate.
1200  */
1201     return setClockCtrlRegister(samplingFrequency, MOTU_CLKSRC_UNCHANGED);
1202 }
1203
1204 std::vector<int>
1205 MotuDevice::getSupportedSamplingFrequencies()
1206 {
1207     std::vector<int> frequencies;
1208     signed int max_freq = DevicesProperty[m_motu_model-1].MaxSampleRate;
1209
1210     /* All MOTUs support 1x rates.  All others must be conditional. */
1211     frequencies.push_back(44100);
1212     frequencies.push_back(48000);
1213
1214     if (88200 <= max_freq)
1215         frequencies.push_back(88200);
1216     if (96000 <= max_freq)
1217         frequencies.push_back(96000);
1218     if (176400 <= max_freq)
1219         frequencies.push_back(176400);
1220     if (192000 <= max_freq)
1221         frequencies.push_back(192000);
1222     return frequencies;
1223 }
1224
1225 FFADODevice::ClockSource
1226 MotuDevice::clockIdToClockSource(unsigned int id) {
1227     ClockSource s;
1228     signed int device_gen = getDeviceGeneration();
1229     s.id = id;
1230
1231     // Assume a clock source is valid/active unless otherwise overridden.
1232     s.valid = true;
1233     s.locked = true;
1234     s.active = true;
1235
1236     switch (id) {
1237         case MOTU_CLKSRC_INTERNAL:
1238             s.type = eCT_Internal;
1239             s.description = "Internal sync";
1240             break;
1241         case MOTU_CLKSRC_ADAT_OPTICAL:
1242             s.type = eCT_ADAT;
1243             s.description = "ADAT optical";
1244             s.valid = s.active = s.locked = (device_gen!=MOTU_DEVICE_G1);
1245             break;
1246         case MOTU_CLKSRC_SPDIF_TOSLINK:
1247             s.type = eCT_SPDIF;
1248             if (device_gen < MOTU_DEVICE_G3)
1249                 s.description = "SPDIF/Toslink";
1250             else
1251                 s.description = "SPDIF";
1252             break;
1253         case MOTU_CLKSRC_SMPTE:
1254             s.type = eCT_SMPTE;
1255             s.description = "SMPTE";
1256             // Since we don't currently know how to deal with SMPTE on these
1257             // devices make sure the SMPTE clock source is disabled.
1258             s.valid = false;
1259             s.active = false;
1260             s.locked = false;
1261             break;
1262         case MOTU_CLKSRC_WORDCLOCK:
1263             s.type = eCT_WordClock;
1264             s.description = "Wordclock";
1265             s.valid = s.active = s.locked = (device_gen!=MOTU_DEVICE_G1);
1266             break;
1267         case MOTU_CLKSRC_ADAT_9PIN:
1268             s.type = eCT_ADAT;
1269             s.description = "ADAT 9-pin";
1270             break;
1271         case MOTU_CLKSRC_AES_EBU:
1272             s.type = eCT_AES;
1273             s.description = "AES/EBU";
1274             s.valid = s.active = s.locked = (device_gen!=MOTU_DEVICE_G1);
1275             break;
1276         case MOTU_CLKSRC_OPTICAL_A:
1277             s.type = eCT_ADAT;
1278             s.description = "ADAT/Toslink port A";
1279             break;
1280         case MOTU_CLKSRC_OPTICAL_B:
1281             s.type = eCT_ADAT;
1282             s.description = "ADAT/Toslink port B";
1283             break;
1284         default:
1285             s.type = eCT_Invalid;
1286     }
1287
1288     s.slipping = false;
1289     return s;
1290 }
1291
1292 FFADODevice::ClockSourceVector
1293 MotuDevice::getSupportedClockSources() {
1294     FFADODevice::ClockSourceVector r;
1295     ClockSource s;
1296     signed int device_gen = getDeviceGeneration();
1297
1298     /* Form a list of clocks supported by MOTU interfaces */
1299
1300     /* All interfaces support an internal clock */
1301     s = clockIdToClockSource(MOTU_CLKSRC_INTERNAL);
1302     r.push_back(s);
1303
1304     if (device_gen == MOTU_DEVICE_G2) {
1305         s = clockIdToClockSource(MOTU_CLKSRC_ADAT_OPTICAL);
1306         r.push_back(s);
1307     }
1308
1309     s = clockIdToClockSource(MOTU_CLKSRC_SPDIF_TOSLINK);
1310     r.push_back(s);
1311     s = clockIdToClockSource(MOTU_CLKSRC_SMPTE);
1312     r.push_back(s);
1313     s = clockIdToClockSource(MOTU_CLKSRC_WORDCLOCK);
1314     r.push_back(s);
1315
1316     /* The 9-pin ADAT sync was only present on selected G2
1317      * devices.
1318      */
1319     if (m_motu_model==MOTU_MODEL_828mkII || m_motu_model==MOTU_MODEL_TRAVELER ||
1320         m_motu_model==MOTU_MODEL_896HD) {
1321         s = clockIdToClockSource(MOTU_CLKSRC_ADAT_9PIN);
1322         r.push_back(s);
1323     }
1324     /* AES/EBU is present on the G2/G3 Travelers and 896HDs */
1325     if (m_motu_model==MOTU_MODEL_TRAVELER || m_motu_model==MOTU_MODEL_TRAVELERmk3 ||
1326         m_motu_model==MOTU_MODEL_896HD || m_motu_model==MOTU_MODEL_896HDmk3) {
1327         s = clockIdToClockSource(MOTU_CLKSRC_AES_EBU);
1328         r.push_back(s);
1329     }
1330
1331     /* Dual-port ADAT is a feature of the G3 devices, and then only some */
1332     if (m_motu_model==MOTU_MODEL_828mk3 || m_motu_model==MOTU_MODEL_TRAVELERmk3 ||
1333         m_motu_model==MOTU_MODEL_896HDmk3) {
1334         s = clockIdToClockSource(MOTU_CLKSRC_OPTICAL_A);
1335         r.push_back(s);
1336         s = clockIdToClockSource(MOTU_CLKSRC_OPTICAL_B);
1337         r.push_back(s);
1338     }
1339
1340     return r;
1341 }
1342
1343 bool
1344 MotuDevice::setActiveClockSource(ClockSource s) {
1345     debugOutput(DEBUG_LEVEL_VERBOSE, "setting clock source to id: %d\n",s.id);
1346
1347     // FIXME: this could do with some error checking
1348     return setClockCtrlRegister(-1, s.id);
1349 }
1350
1351 FFADODevice::ClockSource
1352 MotuDevice::getActiveClockSource() {
1353     ClockSource s;
1354     quadlet_t clock_id = getHwClockSource();
1355     s = clockIdToClockSource(clock_id);
1356     s.active = true;
1357     return s;
1358 }
1359
1360 bool
1361 MotuDevice::lock() {
1362
1363     return true;
1364 }
1365
1366
1367 bool
1368 MotuDevice::unlock() {
1369
1370     return true;
1371 }
1372
1373 void
1374 MotuDevice::showDevice()
1375 {
1376     debugOutput(DEBUG_LEVEL_VERBOSE,
1377         "%s %s at node %d\n", m_model->vendor_name, m_model->model_name,
1378         getNodeId());
1379 }
1380
1381 bool
1382 MotuDevice::prepare() {
1383
1384     int samp_freq = getSamplingFrequency();
1385     unsigned int optical_in_mode_a, optical_out_mode_a;
1386     unsigned int optical_in_mode_b, optical_out_mode_b;
1387     unsigned int event_size_in = getEventSize(MOTU_DIR_IN);
1388     unsigned int event_size_out= getEventSize(MOTU_DIR_OUT);
1389
1390     debugOutput(DEBUG_LEVEL_NORMAL, "Preparing MotuDevice...\n" );
1391
1392     getOpticalMode(MOTU_DIR_IN, &optical_in_mode_a, &optical_in_mode_b);
1393     getOpticalMode(MOTU_DIR_OUT, &optical_out_mode_a, &optical_out_mode_b);
1394
1395     // Explicitly set the optical mode, primarily to ensure that the
1396     // MOTU_REG_OPTICAL_CTRL register is initialised.  We need to do this to
1397     // because some interfaces (the Ultralite for example) appear to power
1398     // up without this set to anything sensible.  In this case, writes to
1399     // MOTU_REG_ISOCTRL fail more often than not, which is bad.
1400     setOpticalMode(MOTU_DIR_IN, optical_in_mode_a, optical_in_mode_b);
1401     setOpticalMode(MOTU_DIR_OUT, optical_out_mode_a, optical_out_mode_b);
1402
1403     // Allocate bandwidth if not previously done.
1404     // FIXME: The bandwidth allocation calculation can probably be
1405     // refined somewhat since this is currently based on a rudimentary
1406     // understanding of the ieee1394 iso protocol.
1407     // Currently we assume the following.
1408     //   * Ack/iso gap = 0.05 us
1409     //   * DATA_PREFIX = 0.16 us
1410     //   * DATA_END    = 0.26 us
1411     // These numbers are the worst-case figures given in the ieee1394
1412     // standard.  This gives approximately 0.5 us of overheads per packet -
1413     // around 25 bandwidth allocation units (from the ieee1394 standard 1
1414     // bandwidth allocation unit is 125/6144 us).  We further assume the
1415     // MOTU is running at S400 (which it should be) so one allocation unit
1416     // is equivalent to 1 transmitted byte; thus the bandwidth allocation
1417     // required for the packets themselves is just the size of the packet.
1418     // We used to allocate based on the maximum packet size (1160 bytes at
1419     // 192 kHz for the traveler) but now do this based on the actual device
1420     // state by utilising the result from getEventSize() and remembering
1421     // that each packet has an 8 byte CIP header.  Note that bandwidth is
1422     // allocated on a *per stream* basis - it must be allocated for both the
1423     // transmit and receive streams.  While most MOTU modules are close to
1424     // symmetric in terms of the number of in/out channels there are
1425     // exceptions, so we deal with receive and transmit bandwidth separately.
1426     signed int n_events_per_packet = samp_freq<=48000?8:(samp_freq<=96000?16:32);
1427     m_rx_bandwidth = 25 + (n_events_per_packet*event_size_in);
1428     m_tx_bandwidth = 25 + (n_events_per_packet*event_size_out);
1429
1430     // Assign iso channels if not already done
1431     if (m_iso_recv_channel < 0)
1432         m_iso_recv_channel = get1394Service().allocateIsoChannelGeneric(m_rx_bandwidth);
1433
1434     if (m_iso_send_channel < 0)
1435         m_iso_send_channel = get1394Service().allocateIsoChannelGeneric(m_tx_bandwidth);
1436
1437     debugOutput(DEBUG_LEVEL_VERBOSE, "recv channel = %d, send channel = %d\n",
1438         m_iso_recv_channel, m_iso_send_channel);
1439
1440     if (m_iso_recv_channel<0 || m_iso_send_channel<0) {
1441         // be nice and deallocate
1442         if (m_iso_recv_channel >= 0)
1443             get1394Service().freeIsoChannel(m_iso_recv_channel);
1444         if (m_iso_send_channel >= 0)
1445             get1394Service().freeIsoChannel(m_iso_send_channel);
1446
1447         debugFatal("Could not allocate iso channels!\n");
1448         return false;
1449     }
1450
1451     // get the device specific and/or global SP configuration
1452     Util::Configuration &config = getDeviceManager().getConfiguration();
1453     // base value is the config.h value
1454     float recv_sp_dll_bw = STREAMPROCESSOR_DLL_BW_HZ;
1455     float xmit_sp_dll_bw = STREAMPROCESSOR_DLL_BW_HZ;
1456
1457     // we can override that globally
1458     config.getValueForSetting("streaming.spm.recv_sp_dll_bw", recv_sp_dll_bw);
1459     config.getValueForSetting("streaming.spm.xmit_sp_dll_bw", xmit_sp_dll_bw);
1460
1461     // or override in the device section
1462     config.getValueForDeviceSetting(getConfigRom().getNodeVendorId(), getConfigRom().getModelId(), "recv_sp_dll_bw", recv_sp_dll_bw);
1463     config.getValueForDeviceSetting(getConfigRom().getNodeVendorId(), getConfigRom().getModelId(), "xmit_sp_dll_bw", xmit_sp_dll_bw);
1464
1465     m_receiveProcessor=new Streaming::MotuReceiveStreamProcessor(*this, event_size_in);
1466     m_receiveProcessor->setVerboseLevel(getDebugLevel());
1467
1468     // The first thing is to initialize the processor.  This creates the
1469     // data structures.
1470     if(!m_receiveProcessor->init()) {
1471         debugFatal("Could not initialize receive processor!\n");
1472         return false;
1473     }
1474
1475     if(!m_receiveProcessor->setDllBandwidth(recv_sp_dll_bw)) {
1476         debugFatal("Could not set DLL bandwidth\n");
1477         delete m_receiveProcessor;
1478         m_receiveProcessor = NULL;
1479         return false;
1480     }
1481
1482     // Now we add ports to the processor
1483     debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to receive processor\n");
1484
1485     char *buff;
1486     Streaming::Port *p=NULL;
1487
1488     // retrieve the ID
1489     std::string id=std::string("dev?");
1490     if(!getOption("id", id)) {
1491         debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n");
1492     }
1493
1494     // Add audio capture ports
1495 #ifndef USE_PORTGROUPS
1496     if (!addDirPorts(Streaming::Port::E_Capture, samp_freq, optical_in_mode_a, optical_in_mode_b)) {
1497         return false;
1498     }
1499 #else
1500     if (!addDirPortGroups(Streaming::Port::E_Capture, samp_freq, optical_in_mode_a, optical_in_mode_b)) {
1501         return false;
1502     }
1503 #endif
1504     // Add MIDI port.  The MOTU only has one MIDI input port, with each
1505     // MIDI byte sent using a 3 byte sequence starting at byte 4 of the
1506     // event data.
1507     asprintf(&buff,"%s_cap_MIDI0",id.c_str());
1508     p = new Streaming::MotuMidiPort(*m_receiveProcessor, buff,
1509         Streaming::Port::E_Capture, 4);
1510     if (!p) {
1511         debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n", buff);
1512     }
1513     free(buff);
1514
1515     // example of adding an control port:
1516 //    asprintf(&buff,"%s_cap_%s",id.c_str(),"myportnamehere");
1517 //    p=new Streaming::MotuControlPort(
1518 //            buff,
1519 //            Streaming::Port::E_Capture,
1520 //            0 // you can add all other port specific stuff you
1521 //              // need to pass by extending MotuXXXPort and MotuPortInfo
1522 //    );
1523 //    free(buff);
1524 //
1525 //    if (!p) {
1526 //        debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
1527 //    } else {
1528 //
1529 //        if (!m_receiveProcessor->addPort(p)) {
1530 //            debugWarning("Could not register port with stream processor\n");
1531 //            return false;
1532 //        } else {
1533 //            debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
1534 //        }
1535 //    }
1536
1537     // Do the same for the transmit processor
1538     m_transmitProcessor=new Streaming::MotuTransmitStreamProcessor(*this, event_size_out);
1539
1540     m_transmitProcessor->setVerboseLevel(getDebugLevel());
1541
1542     if(!m_transmitProcessor->init()) {
1543         debugFatal("Could not initialize transmit processor!\n");
1544         return false;
1545     }
1546
1547     if(!m_transmitProcessor->setDllBandwidth(xmit_sp_dll_bw)) {
1548         debugFatal("Could not set DLL bandwidth\n");
1549         delete m_transmitProcessor;
1550         m_transmitProcessor = NULL;
1551         return false;
1552     }
1553
1554     // Now we add ports to the processor
1555     debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to transmit processor\n");
1556
1557     // Add audio playback ports
1558 #ifndef USE_PORTGROUPS
1559     if (!addDirPorts(Streaming::Port::E_Playback, samp_freq, optical_out_mode_a, optical_out_mode_b)) {
1560         return false;
1561     }
1562 #else
1563     if (!addDirPortGroups(Streaming::Port::E_Playback, samp_freq, optical_out_mode_a, optical_out_mode_b)) {
1564         return false;
1565     }
1566 #endif
1567
1568     // Add MIDI port.  The MOTU only has one output MIDI port, with each
1569     // MIDI byte transmitted using a 3 byte sequence starting at byte 4
1570     // of the event data.
1571     asprintf(&buff,"%s_pbk_MIDI0",id.c_str());
1572     p = new Streaming::MotuMidiPort(*m_transmitProcessor, buff,
1573         Streaming::Port::E_Playback, 4);
1574     if (!p) {
1575         debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n", buff);
1576     }
1577     free(buff);
1578
1579     // example of adding an control port:
1580 //    asprintf(&buff,"%s_pbk_%s",id.c_str(),"myportnamehere");
1581 //
1582 //    p=new Streaming::MotuControlPort(
1583 //            buff,
1584 //            Streaming::Port::E_Playback,
1585 //            0 // you can add all other port specific stuff you
1586 //              // need to pass by extending MotuXXXPort and MotuPortInfo
1587 //    );
1588 //    free(buff);
1589 //
1590 //    if (!p) {
1591 //        debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
1592 //    } else {
1593 //        if (!m_transmitProcessor->addPort(p)) {
1594 //            debugWarning("Could not register port with stream processor\n");
1595 //            return false;
1596 //        } else {
1597 //            debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
1598 //        }
1599 //    }
1600
1601     return true;
1602 }
1603
1604 int
1605 MotuDevice::getStreamCount() {
1606      return 2; // one receive, one transmit
1607 }
1608
1609 Streaming::StreamProcessor *
1610 MotuDevice::getStreamProcessorByIndex(int i) {
1611     switch (i) {
1612     case 0:
1613         return m_receiveProcessor;
1614     case 1:
1615          return m_transmitProcessor;
1616     default:
1617         return NULL;
1618     }
1619     return 0;
1620 }
1621
1622 bool
1623 MotuDevice::startStreamByIndex(int i) {
1624
1625 quadlet_t isoctrl = ReadRegister(MOTU_REG_ISOCTRL);
1626
1627     if (m_motu_model == MOTU_MODEL_828MkI) {
1628         // The 828MkI device does this differently.
1629         // To be implemented
1630         return false;
1631     }
1632
1633     // NOTE: this assumes that you have two streams
1634     switch (i) {
1635     case 0:
1636         // TODO: do the stuff that is nescessary to make the device
1637         // receive a stream
1638
1639         // Set the streamprocessor channel to the one obtained by
1640         // the connection management
1641         m_receiveProcessor->setChannel(m_iso_recv_channel);
1642
1643         // Mask out current transmit settings of the MOTU and replace
1644         // with new ones.  Turn bit 24 on to enable changes to the
1645         // MOTU's iso transmit settings when the iso control register
1646         // is written.  Bit 23 enables iso transmit from the MOTU.
1647         isoctrl &= 0xff00ffff;
1648         isoctrl |= (m_iso_recv_channel << 16);
1649         isoctrl |= 0x00c00000;
1650         WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1651         break;
1652     case 1:
1653         // TODO: do the stuff that is nescessary to make the device
1654         // transmit a stream
1655
1656         // Set the streamprocessor channel to the one obtained by
1657         // the connection management
1658         m_transmitProcessor->setChannel(m_iso_send_channel);
1659
1660         // Mask out current receive settings of the MOTU and replace
1661         // with new ones.  Turn bit 31 on to enable changes to the
1662         // MOTU's iso receive settings when the iso control register
1663         // is written.  Bit 30 enables iso receive by the MOTU.
1664         isoctrl &= 0x00ffffff;
1665         isoctrl |= (m_iso_send_channel << 24);
1666         isoctrl |= 0xc0000000;
1667         WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1668         break;
1669
1670     default: // Invalid stream index
1671         return false;
1672     }
1673
1674     return true;
1675 }
1676
1677 bool
1678 MotuDevice::stopStreamByIndex(int i) {
1679
1680 quadlet_t isoctrl = ReadRegister(MOTU_REG_ISOCTRL);
1681
1682     // TODO: connection management: break connection
1683     // cfr the start function
1684
1685     if (m_motu_model == MOTU_MODEL_828MkI) {
1686         // The 828MkI device does this differently.
1687         // To be implemented
1688         return false;
1689     }
1690
1691     // NOTE: this assumes that you have two streams
1692     switch (i) {
1693     case 0:
1694         // Turn bit 22 off to disable iso send by the MOTU.  Turn
1695         // bit 23 on to enable changes to the MOTU's iso transmit
1696         // settings when the iso control register is written.
1697         isoctrl &= 0xffbfffff;
1698         isoctrl |= 0x00800000;
1699         WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1700         break;
1701     case 1:
1702         // Turn bit 30 off to disable iso receive by the MOTU.  Turn
1703         // bit 31 on to enable changes to the MOTU's iso receive
1704         // settings when the iso control register is written.
1705         isoctrl &= 0xbfffffff;
1706         isoctrl |= 0x80000000;
1707         WriteRegister(MOTU_REG_ISOCTRL, isoctrl);
1708         break;
1709
1710     default: // Invalid stream index
1711         return false;
1712     }
1713
1714     return true;
1715 }
1716
1717 signed int MotuDevice::getIsoRecvChannel(void) {
1718     return m_iso_recv_channel;
1719 }
1720
1721 signed int MotuDevice::getIsoSendChannel(void) {
1722     return m_iso_send_channel;
1723 }
1724
1725 signed int MotuDevice::getDeviceGeneration(void) {
1726     if (m_motu_model == MOTU_MODEL_828MkI)
1727         return MOTU_DEVICE_G1;
1728     if (m_motu_model==MOTU_MODEL_828mk3 ||
1729         m_motu_model==MOTU_MODEL_ULTRALITEmk3 ||
1730         m_motu_model==MOTU_MODEL_ULTRALITEmk3_HYB ||
1731         m_motu_model==MOTU_MODEL_TRAVELERmk3 ||
1732         m_motu_model==MOTU_MODEL_896HDmk3)
1733         return MOTU_DEVICE_G3;
1734     return MOTU_DEVICE_G2;
1735 }
1736
1737 unsigned int MotuDevice::getOpticalMode(unsigned int dir,
1738   unsigned int *port_a_mode, unsigned int *port_b_mode) {
1739     // Only the "Mark 3" (aka G3) MOTU devices had more than one optical
1740     // port.  Therefore the "port_b_mode" parameter is unused by all
1741     // devices other than the Mark 3 devices.
1742     //
1743     // If a mode parameter pointer is NULL it will not be returned.
1744     unsigned int reg;
1745     unsigned int mask, shift;
1746
1747     if (port_b_mode != NULL)
1748         *port_b_mode = MOTU_OPTICAL_MODE_NONE;
1749     if (getDeviceGeneration()!=MOTU_DEVICE_G3 && port_a_mode==NULL)
1750         return 0;
1751
1752     if (m_motu_model == MOTU_MODEL_828MkI) {
1753         // The early devices used a different register layout. 
1754         reg = ReadRegister(MOTU_G1_REG_CONFIG);
1755         mask = (dir==MOTU_DIR_IN)?MOTU_G1_OPT_IN_MODE_MASK:MOTU_G1_OPT_OUT_MODE_MASK;
1756         shift = (dir==MOTU_DIR_IN)?MOTU_G1_OPT_IN_MODE_BIT0:MOTU_G1_OPT_OUT_MODE_BIT0;
1757         switch ((reg & mask) >> shift) {
1758             case MOTU_G1_OPTICAL_OFF: *port_a_mode = MOTU_OPTICAL_MODE_OFF; break;
1759             case MOTU_G1_OPTICAL_TOSLINK: *port_a_mode = MOTU_OPTICAL_MODE_TOSLINK; break;
1760             // MOTU_G1_OPTICAL_OFF and MOTU_G1_OPTICAL_ADAT seem to be
1761             // identical, so currently we don't know how to differentiate
1762             // these two modes.
1763             // case MOTU_G1_OPTICAL_ADAT: return MOTU_OPTICAL_MODE_ADAT;
1764         }
1765         return 0;
1766     }
1767
1768     if (getDeviceGeneration() == MOTU_DEVICE_G3) {
1769         unsigned int mask, enable, toslink;
1770         /* The Ultralite Mk3s don't have any optical ports.  All others have 2. */
1771         if (m_motu_model==MOTU_MODEL_ULTRALITEmk3 || m_motu_model==MOTU_MODEL_ULTRALITEmk3_HYB) {
1772             if (port_a_mode != NULL)
1773                 *port_a_mode = MOTU_OPTICAL_MODE_NONE;
1774             if (port_b_mode != NULL)
1775                 *port_b_mode = MOTU_OPTICAL_MODE_NONE;
1776             return 0;
1777         }
1778         reg = ReadRegister(MOTU_G3_REG_OPTICAL_CTRL);
1779         if (port_a_mode != NULL) {
1780             mask = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_A_IN_MASK:MOTU_G3_OPT_A_OUT_MASK;
1781             enable = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_A_IN_ENABLE:MOTU_G3_OPT_A_OUT_ENABLE;
1782             toslink = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_A_IN_TOSLINK:MOTU_G3_OPT_A_OUT_TOSLINK;
1783             if ((reg & enable) == 0)
1784               *port_a_mode = MOTU_OPTICAL_MODE_OFF;
1785             else
1786             if ((reg & toslink) == 0)
1787               *port_a_mode = MOTU_OPTICAL_MODE_TOSLINK;
1788             else
1789               *port_a_mode = MOTU_OPTICAL_MODE_ADAT;
1790         }
1791         if (port_b_mode != NULL) {
1792             mask = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_B_IN_MASK:MOTU_G3_OPT_B_OUT_MASK;
1793             enable = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_B_IN_ENABLE:MOTU_G3_OPT_B_OUT_ENABLE;
1794             toslink = (dir==MOTU_DIR_IN)?MOTU_G3_OPT_B_IN_TOSLINK:MOTU_G3_OPT_B_OUT_TOSLINK;
1795             if ((reg & enable) == 0)
1796               *port_b_mode = MOTU_OPTICAL_MODE_OFF;
1797             else
1798             if ((reg & toslink) == 0)
1799               *port_b_mode = MOTU_OPTICAL_MODE_TOSLINK;
1800             else
1801               *port_b_mode = MOTU_OPTICAL_MODE_ADAT;
1802         }
1803         return 0;
1804     }
1805
1806     reg = ReadRegister(MOTU_REG_ROUTE_PORT_CONF);
1807     mask = (dir==MOTU_DIR_IN)?MOTU_G2_OPTICAL_IN_MODE_MASK:MOTU_G2_OPTICAL_OUT_MODE_MASK;
1808     shift = (dir==MOTU_DIR_IN)?MOTU_G2_OPTICAL_IN_MODE_BIT0:MOTU_G2_OPTICAL_OUT_MODE_BIT0;
1809     switch ((reg & mask) >> shift) {
1810         case MOTU_G2_OPTICAL_MODE_OFF: *port_a_mode = MOTU_OPTICAL_MODE_OFF; break;
1811         case MOTU_G2_OPTICAL_MODE_ADAT: *port_a_mode = MOTU_OPTICAL_MODE_ADAT; break;
1812         case MOTU_G2_OPTICAL_MODE_TOSLINK: *port_a_mode = MOTU_OPTICAL_MODE_TOSLINK; break;
1813     }
1814     return 0;
1815 }
1816
1817 signed int MotuDevice::setOpticalMode(unsigned int dir,
1818   unsigned int port_a_mode, unsigned int port_b_mode) {
1819     // Only the "Mark 3" (aka G3) MOTU devices had more than one optical port.
1820     // Therefore the "port B" mode is ignored for all devices other than
1821     // the Mark 3 devices.
1822     unsigned int reg, g2mode;
1823     unsigned int opt_ctrl = 0x0000002;
1824
1825     /* THe 896HD doesn't have an SPDIF/TOSLINK optical mode, so don't try to
1826      * set it
1827      */
1828     if (m_motu_model==MOTU_MODEL_896HD && port_a_mode==MOTU_OPTICAL_MODE_TOSLINK)
1829         return -1;
1830
1831     if (getDeviceGeneration()!=MOTU_DEVICE_G3 && port_a_mode==MOTU_OPTICAL_MODE_KEEP)
1832         return 0;
1833
1834     if (m_motu_model == MOTU_MODEL_828MkI) {
1835         // The earlier MOTUs handle this differently.
1836         unsigned int mask, shift, g1mode = 0;
1837         reg = ReadRegister(MOTU_G1_REG_CONFIG);
1838         mask = (dir==MOTU_DIR_IN)?MOTU_G1_OPT_IN_MODE_MASK:MOTU_G1_OPT_OUT_MODE_MASK;
1839         shift = (dir==MOTU_DIR_IN)?MOTU_G1_OPT_IN_MODE_BIT0:MOTU_G1_OPT_OUT_MODE_BIT0;
1840         switch (port_a_mode) {
1841             case MOTU_OPTICAL_MODE_OFF: g1mode = MOTU_G1_OPTICAL_OFF; break;
1842             case MOTU_OPTICAL_MODE_ADAT: g1mode = MOTU_G1_OPTICAL_ADAT; break;
1843             // See comment in getOpticalMode() about mode ambiguity
1844             // case MOTU_OPTICAL_MODE_TOSLINK: g1mode = MOTU_G1_OPTICAL_TOSLINK; break;
1845         }
1846         reg = (reg & ~mask) | (g1mode << shift);
1847         return WriteRegister(MOTU_G1_REG_CONFIG, reg);
1848     }
1849
1850     /* The G3 devices are also quite a bit different to the G2 units */
1851     if (getDeviceGeneration() == MOTU_DEVICE_G3) {
1852         unsigned int mask, enable, toslink;
1853         reg = ReadRegister(MOTU_G3_REG_OPTICAL_CTRL);
1854         if (port_a_mode != MOTU_OPTICAL_MODE_KEEP) {
1855             mask = enable = toslink = 0;
1856             if (dir & MOTU_DIR_IN) {
1857                  mask |= MOTU_G3_OPT_A_IN_MASK;
1858                  enable |= MOTU_G3_OPT_A_IN_ENABLE;
1859                  toslink |= MOTU_G3_OPT_A_IN_TOSLINK;
1860             }
1861             if (dir & MOTU_DIR_OUT) {
1862                  mask |= MOTU_G3_OPT_A_OUT_MASK;
1863                  enable |= MOTU_G3_OPT_A_OUT_ENABLE;
1864                  toslink |= MOTU_G3_OPT_A_OUT_TOSLINK;
1865             }
1866             reg = (reg & ~mask) | enable;
1867             switch (port_a_mode) {
1868                 case MOTU_OPTICAL_MODE_OFF: reg &= ~enable; break;
1869                 case MOTU_OPTICAL_MODE_TOSLINK: reg |= toslink; break;
1870             }
1871         }
1872         if (port_b_mode != MOTU_OPTICAL_MODE_KEEP) {
1873             mask = enable = toslink = 0;
1874             if (dir & MOTU_DIR_IN) {
1875                  mask |= MOTU_G3_OPT_B_IN_MASK;
1876                  enable |= MOTU_G3_OPT_B_IN_ENABLE;
1877                  toslink |= MOTU_G3_OPT_B_IN_TOSLINK;
1878             }
1879             if (dir & MOTU_DIR_OUT) {
1880                  mask |= MOTU_G3_OPT_B_OUT_MASK;
1881                  enable |= MOTU_G3_OPT_B_OUT_ENABLE;
1882                  toslink |= MOTU_G3_OPT_B_OUT_TOSLINK;
1883             }
1884             reg = (reg & ~mask) | enable;
1885             switch (port_a_mode) {
1886                 case MOTU_OPTICAL_MODE_OFF: reg &= ~enable; break;
1887                 case MOTU_OPTICAL_MODE_TOSLINK: reg |= toslink; break;
1888             }
1889             reg = (reg & ~mask) | enable;
1890             switch (port_b_mode) {
1891                 case MOTU_OPTICAL_MODE_OFF: reg &= ~enable; break;
1892                 case MOTU_OPTICAL_MODE_TOSLINK: reg |= toslink; break;
1893             }
1894         }
1895         return WriteRegister(MOTU_G3_REG_OPTICAL_CTRL, reg);
1896     }
1897
1898     reg = ReadRegister(MOTU_REG_ROUTE_PORT_CONF);
1899
1900     // Map from user mode to values sent to the device registers.
1901     g2mode = 0;
1902     switch (port_a_mode) {
1903         case MOTU_OPTICAL_MODE_OFF: g2mode = MOTU_G2_OPTICAL_MODE_OFF; break;
1904         case MOTU_OPTICAL_MODE_ADAT: g2mode = MOTU_G2_OPTICAL_MODE_ADAT; break;
1905         case MOTU_OPTICAL_MODE_TOSLINK: g2mode = MOTU_G2_OPTICAL_MODE_TOSLINK; break;
1906     }
1907
1908     // Set up the optical control register value according to the current
1909     // optical port modes.  At this stage it's not completely understood
1910     // what the "Optical control" register does, so the values it's set to
1911     // are more or less "magic" numbers.
1912     if ((reg & MOTU_G2_OPTICAL_IN_MODE_MASK) != (MOTU_G2_OPTICAL_MODE_ADAT<<MOTU_G2_OPTICAL_IN_MODE_BIT0))
1913         opt_ctrl |= 0x00000080;
1914     if ((reg & MOTU_G2_OPTICAL_OUT_MODE_MASK) != (MOTU_G2_OPTICAL_MODE_ADAT<<MOTU_G2_OPTICAL_OUT_MODE_BIT0))
1915         opt_ctrl |= 0x00000040;
1916
1917     if (dir & MOTU_DIR_IN) {
1918         reg &= ~MOTU_G2_OPTICAL_IN_MODE_MASK;
1919         reg |= (g2mode << MOTU_G2_OPTICAL_IN_MODE_BIT0) & MOTU_G2_OPTICAL_IN_MODE_MASK;
1920         if (g2mode != MOTU_G2_OPTICAL_MODE_ADAT)
1921             opt_ctrl |= 0x00000080;
1922         else
1923             opt_ctrl &= ~0x00000080;
1924     }
1925     if (dir & MOTU_DIR_OUT) {
1926         reg &= ~MOTU_G2_OPTICAL_OUT_MODE_MASK;
1927         reg |= (g2mode << MOTU_G2_OPTICAL_OUT_MODE_BIT0) & MOTU_G2_OPTICAL_OUT_MODE_MASK;
1928         if (g2mode != MOTU_G2_OPTICAL_MODE_ADAT)
1929             opt_ctrl |= 0x00000040;
1930         else
1931             opt_ctrl &= ~0x00000040;
1932     }
1933
1934     /* Setting bit 25 in the route/port configuration register enables the
1935      * setting of the optical mode.  Bit 24 allows the phones assign to be
1936      * set using the lower 8 bits of the register.  This function has no
1937      * business setting that, so make sure bit 24 is masked off.
1938      */
1939     reg |= 0x02000000;
1940     reg &= ~0x01000000;
1941
1942     // FIXME: there seems to be more to it than this, but for
1943     // the moment at least this seems to work.
1944     WriteRegister(MOTU_REG_ROUTE_PORT_CONF, reg);
1945     return WriteRegister(MOTU_REG_OPTICAL_CTRL, opt_ctrl);
1946 }
1947
1948 signed int MotuDevice::getEventSize(unsigned int direction) {
1949 //
1950 // Return the size in bytes of a single event sent to (dir==MOTU_OUT) or
1951 // from (dir==MOTU_IN) the MOTU as part of an iso data packet.
1952 //
1953 // FIXME: for performance it may turn out best to calculate the event
1954 // size in setOpticalMode and cache the result in a data field.  However,
1955 // as it stands this will not adapt to dynamic changes in sample rate - we'd
1956 // need a setFrameRate() for that.
1957 //
1958 // At the very least an event consists of the SPH (4 bytes) and the control/MIDI
1959 // bytes (6 bytes).
1960 // Note that all audio channels are sent using 3 bytes.
1961 signed int sample_rate = getSamplingFrequency();
1962 unsigned int optical_mode_a, optical_mode_b;
1963 signed int size = 4+6;
1964
1965 unsigned int i;
1966 unsigned int dir = direction==Streaming::Port::E_Capture?MOTU_PA_IN:MOTU_PA_OUT;
1967 unsigned int flags = 0;
1968 unsigned int port_flags;
1969 const DevicePropertyEntry *devprop = &DevicesProperty[m_motu_model-1];
1970
1971     getOpticalMode(direction, &optical_mode_a, &optical_mode_b);
1972
1973     if ( sample_rate > 96000 )
1974         flags |= MOTU_PA_RATE_4x;
1975     else if ( sample_rate > 48000 )
1976         flags |= MOTU_PA_RATE_2x;
1977     else
1978         flags |= MOTU_PA_RATE_1x;
1979
1980     switch (optical_mode_a) {
1981         case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_OPTICAL_ANY; break;
1982         case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_OPTICAL_OFF; break;
1983         case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_OPTICAL_ADAT; break;
1984         case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_OPTICAL_TOSLINK; break;
1985     }
1986     switch (optical_mode_b) {
1987         case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_MK3_OPT_B_ANY; break;
1988         case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_MK3_OPT_B_OFF; break;
1989         case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_MK3_OPT_B_ADAT; break;
1990         case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_MK3_OPT_B_TOSLINK; break;
1991     }
1992
1993     // Don't test for padding port flag here since we need to include such
1994     // pseudo-ports when calculating the event size.
1995 #ifndef USE_PORTGROUPS
1996     for (i=0; i < devprop->n_port_entries; i++) {
1997         port_flags = devprop->port_entry[i].port_flags;
1998         /* Make sure the optical port tests return true for devices without
1999          * one or both optical ports.
2000          */
2001         if (optical_mode_a == MOTU_OPTICAL_MODE_NONE) {
2002             port_flags |= MOTU_PA_OPTICAL_ANY;
2003         }
2004         if (optical_mode_b == MOTU_OPTICAL_MODE_NONE) {
2005             port_flags |= MOTU_PA_MK3_OPT_B_ANY;
2006         }
2007         if (( port_flags & dir ) &&
2008            ( port_flags & MOTU_PA_RATE_MASK & flags ) &&
2009            ( port_flags & MOTU_PA_MK3_OPT_B_MASK & flags ) &&
2010            ( port_flags & MOTU_PA_OPTICAL_MASK & flags )) {
2011             size += 3;
2012         }
2013     }
2014 #else
2015     for (i=0; i<devprop->n_portgroup_entries; i++) {
2016         unsigned int portgroup_flags = devprop->portgroup_entry[i].flags;
2017         /* For devices without one or more optical ports, ensure the tests
2018          * on the optical ports always returns "true".
2019          */
2020         if (optical_a_mode == MOTU_OPTICAL_MODE_NONE) {
2021             portgroup_flags |= MOTU_PA_OPTICAL_ANY;
2022         }
2023         if (optical_b_mode == MOTU_OPTICAL_MODE_NONE) {
2024             portgroup_flags |= MOTU_PA_MK3_OPT_B_ANY;
2025         }
2026         if (( portgroup_flags & dir ) &&
2027             ( portgroup_flags & MOTU_PA_RATE_MASK & flags ) &&
2028             ( portgroup_flags & MOTU_PA_OPTICAL_MASK & flags ) &&
2029             ( portgroup_flags & MOTU_PA_MK3_OPT_B_MASK & flags )) {
2030             size += 3*devprop->portgroup_entry[i].n_channels;
2031         }
2032     }
2033 #endif
2034
2035     // Finally round size up to the next quadlet boundary
2036     return ((size+3)/4)*4;
2037 }
2038 /* ======================================================================= */
2039
2040 bool MotuDevice::addPort(Streaming::StreamProcessor *s_processor,
2041   char *name, enum Streaming::Port::E_Direction direction,
2042   int position, int size) {
2043 /*
2044  * Internal helper function to add a MOTU port to a given stream processor.
2045  * This just saves the unnecessary replication of what is essentially
2046  * boilerplate code.  Note that the port name is freed by this function
2047  * prior to exit.
2048  */
2049 Streaming::Port *p=NULL;
2050
2051     p = new Streaming::MotuAudioPort(*s_processor, name, direction, position, size);
2052
2053     if (!p) {
2054         debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",name);
2055     }
2056     free(name);
2057     return true;
2058 }
2059 /* ======================================================================= */
2060
2061 bool MotuDevice::addDirPorts(
2062   enum Streaming::Port::E_Direction direction, unsigned int sample_rate,
2063   unsigned int optical_a_mode, unsigned int optical_b_mode) {
2064 /*
2065  * Internal helper method: adds all required ports for the given direction
2066  * based on the indicated sample rate and optical mode.
2067  *
2068  * Notes: currently ports are not created if they are disabled due to sample
2069  * rate or optical mode.  However, it might be better to unconditionally
2070  * create all ports and just disable those which are not active.
2071  */
2072 const char *mode_str = direction==Streaming::Port::E_Capture?"cap":"pbk";
2073 Streaming::StreamProcessor *s_processor;
2074 unsigned int i;
2075 char *buff;
2076 unsigned int dir = direction==Streaming::Port::E_Capture?MOTU_PA_IN:MOTU_PA_OUT;
2077 unsigned int flags = 0;
2078 unsigned int port_flags;
2079
2080
2081     if ( sample_rate > 96000 )
2082         flags |= MOTU_PA_RATE_4x;
2083     else if ( sample_rate > 48000 )
2084         flags |= MOTU_PA_RATE_2x;
2085     else
2086         flags |= MOTU_PA_RATE_1x;
2087
2088     switch (optical_a_mode) {
2089         case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_OPTICAL_ANY; break;
2090         case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_OPTICAL_OFF; break;
2091         case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_OPTICAL_ADAT; break;
2092         case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_OPTICAL_TOSLINK; break;
2093     }
2094     switch (optical_b_mode) {
2095         case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_MK3_OPT_B_ANY; break;
2096         case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_MK3_OPT_B_OFF; break;
2097         case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_MK3_OPT_B_ADAT; break;
2098         case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_MK3_OPT_B_TOSLINK; break;
2099     }
2100
2101     // retrieve the ID
2102     std::string id=std::string("dev?");
2103     if(!getOption("id", id)) {
2104         debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n");
2105     }
2106
2107     if (direction == Streaming::Port::E_Capture) {
2108         s_processor = m_receiveProcessor;
2109     } else {
2110         s_processor = m_transmitProcessor;
2111     }
2112
2113     for (i=0; i < DevicesProperty[m_motu_model-1].n_port_entries; i++) {
2114         port_flags = DevicesProperty[m_motu_model-1].port_entry[i].port_flags;
2115         /* For devices without one or more optical ports, ensure the tests
2116          * on the optical ports always returns "true".
2117          */
2118         if (optical_a_mode == MOTU_OPTICAL_MODE_NONE)
2119             port_flags |= MOTU_PA_OPTICAL_ANY;
2120         if (optical_b_mode == MOTU_OPTICAL_MODE_NONE)
2121             port_flags |= MOTU_PA_MK3_OPT_B_ANY;
2122
2123         if (( port_flags & dir ) &&
2124            ( port_flags & MOTU_PA_RATE_MASK & flags ) &&
2125            ( port_flags & MOTU_PA_OPTICAL_MASK & flags ) &&
2126            ( port_flags & MOTU_PA_MK3_OPT_B_MASK & flags ) &&
2127            !( port_flags & MOTU_PA_PADDING )) {
2128             asprintf(&buff,"%s_%s_%s" , id.c_str(), mode_str,
2129               DevicesProperty[m_motu_model-1].port_entry[i].port_name);
2130             if (!addPort(s_processor, buff, direction, DevicesProperty[m_motu_model-1].port_entry[i].port_offset, 0))
2131                 return false;
2132         }
2133     }
2134    
2135     return true;
2136 }
2137 /* ======================================================================= */
2138
2139 bool MotuDevice::addDirPortGroups(
2140   enum Streaming::Port::E_Direction direction, unsigned int sample_rate,
2141   unsigned int optical_a_mode, unsigned int optical_b_mode) {
2142 /*
2143  * Internal helper method.  Using a PortGroupEntry array the locations
2144  * of channels within a packet is deduced based on the given sample rate
2145  * and optical port modes.  Locations within the packet start at 10
2146  * and are incremented by 3 for each subsequent channel.  Channel are assumed
2147  * to be ordered in the packet as they are in the port group array.
2148  *
2149  * The port_order field of a port group entry allows the order of port
2150  * creation to be varied.  This is helpful if it's more convenient to have a
2151  * particular port show up first in jackd even through it's located in the
2152  * middle of the packet.  If the port_order field of the first port group is
2153  * -1 it is assumed that the port creation is to happen in the order
2154  * specified in the port group list.
2155  *
2156  * Notes: currently ports are not created if they are disabled due to sample
2157  * rate or optical mode.  However, it might be better to unconditionally
2158  * create all ports and just disable those which are not active.
2159  */
2160 const char *mode_str = direction==Streaming::Port::E_Capture?"cap":"pbk";
2161 Streaming::StreamProcessor *s_processor;
2162 signed int i;
2163 char *buff;
2164 unsigned int dir = direction==Streaming::Port::E_Capture?MOTU_PA_IN:MOTU_PA_OUT;
2165 unsigned int flags = 0;
2166 unsigned int portgroup_flags;
2167 signed int pkt_ofs = 10;       /* Port data starts at offset 10 */
2168 const DevicePropertyEntry *devprop = &DevicesProperty[m_motu_model-1];
2169 signed int n_groups = devprop->n_portgroup_entries;
2170 signed int creation_indices[n_groups];
2171 signed int create_in_order;
2172
2173     if (n_groups <= 0)
2174         return true;
2175
2176     if ( sample_rate > 96000 )
2177         flags |= MOTU_PA_RATE_4x;
2178     else if ( sample_rate > 48000 )
2179         flags |= MOTU_PA_RATE_2x;
2180     else
2181         flags |= MOTU_PA_RATE_1x;
2182
2183     switch (optical_a_mode) {
2184         case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_OPTICAL_ANY; break;
2185         case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_OPTICAL_OFF; break;
2186         case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_OPTICAL_ADAT; break;
2187         case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_OPTICAL_TOSLINK; break;
2188     }
2189     switch (optical_b_mode) {
2190         case MOTU_OPTICAL_MODE_NONE: flags |= MOTU_PA_MK3_OPT_B_ANY; break;
2191         case MOTU_OPTICAL_MODE_OFF: flags |= MOTU_PA_MK3_OPT_B_OFF; break;
2192         case MOTU_OPTICAL_MODE_ADAT: flags |= MOTU_PA_MK3_OPT_B_ADAT; break;
2193         case MOTU_OPTICAL_MODE_TOSLINK: flags |= MOTU_PA_MK3_OPT_B_TOSLINK; break;
2194     }
2195
2196     // retrieve the ID
2197     std::string id=std::string("dev?");
2198     if(!getOption("id", id)) {
2199         debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n");
2200     }
2201
2202     if (direction == Streaming::Port::E_Capture) {
2203         s_processor = m_receiveProcessor;
2204     } else {
2205         s_processor = m_transmitProcessor;
2206     }
2207
2208     for (i=0; i<n_groups; i++) {
2209       creation_indices[i] = -1;
2210     }
2211     create_in_order = devprop->portgroup_entry[0].port_order<0;
2212
2213     /* First scan through the port groups, allocating packet offsets for all
2214      * port groups which are found to be active in the device's current state.
2215      */
2216     for (i=0; i<n_groups; i++) {
2217         portgroup_flags = devprop->portgroup_entry[i].flags;
2218         /* For devices without one or more optical ports, ensure the tests
2219          * on the optical ports always returns "true".
2220          */
2221         if (optical_a_mode == MOTU_OPTICAL_MODE_NONE)
2222             portgroup_flags |= MOTU_PA_OPTICAL_ANY;
2223         if (optical_b_mode == MOTU_OPTICAL_MODE_NONE)
2224             portgroup_flags |= MOTU_PA_MK3_OPT_B_ANY;
2225
2226         devprop->portgroup_entry[i].group_pkt_offset = -1;
2227         if (( portgroup_flags & dir ) &&
2228             ( portgroup_flags & MOTU_PA_RATE_MASK & flags ) &&
2229             ( portgroup_flags & MOTU_PA_OPTICAL_MASK & flags ) &&
2230             ( portgroup_flags & MOTU_PA_MK3_OPT_B_MASK & flags )) {
2231             if ((portgroup_flags & MOTU_PA_PADDING) == 0) {
2232                 devprop->portgroup_entry[i].group_pkt_offset = pkt_ofs;
2233                 if (create_in_order)
2234                     creation_indices[i] = i;
2235                 else
2236                     creation_indices[devprop->portgroup_entry[i].port_order] = i;
2237             }
2238             pkt_ofs += 3*devprop->portgroup_entry[i].n_channels;
2239         }
2240     }
2241
2242     /* Now run through the portgroup list again, this time in creation order,
2243      * to make the ports.
2244      */
2245     for (i=0; i<n_groups; i++) {
2246         char namestr[64];
2247         signed int ch;
2248         signed int entry;
2249         if (creation_indices[i] < 0)
2250             continue;
2251         entry = creation_indices[i];
2252         for (ch=0; ch<devprop->portgroup_entry[entry].n_channels; ch++) {
2253             /* Deduce the full channel name */
2254             if (strstr(devprop->portgroup_entry[entry].group_name_format, "%d") != NULL)
2255                 snprintf(namestr, sizeof(namestr), devprop->portgroup_entry[entry].group_name_format,
2256                 ch+1+devprop->portgroup_entry[entry].port_num_offset);
2257             else
2258             if (strstr(devprop->portgroup_entry[entry].group_name_format, "%s") != NULL)
2259                 snprintf(namestr, sizeof(namestr), devprop->portgroup_entry[entry].group_name_format,
2260                          (ch & 0x1)?"R":"L");
2261             else
2262                 snprintf(namestr, sizeof(namestr), "%s", devprop->portgroup_entry[entry].group_name_format);
2263             asprintf(&buff,"%s_%s_%s" , id.c_str(), mode_str, namestr);
2264             if (!addPort(s_processor, buff, direction,
2265                    devprop->portgroup_entry[entry].group_pkt_offset+3*ch, 0))
2266                 return false;
2267         }
2268     }
2269
2270     return true;
2271 }
2272 /* ======================================================================== */
2273
2274 unsigned int MotuDevice::ReadRegister(fb_nodeaddr_t reg) {
2275 /*
2276  * Attempts to read the requested register from the MOTU.
2277  */
2278
2279     quadlet_t quadlet = 0;
2280
2281     /* If the supplied register has no upper bits set assume it's a G1/G2
2282      * register which is assumed to be relative to MOTU_REG_BASE_ADDR.
2283      */
2284     if ((reg & MOTU_REG_BASE_ADDR) == 0)
2285         reg |= MOTU_REG_BASE_ADDR;
2286
2287     // Note: 1394Service::read() expects a physical ID, not the node id
2288     if (get1394Service().read(0xffc0 | getNodeId(), reg, 1, &quadlet) <= 0) {
2289         debugError("Error doing motu read from register 0x%012llx\n",reg);
2290     }
2291
2292     return CondSwapFromBus32(quadlet);
2293 }
2294
2295 signed int MotuDevice::WriteRegister(fb_nodeaddr_t reg, quadlet_t data) {
2296 /*
2297  * Attempts to write the given data to the requested MOTU register.
2298  */
2299
2300     unsigned int err = 0;
2301     data = CondSwapToBus32(data);
2302
2303     /* If the supplied register has no upper bits set assume it's a G1/G2
2304      * register which is assumed to be relative to MOTU_REG_BASE_ADDR.
2305      */
2306     if ((reg & MOTU_REG_BASE_ADDR) == 0)
2307         reg |= MOTU_REG_BASE_ADDR;
2308
2309     // Note: 1394Service::write() expects a physical ID, not the node id
2310     if (get1394Service().write(0xffc0 | getNodeId(), reg, 1, &data) <= 0) {
2311         err = 1;
2312         debugError("Error doing motu write to register 0x%012llx\n",reg);
2313     }
2314
2315     SleepRelativeUsec(100);
2316     return (err==0)?0:-1;
2317 }
2318
2319 }
Note: See TracBrowser for help on using the browser.