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

Revision 2092, 58.7 kB (checked in by adi, 11 years ago)

DICE-EAP Corrects the number of router entries for clearing in EAP::RouterConfig::write

By Philippe Carriere:

EAP::RouterConfig::write assumes the router has 128 entries, something
which is not part of the Dice EAP specifications. This number is
replaced by the maximal number of entries as read in the rom; introduce
the function getMaxNbRouterEntries() as a public function of EAP. Then
use it in EAP::RouterConfig::write.

Line 
1 /*
2  * Copyright (C) 2005-2009 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 2 of the License, or
12  * (at your option) version 3 of the License.
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_avdevice.h"
25
26 #include "dice_eap.h"
27 #include "dice_defines.h"
28
29 #include "libutil/SystemTimeSource.h"
30 #include "libutil/ByteSwap.h"
31
32 #include <cstdio>
33
34 namespace Dice {
35
36 // ----------- helper functions -------------
37
38 #if 0
39 static const char *
40 srcBlockToString(const char id)
41 {
42     switch(id) {
43         case eRS_AES:   return "AES ";
44         case eRS_ADAT:  return "ADAT";
45         case eRS_Mixer: return "MXR ";
46         case eRS_InS0:  return "INS0";
47         case eRS_InS1:  return "INS1";
48         case eRS_ARM:   return "ARM ";
49         case eRS_ARX0:  return "AVS0";
50         case eRS_ARX1:  return "AVS1";
51         case eRS_Muted: return "MUTE";
52         default :       return "RSVD";
53     }
54 }
55
56 static  const char *
57 dstBlockToString(const char id)
58 {
59     switch(id) {
60         case eRD_AES:    return "AES ";
61         case eRD_ADAT:   return "ADAT";
62         case eRD_Mixer0: return "MXR0";
63         case eRD_Mixer1: return "MXR1";
64         case eRD_InS0:   return "INS0";
65         case eRD_InS1:   return "INS1";
66         case eRD_ARM:    return "ARM ";
67         case eRD_ATX0:   return "AVS0";
68         case eRD_ATX1:   return "AVS1";
69         case eRD_Muted:  return "MUTE";
70         default : return "RSVD";
71     }
72 }
73 #endif
74
75 IMPL_DEBUG_MODULE( EAP, EAP, DEBUG_LEVEL_NORMAL );
76
77 EAP::EAP(Device &d)
78 : Control::Container(&d, "EAP")
79 , m_device(d)
80 , m_mixer( NULL )
81 , m_router( NULL )
82 , m_current_cfg_routing_low ( RouterConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_LOW_ROUTER ) )
83 , m_current_cfg_routing_mid ( RouterConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_MID_ROUTER ) )
84 , m_current_cfg_routing_high( RouterConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_HIGH_ROUTER) )
85 , m_current_cfg_stream_low  ( StreamConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_LOW_STREAM ) )
86 , m_current_cfg_stream_mid  ( StreamConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_MID_STREAM ) )
87 , m_current_cfg_stream_high ( StreamConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_HIGH_STREAM) )
88 {
89 }
90
91 EAP::~EAP()
92 {
93     // remove all control elements registered to this device (w/o free)
94     clearElements(false);
95
96     // delete the helper classes
97     if(m_mixer) delete m_mixer;
98     if(m_router) delete m_router;
99 }
100
101 // offsets and sizes are returned in quadlets, but we use byte values, hence the *= 4
102 #define DICE_EAP_READREG_AND_CHECK(base, addr, var) { \
103     if(!readReg(base, addr, &var)) { \
104         debugError("Could not initialize " #var "\n"); \
105         return false; \
106     } \
107     var *= 4; \
108 }
109
110 bool
111 EAP::init() {
112     if(!supportsEAP(m_device)) {
113         debugWarning("no EAP mixer (device does not support EAP)\n");
114         return false;
115     }
116
117     // offsets and sizes are returned in quadlets, but we use byte values
118     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CAPABILITY_SPACE_OFF, m_capability_offset);
119     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CAPABILITY_SPACE_SZ, m_capability_size);
120     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CMD_SPACE_OFF, m_cmd_offset);
121     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CMD_SPACE_SZ, m_cmd_size);
122     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_MIXER_SPACE_OFF, m_mixer_offset);
123     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_MIXER_SPACE_SZ, m_mixer_size);
124     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_PEAK_SPACE_OFF, m_peak_offset);
125     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_PEAK_SPACE_SZ, m_peak_size);
126     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_NEW_ROUTING_SPACE_OFF, m_new_routing_offset);
127     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_NEW_ROUTING_SPACE_SZ, m_new_routing_size);
128     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_NEW_STREAM_CFG_SPACE_OFF, m_new_stream_cfg_offset);
129     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_NEW_STREAM_CFG_SPACE_SZ, m_new_stream_cfg_size);
130     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CURR_CFG_SPACE_OFF, m_curr_cfg_offset);
131     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CURR_CFG_SPACE_SZ, m_curr_cfg_size);
132     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_STAND_ALONE_CFG_SPACE_OFF, m_standalone_offset);
133     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_STAND_ALONE_CFG_SPACE_SZ, m_standalone_size);
134     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_APP_SPACE_OFF, m_app_offset);
135     DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_APP_SPACE_SZ, m_app_size);
136
137     // initialize the capability info
138     quadlet_t tmp;
139     if(!readReg(eRT_Capability, DICE_EAP_CAPABILITY_ROUTER, &tmp)) {
140         debugError("Could not read router capabilities\n");
141         return false;
142     }
143     m_router_exposed = (tmp >> DICE_EAP_CAP_ROUTER_EXPOSED) & 0x01;
144     m_router_readonly = (tmp >> DICE_EAP_CAP_ROUTER_READONLY) & 0x01;
145     m_router_flashstored = (tmp >> DICE_EAP_CAP_ROUTER_FLASHSTORED) & 0x01;
146     m_router_nb_entries = (tmp >> DICE_EAP_CAP_ROUTER_MAXROUTES) & 0xFFFF;
147
148     if(!readReg(eRT_Capability, DICE_EAP_CAPABILITY_MIXER, &tmp)) {
149         debugError("Could not read mixer capabilities\n");
150         return false;
151     }
152     m_mixer_exposed = (tmp >> DICE_EAP_CAP_MIXER_EXPOSED) & 0x01;
153     m_mixer_readonly = (tmp >> DICE_EAP_CAP_MIXER_READONLY) & 0x01;
154     m_mixer_flashstored = (tmp >> DICE_EAP_CAP_MIXER_FLASHSTORED) & 0x01;
155     m_mixer_tx_id = (tmp >> DICE_EAP_CAP_MIXER_IN_DEV) & 0x000F;
156     m_mixer_rx_id = (tmp >> DICE_EAP_CAP_MIXER_OUT_DEV) & 0x000F;
157     m_mixer_nb_tx = (tmp >> DICE_EAP_CAP_MIXER_INPUTS) & 0x00FF;
158     m_mixer_nb_rx = (tmp >> DICE_EAP_CAP_MIXER_OUTPUTS) & 0x00FF;
159
160     if(!readReg(eRT_Capability, DICE_EAP_CAPABILITY_GENERAL, &tmp)) {
161         debugError("Could not read general capabilities\n");
162         return false;
163     }
164     m_general_support_dynstream = (tmp >> DICE_EAP_CAP_GENERAL_STRM_CFG_EN) & 0x01;
165     m_general_support_flash = (tmp >> DICE_EAP_CAP_GENERAL_FLASH_EN) & 0x01;
166     m_general_peak_enabled = (tmp >> DICE_EAP_CAP_GENERAL_PEAK_EN) & 0x01;
167     m_general_max_tx = (tmp >> DICE_EAP_CAP_GENERAL_MAX_TX_STREAM) & 0x0F;
168     m_general_max_rx = (tmp >> DICE_EAP_CAP_GENERAL_MAX_RX_STREAM) & 0x0F;
169     m_general_stream_cfg_stored = (tmp >> DICE_EAP_CAP_GENERAL_STRM_CFG_FLS) & 0x01;
170     m_general_chip = (tmp >> DICE_EAP_CAP_GENERAL_CHIP) & 0xFFFF;
171
172     // update our view on the current configuration
173     if(!updateConfigurationCache()) {
174         debugError("Could not initialize configuration cache\n");
175         return false;
176     }
177
178     // initialize the helper classes
179     if (m_mixer_exposed) {
180         // initialize the mixer
181         m_mixer = new EAP::Mixer(*this);
182         if(m_mixer == NULL) {
183             debugError("Could not allocate memory for mixer\n");
184             return false;
185         }
186         if(!m_mixer->init()) {
187             debugError("Could not initialize mixer\n");
188             delete m_mixer;
189             m_mixer = NULL;
190             return false;
191         }
192         // add the mixer to the EAP control container
193         if(!addElement(m_mixer)) {
194             debugWarning("Failed to add mixer to control tree\n");
195         }
196        
197         // initialize the peak meter
198         m_router = new EAP::Router(*this);
199         if(m_router == NULL) {
200             debugError("Could not allocate memory for router\n");
201             return false;
202         }
203         m_router->update();
204
205         // add the router to the EAP control container
206         if(!addElement(m_router)) {
207             debugWarning("Failed to add router to control tree\n");
208         }
209     }
210
211     return true;
212 }
213
214
215 void
216 EAP::update()
217 {
218     // update EAP from the last init
219     //   update router sources and destinations
220     if (m_router) {
221         m_router->update();
222     }
223 }
224
225 void
226 EAP::setupSources() {
227     // define router sources (possibly depending on the samplerate)
228     switch(m_device.getCurrentConfig()) {
229         case Device::eDC_Low: setupSources_low(); return;
230         case Device::eDC_Mid: setupSources_mid(); return;
231         case Device::eDC_High: setupSources_high(); return;
232         default:
233             debugError("Unsupported configuration mode\n");
234             return;
235     }
236 }
237
238 void
239 EAP::setupSources_low() {
240     // add the routing sources for a DICE chip
241     switch(m_general_chip) {
242         case DICE_EAP_CAP_GENERAL_CHIP_DICEII:
243             // router/EAP currently not supported
244             break;
245         case DICE_EAP_CAP_GENERAL_CHIP_DICEJR:
246             // second audio port (unique to the junior)
247             addSource("InS1", 0, 8, eRS_InS1);
248         case DICE_EAP_CAP_GENERAL_CHIP_DICEMINI:
249             /// these are common to the mini and junior
250             // the AES receiver
251             addSource("AES", 0, 8, eRS_AES);
252             // the ADAT receiver
253             addSource("ADAT", 0, 8, eRS_ADAT);
254             // the Mixer outputs
255             addSource("MixerOut", 0, 16, eRS_Mixer);
256             // the first audio port
257             addSource("InS0", 0, 8, eRS_InS0);
258             // the ARM audio port
259             addSource("ARM", 0, 8, eRS_ARM);
260             // the 1394 stream receivers
261             addSource("1394_0", 0, 16, eRS_ARX0);
262             addSource("1394_1", 0, 16, eRS_ARX1);
263             // mute
264             addSource("Mute", 0, 1, eRS_Muted);
265             break;
266         default:
267             // this is an unsupported chip
268             break;
269     }
270 }
271
272 void
273 EAP::setupSources_mid() {
274     setupSources_low();
275 }
276
277 void
278 EAP::setupSources_high() {
279     setupSources_low();
280 }
281
282 void
283 EAP::setupDestinations() {
284     switch(m_device.getCurrentConfig()) {
285         case Device::eDC_Low: setupDestinations_low(); return;
286         case Device::eDC_Mid: setupDestinations_mid(); return;
287         case Device::eDC_High: setupDestinations_high(); return;
288         default:
289             debugError("Unsupported configuration mode\n");
290             return;
291     }
292 }
293
294 void
295 EAP::setupDestinations_low() {
296     // add the routing destinations for a DICE chip
297     switch(m_general_chip) {
298         case DICE_EAP_CAP_GENERAL_CHIP_DICEII:
299             // router/EAP currently not supported
300             break;
301         case DICE_EAP_CAP_GENERAL_CHIP_DICEJR:
302             // second audio port (unique to the junior)
303             addDestination("InS1", 0, 8, eRD_InS1);
304         case DICE_EAP_CAP_GENERAL_CHIP_DICEMINI:
305             /// these are common to the mini and junior
306             // the AES receiver
307             addDestination("AES", 0, 8, eRD_AES);
308             // the ADAT receiver
309             addDestination("ADAT", 0, 8, eRD_ADAT);
310             // the Mixer outputs
311             addDestination("MixerIn", 0, 16, eRD_Mixer0);
312             addDestination("MixerIn", 0, 2, eRD_Mixer1, 16);
313             // the first audio port
314             addDestination("InS0", 0, 8, eRD_InS0);
315             // the ARM audio port
316             addDestination("ARM", 0, 8, eRD_ARM);
317             // the 1394 stream receivers
318             addDestination("1394_0", 0, 16, eRD_ATX0);
319             addDestination("1394_1", 0, 16, eRD_ATX1);
320             // mute
321             addDestination("Mute", 0, 1, eRD_Muted);
322             break;
323         default:
324             // this is an unsupported chip
325             break;
326     }
327 }
328 void
329 EAP::setupDestinations_mid() {
330     setupDestinations_low();
331 }
332 void
333 EAP::setupDestinations_high() {
334     setupDestinations_low();
335 }
336
337 void
338 EAP::addSource(const std::string name, unsigned int base, unsigned int count,
339                enum eRouteSource srcid, unsigned int offset)
340 {
341     m_router->addSource(name, srcid, base, count, offset);
342 }
343 void
344 EAP::addDestination(const std::string name, unsigned int base, unsigned int count,
345                     enum eRouteDestination destid, unsigned int offset)
346 {
347     m_router->addDestination(name, destid, base, count, offset);
348 }
349
350 bool
351 EAP::updateConfigurationCache()
352 {
353     if(!m_current_cfg_routing_low.read()) {
354         debugError("Could not initialize current routing configuration (low rates)\n");
355         return false;
356     }
357     if(!m_current_cfg_routing_mid.read()) {
358         debugError("Could not initialize current routing configuration (mid rates)\n");
359         return false;
360     }
361     if(!m_current_cfg_routing_high.read()) {
362         debugError("Could not initialize current routing configuration (high rates)\n");
363         return false;
364     }
365     if(!m_current_cfg_stream_low.read()) {
366         debugError("Could not initialize current stream configuration (low rates)\n");
367         return false;
368     }
369     if(!m_current_cfg_stream_mid.read()) {
370         debugError("Could not initialize current stream configuration (mid rates)\n");
371         return false;
372     }
373     if(!m_current_cfg_stream_high.read()) {
374         debugError("Could not initialize current stream configuration (high rates)\n");
375         return false;
376     }
377     if(m_mixer) m_mixer->updateNameCache();
378     return true;
379 }
380
381 // Get capture and playback names
382 //   If the device has a router, capture and playback are destinations and sources, respectively,
383 //     as defined above
384 //   If no router is found, transmitters and receivers names are returned
385
386 stringlist
387 EAP::getCptrNameString(unsigned int i) {
388     std::vector<unsigned int> destid;
389     unsigned int destid_0;
390     stringlist cptr_names;
391     std::string dest_name, src_name;
392    
393     if (m_router) {
394         switch (i) {
395           case 0: destid_0 = (eRD_ATX0<<4); break;
396           case 1: destid_0 = (eRD_ATX1<<4); break;
397           // Only 2 transmitter possible (?)
398           default: return cptr_names;
399         }
400         // At most 16 destinations per eRD
401         for (int j=0; j<16; j++) {
402           destid.push_back(destid_0+j);
403         }
404         for (unsigned it=0; it<destid.size(); it++) {
405           // If destination identifier is not part of the router, destination name will be empty
406           dest_name = m_router->getDestinationName(destid.at(it));
407           if (dest_name.size() > 0) {
408             // get a source possibly routed to the destination (only one source per destination)
409             src_name = m_router->getSourceForDestination(dest_name);
410             if (src_name.size() > 0) {
411               dest_name.append(" ("); dest_name.append(src_name); dest_name.append(")");
412             }
413             cptr_names.push_back(dest_name);
414           }
415         }
416
417     } else {
418         StreamConfig *scfg = getActiveStreamConfig();
419         if(scfg) {
420           cptr_names = scfg->getTxNamesString(i);
421         }
422     }
423     return cptr_names;
424 }
425
426 stringlist
427 EAP::getPbckNameString(unsigned int i) {
428     std::vector<unsigned int> srcid;
429     unsigned int srcid_0;
430     stringlist pbck_names, dest_names;
431     std::string src_name;
432    
433     if (m_router) {
434         switch (i) {
435            case 0: srcid_0 = (eRS_ARX0<<4); break;
436            case 1: srcid_0 = (eRS_ARX1<<4); break;
437             // Only 2 receiver possible (?)
438           default: return pbck_names;
439         }
440         // At most 16 destinations per eRD
441         for (int j=0; j<16; j++) {
442           srcid.push_back(srcid_0+j);
443         }
444         for (unsigned it=0; it<srcid.size(); it++) {
445           // If source identifier is not part of the router, source name will be empty
446           src_name = m_router->getSourceName(srcid.at(it));
447           if (src_name.size() > 0) {
448             // Search for destinations routed to this source
449             //   Multiple destinations for a single source are possible
450             dest_names = m_router->getDestinationsForSource(src_name);
451             if (dest_names.size() > 0) {
452               src_name.append(" (");
453               stringlist::iterator it_d = dest_names.begin();
454               stringlist::iterator it_d_end_m1 = dest_names.end(); --it_d_end_m1;
455               while (it_d != it_d_end_m1) {
456                 src_name.append((*it_d).c_str()); src_name.append("; ");
457                 it_d++;
458               }
459               src_name.append((*it_d).c_str()); src_name.append(")");
460             }
461             pbck_names.push_back(src_name);
462           }
463         }
464     } else {
465         StreamConfig *scfg = getActiveStreamConfig();
466         if(scfg) {
467           pbck_names = scfg->getRxNamesString(i);
468         }
469     }
470     return pbck_names;
471 }
472
473 /**
474  * Returns the router configuration for the current rate mode
475  */
476 EAP::RouterConfig *
477 EAP::getActiveRouterConfig()
478 {
479     switch(m_device.getCurrentConfig()) {
480         case Device::eDC_Low: return &m_current_cfg_routing_low;
481         case Device::eDC_Mid: return &m_current_cfg_routing_mid;
482         case Device::eDC_High: return &m_current_cfg_routing_high;
483         default:
484             debugError("Unsupported configuration mode\n");
485             return NULL;
486     }
487 }
488
489 /**
490  * Returns the stream configuration for the current rate mode
491  */
492 EAP::StreamConfig *
493 EAP::getActiveStreamConfig()
494 {
495     switch(m_device.getCurrentConfig()) {
496         case Device::eDC_Low: return &m_current_cfg_stream_low;
497         case Device::eDC_Mid: return &m_current_cfg_stream_mid;
498         case Device::eDC_High: return &m_current_cfg_stream_high;
499         default:
500             debugError("Unsupported configuration mode\n");
501             return NULL;
502     }
503 }
504
505 /**
506  * Uploads a new router configuration to the device
507  * @param  rcfg The new RouterConfig
508  * @param low store as config for the low rates
509  * @param mid store as config for the mid rates
510  * @param high store as config for the high rates
511  * @return true if successful, false otherwise
512  */
513 bool
514 EAP::updateRouterConfig(RouterConfig& rcfg, bool low, bool mid, bool high) {
515     // write the router config to the appropriate memory space on the device
516     if(!rcfg.write(eRT_NewRouting, 0)) {
517         debugError("Could not write new router configuration\n");
518         return false;
519     }
520     // perform the store operation
521     if(!loadRouterConfig(low, mid, high)) {
522         debugError("Could not activate new router configuration\n");
523         updateConfigurationCache(); // for consistency
524         return false;
525     }
526     return updateConfigurationCache();
527 }
528
529 /**
530  * Uploads a new router configuration to replace the configuration
531  * for the current rate.
532  * @param  rcfg The new RouterConfig
533  * @return true if successful, false otherwise
534  */
535 bool
536 EAP::updateCurrentRouterConfig(RouterConfig& rcfg) {
537     switch(m_device.getCurrentConfig()) {
538         case Device::eDC_Low: return updateRouterConfig(rcfg, true, false, false);
539         case Device::eDC_Mid: return updateRouterConfig(rcfg, false, true, false);
540         case Device::eDC_High: return updateRouterConfig(rcfg, false, false, true);
541         default:
542             debugError("Unsupported configuration mode\n");
543             return false;
544     }
545 }
546
547 /**
548  * Uploads a new stream configuration to the device
549  * @param scfg The new StreamConfig
550  * @param low store as config for the low rates
551  * @param mid store as config for the mid rates
552  * @param high store as config for the high rates
553  * @return true if successful, false otherwise
554  */
555 bool
556 EAP::updateStreamConfig(StreamConfig& scfg, bool low, bool mid, bool high) {
557     // write the stream config to the appropriate memory space on the device
558     if(!scfg.write(eRT_NewStreamCfg, 0)) {
559         debugError("Could not write new stream configuration\n");
560         return false;
561     }
562     // perform the store operation
563     if(!loadStreamConfig(low, mid, high)) {
564         debugError("Could not activate new stream configuration\n");
565         updateConfigurationCache(); // for consistency
566         return false;
567     }
568     return updateConfigurationCache();
569 }
570
571 /**
572  * Uploads a new router and stream configuration to the device
573  * @param  rcfg The new RouterConfig
574  * @param  scfg The new StreamConfig
575  * @param low store as config for the low rates
576  * @param mid store as config for the mid rates
577  * @param high store as config for the high rates
578  * @return true if successful, false otherwise
579  */
580 bool
581 EAP::updateStreamConfig(RouterConfig& rcfg, StreamConfig& scfg, bool low, bool mid, bool high) {
582     // write the router config to the appropriate memory space on the device
583     if(!rcfg.write(eRT_NewRouting, 0)) {
584         debugError("Could not write new router configuration\n");
585         return false;
586     }
587     // write the stream config to the appropriate memory space on the device
588     if(!scfg.write(eRT_NewStreamCfg, 0)) {
589         debugError("Could not write new stream configuration\n");
590         return false;
591     }
592     // perform the store operation
593     if(!loadRouterAndStreamConfig(low, mid, high)) {
594         debugError("Could not activate new router/stream configuration\n");
595         updateConfigurationCache(); // for consistency
596         return false;
597     }
598     return updateConfigurationCache();
599 }
600
601
602 bool
603 EAP::loadFlashConfig() {
604     bool retval = true;
605     debugWarning("Untested code\n");
606     fb_quadlet_t cmd = DICE_EAP_CMD_OPCODE_LD_FLASH_CFG;
607     cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE;
608     if(!commandHelper(cmd)) {
609         debugWarning("Command failed\n");
610         retval = false;
611     }
612     retval &= updateConfigurationCache();
613     return retval;
614 }
615
616 bool
617 EAP::storeFlashConfig() {
618     //debugWarning("Untested code\n") // Works. -Arnold;
619     fb_quadlet_t cmd = DICE_EAP_CMD_OPCODE_ST_FLASH_CFG;
620     cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE;
621     return commandHelper(cmd);
622 }
623
624 // helpers
625 void
626 EAP::show()
627 {
628     printMessage("== DICE EAP ==\n");
629     printMessage("Parameter Space info:\n");
630     printMessage(" Capability        : offset=%04X size=%06d\n", m_capability_offset, m_capability_size);
631     printMessage(" Command           : offset=%04X size=%06d\n", m_cmd_offset, m_cmd_size);
632     printMessage(" Mixer             : offset=%04X size=%06d\n", m_mixer_offset, m_mixer_size);
633     printMessage(" Peak              : offset=%04X size=%06d\n", m_peak_offset, m_peak_size);
634     printMessage(" New Routing Cfg   : offset=%04X size=%06d\n", m_new_routing_offset, m_new_routing_size);
635     printMessage(" New Stream Cfg    : offset=%04X size=%06d\n", m_new_stream_cfg_offset, m_new_stream_cfg_size);
636     printMessage(" Current Cfg       : offset=%04X size=%06d\n", m_curr_cfg_offset, m_curr_cfg_size);
637     printMessage(" Standalone Cfg    : offset=%04X size=%06d\n", m_standalone_offset, m_standalone_size);
638     printMessage(" Application Space : offset=%04X size=%06d\n", m_app_offset, m_app_size);
639
640     printMessage("Capabilities:\n");
641     printMessage(" Router: %sexposed, %swritable, %sstored, %d routes\n",
642                                      (m_router_exposed?"":"not "),
643                                      (m_router_readonly?"not ":""),
644                                      (m_router_flashstored?"":"not "),
645                                      m_router_nb_entries);
646     printMessage(" Mixer : %sexposed, %swritable, %sstored\n",
647                                      (m_mixer_exposed?"":"not "),
648                                      (m_mixer_readonly?"not ":""),
649                                      (m_mixer_flashstored?"":"not "));
650     printMessage("         tx id: (%d==eRD_Mixer0) ? %s, rx id: (%d==eRS_Mixer) ? %s\n",
651                                      m_mixer_tx_id, (m_mixer_tx_id == eRD_Mixer0)?"true":"false",
652                                      m_mixer_rx_id, (m_mixer_rx_id == eRS_Mixer) ?"true":"false");
653     printMessage("         nb tx channels: %d, nb rx channels: %d\n", m_mixer_nb_tx, m_mixer_nb_rx);
654     printMessage(" General: dynamic stream config %ssupported\n",
655                                      (m_general_support_dynstream?"":"not "));
656     printMessage("          flash load and store %ssupported\n",
657                                      (m_general_support_flash?"":"not "));
658     printMessage("          peak metering %s\n",
659                                      (m_general_peak_enabled?"enabled":"disabled"));
660     printMessage("          stream config %sstored\n",
661                                      (m_general_stream_cfg_stored?"":"not "));
662     printMessage("          max TX streams: %d, max RX streams: %d\n",
663                                      m_general_max_tx, m_general_max_rx);
664
665     if(m_general_chip == DICE_EAP_CAP_GENERAL_CHIP_DICEII) {
666         printMessage("          Chip: DICE-II\n");
667     } else if(m_general_chip == DICE_EAP_CAP_GENERAL_CHIP_DICEMINI) {
668         printMessage("          Chip: DICE Mini (TCD2210)\n");
669     } else if(m_general_chip == DICE_EAP_CAP_GENERAL_CHIP_DICEJR) {
670         printMessage("          Chip: DICE Junior (TCD2220)\n");
671     }
672
673     printMessage("--- Mixer configuration ---\n");
674     if(m_mixer) {
675         m_mixer->show();
676     }
677     printMessage("--- Router/Peak space ---\n");
678     if(m_router) {
679         m_router->show();
680     }
681
682     printMessage("--- Active Router ---\n");
683     RouterConfig *rcfg = getActiveRouterConfig();
684     if(rcfg) {
685         rcfg->show();
686     }
687     printMessage("--- Active Stream ---\n");
688     StreamConfig *scfg = getActiveStreamConfig();
689     if(scfg) {
690         scfg->show();
691     }
692
693 // fixme
694 //     size_t len = 0x1000;
695 //     quadlet_t tmp[len];
696 //     if(!readRegBlock( eRT_CurrentCfg, DICE_EAP_CURRCFG_LOW_STREAM, tmp, len*4) ) {
697 //         debugError("Failed to read block\n");
698 //     } else {
699 //         hexDumpQuadlets(tmp, len);
700 //     }
701
702 }
703 void
704 EAP::showApplication()
705 {
706     printMessage("--- Application space ---\n");
707     fb_quadlet_t* tmp = (fb_quadlet_t *)calloc(128, sizeof(fb_quadlet_t));
708     unsigned int appsize = m_app_size; /// m_app_size is rather big. Start with the first four block of 128 quadlets...
709     unsigned int offset = 0;
710     while ( appsize > 0 ) {
711         if ( ! readRegBlock( eRT_Application, offset, tmp, ((appsize<128)?appsize:128)*sizeof(fb_quadlet_t) ) )
712             appsize = 0;
713         else {
714             hexDumpQuadlets(tmp, 128);
715             offset += 128*sizeof(fb_quadlet_t);
716             appsize -= 128*sizeof(fb_quadlet_t);
717         }
718     }
719 }
720
721 // EAP load/store operations
722
723 enum EAP::eWaitReturn
724 EAP::operationBusy() {
725     fb_quadlet_t tmp;
726     if(!readReg(eRT_Command, DICE_EAP_COMMAND_OPCODE, &tmp)) {
727         debugError("Could not read opcode register\n");
728         return eWR_Error;
729     }
730     if( (tmp & DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE) == DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE) {
731         return eWR_Busy;
732     } else {
733         return eWR_Done;
734     }
735 }
736
737 enum EAP::eWaitReturn
738 EAP::waitForOperationEnd(int max_wait_time_ms) {
739     int max_waits = max_wait_time_ms;
740
741     while(max_waits--) {
742         enum eWaitReturn retval = operationBusy();
743         switch(retval) {
744             case eWR_Busy:
745                 break; // not done yet, keep waiting
746             case eWR_Done:
747                 return eWR_Done;
748             case eWR_Error:
749             case eWR_Timeout:
750                 debugError("Error while waiting for operation to end. (%d)\n", retval);
751         }
752         Util::SystemTimeSource::SleepUsecRelative(1000);
753     }
754     return eWR_Timeout;
755 }
756
757 bool
758 EAP::commandHelper(fb_quadlet_t cmd) {
759     // check whether another command is still running
760     if(operationBusy() == eWR_Busy) {
761         debugError("Other operation in progress\n");
762         return false;
763     }
764
765     // execute the command
766     if(!writeReg(eRT_Command, DICE_EAP_COMMAND_OPCODE, cmd)) {
767         debugError("Could not write opcode register\n");
768         return false;
769     }
770
771     // wait for the operation to end
772     enum eWaitReturn retval = waitForOperationEnd();
773     switch(retval) {
774         case eWR_Done:
775             break; // do nothing
776         case eWR_Timeout:
777             debugWarning("Time-out while waiting for operation to end. (%d)\n", retval);
778             return false;
779         case eWR_Error:
780         case eWR_Busy: // can't be returned
781             debugError("Error while waiting for operation to end. (%d)\n", retval);
782             return false;
783     }
784
785     // check the return value
786     if(!readReg(eRT_Command, DICE_EAP_COMMAND_RETVAL, &cmd)) {
787         debugError("Could not read return value register\n");
788         return false;
789     }
790     if(cmd != 0) {
791         debugWarning("Command failed\n");
792         return false;
793     } else {
794         debugOutput(DEBUG_LEVEL_VERBOSE, "Command successful\n");
795         return true;
796     }
797 }
798
799 bool
800 EAP::loadRouterConfig(bool low, bool mid, bool high) {
801     fb_quadlet_t cmd = DICE_EAP_CMD_OPCODE_LD_ROUTER;
802     if(low) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_LOW;
803     if(mid) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_MID;
804     if(high) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_HIGH;
805     cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE;
806     return commandHelper(cmd);
807 }
808
809 bool
810 EAP::loadStreamConfig(bool low, bool mid, bool high) {
811     debugWarning("Untested code\n");
812     fb_quadlet_t cmd = DICE_EAP_CMD_OPCODE_LD_STRM_CFG;
813     if(low) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_LOW;
814     if(mid) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_MID;
815     if(high) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_HIGH;
816     cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE;
817     return commandHelper(cmd);
818 }
819
820 bool
821 EAP::loadRouterAndStreamConfig(bool low, bool mid, bool high) {
822     debugWarning("Untested code\n");
823     fb_quadlet_t cmd = DICE_EAP_CMD_OPCODE_LD_RTR_STRM_CFG;
824     if(low) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_LOW;
825     if(mid) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_MID;
826     if(high) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_HIGH;
827     cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE;
828     return commandHelper(cmd);
829 }
830
831 /*
832   I/O operations
833   */
834 bool
835 EAP::readReg(enum eRegBase base, unsigned offset, fb_quadlet_t *result) {
836     fb_nodeaddr_t addr = offsetGen(base, offset, 4);
837     return m_device.readReg(addr, result);
838 }
839
840 bool
841 EAP::writeReg(enum eRegBase base, unsigned offset, fb_quadlet_t data) {
842     fb_nodeaddr_t addr = offsetGen(base, offset, 4);
843     return m_device.writeReg(addr, data);
844 }
845
846 bool
847 EAP::readRegBlock(enum eRegBase base, unsigned offset, fb_quadlet_t *data, size_t length) {
848     fb_nodeaddr_t addr = offsetGen(base, offset, length);
849     return m_device.readRegBlock(addr, data, length);
850 }
851
852 bool
853 EAP::writeRegBlock(enum eRegBase base, unsigned offset, fb_quadlet_t *data, size_t length) {
854     fb_nodeaddr_t addr = offsetGen(base, offset, length);
855     return m_device.writeRegBlock(addr, data, length);
856 }
857
858 fb_nodeaddr_t
859 EAP::offsetGen(enum eRegBase base, unsigned offset, size_t length) {
860     fb_nodeaddr_t addr;
861     fb_nodeaddr_t maxlen;
862     switch(base) {
863         case eRT_Base:
864             addr = 0;
865             maxlen = DICE_EAP_MAX_SIZE;
866             break;
867         case eRT_Capability:
868             addr = m_capability_offset;
869             maxlen = m_capability_size;
870             break;
871         case eRT_Command:
872             addr = m_cmd_offset;
873             maxlen = m_cmd_size;
874             break;
875         case eRT_Mixer:
876             addr = m_mixer_offset;
877             maxlen = m_mixer_size;
878             break;
879         case eRT_Peak:
880             addr = m_peak_offset;
881             maxlen = m_peak_size;
882             break;
883         case eRT_NewRouting:
884             addr = m_new_routing_offset;
885             maxlen = m_new_routing_size;
886             break;
887         case eRT_NewStreamCfg:
888             addr = m_new_stream_cfg_offset;
889             maxlen = m_new_stream_cfg_size;
890             break;
891         case eRT_CurrentCfg:
892             addr = m_curr_cfg_offset;
893             maxlen = m_curr_cfg_size;
894             break;
895         case eRT_Standalone:
896             addr = m_standalone_offset;
897             maxlen = m_standalone_size;
898             break;
899         case eRT_Application:
900             addr = m_app_offset;
901             maxlen = m_app_size;
902             break;
903         default:
904             debugError("Unsupported base address\n");
905             return 0;
906     };
907
908     // out-of-range check
909     if(length > maxlen) {
910         debugError("requested length too large: %zd > %"PRIu64"\n", length, maxlen);
911         return DICE_INVALID_OFFSET;
912     }
913     return DICE_EAP_BASE + addr + offset;
914 }
915
916 /**
917  * Check whether a device supports eap
918  * @param d the device to check
919  * @return true if the device supports EAP
920  */
921 bool
922 EAP::supportsEAP(Device &d)
923 {
924     DebugModule &m_debugModule = d.m_debugModule;
925     quadlet_t tmp;
926     if(!d.readReg(DICE_EAP_BASE, &tmp)) {
927         debugOutput(DEBUG_LEVEL_VERBOSE, "Could not read from DICE EAP base address\n");
928         return false;
929     }
930     if(!d.readReg(DICE_EAP_BASE + DICE_EAP_ZERO_MARKER_1, &tmp)) {
931         debugOutput(DEBUG_LEVEL_VERBOSE, "Could not read from DICE EAP zero marker\n");
932         return false;
933     }
934     if(tmp != 0) {
935         debugOutput(DEBUG_LEVEL_VERBOSE, "DICE EAP zero marker not zero\n");
936         return false;
937     }
938     return true;
939 }
940
941 // -------------------------------- Mixer ----------------------------------
942 //   Dice matrix-mixer is a one-dimensional array with inputs index varying
943 //    first
944 //
945 //   "ffado convention" is that inputs are rows and outputs are columns
946 //
947 EAP::Mixer::Mixer(EAP &p)
948 : Control::MatrixMixer(&p.m_device, "MatrixMixer")
949 , m_eap(p)
950 , m_coeff(NULL)
951 , m_debugModule(p.m_debugModule)
952 {
953 }
954
955 EAP::Mixer::~Mixer()
956 {
957     if (m_coeff) {
958         free(m_coeff);
959         m_coeff = NULL;
960     }
961 }
962
963 bool
964 EAP::Mixer::init()
965 {
966     if(!m_eap.m_mixer_exposed) {
967         debugError("Device does not expose mixer\n");
968         return false;
969     }
970
971     // remove previous coefficient array
972     if(m_coeff) {
973         free(m_coeff);
974         m_coeff = NULL;
975     }
976    
977     // allocate coefficient array
978     int nb_inputs = m_eap.m_mixer_nb_tx;
979     int nb_outputs = m_eap.m_mixer_nb_rx;
980
981     m_coeff = (fb_quadlet_t *)calloc(nb_outputs * nb_inputs, sizeof(fb_quadlet_t));
982
983     // load initial values
984     if(!loadCoefficients()) {
985         debugWarning("Could not initialize coefficients\n");
986         return false;
987     }
988     updateNameCache();
989     return true;
990 }
991
992 bool
993 EAP::Mixer::loadCoefficients()
994 {
995     if(m_coeff == NULL) {
996         debugError("Coefficient cache not initialized\n");
997         return false;
998     }
999     int nb_inputs = m_eap.m_mixer_nb_tx;
1000     int nb_outputs = m_eap.m_mixer_nb_rx;
1001     if(!m_eap.readRegBlock(eRT_Mixer, 4, m_coeff, nb_inputs * nb_outputs * 4)) {
1002         debugError("Failed to read coefficients\n");
1003         return false;
1004     }
1005     return true;
1006 }
1007
1008 bool
1009 EAP::Mixer::storeCoefficients()
1010 {
1011     if(m_coeff == NULL) {
1012         debugError("Coefficient cache not initialized\n");
1013         return false;
1014     }
1015     if(m_eap.m_mixer_readonly) {
1016         debugWarning("Mixer is read-only\n");
1017         return false;
1018     }
1019     int nb_inputs = m_eap.m_mixer_nb_tx;
1020     int nb_outputs = m_eap.m_mixer_nb_rx;
1021     if(!m_eap.writeRegBlock(eRT_Mixer, 4, m_coeff, nb_inputs * nb_outputs * 4)) {
1022         debugError("Failed to read coefficients\n");
1023         return false;
1024     }
1025     return true;
1026 }
1027
1028 void
1029 EAP::Mixer::updateNameCache()
1030 {
1031     debugWarning("What is this function about?\n");
1032 #if 0
1033     // figure out the number of i/o's
1034     int nb_inputs = m_eap.m_mixer_nb_tx;
1035     int nb_outputs = m_eap.m_mixer_nb_rx;
1036
1037     // clear the previous map
1038     m_input_route_map.clear();
1039     m_output_route_map.clear();
1040
1041     // find the active router configuration
1042     RouterConfig * rcfg = m_eap.getActiveRouterConfig();
1043     if(rcfg == NULL) {
1044         debugError("Could not get active routing info\n");
1045         return;
1046     }
1047
1048     // find the inputs
1049     for(int i=0; i < nb_inputs; i++) {
1050         int ch = i;
1051         // the destination id of the mixer input
1052         int dest_int = m_eap.m_mixer_tx_id;
1053
1054         // from the DICE mixer spec:
1055         // we can have 16 channels per "block"
1056         // if there are more, consecutive block id's are assumed
1057         while(ch > 15) {
1058             ch -= 16;
1059             dest_int += 1;
1060         }
1061         // the destination block and channel corresponding with this
1062         // mixer input is now known
1063         enum eRouteDestination dest = rcfg->intToRouteDestination(dest_int);
1064
1065         // get the source for this mixer channel
1066         m_input_route_map[i] = rcfg->getRouteForDestination(dest, ch);
1067
1068         debugOutput(DEBUG_LEVEL_VERBOSE, "Mixer input channel %2d source: %s (%d)\n", i,
1069                                           srcBlockToString(m_input_route_map[i].src),
1070                                           m_input_route_map[i].srcChannel);
1071     }
1072
1073     // find where the outputs are connected to
1074     for(int i=0; i < nb_outputs; i++) {
1075         int ch = i;
1076         // the source id of the mixer input
1077         int src_int = m_eap.m_mixer_rx_id;
1078
1079         // from the DICE mixer spec:
1080         // we can have 16 channels per "block"
1081         // if there are more, consecutive block id's are assumed
1082         while(ch > 15) {
1083             ch -= 16;
1084             src_int += 1;
1085         }
1086
1087         // the source block and channel corresponding with this
1088         // mixer output is now known
1089         enum eRouteSource src = rcfg->intToRouteSource(src_int);
1090
1091         // get the routing destinations for this mixer channel
1092         m_output_route_map[i] = rcfg->getRoutesForSource(src, ch);
1093
1094         #ifdef DEBUG
1095         std::string destinations;
1096         for ( RouterConfig::RouteVectorIterator it = m_output_route_map[i].begin();
1097             it != m_output_route_map[i].end();
1098             ++it )
1099         {
1100             RouterConfig::Route r = *it;
1101             // check whether the destination is valid
1102             if((r.dst != eRD_Invalid) && (r.dstChannel >= 0)) {
1103                 char tmp[128];
1104                 snprintf(tmp, 128, "%s:%d,", dstBlockToString(r.dst), r.dstChannel);
1105                 destinations += tmp;
1106             }
1107         }
1108         debugOutput(DEBUG_LEVEL_VERBOSE, "Mixer output channel %2d destinations: %s\n", i, destinations.c_str());
1109         #endif
1110     }
1111 #endif
1112 }
1113
1114 void
1115 EAP::Mixer::show()
1116 {
1117     int nb_inputs = m_eap.m_mixer_nb_tx;
1118     int nb_outputs = m_eap.m_mixer_nb_rx;
1119
1120     updateNameCache();
1121
1122     const size_t bufflen = 4096;
1123     char tmp[bufflen];
1124     int cnt;
1125
1126     //
1127     // Caution the user that, displaying as further, because inputs index varies first
1128     //  inputs will appears as columns at the opposite of the "ffado convention"
1129     printMessage("   -- inputs index -->>\n");
1130     cnt = 0;
1131     for(int j=0; j < nb_inputs; j++) {
1132         cnt += snprintf(tmp+cnt, bufflen-cnt, "   %02d   ", j);
1133     }
1134     printMessage("%s\n", tmp);
1135
1136     cnt = 0;
1137     for(int j=0; j < nb_inputs; j++) {
1138         cnt += snprintf(tmp+cnt, bufflen-cnt, "%s ", getRowName(j).data());
1139     }
1140     printMessage("%s\n", tmp);
1141
1142     // display coefficients
1143     for(int i=0; i < nb_outputs; i++) {
1144         cnt = 0;
1145         for(int j=0; j < nb_inputs; j++) {
1146             cnt += snprintf(tmp+cnt, bufflen-cnt, "%07d ", *(m_coeff + nb_inputs * i + j));
1147         }
1148  
1149         // Display destinations name
1150         cnt += snprintf(tmp+cnt, bufflen-cnt, "=[%02d]=> %s", i, getColName(i).data());
1151         printMessage("%s\n", tmp);
1152     }
1153
1154 }
1155
1156 int
1157 EAP::Mixer::canWrite( const int row, const int col)
1158 {
1159     if(m_eap.m_mixer_readonly) {
1160         return false;
1161     }
1162     return (row >= 0 && row < m_eap.m_mixer_nb_tx && col >= 0 && col < m_eap.m_mixer_nb_rx);
1163 }
1164
1165 double
1166 EAP::Mixer::setValue( const int row, const int col, const double val)
1167 {
1168     if(m_eap.m_mixer_readonly) {
1169         debugWarning("Mixer is read-only\n");
1170         return false;
1171     }
1172     int nb_inputs = m_eap.m_mixer_nb_tx;
1173     int addr = ((nb_inputs * col) + row) * 4;
1174     quadlet_t tmp = (quadlet_t) val;
1175     if(!m_eap.writeRegBlock(eRT_Mixer, 4+addr, &tmp, 4)) {
1176         debugError("Failed to write coefficient\n");
1177         return 0;
1178     }
1179     return (double)(tmp);
1180 }
1181
1182 double
1183 EAP::Mixer::getValue( const int row, const int col)
1184 {
1185     int nb_inputs = m_eap.m_mixer_nb_tx;
1186     int addr = ((nb_inputs * col) + row) * 4;
1187     quadlet_t tmp;
1188     if(!m_eap.readRegBlock(eRT_Mixer, 4+addr, &tmp, 4)) {
1189         debugError("Failed to read coefficient\n");
1190         return 0;
1191     }
1192     return (double)(tmp);
1193 }
1194
1195 int
1196 EAP::Mixer::getRowCount()
1197 {
1198     return m_eap.m_mixer_nb_tx;
1199 }
1200
1201 int
1202 EAP::Mixer::getColCount()
1203 {
1204     return m_eap.m_mixer_nb_rx;
1205 }
1206
1207 // full map updates are unsupported
1208 bool
1209 EAP::Mixer::getCoefficientMap(int &) {
1210     return false;
1211 }
1212
1213 bool
1214 EAP::Mixer::storeCoefficientMap(int &) {
1215     if(m_eap.m_mixer_readonly) {
1216         debugWarning("Mixer is read-only\n");
1217         return false;
1218     }
1219     return false;
1220 }
1221
1222 // Names
1223 std::string
1224 EAP::Mixer::getRowName(const int row) {
1225     std::string mixer_src;
1226     if (row < 0 || row > m_eap.m_mixer_nb_tx) return "Invalid";
1227     unsigned int dstid = (eRD_Mixer0<<4) + row; // Mixer has consecutive ID's
1228     debugOutput(DEBUG_LEVEL_VERBOSE, "EAP::Mixer::getRowName( %d ): ID's %d\n", row, dstid);
1229     if (m_eap.m_router){
1230       std::string mixer_dst = m_eap.m_router->getDestinationName(dstid);
1231       mixer_src = m_eap.m_router->getSourceForDestination(mixer_dst);
1232       debugOutput(DEBUG_LEVEL_VERBOSE, "EAP::Mixer::found %s as source for %s\n", mixer_src.data(),
1233                   mixer_dst.data());
1234     }
1235     else {
1236       char tmp[32];
1237       snprintf(tmp, 32, "MixIn:%d", row);
1238       mixer_src = tmp;
1239     }
1240
1241     return mixer_src;
1242 }
1243
1244 std::string
1245 EAP::Mixer::getColName(const int col) {
1246     std::string mixer_dst;
1247     stringlist dest_names;
1248    
1249     // invalid col index
1250     if (col < 0 || col > m_eap.m_mixer_nb_rx) {
1251       mixer_dst.append("Invalid");
1252       return mixer_dst;
1253     }
1254    
1255     unsigned int srcid = (eRS_Mixer<<4) + col; // Mixer has consecutive ID's
1256     debugOutput(DEBUG_LEVEL_VERBOSE, "EAP::Mixer::getColName( %d ): ID's %d\n", col, srcid);
1257     if (m_eap.m_router){
1258       std::string mixer_src = m_eap.m_router->getSourceName(srcid);
1259       dest_names = m_eap.m_router->getDestinationsForSource(mixer_src);
1260       if (dest_names.size() > 0) {
1261         stringlist::iterator it_d = dest_names.begin();
1262         stringlist::iterator it_d_end_m1 = dest_names.end(); --it_d_end_m1;
1263         while (it_d != it_d_end_m1) {
1264           mixer_dst.append((*it_d).c_str()); mixer_dst.append(";\n");
1265           it_d++;
1266         }
1267         mixer_dst.append((*it_d).c_str());
1268       }
1269     } else {
1270       char tmp[32];
1271       snprintf(tmp, 32, "MixOut:%d", col);
1272       mixer_dst.append(tmp);
1273     }
1274
1275     return mixer_dst;
1276 }
1277
1278 //
1279 // ----------- Router -------------
1280 //
1281
1282 EAP::Router::Router(EAP &p)
1283 : Control::CrossbarRouter(&p.m_device, "Router")
1284 , m_eap(p)
1285 , m_peak( *(new PeakSpace(p)) )
1286 , m_debugModule(p.m_debugModule)
1287 {
1288 }
1289
1290 EAP::Router::~Router()
1291 {
1292     delete &m_peak;
1293 }
1294
1295 void
1296 EAP::Router::update()
1297 {
1298     // Clear and
1299     //   define new sources and destinations for the router
1300     m_sources.clear();
1301     m_eap.setupSources();
1302     m_destinations.clear();
1303     m_eap.setupDestinations();
1304     return;
1305 }
1306
1307 void
1308 EAP::Router::addSource(const std::string& basename, enum eRouteSource srcid,
1309                        unsigned int base, unsigned int cnt, unsigned int offset)
1310 {
1311     std::string name = basename + ":";
1312     char tmp[4];
1313     for (unsigned int i=0; i<cnt; i++) {
1314         snprintf(tmp, 4, "%02d", offset+i);
1315         m_sources[name+tmp] = (srcid<<4) + base+i;
1316     }
1317 }
1318
1319 void
1320 EAP::Router::addDestination(const std::string& basename, enum eRouteDestination dstid,
1321                             unsigned int base, unsigned int cnt, unsigned int offset)
1322 {
1323     std::string name = basename + ":";
1324     char tmp[4];
1325     for (unsigned int i=0; i<cnt; i++) {
1326         snprintf(tmp, 4, "%02d", offset+i);
1327         m_destinations[name+tmp] = (dstid<<4) + base+i;
1328     }
1329 }
1330
1331 std::string
1332 EAP::Router::getSourceName(const int srcid)
1333 {
1334     for (std::map<std::string, int>::iterator it=m_sources.begin(); it!=m_sources.end(); ++it) {
1335         if (it->second == srcid) {
1336             return it->first;
1337         }
1338     }
1339     return "";
1340 }
1341
1342 std::string
1343 EAP::Router::getDestinationName(const int dstid)
1344 {
1345     for (std::map<std::string, int>::iterator it=m_destinations.begin(); it!=m_destinations.end(); ++it) {
1346         if (it->second == dstid) {
1347             return it->first;
1348         }
1349     }
1350     return "";
1351 }
1352
1353 int
1354 EAP::Router::getSourceIndex(std::string name)
1355 {
1356     if (m_sources.count(name) < 1)
1357         return -1;
1358     return m_sources[name];
1359 }
1360
1361 int
1362 EAP::Router::getDestinationIndex(std::string name)
1363 {
1364     if (m_destinations.count(name) < 1)
1365         return -1;
1366     return m_destinations[name];
1367 }
1368
1369 stringlist
1370 EAP::Router::getSourceNames()
1371 {
1372     stringlist n;
1373
1374     for (std::map<std::string, int>::iterator it=m_sources.begin(); it!=m_sources.end(); ++it)
1375         n.push_back(it->first);
1376     return n;
1377 }
1378
1379 stringlist
1380 EAP::Router::getDestinationNames()
1381 {
1382     stringlist n;
1383     for (std::map<std::string, int>::iterator it=m_destinations.begin(); it!=m_destinations.end(); ++it)
1384         n.push_back(it->first);
1385     return n;
1386 }
1387
1388 stringlist
1389 EAP::Router::getDestinationsForSource(const std::string& srcname) {
1390     RouterConfig* rcfg = m_eap.getActiveRouterConfig();
1391     if(rcfg == NULL) {
1392         debugError("Could not request active router configuration\n");
1393         return stringlist();
1394     }
1395     stringlist ret;
1396     std::vector<unsigned char> dests = rcfg->getDestinationsForSource(m_sources[srcname]);
1397     for (unsigned int i=0; i<dests.size(); ++i) {
1398         ret.push_back(getDestinationName(dests[i]));
1399     }
1400     return ret;
1401 }
1402 std::string
1403 EAP::Router::getSourceForDestination(const std::string& dstname) {
1404     RouterConfig* rcfg = m_eap.getActiveRouterConfig();
1405     if(rcfg == NULL) {
1406         debugError("Could not request active router configuration\n");
1407         return "";
1408     }
1409     int source = rcfg->getSourceForDestination(m_destinations[dstname]);
1410     return getSourceName(source);
1411 }
1412
1413
1414 bool
1415 EAP::Router::canConnect(const int source, const int dest)
1416 {
1417     debugWarning("TODO: Implement canConnect(0x%02x, 0x%02x)\n", source, dest);
1418
1419     // we can connect anything
1420     // FIXME: can we?
1421     return true;
1422 }
1423
1424 bool
1425 EAP::Router::setConnectionState(const int source, const int dest, const bool enable)
1426 {
1427     debugOutput(DEBUG_LEVEL_VERBOSE,"Router::setConnectionState(0x%02x -> 0x%02x ? %i)\n", source, dest, enable);
1428     // get the routing configuration
1429     RouterConfig *rcfg = m_eap.getActiveRouterConfig();
1430     if(rcfg == NULL) {
1431         debugError("Could not request active router configuration\n");
1432         return false;
1433     }
1434
1435     bool ret = false;
1436     if (enable) {
1437         ret = rcfg->setupRoute(source, dest);
1438     } else {
1439         ret = rcfg->removeRoute(source, dest);
1440     }
1441     m_eap.updateCurrentRouterConfig(*rcfg);
1442     return ret;
1443 }
1444
1445 bool
1446 EAP::Router::getConnectionState(const int source, const int dest)
1447 {
1448     // get the routing configuration
1449     RouterConfig *rcfg = m_eap.getActiveRouterConfig();
1450     if(rcfg == NULL) {
1451         debugError("Could not request active router configuration\n");
1452         return false;
1453     }
1454     if (rcfg->getSourceForDestination(dest) == source) {
1455         return true;
1456     }
1457     return false;
1458 }
1459
1460 bool
1461 EAP::Router::canConnect(const std::string& src, const std::string& dst)
1462 {
1463     int srcidx = getSourceIndex(src);
1464     int dstidx = getDestinationIndex(dst);
1465     return canConnect(srcidx, dstidx);
1466 }
1467
1468 bool
1469 EAP::Router::setConnectionState(const std::string& src, const std::string& dst, const bool enable)
1470 {
1471     int srcidx = getSourceIndex(src);
1472     int dstidx = getDestinationIndex(dst);
1473     return setConnectionState(srcidx, dstidx, enable);
1474 }
1475
1476 bool
1477 EAP::Router::getConnectionState(const std::string& src, const std::string& dst)
1478 {
1479     int srcidx = getSourceIndex(src);
1480     int dstidx = getDestinationIndex(dst);
1481     return getConnectionState(srcidx, dstidx);
1482 }
1483
1484
1485 bool
1486 EAP::Router::clearAllConnections()
1487 {
1488     // build a new empty routing configuration
1489     RouterConfig newcfg = EAP::RouterConfig(m_eap);
1490
1491     // upload the new router config
1492     if(!m_eap.updateCurrentRouterConfig(newcfg)) {
1493         debugError("Could not update router config\n");
1494         return false;
1495     }
1496     return true;
1497 }
1498
1499 bool
1500 EAP::Router::hasPeakMetering()
1501 {
1502     return m_eap.m_router_exposed;
1503 }
1504
1505 double
1506 EAP::Router::getPeakValue(const std::string& dest)
1507 {
1508     m_peak.read();
1509     unsigned char dst = m_destinations[dest];
1510     return m_peak.getPeak(dst);
1511 }
1512
1513 std::map<std::string, double>
1514 EAP::Router::getPeakValues()
1515 {
1516     m_peak.read();
1517     std::map<std::string, double> ret;
1518     std::map<unsigned char, int> peaks = m_peak.getPeaks();
1519     for (std::map<unsigned char, int>::iterator it=peaks.begin(); it!=peaks.end(); ++it) {
1520         ret[getDestinationName(it->first)] = it->second;
1521     }
1522     return ret;
1523 }
1524
1525 void
1526 EAP::Router::show()
1527 {
1528     // print the peak space as it also contains the routing configuration
1529     printMessage("Router sources:\n");
1530     for ( std::map<std::string, int>::iterator it=m_sources.begin(); it!=m_sources.end(); ++it ) {
1531         printMessage(" 0x%02x : %s\n", (*it).second, (*it).first.c_str());
1532     }
1533     printMessage("Router destinations:\n");
1534     for ( std::map<std::string, int>::iterator it=m_destinations.begin(); it!=m_destinations.end(); ++it ) {
1535         printMessage(" 0x%02x : %s\n", (*it).second, (*it).first.c_str());
1536     }
1537     printMessage("Router connections:\n");
1538     stringlist sources = getSourceNames();
1539     stringlist destinations = getDestinationNames();
1540     for (stringlist::iterator it1=sources.begin(); it1!=sources.end(); ++it1) {
1541         for (stringlist::iterator it2=destinations.begin(); it2!=destinations.end(); ++it2) {
1542             if (getConnectionState(*it1, *it2)) {
1543                 printMessage(" %s -> %s\n", it1->c_str(), it2->c_str());
1544             }
1545         }
1546     }
1547     printMessage("Active router config:\n");
1548     m_eap.getActiveRouterConfig()->show();
1549     printMessage("Active peak config:\n");
1550     m_peak.read();
1551     m_peak.show();
1552 }
1553
1554 // ----------- routing config -------------
1555 EAP::RouterConfig::RouterConfig(EAP &p)
1556 : m_eap(p)
1557 , m_base(eRT_None), m_offset(0)
1558 , m_debugModule(p.m_debugModule)
1559 {}
1560
1561 EAP::RouterConfig::RouterConfig(EAP &p, enum eRegBase b, unsigned int o)
1562 : m_eap(p)
1563 , m_base(b), m_offset(o)
1564 , m_debugModule(p.m_debugModule)
1565 {}
1566
1567 EAP::RouterConfig::~RouterConfig()
1568 {}
1569
1570 bool
1571 EAP::RouterConfig::read(enum eRegBase base, unsigned offset)
1572 {
1573     // first clear the current route vector
1574     m_routes2.clear();
1575
1576     uint32_t nb_routes;
1577     if(!m_eap.readRegBlock(base, offset, &nb_routes, 4)) {
1578         debugError("Failed to read number of entries\n");
1579         return false;
1580     }
1581     if(nb_routes == 0) {
1582         debugWarning("No routes found. Base 0x%x, offset 0x%x\n", base, offset);
1583     }
1584
1585     // read the route info
1586     uint32_t tmp_entries[nb_routes];
1587     if(!m_eap.readRegBlock(base, offset+4, tmp_entries, nb_routes*4)) {
1588         debugError("Failed to read router config block information\n");
1589         return false;
1590     }
1591
1592     // decode into the routing map
1593     for(unsigned int i=0; i < nb_routes; i++) {
1594         m_routes2[tmp_entries[i]&0xff] = (tmp_entries[i]>>8)&0xff;
1595     }
1596     return true;
1597 }
1598
1599 bool
1600 EAP::RouterConfig::write(enum eRegBase base, unsigned offset)
1601 {
1602     uint32_t nb_routes = m_routes2.size();
1603     if(nb_routes == 0) {
1604         debugWarning("Writing 0 routes? This will deactivate routing and make the device very silent...\n");
1605     }
1606     if (nb_routes > 128) {
1607         debugError("More then 128 are not possible, only the first 128 routes will get saved!\n");
1608         nb_routes = 128;
1609     }
1610     uint32_t tmp_entries[nb_routes];
1611
1612     // encode from the routing vector
1613     int i=0;
1614     for (RouteVectorV2::iterator it=m_routes2.begin(); it!=m_routes2.end(); ++it) {
1615         tmp_entries[i] = ((it->second<<8) + it->first)&0xffff;
1616         ++i;
1617     }
1618
1619     unsigned int nb_routes_max = m_eap.getMaxNbRouterEntries();
1620     uint32_t zeros[nb_routes_max+1];
1621
1622     for (unsigned int i=0; i<nb_routes_max+1; ++i) zeros[i] = 0;
1623     if(!m_eap.writeRegBlock(base, offset, zeros, (nb_routes_max+1)*4)) {
1624         debugError("Failed to write zeros to router config block\n");
1625         return false;
1626     }
1627
1628     // write the result to the device
1629     if(!m_eap.writeRegBlock(base, offset+4, tmp_entries, nb_routes*4)) {
1630         debugError("Failed to write router config block information\n");
1631         return false;
1632     }
1633     if(!m_eap.writeRegBlock(base, offset, &nb_routes, 4)) {
1634         debugError("Failed to write number of entries\n");
1635         return false;
1636     }
1637     return true;
1638 }
1639
1640 bool
1641 EAP::RouterConfig::setupRoute(unsigned char src, unsigned char dest) {
1642     debugOutput(DEBUG_LEVEL_VERBOSE,"RouterConfig::setupRoute( 0x%02x, 0x%02x )\n", src, dest);
1643     m_routes2[dest] = src;
1644     return true;
1645 }
1646
1647 bool
1648 EAP::RouterConfig::removeRoute(unsigned char src, unsigned char dest) {
1649     debugOutput(DEBUG_LEVEL_VERBOSE,"RouterConfig::removeRoute( 0x%02x, 0x%02x )\n", src, dest);
1650     if (m_routes2.count(dest) > 0) {
1651         if (src != m_routes2[dest]) {
1652             return false;
1653         }
1654         return removeRoute(dest);
1655     }
1656     return true;
1657 }
1658
1659 bool
1660 EAP::RouterConfig::removeRoute(unsigned char dest) {
1661     debugOutput(DEBUG_LEVEL_VERBOSE,"RouterConfig::removeRoute( 0x%02x )\n", dest);
1662     m_routes2.erase(dest);
1663     if (m_routes2.count(dest) < 1) {
1664         return false;
1665     }
1666     return true;
1667 }
1668
1669 unsigned char
1670 EAP::RouterConfig::getSourceForDestination(unsigned char dest) {
1671     if (m_routes2.count(dest) > 0) {
1672         return m_routes2[dest];
1673     }
1674     return -1;
1675 }
1676
1677 std::vector<unsigned char>
1678 EAP::RouterConfig::getDestinationsForSource(unsigned char source) {
1679     std::vector<unsigned char> ret;
1680     for (RouteVectorV2::iterator it=m_routes2.begin(); it!=m_routes2.end(); ++it) {
1681         if (it->second == source) {
1682             ret.push_back(it->first);
1683         }
1684     }
1685     return ret;
1686 }
1687
1688 void
1689 EAP::RouterConfig::show()
1690 {
1691     for ( RouteVectorV2::iterator it=m_routes2.begin(); it!=m_routes2.end(); ++it ) {
1692         printMessage("0x%02x -> 0x%02x\n", it->second, it->first);
1693     }
1694 }
1695
1696 //
1697 // ----------- peak space -------------
1698 //
1699
1700 bool
1701 EAP::PeakSpace::read(enum eRegBase base, unsigned offset)
1702 {
1703     uint32_t nb_routes;
1704     // we have to figure out the number of entries through the currently
1705     // active router config
1706     RouterConfig *rcfg = m_eap.getActiveRouterConfig();
1707     if(rcfg == NULL) {
1708         debugError("Could not get active router config\n");
1709         return false;
1710     }
1711     nb_routes = rcfg->getNbRoutes();
1712
1713     // read the peak/route info
1714     uint32_t tmp_entries[nb_routes];
1715     if(!m_eap.readRegBlock(base, offset, tmp_entries, nb_routes*4)) {
1716         debugError("Failed to read peak block information\n");
1717         return false;
1718     }
1719     // parse the peaks into the map
1720     for (unsigned int i=0; i<nb_routes; ++i) {
1721         unsigned char dest = tmp_entries[i]&0xff;
1722         int peak = (tmp_entries[i]&0xfff0000)>>16;
1723         if (m_peaks.count(dest) == 0 || m_peaks[dest] < peak) {
1724             m_peaks[dest] = peak;
1725         }
1726     }
1727     return true;
1728 }
1729
1730
1731 void
1732 EAP::PeakSpace::show()
1733 {
1734     printMessage("  %zi peaks\n", m_peaks.size());
1735     for (std::map<unsigned char, int>::iterator it=m_peaks.begin(); it!=m_peaks.end(); ++it) {
1736         printMessage("0x%02x : %i\n", it->first, it->second);
1737     }
1738 }
1739
1740 int
1741 EAP::PeakSpace::getPeak(unsigned char dst) {
1742     int ret = m_peaks[dst];
1743     m_peaks.erase(dst);
1744     return ret;
1745 }
1746
1747 std::map<unsigned char, int>
1748 EAP::PeakSpace::getPeaks() {
1749     // Create a new empty map
1750     std::map<unsigned char, int> ret;
1751     // Swap the peak map with the new and empty one
1752     ret.swap(m_peaks);
1753     // Return the now filled map of the peaks :-)
1754     return ret;
1755 }
1756
1757 // ----------- stream config block -------------
1758 EAP::StreamConfig::StreamConfig(EAP &p, enum eRegBase b, unsigned int o)
1759 : m_eap(p)
1760 , m_base(b), m_offset(o)
1761 , m_nb_tx(0), m_nb_rx(0)
1762 , m_tx_configs(NULL), m_rx_configs(NULL)
1763 , m_debugModule(p.m_debugModule)
1764 {
1765
1766 }
1767
1768 EAP::StreamConfig::~StreamConfig()
1769 {
1770     if(m_tx_configs) delete[]m_tx_configs;
1771     if(m_rx_configs) delete[]m_rx_configs;
1772 }
1773
1774 bool
1775 EAP::StreamConfig::read(enum eRegBase base, unsigned offset)
1776 {
1777     if(!m_eap.readRegBlock(base, offset, &m_nb_tx, 4)) {
1778         debugError("Failed to read number of tx entries\n");
1779         return false;
1780     }
1781     if(!m_eap.readRegBlock(base, offset+4, &m_nb_rx, 4)) {
1782         debugError("Failed to read number of rx entries\n");
1783         return false;
1784     }
1785     debugOutput(DEBUG_LEVEL_VERBOSE, " Entries: TX: %u, RX: %u\n", m_nb_tx, m_nb_rx);
1786
1787     if(m_tx_configs) {
1788         delete[]m_tx_configs;
1789         m_tx_configs = NULL;
1790     }
1791     if(m_rx_configs) {
1792         delete[]m_rx_configs;
1793         m_rx_configs = NULL;
1794     }
1795    
1796     offset += 8;
1797     if(m_nb_tx > 0) {
1798         m_tx_configs = new struct ConfigBlock[m_nb_tx];
1799         for(unsigned int i=0; i<m_nb_tx; i++) {
1800             fb_quadlet_t *ptr = reinterpret_cast<fb_quadlet_t *>(&(m_tx_configs[i]));
1801             if(!m_eap.readRegBlock(base, offset, ptr, sizeof(struct ConfigBlock))) {
1802                 debugError("Failed to read tx entry %d\n", i);
1803                 return false;
1804             }
1805             offset += sizeof(struct ConfigBlock);
1806         }
1807     }
1808
1809     if(m_nb_rx > 0) {
1810         m_rx_configs = new struct ConfigBlock[m_nb_rx];
1811         for(unsigned int i=0; i<m_nb_rx; i++) {
1812             fb_quadlet_t *ptr = reinterpret_cast<fb_quadlet_t *>(&(m_rx_configs[i]));
1813             if(!m_eap.readRegBlock(base, offset, ptr, sizeof(struct ConfigBlock))) {
1814                 debugError("Failed to read rx entry %d\n", i);
1815                 return false;
1816             }
1817             offset += sizeof(struct ConfigBlock);
1818         }
1819     }
1820     return true;
1821 }
1822
1823 bool
1824 EAP::StreamConfig::write(enum eRegBase base, unsigned offset)
1825 {
1826     if(!m_eap.writeRegBlock(base, offset, &m_nb_tx, 4)) {
1827         debugError("Failed to write number of tx entries\n");
1828         return false;
1829     }
1830     if(!m_eap.writeRegBlock(base, offset+4, &m_nb_rx, 4)) {
1831         debugError("Failed to write number of rx entries\n");
1832         return false;
1833     }
1834
1835     offset += 8;
1836     for(unsigned int i=0; i<m_nb_tx; i++) {
1837         fb_quadlet_t *ptr = reinterpret_cast<fb_quadlet_t *>(&(m_tx_configs[i]));
1838         if(!m_eap.writeRegBlock(base, offset, ptr, sizeof(struct ConfigBlock))) {
1839             debugError("Failed to write tx entry %d\n", i);
1840             return false;
1841         }
1842         offset += sizeof(struct ConfigBlock);
1843     }
1844
1845     for(unsigned int i=0; i<m_nb_rx; i++) {
1846         fb_quadlet_t *ptr = reinterpret_cast<fb_quadlet_t *>(&(m_rx_configs[i]));
1847         if(!m_eap.writeRegBlock(base, offset, ptr, sizeof(struct ConfigBlock))) {
1848             debugError("Failed to write rx entry %d\n", i);
1849             return false;
1850         }
1851         offset += sizeof(struct ConfigBlock);
1852     }
1853     return true;
1854 }
1855
1856 stringlist
1857 EAP::StreamConfig::getNamesForBlock(struct ConfigBlock &b)
1858 {
1859     stringlist names;
1860     char namestring[DICE_EAP_CHANNEL_CONFIG_NAMESTR_LEN_BYTES+1];
1861
1862     memcpy(namestring, b.names, DICE_EAP_CHANNEL_CONFIG_NAMESTR_LEN_BYTES);
1863
1864     // Strings from the device are always little-endian,
1865     // so byteswap for big-endian machines
1866     #if __BYTE_ORDER == __BIG_ENDIAN
1867     byteSwapBlock((quadlet_t *)namestring, DICE_EAP_CHANNEL_CONFIG_NAMESTR_LEN_QUADS);
1868     #endif
1869
1870     namestring[DICE_EAP_CHANNEL_CONFIG_NAMESTR_LEN_BYTES]='\0';
1871     return m_eap.m_device.splitNameString(std::string(namestring));
1872 }
1873
1874 stringlist
1875 EAP::StreamConfig::getTxNamesString(unsigned int i)
1876 {
1877     return getNamesForBlock(m_tx_configs[i]);
1878 }
1879
1880 stringlist
1881 EAP::StreamConfig::getRxNamesString(unsigned int i)
1882 {
1883     return getNamesForBlock(m_rx_configs[i]);
1884 }
1885
1886 void
1887 EAP::StreamConfig::showConfigBlock(struct ConfigBlock &b)
1888 {
1889     printMessage(" Channel count : %u audio, %u midi\n", b.nb_audio, b.nb_midi);
1890     printMessage(" AC3 Map       : 0x%08X\n", b.ac3_map);
1891     stringlist channel_names  = getNamesForBlock(b);
1892     printMessage("  Channel names :\n");
1893     for ( stringlist::iterator it = channel_names.begin();
1894         it != channel_names.end();
1895         ++it )
1896     {
1897         printMessage("     %s\n", (*it).c_str());
1898     }
1899 }
1900
1901 void
1902 EAP::StreamConfig::show()
1903 {
1904     for(unsigned int i=0; i<m_nb_tx; i++) {
1905         printMessage("TX Config block %d\n", i);
1906         showConfigBlock(m_tx_configs[i]);
1907     }
1908     for(unsigned int i=0; i<m_nb_rx; i++) {
1909         printMessage("RX Config block %d\n", i);
1910         showConfigBlock(m_rx_configs[i]);
1911     }
1912 }
1913
1914 } // namespace Dice
1915
1916
1917 // vim: et
Note: See TracBrowser for help on using the browser.