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

Revision 554, 18.1 kB (checked in by ppalmers, 16 years ago)

Merge echoaudio branch into trunk.

This adds support for the Echo Audiofire devices to FFADO. Possibly also other devices working with the Apple Class Driver will work with this code. It is not fully complete yet, but the main rework is
done.

First of all the IAvDevice class/interface is renamed to FFADODevice, in order to separate the AV/C code from the FFADO API code. A device supported by FFADO implements a FFADODevice.

The BeBoB device has been split up into three groups:
- libavc/* : all code and commands that are specified by AV/C specs. Note that a lot of the code that used to be in BeBoB::AvDevice? now resides in AVC::Unit
- genericavc/* : a FFADODevice that uses AV/C descriptors & commands for discovery and config
- bebob/* : the bebob FFADODevice that inherits from GenericAVC::AvDevice? but that uses BridgeCo? commands for discovery

Everything has been moved as high as possible in the class hierarchy. If necessary, a subclass that uses device specific commands is introduced (e.g. BeBoB::Plug inherits from AVC::Plug and uses the
BridgeCo? extended plug info command to discover it's properties).

There are some other fixes along the way that have been done too.

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/general/avc_plug_info.h"
31 #include "libavc/general/avc_extended_plug_info.h"
32 #include "libavc/general/avc_subunit_info.h"
33 #include "libavc/streamformat/avc_extended_stream_format.h"
34 #include "libavc/util/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     : FFADODevice( 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 bool BounceDevice::setSamplingFrequency( int s ) {
135     if (s) {
136         m_samplerate=s;
137         return true;
138     } else return false;
139 }
140
141 int BounceDevice::getConfigurationId( ) {
142     return 0;
143 }
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.