About ticket #360

1.Background

Echo Audio produced Fireworks device module for sound devices connected to IEEE 1394. This device module is applied to Mackie F series (Loud Technologies), AudioFire series (Echo Audio) and Robot Interface Pack (Gibson).

Fireworks consists of three chipset; a communication chipset for IEEE 1394 Link/Transaction/Serial-Bus-Management and IEC 61883-1/6 (iceLynx Micro series of Texas Instruments), DSP or/and FPGA for signal processing and flash memory to store firmwares.

Fireworks has some specific features. One of the features is to allow to update its firmware. As of middle of 2014, the version of latest firmware is 5.8.

The content of firmware is different depending on target devices. But usually it consists of three parts; bootstrap, codes for a communication chipset and codes for DSP or/and FPGA. In detail, see: http://subversion.ffado.org/wiki/Fireworks

Fireworks uses its own way for transaction. Fireworks drivers can control Fireworks behaviour via the transaction. The frame of transaction can be transferred by AV/C vendor dependent command or by simple IEEE 1394 WRITE transaction. The former may be for OS X operating system and the latter may be for Windows operating system. FFADO uses the former way.

The frame of transaction can be described in this structure:

struct snd_efw_transaction {
	__be32 length;
	__be32 version;
	__be32 seqnum;
	__be32 category;
	__be32 command;
	__be32 status;
	__be32 params[0];
};

When this frame is transferred by simple IEEE 1394 WRITE transaction, the address for request is 0xecc0'0000'0000 and the address for response is 0xecc0'8000'0000. These addresses are default value. The address for response is changeable by a certain command.

2.Ticket #360 and progress

July 8, 2008, "picander" registered this ticket with some logs. He or She insists that FFADO cannot drive his or her AudioFire12 with firmware version 5.7. http://subversion.ffado.org/wiki/Fireworks

According to the logs, two command are failed. The two commands are to get current sampling rate and to get polled values. Then the latter command causes an assertion due to wrong parameters in response frame: http://subversion.ffado.org/attachment/ticket/360/debug.txt

When this ticket was registered, FFADO developers who commit to Fireworks driver was not active, thus this ticket was kept not to be solved.

May 6, 2012, Matthew Robbetts reported to "ffado-devel" that AudioFire8 has the same issue with firmware version 5.7. http://sourceforge.net/p/ffado/mailman/message/28941892/

Since 2013, I, Takashi Sakamoto, started to develop ALSA driver for Fireworks.

Oct 2013, I had an opportunity to test with AudioFire12 and confirmed that requests/responses over AV/C command caused the issue but they as WRITE transaction didin't. I added some fallbacks for failure of the two requests. In this time, I have little time to investigate deeper because of a short period for investigation. The device is not mine, and in this time I was hard to improve FFADO BeBoB drivers to help my developing for ALSA firewire stack.

Nov 2013, I had a contact to Echo Audio and asked about the three commands. The person replied that they dropped the three commands over AV/C vendor dependent command from recent version for AudioFire8/12. But the version is not disclosed.

Apr 2014, I almost finished my work for ALSA firewire stack and drivers. During reviewing, I just got a time for this issue.

May 2014, for FFADO version 2.2 release, I started to fix this issue. I realized that some fallbacks added Oct 2013 were not enough to solve this issue. Then I managed to fix them and some commits are merged. Then this ticket was closed.

But this was not enough. After FFADO version 2.2.1 was released, it's clear that FFADO Fireworks driver was still not fixed and this ticket is reopened. I had no way to fix this issue because I don't own AudioFire8/12 and users just reported it without enough communication to us.

July 2014, Matthias Küttner personally contacted to me about this issue. He gathered some information with his AudioFire12 and I realized what causes this issue.

3.What causes

The ticket #360 includes several issues:

  1. AudioFire8/12 don't implement EfcPolledValuesCmd/EfcGetClockCmd/EfcGetClockCmd.
  2. A bug in Fireworks::Device::doEfcOverAVC()
  3. FFADO Fireworks driver needs alternatives for EfcGetClockCmd/EfcSetClockCmd.

I describe the detail.

3.1. AudioFire8/12 don't implement EfcPolledValuesCmd/EfcGetClockCmd/EfcSetClockCmd.

Here, I show samples for actual transactions for these requests. They are retrieved by Matthias Küttner with his AudioFire12. His help is really what FFADO developers need. He built FFADO 2.2.1 with "DEBUG_MESSAGES" flag and run FFADO applications (ffado-test/ffado-dbus-server/jackd) with verbose option.

For EfcGetClockCmd

EfcOverAVCCmd:
  Request:
    0:  00 ff 00 00  00 00 00 00  00 00 00 06  00 00 00 00
   16:  00 00 00 0d  00 00 00 00  00 00 00 01  00 00 00 00
    0:  0x00    AVCCommand ctype ('control')
    1:  0xff    AVCCommand subunit (subunit_type = 31, subunit_id = 7)
    2:  0x00    AVCCommand opcode
    3:  0x00    VendorDependentCmd companyid[2]
    4:  0x00    VendorDependentCmd companyid[1]
    5:  0x00    VendorDependentCmd companyid[0]
    6:  0x00    Dummy byte 1
    7:  0x00    Dummy byte 1
    8:  0x06000000      EFC length
   12:  0x00000000      EFC header version
   16:  0x0e000000      EFC header seqnum
   20:  0x00000000      EFC header category
   24:  0x01000000      EFC header command
   28:  0x00000000      EFC header return value

  Response:
    0:  0a ff 00 00  00 00 00 00  00 00 00 06  00 00 00 00
   16:  00 00 00 0d  00 00 00 00  00 00 00 01  00 00 00 00
    0:  0x0a    AVCCommand ctype ('rejected')
    1:  0xff    AVCCommand subunit (subunit_type = 31, subunit_id = 7)
    2:  0x00    AVCCommand opcode
    3:  0x00    VendorDependentCmd companyid[2]
    4:  0x00    VendorDependentCmd companyid[1]
    5:  0x00    VendorDependentCmd companyid[0]
    6:  0x00    Dummy byte 1
    7:  0x00    Dummy byte 1
    8:  0x06000000      EFC length
   12:  0x00000000      EFC header version
   16:  0x0f000000      EFC header seqnum
   20:  0x00000000      EFC header category
   24:  0x01000000      EFC header command
   28:  0x00000000      EFC header return value

For EfcGetClockCmd:

EfcOverAVCCmd:
  Request:
    0:  00 ff 00 00  00 00 00 00  00 00 00 06  00 00 00 00 
   16:  00 00 00 0a  00 00 00 03  00 00 00 01  00 00 00 00 
    0:  0x00    AVCCommand ctype ('control')
    1:  0xff    AVCCommand subunit (subunit_type = 31, subunit_id = 7)
    2:  0x00    AVCCommand opcode
    3:  0x00    VendorDependentCmd companyid[2]
    4:  0x00    VendorDependentCmd companyid[1]
    5:  0x00    VendorDependentCmd companyid[0]
    6:  0x00    Dummy byte 1
    7:  0x00    Dummy byte 1
    8:  0x06000000      EFC length
   12:  0x00000000      EFC header version
   16:  0x0b000000      EFC header seqnum
   20:  0x03000000      EFC header category
   24:  0x01000000      EFC header command
   28:  0x00000000      EFC header return value

  Response:
    0:  0a ff 00 00  00 00 00 00  00 00 00 06  00 00 00 00 
   16:  00 00 00 0a  00 00 00 03  00 00 00 01  00 00 00 00 
    0:  0x0a    AVCCommand ctype ('rejected')
    1:  0xff    AVCCommand subunit (subunit_type = 31, subunit_id = 7)
    2:  0x00    AVCCommand opcode
    3:  0x00    VendorDependentCmd companyid[2]
    4:  0x00    VendorDependentCmd companyid[1]
    5:  0x00    VendorDependentCmd companyid[0]
    6:  0x00    Dummy byte 1
    7:  0x00    Dummy byte 1
    8:  0x06000000      EFC length
   12:  0x00000000      EFC header version
   16:  0x0c000000      EFC header seqnum
   20:  0x03000000      EFC header category
   24:  0x01000000      EFC header command
   28:  0x00000000      EFC header return value

For EfcSetClockCmd:

EfcOverAVCCmd:
  Request:
    0:	00 ff 00 00  00 00 00 00  00 00 00 09  00 00 00 00 
   16:	00 00 00 16  00 00 00 03  00 00 00 00  00 00 00 00 
   32:	00 00 00 00  00 00 bb 80  00 00 00 00 
    0:	0x00	AVCCommand ctype ('control')
    1:	0xff	AVCCommand subunit (subunit_type = 31, subunit_id = 7)
    2:	0x00	AVCCommand opcode
    3:	0x00	VendorDependentCmd companyid[2]
    4:	0x00	VendorDependentCmd companyid[1]
    5:	0x00	VendorDependentCmd companyid[0]
    6:	0x00	Dummy byte 1
    7:	0x00	Dummy byte 1
    8:	0x09000000	EFC length
   12:	0x00000000	EFC header version
   16:	0x17000000	EFC header seqnum
   20:	0x03000000	EFC header category
   24:	0x00000000	EFC header command
   28:	0x00000000	EFC header return value
   32:	0x00000000	Clock
   36:	0x80bb0000	Samplerate
   40:	0x00000000	Index

  Response:
    0:	0a ff 00 00  00 00 00 00  00 00 00 09  00 00 00 00 
   16:	00 00 00 16  00 00 00 03  00 00 00 00  00 00 00 00 
   32:	00 00 00 00  00 00 bb 80  00 00 00 00 
    0:	0x0a	AVCCommand ctype ('rejected')
    1:	0xff	AVCCommand subunit (subunit_type = 31, subunit_id = 7)
    2:	0x00	AVCCommand opcode
    3:	0x00	VendorDependentCmd companyid[2]
    4:	0x00	VendorDependentCmd companyid[1]
    5:	0x00	VendorDependentCmd companyid[0]
    6:	0x00	Dummy byte 1
    7:	0x00	Dummy byte 1
    8:	0x09000000	EFC length
   12:	0x00000000	EFC header version
   16:	0x18000000	EFC header seqnum
   20:	0x03000000	EFC header category
   24:	0x00000000	EFC header command
   28:	0x00000000	EFC header return value
   32:	0x00000000	Clock
   36:	0x80bb0000	Samplerate
   40:	0x00000000	Index

Let's focus on the first byte. It means that the target device reject the requests. It's clear that these three requests are not handled. (According to "AV/C Digital Interface Command Set General Specification", it should be 0x08, "NOT IMPLEMENTED".)

3.2. A bug in Fireworks::Device::doEfcOverAVC()

http://subversion.ffado.org/attachment/ticket/360/debug.txt

ffado-test: src/fireworks/efc/efc_cmds_hardware.cpp:213:
virtual bool FireWorks::EfcPolledValuesCmd::deserialize(Util::Cmd::IISDeserialize&):
Assertion `nb_meters<100' failed.

The assertion was in Fireworks::Device::EfcPolledValuesCmd::deserialize() (until r2451).

libffado:src/fireworks/efc/efc_cmds_hardware.cpp

bool
EfcPolledValuesCmd::deserialize( Util::Cmd::IISDeserialize& de )
{
    bool result=true;
    
    result &= EfcCmd::deserialize ( de );
    
    // the serialization is different from the deserialization
    ....
    EFC_DESERIALIZE_AND_SWAP(de, &m_nb_output_meters, result);
    EFC_DESERIALIZE_AND_SWAP(de, &m_nb_input_meters, result);
    ....
    int nb_meters=m_nb_output_meters+m_nb_input_meters;
    
    assert(nb_meters<POLLED_MAX_NB_METERS);
    ....
    return result;
}

Callgraph:

DeviceManager::discover()
->DeviceManager::showDeviceInfo()
->Fireworks::Device::getSupportedClockSources()
->Fireworks::Device::clockIdToClockSource()
->Fireworks::Device::isClockValid()
->Fireworks::Device::updatePolledValues()
->Fireworks::Device::doEfcOverAVC()
  ->Fireworks::EfcOverAVCCmd::fire() (=AVC::AVCCommand::fire())
    ->Fireworks::EfcOverAVCCmd::deserialize()
      ->AVC::VendorDependentCmd::deserialie()
        ->AVC::AVCCommand::deserialize()
      ->Fireworks::EfcPolledValuesCmd::deserialize()
        ->Fireworks::EfcCmd::deserialize()
  ->Fireworks::EfcPolledValuesCmd::showEfcCmd()

libffado:src/fireworks/efc/efc_avc_cmd.cpp

bool
EfcOverAVCCmd::deserialize( Util::Cmd::IISDeserialize& de )
{
    result &= VendorDependentCmd::deserialize( de );
    
    result &= de.read(&m_dummy_1);
    result &= de.read(&m_dummy_2);

    if(!result) {
        debugWarning("AV/C deserialization failed\n");
        return false;
    }

    result &= m_cmd->deserialize( de );
    
    if(!result) {
        debugWarning("Deserialization failed\n");
    }
    
    return result;
}

When FFADO Fireworks driver transmits a request of EfcPolledValuesCmd and receives the response from target device, then the driver executes this method to parse parameters in the response frame. AudioFire8/12 with recent firmware don't implement this request. They returns 0x0a (rejected) as AV/C response code and Fireworks transaction header only. In this case, the driver doesn't deserialize Fireworks transaction frame, therefore an instance of EfcPolledValuesCmd class has members which is in initial state with garbage data.

libffado:src/fireworks/fireworks_device.cpp

bool Device::doEfcOverAVC(EfcCmd &c)
{
    ....
    if (!cmd.fire()) {
        debugError( "EfcOverAVCCmd command failed\n" );
        c.showEfcCmd();
        return false;
    }

    if ( cmd.getResponse() != AVC::AVCCommand::eR_Accepted) {
        debugError( "EfcOverAVCCmd not accepted\n" );
        return false;
    }

    if (   c.m_header.retval != EfcCmd::eERV_Ok
        && c.m_header.retval != EfcCmd::eERV_FlashBusy) {
        debugError( "EFC command failed\n" );
        c.showEfcCmd();
        return false;
    }

    return true;
}

Although the instance includes garbage data, the driver manage to dump them because the transaction is failed. This is a bug in Fireworks::Device::doEfcOverAVC(). This is a reason to see invalid parameters in a dump of EfcGetClockCmd and to cause assertion in a dump of EfcGetPolledValues.

http://subversion.ffado.org/attachment/ticket/360/debug.txt

Warning (efc_avc_cmd.cpp)[  90] deserialize: Deserialization failed
Error (fireworks_device.cpp)[ 217] doEfcOverAVC: EfcOverAVCCmd command failed
Debug (efc_cmd.cpp)[ 171] showEfcCmd: EFC Length: 6
Debug (efc_cmd.cpp)[ 172] showEfcCmd: EFC Header:
Debug (efc_cmd.cpp)[ 173] showEfcCmd:  Version         : 0x00000000
Debug (efc_cmd.cpp)[ 174] showEfcCmd:  Sequence number : 0x0000000A
Debug (efc_cmd.cpp)[ 175] showEfcCmd:  Category        : 0x00000003
Debug (efc_cmd.cpp)[ 176] showEfcCmd:  Command         : 0x00000001
Debug (efc_cmd.cpp)[ 177] showEfcCmd:  Return Value    : 0x00000000
Debug (efc_cmds_hardware_ctrl.cpp)[  74] showEfcCmd: EFC Get Clock:
Debug (efc_cmds_hardware_ctrl.cpp)[  75] showEfcCmd:  Clock       : 4294967295
Debug (efc_cmds_hardware_ctrl.cpp)[  76] showEfcCmd:  Samplerate  : 4294967295
Debug (efc_cmds_hardware_ctrl.cpp)[  77] showEfcCmd:  Index       : 0
Error (fireworks_device.cpp)[ 624] getClock: Could not get clock info

3.1. FFADO Fireworks driver needs alternatives for EfcGetClockCmd/EfcSetClockCmd.

In current FFADO, the EfcPolledValuesCmd transaction is used just to check current available source of clock, therefore this command is not important as long as supported sources of clock is clear. But the EfcGetClockCmd and the EfcSetClockCmd are important to get/set current sampling rate and current source of clock.

For an alternatives to get/set current sampling rate, "INPUT PLUG SIGNAL FORMAT" and "OUTPUT PLUG SIGNAL FORMAT" commands can be available(*1). These commands are defined in "AV/C Digital Interface Command Set General Specification" which 1394TA published (*2). Fireworks has a face as "GenericAVC" device and implements them.

For an alternatives to get/set current source of clock, "SIGNAL SOURCE" command can be available(*3). This command is defined in "AV/C Connection and Compatibility Management Specification" which 1394TA published (*4). This is an example for unit information of AudioFire12:

Summary
-------

Nr | AddressType     | Direction | SubUnitType | SubUnitId | FunctionBlockType | FunctionBlockId | Id   | Type         |Name
---+-----------------+-----------+-------------+-----------+-------------------+-----------------+------+--------------+------
 0 |         subunit |     Input |       Audio |      0x00 |              0xff |            0xff | 0x00 |      Unknown | Subunit Unknown Input
 1 |         subunit |    Output |       Audio |      0x00 |              0xff |            0xff | 0x00 |      Unknown | Subunit Unknown Output
 2 |         subunit |     Input |       Music |      0x00 |              0xff |            0xff | 0x00 |         Sync | Sync select plug (MSU)
 3 |         subunit |     Input |       Music |      0x00 |              0xff |            0xff | 0x01 |    IsoStream | iPCR0
 4 |         subunit |     Input |       Music |      0x00 |              0xff |            0xff | 0x02 |       Analog | Analog
 5 |         subunit |     Input |       Music |      0x00 |              0xff |            0xff | 0x03 |         MIDI | MIDI
 6 |         subunit |    Output |       Music |      0x00 |              0xff |            0xff | 0x00 |         Sync | Internal clock
 7 |         subunit |    Output |       Music |      0x00 |              0xff |            0xff | 0x01 |    IsoStream | oPCR0
 8 |         subunit |    Output |       Music |      0x00 |              0xff |            0xff | 0x02 |       Analog | Analog
 9 |         subunit |    Output |       Music |      0x00 |              0xff |            0xff | 0x03 |         MIDI | MIDI
10 |             PCR |     Input |        Unit |      0xff |              0xff |            0xff | 0x00 |      Unknown | PCR Unknown Input
11 |             PCR |    Output |        Unit |      0xff |              0xff |            0xff | 0x00 |      Unknown | PCR Unknown Output
12 |        external |     Input |        Unit |      0xff |              0xff |            0xff | 0x00 |      Unknown | External Unknown Input
13 |        external |     Input |        Unit |      0xff |              0xff |            0xff | 0x01 |      Unknown | External Unknown Input
14 |        external |    Output |        Unit |      0xff |              0xff |            0xff | 0x00 |      Unknown | External Unknown Output
15 |        external |    Output |        Unit |      0xff |              0xff |            0xff | 0x01 |      Unknown | External Unknown Output

Connections
-----------
digraph avcconnections {
	"(6) Internal clock" -> "(2) Sync select plug (MSU)"
	"(10) PCR Unknown Input" -> "(3) iPCR0"
	"(12) External Unknown Input" -> "(4) Analog"
	"(13) External Unknown Input" -> "(5) MIDI"
	"(7) oPCR0" -> "(11) PCR Unknown Output"
	"(8) Analog" -> "(14) External Unknown Output"
	"(9) MIDI" -> "(15) External Unknown Output"
	"(0) Subunit Unknown Input" [color=green,style=filled];
	"(1) Subunit Unknown Output" [color=green,style=filled];
	"(2) Sync select plug (MSU)" [color=green,style=filled];
	"(3) iPCR0" [color=green,style=filled];
	"(4) Analog" [color=green,style=filled];
	"(5) MIDI" [color=green,style=filled];
	"(6) Internal clock" [color=green,style=filled];
	"(7) oPCR0" [color=green,style=filled];
	"(8) Analog" [color=green,style=filled];
	"(9) MIDI" [color=green,style=filled];
	"(10) PCR Unknown Input" [color=coral,style=filled];
	"(11) PCR Unknown Output" [color=coral,style=filled];
	"(12) External Unknown Input" [color=slateblue,style=filled];
	"(13) External Unknown Input" [color=slateblue,style=filled];
	"(14) External Unknown Output" [color=slateblue,style=filled];
	"(15) External Unknown Output" [color=slateblue,style=filled];
}

Currently, "Internal clock" is connected to "Sync select plug". If one of "External Unknown Input" can be connected to the "Sync select plug" by "SIGNAL SOURCE" command, a device uses "word clock" as a source of clock. But I have no idea to identify which one is correct, except for actual trials.

Current FFADO Fireworks driver doesn't use this command to get/set current source of clock, therefore work to apply this alternative may lost compatibility for the other Fireworks models. Furthermore, I have never read this specification.

4. Transfer the frame of transaction by IEEE 1394 WRITE transaction, not by AV/C vendor dependent command

It's a bit complicated to apply alternatives, therefore it's better to transfer the frame by IEEE 1394 WRITE transaction. My work for ALSA Fireworks driver uses this way and give hwdep interface for ALSA hwdep applications to achive this.

But this work is just pulled into Linux 3.16 (*5), thus this is not an immediate solution.

5. Conclusion

current FFADO has no way to drive AudioFire8/12 with the recent firmware. Users should use firmware version 4.8 or less.

References

  • *1: libffado/src/libavc/ccm/avc_signal_source.{h,cpp}
  • *2: TA Document 2004006, AV/C Digital Interface Command Set General Specification Version 4.2 (September 1, 2004, 1394TA)
  • *3: libffado/src/libavc/general/avc_signal_format.{h,cpp}
  • *4: TA Document 2002010, AV/C Connection and Compatibility Management Specification Version 1.1
  • *5: [GIT PULL] sound updates for 3.16-rc1 http://lkml.iu.edu/hypermail/linux/kernel/1406.0/02526.html

July 18 2014 Takashi Sakamoto