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

Revision 584, 18.3 kB (checked in by ppalmers, 16 years ago)

- fix bug introduced in previous commit
- focusrite and terratec now have specific bebob devices

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