root/branches/api-cleanup/src/bounce/bounce_avdevice.cpp

Revision 809, 18.0 kB (checked in by ppalmers, 14 years ago)

First round of cleanup:
- make Ports auto-register to a PortManager?
- remove the different 'signal' types, everything is now period-signaled.
- removed obsolete streaming test programs

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 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 3 of the License, or
13  * (at your option) any later version.
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.