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

Revision 848, 35.2 kB (checked in by jwoithe, 14 years ago)

Remove duplicate SPDIF entries in Ultralite port definitions which used the offsets of the main-outs.

Line 
1 /*
2  * Copyright (C) 2005-2007 by Pieter Palmers
3  * Copyright (C) 2005-2007 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 3 of the License, or
13  * (at your option) any later version.
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 "motu/motu_avdevice.h"
26
27 #include "libieee1394/configrom.h"
28 #include "libieee1394/ieee1394service.h"
29
30 #include "libavc/avc_definitions.h"
31
32 #include "debugmodule/debugmodule.h"
33
34 #include "libstreaming/motu/MotuReceiveStreamProcessor.h"
35 #include "libstreaming/motu/MotuTransmitStreamProcessor.h"
36 #include "libstreaming/motu/MotuPort.h"
37
38 #include "libutil/DelayLockedLoop.h"
39 #include "libutil/Time.h"
40
41 #include <string>
42 #include <stdint.h>
43 #include <assert.h>
44 #include <netinet/in.h>
45 #include <iostream>
46 #include <sstream>
47
48 #include <libraw1394/csr.h>
49
50 namespace Motu {
51
52 // to define the supported devices
53 static VendorModelEntry supportedDeviceList[] =
54 {
55 //  {vendor_id, model_id, unit_version, unit_specifier_id, model, vendor_name,model_name}
56     {FW_VENDORID_MOTU, 0, 0x00000003, 0x000001f2, MOTUFW_MODEL_828mkII, "MOTU", "828MkII"},
57     {FW_VENDORID_MOTU, 0, 0x00000009, 0x000001f2, MOTUFW_MODEL_TRAVELER, "MOTU", "Traveler"},
58     {FW_VENDORID_MOTU, 0, 0x0000000d, 0x000001f2, MOTUFW_MODEL_ULTRALITE, "MOTU", "UltraLite"},
59     {FW_VENDORID_MOTU, 0, 0x0000000f, 0x000001f2, MOTUFW_MODEL_8PRE, "MOTU", "8pre"},
60 };
61
62 // Ports declarations
63 const PortEntry Ports_828MKII[] =
64 {
65     {"Main-L", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 40},
66     {"Main-R", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 43},
67     {"Mix-L", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 10},
68     {"Mix-R", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 13},
69     {"Analog1", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 16},
70     {"Analog2", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 19},
71     {"Analog3", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 22},
72     {"Analog4", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 25},
73     {"Analog5", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 28},
74     {"Analog6", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 31},
75     {"Analog7", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 34},
76     {"Analog8", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 37},
77     {"Phones-L", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 10},
78     {"Phones-R", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 13},
79     {"Mic1", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 40},
80     {"Mic2", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 43},
81     {"SPDIF1", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 46},
82     {"SPDIF2", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 49},
83     {"ADAT1", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 52},
84     {"ADAT2", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 55},
85     {"ADAT3", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 58},
86     {"ADAT4", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 61},
87     {"ADAT5", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x|MOTUFW_PA_OPTICAL_ADAT, 63},
88     {"ADAT6", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x|MOTUFW_PA_OPTICAL_ADAT, 66},
89     {"ADAT7", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x|MOTUFW_PA_OPTICAL_ADAT, 69},
90     {"ADAT8", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x|MOTUFW_PA_OPTICAL_ADAT, 72},
91 };
92
93 const PortEntry Ports_TRAVELER[] =
94 {
95     {"Mix-L", MOTUFW_DIR_IN, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_ANY, 10},
96     {"Mix-R", MOTUFW_DIR_IN, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_ANY, 13},
97     {"Phones-L", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_ANY, 10},
98     {"Phones-R", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_ANY, 13},
99     {"Analog1", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 16},
100     {"Analog2", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 19},
101     {"Analog3", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 22},
102     {"Analog4", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 25},
103     {"Analog5", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 28},
104     {"Analog6", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 31},
105     {"Analog7", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 34},
106     {"Analog8", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 37},
107     {"AES/EBU1", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_ANY, 40},
108     {"AES/EBU2", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_ANY, 43},
109     {"SPDIF1", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_OFF|MOTUFW_PA_OPTICAL_ADAT, 46},
110     {"SPDIF2", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_OFF|MOTUFW_PA_OPTICAL_ADAT, 49},
111     {"Toslink1", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_TOSLINK, 46},
112     {"Toslink2", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_TOSLINK, 49},
113     {"ADAT1", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_ADAT, 52},
114     {"ADAT2", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_ADAT, 55},
115     {"ADAT3", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_ADAT, 58},
116     {"ADAT4", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x2x|MOTUFW_PA_OPTICAL_ADAT, 61},
117     {"ADAT5", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x|MOTUFW_PA_OPTICAL_ADAT, 63},
118     {"ADAT6", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x|MOTUFW_PA_OPTICAL_ADAT, 66},
119     {"ADAT7", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x|MOTUFW_PA_OPTICAL_ADAT, 69},
120     {"ADAT8", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_1x|MOTUFW_PA_OPTICAL_ADAT, 72},
121 };
122
123 const PortEntry Ports_ULTRALITE[] =
124 {
125     {"Main-L", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 40},
126     {"Main-R", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 43},
127     {"Mix-L", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 10},
128     {"Mix-R", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 13},
129     {"Mic1", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 16},
130     {"Mic2", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 19},
131     {"Analog1", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 16},
132     {"Analog2", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 19},
133     {"Analog3", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 22},
134     {"Analog4", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 25},
135     {"Analog5", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 28},
136     {"Analog6", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 31},
137     {"Analog7", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 34},
138     {"Analog8", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 37},
139     {"Phones-L", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 10},
140     {"Phones-R", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 13},
141     {"SPDIF1", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 46},
142     {"SPDIF2", MOTUFW_DIR_INOUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 49},
143 };
144
145 const PortEntry Ports_8PRE[] =
146 {
147     {"Analog1", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 16},
148     {"Analog2", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 19},
149     {"Analog3", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 22},
150     {"Analog4", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 25},
151     {"Analog5", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 28},
152     {"Analog6", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 31},
153     {"Analog7", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 34},
154     {"Analog8", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 37},
155     {"Mix-L", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 10},
156     {"Mix-R", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 13},
157     {"Main-L", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 16},
158     {"Main-R", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 19},
159     {"Phones-L", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 10},
160     {"Phones-R", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ANY, 13},
161     {"ADAT1", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 40},
162     {"ADAT1", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 22},
163     {"ADAT2", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 43},
164     {"ADAT2", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 25},
165     {"ADAT3", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 46},
166     {"ADAT3", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 28},
167     {"ADAT4", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 49},
168     {"ADAT4", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 31},
169     {"ADAT5", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 52},
170     {"ADAT5", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 34},
171     {"ADAT6", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 55},
172     {"ADAT6", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 37},
173     {"ADAT7", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 58},
174     {"ADAT7", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 40},
175     {"ADAT8", MOTUFW_DIR_IN, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 61},
176     {"ADAT8", MOTUFW_DIR_OUT, MOTUFW_PA_RATE_ANY|MOTUFW_PA_OPTICAL_ADAT, 43},
177 };
178
179 const DevicePropertyEntry DevicesProperty[] = {
180 //  { Ports_map,       sizeof( Ports_map ),        MaxSR },
181     { Ports_828MKII,   sizeof( Ports_828MKII ),    96000 },
182     { Ports_TRAVELER,  sizeof( Ports_TRAVELER ),  192000 },
183     { Ports_ULTRALITE, sizeof( Ports_ULTRALITE ),  96000 },
184     { Ports_8PRE,      sizeof( Ports_8PRE ),       96000 },
185 };
186
187 MotuDevice::MotuDevice( DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
188     : FFADODevice( d, configRom )
189     , m_motu_model( MOTUFW_MODEL_NONE )
190     , m_iso_recv_channel ( -1 )
191     , m_iso_send_channel ( -1 )
192     , m_rx_bandwidth ( -1 )
193     , m_tx_bandwidth ( -1 )
194     , m_receiveProcessor ( 0 )
195     , m_transmitProcessor ( 0 )
196
197 {
198     debugOutput( DEBUG_LEVEL_VERBOSE, "Created Motu::MotuDevice (NodeID %d)\n",
199                  getConfigRom().getNodeId() );
200
201 }
202
203 MotuDevice::~MotuDevice()
204 {
205     delete m_receiveProcessor;
206     delete m_transmitProcessor;
207
208     // Free ieee1394 bus resources if they have been allocated
209     if (m_iso_recv_channel>=0 && !get1394Service().freeIsoChannel(m_iso_recv_channel)) {
210         debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free recv iso channel %d\n", m_iso_recv_channel);
211     }
212     if (m_iso_send_channel>=0 && !get1394Service().freeIsoChannel(m_iso_send_channel)) {
213         debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free send iso channel %d\n", m_iso_send_channel);
214     }
215 }
216
217 bool
218 MotuDevice::probe( ConfigRom& configRom )
219 {
220     unsigned int vendorId = configRom.getNodeVendorId();
221 //     unsigned int modelId = configRom.getModelId();
222     unsigned int unitVersion = configRom.getUnitVersion();
223     unsigned int unitSpecifierId = configRom.getUnitSpecifierId();
224
225     for ( unsigned int i = 0;
226           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
227           ++i )
228     {
229         if ( ( supportedDeviceList[i].vendor_id == vendorId )
230 //              && ( supportedDeviceList[i].model_id == modelId )
231              && ( supportedDeviceList[i].unit_version == unitVersion )
232              && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
233            )
234         {
235             return true;
236         }
237     }
238
239     return false;
240 }
241
242 FFADODevice *
243 MotuDevice::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
244 {
245     return new MotuDevice(d, configRom);
246 }
247
248 bool
249 MotuDevice::discover()
250 {
251     unsigned int vendorId = getConfigRom().getNodeVendorId();
252 //     unsigned int modelId = getConfigRom().getModelId();
253     unsigned int unitVersion = getConfigRom().getUnitVersion();
254     unsigned int unitSpecifierId = getConfigRom().getUnitSpecifierId();
255
256     for ( unsigned int i = 0;
257           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
258           ++i )
259     {
260         if ( ( supportedDeviceList[i].vendor_id == vendorId )
261 //              && ( supportedDeviceList[i].model_id == modelId )
262              && ( supportedDeviceList[i].unit_version == unitVersion )
263              && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
264            )
265         {
266             m_model = &(supportedDeviceList[i]);
267             m_motu_model=supportedDeviceList[i].model;
268         }
269     }
270
271     if (m_model != NULL) {
272         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
273                 m_model->vendor_name, m_model->model_name);
274         return true;
275     }
276
277     return false;
278 }
279
280 int
281 MotuDevice::getSamplingFrequency( ) {
282 /*
283  * Retrieve the current sample rate from the MOTU device.
284  */
285     quadlet_t q = ReadRegister(MOTUFW_REG_CLK_CTRL);
286     int rate = 0;
287
288     switch (q & MOTUFW_RATE_BASE_MASK) {
289         case MOTUFW_RATE_BASE_44100:
290             rate = 44100;
291             break;
292         case MOTUFW_RATE_BASE_48000:
293             rate = 48000;
294             break;
295     }
296     switch (q & MOTUFW_RATE_MULTIPLIER_MASK) {
297         case MOTUFW_RATE_MULTIPLIER_2X:
298             rate *= 2;
299             break;
300         case MOTUFW_RATE_MULTIPLIER_4X:
301             rate *= 4;
302             break;
303     }
304     return rate;
305 }
306
307 int
308 MotuDevice::getConfigurationId()
309 {
310     return 0;
311 }
312
313 bool
314 MotuDevice::setSamplingFrequency( int samplingFrequency )
315 {
316 /*
317  * Set the MOTU device's samplerate.
318  */
319     char *src_name;
320     quadlet_t q, new_rate=0;
321     int i, supported=true, cancel_adat=false;
322
323     if ( samplingFrequency > DevicesProperty[m_motu_model-1].MaxSampleRate )
324        return false;
325
326     switch ( samplingFrequency ) {
327         case 22050:
328         case 24000:
329         case 32000:
330             supported=false;
331             break;
332         case 44100:
333             new_rate = MOTUFW_RATE_BASE_44100 | MOTUFW_RATE_MULTIPLIER_1X;
334             break;
335         case 48000:
336             new_rate = MOTUFW_RATE_BASE_48000 | MOTUFW_RATE_MULTIPLIER_1X;
337             break;
338         case 88200:
339             new_rate = MOTUFW_RATE_BASE_44100 | MOTUFW_RATE_MULTIPLIER_2X;
340             break;
341         case 96000:
342             new_rate = MOTUFW_RATE_BASE_48000 | MOTUFW_RATE_MULTIPLIER_2X;
343             break;
344         case 176400:
345             new_rate = MOTUFW_RATE_BASE_44100 | MOTUFW_RATE_MULTIPLIER_4X;
346             cancel_adat = true;  // current ADAT protocol doesn't support sample rate > 96000
347             break;
348         case 192000:
349             new_rate = MOTUFW_RATE_BASE_48000 | MOTUFW_RATE_MULTIPLIER_4X;
350             cancel_adat = true;
351             break;
352         default:
353             supported=false;
354     }
355
356     // Update the clock control register.  FIXME: while this is now rather
357     // comprehensive there may still be a need to manipulate MOTUFW_REG_CLK_CTRL
358     // a little more than we do.
359     if (supported) {
360         quadlet_t value=ReadRegister(MOTUFW_REG_CLK_CTRL);
361
362         // If optical port must be disabled (because a 4x sample rate has
363         // been selected) then do so before changing the sample rate.  At
364         // this stage it will be up to the user to re-enable the optical
365         // port if the sample rate is set to a 1x or 2x rate later.
366         if (cancel_adat) {
367             setOpticalMode(MOTUFW_DIR_INOUT, MOTUFW_OPTICAL_MODE_OFF);
368         }
369
370         value &= ~(MOTUFW_RATE_BASE_MASK|MOTUFW_RATE_MULTIPLIER_MASK);
371         value |= new_rate;
372
373         // In other OSes bit 26 of MOTUFW_REG_CLK_CTRL always seems
374         // to be set when this register is written to although the
375         // reason isn't currently known.  When we set it, it appears
376         // to prevent output being produced so we'll leave it unset
377         // until we work out what's going on.  Other systems write
378         // to MOTUFW_REG_CLK_CTRL multiple times, so that may be
379         // part of the mystery.
380         //   value |= 0x04000000;
381         if (WriteRegister(MOTUFW_REG_CLK_CTRL, value) == 0) {
382             supported=true;
383         } else {
384             supported=false;
385         }
386         // A write to the rate/clock control register requires the
387         // textual name of the current clock source be sent to the
388         // clock source name registers.
389         switch (value & MOTUFW_CLKSRC_MASK) {
390             case MOTUFW_CLKSRC_INTERNAL:
391                 src_name = "Internal        ";
392                 break;
393             case MOTUFW_CLKSRC_ADAT_OPTICAL:
394                 src_name = "ADAT Optical    ";
395                 break;
396             case MOTUFW_CLKSRC_SPDIF_TOSLINK:
397                 if (getOpticalMode(MOTUFW_DIR_IN)  == MOTUFW_OPTICAL_MODE_TOSLINK)
398                     src_name = "TOSLink         ";
399                 else
400                     src_name = "SPDIF           ";
401                 break;
402             case MOTUFW_CLKSRC_SMTPE:
403                 src_name = "SMPTE           ";
404                 break;
405             case MOTUFW_CLKSRC_WORDCLOCK:
406                 src_name = "Word Clock In   ";
407                 break;
408             case MOTUFW_CLKSRC_ADAT_9PIN:
409                 src_name = "ADAT 9-pin      ";
410                 break;
411             case MOTUFW_CLKSRC_AES_EBU:
412                 src_name = "AES-EBU         ";
413                 break;
414             default:
415                 src_name = "Unknown         ";
416         }
417         for (i=0; i<16; i+=4) {
418             q = (src_name[i]<<24) | (src_name[i+1]<<16) |
419                 (src_name[i+2]<<8) | src_name[i+3];
420             WriteRegister(MOTUFW_REG_CLKSRC_NAME0+i, q);
421         }
422     }
423     return supported;
424 }
425
426 FFADODevice::ClockSourceVector
427 MotuDevice::getSupportedClockSources() {
428     FFADODevice::ClockSourceVector r;
429     return r;
430 }
431
432 bool
433 MotuDevice::setActiveClockSource(ClockSource s) {
434     return false;
435 }
436
437 FFADODevice::ClockSource
438 MotuDevice::getActiveClockSource() {
439     ClockSource s;
440     return s;
441 }
442
443 bool
444 MotuDevice::lock() {
445
446     return true;
447 }
448
449
450 bool
451 MotuDevice::unlock() {
452
453     return true;
454 }
455
456 void
457 MotuDevice::showDevice()
458 {
459     debugOutput(DEBUG_LEVEL_VERBOSE,
460         "%s %s at node %d\n", m_model->vendor_name, m_model->model_name,
461         getNodeId());
462 }
463
464 bool
465 MotuDevice::prepare() {
466
467     int samp_freq = getSamplingFrequency();
468     unsigned int optical_in_mode = getOpticalMode(MOTUFW_DIR_IN);
469     unsigned int optical_out_mode = getOpticalMode(MOTUFW_DIR_OUT);
470     unsigned int event_size_in = getEventSize(MOTUFW_DIR_IN);
471     unsigned int event_size_out= getEventSize(MOTUFW_DIR_OUT);
472
473     debugOutput(DEBUG_LEVEL_NORMAL, "Preparing MotuDevice...\n" );
474
475     // Allocate bandwidth if not previously done.
476     // FIXME: The bandwidth allocation calculation can probably be
477     // refined somewhat since this is currently based on a rudimentary
478     // understanding of the ieee1394 iso protocol.
479     // Currently we assume the following.
480     //   * Ack/iso gap = 0.05 us
481     //   * DATA_PREFIX = 0.16 us
482     //   * DATA_END    = 0.26 us
483     // These numbers are the worst-case figures given in the ieee1394
484     // standard.  This gives approximately 0.5 us of overheads per packet -
485     // around 25 bandwidth allocation units (from the ieee1394 standard 1
486     // bandwidth allocation unit is 125/6144 us).  We further assume the
487     // MOTU is running at S400 (which it should be) so one allocation unit
488     // is equivalent to 1 transmitted byte; thus the bandwidth allocation
489     // required for the packets themselves is just the size of the packet.
490     // We used to allocate based on the maximum packet size (1160 bytes at
491     // 192 kHz for the traveler) but now do this based on the actual device
492     // state by utilising the result from getEventSize() and remembering
493     // that each packet has an 8 byte CIP header.  Note that bandwidth is
494     // allocated on a *per stream* basis - it must be allocated for both the
495     // transmit and receive streams.  While most MOTU modules are close to
496     // symmetric in terms of the number of in/out channels there are
497     // exceptions, so we deal with receive and transmit bandwidth separately.
498     signed int n_events_per_packet = samp_freq<=48000?8:(samp_freq<=96000?16:32);
499     m_rx_bandwidth = 25 + (n_events_per_packet*event_size_in);
500     m_tx_bandwidth = 25 + (n_events_per_packet*event_size_out);
501
502     // Assign iso channels if not already done
503     if (m_iso_recv_channel < 0)
504         m_iso_recv_channel = get1394Service().allocateIsoChannelGeneric(m_rx_bandwidth);
505
506     if (m_iso_send_channel < 0)
507         m_iso_send_channel = get1394Service().allocateIsoChannelGeneric(m_tx_bandwidth);
508
509     debugOutput(DEBUG_LEVEL_VERBOSE, "recv channel = %d, send channel = %d\n",
510         m_iso_recv_channel, m_iso_send_channel);
511
512     if (m_iso_recv_channel<0 || m_iso_send_channel<0) {
513         // be nice and deallocate
514         if (m_iso_recv_channel >= 0)
515             get1394Service().freeIsoChannel(m_iso_recv_channel);
516         if (m_iso_send_channel >= 0)
517             get1394Service().freeIsoChannel(m_iso_send_channel);
518
519         debugFatal("Could not allocate iso channels!\n");
520         return false;
521     }
522
523     m_receiveProcessor=new Streaming::MotuReceiveStreamProcessor(*this, event_size_in);
524
525     // The first thing is to initialize the processor.  This creates the
526     // data structures.
527     if(!m_receiveProcessor->init()) {
528         debugFatal("Could not initialize receive processor!\n");
529         return false;
530     }
531     m_receiveProcessor->setVerboseLevel(getDebugLevel());
532
533     // Now we add ports to the processor
534     debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to receive processor\n");
535
536     char *buff;
537     Streaming::Port *p=NULL;
538
539     // retrieve the ID
540     std::string id=std::string("dev?");
541     if(!getOption("id", id)) {
542         debugWarning("Could not retrieve id parameter, defauling to 'dev?'\n");
543     }
544
545     // Add audio capture ports
546     if (!addDirPorts(Streaming::Port::E_Capture, samp_freq, optical_in_mode)) {
547         return false;
548     }
549
550     // Add MIDI port.  The MOTU only has one MIDI input port, with each
551     // MIDI byte sent using a 3 byte sequence starting at byte 4 of the
552     // event data.
553     asprintf(&buff,"%s_cap_MIDI0",id.c_str());
554     p = new Streaming::MotuMidiPort(*m_receiveProcessor, buff,
555         Streaming::Port::E_Capture, 4);
556     if (!p) {
557         debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n", buff);
558     }
559     free(buff);
560
561     // example of adding an control port:
562 //    asprintf(&buff,"%s_cap_%s",id.c_str(),"myportnamehere");
563 //    p=new Streaming::MotuControlPort(
564 //            buff,
565 //            Streaming::Port::E_Capture,
566 //            0 // you can add all other port specific stuff you
567 //              // need to pass by extending MotuXXXPort and MotuPortInfo
568 //    );
569 //    free(buff);
570 //
571 //    if (!p) {
572 //        debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
573 //    } else {
574 //
575 //        if (!m_receiveProcessor->addPort(p)) {
576 //            debugWarning("Could not register port with stream processor\n");
577 //            return false;
578 //        } else {
579 //            debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
580 //        }
581 //    }
582
583     // Do the same for the transmit processor
584     m_transmitProcessor=new Streaming::MotuTransmitStreamProcessor(*this, event_size_out);
585
586     m_transmitProcessor->setVerboseLevel(getDebugLevel());
587
588     if(!m_transmitProcessor->init()) {
589         debugFatal("Could not initialize transmit processor!\n");
590         return false;
591     }
592
593     // Now we add ports to the processor
594     debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to transmit processor\n");
595
596     // Add audio playback ports
597     if (!addDirPorts(Streaming::Port::E_Playback, samp_freq, optical_out_mode)) {
598         return false;
599     }
600
601     // Add MIDI port.  The MOTU only has one output MIDI port, with each
602     // MIDI byte transmitted using a 3 byte sequence starting at byte 4
603     // of the event data.
604     asprintf(&buff,"%s_pbk_MIDI0",id.c_str());
605     p = new Streaming::MotuMidiPort(*m_transmitProcessor, buff,
606         Streaming::Port::E_Capture, 4);
607     if (!p) {
608         debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n", buff);
609     }
610     free(buff);
611
612     // example of adding an control port:
613 //    asprintf(&buff,"%s_pbk_%s",id.c_str(),"myportnamehere");
614 //
615 //    p=new Streaming::MotuControlPort(
616 //            buff,
617 //            Streaming::Port::E_Playback,
618 //            0 // you can add all other port specific stuff you
619 //              // need to pass by extending MotuXXXPort and MotuPortInfo
620 //    );
621 //    free(buff);
622 //
623 //    if (!p) {
624 //        debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
625 //    } else {
626 //        if (!m_transmitProcessor->addPort(p)) {
627 //            debugWarning("Could not register port with stream processor\n");
628 //            return false;
629 //        } else {
630 //            debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
631 //        }
632 //    }
633
634     return true;
635 }
636
637 int
638 MotuDevice::getStreamCount() {
639      return 2; // one receive, one transmit
640 }
641
642 Streaming::StreamProcessor *
643 MotuDevice::getStreamProcessorByIndex(int i) {
644     switch (i) {
645     case 0:
646         return m_receiveProcessor;
647     case 1:
648          return m_transmitProcessor;
649     default:
650         return NULL;
651     }
652     return 0;
653 }
654
655 bool
656 MotuDevice::startStreamByIndex(int i) {
657
658 quadlet_t isoctrl = ReadRegister(MOTUFW_REG_ISOCTRL);
659
660     // NOTE: this assumes that you have two streams
661     switch (i) {
662     case 0:
663         // TODO: do the stuff that is nescessary to make the device
664         // receive a stream
665
666         // Set the streamprocessor channel to the one obtained by
667         // the connection management
668         m_receiveProcessor->setChannel(m_iso_recv_channel);
669
670         // Mask out current transmit settings of the MOTU and replace
671         // with new ones.  Turn bit 24 on to enable changes to the
672         // MOTU's iso transmit settings when the iso control register
673         // is written.  Bit 23 enables iso transmit from the MOTU.
674         isoctrl &= 0xff00ffff;
675         isoctrl |= (m_iso_recv_channel << 16);
676         isoctrl |= 0x00c00000;
677         WriteRegister(MOTUFW_REG_ISOCTRL, isoctrl);
678         break;
679     case 1:
680         // TODO: do the stuff that is nescessary to make the device
681         // transmit a stream
682
683         // Set the streamprocessor channel to the one obtained by
684         // the connection management
685         m_transmitProcessor->setChannel(m_iso_send_channel);
686
687         // Mask out current receive settings of the MOTU and replace
688         // with new ones.  Turn bit 31 on to enable changes to the
689         // MOTU's iso receive settings when the iso control register
690         // is written.  Bit 30 enables iso receive by the MOTU.
691         isoctrl &= 0x00ffffff;
692         isoctrl |= (m_iso_send_channel << 24);
693         isoctrl |= 0xc0000000;
694         WriteRegister(MOTUFW_REG_ISOCTRL, isoctrl);
695         break;
696
697     default: // Invalid stream index
698         return false;
699     }
700
701     return true;
702 }
703
704 bool
705 MotuDevice::stopStreamByIndex(int i) {
706
707 quadlet_t isoctrl = ReadRegister(MOTUFW_REG_ISOCTRL);
708
709     // TODO: connection management: break connection
710     // cfr the start function
711
712     // NOTE: this assumes that you have two streams
713     switch (i) {
714     case 0:
715         // Turn bit 22 off to disable iso send by the MOTU.  Turn
716         // bit 23 on to enable changes to the MOTU's iso transmit
717         // settings when the iso control register is written.
718         isoctrl &= 0xffbfffff;
719         isoctrl |= 0x00800000;
720         WriteRegister(MOTUFW_REG_ISOCTRL, isoctrl);
721         break;
722     case 1:
723         // Turn bit 30 off to disable iso receive by the MOTU.  Turn
724         // bit 31 on to enable changes to the MOTU's iso receive
725         // settings when the iso control register is written.
726         isoctrl &= 0xbfffffff;
727         isoctrl |= 0x80000000;
728         WriteRegister(MOTUFW_REG_ISOCTRL, isoctrl);
729         break;
730
731     default: // Invalid stream index
732         return false;
733     }
734
735     return true;
736 }
737
738 signed int MotuDevice::getIsoRecvChannel(void) {
739     return m_iso_recv_channel;
740 }
741
742 signed int MotuDevice::getIsoSendChannel(void) {
743     return m_iso_send_channel;
744 }
745
746 unsigned int MotuDevice::getOpticalMode(unsigned int dir) {
747     unsigned int reg = ReadRegister(MOTUFW_REG_ROUTE_PORT_CONF);
748
749 debugOutput(DEBUG_LEVEL_VERBOSE, "optical mode: %x %x %x %x\n",dir, reg, reg & MOTUFW_OPTICAL_IN_MODE_MASK,
750 reg & MOTUFW_OPTICAL_OUT_MODE_MASK);
751
752     if (dir == MOTUFW_DIR_IN)
753         return (reg & MOTUFW_OPTICAL_IN_MODE_MASK) >> 8;
754     else
755         return (reg & MOTUFW_OPTICAL_OUT_MODE_MASK) >> 10;
756 }
757
758 signed int MotuDevice::setOpticalMode(unsigned int dir, unsigned int mode) {
759     unsigned int reg = ReadRegister(MOTUFW_REG_ROUTE_PORT_CONF);
760     unsigned int opt_ctrl = 0x0000002;
761
762     // Set up the optical control register value according to the current
763     // optical port modes.  At this stage it's not completely understood
764     // what the "Optical control" register does, so the values it's set to
765     // are more or less "magic" numbers.
766     if (reg & MOTUFW_OPTICAL_IN_MODE_MASK != (MOTUFW_OPTICAL_MODE_ADAT<<8))
767         opt_ctrl |= 0x00000080;
768     if (reg & MOTUFW_OPTICAL_OUT_MODE_MASK != (MOTUFW_OPTICAL_MODE_ADAT<<10))
769         opt_ctrl |= 0x00000040;
770
771     if (mode & MOTUFW_DIR_IN) {
772         reg &= ~MOTUFW_OPTICAL_IN_MODE_MASK;
773         reg |= (mode << 8) & MOTUFW_OPTICAL_IN_MODE_MASK;
774         if (mode != MOTUFW_OPTICAL_MODE_ADAT)
775             opt_ctrl |= 0x00000080;
776         else
777             opt_ctrl &= ~0x00000080;
778     }
779     if (mode & MOTUFW_DIR_OUT) {
780         reg &= ~MOTUFW_OPTICAL_OUT_MODE_MASK;
781         reg |= (mode <<10) & MOTUFW_OPTICAL_OUT_MODE_MASK;
782         if (mode != MOTUFW_OPTICAL_MODE_ADAT)
783             opt_ctrl |= 0x00000040;
784         else
785             opt_ctrl &= ~0x00000040;
786     }
787
788     // FIXME: there seems to be more to it than this, but for
789     // the moment at least this seems to work.
790     WriteRegister(MOTUFW_REG_ROUTE_PORT_CONF, reg);
791     return WriteRegister(MOTUFW_REG_OPTICAL_CTRL, opt_ctrl);
792 }
793
794 signed int MotuDevice::getEventSize(unsigned int direction) {
795 //
796 // Return the size in bytes of a single event sent to (dir==MOTUFW_OUT) or
797 // from (dir==MOTUFW_IN) the MOTU as part of an iso data packet.
798 //
799 // FIXME: for performance it may turn out best to calculate the event
800 // size in setOpticalMode and cache the result in a data field.  However,
801 // as it stands this will not adapt to dynamic changes in sample rate - we'd
802 // need a setFrameRate() for that.
803 //
804 // At the very least an event consists of the SPH (4 bytes) and the control/MIDI
805 // bytes (6 bytes).
806 // Note that all audio channels are sent using 3 bytes.
807 signed int sample_rate = getSamplingFrequency();
808 signed int optical_mode = getOpticalMode(direction);
809 signed int size = 4+6;
810
811 unsigned int i;
812 unsigned int dir = direction==Streaming::Port::E_Capture?MOTUFW_DIR_IN:MOTUFW_DIR_OUT;
813 unsigned int flags = (1 << ( optical_mode + 4 ));
814
815     if ( sample_rate > 96000 )
816         flags |= MOTUFW_PA_RATE_4x;
817     else if ( sample_rate > 48000 )
818         flags |= MOTUFW_PA_RATE_2x;
819     else
820         flags |= MOTUFW_PA_RATE_1x;
821
822     for (i=0; i < ( DevicesProperty[m_motu_model-1].PortsListLength /sizeof( PortEntry ) ); i++) {
823         if (( DevicesProperty[m_motu_model-1].PortsList[i].port_dir & dir ) &&
824            ( DevicesProperty[m_motu_model-1].PortsList[i].port_flags & MOTUFW_PA_RATE_MASK & flags ) &&
825            ( DevicesProperty[m_motu_model-1].PortsList[i].port_flags & MOTUFW_PA_OPTICAL_MASK & flags )) {
826             size += 3;
827         }
828     }
829
830     // Finally round size up to the next quadlet boundary
831     return ((size+3)/4)*4;
832 }
833 /* ======================================================================= */
834
835 bool MotuDevice::addPort(Streaming::StreamProcessor *s_processor,
836   char *name, enum Streaming::Port::E_Direction direction,
837   int position, int size) {
838 /*
839  * Internal helper function to add a MOTU port to a given stream processor.
840  * This just saves the unnecessary replication of what is essentially
841  * boilerplate code.  Note that the port name is freed by this function
842  * prior to exit.
843  */
844 Streaming::Port *p=NULL;
845
846     p = new Streaming::MotuAudioPort(*s_processor, name, direction, position, size);
847
848     if (!p) {
849         debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",name);
850     }
851     free(name);
852     return true;
853 }
854 /* ======================================================================= */
855
856 bool MotuDevice::addDirPorts(
857   enum Streaming::Port::E_Direction direction,
858   unsigned int sample_rate, unsigned int optical_mode) {
859 /*
860  * Internal helper method: adds all required ports for the given direction
861  * based on the indicated sample rate and optical mode.
862  *
863  * Notes: currently ports are not created if they are disabled due to sample
864  * rate or optical mode.  However, it might be better to unconditionally
865  * create all ports and just disable those which are not active.
866  */
867 const char *mode_str = direction==Streaming::Port::E_Capture?"cap":"pbk";
868 Streaming::StreamProcessor *s_processor;
869 unsigned int i;
870 char *buff;
871 unsigned int dir = direction==Streaming::Port::E_Capture?MOTUFW_DIR_IN:MOTUFW_DIR_OUT;
872 unsigned int flags = (1 << ( optical_mode + 4 ));
873
874     if ( sample_rate > 96000 )
875         flags |= MOTUFW_PA_RATE_4x;
876     else if ( sample_rate > 48000 )
877         flags |= MOTUFW_PA_RATE_2x;
878     else
879         flags |= MOTUFW_PA_RATE_1x;
880
881     // retrieve the ID
882     std::string id=std::string("dev?");
883     if(!getOption("id", id)) {
884         debugWarning("Could not retrieve id parameter, defauling to 'dev?'\n");
885     }
886
887     if (direction == Streaming::Port::E_Capture) {
888         s_processor = m_receiveProcessor;
889     } else {
890         s_processor = m_transmitProcessor;
891     }
892
893     for (i=0; i < ( DevicesProperty[m_motu_model-1].PortsListLength /sizeof( PortEntry ) ); i++) {
894         if (( DevicesProperty[m_motu_model-1].PortsList[i].port_dir & dir ) &&
895            ( DevicesProperty[m_motu_model-1].PortsList[i].port_flags & MOTUFW_PA_RATE_MASK & flags ) &&
896            ( DevicesProperty[m_motu_model-1].PortsList[i].port_flags & MOTUFW_PA_OPTICAL_MASK & flags )) {
897             asprintf(&buff,"%s_%s_%s" , id.c_str(), mode_str,
898               DevicesProperty[m_motu_model-1].PortsList[i].port_name);
899             if (!addPort(s_processor, buff, direction, DevicesProperty[m_motu_model-1].PortsList[i].port_offset, 0))
900                 return false;
901         }
902     }
903    
904     return true;
905 }
906 /* ======================================================================== */
907
908 unsigned int MotuDevice::ReadRegister(unsigned int reg) {
909 /*
910  * Attempts to read the requested register from the MOTU.
911  */
912
913   quadlet_t quadlet;
914
915   quadlet = 0;
916   // Note: 1394Service::read() expects a physical ID, not the node id
917   if (get1394Service().read(0xffc0 | getNodeId(), MOTUFW_BASE_ADDR+reg, 1, &quadlet) < 0) {
918     debugError("Error doing motu read from register 0x%06x\n",reg);
919   }
920
921   return ntohl(quadlet);
922 }
923
924 signed int MotuDevice::WriteRegister(unsigned int reg, quadlet_t data) {
925 /*
926  * Attempts to write the given data to the requested MOTU register.
927  */
928
929   unsigned int err = 0;
930   data = htonl(data);
931
932   // Note: 1394Service::write() expects a physical ID, not the node id
933   if (get1394Service().write(0xffc0 | getNodeId(), MOTUFW_BASE_ADDR+reg, 1, &data) < 0) {
934     err = 1;
935     debugError("Error doing motu write to register 0x%06x\n",reg);
936   }
937
938   SleepRelativeUsec(100);
939   return (err==0)?0:-1;
940 }
941
942 }
Note: See TracBrowser for help on using the browser.