root/branches/echoaudio/src/bounce/bounce_avdevice.cpp

Revision 500, 18.1 kB (checked in by ppalmers, 17 years ago)

- renamed the IAvDevice to FFADODevice since it's not a pure 'AvDevice?' anymore and it also isn't an interface anymore.

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     : 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( ESamplingFrequency samplingFrequency ) {
135     int retval=convertESamplingFrequency( samplingFrequency );
136     if (retval) {
137         m_samplerate=retval;
138         return true;
139     } else return false;
140 }
141
142 bool
143 BounceDevice::lock() {
144
145     return true;
146 }
147
148
149 bool
150 BounceDevice::unlock() {
151
152     return true;
153 }
154
155 void
156 BounceDevice::showDevice()
157 {
158     debugOutput(DEBUG_LEVEL_NORMAL, "\nI am the bouncedevice, the bouncedevice I am...\n" );
159     debugOutput(DEBUG_LEVEL_NORMAL, "Vendor            :  %s\n", m_pConfigRom->getVendorName().c_str());
160     debugOutput(DEBUG_LEVEL_NORMAL, "Model             :  %s\n", m_pConfigRom->getModelName().c_str());
161     debugOutput(DEBUG_LEVEL_NORMAL, "Vendor Name       :  %s\n", m_model->vendor_name);
162     debugOutput(DEBUG_LEVEL_NORMAL, "Model Name        :  %s\n", m_model->model_name);
163     debugOutput(DEBUG_LEVEL_NORMAL, "Node              :  %d\n", m_nodeId);
164     debugOutput(DEBUG_LEVEL_NORMAL, "GUID              :  0x%016llX\n", m_pConfigRom->getGuid());
165     debugOutput(DEBUG_LEVEL_NORMAL, "\n" );
166 }
167
168 bool
169 BounceDevice::addPortsToProcessor(
170     Streaming::StreamProcessor *processor,
171     Streaming::Port::E_Direction direction) {
172
173     debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to processor\n");
174
175     std::string id=std::string("dev?");
176     if(!getOption("id", id)) {
177         debugWarning("Could not retrieve id parameter, defauling to 'dev?'\n");
178     }
179
180     int i=0;
181     for (i=0;i<BOUNCE_NB_AUDIO_CHANNELS;i++) {
182         char *buff;
183         asprintf(&buff,"%s%s_Port%d",id.c_str(),direction==Streaming::Port::E_Playback?"p":"c",i);
184
185         Streaming::Port *p=NULL;
186         p=new Streaming::AmdtpAudioPort(
187                 buff,
188                 direction,
189                 // \todo: streaming backend expects indexing starting from 0
190                 // but bebob reports it starting from 1. Decide where
191                 // and how to handle this (pp: here)
192                 i,
193                 0,
194                 Streaming::AmdtpPortInfo::E_MBLA
195         );
196
197         if (!p) {
198             debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
199         } else {
200
201             if (!processor->addPort(p)) {
202                 debugWarning("Could not register port with stream processor\n");
203                 free(buff);
204                 return false;
205             } else {
206                 debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
207             }
208         }
209         free(buff);
210     }
211
212     for (i=0;i<BOUNCE_NB_MIDI_CHANNELS;i++) {
213         char *buff;
214         asprintf(&buff,"%s_Midi%s%d",id.c_str(),direction==Streaming::Port::E_Playback?"Out":"In",i);
215
216         Streaming::Port *p=NULL;
217         p=new Streaming::AmdtpMidiPort(
218                 buff,
219                 direction,
220                 // \todo: streaming backend expects indexing starting from 0
221                 // but bebob reports it starting from 1. Decide where
222                 // and how to handle this (pp: here)
223                 BOUNCE_NB_AUDIO_CHANNELS,
224                 i,
225                 Streaming::AmdtpPortInfo::E_Midi
226         );
227
228         if (!p) {
229             debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
230         } else {
231
232             if (!processor->addPort(p)) {
233                 debugWarning("Could not register port with stream processor\n");
234                 free(buff);
235                 return false;
236             } else {
237                 debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
238             }
239         }
240         free(buff);
241      }
242
243     return true;
244 }
245
246 bool
247 BounceDevice::prepare() {
248     debugOutput(DEBUG_LEVEL_NORMAL, "Preparing BounceDevice...\n" );
249
250     bool snoopMode=false;
251     if(!getOption("snoopMode", snoopMode)) {
252         debugWarning("Could not retrieve snoopMode parameter, defauling to false\n");
253     }
254
255     // create & add streamprocessors
256     Streaming::StreamProcessor *p;
257
258     p=new Streaming::AmdtpReceiveStreamProcessor(
259                              m_p1394Service->getPort(),
260                              m_samplerate,
261                              BOUNCE_NB_AUDIO_CHANNELS+(BOUNCE_NB_MIDI_CHANNELS?1:0));
262
263     if(!p->init()) {
264         debugFatal("Could not initialize receive processor!\n");
265         delete p;
266         return false;
267     }
268
269     if (!addPortsToProcessor(p,
270             Streaming::Port::E_Capture)) {
271         debugFatal("Could not add plug to processor!\n");
272         delete p;
273         return false;
274     }
275
276     m_receiveProcessors.push_back(p);
277
278     // do the transmit processor
279     if (snoopMode) {
280         // we are snooping, so this is receive too.
281         p=new Streaming::AmdtpReceiveStreamProcessor(
282                                 m_p1394Service->getPort(),
283                                 m_samplerate,
284                                 BOUNCE_NB_AUDIO_CHANNELS+(BOUNCE_NB_MIDI_CHANNELS?1:0));
285     } else {
286         p=new Streaming::AmdtpTransmitStreamProcessor(
287                                 m_p1394Service->getPort(),
288                                 m_samplerate,
289                                 BOUNCE_NB_AUDIO_CHANNELS+(BOUNCE_NB_MIDI_CHANNELS?1:0));
290     }
291
292     if(!p->init()) {
293         debugFatal("Could not initialize transmit processor %s!\n",
294             (snoopMode?" in snoop mode":""));
295         delete p;
296         return false;
297     }
298
299     if (snoopMode) {
300         if (!addPortsToProcessor(p,
301             Streaming::Port::E_Capture)) {
302             debugFatal("Could not add plug to processor!\n");
303             delete p;
304             return false;
305         }
306         m_receiveProcessors.push_back(p);
307     } else {
308         if (!addPortsToProcessor(p,
309             Streaming::Port::E_Playback)) {
310             debugFatal("Could not add plug to processor!\n");
311             delete p;
312             return false;
313         }
314         m_transmitProcessors.push_back(p);
315     }
316
317     return true;
318 }
319
320 int
321 BounceDevice::getStreamCount() {
322     return m_receiveProcessors.size() + m_transmitProcessors.size();
323 }
324
325 Streaming::StreamProcessor *
326 BounceDevice::getStreamProcessorByIndex(int i) {
327     if (i<(int)m_receiveProcessors.size()) {
328         return m_receiveProcessors.at(i);
329     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
330         return m_transmitProcessors.at(i-m_receiveProcessors.size());
331     }
332
333     return NULL;
334 }
335
336 bool
337 BounceDevice::startStreamByIndex(int i) {
338     if (i<(int)m_receiveProcessors.size()) {
339         int n=i;
340         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
341
342         // allocate ISO channel
343         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
344         if(isochannel<0) {
345             debugError("Could not allocate iso channel for SP %d\n",i);
346             return false;
347         }
348         p->setChannel(isochannel);
349
350         fb_quadlet_t reg_isoch;
351         // check value of ISO_CHANNEL register
352         if(!readReg(BOUNCE_REGISTER_TX_ISOCHANNEL, &reg_isoch)) {
353             debugError("Could not read ISO_CHANNEL register\n", n);
354             p->setChannel(-1);
355             deallocateIsoChannel(isochannel);
356             return false;
357         }
358         if(reg_isoch != 0xFFFFFFFFUL) {
359             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X)\n", reg_isoch);
360             p->setChannel(-1);
361             deallocateIsoChannel(isochannel);
362             return false;
363         }
364
365         // write value of ISO_CHANNEL register
366         reg_isoch=isochannel;
367         if(!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, reg_isoch)) {
368             debugError("Could not write ISO_CHANNEL register\n");
369             p->setChannel(-1);
370             deallocateIsoChannel(isochannel);
371             return false;
372         }
373
374         return true;
375
376     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
377         int n=i-m_receiveProcessors.size();
378         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
379
380         // allocate ISO channel
381         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
382         if(isochannel<0) {
383             debugError("Could not allocate iso channel for SP %d\n",i);
384             return false;
385         }
386         p->setChannel(isochannel);
387
388         fb_quadlet_t reg_isoch;
389         // check value of ISO_CHANNEL register
390         if(!readReg(BOUNCE_REGISTER_RX_ISOCHANNEL, &reg_isoch)) {
391             debugError("Could not read ISO_CHANNEL register\n");
392             p->setChannel(-1);
393             deallocateIsoChannel(isochannel);
394             return false;
395         }
396         if(reg_isoch != 0xFFFFFFFFUL) {
397             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X)\n", reg_isoch);
398             p->setChannel(-1);
399             deallocateIsoChannel(isochannel);
400             return false;
401         }
402
403         // write value of ISO_CHANNEL register
404         reg_isoch=isochannel;
405         if(!writeReg(BOUNCE_REGISTER_RX_ISOCHANNEL, reg_isoch)) {
406             debugError("Could not write ISO_CHANNEL register\n");
407             p->setChannel(-1);
408             deallocateIsoChannel(isochannel);
409             return false;
410         }
411
412         return true;
413     }
414
415     debugError("SP index %d out of range!\n",i);
416
417     return false;
418 }
419
420 bool
421 BounceDevice::stopStreamByIndex(int i) {
422     if (i<(int)m_receiveProcessors.size()) {
423         int n=i;
424         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
425         unsigned int isochannel=p->getChannel();
426
427         fb_quadlet_t reg_isoch;
428         // check value of ISO_CHANNEL register
429         if(!readReg(BOUNCE_REGISTER_TX_ISOCHANNEL, &reg_isoch)) {
430             debugError("Could not read ISO_CHANNEL register\n");
431             return false;
432         }
433         if(reg_isoch != isochannel) {
434             debugError("ISO_CHANNEL register != 0x%08X (=0x%08X)\n", isochannel, reg_isoch);
435             return false;
436         }
437
438         // write value of ISO_CHANNEL register
439         reg_isoch=0xFFFFFFFFUL;
440         if(!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, reg_isoch)) {
441             debugError("Could not write ISO_CHANNEL register" );
442             return false;
443         }
444
445         // deallocate ISO channel
446         if(!deallocateIsoChannel(isochannel)) {
447             debugError("Could not deallocate iso channel for SP\n",i);
448             return false;
449         }
450
451         p->setChannel(-1);
452         return true;
453
454     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
455         int n=i-m_receiveProcessors.size();
456         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
457
458         unsigned int isochannel=p->getChannel();
459
460         fb_quadlet_t reg_isoch;
461         // check value of ISO_CHANNEL register
462         if(!readReg(BOUNCE_REGISTER_RX_ISOCHANNEL, &reg_isoch)) {
463             debugError("Could not read ISO_CHANNEL register\n");
464             return false;
465         }
466         if(reg_isoch != isochannel) {
467             debugError("ISO_CHANNEL register != 0x%08X (=0x%08X)\n", isochannel, reg_isoch);
468             return false;
469         }
470
471         // write value of ISO_CHANNEL register
472         reg_isoch=0xFFFFFFFFUL;
473         if(!writeReg(BOUNCE_REGISTER_RX_ISOCHANNEL, reg_isoch)) {
474             debugError("Could not write ISO_CHANNEL register\n");
475             return false;
476         }
477
478         // deallocate ISO channel
479         if(!deallocateIsoChannel(isochannel)) {
480             debugError("Could not deallocate iso channel for SP (%d)\n",i);
481             return false;
482         }
483
484         p->setChannel(-1);
485         return true;
486     }
487
488     debugError("SP index %d out of range!\n",i);
489     return false;
490 }
491
492 // helper functions
493
494 // allocate ISO resources for the SP's
495 int BounceDevice::allocateIsoChannel(unsigned int packet_size) {
496     unsigned int bandwidth=8+packet_size;
497
498     int ch=m_p1394Service->allocateIsoChannelGeneric(bandwidth);
499
500     debugOutput(DEBUG_LEVEL_VERBOSE, "allocated channel %d, bandwidth %d\n",
501         ch, bandwidth);
502
503     return ch;
504 }
505 // deallocate ISO resources
506 bool BounceDevice::deallocateIsoChannel(int channel) {
507     debugOutput(DEBUG_LEVEL_VERBOSE, "freeing channel %d\n",channel);
508     return m_p1394Service->freeIsoChannel(channel);
509 }
510
511 // I/O functions
512
513 bool
514 BounceDevice::readReg(fb_nodeaddr_t offset, fb_quadlet_t *result) {
515     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX\n", offset);
516
517     if(offset >= BOUNCE_INVALID_OFFSET) {
518         debugError("invalid offset: 0x%016llX\n", offset);
519         return false;
520     }
521
522     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
523     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
524
525     if(!m_p1394Service->read_quadlet( nodeId, addr, result ) ) {
526         debugError("Could not read from node 0x%04X addr 0x%012X\n", nodeId, addr);
527         return false;
528     }
529     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Read result: 0x%08X\n", *result);
530
531     return true;
532 }
533
534 bool
535 BounceDevice::writeReg(fb_nodeaddr_t offset, fb_quadlet_t data) {
536     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, data: 0x%08X\n",
537         offset, data);
538
539     if(offset >= BOUNCE_INVALID_OFFSET) {
540         debugError("invalid offset: 0x%016llX\n", offset);
541         return false;
542     }
543
544     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
545     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
546
547     if(!m_p1394Service->write_quadlet( nodeId, addr, data ) ) {
548         debugError("Could not write to node 0x%04X addr 0x%012X\n", nodeId, addr);
549         return false;
550     }
551     return true;
552 }
553
554 bool
555 BounceDevice::readRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
556     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX, length %u\n",
557         offset, length);
558
559     if(offset >= BOUNCE_INVALID_OFFSET) {
560         debugError("invalid offset: 0x%016llX\n", offset);
561         return false;
562     }
563
564     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
565     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
566
567     if(!m_p1394Service->read( nodeId, addr, length, data ) ) {
568         debugError("Could not read from node 0x%04X addr 0x%012llX\n", nodeId, addr);
569         return false;
570     }
571     return true;
572 }
573
574 bool
575 BounceDevice::writeRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
576     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, length: %u\n",
577         offset, length);
578
579     if(offset >= BOUNCE_INVALID_OFFSET) {
580         debugError("invalid offset: 0x%016llX\n", offset);
581         return false;
582     }
583
584     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
585     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
586
587     if(!m_p1394Service->write( nodeId, addr, length, data ) ) {
588         debugError("Could not write to node 0x%04X addr 0x%012llX\n", nodeId, addr);
589         return false;
590     }
591     return true;
592 }
593
594
595 } // namespace
Note: See TracBrowser for help on using the browser.