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

Revision 2094, 61.1 kB (checked in by adi, 12 years ago)

DICE-EAP Add (possibly) printing the full peak space with test-dice-eap

By Philippe Carriere:

Further information (peak space) for test purposes

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