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

Revision 745, 56.9 kB (checked in by ppalmers, 15 years ago)

implement clock source selection for DICE EVM

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( std::auto_ptr<ConfigRom>( configRom ))
55     : FFADODevice( 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( std::auto_ptr<ConfigRom>( configRom ))
110 {
111     return new DiceAvDevice( 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(
677                              get1394Service().getPort(),
678                              nb_channels);
679
680         if(!p->init()) {
681             debugFatal("Could not initialize receive processor!\n");
682             delete p;
683             continue;
684         }
685
686         // add audio ports to the processor
687         for (unsigned int j=0;j<nb_audio;j++) {
688             diceChannelInfo channelInfo;
689             channelInfo.name=names_audio.at(j);
690             channelInfo.portType=ePT_Analog;
691             channelInfo.streamPosition=j;
692             channelInfo.streamLocation=0;
693
694             if (!addChannelToProcessor(&channelInfo, p, Streaming::Port::E_Capture)) {
695                 debugError("Could not add channel %s to StreamProcessor\n",
696                     channelInfo.name.c_str());
697                 continue;
698             }
699         }
700
701         // add midi ports to the processor
702         for (unsigned int j=0;j<nb_midi;j++) {
703             diceChannelInfo channelInfo;
704             channelInfo.name=names_midi.at(j);
705             channelInfo.portType=ePT_MIDI;
706             channelInfo.streamPosition=nb_audio;
707             channelInfo.streamLocation=j;
708
709             if (!addChannelToProcessor(&channelInfo, p, Streaming::Port::E_Capture)) {
710                 debugError("Could not add channel %s to StreamProcessor\n",
711                     channelInfo.name.c_str());
712                 continue;
713             }
714         }
715
716         // add the SP to the vector
717         m_receiveProcessors.push_back(p);
718     }
719
720     // prepare transmit SP's
721     for (unsigned int i=0;i<m_nb_rx;i++) {
722         fb_quadlet_t nb_audio;
723         fb_quadlet_t nb_midi;
724         unsigned int nb_channels=0;
725
726         if(!readTxReg(i, DICE_REGISTER_RX_NB_AUDIO_BASE, &nb_audio)) {
727             debugError("Could not read DICE_REGISTER_RX_NB_AUDIO_BASE register for ARX%u",i);
728             continue;
729         }
730         if(!readTxReg(i, DICE_REGISTER_RX_MIDI_BASE, &nb_midi)) {
731             debugError("Could not read DICE_REGISTER_RX_MIDI_BASE register for ARX%u",i);
732             continue;
733         }
734
735         // request the channel names
736         diceNameVector names_audio=getRxNameString(i);
737
738         if (names_audio.size() != nb_audio) {
739             debugWarning("The audio channel name vector is incorrect, using default names\n");
740             names_audio.clear();
741
742             for (unsigned int j=0;j<nb_audio;j++) {
743                 std::ostringstream newname;
744                 newname << "output_" << j;
745                 names_audio.push_back(newname.str());
746             }
747         }
748
749         nb_channels=nb_audio;
750         if(nb_midi) nb_channels += 1; // midi-muxed counts as one
751
752         // construct the MIDI names
753         diceNameVector names_midi;
754         for (unsigned int j=0;j<nb_midi;j++) {
755             std::ostringstream newname;
756             newname << "midi_out_" << j;
757             names_midi.push_back(newname.str());
758         }
759
760         // construct the streamprocessor
761         Streaming::AmdtpTransmitStreamProcessor *p;
762         p=new Streaming::AmdtpTransmitStreamProcessor(
763                              get1394Service().getPort(),
764                              nb_channels);
765
766         if(!p->init()) {
767             debugFatal("Could not initialize transmit processor!\n");
768             delete p;
769             continue;
770         }
771
772         // add audio ports to the processor
773         for (unsigned int j=0;j<nb_audio;j++) {
774             diceChannelInfo channelInfo;
775             channelInfo.name=names_audio.at(j);
776             channelInfo.portType=ePT_Analog;
777             channelInfo.streamPosition=j;
778             channelInfo.streamLocation=0;
779
780             if (!addChannelToProcessor(&channelInfo, p, Streaming::Port::E_Playback)) {
781                 debugError("Could not add channel %s to StreamProcessor\n",
782                     channelInfo.name.c_str());
783                 continue;
784             }
785         }
786
787         // add midi ports to the processor
788         for (unsigned int j=0;j<nb_midi;j++) {
789             diceChannelInfo channelInfo;
790             channelInfo.name=names_midi.at(j);
791             channelInfo.portType=ePT_MIDI;
792             channelInfo.streamPosition=nb_audio;
793             channelInfo.streamLocation=j;
794
795             if (!addChannelToProcessor(&channelInfo, p, Streaming::Port::E_Playback)) {
796                 debugError("Could not add channel %s to StreamProcessor\n",
797                     channelInfo.name.c_str());
798                 continue;
799             }
800         }
801
802         m_transmitProcessors.push_back(p);
803     }
804     return true;
805 }
806
807 bool
808 DiceAvDevice::addChannelToProcessor(
809     diceChannelInfo *channelInfo,
810     Streaming::StreamProcessor *processor,
811     Streaming::Port::E_Direction direction) {
812
813     std::string id=std::string("dev?");
814     if(!getOption("id", id)) {
815         debugWarning("Could not retrieve id parameter, defauling to 'dev?'\n");
816     }
817
818     std::ostringstream portname;
819     portname << id;
820     if(direction == Streaming::Port::E_Playback) {
821         portname << "p";
822     } else {
823         portname << "c";
824     }
825
826     portname << "_" << channelInfo->name;
827
828     Streaming::Port *p=NULL;
829     switch(channelInfo->portType) {
830     case ePT_Analog:
831         p=new Streaming::AmdtpAudioPort(
832                 portname.str(),
833                 direction,
834                 channelInfo->streamPosition,
835                 channelInfo->streamLocation,
836                 Streaming::AmdtpPortInfo::E_MBLA
837         );
838         break;
839
840     case ePT_MIDI:
841         p=new Streaming::AmdtpMidiPort(
842                 portname.str(),
843                 direction,
844                 channelInfo->streamPosition,
845                 channelInfo->streamLocation,
846                 Streaming::AmdtpPortInfo::E_Midi
847         );
848
849         break;
850     default:
851     // unsupported
852         break;
853     }
854
855     if (!p) {
856         debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",channelInfo->name.c_str());
857     } else {
858
859         if (!processor->addPort(p)) {
860             debugWarning("Could not register port with stream processor\n");
861             return false;
862         }
863     }
864
865     return true;
866 }
867
868 bool
869 DiceAvDevice::lock() {
870     fb_octlet_t result;
871
872     debugOutput(DEBUG_LEVEL_VERBOSE, "Locking %s %s at node %d\n",
873         m_model->vendor_name, m_model->model_name, getNodeId());
874
875     // get a notifier to handle device notifications
876     nodeaddr_t notify_address;
877     notify_address = get1394Service().findFreeARMBlock(
878                         DICE_NOTIFIER_BASE_ADDRESS,
879                         DICE_NOTIFIER_BLOCK_LENGTH,
880                         DICE_NOTIFIER_BLOCK_LENGTH);
881
882     if (notify_address == 0xFFFFFFFFFFFFFFFFLLU) {
883         debugError("Could not find free ARM block for notification\n");
884         return false;
885     }
886
887     m_notifier=new DiceAvDevice::DiceNotifier(this, notify_address);
888
889     if(!m_notifier) {
890         debugError("Could not allocate notifier\n");
891         return false;
892     }
893
894     if (!get1394Service().registerARMHandler(m_notifier)) {
895         debugError("Could not register notifier\n");
896         delete m_notifier;
897         m_notifier=NULL;
898         return false;
899     }
900
901     // register this notifier
902     fb_nodeaddr_t addr = DICE_REGISTER_BASE
903                        + m_global_reg_offset
904                        + DICE_REGISTER_GLOBAL_OWNER;
905
906     // registry offsets should always be smaller than 0x7FFFFFFF
907     // because otherwise base + offset > 64bit
908     if(m_global_reg_offset & 0x80000000) {
909         debugError("register offset not initialized yet\n");
910         return false;
911     }
912
913     fb_nodeaddr_t swap_value = ((0xFFC0) | get1394Service().getLocalNodeId());
914     swap_value = swap_value << 48;
915     swap_value |= m_notifier->getStart();
916
917     if (!get1394Service().lockCompareSwap64(  getNodeId() | 0xFFC0, addr, DICE_OWNER_NO_OWNER,
918                                        swap_value, &result )) {
919         debugWarning("Could not register ourselves as device owner\n");
920         return false;
921     }
922
923     if (result != DICE_OWNER_NO_OWNER) {
924         debugWarning("Could not register ourselves as device owner, unexpected register value: 0x%016llX\n", result);
925         return false;
926     }
927
928     return true;
929 }
930
931
932 bool
933 DiceAvDevice::unlock() {
934     fb_octlet_t result;
935
936     if(!m_notifier) {
937         debugWarning("Request to unlock, but no notifier present!\n");
938         return false;
939     }
940
941     fb_nodeaddr_t addr = DICE_REGISTER_BASE
942                        + m_global_reg_offset
943                        + DICE_REGISTER_GLOBAL_OWNER;
944
945     // registry offsets should always be smaller than 0x7FFFFFFF
946     // because otherwise base + offset > 64bit
947     if(m_global_reg_offset & 0x80000000) {
948         debugError("register offset not initialized yet\n");
949         return false;
950     }
951
952     fb_nodeaddr_t compare_value = ((0xFFC0) | get1394Service().getLocalNodeId());
953     compare_value <<= 48;
954     compare_value |= m_notifier->getStart();
955
956     if (!get1394Service().lockCompareSwap64(  getNodeId() | 0xFFC0, addr, compare_value,
957                                        DICE_OWNER_NO_OWNER, &result )) {
958         debugWarning("Could not unregister ourselves as device owner\n");
959         return false;
960     }
961
962     get1394Service().unregisterARMHandler(m_notifier);
963     delete m_notifier;
964     m_notifier=NULL;
965
966     return true;
967 }
968
969 bool
970 DiceAvDevice::enableStreaming() {
971     return enableIsoStreaming();
972 }
973
974 bool
975 DiceAvDevice::disableStreaming() {
976     return disableIsoStreaming();
977 }
978
979 int
980 DiceAvDevice::getStreamCount() {
981     return m_receiveProcessors.size() + m_transmitProcessors.size();
982 }
983
984 Streaming::StreamProcessor *
985 DiceAvDevice::getStreamProcessorByIndex(int i) {
986
987     if (i<(int)m_receiveProcessors.size()) {
988         return m_receiveProcessors.at(i);
989     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
990         return m_transmitProcessors.at(i-m_receiveProcessors.size());
991     }
992
993     return NULL;
994 }
995
996 bool
997 DiceAvDevice::startStreamByIndex(int i) {
998
999     if (isIsoStreamingEnabled()) {
1000         debugError("Cannot start streams while streaming is enabled\n");
1001         return false;
1002     }
1003
1004     if (i<(int)m_receiveProcessors.size()) {
1005         int n=i;
1006         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
1007
1008         // allocate ISO channel
1009         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
1010         if(isochannel<0) {
1011             debugError("Could not allocate iso channel for SP %d (ATX %d)\n",i,n);
1012             return false;
1013         }
1014         p->setChannel(isochannel);
1015
1016         fb_quadlet_t reg_isoch;
1017         // check value of ISO_CHANNEL register
1018         if(!readTxReg(n, DICE_REGISTER_TX_ISOC_BASE, &reg_isoch)) {
1019             debugError("Could not read ISO_CHANNEL register for ATX %d\n", n);
1020             p->setChannel(-1);
1021             deallocateIsoChannel(isochannel);
1022             return false;
1023         }
1024         if(reg_isoch != 0xFFFFFFFFUL) {
1025             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X) for ATX %d\n", reg_isoch, n);
1026             p->setChannel(-1);
1027             deallocateIsoChannel(isochannel);
1028             return false;
1029         }
1030
1031         // write value of ISO_CHANNEL register
1032         reg_isoch=isochannel;
1033         if(!writeTxReg(n, DICE_REGISTER_TX_ISOC_BASE, reg_isoch)) {
1034             debugError("Could not write ISO_CHANNEL register for ATX %d\n", n);
1035             p->setChannel(-1);
1036             deallocateIsoChannel(isochannel);
1037             return false;
1038         }
1039
1040         return true;
1041
1042     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
1043         int n=i-m_receiveProcessors.size();
1044         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
1045
1046         // allocate ISO channel
1047         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
1048         if(isochannel<0) {
1049             debugError("Could not allocate iso channel for SP %d (ATX %d)\n",i,n);
1050             return false;
1051         }
1052         p->setChannel(isochannel);
1053
1054         fb_quadlet_t reg_isoch;
1055         // check value of ISO_CHANNEL register
1056         if(!readRxReg(n, DICE_REGISTER_RX_ISOC_BASE, &reg_isoch)) {
1057             debugError("Could not read ISO_CHANNEL register for ARX %d\n", n);
1058             p->setChannel(-1);
1059             deallocateIsoChannel(isochannel);
1060             return false;
1061         }
1062         if(reg_isoch != 0xFFFFFFFFUL) {
1063             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X) for ARX %d\n", reg_isoch, n);
1064             p->setChannel(-1);
1065             deallocateIsoChannel(isochannel);
1066             return false;
1067         }
1068
1069         // write value of ISO_CHANNEL register
1070         reg_isoch=isochannel;
1071         if(!writeRxReg(n, DICE_REGISTER_RX_ISOC_BASE, reg_isoch)) {
1072             debugError("Could not write ISO_CHANNEL register for ARX %d\n", n);
1073             p->setChannel(-1);
1074             deallocateIsoChannel(isochannel);
1075             return false;
1076         }
1077
1078         return true;
1079     }
1080
1081     debugError("SP index %d out of range!\n",i);
1082
1083     return false;
1084 }
1085
1086 bool
1087 DiceAvDevice::stopStreamByIndex(int i) {
1088
1089     if (isIsoStreamingEnabled()) {
1090         debugError("Cannot stop streams while streaming is enabled\n");
1091         return false;
1092     }
1093
1094     if (i<(int)m_receiveProcessors.size()) {
1095         int n=i;
1096         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
1097         unsigned int isochannel=p->getChannel();
1098
1099         fb_quadlet_t reg_isoch;
1100         // check value of ISO_CHANNEL register
1101         if(!readTxReg(n, DICE_REGISTER_TX_ISOC_BASE, &reg_isoch)) {
1102             debugError("Could not read ISO_CHANNEL register for ATX %d\n", n);
1103             return false;
1104         }
1105         if(reg_isoch != isochannel) {
1106             debugError("ISO_CHANNEL register != 0x%08X (=0x%08X) for ATX %d\n", isochannel, reg_isoch, n);
1107             return false;
1108         }
1109
1110         // write value of ISO_CHANNEL register
1111         reg_isoch=0xFFFFFFFFUL;
1112         if(!writeTxReg(n, DICE_REGISTER_TX_ISOC_BASE, reg_isoch)) {
1113             debugError("Could not write ISO_CHANNEL register for ATX %d\n", n);
1114             return false;
1115         }
1116
1117         // deallocate ISO channel
1118         if(!deallocateIsoChannel(isochannel)) {
1119             debugError("Could not deallocate iso channel for SP %d (ATX %d)\n",i,n);
1120             return false;
1121         }
1122
1123         p->setChannel(-1);
1124         return true;
1125
1126     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
1127         int n=i-m_receiveProcessors.size();
1128         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
1129
1130         unsigned int isochannel=p->getChannel();
1131
1132         fb_quadlet_t reg_isoch;
1133         // check value of ISO_CHANNEL register
1134         if(!readRxReg(n, DICE_REGISTER_RX_ISOC_BASE, &reg_isoch)) {
1135             debugError("Could not read ISO_CHANNEL register for ARX %d\n", n);
1136             return false;
1137         }
1138         if(reg_isoch != isochannel) {
1139             debugError("ISO_CHANNEL register != 0x%08X (=0x%08X) for ARX %d\n", isochannel, reg_isoch, n);
1140             return false;
1141         }
1142
1143         // write value of ISO_CHANNEL register
1144         reg_isoch=0xFFFFFFFFUL;
1145         if(!writeRxReg(n, DICE_REGISTER_RX_ISOC_BASE, reg_isoch)) {
1146             debugError("Could not write ISO_CHANNEL register for ARX %d\n", n);
1147             return false;
1148         }
1149
1150         // deallocate ISO channel
1151         if(!deallocateIsoChannel(isochannel)) {
1152             debugError("Could not deallocate iso channel for SP %d (ARX %d)\n",i,n);
1153             return false;
1154         }
1155
1156         p->setChannel(-1);
1157         return true;
1158     }
1159
1160     debugError("SP index %d out of range!\n",i);
1161
1162     return false;
1163 }
1164
1165 // helper routines
1166
1167 // allocate ISO resources for the SP's
1168 int DiceAvDevice::allocateIsoChannel(unsigned int packet_size) {
1169     unsigned int bandwidth=8+packet_size;
1170
1171     int ch=get1394Service().allocateIsoChannelGeneric(bandwidth);
1172
1173     debugOutput(DEBUG_LEVEL_VERBOSE, "allocated channel %d, bandwidth %d\n",
1174         ch, bandwidth);
1175
1176     return ch;
1177 }
1178 // deallocate ISO resources
1179 bool DiceAvDevice::deallocateIsoChannel(int channel) {
1180     debugOutput(DEBUG_LEVEL_VERBOSE, "freeing channel %d\n",channel);
1181     return get1394Service().freeIsoChannel(channel);
1182 }
1183
1184 bool
1185 DiceAvDevice::enableIsoStreaming() {
1186     return writeGlobalReg(DICE_REGISTER_GLOBAL_ENABLE, DICE_ISOSTREAMING_ENABLE);
1187 }
1188
1189 bool
1190 DiceAvDevice::disableIsoStreaming() {
1191     return writeGlobalReg(DICE_REGISTER_GLOBAL_ENABLE, DICE_ISOSTREAMING_DISABLE);
1192 }
1193
1194 bool
1195 DiceAvDevice::isIsoStreamingEnabled() {
1196     fb_quadlet_t result;
1197     readGlobalReg(DICE_REGISTER_GLOBAL_ENABLE, &result);
1198     // I don't know what exactly is 'enable',
1199     // but disable is definately == 0
1200     return (result != DICE_ISOSTREAMING_DISABLE);
1201 }
1202
1203 /**
1204  * @brief performs a masked bit register equals 0 check on the global parameter space
1205  * @return true if readGlobalReg(offset) & mask == 0
1206  */
1207 bool
1208 DiceAvDevice::maskedCheckZeroGlobalReg(fb_nodeaddr_t offset, fb_quadlet_t mask) {
1209     fb_quadlet_t result;
1210     readGlobalReg(offset, &result);
1211     return ((result & mask) == 0);
1212 }
1213 /**
1214  * @brief performs a masked bit register not equal to 0 check on the global parameter space
1215  * @return true if readGlobalReg(offset) & mask != 0
1216  */
1217 bool
1218 DiceAvDevice::maskedCheckNotZeroGlobalReg(fb_nodeaddr_t offset, fb_quadlet_t mask) {
1219     return !maskedCheckZeroGlobalReg(offset, mask);
1220 }
1221
1222 DiceAvDevice::diceNameVector
1223 DiceAvDevice::getTxNameString(unsigned int i) {
1224     diceNameVector names;
1225     char namestring[DICE_TX_NAMES_SIZE+1];
1226
1227     if (!readTxRegBlock(i, DICE_REGISTER_TX_NAMES_BASE,
1228                         (fb_quadlet_t *)namestring, DICE_TX_NAMES_SIZE)) {
1229         debugError("Could not read TX name string \n");
1230         return names;
1231     }
1232
1233     namestring[DICE_TX_NAMES_SIZE]='\0';
1234     return splitNameString(std::string(namestring));
1235 }
1236
1237 DiceAvDevice::diceNameVector
1238 DiceAvDevice::getRxNameString(unsigned int i) {
1239     diceNameVector names;
1240     char namestring[DICE_RX_NAMES_SIZE+1];
1241
1242     if (!readRxRegBlock(i, DICE_REGISTER_RX_NAMES_BASE,
1243                         (fb_quadlet_t *)namestring, DICE_RX_NAMES_SIZE)) {
1244         debugError("Could not read RX name string \n");
1245         return names;
1246     }
1247
1248     namestring[DICE_RX_NAMES_SIZE]='\0';
1249     return splitNameString(std::string(namestring));
1250 }
1251
1252 DiceAvDevice::diceNameVector
1253 DiceAvDevice::getClockSourceNameString() {
1254     diceNameVector names;
1255     char namestring[DICE_CLOCKSOURCENAMES_SIZE+1];
1256
1257     if (!readGlobalRegBlock(DICE_REGISTER_GLOBAL_CLOCKSOURCENAMES,
1258                         (fb_quadlet_t *)namestring, DICE_CLOCKSOURCENAMES_SIZE)) {
1259         debugError("Could not read CLOCKSOURCE name string \n");
1260         return names;
1261     }
1262
1263     namestring[DICE_CLOCKSOURCENAMES_SIZE]='\0';
1264     return splitNameString(std::string(namestring));
1265 }
1266
1267 std::string
1268 DiceAvDevice::getDeviceNickName() {
1269     char namestring[DICE_NICK_NAME_SIZE+1];
1270
1271     if (!readGlobalRegBlock(DICE_REGISTER_GLOBAL_NICK_NAME,
1272                         (fb_quadlet_t *)namestring, DICE_NICK_NAME_SIZE)) {
1273         debugError("Could not read nickname string \n");
1274         return std::string("(unknown)");
1275     }
1276
1277     namestring[DICE_NICK_NAME_SIZE]='\0';
1278     return std::string(namestring);
1279 }
1280
1281 DiceAvDevice::diceNameVector
1282 DiceAvDevice::splitNameString(std::string in) {
1283     diceNameVector names;
1284
1285     // find the end of the string
1286     unsigned int end=in.find(string("\\\\"));
1287     // cut the end
1288     in=in.substr(0,end);
1289
1290     unsigned int cut;
1291     while( (cut = in.find(string("\\"))) != in.npos ) {
1292         if(cut > 0) {
1293             names.push_back(in.substr(0,cut));
1294         }
1295         in = in.substr(cut+1);
1296     }
1297     if(in.length() > 0) {
1298         names.push_back(in);
1299     }
1300     return names;
1301 }
1302
1303
1304 // I/O routines
1305 bool
1306 DiceAvDevice::initIoFunctions() {
1307
1308     // offsets and sizes are returned in quadlets, but we use byte values
1309
1310     if(!readReg(DICE_REGISTER_GLOBAL_PAR_SPACE_OFF, &m_global_reg_offset)) {
1311         debugError("Could not initialize m_global_reg_offset\n");
1312         return false;
1313     }
1314     m_global_reg_offset*=4;
1315
1316     if(!readReg(DICE_REGISTER_GLOBAL_PAR_SPACE_SZ, &m_global_reg_size)) {
1317         debugError("Could not initialize m_global_reg_size\n");
1318         return false;
1319     }
1320     m_global_reg_size*=4;
1321
1322     if(!readReg(DICE_REGISTER_TX_PAR_SPACE_OFF, &m_tx_reg_offset)) {
1323         debugError("Could not initialize m_tx_reg_offset\n");
1324         return false;
1325     }
1326     m_tx_reg_offset*=4;
1327
1328     if(!readReg(DICE_REGISTER_TX_PAR_SPACE_SZ, &m_tx_reg_size)) {
1329         debugError("Could not initialize m_tx_reg_size\n");
1330         return false;
1331     }
1332     m_tx_reg_size*=4;
1333
1334     if(!readReg(DICE_REGISTER_RX_PAR_SPACE_OFF, &m_rx_reg_offset)) {
1335         debugError("Could not initialize m_rx_reg_offset\n");
1336         return false;
1337     }
1338     m_rx_reg_offset*=4;
1339
1340     if(!readReg(DICE_REGISTER_RX_PAR_SPACE_SZ, &m_rx_reg_size)) {
1341         debugError("Could not initialize m_rx_reg_size\n");
1342         return false;
1343     }
1344     m_rx_reg_size*=4;
1345
1346     if(!readReg(DICE_REGISTER_UNUSED1_SPACE_OFF, &m_unused1_reg_offset)) {
1347         debugError("Could not initialize m_unused1_reg_offset\n");
1348         return false;
1349     }
1350     m_unused1_reg_offset*=4;
1351
1352     if(!readReg(DICE_REGISTER_UNUSED1_SPACE_SZ, &m_unused1_reg_size)) {
1353         debugError("Could not initialize m_unused1_reg_size\n");
1354         return false;
1355     }
1356     m_unused1_reg_size*=4;
1357
1358     if(!readReg(DICE_REGISTER_UNUSED2_SPACE_OFF, &m_unused2_reg_offset)) {
1359         debugError("Could not initialize m_unused2_reg_offset\n");
1360         return false;
1361     }
1362     m_unused2_reg_offset*=4;
1363
1364     if(!readReg(DICE_REGISTER_UNUSED2_SPACE_SZ, &m_unused2_reg_size)) {
1365         debugError("Could not initialize m_unused2_reg_size\n");
1366         return false;
1367     }
1368     m_unused2_reg_size*=4;
1369
1370     if(!readReg(m_tx_reg_offset + DICE_REGISTER_TX_NB_TX, &m_nb_tx)) {
1371         debugError("Could not initialize m_nb_tx\n");
1372         return false;
1373     }
1374     if(!readReg(m_tx_reg_offset + DICE_REGISTER_TX_SZ_TX, &m_tx_size)) {
1375         debugError("Could not initialize m_tx_size\n");
1376         return false;
1377     }
1378     m_tx_size*=4;
1379
1380     if(!readReg(m_tx_reg_offset + DICE_REGISTER_RX_NB_RX, &m_nb_rx)) {
1381         debugError("Could not initialize m_nb_rx\n");
1382         return false;
1383     }
1384     if(!readReg(m_tx_reg_offset + DICE_REGISTER_RX_SZ_RX, &m_rx_size)) {
1385         debugError("Could not initialize m_rx_size\n");
1386         return false;
1387     }
1388     m_rx_size*=4;
1389
1390     debugOutput(DEBUG_LEVEL_VERBOSE,"DICE Parameter Space info:\n");
1391     debugOutput(DEBUG_LEVEL_VERBOSE," Global  : offset=%04X size=%04d\n", m_global_reg_offset, m_global_reg_size);
1392     debugOutput(DEBUG_LEVEL_VERBOSE," TX      : offset=%04X size=%04d\n", m_tx_reg_offset, m_tx_reg_size);
1393     debugOutput(DEBUG_LEVEL_VERBOSE,"               nb=%4d size=%04d\n", m_nb_tx, m_tx_size);
1394     debugOutput(DEBUG_LEVEL_VERBOSE," RX      : offset=%04X size=%04d\n", m_rx_reg_offset, m_rx_reg_size);
1395     debugOutput(DEBUG_LEVEL_VERBOSE,"               nb=%4d size=%04d\n", m_nb_rx, m_rx_size);
1396     debugOutput(DEBUG_LEVEL_VERBOSE," UNUSED1 : offset=%04X size=%04d\n", m_unused1_reg_offset, m_unused1_reg_size);
1397     debugOutput(DEBUG_LEVEL_VERBOSE," UNUSED2 : offset=%04X size=%04d\n", m_unused2_reg_offset, m_unused2_reg_size);
1398
1399     return true;
1400 }
1401
1402 bool
1403 DiceAvDevice::readReg(fb_nodeaddr_t offset, fb_quadlet_t *result) {
1404     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX\n", offset);
1405
1406     if(offset >= DICE_INVALID_OFFSET) {
1407         debugError("invalid offset: 0x%016llX\n", offset);
1408         return false;
1409     }
1410
1411     fb_nodeaddr_t addr=DICE_REGISTER_BASE + offset;
1412     fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
1413
1414     if(!get1394Service().read_quadlet( nodeId, addr, result ) ) {
1415         debugError("Could not read from node 0x%04X addr 0x%012X\n", nodeId, addr);
1416         return false;
1417     }
1418
1419     *result=ntohl(*result);
1420
1421     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Read result: 0x%08X\n", *result);
1422
1423     return true;
1424 }
1425
1426 bool
1427 DiceAvDevice::writeReg(fb_nodeaddr_t offset, fb_quadlet_t data) {
1428     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, data: 0x%08X\n",
1429         offset, data);
1430
1431     if(offset >= DICE_INVALID_OFFSET) {
1432         debugError("invalid offset: 0x%016llX\n", offset);
1433         return false;
1434     }
1435
1436     fb_nodeaddr_t addr=DICE_REGISTER_BASE + offset;
1437     fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
1438
1439     if(!get1394Service().write_quadlet( nodeId, addr, htonl(data) ) ) {
1440         debugError("Could not write to node 0x%04X addr 0x%012X\n", nodeId, addr);
1441         return false;
1442     }
1443     return true;
1444 }
1445
1446 bool
1447 DiceAvDevice::readRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1448     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX, length %u\n",
1449         offset, length);
1450
1451     if(offset >= DICE_INVALID_OFFSET) {
1452         debugError("invalid offset: 0x%016llX\n", offset);
1453         return false;
1454     }
1455
1456     fb_nodeaddr_t addr=DICE_REGISTER_BASE + offset;
1457     fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
1458
1459     if(!get1394Service().read( nodeId, addr, length/4, data ) ) {
1460         debugError("Could not read from node 0x%04X addr 0x%012llX\n", nodeId, addr);
1461         return false;
1462     }
1463
1464     for(unsigned int i=0;i<length/4;i++) {
1465         *(data+i)=ntohl(*(data+i));
1466     }
1467
1468     return true;
1469 }
1470
1471 bool
1472 DiceAvDevice::writeRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1473     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, length: %u\n",
1474         offset, length);
1475
1476     if(offset >= DICE_INVALID_OFFSET) {
1477         debugError("invalid offset: 0x%016llX\n", offset);
1478         return false;
1479     }
1480
1481     fb_nodeaddr_t addr=DICE_REGISTER_BASE + offset;
1482     fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
1483
1484     fb_quadlet_t data_out[length/4];
1485
1486     for(unsigned int i=0;i<length/4;i++) {
1487         data_out[i]=ntohl(*(data+i));
1488     }
1489
1490     if(!get1394Service().write( nodeId, addr, length/4, data_out ) ) {
1491         debugError("Could not write to node 0x%04X addr 0x%012llX\n", nodeId, addr);
1492         return false;
1493     }
1494
1495     return true;
1496 }
1497
1498 bool
1499 DiceAvDevice::readGlobalReg(fb_nodeaddr_t offset, fb_quadlet_t *result) {
1500     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading global register offset 0x%04llX\n", offset);
1501
1502     fb_nodeaddr_t offset_gl=globalOffsetGen(offset, sizeof(fb_quadlet_t));
1503     return readReg(m_global_reg_offset + offset_gl, result);
1504 }
1505
1506 bool
1507 DiceAvDevice::writeGlobalReg(fb_nodeaddr_t offset, fb_quadlet_t data) {
1508     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing global register offset 0x%08llX, data: 0x%08X\n",
1509         offset, data);
1510
1511     fb_nodeaddr_t offset_gl=globalOffsetGen(offset, sizeof(fb_quadlet_t));
1512     return writeReg(m_global_reg_offset + offset_gl, data);
1513 }
1514
1515 bool
1516 DiceAvDevice::readGlobalRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1517     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading global register block offset 0x%04llX, length %u bytes\n",
1518         offset, length);
1519
1520     fb_nodeaddr_t offset_gl=globalOffsetGen(offset, length);
1521     return readRegBlock(m_global_reg_offset + offset_gl, data, length);
1522 }
1523
1524 bool
1525 DiceAvDevice::writeGlobalRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1526     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing global register block offset 0x%04llX, length %u bytes\n",
1527         offset, length);
1528
1529     fb_nodeaddr_t offset_gl=globalOffsetGen(offset, length);
1530     return writeRegBlock(m_global_reg_offset + offset_gl, data, length);
1531 }
1532
1533 fb_nodeaddr_t
1534 DiceAvDevice::globalOffsetGen(fb_nodeaddr_t offset, size_t length) {
1535
1536     // registry offsets should always be smaller than 0x7FFFFFFF
1537     // because otherwise base + offset > 64bit
1538     if(m_global_reg_offset & 0x80000000) {
1539         debugError("register offset not initialized yet\n");
1540         return DICE_INVALID_OFFSET;
1541     }
1542     // out-of-range check
1543     if(offset+length > m_global_reg_offset+m_global_reg_size) {
1544         debugError("register offset+length too large: 0x%0llX\n", offset + length);
1545         return DICE_INVALID_OFFSET;
1546     }
1547
1548     return offset;
1549 }
1550
1551 bool
1552 DiceAvDevice::readTxReg(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *result) {
1553     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading tx %d register offset 0x%04llX\n", i, offset);
1554
1555     fb_nodeaddr_t offset_tx=txOffsetGen(i, offset, sizeof(fb_quadlet_t));
1556     return readReg(m_tx_reg_offset + offset_tx, result);
1557 }
1558
1559 bool
1560 DiceAvDevice::writeTxReg(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t data) {
1561     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing tx %d register offset 0x%08llX, data: 0x%08X\n",
1562         i, offset, data);
1563
1564     fb_nodeaddr_t offset_tx=txOffsetGen(i, offset, sizeof(fb_quadlet_t));
1565     return writeReg(m_tx_reg_offset + offset_tx, data);
1566 }
1567
1568 bool
1569 DiceAvDevice::readTxRegBlock(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1570     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading rx register block offset 0x%04llX, length %u bytes\n",
1571         offset, length);
1572
1573     fb_nodeaddr_t offset_tx=txOffsetGen(i, offset, length);
1574     return readRegBlock(m_tx_reg_offset + offset_tx, data, length);
1575 }
1576
1577 bool
1578 DiceAvDevice::writeTxRegBlock(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1579     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing rx register block offset 0x%04llX, length %u bytes\n",
1580         offset, length);
1581
1582     fb_nodeaddr_t offset_tx=txOffsetGen(i, offset, length);
1583     return writeRegBlock(m_tx_reg_offset + offset_tx, data, length);
1584 }
1585
1586 fb_nodeaddr_t
1587 DiceAvDevice::txOffsetGen(unsigned int i, fb_nodeaddr_t offset, size_t length) {
1588     // registry offsets should always be smaller than 0x7FFFFFFF
1589     // because otherwise base + offset > 64bit
1590     if(m_tx_reg_offset & 0x80000000) {
1591         debugError("register offset not initialized yet\n");
1592         return DICE_INVALID_OFFSET;
1593     }
1594     if(m_nb_tx & 0x80000000) {
1595         debugError("m_nb_tx not initialized yet\n");
1596         return DICE_INVALID_OFFSET;
1597     }
1598     if(m_tx_size & 0x80000000) {
1599         debugError("m_tx_size not initialized yet\n");
1600         return DICE_INVALID_OFFSET;
1601     }
1602     if(i >= m_nb_tx) {
1603         debugError("TX index out of range\n");
1604         return DICE_INVALID_OFFSET;
1605     }
1606
1607     fb_nodeaddr_t offset_tx = DICE_REGISTER_TX_PARAM(m_tx_size, i, offset);
1608
1609     // out-of-range check
1610     if(offset_tx + length > m_tx_reg_offset+4+m_tx_reg_size*m_nb_tx) {
1611         debugError("register offset+length too large: 0x%0llX\n", offset_tx + length);
1612         return DICE_INVALID_OFFSET;
1613     }
1614
1615     return offset_tx;
1616 }
1617
1618 bool
1619 DiceAvDevice::readRxReg(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *result) {
1620     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading rx %d register offset 0x%04llX\n", i, offset);
1621
1622     fb_nodeaddr_t offset_rx=rxOffsetGen(i, offset, sizeof(fb_quadlet_t));
1623     return readReg(m_rx_reg_offset + offset_rx, result);
1624 }
1625
1626 bool
1627 DiceAvDevice::writeRxReg(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t data) {
1628     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing rx register offset 0x%08llX, data: 0x%08X\n",
1629         offset, data);
1630
1631     fb_nodeaddr_t offset_rx=rxOffsetGen(i, offset, sizeof(fb_quadlet_t));
1632     return writeReg(m_rx_reg_offset + offset_rx, data);
1633 }
1634
1635 bool
1636 DiceAvDevice::readRxRegBlock(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1637     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading rx register block offset 0x%04llX, length %u bytes\n",
1638         offset, length);
1639
1640     fb_nodeaddr_t offset_rx=rxOffsetGen(i, offset, length);
1641     return readRegBlock(m_rx_reg_offset + offset_rx, data, length);
1642 }
1643
1644 bool
1645 DiceAvDevice::writeRxRegBlock(unsigned int i, fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
1646     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing rx register block offset 0x%04llX, length %u bytes\n",
1647         offset, length);
1648
1649     fb_nodeaddr_t offset_rx=rxOffsetGen(i, offset, length);
1650     return writeRegBlock(m_rx_reg_offset + offset_rx, data, length);
1651 }
1652
1653 fb_nodeaddr_t
1654 DiceAvDevice::rxOffsetGen(unsigned int i, fb_nodeaddr_t offset, size_t length) {
1655     // registry offsets should always be smaller than 0x7FFFFFFF
1656     // because otherwise base + offset > 64bit
1657     if(m_rx_reg_offset & 0x80000000) {
1658         debugError("register offset not initialized yet\n");
1659         return DICE_INVALID_OFFSET;
1660     }
1661     if(m_nb_rx & 0x80000000) {
1662         debugError("m_nb_rx not initialized yet\n");
1663         return DICE_INVALID_OFFSET;
1664     }
1665     if(m_rx_size & 0x80000000) {
1666         debugError("m_rx_size not initialized yet\n");
1667         return DICE_INVALID_OFFSET;
1668     }
1669     if(i >= m_nb_rx) {
1670         debugError("RX index out of range\n");
1671         return DICE_INVALID_OFFSET;
1672     }
1673
1674     fb_nodeaddr_t offset_rx = DICE_REGISTER_RX_PARAM(m_rx_size, i, offset);
1675
1676     // out-of-range check
1677     if(offset_rx + length > m_rx_reg_offset+4+m_rx_reg_size*m_nb_rx) {
1678         debugError("register offset+length too large: 0x%0llX\n", offset_rx + length);
1679         return DICE_INVALID_OFFSET;
1680     }
1681     return offset_rx;
1682 }
1683
1684
1685 // the notifier
1686
1687 DiceAvDevice::DiceNotifier::DiceNotifier(DiceAvDevice *d, nodeaddr_t start)
1688  : ARMHandler(start, DICE_NOTIFIER_BLOCK_LENGTH,
1689               RAW1394_ARM_READ | RAW1394_ARM_WRITE | RAW1394_ARM_LOCK,
1690               RAW1394_ARM_WRITE, 0)
1691  , m_dicedevice(d)
1692 {
1693
1694 }
1695
1696 DiceAvDevice::DiceNotifier::~DiceNotifier()
1697 {
1698
1699 }
1700
1701 }
Note: See TracBrowser for help on using the browser.