root/trunk/libffado/src/digidesign/digidesign_avdevice.cpp

Revision 2691, 18.2 kB (checked in by jwoithe, 7 years ago)

Initial attempt to address deprecation of auto_ptr.

C++11 deprecates auto_ptr, and gcc6 (and later versions) print compile time
warnings to this effect whenever it is encountered in the source. The
replacement type is either shared_ptr or unique_ptr depending on the usage.
For almost all usages within FFADO it seems unique_ptr could be the
appropriate choice, but the symantics are a little different to auto_ptr.
Shared_ptr on the other hand can be a drop-in replacement, although it comes
with considerable overheads which unique_ptr avoids. In the context of the
current usage, the extra overhead incurred is not critical.

The code-base cannot at this time change unconditionally to shared_ptr and
unique_ptr because these are not available in gcc4 unless "--std=c++11" is
given. When gcc4 is used certain older versions of dependent libraries must
be used and these in turn will cause compile failures in their header files
if "--std=c++11" is used (libxml++ being an example). At present there are
sufficient users of FFADO still on gcc4 to justify maintaining compatibility
with that gcc version.

The approach adopted at present is to define ffado_smartptr to be either
auto_ptr (if c++11 is not in use) or shared_ptr if it is. All auto_ptr
instances are then changed to ffado_smartptr. This should allow FFADO to be
compiled without errors or warnings on systems using gcc4 and above. Gcc6
defaults to the c++14 standard, so ffado_smartptr will be shared_ptr in that
case; thus the warnings will be avoided.

In time, once gcc4 drops out of common use, the ffado_smartptr instances can
be progressively migrated to unique_ptr or shared_ptr as is appropriate. It
has been pointed out in the ffado-devel mailing list by Jano Svitok (2 May
2017, subject "smart pointers Was: [FFADO-devel] Liquid Saffire 56") that
bebob_dl_mgr.cpp could use unique_ptr. shared_ptr should be ok in other
auto_ptr sites, but futher analysis may show that at least some of them can
use unique_ptr.

The addressing of the auto_ptr issue was prompted by Xavier Forestier's
patch set submitted to ffado-devel in November 2016.

Line 
1 /*
2  * Copyright (C) 2005-2011 by Jonathan Woithe
3  * Copyright (C) 2005-2008 by Pieter Palmers
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 #warning Digidesign support is at an early development stage and is not functional
26
27 #include "config.h"
28
29 #include "digidesign/digidesign_avdevice.h"
30
31 #include "libieee1394/configrom.h"
32 #include "libieee1394/ieee1394service.h"
33 #include "libieee1394/IsoHandlerManager.h"
34
35 #include "debugmodule/debugmodule.h"
36
37 #include "libstreaming/digidesign/DigidesignPort.h"
38
39 #include "devicemanager.h"
40
41 #include <string>
42 #include <stdint.h>
43 #include <assert.h>
44 #include "libutil/ByteSwap.h"
45
46 #include <iostream>
47 #include <sstream>
48
49 #include <libraw1394/csr.h>
50
51 namespace Digidesign {
52
53 Device::Device( DeviceManager& d,
54                       ffado_smartptr<ConfigRom>( configRom ))
55     : FFADODevice( d, configRom )
56     , m_digidesign_model( DIGIDESIGN_MODEL_NONE )
57     , num_channels( 0 )
58     , frames_per_packet( 0 )
59     , iso_tx_channel( -1 )
60     , iso_rx_channel( -1 )
61     , m_receiveProcessor( NULL )
62     , m_transmitProcessor( NULL )
63 {
64     debugOutput( DEBUG_LEVEL_VERBOSE, "Created Digidesign::Device (NodeID %d)\n",
65                  getConfigRom().getNodeId() );
66 }
67
68 Device::~Device()
69 {
70     delete m_receiveProcessor;
71     delete m_transmitProcessor;
72
73     if (iso_tx_channel>=0 && !get1394Service().freeIsoChannel(iso_tx_channel)) {
74         debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free tx iso channel %d\n", iso_tx_channel);
75     }
76     if (iso_rx_channel>=0 && !get1394Service().freeIsoChannel(iso_rx_channel)) {
77         debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free rx iso channel %d\n", iso_rx_channel);
78     }
79
80     destroyMixer();
81
82 }
83
84 bool
85 Device::buildMixer() {
86
87     destroyMixer();
88     debugOutput(DEBUG_LEVEL_VERBOSE, "Building a Digidesign mixer...\n");
89
90     // From the sounds of it there are no software-controllable device
91     // settings on the Digidesign interfaces beyond those things directly
92     // related to streaming.  Therefore this method probably doesn't need
93     // to do anything.  If this situation changes, check out the RME
94     // Device::buildMixer() method as an example of how it's done.
95
96     return true;
97 }
98
99 bool
100 Device::destroyMixer() {
101     debugOutput(DEBUG_LEVEL_VERBOSE, "destroy mixer...\n");
102
103     // If buildMixer() doesn't do anything then there's nothing for
104     // this function to do either.
105     return false;
106 }
107
108 bool
109 Device::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
110 {
111     if (generic) {
112         return false;
113     } else {
114         // check if device is in supported devices list.  This is where
115         // you insert code which allows you to identify the Digidesign
116         // devices on the bus.  For most devices the entries in the vendor
117         // model table (which are consulted here) are sufficient.
118         unsigned int vendorId = configRom.getNodeVendorId();
119         unsigned int modelId = configRom.getModelId();
120
121         Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
122         return c.isValid(vme) && vme.driver == Util::Configuration::eD_Digidesign;
123     }
124 }
125
126 FFADODevice *
127 Device::createDevice(DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ))
128 {
129     return new Device(d, configRom );
130 }
131
132 bool
133 Device::discover()
134 {
135     unsigned int vendorId = getConfigRom().getNodeVendorId();
136     unsigned int modelId = getConfigRom().getModelId();
137    
138     Util::Configuration &c = getDeviceManager().getConfiguration();
139     Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
140
141     if (c.isValid(vme) && vme.driver == Util::Configuration::eD_Digidesign) {
142         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
143                      vme.vendor_name.c_str(),
144                      vme.model_name.c_str());
145     } else {
146         debugWarning("Device '%s %s' unsupported by Digidesign driver (no generic Digidesign support)\n",
147                      getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
148     }
149
150     // Here you work out what m_digidesign_model should be set to and
151     // set it accordingly.  This can then be used by the rest of the driver
152     // whenever one needs to do different things for different interfaces.
153     //
154     // m_digidesign_model = DIGIDESIGN_MODEL_...
155     //
156     // This function should return true if the device is a supported device
157     // or false if not.  Presently only the 003 Rack is supported.
158
159     if (m_digidesign_model != DIGIDESIGN_MODEL_003_RACK) {
160         debugError("Unsupported model\n");
161         return false;
162     }
163
164     if (!buildMixer()) {
165         debugWarning("Could not build mixer\n");
166     }
167
168     return true;
169 }
170
171 int
172 Device::getSamplingFrequency( ) {
173
174     // This function should return the current sampling rate of the device.
175     return 0;
176 }
177
178 int
179 Device::getConfigurationId()
180 {
181     return 0;
182 }
183
184 bool
185 Device::setSamplingFrequency( int samplingFrequency )
186 {
187     // Do whatever it takes to set the device's sampling rate.  Return false
188     // if the requested rate cannot be done, true if it can.
189     return false;
190 }
191
192 std::vector<int>
193 Device::getSupportedSamplingFrequencies()
194 {
195     std::vector<int> frequencies;
196
197     // Generate a list of sampling rates supported by the device, in Hz.
198     // This may be a relatively simple process.  For example:
199     //   frequencies.push_back(44100);
200     //   frequencies.push_back(48000);
201
202     return frequencies;
203 }
204
205 FFADODevice::ClockSourceVector
206 Device::getSupportedClockSources() {
207     FFADODevice::ClockSourceVector r;
208     ClockSource s;
209
210     // Similar to getSupportedSamplingFrequencies(), the available clock
211     // sources for the device are configured here.  For example:
212     //   s.valid = true;
213     //   s.locked = true;
214     //   s.active = true;
215     //   s.slipping = false;
216     //   s.type = eCT_Internal;
217     //   s.description = "Internal sync";
218     //   r.push_back(s);
219     //
220     // See src/ffadodevice.h for the full list of possible eCT_* types.
221     return r;
222 }
223
224 bool
225 Device::setActiveClockSource(ClockSource s) {
226
227     // Do whatever is necessary to configure the device to use the given
228     // clock source.  Return true on success, false on error.
229     return false;
230 }
231
232 FFADODevice::ClockSource
233 Device::getActiveClockSource() {
234     ClockSource s;
235     // Return the active clock source
236     return s;
237 }
238
239 bool
240 Device::lock() {
241
242     // Use this method (and the companion unlock() method) if a device lock
243     // is required for some reason.
244     return true;
245 }
246
247
248 bool
249 Device::unlock() {
250
251     return true;
252 }
253
254 void
255 Device::showDevice()
256 {
257     unsigned int vendorId = getConfigRom().getNodeVendorId();
258     unsigned int modelId = getConfigRom().getModelId();
259
260     // This method is really just to aid debugging and can be used to to
261     // print useful identification information to the debug output.
262     Util::Configuration &c = getDeviceManager().getConfiguration();
263     Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
264
265     debugOutput(DEBUG_LEVEL_VERBOSE,
266         "%s %s at node %d\n", vme.vendor_name.c_str(), vme.model_name.c_str(), getNodeId());
267 }
268
269 bool
270 Device::prepare() {
271
272     signed int bandwidth;
273     signed int err = 0;
274
275     debugOutput(DEBUG_LEVEL_NORMAL, "Preparing Device...\n" );
276
277     // This method should prepare the device for streaming without actually
278     // turning streaming on.  It is mostly used to configure ports which
279     // will ultimately show up as JACK ports - one per audio channel.
280
281     // Store the number of frames per firewire packet.  Depending on the
282     // device protocol this may not need to be stored in a data field of
283     // the object, in which case frames_per_packet could be come a local
284     // variable.
285     frames_per_packet = getFramesPerPacket();
286
287     // Similarly, the number of channels might not be needed beyond this
288     // method.  In any case, it must be set correctly to permit calculation
289     // of required bus bandwidth.
290     num_channels = 0;
291
292     // Bus bandwidth is calculated here.  We assume the device is an S400
293     // device, so 1 allocation unit is 1 transmitted byte.  There is 25
294     // allocation units of protocol overhead per packet.  The following
295     // expression is correct if each channel of audio data is sent/received
296     // as a 32 bit integer.
297
298     bandwidth = 25 + num_channels*4*frames_per_packet;
299
300     // Depending on the device, the onus on reserving bus bandwidth rests
301     // either with the device or this driver.  The following code shows
302     // how iso channels can be requested from the IRM and then reserved
303     // with the required amount of bandwidth.
304
305     if (iso_tx_channel < 0) {
306         iso_tx_channel = get1394Service().allocateIsoChannelGeneric(bandwidth);
307     }
308     if (iso_tx_channel < 0) {
309         debugFatal("Could not allocate iso tx channel\n");
310         return false;
311     }
312
313     if (iso_rx_channel < 0) {
314         iso_rx_channel = get1394Service().allocateIsoChannelGeneric(bandwidth);
315     }
316     if (iso_rx_channel < 0) {
317         debugFatal("Could not allocate iso rx channel\n");
318         err = 1;
319     }
320  
321     if (err) {
322         if (iso_tx_channel >= 0)
323             get1394Service().freeIsoChannel(iso_tx_channel);
324         if (iso_rx_channel >= 0)
325             get1394Service().freeIsoChannel(iso_rx_channel);
326         return false;
327     }
328
329     // get the device specific and/or global SP configuration
330     Util::Configuration &config = getDeviceManager().getConfiguration();
331     // base value is the config.h value
332     float recv_sp_dll_bw = STREAMPROCESSOR_DLL_BW_HZ;
333     float xmit_sp_dll_bw = STREAMPROCESSOR_DLL_BW_HZ;
334
335     // we can override that globally
336     config.getValueForSetting("streaming.spm.recv_sp_dll_bw", recv_sp_dll_bw);
337     config.getValueForSetting("streaming.spm.xmit_sp_dll_bw", xmit_sp_dll_bw);
338
339     // or override in the device section
340     config.getValueForDeviceSetting(getConfigRom().getNodeVendorId(), getConfigRom().getModelId(), "recv_sp_dll_bw", recv_sp_dll_bw);
341     config.getValueForDeviceSetting(getConfigRom().getNodeVendorId(), getConfigRom().getModelId(), "xmit_sp_dll_bw", xmit_sp_dll_bw);
342
343     // Calculate the event size.  Each audio channel is allocated 4 bytes in
344     // the data stream by the statement which follows.  This will need to be
345     // changed to suit the Digidesign interfaces.
346     signed int event_size = num_channels * 4;
347
348     // Set up receive stream processor, initialise it and set DLL bw
349     m_receiveProcessor = new Streaming::DigidesignReceiveStreamProcessor(*this,
350       event_size);
351     m_receiveProcessor->setVerboseLevel(getDebugLevel());
352     if (!m_receiveProcessor->init()) {
353         debugFatal("Could not initialize receive processor!\n");
354         return false;
355     }
356     if (!m_receiveProcessor->setDllBandwidth(recv_sp_dll_bw)) {
357         debugFatal("Could not set DLL bandwidth\n");
358         delete m_receiveProcessor;
359         m_receiveProcessor = NULL;
360         return false;
361     }
362
363     // Add ports to the receive stream processor - one port per audio channel
364     // expected from the device.
365     std::string id=std::string("dev?");
366
367     // Ports can be added directly in this method.  I (Jonathan Woithe)
368     // prefer them in a separate method to keep the prepare() method as
369     // clear as possible.
370     addDirPorts(Streaming::Port::E_Capture);
371
372     /* Now set up the transmit stream processor */
373     m_transmitProcessor = new Streaming::DigidesignTransmitStreamProcessor(*this,
374       event_size);
375     m_transmitProcessor->setVerboseLevel(getDebugLevel());
376     if (!m_transmitProcessor->init()) {
377         debugFatal("Could not initialise receive processor!\n");
378         return false;
379     }
380     if (!m_transmitProcessor->setDllBandwidth(xmit_sp_dll_bw)) {
381         debugFatal("Could not set DLL bandwidth\n");
382         delete m_transmitProcessor;
383         m_transmitProcessor = NULL;
384         return false;
385     }
386
387     // Add ports to the transmit stream processor. This is one port
388     // per audio channel to be sent to the device.
389     addDirPorts(Streaming::Port::E_Playback);
390    
391     return true;
392 }
393
394 int
395 Device::getStreamCount() {
396     return 2; // Normally this is 2: one receive, one transmit
397 }
398
399 Streaming::StreamProcessor *
400 Device::getStreamProcessorByIndex(int i) {
401     // A housekeeping method.  This should not need to be changed.
402     switch (i) {
403         case 0:
404             return m_receiveProcessor;
405         case 1:
406             return m_transmitProcessor;
407         default:
408             debugWarning("Invalid stream index %d\n", i);
409     }
410     return NULL;
411 }
412
413 bool
414 Device::startStreamByIndex(int i) {
415     // Do whatever is needed to get the device to start the i'th stream.
416     // Some devices don't permit the separate enabling of the different
417     // streams, in which case you can do everything when stream 0 is
418     // requested, and nothing for the others.  Below is an example of this.
419     if (i == 0) {
420         m_receiveProcessor->setChannel(iso_rx_channel);
421         m_transmitProcessor->setChannel(iso_tx_channel);
422
423         // Send commands to device to start the streaming
424     }
425
426     // Return true on success, false on failure.
427     return true;
428 }
429
430 bool
431 Device::stopStreamByIndex(int i) {
432     // This method should stop the streaming for index i, returning true
433     // on success or false on error.  Again, if streams can't be stopped
434     // separately one can react only when i is 0.
435     return true;
436 }
437
438 signed int
439 Device::getFramesPerPacket(void) {
440     // Return the number of frames transmitted in a single firewire packet.
441     // For some devices this is fixed, while for others it depends on the
442     // current sampling rate.
443     //
444     // Getting the current sample rate is as simple as:
445     //   signed int freq = getSamplingFrequency();
446
447     // This needs to be set as required.
448     return 0;
449 }
450
451 bool
452 Device::addPort(Streaming::StreamProcessor *s_processor,
453     char *name, enum Streaming::Port::E_Direction direction,
454     int position, int size) {
455
456     // This is a helper method for addDirPorts() to minimise the amount of
457     // boilerplate code needed in the latter.  It creates the Port object
458     // as required, which is automatically inserted into the supplied stream
459     // processor object.
460     Streaming::Port *p;
461     p = new Streaming::DigidesignAudioPort(*s_processor, name, direction, position, size);
462     if (p == NULL) {
463         debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",name);
464     }
465     return true;
466 }
467
468 bool
469 Device::addDirPorts(enum Streaming::Port::E_Direction direction) {
470
471     const char *mode_str = direction==Streaming::Port::E_Capture?"cap":"pbk";
472     Streaming::StreamProcessor *s_processor;
473     std::string id;
474     char name[128];
475
476     // This method (in conjunction with addPort()) illustrates the port
477     // creation process.
478
479     if (direction == Streaming::Port::E_Capture) {
480         s_processor = m_receiveProcessor;
481     } else {
482         s_processor = m_transmitProcessor;
483     }
484
485     id = std::string("dev?");
486     if (!getOption("id", id)) {
487         debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n");
488     }
489
490     // Add two ports for an example
491     snprintf(name, sizeof(name), "%s_%s_%s", id.c_str(), mode_str, "port_0");
492     addPort(s_processor, name, direction, 0, 0);
493     snprintf(name, sizeof(name), "%s_%s_%s", id.c_str(), mode_str, "port_1");
494     addPort(s_processor, name, direction, 4, 0);
495
496     return true;
497 }
498
499 unsigned int
500 Device::readRegister(fb_nodeaddr_t reg) {
501
502     quadlet_t quadlet = 0;
503
504     // This function is a convenience wrapper around the read() method
505     // from ieee1394service.  It takes care of merging the node ID with
506     // the register address and any other address components which are
507     // required to construct a complete bus address.  It also deals with
508     // byte ordering.
509    
510     if (get1394Service().read(0xffc0 | getNodeId(), reg, 1, &quadlet) <= 0) {
511         debugError("Error doing Digidesign read from register 0x%06llx\n",reg);
512     }
513
514     // This return value assumes that the device uses bus byte order (big
515     // endian) for async packets.  Most do.
516     return CondSwapFromBus32(quadlet);
517 }
518
519 signed int
520 Device::readBlock(fb_nodeaddr_t reg, quadlet_t *buf, unsigned int n_quads) {
521
522     unsigned int i;
523
524     // As for readRegister() except that an arbitary block of data is
525     // transferred to the device.
526
527     if (get1394Service().read(0xffc0 | getNodeId(), reg, n_quads, buf) <= 0) {
528         debugError("Error doing Digidesign block read of %d quadlets from register 0x%06llx\n",
529             n_quads, reg);
530         return -1;
531     }
532     for (i=0; i<n_quads; i++) {
533        buf[i] = CondSwapFromBus32(buf[i]);
534     }
535
536     return 0;
537 }
538
539 signed int
540 Device::writeRegister(fb_nodeaddr_t reg, quadlet_t data) {
541
542     unsigned int err = 0;
543
544     // Similar to readRegister(), this is a convenience wrapper method
545     // around ieee1394service's write() method.  Again, this assumes that
546     // bus byte order (big endian) is expected by the device in async
547     // packets.
548
549     data = CondSwapToBus32(data);
550     if (get1394Service().write(0xffc0 | getNodeId(), reg, 1, &data) <= 0) {
551         err = 1;
552         debugError("Error doing Digidesign write to register 0x%06llx\n",reg);
553     }
554
555     return (err==0)?0:-1;
556 }
557
558 signed int
559 Device::writeBlock(fb_nodeaddr_t reg, quadlet_t *data, unsigned int n_quads) {
560
561     // Write a block of data to the device starting at address "reg".  Note
562     // that the conditional byteswap is done "in place" on data, so the
563     // contents of data may be modified by calling this function.
564
565     unsigned int err = 0;
566     unsigned int i;
567
568     for (i=0; i<n_quads; i++) {
569       data[i] = CondSwapToBus32(data[i]);
570     }
571     if (get1394Service().write(0xffc0 | getNodeId(), reg, n_quads, data) <= 0) {
572         err = 1;
573         debugError("Error doing Digidesign block write of %d quadlets to register 0x%06llx\n",
574           n_quads, reg);
575     }
576
577     return (err==0)?0:-1;
578 }
579                  
580 }
Note: See TracBrowser for help on using the browser.