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

Revision 2136, 63.4 kB (checked in by jwoithe, 10 years ago)

dice: default router setup patch 3/10 from Philippe Carriere: DICE EAP Add the (intermediate) EAP::addRoute function. The function is mainly a call to the EAP::RouterConfig::createRoute function. This will ease further customization for different devices.

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