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

Revision 864, 18.0 kB (checked in by ppalmers, 15 years ago)

update license to GPLv2 or GPLv3 instead of GPLv2 or any later version. Update copyrights to reflect the new year

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