root/trunk/libffado/src/dice/dice_avdevice.cpp

Revision 750, 56.8 kB (checked in by ppalmers, 16 years ago)

Code refactoring. Tries to simplify things and tries to put all code where it belongs.

Line 
1 /*
2  * Copyright (C) 2005-2007 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "dice/dice_avdevice.h"
25 #include "dice/dice_defines.h"
26
27 #include "libieee1394/configrom.h"
28 #include "libieee1394/ieee1394service.h"
29
30 #include "debugmodule/debugmodule.h"
31
32 #include <string>
33 #include <stdint.h>
34 #include <assert.h>
35 #include <netinet/in.h>
36 #include <libraw1394/csr.h>
37
38 #include <iostream>
39 #include <sstream>
40
41 #include <string>
42 using namespace std;
43
44 namespace Dice {
45
46 // to define the supported devices
47 static VendorModelEntry supportedDeviceList[] =
48 {
49     // vendor id, model id, vendor name, model name
50     {FW_VENDORID_TCAT, 0x00000002, "TCAT", "DiceII EVM"},
51     {FW_VENDORID_TCAT, 0x00000004, "TCAT", "DiceII EVM (vxx)"},
52 };
53
54 DiceAvDevice::DiceAvDevice( DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
55     : FFADODevice( d, configRom )
56     , m_model( NULL )
57     , m_global_reg_offset (0xFFFFFFFFLU)
58     , m_global_reg_size (0xFFFFFFFFLU)
59     , m_tx_reg_offset (0xFFFFFFFFLU)
60     , m_tx_reg_size (0xFFFFFFFFLU)
61     , m_rx_reg_offset (0xFFFFFFFFLU)
62     , m_rx_reg_size (0xFFFFFFFFLU)
63     , m_unused1_reg_offset (0xFFFFFFFFLU)
64     , m_unused1_reg_size (0xFFFFFFFFLU)
65     , m_unused2_reg_offset (0xFFFFFFFFLU)
66     , m_unused2_reg_size (0xFFFFFFFFLU)
67     , m_nb_tx (0xFFFFFFFFLU)
68     , m_tx_size (0xFFFFFFFFLU)
69     , m_nb_rx (0xFFFFFFFFLU)
70     , m_rx_size (0xFFFFFFFFLU)
71     , m_notifier (NULL)
72 {
73     debugOutput( DEBUG_LEVEL_VERBOSE, "Created Dice::DiceAvDevice (NodeID %d)\n",
74                  getConfigRom().getNodeId() );
75
76 }
77
78 DiceAvDevice::~DiceAvDevice()
79 {
80     // FIXME: clean up m_receiveProcessors & xmit
81
82     if (m_notifier) {
83         unlock();
84     }
85 }
86
87 bool
88 DiceAvDevice::probe( ConfigRom& configRom )
89 {
90     unsigned int vendorId = configRom.getNodeVendorId();
91     unsigned int modelId = configRom.getModelId();
92
93     for ( unsigned int i = 0;
94           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
95           ++i )
96     {
97         if ( ( supportedDeviceList[i].vendor_id == vendorId )
98              && ( supportedDeviceList[i].model_id == modelId )
99            )
100         {
101             return true;
102         }
103     }
104
105     return false;
106 }
107
108 FFADODevice *
109 DiceAvDevice::createDevice( DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
110 {
111     return new DiceAvDevice( d, configRom );
112 }
113
114 bool
115 DiceAvDevice::discover()
116 {
117     unsigned int vendorId = getConfigRom().getNodeVendorId();
118     unsigned int modelId = getConfigRom().getModelId();
119
120     for ( unsigned int i = 0;
121           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
122           ++i )
123     {
124         if ( ( supportedDeviceList[i].vendor_id == vendorId )
125              && ( supportedDeviceList[i].model_id == modelId )
126            )
127         {
128             m_model = &(supportedDeviceList[i]);
129         }
130     }
131
132     if (m_model == NULL) {
133         debugWarning("DiceAvDevice::discover() called for a non-dice device");
134         return false;
135     }
136
137     if ( !initIoFunctions() ) {
138         debugError("Could not initialize I/O functions\n");
139         return false;
140     }
141
142     debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s (nick: %s)\n",
143                 m_model->vendor_name, m_model->model_name, getDeviceNickName().c_str());
144
145     return true;
146 }
147
148 int
149 DiceAvDevice::getSamplingFrequency( ) {
150     int samplingFrequency;
151
152     fb_quadlet_t clockreg;
153     if (!readGlobalReg(DICE_REGISTER_GLOBAL_CLOCK_SELECT, &clockreg)) {
154         debugError("Could not read CLOCK_SELECT register\n");
155         return false;
156     }
157
158     clockreg = DICE_GET_RATE(clockreg);
159
160     switch (clockreg) {
161         case DICE_RATE_32K:      samplingFrequency = 32000;  break;
162         case DICE_RATE_44K1:     samplingFrequency = 44100;  break;
163         case DICE_RATE_48K:      samplingFrequency = 48000;  break;
164         case DICE_RATE_88K2:     samplingFrequency = 88200;  break;
165         case DICE_RATE_96K:      samplingFrequency = 96000;  break;
166         case DICE_RATE_176K4:    samplingFrequency = 176400; break;
167         case DICE_RATE_192K:     samplingFrequency = 192000; break;
168         case DICE_RATE_ANY_LOW:  samplingFrequency = 0;   break;
169         case DICE_RATE_ANY_MID:  samplingFrequency = 0;   break;
170         case DICE_RATE_ANY_HIGH: samplingFrequency = 0;  break;
171         case DICE_RATE_NONE:     samplingFrequency = 0;     break;
172         default:                 samplingFrequency = 0; break;
173     }
174
175     return samplingFrequency;
176 }
177
178 int
179 DiceAvDevice::getConfigurationId()
180 {
181     return 0;
182 }
183
184 bool
185 DiceAvDevice::setSamplingFrequency( int samplingFrequency )
186 {
187     debugOutput(DEBUG_LEVEL_VERBOSE, "Setting sample rate: %d\n",
188         (samplingFrequency));
189
190     bool supported=false;
191     fb_quadlet_t select=0x0;
192
193     switch ( samplingFrequency ) {
194     default:
195     case 22050:
196     case 24000:
197         supported=false;
198         break;
199     case 32000:
200         supported=maskedCheckNotZeroGlobalReg(
201                     DICE_REGISTER_GLOBAL_CLOCKCAPABILITIES,
202                     DICE_CLOCKCAP_RATE_32K);
203         select=DICE_RATE_32K;
204         break;
205     case 44100:
206         supported=maskedCheckNotZeroGlobalReg(
207                     DICE_REGISTER_GLOBAL_CLOCKCAPABILITIES,
208                     DICE_CLOCKCAP_RATE_44K1);
209         select=DICE_RATE_44K1;
210         break;
211     case 48000:
212         supported=maskedCheckNotZeroGlobalReg(
213                     DICE_REGISTER_GLOBAL_CLOCKCAPABILITIES,
214                     DICE_CLOCKCAP_RATE_48K);
215         select=DICE_RATE_48K;
216         break;
217     case 88200:
218         supported=maskedCheckNotZeroGlobalReg(
219                     DICE_REGISTER_GLOBAL_CLOCKCAPABILITIES,
220                     DICE_CLOCKCAP_RATE_88K2);
221         select=DICE_RATE_88K2;
222         break;
223     case 96000:
224         supported=maskedCheckNotZeroGlobalReg(
225                     DICE_REGISTER_GLOBAL_CLOCKCAPABILITIES,
226                     DICE_CLOCKCAP_RATE_96K);
227         select=DICE_RATE_96K;
228         break;
229     case 176400:
230         supported=maskedCheckNotZeroGlobalReg(
231                     DICE_REGISTER_GLOBAL_CLOCKCAPABILITIES,
232                     DICE_CLOCKCAP_RATE_176K4);
233         select=DICE_RATE_176K4;
234         break;
235     case 192000:
236         supported=maskedCheckNotZeroGlobalReg(
237                     DICE_REGISTER_GLOBAL_CLOCKCAPABILITIES,
238                     DICE_CLOCKCAP_RATE_192K);
239         select=DICE_RATE_192K;
240         break;
241     }
242
243     if (!supported) {
244         debugWarning("Unsupported sample rate: %d\n", (samplingFrequency));
245         return false;
246     }
247
248     if (isIsoStreamingEnabled()) {
249         debugError("Cannot change samplerate while streaming is enabled\n");
250         return false;
251     }
252
253     fb_quadlet_t clockreg;
254     if (!readGlobalReg(DICE_REGISTER_GLOBAL_CLOCK_SELECT, &clockreg)) {
255         debugError("Could not read CLOCK_SELECT register\n");
256         return false;
257     }
258
259     clockreg = DICE_SET_RATE(clockreg, select);
260
261     if (!writeGlobalReg(DICE_REGISTER_GLOBAL_CLOCK_SELECT, clockreg)) {
262         debugError("Could not write CLOCK_SELECT register\n");
263         return false;
264     }
265
266     // check if the write succeeded
267     fb_quadlet_t clockreg_verify;
268     if (!readGlobalReg(DICE_REGISTER_GLOBAL_CLOCK_SELECT, &clockreg_verify)) {
269         debugError("Could not read CLOCK_SELECT register\n");
270         return false;
271     }
272
273     if(clockreg != clockreg_verify) {
274         debugError("Samplerate register write failed\n");
275         return false;
276     }
277
278     return true;
279 }
280
281 FFADODevice::ClockSourceVector
282 DiceAvDevice::getSupportedClockSources() {
283     FFADODevice::ClockSourceVector r;
284
285     quadlet_t clock_caps;
286     readGlobalReg(DICE_REGISTER_GLOBAL_CLOCKCAPABILITIES, &clock_caps);
287     uint16_t clocks_supported = (clock_caps >> 16) & 0xFFFF;
288     debugOutput(DEBUG_LEVEL_VERBOSE," Clock caps: 0x%08X, supported=0x%04X\n",
289                                     clock_caps, clocks_supported);
290
291     quadlet_t clock_select;
292     readGlobalReg(DICE_REGISTER_GLOBAL_CLOCK_SELECT, &clock_select);
293     byte_t clock_selected = (clock_select) & 0xFF;
294     debugOutput(DEBUG_LEVEL_VERBOSE," Clock select: 0x%08X, selected=0x%04X\n",
295                                     clock_select, clock_selected);
296     quadlet_t extended_status;
297     readGlobalReg(DICE_REGISTER_GLOBAL_EXTENDED_STATUS, &extended_status);
298     uint16_t clock_status = (extended_status) & 0xFFFF;
299     uint16_t clock_slipping = (extended_status >> 16) & 0xFFFF;
300     debugOutput(DEBUG_LEVEL_VERBOSE," Clock status: 0x%08X, status=0x%04X, slip=0x%04X\n",
301                                     extended_status, clock_status, clock_slipping);
302
303     diceNameVector names = getClockSourceNameString();
304     if( names.size() < DICE_CLOCKSOURCE_COUNT) {
305         debugError("Not enough clock source names on device\n");
306         return r;
307     }
308     for (unsigned int i=0; i < DICE_CLOCKSOURCE_COUNT; i++) {
309         bool supported = (((clocks_supported >> i) & 0x01) == 1);
310         if (supported) {
311             ClockSource s;
312             s.type = clockIdToType(i);
313             s.id = i;
314             s.valid = true;
315             s.locked = isClockSourceIdLocked(i, extended_status);
316             s.slipping = isClockSourceIdSlipping(i, extended_status);
317             s.active = (clock_selected == i);
318             s.description = names.at(i);
319             r.push_back(s);
320         } else {
321             debugOutput(DEBUG_LEVEL_VERBOSE, "Clock source id %d not supported by device\n", i);
322         }
323     }
324     return r;
325 }
326
327 bool
328 DiceAvDevice::isClockSourceIdLocked(unsigned int id, quadlet_t ext_status_reg) {
329     switch (id) {
330         default: return true;
331         case  DICE_CLOCKSOURCE_AES1:
332                 return ext_status_reg & DICE_EXT_STATUS_AES0_LOCKED;
333         case  DICE_CLOCKSOURCE_AES2:
334                 return ext_status_reg & DICE_EXT_STATUS_AES1_LOCKED;
335         case  DICE_CLOCKSOURCE_AES3:
336                 return ext_status_reg & DICE_EXT_STATUS_AES2_LOCKED;
337         case  DICE_CLOCKSOURCE_AES4:
338                 return ext_status_reg & DICE_EXT_STATUS_AES3_LOCKED;
339         case  DICE_CLOCKSOURCE_AES_ANY:
340                 return ext_status_reg & DICE_EXT_STATUS_AES_ANY_LOCKED;
341         case  DICE_CLOCKSOURCE_ADAT:
342                 return ext_status_reg & DICE_EXT_STATUS_ADAT_LOCKED;
343         case  DICE_CLOCKSOURCE_TDIF:
344                 return ext_status_reg & DICE_EXT_STATUS_TDIF_LOCKED;
345         case  DICE_CLOCKSOURCE_ARX1:
346                 return ext_status_reg & DICE_EXT_STATUS_ARX1_LOCKED;
347         case  DICE_CLOCKSOURCE_ARX2:
348                 return ext_status_reg & DICE_EXT_STATUS_ARX2_LOCKED;
349         case  DICE_CLOCKSOURCE_ARX3:
350                 return ext_status_reg & DICE_EXT_STATUS_ARX3_LOCKED;
351         case  DICE_CLOCKSOURCE_ARX4:
352                 return ext_status_reg & DICE_EXT_STATUS_ARX4_LOCKED;
353         case  DICE_CLOCKSOURCE_WC:
354                 return ext_status_reg & DICE_EXT_STATUS_WC_LOCKED;
355     }
356 }
357 bool
358 DiceAvDevice::isClockSourceIdSlipping(unsigned int id, quadlet_t ext_status_reg) {
359     switch (id) {
360         default: return false;
361         case  DICE_CLOCKSOURCE_AES1:
362                 return ext_status_reg & DICE_EXT_STATUS_AES0_SLIP;
363         case  DICE_CLOCKSOURCE_AES2:
364                 return ext_status_reg & DICE_EXT_STATUS_AES1_SLIP;
365         case  DICE_CLOCKSOURCE_AES3:
366                 return ext_status_reg & DICE_EXT_STATUS_AES2_SLIP;
367         case  DICE_CLOCKSOURCE_AES4:
368                 return ext_status_reg & DICE_EXT_STATUS_AES3_SLIP;
369         case  DICE_CLOCKSOURCE_AES_ANY:
370                 return false;
371         case  DICE_CLOCKSOURCE_ADAT:
372                 return ext_status_reg & DICE_EXT_STATUS_ADAT_SLIP;
373         case  DICE_CLOCKSOURCE_TDIF:
374                 return ext_status_reg & DICE_EXT_STATUS_TDIF_SLIP;
375         case  DICE_CLOCKSOURCE_ARX1:
376                 return ext_status_reg & DICE_EXT_STATUS_ARX1_SLIP;
377         case  DICE_CLOCKSOURCE_ARX2:
378                 return ext_status_reg & DICE_EXT_STATUS_ARX2_SLIP;
379         case  DICE_CLOCKSOURCE_ARX3:
380                 return ext_status_reg & DICE_EXT_STATUS_ARX3_SLIP;
381         case  DICE_CLOCKSOURCE_ARX4:
382                 return ext_status_reg & DICE_EXT_STATUS_ARX4_SLIP;
383         case  DICE_CLOCKSOURCE_WC: // FIXME: not in driver spec, so non-existant
384                 return ext_status_reg & DICE_EXT_STATUS_WC_SLIP;
385     }
386 }
387
388 enum FFADODevice::eClockSourceType
389 DiceAvDevice::clockIdToType(unsigned int id) {
390     switch (id) {
391         default: return eCT_Invalid;
392         case  DICE_CLOCKSOURCE_AES1:
393         case  DICE_CLOCKSOURCE_AES2:
394         case  DICE_CLOCKSOURCE_AES3:
395         case  DICE_CLOCKSOURCE_AES4:
396         case  DICE_CLOCKSOURCE_AES_ANY:
397                 return eCT_AES;
398         case  DICE_CLOCKSOURCE_ADAT:
399                 return eCT_ADAT;
400         case  DICE_CLOCKSOURCE_TDIF:
401                 return eCT_TDIF;
402         case  DICE_CLOCKSOURCE_ARX1:
403         case  DICE_CLOCKSOURCE_ARX2:
404         case  DICE_CLOCKSOURCE_ARX3:
405         case  DICE_CLOCKSOURCE_ARX4:
406                 return eCT_SytMatch;
407         case  DICE_CLOCKSOURCE_WC:
408                 return eCT_WordClock;
409         case DICE_CLOCKSOURCE_INTERNAL:
410                 return eCT_Internal;
411     }
412 }
413
414 bool
415 DiceAvDevice::setActiveClockSource(ClockSource s) {
416     fb_quadlet_t clockreg;
417     if (!readGlobalReg(DICE_REGISTER_GLOBAL_CLOCK_SELECT, &clockreg)) {
418         debugError("Could not read CLOCK_SELECT register\n");
419         return false;
420     }
421
422     clockreg = DICE_SET_CLOCKSOURCE(clockreg, s.id);
423
424     if (!writeGlobalReg(DICE_REGISTER_GLOBAL_CLOCK_SELECT, clockreg)) {
425         debugError("Could not write CLOCK_SELECT register\n");
426         return false;
427     }
428
429     // check if the write succeeded
430     fb_quadlet_t clockreg_verify;
431     if (!readGlobalReg(DICE_REGISTER_GLOBAL_CLOCK_SELECT, &clockreg_verify)) {
432         debugError("Could not read CLOCK_SELECT register\n");
433         return false;
434     }
435
436     if(clockreg != clockreg_verify) {
437         debugError("CLOCK_SELECT register write failed\n");
438         return false;
439     }
440
441     return DICE_GET_CLOCKSOURCE(clockreg_verify) == s.id;
442 }
443
444 FFADODevice::ClockSource
445 DiceAvDevice::getActiveClockSource() {
446     ClockSource s;
447     quadlet_t clock_caps;
448     readGlobalReg(DICE_REGISTER_GLOBAL_CLOCKCAPABILITIES, &clock_caps);
449     uint16_t clocks_supported = (clock_caps >> 16) & 0xFFFF;
450     debugOutput(DEBUG_LEVEL_VERBOSE," Clock caps: 0x%08X, supported=0x%04X\n",
451                                     clock_caps, clocks_supported);
452
453     quadlet_t clock_select;
454     readGlobalReg(DICE_REGISTER_GLOBAL_CLOCK_SELECT, &clock_select);
455     byte_t id = (clock_select) & 0xFF;
456     debugOutput(DEBUG_LEVEL_VERBOSE," Clock select: 0x%08X, selected=0x%04X\n",
457                                     clock_select, id);
458     quadlet_t extended_status;
459     readGlobalReg(DICE_REGISTER_GLOBAL_EXTENDED_STATUS, &extended_status);
460     uint16_t clock_status = (extended_status) & 0xFFFF;
461     uint16_t clock_slipping = (extended_status >> 16) & 0xFFFF;
462     debugOutput(DEBUG_LEVEL_VERBOSE," Clock status: 0x%08X, status=0x%04X, slip=0x%04X\n",
463                                     extended_status, clock_status, clock_slipping);
464
465     diceNameVector names = getClockSourceNameString();
466     if( names.size() < DICE_CLOCKSOURCE_COUNT) {
467         debugError("Not enough clock source names on device\n");
468         return s;
469     }
470     bool supported = (((clocks_supported >> id) & 0x01) == 1);
471     if (supported) {
472         s.type = clockIdToType(id);
473         s.id = id;
474         s.valid = true;
475         s.locked = isClockSourceIdLocked(id, extended_status);
476         s.slipping = isClockSourceIdSlipping(id, extended_status);
477         s.active = true;
478         s.description = names.at(id);
479     } else {
480         debugOutput(DEBUG_LEVEL_VERBOSE, "Clock source id %2d not supported by device\n", id);
481     }
482     return s;
483 }
484
485 void
486 DiceAvDevice::showDevice()
487 {
488     fb_quadlet_t tmp_quadlet;
489     fb_octlet_t tmp_octlet;
490
491     debugOutput(DEBUG_LEVEL_NORMAL, "Device is a DICE device\n");
492     FFADODevice::showDevice();
493
494     debugOutput(DEBUG_LEVEL_VERBOSE," DICE Parameter Space info:\n");
495     debugOutput(DEBUG_LEVEL_VERBOSE,"  Global  : offset=0x%04X size=%04d\n", m_global_reg_offset, m_global_reg_size);
496     debugOutput(DEBUG_LEVEL_VERBOSE,"  TX      : offset=0x%04X size=%04d\n", m_tx_reg_offset, m_tx_reg_size);
497     debugOutput(DEBUG_LEVEL_VERBOSE,"                nb=%4d size=%04d\n", m_nb_tx, m_tx_size);
498     debugOutput(DEBUG_LEVEL_VERBOSE,"  RX      : offset=0x%04X size=%04d\n", m_rx_reg_offset, m_rx_reg_size);
499     debugOutput(DEBUG_LEVEL_VERBOSE,"                nb=%4d size=%04d\n", m_nb_rx, m_rx_size);
500     debugOutput(DEBUG_LEVEL_VERBOSE,"  UNUSED1 : offset=0x%04X size=%04d\n", m_unused1_reg_offset, m_unused1_reg_size);
501     debugOutput(DEBUG_LEVEL_VERBOSE,"  UNUSED2 : offset=0x%04X size=%04d\n", m_unused2_reg_offset, m_unused2_reg_size);
502
503     debugOutput(DEBUG_LEVEL_VERBOSE," Global param space:\n");
504
505     readGlobalRegBlock(DICE_REGISTER_GLOBAL_OWNER, (fb_quadlet_t *)&tmp_octlet,sizeof(fb_octlet_t));
506     debugOutput(DEBUG_LEVEL_VERBOSE,"  Owner            : 0x%016X\n",tmp_octlet);
507
508     readGlobalReg(DICE_REGISTER_GLOBAL_NOTIFICATION, &tmp_quadlet);
509     debugOutput(DEBUG_LEVEL_VERBOSE,"  Notification     : 0x%08X\n",tmp_quadlet);
510
511     readGlobalReg(DICE_REGISTER_GLOBAL_NOTIFICATION, &tmp_quadlet);
512     debugOutput(DEBUG_LEVEL_NORMAL,"  Nick name        : %s\n",getDeviceNickName().c_str());
513
514     readGlobalReg(DICE_REGISTER_GLOBAL_CLOCK_SELECT, &tmp_quadlet);
515     debugOutput(DEBUG_LEVEL_NORMAL,"  Clock Select     : 0x%02X 0x%02X\n",
516         (tmp_quadlet>>8) & 0xFF, tmp_quadlet & 0xFF);
517
518     readGlobalReg(DICE_REGISTER_GLOBAL_ENABLE, &tmp_quadlet);
519     debugOutput(DEBUG_LEVEL_NORMAL,"  Enable           : %s\n",
520         (tmp_quadlet&0x1?"true":"false"));
521
522     readGlobalReg(DICE_REGISTER_GLOBAL_STATUS, &tmp_quadlet);
523     debugOutput(DEBUG_LEVEL_NORMAL,"  Clock Status     : %s 0x%02X\n",
524         (tmp_quadlet&0x1?"locked":"not locked"), (tmp_quadlet>>8) & 0xFF);
525
526     readGlobalReg(DICE_REGISTER_GLOBAL_EXTENDED_STATUS, &tmp_quadlet);
527     debugOutput(DEBUG_LEVEL_VERBOSE,"  Extended Status  : 0x%08X\n",tmp_quadlet);
528
529     readGlobalReg(DICE_REGISTER_GLOBAL_SAMPLE_RATE, &tmp_quadlet);
530     debugOutput(DEBUG_LEVEL_NORMAL,"  Samplerate       : 0x%08X (%lu)\n",tmp_quadlet,tmp_quadlet);
531
532     readGlobalReg(DICE_REGISTER_GLOBAL_VERSION, &tmp_quadlet);
533     debugOutput(DEBUG_LEVEL_NORMAL,"  Version          : 0x%08X (%u.%u.%u.%u)\n",
534         tmp_quadlet,
535         DICE_DRIVER_SPEC_VERSION_NUMBER_GET_A(tmp_quadlet),
536         DICE_DRIVER_SPEC_VERSION_NUMBER_GET_B(tmp_quadlet),
537         DICE_DRIVER_SPEC_VERSION_NUMBER_GET_C(tmp_quadlet),
538         DICE_DRIVER_SPEC_VERSION_NUMBER_GET_D(tmp_quadlet)
539         );
540
541     readGlobalReg(DICE_REGISTER_GLOBAL_CLOCKCAPABILITIES, &tmp_quadlet);
542     debugOutput(DEBUG_LEVEL_VERBOSE,"  Clock caps       : 0x%08X\n",tmp_quadlet);
543
544     diceNameVector names=getClockSourceNameString();
545     debugOutput(DEBUG_LEVEL_VERBOSE,"  Clock sources    :\n");
546
547     for ( diceNameVectorIterator it = names.begin();
548           it != names.end();
549           ++it )
550     {
551         debugOutput(DEBUG_LEVEL_VERBOSE,"    %s\n", (*it).c_str());
552     }
553
554     debugOutput(DEBUG_LEVEL_VERBOSE," TX param space:\n");
555     debugOutput(DEBUG_LEVEL_VERBOSE,"  Nb of xmit        : %1d\n", m_nb_tx);
556     for (unsigned int i=0;i<m_nb_tx;i++) {
557         debugOutput(DEBUG_LEVEL_VERBOSE,"  Transmitter %d:\n",i);
558
559         readTxReg(i, DICE_REGISTER_TX_ISOC_BASE, &tmp_quadlet);
560         debugOutput(DEBUG_LEVEL_VERBOSE,"   ISO channel       : %3d\n", tmp_quadlet);
561         readTxReg(i, DICE_REGISTER_TX_SPEED_BASE, &tmp_quadlet);
562         debugOutput(DEBUG_LEVEL_VERBOSE,"   ISO speed         : %3d\n", tmp_quadlet);
563
564         readTxReg(i, DICE_REGISTER_TX_NB_AUDIO_BASE, &tmp_quadlet);
565         debugOutput(DEBUG_LEVEL_VERBOSE,"   Nb audio channels : %3d\n", tmp_quadlet);
566         readTxReg(i, DICE_REGISTER_TX_MIDI_BASE, &tmp_quadlet);
567         debugOutput(DEBUG_LEVEL_VERBOSE,"   Nb midi channels  : %3d\n", tmp_quadlet);
568
569         readTxReg(i, DICE_REGISTER_TX_AC3_CAPABILITIES_BASE, &tmp_quadlet);
570         debugOutput(DEBUG_LEVEL_VERBOSE,"   AC3 caps          : 0x%08X\n", tmp_quadlet);
571         readTxReg(i, DICE_REGISTER_TX_AC3_ENABLE_BASE, &tmp_quadlet);
572         debugOutput(DEBUG_LEVEL_VERBOSE,"   AC3 enable        : 0x%08X\n", tmp_quadlet);
573
574         diceNameVector channel_names=getTxNameString(i);
575         debugOutput(DEBUG_LEVEL_VERBOSE,"   Channel names     :\n");
576         for ( diceNameVectorIterator it = channel_names.begin();
577             it != channel_names.end();
578             ++it )
579         {
580             debugOutput(DEBUG_LEVEL_VERBOSE,"     %s\n", (*it).c_str());
581         }
582     }
583
584     debugOutput(DEBUG_LEVEL_VERBOSE," RX param space:\n");
585     debugOutput(DEBUG_LEVEL_VERBOSE,"  Nb of recv        : %1d\n", m_nb_tx);
586     for (unsigned int i=0;i<m_nb_rx;i++) {
587         debugOutput(DEBUG_LEVEL_VERBOSE,"  Receiver %d:\n",i);
588
589         readTxReg(i, DICE_REGISTER_RX_ISOC_BASE, &tmp_quadlet);
590         debugOutput(DEBUG_LEVEL_VERBOSE,"   ISO channel       : %3d\n", tmp_quadlet);
591         readTxReg(i, DICE_REGISTER_RX_SEQ_START_BASE, &tmp_quadlet);
592         debugOutput(DEBUG_LEVEL_VERBOSE,"   Sequence start    : %3d\n", tmp_quadlet);
593
594         readTxReg(i, DICE_REGISTER_RX_NB_AUDIO_BASE, &tmp_quadlet);
595         debugOutput(DEBUG_LEVEL_VERBOSE,"   Nb audio channels : %3d\n", tmp_quadlet);
596         readTxReg(i, DICE_REGISTER_RX_MIDI_BASE, &tmp_quadlet);
597         debugOutput(DEBUG_LEVEL_VERBOSE,"   Nb midi channels  : %3d\n", tmp_quadlet);
598
599         readTxReg(i, DICE_REGISTER_RX_AC3_CAPABILITIES_BASE, &tmp_quadlet);
600         debugOutput(DEBUG_LEVEL_VERBOSE,"   AC3 caps          : 0x%08X\n", tmp_quadlet);
601         readTxReg(i, DICE_REGISTER_RX_AC3_ENABLE_BASE, &tmp_quadlet);
602         debugOutput(DEBUG_LEVEL_VERBOSE,"   AC3 enable        : 0x%08X\n", tmp_quadlet);
603
604         diceNameVector channel_names=getRxNameString(i);
605         debugOutput(DEBUG_LEVEL_VERBOSE,"   Channel names     :\n");
606         for ( diceNameVectorIterator it = channel_names.begin();
607             it != channel_names.end();
608             ++it )
609         {
610             debugOutput(DEBUG_LEVEL_VERBOSE,"     %s\n", (*it).c_str());
611         }
612     }
613     flushDebugOutput();
614 }
615
616 // NOTE on bandwidth calculation
617 // FIXME: The bandwidth allocation calculation can probably be
618 // refined somewhat since this is currently based on a rudimentary
619 // understanding of the iso protocol.
620 // Currently we assume the following.
621 //   * Ack/iso gap = 0.05 us
622 //   * DATA_PREFIX = 0.16 us1
623 //   * DATA_END    = 0.26 us
624 // These numbers are the worst-case figures given in the ieee1394
625 // standard.  This gives approximately 0.5 us of overheads per
626 // packet - around 25 bandwidth allocation units (from the ieee1394
627 // standard 1 bandwidth allocation unit is 125/6144 us).  We further
628 // assume the device is running at S400 (which it should be) so one
629 // allocation unit is equivalent to 1 transmitted byte; thus the
630 // bandwidth allocation required for the packets themselves is just
631 // the size of the packet.
632 bool
633 DiceAvDevice::prepare() {
634     // prepare receive SP's
635     for (unsigned int i=0;i<m_nb_tx;i++) {
636         fb_quadlet_t nb_audio;
637         fb_quadlet_t nb_midi;
638         unsigned int nb_channels=0;
639
640         if(!readTxReg(i, DICE_REGISTER_TX_NB_AUDIO_BASE, &nb_audio)) {
641             debugError("Could not read DICE_REGISTER_TX_NB_AUDIO_BASE register for ATX%u",i);
642             continue;
643         }
644         if(!readTxReg(i, DICE_REGISTER_TX_MIDI_BASE, &nb_midi)) {
645             debugError("Could not read DICE_REGISTER_TX_MIDI_BASE register for ATX%u",i);
646             continue;
647         }
648
649         // request the channel names
650         diceNameVector names_audio=getTxNameString(i);
651
652         if (names_audio.size() != nb_audio) {
653             debugWarning("The audio channel name vector is incorrect, using default names\n");
654             names_audio.clear();
655
656             for (unsigned int j=0;j<nb_audio;j++) {
657                 std::ostringstream newname;
658                 newname << "input_" << j;
659                 names_audio.push_back(newname.str());
660             }
661         }
662
663         nb_channels=nb_audio;
664         if(nb_midi) nb_channels += 1; // midi-muxed counts as one
665
666         // construct the MIDI names
667         diceNameVector names_midi;
668         for (unsigned int j=0;j<nb_midi;j++) {
669             std::ostringstream newname;
670             newname << "midi_in_" << j;
671             names_midi.push_back(newname.str());
672         }
673
674         // construct the streamprocessor
675         Streaming::AmdtpReceiveStreamProcessor *p;
676         p=new Streaming::AmdtpReceiveStreamProcessor(*this,
677                              nb_channels);
678
679         if(!p->init()) {
680             debugFatal("Could not initialize receive processor!\n");
681             delete p;
682             continue;
683         }
684
685         // add audio ports to the processor
686         for (unsigned int j=0;j<nb_audio;j++) {
687             diceChannelInfo channelInfo;
688             channelInfo.name=names_audio.at(j);
689             channelInfo.portType=ePT_Analog;
690             channelInfo.streamPosition=j;
691             channelInfo.streamLocation=0;
692
693             if (!addChannelToProcessor(&channelInfo, p, Streaming::Port::E_Capture)) {
694                 debugError("Could not add channel %s to StreamProcessor\n",
695                     channelInfo.name.c_str());
696                 continue;
697             }
698         }
699
700         // add midi ports to the processor
701         for (unsigned int j=0;j<nb_midi;j++) {
702             diceChannelInfo channelInfo;
703             channelInfo.name=names_midi.at(j);
704             channelInfo.portType=ePT_MIDI;
705             channelInfo.streamPosition=nb_audio;
706             channelInfo.streamLocation=j;
707
708             if (!addChannelToProcessor(&channelInfo, p, Streaming::Port::E_Capture)) {
709                 debugError("Could not add channel %s to StreamProcessor\n",
710                     channelInfo.name.c_str());
711                 continue;
712             }
713         }
714
715         // add the SP to the vector
716         m_receiveProcessors.push_back(p);
717     }
718
719     // prepare transmit SP's
720     for (unsigned int i=0;i<m_nb_rx;i++) {
721         fb_quadlet_t nb_audio;
722         fb_quadlet_t nb_midi;
723         unsigned int nb_channels=0;
724
725         if(!readTxReg(i, DICE_REGISTER_RX_NB_AUDIO_BASE, &nb_audio)) {
726             debugError("Could not read DICE_REGISTER_RX_NB_AUDIO_BASE register for ARX%u",i);
727             continue;
728         }
729         if(!readTxReg(i, DICE_REGISTER_RX_MIDI_BASE, &nb_midi)) {
730             debugError("Could not read DICE_REGISTER_RX_MIDI_BASE register for ARX%u",i);
731             continue;
732         }
733
734         // request the channel names
735         diceNameVector names_audio=getRxNameString(i);
736
737         if (names_audio.size() != nb_audio) {
738             debugWarning("The audio channel name vector is incorrect, using default names\n");
739             names_audio.clear();
740
741             for (unsigned int j=0;j<nb_audio;j++) {
742                 std::ostringstream newname;
743                 newname << "output_" << j;
744                 names_audio.push_back(newname.str());
745             }
746         }
747
748         nb_channels=nb_audio;
749         if(nb_midi) nb_channels += 1; // midi-muxed counts as one
750
751         // construct the MIDI names
752         diceNameVector names_midi;
753         for (unsigned int j=0;j<nb_midi;j++) {
754             std::ostringstream newname;
755             newname << "midi_out_" << j;
756             names_midi.push_back(newname.str());
757         }
758
759         // construct the streamprocessor
760         Streaming::AmdtpTransmitStreamProcessor *p;
761         p=new Streaming::AmdtpTransmitStreamProcessor(*this,
762                              nb_channels);
763
764         if(!p->init()) {
765             debugFatal("Could not initialize transmit processor!\n");
766             delete p;
767             continue;
768         }
769
770         // add audio ports to the processor
771         for (unsigned int j=0;j<nb_audio;j++) {
772             diceChannelInfo channelInfo;
773             channelInfo.name=names_audio.at(j);
774             channelInfo.portType=ePT_Analog;
775             channelInfo.streamPosition=j;
776             channelInfo.streamLocation=0;
777
778             if (!addChannelToProcessor(&channelInfo, p, Streaming::Port::E_Playback)) {
779                 debugError("Could not add channel %s to StreamProcessor\n",
780                     channelInfo.name.c_str());
781                 continue;
782             }
783         }
784
785         // add midi ports to the processor
786         for (unsigned int j=0;j<nb_midi;j++) {
787             diceChannelInfo channelInfo;
788             channelInfo.name=names_midi.at(j);
789             channelInfo.portType=ePT_MIDI;
790             channelInfo.streamPosition=nb_audio;
791             channelInfo.streamLocation=j;
792
793             if (!addChannelToProcessor(&channelInfo, p, Streaming::Port::E_Playback)) {
794                 debugError("Could not add channel %s to StreamProcessor\n",
795                     channelInfo.name.c_str());
796                 continue;
797             }
798         }
799
800         m_transmitProcessors.push_back(p);
801     }
802     return true;
803 }
804
805 bool
806 DiceAvDevice::addChannelToProcessor(
807     diceChannelInfo *channelInfo,
808     Streaming::StreamProcessor *processor,
809     Streaming::Port::E_Direction direction) {
810
811     std::string id=std::string("dev?");
812     if(!getOption("id", id)) {
813         debugWarning("Could not retrieve id parameter, defauling to 'dev?'\n");
814     }
815
816     std::ostringstream portname;
817     portname << id;
818     if(direction == Streaming::Port::E_Playback) {
819         portname << "p";
820     } else {
821         portname << "c";
822     }
823
824     portname << "_" << channelInfo->name;
825
826     Streaming::Port *p=NULL;
827     switch(channelInfo->portType) {
828     case ePT_Analog:
829         p=new Streaming::AmdtpAudioPort(
830                 portname.str(),
831                 direction,
832                 channelInfo->streamPosition,
833                 channelInfo->streamLocation,
834                 Streaming::AmdtpPortInfo::E_MBLA
835         );
836         break;
837
838     case ePT_MIDI:
839         p=new Streaming::AmdtpMidiPort(
840                 portname.str(),
841                 direction,
842                 channelInfo->streamPosition,
843                 channelInfo->streamLocation,
844                 Streaming::AmdtpPortInfo::E_Midi
845         );
846
847         break;
848     default:
849     // unsupported
850         break;
851     }
852
853     if (!p) {
854         debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",channelInfo->name.c_str());
855     } else {
856
857         if (!processor->addPort(p)) {
858             debugWarning("Could not register port with stream processor\n");
859             return false;
860         }
861     }
862
863     return true;
864 }
865
866 bool
867 DiceAvDevice::lock() {
868     fb_octlet_t result;
869
870     debugOutput(DEBUG_LEVEL_VERBOSE, "Locking %s %s at node %d\n",
871         m_model->vendor_name, m_model->model_name, getNodeId());
872
873     // get a notifier to handle device notifications
874     nodeaddr_t notify_address;
875     notify_address = get1394Service().findFreeARMBlock(
876                         DICE_NOTIFIER_BASE_ADDRESS,
877                         DICE_NOTIFIER_BLOCK_LENGTH,
878                         DICE_NOTIFIER_BLOCK_LENGTH);
879
880     if (notify_address == 0xFFFFFFFFFFFFFFFFLLU) {
881         debugError("Could not find free ARM block for notification\n");
882         return false;
883     }
884
885     m_notifier=new DiceAvDevice::DiceNotifier(this, notify_address);
886
887     if(!m_notifier) {
888         debugError("Could not allocate notifier\n");
889         return false;
890     }
891
892     if (!get1394Service().registerARMHandler(m_notifier)) {
893         debugError("Could not register notifier\n");
894         delete m_notifier;
895         m_notifier=NULL;
896         return false;
897     }
898
899     // register this notifier
900     fb_nodeaddr_t addr = DICE_REGISTER_BASE
901                        + m_global_reg_offset
902                        + DICE_REGISTER_GLOBAL_OWNER;
903
904     // registry offsets should always be smaller than 0x7FFFFFFF
905     // because otherwise base + offset > 64bit
906     if(m_global_reg_offset & 0x80000000) {
907         debugError("register offset not initialized yet\n");
908         return false;
909     }
910
911     fb_nodeaddr_t swap_value = ((0xFFC0) | get1394Service().getLocalNodeId());
912     swap_value = swap_value << 48;
913     swap_value |= m_notifier->getStart();
914
915     if (!get1394Service().lockCompareSwap64(  getNodeId() | 0xFFC0, addr, DICE_OWNER_NO_OWNER,
916                                        swap_value, &result )) {
917         debugWarning("Could not register ourselves as device owner\n");
918         return false;
919     }
920
921     if (result != DICE_OWNER_NO_OWNER) {
922         debugWarning("Could not register ourselves as device owner, unexpected register value: 0x%016llX\n", result);
923         return false;
924     }
925
926     return true;
927 }
928
929
930 bool
931 DiceAvDevice::unlock() {
932     fb_octlet_t result;
933
934     if(!m_notifier) {
935         debugWarning("Request to unlock, but no notifier present!\n");
936         return false;
937     }
938
939     fb_nodeaddr_t addr = DICE_REGISTER_BASE
940                        + m_global_reg_offset
941                        + DICE_REGISTER_GLOBAL_OWNER;
942
943     // registry offsets should always be smaller than 0x7FFFFFFF
944     // because otherwise base + offset > 64bit
945     if(m_global_reg_offset & 0x80000000) {
946         debugError("register offset not initialized yet\n");
947         return false;
948     }
949
950     fb_nodeaddr_t compare_value = ((0xFFC0) | get1394Service().getLocalNodeId());
951     compare_value <<= 48;
952     compare_value |= m_notifier->getStart();
953
954     if (!get1394Service().lockCompareSwap64(  getNodeId() | 0xFFC0, addr, compare_value,
955                                        DICE_OWNER_NO_OWNER, &result )) {
956         debugWarning("Could not unregister ourselves as device owner\n");
957         return false;
958     }
959
960     get1394Service().unregisterARMHandler(m_notifier);
961     delete m_notifier;
962     m_notifier=NULL;
963
964     return true;
965 }
966
967 bool
968 DiceAvDevice::enableStreaming() {
969     return enableIsoStreaming();
970 }
971
972 bool
973 DiceAvDevice::disableStreaming() {
974     return disableIsoStreaming();
975 }
976
977 int
978 DiceAvDevice::getStreamCount() {
979     return m_receiveProcessors.size() + m_transmitProcessors.size();
980 }
981
982 Streaming::StreamProcessor *
983 DiceAvDevice::getStreamProcessorByIndex(int i) {
984
985     if (i<(int)m_receiveProcessors.size()) {
986         return m_receiveProcessors.at(i);
987     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
988         return m_transmitProcessors.at(i-m_receiveProcessors.size());
989     }
990
991     return NULL;
992 }
993
994 bool
995 DiceAvDevice::startStreamByIndex(int i) {
996
997     if (isIsoStreamingEnabled()) {
998         debugError("Cannot start streams while streaming is enabled\n");
999         return false;
1000     }
1001
1002     if (i<(int)m_receiveProcessors.size()) {
1003         int n=i;
1004         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
1005
1006         // allocate ISO channel
1007         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
1008         if(isochannel<0) {
1009             debugError("Could not allocate iso channel for SP %d (ATX %d)\n",i,n);
1010             return false;
1011         }
1012         p->setChannel(isochannel);
1013
1014         fb_quadlet_t reg_isoch;
1015         // check value of ISO_CHANNEL register
1016         if(!readTxReg(n, DICE_REGISTER_TX_ISOC_BASE, &reg_isoch)) {
1017             debugError("Could not read ISO_CHANNEL register for ATX %d\n", n);
1018             p->setChannel(-1);
1019             deallocateIsoChannel(isochannel);
1020             return false;
1021         }
1022         if(reg_isoch != 0xFFFFFFFFUL) {
1023             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X) for ATX %d\n", reg_isoch, n);
1024             p->setChannel(-1);
1025             deallocateIsoChannel(isochannel);
1026             return false;
1027         }
1028
1029         // write value of ISO_CHANNEL register
1030         reg_isoch=isochannel;
1031         if(!writeTxReg(n, DICE_REGISTER_TX_ISOC_BASE, reg_isoch)) {
1032             debugError("Could not write ISO_CHANNEL register for ATX %d\n", n);
1033             p->setChannel(-1);
1034             deallocateIsoChannel(isochannel);
1035             return false;
1036         }
1037
1038         return true;
1039
1040     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
1041         int n=i-m_receiveProcessors.size();
1042         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
1043
1044         // allocate ISO channel
1045         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
1046         if(isochannel<0) {
1047             debugError("Could not allocate iso channel for SP %d (ATX %d)\n",i,n);
1048             return false;
1049         }
1050         p->setChannel(isochannel);
1051
1052         fb_quadlet_t reg_isoch;
1053         // check value of ISO_CHANNEL register
1054         if(!readRxReg(n, DICE_REGISTER_RX_ISOC_BASE, &reg_isoch)) {
1055             debugError("Could not read ISO_CHANNEL register for ARX %d\n", n);
1056             p->setChannel(-1);
1057             deallocateIsoChannel(isochannel);
1058             return false;
1059         }
1060         if(reg_isoch != 0xFFFFFFFFUL) {
1061             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X) for ARX %d\n", reg_isoch, n);
1062             p->setChannel(-1);
1063             deallocateIsoChannel(isochannel);
1064             return false;
1065         }
1066
1067         // write value of ISO_CHANNEL register
1068         reg_isoch=isochannel;
1069         if(!writeRxReg(n, DICE_REGISTER_RX_ISOC_BASE, reg_isoch)) {
1070             debugError("Could not write ISO_CHANNEL register for ARX %d\n", n);
1071             p->setChannel(-1);
1072             deallocateIsoChannel(isochannel);
1073             return false;
1074         }
1075
1076         return true;
1077     }
1078
1079     debugError("SP index %d out of range!\n",i);
1080
1081     return false;
1082 }
1083
1084 bool
1085 DiceAvDevice::stopStreamByIndex(int i) {
1086
1087     if (isIsoStreamingEnabled()) {
1088         debugError("Cannot stop streams while streaming is enabled\n");
1089         return false;
1090     }
1091
1092     if (i<(int)m_receiveProcessors.size()) {
1093         int n=i;
1094         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
1095         unsigned int isochannel=p->getChannel();
1096
1097         fb_quadlet_t reg_isoch;
1098         // check value of ISO_CHANNEL register
1099         if(!readTxReg(n, DICE_REGISTER_TX_ISOC_BASE, &reg_isoch)) {
1100             debugError("Could not read ISO_CHANNEL register for ATX %d\n", n);
1101             return false;
1102         }
1103         if(reg_isoch != isochannel) {
1104             debugError("ISO_CHANNEL register != 0x%08X (=0x%08X) for ATX %d\n", isochannel, reg_isoch, n);
1105             return false;
1106         }
1107
1108         // write value of ISO_CHANNEL register
1109         reg_isoch=0xFFFFFFFFUL;
1110         if(!writeTxReg(n, DICE_REGISTER_TX_ISOC_BASE, reg_isoch)) {
1111             debugError("Could not write ISO_CHANNEL register for ATX %d\n", n);
1112             return false;
1113         }
1114
1115         // deallocate ISO channel
1116         if(!deallocateIsoChannel(isochannel)) {
1117             debugError("Could not deallocate iso channel for SP %d (ATX %d)\n",i,n);
1118             return false;
1119         }
1120
1121         p->setChannel(-1);
1122         return true;
1123
1124     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
1125         int n=i-m_receiveProcessors.size();
1126         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
1127
1128         unsigned int isochannel=p->getChannel();
1129
1130         fb_quadlet_t reg_isoch;
1131         // check value of ISO_CHANNEL register
1132         if(!readRxReg(n, DICE_REGISTER_RX_ISOC_BASE, &reg_isoch)) {
1133             debugError("Could not read ISO_CHANNEL register for ARX %d\n", n);
1134             return false;
1135         }
1136         if(reg_isoch != isochannel) {
1137             debugError("ISO_CHANNEL register != 0x%08X (=0x%08X) for ARX %d\n", isochannel, reg_isoch, n);
1138             return false;
1139         }
1140
1141         // write value of ISO_CHANNEL register
1142         reg_isoch=0xFFFFFFFFUL;
1143         if(!writeRxReg(n, DICE_REGISTER_RX_ISOC_BASE, reg_isoch)) {
1144             debugError("Could not write ISO_CHANNEL register for ARX %d\n", n);
1145             return false;
1146         }
1147
1148         // deallocate ISO channel
1149         if(!deallocateIsoChannel(isochannel)) {
1150             debugError("Could not deallocate iso channel for SP %d (ARX %d)\n",i,n);
1151             return false;
1152         }
1153
1154         p->setChannel(-1);
1155         return true;
1156     }
1157
1158     debugError("SP index %d out of range!\n",i);
1159
1160     return false;
1161 }
1162
1163 // helper routines
1164
1165 // allocate ISO resources for the SP's
1166 int DiceAvDevice::allocateIsoChannel(unsigned int packet_size) {
1167     unsigned int bandwidth=8+packet_size;
1168
1169     int ch=get1394Service().allocateIsoChannelGeneric(bandwidth);
1170
1171     debugOutput(DEBUG_LEVEL_VERBOSE, "allocated channel %d, bandwidth %d\n",
1172         ch, bandwidth);
1173
1174     return ch;
1175 }
1176 // deallocate ISO resources
1177 bool DiceAvDevice::deallocateIsoChannel(int channel) {
1178     debugOutput(DEBUG_LEVEL_VERBOSE, "freeing channel %d\n",channel);
1179     return get1394Service().freeIsoChannel(channel);
1180 }
1181
1182 bool
1183 DiceAvDevice::enableIsoStreaming() {
1184     return writeGlobalReg(DICE_REGISTER_GLOBAL_ENABLE, DICE_ISOSTREAMING_ENABLE);
1185 }
1186
1187 bool
1188 DiceAvDevice::disableIsoStreaming() {
1189     return writeGlobalReg(DICE_REGISTER_GLOBAL_ENABLE, DICE_ISOSTREAMING_DISABLE);
1190 }
1191
1192 bool
1193 DiceAvDevice::isIsoStreamingEnabled() {
1194     fb_quadlet_t result;
1195     readGlobalReg(DICE_REGISTER_GLOBAL_ENABLE, &result);
1196     // I don't know what exactly is 'enable',
1197     // but disable is definately == 0
1198     return (result != DICE_ISOSTREAMING_DISABLE);
1199 }
1200
1201 /**
1202  * @brief performs a masked bit register equals 0 check on the global parameter space
1203  * @return true if readGlobalReg(offset) & mask == 0
1204  */
1205 bool
1206 DiceAvDevice::maskedCheckZeroGlobalReg(fb_nodeaddr_t offset, fb_quadlet_t mask) {
1207     fb_quadlet_t result;
1208     readGlobalReg(offset, &result);
1209     return ((result & mask) == 0);
1210 }
1211 /**
1212  * @brief performs a masked bit register not equal to 0 check on the global parameter space
1213  * @return true if readGlobalReg(offset) & mask != 0
1214  */
1215 bool
1216 DiceAvDevice::maskedCheckNotZeroGlobalReg(fb_nodeaddr_t offset, fb_quadlet_t mask) {
1217     return !maskedCheckZeroGlobalReg(offset, mask);
1218 }
1219
1220 DiceAvDevice::diceNameVector
1221 DiceAvDevice::getTxNameString(unsigned int i) {
1222     diceNameVector names;
1223     char namestring[DICE_TX_NAMES_SIZE+1];
1224
1225     if (!readTxRegBlock(i, DICE_REGISTER_TX_NAMES_BASE,
1226                         (fb_quadlet_t *)namestring, DICE_TX_NAMES_SIZE)) {
1227         debugError("Could not read TX name string \n");
1228         return names;
1229     }
1230
1231     namestring[DICE_TX_NAMES_SIZE]='\0';
1232     return splitNameString(std::string(namestring));
1233 }
1234
1235 DiceAvDevice::diceNameVector
1236 DiceAvDevice::getRxNameString(unsigned int i) {
1237     diceNameVector names;
1238     char namestring[DICE_RX_NAMES_SIZE+1];
1239
1240     if (!readRxRegBlock(i, DICE_REGISTER_RX_NAMES_BASE,
1241                         (fb_quadlet_t *)namestring, DICE_RX_NAMES_SIZE)) {
1242         debugError("Could not read RX name string \n");
1243         return names;
1244     }
1245
1246     namestring[DICE_RX_NAMES_SIZE]='\0';
1247     return splitNameString(std::string(namestring));
1248 }
1249
1250 DiceAvDevice::diceNameVector
1251 DiceAvDevice::getClockSourceNameString() {
1252     diceNameVector names;
1253     char namestring[DICE_CLOCKSOURCENAMES_SIZE+1];
1254
1255     if (!readGlobalRegBlock(DICE_REGISTER_GLOBAL_CLOCKSOURCENAMES,
1256                         (fb_quadlet_t *)namestring, DICE_CLOCKSOURCENAMES_SIZE)) {
1257         debugError("Could not read CLOCKSOURCE name string \n");
1258         return names;
1259     }
1260
1261     namestring[DICE_CLOCKSOURCENAMES_SIZE]='\0';
1262     return splitNameString(std::string(namestring));
1263 }
1264
1265 std::string
1266 DiceAvDevice::getDeviceNickName() {
1267     char namestring[DICE_NICK_NAME_SIZE+1];
1268
1269     if (!readGlobalRegBlock(DICE_REGISTER_GLOBAL_NICK_NAME,
1270                         (fb_quadlet_t *)namestring, DICE_NICK_NAME_SIZE)) {
1271         debugError("Could not read nickname string \n");
1272         return std::string("(unknown)");
1273     }
1274
1275     namestring[DICE_NICK_NAME_SIZE]='\0';
1276     return std::string(namestring);
1277 }
1278
1279 DiceAvDevice::diceNameVector
1280 DiceAvDevice::splitNameString(std::string in) {
1281     diceNameVector names;
1282
1283     // find the end of the string
1284     unsigned int end=in.find(string("\\\\"));
1285     // cut the end
1286     in=in.substr(0,end);
1287
1288     unsigned int cut;
1289     while( (cut = in.find(string("\\"))) != in.npos ) {
1290         if(cut > 0) {
1291             names.push_back(in.substr(0,cut));
1292         }
1293         in = in.substr(cut+1);
1294     }
1295     if(in.length() > 0) {
1296         names.push_back(in);
1297     }
1298     return names;
1299 }
1300
1301
1302 // I/O routines
1303 bool
1304 DiceAvDevice::initIoFunctions() {
1305
1306     // offsets and sizes are returned in quadlets, but we use byte values
1307
1308     if(!readReg(DICE_REGISTER_GLOBAL_PAR_SPACE_OFF, &m_global_reg_offset)) {
1309         debugError("Could not initialize m_global_reg_offset\n");
1310         return false;
1311     }
1312     m_global_reg_offset*=4;
1313
1314     if(!readReg(DICE_REGISTER_GLOBAL_PAR_SPACE_SZ, &m_global_reg_size)) {
1315         debugError("Could not initialize m_global_reg_size\n");
1316         return false;
1317     }
1318     m_global_reg_size*=4;
1319
1320     if(!readReg(DICE_REGISTER_TX_PAR_SPACE_OFF, &m_tx_reg_offset)) {
1321         debugError("Could not initialize m_tx_reg_offset\n");
1322         return false;
1323     }
1324     m_tx_reg_offset*=4;
1325
1326     if(!readReg(DICE_REGISTER_TX_PAR_SPACE_SZ, &m_tx_reg_size)) {
1327         debugError("Could not initialize m_tx_reg_size\n");
1328         return false;
1329     }
1330     m_tx_reg_size*=4;
1331
1332     if(!readReg(DICE_REGISTER_RX_PAR_SPACE_OFF, &m_rx_reg_offset)) {
1333         debugError("Could not initialize m_rx_reg_offset\n");
1334         return false;
1335     }
1336     m_rx_reg_offset*=4;
1337
1338     if(!readReg(DICE_REGISTER_RX_PAR_SPACE_SZ, &m_rx_reg_size)) {
1339         debugError("Could not initialize m_rx_reg_size\n");
1340         return false;
1341     }
1342     m_rx_reg_size*=4;
1343
1344     if(!readReg(DICE_REGISTER_UNUSED1_SPACE_OFF, &m_unused1_reg_offset)) {
1345         debugError("Could not initialize m_unused1_reg_offset\n");
1346         return false;
1347     }
1348     m_unused1_reg_offset*=4;
1349
1350     if(!readReg(DICE_REGISTER_UNUSED1_SPACE_SZ, &m_unused1_reg_size)) {
1351         debugError("Could not initialize m_unused1_reg_size\n");
1352         return false;
1353     }
1354     m_unused1_reg_size*=4;
1355
1356     if(!readReg(DICE_REGISTER_UNUSED2_SPACE_OFF, &m_unused2_reg_offset)) {
1357         debugError("Could not initialize m_unused2_reg_offset\n");
1358         return false;
1359     }
1360     m_unused2_reg_offset*=4;
1361
1362     if(!readReg(DICE_REGISTER_UNUSED2_SPACE_SZ, &m_unused2_reg_size)) {
1363         debugError("Could not initialize m_unused2_reg_size\n");
1364         return false;
1365     }
1366     m_unused2_reg_size*=4;
1367
1368     if(!readReg(m_tx_reg_offset + DICE_REGISTER_TX_NB_TX, &m_nb_tx)) {
1369         debugError("Could not initialize m_nb_tx\n");
1370         return false;
1371     }
1372     if(!readReg(m_tx_reg_offset + DICE_REGISTER_TX_SZ_TX, &m_tx_size)) {
1373         debugError("Could not initialize m_tx_size\n");
1374         return false;
1375     }
1376     m_tx_size*=4;
1377
1378     if(!readReg(m_tx_reg_offset + DICE_REGISTER_RX_NB_RX, &m_nb_rx)) {
1379         debugError("Could not initialize m_nb_rx\n");
1380         return false;
1381     }
1382     if(!readReg(m_tx_reg_offset + DICE_REGISTER_RX_SZ_RX, &m_rx_size)) {
1383         debugError("Could not initialize m_rx_size\n");
1384         return false;
1385     }
1386     m_rx_size*=4;
1387
1388     debugOutput(DEBUG_LEVEL_VERBOSE,"DICE Parameter Space info:\n");
1389     debugOutput(DEBUG_LEVEL_VERBOSE," Global  : offset=%04X size=%04d\n", m_global_reg_offset, m_global_reg_size);
1390     debugOutput(DEBUG_LEVEL_VERBOSE," TX      : offset=%04X size=%04d\n", m_tx_reg_offset, m_tx_reg_size);
1391     debugOutput(DEBUG_LEVEL_VERBOSE,"               nb=%4d size=%04d\n", m_nb_tx, m_tx_size);
1392     debugOutput(DEBUG_LEVEL_VERBOSE," RX      : offset=%04X size=%04d\n", m_rx_reg_offset, m_rx_reg_size);
1393     debugOutput(DEBUG_LEVEL_VERBOSE,"               nb=%4d size=%04d\n", m_nb_rx, m_rx_size);
1394     debugOutput(DEBUG_LEVEL_VERBOSE," UNUSED1 : offset=%04X size=%04d\n", m_unused1_reg_offset, m_unused1_reg_size);
1395     debugOutput(DEBUG_LEVEL_VERBOSE," UNUSED2 : offset=%04X size=%04d\n", m_unused2_reg_offset, m_unused2_reg_size);
1396
1397     return true;
1398 }
1399
1400 bool
1401 DiceAvDevice::readReg(fb_nodeaddr_t offset, fb_quadlet_t *result) {
1402     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX\n", offset);
1403
1404     if(offset >= DICE_INVALID_OFFSET) {
1405         debugError("invalid offset: 0x%016llX\n", offset);
1406         return false;
1407     }
1408
1409     fb_nodeaddr_t addr=DICE_REGISTER_BASE + offset;
1410     fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
1411
1412     if(!get1394Service().read_quadlet( nodeId, addr, result ) ) {
1413         debugError("Could not read from node 0x%04X addr 0x%012X\n", nodeId, addr);
1414         return false;
1415     }
1416
1417     *result=ntohl(*result);
1418
1419     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Read result: 0x%08X\n", *result);
1420
1421     return true;
1422 }
1423
1424 bool
1425 DiceAvDevice::writeReg(fb_nodeaddr_t offset, fb_quadlet_t data) {
1426     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, data: 0x%08X\n",
1427         offset, data);
1428
1429     if(offset >= DICE_INVALID_OFFSET) {
1430         debugError("invalid offset: 0x%016llX\n", offset);
1431         return false;
1432     }
1433
1434     fb_nodeaddr_t addr=DICE_REGISTER_BASE + offset;
1435     fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
1436
1437     if(!get1394Service().write_quadlet( nodeId, addr, htonl(data) ) ) {
1438         debugError("Could not write to node 0x%04X addr 0x%012X\n", nodeId, addr);
1439         return false;
1440     }
1441     return true;
1442 }
1443
1444 bool
1445 DiceAvDevice::readRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1446     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX, length %u\n",
1447         offset, length);
1448
1449     if(offset >= DICE_INVALID_OFFSET) {
1450         debugError("invalid offset: 0x%016llX\n", offset);
1451         return false;
1452     }
1453
1454     fb_nodeaddr_t addr=DICE_REGISTER_BASE + offset;
1455     fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
1456
1457     if(!get1394Service().read( nodeId, addr, length/4, data ) ) {
1458         debugError("Could not read from node 0x%04X addr 0x%012llX\n", nodeId, addr);
1459         return false;
1460     }
1461
1462     for(unsigned int i=0;i<length/4;i++) {
1463         *(data+i)=ntohl(*(data+i));
1464     }
1465
1466     return true;
1467 }
1468
1469 bool
1470 DiceAvDevice::writeRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1471     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, length: %u\n",
1472         offset, length);
1473
1474     if(offset >= DICE_INVALID_OFFSET) {
1475         debugError("invalid offset: 0x%016llX\n", offset);
1476         return false;
1477     }
1478
1479     fb_nodeaddr_t addr=DICE_REGISTER_BASE + offset;
1480     fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
1481
1482     fb_quadlet_t data_out[length/4];
1483
1484     for(unsigned int i=0;i<length/4;i++) {
1485         data_out[i]=ntohl(*(data+i));
1486     }
1487
1488     if(!get1394Service().write( nodeId, addr, length/4, data_out ) ) {
1489         debugError("Could not write to node 0x%04X addr 0x%012llX\n", nodeId, addr);
1490         return false;
1491     }
1492
1493     return true;
1494 }
1495
1496 bool
1497 DiceAvDevice::readGlobalReg(fb_nodeaddr_t offset, fb_quadlet_t *result) {
1498     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading global register offset 0x%04llX\n", offset);
1499
1500     fb_nodeaddr_t offset_gl=globalOffsetGen(offset, sizeof(fb_quadlet_t));
1501     return readReg(m_global_reg_offset + offset_gl, result);
1502 }
1503
1504 bool
1505 DiceAvDevice::writeGlobalReg(fb_nodeaddr_t offset, fb_quadlet_t data) {
1506     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing global register offset 0x%08llX, data: 0x%08X\n",
1507         offset, data);
1508
1509     fb_nodeaddr_t offset_gl=globalOffsetGen(offset, sizeof(fb_quadlet_t));
1510     return writeReg(m_global_reg_offset + offset_gl, data);
1511 }
1512
1513 bool
1514 DiceAvDevice::readGlobalRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1515     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading global register block offset 0x%04llX, length %u bytes\n",
1516         offset, length);
1517
1518     fb_nodeaddr_t offset_gl=globalOffsetGen(offset, length);
1519     return readRegBlock(m_global_reg_offset + offset_gl, data, length);
1520 }
1521
1522 bool
1523 DiceAvDevice::writeGlobalRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1524     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing global register block offset 0x%04llX, length %u bytes\n",
1525         offset, length);
1526
1527     fb_nodeaddr_t offset_gl=globalOffsetGen(offset, length);
1528     return writeRegBlock(m_global_reg_offset + offset_gl, data, length);
1529 }
1530
1531 fb_nodeaddr_t
1532 DiceAvDevice::globalOffsetGen(fb_nodeaddr_t offset, size_t length) {
1533
1534     // registry offsets should always be smaller than 0x7FFFFFFF
1535     // because otherwise base + offset > 64bit
1536     if(m_global_reg_offset & 0x80000000) {
1537         debugError("register offset not initialized yet\n");
1538         return DICE_INVALID_OFFSET;
1539     }
1540     // out-of-range check
1541     if(offset+length > m_global_reg_offset+m_global_reg_size) {
1542         debugError("register offset+length too large: 0x%0llX\n", offset + length);
1543         return DICE_INVALID_OFFSET;
1544     }
1545
1546     return offset;
1547 }
1548
1549 bool
1550 DiceAvDevice::readTxReg(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *result) {
1551     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading tx %d register offset 0x%04llX\n", i, offset);
1552
1553     fb_nodeaddr_t offset_tx=txOffsetGen(i, offset, sizeof(fb_quadlet_t));
1554     return readReg(m_tx_reg_offset + offset_tx, result);
1555 }
1556
1557 bool
1558 DiceAvDevice::writeTxReg(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t data) {
1559     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing tx %d register offset 0x%08llX, data: 0x%08X\n",
1560         i, offset, data);
1561
1562     fb_nodeaddr_t offset_tx=txOffsetGen(i, offset, sizeof(fb_quadlet_t));
1563     return writeReg(m_tx_reg_offset + offset_tx, data);
1564 }
1565
1566 bool
1567 DiceAvDevice::readTxRegBlock(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1568     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading rx register block offset 0x%04llX, length %u bytes\n",
1569         offset, length);
1570
1571     fb_nodeaddr_t offset_tx=txOffsetGen(i, offset, length);
1572     return readRegBlock(m_tx_reg_offset + offset_tx, data, length);
1573 }
1574
1575 bool
1576 DiceAvDevice::writeTxRegBlock(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1577     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing rx register block offset 0x%04llX, length %u bytes\n",
1578         offset, length);
1579
1580     fb_nodeaddr_t offset_tx=txOffsetGen(i, offset, length);
1581     return writeRegBlock(m_tx_reg_offset + offset_tx, data, length);
1582 }
1583
1584 fb_nodeaddr_t
1585 DiceAvDevice::txOffsetGen(unsigned int i, fb_nodeaddr_t offset, size_t length) {
1586     // registry offsets should always be smaller than 0x7FFFFFFF
1587     // because otherwise base + offset > 64bit
1588     if(m_tx_reg_offset & 0x80000000) {
1589         debugError("register offset not initialized yet\n");
1590         return DICE_INVALID_OFFSET;
1591     }
1592     if(m_nb_tx & 0x80000000) {
1593         debugError("m_nb_tx not initialized yet\n");
1594         return DICE_INVALID_OFFSET;
1595     }
1596     if(m_tx_size & 0x80000000) {
1597         debugError("m_tx_size not initialized yet\n");
1598         return DICE_INVALID_OFFSET;
1599     }
1600     if(i >= m_nb_tx) {
1601         debugError("TX index out of range\n");
1602         return DICE_INVALID_OFFSET;
1603     }
1604
1605     fb_nodeaddr_t offset_tx = DICE_REGISTER_TX_PARAM(m_tx_size, i, offset);
1606
1607     // out-of-range check
1608     if(offset_tx + length > m_tx_reg_offset+4+m_tx_reg_size*m_nb_tx) {
1609         debugError("register offset+length too large: 0x%0llX\n", offset_tx + length);
1610         return DICE_INVALID_OFFSET;
1611     }
1612
1613     return offset_tx;
1614 }
1615
1616 bool
1617 DiceAvDevice::readRxReg(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *result) {
1618     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading rx %d register offset 0x%04llX\n", i, offset);
1619
1620     fb_nodeaddr_t offset_rx=rxOffsetGen(i, offset, sizeof(fb_quadlet_t));
1621     return readReg(m_rx_reg_offset + offset_rx, result);
1622 }
1623
1624 bool
1625 DiceAvDevice::writeRxReg(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t data) {
1626     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing rx register offset 0x%08llX, data: 0x%08X\n",
1627         offset, data);
1628
1629     fb_nodeaddr_t offset_rx=rxOffsetGen(i, offset, sizeof(fb_quadlet_t));
1630     return writeReg(m_rx_reg_offset + offset_rx, data);
1631 }
1632
1633 bool
1634 DiceAvDevice::readRxRegBlock(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1635     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading rx register block offset 0x%04llX, length %u bytes\n",
1636         offset, length);
1637
1638     fb_nodeaddr_t offset_rx=rxOffsetGen(i, offset, length);
1639     return readRegBlock(m_rx_reg_offset + offset_rx, data, length);
1640 }
1641
1642 bool
1643 DiceAvDevice::writeRxRegBlock(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1644     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing rx register block offset 0x%04llX, length %u bytes\n",
1645         offset, length);
1646
1647     fb_nodeaddr_t offset_rx=rxOffsetGen(i, offset, length);
1648     return writeRegBlock(m_rx_reg_offset + offset_rx, data, length);
1649 }
1650
1651 fb_nodeaddr_t
1652 DiceAvDevice::rxOffsetGen(unsigned int i, fb_nodeaddr_t offset, size_t length) {
1653     // registry offsets should always be smaller than 0x7FFFFFFF
1654     // because otherwise base + offset > 64bit
1655     if(m_rx_reg_offset & 0x80000000) {
1656         debugError("register offset not initialized yet\n");
1657         return DICE_INVALID_OFFSET;
1658     }
1659     if(m_nb_rx & 0x80000000) {
1660         debugError("m_nb_rx not initialized yet\n");
1661         return DICE_INVALID_OFFSET;
1662     }
1663     if(m_rx_size & 0x80000000) {
1664         debugError("m_rx_size not initialized yet\n");
1665         return DICE_INVALID_OFFSET;
1666     }
1667     if(i >= m_nb_rx) {
1668         debugError("RX index out of range\n");
1669         return DICE_INVALID_OFFSET;
1670     }
1671
1672     fb_nodeaddr_t offset_rx = DICE_REGISTER_RX_PARAM(m_rx_size, i, offset);
1673
1674     // out-of-range check
1675     if(offset_rx + length > m_rx_reg_offset+4+m_rx_reg_size*m_nb_rx) {
1676         debugError("register offset+length too large: 0x%0llX\n", offset_rx + length);
1677         return DICE_INVALID_OFFSET;
1678     }
1679     return offset_rx;
1680 }
1681
1682
1683 // the notifier
1684
1685 DiceAvDevice::DiceNotifier::DiceNotifier(DiceAvDevice *d, nodeaddr_t start)
1686  : ARMHandler(start, DICE_NOTIFIER_BLOCK_LENGTH,
1687               RAW1394_ARM_READ | RAW1394_ARM_WRITE | RAW1394_ARM_LOCK,
1688               RAW1394_ARM_WRITE, 0)
1689  , m_dicedevice(d)
1690 {
1691
1692 }
1693
1694 DiceAvDevice::DiceNotifier::~DiceNotifier()
1695 {
1696
1697 }
1698
1699 }
Note: See TracBrowser for help on using the browser.