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

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

Converted sample rate setting parameter to a simple integer. The enumerated value
is only valid for the AV/C compliant devices.
(maybe we have to define another enum?)

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