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

Revision 2056, 55.1 kB (checked in by adi, 11 years ago)

DICE EAP

Implements EAP::Mixer::getRowName and EAP::getColName

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