root/trunk/libffado/src/bounce/bounce_avdevice.cpp

Revision 479, 18.1 kB (checked in by wagi, 15 years ago)

- added all missing 'virtual' to function declared in avdevice implementation
- added getConfigurationId function (used for av/c model caching)

Line 
1 /*
2  * Copyright (C) 2005-2007 by Pieter Palmers
3  * Copyright (C) 2005-2007 by Daniel Wagner
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License version 2.1, as published by the Free Software Foundation;
13  *
14  * This library 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 GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  * MA 02110-1301 USA
23  */
24
25 #include "bounce/bounce_avdevice.h"
26
27 #include "libieee1394/configrom.h"
28 #include "libieee1394/ieee1394service.h"
29
30 #include "libavc/avc_plug_info.h"
31 #include "libavc/avc_extended_plug_info.h"
32 #include "libavc/avc_subunit_info.h"
33 #include "libavc/avc_extended_stream_format.h"
34 #include "libavc/avc_serialize.h"
35 #include "libavc/avc_definitions.h"
36
37 #include "debugmodule/debugmodule.h"
38
39 #include <iostream>
40 #include <sstream>
41 #include <stdint.h>
42
43 #include <string>
44 #include <netinet/in.h>
45
46 namespace Bounce {
47
48 // to define the supported devices
49 static VendorModelEntry supportedDeviceList[] =
50 {
51     {0x0B0001LU, 0x0B0001LU, 0x0B0001LU, "FFADO", "Bounce"},
52 };
53
54 BounceDevice::BounceDevice( std::auto_ptr< ConfigRom >( configRom ),
55                             Ieee1394Service& ieee1394service,
56                             int nodeId )
57     : IAvDevice( configRom, ieee1394service, nodeId )
58     , m_samplerate (44100)
59     , m_model( NULL )
60     , m_Notifier ( NULL )
61 {
62     debugOutput( DEBUG_LEVEL_VERBOSE, "Created Bounce::BounceDevice (NodeID %d)\n",
63                  nodeId );
64     addOption(Util::OptionContainer::Option("snoopMode",false));
65 }
66
67 BounceDevice::~BounceDevice()
68 {
69
70 }
71
72 bool
73 BounceDevice::probe( ConfigRom& configRom )
74 {
75
76     debugOutput( DEBUG_LEVEL_VERBOSE, "probing BounceDevice\n");
77 //     unsigned int vendorId = configRom.getNodeVendorId();
78     unsigned int modelId = configRom.getModelId();
79     unsigned int unitSpecifierId = configRom.getUnitSpecifierId();
80     debugOutput( DEBUG_LEVEL_VERBOSE, "modelId = 0x%08X, specid = 0x%08X\n", modelId, unitSpecifierId);
81
82     for ( unsigned int i = 0;
83           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
84           ++i )
85     {
86         if (
87 //             ( supportedDeviceList[i].vendor_id == vendorId )
88              ( supportedDeviceList[i].model_id == modelId )
89              && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
90            )
91         {
92             return true;
93         }
94     }
95
96     return false;
97 }
98
99 bool
100 BounceDevice::discover()
101 {
102     debugOutput( DEBUG_LEVEL_VERBOSE, "discovering BounceDevice (NodeID %d)\n",
103                  m_nodeId );
104
105 //     unsigned int vendorId = m_pConfigRom->getNodeVendorId();
106     unsigned int modelId = m_pConfigRom->getModelId();
107     unsigned int unitSpecifierId = m_pConfigRom->getUnitSpecifierId();
108
109     for ( unsigned int i = 0;
110           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
111           ++i )
112     {
113         if ( //( supportedDeviceList[i].vendor_id == vendorId )
114              ( supportedDeviceList[i].model_id == modelId )
115              && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
116            )
117         {
118             m_model = &(supportedDeviceList[i]);
119         }
120     }
121
122     if (m_model != NULL) {
123         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
124                 m_model->vendor_name, m_model->model_name);
125         return true;
126     }
127     return false;
128 }
129
130 int BounceDevice::getSamplingFrequency( ) {
131     return m_samplerate;
132 }
133
134 int BounceDevice::getConfigurationId( ) {
135     return 0;
136 }
137
138 bool BounceDevice::setSamplingFrequency( ESamplingFrequency samplingFrequency ) {
139     int retval=convertESamplingFrequency( samplingFrequency );
140     if (retval) {
141         m_samplerate=retval;
142         return true;
143     } else return false;
144 }
145
146 bool
147 BounceDevice::lock() {
148
149     return true;
150 }
151
152
153 bool
154 BounceDevice::unlock() {
155
156     return true;
157 }
158
159 void
160 BounceDevice::showDevice()
161 {
162     debugOutput(DEBUG_LEVEL_NORMAL, "\nI am the bouncedevice, the bouncedevice I am...\n" );
163     debugOutput(DEBUG_LEVEL_NORMAL, "Vendor            :  %s\n", m_pConfigRom->getVendorName().c_str());
164     debugOutput(DEBUG_LEVEL_NORMAL, "Model             :  %s\n", m_pConfigRom->getModelName().c_str());
165     debugOutput(DEBUG_LEVEL_NORMAL, "Vendor Name       :  %s\n", m_model->vendor_name);
166     debugOutput(DEBUG_LEVEL_NORMAL, "Model Name        :  %s\n", m_model->model_name);
167     debugOutput(DEBUG_LEVEL_NORMAL, "Node              :  %d\n", m_nodeId);
168     debugOutput(DEBUG_LEVEL_NORMAL, "GUID              :  0x%016llX\n", m_pConfigRom->getGuid());
169     debugOutput(DEBUG_LEVEL_NORMAL, "\n" );
170 }
171
172 bool
173 BounceDevice::addPortsToProcessor(
174     Streaming::StreamProcessor *processor,
175     Streaming::Port::E_Direction direction) {
176
177     debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to processor\n");
178
179     std::string id=std::string("dev?");
180     if(!getOption("id", id)) {
181         debugWarning("Could not retrieve id parameter, defauling to 'dev?'\n");
182     }
183
184     int i=0;
185     for (i=0;i<BOUNCE_NB_AUDIO_CHANNELS;i++) {
186         char *buff;
187         asprintf(&buff,"%s%s_Port%d",id.c_str(),direction==Streaming::Port::E_Playback?"p":"c",i);
188
189         Streaming::Port *p=NULL;
190         p=new Streaming::AmdtpAudioPort(
191                 buff,
192                 direction,
193                 // \todo: streaming backend expects indexing starting from 0
194                 // but bebob reports it starting from 1. Decide where
195                 // and how to handle this (pp: here)
196                 i,
197                 0,
198                 Streaming::AmdtpPortInfo::E_MBLA
199         );
200
201         if (!p) {
202             debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
203         } else {
204
205             if (!processor->addPort(p)) {
206                 debugWarning("Could not register port with stream processor\n");
207                 free(buff);
208                 return false;
209             } else {
210                 debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
211             }
212         }
213         free(buff);
214     }
215
216     for (i=0;i<BOUNCE_NB_MIDI_CHANNELS;i++) {
217         char *buff;
218         asprintf(&buff,"%s_Midi%s%d",id.c_str(),direction==Streaming::Port::E_Playback?"Out":"In",i);
219
220         Streaming::Port *p=NULL;
221         p=new Streaming::AmdtpMidiPort(
222                 buff,
223                 direction,
224                 // \todo: streaming backend expects indexing starting from 0
225                 // but bebob reports it starting from 1. Decide where
226                 // and how to handle this (pp: here)
227                 BOUNCE_NB_AUDIO_CHANNELS,
228                 i,
229                 Streaming::AmdtpPortInfo::E_Midi
230         );
231
232         if (!p) {
233             debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
234         } else {
235
236             if (!processor->addPort(p)) {
237                 debugWarning("Could not register port with stream processor\n");
238                 free(buff);
239                 return false;
240             } else {
241                 debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
242             }
243         }
244         free(buff);
245      }
246
247     return true;
248 }
249
250 bool
251 BounceDevice::prepare() {
252     debugOutput(DEBUG_LEVEL_NORMAL, "Preparing BounceDevice...\n" );
253
254     bool snoopMode=false;
255     if(!getOption("snoopMode", snoopMode)) {
256         debugWarning("Could not retrieve snoopMode parameter, defauling to false\n");
257     }
258
259     // create & add streamprocessors
260     Streaming::StreamProcessor *p;
261
262     p=new Streaming::AmdtpReceiveStreamProcessor(
263                              m_p1394Service->getPort(),
264                              m_samplerate,
265                              BOUNCE_NB_AUDIO_CHANNELS+(BOUNCE_NB_MIDI_CHANNELS?1:0));
266
267     if(!p->init()) {
268         debugFatal("Could not initialize receive processor!\n");
269         delete p;
270         return false;
271     }
272
273     if (!addPortsToProcessor(p,
274             Streaming::Port::E_Capture)) {
275         debugFatal("Could not add plug to processor!\n");
276         delete p;
277         return false;
278     }
279
280     m_receiveProcessors.push_back(p);
281
282     // do the transmit processor
283     if (snoopMode) {
284         // we are snooping, so this is receive too.
285         p=new Streaming::AmdtpReceiveStreamProcessor(
286                                 m_p1394Service->getPort(),
287                                 m_samplerate,
288                                 BOUNCE_NB_AUDIO_CHANNELS+(BOUNCE_NB_MIDI_CHANNELS?1:0));
289     } else {
290         p=new Streaming::AmdtpTransmitStreamProcessor(
291                                 m_p1394Service->getPort(),
292                                 m_samplerate,
293                                 BOUNCE_NB_AUDIO_CHANNELS+(BOUNCE_NB_MIDI_CHANNELS?1:0));
294     }
295
296     if(!p->init()) {
297         debugFatal("Could not initialize transmit processor %s!\n",
298             (snoopMode?" in snoop mode":""));
299         delete p;
300         return false;
301     }
302
303     if (snoopMode) {
304         if (!addPortsToProcessor(p,
305             Streaming::Port::E_Capture)) {
306             debugFatal("Could not add plug to processor!\n");
307             delete p;
308             return false;
309         }
310         m_receiveProcessors.push_back(p);
311     } else {
312         if (!addPortsToProcessor(p,
313             Streaming::Port::E_Playback)) {
314             debugFatal("Could not add plug to processor!\n");
315             delete p;
316             return false;
317         }
318         m_transmitProcessors.push_back(p);
319     }
320
321     return true;
322 }
323
324 int
325 BounceDevice::getStreamCount() {
326     return m_receiveProcessors.size() + m_transmitProcessors.size();
327 }
328
329 Streaming::StreamProcessor *
330 BounceDevice::getStreamProcessorByIndex(int i) {
331     if (i<(int)m_receiveProcessors.size()) {
332         return m_receiveProcessors.at(i);
333     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
334         return m_transmitProcessors.at(i-m_receiveProcessors.size());
335     }
336
337     return NULL;
338 }
339
340 bool
341 BounceDevice::startStreamByIndex(int i) {
342     if (i<(int)m_receiveProcessors.size()) {
343         int n=i;
344         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
345
346         // allocate ISO channel
347         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
348         if(isochannel<0) {
349             debugError("Could not allocate iso channel for SP %d\n",i);
350             return false;
351         }
352         p->setChannel(isochannel);
353
354         fb_quadlet_t reg_isoch;
355         // check value of ISO_CHANNEL register
356         if(!readReg(BOUNCE_REGISTER_TX_ISOCHANNEL, &reg_isoch)) {
357             debugError("Could not read ISO_CHANNEL register\n", n);
358             p->setChannel(-1);
359             deallocateIsoChannel(isochannel);
360             return false;
361         }
362         if(reg_isoch != 0xFFFFFFFFUL) {
363             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X)\n", reg_isoch);
364             p->setChannel(-1);
365             deallocateIsoChannel(isochannel);
366             return false;
367         }
368
369         // write value of ISO_CHANNEL register
370         reg_isoch=isochannel;
371         if(!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, reg_isoch)) {
372             debugError("Could not write ISO_CHANNEL register\n");
373             p->setChannel(-1);
374             deallocateIsoChannel(isochannel);
375             return false;
376         }
377
378         return true;
379
380     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
381         int n=i-m_receiveProcessors.size();
382         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
383
384         // allocate ISO channel
385         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
386         if(isochannel<0) {
387             debugError("Could not allocate iso channel for SP %d\n",i);
388             return false;
389         }
390         p->setChannel(isochannel);
391
392         fb_quadlet_t reg_isoch;
393         // check value of ISO_CHANNEL register
394         if(!readReg(BOUNCE_REGISTER_RX_ISOCHANNEL, &reg_isoch)) {
395             debugError("Could not read ISO_CHANNEL register\n");
396             p->setChannel(-1);
397             deallocateIsoChannel(isochannel);
398             return false;
399         }
400         if(reg_isoch != 0xFFFFFFFFUL) {
401             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X)\n", reg_isoch);
402             p->setChannel(-1);
403             deallocateIsoChannel(isochannel);
404             return false;
405         }
406
407         // write value of ISO_CHANNEL register
408         reg_isoch=isochannel;
409         if(!writeReg(BOUNCE_REGISTER_RX_ISOCHANNEL, reg_isoch)) {
410             debugError("Could not write ISO_CHANNEL register\n");
411             p->setChannel(-1);
412             deallocateIsoChannel(isochannel);
413             return false;
414         }
415
416         return true;
417     }
418
419     debugError("SP index %d out of range!\n",i);
420
421     return false;
422 }
423
424 bool
425 BounceDevice::stopStreamByIndex(int i) {
426     if (i<(int)m_receiveProcessors.size()) {
427         int n=i;
428         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
429         unsigned int isochannel=p->getChannel();
430
431         fb_quadlet_t reg_isoch;
432         // check value of ISO_CHANNEL register
433         if(!readReg(BOUNCE_REGISTER_TX_ISOCHANNEL, &reg_isoch)) {
434             debugError("Could not read ISO_CHANNEL register\n");
435             return false;
436         }
437         if(reg_isoch != isochannel) {
438             debugError("ISO_CHANNEL register != 0x%08X (=0x%08X)\n", isochannel, reg_isoch);
439             return false;
440         }
441
442         // write value of ISO_CHANNEL register
443         reg_isoch=0xFFFFFFFFUL;
444         if(!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, reg_isoch)) {
445             debugError("Could not write ISO_CHANNEL register" );
446             return false;
447         }
448
449         // deallocate ISO channel
450         if(!deallocateIsoChannel(isochannel)) {
451             debugError("Could not deallocate iso channel for SP\n",i);
452             return false;
453         }
454
455         p->setChannel(-1);
456         return true;
457
458     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
459         int n=i-m_receiveProcessors.size();
460         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
461
462         unsigned int isochannel=p->getChannel();
463
464         fb_quadlet_t reg_isoch;
465         // check value of ISO_CHANNEL register
466         if(!readReg(BOUNCE_REGISTER_RX_ISOCHANNEL, &reg_isoch)) {
467             debugError("Could not read ISO_CHANNEL register\n");
468             return false;
469         }
470         if(reg_isoch != isochannel) {
471             debugError("ISO_CHANNEL register != 0x%08X (=0x%08X)\n", isochannel, reg_isoch);
472             return false;
473         }
474
475         // write value of ISO_CHANNEL register
476         reg_isoch=0xFFFFFFFFUL;
477         if(!writeReg(BOUNCE_REGISTER_RX_ISOCHANNEL, reg_isoch)) {
478             debugError("Could not write ISO_CHANNEL register\n");
479             return false;
480         }
481
482         // deallocate ISO channel
483         if(!deallocateIsoChannel(isochannel)) {
484             debugError("Could not deallocate iso channel for SP (%d)\n",i);
485             return false;
486         }
487
488         p->setChannel(-1);
489         return true;
490     }
491
492     debugError("SP index %d out of range!\n",i);
493     return false;
494 }
495
496 // helper functions
497
498 // allocate ISO resources for the SP's
499 int BounceDevice::allocateIsoChannel(unsigned int packet_size) {
500     unsigned int bandwidth=8+packet_size;
501
502     int ch=m_p1394Service->allocateIsoChannelGeneric(bandwidth);
503
504     debugOutput(DEBUG_LEVEL_VERBOSE, "allocated channel %d, bandwidth %d\n",
505         ch, bandwidth);
506
507     return ch;
508 }
509 // deallocate ISO resources
510 bool BounceDevice::deallocateIsoChannel(int channel) {
511     debugOutput(DEBUG_LEVEL_VERBOSE, "freeing channel %d\n",channel);
512     return m_p1394Service->freeIsoChannel(channel);
513 }
514
515 // I/O functions
516
517 bool
518 BounceDevice::readReg(fb_nodeaddr_t offset, fb_quadlet_t *result) {
519     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX\n", offset);
520
521     if(offset >= BOUNCE_INVALID_OFFSET) {
522         debugError("invalid offset: 0x%016llX\n", offset);
523         return false;
524     }
525
526     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
527     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
528
529     if(!m_p1394Service->read_quadlet( nodeId, addr, result ) ) {
530         debugError("Could not read from node 0x%04X addr 0x%012X\n", nodeId, addr);
531         return false;
532     }
533     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Read result: 0x%08X\n", *result);
534
535     return true;
536 }
537
538 bool
539 BounceDevice::writeReg(fb_nodeaddr_t offset, fb_quadlet_t data) {
540     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, data: 0x%08X\n",
541         offset, data);
542
543     if(offset >= BOUNCE_INVALID_OFFSET) {
544         debugError("invalid offset: 0x%016llX\n", offset);
545         return false;
546     }
547
548     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
549     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
550
551     if(!m_p1394Service->write_quadlet( nodeId, addr, data ) ) {
552         debugError("Could not write to node 0x%04X addr 0x%012X\n", nodeId, addr);
553         return false;
554     }
555     return true;
556 }
557
558 bool
559 BounceDevice::readRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
560     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX, length %u\n",
561         offset, length);
562
563     if(offset >= BOUNCE_INVALID_OFFSET) {
564         debugError("invalid offset: 0x%016llX\n", offset);
565         return false;
566     }
567
568     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
569     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
570
571     if(!m_p1394Service->read( nodeId, addr, length, data ) ) {
572         debugError("Could not read from node 0x%04X addr 0x%012llX\n", nodeId, addr);
573         return false;
574     }
575     return true;
576 }
577
578 bool
579 BounceDevice::writeRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
580     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, length: %u\n",
581         offset, length);
582
583     if(offset >= BOUNCE_INVALID_OFFSET) {
584         debugError("invalid offset: 0x%016llX\n", offset);
585         return false;
586     }
587
588     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
589     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
590
591     if(!m_p1394Service->write( nodeId, addr, length, data ) ) {
592         debugError("Could not write to node 0x%04X addr 0x%012llX\n", nodeId, addr);
593         return false;
594     }
595     return true;
596 }
597
598
599 } // namespace
Note: See TracBrowser for help on using the browser.