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

Revision 2096, 62.2 kB (checked in by adi, 12 years ago)

DICE-EAP Mute rather than remove route when disabling a destination

By Philippe Carriere:

Really removing a route is not fully supported by all devices; then
muting is preferable when one just want to set a different connection
state (as part of a modification of one source for another one for a
given destination).

A getMuteId() function is introduced so as to be easily customized for
specific devices, if necessary.

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